Compare commits

...

133 Commits

Author SHA1 Message Date
Robert Mader
d2747a1288 wayland/subsurface: Add check for parent surface
Just as we do in similar places. This avoids crashes under certain
circumstances.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1411


(cherry picked from commit 8cbcd35fdf9d0aa08e62405c89fe83522aa29cd3)
2020-08-23 21:17:48 +00:00
Daniel van Vugt
32d130ddf0 meson_options: Use libGLESv2.so.2 for COGL_DRIVER=gles2, not libGLESv2.so
The former is present on any system that supports OpenGL|ES 2. The latter
is just provided in developer packages. Since we access the library via
`g_module_open` it's safe to just rely on `libGLESv2.so.2`.

Closes: https://gitlab.gnome.org/GNOME/mutter/-/issues/1282

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1298


(cherry picked from commit dfe33897db0989635e4a789290dd2a73da39ca5c)
2020-08-21 11:55:12 +00:00
Florian Müllner
7d061a06de Bump version to 3.36.5
Update NEWS.
2020-08-11 21:41:41 +02:00
Thomas Hindoe Paaboel Andersen
e3b213f9d7 clutter: fix memleak in test error path
If clutter_init fails then we will not free state.

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

(cherry picked from commit d0ef660ff6f2fa5fed774bd577285b2a7006c887)
2020-08-07 13:19:16 +02:00
Marco Trevisan (Treviño)
eea81807ee test-utils: Only initialize client when we're returning it
test_client_new might return early if conditions are not met, leaving some
allocated data around without freeing it.

Since we're not using the client before, there's no need to initialize it early
and just initialize it when it's going to be returned.

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

(cherry picked from commit 506e06589b7feabd184b90bf5ac38ec83cefd92c)
2020-08-07 13:18:58 +02:00
Marco Trevisan (Treviño)
fdb76593d0 group: Free group if returning early
If we get an error when fetching the window attributes, the group isn't ever
free'd, so use an autopointer instead, releasing the stolen one.

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

(cherry picked from commit 1d75d5aa2f5e5a7b14573489877e143f6a06cf5d)
2020-08-07 13:18:41 +02:00
Marco Trevisan (Treviño)
143771441f cogl: Use autopointers to free structs on return
This is a potential leak discovered by static analysis, in fact if
_COGL_GET_CONTEXT returns, the newly allocated struct isn't released.

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

(cherry picked from commit 645d596f9d39e26c239a307fa699f11eeb921e18)
2020-08-07 13:18:31 +02:00
Sebastian Keller
52a6b5df5f x11: Add STRING/UTF8_STRING targets for selection sources lacking them
The memory selection source was only providing the "text/plain" or the
"text/plain;charset=utf-8" mimetype, but not "STRING" or "UTF8_STRING",
which some X11 clients, like wine, are looking for. This was breaking
pasting from the clipboard in wine applications.

Fix this by adding those targets when they are missing and the selection
source provides the corresponding mimetypes.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1369

(cherry picked from commit c7d14244b1b025199fed945e8eb51ebc5d804b4e)
2020-08-07 13:02:18 +02:00
Sebastian Keller
299569c3b8 x11: Handle selection windows being destroyed before new selection
Wine destroys its old selection window immediately before creating a new
selection. This would trigger restoring the clipboard, which would
overwrite the new selection with the old one. The selection window
however can also be destroyed as part of the shutdown process of
applications, such as Chromium for example. In those cases we want the
clipboard to be restored after the selection window has been destroyed.

Solve this by not immediately restoring the clipboard but instead using
a timeout which can be canceled by any new selection owner, such as in
the Wine case.

Fixes https://gitlab.gnome.org/GNOME/mutter/-/issues/1338
https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1369

(cherry picked from commit e1c4e5588061610b5016766253fa2930e0054826)
2020-08-07 13:02:06 +02:00
Daniel van Vugt
3dab5120ed background-actor: Mipmap background texture rendering
gnome-shell displays workspace previews at one tenth scale. That's a
few binary orders of magnitude so even using a LINEAR filter was
resulting in visible jaggies. Now we apply mipmapping so they appear
smooth.

As an added bonus, the mipmaps used occupy roughly 1% the memory of
the original image (0.1 x 0.1 = 0.01) so they actually fit into GPU/CPU
caches now and rendering performance is improved. There's no need to
traverse the original texture which at 4K resolution occupies 33MB,
only a 331KB mipmap.

In my case this reduces the render time for the overview by ~10%.

Closes: https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/1416
Origin: https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1347

(cherry picked from commit 32dbcd935255c9df46a56d12ede323a8f464cecd)
2020-08-03 14:29:46 +08:00
Daniel van Vugt
eae21f01dd cogl-texture-2d: Flush the journal before mipmapping
In the case of indirect rendering like the first frame to use mutter's
background wallpaper:

  Texture_A -> FBO_B (Texture_B) -> FBO_C (screen)

we would be trying to render the contents of both FBO_B and FBO_C in
the same flush, before the contents of Texture_A had made it to FBO_B.
So when FBO_C wants to use mipmaps of Texture_B they didn't exist yet
and appeared all black. And the blackness would remain for subsequent
frames as cogl has now decided the mipmaps of FBO_B are no longer
"dirty" and don't need refreshing:

  FBO_B (Texture_B) (mipmaps_dirty==FALSE but black) -> FBO_C (screen)

We must flush FBO_B before referencing Texture_B for use in rendering
FBO_C. This only happens when Texture_A changes (e.g. when the user
changes their background wallpaper) so there's no ongoing performance
penalty from this flush.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1347

(cherry picked from commit 3a474556b8cda1cc12b128125689fa393d5c1c0b)
2020-07-30 20:34:47 +02:00
Robert Mader
4d8538d6a9 window-actor/wayland: Remove custom get_paint_volume() vfunc
It doesn't take all children - subsurfaces in this case - into
account, thus creating glitches if subsurfaces extend outside
of the toplevel surface.

Further more it doesn't seem to serve any special purpose - it was
added in f7315c9a36462, a pretty big commit, and no discussion was
started about the code in question. So it was likely just overlooked
in the review process.

Closes https://gitlab.gnome.org/GNOME/mutter/-/issues/873
Closes https://gitlab.gnome.org/GNOME/mutter/-/issues/1316

(cherry picked from commit d722e59aacf2bec62d523992296a252974131304)
2020-07-30 20:33:01 +02:00
Rafael Fontenelle
ef3dac7064 Update Brazilian Portuguese translation 2020-07-17 21:36:24 +00:00
Jonas Ådahl
1fd53c480f screen-cast/src: Remove follow up timeout source on disable
We failed to remove the timeout source when disabling, meaning that if a
follow up was scheduled, and shortly after we disabled the source, the
timeout would be invoked after the source was freed causing
use-after-free bugs.

Closes: https://gitlab.gnome.org/GNOME/mutter/-/issues/1337

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1365


(cherry picked from commit d67ba3ea65717ceab3e0c91267191c6ed2aac2c2)
2020-07-10 13:26:19 +00:00
Jonas Ådahl
0c6ac287e6 screen-cast/src: Use G_USEC_PER_SEC instead of 1000000
https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1351
2020-07-08 19:27:24 +02:00
Jonas Ådahl
e8052f169b screen-cast/src: Record follow up frame after timeout
During animation or other things that cause multiple frames in a row
being painted, we might skip recording frames if the max framerate is
reached.

Doing so means we might end up skipping the last frame in a series,
ending with the last frame we sent was not the last one, making things
appear to get stuck sometimes.

Handle this by creating a timeout if we ever throttle, and at the time
the timeout callback is triggered, make sure we eventually send an up to
date frame.

This is handle differently depending on the source type. A monitor
source type reports 1x1 pixel damage on each view its monitor overlaps,
while a window source type simply records a frame from the surface
directly, except without recording a timestamp, so that timestamps
always refer to when damage actually happened.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1351
2020-07-08 19:26:56 +02:00
Jonas Ådahl
449fa7bf81 screen-cast/src: Fix signedness of timestamp field
https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1351
2020-07-08 15:13:06 +02:00
Jonas Ådahl
2d899596e2 screen-cast/src: Make record functions return an error when failing
Now that we don't use the record function to early out depending on
implicit state (don't record pixels if only cursor moved for example),
let it simply report an error when it fails, as we should no longer ever
return without pixels if nothing failed.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1351
2020-07-08 15:13:06 +02:00
Jonas Ådahl
cf88d64882 screen-cast: Let the reason for recording determine what to record
E.g. we'll have pointer movement that, if no painting is already
scheduled, should only send new cursor metadata without any new pixel
buffer. When this happens, tell next step to not record the pixels if
this was the case, instead of having it rediscover this itself.

Closes: https://gitlab.gnome.org/GNOME/mutter/-/issues/1323
https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1351
2020-07-08 15:13:06 +02:00
Jonas Ådahl
92db8902d9 screen-cast/src: Add flag to maybe_record()
Will later be used to make recording avoid recording actual pixel
content if e.g. only the cursor moved.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1351
2020-07-08 15:13:06 +02:00
Jonas Ådahl
b1d45820ef screen-cast/window-stream-src: Fix indentation
https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1351
2020-07-08 15:13:06 +02:00
Jonas Ådahl
d07335cd4c screen-cast-src: Make the two record vfuncs more similarly named
Both do more or less the same but with different methods - one puts
pixels into a buffer using the CPU, the other puts pixels into a buffer
using the GPU.

However, they are behaving slightly different, which they shouldn't.
Lets first address the misleading disconnect in naming, and later we'll
make them behave more similarly.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1351
2020-07-08 15:13:06 +02:00
Florian Müllner
d03deb006c Bump version to 3.36.4
Update NEWS.
2020-07-07 20:41:54 +02:00
Jonas Dreßler
c2146b457e clutter/box-layout: Request the correct size for homogeneous layouts
In case the layout is homogeneous, all children aligned by the box
layout must be allocated the same size. In order to fit them all inside
the container, the size request of the box layout has to look for the
child with the largest size and use that size for all children.

Fixes https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/2737

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1333
2020-07-06 18:19:35 +02:00
Jonas Dreßler
77dc3a5065 clutter/box-layout: Add spacing when computing opposite orientation size
ClutterBoxLayout calculates the preferred size of the opposite
orientation (so for example the height if the orientation is horizontal)
by getting the preferred size of the real orientation first, and then
the preferred size of the opposite orientation, using the other size as
for_width/height when doing the request.

Right now, for non-homogeneous layouts this for_width/height does not
adjust for the spacing set on the box layout. This leads to children
being passed a slightly larger for_width/height, which in case of
ClutterText might cause the line to not wrap when it actually should.
This in turn means we can end up with an incorrect preferred size for
the opposite orientation, leading to a wrong allocation.

So fix that and adjust for the spacing just as we do for homogeneous
layouts by subtracting the total spacing from the available size that is
distributed between children.

This fixes the wrong height of the checkbox label reported in
https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/2574.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1333
2020-07-06 18:19:35 +02:00
Carlos Garnacho
454875248a x11: Look up reason for selection clear events from XFixes
If the event originates from a XSetSelectionOwner request, the event
will contain a XFixesSetSelectionOwnerNotify subtype. The other
subtypes (meant for the selection window being destroyed, and the
client closing) are the situations where we mean to replace the
selection.

Fixes: https://gitlab.gnome.org/GNOME/mutter/-/issues/1268

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1350

(cherry picked from commit 2f1f47d25708cf444e4d35045486fa2841ce0d69)
2020-07-03 18:40:48 +02:00
Robert Mader
ae8acc9980 surface-actor: Add culling offset for geometry scale - take 2
41130b08eb added a fix for culling subsurfaces with geometry scale.
Unfortunately it only did so for the opaque regions, not for clip and
unobscured regions, as the effect was hidden by bug that was only
fixed by 3187fe8ebc7.

Apply the same fix to clip and unobscured regions and use the chance
to move most of the slightly hackish geometry scale related code
into a single place.

We need to scale slightly differently in the two cases, indicated by
the new `ScalePerspectiveType` enum, as the scale is dependent on the
perspective - once from outside, once from inside of the scaled actor.

Closes https://gitlab.gnome.org/GNOME/mutter/-/issues/1312

(cherry picked from commit 86646679f14458ce567f547595ca2f93fb795c4a)
2020-06-30 22:33:52 +02:00
Olivier Fourdan
86d9cd1a66 remote-desktop: Check for screencast only when required
The portal API requires a screencast session only for absolution motion
with remote desktop, other methods including relative motion do not
require a screencast session.

There is no reason to be more strict than the API actually is, check for
a screencast session only when required, like for absolute motion events
and touch events.

Tested with https://gitlab.gnome.org/snippets/1122

Closes: https://gitlab.gnome.org/GNOME/mutter/-/issues/1307


(cherry picked from commit b8524504f475c98591c6f04b7dfcab47d023ac8f)
2020-06-29 18:38:28 +00:00
Daniel van Vugt
3a70ba7ae2 shaped-texture: Use the REPLACE combine function on opaque areas
We were setting the pipeline colour to all white (1.0, 1.0, 1.0, 1.0)
and so the default layer combine function multiplied each pixel
(R, G, B, A) by all ones. Obviously multiplying by one four times per
pixel is a waste of effort so we remove the colour setting *and* set
the layer combine function to a trivial shader that will ignore whatever
the current pipeline colour is set to. So now we do **zero** multiplies
per pixel.

On an i7-7700 at UHD 3840x2160 this results in 5% faster render times
and 10% lower power usage (says intel_gpu_top). The benefit is probably
much higher for virtual machines though, as they're no longer being
asked to do CPU-based math on every pixel of a window.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1331

(cherry picked from commit e5542c3210229d944f66c030dc26fe4e9d010607)
2020-06-27 12:31:02 +02:00
Jonas Ådahl
36a6235f3a wayland/xdg-shell: Don't use xdg_surface private to get window geometry
We already used the actual API in the same function, move that call a
bit higher up to and use the variable in more places.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1295

(cherry picked from commit 4c0aa2afcadef845a8c942bd4a67f66e37e4c75b)
2020-06-26 10:15:58 +02:00
Jonas Ådahl
9b349cb25b wayland/shell: Apply geometry after subsurface state application
The subsurface state may affect the geometry end result, e.g. when
window decoration enlarging the toplevel window are applied. If we don't
wait with calculating the window geometry, intersecting the set region
with the subsurface tree extents will not include the subsurfaces.

Closes: https://gitlab.gnome.org/GNOME/mutter/-/issues/928

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1295

(cherry picked from commit d6af59612cee2050798ea9af092afc1269f0eea5)
2020-06-26 10:15:46 +02:00
Jonas Ådahl
a83d83f087 wayland: Remove a couple of stray newlines
https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1295

(cherry picked from commit be59b514cab8f8765393ee58764e95c20a74a7c3)
2020-06-26 10:15:28 +02:00
Sebastian Keller
b8bd39793a wayland/data-device: Don't create and leak unused memory on dnd
"offer" is overwritten with the result of meta_wayland_data_offer_new a
few lines later.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1293

(cherry picked from commit 99c9f4c1fa4abab4cabe9dda0c6ca8f614a73486)
2020-06-24 22:02:34 +02:00
Sebastian Keller
70072c39dd wayland: Free selection streams streams after transfer
They were only being closed but never freed.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1293

(cherry picked from commit dd32ff018afd6dea7f865d8ec194a8e2c514b5de)
2020-06-24 22:02:34 +02:00
Sebastian Keller
bb4bd4b5c0 core: Free clipboard selection source on shutdown
The clipboard manager is the only code to ever set the display selection
source, so it should also be responsible for unsetting it when the
clipboard manager gets shut down.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1293

(cherry picked from commit 019643bad081f7a29119a99ca5ecbc5c2ba3ee56)
2020-06-24 22:02:34 +02:00
Sebastian Keller
ef848f10d1 core: Fix memory selection source leak after clipboard owner disappears
When an app disappears after some data from it has been copied to the
clipboard, the owner of the clipboard selection becomes a new memory
selection source. The initial reference this new selection source is
never unref'ed, which leads to this being leaked on the next clipboard
selection owner change.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1293

(cherry picked from commit a031ac067e4b275d1de3ae7c018711be187fbb6b)
2020-06-24 22:02:34 +02:00
Carlos Garnacho
59cb259fdd wayland: Add support for wayland-protocols primary selection protocol
This protocol was added some time ago. Supporting it fell through the
cracks. Add new data device/source/offer implementations for it,
interoperation between primary selection protocols (and X11 primary
selection for that matter) comes for free.

Closes: https://gitlab.gnome.org/GNOME/mutter/-/issues/943

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1255

(cherry picked from commit 2becb3dd29f8b62f4b68938ecbfa1ec41a0d9fca)
2020-06-24 22:02:34 +02:00
Carlos Garnacho
76e4b5de7a build: Build scaffolding for primary-selection wayland protocol
https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1255

(cherry picked from commit 55f5177fe0381f0f2869d2a0620bc38c8e625ff9)
2020-06-24 22:02:34 +02:00
Carlos Garnacho
9acb823603 wayland: Rename gtk primary protocol files to "legacy"
We want to make room for the wayland-protocols primary selection
protocol. Rename our private protocol as "legacy".

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1255

(cherry picked from commit 037b68ab8eeb462ad3715c30642f57124794f7b2)
2020-06-24 22:02:34 +02:00
Carlos Garnacho
d721750417 wayland: Send primary offer to all data devices from the same client
Make the data device track the keyboard focus, and use that list to
forward the primary selection to all data devices from the same
client.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1253

(cherry picked from commit b45d5ef3f5a497703fd2c77b7088249cbf3ef367)
2020-06-24 22:02:34 +02:00
Carlos Garnacho
1ec91cc8ee wayland: Send clipboard offers to all data devices from the same client
Make the data device track the keyboard focus, and use that list to
forward the clipboard selection to all data devices from the same
client.

This is however not the case of DnD data offers, as the semantics
of multiple in-flight offers is unclear.

Fixes: https://gitlab.gnome.org/GNOME/mutter/-/issues/1250

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1253

(cherry picked from commit 7e4e3714663952a69ba0a26662841fc5c0cb266c)
2020-06-24 22:02:34 +02:00
Carlos Garnacho
5c7b5ef0d9 wayland: Drop unused struct variable
https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1193

(cherry picked from commit b7366b5b534cbea38fed58ac435f848111924713)
2020-06-24 22:02:34 +02:00
Carlos Garnacho
e98e1c13dd wayland: Move the primary data device manager to its own file
Instead of having everything clumped at MetaWaylandDataManager,
split the primary selection to its own struct. This manager is
handled separately from wl_data_device_manager and other selection
managers, so they would be able to interoperate between them, even.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1193

(cherry picked from commit 5e8d8b9ade55ad7f7f5b9641ba92e20784b778ba)
2020-06-24 22:02:34 +02:00
Carlos Garnacho
8b69e7902a wayland: Move primary data offers to their own file
Following the MetaWaylandDataOffer split.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1193

(cherry picked from commit 4726f3d5d3ac6ea0ca5290886492e5daa1eb830e)
2020-06-24 22:02:34 +02:00
Carlos Garnacho
b52a0be288 wayland: Move MetaWaylandDataOffer to its own file
This is still an openly defined struct, as we will need accessed
by "subclasses". Same principle applies than with the
MetaWaylandDataSource refactor, this is not meant to introduce
functional changes, so just go with it.

On the bright side, the interactions are now clearer, so it could
be made saner in the future.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1193

(cherry picked from commit 91ef7515de688d47ee30265a6651987bae352fc3)
2020-06-24 22:02:34 +02:00
Carlos Garnacho
1eb0812f0a wayland: Move MetaWaylandDataSourcePrimary to its own file
Following the MetaWaylandDataSource split, this goes next.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1193

(cherry picked from commit 317f6c0910b7d66ec24d6232e35f211673d22947)
2020-06-24 22:02:34 +02:00
Carlos Garnacho
b98125a330 wayland: Split MetaWaylandDataSource into a separate file
The split wasn't 100% clean, and some extra private API had to be
added for it (but well, looking at the API, it's already evident
there's a cleanup/streamlining task due). This is meant to be a
refactor with no functional changes, so just go with it.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1193

(cherry picked from commit 6a3d521466f6d554f7c905d4de7ba31546d24452)
2020-06-24 22:02:34 +02:00
Robert Mader
78248d8dd3 Revert "wayland: Send clipboard offers to all data devices from the same client"
This reverts commit 36f5a0a491c92c41ff7526390d09d1b61780c8c7.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1330
2020-06-24 22:02:29 +02:00
Robert Mader
849d8dfae9 Revert "wayland: Send primary offer to all data devices from the same client"
This reverts commit 493aeb65c8ed435c66bd951f830e145c1eaaf06d.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1330
2020-06-24 22:02:25 +02:00
Jonas Ådahl
1f896c9735 gpu-kms: Fix compilation issues from backport
The backport applied cleanly, but didn't build as function type
signatures called changed. This fixes the compilation issues.
2020-06-23 16:25:51 +02:00
Michel Dänzer
cc617b059c gpu/kms: Turn off CRTCs as well for DPMS
This avoids some issues which could happen on some setups[0] due to
meta-native-renderer.c:dummy_power_save_page_flip →
meta_onscreen_native_swap_drm_fb implicitly turning of the primary
plane (by destroying the KMS framebuffer assigned to it):

* drmModeObjectSetProperty could return an "Invalid argument" error
  between setting a non-empty cursor with drmModeSetCursor(2) and
  enabling the primary plane again:

  Failed to DPMS: Failed to set connector 69 property 2: Invalid argument

  (This was harmless other than the error message, as we always re-set
  a mode on the CRTC after setting the DPMS property to on, which
  enables the primary plane and implicitly sets the DRM property to on)

* drmModeSetCursor(2) could return an "Invalid argument" error between
  setting the DPMS property to on and enabling the primary plane again:

  Failed to set hardware cursor (drmModeSetCursor failed: Invalid argument), using OpenGL from now on

[0] E.g. with the amdgpu DC display code.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1240


(cherry picked from commit 2e5b767c01b56ce5d28ca5da3c964cdb9262b80b)
2020-06-23 14:13:39 +00:00
Robert Mader
44a3358125 shaped-texture: Reintroduce clip_region
In commit 4c1fde9d MetaCullable related code was moved out of
MetaShapedTexture into MetaSurfaceActor. While generally desirable,
this removed drawing optimizations in MetaShapedTexture for partial
redraws. The common case for fully obscured actors was still supposed
to work, but it was now discovered that it actually did not.

This commit revert parts of 4c1fde9d: it reintroduces clipping
to MetaShapedTexture but leaves all culling and actor related logic
in MetaSurfaceActor.

Thanks to Daniel van Vugt for uncovering the issue.

Fixes https://gitlab.gnome.org/GNOME/mutter/-/issues/850
Fixes https://gitlab.gnome.org/GNOME/mutter/-/issues/1295

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1326


(cherry picked from commit 3187fe8ebc73cb3907d1d02edecedc4e4ab0c689)
2020-06-22 16:16:37 +00:00
Sebastian Keller
81deb99435 clutter/stage: Make paint_to_buffer use the correct texture/buffer size
The size of the buffer the texture will be written to by
paint_to_buffer() is determined based on
meta_screen_cast_area_stream_src_get_specs() which uses roundf() to
calculate the width and height after scaling. Because the size of the
texture to be written to that buffer is calculated using ceilf(), it
might exceed the allocated buffer when using fractional scaling.

In 3.36 paint_to_buffer() is used from capture_view() which also uses
roundf() to allocate its buffer. Here this leads to a memory corruption
resulting in a crash when taking screenshots of an area.

Fixes https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/2842

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1320


(cherry picked from commit e216d9c6ad377ba5ed51d0edf9805ca7c73a7e63)
2020-06-17 19:36:46 +00:00
Sebastian Keller
f25417efcf clutter/paint-context: Fix NO_PAINT_SIGNAL flag enum value
This flag was using the same value as the NO_CURSORS flag.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1321
2020-06-17 17:52:24 +02:00
Corentin Noël
ecc2b91016 window-actor-x11: switch the signal callback argument and data on shadow factory change
invalidate_shadow takes the MetaWindowActorX11 as argument and not the MetaShadowFactory.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1314


(cherry picked from commit e09ac6769809c39a055ca24be2f027affb31e370)
2020-06-16 16:04:38 +00:00
Jonas Ådahl
b002343dca stage/x11: Check that message is WM_PROTOCOLS before assuming so
When a touch sequence was rejected, we'd update the event timestamps of
incoming touch events to help with implementing grabs. This was done by
sending a ClientMessage with a counter, and comparing the counter to
decide whether we're seing a replayed event or not.

This had the unforseen consequence that we would potentially end up
destroying all actors including the stage, since, when mutter receives a
ClientMessage event, it would assume that it's a WM_PROTOCOLS event, and
handle it as such. The problem with this approach is that it would
ignore fact that there might be other ClientMessage types sent to it,
for example the touch synchronization one. What could happen is that the
touch count value would match up with the value of the WM_DELETE_WINDOW
atom, clutter would treat this as WM_PROTOCOLS:WM_DELETE_WINDOW, which
it'd translate to clutter_actor_destroy(stage).

Destroying the stage in such a way is not expected, and caused wierd
crashes in different places depending on what was going on.

This commit make sure we only treat WM_PROTOCOLS client messages as
WM_PROTOCOLS client messages effectively avoiding the issue.

This fixes crashes such as:

 #0  meta_window_get_buffer_rect (window=0x0, rect=rect@entry=0x7ffd7fc62e40) at core/window.c:4396
 #1  0x00007f1e2634837f in get_top_visible_window_actor (compositor=0x297d700, compositor=0x297d700) at compositor/compositor.c:1059
 #2  meta_compositor_sync_stack (compositor=0x297d700, stack=<optimized out>, stack@entry=0x26e3140) at compositor/compositor.c:1176
 #3  0x00007f1e263757ac in meta_stack_tracker_sync_stack (tracker=0x297dbc0) at core/stack-tracker.c:871
 #4  0x00007f1e26375899 in stack_tracker_sync_stack_later (data=<optimized out>) at core/stack-tracker.c:881
 #5  0x00007f1e26376914 in run_repaint_laters (laters_list=0x7f1e2663b7d8 <laters+24>) at core/util.c:809
 #6  run_all_repaint_laters (data=<optimized out>) at core/util.c:826
 #7  0x00007f1e26b18325 in _clutter_run_repaint_functions (flags=flags@entry=CLUTTER_REPAINT_FLAGS_PRE_PAINT) at clutter-main.c:3448
 #8  0x00007f1e26b18fc5 in master_clock_update_stages (master_clock=0x32d6a80, stages=0x4e5a740) at clutter-master-clock-default.c:437
 #9  clutter_clock_dispatch (source=<optimized out>, callback=<optimized out>, user_data=<optimized out>) at clutter-master-clock-default.c:567
 #10 0x00007f1e27e48049 in g_main_dispatch (context=0x225b8d0) at gmain.c:3175
 #11 g_main_context_dispatch (context=context@entry=0x225b8d0) at gmain.c:3828
 #12 0x00007f1e27e483a8 in g_main_context_iterate (context=0x225b8d0, block=block@entry=1, dispatch=dispatch@entry=1, self=<optimized out>) at gmain.c:3901
 #13 0x00007f1e27e4867a in g_main_loop_run (loop=0x24e29f0) at gmain.c:4097
 #14 0x00007f1e2636a3dc in meta_run () at core/main.c:666
 #15 0x000000000040219c in main (argc=1, argv=0x7ffd7fc63238) at ../src/main.c:534

and

 #0  0x00007f93943c1f25 in raise () at /usr/lib/libc.so.6
 #1  0x00007f93943ab897 in abort () at /usr/lib/libc.so.6
 #2  0x00007f9393e1e062 in g_assertion_message (domain=<optimized out>, file=<optimized out>, line=<optimized out>, func=0x7f93933e6860 <__func__.116322> "meta_x11_get_stage_window",
 #3  0x00007f9393e4ab1d in g_assertion_message_expr ()
 #4  0x00007f939338ecd7 in meta_x11_get_stage_window (stage=<optimized out>) at ../mutter/src/backends/x11/meta-stage-x11.c:923
 #5  0x00007f939339e599 in meta_backend_x11_cm_translate_device_event (x11=<optimized out>, device_event=0x55bc8bcfd6b0) at ../mutter/src/backends/x11/cm/meta-backend-x11-cm.c:381
 #6  0x00007f939339f2e2 in meta_backend_x11_translate_device_event (device_event=0x55bc8bcfd6b0, x11=0x55bc89dd5220) at ../mutter/src/backends/x11/meta-backend-x11.c:179
 #7  0x00007f939339f2e2 in translate_device_event (device_event=0x55bc8bcfd6b0, x11=0x55bc89dd5220) at ../mutter/src/backends/x11/meta-backend-x11.c:208
 #8  0x00007f939339f2e2 in maybe_spoof_event_as_stage_event (input_event=0x55bc8bcfd6b0, x11=0x55bc89dd5220) at ../mutter/src/backends/x11/meta-backend-x11.c:284
 #9  0x00007f939339f2e2 in handle_input_event (event=0x7fff62d60490, x11=0x55bc89dd5220) at ../mutter/src/backends/x11/meta-backend-x11.c:309
 #10 0x00007f939339f2e2 in handle_host_xevent (event=0x7fff62d60490, backend=0x55bc89dd5220) at ../mutter/src/backends/x11/meta-backend-x11.c:413
 #11 0x00007f939339f2e2 in x_event_source_dispatch (source=<optimized out>, callback=<optimized out>, user_data=<optimized out>) at ../mutter/src/backends/x11/meta-backend-x11.c:467
 #12 0x00007f9393e6c39e in g_main_dispatch (context=0x55bc89dd03e0) at ../glib/glib/gmain.c:3179
 #13 0x00007f9393e6c39e in g_main_context_dispatch (context=context@entry=0x55bc89dd03e0) at ../glib/glib/gmain.c:3844
 #14 0x00007f9393e6e1b1 in g_main_context_iterate (context=0x55bc89dd03e0, block=block@entry=1, dispatch=dispatch@entry=1, self=<optimized out>) at ../glib/glib/gmain.c:3917
 #15 0x00007f9393e6f0c3 in g_main_loop_run (loop=0x55bc8a042640) at ../glib/glib/gmain.c:4111
 #16 0x00007f9393369a0c in meta_run () at ../mutter/src/core/main.c:676
 #17 0x000055bc880f2426 in main (argc=<optimized out>, argv=<optimized out>) at ../gnome-shell/src/main.c:552

Related: https://gitlab.gnome.org/GNOME/mutter/-/issues/338
Closes: https://gitlab.gnome.org/GNOME/mutter/-/issues/951

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1317
(cherry picked from commit e5ea8f54836ed2d041f0caa420ee1bcee0ff146a)
2020-06-16 16:18:23 +02:00
Jonas Ådahl
0d9ded403f renderer-native: Don't leak DMA buffer CoglFramebuffer
When we created the DMA buffer backed CoglFramebuffer, we handed it over
to CoglDmaBufHandle which took its own reference. What we failed to do
was to release our own reference to it, effectively leaking it.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1283
(cherry picked from commit c823b5ddba18d30e1fdb74d6764cd40637dc4054)
2020-06-03 08:27:37 +02:00
Florian Müllner
dc75c7d297 Bump version to 3.36.3
Update NEWS.
2020-06-03 01:35:15 +02:00
Jonas Dreßler
33c008b90a clutter/actor: Sanity check new allocations
Apparently some shell extensions are setting invalid NaN allocations,
leading to weird crashes like
https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/1849.

Even though an implementation error like this probably deserves a crash,
those can be hard to debug since the crash can happen anywhere the
allocation is being used later. So let Clutter be the good guy and
prevent implementations from setting invalid allocations by
sanity-checking the ClutterActorBoxes using g_return_if_fail.

Fixes https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/1849

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1280
2020-06-03 01:35:15 +02:00
Jonas Ådahl
98a0c5cb35 screen-cast-src: Destroy hash dmabuf table after stream
The stream will clean up the buffers, so let it do that before we
destroy them under its feet. Note that it'll only do this after the
following PipeWire commit:

    commit fbaa4ddedd84afdffca16f090dcc4b0db8ccfc29
    Author: Wim Taymans <wtaymans@redhat.com>
    Date:   Mon Jun 1 15:36:09 2020 +0200

        stream: allow NULL param and 0 buffers in disconnect

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1283


(cherry picked from commit 97175f8fa14171606ecb95d0bf107ef8b2d71b74)
2020-06-02 19:01:01 +00:00
Carlos Garnacho
b425f11536 backends/native: Drop external keyboard detection for ::touch-mode
This cannot be made to work reliably. Some factoids:

- Internal devices may be connected via USB.
- The ACPI spec provides the _PLD (Physical location of device) hook to
  determine how is an USB device connected, with an anecdotal success
  rate. Internal devices may be seen as external and vice-versa, there is
  also an "unknown" value that is widely used.
- There may be non-USB keyboards, the old "AT Translated Set 2 Keyboard"
  interface does not change on hotplugging.
- Libinput has an internal series of quirks to classify keyboards as
  internal of external, also with an "unknown" value.

These heuristics are kinda hopeless to get right by our own hand. Drop
this external keyboard detection in the hope that there will be something
more deterministic to rely on in the future (e.g. the libinput quirks
made available to us directly or indirectly).

Fixes: https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/2378
Related: https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/2353

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1277


(cherry picked from commit f8e2234ce59fbbfa3bc6f3c81afc2a249ae2d0ed)
2020-05-29 14:53:18 +00:00
Carlos Garnacho
a1bc2e0adc backends/x11: Implement ClutterSeat::touch-mode for the X11 backend
This only checks touchscreen availability as we have no access to
tablet-mode switch events as we do on the native backend.

Fixes: https://gitlab.gnome.org/GNOME/mutter/-/issues/1242

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1278


(cherry picked from commit 38bbd9593bc3d4c8afa77dcd5329adb8c4f20abf)
2020-05-29 14:52:34 +00:00
Jonas Ådahl
63fc71f05b screen-cast-src: Notify about the stream being closed after dispatch
We're iterating inside the PipeWire loop when detecting PipeWire errors,
and shouldn't destroy the PipeWire objects mid-iteration. Avoid this by
first disabling the stream src (effectively stopping the recording),
then notifying about it being closed in an idle callback. The
notification eventually makes the rest of the screen cast code clean up
the objects, including the src and the associated PipeWire objects, but
will do so outside the PipeWire loop iteration.

Closes: https://gitlab.gnome.org/GNOME/mutter/-/issues/1251

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1251
(cherry picked from commit c8e12ead08fd8ee8593b033c1f1a624f94a47ed9)
2020-05-23 00:04:10 +02:00
Jonas Ådahl
31307720bf stage-x11: Move view management to renderer
In the native backend, the MetaRenderer manages the view by creating one
per CRTC, but until now the MetaStageX11 managed the view for the X11
backend. This caused some issues as it meant meta_renderer_get_views()
not returning anything, and that the view of the X11 screen not being a
MetaRendererView, while in the other backends, all views are.

Fix this by moving the view management responsibility to
MetaRendererX11Cm, and have MetaStageX11 only operate on it via
meta_renderer_x11_cm_*() API. The MetaRendererX11Cm takes care of making
sure the view is always added to the list in the renderer, and turning
X11 screen sizes into "layouts" etc.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1251
(cherry picked from commit 8a541c08fba3bc59eddde828f080fc9a62d58b36)
2020-05-23 00:04:10 +02:00
Jonas Ådahl
cb7ba2e90f stage-x11: Clean up include macros
https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1251
(cherry picked from commit dfed5f6a119f832b12c1db2f7780a63566a835c8)
2020-05-23 00:04:10 +02:00
Jonas Ådahl
ba1f4221e9 screen-cast-stream-src: Don't throttle if max framerate is 1/0
The max framerate 1/0 means variable without any particular max, so
don't throttle if that was set.

Not doing this would end up with a floating point exception.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1251
(cherry picked from commit 96dd794fd18ac2650d6186de5c62da7051f0ce92)
2020-05-23 00:04:10 +02:00
Jonas Ådahl
6e6183ec08 renderer: Change 'set_legacy_view()' to 'add_view()'
"Legacy" is a misleading name, it's just how the native backend and the
X11 backend behaves differently. Instead rename it to 'add_view()' and
add the sanity check to the caller.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1251
(cherry picked from commit 73a436362aa75333b1d7faa93bea21a916ec1fef)
2020-05-23 00:04:10 +02:00
Carlos Garnacho
493aeb65c8 wayland: Send primary offer to all data devices from the same client
Make the data device track the keyboard focus, and use that list to
forward the primary selection to all data devices from the same
client.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1253

(cherry-pick of commit b45d5ef3f5a497703fd2c77b7088249cbf3ef367)

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1262
2020-05-20 11:28:23 +00:00
Carlos Garnacho
36f5a0a491 wayland: Send clipboard offers to all data devices from the same client
Make the data device track the keyboard focus, and use that list to
forward the clipboard selection to all data devices from the same
client.

This is however not the case of DnD data offers, as the semantics
of multiple in-flight offers is unclear.

Fixes: https://gitlab.gnome.org/GNOME/mutter/-/issues/1250

(cherry-pick of commit 7e4e3714663952a69ba0a26662841fc5c0cb266c)

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1262
2020-05-20 11:28:23 +00:00
Carlos Garnacho
3daf912449 backends: Make uniform checks on remote desktop input dbus methods
They all checked that the remote session service talked with the
correct peer, and some of them did check that there is an associated
screencast session.

Add a new check for the session being started (as it's state is
decoupled with screencast session availability) and move all checks
to a function that is called from all input-oriented DBus methods.

Fixes: https://gitlab.gnome.org/GNOME/mutter/-/issues/1254

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1258


(cherry picked from commit c8837a8de564705bfe36629e15cb5a213cd0839e)
2020-05-20 11:05:51 +00:00
Carlos Garnacho
fadfca2e16 backends: Ensure remote desktop dbus interface state
Ensure that it does receive Start and Stop orderly, and error out
otherwise.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1258


(cherry picked from commit 283cccbe9f061f769ace25378de306c10fdabc61)
2020-05-20 11:05:41 +00:00
Daniel van Vugt
b1df6d08a5 backend-x11: Reintroduce XInitThreads
It was removed in 3.34 as part of 6ed5d2e2. And we thought that was the
only thread that might exist and use X11. But the top gnome-shell crasher
in 3.36 seems to suggest otherwise.

We don't know what or where the offending thread is, but since:

 1. We used XInitThreads for years already prior to 3.34; and

 2. Extensions or any change to mutter/gnome-shell could conceivably use
    threads to make X calls, directly or indirectly,

it's probably a good idea to reintroduce XInitThreads. The failing assertion
in libx11 is also accompanied by a strong hint:

```
fprintf(stderr, "[xcb] Most likely this is a multi-threaded client " \
                "and XInitThreads has not been called\n");
```

https://bugs.launchpad.net/bugs/1877075

Closes: https://gitlab.gnome.org/GNOME/mutter/-/issues/1252

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1256

(cherry picked from commit 1d5f9b6917517d6e777a652cfa5e648794dc632a)
2020-05-15 12:49:12 +02:00
Florian Müllner
63bf5f1150 Bump version to 3.36.2
Update NEWS.
2020-04-29 22:22:12 +02:00
Jonas Ådahl
d9d8732096 clutter/stage: Use new paint API to implement capture()
This changes the semantics a bit, e.g. we will never include the pointer
cursor sprite, as there is no way to know whether the caller wants to or
not.

We also change things a bit so that when we render to an offscreen paint
context, we don't emit the "paint" signal on actors, as doing so would
end up recursing in gnome-shell's screenshot and screencast code.

Closes: https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/2567

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1222
2020-04-29 18:18:50 +02:00
Jonas Ådahl
797c349245 clutter/paint-context: Add 'no-cursors' paint flag
Will be used by the stage to not paint the overlays. We skip all
overlays since overlays are only ever used for pointer cursors when the
hardware cursors cannot or should not be used.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1222
2020-04-29 18:14:58 +02:00
Jonas Ådahl
b5691d6bf0 stage: Only invoke paint phase callbacks when painting views
These phase callbacks are not intended to be inovked when something
secondary is painting the stage, such as a screen cast stream, or
similar. Thus, only invoke the callbacks when there is a view associated
with the paint context, which will not be the case for offscreen
painting.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1222
2020-04-29 18:14:58 +02:00
Jonas Ådahl
c7ad9b33c2 clutter/stage: Add API to paint to a custom target
Either onto a framebuffer, or into a CPU memory buffer. The latter will
use an former API and then copy the result to CPU memory. The former
allocates an offscreen framebuffer, sets up the relevant framebuffer
matrices and paints part of the stage defined by the passed rectangle.

This will be used by a RecordArea screen cast API. The former to paint
directly onto PipeWire handled dma-buf framebuffers, and the latter for
PipeWire handled shared memory buffers.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1222
2020-04-29 18:14:58 +02:00
Jonas Ådahl
e49297975a stage: Pass paint context in phase callbacks
If there is a paint context available (i.e. for the phases that are
during the actual stage paint), pass it along the callbacks, so that
the callback implementations can change their operation depending on the
paint context state.

This also means we can get the current view from the paint context,
instead of the temporarily used field in the instance struct.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1222
2020-04-29 18:14:58 +02:00
Jonas Ådahl
858c12e73f clutter/paint-context: Add paint flag
A paint flag affects a paint operation in ways defined by the flags.
Currently no flags are defined, so no semantical changes are defined
yet. Eventually a flag aiming to avoid painting of cursors is going to
be added, so that screen cast streams can decide whether to include a
cursor or not.

Changes for gnome-3-36: Removed flag from offscreen context.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1222
2020-04-29 18:14:58 +02:00
Jonas Dreßler
b80b465a65 clutter/stage-cogl: Fix painting the redraw clip with the damage region
The redraw clip that's painted together with the damage region has to be
copied earlier than we do right now. That's because if
PAINT_DAMAGE_REGION is enabled, buffer age is disabled and thus
use_clipped_redraw is FALSE. That means the redraw_clip is updated and
set to the full view-rect. If we copy the queued_redraw_clip after that,
it's also going to be set to the full view-rect. So copy the redraw clip
a bit earlier to make sure we're actually passing the real redraw clip
to paint_damage_region().

Also keep the queued_redraw_clip around a bit longer so it can actually
be used by paint_damage_region() and isn't freed before that.

While at it, move paint_damage_region() from swap_framebuffer() into
clutter_stage_cogl_redraw_view() so we don't have to pass things to
swap_framebuffer() only for debugging.

Fixes https://gitlab.gnome.org/GNOME/mutter/-/issues/1104

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1208


(cherry picked from commit 793a9d45e14909b5c27219a7c41352c99b07f077)
2020-04-28 16:46:28 +00:00
Olivier Fourdan
2cc8061f35 keybindings: Mask out the reserved modifiers mask
When switching layouts, special modifiers bits may be be set for
internal use by Xkb.

As we now ignore a set of modifiers when processing the special
modifiers keys, we ought to also mask out those reserved modifiers
otherwise we would discard the [Super] key after switching layouts
in X11.

Closes: https://gitlab.gnome.org/GNOME/mutter/issues/1144
https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1219

(cherry picked from commit 61356caa0693f19ccb289597bbab5138319e7f3c)
2020-04-27 18:28:19 +02:00
Laurent Bigonville
dbecb93233 compositor: Only include meta-window-actor-wayland.h when building with wayland
https://gitlab.gnome.org/GNOME/mutter/-/issues/1074

(cherry picked from commit d26dc4ae44c1fa921f9e3524ee540e62b3a0ace1)
2020-04-27 16:05:45 +02:00
Olivier Fourdan
adbe09afc3 window-actor/x11: Cache the frame bounds
When resizing an X11 window with client side decorations, the shadow is
clipped by the frame bounds so that we don't need to paint the shadow
under the opaque areas covered by the window and its frame.

When the X11 client uses the EMWH synchronization mechanism (like all
gtk-3 based clients), the actual window may not be updated so that the
actual window and it frame may be behind the expected window frame
bounds, which gives the impression of de-synchronized shadows.

To avoid the issue, keep a copy of the frame bounds as a cache and only
update it when the client is not frozen so that the clipping occurs on
the actual content.

Closes: https://gitlab.gnome.org/GNOME/mutter/issues/1178
https://gitlab.gnome.org/GNOME/mutter/merge_requests/1214

(cherry picked from commit bd45a00fa33f2f9a999ead3ffaa178322d84f4d0)
2020-04-27 13:19:08 +02:00
Christian Kirbach
bfe9b333c0 Update German translation 2020-04-24 22:37:32 +00:00
Pekka Paalanen
06b0d41baf kms-impl/simple: Fix page_flip_data ref leak on fallback
If drmModePageFlip() or custom_page_flip_func fails, process_page_flip() was
forgetting to undo the ref taken for that call. This would leak page_flip_data.

The reference counting works like this:
- when created, ref count is 1
- when calling drmModePageFlip, ref count is increased to 2
- new: if flip failed, ref count is decreased back to 1
- if calling schedule_retry_page_flip(), it takes a ref internally
- if calling mode_set_fallback(), it takes a ref internally
- all return FALSE paths have an explicit unref
- return TRUE path has an explicit unref

This issue was found by code inspection and while debugging an unrelated issue
with debug prints sprinkled around. I am not aware of any end-user visible
issues being fixed by this, as the leak is small and probably very rare.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1209
(cherry picked from commit 36111270aa23dffdc757cb76f4ca01f3425bfbf2)
2020-04-24 14:19:44 +03:00
Pekka Paalanen
a62fe66a25 kms: Make GSource ready by default
When testing a laptop with intel and DisplayLink devices, attempting to set the
DL output as the only active output resulted in GNOME/Wayland freezing. The
main event loop was running fine, but nothing on screen would get updated once
the DL output become the only one. This patch fixes that issue.

DisplayLink USB 3 devices use an out-of-tree kernel DRM driver called EVDI.
EVDI can sometimes fail drmModePageFlip(). For me, the flip fails reliably when
hotplugging the DL dock and when changing display configuration to DL only.
Mutter has a workaround for failing flips, it just calls drmModeSetCrtc() and
that succeeds.

What does not work reliably in the fallback path is Mutter keeping track of the
pageflip. Since drmModePageFlip() failed, there will not be a pageflip event
coming and instead Mutter queues a callback in its stead. When you have more
than one output, some other output repainting will attempt to swap buffers and
calls wait_for_pending_flips() which has the side-effect of dispatching any
queued flip callbacks. With multiple outputs, you don't get stuck (unless they
all fail the exact same way at the same time?). When you have only one output,
it cannot proceed to repaint and buffer swap because the pageflip is not marked
complete yet. Nothing dispatches the flip callback, leading to the freeze.

The flip callback is intended to be an idle callback, implemented with a
GSource. It is supposed to be called as soon as execution returns to the main
event loop. The setup of the GSource is incomplete, so it will never dispatch.

Fix the GSource setup by setting its ready-time to be always in the past. That
gets it dispatched on the next cycle of the main event loop. This is now the
default behavior for all sources created by meta_kms_add_source_in_impl().
Sources that need a delay continue to do that by overriding the ready-time
explicitly.

An alternative solution could have been to implement GSource prepare and check
callbacks returning TRUE. However, since meta_kms_add_source_in_impl() is used
by flip retry code as well, and that code needs a delay through the ready-time,
I was afraid I might break the flip retry code. Hence I decided to use
ready-time instead.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1209
(cherry picked from commit 6e0cfd3e55d554360b7e6963b39bcf996121847b)
2020-04-24 14:19:44 +03:00
Carlos Garnacho
5f40493c84 core: Add private function to get the current selection owner
This is a bit untidy to expose, however may be necessary internally.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1186

(cherry picked from commit fbd6366eddf39704fb79be608dd22cb3fad328e6)
2020-04-22 01:33:10 +02:00
Carlos Garnacho
e8d9996c9c x11: Allow X11 clients to clear the selection
According to the XSetSelectionOwner libX11 documentation:

  [...] If the owner window it has specified in the request is later
  destroyed, the owner of the selection automatically reverts to None,
  but the last-change time is not affected.

This is indeed visible through the selection_timestamp field in
XFixesSelectionNotify events.

Use this to check whether the selection time is recent-ish (thus
likely coming from an explicit XSetSelectionOwner request) and honor
the client intent by setting a "NULL" owner. If the selection time
is too old, it's definitely an indication of the owner client being
closed, the scenario where we do want the clipboard manager to take
over.

This fixes two usecases:
- X11 LibreOffice / WPS clear the selection each time before copying
  its own content. Mutter's clipboard manager would see each of those
  as a hint to take over, competing with the client over selection
  ownership. This would simply no longer happen
- Password managers may want to clear the selection, which would be
  frustrated by our clipboard manager.

There's a slight window of opportunity for the heuristics to fail
though, if a X11 client sets the selection and closes within 50ms, we
would miss the clipboard manager taking over.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1206

(cherry picked from commit 5671f0a284a5875f7d964a4d368470c33581ba80)
2020-04-22 01:20:11 +02:00
Carlos Garnacho
5465c912c7 x11: Generalize x11 selection owner checks
Shuffle things so the x11 selection can check the current owner directly,
instead of its type.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1206

(cherry picked from commit a7e63bea6cac06216ed2f2b98b7112d41b704c36)
2020-04-22 01:20:11 +02:00
Carlos Garnacho
a32bb758f7 x11: Clear X11 selection source after unsetting owner
The X11 selection source was being preserved after unsetting its
ownership. This is no leak as it would be eventually replaced by
another source, or destroyed on finalize. But it's pointless to
keep it.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1206

(cherry picked from commit 94b3c334e5a141f68911c6e69fa2dab49ff260b7)
2020-04-22 01:20:11 +02:00
Carlos Garnacho
ac8075bbf5 x11: Forward current selection state when initializing X11 selections
Most visible with xwayland-on-demand, at the time of setting things up
for X11 selections, we don't forward the current state. This makes the
first started X11 app oblivious to eg. the current clipboard.

Syncing selections up at the time of initializing the X11 selection
stuff ensures that doesn't happen.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1186

(cherry picked from commit 167fd07e010e25feb7ff195706bf91d7c70d1273)
2020-04-22 01:20:11 +02:00
Carlos Garnacho
da9eb4718b wayland: Rely on MetaSelection::owner-changed for .selection event emission
We already have a signal callback that translates selection ownership changes to
data_device/primary .selection events. Given both will be run when a data source
is being replaced, and this event emission being deleted is kinda short sighted
in that in only knows about Wayland, rely entirely on MetaSelection::owner-changed
emission.

Fixes spurious .selection(null) events being sent when a compositor-local source
takes over the selection without the focus changing (eg. screenshot to clipboard).

Closes: https://gitlab.gnome.org/GNOME/mutter/-/issues/1160

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1204

(cherry picked from commit 1363246d4452c0eebf404f2668df9931d06eae92)
2020-04-19 21:51:33 +02:00
Carlos Garnacho
9ad61fe02f wayland: Do not cancel old data source when setting new selection
This is taken care already by the MetaSelection machinery, by
deactivating the previous selection source when setting a new one.
That works across X11 and internal selection sources. This
only works when replacing one wayland source with another, and
actually results in doubly .cancelled events due to the other
paths.

Closes: https://gitlab.gnome.org/GNOME/mutter/-/issues/1177

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1203

(cherry picked from commit 0b6560fac41beaf08d89d30b4450dc7318c5a740)
2020-04-19 21:51:06 +02:00
Carlos Garnacho
7a09d07b9c wayland: Shuffle wl_data_source.cancelled version checks on DnD
We are meant to send a .cancelled event after the drop is performed
in certain situations, but only for version>3 clients. Since this is
all version 3 business, only set the drop_performed flag for v3
clients. This drops the need to perform version checks at the time
of cancelling (which is present for other usecases in v1).

Fixes emission of wl_data_source.cancelled for v1 clients.

Closes: https://gitlab.gnome.org/GNOME/mutter/-/issues/1177

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1203

(cherry picked from commit d4c3870286353e58d7e4c95111f1cdd354ba17ce)
2020-04-19 21:50:48 +02:00
Carlos Garnacho
456e6f345d core: Cater for reading selection in chunks
For the cases where we read a fixed size from the selection (eg. imposing
limits for the clipboard manager), g_input_stream_read_bytes_async() might
not read up to this given size if the other side is spoonfeeding it content.

Cater for multiple read/write cycles here, until (maximum) transfer size is
reached.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1198

(cherry picked from commit 4bdf9a1e70e8aef0066fb3af72ad580069b02fa1)
2020-04-19 21:48:31 +02:00
Carlos Garnacho
20cf6b630d x11: Do not trust there is task in error paths
Flushing the X11 selection output stream may happen synchronously or
implicitly, in which case there is not a task to complete. Check there
is actually a task before returning errors. We additionally set the
pipe_error flag, so future operations will fail with an error, albeit
with a more generic message.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1198

(cherry picked from commit 1909977a6787d6e06d4931df158b821f6fb35ad1)
2020-04-19 21:48:09 +02:00
Carlos Garnacho
1e17f8813b x11: Don't stall on write_async()
If a write_async() comes up while we are flushing on the background,
the task will be queued, but not deemed a reason on itself to keep
flushing (and finish the task) after a property delete event.

To fix this, do not ever queue up write_async tasks (this leaves
priv->pending_task only used for flush(), so the "flush to end"
behavior in the background is consistent). We only start a
background flush if there's reasons to do it, but the tasks are
immediately finished.

All data will still be ensured to be transfered on flush/close,
this makes the caller in this situation still able to reach to it.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1198

(cherry picked from commit 655a783891ac38c01834cb6d9631aa5834666892)
2020-04-19 21:47:49 +02:00
Carlos Garnacho
d985517573 x11: Fix iterative INCR property checks
It does not make sense to check for the stream not being closed,
this might happen multiple times during the lifetime of the stream
for a single transfer. We want to notify the INCR transfer just
once.

Check for the explicit conditions that we want, that the remaining
data is bigger than we can transfer at once, and that we are not
yet within the INCR transfer.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1198

(cherry picked from commit a4596becc43959c3cd049fd49a236a9920fd9f24)
2020-04-19 21:47:27 +02:00
Carlos Garnacho
107bb3d9c2 x11: Don't exceed transfer size in INCR chunks
The stream automatically flushes after data size exceeds the
size we deem for INCR chunks, but we still try to copy it all.
Actually limit the data we copy, and leave the rest for future
INCR chunks.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1198

(cherry picked from commit 7015bb3efd5e588e50be9948f32ee04fa4bd8319)
2020-04-19 21:47:06 +02:00
Carlos Garnacho
b1c47c6213 x11: Don't invariably queue a pending delete request
We don't need doing this roundtrip for non-INCR transfers.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1198

(cherry picked from commit d2c762cc66718f1b79bb476b68439d00a16fd2a2)
2020-04-19 21:46:36 +02:00
Carlos Garnacho
c43f178495 x11: Finish INCR transfers properly
INCR transfers are mandated to finish with a final 0-size XChangeProperty
roundtrip after the final data chunk. Actually honor this and ensure we
iterate just once more for this.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1198

(cherry picked from commit 04d429b743a641c81e2fd8b683a8ec40775b3213)
2020-04-19 21:46:14 +02:00
Carlos Garnacho
c46bea9dff x11: Wait till data is flushed before notifying on the pending task
It does not make sense to notify flushes mid-transfer. We should wait
till the data is actually finished before notifying on the pending
task.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1198

(cherry picked from commit 0b21dcfe08c9a3ac137da518d6ef5f3a80528883)
2020-04-19 21:45:36 +02:00
Carlos Garnacho
622e8c348f x11: Only send SelectionNotify on first INCR chunk
This should only be sent if the selection can be sent at once, or
if we are right about to notify on the first chunk of an INCR
transfer.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1198

(cherry picked from commit 7c939d78c2b20989412a710665cbbea6b12ff8dd)
2020-04-19 21:45:15 +02:00
Carlos Garnacho
51b65b98f5 x11: Ensure flush() Flushes all output stream data
This seemed to work under the assumption that a flush() call can
only result in one INCR roundtrip. This is evidently not true, so
we should hold things off until all pending data is actually flushed.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1198

(cherry picked from commit 8a2b82897db66b3edbe985a370429b4f36b9918c)
2020-04-19 21:44:42 +02:00
Carlos Garnacho
7ec0a9dd68 x11: Unset pending flush flag right before notifying on task
Together with some other state. We can do this altogether on task
notification, instead of lost somewhere in this function flow.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1198

(cherry picked from commit e95c365cf01837862f87dea90190b47392ee7f67)
2020-04-19 21:44:23 +02:00
Carlos Garnacho
6ce42e100f x11: Intern INCR atom
We want to use it, despite it not existing previously.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1198

(cherry picked from commit a32cb7133b1dc97f02ad20496fd03908f0d9328e)
2020-04-19 21:44:06 +02:00
Carlos Garnacho
13a23f16c1 x11: Flag flushes despite having less than the element size
If say we want 32bit data, but have 2 bytes stored, we would simply
ignore flush requests. Allow (and don't clear) the needs_flush flag
if we have less than the element size accumulated.

Instead handle this in can_flush(), so it's triggered whenever we
have enough data to fill 1 element, or if the stream is closing
(seems a broken situation, but triggered by the caller).

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1198

(cherry picked from commit 967966cdee13306501eacd3f25791f56d1fc8249)
2020-04-19 21:43:45 +02:00
Carlos Garnacho
40dc22659b x11: XMaxRequestSize returns 4-byte units
XMaxRequestSize/XMaxExtendedRequestSize are documented to return
the maximum size in 4-byte units, whereas we are comparing this
to byte lenghts. We can afford 4x the data here.

Since I don't know the payload size of the XChangeProperty request,
be generous and allot 400 bytes for it, we have some to spare.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1198

(cherry picked from commit 06d67b6abfd4d5ed8ceecd998b08cd1103946f26)
2020-04-19 21:43:20 +02:00
Marco Trevisan (Treviño)
fdcb68f4d0 monitor-unit-tests: Ensure configuration is preserved in laptop with closed lid
https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1200


(cherry picked from commit f15ce01e2b48ec0127367392d6d49153fadea087)
2020-04-16 16:09:54 +00:00
Marco Trevisan (Treviño)
17491bae06 monitor-config-manager: Fallback to closed laptop lid configuration
When closing the lid of a laptop, we reconfigure all the monitors in order
to update the CRTCs and (if enabled) the global UI scaling factor.

To do this, we try first to reuse the current configuration for the usable
monitors, but if we have only monitor enabled and this one is on the laptop
lid we just end up creating a new configuration where the primary monitor is
the laptop one (as per find_primary_monitor() in MetaMonitorConfigManager),
but ignoring the user parameters.

In case the user selected a different resolution / scaling compared to the
default one, while the laptop lid is closed we might change the monitors
layout, causing applications to rescale or reposition.

To avoid this, when creating the monitors configuration from the current
current state, in case we have only one monitor available and that one is
the laptop panel, let's just reuse this configuration.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1200


(cherry picked from commit e48516679c02bb265a80d6680a4ea34d188127e0)
2020-04-16 16:09:38 +00:00
Jonas Ådahl
568876da95 cursor-renderer-native: Take CRTC transform into account
The CRTC level transform (not necessarily the hw transform) must be
taken into account when calculating the position of the CRTC in the
stage coordinate space, when placing the hw cursor, otherwise we'll
place the cursor as if the monitor was not rotated.

This wasn't a problem in the past, as with rotation, we always used the
OpenGL cursor, so the issue newer showed.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1199
2020-04-15 17:53:50 +02:00
Jonas Ådahl
ea546a8b90 renderer-native: Use CRTC layout in stage view
The port to per CRTC views was incomplete; we still used the logical
monitor layout as the stage view layout, while still using one view per
CRTC.

This worked fine for most cases, e.g. regular monitors, tiled or
non-tiled, transformed or non-transformed. Where it broke, however, was
when a monitor consists of multiple CRTCs. We already have the layout a
CRTC corresponds to on the stage kept with the CRTC metadata, so use
this directly.

Closes: https://gitlab.gnome.org/GNOME/mutter/-/issues/1170

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1199`
2020-04-15 17:53:50 +02:00
Jonas Ådahl
e8f29a3336 tests/monitor-unit-tests: Test non-hw-transform rotated tiled monitors
Should affect the assigned transform, but not the layout, as that is the
layout on the stage, not the coordinates in any buffer.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1199
2020-04-15 17:53:50 +02:00
Jonas Ådahl
5e9986bbcb monitor-config-manager: Only use crtc transform for assignment
The CRTC level transform (i.e. not necessarily the one set on the
hardware) is what is relevant for calculating the layout the CRTC will
have on the stage, so only use the one that can be handled by the
hardware for the CRTC assignment.

This makes the CRTC layout valid for tiled monitors.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1199
2020-04-15 17:53:50 +02:00
Jonas Ådahl
3edf6a5292 monitor: Fix tile coordinate calculation
Previously the tile coordinate was used to offset a CRTC scanout
coordinate within a larger framebuffer. Since 3.36 we're always
scanning out from (0, 0) as we always have one framebuffer per CRTC; we
instead use the tile coordinate to calculate the coordinate the tile has
in the stage view. Adapt calculation to fulfil this promise instead of
the old one.

This also corrects the tiled custom monitor test case.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1199
2020-04-15 17:53:50 +02:00
Phillip Wood
ad500ef4e5 input-settings: fix device list iteration
Dereference the loop variable rather than the original list head. This
fixes a regression introduced in 4413b86a3 ("backends: Replace
ClutterDeviceManager usage in favor of ClutterSeat", 2019-10-04) which
broke button scrolling with trackballs.

Closes:https://gitlab.gnome.org/GNOME/mutter/-/issues/1120

(cherry picked from commit 3e967d731a730cb4afb46f115570bb25f54c4195)
2020-04-12 23:43:01 +02:00
Olivier Fourdan
9a2471db47 wayland: preserve xkb_state on VT switch
On VT switch, the devices are removed, which means for Wayland disabling
the keyboard.

When the keyboard is disabled, the associated `xkb_state` is freed and
recreated whenever the keyboard is re-enabled when switching back to the
compositor VT.

That means the `xkb_state` for Wayland is lost whereas the same for
clutter is kept, which causes to a discrepancy with locked modifiers on
VT switch.

To avoid that issue, preserve the XKB info only to dispose it when the
keyboard is eventually finalized.

Closes: https://gitlab.gnome.org/GNOME/mutter/issues/344
https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1185


(cherry picked from commit 5b30a52bbda87f903d7008d09d1d70cd750cac4a)
2020-04-08 14:04:02 +00:00
Carlos Garnacho
db164bcfa2 wayland/xdnd: Add error traps around Xdnd* IPC
Make all of them spew criticals, except for XdndLeave as it's feasible
to expect the window we are sending the event to did disappear in the
way (eg. if the window is destroyed while the DnD operation is ongoing
and the pointer is over the window).

Fixes: https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/2590

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1184
2020-04-07 20:38:02 +02:00
Jonas Troeger
83553e3f6e backends/native: Translate coordinates of absolute motion events
The motion events of tablets for example need to be mapped on the
selected screen area if the input device is configured to use only a
part of the active logical monitor.
To achieve this behavior each motion event is transformed using the
transformation matrix set for the input device.

Closes: https://gitlab.gnome.org/GNOME/mutter/-/issues/1118
2020-04-07 20:37:53 +02:00
Carlos Garnacho
3b2f6ae93d backends/x11: Fix access to WacomDevice
At some point we crossed the streams... In a short timespan we had
1f00aba92c32 merged, pushing WacomDevice to a common parent object,
and dcaa45fc0c199 implementing device grouping for X11.

The latter did not rely on the former, and just happened to
merge/compile without issues, but would promptly trigger a crash
whenever the API would be used.

Drop all traces of the WacomDevice internal to MetaInputDeviceX11.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1183


(cherry picked from commit f0718c7d95820a38a54222ff362c76c2f7e0ec58)
2020-04-07 17:48:09 +00:00
Jonas Dreßler
bc47f0a1ac clutter/stage: Don't assume stage relayouts reallocate everything
With the introduction of "shallow" relayouts, we are now able to enter
allocation cycles not only at the stage but also deeper down the
hierarchy if we know an actors allocation isn't affected by its children
since the NO_LAYOUT flag is set.

Now that means when queuing relayouts it's possible that
`priv->needs_allocation` gets set to TRUE for some actors down the
hierarchy, but not for actors higher up in the hierarchy. An actor tree
where that happens could look like that:

stage -> container -> container2 (NO_LAYOUT) -> textActor

With that tree, if the "textActor" queues a relayout, "container2" will
be added to the relayout hashtable of the stage and the actors "stage"
and "container" will have `priv->needs_allocation` set to FALSE.

Now if another relayout on the stage actor is queued,
`clutter_stage_queue_actor_relayout()` currently removes all the other
hashtable entries in favour of the stage entry, (wrongly) assuming that
will allocate everything. It doesn't allocate everything because in the
example above "container" has `priv->needs_allocation` set to FALSE,
which makes clutter_actor_allocate() return early before allocating its
children, so in the end "container2" will never get a new allocation.

To fix this, stop flushing the relayout hashtable when queuing a
stage-relayout and still add new entries to the hashtable if a stage
relayout is already queued to make sure we still go through all the
previously queued "shallow" relayouts. That shouldn't hurt performance,
too, because as soon as an actor got allocated once, it doesn't need an
allocation anymore and should bail out in clutter_actor_allocate() as
long as it's absolute position didn't change.

Fixes https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/2538

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1173


(cherry picked from commit e74c2e42cf3dc744aaa53cb5a683138425cda9b6)
2020-04-07 16:47:32 +00:00
Jonas Ådahl
c8986d19e5 window: Check aliveness a bit less aggressively
Currently we check whether a window is alive everytime it's focused.
This means that an application that doesn't respond to the check-alive
event during startup always showing the "application froze" dialog,
without the user ever trying to interact with it.

An example where this tends to to happen is with games, and for this
particular scenario, it's purely an annoyance, as I never tried to
interact with the game window in the first place, so I don't care that
it's not responding - it's loading.

To avoid these unnecessary particular "app-is-frozen" popups, remove the
alive check from the focus function, and instead move it back to the
"meta_window_activate_full()" call. To also trigger it slightly more
often, also add it to the path that triggers the window focus when a
user actively clicks on the window.

This means that we currently check whether a window is alive on:

  * Any time the window is activated. This means e.g. alt-tab or
    selecting the window in the overview.
  * The user clicks on the window.

Note that the second only works for an already focused window on
Wayland, as on X11, we don't refocus it. This particular case isn't
changed with this commit, as we didn't call meta_window_focus() to begin
with here.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1182


(cherry picked from commit 8df3b21a51b0e8dcea4a4376426880e4f3c4f837)
2020-04-07 13:23:21 +00:00
Christian Rauch
7baabc7ed0 x11: fix compilation if 'libwacom=false'
https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1168


(cherry picked from commit a8f6cada883eda2a34e6478a53e2fb7c392d98b7)
2020-04-06 14:57:57 +00:00
Dušan Kazik
b0709504ea Update Slovak translation 2020-04-05 20:22:08 +00:00
Jonas Ådahl
7e94311e2e window-actor: Set viewport when blitting to screencast fb
This fixes an issue where a non-maximized screen casted window would be
stretched to fill the whole screen cast stream, instead of just the crop
that corresponds to the current window size.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1174


(cherry picked from commit a6f94696e2e8ade9e800f3b37092a5f40e22cf38)
2020-04-03 16:30:26 +00:00
Simon McVittie
e339a57ddf cogl: Defend against empty or unallocated framebuffers
It isn't immediately obvious that this is impossible, because there's some
"action at a distance" going on with framebuffers that have their size
set lazily, after their textures get allocated; so let's make this a
critical warning rather than crashing.

In particular, this works around a crash when gnome-shell tries to blur a
background that hasn't yet had any space allocated for it - which it seems
is really an actor layout bug, but more robustness seems good to have.

Workaround for <https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/2538>.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1172

Signed-off-by: Simon McVittie <smcv@debian.org>

(cherry picked from commit c389aadff933c2d4c7fbe4f2b0864832dec40461)
2020-04-03 13:49:34 +02:00
Simon McVittie
e3b2b90c72 cogl: Don't allow creating sized textures with 0 pixels
A texture with no pixels isn't a useful thing to have, and breaks
assumptions elsewhere. For example, CoglFramebuffer assumes that after
a texture has been allocated, it will have width and height both greater
than 0.

In particular, this works around a crash when gnome-shell tries to blur a
background that hasn't yet had any space allocated for it - which it seems
is really an actor layout bug, but more robustness seems good to have.

Workaround for <https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/2538>.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1172

Signed-off-by: Simon McVittie <smcv@debian.org>

(cherry picked from commit 37eda498f2de2cf787a5e65d6f0248e4a8e33490)
2020-04-03 13:48:46 +02:00
Daniel van Vugt
6f094bd399 clutter/master-clock-default: Sync timelines to hardware vsync
Previously clutter timelines advanced according to `g_source_get_time`.
But that meant the spatial stepping of animations was visibly sensitive to
any irregularities in the main loop. It also represented a time older [1]
than the intended presentation time of each frame.

Now we instead use `master_clock_get_next_presentation_time`. This ensures
we get the smoothness of hardware vsync as well as being closer to the
actual presentation time.

This means, for example, backends like Xorg that move the hardware cursor
independently of repaints will have their animations more closely matching
the hardware cursor position. So the cursor appears to stick more closely
when dragging windows or on the lock screen etc.

[1] "older" = (refresh_interval - sync_delay) = ~14ms for 60Hz

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

https://gitlab.gnome.org/GNOME/mutter/merge_requests/724
2020-04-03 10:59:36 +00:00
Daniel van Vugt
2c805524b4 clutter/stage: Add API to get_next_presentation_time
https://gitlab.gnome.org/GNOME/mutter/merge_requests/724
2020-04-03 10:59:36 +00:00
Andre Moreira Magalhaes
95c1baf3d1 clutter/click-action: Do not process captured event if action is disabled
Disabling a click action after a button-press but before a
button-release is captured makes ClutterClickAction connect to
captured-event and never disconnect.

This change fixes it by making sure the captured-event is only
processed if the action is still enabled, otherwise releasing
the action (reset state) and propagating the event.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1170


(cherry picked from commit 5f5ce08ba4f6320f27e53440a0ee8d9799e05cf6)
2020-04-02 17:09:24 +00:00
Georges Basile Stavracas Neto
6f9b5edd4d tests/actor-pick: Allocate actor before picking
Picking now only happens on allocated actors, but the
callback in the actor-pick test is not waiting for the
stage to run an allocation cycle. Ideally, we'd wait
for this cycle, but for now, forcing an allocation works
as well.

Allocate the overlay actor in the actor-pick test.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1169


(cherry picked from commit 7f488e3e1d13f54ff1bbc9b43ee64cd2dfa82905)
2020-03-31 23:13:42 +00:00
Georges Basile Stavracas Neto
31809e1214 tests/actor-pick: Remove tabs
They're evil.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1169


(cherry picked from commit 059d2144b2f5de2b5c0669935b5dda04eb73e01e)
2020-03-31 23:13:15 +00:00
Andre Moreira Magalhaes
82f3bdd14e clutter/actor: Fix pick when actor is not allocated
When selecting the pick regions for an actor we were not considering
whether the actor was allocated and that was causing issues where the
preferred width/height of the actor was used when deciding whether
the actor should be considered as a pick target.

Check if the actor has a valid allocation, in addition to being mapped
and being in pick mode, in clutter_actor_should_pick_paint().

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1169


(cherry picked from commit 902302a174483eabe796227a3fc82a36770f40b2)
2020-03-31 23:12:44 +00:00
105 changed files with 4711 additions and 1987 deletions

74
NEWS
View File

@ -1,3 +1,77 @@
3.36.5
======
* Screencast fixes and improvements [Jonas; !1351, !1365]
* Fix glitches when subsurfaces extend outside the toplevel [Robert; #1316]
* Mipmap background texture rendering [Daniel; !1347]
* Fix wine copy & paste [Sebastian; !1369]
* Plugged memory leaks [Marco, Thomas; !1195]
Contributors:
Jonas Ådahl, Thomas Hindoe Paaboel Andersen, Sebastian Keller, Robert Mader,
Marco Trevisan (Treviño), Daniel van Vugt
Translators:
Rafael Fontenelle [pt_BR]
3.36.4
======
* Fix crash on area screenshots with fractional scaling [Sebastian; !1320]
* Do not paint textures of fully obscured windows [Robert; !1326]
* Turn off CRTCs as well when enabling DPMS [Michel; !1240]
* Improve selection support
[Robert, Carlos, Sebastian; !1330, !1193, !1253, !1255, !1293, !1350]
* Use a more appropriate combine function on opaque areas [Daniel; !1331]
* Fix remote desktop being broken without screencast session [Olivier; #1307]
* Fix popovers disappearing on wayland and HiDPI [Robert; #1312]
* Fixed crashes [Jonas Å.; !1317]
* Plugged memory leaks [Jonas Å.; !1283]
* Misc. bug fixes and cleanups
[Corentin, Sebastian, Jonas Å., Jonas D.; !1314, !1321, !1295, !1333]
Contributors:
Jonas Dreßler, Michel Dänzer, Olivier Fourdan, Carlos Garnacho,
Sebastian Keller, Robert Mader, Corentin Noël, Daniel van Vugt, Jonas Ådahl
3.36.3
======
* Broadcast clipboard/primary offers [Carlos; !1262]
* Fix monitor screen cast on X11 [Jonas Å.; !1251]
* Implement touch-mode detecation for the X11 backend [Carlos; !1278]
* Drop external keyboard detection from touch-mode heuristics [Carlos; !1277]
* Fix leaked DMA buffers in screencasts [Jonas; !1283]
* Fixed crashes [Daniel, Carlos, Jonas D.; !1256, !1258, !1280]
Contributors:
Carlos Garnacho, Daniel van Vugt, Jonas Ådahl
3.36.2
======
* Sync timelines to hardware vsync [Daniel; !724]
* Fix screencasting non-maximized windows [Jonas; !1174]
* Make window-aliveness checks less aggressive [Jonas; !1182]
* Fix stylus coordinates when using screen rotation [Jonas T.; #1118]
* Preserve keyboard state on VT switch [Olivier; !1185]
* Fix trackball button scrolling [Phillip; #1120]
* Fix tiled monitor support [Jonas Å.; !1199]
* Fix various clipboard issues [Carlos; !1198, !1203, !1204, !1186, !1206]
* Synchronize shadows to server-side decorations [Olivier; !1214]
* Fix overview key on X11 when using multiple keyboard layouts [Olivier; !1219]
* Fix capturing with multiple stage views [Jonas Å.; !1222]
* Fixed crashes [Jonas D., Carlos; !1173, !1183]
* Misc. bug fixes and cleanups [Andre, Georges, Simon, Christian, Carlos, Marco,
Pekka, Laurent, Jonas D.; !1169, !1170, !1172, !1168, !1184, !1200, !1209,
#1074, !1208]
Contributors:
Marco Trevisan (Treviño), Laurent Bigonville, Jonas Dreßler, Olivier Fourdan,
Carlos Garnacho, Andre Moreira Magalhaes, Simon McVittie,
Georges Basile Stavracas Neto, Pekka Paalanen, Christian Rauch, Jonas Troeger,
Daniel van Vugt, Phillip Wood, Jonas Ådahl
Translators:
Dušan Kazik [sk], Christian Kirbach [de]
3.36.1
======
* Fix hardware cursor on GPU hotplpug [Pekka; !1097]

View File

@ -2410,6 +2410,7 @@ clutter_actor_should_pick_paint (ClutterActor *self)
g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
if (CLUTTER_ACTOR_IS_MAPPED (self) &&
clutter_actor_has_allocation (self) &&
(_clutter_context_get_pick_mode () == CLUTTER_PICK_ALL ||
CLUTTER_ACTOR_IS_REACTIVE (self)))
return TRUE;
@ -2603,6 +2604,9 @@ clutter_actor_set_allocation_internal (ClutterActor *self,
gboolean retval;
ClutterActorBox old_alloc = { 0, };
g_return_val_if_fail (!isnan (box->x1) && !isnan (box->x2) &&
!isnan (box->y1) && !isnan (box->y2), FALSE);
obj = G_OBJECT (self);
g_object_freeze_notify (obj);
@ -4193,7 +4197,9 @@ clutter_actor_continue_paint (ClutterActor *self,
clutter_paint_node_unref (dummy);
/* XXX:2.0 - Call the paint() virtual directly */
if (g_signal_has_handler_pending (self, actor_signals[PAINT],
if (!(clutter_paint_context_get_paint_flags (paint_context) &
CLUTTER_PAINT_FLAG_NO_PAINT_SIGNAL) &&
g_signal_has_handler_pending (self, actor_signals[PAINT],
0, TRUE))
g_signal_emit (self, actor_signals[PAINT], 0, paint_context);
else
@ -10363,6 +10369,11 @@ clutter_actor_allocate (ClutterActor *self,
old_allocation = priv->allocation;
real_allocation = *box;
g_return_if_fail (!isnan (real_allocation.x1) &&
!isnan (real_allocation.x2) &&
!isnan (real_allocation.y1) &&
!isnan (real_allocation.y2));
/* constraints are allowed to modify the allocation only here; we do
* this prior to all the other checks so that we can bail out if the
* allocation did not change

View File

@ -475,8 +475,10 @@ get_preferred_size_for_orientation (ClutterBoxLayout *self,
ClutterActor *child;
gint n_children = 0;
gfloat minimum, natural;
float largest_min_size, largest_nat_size;
minimum = natural = 0;
largest_min_size = largest_nat_size = 0;
clutter_actor_iter_init (&iter, container);
while (clutter_actor_iter_next (&iter, &child))
@ -491,8 +493,22 @@ get_preferred_size_for_orientation (ClutterBoxLayout *self,
get_child_size (child, priv->orientation,
for_size, &child_min, &child_nat);
minimum += child_min;
natural += child_nat;
if (priv->is_homogeneous)
{
largest_min_size = MAX (largest_min_size, child_min);
largest_nat_size = MAX (largest_nat_size, child_nat);
}
else
{
minimum += child_min;
natural += child_nat;
}
}
if (priv->is_homogeneous)
{
minimum = largest_min_size * n_children;
natural = largest_nat_size * n_children;
}
if (n_children > 1)
@ -623,6 +639,8 @@ get_preferred_size_for_opposite_orientation (ClutterBoxLayout *self,
}
else
{
size -= (nvis_children - 1) * priv->spacing;
/* Bring children up to size first */
if (isnormal (size) || size == 0)
{

View File

@ -346,6 +346,12 @@ on_captured_event (ClutterActor *stage,
ClutterModifierType modifier_state;
gboolean has_button = TRUE;
if (!clutter_actor_meta_get_enabled (CLUTTER_ACTOR_META (action)))
{
clutter_click_action_release (action);
return CLUTTER_EVENT_PROPAGATE;
}
actor = clutter_actor_meta_get_actor (CLUTTER_ACTOR_META (action));
switch (clutter_event_type (event))

View File

@ -190,6 +190,26 @@ master_clock_get_swap_wait_time (ClutterMasterClockDefault *master_clock)
}
}
static int64_t
master_clock_get_next_presentation_time (ClutterMasterClockDefault *master_clock)
{
ClutterStageManager *stage_manager = clutter_stage_manager_get_default ();
const GSList *stages, *l;
int64_t earliest = -1;
stages = clutter_stage_manager_peek_stages (stage_manager);
for (l = stages; l != NULL; l = l->next)
{
gint64 t = _clutter_stage_get_next_presentation_time (l->data);
if (earliest == -1 || (t != -1 && t < earliest))
earliest = t;
}
return earliest;
}
static void
master_clock_schedule_stage_updates (ClutterMasterClockDefault *master_clock)
{
@ -466,7 +486,11 @@ clutter_clock_dispatch (GSource *source,
COGL_TRACE_BEGIN (ClutterMasterClockTick, "Master Clock (tick)");
/* Get the time to use for this frame */
master_clock->cur_tick = g_source_get_time (source);
master_clock->cur_tick = master_clock_get_next_presentation_time (master_clock);
/* On the first frame the backend might not have an answer */
if (master_clock->cur_tick <= 0)
master_clock->cur_tick = g_source_get_time (source);
#ifdef CLUTTER_ENABLE_DEBUG
master_clock->remaining_budget = master_clock->frame_budget;

View File

@ -30,6 +30,7 @@
#include "clutter-input-device-private.h"
#include "clutter-input-pointer-a11y-private.h"
#include "clutter-macros.h"
#include "clutter-paint-context-private.h"
#include "clutter-private.h"
#include "clutter-stage-private.h"
#include "clutter-stage-view.h"
@ -48,6 +49,23 @@ void clutter_stage_capture_into (ClutterStage *stage,
cairo_rectangle_int_t *rect,
uint8_t *data);
CLUTTER_EXPORT
void clutter_stage_paint_to_framebuffer (ClutterStage *stage,
CoglFramebuffer *framebuffer,
const cairo_rectangle_int_t *rect,
float scale,
ClutterPaintFlag paint_flags);
CLUTTER_EXPORT
gboolean clutter_stage_paint_to_buffer (ClutterStage *stage,
const cairo_rectangle_int_t *rect,
float scale,
uint8_t *data,
int stride,
CoglPixelFormat format,
ClutterPaintFlag paint_flags,
GError **error);
CLUTTER_EXPORT
void clutter_stage_freeze_updates (ClutterStage *stage);

View File

@ -20,11 +20,22 @@
#include "clutter-paint-context.h"
typedef enum _ClutterPaintFlag
{
CLUTTER_PAINT_FLAG_NONE = 0,
CLUTTER_PAINT_FLAG_NO_CURSORS = 1 << 0,
CLUTTER_PAINT_FLAG_NO_PAINT_SIGNAL = 1 << 1,
} ClutterPaintFlag;
ClutterPaintContext * clutter_paint_context_new_for_view (ClutterStageView *view,
const cairo_region_t *redraw_clip);
const cairo_region_t *redraw_clip,
ClutterPaintFlag paint_flags);
gboolean clutter_paint_context_is_drawing_off_stage (ClutterPaintContext *paint_context);
CoglFramebuffer * clutter_paint_context_get_base_framebuffer (ClutterPaintContext *paint_context);
CLUTTER_EXPORT
ClutterPaintFlag clutter_paint_context_get_paint_flags (ClutterPaintContext *paint_context);
#endif /* CLUTTER_PAINT_CONTEXT_PRIVATE_H */

View File

@ -23,6 +23,8 @@ struct _ClutterPaintContext
{
grefcount ref_count;
ClutterPaintFlag paint_flags;
GList *framebuffers;
ClutterStageView *view;
@ -36,7 +38,8 @@ G_DEFINE_BOXED_TYPE (ClutterPaintContext, clutter_paint_context,
ClutterPaintContext *
clutter_paint_context_new_for_view (ClutterStageView *view,
const cairo_region_t *redraw_clip)
const cairo_region_t *redraw_clip,
ClutterPaintFlag paint_flags)
{
ClutterPaintContext *paint_context;
CoglFramebuffer *framebuffer;
@ -45,6 +48,7 @@ clutter_paint_context_new_for_view (ClutterStageView *view,
g_ref_count_init (&paint_context->ref_count);
paint_context->view = view;
paint_context->redraw_clip = cairo_region_copy (redraw_clip);
paint_context->paint_flags = paint_flags;
framebuffer = clutter_stage_view_get_framebuffer (view);
clutter_paint_context_push_framebuffer (paint_context, framebuffer);
@ -62,6 +66,8 @@ clutter_paint_context_new_for_framebuffer (CoglFramebuffer *framebuffer)
paint_context = g_new0 (ClutterPaintContext, 1);
g_ref_count_init (&paint_context->ref_count);
paint_context->paint_flags = (CLUTTER_PAINT_FLAG_NO_CURSORS |
CLUTTER_PAINT_FLAG_NO_PAINT_SIGNAL);
clutter_paint_context_push_framebuffer (paint_context, framebuffer);
@ -170,3 +176,12 @@ clutter_paint_context_is_drawing_off_stage (ClutterPaintContext *paint_context)
return !paint_context->view;
}
/**
* clutter_paint_context_get_paint_flags: (skip)
*/
ClutterPaintFlag
clutter_paint_context_get_paint_flags (ClutterPaintContext *paint_context)
{
return paint_context->paint_flags;
}

View File

@ -682,7 +682,6 @@ clutter_seat_warp_pointer (ClutterSeat *seat,
* requirements are fulfilled:
*
* - A touchscreen is available
* - No external keyboard is attached to the device
* - A tablet mode switch, if present, is enabled
*
* Returns: %TRUE if the device is a tablet that doesn't have an external

View File

@ -78,6 +78,7 @@ void _clutter_stage_schedule_update (ClutterStage *stage);
gint64 _clutter_stage_get_update_time (ClutterStage *stage);
void _clutter_stage_clear_update_time (ClutterStage *stage);
gboolean _clutter_stage_has_full_redraw_queued (ClutterStage *stage);
int64_t _clutter_stage_get_next_presentation_time (ClutterStage *stage);
void clutter_stage_log_pick (ClutterStage *stage,
const graphene_point_t *vertices,

View File

@ -178,6 +178,22 @@ _clutter_stage_window_clear_update_time (ClutterStageWindow *window)
iface->clear_update_time (window);
}
int64_t
_clutter_stage_window_get_next_presentation_time (ClutterStageWindow *window)
{
ClutterStageWindowInterface *iface;
g_return_val_if_fail (CLUTTER_IS_STAGE_WINDOW (window), 0);
iface = CLUTTER_STAGE_WINDOW_GET_IFACE (window);
/* If not implemented then just revert to the old behaviour... */
if (iface->get_next_presentation_time == NULL)
return _clutter_stage_window_get_update_time (window);
return iface->get_next_presentation_time (window);
}
void
_clutter_stage_window_set_accept_focus (ClutterStageWindow *window,
gboolean accept_focus)

View File

@ -61,6 +61,8 @@ struct _ClutterStageWindowInterface
GList *(* get_views) (ClutterStageWindow *stage_window);
int64_t (* get_frame_counter) (ClutterStageWindow *stage_window);
void (* finish_frame) (ClutterStageWindow *stage_window);
int64_t (* get_next_presentation_time) (ClutterStageWindow *stage_window);
};
ClutterActor * _clutter_stage_window_get_wrapper (ClutterStageWindow *window);
@ -101,6 +103,8 @@ void _clutter_stage_window_finish_frame (ClutterStageWin
int64_t _clutter_stage_window_get_frame_counter (ClutterStageWindow *window);
int64_t _clutter_stage_window_get_next_presentation_time (ClutterStageWindow *window);
G_END_DECLS
#endif /* __CLUTTER_STAGE_WINDOW_H__ */

View File

@ -934,7 +934,8 @@ clutter_stage_do_paint_view (ClutterStage *stage,
ClutterPaintContext *paint_context;
cairo_rectangle_int_t clip_rect;
paint_context = clutter_paint_context_new_for_view (view, redraw_clip);
paint_context = clutter_paint_context_new_for_view (view, redraw_clip,
CLUTTER_PAINT_FLAG_NONE);
cairo_region_get_extents (redraw_clip, &clip_rect);
setup_view_for_pick_or_paint (stage, view, &clip_rect);
@ -1320,15 +1321,9 @@ clutter_stage_queue_actor_relayout (ClutterStage *stage,
{
ClutterStagePrivate *priv = stage->priv;
if (g_hash_table_contains (priv->pending_relayouts, stage))
return;
if (g_hash_table_size (priv->pending_relayouts) == 0)
_clutter_stage_schedule_update (stage);
if (actor == (ClutterActor *) stage)
g_hash_table_remove_all (priv->pending_relayouts);
g_hash_table_add (priv->pending_relayouts, g_object_ref (actor));
priv->pending_relayouts_version++;
}
@ -3751,6 +3746,21 @@ _clutter_stage_clear_update_time (ClutterStage *stage)
_clutter_stage_window_clear_update_time (stage_window);
}
int64_t
_clutter_stage_get_next_presentation_time (ClutterStage *stage)
{
ClutterStageWindow *stage_window;
if (CLUTTER_ACTOR_IN_DESTRUCTION (stage))
return 0;
stage_window = _clutter_stage_get_window (stage);
if (stage_window == NULL)
return 0;
return _clutter_stage_window_get_next_presentation_time (stage_window);
}
ClutterPaintVolume *
_clutter_stage_paint_volume_stack_allocate (ClutterStage *stage)
{
@ -4463,6 +4473,100 @@ clutter_stage_get_capture_final_size (ClutterStage *stage,
return TRUE;
}
/**
* clutter_stage_paint_to_framebuffer: (skip)
*/
void
clutter_stage_paint_to_framebuffer (ClutterStage *stage,
CoglFramebuffer *framebuffer,
const cairo_rectangle_int_t *rect,
float scale,
ClutterPaintFlag paint_flags)
{
ClutterStagePrivate *priv = stage->priv;
ClutterPaintContext *paint_context;
cairo_region_t *redraw_clip;
redraw_clip = cairo_region_create_rectangle (rect);
paint_context = clutter_paint_context_new_for_framebuffer (framebuffer);
cairo_region_destroy (redraw_clip);
cogl_framebuffer_push_matrix (framebuffer);
cogl_framebuffer_set_projection_matrix (framebuffer, &priv->projection);
cogl_framebuffer_set_viewport (framebuffer,
-(rect->x * scale),
-(rect->y * scale),
priv->viewport[2] * scale,
priv->viewport[3] * scale);
clutter_actor_paint (CLUTTER_ACTOR (stage), paint_context);
cogl_framebuffer_pop_matrix (framebuffer);
clutter_paint_context_destroy (paint_context);
}
/**
* clutter_stage_paint_to_buffer: (skip)
*/
gboolean
clutter_stage_paint_to_buffer (ClutterStage *stage,
const cairo_rectangle_int_t *rect,
float scale,
uint8_t *data,
int stride,
CoglPixelFormat format,
ClutterPaintFlag paint_flags,
GError **error)
{
ClutterBackend *clutter_backend = clutter_get_default_backend ();
CoglContext *cogl_context =
clutter_backend_get_cogl_context (clutter_backend);
int texture_width, texture_height;
CoglTexture2D *texture;
CoglOffscreen *offscreen;
CoglFramebuffer *framebuffer;
CoglBitmap *bitmap;
texture_width = (int) roundf (rect->width * scale);
texture_height = (int) roundf (rect->height * scale);
texture = cogl_texture_2d_new_with_size (cogl_context,
texture_width,
texture_height);
if (!texture)
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"Failed to create %dx%d texture",
texture_width, texture_height);
return FALSE;
}
offscreen = cogl_offscreen_new_with_texture (COGL_TEXTURE (texture));
framebuffer = COGL_FRAMEBUFFER (offscreen);
cogl_object_unref (texture);
if (!cogl_framebuffer_allocate (framebuffer, error))
return FALSE;
clutter_stage_paint_to_framebuffer (stage, framebuffer,
rect, scale, paint_flags);
bitmap = cogl_bitmap_new_for_data (cogl_context,
texture_width, texture_height,
format,
stride,
data);
cogl_framebuffer_read_pixels_into_bitmap (framebuffer,
0, 0,
COGL_READ_PIXELS_COLOR_BUFFER,
bitmap);
cogl_object_unref (bitmap);
cogl_object_unref (framebuffer);
return TRUE;
}
static void
capture_view_into (ClutterStage *stage,
gboolean paint,
@ -4471,50 +4575,17 @@ capture_view_into (ClutterStage *stage,
uint8_t *data,
int stride)
{
CoglFramebuffer *framebuffer;
ClutterBackend *backend;
CoglContext *context;
CoglBitmap *bitmap;
cairo_rectangle_int_t view_layout;
g_autoptr (GError) error = NULL;
float view_scale;
float texture_width;
float texture_height;
g_return_if_fail (CLUTTER_IS_STAGE (stage));
framebuffer = clutter_stage_view_get_framebuffer (view);
if (paint)
{
cairo_region_t *region;
_clutter_stage_maybe_setup_viewport (stage, view);
region = cairo_region_create_rectangle (rect);
clutter_stage_do_paint_view (stage, view, region);
cairo_region_destroy (region);
}
view_scale = clutter_stage_view_get_scale (view);
texture_width = roundf (rect->width * view_scale);
texture_height = roundf (rect->height * view_scale);
backend = clutter_get_default_backend ();
context = clutter_backend_get_cogl_context (backend);
bitmap = cogl_bitmap_new_for_data (context,
texture_width, texture_height,
CLUTTER_CAIRO_FORMAT_ARGB32,
stride,
data);
clutter_stage_view_get_layout (view, &view_layout);
cogl_framebuffer_read_pixels_into_bitmap (framebuffer,
roundf ((rect->x - view_layout.x) * view_scale),
roundf ((rect->y - view_layout.y) * view_scale),
COGL_READ_PIXELS_COLOR_BUFFER,
bitmap);
cogl_object_unref (bitmap);
if (!clutter_stage_paint_to_buffer (stage, rect, view_scale, data, stride,
CLUTTER_CAIRO_FORMAT_ARGB32,
CLUTTER_PAINT_FLAG_NO_CURSORS,
&error))
g_warning ("Failed to capture stage: %s", error->message);
}
void

View File

@ -235,7 +235,12 @@ clutter_stage_cogl_schedule_update (ClutterStageWindow *stage_window,
stage_cogl->update_time = next_presentation_time - max_render_time_allowed;
if (stage_cogl->update_time == stage_cogl->last_update_time)
stage_cogl->update_time = stage_cogl->last_update_time + refresh_interval;
{
stage_cogl->update_time += refresh_interval;
next_presentation_time += refresh_interval;
}
stage_cogl->next_presentation_time = next_presentation_time;
}
static gint64
@ -256,6 +261,29 @@ clutter_stage_cogl_clear_update_time (ClutterStageWindow *stage_window)
stage_cogl->last_update_time = stage_cogl->update_time;
stage_cogl->update_time = -1;
stage_cogl->next_presentation_time = -1;
}
static int64_t
clutter_stage_cogl_get_next_presentation_time (ClutterStageWindow *stage_window)
{
ClutterStageCogl *stage_cogl = CLUTTER_STAGE_COGL (stage_window);
int64_t now = g_get_monotonic_time ();
if (stage_cogl->next_presentation_time > 0 &&
stage_cogl->next_presentation_time <= now)
{
CLUTTER_NOTE (BACKEND,
"Missed some frames. Something blocked for over "
"%" G_GINT64_FORMAT "ms.",
(now - stage_cogl->next_presentation_time) / 1000);
stage_cogl->update_time = -1;
clutter_stage_cogl_schedule_update (stage_window,
stage_cogl->last_sync_delay);
}
return stage_cogl->next_presentation_time;
}
static ClutterActor *
@ -375,15 +403,11 @@ static gboolean
swap_framebuffer (ClutterStageWindow *stage_window,
ClutterStageView *view,
cairo_region_t *swap_region,
gboolean swap_with_damage,
cairo_region_t *queued_redraw_clip)
gboolean swap_with_damage)
{
CoglFramebuffer *framebuffer = clutter_stage_view_get_onscreen (view);
int *damage, n_rects, i;
if (G_UNLIKELY ((clutter_paint_debug_flags & CLUTTER_DEBUG_PAINT_DAMAGE_REGION)))
paint_damage_region (stage_window, view, swap_region, queued_redraw_clip);
n_rects = cairo_region_num_rectangles (swap_region);
damage = g_newa (int, n_rects * 4);
for (i = 0; i < n_rects; i++)
@ -620,7 +644,7 @@ clutter_stage_cogl_redraw_view (ClutterStageWindow *stage_window,
gboolean swap_with_damage;
ClutterActor *wrapper;
cairo_region_t *redraw_clip;
cairo_region_t *queued_redraw_clip;
cairo_region_t *queued_redraw_clip = NULL;
cairo_region_t *fb_clip_region;
cairo_region_t *swap_region;
cairo_rectangle_int_t redraw_rect;
@ -644,6 +668,8 @@ clutter_stage_cogl_redraw_view (ClutterStageWindow *stage_window,
has_buffer_age = cogl_is_onscreen (fb) && is_buffer_age_enabled ();
redraw_clip = clutter_stage_view_take_redraw_clip (view);
if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_PAINT_DAMAGE_REGION))
queued_redraw_clip = cairo_region_copy (redraw_clip);
/* NB: a NULL redraw clip == full stage redraw */
if (!redraw_clip)
@ -711,8 +737,6 @@ clutter_stage_cogl_redraw_view (ClutterStageWindow *stage_window,
redraw_clip = cairo_region_create_rectangle (&view_rect);
}
queued_redraw_clip = cairo_region_copy (redraw_clip);
if (may_use_clipped_redraw &&
G_LIKELY (!(clutter_paint_debug_flags & CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS)))
use_clipped_redraw = TRUE;
@ -922,7 +946,6 @@ clutter_stage_cogl_redraw_view (ClutterStageWindow *stage_window,
}
g_clear_pointer (&redraw_clip, cairo_region_destroy);
g_clear_pointer (&queued_redraw_clip, cairo_region_destroy);
g_clear_pointer (&fb_clip_region, cairo_region_destroy);
if (do_swap_buffer)
@ -943,11 +966,17 @@ clutter_stage_cogl_redraw_view (ClutterStageWindow *stage_window,
swap_region = transformed_swap_region;
}
if (queued_redraw_clip)
{
paint_damage_region (stage_window, view,
swap_region, queued_redraw_clip);
cairo_region_destroy (queued_redraw_clip);
}
res = swap_framebuffer (stage_window,
view,
swap_region,
swap_with_damage,
queued_redraw_clip);
swap_with_damage);
cairo_region_destroy (swap_region);
@ -955,6 +984,7 @@ clutter_stage_cogl_redraw_view (ClutterStageWindow *stage_window,
}
else
{
g_clear_pointer (&queued_redraw_clip, cairo_region_destroy);
return FALSE;
}
}
@ -1008,6 +1038,7 @@ clutter_stage_window_iface_init (ClutterStageWindowInterface *iface)
iface->schedule_update = clutter_stage_cogl_schedule_update;
iface->get_update_time = clutter_stage_cogl_get_update_time;
iface->clear_update_time = clutter_stage_cogl_clear_update_time;
iface->get_next_presentation_time = clutter_stage_cogl_get_next_presentation_time;
iface->redraw = clutter_stage_cogl_redraw;
}
@ -1053,6 +1084,7 @@ _clutter_stage_cogl_init (ClutterStageCogl *stage)
stage->refresh_rate = 0.0;
stage->update_time = -1;
stage->next_presentation_time = -1;
}
static void

View File

@ -48,6 +48,7 @@ struct _ClutterStageCogl
gint64 last_presentation_time;
gint64 update_time;
int64_t last_update_time;
int64_t next_presentation_time;
/* We only enable clipped redraws after 2 frames, since we've seen
* a lot of drivers can struggle to get going and may output some

View File

@ -74,7 +74,7 @@ PangoFontMap *
cogl_pango_font_map_new (void)
{
PangoFontMap *fm = pango_cairo_font_map_new ();
CoglPangoFontMapPriv *priv = g_new0 (CoglPangoFontMapPriv, 1);
g_autofree CoglPangoFontMapPriv *priv = g_new0 (CoglPangoFontMapPriv, 1);
_COGL_GET_CONTEXT (context, NULL);
@ -85,7 +85,7 @@ cogl_pango_font_map_new (void)
* for now. */
g_object_set_qdata_full (G_OBJECT (fm),
cogl_pango_font_map_get_priv_key (),
priv,
g_steal_pointer (&priv),
free_priv);
return fm;

View File

@ -93,10 +93,12 @@ _cogl_onscreen_init_from_template (CoglOnscreen *onscreen,
CoglOnscreen *
_cogl_onscreen_new (void)
{
CoglOnscreen *onscreen = g_new0 (CoglOnscreen, 1);
g_autofree CoglOnscreen *onscreen_ptr = g_new0 (CoglOnscreen, 1);
CoglOnscreen *onscreen;
_COGL_GET_CONTEXT (ctx, NULL);
onscreen = g_steal_pointer (&onscreen_ptr);
_cogl_framebuffer_init (COGL_FRAMEBUFFER (onscreen),
ctx,
COGL_FRAMEBUFFER_TYPE_ONSCREEN,

View File

@ -50,7 +50,7 @@ struct _CoglPipelineCache
CoglPipelineCache *
_cogl_pipeline_cache_new (void)
{
CoglPipelineCache *cache = g_new (CoglPipelineCache, 1);
g_autofree CoglPipelineCache *cache = g_new (CoglPipelineCache, 1);
unsigned long vertex_state;
unsigned long layer_vertex_state;
unsigned int fragment_state;
@ -80,7 +80,7 @@ _cogl_pipeline_cache_new (void)
layer_vertex_state | layer_fragment_state,
"programs");
return cache;
return g_steal_pointer (&cache);
}
void

View File

@ -121,6 +121,9 @@ cogl_texture_2d_new_with_size (CoglContext *ctx,
{
CoglTextureLoader *loader;
g_return_val_if_fail (width >= 1, NULL);
g_return_val_if_fail (height >= 1, NULL);
loader = _cogl_texture_create_loader ();
loader->src_type = COGL_TEXTURE_SOURCE_TYPE_SIZED;
loader->src.sized.width = width;
@ -399,6 +402,11 @@ _cogl_texture_2d_pre_paint (CoglTexture *tex, CoglTexturePrePaintFlags flags)
{
CoglContext *ctx = tex->context;
/* Since we are about to ask the GPU to generate mipmaps of tex, we
* better make sure tex is up-to-date.
*/
_cogl_texture_flush_journal_rendering (tex);
ctx->driver_vtable->texture_2d_generate_mipmap (tex_2d);
tex_2d->mipmaps_dirty = FALSE;

View File

@ -132,8 +132,8 @@ _cogl_framebuffer_gl_flush_viewport_state (CoglFramebuffer *framebuffer)
{
float gl_viewport_y;
g_assert (framebuffer->viewport_width >=0 &&
framebuffer->viewport_height >=0);
g_return_if_fail (framebuffer->viewport_width >= 0);
g_return_if_fail (framebuffer->viewport_height >= 0);
/* Convert the Cogl viewport y offset to an OpenGL viewport y offset
* NB: OpenGL defines its window and viewport origins to be bottom

View File

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

View File

@ -12,7 +12,7 @@ option('opengl_libname',
option('gles2_libname',
type: 'string',
value: 'libGLESv2.so',
value: 'libGLESv2.so.2',
description: 'GLESv2 library file name'
)

View File

@ -13,8 +13,8 @@ msgid ""
msgstr ""
"Project-Id-Version: mutter master\n"
"Report-Msgid-Bugs-To: https://gitlab.gnome.org/GNOME/mutter/issues\n"
"POT-Creation-Date: 2019-08-06 00:49+0000\n"
"PO-Revision-Date: 2019-09-05 23:42+0200\n"
"POT-Creation-Date: 2020-03-30 20:11+0000\n"
"PO-Revision-Date: 2020-04-06 23:13+0200\n"
"Last-Translator: Christian Kirbach <christian.kirbach@gmail.com>\n"
"Language-Team: Deutsch <gnome-de@gnome.org>\n"
"Language: de\n"
@ -22,7 +22,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
"X-Generator: Poedit 2.2.1\n"
"X-Generator: Poedit 2.3\n"
#: data/50-mutter-navigation.xml:6
msgid "Navigation"
@ -435,20 +435,33 @@ msgstr "Zusatztaste zum Finden des Zeigers"
msgid "This key will initiate the “locate pointer” action."
msgstr "Diese Taste wird die Aktion »Zeiger finden« auslösen."
#: data/org.gnome.mutter.gschema.xml.in:155
#: data/org.gnome.mutter.gschema.xml.in:142
msgid "Timeout for check-alive ping"
msgstr "Reaktionsschwellwert bei Kontaktkontrolle"
#: data/org.gnome.mutter.gschema.xml.in:143
msgid ""
"Number of milliseconds a client has to respond to a ping request in order to "
"not be detected as frozen. Using 0 will disable the alive check completely."
msgstr ""
"Zeit in Millisekunden, innerhalb welcher ein Client auf eine "
"Kontaktkontrolle antworten muss, um nicht als abgestürzt zu gelten. »0« "
"bedeutet, dass die Kontaktkontrolle ausgeschaltet wird."
#: data/org.gnome.mutter.gschema.xml.in:165
msgid "Select window from tab popup"
msgstr "Fenster aus Tab-Anzeige auswählen"
#: data/org.gnome.mutter.gschema.xml.in:160
#: data/org.gnome.mutter.gschema.xml.in:170
msgid "Cancel tab popup"
msgstr "Tab-Anzeige abbrechen"
#: data/org.gnome.mutter.gschema.xml.in:165
#: data/org.gnome.mutter.gschema.xml.in:175
msgid "Switch monitor configurations"
msgstr "Bildschirmkonfigurationen wechseln"
# Ich denke nicht, dass »rotate« hier die Bildschirmdrehung meint, sondern eher eine Liste aus Konfigurationen rotiert (d.h. umgewälzt) wird.
#: data/org.gnome.mutter.gschema.xml.in:170
#: data/org.gnome.mutter.gschema.xml.in:180
msgid "Rotates the built-in monitor configuration"
msgstr "Wechselt die Konfiguration des eingebauten Bildschirms"
@ -569,7 +582,7 @@ msgstr ""
#. TRANSLATORS: This string refers to a button that switches between
#. * different modes.
#.
#: src/backends/meta-input-settings.c:2531
#: src/backends/meta-input-settings.c:2631
#, c-format
msgid "Mode Switch (Group %d)"
msgstr "Moduswechsel (Gruppe %d)"
@ -577,34 +590,34 @@ msgstr "Moduswechsel (Gruppe %d)"
#. TRANSLATORS: This string refers to an action, cycles drawing tablets'
#. * mapping through the available outputs.
#.
#: src/backends/meta-input-settings.c:2554
#: src/backends/meta-input-settings.c:2654
msgid "Switch monitor"
msgstr "Bildschirm wechseln"
#: src/backends/meta-input-settings.c:2556
#: src/backends/meta-input-settings.c:2656
msgid "Show on-screen help"
msgstr "Bildschirmhilfe anzeigen"
#: src/backends/meta-monitor.c:223
#: src/backends/meta-monitor.c:226
msgid "Built-in display"
msgstr "Eingebaute Anzeige"
#: src/backends/meta-monitor.c:252
#: src/backends/meta-monitor.c:255
msgid "Unknown"
msgstr "Unbekannt"
#: src/backends/meta-monitor.c:254
#: src/backends/meta-monitor.c:257
msgid "Unknown Display"
msgstr "Unbekannte Anzeige"
#: src/backends/meta-monitor.c:262
#: src/backends/meta-monitor.c:265
#, c-format
msgctxt ""
"This is a monitor vendor name, followed by a size in inches, like 'Dell 15\"'"
msgid "%s %s"
msgstr "%s %s"
#: src/backends/meta-monitor.c:270
#: src/backends/meta-monitor.c:273
#, c-format
msgctxt ""
"This is a monitor vendor name followed by product/model name where size in "
@ -614,13 +627,13 @@ msgstr "%s %s"
# https://de.wikipedia.org/wiki/Composition-Manager
#. Translators: this string will appear in Sysprof
#: src/backends/meta-profiler.c:82
#: src/backends/meta-profiler.c:79
msgid "Compositor"
msgstr "Compositor"
#. This probably means that a non-WM compositor like xcompmgr is running;
#. * we have no way to get it to exit
#: src/compositor/compositor.c:510
#: src/compositor/compositor.c:533
#, c-format
msgid ""
"Another compositing manager is already running on screen %i on display “%s”."
@ -632,47 +645,47 @@ msgstr ""
msgid "Bell event"
msgstr "Klangereignis"
#: src/core/main.c:185
#: src/core/main.c:190
msgid "Disable connection to session manager"
msgstr "Verbindung zur Sitzungsverwaltung deaktivieren"
#: src/core/main.c:191
#: src/core/main.c:196
msgid "Replace the running window manager"
msgstr "Den aktuellen Fensterverwalter ersetzen"
#: src/core/main.c:197
#: src/core/main.c:202
msgid "Specify session management ID"
msgstr "Kennung der Sitzungsverwaltung angeben"
#: src/core/main.c:202
#: src/core/main.c:207
msgid "X Display to use"
msgstr "Zu verwendende X-Anzeige"
#: src/core/main.c:208
#: src/core/main.c:213
msgid "Initialize session from savefile"
msgstr "Sitzung anhand gespeicherter Datei starten"
#: src/core/main.c:214
#: src/core/main.c:219
msgid "Make X calls synchronous"
msgstr "X-Aufrufe abgleichen"
#: src/core/main.c:221
#: src/core/main.c:226
msgid "Run as a wayland compositor"
msgstr "Als Wayland-Compositor ausführen"
#: src/core/main.c:227
#: src/core/main.c:232
msgid "Run as a nested compositor"
msgstr "Als eingebetteten Compositor ausführen"
#: src/core/main.c:233
#: src/core/main.c:238
msgid "Run wayland compositor without starting Xwayland"
msgstr "Wayland-Compositor ausführen, ohne Xwayland zu starten"
#: src/core/main.c:241
#: src/core/main.c:246
msgid "Run as a full display server, rather than nested"
msgstr "Als vollwertigen Display-Server verwenden (nicht eingebettet)"
#: src/core/main.c:247
#: src/core/main.c:252
msgid "Run with X11 backend"
msgstr "Mit X11-Backend ausführen"
@ -728,21 +741,21 @@ msgstr "Version ausgeben"
msgid "Mutter plugin to use"
msgstr "Zu benutzendes Mutter-Plugin"
#: src/core/prefs.c:1849
#: src/core/prefs.c:1911
#, c-format
msgid "Workspace %d"
msgstr "Arbeitsfläche %d"
#: src/core/util.c:121
#: src/core/util.c:122
msgid "Mutter was compiled without support for verbose mode\n"
msgstr "Mutter wurde ohne Unterstützung für den redseligen Modus kompiliert\n"
#: src/wayland/meta-wayland-tablet-pad.c:567
#: src/wayland/meta-wayland-tablet-pad.c:568
#, c-format
msgid "Mode Switch: Mode %d"
msgstr "Moduswechsel: Modus %d"
#: src/x11/meta-x11-display.c:671
#: src/x11/meta-x11-display.c:676
#, c-format
msgid ""
"Display “%s” already has a window manager; try using the --replace option to "
@ -751,21 +764,21 @@ msgstr ""
"Bildschirm »%s« hat bereits einen Fensterverwalter. Versuchen Sie die Option "
"»--replace«, um den aktuellen Fensterverwalter zu ersetzen."
#: src/x11/meta-x11-display.c:1032
#: src/x11/meta-x11-display.c:1089
msgid "Failed to initialize GDK\n"
msgstr "GDK konnte nicht initialisiert werden\n"
#: src/x11/meta-x11-display.c:1056
#: src/x11/meta-x11-display.c:1113
#, c-format
msgid "Failed to open X Window System display “%s”\n"
msgstr "X-Window-Systemanzeige »%s« konnte nicht geöffnet werden\n"
#: src/x11/meta-x11-display.c:1140
#: src/x11/meta-x11-display.c:1196
#, c-format
msgid "Screen %d on display “%s” is invalid\n"
msgstr "Bildschirm %d auf Anzeige »%s« ist ungültig\n"
#: src/x11/meta-x11-selection-input-stream.c:445
#: src/x11/meta-x11-selection-input-stream.c:460
#, c-format
msgid "Format %s not supported"
msgstr "Format %s wird nicht unterstützt"

View File

@ -21,8 +21,8 @@ msgid ""
msgstr ""
"Project-Id-Version: mutter\n"
"Report-Msgid-Bugs-To: https://gitlab.gnome.org/GNOME/mutter/issues\n"
"POT-Creation-Date: 2020-02-23 17:41+0000\n"
"PO-Revision-Date: 2020-02-24 06:39-0300\n"
"POT-Creation-Date: 2020-04-27 14:06+0000\n"
"PO-Revision-Date: 2020-07-17 17:56-0300\n"
"Last-Translator: Rafael Fontenelle <rafaelff@gnome.org>\n"
"Language-Team: Brazilian Portuguese <gnome-pt_br-list@gnome.org>\n"
"Language: pt_BR\n"
@ -30,7 +30,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n > 1)\n"
"X-Generator: Gtranslator 3.32.0\n"
"X-Generator: Gtranslator 3.36.0\n"
"X-Project-Style: gnome\n"
#: data/50-mutter-navigation.xml:6
@ -59,35 +59,35 @@ msgstr "Mover a janela para o último espaço de trabalho"
#: data/50-mutter-navigation.xml:24
msgid "Move window one workspace up"
msgstr "Mover a janela um espaço de trabalho acima"
msgstr "Mover a janela para um espaço de trabalho acima"
#: data/50-mutter-navigation.xml:27
msgid "Move window one workspace down"
msgstr "Mover a janela um espaço de trabalho abaixo"
msgstr "Mover a janela para um espaço de trabalho abaixo"
# Em conformidade com a tradução do gsettings-desktop-schemas --Enrico
#: data/50-mutter-navigation.xml:30
msgid "Move window one monitor to the left"
msgstr "Mover janela para o monitor da esquerda"
msgstr "Mover a janela para o monitor da esquerda"
# Em conformidade com a tradução do gsettings-desktop-schemas --Enrico
#: data/50-mutter-navigation.xml:33
msgid "Move window one monitor to the right"
msgstr "Mover janela para o monitor da direita"
msgstr "Mover a janela para o monitor da direita"
# Em conformidade com a tradução do gsettings-desktop-schemas --Enrico
#: data/50-mutter-navigation.xml:36
msgid "Move window one monitor up"
msgstr "Mover janela para o monitor acima"
msgstr "Mover a janela para o monitor acima"
# Em conformidade com a tradução do gsettings-desktop-schemas --Enrico
#: data/50-mutter-navigation.xml:39
msgid "Move window one monitor down"
msgstr "Mover janela para o monitor abaixo"
msgstr "Mover a janela para o monitor abaixo"
#: data/50-mutter-navigation.xml:43
msgid "Switch applications"
msgstr "Alternar aplicativos"
msgstr "Alternar entre aplicativos"
#: data/50-mutter-navigation.xml:48
msgid "Switch to previous application"
@ -95,7 +95,7 @@ msgstr "Alternar para o aplicativo anterior"
#: data/50-mutter-navigation.xml:52
msgid "Switch windows"
msgstr "Alternar janelas"
msgstr "Alternar entre janelas"
#: data/50-mutter-navigation.xml:57
msgid "Switch to previous window"
@ -111,7 +111,7 @@ msgstr "Alternar para a janela anterior de um aplicativo"
#: data/50-mutter-navigation.xml:70
msgid "Switch system controls"
msgstr "Alternar controles do sistema"
msgstr "Alternar os controles do sistema"
#: data/50-mutter-navigation.xml:75
msgid "Switch to previous system control"
@ -167,11 +167,11 @@ msgstr "Trocar para o último espaço de trabalho"
#: data/50-mutter-navigation.xml:123
msgid "Move to workspace above"
msgstr "Mover para o espaço de trabalho acima"
msgstr "Mover a visualização para o espaço de trabalho acima"
#: data/50-mutter-navigation.xml:126
msgid "Move to workspace below"
msgstr "Mover para o espaço de trabalho abaixo"
msgstr "Mover a visualização para o espaço de trabalho abaixo"
#: data/50-mutter-system.xml:6 data/50-mutter-wayland.xml:6
msgid "System"
@ -199,11 +199,11 @@ msgstr "Ativar o menu da janela"
#: data/50-mutter-windows.xml:10
msgid "Toggle fullscreen mode"
msgstr "Alternar modo de tela inteira"
msgstr "Alternar o modo de tela inteira"
#: data/50-mutter-windows.xml:12
msgid "Toggle maximization state"
msgstr "Alternar estado de maximização"
msgstr "Alternar o estado de maximização"
#: data/50-mutter-windows.xml:14
msgid "Maximize window"
@ -211,35 +211,35 @@ msgstr "Maximizar a janela"
#: data/50-mutter-windows.xml:16
msgid "Restore window"
msgstr "Restaurar janela"
msgstr "Restaurar a anela"
#: data/50-mutter-windows.xml:18
msgid "Close window"
msgstr "Fechar janela"
msgstr "Fechar a janela"
#: data/50-mutter-windows.xml:20
msgid "Hide window"
msgstr "Ocultar janela"
msgstr "Ocultar a janela"
#: data/50-mutter-windows.xml:22
msgid "Move window"
msgstr "Mover janela"
msgstr "Mover a janela"
#: data/50-mutter-windows.xml:24
msgid "Resize window"
msgstr "Redimensionar janela"
msgstr "Redimensionar a janela"
#: data/50-mutter-windows.xml:27
msgid "Toggle window on all workspaces or one"
msgstr "Alternar a janela em todos os espaços de trabalho ou em apenas um"
msgstr "Alternar a janela em todos os espaços de trabalho ou apenas em um"
#: data/50-mutter-windows.xml:29
msgid "Raise window if covered, otherwise lower it"
msgstr "Elevar a janela se estiver coberta; caso contrário, a abaixa"
msgstr "Trazer a janela se estiver coberta; caso contrário, coloca atrás"
#: data/50-mutter-windows.xml:31
msgid "Raise window above other windows"
msgstr "Elevar a janela para frente das outras"
msgstr "Trazer a janela para frente das outras"
#: data/50-mutter-windows.xml:33
msgid "Lower window below other windows"
@ -255,11 +255,11 @@ msgstr "Maximizar a janela horizontalmente"
#: data/50-mutter-windows.xml:41
msgid "View split on left"
msgstr "Visualizar divisão à esquerda"
msgstr "Visualizar a divisão à esquerda"
#: data/50-mutter-windows.xml:45
msgid "View split on right"
msgstr "Visualizar divisão à direita"
msgstr "Visualizar a divisão à direita"
#: data/mutter.desktop.in:4
msgid "Mutter"
@ -580,7 +580,7 @@ msgstr ""
#. TRANSLATORS: This string refers to a button that switches between
#. * different modes.
#.
#: src/backends/meta-input-settings.c:2567
#: src/backends/meta-input-settings.c:2631
#, c-format
msgid "Mode Switch (Group %d)"
msgstr "Alternador de modo (Grupo %d)"
@ -588,34 +588,34 @@ msgstr "Alternador de modo (Grupo %d)"
#. TRANSLATORS: This string refers to an action, cycles drawing tablets'
#. * mapping through the available outputs.
#.
#: src/backends/meta-input-settings.c:2590
#: src/backends/meta-input-settings.c:2654
msgid "Switch monitor"
msgstr "Trocar monitor"
#: src/backends/meta-input-settings.c:2592
#: src/backends/meta-input-settings.c:2656
msgid "Show on-screen help"
msgstr "Mostrar ajuda na tela"
#: src/backends/meta-monitor.c:223
#: src/backends/meta-monitor.c:226
msgid "Built-in display"
msgstr "Tela embutida"
#: src/backends/meta-monitor.c:252
#: src/backends/meta-monitor.c:255
msgid "Unknown"
msgstr "Desconhecido"
#: src/backends/meta-monitor.c:254
#: src/backends/meta-monitor.c:257
msgid "Unknown Display"
msgstr "Monitor desconhecido"
#: src/backends/meta-monitor.c:262
#: src/backends/meta-monitor.c:265
#, c-format
msgctxt ""
"This is a monitor vendor name, followed by a size in inches, like 'Dell 15\"'"
msgid "%s %s"
msgstr "%s %s"
#: src/backends/meta-monitor.c:270
#: src/backends/meta-monitor.c:273
#, c-format
msgctxt ""
"This is a monitor vendor name followed by product/model name where size in "

167
po/sk.po
View File

@ -13,8 +13,8 @@ msgid ""
msgstr ""
"Project-Id-Version: mutter\n"
"Report-Msgid-Bugs-To: https://gitlab.gnome.org/GNOME/mutter/issues\n"
"POT-Creation-Date: 2018-02-06 04:14+0000\n"
"PO-Revision-Date: 2018-03-17 21:52+0100\n"
"POT-Creation-Date: 2020-03-30 20:11+0000\n"
"PO-Revision-Date: 2020-04-05 22:21+0200\n"
"Last-Translator: Dušan Kazik <prescott66@gmail.com>\n"
"Language-Team: Slovak <gnome-sk-list@gnome.org>\n"
"Language: sk\n"
@ -22,7 +22,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=(n==1) ? 1 : (n>=2 && n<=4) ? 2 : 0;\n"
"X-Generator: Poedit 2.0.6\n"
"X-Generator: Poedit 2.3\n"
#: data/50-mutter-navigation.xml:6
msgid "Navigation"
@ -468,29 +468,47 @@ msgid ""
"proof. Currently possible keywords: • “scale-monitor-framebuffer” — makes "
"mutter default to layout logical monitors in a logical pixel coordinate "
"space, while scaling monitor framebuffers instead of window content, to "
"manage HiDPI monitors. Does not require a restart. • “remote-desktop” — "
"enables remote desktop support. To support remote desktop with screen "
"sharing, “screen-cast” must also be enabled. • “screen-cast” — enables "
"screen cast support."
"manage HiDPI monitors. Does not require a restart. • “rt-scheduler” — makes "
"mutter request a low priority real-time scheduling. The executable or user "
"must have CAP_SYS_NICE. Requires a restart. • “autostart-xwayland” — "
"initializes Xwayland lazily if there are X11 clients. Requires restart."
msgstr ""
#: data/org.gnome.mutter.gschema.xml.in:134
msgid "Modifier to use to locate the pointer"
msgstr "Modifikátor použitý na lokalizovanie ukazovateľa"
#: data/org.gnome.mutter.gschema.xml.in:135
msgid "This key will initiate the “locate pointer” action."
msgstr ""
#: data/org.gnome.mutter.gschema.xml.in:142
msgid "Timeout for check-alive ping"
msgstr ""
#: data/org.gnome.mutter.gschema.xml.in:143
msgid ""
"Number of milliseconds a client has to respond to a ping request in order to "
"not be detected as frozen. Using 0 will disable the alive check completely."
msgstr ""
# summary
#: data/org.gnome.mutter.gschema.xml.in:145
#: data/org.gnome.mutter.gschema.xml.in:165
msgid "Select window from tab popup"
msgstr "Vybrať okno z rozbaľovacej ponuky tabulátora"
# summary
#: data/org.gnome.mutter.gschema.xml.in:150
#: data/org.gnome.mutter.gschema.xml.in:170
msgid "Cancel tab popup"
msgstr "Zrušit rozbaľovaciu ponuku tabulátora"
# PK: predpokladam ze to prepisane medzi tlacidlami
# description
#: data/org.gnome.mutter.gschema.xml.in:155
#: data/org.gnome.mutter.gschema.xml.in:175
msgid "Switch monitor configurations"
msgstr "Prepnúť nastavenia monitorov"
#: data/org.gnome.mutter.gschema.xml.in:160
#: data/org.gnome.mutter.gschema.xml.in:180
msgid "Rotates the built-in monitor configuration"
msgstr "Otočí nastavenie vstavaného monitora"
@ -554,23 +572,27 @@ msgid "Re-enable shortcuts"
msgstr "Znovu povoliť klávesové skratky"
#: data/org.gnome.mutter.wayland.gschema.xml.in:64
msgid "Allow grabs with Xwayland"
msgid "Allow X11 grabs to lock keyboard focus with Xwayland"
msgstr ""
#: data/org.gnome.mutter.wayland.gschema.xml.in:65
msgid ""
"Allow keyboard grabs issued by X11 applications running in Xwayland to be "
"taken into account. For a X11 grab to be taken into account under Wayland, "
"the client must also either send a specific X11 ClientMessage to the root "
"window or be among the applications white-listed in key “xwayland-grab-"
"access-rules”."
"Allow all keyboard events to be routed to X11 “override redirect” windows "
"with a grab when running in Xwayland. This option is to support X11 clients "
"which map an “override redirect” window (which do not receive keyboard "
"focus) and issue a keyboard grab to force all keyboard events to that "
"window. This option is seldom used and has no effect on regular X11 windows "
"which can receive keyboard focus under normal circumstances. For a X11 grab "
"to be taken into account under Wayland, the client must also either send a "
"specific X11 ClientMessage to the root window or be among the applications "
"white-listed in key “xwayland-grab-access-rules”."
msgstr ""
#: data/org.gnome.mutter.wayland.gschema.xml.in:77
#: data/org.gnome.mutter.wayland.gschema.xml.in:84
msgid "Xwayland applications allowed to issue keyboard grabs"
msgstr ""
#: data/org.gnome.mutter.wayland.gschema.xml.in:78
#: data/org.gnome.mutter.wayland.gschema.xml.in:85
msgid ""
"List the resource names or resource class of X11 windows either allowed or "
"not allowed to issue X11 keyboard grabs under Xwayland. The resource name or "
@ -587,7 +609,7 @@ msgstr ""
#. TRANSLATORS: This string refers to a button that switches between
#. * different modes.
#.
#: src/backends/meta-input-settings.c:2260
#: src/backends/meta-input-settings.c:2631
#, c-format
msgid "Mode Switch (Group %d)"
msgstr "Prepínač režimu (skupina č. %d)"
@ -597,53 +619,61 @@ msgstr "Prepínač režimu (skupina č. %d)"
#. TRANSLATORS: This string refers to an action, cycles drawing tablets'
#. * mapping through the available outputs.
#.
#: src/backends/meta-input-settings.c:2283
#: src/backends/meta-input-settings.c:2654
msgid "Switch monitor"
msgstr "Prepnúť monitor"
#: src/backends/meta-input-settings.c:2285
#: src/backends/meta-input-settings.c:2656
msgid "Show on-screen help"
msgstr "Zobraziť pomocníka na obrazovke"
#: src/backends/meta-monitor-manager.c:900
#: src/backends/meta-monitor.c:226
msgid "Built-in display"
msgstr "Vstavaný displej"
#: src/backends/meta-monitor-manager.c:923
#: src/backends/meta-monitor.c:255
msgid "Unknown"
msgstr "Neznámy"
#: src/backends/meta-monitor-manager.c:925
#: src/backends/meta-monitor.c:257
msgid "Unknown Display"
msgstr "Neznámy displej"
#. TRANSLATORS: this is a monitor vendor name, followed by a
#. * size in inches, like 'Dell 15"'
#.
#: src/backends/meta-monitor-manager.c:933
#: src/backends/meta-monitor.c:265
#, c-format
#| msgid "%s %s"
msgctxt ""
"This is a monitor vendor name, followed by a size in inches, like 'Dell 15\"'"
msgid "%s %s"
msgstr "%s %s"
#: src/backends/meta-monitor.c:273
#, c-format
#| msgid "%s %s"
msgctxt ""
"This is a monitor vendor name followed by product/model name where size in "
"inches could not be calculated, e.g. Dell U2414H"
msgid "%s %s"
msgstr "%s %s"
#. Translators: this string will appear in Sysprof
#: src/backends/meta-profiler.c:79
msgid "Compositor"
msgstr "Kompozítor"
#. This probably means that a non-WM compositor like xcompmgr is running;
#. * we have no way to get it to exit
#: src/compositor/compositor.c:481
#: src/compositor/compositor.c:533
#, c-format
msgid ""
"Another compositing manager is already running on screen %i on display “%s”."
msgstr ""
"Pre obrazovku č. %i na displeji „%s“ je spustený už iný správca rozloženia."
#: src/core/bell.c:194
#: src/core/bell.c:192
msgid "Bell event"
msgstr "Udalosť zvončeka"
# X window system preloz, napr. system na spravu okien X
#: src/core/display.c:608
#, c-format
msgid "Failed to open X Window System display “%s”\n"
msgstr "Zlyhalo otvorenie displeja systému na správu okien X „%s“\n"
# cmd desc
#: src/core/main.c:190
msgid "Disable connection to session manager"
@ -683,41 +713,45 @@ msgstr "Spustí ako kompozitor protokolu wayland"
msgid "Run as a nested compositor"
msgstr "Spustí ako kompozitor s vnoreným režimom"
#: src/core/main.c:240
#: src/core/main.c:238
msgid "Run wayland compositor without starting Xwayland"
msgstr ""
#: src/core/main.c:246
msgid "Run as a full display server, rather than nested"
msgstr "Spustí ako plnohodnotný zobrazovací server, namiesto vnoreného režimu"
#: src/core/main.c:246
#: src/core/main.c:252
msgid "Run with X11 backend"
msgstr "Spustí s obslužným programom X11"
# %s is a window title
#. Translators: %s is a window title
#: src/core/meta-close-dialog-default.c:147
#: src/core/meta-close-dialog-default.c:151
#, c-format
msgid "“%s” is not responding."
msgstr "„%s“ neodpovedá."
#: src/core/meta-close-dialog-default.c:149
#: src/core/meta-close-dialog-default.c:153
msgid "Application is not responding."
msgstr "Aplikácia neodpovedá."
#: src/core/meta-close-dialog-default.c:154
#: src/core/meta-close-dialog-default.c:158
msgid ""
"You may choose to wait a short while for it to continue or force the "
"application to quit entirely."
msgstr ""
"Môžete chvíľu počkať na pokračovanie aplikácie, alebo ju môžete ukončiť."
#: src/core/meta-close-dialog-default.c:161
#: src/core/meta-close-dialog-default.c:165
msgid "_Force Quit"
msgstr "_Vynútiť ukončenie"
#: src/core/meta-close-dialog-default.c:161
#: src/core/meta-close-dialog-default.c:165
msgid "_Wait"
msgstr "_Počkať"
#: src/core/mutter.c:39
#: src/core/mutter.c:38
#, c-format
msgid ""
"mutter %s\n"
@ -733,21 +767,30 @@ msgstr ""
"Záruka sa NEPOSKYTUJE; ani na PREDAJNOSŤ alebo VHODNOSŤ PRE URČITÝ ÚČEL.\n"
# cmd desc
#: src/core/mutter.c:53
#: src/core/mutter.c:52
msgid "Print version"
msgstr "Zobrazí verziu"
# cmd desc
#: src/core/mutter.c:59
#: src/core/mutter.c:58
msgid "Mutter plugin to use"
msgstr "Použije zásuvný modul Mutter"
#: src/core/prefs.c:1997
#: src/core/prefs.c:1911
#, c-format
msgid "Workspace %d"
msgstr "Pracovný priestor č. %d"
#: src/core/screen.c:583
#: src/core/util.c:122
msgid "Mutter was compiled without support for verbose mode\n"
msgstr "Mutter bol skompilovaný bez výpisu podrobností pri behu\n"
#: src/wayland/meta-wayland-tablet-pad.c:568
#, c-format
msgid "Mode Switch: Mode %d"
msgstr "Prepínač režimu: Režim č. %d"
#: src/x11/meta-x11-display.c:676
#, c-format
msgid ""
"Display “%s” already has a window manager; try using the --replace option to "
@ -756,21 +799,27 @@ msgstr ""
"Displej „%s“ už má správcu okien. Skúste použiť prepínač --replace, aby sa "
"aktuálny správca nahradil."
#: src/core/screen.c:668
#: src/x11/meta-x11-display.c:1089
msgid "Failed to initialize GDK\n"
msgstr "Zlyhala inicializácia GDK\n"
# X window system preloz, napr. system na spravu okien X
#: src/x11/meta-x11-display.c:1113
#, c-format
msgid "Failed to open X Window System display “%s”\n"
msgstr "Zlyhalo otvorenie displeja systému na správu okien X „%s“\n"
#: src/x11/meta-x11-display.c:1196
#, c-format
msgid "Screen %d on display “%s” is invalid\n"
msgstr "Obrazovka č. %d na displeji „%s“ nie je platná\n"
#: src/core/util.c:120
msgid "Mutter was compiled without support for verbose mode\n"
msgstr "Mutter bol skompilovaný bez výpisu podrobností pri behu\n"
#: src/wayland/meta-wayland-tablet-pad.c:563
#: src/x11/meta-x11-selection-input-stream.c:460
#, c-format
msgid "Mode Switch: Mode %d"
msgstr "Prepínač režimu: Režim č. %d"
msgid "Format %s not supported"
msgstr "Formát %s nie je podporovaný"
#: src/x11/session.c:1818
#: src/x11/session.c:1821
msgid ""
"These windows do not support “save current setup” and will have to be "
"restarted manually next time you log in."
@ -779,7 +828,7 @@ msgstr ""
"prihlásení ich budete musieť znovu spustiť ručne."
# window title; wm_client_machine
#: src/x11/window-props.c:559
#: src/x11/window-props.c:569
#, c-format
msgid "%s (on %s)"
msgstr "%s (na %s)"

View File

@ -818,7 +818,7 @@ update_trackball_scroll_button (MetaInputSettings *input_settings,
for (l = devices; l; l = l->next)
{
device = devices->data;
device = l->data;
if (input_settings_class->is_trackball_device (input_settings, device))
input_settings_class->set_scroll_button (input_settings, device, button);

View File

@ -172,6 +172,7 @@ assign_monitor_crtc (MetaMonitor *monitor,
MetaCrtc *crtc;
MetaMonitorTransform transform;
MetaMonitorTransform crtc_transform;
MetaMonitorTransform crtc_hw_transform;
int crtc_x, crtc_y;
float x_offset, y_offset;
float scale = 0.0;
@ -200,10 +201,12 @@ assign_monitor_crtc (MetaMonitor *monitor,
transform = data->logical_monitor_config->transform;
crtc_transform = meta_monitor_logical_to_crtc_transform (monitor, transform);
if (!meta_monitor_manager_is_transform_handled (data->monitor_manager,
crtc,
crtc_transform))
crtc_transform = META_MONITOR_TRANSFORM_NORMAL;
if (meta_monitor_manager_is_transform_handled (data->monitor_manager,
crtc,
crtc_transform))
crtc_hw_transform = crtc_transform;
else
crtc_hw_transform = META_MONITOR_TRANSFORM_NORMAL;
meta_monitor_calculate_crtc_pos (monitor, mode, output, crtc_transform,
&crtc_x, &crtc_y);
@ -244,7 +247,7 @@ assign_monitor_crtc (MetaMonitor *monitor,
.crtc = crtc,
.mode = crtc_mode,
.layout = crtc_layout,
.transform = crtc_transform,
.transform = crtc_hw_transform,
.outputs = g_ptr_array_new ()
};
g_ptr_array_add (crtc_info->outputs, output);
@ -443,23 +446,35 @@ MetaMonitorsConfigKey *
meta_create_monitors_config_key_for_current_state (MetaMonitorManager *monitor_manager)
{
MetaMonitorsConfigKey *config_key;
MetaMonitorSpec *laptop_monitor_spec;
GList *l;
GList *monitor_specs;
laptop_monitor_spec = NULL;
monitor_specs = NULL;
for (l = monitor_manager->monitors; l; l = l->next)
{
MetaMonitor *monitor = l->data;
MetaMonitorSpec *monitor_spec;
if (meta_monitor_is_laptop_panel (monitor) &&
is_lid_closed (monitor_manager))
continue;
if (meta_monitor_is_laptop_panel (monitor))
{
laptop_monitor_spec = meta_monitor_get_spec (monitor);
if (is_lid_closed (monitor_manager))
continue;
}
monitor_spec = meta_monitor_spec_clone (meta_monitor_get_spec (monitor));
monitor_specs = g_list_prepend (monitor_specs, monitor_spec);
}
if (!monitor_specs && laptop_monitor_spec)
{
monitor_specs =
g_list_prepend (NULL, meta_monitor_spec_clone (laptop_monitor_spec));
}
if (!monitor_specs)
return NULL;

View File

@ -817,19 +817,19 @@ calculate_tile_coordinate (MetaMonitor *monitor,
case META_MONITOR_TRANSFORM_270:
case META_MONITOR_TRANSFORM_FLIPPED_270:
if (other_output->tile_info.loc_v_tile == output->tile_info.loc_v_tile &&
other_output->tile_info.loc_h_tile < output->tile_info.loc_h_tile)
other_output->tile_info.loc_h_tile > output->tile_info.loc_h_tile)
y += other_output->tile_info.tile_w;
if (other_output->tile_info.loc_h_tile == output->tile_info.loc_h_tile &&
other_output->tile_info.loc_v_tile < output->tile_info.loc_v_tile)
other_output->tile_info.loc_v_tile > output->tile_info.loc_v_tile)
x += other_output->tile_info.tile_h;
break;
case META_MONITOR_TRANSFORM_90:
case META_MONITOR_TRANSFORM_FLIPPED_90:
if (other_output->tile_info.loc_v_tile == output->tile_info.loc_v_tile &&
other_output->tile_info.loc_h_tile > output->tile_info.loc_h_tile)
other_output->tile_info.loc_h_tile < output->tile_info.loc_h_tile)
y += other_output->tile_info.tile_w;
if (other_output->tile_info.loc_h_tile == output->tile_info.loc_h_tile &&
other_output->tile_info.loc_v_tile > output->tile_info.loc_v_tile)
other_output->tile_info.loc_v_tile < output->tile_info.loc_v_tile)
x += other_output->tile_info.tile_h;
break;
}

View File

@ -55,6 +55,7 @@ struct _MetaRemoteDesktopSession
MetaScreenCastSession *screen_cast_session;
gulong screen_cast_session_closed_handler_id;
guint started : 1;
ClutterVirtualInputDevice *virtual_pointer;
ClutterVirtualInputDevice *virtual_keyboard;
@ -119,7 +120,7 @@ meta_remote_desktop_session_start (MetaRemoteDesktopSession *session,
ClutterBackend *backend = clutter_get_default_backend ();
ClutterSeat *seat = clutter_backend_get_default_seat (backend);
g_assert (!session->virtual_pointer && !session->virtual_keyboard);
g_assert (!session->started);
if (session->screen_cast_session)
{
@ -135,6 +136,7 @@ meta_remote_desktop_session_start (MetaRemoteDesktopSession *session,
clutter_seat_create_virtual_device (seat, CLUTTER_TOUCHSCREEN_DEVICE);
init_remote_access_handle (session);
session->started = TRUE;
return TRUE;
}
@ -145,6 +147,8 @@ meta_remote_desktop_session_close (MetaRemoteDesktopSession *session)
MetaDBusRemoteDesktopSession *skeleton =
META_DBUS_REMOTE_DESKTOP_SESSION (session);
session->started = FALSE;
if (session->screen_cast_session)
{
g_clear_signal_handler (&session->screen_cast_session_closed_handler_id,
@ -249,6 +253,29 @@ check_permission (MetaRemoteDesktopSession *session,
g_dbus_method_invocation_get_sender (invocation)) == 0;
}
static gboolean
meta_remote_desktop_session_check_can_notify (MetaRemoteDesktopSession *session,
GDBusMethodInvocation *invocation)
{
if (!session->started)
{
g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
G_DBUS_ERROR_FAILED,
"Session not started");
return FALSE;
}
if (!check_permission (session, invocation))
{
g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
G_DBUS_ERROR_ACCESS_DENIED,
"Permission denied");
return FALSE;
}
return TRUE;
}
static gboolean
handle_start (MetaDBusRemoteDesktopSession *skeleton,
GDBusMethodInvocation *invocation)
@ -256,6 +283,14 @@ handle_start (MetaDBusRemoteDesktopSession *skeleton,
MetaRemoteDesktopSession *session = META_REMOTE_DESKTOP_SESSION (skeleton);
GError *error = NULL;
if (session->started)
{
g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
G_DBUS_ERROR_FAILED,
"Already started");
return TRUE;
}
if (!check_permission (session, invocation))
{
g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
@ -288,6 +323,14 @@ handle_stop (MetaDBusRemoteDesktopSession *skeleton,
{
MetaRemoteDesktopSession *session = META_REMOTE_DESKTOP_SESSION (skeleton);
if (!session->started)
{
g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
G_DBUS_ERROR_FAILED,
"Session not started");
return TRUE;
}
if (!check_permission (session, invocation))
{
g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
@ -312,13 +355,8 @@ handle_notify_keyboard_keycode (MetaDBusRemoteDesktopSession *skeleton,
MetaRemoteDesktopSession *session = META_REMOTE_DESKTOP_SESSION (skeleton);
ClutterKeyState state;
if (!check_permission (session, invocation))
{
g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
G_DBUS_ERROR_ACCESS_DENIED,
"Permission denied");
return TRUE;
}
if (!meta_remote_desktop_session_check_can_notify (session, invocation))
return TRUE;
if (pressed)
state = CLUTTER_KEY_STATE_PRESSED;
@ -344,13 +382,8 @@ handle_notify_keyboard_keysym (MetaDBusRemoteDesktopSession *skeleton,
MetaRemoteDesktopSession *session = META_REMOTE_DESKTOP_SESSION (skeleton);
ClutterKeyState state;
if (!check_permission (session, invocation))
{
g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
G_DBUS_ERROR_ACCESS_DENIED,
"Permission denied");
return TRUE;
}
if (!meta_remote_desktop_session_check_can_notify (session, invocation))
return TRUE;
if (pressed)
state = CLUTTER_KEY_STATE_PRESSED;
@ -398,13 +431,8 @@ handle_notify_pointer_button (MetaDBusRemoteDesktopSession *skeleton,
uint32_t button;
ClutterButtonState state;
if (!check_permission (session, invocation))
{
g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
G_DBUS_ERROR_ACCESS_DENIED,
"Permission denied");
return TRUE;
}
if (!meta_remote_desktop_session_check_can_notify (session, invocation))
return TRUE;
button = translate_to_clutter_button (button_code);
@ -434,13 +462,8 @@ handle_notify_pointer_axis (MetaDBusRemoteDesktopSession *skeleton,
MetaRemoteDesktopSession *session = META_REMOTE_DESKTOP_SESSION (skeleton);
ClutterScrollFinishFlags finish_flags = CLUTTER_SCROLL_FINISHED_NONE;
if (!check_permission (session, invocation))
{
g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
G_DBUS_ERROR_ACCESS_DENIED,
"Permission denied");
return TRUE;
}
if (!meta_remote_desktop_session_check_can_notify (session, invocation))
return TRUE;
if (flags & META_REMOTE_DESKTOP_NOTIFY_AXIS_FLAGS_FINISH)
{
@ -487,13 +510,8 @@ handle_notify_pointer_axis_discrete (MetaDBusRemoteDesktopSession *skeleton,
ClutterScrollDirection direction;
int step_count;
if (!check_permission (session, invocation))
{
g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
G_DBUS_ERROR_ACCESS_DENIED,
"Permission denied");
return TRUE;
}
if (!meta_remote_desktop_session_check_can_notify (session, invocation))
return TRUE;
if (axis > 1)
{
@ -538,13 +556,8 @@ handle_notify_pointer_motion_relative (MetaDBusRemoteDesktopSession *skeleton,
{
MetaRemoteDesktopSession *session = META_REMOTE_DESKTOP_SESSION (skeleton);
if (!check_permission (session, invocation))
{
g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
G_DBUS_ERROR_ACCESS_DENIED,
"Permission denied");
return TRUE;
}
if (!meta_remote_desktop_session_check_can_notify (session, invocation))
return TRUE;
clutter_virtual_input_device_notify_relative_motion (session->virtual_pointer,
CLUTTER_CURRENT_TIME,
@ -567,13 +580,9 @@ handle_notify_pointer_motion_absolute (MetaDBusRemoteDesktopSession *skeleton,
MetaScreenCastStream *stream;
double abs_x, abs_y;
if (!check_permission (session, invocation))
{
g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
G_DBUS_ERROR_ACCESS_DENIED,
"Permission denied");
return TRUE;
}
if (!meta_remote_desktop_session_check_can_notify (session, invocation))
return TRUE;
if (!session->screen_cast_session)
{
@ -617,13 +626,8 @@ handle_notify_touch_down (MetaDBusRemoteDesktopSession *skeleton,
MetaScreenCastStream *stream;
double abs_x, abs_y;
if (!check_permission (session, invocation))
{
g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
G_DBUS_ERROR_ACCESS_DENIED,
"Permission denied");
return TRUE;
}
if (!meta_remote_desktop_session_check_can_notify (session, invocation))
return TRUE;
if (!session->screen_cast_session)
{
@ -668,13 +672,9 @@ handle_notify_touch_motion (MetaDBusRemoteDesktopSession *skeleton,
MetaScreenCastStream *stream;
double abs_x, abs_y;
if (!check_permission (session, invocation))
{
g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
G_DBUS_ERROR_ACCESS_DENIED,
"Permission denied");
return TRUE;
}
if (!meta_remote_desktop_session_check_can_notify (session, invocation))
return TRUE;
if (!session->screen_cast_session)
{
@ -714,13 +714,8 @@ handle_notify_touch_up (MetaDBusRemoteDesktopSession *skeleton,
{
MetaRemoteDesktopSession *session = META_REMOTE_DESKTOP_SESSION (skeleton);
if (!check_permission (session, invocation))
{
g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
G_DBUS_ERROR_ACCESS_DENIED,
"Permission denied");
return TRUE;
}
if (!meta_remote_desktop_session_check_can_notify (session, invocation))
return TRUE;
clutter_virtual_input_device_notify_touch_up (session->virtual_touchscreen,
CLUTTER_CURRENT_TIME,

View File

@ -160,14 +160,12 @@ meta_renderer_real_rebuild_views (MetaRenderer *renderer)
}
void
meta_renderer_set_legacy_view (MetaRenderer *renderer,
MetaRendererView *legacy_view)
meta_renderer_add_view (MetaRenderer *renderer,
MetaRendererView *view)
{
MetaRendererPrivate *priv = meta_renderer_get_instance_private (renderer);
g_assert (!priv->views);
priv->views = g_list_append (priv->views, legacy_view);
priv->views = g_list_append (priv->views, view);
}
/**

View File

@ -54,8 +54,8 @@ CoglRenderer * meta_renderer_create_cogl_renderer (MetaRenderer *renderer);
void meta_renderer_rebuild_views (MetaRenderer *renderer);
void meta_renderer_set_legacy_view (MetaRenderer *renderer,
MetaRendererView *legacy_view);
void meta_renderer_add_view (MetaRenderer *renderer,
MetaRendererView *view);
META_EXPORT_TEST
GList * meta_renderer_get_views (MetaRenderer *renderer);

View File

@ -115,13 +115,16 @@ meta_screen_cast_monitor_stream_src_get_specs (MetaScreenCastStreamSrc *src,
}
static void
stage_painted (MetaStage *stage,
ClutterStageView *view,
gpointer user_data)
stage_painted (MetaStage *stage,
ClutterStageView *view,
ClutterPaintContext *paint_context,
gpointer user_data)
{
MetaScreenCastStreamSrc *src = META_SCREEN_CAST_STREAM_SRC (user_data);
MetaScreenCastRecordFlag flags;
meta_screen_cast_stream_src_maybe_record_frame (src);
flags = META_SCREEN_CAST_RECORD_FLAG_NONE;
meta_screen_cast_stream_src_maybe_record_frame (src, flags);
}
static MetaBackend *
@ -180,6 +183,7 @@ sync_cursor_state (MetaScreenCastMonitorStreamSrc *monitor_src)
{
MetaScreenCastStreamSrc *src = META_SCREEN_CAST_STREAM_SRC (monitor_src);
ClutterStage *stage = get_stage (monitor_src);
MetaScreenCastRecordFlag flags;
if (!is_cursor_in_stream (monitor_src))
return;
@ -187,7 +191,11 @@ sync_cursor_state (MetaScreenCastMonitorStreamSrc *monitor_src)
if (clutter_stage_is_redraw_queued (stage))
return;
meta_screen_cast_stream_src_maybe_record_frame (src);
if (meta_screen_cast_stream_src_pending_follow_up_frame (src))
return;
flags = META_SCREEN_CAST_RECORD_FLAG_CURSOR_ONLY;
meta_screen_cast_stream_src_maybe_record_frame (src, flags);
}
static void
@ -361,8 +369,9 @@ meta_screen_cast_monitor_stream_src_disable (MetaScreenCastStreamSrc *src)
}
static gboolean
meta_screen_cast_monitor_stream_src_record_frame (MetaScreenCastStreamSrc *src,
uint8_t *data)
meta_screen_cast_monitor_stream_src_record_to_buffer (MetaScreenCastStreamSrc *src,
uint8_t *data,
GError **error)
{
MetaScreenCastMonitorStreamSrc *monitor_src =
META_SCREEN_CAST_MONITOR_STREAM_SRC (src);
@ -371,9 +380,6 @@ meta_screen_cast_monitor_stream_src_record_frame (MetaScreenCastStreamSrc *src,
MetaLogicalMonitor *logical_monitor;
stage = get_stage (monitor_src);
if (!clutter_stage_is_redraw_queued (stage))
return FALSE;
monitor = get_monitor (monitor_src);
logical_monitor = meta_monitor_get_logical_monitor (monitor);
clutter_stage_capture_into (stage, FALSE, &logical_monitor->rect, data);
@ -382,8 +388,9 @@ meta_screen_cast_monitor_stream_src_record_frame (MetaScreenCastStreamSrc *src,
}
static gboolean
meta_screen_cast_monitor_stream_src_blit_to_framebuffer (MetaScreenCastStreamSrc *src,
CoglFramebuffer *framebuffer)
meta_screen_cast_monitor_stream_src_record_to_framebuffer (MetaScreenCastStreamSrc *src,
CoglFramebuffer *framebuffer,
GError **error)
{
MetaScreenCastMonitorStreamSrc *monitor_src =
META_SCREEN_CAST_MONITOR_STREAM_SRC (src);
@ -407,7 +414,6 @@ meta_screen_cast_monitor_stream_src_blit_to_framebuffer (MetaScreenCastStreamSrc
for (l = meta_renderer_get_views (renderer); l; l = l->next)
{
ClutterStageView *view = CLUTTER_STAGE_VIEW (l->data);
g_autoptr (GError) error = NULL;
CoglFramebuffer *view_framebuffer;
MetaRectangle view_layout;
int x, y;
@ -428,12 +434,8 @@ meta_screen_cast_monitor_stream_src_blit_to_framebuffer (MetaScreenCastStreamSrc
x, y,
cogl_framebuffer_get_width (view_framebuffer),
cogl_framebuffer_get_height (view_framebuffer),
&error))
{
g_warning ("Error blitting view into DMABuf framebuffer: %s",
error->message);
return FALSE;
}
error))
return FALSE;
}
cogl_framebuffer_finish (framebuffer);
@ -441,6 +443,44 @@ meta_screen_cast_monitor_stream_src_blit_to_framebuffer (MetaScreenCastStreamSrc
return TRUE;
}
static void
meta_screen_cast_monitor_stream_record_follow_up (MetaScreenCastStreamSrc *src)
{
MetaScreenCastMonitorStreamSrc *monitor_src =
META_SCREEN_CAST_MONITOR_STREAM_SRC (src);
MetaBackend *backend = get_backend (monitor_src);
MetaRenderer *renderer = meta_backend_get_renderer (backend);
ClutterStage *stage = get_stage (monitor_src);
MetaMonitor *monitor;
MetaLogicalMonitor *logical_monitor;
MetaRectangle logical_monitor_layout;
GList *l;
monitor = get_monitor (monitor_src);
logical_monitor = meta_monitor_get_logical_monitor (monitor);
logical_monitor_layout = meta_logical_monitor_get_layout (logical_monitor);
for (l = meta_renderer_get_views (renderer); l; l = l->next)
{
MetaRendererView *view = l->data;
MetaRectangle view_layout;
MetaRectangle damage;
clutter_stage_view_get_layout (CLUTTER_STAGE_VIEW (view), &view_layout);
if (!meta_rectangle_overlap (&logical_monitor_layout, &view_layout))
continue;
damage = (cairo_rectangle_int_t) {
.x = view_layout.x,
.y = view_layout.y,
.width = 1,
.height = 1,
};
clutter_actor_queue_redraw_with_clip (CLUTTER_ACTOR (stage), &damage);
}
}
static void
meta_screen_cast_monitor_stream_src_set_cursor_metadata (MetaScreenCastStreamSrc *src,
struct spa_meta_cursor *spa_meta_cursor)
@ -561,9 +601,12 @@ meta_screen_cast_monitor_stream_src_class_init (MetaScreenCastMonitorStreamSrcCl
src_class->get_specs = meta_screen_cast_monitor_stream_src_get_specs;
src_class->enable = meta_screen_cast_monitor_stream_src_enable;
src_class->disable = meta_screen_cast_monitor_stream_src_disable;
src_class->record_frame = meta_screen_cast_monitor_stream_src_record_frame;
src_class->blit_to_framebuffer =
meta_screen_cast_monitor_stream_src_blit_to_framebuffer;
src_class->record_to_buffer =
meta_screen_cast_monitor_stream_src_record_to_buffer;
src_class->record_to_framebuffer =
meta_screen_cast_monitor_stream_src_record_to_framebuffer;
src_class->record_follow_up =
meta_screen_cast_monitor_stream_record_follow_up;
src_class->set_cursor_metadata =
meta_screen_cast_monitor_stream_src_set_cursor_metadata;
}

View File

@ -68,6 +68,7 @@ typedef struct _MetaPipeWireSource
{
GSource base;
MetaScreenCastStreamSrc *src;
struct pw_loop *pipewire_loop;
} MetaPipeWireSource;
@ -81,6 +82,7 @@ typedef struct _MetaScreenCastStreamSrcPrivate
struct spa_hook pipewire_core_listener;
gboolean is_enabled;
gboolean emit_closed_after_dispatch;
struct pw_stream *pipewire_stream;
struct spa_hook pipewire_stream_listener;
@ -89,7 +91,8 @@ typedef struct _MetaScreenCastStreamSrcPrivate
struct spa_video_info_raw video_format;
int video_stride;
uint64_t last_frame_timestamp_us;
int64_t last_frame_timestamp_us;
guint follow_up_frame_source_id;
GHashTable *dmabuf_handles;
@ -107,6 +110,12 @@ G_DEFINE_TYPE_WITH_CODE (MetaScreenCastStreamSrc,
meta_screen_cast_stream_src_init_initable_iface)
G_ADD_PRIVATE (MetaScreenCastStreamSrc))
static inline uint32_t
us2ms (uint64_t us)
{
return (uint32_t) (us / 1000);
}
static void
meta_screen_cast_stream_src_get_specs (MetaScreenCastStreamSrc *src,
int *width,
@ -133,23 +142,34 @@ meta_screen_cast_stream_src_get_videocrop (MetaScreenCastStreamSrc *src,
}
static gboolean
meta_screen_cast_stream_src_record_frame (MetaScreenCastStreamSrc *src,
uint8_t *data)
meta_screen_cast_stream_src_record_to_buffer (MetaScreenCastStreamSrc *src,
uint8_t *data,
GError **error)
{
MetaScreenCastStreamSrcClass *klass =
META_SCREEN_CAST_STREAM_SRC_GET_CLASS (src);
return klass->record_frame (src, data);
return klass->record_to_buffer (src, data, error);
}
static gboolean
meta_screen_cast_stream_src_blit_to_framebuffer (MetaScreenCastStreamSrc *src,
CoglFramebuffer *framebuffer)
meta_screen_cast_stream_src_record_to_framebuffer (MetaScreenCastStreamSrc *src,
CoglFramebuffer *framebuffer,
GError **error)
{
MetaScreenCastStreamSrcClass *klass =
META_SCREEN_CAST_STREAM_SRC_GET_CLASS (src);
return klass->blit_to_framebuffer (src, framebuffer);
return klass->record_to_framebuffer (src, framebuffer, error);
}
static void
meta_screen_cast_stream_src_record_follow_up (MetaScreenCastStreamSrc *src)
{
MetaScreenCastStreamSrcClass *klass =
META_SCREEN_CAST_STREAM_SRC_GET_CLASS (src);
klass->record_follow_up (src);
}
static void
@ -407,9 +427,10 @@ maybe_record_cursor (MetaScreenCastStreamSrc *src,
}
static gboolean
do_record_frame (MetaScreenCastStreamSrc *src,
struct spa_buffer *spa_buffer,
uint8_t *data)
do_record_frame (MetaScreenCastStreamSrc *src,
struct spa_buffer *spa_buffer,
uint8_t *data,
GError **error)
{
MetaScreenCastStreamSrcPrivate *priv =
meta_screen_cast_stream_src_get_instance_private (src);
@ -417,7 +438,7 @@ do_record_frame (MetaScreenCastStreamSrc *src,
if (spa_buffer->datas[0].data ||
spa_buffer->datas[0].type == SPA_DATA_MemFd)
{
return meta_screen_cast_stream_src_record_frame (src, data);
return meta_screen_cast_stream_src_record_to_buffer (src, data, error);
}
else if (spa_buffer->datas[0].type == SPA_DATA_DmaBuf)
{
@ -427,14 +448,56 @@ do_record_frame (MetaScreenCastStreamSrc *src,
CoglFramebuffer *dmabuf_fbo =
cogl_dma_buf_handle_get_framebuffer (dmabuf_handle);
return meta_screen_cast_stream_src_blit_to_framebuffer (src, dmabuf_fbo);
return meta_screen_cast_stream_src_record_to_framebuffer (src,
dmabuf_fbo,
error);
}
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"Unknown SPA buffer type %u", spa_buffer->datas[0].type);
return FALSE;
}
gboolean
meta_screen_cast_stream_src_pending_follow_up_frame (MetaScreenCastStreamSrc *src)
{
MetaScreenCastStreamSrcPrivate *priv =
meta_screen_cast_stream_src_get_instance_private (src);
return priv->follow_up_frame_source_id != 0;
}
static gboolean
follow_up_frame_cb (gpointer user_data)
{
MetaScreenCastStreamSrc *src = user_data;
MetaScreenCastStreamSrcPrivate *priv =
meta_screen_cast_stream_src_get_instance_private (src);
priv->follow_up_frame_source_id = 0;
meta_screen_cast_stream_src_record_follow_up (src);
return G_SOURCE_REMOVE;
}
static void
maybe_schedule_follow_up_frame (MetaScreenCastStreamSrc *src,
int64_t timeout_us)
{
MetaScreenCastStreamSrcPrivate *priv =
meta_screen_cast_stream_src_get_instance_private (src);
if (priv->follow_up_frame_source_id)
return;
priv->follow_up_frame_source_id = g_timeout_add (us2ms (timeout_us),
follow_up_frame_cb,
src);
}
void
meta_screen_cast_stream_src_maybe_record_frame (MetaScreenCastStreamSrc *src)
meta_screen_cast_stream_src_maybe_record_frame (MetaScreenCastStreamSrc *src,
MetaScreenCastRecordFlag flags)
{
MetaScreenCastStreamSrcPrivate *priv =
meta_screen_cast_stream_src_get_instance_private (src);
@ -443,13 +506,29 @@ meta_screen_cast_stream_src_maybe_record_frame (MetaScreenCastStreamSrc *src)
struct spa_buffer *spa_buffer;
uint8_t *data = NULL;
uint64_t now_us;
g_autoptr (GError) error = NULL;
now_us = g_get_monotonic_time ();
if (priv->last_frame_timestamp_us != 0 &&
(now_us - priv->last_frame_timestamp_us <
((1000000 * priv->video_format.max_framerate.denom) /
priv->video_format.max_framerate.num)))
return;
if (priv->video_format.max_framerate.num > 0 &&
priv->last_frame_timestamp_us != 0)
{
int64_t min_interval_us;
int64_t time_since_last_frame_us;
min_interval_us =
((G_USEC_PER_SEC * priv->video_format.max_framerate.denom) /
priv->video_format.max_framerate.num);
time_since_last_frame_us = now_us - priv->last_frame_timestamp_us;
if (time_since_last_frame_us < min_interval_us)
{
int64_t timeout_us;
timeout_us = min_interval_us - time_since_last_frame_us;
maybe_schedule_follow_up_frame (src, timeout_us);
return;
}
}
if (!priv->pipewire_stream)
return;
@ -467,34 +546,43 @@ meta_screen_cast_stream_src_maybe_record_frame (MetaScreenCastStreamSrc *src)
return;
}
if (do_record_frame (src, spa_buffer, data))
if (!(flags & META_SCREEN_CAST_RECORD_FLAG_CURSOR_ONLY))
{
struct spa_meta_region *spa_meta_video_crop;
spa_buffer->datas[0].chunk->size = spa_buffer->datas[0].maxsize;
spa_buffer->datas[0].chunk->stride = priv->video_stride;
/* Update VideoCrop if needed */
spa_meta_video_crop =
spa_buffer_find_meta_data (spa_buffer, SPA_META_VideoCrop,
sizeof (*spa_meta_video_crop));
if (spa_meta_video_crop)
g_clear_handle_id (&priv->follow_up_frame_source_id, g_source_remove);
if (do_record_frame (src, spa_buffer, data, &error))
{
if (meta_screen_cast_stream_src_get_videocrop (src, &crop_rect))
struct spa_meta_region *spa_meta_video_crop;
spa_buffer->datas[0].chunk->size = spa_buffer->datas[0].maxsize;
spa_buffer->datas[0].chunk->stride = priv->video_stride;
/* Update VideoCrop if needed */
spa_meta_video_crop =
spa_buffer_find_meta_data (spa_buffer, SPA_META_VideoCrop,
sizeof (*spa_meta_video_crop));
if (spa_meta_video_crop)
{
spa_meta_video_crop->region.position.x = crop_rect.x;
spa_meta_video_crop->region.position.y = crop_rect.y;
spa_meta_video_crop->region.size.width = crop_rect.width;
spa_meta_video_crop->region.size.height = crop_rect.height;
}
else
{
spa_meta_video_crop->region.position.x = 0;
spa_meta_video_crop->region.position.y = 0;
spa_meta_video_crop->region.size.width = priv->stream_width;
spa_meta_video_crop->region.size.height = priv->stream_height;
if (meta_screen_cast_stream_src_get_videocrop (src, &crop_rect))
{
spa_meta_video_crop->region.position.x = crop_rect.x;
spa_meta_video_crop->region.position.y = crop_rect.y;
spa_meta_video_crop->region.size.width = crop_rect.width;
spa_meta_video_crop->region.size.height = crop_rect.height;
}
else
{
spa_meta_video_crop->region.position.x = 0;
spa_meta_video_crop->region.position.y = 0;
spa_meta_video_crop->region.size.width = priv->stream_width;
spa_meta_video_crop->region.size.height = priv->stream_height;
}
}
}
else
{
g_warning ("Failed to record screen cast frame: %s", error->message);
spa_buffer->datas[0].chunk->size = 0;
}
}
else
{
@ -536,13 +624,9 @@ meta_screen_cast_stream_src_disable (MetaScreenCastStreamSrc *src)
META_SCREEN_CAST_STREAM_SRC_GET_CLASS (src)->disable (src);
priv->is_enabled = FALSE;
}
g_clear_handle_id (&priv->follow_up_frame_source_id, g_source_remove);
static void
meta_screen_cast_stream_src_notify_closed (MetaScreenCastStreamSrc *src)
{
g_signal_emit (src, signals[CLOSED], 0);
priv->is_enabled = FALSE;
}
static void
@ -559,7 +643,9 @@ on_stream_state_changed (void *data,
{
case PW_STREAM_STATE_ERROR:
g_warning ("pipewire stream error: %s", error_message);
meta_screen_cast_stream_src_notify_closed (src);
if (meta_screen_cast_stream_src_is_enabled (src))
meta_screen_cast_stream_src_disable (src);
priv->emit_closed_after_dispatch = TRUE;
break;
case PW_STREAM_STATE_PAUSED:
if (priv->node_id == SPA_ID_INVALID && priv->pipewire_stream)
@ -827,11 +913,17 @@ on_core_error (void *data,
const char *message)
{
MetaScreenCastStreamSrc *src = data;
MetaScreenCastStreamSrcPrivate *priv =
meta_screen_cast_stream_src_get_instance_private (src);
g_warning ("pipewire remote error: id:%u %s", id, message);
if (id == PW_ID_CORE && res == -EPIPE)
meta_screen_cast_stream_src_notify_closed (src);
{
if (meta_screen_cast_stream_src_is_enabled (src))
meta_screen_cast_stream_src_disable (src);
priv->emit_closed_after_dispatch = TRUE;
}
}
static gboolean
@ -848,12 +940,18 @@ pipewire_loop_source_dispatch (GSource *source,
gpointer user_data)
{
MetaPipeWireSource *pipewire_source = (MetaPipeWireSource *) source;
MetaScreenCastStreamSrc *src = pipewire_source->src;
MetaScreenCastStreamSrcPrivate *priv =
meta_screen_cast_stream_src_get_instance_private (src);
int result;
result = pw_loop_iterate (pipewire_source->pipewire_loop, 0);
if (result < 0)
g_warning ("pipewire_loop_iterate failed: %s", spa_strerror (result));
if (priv->emit_closed_after_dispatch)
g_signal_emit (src, signals[CLOSED], 0);
return TRUE;
}
@ -875,13 +973,14 @@ static GSourceFuncs pipewire_source_funcs =
};
static MetaPipeWireSource *
create_pipewire_source (void)
create_pipewire_source (MetaScreenCastStreamSrc *src)
{
MetaPipeWireSource *pipewire_source;
pipewire_source =
(MetaPipeWireSource *) g_source_new (&pipewire_source_funcs,
sizeof (MetaPipeWireSource));
pipewire_source->src = src;
pipewire_source->pipewire_loop = pw_loop_new (NULL);
if (!pipewire_source->pipewire_loop)
{
@ -913,7 +1012,7 @@ meta_screen_cast_stream_src_initable_init (GInitable *initable,
MetaScreenCastStreamSrcPrivate *priv =
meta_screen_cast_stream_src_get_instance_private (src);
priv->pipewire_source = create_pipewire_source ();
priv->pipewire_source = create_pipewire_source (src);
if (!priv->pipewire_source)
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
@ -975,8 +1074,8 @@ meta_screen_cast_stream_src_finalize (GObject *object)
if (meta_screen_cast_stream_src_is_enabled (src))
meta_screen_cast_stream_src_disable (src);
g_clear_pointer (&priv->dmabuf_handles, g_hash_table_destroy);
g_clear_pointer (&priv->pipewire_stream, pw_stream_destroy);
g_clear_pointer (&priv->dmabuf_handles, g_hash_table_destroy);
g_clear_pointer (&priv->pipewire_core, pw_core_disconnect);
g_clear_pointer (&priv->pipewire_context, pw_context_destroy);
g_source_destroy (&priv->pipewire_source->base);

View File

@ -37,6 +37,12 @@
typedef struct _MetaScreenCastStream MetaScreenCastStream;
typedef enum _MetaScreenCastRecordFlag
{
META_SCREEN_CAST_RECORD_FLAG_NONE = 0,
META_SCREEN_CAST_RECORD_FLAG_CURSOR_ONLY = 1 << 0,
} MetaScreenCastRecordFlag;
#define META_TYPE_SCREEN_CAST_STREAM_SRC (meta_screen_cast_stream_src_get_type ())
G_DECLARE_DERIVABLE_TYPE (MetaScreenCastStreamSrc,
meta_screen_cast_stream_src,
@ -53,17 +59,24 @@ struct _MetaScreenCastStreamSrcClass
float *frame_rate);
void (* enable) (MetaScreenCastStreamSrc *src);
void (* disable) (MetaScreenCastStreamSrc *src);
gboolean (* record_frame) (MetaScreenCastStreamSrc *src,
uint8_t *data);
gboolean (* blit_to_framebuffer) (MetaScreenCastStreamSrc *src,
CoglFramebuffer *framebuffer);
gboolean (* record_to_buffer) (MetaScreenCastStreamSrc *src,
uint8_t *data,
GError **error);
gboolean (* record_to_framebuffer) (MetaScreenCastStreamSrc *src,
CoglFramebuffer *framebuffer,
GError **error);
void (* record_follow_up) (MetaScreenCastStreamSrc *src);
gboolean (* get_videocrop) (MetaScreenCastStreamSrc *src,
MetaRectangle *crop_rect);
void (* set_cursor_metadata) (MetaScreenCastStreamSrc *src,
struct spa_meta_cursor *spa_meta_cursor);
};
void meta_screen_cast_stream_src_maybe_record_frame (MetaScreenCastStreamSrc *src);
void meta_screen_cast_stream_src_maybe_record_frame (MetaScreenCastStreamSrc *src,
MetaScreenCastRecordFlag flags);
gboolean meta_screen_cast_stream_src_pending_follow_up_frame (MetaScreenCastStreamSrc *src);
MetaScreenCastStream * meta_screen_cast_stream_src_get_stream (MetaScreenCastStreamSrc *src);

View File

@ -327,8 +327,10 @@ screen_cast_window_damaged (MetaWindowActor *actor,
MetaScreenCastWindowStreamSrc *window_src)
{
MetaScreenCastStreamSrc *src = META_SCREEN_CAST_STREAM_SRC (window_src);
MetaScreenCastRecordFlag flags;
meta_screen_cast_stream_src_maybe_record_frame (src);
flags = META_SCREEN_CAST_RECORD_FLAG_CURSOR_ONLY;
meta_screen_cast_stream_src_maybe_record_frame (src, flags);
}
static void
@ -365,6 +367,7 @@ static void
sync_cursor_state (MetaScreenCastWindowStreamSrc *window_src)
{
MetaScreenCastStreamSrc *src = META_SCREEN_CAST_STREAM_SRC (window_src);
MetaScreenCastRecordFlag flags;
if (!is_cursor_in_stream (window_src))
return;
@ -372,7 +375,8 @@ sync_cursor_state (MetaScreenCastWindowStreamSrc *window_src)
if (meta_screen_cast_window_has_damage (window_src->screen_cast_window))
return;
meta_screen_cast_stream_src_maybe_record_frame (src);
flags = META_SCREEN_CAST_RECORD_FLAG_CURSOR_ONLY;
meta_screen_cast_stream_src_maybe_record_frame (src, flags);
}
static void
@ -401,6 +405,7 @@ meta_screen_cast_window_stream_src_enable (MetaScreenCastStreamSrc *src)
MetaCursorTracker *cursor_tracker = meta_backend_get_cursor_tracker (backend);
MetaWindowActor *window_actor;
MetaScreenCastStream *stream;
MetaScreenCastRecordFlag flags;
window_actor = meta_window_actor_from_window (get_window (window_src));
if (!window_actor)
@ -438,7 +443,8 @@ meta_screen_cast_window_stream_src_enable (MetaScreenCastStreamSrc *src)
break;
}
meta_screen_cast_stream_src_maybe_record_frame (src);
flags = META_SCREEN_CAST_RECORD_FLAG_NONE;
meta_screen_cast_stream_src_maybe_record_frame (src, flags);
}
static void
@ -451,8 +457,9 @@ meta_screen_cast_window_stream_src_disable (MetaScreenCastStreamSrc *src)
}
static gboolean
meta_screen_cast_window_stream_src_record_frame (MetaScreenCastStreamSrc *src,
uint8_t *data)
meta_screen_cast_window_stream_src_record_to_buffer (MetaScreenCastStreamSrc *src,
uint8_t *data,
GError **error)
{
MetaScreenCastWindowStreamSrc *window_src =
META_SCREEN_CAST_WINDOW_STREAM_SRC (src);
@ -463,8 +470,9 @@ meta_screen_cast_window_stream_src_record_frame (MetaScreenCastStreamSrc *src,
}
static gboolean
meta_screen_cast_window_stream_src_blit_to_framebuffer (MetaScreenCastStreamSrc *src,
CoglFramebuffer *framebuffer)
meta_screen_cast_window_stream_src_record_to_framebuffer (MetaScreenCastStreamSrc *src,
CoglFramebuffer *framebuffer,
GError **error)
{
MetaScreenCastWindowStreamSrc *window_src =
META_SCREEN_CAST_WINDOW_STREAM_SRC (src);
@ -477,9 +485,13 @@ meta_screen_cast_window_stream_src_blit_to_framebuffer (MetaScreenCastStreamSrc
stream_rect.height = get_stream_height (window_src);
if (!meta_screen_cast_window_blit_to_framebuffer (window_src->screen_cast_window,
&stream_rect,
framebuffer))
return FALSE;
&stream_rect,
framebuffer))
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"Failed to blit window content to framebuffer");
return FALSE;
}
stream = meta_screen_cast_stream_src_get_stream (src);
switch (meta_screen_cast_stream_get_cursor_mode (stream))
@ -497,6 +509,15 @@ meta_screen_cast_window_stream_src_blit_to_framebuffer (MetaScreenCastStreamSrc
return TRUE;
}
static void
meta_screen_cast_window_stream_record_follow_up (MetaScreenCastStreamSrc *src)
{
MetaScreenCastRecordFlag flags;
flags = META_SCREEN_CAST_RECORD_FLAG_NONE;
meta_screen_cast_stream_src_maybe_record_frame (src, flags);
}
static void
meta_screen_cast_window_stream_src_set_cursor_metadata (MetaScreenCastStreamSrc *src,
struct spa_meta_cursor *spa_meta_cursor)
@ -580,9 +601,12 @@ meta_screen_cast_window_stream_src_class_init (MetaScreenCastWindowStreamSrcClas
src_class->get_specs = meta_screen_cast_window_stream_src_get_specs;
src_class->enable = meta_screen_cast_window_stream_src_enable;
src_class->disable = meta_screen_cast_window_stream_src_disable;
src_class->record_frame = meta_screen_cast_window_stream_src_record_frame;
src_class->blit_to_framebuffer =
meta_screen_cast_window_stream_src_blit_to_framebuffer;
src_class->record_to_buffer =
meta_screen_cast_window_stream_src_record_to_buffer;
src_class->record_to_framebuffer =
meta_screen_cast_window_stream_src_record_to_framebuffer;
src_class->record_follow_up =
meta_screen_cast_window_stream_record_follow_up;
src_class->get_videocrop = meta_screen_cast_window_stream_src_get_videocrop;
src_class->set_cursor_metadata = meta_screen_cast_window_stream_src_set_cursor_metadata;
}

View File

@ -38,9 +38,10 @@ typedef enum
META_STAGE_WATCH_AFTER_PAINT,
} MetaStageWatchPhase;
typedef void (* MetaStageWatchFunc) (MetaStage *stage,
ClutterStageView *view,
gpointer user_data);
typedef void (* MetaStageWatchFunc) (MetaStage *stage,
ClutterStageView *view,
ClutterPaintContext *paint_context,
gpointer user_data);
ClutterActor *meta_stage_new (MetaBackend *backend);

View File

@ -65,7 +65,6 @@ struct _MetaStage
ClutterStage parent;
GPtrArray *watchers[N_WATCH_MODES];
ClutterStageView *current_view;
GList *overlays;
gboolean is_active;
@ -169,6 +168,7 @@ meta_stage_finalize (GObject *object)
static void
notify_watchers_for_mode (MetaStage *stage,
ClutterStageView *view,
ClutterPaintContext *paint_context,
MetaStageWatchPhase watch_phase)
{
GPtrArray *watchers;
@ -183,7 +183,7 @@ notify_watchers_for_mode (MetaStage *stage,
if (watch->view && view != watch->view)
continue;
watch->callback (stage, view, watch->user_data);
watch->callback (stage, view, paint_context, watch->user_data);
}
}
@ -192,20 +192,34 @@ meta_stage_paint (ClutterActor *actor,
ClutterPaintContext *paint_context)
{
MetaStage *stage = META_STAGE (actor);
ClutterStageView *view;
GList *l;
CLUTTER_ACTOR_CLASS (meta_stage_parent_class)->paint (actor, paint_context);
notify_watchers_for_mode (stage, stage->current_view,
META_STAGE_WATCH_AFTER_ACTOR_PAINT);
view = clutter_paint_context_get_stage_view (paint_context);
if (view)
{
notify_watchers_for_mode (stage, view, paint_context,
META_STAGE_WATCH_AFTER_ACTOR_PAINT);
}
g_signal_emit (stage, signals[ACTORS_PAINTED], 0);
if (!(clutter_paint_context_get_paint_flags (paint_context) &
CLUTTER_PAINT_FLAG_NO_PAINT_SIGNAL))
g_signal_emit (stage, signals[ACTORS_PAINTED], 0);
for (l = stage->overlays; l; l = l->next)
meta_overlay_paint (l->data, paint_context);
if (!(clutter_paint_context_get_paint_flags (paint_context) &
CLUTTER_PAINT_FLAG_NO_CURSORS))
{
for (l = stage->overlays; l; l = l->next)
meta_overlay_paint (l->data, paint_context);
}
notify_watchers_for_mode (stage, stage->current_view,
META_STAGE_WATCH_AFTER_OVERLAY_PAINT);
if (view)
{
notify_watchers_for_mode (stage, view, paint_context,
META_STAGE_WATCH_AFTER_OVERLAY_PAINT);
}
}
static void
@ -215,13 +229,14 @@ meta_stage_paint_view (ClutterStage *stage,
{
MetaStage *meta_stage = META_STAGE (stage);
notify_watchers_for_mode (meta_stage, view, META_STAGE_WATCH_BEFORE_PAINT);
notify_watchers_for_mode (meta_stage, view, NULL,
META_STAGE_WATCH_BEFORE_PAINT);
meta_stage->current_view = view;
CLUTTER_STAGE_CLASS (meta_stage_parent_class)->paint_view (stage, view,
redraw_clip);
notify_watchers_for_mode (meta_stage, view, META_STAGE_WATCH_AFTER_PAINT);
notify_watchers_for_mode (meta_stage, view, NULL,
META_STAGE_WATCH_AFTER_PAINT);
}
static void

View File

@ -407,13 +407,14 @@ update_monitor_crtc_cursor (MetaMonitor *monitor,
else
scale = 1.0;
meta_monitor_calculate_crtc_pos (monitor, monitor_mode,
monitor_crtc_mode->output,
META_MONITOR_TRANSFORM_NORMAL,
&crtc_x, &crtc_y);
transform = meta_logical_monitor_get_transform (data->in_logical_monitor);
transform = meta_monitor_logical_to_crtc_transform (monitor, transform);
meta_monitor_calculate_crtc_pos (monitor, monitor_mode,
monitor_crtc_mode->output,
transform,
&crtc_x, &crtc_y);
if (meta_monitor_transform_is_rotated (transform))
{
crtc_width = monitor_crtc_mode->crtc_mode->height;

View File

@ -232,14 +232,28 @@ meta_gpu_kms_set_power_save_mode (MetaGpuKms *gpu_kms,
uint64_t state,
MetaKmsUpdate *kms_update)
{
MetaGpu *gpu = META_GPU (gpu_kms);
GList *l;
for (l = meta_gpu_get_outputs (META_GPU (gpu_kms)); l; l = l->next)
for (l = meta_gpu_get_outputs (gpu); l; l = l->next)
{
MetaOutput *output = l->data;
meta_output_kms_set_power_save_mode (output, state, kms_update);
}
if (state != META_POWER_SAVE_ON)
{
/* Turn off CRTCs for DPMS */
for (l = meta_gpu_get_crtcs (gpu); l; l = l->next)
{
MetaCrtc *crtc = META_CRTC (l->data);
meta_kms_update_mode_set (kms_update,
meta_crtc_kms_get_kms_crtc (crtc),
NULL, NULL);
}
}
}
gboolean

View File

@ -1,6 +1,6 @@
/*
* Copyright (C) 2018-2019 Red Hat
* Copyright (C) 2019 DisplayLink (UK) Ltd.
* Copyright (C) 2019-2020 DisplayLink (UK) Ltd.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@ -660,6 +660,9 @@ process_page_flip (MetaKmsImpl *impl,
meta_kms_page_flip_data_ref (page_flip_data));
}
if (ret != 0)
meta_kms_page_flip_data_unref (page_flip_data);
if (ret == -EBUSY)
{
CachedModeSet *cached_mode_set;

View File

@ -1,5 +1,6 @@
/*
* Copyright (C) 2018 Red Hat
* Copyright 2020 DisplayLink (UK) Ltd.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@ -383,6 +384,7 @@ meta_kms_add_source_in_impl (MetaKms *kms,
simple_impl_source->kms = kms;
g_source_set_callback (source, func, user_data, user_data_destroy);
g_source_set_ready_time (source, 0);
g_source_attach (source, g_main_context_get_thread_default ());
return source;

View File

@ -2146,6 +2146,7 @@ meta_renderer_native_create_dma_buf (CoglRenderer *cogl_renderer,
case META_RENDERER_NATIVE_MODE_GBM:
{
CoglFramebuffer *dmabuf_fb;
CoglDmaBufHandle *dmabuf_handle;
struct gbm_bo *new_bo;
int dmabuf_fd = -1;
@ -2182,8 +2183,11 @@ meta_renderer_native_create_dma_buf (CoglRenderer *cogl_renderer,
if (!dmabuf_fb)
return NULL;
return cogl_dma_buf_handle_new (dmabuf_fb, dmabuf_fd, new_bo,
(GDestroyNotify) gbm_bo_destroy);
dmabuf_handle =
cogl_dma_buf_handle_new (dmabuf_fb, dmabuf_fd, new_bo,
(GDestroyNotify) gbm_bo_destroy);
cogl_object_unref (dmabuf_fb);
return dmabuf_handle;
}
break;
#ifdef HAVE_EGL_DEVICE
@ -3037,6 +3041,7 @@ meta_renderer_native_create_view (MetaRenderer *renderer,
float scale;
int onscreen_width;
int onscreen_height;
MetaRectangle view_layout;
MetaRendererView *view;
GError *error = NULL;
@ -3108,8 +3113,11 @@ meta_renderer_native_create_view (MetaRenderer *renderer,
else
scale = 1.0;
meta_rectangle_from_graphene_rect (&crtc->config->layout,
META_ROUNDING_STRATEGY_ROUND,
&view_layout);
view = g_object_new (META_TYPE_RENDERER_VIEW,
"layout", &logical_monitor->rect,
"layout", &view_layout,
"scale", scale,
"framebuffer", onscreen,
"offscreen", offscreen,

View File

@ -424,6 +424,9 @@ new_absolute_motion_event (MetaSeatNative *seat,
meta_xkb_translate_state (event, seat->xkb, seat->button_state);
event->motion.x = x;
event->motion.y = y;
meta_input_device_native_translate_coordinates (input_device, stage,
&event->motion.x,
&event->motion.y);
event->motion.axes = axes;
clutter_event_set_device (event, seat->core_pointer);
clutter_event_set_source_device (event, input_device);
@ -1377,35 +1380,6 @@ has_touchscreen (MetaSeatNative *seat)
return FALSE;
}
static gboolean
has_external_keyboard (MetaSeatNative *seat)
{
GList *devices, *l;
gboolean has_external = FALSE;
devices = g_udev_client_query_by_subsystem (seat->udev_client, "input");
for (l = devices; l; l = l->next)
{
if (!g_udev_device_has_property (l->data, "ID_INPUT_KEYBOARD"))
continue;
/* May be "hid" or something else, we don't care. This property
* will not be present in virtual "AT Translated Set 2 keyboard"
* devices.
*/
if (!g_udev_device_has_property (l->data, "ID_TYPE"))
break;
has_external = TRUE;
break;
}
g_list_free_full (devices, g_object_unref);
return has_external;
}
static void
update_touch_mode (MetaSeatNative *seat)
{
@ -1418,10 +1392,10 @@ update_touch_mode (MetaSeatNative *seat)
else if (seat->has_tablet_switch && !seat->tablet_mode_switch_state)
touch_mode = FALSE;
/* If tablet mode is enabled, or if there is no tablet mode switch
* (eg. kiosk machines), check availability of external keyboards.
* (eg. kiosk machines), assume touch-mode.
*/
else
touch_mode = !seat->has_external_keyboard;
touch_mode = TRUE;
if (seat->touch_mode != touch_mode)
{
@ -1462,12 +1436,7 @@ evdev_add_device (MetaSeatNative *seat,
g_signal_emit_by_name (seat, "device-added", device);
if (type == CLUTTER_KEYBOARD_DEVICE)
{
seat->has_external_keyboard = has_external_keyboard (seat);
check_touch_mode = TRUE;
}
else if (type == CLUTTER_TOUCHSCREEN_DEVICE)
if (type == CLUTTER_TOUCHSCREEN_DEVICE)
{
seat->has_touchscreen = TRUE;
check_touch_mode = TRUE;
@ -1500,12 +1469,7 @@ evdev_remove_device (MetaSeatNative *seat,
device_type = clutter_input_device_get_device_type (device);
if (device_type == CLUTTER_KEYBOARD_DEVICE)
{
seat->has_external_keyboard = has_external_keyboard (seat);
update_touch_mode (seat);
}
else if (device_type == CLUTTER_TOUCHSCREEN_DEVICE)
if (device_type == CLUTTER_TOUCHSCREEN_DEVICE)
{
seat->has_touchscreen = has_touchscreen (seat);
update_touch_mode (seat);
@ -2550,7 +2514,6 @@ meta_seat_native_constructed (GObject *object)
xkb_keymap_led_get_index (xkb_keymap, XKB_LED_NAME_SCROLL);
}
seat->has_external_keyboard = has_external_keyboard (seat);
seat->has_touchscreen = has_touchscreen (seat);
update_touch_mode (seat);

View File

@ -120,7 +120,6 @@ struct _MetaSeatNative
GUdevClient *udev_client;
guint tablet_mode_switch_state : 1;
guint has_external_keyboard : 1;
guint has_touchscreen : 1;
guint has_tablet_switch : 1;
guint touch_mode : 1;

View File

@ -24,14 +24,75 @@
#include "backends/x11/cm/meta-renderer-x11-cm.h"
#include "backends/meta-renderer-view.h"
struct _MetaRendererX11Cm
{
MetaRendererX11 parent;
MetaRendererView *screen_view;
};
G_DEFINE_TYPE (MetaRendererX11Cm, meta_renderer_x11_cm,
META_TYPE_RENDERER_X11)
void
meta_renderer_x11_cm_ensure_screen_view (MetaRendererX11Cm *renderer_x11_cm,
int width,
int height)
{
cairo_rectangle_int_t view_layout;
if (renderer_x11_cm->screen_view)
return;
view_layout = (cairo_rectangle_int_t) {
.width = width,
.height = height,
};
renderer_x11_cm->screen_view = g_object_new (META_TYPE_RENDERER_VIEW,
"layout", &view_layout,
NULL);
meta_renderer_add_view (META_RENDERER (renderer_x11_cm),
renderer_x11_cm->screen_view);
}
void
meta_renderer_x11_cm_resize (MetaRendererX11Cm *renderer_x11_cm,
int width,
int height)
{
cairo_rectangle_int_t view_layout;
view_layout = (cairo_rectangle_int_t) {
.width = width,
.height = height,
};
g_object_set (G_OBJECT (renderer_x11_cm->screen_view),
"layout", &view_layout,
NULL);
}
void
meta_renderer_x11_cm_set_onscreen (MetaRendererX11Cm *renderer_x11_cm,
CoglOnscreen *onscreen)
{
g_object_set (G_OBJECT (renderer_x11_cm->screen_view),
"framebuffer", onscreen,
NULL);
}
static void
meta_renderer_x11_cm_rebuild_views (MetaRenderer *renderer)
{
MetaRendererX11Cm *renderer_x11_cm = META_RENDERER_X11_CM (renderer);
g_return_if_fail (!meta_renderer_get_views (renderer));
meta_renderer_add_view (renderer, renderer_x11_cm->screen_view);
}
static void
meta_renderer_x11_cm_init (MetaRendererX11Cm *renderer_x11_cm)
{
@ -40,4 +101,7 @@ meta_renderer_x11_cm_init (MetaRendererX11Cm *renderer_x11_cm)
static void
meta_renderer_x11_cm_class_init (MetaRendererX11CmClass *klass)
{
MetaRendererClass *renderer_class = META_RENDERER_CLASS (klass);
renderer_class->rebuild_views = meta_renderer_x11_cm_rebuild_views;
}

View File

@ -30,4 +30,15 @@ G_DECLARE_FINAL_TYPE (MetaRendererX11Cm, meta_renderer_x11_cm,
META, RENDERER_X11_CM,
MetaRendererX11)
void meta_renderer_x11_cm_ensure_screen_view (MetaRendererX11Cm *renderer_x11_cm,
int width,
int height);
void meta_renderer_x11_cm_resize (MetaRendererX11Cm *renderer_x11_cm,
int width,
int height);
void meta_renderer_x11_cm_set_onscreen (MetaRendererX11Cm *renderer_x11_cm,
CoglOnscreen *onscreen);
#endif /* META_RENDERER_X11_CM_H */

View File

@ -855,6 +855,7 @@ meta_backend_x11_class_init (MetaBackendX11Class *klass)
static void
meta_backend_x11_init (MetaBackendX11 *x11)
{
XInitThreads ();
}
Display *

View File

@ -38,7 +38,6 @@ struct _MetaInputDeviceX11
float current_y;
#ifdef HAVE_LIBWACOM
WacomDevice *wacom_device;
GArray *group_modes;
#endif
};
@ -93,13 +92,16 @@ meta_input_device_x11_is_grouped (ClutterInputDevice *device,
ClutterInputDevice *other_device)
{
#ifdef HAVE_LIBWACOM
MetaInputDeviceX11 *device_x11 = META_INPUT_DEVICE_X11 (device);
MetaInputDeviceX11 *other_device_x11 = META_INPUT_DEVICE_X11 (other_device);
WacomDevice *wacom_device, *other_wacom_device;
if (device_x11->wacom_device &&
other_device_x11->wacom_device &&
libwacom_compare (device_x11->wacom_device,
other_device_x11->wacom_device,
wacom_device =
meta_input_device_get_wacom_device (META_INPUT_DEVICE (device));
other_wacom_device =
meta_input_device_get_wacom_device (META_INPUT_DEVICE (other_device));
if (wacom_device && other_wacom_device &&
libwacom_compare (wacom_device,
other_wacom_device,
WCOMPARE_NORMAL) == 0)
return TRUE;
#endif
@ -122,9 +124,9 @@ meta_input_device_x11_is_grouped (ClutterInputDevice *device,
static void
meta_input_device_x11_finalize (GObject *object)
{
#ifdef HAVE_LIBWACOM
MetaInputDeviceX11 *device_xi2 = META_INPUT_DEVICE_X11 (object);
#ifdef HAVE_LIBWACOM
if (device_xi2->group_modes)
g_array_unref (device_xi2->group_modes);
#endif
@ -413,9 +415,12 @@ pad_switch_mode (ClutterInputDevice *device,
{
MetaInputDeviceX11 *device_x11 = META_INPUT_DEVICE_X11 (device);
uint32_t n_buttons, n_modes, button_group, next_mode, i;
WacomDevice *wacom_device;
GList *switch_buttons = NULL;
n_buttons = libwacom_get_num_buttons (device_x11->wacom_device);
wacom_device =
meta_input_device_get_wacom_device (META_INPUT_DEVICE (device));
n_buttons = libwacom_get_num_buttons (wacom_device);
for (i = 0; i < n_buttons; i++)
{

View File

@ -38,7 +38,10 @@ enum
PROP_OPCODE,
PROP_POINTER_ID,
PROP_KEYBOARD_ID,
N_PROPS
N_PROPS,
/* This property is overridden */
PROP_TOUCH_MODE,
};
struct _MetaSeatX11
@ -54,6 +57,8 @@ struct _MetaSeatX11
int pointer_id;
int keyboard_id;
int opcode;
guint has_touchscreens : 1;
guint touch_mode : 1;
};
static GParamSpec *props[N_PROPS] = { 0 };
@ -605,6 +610,20 @@ pad_passive_button_grab (ClutterInputDevice *device)
g_free (xi_event_mask.mask);
}
static void
update_touch_mode (MetaSeatX11 *seat_x11)
{
gboolean touch_mode;
touch_mode = seat_x11->has_touchscreens;
if (seat_x11->touch_mode == touch_mode)
return;
seat_x11->touch_mode = touch_mode;
g_object_notify (G_OBJECT (seat_x11), "touch-mode");
}
static ClutterInputDevice *
add_device (MetaSeatX11 *seat_x11,
ClutterBackend *backend,
@ -635,6 +654,8 @@ add_device (MetaSeatX11 *seat_x11,
info->attachment == seat_x11->keyboard_id))
{
seat_x11->devices = g_list_prepend (seat_x11->devices, device);
seat_x11->has_touchscreens |=
clutter_input_device_get_device_type (device) == CLUTTER_TOUCHSCREEN_DEVICE;
}
else
{
@ -663,18 +684,38 @@ add_device (MetaSeatX11 *seat_x11,
}
}
update_touch_mode (seat_x11);
return device;
}
static gboolean
has_touchscreens (MetaSeatX11 *seat_x11)
{
GList *l;
for (l = seat_x11->devices; l; l = l->next)
{
if (clutter_input_device_get_device_type (l->data) == CLUTTER_TOUCHSCREEN_DEVICE)
return TRUE;
}
return FALSE;
}
static void
remove_device (MetaSeatX11 *seat_x11,
int device_id)
{
ClutterInputDevice *device;
gboolean check_touchscreens = FALSE;
device = g_hash_table_lookup (seat_x11->devices_by_id,
GINT_TO_POINTER (device_id));
if (clutter_input_device_get_device_type (device) == CLUTTER_TOUCHSCREEN_DEVICE)
check_touchscreens = TRUE;
if (device != NULL)
{
if (seat_x11->core_pointer == device)
@ -695,6 +736,12 @@ remove_device (MetaSeatX11 *seat_x11,
g_hash_table_remove (seat_x11->devices_by_id,
GINT_TO_POINTER (device_id));
}
if (check_touchscreens)
{
seat_x11->has_touchscreens = has_touchscreens (seat_x11);
update_touch_mode (seat_x11);
}
}
static void
@ -1272,6 +1319,7 @@ meta_seat_x11_set_property (GObject *object,
case PROP_KEYBOARD_ID:
seat_x11->keyboard_id = g_value_get_int (value);
break;
case PROP_TOUCH_MODE:
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
@ -1296,6 +1344,9 @@ meta_seat_x11_get_property (GObject *object,
case PROP_KEYBOARD_ID:
g_value_set_int (value, seat_x11->keyboard_id);
break;
case PROP_TOUCH_MODE:
g_value_set_boolean (value, seat_x11->touch_mode);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
@ -1547,6 +1598,9 @@ meta_seat_x11_class_init (MetaSeatX11Class *klass)
G_PARAM_CONSTRUCT_ONLY);
g_object_class_install_properties (object_class, N_PROPS, props);
g_object_class_override_property (object_class, PROP_TOUCH_MODE,
"touch-mode");
}
static void

View File

@ -26,15 +26,17 @@
#include <unistd.h>
#endif
#include "backends/x11/cm/meta-backend-x11-cm.h"
#include "backends/x11/cm/meta-renderer-x11-cm.h"
#include "backends/x11/meta-backend-x11.h"
#include "backends/x11/meta-seat-x11.h"
#include "backends/x11/meta-stage-x11.h"
#include "clutter/clutter-mutter.h"
#include "clutter/x11/clutter-x11.h"
#include "clutter/x11/clutter-backend-x11.h"
#include "cogl/cogl.h"
#include "core/display-private.h"
#include "meta/meta-x11-errors.h"
#include "meta-backend-x11.h"
#include "meta-seat-x11.h"
#include "meta-stage-x11.h"
#define STAGE_X11_IS_MAPPED(s) ((((MetaStageX11 *) (s))->wm_state & STAGE_X11_WITHDRAWN) == 0)
@ -287,8 +289,6 @@ meta_stage_x11_unrealize (ClutterStageWindow *stage_window)
clutter_stage_window_parent_iface->unrealize (stage_window);
g_list_free (stage_x11->legacy_views);
g_clear_object (&stage_x11->legacy_view);
g_clear_pointer (&stage_x11->onscreen, cogl_object_unref);
}
@ -330,10 +330,13 @@ meta_stage_x11_realize (ClutterStageWindow *stage_window)
stage_cogl,
NULL);
if (stage_x11->legacy_view)
g_object_set (G_OBJECT (stage_x11->legacy_view),
"framebuffer", stage_x11->onscreen,
NULL);
if (META_IS_BACKEND_X11_CM (stage_x11->backend))
{
MetaRenderer *renderer = meta_backend_get_renderer (stage_x11->backend);
MetaRendererX11Cm *renderer_x11_cm = META_RENDERER_X11_CM (renderer);
meta_renderer_x11_cm_set_onscreen (renderer_x11_cm, stage_x11->onscreen);
}
/* We just created a window of the size of the actor. No need to fix
the size of the stage, just update it. */
@ -522,34 +525,13 @@ meta_stage_x11_can_clip_redraws (ClutterStageWindow *stage_window)
return stage_x11->clipped_redraws_cool_off == 0;
}
static void
ensure_legacy_view (ClutterStageWindow *stage_window)
{
MetaStageX11 *stage_x11 = META_STAGE_X11 (stage_window);
cairo_rectangle_int_t view_layout;
CoglFramebuffer *framebuffer;
if (stage_x11->legacy_view)
return;
_clutter_stage_window_get_geometry (stage_window, &view_layout);
framebuffer = COGL_FRAMEBUFFER (stage_x11->onscreen);
stage_x11->legacy_view = g_object_new (CLUTTER_TYPE_STAGE_VIEW_COGL,
"layout", &view_layout,
"framebuffer", framebuffer,
NULL);
stage_x11->legacy_views = g_list_append (stage_x11->legacy_views,
stage_x11->legacy_view);
}
static GList *
meta_stage_x11_get_views (ClutterStageWindow *stage_window)
{
MetaStageX11 *stage_x11 = META_STAGE_X11 (stage_window);
MetaRenderer *renderer = meta_backend_get_renderer (stage_x11->backend);
ensure_legacy_view (stage_window);
return stage_x11->legacy_views;
return meta_renderer_get_views (renderer);
}
static int64_t
@ -581,6 +563,9 @@ meta_stage_x11_class_init (MetaStageX11Class *klass)
static void
meta_stage_x11_init (MetaStageX11 *stage)
{
MetaRenderer *renderer;
MetaRendererX11Cm *renderer_x11_cm;
stage->xwin = None;
stage->xwin_width = 640;
stage->xwin_height = 480;
@ -591,6 +576,19 @@ meta_stage_x11_init (MetaStageX11 *stage)
stage->accept_focus = TRUE;
stage->title = NULL;
stage->backend = meta_get_backend ();
g_assert (stage->backend);
if (META_IS_BACKEND_X11_CM (stage->backend))
{
renderer = meta_backend_get_renderer (stage->backend);
renderer_x11_cm = META_RENDERER_X11_CM (renderer);
meta_renderer_x11_cm_ensure_screen_view (renderer_x11_cm,
stage->xwin_width,
stage->xwin_height);
}
}
static void
@ -778,16 +776,16 @@ meta_stage_x11_translate_event (MetaStageX11 *stage_x11,
* X11 compositing manager, we need to reset the legacy
* stage view, now that it has a new size.
*/
if (stage_x11->legacy_view)
if (META_IS_BACKEND_X11_CM (stage_x11->backend))
{
cairo_rectangle_int_t view_layout = {
.width = stage_width,
.height = stage_height
};
MetaBackend *backend = stage_x11->backend;
MetaRenderer *renderer = meta_backend_get_renderer (backend);
MetaRendererX11Cm *renderer_x11_cm =
META_RENDERER_X11_CM (renderer);
g_object_set (G_OBJECT (stage_x11->legacy_view),
"layout", &view_layout,
NULL);
meta_renderer_x11_cm_resize (renderer_x11_cm,
stage_width,
stage_height);
}
}
}
@ -845,12 +843,16 @@ meta_stage_x11_translate_event (MetaStageX11 *stage_x11,
g_debug ("Client message for stage, win:0x%x",
(unsigned int) xevent->xany.window);
if (handle_wm_protocols_event (backend_x11, stage_x11, xevent))
if (xevent->xclient.message_type == backend_x11->atom_WM_PROTOCOLS)
{
event->any.type = CLUTTER_DELETE;
event->any.stage = stage;
res = TRUE;
if (handle_wm_protocols_event (backend_x11, stage_x11, xevent))
{
event->any.type = CLUTTER_DELETE;
event->any.stage = stage;
res = TRUE;
}
}
break;
default:

View File

@ -25,6 +25,7 @@
#include <X11/Xlib.h>
#include <X11/Xatom.h>
#include "backends/meta-backend-private.h"
#include "clutter/clutter-mutter.h"
#include "clutter/x11/clutter-x11.h"
@ -51,14 +52,13 @@ struct _MetaStageX11
{
ClutterStageCogl parent_instance;
MetaBackend *backend;
CoglOnscreen *onscreen;
Window xwin;
gint xwin_width;
gint xwin_height; /* FIXME target_width / height */
ClutterStageView *legacy_view;
GList *legacy_views;
CoglFrameClosure *frame_closure;
gchar *title;

View File

@ -167,7 +167,8 @@ meta_renderer_x11_nested_ensure_legacy_view (MetaRendererX11Nested *renderer_x11
"framebuffer", COGL_FRAMEBUFFER (fake_onscreen),
NULL);
meta_renderer_set_legacy_view (renderer, legacy_view);
g_assert (!meta_renderer_get_views (renderer));
meta_renderer_add_view (renderer, legacy_view);
}
static MetaRendererView *

View File

@ -63,7 +63,6 @@
#include "clutter/clutter-mutter.h"
#include "cogl/cogl.h"
#include "compositor/meta-window-actor-x11.h"
#include "compositor/meta-window-actor-wayland.h"
#include "compositor/meta-window-actor-private.h"
#include "compositor/meta-window-group-private.h"
#include "core/display-private.h"
@ -82,6 +81,7 @@
#include "x11/meta-x11-display-private.h"
#ifdef HAVE_WAYLAND
#include "compositor/meta-window-actor-wayland.h"
#include "wayland/meta-wayland-private.h"
#endif

View File

@ -354,7 +354,7 @@ setup_pipeline (MetaBackgroundActor *self,
guint8 opacity;
float color_component;
CoglFramebuffer *fb;
CoglPipelineFilter filter;
CoglPipelineFilter min_filter, mag_filter;
opacity = clutter_actor_get_paint_opacity (CLUTTER_ACTOR (self));
if (opacity < 255)
@ -455,11 +455,17 @@ setup_pipeline (MetaBackgroundActor *self,
actor_pixel_rect->width,
actor_pixel_rect->height,
NULL, NULL))
filter = COGL_PIPELINE_FILTER_NEAREST;
{
min_filter = COGL_PIPELINE_FILTER_NEAREST;
mag_filter = COGL_PIPELINE_FILTER_NEAREST;
}
else
filter = COGL_PIPELINE_FILTER_LINEAR;
{
min_filter = COGL_PIPELINE_FILTER_LINEAR_MIPMAP_NEAREST;
mag_filter = COGL_PIPELINE_FILTER_LINEAR;
}
cogl_pipeline_set_layer_filters (self->pipeline, 0, filter, filter);
cogl_pipeline_set_layer_filters (self->pipeline, 0, min_filter, mag_filter);
}
static void

View File

@ -66,4 +66,7 @@ gboolean meta_shaped_texture_update_area (MetaShapedTexture *stex,
int meta_shaped_texture_get_width (MetaShapedTexture *stex);
int meta_shaped_texture_get_height (MetaShapedTexture *stex);
void meta_shaped_texture_set_clip_region (MetaShapedTexture *stex,
cairo_region_t *clip_region);
#endif

View File

@ -87,6 +87,9 @@ struct _MetaShapedTexture
/* The region containing only fully opaque pixels */
cairo_region_t *opaque_region;
/* MetaCullable regions, see that documentation for more details */
cairo_region_t *clip_region;
gboolean size_invalid;
MetaMonitorTransform transform;
gboolean has_viewport_src_rect;
@ -214,6 +217,15 @@ ensure_size_valid (MetaShapedTexture *stex)
update_size (stex);
}
void
meta_shaped_texture_set_clip_region (MetaShapedTexture *stex,
cairo_region_t *clip_region)
{
g_clear_pointer (&stex->clip_region, cairo_region_destroy);
if (clip_region)
stex->clip_region = cairo_region_reference (clip_region);
}
static void
meta_shaped_texture_reset_pipelines (MetaShapedTexture *stex)
{
@ -239,6 +251,7 @@ meta_shaped_texture_dispose (GObject *object)
meta_shaped_texture_reset_pipelines (stex);
g_clear_pointer (&stex->opaque_region, cairo_region_destroy);
g_clear_pointer (&stex->clip_region, cairo_region_destroy);
g_clear_pointer (&stex->snippet, cogl_object_unref);
@ -390,17 +403,14 @@ get_unblended_pipeline (MetaShapedTexture *stex,
CoglContext *ctx)
{
CoglPipeline *pipeline;
CoglColor color;
if (stex->unblended_pipeline)
return stex->unblended_pipeline;
pipeline = cogl_pipeline_copy (get_base_pipeline (stex, ctx));
cogl_color_init_from_4ub (&color, 255, 255, 255, 255);
cogl_pipeline_set_blend (pipeline,
"RGBA = ADD (SRC_COLOR, 0)",
NULL);
cogl_pipeline_set_color (pipeline, &color);
cogl_pipeline_set_layer_combine (pipeline, 0,
"RGBA = REPLACE (TEXTURE)",
NULL);
stex->unblended_pipeline = pipeline;
@ -585,12 +595,19 @@ do_paint_content (MetaShapedTexture *stex,
if (use_opaque_region)
{
blended_tex_region = cairo_region_create_rectangle (&content_rect);
if (stex->clip_region)
blended_tex_region = cairo_region_copy (stex->clip_region);
else
blended_tex_region = cairo_region_create_rectangle (&content_rect);
cairo_region_subtract (blended_tex_region, stex->opaque_region);
}
else
{
blended_tex_region = NULL;
if (stex->clip_region)
blended_tex_region = cairo_region_reference (stex->clip_region);
else
blended_tex_region = NULL;
}
/* Limit to how many separate rectangles we'll draw; beyond this just
@ -612,10 +629,21 @@ do_paint_content (MetaShapedTexture *stex,
/* First, paint the unblended parts, which are part of the opaque region. */
if (use_opaque_region)
{
cairo_region_t *region;
int n_rects;
int i;
if (!cairo_region_is_empty (stex->opaque_region))
if (stex->clip_region)
{
region = cairo_region_copy (stex->clip_region);
cairo_region_intersect (region, stex->opaque_region);
}
else
{
region = cairo_region_reference (stex->opaque_region);
}
if (!cairo_region_is_empty (region))
{
CoglPipeline *opaque_pipeline;
@ -623,16 +651,18 @@ do_paint_content (MetaShapedTexture *stex,
cogl_pipeline_set_layer_texture (opaque_pipeline, 0, paint_tex);
cogl_pipeline_set_layer_filters (opaque_pipeline, 0, filter, filter);
n_rects = cairo_region_num_rectangles (stex->opaque_region);
n_rects = cairo_region_num_rectangles (region);
for (i = 0; i < n_rects; i++)
{
cairo_rectangle_int_t rect;
cairo_region_get_rectangle (stex->opaque_region, i, &rect);
cairo_region_get_rectangle (region, i, &rect);
paint_clipped_rectangle_node (stex, root_node,
opaque_pipeline,
&rect, alloc);
}
}
cairo_region_destroy (region);
}
/* Now, go ahead and paint the blended parts. */
@ -757,6 +787,9 @@ meta_shaped_texture_paint_content (ClutterContent *content,
CoglTexture *paint_tex = NULL;
uint8_t opacity;
if (stex->clip_region && cairo_region_is_empty (stex->clip_region))
return;
/* The GL EXT_texture_from_pixmap extension does allow for it to be
* used together with SGIS_generate_mipmap, however this is very
* rarely supported. Also, even when it is supported there

View File

@ -34,7 +34,6 @@ typedef struct _MetaSurfaceActorPrivate
cairo_region_t *input_region;
/* MetaCullable regions, see that documentation for more details */
cairo_region_t *clip_region;
cairo_region_t *unobscured_region;
/* Freeze/thaw accounting */
@ -58,6 +57,12 @@ enum
static guint signals[LAST_SIGNAL];
typedef enum
{
IN_STAGE_PERSPECTIVE,
IN_ACTOR_PERSPECTIVE
} ScalePerspectiveType;
static cairo_region_t *
effective_unobscured_region (MetaSurfaceActor *surface_actor)
{
@ -79,18 +84,39 @@ effective_unobscured_region (MetaSurfaceActor *surface_actor)
}
static cairo_region_t*
get_scaled_region (MetaSurfaceActor *surface_actor,
cairo_region_t *region)
get_scaled_region (MetaSurfaceActor *surface_actor,
cairo_region_t *region,
ScalePerspectiveType scale_perspective)
{
MetaWindowActor *window_actor;
cairo_region_t *scaled_region;
int geometry_scale;
float x, y;
window_actor = meta_window_actor_from_actor (CLUTTER_ACTOR (surface_actor));
geometry_scale = meta_window_actor_get_geometry_scale (window_actor);
return meta_region_scale_double (region,
1.0 / geometry_scale,
META_ROUNDING_STRATEGY_GROW);
clutter_actor_get_position (CLUTTER_ACTOR (surface_actor), &x, &y);
cairo_region_translate (region, x, y);
switch (scale_perspective)
{
case IN_STAGE_PERSPECTIVE:
scaled_region = meta_region_scale_double (region,
geometry_scale,
META_ROUNDING_STRATEGY_GROW);
break;
case IN_ACTOR_PERSPECTIVE:
scaled_region = meta_region_scale_double (region,
1.0 / geometry_scale,
META_ROUNDING_STRATEGY_GROW);
break;
}
cairo_region_translate (region, -x, -y);
cairo_region_translate (scaled_region, -x, -y);
return scaled_region;
}
static void
@ -120,8 +146,9 @@ set_unobscured_region (MetaSurfaceActor *surface_actor,
.height = height,
};
priv->unobscured_region =
get_scaled_region (surface_actor, unobscured_region);
priv->unobscured_region = get_scaled_region (surface_actor,
unobscured_region,
IN_ACTOR_PERSPECTIVE);
cairo_region_intersect_rectangle (priv->unobscured_region, &bounds);
}
@ -134,30 +161,23 @@ set_clip_region (MetaSurfaceActor *surface_actor,
{
MetaSurfaceActorPrivate *priv =
meta_surface_actor_get_instance_private (surface_actor);
MetaShapedTexture *stex = priv->texture;
g_clear_pointer (&priv->clip_region, cairo_region_destroy);
if (clip_region)
if (clip_region && !cairo_region_is_empty (clip_region))
{
if (cairo_region_is_empty (clip_region))
priv->clip_region = cairo_region_reference (clip_region);
else
priv->clip_region = get_scaled_region (surface_actor, clip_region);
cairo_region_t *region;
region = get_scaled_region (surface_actor,
clip_region,
IN_ACTOR_PERSPECTIVE);
meta_shaped_texture_set_clip_region (stex, region);
cairo_region_destroy (region);
}
else
{
meta_shaped_texture_set_clip_region (stex, clip_region);
}
}
static void
meta_surface_actor_paint (ClutterActor *actor,
ClutterPaintContext *paint_context)
{
MetaSurfaceActor *surface_actor = META_SURFACE_ACTOR (actor);
MetaSurfaceActorPrivate *priv =
meta_surface_actor_get_instance_private (surface_actor);
if (priv->clip_region && cairo_region_is_empty (priv->clip_region))
return;
CLUTTER_ACTOR_CLASS (meta_surface_actor_parent_class)->paint (actor,
paint_context);
}
static void
@ -227,7 +247,6 @@ meta_surface_actor_dispose (GObject *object)
g_clear_object (&priv->texture);
set_unobscured_region (self, NULL);
set_clip_region (self, NULL);
G_OBJECT_CLASS (meta_surface_actor_parent_class)->dispose (object);
}
@ -239,7 +258,6 @@ meta_surface_actor_class_init (MetaSurfaceActorClass *klass)
ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
object_class->dispose = meta_surface_actor_dispose;
actor_class->paint = meta_surface_actor_paint;
actor_class->pick = meta_surface_actor_pick;
actor_class->get_paint_volume = meta_surface_actor_get_paint_volume;
@ -279,11 +297,8 @@ meta_surface_actor_cull_out (MetaCullable *cullable,
if (opacity == 0xff)
{
MetaWindowActor *window_actor;
cairo_region_t *scaled_opaque_region;
cairo_region_t *opaque_region;
int geometry_scale;
float x, y;
cairo_region_t *scaled_opaque_region;
opaque_region = meta_shaped_texture_get_opaque_region (priv->texture);
if (opaque_region)
@ -306,14 +321,9 @@ meta_surface_actor_cull_out (MetaCullable *cullable,
return;
}
window_actor = meta_window_actor_from_actor (CLUTTER_ACTOR (surface_actor));
geometry_scale = meta_window_actor_get_geometry_scale (window_actor);
clutter_actor_get_position (CLUTTER_ACTOR (surface_actor), &x, &y);
cairo_region_translate (opaque_region, x, y);
scaled_opaque_region = meta_region_scale (opaque_region, geometry_scale);
cairo_region_translate (scaled_opaque_region, -x, -y);
cairo_region_translate (opaque_region, -x, -y);
scaled_opaque_region = get_scaled_region (surface_actor,
opaque_region,
IN_STAGE_PERSPECTIVE);
if (unobscured_region)
cairo_region_subtract (unobscured_region, scaled_opaque_region);

View File

@ -139,29 +139,6 @@ meta_window_actor_wayland_set_frozen (MetaWindowActor *actor,
{
}
static gboolean
meta_window_actor_wayland_get_paint_volume (ClutterActor *actor,
ClutterPaintVolume *volume)
{
MetaSurfaceActor *surface;
surface = meta_window_actor_get_surface (META_WINDOW_ACTOR (actor));
if (surface)
{
ClutterActor *surface_actor = CLUTTER_ACTOR (surface);
const ClutterPaintVolume *child_volume;
child_volume = clutter_actor_get_transformed_paint_volume (surface_actor,
actor);
if (!child_volume)
return FALSE;
clutter_paint_volume_union (volume, child_volume);
}
return TRUE;
}
static void
meta_window_actor_wayland_update_regions (MetaWindowActor *actor)
{
@ -171,9 +148,6 @@ static void
meta_window_actor_wayland_class_init (MetaWindowActorWaylandClass *klass)
{
MetaWindowActorClass *window_actor_class = META_WINDOW_ACTOR_CLASS (klass);
ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
actor_class->get_paint_volume = meta_window_actor_wayland_get_paint_volume;
window_actor_class->assign_surface_actor = meta_window_actor_wayland_assign_surface_actor;
window_actor_class->frame_complete = meta_window_actor_wayland_frame_complete;

View File

@ -85,6 +85,8 @@ struct _MetaWindowActorX11
cairo_region_t *shape_region;
/* The region we should clip to when painting the shadow */
cairo_region_t *shadow_clip;
/* The frame region */
cairo_region_t *frame_bounds;
/* Extracted size-invariant shape used for shadows */
MetaWindowShape *shadow_shape;
@ -702,11 +704,8 @@ set_clip_region_beneath (MetaWindowActorX11 *actor_x11,
if (clip_shadow_under_window (actor_x11))
{
cairo_region_t *frame_bounds;
frame_bounds = meta_window_get_frame_bounds (window);
if (frame_bounds)
cairo_region_subtract (actor_x11->shadow_clip, frame_bounds);
if (actor_x11->frame_bounds)
cairo_region_subtract (actor_x11->shadow_clip, actor_x11->frame_bounds);
}
}
else
@ -1126,6 +1125,17 @@ update_opaque_region (MetaWindowActorX11 *actor_x11)
cairo_region_destroy (opaque_region);
}
static void
update_frame_bounds (MetaWindowActorX11 *actor_x11)
{
MetaWindow *window =
meta_window_actor_get_meta_window (META_WINDOW_ACTOR (actor_x11));
g_clear_pointer (&actor_x11->frame_bounds, cairo_region_destroy);
actor_x11->frame_bounds =
cairo_region_copy (meta_window_get_frame_bounds (window));
}
static void
update_regions (MetaWindowActorX11 *actor_x11)
{
@ -1197,6 +1207,7 @@ handle_updates (MetaWindowActorX11 *actor_x11)
if (!meta_surface_actor_is_visible (surface))
return;
update_frame_bounds (actor_x11);
check_needs_reshape (actor_x11);
check_needs_shadow (actor_x11);
}
@ -1250,15 +1261,13 @@ meta_window_actor_x11_paint (ClutterActor *actor,
*/
if (!clip && clip_shadow_under_window (actor_x11))
{
cairo_region_t *frame_bounds;
cairo_rectangle_int_t bounds;
get_shadow_bounds (actor_x11, appears_focused, &bounds);
clip = cairo_region_create_rectangle (&bounds);
frame_bounds = meta_window_get_frame_bounds (window);
if (frame_bounds)
cairo_region_subtract (clip, frame_bounds);
if (actor_x11->frame_bounds)
cairo_region_subtract (clip, actor_x11->frame_bounds);
}
framebuffer = clutter_paint_context_get_framebuffer (paint_context);
@ -1545,6 +1554,7 @@ meta_window_actor_x11_dispose (GObject *object)
g_clear_pointer (&actor_x11->shape_region, cairo_region_destroy);
g_clear_pointer (&actor_x11->shadow_clip, cairo_region_destroy);
g_clear_pointer (&actor_x11->frame_bounds, cairo_region_destroy);
g_clear_pointer (&actor_x11->shadow_class, g_free);
g_clear_pointer (&actor_x11->focused_shadow, meta_shadow_unref);
@ -1620,8 +1630,8 @@ meta_window_actor_x11_init (MetaWindowActorX11 *self)
self->shadow_factory = meta_shadow_factory_get_default ();
self->shadow_factory_changed_handler_id =
g_signal_connect (self->shadow_factory,
"changed",
G_CALLBACK (invalidate_shadow),
self);
g_signal_connect_swapped (self->shadow_factory,
"changed",
G_CALLBACK (invalidate_shadow),
self);
}

View File

@ -1300,6 +1300,7 @@ meta_window_actor_blit_to_framebuffer (MetaScreenCastWindow *screen_cast_window,
cogl_color_init_from_4ub (&clear_color, 0, 0, 0, 0);
cogl_framebuffer_clear (framebuffer, COGL_BUFFER_BIT_COLOR, &clear_color);
cogl_framebuffer_orthographic (framebuffer, 0, 0, width, height, 0, 1.0);
cogl_framebuffer_set_viewport (framebuffer, 0, 0, width, height);
meta_rectangle_scale_double (bounds, resource_scale,
META_ROUNDING_STRATEGY_GROW,

View File

@ -2129,7 +2129,7 @@ process_special_modifier_key (MetaDisplay *display,
return TRUE;
}
else if (event->type == CLUTTER_KEY_PRESS &&
(event->modifier_state & ~(IGNORED_MODIFIERS)) == 0 &&
((event->modifier_state & ~(IGNORED_MODIFIERS)) & CLUTTER_MODIFIER_MASK) == 0 &&
resolved_key_combo_has_keycode (resolved_key_combo,
event->hardware_keycode))
{

View File

@ -152,6 +152,7 @@ owner_changed_cb (MetaSelection *selection,
display->saved_clipboard);
g_set_object (&display->selection_source, new_owner);
meta_selection_set_owner (selection, selection_type, new_owner);
g_object_unref (new_owner);
}
}
@ -170,6 +171,7 @@ meta_clipboard_manager_shutdown (MetaDisplay *display)
{
MetaSelection *selection;
g_clear_object (&display->selection_source);
g_clear_pointer (&display->saved_clipboard, g_bytes_unref);
g_clear_pointer (&display->saved_clipboard_mimetype, g_free);
selection = meta_display_get_selection (display);

View File

@ -1,7 +1,5 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/*
* Copyright (C) 2015 Red Hat
* Copyright (C) 2020 Red Hat
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@ -19,16 +17,16 @@
* 02111-1307, USA.
*
* Written by:
* Jonas Ådahl <jadahl@gmail.com>
* Carlos Garnacho <carlosg@gnome.org>
*/
#ifndef META_WAYLAND_DATA_DEVICE_PRIVATE_H
#define META_WAYLAND_DATA_DEVICE_PRIVATE_H
#ifndef META_SELECTION_PRIVATE_H
#define META_SELECTION_PRIVATE_H
#define META_TYPE_WAYLAND_DATA_SOURCE_PRIMARY (meta_wayland_data_source_primary_get_type ())
G_DECLARE_FINAL_TYPE (MetaWaylandDataSourcePrimary,
meta_wayland_data_source_primary,
META, WAYLAND_DATA_SOURCE_PRIMARY,
MetaWaylandDataSource);
#include "meta/meta-selection.h"
#endif /* META_WAYLAND_DATA_DEVICE_PRIVATE_H */
MetaSelectionSource *
meta_selection_get_current_owner (MetaSelection *selection,
MetaSelectionType selection_type);
#endif /* META_SELECTION_PRIVATE_H */

View File

@ -21,6 +21,7 @@
#include "config.h"
#include "core/meta-selection-private.h"
#include "meta/meta-selection.h"
typedef struct TransferRequest TransferRequest;
@ -50,6 +51,9 @@ static guint signals[N_SIGNALS] = { 0 };
G_DEFINE_TYPE (MetaSelection, meta_selection, G_TYPE_OBJECT)
static void read_selection_source_async (GTask *task,
TransferRequest *request);
static void
meta_selection_dispose (GObject *object)
{
@ -216,6 +220,7 @@ write_cb (GOutputStream *stream,
GAsyncResult *result,
GTask *task)
{
TransferRequest *request;
GError *error = NULL;
g_output_stream_write_bytes_finish (stream, result, &error);
@ -226,8 +231,17 @@ write_cb (GOutputStream *stream,
return;
}
g_task_return_boolean (task, TRUE);
g_object_unref (task);
request = g_task_get_task_data (task);
if (request->len > 0)
{
read_selection_source_async (task, request);
}
else
{
g_task_return_boolean (task, TRUE);
g_object_unref (task);
}
}
static void
@ -246,8 +260,26 @@ read_cb (GInputStream *stream,
g_object_unref (task);
return;
}
else if (g_bytes_get_size (bytes) == 0)
{
g_task_return_boolean (task, TRUE);
g_object_unref (task);
return;
}
request = g_task_get_task_data (task);
if (request->len < g_bytes_get_size (bytes))
{
GBytes *copy;
/* Trim content */
copy = g_bytes_new_from_bytes (bytes, 0, request->len);
g_bytes_unref (bytes);
bytes = copy;
}
request->len -= g_bytes_get_size (bytes);
g_output_stream_write_bytes_async (request->ostream,
bytes,
G_PRIORITY_DEFAULT,
@ -257,6 +289,18 @@ read_cb (GInputStream *stream,
g_bytes_unref (bytes);
}
static void
read_selection_source_async (GTask *task,
TransferRequest *request)
{
g_input_stream_read_bytes_async (request->istream,
(gsize) request->len,
G_PRIORITY_DEFAULT,
g_task_get_cancellable (task),
(GAsyncReadyCallback) read_cb,
task);
}
static void
source_read_cb (MetaSelectionSource *source,
GAsyncResult *result,
@ -290,12 +334,7 @@ source_read_cb (MetaSelectionSource *source,
}
else
{
g_input_stream_read_bytes_async (request->istream,
(gsize) request->len,
G_PRIORITY_DEFAULT,
g_task_get_cancellable (task),
(GAsyncReadyCallback) read_cb,
task);
read_selection_source_async (task, request);
}
}
@ -364,3 +403,13 @@ meta_selection_transfer_finish (MetaSelection *selection,
return g_task_propagate_boolean (G_TASK (result), error);
}
MetaSelectionSource *
meta_selection_get_current_owner (MetaSelection *selection,
MetaSelectionType selection_type)
{
g_return_val_if_fail (META_IS_SELECTION (selection), NULL);
g_return_val_if_fail (selection_type < META_N_SELECTION_TYPES, NULL);
return selection->owners[selection_type];
}

View File

@ -3751,6 +3751,8 @@ meta_window_activate_full (MetaWindow *window,
meta_window_focus (window, timestamp);
else
meta_workspace_activate_with_focus (window->workspace, window, timestamp);
meta_window_check_alive (window, timestamp);
}
/* This function exists since most of the functionality in window_activate
@ -4790,8 +4792,6 @@ meta_window_focus (MetaWindow *window,
return;
}
meta_window_check_alive (window, timestamp);
META_WINDOW_GET_CLASS (window)->focus (window, timestamp);
if (window->display->event_route == META_EVENT_ROUTE_NORMAL)
@ -8349,6 +8349,7 @@ meta_window_handle_ungrabbed_event (MetaWindow *window,
"Focusing %s due to button %u press (display.c)\n",
window->desc, button);
meta_window_focus (window, event->any.time);
meta_window_check_alive (window, event->any.time);
}
else
/* However, do allow terminals to lose focus due to new

View File

@ -495,7 +495,22 @@ if have_wayland
'wayland/meta-wayland-cursor-surface.h',
'wayland/meta-wayland-data-device.c',
'wayland/meta-wayland-data-device.h',
'wayland/meta-wayland-data-device-private.h',
'wayland/meta-wayland-data-device-primary.c',
'wayland/meta-wayland-data-device-primary.h',
'wayland/meta-wayland-data-device-primary-legacy.c',
'wayland/meta-wayland-data-device-primary-legacy.h',
'wayland/meta-wayland-data-offer.c',
'wayland/meta-wayland-data-offer.h',
'wayland/meta-wayland-data-offer-primary.c',
'wayland/meta-wayland-data-offer-primary.h',
'wayland/meta-wayland-data-offer-primary-legacy.c',
'wayland/meta-wayland-data-offer-primary-legacy.h',
'wayland/meta-wayland-data-source.c',
'wayland/meta-wayland-data-source.h',
'wayland/meta-wayland-data-source-primary.c',
'wayland/meta-wayland-data-source-primary.h',
'wayland/meta-wayland-data-source-primary-legacy.c',
'wayland/meta-wayland-data-source-primary-legacy.h',
'wayland/meta-wayland-dma-buf.c',
'wayland/meta-wayland-dma-buf.h',
'wayland/meta-wayland-dnd-surface.c',
@ -790,6 +805,7 @@ if have_wayland
['linux-dmabuf', 'unstable', 'v1', ],
['pointer-constraints', 'unstable', 'v1', ],
['pointer-gestures', 'unstable', 'v1', ],
['primary-selection', 'unstable', 'v1', ],
['relative-pointer', 'unstable', 'v1', ],
['tablet', 'unstable', 'v2', ],
['text-input', 'unstable', 'v3', ],

View File

@ -67,6 +67,9 @@ on_timeout (gpointer data)
}
else if (test_num == 2)
{
ClutterActorBox over_actor_box =
CLUTTER_ACTOR_BOX_INIT (0, 0, STAGE_WIDTH, STAGE_HEIGHT);
/* Make the actor visible but set a clip so that only some
of the actors are accessible */
clutter_actor_show (over_actor);
@ -76,6 +79,11 @@ on_timeout (gpointer data)
state->actor_width * (ACTORS_X - 4),
state->actor_height * (ACTORS_Y - 4));
/* Only allocated actors can be picked, so force an allocation
* of the overlay actor here.
*/
clutter_actor_allocate (over_actor, &over_actor_box, 0);
if (g_test_verbose ())
g_print ("Clipped covering actor:\n");
}
@ -175,10 +183,10 @@ actor_pick (void)
for (y = 0; y < ACTORS_Y; y++)
for (x = 0; x < ACTORS_X; x++)
{
ClutterColor color = { x * 255 / (ACTORS_X - 1),
y * 255 / (ACTORS_Y - 1),
128, 255 };
ClutterActor *rect = clutter_rectangle_new_with_color (&color);
ClutterColor color = { x * 255 / (ACTORS_X - 1),
y * 255 / (ACTORS_Y - 1),
128, 255 };
ClutterActor *rect = clutter_rectangle_new_with_color (&color);
clutter_actor_set_position (rect,
x * state.actor_width,
@ -187,9 +195,9 @@ actor_pick (void)
state.actor_width,
state.actor_height);
clutter_actor_add_child (state.stage, rect);
clutter_actor_add_child (state.stage, rect);
state.actors[y * ACTORS_X + x] = rect;
state.actors[y * ACTORS_X + x] = rect;
}
clutter_actor_show (state.stage);

View File

@ -112,7 +112,7 @@ test_cogl_multitexture_main (int argc, char *argv[])
GError *error = NULL;
ClutterActor *stage;
ClutterColor stage_color = { 0x61, 0x56, 0x56, 0xff };
TestMultiLayerMaterialState *state = g_new0 (TestMultiLayerMaterialState, 1);
g_autofree TestMultiLayerMaterialState *state = g_new0 (TestMultiLayerMaterialState, 1);
gfloat stage_w, stage_h;
gchar **files;
gfloat tex_coords[] =

View File

@ -0,0 +1,23 @@
<monitors version="2">
<configuration>
<logicalmonitor>
<x>0</x>
<y>0</y>
<primary>yes</primary>
<scale>2</scale>
<monitor>
<monitorspec>
<connector>eDP-1</connector>
<vendor>MetaProduct's Inc.</vendor>
<product>MetaMonitor</product>
<serial>0x123456</serial>
</monitorspec>
<mode>
<width>1920</width>
<height>1080</height>
<rate>60.000495910644531</rate>
</mode>
</monitor>
</logicalmonitor>
</configuration>
</monitors>

View File

@ -2868,6 +2868,116 @@ meta_test_monitor_lid_closed_with_hotplugged_external (void)
check_monitor_configuration (&test_case);
}
static void
meta_test_monitor_lid_scaled_closed_opened (void)
{
MonitorTestCase test_case = {
.setup = {
.modes = {
{
.width = 1920,
.height = 1080,
.refresh_rate = 60.000495910644531
}
},
.n_modes = 1,
.outputs = {
{
.crtc = 0,
.modes = { 0 },
.n_modes = 1,
.preferred_mode = 0,
.possible_crtcs = { 0 },
.n_possible_crtcs = 1,
.width_mm = 222,
.height_mm = 125,
.is_laptop_panel = TRUE
},
},
.n_outputs = 1,
.crtcs = {
{
.current_mode = 0
},
},
.n_crtcs = 1
},
.expect = {
.monitors = {
{
.outputs = { 0 },
.n_outputs = 1,
.modes = {
{
.width = 1920,
.height = 1080,
.refresh_rate = 60.000495910644531,
.crtc_modes = {
{
.output = 0,
.crtc_mode = 0
}
}
}
},
.n_modes = 1,
.current_mode = 0,
.width_mm = 222,
.height_mm = 125,
}
},
.n_monitors = 1,
.logical_monitors = {
{
.monitors = { 0 },
.n_monitors = 1,
.layout = { .x = 0, .y = 0, .width = 960, .height = 540 },
.scale = 2
}
},
.n_logical_monitors = 1,
.primary_logical_monitor = 0,
.n_outputs = 1,
.crtcs = {
{
.current_mode = 0,
}
},
.n_crtcs = 1,
.n_tiled_monitors = 0,
.screen_width = 960,
.screen_height = 540
}
};
MetaMonitorTestSetup *test_setup;
MetaBackend *backend = meta_get_backend ();
MetaMonitorManager *monitor_manager =
meta_backend_get_monitor_manager (backend);
if (!meta_is_stage_views_enabled ())
{
g_test_skip ("Not using stage views");
return;
}
test_setup = create_monitor_test_setup (&test_case,
MONITOR_TEST_FLAG_NONE);
set_custom_monitor_config ("lid-scale.xml");
emulate_hotplug (test_setup);
check_monitor_configuration (&test_case);
meta_backend_test_set_is_lid_closed (META_BACKEND_TEST (backend), TRUE);
meta_monitor_manager_lid_is_closed_changed (monitor_manager);
check_monitor_configuration (&test_case);
meta_backend_test_set_is_lid_closed (META_BACKEND_TEST (backend), FALSE);
meta_monitor_manager_lid_is_closed_changed (monitor_manager);
check_monitor_configuration (&test_case);
}
static void
meta_test_monitor_no_outputs (void)
{
@ -4828,12 +4938,13 @@ meta_test_monitor_custom_second_rotated_tiled_config (void)
.current_mode = 1,
.transform = META_MONITOR_TRANSFORM_90,
.x = 1024,
.y = 400,
.y = 0,
},
{
.current_mode = 1,
.transform = META_MONITOR_TRANSFORM_90,
.x = 1024,
.y = 400,
}
},
.n_crtcs = 3,
@ -4859,6 +4970,198 @@ meta_test_monitor_custom_second_rotated_tiled_config (void)
check_monitor_configuration (&test_case);
}
static void
meta_test_monitor_custom_second_rotated_nonnative_tiled_config (void)
{
MonitorTestCase test_case = {
.setup = {
.modes = {
{
.width = 1024,
.height = 768,
.refresh_rate = 60.000495910644531
},
{
.width = 400,
.height = 600,
.refresh_rate = 60.000495910644531
}
},
.n_modes = 2,
.outputs = {
{
.crtc = 0,
.modes = { 0 },
.n_modes = 1,
.preferred_mode = 0,
.possible_crtcs = { 0 },
.n_possible_crtcs = 1,
.width_mm = 222,
.height_mm = 125,
},
{
.crtc = -1,
.modes = { 1 },
.n_modes = 1,
.preferred_mode = 1,
.possible_crtcs = { 1, 2 },
.n_possible_crtcs = 2,
.width_mm = 222,
.height_mm = 125,
.tile_info = {
.group_id = 1,
.max_h_tiles = 2,
.max_v_tiles = 1,
.loc_h_tile = 0,
.loc_v_tile = 0,
.tile_w = 400,
.tile_h = 600
}
},
{
.crtc = -1,
.modes = { 1 },
.n_modes = 1,
.preferred_mode = 1,
.possible_crtcs = { 1, 2 },
.n_possible_crtcs = 2,
.width_mm = 222,
.height_mm = 125,
.tile_info = {
.group_id = 1,
.max_h_tiles = 2,
.max_v_tiles = 1,
.loc_h_tile = 1,
.loc_v_tile = 0,
.tile_w = 400,
.tile_h = 600
}
}
},
.n_outputs = 3,
.crtcs = {
{
.current_mode = -1
},
{
.current_mode = -1
},
{
.current_mode = -1
}
},
.n_crtcs = 3
},
.expect = {
.monitors = {
{
.outputs = { 0 },
.n_outputs = 1,
.modes = {
{
.width = 1024,
.height = 768,
.refresh_rate = 60.000495910644531,
.crtc_modes = {
{
.output = 0,
.crtc_mode = 0
}
}
}
},
.n_modes = 1,
.current_mode = 0,
.width_mm = 222,
.height_mm = 125,
},
{
.outputs = { 1, 2 },
.n_outputs = 2,
.modes = {
{
.width = 800,
.height = 600,
.refresh_rate = 60.000495910644531,
.crtc_modes = {
{
.output = 1,
.crtc_mode = 1,
},
{
.output = 2,
.crtc_mode = 1,
}
}
}
},
.n_modes = 1,
.current_mode = 0,
.width_mm = 222,
.height_mm = 125,
}
},
.n_monitors = 2,
.logical_monitors = {
{
.monitors = { 0 },
.n_monitors = 1,
.layout = { .x = 0, .y = 256, .width = 1024, .height = 768 },
.scale = 1
},
{
.monitors = { 1 },
.n_monitors = 1,
.layout = { .x = 1024, .y = 0, .width = 600, .height = 800 },
.scale = 1,
.transform = META_MONITOR_TRANSFORM_90
}
},
.n_logical_monitors = 2,
.primary_logical_monitor = 0,
.n_outputs = 3,
.crtcs = {
{
.current_mode = 0,
.y = 256,
},
{
.current_mode = 1,
.transform = META_MONITOR_TRANSFORM_NORMAL,
.x = 1024,
.y = 0,
},
{
.current_mode = 1,
.transform = META_MONITOR_TRANSFORM_NORMAL,
.x = 1024,
.y = 400,
}
},
.n_crtcs = 3,
.n_tiled_monitors = 1,
.screen_width = 1024 + 600,
.screen_height = 1024
}
};
MetaMonitorTestSetup *test_setup;
MetaBackend *backend = meta_get_backend ();
MetaMonitorManager *monitor_manager =
meta_backend_get_monitor_manager (backend);
MetaMonitorManagerTest *monitor_manager_test =
META_MONITOR_MANAGER_TEST (monitor_manager);
meta_monitor_manager_test_set_handles_transforms (monitor_manager_test,
FALSE);
test_setup = create_monitor_test_setup (&test_case,
MONITOR_TEST_FLAG_NONE);
set_custom_monitor_config ("second-rotated-tiled.xml");
emulate_hotplug (test_setup);
check_monitor_configuration (&test_case);
}
static void
meta_test_monitor_custom_second_rotated_nonnative_config (void)
{
@ -6058,6 +6361,8 @@ init_monitor_tests (void)
meta_test_monitor_lid_closed_no_external);
add_monitor_test ("/backends/monitor/lid-closed-with-hotplugged-external",
meta_test_monitor_lid_closed_with_hotplugged_external);
add_monitor_test ("/backends/monitor/lid-scaled-closed-opened",
meta_test_monitor_lid_scaled_closed_opened);
add_monitor_test ("/backends/monitor/no-outputs",
meta_test_monitor_no_outputs);
add_monitor_test ("/backends/monitor/underscanning-config",
@ -6093,6 +6398,8 @@ init_monitor_tests (void)
meta_test_monitor_custom_second_rotated_config);
add_monitor_test ("/backends/monitor/custom/second-rotated-tiled-config",
meta_test_monitor_custom_second_rotated_tiled_config);
add_monitor_test ("/backends/monitor/custom/second-rotated-nonnative-tiled-config",
meta_test_monitor_custom_second_rotated_nonnative_tiled_config);
add_monitor_test ("/backends/monitor/custom/second-rotated-nonnative-config",
meta_test_monitor_custom_second_rotated_nonnative_config);
add_monitor_test ("/backends/monitor/custom/interlaced-config",

View File

@ -427,7 +427,7 @@ test_client_new (const char *id,
MetaWindowClientType type,
GError **error)
{
TestClient *client = g_new0 (TestClient, 1);
TestClient *client;
GSubprocessLauncher *launcher;
GSubprocess *subprocess;
MetaWaylandCompositor *compositor;
@ -462,6 +462,7 @@ test_client_new (const char *id,
if (!subprocess)
return NULL;
client = g_new0 (TestClient, 1);
client->type = type;
client->id = g_strdup (id);
client->cancellable = g_cancellable_new ();

View File

@ -26,7 +26,6 @@
#include "meta/meta-selection-source.h"
#include "wayland/meta-wayland-data-device.h"
#include "wayland/meta-wayland-data-device-private.h"
#define META_TYPE_SELECTION_SOURCE_WAYLAND (meta_selection_source_wayland_get_type ())

View File

@ -0,0 +1,354 @@
/*
* Copyright © 2011 Kristian Høgsberg
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that copyright
* notice and this permission notice appear in supporting documentation, and
* that the name of the copyright holders not be used in advertising or
* publicity pertaining to distribution of the software without specific,
* written prior permission. The copyright holders make no representations
* about the suitability of this software for any purpose. It is provided "as
* is" without express or implied warranty.
*
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
* OF THIS SOFTWARE.
*/
/* The file is based on src/data-device.c from Weston */
#include "config.h"
#include "wayland/meta-wayland-data-device-primary-legacy.h"
#include "compositor/meta-dnd-actor-private.h"
#include "meta/meta-selection-source-memory.h"
#include "wayland/meta-selection-source-wayland-private.h"
#include "wayland/meta-wayland-data-offer-primary-legacy.h"
#include "wayland/meta-wayland-data-source-primary-legacy.h"
#include "wayland/meta-wayland-dnd-surface.h"
#include "wayland/meta-wayland-pointer.h"
#include "wayland/meta-wayland-private.h"
#include "wayland/meta-wayland-seat.h"
#include "gtk-primary-selection-server-protocol.h"
static struct wl_resource * create_and_send_primary_offer (MetaWaylandDataDevicePrimaryLegacy *data_device,
struct wl_resource *target);
static void
move_resources (struct wl_list *destination,
struct wl_list *source)
{
wl_list_insert_list (destination, source);
wl_list_init (source);
}
static void
move_resources_for_client (struct wl_list *destination,
struct wl_list *source,
struct wl_client *client)
{
struct wl_resource *resource, *tmp;
wl_resource_for_each_safe (resource, tmp, source)
{
if (wl_resource_get_client (resource) == client)
{
wl_list_remove (wl_resource_get_link (resource));
wl_list_insert (destination, wl_resource_get_link (resource));
}
}
}
static void
unbind_resource (struct wl_resource *resource)
{
wl_list_remove (wl_resource_get_link (resource));
}
static void
default_destructor (struct wl_client *client,
struct wl_resource *resource)
{
wl_resource_destroy (resource);
}
static void
set_selection_source (MetaWaylandDataDevicePrimaryLegacy *data_device,
MetaSelectionSource *selection_source)
{
MetaDisplay *display = meta_get_display ();
meta_selection_set_owner (meta_display_get_selection (display),
META_SELECTION_PRIMARY,
selection_source);
g_set_object (&data_device->owner, selection_source);
}
static void
unset_selection_source (MetaWaylandDataDevicePrimaryLegacy *data_device)
{
MetaDisplay *display = meta_get_display ();
if (!data_device->owner)
return;
meta_selection_unset_owner (meta_display_get_selection (display),
META_SELECTION_PRIMARY,
data_device->owner);
g_clear_object (&data_device->owner);
}
static void
primary_source_destroyed (gpointer data,
GObject *object_was_here)
{
MetaWaylandDataDevicePrimaryLegacy *data_device = data;
data_device->data_source = NULL;
unset_selection_source (data_device);
}
static void
meta_wayland_data_device_primary_legacy_set_selection (MetaWaylandDataDevicePrimaryLegacy *data_device,
MetaWaylandDataSource *source,
uint32_t serial)
{
MetaWaylandSeat *seat = wl_container_of (data_device, seat, primary_legacy_data_device);
MetaSelectionSource *selection_source;
g_assert (!source || META_IS_WAYLAND_DATA_SOURCE_PRIMARY_LEGACY (source));
if (data_device->data_source &&
data_device->serial - serial < UINT32_MAX / 2)
return;
if (data_device->data_source)
{
g_object_weak_unref (G_OBJECT (data_device->data_source),
primary_source_destroyed,
data_device);
}
data_device->data_source = source;
data_device->serial = serial;
if (source)
{
meta_wayland_data_source_set_seat (source, seat);
g_object_weak_ref (G_OBJECT (source),
primary_source_destroyed,
data_device);
selection_source = meta_selection_source_wayland_new (source);
}
else
{
selection_source = g_object_new (META_TYPE_SELECTION_SOURCE_MEMORY, NULL);
}
set_selection_source (data_device, selection_source);
g_object_unref (selection_source);
}
static void
primary_device_set_selection (struct wl_client *client,
struct wl_resource *resource,
struct wl_resource *source_resource,
uint32_t serial)
{
MetaWaylandDataDevicePrimaryLegacy *data_device = wl_resource_get_user_data (resource);
MetaWaylandSeat *seat = wl_container_of (data_device, seat, primary_legacy_data_device);
MetaWaylandDataSource *source = NULL;
if (source_resource)
source = wl_resource_get_user_data (source_resource);
if (wl_resource_get_client (resource) !=
meta_wayland_keyboard_get_focus_client (seat->keyboard))
return;
meta_wayland_data_device_primary_legacy_set_selection (data_device, source, serial);
}
static const struct gtk_primary_selection_device_interface primary_device_interface = {
primary_device_set_selection,
default_destructor,
};
static void
owner_changed_cb (MetaSelection *selection,
MetaSelectionType selection_type,
MetaSelectionSource *new_owner,
MetaWaylandDataDevicePrimaryLegacy *data_device)
{
MetaWaylandCompositor *compositor = meta_wayland_compositor_get_default ();
MetaWaylandSeat *seat = compositor->seat;
struct wl_resource *data_device_resource;
struct wl_client *focus_client;
focus_client = meta_wayland_keyboard_get_focus_client (seat->keyboard);
if (!focus_client)
return;
if (selection_type == META_SELECTION_PRIMARY)
{
wl_resource_for_each (data_device_resource, &data_device->focus_resource_list)
{
struct wl_resource *offer = NULL;
if (new_owner)
{
offer = create_and_send_primary_offer (data_device,
data_device_resource);
}
gtk_primary_selection_device_send_selection (data_device_resource,
offer);
}
}
}
static void
ensure_owners_changed_handler_connected (MetaWaylandDataDevicePrimaryLegacy *data_device)
{
if (data_device->selection_owner_signal_id != 0)
return;
data_device->selection_owner_signal_id =
g_signal_connect (meta_display_get_selection (meta_get_display ()),
"owner-changed",
G_CALLBACK (owner_changed_cb), data_device);
}
static void
primary_device_manager_create_source (struct wl_client *client,
struct wl_resource *manager_resource,
guint32 id)
{
struct wl_resource *source_resource;
source_resource =
wl_resource_create (client, &gtk_primary_selection_source_interface,
wl_resource_get_version (manager_resource),
id);
meta_wayland_data_source_primary_legacy_new (source_resource);
}
static void
primary_device_manager_get_device (struct wl_client *client,
struct wl_resource *manager_resource,
guint32 id,
struct wl_resource *seat_resource)
{
MetaWaylandSeat *seat = wl_resource_get_user_data (seat_resource);
struct wl_resource *cr;
cr = wl_resource_create (client, &gtk_primary_selection_device_interface,
wl_resource_get_version (manager_resource), id);
wl_resource_set_implementation (cr, &primary_device_interface,
&seat->primary_legacy_data_device, unbind_resource);
wl_list_insert (&seat->primary_legacy_data_device.resource_list,
wl_resource_get_link (cr));
ensure_owners_changed_handler_connected (&seat->primary_legacy_data_device);
}
static const struct gtk_primary_selection_device_manager_interface primary_manager_interface = {
primary_device_manager_create_source,
primary_device_manager_get_device,
default_destructor,
};
static void
bind_primary_manager (struct wl_client *client,
void *data,
uint32_t version,
uint32_t id)
{
struct wl_resource *resource;
resource = wl_resource_create (client, &gtk_primary_selection_device_manager_interface,
version, id);
wl_resource_set_implementation (resource, &primary_manager_interface, NULL, NULL);
}
void
meta_wayland_data_device_primary_legacy_manager_init (MetaWaylandCompositor *compositor)
{
if (wl_global_create (compositor->wayland_display,
&gtk_primary_selection_device_manager_interface,
1, NULL, bind_primary_manager) == NULL)
g_error ("Could not create data_device");
}
void
meta_wayland_data_device_primary_legacy_init (MetaWaylandDataDevicePrimaryLegacy *data_device)
{
wl_list_init (&data_device->resource_list);
wl_list_init (&data_device->focus_resource_list);
}
static struct wl_resource *
create_and_send_primary_offer (MetaWaylandDataDevicePrimaryLegacy *data_device,
struct wl_resource *target)
{
MetaWaylandDataOffer *offer;
MetaDisplay *display = meta_get_display ();
struct wl_resource *resource;
GList *mimetypes, *l;
mimetypes = meta_selection_get_mimetypes (meta_display_get_selection (display),
META_SELECTION_PRIMARY);
if (!mimetypes)
return NULL;
offer = meta_wayland_data_offer_primary_legacy_new (target);
resource = meta_wayland_data_offer_get_resource (offer);
gtk_primary_selection_device_send_data_offer (target, resource);
for (l = mimetypes; l; l = l->next)
gtk_primary_selection_offer_send_offer (resource, l->data);
g_list_free_full (mimetypes, g_free);
return resource;
}
void
meta_wayland_data_device_primary_legacy_set_keyboard_focus (MetaWaylandDataDevicePrimaryLegacy *data_device)
{
MetaWaylandSeat *seat = wl_container_of (data_device, seat, primary_legacy_data_device);
struct wl_client *focus_client;
struct wl_resource *data_device_resource;
focus_client = meta_wayland_keyboard_get_focus_client (seat->keyboard);
if (focus_client == data_device->focus_client)
return;
data_device->focus_client = focus_client;
move_resources (&data_device->resource_list,
&data_device->focus_resource_list);
if (!focus_client)
return;
move_resources_for_client (&data_device->focus_resource_list,
&data_device->resource_list,
focus_client);
wl_resource_for_each (data_device_resource, &data_device->focus_resource_list)
{
struct wl_resource *offer;
offer = create_and_send_primary_offer (data_device, data_device_resource);
gtk_primary_selection_device_send_selection (data_device_resource, offer);
}
}

View File

@ -0,0 +1,55 @@
/*
* Copyright © 2008 Kristian Høgsberg
* 2020 Red Hat Inc.
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that copyright
* notice and this permission notice appear in supporting documentation, and
* that the name of the copyright holders not be used in advertising or
* publicity pertaining to distribution of the software without specific,
* written prior permission. The copyright holders make no representations
* about the suitability of this software for any purpose. It is provided "as
* is" without express or implied warranty.
*
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
* OF THIS SOFTWARE.
*/
#ifndef META_WAYLAND_DATA_DEVICE_PRIMARY_LEGACY_H
#define META_WAYLAND_DATA_DEVICE_PRIMARY_LEGACY_H
#include <glib-object.h>
#include <wayland-server.h>
#include "clutter/clutter.h"
#include "meta/meta-selection-source.h"
#include "wayland/meta-wayland-data-offer.h"
#include "wayland/meta-wayland-data-source.h"
#include "wayland/meta-wayland-types.h"
struct _MetaWaylandDataDevicePrimaryLegacy
{
uint32_t serial;
MetaWaylandDataSource *data_source;
struct wl_list resource_list;
struct wl_list focus_resource_list;
struct wl_client *focus_client;
guint selection_owner_signal_id;
MetaSelectionSource *owner;
};
void meta_wayland_data_device_primary_legacy_manager_init (MetaWaylandCompositor *compositor);
void meta_wayland_data_device_primary_legacy_init (MetaWaylandDataDevicePrimaryLegacy *data_device);
void meta_wayland_data_device_primary_legacy_set_keyboard_focus (MetaWaylandDataDevicePrimaryLegacy *data_device);
#endif /* META_WAYLAND_DATA_DEVICE_PRIMARY_LEGACY_H */

View File

@ -0,0 +1,353 @@
/*
* Copyright © 2011 Kristian Høgsberg
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that copyright
* notice and this permission notice appear in supporting documentation, and
* that the name of the copyright holders not be used in advertising or
* publicity pertaining to distribution of the software without specific,
* written prior permission. The copyright holders make no representations
* about the suitability of this software for any purpose. It is provided "as
* is" without express or implied warranty.
*
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
* OF THIS SOFTWARE.
*/
/* The file is based on src/data-device.c from Weston */
#include "config.h"
#include "wayland/meta-wayland-data-device-primary.h"
#include "compositor/meta-dnd-actor-private.h"
#include "meta/meta-selection-source-memory.h"
#include "wayland/meta-selection-source-wayland-private.h"
#include "wayland/meta-wayland-data-offer-primary.h"
#include "wayland/meta-wayland-data-source-primary.h"
#include "wayland/meta-wayland-dnd-surface.h"
#include "wayland/meta-wayland-pointer.h"
#include "wayland/meta-wayland-private.h"
#include "wayland/meta-wayland-seat.h"
#include "primary-selection-unstable-v1-server-protocol.h"
static struct wl_resource * create_and_send_primary_offer (MetaWaylandDataDevicePrimary *data_device,
struct wl_resource *target);
static void
move_resources (struct wl_list *destination,
struct wl_list *source)
{
wl_list_insert_list (destination, source);
wl_list_init (source);
}
static void
move_resources_for_client (struct wl_list *destination,
struct wl_list *source,
struct wl_client *client)
{
struct wl_resource *resource, *tmp;
wl_resource_for_each_safe (resource, tmp, source)
{
if (wl_resource_get_client (resource) == client)
{
wl_list_remove (wl_resource_get_link (resource));
wl_list_insert (destination, wl_resource_get_link (resource));
}
}
}
static void
unbind_resource (struct wl_resource *resource)
{
wl_list_remove (wl_resource_get_link (resource));
}
static void
default_destructor (struct wl_client *client,
struct wl_resource *resource)
{
wl_resource_destroy (resource);
}
static void
set_selection_source (MetaWaylandDataDevicePrimary *data_device,
MetaSelectionSource *selection_source)
{
MetaDisplay *display = meta_get_display ();
meta_selection_set_owner (meta_display_get_selection (display),
META_SELECTION_PRIMARY,
selection_source);
g_set_object (&data_device->owner, selection_source);
}
static void
unset_selection_source (MetaWaylandDataDevicePrimary *data_device)
{
MetaDisplay *display = meta_get_display ();
if (!data_device->owner)
return;
meta_selection_unset_owner (meta_display_get_selection (display),
META_SELECTION_PRIMARY,
data_device->owner);
g_clear_object (&data_device->owner);
}
static void
primary_source_destroyed (gpointer data,
GObject *object_was_here)
{
MetaWaylandDataDevicePrimary *data_device = data;
data_device->data_source = NULL;
unset_selection_source (data_device);
}
static void
meta_wayland_data_device_primary_set_selection (MetaWaylandDataDevicePrimary *data_device,
MetaWaylandDataSource *source,
uint32_t serial)
{
MetaWaylandSeat *seat = wl_container_of (data_device, seat, primary_data_device);
MetaSelectionSource *selection_source;
g_assert (!source || META_IS_WAYLAND_DATA_SOURCE_PRIMARY (source));
if (data_device->data_source &&
data_device->serial - serial < UINT32_MAX / 2)
return;
if (data_device->data_source)
{
g_object_weak_unref (G_OBJECT (data_device->data_source),
primary_source_destroyed,
data_device);
}
data_device->data_source = source;
data_device->serial = serial;
if (source)
{
meta_wayland_data_source_set_seat (source, seat);
g_object_weak_ref (G_OBJECT (source),
primary_source_destroyed,
data_device);
selection_source = meta_selection_source_wayland_new (source);
}
else
{
selection_source = g_object_new (META_TYPE_SELECTION_SOURCE_MEMORY, NULL);
}
set_selection_source (data_device, selection_source);
g_object_unref (selection_source);
}
static void
primary_device_set_selection (struct wl_client *client,
struct wl_resource *resource,
struct wl_resource *source_resource,
uint32_t serial)
{
MetaWaylandDataDevicePrimary *data_device = wl_resource_get_user_data (resource);
MetaWaylandSeat *seat = wl_container_of (data_device, seat, primary_data_device);
MetaWaylandDataSource *source = NULL;
if (source_resource)
source = wl_resource_get_user_data (source_resource);
if (wl_resource_get_client (resource) !=
meta_wayland_keyboard_get_focus_client (seat->keyboard))
return;
meta_wayland_data_device_primary_set_selection (data_device, source, serial);
}
static const struct zwp_primary_selection_device_v1_interface primary_device_interface = {
primary_device_set_selection,
default_destructor,
};
static void
owner_changed_cb (MetaSelection *selection,
MetaSelectionType selection_type,
MetaSelectionSource *new_owner,
MetaWaylandDataDevicePrimary *data_device)
{
MetaWaylandCompositor *compositor = meta_wayland_compositor_get_default ();
MetaWaylandSeat *seat = compositor->seat;
struct wl_resource *data_device_resource;
struct wl_client *focus_client;
focus_client = meta_wayland_keyboard_get_focus_client (seat->keyboard);
if (!focus_client)
return;
if (selection_type == META_SELECTION_PRIMARY)
{
wl_resource_for_each (data_device_resource, &data_device->focus_resource_list)
{
struct wl_resource *offer = NULL;
if (new_owner)
{
offer = create_and_send_primary_offer (data_device,
data_device_resource);
}
zwp_primary_selection_device_v1_send_selection (data_device_resource,
offer);
}
}
}
static void
ensure_owners_changed_handler_connected (MetaWaylandDataDevicePrimary *data_device)
{
if (data_device->selection_owner_signal_id != 0)
return;
data_device->selection_owner_signal_id =
g_signal_connect (meta_display_get_selection (meta_get_display ()),
"owner-changed",
G_CALLBACK (owner_changed_cb), data_device);
}
static void
primary_device_manager_create_source (struct wl_client *client,
struct wl_resource *manager_resource,
guint32 id)
{
struct wl_resource *source_resource;
source_resource =
wl_resource_create (client, &zwp_primary_selection_source_v1_interface,
wl_resource_get_version (manager_resource),
id);
meta_wayland_data_source_primary_new (source_resource);
}
static void
primary_device_manager_get_device (struct wl_client *client,
struct wl_resource *manager_resource,
guint32 id,
struct wl_resource *seat_resource)
{
MetaWaylandSeat *seat = wl_resource_get_user_data (seat_resource);
struct wl_resource *cr;
cr = wl_resource_create (client, &zwp_primary_selection_device_v1_interface,
wl_resource_get_version (manager_resource), id);
wl_resource_set_implementation (cr, &primary_device_interface,
&seat->primary_data_device, unbind_resource);
wl_list_insert (&seat->primary_data_device.resource_list, wl_resource_get_link (cr));
ensure_owners_changed_handler_connected (&seat->primary_data_device);
}
static const struct zwp_primary_selection_device_manager_v1_interface primary_manager_interface = {
primary_device_manager_create_source,
primary_device_manager_get_device,
default_destructor,
};
static void
bind_primary_manager (struct wl_client *client,
void *data,
uint32_t version,
uint32_t id)
{
struct wl_resource *resource;
resource = wl_resource_create (client, &zwp_primary_selection_device_manager_v1_interface,
version, id);
wl_resource_set_implementation (resource, &primary_manager_interface, NULL, NULL);
}
void
meta_wayland_data_device_primary_manager_init (MetaWaylandCompositor *compositor)
{
if (wl_global_create (compositor->wayland_display,
&zwp_primary_selection_device_manager_v1_interface,
1, NULL, bind_primary_manager) == NULL)
g_error ("Could not create data_device");
}
void
meta_wayland_data_device_primary_init (MetaWaylandDataDevicePrimary *data_device)
{
wl_list_init (&data_device->resource_list);
wl_list_init (&data_device->focus_resource_list);
}
static struct wl_resource *
create_and_send_primary_offer (MetaWaylandDataDevicePrimary *data_device,
struct wl_resource *target)
{
MetaWaylandDataOffer *offer;
MetaDisplay *display = meta_get_display ();
struct wl_resource *resource;
GList *mimetypes, *l;
mimetypes = meta_selection_get_mimetypes (meta_display_get_selection (display),
META_SELECTION_PRIMARY);
if (!mimetypes)
return NULL;
offer = meta_wayland_data_offer_primary_new (target);
resource = meta_wayland_data_offer_get_resource (offer);
zwp_primary_selection_device_v1_send_data_offer (target, resource);
for (l = mimetypes; l; l = l->next)
zwp_primary_selection_offer_v1_send_offer (resource, l->data);
g_list_free_full (mimetypes, g_free);
return resource;
}
void
meta_wayland_data_device_primary_set_keyboard_focus (MetaWaylandDataDevicePrimary *data_device)
{
MetaWaylandSeat *seat = wl_container_of (data_device, seat, primary_data_device);
struct wl_client *focus_client;
struct wl_resource *data_device_resource;
focus_client = meta_wayland_keyboard_get_focus_client (seat->keyboard);
if (focus_client == data_device->focus_client)
return;
data_device->focus_client = focus_client;
move_resources (&data_device->resource_list,
&data_device->focus_resource_list);
if (!focus_client)
return;
move_resources_for_client (&data_device->focus_resource_list,
&data_device->resource_list,
focus_client);
wl_resource_for_each (data_device_resource, &data_device->focus_resource_list)
{
struct wl_resource *offer;
offer = create_and_send_primary_offer (data_device, data_device_resource);
zwp_primary_selection_device_v1_send_selection (data_device_resource, offer);
}
}

View File

@ -0,0 +1,55 @@
/*
* Copyright © 2008 Kristian Høgsberg
* 2020 Red Hat Inc.
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that copyright
* notice and this permission notice appear in supporting documentation, and
* that the name of the copyright holders not be used in advertising or
* publicity pertaining to distribution of the software without specific,
* written prior permission. The copyright holders make no representations
* about the suitability of this software for any purpose. It is provided "as
* is" without express or implied warranty.
*
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
* OF THIS SOFTWARE.
*/
#ifndef META_WAYLAND_DATA_DEVICE_PRIMARY_H
#define META_WAYLAND_DATA_DEVICE_PRIMARY_H
#include <glib-object.h>
#include <wayland-server.h>
#include "clutter/clutter.h"
#include "meta/meta-selection-source.h"
#include "wayland/meta-wayland-data-offer.h"
#include "wayland/meta-wayland-data-source.h"
#include "wayland/meta-wayland-types.h"
struct _MetaWaylandDataDevicePrimary
{
uint32_t serial;
MetaWaylandDataSource *data_source;
struct wl_list resource_list;
struct wl_list focus_resource_list;
struct wl_client *focus_client;
guint selection_owner_signal_id;
MetaSelectionSource *owner;
};
void meta_wayland_data_device_primary_manager_init (MetaWaylandCompositor *compositor);
void meta_wayland_data_device_primary_init (MetaWaylandDataDevicePrimary *data_device);
void meta_wayland_data_device_primary_set_keyboard_focus (MetaWaylandDataDevicePrimary *data_device);
#endif /* META_WAYLAND_DATA_DEVICE_PRIMARY_H */

File diff suppressed because it is too large Load Diff

View File

@ -28,42 +28,20 @@
#include "clutter/clutter.h"
#include "meta/meta-selection-source.h"
#include "wayland/meta-wayland-data-offer.h"
#include "wayland/meta-wayland-data-source.h"
#include "wayland/meta-wayland-types.h"
typedef struct _MetaWaylandDragGrab MetaWaylandDragGrab;
typedef struct _MetaWaylandDataSourceFuncs MetaWaylandDataSourceFuncs;
#define META_TYPE_WAYLAND_DATA_SOURCE (meta_wayland_data_source_get_type ())
G_DECLARE_DERIVABLE_TYPE (MetaWaylandDataSource, meta_wayland_data_source,
META, WAYLAND_DATA_SOURCE, GObject);
struct _MetaWaylandDataSourceClass
{
GObjectClass parent_class;
void (* send) (MetaWaylandDataSource *source,
const gchar *mime_type,
gint fd);
void (* target) (MetaWaylandDataSource *source,
const gchar *mime_type);
void (* cancel) (MetaWaylandDataSource *source);
void (* action) (MetaWaylandDataSource *source,
uint32_t action);
void (* drop_performed) (MetaWaylandDataSource *source);
void (* drag_finished) (MetaWaylandDataSource *source);
};
struct _MetaWaylandDataDevice
{
uint32_t selection_serial;
uint32_t primary_serial;
MetaWaylandDataSource *selection_data_source;
MetaWaylandDataSource *dnd_data_source;
MetaWaylandDataSource *primary_data_source;
struct wl_listener selection_data_source_listener;
struct wl_list resource_list;
struct wl_list primary_resource_list;
struct wl_list focus_resource_list;
MetaWaylandDragGrab *current_grab;
struct wl_client *focus_client;
@ -89,42 +67,7 @@ void meta_wayland_data_device_set_dnd_source (MetaWaylandDataDevice *data_de
void meta_wayland_data_device_set_selection (MetaWaylandDataDevice *data_device,
MetaWaylandDataSource *source,
guint32 serial);
void meta_wayland_data_device_set_primary (MetaWaylandDataDevice *data_device,
MetaWaylandDataSource *source,
guint32 serial);
gboolean meta_wayland_data_source_add_mime_type (MetaWaylandDataSource *source,
const gchar *mime_type);
gboolean meta_wayland_data_source_has_mime_type (const MetaWaylandDataSource *source,
const gchar *mime_type);
struct wl_array *
meta_wayland_data_source_get_mime_types (const MetaWaylandDataSource *source);
gboolean meta_wayland_data_source_has_target (MetaWaylandDataSource *source);
void meta_wayland_data_source_set_has_target (MetaWaylandDataSource *source,
gboolean has_target);
void meta_wayland_data_source_cancel (MetaWaylandDataSource *source);
void meta_wayland_data_source_send (MetaWaylandDataSource *source,
const gchar *mime_type,
gint fd);
void meta_wayland_data_source_notify_finish (MetaWaylandDataSource *source);
uint32_t meta_wayland_data_source_get_actions (MetaWaylandDataSource *source);
uint32_t meta_wayland_data_source_get_user_action (MetaWaylandDataSource *source);
uint32_t meta_wayland_data_source_get_current_action (MetaWaylandDataSource *source);
void meta_wayland_data_source_set_actions (MetaWaylandDataSource *source,
uint32_t dnd_actions);
void meta_wayland_data_source_set_user_action (MetaWaylandDataSource *source,
uint32_t action);
void meta_wayland_data_source_set_current_action (MetaWaylandDataSource *source,
uint32_t action);
void meta_wayland_data_device_unset_dnd_selection (MetaWaylandDataDevice *data_device);
const MetaWaylandDragDestFuncs *
meta_wayland_data_device_get_drag_dest_funcs (void);

View File

@ -0,0 +1,139 @@
/*
* Copyright © 2011 Kristian Høgsberg
* 2020 Red Hat Inc.
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that copyright
* notice and this permission notice appear in supporting documentation, and
* that the name of the copyright holders not be used in advertising or
* publicity pertaining to distribution of the software without specific,
* written prior permission. The copyright holders make no representations
* about the suitability of this software for any purpose. It is provided "as
* is" without express or implied warranty.
*
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
* OF THIS SOFTWARE.
*/
#include "config.h"
#include "meta-wayland-data-offer-primary-legacy.h"
#include <gio/gunixoutputstream.h>
#include <glib-unix.h>
#include <glib.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "core/display-private.h"
#include "gtk-primary-selection-server-protocol.h"
#include "wayland/meta-wayland-data-offer.h"
static void
transfer_cb (MetaSelection *selection,
GAsyncResult *res,
GOutputStream *stream)
{
GError *error = NULL;
if (!meta_selection_transfer_finish (selection, res, &error))
{
g_warning ("Could not fetch selection data: %s", error->message);
g_error_free (error);
}
g_output_stream_close (stream, NULL, NULL);
g_object_unref (stream);
}
static void
primary_offer_receive (struct wl_client *client,
struct wl_resource *resource,
const char *mime_type,
int32_t fd)
{
MetaDisplay *display = meta_get_display ();
GOutputStream *stream;
GList *mime_types;
gboolean found;
mime_types = meta_selection_get_mimetypes (meta_display_get_selection (display),
META_SELECTION_PRIMARY);
found = g_list_find_custom (mime_types, mime_type, (GCompareFunc) g_strcmp0) != NULL;
g_list_free_full (mime_types, g_free);
if (!found)
{
close (fd);
return;
}
stream = g_unix_output_stream_new (fd, TRUE);
meta_selection_transfer_async (meta_display_get_selection (display),
META_SELECTION_PRIMARY,
mime_type,
-1,
stream,
NULL,
(GAsyncReadyCallback) transfer_cb,
stream);
}
static void
primary_offer_destroy (struct wl_client *client,
struct wl_resource *resource)
{
wl_resource_destroy (resource);
}
static const struct gtk_primary_selection_offer_interface primary_offer_interface = {
primary_offer_receive,
primary_offer_destroy,
};
static void
destroy_primary_offer (struct wl_resource *resource)
{
MetaWaylandDataOffer *offer = wl_resource_get_user_data (resource);
if (offer->source)
{
if (offer == meta_wayland_data_source_get_current_offer (offer->source))
{
meta_wayland_data_source_cancel (offer->source);
meta_wayland_data_source_set_current_offer (offer->source, NULL);
}
g_object_remove_weak_pointer (G_OBJECT (offer->source),
(gpointer *)&offer->source);
offer->source = NULL;
}
meta_display_sync_wayland_input_focus (meta_get_display ());
g_slice_free (MetaWaylandDataOffer, offer);
}
MetaWaylandDataOffer *
meta_wayland_data_offer_primary_legacy_new (struct wl_resource *target)
{
MetaWaylandDataOffer *offer;
offer = g_slice_new0 (MetaWaylandDataOffer);
offer->selection_type = META_SELECTION_PRIMARY;
offer->resource = wl_resource_create (wl_resource_get_client (target),
&gtk_primary_selection_offer_interface,
wl_resource_get_version (target), 0);
wl_resource_set_implementation (offer->resource,
&primary_offer_interface,
offer,
destroy_primary_offer);
return offer;
}

View File

@ -0,0 +1,31 @@
/*
* Copyright © 2011 Kristian Høgsberg
* 2020 Red Hat Inc.
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that copyright
* notice and this permission notice appear in supporting documentation, and
* that the name of the copyright holders not be used in advertising or
* publicity pertaining to distribution of the software without specific,
* written prior permission. The copyright holders make no representations
* about the suitability of this software for any purpose. It is provided "as
* is" without express or implied warranty.
*
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
* OF THIS SOFTWARE.
*/
#ifndef META_WAYLAND_DATA_OFFER_PRIMARY_LEGACY_H
#define META_WAYLAND_DATA_OFFER_PRIMARY_LEGACY_H
#include "meta-wayland-data-offer.h"
MetaWaylandDataOffer * meta_wayland_data_offer_primary_legacy_new (struct wl_resource *target);
#endif /* META_WAYLAND_DATA_OFFER_PRIMARY_LEGACY_H */

View File

@ -0,0 +1,139 @@
/*
* Copyright © 2011 Kristian Høgsberg
* 2020 Red Hat Inc.
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that copyright
* notice and this permission notice appear in supporting documentation, and
* that the name of the copyright holders not be used in advertising or
* publicity pertaining to distribution of the software without specific,
* written prior permission. The copyright holders make no representations
* about the suitability of this software for any purpose. It is provided "as
* is" without express or implied warranty.
*
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
* OF THIS SOFTWARE.
*/
#include "config.h"
#include "meta-wayland-data-offer-primary.h"
#include <gio/gunixoutputstream.h>
#include <glib-unix.h>
#include <glib.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "core/display-private.h"
#include "primary-selection-unstable-v1-server-protocol.h"
#include "wayland/meta-wayland-data-offer.h"
static void
transfer_cb (MetaSelection *selection,
GAsyncResult *res,
GOutputStream *stream)
{
GError *error = NULL;
if (!meta_selection_transfer_finish (selection, res, &error))
{
g_warning ("Could not fetch selection data: %s", error->message);
g_error_free (error);
}
g_output_stream_close (stream, NULL, NULL);
g_object_unref (stream);
}
static void
primary_offer_receive (struct wl_client *client,
struct wl_resource *resource,
const char *mime_type,
int32_t fd)
{
MetaDisplay *display = meta_get_display ();
GOutputStream *stream;
GList *mime_types;
gboolean found;
mime_types = meta_selection_get_mimetypes (meta_display_get_selection (display),
META_SELECTION_PRIMARY);
found = g_list_find_custom (mime_types, mime_type, (GCompareFunc) g_strcmp0) != NULL;
g_list_free_full (mime_types, g_free);
if (!found)
{
close (fd);
return;
}
stream = g_unix_output_stream_new (fd, TRUE);
meta_selection_transfer_async (meta_display_get_selection (display),
META_SELECTION_PRIMARY,
mime_type,
-1,
stream,
NULL,
(GAsyncReadyCallback) transfer_cb,
stream);
}
static void
primary_offer_destroy (struct wl_client *client,
struct wl_resource *resource)
{
wl_resource_destroy (resource);
}
static const struct zwp_primary_selection_offer_v1_interface primary_offer_interface = {
primary_offer_receive,
primary_offer_destroy,
};
static void
destroy_primary_offer (struct wl_resource *resource)
{
MetaWaylandDataOffer *offer = wl_resource_get_user_data (resource);
if (offer->source)
{
if (offer == meta_wayland_data_source_get_current_offer (offer->source))
{
meta_wayland_data_source_cancel (offer->source);
meta_wayland_data_source_set_current_offer (offer->source, NULL);
}
g_object_remove_weak_pointer (G_OBJECT (offer->source),
(gpointer *)&offer->source);
offer->source = NULL;
}
meta_display_sync_wayland_input_focus (meta_get_display ());
g_slice_free (MetaWaylandDataOffer, offer);
}
MetaWaylandDataOffer *
meta_wayland_data_offer_primary_new (struct wl_resource *target)
{
MetaWaylandDataOffer *offer;
offer = g_slice_new0 (MetaWaylandDataOffer);
offer->selection_type = META_SELECTION_PRIMARY;
offer->resource = wl_resource_create (wl_resource_get_client (target),
&zwp_primary_selection_offer_v1_interface,
wl_resource_get_version (target), 0);
wl_resource_set_implementation (offer->resource,
&primary_offer_interface,
offer,
destroy_primary_offer);
return offer;
}

View File

@ -0,0 +1,31 @@
/*
* Copyright © 2011 Kristian Høgsberg
* 2020 Red Hat Inc.
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that copyright
* notice and this permission notice appear in supporting documentation, and
* that the name of the copyright holders not be used in advertising or
* publicity pertaining to distribution of the software without specific,
* written prior permission. The copyright holders make no representations
* about the suitability of this software for any purpose. It is provided "as
* is" without express or implied warranty.
*
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
* OF THIS SOFTWARE.
*/
#ifndef META_WAYLAND_DATA_OFFER_PRIMARY_H
#define META_WAYLAND_DATA_OFFER_PRIMARY_H
#include "meta-wayland-data-offer.h"
MetaWaylandDataOffer * meta_wayland_data_offer_primary_new (struct wl_resource *target);
#endif /* META_WAYLAND_DATA_OFFER_PRIMARY_H */

View File

@ -0,0 +1,327 @@
/*
* Copyright © 2011 Kristian Høgsberg
* 2020 Red Hat Inc.
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that copyright
* notice and this permission notice appear in supporting documentation, and
* that the name of the copyright holders not be used in advertising or
* publicity pertaining to distribution of the software without specific,
* written prior permission. The copyright holders make no representations
* about the suitability of this software for any purpose. It is provided "as
* is" without express or implied warranty.
*
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
* OF THIS SOFTWARE.
*/
#include "config.h"
#include <gio/gunixoutputstream.h>
#include <glib-unix.h>
#include <glib.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "meta/meta-selection.h"
#include "wayland/meta-wayland-data-device.h"
#include "wayland/meta-wayland-private.h"
#include "meta-wayland-data-offer.h"
#define ALL_ACTIONS (WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY | \
WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE | \
WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK)
static void
data_offer_accept (struct wl_client *client,
struct wl_resource *resource,
guint32 serial,
const char *mime_type)
{
MetaWaylandDataOffer *offer = wl_resource_get_user_data (resource);
/* FIXME: Check that client is currently focused by the input
* device that is currently dragging this data source. Should
* this be a wl_data_device request? */
if (offer->source)
{
meta_wayland_data_source_target (offer->source, mime_type);
meta_wayland_data_source_set_has_target (offer->source,
mime_type != NULL);
}
offer->accepted = mime_type != NULL;
}
static void
transfer_cb (MetaSelection *selection,
GAsyncResult *res,
GOutputStream *stream)
{
GError *error = NULL;
if (!meta_selection_transfer_finish (selection, res, &error))
{
g_warning ("Could not fetch selection data: %s", error->message);
g_error_free (error);
}
g_output_stream_close (stream, NULL, NULL);
g_object_unref (stream);
}
static void
data_offer_receive (struct wl_client *client, struct wl_resource *resource,
const char *mime_type, int32_t fd)
{
MetaWaylandDataOffer *offer = wl_resource_get_user_data (resource);
MetaDisplay *display = meta_get_display ();
MetaSelectionType selection_type;
GList *mime_types;
gboolean found;
selection_type = offer->selection_type;
mime_types = meta_selection_get_mimetypes (meta_display_get_selection (display),
selection_type);
found = g_list_find_custom (mime_types, mime_type, (GCompareFunc) g_strcmp0) != NULL;
g_list_free_full (mime_types, g_free);
if (found)
{
GOutputStream *stream;
stream = g_unix_output_stream_new (fd, TRUE);
meta_selection_transfer_async (meta_display_get_selection (display),
selection_type,
mime_type,
-1,
stream,
NULL,
(GAsyncReadyCallback) transfer_cb,
stream);
}
else
{
close (fd);
}
}
static void
data_offer_destroy (struct wl_client *client,
struct wl_resource *resource)
{
wl_resource_destroy (resource);
}
static void
data_offer_finish (struct wl_client *client,
struct wl_resource *resource)
{
MetaWaylandDataOffer *offer = wl_resource_get_user_data (resource);
enum wl_data_device_manager_dnd_action current_action;
if (!offer->source ||
offer != meta_wayland_data_source_get_current_offer (offer->source))
return;
if (!offer->accepted || !offer->action_sent)
{
wl_resource_post_error (offer->resource,
WL_DATA_OFFER_ERROR_INVALID_FINISH,
"premature finish request");
return;
}
current_action = meta_wayland_data_source_get_current_action (offer->source);
if (current_action == WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE ||
current_action == WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK)
{
wl_resource_post_error (offer->resource,
WL_DATA_OFFER_ERROR_INVALID_OFFER,
"offer finished with an invalid action");
return;
}
meta_wayland_data_source_notify_finish (offer->source);
}
static void
data_offer_set_actions (struct wl_client *client,
struct wl_resource *resource,
uint32_t dnd_actions,
uint32_t preferred_action)
{
MetaWaylandDataOffer *offer = wl_resource_get_user_data (resource);
if (dnd_actions & ~(ALL_ACTIONS))
{
wl_resource_post_error (offer->resource,
WL_DATA_OFFER_ERROR_INVALID_ACTION_MASK,
"invalid actions mask %x", dnd_actions);
return;
}
if (preferred_action &&
(!(preferred_action & dnd_actions) ||
__builtin_popcount (preferred_action) > 1))
{
wl_resource_post_error (offer->resource,
WL_DATA_OFFER_ERROR_INVALID_ACTION,
"invalid action %x", preferred_action);
return;
}
offer->dnd_actions = dnd_actions;
offer->preferred_dnd_action = preferred_action;
meta_wayland_data_offer_update_action (offer);
}
static const struct wl_data_offer_interface data_offer_interface = {
data_offer_accept,
data_offer_receive,
data_offer_destroy,
data_offer_finish,
data_offer_set_actions,
};
static void
destroy_data_offer (struct wl_resource *resource)
{
MetaWaylandDataOffer *offer = wl_resource_get_user_data (resource);
MetaWaylandSeat *seat;
if (offer->source)
{
seat = meta_wayland_data_source_get_seat (offer->source);
if (offer == meta_wayland_data_source_get_current_offer (offer->source))
{
if (seat->data_device.dnd_data_source == offer->source)
{
if (wl_resource_get_version (offer->resource) <
WL_DATA_OFFER_ACTION_SINCE_VERSION)
meta_wayland_data_source_notify_finish (offer->source);
else if (meta_wayland_data_source_get_drop_performed (offer->source))
meta_wayland_data_source_cancel (offer->source);
}
else
{
meta_wayland_data_source_set_current_offer (offer->source, NULL);
meta_wayland_data_source_set_has_target (offer->source, FALSE);
}
}
g_object_remove_weak_pointer (G_OBJECT (offer->source),
(gpointer *)&offer->source);
offer->source = NULL;
}
meta_display_sync_wayland_input_focus (meta_get_display ());
g_slice_free (MetaWaylandDataOffer, offer);
}
MetaWaylandDataOffer *
meta_wayland_data_offer_new (MetaSelectionType selection_type,
MetaWaylandDataSource *source,
struct wl_resource *target)
{
MetaWaylandDataOffer *offer;
offer = g_slice_new0 (MetaWaylandDataOffer);
offer->selection_type = selection_type;
offer->resource = wl_resource_create (wl_resource_get_client (target),
&wl_data_offer_interface,
wl_resource_get_version (target), 0);
wl_resource_set_implementation (offer->resource,
&data_offer_interface,
offer,
destroy_data_offer);
if (source)
{
offer->source = source;
g_object_add_weak_pointer (G_OBJECT (source), (gpointer *)&offer->source);
}
return offer;
}
static enum wl_data_device_manager_dnd_action
data_offer_choose_action (MetaWaylandDataOffer *offer)
{
MetaWaylandDataSource *source = offer->source;
uint32_t actions, user_action, available_actions;
if (wl_resource_get_version (offer->resource) <
WL_DATA_OFFER_ACTION_SINCE_VERSION)
return WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY;
meta_wayland_data_source_get_actions (source, &actions);
user_action = meta_wayland_data_source_get_user_action (source);
available_actions = actions & offer->dnd_actions;
if (!available_actions)
return WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE;
/* If the user is forcing an action, go for it */
if ((user_action & available_actions) != 0)
return user_action;
/* If the dest side has a preferred DnD action, use it */
if ((offer->preferred_dnd_action & available_actions) != 0)
return offer->preferred_dnd_action;
/* Use the first found action, in bit order */
return 1 << (ffs (available_actions) - 1);
}
void
meta_wayland_data_offer_update_action (MetaWaylandDataOffer *offer)
{
enum wl_data_device_manager_dnd_action current_action, action;
MetaWaylandDataSource *source;
if (!offer->source)
return;
source = offer->source;
current_action = meta_wayland_data_source_get_current_action (source);
action = data_offer_choose_action (offer);
if (current_action == action)
return;
meta_wayland_data_source_set_current_action (source, action);
if (!meta_wayland_data_source_get_in_ask (source) &&
wl_resource_get_version (offer->resource) >=
WL_DATA_OFFER_ACTION_SINCE_VERSION)
{
wl_data_offer_send_action (offer->resource, action);
offer->action_sent = TRUE;
}
}
struct wl_resource *
meta_wayland_data_offer_get_resource (MetaWaylandDataOffer *offer)
{
return offer->resource;
}
MetaWaylandDataSource *
meta_wayland_data_offer_get_source (MetaWaylandDataOffer *offer)
{
return offer->source;
}

View File

@ -0,0 +1,51 @@
/*
* Copyright © 2011 Kristian Høgsberg
* 2020 Red Hat Inc.
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that copyright
* notice and this permission notice appear in supporting documentation, and
* that the name of the copyright holders not be used in advertising or
* publicity pertaining to distribution of the software without specific,
* written prior permission. The copyright holders make no representations
* about the suitability of this software for any purpose. It is provided "as
* is" without express or implied warranty.
*
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
* OF THIS SOFTWARE.
*/
#ifndef META_WAYLAND_DATA_OFFER_H
#define META_WAYLAND_DATA_OFFER_H
#include "meta/meta-selection.h"
#include "wayland/meta-wayland-data-source.h"
struct _MetaWaylandDataOffer
{
struct wl_resource *resource;
MetaWaylandDataSource *source;
struct wl_listener source_destroy_listener;
gboolean accepted;
gboolean action_sent;
uint32_t dnd_actions;
enum wl_data_device_manager_dnd_action preferred_dnd_action;
MetaSelectionType selection_type;
};
MetaWaylandDataOffer * meta_wayland_data_offer_new (MetaSelectionType selection_type,
MetaWaylandDataSource *source,
struct wl_resource *resource);
void meta_wayland_data_offer_update_action (MetaWaylandDataOffer *offer);
struct wl_resource * meta_wayland_data_offer_get_resource (MetaWaylandDataOffer *offer);
MetaWaylandDataSource * meta_wayland_data_offer_get_source (MetaWaylandDataOffer *offer);
#endif /* META_WAYLAND_DATA_OFFER_H */

View File

@ -0,0 +1,117 @@
/*
* Copyright © 2011 Kristian Høgsberg
* 2020 Red Hat Inc.
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that copyright
* notice and this permission notice appear in supporting documentation, and
* that the name of the copyright holders not be used in advertising or
* publicity pertaining to distribution of the software without specific,
* written prior permission. The copyright holders make no representations
* about the suitability of this software for any purpose. It is provided "as
* is" without express or implied warranty.
*
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
* OF THIS SOFTWARE.
*/
#include "config.h"
#include <unistd.h>
#include "gtk-primary-selection-server-protocol.h"
#include "wayland/meta-wayland-data-source-primary-legacy.h"
typedef struct _MetaWaylandDataSourcePrimaryLegacy
{
MetaWaylandDataSource parent;
} MetaWaylandDataSourcePrimaryLegacy;
G_DEFINE_TYPE (MetaWaylandDataSourcePrimaryLegacy, meta_wayland_data_source_primary_legacy,
META_TYPE_WAYLAND_DATA_SOURCE);
static void
primary_source_offer (struct wl_client *client,
struct wl_resource *resource,
const char *type)
{
MetaWaylandDataSource *source = wl_resource_get_user_data (resource);
if (!meta_wayland_data_source_add_mime_type (source, type))
wl_resource_post_no_memory (resource);
}
static void
primary_source_destroy (struct wl_client *client,
struct wl_resource *resource)
{
wl_resource_destroy (resource);
}
static struct gtk_primary_selection_source_interface primary_source_interface = {
primary_source_offer,
primary_source_destroy,
};
static void
destroy_primary_source (struct wl_resource *resource)
{
MetaWaylandDataSource *source = wl_resource_get_user_data (resource);
meta_wayland_data_source_set_resource (source, NULL);
g_object_unref (source);
}
static void
meta_wayland_data_source_primary_legacy_send (MetaWaylandDataSource *source,
const gchar *mime_type,
gint fd)
{
struct wl_resource *resource = meta_wayland_data_source_get_resource (source);
gtk_primary_selection_source_send_send (resource, mime_type, fd);
close (fd);
}
static void
meta_wayland_data_source_primary_legacy_cancel (MetaWaylandDataSource *source)
{
struct wl_resource *resource = meta_wayland_data_source_get_resource (source);
if (resource)
gtk_primary_selection_source_send_cancelled (resource);
}
static void
meta_wayland_data_source_primary_legacy_init (MetaWaylandDataSourcePrimaryLegacy *source_primary)
{
}
static void
meta_wayland_data_source_primary_legacy_class_init (MetaWaylandDataSourcePrimaryLegacyClass *klass)
{
MetaWaylandDataSourceClass *data_source_class =
META_WAYLAND_DATA_SOURCE_CLASS (klass);
data_source_class->send = meta_wayland_data_source_primary_legacy_send;
data_source_class->cancel = meta_wayland_data_source_primary_legacy_cancel;
}
MetaWaylandDataSource *
meta_wayland_data_source_primary_legacy_new (struct wl_resource *resource)
{
MetaWaylandDataSource *source_primary =
g_object_new (META_TYPE_WAYLAND_DATA_SOURCE_PRIMARY_LEGACY, NULL);
meta_wayland_data_source_set_resource (source_primary, resource);
wl_resource_set_implementation (resource, &primary_source_interface,
source_primary, destroy_primary_source);
return source_primary;
}

View File

@ -0,0 +1,37 @@
/*
* Copyright © 2011 Kristian Høgsberg
* 2020 Red Hat Inc.
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that copyright
* notice and this permission notice appear in supporting documentation, and
* that the name of the copyright holders not be used in advertising or
* publicity pertaining to distribution of the software without specific,
* written prior permission. The copyright holders make no representations
* about the suitability of this software for any purpose. It is provided "as
* is" without express or implied warranty.
*
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
* OF THIS SOFTWARE.
*/
#ifndef META_WAYLAND_DATA_SOURCE_PRIMARY_LEGACY_H
#define META_WAYLAND_DATA_SOURCE_PRIMARY_LEGACY_H
#include "meta-wayland-data-source.h"
#define META_TYPE_WAYLAND_DATA_SOURCE_PRIMARY_LEGACY (meta_wayland_data_source_primary_legacy_get_type ())
G_DECLARE_FINAL_TYPE (MetaWaylandDataSourcePrimaryLegacy,
meta_wayland_data_source_primary_legacy,
META, WAYLAND_DATA_SOURCE_PRIMARY_LEGACY,
MetaWaylandDataSource);
MetaWaylandDataSource * meta_wayland_data_source_primary_legacy_new (struct wl_resource *resource);
#endif /* META_WAYLAND_DATA_SOURCE_PRIMARY_LEGACY_H */

View File

@ -0,0 +1,117 @@
/*
* Copyright © 2011 Kristian Høgsberg
* 2020 Red Hat Inc.
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that copyright
* notice and this permission notice appear in supporting documentation, and
* that the name of the copyright holders not be used in advertising or
* publicity pertaining to distribution of the software without specific,
* written prior permission. The copyright holders make no representations
* about the suitability of this software for any purpose. It is provided "as
* is" without express or implied warranty.
*
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
* OF THIS SOFTWARE.
*/
#include "config.h"
#include <unistd.h>
#include "primary-selection-unstable-v1-server-protocol.h"
#include "wayland/meta-wayland-data-source-primary.h"
typedef struct _MetaWaylandDataSourcePrimary
{
MetaWaylandDataSource parent;
} MetaWaylandDataSourcePrimary;
G_DEFINE_TYPE (MetaWaylandDataSourcePrimary, meta_wayland_data_source_primary,
META_TYPE_WAYLAND_DATA_SOURCE);
static void
primary_source_offer (struct wl_client *client,
struct wl_resource *resource,
const char *type)
{
MetaWaylandDataSource *source = wl_resource_get_user_data (resource);
if (!meta_wayland_data_source_add_mime_type (source, type))
wl_resource_post_no_memory (resource);
}
static void
primary_source_destroy (struct wl_client *client,
struct wl_resource *resource)
{
wl_resource_destroy (resource);
}
static struct zwp_primary_selection_source_v1_interface primary_source_interface = {
primary_source_offer,
primary_source_destroy,
};
static void
destroy_primary_source (struct wl_resource *resource)
{
MetaWaylandDataSource *source = wl_resource_get_user_data (resource);
meta_wayland_data_source_set_resource (source, NULL);
g_object_unref (source);
}
static void
meta_wayland_data_source_primary_send (MetaWaylandDataSource *source,
const gchar *mime_type,
gint fd)
{
struct wl_resource *resource = meta_wayland_data_source_get_resource (source);
zwp_primary_selection_source_v1_send_send (resource, mime_type, fd);
close (fd);
}
static void
meta_wayland_data_source_primary_cancel (MetaWaylandDataSource *source)
{
struct wl_resource *resource = meta_wayland_data_source_get_resource (source);
if (resource)
zwp_primary_selection_source_v1_send_cancelled (resource);
}
static void
meta_wayland_data_source_primary_init (MetaWaylandDataSourcePrimary *source_primary)
{
}
static void
meta_wayland_data_source_primary_class_init (MetaWaylandDataSourcePrimaryClass *klass)
{
MetaWaylandDataSourceClass *data_source_class =
META_WAYLAND_DATA_SOURCE_CLASS (klass);
data_source_class->send = meta_wayland_data_source_primary_send;
data_source_class->cancel = meta_wayland_data_source_primary_cancel;
}
MetaWaylandDataSource *
meta_wayland_data_source_primary_new (struct wl_resource *resource)
{
MetaWaylandDataSource *source_primary =
g_object_new (META_TYPE_WAYLAND_DATA_SOURCE_PRIMARY, NULL);
meta_wayland_data_source_set_resource (source_primary, resource);
wl_resource_set_implementation (resource, &primary_source_interface,
source_primary, destroy_primary_source);
return source_primary;
}

View File

@ -0,0 +1,37 @@
/*
* Copyright © 2011 Kristian Høgsberg
* 2020 Red Hat Inc.
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that copyright
* notice and this permission notice appear in supporting documentation, and
* that the name of the copyright holders not be used in advertising or
* publicity pertaining to distribution of the software without specific,
* written prior permission. The copyright holders make no representations
* about the suitability of this software for any purpose. It is provided "as
* is" without express or implied warranty.
*
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
* OF THIS SOFTWARE.
*/
#ifndef META_WAYLAND_DATA_SOURCE_PRIMARY_H
#define META_WAYLAND_DATA_SOURCE_PRIMARY_H
#include "meta-wayland-data-source.h"
#define META_TYPE_WAYLAND_DATA_SOURCE_PRIMARY (meta_wayland_data_source_primary_get_type ())
G_DECLARE_FINAL_TYPE (MetaWaylandDataSourcePrimary,
meta_wayland_data_source_primary,
META, WAYLAND_DATA_SOURCE_PRIMARY,
MetaWaylandDataSource);
MetaWaylandDataSource * meta_wayland_data_source_primary_new (struct wl_resource *resource);
#endif /* META_WAYLAND_DATA_SOURCE_PRIMARY_H */

View File

@ -0,0 +1,523 @@
/*
* Copyright © 2011 Kristian Høgsberg
* 2020 Red Hat Inc.
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that copyright
* notice and this permission notice appear in supporting documentation, and
* that the name of the copyright holders not be used in advertising or
* publicity pertaining to distribution of the software without specific,
* written prior permission. The copyright holders make no representations
* about the suitability of this software for any purpose. It is provided "as
* is" without express or implied warranty.
*
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
* OF THIS SOFTWARE.
*/
#include "config.h"
#include <unistd.h>
#include "wayland/meta-wayland-data-source.h"
#include "wayland/meta-wayland-private.h"
#define ALL_ACTIONS (WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY | \
WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE | \
WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK)
typedef struct _MetaWaylandDataSourcePrivate
{
struct wl_resource *resource;
MetaWaylandDataOffer *offer;
struct wl_array mime_types;
gboolean has_target;
uint32_t dnd_actions;
enum wl_data_device_manager_dnd_action user_dnd_action;
enum wl_data_device_manager_dnd_action current_dnd_action;
MetaWaylandSeat *seat;
guint actions_set : 1;
guint in_ask : 1;
guint drop_performed : 1;
} MetaWaylandDataSourcePrivate;
G_DEFINE_TYPE_WITH_PRIVATE (MetaWaylandDataSource, meta_wayland_data_source,
G_TYPE_OBJECT);
static void
meta_wayland_data_source_real_send (MetaWaylandDataSource *source,
const gchar *mime_type,
gint fd)
{
MetaWaylandDataSourcePrivate *priv =
meta_wayland_data_source_get_instance_private (source);
wl_data_source_send_send (priv->resource, mime_type, fd);
close (fd);
}
static void
meta_wayland_data_source_real_target (MetaWaylandDataSource *source,
const gchar *mime_type)
{
MetaWaylandDataSourcePrivate *priv =
meta_wayland_data_source_get_instance_private (source);
wl_data_source_send_target (priv->resource, mime_type);
}
static void
meta_wayland_data_source_real_cancel (MetaWaylandDataSource *source)
{
MetaWaylandDataSourcePrivate *priv =
meta_wayland_data_source_get_instance_private (source);
if (!priv->resource)
return;
wl_data_source_send_cancelled (priv->resource);
}
static void
meta_wayland_data_source_real_action (MetaWaylandDataSource *source,
enum wl_data_device_manager_dnd_action action)
{
MetaWaylandDataSourcePrivate *priv =
meta_wayland_data_source_get_instance_private (source);
if (wl_resource_get_version (priv->resource) >=
WL_DATA_SOURCE_ACTION_SINCE_VERSION)
wl_data_source_send_action (priv->resource, action);
}
static void
meta_wayland_data_source_real_drop_performed (MetaWaylandDataSource *source)
{
MetaWaylandDataSourcePrivate *priv =
meta_wayland_data_source_get_instance_private (source);
if (wl_resource_get_version (priv->resource) >=
WL_DATA_SOURCE_DND_DROP_PERFORMED_SINCE_VERSION)
{
priv->drop_performed = TRUE;
wl_data_source_send_dnd_drop_performed (priv->resource);
}
}
static void
meta_wayland_data_source_real_drag_finished (MetaWaylandDataSource *source)
{
MetaWaylandDataSourcePrivate *priv =
meta_wayland_data_source_get_instance_private (source);
enum wl_data_device_manager_dnd_action action;
if (meta_wayland_data_source_get_in_ask (source))
{
action = meta_wayland_data_source_get_current_action (source);
meta_wayland_data_source_real_action (source, action);
}
if (wl_resource_get_version (priv->resource) >=
WL_DATA_SOURCE_DND_FINISHED_SINCE_VERSION)
wl_data_source_send_dnd_finished (priv->resource);
}
static void
meta_wayland_data_source_finalize (GObject *object)
{
MetaWaylandDataSource *source = META_WAYLAND_DATA_SOURCE (object);
MetaWaylandDataSourcePrivate *priv =
meta_wayland_data_source_get_instance_private (source);
char **pos;
wl_array_for_each (pos, &priv->mime_types)
g_free (*pos);
wl_array_release (&priv->mime_types);
G_OBJECT_CLASS (meta_wayland_data_source_parent_class)->finalize (object);
}
static void
meta_wayland_data_source_init (MetaWaylandDataSource *source)
{
MetaWaylandDataSourcePrivate *priv =
meta_wayland_data_source_get_instance_private (source);
wl_array_init (&priv->mime_types);
priv->current_dnd_action = -1;
priv->drop_performed = FALSE;
}
static void
meta_wayland_data_source_class_init (MetaWaylandDataSourceClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->finalize = meta_wayland_data_source_finalize;
klass->send = meta_wayland_data_source_real_send;
klass->target = meta_wayland_data_source_real_target;
klass->cancel = meta_wayland_data_source_real_cancel;
klass->action = meta_wayland_data_source_real_action;
klass->drop_performed = meta_wayland_data_source_real_drop_performed;
klass->drag_finished = meta_wayland_data_source_real_drag_finished;
}
static void
data_source_offer (struct wl_client *client,
struct wl_resource *resource, const char *type)
{
MetaWaylandDataSource *source = wl_resource_get_user_data (resource);
if (!meta_wayland_data_source_add_mime_type (source, type))
wl_resource_post_no_memory (resource);
}
static void
data_source_destroy (struct wl_client *client,
struct wl_resource *resource)
{
wl_resource_destroy (resource);
}
static void
data_source_set_actions (struct wl_client *client,
struct wl_resource *resource,
uint32_t dnd_actions)
{
MetaWaylandDataSource *source = wl_resource_get_user_data (resource);
MetaWaylandDataSourcePrivate *priv =
meta_wayland_data_source_get_instance_private (source);
if (priv->actions_set)
{
wl_resource_post_error (priv->resource,
WL_DATA_SOURCE_ERROR_INVALID_ACTION_MASK,
"cannot set actions more than once");
return;
}
if (dnd_actions & ~(ALL_ACTIONS))
{
wl_resource_post_error (priv->resource,
WL_DATA_SOURCE_ERROR_INVALID_ACTION_MASK,
"invalid actions mask %x", dnd_actions);
return;
}
if (meta_wayland_data_source_get_seat (source))
{
wl_resource_post_error (priv->resource,
WL_DATA_SOURCE_ERROR_INVALID_ACTION_MASK,
"invalid action change after "
"wl_data_device.start_drag");
return;
}
meta_wayland_data_source_set_actions (source, dnd_actions);
}
static struct wl_data_source_interface data_source_interface = {
data_source_offer,
data_source_destroy,
data_source_set_actions
};
static void
destroy_data_source (struct wl_resource *resource)
{
MetaWaylandDataSource *source = wl_resource_get_user_data (resource);
meta_wayland_data_source_set_resource (source, NULL);
g_object_unref (source);
}
MetaWaylandDataSource *
meta_wayland_data_source_new (struct wl_resource *resource)
{
MetaWaylandDataSource *source =
g_object_new (META_TYPE_WAYLAND_DATA_SOURCE, NULL);
MetaWaylandDataSourcePrivate *priv =
meta_wayland_data_source_get_instance_private (source);
meta_wayland_data_source_set_resource (source, resource);
wl_resource_set_implementation (resource, &data_source_interface,
source, destroy_data_source);
if (wl_resource_get_version (resource) < WL_DATA_SOURCE_ACTION_SINCE_VERSION)
{
priv->dnd_actions = priv->user_dnd_action =
WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY;
}
return source;
}
struct wl_resource *
meta_wayland_data_source_get_resource (MetaWaylandDataSource *source)
{
MetaWaylandDataSourcePrivate *priv =
meta_wayland_data_source_get_instance_private (source);
return priv->resource;
}
void
meta_wayland_data_source_set_resource (MetaWaylandDataSource *source,
struct wl_resource *resource)
{
MetaWaylandDataSourcePrivate *priv =
meta_wayland_data_source_get_instance_private (source);
priv->resource = resource;
}
gboolean
meta_wayland_data_source_get_in_ask (MetaWaylandDataSource *source)
{
MetaWaylandDataSourcePrivate *priv =
meta_wayland_data_source_get_instance_private (source);
return priv->in_ask;
}
void
meta_wayland_data_source_update_in_ask (MetaWaylandDataSource *source)
{
MetaWaylandDataSourcePrivate *priv =
meta_wayland_data_source_get_instance_private (source);
priv->in_ask =
priv->current_dnd_action == WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK;
}
void
meta_wayland_data_source_target (MetaWaylandDataSource *source,
const char *mime_type)
{
if (META_WAYLAND_DATA_SOURCE_GET_CLASS (source)->target)
META_WAYLAND_DATA_SOURCE_GET_CLASS (source)->target (source, mime_type);
}
void
meta_wayland_data_source_send (MetaWaylandDataSource *source,
const char *mime_type,
int fd)
{
META_WAYLAND_DATA_SOURCE_GET_CLASS (source)->send (source, mime_type, fd);
}
gboolean
meta_wayland_data_source_has_target (MetaWaylandDataSource *source)
{
MetaWaylandDataSourcePrivate *priv =
meta_wayland_data_source_get_instance_private (source);
return priv->has_target;
}
void
meta_wayland_data_source_set_seat (MetaWaylandDataSource *source,
MetaWaylandSeat *seat)
{
MetaWaylandDataSourcePrivate *priv =
meta_wayland_data_source_get_instance_private (source);
priv->seat = seat;
}
MetaWaylandSeat *
meta_wayland_data_source_get_seat (MetaWaylandDataSource *source)
{
MetaWaylandDataSourcePrivate *priv =
meta_wayland_data_source_get_instance_private (source);
return priv->seat;
}
void
meta_wayland_data_source_set_has_target (MetaWaylandDataSource *source,
gboolean has_target)
{
MetaWaylandDataSourcePrivate *priv =
meta_wayland_data_source_get_instance_private (source);
priv->has_target = has_target;
}
struct wl_array *
meta_wayland_data_source_get_mime_types (MetaWaylandDataSource *source)
{
MetaWaylandDataSourcePrivate *priv =
meta_wayland_data_source_get_instance_private ((MetaWaylandDataSource *)source);
return &priv->mime_types;
}
void
meta_wayland_data_source_cancel (MetaWaylandDataSource *source)
{
META_WAYLAND_DATA_SOURCE_GET_CLASS (source)->cancel (source);
}
gboolean
meta_wayland_data_source_get_actions (MetaWaylandDataSource *source,
uint32_t *dnd_actions)
{
MetaWaylandDataSourcePrivate *priv =
meta_wayland_data_source_get_instance_private (source);
if (dnd_actions)
*dnd_actions = priv->dnd_actions;
return priv->actions_set;
}
enum wl_data_device_manager_dnd_action
meta_wayland_data_source_get_user_action (MetaWaylandDataSource *source)
{
MetaWaylandDataSourcePrivate *priv =
meta_wayland_data_source_get_instance_private (source);
if (!priv->seat)
return WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE;
return priv->user_dnd_action;
}
enum wl_data_device_manager_dnd_action
meta_wayland_data_source_get_current_action (MetaWaylandDataSource *source)
{
MetaWaylandDataSourcePrivate *priv =
meta_wayland_data_source_get_instance_private (source);
return priv->current_dnd_action;
}
void
meta_wayland_data_source_set_current_offer (MetaWaylandDataSource *source,
MetaWaylandDataOffer *offer)
{
MetaWaylandDataSourcePrivate *priv =
meta_wayland_data_source_get_instance_private (source);
priv->offer = offer;
}
MetaWaylandDataOffer *
meta_wayland_data_source_get_current_offer (MetaWaylandDataSource *source)
{
MetaWaylandDataSourcePrivate *priv =
meta_wayland_data_source_get_instance_private (source);
return priv->offer;
}
void
meta_wayland_data_source_set_current_action (MetaWaylandDataSource *source,
enum wl_data_device_manager_dnd_action action)
{
MetaWaylandDataSourcePrivate *priv =
meta_wayland_data_source_get_instance_private (source);
if (priv->current_dnd_action == action)
return;
priv->current_dnd_action = action;
if (!meta_wayland_data_source_get_in_ask (source))
META_WAYLAND_DATA_SOURCE_GET_CLASS (source)->action (source, action);
}
void
meta_wayland_data_source_set_actions (MetaWaylandDataSource *source,
uint32_t dnd_actions)
{
MetaWaylandDataSourcePrivate *priv =
meta_wayland_data_source_get_instance_private (source);
priv->dnd_actions = dnd_actions;
priv->actions_set = TRUE;
}
void
meta_wayland_data_source_set_user_action (MetaWaylandDataSource *source,
uint32_t action)
{
MetaWaylandDataSourcePrivate *priv =
meta_wayland_data_source_get_instance_private (source);
MetaWaylandDataOffer *offer;
if (priv->user_dnd_action == action)
return;
priv->user_dnd_action = action;
offer = meta_wayland_data_source_get_current_offer (source);
if (offer)
meta_wayland_data_offer_update_action (offer);
}
gboolean
meta_wayland_data_source_get_drop_performed (MetaWaylandDataSource *source)
{
MetaWaylandDataSourcePrivate *priv =
meta_wayland_data_source_get_instance_private (source);
return priv->drop_performed;
}
void
meta_wayland_data_source_notify_drop_performed (MetaWaylandDataSource *source)
{
META_WAYLAND_DATA_SOURCE_GET_CLASS (source)->drop_performed (source);
}
void
meta_wayland_data_source_notify_finish (MetaWaylandDataSource *source)
{
META_WAYLAND_DATA_SOURCE_GET_CLASS (source)->drag_finished (source);
}
gboolean
meta_wayland_data_source_add_mime_type (MetaWaylandDataSource *source,
const char *mime_type)
{
MetaWaylandDataSourcePrivate *priv =
meta_wayland_data_source_get_instance_private (source);
char **pos;
pos = wl_array_add (&priv->mime_types, sizeof (*pos));
if (pos)
{
*pos = g_strdup (mime_type);
return *pos != NULL;
}
return FALSE;
}
gboolean
meta_wayland_data_source_has_mime_type (MetaWaylandDataSource *source,
const char *mime_type)
{
MetaWaylandDataSourcePrivate *priv =
meta_wayland_data_source_get_instance_private (source);
char **p;
wl_array_for_each (p, &priv->mime_types)
{
if (g_strcmp0 (mime_type, *p) == 0)
return TRUE;
}
return FALSE;
}

View File

@ -0,0 +1,112 @@
/*
* Copyright © 2011 Kristian Høgsberg
* 2020 Red Hat Inc.
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that copyright
* notice and this permission notice appear in supporting documentation, and
* that the name of the copyright holders not be used in advertising or
* publicity pertaining to distribution of the software without specific,
* written prior permission. The copyright holders make no representations
* about the suitability of this software for any purpose. It is provided "as
* is" without express or implied warranty.
*
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
* OF THIS SOFTWARE.
*/
#ifndef META_WAYLAND_DATA_SOURCE_H
#define META_WAYLAND_DATA_SOURCE_H
#include <glib-object.h>
#include <wayland-server.h>
#include "wayland/meta-wayland-types.h"
#define META_TYPE_WAYLAND_DATA_SOURCE (meta_wayland_data_source_get_type ())
G_DECLARE_DERIVABLE_TYPE (MetaWaylandDataSource,
meta_wayland_data_source,
META, WAYLAND_DATA_SOURCE,
GObject)
typedef struct _MetaWaylandDataSourceClass MetaWaylandDataSourceClass;
struct _MetaWaylandDataSourceClass
{
GObjectClass parent_class;
void (* send) (MetaWaylandDataSource *source,
const gchar *mime_type,
gint fd);
void (* target) (MetaWaylandDataSource *source,
const gchar *mime_type);
void (* cancel) (MetaWaylandDataSource *source);
void (* action) (MetaWaylandDataSource *source,
uint32_t action);
void (* drop_performed) (MetaWaylandDataSource *source);
void (* drag_finished) (MetaWaylandDataSource *source);
};
MetaWaylandDataSource * meta_wayland_data_source_new (struct wl_resource *resource);
struct wl_resource * meta_wayland_data_source_get_resource (MetaWaylandDataSource *source);
void meta_wayland_data_source_set_resource (MetaWaylandDataSource *source,
struct wl_resource *resource);
gboolean meta_wayland_data_source_get_in_ask (MetaWaylandDataSource *source);
void meta_wayland_data_source_update_in_ask (MetaWaylandDataSource *source);
void meta_wayland_data_source_target (MetaWaylandDataSource *source,
const char *mime_type);
void meta_wayland_data_source_send (MetaWaylandDataSource *source,
const char *mime_type,
int fd);
void meta_wayland_data_source_cancel (MetaWaylandDataSource *source);
gboolean meta_wayland_data_source_has_target (MetaWaylandDataSource *source);
void meta_wayland_data_source_set_seat (MetaWaylandDataSource *source,
MetaWaylandSeat *seat);
MetaWaylandSeat * meta_wayland_data_source_get_seat (MetaWaylandDataSource *source);
void meta_wayland_data_source_set_has_target (MetaWaylandDataSource *source,
gboolean has_target);
struct wl_array * meta_wayland_data_source_get_mime_types (MetaWaylandDataSource *source);
gboolean meta_wayland_data_source_add_mime_type (MetaWaylandDataSource *source,
const gchar *mime_type);
gboolean meta_wayland_data_source_has_mime_type (MetaWaylandDataSource *source,
const char *mime_type);
gboolean meta_wayland_data_source_get_actions (MetaWaylandDataSource *source,
uint32_t *dnd_actions);
void meta_wayland_data_source_set_actions (MetaWaylandDataSource *source,
uint32_t dnd_actions);
enum wl_data_device_manager_dnd_action
meta_wayland_data_source_get_current_action (MetaWaylandDataSource *source);
void meta_wayland_data_source_set_current_action (MetaWaylandDataSource *source,
enum wl_data_device_manager_dnd_action action);
enum wl_data_device_manager_dnd_action
meta_wayland_data_source_get_user_action (MetaWaylandDataSource *source);
void meta_wayland_data_source_set_user_action (MetaWaylandDataSource *source,
uint32_t action);
MetaWaylandDataOffer *
meta_wayland_data_source_get_current_offer (MetaWaylandDataSource *source);
void meta_wayland_data_source_set_current_offer (MetaWaylandDataSource *source,
MetaWaylandDataOffer *offer);
gboolean meta_wayland_data_source_get_drop_performed (MetaWaylandDataSource *source);
void meta_wayland_data_source_notify_drop_performed (MetaWaylandDataSource *source);
void meta_wayland_data_source_notify_finish (MetaWaylandDataSource *source);
#endif /* META_WAYLAND_DATA_SOURCE_H */

View File

@ -603,7 +603,6 @@ meta_wayland_keyboard_disable (MetaWaylandKeyboard *keyboard)
meta_wayland_keyboard_end_grab (keyboard);
meta_wayland_keyboard_set_focus (keyboard, NULL);
meta_wayland_xkb_info_destroy (&keyboard->xkb_info);
wl_list_remove (&keyboard->resource_list);
wl_list_init (&keyboard->resource_list);
@ -917,7 +916,18 @@ meta_wayland_keyboard_init (MetaWaylandKeyboard *keyboard)
keyboard_handle_focus_surface_destroy;
}
static void
meta_wayland_keyboard_finalize (GObject *object)
{
MetaWaylandKeyboard *keyboard = META_WAYLAND_KEYBOARD (object);
meta_wayland_xkb_info_destroy (&keyboard->xkb_info);
}
static void
meta_wayland_keyboard_class_init (MetaWaylandKeyboardClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->finalize = meta_wayland_keyboard_finalize;
}

View File

@ -662,8 +662,6 @@ meta_wayland_zxdg_toplevel_v6_apply_state (MetaWaylandSurfaceRole *surface_role
MetaWaylandSurface *surface =
meta_wayland_surface_role_get_surface (surface_role);
MetaWindow *window;
MetaRectangle old_geometry;
gboolean geometry_changed;
window = meta_wayland_surface_get_window (surface);
if (!window)
@ -672,8 +670,6 @@ meta_wayland_zxdg_toplevel_v6_apply_state (MetaWaylandSurfaceRole *surface_role
return;
}
old_geometry = xdg_surface_priv->geometry;
surface_role_class =
META_WAYLAND_SURFACE_ROLE_CLASS (meta_wayland_zxdg_toplevel_v6_parent_class);
surface_role_class->apply_state (surface_role, pending);
@ -688,13 +684,37 @@ meta_wayland_zxdg_toplevel_v6_apply_state (MetaWaylandSurfaceRole *surface_role
meta_wayland_window_configuration_free (configuration);
return;
}
}
static void
meta_wayland_zxdg_toplevel_v6_post_apply_state (MetaWaylandSurfaceRole *surface_role,
MetaWaylandSurfaceState *pending)
{
MetaWaylandZxdgToplevelV6 *xdg_toplevel =
META_WAYLAND_ZXDG_TOPLEVEL_V6 (surface_role);
MetaWaylandZxdgSurfaceV6 *xdg_surface =
META_WAYLAND_ZXDG_SURFACE_V6 (xdg_toplevel);
MetaWaylandZxdgSurfaceV6Private *xdg_surface_priv =
meta_wayland_zxdg_surface_v6_get_instance_private (xdg_surface);
MetaWaylandSurfaceRoleClass *surface_role_class;
MetaWaylandSurface *surface =
meta_wayland_surface_role_get_surface (surface_role);
MetaWindow *window;
MetaRectangle old_geometry;
gboolean geometry_changed;
window = meta_wayland_surface_get_window (surface);
if (!window)
return;
if (!pending->newly_attached)
return;
/* If the window disappeared the surface is not coming back. */
if (!window)
return;
old_geometry = xdg_surface_priv->geometry;
surface_role_class =
META_WAYLAND_SURFACE_ROLE_CLASS (meta_wayland_zxdg_toplevel_v6_parent_class);
surface_role_class->post_apply_state (surface_role, pending);
geometry_changed = !meta_rectangle_equal (&old_geometry, &xdg_surface_priv->geometry);
@ -734,7 +754,6 @@ meta_wayland_zxdg_toplevel_v6_apply_state (MetaWaylandSurfaceRole *surface_role
wl_resource_post_error (surface->resource,
ZXDG_SHELL_V6_ERROR_INVALID_SURFACE_STATE,
"Invalid min/max size");
}
}
}
@ -832,6 +851,8 @@ meta_wayland_zxdg_toplevel_v6_class_init (MetaWaylandZxdgToplevelV6Class *klass)
surface_role_class = META_WAYLAND_SURFACE_ROLE_CLASS (klass);
surface_role_class->apply_state = meta_wayland_zxdg_toplevel_v6_apply_state;
surface_role_class->post_apply_state =
meta_wayland_zxdg_toplevel_v6_post_apply_state;
surface_role_class->get_toplevel = meta_wayland_zxdg_toplevel_v6_get_toplevel;
shell_surface_class = META_WAYLAND_SHELL_SURFACE_CLASS (klass);
@ -964,12 +985,7 @@ meta_wayland_zxdg_popup_v6_apply_state (MetaWaylandSurfaceRole *surface_role,
MetaWaylandSurfaceState *pending)
{
MetaWaylandZxdgPopupV6 *xdg_popup = META_WAYLAND_ZXDG_POPUP_V6 (surface_role);
MetaWaylandZxdgSurfaceV6 *xdg_surface =
META_WAYLAND_ZXDG_SURFACE_V6 (surface_role);
MetaWaylandSurfaceRoleClass *surface_role_class;
MetaWaylandSurface *surface =
meta_wayland_surface_role_get_surface (surface_role);
MetaWindow *window;
if (xdg_popup->setup.parent_surface)
finish_popup_setup (xdg_popup);
@ -977,12 +993,27 @@ meta_wayland_zxdg_popup_v6_apply_state (MetaWaylandSurfaceRole *surface_role,
surface_role_class =
META_WAYLAND_SURFACE_ROLE_CLASS (meta_wayland_zxdg_popup_v6_parent_class);
surface_role_class->apply_state (surface_role, pending);
}
static void
meta_wayland_zxdg_popup_v6_post_apply_state (MetaWaylandSurfaceRole *surface_role,
MetaWaylandSurfaceState *pending)
{
MetaWaylandZxdgSurfaceV6 *xdg_surface =
META_WAYLAND_ZXDG_SURFACE_V6 (surface_role);
MetaWaylandSurfaceRoleClass *surface_role_class;
MetaWaylandSurface *surface =
meta_wayland_surface_role_get_surface (surface_role);
MetaWindow *window;
/* If the window disappeared the surface is not coming back. */
window = meta_wayland_surface_get_window (surface);
if (!window)
return;
surface_role_class =
META_WAYLAND_SURFACE_ROLE_CLASS (meta_wayland_zxdg_popup_v6_parent_class);
surface_role_class->post_apply_state (surface_role, pending);
if (!pending->newly_attached)
return;
@ -1165,6 +1196,8 @@ meta_wayland_zxdg_popup_v6_class_init (MetaWaylandZxdgPopupV6Class *klass)
surface_role_class = META_WAYLAND_SURFACE_ROLE_CLASS (klass);
surface_role_class->apply_state = meta_wayland_zxdg_popup_v6_apply_state;
surface_role_class->post_apply_state =
meta_wayland_zxdg_popup_v6_post_apply_state;
surface_role_class->get_toplevel = meta_wayland_zxdg_popup_v6_get_toplevel;
shell_surface_class = META_WAYLAND_SHELL_SURFACE_CLASS (klass);
@ -1331,8 +1364,6 @@ meta_wayland_zxdg_surface_v6_apply_state (MetaWaylandSurfaceRole *surface_role,
{
MetaWaylandZxdgSurfaceV6 *xdg_surface =
META_WAYLAND_ZXDG_SURFACE_V6 (surface_role);
MetaWaylandShellSurface *shell_surface =
META_WAYLAND_SHELL_SURFACE (xdg_surface);
MetaWaylandZxdgSurfaceV6Private *priv =
meta_wayland_zxdg_surface_v6_get_instance_private (xdg_surface);
MetaWaylandSurface *surface =
@ -1370,8 +1401,18 @@ meta_wayland_zxdg_surface_v6_apply_state (MetaWaylandSurfaceRole *surface_role,
if (surface->buffer_ref.buffer)
priv->first_buffer_attached = TRUE;
else
return;
}
static void
meta_wayland_zxdg_surface_v6_post_apply_state (MetaWaylandSurfaceRole *surface_role,
MetaWaylandSurfaceState *pending)
{
MetaWaylandZxdgSurfaceV6 *xdg_surface =
META_WAYLAND_ZXDG_SURFACE_V6 (surface_role);
MetaWaylandZxdgSurfaceV6Private *priv =
meta_wayland_zxdg_surface_v6_get_instance_private (xdg_surface);
MetaWaylandShellSurface *shell_surface =
META_WAYLAND_SHELL_SURFACE (xdg_surface);
if (pending->has_new_geometry)
{
@ -1526,6 +1567,8 @@ meta_wayland_zxdg_surface_v6_class_init (MetaWaylandZxdgSurfaceV6Class *klass)
surface_role_class = META_WAYLAND_SURFACE_ROLE_CLASS (klass);
surface_role_class->apply_state = meta_wayland_zxdg_surface_v6_apply_state;
surface_role_class->post_apply_state =
meta_wayland_zxdg_surface_v6_post_apply_state;
surface_role_class->assigned = meta_wayland_zxdg_surface_v6_assigned;
shell_surface_class = META_WAYLAND_SHELL_SURFACE_CLASS (klass);

View File

@ -24,6 +24,7 @@
#include "wayland/meta-wayland-seat.h"
#include "wayland/meta-wayland-data-device.h"
#include "wayland/meta-wayland-data-device-primary-legacy.h"
#include "wayland/meta-wayland-private.h"
#include "wayland/meta-wayland-tablet-seat.h"
#include "wayland/meta-wayland-versions.h"
@ -231,6 +232,8 @@ meta_wayland_seat_new (MetaWaylandCompositor *compositor,
seat->gtk_text_input = meta_wayland_gtk_text_input_new (seat);
meta_wayland_data_device_init (&seat->data_device);
meta_wayland_data_device_primary_init (&seat->primary_data_device);
meta_wayland_data_device_primary_legacy_init (&seat->primary_legacy_data_device);
clutter_seat = clutter_backend_get_default_seat (clutter_get_default_backend ());
meta_wayland_seat_update_capabilities (seat, clutter_seat);
@ -431,6 +434,8 @@ meta_wayland_seat_set_input_focus (MetaWaylandSeat *seat,
{
meta_wayland_keyboard_set_focus (seat->keyboard, surface);
meta_wayland_data_device_set_keyboard_focus (&seat->data_device);
meta_wayland_data_device_primary_set_keyboard_focus (&seat->primary_data_device);
meta_wayland_data_device_primary_legacy_set_keyboard_focus (&seat->primary_legacy_data_device);
}
tablet_seat = meta_wayland_tablet_manager_ensure_seat (compositor->tablet_manager, seat);

View File

@ -26,6 +26,8 @@
#include "clutter/clutter.h"
#include "wayland/meta-wayland-data-device.h"
#include "wayland/meta-wayland-data-device-primary.h"
#include "wayland/meta-wayland-data-device-primary-legacy.h"
#include "wayland/meta-wayland-input-device.h"
#include "wayland/meta-wayland-keyboard.h"
#include "wayland/meta-wayland-pointer.h"
@ -45,6 +47,8 @@ struct _MetaWaylandSeat
MetaWaylandTouch *touch;
MetaWaylandDataDevice data_device;
MetaWaylandDataDevicePrimary primary_data_device;
MetaWaylandDataDevicePrimaryLegacy primary_legacy_data_device;
MetaWaylandGtkTextInput *gtk_text_input;
MetaWaylandTextInput *text_input;

View File

@ -275,7 +275,8 @@ meta_wayland_subsurface_notify_subsurface_state_changed (MetaWaylandSurfaceRole
meta_wayland_surface_role_get_surface (surface_role);
MetaWaylandSurface *parent = surface->sub.parent;
return meta_wayland_surface_notify_subsurface_state_changed (parent);
if (parent)
return meta_wayland_surface_notify_subsurface_state_changed (parent);
}
static double

View File

@ -113,6 +113,10 @@ static void
meta_wayland_surface_role_apply_state (MetaWaylandSurfaceRole *surface_role,
MetaWaylandSurfaceState *pending);
static void
meta_wayland_surface_role_post_apply_state (MetaWaylandSurfaceRole *surface_role,
MetaWaylandSurfaceState *pending);
static gboolean
meta_wayland_surface_role_is_on_logical_monitor (MetaWaylandSurfaceRole *surface_role,
MetaLogicalMonitor *logical_monitor);
@ -757,8 +761,6 @@ cleanup:
surface_state_signals[SURFACE_STATE_SIGNAL_APPLIED],
0);
meta_wayland_surface_state_reset (state);
META_WAYLAND_SURFACE_FOREACH_SUBSURFACE (surface, subsurface_surface)
{
MetaWaylandSubsurface *subsurface;
@ -782,6 +784,11 @@ cleanup:
meta_window_actor_notify_damaged (toplevel_window_actor);
}
}
if (surface->role)
meta_wayland_surface_role_post_apply_state (surface->role, state);
meta_wayland_surface_state_reset (state);
}
void
@ -1696,6 +1703,17 @@ meta_wayland_surface_role_pre_apply_state (MetaWaylandSurfaceRole *surface_role
klass->pre_apply_state (surface_role, pending);
}
static void
meta_wayland_surface_role_post_apply_state (MetaWaylandSurfaceRole *surface_role,
MetaWaylandSurfaceState *pending)
{
MetaWaylandSurfaceRoleClass *klass;
klass = META_WAYLAND_SURFACE_ROLE_GET_CLASS (surface_role);
if (klass->post_apply_state)
klass->post_apply_state (surface_role, pending);
}
static void
meta_wayland_surface_role_apply_state (MetaWaylandSurfaceRole *surface_role,
MetaWaylandSurfaceState *pending)

View File

@ -58,6 +58,8 @@ struct _MetaWaylandSurfaceRoleClass
MetaWaylandSurfaceState *pending);
void (*apply_state) (MetaWaylandSurfaceRole *surface_role,
MetaWaylandSurfaceState *pending);
void (*post_apply_state) (MetaWaylandSurfaceRole *surface_role,
MetaWaylandSurfaceState *pending);
gboolean (*is_on_logical_monitor) (MetaWaylandSurfaceRole *surface_role,
MetaLogicalMonitor *logical_monitor);
MetaWaylandSurface * (*get_toplevel) (MetaWaylandSurfaceRole *surface_role);

View File

@ -37,6 +37,8 @@ typedef struct _MetaWaylandTouch MetaWaylandTouch;
typedef struct _MetaWaylandDragDestFuncs MetaWaylandDragDestFuncs;
typedef struct _MetaWaylandDataOffer MetaWaylandDataOffer;
typedef struct _MetaWaylandDataDevice MetaWaylandDataDevice;
typedef struct _MetaWaylandDataDevicePrimary MetaWaylandDataDevicePrimary;
typedef struct _MetaWaylandDataDevicePrimaryLegacy MetaWaylandDataDevicePrimaryLegacy;
typedef struct _MetaWaylandTabletManager MetaWaylandTabletManager;
typedef struct _MetaWaylandTabletSeat MetaWaylandTabletSeat;

View File

@ -744,8 +744,6 @@ meta_wayland_xdg_toplevel_apply_state (MetaWaylandSurfaceRole *surface_role,
MetaWaylandSurface *surface =
meta_wayland_surface_role_get_surface (surface_role);
MetaWindow *window;
MetaRectangle old_geometry;
gboolean geometry_changed;
window = meta_wayland_surface_get_window (surface);
if (!window)
@ -765,8 +763,6 @@ meta_wayland_xdg_toplevel_apply_state (MetaWaylandSurfaceRole *surface_role,
return;
}
old_geometry = xdg_surface_priv->geometry;
surface_role_class =
META_WAYLAND_SURFACE_ROLE_CLASS (meta_wayland_xdg_toplevel_parent_class);
surface_role_class->apply_state (surface_role, pending);
@ -780,17 +776,42 @@ meta_wayland_xdg_toplevel_apply_state (MetaWaylandSurfaceRole *surface_role,
meta_wayland_window_configuration_free (configuration);
return;
}
}
static void
meta_wayland_xdg_toplevel_post_apply_state (MetaWaylandSurfaceRole *surface_role,
MetaWaylandSurfaceState *pending)
{
MetaWaylandXdgSurface *xdg_surface = META_WAYLAND_XDG_SURFACE (surface_role);
MetaWaylandXdgSurfacePrivate *xdg_surface_priv =
meta_wayland_xdg_surface_get_instance_private (xdg_surface);
MetaWaylandSurface *surface =
meta_wayland_surface_role_get_surface (surface_role);
MetaWaylandSurfaceRoleClass *surface_role_class;
MetaWindow *window;
MetaRectangle old_geometry;
MetaRectangle window_geometry;
gboolean geometry_changed;
window = meta_wayland_surface_get_window (surface);
if (!window)
return;
old_geometry = xdg_surface_priv->geometry;
surface_role_class =
META_WAYLAND_SURFACE_ROLE_CLASS (meta_wayland_xdg_toplevel_parent_class);
surface_role_class->post_apply_state (surface_role, pending);
if (!pending->newly_attached)
return;
geometry_changed = !meta_rectangle_equal (&old_geometry, &xdg_surface_priv->geometry);
window_geometry = meta_wayland_xdg_surface_get_window_geometry (xdg_surface);
geometry_changed = !meta_rectangle_equal (&old_geometry, &window_geometry);
if (geometry_changed || pending->has_acked_configure_serial)
{
MetaRectangle window_geometry;
window_geometry = meta_wayland_xdg_surface_get_window_geometry (xdg_surface);
meta_window_wayland_finish_move_resize (window, window_geometry, pending);
}
else if (pending->dx != 0 || pending->dy != 0)
@ -821,7 +842,6 @@ meta_wayland_xdg_toplevel_apply_state (MetaWaylandSurfaceRole *surface_role,
wl_resource_post_error (surface->resource,
XDG_WM_BASE_ERROR_INVALID_SURFACE_STATE,
"Invalid min/max size");
}
}
}
@ -940,6 +960,7 @@ meta_wayland_xdg_toplevel_class_init (MetaWaylandXdgToplevelClass *klass)
surface_role_class = META_WAYLAND_SURFACE_ROLE_CLASS (klass);
surface_role_class->apply_state = meta_wayland_xdg_toplevel_apply_state;
surface_role_class->post_apply_state = meta_wayland_xdg_toplevel_post_apply_state;
surface_role_class->get_toplevel = meta_wayland_xdg_toplevel_get_toplevel;
shell_surface_class = META_WAYLAND_SHELL_SURFACE_CLASS (klass);
@ -1092,10 +1113,6 @@ meta_wayland_xdg_popup_apply_state (MetaWaylandSurfaceRole *surface_role,
MetaWaylandSurfaceRoleClass *surface_role_class;
MetaWaylandSurface *surface =
meta_wayland_surface_role_get_surface (surface_role);
MetaWindow *window;
MetaRectangle buffer_rect;
MetaWindow *parent_window;
MetaRectangle parent_buffer_rect;
if (xdg_popup->setup.parent_surface)
finish_popup_setup (xdg_popup);
@ -1118,8 +1135,23 @@ meta_wayland_xdg_popup_apply_state (MetaWaylandSurfaceRole *surface_role,
"Can't commit buffer to dismissed popup");
return;
}
}
static void
meta_wayland_xdg_popup_post_apply_state (MetaWaylandSurfaceRole *surface_role,
MetaWaylandSurfaceState *pending)
{
MetaWaylandXdgPopup *xdg_popup = META_WAYLAND_XDG_POPUP (surface_role);
MetaWaylandXdgSurface *xdg_surface = META_WAYLAND_XDG_SURFACE (surface_role);
MetaWaylandSurface *surface =
meta_wayland_surface_role_get_surface (surface_role);
MetaWaylandSurfaceRoleClass *surface_role_class =
META_WAYLAND_SURFACE_ROLE_CLASS (meta_wayland_xdg_popup_parent_class);
MetaWindow *window;
MetaWindow *parent_window;
MetaRectangle buffer_rect;
MetaRectangle parent_buffer_rect;
/* If the window disappeared the surface is not coming back. */
window = meta_wayland_surface_get_window (surface);
if (!window)
return;
@ -1130,6 +1162,8 @@ meta_wayland_xdg_popup_apply_state (MetaWaylandSurfaceRole *surface_role,
if (!surface->buffer_ref.buffer)
return;
surface_role_class->post_apply_state (surface_role, pending);
if (pending->has_acked_configure_serial)
{
MetaRectangle window_geometry;
@ -1326,6 +1360,7 @@ meta_wayland_xdg_popup_class_init (MetaWaylandXdgPopupClass *klass)
surface_role_class = META_WAYLAND_SURFACE_ROLE_CLASS (klass);
surface_role_class->apply_state = meta_wayland_xdg_popup_apply_state;
surface_role_class->post_apply_state = meta_wayland_xdg_popup_post_apply_state;
surface_role_class->get_toplevel = meta_wayland_xdg_popup_get_toplevel;
shell_surface_class = META_WAYLAND_SHELL_SURFACE_CLASS (klass);
@ -1504,8 +1539,6 @@ meta_wayland_xdg_surface_apply_state (MetaWaylandSurfaceRole *surface_role,
MetaWaylandSurfaceState *pending)
{
MetaWaylandXdgSurface *xdg_surface = META_WAYLAND_XDG_SURFACE (surface_role);
MetaWaylandShellSurface *shell_surface =
META_WAYLAND_SHELL_SURFACE (xdg_surface);
MetaWaylandXdgSurfacePrivate *priv =
meta_wayland_xdg_surface_get_instance_private (xdg_surface);
MetaWaylandSurface *surface =
@ -1526,8 +1559,17 @@ meta_wayland_xdg_surface_apply_state (MetaWaylandSurfaceRole *surface_role,
if (surface->buffer_ref.buffer)
priv->first_buffer_attached = TRUE;
else
return;
}
static void
meta_wayland_xdg_surface_post_apply_state (MetaWaylandSurfaceRole *surface_role,
MetaWaylandSurfaceState *pending)
{
MetaWaylandXdgSurface *xdg_surface = META_WAYLAND_XDG_SURFACE (surface_role);
MetaWaylandXdgSurfacePrivate *priv =
meta_wayland_xdg_surface_get_instance_private (xdg_surface);
MetaWaylandShellSurface *shell_surface =
META_WAYLAND_SHELL_SURFACE (surface_role);
if (pending->has_new_geometry)
{
@ -1680,6 +1722,7 @@ meta_wayland_xdg_surface_class_init (MetaWaylandXdgSurfaceClass *klass)
surface_role_class = META_WAYLAND_SURFACE_ROLE_CLASS (klass);
surface_role_class->apply_state = meta_wayland_xdg_surface_apply_state;
surface_role_class->post_apply_state = meta_wayland_xdg_surface_post_apply_state;
surface_role_class->assigned = meta_wayland_xdg_surface_assigned;
shell_surface_class = META_WAYLAND_SHELL_SURFACE_CLASS (klass);

View File

@ -395,6 +395,8 @@ meta_wayland_init (void)
meta_wayland_outputs_init (compositor);
meta_wayland_data_device_manager_init (compositor);
meta_wayland_data_device_primary_manager_init (compositor);
meta_wayland_data_device_primary_legacy_manager_init (compositor);
meta_wayland_subsurfaces_init (compositor);
meta_wayland_shell_init (compositor);
meta_wayland_pointer_gestures_init (compositor);

Some files were not shown because too many files have changed in this diff Show More