Compare commits

...

85 Commits

Author SHA1 Message Date
Carlos Garnacho
a416bed34c 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-06-23 20:40:33 +02:00
Carlos Garnacho
80c0a470e7 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-06-23 20:40:21 +02:00
Jonas Ådahl
8802f7f0d8 stage/x11: Check that message is WM_PROTOCOLS before assuming so
When a touch sequence was rejected, we'd update the event timestamps of
incoming touch events to help with implementing grabs. This was done by
sending a ClientMessage with a counter, and comparing the counter to
decide whether we're seing a replayed event or not.

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

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

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

This fixes crashes such as:

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

and

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

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

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1317
(cherry picked from commit e5ea8f5483)
2020-06-16 16:27:02 +02:00
Daniel van Vugt
8b3f1117be 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:50:23 +02:00
Florian Müllner
48ffbb5824 Bump version to 3.34.6
Update NEWS.
2020-04-30 17:13:07 +02:00
Olivier Fourdan
129d134704 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-30 16:52:40 +02:00
Olivier Fourdan
4078ba1828 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-30 14:26:28 +00:00
Carlos Garnacho
fd8ccbac82 keybindings: Check the special modifiers specifically
Make sure it is only the special modifier (hardcoded to 1 currently)
which is being pressed (not counting locked modifiers) before notifying
that the special modifier is pressed, as we are interested in it being
pressed alone and not in combination with other modifier keys.

This helps in two ways:
- Pressing alt, then ctrl, then releasing both won't trigger the locate
  pointer action.
- Pressing alt, then ctrl, then down/up to switch workspace won't interpret
  the last up/down keypress as an additional key on top of the special ctrl
  modifier, thus won't be forwarded down to the focused client in the last
  second.

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

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1014
(cherry picked from commit 23da6c2426)
2020-04-30 14:26:27 +00:00
Laurent Bigonville
93417d0ceb 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:06:55 +02:00
Pekka Paalanen
3bafd23424 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:18:49 +03:00
Pekka Paalanen
e328fcc379 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:18:49 +03:00
Carlos Garnacho
e845bbd579 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:34:22 +02:00
Carlos Garnacho
025730349d 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:27:19 +02:00
Carlos Garnacho
f6d0af0c93 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:27:05 +02:00
Carlos Garnacho
8acff5309d 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:26:21 +02:00
Carlos Garnacho
0ab8b17433 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:26:21 +02:00
Sebastian Keller
50f383d2e9 x11-selection: Plug MetaSelectionSourceX11 leak
meta_selection_source_x11_new_finish() transfers the ownership of the
selection source, but source_new_cb() was not freeing it.

Fixes https://gitlab.gnome.org/GNOME/mutter/issues/998
https://gitlab.gnome.org/GNOME/mutter/merge_requests/1001

(cherry picked from commit 8e6821bc65)
2020-04-22 01:26:21 +02:00
Carlos Garnacho
7fbba4ad14 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:59:52 +02:00
Carlos Garnacho
eb6189d6b6 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:59:43 +02:00
Carlos Garnacho
668d13ffb5 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:59:35 +02:00
Carlos Garnacho
02947e7872 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:59:27 +02:00
Carlos Garnacho
ebfe5e44c2 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:59:20 +02:00
Carlos Garnacho
8f64b3dcad 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:59:11 +02:00
Carlos Garnacho
8de5b95123 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:59:02 +02:00
Carlos Garnacho
cedab9442f 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:58:53 +02:00
Carlos Garnacho
7cc5ed96fc 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:58:44 +02:00
Carlos Garnacho
bb831f04c5 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:58:34 +02:00
Carlos Garnacho
c92267feb2 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:58:24 +02:00
Carlos Garnacho
8240aba80f 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:58:13 +02:00
Carlos Garnacho
5f34a0f245 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:58:05 +02:00
Carlos Garnacho
83eeb3dbd2 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:57:56 +02:00
Carlos Garnacho
c25011ffba 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:57:46 +02:00
Carlos Garnacho
abd67819fe 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:57:36 +02:00
Carlos Garnacho
6f3b7b733a 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:57:26 +02:00
Florian Müllner
e2c61f2739 window: Really propagate effective on-all-workspaces setting to transients
Commit cda9579034 fixed a corner case when setting the initial workspace
state of transient windows, but it still missed a case:

should_be_on_all_workspaces() returns whether the window should be on all
workspaces according to its properties/placement, but it doesn't take
transient relations into account.

That means in case of nested transients, we can still fail the assert:

 1. on-all-workspaces toplevel
 2. should_be_on_all_workspaces() is TRUE for the first transient's parent,
    as the window from (1) has on_all_workspaces_requested == TRUE
 3. should_be_on_all_workspaces() is FALSE for the second transient's
    parent, as the window from (2) is only on-all-workspace because
    of its parent

We can fix this by either using the state from the root ancestor
instead of the direct transient parent, or by using the parent's
on_all_workspaces_state.

The latter is simpler, so go with that.

https://gitlab.gnome.org/GNOME/mutter/issues/1083
2020-04-09 00:35:36 +02:00
Florian Müllner
1a3dfd8110 Bump version to 3.34.5
Update NEWS.
2020-03-31 01:17:00 +02:00
Carlos Garnacho
aeb781acd6 x11: Handle windowing errors while writing selection INCR data
This error was just logged but not raised. Do as the code comment said
and raise a pipe error at that moment, and for subsequent operations
on the output stream (although none besides close() should be expected
after propagating the error properly).

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

(cherry picked from commit 2ecbf6d746)
2020-03-30 16:35:12 +02:00
Robert Mader
092591b872 core: Demote tiff and bmp image formats in the clipboard manager
Support for them appears to be way less common than e.g. png, which is
currently the preferred format from Firefox, Chromium, Libreoffice and others.
Adopt to that fact.

As a side effect, this works around a bug observed when copying images in
Firefox on Wayland.

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

(cherry picked from commit 6aa546145f)
2020-03-29 12:41:38 +02:00
Jonas Ådahl
57992f37cc wayland: Don't crash when trying to fullscreen on inert wl_output
There is a race where an output can be used as a fullscreen target, but
it has already been removed due to a hotplug. Handle this gracefully by
ignoring said output in such situations.

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


(cherry picked from commit 512bb7d1cd)
2020-03-12 20:46:43 +00:00
Jonas Ådahl
7655a63af6 kms-impl-device: Clean up state if drm resources disappear
It may happen that drmModeGetResources() starts returning NULL. Handle
this gracefully by removing all connectors, CRTCs and planes making the
device in practice defunct.

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


(cherry picked from commit 5319949a45)
2020-03-12 20:45:55 +00:00
Pekka Paalanen
a5b5e95ad9 cursor-renderer/native: Handle GPU hotplug
Listen for GPU hotplug events to initialize their cursor support.

This fixes one reason for why DisplayLink devices may not be using a hardware
cursor. Particularly, when a DisplayLink device is hotplugged for the first
time such that EVDI creates a new DRM device node after gnome-shell has already
started, we used to forget to initialize the cursor support.

https://gitlab.gnome.org/GNOME/mutter/merge_requests/1097
(cherry picked from commit 8abdf16a39)
2020-03-10 11:48:40 +02:00
Pekka Paalanen
11da42b2f8 cursor-renderer/native: Refactor init to per-gpu
Extract the code to initialize a single GPU cursor support into its own
function. The new function will be used by GPU hotplug in the future.

This is a pure refactoring without any behavioral changes.

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

Backported from 4cc29cfb61.
2020-03-10 11:47:23 +02:00
Olivier Fourdan
2709a4ffb1 wayland/data-device: Fix crash with offer from X11 client
If a data offer comes from an X11 client, the Wayland resource would be
NULL, causing a crash in `data_offer_choose_action()` trying to get the
resource version.

So instead of doing the version check in `data_offer_choose_action()`,
do it early when creating the data source.

Closes: https://gitlab.gnome.org/GNOME/mutter/issues/1057
https://gitlab.gnome.org/GNOME/mutter/merge_requests/1073

(cherry picked from commit f9326cfa3d)
2020-02-23 18:19:23 +01:00
Olivier Fourdan
c65db40178 wayland/data-device: Check resource version on cancel
For clarity, check the resource version needs the "cancelled" message in
the actual vmethod rather than from the caller function.

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

(cherry picked from commit 963108a9a6)
2020-02-23 18:18:59 +01:00
Jonas Ådahl
011ff15603 window-actor: Don't show actor until meta_window_actor_show()
By default clutter will show an actor as it is added to a parent. This
means that after we create the window actor, when it's added to the
window group, we implicitly show it. What we really want is to not show
it until the window is supposed to be shown, which happens when
meta_window_actor_show() is called, as showing prior to that, could
cause issues.

Avoid the implicit show by setting the "show-on-set-parent" property on
the window actor to `FALSE` on window actor construction.

https://gitlab.gnome.org/GNOME/mutter/merge_requests/1066
2020-02-20 01:27:50 +01:00
Florian Müllner
c3d2f3f399 window: Ignore requests to be placed on non-existent workspaces
When an X11 window requests an initial workspace, we currently trust
it that the workspace actually exists. However dynamic workspaces
make this easy to get wrong for applications: They make it likely
for the number of workspaces to change between application starts,
and if the app blindly applies its saved state on startup, it will
trigger an assertion.

Make sure that we pass valid parameters to set_workspace_state(),
and simply let the workspace assignment fall through to the default
handling otherwise.

https://gitlab.gnome.org/GNOME/mutter/issues/1029
2020-02-20 01:26:41 +01:00
Yi-Jyun Pan
053bb5901a Update Chinese (Taiwan) translation 2020-02-19 03:08:50 +00:00
Florian Müllner
0bce4323c7 Bump version to 3.34.4
Update NEWS.
2020-02-16 15:49:35 +01:00
Olivier Fourdan
b2bc345463 wayland/subsurface: Keep subsurface actors reactive
The actors of Wayland subsurfaces are set to be reactive on creation,
when receiving the `wl_subcompositor.get_subsurface` request.

However, if a client creates several subsurfaces and then creates the
xdg_toplevel object after, the previous subsurface actors are reset.

As a result, Clutter picking will skip and ignore those actors in
`clutter_actor_should_pick_paint()` because they aren't marked as
reactive anymore.

An example of such a client being affected by this issue is SCTK, the
Rust library implementing client side decorations for Wayland used
internally by winit and alacritty.

Move the `set_reactive()` call from `get_subsurface()` to the subsurface
`sync_actor_subsurface_state()` vfunc to make sure those remain reactive
even after `xdg_surface.get_toplevel` is invoked.

Closes: https://gitlab.gnome.org/GNOME/mutter/issues/1024
https://gitlab.gnome.org/GNOME/mutter/merge_requests/1040


(cherry picked from commit 934a829a57)
2020-02-10 09:02:30 +00:00
Robert Mader
2235629d25 core: Extend list of image formats to be stored in the clipboard manager
These types are probably common enough to support.

See also:
https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types/Complete_list_of_MIME_types

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

(cherry picked from commit b91d66bf98)
2020-02-04 00:27:46 +01:00
Carlos Garnacho
59da900a45 core: Define specific image formats to be stored in the clipboard manager
And order those preferences in order of lossiness (jpeg < png < bmp). This
avoids us from prefering other formats that are not useful or widely
recognized.

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

(cherry picked from commit 832c0fb0ea)
2020-02-04 00:27:17 +01:00
Carlos Garnacho
0e0dae2774 core: Demote image formats' priority from preservation in clipboard manager
Most usually, applications either expose clipboard content either as text
or as images, so the prioritization here is pointless. However there's some
outliers like LibreOffice Calc which exports content as both image and text
formats (besides other internal ones).

In that mixed case, we probably prefer to keep text formats, rather than
image based ones.

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

(cherry picked from commit 2fbbf657d5)
2020-02-04 00:26:39 +01:00
Georges Basile Stavracas Neto
4959ae8bc4 clutter/brightness-contrast-effect: Compare float with G_APPROX_VALUE
Nobody should ever compare float for equality. Use G_APPROX_VALUE to
check that.

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

(cherry picked from commit 84ea4ad990)
2020-02-02 17:50:30 +01:00
Georges Basile Stavracas Neto
aea5541ffa clutter/offscreen-effect: Clear offscreen when pre-paint fails
Some ClutterOffscreenEffect subclasses, such as ClutterBrightnessContrastEffect,
early-return FALSE in pre-paint before chaining up. It's an important optimization
that avoids creating or updating the offscreen framebuffer.

However, if an offscreen framebuffer already exists by the time pre-paint fails,
it will be used *without* repaint the actor over it. That causes an old picture
of the actor to be displayed.

Fix that by always clearing the offscreen framebuffer when pre-paint fails.

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

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

(cherry picked from commit 64685f4b20)
2020-02-02 17:49:34 +01:00
Georges Basile Stavracas Neto
47fe7ac25b clutter/offscreen-effect: Clear offscreen framebuffer when disabling
When changing the 'enabled' property and disabling the offscreen effect,
it doesn't make sense to preserve the offscreen framebuffer. It's not
drawing, after all.

Furthermore, because ClutterOffscreenEffect only checks if the offscreen
framebuffer exists to decide whether or not to redraw, keeping the fbo
alive is a waste of resources.

Clear the offscreen framebuffer when the effect is disabled or enabled.

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

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

(cherry picked from commit bf594e9fb6)
2020-02-02 17:31:46 +01:00
Georges Basile Stavracas Neto
d35d7fb618 clutter/offscreen-effect: Use g_clear_pointer for cleanup
It does the exact same checks, and saves us a few lines of code.

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

(cherry picked from commit 3958e75ed2)
2020-02-02 17:31:46 +01:00
Carlos Garnacho
666bd25005 wayland: Handle dragging from/dropping to v1 data device users
Interoperation between wl_data_device_manager v1 and v3 got broken
at some point. Ensure that we resort to the "copy" action if either
the drop site or the drag source are from a client that requested v1.

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

(cherry picked from commit ffad55c66f)
2020-02-01 16:30:25 +01:00
Robert Mader
208fd1b083 wayland/data-device: Small style fixes
https://gitlab.gnome.org/GNOME/mutter/merge_requests/1031

(cherry picked from commit 15b46a6f88,
to keep future backports easy)
2020-01-31 15:21:18 +01:00
Robert Mader
12152c7edb wayland/data-device: Guard against a potential crash
https://gitlab.gnome.org/GNOME/mutter/merge_requests/1031

(cherry picked from commit c27fc3537b)
2020-01-31 15:20:55 +01:00
Robert Mader
de7782221a wayland/data-device: Cancel drag source when the drag finished unsuccessfully
When a drag was performed but did not finish successfully, e.g. because no
mimetype was accepted, we need to send the source cancel event so clients
know they can destroy the drag source (since version 3).

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

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

