Compare commits

...

76 Commits
main ... 3.36.3

Author SHA1 Message Date
dc75c7d297 Bump version to 3.36.3
Update NEWS.
2020-06-03 01:35:15 +02:00
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
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 97175f8fa1)
2020-06-02 19:01:01 +00:00
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 f8e2234ce5)
2020-05-29 14:53:18 +00:00
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 38bbd9593b)
2020-05-29 14:52:34 +00:00
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 c8e12ead08)
2020-05-23 00:04:10 +02:00
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 8a541c08fb)
2020-05-23 00:04:10 +02:00
cb7ba2e90f stage-x11: Clean up include macros
https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1251
(cherry picked from commit dfed5f6a11)
2020-05-23 00:04:10 +02:00
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 96dd794fd1)
2020-05-23 00:04:10 +02:00
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 73a436362a)
2020-05-23 00:04:10 +02:00
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 b45d5ef3f5)

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1262
2020-05-20 11:28:23 +00:00
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 7e4e371466)

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1262
2020-05-20 11:28:23 +00:00
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 c8837a8de5)
2020-05-20 11:05:51 +00:00
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 283cccbe9f)
2020-05-20 11:05:41 +00:00
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 1d5f9b6917)
2020-05-15 12:49:12 +02:00
63bf5f1150 Bump version to 3.36.2
Update NEWS.
2020-04-29 22:22:12 +02:00
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
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
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
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
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
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
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 793a9d45e1)
2020-04-28 16:46:28 +00:00
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 61356caa06)
2020-04-27 18:28:19 +02:00
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 d26dc4ae44)
2020-04-27 16:05:45 +02:00
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 bd45a00fa3)
2020-04-27 13:19:08 +02:00
bfe9b333c0 Update German translation 2020-04-24 22:37:32 +00:00
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 36111270aa)
2020-04-24 14:19:44 +03:00
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 6e0cfd3e55)
2020-04-24 14:19:44 +03:00
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 fbd6366edd)
2020-04-22 01:33:10 +02:00
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 5671f0a284)
2020-04-22 01:20:11 +02:00
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 a7e63bea6c)
2020-04-22 01:20:11 +02:00
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 94b3c334e5)
2020-04-22 01:20:11 +02:00
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 167fd07e01)
2020-04-22 01:20:11 +02:00
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 1363246d44)
2020-04-19 21:51:33 +02:00
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 0b6560fac4)
2020-04-19 21:51:06 +02:00
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 d4c3870286)
2020-04-19 21:50:48 +02:00
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 4bdf9a1e70)
2020-04-19 21:48:31 +02:00
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 1909977a67)
2020-04-19 21:48:09 +02:00
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 655a783891)
2020-04-19 21:47:49 +02:00
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 a4596becc4)
2020-04-19 21:47:27 +02:00
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 7015bb3efd)
2020-04-19 21:47:06 +02:00
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 d2c762cc66)
2020-04-19 21:46:36 +02:00
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 04d429b743)
2020-04-19 21:46:14 +02:00
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 0b21dcfe08)
2020-04-19 21:45:36 +02:00
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 7c939d78c2)
2020-04-19 21:45:15 +02:00
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 8a2b82897d)
2020-04-19 21:44:42 +02:00
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 e95c365cf0)
2020-04-19 21:44:23 +02:00
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 a32cb7133b)
2020-04-19 21:44:06 +02:00
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 967966cdee)
2020-04-19 21:43:45 +02:00
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 06d67b6abf)
2020-04-19 21:43:20 +02:00
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 f15ce01e2b)
2020-04-16 16:09:54 +00:00
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 e48516679c)
2020-04-16 16:09:38 +00:00
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
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
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
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
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
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 3e967d731a)
2020-04-12 23:43:01 +02:00
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 5b30a52bbd)
2020-04-08 14:04:02 +00:00
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
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
3b2f6ae93d backends/x11: Fix access to WacomDevice
At some point we crossed the streams... In a short timespan we had
1f00aba92c merged, pushing WacomDevice to a common parent object,
and dcaa45fc0c 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 f0718c7d95)
2020-04-07 17:48:09 +00:00
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 e74c2e42cf)
2020-04-07 16:47:32 +00:00
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 8df3b21a51)
2020-04-07 13:23:21 +00:00
7baabc7ed0 x11: fix compilation if 'libwacom=false'
https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1168


