Compare commits

..

47 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
22 changed files with 534 additions and 233 deletions

27
NEWS
View File

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

View File

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

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

@@ -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
@@ -650,6 +650,9 @@ process_page_flip (MetaKmsImpl *impl,
meta_kms_page_flip_data_ref (page_flip_data));
}
if (ret != 0)
meta_kms_page_flip_data_unref (page_flip_data);
if (ret == -EBUSY)
{
CachedModeSet *cached_mode_set;

View File

@@ -1,5 +1,6 @@
/*
* Copyright (C) 2018 Red Hat
* Copyright 2020 DisplayLink (UK) Ltd.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@@ -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

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

@@ -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,12 +32,12 @@ 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/bmp", MAX_IMAGE_SIZE },
{ "image/tiff", MAX_IMAGE_SIZE },
{ "image/svg+xml", MAX_IMAGE_SIZE },
{ "text/plain", MAX_TEXT_SIZE },
{ "text/plain;charset=utf-8", MAX_TEXT_SIZE },

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

@@ -108,6 +108,30 @@ static struct wl_resource * create_and_send_primary_offer (MetaWaylandDataDevi
struct wl_resource *target);
static struct wl_resource * meta_wayland_data_source_get_resource (MetaWaylandDataSource *source);
static void
move_resources (struct wl_list *destination,
struct wl_list *source)
{
wl_list_insert_list (destination, source);
wl_list_init (source);
}
static void
move_resources_for_client (struct wl_list *destination,
struct wl_list *source,
struct wl_client *client)
{
struct wl_resource *resource, *tmp;
wl_resource_for_each_safe (resource, tmp, source)
{
if (wl_resource_get_client (resource) == client)
{
wl_list_remove (wl_resource_get_link (resource));
wl_list_insert (destination, wl_resource_get_link (resource));
}
}
}
static void
unbind_resource (struct wl_resource *resource)
{
@@ -143,16 +167,8 @@ data_offer_choose_action (MetaWaylandDataOffer *offer)
WL_DATA_OFFER_ACTION_SINCE_VERSION)
return WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY;
if (wl_resource_get_version (meta_wayland_data_source_get_resource (source)) <
WL_DATA_SOURCE_ACTION_SINCE_VERSION)
{
actions = user_action = WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY;
}
else
{
actions = meta_wayland_data_source_get_actions (source);
user_action = meta_wayland_data_source_get_user_action (source);
}
actions = meta_wayland_data_source_get_actions (source);
user_action = meta_wayland_data_source_get_user_action (source);
available_actions = actions & offer->dnd_actions;
@@ -608,11 +624,7 @@ destroy_data_offer (struct wl_resource *resource)
if (wl_resource_get_version (offer->resource) <
WL_DATA_OFFER_ACTION_SINCE_VERSION)
meta_wayland_data_source_notify_finish (offer->source);
else if (meta_wayland_data_source_get_drop_performed (offer->source) &&
meta_wayland_data_source_get_resource(offer->source) &&
wl_resource_get_version(
meta_wayland_data_source_get_resource(offer->source)) >=
WL_DATA_SOURCE_DND_FINISHED_SINCE_VERSION)
else if (meta_wayland_data_source_get_drop_performed (offer->source))
meta_wayland_source_cancel (offer->source);
}
else
@@ -913,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);
@@ -1343,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);
}
@@ -1388,8 +1394,10 @@ meta_wayland_source_cancel (MetaWaylandDataSource *source)
MetaWaylandDataSourcePrivate *priv =
meta_wayland_data_source_get_instance_private (source);
if (priv->resource)
wl_data_source_send_cancelled (priv->resource);
if (!priv->resource)
return;
wl_data_source_send_cancelled (priv->resource);
}
static void
@@ -1410,11 +1418,12 @@ meta_wayland_source_drop_performed (MetaWaylandDataSource *source)
MetaWaylandDataSourcePrivate *priv =
meta_wayland_data_source_get_instance_private (source);
priv->drop_performed = TRUE;
if (wl_resource_get_version (priv->resource) >=
WL_DATA_SOURCE_DND_DROP_PERFORMED_SINCE_VERSION)
wl_data_source_send_dnd_drop_performed (priv->resource);
{
priv->drop_performed = TRUE;
wl_data_source_send_dnd_drop_performed (priv->resource);
}
}
static void
@@ -1655,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 &&
@@ -1665,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);
@@ -1692,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
@@ -1754,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);
}
@@ -1778,8 +1759,6 @@ meta_wayland_data_device_set_primary (MetaWaylandDataDevice *data_device,
guint32 serial)
{
MetaWaylandSeat *seat = wl_container_of (data_device, seat, data_device);
struct wl_resource *data_device_resource;
struct wl_client *focus_client;
MetaSelectionSource *selection_source;
g_assert (!source || META_IS_WAYLAND_DATA_SOURCE_PRIMARY (source));
@@ -1790,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);
@@ -1816,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
@@ -1892,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;
@@ -1911,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;
@@ -2049,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 *
@@ -2131,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);
}
@@ -2188,11 +2162,19 @@ meta_wayland_data_source_new (struct wl_resource *resource)
{
MetaWaylandDataSource *source =
g_object_new (META_TYPE_WAYLAND_DATA_SOURCE, NULL);
MetaWaylandDataSourcePrivate *priv =
meta_wayland_data_source_get_instance_private (source);
meta_wayland_data_source_set_resource (source, resource);
wl_resource_set_implementation (resource, &data_source_interface,
source, destroy_data_source);
if (wl_resource_get_version (resource) < WL_DATA_SOURCE_ACTION_SINCE_VERSION)
{
priv->dnd_actions = priv->user_dnd_action =
WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY;
}
return source;
}

View File

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

View File

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

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

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

View File

@@ -23,6 +23,8 @@
#include <gdk/gdkx.h>
#include "core/meta-selection-private.h"
#include "meta/meta-selection-source-memory.h"
#include "x11/meta-selection-source-x11-private.h"
#include "x11/meta-x11-selection-output-stream-private.h"
#include "x11/meta-x11-selection-private.h"
@@ -30,6 +32,13 @@
#define UTF8_STRING_MIMETYPE "text/plain;charset=utf-8"
#define STRING_MIMETYPE "text/plain"
/* Set an arbitrary (although generous) threshold to determine whether a
* XFixesSelectionNotify corresponds to a XSetSelectionOwner from another
* client. The selection timestamp is not updated if the owner client is
* closed.
*/
#define SELECTION_CLEARED_BY_CLIENT(e) (e->timestamp - e->selection_timestamp < 50)
static gboolean
atom_to_selection_type (Display *xdisplay,
Atom selection,
@@ -295,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))
{
@@ -329,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;
@@ -372,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])
{
@@ -402,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;
@@ -422,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
@@ -442,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)
{