(cherry picked from commit 6cc748cce9)
2020-01-31 15:20:20 +01:00
Carlos Garnacho
651d2a57f8 wayland: Check focus surface client in wl_data_device.set_selection()
Similar to our handling in set_primary(), ignore set_selection() requests
that come from unfocused clients.

https://gitlab.gnome.org/GNOME/mutter/issues/878

(cherry picked from commit e865fcc460)
2020-01-31 15:18:42 +01:00
Carlos Garnacho
e18aa564b0 wayland: Clean up meta_wayland_data_device_set_primary()
This function is already checking for the focus surface client
matching the requestor. The type check was slightly bogus though
as it'd be an screwup in our code, make it an assert instead.

Also, move the check for the client having the focus into the
upper call, so this and wl_data_device.set_selection code can
get more in line.

https://gitlab.gnome.org/GNOME/mutter/issues/878

(cherry picked from commit 16eb461054)
2020-01-31 15:18:16 +01:00
Carlos Garnacho
4cc5b85c5d wayland: Flatten data source object hierarchy
We have an abstract MetaWaylandDataSource and 2 subclasses for
clipboard/primary data sources. Since the abstraction provided
by the additional sublevel is arguable, push the wl_resource
field up, and leave us with just 2 objects to think about, all
of them containing a wl_resource.

https://gitlab.gnome.org/GNOME/mutter/issues/878

(cherry picked from commit c11ef6ef07)
2020-01-31 15:17:43 +01:00
Adam Jackson
ca5ed7369d cogl: Fix GLES2 fallback
Say you're using intel gen3, you poor soul. Your big-GL maxes out at 1.5
unless you use dirty tricks, but you do have GLES2. We try to fall back
to GLES in this case, but we only ever say eglBindAPI(EGL_OPENGL_API).
So when we go to do CreateContext, even though we think we've requested
GLES 2.0, the driver will compare that "2.0" against the maximum big-GL
version, and things will fail.

Fix this by binding EGL_OPENGL_ES_API before trying a GLES context.

https://gitlab.gnome.org/GNOME/mutter/issues/635

(cherry picket from commit f4f7e31303)
2020-01-27 17:09:09 +01:00
Carlos Garnacho
5ae317e004 wayland: Do not check current offer on DnD button release
This check was added on commit 48639ac5 as a means to disregard
DnD drops where the offer would disappear beforehand. However since
that commit was all about wl_data_device_manager version < 3,
forgetting about the selected mimetype seems a behavior more inline
with those versions.

Since no current drop is something expected on X11 drop sites, fixes
DnD over those, while keeping the original bug fixed.