(cherry picked from commit a8f6cada88)
2020-04-06 14:57:57 +00:00
b0709504ea Update Slovak translation 2020-04-05 20:22:08 +00:00
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 a6f94696e2)
2020-04-03 16:30:26 +00:00
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 c389aadff9)
2020-04-03 13:49:34 +02:00
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 37eda498f2)
2020-04-03 13:48:46 +02:00
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
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
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 5f5ce08ba4)
2020-04-02 17:09:24 +00:00
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 7f488e3e1d)
2020-03-31 23:13:42 +00:00
31809e1214 tests/actor-pick: Remove tabs
They're evil.

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


(cherry picked from commit 059d2144b2)
2020-03-31 23:13:15 +00:00
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 902302a174)
2020-03-31 23:12:44 +00:00
59 changed files with 1500 additions and 559 deletions

39
NEWS
View File

@ -1,3 +1,42 @@
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

@ -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 << 0,
} 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) ceilf (rect->width * scale);
texture_height = (int) ceilf (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

@ -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;

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.3',
meson_version: '>= 0.50.0',
license: 'GPLv2+'
)

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"

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,37 @@ 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;
}
if (!session->screen_cast_session)
{
g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
G_DBUS_ERROR_FAILED,
"No screen cast active");
return FALSE;
}
return TRUE;
}
static gboolean
handle_start (MetaDBusRemoteDesktopSession *skeleton,
GDBusMethodInvocation *invocation)
@ -256,6 +291,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 +331,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 +363,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 +390,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 +439,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 +470,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 +518,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 +564,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,21 +588,8 @@ 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 (!session->screen_cast_session)
{
g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
G_DBUS_ERROR_FAILED,
"No screen cast active");
return TRUE;
}
if (!meta_remote_desktop_session_check_can_notify (session, invocation))
return TRUE;
stream = meta_screen_cast_session_get_stream (session->screen_cast_session,
stream_path);
@ -617,21 +625,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 (!session->screen_cast_session)
{
g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
G_DBUS_ERROR_FAILED,
"No screen cast active");
return TRUE;
}
if (!meta_remote_desktop_session_check_can_notify (session, invocation))
return TRUE;
stream = meta_screen_cast_session_get_stream (session->screen_cast_session,
stream_path);
@ -668,21 +663,8 @@ 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 (!session->screen_cast_session)
{
g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
G_DBUS_ERROR_FAILED,
"No screen cast active");
return TRUE;
}
if (!meta_remote_desktop_session_check_can_notify (session, invocation))
return TRUE;
stream = meta_screen_cast_session_get_stream (session->screen_cast_session,
stream_path);
@ -714,13 +696,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,9 +115,10 @@ 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);

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;
@ -445,7 +447,8 @@ meta_screen_cast_stream_src_maybe_record_frame (MetaScreenCastStreamSrc *src)
uint64_t now_us;
now_us = g_get_monotonic_time ();
if (priv->last_frame_timestamp_us != 0 &&
if (priv->video_format.max_framerate.num > 0 &&
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)))
@ -539,12 +542,6 @@ meta_screen_cast_stream_src_disable (MetaScreenCastStreamSrc *src)
priv->is_enabled = FALSE;
}
static void
meta_screen_cast_stream_src_notify_closed (MetaScreenCastStreamSrc *src)
{
g_signal_emit (src, signals[CLOSED], 0);
}
static void
on_stream_state_changed (void *data,
enum pw_stream_state old,
@ -559,7 +556,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 +826,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 +853,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 +886,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 +925,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 +987,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

@ -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

@ -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

@ -3037,6 +3037,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 +3109,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);
}
}
}

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

@ -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);

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

