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
905 changed files with 48308 additions and 75143 deletions

View File

@ -1,372 +1,117 @@
include:
- remote: 'https://gitlab.freedesktop.org/freedesktop/ci-templates/-/raw/bbe5232986c9b98eb1efe62484e07216f7d1a4df/templates/fedora.yml'
- remote: 'https://gitlab.freedesktop.org/freedesktop/ci-templates/-/raw/bbe5232986c9b98eb1efe62484e07216f7d1a4df/templates/ci-fairy.yml'
image: registry.gitlab.gnome.org/gnome/mutter/master:v4
stages:
- review
- prepare
- code-review
- build
- test
- analyze
- deploy
variables:
FDO_UPSTREAM_REPO: GNOME/mutter
.mutter.fedora:34@common:
variables:
FDO_DISTRIBUTION_VERSION: 34
BASE_TAG: '2021-09-04.1'
FDO_DISTRIBUTION_PACKAGES:
asciidoc
clang
gcovr
gdm
gnome-shell
python3-dbusmock
sassc
uncrustify
xorg-x11-server-Xvfb
FDO_DISTRIBUTION_EXEC: |
dnf install -y 'dnf-command(builddep)' &&
dnf builddep -y mutter --setopt=install_weak_deps=False &&
dnf builddep -y gnome-shell --setopt=install_weak_deps=False &&
./.gitlab-ci/install-meson-project.sh \
https://gitlab.gnome.org/GNOME/glib.git \
main . 02742ef957b532789c003eef80ec7f51c370e3d5 &&
./.gitlab-ci/install-meson-project.sh \
https://gitlab.gnome.org/GNOME/gsettings-desktop-schemas.git \
41.alpha . &&
./.gitlab-ci/install-meson-project.sh \
https://gitlab.gnome.org/GNOME/gjs.git \
1.69.2 . &&
rpm -e --nodeps gnome-bluetooth-libs-devel \
mutter mutter-devel \
gnome-shell &&
dnf clean all
default:
# Cancel jobs if newer commits are pushed to the branch
interruptible: true
# Auto-retry jobs in case of infra failures
retry:
max: 1
when:
- 'runner_system_failure'
- 'stuck_or_timeout_failure'
- 'scheduler_failure'
- 'api_failure'
.mutter.fedora:34@x86_64:
extends: .mutter.fedora:34@common
variables:
FDO_DISTRIBUTION_TAG: "x86_64-${BASE_TAG}"
.mutter.fedora:34@aarch64:
extends: .mutter.fedora:34@common
variables:
FDO_DISTRIBUTION_TAG: "aarch64-${BASE_TAG}"
tags:
- aarch64
workflow:
rules:
- if: '$CI_MERGE_REQUEST_IID'
- if: '$CI_COMMIT_TAG'
- if: '$CI_COMMIT_BRANCH'
.pipline-guard: &pipline-guard
rules:
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
- if: '$CI_COMMIT_TAG'
- if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH'
- if: '$CI_COMMIT_BRANCH =~ /^gnome-[0-9-]+$/'
- when: 'manual'
- coverage
check-commit-log:
extends:
- .fdo.ci-fairy
stage: review
variables:
GIT_DEPTH: "100"
script:
- if [[ x"$CI_MERGE_REQUEST_TARGET_BRANCH_NAME" != "x" ]] ;
then
ci-fairy check-commits --junit-xml=commit-message-junit-report.xml ;
else
echo "Not a merge request" ;
fi
artifacts:
expire_in: 1 week
paths:
- commit-message-junit-report.xml
reports:
junit: commit-message-junit-report.xml
<<: *pipline-guard
- ./.gitlab-ci/check-commit-log.sh
only:
- merge_requests
check-merge-request:
extends:
- .fdo.ci-fairy
stage: review
variables:
GIT_STRATEGY: none
script:
- if [[ x"$CI_MERGE_REQUEST_TARGET_BRANCH_NAME" != "x" ]] ;
then
ci-fairy check-merge-request --require-allow-collaboration --junit-xml=check-merge-request-report.xml ;
else
echo "Not a merge request" ;
fi
artifacts:
expire_in: 1 week
paths:
- check-merge-request-report.xml
reports:
junit: check-merge-request-report.xml
<<: *pipline-guard
build-fedora-container@x86_64:
extends:
- .fdo.container-build@fedora@x86_64
- .mutter.fedora:34@x86_64
stage: prepare
needs:
- check-commit-log
- check-merge-request
variables:
GIT_STRATEGY: none
build-fedora-container@aarch64:
extends:
- .fdo.container-build@fedora@aarch64
- .mutter.fedora:34@aarch64
stage: prepare
needs:
- check-commit-log
- check-merge-request
variables:
GIT_STRATEGY: none
check-code-style:
extends:
- .fdo.distribution-image@fedora
- .mutter.fedora:34@x86_64
stage: code-review
needs:
- build-fedora-container@x86_64
script:
- if [[ x"$CI_MERGE_REQUEST_TARGET_BRANCH_NAME" != "x" ]] ;
then
git remote add target $CI_MERGE_REQUEST_PROJECT_URL.git ;
git fetch target $CI_MERGE_REQUEST_TARGET_BRANCH_NAME ;
export common_parent_sha=$(diff --old-line-format='' --new-line-format='' <(git rev-list --first-parent "target/$CI_MERGE_REQUEST_TARGET_BRANCH_NAME") <(git rev-list --first-parent HEAD) | head -1) ;
python3 -u ./check-style.py --dry-run --sha $common_parent_sha ;
else
echo "Not a merge request" ;
fi
allow_failure: true
.build-mutter:
extends:
- .fdo.distribution-image@fedora
build-mutter:
stage: build
needs: []
script:
- meson . build -Dbuildtype=debugoptimized -Db_coverage=true -Degl_device=true -Dwayland_eglstream=true --werror --prefix /usr
- meson compile -C build
- meson install -C build
- ninja -C build
- ninja -C build install
artifacts:
expire_in: 1 day
paths:
- build
only:
- merge_requests
- /^.*$/
build-mutter@x86_64:
extends:
- .build-mutter
- .mutter.fedora:34@x86_64
needs:
- build-fedora-container@x86_64
build-mutter@aarch64:
extends:
- .build-mutter
- .mutter.fedora:34@aarch64
needs:
- build-fedora-container@aarch64
build-without-opengl-and-glx@x86_64:
extends:
- .fdo.distribution-image@fedora
- .mutter.fedora:34@x86_64
build-without-opengl-and-glx:
stage: build
needs:
- build-fedora-container@x86_64
needs: []
script:
- meson . build -Dbuildtype=debugoptimized -Dopengl=false -Dglx=false -Degl_device=true -Dwayland_eglstream=true --werror --prefix /usr
- meson compile -C build
- meson install -C build
- ninja -C build
- ninja -C build install
artifacts:
paths:
- build/meson-logs
only:
- merge_requests
- /^.*$/
build-without-native-backend-and-wayland@x86_64:
extends:
- .fdo.distribution-image@fedora
- .mutter.fedora:34@x86_64
build-without-native-backend-and-wayland:
stage: build
needs:
- build-fedora-container@x86_64
needs: []
script:
- meson . build -Dbuildtype=debugoptimized -Dnative_backend=false -Dudev=false -Dwayland=false -Dcore_tests=false -Dnative_tests=false --werror --prefix /usr
- meson compile -C build
- meson install -C build
- meson . build -Dbuildtype=debugoptimized -Dnative_backend=false -Dudev=false -Dwayland=false -Dcore_tests=false --werror --prefix /usr
- ninja -C build
- ninja -C build install
artifacts:
paths:
- build/meson-logs
only:
- merge_requests
- /^.*$/
.test-setup: &test-setup
test-mutter:
stage: test
dependencies:
- build-mutter
needs: ["build-mutter"]
variables:
XDG_RUNTIME_DIR: "$CI_PROJECT_DIR/runtime-dir"
GSETTINGS_SCHEMA_DIR: "$CI_PROJECT_DIR/build/data"
MUTTER_DEBUG_DUMMY_MODE_SPECS: "800x600@10.0"
PIPEWIRE_DEBUG: 2
PIPEWIRE_LOG: "$CI_PROJECT_DIR/build/meson-logs/pipewire.log"
XVFB_SERVER_ARGS: "+iglx -noreset"
G_SLICE: "always-malloc"
MALLOC_CHECK_: "3"
NO_AT_BRIDGE: "1"
before_script:
- glib-compile-schemas $GSETTINGS_SCHEMA_DIR
# Disable e.g. audio support to not dead lock screen cast tests
- rm -f /usr/share/pipewire/media-session.d/with-*
- mkdir -m 700 $XDG_RUNTIME_DIR
- pipewire & sleep 2
.test-mutter:
extends:
- .fdo.distribution-image@fedora
<<: *test-setup
stage: test
script:
- dbus-run-session -- xvfb-run -a -s "$XVFB_SERVER_ARGS"
catchsegv meson test -C build --no-rebuild -t 10
- dconf update
- mkdir -m 700 $XDG_RUNTIME_DIR
- glib-compile-schemas $GSETTINGS_SCHEMA_DIR
- >
dbus-run-session -- xvfb-run -s '+iglx -noreset'
meson test -C build --no-rebuild -t 10 --verbose --no-stdsplit --print-errorlogs --wrap catchsegv
artifacts:
expire_in: 1 day
reports:
junit: "build/meson-logs/testlog-catchsegv.junit.xml"
name: "mutter-${CI_JOB_NAME}-${CI_COMMIT_REF_NAME}"
when: always
paths:
- build
only:
- merge_requests
- /^.*$/
test-mutter@x86_64:
extends:
- .test-mutter
- .mutter.fedora:34@x86_64
needs:
- build-mutter@x86_64
test-mutter@aarch64:
extends:
- .test-mutter
- .mutter.fedora:34@aarch64
needs:
- build-mutter@aarch64
.test-mutter-coverage:
extends:
- .fdo.distribution-image@fedora
stage: analyze
test-mutter-coverage:
stage: coverage
dependencies:
- test-mutter
needs: ["test-mutter"]
script:
- ninja -C build coverage
- cat build/meson-logs/coverage.txt
artifacts:
paths:
- build/meson-logs/coveragereport
coverage: '/^TOTAL.*\s+(\d+\%)$/'
- build/meson-logs
when: manual
except:
refs:
- tags
- master
test-mutter-coverage@x86_64:
extends:
- .test-mutter-coverage
- .mutter.fedora:34@x86_64
needs:
- test-mutter@x86_64
test-mutter-coverage@aarch64:
extends:
- .test-mutter-coverage
- .mutter.fedora:34@aarch64
needs:
- test-mutter@aarch64
can-build-gnome-shell@x86_64:
extends:
- .fdo.distribution-image@fedora
- .mutter.fedora:34@x86_64
can-build-gnome-shell:
stage: test
needs:
- build-mutter@x86_64
dependencies:
- build-mutter
needs: ["build-mutter"]
before_script:
- meson install --no-rebuild -C build
script:
- .gitlab-ci/checkout-gnome-shell.sh
- meson gnome-shell gnome-shell/build --prefix /usr -Dman=false
- meson install -C gnome-shell/build
test-mutter-coverity:
rules:
- if: '$CI_PIPELINE_SOURCE == "schedule" && $MUTTER_SCHEDULED_JOB == "coverity"'
when: always
- when: manual
extends:
- .fdo.distribution-image@fedora
- .mutter.fedora:34@x86_64
needs:
- build-fedora-container@x86_64
stage: analyze
allow_failure: true
script:
- .gitlab-ci/download-coverity-tarball.sh
- CC=clang meson coverity-build -Dprofiler=false
- ./coverity/cov-analysis-linux64-*/bin/cov-build --dir cov-int meson compile -C coverity-build
- tar czf cov-int.tar.gz cov-int
- curl https://scan.coverity.com/builds?project=mutter
--form token=$COVERITY_TOKEN --form email=carlosg@gnome.org
--form file=@cov-int.tar.gz --form version="`git describe --tags`"
--form description="GitLab CI build"
cache:
key: coverity-tarball
paths:
- coverity
dist-mutter:
extends:
- .fdo.distribution-image@fedora
- .mutter.fedora:34@x86_64
<<: *test-setup
stage: deploy
needs:
- build-mutter@x86_64
script:
- dbus-run-session -- xvfb-run -a -s "$XVFB_SERVER_ARGS" meson dist -C build
rules:
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
changes:
- "**/meson.build"
- meson/*
dist-mutter-tarball:
extends: dist-mutter
artifacts:
expose_as: 'Get tarball here'
paths:
- build/meson-dist/$CI_PROJECT_NAME-$CI_COMMIT_TAG.tar.xz
rules:
- if: '$CI_COMMIT_TAG'
- ninja -C gnome-shell/build install
only:
- merge_requests
- /^.*$/

28
.gitlab-ci/Dockerfile Normal file
View File

@ -0,0 +1,28 @@
# Rebuild and push with
#
# cd .gitlab-ci/
# podman build --format docker --no-cache -t registry.gitlab.gnome.org/gnome/mutter/master:v4 .
# podman push registry.gitlab.gnome.org/gnome/mutter/master:v4
#
FROM fedora:32
RUN dnf -y update && dnf -y upgrade && \
dnf install -y 'dnf-command(builddep)' && \
dnf install -y 'dnf-command(copr)' && \
dnf copr enable -y jadahl/mutter-ci && \
dnf builddep -y mutter --setopt=install_weak_deps=False && \
# For running unit tests
dnf install -y xorg-x11-server-Xvfb mesa-dri-drivers dbus dbus-x11 \
'*/xvfb-run' gdm-lib accountsservice-libs gnome-control-center gcovr \
libnma python3-gobject python3-dbusmock \
--setopt=install_weak_deps=False && \
# GNOME Shell
dnf builddep -y gnome-shell --setopt=install_weak_deps=False && \
dnf remove -y gnome-bluetooth-libs-devel && \
dnf remove -y --noautoremove mutter mutter-devel && \
dnf clean all

60
.gitlab-ci/check-commit-log.sh Executable file
View File

@ -0,0 +1,60 @@
#!/usr/bin/env bash
if [ -z "$CI_MERGE_REQUEST_TARGET_BRANCH_NAME" ]; then
echo Cannot review non-merge request
exit 1
fi
git fetch $CI_MERGE_REQUEST_PROJECT_URL.git $CI_MERGE_REQUEST_TARGET_BRANCH_NAME
branch_point=$(git merge-base HEAD FETCH_HEAD)
commits=$(git log --format='format:%H' $branch_point..$CI_COMMIT_SHA)
if [ -z "$commits" ]; then
echo Commit range empty
exit 1
fi
function commit_message_has_url() {
commit=$1
commit_message=$(git show -s --format='format:%b' $commit)
echo "$commit_message" | grep -qe "\($CI_MERGE_REQUEST_PROJECT_URL/\(-/\)\?\(issues\|merge_requests\)/[0-9]\+\|https://bugzilla.gnome.org/show_bug.cgi?id=[0-9]\+\)"
return $?
}
function commit_message_subject_is_compliant() {
commit=$1
commit_message_subject=$(git show -s --format='format:%s' $commit)
if echo "$commit_message_subject" | grep -qe "\(^meta-\|^Meta\)"; then
echo " - message subject should not be prefixed with 'meta-' or 'Meta'"
return 1
fi
if echo "$commit_message_subject" | grep -qe "\.[ch]:"; then
echo " - message subject prefix should not include .c, .h, etc."
return 1
fi
return 0
}
RET=0
for commit in $commits; do
commit_short=$(echo $commit | cut -c -8)
if ! commit_message_has_url $commit; then
echo "Commit $commit_short needs a merge request or issue URL"
exit 1
fi
errors=$(commit_message_subject_is_compliant $commit)
if [ $? != 0 ]; then
echo "Commit message for $commit_short is not compliant:"
echo "$errors"
RET=1
fi
done
exit $RET

View File

@ -1,19 +1,11 @@
#!/usr/bin/bash
fetch() {
local remote=$1
local ref=$2
git fetch --quiet --depth=1 $remote $ref 2>/dev/null
}
gnome_shell_target=
echo -n Cloning into gnome-shell ...
if git clone --quiet --depth=1 https://gitlab.gnome.org/GNOME/gnome-shell.git; then
echo \ done
else
echo \ failed
git clone https://gitlab.gnome.org/GNOME/gnome-shell.git
if [ $? -ne 0 ]; then
echo Checkout failed
exit 1
fi
@ -23,33 +15,19 @@ if [ "$CI_MERGE_REQUEST_TARGET_BRANCH_NAME" ]; then
merge_request_remote=${CI_MERGE_REQUEST_SOURCE_PROJECT_URL//mutter/gnome-shell}
merge_request_branch=$CI_MERGE_REQUEST_SOURCE_BRANCH_NAME
echo -n Looking for $merge_request_branch on remote ...
if fetch $merge_request_remote $merge_request_branch; then
echo \ found
echo Looking for $merge_request_branch on remote ...
if git fetch -q $merge_request_remote $merge_request_branch 2>/dev/null; then
gnome_shell_target=FETCH_HEAD
else
echo \ not found
echo -n Looking for $CI_MERGE_REQUEST_TARGET_BRANCH_NAME instead ...
if fetch origin $CI_MERGE_REQUEST_TARGET_BRANCH_NAME; then
echo \ found
gnome_shell_target=FETCH_HEAD
else
echo \ not found
fi
fi
fi
if [ -z "$gnome_shell_target" ]; then
echo -n Looking for $CI_COMMIT_REF_NAME on remote ...
if fetch origin $CI_COMMIT_REF_NAME; then
echo \ found
gnome_shell_target=FETCH_HEAD
else
echo \ not found
gnome_shell_target=HEAD
gnome_shell_target=origin/$CI_MERGE_REQUEST_TARGET_BRANCH_NAME
echo Using $gnome_shell_target instead
fi
fi
if [ -z "$gnome_shell_target" ]; then
gnome_shell_target=$(git branch -r -l origin/$CI_COMMIT_REF_NAME)
gnome_shell_target=${gnome_shell_target:-origin/master}
echo Using $gnome_shell_target instead
fi
git checkout -q $gnome_shell_target

View File

@ -1,19 +0,0 @@
patterns:
deny:
- regex: '^$CI_MERGE_REQUEST_PROJECT_URL/(-/)?merge_requests/$CI_MERGE_REQUEST_IID$'
message: Commit message must not contain a link to its own merge request
- regex: '^(meta-|Meta)'
message: Commit message subject should not be prefixed with 'meta-' or 'Meta'
where: subject
- regex: '^(clutter-|Clutter)'
message: Commit message subject should not be prefixed with 'clutter-' or 'Clutter', use 'clutter/' instead
where: subject
- regex: '^(cogl-|Cogl)'
message: Commit message subject should not be prefixed with 'cogl-' or 'Cogl', use 'cogl/' instead
where: subject
- regex: '^[^:]+: [a-z]'
message: "Commit message subject should be properly Capitalized. E.g. 'window: Marginalize extradicity'"
where: subject
- regex: '^\S*\.[ch]:'
message: Commit message subject prefix should not include .c, .h, etc.
where: subject

View File

@ -1,38 +0,0 @@
#!/usr/bin/bash
# We need a coverity token to fetch the tarball
if [ -x $COVERITY_TOKEN ]
then
echo "No coverity token. Run this job from a protected branch."
exit -1
fi
mkdir -p coverity
# Download and check MD5 first
curl https://scan.coverity.com/download/linux64 \
--data "token=$COVERITY_TOKEN&project=mutter&md5=1" \
--output /tmp/coverity_tool.md5
diff /tmp/coverity_tool.md5 coverity/coverity_tool.md5 >/dev/null 2>&1
if [ $? -eq 0 -a -d coverity/cov-analysis* ]
then
echo "Coverity tarball is up-to-date"
exit 0
fi
# Download and extract coverity tarball
curl https://scan.coverity.com/download/linux64 \
--data "token=$COVERITY_TOKEN&project=mutter" \
--output /tmp/coverity_tool.tgz
rm -rf ./coverity/cov-analysis*
tar zxf /tmp/coverity_tool.tgz -C coverity/
if [ $? -eq 0 ]
then
mv /tmp/coverity_tool.md5 coverity/
fi
rm /tmp/coverity_tool.tgz

View File

@ -1,39 +0,0 @@
#!/bin/bash
set -e
if [[ $# -lt 3 ]]; then
echo Usage: $0 [options] [repo-url] [commit] [subdir]
echo Options:
echo -Dkey=val
exit 1
fi
MESON_OPTIONS=()
while [[ $1 =~ ^-D ]]; do
MESON_OPTIONS+=( "$1" )
shift
done
REPO_URL="$1"
TAG_OR_BRANCH="$2"
SUBDIR="$3"
COMMIT="$4"
REPO_DIR="$(basename ${REPO_URL%.git})"
git clone --depth 1 "$REPO_URL" -b "$TAG_OR_BRANCH"
pushd "$REPO_DIR"
pushd "$SUBDIR"
if [ ! -z "$COMMIT" ]; then
git fetch origin "$COMMIT"
git checkout "$COMMIT"
fi
meson --prefix=/usr _build "${MESON_OPTIONS[@]}"
meson install -C _build
popd
popd
rm -rf "$REPO_DIR"

View File

@ -1,286 +0,0 @@
# Style
The coding style used is primarily the GNU flavor of the [GNOME coding
style][gnome-coding-style], with some additions described below.
## General
* Use this code style on new code. When changing old code with a different
code style, feel free to also adjust it to use this code style.
* Use regular C types and `stdint.h` types instead of GLib fundamental
types, except for `gboolean`, and `guint`/`gulong` for GSource IDs and
signal handler IDs. That means e.g. `uint64_t` instead of `guint64`, `int`
instead of `gint`, `unsigned int` instead of `guint` if unsignedness
is of importance, `uint8_t` instead of `guchar`, and so on.
* Try to to limit line length to 80 characters, although it's not a
strict limit.
* Usage of `g_autofree` and `g_autoptr` is encouraged. The style to use is
```c
g_autofree char *text = NULL;
g_autoptr (MetaSomeThing) thing = NULL;
text = g_strdup_printf ("The text: %d", a_number);
thing = g_object_new (META_TYPE_SOME_THING,
"text", text,
NULL);
thinger_use_thing (rocket, thing);
```
* Declare variables at the top of the block they are used, but avoid
non-trivial logic among variable declarations. Non-trivial logic can be
getting a pointer that may be `NULL`, any kind of math, or anything
that may have side effects.
* Instead of boolean arguments in functions, prefer enums or flags when
they're more expressive. The naming convention for flags is
```c
typedef _MetaSomeThingFlags
{
META_SOME_THING_FLAG_NONE = 0,
META_SOME_THING_FLAG_ALTER_REALITY = 1 << 0,
META_SOME_THING_FLAG_MANIPULATE_PERCEPTION = 1 << 1,
} MetaSomeThingFlags;
```
* Use `g_new0 ()` etc. instead of `g_slice_new0 ()`.
* Initialize and assign floating point variables (i.e. `float` or
`double`) using the form `floating_point = 3.14159` or `ratio = 2.0`.
## Header (.h) files
* The return type and `*` are separated by a space.
* Function name starts one space after the last `*`.
* Parenthesis comes one space after the function name.
As an example, this is how functions in a header file should look like:
```c
gboolean meta_udev_is_drm_device (MetaUdev *udev,
GUdevDevice *device);
GList * meta_udev_list_drm_devices (MetaUdev *udev,
GError **error);
MetaUdev * meta_udev_new (MetaBackendNative *backend_native);
```
## Source code
Keep functions in the following order in source files:
1. GPL header
2. Enums
3. Structures
4. Function prototypes
5. `G_DEFINE_TYPE()`
6. Static variables
7. Auxiliary functions
8. Callbacks
9. Interface implementations
10. Parent vfunc overrides
11. class_init and init
12. Public API
### Structures
Each structure field has a space after their type name. Structure fields aren't
aligned. For example:
```c
struct _MetaFooBar
{
MetaFoo parent;
MetaBar *bar;
MetaSomething *something;
};
```
### Function Prototypes
Function prototypes must be formatted just like in header files.
### Overrides
When overriding parent class vfuncs, or implementing an interface, vfunc
overrides should be named as a composition of the current class prefix,
followed by the vfunc name. For example:
```c
static void
meta_bar_spawn_unicorn (MetaParent *parent)
{
/* ... */
}
static void
meta_bar_dispose (GObject *object)
{
/* ... */
}
static void
meta_bar_finalize (GObject *object)
{
/* ... */
}
static void
meta_bar_class_init (MetaBarClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
MetaParentClass *parent_class = META_PARENT_CLASS (klass);
object_class->dispose = meta_bar_dispose;
object_class->finalize = meta_bar_finalize;
parent_class->spawn_unicorn = meta_bar_spawn_unicorn;
}
```
### Interface Implementations
When implementing interfaces, two groups of functions are involved: the init
function, and the overrides.
The interface init function is named after the interface type in snake case,
followed by the `_iface_init` suffix. For example:
```c
static void meta_foo_iface_init (MetaFooInterface *foo_iface);
G_DEFINE_TYPE_WITH_CODE (MetaBar, meta_bar, G_TYPE_OBJECT,
G_IMPLEMENT_INTERFACE (META_TYPE_FOO,
meta_foo_iface_init));
```
Then, when implementing each vfunc of the interface, follow the same pattern
of the [Overrides](###Overrides) section. Here's an example:
```c
static void
meta_bar_do_something (MetaFoo *foo)
{
/* ... */
}
static void
meta_foo_iface_init (MetaFooInterface *foo_iface)
{
foo_iface->do_something = meta_bar_do_something;
}
```
### Auxiliary Functions
Auxiliary functions are above every other functions to minimize the number of
function prototypes in the file. These functions often grow when factoring out
the same code between two or more functions:
```c
static void
do_something_on_data (Foo *data,
Bar *bar)
{
/* ... */
}
static void
random_function (Foo *foo)
{
do_something_on_data (foo, bar);
}
static void
another_random_function (Foo *foo)
{
do_something_on_data (foo, bar);
}
```
Sometimes, however, auxiliary functions are created to break down otherwise
large functions - in this case, it is appropriate to keep these auxiliary
functions close to the function they are tightly related to.
Auxiliary function names must have a verb in the imperative form, and should
always perform an action over something. They usually don't have the class
prefix (`meta_`, `clutter_`, or `cogl_`). For example:
```c
static void
do_something_on_data (Foo *data,
Bar *bar)
{
/* ... */
}
```
Exceptionally, when converting between types, auxiliary function names may
have the class prefix to this rule. For example:
```c
static MetaFoo *
meta_foo_from_bar (Bar *bar)
{
/* ... */
}
```
### Callback Functions
Callback function names should have the name of the action in imperative
form. They don't have any prefix, but have a `_func` suffix. For example:
```c
static void
filter_something_func (Foo *foo,
Bar *bar,
gpointer user_data)
{
/* ... */
}
```
### Signal Callbacks
Signal callbacks generally have the signal name. They should be prefixed with
`on_`, or suffixed with `_cb`, but not both. For example:
```c
static void
on_realize (ClutterActor *actor,
gpointer user_data)
{
/* ... */
}
static void
destroy_cb (ClutterActor *actor,
gpointer user_data)
{
/* ... */
}
```
When the callback is named after the object that generated it, and the signal,
then passive voice is used. For example:
```c
static void
click_action_clicked_cb (ClutterClickAction *click_action,
ClutterActor *actor,
gpointer user_data)
{
/* ... */
}
```
[gnome-coding-style]: https://developer.gnome.org/programming-guidelines/stable/c-coding-style.html.en

463
NEWS
View File

@ -1,440 +1,3 @@
41.1
====
* Fix monitor screencast scanouts [Michel; !1914]
* dma-buf: Use alpha-less pixel formats where appropriate [Robert; !1810]
* wayland: Allow clients to maximize windows regardless of constraints
[Christian; !1997]
* Handle hotplug events without relevant changes more effectively
[Marco; !1964]
* Improve error reporting when startup fails [Jonas; !1994]
* dma-buf: Add support for ABGR and XBGR formats [Erfan; !1999]
* Fix X11 middle button emulation setting [José; !2000]
* Include server-side shadows in window screenshots [Robert; !1996]
* Don't change workspaces of unmanaged windows [Sebastian; !2003]
* Reset idletime when unplugging the power cable [Bastien; !2029]
* xwayland: Avoid unnecessary _NET_WM_STATE events [Dor; !2032]
* Fix videos in Firefox stuttering in overview [Robert; !2034]
* Don't use atomic mode setting for virtio_gpu driver [Jonas; !2040]
* Improve on-screen keyboard on X11 [Sebastian, Ray; !1955, !2039]
* misc [Daniel, Jonas, Corentin, Robert; !1992, !2007, !2008, !2026, !2044]
* Fix text glitches after size changes [Sebastian; !2006]
* Fix reporting output rotation to xwayland [Olivier; !2050]
* wayland: Accept final preference of drop destination [Robert; !2043]
* Fix erratic scrolling in GTK apps [Carlos; gnome-shell#4647]
* Fix tilt direction of pen/tablet inputs [Quytelda; !2065]
* Use b/w unicode for tablet mode OSD [Carlos; !2064]
* Fix negative paint volume offscreen effect [Sebastian; !2031]
* Only add paint volumes of mapped actors to stage clip [Robert; !2035]
* Fix mapping tablet input to correct monitor [Jason; !1934]
* Misc. bug fixes and cleanups
Contributors:
Marco Trevisan (Treviño), Erfan Abdi, Dor Askayo, Michel Dänzer,
José Expósito, Olivier Fourdan, Carlos Garnacho, Jason Gerecke,
Quytelda Kahja, Sebastian Keller, Robert Mader, Bastien Nocera, Corentin Noël,
Christian Rauch, Ray Strode, Daniel van Vugt, Jonas Ådahl
Translators:
eshagh shahidani [fa], Danial Behzadi [fa], Марко Костић [sr],
Zander Brown [en_GB], Ngọc Quân Trần [vi], Rūdolfs Mazurs [lv]
41.0
====
* Avoid race in wl_seat capabilities [Olivier; !77]
* Expose option groups/entries to introspection [Corentin; !1976]
Contributors:
Olivier Fourdan, Corentin Noël
Translators:
Daniel Șerbănescu [ro], Goran Vidović [hr], Luna Jernberg [sv],
eshagh shahidani [fa], Gwan-gyeong Mun [ko], Emin Tufan Çetin [tr],
Philipp Kiemle [de], Balázs Úr [hu], Piotr Drąg [pl], Nathan Follens [nl],
Jordi Mas [ca], Ask Hjorth Larsen [da]
41.rc
=====
* Add clutter_stage_paint_to_content() [Ivan; !1899]
* Add meta_cursor_tracker_get_scale() [Ivan; !1967]
* wayland: Make each wl_output correspond to one monitor [Jonas; !1712]
* Expose 'inactive-since' timestamp to uresourced [Nishal; !1960]
* Pass dirty rects to secondary GPU [Piotr; !1879]
* Support commiting preedit string on focus loss [Carlos; !1940]
* Improve auto-rotation support [Marco; !1233]
* Add meta_window_actor_paint_to_content() [Robert; !1893]
* Fixed crashes [Jonas, Ray, Robert; !1947, !1979, !1965, !1958]
* Misc. bug fixes and cleanups [Florian, Carlos, Robert, Daniel, Erico, Dor;
!1957, !1924, !1970, !1971, !1972, !1973, !1974, !1977, !1978, !1975, !1886,
!1983, !1990, !1980]
Contributors:
Marco Trevisan (Treviño), Dor Askayo, Carlos Garnacho, Nishal Kulkarni,
Piotr Lopatka, Robert Mader, Ivan Molodetskikh, Florian Müllner, Erico Nunes,
Ray Strode, Daniel van Vugt, Jonas Ådahl
Translators:
Asier Sarasua Garmendia [eu], Claude Paroz [fr], Jiri Grönroos [fi],
Baurzhan Muftakhidinov [kk], Aurimas Černius [lt]
41.beta
=======
* Fix mouse position in remote desktop with fractional scaling [Pascal; !1867]
* Manage idle monitors via MetaIdleManager [Jonas Å.; !1859]
* Disable KMS modifiers on radeon driver [Carlos; !1872]
* Fix fd leak [Carlos; !1870]
* Fix adding virtual monitor to physical session [Jonas Å.; !1891]
* Unbreak press-drag-release to pop up and select right click menus
[Carlos; !1885]
* Fix VKMS detection [Jonas Å.; !1892]
* Fix swipe cancellation [JoseExposito; !1857]
* Add ClutterTextureContent [Robert; !1888]
* Fix mapping tablet to monitor [Christoph; !1887]
* Fix area screencasts when window is unredirected [Michel; !1902]
* Don't require a newly attached buffer to apply state [Christian, Jonas; !1795]
* Close unused mode setting and rendering devices [Jonas Å.; !1828]
* Only support super+scroll on wayland [Florian; !1922]
* Implement the xdg-activation protocol [Carlos; !1845]
* Reduce input latency by computing max render time heuristically [Ivan; !1762]
* Apply dithering to dispatch time when needed [Daniel; !1826]
* Introduce MetaContext [Jonas Å.; !1861]
* x11: Compute monitor scale per output [Marco; !336]
* Shrink and optimize the rounded-background-clip shader [Daniel; !1860]
* remote-desktop: Handle non-responding selection owners [Pascal; !1874]
* Improve sysprof support [Jonas Å.; !1700]
* Allow clients to delegate titlebar gestures to the compositor [Florian; !1944]
* Fix upside-down Xshape surface with EGLstream [Robert; !1937]
* Fix 'kms-modifiers' experimental setting [Robert; !1953]
* Make default focus window on each workspace appear focused [Alexander; !850]
* Plugged memory leaks [Jonas Å.; !1869]
* Fixed crashes crash [Daniel, Jonas Å., Florian; !1883, !1895,
!1910, !1925, !1956]
* Misc. bug fixes and cleanups [Jonas Å., Marco, Daniel, Florian, Georges,
Zander, Carlos, Robert; !1833, !1863, !1876, !1873, !1884, !1890, !1900,
!1912, !1916, !1911, !1920, !1865, !1927, !1923, !1929, !1100, !1932, !1931,
!1862, !1933, !1930, !1935, !1936, !1878, !1938, !1942, !1951, !522, !1941]
Contributors:
Marco Trevisan (Treviño), Zander Brown, Piotr Drąg, Michel Dänzer,
Carlos Garnacho, JoseExposito, Robert Mader, Alexander Mikhaylenko,
Ivan Molodetskikh, Florian Müllner, Georges Basile Stavracas Neto,
Pascal Nowack, Christian Rauch, Christoph Trassl, Daniel van Vugt, Jonas Ådahl
Translators:
Pawan Chitrakar [ne], Charles Monzat [fr], Dušan Kazik [sk],
Quentin PAGÈS [oc], Alexey Rubtsov [ru], Alexander Shopov [bg],
Florentina Mușat [ro], Chao-Hsiung Liao [zh_TW], Yuri Chornoivan [uk],
Fran Dieguez [gl], Hugo Carvalho [pt], Rafael Fontenelle [pt_BR],
Fabio Tomat [fur], Kukuh Syafaat [id], Yaron Shahrabani [he],
Marek Černocký [cs], Matej Urbančič [sl], Boyuan Yang [zh_CN],
Daniel Mustieles [es]
40.1
====
* Prevent clients from pasting old selection data [Carlos; !1772]
* Fix forward_key IM functionality on wayland [Takao; !1802]
* Ensure valid window texture size after viewport changes [Robert; !1799]
* Only update cached paint volumes when necessary [Jonas D.; !1773, !1829]
* Only disable KMS modifiers for drivers with known problems [Jonas Å; !1792]
* Fix X11 client resize during moves [Olivier; !1777]
* Fix performance drop during night light transition with Nvidia [Aaron; !1816]
* kms: Don't add common modes that exceed the max bandwidth [Jonas Å.; !1834]
* Create virtual input devices on demand [Jonas Å; !1800, !1858]
* Fix wrong night light gamma when leaving power saving [Jonas Å.; !1835]
* Fix picking edge case [Sebastian; !1842]
* Properly tear down things when shutting down [Jonas Å.; !1822, !1856, !1853]
* Fix monitor screencasting with fractional scaling [kirbykevinson; !1855]
* Fixed crash [Carlos; !1849]
* Plugged memory leak [Carlos; !1839]
* Misc. bug fixes and cleanups [Carlos, Daniel, Jonas D., Jonas Å., Robert,
Aleksandr, Florian, Michel, Sebastian, Olivier; !1785, !1798, !1784,
!1791, !1801, !1807, !1786, !1793, !1804, !1820, !1824, !1819, !1803,
!1821, !1806, !1814, !1831, !1832, !1836, !1843, !1740, !1841, !1827,
!1844, !1852, !1850, !1851]
Contributors:
Jonas Ådahl, Michel Dänzer, Jonas Dreßler, Olivier Fourdan, Takao Fujiwara,
Carlos Garnacho, Sebastian Keller, kirbykevinson, Robert Mader,
Aleksandr Mezin, Florian Müllner, Aaron Plattner, Daniel van Vugt
Translators:
Bruce Cowan [en_GB], Ngọc Quân Trần [vi], Marek Černocký [cs],
Dz Chen [zh_CN], Yosef Or Boczko [he], Nathan Follens [nl],
Yuri Chornoivan [uk], Jordi Mas [ca], Piotr Drąg [pl], Tim Sabsch [de],
Luna Jernberg [sv], Hugo Carvalho [pt], Rafael Fontenelle [pt_BR],
Asier Sarasua Garmendia [eu], Quentin PAGÈS [oc], Matej Urbančič [sl]
40.0
====
* xwayland: Check permissions on /tmp/.X11-unix [Olivier; !1787]
Contributors:
Olivier Fourdan
Translators:
Hugo Carvalho [pt], Tim Sabsch [de], Daniel Mustieles [es],
Matej Urbančič [sl], Марко Костић [sr], Fran Dieguez [gl]
40.rc
=====
* Fix keyboard input from remote desktop in Xorg session [Pascal; !1732]
* Fix restoring focus to windows using globally active input [Olivier; !1716]
* Expose unaccalerated touchpad gesture deltas [Alexander; !1353]
* Avoid relayout on text attribute changes when possible [Jonas D.; !1750]
* Add remote desktop caps- and num-lock state properties [Jonas Å.; !1739]
* Improve refresh rate calculation [Akihiko; !1737]
* Implement presentation-time protocol [Ivan; !1484]
* Disable double-buffered shadow buffering [Jonas Å.; !1724]
* Fix missing cursor on tablet devices [Jonas D.; !1758]
* Fix frame timings causing X11 clients to get stuck [Jonas Å.; !1754]
* Fix applying input settings on X11 [Marco, Suryashankar; !1769, !1767]
* Add headless native backend [Jonas Å.; !1698]
* Fix high latency and stalls with proprietary nvidia driver [Daniel; !1726]
* Fix maximized windows not reacting to strut changes [Aleksandr; !1755]
* Only start XWayland on demand when running under systemd [Benjamin; !1771]
* Sync LEDs when a new input device is added [Olivier; !1662]
* Fix order in which subsurface placement operations are handled [Robert; !1768]
* Fixed crashes [Jonas Å., Sebastian; !1745, !1747, !1759, !1748, !1776, !1775]
* Plugged leaks [Philip, Sebastian; !1738, !1728]
* Misc. bug fixes and cleanups [Jonas Å., Jonas D., Ivan, Florian, Marco,
Robert; !1688, !1744, !1736, !1749, !1752, !1753, !427, !1757, !1751, !1760,
!1765, !1770, !1763, !1774, !1780, !1779, !1783]
Contributors:
Jonas Ådahl, Benjamin Berg, Suryashankar Das, Jonas Dreßler, Olivier Fourdan,
Sebastian Keller, Robert Mader, Aleksandr Mezin, Alexander Mikhaylenko,
Ivan Molodetskikh, Florian Müllner, Pascal Nowack, Akihiko Odaki,
Marco Trevisan (Treviño), Daniel van Vugt, Philip Withnall
Translators:
Fran Dieguez [gl], Asier Sarasua Garmendia [eu], Claude Paroz [fr],
Piotr Drąg [pl], Hugo Carvalho [pt], Jordi Mas [ca], Fabio Tomat [fur],
Yuri Chornoivan [uk], Enrico Nicoletto [pt_BR], Emin Tufan Çetin [tr],
Daniel Șerbănescu [ro], Marek Černocký [cs], Balázs Úr [hu],
Aurimas Černius [lt], Kukuh Syafaat [id], A S Alam [pa], Anders Jonsson [sv],
Milo Casagrande [it], Gwan-gyeong Mun [ko]
40.beta
=======
* Consider clients without mapped windows for xwayland auto-shutdown
[Olivier; !1671]
* Let compositor to handle super+scroll events [Florian; !1674, !1695]
* Default to starting Xwayland on demand [Olivier; !1673]
* xwayland: Restore abstract socket support [James, Olivier; !1669]
* Add support for atomic mode setting [Jonas Å.; !1488]
* Fix clip region glitches when using fractional scaling [Daniel; !1554]
* Default to horizontal workspace layout [Georges, Florian; !1684, !1706]
* Do not ping unmanaging windows [Florian; gnome-shell#2467]
* Handle monitor changes during screencasts [Jonas Å.; !1691]
* Fix unexpected jumps after restoring misbehaving clients [Jonas Å.; !1445]
* Fix newly opened X11 windows being invisible in overview [Olivier; !1678]
* Fix viewport of offscreen effects [Daniel; !1053]
* Fix drag cancel animation when using geometry scaling [Robert; !1683]
* Improve touch-mode heuristics [Carlos; !1710]
* Integrate clipboard with remote desktop sessions [Jonas Å.; !1552]
* Fix stuck icon in DND operation between X11 and wayland [Carlos; !1720]
* Automatically synchronize pointer position after modal grabs [Carlos; !1659]
* Reimplement support for CLUTTER_SHOW_FPS [Daniel; !154]
* Only pick on events that may move the pointer [Jonas D.; !1729, !1733]
* Emit discrete scroll events for accumulated smooth events in virtual
X11 devices [Pascal; !1727]
* Add support for rounded clipping when drawing background [Jonas D.; !1717]
* Plugged memory leaks [Sebastian; !1307, !1699]
* Fixed crashes [Carlos, Thomas, Jonas Å., Olivier; !1677, !1685, !1692,
!1719, !1718, !1735]
* Misc. bug fixes and cleanups [Jonas Å., Carlos, Olivier, Sebastian, Björn,
Jonas D., Ivan, Georges, Dor, Michel, Robert; !1670, !1679, !1680, !1682,
!1681, !1661, !1689, !1690, !1693, !1514, !1696, !1697, !1708, !1709, !1707,
!1701, !1702, !1715, !1725, !1734, !1512]
Contributors:
Jonas Ådahl, Dor Askayo, Björn Daase, Michel Dänzer, Jonas Dreßler,
Olivier Fourdan, Carlos Garnacho, James Henstridge, Sebastian Keller,
Robert Mader, Ivan Molodetskikh, Thomas Mühlbacher, Florian Müllner,
Georges Basile Stavracas Neto, Pascal Nowack, Daniel van Vugt
Translators:
Марко Костић [sr], Jordi Mas [ca], Yuri Chornoivan [uk],
Daniel Șerbănescu [ro], Hugo Carvalho [pt], Fran Dieguez [gl],
Matej Urbančič [sl], Marek Černocký [cs], Rafael Fontenelle [pt_BR],
Philipp Kiemle [de], A S Alam [pa], Balázs Úr [hu], Anders Jonsson [sv],
Daniel Mustieles [es], Emin Tufan Çetin [tr], Kukuh Syafaat [id],
Aurimas Černius [lt]
40.alpha.1.1
============
* Adapt to settings moving to gsettings-desktop-schemas [Carlos; !1416]
* Misc. bug fixes and cleanups [Georges; !1667]
Contributors:
Carlos Garnacho, Georges Basile Stavracas Neto
40.alpha.1
==========
* Base ClutterEffects on ClutterPaintNodes [Georges; !1340, !1355]
* xwayland: Set xrandr primary output [Aleksandr; !1558]
* Add paint node based blur support [Georges; !1627, !1646]
* Disable CRTCs if there is no monitor [Kai-Heng; !1561]
* Fix updates of mipmapped animated backgrounds [Daniel; !1664]
* Allow remote desktop clients to specify scroll source [Pascal; !1636]
* Support the color transform matrix RandR property on X11 [Aaron; !1048]
* Plugged memory leaks [Jonas D.; !1632]
* Fixed crashes [Jonas Å., Olivier, Carlos; !1557, !1648, !1643, !1654, !1663]
* Misc. bug fixes and cleanups [Olivier, Niels, Carlos, Jonas Å., Florian,
Jonas D., Daniel, Georges, Michel, Sebastian, Marc-Antoine; !1621, !1622,
!1624, !1623, !1625, !1626, !1630, !1631, !1576, !1635, !1640, !1642,
!1639, !1644, !1637, !1615, !1647, !1633, !1634, !1651, !1652, !1657,
!1660, !1658, !1665, !1649, !1668, !1655]
Contributors:
Jonas Ådahl, Michel Dänzer, Jonas Dreßler, Kai-Heng Feng, Olivier Fourdan,
Carlos Garnacho, Niels De Graef, Sebastian Keller, Aleksandr Mezin,
Florian Müllner, Georges Basile Stavracas Neto, Pascal Nowack,
Marc-Antoine Perennou, Aaron Plattner, Daniel van Vugt
Translators:
Kjartan Maraas [nb], Juliano de Souza Camargo [pt], Florentina Mușat [ro],
Daniel Mustieles [es], Jordi Mas i Hernandez [ca], Fabio Tomat [fur],
Philipp Kiemle [de], Asier Sarasua Garmendia [eu], Aurimas Černius [lt],
Fran Dieguez [gl], Hugo Carvalho [pt], Matej Urbančič [sl]
40.alpha
========
* Replace CoglMatrix with graphene_matrix [Georges; !1439]
* Allow to specify debug topics in MUTTER_DEBUG [Jonas Å.; !1465]
* Fix unwanted position changes on window resize
[Jonas Å., Olivier, Robert; !1477, !1495]
* Do not disable the X Security extension by default [Olivier; !1485]
* Fix _NET_WM_FRAME_DRAWN timestamps [Jonas Å.; !1494]
* Fix tiling to the correct monitor [Florian; #1389]
* Only snap to window edges when CTRL is pressed [Florian; #679609]
* Add support for scroll button locking [Peter; !1432]
* Clip Frustra [Georges; !1489]
* Improve tablet-mode-switch support [Hans; !1506]
* Fix missed redraws of newly-mapped actors [Jonas D.; !1366, #1494]
* Gracefully handle Xwayland crashes [Carlos; !1447]
* wayland: Provide previous window dimensions on restore [Christian; !801]
* Remove the ClutterActor::paint signal [Jonas; !1522]
* Fix background artifacts in magnifier [Daniel; #1480]
* Use raycasting for picking [Georges; !1509]
* Fix monitor tiling support on X11 [Jonas Å.; #1524]
* Fix xwayland grabs for override-redirect windows [Olivier; !1254]
* Fix device configuration not being picked up on X11 [Carlos; !1553]
* Support tagging devices as primary GPU via udev [Jonas Å.; !1562]
* Fix size hints with CSD [Olivier; !1594]
* Fix unresponsive input after screen blank [Simon; !1601]
* Cull actors when picking [Georges; !1520]
* Handle input in a thread [Carlos; !1403]
* Improve freezes when switching workspace [Jonas Å.; !1616]
* Plugged memory leaks [Ray; !1225]
* Fixed crashes [Christian, Olivier, Daniel, Robert, Jonas Å., Florian Z.,
Simon, Carlos; #1481, !1529, !1519, !1534, #1521, !1563, !1604, !1605,
!1607, !1612]
* Misc. bug fixes and cleanups [Florian, Carlos, Olivier, Georges, Björn,
Jonas Å., Julius, Corentin, Bastien, Robert, Daniel, Niels, Jonas D., Uday,
Ian, Jordan, Piotr; !1473, !1472, !1438, #1449, !1475, !1474, !1481, !1466,
!1483, !1427, !1413, !1103, !1467, !1339, !1297, #1384, !1491, !528, !1496,
!1510, !1507, !1387, !1498, !1515, !1516, !1517, !1486, !1524, !1527, !1528,
!1531, !1532, !1521, !1535, #1490, !1545, !1555, !1564, !1549, !1567, !1565,
!1572, !1569, !1573, !1566, !1525, !1468, !1578, !1583, !1584, !1585, !1571,
!1327, !1586, !1590, !1588, !1050, !1596, !1592, !1587, !1599, !1577, !1511,
!1591, !1603, !1611, !1593, !1617, !1619]
Contributors:
Björn Daase, Jonas Dreßler, Piotr Drąg, Olivier Fourdan, Carlos Garnacho,
Hans de Goede, Niels De Graef, Peter Hutterer, Julius Lehmann, Robert Mader,
Simon McVittie, Florian Müllner, Georges Basile Stavracas Neto,
Bastien Nocera, Corentin Noël, Jordan Petridis, Uday Kiran Pichika,
Christian Rauch, Ian Douglas Scott, Ray Strode, Daniel van Vugt,
Florian Zwoch, Jonas Ådahl
Translators:
Juliano de Souza Camargo [pt], Ask Hjorth Larsen [da], Yuri Chornoivan [uk]
3.38.1
======
* Fix Night Light updates after DPMS [Jonas, Benjamin; #1392]
* Fix button scrolling on X11 [Peter; !1431]
* Always use correct font-dpi setting on X11 [Marco; !1444]
* Improve handling of scanout failures [Jonas; #1410]
* Fix middle/right button mixup in scroll button assignment [Peter; !1433]
* Fix resizing of attached modal dialogs on wayland [Jonas; !1446]
* Enable KMS modifiers on devices that need them [Karol; !1443]
* Fix IM handling on X11 [Carlos; #1413]
* Fix glitches in "undefined" screencast areas [Jonas; !1459]
* Fix visual glitches on background with fractional scaling [Daniel; !1464]
* Fix using correct refresh rate [Jonas; #1430]
* Misc. bug fixes and cleanups [Daniel, Carlos, Robert, Simon, Sergio; !1362,
!1448, !1452, !1273, !1454, !1429, !1460, !1458, !1463, !1462]
* Plugged memory leaks [Ray; !1449, !1451]
Contributors:
Marco Trevisan (Treviño), Benjamin Berg, Sergio Costas, Carlos Garnacho,
Karol Herbst, Peter Hutterer, Robert Mader, Simon McVittie, Ray Strode,
Daniel van Vugt, Jonas Ådahl
Translators:
Juliano de Souza Camargo [pt], Rafael Fontenelle [pt_BR],
Yosef Or Boczko [he], Jordi Mas [ca]
3.38.0
======
* screencast: Only use DMA buffers for i915 [Jonas; !1442]
* Fixed crashes [Jonas, Simon; !1430, #1414]
Contributors:
Simon McVittie, Jonas Ådahl
Translators:
Anders Jonsson [sv], Gil Forcada [ca], Balázs Meskó [hu], Tim Sabsch [de],
Milo Casagrande [it], Bruce Cowan [en_GB], Rūdolfs Mazurs [lv]
3.37.92
=======
* Fix stale cursor positions in remote desktop sessions [Georges; !1417]
* xwayland: Add a setting to disable selected X extensions [Olivier; !1405]
* Fix screencasting when using QXL [Jonas Å., Grey; !1318]
* Cull actors that don't intersect with the redraw clip [Daniel; !1359]
* Optimize painting of backgrounds when culling is unavailable [Daniel; !1363]
* Improve support for Hangul input method [Carlos; !1286]
* Support debug paint overlay for opaque regions [Robert; !1372]
* Fix launching flatpak applications when autostarting Xwayland [Carlos; !1424]
* Add support for capture scanouts in screencasts [Georges; !1421]
* Allow integrated tablet devices to cycle outputs [Carlos; !1201]
* Improve mapping input devices to the most relevant output [Carlos; !1202]
* Only enable auto-rotation in touch mode [Carlos; !1311]
* Fixed crashes [Pascal, Robert, Carlos, Benjamin, Marco; !1414, !1409, !1408,
!1415, #1395, !1392, !1371, #1345]
* Misc. bug fixes and cleanups [Björn, Jonas D., Florian; !1410, !1358, !1425]
Contributors:
Marco Trevisan (Treviño), Benjamin Berg, Grey Christoforo, Björn Daase,
Jonas Dreßler, Olivier Fourdan, Carlos Garnacho, Robert Mader,
Florian Müllner, Georges Basile Stavracas Neto, Pascal Nowack,
Daniel van Vugt, Jonas Ådahl
Translators:
Marek Černocký [cs], Aurimas Černius [lt], Asier Sarasua Garmendia [eu],
Gwan-gyeong Mun [ko], Yuri Chornoivan [uk], Boyuan Yang [zh_CN],
Kukuh Syafaat [id], Piotr Drąg [pl], Rafael Fontenelle [pt_BR],
Марко Костић [sr], Matej Urbančič [sl], Fabio Tomat [fur],
Daniel Mustieles [es], Fran Dieguez [gl], Goran Vidović [hr],
Claude Paroz [fr], Andre Klapper [or, ug, te], Emin Tufan Çetin [tr]
3.37.91
=======
* Fix initial state of display mode OSD [Jian-Hong; #1362]
* Fixed crashes [Jonas Å., Robert; !1407, !1411]
* Misc. bug fixes and cleanups [Jonas Å., Christian; !1404, !1364, #1331]
Contributors:
Jonas Ådahl, Robert Mader, Jian-Hong Pan, Christian Rauch
Translators:
Fran Dieguez [gl], Daniel Mustieles [es], Florentina Mușat [ro],
Kukuh Syafaat [id], Piotr Drąg [pl], Emin Tufan Çetin [tr], Марко Костић [sr],
Akarshan Biswas [bn_IN], Matej Urbančič [sl], Boyuan Yang [zh_CN],
Goran Vidović [hr], Rafael Fontenelle [pt_BR]
3.37.90
=======
* Fix using NEAREST filter for backgrounds on scaled monitors [Daniel V.; !1346]
@ -994,7 +557,7 @@ Contributors:
3.31.92
=======
* Fix flicker of apps that use multiple SHM buffers [Jonas Å.; #199]
* Don't disable page flips after temporary failures [Jonas Å.; #460]
* Don't disable page flips after temporary failues [Jonas Å.; #460]
* Improve redraw performance [Carlos; !196]
* Add cursor-mode support to window screencasting [Jonas Å.; !413]
* Add back support for system-wide monitor configurations [Jonas Å.; !253]
@ -1406,7 +969,7 @@ Translations:
=======
* Reduce memory use of suspended instances [Jonas; #786299]
* Make supported scales determination saner [Rui; #786474]
* Fix crash on inhibit-shortcuts dialog response [Jonas; #786385]
* Fix crash on inhibit-shortcuts dialog reponse [Jonas; #786385]
* Support libinput's tag-and-drag setting [freeroot; #775755]
* Avoid overlapping keybindings with multiple layouts [Jonas; #786408]
* Fix non-transformed cursor on rotated monitors [Jonas; #786023]
@ -1725,7 +1288,7 @@ Translations:
* Consider XDG_SESSION_TYPE when determining session type [Jouke; #759388]
* Re-add support for edge scrolling on some touchpads [Bastien; #768245]
* Support mouse and trackball acceleration profile [Jonas; #769179]
* Draw monitor content to individual framebuffer [Jonas; #768976]
* Draw monitor contentn to individual framebuffer [Jonas; #768976]
* Support virtual input devices [Jonas, Carlos; #765009]
* Set correct output scale on hotplug [Jonas; #769505]
* Misc. bug fixes and cleanups [Florian, Jonas, Thomas, Bastien, Carlos;
@ -2550,7 +2113,7 @@ Translations:
* Ignore skip-taskbar hints on parentless dialogs [Giovanni; #673399]
* Don't save pixbuf data in user data [Tim; #706777]
* Don't queue redraws for obscured regions [Adel; #703332]
* Support the opaque region hints for wayland clients [Jasper; #707019]
* Suppor the opaque region hints for wayland clients [Jasper; #707019]
* Turn blending off when drawing entirely opaque regions [Jasper; #707019]
* Check event timestamps before reconfiguring [Giovanni; #706735]
* Merge the DBus API for display configuration in the wayland branch [Giovanni]
@ -3035,7 +2598,7 @@ Translations:
======
* Automaximize large windows on map [Adel; #671677]
* When unmaximizing windows, make sure the unminimized size
is significantly less than the maximized size [Adel; #671677]
is signficantly less than the maximized size [Adel; #671677]
* Don't offer maximize option for windows larger than the screen
[Jasper; #643606]
* Always focus the window immediately underneath without restacking
@ -3135,7 +2698,7 @@ Translations:
* Move from GConf to GSettings for preferences [Florian; #635378]
* Add meta_display_add_keybinding()/meta_display_remove_keybinding()
to allow creating new keybindings at runtime [Florian; #663428]
* Add support for new _NET_WM_STATE_FOCUSED atom in _NET_WM_STATE
* Add suport for new _NET_WM_STATE_FOCUSED atom in _NET_WM_STATE
to allow applications to draw unfocused windows differently
[Rui; #661427]
* Add meta_window_move_resize_frame() to allow specifying the
@ -3247,7 +2810,7 @@ Contributors:
for easy resizing with thin borders. (New draggable_border_width GConf key
controls the total width of visible and invisible borders.)
[Jasper; #644930]
* Draw rounded window corners with antialiasing [Jasper; #628195]
* Draw rounded window corners with antialising [Jasper; #628195]
* Unredirect override-redirect fullscreen windows, such as full-screen
3D games to avoid any performance impact [Adel; #597014]
* Add :resizable and :above properties to MetaWindow. [Tim; #653858]
@ -3340,7 +2903,7 @@ Translations:
3.0.2.1
=======
* When saving the session, use the "program name" rather than
hardcoding mutter, fixing session saving for gnome-shell [Matthias]
harcoding mutter, fixing session saving for gnome-shell [Matthias]
https://bugzilla.gnome.org/show_bug.cgi?id=648828
Contributors:
@ -3658,7 +3221,7 @@ Bugs fixed:
634779 MetaWindowGroup: further optimize paints by using current scissor
634833 Draw the root window background
592382 improve shadow effect
628199 Add antialiasing to arc and line drawing operations
628199 Add antialising to arc and line drawing operations
633002 meta-actor-window: Use G_UNLIKELY for TFP check
634771 MetaStackTracker: Avoid queueing resync for obvious no-ops
635421 Fix crash in check_needs_shadow
@ -3855,7 +3418,7 @@ Fixed Bugs:
- Allow a theme to turn on title ellipsization
* Performance enhancements:
- Stream raw damage updates to ClutterX11TexturePixmap
to enable partial stage updates when windows change [Robert]
to enable partial stage updates when windos change [Robert]
- Don't trap XErrors in meta_compositor_process_event [Adel]
* Add meta_prefs_override_preference_location(); this allows
a plugin like GNOME Shell to redirect preferences to a
@ -3900,7 +3463,7 @@ Fixed Bugs:
613136 - remove over-restrictive assert from meta_prefs_get_workspace_name()
613398 - Don't trap XErrors in meta_compositor_process_event
615586 - Allow redirecting preferences to a different GConf key
615672 - can't compile mutter error: dereferencing pointer p does break
615672 - cant' compile mutter error: dereferencing pointer p does break
strict-aliasing rules
616050 - alt-tab infrastructure patches
616274 - mutter from git fails with gcc 4.5 (on new warning)
@ -4846,7 +4409,7 @@ Arthur Taylor, Elijah Newren, Josselin Mouette, Havoc Pennington,
Benjamin Berg, and Carlo Wood for improvements in this release.
- new icon for the force-quit dialog (Jaap) [#396655]
- add configurable mouse click action abilities, and clean up lots of
- add configureable mouse click action abilities, and clean up lots of
related code (Linus) [#408899, #408902, others]
- add schemeas for middle and right click titlebar actions (Charlie)
[#408903]
@ -5400,7 +4963,7 @@ this release.
running with --disable-gconf. Make --disable-gconf actually work.
(Elijah) [#326661]
- fix some reading-from-free'd-data errors (Søren) [#327575]
- fix an uninitialized value problem when in raise-on-click mode
- fix an unitialized value problem when in raise-on-click mode
(Søren) [#327572]
- avoid flashing original-sized window when closing a maximized
window (Elijah) [#317254]

View File

@ -26,34 +26,15 @@ debugging purposes.
To contribute, open merge requests at https://gitlab.gnome.org/GNOME/mutter.
It can be useful to look at the documentation available at the
[Wiki](https://gitlab.gnome.org/GNOME/mutter/-/wikis/home).
## Coding style and conventions
See [HACKING.md](./HACKING.md).
## Git messages
The coding style used is primarily the GNU flavor of the [GNOME coding
style](https://developer.gnome.org/programming-guidelines/stable/c-coding-style.html.en)
with some minor additions such as preferring `stdint.h` types over GLib
fundamental types, and a soft 80 character line limit. However, in general,
look at the file you're editing for inspiration.
Commit messages should follow the [GNOME commit message
guidelines](https://wiki.gnome.org/Git/CommitMessages). We require an URL
to either an issue or a merge request in each commit. Try to always prefix
commit subjects with a relevant topic, such as `compositor:` or
`clutter/actor:`, and it's always better to write too much in the commit
message body than too little.
## Default branch
The default development branch is `main`. If you still have a local
checkout under the old name, use:
```sh
git checkout master
git branch -m master main
git fetch
git branch --unset-upstream
git branch -u origin/main
git symbolic-ref refs/remotes/origin/HEAD refs/remotes/origin/main
```
to either an issue or a merge request in each commit.
## License

View File

@ -1,138 +0,0 @@
#!/bin/env python3
import argparse
import os
import re
import subprocess
import sys
import tempfile
# Path relative to this script
uncrustify_cfg = 'tools/uncrustify.cfg'
def run_diff(sha):
proc = subprocess.Popen(["git", "diff", "-U0", "--function-context", sha, "HEAD"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
files = proc.stdout.read().strip().decode('utf-8')
return files.split('\n')
def find_chunks(diff):
file_entry_re = re.compile('^\+\+\+ b/(.*)$')
diff_chunk_re = re.compile('^@@ -\d+,\d+ \+(\d+),(\d+)')
file = None
chunks = []
for line in diff:
match = file_entry_re.match(line)
if match:
file = match.group(1)
match = diff_chunk_re.match(line)
if match:
start = int(match.group(1))
len = int(match.group(2))
end = start + len
if len > 0 and (file.endswith('.c') or file.endswith('.h') or file.endswith('.vala')):
chunks.append({ 'file': file, 'start': start, 'end': end })
return chunks
def reformat_chunks(chunks, rewrite):
# Creates temp file with INDENT-ON/OFF comments
def create_temp_file(file, start, end):
with open(file) as f:
tmp = tempfile.NamedTemporaryFile()
tmp.write(b'/** *INDENT-OFF* **/\n')
for i, line in enumerate(f):
if i == start - 2:
tmp.write(b'/** *INDENT-ON* **/\n')
tmp.write(bytes(line, 'utf-8'))
if i == end - 2:
tmp.write(b'/** *INDENT-OFF* **/\n')
tmp.seek(0)
return tmp
# Removes uncrustify INDENT-ON/OFF helper comments
def remove_indent_comments(output):
tmp = tempfile.NamedTemporaryFile()
for line in output:
if line != b'/** *INDENT-OFF* **/\n' and line != b'/** *INDENT-ON* **/\n':
tmp.write(line)
tmp.seek(0)
return tmp
changed = None
for chunk in chunks:
# Add INDENT-ON/OFF comments
tmp = create_temp_file(chunk['file'], chunk['start'], chunk['end'])
# uncrustify chunk
proc = subprocess.Popen(["uncrustify", "-c", uncrustify_cfg, "-f", tmp.name], stdout=subprocess.PIPE)
reindented = proc.stdout.readlines()
proc.wait()
if proc.returncode != 0:
continue
tmp.close()
# Remove INDENT-ON/OFF comments
formatted = remove_indent_comments(reindented)
if dry_run is True:
# Show changes
proc = subprocess.Popen(["diff", "-up", "--color=always", chunk['file'], formatted.name], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
diff = proc.stdout.read().decode('utf-8')
if diff != '':
output = re.sub('\t', '\t', diff)
print(output)
changed = True
else:
# Apply changes
diff = subprocess.Popen(["diff", "-up", chunk['file'], formatted.name], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
patch = subprocess.Popen(["patch", chunk['file']], stdin=diff.stdout)
diff.stdout.close()
patch.communicate()
formatted.close()
return changed
parser = argparse.ArgumentParser(description='Check code style.')
parser.add_argument('--sha', metavar='SHA', type=str,
help='SHA for the commit to compare HEAD with')
parser.add_argument('--dry-run', '-d', type=bool,
action=argparse.BooleanOptionalAction,
help='Only print changes to stdout, do not change code')
parser.add_argument('--rewrite', '-r', type=bool,
action=argparse.BooleanOptionalAction,
help='Whether to amend the result to the last commit (e.g. \'git rebase --exec "%(prog)s -r"\')')
# Change CWD to script location, necessary for always locating the configuration file
os.chdir(os.path.dirname(os.path.abspath(sys.argv[0])))
args = parser.parse_args()
sha = args.sha or 'HEAD^'
rewrite = args.rewrite
dry_run = args.dry_run
diff = run_diff(sha)
chunks = find_chunks(diff)
changed = reformat_chunks(chunks, rewrite)
if dry_run is not True and rewrite is True:
proc = subprocess.Popen(["git", "commit", "--all", "--amend", "-C", "HEAD"], stdout=subprocess.DEVNULL)
os._exit(0)
elif dry_run is True and changed is True:
print ("\nIssue the following command in your local tree to apply the suggested changes (needs uncrustify installed):\n\n $ git rebase origin/main --exec \"./check-style.py -r\" \n")
os._exit(-1)
os._exit(0)

View File

@ -28,7 +28,7 @@
#include "cally-actor.h"
/*
* Auxiliary define, in order to get the clutter actor from the AtkObject using
* Auxiliar define, in order to get the clutter actor from the AtkObject using
* AtkGObject methods
*
*/

View File

@ -72,7 +72,9 @@
#include <glib.h>
#include <clutter/clutter.h>
#include "clutter/clutter-actor-private.h"
#ifdef CLUTTER_WINDOWING_X11
#include <clutter/x11/clutter-x11.h>
#endif
#include <math.h>
@ -765,11 +767,10 @@ static gboolean
cally_actor_action_do_action (AtkAction *action,
gint index)
{
CallyActor *cally_actor = NULL;
AtkStateSet *set = NULL;
CallyActorPrivate *priv = NULL;
CallyActorActionInfo *info = NULL;
gboolean did_action = FALSE;
CallyActor *cally_actor = NULL;
AtkStateSet *set = NULL;
CallyActorPrivate *priv = NULL;
CallyActorActionInfo *info = NULL;
cally_actor = CALLY_ACTOR (action);
priv = cally_actor->priv;
@ -777,19 +778,21 @@ cally_actor_action_do_action (AtkAction *action,
set = atk_object_ref_state_set (ATK_OBJECT (cally_actor));
if (atk_state_set_contains_state (set, ATK_STATE_DEFUNCT))
goto out;
return FALSE;
if (!atk_state_set_contains_state (set, ATK_STATE_SENSITIVE) ||
!atk_state_set_contains_state (set, ATK_STATE_SHOWING))
goto out;
return FALSE;
g_object_unref (set);
info = _cally_actor_get_action_info (cally_actor, index);
if (info == NULL)
goto out;
return FALSE;
if (info->do_action_func == NULL)
goto out;
return FALSE;
if (!priv->action_queue)
priv->action_queue = g_queue_new ();
@ -799,12 +802,7 @@ cally_actor_action_do_action (AtkAction *action,
if (!priv->action_idle_handler)
priv->action_idle_handler = g_idle_add (idle_do_action, cally_actor);
did_action = TRUE;
out:
g_clear_object (&set);
return did_action;
return TRUE;
}
static gboolean
@ -970,7 +968,7 @@ cally_actor_real_notify_clutter (GObject *obj,
* paint it; we don't want this to generate an ATK
* state change
*/
if (clutter_actor_is_painting_unmapped (actor))
if (clutter_actor_is_in_clone_paint (actor))
return;
state = ATK_STATE_SHOWING;
@ -1086,7 +1084,7 @@ cally_actor_add_action_full (CallyActor *cally_actor,
priv = cally_actor->priv;
info = g_new0 (CallyActorActionInfo, 1);
info = g_slice_new (CallyActorActionInfo);
info->name = g_strdup (action_name);
info->description = g_strdup (action_description);
info->keybinding = g_strdup (action_keybinding);
@ -1106,7 +1104,7 @@ cally_actor_add_action_full (CallyActor *cally_actor,
*
* Removes a action, using the @action_id returned by cally_actor_add_action()
*
* Return value: %TRUE if the operation was successful, %FALSE otherwise
* Return value: %TRUE if the operation was succesful, %FALSE otherwise
*
* Since: 1.4
*/
@ -1140,7 +1138,7 @@ cally_actor_remove_action (CallyActor *cally_actor,
* Removes an action, using the @action_name used when the action was added
* with cally_actor_add_action()
*
* Return value: %TRUE if the operation was successful, %FALSE otherwise
* Return value: %TRUE if the operation was succesful, %FALSE otherwise
*
* Since: 1.4
*/
@ -1191,5 +1189,5 @@ _cally_actor_destroy_action_info (gpointer action_info,
if (info->notify)
info->notify (info->user_data);
g_free (info);
g_slice_free (CallyActorActionInfo, info);
}

View File

@ -47,7 +47,7 @@ static AtkStateSet* cally_stage_ref_state_set (AtkObject *obj);
/* AtkWindow */
static void cally_stage_window_interface_init (AtkWindowIface *iface);
/* Auxiliary */
/* Auxiliar */
static void cally_stage_activate_cb (ClutterStage *stage,
gpointer data);
static void cally_stage_deactivate_cb (ClutterStage *stage,
@ -134,11 +134,8 @@ cally_stage_notify_key_focus_cb (ClutterStage *stage,
if (self->priv->key_focus != NULL)
{
if (self->priv->key_focus != CLUTTER_ACTOR (stage))
{
g_object_remove_weak_pointer (G_OBJECT (self->priv->key_focus),
(gpointer *) &self->priv->key_focus);
}
g_object_remove_weak_pointer (G_OBJECT (self->priv->key_focus),
(gpointer *) &self->priv->key_focus);
old = clutter_actor_get_accessible (self->priv->key_focus);
}
else
@ -163,11 +160,8 @@ cally_stage_notify_key_focus_cb (ClutterStage *stage,
*
* we remove the weak pointer above.
*/
if (key_focus != CLUTTER_ACTOR (stage))
{
g_object_add_weak_pointer (G_OBJECT (self->priv->key_focus),
(gpointer *) &self->priv->key_focus);
}
g_object_add_weak_pointer (G_OBJECT (self->priv->key_focus),
(gpointer *) &self->priv->key_focus);
new = clutter_actor_get_accessible (key_focus);
}
@ -228,7 +222,7 @@ cally_stage_window_interface_init (AtkWindowIface *iface)
/* At this moment AtkWindow is just about signals */
}
/* Auxiliary */
/* Auxiliar */
static void
cally_stage_activate_cb (ClutterStage *stage,
gpointer data)

View File

@ -1513,7 +1513,7 @@ cally_text_get_offset_at_point (AtkText *text,
}
/******** Auxiliary private methods ******/
/******** Auxiliar private methods ******/
/* ClutterText only maintains the current cursor position and a extra selection
bound, but this could be before or after the cursor. This method returns
@ -1552,7 +1552,7 @@ _cally_text_delete_text_cb (ClutterText *clutter_text,
g_return_if_fail (CALLY_IS_TEXT (data));
/* Ignore zero length deletions */
/* Ignore zero lengh deletions */
if (end_pos - start_pos == 0)
return;
@ -1653,7 +1653,7 @@ cally_text_insert_text (AtkEditableText *text,
clutter_text_insert_text (CLUTTER_TEXT (actor),
string, *position);
/* we suppose that the text insertion will be successful,
/* we suppose that the text insertion will be succesful,
clutter-text doesn't warn about it. A option would be search for
the text, but it seems not really required */
*position += length;
@ -1866,7 +1866,7 @@ static gint
_cally_atk_attribute_lookup_func (gconstpointer data,
gconstpointer user_data)
{
AtkTextAttribute attr = (AtkTextAttribute) GPOINTER_TO_INT (user_data);
AtkTextAttribute attr = (AtkTextAttribute) user_data;
AtkAttribute *at = (AtkAttribute *) data;
if (!g_strcmp0 (at->name, atk_text_attribute_get_name (attr)))
return 0;

View File

@ -54,7 +54,7 @@ clutter_actor_box_new (gfloat x_1,
ClutterActorBox *
clutter_actor_box_alloc (void)
{
return g_new0 (ClutterActorBox, 1);
return g_slice_new0 (ClutterActorBox);
}
/**
@ -130,7 +130,7 @@ ClutterActorBox *
clutter_actor_box_copy (const ClutterActorBox *box)
{
if (G_LIKELY (box != NULL))
return g_memdup2 (box, sizeof (ClutterActorBox));
return g_slice_dup (ClutterActorBox, box);
return NULL;
}
@ -148,7 +148,7 @@ void
clutter_actor_box_free (ClutterActorBox *box)
{
if (G_LIKELY (box != NULL))
g_free (box);
g_slice_free (ClutterActorBox, box);
}
/**
@ -320,7 +320,7 @@ clutter_actor_box_get_area (const ClutterActorBox *box)
* @y: Y coordinate of the point
*
* Checks whether a point with @x, @y coordinates is contained
* within @box
* withing @box
*
* Return value: %TRUE if the point is contained by the #ClutterActorBox
*
@ -554,7 +554,7 @@ _clutter_actor_box_enlarge_for_effects (ClutterActorBox *box)
*
* The reason this is important is because effects will use this
* API to determine the size of offscreen framebuffers and so for
* a fixed-size object that may be animated across the screen we
* a fixed-size object that may be animated accross the screen we
* want to make sure that the stage paint-box has an equally stable
* size so that effects aren't made to continuously re-allocate
* a corresponding fbo.
@ -583,7 +583,7 @@ _clutter_actor_box_enlarge_for_effects (ClutterActorBox *box)
/* Now we redefine the top-left relative to the bottom right based on the
* rounded width/height determined above + a constant so that the overall
* size of the box will be stable and not dependent on the box's
* size of the box will be stable and not dependant on the box's
* position.
*
* Adding 3px to the width/height will ensure we cover the maximum of

View File

@ -26,6 +26,23 @@
G_BEGIN_DECLS
/*< private >
* ClutterRedrawFlags:
* @CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION: Tells clutter the maximum
* extents of what needs to be redrawn lies within the actors
* current allocation. (Only use this for 2D actors though because
* any actor with depth may be projected outside of its allocation)
*
* Flags passed to the clutter_actor_queue_redraw_with_clip ()
* function
*
* Since: 1.6
*/
typedef enum
{
CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION = 1 << 0
} ClutterRedrawFlags;
/*< private >
* ClutterActorTraverseFlags:
* CLUTTER_ACTOR_TRAVERSE_DEPTH_FIRST: Traverse the graph in
@ -163,10 +180,10 @@ struct _ClutterTransformInfo
graphene_point_t pivot;
gfloat pivot_z;
graphene_matrix_t transform;
CoglMatrix transform;
guint transform_set : 1;
graphene_matrix_t child_transform;
CoglMatrix child_transform;
guint child_transform_set : 1;
};
@ -203,11 +220,11 @@ void _clutter_actor_traverse
gpointer user_data);
ClutterActor * _clutter_actor_get_stage_internal (ClutterActor *actor);
void _clutter_actor_apply_modelview_transform (ClutterActor *self,
graphene_matrix_t *matrix);
void _clutter_actor_apply_relative_transformation_matrix (ClutterActor *self,
ClutterActor *ancestor,
graphene_matrix_t *matrix);
void _clutter_actor_apply_modelview_transform (ClutterActor *self,
CoglMatrix *matrix);
void _clutter_actor_apply_relative_transformation_matrix (ClutterActor *self,
ClutterActor *ancestor,
CoglMatrix *matrix);
void _clutter_actor_rerealize (ClutterActor *self,
ClutterCallback callback,
@ -228,21 +245,30 @@ void _clutter_actor_set_has_pointer
void _clutter_actor_set_has_key_focus (ClutterActor *self,
gboolean has_key_focus);
void _clutter_actor_queue_redraw_with_clip (ClutterActor *self,
ClutterRedrawFlags flags,
const ClutterPaintVolume *clip_volume);
void _clutter_actor_queue_redraw_full (ClutterActor *self,
ClutterRedrawFlags flags,
const ClutterPaintVolume *volume,
ClutterEffect *effect);
void _clutter_actor_finish_queue_redraw (ClutterActor *self);
void _clutter_actor_finish_queue_redraw (ClutterActor *self,
ClutterPaintVolume *clip);
gboolean _clutter_actor_set_default_paint_volume (ClutterActor *self,
GType check_gtype,
ClutterPaintVolume *volume);
const char * _clutter_actor_get_debug_name (ClutterActor *self);
const gchar * _clutter_actor_get_debug_name (ClutterActor *self);
void _clutter_actor_push_clone_paint (void);
void _clutter_actor_pop_clone_paint (void);
void _clutter_actor_shader_pre_paint (ClutterActor *actor,
gboolean repeat);
void _clutter_actor_shader_post_paint (ClutterActor *actor);
ClutterActorAlign _clutter_actor_get_effective_x_align (ClutterActor *self);
void _clutter_actor_handle_event (ClutterActor *actor,
@ -252,6 +278,8 @@ void _clutter_actor_attach_clone
ClutterActor *clone);
void _clutter_actor_detach_clone (ClutterActor *actor,
ClutterActor *clone);
void _clutter_actor_queue_redraw_on_clones (ClutterActor *actor);
void _clutter_actor_queue_relayout_on_clones (ClutterActor *actor);
void _clutter_actor_queue_only_relayout (ClutterActor *actor);
void clutter_actor_clear_stage_views_recursive (ClutterActor *actor);
@ -260,17 +288,11 @@ float clutter_actor_get_real_resource_scale
ClutterPaintNode * clutter_actor_create_texture_paint_node (ClutterActor *self,
CoglTexture *texture);
void clutter_actor_finish_layout (ClutterActor *self,
int phase);
void clutter_actor_update_stage_views (ClutterActor *self,
int phase);
void clutter_actor_queue_immediate_relayout (ClutterActor *self);
gboolean clutter_actor_is_painting_unmapped (ClutterActor *self);
gboolean clutter_actor_get_redraw_clip (ClutterActor *self,
ClutterPaintVolume *dst_old_pv,
ClutterPaintVolume *dst_new_pv);
G_END_DECLS
#endif /* __CLUTTER_ACTOR_PRIVATE_H__ */

File diff suppressed because it is too large Load Diff

View File

@ -187,6 +187,7 @@ struct _ClutterActor
* chain up to the parent's implementation
* @pick: virtual function, used to draw an outline of the actor with
* the given color
* @queue_redraw: class handler for #ClutterActor::queue-redraw
* @event: class handler for #ClutterActor::event
* @button_press_event: class handler for #ClutterActor::button-press-event
* @button_release_event: class handler for
@ -238,6 +239,10 @@ struct _ClutterActorClass
void (* pick) (ClutterActor *actor,
ClutterPickContext *pick_context);
gboolean (* queue_redraw) (ClutterActor *actor,
ClutterActor *leaf_that_queued,
ClutterPaintVolume *paint_volume);
/* size negotiation */
void (* get_preferred_width) (ClutterActor *self,
gfloat for_height,
@ -252,7 +257,7 @@ struct _ClutterActorClass
/* transformations */
void (* apply_transform) (ClutterActor *actor,
graphene_matrix_t *matrix);
ClutterMatrix *matrix);
/* event signals */
gboolean (* event) (ClutterActor *actor,
@ -586,8 +591,7 @@ void clutter_actor_set_offscreen_redirect
CLUTTER_EXPORT
ClutterOffscreenRedirect clutter_actor_get_offscreen_redirect (ClutterActor *self);
CLUTTER_EXPORT
gboolean clutter_actor_should_pick (ClutterActor *self,
ClutterPickContext *pick_context);
gboolean clutter_actor_should_pick_paint (ClutterActor *self);
CLUTTER_EXPORT
gboolean clutter_actor_is_in_clone_paint (ClutterActor *self);
CLUTTER_EXPORT
@ -799,16 +803,16 @@ void clutter_actor_get_translation
gfloat *translate_z);
CLUTTER_EXPORT
void clutter_actor_set_transform (ClutterActor *self,
const graphene_matrix_t *transform);
const ClutterMatrix *transform);
CLUTTER_EXPORT
void clutter_actor_get_transform (ClutterActor *self,
graphene_matrix_t *transform);
ClutterMatrix *transform);
CLUTTER_EXPORT
void clutter_actor_set_child_transform (ClutterActor *self,
const graphene_matrix_t *transform);
const ClutterMatrix *transform);
CLUTTER_EXPORT
void clutter_actor_get_child_transform (ClutterActor *self,
graphene_matrix_t *transform);
ClutterMatrix *transform);
CLUTTER_EXPORT
void clutter_actor_get_transformed_extents (ClutterActor *self,
@ -931,9 +935,6 @@ GList * clutter_actor_peek_stage_views (ClutterActor *self);
CLUTTER_EXPORT
void clutter_actor_invalidate_transform (ClutterActor *self);
CLUTTER_EXPORT
void clutter_actor_invalidate_paint_volume (ClutterActor *self);
G_END_DECLS
#endif /* __CLUTTER_ACTOR_H__ */

View File

@ -83,6 +83,7 @@ G_DEFINE_AUTOPTR_CLEANUP_FUNC (ClutterZoomAction, g_object_unref)
G_DEFINE_AUTOPTR_CLEANUP_FUNC (ClutterActorBox, clutter_actor_box_free)
G_DEFINE_AUTOPTR_CLEANUP_FUNC (ClutterColor, clutter_color_free)
G_DEFINE_AUTOPTR_CLEANUP_FUNC (ClutterMargin, clutter_margin_free)
G_DEFINE_AUTOPTR_CLEANUP_FUNC (ClutterMatrix, clutter_matrix_free)
G_DEFINE_AUTOPTR_CLEANUP_FUNC (ClutterPaintContext, clutter_paint_context_unref)
G_DEFINE_AUTOPTR_CLEANUP_FUNC (ClutterPaintNode, clutter_paint_node_unref)
G_DEFINE_AUTOPTR_CLEANUP_FUNC (ClutterPaintVolume, clutter_paint_volume_free)

View File

@ -73,6 +73,7 @@ struct _ClutterBackendClass
ClutterStageWindow * (* create_stage) (ClutterBackend *backend,
ClutterStage *wrapper,
GError **error);
void (* init_events) (ClutterBackend *backend);
void (* init_features) (ClutterBackend *backend);
void (* add_options) (ClutterBackend *backend,
GOptionGroup *group);
@ -115,6 +116,12 @@ gboolean _clutter_backend_pre_parse (Clutter
gboolean _clutter_backend_post_parse (ClutterBackend *backend,
GError **error);
void _clutter_backend_init_events (ClutterBackend *backend);
void _clutter_backend_copy_event_data (ClutterBackend *backend,
const ClutterEvent *src,
ClutterEvent *dest);
void _clutter_backend_free_event_data (ClutterBackend *backend,
ClutterEvent *event);
CLUTTER_EXPORT
gboolean _clutter_backend_translate_event (ClutterBackend *backend,
gpointer native,
@ -139,9 +146,6 @@ float clutter_backend_get_fallback_resource_scale (ClutterBackend *backend);
gboolean clutter_backend_is_display_server (ClutterBackend *backend);
CLUTTER_EXPORT
void clutter_backend_destroy (ClutterBackend *backend);
G_END_DECLS
#endif /* __CLUTTER_BACKEND_PRIVATE_H__ */

View File

@ -40,6 +40,8 @@
#include "clutter-build-config.h"
#define CLUTTER_ENABLE_EXPERIMENTAL_API
#include "clutter-backend-private.h"
#include "clutter-debug.h"
#include "clutter-event-private.h"
@ -50,8 +52,18 @@
#include "clutter-stage-private.h"
#include "clutter-stage-window.h"
#ifdef CLUTTER_HAS_WAYLAND_COMPOSITOR_SUPPORT
#include "wayland/clutter-wayland-compositor.h"
#endif
#include <cogl/cogl.h>
#ifdef CLUTTER_HAS_WAYLAND_COMPOSITOR_SUPPORT
#include <cogl/cogl-wayland-server.h>
#include <wayland-server.h>
#include "wayland/clutter-wayland-compositor.h"
#endif
#define DEFAULT_FONT_NAME "Sans 10"
enum
@ -67,6 +79,12 @@ G_DEFINE_ABSTRACT_TYPE (ClutterBackend, clutter_backend, G_TYPE_OBJECT)
static guint backend_signals[LAST_SIGNAL] = { 0, };
/* Global for being able to specify a compositor side wayland display
* pointer before clutter initialization */
#ifdef CLUTTER_HAS_WAYLAND_COMPOSITOR_SUPPORT
static struct wl_display *_wayland_compositor_display;
#endif
static void
clutter_backend_dispose (GObject *gobject)
{
@ -75,20 +93,28 @@ clutter_backend_dispose (GObject *gobject)
/* clear the events still in the queue of the main context */
_clutter_clear_events_queue ();
g_clear_object (&backend->dummy_onscreen);
g_clear_pointer (&backend->dummy_onscreen, cogl_object_unref);
if (backend->stage_window)
{
g_object_remove_weak_pointer (G_OBJECT (backend->stage_window),
(gpointer *) &backend->stage_window);
backend->stage_window = NULL;
}
g_clear_pointer (&backend->cogl_source, g_source_destroy);
g_clear_pointer (&backend->font_name, g_free);
g_clear_pointer (&backend->font_options, cairo_font_options_destroy);
G_OBJECT_CLASS (clutter_backend_parent_class)->dispose (gobject);
}
static void
clutter_backend_finalize (GObject *gobject)
{
ClutterBackend *backend = CLUTTER_BACKEND (gobject);
g_source_destroy (backend->cogl_source);
g_free (backend->font_name);
clutter_backend_set_font_options (backend, NULL);
g_clear_object (&backend->input_method);
G_OBJECT_CLASS (clutter_backend_parent_class)->dispose (gobject);
G_OBJECT_CLASS (clutter_backend_parent_class)->finalize (gobject);
}
static gfloat
@ -189,20 +215,22 @@ clutter_backend_do_real_create_context (ClutterBackend *backend,
{
ClutterBackendClass *klass;
CoglSwapChain *swap_chain;
GError *internal_error;
klass = CLUTTER_BACKEND_GET_CLASS (backend);
swap_chain = NULL;
internal_error = NULL;
CLUTTER_NOTE (BACKEND, "Creating Cogl renderer");
backend->cogl_renderer = klass->get_renderer (backend, error);
backend->cogl_renderer = klass->get_renderer (backend, &internal_error);
if (backend->cogl_renderer == NULL)
goto error;
CLUTTER_NOTE (BACKEND, "Connecting the renderer");
cogl_renderer_set_driver (backend->cogl_renderer, driver_id);
if (!cogl_renderer_connect (backend->cogl_renderer, error))
if (!cogl_renderer_connect (backend->cogl_renderer, &internal_error))
goto error;
CLUTTER_NOTE (BACKEND, "Creating Cogl swap chain");
@ -214,7 +242,7 @@ clutter_backend_do_real_create_context (ClutterBackend *backend,
backend->cogl_display = klass->get_display (backend,
backend->cogl_renderer,
swap_chain,
error);
&internal_error);
}
else
{
@ -230,7 +258,7 @@ clutter_backend_do_real_create_context (ClutterBackend *backend,
*/
res = cogl_renderer_check_onscreen_template (backend->cogl_renderer,
tmpl,
error);
&internal_error);
if (!res)
goto error;
@ -244,12 +272,17 @@ clutter_backend_do_real_create_context (ClutterBackend *backend,
if (backend->cogl_display == NULL)
goto error;
#ifdef CLUTTER_HAS_WAYLAND_COMPOSITOR_SUPPORT
cogl_wayland_display_set_compositor_display (backend->cogl_display,
_wayland_compositor_display);
#endif
CLUTTER_NOTE (BACKEND, "Setting up the display");
if (!cogl_display_setup (backend->cogl_display, error))
if (!cogl_display_setup (backend->cogl_display, &internal_error))
goto error;
CLUTTER_NOTE (BACKEND, "Creating the Cogl context");
backend->cogl_context = cogl_context_new (backend->cogl_display, error);
backend->cogl_context = cogl_context_new (backend->cogl_display, &internal_error);
if (backend->cogl_context == NULL)
goto error;
@ -413,12 +446,19 @@ _clutter_create_backend (void)
return retval;
}
static void
clutter_backend_real_init_events (ClutterBackend *backend)
{
g_error ("Unknown input backend");
}
static void
clutter_backend_class_init (ClutterBackendClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
gobject_class->dispose = clutter_backend_dispose;
gobject_class->finalize = clutter_backend_finalize;
/**
* ClutterBackend::resolution-changed:
@ -474,6 +514,7 @@ clutter_backend_class_init (ClutterBackendClass *klass)
klass->resolution_changed = clutter_backend_real_resolution_changed;
klass->font_changed = clutter_backend_real_font_changed;
klass->init_events = clutter_backend_real_init_events;
klass->create_context = clutter_backend_real_create_context;
klass->get_features = clutter_backend_real_get_features;
}
@ -612,6 +653,17 @@ _clutter_backend_get_features (ClutterBackend *backend)
return 0;
}
void
_clutter_backend_init_events (ClutterBackend *backend)
{
ClutterBackendClass *klass;
g_assert (CLUTTER_IS_BACKEND (backend));
klass = CLUTTER_BACKEND_GET_CLASS (backend);
klass->init_events (backend);
}
gfloat
_clutter_backend_get_units_per_em (ClutterBackend *backend,
PangoFontDescription *font_desc)
@ -626,6 +678,31 @@ _clutter_backend_get_units_per_em (ClutterBackend *backend,
return backend->units_per_em;
}
void
_clutter_backend_copy_event_data (ClutterBackend *backend,
const ClutterEvent *src,
ClutterEvent *dest)
{
ClutterSeatClass *seat_class;
ClutterSeat *seat;
seat = clutter_backend_get_default_seat (backend);
seat_class = CLUTTER_SEAT_GET_CLASS (seat);
seat_class->copy_event_data (seat, src, dest);
}
void
_clutter_backend_free_event_data (ClutterBackend *backend,
ClutterEvent *event)
{
ClutterSeatClass *seat_class;
ClutterSeat *seat;
seat = clutter_backend_get_default_seat (backend);
seat_class = CLUTTER_SEAT_GET_CLASS (seat);
seat_class->free_event_data (seat, event);
}
/**
* clutter_get_default_backend:
*
@ -795,6 +872,31 @@ clutter_backend_get_cogl_context (ClutterBackend *backend)
return backend->cogl_context;
}
#ifdef CLUTTER_HAS_WAYLAND_COMPOSITOR_SUPPORT
/**
* clutter_wayland_set_compositor_display:
* @display: A compositor side struct wl_display pointer
*
* This informs Clutter of your compositor side Wayland display
* object. This must be called before calling clutter_init().
*
* Since: 1.8
* Stability: unstable
*/
void
clutter_wayland_set_compositor_display (void *display)
{
if (_clutter_context_is_initialized ())
{
g_warning ("%s() can only be used before calling clutter_init()",
G_STRFUNC);
return;
}
_wayland_compositor_display = display;
}
#endif
void
clutter_set_allowed_drivers (const char *drivers)
{
@ -875,10 +977,3 @@ clutter_backend_is_display_server (ClutterBackend *backend)
{
return CLUTTER_BACKEND_GET_CLASS (backend)->is_display_server (backend);
}
void
clutter_backend_destroy (ClutterBackend *backend)
{
g_object_run_dispose (G_OBJECT (backend));
g_object_unref (backend);
}

View File

@ -33,6 +33,7 @@
#include <cogl/cogl.h>
#include <clutter/clutter-config.h>
#include <clutter/clutter-keymap.h>
#include <clutter/clutter-types.h>
#include <clutter/clutter-seat.h>

View File

@ -59,7 +59,7 @@
ClutterMargin *
clutter_margin_new (void)
{
return g_new0 (ClutterMargin, 1);
return g_slice_new0 (ClutterMargin);
}
/**
@ -77,7 +77,7 @@ ClutterMargin *
clutter_margin_copy (const ClutterMargin *margin_)
{
if (G_LIKELY (margin_ != NULL))
return g_memdup2 (margin_, sizeof (ClutterMargin));
return g_slice_dup (ClutterMargin, margin_);
return NULL;
}
@ -95,9 +95,198 @@ void
clutter_margin_free (ClutterMargin *margin_)
{
if (G_LIKELY (margin_ != NULL))
g_free (margin_);
g_slice_free (ClutterMargin, margin_);
}
G_DEFINE_BOXED_TYPE (ClutterMargin, clutter_margin,
clutter_margin_copy,
clutter_margin_free)
/**
* ClutterMatrix:
*
* A type representing a 4x4 matrix.
*
* It is identicaly to #CoglMatrix.
*
* Since: 1.12
*/
static gpointer
clutter_matrix_copy (gpointer data)
{
return cogl_matrix_copy (data);
}
static gboolean
clutter_matrix_progress (const GValue *a,
const GValue *b,
gdouble progress,
GValue *retval)
{
const ClutterMatrix *matrix1 = g_value_get_boxed (a);
const ClutterMatrix *matrix2 = g_value_get_boxed (b);
graphene_point3d_t scale1 = GRAPHENE_POINT3D_INIT (1.f, 1.f, 1.f);
float shear1[3] = { 0.f, 0.f, 0.f };
graphene_point3d_t rotate1 = GRAPHENE_POINT3D_INIT_ZERO;
graphene_point3d_t translate1 = GRAPHENE_POINT3D_INIT_ZERO;
ClutterVertex4 perspective1 = { 0.f, 0.f, 0.f, 0.f };
graphene_point3d_t scale2 = GRAPHENE_POINT3D_INIT (1.f, 1.f, 1.f);
float shear2[3] = { 0.f, 0.f, 0.f };
graphene_point3d_t rotate2 = GRAPHENE_POINT3D_INIT_ZERO;
graphene_point3d_t translate2 = GRAPHENE_POINT3D_INIT_ZERO;
ClutterVertex4 perspective2 = { 0.f, 0.f, 0.f, 0.f };
graphene_point3d_t scale_res = GRAPHENE_POINT3D_INIT (1.f, 1.f, 1.f);
float shear_res = 0.f;
graphene_point3d_t rotate_res = GRAPHENE_POINT3D_INIT_ZERO;
graphene_point3d_t translate_res = GRAPHENE_POINT3D_INIT_ZERO;
ClutterVertex4 perspective_res = { 0.f, 0.f, 0.f, 0.f };
ClutterMatrix res;
clutter_matrix_init_identity (&res);
_clutter_util_matrix_decompose (matrix1,
&scale1, shear1, &rotate1, &translate1,
&perspective1);
_clutter_util_matrix_decompose (matrix2,
&scale2, shear2, &rotate2, &translate2,
&perspective2);
/* perspective */
_clutter_util_vertex4_interpolate (&perspective1, &perspective2, progress, &perspective_res);
res.wx = perspective_res.x;
res.wy = perspective_res.y;
res.wz = perspective_res.z;
res.ww = perspective_res.w;
/* translation */
graphene_point3d_interpolate (&translate1, &translate2, progress, &translate_res);
cogl_matrix_translate (&res, translate_res.x, translate_res.y, translate_res.z);
/* rotation */
graphene_point3d_interpolate (&rotate1, &rotate2, progress, &rotate_res);
cogl_matrix_rotate (&res, rotate_res.x, 1.0f, 0.0f, 0.0f);
cogl_matrix_rotate (&res, rotate_res.y, 0.0f, 1.0f, 0.0f);
cogl_matrix_rotate (&res, rotate_res.z, 0.0f, 0.0f, 1.0f);
/* skew */
shear_res = shear1[2] + (shear2[2] - shear1[2]) * progress; /* YZ */
if (shear_res != 0.f)
_clutter_util_matrix_skew_yz (&res, shear_res);
shear_res = shear1[1] + (shear2[1] - shear1[1]) * progress; /* XZ */
if (shear_res != 0.f)
_clutter_util_matrix_skew_xz (&res, shear_res);
shear_res = shear1[0] + (shear2[0] - shear1[0]) * progress; /* XY */
if (shear_res != 0.f)
_clutter_util_matrix_skew_xy (&res, shear_res);
/* scale */
graphene_point3d_interpolate (&scale1, &scale2, progress, &scale_res);
cogl_matrix_scale (&res, scale_res.x, scale_res.y, scale_res.z);
g_value_set_boxed (retval, &res);
return TRUE;
}
G_DEFINE_BOXED_TYPE_WITH_CODE (ClutterMatrix, clutter_matrix,
clutter_matrix_copy,
clutter_matrix_free,
CLUTTER_REGISTER_INTERVAL_PROGRESS (clutter_matrix_progress))
/**
* clutter_matrix_alloc:
*
* Allocates enough memory to hold a #ClutterMatrix.
*
* Return value: (transfer full): the newly allocated #ClutterMatrix
*
* Since: 1.12
*/
ClutterMatrix *
clutter_matrix_alloc (void)
{
return g_new0 (ClutterMatrix, 1);
}
/**
* clutter_matrix_free:
* @matrix: (allow-none): a #ClutterMatrix
*
* Frees the memory allocated by clutter_matrix_alloc().
*
* Since: 1.12
*/
void
clutter_matrix_free (ClutterMatrix *matrix)
{
cogl_matrix_free (matrix);
}
/**
* clutter_matrix_init_identity:
* @matrix: a #ClutterMatrix
*
* Initializes @matrix with the identity matrix, i.e.:
*
* |[
* .xx = 1.0, .xy = 0.0, .xz = 0.0, .xw = 0.0
* .yx = 0.0, .yy = 1.0, .yz = 0.0, .yw = 0.0
* .zx = 0.0, .zy = 0.0, .zz = 1.0, .zw = 0.0
* .wx = 0.0, .wy = 0.0, .wz = 0.0, .ww = 1.0
* ]|
*
* Return value: (transfer none): the initialized #ClutterMatrix
*
* Since: 1.12
*/
ClutterMatrix *
clutter_matrix_init_identity (ClutterMatrix *matrix)
{
cogl_matrix_init_identity (matrix);
return matrix;
}
/**
* clutter_matrix_init_from_array:
* @matrix: a #ClutterMatrix
* @values: (array fixed-size=16): a C array of 16 floating point values,
* representing a 4x4 matrix, with column-major order
*
* Initializes @matrix with the contents of a C array of floating point
* values.
*
* Return value: (transfer none): the initialzed #ClutterMatrix
*
* Since: 1.12
*/
ClutterMatrix *
clutter_matrix_init_from_array (ClutterMatrix *matrix,
const float values[16])
{
cogl_matrix_init_from_array (matrix, values);
return matrix;
}
/**
* clutter_matrix_init_from_matrix:
* @a: the #ClutterMatrix to initialize
* @b: the #ClutterMatrix to copy
*
* Initializes the #ClutterMatrix @a with the contents of the
* #ClutterMatrix @b.
*
* Return value: (transfer none): the initialized #ClutterMatrix
*
* Since: 1.12
*/
ClutterMatrix *
clutter_matrix_init_from_matrix (ClutterMatrix *a,
const ClutterMatrix *b)
{
return memcpy (a, b, sizeof (ClutterMatrix));
}

View File

@ -35,7 +35,7 @@
#undef CBZ_L2T_INTERPOLATION
/****************************************************************************
* ClutterBezier -- representation of a cubic bezier curve *
* ClutterBezier -- represenation of a cubic bezier curve *
* (private; a building block for the public bspline object) *
****************************************************************************/
@ -104,7 +104,7 @@ struct _ClutterBezier
ClutterBezier *
_clutter_bezier_new (void)
{
return g_new0 (ClutterBezier, 1);
return g_slice_new0 (ClutterBezier);
}
void
@ -112,7 +112,7 @@ _clutter_bezier_free (ClutterBezier * b)
{
if (G_LIKELY (b))
{
g_free (b);
g_slice_free (ClutterBezier, b);
}
}
@ -213,7 +213,7 @@ sqrti (int number)
* algorithm does not calculate the square root, but its reciprocal ('y'
* below), which is only at the end turned to the inverse value. In order
* for the algorithm to produce satisfactory results, the reciprocal value
* must be represented with sufficient precision; the 16.16 we use
* must be represented with sufficient precission; the 16.16 we use
* elsewhere in clutter is not good enough, and 10.22 is used instead.
*/
_FixedT x;
@ -236,7 +236,7 @@ sqrti (int number)
/* Now, we convert the float to 10.22 fixed. We exploit the mechanism
* described at http://www.d6.com/users/checker/pdfs/gdmfp.pdf.
*
* We want 22 bit fraction; a single precision float uses 23 bit
* We want 22 bit fraction; a single precission float uses 23 bit
* mantisa, so we only need to add 2^(23-22) (no need for the 1.5
* multiplier as we are only dealing with positive numbers).
*
@ -256,7 +256,7 @@ sqrti (int number)
flt2.i = (flt2.i >> 11) * (y_1 >> 11);
/* If the original argument is less than 342, we do another
* iteration to improve precision (for arguments >= 342, the single
* iteration to improve precission (for arguments >= 342, the single
* iteration produces generally better results).
*/
if (x < 171)

View File

@ -189,7 +189,7 @@ binding_entry_new (const gchar *name,
modifiers = modifiers & BINDING_MOD_MASK;
entry = g_new0 (ClutterBindingEntry, 1);
entry = g_slice_new (ClutterBindingEntry);
entry->key_val = key_val;
entry->modifiers = modifiers;
entry->name = (gchar *) g_intern_string (name);
@ -221,7 +221,7 @@ binding_entry_free (gpointer data)
g_closure_unref (entry->closure);
g_free (entry);
g_slice_free (ClutterBindingEntry, entry);
}
}

View File

@ -39,6 +39,8 @@
#include "clutter-build-config.h"
#define CLUTTER_ENABLE_EXPERIMENTAL_API
#include "clutter-blur-effect.h"
#include "cogl/cogl.h"
@ -79,6 +81,9 @@ struct _ClutterBlurEffect
gint pixel_step_uniform;
gint tex_width;
gint tex_height;
CoglPipeline *pipeline;
};
@ -93,42 +98,20 @@ G_DEFINE_TYPE (ClutterBlurEffect,
clutter_blur_effect,
CLUTTER_TYPE_OFFSCREEN_EFFECT);
static CoglPipeline *
clutter_blur_effect_create_pipeline (ClutterOffscreenEffect *effect,
CoglTexture *texture)
{
ClutterBlurEffect *blur_effect = CLUTTER_BLUR_EFFECT (effect);
if (blur_effect->pixel_step_uniform > -1)
{
float pixel_step[2];
int tex_width, tex_height;
tex_width = cogl_texture_get_width (texture);
tex_height = cogl_texture_get_height (texture);
pixel_step[0] = 1.0f / tex_width;
pixel_step[1] = 1.0f / tex_height;
cogl_pipeline_set_uniform_float (blur_effect->pipeline,
blur_effect->pixel_step_uniform,
2, /* n_components */
1, /* count */
pixel_step);
}
cogl_pipeline_set_layer_texture (blur_effect->pipeline, 0, texture);
return cogl_object_ref (blur_effect->pipeline);
}
static gboolean
clutter_blur_effect_pre_paint (ClutterEffect *effect,
ClutterPaintNode *node,
ClutterPaintContext *paint_context)
{
ClutterBlurEffect *self = CLUTTER_BLUR_EFFECT (effect);
ClutterEffectClass *parent_class;
if (!clutter_actor_meta_get_enabled (CLUTTER_ACTOR_META (effect)))
return FALSE;
self->actor = clutter_actor_meta_get_actor (CLUTTER_ACTOR_META (effect));
if (self->actor == NULL)
return FALSE;
if (!clutter_feature_available (CLUTTER_FEATURE_SHADERS_GLSL))
{
/* if we don't have support for GLSL shaders then we
@ -142,7 +125,59 @@ clutter_blur_effect_pre_paint (ClutterEffect *effect,
}
parent_class = CLUTTER_EFFECT_CLASS (clutter_blur_effect_parent_class);
return parent_class->pre_paint (effect, node, paint_context);
if (parent_class->pre_paint (effect, paint_context))
{
ClutterOffscreenEffect *offscreen_effect =
CLUTTER_OFFSCREEN_EFFECT (effect);
CoglHandle texture;
texture = clutter_offscreen_effect_get_texture (offscreen_effect);
self->tex_width = cogl_texture_get_width (texture);
self->tex_height = cogl_texture_get_height (texture);
if (self->pixel_step_uniform > -1)
{
gfloat pixel_step[2];
pixel_step[0] = 1.0f / self->tex_width;
pixel_step[1] = 1.0f / self->tex_height;
cogl_pipeline_set_uniform_float (self->pipeline,
self->pixel_step_uniform,
2, /* n_components */
1, /* count */
pixel_step);
}
cogl_pipeline_set_layer_texture (self->pipeline, 0, texture);
return TRUE;
}
else
return FALSE;
}
static void
clutter_blur_effect_paint_target (ClutterOffscreenEffect *effect,
ClutterPaintContext *paint_context)
{
ClutterBlurEffect *self = CLUTTER_BLUR_EFFECT (effect);
CoglFramebuffer *framebuffer =
clutter_paint_context_get_framebuffer (paint_context);
guint8 paint_opacity;
paint_opacity = clutter_actor_get_paint_opacity (self->actor);
cogl_pipeline_set_color4ub (self->pipeline,
paint_opacity,
paint_opacity,
paint_opacity,
paint_opacity);
cogl_framebuffer_draw_rectangle (framebuffer,
self->pipeline,
0, 0,
self->tex_width, self->tex_height);
}
static gboolean
@ -194,7 +229,7 @@ clutter_blur_effect_class_init (ClutterBlurEffectClass *klass)
effect_class->modify_paint_volume = clutter_blur_effect_modify_paint_volume;
offscreen_class = CLUTTER_OFFSCREEN_EFFECT_CLASS (klass);
offscreen_class->create_pipeline = clutter_blur_effect_create_pipeline;
offscreen_class->paint_target = clutter_blur_effect_paint_target;
}
static void

View File

@ -1,431 +0,0 @@
/*
* Copyright (C) 2020 Endless OS Foundation, LLC
*
* 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/>.
*/
#include "clutter-blur-private.h"
#include "clutter-backend.h"
/**
* SECTION:clutter-blur
* @short_description: Blur textures
*
* #ClutterBlur is a moderately fast gaussian blur implementation.
*
* # Optimizations
*
* There are a number of optimizations in place to make this blur implementation
* real-time. All in all, the implementation performs best when using large
* blur-radii that allow downscaling the texture to smaller sizes, at small
* radii where no downscaling is possible this can easily halve the framerate.
*
* ## Multipass
*
* It is implemented in 2 passes: vertical and horizontal.
*
* ## Downscaling
*
* #ClutterBlur uses dynamic downscaling to speed up blurring. Downscaling
* happens in factors of 2 (the image is downscaled either by 2, 4, 8, 16, )
* and depends on the blur radius, the texture size, among others.
*
* The texture is drawn into a downscaled framebuffer; the blur passes are
* applied on the downscaled texture contents; and finally, the blurred
* contents are drawn
* upscaled again.
*
* ## Hardware Interpolation
*
* This blur implementation cuts down the number of sampling operations by
* exploiting the hardware interpolation that is performed when sampling between
* pixel boundaries. This technique is described at:
*
* http://rastergrid.com/blog/2010/09/efficient-gaussian-blur-with-linear-sampling/
*
* ## Incremental gauss-factor calculation
*
* The kernel values for the gaussian kernel are computed incrementally instead
* of running the expensive calculations multiple times inside the blur shader.
* The implementation is based on the algorithm presented by K. Turkowski in
* GPU Gems 3, chapter 40:
*
* https://developer.nvidia.com/gpugems/GPUGems3/gpugems3_ch40.html
*
*/
static const char *gaussian_blur_glsl_declarations =
"uniform float sigma; \n"
"uniform float pixel_step; \n"
"uniform vec2 direction; \n";
static const char *gaussian_blur_glsl =
" vec2 uv = vec2 (cogl_tex_coord.st); \n"
" \n"
" vec3 gauss_coefficient; \n"
" gauss_coefficient.x = 1.0 / (sqrt (2.0 * 3.14159265) * sigma); \n"
" gauss_coefficient.y = exp (-0.5 / (sigma * sigma)); \n"
" gauss_coefficient.z = gauss_coefficient.y * gauss_coefficient.y; \n"
" \n"
" float gauss_coefficient_total = gauss_coefficient.x; \n"
" \n"
" vec4 ret = texture2D (cogl_sampler, uv) * gauss_coefficient.x; \n"
" gauss_coefficient.xy *= gauss_coefficient.yz; \n"
" \n"
" int n_steps = int (ceil (1.5 * sigma)) * 2; \n"
" \n"
" for (int i = 1; i <= n_steps; i += 2) { \n"
" float coefficient_subtotal = gauss_coefficient.x; \n"
" gauss_coefficient.xy *= gauss_coefficient.yz; \n"
" coefficient_subtotal += gauss_coefficient.x; \n"
" \n"
" float gauss_ratio = gauss_coefficient.x / coefficient_subtotal; \n"
" \n"
" float foffset = float (i) + gauss_ratio; \n"
" vec2 offset = direction * foffset * pixel_step; \n"
" \n"
" ret += texture2D (cogl_sampler, uv + offset) * coefficient_subtotal; \n"
" ret += texture2D (cogl_sampler, uv - offset) * coefficient_subtotal; \n"
" \n"
" gauss_coefficient_total += 2.0 * coefficient_subtotal; \n"
" gauss_coefficient.xy *= gauss_coefficient.yz; \n"
" } \n"
" \n"
" cogl_texel = ret / gauss_coefficient_total; \n";
#define MIN_DOWNSCALE_SIZE 256.f
#define MAX_SIGMA 6.f
enum
{
VERTICAL,
HORIZONTAL,
};
typedef struct
{
CoglFramebuffer *framebuffer;
CoglPipeline *pipeline;
CoglTexture *texture;
int orientation;
} BlurPass;
struct _ClutterBlur
{
CoglTexture *source_texture;
float sigma;
float downscale_factor;
BlurPass pass[2];
};
static CoglPipeline*
create_blur_pipeline (void)
{
static CoglPipelineKey blur_pipeline_key = "clutter-blur-pipeline-private";
CoglContext *ctx =
clutter_backend_get_cogl_context (clutter_get_default_backend ());
CoglPipeline *blur_pipeline;
blur_pipeline =
cogl_context_get_named_pipeline (ctx, &blur_pipeline_key);
if (G_UNLIKELY (blur_pipeline == NULL))
{
CoglSnippet *snippet;
blur_pipeline = cogl_pipeline_new (ctx);
cogl_pipeline_set_layer_null_texture (blur_pipeline, 0);
cogl_pipeline_set_layer_filters (blur_pipeline,
0,
COGL_PIPELINE_FILTER_LINEAR,
COGL_PIPELINE_FILTER_LINEAR);
cogl_pipeline_set_layer_wrap_mode (blur_pipeline,
0,
COGL_PIPELINE_WRAP_MODE_CLAMP_TO_EDGE);
snippet = cogl_snippet_new (COGL_SNIPPET_HOOK_TEXTURE_LOOKUP,
gaussian_blur_glsl_declarations,
NULL);
cogl_snippet_set_replace (snippet, gaussian_blur_glsl);
cogl_pipeline_add_layer_snippet (blur_pipeline, 0, snippet);
cogl_object_unref (snippet);
cogl_context_set_named_pipeline (ctx, &blur_pipeline_key, blur_pipeline);
}
return cogl_pipeline_copy (blur_pipeline);
}
static void
update_blur_uniforms (ClutterBlur *blur,
BlurPass *pass)
{
gboolean vertical = pass->orientation == VERTICAL;
int sigma_uniform;
int pixel_step_uniform;
int direction_uniform;
pixel_step_uniform =
cogl_pipeline_get_uniform_location (pass->pipeline, "pixel_step");
if (pixel_step_uniform > -1)
{
float pixel_step;
if (vertical)
pixel_step = 1.f / cogl_texture_get_height (pass->texture);
else
pixel_step = 1.f / cogl_texture_get_width (pass->texture);
cogl_pipeline_set_uniform_1f (pass->pipeline,
pixel_step_uniform,
pixel_step);
}
sigma_uniform = cogl_pipeline_get_uniform_location (pass->pipeline, "sigma");
if (sigma_uniform > -1)
{
cogl_pipeline_set_uniform_1f (pass->pipeline,
sigma_uniform,
blur->sigma / blur->downscale_factor);
}
direction_uniform =
cogl_pipeline_get_uniform_location (pass->pipeline, "direction");
if (direction_uniform > -1)
{
gboolean horizontal = !vertical;
float direction[2] = {
horizontal,
vertical,
};
cogl_pipeline_set_uniform_float (pass->pipeline,
direction_uniform,
2, 1,
direction);
}
}
static gboolean
create_fbo (ClutterBlur *blur,
BlurPass *pass)
{
CoglContext *ctx =
clutter_backend_get_cogl_context (clutter_get_default_backend ());
float scaled_height;
float scaled_width;
float height;
float width;
g_clear_pointer (&pass->texture, cogl_object_unref);
g_clear_object (&pass->framebuffer);
width = cogl_texture_get_width (blur->source_texture);
height = cogl_texture_get_height (blur->source_texture);
scaled_width = floorf (width / blur->downscale_factor);
scaled_height = floorf (height / blur->downscale_factor);
pass->texture = COGL_TEXTURE (cogl_texture_2d_new_with_size (ctx,
scaled_width,
scaled_height));
if (!pass->texture)
return FALSE;
pass->framebuffer =
COGL_FRAMEBUFFER (cogl_offscreen_new_with_texture (pass->texture));
if (!pass->framebuffer)
{
g_warning ("%s: Unable to create an Offscreen buffer", G_STRLOC);
return FALSE;
}
cogl_framebuffer_orthographic (pass->framebuffer,
0.0, 0.0,
scaled_width,
scaled_height,
0.0, 1.0);
return TRUE;
}
static gboolean
setup_blur_pass (ClutterBlur *blur,
BlurPass *pass,
int orientation,
CoglTexture *texture)
{
pass->orientation = orientation;
pass->pipeline = create_blur_pipeline ();
cogl_pipeline_set_layer_texture (pass->pipeline, 0, texture);
if (!create_fbo (blur, pass))
return FALSE;
update_blur_uniforms (blur, pass);
return TRUE;
}
static float
calculate_downscale_factor (float width,
float height,
float sigma)
{
float downscale_factor = 1.f;
float scaled_width = width;
float scaled_height = height;
float scaled_sigma = sigma;
/* This is the algorithm used by Firefox; keep downscaling until either the
* blur radius is lower than the threshold, or the downscaled texture is too
* small.
*/
while (scaled_sigma > MAX_SIGMA &&
scaled_width > MIN_DOWNSCALE_SIZE &&
scaled_height > MIN_DOWNSCALE_SIZE)
{
downscale_factor *= 2.f;
scaled_width = width / downscale_factor;
scaled_height = height / downscale_factor;
scaled_sigma = sigma / downscale_factor;
}
return downscale_factor;
}
static void
apply_blur_pass (BlurPass *pass)
{
CoglColor transparent;
cogl_color_init_from_4ub (&transparent, 0, 0, 0, 0);
cogl_framebuffer_clear (pass->framebuffer,
COGL_BUFFER_BIT_COLOR,
&transparent);
cogl_framebuffer_draw_rectangle (pass->framebuffer,
pass->pipeline,
0, 0,
cogl_texture_get_width (pass->texture),
cogl_texture_get_height (pass->texture));
}
static void
clear_blur_pass (BlurPass *pass)
{
g_clear_pointer (&pass->pipeline, cogl_object_unref);
g_clear_pointer (&pass->texture, cogl_object_unref);
g_clear_object (&pass->framebuffer);
}
/**
* clutter_blur_new:
* @texture: a #CoglTexture
* @sigma: blur sigma
*
* Creates a new #ClutterBlur.
*
* Returns: (transfer full) (nullable): A newly created #ClutterBlur
*/
ClutterBlur *
clutter_blur_new (CoglTexture *texture,
float sigma)
{
ClutterBlur *blur;
unsigned int height;
unsigned int width;
BlurPass *hpass;
BlurPass *vpass;
g_return_val_if_fail (texture != NULL, NULL);
g_return_val_if_fail (sigma >= 0.0, NULL);
width = cogl_texture_get_width (texture);
height = cogl_texture_get_height (texture);
blur = g_new0 (ClutterBlur, 1);
blur->sigma = sigma;
blur->source_texture = cogl_object_ref (texture);
blur->downscale_factor = calculate_downscale_factor (width, height, sigma);
if (G_APPROX_VALUE (sigma, 0.0, FLT_EPSILON))
goto out;
vpass = &blur->pass[VERTICAL];
hpass = &blur->pass[HORIZONTAL];
if (!setup_blur_pass (blur, vpass, VERTICAL, texture) ||
!setup_blur_pass (blur, hpass, HORIZONTAL, vpass->texture))
{
clutter_blur_free (blur);
return NULL;
}
out:
return g_steal_pointer (&blur);
}
/**
* clutter_blur_apply:
* @blur: a #ClutterBlur
*
* Applies the blur. The resulting texture can be retrieved by
* clutter_blur_get_texture().
*/
void
clutter_blur_apply (ClutterBlur *blur)
{
if (G_APPROX_VALUE (blur->sigma, 0.0, FLT_EPSILON))
return;
apply_blur_pass (&blur->pass[VERTICAL]);
apply_blur_pass (&blur->pass[HORIZONTAL]);
}
/**
* clutter_blur_get_texture:
* @blur: a #ClutterBlur
*
* Retrieves the texture where the blurred contents are stored. The
* contents are undefined until clutter_blur_apply() is called.
*
* Returns: (transfer none): a #CoglTexture
*/
CoglTexture *
clutter_blur_get_texture (ClutterBlur *blur)
{
if (G_APPROX_VALUE (blur->sigma, 0.0, FLT_EPSILON))
return blur->source_texture;
else
return blur->pass[HORIZONTAL].texture;
}
/**
* clutter_blur_free:
* @blur: A #ClutterBlur
*
* Frees @blur.
*/
void
clutter_blur_free (ClutterBlur *blur)
{
g_assert (blur);
clear_blur_pass (&blur->pass[VERTICAL]);
clear_blur_pass (&blur->pass[HORIZONTAL]);
cogl_clear_object (&blur->source_texture);
g_free (blur);
}

View File

@ -39,7 +39,7 @@
* #ClutterActor:y-expand are set, the available size
* - honours the #ClutterActor's #ClutterActor:x-align and #ClutterActor:y-align properties
* to fill the available size
* - if the #ClutterBoxLayout:homogeneous boolean property is set, then all widgets will
* - if the #ClutterBoxLayout:homogeneous boolean propert is set, then all widgets will
* get the same size, ignoring expand settings and the preferred sizes
*
* It is possible to control the spacing between children of a
@ -719,7 +719,7 @@ clutter_box_layout_allocate (ClutterLayoutManager *layout,
if (priv->is_homogeneous)
{
/* If were homogeneous we still need to run the above loop to get the
/* If were homogenous we still need to run the above loop to get the
* minimum sizes for children that are not going to fill
*/
if (priv->orientation == CLUTTER_ORIENTATION_VERTICAL)
@ -1218,7 +1218,7 @@ clutter_box_layout_get_homogeneous (ClutterBoxLayout *layout)
* @pack_start: %TRUE if the @layout should pack children at the
* beginning of the layout
*
* Sets whether children of @layout should be laid out by appending
* Sets whether children of @layout should be layed out by appending
* them or by prepending them
*
* Since: 1.2

View File

@ -41,6 +41,8 @@
#include <math.h>
#define CLUTTER_ENABLE_EXPERIMENTAL_API
#include "clutter-brightness-contrast-effect.h"
#include <cogl/cogl.h>
@ -67,6 +69,9 @@ struct _ClutterBrightnessContrastEffect
gint brightness_offset_uniform;
gint contrast_uniform;
gint tex_width;
gint tex_height;
CoglPipeline *pipeline;
};
@ -124,26 +129,16 @@ will_have_no_effect (ClutterBrightnessContrastEffect *self)
G_APPROX_VALUE (self->contrast_blue, no_change, FLT_EPSILON));
}
static CoglPipeline *
clutter_brightness_contrast_effect_create_pipeline (ClutterOffscreenEffect *effect,
CoglTexture *texture)
{
ClutterBrightnessContrastEffect *self =
CLUTTER_BRIGHTNESS_CONTRAST_EFFECT (effect);
cogl_pipeline_set_layer_texture (self->pipeline, 0, texture);
return cogl_object_ref (self->pipeline);
}
static gboolean
clutter_brightness_contrast_effect_pre_paint (ClutterEffect *effect,
ClutterPaintNode *node,
ClutterPaintContext *paint_context)
{
ClutterBrightnessContrastEffect *self = CLUTTER_BRIGHTNESS_CONTRAST_EFFECT (effect);
ClutterEffectClass *parent_class;
if (!clutter_actor_meta_get_enabled (CLUTTER_ACTOR_META (effect)))
return FALSE;
if (will_have_no_effect (self))
return FALSE;
@ -162,8 +157,47 @@ clutter_brightness_contrast_effect_pre_paint (ClutterEffect *effect,
parent_class =
CLUTTER_EFFECT_CLASS (clutter_brightness_contrast_effect_parent_class);
if (parent_class->pre_paint (effect, paint_context))
{
ClutterOffscreenEffect *offscreen_effect =
CLUTTER_OFFSCREEN_EFFECT (effect);
CoglHandle texture;
return parent_class->pre_paint (effect, node, paint_context);
texture = clutter_offscreen_effect_get_texture (offscreen_effect);
self->tex_width = cogl_texture_get_width (texture);
self->tex_height = cogl_texture_get_height (texture);
cogl_pipeline_set_layer_texture (self->pipeline, 0, texture);
return TRUE;
}
else
return FALSE;
}
static void
clutter_brightness_contrast_effect_paint_target (ClutterOffscreenEffect *effect,
ClutterPaintContext *paint_context)
{
ClutterBrightnessContrastEffect *self = CLUTTER_BRIGHTNESS_CONTRAST_EFFECT (effect);
CoglFramebuffer *framebuffer =
clutter_paint_context_get_framebuffer (paint_context);
ClutterActor *actor;
guint8 paint_opacity;
actor = clutter_actor_meta_get_actor (CLUTTER_ACTOR_META (effect));
paint_opacity = clutter_actor_get_paint_opacity (actor);
cogl_pipeline_set_color4ub (self->pipeline,
paint_opacity,
paint_opacity,
paint_opacity,
paint_opacity);
cogl_framebuffer_draw_rectangle (framebuffer,
self->pipeline,
0, 0,
self->tex_width, self->tex_height);
}
static void
@ -263,7 +297,7 @@ clutter_brightness_contrast_effect_class_init (ClutterBrightnessContrastEffectCl
ClutterOffscreenEffectClass *offscreen_class;
offscreen_class = CLUTTER_OFFSCREEN_EFFECT_CLASS (klass);
offscreen_class->create_pipeline = clutter_brightness_contrast_effect_create_pipeline;
offscreen_class->paint_target = clutter_brightness_contrast_effect_paint_target;
effect_class->pre_paint = clutter_brightness_contrast_effect_pre_paint;

View File

@ -4,5 +4,11 @@
/* List of Cogl drivers */
#mesondefine CLUTTER_DRIVERS
/* Have evdev support for input handling */
#mesondefine HAVE_EVDEV
/* Building with libwacom for advanced tablet management */
#mesondefine HAVE_LIBWACOM
/* Supports PangoFt2 */
#mesondefine HAVE_PANGO_FT2

View File

@ -50,6 +50,8 @@
#include "clutter-canvas.h"
#define CLUTTER_ENABLE_EXPERIMENTAL_API
#include "clutter-actor-private.h"
#include "clutter-backend.h"
#include "clutter-cairo.h"

View File

@ -114,7 +114,7 @@ struct _ClutterClickActionPrivate
gint drag_threshold;
guint press_button;
ClutterInputDevice *press_device;
gint press_device_id;
ClutterEventSequence *press_sequence;
ClutterModifierType modifier_state;
gfloat press_x;
@ -272,23 +272,6 @@ click_action_cancel_long_press (ClutterClickAction *action)
}
}
static inline gboolean
event_within_drag_threshold (ClutterClickAction *click_action,
ClutterEvent *event)
{
ClutterClickActionPrivate *priv =
clutter_click_action_get_instance_private (click_action);
float motion_x, motion_y;
float delta_x, delta_y;
clutter_event_get_coords (event, &motion_x, &motion_y);
delta_x = ABS (motion_x - priv->press_x);
delta_y = ABS (motion_y - priv->press_y);
return delta_x <= priv->drag_threshold && delta_y <= priv->drag_threshold;
}
static gboolean
on_event (ClutterActor *actor,
ClutterEvent *event,
@ -316,7 +299,7 @@ on_event (ClutterActor *actor,
return CLUTTER_EVENT_PROPAGATE;
priv->press_button = has_button ? clutter_event_get_button (event) : 0;
priv->press_device = clutter_event_get_device (event);
priv->press_device_id = clutter_event_get_device_id (event);
priv->press_sequence = clutter_event_get_event_sequence (event);
priv->modifier_state = clutter_event_get_state (event);
clutter_event_get_coords (event, &priv->press_x, &priv->press_y);
@ -387,7 +370,7 @@ on_captured_event (ClutterActor *stage,
if ((has_button && clutter_event_get_button (event) != priv->press_button) ||
(has_button && clutter_event_get_click_count (event) != 1) ||
clutter_event_get_device (event) != priv->press_device ||
clutter_event_get_device_id (event) != priv->press_device_id ||
clutter_event_get_event_sequence (event) != priv->press_sequence)
return CLUTTER_EVENT_PROPAGATE;
@ -419,23 +402,30 @@ on_captured_event (ClutterActor *stage,
priv->modifier_state = 0;
click_action_set_pressed (action, FALSE);
if (event_within_drag_threshold (action, event))
g_signal_emit (action, click_signals[CLICKED], 0, actor);
g_signal_emit (action, click_signals[CLICKED], 0, actor);
break;
case CLUTTER_MOTION:
case CLUTTER_TOUCH_UPDATE:
{
if (clutter_event_get_device (event) != priv->press_device ||
gfloat motion_x, motion_y;
gfloat delta_x, delta_y;
if (clutter_event_get_device_id (event) != priv->press_device_id ||
clutter_event_get_event_sequence (event) != priv->press_sequence)
return CLUTTER_EVENT_PROPAGATE;
if (!priv->is_held)
return CLUTTER_EVENT_PROPAGATE;
if (!event_within_drag_threshold (action, event))
clutter_click_action_release (action);
clutter_event_get_coords (event, &motion_x, &motion_y);
delta_x = ABS (motion_x - priv->press_x);
delta_y = ABS (motion_y - priv->press_y);
if (delta_x > priv->drag_threshold ||
delta_y > priv->drag_threshold)
click_action_cancel_long_press (action);
}
break;

View File

@ -39,6 +39,7 @@
#include "clutter-build-config.h"
#define CLUTTER_ENABLE_EXPERIMENTAL_API
#include "clutter-actor-private.h"
#include "clutter-clone.h"
#include "clutter-debug.h"
@ -120,17 +121,20 @@ clutter_clone_get_preferred_height (ClutterActor *self,
}
static void
clutter_clone_apply_transform (ClutterActor *self,
graphene_matrix_t *matrix)
clutter_clone_apply_transform (ClutterActor *self, CoglMatrix *matrix)
{
ClutterClonePrivate *priv = CLUTTER_CLONE (self)->priv;
if (priv->clone_source)
graphene_matrix_scale (matrix, priv->x_scale, priv->y_scale, 1.f);
/* First chain up and apply all the standard ClutterActor
* transformations... */
CLUTTER_ACTOR_CLASS (clutter_clone_parent_class)->apply_transform (self,
matrix);
/* if we don't have a source, nothing else to do */
if (priv->clone_source == NULL)
return;
cogl_matrix_scale (matrix, priv->x_scale, priv->y_scale, 1.f);
}
static void
@ -195,7 +199,7 @@ clutter_clone_get_paint_volume (ClutterActor *actor,
if (priv->clone_source == NULL)
return TRUE;
/* query the volume of the source actor and simply masquerade it as
/* query the volume of the source actor and simply masquarade it as
* the clones volume... */
source_volume = clutter_actor_get_paint_volume (priv->clone_source);
if (source_volume == NULL)

View File

@ -611,7 +611,7 @@ parse_hsla (ClutterColor *color,
/**
* clutter_color_from_string:
* @color: (out caller-allocates): return location for a #ClutterColor
* @str: a string specifying a color
* @str: a string specifiying a color
*
* Parses a string definition of a color, filling the #ClutterColor.red,
* #ClutterColor.green, #ClutterColor.blue and #ClutterColor.alpha fields
@ -911,7 +911,7 @@ ClutterColor *
clutter_color_copy (const ClutterColor *color)
{
if (G_LIKELY (color != NULL))
return g_memdup2 (color, sizeof (ClutterColor));
return g_slice_dup (ClutterColor, color);
return NULL;
}
@ -928,7 +928,7 @@ void
clutter_color_free (ClutterColor *color)
{
if (G_LIKELY (color != NULL))
g_free (color);
g_slice_free (ClutterColor, color);
}
/**
@ -977,7 +977,7 @@ clutter_color_new (guint8 red,
ClutterColor *
clutter_color_alloc (void)
{
return g_new0 (ClutterColor, 1);
return g_slice_new0 (ClutterColor);
}
/**

View File

@ -39,6 +39,8 @@
#include "clutter-build-config.h"
#define CLUTTER_ENABLE_EXPERIMENTAL_API
#include "clutter-colorize-effect.h"
#include "cogl/cogl.h"
@ -57,6 +59,9 @@ struct _ClutterColorizeEffect
gint tint_uniform;
gint tex_width;
gint tex_height;
CoglPipeline *pipeline;
};
@ -99,24 +104,16 @@ G_DEFINE_TYPE (ClutterColorizeEffect,
clutter_colorize_effect,
CLUTTER_TYPE_OFFSCREEN_EFFECT);
static CoglPipeline *
clutter_colorize_effect_create_pipeline (ClutterOffscreenEffect *effect,
CoglTexture *texture)
{
ClutterColorizeEffect *colorize_effect = CLUTTER_COLORIZE_EFFECT (effect);
cogl_pipeline_set_layer_texture (colorize_effect->pipeline, 0, texture);
return cogl_object_ref (colorize_effect->pipeline);
}
static gboolean
clutter_colorize_effect_pre_paint (ClutterEffect *effect,
ClutterPaintNode *node,
ClutterPaintContext *paint_context)
{
ClutterColorizeEffect *self = CLUTTER_COLORIZE_EFFECT (effect);
ClutterEffectClass *parent_class;
if (!clutter_actor_meta_get_enabled (CLUTTER_ACTOR_META (effect)))
return FALSE;
if (!clutter_feature_available (CLUTTER_FEATURE_SHADERS_GLSL))
{
/* if we don't have support for GLSL shaders then we
@ -130,7 +127,47 @@ clutter_colorize_effect_pre_paint (ClutterEffect *effect,
}
parent_class = CLUTTER_EFFECT_CLASS (clutter_colorize_effect_parent_class);
return parent_class->pre_paint (effect, node, paint_context);
if (parent_class->pre_paint (effect, paint_context))
{
ClutterOffscreenEffect *offscreen_effect =
CLUTTER_OFFSCREEN_EFFECT (effect);
CoglHandle texture;
texture = clutter_offscreen_effect_get_texture (offscreen_effect);
self->tex_width = cogl_texture_get_width (texture);
self->tex_height = cogl_texture_get_height (texture);
cogl_pipeline_set_layer_texture (self->pipeline, 0, texture);
return TRUE;
}
else
return FALSE;
}
static void
clutter_colorize_effect_paint_target (ClutterOffscreenEffect *effect,
ClutterPaintContext *paint_context)
{
ClutterColorizeEffect *self = CLUTTER_COLORIZE_EFFECT (effect);
CoglFramebuffer *framebuffer =
clutter_paint_context_get_framebuffer (paint_context);
ClutterActor *actor;
guint8 paint_opacity;
actor = clutter_actor_meta_get_actor (CLUTTER_ACTOR_META (effect));
paint_opacity = clutter_actor_get_paint_opacity (actor);
cogl_pipeline_set_color4ub (self->pipeline,
paint_opacity,
paint_opacity,
paint_opacity,
paint_opacity);
cogl_framebuffer_draw_rectangle (framebuffer,
self->pipeline,
0, 0,
self->tex_width, self->tex_height);
}
static void
@ -196,7 +233,7 @@ clutter_colorize_effect_class_init (ClutterColorizeEffectClass *klass)
ClutterOffscreenEffectClass *offscreen_class;
offscreen_class = CLUTTER_OFFSCREEN_EFFECT_CLASS (klass);
offscreen_class->create_pipeline = clutter_colorize_effect_create_pipeline;
offscreen_class->paint_target = clutter_colorize_effect_paint_target;
effect_class->pre_paint = clutter_colorize_effect_pre_paint;

View File

@ -0,0 +1,22 @@
#if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION)
#error "Only <clutter/clutter.h> can be included directly."
#endif
#ifndef __CLUTTER_CONFIG_H__
#define __CLUTTER_CONFIG_H__
#include <glib.h>
G_BEGIN_DECLS
#mesondefine CLUTTER_HAS_WAYLAND_COMPOSITOR_SUPPORT
#mesondefine CLUTTER_WINDOWING_X11
#mesondefine CLUTTER_INPUT_X11
#mesondefine CLUTTER_WINDOWING_GLX
#mesondefine CLUTTER_WINDOWING_EGL
#mesondefine CLUTTER_INPUT_EVDEV
#mesondefine CLUTTER_INPUT_NULL
G_END_DECLS
#endif /* __CLUTTER_CONFIG_H__ */

View File

@ -74,7 +74,7 @@ typedef struct _ClutterContainerIface ClutterContainerIface;
* fields in the instance and add the record to a data structure for
* subsequent access for #ClutterContainerIface::get_child_meta
* @destroy_child_meta: virtual function that gets called when a child is
* removed; it should release all resources held by the record
* removed; it shuld release all resources held by the record
* @get_child_meta: return the record for a container child
* @actor_added: class handler for #ClutterContainer::actor-added
* @actor_removed: class handler for #ClutterContainer::actor-removed

View File

@ -22,28 +22,20 @@
#include <cairo.h>
#include <glib.h>
#include "clutter-macros.h"
typedef struct _ClutterDamageHistory ClutterDamageHistory;
CLUTTER_EXPORT
ClutterDamageHistory * clutter_damage_history_new (void);
CLUTTER_EXPORT
void clutter_damage_history_free (ClutterDamageHistory *history);
CLUTTER_EXPORT
gboolean clutter_damage_history_is_age_valid (ClutterDamageHistory *history,
int age);
CLUTTER_EXPORT
void clutter_damage_history_record (ClutterDamageHistory *history,
const cairo_region_t *damage);
CLUTTER_EXPORT
void clutter_damage_history_step (ClutterDamageHistory *history);
CLUTTER_EXPORT
const cairo_region_t * clutter_damage_history_lookup (ClutterDamageHistory *history,
int age);

View File

@ -41,7 +41,6 @@ G_BEGIN_DECLS
extern guint clutter_debug_flags;
extern guint clutter_pick_debug_flags;
extern guint clutter_paint_debug_flags;
extern int clutter_max_render_time_constant_us;
void _clutter_debug_messagev (const char *format,
va_list var_args) G_GNUC_PRINTF (1, 0);

View File

@ -53,16 +53,14 @@
#include "clutter-build-config.h"
#define CLUTTER_ENABLE_EXPERIMENTAL_API
#include "clutter-deform-effect.h"
#include <cogl/cogl.h>
#include "clutter-color.h"
#include "clutter-debug.h"
#include "clutter-enum-types.h"
#include "clutter-offscreen-effect-private.h"
#include "clutter-paint-node.h"
#include "clutter-paint-nodes.h"
#include "clutter-private.h"
#define DEFAULT_N_TILES 32
@ -168,16 +166,19 @@ clutter_deform_effect_set_actor (ClutterActorMeta *meta,
static void
clutter_deform_effect_paint_target (ClutterOffscreenEffect *effect,
ClutterPaintNode *node,
ClutterPaintContext *paint_context)
{
ClutterDeformEffect *self= CLUTTER_DEFORM_EFFECT (effect);
ClutterDeformEffectPrivate *priv = self->priv;
CoglHandle material;
CoglPipeline *pipeline;
CoglDepthState depth_state;
CoglFramebuffer *fb =
clutter_paint_context_get_framebuffer (paint_context);
if (priv->is_dirty)
{
graphene_rect_t rect;
gboolean mapped_buffer;
CoglVertexP3T2C4 *verts;
ClutterActor *actor;
@ -191,7 +192,12 @@ clutter_deform_effect_paint_target (ClutterOffscreenEffect *effect,
/* if we don't have a target size, fall back to the actor's
* allocation, though wrong it might be
*/
if (!clutter_offscreen_effect_get_target_size (effect, &width, &height))
if (clutter_offscreen_effect_get_target_rect (effect, &rect))
{
width = graphene_rect_get_width (&rect);
height = graphene_rect_get_height (&rect);
}
else
clutter_actor_get_size (actor, &width, &height);
/* XXX ideally, the sub-classes should tell us what they
@ -271,7 +277,8 @@ clutter_deform_effect_paint_target (ClutterOffscreenEffect *effect,
priv->is_dirty = FALSE;
}
pipeline = clutter_offscreen_effect_get_pipeline (effect);
material = clutter_offscreen_effect_get_target (effect);
pipeline = COGL_PIPELINE (material);
/* enable depth testing */
cogl_depth_state_init (&depth_state);
@ -285,22 +292,12 @@ clutter_deform_effect_paint_target (ClutterOffscreenEffect *effect,
COGL_PIPELINE_CULL_FACE_MODE_BACK);
/* draw the front */
if (pipeline != NULL)
{
ClutterPaintNode *front_node;
front_node = clutter_pipeline_node_new (pipeline);
clutter_paint_node_set_static_name (front_node,
"ClutterDeformEffect (front)");
clutter_paint_node_add_child (node, front_node);
clutter_paint_node_add_primitive (front_node, priv->primitive);
clutter_paint_node_unref (front_node);
}
if (material != NULL)
cogl_framebuffer_draw_primitive (fb, pipeline, priv->primitive);
/* draw the back */
if (priv->back_pipeline != NULL)
{
ClutterPaintNode *back_node;
CoglPipeline *back_pipeline;
/* We probably shouldn't be modifying the user's material so
@ -310,30 +307,20 @@ clutter_deform_effect_paint_target (ClutterOffscreenEffect *effect,
cogl_pipeline_set_cull_face_mode (back_pipeline,
COGL_PIPELINE_CULL_FACE_MODE_FRONT);
cogl_framebuffer_draw_primitive (fb, back_pipeline, priv->primitive);
back_node = clutter_pipeline_node_new (back_pipeline);
clutter_paint_node_set_static_name (back_node,
"ClutterDeformEffect (back)");
clutter_paint_node_add_child (node, back_node);
clutter_paint_node_add_primitive (back_node, priv->primitive);
clutter_paint_node_unref (back_node);
cogl_object_unref (back_pipeline);
}
if (G_UNLIKELY (priv->lines_primitive != NULL))
{
const ClutterColor *red;
ClutterPaintNode *lines_node;
red = clutter_color_get_static (CLUTTER_COLOR_RED);
lines_node = clutter_color_node_new (red);
clutter_paint_node_set_static_name (lines_node,
"ClutterDeformEffect (lines)");
clutter_paint_node_add_child (node, lines_node);
clutter_paint_node_add_primitive (lines_node, priv->lines_primitive);
clutter_paint_node_unref (lines_node);
CoglContext *ctx =
clutter_backend_get_cogl_context (clutter_get_default_backend ());
CoglPipeline *lines_pipeline = cogl_pipeline_new (ctx);
cogl_pipeline_set_color4f (lines_pipeline, 1.0, 0, 0, 1.0);
cogl_framebuffer_draw_primitive (fb, lines_pipeline,
priv->lines_primitive);
cogl_object_unref (lines_pipeline);
}
}

View File

@ -28,7 +28,7 @@
* @see_also: #ClutterEffect, #ClutterOffscreenEffect
*
* #ClutterDesaturateEffect is a sub-class of #ClutterEffect that
* desaturates the color of an actor and its contents. The strength
* desaturates the color of an actor and its contents. The strenght
* of the desaturation effect is controllable and animatable through
* the #ClutterDesaturateEffect:factor property.
*
@ -41,6 +41,8 @@
#include "clutter-build-config.h"
#define CLUTTER_ENABLE_EXPERIMENTAL_API
#include <math.h>
#include "clutter-desaturate-effect.h"
@ -109,25 +111,16 @@ G_DEFINE_TYPE (ClutterDesaturateEffect,
clutter_desaturate_effect,
CLUTTER_TYPE_OFFSCREEN_EFFECT);
static CoglPipeline *
clutter_desaturate_effect_create_pipeline (ClutterOffscreenEffect *effect,
CoglTexture *texture)
{
ClutterDesaturateEffect *desaturate_effect =
CLUTTER_DESATURATE_EFFECT (effect);
cogl_pipeline_set_layer_texture (desaturate_effect->pipeline, 0, texture);
return cogl_object_ref (desaturate_effect->pipeline);
}
static gboolean
clutter_desaturate_effect_pre_paint (ClutterEffect *effect,
ClutterPaintNode *node,
ClutterPaintContext *paint_context)
{
ClutterDesaturateEffect *self = CLUTTER_DESATURATE_EFFECT (effect);
ClutterEffectClass *parent_class;
if (!clutter_actor_meta_get_enabled (CLUTTER_ACTOR_META (effect)))
return FALSE;
if (!clutter_feature_available (CLUTTER_FEATURE_SHADERS_GLSL))
{
/* if we don't have support for GLSL shaders then we
@ -141,7 +134,52 @@ clutter_desaturate_effect_pre_paint (ClutterEffect *effect,
}
parent_class = CLUTTER_EFFECT_CLASS (clutter_desaturate_effect_parent_class);
return parent_class->pre_paint (effect, node, paint_context);
if (parent_class->pre_paint (effect, paint_context))
{
ClutterOffscreenEffect *offscreen_effect =
CLUTTER_OFFSCREEN_EFFECT (effect);
CoglHandle texture;
texture = clutter_offscreen_effect_get_texture (offscreen_effect);
self->tex_width = cogl_texture_get_width (texture);
self->tex_height = cogl_texture_get_height (texture);
cogl_pipeline_set_layer_texture (self->pipeline, 0, texture);
return TRUE;
}
else
return FALSE;
}
static void
clutter_desaturate_effect_paint_target (ClutterOffscreenEffect *effect,
ClutterPaintContext *paint_context)
{
ClutterDesaturateEffect *self = CLUTTER_DESATURATE_EFFECT (effect);
CoglFramebuffer *framebuffer =
clutter_paint_context_get_framebuffer (paint_context);
ClutterActor *actor;
CoglHandle texture;
guint8 paint_opacity;
texture = clutter_offscreen_effect_get_texture (effect);
cogl_pipeline_set_layer_texture (self->pipeline, 0, texture);
actor = clutter_actor_meta_get_actor (CLUTTER_ACTOR_META (effect));
paint_opacity = clutter_actor_get_paint_opacity (actor);
cogl_pipeline_set_color4ub (self->pipeline,
paint_opacity,
paint_opacity,
paint_opacity,
paint_opacity);
cogl_framebuffer_draw_rectangle (framebuffer,
self->pipeline,
0, 0,
cogl_texture_get_width (texture),
cogl_texture_get_height (texture));
}
static void
@ -216,7 +254,7 @@ clutter_desaturate_effect_class_init (ClutterDesaturateEffectClass *klass)
ClutterOffscreenEffectClass *offscreen_class;
offscreen_class = CLUTTER_OFFSCREEN_EFFECT_CLASS (klass);
offscreen_class->create_pipeline = clutter_desaturate_effect_create_pipeline;
offscreen_class->paint_target = clutter_desaturate_effect_paint_target;
effect_class->pre_paint = clutter_desaturate_effect_pre_paint;

View File

@ -5,11 +5,14 @@
G_BEGIN_DECLS
gboolean _clutter_effect_pre_paint (ClutterEffect *effect,
ClutterPaintContext *paint_context);
void _clutter_effect_post_paint (ClutterEffect *effect,
ClutterPaintContext *paint_context);
gboolean _clutter_effect_modify_paint_volume (ClutterEffect *effect,
ClutterPaintVolume *volume);
gboolean _clutter_effect_has_custom_paint_volume (ClutterEffect *effect);
void _clutter_effect_paint (ClutterEffect *effect,
ClutterPaintNode *node,
ClutterPaintContext *paint_context,
ClutterEffectPaintFlags flags);
void _clutter_effect_pick (ClutterEffect *effect,

View File

@ -169,8 +169,6 @@
#include "clutter-effect-private.h"
#include "clutter-enum-types.h"
#include "clutter-marshal.h"
#include "clutter-paint-node-private.h"
#include "clutter-paint-nodes.h"
#include "clutter-private.h"
#include "clutter-actor-private.h"
@ -180,7 +178,6 @@ G_DEFINE_ABSTRACT_TYPE (ClutterEffect,
static gboolean
clutter_effect_real_pre_paint (ClutterEffect *effect,
ClutterPaintNode *node,
ClutterPaintContext *paint_context)
{
return TRUE;
@ -188,7 +185,6 @@ clutter_effect_real_pre_paint (ClutterEffect *effect,
static void
clutter_effect_real_post_paint (ClutterEffect *effect,
ClutterPaintNode *node,
ClutterPaintContext *paint_context)
{
}
@ -200,54 +196,26 @@ clutter_effect_real_modify_paint_volume (ClutterEffect *effect,
return TRUE;
}
static void
add_actor_node (ClutterEffect *effect,
ClutterPaintNode *node)
{
ClutterPaintNode *actor_node;
ClutterActor *actor;
actor = clutter_actor_meta_get_actor (CLUTTER_ACTOR_META (effect));
actor_node = clutter_actor_node_new (actor, -1);
clutter_paint_node_add_child (node, actor_node);
clutter_paint_node_unref (actor_node);
}
static void
clutter_effect_real_paint_node (ClutterEffect *effect,
ClutterPaintNode *node,
ClutterPaintContext *paint_context,
ClutterEffectPaintFlags flags)
{
add_actor_node (effect, node);
}
static void
clutter_effect_real_paint (ClutterEffect *effect,
ClutterPaintNode *node,
ClutterPaintContext *paint_context,
ClutterEffectPaintFlags flags)
{
ClutterEffectClass *effect_class = CLUTTER_EFFECT_GET_CLASS (effect);
ClutterActorMeta *actor_meta = CLUTTER_ACTOR_META (effect);
ClutterActor *actor;
gboolean pre_paint_succeeded;
/* The default implementation provides a compatibility wrapper for
effects that haven't migrated to use the 'paint' virtual yet. This
just calls the old pre and post virtuals before chaining on */
pre_paint_succeeded = effect_class->pre_paint (effect, node,paint_context);
pre_paint_succeeded = _clutter_effect_pre_paint (effect, paint_context);
actor = clutter_actor_meta_get_actor (actor_meta);
clutter_actor_continue_paint (actor, paint_context);
if (pre_paint_succeeded)
{
effect_class->paint_node (effect, node, paint_context, flags);
effect_class->post_paint (effect, node, paint_context);
}
else
{
/* Just paint the actor as fallback */
add_actor_node (effect, node);
}
_clutter_effect_post_paint (effect, paint_context);
}
static void
@ -287,7 +255,6 @@ clutter_effect_class_init (ClutterEffectClass *klass)
klass->post_paint = clutter_effect_real_post_paint;
klass->modify_paint_volume = clutter_effect_real_modify_paint_volume;
klass->paint = clutter_effect_real_paint;
klass->paint_node = clutter_effect_real_paint_node;
klass->pick = clutter_effect_real_pick;
}
@ -296,18 +263,32 @@ clutter_effect_init (ClutterEffect *self)
{
}
gboolean
_clutter_effect_pre_paint (ClutterEffect *effect,
ClutterPaintContext *paint_context)
{
g_return_val_if_fail (CLUTTER_IS_EFFECT (effect), FALSE);
return CLUTTER_EFFECT_GET_CLASS (effect)->pre_paint (effect, paint_context);
}
void
_clutter_effect_post_paint (ClutterEffect *effect,
ClutterPaintContext *paint_context)
{
g_return_if_fail (CLUTTER_IS_EFFECT (effect));
CLUTTER_EFFECT_GET_CLASS (effect)->post_paint (effect, paint_context);
}
void
_clutter_effect_paint (ClutterEffect *effect,
ClutterPaintNode *node,
ClutterPaintContext *paint_context,
ClutterEffectPaintFlags flags)
{
g_return_if_fail (CLUTTER_IS_EFFECT (effect));
CLUTTER_EFFECT_GET_CLASS (effect)->paint (effect,
node,
paint_context,
flags);
CLUTTER_EFFECT_GET_CLASS (effect)->paint (effect, paint_context, flags);
}
void
@ -368,7 +349,7 @@ _clutter_effect_has_custom_paint_volume (ClutterEffect *effect)
* the actor itself so the %CLUTTER_EFFECT_PAINT_ACTOR_DIRTY would still
* not be set. The effect can detect this case by keeping track of the
* last modelview matrix that was used to render the actor and
* verifying that it remains the same in the next paint.
* veryifying that it remains the same in the next paint.
*
* Any other effects that are layered on top of the passed in effect
* will still be passed the %CLUTTER_EFFECT_PAINT_ACTOR_DIRTY flag. If
@ -392,6 +373,7 @@ clutter_effect_queue_repaint (ClutterEffect *effect)
/* If the effect has no actor then nothing needs to be done */
if (actor != NULL)
_clutter_actor_queue_redraw_full (actor,
0, /* flags */
NULL, /* clip volume */
effect /* effect */);
}

View File

@ -77,21 +77,14 @@ struct _ClutterEffectClass
/*< public >*/
gboolean (* pre_paint) (ClutterEffect *effect,
ClutterPaintNode *node,
ClutterPaintContext *paint_context);
void (* post_paint) (ClutterEffect *effect,
ClutterPaintNode *node,
ClutterPaintContext *paint_context);
gboolean (* modify_paint_volume) (ClutterEffect *effect,
ClutterPaintVolume *volume);
void (* paint) (ClutterEffect *effect,
ClutterPaintNode *node,
ClutterPaintContext *paint_context,
ClutterEffectPaintFlags flags);
void (* paint_node) (ClutterEffect *effect,
ClutterPaintNode *node,
ClutterPaintContext *paint_context,
ClutterEffectPaintFlags flags);
void (* pick) (ClutterEffect *effect,

View File

@ -14,9 +14,9 @@
GType
@enum_name@_get_type (void)
{
static size_t g_enum_type_id = 0;
static volatile gsize g_enum_type_id__volatile = 0;
if (g_once_init_enter (&g_enum_type_id))
if (g_once_init_enter (&g_enum_type_id__volatile))
{
static const G@Type@Value values[] = {
/*** END value-header ***/
@ -28,13 +28,14 @@ GType
/*** BEGIN value-tail ***/
{ 0, NULL, NULL }
};
GType id;
GType g_enum_type_id;
id = g_@type@_register_static (g_intern_static_string ("@EnumName@"), values);
g_enum_type_id =
g_@type@_register_static (g_intern_static_string ("@EnumName@"), values);
g_once_init_leave (&g_enum_type_id, id);
g_once_init_leave (&g_enum_type_id__volatile, g_enum_type_id);
}
return g_enum_type_id;
return g_enum_type_id__volatile;
}
/*** END value-tail ***/

View File

@ -127,7 +127,7 @@ typedef enum /*< prefix=CLUTTER_REQUEST >*/
* @CLUTTER_EASE_IN_OUT_QUAD: quadratic tweening, combininig
* %CLUTTER_EASE_IN_QUAD and %CLUTTER_EASE_OUT_QUAD
* @CLUTTER_EASE_IN_CUBIC: cubic tweening
* @CLUTTER_EASE_OUT_CUBIC: cubic tweening, inverse of
* @CLUTTER_EASE_OUT_CUBIC: cubic tweening, invers of
* %CLUTTER_EASE_IN_CUBIC
* @CLUTTER_EASE_IN_OUT_CUBIC: cubic tweening, combining
* %CLUTTER_EASE_IN_CUBIC and %CLUTTER_EASE_OUT_CUBIC
@ -475,7 +475,7 @@ typedef enum {
* a toplevel, and all parents visible)
* @CLUTTER_ACTOR_REALIZED: the resources associated to the actor have been
* allocated
* @CLUTTER_ACTOR_REACTIVE: the actor 'reacts' to mouse events emitting event
* @CLUTTER_ACTOR_REACTIVE: the actor 'reacts' to mouse events emmitting event
* signals
* @CLUTTER_ACTOR_VISIBLE: the actor has been shown by the application program
* @CLUTTER_ACTOR_NO_LAYOUT: the actor provides an explicit layout management
@ -802,8 +802,7 @@ typedef enum /*< flags prefix=CLUTTER_EVENT >*/
CLUTTER_EVENT_NONE = 0,
CLUTTER_EVENT_FLAG_SYNTHETIC = 1 << 0,
CLUTTER_EVENT_FLAG_INPUT_METHOD = 1 << 1,
CLUTTER_EVENT_FLAG_REPEATED = 1 << 2,
CLUTTER_EVENT_FLAG_RELATIVE_MOTION = 1 << 3,
CLUTTER_EVENT_FLAG_REPEATED = 1 << 2
} ClutterEventFlags;
/**
@ -817,6 +816,9 @@ typedef enum /*< flags prefix=CLUTTER_EVENT >*/
* @CLUTTER_BUTTON_PRESS: Pointer button press event
* @CLUTTER_BUTTON_RELEASE: Pointer button release event
* @CLUTTER_SCROLL: Pointer scroll event
* @CLUTTER_STAGE_STATE: Stage state change event
* @CLUTTER_DESTROY_NOTIFY: Destroy notification event
* @CLUTTER_CLIENT_MESSAGE: Client message event
* @CLUTTER_TOUCH_BEGIN: A new touch event sequence has started;
* event added in 1.10
* @CLUTTER_TOUCH_UPDATE: A touch event sequence has been updated;
@ -851,6 +853,9 @@ typedef enum /*< prefix=CLUTTER >*/
CLUTTER_BUTTON_PRESS,
CLUTTER_BUTTON_RELEASE,
CLUTTER_SCROLL,
CLUTTER_STAGE_STATE,
CLUTTER_DESTROY_NOTIFY,
CLUTTER_CLIENT_MESSAGE,
CLUTTER_TOUCH_BEGIN,
CLUTTER_TOUCH_UPDATE,
CLUTTER_TOUCH_END,
@ -865,9 +870,6 @@ typedef enum /*< prefix=CLUTTER >*/
CLUTTER_PAD_RING,
CLUTTER_DEVICE_ADDED,
CLUTTER_DEVICE_REMOVED,
CLUTTER_IM_COMMIT,
CLUTTER_IM_DELETE,
CLUTTER_IM_PREEDIT,
CLUTTER_EVENT_LAST /* helper */
} ClutterEventType;
@ -896,6 +898,19 @@ typedef enum /*< prefix=CLUTTER_SCROLL >*/
CLUTTER_SCROLL_SMOOTH
} ClutterScrollDirection;
/**
* ClutterStageState:
* @CLUTTER_STAGE_STATE_ACTIVATED: Activated mask
*
* Stage state masks, used by the #ClutterEvent of type %CLUTTER_STAGE_STATE.
*
* Since: 0.4
*/
typedef enum
{
CLUTTER_STAGE_STATE_ACTIVATED = (1 << 3)
} ClutterStageState;
/**
* ClutterFeatureFlags:
* @CLUTTER_FEATURE_STAGE_STATIC: Set if stage size if fixed (i.e framebuffer)
@ -979,11 +994,11 @@ typedef enum
/**
* ClutterInputMode:
* @CLUTTER_INPUT_MODE_LOGICAL: A logical, virtual device
* @CLUTTER_INPUT_MODE_PHYSICAL: A physical device, attached to
* a logical device
* @CLUTTER_INPUT_MODE_FLOATING: A physical device, not attached
* to a logical device
* @CLUTTER_INPUT_MODE_MASTER: A master, virtual device
* @CLUTTER_INPUT_MODE_SLAVE: A slave, physical device, attached to
* a master device
* @CLUTTER_INPUT_MODE_FLOATING: A slave, physical device, not attached
* to a master device
*
* The mode for input devices available.
*
@ -991,8 +1006,8 @@ typedef enum
*/
typedef enum
{
CLUTTER_INPUT_MODE_LOGICAL,
CLUTTER_INPUT_MODE_PHYSICAL,
CLUTTER_INPUT_MODE_MASTER,
CLUTTER_INPUT_MODE_SLAVE,
CLUTTER_INPUT_MODE_FLOATING
} ClutterInputMode;
@ -1032,20 +1047,6 @@ typedef enum
CLUTTER_INPUT_AXIS_LAST
} ClutterInputAxis;
typedef enum
{
CLUTTER_INPUT_AXIS_FLAG_NONE = 0,
CLUTTER_INPUT_AXIS_FLAG_X = 1 << CLUTTER_INPUT_AXIS_X,
CLUTTER_INPUT_AXIS_FLAG_Y = 1 << CLUTTER_INPUT_AXIS_Y,
CLUTTER_INPUT_AXIS_FLAG_PRESSURE = 1 << CLUTTER_INPUT_AXIS_PRESSURE,
CLUTTER_INPUT_AXIS_FLAG_XTILT = 1 << CLUTTER_INPUT_AXIS_XTILT,
CLUTTER_INPUT_AXIS_FLAG_YTILT = 1 << CLUTTER_INPUT_AXIS_YTILT,
CLUTTER_INPUT_AXIS_FLAG_WHEEL = 1 << CLUTTER_INPUT_AXIS_WHEEL,
CLUTTER_INPUT_AXIS_FLAG_DISTANCE = 1 << CLUTTER_INPUT_AXIS_DISTANCE,
CLUTTER_INPUT_AXIS_FLAG_ROTATION = 1 << CLUTTER_INPUT_AXIS_ROTATION,
CLUTTER_INPUT_AXIS_FLAG_SLIDER = 1 << CLUTTER_INPUT_AXIS_SLIDER,
} ClutterInputAxisFlags;
/**
* ClutterSnapEdge:
* @CLUTTER_SNAP_EDGE_TOP: the top edge
@ -1159,7 +1160,7 @@ typedef enum /*< prefix=CLUTTER_TEXTURE >*/
*
* Since: 0.8
*
* Deprecated: 1.22: The #ClutterTexture class was the only user of
* Deprecated: 1.22: The #ClutterTexture class was the only used ot
* this API; use #ClutterImage and clutter_actor_set_content_scaling_filters()
* instead.
*/
@ -1593,13 +1594,6 @@ typedef enum
CLUTTER_INPUT_DEVICE_PAD_SOURCE_FINGER,
} ClutterInputDevicePadSource;
typedef enum
{
CLUTTER_PAD_FEATURE_BUTTON,
CLUTTER_PAD_FEATURE_RING,
CLUTTER_PAD_FEATURE_STRIP,
} ClutterInputDevicePadFeature;
typedef enum
{
CLUTTER_INPUT_CONTENT_HINT_COMPLETION = 1 << 0,
@ -1638,12 +1632,6 @@ typedef enum
CLUTTER_INPUT_PANEL_STATE_TOGGLE,
} ClutterInputPanelState;
typedef enum
{
CLUTTER_PREEDIT_RESET_CLEAR,
CLUTTER_PREEDIT_RESET_COMMIT,
} ClutterPreeditResetMode;
G_END_DECLS
#endif /* __CLUTTER_ENUMS_H__ */

View File

@ -18,6 +18,7 @@ gboolean _clutter_event_process_filters (ClutterEvent *eve
/* clears the event queue inside the main context */
void _clutter_clear_events_queue (void);
void _clutter_clear_events_queue_for_stage (ClutterStage *stage);
CLUTTER_EXPORT
void _clutter_event_set_platform_data (ClutterEvent *event,

View File

@ -73,6 +73,8 @@ typedef struct _ClutterEventFilter {
gpointer user_data;
} ClutterEventFilter;
static GHashTable *all_events = NULL;
G_DEFINE_BOXED_TYPE (ClutterEvent, clutter_event,
clutter_event_copy,
clutter_event_free);
@ -94,6 +96,15 @@ G_DEFINE_BOXED_TYPE (ClutterEventSequence, clutter_event_sequence,
clutter_event_sequence_copy,
clutter_event_sequence_free);
static gboolean
is_event_allocated (const ClutterEvent *event)
{
if (all_events == NULL)
return FALSE;
return g_hash_table_lookup (all_events, event) != NULL;
}
/*
* _clutter_event_get_platform_data:
* @event: a #ClutterEvent
@ -107,6 +118,9 @@ G_DEFINE_BOXED_TYPE (ClutterEventSequence, clutter_event_sequence,
gpointer
_clutter_event_get_platform_data (const ClutterEvent *event)
{
if (!is_event_allocated (event))
return NULL;
return ((ClutterEventPrivate *) event)->platform_data;
}
@ -123,6 +137,9 @@ void
_clutter_event_set_platform_data (ClutterEvent *event,
gpointer data)
{
if (!is_event_allocated (event))
return;
((ClutterEventPrivate *) event)->platform_data = data;
}
@ -130,6 +147,9 @@ void
_clutter_event_set_pointer_emulated (ClutterEvent *event,
gboolean is_emulated)
{
if (!is_event_allocated (event))
return;
((ClutterEventPrivate *) event)->is_pointer_emulated = !!is_emulated;
}
@ -384,6 +404,9 @@ clutter_event_get_position (const ClutterEvent *event,
case CLUTTER_NOTHING:
case CLUTTER_KEY_PRESS:
case CLUTTER_KEY_RELEASE:
case CLUTTER_STAGE_STATE:
case CLUTTER_DESTROY_NOTIFY:
case CLUTTER_CLIENT_MESSAGE:
case CLUTTER_EVENT_LAST:
case CLUTTER_PROXIMITY_IN:
case CLUTTER_PROXIMITY_OUT:
@ -393,9 +416,6 @@ clutter_event_get_position (const ClutterEvent *event,
case CLUTTER_PAD_RING:
case CLUTTER_DEVICE_ADDED:
case CLUTTER_DEVICE_REMOVED:
case CLUTTER_IM_COMMIT:
case CLUTTER_IM_DELETE:
case CLUTTER_IM_PREEDIT:
graphene_point_init (position, 0.f, 0.f);
break;
@ -459,6 +479,9 @@ clutter_event_set_coords (ClutterEvent *event,
case CLUTTER_NOTHING:
case CLUTTER_KEY_PRESS:
case CLUTTER_KEY_RELEASE:
case CLUTTER_STAGE_STATE:
case CLUTTER_DESTROY_NOTIFY:
case CLUTTER_CLIENT_MESSAGE:
case CLUTTER_EVENT_LAST:
case CLUTTER_PROXIMITY_IN:
case CLUTTER_PROXIMITY_OUT:
@ -468,9 +491,6 @@ clutter_event_set_coords (ClutterEvent *event,
case CLUTTER_PAD_RING:
case CLUTTER_DEVICE_ADDED:
case CLUTTER_DEVICE_REMOVED:
case CLUTTER_IM_COMMIT:
case CLUTTER_IM_DELETE:
case CLUTTER_IM_PREEDIT:
break;
case CLUTTER_ENTER:
@ -697,6 +717,9 @@ clutter_event_set_scroll_delta (ClutterEvent *event,
g_return_if_fail (event != NULL);
g_return_if_fail (event->type == CLUTTER_SCROLL);
if (!is_event_allocated (event))
return;
event->scroll.direction = CLUTTER_SCROLL_SMOOTH;
((ClutterEventPrivate *) event)->delta_x = dx;
@ -727,8 +750,13 @@ clutter_event_get_scroll_delta (const ClutterEvent *event,
g_return_if_fail (event->type == CLUTTER_SCROLL);
g_return_if_fail (event->scroll.direction == CLUTTER_SCROLL_SMOOTH);
delta_x = ((ClutterEventPrivate *) event)->delta_x;
delta_y = ((ClutterEventPrivate *) event)->delta_y;
delta_x = delta_y = 0;
if (is_event_allocated (event))
{
delta_x = ((ClutterEventPrivate *) event)->delta_x;
delta_y = ((ClutterEventPrivate *) event)->delta_y;
}
if (dx != NULL)
*dx = delta_x;
@ -1002,6 +1030,29 @@ clutter_event_get_event_sequence (const ClutterEvent *event)
return NULL;
}
/**
* clutter_event_get_device_id:
* @event: a clutter event
*
* Retrieves the events device id if set.
*
* Return value: A unique identifier for the device or -1 if the event has
* no specific device set.
*/
gint
clutter_event_get_device_id (const ClutterEvent *event)
{
ClutterInputDevice *device = NULL;
g_return_val_if_fail (event != NULL, CLUTTER_POINTER_DEVICE);
device = clutter_event_get_device (event);
if (device != NULL)
return clutter_input_device_get_device_id (device);
return -1;
}
/**
* clutter_event_get_device_type:
* @event: a #ClutterEvent
@ -1040,20 +1091,23 @@ void
clutter_event_set_device (ClutterEvent *event,
ClutterInputDevice *device)
{
ClutterEventPrivate *real_event = (ClutterEventPrivate *) event;
g_return_if_fail (event != NULL);
g_return_if_fail (device == NULL || CLUTTER_IS_INPUT_DEVICE (device));
g_set_object (&real_event->device, device);
if (is_event_allocated (event))
{
ClutterEventPrivate *real_event = (ClutterEventPrivate *) event;
g_set_object (&real_event->device, device);
}
switch (event->type)
{
case CLUTTER_NOTHING:
case CLUTTER_STAGE_STATE:
case CLUTTER_DESTROY_NOTIFY:
case CLUTTER_CLIENT_MESSAGE:
case CLUTTER_EVENT_LAST:
case CLUTTER_IM_COMMIT:
case CLUTTER_IM_DELETE:
case CLUTTER_IM_PREEDIT:
break;
case CLUTTER_ENTER:
@ -1137,19 +1191,23 @@ ClutterInputDevice *
clutter_event_get_device (const ClutterEvent *event)
{
ClutterInputDevice *device = NULL;
ClutterEventPrivate *real_event = (ClutterEventPrivate *) event;
g_return_val_if_fail (event != NULL, NULL);
if (real_event->device != NULL)
return real_event->device;
if (is_event_allocated (event))
{
ClutterEventPrivate *real_event = (ClutterEventPrivate *) event;
if (real_event->device != NULL)
return real_event->device;
}
switch (event->type)
{
case CLUTTER_NOTHING:
case CLUTTER_IM_COMMIT:
case CLUTTER_IM_DELETE:
case CLUTTER_IM_PREEDIT:
case CLUTTER_STAGE_STATE:
case CLUTTER_DESTROY_NOTIFY:
case CLUTTER_CLIENT_MESSAGE:
case CLUTTER_EVENT_LAST:
break;
@ -1228,11 +1286,14 @@ void
clutter_event_set_device_tool (ClutterEvent *event,
ClutterInputDeviceTool *tool)
{
ClutterEventPrivate *real_event = (ClutterEventPrivate *) event;
g_return_if_fail (event != NULL);
real_event->tool = tool;
if (is_event_allocated (event))
{
ClutterEventPrivate *real_event = (ClutterEventPrivate *) event;
real_event->tool = tool;
}
}
/**
@ -1248,11 +1309,16 @@ clutter_event_set_device_tool (ClutterEvent *event,
ClutterInputDeviceTool *
clutter_event_get_device_tool (const ClutterEvent *event)
{
ClutterEventPrivate *real_event = (ClutterEventPrivate *) event;
g_return_val_if_fail (event != NULL, NULL);
return real_event->tool;
if (is_event_allocated (event))
{
ClutterEventPrivate *real_event = (ClutterEventPrivate *) event;
return real_event->tool;
}
return NULL;
}
/**
@ -1269,11 +1335,16 @@ clutter_event_new (ClutterEventType type)
ClutterEvent *new_event;
ClutterEventPrivate *priv;
priv = g_new0 (ClutterEventPrivate, 1);
priv = g_slice_new0 (ClutterEventPrivate);
new_event = (ClutterEvent *) priv;
new_event->type = new_event->any.type = type;
if (G_UNLIKELY (all_events == NULL))
all_events = g_hash_table_new (NULL, NULL);
g_hash_table_replace (all_events, priv, GUINT_TO_POINTER (1));
return new_event;
}
@ -1290,7 +1361,8 @@ clutter_event_copy (const ClutterEvent *event)
{
ClutterEvent *new_event;
ClutterEventPrivate *new_real_event;
ClutterEventPrivate *real_event = (ClutterEventPrivate *) event;
ClutterInputDevice *device;
gint n_axes = 0;
g_return_val_if_fail (event != NULL, NULL);
@ -1299,45 +1371,45 @@ clutter_event_copy (const ClutterEvent *event)
*new_event = *event;
g_set_object (&new_real_event->device, real_event->device);
g_set_object (&new_real_event->source_device, real_event->source_device);
new_real_event->delta_x = real_event->delta_x;
new_real_event->delta_y = real_event->delta_y;
new_real_event->is_pointer_emulated = real_event->is_pointer_emulated;
new_real_event->base_state = real_event->base_state;
new_real_event->button_state = real_event->button_state;
new_real_event->latched_state = real_event->latched_state;
new_real_event->locked_state = real_event->locked_state;
new_real_event->tool = real_event->tool;
if (is_event_allocated (event))
{
ClutterEventPrivate *real_event = (ClutterEventPrivate *) event;
g_set_object (&new_real_event->device, real_event->device);
g_set_object (&new_real_event->source_device, real_event->source_device);
new_real_event->delta_x = real_event->delta_x;
new_real_event->delta_y = real_event->delta_y;
new_real_event->is_pointer_emulated = real_event->is_pointer_emulated;
new_real_event->base_state = real_event->base_state;
new_real_event->button_state = real_event->button_state;
new_real_event->latched_state = real_event->latched_state;
new_real_event->locked_state = real_event->locked_state;
new_real_event->tool = real_event->tool;
}
device = clutter_event_get_device (event);
if (device != NULL)
n_axes = clutter_input_device_get_n_axes (device);
switch (event->type)
{
case CLUTTER_BUTTON_PRESS:
case CLUTTER_BUTTON_RELEASE:
if (event->button.axes != NULL)
{
new_event->button.axes =
g_memdup2 (event->button.axes,
sizeof (double) * CLUTTER_INPUT_AXIS_LAST);
}
new_event->button.axes = g_memdup (event->button.axes,
sizeof (gdouble) * n_axes);
break;
case CLUTTER_SCROLL:
if (event->scroll.axes != NULL)
{
new_event->scroll.axes =
g_memdup2 (event->scroll.axes,
sizeof (double) * CLUTTER_INPUT_AXIS_LAST);
}
new_event->scroll.axes = g_memdup (event->scroll.axes,
sizeof (gdouble) * n_axes);
break;
case CLUTTER_MOTION:
if (event->motion.axes != NULL)
{
new_event->motion.axes =
g_memdup2 (event->motion.axes,
sizeof (double) * CLUTTER_INPUT_AXIS_LAST);
}
new_event->motion.axes = g_memdup (event->motion.axes,
sizeof (gdouble) * n_axes);
break;
case CLUTTER_TOUCH_BEGIN:
@ -1345,26 +1417,21 @@ clutter_event_copy (const ClutterEvent *event)
case CLUTTER_TOUCH_END:
case CLUTTER_TOUCH_CANCEL:
if (event->touch.axes != NULL)
{
new_event->touch.axes =
g_memdup2 (event->touch.axes,
sizeof (double) * CLUTTER_INPUT_AXIS_LAST);
}
new_event->touch.axes = g_memdup (event->touch.axes,
sizeof (gdouble) * n_axes);
break;
case CLUTTER_DEVICE_ADDED:
case CLUTTER_DEVICE_REMOVED:
new_event->device.device = event->device.device;
break;
case CLUTTER_IM_COMMIT:
case CLUTTER_IM_PREEDIT:
new_event->im.text = g_strdup (event->im.text);
break;
default:
break;
}
if (is_event_allocated (event))
_clutter_backend_copy_event_data (clutter_get_default_backend (),
event,
new_event);
return new_event;
}
@ -1379,10 +1446,15 @@ clutter_event_free (ClutterEvent *event)
{
if (G_LIKELY (event != NULL))
{
ClutterEventPrivate *real_event = (ClutterEventPrivate *) event;
_clutter_backend_free_event_data (clutter_get_default_backend (), event);
g_clear_object (&real_event->device);
g_clear_object (&real_event->source_device);
if (is_event_allocated (event))
{
ClutterEventPrivate *real_event = (ClutterEventPrivate *) event;
g_clear_object (&real_event->device);
g_clear_object (&real_event->source_device);
}
switch (event->type)
{
@ -1405,17 +1477,16 @@ clutter_event_free (ClutterEvent *event)
case CLUTTER_TOUCH_CANCEL:
g_free (event->touch.axes);
break;
case CLUTTER_IM_COMMIT:
case CLUTTER_IM_PREEDIT:
g_free (event->im.text);
case CLUTTER_DEVICE_ADDED:
case CLUTTER_DEVICE_REMOVED:
break;
default:
break;
}
g_free ((ClutterEventPrivate *) event);
g_hash_table_remove (all_events, event);
g_slice_free (ClutterEventPrivate, (ClutterEventPrivate *) event);
}
}
@ -1440,6 +1511,12 @@ clutter_event_get (void)
return event;
}
static gboolean
spin_context (gpointer data)
{
return G_SOURCE_REMOVE;
}
void
_clutter_event_push (const ClutterEvent *event,
gboolean do_copy)
@ -1457,7 +1534,7 @@ _clutter_event_push (const ClutterEvent *event,
}
g_async_queue_push (context->events_queue, (gpointer) event);
g_main_context_wakeup (NULL);
g_idle_add (spin_context, NULL);
}
/**
@ -1564,6 +1641,9 @@ clutter_event_get_source_device (const ClutterEvent *event)
{
ClutterEventPrivate *real_event;
if (!is_event_allocated (event))
return NULL;
real_event = (ClutterEventPrivate *) event;
if (real_event->source_device != NULL)
@ -1592,6 +1672,9 @@ clutter_event_set_source_device (ClutterEvent *event,
g_return_if_fail (event != NULL);
g_return_if_fail (device == NULL || CLUTTER_IS_INPUT_DEVICE (device));
if (!is_event_allocated (event))
return;
real_event = (ClutterEventPrivate *) event;
g_set_object (&real_event->source_device, device);
}
@ -1612,10 +1695,14 @@ clutter_event_get_axes (const ClutterEvent *event,
guint *n_axes)
{
gdouble *retval = NULL;
guint len = 0;
switch (event->type)
{
case CLUTTER_NOTHING:
case CLUTTER_STAGE_STATE:
case CLUTTER_DESTROY_NOTIFY:
case CLUTTER_CLIENT_MESSAGE:
case CLUTTER_ENTER:
case CLUTTER_LEAVE:
case CLUTTER_KEY_PRESS:
@ -1653,14 +1740,22 @@ clutter_event_get_axes (const ClutterEvent *event,
case CLUTTER_PAD_BUTTON_RELEASE:
case CLUTTER_PAD_STRIP:
case CLUTTER_PAD_RING:
case CLUTTER_IM_COMMIT:
case CLUTTER_IM_DELETE:
case CLUTTER_IM_PREEDIT:
break;
}
if (retval != NULL)
{
ClutterInputDevice *device;
device = clutter_event_get_device (event);
if (device != NULL)
len = clutter_input_device_get_n_axes (device);
else
retval = NULL;
}
if (n_axes)
*n_axes = CLUTTER_INPUT_AXIS_LAST;
*n_axes = len;
return retval;
}
@ -1779,6 +1874,9 @@ clutter_event_is_pointer_emulated (const ClutterEvent *event)
{
g_return_val_if_fail (event != NULL, FALSE);
if (!is_event_allocated (event))
return FALSE;
return ((ClutterEventPrivate *) event)->is_pointer_emulated;
}
@ -1830,7 +1928,7 @@ clutter_event_add_filter (ClutterStage *stage,
gpointer user_data)
{
ClutterMainContext *context = _clutter_context_get_default ();
ClutterEventFilter *event_filter = g_new0 (ClutterEventFilter, 1);
ClutterEventFilter *event_filter = g_slice_new (ClutterEventFilter);
static guint event_filter_id = 0;
event_filter->stage = stage;
@ -1871,7 +1969,7 @@ clutter_event_remove_filter (guint id)
event_filter->notify (event_filter->user_data);
context->event_filters = g_list_delete_link (context->event_filters, l);
g_free (event_filter);
g_slice_free (ClutterEventFilter, event_filter);
return;
}
}
@ -2007,42 +2105,6 @@ clutter_event_get_gesture_motion_delta (const ClutterEvent *event,
}
}
/**
* clutter_event_get_gesture_motion_delta_unaccelerated:
* @event: A clutter touchpad gesture event
* @dx: (out) (allow-none): the displacement relative to the pointer
* position in the X axis, or %NULL
* @dy: (out) (allow-none): the displacement relative to the pointer
* position in the Y axis, or %NULL
*
* Returns the unaccelerated gesture motion deltas relative to the current
* pointer position. Unlike clutter_event_get_gesture_motion_delta(),
* pointer acceleration is ignored.
**/
void
clutter_event_get_gesture_motion_delta_unaccelerated (const ClutterEvent *event,
gdouble *dx,
gdouble *dy)
{
g_return_if_fail (event != NULL);
g_return_if_fail (event->type == CLUTTER_TOUCHPAD_PINCH ||
event->type == CLUTTER_TOUCHPAD_SWIPE);
if (event->type == CLUTTER_TOUCHPAD_PINCH)
{
if (dx)
*dx = event->touchpad_pinch.dx_unaccel;
if (dy)
*dy = event->touchpad_pinch.dy_unaccel;
}
else if (event->type == CLUTTER_TOUCHPAD_SWIPE)
{
if (dx)
*dx = event->touchpad_swipe.dx_unaccel;
if (dy)
*dy = event->touchpad_swipe.dy_unaccel;
}
}
/**
* clutter_event_get_scroll_source:
* @event: an scroll event
@ -2163,58 +2225,3 @@ clutter_event_get_pad_event_details (const ClutterEvent *event,
return TRUE;
}
uint32_t
clutter_event_get_event_code (const ClutterEvent *event)
{
if (event->type == CLUTTER_KEY_PRESS ||
event->type == CLUTTER_KEY_RELEASE)
return event->key.evdev_code;
else if (event->type == CLUTTER_BUTTON_PRESS ||
event->type == CLUTTER_BUTTON_RELEASE)
return event->button.evdev_code;
return 0;
}
int32_t
clutter_event_sequence_get_slot (const ClutterEventSequence *sequence)
{
g_return_val_if_fail (sequence != NULL, -1);
return GPOINTER_TO_INT (sequence) - 1;
}
int64_t
clutter_event_get_time_us (const ClutterEvent *event)
{
if (event->type == CLUTTER_MOTION)
return event->motion.time_us;
return 0;
}
gboolean
clutter_event_get_relative_motion (const ClutterEvent *event,
double *dx,
double *dy,
double *dx_unaccel,
double *dy_unaccel)
{
if (event->type == CLUTTER_MOTION &&
event->motion.flags & CLUTTER_EVENT_FLAG_RELATIVE_MOTION)
{
if (dx)
*dx = event->motion.dx;
if (dy)
*dy = event->motion.dy;
if (dx_unaccel)
*dx_unaccel = event->motion.dx_unaccel;
if (dy_unaccel)
*dy_unaccel = event->motion.dy_unaccel;
return TRUE;
}
else
return FALSE;
}

View File

@ -112,6 +112,7 @@ typedef struct _ClutterButtonEvent ClutterButtonEvent;
typedef struct _ClutterKeyEvent ClutterKeyEvent;
typedef struct _ClutterMotionEvent ClutterMotionEvent;
typedef struct _ClutterScrollEvent ClutterScrollEvent;
typedef struct _ClutterStageStateEvent ClutterStageStateEvent;
typedef struct _ClutterCrossingEvent ClutterCrossingEvent;
typedef struct _ClutterTouchEvent ClutterTouchEvent;
typedef struct _ClutterTouchpadPinchEvent ClutterTouchpadPinchEvent;
@ -121,7 +122,6 @@ typedef struct _ClutterPadButtonEvent ClutterPadButtonEvent;
typedef struct _ClutterPadStripEvent ClutterPadStripEvent;
typedef struct _ClutterPadRingEvent ClutterPadRingEvent;
typedef struct _ClutterDeviceEvent ClutterDeviceEvent;
typedef struct _ClutterIMEvent ClutterIMEvent;
/**
* ClutterAnyEvent:
@ -173,7 +173,6 @@ struct _ClutterKeyEvent
guint keyval;
guint16 hardware_keycode;
gunichar unicode_value;
uint32_t evdev_code;
ClutterInputDevice *device;
};
@ -217,7 +216,6 @@ struct _ClutterButtonEvent
guint click_count;
gdouble *axes; /* Future use */
ClutterInputDevice *device;
uint32_t evdev_code;
};
/**
@ -307,12 +305,6 @@ struct _ClutterMotionEvent
ClutterModifierType modifier_state;
gdouble *axes; /* Future use */
ClutterInputDevice *device;
int64_t time_us;
double dx;
double dy;
double dx_unaccel;
double dy_unaccel;
};
/**
@ -354,6 +346,32 @@ struct _ClutterScrollEvent
ClutterScrollFinishFlags finish_flags;
};
/**
* ClutterStageStateEvent:
* @type: event type
* @time: event time
* @flags: event flags
* @stage: event source stage
* @source: event source actor (unused)
* @changed_mask: bitwise OR of the changed flags
* @new_state: bitwise OR of the current state flags
*
* Event signalling a change in the #ClutterStage state.
*
* Since: 0.2
*/
struct _ClutterStageStateEvent
{
ClutterEventType type;
guint32 time;
ClutterEventFlags flags;
ClutterStage *stage;
ClutterActor *source; /* XXX: should probably be the stage itself */
ClutterStageState changed_mask;
ClutterStageState new_state;
};
/**
* ClutterTouchEvent:
* @type: event type
@ -414,10 +432,6 @@ struct _ClutterTouchEvent
* @y: the Y coordinate of the pointer, relative to the stage
* @dx: movement delta of the pinch focal point in the X axis
* @dy: movement delta of the pinch focal point in the Y axis
* @dx_unaccel: unaccelerated movement delta of the pinch focal
* point in the X axis
* @dy_unaccel: unaccelerated movement delta of the pinch focal
* point in the Y axis
* @angle_delta: angle delta in degrees, clockwise rotations are
* represented by positive deltas
* @scale: the current scale
@ -445,8 +459,6 @@ struct _ClutterTouchpadPinchEvent
gfloat y;
gfloat dx;
gfloat dy;
gfloat dx_unaccel;
gfloat dy_unaccel;
gfloat angle_delta;
gfloat scale;
guint n_fingers;
@ -463,12 +475,8 @@ struct _ClutterTouchpadPinchEvent
* @n_fingers: the number of fingers triggering the swipe
* @x: the X coordinate of the pointer, relative to the stage
* @y: the Y coordinate of the pointer, relative to the stage
* @dx: movement delta of the swipe center point in the X axis
* @dy: movement delta of the swipe center point in the Y axis
* @dx_unaccel: unaccelerated movement delta of the swipe center
* point in the X axis
* @dy_unaccel: unaccelerated movement delta of the swipe center
* point in the Y axis
* @dx: movement delta of the pinch focal point in the X axis
* @dy: movement delta of the pinch focal point in the Y axis
*
* Used for touchpad swipe gesture events. The current state of the
* gesture will be determined by the @phase field.
@ -489,8 +497,6 @@ struct _ClutterTouchpadSwipeEvent
gfloat y;
gfloat dx;
gfloat dy;
gfloat dx_unaccel;
gfloat dy_unaccel;
};
struct _ClutterPadButtonEvent
@ -550,20 +556,6 @@ struct _ClutterDeviceEvent
ClutterInputDevice *device;
};
struct _ClutterIMEvent
{
ClutterEventType type;
uint32_t time;
ClutterEventFlags flags;
ClutterStage *stage;
ClutterActor *source;
char *text;
int32_t offset;
uint32_t len;
ClutterPreeditResetMode mode;
};
/**
* ClutterEvent:
*
@ -581,6 +573,7 @@ union _ClutterEvent
ClutterKeyEvent key;
ClutterMotionEvent motion;
ClutterScrollEvent scroll;
ClutterStageStateEvent stage_state;
ClutterCrossingEvent crossing;
ClutterTouchEvent touch;
ClutterTouchpadPinchEvent touchpad_pinch;
@ -590,7 +583,6 @@ union _ClutterEvent
ClutterPadStripEvent pad_strip;
ClutterPadRingEvent pad_ring;
ClutterDeviceEvent device;
ClutterIMEvent im;
};
/**
@ -692,6 +684,8 @@ void clutter_event_set_stage (ClutterEvent
CLUTTER_EXPORT
ClutterStage * clutter_event_get_stage (const ClutterEvent *event);
CLUTTER_EXPORT
gint clutter_event_get_device_id (const ClutterEvent *event);
CLUTTER_EXPORT
ClutterInputDeviceType clutter_event_get_device_type (const ClutterEvent *event);
CLUTTER_EXPORT
void clutter_event_set_coords (ClutterEvent *event,
@ -790,11 +784,6 @@ void clutter_event_get_gesture_motion_delta (const Clut
gdouble *dx,
gdouble *dy);
CLUTTER_EXPORT
void clutter_event_get_gesture_motion_delta_unaccelerated (const ClutterEvent *event,
gdouble *dx,
gdouble *dy);
CLUTTER_EXPORT
ClutterScrollSource clutter_event_get_scroll_source (const ClutterEvent *event);
@ -809,20 +798,6 @@ gboolean clutter_event_get_pad_event_details (const Clut
guint *number,
guint *mode,
gdouble *value);
CLUTTER_EXPORT
uint32_t clutter_event_get_event_code (const ClutterEvent *event);
CLUTTER_EXPORT
int32_t clutter_event_sequence_get_slot (const ClutterEventSequence *sequence);
CLUTTER_EXPORT
int64_t clutter_event_get_time_us (const ClutterEvent *event);
CLUTTER_EXPORT
gboolean clutter_event_get_relative_motion (const ClutterEvent *event,
double *dx,
double *dy,
double *dx_unaccel,
double *dy_unaccel);
G_END_DECLS

View File

@ -913,7 +913,7 @@ clutter_flow_layout_class_init (ClutterFlowLayoutClass *klass)
* ClutterFlowLayout:orientation:
*
* The orientation of the #ClutterFlowLayout. The children
* of the layout will be laid out following the orientation.
* of the layout will be layed out following the orientation.
*
* This property also controls the overflowing directions
*

View File

@ -19,7 +19,6 @@
#include "clutter/clutter-frame-clock.h"
#include "clutter/clutter-debug.h"
#include "clutter/clutter-main.h"
#include "clutter/clutter-private.h"
#include "clutter/clutter-timeline-private.h"
@ -34,21 +33,8 @@ enum
static guint signals[N_SIGNALS];
/* An estimate queue holds several int64_t values. Adding a new value to the
* queue overwrites the oldest value.
*/
#define ESTIMATE_QUEUE_LENGTH 16
typedef struct _EstimateQueue
{
int64_t values[ESTIMATE_QUEUE_LENGTH];
int next_index;
} EstimateQueue;
/* When heuristic render time is off,
* wait 2ms after vblank before starting to draw next frame.
*/
#define SYNC_DELAY_FALLBACK_US ms2us (2)
/* Wait 2ms after vblank before starting to draw next frame */
#define SYNC_DELAY_US ms2us (2)
typedef struct _ClutterFrameListener
{
@ -77,7 +63,6 @@ struct _ClutterFrameClock
GObject parent;
float refresh_rate;
int64_t refresh_interval_us;
ClutterFrameListener listener;
GSource *source;
@ -85,29 +70,11 @@ struct _ClutterFrameClock
int64_t frame_count;
ClutterFrameClockState state;
int64_t last_dispatch_time_us;
int64_t last_dispatch_lateness_us;
int64_t last_presentation_time_us;
gboolean is_next_presentation_time_valid;
int64_t next_presentation_time_us;
/* Buffer must be submitted to KMS and GPU rendering must be finished
* this amount of time before the next presentation time.
*/
int64_t vblank_duration_us;
/* Last KMS buffer submission time. */
int64_t last_flip_time_us;
/* Last few durations between dispatch start and buffer swap. */
EstimateQueue dispatch_to_swap_us;
/* Last few durations between buffer swap and GPU rendering finish. */
EstimateQueue swap_to_rendering_done_us;
/* Last few durations between buffer swap and KMS submission. */
EstimateQueue swap_to_flip_us;
/* If we got new measurements last frame. */
gboolean got_measurements_last_frame;
gboolean pending_reschedule;
gboolean pending_reschedule_now;
@ -119,29 +86,12 @@ struct _ClutterFrameClock
G_DEFINE_TYPE (ClutterFrameClock, clutter_frame_clock,
G_TYPE_OBJECT)
static void
estimate_queue_add_value (EstimateQueue *queue,
int64_t value)
{
queue->values[queue->next_index] = value;
queue->next_index = (queue->next_index + 1) % ESTIMATE_QUEUE_LENGTH;
}
float
clutter_frame_clock_get_refresh_rate (ClutterFrameClock *frame_clock)
{
return frame_clock->refresh_rate;
}
static void
clutter_frame_clock_set_refresh_rate (ClutterFrameClock *frame_clock,
float refresh_rate)
{
frame_clock->refresh_rate = refresh_rate;
frame_clock->refresh_interval_us =
(int64_t) (0.5 + G_USEC_PER_SEC / refresh_rate);
}
void
clutter_frame_clock_add_timeline (ClutterFrameClock *frame_clock,
ClutterTimeline *timeline)
@ -231,44 +181,20 @@ void
clutter_frame_clock_notify_presented (ClutterFrameClock *frame_clock,
ClutterFrameInfo *frame_info)
{
frame_clock->last_presentation_time_us = frame_info->presentation_time;
int64_t presentation_time_us = frame_info->presentation_time;
frame_clock->got_measurements_last_frame = FALSE;
if (frame_info->cpu_time_before_buffer_swap_us != 0 &&
frame_info->gpu_rendering_duration_ns != 0)
if (presentation_time_us > frame_clock->last_presentation_time_us ||
((presentation_time_us - frame_clock->last_presentation_time_us) >
INT64_MAX / 2))
{
int64_t dispatch_to_swap_us, swap_to_rendering_done_us, swap_to_flip_us;
dispatch_to_swap_us =
frame_info->cpu_time_before_buffer_swap_us -
frame_clock->last_dispatch_time_us;
swap_to_rendering_done_us =
frame_info->gpu_rendering_duration_ns / 1000;
swap_to_flip_us =
frame_clock->last_flip_time_us -
frame_info->cpu_time_before_buffer_swap_us;
CLUTTER_NOTE (FRAME_TIMINGS,
"dispatch2swap %ld µs, swap2render %ld µs, swap2flip %ld µs",
dispatch_to_swap_us,
swap_to_rendering_done_us,
swap_to_flip_us);
estimate_queue_add_value (&frame_clock->dispatch_to_swap_us,
dispatch_to_swap_us);
estimate_queue_add_value (&frame_clock->swap_to_rendering_done_us,
swap_to_rendering_done_us);
estimate_queue_add_value (&frame_clock->swap_to_flip_us,
swap_to_flip_us);
frame_clock->got_measurements_last_frame = TRUE;
frame_clock->last_presentation_time_us = presentation_time_us;
}
if (frame_info->refresh_rate > 1)
else
{
clutter_frame_clock_set_refresh_rate (frame_clock,
frame_info->refresh_rate);
g_warning_once ("Bogus presentation time %" G_GINT64_FORMAT
" travelled back in time, using current time.",
presentation_time_us);
frame_clock->last_presentation_time_us = g_get_monotonic_time ();
}
switch (frame_clock->state)
@ -286,76 +212,6 @@ clutter_frame_clock_notify_presented (ClutterFrameClock *frame_clock,
}
}
void
clutter_frame_clock_notify_ready (ClutterFrameClock *frame_clock)
{
switch (frame_clock->state)
{
case CLUTTER_FRAME_CLOCK_STATE_INIT:
case CLUTTER_FRAME_CLOCK_STATE_IDLE:
case CLUTTER_FRAME_CLOCK_STATE_SCHEDULED:
g_warn_if_reached ();
break;
case CLUTTER_FRAME_CLOCK_STATE_DISPATCHING:
case CLUTTER_FRAME_CLOCK_STATE_PENDING_PRESENTED:
frame_clock->state = CLUTTER_FRAME_CLOCK_STATE_IDLE;
maybe_reschedule_update (frame_clock);
break;
}
}
static int64_t
clutter_frame_clock_compute_max_render_time_us (ClutterFrameClock *frame_clock)
{
int64_t refresh_interval_us;
int64_t max_dispatch_to_swap_us = 0;
int64_t max_swap_to_rendering_done_us = 0;
int64_t max_swap_to_flip_us = 0;
int64_t max_render_time_us;
int i;
refresh_interval_us =
(int64_t) (0.5 + G_USEC_PER_SEC / frame_clock->refresh_rate);
if (!frame_clock->got_measurements_last_frame ||
G_UNLIKELY (clutter_paint_debug_flags &
CLUTTER_DEBUG_DISABLE_DYNAMIC_MAX_RENDER_TIME))
return refresh_interval_us - SYNC_DELAY_FALLBACK_US;
for (i = 0; i < ESTIMATE_QUEUE_LENGTH; ++i)
{
max_dispatch_to_swap_us =
MAX (max_dispatch_to_swap_us,
frame_clock->dispatch_to_swap_us.values[i]);
max_swap_to_rendering_done_us =
MAX (max_swap_to_rendering_done_us,
frame_clock->swap_to_rendering_done_us.values[i]);
max_swap_to_flip_us =
MAX (max_swap_to_flip_us,
frame_clock->swap_to_flip_us.values[i]);
}
/* Max render time shows how early the frame clock needs to be dispatched
* to make it to the predicted next presentation time. It is composed of:
* - An estimate of duration from dispatch start to buffer swap.
* - Maximum between estimates of duration from buffer swap to GPU rendering
* finish and duration from buffer swap to buffer submission to KMS. This
* is because both of these things need to happen before the vblank, and
* they are done in parallel.
* - Duration of the vblank.
* - A constant to account for variations in the above estimates.
*/
max_render_time_us =
max_dispatch_to_swap_us +
MAX (max_swap_to_rendering_done_us, max_swap_to_flip_us) +
frame_clock->vblank_duration_us +
clutter_max_render_time_constant_us;
max_render_time_us = CLAMP (max_render_time_us, 0, refresh_interval_us);
return max_render_time_us;
}
static void
calculate_next_update_time_us (ClutterFrameClock *frame_clock,
int64_t *out_next_update_time_us,
@ -363,6 +219,7 @@ calculate_next_update_time_us (ClutterFrameClock *frame_clock,
{
int64_t last_presentation_time_us;
int64_t now_us;
float refresh_rate;
int64_t refresh_interval_us;
int64_t min_render_time_allowed_us;
int64_t max_render_time_allowed_us;
@ -373,119 +230,36 @@ calculate_next_update_time_us (ClutterFrameClock *frame_clock,
now_us = g_get_monotonic_time ();
refresh_interval_us = frame_clock->refresh_interval_us;
if (frame_clock->last_presentation_time_us == 0)
{
*out_next_update_time_us =
frame_clock->last_dispatch_time_us ?
((frame_clock->last_dispatch_time_us -
frame_clock->last_dispatch_lateness_us) + refresh_interval_us) :
now_us;
*out_next_presentation_time_us = 0;
return;
}
refresh_rate = frame_clock->refresh_rate;
refresh_interval_us = (int64_t) (0.5 + G_USEC_PER_SEC / refresh_rate);
min_render_time_allowed_us = refresh_interval_us / 2;
max_render_time_allowed_us =
clutter_frame_clock_compute_max_render_time_us (frame_clock);
max_render_time_allowed_us = refresh_interval_us - SYNC_DELAY_US;
if (min_render_time_allowed_us > max_render_time_allowed_us)
min_render_time_allowed_us = max_render_time_allowed_us;
/*
* The common case is that the next presentation happens 1 refresh interval
* after the last presentation:
*
* last_presentation_time_us
* / next_presentation_time_us
* / /
* / /
* |--|--o----|-------|--> presentation times
* | | \ |
* | | now_us
* | \______/
* | refresh_interval_us
* |
* 0
*
*/
last_presentation_time_us = frame_clock->last_presentation_time_us;
next_presentation_time_us = last_presentation_time_us + refresh_interval_us;
/*
* However, the last presentation could have happened more than a frame ago.
* For example, due to idling (nothing on screen changed, so no need to
* redraw) or due to frames missing deadlines (GPU busy with heavy rendering).
* The following code adjusts next_presentation_time_us to be in the future,
* but still aligned to display presentation times. Instead of
* next presentation = last presentation + 1 * refresh interval, it will be
* next presentation = last presentation + N * refresh interval.
*/
/* Skip ahead to get close to the actual next presentation time. */
if (next_presentation_time_us < now_us)
{
int64_t presentation_phase_us;
int64_t current_phase_us;
int64_t current_refresh_interval_start_us;
int64_t logical_clock_offset_us;
int64_t logical_clock_phase_us;
int64_t hw_clock_offset_us;
/*
* Let's say we're just past next_presentation_time_us.
*
* First, we compute presentation_phase_us. Real presentation times don't
* have to be exact multiples of refresh_interval_us and
* presentation_phase_us represents this difference. Next, we compute
* current phase and the refresh interval start corresponding to now_us.
* Finally, add presentation_phase_us and a refresh interval to get the
* next presentation after now_us.
*
* last_presentation_time_us
* / next_presentation_time_us
* / / now_us
* / / / new next_presentation_time_us
* |--|-------|---o---|-------|--> presentation times
* | __|
* | |presentation_phase_us
* | |
* | | now_us - presentation_phase_us
* | | /
* |-------|---o---|-------|-----> integer multiples of refresh_interval_us
* | \__/
* | |current_phase_us
* | \
* | current_refresh_interval_start_us
* 0
*
*/
logical_clock_offset_us = now_us % refresh_interval_us;
logical_clock_phase_us = now_us - logical_clock_offset_us;
hw_clock_offset_us = last_presentation_time_us % refresh_interval_us;
presentation_phase_us = last_presentation_time_us % refresh_interval_us;
current_phase_us = (now_us - presentation_phase_us) % refresh_interval_us;
current_refresh_interval_start_us =
now_us - presentation_phase_us - current_phase_us;
next_presentation_time_us =
current_refresh_interval_start_us +
presentation_phase_us +
refresh_interval_us;
next_presentation_time_us = logical_clock_phase_us + hw_clock_offset_us;
}
/*
* Skip one interval if we got an early presented event.
*
* last frame this was last_presentation_time
* / frame_clock->next_presentation_time_us
* / /
* |---|-o-----|-x----->
* | \
* \ next_presentation_time_us is thus right after the last one
* but got an unexpected early presentation
* \_/
* time_since_last_next_presentation_time_us
*
*/
/* Skip one interval if we got an early presented event. */
last_next_presentation_time_us = frame_clock->next_presentation_time_us;
time_since_last_next_presentation_time_us =
next_presentation_time_us - last_next_presentation_time_us;
next_presentation_time_us - last_next_presentation_time_us;
if (frame_clock->is_next_presentation_time_valid &&
time_since_last_next_presentation_time_us < (refresh_interval_us / 2))
{
@ -592,8 +366,7 @@ clutter_frame_clock_schedule_update (ClutterFrameClock *frame_clock)
calculate_next_update_time_us (frame_clock,
&next_update_time_us,
&frame_clock->next_presentation_time_us);
frame_clock->is_next_presentation_time_valid =
(frame_clock->next_presentation_time_us != 0);
frame_clock->is_next_presentation_time_valid = TRUE;
break;
case CLUTTER_FRAME_CLOCK_STATE_SCHEDULED:
return;
@ -615,21 +388,9 @@ clutter_frame_clock_dispatch (ClutterFrameClock *frame_clock,
{
int64_t frame_count;
ClutterFrameResult result;
int64_t ideal_dispatch_time_us, lateness_us;
COGL_TRACE_BEGIN_SCOPED (ClutterFrameClockDispatch, "Frame Clock (dispatch)");
COGL_TRACE_BEGIN_SCOPED (ClutterFrameCLockDispatch, "Frame Clock (dispatch)");
ideal_dispatch_time_us = (frame_clock->last_dispatch_time_us -
frame_clock->last_dispatch_lateness_us) +
frame_clock->refresh_interval_us;
lateness_us = time_us - ideal_dispatch_time_us;
if (lateness_us < 0 || lateness_us >= frame_clock->refresh_interval_us)
frame_clock->last_dispatch_lateness_us = 0;
else
frame_clock->last_dispatch_lateness_us = lateness_us;
frame_clock->last_dispatch_time_us = time_us;
g_source_set_ready_time (frame_clock->source, -1);
frame_clock->state = CLUTTER_FRAME_CLOCK_STATE_DISPATCHING;
@ -695,58 +456,6 @@ frame_clock_source_dispatch (GSource *source,
return G_SOURCE_CONTINUE;
}
void
clutter_frame_clock_record_flip_time (ClutterFrameClock *frame_clock,
int64_t flip_time_us)
{
frame_clock->last_flip_time_us = flip_time_us;
}
GString *
clutter_frame_clock_get_max_render_time_debug_info (ClutterFrameClock *frame_clock)
{
int64_t max_dispatch_to_swap_us = 0;
int64_t max_swap_to_rendering_done_us = 0;
int64_t max_swap_to_flip_us = 0;
int i;
GString *string;
string = g_string_new (NULL);
g_string_append_printf (string, "Max render time: %ld µs",
clutter_frame_clock_compute_max_render_time_us (frame_clock));
if (frame_clock->got_measurements_last_frame)
g_string_append_printf (string, " =");
else
g_string_append_printf (string, " (no measurements last frame)");
for (i = 0; i < ESTIMATE_QUEUE_LENGTH; ++i)
{
max_dispatch_to_swap_us =
MAX (max_dispatch_to_swap_us,
frame_clock->dispatch_to_swap_us.values[i]);
max_swap_to_rendering_done_us =
MAX (max_swap_to_rendering_done_us,
frame_clock->swap_to_rendering_done_us.values[i]);
max_swap_to_flip_us =
MAX (max_swap_to_flip_us,
frame_clock->swap_to_flip_us.values[i]);
}
g_string_append_printf (string, "\nVblank duration: %ld µs +",
frame_clock->vblank_duration_us);
g_string_append_printf (string, "\nDispatch to swap: %ld µs +",
max_dispatch_to_swap_us);
g_string_append_printf (string, "\nmax(Swap to rendering done: %ld µs,",
max_swap_to_rendering_done_us);
g_string_append_printf (string, "\nSwap to flip: %ld µs) +",
max_swap_to_flip_us);
g_string_append_printf (string, "\nConstant: %d µs",
clutter_max_render_time_constant_us);
return string;
}
static GSourceFuncs frame_clock_source_funcs = {
NULL,
NULL,
@ -776,7 +485,6 @@ init_frame_clock_source (ClutterFrameClock *frame_clock)
ClutterFrameClock *
clutter_frame_clock_new (float refresh_rate,
int64_t vblank_duration_us,
const ClutterFrameListenerIface *iface,
gpointer user_data)
{
@ -791,8 +499,7 @@ clutter_frame_clock_new (float refresh_rate,
init_frame_clock_source (frame_clock);
clutter_frame_clock_set_refresh_rate (frame_clock, refresh_rate);
frame_clock->vblank_duration_us = vblank_duration_us;
frame_clock->refresh_rate = refresh_rate;
return frame_clock;
}

View File

@ -40,9 +40,6 @@ G_DECLARE_FINAL_TYPE (ClutterFrameClock, clutter_frame_clock,
CLUTTER, FRAME_CLOCK,
GObject)
/**
* ClutterFrameListenerIface: (skip)
*/
typedef struct _ClutterFrameListenerIface
{
void (* before_frame) (ClutterFrameClock *frame_clock,
@ -56,7 +53,6 @@ typedef struct _ClutterFrameListenerIface
CLUTTER_EXPORT
ClutterFrameClock * clutter_frame_clock_new (float refresh_rate,
int64_t vblank_duration_us,
const ClutterFrameListenerIface *iface,
gpointer user_data);
@ -67,9 +63,6 @@ CLUTTER_EXPORT
void clutter_frame_clock_notify_presented (ClutterFrameClock *frame_clock,
ClutterFrameInfo *frame_info);
CLUTTER_EXPORT
void clutter_frame_clock_notify_ready (ClutterFrameClock *frame_clock);
CLUTTER_EXPORT
void clutter_frame_clock_schedule_update (ClutterFrameClock *frame_clock);
@ -91,9 +84,4 @@ void clutter_frame_clock_remove_timeline (ClutterFrameClock *frame_clock,
CLUTTER_EXPORT
float clutter_frame_clock_get_refresh_rate (ClutterFrameClock *frame_clock);
void clutter_frame_clock_record_flip_time (ClutterFrameClock *frame_clock,
int64_t flip_time_us);
GString * clutter_frame_clock_get_max_render_time_debug_info (ClutterFrameClock *frame_clock);
#endif /* CLUTTER_FRAME_CLOCK_H */

View File

@ -1,33 +0,0 @@
/*
* Copyright (C) 2020 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/>.
*/
#ifndef CLUTTER_FRAME_PRIVATE_H
#define CLUTTER_FRAME_PRIVATE_H
#include "clutter/clutter-frame.h"
struct _ClutterFrame
{
gboolean has_result;
ClutterFrameResult result;
};
#define CLUTTER_FRAME_INIT ((ClutterFrame) { 0 })
ClutterFrameResult clutter_frame_get_result (ClutterFrame *frame);
#endif /* CLUTTER_FRAME_PRIVATE_H */

View File

@ -1,42 +0,0 @@
/*
* Copyright (C) 2020 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/>.
*/
#include "clutter/clutter-frame-private.h"
ClutterFrameResult
clutter_frame_get_result (ClutterFrame *frame)
{
g_return_val_if_fail (frame->has_result, CLUTTER_FRAME_RESULT_IDLE);
return frame->result;
}
gboolean
clutter_frame_has_result (ClutterFrame *frame)
{
return frame->has_result;
}
void
clutter_frame_set_result (ClutterFrame *frame,
ClutterFrameResult result)
{
g_warn_if_fail (!frame->has_result);
frame->result = result;
frame->has_result = TRUE;
}

View File

@ -1,36 +0,0 @@
/*
* Copyright (C) 2020 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/>.
*/
#ifndef CLUTTER_FRAME_H
#define CLUTTER_FRAME_H
#if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION)
#error "Only <clutter/clutter.h> can be included directly."
#endif
#include "clutter/clutter-frame-clock.h"
typedef struct _ClutterFrame ClutterFrame;
CLUTTER_EXPORT
void clutter_frame_set_result (ClutterFrame *frame,
ClutterFrameResult result);
CLUTTER_EXPORT
gboolean clutter_frame_has_result (ClutterFrame *frame);
#endif /* CLUTTER_FRAME_H */

View File

@ -416,10 +416,12 @@ stage_captured_event_cb (ClutterActor *stage,
return CLUTTER_EVENT_PROPAGATE;
}
gesture_update_motion_point (point, event);
if (!begin_gesture (action, actor))
return CLUTTER_EVENT_PROPAGATE;
{
if ((point = gesture_find_point (action, event, &position)) != NULL)
gesture_update_motion_point (point, event);
return CLUTTER_EVENT_PROPAGATE;
}
if ((point = gesture_find_point (action, event, &position)) == NULL)
return CLUTTER_EVENT_PROPAGATE;
@ -572,13 +574,8 @@ clutter_gesture_action_set_enabled (ClutterActorMeta *meta,
ClutterGestureActionPrivate *priv =
clutter_gesture_action_get_instance_private (gesture_action);
if (!is_enabled)
{
if (priv->in_gesture)
cancel_gesture (gesture_action);
else
g_array_set_size (priv->points, 0);
}
if (!is_enabled && priv->in_gesture)
cancel_gesture (gesture_action);
meta_class->set_enabled (meta, is_enabled);
}

View File

@ -29,23 +29,6 @@
#include "clutter-private.h"
#include "clutter-types.h"
static gboolean
graphene_matrix_progress (const GValue *a,
const GValue *b,
double progress,
GValue *retval)
{
const graphene_matrix_t *am = g_value_get_boxed (a);
const graphene_matrix_t *bm = g_value_get_boxed (b);
graphene_matrix_t res;
graphene_matrix_interpolate (am, bm, progress, &res);
g_value_set_boxed (retval, &res);
return TRUE;
}
static gboolean
graphene_point_progress (const GValue *a,
const GValue *b,
@ -117,8 +100,6 @@ graphene_size_progress (const GValue *a,
void
clutter_graphene_init (void)
{
clutter_interval_register_progress_func (GRAPHENE_TYPE_MATRIX,
graphene_matrix_progress);
clutter_interval_register_progress_func (GRAPHENE_TYPE_POINT,
graphene_point_progress);
clutter_interval_register_progress_func (GRAPHENE_TYPE_POINT3D,

View File

@ -44,7 +44,7 @@ _clutter_id_pool_new (guint initial_size)
{
ClutterIDPool *self;
self = g_new0 (ClutterIDPool, 1);
self = g_slice_new (ClutterIDPool);
self->array = g_array_sized_new (FALSE, FALSE,
sizeof (gpointer), initial_size);
@ -59,7 +59,7 @@ _clutter_id_pool_free (ClutterIDPool *id_pool)
g_array_free (id_pool->array, TRUE);
g_slist_free (id_pool->free_ids);
g_free (id_pool);
g_slice_free (ClutterIDPool, id_pool);
}
guint32

View File

@ -38,6 +38,8 @@
#include "clutter-build-config.h"
#define CLUTTER_ENABLE_EXPERIMENTAL_API
#include "clutter-image.h"
#include "clutter-actor-private.h"

View File

@ -32,6 +32,35 @@
G_BEGIN_DECLS
typedef struct _ClutterAxisInfo
{
ClutterInputAxis axis;
double min_axis;
double max_axis;
double min_value;
double max_value;
double resolution;
} ClutterAxisInfo;
typedef struct _ClutterKeyInfo
{
guint keyval;
ClutterModifierType modifiers;
} ClutterKeyInfo;
typedef struct _ClutterScrollInfo
{
guint axis_id;
ClutterScrollDirection direction;
double increment;
double last_value;
guint last_value_valid : 1;
} ClutterScrollInfo;
typedef struct _ClutterPtrA11yData
{
int n_btn_pressed;
@ -53,6 +82,26 @@ struct _ClutterInputDevice
{
GObject parent_instance;
int id;
ClutterInputDeviceType device_type;
ClutterInputMode device_mode;
char *device_name;
ClutterSeat *seat;
ClutterBackend *backend;
/* the associated device */
ClutterInputDevice *associated;
GList *slaves;
/* the actor underneath the pointer */
ClutterActor *cursor_actor;
GHashTable *inv_touch_sequence_actors;
/* the actor that has a grab in place for the device */
ClutterActor *pointer_grab_actor;
ClutterActor *keyboard_grab_actor;
@ -61,7 +110,13 @@ struct _ClutterInputDevice
/* the current click count */
int click_count;
/* the current state */
int current_button_number;
ClutterModifierType current_state;
/* the current touch points targets */
GHashTable *touch_sequence_actors;
/* the previous state, used for click count generation */
int previous_x;
@ -69,9 +124,103 @@ struct _ClutterInputDevice
uint32_t previous_time;
int previous_button_number;
GArray *axes;
guint n_keys;
GArray *keys;
GArray *scroll_info;
char *vendor_id;
char *product_id;
char *node_path;
GPtrArray *tools;
int n_rings;
int n_strips;
int n_mode_groups;
guint has_cursor : 1;
guint is_enabled : 1;
/* Accessiblity */
ClutterVirtualInputDevice *accessibility_virtual_device;
ClutterPtrA11yData *ptr_a11y_data;
};
CLUTTER_EXPORT
void _clutter_input_device_set_associated_device (ClutterInputDevice *device,
ClutterInputDevice *associated);
CLUTTER_EXPORT
void _clutter_input_device_add_slave (ClutterInputDevice *master,
ClutterInputDevice *slave);
CLUTTER_EXPORT
void _clutter_input_device_remove_slave (ClutterInputDevice *master,
ClutterInputDevice *slave);
CLUTTER_EXPORT
void clutter_input_device_update_from_tool (ClutterInputDevice *device,
ClutterInputDeviceTool *tool);
CLUTTER_EXPORT
ClutterActor * clutter_input_device_update (ClutterInputDevice *device,
ClutterEventSequence *sequence,
ClutterStage *stage,
gboolean emit_crossing,
ClutterEvent *for_event);
CLUTTER_EXPORT
void _clutter_input_device_remove_event_sequence (ClutterInputDevice *device,
ClutterEvent *event);
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,
gdouble *axis_value);
CLUTTER_EXPORT
guint _clutter_input_device_add_axis (ClutterInputDevice *device,
ClutterInputAxis axis,
gdouble minimum,
gdouble maximum,
gdouble resolution);
CLUTTER_EXPORT
void _clutter_input_device_reset_axes (ClutterInputDevice *device);
CLUTTER_EXPORT
void _clutter_input_device_add_scroll_info (ClutterInputDevice *device,
guint index_,
ClutterScrollDirection direction,
gdouble increment);
CLUTTER_EXPORT
gboolean _clutter_input_device_get_scroll_delta (ClutterInputDevice *device,
guint index_,
gdouble value,
ClutterScrollDirection *direction_p,
gdouble *delta_p);
CLUTTER_EXPORT
void _clutter_input_device_reset_scroll_info (ClutterInputDevice *device);
CLUTTER_EXPORT
void clutter_input_device_add_tool (ClutterInputDevice *device,
ClutterInputDeviceTool *tool);
CLUTTER_EXPORT
ClutterInputDeviceTool *
clutter_input_device_lookup_tool (ClutterInputDevice *device,
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

@ -33,7 +33,6 @@ struct _ClutterInputDeviceToolPrivate
ClutterInputDeviceToolType type;
guint64 serial;
guint64 id;
ClutterInputAxisFlags axes;
};
enum
@ -42,7 +41,6 @@ enum
PROP_TYPE,
PROP_SERIAL,
PROP_ID,
PROP_AXES,
PROP_LAST
};
@ -72,9 +70,6 @@ clutter_input_device_tool_set_property (GObject *object,
case PROP_ID:
priv->id = g_value_get_uint64 (value);
break;
case PROP_AXES:
priv->axes = g_value_get_flags (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
@ -102,9 +97,6 @@ clutter_input_device_tool_get_property (GObject *object,
case PROP_ID:
g_value_set_uint64 (value, priv->id);
break;
case PROP_AXES:
g_value_set_flags (value, priv->axes);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
@ -137,13 +129,6 @@ clutter_input_device_tool_class_init (ClutterInputDeviceToolClass *klass)
P_("Tool ID"),
0, G_MAXUINT64, 0,
CLUTTER_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
props[PROP_AXES] =
g_param_spec_flags ("axes",
P_("Axes"),
P_("Axes"),
CLUTTER_TYPE_INPUT_AXIS_FLAGS,
CLUTTER_INPUT_AXIS_FLAG_NONE,
CLUTTER_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
g_object_class_install_properties (gobject_class, PROP_LAST, props);
}
@ -219,15 +204,3 @@ clutter_input_device_tool_get_id (ClutterInputDeviceTool *tool)
return priv->id;
}
ClutterInputAxisFlags
clutter_input_device_tool_get_axes (ClutterInputDeviceTool *tool)
{
ClutterInputDeviceToolPrivate *priv;
g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE_TOOL (tool), 0);
priv = clutter_input_device_tool_get_instance_private (tool);
return priv->axes;
}

View File

@ -64,9 +64,6 @@ ClutterInputDeviceToolType clutter_input_device_tool_get_tool_type (ClutterInput
CLUTTER_EXPORT
guint64 clutter_input_device_tool_get_id (ClutterInputDeviceTool *tool);
CLUTTER_EXPORT
ClutterInputAxisFlags clutter_input_device_tool_get_axes (ClutterInputDeviceTool *tool);
G_END_DECLS
#endif /* __CLUTTER_INPUT_DEVICE_TOOL_H__ */

File diff suppressed because it is too large Load Diff

View File

@ -34,10 +34,19 @@
G_BEGIN_DECLS
typedef void (*ClutterEmitInputDeviceEvent) (ClutterEvent *event,
ClutterInputDevice *device);
struct _ClutterInputDeviceClass
{
GObjectClass parent_class;
gboolean (* keycode_to_evdev) (ClutterInputDevice *device,
guint hardware_keycode,
guint *evdev_keycode);
void (* update_from_tool) (ClutterInputDevice *device,
ClutterInputDeviceTool *tool);
gboolean (* is_mode_switch_button) (ClutterInputDevice *device,
guint group,
guint button);
@ -47,9 +56,10 @@ struct _ClutterInputDeviceClass
gboolean (* is_grouped) (ClutterInputDevice *device,
ClutterInputDevice *other_device);
int (* get_pad_feature_group) (ClutterInputDevice *device,
ClutterInputDevicePadFeature feature,
int n_feature);
/* Keyboard accessbility */
void (* process_kbd_a11y_event) (ClutterEvent *event,
ClutterInputDevice *device,
ClutterEmitInputDeviceEvent emit_event_func);
};
#define CLUTTER_TYPE_INPUT_DEVICE (clutter_input_device_get_type ())
@ -72,7 +82,18 @@ GType clutter_input_device_get_type (void) G_GNUC_CONST;
CLUTTER_EXPORT
ClutterInputDeviceType clutter_input_device_get_device_type (ClutterInputDevice *device);
CLUTTER_EXPORT
gint clutter_input_device_get_device_id (ClutterInputDevice *device);
CLUTTER_EXPORT
gboolean clutter_input_device_get_coords (ClutterInputDevice *device,
ClutterEventSequence *sequence,
graphene_point_t *point);
CLUTTER_EXPORT
ClutterModifierType clutter_input_device_get_modifier_state (ClutterInputDevice *device);
CLUTTER_EXPORT
ClutterActor * clutter_input_device_get_actor (ClutterInputDevice *device,
ClutterEventSequence *sequence);
CLUTTER_EXPORT
const gchar * clutter_input_device_get_device_name (ClutterInputDevice *device);
CLUTTER_EXPORT
@ -80,6 +101,30 @@ ClutterInputMode clutter_input_device_get_device_mode (ClutterInputDev
CLUTTER_EXPORT
gboolean clutter_input_device_get_has_cursor (ClutterInputDevice *device);
CLUTTER_EXPORT
guint clutter_input_device_get_n_axes (ClutterInputDevice *device);
CLUTTER_EXPORT
ClutterInputAxis clutter_input_device_get_axis (ClutterInputDevice *device,
guint index_);
CLUTTER_EXPORT
gboolean clutter_input_device_get_axis_value (ClutterInputDevice *device,
gdouble *axes,
ClutterInputAxis axis,
gdouble *value);
CLUTTER_EXPORT
guint clutter_input_device_get_n_keys (ClutterInputDevice *device);
CLUTTER_EXPORT
gboolean clutter_input_device_get_key (ClutterInputDevice *device,
guint index_,
guint *keyval,
ClutterModifierType *modifiers);
CLUTTER_EXPORT
ClutterInputDevice * clutter_input_device_get_associated_device (ClutterInputDevice *device);
CLUTTER_EXPORT
GList * clutter_input_device_get_slave_devices (ClutterInputDevice *device);
CLUTTER_EXPORT
void clutter_input_device_grab (ClutterInputDevice *device,
ClutterActor *actor);
@ -110,9 +155,6 @@ CLUTTER_EXPORT
gint clutter_input_device_get_n_strips (ClutterInputDevice *device);
CLUTTER_EXPORT
gint clutter_input_device_get_n_mode_groups (ClutterInputDevice *device);
CLUTTER_EXPORT
int clutter_input_device_get_n_buttons (ClutterInputDevice *device);
CLUTTER_EXPORT
gint clutter_input_device_get_group_n_modes (ClutterInputDevice *device,
@ -135,11 +177,6 @@ gboolean clutter_input_device_is_grouped (ClutterInputDev
CLUTTER_EXPORT
ClutterSeat * clutter_input_device_get_seat (ClutterInputDevice *device);
CLUTTER_EXPORT
int clutter_input_device_get_pad_feature_group (ClutterInputDevice *device,
ClutterInputDevicePadFeature feature,
int n_feature);
G_END_DECLS
#endif /* __CLUTTER_INPUT_DEVICE_H__ */

View File

@ -30,8 +30,6 @@ typedef struct _ClutterInputFocusPrivate ClutterInputFocusPrivate;
struct _ClutterInputFocusPrivate
{
ClutterInputMethod *im;
char *preedit;
ClutterPreeditResetMode mode;
};
G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (ClutterInputFocus, clutter_input_focus, G_TYPE_OBJECT)
@ -55,25 +53,9 @@ clutter_input_focus_real_focus_out (ClutterInputFocus *focus)
priv->im = NULL;
}
static void
clutter_input_focus_finalize (GObject *object)
{
ClutterInputFocus *focus = CLUTTER_INPUT_FOCUS (object);
ClutterInputFocusPrivate *priv =
clutter_input_focus_get_instance_private (focus);
g_clear_pointer (&priv->preedit, g_free);
G_OBJECT_CLASS (clutter_input_focus_parent_class)->finalize (object);
}
static void
clutter_input_focus_class_init (ClutterInputFocusClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->finalize = clutter_input_focus_finalize;
klass->focus_in = clutter_input_focus_real_focus_in;
klass->focus_out = clutter_input_focus_real_focus_out;
}
@ -103,16 +85,6 @@ clutter_input_focus_reset (ClutterInputFocus *focus)
priv = clutter_input_focus_get_instance_private (focus);
if (priv->preedit)
{
if (priv->mode == CLUTTER_PREEDIT_RESET_COMMIT)
clutter_input_focus_commit (focus, priv->preedit);
clutter_input_focus_set_preedit_text (focus, NULL, 0);
g_clear_pointer (&priv->preedit, g_free);
}
priv->mode = CLUTTER_PREEDIT_RESET_CLEAR;
clutter_input_method_reset (priv->im);
}
@ -175,8 +147,8 @@ clutter_input_focus_set_content_purpose (ClutterInputFocus *focus,
}
gboolean
clutter_input_focus_filter_event (ClutterInputFocus *focus,
const ClutterEvent *event)
clutter_input_focus_filter_key_event (ClutterInputFocus *focus,
const ClutterKeyEvent *key)
{
ClutterInputFocusPrivate *priv;
@ -185,41 +157,7 @@ clutter_input_focus_filter_event (ClutterInputFocus *focus,
priv = clutter_input_focus_get_instance_private (focus);
if (event->type == CLUTTER_KEY_PRESS ||
event->type == CLUTTER_KEY_RELEASE)
{
return clutter_input_method_filter_key_event (priv->im, &event->key);
}
else if (event->type == CLUTTER_IM_COMMIT)
{
clutter_input_focus_commit (focus, event->im.text);
return TRUE;
}
else if (event->type == CLUTTER_IM_DELETE)
{
clutter_input_focus_delete_surrounding (focus, event->im.offset,
event->im.len);
return TRUE;
}
else if (event->type == CLUTTER_IM_PREEDIT)
{
g_clear_pointer (&priv->preedit, g_free);
priv->preedit = g_strdup (event->im.text);
priv->mode = event->im.mode;
clutter_input_focus_set_preedit_text (focus, event->im.text,
event->im.offset);
return TRUE;
}
else if (event->type == CLUTTER_TOUCH_BEGIN ||
(event->type == CLUTTER_BUTTON_PRESS &&
event->button.button == CLUTTER_BUTTON_PRIMARY))
{
clutter_input_focus_reset (focus);
/* pointing events are not consumed by IMs */
return FALSE;
}
return FALSE;
return clutter_input_method_filter_key_event (priv->im, key);
}
void

View File

@ -72,8 +72,8 @@ CLUTTER_EXPORT
void clutter_input_focus_set_content_purpose (ClutterInputFocus *focus,
ClutterInputContentPurpose purpose);
CLUTTER_EXPORT
gboolean clutter_input_focus_filter_event (ClutterInputFocus *focus,
const ClutterEvent *event);
gboolean clutter_input_focus_filter_key_event (ClutterInputFocus *focus,
const ClutterKeyEvent *key);
CLUTTER_EXPORT
void clutter_input_focus_set_can_show_preedit (ClutterInputFocus *focus,
gboolean can_show_preedit);

View File

@ -277,48 +277,17 @@ clutter_input_method_get_focus (ClutterInputMethod *im)
return priv->focus;
}
static void
clutter_input_method_put_im_event (ClutterInputMethod *im,
ClutterEventType event_type,
const char *text,
int32_t offset,
uint32_t len,
ClutterPreeditResetMode mode)
{
ClutterInputDevice *keyboard;
ClutterSeat *seat;
ClutterStageManager *stage_manager;
ClutterStage *stage;
ClutterEvent *event;
seat = clutter_backend_get_default_seat (clutter_get_default_backend ());
keyboard = clutter_seat_get_keyboard (seat);
stage_manager = clutter_stage_manager_get_default ();
stage = clutter_stage_manager_get_default_stage (stage_manager);
event = clutter_event_new (event_type);
event->im.text = g_strdup (text);
event->im.offset = offset;
event->im.len = len;
event->im.mode = mode;
clutter_event_set_device (event, keyboard);
clutter_event_set_source_device (event, keyboard);
clutter_event_set_flags (event, CLUTTER_EVENT_FLAG_INPUT_METHOD);
clutter_event_set_stage (event, stage);
clutter_event_put (event);
clutter_event_free (event);
}
void
clutter_input_method_commit (ClutterInputMethod *im,
const gchar *text)
{
ClutterInputMethodPrivate *priv;
g_return_if_fail (CLUTTER_IS_INPUT_METHOD (im));
clutter_input_method_put_im_event (im, CLUTTER_IM_COMMIT, text, 0, 0,
CLUTTER_PREEDIT_RESET_CLEAR);
priv = clutter_input_method_get_instance_private (im);
if (priv->focus)
clutter_input_focus_commit (priv->focus, text);
}
void
@ -326,10 +295,13 @@ clutter_input_method_delete_surrounding (ClutterInputMethod *im,
int offset,
guint len)
{
ClutterInputMethodPrivate *priv;
g_return_if_fail (CLUTTER_IS_INPUT_METHOD (im));
clutter_input_method_put_im_event (im, CLUTTER_IM_DELETE, NULL, offset, len,
CLUTTER_PREEDIT_RESET_CLEAR);
priv = clutter_input_method_get_instance_private (im);
if (priv->focus)
clutter_input_focus_delete_surrounding (priv->focus, offset, len);
}
void
@ -353,15 +325,17 @@ clutter_input_method_request_surrounding (ClutterInputMethod *im)
* Sets the preedit text on the current input focus.
**/
void
clutter_input_method_set_preedit_text (ClutterInputMethod *im,
const gchar *preedit,
unsigned int cursor,
ClutterPreeditResetMode mode)
clutter_input_method_set_preedit_text (ClutterInputMethod *im,
const gchar *preedit,
guint cursor)
{
ClutterInputMethodPrivate *priv;
g_return_if_fail (CLUTTER_IS_INPUT_METHOD (im));
clutter_input_method_put_im_event (im, CLUTTER_IM_PREEDIT, preedit,
cursor, 0, mode);
priv = clutter_input_method_get_instance_private (im);
if (priv->focus)
clutter_input_focus_set_preedit_text (priv->focus, preedit, cursor);
}
void
@ -501,7 +475,6 @@ clutter_input_method_forward_key (ClutterInputMethod *im,
event->key.modifier_state = state;
event->key.keyval = keyval;
event->key.hardware_keycode = keycode;
event->key.evdev_code = keycode - 8;
event->key.unicode_value = clutter_keysym_to_unicode (keyval);
clutter_event_set_device (event, keyboard);

View File

@ -74,10 +74,9 @@ CLUTTER_EXPORT
void clutter_input_method_request_surrounding (ClutterInputMethod *im);
CLUTTER_EXPORT
void clutter_input_method_set_preedit_text (ClutterInputMethod *im,
const gchar *preedit,
unsigned int cursor,
ClutterPreeditResetMode mode);
void clutter_input_method_set_preedit_text (ClutterInputMethod *im,
const gchar *preedit,
guint cursor);
CLUTTER_EXPORT
void clutter_input_method_notify_key_event (ClutterInputMethod *im,

View File

@ -36,9 +36,8 @@ static gboolean
is_secondary_click_enabled (ClutterInputDevice *device)
{
ClutterPointerA11ySettings settings;
ClutterSeat *seat = clutter_input_device_get_seat (device);
clutter_seat_get_pointer_a11y_settings (seat, &settings);
clutter_seat_get_pointer_a11y_settings (device->seat, &settings);
return (settings.controls & CLUTTER_A11Y_SECONDARY_CLICK_ENABLED);
}
@ -47,9 +46,8 @@ static gboolean
is_dwell_click_enabled (ClutterInputDevice *device)
{
ClutterPointerA11ySettings settings;
ClutterSeat *seat = clutter_input_device_get_seat (device);
clutter_seat_get_pointer_a11y_settings (seat, &settings);
clutter_seat_get_pointer_a11y_settings (device->seat, &settings);
return (settings.controls & CLUTTER_A11Y_DWELL_ENABLED);
}
@ -58,9 +56,8 @@ static unsigned int
get_secondary_click_delay (ClutterInputDevice *device)
{
ClutterPointerA11ySettings settings;
ClutterSeat *seat = clutter_input_device_get_seat (device);
clutter_seat_get_pointer_a11y_settings (seat, &settings);
clutter_seat_get_pointer_a11y_settings (device->seat, &settings);
return settings.secondary_click_delay;
}
@ -69,9 +66,8 @@ static unsigned int
get_dwell_delay (ClutterInputDevice *device)
{
ClutterPointerA11ySettings settings;
ClutterSeat *seat = clutter_input_device_get_seat (device);
clutter_seat_get_pointer_a11y_settings (seat, &settings);
clutter_seat_get_pointer_a11y_settings (device->seat, &settings);
return settings.dwell_delay;
}
@ -80,9 +76,8 @@ static unsigned int
get_dwell_threshold (ClutterInputDevice *device)
{
ClutterPointerA11ySettings settings;
ClutterSeat *seat = clutter_input_device_get_seat (device);
clutter_seat_get_pointer_a11y_settings (seat, &settings);
clutter_seat_get_pointer_a11y_settings (device->seat, &settings);
return settings.dwell_threshold;
}
@ -91,9 +86,8 @@ static ClutterPointerA11yDwellMode
get_dwell_mode (ClutterInputDevice *device)
{
ClutterPointerA11ySettings settings;
ClutterSeat *seat = clutter_input_device_get_seat (device);
clutter_seat_get_pointer_a11y_settings (seat, &settings);
clutter_seat_get_pointer_a11y_settings (device->seat, &settings);
return settings.dwell_mode;
}
@ -102,9 +96,8 @@ static ClutterPointerA11yDwellClickType
get_dwell_click_type (ClutterInputDevice *device)
{
ClutterPointerA11ySettings settings;
ClutterSeat *seat = clutter_input_device_get_seat (device);
clutter_seat_get_pointer_a11y_settings (seat, &settings);
clutter_seat_get_pointer_a11y_settings (device->seat, &settings);
return settings.dwell_click_type;
}
@ -114,9 +107,8 @@ get_dwell_click_type_for_direction (ClutterInputDevice *device,
ClutterPointerA11yDwellDirection direction)
{
ClutterPointerA11ySettings settings;
ClutterSeat *seat = clutter_input_device_get_seat (device);
clutter_seat_get_pointer_a11y_settings (seat, &settings);
clutter_seat_get_pointer_a11y_settings (device->seat, &settings);
if (direction == settings.dwell_gesture_single)
return CLUTTER_A11Y_DWELL_CLICK_TYPE_PRIMARY;
@ -171,12 +163,11 @@ static gboolean
trigger_secondary_click (gpointer data)
{
ClutterInputDevice *device = data;
ClutterSeat *seat = clutter_input_device_get_seat (device);
device->ptr_a11y_data->secondary_click_triggered = TRUE;
device->ptr_a11y_data->secondary_click_timer = 0;
g_signal_emit_by_name (seat,
g_signal_emit_by_name (device->seat,
"ptr-a11y-timeout-stopped",
device,
CLUTTER_A11Y_TIMEOUT_TYPE_SECONDARY_CLICK,
@ -189,12 +180,11 @@ static void
start_secondary_click_timeout (ClutterInputDevice *device)
{
unsigned int delay = get_secondary_click_delay (device);
ClutterSeat *seat = clutter_input_device_get_seat (device);
device->ptr_a11y_data->secondary_click_timer =
clutter_threads_add_timeout (delay, trigger_secondary_click, device);
g_signal_emit_by_name (seat,
g_signal_emit_by_name (device->seat,
"ptr-a11y-timeout-started",
device,
CLUTTER_A11Y_TIMEOUT_TYPE_SECONDARY_CLICK,
@ -204,14 +194,12 @@ start_secondary_click_timeout (ClutterInputDevice *device)
static void
stop_secondary_click_timeout (ClutterInputDevice *device)
{
ClutterSeat *seat = clutter_input_device_get_seat (device);
if (device->ptr_a11y_data->secondary_click_timer)
{
g_clear_handle_id (&device->ptr_a11y_data->secondary_click_timer,
g_source_remove);
g_signal_emit_by_name (seat,
g_signal_emit_by_name (device->seat,
"ptr-a11y-timeout-stopped",
device,
CLUTTER_A11Y_TIMEOUT_TYPE_SECONDARY_CLICK,
@ -314,9 +302,8 @@ update_dwell_click_type (ClutterInputDevice *device)
{
ClutterPointerA11ySettings settings;
ClutterPointerA11yDwellClickType dwell_click_type;
ClutterSeat *seat = clutter_input_device_get_seat (device);
clutter_seat_get_pointer_a11y_settings (seat, &settings);
clutter_seat_get_pointer_a11y_settings (device->seat, &settings);
dwell_click_type = settings.dwell_click_type;
switch (dwell_click_type)
@ -341,9 +328,9 @@ update_dwell_click_type (ClutterInputDevice *device)
if (dwell_click_type != settings.dwell_click_type)
{
settings.dwell_click_type = dwell_click_type;
clutter_seat_set_pointer_a11y_settings (seat, &settings);
clutter_seat_set_pointer_a11y_settings (device->seat, &settings);
g_signal_emit_by_name (seat,
g_signal_emit_by_name (device->seat,
"ptr-a11y-dwell-click-type-changed",
dwell_click_type);
}
@ -437,7 +424,6 @@ trigger_dwell_gesture (gpointer data)
ClutterInputDevice *device = data;
ClutterPointerA11yDwellDirection direction;
unsigned int delay = get_dwell_delay (device);
ClutterSeat *seat = clutter_input_device_get_seat (device);
restore_dwell_position (device);
direction = get_dwell_direction (device);
@ -449,7 +435,7 @@ trigger_dwell_gesture (gpointer data)
device->ptr_a11y_data->dwell_timer =
clutter_threads_add_timeout (delay, trigger_clear_dwell_gesture, device);
g_signal_emit_by_name (seat,
g_signal_emit_by_name (device->seat,
"ptr-a11y-timeout-stopped",
device,
CLUTTER_A11Y_TIMEOUT_TYPE_GESTURE,
@ -462,13 +448,12 @@ static void
start_dwell_gesture_timeout (ClutterInputDevice *device)
{
unsigned int delay = get_dwell_delay (device);
ClutterSeat *seat = clutter_input_device_get_seat (device);
device->ptr_a11y_data->dwell_timer =
clutter_threads_add_timeout (delay, trigger_dwell_gesture, device);
device->ptr_a11y_data->dwell_gesture_started = TRUE;
g_signal_emit_by_name (seat,
g_signal_emit_by_name (device->seat,
"ptr-a11y-timeout-started",
device,
CLUTTER_A11Y_TIMEOUT_TYPE_GESTURE,
@ -479,11 +464,10 @@ static gboolean
trigger_dwell_click (gpointer data)
{
ClutterInputDevice *device = data;
ClutterSeat *seat = clutter_input_device_get_seat (device);
device->ptr_a11y_data->dwell_timer = 0;
g_signal_emit_by_name (seat,
g_signal_emit_by_name (device->seat,
"ptr-a11y-timeout-stopped",
device,
CLUTTER_A11Y_TIMEOUT_TYPE_DWELL,
@ -509,12 +493,11 @@ static void
start_dwell_timeout (ClutterInputDevice *device)
{
unsigned int delay = get_dwell_delay (device);
ClutterSeat *seat = clutter_input_device_get_seat (device);
device->ptr_a11y_data->dwell_timer =
clutter_threads_add_timeout (delay, trigger_dwell_click, device);
g_signal_emit_by_name (seat,
g_signal_emit_by_name (device->seat,
"ptr-a11y-timeout-started",
device,
CLUTTER_A11Y_TIMEOUT_TYPE_DWELL,
@ -524,14 +507,12 @@ start_dwell_timeout (ClutterInputDevice *device)
static void
stop_dwell_timeout (ClutterInputDevice *device)
{
ClutterSeat *seat = clutter_input_device_get_seat (device);
if (device->ptr_a11y_data->dwell_timer)
{
g_clear_handle_id (&device->ptr_a11y_data->dwell_timer, g_source_remove);
device->ptr_a11y_data->dwell_gesture_started = FALSE;
g_signal_emit_by_name (seat,
g_signal_emit_by_name (device->seat,
"ptr-a11y-timeout-stopped",
device,
CLUTTER_A11Y_TIMEOUT_TYPE_DWELL,
@ -589,9 +570,8 @@ static gboolean
is_device_core_pointer (ClutterInputDevice *device)
{
ClutterInputDevice *core_pointer;
ClutterSeat *seat = clutter_input_device_get_seat (device);
core_pointer = clutter_seat_get_pointer (seat);
core_pointer = clutter_seat_get_pointer (device->seat);
if (core_pointer == NULL)
return FALSE;
@ -601,13 +581,11 @@ is_device_core_pointer (ClutterInputDevice *device)
void
_clutter_input_pointer_a11y_add_device (ClutterInputDevice *device)
{
ClutterSeat *seat = clutter_input_device_get_seat (device);
if (!is_device_core_pointer (device))
return;
device->accessibility_virtual_device =
clutter_seat_create_virtual_device (seat,
clutter_seat_create_virtual_device (device->seat,
CLUTTER_POINTER_DEVICE);
device->ptr_a11y_data = g_new0 (ClutterPtrA11yData, 1);

View File

@ -1176,7 +1176,7 @@ clutter_interval_compute_value (ClutterInterval *interval,
* g_object_set_property()
*
* Return value: (transfer none): a pointer to the computed value,
* or %NULL if the computation was not successful
* or %NULL if the computation was not successfull
*
* Since: 1.4
*/

View File

@ -1,31 +0,0 @@
/*
* Copyright (C) 2021 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.
*
*/
#ifndef CLUTTER_KEYMAP_PRIVATE_H
#define CLUTTER_KEYMAP_PRIVATE_H
#include "clutter/clutter-keymap.h"
CLUTTER_EXPORT
void clutter_keymap_set_lock_modifier_state (ClutterKeymap *keymap,
gboolean caps_lock_state,
gboolean num_lock_state);
#endif /* CLUTTER_KEYMAP_PRIVATE_H */

View File

@ -21,29 +21,10 @@
#include "clutter-build-config.h"
#include "clutter-keymap-private.h"
#include "clutter-keymap.h"
#include "clutter-private.h"
enum
{
PROP_0,
PROP_CAPS_LOCK_STATE,
PROP_NUM_LOCK_STATE,
N_PROPS
};
static GParamSpec *obj_props[N_PROPS];
typedef struct _ClutterKeymapPrivate
{
gboolean caps_lock_state;
gboolean num_lock_state;
} ClutterKeymapPrivate;
G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (ClutterKeymap, clutter_keymap,
G_TYPE_OBJECT)
G_DEFINE_ABSTRACT_TYPE (ClutterKeymap, clutter_keymap, G_TYPE_OBJECT)
enum
{
@ -53,76 +34,9 @@ enum
static guint signals[N_SIGNALS] = { 0, };
static void
clutter_keymap_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
ClutterKeymap *keymap = CLUTTER_KEYMAP (object);
ClutterKeymapPrivate *priv = clutter_keymap_get_instance_private (keymap);
switch (prop_id)
{
case PROP_CAPS_LOCK_STATE:
g_value_set_boolean (value, priv->caps_lock_state);
break;
case PROP_NUM_LOCK_STATE:
g_value_set_boolean (value, priv->num_lock_state);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
clutter_keymap_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
ClutterKeymap *keymap = CLUTTER_KEYMAP (object);
ClutterKeymapPrivate *priv = clutter_keymap_get_instance_private (keymap);
switch (prop_id)
{
case PROP_CAPS_LOCK_STATE:
priv->caps_lock_state = g_value_get_boolean (value);
break;
case PROP_NUM_LOCK_STATE:
priv->num_lock_state = g_value_get_boolean (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
clutter_keymap_class_init (ClutterKeymapClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->get_property = clutter_keymap_get_property;
object_class->set_property = clutter_keymap_set_property;
obj_props[PROP_CAPS_LOCK_STATE] =
g_param_spec_boolean ("caps-lock-state",
"Caps lock state",
"Caps lock state",
FALSE,
G_PARAM_READABLE |
G_PARAM_STATIC_STRINGS);
obj_props[PROP_NUM_LOCK_STATE] =
g_param_spec_boolean ("num-lock-state",
"Num lock state",
"Num lock state",
FALSE,
G_PARAM_READABLE |
G_PARAM_STATIC_STRINGS);
g_object_class_install_properties (object_class, N_PROPS, obj_props);
signals[STATE_CHANGED] =
g_signal_new (I_("state-changed"),
G_TYPE_FROM_CLASS (klass),
@ -140,17 +54,13 @@ clutter_keymap_init (ClutterKeymap *keymap)
gboolean
clutter_keymap_get_num_lock_state (ClutterKeymap *keymap)
{
ClutterKeymapPrivate *priv = clutter_keymap_get_instance_private (keymap);
return priv->num_lock_state;
return CLUTTER_KEYMAP_GET_CLASS (keymap)->get_num_lock_state (keymap);
}
gboolean
clutter_keymap_get_caps_lock_state (ClutterKeymap *keymap)
{
ClutterKeymapPrivate *priv = clutter_keymap_get_instance_private (keymap);
return priv->caps_lock_state;
return CLUTTER_KEYMAP_GET_CLASS (keymap)->get_caps_lock_state (keymap);
}
PangoDirection
@ -158,35 +68,3 @@ clutter_keymap_get_direction (ClutterKeymap *keymap)
{
return CLUTTER_KEYMAP_GET_CLASS (keymap)->get_direction (keymap);
}
void
clutter_keymap_set_lock_modifier_state (ClutterKeymap *keymap,
gboolean caps_lock_state,
gboolean num_lock_state)
{
ClutterKeymapPrivate *priv = clutter_keymap_get_instance_private (keymap);
if (priv->caps_lock_state == caps_lock_state &&
priv->num_lock_state == num_lock_state)
return;
if (priv->caps_lock_state != caps_lock_state)
{
priv->caps_lock_state = caps_lock_state;
g_object_notify_by_pspec (G_OBJECT (keymap),
obj_props[PROP_CAPS_LOCK_STATE]);
}
if (priv->num_lock_state != num_lock_state)
{
priv->num_lock_state = num_lock_state;
g_object_notify_by_pspec (G_OBJECT (keymap),
obj_props[PROP_NUM_LOCK_STATE]);
}
g_debug ("Locks state changed - Num: %s, Caps: %s",
priv->num_lock_state ? "set" : "unset",
priv->caps_lock_state ? "set" : "unset");
g_signal_emit (keymap, signals[STATE_CHANGED], 0);
}

View File

@ -38,6 +38,8 @@ struct _ClutterKeymapClass
{
GObjectClass parent_class;
gboolean (* get_num_lock_state) (ClutterKeymap *keymap);
gboolean (* get_caps_lock_state) (ClutterKeymap *keymap);
PangoDirection (* get_direction) (ClutterKeymap *keymap);
};

View File

@ -1,7 +1,7 @@
#!/usr/bin/env perl
# Author : Simos Xenitellis <simos at gnome dot org>.
# Author : Bastien Nocera <hadess@hadess.net>
# Authos : Bastien Nocera <hadess@hadess.net>
# Version : 1.2
#
# Notes : It downloads keysymdef.h from the Internet, if not found locally,

View File

@ -41,7 +41,7 @@
* The implementation of a layout manager does not differ from the
* implementation of the size requisition and allocation bits of
* #ClutterActor, so you should read the relative documentation
* for subclassing #ClutterActor.
* forr subclassing #ClutterActor.
*
* The layout manager implementation can hold a back pointer to the
* #ClutterContainer by implementing the #ClutterLayoutManagerClass.set_container()

View File

@ -84,7 +84,7 @@ struct _ClutterLayoutManager
* in newly written code.
* @end_animation: virtual function; override to end an animation started
* by clutter_layout_manager_begin_animation(). This virtual function is
* deprecated, and it should not be overridden in newly written code.
* deprecated, and it should not be overriden in newly written code.
* @get_animation_progress: virtual function; override to control the
* progress of the animation of a #ClutterLayoutManager. This virtual
* function is deprecated, and it should not be overridden in newly written

View File

@ -53,6 +53,7 @@
#include "clutter-actor-private.h"
#include "clutter-backend-private.h"
#include "clutter-config.h"
#include "clutter-debug.h"
#include "clutter-event-private.h"
#include "clutter-feature.h"
@ -64,7 +65,6 @@
#include "clutter-paint-node-private.h"
#include "clutter-private.h"
#include "clutter-settings-private.h"
#include "clutter-stage.h"
#include "clutter-stage-manager.h"
#include "clutter-stage-private.h"
#include "clutter-backend-private.h"
@ -94,11 +94,6 @@ guint clutter_debug_flags = 0;
guint clutter_paint_debug_flags = 0;
guint clutter_pick_debug_flags = 0;
/* A constant added to heuristic max render time to account for variations
* in the estimates.
*/
int clutter_max_render_time_constant_us = 2000;
#ifdef CLUTTER_ENABLE_DEBUG
static const GDebugKey clutter_debug_keys[] = {
{ "misc", CLUTTER_DEBUG_MISC },
@ -116,8 +111,6 @@ static const GDebugKey clutter_debug_keys[] = {
{ "layout", CLUTTER_DEBUG_LAYOUT },
{ "clipping", CLUTTER_DEBUG_CLIPPING },
{ "oob-transforms", CLUTTER_DEBUG_OOB_TRANSFORMS },
{ "frame-timings", CLUTTER_DEBUG_FRAME_TIMINGS },
{ "detailed-trace", CLUTTER_DEBUG_DETAILED_TRACE },
};
#endif /* CLUTTER_ENABLE_DEBUG */
@ -135,10 +128,201 @@ static const GDebugKey clutter_paint_debug_keys[] = {
{ "continuous-redraw", CLUTTER_DEBUG_CONTINUOUS_REDRAW },
{ "paint-deform-tiles", CLUTTER_DEBUG_PAINT_DEFORM_TILES },
{ "damage-region", CLUTTER_DEBUG_PAINT_DAMAGE_REGION },
{ "disable-dynamic-max-render-time", CLUTTER_DEBUG_DISABLE_DYNAMIC_MAX_RENDER_TIME },
{ "max-render-time", CLUTTER_DEBUG_PAINT_MAX_RENDER_TIME },
};
#define ENVIRONMENT_GROUP "Environment"
#define DEBUG_GROUP "Debug"
static void
clutter_config_read_from_key_file (GKeyFile *keyfile)
{
GError *key_error = NULL;
gboolean bool_value;
gint int_value;
gchar *str_value;
if (!g_key_file_has_group (keyfile, ENVIRONMENT_GROUP))
return;
str_value =
g_key_file_get_string (keyfile, ENVIRONMENT_GROUP,
"Drivers",
&key_error);
if (key_error != NULL)
g_clear_error (&key_error);
else
clutter_set_allowed_drivers (str_value);
g_free (str_value);
bool_value =
g_key_file_get_boolean (keyfile, ENVIRONMENT_GROUP,
"ShowFps",
&key_error);
if (key_error != NULL)
g_clear_error (&key_error);
else
clutter_show_fps = bool_value;
bool_value =
g_key_file_get_boolean (keyfile, ENVIRONMENT_GROUP,
"DisableMipmappedText",
&key_error);
if (key_error != NULL)
g_clear_error (&key_error);
else
clutter_disable_mipmap_text = bool_value;
bool_value =
g_key_file_get_boolean (keyfile, ENVIRONMENT_GROUP,
"EnableAccessibility",
&key_error);
if (key_error != NULL)
g_clear_error (&key_error);
else
clutter_enable_accessibility = bool_value;
int_value =
g_key_file_get_integer (keyfile, ENVIRONMENT_GROUP,
"DefaultFps",
&key_error);
if (key_error != NULL)
g_clear_error (&key_error);
else
clutter_default_fps = int_value;
str_value =
g_key_file_get_string (keyfile, ENVIRONMENT_GROUP,
"TextDirection",
&key_error);
if (key_error != NULL)
g_clear_error (&key_error);
else
{
if (g_strcmp0 (str_value, "rtl") == 0)
clutter_text_direction = CLUTTER_TEXT_DIRECTION_RTL;
else
clutter_text_direction = CLUTTER_TEXT_DIRECTION_LTR;
}
g_free (str_value);
}
#ifdef CLUTTER_ENABLE_DEBUG
static void
clutter_debug_read_from_key_file (GKeyFile *keyfile)
{
GError *key_error = NULL;
gchar *value;
if (!g_key_file_has_group (keyfile, DEBUG_GROUP))
return;
value = g_key_file_get_value (keyfile, DEBUG_GROUP,
"Debug",
&key_error);
if (key_error == NULL)
{
clutter_debug_flags |=
g_parse_debug_string (value,
clutter_debug_keys,
G_N_ELEMENTS (clutter_debug_keys));
}
else
g_clear_error (&key_error);
g_free (value);
value = g_key_file_get_value (keyfile, DEBUG_GROUP,
"PaintDebug",
&key_error);
if (key_error == NULL)
{
clutter_paint_debug_flags |=
g_parse_debug_string (value,
clutter_paint_debug_keys,
G_N_ELEMENTS (clutter_paint_debug_keys));
}
else
g_clear_error (&key_error);
g_free (value);
value = g_key_file_get_value (keyfile, DEBUG_GROUP,
"PickDebug",
&key_error);
if (key_error == NULL)
{
clutter_pick_debug_flags |=
g_parse_debug_string (value,
clutter_pick_debug_keys,
G_N_ELEMENTS (clutter_pick_debug_keys));
}
else
g_clear_error (&key_error);
g_free (value);
}
#endif
static void
clutter_config_read_from_file (const gchar *config_path)
{
ClutterSettings *settings = clutter_settings_get_default ();
GKeyFile *key_file = g_key_file_new ();
GError *error = NULL;
g_key_file_load_from_file (key_file, config_path, G_KEY_FILE_NONE, &error);
if (error == NULL)
{
CLUTTER_NOTE (MISC, "Reading configuration from '%s'", config_path);
clutter_config_read_from_key_file (key_file);
#ifdef CLUTTER_ENABLE_DEBUG
clutter_debug_read_from_key_file (key_file);
#endif
_clutter_settings_read_from_key_file (settings, key_file);
}
else
{
g_warning ("Unable to read configuration settings from '%s': %s",
config_path,
error->message);
g_error_free (error);
}
g_key_file_free (key_file);
}
static void
clutter_config_read (void)
{
gchar *config_path;
config_path = g_build_filename (CLUTTER_SYSCONFDIR,
"clutter-1.0",
"settings.ini",
NULL);
if (g_file_test (config_path, G_FILE_TEST_EXISTS))
clutter_config_read_from_file (config_path);
g_free (config_path);
config_path = g_build_filename (g_get_user_config_dir (),
"clutter-1.0",
"settings.ini",
NULL);
if (g_file_test (config_path, G_FILE_TEST_EXISTS))
clutter_config_read_from_file (config_path);
g_free (config_path);
}
gboolean
_clutter_context_get_show_fps (void)
{
@ -271,7 +455,7 @@ _clutter_threads_dispatch_free (gpointer data)
if (dispatch->notify)
dispatch->notify (dispatch->data);
g_free (dispatch);
g_slice_free (ClutterThreadsDispatch, dispatch);
}
/**
@ -371,7 +555,7 @@ clutter_threads_add_idle_full (gint priority,
g_return_val_if_fail (func != NULL, 0);
dispatch = g_new0 (ClutterThreadsDispatch, 1);
dispatch = g_slice_new (ClutterThreadsDispatch);
dispatch->func = func;
dispatch->data = data;
dispatch->notify = notify;
@ -442,7 +626,7 @@ clutter_threads_add_timeout_full (gint priority,
g_return_val_if_fail (func != NULL, 0);
dispatch = g_new0 (ClutterThreadsDispatch, 1);
dispatch = g_slice_new (ClutterThreadsDispatch);
dispatch->func = func;
dispatch->data = data;
dispatch->notify = notify;
@ -494,6 +678,12 @@ _clutter_context_get_default (void)
{
ClutterMainContext *ctx;
/* Read the configuration file, if any, before we set up the
* whole thing, so that we can override things like the backend
* and the driver
*/
clutter_config_read ();
ClutterCntx = ctx = g_new0 (ClutterMainContext, 1);
ctx->is_initialized = FALSE;
@ -616,6 +806,9 @@ clutter_init_real (GError **error)
clutter_text_direction = clutter_get_text_direction ();
/* Initiate event collection */
_clutter_backend_init_events (ctx->backend);
clutter_is_initialized = TRUE;
ctx->is_initialized = TRUE;
@ -863,6 +1056,99 @@ clutter_get_option_group_without_init (void)
* allow the common case of argc=NULL, argv=NULL to work.
*/
/**
* clutter_init_with_args:
* @argc: (inout): a pointer to the number of command line arguments
* @argv: (array length=argc) (inout) (allow-none): a pointer to the array
* of command line arguments
* @parameter_string: (allow-none): a string which is displayed in the
* first line of <option>--help</option> output, after
* <literal><replaceable>programname</replaceable> [OPTION...]</literal>
* @entries: (array) (allow-none): a %NULL terminated array of
* #GOptionEntry<!-- -->s describing the options of your program
* @translation_domain: (allow-none): a translation domain to use for
* translating the <option>--help</option> output for the options in
* @entries with gettext(), or %NULL
* @error: (allow-none): a return location for a #GError
*
* This function does the same work as clutter_init(). Additionally,
* it allows you to add your own command line options, and it
* automatically generates nicely formatted <option>--help</option>
* output. Note that your program will be terminated after writing
* out the help output. Also note that, in case of error, the
* error message will be placed inside @error instead of being
* printed on the display.
*
* Just like clutter_init(), if this function returns an error code then
* any subsequent call to any other Clutter API will result in undefined
* behaviour - including segmentation faults.
*
* Return value: %CLUTTER_INIT_SUCCESS if Clutter has been successfully
* initialised, or other values or #ClutterInitError in case of
* error.
*
* Since: 0.2
*/
ClutterInitError
clutter_init_with_args (int *argc,
char ***argv,
const char *parameter_string,
GOptionEntry *entries,
const char *translation_domain,
GError **error)
{
GOptionContext *context;
GOptionGroup *group;
gboolean res;
ClutterMainContext *ctx;
if (clutter_is_initialized)
return CLUTTER_INIT_SUCCESS;
clutter_base_init ();
ctx = _clutter_context_get_default ();
if (!ctx->defer_display_setup)
{
#if 0
if (argc && *argc > 0 && *argv)
g_set_prgname ((*argv)[0]);
#endif
context = g_option_context_new (parameter_string);
group = clutter_get_option_group ();
g_option_context_add_group (context, group);
group = cogl_get_option_group ();
g_option_context_add_group (context, group);
if (entries)
g_option_context_add_main_entries (context, entries, translation_domain);
res = g_option_context_parse (context, argc, argv, error);
g_option_context_free (context);
/* if res is FALSE, the error is filled for
* us by g_option_context_parse()
*/
if (!res)
{
/* if there has been an error in the initialization, the
* error id will be preserved inside the GError code
*/
if (error && *error)
return (*error)->code;
else
return CLUTTER_INIT_ERROR_INTERNAL;
}
return CLUTTER_INIT_SUCCESS;
}
else
return clutter_init_real (error);
}
static gboolean
clutter_parse_args (int *argc,
@ -914,7 +1200,9 @@ clutter_parse_args (int *argc,
* This function will not abort in case of errors during
* initialization; clutter_init() will print out the error message on
* stderr, and will return an error code. It is up to the application
* code to handle this case.
* code to handle this case. If you need to display the error message
* yourself, you can use clutter_init_with_args(), which takes a #GError
* pointer.
*
* If this function fails, and returns an error code, any subsequent
* Clutter API will have undefined behaviour - including segmentation
@ -1033,9 +1321,9 @@ event_click_count_generate (ClutterEvent *event)
previous_button_number = device->previous_button_number;
CLUTTER_NOTE (EVENT,
"Restoring previous click count:%d (device:%s, time:%u)",
"Restoring previous click count:%d (device:%d, time:%u)",
click_count,
clutter_input_device_get_device_name (device),
clutter_input_device_get_device_id (device),
previous_time);
}
else
@ -1089,9 +1377,9 @@ event_click_count_generate (ClutterEvent *event)
if (event->type == CLUTTER_BUTTON_PRESS && device != NULL)
{
CLUTTER_NOTE (EVENT, "Storing click count: %d (device:%s, time:%u)",
CLUTTER_NOTE (EVENT, "Storing click count: %d (device:%d, time:%u)",
click_count,
clutter_input_device_get_device_name (device),
clutter_input_device_get_device_id (device),
previous_time);
device->click_count = click_count;
@ -1105,13 +1393,26 @@ event_click_count_generate (ClutterEvent *event)
static inline void
emit_event_chain (ClutterEvent *event)
{
static gboolean lock = FALSE;
if (event->any.source == NULL)
{
CLUTTER_NOTE (EVENT, "No source set, discarding event");
return;
}
/* reentrancy check */
if (lock != FALSE)
{
g_warning ("Tried emitting event during event delivery, bailing out.");
return;
}
lock = TRUE;
_clutter_actor_handle_event (event->any.source, event);
lock = FALSE;
}
/*
@ -1187,8 +1488,8 @@ emit_touch_event (ClutterEvent *event,
}
static inline void
process_key_event (ClutterEvent *event,
ClutterInputDevice *device)
emit_keyboard_event (ClutterEvent *event,
ClutterInputDevice *device)
{
if (_clutter_event_process_filters (event))
return;
@ -1199,6 +1500,21 @@ process_key_event (ClutterEvent *event,
emit_event_chain (event);
}
static inline void
process_key_event (ClutterEvent *event,
ClutterInputDevice *device)
{
ClutterInputDeviceClass *device_class = CLUTTER_INPUT_DEVICE_GET_CLASS (device);
if (device_class->process_kbd_a11y_event)
{
device_class->process_kbd_a11y_event (event, device, emit_keyboard_event);
return;
}
emit_keyboard_event (event, device);
}
static gboolean
is_off_stage (ClutterActor *stage,
gfloat x,
@ -1252,168 +1568,6 @@ clutter_do_event (ClutterEvent *event)
_clutter_stage_queue_event (event->any.stage, event, TRUE);
}
static void
create_crossing_event (ClutterStage *stage,
ClutterInputDevice *device,
ClutterEventSequence *sequence,
ClutterEventType event_type,
ClutterActor *source,
ClutterActor *related,
graphene_point_t coords,
uint32_t time)
{
ClutterEvent *event;
event = clutter_event_new (event_type);
event->crossing.time = time;
event->crossing.flags = 0;
event->crossing.stage = stage;
event->crossing.source = source;
event->crossing.x = coords.x;
event->crossing.y = coords.y;
event->crossing.related = related;
event->crossing.sequence = sequence;
clutter_event_set_device (event, device);
/* we need to make sure that this event is processed
* before any other event we might have queued up until
* now, so we go on, and synthesize the event emission
* ourselves
*/
_clutter_process_event (event);
clutter_event_free (event);
}
void
clutter_stage_update_device (ClutterStage *stage,
ClutterInputDevice *device,
ClutterEventSequence *sequence,
graphene_point_t point,
uint32_t time,
ClutterActor *new_actor,
gboolean emit_crossing)
{
ClutterInputDeviceType device_type;
ClutterActor *old_actor;
gboolean device_actor_changed;
device_type = clutter_input_device_get_device_type (device);
g_assert (device_type != CLUTTER_KEYBOARD_DEVICE &&
device_type != CLUTTER_PAD_DEVICE);
old_actor = clutter_stage_get_device_actor (stage, device, sequence);
device_actor_changed = new_actor != old_actor;
clutter_stage_update_device_entry (stage,
device, sequence,
point,
new_actor);
if (device_actor_changed)
{
CLUTTER_NOTE (EVENT,
"Updating actor under cursor (device %s, at %.2f, %.2f): %s",
clutter_input_device_get_device_name (device),
point.x,
point.y,
_clutter_actor_get_debug_name (new_actor));
if (old_actor && emit_crossing)
{
create_crossing_event (stage,
device, sequence,
CLUTTER_LEAVE,
old_actor, new_actor,
point, time);
}
if (new_actor && emit_crossing)
{
create_crossing_event (stage,
device, sequence,
CLUTTER_ENTER,
new_actor, old_actor,
point, time);
}
}
}
void
clutter_stage_repick_device (ClutterStage *stage,
ClutterInputDevice *device)
{
graphene_point_t point;
ClutterActor *new_actor;
clutter_stage_get_device_coords (stage, device, NULL, &point);
new_actor =
clutter_stage_get_actor_at_pos (stage, CLUTTER_PICK_REACTIVE,
point.x, point.y);
clutter_stage_update_device (stage,
device, NULL,
point,
CLUTTER_CURRENT_TIME,
new_actor,
TRUE);
}
static ClutterActor *
update_device_for_event (ClutterStage *stage,
ClutterEvent *event,
gboolean emit_crossing)
{
ClutterInputDevice *device = clutter_event_get_device (event);
ClutterEventSequence *sequence = clutter_event_get_event_sequence (event);
ClutterActor *new_actor;
graphene_point_t point;
uint32_t time;
clutter_event_get_coords (event, &point.x, &point.y);
time = clutter_event_get_time (event);
new_actor =
_clutter_stage_do_pick (stage, point.x, point.y, CLUTTER_PICK_REACTIVE);
/* Picking should never fail, but if it does, we bail out here */
g_return_val_if_fail (new_actor != NULL, NULL);
clutter_stage_update_device (stage,
device, sequence,
point,
time,
new_actor,
emit_crossing);
return new_actor;
}
static void
remove_device_for_event (ClutterStage *stage,
ClutterEvent *event,
gboolean emit_crossing)
{
ClutterInputDevice *device = clutter_event_get_device (event);
ClutterEventSequence *sequence = clutter_event_get_event_sequence (event);
graphene_point_t point;
uint32_t time;
clutter_event_get_coords (event, &point.x, &point.y);
time = clutter_event_get_time (event);
clutter_stage_update_device (stage,
device, sequence,
point,
time,
NULL,
TRUE);
clutter_stage_remove_device_entry (stage, device, sequence);
}
static void
_clutter_process_event_details (ClutterActor *stage,
ClutterMainContext *context,
@ -1438,9 +1592,6 @@ _clutter_process_event_details (ClutterActor *stage,
case CLUTTER_PAD_BUTTON_RELEASE:
case CLUTTER_PAD_STRIP:
case CLUTTER_PAD_RING:
case CLUTTER_IM_COMMIT:
case CLUTTER_IM_DELETE:
case CLUTTER_IM_PREEDIT:
{
ClutterActor *actor = NULL;
@ -1472,7 +1623,9 @@ _clutter_process_event_details (ClutterActor *stage,
emit_crossing_event (event, device);
actor = update_device_for_event (CLUTTER_STAGE (stage), event, FALSE);
actor = clutter_input_device_update (device, NULL,
CLUTTER_STAGE (stage), FALSE,
event);
if (actor != stage)
{
ClutterEvent *crossing;
@ -1498,14 +1651,13 @@ _clutter_process_event_details (ClutterActor *stage,
*/
if (event->any.source == stage &&
event->crossing.related == NULL &&
clutter_stage_get_device_actor (CLUTTER_STAGE (stage), device, NULL) != stage)
device->cursor_actor != stage)
{
ClutterEvent *crossing;
crossing = clutter_event_copy (event);
crossing->crossing.related = stage;
crossing->crossing.source =
clutter_stage_get_device_actor (CLUTTER_STAGE (stage), device, NULL);
crossing->crossing.source = device->cursor_actor;
emit_crossing_event (crossing, device);
clutter_event_free (crossing);
@ -1513,6 +1665,16 @@ _clutter_process_event_details (ClutterActor *stage,
emit_crossing_event (event, device);
break;
case CLUTTER_DESTROY_NOTIFY:
event->any.source = stage;
if (_clutter_event_process_filters (event))
break;
/* the stage did not handle the event, so we just quit */
clutter_stage_event (CLUTTER_STAGE (stage), event);
break;
case CLUTTER_MOTION:
if (clutter_backend_is_display_server (backend) &&
!(event->any.flags & CLUTTER_EVENT_FLAG_SYNTHETIC))
@ -1568,6 +1730,7 @@ _clutter_process_event_details (ClutterActor *stage,
case CLUTTER_TOUCHPAD_PINCH:
case CLUTTER_TOUCHPAD_SWIPE:
{
ClutterActor *actor;
gfloat x, y;
clutter_event_get_coords (event, &x, &y);
@ -1611,32 +1774,24 @@ _clutter_process_event_details (ClutterActor *stage,
break;
}
/* We need to repick on both motion and button press events, the
* latter is only needed for X11 (there the device actor might be
* stale because we don't always receive motion events).
*/
if (event->type == CLUTTER_BUTTON_PRESS ||
event->type == CLUTTER_MOTION)
{
event->any.source =
update_device_for_event (CLUTTER_STAGE (stage), event, TRUE);
}
else
{
event->any.source =
clutter_stage_get_device_actor (CLUTTER_STAGE (stage),
device,
NULL);
}
if (event->any.source == NULL)
actor = clutter_input_device_update (device, NULL,
CLUTTER_STAGE (stage),
TRUE, event);
if (actor == NULL)
break;
event->any.source = actor;
}
else
{
/* use the source already set in the synthetic event */
actor = event->any.source;
}
CLUTTER_NOTE (EVENT,
"Reactive event received at %.2f, %.2f - actor: %p",
x, y,
event->any.source);
actor);
/* button presses and releases need a click count */
if (event->type == CLUTTER_BUTTON_PRESS ||
@ -1690,8 +1845,13 @@ _clutter_process_event_details (ClutterActor *stage,
case CLUTTER_TOUCH_CANCEL:
case CLUTTER_TOUCH_END:
{
ClutterActor *actor;
ClutterEventSequence *sequence;
gfloat x, y;
sequence =
clutter_event_get_event_sequence (event);
clutter_event_get_coords (event, &x, &y);
/* Only do a pick to find the source if source is not already set
@ -1716,45 +1876,44 @@ _clutter_process_event_details (ClutterActor *stage,
if (event->type == CLUTTER_TOUCH_END ||
event->type == CLUTTER_TOUCH_CANCEL)
remove_device_for_event (CLUTTER_STAGE (stage), event, TRUE);
_clutter_input_device_remove_event_sequence (device, event);
break;
}
if (event->type == CLUTTER_TOUCH_BEGIN ||
event->type == CLUTTER_TOUCH_UPDATE)
{
event->any.source =
update_device_for_event (CLUTTER_STAGE (stage), event, TRUE);
}
else
{
event->any.source =
clutter_stage_get_device_actor (CLUTTER_STAGE (stage),
device,
event->touch.sequence);
}
if (event->any.source == NULL)
actor = clutter_input_device_update (device, sequence,
CLUTTER_STAGE (stage),
TRUE, event);
if (actor == NULL)
break;
event->any.source = actor;
}
else
{
/* use the source already set in the synthetic event */
actor = event->any.source;
}
CLUTTER_NOTE (EVENT,
"Reactive event received at %.2f, %.2f - actor: %p",
x, y,
event->any.source);
actor);
emit_touch_event (event, device);
if (event->type == CLUTTER_TOUCH_END ||
event->type == CLUTTER_TOUCH_CANCEL)
remove_device_for_event (CLUTTER_STAGE (stage), event, TRUE);
_clutter_input_device_remove_event_sequence (device, event);
break;
}
case CLUTTER_PROXIMITY_IN:
case CLUTTER_PROXIMITY_OUT:
clutter_input_device_update_from_tool (clutter_event_get_source_device (event),
clutter_event_get_device_tool (event));
if (_clutter_event_process_filters (event))
break;
@ -1766,26 +1925,20 @@ _clutter_process_event_details (ClutterActor *stage,
break;
case CLUTTER_DEVICE_ADDED:
_clutter_event_process_filters (event);
case CLUTTER_STAGE_STATE:
/* focus - forward to stage */
event->any.source = stage;
if (!_clutter_event_process_filters (event))
clutter_stage_event (CLUTTER_STAGE (stage), event);
break;
case CLUTTER_CLIENT_MESSAGE:
break;
case CLUTTER_DEVICE_ADDED:
case CLUTTER_DEVICE_REMOVED:
{
ClutterInputDeviceType device_type;
_clutter_event_process_filters (event);
device_type = clutter_input_device_get_device_type (device);
if (device_type == CLUTTER_POINTER_DEVICE ||
device_type == CLUTTER_TABLET_DEVICE ||
device_type == CLUTTER_PEN_DEVICE ||
device_type == CLUTTER_ERASER_DEVICE ||
device_type == CLUTTER_CURSOR_DEVICE)
remove_device_for_event (CLUTTER_STAGE (stage), event, TRUE);
break;
}
_clutter_event_process_filters (event);
break;
case CLUTTER_EVENT_LAST:
break;
@ -1804,10 +1957,8 @@ _clutter_process_event (ClutterEvent *event)
{
ClutterMainContext *context;
ClutterActor *stage;
ClutterSeat *seat;
context = _clutter_context_get_default ();
seat = clutter_backend_get_default_seat (context->backend);
stage = CLUTTER_ACTOR (event->any.stage);
if (stage == NULL)
@ -1822,7 +1973,6 @@ _clutter_process_event (ClutterEvent *event)
*/
context->current_event = g_slist_prepend (context->current_event, event);
clutter_seat_handle_event_post (seat, event);
_clutter_process_event_details (stage, context, event);
context->current_event = g_slist_delete_link (context->current_event, context->current_event);
@ -1925,7 +2075,7 @@ clutter_threads_remove_repaint_func (guint handle_id)
if (repaint_func->notify)
repaint_func->notify (repaint_func->data);
g_free (repaint_func);
g_slice_free (ClutterRepaintFunction, repaint_func);
break;
}
@ -2032,7 +2182,7 @@ clutter_threads_add_repaint_func_full (ClutterRepaintFlags flags,
context = _clutter_context_get_default ();
repaint_func = g_new0 (ClutterRepaintFunction, 1);
repaint_func = g_slice_new (ClutterRepaintFunction);
repaint_func->id = context->last_repaint_id++;
@ -2096,7 +2246,7 @@ _clutter_run_repaint_functions (ClutterRepaintFlags flags)
if (repaint_func->notify != NULL)
repaint_func->notify (repaint_func->data);
g_free (repaint_func);
g_slice_free (ClutterRepaintFunction, repaint_func);
}
}
@ -2139,21 +2289,23 @@ _clutter_clear_events_queue (void)
{
ClutterMainContext *context = _clutter_context_get_default ();
ClutterEvent *event;
GAsyncQueue *events_queue;
if (!context->events_queue)
return;
/* Lock the queue for as long as it lives */
g_async_queue_lock (context->events_queue);
while ((event = g_async_queue_try_pop_unlocked (context->events_queue)))
clutter_event_free (event);
events_queue = context->events_queue;
g_async_queue_unref (context->events_queue);
context->events_queue = NULL;
}
g_async_queue_unlock (events_queue);
g_async_queue_unref (events_queue);
ClutterPickMode
_clutter_context_get_pick_mode (void)
{
ClutterMainContext *context = _clutter_context_get_default ();
return context->pick_mode;
}
/**
@ -2186,25 +2338,6 @@ clutter_remove_debug_flags (ClutterDebugFlag debug_flags,
clutter_pick_debug_flags &= ~pick_flags;
}
void
clutter_debug_set_max_render_time_constant (int max_render_time_constant_us)
{
clutter_max_render_time_constant_us = max_render_time_constant_us;
}
void
clutter_get_debug_flags (ClutterDebugFlag *debug_flags,
ClutterDrawDebugFlag *draw_flags,
ClutterPickDebugFlag *pick_flags)
{
if (debug_flags)
*debug_flags = clutter_debug_flags;
if (draw_flags)
*draw_flags = clutter_paint_debug_flags;
if (pick_flags)
*pick_flags = clutter_pick_debug_flags;
}
void
_clutter_set_sync_to_vblank (gboolean sync_to_vblank)
{

View File

@ -53,8 +53,6 @@ typedef enum
CLUTTER_DEBUG_EVENTLOOP = 1 << 14,
CLUTTER_DEBUG_CLIPPING = 1 << 15,
CLUTTER_DEBUG_OOB_TRANSFORMS = 1 << 16,
CLUTTER_DEBUG_FRAME_TIMINGS = 1 << 17,
CLUTTER_DEBUG_DETAILED_TRACE = 1 << 18,
} ClutterDebugFlag;
typedef enum
@ -64,17 +62,15 @@ typedef enum
typedef enum
{
CLUTTER_DEBUG_DISABLE_SWAP_EVENTS = 1 << 0,
CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS = 1 << 1,
CLUTTER_DEBUG_REDRAWS = 1 << 2,
CLUTTER_DEBUG_PAINT_VOLUMES = 1 << 3,
CLUTTER_DEBUG_DISABLE_CULLING = 1 << 4,
CLUTTER_DEBUG_DISABLE_OFFSCREEN_REDIRECT = 1 << 5,
CLUTTER_DEBUG_CONTINUOUS_REDRAW = 1 << 6,
CLUTTER_DEBUG_PAINT_DEFORM_TILES = 1 << 7,
CLUTTER_DEBUG_PAINT_DAMAGE_REGION = 1 << 8,
CLUTTER_DEBUG_DISABLE_DYNAMIC_MAX_RENDER_TIME = 1 << 9,
CLUTTER_DEBUG_PAINT_MAX_RENDER_TIME = 1 << 10,
CLUTTER_DEBUG_DISABLE_SWAP_EVENTS = 1 << 0,
CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS = 1 << 1,
CLUTTER_DEBUG_REDRAWS = 1 << 2,
CLUTTER_DEBUG_PAINT_VOLUMES = 1 << 3,
CLUTTER_DEBUG_DISABLE_CULLING = 1 << 4,
CLUTTER_DEBUG_DISABLE_OFFSCREEN_REDIRECT = 1 << 5,
CLUTTER_DEBUG_CONTINUOUS_REDRAW = 1 << 6,
CLUTTER_DEBUG_PAINT_DEFORM_TILES = 1 << 7,
CLUTTER_DEBUG_PAINT_DAMAGE_REGION = 1 << 8,
} ClutterDrawDebugFlag;
/**
@ -92,7 +88,7 @@ typedef enum
* @CLUTTER_INIT_ERROR_BACKEND: Backend initialisation failed
* @CLUTTER_INIT_ERROR_INTERNAL: Internal error
*
* Error conditions returned by clutter_init().
* Error conditions returned by clutter_init() and clutter_init_with_args().
*
* Since: 0.2
*/
@ -127,6 +123,13 @@ void clutter_base_init (void);
CLUTTER_EXPORT
ClutterInitError clutter_init (int *argc,
char ***argv) G_GNUC_WARN_UNUSED_RESULT;
CLUTTER_EXPORT
ClutterInitError clutter_init_with_args (int *argc,
char ***argv,
const char *parameter_string,
GOptionEntry *entries,
const char *translation_domain,
GError **error) G_GNUC_WARN_UNUSED_RESULT;
CLUTTER_EXPORT
GOptionGroup * clutter_get_option_group (void);
@ -193,9 +196,6 @@ void clutter_remove_debug_flags (ClutterDebugFla
ClutterDrawDebugFlag draw_flags,
ClutterPickDebugFlag pick_flags);
CLUTTER_EXPORT
void clutter_debug_set_max_render_time_constant (int max_render_time_constant_us);
G_END_DECLS
#endif /* _CLUTTER_MAIN_H__ */

View File

@ -26,8 +26,6 @@
#define __CLUTTER_H_INSIDE__
#include "clutter-backend.h"
#include "clutter-backend-private.h"
#include "clutter-damage-history.h"
#include "clutter-event-private.h"
#include "clutter-input-device-private.h"
#include "clutter-input-pointer-a11y-private.h"
@ -35,8 +33,8 @@
#include "clutter-private.h"
#include "clutter-stage-private.h"
#include "clutter-stage-view.h"
#include "clutter-stage-view-private.h"
#include "clutter.h"
#include "cogl/clutter-stage-cogl.h"
#include "clutter/x11/clutter-backend-x11.h"
CLUTTER_EXPORT
GList * clutter_stage_peek_stage_views (ClutterStage *stage);
@ -52,11 +50,10 @@ CLUTTER_EXPORT
int64_t clutter_stage_get_frame_counter (ClutterStage *stage);
CLUTTER_EXPORT
void clutter_stage_capture_view_into (ClutterStage *stage,
ClutterStageView *view,
cairo_rectangle_int_t *rect,
uint8_t *data,
int stride);
void clutter_stage_capture_into (ClutterStage *stage,
gboolean paint,
cairo_rectangle_int_t *rect,
uint8_t *data);
CLUTTER_EXPORT
void clutter_stage_clear_stage_views (ClutterStage *stage);
@ -78,29 +75,6 @@ CLUTTER_EXPORT
gboolean clutter_seat_handle_event_post (ClutterSeat *seat,
const ClutterEvent *event);
CLUTTER_EXPORT
void clutter_stage_update_device (ClutterStage *stage,
ClutterInputDevice *device,
ClutterEventSequence *sequence,
graphene_point_t point,
uint32_t time,
ClutterActor *new_actor,
gboolean emit_crossing);
CLUTTER_EXPORT
void clutter_stage_get_device_coords (ClutterStage *stage,
ClutterInputDevice *device,
ClutterEventSequence *sequence,
graphene_point_t *coords);
CLUTTER_EXPORT
void clutter_stage_repick_device (ClutterStage *stage,
ClutterInputDevice *device);
CLUTTER_EXPORT
void clutter_get_debug_flags (ClutterDebugFlag *debug_flags,
ClutterDrawDebugFlag *draw_flags,
ClutterPickDebugFlag *pick_flags);
#undef __CLUTTER_H_INSIDE__
#endif /* __CLUTTER_MUTTER_H__ */

View File

@ -60,30 +60,6 @@
* #ClutterOffscreenEffectClass.create_texture() virtual function; no chain up
* to the #ClutterOffscreenEffect implementation is required in this
* case.
*
* ## Paint nodes
*
* #ClutterOffscreenEffect generates the following paint node tree:
*
* |[<!-- language="plain" -->
* Effect
*
* Layer Pipeline
*
* Actor
* ]|
*
* When the actor contents are cached, the generated paint node tree
* looks like this:
*
* |[<!-- language="plain" -->
* Effect
*
* Pipeline
* ]|
*
* In both cases, the "Pipeline" node is created with the return value
* of #ClutterOffscreenEffectClass.create_pipeline().
*/
#include "clutter-build-config.h"
@ -99,20 +75,20 @@
#include "clutter-private.h"
#include "clutter-stage-private.h"
#include "clutter-paint-context-private.h"
#include "clutter-paint-node-private.h"
#include "clutter-paint-nodes.h"
#include "clutter-paint-volume-private.h"
#include "clutter-actor-box-private.h"
struct _ClutterOffscreenEffectPrivate
{
CoglOffscreen *offscreen;
CoglHandle offscreen;
CoglPipeline *pipeline;
CoglHandle texture;
ClutterActor *actor;
ClutterActor *stage;
graphene_point3d_t position;
int fbo_offset_x;
int fbo_offset_y;
@ -123,6 +99,8 @@ struct _ClutterOffscreenEffectPrivate
int target_width;
int target_height;
gint old_opacity_override;
gulong purge_handler_id;
};
@ -142,7 +120,7 @@ clutter_offscreen_effect_set_actor (ClutterActorMeta *meta,
meta_class->set_actor (meta, actor);
/* clear out the previous state */
g_clear_object (&priv->offscreen);
g_clear_pointer (&priv->offscreen, cogl_object_unref);
/* we keep a back pointer here, to avoid going through the ActorMeta */
priv->actor = clutter_actor_meta_get_actor (meta);
@ -182,29 +160,10 @@ ensure_pipeline_filter_for_scale (ClutterOffscreenEffect *self,
filter, filter);
}
static CoglPipeline *
clutter_offscreen_effect_real_create_pipeline (ClutterOffscreenEffect *effect,
CoglTexture *texture)
{
ClutterOffscreenEffectPrivate *priv = effect->priv;
CoglContext *ctx =
clutter_backend_get_cogl_context (clutter_get_default_backend ());
CoglPipeline *pipeline;
float resource_scale;
resource_scale = clutter_actor_get_real_resource_scale (priv->actor);
pipeline = cogl_pipeline_new (ctx);
ensure_pipeline_filter_for_scale (effect, resource_scale);
cogl_pipeline_set_layer_texture (pipeline, 0, texture);
return pipeline;
}
static void
video_memory_purged (ClutterOffscreenEffect *self)
{
g_clear_object (&self->priv->offscreen);
g_clear_pointer (&self->priv->offscreen, cogl_object_unref);
}
static gboolean
@ -214,12 +173,8 @@ update_fbo (ClutterEffect *effect,
float resource_scale)
{
ClutterOffscreenEffect *self = CLUTTER_OFFSCREEN_EFFECT (effect);
ClutterOffscreenEffectClass *offscreen_class =
CLUTTER_OFFSCREEN_EFFECT_GET_CLASS (self);
ClutterOffscreenEffectPrivate *priv = self->priv;
ClutterActor *stage_actor;
CoglOffscreen *offscreen;
g_autoptr (GError) error = NULL;
stage_actor = clutter_actor_get_stage (priv->actor);
if (stage_actor != priv->stage)
@ -256,25 +211,35 @@ update_fbo (ClutterEffect *effect,
return TRUE;
}
if (priv->pipeline == NULL)
{
CoglContext *ctx =
clutter_backend_get_cogl_context (clutter_get_default_backend ());
priv->pipeline = cogl_pipeline_new (ctx);
ensure_pipeline_filter_for_scale (self, resource_scale);
}
g_clear_pointer (&priv->texture, cogl_object_unref);
g_clear_object (&priv->offscreen);
g_clear_pointer (&priv->offscreen, cogl_object_unref);
priv->texture =
clutter_offscreen_effect_create_texture (self, target_width, target_height);
if (priv->texture == NULL)
return FALSE;
cogl_pipeline_set_layer_texture (priv->pipeline, 0, priv->texture);
priv->target_width = target_width;
priv->target_height = target_height;
offscreen = cogl_offscreen_new_with_texture (priv->texture);
if (!cogl_framebuffer_allocate (COGL_FRAMEBUFFER (offscreen), &error))
priv->offscreen = cogl_offscreen_new_to_texture (priv->texture);
if (priv->offscreen == NULL)
{
g_warning ("Failed to create offscreen effect framebuffer: %s",
error->message);
g_warning ("%s: Unable to create an Offscreen buffer", G_STRLOC);
g_object_unref (offscreen);
cogl_clear_object (&priv->pipeline);
cogl_object_unref (priv->pipeline);
priv->pipeline = NULL;
priv->target_width = 0;
priv->target_height = 0;
@ -282,36 +247,35 @@ update_fbo (ClutterEffect *effect,
return FALSE;
}
priv->offscreen = offscreen;
cogl_clear_object (&priv->pipeline);
priv->pipeline = offscreen_class->create_pipeline (self, priv->texture);
return TRUE;
}
static gboolean
clutter_offscreen_effect_pre_paint (ClutterEffect *effect,
ClutterPaintNode *node,
ClutterPaintContext *paint_context)
{
ClutterOffscreenEffect *self = CLUTTER_OFFSCREEN_EFFECT (effect);
ClutterOffscreenEffectPrivate *priv = self->priv;
CoglFramebuffer *offscreen;
ClutterActorBox raw_box, box;
ClutterActor *stage;
graphene_matrix_t projection, modelview, transform;
CoglMatrix projection, old_modelview, modelview;
const ClutterPaintVolume *volume;
CoglColor transparent;
gfloat stage_width, stage_height;
gfloat target_width = -1, target_height = -1;
CoglFramebuffer *framebuffer;
float resource_scale;
float ceiled_resource_scale;
graphene_point3d_t local_offset;
gfloat old_viewport[4];
local_offset = GRAPHENE_POINT3D_INIT (0.0f, 0.0f, 0.0f);
if (!clutter_actor_meta_get_enabled (CLUTTER_ACTOR_META (effect)))
goto disable_effect;
return FALSE;
if (priv->actor == NULL)
goto disable_effect;
return FALSE;
stage = _clutter_actor_get_stage_internal (priv->actor);
clutter_actor_get_size (stage, &stage_width, &stage_height);
@ -336,24 +300,18 @@ clutter_offscreen_effect_pre_paint (ClutterEffect *effect,
_clutter_paint_volume_copy_static (volume, &mutable_volume);
_clutter_paint_volume_get_bounding_box (&mutable_volume, &raw_box);
clutter_paint_volume_free (&mutable_volume);
box = raw_box;
_clutter_actor_box_enlarge_for_effects (&box);
priv->fbo_offset_x = box.x1;
priv->fbo_offset_y = box.y1;
}
else
{
clutter_actor_get_allocation_box (priv->actor, &raw_box);
box = raw_box;
_clutter_actor_box_enlarge_for_effects (&box);
priv->fbo_offset_x = box.x1 - raw_box.x1;
priv->fbo_offset_y = box.y1 - raw_box.y1;
}
box = raw_box;
_clutter_actor_box_enlarge_for_effects (&box);
priv->fbo_offset_x = box.x1 - raw_box.x1;
priv->fbo_offset_y = box.y1 - raw_box.y1;
clutter_actor_box_scale (&box, ceiled_resource_scale);
clutter_actor_box_get_size (&box, &target_width, &target_height);
@ -362,9 +320,12 @@ clutter_offscreen_effect_pre_paint (ClutterEffect *effect,
/* First assert that the framebuffer is the right size... */
if (!update_fbo (effect, target_width, target_height, resource_scale))
goto disable_effect;
return FALSE;
offscreen = COGL_FRAMEBUFFER (priv->offscreen);
framebuffer = clutter_paint_context_get_framebuffer (paint_context);
cogl_framebuffer_get_modelview_matrix (framebuffer, &old_modelview);
clutter_paint_context_push_framebuffer (paint_context, priv->offscreen);
/* We don't want the FBO contents to be transformed. That could waste memory
* (e.g. during zoom), or result in something that's not rectangular (clipped
@ -374,46 +335,67 @@ clutter_offscreen_effect_pre_paint (ClutterEffect *effect,
* contents on screen...
*/
clutter_actor_get_transform (priv->stage, &modelview);
graphene_matrix_init_translate (&transform,
&GRAPHENE_POINT3D_INIT (-priv->fbo_offset_x,
-priv->fbo_offset_y,
0.0));
graphene_matrix_scale (&transform,
stage_width / target_width,
stage_height / target_height,
1.0);
graphene_matrix_multiply (&transform, &modelview, &modelview);
cogl_framebuffer_set_modelview_matrix (offscreen, &modelview);
cogl_framebuffer_set_modelview_matrix (priv->offscreen, &modelview);
/* Set up the viewport so that it has the minimal size required to render any
* pixel in the FBO without clipping.
/* Save the original viewport for calculating priv->position */
_clutter_stage_get_viewport (CLUTTER_STAGE (priv->stage),
&old_viewport[0],
&old_viewport[1],
&old_viewport[2],
&old_viewport[3]);
/* Set up the viewport so that it has the same size as the stage (avoid
* distortion), but translated to account for the FBO offset...
*/
cogl_framebuffer_set_viewport (offscreen,
0,
0,
target_width,
target_height);
cogl_framebuffer_set_viewport (priv->offscreen,
-priv->fbo_offset_x,
-priv->fbo_offset_y,
stage_width,
stage_height);
/* Copy the stage's projection matrix across to the offscreen */
/* Copy the stage's projection matrix across to the framebuffer */
_clutter_stage_get_projection_matrix (CLUTTER_STAGE (priv->stage),
&projection);
cogl_framebuffer_set_projection_matrix (offscreen, &projection);
/* Now save the global position of the effect (not just of the actor).
* It doesn't appear anyone actually uses this yet, but get_target_rect is
* documented as returning it. So we should...
*/
_clutter_util_fully_transform_vertices (&old_modelview,
&projection,
old_viewport,
&local_offset,
&priv->position,
1);
cogl_framebuffer_set_projection_matrix (priv->offscreen, &projection);
cogl_color_init_from_4ub (&transparent, 0, 0, 0, 0);
cogl_framebuffer_clear (priv->offscreen,
COGL_BUFFER_BIT_COLOR |
COGL_BUFFER_BIT_DEPTH,
&transparent);
cogl_framebuffer_push_matrix (priv->offscreen);
/* Override the actor's opacity to fully opaque - we paint the offscreen
* texture with the actor's paint opacity, so we need to do this to avoid
* multiplying the opacity twice.
*/
priv->old_opacity_override =
clutter_actor_get_opacity_override (priv->actor);
clutter_actor_set_opacity_override (priv->actor, 0xff);
return TRUE;
disable_effect:
g_clear_object (&priv->offscreen);
return FALSE;
}
static void
clutter_offscreen_effect_real_paint_target (ClutterOffscreenEffect *effect,
ClutterPaintNode *node,
ClutterPaintContext *paint_context)
{
ClutterOffscreenEffectPrivate *priv = effect->priv;
ClutterPaintNode *pipeline_node;
CoglFramebuffer *framebuffer =
clutter_paint_context_get_framebuffer (paint_context);
guint8 paint_opacity;
paint_opacity = clutter_actor_get_paint_opacity (priv->actor);
@ -424,125 +406,97 @@ clutter_offscreen_effect_real_paint_target (ClutterOffscreenEffect *effect,
paint_opacity,
paint_opacity);
pipeline_node = clutter_pipeline_node_new (priv->pipeline);
clutter_paint_node_set_static_name (pipeline_node,
"ClutterOffscreenEffect (pipeline)");
clutter_paint_node_add_child (node, pipeline_node);
/* At this point we are in stage coordinates translated so if
* we draw our texture using a textured quad the size of the paint
* box then we will overlay where the actor would have drawn if it
* hadn't been redirected offscreen.
*/
clutter_paint_node_add_rectangle (pipeline_node,
&(ClutterActorBox) {
0.f, 0.f,
cogl_texture_get_width (priv->texture),
cogl_texture_get_height (priv->texture),
});
clutter_paint_node_unref (pipeline_node);
cogl_framebuffer_draw_textured_rectangle (framebuffer,
priv->pipeline,
0, 0,
cogl_texture_get_width (priv->texture),
cogl_texture_get_height (priv->texture),
0.0, 0.0,
1.0, 1.0);
}
static void
clutter_offscreen_effect_paint_texture (ClutterOffscreenEffect *effect,
ClutterPaintNode *node,
ClutterPaintContext *paint_context)
{
ClutterOffscreenEffectPrivate *priv = effect->priv;
graphene_matrix_t transform;
float unscale;
CoglFramebuffer *framebuffer =
clutter_paint_context_get_framebuffer (paint_context);
CoglMatrix modelview;
float resource_scale;
unscale = 1.0 / clutter_actor_get_resource_scale (priv->actor);
graphene_matrix_init_scale (&transform, unscale, unscale, 1.0);
graphene_matrix_translate (&transform,
&GRAPHENE_POINT3D_INIT (priv->fbo_offset_x,
priv->fbo_offset_y,
0.0));
cogl_framebuffer_push_matrix (framebuffer);
if (!graphene_matrix_is_identity (&transform))
/* The current modelview matrix is *almost* perfect already. It's only
* missing a correction for the expanded FBO and offset rendering within...
*/
cogl_framebuffer_get_modelview_matrix (framebuffer, &modelview);
resource_scale = clutter_actor_get_resource_scale (priv->actor);
if (resource_scale != 1.0f)
{
ClutterPaintNode *transform_node;
transform_node = clutter_transform_node_new (&transform);
clutter_paint_node_set_static_name (transform_node,
"ClutterOffscreenEffect (transform)");
clutter_paint_node_add_child (node, transform_node);
clutter_paint_node_unref (transform_node);
node = transform_node;
float paint_scale = 1.0f / resource_scale;
cogl_matrix_scale (&modelview, paint_scale, paint_scale, 1);
}
cogl_matrix_translate (&modelview,
priv->fbo_offset_x,
priv->fbo_offset_y,
0.0f);
cogl_framebuffer_set_modelview_matrix (framebuffer, &modelview);
/* paint the target material; this is virtualized for
* sub-classes that require special hand-holding
*/
clutter_offscreen_effect_paint_target (effect, node, paint_context);
clutter_offscreen_effect_paint_target (effect, paint_context);
cogl_framebuffer_pop_matrix (framebuffer);
}
static void
clutter_offscreen_effect_post_paint (ClutterEffect *effect,
ClutterPaintNode *node,
ClutterPaintContext *paint_context)
{
ClutterOffscreenEffect *self = CLUTTER_OFFSCREEN_EFFECT (effect);
ClutterOffscreenEffectPrivate *priv = self->priv;
CoglFramebuffer *framebuffer;
g_warn_if_fail (priv->offscreen);
g_warn_if_fail (priv->pipeline);
g_warn_if_fail (priv->actor);
clutter_offscreen_effect_paint_texture (self, node, paint_context);
}
/* Restore the previous opacity override */
if (priv->actor)
{
clutter_actor_set_opacity_override (priv->actor,
priv->old_opacity_override);
}
static void
add_actor_node (ClutterOffscreenEffect *offscreen_effect,
ClutterPaintNode *node,
int paint_opacity)
{
ClutterOffscreenEffectPrivate *priv = offscreen_effect->priv;
ClutterPaintNode *actor_node;
framebuffer = clutter_paint_context_get_framebuffer (paint_context);
cogl_framebuffer_pop_matrix (framebuffer);
clutter_paint_context_pop_framebuffer (paint_context);
actor_node = clutter_actor_node_new (priv->actor, paint_opacity);
clutter_paint_node_add_child (node, actor_node);
clutter_paint_node_unref (actor_node);
}
static void
clutter_offscreen_effect_paint_node (ClutterEffect *effect,
ClutterPaintNode *node,
ClutterPaintContext *paint_context,
ClutterEffectPaintFlags flags)
{
ClutterOffscreenEffect *offscreen_effect = CLUTTER_OFFSCREEN_EFFECT (effect);
ClutterOffscreenEffectPrivate *priv = offscreen_effect->priv;
ClutterPaintNode *layer_node;
CoglFramebuffer *fb;
fb = COGL_FRAMEBUFFER (priv->offscreen);
layer_node = clutter_layer_node_new_to_framebuffer (fb, priv->pipeline);
clutter_paint_node_set_static_name (layer_node,
"ClutterOffscreenEffect (actor offscreen)");
clutter_paint_node_add_child (node, layer_node);
clutter_paint_node_unref (layer_node);
add_actor_node (offscreen_effect, layer_node, 255);
clutter_offscreen_effect_paint_texture (self, paint_context);
}
static void
clutter_offscreen_effect_paint (ClutterEffect *effect,
ClutterPaintNode *node,
ClutterPaintContext *paint_context,
ClutterEffectPaintFlags flags)
{
ClutterOffscreenEffect *self = CLUTTER_OFFSCREEN_EFFECT (effect);
ClutterOffscreenEffectPrivate *priv = self->priv;
ClutterEffectClass *parent_class =
CLUTTER_EFFECT_CLASS (clutter_offscreen_effect_parent_class);
if (flags & CLUTTER_EFFECT_PAINT_BYPASS_EFFECT)
{
add_actor_node (self, node, -1);
g_clear_object (&priv->offscreen);
clutter_actor_continue_paint (priv->actor, paint_context);
cogl_clear_object (&priv->offscreen);
return;
}
@ -550,9 +504,21 @@ clutter_offscreen_effect_paint (ClutterEffect *effect,
* then we can just use the cached image in the FBO.
*/
if (priv->offscreen == NULL || (flags & CLUTTER_EFFECT_PAINT_ACTOR_DIRTY))
parent_class->paint (effect, node, paint_context, flags);
{
ClutterEffectClass *effect_class = CLUTTER_EFFECT_GET_CLASS (effect);
gboolean pre_paint_succeeded;
pre_paint_succeeded = effect_class->pre_paint (effect, paint_context);
clutter_actor_continue_paint (priv->actor, paint_context);
if (pre_paint_succeeded)
effect_class->post_paint (effect, paint_context);
else
g_clear_pointer (&priv->offscreen, cogl_object_unref);
}
else
clutter_offscreen_effect_paint_texture (self, node, paint_context);
clutter_offscreen_effect_paint_texture (self, paint_context);
}
static void
@ -564,7 +530,7 @@ clutter_offscreen_effect_set_enabled (ClutterActorMeta *meta,
ClutterOffscreenEffect *offscreen_effect = CLUTTER_OFFSCREEN_EFFECT (meta);
ClutterOffscreenEffectPrivate *priv = offscreen_effect->priv;
g_clear_object (&priv->offscreen);
g_clear_pointer (&priv->offscreen, cogl_object_unref);
parent_class->set_enabled (meta, is_enabled);
}
@ -575,7 +541,7 @@ clutter_offscreen_effect_finalize (GObject *gobject)
ClutterOffscreenEffect *self = CLUTTER_OFFSCREEN_EFFECT (gobject);
ClutterOffscreenEffectPrivate *priv = self->priv;
g_clear_object (&priv->offscreen);
g_clear_pointer (&priv->offscreen, cogl_object_unref);
g_clear_pointer (&priv->texture, cogl_object_unref);
g_clear_pointer (&priv->pipeline, cogl_object_unref);
@ -590,7 +556,6 @@ clutter_offscreen_effect_class_init (ClutterOffscreenEffectClass *klass)
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
klass->create_texture = clutter_offscreen_effect_real_create_texture;
klass->create_pipeline = clutter_offscreen_effect_real_create_pipeline;
klass->paint_target = clutter_offscreen_effect_real_paint_target;
meta_class->set_actor = clutter_offscreen_effect_set_actor;
@ -599,7 +564,6 @@ clutter_offscreen_effect_class_init (ClutterOffscreenEffectClass *klass)
effect_class->pre_paint = clutter_offscreen_effect_pre_paint;
effect_class->post_paint = clutter_offscreen_effect_post_paint;
effect_class->paint = clutter_offscreen_effect_paint;
effect_class->paint_node = clutter_offscreen_effect_paint_node;
gobject_class->finalize = clutter_offscreen_effect_finalize;
}
@ -640,34 +604,33 @@ clutter_offscreen_effect_get_texture (ClutterOffscreenEffect *effect)
}
/**
* clutter_offscreen_effect_get_pipeline:
* clutter_offscreen_effect_get_target: (skip)
* @effect: a #ClutterOffscreenEffect
*
* Retrieves the pipeline used as a render target for the offscreen
* Retrieves the material used as a render target for the offscreen
* buffer created by @effect
*
* You should only use the returned #CoglPipeline when painting. The
* returned pipeline might change between different frames.
* You should only use the returned #CoglMaterial when painting. The
* returned material might change between different frames.
*
* Return value: (transfer none)(nullable): a #CoglPipeline. The
* pipeline is owned by Clutter and it should not be modified
* or freed
* Return value: (transfer none): a #CoglMaterial or %NULL. The
* returned material is owned by Clutter and it should not be
* modified or freed
*
* Since: 1.4
*/
CoglPipeline *
clutter_offscreen_effect_get_pipeline (ClutterOffscreenEffect *effect)
CoglMaterial *
clutter_offscreen_effect_get_target (ClutterOffscreenEffect *effect)
{
g_return_val_if_fail (CLUTTER_IS_OFFSCREEN_EFFECT (effect),
NULL);
return effect->priv->pipeline;
return (CoglMaterial *)effect->priv->pipeline;
}
/**
* clutter_offscreen_effect_paint_target:
* @effect: a #ClutterOffscreenEffect
* @node: a #ClutterPaintNode
* @paint_context: a #ClutterPaintContext
*
* Calls the paint_target() virtual function of the @effect
@ -676,13 +639,11 @@ clutter_offscreen_effect_get_pipeline (ClutterOffscreenEffect *effect)
*/
void
clutter_offscreen_effect_paint_target (ClutterOffscreenEffect *effect,
ClutterPaintNode *node,
ClutterPaintContext *paint_context)
{
g_return_if_fail (CLUTTER_IS_OFFSCREEN_EFFECT (effect));
CLUTTER_OFFSCREEN_EFFECT_GET_CLASS (effect)->paint_target (effect,
node,
paint_context);
}
@ -730,6 +691,8 @@ clutter_offscreen_effect_create_texture (ClutterOffscreenEffect *effect,
* and %FALSE otherwise
*
* Since: 1.8
*
* Deprecated: 1.14: Use clutter_offscreen_effect_get_target_rect() instead
*/
gboolean
clutter_offscreen_effect_get_target_size (ClutterOffscreenEffect *effect,
@ -753,3 +716,43 @@ clutter_offscreen_effect_get_target_size (ClutterOffscreenEffect *effect,
return TRUE;
}
/**
* clutter_offscreen_effect_get_target_rect:
* @effect: a #ClutterOffscreenEffect
* @rect: (out caller-allocates): return location for the target area
*
* Retrieves the origin and size of the offscreen buffer used by @effect to
* paint the actor to which it has been applied.
*
* This function should only be called by #ClutterOffscreenEffect
* implementations, from within the #ClutterOffscreenEffectClass.paint_target()
* virtual function.
*
* Return value: %TRUE if the offscreen buffer has a valid rectangle,
* and %FALSE otherwise
*
* Since: 1.14
*/
gboolean
clutter_offscreen_effect_get_target_rect (ClutterOffscreenEffect *effect,
graphene_rect_t *rect)
{
ClutterOffscreenEffectPrivate *priv;
g_return_val_if_fail (CLUTTER_IS_OFFSCREEN_EFFECT (effect), FALSE);
g_return_val_if_fail (rect != NULL, FALSE);
priv = effect->priv;
if (priv->texture == NULL)
return FALSE;
graphene_rect_init (rect,
priv->position.x,
priv->position.y,
cogl_texture_get_width (priv->texture),
cogl_texture_get_height (priv->texture));
return TRUE;
}

View File

@ -79,10 +79,7 @@ struct _ClutterOffscreenEffectClass
CoglHandle (* create_texture) (ClutterOffscreenEffect *effect,
gfloat width,
gfloat height);
CoglPipeline* (* create_pipeline) (ClutterOffscreenEffect *effect,
CoglTexture *texture);
void (* paint_target) (ClutterOffscreenEffect *effect,
ClutterPaintNode *node,
ClutterPaintContext *paint_context);
/*< private >*/
@ -99,25 +96,28 @@ CLUTTER_EXPORT
GType clutter_offscreen_effect_get_type (void) G_GNUC_CONST;
CLUTTER_EXPORT
CoglPipeline * clutter_offscreen_effect_get_pipeline (ClutterOffscreenEffect *effect);
CoglMaterial * clutter_offscreen_effect_get_target (ClutterOffscreenEffect *effect);
CLUTTER_EXPORT
CoglHandle clutter_offscreen_effect_get_texture (ClutterOffscreenEffect *effect);
CLUTTER_EXPORT
void clutter_offscreen_effect_paint_target (ClutterOffscreenEffect *effect,
ClutterPaintNode *node,
ClutterPaintContext *paint_context);
CLUTTER_EXPORT
CoglHandle clutter_offscreen_effect_create_texture (ClutterOffscreenEffect *effect,
gfloat width,
gfloat height);
CLUTTER_EXPORT
CLUTTER_DEPRECATED_FOR (clutter_offscreen_effect_get_target_rect)
gboolean clutter_offscreen_effect_get_target_size (ClutterOffscreenEffect *effect,
gfloat *width,
gfloat *height);
CLUTTER_EXPORT
gboolean clutter_offscreen_effect_get_target_rect (ClutterOffscreenEffect *effect,
graphene_rect_t *rect);
G_END_DECLS
#endif /* __CLUTTER_OFFSCREEN_EFFECT_H__ */

View File

@ -20,17 +20,12 @@
#include "clutter-paint-context.h"
ClutterPaintContext *
clutter_paint_context_new_for_view (ClutterStageView *view,
const cairo_region_t *redraw_clip,
GArray *clip_frusta,
ClutterPaintFlag paint_flags);
ClutterPaintContext * clutter_paint_context_new_for_view (ClutterStageView *view,
const cairo_region_t *redraw_clip,
ClutterPaintFlag paint_flags);
gboolean clutter_paint_context_is_drawing_off_stage (ClutterPaintContext *paint_context);
CoglFramebuffer * clutter_paint_context_get_base_framebuffer (ClutterPaintContext *paint_context);
const GArray *
clutter_paint_context_get_clip_frusta (ClutterPaintContext *paint_context);
#endif /* CLUTTER_PAINT_CONTEXT_PRIVATE_H */

View File

@ -30,7 +30,6 @@ struct _ClutterPaintContext
ClutterStageView *view;
cairo_region_t *redraw_clip;
GArray *clip_frusta;
};
G_DEFINE_BOXED_TYPE (ClutterPaintContext, clutter_paint_context,
@ -40,7 +39,6 @@ G_DEFINE_BOXED_TYPE (ClutterPaintContext, clutter_paint_context,
ClutterPaintContext *
clutter_paint_context_new_for_view (ClutterStageView *view,
const cairo_region_t *redraw_clip,
GArray *clip_frusta,
ClutterPaintFlag paint_flags)
{
ClutterPaintContext *paint_context;
@ -50,7 +48,6 @@ clutter_paint_context_new_for_view (ClutterStageView *view,
g_ref_count_init (&paint_context->ref_count);
paint_context->view = view;
paint_context->redraw_clip = cairo_region_copy (redraw_clip);
paint_context->clip_frusta = g_array_ref (clip_frusta);
paint_context->paint_flags = paint_flags;
framebuffer = clutter_stage_view_get_framebuffer (view);
@ -89,10 +86,10 @@ clutter_paint_context_ref (ClutterPaintContext *paint_context)
static void
clutter_paint_context_dispose (ClutterPaintContext *paint_context)
{
g_list_free_full (paint_context->framebuffers, g_object_unref);
g_list_free_full (paint_context->framebuffers,
cogl_object_unref);
paint_context->framebuffers = NULL;
g_clear_pointer (&paint_context->redraw_clip, cairo_region_destroy);
g_clear_pointer (&paint_context->clip_frusta, g_array_unref);
}
void
@ -117,7 +114,7 @@ clutter_paint_context_push_framebuffer (ClutterPaintContext *paint_context,
CoglFramebuffer *framebuffer)
{
paint_context->framebuffers = g_list_prepend (paint_context->framebuffers,
g_object_ref (framebuffer));
cogl_object_ref (framebuffer));
}
void
@ -125,7 +122,7 @@ clutter_paint_context_pop_framebuffer (ClutterPaintContext *paint_context)
{
g_return_if_fail (paint_context->framebuffers);
g_object_unref (paint_context->framebuffers->data);
cogl_object_unref (paint_context->framebuffers->data);
paint_context->framebuffers =
g_list_delete_link (paint_context->framebuffers,
paint_context->framebuffers);
@ -137,12 +134,6 @@ clutter_paint_context_get_redraw_clip (ClutterPaintContext *paint_context)
return paint_context->redraw_clip;
}
const GArray *
clutter_paint_context_get_clip_frusta (ClutterPaintContext *paint_context)
{
return paint_context->clip_frusta;
}
/**
* clutter_paint_context_get_framebuffer:
* @paint_context: The #ClutterPaintContext

View File

@ -34,7 +34,6 @@ typedef enum _ClutterPaintFlag
CLUTTER_PAINT_FLAG_NONE = 0,
CLUTTER_PAINT_FLAG_NO_CURSORS = 1 << 0,
CLUTTER_PAINT_FLAG_FORCE_CURSORS = 1 << 1,
CLUTTER_PAINT_FLAG_CLEAR = 1 << 2,
} ClutterPaintFlag;
#define CLUTTER_TYPE_PAINT_CONTEXT (clutter_paint_context_get_type ())

View File

@ -82,7 +82,6 @@ typedef enum
{
PAINT_OP_INVALID = 0,
PAINT_OP_TEX_RECT,
PAINT_OP_TEX_RECTS,
PAINT_OP_MULTITEX_RECT,
PAINT_OP_PRIMITIVE
} PaintOpCode;
@ -91,7 +90,7 @@ struct _ClutterPaintOperation
{
PaintOpCode opcode;
GArray *coords;
GArray *multitex_coords;
union {
float texrect[8];
@ -112,7 +111,7 @@ void _clutter_paint_operation_paint_primitive (const C
void _clutter_paint_node_init_types (void);
gpointer _clutter_paint_node_create (GType gtype);
ClutterPaintNode * _clutter_transform_node_new (const graphene_matrix_t *matrix);
ClutterPaintNode * _clutter_transform_node_new (const CoglMatrix *matrix);
ClutterPaintNode * _clutter_dummy_node_new (ClutterActor *actor,
CoglFramebuffer *framebuffer);
@ -142,26 +141,6 @@ ClutterPaintNode * clutter_paint_node_get_last_child (Clutter
G_GNUC_INTERNAL
ClutterPaintNode * clutter_paint_node_get_parent (ClutterPaintNode *node);
#define CLUTTER_TYPE_EFFECT_NODE (clutter_effect_node_get_type ())
#define CLUTTER_EFFECT_NODE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_EFFECT_NODE, ClutterEffectNode))
#define CLUTTER_IS_EFFECT_NODE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_EFFECT_NODE))
/**
* ClutterEffectNode:
*
* The #ClutterEffectNode structure is an opaque
* type whose members cannot be directly accessed.
*/
typedef struct _ClutterEffectNode ClutterEffectNode;
typedef struct _ClutterEffectNode ClutterEffectNodeClass;
CLUTTER_EXPORT
GType clutter_effect_node_get_type (void) G_GNUC_CONST;
CLUTTER_EXPORT
ClutterPaintNode * clutter_effect_node_new (ClutterEffect *effect);
G_END_DECLS
#endif /* __CLUTTER_PAINT_NODE_PRIVATE_H__ */

View File

@ -60,6 +60,8 @@
#include "clutter-build-config.h"
#define CLUTTER_ENABLE_EXPERIMENTAL_API
#include <pango/pango.h>
#include <cogl/cogl.h>
#include <json-glib/json-glib.h>
@ -234,9 +236,9 @@ clutter_paint_node_init (ClutterPaintNode *self)
GType
clutter_paint_node_get_type (void)
{
static size_t paint_node_type_id = 0;
static volatile gsize paint_node_type_id__volatile = 0;
if (g_once_init_enter (&paint_node_type_id))
if (g_once_init_enter (&paint_node_type_id__volatile))
{
static const GTypeFundamentalInfo finfo = {
(G_TYPE_FLAG_CLASSED |
@ -272,16 +274,16 @@ clutter_paint_node_get_type (void)
&value_table,
};
GType id =
GType paint_node_type_id =
g_type_register_fundamental (g_type_fundamental_next (),
I_("ClutterPaintNode"),
&node_info, &finfo,
G_TYPE_FLAG_ABSTRACT);
g_once_init_leave (&paint_node_type_id, id);
g_once_init_leave (&paint_node_type_id__volatile, paint_node_type_id);
}
return paint_node_type_id;
return paint_node_type_id__volatile;
}
/**
@ -775,9 +777,9 @@ clutter_paint_operation_clear (ClutterPaintOperation *op)
case PAINT_OP_TEX_RECT:
break;
case PAINT_OP_TEX_RECTS:
case PAINT_OP_MULTITEX_RECT:
g_clear_pointer (&op->coords, g_array_unref);
if (op->multitex_coords != NULL)
g_array_unref (op->multitex_coords);
break;
case PAINT_OP_PRIMITIVE:
@ -808,36 +810,6 @@ clutter_paint_op_init_tex_rect (ClutterPaintOperation *op,
op->op.texrect[7] = y_2;
}
static inline void
clutter_paint_op_init_tex_rects (ClutterPaintOperation *op,
const float *coords,
unsigned int n_rects,
gboolean use_default_tex_coords)
{
const unsigned int n_floats = n_rects * 8;
clutter_paint_operation_clear (op);
op->opcode = PAINT_OP_TEX_RECTS;
op->coords = g_array_sized_new (FALSE, FALSE, sizeof (float), n_floats);
if (use_default_tex_coords)
{
const float default_tex_coords[4] = { 0.0, 0.0, 1.0, 1.0 };
int i;
for (i = 0; i < n_rects; i++)
{
g_array_append_vals (op->coords, &coords[i * 4], 4);
g_array_append_vals (op->coords, default_tex_coords, 4);
}
}
else
{
g_array_append_vals (op->coords, coords, n_floats);
}
}
static inline void
clutter_paint_op_init_multitex_rect (ClutterPaintOperation *op,
const ClutterActorBox *rect,
@ -847,11 +819,11 @@ clutter_paint_op_init_multitex_rect (ClutterPaintOperation *op,
clutter_paint_operation_clear (op);
op->opcode = PAINT_OP_MULTITEX_RECT;
op->coords = g_array_sized_new (FALSE, FALSE,
sizeof (float),
tex_coords_len);
op->multitex_coords = g_array_sized_new (FALSE, FALSE,
sizeof (float),
tex_coords_len);
g_array_append_vals (op->coords, tex_coords, tex_coords_len);
g_array_append_vals (op->multitex_coords, tex_coords, tex_coords_len);
op->op.texrect[0] = rect->x1;
op->op.texrect[1] = rect->y1;
@ -963,74 +935,6 @@ clutter_paint_node_add_multitexture_rectangle (ClutterPaintNode *node,
g_array_append_val (node->operations, operation);
}
/**
* clutter_paint_node_add_rectangles:
* @node: a #ClutterPaintNode
* @coords: (in) (array length=n_rects) (transfer none): array of
* coordinates containing groups of 4 float values: [x_1, y_1, x_2, y_2] that
* are interpreted as two position coordinates; one for the top left of the
* rectangle (x1, y1), and one for the bottom right of the rectangle
* (x2, y2).
* @n_rects: number of rectangles defined in @coords.
*
* Adds a series of rectangles to @node.
*
* As a general rule for better performance its recommended to use this API
* instead of calling clutter_paint_node_add_rectangle() separately for
* multiple rectangles if all of the rectangles will be drawn together.
*
* See cogl_framebuffer_draw_rectangles().
*/
void
clutter_paint_node_add_rectangles (ClutterPaintNode *node,
const float *coords,
unsigned int n_rects)
{
ClutterPaintOperation operation = PAINT_OP_INIT;
g_return_if_fail (CLUTTER_IS_PAINT_NODE (node));
g_return_if_fail (coords != NULL);
clutter_paint_node_maybe_init_operations (node);
clutter_paint_op_init_tex_rects (&operation, coords, n_rects, TRUE);
g_array_append_val (node->operations, operation);
}
/**
* clutter_paint_node_add_texture_rectangles:
* @node: a #ClutterPaintNode
* @coords: (in) (array length=n_rects) (transfer none): array containing
* groups of 8 float values: [x_1, y_1, x_2, y_2, s_1, t_1, s_2, t_2]
* that have the same meaning as the arguments for
* cogl_framebuffer_draw_textured_rectangle().
* @n_rects: number of rectangles defined in @coords.
*
* Adds a series of rectangles to @node.
*
* The given texture coordinates should always be normalized such that
* (0, 0) corresponds to the top left and (1, 1) corresponds to the
* bottom right. To map an entire texture across the rectangle pass
* in s_1=0, t_1=0, s_2=1, t_2=1.
*
* See cogl_framebuffer_draw_textured_rectangles().
*/
void
clutter_paint_node_add_texture_rectangles (ClutterPaintNode *node,
const float *coords,
unsigned int n_rects)
{
ClutterPaintOperation operation = PAINT_OP_INIT;
g_return_if_fail (CLUTTER_IS_PAINT_NODE (node));
g_return_if_fail (coords != NULL);
clutter_paint_node_maybe_init_operations (node);
clutter_paint_op_init_tex_rects (&operation, coords, n_rects, FALSE);
g_array_append_val (node->operations, operation);
}
/**
* clutter_paint_node_add_primitive: (skip)
* @node: a #ClutterPaintNode
@ -1154,26 +1058,13 @@ clutter_paint_node_to_json (ClutterPaintNode *node)
json_builder_end_array (builder);
break;
case PAINT_OP_TEX_RECTS:
json_builder_set_member_name (builder, "texrects");
json_builder_begin_array (builder);
for (j = 0; i < op->coords->len; j++)
{
float coord = g_array_index (op->coords, float, j);
json_builder_add_double_value (builder, coord);
}
json_builder_end_array (builder);
break;
case PAINT_OP_MULTITEX_RECT:
json_builder_set_member_name (builder, "texrect");
json_builder_begin_array (builder);
for (j = 0; i < op->coords->len; j++)
for (j = 0; i < op->multitex_coords->len; j++)
{
float coord = g_array_index (op->coords, float, j);
float coord = g_array_index (op->multitex_coords, float, j);
json_builder_add_double_value (builder, coord);
}
@ -1258,14 +1149,24 @@ _clutter_paint_node_create (GType gtype)
return (gpointer) g_type_create_instance (gtype);
}
static ClutterPaintNode *
clutter_paint_node_get_root (ClutterPaintNode *node)
{
ClutterPaintNode *iter;
iter = node;
while (iter != NULL && iter->parent != NULL)
iter = iter->parent;
return iter;
}
/**
* clutter_paint_node_get_framebuffer:
* @node: a #ClutterPaintNode
*
* Retrieves the #CoglFramebuffer that @node will draw
* into. If @node doesn't specify a custom framebuffer,
* the first ancestor with a custom framebuffer will be
* used.
* into, if it the root node has a custom framebuffer set.
*
* Returns: (transfer none): a #CoglFramebuffer or %NULL if no custom one is
* set.
@ -1273,17 +1174,12 @@ _clutter_paint_node_create (GType gtype)
CoglFramebuffer *
clutter_paint_node_get_framebuffer (ClutterPaintNode *node)
{
ClutterPaintNode *root = clutter_paint_node_get_root (node);
ClutterPaintNodeClass *klass;
while (node)
{
klass = CLUTTER_PAINT_NODE_GET_CLASS (node);
if (klass->get_framebuffer != NULL)
return klass->get_framebuffer (node);
node = node->parent;
}
return NULL;
klass = CLUTTER_PAINT_NODE_GET_CLASS (root);
if (klass->get_framebuffer != NULL)
return klass->get_framebuffer (root);
else
return NULL;
}

View File

@ -83,15 +83,6 @@ void clutter_paint_node_add_multitexture_rectangle (ClutterP
const float *text_coords,
unsigned int text_coords_len);
CLUTTER_EXPORT
void clutter_paint_node_add_rectangles (ClutterPaintNode *node,
const float *coords,
unsigned int n_rects);
CLUTTER_EXPORT
void clutter_paint_node_add_texture_rectangles (ClutterPaintNode *node,
const float *coords,
unsigned int n_rects);
CLUTTER_EXPORT
void clutter_paint_node_add_primitive (ClutterPaintNode *node,
CoglPrimitive *primitive);

View File

@ -33,13 +33,14 @@
#include "clutter-build-config.h"
#define CLUTTER_ENABLE_EXPERIMENTAL_API
#include "clutter-paint-node-private.h"
#include <pango/pango.h>
#include <cogl/cogl.h>
#include "clutter-actor-private.h"
#include "clutter-blur-private.h"
#include "clutter-color.h"
#include "clutter-debug.h"
#include "clutter-private.h"
@ -129,7 +130,7 @@ clutter_root_node_finalize (ClutterPaintNode *node)
{
ClutterRootNode *rnode = (ClutterRootNode *) node;
g_object_unref (rnode->framebuffer);
cogl_object_unref (rnode->framebuffer);
CLUTTER_PAINT_NODE_CLASS (clutter_root_node_parent_class)->finalize (node);
}
@ -176,7 +177,7 @@ clutter_root_node_new (CoglFramebuffer *framebuffer,
clear_color->alpha);
cogl_color_premultiply (&res->clear_color);
res->framebuffer = g_object_ref (framebuffer);
res->framebuffer = cogl_object_ref (framebuffer);
res->clear_flags = clear_flags;
return (ClutterPaintNode *) res;
@ -190,7 +191,7 @@ struct _ClutterTransformNode
{
ClutterPaintNode parent_instance;
graphene_matrix_t transform;
CoglMatrix transform;
};
struct _ClutterTransformNodeClass
@ -237,7 +238,7 @@ clutter_transform_node_class_init (ClutterTransformNodeClass *klass)
static void
clutter_transform_node_init (ClutterTransformNode *self)
{
graphene_matrix_init_identity (&self->transform);
cogl_matrix_init_identity (&self->transform);
}
/*
@ -248,13 +249,13 @@ clutter_transform_node_init (ClutterTransformNode *self)
* Use clutter_paint_node_unref() when done.
*/
ClutterPaintNode *
clutter_transform_node_new (const graphene_matrix_t *transform)
clutter_transform_node_new (const CoglMatrix *transform)
{
ClutterTransformNode *res;
res = _clutter_paint_node_create (CLUTTER_TYPE_TRANSFORM_NODE);
if (transform)
graphene_matrix_init_from_matrix (&res->transform, transform);
res->transform = *transform;
return (ClutterPaintNode *) res;
}
@ -325,7 +326,7 @@ clutter_dummy_node_finalize (ClutterPaintNode *node)
{
ClutterDummyNode *dnode = (ClutterDummyNode *) node;
g_clear_object (&dnode->framebuffer);
cogl_clear_object (&dnode->framebuffer);
CLUTTER_PAINT_NODE_CLASS (clutter_dummy_node_parent_class)->finalize (node);
}
@ -357,7 +358,7 @@ _clutter_dummy_node_new (ClutterActor *actor,
dnode = (ClutterDummyNode *) res;
dnode->actor = actor;
dnode->framebuffer = g_object_ref (framebuffer);
dnode->framebuffer = cogl_object_ref (framebuffer);
return res;
}
@ -465,13 +466,6 @@ clutter_pipeline_node_draw (ClutterPaintNode *node,
op->op.texrect[7]);
break;
case PAINT_OP_TEX_RECTS:
cogl_framebuffer_draw_textured_rectangles (fb,
pnode->pipeline,
(float *) op->coords->data,
op->coords->len / 8);
break;
case PAINT_OP_MULTITEX_RECT:
cogl_framebuffer_draw_multitextured_rectangle (fb,
pnode->pipeline,
@ -479,8 +473,8 @@ clutter_pipeline_node_draw (ClutterPaintNode *node,
op->op.texrect[1],
op->op.texrect[2],
op->op.texrect[3],
(float *) op->coords->data,
op->coords->len);
(float*) op->multitex_coords->data,
op->multitex_coords->len);
break;
case PAINT_OP_PRIMITIVE:
@ -557,7 +551,7 @@ clutter_pipeline_node_init (ClutterPipelineNode *self)
}
/**
* clutter_pipeline_node_new:
* clutter_pipeline_node_new: (skip)
* @pipeline: (allow-none): a Cogl pipeline state object, or %NULL
*
* Creates a new #ClutterPaintNode that will use the @pipeline to
@ -877,7 +871,6 @@ clutter_text_node_draw (ClutterPaintNode *node,
cogl_framebuffer_pop_clip (fb);
break;
case PAINT_OP_TEX_RECTS:
case PAINT_OP_MULTITEX_RECT:
case PAINT_OP_PRIMITIVE:
case PAINT_OP_INVALID:
@ -1039,7 +1032,6 @@ clutter_clip_node_pre_draw (ClutterPaintNode *node,
retval = TRUE;
break;
case PAINT_OP_TEX_RECTS:
case PAINT_OP_MULTITEX_RECT:
case PAINT_OP_PRIMITIVE:
case PAINT_OP_INVALID:
@ -1074,7 +1066,6 @@ clutter_clip_node_post_draw (ClutterPaintNode *node,
cogl_framebuffer_pop_clip (fb);
break;
case PAINT_OP_TEX_RECTS:
case PAINT_OP_MULTITEX_RECT:
case PAINT_OP_PRIMITIVE:
case PAINT_OP_INVALID:
@ -1124,8 +1115,6 @@ struct _ClutterActorNode
ClutterPaintNode parent_instance;
ClutterActor *actor;
int opacity_override;
int saved_opacity_override;
};
struct _ClutterActorNodeClass
@ -1141,14 +1130,6 @@ clutter_actor_node_pre_draw (ClutterPaintNode *node,
{
ClutterActorNode *actor_node = CLUTTER_ACTOR_NODE (node);
if (actor_node->opacity_override != -1)
{
actor_node->saved_opacity_override =
clutter_actor_get_opacity_override (actor_node->actor);
clutter_actor_set_opacity_override (actor_node->actor,
actor_node->opacity_override);
}
CLUTTER_SET_PRIVATE_FLAGS (actor_node->actor, CLUTTER_IN_PAINT);
return TRUE;
@ -1170,12 +1151,6 @@ clutter_actor_node_post_draw (ClutterPaintNode *node,
ClutterActorNode *actor_node = CLUTTER_ACTOR_NODE (node);
CLUTTER_UNSET_PRIVATE_FLAGS (actor_node->actor, CLUTTER_IN_PAINT);
if (actor_node->opacity_override != -1)
{
clutter_actor_set_opacity_override (actor_node->actor,
actor_node->saved_opacity_override);
}
}
static JsonNode *
@ -1217,7 +1192,6 @@ clutter_actor_node_init (ClutterActorNode *self)
/*
* clutter_actor_node_new:
* @actor: the actor to paint
* @opacity: opacity to draw the actor with, or -1 to use the actor's opacity
*
* Creates a new #ClutterActorNode.
*
@ -1229,8 +1203,7 @@ clutter_actor_node_init (ClutterActorNode *self)
* Use clutter_paint_node_unref() when done.
*/
ClutterPaintNode *
clutter_actor_node_new (ClutterActor *actor,
int opacity)
clutter_actor_node_new (ClutterActor *actor)
{
ClutterActorNode *res;
@ -1238,96 +1211,11 @@ clutter_actor_node_new (ClutterActor *actor,
res = _clutter_paint_node_create (CLUTTER_TYPE_ACTOR_NODE);
res->actor = actor;
res->opacity_override = CLAMP (opacity, -1, 255);
return (ClutterPaintNode *) res;
}
/*
* ClutterEffectNode
*/
struct _ClutterEffectNode
{
ClutterPaintNode parent_instance;
ClutterEffect *effect;
};
struct _ClutterEffectNodeClass
{
ClutterPaintNodeClass parent_class;
};
G_DEFINE_TYPE (ClutterEffectNode, clutter_effect_node, CLUTTER_TYPE_PAINT_NODE)
static JsonNode *
clutter_effect_node_serialize (ClutterPaintNode *node)
{
ClutterEffectNode *effect_node = CLUTTER_EFFECT_NODE (node);
ClutterActorMeta *effect_meta = CLUTTER_ACTOR_META (effect_node->effect);
g_autoptr (JsonBuilder) builder = NULL;
g_autoptr (GString) string = NULL;
const char *meta_name;
meta_name = clutter_actor_meta_get_name (effect_meta);
string = g_string_new (NULL);
g_string_append (string, G_OBJECT_TYPE_NAME (effect_node->effect));
g_string_append (string, " (");
if (meta_name)
g_string_append_printf (string, "\"%s\"", meta_name);
else
g_string_append (string, "unnamed");
g_string_append (string, ")");
builder = json_builder_new ();
json_builder_begin_object (builder);
json_builder_set_member_name (builder, "effect");
json_builder_add_string_value (builder, string->str);
json_builder_end_object (builder);
return json_builder_get_root (builder);
}
static void
clutter_effect_node_class_init (ClutterEffectNodeClass *klass)
{
ClutterPaintNodeClass *node_class;
node_class = CLUTTER_PAINT_NODE_CLASS (klass);
node_class->serialize = clutter_effect_node_serialize;
}
static void
clutter_effect_node_init (ClutterEffectNode *self)
{
}
/**
* clutter_effect_node_new:
* @effect: the actor to paint
*
* Creates a new #ClutterEffectNode.
*
* Return value: (transfer full): the newly created #ClutterEffectNode.
* Use clutter_paint_node_unref() when done.
*/
ClutterPaintNode *
clutter_effect_node_new (ClutterEffect *effect)
{
ClutterEffectNode *res;
g_assert (CLUTTER_IS_EFFECT (effect));
res = _clutter_paint_node_create (CLUTTER_TYPE_EFFECT_NODE);
res->effect = effect;
return (ClutterPaintNode *) res;
}
/*
* ClutterLayerNode
*/
@ -1338,7 +1226,7 @@ struct _ClutterLayerNode
cairo_rectangle_t viewport;
graphene_matrix_t projection;
CoglMatrix projection;
float fbo_width;
float fbo_height;
@ -1347,8 +1235,6 @@ struct _ClutterLayerNode
CoglFramebuffer *offscreen;
guint8 opacity;
gboolean needs_fbo_setup : 1;
};
struct _ClutterLayerNodeClass
@ -1364,7 +1250,7 @@ clutter_layer_node_pre_draw (ClutterPaintNode *node,
{
ClutterLayerNode *lnode = (ClutterLayerNode *) node;
CoglFramebuffer *framebuffer;
graphene_matrix_t matrix;
CoglMatrix matrix;
/* if we were unable to create an offscreen buffer for this node, then
* we simply ignore it
@ -1372,27 +1258,29 @@ clutter_layer_node_pre_draw (ClutterPaintNode *node,
if (lnode->offscreen == NULL)
return FALSE;
if (lnode->needs_fbo_setup)
{
/* copy the same modelview from the current framebuffer to the one we
* are going to use
*/
framebuffer = clutter_paint_context_get_framebuffer (paint_context);
cogl_framebuffer_get_modelview_matrix (framebuffer, &matrix);
cogl_framebuffer_set_modelview_matrix (lnode->offscreen, &matrix);
/* if no geometry was submitted for this node then we simply ignore it */
if (node->operations == NULL)
return FALSE;
cogl_framebuffer_set_viewport (lnode->offscreen,
lnode->viewport.x,
lnode->viewport.y,
lnode->viewport.width,
lnode->viewport.height);
cogl_framebuffer_set_projection_matrix (lnode->offscreen,
&lnode->projection);
}
/* copy the same modelview from the current framebuffer to the one we
* are going to use
*/
framebuffer = clutter_paint_context_get_framebuffer (paint_context);
cogl_framebuffer_get_modelview_matrix (framebuffer, &matrix);
clutter_paint_context_push_framebuffer (paint_context, lnode->offscreen);
cogl_framebuffer_set_modelview_matrix (lnode->offscreen, &matrix);
cogl_framebuffer_set_viewport (lnode->offscreen,
lnode->viewport.x,
lnode->viewport.y,
lnode->viewport.width,
lnode->viewport.height);
cogl_framebuffer_set_projection_matrix (lnode->offscreen,
&lnode->projection);
/* clear out the target framebuffer */
cogl_framebuffer_clear4f (lnode->offscreen,
COGL_BUFFER_BIT_COLOR | COGL_BUFFER_BIT_DEPTH,
@ -1419,9 +1307,6 @@ clutter_layer_node_post_draw (ClutterPaintNode *node,
cogl_framebuffer_pop_matrix (lnode->offscreen);
clutter_paint_context_pop_framebuffer (paint_context);
if (!node->operations)
return;
fb = clutter_paint_context_get_framebuffer (paint_context);
for (i = 0; i < node->operations->len; i++)
@ -1448,13 +1333,6 @@ clutter_layer_node_post_draw (ClutterPaintNode *node,
op->op.texrect[7]);
break;
case PAINT_OP_TEX_RECTS:
cogl_framebuffer_draw_textured_rectangles (fb,
lnode->pipeline,
(float *) op->coords->data,
op->coords->len / 8);
break;
case PAINT_OP_MULTITEX_RECT:
cogl_framebuffer_draw_multitextured_rectangle (fb,
lnode->pipeline,
@ -1462,8 +1340,8 @@ clutter_layer_node_post_draw (ClutterPaintNode *node,
op->op.texrect[1],
op->op.texrect[2],
op->op.texrect[3],
(float *) op->coords->data,
op->coords->len);
(float*) op->multitex_coords->data,
op->multitex_coords->len);
break;
case PAINT_OP_PRIMITIVE:
@ -1483,30 +1361,12 @@ clutter_layer_node_finalize (ClutterPaintNode *node)
if (lnode->pipeline != NULL)
cogl_object_unref (lnode->pipeline);
g_clear_object (&lnode->offscreen);
if (lnode->offscreen != NULL)
cogl_object_unref (lnode->offscreen);
CLUTTER_PAINT_NODE_CLASS (clutter_layer_node_parent_class)->finalize (node);
}
static JsonNode *
clutter_layer_node_serialize (ClutterPaintNode *node)
{
ClutterLayerNode *layer_node = CLUTTER_LAYER_NODE (node);
g_autoptr (JsonBuilder) builder = NULL;
g_autofree char *framebuffer_ptr = NULL;
builder = json_builder_new ();
framebuffer_ptr = g_strdup_printf ("%p", layer_node->offscreen);
json_builder_begin_object (builder);
json_builder_set_member_name (builder, "framebuffer");
json_builder_add_string_value (builder, framebuffer_ptr);
json_builder_end_object (builder);
return json_builder_get_root (builder);
}
static void
clutter_layer_node_class_init (ClutterLayerNodeClass *klass)
{
@ -1516,13 +1376,12 @@ clutter_layer_node_class_init (ClutterLayerNodeClass *klass)
node_class->pre_draw = clutter_layer_node_pre_draw;
node_class->post_draw = clutter_layer_node_post_draw;
node_class->finalize = clutter_layer_node_finalize;
node_class->serialize = clutter_layer_node_serialize;
}
static void
clutter_layer_node_init (ClutterLayerNode *self)
{
graphene_matrix_init_identity (&self->projection);
cogl_matrix_init_identity (&self->projection);
}
/*
@ -1545,427 +1404,57 @@ clutter_layer_node_init (ClutterLayerNode *self)
* Since: 1.10
*/
ClutterPaintNode *
clutter_layer_node_new (const graphene_matrix_t *projection,
clutter_layer_node_new (const CoglMatrix *projection,
const cairo_rectangle_t *viewport,
float width,
float height,
guint8 opacity)
{
ClutterLayerNode *lnode;
ClutterLayerNode *res;
CoglContext *context;
CoglTexture2D *tex_2d;
CoglTexture *texture;
CoglColor color;
g_autoptr (CoglOffscreen) offscreen = NULL;
g_autoptr (GError) error = NULL;
lnode = _clutter_paint_node_create (CLUTTER_TYPE_LAYER_NODE);
res = _clutter_paint_node_create (CLUTTER_TYPE_LAYER_NODE);
lnode->needs_fbo_setup = TRUE;
lnode->projection = *projection;
lnode->viewport = *viewport;
lnode->fbo_width = width;
lnode->fbo_height = height;
lnode->opacity = opacity;
res->projection = *projection;
res->viewport = *viewport;
res->fbo_width = width;
res->fbo_height = height;
res->opacity = opacity;
/* the texture backing the FBO */
context = clutter_backend_get_cogl_context (clutter_get_default_backend ());
tex_2d = cogl_texture_2d_new_with_size (context,
MAX (lnode->fbo_width, 1),
MAX (lnode->fbo_height, 1));
MAX (res->fbo_width, 1),
MAX (res->fbo_height, 1));
texture = COGL_TEXTURE (tex_2d);
cogl_texture_set_premultiplied (texture, TRUE);
offscreen = cogl_offscreen_new_with_texture (texture);
if (!cogl_framebuffer_allocate (COGL_FRAMEBUFFER (offscreen), &error))
res->offscreen = COGL_FRAMEBUFFER (cogl_offscreen_new_to_texture (texture));
if (res->offscreen == NULL)
{
g_warning ("Unable to create an allocate paint node offscreen: %s",
error->message);
cogl_object_unref (texture);
return NULL;
g_critical ("%s: Unable to create an offscreen buffer", G_STRLOC);
goto out;
}
lnode->offscreen = COGL_FRAMEBUFFER (g_steal_pointer (&offscreen));
cogl_color_init_from_4ub (&color, opacity, opacity, opacity, opacity);
/* the pipeline used to paint the texture; we use nearest
* interpolation filters because the texture is always
* going to be painted at a 1:1 texel:pixel ratio
*/
lnode->pipeline = cogl_pipeline_copy (default_texture_pipeline);
cogl_pipeline_set_layer_filters (lnode->pipeline, 0,
res->pipeline = cogl_pipeline_copy (default_texture_pipeline);
cogl_pipeline_set_layer_filters (res->pipeline, 0,
COGL_PIPELINE_FILTER_NEAREST,
COGL_PIPELINE_FILTER_NEAREST);
cogl_pipeline_set_layer_texture (lnode->pipeline, 0, texture);
cogl_pipeline_set_color (lnode->pipeline, &color);
cogl_object_unref (texture);
return (ClutterPaintNode *) lnode;
}
/**
* clutter_layer_node_new_to_framebuffer:
* @framebuffer: a #CoglFramebuffer
* @pipeline: a #CoglPipeline
*
* Creates a new #ClutterLayerNode that will redirect drawing at
* @framebuffer. It will then use @pipeline to paint the stored
* operations.
*
* When using this constructor, the caller is reponsible for setting
* up @framebuffer, including its modelview and projection matrices,
* and the viewport, and the @pipeline as well.
*
* Return value: (transfer full): the newly created #ClutterLayerNode.
* Use clutter_paint_node_unref() when done.
*/
ClutterPaintNode *
clutter_layer_node_new_to_framebuffer (CoglFramebuffer *framebuffer,
CoglPipeline *pipeline)
{
ClutterLayerNode *res;
g_return_val_if_fail (COGL_IS_FRAMEBUFFER (framebuffer), NULL);
g_return_val_if_fail (cogl_is_pipeline (pipeline), NULL);
res = _clutter_paint_node_create (CLUTTER_TYPE_LAYER_NODE);
res->needs_fbo_setup = FALSE;
res->fbo_width = cogl_framebuffer_get_width (framebuffer);
res->fbo_height = cogl_framebuffer_get_height (framebuffer);
res->offscreen = g_object_ref (framebuffer);
res->pipeline = cogl_pipeline_copy (pipeline);
return (ClutterPaintNode *) res;
}
/*
* ClutterBlitNode
*/
struct _ClutterBlitNode
{
ClutterPaintNode parent_instance;
CoglFramebuffer *src;
};
G_DEFINE_TYPE (ClutterBlitNode, clutter_blit_node, CLUTTER_TYPE_PAINT_NODE)
static gboolean
clutter_blit_node_pre_draw (ClutterPaintNode *node,
ClutterPaintContext *paint_context)
{
return TRUE;
}
static void
clutter_blit_node_draw (ClutterPaintNode *node,
ClutterPaintContext *paint_context)
{
ClutterBlitNode *blit_node = CLUTTER_BLIT_NODE (node);
g_autoptr (GError) error = NULL;
CoglFramebuffer *framebuffer;
unsigned int i;
if (node->operations == NULL)
return;
framebuffer = get_target_framebuffer (node, paint_context);
for (i = 0; i < node->operations->len; i++)
{
const ClutterPaintOperation *op;
float op_width, op_height;
op = &g_array_index (node->operations, ClutterPaintOperation, i);
switch (op->opcode)
{
case PAINT_OP_INVALID:
break;
case PAINT_OP_TEX_RECT:
op_width = op->op.texrect[6] - op->op.texrect[4];
op_height = op->op.texrect[7] - op->op.texrect[5];
cogl_blit_framebuffer (blit_node->src,
framebuffer,
op->op.texrect[0],
op->op.texrect[1],
op->op.texrect[4],
op->op.texrect[5],
op_width,
op_height,
&error);
if (error)
{
g_warning ("Error blitting framebuffers: %s", error->message);
return;
}
break;
case PAINT_OP_TEX_RECTS:
case PAINT_OP_MULTITEX_RECT:
case PAINT_OP_PRIMITIVE:
break;
}
}
}
static void
clutter_blit_node_finalize (ClutterPaintNode *node)
{
ClutterBlitNode *blit_node = CLUTTER_BLIT_NODE (node);
g_clear_object (&blit_node->src);
CLUTTER_PAINT_NODE_CLASS (clutter_blit_node_parent_class)->finalize (node);
}
static JsonNode *
clutter_blit_node_serialize (ClutterPaintNode *node)
{
ClutterBlitNode *blit_node = CLUTTER_BLIT_NODE (node);
g_autoptr (JsonBuilder) builder = NULL;
g_autofree char *src_ptr = NULL;
src_ptr = g_strdup_printf ("%p", blit_node->src);
builder = json_builder_new ();
json_builder_begin_object (builder);
json_builder_set_member_name (builder, "source");
json_builder_add_string_value (builder, src_ptr);
json_builder_end_object (builder);
return json_builder_get_root (builder);
}
static void
clutter_blit_node_class_init (ClutterBlitNodeClass *klass)
{
ClutterPaintNodeClass *node_class;
node_class = CLUTTER_PAINT_NODE_CLASS (klass);
node_class->pre_draw = clutter_blit_node_pre_draw;
node_class->draw = clutter_blit_node_draw;
node_class->finalize = clutter_blit_node_finalize;
node_class->serialize = clutter_blit_node_serialize;
}
static void
clutter_blit_node_init (ClutterBlitNode *self)
{
}
/**
* clutter_blit_node_new:
* @src: the source #CoglFramebuffer
*
* Creates a new #ClutterBlitNode that blits @src into the current
* draw framebuffer.
*
* You must only add rectangles using clutter_blit_node_add_blit_rectangle().
*
* Return value: (transfer full): the newly created #ClutterBlitNode.
* Use clutter_paint_node_unref() when done.
*/
ClutterPaintNode *
clutter_blit_node_new (CoglFramebuffer *src)
{
ClutterBlitNode *res;
g_return_val_if_fail (COGL_IS_FRAMEBUFFER (src), NULL);
res = _clutter_paint_node_create (CLUTTER_TYPE_BLIT_NODE);
res->src = g_object_ref (src);
return (ClutterPaintNode *) res;
}
/**
* clutter_blit_node_add_blit_rectangle:
* @blit_node: a #ClutterBlitNode
* @src_x: Source x position
* @src_y: Source y position
* @dst_x: Destination x position
* @dst_y: Destination y position
* @width: Width of region to copy
* @height: Height of region to copy
*
* Adds a new blit rectangle to the stack of rectangles. All the
* constraints of cogl_blit_framebuffer() apply here.
*/
void
clutter_blit_node_add_blit_rectangle (ClutterBlitNode *blit_node,
int src_x,
int src_y,
int dst_x,
int dst_y,
int width,
int height)
{
g_return_if_fail (CLUTTER_IS_BLIT_NODE (blit_node));
clutter_paint_node_add_texture_rectangle (CLUTTER_PAINT_NODE (blit_node),
&(ClutterActorBox) {
.x1 = src_x,
.y1 = src_y,
.x2 = src_x + width,
.y2 = src_y + height,
},
dst_x,
dst_y,
dst_x + width,
dst_y + height);
}
/*
* ClutterBlurNode
*/
struct _ClutterBlurNode
{
ClutterLayerNode parent_instance;
ClutterBlur *blur;
unsigned int sigma;
};
G_DEFINE_TYPE (ClutterBlurNode, clutter_blur_node, CLUTTER_TYPE_LAYER_NODE)
static void
clutter_blur_node_post_draw (ClutterPaintNode *node,
ClutterPaintContext *paint_context)
{
ClutterPaintNodeClass *parent_class =
CLUTTER_PAINT_NODE_CLASS (clutter_blur_node_parent_class);
ClutterBlurNode *blur_node = CLUTTER_BLUR_NODE (node);
clutter_blur_apply (blur_node->blur);
parent_class->post_draw (node, paint_context);
}
static void
clutter_blur_node_finalize (ClutterPaintNode *node)
{
ClutterBlurNode *blur_node = CLUTTER_BLUR_NODE (node);
g_clear_pointer (&blur_node->blur, clutter_blur_free);
CLUTTER_PAINT_NODE_CLASS (clutter_blur_node_parent_class)->finalize (node);
}
static JsonNode *
clutter_blur_node_serialize (ClutterPaintNode *node)
{
ClutterBlurNode *blur_node = CLUTTER_BLUR_NODE (node);
g_autoptr (JsonBuilder) builder = NULL;
g_autofree char *src_ptr = NULL;
src_ptr = g_strdup_printf ("%d", blur_node->sigma);
builder = json_builder_new ();
json_builder_begin_object (builder);
json_builder_set_member_name (builder, "sigma");
json_builder_add_string_value (builder, src_ptr);
json_builder_end_object (builder);
return json_builder_get_root (builder);
}
static void
clutter_blur_node_class_init (ClutterBlurNodeClass *klass)
{
ClutterPaintNodeClass *node_class;
node_class = CLUTTER_PAINT_NODE_CLASS (klass);
node_class->post_draw = clutter_blur_node_post_draw;
node_class->finalize = clutter_blur_node_finalize;
node_class->serialize = clutter_blur_node_serialize;
}
static void
clutter_blur_node_init (ClutterBlurNode *blur_node)
{
}
/**
* clutter_blur_node_new:
* @width width of the blur layer
* @height: height of the blur layer
* @sigma: sigma value of the blur
*
* Creates a new #ClutterBlurNode.
*
* Children of this node will be painted inside a separate framebuffer,
* which will be blurred and painted on the current draw framebuffer.
*
* Return value: (transfer full): the newly created #ClutterBlurNode.
* Use clutter_paint_node_unref() when done.
*/
ClutterPaintNode *
clutter_blur_node_new (unsigned int width,
unsigned int height,
float sigma)
{
g_autoptr (CoglOffscreen) offscreen = NULL;
g_autoptr (GError) error = NULL;
ClutterLayerNode *layer_node;
ClutterBlurNode *blur_node;
CoglTexture2D *tex_2d;
CoglContext *context;
CoglTexture *texture;
ClutterBlur *blur;
g_return_val_if_fail (sigma >= 0.0, NULL);
blur_node = _clutter_paint_node_create (CLUTTER_TYPE_BLUR_NODE);
blur_node->sigma = sigma;
context = clutter_backend_get_cogl_context (clutter_get_default_backend ());
tex_2d = cogl_texture_2d_new_with_size (context, width, height);
texture = COGL_TEXTURE (tex_2d);
cogl_texture_set_premultiplied (texture, TRUE);
offscreen = cogl_offscreen_new_with_texture (texture);
cogl_object_unref (tex_2d);
if (!cogl_framebuffer_allocate (COGL_FRAMEBUFFER (offscreen), &error))
{
g_warning ("Unable to allocate paint node offscreen: %s",
error->message);
goto out;
}
blur = clutter_blur_new (texture, sigma);
blur_node->blur = blur;
if (!blur)
{
g_warning ("Failed to create blur pipeline");
goto out;
}
layer_node = CLUTTER_LAYER_NODE (blur_node);
layer_node->offscreen = COGL_FRAMEBUFFER (g_steal_pointer (&offscreen));
layer_node->pipeline = cogl_pipeline_copy (default_texture_pipeline);
cogl_pipeline_set_layer_filters (layer_node->pipeline, 0,
COGL_PIPELINE_FILTER_LINEAR,
COGL_PIPELINE_FILTER_LINEAR);
cogl_pipeline_set_layer_texture (layer_node->pipeline,
0,
clutter_blur_get_texture (blur));
cogl_framebuffer_orthographic (layer_node->offscreen,
0.0, 0.0,
width, height,
0.0, 1.0);
cogl_pipeline_set_layer_texture (res->pipeline, 0, texture);
cogl_pipeline_set_color (res->pipeline, &color);
out:
return (ClutterPaintNode *) blur_node;
cogl_object_unref (texture);
return (ClutterPaintNode *) res;
}

View File

@ -160,8 +160,7 @@ CLUTTER_EXPORT
GType clutter_actor_node_get_type (void) G_GNUC_CONST;
CLUTTER_EXPORT
ClutterPaintNode * clutter_actor_node_new (ClutterActor *actor,
int opacity);
ClutterPaintNode * clutter_actor_node_new (ClutterActor *actor);
#define CLUTTER_TYPE_ROOT_NODE (clutter_root_node_get_type ())
#define CLUTTER_ROOT_NODE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_ROOT_NODE, ClutterRootNode))
@ -203,16 +202,12 @@ CLUTTER_EXPORT
GType clutter_layer_node_get_type (void) G_GNUC_CONST;
CLUTTER_EXPORT
ClutterPaintNode * clutter_layer_node_new (const graphene_matrix_t *projection,
ClutterPaintNode * clutter_layer_node_new (const CoglMatrix *projection,
const cairo_rectangle_t *viewport,
float width,
float height,
guint8 opacity);
CLUTTER_EXPORT
ClutterPaintNode * clutter_layer_node_new_to_framebuffer (CoglFramebuffer *framebuffer,
CoglPipeline *pipeline);
#define CLUTTER_TYPE_TRANSFORM_NODE (clutter_transform_node_get_type ())
#define CLUTTER_TRANSFORM_NODE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_TRANSFORM_NODE, ClutterTransformNode))
@ -233,56 +228,7 @@ CLUTTER_EXPORT
GType clutter_transform_node_get_type (void) G_GNUC_CONST;
CLUTTER_EXPORT
ClutterPaintNode * clutter_transform_node_new (const graphene_matrix_t *projection);
#define CLUTTER_TYPE_BLIT_NODE (clutter_blit_node_get_type ())
#define CLUTTER_BLIT_NODE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_BLIT_NODE, ClutterBlitNode))
#define CLUTTER_IS_BLIT_NODE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_BLIT_NODE))
/*
* ClutterBlitNode:
*
* The #ClutterBlitNode structure is an opaque
* type whose members cannot be directly accessed.
*/
typedef struct _ClutterBlitNode ClutterBlitNode;
typedef struct _ClutterPaintNodeClass ClutterBlitNodeClass;
CLUTTER_EXPORT
GType clutter_blit_node_get_type (void) G_GNUC_CONST;
CLUTTER_EXPORT
ClutterPaintNode * clutter_blit_node_new (CoglFramebuffer *src);
CLUTTER_EXPORT
void clutter_blit_node_add_blit_rectangle (ClutterBlitNode *blit_node,
int src_x,
int src_y,
int dst_x,
int dst_y,
int width,
int height);
#define CLUTTER_TYPE_BLUR_NODE (clutter_blur_node_get_type ())
#define CLUTTER_BLUR_NODE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_BLUR_NODE, ClutterBlurNode))
#define CLUTTER_IS_BLUR_NODE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_BLUR_NODE))
/**
* ClutterBlurNode:
*
* The #ClutterBurNode structure is an opaque
* type whose members cannot be directly accessed.
*/
typedef struct _ClutterBlurNode ClutterBlurNode;
typedef struct _ClutterLayerNodeClass ClutterBlurNodeClass;
CLUTTER_EXPORT
GType clutter_blur_node_get_type (void) G_GNUC_CONST;
CLUTTER_EXPORT
ClutterPaintNode * clutter_blur_node_new (unsigned int width,
unsigned int height,
float sigma);
ClutterPaintNode * clutter_transform_node_new (const CoglMatrix *projection);
G_END_DECLS

View File

@ -62,7 +62,7 @@ struct _ClutterPaintVolume
/* As an optimization for internally managed PaintVolumes we allow
* initializing ClutterPaintVolume variables allocated on the stack
* so we can avoid hammering the memory allocator. */
* so we can avoid hammering the slice allocator. */
guint is_static:1;
/* A newly initialized PaintVolume is considered empty as it is
@ -85,8 +85,8 @@ struct _ClutterPaintVolume
* TRUE) */
guint is_2d:1;
/* Set to TRUE initially but cleared if the paint volume is
* transformed by a matrix. */
/* Set to TRUE initialy but cleared if the paint volume is
* transfomed by a matrix. */
guint is_axis_aligned:1;
@ -111,20 +111,20 @@ void _clutter_paint_volume_set_from_volume (ClutterPaintVolu
const ClutterPaintVolume *src);
void _clutter_paint_volume_complete (ClutterPaintVolume *pv);
void _clutter_paint_volume_transform (ClutterPaintVolume *pv,
const graphene_matrix_t *matrix);
void _clutter_paint_volume_project (ClutterPaintVolume *pv,
const graphene_matrix_t *modelview,
const graphene_matrix_t *projection,
const float *viewport);
void _clutter_paint_volume_transform (ClutterPaintVolume *pv,
const CoglMatrix *matrix);
void _clutter_paint_volume_project (ClutterPaintVolume *pv,
const CoglMatrix *modelview,
const CoglMatrix *projection,
const float *viewport);
void _clutter_paint_volume_get_bounding_box (ClutterPaintVolume *pv,
ClutterActorBox *box);
void _clutter_paint_volume_axis_align (ClutterPaintVolume *pv);
void _clutter_paint_volume_set_reference_actor (ClutterPaintVolume *pv,
ClutterActor *actor);
ClutterCullResult _clutter_paint_volume_cull (ClutterPaintVolume *pv,
const graphene_frustum_t *frustum);
ClutterCullResult _clutter_paint_volume_cull (ClutterPaintVolume *pv,
const ClutterPlane *planes);
void _clutter_paint_volume_get_stage_paint_box (ClutterPaintVolume *pv,
ClutterStage *stage,
@ -133,9 +133,6 @@ void _clutter_paint_volume_get_stage_paint_box (ClutterPaintVolu
void _clutter_paint_volume_transform_relative (ClutterPaintVolume *pv,
ClutterActor *relative_to_ancestor);
void clutter_paint_volume_to_box (ClutterPaintVolume *pv,
graphene_box_t *box);
G_END_DECLS
#endif /* __CLUTTER_PAINT_VOLUME_PRIVATE_H__ */

View File

@ -59,7 +59,7 @@ _clutter_paint_volume_new (ClutterActor *actor)
g_return_val_if_fail (actor != NULL, NULL);
pv = g_new0 (ClutterPaintVolume, 1);
pv = g_slice_new (ClutterPaintVolume);
pv->actor = actor;
@ -78,7 +78,7 @@ _clutter_paint_volume_new (ClutterActor *actor)
* traversal of a Clutter scene graph and since paint volumes often
* have a very short life cycle that maps well to stack allocation we
* allow initializing a static ClutterPaintVolume variable to avoid
* hammering the memory allocator.
* hammering the slice allocator.
*
* We were seeing slice allocation take about 1% cumulative CPU time
* for some very simple clutter tests which although it isn't a *lot*
@ -133,7 +133,7 @@ clutter_paint_volume_copy (const ClutterPaintVolume *pv)
g_return_val_if_fail (pv != NULL, NULL);
copy = g_memdup2 (pv, sizeof (ClutterPaintVolume));
copy = g_slice_dup (ClutterPaintVolume, pv);
copy->is_static = FALSE;
return copy;
@ -164,7 +164,7 @@ clutter_paint_volume_free (ClutterPaintVolume *pv)
if (G_LIKELY (pv->is_static))
return;
g_free (pv);
g_slice_free (ClutterPaintVolume, pv);
}
/**
@ -533,11 +533,6 @@ clutter_paint_volume_union (ClutterPaintVolume *pv,
const ClutterPaintVolume *another_pv)
{
ClutterPaintVolume aligned_pv;
graphene_point3d_t min;
graphene_point3d_t max;
graphene_box_t another_box;
graphene_box_t union_box;
graphene_box_t box;
g_return_if_fail (pv != NULL);
g_return_if_fail (another_pv != NULL);
@ -545,6 +540,9 @@ clutter_paint_volume_union (ClutterPaintVolume *pv,
/* Both volumes have to belong to the same local coordinate space */
g_return_if_fail (pv->actor == another_pv->actor);
/* NB: we only have to update vertices 0, 1, 3 and 4
* (See the ClutterPaintVolume typedef for more details) */
/* We special case empty volumes because otherwise we'd end up
* calculating a bounding box that would enclose the origin of
* the empty volume which isn't desired.
@ -561,34 +559,78 @@ clutter_paint_volume_union (ClutterPaintVolume *pv,
if (!pv->is_axis_aligned)
_clutter_paint_volume_axis_align (pv);
_clutter_paint_volume_complete (pv);
if (!another_pv->is_axis_aligned || !another_pv->is_complete)
if (!another_pv->is_axis_aligned)
{
_clutter_paint_volume_copy_static (another_pv, &aligned_pv);
_clutter_paint_volume_axis_align (&aligned_pv);
_clutter_paint_volume_complete (&aligned_pv);
another_pv = &aligned_pv;
}
if (G_LIKELY (pv->is_2d))
graphene_box_init_from_points (&box, 4, pv->vertices);
else
graphene_box_init_from_points (&box, 8, pv->vertices);
/* grow left*/
/* left vertices 0, 3, 4, 7 */
if (another_pv->vertices[0].x < pv->vertices[0].x)
{
int min_x = another_pv->vertices[0].x;
pv->vertices[0].x = min_x;
pv->vertices[3].x = min_x;
pv->vertices[4].x = min_x;
/* pv->vertices[7].x = min_x; */
}
if (G_LIKELY (another_pv->is_2d))
graphene_box_init_from_points (&another_box, 4, another_pv->vertices);
else
graphene_box_init_from_points (&another_box, 8, another_pv->vertices);
/* grow right */
/* right vertices 1, 2, 5, 6 */
if (another_pv->vertices[1].x > pv->vertices[1].x)
{
int max_x = another_pv->vertices[1].x;
pv->vertices[1].x = max_x;
/* pv->vertices[2].x = max_x; */
/* pv->vertices[5].x = max_x; */
/* pv->vertices[6].x = max_x; */
}
graphene_box_union (&box, &another_box, &union_box);
/* grow up */
/* top vertices 0, 1, 4, 5 */
if (another_pv->vertices[0].y < pv->vertices[0].y)
{
int min_y = another_pv->vertices[0].y;
pv->vertices[0].y = min_y;
pv->vertices[1].y = min_y;
pv->vertices[4].y = min_y;
/* pv->vertices[5].y = min_y; */
}
graphene_box_get_min (&union_box, &min);
graphene_box_get_max (&union_box, &max);
graphene_point3d_init (&pv->vertices[0], min.x, min.y, min.z);
graphene_point3d_init (&pv->vertices[1], max.x, min.y, min.z);
graphene_point3d_init (&pv->vertices[3], min.x, max.y, min.z);
graphene_point3d_init (&pv->vertices[4], min.x, min.y, max.z);
/* grow down */
/* bottom vertices 2, 3, 6, 7 */
if (another_pv->vertices[3].y > pv->vertices[3].y)
{
int may_y = another_pv->vertices[3].y;
/* pv->vertices[2].y = may_y; */
pv->vertices[3].y = may_y;
/* pv->vertices[6].y = may_y; */
/* pv->vertices[7].y = may_y; */
}
/* grow forward */
/* front vertices 0, 1, 2, 3 */
if (another_pv->vertices[0].z < pv->vertices[0].z)
{
int min_z = another_pv->vertices[0].z;
pv->vertices[0].z = min_z;
pv->vertices[1].z = min_z;
/* pv->vertices[2].z = min_z; */
pv->vertices[3].z = min_z;
}
/* grow backward */
/* back vertices 4, 5, 6, 7 */
if (another_pv->vertices[4].z > pv->vertices[4].z)
{
int maz_z = another_pv->vertices[4].z;
pv->vertices[4].z = maz_z;
/* pv->vertices[5].z = maz_z; */
/* pv->vertices[6].z = maz_z; */
/* pv->vertices[7].z = maz_z; */
}
if (pv->vertices[4].z == pv->vertices[0].z)
pv->is_2d = TRUE;
@ -766,8 +808,8 @@ _clutter_paint_volume_get_bounding_box (ClutterPaintVolume *pv,
void
_clutter_paint_volume_project (ClutterPaintVolume *pv,
const graphene_matrix_t *modelview,
const graphene_matrix_t *projection,
const CoglMatrix *modelview,
const CoglMatrix *projection,
const float *viewport)
{
int transform_count;
@ -785,7 +827,7 @@ _clutter_paint_volume_project (ClutterPaintVolume *pv,
}
/* All the vertices must be up to date, since after the projection
* it won't be trivial to derive the other vertices. */
* it wont be trivial to derive the other vertices. */
_clutter_paint_volume_complete (pv);
/* Most actors are 2D so we only have to transform the front 4
@ -807,7 +849,7 @@ _clutter_paint_volume_project (ClutterPaintVolume *pv,
void
_clutter_paint_volume_transform (ClutterPaintVolume *pv,
const graphene_matrix_t *matrix)
const CoglMatrix *matrix)
{
int transform_count;
@ -815,16 +857,16 @@ _clutter_paint_volume_transform (ClutterPaintVolume *pv,
{
gfloat w = 1;
/* Just transform the origin */
cogl_graphene_matrix_project_point (matrix,
&pv->vertices[0].x,
&pv->vertices[0].y,
&pv->vertices[0].z,
&w);
cogl_matrix_transform_point (matrix,
&pv->vertices[0].x,
&pv->vertices[0].y,
&pv->vertices[0].z,
&w);
return;
}
/* All the vertices must be up to date, since after the transform
* it won't be trivial to derive the other vertices. */
* it wont be trivial to derive the other vertices. */
_clutter_paint_volume_complete (pv);
/* Most actors are 2D so we only have to transform the front 4
@ -834,13 +876,13 @@ _clutter_paint_volume_transform (ClutterPaintVolume *pv,
else
transform_count = 8;
cogl_graphene_matrix_transform_points (matrix,
3,
sizeof (graphene_point3d_t),
pv->vertices,
sizeof (graphene_point3d_t),
pv->vertices,
transform_count);
cogl_matrix_transform_points (matrix,
3,
sizeof (graphene_point3d_t),
pv->vertices,
sizeof (graphene_point3d_t),
pv->vertices,
transform_count);
pv->is_axis_aligned = FALSE;
}
@ -1015,9 +1057,9 @@ clutter_paint_volume_set_from_allocation (ClutterPaintVolume *pv,
}
/* Currently paint volumes are defined relative to a given actor, but
* in some cases it is desirable to be able to change the actor that
* in some cases it is desireable to be able to change the actor that
* a volume relates too (For instance for ClutterClone actors where we
* need to masquerade the source actors volume as the volume for the
* need to masquarade the source actors volume as the volume for the
* clone). */
void
_clutter_paint_volume_set_reference_actor (ClutterPaintVolume *pv,
@ -1029,11 +1071,14 @@ _clutter_paint_volume_set_reference_actor (ClutterPaintVolume *pv,
}
ClutterCullResult
_clutter_paint_volume_cull (ClutterPaintVolume *pv,
const graphene_frustum_t *frustum)
_clutter_paint_volume_cull (ClutterPaintVolume *pv,
const ClutterPlane *planes)
{
int vertex_count;
graphene_box_t box;
graphene_point3d_t *vertices = pv->vertices;
gboolean partial = FALSE;
int i;
int j;
if (pv->is_empty)
return CLUTTER_CULL_RESULT_OUT;
@ -1050,12 +1095,33 @@ _clutter_paint_volume_cull (ClutterPaintVolume *pv,
else
vertex_count = 8;
graphene_box_init_from_points (&box, vertex_count, pv->vertices);
for (i = 0; i < 4; i++)
{
const ClutterPlane *plane = &planes[i];
int out = 0;
for (j = 0; j < vertex_count; j++)
{
graphene_vec3_t v;
if (graphene_frustum_intersects_box (frustum, &box))
return CLUTTER_CULL_RESULT_IN;
graphene_vec3_init (&v,
vertices[j].x - graphene_vec3_get_x (&plane->v0),
vertices[j].y - graphene_vec3_get_y (&plane->v0),
vertices[j].z - graphene_vec3_get_z (&plane->v0));
if (graphene_vec3_dot (&plane->n, &v) < 0)
out++;
}
if (out == vertex_count)
return CLUTTER_CULL_RESULT_OUT;
else if (out != 0)
partial = TRUE;
}
if (partial)
return CLUTTER_CULL_RESULT_PARTIAL;
else
return CLUTTER_CULL_RESULT_OUT;
return CLUTTER_CULL_RESULT_IN;
}
void
@ -1064,13 +1130,13 @@ _clutter_paint_volume_get_stage_paint_box (ClutterPaintVolume *pv,
ClutterActorBox *box)
{
ClutterPaintVolume projected_pv;
graphene_matrix_t modelview;
graphene_matrix_t projection;
CoglMatrix modelview;
CoglMatrix projection;
float viewport[4];
_clutter_paint_volume_copy_static (pv, &projected_pv);
graphene_matrix_init_identity (&modelview);
cogl_matrix_init_identity (&modelview);
/* If the paint volume isn't already in eye coordinates... */
if (pv->actor)
@ -1115,7 +1181,7 @@ void
_clutter_paint_volume_transform_relative (ClutterPaintVolume *pv,
ClutterActor *relative_to_ancestor)
{
graphene_matrix_t matrix;
CoglMatrix matrix;
ClutterActor *actor;
actor = pv->actor;
@ -1124,32 +1190,10 @@ _clutter_paint_volume_transform_relative (ClutterPaintVolume *pv,
_clutter_paint_volume_set_reference_actor (pv, relative_to_ancestor);
graphene_matrix_init_identity (&matrix);
cogl_matrix_init_identity (&matrix);
_clutter_actor_apply_relative_transformation_matrix (actor,
relative_to_ancestor,
&matrix);
_clutter_paint_volume_transform (pv, &matrix);
}
void
clutter_paint_volume_to_box (ClutterPaintVolume *pv,
graphene_box_t *box)
{
int vertex_count;
if (pv->is_empty)
{
graphene_box_init_from_box (box, graphene_box_empty ());
return;
}
_clutter_paint_volume_complete (pv);
if (G_LIKELY (pv->is_2d))
vertex_count = 4;
else
vertex_count = 8;
graphene_box_init_from_points (box, vertex_count, pv->vertices);
}

View File

@ -354,15 +354,12 @@ clutter_pan_action_real_pan (ClutterPanAction *self,
gboolean is_interpolated)
{
gfloat dx, dy;
graphene_matrix_t transform;
graphene_matrix_t translate;
ClutterMatrix transform;
clutter_pan_action_get_constrained_motion_delta (self, 0, &dx, &dy);
clutter_actor_get_child_transform (actor, &transform);
graphene_matrix_init_translate (&translate,
&GRAPHENE_POINT3D_INIT (dx, dy, 0.0f));
graphene_matrix_multiply (&translate, &transform, &transform);
cogl_matrix_translate (&transform, dx, dy, 0.0f);
clutter_actor_set_child_transform (actor, &transform);
return TRUE;
}

View File

@ -314,7 +314,7 @@ clutter_path_add_node_full (ClutterPath *path,
priv->nodes_dirty = TRUE;
}
/* Helper function to make the rest of the add_* functions shorter */
/* Helper function to make the rest of teh add_* functions shorter */
static void
clutter_path_add_node_helper (ClutterPath *path,
ClutterPathNodeType type,
@ -1446,7 +1446,7 @@ clutter_path_get_length (ClutterPath *path)
static ClutterPathNodeFull *
clutter_path_node_full_new (void)
{
return g_new0 (ClutterPathNodeFull, 1);
return g_slice_new0 (ClutterPathNodeFull);
}
static void
@ -1455,7 +1455,7 @@ clutter_path_node_full_free (ClutterPathNodeFull *node)
if (node->bezier)
_clutter_bezier_free (node->bezier);
g_free (node);
g_slice_free (ClutterPathNodeFull, node);
}
/**
@ -1471,7 +1471,7 @@ clutter_path_node_full_free (ClutterPathNodeFull *node)
ClutterPathNode *
clutter_path_node_copy (const ClutterPathNode *node)
{
return g_memdup2 (node, sizeof (ClutterPathNode));
return g_slice_dup (ClutterPathNode, node);
}
/**
@ -1486,7 +1486,7 @@ void
clutter_path_node_free (ClutterPathNode *node)
{
if (G_LIKELY (node))
g_free (node);
g_slice_free (ClutterPathNode, node);
}
/**
@ -1550,7 +1550,7 @@ clutter_knot_copy (const ClutterKnot *knot)
if (G_UNLIKELY (knot == NULL))
return NULL;
return g_memdup2 (knot, sizeof (ClutterKnot));
return g_slice_dup (ClutterKnot, knot);
}
/**
@ -1565,7 +1565,7 @@ void
clutter_knot_free (ClutterKnot *knot)
{
if (G_LIKELY (knot != NULL))
g_free (knot);
g_slice_free (ClutterKnot, knot);
}
/**

View File

@ -19,19 +19,7 @@
#define CLUTTER_PICK_CONTEXT_PRIVATE_H
#include "clutter-pick-context.h"
#include "clutter-pick-stack-private.h"
ClutterPickContext *
clutter_pick_context_new_for_view (ClutterStageView *view,
ClutterPickMode mode,
const graphene_point3d_t *point,
const graphene_ray_t *ray);
ClutterPickStack *
clutter_pick_context_steal_stack (ClutterPickContext *pick_context);
gboolean
clutter_pick_context_intersects_box (ClutterPickContext *pick_context,
const graphene_box_t *box);
ClutterPickContext * clutter_pick_context_new_for_view (ClutterStageView *view);
#endif /* CLUTTER_PICK_CONTEXT_PRIVATE_H */

View File

@ -17,18 +17,13 @@
#include "clutter-build-config.h"
#include "clutter-backend.h"
#include "clutter-pick-context-private.h"
struct _ClutterPickContext
{
grefcount ref_count;
ClutterPickMode mode;
ClutterPickStack *pick_stack;
graphene_ray_t ray;
graphene_point3d_t point;
CoglFramebuffer *framebuffer;
};
G_DEFINE_BOXED_TYPE (ClutterPickContext, clutter_pick_context,
@ -36,22 +31,14 @@ G_DEFINE_BOXED_TYPE (ClutterPickContext, clutter_pick_context,
clutter_pick_context_unref)
ClutterPickContext *
clutter_pick_context_new_for_view (ClutterStageView *view,
ClutterPickMode mode,
const graphene_point3d_t *point,
const graphene_ray_t *ray)
clutter_pick_context_new_for_view (ClutterStageView *view)
{
ClutterPickContext *pick_context;
CoglContext *context;
pick_context = g_new0 (ClutterPickContext, 1);
g_ref_count_init (&pick_context->ref_count);
pick_context->mode = mode;
graphene_ray_init_from_ray (&pick_context->ray, ray);
graphene_point3d_init_from_point (&pick_context->point, point);
context = clutter_backend_get_cogl_context (clutter_get_default_backend ());
pick_context->pick_stack = clutter_pick_stack_new (context);
pick_context->framebuffer =
cogl_object_ref (clutter_stage_view_get_framebuffer (view));
return pick_context;
}
@ -66,7 +53,7 @@ clutter_pick_context_ref (ClutterPickContext *pick_context)
static void
clutter_pick_context_dispose (ClutterPickContext *pick_context)
{
g_clear_pointer (&pick_context->pick_stack, clutter_pick_stack_unref);
g_clear_pointer (&pick_context->framebuffer, cogl_object_unref);
}
void
@ -87,113 +74,10 @@ clutter_pick_context_destroy (ClutterPickContext *pick_context)
}
/**
* clutter_pick_context_get_mode: (skip)
* clutter_pick_context_get_framebuffer: (skip)
*/
ClutterPickMode
clutter_pick_context_get_mode (ClutterPickContext *pick_context)
CoglFramebuffer *
clutter_pick_context_get_framebuffer (ClutterPickContext *pick_context)
{
return pick_context->mode;
}
ClutterPickStack *
clutter_pick_context_steal_stack (ClutterPickContext *pick_context)
{
clutter_pick_stack_seal (pick_context->pick_stack);
return g_steal_pointer (&pick_context->pick_stack);
}
/**
* clutter_pick_context_log_pick:
* @pick_context: a #ClutterPickContext
* @box: a #ClutterActorBox
* @actor: a #ClutterActor
*
* Logs a pick rectangle into the pick stack.
*/
void
clutter_pick_context_log_pick (ClutterPickContext *pick_context,
const ClutterActorBox *box,
ClutterActor *actor)
{
clutter_pick_stack_log_pick (pick_context->pick_stack, box, actor);
}
/**
* clutter_pick_context_push_clip:
* @pick_context: a #ClutterPickContext
* @box: a #ClutterActorBox
*
* Pushes a clip rectangle defined by @box into the pick stack. Pop with
* clutter_pick_context_pop_clip() when done.
*/
void
clutter_pick_context_push_clip (ClutterPickContext *pick_context,
const ClutterActorBox *box)
{
clutter_pick_stack_push_clip (pick_context->pick_stack, box);
}
/**
* clutter_pick_context_pop_clip:
* @pick_context: a #ClutterPickContext
*
* Pops the current clip rectangle from the clip stack. It is a programming
* error to call this without a corresponding clutter_pick_context_push_clip()
* call first.
*/
void
clutter_pick_context_pop_clip (ClutterPickContext *pick_context)
{
clutter_pick_stack_pop_clip (pick_context->pick_stack);
}
/**
* clutter_pick_context_push_transform:
* @pick_context: a #ClutterPickContext
* @transform: a #graphene_matrix_t
*
* Pushes @transform into the pick stack. Pop with
* clutter_pick_context_pop_transform() when done.
*/
void
clutter_pick_context_push_transform (ClutterPickContext *pick_context,
const graphene_matrix_t *transform)
{
clutter_pick_stack_push_transform (pick_context->pick_stack, transform);
}
/**
* clutter_pick_context_get_transform:
* @pick_context: a #ClutterPickContext
* @out_matrix: (out): a #graphene_matrix_t
*
* Retrieves the current transform of the pick stack.
*/
void
clutter_pick_context_get_transform (ClutterPickContext *pick_context,
graphene_matrix_t *out_transform)
{
clutter_pick_stack_get_transform (pick_context->pick_stack, out_transform);
}
/**
* clutter_pick_context_pop_transform:
* @pick_context: a #ClutterPickContext
*
* Pops the current transform from the clip stack. It is a programming error
* to call this without a corresponding clutter_pick_context_push_transform()
* call first.
*/
void
clutter_pick_context_pop_transform (ClutterPickContext *pick_context)
{
clutter_pick_stack_pop_transform (pick_context->pick_stack);
}
gboolean
clutter_pick_context_intersects_box (ClutterPickContext *pick_context,
const graphene_box_t *box)
{
return graphene_box_contains_point (box, &pick_context->point) ||
graphene_ray_intersects_box (&pick_context->ray, box);
return pick_context->framebuffer;
}

View File

@ -44,29 +44,6 @@ CLUTTER_EXPORT
void clutter_pick_context_destroy (ClutterPickContext *pick_context);
CLUTTER_EXPORT
ClutterPickMode clutter_pick_context_get_mode (ClutterPickContext *pick_context);
CLUTTER_EXPORT
void clutter_pick_context_log_pick (ClutterPickContext *pick_context,
const ClutterActorBox *box,
ClutterActor *actor);
CLUTTER_EXPORT
void clutter_pick_context_push_clip (ClutterPickContext *pick_context,
const ClutterActorBox *box);
CLUTTER_EXPORT
void clutter_pick_context_pop_clip (ClutterPickContext *pick_context);
CLUTTER_EXPORT
void clutter_pick_context_push_transform (ClutterPickContext *pick_context,
const graphene_matrix_t *transform);
CLUTTER_EXPORT
void clutter_pick_context_get_transform (ClutterPickContext *pick_context,
graphene_matrix_t *out_matrix);
CLUTTER_EXPORT
void clutter_pick_context_pop_transform (ClutterPickContext *pick_context);
CoglFramebuffer * clutter_pick_context_get_framebuffer (ClutterPickContext *pick_context);
#endif /* CLUTTER_PICK_CONTEXT_H */

View File

@ -1,68 +0,0 @@
/*
* Copyright (C) 2020 Endless OS Foundation, LLC
*
* 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/>.
*/
#ifndef CLUTTER_PICK_STACK_PRIVATE_H
#define CLUTTER_PICK_STACK_PRIVATE_H
#include <glib-object.h>
#include "clutter-macros.h"
#include "clutter-stage-view.h"
G_BEGIN_DECLS
#define CLUTTER_TYPE_PICK_STACK (clutter_pick_stack_get_type ())
typedef struct _ClutterPickStack ClutterPickStack;
GType clutter_pick_stack_get_type (void) G_GNUC_CONST;
ClutterPickStack * clutter_pick_stack_new (CoglContext *context);
ClutterPickStack * clutter_pick_stack_ref (ClutterPickStack *pick_stack);
void clutter_pick_stack_unref (ClutterPickStack *pick_stack);
void clutter_pick_stack_seal (ClutterPickStack *pick_stack);
void clutter_pick_stack_log_pick (ClutterPickStack *pick_stack,
const ClutterActorBox *box,
ClutterActor *actor);
void clutter_pick_stack_push_clip (ClutterPickStack *pick_stack,
const ClutterActorBox *box);
void clutter_pick_stack_pop_clip (ClutterPickStack *pick_stack);
void clutter_pick_stack_push_transform (ClutterPickStack *pick_stack,
const graphene_matrix_t *transform);
void clutter_pick_stack_get_transform (ClutterPickStack *pick_stack,
graphene_matrix_t *out_transform);
void clutter_pick_stack_pop_transform (ClutterPickStack *pick_stack);
ClutterActor *
clutter_pick_stack_search_actor (ClutterPickStack *pick_stack,
const graphene_point3d_t *point,
const graphene_ray_t *ray);
G_DEFINE_AUTOPTR_CLEANUP_FUNC (ClutterPickStack, clutter_pick_stack_unref)
G_END_DECLS
#endif /* CLUTTER_PICK_STACK_PRIVATE_H */

View File

@ -1,436 +0,0 @@
/*
* Copyright (C) 2020 Endless OS Foundation, LLC
* Copyright (C) 2018 Canonical Ltd.
*
* 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/>.
*/
#include "clutter-pick-stack-private.h"
#include "clutter-private.h"
typedef struct
{
graphene_point3d_t vertices[4];
CoglMatrixEntry *matrix_entry;
ClutterActorBox rect;
gboolean projected;
} Record;
typedef struct
{
Record base;
ClutterActor *actor;
int clip_index;
} PickRecord;
typedef struct
{
Record base;
int prev;
} PickClipRecord;
struct _ClutterPickStack
{
grefcount ref_count;
CoglMatrixStack *matrix_stack;
GArray *vertices_stack;
GArray *clip_stack;
int current_clip_stack_top;
gboolean sealed : 1;
};
G_DEFINE_BOXED_TYPE (ClutterPickStack, clutter_pick_stack,
clutter_pick_stack_ref, clutter_pick_stack_unref)
static void
project_vertices (CoglMatrixEntry *matrix_entry,
const ClutterActorBox *box,
graphene_point3d_t vertices[4])
{
graphene_matrix_t m;
int i;
cogl_matrix_entry_get (matrix_entry, &m);
graphene_point3d_init (&vertices[0], box->x1, box->y1, 0.f);
graphene_point3d_init (&vertices[1], box->x2, box->y1, 0.f);
graphene_point3d_init (&vertices[2], box->x2, box->y2, 0.f);
graphene_point3d_init (&vertices[3], box->x1, box->y2, 0.f);
for (i = 0; i < 4; i++)
{
float w = 1.f;
cogl_graphene_matrix_project_point (&m,
&vertices[i].x,
&vertices[i].y,
&vertices[i].z,
&w);
}
}
static void
maybe_project_record (Record *rec)
{
if (!rec->projected)
{
project_vertices (rec->matrix_entry, &rec->rect, rec->vertices);
rec->projected = TRUE;
}
}
static inline gboolean
is_axis_aligned_2d_rectangle (const graphene_point3d_t vertices[4])
{
int i;
for (i = 0; i < 4; i++)
{
if (!G_APPROX_VALUE (vertices[i].z,
vertices[(i + 1) % 4].z,
FLT_EPSILON))
return FALSE;
if (!G_APPROX_VALUE (vertices[i].x,
vertices[(i + 1) % 4].x,
FLT_EPSILON) &&
!G_APPROX_VALUE (vertices[i].y,
vertices[(i + 1) % 4].y,
FLT_EPSILON))
return FALSE;
}
return TRUE;
}
static gboolean
ray_intersects_input_region (Record *rec,
const graphene_ray_t *ray,
const graphene_point3d_t *point)
{
maybe_project_record (rec);
if (G_LIKELY (is_axis_aligned_2d_rectangle (rec->vertices)))
{
graphene_box_t box;
graphene_box_t right_border;
graphene_box_t bottom_border;
/* Graphene considers both the start and end coordinates of boxes to be
* inclusive, while the vertices of a clutter actor are exclusive. So we
* need to manually exclude hits on these borders
*/
graphene_box_init_from_points (&box, 4, rec->vertices);
graphene_box_init_from_points (&right_border, 2, rec->vertices + 1);
graphene_box_init_from_points (&bottom_border, 2, rec->vertices + 2);
/* Fast path for actors without 3D transforms */
if (graphene_box_contains_point (&box, point))
{
return !graphene_box_contains_point (&right_border, point) &&
!graphene_box_contains_point (&bottom_border, point);
}
return graphene_ray_intersects_box (ray, &box) &&
!graphene_ray_intersects_box (ray, &right_border) &&
!graphene_ray_intersects_box (ray, &bottom_border);
}
else
{
graphene_triangle_t t0, t1;
/*
* Degrade the projected quad into the following triangles:
*
* 0 -------------- 1
* | |
* | t0 |
* | |
* | t1 |
* | |
* 3 -------------- 2
*/
graphene_triangle_init_from_point3d (&t0,
&rec->vertices[0],
&rec->vertices[1],
&rec->vertices[2]);
graphene_triangle_init_from_point3d (&t1,
&rec->vertices[0],
&rec->vertices[2],
&rec->vertices[3]);
return graphene_triangle_contains_point (&t0, point) ||
graphene_triangle_contains_point (&t1, point) ||
graphene_ray_intersects_triangle (ray, &t0) ||
graphene_ray_intersects_triangle (ray, &t1);
}
}
static gboolean
ray_intersects_record (ClutterPickStack *pick_stack,
PickRecord *rec,
const graphene_point3d_t *point,
const graphene_ray_t *ray)
{
int clip_index;
if (!ray_intersects_input_region (&rec->base, ray, point))
return FALSE;
clip_index = rec->clip_index;
while (clip_index >= 0)
{
PickClipRecord *clip =
&g_array_index (pick_stack->clip_stack, PickClipRecord, clip_index);
if (!ray_intersects_input_region (&clip->base, ray, point))
return FALSE;
clip_index = clip->prev;
}
return TRUE;
}
static void
add_pick_stack_weak_refs (ClutterPickStack *pick_stack)
{
int i;
g_assert (!pick_stack->sealed);
for (i = 0; i < pick_stack->vertices_stack->len; i++)
{
PickRecord *rec =
&g_array_index (pick_stack->vertices_stack, PickRecord, i);
if (rec->actor)
g_object_add_weak_pointer (G_OBJECT (rec->actor),
(gpointer) &rec->actor);
}
}
static void
remove_pick_stack_weak_refs (ClutterPickStack *pick_stack)
{
int i;
for (i = 0; i < pick_stack->vertices_stack->len; i++)
{
PickRecord *rec =
&g_array_index (pick_stack->vertices_stack, PickRecord, i);
if (rec->actor)
g_object_remove_weak_pointer (G_OBJECT (rec->actor),
(gpointer) &rec->actor);
}
}
static void
clutter_pick_stack_dispose (ClutterPickStack *pick_stack)
{
remove_pick_stack_weak_refs (pick_stack);
g_clear_pointer (&pick_stack->matrix_stack, cogl_object_unref);
g_clear_pointer (&pick_stack->vertices_stack, g_array_unref);
g_clear_pointer (&pick_stack->clip_stack, g_array_unref);
}
static void
clear_pick_record (gpointer data)
{
PickRecord *rec = data;
g_clear_pointer (&rec->base.matrix_entry, cogl_matrix_entry_unref);
}
static void
clear_clip_record (gpointer data)
{
PickClipRecord *clip = data;
g_clear_pointer (&clip->base.matrix_entry, cogl_matrix_entry_unref);
}
/**
* clutter_pick_stack_new:
* @context: a #CoglContext
*
* Creates a new #ClutterPickStack.
*
* Returns: (transfer full): A newly created #ClutterPickStack
*/
ClutterPickStack *
clutter_pick_stack_new (CoglContext *context)
{
ClutterPickStack *pick_stack;
pick_stack = g_new0 (ClutterPickStack, 1);
g_ref_count_init (&pick_stack->ref_count);
pick_stack->matrix_stack = cogl_matrix_stack_new (context);
pick_stack->vertices_stack = g_array_new (FALSE, FALSE, sizeof (PickRecord));
pick_stack->clip_stack = g_array_new (FALSE, FALSE, sizeof (PickClipRecord));
pick_stack->current_clip_stack_top = -1;
g_array_set_clear_func (pick_stack->vertices_stack, clear_pick_record);
g_array_set_clear_func (pick_stack->clip_stack, clear_clip_record);
return pick_stack;
}
/**
* clutter_pick_stack_ref:
* @pick_stack: A #ClutterPickStack
*
* Increments the reference count of @pick_stack by one.
*
* Returns: (transfer full): @pick_stack
*/
ClutterPickStack *
clutter_pick_stack_ref (ClutterPickStack *pick_stack)
{
g_ref_count_inc (&pick_stack->ref_count);
return pick_stack;
}
/**
* clutter_pick_stack_unref:
* @pick_stack: A #ClutterPickStack
*
* Decrements the reference count of @pick_stack by one, freeing the structure
* when the reference count reaches zero.
*/
void
clutter_pick_stack_unref (ClutterPickStack *pick_stack)
{
if (g_ref_count_dec (&pick_stack->ref_count))
{
clutter_pick_stack_dispose (pick_stack);
g_free (pick_stack);
}
}
void
clutter_pick_stack_seal (ClutterPickStack *pick_stack)
{
g_assert (!pick_stack->sealed);
add_pick_stack_weak_refs (pick_stack);
pick_stack->sealed = TRUE;
}
void
clutter_pick_stack_log_pick (ClutterPickStack *pick_stack,
const ClutterActorBox *box,
ClutterActor *actor)
{
PickRecord rec;
g_return_if_fail (actor != NULL);
g_assert (!pick_stack->sealed);
rec.actor = actor;
rec.clip_index = pick_stack->current_clip_stack_top;
rec.base.rect = *box;
rec.base.projected = FALSE;
rec.base.matrix_entry = cogl_matrix_stack_get_entry (pick_stack->matrix_stack);
cogl_matrix_entry_ref (rec.base.matrix_entry);
g_array_append_val (pick_stack->vertices_stack, rec);
}
void
clutter_pick_stack_push_clip (ClutterPickStack *pick_stack,
const ClutterActorBox *box)
{
PickClipRecord clip;
g_assert (!pick_stack->sealed);
clip.prev = pick_stack->current_clip_stack_top;
clip.base.rect = *box;
clip.base.projected = FALSE;
clip.base.matrix_entry = cogl_matrix_stack_get_entry (pick_stack->matrix_stack);
cogl_matrix_entry_ref (clip.base.matrix_entry);
g_array_append_val (pick_stack->clip_stack, clip);
pick_stack->current_clip_stack_top = pick_stack->clip_stack->len - 1;
}
void
clutter_pick_stack_pop_clip (ClutterPickStack *pick_stack)
{
const PickClipRecord *top;
g_assert (!pick_stack->sealed);
g_assert (pick_stack->current_clip_stack_top >= 0);
/* Individual elements of clip_stack are not freed. This is so they can
* be shared as part of a tree of different stacks used by different
* actors in the pick_stack. The whole clip_stack does however get
* freed later in clutter_pick_stack_dispose.
*/
top = &g_array_index (pick_stack->clip_stack,
PickClipRecord,
pick_stack->current_clip_stack_top);
pick_stack->current_clip_stack_top = top->prev;
}
void
clutter_pick_stack_push_transform (ClutterPickStack *pick_stack,
const graphene_matrix_t *transform)
{
cogl_matrix_stack_push (pick_stack->matrix_stack);
cogl_matrix_stack_multiply (pick_stack->matrix_stack, transform);
}
void
clutter_pick_stack_get_transform (ClutterPickStack *pick_stack,
graphene_matrix_t *out_transform)
{
cogl_matrix_stack_get (pick_stack->matrix_stack, out_transform);
}
void
clutter_pick_stack_pop_transform (ClutterPickStack *pick_stack)
{
cogl_matrix_stack_pop (pick_stack->matrix_stack);
}
ClutterActor *
clutter_pick_stack_search_actor (ClutterPickStack *pick_stack,
const graphene_point3d_t *point,
const graphene_ray_t *ray)
{
int i;
/* Search all "painted" pickable actors from front to back. A linear search
* is required, and also performs fine since there is typically only
* on the order of dozens of actors in the list (on screen) at a time.
*/
for (i = pick_stack->vertices_stack->len - 1; i >= 0; i--)
{
PickRecord *rec =
&g_array_index (pick_stack->vertices_stack, PickRecord, i);
if (rec->actor && ray_intersects_record (pick_stack, rec, point, ray))
return rec->actor;
}
return NULL;
}

View File

@ -44,6 +44,7 @@
G_BEGIN_DECLS
typedef struct _ClutterMainContext ClutterMainContext;
typedef struct _ClutterVertex4 ClutterVertex4;
#define CLUTTER_REGISTER_VALUE_TRANSFORM_TO(TYPE_TO,func) { \
g_value_register_transform_func (g_define_type_id, TYPE_TO, func); \
@ -127,6 +128,8 @@ struct _ClutterMainContext
* ordered from least recently added to most recently added */
GList *event_filters;
ClutterPickMode pick_mode;
/* default FPS; this is only used if we cannot sync to vblank */
guint frame_rate;
@ -173,8 +176,8 @@ void _clutter_threads_dispatch_free (gpointer data);
ClutterMainContext * _clutter_context_get_default (void);
void _clutter_context_lock (void);
void _clutter_context_unlock (void);
CLUTTER_EXPORT
gboolean _clutter_context_is_initialized (void);
ClutterPickMode _clutter_context_get_pick_mode (void);
gboolean _clutter_context_get_show_fps (void);
gboolean _clutter_feature_init (GError **error);
@ -208,18 +211,16 @@ void _clutter_run_repaint_functions (ClutterRepaintFlags flags);
GType _clutter_layout_manager_get_child_meta_type (ClutterLayoutManager *manager);
void _clutter_util_fully_transform_vertices (const graphene_matrix_t *modelview,
const graphene_matrix_t *projection,
void _clutter_util_fully_transform_vertices (const CoglMatrix *modelview,
const CoglMatrix *projection,
const float *viewport,
const graphene_point3d_t *vertices_in,
graphene_point3d_t *vertices_out,
int n_vertices);
CLUTTER_EXPORT
void _clutter_util_rect_from_rectangle (const cairo_rectangle_int_t *src,
graphene_rect_t *dest);
CLUTTER_EXPORT
void _clutter_util_rectangle_int_extents (const graphene_rect_t *src,
cairo_rectangle_int_t *dest);
@ -239,17 +240,62 @@ gboolean _clutter_util_rectangle_intersection (const cairo_rectangle_int_t *src1
gboolean clutter_util_rectangle_equal (const cairo_rectangle_int_t *src1,
const cairo_rectangle_int_t *src2);
struct _ClutterVertex4
{
float x;
float y;
float z;
float w;
};
void
_clutter_util_vertex4_interpolate (const ClutterVertex4 *a,
const ClutterVertex4 *b,
double progress,
ClutterVertex4 *res);
#define CLUTTER_MATRIX_INIT_IDENTITY { \
1.0f, 0.0f, 0.0f, 0.0f, \
0.0f, 1.0f, 0.0f, 0.0f, \
0.0f, 0.0f, 1.0f, 0.0f, \
0.0f, 0.0f, 0.0f, 1.0f, \
}
float _clutter_util_matrix_determinant (const ClutterMatrix *matrix);
void _clutter_util_matrix_skew_xy (ClutterMatrix *matrix,
float factor);
void _clutter_util_matrix_skew_xz (ClutterMatrix *matrix,
float factor);
void _clutter_util_matrix_skew_yz (ClutterMatrix *matrix,
float factor);
gboolean _clutter_util_matrix_decompose (const ClutterMatrix *src,
graphene_point3d_t *scale_p,
float shear_p[3],
graphene_point3d_t *rotate_p,
graphene_point3d_t *translate_p,
ClutterVertex4 *perspective_p);
CLUTTER_EXPORT
PangoDirection _clutter_pango_unichar_direction (gunichar ch);
PangoDirection _clutter_pango_find_base_dir (const gchar *text,
gint length);
typedef struct _ClutterPlane
{
graphene_vec3_t v0;
graphene_vec3_t n;
} ClutterPlane;
typedef enum _ClutterCullResult
{
CLUTTER_CULL_RESULT_UNKNOWN,
CLUTTER_CULL_RESULT_IN,
CLUTTER_CULL_RESULT_OUT,
CLUTTER_CULL_RESULT_PARTIAL
} ClutterCullResult;
gboolean _clutter_has_progress_function (GType gtype);
@ -261,78 +307,36 @@ gboolean _clutter_run_progress_function (GType gtype,
void clutter_timeline_cancel_delay (ClutterTimeline *timeline);
static inline void
clutter_round_to_256ths (float *f)
{
*f = roundf ((*f) * 256) / 256;
}
static inline uint64_t
ns (uint64_t ns)
{
return ns;
}
static inline int64_t
us (int64_t us)
us (uint64_t us)
{
return us;
}
static inline int64_t
ms (int64_t ms)
static inline uint32_t
ms (uint32_t ms)
{
return ms;
}
static inline int64_t
ms2us (int64_t ms)
static inline uint64_t
ms2us (uint64_t ms)
{
return us (ms * 1000);
}
static inline int64_t
us2ns (int64_t us)
static inline uint32_t
us2ms (uint64_t us)
{
return ns (us * 1000);
return (uint32_t) (us / 1000);
}
static inline int64_t
us2ms (int64_t us)
{
return (int64_t) (us / 1000);
}
static inline int64_t
ns2us (int64_t ns)
static inline uint64_t
ns2us (uint64_t ns)
{
return us (ns / 1000);
}
static inline int64_t
s2us (int64_t s)
{
return s * G_USEC_PER_SEC;
}
static inline int64_t
us2s (int64_t us)
{
return us / G_USEC_PER_SEC;
}
static inline int64_t
s2ns (int64_t s)
{
return us2ns (s2us (s));
}
static inline int64_t
s2ms (int64_t s)
{
return (int64_t) ms (s * 1000);
}
G_END_DECLS
#endif /* __CLUTTER_PRIVATE_H__ */

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