Compare commits

...

103 Commits

Author SHA1 Message Date
Carlos Garnacho
208e292df1 backends/native: Add input thread inside MetaSeatImpl
This (now) doesn't change anything in regards to the API that the UI
thread should access from the MetaSeatImpl. The MetaInputDeviceNative,
MetaInputSettings and MetaKeymap objects are now considered owned by
the input thread, as well as all of libinput objects.

The MetaEventSource now dispatches events in a GMainContext that is
the thread default to this thread, and all UI-thread-accessible API
(seat and virtual input device API) will be handled in a serialized
manner by that same input thread.

The MetaSeatImpl itself is still considered to be owned by the caller
thread, and all the signals that this object emits will be emitted in
the GMainContext that is default at the time of calling
meta_seat_impl_new().

The MetaInputSettings configuration changes will likewise be handled
in the input thread, close to libinput devices.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1403
2020-08-13 21:40:10 +02:00
Carlos Garnacho
548e5138fc backends/native: Make MetaVirtualInputDevice vmethods "async"
These are one-way API calls, that now should get executed in the MetaSeatImpl
context. Use the MetaSeatImpl async task plumbing so that's the case.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1403
2020-08-13 21:40:10 +02:00
Carlos Garnacho
6b8d95d9c4 backends/native: Make some MetaSeatImpl API "async"
This API is the one accessed from different bits of the UI thread,
make it "async" (it's basically one-way setters, so API stays the same
in the surface) and able to run in the MetaSeatImpl main context.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1403
2020-08-13 21:40:10 +02:00
Carlos Garnacho
faec8d29b0 backends/native: Shuffle xkb_keymap creation
Push it a little bit down to the MetaSeatNative. As both the UI thread
and the input thread are interested in dealing with the xkb_keymap and
it is not meant to be used in different threads, keep 2 separate copies
around.

The keyboard map will always be set from the UI thread, so the xkb_keymap
owned by the MetaSeatNative (owned by the UI thread) can be considered
canonical.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1403
2020-08-13 21:40:10 +02:00
Carlos Garnacho
4b88a769d2 backends/native: Seal MetaKeymapNative xkb usage
Don't let the vfuncs (meant to be called from the UI thread) deal with
xkb state itself. Instead store the current state in struct fields, which
is then fetched in vfuncs.

This makes the keymap able to be used from the UI thread, while being
maintained by the input thread. Same caveats apply than
clutter_seat_query_state(), you are asking for the most up-to-date state,
but it still may be changing under your feet.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1403
2020-08-13 21:40:10 +02:00
Carlos Garnacho
6704e986a0 backends/native: Surround device state queries/updates with RW lock
Wrap all keyboard state updates, and all pointer/stylus/touch cursor
position with a write lock, and ::query_state() (The only entrypoint
to this state from other threads) with a read lock.

The principle is that query_state may be called from different threads
(UI so far, but maybe KMS too in the future), while the input thread
may (or may not) be updating it. This state is fetched "atomically"
(eg. x/y will be consistently old or new, if the input thread were
updating it at the same time).

There's other places deep in backends/native that read this state,
they all will run in the input thread, so they count as "other readers"
to the other thread. Those changes are already mutually exclusive with
updates, so they don't explicitly need the RW lock.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1403
2020-08-13 21:40:10 +02:00
Carlos Garnacho
d55b44df50 backends/native: Protect MetaBarrierManagerNative
While barriers will be added from the main thread, the native barrier
manager will sit close to the MetaSeatImpl in its own thread. Add the
necessary locking so that we can pass MetaBarrierImplNative from the
UI thread to the input thread, and ensure the MetaBarrier signals are
still emitted in the UI thread.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1403
2020-08-13 21:40:10 +02:00
Carlos Garnacho
6496cd7c55 clutter: Switch to GAsyncQueue for ClutterMainContext event queue
https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1403
2020-08-13 21:40:10 +02:00
Carlos Garnacho
6f3ce4de24 clutter: Drop _clutter_clear_events_queue_for_stage()
There's only one stage. Let's not overcomplicate things, as it
will not be possible to simply go through the event queue inspecting
every event.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1403
2020-08-13 21:40:10 +02:00
Carlos Garnacho
034aff4306 clutter: Drop clutter_event_peek()
Peeking doesn't seem such a good idea when we switch to async queues.
Luckily nobody seems to be using this.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1403
2020-08-13 21:40:10 +02:00
Carlos Garnacho
af5f93377a backends: Avoid usage of ClutterBackend/ClutterSeat in MetaInputDeviceNative
https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1403
2020-08-13 21:40:10 +02:00
Carlos Garnacho
abd858fb69 backends/native: Move MetaInputSettings ownership to MetaSeatImpl
Together with keymaps and devices, MetaInputSettings will live in the
ninth circle of hell with MetaSeatImpl, forever tied to it.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1403
2020-08-13 21:40:10 +02:00
Carlos Garnacho
09e02a772e backends/native: Do not dispatch libinput during MetaSeatImpl construction
This saves us from some egg/chicken problems, since we mean to use the
MetaInputSettings while it (thus far) is created at a later stage.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1403
2020-08-13 21:40:10 +02:00
Carlos Garnacho
c850aa9733 backends: Do not use clutter_seat_list_devices() in MetaInputSettings
Make it keep its own list of devices, it's not that far off.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1403
2020-08-13 21:40:10 +02:00
Carlos Garnacho
5a1c7e4a54 backends: Make device tracking at MetaInputSettings ad-hoc API
Depending on the backend, we want to integrate this object at different
levels. It will sit close to the MetaBackendX11/MetaSeatX11 in X11, but
it will be put deep down with MetaSeatImpl in the native backend, in a
separate thread.

Since we can't depend on a single object type, nor are able to track
ClutterSeat signals neatly, make this API something to be called
explicitly by backends.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1403
2020-08-13 21:40:10 +02:00
Carlos Garnacho
e324f0fad0 backends: Simplify function arguments
We just pass a device in order to check it with the seat pointer, we
can do without this.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1403
2020-08-13 21:40:10 +02:00
Carlos Garnacho
5978531963 backends/native: Proxy modifier state changes via MetaSeatImpl
This changes within the MetaSeatImpl realm, so use a signal to forward
this to the MetaSeatNative/MetaKeymapNative one.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1403
2020-08-13 21:40:10 +02:00
Carlos Garnacho
bc111bf958 backends/native: Proxy bell notifications from within the MetaSeatImpl
As with other changes from within the MetaSeatImpl realm, proxy that
through a MetaSeatImpl signal, instead of poking directly on the ClutterSeat.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1403
2020-08-13 21:40:10 +02:00
Carlos Garnacho
074d78bd9b backends/native: Proxy touch-mode via MetaSeatImpl
Handle this via a MetaSeatImpl signal, as the heuristics that apply
here are based on libinput events. The MetaSeatNative just forwards
the touch-mode changes now.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1403
2020-08-13 21:40:10 +02:00
Carlos Garnacho
2e604709df backends/native: Forward keyboard a11y changes via the MetaSeatImpl
These changes will happen in the input event management code, so let them
be emitted via the MetaSeatImpl, as that's what we'll have neat access to.
The ClutterSeat signals are now emitted from there.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1403
2020-08-13 21:40:10 +02:00
Carlos Garnacho
6c265c131f clutter: Don't keep extra copy on device events
https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1403
2020-08-13 21:40:10 +02:00
Carlos Garnacho
06adde5c6b backends/native: Spin MetaSeatImpl off MetaSeatNative
Move most of the functional bits (those meant to run on a standalone
thread) to a MetaSeatImpl object. This object is managed by the MetaSeatImpl
and not exposed outside the friend MetaSeatNative/MetaInputDeviceNative/
MetaInputSettings classes.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1403
2020-08-13 21:40:10 +02:00
Carlos Garnacho
a2616d83e8 clutter: Make ClutterSeat::handle_device_event vfunc more generic
Make it able to handle not just device added/removed events, but perform
any kind of post-processing that needed to be done on ClutterEvents at
the seat level.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1403
2020-08-13 21:40:10 +02:00
Carlos Garnacho
92bc79fd51 backends/native: Remove unused function
This meta_seat_native_get_device() function has been unused for some time.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1403
2020-08-13 21:13:38 +02:00
Carlos Garnacho
ef67fab737 backends: Move keyboard a11y into backends
And out of Clutter API. This is mainly set via settings, or the windowing
itself, so we don't need to leak these details up our own backend.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1403
2020-08-13 21:13:34 +02:00
Carlos Garnacho
9acb7f0eed backends: Make MetaInputMapper take over MetaInputSettings public API
Banish MetaInputSettings from MetaBackend "public" API, it's now meant to
spend the rest of its days in the backend dungeons, maybe hanging
off a thread.

MetaInputMapper replaces all external uses.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1403
2020-08-13 21:13:30 +02:00
Carlos Garnacho
c678cdab5a backends: Move all output management to MetaInputMapper
Delegate on the MetaInputMapper all matching of inputs and outputs,
including configuration. Other secondary aspects, like output
aspect ratio for tablet letterbox mode, or toggling attached devices
with power saving changes, are also moved here.

This makes MetaInputSettings independent of MetaMonitorManager,
all interaction with it happens indirectly via public API entrypoints.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1403
2020-08-13 21:13:25 +02:00
Carlos Garnacho
91f6b3b5bc backends: Simplify MetaInputSettings vfunc
Rename the set_tablet_keep_aspect() vfunc into a set_tablet_aspect_ratio()
one that takes an aspect ratio double, instead of leaking monitor info
into subclasses to let them all figure out this number themselves.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1403
2020-08-13 21:13:19 +02:00
Carlos Garnacho
696915a951 backends/native: Drop meta_seat_native_[gs]et_stage()
This is now unused.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1403
2020-08-13 21:13:15 +02:00
Carlos Garnacho
2e07c55241 backends: Assign stage to events in MetaBackend
Don't do this in the MetaSeatNative, this should be detached from
the stage.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1403
2020-08-13 21:13:11 +02:00
Carlos Garnacho
0f0848191e backends/native: Drop early processing of ClutterEvents
We have 2 sources (this one in MetaSeatNative, and the one in
MetaBackend) dispatching ClutterEvents to the stage. Make the
MetaSeatNative one exclusively about dispatching the libinput
queue, and leave ClutterEvents to the other.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1403
2020-08-13 21:13:04 +02:00
Carlos Garnacho
4b0d3f44e1 backends/native: Use viewport info to find out stage extents
This information is equivalent to the stage extents, this just
leaves meta_seat_native_get_stage() used for setting event->any.stage,
which is a tiny lame excuse.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1403
2020-08-13 21:12:59 +02:00
Carlos Garnacho
4f794d3acb backends: Add method to get extents from viewport info
This way we know the stage extents without poking the stage.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1403
2020-08-13 21:12:55 +02:00
Carlos Garnacho
3252ef5dd7 backends: Use also a native cursor renderer for tablets
This will resort to SW rendering if this cursor renderer does not
own the MetaKmsCursorRenderer, so it's pretty much equivalent thus
far, except we may now implement logic to flip the kms cursor renderer
around.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1403
2020-08-13 21:12:51 +02:00
Carlos Garnacho
0c9bbbe90e backends: Use MetaViewportInfo to keep MetaSeatNative informed of layout
Use this for the calculations to keep absolute motion properly constrained,
and relative motion properly scaled.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1403
2020-08-13 21:12:44 +02:00
Carlos Garnacho
bb62d9e4b0 backends: Add simple object to delegate logical monitor layout queries
This object can be passed to random places, and be trusted to remain unchanged
till replaced. Makes it an ideal replacement for MetaMonitorManager across
threads.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1403
2020-08-13 21:12:40 +02:00
Carlos Garnacho
579220a762 clutter: Drop ClutterInputDevice::enabled and setter/getter
This is unused now, and not something we generally allow.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1403
2020-08-13 21:12:37 +02:00
Carlos Garnacho
575a4ca281 backends: Move away from clutter_input_device_set_enabled()
We actually have a set_send_events() vfunc that can enable or disable
devices at the libinput and X11 input driver level, so use that. A
positive side effect is that those layers will leave the device at
a consistent idle state (as opposed to going mute maybe amid user
input).

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1403
2020-08-13 21:12:31 +02:00
Carlos Garnacho
4b7f2905d6 backends: Split pad action mapping to a separate object
This now lives in the core, and will get updated from events in the
UI thread.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1403
2020-08-13 21:12:26 +02:00
Carlos Garnacho
c7758046eb backends: Drop unused function
https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1403
2020-08-13 21:12:22 +02:00
Carlos Garnacho
e64112de64 backends: Split kms cursor renderer from MetaCursorRendererNative
Move the KMS updating pieces to a distinct MetaKmsCursorRenderer whose
cursor sprite will get updated from the driving MetaCursorRenderer.
Since there could be multiple MetaCursorRenderers, also add the
necessary pieces to move the KMS cursor renderer between renderers.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1403
2020-08-13 21:12:19 +02:00
Carlos Garnacho
05f385c8ee backends: Move HW cursor inhibitors to MetaBackend
We are aiming for a split of HW and SW cursor rendering management.
Given the HW plane is a limited resource and the amount of cursor
renderers may be >1 (due to tablets, even though we currently use an
always-software cursor renderer there), it would ideally be able to
switch between renderers.

Being MetaCursorRenderer not really a singleton, having cursor
inhibitor accounting here doesn't pan out. Make it MetaBackend API
so all cursor renderers get the same picture.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1403
2020-08-13 21:12:14 +02:00
Carlos Garnacho
8a2b529ca3 backends: Make MetaHwCursorInhibitor less about sprites
Remove the sprite argument from the vfunc, it's used in no implementations
and conceptually gets a bit in the middle.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1403
2020-08-13 21:12:11 +02:00
Carlos Garnacho
0c92417178 core: Centralize cursor renderer and tracker updates
These use now more of a "pull" model, where they receive update
notifications and the relevant input position is queried, instead
of the coordinates being passed along.

This allows to treat cursor renderers all the same independently
of the device they track. This notifying of position changes should
ideally be more backend-y than core-y, a better location will be
figured out in future commits.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1403
2020-08-13 21:11:48 +02:00
Carlos Garnacho
543d232b51 backends: Drop meta_cursor_renderer_get_position()
This is now unused.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1403
2020-08-13 21:11:45 +02:00
Carlos Garnacho
4398d63566 wayland: Move away from meta_cursor_renderer_get_position()
Fetch the cursor renderer device, and query its position instead.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1403
2020-08-13 21:11:42 +02:00
Carlos Garnacho
dc022a67b0 backends: Add ::device property to MetaCursorRenderer
A cursor renderer is made to invariably follow a pointer device, make
it a construct-time property, and update all creators of cursor renderers
to specify it.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1403
2020-08-13 21:11:38 +02:00
Carlos Garnacho
60fa895ae3 backends: Move away from meta_cursor_renderer_get_position()
We are moving onto relying fully on the seat cursor position. As
this focuses (thus far?) on mouse pointers only, use the cursor
tracker as a convenient shortcut.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1403
2020-08-13 21:11:35 +02:00
Carlos Garnacho
7bb3fe25aa backends: Use graphene_point_t on meta_cursor_tracker_get_pointer()
It's nicer to propagate along.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1403
2020-08-13 21:11:31 +02:00
Carlos Garnacho
6c5bba94fd backends: Manage tablet cursors in backend
Instead of letting the wayland bits maintain an always-software
cursor renderer, let the cursor renderer be managed by the backend,
and only hook to it (as we do for pointer cursor) in the wayland
bits.

ATM, make the cursor renderer still always-software, although
ideally we should allow moving the HW cursor management between
renderers.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1403
2020-08-13 21:11:18 +02:00
Carlos Garnacho
667b2726f5 wayland: Look up cursor renderer for device on MetaWaylandPointer
Make it explicitly look up the pointer device, instead of implicitly
relying on it.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1403
2020-08-13 21:11:15 +02:00
Carlos Garnacho
1d3588ba48 backends: Add meta_backend_get_cursor_renderer_for_device()
Different devices may get standalone cursor renderers, add this API
to adapt slowly to this. The meta_backend_get_cursor_renderer() call
still exists, but shortcuts to the mouse pointer's renderer (as it
actually did before).

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1403
2020-08-13 21:11:11 +02:00
Carlos Garnacho
16317cec12 wayland: Replace cursor renderer usage with cursor tracker
We just want to know the pointer position, let's use something else
here.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1403
2020-08-13 21:11:08 +02:00
Carlos Garnacho
f3991c0164 backends: Add argument for best scale on MetaCursorSprite::prepare-at
Instead of letting implementations poke backend internals from various
places, give that information right away.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1403
2020-08-13 21:11:05 +02:00
Carlos Garnacho
b07d9c5f92 core: Do not force cursor renderer update here
This is already taken care of in meta_backend_monitors_changed(), called
from the same code paths that emit ::monitors-changed-internal. It is
better to leave this up to backend internals.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1403
2020-08-13 21:11:02 +02:00
Carlos Garnacho
be51a8c18c backends: Remove x/y arguments from MetaCursorTracker::cursor-moved
Make this signal a hint, the actual coordinates should be queried to the
cursor tracker, the device, the seat... There's enough options.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1403
2020-08-13 21:10:58 +02:00
Carlos Garnacho
11c86f9cb3 core: Remove unused struct field
https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1403
2020-08-13 21:10:55 +02:00
Carlos Garnacho
87c0821a30 backends: Drop unused function
meta_cursor_tracker_get_displayed_cursor() is used nowhere.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1403
2020-08-13 21:10:52 +02:00
Carlos Garnacho
03f2bade19 backends: Delegate pointer confinements to an impl object
https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1403
2020-08-13 21:10:49 +02:00
Carlos Garnacho
a3825f2085 backends: Fix typo in comment
https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1403
2020-08-13 21:10:46 +02:00
Carlos Garnacho
8b2a89041a backends: Drop GDK device querying code from MetaCursorTracker
Clutter behavior is now equivalent to GDK's on X11, avoid poking to
GDK here.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1403
2020-08-13 21:10:42 +02:00
Carlos Garnacho
52da5fe4f2 clutter: Simplify backend-independent touch accounting
Coordinates are tracked by the ClutterSeat backends, we just need to
track the target actor at this level.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1403
2020-08-13 21:10:39 +02:00
Carlos Garnacho
307be1e495 clutter: Drop clutter_input_device_set_coords()
Input devices aren't "updated" anymore, but their state queried to the
seat. This goes nowhere.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1403
2020-08-13 21:10:36 +02:00
Carlos Garnacho
9b3ca86b7c clutter: Drop clutter_input_device_update_from_event()
Input devices aren't "updated" anymore, but their state queried to
the seat instead. This is API only meant for embedders of Clutter,
and is pointless to us.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1403
2020-08-13 21:10:33 +02:00
Carlos Garnacho
da55f15156 clutter: Pass base event to clutter_input_device_update()
So we may fetch coordinates without necessarily querying the device
state.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1403
2020-08-13 21:10:29 +02:00
Carlos Garnacho
b13fe4895f clutter: Drop clutter_input_device_set_state()
Nothing uses it anymore.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1403
2020-08-13 21:10:25 +02:00
Carlos Garnacho
aae4a6065c backends/native: Move away from ClutterInputDevice coords
Use a new set in MetaInputDeviceNative for the time being.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1403
2020-08-13 21:10:22 +02:00
Carlos Garnacho
1555ecad11 clutter: Use ClutterSeat underneath coords/modifiers input device getters
This is not device state, but belonging to seat guts.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1403
2020-08-13 21:10:18 +02:00
Carlos Garnacho
292b4dd605 backends/native: Implement ClutterSeat::query_state() vmethod
https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1403
2020-08-13 21:10:15 +02:00
Carlos Garnacho
4766e2f858 backends/x11: Implement ClutterSeat::query_state() vmethod
https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1403
2020-08-13 21:10:12 +02:00
Carlos Garnacho
e3fe8c3dd1 clutter: Add ClutterSeat::query_state() vmethod
This will query a device state; position and modifiers.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1403
2020-08-13 21:10:09 +02:00
Carlos Garnacho
d3e1ce7dbc clutter: Drop unused field in ClutterInputDevice struct
https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1403
2020-08-13 21:10:04 +02:00
Carlos Garnacho
63ad2c958d clutter: Drop clutter_input_device_set_time()
An input device does not have time on itself, events do. This was made
unused so drop it.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1403
2020-08-13 21:10:01 +02:00
Carlos Garnacho
849cc3d7f5 clutter: Pass timestamp to clutter_input_device_set_actor()
This function emits crossing events, so needs a (most times truthful)
timestamp. Make it explicit instead of fetching it from the device.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1403
2020-08-13 21:09:58 +02:00
Carlos Garnacho
8d8c933eb4 clutter/main: Drop dead code branches
We shouldn't get an input event that has not a device.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1403
2020-08-13 21:09:54 +02:00
Carlos Garnacho
2363f4c30b clutter: Drop clutter_input_device_set_stage()
No one uses this already.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1403
2020-08-13 21:09:51 +02:00
Carlos Garnacho
5d45722362 backends/x11: Drop users of clutter_input_device_set_stage()
There is no getter, so this information is useless.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1403
2020-08-13 21:09:47 +02:00
Carlos Garnacho
cef6520836 backends/native: Drop users of clutter_input_device_set_stage()
There is no getter, so doing this is now pointless.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1403
2020-08-13 21:09:44 +02:00
Carlos Garnacho
0fbbeb0c82 clutter: Drop clutter_input_device_get_[pointer_]stage()
Input devices are not related to the stage in any way. Drop all the
users that relied on it being so.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1403
2020-08-13 21:09:40 +02:00
Carlos Garnacho
b97519bb6e backends/x11: Drop all users of clutter_input_device_get_stage()
And clutter_input_device_get_pointer_stage().

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1403
2020-08-13 21:09:36 +02:00
Carlos Garnacho
60b3f628a6 backends/native: Drop all uses of clutter_input_device_get_stage()
Rely on the seat stage, or other ways to fetch it. Also rely that
there is actually a single stage, so that we assign the right stage
to all events going out of the seat, in a single place.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1403
2020-08-13 21:09:32 +02:00
Carlos Garnacho
37deba9557 clutter: Do not depend on device stage on ClutterInputMethod
Look it up through other means.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1403
2020-08-13 21:09:29 +02:00
Carlos Garnacho
89cefd037f clutter: Work out stage from actor on which to emit crossing
Don't rely on the device stage.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1403
2020-08-13 21:09:26 +02:00
Carlos Garnacho
c9efadacd1 clutter: Specify stage on clutter_input_device_update() function
This is the function performing the picking, tell it explicitly the
stage it should happen on.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1403
2020-08-13 21:09:22 +02:00
Carlos Garnacho
df724f5c75 backends/native: Move relative motion filter to MetaSeatNative altogether
And drop the relative motion filter API. The seat will handle relative motion
across outputs with different scales. This accesses the MetaMonitorManager
ATM.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1403
2020-08-13 21:09:19 +02:00
Carlos Garnacho
44bb21c7aa backends/native: Make seat constrain pointer to monitors out of the box
It does access the MetaMonitorManager directly ATM.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1403
2020-08-13 21:09:15 +02:00
Carlos Garnacho
73e705a49b backend/native: Move barrier manager to MetaSeatNative
https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1403
2020-08-13 21:09:10 +02:00
Carlos Garnacho
2316dfe394 backends/native: Use libinput seat slot API
Instead of creating a seat-wide touch slot ID ourselves, rely on libinput
API doing this for us.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1403
2020-08-13 21:09:06 +02:00
Carlos Garnacho
9597b5a703 backends: Move absolute/relative device mapping to native backend
This is a bit scattered around, with the setter/getter in Clutter, and
it only being only directly honored in Wayland (it goes straight through
device properties in X11).

Make this private native API, and out of public ClutterInputDevice API.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1403
2020-08-13 21:09:02 +02:00
Carlos Garnacho
0be0a14225 backends: Move device mapping check into backend
Make the upper parts agnostic about the device being relative in
order to apply the display mapping. Just make the low level bits
resort to the identity matrix for those.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1403
2020-08-13 21:08:58 +02:00
Carlos Garnacho
7fafec21b6 backends: Fold device mapping check into backend
Make the upper part agnostic about the device being relative in order
to avoid applying keep-aspect. The X11 bits already are, so make it
sure it's also the case for the native backend.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1403
2020-08-13 21:08:55 +02:00
Carlos Garnacho
88f03d3a26 clutter: Sanitize ClutterInputDevice header
Move some exposed setters to private headers. It makes some sense to
provide those for backends, not as much to the upper layers.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1403
2020-08-13 21:08:51 +02:00
Carlos Garnacho
edc399e5cf backends: Drop extra layer of touch info handling
We have a hashtable in the device that does not add much on top
to the seat handling. Make all the places rely on the seat accounting
instead.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1403
2020-08-13 21:08:48 +02:00
Carlos Garnacho
908a331fa8 backends: Drop the filter for libinput events
This is now unused, and it's arguably any useful to stay.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1403
2020-08-13 21:08:43 +02:00
Carlos Garnacho
3083e98254 wayland: Use Clutter event to handle touch cancel
The semantics for libinput events are not as expected here. Besides
it's pointless, as those should arrive per-slot in a burst, and we
cancel on the first event.

We can simply use the Clutter event for this.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1403
2020-08-13 21:08:39 +02:00
Carlos Garnacho
7dc1a28c8c backends: Use slot from cancel events
As it does seem from a read to libinput code, TOUCH_CANCEL events
actually do contain slot information, and are emitted per-slot.
This means we can avoid iterating over the slots ourselves, they
are still expected to be sent altogether.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1403
2020-08-13 21:08:35 +02:00
Carlos Garnacho
3ce5b34ade wayland: Simplify wl_touch.frame handling
We want to coalesce multiple touch events into the same wl_touch.frame
event. Instead of poking internals to peek the touch events (and their
slots) coming at us before we handle them, simplify things by queueing
the event at a slightly lower priority than events, so we are ensured
to handle all pending input events before sending the event.

If there's no pending events, we can just send the frame event. As it
doesn't make sense to hold any longer.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1403
2020-08-13 21:07:22 +02:00
Marco Trevisan (Treviño)
5677fbb64d seat-native: Process device added/removed events as ClutterEvents
Delay the addition and removal of devices using ClutterDeviceEvent's so that
they are processed following the libinput event order, and that we don't
have to flush the events on removal.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1371
2020-08-13 21:07:18 +02:00
Marco Trevisan (Treviño)
e7f29e764f seat-x11: Translate device enabled/disabled into clutter events
When a device is removed from the seat the events that this device may have
emitted just before being removed might still be in the stage events queue,
this may lead a to a crash because:

Once the device is removed, we dispose it and the staling event is
kept in queue and sent for processing at next loop.
During event processing we ask the backend to update the last device
with the disposed device
The device is disposed once the events referencing it, are free'd
The actual last device emission happens in an idle, but at this point
the device may have been free'd, and in any case will be still disposed
and so not providing useful informations.

To avoid this, once a device has been added/removed from the seat, we queue
ClutterDeviceEvent events to inform the stack that the device state has
changed, preserving the order with the other actual generated device events.
In this way it can't happen that we emit another event before that the
device has been added or after that it has been removed.

Fixes: https://gitlab.gnome.org/GNOME/mutter/-/issues/1345
2020-08-13 21:07:08 +02:00
Marco Trevisan (Treviño)
5563bfe7d9 clutter-seat: Handle device events and emit signals
Clutter device events are special events coming from the backend when an
input device is added or removed.

When such events are processed, we should make the seat to handle them by
calling vfunc that can be implemented by each backend and eventually
emitting the appropriate signal.

If a device is removed, we can also safely dispose it, as it can be
considered stale at this point.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1371
2020-08-13 21:07:05 +02:00
Marco Trevisan (Treviño)
cd00e69ce3 clutter-event: Add device added/removed events
Add clutter device added and removed events to allow processing of them as
it happens in the backends, queuing them and performing actions in order.

This allows not to loose any event that is performed just before removing or
disabling a device, and still process the events in order in the event
queue.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1371
2020-08-13 21:07:03 +02:00
Marco Trevisan (Treviño)
fe1d297680 backend: Use connect-after to perform actions on device removed
When a device is removed we perform some actions such as stopping the
"::last-device-changed" signal emission and unsetting the current device.
And we want to be sure that these actions happen after all the
device-removed operations are sorted out.

Related to: https://gitlab.gnome.org/GNOME/mutter/-/issues/1345
https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1371
2020-08-13 21:07:00 +02:00
Marco Trevisan (Treviño)
67a31633d8 backend: Don't emit last-device updates with no device
When removing a device that has been just marked as the last in use, we may
try to notify that a NULL device is the last one.

This is not supported, as both update_last_device() and the clients of the
"::last-device-changed" signal are assuming that the last device is always
a valid ClutterInputDevice.

So let's avoid erroring, and stop the idle when clearing the current device.

Related to: https://gitlab.gnome.org/GNOME/mutter/-/issues/1345
https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1371
2020-08-13 21:06:51 +02:00
93 changed files with 10541 additions and 8684 deletions

View File

@ -12715,6 +12715,9 @@ clutter_actor_event (ClutterActor *actor,
signal_num = -1;
detail = quark_stage;
break;
case CLUTTER_DEVICE_ADDED:
case CLUTTER_DEVICE_REMOVED:
break;
case CLUTTER_EVENT_LAST: /* Just keep compiler warnings quiet */
break;
}

View File

@ -387,44 +387,6 @@ typedef enum
CLUTTER_MODIFIER_MASK = 0x5c001fff
} ClutterModifierType;
/**
* ClutterKeyboardA11yFlags:
* @CLUTTER_A11Y_KEYBOARD_ENABLED:
* @CLUTTER_A11Y_TIMEOUT_ENABLED:
* @CLUTTER_A11Y_MOUSE_KEYS_ENABLED:
* @CLUTTER_A11Y_SLOW_KEYS_ENABLED:
* @CLUTTER_A11Y_SLOW_KEYS_BEEP_PRESS:
* @CLUTTER_A11Y_SLOW_KEYS_BEEP_ACCEPT:
* @CLUTTER_A11Y_SLOW_KEYS_BEEP_REJECT:
* @CLUTTER_A11Y_BOUNCE_KEYS_ENABLED:
* @CLUTTER_A11Y_BOUNCE_KEYS_BEEP_REJECT:
* @CLUTTER_A11Y_TOGGLE_KEYS_ENABLED:
* @CLUTTER_A11Y_STICKY_KEYS_ENABLED:
* @CLUTTER_A11Y_STICKY_KEYS_TWO_KEY_OFF:
* @CLUTTER_A11Y_STICKY_KEYS_BEEP:
* @CLUTTER_A11Y_FEATURE_STATE_CHANGE_BEEP:
*
* Keyboard accessibility features applied to a ClutterInputDevice keyboard.
*
*/
typedef enum
{
CLUTTER_A11Y_KEYBOARD_ENABLED = 1 << 0,
CLUTTER_A11Y_TIMEOUT_ENABLED = 1 << 1,
CLUTTER_A11Y_MOUSE_KEYS_ENABLED = 1 << 2,
CLUTTER_A11Y_SLOW_KEYS_ENABLED = 1 << 3,
CLUTTER_A11Y_SLOW_KEYS_BEEP_PRESS = 1 << 4,
CLUTTER_A11Y_SLOW_KEYS_BEEP_ACCEPT = 1 << 5,
CLUTTER_A11Y_SLOW_KEYS_BEEP_REJECT = 1 << 6,
CLUTTER_A11Y_BOUNCE_KEYS_ENABLED = 1 << 7,
CLUTTER_A11Y_BOUNCE_KEYS_BEEP_REJECT = 1 << 8,
CLUTTER_A11Y_TOGGLE_KEYS_ENABLED = 1 << 9,
CLUTTER_A11Y_STICKY_KEYS_ENABLED = 1 << 10,
CLUTTER_A11Y_STICKY_KEYS_TWO_KEY_OFF = 1 << 11,
CLUTTER_A11Y_STICKY_KEYS_BEEP = 1 << 12,
CLUTTER_A11Y_FEATURE_STATE_CHANGE_BEEP = 1 << 13,
} ClutterKeyboardA11yFlags;
/**
* ClutterPointerA11yFlags:
* @CLUTTER_A11Y_POINTER_ENABLED:
@ -906,6 +868,8 @@ typedef enum /*< prefix=CLUTTER >*/
CLUTTER_PAD_BUTTON_RELEASE,
CLUTTER_PAD_STRIP,
CLUTTER_PAD_RING,
CLUTTER_DEVICE_ADDED,
CLUTTER_DEVICE_REMOVED,
CLUTTER_EVENT_LAST /* helper */
} ClutterEventType;
@ -1630,12 +1594,6 @@ typedef enum
CLUTTER_INPUT_DEVICE_PAD_SOURCE_FINGER,
} ClutterInputDevicePadSource;
typedef enum
{
CLUTTER_INPUT_DEVICE_MAPPING_ABSOLUTE,
CLUTTER_INPUT_DEVICE_MAPPING_RELATIVE,
} ClutterInputDeviceMapping;
typedef enum
{
CLUTTER_INPUT_CONTENT_HINT_COMPLETION = 1 << 0,

View File

@ -414,6 +414,8 @@ clutter_event_get_position (const ClutterEvent *event,
case CLUTTER_PAD_BUTTON_RELEASE:
case CLUTTER_PAD_STRIP:
case CLUTTER_PAD_RING:
case CLUTTER_DEVICE_ADDED:
case CLUTTER_DEVICE_REMOVED:
graphene_point_init (position, 0.f, 0.f);
break;
@ -487,6 +489,8 @@ clutter_event_set_coords (ClutterEvent *event,
case CLUTTER_PAD_BUTTON_RELEASE:
case CLUTTER_PAD_STRIP:
case CLUTTER_PAD_RING:
case CLUTTER_DEVICE_ADDED:
case CLUTTER_DEVICE_REMOVED:
break;
case CLUTTER_ENTER:
@ -1158,6 +1162,11 @@ clutter_event_set_device (ClutterEvent *event,
case CLUTTER_PAD_RING:
event->pad_ring.device = device;
break;
case CLUTTER_DEVICE_ADDED:
case CLUTTER_DEVICE_REMOVED:
event->device.device = device;
break;
}
}
@ -1254,6 +1263,11 @@ clutter_event_get_device (const ClutterEvent *event)
case CLUTTER_PAD_RING:
device = event->pad_ring.device;
break;
case CLUTTER_DEVICE_ADDED:
case CLUTTER_DEVICE_REMOVED:
device = event->device.device;
break;
}
return device;
@ -1407,6 +1421,8 @@ clutter_event_copy (const ClutterEvent *event)
sizeof (gdouble) * n_axes);
break;
case CLUTTER_DEVICE_ADDED:
case CLUTTER_DEVICE_REMOVED:
default:
break;
}
@ -1461,6 +1477,9 @@ clutter_event_free (ClutterEvent *event)
case CLUTTER_TOUCH_CANCEL:
g_free (event->touch.axes);
break;
case CLUTTER_DEVICE_ADDED:
case CLUTTER_DEVICE_REMOVED:
break;
default:
break;
@ -1485,40 +1504,17 @@ ClutterEvent *
clutter_event_get (void)
{
ClutterMainContext *context = _clutter_context_get_default ();
ClutterEvent *event;
if (context->events_queue == NULL)
return NULL;
event = g_async_queue_try_pop (context->events_queue);
if (g_queue_is_empty (context->events_queue))
return NULL;
return g_queue_pop_tail (context->events_queue);
return event;
}
/**
* clutter_event_peek:
*
* Returns a pointer to the first event from the event queue but
* does not remove it.
*
* Return value: (transfer none): A #ClutterEvent or NULL if queue empty.
*
* Since: 0.4
*/
ClutterEvent *
clutter_event_peek (void)
static gboolean
spin_context (gpointer data)
{
ClutterMainContext *context = _clutter_context_get_default ();
g_return_val_if_fail (context != NULL, NULL);
if (context->events_queue == NULL)
return NULL;
if (g_queue_is_empty (context->events_queue))
return NULL;
return g_queue_peek_tail (context->events_queue);
return G_SOURCE_REMOVE;
}
void
@ -1526,21 +1522,9 @@ _clutter_event_push (const ClutterEvent *event,
gboolean do_copy)
{
ClutterMainContext *context = _clutter_context_get_default ();
ClutterInputDevice *device;
g_assert (context != NULL);
if (context->events_queue == NULL)
context->events_queue = g_queue_new ();
/* disabled devices don't propagate events */
device = clutter_event_get_device (event);
if (device != NULL)
{
if (!clutter_input_device_get_enabled (device))
return;
}
if (do_copy)
{
ClutterEvent *copy;
@ -1549,7 +1533,8 @@ _clutter_event_push (const ClutterEvent *event,
event = copy;
}
g_queue_push_head (context->events_queue, (gpointer) event);
g_async_queue_push (context->events_queue, (gpointer) event);
g_idle_add (spin_context, NULL);
}
/**
@ -1586,10 +1571,7 @@ clutter_events_pending (void)
g_return_val_if_fail (context != NULL, FALSE);
if (context->events_queue == NULL)
return FALSE;
return g_queue_is_empty (context->events_queue) == FALSE;
return g_async_queue_length (context->events_queue) > 0;
}
/**
@ -1728,6 +1710,8 @@ clutter_event_get_axes (const ClutterEvent *event,
case CLUTTER_EVENT_LAST:
case CLUTTER_PROXIMITY_IN:
case CLUTTER_PROXIMITY_OUT:
case CLUTTER_DEVICE_ADDED:
case CLUTTER_DEVICE_REMOVED:
break;
case CLUTTER_SCROLL:

View File

@ -121,6 +121,7 @@ typedef struct _ClutterProximityEvent ClutterProximityEvent;
typedef struct _ClutterPadButtonEvent ClutterPadButtonEvent;
typedef struct _ClutterPadStripEvent ClutterPadStripEvent;
typedef struct _ClutterPadRingEvent ClutterPadRingEvent;
typedef struct _ClutterDeviceEvent ClutterDeviceEvent;
/**
* ClutterAnyEvent:
@ -544,6 +545,17 @@ struct _ClutterPadRingEvent
guint32 mode;
};
struct _ClutterDeviceEvent
{
ClutterEventType type;
guint32 time;
ClutterEventFlags flags;
ClutterStage *stage;
ClutterActor *source;
ClutterInputDevice *device;
};
/**
* ClutterEvent:
*
@ -570,6 +582,7 @@ union _ClutterEvent
ClutterPadButtonEvent pad_button;
ClutterPadStripEvent pad_strip;
ClutterPadRingEvent pad_ring;
ClutterDeviceEvent device;
};
/**
@ -601,8 +614,6 @@ gboolean clutter_events_pending (void);
CLUTTER_EXPORT
ClutterEvent * clutter_event_get (void);
CLUTTER_EXPORT
ClutterEvent * clutter_event_peek (void);
CLUTTER_EXPORT
void clutter_event_put (const ClutterEvent *event);
CLUTTER_EXPORT

View File

@ -61,15 +61,6 @@ typedef struct _ClutterScrollInfo
guint last_value_valid : 1;
} ClutterScrollInfo;
typedef struct _ClutterTouchInfo
{
ClutterEventSequence *sequence;
ClutterActor *actor;
float current_x;
float current_y;
} ClutterTouchInfo;
typedef struct _ClutterPtrA11yData
{
int n_btn_pressed;
@ -120,25 +111,18 @@ struct _ClutterInputDevice
/* the current click count */
int click_count;
/* the stage the device is on */
ClutterStage *stage;
/* the current state */
float current_x;
float current_y;
uint32_t current_time;
int current_button_number;
ClutterModifierType current_state;
/* the current touch points states */
GHashTable *touch_sequences_info;
/* the current touch points targets */
GHashTable *touch_sequence_actors;
/* the previous state, used for click count generation */
int previous_x;
int previous_y;
uint32_t previous_time;
int previous_button_number;
ClutterModifierType previous_state;
GArray *axes;
@ -157,8 +141,6 @@ struct _ClutterInputDevice
int n_strips;
int n_mode_groups;
ClutterInputDeviceMapping mapping_mode;
guint has_cursor : 1;
guint is_enabled : 1;
@ -180,33 +162,11 @@ CLUTTER_EXPORT
void clutter_input_device_update_from_tool (ClutterInputDevice *device,
ClutterInputDeviceTool *tool);
CLUTTER_EXPORT
ClutterStage * _clutter_input_device_get_stage (ClutterInputDevice *device);
CLUTTER_EXPORT
void _clutter_input_device_set_stage (ClutterInputDevice *device,
ClutterStage *stage);
CLUTTER_EXPORT
void _clutter_input_device_set_coords (ClutterInputDevice *device,
ClutterEventSequence *sequence,
gfloat x,
gfloat y,
ClutterStage *stage);
CLUTTER_EXPORT
void _clutter_input_device_set_state (ClutterInputDevice *device,
ClutterModifierType state);
CLUTTER_EXPORT
void _clutter_input_device_set_time (ClutterInputDevice *device,
guint32 time_);
void _clutter_input_device_set_actor (ClutterInputDevice *device,
ClutterEventSequence *sequence,
ClutterActor *actor,
gboolean emit_crossing);
CLUTTER_EXPORT
ClutterActor * clutter_input_device_update (ClutterInputDevice *device,
ClutterEventSequence *sequence,
gboolean emit_crossing);
CLUTTER_EXPORT
void _clutter_input_device_add_event_sequence (ClutterInputDevice *device,
ClutterEvent *event);
ClutterStage *stage,
gboolean emit_crossing,
ClutterEvent *for_event);
CLUTTER_EXPORT
void _clutter_input_device_remove_event_sequence (ClutterInputDevice *device,
ClutterEvent *event);
@ -214,6 +174,12 @@ CLUTTER_EXPORT
void _clutter_input_device_set_n_keys (ClutterInputDevice *device,
guint n_keys);
CLUTTER_EXPORT
void clutter_input_device_set_key (ClutterInputDevice *device,
guint index_,
guint keyval,
ClutterModifierType modifiers);
CLUTTER_EXPORT
gboolean _clutter_input_device_translate_axis (ClutterInputDevice *device,
guint index_,
gdouble value,
@ -252,4 +218,9 @@ ClutterInputDeviceTool *
guint64 serial,
ClutterInputDeviceToolType type);
CLUTTER_EXPORT
gboolean clutter_input_device_keycode_to_evdev (ClutterInputDevice *device,
guint hardware_keycode,
guint *evdev_keycode);
#endif /* CLUTTER_INPUT_DEVICE_PRIVATE_H */

View File

@ -61,7 +61,6 @@ enum
PROP_DEVICE_MODE,
PROP_HAS_CURSOR,
PROP_ENABLED,
PROP_N_AXES,
@ -72,12 +71,10 @@ enum
PROP_N_RINGS,
PROP_N_MODE_GROUPS,
PROP_DEVICE_NODE,
PROP_MAPPING_MODE,
PROP_LAST
};
static void _clutter_input_device_free_touch_info (gpointer data);
static void on_cursor_actor_destroy (ClutterActor *actor,
ClutterInputDevice *device);
static void on_cursor_actor_reactive_changed (ClutterActor *actor,
@ -114,7 +111,7 @@ clutter_input_device_dispose (GObject *gobject)
g_clear_pointer (&device->axes, g_array_unref);
g_clear_pointer (&device->keys, g_array_unref);
g_clear_pointer (&device->scroll_info, g_array_unref);
g_clear_pointer (&device->touch_sequences_info, g_hash_table_unref);
g_clear_pointer (&device->touch_sequence_actors, g_hash_table_unref);
if (device->cursor_actor)
{
@ -191,10 +188,6 @@ clutter_input_device_set_property (GObject *gobject,
self->has_cursor = g_value_get_boolean (value);
break;
case PROP_ENABLED:
clutter_input_device_set_enabled (self, g_value_get_boolean (value));
break;
case PROP_VENDOR_ID:
self->vendor_id = g_value_dup_string (value);
break;
@ -219,10 +212,6 @@ clutter_input_device_set_property (GObject *gobject,
self->node_path = g_value_dup_string (value);
break;
case PROP_MAPPING_MODE:
self->mapping_mode = g_value_get_enum (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
break;
@ -271,10 +260,6 @@ clutter_input_device_get_property (GObject *gobject,
g_value_set_uint (value, clutter_input_device_get_n_axes (self));
break;
case PROP_ENABLED:
g_value_set_boolean (value, self->is_enabled);
break;
case PROP_VENDOR_ID:
g_value_set_string (value, self->vendor_id);
break;
@ -299,10 +284,6 @@ clutter_input_device_get_property (GObject *gobject,
g_value_set_string (value, self->node_path);
break;
case PROP_MAPPING_MODE:
g_value_set_enum (value, self->mapping_mode);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
break;
@ -402,25 +383,6 @@ clutter_input_device_class_init (ClutterInputDeviceClass *klass)
FALSE,
CLUTTER_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
/**
* ClutterInputDevice:enabled:
*
* Whether the device is enabled.
*
* A device with the #ClutterInputDevice:device-mode property set
* to %CLUTTER_INPUT_MODE_MASTER cannot be disabled.
*
* A device must be enabled in order to receive events from it.
*
* Since: 1.6
*/
obj_props[PROP_ENABLED] =
g_param_spec_boolean ("enabled",
P_("Enabled"),
P_("Whether the device is enabled"),
FALSE,
CLUTTER_PARAM_READWRITE);
/**
* ClutterInputDevice:n-axes:
*
@ -506,14 +468,6 @@ clutter_input_device_class_init (ClutterInputDeviceClass *klass)
NULL,
CLUTTER_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
obj_props[PROP_MAPPING_MODE] =
g_param_spec_enum ("mapping-mode",
P_("Device mapping mode"),
P_("Device mapping mode"),
CLUTTER_TYPE_INPUT_DEVICE_MAPPING,
CLUTTER_INPUT_DEVICE_MAPPING_ABSOLUTE,
CLUTTER_PARAM_READWRITE);
gobject_class->dispose = clutter_input_device_dispose;
gobject_class->set_property = clutter_input_device_set_property;
gobject_class->get_property = clutter_input_device_get_property;
@ -528,91 +482,15 @@ clutter_input_device_init (ClutterInputDevice *self)
self->click_count = 0;
self->current_time = self->previous_time = CLUTTER_CURRENT_TIME;
self->current_x = self->previous_x = -1;
self->current_y = self->previous_y = -1;
self->previous_time = CLUTTER_CURRENT_TIME;
self->previous_x = -1;
self->previous_y = -1;
self->current_button_number = self->previous_button_number = -1;
self->current_state = self->previous_state = 0;
self->touch_sequences_info =
g_hash_table_new_full (NULL, NULL,
NULL, _clutter_input_device_free_touch_info);
self->touch_sequence_actors = g_hash_table_new (NULL, NULL);
self->inv_touch_sequence_actors = g_hash_table_new (NULL, NULL);
}
static ClutterTouchInfo *
_clutter_input_device_ensure_touch_info (ClutterInputDevice *device,
ClutterEventSequence *sequence,
ClutterStage *stage)
{
ClutterTouchInfo *info;
info = g_hash_table_lookup (device->touch_sequences_info, sequence);
if (info == NULL)
{
info = g_slice_new0 (ClutterTouchInfo);
info->sequence = sequence;
g_hash_table_insert (device->touch_sequences_info, sequence, info);
if (g_hash_table_size (device->touch_sequences_info) == 1)
_clutter_input_device_set_stage (device, stage);
}
return info;
}
/*< private >
* clutter_input_device_set_coords:
* @device: a #ClutterInputDevice
* @sequence: a #ClutterEventSequence or NULL
* @x: X coordinate of the device
* @y: Y coordinate of the device
*
* Stores the last known coordinates of the device
*/
void
_clutter_input_device_set_coords (ClutterInputDevice *device,
ClutterEventSequence *sequence,
gfloat x,
gfloat y,
ClutterStage *stage)
{
g_return_if_fail (CLUTTER_IS_INPUT_DEVICE (device));
if (sequence == NULL)
{
if (device->current_x != x)
device->current_x = x;
if (device->current_y != y)
device->current_y = y;
}
else
{
ClutterTouchInfo *info;
info = _clutter_input_device_ensure_touch_info (device, sequence, stage);
info->current_x = x;
info->current_y = y;
}
}
/*< private >
* clutter_input_device_set_state:
* @device: a #ClutterInputDevice
* @state: a bitmask of modifiers
*
* Stores the last known modifiers state of the device
*/
void
_clutter_input_device_set_state (ClutterInputDevice *device,
ClutterModifierType state)
{
g_return_if_fail (CLUTTER_IS_INPUT_DEVICE (device));
device->current_state = state;
}
/**
* clutter_input_device_get_modifier_state:
* @device: a #ClutterInputDevice
@ -627,69 +505,17 @@ _clutter_input_device_set_state (ClutterInputDevice *device,
ClutterModifierType
clutter_input_device_get_modifier_state (ClutterInputDevice *device)
{
uint32_t modifiers;
ClutterSeat *seat;
g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), 0);
return device->current_state;
}
seat = clutter_input_device_get_seat (device);
/*< private >
* clutter_input_device_set_time:
* @device: a #ClutterInputDevice
* @time_: the time
*
* Stores the last known event time of the device
*/
void
_clutter_input_device_set_time (ClutterInputDevice *device,
guint32 time_)
{
g_return_if_fail (CLUTTER_IS_INPUT_DEVICE (device));
if (!clutter_seat_query_state (seat, device, NULL, NULL, &modifiers))
return 0;
if (device->current_time != time_)
device->current_time = time_;
}
/*< private >
* clutter_input_device_set_stage:
* @device: a #ClutterInputDevice
* @stage: a #ClutterStage or %NULL
*
* Stores the stage under the device
*/
void
_clutter_input_device_set_stage (ClutterInputDevice *device,
ClutterStage *stage)
{
if (device->stage == stage)
return;
device->stage = stage;
/* we leave the ->cursor_actor in place in order to check
* if we left the stage without crossing it again; this way
* we can emit a leave event on the cursor actor right before
* we emit the leave event on the stage.
*/
}
/*< private >
* clutter_input_device_get_stage:
* @device: a #ClutterInputDevice
*
* Retrieves the stage currently associated with @device.
*
* Return value: The stage currently associated with @device.
*/
ClutterStage *
_clutter_input_device_get_stage (ClutterInputDevice *device)
{
return device->stage;
}
static void
_clutter_input_device_free_touch_info (gpointer data)
{
g_slice_free (ClutterTouchInfo, data);
return modifiers;
}
static void
@ -703,12 +529,8 @@ _clutter_input_device_associate_actor (ClutterInputDevice *device,
{
GList *sequences =
g_hash_table_lookup (device->inv_touch_sequence_actors, actor);
ClutterTouchInfo *info;
ClutterStage *stage = CLUTTER_STAGE (clutter_actor_get_stage (actor));
info = _clutter_input_device_ensure_touch_info (device, sequence, stage);
info->actor = actor;
g_hash_table_insert (device->touch_sequence_actors, sequence, actor);
g_hash_table_insert (device->inv_touch_sequence_actors,
actor, g_list_prepend (sequences, sequence));
}
@ -736,13 +558,7 @@ _clutter_input_device_unassociate_actor (ClutterInputDevice *device,
actor);
for (l = sequences; l != NULL; l = l->next)
{
ClutterTouchInfo *info =
g_hash_table_lookup (device->touch_sequences_info, l->data);
if (info)
info->actor = NULL;
}
g_hash_table_remove (device->touch_sequence_actors, l->data);
g_list_free (sequences);
g_hash_table_remove (device->inv_touch_sequence_actors, actor);
@ -795,17 +611,31 @@ on_cursor_actor_reactive_changed (ClutterActor *actor,
* - set to %TRUE the :has-pointer property of the new pointer
* actor
*/
void
static void
_clutter_input_device_set_actor (ClutterInputDevice *device,
ClutterEventSequence *sequence,
ClutterActor *actor,
gboolean emit_crossing)
gboolean emit_crossing,
graphene_point_t coords,
uint32_t time_)
{
ClutterActor *old_actor = clutter_input_device_get_actor (device, sequence);
ClutterStage *stage = NULL;
if (old_actor == actor)
return;
if (emit_crossing)
{
if (actor)
stage = CLUTTER_STAGE (clutter_actor_get_stage (actor));
else if (old_actor)
stage = CLUTTER_STAGE (clutter_actor_get_stage (old_actor));
if (!stage)
return;
}
if (old_actor != NULL)
{
ClutterActor *tmp_old_actor;
@ -815,12 +645,12 @@ _clutter_input_device_set_actor (ClutterInputDevice *device,
ClutterEvent *event;
event = clutter_event_new (CLUTTER_LEAVE);
event->crossing.time = device->current_time;
event->crossing.time = time_;
event->crossing.flags = 0;
event->crossing.stage = device->stage;
event->crossing.stage = stage;
event->crossing.source = old_actor;
event->crossing.x = device->current_x;
event->crossing.y = device->current_y;
event->crossing.x = coords.x;
event->crossing.y = coords.y;
event->crossing.related = actor;
event->crossing.sequence = sequence;
clutter_event_set_device (event, device);
@ -852,11 +682,11 @@ _clutter_input_device_set_actor (ClutterInputDevice *device,
ClutterEvent *event;
event = clutter_event_new (CLUTTER_ENTER);
event->crossing.time = device->current_time;
event->crossing.time = time_;
event->crossing.flags = 0;
event->crossing.stage = device->stage;
event->crossing.x = device->current_x;
event->crossing.y = device->current_y;
event->crossing.stage = stage;
event->crossing.x = coords.x;
event->crossing.y = coords.y;
event->crossing.source = actor;
event->crossing.related = old_actor;
event->crossing.sequence = sequence;
@ -907,56 +737,6 @@ clutter_input_device_get_device_id (ClutterInputDevice *device)
return device->id;
}
/**
* clutter_input_device_set_enabled:
* @device: a #ClutterInputDevice
* @enabled: %TRUE to enable the @device
*
* Enables or disables a #ClutterInputDevice.
*
* Only devices with a #ClutterInputDevice:device-mode property set
* to %CLUTTER_INPUT_MODE_SLAVE or %CLUTTER_INPUT_MODE_FLOATING can
* be disabled.
*
* Since: 1.6
*/
void
clutter_input_device_set_enabled (ClutterInputDevice *device,
gboolean enabled)
{
g_return_if_fail (CLUTTER_IS_INPUT_DEVICE (device));
enabled = !!enabled;
if (!enabled && device->device_mode == CLUTTER_INPUT_MODE_MASTER)
return;
if (device->is_enabled == enabled)
return;
device->is_enabled = enabled;
g_object_notify_by_pspec (G_OBJECT (device), obj_props[PROP_ENABLED]);
}
/**
* clutter_input_device_get_enabled:
* @device: a #ClutterInputDevice
*
* Retrieves whether @device is enabled.
*
* Return value: %TRUE if the device is enabled
*
* Since: 1.6
*/
gboolean
clutter_input_device_get_enabled (ClutterInputDevice *device)
{
g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), FALSE);
return device->is_enabled;
}
/**
* clutter_input_device_get_coords:
* @device: a #ClutterInputDevice
@ -978,27 +758,14 @@ clutter_input_device_get_coords (ClutterInputDevice *device,
ClutterEventSequence *sequence,
graphene_point_t *point)
{
ClutterSeat *seat;
g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), FALSE);
g_return_val_if_fail (point != NULL, FALSE);
if (sequence == NULL)
{
point->x = device->current_x;
point->y = device->current_y;
}
else
{
ClutterTouchInfo *info =
g_hash_table_lookup (device->touch_sequences_info, sequence);
seat = clutter_input_device_get_seat (device);
if (info == NULL)
return FALSE;
point->x = info->current_x;
point->y = info->current_y;
}
return TRUE;
return clutter_seat_query_state (seat, device, sequence, point, NULL);
}
/*
@ -1018,27 +785,29 @@ clutter_input_device_get_coords (ClutterInputDevice *device,
ClutterActor *
clutter_input_device_update (ClutterInputDevice *device,
ClutterEventSequence *sequence,
gboolean emit_crossing)
ClutterStage *stage,
gboolean emit_crossing,
ClutterEvent *for_event)
{
ClutterStage *stage;
ClutterActor *new_cursor_actor;
ClutterActor *old_cursor_actor;
graphene_point_t point = GRAPHENE_POINT_INIT (-1.0f, -1.0f);
ClutterInputDeviceType device_type = device->device_type;
uint32_t time_;
g_assert (device_type != CLUTTER_KEYBOARD_DEVICE &&
device_type != CLUTTER_PAD_DEVICE);
stage = device->stage;
if (G_UNLIKELY (stage == NULL))
if (for_event)
{
CLUTTER_NOTE (EVENT, "No stage defined for device %d '%s'",
clutter_input_device_get_device_id (device),
clutter_input_device_get_device_name (device));
return NULL;
clutter_event_get_coords (for_event, &point.x, &point.y);
time_ = clutter_event_get_time (for_event);
}
else
{
clutter_input_device_get_coords (device, sequence, &point);
time_ = CLUTTER_CURRENT_TIME;
}
old_cursor_actor = clutter_input_device_get_actor (device, sequence);
new_cursor_actor =
@ -1065,7 +834,8 @@ clutter_input_device_update (ClutterInputDevice *device,
_clutter_input_device_set_actor (device, sequence,
new_cursor_actor,
emit_crossing);
emit_crossing,
point, time_);
return new_cursor_actor;
}
@ -1086,37 +856,12 @@ ClutterActor *
clutter_input_device_get_actor (ClutterInputDevice *device,
ClutterEventSequence *sequence)
{
ClutterTouchInfo *info;
g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), NULL);
if (sequence == NULL)
return device->cursor_actor;
info = g_hash_table_lookup (device->touch_sequences_info, sequence);
g_return_val_if_fail (info != NULL, NULL);
return info->actor;
}
/**
* clutter_input_device_get_pointer_stage:
* @device: a #ClutterInputDevice of type %CLUTTER_POINTER_DEVICE
*
* Retrieves the #ClutterStage underneath the pointer of @device
*
* Return value: (transfer none): a pointer to the #ClutterStage or %NULL
*
* Since: 1.2
*/
ClutterStage *
clutter_input_device_get_pointer_stage (ClutterInputDevice *device)
{
g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), NULL);
g_return_val_if_fail (device->device_type == CLUTTER_POINTER_DEVICE, NULL);
return device->stage;
return g_hash_table_lookup (device->touch_sequence_actors, sequence);
}
/**
@ -1177,95 +922,6 @@ clutter_input_device_get_device_mode (ClutterInputDevice *device)
return device->device_mode;
}
/**
* clutter_input_device_update_from_event:
* @device: a #ClutterInputDevice
* @event: a #ClutterEvent
* @update_stage: whether to update the #ClutterStage of the @device
* using the stage of the event
*
* Forcibly updates the state of the @device using a #ClutterEvent
*
* This function should never be used by applications: it is meant
* for integration with embedding toolkits, like clutter-gtk
*
* Embedding toolkits that disable the event collection inside Clutter
* need to use this function to update the state of input devices depending
* on a #ClutterEvent that they are going to submit to the event handling code
* in Clutter though clutter_do_event(). Since the input devices hold the state
* that is going to be used to fill in fields like the #ClutterButtonEvent
* click count, or to emit synthesized events like %CLUTTER_ENTER and
* %CLUTTER_LEAVE, it is necessary for embedding toolkits to also be
* responsible of updating the input device state.
*
* For instance, this might be the code to translate an embedding toolkit
* native motion notification into a Clutter #ClutterMotionEvent and ask
* Clutter to process it:
*
* |[
* ClutterEvent c_event;
*
* translate_native_event_to_clutter (native_event, &c_event);
*
* clutter_do_event (&c_event);
* ]|
*
* Before letting clutter_do_event() process the event, it is necessary to call
* clutter_input_device_update_from_event():
*
* |[
* ClutterEvent c_event;
* ClutterDeviceManager *manager;
* ClutterInputDevice *device;
*
* translate_native_event_to_clutter (native_event, &c_event);
*
* // get the seat
* seat = clutter_backend_get_deafult_seat (clutter_get_default_backend ());
*
* // use the default Core Pointer that Clutter backends register by default
* device = clutter_seat_get_pointer (seat);
*
* // update the state of the input device
* clutter_input_device_update_from_event (device, &c_event, FALSE);
*
* clutter_do_event (&c_event);
* ]|
*
* The @update_stage boolean argument should be used when the input device
* enters and leaves a #ClutterStage; it will use the #ClutterStage field
* of the passed @event to update the stage associated to the input device.
*
* Since: 1.2
*/
void
clutter_input_device_update_from_event (ClutterInputDevice *device,
ClutterEvent *event,
gboolean update_stage)
{
ClutterModifierType event_state;
ClutterEventSequence *sequence;
ClutterStage *event_stage;
gfloat event_x, event_y;
guint32 event_time;
g_return_if_fail (CLUTTER_IS_INPUT_DEVICE (device));
g_return_if_fail (event != NULL);
event_state = clutter_event_get_state (event);
event_time = clutter_event_get_time (event);
event_stage = clutter_event_get_stage (event);
sequence = clutter_event_get_event_sequence (event);
clutter_event_get_coords (event, &event_x, &event_y);
_clutter_input_device_set_coords (device, sequence, event_x, event_y, event_stage);
_clutter_input_device_set_state (device, event_state);
_clutter_input_device_set_time (device, event_time);
if (update_stage)
_clutter_input_device_set_stage (device, event_stage);
}
/*< private >
* clutter_input_device_reset_axes:
* @device: a #ClutterInputDevice
@ -1646,31 +1302,6 @@ _clutter_input_device_remove_slave (ClutterInputDevice *master,
master->slaves = g_list_remove (master->slaves, slave);
}
/*< private >
* clutter_input_device_add_sequence:
* @device: a #ClutterInputDevice
* @sequence: a #ClutterEventSequence
*
* Start tracking informations related to a touch point (position,
* actor underneath the touch point).
*/
void
_clutter_input_device_add_event_sequence (ClutterInputDevice *device,
ClutterEvent *event)
{
ClutterEventSequence *sequence = clutter_event_get_event_sequence (event);
ClutterStage *stage;
if (sequence == NULL)
return;
stage = clutter_event_get_stage (event);
if (stage == NULL)
return;
_clutter_input_device_ensure_touch_info (device, sequence, stage);
}
/*< private >
* clutter_input_device_remove_sequence:
* @device: a #ClutterInputDevice
@ -1683,25 +1314,25 @@ _clutter_input_device_remove_event_sequence (ClutterInputDevice *device,
ClutterEvent *event)
{
ClutterEventSequence *sequence = clutter_event_get_event_sequence (event);
ClutterTouchInfo *info =
g_hash_table_lookup (device->touch_sequences_info, sequence);
ClutterActor *actor =
g_hash_table_lookup (device->touch_sequence_actors, sequence);
if (info == NULL)
return;
if (info->actor != NULL)
if (actor != NULL)
{
GList *sequences =
g_hash_table_lookup (device->inv_touch_sequence_actors, info->actor);
g_hash_table_lookup (device->inv_touch_sequence_actors, actor);
graphene_point_t point;
sequences = g_list_remove (sequences, sequence);
g_hash_table_replace (device->inv_touch_sequence_actors,
info->actor, sequences);
_clutter_input_device_set_actor (device, sequence, NULL, TRUE);
actor, sequences);
clutter_event_get_coords (event, &point.x, &point.y);
_clutter_input_device_set_actor (device, sequence, NULL, TRUE, point,
clutter_event_get_time (event));
}
g_hash_table_remove (device->touch_sequences_info, sequence);
g_hash_table_remove (device->touch_sequence_actors, sequence);
}
/**
@ -2391,43 +2022,6 @@ clutter_input_device_get_device_node (ClutterInputDevice *device)
return device->node_path;
}
ClutterInputDeviceMapping
clutter_input_device_get_mapping_mode (ClutterInputDevice *device)
{
ClutterInputDeviceType device_type;
g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device),
CLUTTER_INPUT_DEVICE_MAPPING_ABSOLUTE);
device_type = clutter_input_device_get_device_type (device);
g_return_val_if_fail (device_type == CLUTTER_TABLET_DEVICE ||
device_type == CLUTTER_PEN_DEVICE ||
device_type == CLUTTER_ERASER_DEVICE,
CLUTTER_INPUT_DEVICE_MAPPING_ABSOLUTE);
return device->mapping_mode;
}
void
clutter_input_device_set_mapping_mode (ClutterInputDevice *device,
ClutterInputDeviceMapping mapping)
{
ClutterInputDeviceType device_type;
g_return_if_fail (CLUTTER_IS_INPUT_DEVICE (device));
device_type = clutter_input_device_get_device_type (device);
g_return_if_fail (device_type == CLUTTER_TABLET_DEVICE ||
device_type == CLUTTER_PEN_DEVICE ||
device_type == CLUTTER_ERASER_DEVICE);
if (device->mapping_mode == mapping)
return;
device->mapping_mode = mapping;
g_object_notify (G_OBJECT (device), "mapping-mode");
}
gboolean
clutter_input_device_is_grouped (ClutterInputDevice *device,
ClutterInputDevice *other_device)

View File

@ -95,18 +95,11 @@ CLUTTER_EXPORT
ClutterActor * clutter_input_device_get_actor (ClutterInputDevice *device,
ClutterEventSequence *sequence);
CLUTTER_EXPORT
ClutterStage * clutter_input_device_get_pointer_stage (ClutterInputDevice *device);
CLUTTER_EXPORT
const gchar * clutter_input_device_get_device_name (ClutterInputDevice *device);
CLUTTER_EXPORT
ClutterInputMode clutter_input_device_get_device_mode (ClutterInputDevice *device);
CLUTTER_EXPORT
gboolean clutter_input_device_get_has_cursor (ClutterInputDevice *device);
CLUTTER_EXPORT
void clutter_input_device_set_enabled (ClutterInputDevice *device,
gboolean enabled);
CLUTTER_EXPORT
gboolean clutter_input_device_get_enabled (ClutterInputDevice *device);
CLUTTER_EXPORT
guint clutter_input_device_get_n_axes (ClutterInputDevice *device);
@ -122,11 +115,6 @@ gboolean clutter_input_device_get_axis_value (ClutterInputDev
CLUTTER_EXPORT
guint clutter_input_device_get_n_keys (ClutterInputDevice *device);
CLUTTER_EXPORT
void clutter_input_device_set_key (ClutterInputDevice *device,
guint index_,
guint keyval,
ClutterModifierType modifiers);
CLUTTER_EXPORT
gboolean clutter_input_device_get_key (ClutterInputDevice *device,
guint index_,
guint *keyval,
@ -137,11 +125,6 @@ ClutterInputDevice * clutter_input_device_get_associated_device (ClutterInput
CLUTTER_EXPORT
GList * clutter_input_device_get_slave_devices (ClutterInputDevice *device);
CLUTTER_EXPORT
void clutter_input_device_update_from_event (ClutterInputDevice *device,
ClutterEvent *event,
gboolean update_stage);
CLUTTER_EXPORT
void clutter_input_device_grab (ClutterInputDevice *device,
ClutterActor *actor);
@ -161,11 +144,6 @@ CLUTTER_EXPORT
ClutterActor * clutter_input_device_sequence_get_grabbed_actor (ClutterInputDevice *device,
ClutterEventSequence *sequence);
CLUTTER_EXPORT
gboolean clutter_input_device_keycode_to_evdev (ClutterInputDevice *device,
guint hardware_keycode,
guint *evdev_keycode);
CLUTTER_EXPORT
const gchar * clutter_input_device_get_vendor_id (ClutterInputDevice *device);
CLUTTER_EXPORT
@ -193,12 +171,6 @@ gint clutter_input_device_get_mode_switch_button_group (Clutt
CLUTTER_EXPORT
const gchar * clutter_input_device_get_device_node (ClutterInputDevice *device);
CLUTTER_EXPORT
ClutterInputDeviceMapping clutter_input_device_get_mapping_mode (ClutterInputDevice *device);
CLUTTER_EXPORT
void clutter_input_device_set_mapping_mode (ClutterInputDevice *device,
ClutterInputDeviceMapping mapping);
CLUTTER_EXPORT
gboolean clutter_input_device_is_grouped (ClutterInputDevice *device,
ClutterInputDevice *other_device);

View File

@ -454,6 +454,7 @@ clutter_input_method_forward_key (ClutterInputMethod *im,
ClutterInputMethodPrivate *priv;
ClutterInputDevice *keyboard;
ClutterSeat *seat;
ClutterStageManager *stage_manager;
ClutterStage *stage;
ClutterEvent *event;
@ -464,10 +465,9 @@ clutter_input_method_forward_key (ClutterInputMethod *im,
return;
seat = clutter_backend_get_default_seat (clutter_get_default_backend ());
stage_manager = clutter_stage_manager_get_default ();
stage = clutter_stage_manager_get_default_stage (stage_manager);
keyboard = clutter_seat_get_keyboard (seat);
stage = _clutter_input_device_get_stage (keyboard);
if (stage == NULL)
return;
event = clutter_event_new (press ? CLUTTER_KEY_PRESS : CLUTTER_KEY_RELEASE);
event->key.time = time_;

View File

@ -697,6 +697,8 @@ _clutter_context_get_default (void)
ctx->settings = clutter_settings_get_default ();
_clutter_settings_set_backend (ctx->settings, ctx->backend);
ctx->events_queue = g_async_queue_new ();
ctx->last_repaint_id = 1;
}
@ -1621,7 +1623,9 @@ _clutter_process_event_details (ClutterActor *stage,
emit_crossing_event (event, device);
actor = clutter_input_device_update (device, NULL, FALSE);
actor = clutter_input_device_update (device, NULL,
CLUTTER_STAGE (stage), FALSE,
event);
if (actor != stage)
{
ClutterEvent *crossing;
@ -1770,21 +1774,9 @@ _clutter_process_event_details (ClutterActor *stage,
break;
}
/* if the backend provides a device then we should
* already have everything we need to update it and
* get the actor underneath
*/
if (device != NULL)
actor = clutter_input_device_update (device, NULL, TRUE);
else
{
CLUTTER_NOTE (EVENT, "No device found: picking");
actor = _clutter_stage_do_pick (CLUTTER_STAGE (stage),
x, y,
CLUTTER_PICK_REACTIVE);
}
actor = clutter_input_device_update (device, NULL,
CLUTTER_STAGE (stage),
TRUE, event);
if (actor == NULL)
break;
@ -1860,9 +1852,6 @@ _clutter_process_event_details (ClutterActor *stage,
sequence =
clutter_event_get_event_sequence (event);
if (event->type == CLUTTER_TOUCH_BEGIN)
_clutter_input_device_add_event_sequence (device, event);
clutter_event_get_coords (event, &x, &y);
/* Only do a pick to find the source if source is not already set
@ -1892,17 +1881,9 @@ _clutter_process_event_details (ClutterActor *stage,
break;
}
if (device != NULL)
actor = clutter_input_device_update (device, sequence, TRUE);
else
{
CLUTTER_NOTE (EVENT, "No device found: picking");
actor = _clutter_stage_do_pick (CLUTTER_STAGE (stage),
x, y,
CLUTTER_PICK_REACTIVE);
}
actor = clutter_input_device_update (device, sequence,
CLUTTER_STAGE (stage),
TRUE, event);
if (actor == NULL)
break;
@ -1954,6 +1935,11 @@ _clutter_process_event_details (ClutterActor *stage,
case CLUTTER_CLIENT_MESSAGE:
break;
case CLUTTER_DEVICE_ADDED:
case CLUTTER_DEVICE_REMOVED:
_clutter_event_process_filters (event);
break;
case CLUTTER_EVENT_LAST:
break;
}
@ -2302,39 +2288,16 @@ void
_clutter_clear_events_queue (void)
{
ClutterMainContext *context = _clutter_context_get_default ();
ClutterEvent *event;
if (context->events_queue != NULL)
{
g_queue_foreach (context->events_queue,
(GFunc) clutter_event_free,
NULL);
g_queue_free (context->events_queue);
context->events_queue = NULL;
}
}
/* Lock the queue for as long as it lives */
g_async_queue_lock (context->events_queue);
void
_clutter_clear_events_queue_for_stage (ClutterStage *stage)
{
ClutterMainContext *context = _clutter_context_get_default ();
GList *l, *next;
if (context->events_queue == NULL)
return;
/* Remove any pending events for this stage from the event queue */
for (l = context->events_queue->head; l; l = next)
{
ClutterEvent *event = l->data;
next = l->next;
if (event->any.stage == stage)
{
g_queue_delete_link (context->events_queue, l);
while ((event = g_async_queue_try_pop_unlocked (context->events_queue)))
clutter_event_free (event);
}
}
g_async_queue_unref (context->events_queue);
context->events_queue = NULL;
}
ClutterPickMode

View File

@ -71,6 +71,9 @@ gboolean clutter_actor_has_transitions (ClutterActor *actor);
CLUTTER_EXPORT
ClutterFrameClock * clutter_actor_pick_frame_clock (ClutterActor *self,
ClutterActor **out_actor);
CLUTTER_EXPORT
gboolean clutter_seat_handle_event_post (ClutterSeat *seat,
const ClutterEvent *event);
#undef __CLUTTER_H_INSIDE__

View File

@ -122,7 +122,7 @@ struct _ClutterMainContext
ClutterStageManager *stage_manager;
/* the main event queue */
GQueue *events_queue;
GAsyncQueue *events_queue;
/* the event filters added via clutter_event_add_filter. these are
* ordered from least recently added to most recently added */

View File

@ -27,6 +27,7 @@
#include "clutter-input-device-tool.h"
#include "clutter-input-pointer-a11y-private.h"
#include "clutter-marshal.h"
#include "clutter-mutter.h"
#include "clutter-private.h"
#include "clutter-seat.h"
#include "clutter-virtual-input-device.h"
@ -65,9 +66,6 @@ struct _ClutterSeatPrivate
unsigned int inhibit_unfocus_count;
/* Keyboard a11y */
ClutterKbdA11ySettings kbd_a11y_settings;
/* Pointer a11y */
ClutterPointerA11ySettings pointer_a11y_settings;
};
@ -404,43 +402,6 @@ clutter_seat_get_keymap (ClutterSeat *seat)
return CLUTTER_SEAT_GET_CLASS (seat)->get_keymap (seat);
}
static gboolean
are_kbd_a11y_settings_equal (ClutterKbdA11ySettings *a,
ClutterKbdA11ySettings *b)
{
return (memcmp (a, b, sizeof (ClutterKbdA11ySettings)) == 0);
}
void
clutter_seat_set_kbd_a11y_settings (ClutterSeat *seat,
ClutterKbdA11ySettings *settings)
{
ClutterSeatClass *seat_class;
ClutterSeatPrivate *priv = clutter_seat_get_instance_private (seat);
g_return_if_fail (CLUTTER_IS_SEAT (seat));
if (are_kbd_a11y_settings_equal (&priv->kbd_a11y_settings, settings))
return;
priv->kbd_a11y_settings = *settings;
seat_class = CLUTTER_SEAT_GET_CLASS (seat);
if (seat_class->apply_kbd_a11y_settings)
seat_class->apply_kbd_a11y_settings (seat, settings);
}
void
clutter_seat_get_kbd_a11y_settings (ClutterSeat *seat,
ClutterKbdA11ySettings *settings)
{
ClutterSeatPrivate *priv = clutter_seat_get_instance_private (seat);
g_return_if_fail (CLUTTER_IS_SEAT (seat));
*settings = priv->kbd_a11y_settings;
}
void
clutter_seat_ensure_a11y_state (ClutterSeat *seat)
{
@ -674,6 +635,40 @@ clutter_seat_compress_motion (ClutterSeat *seat,
seat_class->compress_motion (seat, event, to_discard);
}
gboolean
clutter_seat_handle_event_post (ClutterSeat *seat,
const ClutterEvent *event)
{
ClutterSeatClass *seat_class;
ClutterInputDevice *device;
g_return_val_if_fail (CLUTTER_IS_SEAT (seat), FALSE);
g_return_val_if_fail (event, FALSE);
seat_class = CLUTTER_SEAT_GET_CLASS (seat);
if (seat_class->handle_event_post)
seat_class->handle_event_post (seat, event);
device = clutter_event_get_source_device (event);
g_assert_true (CLUTTER_IS_INPUT_DEVICE (device));
switch (event->type)
{
case CLUTTER_DEVICE_ADDED:
g_signal_emit (seat, signals[DEVICE_ADDED], 0, device);
break;
case CLUTTER_DEVICE_REMOVED:
g_signal_emit (seat, signals[DEVICE_REMOVED], 0, device);
g_object_run_dispose (G_OBJECT (device));
break;
default:
break;
}
return TRUE;
}
void
clutter_seat_warp_pointer (ClutterSeat *seat,
int x,
@ -709,3 +704,20 @@ clutter_seat_get_touch_mode (ClutterSeat *seat)
return touch_mode;
}
gboolean
clutter_seat_query_state (ClutterSeat *seat,
ClutterInputDevice *device,
ClutterEventSequence *sequence,
graphene_point_t *coords,
ClutterModifierType *modifiers)
{
g_return_val_if_fail (CLUTTER_IS_SEAT (seat), FALSE);
g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), FALSE);
return CLUTTER_SEAT_GET_CLASS (seat)->query_state (seat,
device,
sequence,
coords,
modifiers);
}

View File

@ -37,24 +37,6 @@ CLUTTER_EXPORT
G_DECLARE_DERIVABLE_TYPE (ClutterSeat, clutter_seat,
CLUTTER, SEAT, GObject)
/**
* ClutterKbdA11ySettings:
*
* The #ClutterKbdA11ySettings structure contains keyboard accessibility
* settings
*
*/
typedef struct _ClutterKbdA11ySettings
{
ClutterKeyboardA11yFlags controls;
gint slowkeys_delay;
gint debounce_delay;
gint timeout_delay;
gint mousekeys_init_delay;
gint mousekeys_max_speed;
gint mousekeys_accel_time;
} ClutterKbdA11ySettings;
/**
* ClutterPointerA11ySettings:
*
@ -106,10 +88,19 @@ struct _ClutterSeatClass
ClutterEvent *event,
const ClutterEvent *to_discard);
gboolean (* handle_event_post) (ClutterSeat *seat,
const ClutterEvent *event);
void (* warp_pointer) (ClutterSeat *seat,
int x,
int y);
gboolean (* query_state) (ClutterSeat *seat,
ClutterInputDevice *device,
ClutterEventSequence *sequence,
graphene_point_t *coords,
ClutterModifierType *modifiers);
/* Event platform data */
void (* copy_event_data) (ClutterSeat *seat,
const ClutterEvent *src,
@ -117,10 +108,6 @@ struct _ClutterSeatClass
void (* free_event_data) (ClutterSeat *seat,
ClutterEvent *event);
/* Keyboard accessibility */
void (* apply_kbd_a11y_settings) (ClutterSeat *seat,
ClutterKbdA11ySettings *settings);
/* Virtual devices */
ClutterVirtualInputDevice * (* create_virtual_device) (ClutterSeat *seat,
ClutterInputDeviceType device_type);
@ -140,12 +127,6 @@ void clutter_seat_bell_notify (ClutterSeat *seat);
CLUTTER_EXPORT
ClutterKeymap * clutter_seat_get_keymap (ClutterSeat *seat);
CLUTTER_EXPORT
void clutter_seat_set_kbd_a11y_settings (ClutterSeat *seat,
ClutterKbdA11ySettings *settings);
CLUTTER_EXPORT
void clutter_seat_get_kbd_a11y_settings (ClutterSeat *seat,
ClutterKbdA11ySettings *settings);
CLUTTER_EXPORT
void clutter_seat_ensure_a11y_state (ClutterSeat *seat);
@ -188,4 +169,11 @@ void clutter_seat_warp_pointer (ClutterSeat *seat,
CLUTTER_EXPORT
gboolean clutter_seat_get_touch_mode (ClutterSeat *seat);
CLUTTER_EXPORT
gboolean clutter_seat_query_state (ClutterSeat *seat,
ClutterInputDevice *device,
ClutterEventSequence *sequence,
graphene_point_t *coords,
ClutterModifierType *modifiers);
#endif /* CLUTTER_SEAT_H */

View File

@ -1013,7 +1013,6 @@ _clutter_stage_queue_event (ClutterStage *stage,
{
ClutterStagePrivate *priv;
gboolean first_event;
ClutterInputDevice *device;
g_return_if_fail (CLUTTER_IS_STAGE (stage));
@ -1024,25 +1023,6 @@ _clutter_stage_queue_event (ClutterStage *stage,
if (copy_event)
event = clutter_event_copy (event);
/* if needed, update the state of the input device of the event.
* we do it here to avoid calling the same code from every backend
* event processing function
*/
device = clutter_event_get_device (event);
if (device != NULL &&
event->type != CLUTTER_PROXIMITY_IN &&
event->type != CLUTTER_PROXIMITY_OUT)
{
ClutterEventSequence *sequence = clutter_event_get_event_sequence (event);
guint32 event_time = clutter_event_get_time (event);
gfloat event_x, event_y;
clutter_event_get_coords (event, &event_x, &event_y);
_clutter_input_device_set_coords (device, sequence, event_x, event_y, stage);
_clutter_input_device_set_time (device, event_time);
}
if (first_event)
{
gboolean compressible = event->type == CLUTTER_MOTION ||
@ -1363,7 +1343,7 @@ clutter_stage_update_devices (ClutterStage *stage,
for (l = devices; l; l = l->next)
{
ClutterInputDevice *device = l->data;
clutter_input_device_update (device, NULL, TRUE);
clutter_input_device_update (device, NULL, stage, TRUE, NULL);
}
}
@ -1680,7 +1660,7 @@ clutter_stage_dispose (GObject *object)
clutter_actor_hide (CLUTTER_ACTOR (object));
_clutter_clear_events_queue_for_stage (stage);
_clutter_clear_events_queue ();
if (priv->impl != NULL)
{

View File

@ -34,6 +34,7 @@
#include "backends/meta-backend-types.h"
#include "backends/meta-cursor-renderer.h"
#include "backends/meta-egl.h"
#include "backends/meta-input-mapper-private.h"
#include "backends/meta-input-settings-private.h"
#include "backends/meta-monitor-manager-private.h"
#include "backends/meta-orientation-manager.h"
@ -67,7 +68,8 @@ struct _MetaBackendClass
MetaMonitorManager * (* create_monitor_manager) (MetaBackend *backend,
GError **error);
MetaCursorRenderer * (* create_cursor_renderer) (MetaBackend *backend);
MetaCursorRenderer * (* get_cursor_renderer) (MetaBackend *backend,
ClutterInputDevice *device);
MetaCursorTracker * (* create_cursor_tracker) (MetaBackend *backend);
MetaRenderer * (* create_renderer) (MetaBackend *backend,
GError **error);
@ -105,6 +107,8 @@ struct _MetaBackendClass
void (* set_numlock) (MetaBackend *backend,
gboolean numlock_state);
void (* set_pointer_constraint) (MetaBackend *backend,
MetaPointerConstraint *constraint);
};
void meta_init_backend (GType backend_gtype);
@ -129,6 +133,8 @@ META_EXPORT_TEST
MetaMonitorManager * meta_backend_get_monitor_manager (MetaBackend *backend);
MetaOrientationManager * meta_backend_get_orientation_manager (MetaBackend *backend);
MetaCursorTracker * meta_backend_get_cursor_tracker (MetaBackend *backend);
MetaCursorRenderer * meta_backend_get_cursor_renderer_for_device (MetaBackend *backend,
ClutterInputDevice *device);
MetaCursorRenderer * meta_backend_get_cursor_renderer (MetaBackend *backend);
META_EXPORT_TEST
MetaRenderer * meta_backend_get_renderer (MetaBackend *backend);
@ -171,6 +177,7 @@ gboolean meta_is_stage_views_enabled (void);
gboolean meta_is_stage_views_scaled (void);
MetaInputMapper *meta_backend_get_input_mapper (MetaBackend *backend);
MetaInputSettings *meta_backend_get_input_settings (MetaBackend *backend);
void meta_backend_notify_keymap_changed (MetaBackend *backend);
@ -191,4 +198,12 @@ GList * meta_backend_get_gpus (MetaBackend *backend);
WacomDeviceDatabase * meta_backend_get_wacom_database (MetaBackend *backend);
#endif
void meta_backend_add_hw_cursor_inhibitor (MetaBackend *backend,
MetaHwCursorInhibitor *inhibitor);
void meta_backend_remove_hw_cursor_inhibitor (MetaBackend *backend,
MetaHwCursorInhibitor *inhibitor);
gboolean meta_backend_is_hw_cursors_inhibited (MetaBackend *backend);
#endif /* META_BACKEND_PRIVATE_H */

View File

@ -53,8 +53,10 @@
#include <stdlib.h>
#include "backends/meta-cursor-renderer.h"
#include "backends/meta-cursor-tracker-private.h"
#include "backends/meta-idle-monitor-private.h"
#include "backends/meta-input-mapper-private.h"
#include "backends/meta-input-settings-private.h"
#include "backends/meta-logical-monitor.h"
#include "backends/meta-monitor-manager-dummy.h"
@ -120,8 +122,9 @@ struct _MetaBackendPrivate
MetaMonitorManager *monitor_manager;
MetaOrientationManager *orientation_manager;
MetaCursorTracker *cursor_tracker;
MetaCursorRenderer *cursor_renderer;
GHashTable *cursor_renderers;
MetaInputSettings *input_settings;
MetaInputMapper *input_mapper;
MetaRenderer *renderer;
#ifdef HAVE_EGL
MetaEgl *egl;
@ -150,6 +153,7 @@ struct _MetaBackendPrivate
ClutterActor *stage;
GList *gpus;
GList *hw_cursor_inhibitors;
gboolean is_pointer_position_initialized;
@ -173,6 +177,14 @@ struct _MetaBackendPrivate
};
typedef struct _MetaBackendPrivate MetaBackendPrivate;
typedef struct _MetaBackendSource MetaBackendSource;
struct _MetaBackendSource
{
GSource parent;
MetaBackend *backend;
};
static void
initable_iface_init (GInitableIface *initable_iface);
@ -213,6 +225,8 @@ meta_backend_finalize (GObject *object)
g_clear_pointer (&priv->wacom_db, libwacom_database_destroy);
#endif
g_hash_table_unref (priv->cursor_renderers);
if (priv->sleep_signal_id)
g_dbus_connection_signal_unsubscribe (priv->system_bus, priv->sleep_signal_id);
if (priv->upower_watch_id)
@ -264,6 +278,19 @@ reset_pointer_position (MetaBackend *backend)
primary->rect.y + primary->rect.height * 0.9);
}
static void
update_cursors (MetaBackend *backend)
{
MetaBackendPrivate *priv = meta_backend_get_instance_private (backend);
MetaCursorRenderer *renderer;
GHashTableIter iter;
g_hash_table_iter_init (&iter, priv->cursor_renderers);
while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &renderer))
meta_cursor_renderer_force_update (renderer);
}
void
meta_backend_monitors_changed (MetaBackend *backend)
{
@ -289,7 +316,7 @@ meta_backend_monitors_changed (MetaBackend *backend)
}
}
meta_cursor_renderer_force_update (priv->cursor_renderer);
update_cursors (backend);
}
void
@ -355,8 +382,19 @@ on_device_added (ClutterSeat *seat,
gpointer user_data)
{
MetaBackend *backend = META_BACKEND (user_data);
MetaBackendPrivate *priv = meta_backend_get_instance_private (backend);
ClutterInputDeviceType device_type;
create_device_monitor (backend, device);
device_type = clutter_input_device_get_device_type (device);
if (device_type == CLUTTER_TOUCHSCREEN_DEVICE ||
device_type == CLUTTER_TABLET_DEVICE ||
device_type == CLUTTER_PEN_DEVICE ||
device_type == CLUTTER_ERASER_DEVICE ||
device_type == CLUTTER_CURSOR_DEVICE ||
device_type == CLUTTER_PAD_DEVICE)
meta_input_mapper_add_device (priv->input_mapper, device);
}
static inline gboolean
@ -428,6 +466,8 @@ on_device_removed (ClutterSeat *seat,
destroy_device_monitor (backend, device);
meta_input_mapper_remove_device (priv->input_mapper, device);
/* If the device the user last interacted goes away, check again pointer
* visibility.
*/
@ -438,6 +478,7 @@ on_device_removed (ClutterSeat *seat,
ClutterInputDeviceType device_type;
priv->current_device = NULL;
g_clear_handle_id (&priv->device_update_idle_id, g_source_remove);
device_type = clutter_input_device_get_device_type (device);
has_touchscreen = check_has_slave_touchscreen (seat);
@ -504,6 +545,42 @@ meta_backend_create_input_settings (MetaBackend *backend)
return META_BACKEND_GET_CLASS (backend)->create_input_settings (backend);
}
static void
input_mapper_device_mapped_cb (MetaInputMapper *mapper,
ClutterInputDevice *device,
float matrix[6],
MetaBackend *backend)
{
MetaBackendPrivate *priv = meta_backend_get_instance_private (backend);
MetaInputSettings *input_settings = priv->input_settings;
meta_input_settings_set_device_matrix (input_settings, device, matrix);
}
static void
input_mapper_device_enabled_cb (MetaInputMapper *mapper,
ClutterInputDevice *device,
gboolean enabled,
MetaBackend *backend)
{
MetaBackendPrivate *priv = meta_backend_get_instance_private (backend);
MetaInputSettings *input_settings = priv->input_settings;
meta_input_settings_set_device_enabled (input_settings, device, enabled);
}
static void
input_mapper_device_aspect_ratio_cb (MetaInputMapper *mapper,
ClutterInputDevice *device,
double aspect_ratio,
MetaBackend *backend)
{
MetaBackendPrivate *priv = meta_backend_get_instance_private (backend);
MetaInputSettings *input_settings = priv->input_settings;
meta_input_settings_set_device_aspect_ratio (input_settings, device, aspect_ratio);
}
static void
meta_backend_real_post_init (MetaBackend *backend)
{
@ -519,8 +596,6 @@ meta_backend_real_post_init (MetaBackend *backend)
meta_backend_sync_screen_size (backend);
priv->cursor_renderer = META_BACKEND_GET_CLASS (backend)->create_cursor_renderer (backend);
priv->device_monitors =
g_hash_table_new_full (NULL, NULL, NULL, (GDestroyNotify) g_object_unref);
@ -529,7 +604,8 @@ meta_backend_real_post_init (MetaBackend *backend)
g_signal_connect_object (seat, "device-added",
G_CALLBACK (on_device_added), backend, 0);
g_signal_connect_object (seat, "device-removed",
G_CALLBACK (on_device_removed), backend, 0);
G_CALLBACK (on_device_removed), backend,
G_CONNECT_AFTER);
set_initial_pointer_visibility (backend, seat);
@ -544,6 +620,14 @@ meta_backend_real_post_init (MetaBackend *backend)
meta_input_settings_maybe_restore_numlock_state (priv->input_settings);
}
priv->input_mapper = meta_input_mapper_new ();
g_signal_connect (priv->input_mapper, "device-mapped",
G_CALLBACK (input_mapper_device_mapped_cb), backend);
g_signal_connect (priv->input_mapper, "device-enabled",
G_CALLBACK (input_mapper_device_enabled_cb), backend);
g_signal_connect (priv->input_mapper, "device-aspect-ratio",
G_CALLBACK (input_mapper_device_aspect_ratio_cb), backend);
#ifdef HAVE_REMOTE_DESKTOP
priv->dbus_session_watcher = g_object_new (META_TYPE_DBUS_SESSION_WATCHER, NULL);
priv->screen_cast = meta_screen_cast_new (backend,
@ -916,10 +1000,18 @@ clutter_source_dispatch (GSource *source,
GSourceFunc callback,
gpointer user_data)
{
MetaBackendSource *backend_source = (MetaBackendSource *) source;
MetaBackendPrivate *priv =
meta_backend_get_instance_private (backend_source->backend);
ClutterEvent *event = clutter_event_get ();
ClutterSeat *seat;
if (event)
{
event->any.stage =
CLUTTER_STAGE (meta_backend_get_stage (backend_source->backend));
seat = clutter_backend_get_default_seat (priv->clutter_backend);
clutter_seat_handle_event_post (seat, event);
clutter_do_event (event);
clutter_event_free (event);
}
@ -945,6 +1037,7 @@ static gboolean
init_clutter (MetaBackend *backend,
GError **error)
{
MetaBackendSource *backend_source;
GSource *source;
clutter_set_custom_backend_func (meta_get_clutter_backend);
@ -956,7 +1049,9 @@ init_clutter (MetaBackend *backend,
return FALSE;
}
source = g_source_new (&clutter_source_funcs, sizeof (GSource));
source = g_source_new (&clutter_source_funcs, sizeof (MetaBackendSource));
backend_source = (MetaBackendSource *) source;
backend_source->backend = backend;
g_source_attach (source, NULL);
g_source_unref (source);
@ -1081,8 +1176,25 @@ MetaCursorRenderer *
meta_backend_get_cursor_renderer (MetaBackend *backend)
{
MetaBackendPrivate *priv = meta_backend_get_instance_private (backend);
ClutterInputDevice *pointer;
ClutterSeat *seat;
return priv->cursor_renderer;
seat = clutter_backend_get_default_seat (priv->clutter_backend);
pointer = clutter_seat_get_pointer (seat);
return meta_backend_get_cursor_renderer_for_device (backend, pointer);
}
MetaCursorRenderer *
meta_backend_get_cursor_renderer_for_device (MetaBackend *backend,
ClutterInputDevice *device)
{
g_return_val_if_fail (META_IS_BACKEND (backend), NULL);
g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), NULL);
g_return_val_if_fail (clutter_input_device_get_device_type (device) !=
CLUTTER_KEYBOARD_DEVICE, NULL);
return META_BACKEND_GET_CLASS (backend)->get_cursor_renderer (backend, device);
}
/**
@ -1329,7 +1441,7 @@ meta_backend_get_client_pointer_constraint (MetaBackend *backend)
* @constraint: (nullable): the client constraint to follow.
*
* Sets the current pointer constraint and removes (and unrefs) the previous
* one. If @constrant is %NULL, this means that there is no
* one. If @constraint is %NULL, this means that there is no
* #MetaPointerConstraint active.
*/
void
@ -1338,11 +1450,8 @@ meta_backend_set_client_pointer_constraint (MetaBackend *backend,
{
MetaBackendPrivate *priv = meta_backend_get_instance_private (backend);
g_assert (!constraint || !priv->client_pointer_constraint);
g_clear_object (&priv->client_pointer_constraint);
if (constraint)
priv->client_pointer_constraint = g_object_ref (constraint);
META_BACKEND_GET_CLASS (backend)->set_pointer_constraint (backend, constraint);
g_set_object (&priv->client_pointer_constraint, constraint);
}
ClutterBackend *
@ -1408,6 +1517,14 @@ meta_is_stage_views_scaled (void)
return layout_mode == META_LOGICAL_MONITOR_LAYOUT_MODE_LOGICAL;
}
MetaInputMapper *
meta_backend_get_input_mapper (MetaBackend *backend)
{
MetaBackendPrivate *priv = meta_backend_get_instance_private (backend);
return priv->input_mapper;
}
MetaInputSettings *
meta_backend_get_input_settings (MetaBackend *backend)
{
@ -1474,3 +1591,40 @@ meta_backend_get_wacom_database (MetaBackend *backend)
return priv->wacom_db;
}
#endif
void
meta_backend_add_hw_cursor_inhibitor (MetaBackend *backend,
MetaHwCursorInhibitor *inhibitor)
{
MetaBackendPrivate *priv = meta_backend_get_instance_private (backend);
priv->hw_cursor_inhibitors = g_list_prepend (priv->hw_cursor_inhibitors,
inhibitor);
}
void
meta_backend_remove_hw_cursor_inhibitor (MetaBackend *backend,
MetaHwCursorInhibitor *inhibitor)
{
MetaBackendPrivate *priv = meta_backend_get_instance_private (backend);
priv->hw_cursor_inhibitors = g_list_remove (priv->hw_cursor_inhibitors,
inhibitor);
}
gboolean
meta_backend_is_hw_cursors_inhibited (MetaBackend *backend)
{
MetaBackendPrivate *priv = meta_backend_get_instance_private (backend);
GList *l;
for (l = priv->hw_cursor_inhibitors; l; l = l->next)
{
MetaHwCursorInhibitor *inhibitor = l->data;
if (meta_hw_cursor_inhibitor_is_cursor_inhibited (inhibitor))
return TRUE;
}
return FALSE;
}

View File

@ -28,6 +28,8 @@
#include <math.h>
#include "backends/meta-backend-private.h"
#include "backends/meta-logical-monitor.h"
#include "backends/meta-stage-private.h"
#include "clutter/clutter.h"
#include "clutter/clutter-mutter.h"
@ -44,6 +46,7 @@ enum
PROP_0,
PROP_BACKEND,
PROP_DEVICE,
N_PROPS
};
@ -57,6 +60,7 @@ struct _MetaCursorRendererPrivate
float current_x;
float current_y;
ClutterInputDevice *device;
MetaCursorSprite *displayed_cursor;
MetaCursorSprite *overlay_cursor;
@ -77,14 +81,13 @@ static guint signals[LAST_SIGNAL];
G_DEFINE_TYPE_WITH_PRIVATE (MetaCursorRenderer, meta_cursor_renderer, G_TYPE_OBJECT);
static gboolean
meta_hw_cursor_inhibitor_is_cursor_sprite_inhibited (MetaHwCursorInhibitor *inhibitor,
MetaCursorSprite *cursor_sprite)
gboolean
meta_hw_cursor_inhibitor_is_cursor_inhibited (MetaHwCursorInhibitor *inhibitor)
{
MetaHwCursorInhibitorInterface *iface =
META_HW_CURSOR_INHIBITOR_GET_IFACE (inhibitor);
return iface->is_cursor_sprite_inhibited (inhibitor, cursor_sprite);
return iface->is_cursor_inhibited (inhibitor);
}
static void
@ -203,6 +206,9 @@ meta_cursor_renderer_get_property (GObject *object,
case PROP_BACKEND:
g_value_set_object (value, priv->backend);
break;
case PROP_DEVICE:
g_value_set_object (value, priv->device);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@ -224,6 +230,9 @@ meta_cursor_renderer_set_property (GObject *object,
case PROP_BACKEND:
priv->backend = g_value_get_object (value);
break;
case PROP_DEVICE:
priv->device = g_value_get_object (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@ -284,6 +293,14 @@ meta_cursor_renderer_class_init (MetaCursorRendererClass *klass)
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS);
obj_props[PROP_DEVICE] =
g_param_spec_object ("device",
"device",
"Input device",
CLUTTER_TYPE_INPUT_DEVICE,
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS);
g_object_class_install_properties (object_class, N_PROPS, obj_props);
signals[CURSOR_PAINTED] = g_signal_new ("cursor-painted",
@ -332,6 +349,41 @@ meta_cursor_renderer_calculate_rect (MetaCursorRenderer *renderer,
};
}
static float
find_highest_logical_monitor_scale (MetaBackend *backend,
MetaCursorSprite *cursor_sprite)
{
MetaMonitorManager *monitor_manager =
meta_backend_get_monitor_manager (backend);
MetaCursorRenderer *cursor_renderer =
meta_backend_get_cursor_renderer (backend);
graphene_rect_t cursor_rect;
GList *logical_monitors;
GList *l;
float highest_scale = 0.0;
cursor_rect = meta_cursor_renderer_calculate_rect (cursor_renderer,
cursor_sprite);
logical_monitors =
meta_monitor_manager_get_logical_monitors (monitor_manager);
for (l = logical_monitors; l; l = l->next)
{
MetaLogicalMonitor *logical_monitor = l->data;
graphene_rect_t logical_monitor_rect =
meta_rectangle_to_graphene_rect (&logical_monitor->rect);
if (!graphene_rect_intersection (&cursor_rect,
&logical_monitor_rect,
NULL))
continue;
highest_scale = MAX (highest_scale, logical_monitor->scale);
}
return highest_scale;
}
static void
meta_cursor_renderer_update_cursor (MetaCursorRenderer *renderer,
MetaCursorSprite *cursor_sprite)
@ -340,9 +392,14 @@ meta_cursor_renderer_update_cursor (MetaCursorRenderer *renderer,
gboolean handled_by_backend;
if (cursor_sprite)
{
float scale = find_highest_logical_monitor_scale (priv->backend,
cursor_sprite);
meta_cursor_sprite_prepare_at (cursor_sprite,
MAX (1, scale),
(int) priv->current_x,
(int) priv->current_y);
}
handled_by_backend =
META_CURSOR_RENDERER_GET_CLASS (renderer)->update_cursor (renderer,
@ -354,10 +411,12 @@ meta_cursor_renderer_update_cursor (MetaCursorRenderer *renderer,
}
MetaCursorRenderer *
meta_cursor_renderer_new (MetaBackend *backend)
meta_cursor_renderer_new (MetaBackend *backend,
ClutterInputDevice *device)
{
return g_object_new (META_TYPE_CURSOR_RENDERER,
"backend", backend,
"device", device,
NULL);
}
@ -384,30 +443,18 @@ meta_cursor_renderer_force_update (MetaCursorRenderer *renderer)
}
void
meta_cursor_renderer_set_position (MetaCursorRenderer *renderer,
float x,
float y)
meta_cursor_renderer_update_position (MetaCursorRenderer *renderer)
{
MetaCursorRendererPrivate *priv = meta_cursor_renderer_get_instance_private (renderer);
graphene_point_t pos;
priv->current_x = x;
priv->current_y = y;
clutter_input_device_get_coords (priv->device, NULL, &pos);
priv->current_x = pos.x;
priv->current_y = pos.y;
meta_cursor_renderer_update_cursor (renderer, priv->displayed_cursor);
}
graphene_point_t
meta_cursor_renderer_get_position (MetaCursorRenderer *renderer)
{
MetaCursorRendererPrivate *priv =
meta_cursor_renderer_get_instance_private (renderer);
return (graphene_point_t) {
.x = priv->current_x,
.y = priv->current_y
};
}
MetaCursorSprite *
meta_cursor_renderer_get_cursor (MetaCursorRenderer *renderer)
{
@ -428,44 +475,11 @@ meta_cursor_renderer_is_overlay_visible (MetaCursorRenderer *renderer)
return meta_overlay_is_visible (priv->stage_overlay);
}
void
meta_cursor_renderer_add_hw_cursor_inhibitor (MetaCursorRenderer *renderer,
MetaHwCursorInhibitor *inhibitor)
ClutterInputDevice *
meta_cursor_renderer_get_input_device (MetaCursorRenderer *renderer)
{
MetaCursorRendererPrivate *priv =
meta_cursor_renderer_get_instance_private (renderer);
priv->hw_cursor_inhibitors = g_list_prepend (priv->hw_cursor_inhibitors,
inhibitor);
}
void
meta_cursor_renderer_remove_hw_cursor_inhibitor (MetaCursorRenderer *renderer,
MetaHwCursorInhibitor *inhibitor)
{
MetaCursorRendererPrivate *priv =
meta_cursor_renderer_get_instance_private (renderer);
priv->hw_cursor_inhibitors = g_list_remove (priv->hw_cursor_inhibitors,
inhibitor);
}
gboolean
meta_cursor_renderer_is_hw_cursors_inhibited (MetaCursorRenderer *renderer,
MetaCursorSprite *cursor_sprite)
{
MetaCursorRendererPrivate *priv =
meta_cursor_renderer_get_instance_private (renderer);
GList *l;
for (l = priv->hw_cursor_inhibitors; l; l = l->next)
{
MetaHwCursorInhibitor *inhibitor = l->data;
if (meta_hw_cursor_inhibitor_is_cursor_sprite_inhibited (inhibitor,
cursor_sprite))
return TRUE;
}
return FALSE;
return priv->device;
}

View File

@ -38,10 +38,11 @@ struct _MetaHwCursorInhibitorInterface
{
GTypeInterface parent_iface;
gboolean (* is_cursor_sprite_inhibited) (MetaHwCursorInhibitor *inhibitor,
MetaCursorSprite *cursor_sprite);
gboolean (* is_cursor_inhibited) (MetaHwCursorInhibitor *inhibitor);
};
gboolean meta_hw_cursor_inhibitor_is_cursor_inhibited (MetaHwCursorInhibitor *inhibitor);
#define META_TYPE_CURSOR_RENDERER (meta_cursor_renderer_get_type ())
G_DECLARE_DERIVABLE_TYPE (MetaCursorRenderer, meta_cursor_renderer,
META, CURSOR_RENDERER, GObject);
@ -54,35 +55,25 @@ struct _MetaCursorRendererClass
MetaCursorSprite *cursor_sprite);
};
MetaCursorRenderer * meta_cursor_renderer_new (MetaBackend *backend);
MetaCursorRenderer * meta_cursor_renderer_new (MetaBackend *backend,
ClutterInputDevice *device);
void meta_cursor_renderer_set_cursor (MetaCursorRenderer *renderer,
MetaCursorSprite *cursor_sprite);
void meta_cursor_renderer_set_position (MetaCursorRenderer *renderer,
float x,
float y);
graphene_point_t meta_cursor_renderer_get_position (MetaCursorRenderer *renderer);
void meta_cursor_renderer_update_position (MetaCursorRenderer *renderer);
void meta_cursor_renderer_force_update (MetaCursorRenderer *renderer);
MetaCursorSprite * meta_cursor_renderer_get_cursor (MetaCursorRenderer *renderer);
gboolean meta_cursor_renderer_is_overlay_visible (MetaCursorRenderer *renderer);
void meta_cursor_renderer_add_hw_cursor_inhibitor (MetaCursorRenderer *renderer,
MetaHwCursorInhibitor *inhibitor);
void meta_cursor_renderer_remove_hw_cursor_inhibitor (MetaCursorRenderer *renderer,
MetaHwCursorInhibitor *inhibitor);
gboolean meta_cursor_renderer_is_hw_cursors_inhibited (MetaCursorRenderer *renderer,
MetaCursorSprite *cursor_sprite);
graphene_rect_t meta_cursor_renderer_calculate_rect (MetaCursorRenderer *renderer,
MetaCursorSprite *cursor_sprite);
void meta_cursor_renderer_emit_painted (MetaCursorRenderer *renderer,
MetaCursorSprite *cursor_sprite);
ClutterInputDevice * meta_cursor_renderer_get_input_device (MetaCursorRenderer *renderer);
void meta_cursor_renderer_update_stage_overlay (MetaCursorRenderer *renderer,
MetaCursorSprite *cursor_sprite);

View File

@ -41,16 +41,12 @@ void meta_cursor_tracker_unset_window_cursor (MetaCursorTracker *tracker);
void meta_cursor_tracker_set_root_cursor (MetaCursorTracker *tracker,
MetaCursorSprite *cursor_sprite);
void meta_cursor_tracker_update_position (MetaCursorTracker *tracker,
float new_x,
float new_y);
void meta_cursor_tracker_update_position (MetaCursorTracker *tracker);
void meta_cursor_tracker_track_position (MetaCursorTracker *tracker);
void meta_cursor_tracker_untrack_position (MetaCursorTracker *tracker);
MetaCursorSprite * meta_cursor_tracker_get_displayed_cursor (MetaCursorTracker *tracker);
MetaBackend * meta_cursor_tracker_get_backend (MetaCursorTracker *tracker);
void meta_cursor_tracker_notify_cursor_changed (MetaCursorTracker *tracker);

View File

@ -31,15 +31,12 @@
#include "backends/meta-cursor-tracker-private.h"
#include <gdk/gdk.h>
#include <gdk/gdkx.h>
#include <string.h>
#include "backends/meta-backend-private.h"
#include "cogl/cogl.h"
#include "core/display-private.h"
#include "clutter/clutter.h"
#include "meta-marshal.h"
#include "meta/main.h"
#include "meta/util.h"
@ -303,14 +300,8 @@ meta_cursor_tracker_class_init (MetaCursorTrackerClass *klass)
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST,
0,
NULL, NULL,
meta_marshal_VOID__FLOAT_FLOAT,
G_TYPE_NONE, 2,
G_TYPE_FLOAT,
G_TYPE_FLOAT);
g_signal_set_va_marshaller (signals[CURSOR_MOVED],
G_TYPE_FROM_CLASS (klass),
meta_marshal_VOID__FLOAT_FLOATv);
NULL, NULL, NULL,
G_TYPE_NONE, 0);
signals[VISIBILITY_CHANGED] = g_signal_new ("visibility-changed",
G_TYPE_FROM_CLASS (klass),
@ -437,88 +428,23 @@ meta_cursor_tracker_set_root_cursor (MetaCursorTracker *tracker,
}
void
meta_cursor_tracker_update_position (MetaCursorTracker *tracker,
float new_x,
float new_y)
meta_cursor_tracker_update_position (MetaCursorTracker *tracker)
{
MetaCursorTrackerPrivate *priv =
meta_cursor_tracker_get_instance_private (tracker);
MetaCursorRenderer *cursor_renderer =
meta_backend_get_cursor_renderer (priv->backend);
gboolean position_changed;
if (priv->x != new_x || priv->y != new_y)
{
position_changed = TRUE;
priv->x = new_x;
priv->y = new_y;
}
else
{
position_changed = FALSE;
}
meta_cursor_renderer_set_position (cursor_renderer, new_x, new_y);
if (position_changed)
g_signal_emit (tracker, signals[CURSOR_MOVED], 0, new_x, new_y);
}
static void
get_pointer_position_gdk (int *x,
int *y,
int *mods)
{
GdkSeat *gseat;
GdkDevice *gdevice;
GdkScreen *gscreen;
gseat = gdk_display_get_default_seat (gdk_display_get_default ());
gdevice = gdk_seat_get_pointer (gseat);
gdk_device_get_position (gdevice, &gscreen, x, y);
if (mods)
gdk_device_get_state (gdevice,
gdk_screen_get_root_window (gscreen),
NULL, (GdkModifierType*)mods);
}
static void
get_pointer_position_clutter (int *x,
int *y,
int *mods)
{
ClutterSeat *seat;
ClutterInputDevice *cdevice;
graphene_point_t point;
seat = clutter_backend_get_default_seat (clutter_get_default_backend ());
cdevice = clutter_seat_get_pointer (seat);
clutter_input_device_get_coords (cdevice, NULL, &point);
if (x)
*x = point.x;
if (y)
*y = point.y;
if (mods)
*mods = clutter_input_device_get_modifier_state (cdevice);
g_signal_emit (tracker, signals[CURSOR_MOVED], 0);
}
void
meta_cursor_tracker_get_pointer (MetaCursorTracker *tracker,
int *x,
int *y,
graphene_point_t *coords,
ClutterModifierType *mods)
{
/* We can't use the clutter interface when not running as a wayland compositor,
because we need to query the server, rather than using the last cached value.
OTOH, on wayland we can't use GDK, because that only sees the events
we forward to xwayland.
*/
if (meta_is_wayland_compositor ())
get_pointer_position_clutter (x, y, (int*)mods);
else
get_pointer_position_gdk (x, y, (int*)mods);
ClutterSeat *seat;
ClutterInputDevice *cdevice;
seat = clutter_backend_get_default_seat (clutter_get_default_backend ());
cdevice = clutter_seat_get_pointer (seat);
clutter_seat_query_state (seat, cdevice, NULL, coords, mods);
}
void
@ -579,16 +505,6 @@ meta_cursor_tracker_set_pointer_visible (MetaCursorTracker *tracker,
g_signal_emit (tracker, signals[VISIBILITY_CHANGED], 0);
}
MetaCursorSprite *
meta_cursor_tracker_get_displayed_cursor (MetaCursorTracker *tracker)
{
MetaCursorTrackerPrivate *priv =
meta_cursor_tracker_get_instance_private (tracker);
return priv->displayed_cursor;
}
MetaBackend *
meta_cursor_tracker_get_backend (MetaCursorTracker *tracker)
{

View File

@ -180,10 +180,11 @@ meta_cursor_sprite_get_texture_transform (MetaCursorSprite *sprite)
void
meta_cursor_sprite_prepare_at (MetaCursorSprite *sprite,
float best_scale,
int x,
int y)
{
g_signal_emit (sprite, signals[PREPARE_AT], 0, x, y);
g_signal_emit (sprite, signals[PREPARE_AT], 0, best_scale, x, y);
}
void
@ -226,7 +227,8 @@ meta_cursor_sprite_class_init (MetaCursorSpriteClass *klass)
G_SIGNAL_RUN_LAST,
0,
NULL, NULL, NULL,
G_TYPE_NONE, 2,
G_TYPE_NONE, 3,
G_TYPE_FLOAT,
G_TYPE_INT,
G_TYPE_INT);
signals[TEXTURE_CHANGED] = g_signal_new ("texture-changed",

View File

@ -43,6 +43,7 @@ struct _MetaCursorSpriteClass
};
void meta_cursor_sprite_prepare_at (MetaCursorSprite *sprite,
float best_scale,
int x,
int y);

View File

@ -23,7 +23,8 @@
#define META_INPUT_MAPPER_H
#include <clutter/clutter.h>
#include "meta-monitor-manager-private.h"
#include "backends/meta-backend-types.h"
#define META_TYPE_INPUT_MAPPER (meta_input_mapper_get_type ())
@ -33,8 +34,7 @@ G_DECLARE_FINAL_TYPE (MetaInputMapper, meta_input_mapper,
MetaInputMapper * meta_input_mapper_new (void);
void meta_input_mapper_add_device (MetaInputMapper *mapper,
ClutterInputDevice *device,
gboolean builtin);
ClutterInputDevice *device);
void meta_input_mapper_remove_device (MetaInputMapper *mapper,
ClutterInputDevice *device);
@ -46,4 +46,7 @@ MetaLogicalMonitor *
meta_input_mapper_get_device_logical_monitor (MetaInputMapper *mapper,
ClutterInputDevice *device);
GSettings * meta_input_mapper_get_tablet_settings (MetaInputMapper *mapper,
ClutterInputDevice *device);
#endif /* META_INPUT_MAPPER_H */

View File

@ -24,6 +24,7 @@
#include <gudev/gudev.h>
#endif
#include "backends/meta-input-device-private.h"
#include "meta-input-mapper-private.h"
#include "meta-monitor-manager-private.h"
#include "meta-logical-monitor.h"
@ -59,6 +60,7 @@ typedef enum
typedef enum
{
META_MATCH_CONFIG, /* Specified by config */
META_MATCH_IS_BUILTIN, /* Output is builtin, applies mainly to system-integrated devices */
META_MATCH_SIZE, /* Size from input device and output match */
META_MATCH_EDID_FULL, /* Full EDID model match, eg. "Cintiq 12WX" */
@ -72,6 +74,7 @@ struct _MetaMapperInputInfo
ClutterInputDevice *device;
MetaInputMapper *mapper;
MetaMapperOutputInfo *output;
GSettings *settings;
guint builtin : 1;
};
@ -99,24 +102,149 @@ struct _DeviceCandidates
enum
{
DEVICE_MAPPED,
DEVICE_ENABLED,
DEVICE_ASPECT_RATIO,
N_SIGNALS
};
static guint signals[N_SIGNALS] = { 0, };
static void mapper_recalculate_input (MetaInputMapper *mapper,
MetaMapperInputInfo *input);
G_DEFINE_TYPE (MetaInputMapper, meta_input_mapper, G_TYPE_OBJECT)
static GSettings *
get_device_settings (ClutterInputDevice *device)
{
const gchar *group, *schema, *vendor, *product;
ClutterInputDeviceType type;
GSettings *settings;
gchar *path;
type = clutter_input_device_get_device_type (device);
if (type == CLUTTER_TOUCHSCREEN_DEVICE)
{
group = "touchscreens";
schema = "org.gnome.desktop.peripherals.touchscreen";
}
else if (type == CLUTTER_TABLET_DEVICE ||
type == CLUTTER_PEN_DEVICE ||
type == CLUTTER_ERASER_DEVICE ||
type == CLUTTER_CURSOR_DEVICE ||
type == CLUTTER_PAD_DEVICE)
{
group = "tablets";
schema = "org.gnome.desktop.peripherals.tablet";
}
else
return NULL;
vendor = clutter_input_device_get_vendor_id (device);
product = clutter_input_device_get_product_id (device);
path = g_strdup_printf ("/org/gnome/desktop/peripherals/%s/%s:%s/",
group, vendor, product);
settings = g_settings_new_with_path (schema, path);
g_free (path);
return settings;
}
static MetaMonitor *
logical_monitor_find_monitor (MetaLogicalMonitor *logical_monitor,
const char *vendor,
const char *product,
const char *serial)
{
GList *monitors;
GList *l;
monitors = meta_logical_monitor_get_monitors (logical_monitor);
for (l = monitors; l; l = l->next)
{
MetaMonitor *monitor = l->data;
if (g_strcmp0 (meta_monitor_get_vendor (monitor), vendor) == 0 &&
g_strcmp0 (meta_monitor_get_product (monitor), product) == 0 &&
g_strcmp0 (meta_monitor_get_serial (monitor), serial) == 0)
return monitor;
}
return NULL;
}
static void
find_settings_monitor (MetaInputMapper *mapper,
GSettings *settings,
ClutterInputDevice *device,
MetaMonitor **out_monitor,
MetaLogicalMonitor **out_logical_monitor)
{
MetaMonitor *monitor;
guint n_values;
GList *logical_monitors;
GList *l;
gchar **edid;
edid = g_settings_get_strv (settings, "output");
n_values = g_strv_length (edid);
if (n_values != 3)
{
g_warning ("EDID configuration for device '%s' "
"is incorrect, must have 3 values",
clutter_input_device_get_device_name (device));
goto out;
}
if (!*edid[0] && !*edid[1] && !*edid[2])
goto out;
logical_monitors =
meta_monitor_manager_get_logical_monitors (mapper->monitor_manager);
for (l = logical_monitors; l; l = l->next)
{
MetaLogicalMonitor *logical_monitor = l->data;
monitor = logical_monitor_find_monitor (logical_monitor,
edid[0], edid[1], edid[2]);
if (monitor)
{
if (out_monitor)
*out_monitor = monitor;
if (out_logical_monitor)
*out_logical_monitor = logical_monitor;
break;
}
}
out:
g_strfreev (edid);
}
static void
settings_output_changed_cb (GSettings *settings,
const gchar *key,
MetaMapperInputInfo *info)
{
mapper_recalculate_input (info->mapper, info);
}
static MetaMapperInputInfo *
mapper_input_info_new (ClutterInputDevice *device,
MetaInputMapper *mapper,
gboolean builtin)
MetaInputMapper *mapper)
{
MetaMapperInputInfo *info;
info = g_new0 (MetaMapperInputInfo, 1);
info->mapper = mapper;
info->device = device;
info->builtin = builtin;
info->settings = get_device_settings (device);
g_signal_connect (info->settings, "changed::output",
G_CALLBACK (settings_output_changed_cb), info);
return info;
}
@ -124,6 +252,7 @@ mapper_input_info_new (ClutterInputDevice *device,
static void
mapper_input_info_free (MetaMapperInputInfo *info)
{
g_object_unref (info->settings);
g_free (info);
}
@ -174,13 +303,36 @@ mapper_input_info_set_output (MetaMapperInputInfo *input,
MetaMapperOutputInfo *output,
MetaMonitor *monitor)
{
MetaInputMapper *mapper = input->mapper;
float matrix[6] = { 1, 0, 0, 0, 1, 0 };
double aspect_ratio;
int width, height;
if (input->output == output)
return;
input->output = output;
if (output && monitor)
{
meta_monitor_manager_get_monitor_matrix (mapper->monitor_manager,
monitor,
output->logical_monitor,
matrix);
meta_monitor_get_current_resolution (monitor, &width, &height);
}
else
{
meta_monitor_manager_get_screen_size (mapper->monitor_manager,
&width, &height);
}
aspect_ratio = (double) width / height;
g_signal_emit (input->mapper, signals[DEVICE_MAPPED], 0,
input->device,
output ? output->logical_monitor : NULL, monitor);
input->device, matrix);
g_signal_emit (input->mapper, signals[DEVICE_ASPECT_RATIO], 0,
input->device, aspect_ratio);
}
static void
@ -361,6 +513,32 @@ guess_candidates (MetaInputMapper *mapper,
MetaOutputMatchType best = N_OUTPUT_MATCHES;
GList *monitors, *l;
MetaMonitor *matched_monitor = NULL;
gboolean builtin = FALSE;
gboolean integrated = TRUE;
#ifdef HAVE_LIBWACOM
if (clutter_input_device_get_device_type (input->device) != CLUTTER_TOUCHSCREEN_DEVICE)
{
WacomDevice *wacom_device;
WacomIntegrationFlags flags = 0;
wacom_device =
meta_input_device_get_wacom_device (META_INPUT_DEVICE (input->device));
if (wacom_device)
{
flags = libwacom_get_integration_flags (wacom_device);
if ((flags & (WACOM_DEVICE_INTEGRATED_SYSTEM |
WACOM_DEVICE_INTEGRATED_DISPLAY)) == 0)
return;
integrated = (flags & (WACOM_DEVICE_INTEGRATED_SYSTEM |
WACOM_DEVICE_INTEGRATED_DISPLAY)) != 0;
builtin = (flags & WACOM_DEVICE_INTEGRATED_SYSTEM) != 0;
}
}
#endif
monitors = meta_monitor_manager_get_monitors (mapper->monitor_manager);
@ -375,18 +553,23 @@ guess_candidates (MetaInputMapper *mapper,
}
}
if (find_size_match (input, monitors, &matched_monitor))
if (integrated && find_size_match (input, monitors, &matched_monitor))
{
best = MIN (best, META_MATCH_SIZE);
info->candidates[META_MATCH_SIZE] = matched_monitor;
}
if (input->builtin || best == N_OUTPUT_MATCHES)
if (builtin || best == N_OUTPUT_MATCHES)
{
best = MIN (best, META_MATCH_IS_BUILTIN);
find_builtin_output (mapper, &info->candidates[META_MATCH_IS_BUILTIN]);
}
find_settings_monitor (mapper, input->settings, input->device,
&info->candidates[META_MATCH_CONFIG], NULL);
if (info->candidates[META_MATCH_CONFIG])
best = MIN (best, META_MATCH_CONFIG);
info->best = best;
}
@ -524,6 +707,37 @@ input_mapper_monitors_changed_cb (MetaMonitorManager *monitor_manager,
mapper_update_outputs (mapper);
}
static void
input_mapper_power_save_mode_changed_cb (MetaMonitorManager *monitor_manager,
MetaInputMapper *mapper)
{
ClutterInputDevice *device;
MetaLogicalMonitor *logical_monitor;
MetaMonitor *builtin;
MetaPowerSave power_save_mode;
gboolean on;
power_save_mode =
meta_monitor_manager_get_power_save_mode (mapper->monitor_manager);
on = power_save_mode == META_POWER_SAVE_ON;
if (!find_builtin_output (mapper, &builtin))
return;
logical_monitor = meta_monitor_get_logical_monitor (builtin);
if (!logical_monitor)
return;
device =
meta_input_mapper_get_logical_monitor_device (mapper,
logical_monitor,
CLUTTER_TOUCHSCREEN_DEVICE);
if (!device)
return;
g_signal_emit (mapper, signals[DEVICE_ENABLED], 0, device, on);
}
static void
input_mapper_device_removed_cb (ClutterSeat *seat,
ClutterInputDevice *device,
@ -576,6 +790,9 @@ meta_input_mapper_constructed (GObject *object)
mapper->monitor_manager = meta_backend_get_monitor_manager (backend);
g_signal_connect (mapper->monitor_manager, "monitors-changed-internal",
G_CALLBACK (input_mapper_monitors_changed_cb), mapper);
g_signal_connect (mapper->monitor_manager, "power-save-mode-changed",
G_CALLBACK (input_mapper_power_save_mode_changed_cb),
mapper);
mapper_update_outputs (mapper);
}
@ -594,9 +811,27 @@ meta_input_mapper_class_init (MetaInputMapperClass *klass)
G_SIGNAL_RUN_LAST,
0,
NULL, NULL, NULL,
G_TYPE_NONE, 3,
G_TYPE_NONE, 2,
CLUTTER_TYPE_INPUT_DEVICE,
G_TYPE_POINTER, G_TYPE_POINTER);
G_TYPE_POINTER);
signals[DEVICE_ENABLED] =
g_signal_new ("device-enabled",
G_TYPE_FROM_CLASS (object_class),
G_SIGNAL_RUN_LAST,
0,
NULL, NULL, NULL,
G_TYPE_NONE, 2,
CLUTTER_TYPE_INPUT_DEVICE,
G_TYPE_BOOLEAN);
signals[DEVICE_ASPECT_RATIO] =
g_signal_new ("device-aspect-ratio",
G_TYPE_FROM_CLASS (object_class),
G_SIGNAL_RUN_LAST,
0,
NULL, NULL, NULL,
G_TYPE_NONE, 2,
CLUTTER_TYPE_INPUT_DEVICE,
G_TYPE_DOUBLE);
}
static void
@ -618,8 +853,7 @@ meta_input_mapper_new (void)
void
meta_input_mapper_add_device (MetaInputMapper *mapper,
ClutterInputDevice *device,
gboolean builtin)
ClutterInputDevice *device)
{
MetaMapperInputInfo *info;
@ -629,7 +863,7 @@ meta_input_mapper_add_device (MetaInputMapper *mapper,
if (g_hash_table_contains (mapper->input_devices, device))
return;
info = mapper_input_info_new (device, mapper, builtin);
info = mapper_input_info_new (device, mapper);
g_hash_table_insert (mapper->input_devices, device, info);
mapper_recalculate_input (mapper, info);
}
@ -676,6 +910,43 @@ meta_input_mapper_get_logical_monitor_device (MetaInputMapper *mapper,
return NULL;
}
static ClutterInputDevice *
find_grouped_pen (ClutterInputDevice *device)
{
GList *l, *devices;
ClutterInputDeviceType device_type;
ClutterInputDevice *pen = NULL;
ClutterSeat *seat;
device_type = clutter_input_device_get_device_type (device);
if (device_type == CLUTTER_TABLET_DEVICE ||
device_type == CLUTTER_PEN_DEVICE)
return device;
seat = clutter_input_device_get_seat (device);
devices = clutter_seat_list_devices (seat);
for (l = devices; l; l = l->next)
{
ClutterInputDevice *other_device = l->data;
device_type = clutter_input_device_get_device_type (other_device);
if ((device_type == CLUTTER_TABLET_DEVICE ||
device_type == CLUTTER_PEN_DEVICE) &&
clutter_input_device_is_grouped (device, other_device))
{
pen = other_device;
break;
}
}
g_list_free (devices);
return pen;
}
MetaLogicalMonitor *
meta_input_mapper_get_device_logical_monitor (MetaInputMapper *mapper,
ClutterInputDevice *device)
@ -685,6 +956,13 @@ meta_input_mapper_get_device_logical_monitor (MetaInputMapper *mapper,
GHashTableIter iter;
GList *l;
if (clutter_input_device_get_device_type (device) == CLUTTER_PAD_DEVICE)
{
device = find_grouped_pen (device);
if (!device)
return NULL;
}
g_hash_table_iter_init (&iter, mapper->output_devices);
while (g_hash_table_iter_next (&iter, (gpointer *) &logical_monitor,
@ -701,3 +979,19 @@ meta_input_mapper_get_device_logical_monitor (MetaInputMapper *mapper,
return NULL;
}
GSettings *
meta_input_mapper_get_tablet_settings (MetaInputMapper *mapper,
ClutterInputDevice *device)
{
MetaMapperInputInfo *input;
g_return_val_if_fail (META_IS_INPUT_MAPPER (mapper), NULL);
g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), NULL);
input = g_hash_table_lookup (mapper->input_devices, device);
if (!input)
return NULL;
return input->settings;
}

View File

@ -36,6 +36,62 @@
G_DECLARE_DERIVABLE_TYPE (MetaInputSettings, meta_input_settings,
META, INPUT_SETTINGS, GObject)
/**
* MetaKeyboardA11yFlags:
* @CLUTTER_A11Y_KEYBOARD_ENABLED:
* @CLUTTER_A11Y_TIMEOUT_ENABLED:
* @CLUTTER_A11Y_MOUSE_KEYS_ENABLED:
* @CLUTTER_A11Y_SLOW_KEYS_ENABLED:
* @CLUTTER_A11Y_SLOW_KEYS_BEEP_PRESS:
* @CLUTTER_A11Y_SLOW_KEYS_BEEP_ACCEPT:
* @CLUTTER_A11Y_SLOW_KEYS_BEEP_REJECT:
* @CLUTTER_A11Y_BOUNCE_KEYS_ENABLED:
* @CLUTTER_A11Y_BOUNCE_KEYS_BEEP_REJECT:
* @CLUTTER_A11Y_TOGGLE_KEYS_ENABLED:
* @CLUTTER_A11Y_STICKY_KEYS_ENABLED:
* @CLUTTER_A11Y_STICKY_KEYS_TWO_KEY_OFF:
* @CLUTTER_A11Y_STICKY_KEYS_BEEP:
* @CLUTTER_A11Y_FEATURE_STATE_CHANGE_BEEP:
*
* Keyboard accessibility features applied to a ClutterInputDevice keyboard.
*
*/
typedef enum
{
META_A11Y_KEYBOARD_ENABLED = 1 << 0,
META_A11Y_TIMEOUT_ENABLED = 1 << 1,
META_A11Y_MOUSE_KEYS_ENABLED = 1 << 2,
META_A11Y_SLOW_KEYS_ENABLED = 1 << 3,
META_A11Y_SLOW_KEYS_BEEP_PRESS = 1 << 4,
META_A11Y_SLOW_KEYS_BEEP_ACCEPT = 1 << 5,
META_A11Y_SLOW_KEYS_BEEP_REJECT = 1 << 6,
META_A11Y_BOUNCE_KEYS_ENABLED = 1 << 7,
META_A11Y_BOUNCE_KEYS_BEEP_REJECT = 1 << 8,
META_A11Y_TOGGLE_KEYS_ENABLED = 1 << 9,
META_A11Y_STICKY_KEYS_ENABLED = 1 << 10,
META_A11Y_STICKY_KEYS_TWO_KEY_OFF = 1 << 11,
META_A11Y_STICKY_KEYS_BEEP = 1 << 12,
META_A11Y_FEATURE_STATE_CHANGE_BEEP = 1 << 13,
} MetaKeyboardA11yFlags;
/**
* MetaKbdA11ySettings:
*
* The #MetaKbdA11ySettings structure contains keyboard accessibility
* settings
*
*/
typedef struct _MetaKbdA11ySettings
{
MetaKeyboardA11yFlags controls;
gint slowkeys_delay;
gint debounce_delay;
gint timeout_delay;
gint mousekeys_init_delay;
gint mousekeys_max_speed;
gint mousekeys_accel_time;
} MetaKbdA11ySettings;
struct _MetaInputSettingsClass
{
GObjectClass parent_class;
@ -92,10 +148,9 @@ struct _MetaInputSettingsClass
void (* set_tablet_mapping) (MetaInputSettings *settings,
ClutterInputDevice *device,
GDesktopTabletMapping mapping);
void (* set_tablet_keep_aspect) (MetaInputSettings *settings,
void (* set_tablet_aspect_ratio) (MetaInputSettings *settings,
ClutterInputDevice *device,
MetaLogicalMonitor *logical_monitor,
gboolean keep_aspect);
double ratio);
void (* set_tablet_area) (MetaInputSettings *settings,
ClutterInputDevice *device,
gdouble padding_left,
@ -137,26 +192,31 @@ struct _MetaInputSettingsClass
ClutterInputDevice *device);
};
GSettings * meta_input_settings_get_tablet_settings (MetaInputSettings *settings,
ClutterInputDevice *device);
MetaLogicalMonitor * meta_input_settings_get_tablet_logical_monitor (MetaInputSettings *settings,
ClutterInputDevice *device);
GDesktopTabletMapping meta_input_settings_get_tablet_mapping (MetaInputSettings *settings,
ClutterInputDevice *device);
gboolean meta_input_settings_is_pad_button_grabbed (MetaInputSettings *input_settings,
ClutterInputDevice *pad,
guint button);
gboolean meta_input_settings_handle_pad_event (MetaInputSettings *input_settings,
const ClutterEvent *event);
gchar * meta_input_settings_get_pad_action_label (MetaInputSettings *input_settings,
ClutterInputDevice *pad,
MetaPadActionType action,
guint number);
void meta_input_settings_maybe_save_numlock_state (MetaInputSettings *input_settings);
void meta_input_settings_maybe_restore_numlock_state (MetaInputSettings *input_settings);
void meta_input_settings_set_device_matrix (MetaInputSettings *input_settings,
ClutterInputDevice *device,
float matrix[6]);
void meta_input_settings_set_device_enabled (MetaInputSettings *input_settings,
ClutterInputDevice *device,
gboolean enabled);
void meta_input_settings_set_device_aspect_ratio (MetaInputSettings *input_settings,
ClutterInputDevice *device,
double aspect_ratio);
void meta_input_settings_get_kbd_a11y_settings (MetaInputSettings *input_settings,
MetaKbdA11ySettings *a11y_settings);
void meta_input_settings_add_device (MetaInputSettings *input_settings,
ClutterInputDevice *device);
void meta_input_settings_remove_device (MetaInputSettings *input_settings,
ClutterInputDevice *device);
void meta_input_settings_notify_tool_change (MetaInputSettings *input_settings,
ClutterInputDevice *device,
ClutterInputDeviceTool *tool);
void meta_input_settings_notify_kbd_a11y_change (MetaInputSettings *input_settings,
MetaKeyboardA11yFlags new_flags,
MetaKeyboardA11yFlags what_changed);
#endif /* META_INPUT_SETTINGS_PRIVATE_H */

File diff suppressed because it is too large Load Diff

View File

@ -31,6 +31,7 @@
#include "backends/meta-cursor.h"
#include "backends/meta-display-config-shared.h"
#include "backends/meta-monitor-transform.h"
#include "backends/meta-viewport-info.h"
#include "core/util-private.h"
#include "meta/display.h"
#include "meta/meta-monitor-manager.h"
@ -405,4 +406,6 @@ meta_find_output_assignment (MetaOutputAssignment **outputs,
return NULL;
}
MetaViewportInfo * meta_monitor_manager_get_viewports (MetaMonitorManager *manager);
#endif /* META_MONITOR_MANAGER_PRIVATE_H */

View File

@ -3175,3 +3175,37 @@ meta_monitor_manager_get_vendor_name (MetaMonitorManager *manager,
return gnome_pnp_ids_get_pnp_id (manager->pnp_ids, vendor);
}
MetaViewportInfo *
meta_monitor_manager_get_viewports (MetaMonitorManager *manager)
{
MetaViewportInfo *info;
GArray *views, *scales;
GList *logical_monitors, *l;
views = g_array_new (FALSE, FALSE, sizeof (cairo_rectangle_int_t));
scales = g_array_new (FALSE, FALSE, sizeof (float));
logical_monitors = meta_monitor_manager_get_logical_monitors (manager);
for (l = logical_monitors; l; l = l->next)
{
MetaLogicalMonitor *logical_monitor = l->data;
cairo_rectangle_int_t rect;
float scale;
rect = logical_monitor->rect;
g_array_append_val (views, rect);
scale = logical_monitor->scale;
g_array_append_val (scales, scale);
}
info = meta_viewport_info_new ((cairo_rectangle_int_t *) views->data,
(float *) scales->data,
views->len);
g_array_unref (views);
g_array_unref (scales);
return info;
}

View File

@ -39,8 +39,19 @@
#include "backends/meta-pointer-constraint.h"
#ifdef HAVE_NATIVE_BACKEND
#include "backends/native/meta-backend-native.h"
#include "backends/native/meta-pointer-constraint-native.h"
#endif
#include <glib-object.h>
struct _MetaPointerConstraint
{
GObject parent_instance;
cairo_region_t *region;
};
G_DEFINE_TYPE (MetaPointerConstraint, meta_pointer_constraint, G_TYPE_OBJECT);
static void
@ -53,9 +64,40 @@ meta_pointer_constraint_class_init (MetaPointerConstraintClass *klass)
{
}
MetaPointerConstraint *
meta_pointer_constraint_new (const cairo_region_t *region)
{
MetaPointerConstraint *constraint;
constraint = g_object_new (META_TYPE_POINTER_CONSTRAINT, NULL);
constraint->region = cairo_region_copy (region);
return constraint;
}
cairo_region_t *
meta_pointer_constraint_get_region (MetaPointerConstraint *constraint)
{
return constraint->region;
}
G_DEFINE_TYPE (MetaPointerConstraintImpl, meta_pointer_constraint_impl,
G_TYPE_OBJECT);
static void
meta_pointer_constraint_impl_init (MetaPointerConstraintImpl *impl)
{
}
static void
meta_pointer_constraint_impl_class_init (MetaPointerConstraintImplClass *klass)
{
}
/**
* meta_pointer_constraint_constrain:
* @constraint: a #MetaPointerConstraint.
* meta_pointer_constraint_impl_constrain:
* @impl: a #MetaPointerConstraintImpl.
* @device; the device of the pointer.
* @time: the timestamp (in ms) of the event.
* @prev_x: X-coordinate of the previous pointer position.
@ -67,17 +109,25 @@ meta_pointer_constraint_class_init (MetaPointerConstraintClass *klass)
* if needed.
*/
void
meta_pointer_constraint_constrain (MetaPointerConstraint *constraint,
meta_pointer_constraint_impl_constrain (MetaPointerConstraintImpl *impl,
ClutterInputDevice *device,
guint32 time,
uint32_t time,
float prev_x,
float prev_y,
float *x,
float *y)
{
META_POINTER_CONSTRAINT_GET_CLASS (constraint)->constrain (constraint,
META_POINTER_CONSTRAINT_IMPL_GET_CLASS (impl)->constrain (impl,
device,
time,
prev_x, prev_y,
x, y);
}
void
meta_pointer_constraint_impl_ensure_constrained (MetaPointerConstraintImpl *impl,
ClutterInputDevice *device)
{
META_POINTER_CONSTRAINT_IMPL_GET_CLASS (impl)->ensure_constrained (impl,
device);
}

View File

@ -32,34 +32,45 @@
G_BEGIN_DECLS
#define META_TYPE_POINTER_CONSTRAINT (meta_pointer_constraint_get_type ())
G_DECLARE_DERIVABLE_TYPE (MetaPointerConstraint, meta_pointer_constraint,
G_DECLARE_FINAL_TYPE (MetaPointerConstraint, meta_pointer_constraint,
META, POINTER_CONSTRAINT, GObject);
MetaPointerConstraint * meta_pointer_constraint_new (const cairo_region_t *region);
cairo_region_t * meta_pointer_constraint_get_region (MetaPointerConstraint *constraint);
#define META_TYPE_POINTER_CONSTRAINT_IMPL (meta_pointer_constraint_impl_get_type ())
G_DECLARE_DERIVABLE_TYPE (MetaPointerConstraintImpl, meta_pointer_constraint_impl,
META, POINTER_CONSTRAINT_IMPL, GObject);
/**
* MetaPointerConstraintClass:
* MetaPointerConstraintImplClass:
* @constrain: the virtual function pointer for
* meta_pointer_constraint_constrain().
* meta_pointer_constraint_impl_constrain().
*/
struct _MetaPointerConstraintClass
struct _MetaPointerConstraintImplClass
{
GObjectClass parent_class;
void (*constrain) (MetaPointerConstraint *constraint,
void (* constrain) (MetaPointerConstraintImpl *impl,
ClutterInputDevice *device,
guint32 time,
uint32_t time,
float prev_x,
float prev_y,
float *x,
float *y);
void (* ensure_constrained) (MetaPointerConstraintImpl *impl,
ClutterInputDevice *device);
};
void meta_pointer_constraint_constrain (MetaPointerConstraint *constraint,
void meta_pointer_constraint_impl_constrain (MetaPointerConstraintImpl *impl,
ClutterInputDevice *device,
guint32 time,
uint32_t time,
float prev_x,
float prev_y,
float *x,
float *y);
void meta_pointer_constraint_impl_ensure_constrained (MetaPointerConstraintImpl *impl,
ClutterInputDevice *device);
G_END_DECLS

View File

@ -83,19 +83,6 @@ get_backend (MetaScreenCastAreaStreamSrc *area_src)
return meta_screen_cast_get_backend (screen_cast);
}
static MetaCursorRenderer *
get_cursor_renderer (MetaScreenCastAreaStreamSrc *area_src)
{
MetaScreenCastStreamSrc *src = META_SCREEN_CAST_STREAM_SRC (area_src);
MetaScreenCastStream *stream = meta_screen_cast_stream_src_get_stream (src);
MetaScreenCastSession *session = meta_screen_cast_stream_get_session (stream);
MetaScreenCast *screen_cast =
meta_screen_cast_session_get_screen_cast (session);
MetaBackend *backend = meta_screen_cast_get_backend (screen_cast);
return meta_backend_get_cursor_renderer (backend);
}
static void
meta_screen_cast_area_stream_src_get_specs (MetaScreenCastStreamSrc *src,
int *width,
@ -142,9 +129,11 @@ is_cursor_in_stream (MetaScreenCastAreaStreamSrc *area_src)
}
else
{
MetaCursorTracker *cursor_tracker =
meta_backend_get_cursor_tracker (backend);
graphene_point_t cursor_position;
cursor_position = meta_cursor_renderer_get_position (cursor_renderer);
meta_cursor_tracker_get_pointer (cursor_tracker, &cursor_position, NULL);
return graphene_rect_contains_point (&area_rect, &cursor_position);
}
}
@ -184,8 +173,6 @@ sync_cursor_state (MetaScreenCastAreaStreamSrc *area_src)
static void
cursor_moved (MetaCursorTracker *cursor_tracker,
float x,
float y,
MetaScreenCastAreaStreamSrc *area_src)
{
sync_cursor_state (area_src);
@ -202,14 +189,14 @@ cursor_changed (MetaCursorTracker *cursor_tracker,
static void
inhibit_hw_cursor (MetaScreenCastAreaStreamSrc *area_src)
{
MetaCursorRenderer *cursor_renderer;
MetaHwCursorInhibitor *inhibitor;
MetaBackend *backend;
g_return_if_fail (!area_src->hw_cursor_inhibited);
cursor_renderer = get_cursor_renderer (area_src);
backend = get_backend (area_src);
inhibitor = META_HW_CURSOR_INHIBITOR (area_src);
meta_cursor_renderer_add_hw_cursor_inhibitor (cursor_renderer, inhibitor);
meta_backend_add_hw_cursor_inhibitor (backend, inhibitor);
area_src->hw_cursor_inhibited = TRUE;
}
@ -217,14 +204,14 @@ inhibit_hw_cursor (MetaScreenCastAreaStreamSrc *area_src)
static void
uninhibit_hw_cursor (MetaScreenCastAreaStreamSrc *area_src)
{
MetaCursorRenderer *cursor_renderer;
MetaHwCursorInhibitor *inhibitor;
MetaBackend *backend;
g_return_if_fail (area_src->hw_cursor_inhibited);
cursor_renderer = get_cursor_renderer (area_src);
backend = get_backend (area_src);
inhibitor = META_HW_CURSOR_INHIBITOR (area_src);
meta_cursor_renderer_remove_hw_cursor_inhibitor (cursor_renderer, inhibitor);
meta_backend_remove_hw_cursor_inhibitor (backend, inhibitor);
area_src->hw_cursor_inhibited = FALSE;
}
@ -506,6 +493,8 @@ meta_screen_cast_area_stream_src_set_cursor_metadata (MetaScreenCastStreamSrc *s
MetaScreenCastStream *stream = meta_screen_cast_stream_src_get_stream (src);
MetaScreenCastAreaStream *area_stream = META_SCREEN_CAST_AREA_STREAM (stream);
MetaBackend *backend = get_backend (area_src);
MetaCursorTracker *cursor_tracker =
meta_backend_get_cursor_tracker (backend);
MetaCursorRenderer *cursor_renderer =
meta_backend_get_cursor_renderer (backend);
MetaCursorSprite *cursor_sprite;
@ -526,7 +515,7 @@ meta_screen_cast_area_stream_src_set_cursor_metadata (MetaScreenCastStreamSrc *s
area = meta_screen_cast_area_stream_get_area (area_stream);
scale = meta_screen_cast_area_stream_get_scale (area_stream);
cursor_position = meta_cursor_renderer_get_position (cursor_renderer);
meta_cursor_tracker_get_pointer (cursor_tracker, &cursor_position, NULL);
cursor_position.x -= area->x;
cursor_position.y -= area->y;
cursor_position.x *= scale;
@ -568,8 +557,7 @@ meta_screen_cast_area_stream_src_set_cursor_metadata (MetaScreenCastStreamSrc *s
}
static gboolean
meta_screen_cast_area_stream_src_is_cursor_sprite_inhibited (MetaHwCursorInhibitor *inhibitor,
MetaCursorSprite *cursor_sprite)
meta_screen_cast_area_stream_src_is_cursor_inhibited (MetaHwCursorInhibitor *inhibitor)
{
MetaScreenCastAreaStreamSrc *area_src =
META_SCREEN_CAST_AREA_STREAM_SRC (inhibitor);
@ -580,8 +568,8 @@ meta_screen_cast_area_stream_src_is_cursor_sprite_inhibited (MetaHwCursorInhibit
static void
hw_cursor_inhibitor_iface_init (MetaHwCursorInhibitorInterface *iface)
{
iface->is_cursor_sprite_inhibited =
meta_screen_cast_area_stream_src_is_cursor_sprite_inhibited;
iface->is_cursor_inhibited =
meta_screen_cast_area_stream_src_is_cursor_inhibited;
}
MetaScreenCastAreaStreamSrc *

View File

@ -170,9 +170,11 @@ is_cursor_in_stream (MetaScreenCastMonitorStreamSrc *monitor_src)
}
else
{
MetaCursorTracker *cursor_tracker =
meta_backend_get_cursor_tracker (backend);
graphene_point_t cursor_position;
cursor_position = meta_cursor_renderer_get_position (cursor_renderer);
meta_cursor_tracker_get_pointer (cursor_tracker, &cursor_position, NULL);
return graphene_rect_contains_point (&logical_monitor_rect,
&cursor_position);
}
@ -221,8 +223,6 @@ sync_cursor_state (MetaScreenCastMonitorStreamSrc *monitor_src)
static void
cursor_moved (MetaCursorTracker *cursor_tracker,
float x,
float y,
MetaScreenCastMonitorStreamSrc *monitor_src)
{
sync_cursor_state (monitor_src);
@ -236,30 +236,17 @@ cursor_changed (MetaCursorTracker *cursor_tracker,
sync_cursor_state (monitor_src);
}
static MetaCursorRenderer *
get_cursor_renderer (MetaScreenCastMonitorStreamSrc *monitor_src)
{
MetaScreenCastStreamSrc *src = META_SCREEN_CAST_STREAM_SRC (monitor_src);
MetaScreenCastStream *stream = meta_screen_cast_stream_src_get_stream (src);
MetaScreenCastSession *session = meta_screen_cast_stream_get_session (stream);
MetaScreenCast *screen_cast =
meta_screen_cast_session_get_screen_cast (session);
MetaBackend *backend = meta_screen_cast_get_backend (screen_cast);
return meta_backend_get_cursor_renderer (backend);
}
static void
inhibit_hw_cursor (MetaScreenCastMonitorStreamSrc *monitor_src)
{
MetaCursorRenderer *cursor_renderer;
MetaHwCursorInhibitor *inhibitor;
MetaBackend *backend;
g_return_if_fail (!monitor_src->hw_cursor_inhibited);
cursor_renderer = get_cursor_renderer (monitor_src);
backend = get_backend (monitor_src);
inhibitor = META_HW_CURSOR_INHIBITOR (monitor_src);
meta_cursor_renderer_add_hw_cursor_inhibitor (cursor_renderer, inhibitor);
meta_backend_add_hw_cursor_inhibitor (backend, inhibitor);
monitor_src->hw_cursor_inhibited = TRUE;
}
@ -267,14 +254,14 @@ inhibit_hw_cursor (MetaScreenCastMonitorStreamSrc *monitor_src)
static void
uninhibit_hw_cursor (MetaScreenCastMonitorStreamSrc *monitor_src)
{
MetaCursorRenderer *cursor_renderer;
MetaHwCursorInhibitor *inhibitor;
MetaBackend *backend;
g_return_if_fail (monitor_src->hw_cursor_inhibited);
cursor_renderer = get_cursor_renderer (monitor_src);
backend = get_backend (monitor_src);
inhibitor = META_HW_CURSOR_INHIBITOR (monitor_src);
meta_cursor_renderer_remove_hw_cursor_inhibitor (cursor_renderer, inhibitor);
meta_backend_remove_hw_cursor_inhibitor (backend, inhibitor);
monitor_src->hw_cursor_inhibited = FALSE;
}
@ -598,6 +585,8 @@ meta_screen_cast_monitor_stream_src_set_cursor_metadata (MetaScreenCastStreamSrc
MetaBackend *backend = get_backend (monitor_src);
MetaCursorRenderer *cursor_renderer =
meta_backend_get_cursor_renderer (backend);
MetaCursorTracker *cursor_tracker =
meta_backend_get_cursor_tracker (backend);
MetaCursorSprite *cursor_sprite;
MetaMonitor *monitor;
MetaLogicalMonitor *logical_monitor;
@ -627,7 +616,7 @@ meta_screen_cast_monitor_stream_src_set_cursor_metadata (MetaScreenCastStreamSrc
else
view_scale = 1.0;
cursor_position = meta_cursor_renderer_get_position (cursor_renderer);
meta_cursor_tracker_get_pointer (cursor_tracker, &cursor_position, NULL);
cursor_position.x -= logical_monitor_rect.origin.x;
cursor_position.y -= logical_monitor_rect.origin.y;
cursor_position.x *= view_scale;
@ -669,8 +658,7 @@ meta_screen_cast_monitor_stream_src_set_cursor_metadata (MetaScreenCastStreamSrc
}
static gboolean
meta_screen_cast_monitor_stream_src_is_cursor_sprite_inhibited (MetaHwCursorInhibitor *inhibitor,
MetaCursorSprite *cursor_sprite)
meta_screen_cast_monitor_stream_src_is_cursor_inhibited (MetaHwCursorInhibitor *inhibitor)
{
MetaScreenCastMonitorStreamSrc *monitor_src =
META_SCREEN_CAST_MONITOR_STREAM_SRC (inhibitor);
@ -681,8 +669,8 @@ meta_screen_cast_monitor_stream_src_is_cursor_sprite_inhibited (MetaHwCursorInhi
static void
hw_cursor_inhibitor_iface_init (MetaHwCursorInhibitorInterface *iface)
{
iface->is_cursor_sprite_inhibited =
meta_screen_cast_monitor_stream_src_is_cursor_sprite_inhibited;
iface->is_cursor_inhibited =
meta_screen_cast_monitor_stream_src_is_cursor_inhibited;
}
MetaScreenCastMonitorStreamSrc *

View File

@ -110,6 +110,8 @@ maybe_draw_cursor_sprite (MetaScreenCastWindowStreamSrc *window_src,
MetaBackend *backend = get_backend (window_src);
MetaCursorRenderer *cursor_renderer =
meta_backend_get_cursor_renderer (backend);
MetaCursorTracker *cursor_tracker =
meta_backend_get_cursor_tracker (backend);
MetaCursorSprite *cursor_sprite;
CoglTexture *cursor_texture;
MetaScreenCastWindow *screen_cast_window;
@ -133,7 +135,7 @@ maybe_draw_cursor_sprite (MetaScreenCastWindowStreamSrc *window_src,
return;
screen_cast_window = window_src->screen_cast_window;
cursor_position = meta_cursor_renderer_get_position (cursor_renderer);
meta_cursor_tracker_get_pointer (cursor_tracker, &cursor_position, NULL);
if (!meta_screen_cast_window_transform_cursor_position (screen_cast_window,
cursor_sprite,
&cursor_position,
@ -189,6 +191,8 @@ maybe_blit_cursor_sprite (MetaScreenCastWindowStreamSrc *window_src,
clutter_backend_get_cogl_context (clutter_get_default_backend ());
MetaCursorRenderer *cursor_renderer =
meta_backend_get_cursor_renderer (backend);
MetaCursorTracker *cursor_tracker =
meta_backend_get_cursor_tracker (backend);
MetaScreenCastWindow *screen_cast_window;
MetaCursorSprite *cursor_sprite;
graphene_point_t relative_cursor_position;
@ -209,7 +213,7 @@ maybe_blit_cursor_sprite (MetaScreenCastWindowStreamSrc *window_src,
return;
screen_cast_window = window_src->screen_cast_window;
cursor_position = meta_cursor_renderer_get_position (cursor_renderer);
meta_cursor_tracker_get_pointer (cursor_tracker, &cursor_position, NULL);
if (!meta_screen_cast_window_transform_cursor_position (screen_cast_window,
cursor_sprite,
&cursor_position,
@ -360,13 +364,15 @@ is_cursor_in_stream (MetaScreenCastWindowStreamSrc *window_src)
MetaBackend *backend = get_backend (window_src);
MetaCursorRenderer *cursor_renderer =
meta_backend_get_cursor_renderer (backend);
MetaCursorTracker *cursor_tracker =
meta_backend_get_cursor_tracker (backend);
MetaCursorSprite *cursor_sprite;
graphene_point_t cursor_position;
MetaScreenCastWindow *screen_cast_window;
cursor_sprite = meta_cursor_renderer_get_cursor (cursor_renderer);
cursor_position = meta_cursor_renderer_get_position (cursor_renderer);
meta_cursor_tracker_get_pointer (cursor_tracker, &cursor_position, NULL);
screen_cast_window = window_src->screen_cast_window;
return meta_screen_cast_window_transform_cursor_position (screen_cast_window,
@ -394,8 +400,6 @@ sync_cursor_state (MetaScreenCastWindowStreamSrc *window_src)
static void
cursor_moved (MetaCursorTracker *cursor_tracker,
float x,
float y,
MetaScreenCastWindowStreamSrc *window_src)
{
sync_cursor_state (window_src);
@ -541,6 +545,8 @@ meta_screen_cast_window_stream_src_set_cursor_metadata (MetaScreenCastStreamSrc
MetaBackend *backend = get_backend (window_src);
MetaCursorRenderer *cursor_renderer =
meta_backend_get_cursor_renderer (backend);
MetaCursorTracker *cursor_tracker =
meta_backend_get_cursor_tracker (backend);
MetaScreenCastWindow *screen_cast_window = window_src->screen_cast_window;
MetaCursorSprite *cursor_sprite;
graphene_point_t cursor_position;
@ -549,7 +555,7 @@ meta_screen_cast_window_stream_src_set_cursor_metadata (MetaScreenCastStreamSrc
int x, y;
cursor_sprite = meta_cursor_renderer_get_cursor (cursor_renderer);
cursor_position = meta_cursor_renderer_get_position (cursor_renderer);
meta_cursor_tracker_get_pointer (cursor_tracker, &cursor_position, NULL);
if (!meta_screen_cast_window_transform_cursor_position (screen_cast_window,
cursor_sprite,

View File

@ -0,0 +1,212 @@
/*
* 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>
*/
#include "config.h"
#include "meta-viewport-info.h"
#include "core/main-private.h"
#include "core/boxes-private.h"
typedef struct _ViewInfo ViewInfo;
struct _ViewInfo
{
cairo_rectangle_int_t rect;
float scale;
};
struct _MetaViewportInfo
{
GObject parent_class;
GArray *views;
};
G_DEFINE_TYPE (MetaViewportInfo, meta_viewport_info, G_TYPE_OBJECT)
static void
meta_viewport_info_finalize (GObject *object)
{
MetaViewportInfo *info = META_VIEWPORT_INFO (object);
g_array_unref (info->views);
G_OBJECT_CLASS (meta_viewport_info_parent_class)->finalize (object);
}
static void
meta_viewport_info_class_init (MetaViewportInfoClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->finalize = meta_viewport_info_finalize;
}
static void
meta_viewport_info_init (MetaViewportInfo *info)
{
info->views = g_array_new (FALSE, FALSE, sizeof (ViewInfo));
}
MetaViewportInfo *
meta_viewport_info_new (cairo_rectangle_int_t *views,
float *scales,
guint n_views)
{
MetaViewportInfo *viewport_info;
int i;
viewport_info = g_object_new (META_TYPE_VIEWPORT_INFO, NULL);
for (i = 0; i < n_views; i++)
{
ViewInfo info;
info.rect = views[i];
info.scale = scales[i];
g_array_append_val (viewport_info->views, info);
}
return viewport_info;
}
int
meta_viewport_info_get_view_at (MetaViewportInfo *viewport_info,
float x,
float y)
{
int i;
for (i = 0; i < viewport_info->views->len; i++)
{
ViewInfo *info = &g_array_index (viewport_info->views, ViewInfo, i);
if (META_POINT_IN_RECT (x, y, info->rect))
return i;
}
return -1;
}
gboolean
meta_viewport_info_get_view (MetaViewportInfo *viewport_info,
int idx,
cairo_rectangle_int_t *rect,
float *scale)
{
ViewInfo *info;
if (idx < 0 || idx >= viewport_info->views->len)
return FALSE;
info = &g_array_index (viewport_info->views, ViewInfo, idx);
if (rect)
*rect = info->rect;
if (scale)
*scale = info->scale;
return TRUE;
}
static gboolean
view_has_neighbor (cairo_rectangle_int_t *view,
cairo_rectangle_int_t *neighbor,
MetaDisplayDirection neighbor_direction)
{
switch (neighbor_direction)
{
case META_DISPLAY_RIGHT:
if (neighbor->x == (view->x + view->width) &&
meta_rectangle_vert_overlap (neighbor, view))
return TRUE;
break;
case META_DISPLAY_LEFT:
if (view->x == (neighbor->x + neighbor->width) &&
meta_rectangle_vert_overlap (neighbor, view))
return TRUE;
break;
case META_DISPLAY_UP:
if (view->y == (neighbor->y + neighbor->height) &&
meta_rectangle_horiz_overlap (neighbor, view))
return TRUE;
break;
case META_DISPLAY_DOWN:
if (neighbor->y == (view->y + view->height) &&
meta_rectangle_horiz_overlap (neighbor, view))
return TRUE;
break;
}
return FALSE;
}
int
meta_viewport_info_get_neighbor (MetaViewportInfo *viewport_info,
int idx,
MetaDisplayDirection direction)
{
cairo_rectangle_int_t rect;
int i;
if (!meta_viewport_info_get_view (viewport_info, idx, &rect, NULL))
return -1;
for (i = 0; i < viewport_info->views->len; i++)
{
ViewInfo *info = &g_array_index (viewport_info->views, ViewInfo, i);
if (idx == i)
continue;
if (view_has_neighbor (&rect, &info->rect, direction))
return i;
}
return -1;
}
int
meta_viewport_info_get_num_views (MetaViewportInfo *info)
{
return info->views->len;
}
void
meta_viewport_info_get_extents (MetaViewportInfo *viewport_info,
float *width,
float *height)
{
int min_x = G_MAXINT, min_y = G_MAXINT, max_x = G_MININT, max_y = G_MININT, i;
for (i = 0; i < viewport_info->views->len; i++)
{
ViewInfo *info = &g_array_index (viewport_info->views, ViewInfo, i);
min_x = MIN (min_x, info->rect.x);
max_x = MAX (max_x, info->rect.x + info->rect.width);
min_y = MIN (min_y, info->rect.y);
max_y = MAX (max_y, info->rect.y + info->rect.height);
}
if (width)
*width = (float) max_x - min_x;
if (height)
*height = (float) max_y - min_y;
}

View File

@ -0,0 +1,57 @@
/*
* 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_VIEWPORT_INFO_H
#define META_VIEWPORT_INFO_H
#include <cairo.h>
#include <glib-object.h>
#include "meta/display.h"
#define META_TYPE_VIEWPORT_INFO (meta_viewport_info_get_type ())
G_DECLARE_FINAL_TYPE (MetaViewportInfo, meta_viewport_info,
META, VIEWPORT_INFO, GObject)
MetaViewportInfo * meta_viewport_info_new (cairo_rectangle_int_t *views,
float *scales,
guint n_views);
int meta_viewport_info_get_view_at (MetaViewportInfo *info,
float x,
float y);
gboolean meta_viewport_info_get_view (MetaViewportInfo *viewport_info,
int idx,
cairo_rectangle_int_t *rect,
float *scale);
int meta_viewport_info_get_neighbor (MetaViewportInfo *info,
int idx,
MetaDisplayDirection direction);
int meta_viewport_info_get_num_views (MetaViewportInfo *info);
void meta_viewport_info_get_extents (MetaViewportInfo *info,
float *width,
float *height);
#endif /* META_VIEWPORT_INFO_H */

View File

@ -22,5 +22,6 @@
#define META_BACKEND_NATIVE_TYPES_H
typedef struct _MetaBackendNative MetaBackendNative;
typedef struct _MetaSeatNative MetaSeatNative;
#endif /* META_BACKEND_NATIVE_TYPES_H */

View File

@ -48,10 +48,9 @@
#include "backends/meta-pointer-constraint.h"
#include "backends/meta-settings-private.h"
#include "backends/meta-stage-private.h"
#include "backends/native/meta-barrier-native.h"
#include "backends/native/meta-clutter-backend-native.h"
#include "backends/native/meta-cursor-renderer-native.h"
#include "backends/native/meta-event-native.h"
#include "backends/native/meta-input-device-native.h"
#include "backends/native/meta-input-settings-native.h"
#include "backends/native/meta-kms.h"
#include "backends/native/meta-kms-device.h"
@ -71,7 +70,7 @@ struct _MetaBackendNative
MetaLauncher *launcher;
MetaUdev *udev;
MetaKms *kms;
MetaBarrierManagerNative *barrier_manager;
MetaInputSettings *input_settings;
gulong udev_device_added_handler_id;
};
@ -99,239 +98,11 @@ meta_backend_native_finalize (GObject *object)
g_clear_object (&native->udev);
g_clear_object (&native->kms);
meta_launcher_free (native->launcher);
g_clear_object (&native->input_settings);
G_OBJECT_CLASS (meta_backend_native_parent_class)->finalize (object);
}
static void
constrain_to_barriers (ClutterInputDevice *device,
guint32 time,
float *new_x,
float *new_y)
{
MetaBackendNative *native = META_BACKEND_NATIVE (meta_get_backend ());
meta_barrier_manager_native_process (native->barrier_manager,
device,
time,
new_x, new_y);
}
static void
constrain_to_client_constraint (ClutterInputDevice *device,
guint32 time,
float prev_x,
float prev_y,
float *x,
float *y)
{
MetaBackend *backend = meta_get_backend ();
MetaPointerConstraint *constraint =
meta_backend_get_client_pointer_constraint (backend);
if (!constraint)
return;
meta_pointer_constraint_constrain (constraint, device,
time, prev_x, prev_y, x, y);
}
/*
* The pointer constrain code is mostly a rip-off of the XRandR code from Xorg.
* (from xserver/randr/rrcrtc.c, RRConstrainCursorHarder)
*
* Copyright © 2006 Keith Packard
* Copyright 2010 Red Hat, Inc
*
*/
static void
constrain_all_screen_monitors (ClutterInputDevice *device,
MetaMonitorManager *monitor_manager,
float *x,
float *y)
{
graphene_point_t current;
float cx, cy;
GList *logical_monitors, *l;
clutter_input_device_get_coords (device, NULL, &current);
cx = current.x;
cy = current.y;
/* if we're trying to escape, clamp to the CRTC we're coming from */
logical_monitors =
meta_monitor_manager_get_logical_monitors (monitor_manager);
for (l = logical_monitors; l; l = l->next)
{
MetaLogicalMonitor *logical_monitor = l->data;
int left, right, top, bottom;
left = logical_monitor->rect.x;
right = left + logical_monitor->rect.width;
top = logical_monitor->rect.y;
bottom = top + logical_monitor->rect.height;
if ((cx >= left) && (cx < right) && (cy >= top) && (cy < bottom))
{
if (*x < left)
*x = left;
if (*x >= right)
*x = right - 1;
if (*y < top)
*y = top;
if (*y >= bottom)
*y = bottom - 1;
return;
}
}
}
static void
pointer_constrain_callback (ClutterInputDevice *device,
guint32 time,
float prev_x,
float prev_y,
float *new_x,
float *new_y,
gpointer user_data)
{
MetaBackend *backend = meta_get_backend ();
MetaMonitorManager *monitor_manager =
meta_backend_get_monitor_manager (backend);
/* Constrain to barriers */
constrain_to_barriers (device, time, new_x, new_y);
/* Constrain to pointer lock */
constrain_to_client_constraint (device, time, prev_x, prev_y, new_x, new_y);
/* if we're moving inside a monitor, we're fine */
if (meta_monitor_manager_get_logical_monitor_at (monitor_manager,
*new_x, *new_y))
return;
/* if we're trying to escape, clamp to the CRTC we're coming from */
constrain_all_screen_monitors (device, monitor_manager, new_x, new_y);
}
static void
relative_motion_across_outputs (MetaMonitorManager *monitor_manager,
MetaLogicalMonitor *current,
float cur_x,
float cur_y,
float *dx_inout,
float *dy_inout)
{
MetaLogicalMonitor *cur = current;
float x = cur_x, y = cur_y;
float target_x = cur_x, target_y = cur_y;
float dx = *dx_inout, dy = *dy_inout;
MetaDisplayDirection direction = -1;
while (cur)
{
MetaLine2 left, right, top, bottom, motion;
MetaVector2 intersection;
motion = (MetaLine2) {
.a = { x, y },
.b = { x + (dx * cur->scale), y + (dy * cur->scale) }
};
left = (MetaLine2) {
{ cur->rect.x, cur->rect.y },
{ cur->rect.x, cur->rect.y + cur->rect.height }
};
right = (MetaLine2) {
{ cur->rect.x + cur->rect.width, cur->rect.y },
{ cur->rect.x + cur->rect.width, cur->rect.y + cur->rect.height }
};
top = (MetaLine2) {
{ cur->rect.x, cur->rect.y },
{ cur->rect.x + cur->rect.width, cur->rect.y }
};
bottom = (MetaLine2) {
{ cur->rect.x, cur->rect.y + cur->rect.height },
{ cur->rect.x + cur->rect.width, cur->rect.y + cur->rect.height }
};
target_x = motion.b.x;
target_y = motion.b.y;
if (direction != META_DISPLAY_RIGHT &&
meta_line2_intersects_with (&motion, &left, &intersection))
direction = META_DISPLAY_LEFT;
else if (direction != META_DISPLAY_LEFT &&
meta_line2_intersects_with (&motion, &right, &intersection))
direction = META_DISPLAY_RIGHT;
else if (direction != META_DISPLAY_DOWN &&
meta_line2_intersects_with (&motion, &top, &intersection))
direction = META_DISPLAY_UP;
else if (direction != META_DISPLAY_UP &&
meta_line2_intersects_with (&motion, &bottom, &intersection))
direction = META_DISPLAY_DOWN;
else
/* We reached the dest logical monitor */
break;
x = intersection.x;
y = intersection.y;
dx -= intersection.x - motion.a.x;
dy -= intersection.y - motion.a.y;
cur = meta_monitor_manager_get_logical_monitor_neighbor (monitor_manager,
cur, direction);
}
*dx_inout = target_x - cur_x;
*dy_inout = target_y - cur_y;
}
static void
relative_motion_filter (ClutterInputDevice *device,
float x,
float y,
float *dx,
float *dy,
gpointer user_data)
{
MetaMonitorManager *monitor_manager = user_data;
MetaLogicalMonitor *logical_monitor, *dest_logical_monitor;
float new_dx, new_dy;
if (meta_is_stage_views_scaled ())
return;
logical_monitor = meta_monitor_manager_get_logical_monitor_at (monitor_manager,
x, y);
if (!logical_monitor)
return;
new_dx = (*dx) * logical_monitor->scale;
new_dy = (*dy) * logical_monitor->scale;
dest_logical_monitor = meta_monitor_manager_get_logical_monitor_at (monitor_manager,
x + new_dx,
y + new_dy);
if (dest_logical_monitor &&
dest_logical_monitor != logical_monitor)
{
/* If we are crossing monitors, attempt to bisect the distance on each
* axis and apply the relative scale for each of them.
*/
new_dx = *dx;
new_dy = *dy;
relative_motion_across_outputs (monitor_manager, logical_monitor,
x, y, &new_dx, &new_dy);
}
*dx = new_dx;
*dy = new_dy;
}
static ClutterBackend *
meta_backend_native_create_clutter_backend (MetaBackend *backend)
{
@ -339,18 +110,47 @@ meta_backend_native_create_clutter_backend (MetaBackend *backend)
}
static void
meta_backend_native_post_init (MetaBackend *backend)
update_viewports (MetaBackend *backend)
{
MetaMonitorManager *monitor_manager =
meta_backend_get_monitor_manager (backend);
ClutterBackend *clutter_backend = meta_backend_get_clutter_backend (backend);
MetaSeatNative *seat =
META_SEAT_NATIVE (clutter_backend_get_default_seat (clutter_backend));
MetaViewportInfo *viewports;
viewports = meta_monitor_manager_get_viewports (monitor_manager);
meta_seat_native_set_viewports (seat, viewports);
g_object_unref (viewports);
}
static void
kbd_a11y_changed_cb (MetaInputSettings *input_settings,
MetaKbdA11ySettings *a11y_settings,
MetaBackend *backend)
{
ClutterBackend *clutter_backend = meta_backend_get_clutter_backend (backend);
ClutterSeat *seat = clutter_backend_get_default_seat (clutter_backend);
MetaSettings *settings = meta_backend_get_settings (backend);
ClutterInputDevice *device;
meta_seat_native_set_pointer_constrain_callback (META_SEAT_NATIVE (seat),
pointer_constrain_callback,
NULL, NULL);
meta_seat_native_set_relative_motion_filter (META_SEAT_NATIVE (seat),
relative_motion_filter,
meta_backend_get_monitor_manager (backend));
device = clutter_seat_get_keyboard (seat);
if (device)
meta_input_device_native_apply_kbd_a11y_settings (META_INPUT_DEVICE_NATIVE (device),
a11y_settings);
}
static void
meta_backend_native_post_init (MetaBackend *backend)
{
MetaBackendNative *native = META_BACKEND_NATIVE (backend);
MetaSettings *settings = meta_backend_get_settings (backend);
ClutterBackend *clutter_backend = meta_backend_get_clutter_backend (backend);
MetaSeatNative *seat =
META_SEAT_NATIVE (clutter_backend_get_default_seat (clutter_backend));
native->input_settings = meta_seat_impl_get_input_settings (seat->impl);
g_signal_connect_object (native->input_settings, "kbd-a11y-changed",
G_CALLBACK (kbd_a11y_changed_cb), backend, 0);
META_BACKEND_CLASS (meta_backend_native_parent_class)->post_init (backend);
@ -368,6 +168,8 @@ meta_backend_native_post_init (MetaBackend *backend)
g_warning ("Failed to set RT scheduler: %m");
}
update_viewports (backend);
#ifdef HAVE_WAYLAND
meta_backend_init_wayland (backend);
#endif
@ -377,15 +179,26 @@ static MetaMonitorManager *
meta_backend_native_create_monitor_manager (MetaBackend *backend,
GError **error)
{
return g_initable_new (META_TYPE_MONITOR_MANAGER_KMS, NULL, error,
MetaMonitorManager *manager;
manager = g_initable_new (META_TYPE_MONITOR_MANAGER_KMS, NULL, error,
"backend", backend,
NULL);
g_signal_connect_swapped (manager, "monitors-changed-internal",
G_CALLBACK (update_viewports), backend);
return manager;
}
static MetaCursorRenderer *
meta_backend_native_create_cursor_renderer (MetaBackend *backend)
meta_backend_native_get_cursor_renderer (MetaBackend *backend,
ClutterInputDevice *device)
{
return META_CURSOR_RENDERER (meta_cursor_renderer_native_new (backend));
ClutterBackend *clutter_backend = meta_backend_get_clutter_backend (backend);
MetaSeatNative *seat =
META_SEAT_NATIVE (clutter_backend_get_default_seat (clutter_backend));
return meta_seat_native_get_cursor_renderer (seat, device);
}
static MetaRenderer *
@ -405,7 +218,9 @@ meta_backend_native_create_renderer (MetaBackend *backend,
static MetaInputSettings *
meta_backend_native_create_input_settings (MetaBackend *backend)
{
return g_object_new (META_TYPE_INPUT_SETTINGS_NATIVE, NULL);
MetaBackendNative *native = META_BACKEND_NATIVE (backend);
return native->input_settings;
}
static MetaLogicalMonitor *
@ -414,10 +229,11 @@ meta_backend_native_get_current_logical_monitor (MetaBackend *backend)
MetaCursorTracker *cursor_tracker = meta_backend_get_cursor_tracker (backend);
MetaMonitorManager *monitor_manager =
meta_backend_get_monitor_manager (backend);
int x, y;
graphene_point_t point;
meta_cursor_tracker_get_pointer (cursor_tracker, &x, &y, NULL);
return meta_monitor_manager_get_logical_monitor_at (monitor_manager, x, y);
meta_cursor_tracker_get_pointer (cursor_tracker, &point, NULL);
return meta_monitor_manager_get_logical_monitor_at (monitor_manager,
point.x, point.y);
}
static void
@ -427,27 +243,13 @@ meta_backend_native_set_keymap (MetaBackend *backend,
const char *options)
{
ClutterBackend *clutter_backend = meta_backend_get_clutter_backend (backend);
struct xkb_rule_names names;
struct xkb_keymap *keymap;
struct xkb_context *context;
ClutterSeat *seat;
names.rules = DEFAULT_XKB_RULES_FILE;
names.model = DEFAULT_XKB_MODEL;
names.layout = layouts;
names.variant = variants;
names.options = options;
context = meta_create_xkb_context ();
keymap = xkb_keymap_new_from_names (context, &names, XKB_KEYMAP_COMPILE_NO_FLAGS);
xkb_context_unref (context);
seat = clutter_backend_get_default_seat (clutter_backend);
meta_seat_native_set_keyboard_map (META_SEAT_NATIVE (seat), keymap);
meta_seat_native_set_keyboard_map (META_SEAT_NATIVE (seat),
layouts, variants, options);
meta_backend_notify_keymap_changed (backend);
xkb_keymap_unref (keymap);
}
static struct xkb_keymap *
@ -499,6 +301,25 @@ meta_backend_native_set_numlock (MetaBackend *backend,
numlock_state);
}
static void
meta_backend_native_set_pointer_constraint (MetaBackend *backend,
MetaPointerConstraint *constraint)
{
ClutterBackend *clutter_backend = meta_backend_get_clutter_backend (backend);
ClutterSeat *seat = clutter_backend_get_default_seat (clutter_backend);
MetaPointerConstraintImpl *constraint_impl = NULL;
cairo_region_t *region;
if (constraint)
{
region = meta_pointer_constraint_get_region (constraint);
constraint_impl = meta_pointer_constraint_impl_native_new (constraint, region);
}
meta_seat_native_set_pointer_constraint (META_SEAT_NATIVE (seat),
constraint_impl);
}
static void
meta_backend_native_update_screen_size (MetaBackend *backend,
int width, int height)
@ -662,7 +483,6 @@ meta_backend_native_initable_init (GInitable *initable,
#endif
native->udev = meta_udev_new (native);
native->barrier_manager = meta_barrier_manager_native_new ();
native->kms = meta_kms_new (META_BACKEND (native), error);
if (!native->kms)
@ -695,7 +515,7 @@ meta_backend_native_class_init (MetaBackendNativeClass *klass)
backend_class->post_init = meta_backend_native_post_init;
backend_class->create_monitor_manager = meta_backend_native_create_monitor_manager;
backend_class->create_cursor_renderer = meta_backend_native_create_cursor_renderer;
backend_class->get_cursor_renderer = meta_backend_native_get_cursor_renderer;
backend_class->create_renderer = meta_backend_native_create_renderer;
backend_class->create_input_settings = meta_backend_native_create_input_settings;
@ -707,6 +527,8 @@ meta_backend_native_class_init (MetaBackendNativeClass *klass)
backend_class->lock_layout_group = meta_backend_native_lock_layout_group;
backend_class->update_screen_size = meta_backend_native_update_screen_size;
backend_class->set_numlock = meta_backend_native_set_numlock;
backend_class->set_pointer_constraint = meta_backend_native_set_pointer_constraint;
}
static void
@ -742,12 +564,6 @@ meta_activate_vt (int vt, GError **error)
return meta_launcher_activate_vt (launcher, vt, error);
}
MetaBarrierManagerNative *
meta_backend_native_get_barrier_manager (MetaBackendNative *native)
{
return native->barrier_manager;
}
/**
* meta_activate_session:
*
@ -809,7 +625,6 @@ void meta_backend_native_resume (MetaBackendNative *native)
meta_backend_get_monitor_manager (backend);
MetaMonitorManagerKms *monitor_manager_kms =
META_MONITOR_MANAGER_KMS (monitor_manager);
MetaInputSettings *input_settings;
MetaIdleMonitor *idle_monitor;
ClutterBackend *clutter_backend = meta_backend_get_clutter_backend (backend);
MetaSeatNative *seat =
@ -831,8 +646,7 @@ void meta_backend_native_resume (MetaBackendNative *native)
idle_monitor = meta_idle_monitor_get_core ();
meta_idle_monitor_reset_idletime (idle_monitor);
input_settings = meta_backend_get_input_settings (backend);
meta_input_settings_maybe_restore_numlock_state (input_settings);
meta_input_settings_maybe_restore_numlock_state (native->input_settings);
clutter_seat_ensure_a11y_state (CLUTTER_SEAT (seat));
}

View File

@ -36,14 +36,14 @@
#include "backends/meta-backend-private.h"
#include "backends/meta-barrier-private.h"
#include "backends/native/meta-backend-native.h"
#include "backends/native/meta-backend-native-private.h"
#include "backends/native/meta-seat-native.h"
#include "meta/barrier.h"
#include "meta/util.h"
struct _MetaBarrierManagerNative
{
GHashTable *barriers;
GMutex mutex;
};
typedef enum
@ -78,6 +78,7 @@ struct _MetaBarrierImplNative
int trigger_serial;
guint32 last_event_time;
MetaBarrierDirection blocked_dir;
GMainContext *context;
};
G_DEFINE_TYPE (MetaBarrierImplNative,
@ -341,6 +342,48 @@ typedef struct _MetaBarrierEventData
float dy;
} MetaBarrierEventData;
typedef struct
{
MetaBarrierEvent *event;
MetaBarrier *barrier;
MetaBarrierState state;
} MetaBarrierIdleData;
static gboolean
emit_event_idle (MetaBarrierIdleData *idle_data)
{
if (idle_data->state == META_BARRIER_STATE_HELD)
_meta_barrier_emit_hit_signal (idle_data->barrier, idle_data->event);
else
_meta_barrier_emit_left_signal (idle_data->barrier, idle_data->event);
meta_barrier_event_unref (idle_data->event);
return G_SOURCE_REMOVE;
}
static void
emit_event (MetaBarrierImplNative *self,
MetaBarrierEvent *event)
{
MetaBarrierIdleData *idle_data;
GSource *source;
idle_data = g_new0 (MetaBarrierIdleData, 1);
idle_data->state = self->state;
idle_data->barrier = self->barrier;
idle_data->event = event;
source = g_idle_source_new ();
g_source_set_priority (source, G_PRIORITY_HIGH);
g_source_set_callback (source,
(GSourceFunc) emit_event_idle,
idle_data,
g_free);
g_source_attach (source, self->context);
}
static void
emit_barrier_event (MetaBarrierImplNative *self,
guint32 time,
@ -351,7 +394,6 @@ emit_barrier_event (MetaBarrierImplNative *self,
float dx,
float dy)
{
MetaBarrier *barrier = self->barrier;
MetaBarrierEvent *event = g_slice_new0 (MetaBarrierEvent);
MetaBarrierState old_state = self->state;
@ -390,12 +432,7 @@ emit_barrier_event (MetaBarrierImplNative *self,
self->last_event_time = time;
if (self->state == META_BARRIER_STATE_HELD)
_meta_barrier_emit_hit_signal (barrier, event);
else
_meta_barrier_emit_left_signal (barrier, event);
meta_barrier_event_unref (event);
emit_event (self, event);
}
static void
@ -480,6 +517,8 @@ meta_barrier_manager_native_process (MetaBarrierManagerNative *manager,
if (!clutter_input_device_get_coords (device, NULL, &prev_pos))
return;
g_mutex_lock (&manager->mutex);
prev_x = prev_pos.x;
prev_y = prev_pos.y;
@ -524,6 +563,8 @@ meta_barrier_manager_native_process (MetaBarrierManagerNative *manager,
g_hash_table_foreach (manager->barriers,
maybe_emit_barrier_event,
&barrier_event_data);
g_mutex_unlock (&manager->mutex);
}
static gboolean
@ -550,7 +591,10 @@ _meta_barrier_impl_native_destroy (MetaBarrierImpl *impl)
{
MetaBarrierImplNative *self = META_BARRIER_IMPL_NATIVE (impl);
g_mutex_lock (&self->manager->mutex);
g_hash_table_remove (self->manager->barriers, self);
g_mutex_unlock (&self->manager->mutex);
g_main_context_unref (self->context);
self->is_active = FALSE;
}
@ -558,18 +602,21 @@ MetaBarrierImpl *
meta_barrier_impl_native_new (MetaBarrier *barrier)
{
MetaBarrierImplNative *self;
MetaBackendNative *native;
MetaBarrierManagerNative *manager;
ClutterBackend *backend = clutter_get_default_backend ();
ClutterSeat *seat = clutter_backend_get_default_seat (backend);
self = g_object_new (META_TYPE_BARRIER_IMPL_NATIVE, NULL);
self->barrier = barrier;
self->is_active = TRUE;
self->context = g_main_context_ref_thread_default ();
native = META_BACKEND_NATIVE (meta_get_backend ());
manager = meta_backend_native_get_barrier_manager (native);
manager = meta_seat_native_get_barrier_manager (META_SEAT_NATIVE (seat));
self->manager = manager;
g_mutex_lock (&manager->mutex);
g_hash_table_add (manager->barriers, self);
g_mutex_unlock (&manager->mutex);
return META_BARRIER_IMPL (self);
}
@ -597,6 +644,7 @@ meta_barrier_manager_native_new (void)
manager = g_new0 (MetaBarrierManagerNative, 1);
manager->barriers = g_hash_table_new (NULL, NULL);
g_mutex_init (&manager->mutex);
return manager;
}

File diff suppressed because it is too large Load Diff

View File

@ -26,6 +26,7 @@
#define META_CURSOR_RENDERER_NATIVE_H
#include "backends/meta-cursor-renderer.h"
#include "backends/native/meta-kms-cursor-renderer.h"
#include "meta/meta-backend.h"
#define META_TYPE_CURSOR_RENDERER_NATIVE (meta_cursor_renderer_native_get_type ())
@ -33,6 +34,10 @@ G_DECLARE_FINAL_TYPE (MetaCursorRendererNative, meta_cursor_renderer_native,
META, CURSOR_RENDERER_NATIVE,
MetaCursorRenderer)
MetaCursorRendererNative * meta_cursor_renderer_native_new (MetaBackend *backend);
MetaCursorRendererNative * meta_cursor_renderer_native_new (MetaBackend *backend,
ClutterInputDevice *device);
void meta_cursor_renderer_native_set_kms_cursor_renderer (MetaCursorRendererNative *native,
MetaKmsCursorRenderer *kms_cursor_renderer);
#endif /* META_CURSOR_RENDERER_NATIVE_H */

View File

@ -24,9 +24,10 @@
#include <math.h>
#include <cairo-gobject.h>
#include "backends/meta-backend-private.h"
#include "backends/native/meta-input-device-tool-native.h"
#include "backends/native/meta-input-device-native.h"
#include "backends/native/meta-seat-native.h"
#include "backends/native/meta-seat-impl.h"
#include "clutter/clutter-mutter.h"
G_DEFINE_TYPE (MetaInputDeviceNative,
@ -61,19 +62,11 @@ meta_input_device_native_finalize (GObject *object)
{
ClutterInputDevice *device = CLUTTER_INPUT_DEVICE (object);
MetaInputDeviceNative *device_evdev = META_INPUT_DEVICE_NATIVE (object);
ClutterBackend *backend;
ClutterSeat *seat;
if (device_evdev->libinput_device)
libinput_device_unref (device_evdev->libinput_device);
meta_input_device_native_release_touch_slots (device_evdev,
g_get_monotonic_time ());
g_clear_pointer (&device_evdev->touches, g_hash_table_unref);
backend = clutter_get_default_backend ();
seat = clutter_backend_get_default_seat (backend);
meta_seat_native_release_device_id (META_SEAT_NATIVE (seat), device);
meta_seat_impl_release_device_id (device_evdev->seat_impl, device);
clear_slow_keys (device_evdev);
stop_bounce_keys (device_evdev);
@ -225,7 +218,7 @@ meta_input_device_native_is_grouped (ClutterInputDevice *device,
static void
meta_input_device_native_bell_notify (MetaInputDeviceNative *device)
{
clutter_seat_bell_notify (CLUTTER_SEAT (device->seat));
meta_seat_impl_notify_bell (device->seat_impl);
}
static void
@ -250,10 +243,11 @@ static guint
get_slow_keys_delay (ClutterInputDevice *device)
{
MetaInputDeviceNative *device_native = META_INPUT_DEVICE_NATIVE (device);
ClutterKbdA11ySettings a11y_settings;
MetaKbdA11ySettings a11y_settings;
MetaInputSettings *input_settings;
clutter_seat_get_kbd_a11y_settings (CLUTTER_SEAT (device_native->seat),
&a11y_settings);
input_settings = meta_seat_impl_get_input_settings (device_native->seat_impl);
meta_input_settings_get_kbd_a11y_settings (input_settings, &a11y_settings);
/* Settings use int, we use uint, make sure we dont go negative */
return MAX (0, a11y_settings.slowkeys_delay);
}
@ -274,7 +268,7 @@ trigger_slow_keys (gpointer data)
device->slow_keys_list = g_list_remove (device->slow_keys_list, slow_keys_event);
meta_input_device_native_free_pending_slow_key (slow_keys_event);
if (device->a11y_flags & CLUTTER_A11Y_SLOW_KEYS_BEEP_ACCEPT)
if (device->a11y_flags & META_A11Y_SLOW_KEYS_BEEP_ACCEPT)
meta_input_device_native_bell_notify (device);
return G_SOURCE_REMOVE;
@ -312,7 +306,7 @@ start_slow_keys (ClutterEvent *event,
slow_keys_event);
device->slow_keys_list = g_list_append (device->slow_keys_list, slow_keys_event);
if (device->a11y_flags & CLUTTER_A11Y_SLOW_KEYS_BEEP_PRESS)
if (device->a11y_flags & META_A11Y_SLOW_KEYS_BEEP_PRESS)
meta_input_device_native_bell_notify (device);
}
@ -332,7 +326,7 @@ stop_slow_keys (ClutterEvent *event,
device->slow_keys_list = g_list_delete_link (device->slow_keys_list, item);
meta_input_device_native_free_pending_slow_key (slow_keys_event);
if (device->a11y_flags & CLUTTER_A11Y_SLOW_KEYS_BEEP_REJECT)
if (device->a11y_flags & META_A11Y_SLOW_KEYS_BEEP_REJECT)
meta_input_device_native_bell_notify (device);
return;
@ -346,10 +340,11 @@ static guint
get_debounce_delay (ClutterInputDevice *device)
{
MetaInputDeviceNative *device_native = META_INPUT_DEVICE_NATIVE (device);
ClutterKbdA11ySettings a11y_settings;
MetaKbdA11ySettings a11y_settings;
MetaInputSettings *input_settings;
clutter_seat_get_kbd_a11y_settings (CLUTTER_SEAT (device_native->seat),
&a11y_settings);
input_settings = meta_seat_impl_get_input_settings (device_native->seat_impl);
meta_input_settings_get_kbd_a11y_settings (input_settings, &a11y_settings);
/* Settings use int, we use uint, make sure we dont go negative */
return MAX (0, a11y_settings.debounce_delay);
}
@ -387,7 +382,7 @@ stop_bounce_keys (MetaInputDeviceNative *device)
static void
notify_bounce_keys_reject (MetaInputDeviceNative *device)
{
if (device->a11y_flags & CLUTTER_A11Y_BOUNCE_KEYS_BEEP_REJECT)
if (device->a11y_flags & META_A11Y_BOUNCE_KEYS_BEEP_REJECT)
meta_input_device_native_bell_notify (device);
}
@ -426,8 +421,7 @@ key_event_is_modifier (ClutterEvent *event)
static void
notify_stickykeys_mask (MetaInputDeviceNative *device)
{
g_signal_emit_by_name (device->seat,
"kbd-a11y-mods-state-changed",
meta_seat_impl_notify_kbd_a11y_mods_state_changed (device->seat_impl,
device->stickykeys_latched_mask,
device->stickykeys_locked_mask);
}
@ -437,15 +431,19 @@ update_internal_xkb_state (MetaInputDeviceNative *device,
xkb_mod_mask_t new_latched_mask,
xkb_mod_mask_t new_locked_mask)
{
MetaSeatNative *seat = device->seat;
MetaSeatImpl *seat_impl = device->seat_impl;
xkb_mod_mask_t depressed_mods;
xkb_mod_mask_t latched_mods;
xkb_mod_mask_t locked_mods;
xkb_mod_mask_t group_mods;
struct xkb_state *xkb_state;
depressed_mods = xkb_state_serialize_mods (seat->xkb, XKB_STATE_MODS_DEPRESSED);
latched_mods = xkb_state_serialize_mods (seat->xkb, XKB_STATE_MODS_LATCHED);
locked_mods = xkb_state_serialize_mods (seat->xkb, XKB_STATE_MODS_LOCKED);
g_rw_lock_writer_lock (&seat_impl->state_lock);
xkb_state = meta_seat_impl_get_xkb_state (seat_impl);
depressed_mods = xkb_state_serialize_mods (xkb_state, XKB_STATE_MODS_DEPRESSED);
latched_mods = xkb_state_serialize_mods (xkb_state, XKB_STATE_MODS_LATCHED);
locked_mods = xkb_state_serialize_mods (xkb_state, XKB_STATE_MODS_LOCKED);
latched_mods &= ~device->stickykeys_latched_mask;
locked_mods &= ~device->stickykeys_locked_mask;
@ -456,14 +454,16 @@ update_internal_xkb_state (MetaInputDeviceNative *device,
latched_mods |= device->stickykeys_latched_mask;
locked_mods |= device->stickykeys_locked_mask;
group_mods = xkb_state_serialize_layout (seat->xkb, XKB_STATE_LAYOUT_EFFECTIVE);
group_mods = xkb_state_serialize_layout (xkb_state, XKB_STATE_LAYOUT_EFFECTIVE);
xkb_state_update_mask (seat->xkb,
xkb_state_update_mask (xkb_state,
depressed_mods,
latched_mods,
locked_mods,
0, 0, group_mods);
notify_stickykeys_mask (device);
g_rw_lock_writer_unlock (&seat_impl->state_lock);
}
static void
@ -472,23 +472,25 @@ update_stickykeys_event (ClutterEvent *event,
xkb_mod_mask_t new_latched_mask,
xkb_mod_mask_t new_locked_mask)
{
MetaSeatNative *seat = device->seat;
MetaSeatImpl *seat_impl = device->seat_impl;
xkb_mod_mask_t effective_mods;
xkb_mod_mask_t latched_mods;
xkb_mod_mask_t locked_mods;
struct xkb_state *xkb_state;
update_internal_xkb_state (device, new_latched_mask, new_locked_mask);
effective_mods = xkb_state_serialize_mods (seat->xkb, XKB_STATE_MODS_EFFECTIVE);
latched_mods = xkb_state_serialize_mods (seat->xkb, XKB_STATE_MODS_LATCHED);
locked_mods = xkb_state_serialize_mods (seat->xkb, XKB_STATE_MODS_LOCKED);
xkb_state = meta_seat_impl_get_xkb_state (seat_impl);
effective_mods = xkb_state_serialize_mods (xkb_state, XKB_STATE_MODS_EFFECTIVE);
latched_mods = xkb_state_serialize_mods (xkb_state, XKB_STATE_MODS_LATCHED);
locked_mods = xkb_state_serialize_mods (xkb_state, XKB_STATE_MODS_LOCKED);
_clutter_event_set_state_full (event,
seat->button_state,
seat_impl->button_state,
device->stickykeys_depressed_mask,
latched_mods,
locked_mods,
effective_mods | seat->button_state);
effective_mods | seat_impl->button_state);
}
static void
@ -498,23 +500,22 @@ notify_stickykeys_change (MetaInputDeviceNative *device)
device->stickykeys_depressed_mask = 0;
update_internal_xkb_state (device, 0, 0);
g_signal_emit_by_name (CLUTTER_INPUT_DEVICE (device)->seat,
"kbd-a11y-flags-changed",
meta_seat_impl_notify_kbd_a11y_flags_changed (device->seat_impl,
device->a11y_flags,
CLUTTER_A11Y_STICKY_KEYS_ENABLED);
META_A11Y_STICKY_KEYS_ENABLED);
}
static void
set_stickykeys_off (MetaInputDeviceNative *device)
{
device->a11y_flags &= ~CLUTTER_A11Y_STICKY_KEYS_ENABLED;
device->a11y_flags &= ~META_A11Y_STICKY_KEYS_ENABLED;
notify_stickykeys_change (device);
}
static void
set_stickykeys_on (MetaInputDeviceNative *device)
{
device->a11y_flags |= CLUTTER_A11Y_STICKY_KEYS_ENABLED;
device->a11y_flags |= META_A11Y_STICKY_KEYS_ENABLED;
notify_stickykeys_change (device);
}
@ -529,45 +530,45 @@ clear_stickykeys_event (ClutterEvent *event,
static void
set_slowkeys_off (MetaInputDeviceNative *device)
{
device->a11y_flags &= ~CLUTTER_A11Y_SLOW_KEYS_ENABLED;
device->a11y_flags &= ~META_A11Y_SLOW_KEYS_ENABLED;
g_signal_emit_by_name (CLUTTER_INPUT_DEVICE (device)->seat,
"kbd-a11y-flags-changed",
meta_seat_impl_notify_kbd_a11y_flags_changed (device->seat_impl,
device->a11y_flags,
CLUTTER_A11Y_SLOW_KEYS_ENABLED);
META_A11Y_SLOW_KEYS_ENABLED);
}
static void
set_slowkeys_on (MetaInputDeviceNative *device)
{
device->a11y_flags |= CLUTTER_A11Y_SLOW_KEYS_ENABLED;
device->a11y_flags |= META_A11Y_SLOW_KEYS_ENABLED;
g_signal_emit_by_name (CLUTTER_INPUT_DEVICE (device)->seat,
"kbd-a11y-flags-changed",
meta_seat_impl_notify_kbd_a11y_flags_changed (device->seat_impl,
device->a11y_flags,
CLUTTER_A11Y_SLOW_KEYS_ENABLED);
META_A11Y_SLOW_KEYS_ENABLED);
}
static void
handle_stickykeys_press (ClutterEvent *event,
MetaInputDeviceNative *device)
{
MetaSeatNative *seat = device->seat;
MetaSeatImpl *seat_impl = device->seat_impl;
xkb_mod_mask_t depressed_mods;
xkb_mod_mask_t new_latched_mask;
xkb_mod_mask_t new_locked_mask;
struct xkb_state *xkb_state;
if (!key_event_is_modifier (event))
return;
if (device->stickykeys_depressed_mask &&
(device->a11y_flags & CLUTTER_A11Y_STICKY_KEYS_TWO_KEY_OFF))
(device->a11y_flags & META_A11Y_STICKY_KEYS_TWO_KEY_OFF))
{
clear_stickykeys_event (event, device);
return;
}
depressed_mods = xkb_state_serialize_mods (seat->xkb, XKB_STATE_MODS_DEPRESSED);
xkb_state = meta_seat_impl_get_xkb_state (seat_impl);
depressed_mods = xkb_state_serialize_mods (xkb_state, XKB_STATE_MODS_DEPRESSED);
/* Ignore the lock modifier mask, that one cannot be sticky, yet the
* CAPS_LOCK key itself counts as a modifier as it might be remapped
* to some other modifier which can be sticky.
@ -600,14 +601,16 @@ static void
handle_stickykeys_release (ClutterEvent *event,
MetaInputDeviceNative *device)
{
MetaSeatNative *seat = device->seat;
MetaSeatImpl *seat_impl = device->seat_impl;
struct xkb_state *xkb_state;
xkb_state = meta_seat_impl_get_xkb_state (seat_impl);
device->stickykeys_depressed_mask =
xkb_state_serialize_mods (seat->xkb, XKB_STATE_MODS_DEPRESSED);
xkb_state_serialize_mods (xkb_state, XKB_STATE_MODS_DEPRESSED);
if (key_event_is_modifier (event))
{
if (device->a11y_flags & CLUTTER_A11Y_STICKY_KEYS_BEEP)
if (device->a11y_flags & META_A11Y_STICKY_KEYS_BEEP)
meta_input_device_native_bell_notify (device);
return;
@ -626,10 +629,10 @@ trigger_toggle_slowkeys (gpointer data)
device->toggle_slowkeys_timer = 0;
if (device->a11y_flags & CLUTTER_A11Y_FEATURE_STATE_CHANGE_BEEP)
if (device->a11y_flags & META_A11Y_FEATURE_STATE_CHANGE_BEEP)
meta_input_device_native_bell_notify (device);
if (device->a11y_flags & CLUTTER_A11Y_SLOW_KEYS_ENABLED)
if (device->a11y_flags & META_A11Y_SLOW_KEYS_ENABLED)
set_slowkeys_off (device);
else
set_slowkeys_on (device);
@ -688,10 +691,10 @@ handle_enablekeys_release (ClutterEvent *event,
{
device->shift_count = 0;
if (device->a11y_flags & CLUTTER_A11Y_FEATURE_STATE_CHANGE_BEEP)
if (device->a11y_flags & META_A11Y_FEATURE_STATE_CHANGE_BEEP)
meta_input_device_native_bell_notify (device);
if (device->a11y_flags & CLUTTER_A11Y_STICKY_KEYS_ENABLED)
if (device->a11y_flags & META_A11Y_STICKY_KEYS_ENABLED)
set_stickykeys_off (device);
else
set_stickykeys_on (device);
@ -759,7 +762,7 @@ emulate_button_click (MetaInputDeviceNative *device)
static void
update_mousekeys_params (MetaInputDeviceNative *device,
ClutterKbdA11ySettings *settings)
MetaKbdA11ySettings *settings)
{
/* Prevent us from broken settings values */
device->mousekeys_max_speed = MAX (1, settings->mousekeys_max_speed);
@ -841,8 +844,12 @@ emulate_pointer_motion (MetaInputDeviceNative *device_evdev,
static gboolean
is_numlock_active (MetaInputDeviceNative *device)
{
MetaSeatNative *seat = device->seat;
return xkb_state_mod_name_is_active (seat->xkb,
MetaSeatImpl *seat_impl = device->seat_impl;
struct xkb_state *xkb_state;
xkb_state = meta_seat_impl_get_xkb_state (seat_impl);
return xkb_state_mod_name_is_active (xkb_state,
"Mod2",
XKB_STATE_MODS_LOCKED);
}
@ -862,7 +869,7 @@ enable_mousekeys (MetaInputDeviceNative *device_evdev)
return;
device->accessibility_virtual_device =
clutter_seat_create_virtual_device (CLUTTER_SEAT (device_evdev->seat),
clutter_seat_create_virtual_device (clutter_input_device_get_seat (device),
CLUTTER_POINTER_DEVICE);
}
@ -1128,7 +1135,7 @@ meta_input_device_native_process_kbd_a11y_event (ClutterEvent *eve
if (event->key.flags & CLUTTER_EVENT_FLAG_INPUT_METHOD)
goto emit_event;
if (device_evdev->a11y_flags & CLUTTER_A11Y_KEYBOARD_ENABLED)
if (device_evdev->a11y_flags & META_A11Y_KEYBOARD_ENABLED)
{
if (event->type == CLUTTER_KEY_PRESS)
handle_enablekeys_press (event, device_evdev);
@ -1136,7 +1143,7 @@ meta_input_device_native_process_kbd_a11y_event (ClutterEvent *eve
handle_enablekeys_release (event, device_evdev);
}
if (device_evdev->a11y_flags & CLUTTER_A11Y_MOUSE_KEYS_ENABLED)
if (device_evdev->a11y_flags & META_A11Y_MOUSE_KEYS_ENABLED)
{
if (event->type == CLUTTER_KEY_PRESS &&
handle_mousekeys_press (event, device_evdev))
@ -1146,7 +1153,7 @@ meta_input_device_native_process_kbd_a11y_event (ClutterEvent *eve
return; /* swallow event */
}
if ((device_evdev->a11y_flags & CLUTTER_A11Y_BOUNCE_KEYS_ENABLED) &&
if ((device_evdev->a11y_flags & META_A11Y_BOUNCE_KEYS_ENABLED) &&
(get_debounce_delay (device) != 0))
{
if ((event->type == CLUTTER_KEY_PRESS) && debounce_key (event, device_evdev))
@ -1159,7 +1166,7 @@ meta_input_device_native_process_kbd_a11y_event (ClutterEvent *eve
start_bounce_keys (event, device_evdev);
}
if ((device_evdev->a11y_flags & CLUTTER_A11Y_SLOW_KEYS_ENABLED) &&
if ((device_evdev->a11y_flags & META_A11Y_SLOW_KEYS_ENABLED) &&
(get_slow_keys_delay (device) != 0))
{
if (event->type == CLUTTER_KEY_PRESS)
@ -1170,7 +1177,7 @@ meta_input_device_native_process_kbd_a11y_event (ClutterEvent *eve
return;
}
if (device_evdev->a11y_flags & CLUTTER_A11Y_STICKY_KEYS_ENABLED)
if (device_evdev->a11y_flags & META_A11Y_STICKY_KEYS_ENABLED)
{
if (event->type == CLUTTER_KEY_PRESS)
handle_stickykeys_press (event, device_evdev);
@ -1184,33 +1191,33 @@ emit_event:
void
meta_input_device_native_apply_kbd_a11y_settings (MetaInputDeviceNative *device,
ClutterKbdA11ySettings *settings)
MetaKbdA11ySettings *settings)
{
ClutterKeyboardA11yFlags changed_flags = (device->a11y_flags ^ settings->controls);
MetaKeyboardA11yFlags changed_flags = (device->a11y_flags ^ settings->controls);
if (changed_flags & (CLUTTER_A11Y_KEYBOARD_ENABLED | CLUTTER_A11Y_SLOW_KEYS_ENABLED))
if (changed_flags & (META_A11Y_KEYBOARD_ENABLED | META_A11Y_SLOW_KEYS_ENABLED))
clear_slow_keys (device);
if (changed_flags & (CLUTTER_A11Y_KEYBOARD_ENABLED | CLUTTER_A11Y_BOUNCE_KEYS_ENABLED))
if (changed_flags & (META_A11Y_KEYBOARD_ENABLED | META_A11Y_BOUNCE_KEYS_ENABLED))
device->debounce_key = 0;
if (changed_flags & (CLUTTER_A11Y_KEYBOARD_ENABLED | CLUTTER_A11Y_STICKY_KEYS_ENABLED))
if (changed_flags & (META_A11Y_KEYBOARD_ENABLED | META_A11Y_STICKY_KEYS_ENABLED))
{
device->stickykeys_depressed_mask = 0;
update_internal_xkb_state (device, 0, 0);
}
if (changed_flags & CLUTTER_A11Y_KEYBOARD_ENABLED)
if (changed_flags & META_A11Y_KEYBOARD_ENABLED)
{
device->toggle_slowkeys_timer = 0;
device->shift_count = 0;
device->last_shift_time = 0;
}
if (changed_flags & (CLUTTER_A11Y_KEYBOARD_ENABLED | CLUTTER_A11Y_MOUSE_KEYS_ENABLED))
if (changed_flags & (META_A11Y_KEYBOARD_ENABLED | META_A11Y_MOUSE_KEYS_ENABLED))
{
if (settings->controls &
(CLUTTER_A11Y_KEYBOARD_ENABLED | CLUTTER_A11Y_MOUSE_KEYS_ENABLED))
(META_A11Y_KEYBOARD_ENABLED | META_A11Y_MOUSE_KEYS_ENABLED))
enable_mousekeys (device);
else
disable_mousekeys (device);
@ -1224,48 +1231,10 @@ meta_input_device_native_apply_kbd_a11y_settings (MetaInputDeviceNative *device
void
meta_input_device_native_a11y_maybe_notify_toggle_keys (MetaInputDeviceNative *device)
{
if (device->a11y_flags & CLUTTER_A11Y_TOGGLE_KEYS_ENABLED)
if (device->a11y_flags & META_A11Y_TOGGLE_KEYS_ENABLED)
meta_input_device_native_bell_notify (device);
}
static void
release_device_touch_slot (gpointer value)
{
MetaTouchState *touch_state = value;
meta_seat_native_release_touch_state (touch_state->seat, touch_state);
}
MetaTouchState *
meta_input_device_native_acquire_touch_state (MetaInputDeviceNative *device,
int device_slot)
{
MetaTouchState *touch_state;
touch_state = meta_seat_native_acquire_touch_state (device->seat,
device_slot);
g_hash_table_insert (device->touches,
GINT_TO_POINTER (device_slot),
touch_state);
return touch_state;
}
MetaTouchState *
meta_input_device_native_lookup_touch_state (MetaInputDeviceNative *device,
int device_slot)
{
return g_hash_table_lookup (device->touches, GINT_TO_POINTER (device_slot));
}
void
meta_input_device_native_release_touch_state (MetaInputDeviceNative *device,
MetaTouchState *touch_state)
{
g_hash_table_remove (device->touches,
GINT_TO_POINTER (touch_state->device_slot));
}
static void
meta_input_device_native_class_init (MetaInputDeviceNativeClass *klass)
{
@ -1305,9 +1274,6 @@ meta_input_device_native_init (MetaInputDeviceNative *self)
cairo_matrix_init_identity (&self->device_matrix);
self->device_aspect_ratio = 0;
self->output_ratio = 0;
self->touches = g_hash_table_new_full (NULL, NULL,
NULL, release_device_touch_slot);
}
/*
@ -1320,7 +1286,7 @@ meta_input_device_native_init (MetaInputDeviceNative *self)
* it with the provided seat.
*/
ClutterInputDevice *
meta_input_device_native_new (MetaSeatNative *seat,
meta_input_device_native_new (MetaSeatImpl *seat_impl,
struct libinput_device *libinput_device)
{
MetaInputDeviceNative *device;
@ -1333,7 +1299,7 @@ meta_input_device_native_new (MetaSeatNative *seat,
type = meta_input_device_native_determine_type (libinput_device);
vendor = g_strdup_printf ("%.4x", libinput_device_get_id_vendor (libinput_device));
product = g_strdup_printf ("%.4x", libinput_device_get_id_product (libinput_device));
device_id = meta_seat_native_acquire_device_id (seat);
device_id = meta_seat_impl_acquire_device_id (seat_impl);
node_path = g_strdup_printf ("/dev/input/%s", libinput_device_get_sysname (libinput_device));
if (libinput_device_has_capability (libinput_device,
@ -1349,17 +1315,16 @@ meta_input_device_native_new (MetaSeatNative *seat,
"name", libinput_device_get_name (libinput_device),
"device-type", type,
"device-mode", CLUTTER_INPUT_MODE_SLAVE,
"enabled", TRUE,
"vendor-id", vendor,
"product-id", product,
"n-rings", n_rings,
"n-strips", n_strips,
"n-mode-groups", n_groups,
"device-node", node_path,
"seat", seat,
"seat", seat_impl->seat,
NULL);
device->seat = seat;
device->seat_impl = seat_impl;
device->libinput_device = libinput_device;
libinput_device_set_user_data (libinput_device, device);
@ -1382,7 +1347,7 @@ meta_input_device_native_new (MetaSeatNative *seat,
* Create a new virtual ClutterInputDevice of the given type.
*/
ClutterInputDevice *
meta_input_device_native_new_virtual (MetaSeatNative *seat,
meta_input_device_native_new_virtual (MetaSeatImpl *seat_impl,
ClutterInputDeviceType type,
ClutterInputMode mode)
{
@ -1406,25 +1371,24 @@ meta_input_device_native_new_virtual (MetaSeatNative *seat,
break;
};
device_id = meta_seat_native_acquire_device_id (seat);
device_id = meta_seat_impl_acquire_device_id (seat_impl);
device = g_object_new (META_TYPE_INPUT_DEVICE_NATIVE,
"id", device_id,
"name", name,
"device-type", type,
"device-mode", mode,
"enabled", TRUE,
"seat", seat,
"seat", seat_impl->seat,
NULL);
device->seat = seat;
device->seat_impl = seat_impl;
return CLUTTER_INPUT_DEVICE (device);
}
MetaSeatNative *
meta_input_device_native_get_seat (MetaInputDeviceNative *device)
MetaSeatImpl *
meta_input_device_native_get_seat_impl (MetaInputDeviceNative *device)
{
return device->seat;
return device->seat_impl;
}
void
@ -1484,17 +1448,16 @@ meta_input_device_native_get_libinput_device (ClutterInputDevice *device)
void
meta_input_device_native_translate_coordinates (ClutterInputDevice *device,
ClutterStage *stage,
MetaViewportInfo *viewports,
float *x,
float *y)
{
MetaInputDeviceNative *device_evdev = META_INPUT_DEVICE_NATIVE (device);
double min_x = 0, min_y = 0, max_x = 1, max_y = 1;
double stage_width, stage_height;
float stage_width, stage_height;
double x_d, y_d;
stage_width = clutter_actor_get_width (CLUTTER_ACTOR (stage));
stage_height = clutter_actor_get_height (CLUTTER_ACTOR (stage));
meta_viewport_info_get_extents (viewports, &stage_width, &stage_height);
x_d = *x / stage_width;
y_d = *y / stage_height;
@ -1518,23 +1481,50 @@ meta_input_device_native_translate_coordinates (ClutterInputDevice *device,
*y = CLAMP (y_d, MIN (min_y, max_y), MAX (min_y, max_y)) * stage_height;
}
void
meta_input_device_native_release_touch_slots (MetaInputDeviceNative *device_evdev,
uint64_t time_us)
MetaInputDeviceMapping
meta_input_device_native_get_mapping_mode (ClutterInputDevice *device)
{
GHashTableIter iter;
MetaTouchState *touch_state;
MetaInputDeviceNative *device_native = META_INPUT_DEVICE_NATIVE (device);
ClutterInputDeviceType device_type;
g_hash_table_iter_init (&iter, device_evdev->touches);
while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &touch_state))
g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device),
META_INPUT_DEVICE_MAPPING_ABSOLUTE);
device_type = clutter_input_device_get_device_type (device);
g_return_val_if_fail (device_type == CLUTTER_TABLET_DEVICE ||
device_type == CLUTTER_PEN_DEVICE ||
device_type == CLUTTER_ERASER_DEVICE,
META_INPUT_DEVICE_MAPPING_ABSOLUTE);
return device_native->mapping_mode;
}
void
meta_input_device_native_set_mapping_mode (ClutterInputDevice *device,
MetaInputDeviceMapping mapping)
{
meta_seat_native_notify_touch_event (touch_state->seat,
CLUTTER_INPUT_DEVICE (device_evdev),
CLUTTER_TOUCH_CANCEL,
time_us,
touch_state->seat_slot,
touch_state->coords.x,
touch_state->coords.y);
g_hash_table_iter_remove (&iter);
MetaInputDeviceNative *device_native = META_INPUT_DEVICE_NATIVE (device);
ClutterInputDeviceType device_type;
g_return_if_fail (CLUTTER_IS_INPUT_DEVICE (device));
device_type = clutter_input_device_get_device_type (device);
g_return_if_fail (device_type == CLUTTER_TABLET_DEVICE ||
device_type == CLUTTER_PEN_DEVICE ||
device_type == CLUTTER_ERASER_DEVICE);
if (device_native->mapping_mode == mapping)
return;
device_native->mapping_mode = mapping;
g_object_notify (G_OBJECT (device), "mapping-mode");
}
void
meta_input_device_native_update_coords (MetaInputDeviceNative *device_native,
double x,
double y)
{
device_native->pointer_x = x;
device_native->pointer_y = y;
}

View File

@ -29,6 +29,7 @@
#include <glib-object.h>
#include "backends/meta-input-device-private.h"
#include "backends/meta-input-settings-private.h"
#include "backends/native/meta-seat-native.h"
#include "clutter/clutter-mutter.h"
@ -54,6 +55,12 @@
(G_TYPE_INSTANCE_GET_CLASS ((obj), \
META_TYPE_INPUT_DEVICE_NATIVE, MetaInputDeviceNativeClass))
typedef enum
{
META_INPUT_DEVICE_MAPPING_ABSOLUTE,
META_INPUT_DEVICE_MAPPING_RELATIVE,
} MetaInputDeviceMapping;
typedef struct _MetaInputDeviceNative MetaInputDeviceNative;
typedef struct _MetaInputDeviceNativeClass MetaInputDeviceNativeClass;
@ -62,17 +69,20 @@ struct _MetaInputDeviceNative
ClutterInputDevice parent;
struct libinput_device *libinput_device;
MetaSeatNative *seat;
MetaSeatImpl *seat_impl;
ClutterInputDeviceTool *last_tool;
cairo_matrix_t device_matrix;
double device_aspect_ratio; /* w:h */
double output_ratio; /* w:h */
MetaInputDeviceMapping mapping_mode;
GHashTable *touches;
/* Pointer position */
double pointer_x;
double pointer_y;
/* Keyboard a11y */
ClutterKeyboardA11yFlags a11y_flags;
MetaKeyboardA11yFlags a11y_flags;
GList *slow_keys_list;
guint debounce_timer;
uint16_t debounce_key;
@ -99,17 +109,16 @@ struct _MetaInputDeviceNativeClass
ClutterInputDeviceClass parent_class;
};
GType meta_input_device_native_get_type (void) G_GNUC_CONST;
ClutterInputDevice * meta_input_device_native_new (MetaSeatNative *seat,
ClutterInputDevice * meta_input_device_native_new (MetaSeatImpl *seat_impl,
struct libinput_device *libinput_device);
ClutterInputDevice * meta_input_device_native_new_virtual (MetaSeatNative *seat,
ClutterInputDevice * meta_input_device_native_new_virtual (MetaSeatImpl *seat_impl,
ClutterInputDeviceType type,
ClutterInputMode mode);
MetaSeatNative * meta_input_device_native_get_seat (MetaInputDeviceNative *device);
MetaSeatImpl * meta_input_device_native_get_seat_impl (MetaInputDeviceNative *device);
void meta_input_device_native_update_leds (MetaInputDeviceNative *device,
enum libinput_led leds);
@ -118,27 +127,23 @@ ClutterInputDeviceType meta_input_device_native_determine_type (struct libin
void meta_input_device_native_translate_coordinates (ClutterInputDevice *device,
ClutterStage *stage,
MetaViewportInfo *viewports,
float *x,
float *y);
MetaInputDeviceMapping meta_input_device_native_get_mapping_mode (ClutterInputDevice *device);
void meta_input_device_native_set_mapping_mode (ClutterInputDevice *device,
MetaInputDeviceMapping mapping);
void meta_input_device_native_apply_kbd_a11y_settings (MetaInputDeviceNative *device,
ClutterKbdA11ySettings *settings);
MetaTouchState * meta_input_device_native_acquire_touch_state (MetaInputDeviceNative *device,
int device_slot);
MetaTouchState * meta_input_device_native_lookup_touch_state (MetaInputDeviceNative *device,
int device_slot);
void meta_input_device_native_release_touch_state (MetaInputDeviceNative *device,
MetaTouchState *touch_state);
void meta_input_device_native_release_touch_slots (MetaInputDeviceNative *device_evdev,
uint64_t time_us);
MetaKbdA11ySettings *settings);
void meta_input_device_native_a11y_maybe_notify_toggle_keys (MetaInputDeviceNative *device_evdev);
struct libinput_device * meta_input_device_native_get_libinput_device (ClutterInputDevice *device);
void meta_input_device_native_update_coords (MetaInputDeviceNative *device_native,
double x,
double y);
#endif /* META_INPUT_DEVICE_NATIVE_H */

View File

@ -26,7 +26,6 @@
#include <linux/input-event-codes.h>
#include <libinput.h>
#include "backends/meta-logical-monitor.h"
#include "backends/native/meta-backend-native.h"
#include "backends/native/meta-input-device-native.h"
#include "backends/native/meta-input-device-tool-native.h"
@ -34,6 +33,55 @@
G_DEFINE_TYPE (MetaInputSettingsNative, meta_input_settings_native, META_TYPE_INPUT_SETTINGS)
enum
{
PROP_0,
PROP_SEAT_IMPL,
N_PROPS,
};
GParamSpec *props[N_PROPS] = { 0 };
static void
meta_input_settings_native_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
MetaInputSettingsNative *input_settings_native =
META_INPUT_SETTINGS_NATIVE (object);
switch (prop_id)
{
case PROP_SEAT_IMPL:
input_settings_native->seat_impl = g_value_get_object (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
meta_input_settings_native_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
MetaInputSettingsNative *input_settings_native =
META_INPUT_SETTINGS_NATIVE (object);
switch (prop_id)
{
case PROP_SEAT_IMPL:
g_value_set_object (value, input_settings_native->seat_impl);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
meta_input_settings_native_set_send_events (MetaInputSettings *settings,
ClutterInputDevice *device,
@ -70,8 +118,19 @@ meta_input_settings_native_set_matrix (MetaInputSettings *settings,
{
cairo_matrix_t dev_matrix;
if (clutter_input_device_get_device_type (device) ==
CLUTTER_TOUCHSCREEN_DEVICE ||
meta_input_device_native_get_mapping_mode (device) ==
META_INPUT_DEVICE_MAPPING_ABSOLUTE)
{
cairo_matrix_init (&dev_matrix, matrix[0], matrix[3], matrix[1],
matrix[4], matrix[2], matrix[5]);
}
else
{
cairo_matrix_init_identity (&dev_matrix);
}
g_object_set (device, "device-matrix", &dev_matrix, NULL);
}
@ -376,10 +435,10 @@ meta_input_settings_native_set_keyboard_repeat (MetaInputSettings *settings,
guint delay,
guint interval)
{
ClutterSeat *seat;
MetaInputSettingsNative *input_settings_native;
seat = clutter_backend_get_default_seat (clutter_get_default_backend ());
meta_seat_native_set_keyboard_repeat (META_SEAT_NATIVE (seat),
input_settings_native = META_INPUT_SETTINGS_NATIVE (settings);
meta_seat_impl_set_keyboard_repeat (input_settings_native->seat_impl,
enabled, delay, interval);
}
@ -502,49 +561,26 @@ meta_input_settings_native_set_tablet_mapping (MetaInputSettings *settings,
ClutterInputDevice *device,
GDesktopTabletMapping mapping)
{
ClutterInputDeviceMapping dev_mapping;
MetaInputDeviceMapping dev_mapping;
if (mapping == G_DESKTOP_TABLET_MAPPING_ABSOLUTE)
dev_mapping = CLUTTER_INPUT_DEVICE_MAPPING_ABSOLUTE;
dev_mapping = META_INPUT_DEVICE_MAPPING_ABSOLUTE;
else if (mapping == G_DESKTOP_TABLET_MAPPING_RELATIVE)
dev_mapping = CLUTTER_INPUT_DEVICE_MAPPING_RELATIVE;
dev_mapping = META_INPUT_DEVICE_MAPPING_RELATIVE;
else
return;
clutter_input_device_set_mapping_mode (device, dev_mapping);
meta_input_device_native_set_mapping_mode (device, dev_mapping);
}
static void
meta_input_settings_native_set_tablet_keep_aspect (MetaInputSettings *settings,
meta_input_settings_native_set_tablet_aspect_ratio (MetaInputSettings *settings,
ClutterInputDevice *device,
MetaLogicalMonitor *logical_monitor,
gboolean keep_aspect)
gdouble aspect_ratio)
{
double aspect_ratio = 0;
if (keep_aspect)
{
int width, height;
if (logical_monitor)
{
width = logical_monitor->rect.width;
height = logical_monitor->rect.height;
}
else
{
MetaMonitorManager *monitor_manager;
MetaBackend *backend;
backend = meta_get_backend ();
monitor_manager = meta_backend_get_monitor_manager (backend);
meta_monitor_manager_get_screen_size (monitor_manager,
&width,
&height);
}
aspect_ratio = (double) width / height;
}
if (meta_input_device_native_get_mapping_mode (device) ==
META_INPUT_DEVICE_MAPPING_RELATIVE)
aspect_ratio = 0;
g_object_set (device, "output-aspect-ratio", aspect_ratio, NULL);
}
@ -688,6 +724,10 @@ static void
meta_input_settings_native_class_init (MetaInputSettingsNativeClass *klass)
{
MetaInputSettingsClass *input_settings_class = META_INPUT_SETTINGS_CLASS (klass);
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->set_property = meta_input_settings_native_set_property;
object_class->get_property = meta_input_settings_native_get_property;
input_settings_class->set_send_events = meta_input_settings_native_set_send_events;
input_settings_class->set_matrix = meta_input_settings_native_set_matrix;
@ -707,7 +747,7 @@ meta_input_settings_native_class_init (MetaInputSettingsNativeClass *klass)
input_settings_class->set_disable_while_typing = meta_input_settings_native_set_disable_while_typing;
input_settings_class->set_tablet_mapping = meta_input_settings_native_set_tablet_mapping;
input_settings_class->set_tablet_keep_aspect = meta_input_settings_native_set_tablet_keep_aspect;
input_settings_class->set_tablet_aspect_ratio = meta_input_settings_native_set_tablet_aspect_ratio;
input_settings_class->set_tablet_area = meta_input_settings_native_set_tablet_area;
input_settings_class->set_mouse_accel_profile = meta_input_settings_native_set_mouse_accel_profile;
@ -722,9 +762,27 @@ meta_input_settings_native_class_init (MetaInputSettingsNativeClass *klass)
input_settings_class->has_two_finger_scroll = meta_input_settings_native_has_two_finger_scroll;
input_settings_class->is_trackball_device = meta_input_settings_native_is_trackball_device;
props[PROP_SEAT_IMPL] =
g_param_spec_object ("seat-impl",
"Seat Impl",
"Seat Impl",
PROP_SEAT_IMPL,
CLUTTER_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY);
g_object_class_install_properties (object_class, N_PROPS, props);
}
static void
meta_input_settings_native_init (MetaInputSettingsNative *settings)
{
}
MetaInputSettings *
meta_input_settings_native_new (MetaSeatImpl *seat)
{
return g_object_new (META_TYPE_INPUT_SETTINGS_NATIVE,
"seat-impl", seat,
NULL);
}

View File

@ -37,6 +37,7 @@ typedef struct _MetaInputSettingsNativeClass MetaInputSettingsNativeClass;
struct _MetaInputSettingsNative
{
MetaInputSettings parent_instance;
MetaSeatImpl *seat_impl;
};
struct _MetaInputSettingsNativeClass
@ -46,4 +47,6 @@ struct _MetaInputSettingsNativeClass
GType meta_input_settings_native_get_type (void) G_GNUC_CONST;
MetaInputSettings * meta_input_settings_native_new (MetaSeatImpl *seat);
#endif /* META_INPUT_SETTINGS_NATIVE_H */

View File

@ -25,10 +25,6 @@
#include "backends/native/meta-keymap-native.h"
#include "backends/native/meta-seat-native.h"
static const char *option_xkb_layout = "us";
static const char *option_xkb_variant = "";
static const char *option_xkb_options = "";
typedef struct _MetaKeymapNative MetaKeymapNative;
struct _MetaKeymapNative
@ -36,6 +32,8 @@ struct _MetaKeymapNative
ClutterKeymap parent_instance;
struct xkb_keymap *keymap;
gboolean num_lock;
gboolean caps_lock;
};
G_DEFINE_TYPE (MetaKeymapNative, meta_keymap_native,
@ -54,31 +52,17 @@ meta_keymap_native_finalize (GObject *object)
static gboolean
meta_keymap_native_get_num_lock_state (ClutterKeymap *keymap)
{
struct xkb_state *xkb_state;
ClutterSeat *seat;
MetaKeymapNative *keymap_native = META_KEYMAP_NATIVE (keymap);
seat = clutter_backend_get_default_seat (clutter_get_default_backend ());
xkb_state = meta_seat_native_get_xkb_state (META_SEAT_NATIVE (seat));
return xkb_state_mod_name_is_active (xkb_state,
XKB_MOD_NAME_NUM,
XKB_STATE_MODS_LATCHED |
XKB_STATE_MODS_LOCKED);
return keymap_native->num_lock;
}
static gboolean
meta_keymap_native_get_caps_lock_state (ClutterKeymap *keymap)
{
struct xkb_state *xkb_state;
ClutterSeat *seat;
MetaKeymapNative *keymap_native = META_KEYMAP_NATIVE (keymap);
seat = clutter_backend_get_default_seat (clutter_get_default_backend ());
xkb_state = meta_seat_native_get_xkb_state (META_SEAT_NATIVE (seat));
return xkb_state_mod_name_is_active (xkb_state,
XKB_MOD_NAME_CAPS,
XKB_STATE_MODS_LATCHED |
XKB_STATE_MODS_LOCKED);
return keymap_native->caps_lock;
}
static PangoDirection
@ -103,19 +87,6 @@ meta_keymap_native_class_init (MetaKeymapNativeClass *klass)
static void
meta_keymap_native_init (MetaKeymapNative *keymap)
{
struct xkb_context *ctx;
struct xkb_rule_names names;
names.rules = "evdev";
names.model = "pc105";
names.layout = option_xkb_layout;
names.variant = option_xkb_variant;
names.options = option_xkb_options;
ctx = meta_create_xkb_context ();
g_assert (ctx);
keymap->keymap = xkb_keymap_new_from_names (ctx, &names, 0);
xkb_context_unref (ctx);
}
void
@ -132,3 +103,24 @@ meta_keymap_native_get_keyboard_map (MetaKeymapNative *keymap)
{
return keymap->keymap;
}
void
meta_keymap_native_update (MetaKeymapNative *keymap)
{
struct xkb_state *xkb_state;
ClutterSeat *seat;
seat = clutter_backend_get_default_seat (clutter_get_default_backend ());
xkb_state = meta_seat_impl_get_xkb_state (META_SEAT_NATIVE (seat)->impl);
keymap->num_lock =
xkb_state_mod_name_is_active (xkb_state,
XKB_MOD_NAME_NUM,
XKB_STATE_MODS_LATCHED |
XKB_STATE_MODS_LOCKED);
keymap->caps_lock =
xkb_state_mod_name_is_active (xkb_state,
XKB_MOD_NAME_CAPS,
XKB_STATE_MODS_LATCHED |
XKB_STATE_MODS_LOCKED);
}

View File

@ -32,5 +32,6 @@ G_DECLARE_FINAL_TYPE (MetaKeymapNative, meta_keymap_native,
void meta_keymap_native_set_keyboard_map (MetaKeymapNative *keymap,
struct xkb_keymap *xkb_keymap);
struct xkb_keymap * meta_keymap_native_get_keyboard_map (MetaKeymapNative *keymap);
void meta_keymap_native_update (MetaKeymapNative *keymap);
#endif /* META_KEYMAP_NATIVE_H */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,43 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/*
* Copyright (C) 2014 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:
* Jasper St. Pierre <jstpierre@mecheye.net>
*/
#ifndef META_KMS_CURSOR_RENDERER_H
#define META_KMS_CURSOR_RENDERER_H
#include "backends/meta-cursor-renderer.h"
#include "meta/meta-backend.h"
#define META_TYPE_KMS_CURSOR_RENDERER (meta_kms_cursor_renderer_get_type ())
G_DECLARE_FINAL_TYPE (MetaKmsCursorRenderer, meta_kms_cursor_renderer,
META, KMS_CURSOR_RENDERER,
GObject)
MetaKmsCursorRenderer * meta_kms_cursor_renderer_new (MetaBackend *backend);
void meta_kms_cursor_renderer_invalidate_state (MetaKmsCursorRenderer *kms_renderer);
gboolean meta_kms_cursor_renderer_update_cursor (MetaKmsCursorRenderer *kms_cursor_renderer,
MetaCursorSprite *sprite);
void meta_kms_cursor_renderer_set_cursor_renderer (MetaKmsCursorRenderer *kms_renderer,
MetaCursorRenderer *renderer);
#endif /* META_KMS_CURSOR_RENDERER_H */

View File

@ -528,7 +528,7 @@ meta_launcher_new (GError **error)
meta_clutter_backend_native_set_seat_id (self->seat_id);
meta_seat_native_set_device_callbacks (on_evdev_device_open,
meta_seat_impl_set_device_callbacks (on_evdev_device_open,
on_evdev_device_close,
self);

View File

@ -0,0 +1,676 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/*
* Copyright (C) 2015-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:
* Jonas Ådahl <jadahl@gmail.com>
*/
#include "config.h"
#include <glib-object.h>
#include <wayland-server.h>
#include "core/meta-border.h"
#include "meta-pointer-constraint-native.h"
struct _MetaPointerConstraintImplNative
{
MetaPointerConstraintImpl parent;
MetaPointerConstraint *constraint;
cairo_region_t *region;
};
G_DEFINE_TYPE (MetaPointerConstraintImplNative,
meta_pointer_constraint_impl_native,
META_TYPE_POINTER_CONSTRAINT_IMPL);
typedef struct _MetaBox
{
int x1;
int y1;
int x2;
int y2;
} MetaBox;
static MetaBorder *
add_border (GArray *borders,
float x1,
float y1,
float x2,
float y2,
MetaBorderMotionDirection blocking_directions)
{
MetaBorder border;
border = (MetaBorder) {
.line = (MetaLine2) {
.a = (MetaVector2) {
.x = x1,
.y = y1,
},
.b = (MetaVector2) {
.x = x2,
.y = y2,
},
},
.blocking_directions = blocking_directions,
};
g_array_append_val (borders, border);
return &g_array_index (borders, MetaBorder, borders->len - 1);
}
static gint
compare_lines_x (gconstpointer a,
gconstpointer b)
{
const MetaBorder *border_a = a;
const MetaBorder *border_b = b;
if (border_a->line.a.x == border_b->line.a.x)
return border_a->line.b.x < border_b->line.b.x;
else
return border_a->line.a.x > border_b->line.a.x;
}
static void
add_non_overlapping_edges (MetaBox *boxes,
unsigned int band_above_start,
unsigned int band_below_start,
unsigned int band_below_end,
GArray *borders)
{
unsigned int i;
GArray *band_merge;
MetaBorder *border;
MetaBorder *prev_border;
MetaBorder *new_border;
band_merge = g_array_new (FALSE, FALSE, sizeof *border);
/* Add bottom band of previous row, and top band of current row, and
* sort them so lower left x coordinate comes first. If there are two
* borders with the same left x coordinate, the wider one comes first.
*/
for (i = band_above_start; i < band_below_start; i++)
{
MetaBox *box = &boxes[i];
add_border (band_merge, box->x1, box->y2, box->x2, box->y2,
META_BORDER_MOTION_DIRECTION_POSITIVE_Y);
}
for (i = band_below_start; i < band_below_end; i++)
{
MetaBox *box= &boxes[i];
add_border (band_merge, box->x1, box->y1, box->x2, box->y1,
META_BORDER_MOTION_DIRECTION_NEGATIVE_Y);
}
g_array_sort (band_merge, compare_lines_x);
/* Combine the two combined bands so that any overlapping border is
* eliminated. */
prev_border = NULL;
for (i = 0; i < band_merge->len; i++)
{
border = &g_array_index (band_merge, MetaBorder, i);
g_assert (border->line.a.y == border->line.b.y);
g_assert (!prev_border ||
prev_border->line.a.y == border->line.a.y);
g_assert (!prev_border ||
(prev_border->line.a.x != border->line.a.x ||
prev_border->line.b.x != border->line.b.x));
g_assert (!prev_border ||
prev_border->line.a.x <= border->line.a.x);
if (prev_border &&
prev_border->line.a.x == border->line.a.x)
{
/*
* ------------ +
* ------- =
* [ ]-----
*/
prev_border->line.a.x = border->line.b.x;
}
else if (prev_border &&
prev_border->line.b.x == border->line.b.x)
{
/*
* ------------ +
* ------ =
* ------[ ]
*/
prev_border->line.b.x = border->line.a.x;
}
else if (prev_border &&
prev_border->line.b.x == border->line.a.x)
{
/*
* -------- +
* ------ =
* --------------
*/
prev_border->line.b.x = border->line.b.x;
}
else if (prev_border &&
prev_border->line.b.x >= border->line.a.x)
{
/*
* --------------- +
* ------ =
* -----[ ]----
*/
new_border = add_border (borders,
border->line.b.x,
border->line.b.y,
prev_border->line.b.x,
prev_border->line.b.y,
prev_border->blocking_directions);
prev_border->line.b.x = border->line.a.x;
prev_border = new_border;
}
else
{
g_assert (!prev_border ||
prev_border->line.b.x < border->line.a.x);
/*
* First border or non-overlapping.
*
* ----- +
* ----- =
* ----- -----
*/
g_array_append_val (borders, *border);
prev_border = &g_array_index (borders, MetaBorder, borders->len - 1);
}
}
g_array_free (band_merge, FALSE);
}
static void
add_band_bottom_edges (MetaBox *boxes,
int band_start,
int band_end,
GArray *borders)
{
int i;
for (i = band_start; i < band_end; i++)
{
add_border (borders,
boxes[i].x1, boxes[i].y2,
boxes[i].x2, boxes[i].y2,
META_BORDER_MOTION_DIRECTION_POSITIVE_Y);
}
}
static void
region_to_outline (cairo_region_t *region,
GArray *borders)
{
MetaBox *boxes;
int num_boxes;
int i;
int top_most, bottom_most;
int current_roof;
int prev_top;
int band_start, prev_band_start;
/*
* Remove any overlapping lines from the set of rectangles. Note that
* pixman regions are grouped as rows of rectangles, where rectangles
* in one row never touch or overlap and are all of the same height.
*
* -------- --- -------- ---
* | | | | | | | |
* ----------====---- --- ----------- ----- ---
* | | => | |
* ----==========--------- ----- ----------
* | | | |
* ------------------- -------------------
*
*/
num_boxes = cairo_region_num_rectangles (region);
boxes = g_new (MetaBox, num_boxes);
for (i = 0; i < num_boxes; i++)
{
cairo_rectangle_int_t rect;
cairo_region_get_rectangle (region, i, &rect);
boxes[i] = (MetaBox) {
.x1 = rect.x,
.y1 = rect.y,
.x2 = rect.x + rect.width,
.y2 = rect.y + rect.height,
};
}
prev_top = 0;
top_most = boxes[0].y1;
current_roof = top_most;
bottom_most = boxes[num_boxes - 1].y2;
band_start = 0;
prev_band_start = 0;
for (i = 0; i < num_boxes; i++)
{
/* Detect if there is a vertical empty space, and add the lower
* level of the previous band if so was the case. */
if (i > 0 &&
boxes[i].y1 != prev_top &&
boxes[i].y1 != boxes[i - 1].y2)
{
current_roof = boxes[i].y1;
add_band_bottom_edges (boxes,
band_start,
i,
borders);
}
/* Special case adding the last band, since it won't be handled
* by the band change detection below. */
if (boxes[i].y1 != current_roof && i == num_boxes - 1)
{
if (boxes[i].y1 != prev_top)
{
/* The last band is a single box, so we don't
* have a prev_band_start to tell us when the
* previous band started. */
add_non_overlapping_edges (boxes,
band_start,
i,
i + 1,
borders);
}
else
{
add_non_overlapping_edges (boxes,
prev_band_start,
band_start,
i + 1,
borders);
}
}
/* Detect when passing a band and combine the top border of the
* just passed band with the bottom band of the previous band.
*/
if (boxes[i].y1 != top_most && boxes[i].y1 != prev_top)
{
/* Combine the two passed bands. */
if (prev_top != current_roof)
{
add_non_overlapping_edges (boxes,
prev_band_start,
band_start,
i,
borders);
}
prev_band_start = band_start;
band_start = i;
}
/* Add the top border if the box is part of the current roof. */
if (boxes[i].y1 == current_roof)
{
add_border (borders,
boxes[i].x1, boxes[i].y1,
boxes[i].x2, boxes[i].y1,
META_BORDER_MOTION_DIRECTION_NEGATIVE_Y);
}
/* Add the bottom border of the last band. */
if (boxes[i].y2 == bottom_most)
{
add_border (borders,
boxes[i].x1, boxes[i].y2,
boxes[i].x2, boxes[i].y2,
META_BORDER_MOTION_DIRECTION_POSITIVE_Y);
}
/* Always add the left border. */
add_border (borders,
boxes[i].x1, boxes[i].y1,
boxes[i].x1, boxes[i].y2,
META_BORDER_MOTION_DIRECTION_NEGATIVE_X);
/* Always add the right border. */
add_border (borders,
boxes[i].x2, boxes[i].y1,
boxes[i].x2, boxes[i].y2,
META_BORDER_MOTION_DIRECTION_POSITIVE_X);
prev_top = boxes[i].y1;
}
g_free (boxes);
}
static MetaBorder *
get_closest_border (GArray *borders,
MetaLine2 *motion,
uint32_t directions)
{
MetaBorder *border;
MetaVector2 intersection;
MetaVector2 delta;
float distance_2;
MetaBorder *closest_border = NULL;
float closest_distance_2 = DBL_MAX;
unsigned int i;
for (i = 0; i < borders->len; i++)
{
border = &g_array_index (borders, MetaBorder, i);
if (!meta_border_is_blocking_directions (border, directions))
continue;
if (!meta_line2_intersects_with (&border->line, motion, &intersection))
continue;
delta = meta_vector2_subtract (intersection, motion->a);
distance_2 = delta.x*delta.x + delta.y*delta.y;
if (distance_2 < closest_distance_2)
{
closest_border = border;
closest_distance_2 = distance_2;
}
}
return closest_border;
}
static void
clamp_to_border (MetaBorder *border,
MetaLine2 *motion,
uint32_t *motion_dir)
{
/*
* When clamping either rightward or downward motions, the motion needs to be
* clamped so that the destination coordinate does not end up on the border
* (see weston_pointer_clamp_event_to_region). Do this by clamping such
* motions to the border minus the smallest possible wl_fixed_t value.
*
* When clamping in either leftward or upward motion, the resulting coordinate
* needs to be clamped so that it is enough on the inside to avoid the
* inaccuracies of clutter's stage to actor transformation algorithm (the one
* used in clutter_actor_transform_stage_point) to make it end up outside the
* next motion. It also needs to be clamped so that to the wl_fixed_t
* coordinate may still be right on the border (i.e. at .0). Testing shows
* that the smallest wl_fixed_t value divided by 10 is small enough to make
* the wl_fixed_t coordinate .0 and large enough to avoid the inaccuracies of
* clutters transform algorithm.
*/
if (meta_border_is_horizontal (border))
{
if (*motion_dir & META_BORDER_MOTION_DIRECTION_POSITIVE_Y)
motion->b.y = border->line.a.y - wl_fixed_to_double (1);
else
motion->b.y = border->line.a.y + wl_fixed_to_double (1) / 10;
*motion_dir &= ~(META_BORDER_MOTION_DIRECTION_POSITIVE_Y |
META_BORDER_MOTION_DIRECTION_NEGATIVE_Y);
}
else
{
if (*motion_dir & META_BORDER_MOTION_DIRECTION_POSITIVE_X)
motion->b.x = border->line.a.x - wl_fixed_to_double (1);
else
motion->b.x = border->line.a.x + wl_fixed_to_double (1) / 10;
*motion_dir &= ~(META_BORDER_MOTION_DIRECTION_POSITIVE_X |
META_BORDER_MOTION_DIRECTION_NEGATIVE_X);
}
}
static uint32_t
get_motion_directions (MetaLine2 *motion)
{
uint32_t directions = 0;
if (motion->a.x < motion->b.x)
directions |= META_BORDER_MOTION_DIRECTION_POSITIVE_X;
else if (motion->a.x > motion->b.x)
directions |= META_BORDER_MOTION_DIRECTION_NEGATIVE_X;
if (motion->a.y < motion->b.y)
directions |= META_BORDER_MOTION_DIRECTION_POSITIVE_Y;
else if (motion->a.y > motion->b.y)
directions |= META_BORDER_MOTION_DIRECTION_NEGATIVE_Y;
return directions;
}
static void
meta_pointer_constraint_impl_native_constraint (MetaPointerConstraintImpl *impl,
ClutterInputDevice *device,
uint32_t time,
float prev_x,
float prev_y,
float *x_inout,
float *y_inout)
{
MetaPointerConstraintImplNative *native = META_POINTER_CONSTRAINT_IMPL_NATIVE (impl);
cairo_region_t *region;
float x, y;
GArray *borders;
MetaLine2 motion;
MetaBorder *closest_border;
uint32_t directions;
region = cairo_region_reference (native->region);
x = *x_inout;
y = *y_inout;
/* For motions in a positive direction on any axis, append the smallest
* possible value representable in a Wayland absolute coordinate. This is
* in order to avoid not clamping motion that as a floating point number
* won't be clamped, but will be rounded up to be outside of the range
* of wl_fixed_t. */
if (x > prev_x)
x += (float) wl_fixed_to_double(1);
if (y > prev_y)
y += (float) wl_fixed_to_double(1);
borders = g_array_new (FALSE, FALSE, sizeof (MetaBorder));
/*
* Generate borders given the confine region we are to use. The borders
* are defined to be the outer region of the allowed area. This means
* top/left borders are "within" the allowed area, while bottom/right
* borders are outside. This needs to be considered when clamping
* confined motion vectors.
*/
region_to_outline (region, borders);
cairo_region_destroy (region);
motion = (MetaLine2) {
.a = (MetaVector2) {
.x = prev_x,
.y = prev_y,
},
.b = (MetaVector2) {
.x = x,
.y = y,
},
};
directions = get_motion_directions (&motion);
while (directions)
{
closest_border = get_closest_border (borders,
&motion,
directions);
if (closest_border)
clamp_to_border (closest_border, &motion, &directions);
else
break;
}
*x_inout = motion.b.x;
*y_inout = motion.b.y;
g_array_free (borders, FALSE);
}
static float
point_to_border_distance_2 (MetaBorder *border,
float x,
float y)
{
float orig_x, orig_y;
float dx, dy;
if (meta_border_is_horizontal (border))
{
if (x < border->line.a.x)
orig_x = border->line.a.x;
else if (x > border->line.b.x)
orig_x = border->line.b.x;
else
orig_x = x;
orig_y = border->line.a.y;
}
else
{
if (y < border->line.a.y)
orig_y = border->line.a.y;
else if (y > border->line.b.y)
orig_y = border->line.b.y;
else
orig_y = y;
orig_x = border->line.a.x;
}
dx = fabsf (orig_x - x);
dy = fabsf (orig_y - y);
return dx*dx + dy*dy;
}
static void
closest_point_behind_border (MetaBorder *border,
float *sx,
float *sy)
{
switch (border->blocking_directions)
{
case META_BORDER_MOTION_DIRECTION_POSITIVE_X:
case META_BORDER_MOTION_DIRECTION_NEGATIVE_X:
if (border->blocking_directions == META_BORDER_MOTION_DIRECTION_POSITIVE_X)
*sx = border->line.a.x - wl_fixed_to_double (1);
else
*sx = border->line.a.x + wl_fixed_to_double (1);
if (*sy < border->line.a.y)
*sy = border->line.a.y + wl_fixed_to_double (1);
else if (*sy > border->line.b.y)
*sy = border->line.b.y - wl_fixed_to_double (1);
break;
case META_BORDER_MOTION_DIRECTION_POSITIVE_Y:
case META_BORDER_MOTION_DIRECTION_NEGATIVE_Y:
if (border->blocking_directions == META_BORDER_MOTION_DIRECTION_POSITIVE_Y)
*sy = border->line.a.y - wl_fixed_to_double (1);
else
*sy = border->line.a.y + wl_fixed_to_double (1);
if (*sx < border->line.a.x)
*sx = border->line.a.x + wl_fixed_to_double (1);
else if (*sx > (border->line.b.x))
*sx = border->line.b.x - wl_fixed_to_double (1);
break;
}
}
static void
meta_pointer_constraint_impl_native_ensure_constrained (MetaPointerConstraintImpl *impl,
ClutterInputDevice *device)
{
MetaPointerConstraintImplNative *impl_native;
graphene_point_t point;
cairo_region_t *region;
float x;
float y;
impl_native = META_POINTER_CONSTRAINT_IMPL_NATIVE (impl);
region = cairo_region_reference (impl_native->region);
clutter_input_device_get_coords (device, NULL, &point);
x = point.x;
y = point.y;
if (!cairo_region_contains_point (region, (int) x, (int) y))
{
GArray *borders;
float closest_distance_2 = FLT_MAX;
MetaBorder *closest_border = NULL;
ClutterSeat *seat;
unsigned int i;
borders = g_array_new (FALSE, FALSE, sizeof (MetaBorder));
region_to_outline (region, borders);
for (i = 0; i < borders->len; i++)
{
MetaBorder *border = &g_array_index (borders, MetaBorder, i);
float distance_2;
distance_2 = point_to_border_distance_2 (border, x, y);
if (distance_2 < closest_distance_2)
{
closest_border = border;
closest_distance_2 = distance_2;
}
}
closest_point_behind_border (closest_border, &x, &y);
seat = clutter_backend_get_default_seat (clutter_get_default_backend ());
clutter_seat_warp_pointer (seat, x, y);
}
cairo_region_destroy (region);
}
static void
meta_pointer_constraint_impl_native_init (MetaPointerConstraintImplNative *constraint)
{
}
static void
meta_pointer_constraint_impl_native_class_init (MetaPointerConstraintImplNativeClass *klass)
{
MetaPointerConstraintImplClass *constraint_impl;
constraint_impl = META_POINTER_CONSTRAINT_IMPL_CLASS (klass);
constraint_impl->constrain = meta_pointer_constraint_impl_native_constraint;
constraint_impl->ensure_constrained =
meta_pointer_constraint_impl_native_ensure_constrained;
}
MetaPointerConstraintImpl *
meta_pointer_constraint_impl_native_new (MetaPointerConstraint *constraint,
const cairo_region_t *region)
{
MetaPointerConstraintImplNative *impl;
impl = g_object_new (META_TYPE_POINTER_CONSTRAINT_IMPL_NATIVE, NULL);
impl->constraint = constraint;
impl->region = cairo_region_copy (region);
return META_POINTER_CONSTRAINT_IMPL (impl);
}

View File

@ -0,0 +1,46 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/*
* 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_POINTER_CONSTRAINT_NATIVE_H
#define META_POINTER_CONSTRAINT_NATIVE_H
#include <glib-object.h>
#include "clutter/clutter.h"
#include "backends/meta-pointer-constraint.h"
G_BEGIN_DECLS
#define META_TYPE_POINTER_CONSTRAINT_IMPL_NATIVE (meta_pointer_constraint_impl_native_get_type ())
G_DECLARE_FINAL_TYPE (MetaPointerConstraintImplNative,
meta_pointer_constraint_impl_native,
META, POINTER_CONSTRAINT_IMPL_NATIVE,
MetaPointerConstraintImpl)
MetaPointerConstraintImpl * meta_pointer_constraint_impl_native_new (MetaPointerConstraint *constraint,
const cairo_region_t *region);
G_END_DECLS
#endif /* META_POINTER_CONSTRAINT_NATIVE_H */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,276 @@
/*
* Copyright (C) 2010 Intel Corp.
* Copyright (C) 2014 Jonas Ådahl
* Copyright (C) 2016 Red Hat Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
* Author: Damien Lespiau <damien.lespiau@intel.com>
* Author: Jonas Ådahl <jadahl@gmail.com>
*/
#ifndef META_SEAT_IMPL_H
#define META_SEAT_IMPL_H
#include <gudev/gudev.h>
#include <libinput.h>
#include <linux/input-event-codes.h>
#include "backends/meta-input-settings-private.h"
#include "backends/meta-viewport-info.h"
#include "backends/native/meta-backend-native-types.h"
#include "backends/native/meta-barrier-native.h"
#include "backends/native/meta-cursor-renderer-native.h"
#include "backends/native/meta-keymap-native.h"
#include "backends/native/meta-pointer-constraint-native.h"
#include "backends/native/meta-xkb-utils.h"
#include "clutter/clutter.h"
typedef struct _MetaTouchState MetaTouchState;
typedef struct _MetaSeatImpl MetaSeatImpl;
typedef struct _MetaEventSource MetaEventSource;
struct _MetaTouchState
{
MetaSeatImpl *seat;
int device_slot;
int seat_slot;
graphene_point_t coords;
};
struct _MetaSeatImpl
{
GObject parent_instance;
GMainContext *caller_context;
GMainContext *input_context;
GMainLoop *input_loop;
GThread *input_thread;
MetaSeatNative *seat;
char *seat_id;
MetaEventSource *event_source;
struct libinput *libinput;
struct libinput_seat *libinput_seat;
GRWLock state_lock;
GSList *devices;
ClutterInputDevice *core_pointer;
ClutterInputDevice *core_keyboard;
GHashTable *touch_states;
GHashTable *cursor_renderers;
struct xkb_state *xkb;
xkb_led_index_t caps_lock_led;
xkb_led_index_t num_lock_led;
xkb_led_index_t scroll_lock_led;
xkb_layout_index_t layout_idx;
uint32_t button_state;
int button_count[KEY_CNT];
int device_id_next;
GList *free_device_ids;
MetaBarrierManagerNative *barrier_manager;
MetaPointerConstraintImpl *pointer_constraint;
MetaKeymapNative *keymap;
MetaInputSettings *input_settings;
MetaViewportInfo *viewports;
GUdevClient *udev_client;
guint tablet_mode_switch_state : 1;
guint has_touchscreen : 1;
guint has_tablet_switch : 1;
guint touch_mode : 1;
guint input_thread_initialized : 1;
/* keyboard repeat */
gboolean repeat;
uint32_t repeat_delay;
uint32_t repeat_interval;
uint32_t repeat_key;
uint32_t repeat_count;
uint32_t repeat_timer;
ClutterInputDevice *repeat_device;
float pointer_x;
float pointer_y;
/* Emulation of discrete scroll events out of smooth ones */
float accum_scroll_dx;
float accum_scroll_dy;
gboolean released;
};
#define META_TYPE_SEAT_IMPL meta_seat_impl_get_type ()
G_DECLARE_FINAL_TYPE (MetaSeatImpl, meta_seat_impl,
META, SEAT_IMPL, GObject)
MetaSeatImpl * meta_seat_impl_new (MetaSeatNative *seat,
const gchar *seat_id);
void meta_seat_impl_run_input_task (MetaSeatImpl *impl,
GTask *task,
GSourceFunc dispatch_func);
void meta_seat_impl_notify_key (MetaSeatImpl *seat,
ClutterInputDevice *device,
uint64_t time_us,
uint32_t key,
uint32_t state,
gboolean update_keys);
void meta_seat_impl_notify_relative_motion (MetaSeatImpl *seat_evdev,
ClutterInputDevice *input_device,
uint64_t time_us,
float dx,
float dy,
float dx_unaccel,
float dy_unaccel);
void meta_seat_impl_notify_absolute_motion (MetaSeatImpl *seat_evdev,
ClutterInputDevice *input_device,
uint64_t time_us,
float x,
float y,
double *axes);
void meta_seat_impl_notify_button (MetaSeatImpl *seat,
ClutterInputDevice *input_device,
uint64_t time_us,
uint32_t button,
uint32_t state);
void meta_seat_impl_notify_scroll_continuous (MetaSeatImpl *seat,
ClutterInputDevice *input_device,
uint64_t time_us,
double dx,
double dy,
ClutterScrollSource source,
ClutterScrollFinishFlags flags);
void meta_seat_impl_notify_discrete_scroll (MetaSeatImpl *seat,
ClutterInputDevice *input_device,
uint64_t time_us,
double discrete_dx,
double discrete_dy,
ClutterScrollSource source);
void meta_seat_impl_notify_touch_event (MetaSeatImpl *seat,
ClutterInputDevice *input_device,
ClutterEventType evtype,
uint64_t time_us,
int slot,
double x,
double y);
void meta_seat_impl_set_libinput_seat (MetaSeatImpl *seat,
struct libinput_seat *libinput_seat);
void meta_seat_impl_sync_leds (MetaSeatImpl *seat);
MetaTouchState * meta_seat_impl_acquire_touch_state (MetaSeatImpl *seat,
int seat_slot);
MetaTouchState * meta_seat_impl_lookup_touch_state (MetaSeatImpl *seat,
int seat_slot);
void meta_seat_impl_release_touch_state (MetaSeatImpl *seat,
int seat_slot);
gint meta_seat_impl_acquire_device_id (MetaSeatImpl *seat);
void meta_seat_impl_release_device_id (MetaSeatImpl *seat,
ClutterInputDevice *device);
void meta_seat_impl_update_xkb_state (MetaSeatImpl *seat);
/**
* MetaOpenDeviceCallback:
* @path: the device path
* @flags: flags to be passed to open
*
* This callback will be called when Clutter needs to access an input
* device. It should return an open file descriptor for the file at @path,
* or -1 if opening failed.
*/
typedef int (* MetaOpenDeviceCallback) (const char *path,
int flags,
gpointer user_data,
GError **error);
typedef void (* MetaCloseDeviceCallback) (int fd,
gpointer user_data);
void meta_seat_impl_set_device_callbacks (MetaOpenDeviceCallback open_callback,
MetaCloseDeviceCallback close_callback,
gpointer user_data);
void meta_seat_impl_release_devices (MetaSeatImpl *seat);
void meta_seat_impl_reclaim_devices (MetaSeatImpl *seat);
struct xkb_state * meta_seat_impl_get_xkb_state (MetaSeatImpl *seat);
void meta_seat_impl_set_keyboard_map (MetaSeatImpl *seat,
struct xkb_keymap *keymap);
void meta_seat_impl_set_keyboard_layout_index (MetaSeatImpl *seat,
xkb_layout_index_t idx);
void meta_seat_impl_set_keyboard_numlock (MetaSeatImpl *seat,
gboolean numlock_state);
void meta_seat_impl_set_keyboard_repeat (MetaSeatImpl *seat,
gboolean repeat,
uint32_t delay,
uint32_t interval);
MetaBarrierManagerNative * meta_seat_impl_get_barrier_manager (MetaSeatImpl *seat);
void meta_seat_impl_set_pointer_constraint (MetaSeatImpl *seat,
MetaPointerConstraintImpl *impl);
void meta_seat_impl_set_viewports (MetaSeatImpl *seat,
MetaViewportInfo *viewports);
void meta_seat_impl_warp_pointer (MetaSeatImpl *seat,
int x,
int y);
ClutterVirtualInputDevice *
meta_seat_impl_create_virtual_device (MetaSeatImpl *seat,
ClutterInputDeviceType device_type);
gboolean meta_seat_impl_query_state (MetaSeatImpl *seat,
ClutterInputDevice *device,
ClutterEventSequence *sequence,
graphene_point_t *coords,
ClutterModifierType *modifiers);
ClutterInputDevice * meta_seat_impl_get_pointer (MetaSeatImpl *seat);
ClutterInputDevice * meta_seat_impl_get_keyboard (MetaSeatImpl *seat);
GSList * meta_seat_impl_get_devices (MetaSeatImpl *seat);
MetaKeymapNative * meta_seat_impl_get_keymap (MetaSeatImpl *seat);
void meta_seat_impl_notify_kbd_a11y_flags_changed (MetaSeatImpl *impl,
MetaKeyboardA11yFlags new_flags,
MetaKeyboardA11yFlags what_changed);
void meta_seat_impl_notify_kbd_a11y_mods_state_changed (MetaSeatImpl *impl,
xkb_mod_mask_t new_latched_mods,
xkb_mod_mask_t new_locked_mods);
void meta_seat_impl_notify_bell (MetaSeatImpl *impl);
MetaInputSettings * meta_seat_impl_get_input_settings (MetaSeatImpl *impl);
#endif /* META_SEAT_IMPL_H */

File diff suppressed because it is too large Load Diff

View File

@ -27,220 +27,49 @@
#include <libinput.h>
#include <linux/input-event-codes.h>
#include "backends/meta-viewport-info.h"
#include "backends/native/meta-barrier-native.h"
#include "backends/native/meta-cursor-renderer-native.h"
#include "backends/native/meta-keymap-native.h"
#include "backends/native/meta-pointer-constraint-native.h"
#include "backends/native/meta-seat-impl.h"
#include "backends/native/meta-xkb-utils.h"
#include "clutter/clutter.h"
typedef struct _MetaTouchState MetaTouchState;
typedef struct _MetaSeatNative MetaSeatNative;
typedef struct _MetaEventSource MetaEventSource;
/**
* MetaPointerConstrainCallback:
* @device: the core pointer device
* @time: the event time in milliseconds
* @x: (inout): the new X coordinate
* @y: (inout): the new Y coordinate
* @user_data: user data passed to this function
*
* This callback will be called for all pointer motion events, and should
* update (@x, @y) to constrain the pointer position appropriately.
* The subsequent motion event will use the updated values as the new coordinates.
* Note that the coordinates are not clamped to the stage size, and the callback
* must make sure that this happens before it returns.
* Also note that the event will be emitted even if the pointer is constrained
* to be in the same position.
*/
typedef void (* MetaPointerConstrainCallback) (ClutterInputDevice *device,
uint32_t time,
float prev_x,
float prev_y,
float *x,
float *y,
gpointer user_data);
typedef void (* MetaRelativeMotionFilter) (ClutterInputDevice *device,
float x,
float y,
float *dx,
float *dy,
gpointer user_data);
struct _MetaTouchState
{
MetaSeatNative *seat;
int device_slot;
int seat_slot;
graphene_point_t coords;
};
struct _MetaSeatNative
{
ClutterSeat parent_instance;
MetaSeatImpl *impl;
char *seat_id;
MetaEventSource *event_source;
struct libinput *libinput;
struct libinput_seat *libinput_seat;
GSList *devices;
GList *devices;
struct xkb_keymap *xkb_keymap;
xkb_layout_index_t xkb_layout_index;
ClutterInputDevice *core_pointer;
ClutterInputDevice *core_keyboard;
MetaTouchState **touch_states;
int n_alloc_touch_states;
struct xkb_state *xkb;
xkb_led_index_t caps_lock_led;
xkb_led_index_t num_lock_led;
xkb_led_index_t scroll_lock_led;
xkb_layout_index_t layout_idx;
uint32_t button_state;
int button_count[KEY_CNT];
ClutterStage *stage;
ClutterStageManager *stage_manager;
gulong stage_added_handler;
gulong stage_removed_handler;
int device_id_next;
GList *free_device_ids;
MetaPointerConstrainCallback constrain_callback;
gpointer constrain_data;
GDestroyNotify constrain_data_notify;
MetaRelativeMotionFilter relative_motion_filter;
gpointer relative_motion_filter_user_data;
GSList *event_filters;
MetaKeymapNative *keymap;
GUdevClient *udev_client;
guint tablet_mode_switch_state : 1;
guint has_touchscreen : 1;
guint has_tablet_switch : 1;
guint touch_mode : 1;
/* keyboard repeat */
gboolean repeat;
uint32_t repeat_delay;
uint32_t repeat_interval;
uint32_t repeat_key;
uint32_t repeat_count;
uint32_t repeat_timer;
ClutterInputDevice *repeat_device;
float pointer_x;
float pointer_y;
/* Emulation of discrete scroll events out of smooth ones */
float accum_scroll_dx;
float accum_scroll_dy;
MetaCursorRenderer *cursor_renderer;
MetaKmsCursorRenderer *kms_cursor_renderer;
GHashTable *tablet_cursors;
gboolean released;
gboolean touch_mode;
};
#define META_TYPE_SEAT_NATIVE meta_seat_native_get_type ()
G_DECLARE_FINAL_TYPE (MetaSeatNative, meta_seat_native,
META, SEAT_NATIVE, ClutterSeat)
void meta_seat_native_notify_key (MetaSeatNative *seat,
ClutterInputDevice *device,
uint64_t time_us,
uint32_t key,
uint32_t state,
gboolean update_keys);
void meta_seat_native_notify_relative_motion (MetaSeatNative *seat_evdev,
ClutterInputDevice *input_device,
uint64_t time_us,
float dx,
float dy,
float dx_unaccel,
float dy_unaccel);
void meta_seat_native_notify_absolute_motion (MetaSeatNative *seat_evdev,
ClutterInputDevice *input_device,
uint64_t time_us,
float x,
float y,
double *axes);
void meta_seat_native_notify_button (MetaSeatNative *seat,
ClutterInputDevice *input_device,
uint64_t time_us,
uint32_t button,
uint32_t state);
void meta_seat_native_notify_scroll_continuous (MetaSeatNative *seat,
ClutterInputDevice *input_device,
uint64_t time_us,
double dx,
double dy,
ClutterScrollSource source,
ClutterScrollFinishFlags flags);
void meta_seat_native_notify_discrete_scroll (MetaSeatNative *seat,
ClutterInputDevice *input_device,
uint64_t time_us,
double discrete_dx,
double discrete_dy,
ClutterScrollSource source);
void meta_seat_native_notify_touch_event (MetaSeatNative *seat,
ClutterInputDevice *input_device,
ClutterEventType evtype,
uint64_t time_us,
int slot,
double x,
double y);
void meta_seat_native_set_libinput_seat (MetaSeatNative *seat,
struct libinput_seat *libinput_seat);
void meta_seat_native_sync_leds (MetaSeatNative *seat);
ClutterInputDevice * meta_seat_native_get_device (MetaSeatNative *seat,
int id);
MetaTouchState * meta_seat_native_acquire_touch_state (MetaSeatNative *seat,
int device_slot);
void meta_seat_native_release_touch_state (MetaSeatNative *seat,
MetaTouchState *touch_state);
void meta_seat_native_set_stage (MetaSeatNative *seat,
ClutterStage *stage);
ClutterStage * meta_seat_native_get_stage (MetaSeatNative *seat);
void meta_seat_native_clear_repeat_timer (MetaSeatNative *seat);
gint meta_seat_native_acquire_device_id (MetaSeatNative *seat);
void meta_seat_native_release_device_id (MetaSeatNative *seat,
ClutterInputDevice *device);
void meta_seat_native_update_xkb_state (MetaSeatNative *seat);
void meta_seat_native_constrain_pointer (MetaSeatNative *seat,
ClutterInputDevice *core_pointer,
uint64_t time_us,
float x,
float y,
float *new_x,
float *new_y);
void meta_seat_native_filter_relative_motion (MetaSeatNative *seat,
ClutterInputDevice *device,
float x,
float y,
float *dx,
float *dy);
void meta_seat_native_dispatch (MetaSeatNative *seat);
/**
* MetaOpenDeviceCallback:
* @path: the device path
@ -264,30 +93,10 @@ void meta_seat_native_set_device_callbacks (MetaOpenDeviceCallback open_callba
void meta_seat_native_release_devices (MetaSeatNative *seat);
void meta_seat_native_reclaim_devices (MetaSeatNative *seat);
void meta_seat_native_set_pointer_constrain_callback (MetaSeatNative *seat,
MetaPointerConstrainCallback callback,
gpointer user_data,
GDestroyNotify user_data_notify);
void meta_seat_native_set_relative_motion_filter (MetaSeatNative *seat,
MetaRelativeMotionFilter filter,
gpointer user_data);
typedef gboolean (* MetaEvdevFilterFunc) (struct libinput_event *event,
gpointer data);
void meta_seat_native_add_filter (MetaSeatNative *seat,
MetaEvdevFilterFunc func,
gpointer data,
GDestroyNotify destroy_notify);
void meta_seat_native_remove_filter (MetaSeatNative *seat,
MetaEvdevFilterFunc func,
gpointer data);
struct xkb_state * meta_seat_native_get_xkb_state (MetaSeatNative *seat);
void meta_seat_native_set_keyboard_map (MetaSeatNative *seat,
struct xkb_keymap *keymap);
const char *layouts,
const char *variants,
const char *options);
struct xkb_keymap * meta_seat_native_get_keyboard_map (MetaSeatNative *seat);
@ -304,4 +113,17 @@ void meta_seat_native_set_keyboard_repeat (MetaSeatNative *seat,
uint32_t delay,
uint32_t interval);
MetaBarrierManagerNative * meta_seat_native_get_barrier_manager (MetaSeatNative *seat);
void meta_seat_native_set_pointer_constraint (MetaSeatNative *seat,
MetaPointerConstraintImpl *impl);
MetaCursorRenderer * meta_seat_native_get_cursor_renderer (MetaSeatNative *seat,
ClutterInputDevice *device);
void meta_seat_native_set_viewports (MetaSeatNative *seat,
MetaViewportInfo *viewports);
void meta_seat_native_notify_kbd_a11y_change (MetaSeatNative *seat,
MetaKeyboardA11yFlags new_flags,
MetaKeyboardA11yFlags what_changed);
#endif /* META_SEAT_NATIVE_H */

View File

@ -49,6 +49,45 @@ struct _MetaVirtualInputDeviceNative
int button_count[KEY_CNT];
};
typedef struct
{
uint64_t time_us;
double x;
double y;
} MetaVirtualEventMotion;
typedef struct
{
uint64_t time_us;
uint32_t button;
ClutterButtonState button_state;
} MetaVirtualEventButton;
typedef struct
{
uint64_t time_us;
double dx;
double dy;
ClutterScrollDirection direction;
ClutterScrollSource scroll_source;
ClutterScrollFinishFlags finish_flags;
} MetaVirtualEventScroll;
typedef struct
{
uint64_t time_us;
uint32_t key;
ClutterKeyState key_state;
} MetaVirtualEventKey;
typedef struct
{
uint64_t time_us;
int device_slot;
double x;
double y;
} MetaVirtualEventTouch;
G_DEFINE_TYPE (MetaVirtualInputDeviceNative,
meta_virtual_input_device_native,
CLUTTER_TYPE_VIRTUAL_INPUT_DEVICE)
@ -107,11 +146,10 @@ get_button_type (uint16_t code)
return EVDEV_BUTTON_TYPE_NONE;
}
static void
release_pressed_buttons (ClutterVirtualInputDevice *virtual_device)
static gboolean
release_device (GTask *task)
{
MetaVirtualInputDeviceNative *virtual_evdev =
META_VIRTUAL_INPUT_DEVICE_NATIVE (virtual_device);
MetaVirtualInputDeviceNative *virtual_evdev = g_task_get_task_data (task);
int code;
uint64_t time_us;
@ -119,7 +157,7 @@ release_pressed_buttons (ClutterVirtualInputDevice *virtual_device)
meta_topic (META_DEBUG_INPUT,
"Releasing pressed buttons while destroying virtual input device "
"(device %p)\n", virtual_device);
"(device %p)\n", virtual_evdev);
for (code = 0; code < G_N_ELEMENTS (virtual_evdev->button_count); code++)
{
@ -129,7 +167,7 @@ release_pressed_buttons (ClutterVirtualInputDevice *virtual_device)
switch (get_button_type (code))
{
case EVDEV_BUTTON_TYPE_KEY:
meta_seat_native_notify_key (virtual_evdev->seat,
meta_seat_impl_notify_key (virtual_evdev->seat->impl,
virtual_evdev->device,
time_us,
code,
@ -137,7 +175,7 @@ release_pressed_buttons (ClutterVirtualInputDevice *virtual_device)
TRUE);
break;
case EVDEV_BUTTON_TYPE_BUTTON:
meta_seat_native_notify_button (virtual_evdev->seat,
meta_seat_impl_notify_button (virtual_evdev->seat->impl,
virtual_evdev->device,
time_us,
code,
@ -149,6 +187,31 @@ release_pressed_buttons (ClutterVirtualInputDevice *virtual_device)
update_button_count (virtual_evdev, code, 0);
}
g_clear_object (&virtual_evdev->device);
g_task_return_boolean (task, TRUE);
return G_SOURCE_REMOVE;
}
static gboolean
notify_relative_motion (GTask *task)
{
MetaVirtualInputDeviceNative *virtual_evdev =
g_task_get_source_object (task);
MetaSeatImpl *seat = virtual_evdev->seat->impl;
MetaVirtualEventMotion *event = g_task_get_task_data (task);
if (event->time_us == CLUTTER_CURRENT_TIME)
event->time_us = g_get_monotonic_time ();
meta_seat_impl_notify_relative_motion (seat,
virtual_evdev->device,
event->time_us,
event->x, event->y,
event->x, event->y);
g_task_return_boolean (task, TRUE);
return G_SOURCE_REMOVE;
}
static void
@ -157,19 +220,43 @@ meta_virtual_input_device_native_notify_relative_motion (ClutterVirtualInputDevi
double dx,
double dy)
{
MetaVirtualEventMotion *event;
MetaVirtualInputDeviceNative *virtual_evdev =
META_VIRTUAL_INPUT_DEVICE_NATIVE (virtual_device);
GTask *task;
g_return_if_fail (virtual_evdev->device != NULL);
if (time_us == CLUTTER_CURRENT_TIME)
time_us = g_get_monotonic_time ();
event = g_new0 (MetaVirtualEventMotion, 1);
event->time_us = time_us;
event->x = dx;
event->y = dy;
meta_seat_native_notify_relative_motion (virtual_evdev->seat,
task = g_task_new (virtual_device, NULL, NULL, NULL);
g_task_set_task_data (task, event, g_free);
meta_seat_impl_run_input_task (virtual_evdev->seat->impl, task,
(GSourceFunc) notify_relative_motion);
g_object_unref (task);
}
static gboolean
notify_absolute_motion (GTask *task)
{
MetaVirtualInputDeviceNative *virtual_evdev =
g_task_get_source_object (task);
MetaSeatImpl *seat = virtual_evdev->seat->impl;
MetaVirtualEventMotion *event = g_task_get_task_data (task);
if (event->time_us == CLUTTER_CURRENT_TIME)
event->time_us = g_get_monotonic_time ();
meta_seat_impl_notify_absolute_motion (seat,
virtual_evdev->device,
time_us,
dx, dy,
dx, dy);
event->time_us,
event->x, event->y,
NULL);
g_task_return_boolean (task, TRUE);
return G_SOURCE_REMOVE;
}
static void
@ -178,19 +265,23 @@ meta_virtual_input_device_native_notify_absolute_motion (ClutterVirtualInputDevi
double x,
double y)
{
MetaVirtualEventMotion *event;
MetaVirtualInputDeviceNative *virtual_evdev =
META_VIRTUAL_INPUT_DEVICE_NATIVE (virtual_device);
GTask *task;
g_return_if_fail (virtual_evdev->device != NULL);
if (time_us == CLUTTER_CURRENT_TIME)
time_us = g_get_monotonic_time ();
event = g_new0 (MetaVirtualEventMotion, 1);
event->time_us = time_us;
event->x = x;
event->y = y;
meta_seat_native_notify_absolute_motion (virtual_evdev->seat,
virtual_evdev->device,
time_us,
x, y,
NULL);
task = g_task_new (virtual_device, NULL, NULL, NULL);
g_task_set_task_data (task, event, g_free);
meta_seat_impl_run_input_task (virtual_evdev->seat->impl, task,
(GSourceFunc) notify_absolute_motion);
g_object_unref (task);
}
static int
@ -213,50 +304,123 @@ translate_to_evdev_button (int clutter_button)
}
}
static gboolean
notify_button (GTask *task)
{
MetaVirtualInputDeviceNative *virtual_evdev =
g_task_get_source_object (task);
MetaSeatImpl *seat = virtual_evdev->seat->impl;
MetaVirtualEventButton *event = g_task_get_task_data (task);
int button_count;
int evdev_button;
if (event->time_us == CLUTTER_CURRENT_TIME)
event->time_us = g_get_monotonic_time ();
evdev_button = translate_to_evdev_button (event->button);
if (get_button_type (evdev_button) != EVDEV_BUTTON_TYPE_BUTTON)
{
g_warning ("Unknown/invalid virtual device button 0x%x pressed",
evdev_button);
goto out;
}
button_count = update_button_count (virtual_evdev, evdev_button,
event->button_state);
if (button_count < 0 || button_count > 1)
{
g_warning ("Received multiple virtual 0x%x button %s (ignoring)", evdev_button,
event->button_state == CLUTTER_BUTTON_STATE_PRESSED ?
"presses" : "releases");
update_button_count (virtual_evdev, evdev_button, 1 - event->button_state);
goto out;
}
meta_topic (META_DEBUG_INPUT,
"Emitting virtual button-%s of button 0x%x (device %p)\n",
event->button_state == CLUTTER_BUTTON_STATE_PRESSED ?
"press" : "release",
evdev_button, virtual_evdev);
meta_seat_impl_notify_button (seat,
virtual_evdev->device,
event->time_us,
evdev_button,
event->button_state);
out:
g_task_return_boolean (task, TRUE);
return G_SOURCE_REMOVE;
}
static void
meta_virtual_input_device_native_notify_button (ClutterVirtualInputDevice *virtual_device,
uint64_t time_us,
uint32_t button,
ClutterButtonState button_state)
{
MetaVirtualEventButton *event;
MetaVirtualInputDeviceNative *virtual_evdev =
META_VIRTUAL_INPUT_DEVICE_NATIVE (virtual_device);
int button_count;
int evdev_button;
GTask *task;
g_return_if_fail (virtual_evdev->device != NULL);
if (time_us == CLUTTER_CURRENT_TIME)
time_us = g_get_monotonic_time ();
event = g_new0 (MetaVirtualEventButton, 1);
event->time_us = time_us;
event->button = button;
event->button_state = button_state;
evdev_button = translate_to_evdev_button (button);
if (get_button_type (evdev_button) != EVDEV_BUTTON_TYPE_BUTTON)
{
g_warning ("Unknown/invalid virtual device button 0x%x pressed",
evdev_button);
return;
task = g_task_new (virtual_device, NULL, NULL, NULL);
g_task_set_task_data (task, event, g_free);
meta_seat_impl_run_input_task (virtual_evdev->seat->impl, task,
(GSourceFunc) notify_button);
g_object_unref (task);
}
button_count = update_button_count (virtual_evdev, evdev_button, button_state);
if (button_count < 0 || button_count > 1)
static gboolean
notify_key (GTask *task)
{
g_warning ("Received multiple virtual 0x%x button %s (ignoring)", evdev_button,
button_state == CLUTTER_BUTTON_STATE_PRESSED ? "presses" : "releases");
update_button_count (virtual_evdev, evdev_button, 1 - button_state);
return;
MetaVirtualInputDeviceNative *virtual_evdev =
g_task_get_source_object (task);
MetaSeatImpl *seat = virtual_evdev->seat->impl;
MetaVirtualEventKey *event = g_task_get_task_data (task);
int key_count;
if (event->time_us == CLUTTER_CURRENT_TIME)
event->time_us = g_get_monotonic_time ();
if (get_button_type (event->key) != EVDEV_BUTTON_TYPE_KEY)
{
g_warning ("Unknown/invalid virtual device key 0x%x pressed\n", event->key);
goto out;
}
key_count = update_button_count (virtual_evdev, event->key, event->key_state);
if (key_count < 0 || key_count > 1)
{
g_warning ("Received multiple virtual 0x%x key %s (ignoring)", event->key,
event->key_state == CLUTTER_KEY_STATE_PRESSED ?
"presses" : "releases");
update_button_count (virtual_evdev, event->key, 1 - event->key_state);
goto out;
}
meta_topic (META_DEBUG_INPUT,
"Emitting virtual button-%s of button 0x%x (device %p)\n",
button_state == CLUTTER_BUTTON_STATE_PRESSED ? "press" : "release",
evdev_button, virtual_device);
"Emitting virtual key-%s of key 0x%x (device %p)\n",
event->key_state == CLUTTER_KEY_STATE_PRESSED ? "press" : "release",
event->key, virtual_evdev);
meta_seat_native_notify_button (virtual_evdev->seat,
meta_seat_impl_notify_key (seat,
virtual_evdev->device,
time_us,
evdev_button,
button_state);
event->time_us,
event->key,
event->key_state,
TRUE);
out:
g_task_return_boolean (task, TRUE);
return G_SOURCE_REMOVE;
}
static void
@ -265,41 +429,23 @@ meta_virtual_input_device_native_notify_key (ClutterVirtualInputDevice *virtual_
uint32_t key,
ClutterKeyState key_state)
{
MetaVirtualEventKey *event;
MetaVirtualInputDeviceNative *virtual_evdev =
META_VIRTUAL_INPUT_DEVICE_NATIVE (virtual_device);
int key_count;
GTask *task;
g_return_if_fail (virtual_evdev->device != NULL);
if (time_us == CLUTTER_CURRENT_TIME)
time_us = g_get_monotonic_time ();
event = g_new0 (MetaVirtualEventKey, 1);
event->time_us = time_us;
event->key = key;
event->key_state = key_state;
if (get_button_type (key) != EVDEV_BUTTON_TYPE_KEY)
{
g_warning ("Unknown/invalid virtual device key 0x%x pressed\n", key);
return;
}
key_count = update_button_count (virtual_evdev, key, key_state);
if (key_count < 0 || key_count > 1)
{
g_warning ("Received multiple virtual 0x%x key %s (ignoring)", key,
key_state == CLUTTER_KEY_STATE_PRESSED ? "presses" : "releases");
update_button_count (virtual_evdev, key, 1 - key_state);
return;
}
meta_topic (META_DEBUG_INPUT,
"Emitting virtual key-%s of key 0x%x (device %p)\n",
key_state == CLUTTER_KEY_STATE_PRESSED ? "press" : "release",
key, virtual_device);
meta_seat_native_notify_key (virtual_evdev->seat,
virtual_evdev->device,
time_us,
key,
key_state,
TRUE);
task = g_task_new (virtual_device, NULL, NULL, NULL);
g_task_set_task_data (task, event, g_free);
meta_seat_impl_run_input_task (virtual_evdev->seat->impl, task,
(GSourceFunc) notify_key);
g_object_unref (task);
}
static gboolean
@ -320,7 +466,7 @@ pick_keycode_for_keyval_in_current_group (ClutterVirtualInputDevice *virtual_dev
backend = clutter_get_default_backend ();
keymap = clutter_seat_get_keymap (clutter_backend_get_default_seat (backend));
xkb_keymap = meta_keymap_native_get_keyboard_map (META_KEYMAP_NATIVE (keymap));
state = virtual_evdev->seat->xkb;
state = meta_seat_impl_get_xkb_state (virtual_evdev->seat->impl);
layout = xkb_state_serialize_layout (state, XKB_STATE_LAYOUT_EFFECTIVE);
min_keycode = xkb_keymap_min_keycode (xkb_keymap);
@ -389,7 +535,7 @@ apply_level_modifiers (ClutterVirtualInputDevice *virtual_device,
key_state == CLUTTER_KEY_STATE_PRESSED ? "press" : "release",
evcode, virtual_device);
meta_seat_native_notify_key (virtual_evdev->seat,
meta_seat_impl_notify_key (virtual_evdev->seat->impl,
virtual_evdev->device,
time_us,
evcode,
@ -397,27 +543,26 @@ apply_level_modifiers (ClutterVirtualInputDevice *virtual_device,
TRUE);
}
static void
meta_virtual_input_device_native_notify_keyval (ClutterVirtualInputDevice *virtual_device,
uint64_t time_us,
uint32_t keyval,
ClutterKeyState key_state)
static gboolean
notify_keyval (GTask *task)
{
MetaVirtualInputDeviceNative *virtual_evdev =
META_VIRTUAL_INPUT_DEVICE_NATIVE (virtual_device);
g_task_get_source_object (task);
ClutterVirtualInputDevice *virtual_device =
CLUTTER_VIRTUAL_INPUT_DEVICE (virtual_evdev);
MetaSeatImpl *seat = virtual_evdev->seat->impl;
MetaVirtualEventKey *event = g_task_get_task_data (task);
int key_count;
guint keycode = 0, level = 0, evcode = 0;
g_return_if_fail (virtual_evdev->device != NULL);
if (time_us == CLUTTER_CURRENT_TIME)
time_us = g_get_monotonic_time ();
if (event->time_us == CLUTTER_CURRENT_TIME)
event->time_us = g_get_monotonic_time ();
if (!pick_keycode_for_keyval_in_current_group (virtual_device,
keyval, &keycode, &level))
event->key, &keycode, &level))
{
g_warning ("No keycode found for keyval %x in current group", keyval);
return;
g_warning ("No keycode found for keyval %x in current group", event->key);
goto out;
}
clutter_input_device_keycode_to_evdev (virtual_evdev->device,
@ -426,36 +571,66 @@ meta_virtual_input_device_native_notify_keyval (ClutterVirtualInputDevice *virtu
if (get_button_type (evcode) != EVDEV_BUTTON_TYPE_KEY)
{
g_warning ("Unknown/invalid virtual device key 0x%x pressed\n", evcode);
return;
goto out;
}
key_count = update_button_count (virtual_evdev, evcode, key_state);
key_count = update_button_count (virtual_evdev, evcode, event->key_state);
if (key_count < 0 || key_count > 1)
{
g_warning ("Received multiple virtual 0x%x key %s (ignoring)", evcode,
key_state == CLUTTER_KEY_STATE_PRESSED ? "presses" : "releases");
update_button_count (virtual_evdev, evcode, 1 - key_state);
return;
event->key_state == CLUTTER_KEY_STATE_PRESSED ?
"presses" : "releases");
update_button_count (virtual_evdev, evcode, 1 - event->key_state);
goto out;
}
meta_topic (META_DEBUG_INPUT,
"Emitting virtual key-%s of key 0x%x with modifier level %d, "
"press count %d (device %p)\n",
key_state == CLUTTER_KEY_STATE_PRESSED ? "press" : "release",
evcode, level, key_count, virtual_device);
event->key_state == CLUTTER_KEY_STATE_PRESSED ? "press" : "release",
evcode, level, key_count, virtual_evdev);
if (key_state)
apply_level_modifiers (virtual_device, time_us, level, key_state);
if (event->key_state)
apply_level_modifiers (virtual_device, event->time_us, level, event->key_state);
meta_seat_native_notify_key (virtual_evdev->seat,
meta_seat_impl_notify_key (seat,
virtual_evdev->device,
time_us,
event->time_us,
evcode,
key_state,
event->key_state,
TRUE);
if (!key_state)
apply_level_modifiers (virtual_device, time_us, level, key_state);
if (!event->key_state)
apply_level_modifiers (virtual_device, event->time_us, level, event->key_state);
out:
g_task_return_boolean (task, TRUE);
return G_SOURCE_REMOVE;
}
static void
meta_virtual_input_device_native_notify_keyval (ClutterVirtualInputDevice *virtual_device,
uint64_t time_us,
uint32_t keyval,
ClutterKeyState key_state)
{
MetaVirtualEventKey *event;
MetaVirtualInputDeviceNative *virtual_evdev =
META_VIRTUAL_INPUT_DEVICE_NATIVE (virtual_device);
GTask *task;
g_return_if_fail (virtual_evdev->device != NULL);
event = g_new0 (MetaVirtualEventKey, 1);
event->time_us = time_us;
event->key = keyval;
event->key_state = key_state;
task = g_task_new (virtual_device, NULL, NULL, NULL);
g_task_set_task_data (task, event, g_free);
meta_seat_impl_run_input_task (virtual_evdev->seat->impl, task,
(GSourceFunc) notify_keyval);
g_object_unref (task);
}
static void
@ -487,28 +662,74 @@ direction_to_discrete (ClutterScrollDirection direction,
}
}
static gboolean
notify_discrete_scroll (GTask *task)
{
MetaVirtualInputDeviceNative *virtual_evdev =
g_task_get_source_object (task);
MetaSeatImpl *seat = virtual_evdev->seat->impl;
MetaVirtualEventScroll *event = g_task_get_task_data (task);
double discrete_dx = 0.0, discrete_dy = 0.0;
if (event->time_us == CLUTTER_CURRENT_TIME)
event->time_us = g_get_monotonic_time ();
direction_to_discrete (event->direction, &discrete_dx, &discrete_dy);
meta_seat_impl_notify_discrete_scroll (seat,
virtual_evdev->device,
event->time_us,
discrete_dx, discrete_dy,
event->scroll_source);
g_task_return_boolean (task, TRUE);
return G_SOURCE_REMOVE;
}
static void
meta_virtual_input_device_native_notify_discrete_scroll (ClutterVirtualInputDevice *virtual_device,
uint64_t time_us,
ClutterScrollDirection direction,
ClutterScrollSource scroll_source)
{
MetaVirtualEventScroll *event;
MetaVirtualInputDeviceNative *virtual_evdev =
META_VIRTUAL_INPUT_DEVICE_NATIVE (virtual_device);
double discrete_dx = 0.0, discrete_dy = 0.0;
GTask *task;
g_return_if_fail (virtual_evdev->device != NULL);
if (time_us == CLUTTER_CURRENT_TIME)
time_us = g_get_monotonic_time ();
event = g_new0 (MetaVirtualEventScroll, 1);
event->time_us = time_us;
event->direction = direction;
event->scroll_source = scroll_source;
direction_to_discrete (direction, &discrete_dx, &discrete_dy);
task = g_task_new (virtual_device, NULL, NULL, NULL);
g_task_set_task_data (task, event, g_free);
meta_seat_impl_run_input_task (virtual_evdev->seat->impl, task,
(GSourceFunc) notify_discrete_scroll);
g_object_unref (task);
}
meta_seat_native_notify_discrete_scroll (virtual_evdev->seat,
static gboolean
notify_scroll_continuous (GTask *task)
{
MetaVirtualInputDeviceNative *virtual_evdev =
g_task_get_source_object (task);
MetaSeatImpl *seat = virtual_evdev->seat->impl;
MetaVirtualEventScroll *event = g_task_get_task_data (task);
if (event->time_us == CLUTTER_CURRENT_TIME)
event->time_us = g_get_monotonic_time ();
meta_seat_impl_notify_scroll_continuous (seat,
virtual_evdev->device,
time_us,
discrete_dx, discrete_dy,
scroll_source);
event->time_us,
event->dx, event->dy,
event->scroll_source,
CLUTTER_SCROLL_FINISHED_NONE);
g_task_return_boolean (task, TRUE);
return G_SOURCE_REMOVE;
}
static void
@ -519,20 +740,58 @@ meta_virtual_input_device_native_notify_scroll_continuous (ClutterVirtualInputDe
ClutterScrollSource scroll_source,
ClutterScrollFinishFlags finish_flags)
{
MetaVirtualEventScroll *event;
MetaVirtualInputDeviceNative *virtual_evdev =
META_VIRTUAL_INPUT_DEVICE_NATIVE (virtual_device);
GTask *task;
g_return_if_fail (virtual_evdev->device != NULL);
if (time_us == CLUTTER_CURRENT_TIME)
time_us = g_get_monotonic_time ();
event = g_new0 (MetaVirtualEventScroll, 1);
event->time_us = time_us;
event->dx = dx;
event->dy = dy;
event->scroll_source = scroll_source;
event->finish_flags = finish_flags;
meta_seat_native_notify_scroll_continuous (virtual_evdev->seat,
task = g_task_new (virtual_device, NULL, NULL, NULL);
g_task_set_task_data (task, event, g_free);
meta_seat_impl_run_input_task (virtual_evdev->seat->impl, task,
(GSourceFunc) notify_scroll_continuous);
g_object_unref (task);
}
static gboolean
notify_touch_down (GTask *task)
{
MetaVirtualInputDeviceNative *virtual_evdev =
g_task_get_source_object (task);
MetaSeatImpl *seat = virtual_evdev->seat->impl;
MetaVirtualEventTouch *event = g_task_get_task_data (task);
MetaTouchState *touch_state;
if (event->time_us == CLUTTER_CURRENT_TIME)
event->time_us = g_get_monotonic_time ();
touch_state = meta_seat_impl_acquire_touch_state (seat,
event->device_slot);
if (!touch_state)
goto out;
touch_state->coords.x = event->x;
touch_state->coords.y = event->y;
meta_seat_impl_notify_touch_event (seat,
virtual_evdev->device,
time_us,
dx, dy,
scroll_source,
CLUTTER_SCROLL_FINISHED_NONE);
CLUTTER_TOUCH_BEGIN,
event->time_us,
touch_state->seat_slot,
touch_state->coords.x,
touch_state->coords.y);
out:
g_task_return_boolean (task, TRUE);
return G_SOURCE_REMOVE;
}
static void
@ -542,32 +801,57 @@ meta_virtual_input_device_native_notify_touch_down (ClutterVirtualInputDevice *v
double x,
double y)
{
MetaVirtualEventTouch *event;
MetaVirtualInputDeviceNative *virtual_evdev =
META_VIRTUAL_INPUT_DEVICE_NATIVE (virtual_device);
MetaInputDeviceNative *device_evdev =
META_INPUT_DEVICE_NATIVE (virtual_evdev->device);
MetaTouchState *touch_state;
GTask *task;
g_return_if_fail (virtual_evdev->device != NULL);
if (time_us == CLUTTER_CURRENT_TIME)
time_us = g_get_monotonic_time ();
event = g_new0 (MetaVirtualEventTouch, 1);
event->time_us = time_us;
event->device_slot = device_slot;
event->x = x;
event->y = y;
touch_state = meta_input_device_native_acquire_touch_state (device_evdev,
device_slot);
task = g_task_new (virtual_device, NULL, NULL, NULL);
g_task_set_task_data (task, event, g_free);
meta_seat_impl_run_input_task (virtual_evdev->seat->impl, task,
(GSourceFunc) notify_touch_down);
g_object_unref (task);
}
static gboolean
notify_touch_motion (GTask *task)
{
MetaVirtualInputDeviceNative *virtual_evdev =
g_task_get_source_object (task);
MetaSeatImpl *seat = virtual_evdev->seat->impl;
MetaVirtualEventTouch *event = g_task_get_task_data (task);
MetaTouchState *touch_state;
if (event->time_us == CLUTTER_CURRENT_TIME)
event->time_us = g_get_monotonic_time ();
touch_state = meta_seat_impl_lookup_touch_state (seat,
event->device_slot);
if (!touch_state)
return;
goto out;
touch_state->coords.x = x;
touch_state->coords.y = y;
touch_state->coords.x = event->x;
touch_state->coords.y = event->y;
meta_seat_native_notify_touch_event (virtual_evdev->seat,
meta_seat_impl_notify_touch_event (seat,
virtual_evdev->device,
CLUTTER_TOUCH_BEGIN,
time_us,
CLUTTER_TOUCH_UPDATE,
event->time_us,
touch_state->seat_slot,
touch_state->coords.x,
touch_state->coords.y);
out:
g_task_return_boolean (task, TRUE);
return G_SOURCE_REMOVE;
}
static void
@ -577,32 +861,57 @@ meta_virtual_input_device_native_notify_touch_motion (ClutterVirtualInputDevice
double x,
double y)
{
MetaVirtualEventTouch *event;
MetaVirtualInputDeviceNative *virtual_evdev =
META_VIRTUAL_INPUT_DEVICE_NATIVE (virtual_device);
MetaInputDeviceNative *device_evdev =
META_INPUT_DEVICE_NATIVE (virtual_evdev->device);
MetaTouchState *touch_state;
GTask *task;
g_return_if_fail (virtual_evdev->device != NULL);
if (time_us == CLUTTER_CURRENT_TIME)
time_us = g_get_monotonic_time ();
event = g_new0 (MetaVirtualEventTouch, 1);
event->time_us = time_us;
event->device_slot = device_slot;
event->x = x;
event->y = y;
touch_state = meta_input_device_native_lookup_touch_state (device_evdev,
device_slot);
task = g_task_new (virtual_device, NULL, NULL, NULL);
g_task_set_task_data (task, event, g_free);
meta_seat_impl_run_input_task (virtual_evdev->seat->impl, task,
(GSourceFunc) notify_touch_motion);
g_object_unref (task);
}
static gboolean
notify_touch_up (GTask *task)
{
MetaVirtualInputDeviceNative *virtual_evdev =
g_task_get_source_object (task);
MetaSeatImpl *seat = virtual_evdev->seat->impl;
MetaVirtualEventTouch *event = g_task_get_task_data (task);
MetaTouchState *touch_state;
if (event->time_us == CLUTTER_CURRENT_TIME)
event->time_us = g_get_monotonic_time ();
touch_state = meta_seat_impl_lookup_touch_state (seat,
event->device_slot);
if (!touch_state)
return;
goto out;
touch_state->coords.x = x;
touch_state->coords.y = y;
meta_seat_native_notify_touch_event (virtual_evdev->seat,
meta_seat_impl_notify_touch_event (seat,
virtual_evdev->device,
CLUTTER_TOUCH_BEGIN,
time_us,
CLUTTER_TOUCH_END,
event->time_us,
touch_state->seat_slot,
touch_state->coords.x,
touch_state->coords.y);
meta_seat_impl_release_touch_state (virtual_evdev->seat->impl,
touch_state->seat_slot);
out:
g_task_return_boolean (task, TRUE);
return G_SOURCE_REMOVE;
}
static void
@ -610,31 +919,22 @@ meta_virtual_input_device_native_notify_touch_up (ClutterVirtualInputDevice *vir
uint64_t time_us,
int device_slot)
{
MetaVirtualEventTouch *event;
MetaVirtualInputDeviceNative *virtual_evdev =
META_VIRTUAL_INPUT_DEVICE_NATIVE (virtual_device);
MetaInputDeviceNative *device_evdev =
META_INPUT_DEVICE_NATIVE (virtual_evdev->device);
MetaTouchState *touch_state;
GTask *task;
g_return_if_fail (virtual_evdev->device != NULL);
if (time_us == CLUTTER_CURRENT_TIME)
time_us = g_get_monotonic_time ();
event = g_new0 (MetaVirtualEventTouch, 1);
event->time_us = time_us;
event->device_slot = device_slot;
touch_state = meta_input_device_native_lookup_touch_state (device_evdev,
device_slot);
if (!touch_state)
return;
meta_seat_native_notify_touch_event (virtual_evdev->seat,
virtual_evdev->device,
CLUTTER_TOUCH_BEGIN,
time_us,
touch_state->seat_slot,
touch_state->coords.x,
touch_state->coords.y);
meta_input_device_native_release_touch_state (device_evdev, touch_state);
task = g_task_new (virtual_device, NULL, NULL, NULL);
g_task_set_task_data (task, event, g_free);
meta_seat_impl_run_input_task (virtual_evdev->seat->impl, task,
(GSourceFunc) notify_touch_up);
g_object_unref (task);
}
static void
@ -685,7 +985,6 @@ meta_virtual_input_device_native_constructed (GObject *object)
MetaVirtualInputDeviceNative *virtual_evdev =
META_VIRTUAL_INPUT_DEVICE_NATIVE (object);
ClutterInputDeviceType device_type;
ClutterStage *stage;
device_type = clutter_virtual_input_device_get_device_type (virtual_device);
@ -694,16 +993,9 @@ meta_virtual_input_device_native_constructed (GObject *object)
device_type, virtual_device);
virtual_evdev->device =
meta_input_device_native_new_virtual (virtual_evdev->seat,
meta_input_device_native_new_virtual (virtual_evdev->seat->impl,
device_type,
CLUTTER_INPUT_MODE_SLAVE);
stage = meta_seat_native_get_stage (virtual_evdev->seat);
_clutter_input_device_set_stage (virtual_evdev->device, stage);
g_signal_emit_by_name (virtual_evdev->seat,
"device-added",
virtual_evdev->device);
}
static void
@ -718,12 +1010,13 @@ meta_virtual_input_device_native_dispose (GObject *object)
if (virtual_evdev->device)
{
release_pressed_buttons (virtual_device);
g_signal_emit_by_name (virtual_evdev->seat,
"device-removed",
virtual_evdev->device);
GTask *task;
g_clear_object (&virtual_evdev->device);
task = g_task_new (virtual_device, NULL, NULL, NULL);
g_task_set_task_data (task, g_object_ref (virtual_device), g_object_unref);
meta_seat_impl_run_input_task (virtual_evdev->seat->impl, task,
(GSourceFunc) release_device);
g_object_unref (task);
}
object_class->dispose (object);

View File

@ -28,7 +28,6 @@
/*
* _clutter_event_new_from_evdev: Create a new Clutter ClutterKeyEvent
* @device: a ClutterInputDevice
* @stage: the stage the event should be delivered to
* @xkb: XKB rules to translate the event
* @_time: timestamp of the event
* @key: a key code coming from a Linux input device
@ -42,7 +41,6 @@
ClutterEvent *
meta_key_event_new_from_evdev (ClutterInputDevice *device,
ClutterInputDevice *core_device,
ClutterStage *stage,
struct xkb_state *xkb_state,
uint32_t button_state,
uint32_t _time,
@ -72,7 +70,6 @@ meta_key_event_new_from_evdev (ClutterInputDevice *device,
else
sym = XKB_KEY_NoSymbol;
event->key.stage = stage;
event->key.time = _time;
meta_xkb_translate_state (event, xkb_state, button_state);
event->key.hardware_keycode = key;
@ -109,3 +106,10 @@ meta_xkb_translate_state (ClutterEvent *event,
xkb_state_serialize_mods (state, XKB_STATE_MODS_LOCKED),
xkb_state_serialize_mods (state, XKB_STATE_MODS_EFFECTIVE) | button_state);
}
uint32_t
meta_xkb_translate_modifiers (struct xkb_state *state,
uint32_t button_state)
{
return xkb_state_serialize_mods (state, XKB_STATE_MODS_EFFECTIVE) | button_state;
}

View File

@ -27,7 +27,6 @@
ClutterEvent * meta_key_event_new_from_evdev (ClutterInputDevice *device,
ClutterInputDevice *core_keyboard,
ClutterStage *stage,
struct xkb_state *xkb_state,
uint32_t button_state,
uint32_t _time,
@ -36,5 +35,7 @@ ClutterEvent * meta_key_event_new_from_evdev (ClutterInputDevice *device,
void meta_xkb_translate_state (ClutterEvent *event,
struct xkb_state *xkb_state,
uint32_t button_state);
uint32_t meta_xkb_translate_modifiers (struct xkb_state *state,
uint32_t button_state);
#endif /* META_XKB_UTILS_H */

View File

@ -41,6 +41,7 @@ struct _MetaBackendX11Cm
{
MetaBackendX11 parent;
MetaCursorRenderer *cursor_renderer;
char *keymap_layouts;
char *keymap_variants;
char *keymap_options;
@ -116,13 +117,23 @@ meta_backend_x11_cm_create_monitor_manager (MetaBackend *backend,
}
static MetaCursorRenderer *
meta_backend_x11_cm_create_cursor_renderer (MetaBackend *backend)
meta_backend_x11_cm_get_cursor_renderer (MetaBackend *backend,
ClutterInputDevice *device)
{
return g_object_new (META_TYPE_CURSOR_RENDERER_X11,
MetaBackendX11Cm *x11_cm = META_BACKEND_X11_CM (backend);
if (!x11_cm->cursor_renderer)
{
x11_cm->cursor_renderer =
g_object_new (META_TYPE_CURSOR_RENDERER_X11,
"backend", backend,
"device", device,
NULL);
}
return x11_cm->cursor_renderer;
}
static MetaCursorTracker *
meta_backend_x11_cm_create_cursor_tracker (MetaBackend *backend)
{
@ -444,7 +455,7 @@ meta_backend_x11_cm_class_init (MetaBackendX11CmClass *klass)
backend_class->post_init = meta_backend_x11_cm_post_init;
backend_class->create_renderer = meta_backend_x11_cm_create_renderer;
backend_class->create_monitor_manager = meta_backend_x11_cm_create_monitor_manager;
backend_class->create_cursor_renderer = meta_backend_x11_cm_create_cursor_renderer;
backend_class->get_cursor_renderer = meta_backend_x11_cm_get_cursor_renderer;
backend_class->create_cursor_tracker = meta_backend_x11_cm_create_cursor_tracker;
backend_class->create_input_settings = meta_backend_x11_cm_create_input_settings;
backend_class->update_screen_size = meta_backend_x11_cm_update_screen_size;

View File

@ -50,6 +50,7 @@
#include "backends/x11/meta-seat-x11.h"
#include "backends/x11/meta-stage-x11.h"
#include "backends/x11/meta-renderer-x11.h"
#include "backends/x11/meta-xkb-a11y-x11.h"
#include "clutter/clutter.h"
#include "clutter/x11/clutter-x11.h"
#include "compositor/compositor-private.h"
@ -519,12 +520,24 @@ on_monitors_changed (MetaMonitorManager *manager,
priv->cached_current_logical_monitor = NULL;
}
static void
on_kbd_a11y_changed (MetaInputSettings *input_settings,
MetaKbdA11ySettings *a11y_settings,
MetaBackend *backend)
{
ClutterBackend *clutter_backend = meta_backend_get_clutter_backend (backend);
ClutterSeat *seat = clutter_backend_get_default_seat (clutter_backend);
meta_seat_x11_apply_kbd_a11y_settings (seat, a11y_settings);
}
static void
meta_backend_x11_post_init (MetaBackend *backend)
{
MetaBackendX11 *x11 = META_BACKEND_X11 (backend);
MetaBackendX11Private *priv = meta_backend_x11_get_instance_private (x11);
MetaMonitorManager *monitor_manager;
MetaInputSettings *input_settings;
int major, minor;
gboolean has_xi = FALSE;
@ -577,6 +590,15 @@ meta_backend_x11_post_init (MetaBackend *backend)
priv->touch_replay_sync_atom = XInternAtom (priv->xdisplay,
"_MUTTER_TOUCH_SEQUENCE_SYNC",
False);
input_settings = meta_backend_get_input_settings (backend);
if (input_settings)
{
g_signal_connect_object (meta_backend_get_input_settings (backend),
"kbd-a11y-changed",
G_CALLBACK (on_kbd_a11y_changed), backend, 0);
}
}
static ClutterBackend *
@ -677,7 +699,7 @@ meta_backend_x11_get_current_logical_monitor (MetaBackend *backend)
MetaBackendX11 *x11 = META_BACKEND_X11 (backend);
MetaBackendX11Private *priv = meta_backend_x11_get_instance_private (x11);
MetaCursorTracker *cursor_tracker;
int x, y;
graphene_point_t point;
MetaMonitorManager *monitor_manager;
MetaLogicalMonitor *logical_monitor;
@ -685,10 +707,11 @@ meta_backend_x11_get_current_logical_monitor (MetaBackend *backend)
return priv->cached_current_logical_monitor;
cursor_tracker = meta_backend_get_cursor_tracker (backend);
meta_cursor_tracker_get_pointer (cursor_tracker, &x, &y, NULL);
meta_cursor_tracker_get_pointer (cursor_tracker, &point, NULL);
monitor_manager = meta_backend_get_monitor_manager (backend);
logical_monitor =
meta_monitor_manager_get_logical_monitor_at (monitor_manager, x, y);
meta_monitor_manager_get_logical_monitor_at (monitor_manager,
point.x, point.y);
if (!logical_monitor && monitor_manager->logical_monitors)
logical_monitor = monitor_manager->logical_monitors->data;

View File

@ -69,10 +69,8 @@ static void
update_position (MetaCursorTrackerX11 *tracker_x11)
{
MetaCursorTracker *tracker = META_CURSOR_TRACKER (tracker_x11);
int x, y;
meta_cursor_tracker_get_pointer (tracker, &x, &y, NULL);
meta_cursor_tracker_update_position (tracker, x, y);
meta_cursor_tracker_update_position (tracker);
}
static gboolean

View File

@ -35,7 +35,6 @@
#include <gudev/gudev.h>
#endif
#include "backends/meta-logical-monitor.h"
#include "backends/x11/meta-backend-x11.h"
#include "core/display-private.h"
#include "meta/meta-x11-errors.h"
@ -665,15 +664,6 @@ meta_input_settings_x11_set_tablet_mapping (MetaInputSettings *settings,
g_warning ("Could not set tablet mapping for %s",
clutter_input_device_get_device_name (device));
}
else
{
ClutterInputDeviceMapping dev_mapping;
dev_mapping = (mapping == G_DESKTOP_TABLET_MAPPING_ABSOLUTE) ?
CLUTTER_INPUT_DEVICE_MAPPING_ABSOLUTE :
CLUTTER_INPUT_DEVICE_MAPPING_RELATIVE;
clutter_input_device_set_mapping_mode (device, dev_mapping);
}
}
static gboolean
@ -750,37 +740,19 @@ meta_input_settings_x11_set_tablet_area (MetaInputSettings *settings,
}
static void
meta_input_settings_x11_set_tablet_keep_aspect (MetaInputSettings *settings,
meta_input_settings_x11_set_tablet_aspect_ratio (MetaInputSettings *settings,
ClutterInputDevice *device,
MetaLogicalMonitor *logical_monitor,
gboolean keep_aspect)
gdouble aspect_ratio)
{
gint32 width, height, dev_x, dev_y, dev_width, dev_height, area[4] = { 0 };
gint32 dev_x, dev_y, dev_width, dev_height, area[4] = { 0 };
if (!device_query_area (device, &dev_x, &dev_y, &dev_width, &dev_height))
return;
if (keep_aspect)
if (aspect_ratio > 0)
{
double aspect_ratio, dev_aspect;
double dev_aspect;
if (logical_monitor)
{
width = logical_monitor->rect.width;
height = logical_monitor->rect.height;
}
else
{
MetaMonitorManager *monitor_manager;
MetaBackend *backend;
backend = meta_get_backend ();
monitor_manager = meta_backend_get_monitor_manager (backend);
meta_monitor_manager_get_screen_size (monitor_manager,
&width, &height);
}
aspect_ratio = (double) width / height;
dev_aspect = (double) dev_width / dev_height;
if (dev_aspect > aspect_ratio)
@ -952,7 +924,7 @@ meta_input_settings_x11_class_init (MetaInputSettingsX11Class *klass)
input_settings_class->set_keyboard_repeat = meta_input_settings_x11_set_keyboard_repeat;
input_settings_class->set_tablet_mapping = meta_input_settings_x11_set_tablet_mapping;
input_settings_class->set_tablet_keep_aspect = meta_input_settings_x11_set_tablet_keep_aspect;
input_settings_class->set_tablet_aspect_ratio = meta_input_settings_x11_set_tablet_aspect_ratio;
input_settings_class->set_tablet_area = meta_input_settings_x11_set_tablet_area;
input_settings_class->set_mouse_accel_profile = meta_input_settings_x11_set_mouse_accel_profile;

View File

@ -20,6 +20,8 @@
#include <X11/extensions/XInput2.h>
#include "backends/meta-input-settings-private.h"
#include "backends/x11/meta-backend-x11.h"
#include "backends/x11/meta-event-x11.h"
#include "backends/x11/meta-input-device-tool-x11.h"
#include "backends/x11/meta-input-device-x11.h"
@ -44,6 +46,15 @@ enum
PROP_TOUCH_MODE,
};
typedef struct _MetaTouchInfo MetaTouchInfo;
struct _MetaTouchInfo
{
ClutterEventSequence *sequence;
double x;
double y;
};
struct _MetaSeatX11
{
ClutterSeat parent_instance;
@ -52,6 +63,7 @@ struct _MetaSeatX11
GList *devices;
GHashTable *devices_by_id;
GHashTable *tools_by_serial;
GHashTable *touch_coords;
MetaKeymapX11 *keymap;
int pointer_id;
@ -462,7 +474,6 @@ create_device (MetaSeatX11 *seat_x11,
ClutterInputDeviceType source, touch_source;
ClutterInputDevice *retval;
ClutterInputMode mode;
gboolean is_enabled;
uint32_t num_touches = 0, num_rings = 0, num_strips = 0;
char *vendor_id = NULL, *product_id = NULL, *node_path = NULL;
@ -508,19 +519,16 @@ create_device (MetaSeatX11 *seat_x11,
case XIMasterKeyboard:
case XIMasterPointer:
mode = CLUTTER_INPUT_MODE_MASTER;
is_enabled = TRUE;
break;
case XISlaveKeyboard:
case XISlavePointer:
mode = CLUTTER_INPUT_MODE_SLAVE;
is_enabled = FALSE;
break;
case XIFloatingSlave:
default:
mode = CLUTTER_INPUT_MODE_FLOATING;
is_enabled = FALSE;
break;
}
@ -532,10 +540,7 @@ create_device (MetaSeatX11 *seat_x11,
}
if (source == CLUTTER_PAD_DEVICE)
{
is_enabled = TRUE;
get_pad_features (info, &num_rings, &num_strips);
}
retval = g_object_new (META_TYPE_INPUT_DEVICE_X11,
"name", info->name,
@ -544,7 +549,6 @@ create_device (MetaSeatX11 *seat_x11,
"device-type", source,
"device-mode", mode,
"backend", backend,
"enabled", is_enabled,
"vendor-id", vendor_id,
"product-id", product_id,
"device-node", node_path,
@ -654,8 +658,6 @@ add_device (MetaSeatX11 *seat_x11,
info->attachment == seat_x11->keyboard_id))
{
seat_x11->devices = g_list_prepend (seat_x11->devices, device);
seat_x11->has_touchscreens |=
clutter_input_device_get_device_type (device) == CLUTTER_TOUCHSCREEN_DEVICE;
}
else
{
@ -679,13 +681,9 @@ add_device (MetaSeatX11 *seat_x11,
GINT_TO_POINTER (info->attachment));
_clutter_input_device_set_associated_device (device, master);
_clutter_input_device_add_slave (master, device);
g_signal_emit_by_name (seat_x11, "device-added", device);
}
}
update_touch_mode (seat_x11);
return device;
}
@ -705,18 +703,7 @@ has_touchscreens (MetaSeatX11 *seat_x11)
static void
remove_device (MetaSeatX11 *seat_x11,
int device_id)
{
ClutterInputDevice *device;
gboolean check_touchscreens = FALSE;
device = g_hash_table_lookup (seat_x11->devices_by_id,
GINT_TO_POINTER (device_id));
if (clutter_input_device_get_device_type (device) == CLUTTER_TOUCHSCREEN_DEVICE)
check_touchscreens = TRUE;
if (device != NULL)
ClutterInputDevice *device)
{
if (seat_x11->core_pointer == device)
{
@ -729,19 +716,41 @@ remove_device (MetaSeatX11 *seat_x11,
else
{
seat_x11->devices = g_list_remove (seat_x11->devices, device);
g_signal_emit_by_name (seat_x11, "device-removed", device);
}
}
g_object_run_dispose (G_OBJECT (device));
g_hash_table_remove (seat_x11->devices_by_id,
GINT_TO_POINTER (device_id));
}
if (check_touchscreens)
static gboolean
meta_seat_x11_handle_event_post (ClutterSeat *seat,
const ClutterEvent *event)
{
MetaSeatX11 *seat_x11 = META_SEAT_X11 (seat);
ClutterInputDevice *device = event->device.device;
MetaInputSettings *input_settings;
gboolean is_touch;
is_touch =
clutter_input_device_get_device_type (device) == CLUTTER_TOUCHSCREEN_DEVICE;
input_settings = meta_backend_get_input_settings (meta_get_backend ());
switch (event->type)
{
case CLUTTER_DEVICE_ADDED:
meta_input_settings_add_device (input_settings, device);
seat_x11->has_touchscreens |= is_touch;
break;
case CLUTTER_DEVICE_REMOVED:
if (is_touch)
seat_x11->has_touchscreens = has_touchscreens (seat_x11);
update_touch_mode (seat_x11);
meta_input_settings_remove_device (input_settings, device);
break;
default:
break;
}
if (is_touch)
update_touch_mode (seat_x11);
return TRUE;
}
static void
@ -803,12 +812,14 @@ device_get_tool_serial (ClutterInputDevice *device)
return serial_id;
}
static void
static gboolean
translate_hierarchy_event (ClutterBackend *backend,
MetaSeatX11 *seat_x11,
XIHierarchyEvent *ev)
XIHierarchyEvent *ev,
ClutterEvent *event)
{
int i;
gboolean retval = FALSE;
for (i = 0; i < ev->num_info; i++)
{
@ -828,15 +839,38 @@ translate_hierarchy_event (ClutterBackend *backend,
clutter_x11_untrap_x_errors ();
if (info != NULL)
{
add_device (seat_x11, backend, &info[0], FALSE);
ClutterInputDevice *device;
device = add_device (seat_x11, backend, &info[0], FALSE);
event->any.type = CLUTTER_DEVICE_ADDED;
event->any.time = ev->time;
clutter_event_set_device (event, device);
retval = TRUE;
XIFreeDeviceInfo (info);
}
}
else if (ev->info[i].flags & XIDeviceDisabled)
{
g_autoptr (ClutterInputDevice) device = NULL;
g_debug ("Hierarchy event: device disabled");
remove_device (seat_x11, ev->info[i].deviceid);
g_hash_table_steal_extended (seat_x11->devices_by_id,
GINT_TO_POINTER (ev->info[i].deviceid),
NULL,
(gpointer) &device);
if (device != NULL)
{
remove_device (seat_x11, device);
event->any.type = CLUTTER_DEVICE_REMOVED;
event->any.time = ev->time;
clutter_event_set_device (event, device);
retval = TRUE;
}
}
else if ((ev->info[i].flags & XISlaveAttached) ||
(ev->info[i].flags & XISlaveDetached))
@ -883,6 +917,8 @@ translate_hierarchy_event (ClutterBackend *backend,
}
}
}
return retval;
}
static void
@ -902,6 +938,7 @@ translate_property_event (MetaSeatX11 *seat_x11,
{
ClutterInputDeviceTool *tool = NULL;
ClutterInputDeviceToolType type;
MetaInputSettings *input_settings;
int serial_id;
serial_id = device_get_tool_serial (device);
@ -922,7 +959,8 @@ translate_property_event (MetaSeatX11 *seat_x11,
}
meta_input_device_x11_update_tool (device, tool);
g_signal_emit_by_name (seat_x11, "tool-changed", device, tool);
input_settings = meta_backend_get_input_settings (meta_get_backend ());
meta_input_settings_notify_tool_change (input_settings, device, tool);
}
}
@ -1115,6 +1153,9 @@ get_event_stage (MetaSeatX11 *seat_x11,
}
break;
case XI_HierarchyChanged:
return CLUTTER_STAGE (meta_backend_get_stage (meta_get_backend ()));
default:
break;
}
@ -1290,13 +1331,15 @@ static void
on_keymap_state_change (MetaKeymapX11 *keymap_x11,
gpointer data)
{
ClutterSeat *seat = CLUTTER_SEAT (data);
ClutterKbdA11ySettings kbd_a11y_settings;
ClutterSeat *seat = data;
MetaInputSettings *input_settings;
MetaKbdA11ySettings kbd_a11y_settings;
/* On keymaps state change, just reapply the current settings, it'll
* take care of enabling/disabling mousekeys based on NumLock state.
*/
clutter_seat_get_kbd_a11y_settings (seat, &kbd_a11y_settings);
input_settings = meta_backend_get_input_settings (meta_get_backend ());
meta_input_settings_get_kbd_a11y_settings (input_settings, &kbd_a11y_settings);
meta_seat_x11_apply_kbd_a11y_settings (seat, &kbd_a11y_settings);
}
@ -1450,6 +1493,7 @@ meta_seat_x11_finalize (GObject *object)
g_hash_table_unref (seat_x11->devices_by_id);
g_hash_table_unref (seat_x11->tools_by_serial);
g_hash_table_unref (seat_x11->touch_coords);
g_list_free (seat_x11->devices);
G_OBJECT_CLASS (meta_seat_x11_parent_class)->finalize (object);
@ -1548,6 +1592,140 @@ meta_seat_x11_warp_pointer (ClutterSeat *seat,
x, y);
}
static uint32_t
translate_state (XIButtonState *button_state,
XIModifierState *modifier_state,
XIGroupState *group_state)
{
uint32_t state = 0;
int i;
if (modifier_state)
state |= modifier_state->effective;
if (button_state)
{
for (i = 1; i < XIMaskLen (button_state->mask_len); i++)
{
if (!XIMaskIsSet (button_state->mask, i))
continue;
switch (i)
{
case 1:
state |= CLUTTER_BUTTON1_MASK;
break;
case 2:
state |= CLUTTER_BUTTON2_MASK;
break;
case 3:
state |= CLUTTER_BUTTON3_MASK;
break;
case 8:
state |= CLUTTER_BUTTON4_MASK;
break;
case 9:
state |= CLUTTER_BUTTON5_MASK;
break;
default:
break;
}
}
}
if (group_state)
state |= (group_state->effective) << 13;
return state;
}
static gboolean
meta_seat_x11_query_state (ClutterSeat *seat,
ClutterInputDevice *device,
ClutterEventSequence *sequence,
graphene_point_t *coords,
ClutterModifierType *modifiers)
{
MetaBackendX11 *backend_x11 = META_BACKEND_X11 (meta_get_backend ());
MetaSeatX11 *seat_x11 = META_SEAT_X11 (seat);
Window root_ret, child_ret;
double root_x, root_y, win_x, win_y;
XIButtonState button_state;
XIModifierState modifier_state;
XIGroupState group_state;
clutter_x11_trap_x_errors ();
XIQueryPointer (clutter_x11_get_default_display (),
seat_x11->pointer_id,
meta_backend_x11_get_xwindow (backend_x11),
&root_ret, &child_ret,
&root_x, &root_y, &win_x, &win_y,
&button_state, &modifier_state, &group_state);
if (clutter_x11_untrap_x_errors ())
return FALSE;
if (sequence)
{
MetaTouchInfo *touch_info;
touch_info = g_hash_table_lookup (seat_x11->touch_coords, sequence);
if (!touch_info)
return FALSE;
if (coords)
{
coords->x = touch_info->x;
coords->y = touch_info->y;
}
}
else
{
if (coords)
{
coords->x = win_x;
coords->y = win_y;
}
}
if (modifiers)
*modifiers = translate_state (&button_state, &modifier_state, &group_state);
return TRUE;
}
static void
meta_seat_x11_update_touchpoint (MetaSeatX11 *seat,
ClutterEventSequence *sequence,
double x,
double y)
{
MetaTouchInfo *touch_info;
touch_info = g_hash_table_lookup (seat->touch_coords, sequence);
if (!touch_info)
{
touch_info = g_slice_new (MetaTouchInfo);
touch_info->sequence = sequence;
g_hash_table_insert (seat->touch_coords, sequence, touch_info);
}
touch_info->x = x;
touch_info->y = y;
}
static void
meta_seat_x11_remove_touchpoint (MetaSeatX11 *seat,
ClutterEventSequence *sequence)
{
g_hash_table_remove (seat->touch_coords, sequence);
}
static void
meta_touch_info_free (MetaTouchInfo *touch_info)
{
g_slice_free (MetaTouchInfo, touch_info);
}
static void
meta_seat_x11_class_init (MetaSeatX11Class *klass)
{
@ -1566,10 +1744,11 @@ meta_seat_x11_class_init (MetaSeatX11Class *klass)
seat_class->get_keymap = meta_seat_x11_get_keymap;
seat_class->copy_event_data = meta_seat_x11_copy_event_data;
seat_class->free_event_data = meta_seat_x11_free_event_data;
seat_class->apply_kbd_a11y_settings = meta_seat_x11_apply_kbd_a11y_settings;
seat_class->create_virtual_device = meta_seat_x11_create_virtual_device;
seat_class->get_supported_virtual_device_types = meta_seat_x11_get_supported_virtual_device_types;
seat_class->warp_pointer = meta_seat_x11_warp_pointer;
seat_class->handle_event_post = meta_seat_x11_handle_event_post;
seat_class->query_state = meta_seat_x11_query_state;
props[PROP_OPCODE] =
g_param_spec_int ("opcode",
@ -1607,6 +1786,8 @@ meta_seat_x11_init (MetaSeatX11 *seat)
(GDestroyNotify) g_object_unref);
seat->tools_by_serial = g_hash_table_new_full (NULL, NULL, NULL,
(GDestroyNotify) g_object_unref);
seat->touch_coords = g_hash_table_new_full (NULL, NULL, NULL,
(GDestroyNotify) meta_touch_info_free);
}
MetaSeatX11 *
@ -1672,8 +1853,7 @@ meta_seat_x11_translate_event (MetaSeatX11 *seat,
return FALSE;
}
if (!(xi_event->evtype == XI_HierarchyChanged ||
xi_event->evtype == XI_DeviceChanged ||
if (!(xi_event->evtype == XI_DeviceChanged ||
xi_event->evtype == XI_PropertyEvent))
{
stage = get_event_stage (seat, xi_event);
@ -1691,9 +1871,8 @@ meta_seat_x11_translate_event (MetaSeatX11 *seat,
{
XIHierarchyEvent *xev = (XIHierarchyEvent *) xi_event;
translate_hierarchy_event (backend, seat, xev);
retval = translate_hierarchy_event (backend, seat, xev, event);
}
retval = FALSE;
break;
case XI_DeviceChanged:
@ -1815,12 +1994,6 @@ meta_seat_x11_translate_event (MetaSeatX11 *seat,
device = g_hash_table_lookup (seat->devices_by_id,
GINT_TO_POINTER (xev->deviceid));
/* Set the stage for core events coming out of nowhere (see bug #684509) */
if (clutter_input_device_get_device_mode (device) == CLUTTER_INPUT_MODE_MASTER &&
clutter_input_device_get_pointer_stage (device) == NULL &&
stage != NULL)
_clutter_input_device_set_stage (device, stage);
if (clutter_input_device_get_device_type (source_device) == CLUTTER_PAD_DEVICE)
{
/* We got these events because of the passive button grab */
@ -1978,9 +2151,6 @@ meta_seat_x11_translate_event (MetaSeatX11 *seat,
break;
}
if (device->stage != NULL)
_clutter_input_device_set_stage (source_device, device->stage);
if (xev->flags & XIPointerEmulated)
_clutter_event_set_pointer_emulated (event, TRUE);
@ -2012,12 +2182,6 @@ meta_seat_x11_translate_event (MetaSeatX11 *seat,
break;
}
/* Set the stage for core events coming out of nowhere (see bug #684509) */
if (clutter_input_device_get_device_mode (device) == CLUTTER_INPUT_MODE_MASTER &&
clutter_input_device_get_pointer_stage (device) == NULL &&
stage != NULL)
_clutter_input_device_set_stage (device, stage);
if (scroll_valuators_changed (source_device,
&xev->valuators,
&delta_x, &delta_y))
@ -2070,9 +2234,6 @@ meta_seat_x11_translate_event (MetaSeatX11 *seat,
event->motion.y,
&xev->valuators);
if (device->stage != NULL)
_clutter_input_device_set_stage (source_device, device->stage);
if (xev->flags & XIPointerEmulated)
_clutter_event_set_pointer_emulated (event, TRUE);
@ -2093,8 +2254,6 @@ meta_seat_x11_translate_event (MetaSeatX11 *seat,
XIDeviceEvent *xev = (XIDeviceEvent *) xi_event;
device = g_hash_table_lookup (seat->devices_by_id,
GINT_TO_POINTER (xev->deviceid));
if (!_clutter_input_device_get_stage (device))
_clutter_input_device_set_stage (device, stage);
}
/* Fall through */
case XI_TouchEnd:
@ -2133,6 +2292,15 @@ meta_seat_x11_translate_event (MetaSeatX11 *seat,
event->touch.modifier_state |= CLUTTER_BUTTON1_MASK;
meta_stage_x11_set_user_time (stage_x11, event->touch.time);
meta_seat_x11_update_touchpoint (seat,
GUINT_TO_POINTER (xev->detail),
xev->root_x,
xev->root_y);
}
else if (xi_event->evtype == XI_TouchEnd)
{
meta_seat_x11_remove_touchpoint (seat,
GUINT_TO_POINTER (xev->detail));
}
event->touch.sequence = GUINT_TO_POINTER (xev->detail);
@ -2187,6 +2355,11 @@ meta_seat_x11_translate_event (MetaSeatX11 *seat,
if (xev->flags & XITouchEmulatingPointer)
_clutter_event_set_pointer_emulated (event, TRUE);
meta_seat_x11_update_touchpoint (seat,
event->touch.sequence,
xev->root_x,
xev->root_y);
g_debug ("touch update: win:0x%x device:%d '%s' (seq:%d, x:%.2f, y:%.2f, axes:%s)",
(unsigned int) stage_x11->xwin,
event->touch.device->id,
@ -2224,14 +2397,6 @@ meta_seat_x11_translate_event (MetaSeatX11 *seat,
}
else
{
if (device->stage == NULL)
{
g_debug ("Discarding Leave for ButtonRelease "
"event off-stage");
retval = FALSE;
break;
}
event->crossing.type = event->type = CLUTTER_LEAVE;
event->crossing.stage = stage;

View File

@ -78,47 +78,55 @@ static void
check_settings_changed (ClutterSeat *seat)
{
Display *xdisplay = clutter_x11_get_default_display ();
ClutterKbdA11ySettings kbd_a11y_settings;
ClutterKeyboardA11yFlags what_changed = 0;
MetaKbdA11ySettings kbd_a11y_settings;
MetaKeyboardA11yFlags what_changed = 0;
MetaInputSettings *input_settings;
XkbDescRec *desc;
desc = get_xkb_desc_rec (xdisplay);
if (!desc)
return;
clutter_seat_get_kbd_a11y_settings (seat, &kbd_a11y_settings);
input_settings = meta_backend_get_input_settings (meta_get_backend ());
meta_input_settings_get_kbd_a11y_settings (input_settings,
&kbd_a11y_settings);
if (desc->ctrls->enabled_ctrls & XkbSlowKeysMask &&
!(kbd_a11y_settings.controls & CLUTTER_A11Y_SLOW_KEYS_ENABLED))
!(kbd_a11y_settings.controls & META_A11Y_SLOW_KEYS_ENABLED))
{
what_changed |= CLUTTER_A11Y_SLOW_KEYS_ENABLED;
kbd_a11y_settings.controls |= CLUTTER_A11Y_SLOW_KEYS_ENABLED;
what_changed |= META_A11Y_SLOW_KEYS_ENABLED;
kbd_a11y_settings.controls |= META_A11Y_SLOW_KEYS_ENABLED;
}
else if (!(desc->ctrls->enabled_ctrls & XkbSlowKeysMask) &&
kbd_a11y_settings.controls & CLUTTER_A11Y_SLOW_KEYS_ENABLED)
kbd_a11y_settings.controls & META_A11Y_SLOW_KEYS_ENABLED)
{
what_changed |= CLUTTER_A11Y_SLOW_KEYS_ENABLED;
kbd_a11y_settings.controls &= ~CLUTTER_A11Y_SLOW_KEYS_ENABLED;
what_changed |= META_A11Y_SLOW_KEYS_ENABLED;
kbd_a11y_settings.controls &= ~META_A11Y_SLOW_KEYS_ENABLED;
}
if (desc->ctrls->enabled_ctrls & XkbStickyKeysMask &&
!(kbd_a11y_settings.controls & CLUTTER_A11Y_STICKY_KEYS_ENABLED))
!(kbd_a11y_settings.controls & META_A11Y_STICKY_KEYS_ENABLED))
{
what_changed |= CLUTTER_A11Y_STICKY_KEYS_ENABLED;
kbd_a11y_settings.controls |= CLUTTER_A11Y_STICKY_KEYS_ENABLED;
what_changed |= META_A11Y_STICKY_KEYS_ENABLED;
kbd_a11y_settings.controls |= META_A11Y_STICKY_KEYS_ENABLED;
}
else if (!(desc->ctrls->enabled_ctrls & XkbStickyKeysMask) &&
kbd_a11y_settings.controls & CLUTTER_A11Y_STICKY_KEYS_ENABLED)
kbd_a11y_settings.controls & META_A11Y_STICKY_KEYS_ENABLED)
{
what_changed |= CLUTTER_A11Y_STICKY_KEYS_ENABLED;
kbd_a11y_settings.controls &= ~CLUTTER_A11Y_STICKY_KEYS_ENABLED;
what_changed |= META_A11Y_STICKY_KEYS_ENABLED;
kbd_a11y_settings.controls &= ~META_A11Y_STICKY_KEYS_ENABLED;
}
if (what_changed)
{
meta_input_settings_notify_kbd_a11y_change (input_settings,
kbd_a11y_settings.controls,
what_changed);
g_signal_emit_by_name (seat,
"kbd-a11y-flags-changed",
kbd_a11y_settings.controls,
what_changed);
}
XkbFreeKeyboard (desc, XkbAllComponentsMask, TRUE);
}
@ -183,8 +191,8 @@ set_value_mask (gboolean flag,
static gboolean
set_xkb_ctrl (XkbDescRec *desc,
ClutterKeyboardA11yFlags settings,
ClutterKeyboardA11yFlags flag,
MetaKeyboardA11yFlags settings,
MetaKeyboardA11yFlags flag,
unsigned long mask)
{
gboolean result = (settings & flag) == flag;
@ -195,7 +203,7 @@ set_xkb_ctrl (XkbDescRec *desc,
void
meta_seat_x11_apply_kbd_a11y_settings (ClutterSeat *seat,
ClutterKbdA11ySettings *kbd_a11y_settings)
MetaKbdA11ySettings *kbd_a11y_settings)
{
Display *xdisplay = clutter_x11_get_default_display ();
XkbDescRec *desc;
@ -206,13 +214,13 @@ meta_seat_x11_apply_kbd_a11y_settings (ClutterSeat *seat,
return;
/* general */
enable_accessX = kbd_a11y_settings->controls & CLUTTER_A11Y_KEYBOARD_ENABLED;
enable_accessX = kbd_a11y_settings->controls & META_A11Y_KEYBOARD_ENABLED;
desc->ctrls->enabled_ctrls = set_value_mask (enable_accessX,
desc->ctrls->enabled_ctrls,
XkbAccessXKeysMask);
if (set_xkb_ctrl (desc, kbd_a11y_settings->controls, CLUTTER_A11Y_TIMEOUT_ENABLED,
if (set_xkb_ctrl (desc, kbd_a11y_settings->controls, META_A11Y_TIMEOUT_ENABLED,
XkbAccessXTimeoutMask))
{
desc->ctrls->ax_timeout = kbd_a11y_settings->timeout_delay;
@ -226,17 +234,17 @@ meta_seat_x11_apply_kbd_a11y_settings (ClutterSeat *seat,
}
desc->ctrls->ax_options =
set_value_mask (kbd_a11y_settings->controls & CLUTTER_A11Y_FEATURE_STATE_CHANGE_BEEP,
set_value_mask (kbd_a11y_settings->controls & META_A11Y_FEATURE_STATE_CHANGE_BEEP,
desc->ctrls->ax_options,
XkbAccessXFeedbackMask | XkbAX_FeatureFBMask | XkbAX_SlowWarnFBMask);
/* bounce keys */
if (set_xkb_ctrl (desc, kbd_a11y_settings->controls,
CLUTTER_A11Y_BOUNCE_KEYS_ENABLED, XkbBounceKeysMask))
META_A11Y_BOUNCE_KEYS_ENABLED, XkbBounceKeysMask))
{
desc->ctrls->debounce_delay = kbd_a11y_settings->debounce_delay;
desc->ctrls->ax_options =
set_value_mask (kbd_a11y_settings->controls & CLUTTER_A11Y_BOUNCE_KEYS_BEEP_REJECT,
set_value_mask (kbd_a11y_settings->controls & META_A11Y_BOUNCE_KEYS_BEEP_REJECT,
desc->ctrls->ax_options,
XkbAccessXFeedbackMask | XkbAX_BKRejectFBMask);
}
@ -248,7 +256,7 @@ meta_seat_x11_apply_kbd_a11y_settings (ClutterSeat *seat,
desc->ctrls->enabled_ctrls &= ~(XkbMouseKeysMask | XkbMouseKeysAccelMask);
}
else if (set_xkb_ctrl (desc, kbd_a11y_settings->controls,
CLUTTER_A11Y_MOUSE_KEYS_ENABLED, XkbMouseKeysMask | XkbMouseKeysAccelMask))
META_A11Y_MOUSE_KEYS_ENABLED, XkbMouseKeysMask | XkbMouseKeysAccelMask))
{
int mk_max_speed;
int mk_accel_time;
@ -273,16 +281,16 @@ meta_seat_x11_apply_kbd_a11y_settings (ClutterSeat *seat,
/* slow keys */
if (set_xkb_ctrl (desc, kbd_a11y_settings->controls,
CLUTTER_A11Y_SLOW_KEYS_ENABLED, XkbSlowKeysMask))
META_A11Y_SLOW_KEYS_ENABLED, XkbSlowKeysMask))
{
desc->ctrls->ax_options =
set_value_mask (kbd_a11y_settings->controls & CLUTTER_A11Y_SLOW_KEYS_BEEP_PRESS,
set_value_mask (kbd_a11y_settings->controls & META_A11Y_SLOW_KEYS_BEEP_PRESS,
desc->ctrls->ax_options, XkbAccessXFeedbackMask | XkbAX_SKPressFBMask);
desc->ctrls->ax_options =
set_value_mask (kbd_a11y_settings->controls & CLUTTER_A11Y_SLOW_KEYS_BEEP_ACCEPT,
set_value_mask (kbd_a11y_settings->controls & META_A11Y_SLOW_KEYS_BEEP_ACCEPT,
desc->ctrls->ax_options, XkbAccessXFeedbackMask | XkbAX_SKAcceptFBMask);
desc->ctrls->ax_options =
set_value_mask (kbd_a11y_settings->controls & CLUTTER_A11Y_SLOW_KEYS_BEEP_REJECT,
set_value_mask (kbd_a11y_settings->controls & META_A11Y_SLOW_KEYS_BEEP_REJECT,
desc->ctrls->ax_options, XkbAccessXFeedbackMask | XkbAX_SKRejectFBMask);
desc->ctrls->slow_keys_delay = kbd_a11y_settings->slowkeys_delay;
/* anything larger than 500 seems to loose all keyboard input */
@ -292,20 +300,20 @@ meta_seat_x11_apply_kbd_a11y_settings (ClutterSeat *seat,
/* sticky keys */
if (set_xkb_ctrl (desc, kbd_a11y_settings->controls,
CLUTTER_A11Y_STICKY_KEYS_ENABLED, XkbStickyKeysMask))
META_A11Y_STICKY_KEYS_ENABLED, XkbStickyKeysMask))
{
desc->ctrls->ax_options |= XkbAX_LatchToLockMask;
desc->ctrls->ax_options =
set_value_mask (kbd_a11y_settings->controls & CLUTTER_A11Y_STICKY_KEYS_TWO_KEY_OFF,
set_value_mask (kbd_a11y_settings->controls & META_A11Y_STICKY_KEYS_TWO_KEY_OFF,
desc->ctrls->ax_options, XkbAccessXFeedbackMask | XkbAX_TwoKeysMask);
desc->ctrls->ax_options =
set_value_mask (kbd_a11y_settings->controls & CLUTTER_A11Y_STICKY_KEYS_BEEP,
set_value_mask (kbd_a11y_settings->controls & META_A11Y_STICKY_KEYS_BEEP,
desc->ctrls->ax_options, XkbAccessXFeedbackMask | XkbAX_StickyKeysFBMask);
}
/* toggle keys */
desc->ctrls->ax_options =
set_value_mask (kbd_a11y_settings->controls & CLUTTER_A11Y_TOGGLE_KEYS_ENABLED,
set_value_mask (kbd_a11y_settings->controls & META_A11Y_TOGGLE_KEYS_ENABLED,
desc->ctrls->ax_options, XkbAccessXFeedbackMask | XkbAX_IndicatorFBMask);
set_xkb_desc_rec (xdisplay, desc);

View File

@ -26,11 +26,12 @@
#include <X11/Xlib.h>
#include "backends/meta-input-settings-private.h"
#include "clutter/clutter.h"
void
meta_seat_x11_apply_kbd_a11y_settings (ClutterSeat *seat,
ClutterKbdA11ySettings *kbd_a11y_settings);
MetaKbdA11ySettings *kbd_a11y_settings);
gboolean
meta_seat_x11_a11y_init (ClutterSeat *seat);

View File

@ -31,6 +31,7 @@
typedef struct _MetaBackendX11NestedPrivate
{
MetaGpu *gpu;
MetaCursorRenderer *cursor_renderer;
} MetaBackendX11NestedPrivate;
static GInitableIface *initable_parent_iface;
@ -63,13 +64,25 @@ meta_backend_x11_nested_create_monitor_manager (MetaBackend *backend,
}
static MetaCursorRenderer *
meta_backend_x11_nested_create_cursor_renderer (MetaBackend *backend)
meta_backend_x11_nested_get_cursor_renderer (MetaBackend *backend,
ClutterInputDevice *device)
{
return g_object_new (META_TYPE_CURSOR_RENDERER_X11_NESTED,
MetaBackendX11Nested *backend_x11_nested = META_BACKEND_X11_NESTED (backend);
MetaBackendX11NestedPrivate *priv =
meta_backend_x11_nested_get_instance_private (backend_x11_nested);
if (!priv->cursor_renderer)
{
priv->cursor_renderer =
g_object_new (META_TYPE_CURSOR_RENDERER_X11_NESTED,
"backend", backend,
"device", device,
NULL);
}
return priv->cursor_renderer;
}
static MetaInputSettings *
meta_backend_x11_nested_create_input_settings (MetaBackend *backend)
{
@ -275,7 +288,7 @@ meta_backend_x11_nested_class_init (MetaBackendX11NestedClass *klass)
backend_class->post_init = meta_backend_x11_nested_post_init;
backend_class->create_renderer = meta_backend_x11_nested_create_renderer;
backend_class->create_monitor_manager = meta_backend_x11_nested_create_monitor_manager;
backend_class->create_cursor_renderer = meta_backend_x11_nested_create_cursor_renderer;
backend_class->get_cursor_renderer = meta_backend_x11_nested_get_cursor_renderer;
backend_class->create_input_settings = meta_backend_x11_nested_create_input_settings;
backend_class->update_screen_size = meta_backend_x11_nested_update_screen_size;
backend_class->select_stage_events = meta_backend_x11_nested_select_stage_events;

View File

@ -38,6 +38,7 @@
#include "clutter/clutter.h"
#include "core/keybindings-private.h"
#include "core/meta-gesture-tracker-private.h"
#include "core/meta-pad-action-mapper.h"
#include "core/stack-tracker.h"
#include "core/startup-notification-private.h"
#include "meta/barrier.h"
@ -199,9 +200,6 @@ struct _MetaDisplay
MetaKeyBindingManager key_binding_manager;
/* Monitor cache */
unsigned int monitor_cache_invalidated : 1;
/* Opening the display */
unsigned int display_opening : 1;
@ -215,6 +213,7 @@ struct _MetaDisplay
ClutterEventSequence *pointer_emulating_sequence;
ClutterActor *current_pad_osd;
MetaPadActionMapper *pad_action_mapper;
MetaStartupNotification *startup_notification;

View File

@ -45,8 +45,7 @@
#include "backends/meta-cursor-tracker-private.h"
#include "backends/meta-idle-monitor-dbus.h"
#include "backends/meta-input-device-private.h"
#include "backends/meta-input-settings-private.h"
#include "backends/meta-logical-monitor.h"
#include "backends/meta-input-mapper-private.h"
#include "backends/meta-stage-private.h"
#include "backends/x11/meta-backend-x11.h"
#include "backends/x11/meta-event-x11.h"
@ -844,6 +843,8 @@ meta_display_open (void)
meta_prefs_add_listener (prefs_changed_callback, display);
display->pad_action_mapper = meta_pad_action_mapper_new ();
/* Get events */
meta_display_init_events (display);
@ -1120,6 +1121,7 @@ meta_display_close (MetaDisplay *display,
meta_clipboard_manager_shutdown (display);
g_clear_object (&display->selection);
g_clear_object (&display->pad_action_mapper);
g_object_unref (display);
the_display = NULL;
@ -1629,43 +1631,9 @@ meta_cursor_for_grab_op (MetaGrabOp op)
return META_CURSOR_DEFAULT;
}
static float
find_highest_logical_monitor_scale (MetaBackend *backend,
MetaCursorSprite *cursor_sprite)
{
MetaMonitorManager *monitor_manager =
meta_backend_get_monitor_manager (backend);
MetaCursorRenderer *cursor_renderer =
meta_backend_get_cursor_renderer (backend);
graphene_rect_t cursor_rect;
GList *logical_monitors;
GList *l;
float highest_scale = 0.0;
cursor_rect = meta_cursor_renderer_calculate_rect (cursor_renderer,
cursor_sprite);
logical_monitors =
meta_monitor_manager_get_logical_monitors (monitor_manager);
for (l = logical_monitors; l; l = l->next)
{
MetaLogicalMonitor *logical_monitor = l->data;
graphene_rect_t logical_monitor_rect =
meta_rectangle_to_graphene_rect (&logical_monitor->rect);
if (!graphene_rect_intersection (&cursor_rect,
&logical_monitor_rect,
NULL))
continue;
highest_scale = MAX (highest_scale, logical_monitor->scale);
}
return highest_scale;
}
static void
root_cursor_prepare_at (MetaCursorSpriteXcursor *sprite_xcursor,
float best_scale,
int x,
int y,
MetaDisplay *display)
@ -1675,14 +1643,11 @@ root_cursor_prepare_at (MetaCursorSpriteXcursor *sprite_xcursor,
if (meta_is_stage_views_scaled ())
{
float scale;
scale = find_highest_logical_monitor_scale (backend, cursor_sprite);
if (scale != 0.0)
if (best_scale != 0.0)
{
float ceiled_scale;
ceiled_scale = ceilf (scale);
ceiled_scale = ceilf (best_scale);
meta_cursor_sprite_xcursor_set_theme_scale (sprite_xcursor,
(int) ceiled_scale);
meta_cursor_sprite_set_texture_scale (cursor_sprite,
@ -2944,7 +2909,7 @@ meta_display_request_pad_osd (MetaDisplay *display,
gboolean edition_mode)
{
MetaBackend *backend = meta_get_backend ();
MetaInputSettings *input_settings;
MetaInputMapper *input_mapper;
const gchar *layout_path = NULL;
ClutterActor *osd;
MetaLogicalMonitor *logical_monitor;
@ -2960,13 +2925,13 @@ meta_display_request_pad_osd (MetaDisplay *display,
if (display->current_pad_osd)
return;
input_settings = meta_backend_get_input_settings (meta_get_backend ());
input_mapper = meta_backend_get_input_mapper (meta_get_backend ());
if (input_settings)
if (input_mapper)
{
settings = meta_input_settings_get_tablet_settings (input_settings, pad);
settings = meta_input_mapper_get_tablet_settings (input_mapper, pad);
logical_monitor =
meta_input_settings_get_tablet_logical_monitor (input_settings, pad);
meta_input_mapper_get_device_logical_monitor (input_mapper, pad);
#ifdef HAVE_LIBWACOM
wacom_device = meta_input_device_get_wacom_device (META_INPUT_DEVICE (pad));
layout_path = libwacom_get_layout_filename (wacom_device);
@ -2999,12 +2964,12 @@ meta_display_get_pad_action_label (MetaDisplay *display,
MetaPadActionType action_type,
guint action_number)
{
MetaInputSettings *settings;
gchar *label;
/* First, lookup the action, as imposed by settings */
settings = meta_backend_get_input_settings (meta_get_backend ());
label = meta_input_settings_get_pad_action_label (settings, pad, action_type, action_number);
label = meta_pad_action_mapper_get_action_label (display->pad_action_mapper,
pad, action_type,
action_number);
if (label)
return label;
@ -3050,15 +3015,15 @@ static gint
lookup_tablet_monitor (MetaDisplay *display,
ClutterInputDevice *device)
{
MetaInputSettings *input_settings;
MetaInputMapper *input_mapper;
MetaLogicalMonitor *monitor;
gint monitor_idx = -1;
input_settings = meta_backend_get_input_settings (meta_get_backend ());
if (!input_settings)
input_mapper = meta_backend_get_input_mapper (meta_get_backend ());
if (!input_mapper)
return -1;
monitor = meta_input_settings_get_tablet_logical_monitor (input_settings, device);
monitor = meta_input_mapper_get_device_logical_monitor (input_mapper, device);
if (monitor)
{
@ -3144,9 +3109,6 @@ static void
on_monitors_changed_internal (MetaMonitorManager *monitor_manager,
MetaDisplay *display)
{
MetaBackend *backend;
MetaCursorRenderer *cursor_renderer;
meta_workspace_manager_reload_work_areas (display->workspace_manager);
/* Fix up monitor for all windows on this display */
@ -3159,10 +3121,6 @@ on_monitors_changed_internal (MetaMonitorManager *monitor_manager,
meta_display_resize_func, 0);
meta_display_queue_check_fullscreen (display);
backend = meta_get_backend ();
cursor_renderer = meta_backend_get_cursor_renderer (backend);
meta_cursor_renderer_force_update (cursor_renderer);
}
void
@ -3750,18 +3708,18 @@ meta_display_get_pointer_window (MetaDisplay *display,
MetaBackend *backend = meta_get_backend ();
MetaCursorTracker *cursor_tracker = meta_backend_get_cursor_tracker (backend);
MetaWindow *window;
int x, y;
graphene_point_t point;
if (not_this_one)
meta_topic (META_DEBUG_FOCUS,
"Focusing mouse window excluding %s\n", not_this_one->desc);
meta_cursor_tracker_get_pointer (cursor_tracker, &x, &y, NULL);
meta_cursor_tracker_get_pointer (cursor_tracker, &point, NULL);
window = meta_stack_get_default_focus_window_at_point (display->stack,
workspace_manager->active_workspace,
not_this_one,
x, y);
point.x, point.y);
return window;
}

View File

@ -263,8 +263,7 @@ meta_display_handle_event (MetaDisplay *display,
handle_pad_event = !display->current_pad_osd || is_mode_switch;
if (handle_pad_event &&
meta_input_settings_handle_pad_event (meta_backend_get_input_settings (backend),
event))
meta_pad_action_mapper_handle_event (display->pad_action_mapper, event))
{
bypass_wayland = bypass_clutter = TRUE;
goto out;
@ -279,25 +278,22 @@ meta_display_handle_event (MetaDisplay *display,
#ifdef HAVE_WAYLAND
if (meta_is_wayland_compositor () && event->type == CLUTTER_MOTION)
{
MetaWaylandCompositor *compositor;
MetaCursorRenderer *cursor_renderer;
ClutterInputDevice *device;
compositor = meta_wayland_compositor_get_default ();
device = clutter_event_get_device (event);
cursor_renderer = meta_backend_get_cursor_renderer_for_device (backend,
device);
if (cursor_renderer)
meta_cursor_renderer_update_position (cursor_renderer);
if (meta_wayland_tablet_manager_consumes_event (compositor->tablet_manager, event))
{
meta_wayland_tablet_manager_update_cursor_position (compositor->tablet_manager, event);
}
else
if (device == clutter_seat_get_pointer (clutter_input_device_get_seat (device)))
{
MetaCursorTracker *cursor_tracker =
meta_backend_get_cursor_tracker (backend);
meta_cursor_tracker_update_position (cursor_tracker,
event->motion.x,
event->motion.y);
meta_cursor_tracker_update_position (cursor_tracker);
}
display->monitor_cache_invalidated = TRUE;
}
#endif

View File

@ -0,0 +1,852 @@
/*
* Copyright (C) 2014-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>
*/
#include "config.h"
#include <glib/gi18n-lib.h>
#include <gsettings-desktop-schemas/gdesktop-enums.h>
#ifdef HAVE_LIBWACOM
#include <libwacom/libwacom.h>
#endif
#include "meta-pad-action-mapper.h"
#include "backends/meta-input-device-private.h"
#include "backends/meta-logical-monitor.h"
#include "backends/meta-monitor.h"
#include "core/display-private.h"
typedef struct _PadMappingInfo PadMappingInfo;
struct _PadMappingInfo
{
ClutterInputDevice *device;
GSettings *settings;
guint *group_modes;
};
typedef enum
{
META_PAD_DIRECTION_NONE = -1,
META_PAD_DIRECTION_UP = 0,
META_PAD_DIRECTION_DOWN,
META_PAD_DIRECTION_CW,
META_PAD_DIRECTION_CCW,
} MetaPadDirection;
struct _MetaPadActionMapper
{
GObject parent_class;
GHashTable *pads;
ClutterSeat *seat;
ClutterVirtualInputDevice *virtual_pad_keyboard;
MetaMonitorManager *monitor_manager;
gulong monitors_changed_id;
/* Pad ring/strip emission */
struct {
ClutterInputDevice *pad;
MetaPadActionType action;
guint number;
gdouble value;
} last_pad_action_info;
};
G_DEFINE_TYPE (MetaPadActionMapper, meta_pad_action_mapper, G_TYPE_OBJECT)
static void
meta_pad_action_mapper_finalize (GObject *object)
{
MetaPadActionMapper *mapper = META_PAD_ACTION_MAPPER (object);
g_hash_table_unref (mapper->pads);
g_signal_handler_disconnect (mapper->monitor_manager,
mapper->monitors_changed_id);
g_object_unref (mapper->monitor_manager);
g_clear_object (&mapper->virtual_pad_keyboard);
G_OBJECT_CLASS (meta_pad_action_mapper_parent_class)->finalize (object);
}
static void
meta_pad_action_mapper_class_init (MetaPadActionMapperClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->finalize = meta_pad_action_mapper_finalize;
}
static GSettings *
lookup_device_settings (ClutterInputDevice *device)
{
const gchar *vendor, *product;
GSettings *settings;
gchar *path;
vendor = clutter_input_device_get_vendor_id (device);
product = clutter_input_device_get_product_id (device);
path = g_strdup_printf ("/org/gnome/desktop/peripherals/tablets/%s:%s/",
vendor, product);
settings = g_settings_new_with_path ("org.gnome.desktop.peripherals.tablet",
path);
g_free (path);
return settings;
}
static PadMappingInfo *
pad_mapping_info_new (ClutterInputDevice *pad)
{
PadMappingInfo *info;
info = g_new0 (PadMappingInfo, 1);
info->device = pad;
info->settings = lookup_device_settings (pad);
info->group_modes =
g_new0 (guint, clutter_input_device_get_n_mode_groups (pad));
return info;
}
static void
pad_mapping_info_free (PadMappingInfo *info)
{
g_object_unref (info->settings);
g_free (info->group_modes);
g_free (info);
}
static void
device_added (ClutterSeat *seat,
ClutterInputDevice *device,
MetaPadActionMapper *mapper)
{
PadMappingInfo *info;
if (clutter_input_device_get_device_type (device) == CLUTTER_PAD_DEVICE)
{
info = pad_mapping_info_new (device);
g_hash_table_insert (mapper->pads, device, info);
}
}
static void
device_removed (ClutterSeat *seat,
ClutterInputDevice *device,
MetaPadActionMapper *mapper)
{
g_hash_table_remove (mapper->pads, device);
}
static void
meta_pad_action_mapper_init (MetaPadActionMapper *mapper)
{
mapper->pads = g_hash_table_new_full (NULL, NULL, NULL,
(GDestroyNotify) pad_mapping_info_free);
mapper->seat = clutter_backend_get_default_seat (clutter_get_default_backend ());
g_signal_connect (mapper->seat, "device-added",
G_CALLBACK (device_added), mapper);
g_signal_connect (mapper->seat, "device-removed",
G_CALLBACK (device_removed), mapper);
}
MetaPadActionMapper *
meta_pad_action_mapper_new (void)
{
return g_object_new (META_TYPE_PAD_ACTION_MAPPER, NULL);
}
static GSettings *
lookup_pad_action_settings (ClutterInputDevice *device,
MetaPadActionType action,
guint number,
MetaPadDirection direction,
gint mode)
{
const gchar *vendor, *product, *action_type, *detail_type = NULL;
GSettings *settings;
GString *path;
gchar action_label;
vendor = clutter_input_device_get_vendor_id (device);
product = clutter_input_device_get_product_id (device);
action_label = 'A' + number;
switch (action)
{
case META_PAD_ACTION_BUTTON:
action_type = "button";
break;
case META_PAD_ACTION_RING:
g_assert (direction == META_PAD_DIRECTION_CW ||
direction == META_PAD_DIRECTION_CCW);
action_type = "ring";
detail_type = (direction == META_PAD_DIRECTION_CW) ? "cw" : "ccw";
break;
case META_PAD_ACTION_STRIP:
g_assert (direction == META_PAD_DIRECTION_UP ||
direction == META_PAD_DIRECTION_DOWN);
action_type = "strip";
detail_type = (direction == META_PAD_DIRECTION_UP) ? "up" : "down";
break;
default:
return NULL;
}
path = g_string_new (NULL);
g_string_append_printf (path, "/org/gnome/desktop/peripherals/tablets/%s:%s/%s%c",
vendor, product, action_type, action_label);
if (detail_type)
g_string_append_printf (path, "-%s", detail_type);
if (mode >= 0)
g_string_append_printf (path, "-mode-%d", mode);
g_string_append_c (path, '/');
settings = g_settings_new_with_path ("org.gnome.desktop.peripherals.tablet.pad-button",
path->str);
g_string_free (path, TRUE);
return settings;
}
static GDesktopPadButtonAction
meta_pad_action_mapper_get_button_action (MetaPadActionMapper *mapper,
ClutterInputDevice *pad,
guint button)
{
GDesktopPadButtonAction action;
GSettings *settings;
g_return_val_if_fail (META_IS_PAD_ACTION_MAPPER (mapper),
G_DESKTOP_PAD_BUTTON_ACTION_NONE);
g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (pad),
G_DESKTOP_PAD_BUTTON_ACTION_NONE);
settings = lookup_pad_action_settings (pad, META_PAD_ACTION_BUTTON,
button, META_PAD_DIRECTION_NONE, -1);
action = g_settings_get_enum (settings, "action");
g_object_unref (settings);
return action;
}
static gboolean
cycle_logical_monitors (MetaPadActionMapper *mapper,
MetaLogicalMonitor *current_logical_monitor,
MetaLogicalMonitor **next_logical_monitor)
{
MetaMonitorManager *monitor_manager = mapper->monitor_manager;
GList *logical_monitors;
/* We cycle between:
* - the span of all monitors (current_output = NULL)
* - each monitor individually.
*/
logical_monitors =
meta_monitor_manager_get_logical_monitors (monitor_manager);
if (!current_logical_monitor)
{
*next_logical_monitor = logical_monitors->data;
}
else
{
GList *l;
l = g_list_find (logical_monitors, current_logical_monitor);
if (l->next)
*next_logical_monitor = l->next->data;
else
*next_logical_monitor = NULL;
}
return TRUE;
}
static MetaMonitor *
logical_monitor_find_monitor (MetaLogicalMonitor *logical_monitor,
const char *vendor,
const char *product,
const char *serial)
{
GList *monitors;
GList *l;
monitors = meta_logical_monitor_get_monitors (logical_monitor);
for (l = monitors; l; l = l->next)
{
MetaMonitor *monitor = l->data;
if (g_strcmp0 (meta_monitor_get_vendor (monitor), vendor) == 0 &&
g_strcmp0 (meta_monitor_get_product (monitor), product) == 0 &&
g_strcmp0 (meta_monitor_get_serial (monitor), serial) == 0)
return monitor;
}
return NULL;
}
static void
meta_pad_action_mapper_find_monitor (MetaPadActionMapper *mapper,
GSettings *settings,
ClutterInputDevice *device,
MetaMonitor **out_monitor,
MetaLogicalMonitor **out_logical_monitor)
{
MetaMonitorManager *monitor_manager;
MetaMonitor *monitor;
guint n_values;
GList *logical_monitors;
GList *l;
gchar **edid;
edid = g_settings_get_strv (settings, "output");
n_values = g_strv_length (edid);
if (n_values != 3)
{
g_warning ("EDID configuration for device '%s' "
"is incorrect, must have 3 values",
clutter_input_device_get_device_name (device));
goto out;
}
if (!*edid[0] && !*edid[1] && !*edid[2])
goto out;
monitor_manager = mapper->monitor_manager;
logical_monitors =
meta_monitor_manager_get_logical_monitors (monitor_manager);
for (l = logical_monitors; l; l = l->next)
{
MetaLogicalMonitor *logical_monitor = l->data;
monitor = logical_monitor_find_monitor (logical_monitor,
edid[0], edid[1], edid[2]);
if (monitor)
{
if (out_monitor)
*out_monitor = monitor;
if (out_logical_monitor)
*out_logical_monitor = logical_monitor;
break;
}
}
out:
g_strfreev (edid);
}
static void
meta_pad_action_mapper_cycle_tablet_output (MetaPadActionMapper *mapper,
ClutterInputDevice *device)
{
PadMappingInfo *info;
MetaLogicalMonitor *logical_monitor = NULL;
const gchar *edid[4] = { 0 }, *pretty_name = NULL;
#ifdef HAVE_LIBWACOM
WacomDevice *wacom_device;
#endif
g_return_if_fail (META_IS_PAD_ACTION_MAPPER (mapper));
g_return_if_fail (CLUTTER_IS_INPUT_DEVICE (device));
g_return_if_fail (clutter_input_device_get_device_type (device) == CLUTTER_TABLET_DEVICE ||
clutter_input_device_get_device_type (device) == CLUTTER_PAD_DEVICE);
info = g_hash_table_lookup (mapper->pads, device);
g_return_if_fail (info != NULL);
#ifdef HAVE_LIBWACOM
wacom_device = meta_input_device_get_wacom_device (META_INPUT_DEVICE (device));
if (wacom_device)
{
/* Output rotation only makes sense on external tablets */
if (libwacom_get_integration_flags (wacom_device) != WACOM_DEVICE_INTEGRATED_NONE)
return;
pretty_name = libwacom_get_name (wacom_device);
}
#endif
meta_pad_action_mapper_find_monitor (mapper, info->settings, device,
NULL, &logical_monitor);
if (!cycle_logical_monitors (mapper,
logical_monitor,
&logical_monitor))
return;
if (logical_monitor)
{
MetaMonitor *monitor;
/* Pick an arbitrary monitor in the logical monitor to represent it. */
monitor = meta_logical_monitor_get_monitors (logical_monitor)->data;
edid[0] = meta_monitor_get_vendor (monitor);
edid[1] = meta_monitor_get_product (monitor);
edid[2] = meta_monitor_get_serial (monitor);
}
else
{
edid[0] = "";
edid[1] = "";
edid[2] = "";
}
g_settings_set_strv (info->settings, "output", edid);
meta_display_show_tablet_mapping_notification (meta_get_display (),
device, pretty_name);
}
gboolean
meta_pad_action_mapper_is_button_grabbed (MetaPadActionMapper *mapper,
ClutterInputDevice *pad,
guint button)
{
g_return_val_if_fail (META_IS_PAD_ACTION_MAPPER (mapper), FALSE);
g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (pad), FALSE);
g_return_val_if_fail (clutter_input_device_get_device_type (pad) ==
CLUTTER_PAD_DEVICE, FALSE);
return (meta_pad_action_mapper_get_button_action (mapper, pad, button) !=
G_DESKTOP_PAD_BUTTON_ACTION_NONE);
}
static void
emulate_modifiers (ClutterVirtualInputDevice *device,
ClutterModifierType mods,
ClutterKeyState state)
{
guint i;
struct {
ClutterModifierType mod;
guint keyval;
} mod_map[] = {
{ CLUTTER_SHIFT_MASK, CLUTTER_KEY_Shift_L },
{ CLUTTER_CONTROL_MASK, CLUTTER_KEY_Control_L },
{ CLUTTER_MOD1_MASK, CLUTTER_KEY_Meta_L }
};
for (i = 0; i < G_N_ELEMENTS (mod_map); i++)
{
if ((mods & mod_map[i].mod) == 0)
continue;
clutter_virtual_input_device_notify_keyval (device,
clutter_get_current_event_time (),
mod_map[i].keyval, state);
}
}
static void
meta_pad_action_mapper_emulate_keybinding (MetaPadActionMapper *mapper,
const gchar *accel,
gboolean is_press)
{
ClutterKeyState state;
guint key, mods;
if (!accel || !*accel)
return;
/* FIXME: This is appalling */
gtk_accelerator_parse (accel, &key, &mods);
if (!mapper->virtual_pad_keyboard)
{
ClutterBackend *backend;
ClutterSeat *seat;
backend = clutter_get_default_backend ();
seat = clutter_backend_get_default_seat (backend);
mapper->virtual_pad_keyboard =
clutter_seat_create_virtual_device (seat,
CLUTTER_KEYBOARD_DEVICE);
}
state = is_press ? CLUTTER_KEY_STATE_PRESSED : CLUTTER_KEY_STATE_RELEASED;
if (is_press)
emulate_modifiers (mapper->virtual_pad_keyboard, mods, state);
clutter_virtual_input_device_notify_keyval (mapper->virtual_pad_keyboard,
clutter_get_current_event_time (),
key, state);
if (!is_press)
emulate_modifiers (mapper->virtual_pad_keyboard, mods, state);
}
static gboolean
meta_pad_action_mapper_handle_button (MetaPadActionMapper *mapper,
ClutterInputDevice *pad,
const ClutterPadButtonEvent *event)
{
GDesktopPadButtonAction action;
gint button, group, mode;
gboolean is_press;
GSettings *settings;
gchar *accel;
g_return_val_if_fail (META_IS_PAD_ACTION_MAPPER (mapper), FALSE);
g_return_val_if_fail (event->type == CLUTTER_PAD_BUTTON_PRESS ||
event->type == CLUTTER_PAD_BUTTON_RELEASE, FALSE);
button = event->button;
mode = event->mode;
group = clutter_input_device_get_mode_switch_button_group (pad, button);
is_press = event->type == CLUTTER_PAD_BUTTON_PRESS;
if (is_press && group >= 0)
{
guint n_modes = clutter_input_device_get_group_n_modes (pad, group);
const gchar *pretty_name = NULL;
PadMappingInfo *info;
#ifdef HAVE_LIBWACOM
WacomDevice *wacom_device;
#endif
info = g_hash_table_lookup (mapper->pads, pad);
#ifdef HAVE_LIBWACOM
wacom_device = meta_input_device_get_wacom_device (META_INPUT_DEVICE (pad));
if (wacom_device)
pretty_name = libwacom_get_name (wacom_device);
#endif
meta_display_notify_pad_group_switch (meta_get_display (), pad,
pretty_name, group, mode, n_modes);
info->group_modes[group] = mode;
}
action = meta_pad_action_mapper_get_button_action (mapper, pad, button);
switch (action)
{
case G_DESKTOP_PAD_BUTTON_ACTION_SWITCH_MONITOR:
if (is_press)
meta_pad_action_mapper_cycle_tablet_output (mapper, pad);
return TRUE;
case G_DESKTOP_PAD_BUTTON_ACTION_HELP:
if (is_press)
meta_display_request_pad_osd (meta_get_display (), pad, FALSE);
return TRUE;
case G_DESKTOP_PAD_BUTTON_ACTION_KEYBINDING:
settings = lookup_pad_action_settings (pad, META_PAD_ACTION_BUTTON,
button, META_PAD_DIRECTION_NONE, -1);
accel = g_settings_get_string (settings, "keybinding");
meta_pad_action_mapper_emulate_keybinding (mapper, accel, is_press);
g_object_unref (settings);
g_free (accel);
return TRUE;
case G_DESKTOP_PAD_BUTTON_ACTION_NONE:
default:
return FALSE;
}
}
static gboolean
meta_pad_action_mapper_handle_action (MetaPadActionMapper *mapper,
ClutterInputDevice *pad,
MetaPadActionType action,
guint number,
MetaPadDirection direction,
guint mode)
{
GSettings *settings;
gboolean handled = FALSE;
gchar *accel;
settings = lookup_pad_action_settings (pad, action, number, direction, mode);
accel = g_settings_get_string (settings, "keybinding");
if (accel && *accel)
{
meta_pad_action_mapper_emulate_keybinding (mapper, accel, TRUE);
meta_pad_action_mapper_emulate_keybinding (mapper, accel, FALSE);
handled = TRUE;
}
g_object_unref (settings);
g_free (accel);
return handled;
}
static gboolean
meta_pad_action_mapper_get_action_direction (MetaPadActionMapper *mapper,
const ClutterEvent *event,
MetaPadDirection *direction)
{
ClutterInputDevice *pad = clutter_event_get_device (event);
MetaPadActionType pad_action;
gboolean has_direction = FALSE;
MetaPadDirection inc_dir, dec_dir;
guint number;
gdouble value;
*direction = META_PAD_DIRECTION_NONE;
switch (event->type)
{
case CLUTTER_PAD_RING:
pad_action = META_PAD_ACTION_RING;
number = event->pad_ring.ring_number;
value = event->pad_ring.angle;
inc_dir = META_PAD_DIRECTION_CW;
dec_dir = META_PAD_DIRECTION_CCW;
break;
case CLUTTER_PAD_STRIP:
pad_action = META_PAD_ACTION_STRIP;
number = event->pad_strip.strip_number;
value = event->pad_strip.value;
inc_dir = META_PAD_DIRECTION_DOWN;
dec_dir = META_PAD_DIRECTION_UP;
break;
default:
return FALSE;
}
if (mapper->last_pad_action_info.pad == pad &&
mapper->last_pad_action_info.action == pad_action &&
mapper->last_pad_action_info.number == number &&
value >= 0 && mapper->last_pad_action_info.value >= 0)
{
*direction = (value - mapper->last_pad_action_info.value) > 0 ?
inc_dir : dec_dir;
has_direction = TRUE;
}
mapper->last_pad_action_info.pad = pad;
mapper->last_pad_action_info.action = pad_action;
mapper->last_pad_action_info.number = number;
mapper->last_pad_action_info.value = value;
return has_direction;
}
gboolean
meta_pad_action_mapper_handle_event (MetaPadActionMapper *mapper,
const ClutterEvent *event)
{
ClutterInputDevice *pad;
MetaPadDirection direction = META_PAD_DIRECTION_NONE;
pad = clutter_event_get_source_device ((ClutterEvent *) event);
switch (event->type)
{
case CLUTTER_PAD_BUTTON_PRESS:
case CLUTTER_PAD_BUTTON_RELEASE:
return meta_pad_action_mapper_handle_button (mapper, pad,
&event->pad_button);
case CLUTTER_PAD_RING:
if (!meta_pad_action_mapper_get_action_direction (mapper,
event, &direction))
return FALSE;
return meta_pad_action_mapper_handle_action (mapper, pad,
META_PAD_ACTION_RING,
event->pad_ring.ring_number,
direction,
event->pad_ring.mode);
case CLUTTER_PAD_STRIP:
if (!meta_pad_action_mapper_get_action_direction (mapper,
event, &direction))
return FALSE;
return meta_pad_action_mapper_handle_action (mapper, pad,
META_PAD_ACTION_STRIP,
event->pad_strip.strip_number,
direction,
event->pad_strip.mode);
default:
return FALSE;
}
}
static gchar *
compose_directional_action_label (GSettings *direction1,
GSettings *direction2)
{
gchar *accel1, *accel2, *str = NULL;
accel1 = g_settings_get_string (direction1, "keybinding");
accel2 = g_settings_get_string (direction2, "keybinding");
if (accel1 && *accel1 && accel2 && *accel2)
str = g_strdup_printf ("%s / %s", accel1, accel2);
g_free (accel1);
g_free (accel2);
return str;
}
static gchar *
meta_pad_action_mapper_get_ring_label (MetaPadActionMapper *mapper,
ClutterInputDevice *pad,
guint number,
guint mode)
{
GSettings *settings1, *settings2;
gchar *label;
/* We only allow keybinding actions with those */
settings1 = lookup_pad_action_settings (pad, META_PAD_ACTION_RING, number,
META_PAD_DIRECTION_CW, mode);
settings2 = lookup_pad_action_settings (pad, META_PAD_ACTION_RING, number,
META_PAD_DIRECTION_CCW, mode);
label = compose_directional_action_label (settings1, settings2);
g_object_unref (settings1);
g_object_unref (settings2);
return label;
}
static gchar *
meta_pad_action_mapper_get_strip_label (MetaPadActionMapper *mapper,
ClutterInputDevice *pad,
guint number,
guint mode)
{
GSettings *settings1, *settings2;
gchar *label;
/* We only allow keybinding actions with those */
settings1 = lookup_pad_action_settings (pad, META_PAD_ACTION_STRIP, number,
META_PAD_DIRECTION_UP, mode);
settings2 = lookup_pad_action_settings (pad, META_PAD_ACTION_STRIP, number,
META_PAD_DIRECTION_DOWN, mode);
label = compose_directional_action_label (settings1, settings2);
g_object_unref (settings1);
g_object_unref (settings2);
return label;
}
static gchar *
meta_pad_action_mapper_get_button_label (MetaPadActionMapper *mapper,
ClutterInputDevice *pad,
guint button)
{
GDesktopPadButtonAction action;
gint group;
g_return_val_if_fail (META_IS_PAD_ACTION_MAPPER (mapper), NULL);
g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (pad), NULL);
g_return_val_if_fail (clutter_input_device_get_device_type (pad) ==
CLUTTER_PAD_DEVICE, NULL);
group = clutter_input_device_get_mode_switch_button_group (pad, button);
if (group >= 0)
{
/* TRANSLATORS: This string refers to a button that switches between
* different modes.
*/
return g_strdup_printf (_("Mode Switch (Group %d)"), group);
}
action = meta_pad_action_mapper_get_button_action (mapper, pad, button);
switch (action)
{
case G_DESKTOP_PAD_BUTTON_ACTION_KEYBINDING:
{
GSettings *settings;
gchar *accel;
settings = lookup_pad_action_settings (pad, META_PAD_ACTION_BUTTON,
button, META_PAD_DIRECTION_NONE, -1);
accel = g_settings_get_string (settings, "keybinding");
g_object_unref (settings);
return accel;
}
case G_DESKTOP_PAD_BUTTON_ACTION_SWITCH_MONITOR:
/* TRANSLATORS: This string refers to an action, cycles drawing tablets'
* mapping through the available outputs.
*/
return g_strdup (_("Switch monitor"));
case G_DESKTOP_PAD_BUTTON_ACTION_HELP:
return g_strdup (_("Show on-screen help"));
case G_DESKTOP_PAD_BUTTON_ACTION_NONE:
default:
return NULL;
}
}
static guint
get_current_pad_mode (MetaPadActionMapper *mapper,
ClutterInputDevice *pad,
MetaPadActionType action_type,
guint number)
{
PadMappingInfo *info;
guint group = 0, n_groups;
info = g_hash_table_lookup (mapper->pads, pad);
n_groups = clutter_input_device_get_n_mode_groups (pad);
if (!info->group_modes || n_groups == 0)
return 0;
if (action_type == META_PAD_ACTION_RING ||
action_type == META_PAD_ACTION_STRIP)
{
/* Assume features are evenly distributed in groups */
group = number % n_groups;
}
return info->group_modes[group];
}
gchar *
meta_pad_action_mapper_get_action_label (MetaPadActionMapper *mapper,
ClutterInputDevice *pad,
MetaPadActionType action_type,
guint number)
{
guint mode;
switch (action_type)
{
case META_PAD_ACTION_BUTTON:
return meta_pad_action_mapper_get_button_label (mapper, pad, number);
case META_PAD_ACTION_RING:
mode = get_current_pad_mode (mapper, pad, action_type, number);
return meta_pad_action_mapper_get_ring_label (mapper, pad, number, mode);
case META_PAD_ACTION_STRIP:
mode = get_current_pad_mode (mapper, pad, action_type, number);
return meta_pad_action_mapper_get_strip_label (mapper, pad, number, mode);
}
return NULL;
}

View File

@ -0,0 +1,46 @@
/*
* 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_PAD_ACTION_MAPPER_H
#define META_PAD_ACTION_MAPPER_H
#include <clutter/clutter.h>
#include "meta/display.h"
#define META_TYPE_PAD_ACTION_MAPPER (meta_pad_action_mapper_get_type ())
G_DECLARE_FINAL_TYPE (MetaPadActionMapper, meta_pad_action_mapper,
META, PAD_ACTION_MAPPER, GObject)
MetaPadActionMapper * meta_pad_action_mapper_new (void);
gboolean meta_pad_action_mapper_is_button_grabbed (MetaPadActionMapper *mapper,
ClutterInputDevice *pad,
guint button);
gboolean meta_pad_action_mapper_handle_event (MetaPadActionMapper *mapper,
const ClutterEvent *event);
gchar * meta_pad_action_mapper_get_action_label (MetaPadActionMapper *mapper,
ClutterInputDevice *pad,
MetaPadActionType action,
guint number);
#endif /* META_PAD_ACTION_MAPPER_H */

View File

@ -8183,19 +8183,19 @@ window_focus_on_pointer_rest_callback (gpointer data)
MetaDisplay *display = window->display;
MetaBackend *backend = meta_get_backend ();
MetaCursorTracker *cursor_tracker = meta_backend_get_cursor_tracker (backend);
int root_x, root_y;
graphene_point_t point;
guint32 timestamp;
if (meta_prefs_get_focus_mode () == G_DESKTOP_FOCUS_MODE_CLICK)
goto out;
meta_cursor_tracker_get_pointer (cursor_tracker, &root_x, &root_y, NULL);
meta_cursor_tracker_get_pointer (cursor_tracker, &point, NULL);
if (root_x != focus_data->pointer_x ||
root_y != focus_data->pointer_y)
if ((int) point.x != focus_data->pointer_x ||
(int) point.y != focus_data->pointer_y)
{
focus_data->pointer_x = root_x;
focus_data->pointer_y = root_y;
focus_data->pointer_x = point.x;
focus_data->pointer_y = point.y;
return G_SOURCE_CONTINUE;
}

View File

@ -233,6 +233,8 @@ mutter_sources = [
'backends/meta-settings-private.h',
'backends/meta-stage.c',
'backends/meta-stage-private.h',
'backends/meta-viewport-info.c',
'backends/meta-viewport-info.h',
'backends/x11/cm/meta-backend-x11-cm.c',
'backends/x11/cm/meta-backend-x11-cm.h',
'backends/x11/cm/meta-cursor-sprite-xfixes.c',
@ -374,6 +376,7 @@ mutter_sources = [
'core/meta-inhibit-shortcuts-dialog-default.c',
'core/meta-inhibit-shortcuts-dialog-default-private.h',
'core/meta-launch-context.c',
'core/meta-pad-action-mapper.c',
'core/meta-selection.c',
'core/meta-selection-source.c',
'core/meta-selection-source-memory.c',
@ -672,6 +675,8 @@ if have_native_backend
'backends/native/meta-kms-crtc-private.h',
'backends/native/meta-kms-crtc.c',
'backends/native/meta-kms-crtc.h',
'backends/native/meta-kms-cursor-renderer.c',
'backends/native/meta-kms-cursor-renderer.h',
'backends/native/meta-kms-device-private.h',
'backends/native/meta-kms-device.c',
'backends/native/meta-kms-device.h',
@ -695,9 +700,13 @@ if have_native_backend
'backends/native/meta-kms-utils.h',
'backends/native/meta-kms.c',
'backends/native/meta-kms.h',
'backends/native/meta-pointer-constraint-native.c',
'backends/native/meta-pointer-constraint-native.h',
'backends/native/meta-renderer-native-gles3.c',
'backends/native/meta-renderer-native-gles3.h',
'backends/native/meta-renderer-native.h',
'backends/native/meta-seat-impl.c',
'backends/native/meta-seat-impl.h',
'backends/native/meta-seat-native.c',
'backends/native/meta-seat-native.h',
'backends/native/meta-stage-native.c',
@ -749,14 +758,6 @@ dbus_idle_monitor_built_sources = gnome.gdbus_codegen('meta-dbus-idle-monitor',
)
mutter_built_sources += dbus_idle_monitor_built_sources
mutter_marshal = gnome.genmarshal('meta-marshal',
sources: ['meta-marshal.list'],
prefix: 'meta_marshal',
internal: true,
valist_marshallers: true,
)
mutter_built_sources += mutter_marshal
if have_profiler
mutter_sources += [
'backends/meta-profiler.c',

View File

@ -1 +0,0 @@
VOID:FLOAT,FLOAT

View File

@ -50,8 +50,7 @@ CoglTexture *meta_cursor_tracker_get_sprite (MetaCursorTracker *tracker);
META_EXPORT
void meta_cursor_tracker_get_pointer (MetaCursorTracker *tracker,
int *x,
int *y,
graphene_point_t *coords,
ClutterModifierType *mods);
META_EXPORT

View File

@ -173,8 +173,6 @@ seat_device_added_cb (ClutterSeat *seat,
g_print ("*** enabling device '%s' ***\n",
clutter_input_device_get_device_name (device));
clutter_input_device_set_enabled (device, TRUE);
hand = clutter_test_utils_create_texture_from_file (TESTS_DATADIR
G_DIR_SEPARATOR_S
"redhand.png",
@ -272,8 +270,6 @@ test_devices_main (int argc, char **argv)
g_print ("*** enabling device '%s' ***\n",
clutter_input_device_get_device_name (device));
clutter_input_device_set_enabled (device, TRUE);
hand = clutter_test_utils_create_texture_from_file (TESTS_DATADIR
G_DIR_SEPARATOR_S
"redhand.png",

View File

@ -1,6 +1,7 @@
#include <stdlib.h>
#include <glib.h>
#include <clutter/clutter.h>
#include <clutter/clutter-mutter.h>
#include "tests/clutter-test-utils.h"
@ -109,7 +110,6 @@ static gboolean perf_fake_mouse_cb (gpointer stage)
event2->crossing.related = NULL;
clutter_event_set_device (event2, device);
clutter_input_device_update_from_event (device, event2, TRUE);
clutter_event_put (event2);
clutter_event_free (event2);

View File

@ -41,667 +41,70 @@
#include "backends/meta-backend-private.h"
#include "backends/meta-pointer-constraint.h"
#include "compositor/meta-surface-actor-wayland.h"
#include "core/meta-border.h"
#include "wayland/meta-wayland-pointer-constraints.h"
#include "wayland/meta-wayland-pointer.h"
#include "wayland/meta-wayland-seat.h"
#include "wayland/meta-wayland-surface.h"
struct _MetaPointerConfinementWayland
{
MetaPointerConstraint parent;
typedef struct _MetaPointerConfinementWaylandPrivate MetaPointerConfinementWaylandPrivate;
struct _MetaPointerConfinementWaylandPrivate
{
MetaWaylandPointerConstraint *constraint;
gboolean enabled;
};
typedef struct _MetaBox
enum
{
int x1;
int y1;
int x2;
int y2;
} MetaBox;
G_DEFINE_TYPE (MetaPointerConfinementWayland, meta_pointer_confinement_wayland,
META_TYPE_POINTER_CONSTRAINT);
static MetaBorder *
add_border (GArray *borders,
float x1, float y1,
float x2, float y2,
MetaBorderMotionDirection blocking_directions)
{
MetaBorder border;
border = (MetaBorder) {
.line = (MetaLine2) {
.a = (MetaVector2) {
.x = x1,
.y = y1,
},
.b = (MetaVector2) {
.x = x2,
.y = y2,
},
},
.blocking_directions = blocking_directions,
PROP_0,
PROP_WAYLAND_POINTER_CONSTRAINT,
N_PROPS,
};
g_array_append_val (borders, border);
static GParamSpec *props[N_PROPS] = { 0 };
return &g_array_index (borders, MetaBorder, borders->len - 1);
}
static gint
compare_lines_x (gconstpointer a, gconstpointer b)
{
const MetaBorder *border_a = a;
const MetaBorder *border_b = b;
if (border_a->line.a.x == border_b->line.a.x)
return border_a->line.b.x < border_b->line.b.x;
else
return border_a->line.a.x > border_b->line.a.x;
}
G_DEFINE_TYPE_WITH_PRIVATE (MetaPointerConfinementWayland,
meta_pointer_confinement_wayland,
G_TYPE_OBJECT)
static void
add_non_overlapping_edges (MetaBox *boxes,
unsigned int band_above_start,
unsigned int band_below_start,
unsigned int band_below_end,
GArray *borders)
meta_pointer_confinement_wayland_update (MetaPointerConfinementWayland *self)
{
unsigned int i;
GArray *band_merge;
MetaBorder *border;
MetaBorder *prev_border;
MetaBorder *new_border;
MetaPointerConstraint *constraint;
band_merge = g_array_new (FALSE, FALSE, sizeof *border);
/* Add bottom band of previous row, and top band of current row, and
* sort them so lower left x coordinate comes first. If there are two
* borders with the same left x coordinate, the wider one comes first.
*/
for (i = band_above_start; i < band_below_start; i++)
{
MetaBox *box = &boxes[i];
add_border (band_merge, box->x1, box->y2, box->x2, box->y2,
META_BORDER_MOTION_DIRECTION_POSITIVE_Y);
}
for (i = band_below_start; i < band_below_end; i++)
{
MetaBox *box= &boxes[i];
add_border (band_merge, box->x1, box->y1, box->x2, box->y1,
META_BORDER_MOTION_DIRECTION_NEGATIVE_Y);
}
g_array_sort (band_merge, compare_lines_x);
/* Combine the two combined bands so that any overlapping border is
* eliminated. */
prev_border = NULL;
for (i = 0; i < band_merge->len; i++)
{
border = &g_array_index (band_merge, MetaBorder, i);
g_assert (border->line.a.y == border->line.b.y);
g_assert (!prev_border ||
prev_border->line.a.y == border->line.a.y);
g_assert (!prev_border ||
(prev_border->line.a.x != border->line.a.x ||
prev_border->line.b.x != border->line.b.x));
g_assert (!prev_border ||
prev_border->line.a.x <= border->line.a.x);
if (prev_border &&
prev_border->line.a.x == border->line.a.x)
{
/*
* ------------ +
* ------- =
* [ ]-----
*/
prev_border->line.a.x = border->line.b.x;
}
else if (prev_border &&
prev_border->line.b.x == border->line.b.x)
{
/*
* ------------ +
* ------ =
* ------[ ]
*/
prev_border->line.b.x = border->line.a.x;
}
else if (prev_border &&
prev_border->line.b.x == border->line.a.x)
{
/*
* -------- +
* ------ =
* --------------
*/
prev_border->line.b.x = border->line.b.x;
}
else if (prev_border &&
prev_border->line.b.x >= border->line.a.x)
{
/*
* --------------- +
* ------ =
* -----[ ]----
*/
new_border = add_border (borders,
border->line.b.x,
border->line.b.y,
prev_border->line.b.x,
prev_border->line.b.y,
prev_border->blocking_directions);
prev_border->line.b.x = border->line.a.x;
prev_border = new_border;
}
else
{
g_assert (!prev_border ||
prev_border->line.b.x < border->line.a.x);
/*
* First border or non-overlapping.
*
* ----- +
* ----- =
* ----- -----
*/
g_array_append_val (borders, *border);
prev_border = &g_array_index (borders, MetaBorder, borders->len - 1);
}
}
g_array_free (band_merge, FALSE);
}
static void
add_band_bottom_edges (MetaBox *boxes,
int band_start,
int band_end,
GArray *borders)
{
int i;
for (i = band_start; i < band_end; i++)
{
add_border (borders,
boxes[i].x1, boxes[i].y2,
boxes[i].x2, boxes[i].y2,
META_BORDER_MOTION_DIRECTION_POSITIVE_Y);
}
}
static void
region_to_outline (cairo_region_t *region,
GArray *borders)
{
MetaBox *boxes;
int num_boxes;
int i;
int top_most, bottom_most;
int current_roof;
int prev_top;
int band_start, prev_band_start;
/*
* Remove any overlapping lines from the set of rectangles. Note that
* pixman regions are grouped as rows of rectangles, where rectangles
* in one row never touch or overlap and are all of the same height.
*
* -------- --- -------- ---
* | | | | | | | |
* ----------====---- --- ----------- ----- ---
* | | => | |
* ----==========--------- ----- ----------
* | | | |
* ------------------- -------------------
*
*/
num_boxes = cairo_region_num_rectangles (region);
boxes = g_new (MetaBox, num_boxes);
for (i = 0; i < num_boxes; i++)
{
cairo_rectangle_int_t rect;
cairo_region_get_rectangle (region, i, &rect);
boxes[i] = (MetaBox) {
.x1 = rect.x,
.y1 = rect.y,
.x2 = rect.x + rect.width,
.y2 = rect.y + rect.height,
};
}
prev_top = 0;
top_most = boxes[0].y1;
current_roof = top_most;
bottom_most = boxes[num_boxes - 1].y2;
band_start = 0;
prev_band_start = 0;
for (i = 0; i < num_boxes; i++)
{
/* Detect if there is a vertical empty space, and add the lower
* level of the previous band if so was the case. */
if (i > 0 &&
boxes[i].y1 != prev_top &&
boxes[i].y1 != boxes[i - 1].y2)
{
current_roof = boxes[i].y1;
add_band_bottom_edges (boxes,
band_start,
i,
borders);
}
/* Special case adding the last band, since it won't be handled
* by the band change detection below. */
if (boxes[i].y1 != current_roof && i == num_boxes - 1)
{
if (boxes[i].y1 != prev_top)
{
/* The last band is a single box, so we don't
* have a prev_band_start to tell us when the
* previous band started. */
add_non_overlapping_edges (boxes,
band_start,
i,
i + 1,
borders);
}
else
{
add_non_overlapping_edges (boxes,
prev_band_start,
band_start,
i + 1,
borders);
}
}
/* Detect when passing a band and combine the top border of the
* just passed band with the bottom band of the previous band.
*/
if (boxes[i].y1 != top_most && boxes[i].y1 != prev_top)
{
/* Combine the two passed bands. */
if (prev_top != current_roof)
{
add_non_overlapping_edges (boxes,
prev_band_start,
band_start,
i,
borders);
}
prev_band_start = band_start;
band_start = i;
}
/* Add the top border if the box is part of the current roof. */
if (boxes[i].y1 == current_roof)
{
add_border (borders,
boxes[i].x1, boxes[i].y1,
boxes[i].x2, boxes[i].y1,
META_BORDER_MOTION_DIRECTION_NEGATIVE_Y);
}
/* Add the bottom border of the last band. */
if (boxes[i].y2 == bottom_most)
{
add_border (borders,
boxes[i].x1, boxes[i].y2,
boxes[i].x2, boxes[i].y2,
META_BORDER_MOTION_DIRECTION_POSITIVE_Y);
}
/* Always add the left border. */
add_border (borders,
boxes[i].x1, boxes[i].y1,
boxes[i].x1, boxes[i].y2,
META_BORDER_MOTION_DIRECTION_NEGATIVE_X);
/* Always add the right border. */
add_border (borders,
boxes[i].x2, boxes[i].y1,
boxes[i].x2, boxes[i].y2,
META_BORDER_MOTION_DIRECTION_POSITIVE_X);
prev_top = boxes[i].y1;
}
g_free (boxes);
}
static MetaBorder *
get_closest_border (GArray *borders,
MetaLine2 *motion,
uint32_t directions)
{
MetaBorder *border;
MetaVector2 intersection;
MetaVector2 delta;
float distance_2;
MetaBorder *closest_border = NULL;
float closest_distance_2 = DBL_MAX;
unsigned int i;
for (i = 0; i < borders->len; i++)
{
border = &g_array_index (borders, MetaBorder, i);
if (!meta_border_is_blocking_directions (border, directions))
continue;
if (!meta_line2_intersects_with (&border->line, motion, &intersection))
continue;
delta = meta_vector2_subtract (intersection, motion->a);
distance_2 = delta.x*delta.x + delta.y*delta.y;
if (distance_2 < closest_distance_2)
{
closest_border = border;
closest_distance_2 = distance_2;
}
}
return closest_border;
}
static void
clamp_to_border (MetaBorder *border,
MetaLine2 *motion,
uint32_t *motion_dir)
{
/*
* When clamping either rightward or downward motions, the motion needs to be
* clamped so that the destination coordinate does not end up on the border
* (see weston_pointer_clamp_event_to_region). Do this by clamping such
* motions to the border minus the smallest possible wl_fixed_t value.
*
* When clamping in either leftward or upward motion, the resulting coordinate
* needs to be clamped so that it is enough on the inside to avoid the
* inaccuracies of clutter's stage to actor transformation algorithm (the one
* used in clutter_actor_transform_stage_point) to make it end up outside the
* next motion. It also needs to be clamped so that to the wl_fixed_t
* coordinate may still be right on the border (i.e. at .0). Testing shows
* that the smallest wl_fixed_t value divided by 10 is small enough to make
* the wl_fixed_t coordinate .0 and large enough to avoid the inaccuracies of
* clutters transform algorithm.
*/
if (meta_border_is_horizontal (border))
{
if (*motion_dir & META_BORDER_MOTION_DIRECTION_POSITIVE_Y)
motion->b.y = border->line.a.y - wl_fixed_to_double (1);
else
motion->b.y = border->line.a.y + wl_fixed_to_double (1) / 10;
*motion_dir &= ~(META_BORDER_MOTION_DIRECTION_POSITIVE_Y |
META_BORDER_MOTION_DIRECTION_NEGATIVE_Y);
}
else
{
if (*motion_dir & META_BORDER_MOTION_DIRECTION_POSITIVE_X)
motion->b.x = border->line.a.x - wl_fixed_to_double (1);
else
motion->b.x = border->line.a.x + wl_fixed_to_double (1) / 10;
*motion_dir &= ~(META_BORDER_MOTION_DIRECTION_POSITIVE_X |
META_BORDER_MOTION_DIRECTION_NEGATIVE_X);
}
}
static uint32_t
get_motion_directions (MetaLine2 *motion)
{
uint32_t directions = 0;
if (motion->a.x < motion->b.x)
directions |= META_BORDER_MOTION_DIRECTION_POSITIVE_X;
else if (motion->a.x > motion->b.x)
directions |= META_BORDER_MOTION_DIRECTION_NEGATIVE_X;
if (motion->a.y < motion->b.y)
directions |= META_BORDER_MOTION_DIRECTION_POSITIVE_Y;
else if (motion->a.y > motion->b.y)
directions |= META_BORDER_MOTION_DIRECTION_NEGATIVE_Y;
return directions;
}
static void
meta_pointer_confinement_wayland_constrain (MetaPointerConstraint *constraint,
ClutterInputDevice *device,
guint32 time,
float prev_x,
float prev_y,
float *x,
float *y)
{
MetaPointerConfinementWayland *self =
META_POINTER_CONFINEMENT_WAYLAND (constraint);
MetaWaylandSurface *surface;
cairo_region_t *region;
float sx, sy;
float prev_sx, prev_sy;
GArray *borders;
MetaLine2 motion;
MetaBorder *closest_border;
uint32_t directions;
surface = meta_wayland_pointer_constraint_get_surface (self->constraint);
meta_wayland_surface_get_relative_coordinates (surface, *x, *y, &sx, &sy);
meta_wayland_surface_get_relative_coordinates (surface, prev_x, prev_y,
&prev_sx, &prev_sy);
/* For motions in a positive direction on any axis, append the smallest
* possible value representable in a Wayland absolute coordinate. This is
* in order to avoid not clamping motion that as a floating point number
* won't be clamped, but will be rounded up to be outside of the range
* of wl_fixed_t. */
if (sx > prev_sx)
sx += (float)wl_fixed_to_double(1);
if (sy > prev_sy)
sy += (float)wl_fixed_to_double(1);
borders = g_array_new (FALSE, FALSE, sizeof (MetaBorder));
/*
* Generate borders given the confine region we are to use. The borders
* are defined to be the outer region of the allowed area. This means
* top/left borders are "within" the allowed area, while bottom/right
* borders are outside. This needs to be considered when clamping
* confined motion vectors.
*/
region =
meta_wayland_pointer_constraint_calculate_effective_region (self->constraint);
region_to_outline (region, borders);
cairo_region_destroy (region);
motion = (MetaLine2) {
.a = (MetaVector2) {
.x = prev_sx,
.y = prev_sy,
},
.b = (MetaVector2) {
.x = sx,
.y = sy,
},
};
directions = get_motion_directions (&motion);
while (directions)
{
closest_border = get_closest_border (borders,
&motion,
directions);
if (closest_border)
clamp_to_border (closest_border, &motion, &directions);
else
break;
}
meta_wayland_surface_get_absolute_coordinates (surface,
motion.b.x, motion.b.y,
x, y);
g_array_free (borders, FALSE);
}
static float
point_to_border_distance_2 (MetaBorder *border,
float x,
float y)
{
float orig_x, orig_y;
float dx, dy;
if (meta_border_is_horizontal (border))
{
if (x < border->line.a.x)
orig_x = border->line.a.x;
else if (x > border->line.b.x)
orig_x = border->line.b.x;
else
orig_x = x;
orig_y = border->line.a.y;
}
else
{
if (y < border->line.a.y)
orig_y = border->line.a.y;
else if (y > border->line.b.y)
orig_y = border->line.b.y;
else
orig_y = y;
orig_x = border->line.a.x;
}
dx = fabsf (orig_x - x);
dy = fabsf (orig_y - y);
return dx*dx + dy*dy;
}
static void
warp_to_behind_border (MetaBorder *border,
float *sx,
float *sy)
{
switch (border->blocking_directions)
{
case META_BORDER_MOTION_DIRECTION_POSITIVE_X:
case META_BORDER_MOTION_DIRECTION_NEGATIVE_X:
if (border->blocking_directions == META_BORDER_MOTION_DIRECTION_POSITIVE_X)
*sx = border->line.a.x - wl_fixed_to_double (1);
else
*sx = border->line.a.x + wl_fixed_to_double (1);
if (*sy < border->line.a.y)
*sy = border->line.a.y + wl_fixed_to_double (1);
else if (*sy > border->line.b.y)
*sy = border->line.b.y - wl_fixed_to_double (1);
break;
case META_BORDER_MOTION_DIRECTION_POSITIVE_Y:
case META_BORDER_MOTION_DIRECTION_NEGATIVE_Y:
if (border->blocking_directions == META_BORDER_MOTION_DIRECTION_POSITIVE_Y)
*sy = border->line.a.y - wl_fixed_to_double (1);
else
*sy = border->line.a.y + wl_fixed_to_double (1);
if (*sx < border->line.a.x)
*sx = border->line.a.x + wl_fixed_to_double (1);
else if (*sx > (border->line.b.x))
*sx = border->line.b.x - wl_fixed_to_double (1);
break;
}
}
static void
meta_pointer_confinement_wayland_maybe_warp (MetaPointerConfinementWayland *self)
{
MetaWaylandSeat *seat;
MetaWaylandSurface *surface;
graphene_point_t point;
float sx;
float sy;
cairo_region_t *region;
seat = meta_wayland_pointer_constraint_get_seat (self->constraint);
surface = meta_wayland_pointer_constraint_get_surface (self->constraint);
clutter_input_device_get_coords (seat->pointer->device, NULL, &point);
meta_wayland_surface_get_relative_coordinates (surface,
point.x, point.y,
&sx, &sy);
region =
meta_wayland_pointer_constraint_calculate_effective_region (self->constraint);
if (!cairo_region_contains_point (region, (int)sx, (int)sy))
{
GArray *borders;
float closest_distance_2 = FLT_MAX;
MetaBorder *closest_border = NULL;
ClutterSeat *seat;
unsigned int i;
float x;
float y;
borders = g_array_new (FALSE, FALSE, sizeof (MetaBorder));
region_to_outline (region, borders);
for (i = 0; i < borders->len; i++)
{
MetaBorder *border = &g_array_index (borders, MetaBorder, i);
float distance_2;
distance_2 = point_to_border_distance_2 (border, sx, sy);
if (distance_2 < closest_distance_2)
{
closest_border = border;
closest_distance_2 = distance_2;
}
}
warp_to_behind_border (closest_border, &sx, &sy);
meta_wayland_surface_get_absolute_coordinates (surface, sx, sy, &x, &y);
seat = clutter_backend_get_default_seat (clutter_get_default_backend ());
clutter_seat_warp_pointer (seat, (int)x, (int)y);
}
cairo_region_destroy (region);
constraint =
META_POINTER_CONFINEMENT_WAYLAND_GET_CLASS (self)->create_constraint (self);
meta_backend_set_client_pointer_constraint (meta_get_backend (), constraint);
g_object_unref (constraint);
}
static void
surface_geometry_changed (MetaWaylandSurface *surface,
MetaPointerConfinementWayland *self)
{
meta_pointer_confinement_wayland_maybe_warp (self);
meta_pointer_confinement_wayland_update (self);
}
static void
window_position_changed (MetaWindow *window,
MetaPointerConfinementWayland *self)
{
meta_pointer_confinement_wayland_maybe_warp (self);
meta_pointer_confinement_wayland_update (self);
}
MetaPointerConstraint *
meta_pointer_confinement_wayland_new (MetaWaylandPointerConstraint *constraint)
void
meta_pointer_confinement_wayland_enable (MetaPointerConfinementWayland *confinement)
{
GObject *object;
MetaPointerConfinementWayland *confinement;
MetaPointerConfinementWaylandPrivate *priv;
MetaWaylandPointerConstraint *constraint;
MetaWaylandSurface *surface;
MetaWindow *window;
object = g_object_new (META_TYPE_POINTER_CONFINEMENT_WAYLAND, NULL);
confinement = META_POINTER_CONFINEMENT_WAYLAND (object);
priv = meta_pointer_confinement_wayland_get_instance_private (confinement);
g_assert (!priv->enabled);
confinement->constraint = constraint;
priv->enabled = TRUE;
constraint = priv->constraint;
surface = meta_wayland_pointer_constraint_get_surface (constraint);
g_signal_connect_object (surface,
@ -720,7 +123,34 @@ meta_pointer_confinement_wayland_new (MetaWaylandPointerConstraint *constraint)
0);
}
return META_POINTER_CONSTRAINT (confinement);
meta_pointer_confinement_wayland_update (confinement);
}
void
meta_pointer_confinement_wayland_disable (MetaPointerConfinementWayland *confinement)
{
MetaPointerConfinementWaylandPrivate *priv;
MetaWaylandPointerConstraint *constraint;
MetaWaylandSurface *surface;
MetaWindow *window;
priv = meta_pointer_confinement_wayland_get_instance_private (confinement);
constraint = priv->constraint;
g_assert (priv->enabled);
priv->enabled = FALSE;
surface = meta_wayland_pointer_constraint_get_surface (constraint);
g_signal_handlers_disconnect_by_func (surface, surface_geometry_changed,
confinement);
window = meta_wayland_surface_get_window (surface);
if (window)
{
g_signal_handlers_disconnect_by_func (window, window_position_changed,
confinement);
}
meta_backend_set_client_pointer_constraint (meta_get_backend (), NULL);
}
static void
@ -728,11 +158,110 @@ meta_pointer_confinement_wayland_init (MetaPointerConfinementWayland *confinemen
{
}
static void
meta_pointer_confinement_wayland_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
MetaPointerConfinementWayland *confinement;
MetaPointerConfinementWaylandPrivate *priv;
confinement = META_POINTER_CONFINEMENT_WAYLAND (object);
priv = meta_pointer_confinement_wayland_get_instance_private (confinement);
switch (prop_id)
{
case PROP_WAYLAND_POINTER_CONSTRAINT:
g_value_set_object (value, priv->constraint);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
meta_pointer_confinement_wayland_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
MetaPointerConfinementWayland *confinement;
MetaPointerConfinementWaylandPrivate *priv;
confinement = META_POINTER_CONFINEMENT_WAYLAND (object);
priv = meta_pointer_confinement_wayland_get_instance_private (confinement);
switch (prop_id)
{
case PROP_WAYLAND_POINTER_CONSTRAINT:
priv->constraint = g_value_get_object (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static MetaPointerConstraint *
meta_pointer_confinement_wayland_create_constraint (MetaPointerConfinementWayland *confinement)
{
MetaPointerConfinementWaylandPrivate *priv;
MetaPointerConstraint *constraint;
MetaWaylandSurface *surface;
cairo_region_t *region;
float dx, dy;
priv = meta_pointer_confinement_wayland_get_instance_private (confinement);
surface = meta_wayland_pointer_constraint_get_surface (priv->constraint);
region =
meta_wayland_pointer_constraint_calculate_effective_region (priv->constraint);
meta_wayland_surface_get_absolute_coordinates (surface, 0, 0, &dx, &dy);
cairo_region_translate (region, dx, dy);
constraint = meta_pointer_constraint_new (region);
cairo_region_destroy (region);
return constraint;
}
static void
meta_pointer_confinement_wayland_class_init (MetaPointerConfinementWaylandClass *klass)
{
MetaPointerConstraintClass *pointer_constraint_class =
META_POINTER_CONSTRAINT_CLASS (klass);
GObjectClass *object_class = G_OBJECT_CLASS (klass);
pointer_constraint_class->constrain = meta_pointer_confinement_wayland_constrain;
object_class->set_property = meta_pointer_confinement_wayland_set_property;
object_class->get_property = meta_pointer_confinement_wayland_get_property;
klass->create_constraint = meta_pointer_confinement_wayland_create_constraint;
props[PROP_WAYLAND_POINTER_CONSTRAINT] =
g_param_spec_object ("wayland-pointer-constraint",
"Wayland pointer constraint",
"Wayland pointer constraint",
META_TYPE_WAYLAND_POINTER_CONSTRAINT,
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS);
g_object_class_install_properties (object_class, N_PROPS, props);
}
MetaPointerConfinementWayland *
meta_pointer_confinement_wayland_new (MetaWaylandPointerConstraint *constraint)
{
return g_object_new (META_TYPE_POINTER_CONFINEMENT_WAYLAND,
"wayland-pointer-constraint", constraint,
NULL);
}
MetaWaylandPointerConstraint *
meta_pointer_confinement_wayland_get_wayland_pointer_constraint (MetaPointerConfinementWayland *confinement)
{
MetaPointerConfinementWaylandPrivate *priv;
priv = meta_pointer_confinement_wayland_get_instance_private (confinement);
return priv->constraint;
}

View File

@ -33,12 +33,23 @@
G_BEGIN_DECLS
#define META_TYPE_POINTER_CONFINEMENT_WAYLAND (meta_pointer_confinement_wayland_get_type ())
G_DECLARE_FINAL_TYPE (MetaPointerConfinementWayland,
G_DECLARE_DERIVABLE_TYPE (MetaPointerConfinementWayland,
meta_pointer_confinement_wayland,
META, POINTER_CONFINEMENT_WAYLAND,
MetaPointerConstraint);
GObject)
MetaPointerConstraint *meta_pointer_confinement_wayland_new (MetaWaylandPointerConstraint *constraint);
struct _MetaPointerConfinementWaylandClass
{
GObjectClass parent_class;
MetaPointerConstraint * (*create_constraint) (MetaPointerConfinementWayland *confinement);
};
MetaPointerConfinementWayland *meta_pointer_confinement_wayland_new (MetaWaylandPointerConstraint *constraint);
MetaWaylandPointerConstraint *
meta_pointer_confinement_wayland_get_wayland_pointer_constraint (MetaPointerConfinementWayland *confinement);
void meta_pointer_confinement_wayland_enable (MetaPointerConfinementWayland *confinement);
void meta_pointer_confinement_wayland_disable (MetaPointerConfinementWayland *confinement);
G_END_DECLS

View File

@ -37,33 +37,55 @@
#include <glib-object.h>
#include "backends/meta-pointer-constraint.h"
#include "backends/meta-backend-private.h"
#include "compositor/meta-surface-actor-wayland.h"
struct _MetaPointerLockWayland
{
MetaPointerConstraint parent;
GObject parent;
MetaWaylandPointerConstraint *constraint;
};
G_DEFINE_TYPE (MetaPointerLockWayland, meta_pointer_lock_wayland,
META_TYPE_POINTER_CONSTRAINT);
META_TYPE_POINTER_CONFINEMENT_WAYLAND)
static void
meta_pointer_lock_wayland_constrain (MetaPointerConstraint *constraint,
ClutterInputDevice *device,
guint32 time,
float prev_x,
float prev_y,
float *x,
float *y)
static MetaPointerConstraint *
meta_pointer_lock_wayland_create_constraint (MetaPointerConfinementWayland *confinement)
{
*x = prev_x;
*y = prev_y;
MetaBackend *backend = meta_get_backend ();
ClutterBackend *clutter_backend = meta_backend_get_clutter_backend (backend);
ClutterSeat *seat = clutter_backend_get_default_seat (clutter_backend);
ClutterInputDevice *pointer = clutter_seat_get_pointer (seat);
MetaWaylandPointerConstraint *wayland_constraint;
MetaPointerConstraint *constraint;
MetaWaylandSurface *surface;
graphene_point_t point;
cairo_region_t *region;
float sx, sy, x, y;
clutter_input_device_get_coords (pointer, NULL, &point);
wayland_constraint =
meta_pointer_confinement_wayland_get_wayland_pointer_constraint (confinement);
surface = meta_wayland_pointer_constraint_get_surface (wayland_constraint);
meta_wayland_surface_get_relative_coordinates (surface,
point.x, point.y,
&sx, &sy);
meta_wayland_surface_get_absolute_coordinates (surface, sx, sy, &x, &y);
region = cairo_region_create_rectangle (&(cairo_rectangle_int_t) { (int) x, (int) y, 1 , 1 });
constraint = meta_pointer_constraint_new (region);
cairo_region_destroy (region);
return constraint;
}
MetaPointerConstraint *
meta_pointer_lock_wayland_new (void)
MetaPointerConfinementWayland *
meta_pointer_lock_wayland_new (MetaWaylandPointerConstraint *constraint)
{
return g_object_new (META_TYPE_POINTER_LOCK_WAYLAND, NULL);
return g_object_new (META_TYPE_POINTER_LOCK_WAYLAND,
"wayland-pointer-constraint", constraint,
NULL);
}
static void
@ -74,8 +96,9 @@ meta_pointer_lock_wayland_init (MetaPointerLockWayland *lock_wayland)
static void
meta_pointer_lock_wayland_class_init (MetaPointerLockWaylandClass *klass)
{
MetaPointerConstraintClass *pointer_constraint_class =
META_POINTER_CONSTRAINT_CLASS (klass);
MetaPointerConfinementWaylandClass *confinement_class =
META_POINTER_CONFINEMENT_WAYLAND_CLASS (klass);
pointer_constraint_class->constrain = meta_pointer_lock_wayland_constrain;
confinement_class->create_constraint =
meta_pointer_lock_wayland_create_constraint;
}

View File

@ -27,15 +27,15 @@
#include <glib-object.h>
#include "backends/meta-pointer-constraint.h"
#include "wayland/meta-pointer-confinement-wayland.h"
G_BEGIN_DECLS
#define META_TYPE_POINTER_LOCK_WAYLAND (meta_pointer_lock_wayland_get_type ())
G_DECLARE_FINAL_TYPE (MetaPointerLockWayland, meta_pointer_lock_wayland,
META, POINTER_LOCK_WAYLAND, MetaPointerConstraint);
META, POINTER_LOCK_WAYLAND, MetaPointerConfinementWayland)
MetaPointerConstraint *meta_pointer_lock_wayland_new (void);
MetaPointerConfinementWayland *meta_pointer_lock_wayland_new (MetaWaylandPointerConstraint *constraint);
G_END_DECLS

View File

@ -81,6 +81,7 @@ update_cursor_sprite_texture (MetaWaylandCursorSurface *cursor_surface)
static void
cursor_sprite_prepare_at (MetaCursorSprite *cursor_sprite,
float best_scale,
int x,
int y,
MetaWaylandCursorSurface *cursor_surface)
@ -186,6 +187,7 @@ meta_wayland_cursor_surface_is_on_logical_monitor (MetaWaylandSurfaceRole *role,
META_WAYLAND_CURSOR_SURFACE (surface->role);
MetaWaylandCursorSurfacePrivate *priv =
meta_wayland_cursor_surface_get_instance_private (cursor_surface);
ClutterInputDevice *device;
graphene_point_t point;
graphene_rect_t logical_monitor_rect;
@ -195,7 +197,8 @@ meta_wayland_cursor_surface_is_on_logical_monitor (MetaWaylandSurfaceRole *role,
logical_monitor_rect =
meta_rectangle_to_graphene_rect (&logical_monitor->rect);
point = meta_cursor_renderer_get_position (priv->cursor_renderer);
device = meta_cursor_renderer_get_input_device (priv->cursor_renderer);
clutter_input_device_get_coords (device, NULL, &point);
return graphene_rect_contains_point (&logical_monitor_rect, &point);
}

View File

@ -74,16 +74,15 @@ static MetaLogicalMonitor *
dnd_surface_find_logical_monitor (MetaWaylandActorSurface *actor_surface)
{
MetaBackend *backend = meta_get_backend ();
MetaCursorRenderer *cursor_renderer =
meta_backend_get_cursor_renderer (backend);
MetaCursorTracker *cursor_tracker =
meta_backend_get_cursor_tracker (backend);
MetaMonitorManager *monitor_manager =
meta_backend_get_monitor_manager (backend);
graphene_point_t pointer_pos;
graphene_point_t point;
pointer_pos = meta_cursor_renderer_get_position (cursor_renderer);
meta_cursor_tracker_get_pointer (cursor_tracker, &point, NULL);
return meta_monitor_manager_get_logical_monitor_at (monitor_manager,
pointer_pos.x,
pointer_pos.y);
point.x, point.y);
}
static double

View File

@ -68,7 +68,7 @@ struct _MetaWaylandPointerConstraint
wl_fixed_t x_hint;
wl_fixed_t y_hint;
MetaPointerConstraint *constraint;
MetaPointerConfinementWayland *confinement;
};
typedef struct _MetaWaylandSurfacePointerConstraintsData
@ -375,7 +375,7 @@ meta_wayland_pointer_constraint_notify_deactivated (MetaWaylandPointerConstraint
zwp_confined_pointer_v1_send_unconfined (resource);
}
static MetaPointerConstraint *
static MetaPointerConfinementWayland *
meta_wayland_pointer_constraint_create_pointer_constraint (MetaWaylandPointerConstraint *constraint)
{
struct wl_resource *resource = constraint->resource;
@ -384,7 +384,7 @@ meta_wayland_pointer_constraint_create_pointer_constraint (MetaWaylandPointerCon
&zwp_locked_pointer_v1_interface,
&locked_pointer_interface))
{
return meta_pointer_lock_wayland_new ();
return meta_pointer_lock_wayland_new (constraint);
}
else if (wl_resource_instance_of (resource,
&zwp_confined_pointer_v1_interface,
@ -399,8 +399,6 @@ meta_wayland_pointer_constraint_create_pointer_constraint (MetaWaylandPointerCon
static void
meta_wayland_pointer_constraint_enable (MetaWaylandPointerConstraint *constraint)
{
MetaBackend *backend = meta_get_backend ();
g_assert (!constraint->is_enabled);
constraint->is_enabled = TRUE;
@ -408,20 +406,25 @@ meta_wayland_pointer_constraint_enable (MetaWaylandPointerConstraint *constraint
meta_wayland_pointer_start_grab (constraint->seat->pointer,
&constraint->grab);
constraint->constraint =
constraint->confinement =
meta_wayland_pointer_constraint_create_pointer_constraint (constraint);
meta_backend_set_client_pointer_constraint (backend, constraint->constraint);
g_object_add_weak_pointer (G_OBJECT (constraint->constraint),
(gpointer *) &constraint->constraint);
g_object_unref (constraint->constraint);
meta_pointer_confinement_wayland_enable (constraint->confinement);
g_object_add_weak_pointer (G_OBJECT (constraint->confinement),
(gpointer *) &constraint->confinement);
}
static void
meta_wayland_pointer_constraint_disable (MetaWaylandPointerConstraint *constraint)
{
constraint->is_enabled = FALSE;
if (constraint->confinement)
{
meta_pointer_confinement_wayland_disable (constraint->confinement);
g_object_unref (constraint->confinement);
}
meta_wayland_pointer_constraint_notify_deactivated (constraint);
meta_backend_set_client_pointer_constraint (meta_get_backend (), NULL);
meta_wayland_pointer_end_grab (constraint->grab.pointer);
}

View File

@ -1044,7 +1044,11 @@ meta_wayland_pointer_start_popup_grab (MetaWaylandPointer *pointer,
void
meta_wayland_pointer_repick (MetaWaylandPointer *pointer)
{
clutter_input_device_update (pointer->device, NULL, FALSE);
MetaBackend *backend = meta_get_backend ();
ClutterStage *stage = CLUTTER_STAGE (meta_backend_get_stage (backend));
clutter_input_device_update (pointer->device, NULL, stage, FALSE,
CLUTTER_CURRENT_TIME);
repick_for_event (pointer, NULL);
}
@ -1164,8 +1168,13 @@ pointer_set_cursor (struct wl_client *client,
if (surface)
{
ClutterBackend *clutter_backend = clutter_get_default_backend ();
ClutterSeat *clutter_seat =
clutter_backend_get_default_seat (clutter_backend);
ClutterInputDevice *device = clutter_seat_get_pointer (clutter_seat);
MetaCursorRenderer *cursor_renderer =
meta_backend_get_cursor_renderer (meta_get_backend ());
meta_backend_get_cursor_renderer_for_device (meta_get_backend (),
device);
MetaWaylandCursorSurface *cursor_surface;
cursor_surface = META_WAYLAND_CURSOR_SURFACE (surface->role);

View File

@ -242,30 +242,3 @@ meta_wayland_tablet_manager_ensure_seat (MetaWaylandTabletManager *manager,
return tablet_seat;
}
void
meta_wayland_tablet_manager_update_cursor_position (MetaWaylandTabletManager *manager,
const ClutterEvent *event)
{
MetaWaylandTabletSeat *tablet_seat = NULL;
MetaWaylandTabletTool *tool = NULL;
ClutterInputDeviceTool *device_tool;
ClutterInputDevice *device;
device = clutter_event_get_source_device (event);
device_tool = clutter_event_get_device_tool (event);
if (device)
tablet_seat = meta_wayland_tablet_manager_lookup_seat (manager, device);
if (tablet_seat && device_tool)
tool = meta_wayland_tablet_seat_lookup_tool (tablet_seat, device_tool);
if (tool)
{
gfloat new_x, new_y;
clutter_event_get_coords (event, &new_x, &new_y);
meta_wayland_tablet_tool_set_cursor_position (tool, new_x, new_y);
}
}

View File

@ -50,7 +50,4 @@ MetaWaylandTabletSeat *
meta_wayland_tablet_manager_ensure_seat (MetaWaylandTabletManager *manager,
MetaWaylandSeat *seat);
void meta_wayland_tablet_manager_update_cursor_position (MetaWaylandTabletManager *manager,
const ClutterEvent *event);
#endif /* META_WAYLAND_TABLET_MANAGER_H */

View File

@ -28,6 +28,7 @@
#include <wayland-server.h>
#include "backends/meta-input-settings-private.h"
#include "core/display-private.h"
#include "compositor/meta-surface-actor-wayland.h"
#include "wayland/meta-wayland-private.h"
#include "wayland/meta-wayland-tablet-pad-group.h"
@ -244,15 +245,14 @@ tablet_pad_set_feedback (struct wl_client *client,
{
MetaWaylandTabletPad *pad = wl_resource_get_user_data (resource);
MetaWaylandTabletPadGroup *group = tablet_pad_lookup_button_group (pad, button);
MetaInputSettings *input_settings;
MetaPadActionMapper *mapper;
if (!group || group->mode_switch_serial != serial)
return;
input_settings = meta_backend_get_input_settings (meta_get_backend ());
mapper = meta_get_display ()->pad_action_mapper;
if (input_settings &&
meta_input_settings_is_pad_button_grabbed (input_settings, pad->device, button))
if (meta_pad_action_mapper_is_button_grabbed (mapper, pad->device, button))
return;
if (meta_wayland_tablet_pad_group_is_mode_switch_button (group, button))
@ -367,14 +367,13 @@ static gboolean
meta_wayland_tablet_pad_handle_event_action (MetaWaylandTabletPad *pad,
const ClutterEvent *event)
{
MetaInputSettings *input_settings;
MetaPadActionMapper *mapper;
ClutterInputDevice *device;
device = clutter_event_get_source_device (event);
input_settings = meta_backend_get_input_settings (meta_get_backend ());
mapper = meta_get_display ()->pad_action_mapper;
if (input_settings &&
meta_input_settings_is_pad_button_grabbed (input_settings, device,
if (meta_pad_action_mapper_is_button_grabbed (mapper, device,
event->pad_button.button))
return TRUE;

View File

@ -395,6 +395,7 @@ tablet_tool_handle_cursor_surface_destroy (struct wl_listener *listener,
static void
tool_cursor_prepare_at (MetaCursorSpriteXcursor *sprite_xcursor,
float best_scale,
int x,
int y,
MetaWaylandTabletTool *tool)
@ -931,7 +932,14 @@ meta_wayland_tablet_tool_update (MetaWaylandTabletTool *tool,
break;
case CLUTTER_PROXIMITY_IN:
if (!tool->cursor_renderer)
tool->cursor_renderer = meta_cursor_renderer_new (meta_get_backend ());
{
MetaCursorRenderer *renderer;
renderer =
meta_backend_get_cursor_renderer_for_device (meta_get_backend (),
clutter_event_get_source_device (event));
g_set_object (&tool->cursor_renderer, renderer);
}
tool->current_tablet =
meta_wayland_tablet_seat_lookup_tablet (tool->seat,
clutter_event_get_source_device (event));
@ -976,15 +984,6 @@ meta_wayland_tablet_tool_handle_event (MetaWaylandTabletTool *tool,
return CLUTTER_EVENT_STOP;
}
void
meta_wayland_tablet_tool_set_cursor_position (MetaWaylandTabletTool *tool,
float new_x,
float new_y)
{
if (tool->cursor_renderer)
meta_cursor_renderer_set_position (tool->cursor_renderer, new_x, new_y);
}
static gboolean
tablet_tool_can_grab_surface (MetaWaylandTabletTool *tool,
MetaWaylandSurface *surface)

View File

@ -78,10 +78,6 @@ void meta_wayland_tablet_tool_update (MetaWaylandTabletTool *t
gboolean meta_wayland_tablet_tool_handle_event (MetaWaylandTabletTool *tool,
const ClutterEvent *event);
void meta_wayland_tablet_tool_set_cursor_position (MetaWaylandTabletTool *tool,
float new_x,
float new_y);
gboolean meta_wayland_tablet_tool_can_grab_surface (MetaWaylandTabletTool *tool,
MetaWaylandSurface *surface,
uint32_t serial);

View File

@ -401,35 +401,34 @@ touch_send_frame_event (MetaWaylandTouch *touch)
g_list_free (surfaces);
}
static void
check_send_frame_event (MetaWaylandTouch *touch,
const ClutterEvent *event)
static gboolean
queue_frame_event_cb (MetaWaylandTouch *touch)
{
gboolean send_frame_event;
#ifdef HAVE_NATIVE_BACKEND
MetaBackend *backend = meta_get_backend ();
ClutterEventSequence *sequence;
gint32 slot;
if (META_IS_BACKEND_NATIVE (backend))
{
sequence = clutter_event_get_event_sequence (event);
slot = meta_event_native_sequence_get_slot (sequence);
touch->frame_slots &= ~(1 << slot);
if (touch->frame_slots == 0)
send_frame_event = TRUE;
else
send_frame_event = FALSE;
}
else
#endif /* HAVE_NATIVE_BACKEND */
{
send_frame_event = TRUE;
}
if (send_frame_event)
touch_send_frame_event (touch);
touch->queued_frame_id = 0;
return G_SOURCE_REMOVE;
}
static void
send_or_queue_frame_event (MetaWaylandTouch *touch)
{
if (clutter_events_pending ())
{
if (!touch->queued_frame_id)
{
touch->queued_frame_id =
g_idle_add_full (CLUTTER_PRIORITY_EVENTS + 1,
(GSourceFunc) queue_frame_event_cb,
touch, NULL);
}
}
else
{
/* There's no more events */
g_clear_handle_id (&touch->queued_frame_id, g_source_remove);
touch_send_frame_event (touch);
}
}
gboolean
@ -450,11 +449,15 @@ meta_wayland_touch_handle_event (MetaWaylandTouch *touch,
handle_touch_end (touch, event);
break;
case CLUTTER_TOUCH_CANCEL:
meta_wayland_touch_cancel (touch);
break;
default:
return FALSE;
}
check_send_frame_event (touch, event);
send_or_queue_frame_event (touch);
return FALSE;
}
@ -511,45 +514,6 @@ meta_wayland_touch_cancel (MetaWaylandTouch *touch)
g_list_free (surfaces);
}
#ifdef HAVE_NATIVE_BACKEND
static gboolean
evdev_filter_func (struct libinput_event *event,
gpointer data)
{
MetaWaylandTouch *touch = data;
switch (libinput_event_get_type (event))
{
case LIBINPUT_EVENT_TOUCH_DOWN:
case LIBINPUT_EVENT_TOUCH_UP:
case LIBINPUT_EVENT_TOUCH_MOTION: {
struct libinput_event_touch *touch_event;
int32_t slot;
touch_event = libinput_event_get_touch_event (event);
slot = libinput_event_touch_get_slot (touch_event);
/* XXX: Could theoretically overflow, 64 slots should be
* enough for most hw/usecases though.
*/
touch->frame_slots |= (1 << slot);
break;
}
case LIBINPUT_EVENT_TOUCH_CANCEL:
/* Clutter translates this into individual CLUTTER_TOUCH_CANCEL events,
* which are not so useful when sending a global signal as the protocol
* requires.
*/
meta_wayland_touch_cancel (touch);
break;
default:
break;
}
return CLUTTER_EVENT_PROPAGATE;
}
#endif
void
meta_wayland_touch_enable (MetaWaylandTouch *touch)
{
@ -561,35 +525,11 @@ meta_wayland_touch_enable (MetaWaylandTouch *touch)
#endif /* HAVE_NATIVE_BACKEND */
wl_list_init (&touch->resource_list);
#ifdef HAVE_NATIVE_BACKEND
MetaBackend *backend = meta_get_backend ();
if (META_IS_BACKEND_NATIVE (backend))
{
ClutterBackend *backend = clutter_get_default_backend ();
ClutterSeat *seat = clutter_backend_get_default_seat (backend);
meta_seat_native_add_filter (META_SEAT_NATIVE (seat),
evdev_filter_func, touch, NULL);
}
#endif
}
void
meta_wayland_touch_disable (MetaWaylandTouch *touch)
{
#ifdef HAVE_NATIVE_BACKEND
MetaBackend *backend = meta_get_backend ();
if (META_IS_BACKEND_NATIVE (backend))
{
ClutterBackend *backend = clutter_get_default_backend ();
ClutterSeat *seat = clutter_backend_get_default_seat (backend);
meta_seat_native_remove_filter (META_SEAT_NATIVE (seat),
evdev_filter_func, touch);
}
#endif
meta_wayland_touch_cancel (touch);
g_clear_pointer (&touch->touch_surfaces, g_hash_table_unref);

View File

@ -41,10 +41,9 @@ struct _MetaWaylandTouch
struct wl_list resource_list;
guint queued_frame_id;
GHashTable *touch_surfaces; /* HT of MetaWaylandSurface->MetaWaylandTouchSurface */
GHashTable *touches; /* HT of sequence->MetaWaylandTouchInfo */
guint64 frame_slots;
};
void meta_wayland_touch_enable (MetaWaylandTouch *touch);

View File

@ -2802,7 +2802,7 @@ query_pressed_buttons (MetaWindow *window)
ClutterModifierType mods;
int button = 0;
meta_cursor_tracker_get_pointer (tracker, NULL, NULL, &mods);
meta_cursor_tracker_get_pointer (tracker, NULL, &mods);
if (mods & CLUTTER_BUTTON1_MASK)
button |= 1 << 1;