@ -0,0 +1,32 @@
/*
* 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
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*
* Written by:
* Carlos Garnacho <carlosg@gnome.org>
*/
#ifndef META_SELECTION_PRIVATE_H
#define META_SELECTION_PRIVATE_H
#include "meta/meta-selection.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

@ -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

@ -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

@ -108,6 +108,30 @@ static struct wl_resource * create_and_send_primary_offer (MetaWaylandDataDevi
struct wl_resource *target);
static struct wl_resource * meta_wayland_data_source_get_resource (MetaWaylandDataSource *source);
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)
{
@ -901,6 +925,12 @@ meta_wayland_drag_grab_set_focus (MetaWaylandDragGrab *drag_grab,
client = wl_resource_get_client (surface->resource);
data_device_resource = wl_resource_find_for_client (&seat->data_device.resource_list, client);
if (!data_device_resource)
{
data_device_resource =
wl_resource_find_for_client (&seat->data_device.focus_resource_list,
client);
}
if (source && data_device_resource)
offer = create_and_send_dnd_offer (source, data_device_resource);
@ -1344,20 +1374,8 @@ static void
selection_data_source_destroyed (gpointer data, GObject *object_was_here)
{
MetaWaylandDataDevice *data_device = data;
MetaWaylandSeat *seat = wl_container_of (data_device, seat, data_device);
struct wl_resource *data_device_resource;
struct wl_client *focus_client = NULL;
data_device->selection_data_source = NULL;
focus_client = meta_wayland_keyboard_get_focus_client (seat->keyboard);
if (focus_client)
{
data_device_resource = wl_resource_find_for_client (&data_device->resource_list, focus_client);
if (data_device_resource)
wl_data_device_send_selection (data_device_resource, NULL);
}
unset_selection_source (data_device, META_SELECTION_CLIPBOARD);
}
@ -1392,8 +1410,7 @@ meta_wayland_source_cancel (MetaWaylandDataSource *source)
if (!priv->resource)
return;
if (wl_resource_get_version(priv->resource) >= WL_DATA_SOURCE_DND_FINISHED_SINCE_VERSION)
wl_data_source_send_cancelled (priv->resource);
wl_data_source_send_cancelled (priv->resource);
}
static void
@ -1414,11 +1431,12 @@ meta_wayland_source_drop_performed (MetaWaylandDataSource *source)
MetaWaylandDataSourcePrivate *priv =
meta_wayland_data_source_get_instance_private (source);
priv->drop_performed = TRUE;
if (wl_resource_get_version (priv->resource) >=
WL_DATA_SOURCE_DND_DROP_PERFORMED_SINCE_VERSION)
wl_data_source_send_dnd_drop_performed (priv->resource);
{
priv->drop_performed = TRUE;
wl_data_source_send_dnd_drop_performed (priv->resource);
}
}
static void
@ -1659,8 +1677,6 @@ meta_wayland_data_device_set_selection (MetaWaylandDataDevice *data_device,
guint32 serial)
{
MetaWaylandSeat *seat = wl_container_of (data_device, seat, data_device);
struct wl_resource *data_device_resource;
struct wl_client *focus_client;
MetaSelectionSource *selection_source;
if (data_device->selection_data_source &&
@ -1669,7 +1685,6 @@ meta_wayland_data_device_set_selection (MetaWaylandDataDevice *data_device,
if (data_device->selection_data_source)
{
meta_wayland_data_source_cancel (data_device->selection_data_source);
g_object_weak_unref (G_OBJECT (data_device->selection_data_source),
selection_data_source_destroyed,
data_device);
@ -1696,18 +1711,6 @@ meta_wayland_data_device_set_selection (MetaWaylandDataDevice *data_device,
set_selection_source (data_device, META_SELECTION_CLIPBOARD,
selection_source);
g_object_unref (selection_source);
focus_client = meta_wayland_keyboard_get_focus_client (seat->keyboard);
if (focus_client)
{
data_device_resource = wl_resource_find_for_client (&data_device->resource_list, focus_client);
if (data_device_resource)
{
struct wl_resource *offer;
offer = create_and_send_clipboard_offer (data_device, data_device_resource);
wl_data_device_send_selection (data_device_resource, offer);
}
}
}
static void
@ -1758,21 +1761,8 @@ primary_source_destroyed (gpointer data,
GObject *object_was_here)
{
MetaWaylandDataDevice *data_device = data;
MetaWaylandSeat *seat = wl_container_of (data_device, seat, data_device);
struct wl_client *focus_client = NULL;
data_device->primary_data_source = NULL;
focus_client = meta_wayland_keyboard_get_focus_client (seat->keyboard);
if (focus_client)
{
struct wl_resource *data_device_resource;
data_device_resource = wl_resource_find_for_client (&data_device->primary_resource_list, focus_client);
if (data_device_resource)
gtk_primary_selection_device_send_selection (data_device_resource, NULL);
}
unset_selection_source (data_device, META_SELECTION_PRIMARY);
}
@ -1782,8 +1772,6 @@ meta_wayland_data_device_set_primary (MetaWaylandDataDevice *data_device,
guint32 serial)
{
MetaWaylandSeat *seat = wl_container_of (data_device, seat, data_device);
struct wl_resource *data_device_resource;
struct wl_client *focus_client;
MetaSelectionSource *selection_source;
g_assert (!source || META_IS_WAYLAND_DATA_SOURCE_PRIMARY (source));
@ -1794,7 +1782,6 @@ meta_wayland_data_device_set_primary (MetaWaylandDataDevice *data_device,
if (data_device->primary_data_source)
{
meta_wayland_data_source_cancel (data_device->primary_data_source);
g_object_weak_unref (G_OBJECT (data_device->primary_data_source),
primary_source_destroyed,
data_device);
@ -1820,18 +1807,6 @@ meta_wayland_data_device_set_primary (MetaWaylandDataDevice *data_device,
set_selection_source (data_device, META_SELECTION_PRIMARY,
selection_source);
g_object_unref (selection_source);
focus_client = meta_wayland_keyboard_get_focus_client (seat->keyboard);
if (focus_client)
{
data_device_resource = wl_resource_find_for_client (&data_device->primary_resource_list, focus_client);
if (data_device_resource)
{
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);
}
}
}
static void
@ -1896,10 +1871,7 @@ owner_changed_cb (MetaSelection *selection,
if (selection_type == META_SELECTION_PRIMARY)
{
data_device_resource =
wl_resource_find_for_client (&data_device->primary_resource_list,
focus_client);
if (data_device_resource)
wl_resource_for_each (data_device_resource, &data_device->primary_focus_resource_list)
{
struct wl_resource *offer = NULL;
@ -1915,10 +1887,7 @@ owner_changed_cb (MetaSelection *selection,
}
else if (selection_type == META_SELECTION_CLIPBOARD)
{
data_device_resource =
wl_resource_find_for_client (&data_device->resource_list, focus_client);
if (data_device_resource)
wl_resource_for_each (data_device_resource, &data_device->focus_resource_list)
{
struct wl_resource *offer = NULL;
@ -2053,7 +2022,9 @@ void
meta_wayland_data_device_init (MetaWaylandDataDevice *data_device)
{
wl_list_init (&data_device->resource_list);
wl_list_init (&data_device->focus_resource_list);
wl_list_init (&data_device->primary_resource_list);
wl_list_init (&data_device->primary_focus_resource_list);
}
static struct wl_resource *
@ -2135,22 +2106,34 @@ meta_wayland_data_device_set_keyboard_focus (MetaWaylandDataDevice *data_device)
return;
data_device->focus_client = focus_client;
move_resources (&data_device->resource_list,
&data_device->focus_resource_list);
move_resources (&data_device->primary_resource_list,
&data_device->primary_focus_resource_list);
if (!focus_client)
return;
data_device_resource = wl_resource_find_for_client (&data_device->resource_list, focus_client);
if (data_device_resource)
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_clipboard_offer (data_device, data_device_resource);
wl_data_device_send_selection (data_device_resource, offer);
}
data_device_resource = wl_resource_find_for_client (&data_device->primary_resource_list, focus_client);
if (data_device_resource)
move_resources_for_client (&data_device->primary_focus_resource_list,
&data_device->primary_resource_list,
focus_client);
wl_resource_for_each (data_device_resource, &data_device->primary_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

@ -63,7 +63,9 @@ struct _MetaWaylandDataDevice
MetaWaylandDataSource *primary_data_source;
struct wl_listener selection_data_source_listener;
struct wl_list resource_list;
struct wl_list focus_resource_list;
struct wl_list primary_resource_list;
struct wl_list primary_focus_resource_list;
MetaWaylandDragGrab *current_grab;
struct wl_client *focus_client;

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

@ -145,6 +145,8 @@ xdnd_send_enter (MetaXWaylandDnd *dnd,
gchar **p;
struct wl_array *source_mime_types;
meta_x11_error_trap_push (x11_display);
data_source = compositor->seat->data_device.dnd_data_source;
xev.xclient.type = ClientMessage;
xev.xclient.message_type = xdnd_atoms[ATOM_DND_ENTER];
@ -189,6 +191,9 @@ xdnd_send_enter (MetaXWaylandDnd *dnd,
}
XSendEvent (xdisplay, dest, False, NoEventMask, &xev);
if (meta_x11_error_trap_pop_with_return (x11_display) != Success)
g_critical ("Error sending XdndEnter");
}
static void
@ -205,7 +210,9 @@ xdnd_send_leave (MetaXWaylandDnd *dnd,
xev.xclient.window = dest;
xev.xclient.data.l[0] = x11_display->selection.xwindow;
meta_x11_error_trap_push (x11_display);
XSendEvent (xdisplay, dest, False, NoEventMask, &xev);
meta_x11_error_trap_pop (x11_display);
}
static void
@ -241,7 +248,11 @@ xdnd_send_position (MetaXWaylandDnd *dnd,
xev.xclient.data.l[3] = time;
xev.xclient.data.l[4] = action_to_atom (action);
meta_x11_error_trap_push (x11_display);
XSendEvent (xdisplay, dest, False, NoEventMask, &xev);
if (meta_x11_error_trap_pop_with_return (x11_display) != Success)
g_critical ("Error sending XdndPosition");
}
static void
@ -261,7 +272,11 @@ xdnd_send_drop (MetaXWaylandDnd *dnd,
xev.xclient.data.l[0] = x11_display->selection.xwindow;
xev.xclient.data.l[2] = time;
meta_x11_error_trap_push (x11_display);
XSendEvent (xdisplay, dest, False, NoEventMask, &xev);
if (meta_x11_error_trap_pop_with_return (x11_display) != Success)
g_critical ("Error sending XdndDrop");
}
static void
@ -289,7 +304,11 @@ xdnd_send_finished (MetaXWaylandDnd *dnd,
xev.xclient.data.l[2] = action_to_atom (action);
}
meta_x11_error_trap_push (x11_display);
XSendEvent (xdisplay, dest, False, NoEventMask, &xev);
if (meta_x11_error_trap_pop_with_return (x11_display) != Success)
g_critical ("Error sending XdndFinished");
}
static void
@ -297,6 +316,7 @@ xdnd_send_status (MetaXWaylandDnd *dnd,
Window dest,
uint32_t action)
{
MetaX11Display *x11_display = meta_get_display ()->x11_display;
Display *xdisplay = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());
XEvent xev = { 0 };
@ -312,7 +332,11 @@ xdnd_send_status (MetaXWaylandDnd *dnd,
if (xev.xclient.data.l[4])
xev.xclient.data.l[1] |= 1 << 0; /* Bit 1: dest accepts the drop */
meta_x11_error_trap_push (x11_display);
XSendEvent (xdisplay, dest, False, NoEventMask, &xev);
if (meta_x11_error_trap_pop_with_return (x11_display) != Success)
g_critical ("Error sending Xdndstatus");
}
static void

View File

@ -60,6 +60,8 @@ G_DEFINE_TYPE_WITH_PRIVATE (MetaX11SelectionOutputStream,
meta_x11_selection_output_stream,
G_TYPE_OUTPUT_STREAM);
static size_t get_element_size (int format);
static void
meta_x11_selection_output_stream_notify_selection (MetaX11SelectionOutputStream *stream)
{
@ -97,6 +99,9 @@ meta_x11_selection_output_stream_can_flush (MetaX11SelectionOutputStream *stream
if (priv->delete_pending)
return FALSE;
if (!g_output_stream_is_closing (G_OUTPUT_STREAM (stream)) &&
priv->data->len < get_element_size (priv->format))
return FALSE;
return TRUE;
}
@ -110,7 +115,7 @@ get_max_request_size (MetaX11Display *display)
if (size <= 0)
size = XMaxRequestSize (display->xdisplay);
return size - 100;
return (size - 100) * 4;
}
static gboolean
@ -120,7 +125,12 @@ meta_x11_selection_output_stream_needs_flush_unlocked (MetaX11SelectionOutputStr
meta_x11_selection_output_stream_get_instance_private (stream);
if (priv->data->len == 0)
return FALSE;
{
if (priv->incr)
return g_output_stream_is_closing (G_OUTPUT_STREAM (stream));
else
return FALSE;
}
if (g_output_stream_is_closing (G_OUTPUT_STREAM (stream)))
return TRUE;
@ -193,7 +203,8 @@ meta_x11_selection_output_stream_perform_flush (MetaX11SelectionOutputStream *st
MetaX11SelectionOutputStreamPrivate *priv =
meta_x11_selection_output_stream_get_instance_private (stream);
Display *xdisplay;
size_t element_size, n_elements;
size_t element_size, n_elements, max_size;
gboolean first_chunk = FALSE;
int error_code;
g_assert (!priv->delete_pending);
@ -207,8 +218,12 @@ meta_x11_selection_output_stream_perform_flush (MetaX11SelectionOutputStream *st
element_size = get_element_size (priv->format);
n_elements = priv->data->len / element_size;
max_size = get_max_request_size (priv->x11_display);
if (!g_output_stream_is_closing (G_OUTPUT_STREAM (stream)))
if (!priv->incr)
first_chunk = TRUE;
if (!priv->incr && priv->data->len > max_size)
{
XWindowAttributes attrs;
@ -224,14 +239,22 @@ meta_x11_selection_output_stream_perform_flush (MetaX11SelectionOutputStream *st
XChangeProperty (xdisplay,
priv->xwindow,
priv->xproperty,
XInternAtom (priv->x11_display->xdisplay, "INCR", True),
XInternAtom (priv->x11_display->xdisplay, "INCR", False),
32,
PropModeReplace,
(guchar *) &(long) { n_elements },
1);
priv->delete_pending = TRUE;
}
else
{
size_t copy_n_elements;
if (priv->incr && priv->data->len > 0)
priv->delete_pending = TRUE;
copy_n_elements = MIN (n_elements, max_size / element_size);
XChangeProperty (xdisplay,
priv->xwindow,
priv->xproperty,
@ -239,15 +262,13 @@ meta_x11_selection_output_stream_perform_flush (MetaX11SelectionOutputStream *st
priv->format,
PropModeReplace,
priv->data->data,
n_elements);
g_byte_array_remove_range (priv->data, 0, n_elements * element_size);
if (priv->data->len < element_size)
priv->flush_requested = FALSE;
copy_n_elements);
g_byte_array_remove_range (priv->data, 0, copy_n_elements * element_size);
}
meta_x11_selection_output_stream_notify_selection (stream);
if (first_chunk)
meta_x11_selection_output_stream_notify_selection (stream);
priv->delete_pending = TRUE;
g_cond_broadcast (&priv->cond);
g_mutex_unlock (&priv->mutex);
@ -257,19 +278,26 @@ meta_x11_selection_output_stream_perform_flush (MetaX11SelectionOutputStream *st
{
char error_str[100];
XGetErrorText (xdisplay, error_code, error_str, sizeof (error_str));
g_task_return_new_error (priv->pending_task,
G_IO_ERROR,
G_IO_ERROR_BROKEN_PIPE,
"Failed to flush selection output stream: %s",
error_str);
g_clear_object (&priv->pending_task);
priv->flush_requested = FALSE;
priv->delete_pending = FALSE;
priv->pipe_error = TRUE;
if (priv->pending_task)
{
XGetErrorText (xdisplay, error_code, error_str, sizeof (error_str));
g_task_return_new_error (priv->pending_task,
G_IO_ERROR,
G_IO_ERROR_BROKEN_PIPE,
"Failed to flush selection output stream: %s",
error_str);
g_clear_object (&priv->pending_task);
}
}
else if (priv->pending_task)
else if (priv->pending_task && priv->data->len == 0 && !priv->delete_pending)
{
size_t result;
priv->flush_requested = FALSE;
result = GPOINTER_TO_SIZE (g_task_get_task_data (priv->pending_task));
g_task_return_int (priv->pending_task, result);
g_clear_object (&priv->pending_task);
@ -281,12 +309,17 @@ meta_x11_selection_output_stream_invoke_flush (gpointer data)
{
MetaX11SelectionOutputStream *stream =
META_X11_SELECTION_OUTPUT_STREAM (data);
MetaX11SelectionOutputStreamPrivate *priv =
meta_x11_selection_output_stream_get_instance_private (stream);
if (meta_x11_selection_output_stream_needs_flush (stream) &&
meta_x11_selection_output_stream_can_flush (stream))
meta_x11_selection_output_stream_perform_flush (stream);
return G_SOURCE_REMOVE;
if (priv->delete_pending || priv->data->len > 0)
return G_SOURCE_CONTINUE;
else
return G_SOURCE_REMOVE;
}
static gssize
@ -354,16 +387,11 @@ meta_x11_selection_output_stream_write_async (GOutputStream *output_stream
g_object_unref (task);
return;
}
else if (!meta_x11_selection_output_stream_can_flush (stream))
{
g_assert (priv->pending_task == NULL);
priv->pending_task = task;
g_task_set_task_data (task, GSIZE_TO_POINTER (count), NULL);
return;
}
else
{
meta_x11_selection_output_stream_perform_flush (stream);
if (meta_x11_selection_output_stream_can_flush (stream))
meta_x11_selection_output_stream_perform_flush (stream);
g_task_return_int (task, count);
g_object_unref (task);
return;
@ -391,7 +419,7 @@ meta_x11_selection_output_request_flush (MetaX11SelectionOutputStream *stream)
g_mutex_lock (&priv->mutex);
if (priv->data->len >= get_element_size (priv->format))
if (priv->data->len > 0)
priv->flush_requested = TRUE;
needs_flush = meta_x11_selection_output_stream_needs_flush_unlocked (stream);
@ -466,10 +494,9 @@ meta_x11_selection_output_stream_flush_async (GOutputStream *output_stream
}
}
g_assert (priv->pending_task == NULL);
priv->pending_task = task;
meta_x11_selection_output_stream_perform_flush (stream);
g_task_return_boolean (task, TRUE);
g_object_unref (task);
return;
}
static gboolean

View File

@ -23,6 +23,8 @@
#include <gdk/gdkx.h>
#include "core/meta-selection-private.h"
#include "meta/meta-selection-source-memory.h"
#include "x11/meta-selection-source-x11-private.h"
#include "x11/meta-x11-selection-output-stream-private.h"
#include "x11/meta-x11-selection-private.h"
@ -30,6 +32,13 @@
#define UTF8_STRING_MIMETYPE "text/plain;charset=utf-8"
#define STRING_MIMETYPE "text/plain"
/* Set an arbitrary (although generous) threshold to determine whether a
* XFixesSelectionNotify corresponds to a XSetSelectionOwner from another
* client. The selection timestamp is not updated if the owner client is
* closed.
*/
#define SELECTION_CLEARED_BY_CLIENT(e) (e->timestamp - e->selection_timestamp < 50)
static gboolean
atom_to_selection_type (Display *xdisplay,
Atom selection,
@ -296,8 +305,8 @@ source_new_cb (GObject *object,
source = meta_selection_source_x11_new_finish (res, &error);
if (source)
{
meta_selection_set_owner (selection, selection_type, source);
g_set_object (&x11_display->selection.owners[selection_type], source);
meta_selection_set_owner (selection, selection_type, source);
g_object_unref (source);
}
else if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
@ -331,16 +340,27 @@ meta_x11_selection_handle_xfixes_selection_notify (MetaX11Display *x11_display,
x11_display->selection.cancellables[selection_type] = g_cancellable_new ();
if (event->owner == None)
if (event->owner == None && x11_display->selection.owners[selection_type])
{
if (x11_display->selection.owners[selection_type])
if (SELECTION_CLEARED_BY_CLIENT (event))
{
MetaSelectionSource *source;
/* Replace with an empty owner */
source = g_object_new (META_TYPE_SELECTION_SOURCE_MEMORY, NULL);
g_set_object (&x11_display->selection.owners[selection_type], source);
meta_selection_set_owner (selection, selection_type, source);
g_object_unref (source);
}
else
{
/* An X client went away, clear the selection */
meta_selection_unset_owner (selection, selection_type,
x11_display->selection.owners[selection_type]);
g_clear_object (&x11_display->selection.owners[selection_type]);
}
}
else if (event->owner != x11_display->selection.xwindow)
else if (event->owner != None && event->owner != x11_display->selection.xwindow)
{
SourceNewData *data;
@ -374,14 +394,13 @@ meta_x11_selection_handle_event (MetaX11Display *x11_display,
}
static void
owner_changed_cb (MetaSelection *selection,
MetaSelectionType selection_type,
MetaSelectionSource *new_owner,
MetaX11Display *x11_display)
notify_selection_owner (MetaX11Display *x11_display,
MetaSelectionType selection_type,
MetaSelectionSource *new_owner)
{
Display *xdisplay = x11_display->xdisplay;
if (new_owner && !META_IS_SELECTION_SOURCE_X11 (new_owner))
if (new_owner && new_owner != x11_display->selection.owners[selection_type])
{
if (x11_display->selection.cancellables[selection_type])
{
@ -404,6 +423,7 @@ meta_x11_selection_init (MetaX11Display *x11_display)
{
XSetWindowAttributes attributes = { 0 };
MetaDisplay *display = meta_get_display ();
MetaSelection *selection;
guint mask, i;
attributes.event_mask = PropertyChangeMask | SubstructureNotifyMask;
@ -424,18 +444,24 @@ meta_x11_selection_init (MetaX11Display *x11_display)
XFixesSelectionWindowDestroyNotifyMask |
XFixesSelectionClientCloseNotifyMask;
selection = meta_display_get_selection (display);
for (i = 0; i < META_N_SELECTION_TYPES; i++)
{
MetaSelectionSource *owner;
XFixesSelectSelectionInput (x11_display->xdisplay,
x11_display->selection.xwindow,
selection_to_atom (i, x11_display->xdisplay),
mask);
owner = meta_selection_get_current_owner (selection, i);
notify_selection_owner (x11_display, i, owner);
}
g_signal_connect (meta_display_get_selection (display),
"owner-changed",
G_CALLBACK (owner_changed_cb),
x11_display);
g_signal_connect_swapped (selection,
"owner-changed",
G_CALLBACK (notify_selection_owner),
x11_display);
}
void
@ -445,7 +471,7 @@ meta_x11_selection_shutdown (MetaX11Display *x11_display)
guint i;
g_signal_handlers_disconnect_by_func (meta_display_get_selection (display),
owner_changed_cb,
notify_selection_owner,
x11_display);
for (i = 0; i < META_N_SELECTION_TYPES; i++)