Found by Robert Mader (https://gitlab.gnome.org/GNOME/mutter/issues/974#note_688144)

https://gitlab.gnome.org/GNOME/mutter/issues/974
https://gitlab.gnome.org/GNOME/mutter/merge_requests/1005

(cherry picked from commit 30bf588a38)
2020-01-27 15:28:57 +01:00
Carlos Garnacho
21dca32934 xwayland: Set XDND source-side actions as per XDND
In XDND, we just get a hint on XdndPosition about what's the action
chosen by the user. Make the data source actions the full set on
XdndEnter (as we can't know better), and pass the hint in XdndPosition
as the user chosen action as it should be.

Makes Wayland drop sites aware of the user action as per XDND with X11
drag sources, and still makes modifiers during DnD work.

https://gitlab.gnome.org/GNOME/mutter/issues/974
https://gitlab.gnome.org/GNOME/mutter/merge_requests/1005

(cherry picked from commit 090a6ad409)
2020-01-27 15:28:30 +01:00
Carlos Garnacho
41c6e1375b x11: Map x11 (UTF8_)STRING requests to text/plain mimetypes
Make the x11 selection proxy map UTF8_STRING and STRING to proper
mimetypes, as the selection source (wayland or memory) might not
offer those for backwards compatibility.

Closes: https://gitlab.gnome.org/GNOME/gnome-shell/issues/1355
https://gitlab.gnome.org/GNOME/mutter/merge_requests/1005

(cherry picked from commit a6c195b05c)
2020-01-27 15:28:03 +01:00
Carlos Garnacho
d38c30c128 wayland: Preserve XdndTypeList for future callers
This Xdnd property is owned by the drag source, we shouldn't delete
it when reading/proxying it to Wayland clients.

Closes: https://gitlab.gnome.org/GNOME/gtk/issues/2347
https://gitlab.gnome.org/GNOME/mutter/merge_requests/1005

(cherry picked from commit c1df48befd)
2020-01-27 15:27:11 +01:00
Adam Jackson
59e9b073a5 renderer-native: Fix memory leak in secondary GPU update
Leaking a texture object and a framebuffer object every time you update
the secondary GPU is perhaps not the best plan.

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


(cherry picked from commit 545fcb3dbf)
2020-01-21 14:47:09 +00:00
Sebastian Keller
6b6e724425 shaped-texture: Plug region leak
https://gitlab.gnome.org/GNOME/mutter/merge_requests/1002


(cherry picked from commit b30a29f830)
2020-01-21 14:26:15 +00:00
Carlos Garnacho
156dd576f4 x11: Iterate over selections in a safer manner for event handling
It might be the case that handling an event induces the stream to
trigger completion, hence removing itself from the list. In that
case we would operate on the no longer valid list element to fetch
the next one.

Keep a pointer to the next element beforehand, so we can tiptoe
over streams that did remove themselves.

https://gitlab.gnome.org/GNOME/mutter/merge_requests/869
(cherry picked from commit 45a8806e65)
2020-01-17 13:57:31 +01:00
Carlos Garnacho
4d0a331cfe x11: Detach selection streams on dispose
The streams were only detached from MetaX11Display (and its event handling)
on completion. This is too much to expect, and those might be in some
circumstances replaced while operating.

Make those streams detach themselves on dispose(), so we don't trip into
freed memory later on when trying to dispatch unrelated X11 selection events.

https://gitlab.gnome.org/GNOME/mutter/merge_requests/869
(cherry picked from commit e1fa0734a9)
2020-01-17 13:57:24 +01:00
Jonas Ådahl
01d93f2819 kms-impl-simple: Handle mode set race conditions gracefully
If we end up trying to do a mode set on a DRM state that has already
changed behind our back without us yet having seen the hotplug event we
may fail with `EINVAL`. Since the renderer layer doesn't handle mode set
failure, it'll still try to page flip later on, which will then also
fail. When failing, it'll try to look up the cached mode set in order to
retry the mode set later on, as is needed to handle other error
conditions. However, if the mode set prior to the page flip failed, we
won't cache the mode set, and the page flip error handling code will get
confused.

Instead of asserting that a page flip always has a valid cached mode set
ready to look up, handle it being missing more gracefully by failing to
mode set. It is expected that things will correct themself as there
should be a hotplug event waiting around the the corner, to reconfigure
the monitor configuration setting new modes.

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

https://gitlab.gnome.org/GNOME/mutter/merge_requests/1007
(cherry picked from commit ce3409b2b7)
2020-01-16 16:02:42 +01:00
Jonas Ådahl
be777dbd79 kms-impl-simple: Include mode name in error message
https://gitlab.gnome.org/GNOME/mutter/merge_requests/1007
(cherry picked from commit 7733f88168)
2020-01-16 16:02:42 +01:00
Jonas Ådahl
a9a0110818 wayland/actor-surface: Always consider unmapped actors not on output
This avoids using bogus geometric values from an unmapped actor to
determine whether an actor is on a logical monitor or not. This would
happen when committing to a subsurface of a yet to be mapped toplevel.

https://gitlab.gnome.org/GNOME/mutter/merge_requests/961
(cherry picked from commit 6d15231f10)
2020-01-16 08:54:31 +01:00
Jonas Ådahl
fd7d0fb339 wayland/surface: Move shaped-texture synchronization to actor surface
As with most other state that ends up being pushed to the actor and the
associated shaped texture, also push the texture and the corresponding
metadata from the actor surface. This fixes an issue when a toplevel
surface was reset, where before the subsurface content was not properly
re-initialized, as content state synchronization only happened on
commit, not when asked to synchronize.

https://gitlab.gnome.org/GNOME/mutter/merge_requests/961
(cherry picked from commit f0df07cba3)
2020-01-16 08:54:31 +01:00
Jonas Ådahl
1671692590 wayland/surface-actor: Reset and sync subsurface state when resetting
A actor surface may be reset by an xdg_toplevel if a NULL buffer is
attached. This should reset the actor state of the toplevel to an empty
state, while unmapping the previous actor. Subsurfaces, however, should
stay intact, including their relationship to the toplevel. They should
also not be yanked away from the actor of the actor surface prior to it
resetting, so that a window-destroy animation can include the subsurface
actor.

This fixes a potential crash when a subsurface tries to commit to its
wl_surface after the destroy animation of the toplevel has finished, as
the actor would at that point have been destroyed and cleared from the
actor surface struct, causing a segmentation fault.

https://gitlab.gnome.org/GNOME/mutter/merge_requests/961
(cherry picked from commit fe7bece31e)
2020-01-16 08:54:31 +01:00
Jonas Ådahl
06fc756f0f shaped-texture: Make setting the same texture a no-op
Will be helpful when pushing state to the shaped texture, letting the
one pushing not have to care about checking if anything changed.

https://gitlab.gnome.org/GNOME/mutter/merge_requests/961
(cherry picked from commit 3969285e5c)
2020-01-16 08:54:31 +01:00
Jonas Ådahl
81b7196ad9 shaped-texture: Minor clean up
Use cogl_clear_object(), add reference to texture when setting, and
remove redundant runtime type check.

https://gitlab.gnome.org/GNOME/mutter/merge_requests/961
(cherry picked from commit 60ebf19c9e)
2020-01-16 08:54:31 +01:00
Jonas Ådahl
e91b12fdf9 wayland: Replace manual GNode subsurface iteration with macro
Similar to wl_list_foreach(), add
META_WAYLAND_SURFACE_FOREACH_SUBSURFACE() that iterates over all the
subsurfaces of a surface, without the caller needing to care about
implementation details, such as leaf nodes vs non-leaf nodes.

https://gitlab.gnome.org/GNOME/mutter/merge_requests/961
(cherry picked from commit fcfe90aa9f)
2020-01-16 08:54:31 +01:00
Jonas Ådahl
f52c0a3bf7 wayland/egl-stream: Cache texture snippet
While it's not very relevant now, as we would rarely create it anyway
since the buffer nor texture never changes for a surface, it will be in
the future, as the actor state (including its content,
MetaShapedTexture) will be synchronized by the MetaWaylandActorSurface
at a later point in time, and not by MetaWaylandSurface, at state
application time.

https://gitlab.gnome.org/GNOME/mutter/merge_requests/961
(cherry picked from commit 76ee026caa)
2020-01-16 08:54:31 +01:00
Umarzuki Bin Mochlis Moktar
78a45e1813 Update Malay translation 2020-01-08 15:06:57 +00:00
Florian Müllner
4947e8ae5b Bump version to 3.34.3
Update NEWS.
2020-01-05 12:37:05 +01:00
Sebastian Keller
5724310899 clutter/stage: Fix picking of rectangles with negative positions
FLT_MIN is the smallest *positive* number above 0 that can be
represented as floating point number. If this is used to initialize the
maximum x/y coordinates of a rectangle, this will always be used if all
x/y coordinates of the rectangle are negative. This means that picking
at 0,0 will always be a hit for such rectangles.

Since mutter creates such a window for server side decorations on X11,
this window will always be picked at 0,0 preventing clicking/hovering
the activities button in gnome-shell at that coordinate.

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


(cherry picked from commit 674f52ba74)
2019-12-24 16:52:37 +00:00
Pascal Nowack
9772f084bf screen-cast: Fix window recording on HiDPI
Using the same scale for the window as the
logical monitor only works correctly when having
the experimental 'scale-monitor-framebuffer'
feature enabled.
Without this experimental feature, the stream
will contain a black screen, where the actual
window only takes a small part of it.

Therefore, use a scale of 1 for the non-
experimental case.

Patch is based on commit 3fa6a92cc5.

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


(cherry picked from commit e89cea8e5a)
2019-12-18 19:54:03 +00:00
47 changed files with 2655 additions and 3183 deletions

53
NEWS
View File

@@ -1,3 +1,56 @@
3.34.6
======
* Fix various clipboard issues [Carlos; !1198, !1203, !1204, !1186, !1206]
* Fix locate-pointer feature interfering with keybindings [Carlos; !1014]
* Fix overview key on X11 when using multiple keyboard layouts [Olivier; !1219]
* Preserve keyboard state on VT switch [Olivier; !1185]
* Fixed crashes [Florian; #1083]
* Plugged memory leaks [Sebastian; !1001]
* Misc. bug fixes and cleanups [Pekka, Laurent; !1209, #1074]
Contributors:
Laurent Bigonville, Olivier Fourdan, Carlos Garnacho, Sebastian Keller,
Florian Müllner, Pekka Paalanen
3.34.5
======
* Fix visibility of initially hidden windows [Jonas; !1066]
* Fix hardware cursor on GPU hotplug [Pekka; !1097]
* Fix pasting images from wayland [Robert, Carlos; !1141, #1065]
* Fixed crashes [Florian, Olivier, Jonas; #1029, !1073, !1121, !1120]
Contributors:
Olivier Fourdan, Carlos Garnacho, Robert Mader, Florian Müllner,
Pekka Paalanen, Jonas Ådahl
Translators:
Yi-Jyun Pan [zh_TW]
3.34.4
======
* Handle mode set race conditions more gracefully [Jonas; !1007]
* Fix fallback to GLES2 [Adam; #635]
* Fix interoperation with wl_data_device_manager v1 [Carlos; #965]
* Fix visual glitches with offscreen effects applied [Georges; !992]
* Favor text over images in clipboard manager [Carlos; #919]
* Fixes crashes [Jonas, Carlos; !961, !869]
* Plugged memory leaks [Sebastian, Adam; !1002, !1011]
* Misc. bug fixes [Carlos, Robert, Olivier; !1005, #878, !1031, !1034, !1040]
Contributors:
Olivier Fourdan, Carlos Garnacho, Adam Jackson, Sebastian Keller,
Robert Mader, Georges Basile Stavracas Neto, Jonas Ådahl
Translators:
Umarzuki Bin Mochlis Moktar [ms]
3.34.3
======
* Fix window recording on HiDPI [Pascal; !976]
* Fix top-left pixel being insensitive to clicks [Sebastian; #893]
Contributors:
Sebastian Keller, Pascal Nowack
3.34.2
======
* Fix immediate screen blank after releasing inhibitor [Tim; #573]

View File

@@ -121,12 +121,12 @@ G_DEFINE_TYPE (ClutterBrightnessContrastEffect,
static gboolean
will_have_no_effect (ClutterBrightnessContrastEffect *self)
{
return (self->brightness_red == no_change &&
self->brightness_green == no_change &&
self->brightness_blue == no_change &&
self->contrast_red == no_change &&
self->contrast_green == no_change &&
self->contrast_blue == no_change);
return (G_APPROX_VALUE (self->brightness_red, no_change, FLT_EPSILON) &&
G_APPROX_VALUE (self->brightness_green, no_change, FLT_EPSILON) &&
G_APPROX_VALUE (self->brightness_blue, no_change, FLT_EPSILON) &&
G_APPROX_VALUE (self->contrast_red, no_change, FLT_EPSILON) &&
G_APPROX_VALUE (self->contrast_green, no_change, FLT_EPSILON) &&
G_APPROX_VALUE (self->contrast_blue, no_change, FLT_EPSILON));
}
static gboolean
@@ -494,9 +494,9 @@ clutter_brightness_contrast_effect_set_brightness_full (ClutterBrightnessContras
{
g_return_if_fail (CLUTTER_IS_BRIGHTNESS_CONTRAST_EFFECT (effect));
if (red == effect->brightness_red &&
green == effect->brightness_green &&
blue == effect->brightness_blue)
if (G_APPROX_VALUE (red, effect->brightness_red, FLT_EPSILON) &&
G_APPROX_VALUE (green, effect->brightness_green, FLT_EPSILON) &&
G_APPROX_VALUE (blue, effect->brightness_blue, FLT_EPSILON))
return;
effect->brightness_red = red;
@@ -584,9 +584,9 @@ clutter_brightness_contrast_effect_set_contrast_full (ClutterBrightnessContrastE
{
g_return_if_fail (CLUTTER_IS_BRIGHTNESS_CONTRAST_EFFECT (effect));
if (red == effect->contrast_red &&
green == effect->contrast_green &&
blue == effect->contrast_blue)
if (G_APPROX_VALUE (red, effect->contrast_red, FLT_EPSILON) &&
G_APPROX_VALUE (green, effect->contrast_green, FLT_EPSILON) &&
G_APPROX_VALUE (blue, effect->contrast_blue, FLT_EPSILON))
return;
effect->contrast_red = red;

View File

@@ -117,11 +117,7 @@ clutter_offscreen_effect_set_actor (ClutterActorMeta *meta,
meta_class->set_actor (meta, actor);
/* clear out the previous state */
if (priv->offscreen != NULL)
{
cogl_handle_unref (priv->offscreen);
priv->offscreen = NULL;
}
g_clear_pointer (&priv->offscreen, cogl_object_unref);
/* we keep a back pointer here, to avoid going through the ActorMeta */
priv->actor = clutter_actor_meta_get_actor (meta);
@@ -197,17 +193,8 @@ update_fbo (ClutterEffect *effect,
ensure_pipeline_filter_for_scale (self, resource_scale);
}
if (priv->texture != NULL)
{
cogl_handle_unref (priv->texture);
priv->texture = NULL;
}
if (priv->offscreen != NULL)
{
cogl_handle_unref (priv->offscreen);
priv->offscreen = NULL;
}
g_clear_pointer (&priv->texture, cogl_object_unref);
g_clear_pointer (&priv->offscreen, cogl_object_unref);
priv->texture =
clutter_offscreen_effect_create_texture (self, target_width, target_height);
@@ -471,29 +458,44 @@ clutter_offscreen_effect_paint (ClutterEffect *effect,
*/
if (priv->offscreen == NULL || (flags & CLUTTER_EFFECT_PAINT_ACTOR_DIRTY))
{
/* Chain up to the parent paint method which will call the pre and
post paint functions to update the image */
CLUTTER_EFFECT_CLASS (clutter_offscreen_effect_parent_class)->
paint (effect, flags);
ClutterEffectClass *effect_class = CLUTTER_EFFECT_GET_CLASS (effect);
gboolean pre_paint_succeeded;
pre_paint_succeeded = effect_class->pre_paint (effect);
clutter_actor_continue_paint (priv->actor);
if (pre_paint_succeeded)
effect_class->post_paint (effect);
else
g_clear_pointer (&priv->offscreen, cogl_object_unref);
}
else
clutter_offscreen_effect_paint_texture (self);
}
static void
clutter_offscreen_effect_notify (GObject *gobject,
GParamSpec *pspec)
{
ClutterOffscreenEffect *offscreen_effect = CLUTTER_OFFSCREEN_EFFECT (gobject);
ClutterOffscreenEffectPrivate *priv = offscreen_effect->priv;
if (strcmp (pspec->name, "enabled") == 0)
g_clear_pointer (&priv->offscreen, cogl_object_unref);
G_OBJECT_CLASS (clutter_offscreen_effect_parent_class)->notify (gobject, pspec);
}
static void
clutter_offscreen_effect_finalize (GObject *gobject)
{
ClutterOffscreenEffect *self = CLUTTER_OFFSCREEN_EFFECT (gobject);
ClutterOffscreenEffectPrivate *priv = self->priv;
if (priv->offscreen)
cogl_handle_unref (priv->offscreen);
if (priv->target)
cogl_handle_unref (priv->target);
if (priv->texture)
cogl_handle_unref (priv->texture);
g_clear_pointer (&priv->offscreen, cogl_object_unref);
g_clear_pointer (&priv->texture, cogl_object_unref);
g_clear_pointer (&priv->target, cogl_object_unref);
G_OBJECT_CLASS (clutter_offscreen_effect_parent_class)->finalize (gobject);
}
@@ -515,6 +517,7 @@ clutter_offscreen_effect_class_init (ClutterOffscreenEffectClass *klass)
effect_class->paint = clutter_offscreen_effect_paint;
gobject_class->finalize = clutter_offscreen_effect_finalize;
gobject_class->notify = clutter_offscreen_effect_notify;
}
static void

View File

@@ -486,9 +486,9 @@ is_inside_axis_aligned_rectangle (const ClutterPoint *point,
const ClutterPoint *vertices)
{
float min_x = FLT_MAX;
float max_x = FLT_MIN;
float max_x = -FLT_MAX;
float min_y = FLT_MAX;
float max_y = FLT_MIN;
float max_y = -FLT_MAX;
int i;
for (i = 0; i < 3; i++)

View File

@@ -329,6 +329,8 @@ try_create_context (CoglDisplay *display,
if (renderer->driver == COGL_DRIVER_GL ||
renderer->driver == COGL_DRIVER_GL3)
eglBindAPI (EGL_OPENGL_API);
else if (renderer->driver == COGL_DRIVER_GLES2)
eglBindAPI (EGL_OPENGL_ES_API);
egl_attributes_from_framebuffer_config (display,
&display->onscreen_template->config,

View File

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

4250
po/ms.po

File diff suppressed because it is too large Load Diff

View File

@@ -10,8 +10,8 @@ msgid ""
msgstr ""
"Project-Id-Version: metacity 3.3.4\n"
"Report-Msgid-Bugs-To: https://gitlab.gnome.org/GNOME/mutter/issues\n"
"POT-Creation-Date: 2019-02-04 17:52+0000\n"
"PO-Revision-Date: 2019-02-17 23:15+0800\n"
"POT-Creation-Date: 2019-11-21 15:22+0000\n"
"PO-Revision-Date: 2019-11-23 13:58+0800\n"
"Last-Translator: pan93412 <pan93412@gmail.com>\n"
"Language-Team: Chinese <zh-l10n@linux.org.tw>\n"
"Language: zh_TW\n"
@@ -19,7 +19,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=1; plural=0;\n"
"X-Generator: Lokalize 18.12.2\n"
"X-Generator: Lokalize 19.11.80\n"
#: data/50-mutter-navigation.xml:6
msgid "Navigation"
@@ -371,6 +371,16 @@ msgid "Enable experimental features"
msgstr "啟用試驗性功能"
#: data/org.gnome.mutter.gschema.xml.in:108
#| msgid ""
#| "To enable experimental features, add the feature keyword to the list. "
#| "Whether the feature requires restarting the compositor depends on the "
#| "given feature. Any experimental feature is not required to still be "
#| "available, or configurable. Dont expect adding anything in this setting "
#| "to be future 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."
msgid ""
"To enable experimental features, add the feature keyword to the list. "
"Whether the feature requires restarting the compositor depends on the given "
@@ -379,27 +389,41 @@ 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."
"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 ""
"若要啟用實驗性功能,請將功能關鍵字加入列表中。置於該功能是否須要重新啟動混成"
"器則視給予的功能而定。任何實驗性功能不一定能用、或是可以調整設定。請不要預期"
"在此設定中加入的任何東西未來都能存在。目前可用的關鍵字有: • “scale-monitor-"
"framebuffer— 讓 mutter 預設採用邏輯像素座標空間的配置邏輯螢幕,而縮放螢幕 "
"framebuffer 則取代視窗內容以管理 HiDPI 螢幕。不要重新啟動。"
"在此設定中加入的任何東西未來都能存在。目前可用的關鍵字有:"
"• 「scale-monitor-framebuffer— 讓 mutter 預設採用邏輯像素座標空間的"
"配置邏輯螢幕,而縮放螢幕 framebuffer 則取代視窗內容以管理 HiDPI 螢幕。不要重新啟動。"
"• 「rt-scheduler」— 讓 mutter 請求低優先級的即時排程。可執行檔或使用者必須要有"
"CAP_SYS_NICE。需要重新啟動。"
"• 「autostart-xwayland」— 如果有 X11 用戶端就延遲初始化 Xwayland。需要重新啟動。"
#: data/org.gnome.mutter.gschema.xml.in:141
#: data/org.gnome.mutter.gschema.xml.in:134
msgid "Modifier to use to locate the pointer"
msgstr "要用來定位指標的輔助鍵"
#: 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:155
msgid "Select window from tab popup"
msgstr "從分頁彈出項選擇視窗"
#: data/org.gnome.mutter.gschema.xml.in:146
#: data/org.gnome.mutter.gschema.xml.in:160
msgid "Cancel tab popup"
msgstr "取消分頁彈出項"
#: data/org.gnome.mutter.gschema.xml.in:151
#: data/org.gnome.mutter.gschema.xml.in:165
msgid "Switch monitor configurations"
msgstr "切換螢幕組態"
#: data/org.gnome.mutter.gschema.xml.in:156
#: data/org.gnome.mutter.gschema.xml.in:170
msgid "Rotates the built-in monitor configuration"
msgstr "旋轉切換內建螢幕組態"
@@ -456,26 +480,38 @@ msgid "Re-enable shortcuts"
msgstr "重新啟用快捷鍵"
#: data/org.gnome.mutter.wayland.gschema.xml.in:64
msgid "Allow grabs with Xwayland"
msgstr "在 Xwayland 允許抓取"
#| msgid "Allow grabs with Xwayland"
msgid "Allow X11 grabs to lock keyboard focus with Xwayland"
msgstr "允許 X11 抓取以使用 Xwayland 鎖定鍵盤焦點"
#: data/org.gnome.mutter.wayland.gschema.xml.in:65
#, fuzzy
#| 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”."
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 ""
"考慮到在 Xwayland 中執行的 X11 應用程序發出的鍵盤抓取。對於在 Wayland 下考慮"
"的 X11 抓取,客戶端也必須送出一個特定的 X11 ClientMessage 到 root 視窗或者在 "
"xwayland-grab-access-rules 鍵白名單其中的應用程式"
"xwayland-grab-access-rules 鍵白名單其中的應用程式"
#: 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 "Xwayland 應用程式允許發出鍵盤抓取"
#: 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 "
@@ -499,7 +535,7 @@ msgstr ""
#. TRANSLATORS: This string refers to a button that switches between
#. * different modes.
#.
#: src/backends/meta-input-settings.c:2423
#: src/backends/meta-input-settings.c:2532
#, c-format
msgid "Mode Switch (Group %d)"
msgstr "模式切換( 群組 %d)"
@@ -507,121 +543,124 @@ msgstr "模式切換( 群組 %d)"
#. TRANSLATORS: This string refers to an action, cycles drawing tablets'
#. * mapping through the available outputs.
#.
#: src/backends/meta-input-settings.c:2446
#: src/backends/meta-input-settings.c:2555
msgid "Switch monitor"
msgstr "切換螢幕"
#: src/backends/meta-input-settings.c:2448
#: src/backends/meta-input-settings.c:2557
msgid "Show on-screen help"
msgstr "顯示螢幕求助"
#: src/backends/meta-monitor-manager.c:954
#: src/backends/meta-monitor.c:223
msgid "Built-in display"
msgstr "內建顯示"
#: src/backends/meta-monitor-manager.c:986
#: src/backends/meta-monitor.c:252
msgid "Unknown"
msgstr "不明"
#: src/backends/meta-monitor-manager.c:988
#: src/backends/meta-monitor.c:254
msgid "Unknown Display"
msgstr "不明的顯示器"
#: src/backends/meta-monitor-manager.c:996
#: src/backends/meta-monitor.c:262
#, 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-manager.c:1004
#: src/backends/meta-monitor.c:270
#, 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:82
msgid "Compositor"
msgstr "合成器"
# FIXME: I'm still unclear about the meaning of XGetSelectionOwner -- Abel
#. 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:482
#: src/compositor/compositor.c:509
#, c-format
msgid ""
"Another compositing manager is already running on screen %i on display “%s”."
msgstr "在畫面「%2$s」中的第 %1$i 個螢幕中已啟動另一個組合視窗管理員。"
#: src/core/bell.c:252
#: src/core/bell.c:192
msgid "Bell event"
msgstr "響鈴事件"
#: src/core/main.c:185
#: src/core/main.c:190
msgid "Disable connection to session manager"
msgstr "停用到作業階段管理員的連線"
#: src/core/main.c:191
#: src/core/main.c:196
msgid "Replace the running window manager"
msgstr "取代執行中的視窗管理員"
#: src/core/main.c:197
#: src/core/main.c:202
msgid "Specify session management ID"
msgstr "指定作業階段管理 ID"
#: src/core/main.c:202
#: src/core/main.c:207
msgid "X Display to use"
msgstr "使用的 X 畫面"
#: src/core/main.c:208
#: src/core/main.c:213
msgid "Initialize session from savefile"
msgstr "以 savefile 初始化作業階段"
#: src/core/main.c:214
#: src/core/main.c:219
msgid "Make X calls synchronous"
msgstr "使用同步方式調用 X 函式"
#: src/core/main.c:221
#: src/core/main.c:226
msgid "Run as a wayland compositor"
msgstr "以 wayland 組合器執行"
#: src/core/main.c:227
#: src/core/main.c:232
msgid "Run as a nested compositor"
msgstr "以巢狀組合器執行"
#: src/core/main.c:233
#: src/core/main.c:238
msgid "Run wayland compositor without starting Xwayland"
msgstr "在不啟動 Xwayland 的情況下開啟 Wayland 合成器"
#: src/core/main.c:241
#: src/core/main.c:246
msgid "Run as a full display server, rather than nested"
msgstr "以完全顯示伺服器執行,而非巢狀"
#: src/core/main.c:247
#: src/core/main.c:252
msgid "Run with X11 backend"
msgstr "透過 X11 後端執行"
#. Translators: %s is a window title
#: src/core/meta-close-dialog-default.c:150
#: src/core/meta-close-dialog-default.c:151
#, c-format
msgid "“%s” is not responding."
msgstr "「%s」沒有回應。"
#: src/core/meta-close-dialog-default.c:152
#: src/core/meta-close-dialog-default.c:153
msgid "Application is not responding."
msgstr "應用程式沒有回應。"
#: src/core/meta-close-dialog-default.c:157
#: 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 "您可以選擇稍等一下讓它繼續,或者強制完全退出程式。"
#: src/core/meta-close-dialog-default.c:164
#: src/core/meta-close-dialog-default.c:165
msgid "_Force Quit"
msgstr "強制退出(_F)"
#: src/core/meta-close-dialog-default.c:164
#: src/core/meta-close-dialog-default.c:165
msgid "_Wait"
msgstr "等待(_W)"
@@ -648,21 +687,21 @@ msgid "Mutter plugin to use"
msgstr "要使用的 Mutter 外掛程式"
# (Abel) take care of the same string in libwnck
#: src/core/prefs.c:1786
#: src/core/prefs.c:1849
#, c-format
msgid "Workspace %d"
msgstr "工作區 %d"
#: src/core/util.c:121
#: src/core/util.c:122
msgid "Mutter was compiled without support for verbose mode\n"
msgstr "編譯 Mutter 時並沒有加入詳細偵錯模式的支援\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 "模式切換:模式 %d"
#: src/x11/meta-x11-display.c:666
#: src/x11/meta-x11-display.c:679
#, c-format
msgid ""
"Display “%s” already has a window manager; try using the --replace option to "
@@ -671,27 +710,32 @@ msgstr ""
"畫面「%s」已經有了視窗管理員請嘗試使用 --replace 選項來替換目前的視窗管理"
"員。"
#: src/x11/meta-x11-display.c:1008
#: src/x11/meta-x11-display.c:1040
msgid "Failed to initialize GDK\n"
msgstr "無法初始化 GDK\n"
#: src/x11/meta-x11-display.c:1032
#: src/x11/meta-x11-display.c:1064
#, c-format
msgid "Failed to open X Window System display “%s”\n"
msgstr "無法開啟 X Window 系統畫面「%s」\n"
#: src/x11/meta-x11-display.c:1115
#: src/x11/meta-x11-display.c:1147
#, c-format
msgid "Screen %d on display “%s” is invalid\n"
msgstr "畫面「%2$s」中的第 %1$d 個螢幕無效\n"
#: src/x11/meta-x11-selection-input-stream.c:445
#, c-format
msgid "Format %s not supported"
msgstr "不支援 %s 格式"
#: 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."
msgstr "這些視窗不支援「儲存目前的設定」,必須在下次登入後自行啟動。"
#: src/x11/window-props.c:568
#: src/x11/window-props.c:569
#, c-format
msgid "%s (on %s)"
msgstr "%s在 %s"

View File

@@ -226,11 +226,15 @@ meta_screen_cast_window_stream_initable_init (GInitable *initable,
G_CALLBACK (on_window_unmanaged),
window_stream);
if (meta_is_stage_views_scaled ())
scale = (int) ceilf (meta_logical_monitor_get_scale (logical_monitor));
else
scale = 1;
/* We cannot set the stream size to the exact size of the window, because
* windows can be resized, whereas streams cannot.
* So we set a size equals to the size of the logical monitor for the window.
*/
scale = (int) ceil (meta_logical_monitor_get_scale (logical_monitor));
window_stream->logical_width = logical_monitor->rect.width;
window_stream->logical_height = logical_monitor->rect.height;
window_stream->stream_width = logical_monitor->rect.width * scale;

View File

@@ -2,6 +2,7 @@
/*
* Copyright (C) 2014 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
@@ -1176,6 +1177,42 @@ on_monitors_changed (MetaMonitorManager *monitors,
force_update_hw_cursor (native);
}
static void
init_hw_cursor_support_for_gpu (MetaGpuKms *gpu_kms)
{
MetaCursorRendererNativeGpuData *cursor_renderer_gpu_data;
int kms_fd;
struct gbm_device *gbm_device;
uint64_t width, height;
gbm_device = meta_gbm_device_from_gpu (gpu_kms);
if (!gbm_device)
return;
cursor_renderer_gpu_data =
meta_create_cursor_renderer_native_gpu_data (gpu_kms);
kms_fd = meta_gpu_kms_get_fd (gpu_kms);
if (drmGetCap (kms_fd, DRM_CAP_CURSOR_WIDTH, &width) == 0 &&
drmGetCap (kms_fd, DRM_CAP_CURSOR_HEIGHT, &height) == 0)
{
cursor_renderer_gpu_data->cursor_width = width;
cursor_renderer_gpu_data->cursor_height = height;
}
else
{
cursor_renderer_gpu_data->cursor_width = 64;
cursor_renderer_gpu_data->cursor_height = 64;
}
}
static void
on_gpu_added_for_cursor (MetaBackend *backend,
MetaGpuKms *gpu_kms)
{
init_hw_cursor_support_for_gpu (gpu_kms);
}
static void
init_hw_cursor_support (MetaCursorRendererNative *cursor_renderer_native)
{
@@ -1188,30 +1225,8 @@ init_hw_cursor_support (MetaCursorRendererNative *cursor_renderer_native)
for (l = gpus; l; l = l->next)
{
MetaGpuKms *gpu_kms = l->data;
MetaCursorRendererNativeGpuData *cursor_renderer_gpu_data;
int kms_fd;
struct gbm_device *gbm_device;
uint64_t width, height;
gbm_device = meta_gbm_device_from_gpu (gpu_kms);
if (!gbm_device)
continue;
cursor_renderer_gpu_data =
meta_create_cursor_renderer_native_gpu_data (gpu_kms);
kms_fd = meta_gpu_kms_get_fd (gpu_kms);
if (drmGetCap (kms_fd, DRM_CAP_CURSOR_WIDTH, &width) == 0 &&
drmGetCap (kms_fd, DRM_CAP_CURSOR_HEIGHT, &height) == 0)
{
cursor_renderer_gpu_data->cursor_width = width;
cursor_renderer_gpu_data->cursor_height = height;
}
else
{
cursor_renderer_gpu_data->cursor_width = 64;
cursor_renderer_gpu_data->cursor_height = 64;
}
init_hw_cursor_support_for_gpu (gpu_kms);
}
}
@@ -1231,6 +1246,8 @@ meta_cursor_renderer_native_new (MetaBackend *backend)
g_signal_connect_object (monitor_manager, "monitors-changed-internal",
G_CALLBACK (on_monitors_changed),
cursor_renderer_native, 0);
g_signal_connect (backend, "gpu-added",
G_CALLBACK (on_gpu_added_for_cursor), NULL);
priv->backend = backend;
priv->hw_state_invalidated = TRUE;

View File

@@ -326,6 +326,16 @@ meta_kms_impl_device_update_states (MetaKmsImplDevice *impl_device)
meta_assert_in_kms_impl (meta_kms_impl_get_kms (impl_device->impl));
drm_resources = drmModeGetResources (impl_device->fd);
if (!drm_resources)
{
g_list_free_full (impl_device->planes, g_object_unref);
g_list_free_full (impl_device->crtcs, g_object_unref);
g_list_free_full (impl_device->connectors, g_object_unref);
impl_device->planes = NULL;
impl_device->crtcs = NULL;
impl_device->connectors = NULL;
return;
}
update_connectors (impl_device, drm_resources);

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
@@ -247,7 +247,8 @@ process_mode_set (MetaKmsImpl *impl,
if (ret != 0)
{
g_set_error (error, G_IO_ERROR, g_io_error_from_errno (-ret),
"Failed to set mode on CRTC %u: %s",
"Failed to set mode %s on CRTC %u: %s",
mode_set->drm_mode ? mode_set->drm_mode->name : "off",
meta_kms_crtc_get_id (crtc),
g_strerror (-ret));
return FALSE;
@@ -323,6 +324,13 @@ retry_page_flip_data_free (RetryPageFlipData *retry_page_flip_data)
g_free (retry_page_flip_data);
}
static CachedModeSet *
get_cached_mode_set (MetaKmsImplSimple *impl_simple,
MetaKmsCrtc *crtc)
{
return g_hash_table_lookup (impl_simple->cached_mode_sets, crtc);
}
static float
get_cached_crtc_refresh_rate (MetaKmsImplSimple *impl_simple,
MetaKmsCrtc *crtc)
@@ -642,16 +650,35 @@ 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)
{
float refresh_rate;
CachedModeSet *cached_mode_set;
refresh_rate = get_cached_crtc_refresh_rate (impl_simple, crtc);
schedule_retry_page_flip (impl_simple,
crtc,
plane_assignment->fb_id,
refresh_rate,
page_flip_data);
cached_mode_set = get_cached_mode_set (impl_simple, crtc);
if (cached_mode_set)
{
drmModeModeInfo *drm_mode;
float refresh_rate;
drm_mode = cached_mode_set->drm_mode;
refresh_rate = meta_calculate_drm_mode_refresh_rate (drm_mode);
schedule_retry_page_flip (impl_simple,
crtc,
plane_assignment->fb_id,
refresh_rate,
page_flip_data);
}
else
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"Page flip of %u failed, and no mode set available",
meta_kms_crtc_get_id (crtc));
meta_kms_page_flip_data_unref (page_flip_data);
return FALSE;
}
}
else if (ret == -EINVAL)
{

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
@@ -385,6 +386,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

@@ -82,6 +82,9 @@ paint_egl_image (MetaGles3 *gles3,
0, 0, width, height,
GL_COLOR_BUFFER_BIT,
GL_NEAREST));
GLBAS (gles3, glDeleteTextures, (1, &texture));
GLBAS (gles3, glDeleteFramebuffers, (1, &framebuffer));
}
gboolean

View File

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

View File

@@ -896,12 +896,16 @@ meta_stage_x11_translate_event (MetaStageX11 *stage_x11,
g_debug ("Client message for stage, win:0x%x",
(unsigned int) xevent->xany.window);
if (handle_wm_protocols_event (backend_x11, stage_x11, xevent))
if (xevent->xclient.message_type == backend_x11->atom_WM_PROTOCOLS)
{
event->any.type = CLUTTER_DELETE;
event->any.stage = stage;
res = TRUE;
if (handle_wm_protocols_event (backend_x11, stage_x11, xevent))
{
event->any.type = CLUTTER_DELETE;
event->any.stage = stage;
res = TRUE;
}
}
break;
default:

View File

@@ -63,7 +63,6 @@
#include "clutter/clutter-mutter.h"
#include "cogl/cogl-trace.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/core.h"
@@ -83,6 +82,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
@@ -607,6 +607,7 @@ meta_compositor_add_window (MetaCompositor *compositor,
window_actor = g_object_new (window_actor_type,
"meta-window", window,
"show-on-set-parent", FALSE,
NULL);
if (window->layer == META_LAYER_OVERRIDE_REDIRECT)

View File

@@ -243,6 +243,8 @@ meta_shaped_texture_dispose (GObject *object)
meta_shaped_texture_set_mask_texture (stex, NULL);
meta_shaped_texture_reset_pipelines (stex);
g_clear_pointer (&stex->opaque_region, cairo_region_destroy);
g_clear_pointer (&stex->snippet, cogl_object_unref);
G_OBJECT_CLASS (meta_shaped_texture_parent_class)->dispose (object);
@@ -458,16 +460,11 @@ set_cogl_texture (MetaShapedTexture *stex,
{
int width, height;
g_return_if_fail (META_IS_SHAPED_TEXTURE (stex));
if (stex->texture)
cogl_object_unref (stex->texture);
stex->texture = cogl_tex;
cogl_clear_object (&stex->texture);
if (cogl_tex != NULL)
{
cogl_object_ref (cogl_tex);
stex->texture = cogl_object_ref (cogl_tex);
width = cogl_texture_get_width (COGL_TEXTURE (cogl_tex));
height = cogl_texture_get_height (COGL_TEXTURE (cogl_tex));
}
@@ -937,6 +934,9 @@ meta_shaped_texture_set_texture (MetaShapedTexture *stex,
{
g_return_if_fail (META_IS_SHAPED_TEXTURE (stex));
if (stex->texture == texture)
return;
set_cogl_texture (stex, texture);
}

View File

@@ -63,6 +63,15 @@
#define META_KEY_BINDING_PRIMARY_LAYOUT 0
#define META_KEY_BINDING_SECONDARY_LAYOUT 1
/* Only for special modifier keys */
#define IGNORED_MODIFIERS (CLUTTER_LOCK_MASK | \
CLUTTER_MOD2_MASK | \
CLUTTER_BUTTON1_MASK | \
CLUTTER_BUTTON2_MASK | \
CLUTTER_BUTTON3_MASK | \
CLUTTER_BUTTON4_MASK | \
CLUTTER_BUTTON5_MASK)
static gboolean add_builtin_keybinding (MetaDisplay *display,
const char *name,
GSettings *settings,
@@ -2114,6 +2123,7 @@ process_special_modifier_key (MetaDisplay *display,
return TRUE;
}
else if (event->type == CLUTTER_KEY_PRESS &&
((event->modifier_state & ~(IGNORED_MODIFIERS)) & CLUTTER_MODIFIER_MASK) == 0 &&
resolved_key_combo_has_keycode (resolved_key_combo,
event->hardware_keycode))
{

View File

@@ -32,9 +32,15 @@ static struct {
const char *mimetype_glob;
ssize_t max_transfer_size;
} supported_mimetypes[] = {
{ "image/tiff", MAX_IMAGE_SIZE },
{ "image/bmp", MAX_IMAGE_SIZE },
{ "image/gif", MAX_IMAGE_SIZE },
{ "image/jpeg", MAX_IMAGE_SIZE },
{ "image/webp", MAX_IMAGE_SIZE },
{ "image/png", MAX_IMAGE_SIZE },
{ "image/svg+xml", MAX_IMAGE_SIZE },
{ "text/plain", MAX_TEXT_SIZE },
{ "text/plain;charset=utf-8", MAX_TEXT_SIZE },
{ "image/*", MAX_IMAGE_SIZE },
};
static gboolean

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_class_init (MetaSelectionClass *klass)
{
@@ -198,6 +202,7 @@ write_cb (GOutputStream *stream,
GAsyncResult *result,
GTask *task)
{
TransferRequest *request;
GError *error = NULL;
g_output_stream_write_bytes_finish (stream, result, &error);
@@ -208,8 +213,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
@@ -228,8 +242,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,
@@ -239,6 +271,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,
@@ -271,12 +315,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);
}
}
@@ -345,3 +384,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

@@ -1289,7 +1289,10 @@ _meta_window_shared_new (MetaDisplay *display,
window->initial_workspace);
}
set_workspace_state (window, on_all_workspaces, workspace);
/* Ignore when a window requests to be placed on a non-existent workspace
*/
if (on_all_workspaces || workspace != NULL)
set_workspace_state (window, on_all_workspaces, workspace);
}
/* override-redirect windows are subtly different from other windows
@@ -1308,7 +1311,7 @@ _meta_window_shared_new (MetaDisplay *display,
g_warn_if_fail (!window->transient_for->override_redirect);
set_workspace_state (window,
should_be_on_all_workspaces (window->transient_for),
window->transient_for->on_all_workspaces,
window->transient_for->workspace);
}
else if (window->on_all_workspaces)

View File

@@ -28,6 +28,7 @@
#include "compositor/meta-surface-actor-wayland.h"
#include "compositor/meta-window-actor-wayland.h"
#include "compositor/region-utils.h"
#include "wayland/meta-wayland-buffer.h"
#include "wayland/meta-wayland-surface.h"
#include "wayland/meta-window-wayland.h"
@@ -147,13 +148,33 @@ meta_wayland_actor_surface_real_sync_actor_state (MetaWaylandActorSurface *actor
meta_wayland_surface_role_get_surface (surface_role);
MetaSurfaceActor *surface_actor;
MetaShapedTexture *stex;
GNode *n;
MetaWaylandBuffer *buffer;
cairo_rectangle_int_t surface_rect;
int geometry_scale;
MetaWaylandSurface *subsurface_surface;
surface_actor = priv->actor;
stex = meta_surface_actor_get_texture (surface_actor);
meta_shaped_texture_set_buffer_scale (stex, surface->scale);
buffer = surface->buffer_ref.buffer;
if (buffer)
{
CoglSnippet *snippet;
gboolean is_y_inverted;
snippet = meta_wayland_buffer_create_snippet (buffer);
is_y_inverted = meta_wayland_buffer_is_y_inverted (buffer);
meta_shaped_texture_set_texture (stex, surface->texture);
meta_shaped_texture_set_snippet (stex, snippet);
meta_shaped_texture_set_is_y_inverted (stex, is_y_inverted);
meta_shaped_texture_set_buffer_scale (stex, surface->scale);
cogl_clear_object (&snippet);
}
else
{
meta_shaped_texture_set_texture (stex, NULL);
}
/* Wayland surface coordinate space -> stage coordinate space */
geometry_scale = meta_wayland_actor_surface_get_geometry_scale (actor_surface);
@@ -213,19 +234,12 @@ meta_wayland_actor_surface_real_sync_actor_state (MetaWaylandActorSurface *actor
meta_surface_actor_reset_viewport_dst_size (surface_actor);
}
for (n = g_node_first_child (surface->subsurface_branch_node);
n;
n = g_node_next_sibling (n))
META_WAYLAND_SURFACE_FOREACH_SUBSURFACE (surface, subsurface_surface)
{
MetaWaylandSurface *subsurface_surface = n->data;
MetaWaylandActorSurface *subsurface_actor_surface;
MetaWaylandActorSurface *actor_surface;
if (G_NODE_IS_LEAF (n))
continue;
subsurface_actor_surface =
META_WAYLAND_ACTOR_SURFACE (subsurface_surface->role);
meta_wayland_actor_surface_sync_actor_state (subsurface_actor_surface);
actor_surface = META_WAYLAND_ACTOR_SURFACE (subsurface_surface->role);
meta_wayland_actor_surface_sync_actor_state (actor_surface);
}
}
@@ -278,6 +292,9 @@ meta_wayland_actor_surface_is_on_logical_monitor (MetaWaylandSurfaceRole *surfac
MetaRectangle logical_monitor_layout;
gboolean is_on_monitor;
if (!clutter_actor_is_mapped (actor))
return FALSE;
clutter_actor_get_transformed_position (actor, &x, &y);
clutter_actor_get_transformed_size (actor, &width, &height);
@@ -355,6 +372,16 @@ meta_wayland_actor_surface_reset_actor (MetaWaylandActorSurface *actor_surface)
meta_wayland_actor_surface_get_instance_private (actor_surface);
MetaWaylandSurface *surface =
meta_wayland_surface_role_get_surface (META_WAYLAND_SURFACE_ROLE (actor_surface));
MetaWaylandSurface *subsurface_surface;
META_WAYLAND_SURFACE_FOREACH_SUBSURFACE (surface, subsurface_surface)
{
MetaWaylandActorSurface *actor_surface;
actor_surface = META_WAYLAND_ACTOR_SURFACE (subsurface_surface->role);
meta_wayland_actor_surface_reset_actor (actor_surface);
meta_wayland_actor_surface_sync_actor_state (actor_surface);
}
clear_surface_actor (actor_surface);

View File

@@ -198,7 +198,6 @@ shm_buffer_get_cogl_pixel_format (struct wl_shm_buffer *shm_buffer,
static gboolean
shm_buffer_attach (MetaWaylandBuffer *buffer,
CoglTexture **texture,
gboolean *changed_texture,
GError **error)
{
MetaBackend *backend = meta_get_backend ();
@@ -224,7 +223,6 @@ shm_buffer_attach (MetaWaylandBuffer *buffer,
_cogl_texture_get_format (*texture) == format)
{
buffer->is_y_inverted = TRUE;
*changed_texture = FALSE;
return TRUE;
}
@@ -269,7 +267,6 @@ shm_buffer_attach (MetaWaylandBuffer *buffer,
return FALSE;
*texture = new_texture;
*changed_texture = TRUE;
buffer->is_y_inverted = TRUE;
return TRUE;
@@ -278,7 +275,6 @@ shm_buffer_attach (MetaWaylandBuffer *buffer,
static gboolean
egl_image_buffer_attach (MetaWaylandBuffer *buffer,
CoglTexture **texture,
gboolean *changed_texture,
GError **error)
{
MetaBackend *backend = meta_get_backend ();
@@ -294,7 +290,6 @@ egl_image_buffer_attach (MetaWaylandBuffer *buffer,
if (buffer->egl_image.texture)
{
*changed_texture = *texture != buffer->egl_image.texture;
cogl_clear_object (texture);
*texture = cogl_object_ref (buffer->egl_image.texture);
return TRUE;
@@ -362,7 +357,6 @@ egl_image_buffer_attach (MetaWaylandBuffer *buffer,
cogl_clear_object (texture);
*texture = cogl_object_ref (buffer->egl_image.texture);
*changed_texture = TRUE;
return TRUE;
}
@@ -371,7 +365,6 @@ egl_image_buffer_attach (MetaWaylandBuffer *buffer,
static gboolean
egl_stream_buffer_attach (MetaWaylandBuffer *buffer,
CoglTexture **texture,
gboolean *changed_texture,
GError **error)
{
MetaWaylandEglStream *stream = buffer->egl_stream.stream;
@@ -381,7 +374,6 @@ egl_stream_buffer_attach (MetaWaylandBuffer *buffer,
if (!meta_wayland_egl_stream_attach (stream, error))
return FALSE;
*changed_texture = *texture != buffer->egl_stream.texture;
cogl_clear_object (texture);
*texture = cogl_object_ref (buffer->egl_stream.texture);
@@ -411,7 +403,6 @@ egl_stream_buffer_attach (MetaWaylandBuffer *buffer,
gboolean
meta_wayland_buffer_attach (MetaWaylandBuffer *buffer,
CoglTexture **texture,
gboolean *changed_texture,
GError **error)
{
g_return_val_if_fail (buffer->resource, FALSE);
@@ -428,17 +419,16 @@ meta_wayland_buffer_attach (MetaWaylandBuffer *buffer,
switch (buffer->type)
{
case META_WAYLAND_BUFFER_TYPE_SHM:
return shm_buffer_attach (buffer, texture, changed_texture, error);
return shm_buffer_attach (buffer, texture, error);
case META_WAYLAND_BUFFER_TYPE_EGL_IMAGE:
return egl_image_buffer_attach (buffer, texture, changed_texture, error);
return egl_image_buffer_attach (buffer, texture, error);
#ifdef HAVE_WAYLAND_EGLSTREAM
case META_WAYLAND_BUFFER_TYPE_EGL_STREAM:
return egl_stream_buffer_attach (buffer, texture, changed_texture, error);
return egl_stream_buffer_attach (buffer, texture, error);
#endif
case META_WAYLAND_BUFFER_TYPE_DMA_BUF:
return meta_wayland_dma_buf_buffer_attach (buffer,
texture,
changed_texture,
error);
case META_WAYLAND_BUFFER_TYPE_UNKNOWN:
g_assert_not_reached ();
@@ -456,7 +446,7 @@ meta_wayland_buffer_create_snippet (MetaWaylandBuffer *buffer)
if (!buffer->egl_stream.stream)
return NULL;
return meta_wayland_egl_stream_create_snippet ();
return meta_wayland_egl_stream_create_snippet (buffer->egl_stream.stream);
#else
return NULL;
#endif /* HAVE_WAYLAND_EGLSTREAM */

View File

@@ -82,7 +82,6 @@ gboolean meta_wayland_buffer_is_realized (MetaWaylandBuff
gboolean meta_wayland_buffer_realize (MetaWaylandBuffer *buffer);
gboolean meta_wayland_buffer_attach (MetaWaylandBuffer *buffer,
CoglTexture **texture,
gboolean *changed_texture,
GError **error);
CoglSnippet * meta_wayland_buffer_create_snippet (MetaWaylandBuffer *buffer);
gboolean meta_wayland_buffer_is_y_inverted (MetaWaylandBuffer *buffer);

View File

@@ -25,16 +25,10 @@
#ifndef META_WAYLAND_DATA_DEVICE_PRIVATE_H
#define META_WAYLAND_DATA_DEVICE_PRIVATE_H
#define META_TYPE_WAYLAND_DATA_SOURCE_WAYLAND (meta_wayland_data_source_wayland_get_type ())
G_DECLARE_FINAL_TYPE (MetaWaylandDataSourceWayland,
meta_wayland_data_source_wayland,
META, WAYLAND_DATA_SOURCE_WAYLAND,
MetaWaylandDataSource);
#define META_TYPE_WAYLAND_DATA_SOURCE_PRIMARY (meta_wayland_data_source_primary_get_type ())
G_DECLARE_FINAL_TYPE (MetaWaylandDataSourcePrimary,
meta_wayland_data_source_primary,
META, WAYLAND_DATA_SOURCE_PRIMARY,
MetaWaylandDataSourceWayland);
MetaWaylandDataSource);
#endif /* META_WAYLAND_DATA_DEVICE_PRIVATE_H */

View File

@@ -65,6 +65,7 @@ struct _MetaWaylandDataOffer
typedef struct _MetaWaylandDataSourcePrivate
{
struct wl_resource *resource;
MetaWaylandDataOffer *offer;
struct wl_array mime_types;
gboolean has_target;
@@ -74,35 +75,30 @@ typedef struct _MetaWaylandDataSourcePrivate
MetaWaylandSeat *seat;
guint actions_set : 1;
guint in_ask : 1;
guint drop_performed : 1;
} MetaWaylandDataSourcePrivate;
typedef struct _MetaWaylandDataSourceWayland
{
MetaWaylandDataSource parent;
struct wl_resource *resource;
} MetaWaylandDataSourceWayland;
typedef struct _MetaWaylandDataSourcePrimary
{
MetaWaylandDataSourceWayland parent;
MetaWaylandDataSource parent;
} MetaWaylandDataSourcePrimary;
G_DEFINE_TYPE_WITH_PRIVATE (MetaWaylandDataSource, meta_wayland_data_source,
G_TYPE_OBJECT);
G_DEFINE_TYPE (MetaWaylandDataSourceWayland, meta_wayland_data_source_wayland,
META_TYPE_WAYLAND_DATA_SOURCE);
G_DEFINE_TYPE (MetaWaylandDataSourcePrimary, meta_wayland_data_source_primary,
META_TYPE_WAYLAND_DATA_SOURCE_WAYLAND);
META_TYPE_WAYLAND_DATA_SOURCE);
static void unset_selection_source (MetaWaylandDataDevice *data_device,
MetaSelectionType selection_type);
static MetaWaylandDataSource *
meta_wayland_data_source_wayland_new (struct wl_resource *resource);
meta_wayland_data_source_new (struct wl_resource *resource);
static MetaWaylandDataSource *
meta_wayland_data_source_primary_new (struct wl_resource *resource);
static void
meta_wayland_source_cancel (MetaWaylandDataSource *source);
static void
drag_grab_data_source_destroyed (gpointer data, GObject *where_the_object_was);
@@ -110,6 +106,31 @@ static struct wl_resource * create_and_send_clipboard_offer (MetaWaylandDataDevi
struct wl_resource *target);
static struct wl_resource * create_and_send_primary_offer (MetaWaylandDataDevice *data_device,
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)
@@ -142,6 +163,10 @@ data_offer_choose_action (MetaWaylandDataOffer *offer)
MetaWaylandDataSource *source = offer->source;
uint32_t actions, user_action, available_actions;
if (wl_resource_get_version (offer->resource) <
WL_DATA_OFFER_ACTION_SINCE_VERSION)
return WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY;
actions = meta_wayland_data_source_get_actions (source);
user_action = meta_wayland_data_source_get_user_action (source);
@@ -189,6 +214,25 @@ data_offer_update_action (MetaWaylandDataOffer *offer)
}
}
static struct wl_resource *
meta_wayland_data_source_get_resource (MetaWaylandDataSource *source)
{
MetaWaylandDataSourcePrivate *priv =
meta_wayland_data_source_get_instance_private (source);
return priv->resource;
}
static void
meta_wayland_data_source_set_resource (MetaWaylandDataSource *source,
struct wl_resource *resource)
{
MetaWaylandDataSourcePrivate *priv =
meta_wayland_data_source_get_instance_private (source);
priv->resource = resource;
}
static void
meta_wayland_data_source_target (MetaWaylandDataSource *source,
const char *mime_type)
@@ -334,9 +378,9 @@ meta_wayland_data_source_set_actions (MetaWaylandDataSource *source,
priv->actions_set = TRUE;
}
static void
meta_wayland_data_source_set_user_action (MetaWaylandDataSource *source,
enum wl_data_device_manager_dnd_action action)
void
meta_wayland_data_source_set_user_action (MetaWaylandDataSource *source,
uint32_t action)
{
MetaWaylandDataSourcePrivate *priv =
meta_wayland_data_source_get_instance_private (source);
@@ -352,6 +396,15 @@ meta_wayland_data_source_set_user_action (MetaWaylandDataSource
data_offer_update_action (offer);
}
static gboolean
meta_wayland_data_source_get_drop_performed (MetaWaylandDataSource *source)
{
MetaWaylandDataSourcePrivate *priv =
meta_wayland_data_source_get_instance_private (source);
return priv->drop_performed;
}
static void
data_offer_accept (struct wl_client *client,
struct wl_resource *resource,
@@ -566,12 +619,19 @@ destroy_data_offer (struct wl_resource *resource)
if (offer == meta_wayland_data_source_get_current_offer (offer->source))
{
if (seat->data_device.dnd_data_source == offer->source &&
wl_resource_get_version (offer->resource) <
WL_DATA_OFFER_ACTION_SINCE_VERSION)
meta_wayland_data_source_notify_finish (offer->source);
if (seat->data_device.dnd_data_source == offer->source)
{
if (wl_resource_get_version (offer->resource) <
WL_DATA_OFFER_ACTION_SINCE_VERSION)
meta_wayland_data_source_notify_finish (offer->source);
else if (meta_wayland_data_source_get_drop_performed (offer->source))
meta_wayland_source_cancel (offer->source);
}
else
meta_wayland_data_source_set_current_offer (offer->source, NULL);
{
meta_wayland_data_source_set_current_offer (offer->source, NULL);
meta_wayland_data_source_set_has_target (offer->source, FALSE);
}
}
g_object_remove_weak_pointer (G_OBJECT (offer->source),
@@ -654,12 +714,10 @@ data_source_set_actions (struct wl_client *client,
MetaWaylandDataSource *source = wl_resource_get_user_data (resource);
MetaWaylandDataSourcePrivate *priv =
meta_wayland_data_source_get_instance_private (source);
MetaWaylandDataSourceWayland *source_wayland =
META_WAYLAND_DATA_SOURCE_WAYLAND (source);
if (priv->actions_set)
{
wl_resource_post_error (source_wayland->resource,
wl_resource_post_error (priv->resource,
WL_DATA_SOURCE_ERROR_INVALID_ACTION_MASK,
"cannot set actions more than once");
return;
@@ -667,7 +725,7 @@ data_source_set_actions (struct wl_client *client,
if (dnd_actions & ~(ALL_ACTIONS))
{
wl_resource_post_error (source_wayland->resource,
wl_resource_post_error (priv->resource,
WL_DATA_SOURCE_ERROR_INVALID_ACTION_MASK,
"invalid actions mask %x", dnd_actions);
return;
@@ -675,7 +733,7 @@ data_source_set_actions (struct wl_client *client,
if (meta_wayland_data_source_get_seat (source))
{
wl_resource_post_error (source_wayland->resource,
wl_resource_post_error (priv->resource,
WL_DATA_SOURCE_ERROR_INVALID_ACTION_MASK,
"invalid action change after "
"wl_data_device.start_drag");
@@ -867,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);
@@ -1018,7 +1082,7 @@ meta_wayland_data_source_fake_read (MetaWaylandDataSource *source,
static void
drag_grab_button (MetaWaylandPointerGrab *grab,
const ClutterEvent *event)
const ClutterEvent *event)
{
MetaWaylandDragGrab *drag_grab = (MetaWaylandDragGrab*) grab;
MetaWaylandSeat *seat = drag_grab->seat;
@@ -1031,7 +1095,6 @@ drag_grab_button (MetaWaylandPointerGrab *grab,
gboolean success;
if (drag_grab->drag_focus && source &&
meta_wayland_data_source_get_current_offer (source) &&
meta_wayland_data_source_has_target (source) &&
meta_wayland_data_source_get_current_action (source))
{
@@ -1055,10 +1118,11 @@ drag_grab_button (MetaWaylandPointerGrab *grab,
}
else
{
meta_wayland_data_source_set_current_offer (source, NULL);
if (source)
meta_wayland_data_source_set_current_offer (source, NULL);
meta_wayland_data_device_set_dnd_source (&seat->data_device, NULL);
unset_selection_source (&seat->data_device, META_SELECTION_DND);
success= FALSE;
success = FALSE;
}
/* Finish drag and let actor self-destruct */
@@ -1297,20 +1361,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);
}
@@ -1319,10 +1371,10 @@ meta_wayland_source_send (MetaWaylandDataSource *source,
const gchar *mime_type,
gint fd)
{
MetaWaylandDataSourceWayland *source_wayland =
META_WAYLAND_DATA_SOURCE_WAYLAND (source);
MetaWaylandDataSourcePrivate *priv =
meta_wayland_data_source_get_instance_private (source);
wl_data_source_send_send (source_wayland->resource, mime_type, fd);
wl_data_source_send_send (priv->resource, mime_type, fd);
close (fd);
}
@@ -1330,43 +1382,48 @@ static void
meta_wayland_source_target (MetaWaylandDataSource *source,
const gchar *mime_type)
{
MetaWaylandDataSourceWayland *source_wayland =
META_WAYLAND_DATA_SOURCE_WAYLAND (source);
MetaWaylandDataSourcePrivate *priv =
meta_wayland_data_source_get_instance_private (source);
wl_data_source_send_target (source_wayland->resource, mime_type);
wl_data_source_send_target (priv->resource, mime_type);
}
static void
meta_wayland_source_cancel (MetaWaylandDataSource *source)
{
MetaWaylandDataSourceWayland *source_wayland =
META_WAYLAND_DATA_SOURCE_WAYLAND (source);
MetaWaylandDataSourcePrivate *priv =
meta_wayland_data_source_get_instance_private (source);
if (source_wayland->resource)
wl_data_source_send_cancelled (source_wayland->resource);
if (!priv->resource)
return;
wl_data_source_send_cancelled (priv->resource);
}
static void
meta_wayland_source_action (MetaWaylandDataSource *source,
enum wl_data_device_manager_dnd_action action)
{
MetaWaylandDataSourceWayland *source_wayland =
META_WAYLAND_DATA_SOURCE_WAYLAND (source);
MetaWaylandDataSourcePrivate *priv =
meta_wayland_data_source_get_instance_private (source);
if (wl_resource_get_version (source_wayland->resource) >=
if (wl_resource_get_version (priv->resource) >=
WL_DATA_SOURCE_ACTION_SINCE_VERSION)
wl_data_source_send_action (source_wayland->resource, action);
wl_data_source_send_action (priv->resource, action);
}
static void
meta_wayland_source_drop_performed (MetaWaylandDataSource *source)
{
MetaWaylandDataSourceWayland *source_wayland =
META_WAYLAND_DATA_SOURCE_WAYLAND (source);
MetaWaylandDataSourcePrivate *priv =
meta_wayland_data_source_get_instance_private (source);
if (wl_resource_get_version (source_wayland->resource) >=
if (wl_resource_get_version (priv->resource) >=
WL_DATA_SOURCE_DND_DROP_PERFORMED_SINCE_VERSION)
wl_data_source_send_dnd_drop_performed (source_wayland->resource);
{
priv->drop_performed = TRUE;
wl_data_source_send_dnd_drop_performed (priv->resource);
}
}
static void
@@ -1374,8 +1431,8 @@ meta_wayland_source_drag_finished (MetaWaylandDataSource *source)
{
MetaWaylandCompositor *compositor = meta_wayland_compositor_get_default ();
MetaWaylandDataDevice *data_device = &compositor->seat->data_device;
MetaWaylandDataSourceWayland *source_wayland =
META_WAYLAND_DATA_SOURCE_WAYLAND (source);
MetaWaylandDataSourcePrivate *priv =
meta_wayland_data_source_get_instance_private (source);
enum wl_data_device_manager_dnd_action action;
if (meta_wayland_source_get_in_ask (source))
@@ -1384,81 +1441,15 @@ meta_wayland_source_drag_finished (MetaWaylandDataSource *source)
meta_wayland_source_action (source, action);
}
if (wl_resource_get_version (source_wayland->resource) >=
if (wl_resource_get_version (priv->resource) >=
WL_DATA_SOURCE_DND_FINISHED_SINCE_VERSION)
wl_data_source_send_dnd_finished (source_wayland->resource);
wl_data_source_send_dnd_finished (priv->resource);
unset_selection_source (data_device, META_SELECTION_DND);
}
static void
meta_wayland_source_finalize (GObject *object)
{
G_OBJECT_CLASS (meta_wayland_data_source_wayland_parent_class)->finalize (object);
}
static void
meta_wayland_data_source_wayland_init (MetaWaylandDataSourceWayland *source_wayland)
{
}
static void
meta_wayland_data_source_wayland_class_init (MetaWaylandDataSourceWaylandClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
MetaWaylandDataSourceClass *data_source_class =
META_WAYLAND_DATA_SOURCE_CLASS (klass);
object_class->finalize = meta_wayland_source_finalize;
data_source_class->send = meta_wayland_source_send;
data_source_class->target = meta_wayland_source_target;
data_source_class->cancel = meta_wayland_source_cancel;
data_source_class->action = meta_wayland_source_action;
data_source_class->drop_performed = meta_wayland_source_drop_performed;
data_source_class->drag_finished = meta_wayland_source_drag_finished;
}
static void
meta_wayland_data_source_primary_send (MetaWaylandDataSource *source,
const gchar *mime_type,
gint fd)
{
MetaWaylandDataSourceWayland *source_wayland;
source_wayland = META_WAYLAND_DATA_SOURCE_WAYLAND (source);
gtk_primary_selection_source_send_send (source_wayland->resource,
mime_type, fd);
close (fd);
}
static void
meta_wayland_data_source_primary_cancel (MetaWaylandDataSource *source)
{
MetaWaylandDataSourceWayland *source_wayland;
source_wayland = META_WAYLAND_DATA_SOURCE_WAYLAND (source);
if (source_wayland->resource)
gtk_primary_selection_source_send_cancelled (source_wayland->resource);
}
static void
meta_wayland_data_source_primary_init (MetaWaylandDataSourcePrimary *source_primary)
{
}
static void
meta_wayland_data_source_primary_class_init (MetaWaylandDataSourcePrimaryClass *klass)
{
MetaWaylandDataSourceClass *data_source_class =
META_WAYLAND_DATA_SOURCE_CLASS (klass);
data_source_class->send = meta_wayland_data_source_primary_send;
data_source_class->cancel = meta_wayland_data_source_primary_cancel;
}
static void
meta_wayland_data_source_finalize (GObject *object)
{
MetaWaylandDataSource *source = META_WAYLAND_DATA_SOURCE (object);
MetaWaylandDataSourcePrivate *priv =
@@ -1480,6 +1471,7 @@ meta_wayland_data_source_init (MetaWaylandDataSource *source)
wl_array_init (&priv->mime_types);
priv->current_dnd_action = -1;
priv->drop_performed = FALSE;
}
static void
@@ -1487,7 +1479,49 @@ meta_wayland_data_source_class_init (MetaWaylandDataSourceClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->finalize = meta_wayland_data_source_finalize;
object_class->finalize = meta_wayland_source_finalize;
klass->send = meta_wayland_source_send;
klass->target = meta_wayland_source_target;
klass->cancel = meta_wayland_source_cancel;
klass->action = meta_wayland_source_action;
klass->drop_performed = meta_wayland_source_drop_performed;
klass->drag_finished = meta_wayland_source_drag_finished;
}
static void
meta_wayland_data_source_primary_send (MetaWaylandDataSource *source,
const gchar *mime_type,
gint fd)
{
struct wl_resource *resource = meta_wayland_data_source_get_resource (source);
gtk_primary_selection_source_send_send (resource, mime_type, fd);
close (fd);
}
static void
meta_wayland_data_source_primary_cancel (MetaWaylandDataSource *source)
{
struct wl_resource *resource = meta_wayland_data_source_get_resource (source);
if (resource)
gtk_primary_selection_source_send_cancelled (resource);
}
static void
meta_wayland_data_source_primary_init (MetaWaylandDataSourcePrimary *source_primary)
{
}
static void
meta_wayland_data_source_primary_class_init (MetaWaylandDataSourcePrimaryClass *klass)
{
MetaWaylandDataSourceClass *data_source_class =
META_WAYLAND_DATA_SOURCE_CLASS (klass);
data_source_class->send = meta_wayland_data_source_primary_send;
data_source_class->cancel = meta_wayland_data_source_primary_cancel;
}
static void
@@ -1630,8 +1664,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 &&
@@ -1640,7 +1672,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);
@@ -1667,18 +1698,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
@@ -1688,6 +1707,7 @@ data_device_set_selection (struct wl_client *client,
guint32 serial)
{
MetaWaylandDataDevice *data_device = wl_resource_get_user_data (resource);
MetaWaylandSeat *seat = wl_container_of (data_device, seat, data_device);
MetaWaylandDataSourcePrivate *priv;
MetaWaylandDataSource *source;
@@ -1709,6 +1729,10 @@ data_device_set_selection (struct wl_client *client,
}
}
if (wl_resource_get_client (resource) !=
meta_wayland_keyboard_get_focus_client (seat->keyboard))
return;
/* FIXME: Store serial and check against incoming serial here. */
meta_wayland_data_device_set_selection (data_device, source, serial);
}
@@ -1724,21 +1748,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);
}
@@ -1748,20 +1759,9 @@ 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;
if (META_IS_WAYLAND_DATA_SOURCE_PRIMARY (source))
{
struct wl_resource *resource;
resource = META_WAYLAND_DATA_SOURCE_WAYLAND (source)->resource;
if (wl_resource_get_client (resource) !=
meta_wayland_keyboard_get_focus_client (seat->keyboard))
return;
}
g_assert (!source || META_IS_WAYLAND_DATA_SOURCE_PRIMARY (source));
if (data_device->primary_data_source &&
data_device->primary_serial - serial < UINT32_MAX / 2)
@@ -1769,7 +1769,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);
@@ -1795,18 +1794,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
@@ -1816,10 +1803,16 @@ primary_device_set_selection (struct wl_client *client,
uint32_t serial)
{
MetaWaylandDataDevice *data_device = wl_resource_get_user_data (resource);
MetaWaylandSeat *seat = wl_container_of (data_device, seat, data_device);
MetaWaylandDataSource *source = NULL;
if (source_resource)
source = wl_resource_get_user_data (source_resource);
if (wl_resource_get_client (resource) !=
meta_wayland_keyboard_get_focus_client (seat->keyboard))
return;
meta_wayland_data_device_set_primary (data_device, source, serial);
}
@@ -1831,9 +1824,9 @@ static const struct gtk_primary_selection_device_interface primary_device_interf
static void
destroy_data_source (struct wl_resource *resource)
{
MetaWaylandDataSourceWayland *source = wl_resource_get_user_data (resource);
MetaWaylandDataSource *source = wl_resource_get_user_data (resource);
source->resource = NULL;
meta_wayland_data_source_set_resource (source, NULL);
g_object_unref (source);
}
@@ -1845,7 +1838,7 @@ create_data_source (struct wl_client *client,
source_resource = wl_resource_create (client, &wl_data_source_interface,
wl_resource_get_version (resource), id);
meta_wayland_data_source_wayland_new (source_resource);
meta_wayland_data_source_new (source_resource);
}
static void
@@ -1865,10 +1858,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;
@@ -1884,10 +1874,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;
@@ -1937,9 +1924,9 @@ static const struct wl_data_device_manager_interface manager_interface = {
static void
destroy_primary_source (struct wl_resource *resource)
{
MetaWaylandDataSourceWayland *source = wl_resource_get_user_data (resource);
MetaWaylandDataSource *source = wl_resource_get_user_data (resource);
source->resource = NULL;
meta_wayland_data_source_set_resource (source, NULL);
g_object_unref (source);
}
@@ -2022,7 +2009,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 *
@@ -2104,22 +2093,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);
}
@@ -2157,29 +2158,37 @@ meta_wayland_data_source_has_mime_type (const MetaWaylandDataSource *source,
}
static MetaWaylandDataSource *
meta_wayland_data_source_wayland_new (struct wl_resource *resource)
meta_wayland_data_source_new (struct wl_resource *resource)
{
MetaWaylandDataSourceWayland *source_wayland =
g_object_new (META_TYPE_WAYLAND_DATA_SOURCE_WAYLAND, NULL);
MetaWaylandDataSource *source =
g_object_new (META_TYPE_WAYLAND_DATA_SOURCE, NULL);
MetaWaylandDataSourcePrivate *priv =
meta_wayland_data_source_get_instance_private (source);
source_wayland->resource = resource;
meta_wayland_data_source_set_resource (source, resource);
wl_resource_set_implementation (resource, &data_source_interface,
source_wayland, destroy_data_source);
source, destroy_data_source);
return META_WAYLAND_DATA_SOURCE (source_wayland);
if (wl_resource_get_version (resource) < WL_DATA_SOURCE_ACTION_SINCE_VERSION)
{
priv->dnd_actions = priv->user_dnd_action =
WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY;
}
return source;
}
static MetaWaylandDataSource *
meta_wayland_data_source_primary_new (struct wl_resource *resource)
{
MetaWaylandDataSourceWayland *source_primary =
MetaWaylandDataSource *source_primary =
g_object_new (META_TYPE_WAYLAND_DATA_SOURCE_PRIMARY, NULL);
source_primary->resource = resource;
meta_wayland_data_source_set_resource (source_primary, resource);
wl_resource_set_implementation (resource, &primary_source_interface,
source_primary, destroy_primary_source);
return META_WAYLAND_DATA_SOURCE (source_primary);
return source_primary;
}
gboolean

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;
@@ -121,6 +123,8 @@ uint32_t meta_wayland_data_source_get_current_action (MetaWaylandDataSource *sou
void meta_wayland_data_source_set_actions (MetaWaylandDataSource *source,
uint32_t dnd_actions);
void meta_wayland_data_source_set_user_action (MetaWaylandDataSource *source,
uint32_t action);
void meta_wayland_data_source_set_current_action (MetaWaylandDataSource *source,
uint32_t action);

View File

@@ -158,13 +158,11 @@ meta_wayland_dma_buf_realize_texture (MetaWaylandBuffer *buffer,
gboolean
meta_wayland_dma_buf_buffer_attach (MetaWaylandBuffer *buffer,
CoglTexture **texture,
gboolean *changed_texture,
GError **error)
{
if (!meta_wayland_dma_buf_realize_texture (buffer, error))
return FALSE;
*changed_texture = *texture != buffer->dma_buf.texture;
cogl_clear_object (texture);
*texture = cogl_object_ref (buffer->dma_buf.texture);
return TRUE;

View File

@@ -44,7 +44,6 @@ gboolean meta_wayland_dma_buf_init (MetaWaylandCompositor *compositor);
gboolean
meta_wayland_dma_buf_buffer_attach (MetaWaylandBuffer *buffer,
CoglTexture **texture,
gboolean *changed_texture,
GError **error);
MetaWaylandDmaBufBuffer *

View File

@@ -134,6 +134,7 @@ struct _MetaWaylandEglStream
MetaWaylandBuffer *buffer;
CoglTexture2D *texture;
gboolean is_y_inverted;
CoglSnippet *snippet;
};
G_DEFINE_TYPE (MetaWaylandEglStream, meta_wayland_egl_stream,
@@ -289,18 +290,22 @@ meta_wayland_egl_stream_is_y_inverted (MetaWaylandEglStream *stream)
}
CoglSnippet *
meta_wayland_egl_stream_create_snippet (void)
meta_wayland_egl_stream_create_snippet (MetaWaylandEglStream *stream)
{
CoglSnippet *snippet;
if (!stream->snippet)
{
CoglSnippet *snippet;
snippet = cogl_snippet_new (COGL_SNIPPET_HOOK_TEXTURE_LOOKUP,
"uniform samplerExternalOES tex_external;",
NULL);
cogl_snippet_set_replace (snippet,
"cogl_texel = texture2D (tex_external,\n"
" cogl_tex_coord.xy);");
snippet = cogl_snippet_new (COGL_SNIPPET_HOOK_TEXTURE_LOOKUP,
"uniform samplerExternalOES tex_external;",
NULL);
cogl_snippet_set_replace (snippet,
"cogl_texel = texture2D (tex_external,\n"
" cogl_tex_coord.xy);");
stream->snippet = snippet;
}
return snippet;
return cogl_object_ref (stream->snippet);
}
gboolean
@@ -341,6 +346,8 @@ meta_wayland_egl_stream_finalize (GObject *object)
meta_egl_destroy_stream (egl, egl_display, stream->egl_stream, NULL);
cogl_clear_object (&stream->snippet);
G_OBJECT_CLASS (meta_wayland_egl_stream_parent_class)->finalize (object);
}

View File

@@ -47,7 +47,7 @@ gboolean meta_wayland_egl_stream_attach (MetaWaylandEglStream *stream,
CoglTexture2D * meta_wayland_egl_stream_create_texture (MetaWaylandEglStream *stream,
GError **error);
CoglSnippet * meta_wayland_egl_stream_create_snippet (void);
CoglSnippet * meta_wayland_egl_stream_create_snippet (MetaWaylandEglStream *stream);
gboolean meta_wayland_egl_stream_is_y_inverted (MetaWaylandEglStream *stream);

View File

@@ -599,7 +599,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);
@@ -913,7 +912,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

@@ -434,7 +434,7 @@ zxdg_toplevel_v6_set_fullscreen (struct wl_client *client,
if (output_resource)
{
MetaWaylandOutput *output = wl_resource_get_user_data (output_resource);
if (output)
if (output && output->logical_monitor)
meta_window_move_to_monitor (window, output->logical_monitor->number);
}

View File

@@ -1209,20 +1209,13 @@ static gboolean
pointer_can_grab_surface (MetaWaylandPointer *pointer,
MetaWaylandSurface *surface)
{
GNode *n;
MetaWaylandSurface *subsurface;
if (pointer->focus_surface == surface)
return TRUE;
for (n = g_node_first_child (surface->subsurface_branch_node);
n;
n = g_node_next_sibling (n))
META_WAYLAND_SURFACE_FOREACH_SUBSURFACE (surface, subsurface)
{
MetaWaylandSurface *subsurface = n->data;
if (G_NODE_IS_LEAF (n))
continue;
if (pointer_can_grab_surface (pointer, subsurface))
return TRUE;
}

View File

@@ -43,23 +43,17 @@ meta_wayland_shell_surface_calculate_geometry (MetaWaylandShellSurface *shell_su
MetaWaylandSurface *surface =
meta_wayland_surface_role_get_surface (surface_role);
MetaRectangle geometry;
GNode *n;
MetaWaylandSurface *subsurface_surface;
geometry = (MetaRectangle) {
.width = meta_wayland_surface_get_width (surface),
.height = meta_wayland_surface_get_height (surface),
};
for (n = g_node_first_child (surface->subsurface_branch_node);
n;
n = g_node_next_sibling (n))
META_WAYLAND_SURFACE_FOREACH_SUBSURFACE (surface, subsurface_surface)
{
MetaWaylandSurface *subsurface_surface = n->data;
MetaWaylandSubsurface *subsurface;
if (G_NODE_IS_LEAF (n))
continue;
subsurface = META_WAYLAND_SUBSURFACE (subsurface_surface->role);
meta_wayland_subsurface_union_geometry (subsurface,
0, 0,

View File

@@ -85,6 +85,7 @@ sync_actor_subsurface_state (MetaWaylandSurface *surface)
transform_subsurface_position (surface, &x, &y);
clutter_actor_set_position (actor, x, y);
clutter_actor_set_reactive (actor, TRUE);
if (surface->buffer_ref.buffer)
clutter_actor_show (actor);
@@ -198,7 +199,7 @@ meta_wayland_subsurface_union_geometry (MetaWaylandSubsurface *subsurface,
MetaWaylandSurface *surface =
meta_wayland_surface_role_get_surface (surface_role);
MetaRectangle geometry;
GNode *n;
MetaWaylandSurface *subsurface_surface;
geometry = (MetaRectangle) {
.x = surface->offset_x + surface->sub.x,
@@ -209,16 +210,10 @@ meta_wayland_subsurface_union_geometry (MetaWaylandSubsurface *subsurface,
meta_rectangle_union (out_geometry, &geometry, out_geometry);
for (n = g_node_first_child (surface->subsurface_branch_node);
n;
n = g_node_next_sibling (n))
META_WAYLAND_SURFACE_FOREACH_SUBSURFACE (surface, subsurface_surface)
{
MetaWaylandSurface *subsurface_surface = n->data;
MetaWaylandSubsurface *subsurface;
if (G_NODE_IS_LEAF (n))
continue;
subsurface = META_WAYLAND_SUBSURFACE (subsurface_surface->role);
meta_wayland_subsurface_union_geometry (subsurface,
parent_x + geometry.x,
@@ -503,7 +498,6 @@ wl_subcompositor_get_subsurface (struct wl_client *client,
MetaWaylandSurface *parent = wl_resource_get_user_data (parent_resource);
MetaWindow *toplevel_window;
MetaWindowActor *window_actor;
MetaSurfaceActor *surface_actor;
if (surface->wl_subsurface)
{
@@ -552,9 +546,6 @@ wl_subcompositor_get_subsurface (struct wl_client *client,
window_actor = meta_window_actor_wayland_from_surface (surface);
if (window_actor)
meta_window_actor_wayland_rebuild_surface_tree (window_actor);
surface_actor = meta_wayland_surface_get_actor (surface);
clutter_actor_set_reactive (CLUTTER_ACTOR (surface_actor), TRUE);
}
static const struct wl_subcompositor_interface meta_wayland_subcompositor_interface = {

View File

@@ -632,20 +632,6 @@ meta_wayland_surface_is_effectively_synchronized (MetaWaylandSurface *surface)
}
}
static void
parent_surface_state_applied (GNode *subsurface_node,
gpointer user_data)
{
MetaWaylandSurface *surface = subsurface_node->data;
MetaWaylandSubsurface *subsurface;
if (G_NODE_IS_LEAF (subsurface_node))
return;
subsurface = META_WAYLAND_SUBSURFACE (surface->role);
meta_wayland_subsurface_parent_state_applied (subsurface);
}
void
meta_wayland_surface_cache_pending_frame_callbacks (MetaWaylandSurface *surface,
MetaWaylandPendingState *pending)
@@ -659,6 +645,7 @@ void
meta_wayland_surface_apply_pending_state (MetaWaylandSurface *surface,
MetaWaylandPendingState *pending)
{
MetaWaylandSurface *subsurface_surface;
gboolean had_damage = FALSE;
if (surface->role)
@@ -695,11 +682,9 @@ meta_wayland_surface_apply_pending_state (MetaWaylandSurface *surface,
if (pending->buffer)
{
GError *error = NULL;
gboolean changed_texture;
if (!meta_wayland_buffer_attach (pending->buffer,
&surface->texture,
&changed_texture,
&error))
{
g_warning ("Could not import pending buffer: %s", error->message);
@@ -710,24 +695,6 @@ meta_wayland_surface_apply_pending_state (MetaWaylandSurface *surface,
g_error_free (error);
goto cleanup;
}
if (changed_texture && meta_wayland_surface_get_actor (surface))
{
MetaShapedTexture *stex;
CoglTexture *texture;
CoglSnippet *snippet;
gboolean is_y_inverted;
stex = meta_surface_actor_get_texture (meta_wayland_surface_get_actor (surface));
texture = surface->texture;
snippet = meta_wayland_buffer_create_snippet (pending->buffer);
is_y_inverted = meta_wayland_buffer_is_y_inverted (pending->buffer);
meta_shaped_texture_set_texture (stex, texture);
meta_shaped_texture_set_snippet (stex, snippet);
meta_shaped_texture_set_is_y_inverted (stex, is_y_inverted);
g_clear_pointer (&snippet, cogl_object_unref);
}
}
else
{
@@ -832,10 +799,13 @@ cleanup:
pending_state_reset (pending);
g_node_children_foreach (surface->subsurface_branch_node,
G_TRAVERSE_ALL,
parent_surface_state_applied,
NULL);
META_WAYLAND_SURFACE_FOREACH_SUBSURFACE (surface, subsurface_surface)
{
MetaWaylandSubsurface *subsurface;
subsurface = META_WAYLAND_SUBSURFACE (subsurface_surface->role);
meta_wayland_subsurface_parent_state_applied (subsurface);
}
if (had_damage)
{
@@ -1276,22 +1246,14 @@ meta_wayland_surface_update_outputs (MetaWaylandSurface *surface)
static void
meta_wayland_surface_update_outputs_recursively (MetaWaylandSurface *surface)
{
GNode *n;
MetaWaylandSurface *subsurface_surface;
meta_wayland_surface_update_outputs (surface);
for (n = g_node_first_child (surface->subsurface_branch_node);
n;
n = g_node_next_sibling (n))
{
if (G_NODE_IS_LEAF (n))
continue;
meta_wayland_surface_update_outputs_recursively (n->data);
}
META_WAYLAND_SURFACE_FOREACH_SUBSURFACE (surface, subsurface_surface)
meta_wayland_surface_update_outputs_recursively (subsurface_surface);
}
void
meta_wayland_surface_set_window (MetaWaylandSurface *surface,
MetaWindow *window)

View File

@@ -327,4 +327,38 @@ void meta_wayland_surface_notify_geometry_changed (MetaWaylandSur
int meta_wayland_surface_get_width (MetaWaylandSurface *surface);
int meta_wayland_surface_get_height (MetaWaylandSurface *surface);
static inline GNode *
meta_get_next_subsurface_sibling (GNode *n)
{
GNode *next;
if (!n)
return NULL;
next = g_node_next_sibling (n);
if (!next)
return NULL;
if (!G_NODE_IS_LEAF (next))
return next;
else
return meta_get_next_subsurface_sibling (next);
}
static inline GNode *
meta_get_first_subsurface_node (MetaWaylandSurface *surface)
{
GNode *n;
n = g_node_first_child (surface->subsurface_branch_node);
if (!G_NODE_IS_LEAF (n))
return n;
else
return meta_get_next_subsurface_sibling (n);
}
#define META_WAYLAND_SURFACE_FOREACH_SUBSURFACE(surface, subsurface) \
for (GNode *G_PASTE(__n, __LINE__) = meta_get_first_subsurface_node ((surface)); \
(subsurface = (G_PASTE (__n, __LINE__) ? G_PASTE (__n, __LINE__)->data : NULL)); \
G_PASTE (__n, __LINE__) = meta_get_next_subsurface_sibling (G_PASTE (__n, __LINE__)))
#endif

View File

@@ -989,20 +989,13 @@ static gboolean
tablet_tool_can_grab_surface (MetaWaylandTabletTool *tool,
MetaWaylandSurface *surface)
{
GNode *n;
MetaWaylandSurface *subsurface;
if (tool->focus_surface == surface)
return TRUE;
for (n = g_node_first_child (surface->subsurface_branch_node);
n;
n = g_node_next_sibling (n))
META_WAYLAND_SURFACE_FOREACH_SUBSURFACE (surface, subsurface)
{
MetaWaylandSurface *subsurface = n->data;
if (G_NODE_IS_LEAF (n))
continue;
if (tablet_tool_can_grab_surface (tool, subsurface))
return TRUE;
}

View File

@@ -431,7 +431,7 @@ xdg_toplevel_set_fullscreen (struct wl_client *client,
{
MetaWaylandOutput *output = wl_resource_get_user_data (output_resource);
if (output)
if (output && output->logical_monitor)
{
meta_window_move_to_monitor (window,
output->logical_monitor->number);

View File

@@ -562,7 +562,7 @@ meta_xwayland_data_source_fetch_mimetype_list (MetaWaylandDataSource *source,
XGetWindowProperty (xdisplay, window, prop,
0, /* offset */
0x1fffffff, /* length */
True, /* delete */
False, /* delete */
AnyPropertyType,
&type_ret,
&format_ret,
@@ -787,6 +787,10 @@ meta_xwayland_dnd_handle_client_message (MetaWaylandCompositor *compositor,
xdnd_atoms[ATOM_DND_TYPE_LIST]);
}
meta_wayland_data_source_set_actions (dnd->source,
WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY |
WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE |
WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK);
meta_wayland_drag_grab_set_focus (drag_grab, dnd->focus_surface);
return TRUE;
}
@@ -806,7 +810,7 @@ meta_xwayland_dnd_handle_client_message (MetaWaylandCompositor *compositor,
clutter_event_set_time (motion, dnd->last_motion_time);
action = atom_to_action ((Atom) event->data.l[4]);
meta_wayland_data_source_set_actions (dnd->source, action);
meta_wayland_data_source_set_user_action (dnd->source, action);
meta_wayland_surface_drag_dest_motion (drag_focus, motion);
xdnd_send_status (dnd, (Window) event->data.l[0],

View File

@@ -1734,11 +1734,21 @@ process_selection_event (MetaX11Display *x11_display,
handled |= meta_x11_selection_handle_event (x11_display, event);
for (l = x11_display->selection.input_streams; l && !handled; l = l->next)
handled |= meta_x11_selection_input_stream_xevent (l->data, event);
for (l = x11_display->selection.input_streams; l && !handled;)
{
GList *next = l->next;
for (l = x11_display->selection.output_streams; l && !handled; l = l->next)
handled |= meta_x11_selection_output_stream_xevent (l->data, event);
handled |= meta_x11_selection_input_stream_xevent (l->data, event);
l = next;
}
for (l = x11_display->selection.output_streams; l && !handled;)
{
GList *next = l->next;
handled |= meta_x11_selection_output_stream_xevent (l->data, event);
l = next;
}
return handled;
}

View File

@@ -261,6 +261,20 @@ meta_x11_selection_input_stream_close_finish (GInputStream *stream,
return TRUE;
}
static void
meta_x11_selection_input_stream_dispose (GObject *object)
{
MetaX11SelectionInputStream *stream =
META_X11_SELECTION_INPUT_STREAM (object);
MetaX11SelectionInputStreamPrivate *priv =
meta_x11_selection_input_stream_get_instance_private (stream);
priv->x11_display->selection.input_streams =
g_list_remove (priv->x11_display->selection.input_streams, stream);
G_OBJECT_CLASS (meta_x11_selection_input_stream_parent_class)->dispose (object);
}
static void
meta_x11_selection_input_stream_finalize (GObject *object)
{
@@ -284,6 +298,7 @@ meta_x11_selection_input_stream_class_init (MetaX11SelectionInputStreamClass *kl
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GInputStreamClass *istream_class = G_INPUT_STREAM_CLASS (klass);
object_class->dispose = meta_x11_selection_input_stream_dispose;
object_class->finalize = meta_x11_selection_input_stream_finalize;
istream_class->read_fn = meta_x11_selection_input_stream_read;

View File

@@ -57,12 +57,15 @@ struct _MetaX11SelectionOutputStreamPrivate
guint incr : 1;
guint delete_pending : 1;
guint pipe_error : 1;
};
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)
{
@@ -100,6 +103,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;
}
@@ -113,7 +119,7 @@ get_max_request_size (MetaX11Display *display)
if (size <= 0)
size = XMaxRequestSize (display->xdisplay);
return size - 100;
return (size - 100) * 4;
}
static gboolean
@@ -123,7 +129,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;
@@ -171,13 +182,34 @@ get_element_size (int format)
}
}
static gboolean
meta_x11_selection_output_stream_check_pipe (MetaX11SelectionOutputStream *stream,
GError **error)
{
MetaX11SelectionOutputStreamPrivate *priv =
meta_x11_selection_output_stream_get_instance_private (stream);
if (priv->pipe_error)
{
g_set_error (error,
G_IO_ERROR,
G_IO_ERROR_BROKEN_PIPE,
"Connection with client was broken");
return FALSE;
}
return TRUE;
}
static void
meta_x11_selection_output_stream_perform_flush (MetaX11SelectionOutputStream *stream)
{
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);
@@ -190,8 +222,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;
@@ -207,14 +243,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,
@@ -222,30 +266,45 @@ 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);
/* XXX: handle failure here and report EPIPE for future operations on the stream? */
if (meta_x11_error_trap_pop_with_return (priv->x11_display))
g_warning ("Failed to flush selection output stream");
error_code = meta_x11_error_trap_pop_with_return (priv->x11_display);
if (priv->pending_task)
if (error_code != Success)
{
char error_str[100];
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 && 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_object_unref (priv->pending_task);
priv->pending_task = NULL;
g_clear_object (&priv->pending_task);
}
}
@@ -254,12 +313,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
@@ -274,6 +338,9 @@ meta_x11_selection_output_stream_write (GOutputStream *output_stream,
MetaX11SelectionOutputStreamPrivate *priv =
meta_x11_selection_output_stream_get_instance_private (stream);
if (!meta_x11_selection_output_stream_check_pipe (stream, error))
return -1;
g_mutex_lock (&priv->mutex);
g_byte_array_append (priv->data, buffer, count);
g_mutex_unlock (&priv->mutex);
@@ -301,12 +368,19 @@ meta_x11_selection_output_stream_write_async (GOutputStream *output_stream
META_X11_SELECTION_OUTPUT_STREAM (output_stream);
MetaX11SelectionOutputStreamPrivate *priv =
meta_x11_selection_output_stream_get_instance_private (stream);
GError *error = NULL;
GTask *task;
task = g_task_new (stream, cancellable, callback, user_data);
g_task_set_source_tag (task, meta_x11_selection_output_stream_write_async);
g_task_set_priority (task, io_priority);
if (!meta_x11_selection_output_stream_check_pipe (stream, &error))
{
g_task_return_error (task, error);
return;
}
g_mutex_lock (&priv->mutex);
g_byte_array_append (priv->data, buffer, count);
g_mutex_unlock (&priv->mutex);
@@ -317,16 +391,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;
@@ -354,7 +423,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);
@@ -373,6 +442,8 @@ meta_x11_selection_output_stream_flush (GOutputStream *output_stream,
MetaX11SelectionOutputStreamPrivate *priv =
meta_x11_selection_output_stream_get_instance_private (stream);
if (!meta_x11_selection_output_stream_check_pipe (stream, error))
return FALSE;
if (!meta_x11_selection_output_request_flush (stream))
return TRUE;
@@ -398,12 +469,19 @@ meta_x11_selection_output_stream_flush_async (GOutputStream *output_stream
META_X11_SELECTION_OUTPUT_STREAM (output_stream);
MetaX11SelectionOutputStreamPrivate *priv =
meta_x11_selection_output_stream_get_instance_private (stream);
GError *error = NULL;
GTask *task;
task = g_task_new (stream, cancellable, callback, user_data);
g_task_set_source_tag (task, meta_x11_selection_output_stream_flush_async);
g_task_set_priority (task, io_priority);
if (!meta_x11_selection_output_stream_check_pipe (stream, &error))
{
g_task_return_error (task, error);
return;
}
if (!meta_x11_selection_output_stream_can_flush (stream))
{
if (meta_x11_selection_output_request_flush (stream))
@@ -420,10 +498,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
@@ -489,6 +566,20 @@ meta_x11_selection_output_stream_close_finish (GOutputStream *stream,
return g_task_propagate_boolean (G_TASK (result), error);
}
static void
meta_x11_selection_output_stream_dispose (GObject *object)
{
MetaX11SelectionOutputStream *stream =
META_X11_SELECTION_OUTPUT_STREAM (object);
MetaX11SelectionOutputStreamPrivate *priv =
meta_x11_selection_output_stream_get_instance_private (stream);
priv->x11_display->selection.output_streams =
g_list_remove (priv->x11_display->selection.output_streams, stream);
G_OBJECT_CLASS (meta_x11_selection_output_stream_parent_class)->dispose (object);
}
static void
meta_x11_selection_output_stream_finalize (GObject *object)
{
@@ -514,6 +605,7 @@ meta_x11_selection_output_stream_class_init (MetaX11SelectionOutputStreamClass *
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GOutputStreamClass *output_stream_class = G_OUTPUT_STREAM_CLASS (klass);
object_class->dispose = meta_x11_selection_output_stream_dispose;
object_class->finalize = meta_x11_selection_output_stream_finalize;
output_stream_class->write_fn = meta_x11_selection_output_stream_write;

View File

@@ -23,10 +23,22 @@
#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"
#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,
@@ -141,6 +153,45 @@ transfer_cb (MetaSelection *selection,
g_object_unref (output);
}
static char *
meta_x11_selection_find_target (MetaX11Display *x11_display,
MetaSelection *selection,
MetaSelectionType selection_type,
Atom selection_atom)
{
GList* mimetypes = NULL;
const gchar *atom_name;
char *retval;
mimetypes = meta_selection_get_mimetypes (selection, selection_type);
atom_name = gdk_x11_get_xatom_name (selection_atom);
if (g_list_find_custom (mimetypes, atom_name, (GCompareFunc) g_strcmp0))
{
retval = g_strdup (atom_name);
}
else if (strcmp (atom_name, "UTF8_STRING") == 0 &&
g_list_find_custom (mimetypes, UTF8_STRING_MIMETYPE,
(GCompareFunc) g_strcmp0))
{
retval = g_strdup (UTF8_STRING_MIMETYPE);
}
else if (strcmp (atom_name, "STRING") == 0 &&
g_list_find_custom (mimetypes, STRING_MIMETYPE,
(GCompareFunc) g_strcmp0))
{
retval = g_strdup (STRING_MIMETYPE);
}
else
{
retval = NULL;
}
g_list_free_full (mimetypes, g_free);
return retval;
}
static gboolean
meta_x11_selection_handle_selection_request (MetaX11Display *x11_display,
XEvent *xevent)
@@ -197,15 +248,12 @@ meta_x11_selection_handle_selection_request (MetaX11Display *x11_display,
}
else
{
gboolean has_target;
g_autofree char *target = NULL;
mimetypes = meta_selection_get_mimetypes (selection, selection_type);
has_target = g_list_find_custom (mimetypes,
gdk_x11_get_xatom_name (event->target),
(GCompareFunc) g_strcmp0) != NULL;
g_list_free_full (mimetypes, g_free);
target = meta_x11_selection_find_target (x11_display, selection,
selection_type, event->target);
if (has_target)
if (target != NULL)
{
output = meta_x11_selection_output_stream_new (x11_display,
event->requestor,
@@ -217,7 +265,7 @@ meta_x11_selection_handle_selection_request (MetaX11Display *x11_display,
meta_selection_transfer_async (selection,
selection_type,
gdk_x11_get_xatom_name (event->target),
target,
-1,
output,
NULL,
@@ -226,7 +274,9 @@ meta_x11_selection_handle_selection_request (MetaX11Display *x11_display,
return TRUE;
}
else
send_selection_notify (event, FALSE);
{
send_selection_notify (event, FALSE);
}
}
return FALSE;
@@ -254,8 +304,9 @@ 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))
{
@@ -288,16 +339,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;
@@ -331,14 +393,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])
{
@@ -361,6 +422,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;
@@ -381,18 +443,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
@@ -401,7 +469,7 @@ meta_x11_selection_shutdown (MetaX11Display *x11_display)
MetaDisplay *display = meta_get_display ();
g_signal_handlers_disconnect_by_func (meta_display_get_selection (display),
owner_changed_cb,
notify_selection_owner,
x11_display);
if (x11_display->selection.xwindow != None)
{