Compare commits

...

146 Commits

Author SHA1 Message Date
2efd0dfc06 cogl tests: Show the actual output from tests if VERBOSE is set
Writing tests' output to a log file makes them difficult to debug when
the test might be running on an autobuilder or CI system where only
stdout/stderr are recorded. This is particularly troublesome if a
failure is only reproducible on a particular autobuilder.

Recent Automake versions have the convention that detailed output from
failing tests is written to stdout/stderr, not just to log files, when
the VERBOSE environment variable is set; borrow that convention as a
trigger for producing detailed test output.

This was originally cogl!14, but applies equally to mutter's fork of cogl.

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

Signed-off-by: Simon McVittie <smcv@debian.org>
2020-05-27 15:50:21 +01:00
0b6a3166ed clutter/text: Also queue relayout if the actor has no valid allocation
In clutter_text_queue_redraw_or_relayout() we check whether the size
of the layout has changed and queue a relayout if it did, otherwise we
only queue a redraw and save some resources.

The current check for this also queues a redraw if the actor has no
valid allocation. That seems right on the first glance since the actor
will be allocated anyway, but we actually want to call
clutter_actor_queue_relayout() again here because that also invalidates
the size cache of the actor which might have been updated and marked
valid in the meantime.

So make sure the size cache is always properly invalidated after the
size of the layout changed and also call clutter_actor_queue_relayout()
in case the actor has no allocation.

This fixes a bug where getting the preferred width of a non-allocated
ClutterText, then changing the string of the ClutterText, and then
getting the preferred width again would return the old cached width (the
width before we changed the string).

The only place where this bug is currently happening is in the overview,
where we call get_preferred_width() on the unallocated ClutterText of
the window clone title: When the window title changes while the
ClutterText is unallocated the size of the title is going to be wrong
and the text might end up ellipsized or too large.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1150
2020-05-27 08:41:31 +00:00
066bc5986d wayland: Drive frame callbacks from stage updates
Don't tie frame callbacks to actor painting, as it may end up in
situations where we miss sending frame callbacks when we should have. An
example of this is when a surface is partially off screen, and then
reports damage that is fully off screen. When this happen, we are likely
not to repaint anything, thus we won't send any frame callbacks even
though it's "suitable" for rendering again, as the surface is not on a
separate workspace or fully obscured.

Closes: https://gitlab.gnome.org/GNOME/mutter/-/issues/817
Closes: https://gitlab.gnome.org/GNOME/mutter/-/issues/1152

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1218
2020-05-26 16:46:57 +02:00
e8b09df8d2 wayland/compositor: Pass backend when constructing
This is so that it can be retrieved later without going via the global
singleton.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1218
2020-05-26 16:35:01 +02:00
1571f8078a Reshuffle Wayland initailization
Move Wayland support (i.e. the MetaWaylandCompositor object) made to be
part of the backend. This is due to the fact that it is needed by the
backend initialization, e.g. the Wayland EGLDisplay server support.

The backend is changed to be more involved in Wayland and clutter
initialization, so that the parts needed for clutter initialization
happens before clutter itself initialization happens, and the rest
happens after. This simplifies the setup a bit, as clutter and Wayland
init now happens as part of the backend initialization.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1218
2020-05-26 16:35:00 +02:00
510cbef15a surface-actor: Move out some X11-ism to X11 subclass
On X11 we don't update the texture in certain circumstances, such as if
the surface is a fullscreen unredirect, or doesn't have a Pixmap. On
Wayland we only want to avoid updating the texture if there is no
texture, but as this is handled implicitly by MetashapedTexture, we
don't need to try to emulate the X11-y conditions in the generic layer
and instead just have the implementations handle update processing
themself.

This doesn't have any functional changes, but removes a vfunc from
MetaSurfaceActorClass.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1218
2020-05-26 16:35:00 +02:00
99c9a14bc8 clutter/stage: Make clutter_stage_schedule_update() public API
It's effectively used by mutter by abusing a ClutterTimeline to scedule
updates.  Timelines are not really suited in places that is done, as it
is really just about getting a single new update scheduled whenever
suitable, so expose the API so we can use it directly.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1218
2020-05-26 16:35:00 +02:00
b8003807b0 clutter/stage: Make clutter_stage_schedule_update() always schedule
We could call clutter_stage_schedule_update() and it wouldn't actually
schedule anything, as the master frame clock only tries to reschedule if
1) there is an active timeline, 2) there are pending relayouts, 3) there
are pending redraws, or 4) there are pending events. Thus, a call to
clutter_stage_schedule_update() didn't have any effect if it was called
at the wrong time.

Fix this by adding a boolean state "needs_update" to the stage, set on
clutter_stage_schedule_update() and cleared on
_clutter_stage_do_update(), that will make the master clock reschedule
an update if it is TRUE.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1218
2020-05-26 16:35:00 +02:00
8e1bd64e05 clutter/stage-cogl: Use view fb instead of onscreen fb for debug-drawing
We need to use the framebuffer of the view instead of the onscreen
framebuffer when painting the damage region, otherwise the redraw clips
on rotated monitors won't be shown correctly.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1237
2020-05-26 13:54:28 +00:00
5aa56aa7f5 clutter/stage-cogl: Remove unneeded helper
The helper called a single function; lets just call it directly instead.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1237
2020-05-26 13:54:28 +00:00
c2c4f74923 clutter/stage-view: Add tile based shadow damage detection
Compare, tile by tile, whether actual damage actually changed any
pixels. While this requires mmap():ing DMA buffers and comparing their
content, we should only ever use shadow buffers when we're using the
software renderer, meaning mmap() is cheap as it doesn't involve any
downloading.

This works by making the shadow framebuffer double buffered, while
keeping track of damage history. When we're about to swap the onscreen
buffer, we compare what part of the posted damage actually changed,
records that into a damage history, then given the onscreen buffer age,
collect all actual damage for that age. The intersection of these tiles,
and the actual damage, is then used when blitting the shadow buffer to
the onscreen framebuffer.

Closes: https://gitlab.gnome.org/GNOME/mutter/-/issues/1157

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1237
2020-05-26 13:54:28 +00:00
f8daa6bc70 cogl/dma-buf: Add mmap/munmap helpers
Avoids dealing directly with mmap() and munmap().

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1237
2020-05-26 13:54:28 +00:00
5b07ccd0a7 cogl/dma-buf: Add API to synchronize reading
Used before and after accessing DMA buffer content using mmap().

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1237
2020-05-26 13:54:28 +00:00
ae4d299499 clutter/stage-cogl: Extract damage history logic
Move the damage history tracking to a new ClutterDamageHistory helper
type. The aim is to be able to track damage history elsewhere without
reimplementing the data structure and tracking logic.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1237
2020-05-26 13:54:28 +00:00
8798325489 clutter/stage-view: Only blit the damage part of the shadow buffer
This fixes the last "copy everything" paths when clutter doesn't
directly paint onto the onscreen framebuffer. It adds a new hook into
the stage view called before the swap buffer, as at this point, we have
the swap buffer damag regions ready, which corresponds to the regions we
must blit according to the damage reported to clutter.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1237
2020-05-26 13:54:28 +00:00
9e34028742 clutter/stage-cogl: Only construct damage array if it'll be used
It's only used when we actually swap buffers, which we only do if the
target framebuffer is an onscreen.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1237
2020-05-26 13:54:28 +00:00
258f859e8d clutter/stage-view: Only paint redraw clip from offscreen
The rest didn't change, so only actually paint the part of the offscreen
that was composited as part of the stage painting. In practice, this
means that, unless a shadow buffer is used, we now only paint the
damaged part of the stage, and copy the damage part of the offscreen to
the onscreen.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1237
2020-05-26 13:54:28 +00:00
9d3e4fd402 clutter/stage-cogl: Use buffer age when view monitor is rotated
We failed to use the buffer age when monitors were rotated, as when they
are, we first composite to an offscreen framebuffer, then later again to
the onscreen. The buffer age checking happened on the offscreen, and an
offscreen being single buffered, they can't possible support buffer
ages.

Instead, move the buffer age check to check the actual onscreen
framebuffer. The offscreen to onscreen painting is still always full
frame, but that will be fixed in a later commit.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1237
2020-05-26 13:54:28 +00:00
03c65b93e6 region-utils: Make transform util const correct
The input should be const, as it will not be altered.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1237
2020-05-26 13:54:28 +00:00
db975bd2a8 clutter/stage-view: Simplify painting of offscreen slightly
We will only ever have an "offscreen" if we're painting transformed in
some way, so the 'can_blit' checking is unnecessary. Remove it.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1237
2020-05-26 13:54:28 +00:00
4e27a4ea1d clutter/stage-view: Always use cogl_blit_framebuffer() from shadowfb
It should only be used when direct blitting is supported, so there is no
reason we should have to deal with pipelines etc when blitting from the
shadow buffer to the onscreen.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1237
2020-05-26 13:54:28 +00:00
346cadeddb renderer/native: Only enable shadowfbs if we can blit
There is no point in enabling shadow buffers if we can't as that'd be
even slower than not having them at all.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1237
2020-05-26 13:54:28 +00:00
f60c485117 cogl: Make private BLIT_FRAMEBUFFER feature public
Will be a requirement for enabling shadow buffers.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1237
2020-05-26 13:54:28 +00:00
19550c28f9 clutter/stage-view: Change set_dirty..() API to invalidate..()
The manual "cleaning" of the viewport and projection state is removed,
and we only ever try to invalidate the state so that it'll be updated
next time. Change the API used to reflect this.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1237
2020-05-26 13:54:28 +00:00
c4949b553d clutter/stage-view: Move fb viewport and projection setting to here
The stage would fetch the front framebuffer and set the viewport and
projection matrix, but if we are going to more than one front buffer,
that won't work, so let the stage just pass the viewport and projection
matrix to the view and have the view deal with the framebuffer(s).

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1237
2020-05-26 13:54:27 +00:00
675a2d13b9 clutter/stage-view: Move shadowfb struct fields into anonymous struct
With the aim to collect shadow buffer related things in one place, place
them in an anonymous struct.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1237
2020-05-26 13:54:27 +00:00
f4d9953b9c renderer-native: Move shadow fb construction to the stage view
The stage view will need a more involved approach to shadow buffers, in
order to implement things such double buffered shadow buffers and damage
detection.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1237
2020-05-26 13:54:27 +00:00
6db94a0b77 clutter/stage-view: Add name property
Will be used for logging to identify what view a log entry concerns. For
the native and nested backend this is the name of the output the CRTC is
assigned to drive; for X11 it's just "X11 screen", and for the legacy
"X11 screen" emulation mode of the nested backend it's called "legacy
nested".

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1237
2020-05-26 13:54:27 +00:00
9bf6faf639 output: Add name getter
This will return the name of the connector, e.g. DP-2.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1237
2020-05-26 13:54:27 +00:00
4434a17d08 cogl/dma-buf-handle: Pass more metadata to handle constructor
Could be useful would one want to mmap the dmabuf and deal with its
content manually in CPU space.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1237
2020-05-26 13:54:27 +00:00
c65f63b647 wayland/actor-surface: Don't notify geometry-changed on mapped changes
There's no reason to notify the surface that its geometry changed when
the visibility of the actor changes. This is only needed to update the
outputs of the surface, so do that directly instead.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1235
2020-05-26 14:54:57 +02:00
79d981aac9 wayland/actor-surface: Factor in mapped clones in mapped check
We started listening to notify::mapped with commit
5eb5f72434 in order to emit
wl_surface.leave events consistently when a surface gets hidden. This
caused a problem with the ClutterClones used in the overview, since
those temporarily map and unmap the windows for painting, spamming
wl_surface.leave and enter events to all surfaces.

We can easily fix that by also treating mapped clones as mapped, which
means the surface should also be on a wl_output when the overview is
shown.

Fixes https://gitlab.gnome.org/GNOME/mutter/-/issues/1141

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1235
2020-05-26 14:54:57 +02:00
2791f5b466 clutter/actor: Make has_mapped_clones() factor in parent actors
All existing users of clutter_actor_has_mapped_clones() actually want to
know whether the actor is being cloned by a visible clone, it doesn't
matter to them if that clone is attached to an actor somewhere else in
the tree or to the actor itself.

So make clutter_actor_has_mapped_clones() a bit more convenient to use
and also check the clones of the parent-actors in that function.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1235
2020-05-26 14:54:57 +02:00
e68bb27df2 wayland/actor-surface: Don't listen to notify::position signal
We started listening to "notify::position" on surface actors with commit
08e4cb54. This commit was done to fix a regression from commit cf1edff9,
which forgot to handle some cases like the actual WindowActor and not
the SurfaceActor (which is a child of the WindowActor) moving (that was
fixed by listening to MetaWindows "position-changed" signal). Also that
commit introduced meta_wayland_surface_update_outputs_recursively(),
which updates the outputs of all (sub-)surfaces in case any position
changed and made sure subsurfaces also get their outputs updated in case
the parent actor moved.

Connecting to the "notify::position" signal, which the above commit also
did is now superflous though because position changes will queue a
relayout and the actors allocation will change during the next
allocation cycle, notifying the "allocation" property which we also
listen to.

So save some resources and stop listening to that signal.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1235
2020-05-26 14:52:15 +02:00
e12b2c417e clutter/actor: Use priv->allocation instead of get_allocation_box()
The comment in _clutter_actor_get_allocation_clip() explicitely notices
that it doesn't need the behavior of doing an immediate relayout as
clutter_actor_get_allocation_box() does. The comment is also still valid
since the code calling _clutter_actor_get_allocation_clip() checks for
priv->needs_allocation just before.

So let's just use the allocation directly here instead of going through
that function.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1264
2020-05-23 10:35:25 +00:00
0fbda366e8 native: Return an error if no drm devices are found
Without this, we'll end up segfaulting when trying to log the
non-existing error.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1217
2020-05-22 20:25:06 +00:00
106d332c71 backend/xcursor: Support a "blank" cursor type
We don't have enough Xlib code in mutter ...

Joking aside, it can be useful to make the cursor invisible
without hiding it, for example for replacing the actual cursor
with an actor in gnome-shell; the real cursor should still
update the focus surface in that case, and not sneak into
screenshots or -casts.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1244
2020-05-22 14:10:50 +00:00
c42c11583d clutter: Use G_DECLARE_DERIVABLE_TYPE for ClutterAction and subclasses
https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/788
2020-05-22 08:56:23 +00:00
8c131b32b1 clutter/actor-meta: Use G_DECLARE_DERIVABLE_TYPE
https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/788
2020-05-22 08:56:23 +00:00
c8e12ead08 screen-cast-src: Notify about the stream being closed after dispatch
We're iterating inside the PipeWire loop when detecting PipeWire errors,
and shouldn't destroy the PipeWire objects mid-iteration. Avoid this by
first disabling the stream src (effectively stopping the recording),
then notifying about it being closed in an idle callback. The
notification eventually makes the rest of the screen cast code clean up
the objects, including the src and the associated PipeWire objects, but
will do so outside the PipeWire loop iteration.

Closes: https://gitlab.gnome.org/GNOME/mutter/-/issues/1251

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1251
2020-05-22 00:15:48 +00:00
8a541c08fb stage-x11: Move view management to renderer
In the native backend, the MetaRenderer manages the view by creating one
per CRTC, but until now the MetaStageX11 managed the view for the X11
backend. This caused some issues as it meant meta_renderer_get_views()
not returning anything, and that the view of the X11 screen not being a
MetaRendererView, while in the other backends, all views are.

Fix this by moving the view management responsibility to
MetaRendererX11Cm, and have MetaStageX11 only operate on it via
meta_renderer_x11_cm_*() API. The MetaRendererX11Cm takes care of making
sure the view is always added to the list in the renderer, and turning
X11 screen sizes into "layouts" etc.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1251
2020-05-22 00:15:48 +00:00
dfed5f6a11 stage-x11: Clean up include macros
https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1251
2020-05-22 00:15:48 +00:00
96dd794fd1 screen-cast-stream-src: Don't throttle if max framerate is 1/0
The max framerate 1/0 means variable without any particular max, so
don't throttle if that was set.

Not doing this would end up with a floating point exception.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1251
2020-05-22 00:15:48 +00:00
73a436362a renderer: Change 'set_legacy_view()' to 'add_view()'
"Legacy" is a misleading name, it's just how the native backend and the
X11 backend behaves differently. Instead rename it to 'add_view()' and
add the sanity check to the caller.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1251
2020-05-22 00:15:48 +00:00
7343b8d817 wayland/dma-buf: Make gbm_bo import function better named
It imports a DMA buffer as a gbm_bo, but only if it can be used to scan
it out, so name it import_scanout_gbm_bo().

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1261
2020-05-21 23:59:56 +00:00
dbf47b652e wayland/dma-buf: Handle failing to import scanout DMA buffer
A DMA buffer might not be able to scanout, and in that case the import
with GBM_BO_USE_SCANOUT will fail. Handle that by failing to scanout,
effectively falling back to compositing.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1261
2020-05-21 23:59:56 +00:00
b97a6e62a3 window: Add a note about the trustworthiness of the client PID
Since PIDs are inherently insecure because they are reused after a
certain amount of processes was started, it's possible the client PID
was spoofed by the client.

So make sure users of the meta_window_get_pid() API are aware of those
issues and add a note to the documentation that the PID can not be
totally trusted.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1180
2020-05-21 23:10:23 +00:00
4fac1a4862 window: Cache the client PID
Since the PID of a window can't change as long as the window exists, we
can safely cache it after we got a valid PID once, so do that by adding
a new `window->client_pid` private property.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1180
2020-05-21 23:10:23 +00:00
70ba844c3c window: Return pid_t in meta_window_get_pid()
Just as with the last commit, pid_t is compatible with all platforms and
we should use that everywhere, so also make meta_window_get_pid() return
a pid_t.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1180
2020-05-21 23:10:23 +00:00
bc0b9f7628 window: Use pid_t for get_client_pid() vfunc
It makes sense to use pid_t when getting the PID since that will work on
all platforms and architectures.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1180
2020-05-21 23:10:23 +00:00
c971d6ea1f window: Remove support for _NET_WM_PID
We have the client pid API that works on both Wayland and X11 nowadays,
so the _NET_WM_PID property is no longer needed, remove it.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1180
2020-05-21 23:10:23 +00:00
dac09a8e23 window: Use client PID for meta_window_get_pid()
The shell uses the PID of windows to map them to apps or to find out
which window/app triggered a dialog. It currently fails to do that in
some situations on Wayland, because meta_window_get_pid() only returns a
valid PID for x11 clients.

So use the client PID instead of the X11-exclusive _NET_WM_PID property
to find out the PID of the process that started the window. We can do
that by simply renaming the already existing
meta_window_get_client_pid() API to meta_window_get_pid() and moving
the old API providing the _NET_WM_PID to meta_window_get_netwm_pid().

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1180
2020-05-21 23:10:23 +00:00
11f224f4b0 clutter/box-layout: Remove child meta
ClutterBoxLayout's layout policy of using the generic ClutterActor
align/expand properties for children that are expanded and a custom
meta otherwise is confusing, in particular as the x-fill/y-fill
defaults don't match the default CLUTTER_ACTOR_ALIGN_FILL align.

StBoxLayout's own custom child meta (which was deprecated last
cycle) is probably the only consumer. And luckily, the St meta
uses different x-fill/y-fill default that match the ClutterActor
defaults, so removing it will not affect code that doesn't use
the deprecated properties themselves.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1265
2020-05-21 15:49:31 +02:00
a1be7cdbd7 tests/clutter: Don't test BoxLayout's child properties
They are about to become ex-properties.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1265
2020-05-21 15:49:31 +02:00
82d96aebe1 clutter/box-layout: Remove deprecated API
This stuff has been deprecated for a very long time, and given that
ClutterBoxLayout is most commonly used via StBoxLayout, the impact of
removing it should be low. It will however open the door to further
cleanups.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1265
2020-05-21 15:49:31 +02:00
c14ba5937f clutter/tests: Stop using deprecated BoxLayout API
... so that we can remove it.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1265
2020-05-21 15:49:31 +02:00
e50e14af82 clutter/actor: Remove "allocation-changed" signal
Since we now no have ClutterAllocationFlags, there's no reason anymore
for keeping the "allocation-changed" signal, so remove it.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1245
2020-05-20 12:50:31 +00:00
787d9a5a15 clutter: Use notify::allocation instead of allocation-changed
We're going to remove the "allocation-changed" signal from ClutterActor
since it's no longer needed now that ClutterAllocationFlags are gone.

So listen to "notify-allocation" instead, which has been the recommended
thing to do for some time now anyway.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1245
2020-05-20 12:50:31 +00:00
3c29bf7491 clutter: Remove allocation flags
Since there are now no more allocation flags, we can remove
ClutterAllocationFlags from Clutter.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1245
2020-05-20 12:50:31 +00:00
dc8e5c7f8b clutter/actor: Replace ABSOLUTE_ORIGIN_CHANGED flag with a property
The ABSOLUTE_ORIGIN_CHANGED allocation flag is only really useful to
propagate the information of the absolute origin of an actor having
changed inside Clutter. It wasn't used anywhere else besides for some
debug messages and it probably shouldn't be used in custom layout
implementations anyway since 1) actors shouldn't have to be aware of
absolute allocation changes and 2) it doesn't factor in changes to the
transformation matrix of a parent.

Also the propagation of absolute origin changes using this flag broke
with commit 0eab73dc2e and now hidden actors are no longer notified
about those changes.

Additionally, this flag gets in the way of a few potential optimizations
since it has to be propagated even if the allocation box of the child
hasn't changed, forcing a reallocation of the child.

So replace this flag with a simple new private property of ClutterActor
absolute_origin_changed, but keep the exact same behavior for now.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1245
2020-05-20 12:50:31 +00:00
0a986fc885 clutter/tests: Remove usage of ABSOLUTE_ORIGIN_CHANGED flag
We're going to remove this allocation flag, so stop using in the
interactive test-layout test.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1245
2020-05-20 12:50:31 +00:00
04e983383f clutter/stage: Remove ABSOLUTE_ORIGIN_CHANGED flag from debug message
The ABSOLUTE_ORIGIN_CHANGED allocation flag is going to be removed from
Clutter, so stop using it for this debug message.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1245
2020-05-20 12:50:31 +00:00
7ae6e0101c clutter/actor: Remove clutter_actor_maybe_layout_children()
Since we now only layout the children ourselves in case the actor
implementation doesn't override the allocate vfunc, we can remove
clutter_actor_maybe_layout_children() and move the functionality inside
clutter_actor_real_allocate().

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1245
2020-05-20 12:50:31 +00:00
affb3de829 clutter/actor: Don't layout children inside set_allocation()
Now that we no longer have the DELEGATE_LAYOUT we expect all actors
overriding the allocate() vfunc to allocate their children themselves.

Since clutter_actor_set_allocation() is only called from custom
vfunc_allocate() implementations, the condition in
clutter_actor_maybe_layout_children() would always fail, which makes
calling the function useless anyway.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1245
2020-05-20 12:50:30 +00:00
24d7a7ad0b clutter: Remove DELEGATE_LAYOUT allocation flag
The CLUTTER_DELEGATE_LAYOUT flag is unintuitive and makes the allocation
process inside Clutter unnecessarily complicated. It's very easy for
actors overriding the allocate() vfunc to layout their children
themselves (in fact most of them do this), and it also never made sense
that clutter_actor_set_allocation() does eventually layout children.

There was no ClutterActor implementation in mutter or gnome-shell which
actually used the DELEGATE_LAYOUT flag, but even without it, it's fairly
easy to archive the same behavior now: In the allocate() override,
adjust the allocation as wanted, then chain up to the parent vfunc
without calling clutter_actor_set_allocation().

So remove the CLUTTER_DELEGATE_LAYOUT flag, which will allow making the
relayout code in Clutter a bit easier to follow.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1245
2020-05-20 12:50:30 +00:00
4729cb779e clutter/stage: Stop using DELEGATE_LAYOUT allocation flag
We're going to remove allocation flags, so stop depending on the
DELEGATE_LAYOUT flag in ClutterStage and call
clutter_layout_manager_allocate() directly, which is pretty
straightforward.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1245
2020-05-20 12:50:30 +00:00
c8837a8de5 backends: Make uniform checks on remote desktop input dbus methods
They all checked that the remote session service talked with the
correct peer, and some of them did check that there is an associated
screencast session.

Add a new check for the session being started (as it's state is
decoupled with screencast session availability) and move all checks
to a function that is called from all input-oriented DBus methods.

Fixes: https://gitlab.gnome.org/GNOME/mutter/-/issues/1254

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1258
2020-05-20 10:19:24 +00:00
283cccbe9f backends: Ensure remote desktop dbus interface state
Ensure that it does receive Start and Stop orderly, and error out
otherwise.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1258
2020-05-20 10:19:24 +00:00
a7bf6322e3 clutter/actor: Use priv->parent instead of public API sometimes
The public API to get the parent actor, clutter_actor_get_parent() does
a type check whether the actor is actually a ClutterActor. In case of
_clutter_actor_apply_relative_transformation_matrix(), which is called
recursively and very often during the paint process, this type check
shows up with almost twice the amount of hits than the actual matrix
multiplication.

So use the parent pointer directly in some code paths that are executed
very often and avoid the expensive type checking there, we can do that
since both places are not public API.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1259
2020-05-19 08:17:09 +00:00
1d5f9b6917 backend-x11: Reintroduce XInitThreads
It was removed in 3.34 as part of 6ed5d2e2. And we thought that was the
only thread that might exist and use X11. But the top gnome-shell crasher
in 3.36 seems to suggest otherwise.

We don't know what or where the offending thread is, but since:

 1. We used XInitThreads for years already prior to 3.34; and

 2. Extensions or any change to mutter/gnome-shell could conceivably use
    threads to make X calls, directly or indirectly,

it's probably a good idea to reintroduce XInitThreads. The failing assertion
in libx11 is also accompanied by a strong hint:

```
fprintf(stderr, "[xcb] Most likely this is a multi-threaded client " \
                "and XInitThreads has not been called\n");
```

https://bugs.launchpad.net/bugs/1877075

Closes: https://gitlab.gnome.org/GNOME/mutter/-/issues/1252

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1256
2020-05-15 15:30:09 +08:00
3c068ef135 wayland/surface: Simplify state cleanup after merge
Instead of manually freeing things, use the existing helper function.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1232
2020-05-14 00:34:49 +02:00
2becb3dd29 wayland: Add support for wayland-protocols primary selection protocol
This protocol was added some time ago. Supporting it fell through the
cracks. Add new data device/source/offer implementations for it,
interoperation between primary selection protocols (and X11 primary
selection for that matter) comes for free.

Closes: https://gitlab.gnome.org/GNOME/mutter/-/issues/943

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1255
2020-05-13 18:27:46 +02:00
55f5177fe0 build: Build scaffolding for primary-selection wayland protocol
https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1255
2020-05-13 18:18:18 +02:00
037b68ab8e wayland: Rename gtk primary protocol files to "legacy"
We want to make room for the wayland-protocols primary selection
protocol. Rename our private protocol as "legacy".

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1255
2020-05-13 18:18:14 +02:00
b45d5ef3f5 wayland: Send primary offer to all data devices from the same client
Make the data device track the keyboard focus, and use that list to
forward the primary selection to all data devices from the same
client.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1253
2020-05-13 14:44:55 +00:00
7e4e371466 wayland: Send clipboard offers to all data devices from the same client
Make the data device track the keyboard focus, and use that list to
forward the clipboard selection to all data devices from the same
client.

This is however not the case of DnD data offers, as the semantics
of multiple in-flight offers is unclear.

Fixes: https://gitlab.gnome.org/GNOME/mutter/-/issues/1250

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1253
2020-05-13 14:44:55 +00:00
fbfa136bbb clutter/stage-cogl: Cleanup damage history (un-)scaling a bit
Reverting the scale and offset applied to the damage history can be done
in one step, using a few less temporary allocations by passing the
offset right away to a new scale_offset_and_clamp_region() function.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1113
2020-05-13 11:08:54 +00:00
434845dbe5 clutter/stage-cogl: Don't loop through region rects twice
There's no reason for using two loops to fill the rects array in
offset_scale_and_clamp_region(), we can do that using only one loop.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1113
2020-05-13 11:08:54 +00:00
967511be61 clutter/stage-cogl: Don't intersect the damage region with the view
Since the damage history region is tracked per-view, all the regions it
includes should be inside the current view anyway, so don't
unnecessarily intersect that region with the view.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1113
2020-05-13 11:08:53 +00:00
43c7a82461 clutter/stage-cogl: Cleanup setting of the damage history
Since we now check for the buffer age before setting up the
fb_clip_region, that region will be set to the full extents of the view
in case the buffer age is invalid. This in turn means we don't have to
do this again later and can simply fill the damage history with the
fb_clip_region that's already set for us.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1113
2020-05-13 11:08:53 +00:00
066e78c9b3 clutter/stage-cogl: Warn if the fb_clip_region is empty
Since a NULL redraw_clip means that a full view redraw should be done
and an empty redraw clip may never be set (see the width/height checks
in clutter_stage_view_add_redraw_clip()), the fb_clip_region should
always be set to a reasonable region that's either the whole view or
individual regions inside the view.

So make sure that's actually the case by warning and that the
fb_clip_region isn't empty, which allows dropping another few lines of
code.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1113
2020-05-13 11:08:53 +00:00
08f47fee16 clutter/stage-cogl: Check for DISABLE_CLIPPED_REDRAWS earlier
Right now we're checking for the DISABLE_CLIPPED_REDRAWS debug flag
after creating the fb_clip_region and adjusting the redraw_clip. That
means that if may_use_clipped_redraw was TRUE, the redraw_clip will
still be set to the region and thus cause the stage to only be partially
redrawn. Since we don't push a clip to the framebuffer though
(use_clipped_redraw is now FALSE), parts of the view will get corrupted.

To fix that, disable clipped redraws right away if the debug flag is
set. This also allows removing the may_use_clipped_redraw bool and
replacing it entirely with use_clipped_redraw.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1113
2020-05-13 11:08:53 +00:00
afe4cd482e clutter/stage-cogl: Stop painting redraw clip outline
We already have a better way to paint the redraw clip: Painting the
damage region paints the individual rects of the clip region and not
only the bounding rect.

So stop painting an outline around the redraw clip bounding rect when
CLUTTER_DEBUG_REDRAWS is set.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1113
2020-05-13 11:08:53 +00:00
3fed768db4 clutter/stage-cogl: Don't push scissor clip with one clip rectangle
While this is meant as an optimzation to only use the scissor clip and
not the stencil buffer if there's only one clip rectangle, it's not
needed since this optimization is going to be applied to region clips
anyway inside _cogl_clip_stack_gl_flush() (see cogl-clip-stack-gl.c).

So remove the unnecessary optimization here and rely on cogl-clip-stack
to do it for us.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1113
2020-05-13 11:08:53 +00:00
8c52b431bb clutter/stage-cogl: Stop doing subpixel compensation
This was introduced with commit 9ab338d7b6 because the clipping of
fractionally scaled redraws caused glitches, it seems like this is no
longer needed nowadays, so let's remove it.

This should make obscured region culling work a bit better for
fractionally scaled framebuffers because because we overdraw a slightly
smaller region than the actually damaged one. We still do overdraw
though since the clipping region is stored using integers and thus
any non-integer values have to be extended to the bounding rect.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1113
2020-05-13 11:08:53 +00:00
d9ffbf0576 clutter/stage-cogl: Don't clip when clipped redraws are disabled
It doesn't make sense to set the redraw clip when painting the stage if
clipped redraws are disabled. That's because when visualizing the redraw
clip and any new redraws are clipped, the old visualiziations would
remain visible, leaving multiple confusing rectangles on the screen.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1113
2020-05-13 11:08:53 +00:00
b0953b92ba clutter/stage-cogl: Remove scale_and_clamp_rect() function
This function  is only used in offset_scale_and_clamp_region() and can
simply be included there.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1113
2020-05-13 11:08:53 +00:00
819f9afa31 shaped-texture: Fix typo in documentation
https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1252
2020-05-13 12:12:01 +02:00
7a0bc5af7f background: Limit mipmap levels to avoid loss of visible detail
When the wallpaper image is larger than the monitor resolution we already
use mipmapping to scale it down smoothly in hardware. We use
`GL_TEXTURE_MIN_FILTER` = `GL_LINEAR_MIPMAP_LINEAR` for the highest quality
scaling that GL can do. However that option is designed for 3D use cases
where the mipmap level is changing over time or space.

Since our wallpaper is not changing distance from us we can improve the
rendering quality even more than `GL_LINEAR_MIPMAP_LINEAR`. To do this we
now set `GL_TEXTURE_MAX_LEVEL` (if available) to limit the mipmap level or
blurriness level to the lowest resolution (highest level) that is still
equal to or higher than the monitor itself. This way we get the benefits
of mipmapping (downscaling in hardware) *and* retain the maximum possible
sharpness for the monitor resolution -- something that
`GL_LINEAR_MIPMAP_LINEAR` alone doesn't do.

Example:

  Monitor is 1920x1080
  Wallpaper photo is 4000x3000
  Mipmaps stored on the GPU are 4000x3000, 2000x1500, 1000x750, ...

  Before: You would see an average of the 2000x1500 and 1000x750 images.
  After:  You will now only see the 2000x1500 image, linearly sampled.

https://gitlab.gnome.org/GNOME/mutter/merge_requests/1003
2020-05-13 09:37:31 +00:00
c5fbab6bad cogl: Add new function cogl_pipeline_set_layer_max_mipmap_level()
To configure an exact value of `GL_TEXTURE_MAX_LEVEL` clamped to within
the range of possible levels.

https://gitlab.gnome.org/GNOME/mutter/merge_requests/1003
2020-05-13 09:37:31 +00:00
f4301b77fa cogl: Generalize maybe_update_max_level() into set_max_level()
This way the caller can choose their own precondition.

https://gitlab.gnome.org/GNOME/mutter/merge_requests/1003
2020-05-13 09:37:31 +00:00
a3f27dfd89 cogl: Ensure GL_TEXTURE_MAX_LEVEL is set before using it
Just in case it was lower before. So that `upload_subregion_to_gl` is
not trying to upload to a disallowed mipmap level.

https://gitlab.gnome.org/GNOME/mutter/merge_requests/1003
2020-05-13 09:37:31 +00:00
73ce9c2e81 cogl: Replace an outdated #ifdef
The feature `GL_TEXTURE_MAX_LEVEL` it is hiding actually exists
in ES>=3.0, so the #ifdef is not appropriate.

https://gitlab.gnome.org/GNOME/mutter/merge_requests/1003
2020-05-13 09:37:31 +00:00
fd27c7c444 cogl: Delete a duplicate (masked) variable declaration
https://gitlab.gnome.org/GNOME/mutter/merge_requests/1003
2020-05-13 09:37:31 +00:00
a51807fc1e tests: Move monitor test functions into common utils
It's very useful to have common functions for easily creating a monitor
test setup for all kinds of tests, so move create_monitor_test_setup()
and check_monitor_configuration() and all the structs those are using to
monitor-test-utils.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1243
2020-05-13 08:38:40 +00:00
3c35a78769 tests/monitor-store-unit-tests: Rename some structs
We're going to move some structs from monitor-unit-tests.c to
monitor-test-utils.h and some names are currently clashing with the
struct names here, so rename those to be specific to the
MonitorStoreUnitTests.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1243
2020-05-13 08:38:40 +00:00
ae7cb7a3bf tests/monitor-unit-tests: Check test state outside of common function
check_monitor_test_clients_state() is a function that's only meant to be
used in the monitor-unit-tests, and since we're going to move the
functions for creating MonitorTestSetups into a common file, this
function is going to be in the way of that. So move the checking of the
test client state outside of check_monitor_test_clients_state().

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1243
2020-05-13 08:38:39 +00:00
531b0ab300 tests/monitor-unit-tests: Use TestCaseExpect for checking configuration
Similar to the last commit, allow checking configurations without
passing the whole MonitorTestCase, but instead only the
MonitorTestCaseExpect object.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1243
2020-05-13 08:38:39 +00:00
7cc604b9e5 tests/monitor-unit-tests: Use TestCaseSetup for building TestSetup
We're going to move the functions for building MonitorTestSetups to the
common monitor-test-utils.c file.

To make building test setups a bit more straightforward in case no
TestCaseExpect is wanted, change create_monitor_test_setup() to take a
MonitorTestCaseSetup instead of a MonitorTestCase as an argument.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1243
2020-05-13 08:38:39 +00:00
f3a65c9b32 tests/monitor-test-utils: Remove unused function definition
https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1243
2020-05-13 08:38:39 +00:00
dec97a6541 tests/monitor-transform: Also test invert()
Commit e06daa58c3 changed the tested values to use corresponding valid
enum values instead of negative ones. Unfortunately that made one value
become a duplicate of an existing one and also in part defeated the original
intention of checking the implementation of
`meta_output_crtc_to_logical_transform`.

Use `meta_monitor_transform_invert` to fix both shortcomings.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1242
2020-05-13 08:19:42 +00:00
cfa2d1abf7 shaped-texture: Add a few explanatory comments
One of the important classes in Mutter's handling of client textures is
the `MetaShapedTexture`. This commit adds a few gtk-doc comments which
explain its purpose, with special attention to the viewport methods.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1210
2020-05-13 07:57:58 +00:00
d9fb6b5ca2 wayland/surface: Connect to "output-destroyed" in surface_entered_output
Since we're now connecting to one more signal of MetaWaylandOutput, keep
signal connections in one place and move connecting the
"output-destroyed" signal to surface_entered_output() and disconnecting
it to surface_left_output().

This also allows us to use the "outputs_to_destroy_notify_id" as a
simple set and rename it to "outputs".

While at it, also use g_hash_table_destroy() instead of
g_hash_table_unref() since destroy is more clear than unref and does the
same thing in this case.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1230
2020-05-11 18:06:58 +00:00
696b534570 wayland/surface: Send enter event when a client binds to wl_output late
When hotplugging a new monitor, we recreate all the MetaWaylandOutputs
and need to emit leave events to the surfaces for the old wl_outputs and
enter events for the newly created ones.

There's a race condition though: We might update the monitors a surface
is on (and thus emit enter/leave events for the wl_outputs) before the
Wayland client is registered with the new wl_output (ie. the
bind_output() callback of MetaWaylandOutput was called), which means we
don't send an enter event to the client in surface_entered_output().
Since MetaWaylandSurface now has the MetaWaylandOutput in its outputs
hashtable, it thinks the client has been notified and won't send any
more enter events.

To fix that, make MetaWaylandOutput emit a new signal "output-bound"
when a client bound to the output and make all surfaces which are on
that output listen to the signal. In the signal handler compare the
newly added client to the client the surface belongs to, and if it's the
same one, send an enter event to that client.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1230
2020-05-11 18:06:58 +00:00
38db4a5a65 wayland/wl-output: Emit "output-destroyed" signal earlier
The "output-destroyed" signal is used for notifying MetaWaylandSurfaces
that an output they are shown just got invalid (for example because a
monitor hotplug happened).

While we delay the destroying of outputs by 10 seconds since commit
1923db97 because of a race-condition, it doesn't make sense to wait 10
seconds until we let surfaces know that an output was destroyed.

So move the emission of the "output-destroyed" signal to
make_output_inert(), which is called before we start the 10 seconds
delay.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1230
2020-05-11 18:06:58 +00:00
6f62c5b575 core/place: Use work area when centering new window.
use the workarea instead of the logical monitor

Closes https://gitlab.gnome.org/GNOME/mutter/-/issues/964
2020-05-09 09:47:42 +00:00
d823a54b5d monitor-transform: Don't call abs on non-negative enum
It causes Clang to show a lot of warnings during compilation because it
thinks the abs call is useless.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1234
2020-05-09 01:02:22 +02:00
e06daa58c3 tests/monitor-transform: Test only valid enums
This test was introduces assuming we'd do interger math outside
of `meta-monitor-transform`. We later agreed to not do that and require
valid enums, but forgot to remove the corresponding test case.

Test the corresponding valid enums instead of negative ones.

See https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1064

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1234
2020-05-09 01:02:22 +02:00
1880e22229 clutter-actor: Remove unused clutter_actor_get_allocation_vertices
It was also apparently broken (mutter#1126)

Closes: https://gitlab.gnome.org/GNOME/mutter/issues/1126
2020-05-08 09:52:49 +00:00
bd28581471 monitor-manager: Remove "supports-mirroring" from D-Bus desciption file
This is unused since commit 0a6034ef3a

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1134
2020-05-08 06:50:16 +00:00
82470cd40d tests/stacking: Add test checking the initial size
https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1171
2020-05-07 23:15:25 +00:00
b4972f573c tests/stacking: Add test for checking restored positions
Going maximized -> unmaximized should restore the previous position. The
same for untiling, or going from tiled, to maximized, to floating.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1171
2020-05-07 23:15:25 +00:00
c97c409c50 tests/test-runner: Add 'move' and 'assert_position'
Make it possible for tests to move the windows, and check their
positions.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1171
2020-05-07 23:15:25 +00:00
989e2ccc46 tests/restore-size: Also test that untiling restores correctly
Tiling, then untiling should restore to the size prior to tiling.

Tiling, maximizing, then unmaximizing should also restore to the size
prior to tiling.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1171
2020-05-07 23:15:25 +00:00
e09e62d585 tests/test-runner: Add tile and untile commands
This allows test cases to tile windows to the right or left, and untile,
just as the keyboard shortcuts does.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1171
2020-05-07 23:15:24 +00:00
033f0d11bf window: Set fall-back tile monitor if not set
When tiling, we want to set the tile monitor. To not have to do this
from the call site, make meta_window_tile() fall back to the current
monitor if nothing set it prior to the call.

This will make it more convenient for test cases to test tiling
behavior.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1171
2020-05-07 23:15:24 +00:00
668eb318c7 window: Add meta_window_untile()
It does the same as the untile keyboard shortcut does, i.e. handles
going back to saved maximized state. It's split out to be able to be
tested by the stacking tests.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1171
2020-05-07 23:15:24 +00:00
449cbe153b tests/stacking: Test some maximize fullscreen interaction
https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1171
2020-05-07 23:15:24 +00:00
9b8e5a05f5 tests/test-client: Add 'fullscreen' and 'unfullscreen' commands
This needs some hand holding when calculating the "full" size of the
window, as the titlebar isn't actually shown.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1171
2020-05-07 23:15:24 +00:00
d14c8cf9a4 tests/stacking: Check that unmaximize to new size works
A client that set a new fallback size while being maximized should not
restore to the one prior to being maximized.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1171
2020-05-07 23:15:24 +00:00
4571de5772 tests/stacking: Add test to verify we unmaximize correctly
The test tests that (for both X11 and Wayland) that:

 * The client unmaximizes after mapping maximized to a predictable size
 * That the client unmaximizes to the same size after toggling maximize

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1171
2020-05-07 23:15:24 +00:00
62f449d7d5 tests/test-runner: Add a 'wait_reconfigure' command
This makes sure that a client has properly responded to a configure
event it itself triggered. In practice, this is just two 'wait'
commands, with a 'dispatch' in between, which is needed because a single
one does not reliably include the two way round trip happening when e.g.
responding to a unmaximize configure event triggered by a unmaximize
request.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1171
2020-05-07 23:15:24 +00:00
476ef76de6 tests/test-runner: Add 'assert_size' command
The 'assert_size' command checks that the size of the window, both
client side and compositor side, corresponds to an expected size set by
the test case.

The size comparison can only be done when the window is using 'csd', in
order for both the client and server to have the same amount of
understanding of the title bar. For ssd, the client cannot know how
large the title bar, thus cannot verify the full window size.

Sizes can be specified to mean the size of the monitor divided by a
number. This is that one can make sure a window is maximized or
fullscreened correctly.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1171
2020-05-07 23:15:24 +00:00
48de81b63e tests/test-client: Remove shadow from X11 test client CSS style
Gtk is quite buggy and "fluid" in how it handles the shadow margins for
windows under X11. The "size" of the window fluctuate between including and
excluding a shadow margin in a way that causes issues, as there are no
atomic update of any state going on.

In order to avoid running into those particular issues now, lets get rid
of shadows so the margins are always zero, when the client is using the
X11 backend.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1171
2020-05-07 23:15:24 +00:00
2ee3d5392b tests/test-client: Make 'resize' client command include the titlebar
To get some kind of consistency between what 'resize' means for the
compositor and the client, make the size correspond to the "frame rect"
of the window, i.e. the window geometry in the Wayland case, and the
window size including the titlebar in the X11 case.

This is so that the window size later can be reliably compared both in
the compositor and in the client using the same expected dimensions.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1171
2020-05-07 23:15:24 +00:00
0f2a33cc9c tests/test-client: Add line breaks to warning messages
When toying with the test client to try to reproduce issues (e.g.
writing commands on stdin to create and manipulate windows), when you
write a command incorrectly you'll get a warning printed to standard
out. The problem, however, is that it doesn't include a line break in
the end, meaning when you type the correct command, it won't be on a new
line.

Fix this minor annoyance by adding line breaks to all warning messages.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1171
2020-05-07 23:15:24 +00:00
2ce622f057 tests/test-runner: Plumb "resize" command
The test client could already understand the resize command, but they
could not be added to metatests as the command was not properly plumbed
via the test runner. Establish the plumbing for the resize command so
that resize tests can be added.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1171
2020-05-07 23:15:24 +00:00
76083d76af tests/test-client: Add commands to maximize/unmaximize
https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1171
2020-05-07 23:15:24 +00:00
132060db21 ci: Save built artifacts only for the test build
We only test the meson-build job, so there's no point to save artifacts for
the other test-build only builds.

So, only save meson logs artifacts (with a default gitlab expiration time)
for the other build-without-* jobs

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1236
2020-05-07 22:08:44 +00:00
c7f2ae1b16 build: Add configuration summary line about coverage being enabled
https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1236
2020-05-07 22:08:44 +00:00
24a0e72ae9 ci: Remove the MALLOC_PERTURB_ definition
meson already provides one by default [1].

[1] https://github.com/mesonbuild/meson/blob/master/docs/markdown/Unit-tests.md#malloc_perturb_

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1236
2020-05-07 22:08:44 +00:00
5c4938e479 ci: Enable coverage reports in test build
While we don't have an high number of tests, we still have some code
coverage and so we can track this via gitlab CI, given that it supports it
natively.

So add gcovr to the DockerFile dependency, build with -Db_coverage=true
meson native parameter, and add another manual job to make ninja to generate
the coverage reports on requests or in any master or tag ref.

Keep the artifacts around to be able to browse the generated HTML files and
eventually print the text reports so that they can be parsed by gitlab.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1236
2020-05-07 22:08:44 +00:00
322b51cded clutter: Remove ClutterAnimation
This removes ClutterAnimation and related tests. ClutterAnimation has
been deprecated for a long time, and replacements exist and are used by
e.g. GNOME Shell since a while back.

This also disables a few relatively unrelated interactive tests, as they
rely on ClutterAnimation to implement some animations they use to
illustrate what they actually test.

As interactive tests currently are more or less untestable due to any
interaction with them crashing, as well as they in practice means
rewriting the tests using non-deprecated animation APIs, they are not
ported right now. To actually port the interactive tests, it needs to be
possible to fist interact with them.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1192
2020-05-07 20:04:07 +00:00
b46bc98d44 tests/clutter/conform: Remove left-over ClutterAnimator scripts
ClutterAnimator is long gone; remove some leftover test scripts.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1192
2020-05-07 20:04:07 +00:00
da5be1fdea clutter/animatable: Remove left-over vfunc
https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1192
2020-05-07 20:04:07 +00:00
bc18438cb0 clutter/box-layout: Make 'easing-mode' be an enum
In the past, it was a odd mix of possible different types, all coalesced
into an unsigned integer. Now, hovewer, it's always a
ClutterAnimationType, so lets change the name of getter, setter and
property to what it really is.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1192
2020-05-07 20:04:07 +00:00
e3c0fcf7d5 tests/clutter: Add back redhand_alpha.png and light0.png
They were removed long long ago, but are still used, so add them back to
get the relevant tests usable again.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1192
2020-05-07 20:04:07 +00:00
73cb96ddb9 clutter: Remove 'ClutterAlpha'
It was some kind of deprecated interpolation mechanism used in
ClutterAnimation. We're not using it, and have non-deprecated
replacement functionality, so lets drop it.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1192
2020-05-07 20:04:07 +00:00
1cb59f44ab clutter/layout-manager: Remove unused animation API
One less unused animation API to care about.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1192
2020-05-07 20:04:07 +00:00
a55a286b15 clutter: Remove deprecated 'ClutterState'
https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1192
2020-05-07 20:04:07 +00:00
18e7b814f2 tests/wayland: Don't test file sealing on the fallback case
When memfd_create isn't used, the file isn't sealed. Therefore, we
should skip test_readonly_seals on the fallback case. This fixes
compilation error on FreeBSD 12, which does not support memfd_create.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1229
2020-05-07 19:39:13 +00:00
e073076119 backends/native: Unset the correct button codes when a virtual device is destroyed
We were iterating through evcodes, but using API that expects Clutter button
numbers. Instead of transforming those to Clutter numbers to have those translated
back, use the inner seat API that already takes evcodes.

Fixes stuck buttons keys after a virtual device is destroyed while those are
pressed.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1239
2020-05-07 17:01:05 +00:00
5d58156134 wayland/keyboard: Chain finalize up to the parent class
Finalize the parent class of the Wayland keyboard object.

Suggested-by: Marco Trevisan (Treviño) <mail@3v1n0.net>
https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1238
2020-05-07 10:27:32 +00:00
c38fa4fa5c clutter: Remove CLUTTER_ACTOR_IN_REPARENT flag
The CLUTTER_ACTOR_IN_REPARENT and the CLUTTER_IN_REPARENT flag are never
set and the logic for skipping unmap, unrealize and the emission of the
"parent-set" signal during reparents has been solved differently by
leaving out the CHECK_STATE and EMIT_PARENT_SET flags when calling
add_child_internal() and remove_child_internal().

The only place where those REPARENT flags are theoretically still useful
is in the clutter_actor_verify_map_state() debugging function, but that
is never called during reparent anyway, so simply leave the comment
regarding reparent there.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1228
2020-05-07 09:01:31 +00:00
5201d77b0b keybindings: Use current monitor for move-to-center
Move to center uses all monitors for calculating work area.

This can lead to an unexpected behaviour on some monitor
configurations resulting in current window being split between
monitors. We should move window to the center of the active display.

Closes https://gitlab.gnome.org/GNOME/mutter/-/issues/1073
2020-05-06 16:03:45 +05:00
aedf692e0c backends: move 'input_device' to HAVE_LIBWACOM scope
https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1231
2020-05-03 23:35:03 +01:00
197 changed files with 5426 additions and 11094 deletions

View File

@ -4,6 +4,7 @@ stages:
- review
- build
- test
- coverage
check-commit-log:
stage: review
@ -17,7 +18,7 @@ check-commit-log:
build-mutter:
stage: build
script:
- meson . build -Dbuildtype=debugoptimized -Degl_device=true -Dwayland_eglstream=true --werror --prefix /usr
- meson . build -Dbuildtype=debugoptimized -Db_coverage=true -Degl_device=true -Dwayland_eglstream=true --werror --prefix /usr
- ninja -C build
- ninja -C build install
artifacts:
@ -35,9 +36,8 @@ build-without-opengl-and-glx:
- ninja -C build
- ninja -C build install
artifacts:
expire_in: 1 day
paths:
- build
- build/meson-logs
only:
- merge_requests
- /^.*$/
@ -49,9 +49,8 @@ build-without-native-backend-and-wayland:
- ninja -C build
- ninja -C build install
artifacts:
expire_in: 1 day
paths:
- build
- build/meson-logs
only:
- merge_requests
- /^.*$/
@ -66,7 +65,6 @@ test-mutter:
G_SLICE: "always-malloc"
MALLOC_CHECK_: "3"
NO_AT_BRIDGE: "1"
MALLOC_PERTURB_: "123"
script:
- dconf update
- mkdir -m 700 $XDG_RUNTIME_DIR
@ -74,10 +72,30 @@ test-mutter:
- >
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
paths:
- build
only:
- merge_requests
- /^.*$/
test-mutter-coverage:
stage: coverage
dependencies:
- test-mutter
script:
- ninja -C build coverage
- cat build/meson-logs/coverage.txt
artifacts:
paths:
- build/meson-logs
when: manual
except:
refs:
- tags
- master
can-build-gnome-shell:
stage: test
dependencies:

View File

@ -16,7 +16,7 @@ RUN dnf -y update && dnf -y upgrade && \
# 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 \
'*/xvfb-run' gdm-lib accountsservice-libs gnome-control-center gcovr \
--setopt=install_weak_deps=False && \
# GNOME Shell

View File

@ -33,28 +33,11 @@
G_BEGIN_DECLS
#define CLUTTER_TYPE_ACTION (clutter_action_get_type ())
#define CLUTTER_ACTION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_ACTION, ClutterAction))
#define CLUTTER_IS_ACTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_ACTION))
#define CLUTTER_ACTION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_ACTION, ClutterActionClass))
#define CLUTTER_IS_ACTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_ACTION))
#define CLUTTER_ACTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_ACTION, ClutterActionClass))
#define CLUTTER_TYPE_ACTION (clutter_action_get_type ())
typedef struct _ClutterActionClass ClutterActionClass;
/**
* ClutterAction:
*
* The #ClutterAction structure contains only private data and
* should be accessed using the provided API.
*
* Since: 1.4
*/
struct _ClutterAction
{
/*< private >*/
ClutterActorMeta parent_instance;
};
CLUTTER_EXPORT
G_DECLARE_DERIVABLE_TYPE (ClutterAction, clutter_action,
CLUTTER, ACTION, ClutterActorMeta);
/**
* ClutterActionClass:
@ -78,9 +61,6 @@ struct _ClutterActionClass
void (* _clutter_action8) (void);
};
CLUTTER_EXPORT
GType clutter_action_get_type (void) G_GNUC_CONST;
/* ClutterActor API */
CLUTTER_EXPORT
void clutter_actor_add_action (ClutterActor *self,

View File

@ -81,38 +81,47 @@ static void
on_actor_destroy (ClutterActor *actor,
ClutterActorMeta *meta)
{
meta->priv->actor = NULL;
ClutterActorMetaPrivate *priv =
clutter_actor_meta_get_instance_private (meta);
priv->actor = NULL;
}
static void
clutter_actor_meta_real_set_actor (ClutterActorMeta *meta,
ClutterActor *actor)
{
g_warn_if_fail (!meta->priv->actor ||
!CLUTTER_ACTOR_IN_PAINT (meta->priv->actor));
ClutterActorMetaPrivate *priv =
clutter_actor_meta_get_instance_private (meta);
g_warn_if_fail (!priv->actor ||
!CLUTTER_ACTOR_IN_PAINT (priv->actor));
g_warn_if_fail (!actor || !CLUTTER_ACTOR_IN_PAINT (actor));
if (meta->priv->actor == actor)
if (priv->actor == actor)
return;
g_clear_signal_handler (&meta->priv->destroy_id, meta->priv->actor);
g_clear_signal_handler (&priv->destroy_id, priv->actor);
meta->priv->actor = actor;
priv->actor = actor;
if (meta->priv->actor != NULL)
meta->priv->destroy_id = g_signal_connect (meta->priv->actor, "destroy",
G_CALLBACK (on_actor_destroy),
meta);
if (priv->actor != NULL)
priv->destroy_id = g_signal_connect (priv->actor, "destroy",
G_CALLBACK (on_actor_destroy),
meta);
}
static void
clutter_actor_meta_real_set_enabled (ClutterActorMeta *meta,
gboolean is_enabled)
{
g_warn_if_fail (!meta->priv->actor ||
!CLUTTER_ACTOR_IN_PAINT (meta->priv->actor));
ClutterActorMetaPrivate *priv =
clutter_actor_meta_get_instance_private (meta);
meta->priv->is_enabled = is_enabled;
g_warn_if_fail (!priv->actor ||
!CLUTTER_ACTOR_IN_PAINT (priv->actor));
priv->is_enabled = is_enabled;
g_object_notify_by_pspec (G_OBJECT (meta), obj_props[PROP_ENABLED]);
}
@ -147,20 +156,21 @@ clutter_actor_meta_get_property (GObject *gobject,
GValue *value,
GParamSpec *pspec)
{
ClutterActorMeta *meta = CLUTTER_ACTOR_META (gobject);
ClutterActorMetaPrivate *priv =
clutter_actor_meta_get_instance_private (CLUTTER_ACTOR_META (gobject));
switch (prop_id)
{
case PROP_ACTOR:
g_value_set_object (value, meta->priv->actor);
g_value_set_object (value, priv->actor);
break;
case PROP_NAME:
g_value_set_string (value, meta->priv->name);
g_value_set_string (value, priv->name);
break;
case PROP_ENABLED:
g_value_set_boolean (value, meta->priv->is_enabled);
g_value_set_boolean (value, priv->is_enabled);
break;
default:
@ -172,7 +182,8 @@ clutter_actor_meta_get_property (GObject *gobject,
static void
clutter_actor_meta_finalize (GObject *gobject)
{
ClutterActorMetaPrivate *priv = CLUTTER_ACTOR_META (gobject)->priv;
ClutterActorMetaPrivate *priv =
clutter_actor_meta_get_instance_private (CLUTTER_ACTOR_META (gobject));
if (priv->actor != NULL)
g_clear_signal_handler (&priv->destroy_id, priv->actor);
@ -243,9 +254,11 @@ clutter_actor_meta_class_init (ClutterActorMetaClass *klass)
void
clutter_actor_meta_init (ClutterActorMeta *self)
{
self->priv = clutter_actor_meta_get_instance_private (self);
self->priv->is_enabled = TRUE;
self->priv->priority = CLUTTER_ACTOR_META_PRIORITY_DEFAULT;
ClutterActorMetaPrivate *priv =
clutter_actor_meta_get_instance_private (self);
priv->is_enabled = TRUE;
priv->priority = CLUTTER_ACTOR_META_PRIORITY_DEFAULT;
}
/**
@ -263,13 +276,17 @@ void
clutter_actor_meta_set_name (ClutterActorMeta *meta,
const gchar *name)
{
ClutterActorMetaPrivate *priv;
g_return_if_fail (CLUTTER_IS_ACTOR_META (meta));
if (g_strcmp0 (meta->priv->name, name) == 0)
priv = clutter_actor_meta_get_instance_private (meta);
if (g_strcmp0 (priv->name, name) == 0)
return;
g_free (meta->priv->name);
meta->priv->name = g_strdup (name);
g_free (priv->name);
priv->name = g_strdup (name);
g_object_notify_by_pspec (G_OBJECT (meta), obj_props[PROP_NAME]);
}
@ -290,9 +307,13 @@ clutter_actor_meta_set_name (ClutterActorMeta *meta,
const gchar *
clutter_actor_meta_get_name (ClutterActorMeta *meta)
{
ClutterActorMetaPrivate *priv;
g_return_val_if_fail (CLUTTER_IS_ACTOR_META (meta), NULL);
return meta->priv->name;
priv = clutter_actor_meta_get_instance_private (meta);
return priv->name;
}
/**
@ -308,11 +329,14 @@ void
clutter_actor_meta_set_enabled (ClutterActorMeta *meta,
gboolean is_enabled)
{
ClutterActorMetaPrivate *priv;
g_return_if_fail (CLUTTER_IS_ACTOR_META (meta));
priv = clutter_actor_meta_get_instance_private (meta);
is_enabled = !!is_enabled;
if (meta->priv->is_enabled == is_enabled)
if (priv->is_enabled == is_enabled)
return;
CLUTTER_ACTOR_META_GET_CLASS (meta)->set_enabled (meta, is_enabled);
@ -331,9 +355,13 @@ clutter_actor_meta_set_enabled (ClutterActorMeta *meta,
gboolean
clutter_actor_meta_get_enabled (ClutterActorMeta *meta)
{
ClutterActorMetaPrivate *priv;
g_return_val_if_fail (CLUTTER_IS_ACTOR_META (meta), FALSE);
return meta->priv->is_enabled;
priv = clutter_actor_meta_get_instance_private (meta);
return priv->is_enabled;
}
/*
@ -369,40 +397,54 @@ _clutter_actor_meta_set_actor (ClutterActorMeta *meta,
ClutterActor *
clutter_actor_meta_get_actor (ClutterActorMeta *meta)
{
ClutterActorMetaPrivate *priv;
g_return_val_if_fail (CLUTTER_IS_ACTOR_META (meta), NULL);
return meta->priv->actor;
priv = clutter_actor_meta_get_instance_private (meta);
return priv->actor;
}
void
_clutter_actor_meta_set_priority (ClutterActorMeta *meta,
gint priority)
{
ClutterActorMetaPrivate *priv;
g_return_if_fail (CLUTTER_IS_ACTOR_META (meta));
priv = clutter_actor_meta_get_instance_private (meta);
/* This property shouldn't be modified after the actor meta is in
use because ClutterMetaGroup doesn't resort the list when it
changes. If we made the priority public then we could either make
the priority a construct-only property or listen for
notifications on the property from the ClutterMetaGroup and
resort. */
g_return_if_fail (meta->priv->actor == NULL);
g_return_if_fail (priv->actor == NULL);
meta->priv->priority = priority;
priv->priority = priority;
}
gint
_clutter_actor_meta_get_priority (ClutterActorMeta *meta)
{
ClutterActorMetaPrivate *priv;
g_return_val_if_fail (CLUTTER_IS_ACTOR_META (meta), 0);
return meta->priv->priority;
priv = clutter_actor_meta_get_instance_private (meta);
return priv->priority;
}
gboolean
_clutter_actor_meta_is_internal (ClutterActorMeta *meta)
{
gint priority = meta->priv->priority;
ClutterActorMetaPrivate *priv =
clutter_actor_meta_get_instance_private (meta);
gint priority = priv->priority;
return (priority <= CLUTTER_ACTOR_META_PRIORITY_INTERNAL_LOW ||
priority >= CLUTTER_ACTOR_META_PRIORITY_INTERNAL_HIGH);
@ -449,19 +491,21 @@ void
_clutter_meta_group_add_meta (ClutterMetaGroup *group,
ClutterActorMeta *meta)
{
ClutterActorMetaPrivate *priv =
clutter_actor_meta_get_instance_private (meta);
GList *prev = NULL, *l;
if (meta->priv->actor != NULL)
if (priv->actor != NULL)
{
g_warning ("The meta of type '%s' with name '%s' is "
"already attached to actor '%s'",
G_OBJECT_TYPE_NAME (meta),
meta->priv->name != NULL
? meta->priv->name
priv->name != NULL
? priv->name
: "<unknown>",
clutter_actor_get_name (meta->priv->actor) != NULL
? clutter_actor_get_name (meta->priv->actor)
: G_OBJECT_TYPE_NAME (meta->priv->actor));
clutter_actor_get_name (priv->actor) != NULL
? clutter_actor_get_name (priv->actor)
: G_OBJECT_TYPE_NAME (priv->actor));
return;
}
@ -497,13 +541,16 @@ void
_clutter_meta_group_remove_meta (ClutterMetaGroup *group,
ClutterActorMeta *meta)
{
if (meta->priv->actor != group->actor)
ClutterActorMetaPrivate *priv =
clutter_actor_meta_get_instance_private (meta);
if (priv->actor != group->actor)
{
g_warning ("The meta of type '%s' with name '%s' is not "
"attached to the actor '%s'",
G_OBJECT_TYPE_NAME (meta),
meta->priv->name != NULL
? meta->priv->name
priv->name != NULL
? priv->name
: "<unknown>",
clutter_actor_get_name (group->actor) != NULL
? clutter_actor_get_name (group->actor)
@ -646,8 +693,10 @@ _clutter_meta_group_get_meta (ClutterMetaGroup *group,
for (l = group->meta; l != NULL; l = l->next)
{
ClutterActorMeta *meta = l->data;
ClutterActorMetaPrivate *priv =
clutter_actor_meta_get_instance_private (meta);
if (g_strcmp0 (meta->priv->name, name) == 0)
if (g_strcmp0 (priv->name, name) == 0)
return meta;
}
@ -667,6 +716,8 @@ _clutter_meta_group_get_meta (ClutterMetaGroup *group,
const gchar *
_clutter_actor_meta_get_debug_name (ClutterActorMeta *meta)
{
return meta->priv->name != NULL ? meta->priv->name
: G_OBJECT_TYPE_NAME (meta);
ClutterActorMetaPrivate *priv =
clutter_actor_meta_get_instance_private (meta);
return priv->name != NULL ? priv->name : G_OBJECT_TYPE_NAME (meta);
}

View File

@ -33,31 +33,13 @@
G_BEGIN_DECLS
#define CLUTTER_TYPE_ACTOR_META (clutter_actor_meta_get_type ())
#define CLUTTER_ACTOR_META(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_ACTOR_META, ClutterActorMeta))
#define CLUTTER_IS_ACTOR_META(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_ACTOR_META))
#define CLUTTER_ACTOR_META_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_ACTOR_META, ClutterActorMetaClass))
#define CLUTTER_IS_ACTOR_META_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_ACTOR_META))
#define CLUTTER_ACTOR_META_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_ACTOR_META, ClutterActorMetaClass))
#define CLUTTER_TYPE_ACTOR_META (clutter_actor_meta_get_type ())
typedef struct _ClutterActorMetaPrivate ClutterActorMetaPrivate;
typedef struct _ClutterActorMetaClass ClutterActorMetaClass;
CLUTTER_EXPORT
G_DECLARE_DERIVABLE_TYPE (ClutterActorMeta, clutter_actor_meta,
CLUTTER, ACTOR_META, GInitiallyUnowned);
/**
* ClutterActorMeta:
*
* The #ClutterActorMeta structure contains only
* private data and should be accessed using the provided API
*
* Since: 1.4
*/
struct _ClutterActorMeta
{
/*< private >*/
GInitiallyUnowned parent_instance;
ClutterActorMetaPrivate *priv;
};
typedef struct _ClutterActorMetaPrivate ClutterActorMetaPrivate;
/**
* ClutterActorMetaClass:
@ -99,9 +81,6 @@ struct _ClutterActorMetaClass
void (* _clutter_meta6) (void);
};
CLUTTER_EXPORT
GType clutter_actor_meta_get_type (void) G_GNUC_CONST;
CLUTTER_EXPORT
void clutter_actor_meta_set_name (ClutterActorMeta *meta,
const gchar *name);

View File

@ -698,7 +698,6 @@ struct _ClutterActorPrivate
* allocation
*/
ClutterActorBox allocation;
ClutterAllocationFlags allocation_flags;
/* clip, in actor coordinates */
graphene_rect_t clip;
@ -854,6 +853,7 @@ struct _ClutterActorPrivate
guint needs_paint_volume_update : 1;
guint had_effects_on_last_paint_volume_update : 1;
guint needs_compute_resource_scale : 1;
guint absolute_origin_changed : 1;
};
enum
@ -1013,7 +1013,6 @@ enum
MOTION_EVENT,
ENTER_EVENT,
LEAVE_EVENT,
ALLOCATION_CHANGED,
TRANSITIONS_COMPLETED,
TOUCH_EVENT,
TRANSITION_STOPPED,
@ -1198,28 +1197,21 @@ clutter_actor_verify_map_state (ClutterActor *self)
if (CLUTTER_ACTOR_IS_REALIZED (self))
{
/* all bets are off during reparent when we're potentially realized,
* but should not be according to invariants
*/
if (!CLUTTER_ACTOR_IN_REPARENT (self))
if (priv->parent == NULL)
{
if (priv->parent == NULL)
if (!CLUTTER_ACTOR_IS_TOPLEVEL (self))
{
if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
{
}
else
g_warning ("Realized non-toplevel actor '%s' should "
"have a parent",
_clutter_actor_get_debug_name (self));
}
else if (!CLUTTER_ACTOR_IS_REALIZED (priv->parent))
{
g_warning ("Realized actor %s has an unrealized parent %s",
_clutter_actor_get_debug_name (self),
_clutter_actor_get_debug_name (priv->parent));
g_warning ("Realized non-toplevel actor '%s' should "
"have a parent",
_clutter_actor_get_debug_name (self));
}
}
else if (!CLUTTER_ACTOR_IS_REALIZED (priv->parent))
{
g_warning ("Realized actor %s has an unrealized parent %s",
_clutter_actor_get_debug_name (self),
_clutter_actor_get_debug_name (priv->parent));
}
}
if (CLUTTER_ACTOR_IS_MAPPED (self))
@ -1228,70 +1220,64 @@ clutter_actor_verify_map_state (ClutterActor *self)
g_warning ("Actor '%s' is mapped but not realized",
_clutter_actor_get_debug_name (self));
/* remaining bets are off during reparent when we're potentially
* mapped, but should not be according to invariants
*/
if (!CLUTTER_ACTOR_IN_REPARENT (self))
if (priv->parent == NULL)
{
if (priv->parent == NULL)
if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
{
if (CLUTTER_ACTOR_IS_TOPLEVEL (self))
if (!CLUTTER_ACTOR_IS_VISIBLE (self) &&
!CLUTTER_ACTOR_IN_DESTRUCTION (self))
{
if (!CLUTTER_ACTOR_IS_VISIBLE (self) &&
!CLUTTER_ACTOR_IN_DESTRUCTION (self))
{
g_warning ("Toplevel actor '%s' is mapped "
"but not visible",
_clutter_actor_get_debug_name (self));
}
}
else
{
g_warning ("Mapped actor '%s' should have a parent",
g_warning ("Toplevel actor '%s' is mapped "
"but not visible",
_clutter_actor_get_debug_name (self));
}
}
else
{
ClutterActor *iter = self;
g_warning ("Mapped actor '%s' should have a parent",
_clutter_actor_get_debug_name (self));
}
}
else
{
ClutterActor *iter = self;
/* check for the enable_paint_unmapped flag on the actor
* and parents; if the flag is enabled at any point of this
* branch of the scene graph then all the later checks
* become pointless
*/
while (iter != NULL)
{
if (iter->priv->enable_paint_unmapped)
return;
/* check for the enable_paint_unmapped flag on the actor
* and parents; if the flag is enabled at any point of this
* branch of the scene graph then all the later checks
* become pointless
*/
while (iter != NULL)
{
if (iter->priv->enable_paint_unmapped)
return;
iter = iter->priv->parent;
}
iter = iter->priv->parent;
}
if (!CLUTTER_ACTOR_IS_VISIBLE (priv->parent))
{
g_warning ("Actor '%s' should not be mapped if parent '%s'"
"is not visible",
_clutter_actor_get_debug_name (self),
_clutter_actor_get_debug_name (priv->parent));
}
if (!CLUTTER_ACTOR_IS_VISIBLE (priv->parent))
{
g_warning ("Actor '%s' should not be mapped if parent '%s'"
"is not visible",
_clutter_actor_get_debug_name (self),
_clutter_actor_get_debug_name (priv->parent));
}
if (!CLUTTER_ACTOR_IS_REALIZED (priv->parent))
{
g_warning ("Actor '%s' should not be mapped if parent '%s'"
"is not realized",
_clutter_actor_get_debug_name (self),
_clutter_actor_get_debug_name (priv->parent));
}
if (!CLUTTER_ACTOR_IS_REALIZED (priv->parent))
{
g_warning ("Actor '%s' should not be mapped if parent '%s'"
"is not realized",
_clutter_actor_get_debug_name (self),
_clutter_actor_get_debug_name (priv->parent));
}
if (!CLUTTER_ACTOR_IS_TOPLEVEL (priv->parent))
{
if (!CLUTTER_ACTOR_IS_MAPPED (priv->parent))
g_warning ("Actor '%s' is mapped but its non-toplevel "
"parent '%s' is not mapped",
_clutter_actor_get_debug_name (self),
_clutter_actor_get_debug_name (priv->parent));
}
if (!CLUTTER_ACTOR_IS_TOPLEVEL (priv->parent))
{
if (!CLUTTER_ACTOR_IS_MAPPED (priv->parent))
g_warning ("Actor '%s' is mapped but its non-toplevel "
"parent '%s' is not mapped",
_clutter_actor_get_debug_name (self),
_clutter_actor_get_debug_name (priv->parent));
}
}
}
@ -1586,13 +1572,10 @@ clutter_actor_update_map_state (ClutterActor *self,
_clutter_actor_get_debug_name (priv->parent));
}
/* If in reparent, we temporarily suspend unmap and unrealize.
*
* We want to go in the order "realize, map" and "unmap, unrealize"
*/
/* We want to go in the order "realize, map" and "unmap, unrealize" */
/* Unmap */
if (!should_be_mapped && !CLUTTER_ACTOR_IN_REPARENT (self))
if (!should_be_mapped)
clutter_actor_set_mapped (self, FALSE);
/* Realize */
@ -1603,7 +1586,7 @@ clutter_actor_update_map_state (ClutterActor *self,
g_assert (!(must_be_realized && !may_be_realized));
/* Unrealize */
if (!may_be_realized && !CLUTTER_ACTOR_IN_REPARENT (self))
if (!may_be_realized)
clutter_actor_unrealize_not_hiding (self);
/* Map */
@ -2593,15 +2576,13 @@ clutter_actor_notify_if_geometry_changed (ClutterActor *self,
* Return value: %TRUE if the allocation of the #ClutterActor has been
* changed, and %FALSE otherwise
*/
static inline gboolean
static inline void
clutter_actor_set_allocation_internal (ClutterActor *self,
const ClutterActorBox *box,
ClutterAllocationFlags flags)
const ClutterActorBox *box)
{
ClutterActorPrivate *priv = self->priv;
GObject *obj;
gboolean x1_changed, y1_changed, x2_changed, y2_changed;
gboolean retval;
ClutterActorBox old_alloc = { 0, };
obj = G_OBJECT (self);
@ -2616,7 +2597,6 @@ clutter_actor_set_allocation_internal (ClutterActor *self,
y2_changed = priv->allocation.y2 != box->y2;
priv->allocation = *box;
priv->allocation_flags = flags;
/* allocation is authoritative */
priv->needs_width_request = FALSE;
@ -2641,88 +2621,37 @@ clutter_actor_set_allocation_internal (ClutterActor *self,
priv->content_box_valid = FALSE;
g_object_notify_by_pspec (obj, obj_props[PROP_CONTENT_BOX]);
}
retval = TRUE;
}
else
retval = FALSE;
clutter_actor_notify_if_geometry_changed (self, &old_alloc);
g_object_thaw_notify (obj);
return retval;
}
static void clutter_actor_real_allocate (ClutterActor *self,
const ClutterActorBox *box,
ClutterAllocationFlags flags);
static inline void
clutter_actor_maybe_layout_children (ClutterActor *self,
const ClutterActorBox *allocation,
ClutterAllocationFlags flags)
static void
clutter_actor_real_allocate (ClutterActor *self,
const ClutterActorBox *box)
{
ClutterActorPrivate *priv = self->priv;
/* this is going to be a bit hard to follow, so let's put an explanation
* here.
*
* we want ClutterActor to have a default layout manager if the actor was
* created using "g_object_new (CLUTTER_TYPE_ACTOR, NULL)".
*
* we also want any subclass of ClutterActor that does not override the
* ::allocate() virtual function to delegate to a layout manager.
*
* finally, we want to allow people subclassing ClutterActor and overriding
* the ::allocate() vfunc to let Clutter delegate to the layout manager.
*
* on the other hand, we want existing actor subclasses overriding the
* ::allocate() virtual function and chaining up to the parent's
* implementation to continue working without allocating their children
* twice, or without entering an allocation loop.
*
* for the first two points, we check if the class of the actor is
* overridding the ::allocate() virtual function; if it isn't, then we
* follow through with checking whether we have children and a layout
* manager, and eventually calling clutter_layout_manager_allocate().
*
* for the third point, we check the CLUTTER_DELEGATE_LAYOUT flag in the
* allocation flags that we got passed, and if it is present, we continue
* with the check above.
*
* if neither of these two checks yields a positive result, we just
* assume that the ::allocate() virtual function that resulted in this
* function being called will also allocate the children of the actor.
g_object_freeze_notify (G_OBJECT (self));
clutter_actor_set_allocation_internal (self, box);
/* we allocate our children before we notify changes in our geometry,
* so that people connecting to properties will be able to get valid
* data out of the sub-tree of the scene graph that has this actor at
* the root.
*/
if (CLUTTER_ACTOR_GET_CLASS (self)->allocate == clutter_actor_real_allocate)
goto check_layout;
if ((flags & CLUTTER_DELEGATE_LAYOUT) != 0)
goto check_layout;
return;
check_layout:
if (priv->n_children != 0 &&
priv->layout_manager != NULL)
{
ClutterContainer *container = CLUTTER_CONTAINER (self);
ClutterAllocationFlags children_flags;
ClutterActorBox children_box;
/* normalize the box passed to the layout manager */
children_box.x1 = children_box.y1 = 0.f;
children_box.x2 = (allocation->x2 - allocation->x1);
children_box.y2 = (allocation->y2 - allocation->y1);
/* remove the DELEGATE_LAYOUT flag; this won't be passed to
* the actor's children, since it refers only to the current
* actor's allocation.
*/
children_flags = flags;
children_flags &= ~CLUTTER_DELEGATE_LAYOUT;
children_box.x2 = box->x2 - box->x1;
children_box.y2 = box->y2 - box->y1;
CLUTTER_NOTE (LAYOUT,
"Allocating %d children of %s "
@ -2730,46 +2659,15 @@ check_layout:
"using %s",
priv->n_children,
_clutter_actor_get_debug_name (self),
allocation->x1,
allocation->y1,
(allocation->x2 - allocation->x1),
(allocation->y2 - allocation->y1),
box->x1,
box->y1,
(box->x2 - box->x1),
(box->y2 - box->y1),
G_OBJECT_TYPE_NAME (priv->layout_manager));
clutter_layout_manager_allocate (priv->layout_manager,
container,
&children_box,
children_flags);
}
}
static void
clutter_actor_real_allocate (ClutterActor *self,
const ClutterActorBox *box,
ClutterAllocationFlags flags)
{
ClutterActorPrivate *priv = self->priv;
gboolean changed;
g_object_freeze_notify (G_OBJECT (self));
changed = clutter_actor_set_allocation_internal (self, box, flags);
/* we allocate our children before we notify changes in our geometry,
* so that people connecting to properties will be able to get valid
* data out of the sub-tree of the scene graph that has this actor at
* the root.
*/
clutter_actor_maybe_layout_children (self, box, flags);
if (changed)
{
ClutterActorBox signal_box = priv->allocation;
ClutterAllocationFlags signal_flags = priv->allocation_flags;
g_signal_emit (self, actor_signals[ALLOCATION_CHANGED], 0,
&signal_box,
signal_flags);
CLUTTER_CONTAINER (self),
&children_box);
}
g_object_thaw_notify (G_OBJECT (self));
@ -2808,7 +2706,7 @@ _clutter_actor_propagate_queue_redraw (ClutterActor *self,
if (stop)
break;
self = clutter_actor_get_parent (self);
self = self->priv->parent;
}
}
@ -3092,96 +2990,6 @@ _clutter_actor_transform_and_project_box (ClutterActor *self,
_clutter_actor_fully_transform_vertices (self, box_vertices, verts, 4);
}
/**
* clutter_actor_get_allocation_vertices:
* @self: A #ClutterActor
* @ancestor: (allow-none): A #ClutterActor to calculate the vertices
* against, or %NULL to use the #ClutterStage
* @verts: (out) (array fixed-size=4): return
* location for an array of 4 #graphene_point3d_t in which to store the result
*
* Calculates the transformed coordinates of the four corners of the
* actor in the plane of @ancestor. The returned vertices relate to
* the #ClutterActorBox coordinates as follows:
*
* - @verts[0] contains (x1, y1)
* - @verts[1] contains (x2, y1)
* - @verts[2] contains (x1, y2)
* - @verts[3] contains (x2, y2)
*
* If @ancestor is %NULL the ancestor will be the #ClutterStage. In
* this case, the coordinates returned will be the coordinates on
* the stage before the projection is applied. This is different from
* the behaviour of clutter_actor_get_abs_allocation_vertices().
*
* Since: 0.6
*/
void
clutter_actor_get_allocation_vertices (ClutterActor *self,
ClutterActor *ancestor,
graphene_point3d_t *verts)
{
ClutterActorPrivate *priv;
ClutterActorBox box;
graphene_point3d_t vertices[4];
CoglMatrix modelview;
g_return_if_fail (CLUTTER_IS_ACTOR (self));
g_return_if_fail (ancestor == NULL || CLUTTER_IS_ACTOR (ancestor));
if (ancestor == NULL)
ancestor = _clutter_actor_get_stage_internal (self);
/* Fallback to a NOP transform if the actor isn't parented under a
* stage. */
if (ancestor == NULL)
ancestor = self;
priv = self->priv;
/* if the actor needs to be allocated we force a relayout, so that
* we will have valid values to use in the transformations */
if (priv->needs_allocation)
{
ClutterActor *stage = _clutter_actor_get_stage_internal (self);
if (stage)
_clutter_stage_maybe_relayout (stage);
else
{
box.x1 = box.y1 = 0;
/* The result isn't really meaningful in this case but at
* least try to do something *vaguely* reasonable... */
clutter_actor_get_size (self, &box.x2, &box.y2);
}
}
clutter_actor_get_allocation_box (self, &box);
vertices[0].x = box.x1;
vertices[0].y = box.y1;
vertices[0].z = 0;
vertices[1].x = box.x2;
vertices[1].y = box.y1;
vertices[1].z = 0;
vertices[2].x = box.x1;
vertices[2].y = box.y2;
vertices[2].z = 0;
vertices[3].x = box.x2;
vertices[3].y = box.y2;
vertices[3].z = 0;
_clutter_actor_get_relative_transformation_matrix (self, ancestor,
&modelview);
cogl_matrix_transform_points (&modelview,
3,
sizeof (graphene_point3d_t),
vertices,
sizeof (graphene_point3d_t),
vertices,
4);
}
/**
* clutter_actor_get_abs_allocation_vertices:
* @self: A #ClutterActor
@ -3416,8 +3224,6 @@ _clutter_actor_apply_relative_transformation_matrix (ClutterActor *self,
ClutterActor *ancestor,
CoglMatrix *matrix)
{
ClutterActor *parent;
/* Note we terminate before ever calling stage->apply_transform()
* since that would conceptually be relative to the underlying
* window OpenGL coordinates so we'd need a special @ancestor
@ -3425,10 +3231,9 @@ _clutter_actor_apply_relative_transformation_matrix (ClutterActor *self,
if (self == ancestor)
return;
parent = clutter_actor_get_parent (self);
if (parent != NULL)
_clutter_actor_apply_relative_transformation_matrix (parent, ancestor,
if (self->priv->parent != NULL)
_clutter_actor_apply_relative_transformation_matrix (self->priv->parent,
ancestor,
matrix);
_clutter_actor_apply_modelview_transform (self, matrix);
@ -4578,8 +4383,7 @@ clutter_actor_remove_child_internal (ClutterActor *self,
clutter_actor_queue_compute_expand (self);
}
if (emit_parent_set && !CLUTTER_ACTOR_IN_REPARENT (child) &&
!CLUTTER_ACTOR_IN_DESTRUCTION (child))
if (emit_parent_set && !CLUTTER_ACTOR_IN_DESTRUCTION (child))
{
child->priv->needs_compute_resource_scale = TRUE;
g_signal_emit (child, actor_signals[PARENT_SET], 0, self);
@ -8715,35 +8519,6 @@ clutter_actor_class_init (ClutterActorClass *klass)
G_TYPE_NONE, 1,
CLUTTER_TYPE_PICK_CONTEXT);
/**
* ClutterActor::allocation-changed:
* @actor: the #ClutterActor that emitted the signal
* @box: a #ClutterActorBox with the new allocation
* @flags: #ClutterAllocationFlags for the allocation
*
* The ::allocation-changed signal is emitted when the
* #ClutterActor:allocation property changes. Usually, application
* code should just use the notifications for the :allocation property
* but if you want to track the allocation flags as well, for instance
* to know whether the absolute origin of @actor changed, then you might
* want use this signal instead.
*
* Since: 1.0
*/
actor_signals[ALLOCATION_CHANGED] =
g_signal_new (I_("allocation-changed"),
G_TYPE_FROM_CLASS (object_class),
G_SIGNAL_RUN_LAST,
0,
NULL, NULL,
_clutter_marshal_VOID__BOXED_FLAGS,
G_TYPE_NONE, 2,
CLUTTER_TYPE_ACTOR_BOX | G_SIGNAL_TYPE_STATIC_SCOPE,
CLUTTER_TYPE_ALLOCATION_FLAGS);
g_signal_set_va_marshaller (actor_signals[ALLOCATION_CHANGED],
G_TYPE_FROM_CLASS (object_class),
_clutter_marshal_VOID__BOXED_FLAGSv);
/**
* ClutterActor::transitions-completed:
* @actor: a #ClutterActor
@ -8975,26 +8750,15 @@ static void
_clutter_actor_get_allocation_clip (ClutterActor *self,
ClutterActorBox *clip)
{
ClutterActorBox allocation;
/* XXX: we don't care if we get an out of date allocation here
* because clutter_actor_queue_redraw_with_clip knows to ignore
* the clip if the actor's allocation is invalid.
*
* This is noted because clutter_actor_get_allocation_box does some
* unnecessary work to support buggy code with a comment suggesting
* that it could be changed later which would be good for this use
* case!
*/
clutter_actor_get_allocation_box (self, &allocation);
ClutterActorPrivate *priv = self->priv;
/* NB: clutter_actor_queue_redraw_with_clip expects a box in the
* actor's own coordinate space but the allocation is in parent
* coordinates */
clip->x1 = 0;
clip->y1 = 0;
clip->x2 = allocation.x2 - allocation.x1;
clip->y2 = allocation.y2 - allocation.y1;
clip->x2 = priv->allocation.x2 - priv->allocation.x1;
clip->y2 = priv->allocation.y2 - priv->allocation.y1;
}
void
@ -9083,25 +8847,21 @@ _clutter_actor_queue_redraw_full (ClutterActor *self,
if (CLUTTER_ACTOR_IN_DESTRUCTION (self))
return;
/* we can ignore unmapped actors, unless they have at least one
* mapped clone or they are inside a cloned branch of the scene
* graph, as unmapped actors will simply be left unpainted.
/* we can ignore unmapped actors, unless they are inside a cloned branch
* of the scene graph, as unmapped actors will simply be left unpainted.
*
* this allows us to ignore redraws queued on leaf nodes when one
* of their parents has been hidden
*/
if (!CLUTTER_ACTOR_IS_MAPPED (self) &&
self->priv->in_cloned_branch == 0 &&
!clutter_actor_has_mapped_clones (self))
{
CLUTTER_NOTE (PAINT,
"Skipping queue_redraw('%s'): mapped=%s, "
"mapped_clones=%s, "
"in_cloned_branch=%s",
"has_mapped_clones=%s",
_clutter_actor_get_debug_name (self),
CLUTTER_ACTOR_IS_MAPPED (self) ? "yes" : "no",
clutter_actor_has_mapped_clones (self) ? "yes" : "no",
self->priv->in_cloned_branch != 0 ? "yes" : "no");
clutter_actor_has_mapped_clones (self) ? "yes" : "no");
return;
}
@ -10281,8 +10041,7 @@ clutter_actor_adjust_allocation (ClutterActor *self,
static void
clutter_actor_allocate_internal (ClutterActor *self,
const ClutterActorBox *allocation,
ClutterAllocationFlags flags)
const ClutterActorBox *allocation)
{
ClutterActorClass *klass;
@ -10292,7 +10051,7 @@ clutter_actor_allocate_internal (ClutterActor *self,
_clutter_actor_get_debug_name (self));
klass = CLUTTER_ACTOR_GET_CLASS (self);
klass->allocate (self, allocation, flags);
klass->allocate (self, allocation);
CLUTTER_UNSET_PRIVATE_FLAGS (self, CLUTTER_IN_RELAYOUT);
@ -10305,7 +10064,6 @@ clutter_actor_allocate_internal (ClutterActor *self,
* clutter_actor_allocate:
* @self: A #ClutterActor
* @box: new allocation of the actor, in parent-relative coordinates
* @flags: flags that control the allocation
*
* Assigns the size of a #ClutterActor from the given @box.
*
@ -10331,12 +10089,11 @@ clutter_actor_allocate_internal (ClutterActor *self,
* Since: 0.8
*/
void
clutter_actor_allocate (ClutterActor *self,
const ClutterActorBox *box,
ClutterAllocationFlags flags)
clutter_actor_allocate (ClutterActor *self,
const ClutterActorBox *box)
{
ClutterActorBox old_allocation, real_allocation;
gboolean origin_changed, child_moved, size_changed;
gboolean origin_changed, size_changed;
gboolean stage_allocation_changed;
ClutterActorPrivate *priv;
@ -10379,18 +10136,19 @@ clutter_actor_allocate (ClutterActor *self,
real_allocation.x2 = MAX (real_allocation.x2, real_allocation.x1);
real_allocation.y2 = MAX (real_allocation.y2, real_allocation.y1);
origin_changed = (flags & CLUTTER_ABSOLUTE_ORIGIN_CHANGED);
child_moved = (real_allocation.x1 != old_allocation.x1 ||
real_allocation.y1 != old_allocation.y1);
origin_changed = (real_allocation.x1 != old_allocation.x1 ||
real_allocation.y1 != old_allocation.y1);
size_changed = (real_allocation.x2 != old_allocation.x2 ||
real_allocation.y2 != old_allocation.y2);
if (origin_changed || child_moved || size_changed)
stage_allocation_changed = TRUE;
else
stage_allocation_changed = FALSE;
priv->absolute_origin_changed = priv->parent
? priv->parent->priv->absolute_origin_changed
: FALSE;
priv->absolute_origin_changed |= origin_changed;
stage_allocation_changed = priv->absolute_origin_changed || size_changed;
/* If we get an allocation "out of the blue"
* (we did not queue relayout), then we want to
@ -10420,24 +10178,10 @@ clutter_actor_allocate (ClutterActor *self,
{
/* If the actor didn't move but needs_allocation is set, we just
* need to allocate the children */
clutter_actor_allocate_internal (self, &real_allocation, flags);
clutter_actor_allocate_internal (self, &real_allocation);
return;
}
/* When ABSOLUTE_ORIGIN_CHANGED is passed in to
* clutter_actor_allocate(), it indicates whether the parent has its
* absolute origin moved; when passed in to ClutterActor::allocate()
* virtual method though, it indicates whether the child has its
* absolute origin moved. So we set it when child_moved is TRUE
*/
if (child_moved)
flags |= CLUTTER_ABSOLUTE_ORIGIN_CHANGED;
/* store the flags here, so that they can be propagated by the
* transition code
*/
self->priv->allocation_flags = flags;
_clutter_actor_create_transition (self, obj_props[PROP_ALLOCATION],
&priv->allocation,
&real_allocation);
@ -10447,20 +10191,14 @@ clutter_actor_allocate (ClutterActor *self,
* clutter_actor_set_allocation:
* @self: a #ClutterActor
* @box: a #ClutterActorBox
* @flags: allocation flags
*
* Stores the allocation of @self as defined by @box.
*
* This function can only be called from within the implementation of
* the #ClutterActorClass.allocate() virtual function.
*
* The allocation should have been adjusted to take into account constraints,
* alignment, and margin properties. If you are implementing a #ClutterActor
* subclass that provides its own layout management policy for its children
* instead of using a #ClutterLayoutManager delegate, you should not call
* this function on the children of @self; instead, you should call
* clutter_actor_allocate(), which will adjust the allocation box for
* you.
* The allocation @box should have been adjusted to take into account
* constraints, alignment, and margin properties.
*
* This function should only be used by subclasses of #ClutterActor
* that wish to store their allocation but cannot chain up to the
@ -10468,69 +10206,12 @@ clutter_actor_allocate (ClutterActor *self,
* #ClutterActorClass.allocate() virtual function will call this
* function.
*
* It is important to note that, while chaining up was the recommended
* behaviour for #ClutterActor subclasses prior to the introduction of
* this function, it is recommended to call clutter_actor_set_allocation()
* instead.
*
* If the #ClutterActor is using a #ClutterLayoutManager delegate object
* to handle the allocation of its children, this function will call
* the clutter_layout_manager_allocate() function only if the
* %CLUTTER_DELEGATE_LAYOUT flag is set on @flags, otherwise it is
* expected that the subclass will call clutter_layout_manager_allocate()
* by itself. For instance, the following code:
*
* |[<!-- language="C" -->
* static void
* my_actor_allocate (ClutterActor *actor,
* const ClutterActorBox *allocation,
* ClutterAllocationFlags flags)
* {
* ClutterActorBox new_alloc;
* ClutterAllocationFlags new_flags;
*
* adjust_allocation (allocation, &new_alloc);
*
* new_flags = flags | CLUTTER_DELEGATE_LAYOUT;
*
* // this will use the layout manager set on the actor
* clutter_actor_set_allocation (actor, &new_alloc, new_flags);
* }
* ]|
*
* is equivalent to this:
*
* |[<!-- language="C" -->
* static void
* my_actor_allocate (ClutterActor *actor,
* const ClutterActorBox *allocation,
* ClutterAllocationFlags flags)
* {
* ClutterLayoutManager *layout;
* ClutterActorBox new_alloc;
*
* adjust_allocation (allocation, &new_alloc);
*
* clutter_actor_set_allocation (actor, &new_alloc, flags);
*
* layout = clutter_actor_get_layout_manager (actor);
* clutter_layout_manager_allocate (layout,
* CLUTTER_CONTAINER (actor),
* &new_alloc,
* flags);
* }
* ]|
*
* Since: 1.10
*/
void
clutter_actor_set_allocation (ClutterActor *self,
const ClutterActorBox *box,
ClutterAllocationFlags flags)
const ClutterActorBox *box)
{
ClutterActorPrivate *priv;
gboolean changed;
g_return_if_fail (CLUTTER_IS_ACTOR (self));
g_return_if_fail (box != NULL);
@ -10542,28 +10223,9 @@ clutter_actor_set_allocation (ClutterActor *self,
return;
}
priv = self->priv;
g_object_freeze_notify (G_OBJECT (self));
changed = clutter_actor_set_allocation_internal (self, box, flags);
/* we allocate our children before we notify changes in our geometry,
* so that people connecting to properties will be able to get valid
* data out of the sub-tree of the scene graph that has this actor at
* the root.
*/
clutter_actor_maybe_layout_children (self, box, flags);
if (changed)
{
ClutterActorBox signal_box = priv->allocation;
ClutterAllocationFlags signal_flags = priv->allocation_flags;
g_signal_emit (self, actor_signals[ALLOCATION_CHANGED], 0,
&signal_box,
signal_flags);
}
clutter_actor_set_allocation_internal (self, box);
g_object_thaw_notify (G_OBJECT (self));
}
@ -13193,7 +12855,7 @@ clutter_actor_add_child_internal (ClutterActor *self,
clutter_actor_queue_compute_expand (self);
}
if (emit_parent_set && !CLUTTER_ACTOR_IN_REPARENT (child))
if (emit_parent_set)
{
child->priv->needs_compute_resource_scale = TRUE;
g_signal_emit (child, actor_signals[PARENT_SET], 0, NULL);
@ -15036,9 +14698,7 @@ clutter_actor_set_animatable_property (ClutterActor *actor,
break;
case PROP_ALLOCATION:
clutter_actor_allocate_internal (actor,
g_value_get_boxed (value),
actor->priv->allocation_flags);
clutter_actor_allocate_internal (actor, g_value_get_boxed (value));
clutter_actor_queue_redraw (actor);
break;
@ -15432,7 +15092,6 @@ clutter_actor_get_stage (ClutterActor *actor)
* actor's natural width
* @available_height: the maximum available height, or -1 to use the
* actor's natural height
* @flags: flags controlling the allocation
*
* Allocates @self taking into account the #ClutterActor's
* preferred size, but limiting it to the maximum available width
@ -15479,7 +15138,7 @@ clutter_actor_get_stage (ClutterActor *actor)
* box.x1 = x; box.y1 = y;
* box.x2 = box.x1 + available_width;
* box.y2 = box.y1 + available_height;
* clutter_actor_allocate (self, &box, flags);
* clutter_actor_allocate (self, &box);
* ]|
*
* This function can be used by fluid layout managers to allocate
@ -15493,8 +15152,7 @@ clutter_actor_allocate_available_size (ClutterActor *self,
gfloat x,
gfloat y,
gfloat available_width,
gfloat available_height,
ClutterAllocationFlags flags)
gfloat available_height)
{
ClutterActorPrivate *priv;
gfloat width, height;
@ -15550,13 +15208,12 @@ clutter_actor_allocate_available_size (ClutterActor *self,
box.y1 = y;
box.x2 = box.x1 + width;
box.y2 = box.y1 + height;
clutter_actor_allocate (self, &box, flags);
clutter_actor_allocate (self, &box);
}
/**
* clutter_actor_allocate_preferred_size:
* @self: a #ClutterActor
* @flags: flags controlling the allocation
*
* Allocates the natural size of @self.
*
@ -15574,8 +15231,7 @@ clutter_actor_allocate_available_size (ClutterActor *self,
* Since: 0.8
*/
void
clutter_actor_allocate_preferred_size (ClutterActor *self,
ClutterAllocationFlags flags)
clutter_actor_allocate_preferred_size (ClutterActor *self)
{
gfloat actor_x, actor_y;
gfloat natural_width, natural_height;
@ -15609,7 +15265,7 @@ clutter_actor_allocate_preferred_size (ClutterActor *self,
actor_box.x2 = actor_box.x1 + natural_width;
actor_box.y2 = actor_box.y1 + natural_height;
clutter_actor_allocate (self, &actor_box, flags);
clutter_actor_allocate (self, &actor_box);
}
/**
@ -15620,7 +15276,6 @@ clutter_actor_allocate_preferred_size (ClutterActor *self,
* @y_align: the vertical alignment, between 0 and 1
* @x_fill: whether the actor should fill horizontally
* @y_fill: whether the actor should fill vertically
* @flags: allocation flags to be passed to clutter_actor_allocate()
*
* Allocates @self by taking into consideration the available allocation
* area; an alignment factor on either axis; and whether the actor should
@ -15647,8 +15302,7 @@ clutter_actor_allocate_align_fill (ClutterActor *self,
gdouble x_align,
gdouble y_align,
gboolean x_fill,
gboolean y_fill,
ClutterAllocationFlags flags)
gboolean y_fill)
{
ClutterActorPrivate *priv;
ClutterActorBox allocation = CLUTTER_ACTOR_BOX_INIT_ZERO;
@ -15764,7 +15418,7 @@ out:
allocation.x2 = ceilf (allocation.x1 + MAX (child_width, 0));
allocation.y2 = ceilf (allocation.y1 + MAX (child_height, 0));
clutter_actor_allocate (self, &allocation, flags);
clutter_actor_allocate (self, &allocation);
}
/**
@ -19426,7 +19080,6 @@ should_skip_implicit_transition (ClutterActor *self,
* when those transitions happen
*/
if (!CLUTTER_ACTOR_IS_MAPPED (self) &&
priv->in_cloned_branch == 0 &&
!clutter_actor_has_mapped_clones (self))
return TRUE;
@ -21046,31 +20699,41 @@ _clutter_actor_queue_relayout_on_clones (ClutterActor *self)
* clutter_actor_has_mapped_clones:
* @self: a #ClutterActor
*
* Returns whether a #ClutterActor has any mapped clones.
* Returns whether a #ClutterActor or any parent actors have mapped clones
* that are clone-painting @self.
*
* Return: %TRUE if the actor has mapped clones, and %FALSE otherwise
*
* Since: 1.16
* Returns: %TRUE if the actor has mapped clones, %FALSE otherwise
*/
gboolean
clutter_actor_has_mapped_clones (ClutterActor *self)
{
ClutterActorPrivate *priv;
ClutterActor *actor;
GHashTableIter iter;
gpointer key;
g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
priv = self->priv;
if (priv->clones == NULL)
if (self->priv->in_cloned_branch == 0)
return FALSE;
g_hash_table_iter_init (&iter, priv->clones);
while (g_hash_table_iter_next (&iter, &key, NULL))
for (actor = self; actor; actor = actor->priv->parent)
{
if (CLUTTER_ACTOR_IS_MAPPED (key))
return TRUE;
if (actor->priv->clones)
{
g_hash_table_iter_init (&iter, actor->priv->clones);
while (g_hash_table_iter_next (&iter, &key, NULL))
{
if (CLUTTER_ACTOR_IS_MAPPED (key))
return TRUE;
}
}
/* Clones will force-show their own source actor but not children of
* it, so if we're hidden and an actor up the hierarchy has a clone,
* we won't be visisble.
*/
if (!CLUTTER_ACTOR_IS_VISIBLE (actor))
return FALSE;
}
return FALSE;

View File

@ -175,9 +175,12 @@ struct _ClutterActor
* @get_preferred_height: virtual function, used when querying the minimum
* and natural heights of an actor for a given width; it is used by
* clutter_actor_get_preferred_height()
* @allocate: virtual function, used when settings the coordinates of an
* actor; it is used by clutter_actor_allocate(); it must chain up to
* the parent's implementation, or call clutter_actor_set_allocation()
* @allocate: virtual function, used when setting the coordinates of an
* actor; it is used by clutter_actor_allocate(); when overriding this
* function without chaining up, clutter_actor_set_allocation() must be
* called and children must be allocated by the implementation, when
* chaining up though, those things will be done by the parent's
* implementation.
* @apply_transform: virtual function, used when applying the transformations
* to an actor before painting it or when transforming coordinates or
* the allocation; it must chain up to the parent's implementation
@ -253,8 +256,7 @@ struct _ClutterActorClass
gfloat *min_height_p,
gfloat *natural_height_p);
void (* allocate) (ClutterActor *self,
const ClutterActorBox *box,
ClutterAllocationFlags flags);
const ClutterActorBox *box);
/* transformations */
void (* apply_transform) (ClutterActor *actor,
@ -415,38 +417,29 @@ void clutter_actor_get_preferred_size
gfloat *natural_height_p);
CLUTTER_EXPORT
void clutter_actor_allocate (ClutterActor *self,
const ClutterActorBox *box,
ClutterAllocationFlags flags);
const ClutterActorBox *box);
CLUTTER_EXPORT
void clutter_actor_allocate_preferred_size (ClutterActor *self,
ClutterAllocationFlags flags);
void clutter_actor_allocate_preferred_size (ClutterActor *self);
CLUTTER_EXPORT
void clutter_actor_allocate_available_size (ClutterActor *self,
gfloat x,
gfloat y,
gfloat available_width,
gfloat available_height,
ClutterAllocationFlags flags);
gfloat available_height);
CLUTTER_EXPORT
void clutter_actor_allocate_align_fill (ClutterActor *self,
const ClutterActorBox *box,
gdouble x_align,
gdouble y_align,
gboolean x_fill,
gboolean y_fill,
ClutterAllocationFlags flags);
gboolean y_fill);
CLUTTER_EXPORT
void clutter_actor_set_allocation (ClutterActor *self,
const ClutterActorBox *box,
ClutterAllocationFlags flags);
const ClutterActorBox *box);
CLUTTER_EXPORT
void clutter_actor_get_allocation_box (ClutterActor *self,
ClutterActorBox *box);
CLUTTER_EXPORT
void clutter_actor_get_allocation_vertices (ClutterActor *self,
ClutterActor *ancestor,
graphene_point3d_t *verts);
CLUTTER_EXPORT
gboolean clutter_actor_has_allocation (ClutterActor *self);
CLUTTER_EXPORT
void clutter_actor_set_size (ClutterActor *self,

View File

@ -85,8 +85,7 @@ G_DEFINE_TYPE (ClutterAlignConstraint,
static void
source_position_changed (ClutterActor *actor,
const ClutterActorBox *allocation,
ClutterAllocationFlags flags,
GParamSpec *pspec,
ClutterAlignConstraint *align)
{
if (align->actor != NULL)
@ -410,7 +409,7 @@ clutter_align_constraint_set_source (ClutterAlignConstraint *align,
align->source = source;
if (align->source != NULL)
{
g_signal_connect (align->source, "allocation-changed",
g_signal_connect (align->source, "notify::allocation",
G_CALLBACK (source_position_changed),
align);
g_signal_connect (align->source, "destroy",

View File

@ -27,35 +27,23 @@
* @short_description: Interface for animatable classes
*
* #ClutterAnimatable is an interface that allows a #GObject class
* to control how a #ClutterAnimation will animate a property.
* to control how an actor will animate a property.
*
* Each #ClutterAnimatable should implement the
* #ClutterAnimatableInterface.interpolate_property() virtual function of the
* interface to compute the animation state between two values of an interval
* depending on a progress factor, expressed as a floating point value.
*
* If a #ClutterAnimatable is animated by a #ClutterAnimation
* instance, the #ClutterAnimation will call
* clutter_animatable_interpolate_property() passing the name of the
* currently animated property; the values interval; and the progress factor.
* The #ClutterAnimatable implementation should return the computed value for
* the animated
* property.
*
* #ClutterAnimatable is available since Clutter 1.0
*/
#include "clutter-build-config.h"
#define CLUTTER_DISABLE_DEPRECATION_WARNINGS
#include "clutter-animatable.h"
#include "clutter-interval.h"
#include "clutter-debug.h"
#include "clutter-private.h"
#include "deprecated/clutter-animation.h"
G_DEFINE_INTERFACE (ClutterAnimatable, clutter_animatable, G_TYPE_OBJECT);
static void

View File

@ -42,8 +42,6 @@ G_DECLARE_INTERFACE (ClutterAnimatable, clutter_animatable,
/**
* ClutterAnimatableInterface:
* @animate_property: virtual function for custom interpolation of a
* property. This virtual function is deprecated
* @find_property: virtual function for retrieving the #GParamSpec of
* an animatable property
* @get_initial_state: virtual function for retrieving the initial
@ -53,9 +51,6 @@ G_DECLARE_INTERFACE (ClutterAnimatable, clutter_animatable,
* @interpolate_value: virtual function for interpolating the progress
* of a property
*
* Base interface for #GObject<!-- -->s that can be animated by a
* a #ClutterAnimation.
*
* Since: 1.0
*/
struct _ClutterAnimatableInterface
@ -64,13 +59,6 @@ struct _ClutterAnimatableInterface
GTypeInterface parent_iface;
/*< public >*/
gboolean (* animate_property) (ClutterAnimatable *animatable,
ClutterAnimation *animation,
const gchar *property_name,
const GValue *initial_value,
const GValue *final_value,
gdouble progress,
GValue *value);
GParamSpec *(* find_property) (ClutterAnimatable *animatable,
const gchar *property_name);
void (* get_initial_state) (ClutterAnimatable *animatable,

View File

@ -30,9 +30,7 @@
#ifndef __GI_SCANNER__
G_DEFINE_AUTOPTR_CLEANUP_FUNC (ClutterAction, g_object_unref)
G_DEFINE_AUTOPTR_CLEANUP_FUNC (ClutterActor, g_object_unref)
G_DEFINE_AUTOPTR_CLEANUP_FUNC (ClutterActorMeta, g_object_unref)
G_DEFINE_AUTOPTR_CLEANUP_FUNC (ClutterAlignConstraint, g_object_unref)
G_DEFINE_AUTOPTR_CLEANUP_FUNC (ClutterBackend, g_object_unref)
G_DEFINE_AUTOPTR_CLEANUP_FUNC (ClutterBindConstraint, g_object_unref)
@ -43,7 +41,6 @@ G_DEFINE_AUTOPTR_CLEANUP_FUNC (ClutterBoxLayout, g_object_unref)
G_DEFINE_AUTOPTR_CLEANUP_FUNC (ClutterBrightnessContrastEffect, g_object_unref)
G_DEFINE_AUTOPTR_CLEANUP_FUNC (ClutterCanvas, g_object_unref)
G_DEFINE_AUTOPTR_CLEANUP_FUNC (ClutterChildMeta, g_object_unref)
G_DEFINE_AUTOPTR_CLEANUP_FUNC (ClutterClickAction, g_object_unref)
G_DEFINE_AUTOPTR_CLEANUP_FUNC (ClutterClone, g_object_unref)
G_DEFINE_AUTOPTR_CLEANUP_FUNC (ClutterColorizeEffect, g_object_unref)
G_DEFINE_AUTOPTR_CLEANUP_FUNC (ClutterConstraint, g_object_unref)
@ -53,7 +50,6 @@ G_DEFINE_AUTOPTR_CLEANUP_FUNC (ClutterDesaturateEffect, g_object_unref)
G_DEFINE_AUTOPTR_CLEANUP_FUNC (ClutterEffect, g_object_unref)
G_DEFINE_AUTOPTR_CLEANUP_FUNC (ClutterFixedLayout, g_object_unref)
G_DEFINE_AUTOPTR_CLEANUP_FUNC (ClutterFlowLayout, g_object_unref)
G_DEFINE_AUTOPTR_CLEANUP_FUNC (ClutterGestureAction, g_object_unref)
G_DEFINE_AUTOPTR_CLEANUP_FUNC (ClutterGridLayout, g_object_unref)
G_DEFINE_AUTOPTR_CLEANUP_FUNC (ClutterImage, g_object_unref)
G_DEFINE_AUTOPTR_CLEANUP_FUNC (ClutterInputDevice, g_object_unref)

View File

@ -406,8 +406,7 @@ get_actor_align_factor (ClutterActorAlign alignment)
static void
clutter_bin_layout_allocate (ClutterLayoutManager *manager,
ClutterContainer *container,
const ClutterActorBox *allocation,
ClutterAllocationFlags flags)
const ClutterActorBox *allocation)
{
gfloat allocation_x, allocation_y;
gfloat available_w, available_h;
@ -515,8 +514,7 @@ clutter_bin_layout_allocate (ClutterLayoutManager *manager,
clutter_actor_allocate_align_fill (child, &child_alloc,
x_align, y_align,
x_fill, y_fill,
flags);
x_fill, y_fill);
}
}

File diff suppressed because it is too large Load Diff

View File

@ -105,64 +105,6 @@ void clutter_box_layout_set_pack_start (ClutterBoxLayou
CLUTTER_EXPORT
gboolean clutter_box_layout_get_pack_start (ClutterBoxLayout *layout);
CLUTTER_DEPRECATED_FOR(clutter_box_layout_set_orientation)
void clutter_box_layout_set_vertical (ClutterBoxLayout *layout,
gboolean vertical);
CLUTTER_DEPRECATED_FOR(clutter_box_layout_get_orientation)
gboolean clutter_box_layout_get_vertical (ClutterBoxLayout *layout);
CLUTTER_EXPORT
void clutter_box_layout_pack (ClutterBoxLayout *layout,
ClutterActor *actor,
gboolean expand,
gboolean x_fill,
gboolean y_fill,
ClutterBoxAlignment x_align,
ClutterBoxAlignment y_align);
CLUTTER_DEPRECATED
void clutter_box_layout_set_alignment (ClutterBoxLayout *layout,
ClutterActor *actor,
ClutterBoxAlignment x_align,
ClutterBoxAlignment y_align);
CLUTTER_DEPRECATED
void clutter_box_layout_get_alignment (ClutterBoxLayout *layout,
ClutterActor *actor,
ClutterBoxAlignment *x_align,
ClutterBoxAlignment *y_align);
CLUTTER_DEPRECATED
void clutter_box_layout_set_fill (ClutterBoxLayout *layout,
ClutterActor *actor,
gboolean x_fill,
gboolean y_fill);
CLUTTER_DEPRECATED
void clutter_box_layout_get_fill (ClutterBoxLayout *layout,
ClutterActor *actor,
gboolean *x_fill,
gboolean *y_fill);
CLUTTER_DEPRECATED
void clutter_box_layout_set_expand (ClutterBoxLayout *layout,
ClutterActor *actor,
gboolean expand);
CLUTTER_DEPRECATED
gboolean clutter_box_layout_get_expand (ClutterBoxLayout *layout,
ClutterActor *actor);
CLUTTER_DEPRECATED
void clutter_box_layout_set_use_animations (ClutterBoxLayout *layout,
gboolean animate);
CLUTTER_DEPRECATED
gboolean clutter_box_layout_get_use_animations (ClutterBoxLayout *layout);
CLUTTER_DEPRECATED
void clutter_box_layout_set_easing_mode (ClutterBoxLayout *layout,
gulong mode);
CLUTTER_DEPRECATED
gulong clutter_box_layout_get_easing_mode (ClutterBoxLayout *layout);
CLUTTER_DEPRECATED
void clutter_box_layout_set_easing_duration (ClutterBoxLayout *layout,
guint msecs);
CLUTTER_DEPRECATED
guint clutter_box_layout_get_easing_duration (ClutterBoxLayout *layout);
G_END_DECLS
#endif /* __CLUTTER_BOX_LAYOUT_H__ */

View File

@ -159,7 +159,8 @@ static inline void
click_action_set_pressed (ClutterClickAction *action,
gboolean is_pressed)
{
ClutterClickActionPrivate *priv = action->priv;
ClutterClickActionPrivate *priv =
clutter_click_action_get_instance_private (action);
is_pressed = !!is_pressed;
@ -174,7 +175,8 @@ static inline void
click_action_set_held (ClutterClickAction *action,
gboolean is_held)
{
ClutterClickActionPrivate *priv = action->priv;
ClutterClickActionPrivate *priv =
clutter_click_action_get_instance_private (action);
is_held = !!is_held;
@ -189,7 +191,8 @@ static gboolean
click_action_emit_long_press (gpointer data)
{
ClutterClickAction *action = data;
ClutterClickActionPrivate *priv = action->priv;
ClutterClickActionPrivate *priv =
clutter_click_action_get_instance_private (action);
ClutterActor *actor;
gboolean result;
@ -213,7 +216,8 @@ click_action_emit_long_press (gpointer data)
static inline void
click_action_query_long_press (ClutterClickAction *action)
{
ClutterClickActionPrivate *priv = action->priv;
ClutterClickActionPrivate *priv =
clutter_click_action_get_instance_private (action);
ClutterActor *actor;
gboolean result = FALSE;
gint timeout;
@ -249,7 +253,8 @@ click_action_query_long_press (ClutterClickAction *action)
static inline void
click_action_cancel_long_press (ClutterClickAction *action)
{
ClutterClickActionPrivate *priv = action->priv;
ClutterClickActionPrivate *priv =
clutter_click_action_get_instance_private (action);
if (priv->long_press_id != 0)
{
@ -272,7 +277,8 @@ on_event (ClutterActor *actor,
ClutterEvent *event,
ClutterClickAction *action)
{
ClutterClickActionPrivate *priv = action->priv;
ClutterClickActionPrivate *priv =
clutter_click_action_get_instance_private (action);
gboolean has_button = TRUE;
if (!clutter_actor_meta_get_enabled (CLUTTER_ACTOR_META (action)))
@ -342,7 +348,8 @@ on_captured_event (ClutterActor *stage,
ClutterEvent *event,
ClutterClickAction *action)
{
ClutterClickActionPrivate *priv = action->priv;
ClutterClickActionPrivate *priv =
clutter_click_action_get_instance_private (action);
ClutterActor *actor;
ClutterModifierType modifier_state;
gboolean has_button = TRUE;
@ -434,7 +441,8 @@ clutter_click_action_set_actor (ClutterActorMeta *meta,
ClutterActor *actor)
{
ClutterClickAction *action = CLUTTER_CLICK_ACTION (meta);
ClutterClickActionPrivate *priv = action->priv;
ClutterClickActionPrivate *priv =
clutter_click_action_get_instance_private (action);
if (priv->event_id != 0)
{
@ -488,7 +496,8 @@ clutter_click_action_set_property (GObject *gobject,
const GValue *value,
GParamSpec *pspec)
{
ClutterClickActionPrivate *priv = CLUTTER_CLICK_ACTION (gobject)->priv;
ClutterClickActionPrivate *priv =
clutter_click_action_get_instance_private (CLUTTER_CLICK_ACTION (gobject));
switch (prop_id)
{
@ -512,7 +521,8 @@ clutter_click_action_get_property (GObject *gobject,
GValue *value,
GParamSpec *pspec)
{
ClutterClickActionPrivate *priv = CLUTTER_CLICK_ACTION (gobject)->priv;
ClutterClickActionPrivate *priv =
clutter_click_action_get_instance_private (CLUTTER_CLICK_ACTION (gobject));
switch (prop_id)
{
@ -541,7 +551,8 @@ clutter_click_action_get_property (GObject *gobject,
static void
clutter_click_action_dispose (GObject *gobject)
{
ClutterClickActionPrivate *priv = CLUTTER_CLICK_ACTION (gobject)->priv;
ClutterClickActionPrivate *priv =
clutter_click_action_get_instance_private (CLUTTER_CLICK_ACTION (gobject));
g_clear_signal_handler (&priv->event_id,
clutter_actor_meta_get_actor (CLUTTER_ACTOR_META (gobject)));
@ -699,9 +710,11 @@ clutter_click_action_class_init (ClutterClickActionClass *klass)
static void
clutter_click_action_init (ClutterClickAction *self)
{
self->priv = clutter_click_action_get_instance_private (self);
self->priv->long_press_threshold = -1;
self->priv->long_press_duration = -1;
ClutterClickActionPrivate *priv =
clutter_click_action_get_instance_private (self);
priv->long_press_threshold = -1;
priv->long_press_duration = -1;
}
/**
@ -741,7 +754,7 @@ clutter_click_action_release (ClutterClickAction *action)
g_return_if_fail (CLUTTER_IS_CLICK_ACTION (action));
priv = action->priv;
priv = clutter_click_action_get_instance_private (action);
if (!priv->is_held)
return;
@ -767,9 +780,13 @@ clutter_click_action_release (ClutterClickAction *action)
guint
clutter_click_action_get_button (ClutterClickAction *action)
{
ClutterClickActionPrivate *priv;
g_return_val_if_fail (CLUTTER_IS_CLICK_ACTION (action), 0);
return action->priv->press_button;
priv = clutter_click_action_get_instance_private (action);
return priv->press_button;
}
/**
@ -785,9 +802,13 @@ clutter_click_action_get_button (ClutterClickAction *action)
ClutterModifierType
clutter_click_action_get_state (ClutterClickAction *action)
{
ClutterClickActionPrivate *priv;
g_return_val_if_fail (CLUTTER_IS_CLICK_ACTION (action), 0);
return action->priv->modifier_state;
priv = clutter_click_action_get_instance_private (action);
return priv->modifier_state;
}
/**
@ -805,11 +826,15 @@ clutter_click_action_get_coords (ClutterClickAction *action,
gfloat *press_x,
gfloat *press_y)
{
ClutterClickActionPrivate *priv;
g_return_if_fail (CLUTTER_IS_ACTION (action));
priv = clutter_click_action_get_instance_private (action);
if (press_x != NULL)
*press_x = action->priv->press_x;
*press_x = priv->press_x;
if (press_y != NULL)
*press_y = action->priv->press_y;
*press_y = priv->press_y;
}

View File

@ -37,32 +37,13 @@
G_BEGIN_DECLS
#define CLUTTER_TYPE_CLICK_ACTION (clutter_click_action_get_type ())
#define CLUTTER_CLICK_ACTION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_CLICK_ACTION, ClutterClickAction))
#define CLUTTER_IS_CLICK_ACTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_CLICK_ACTION))
#define CLUTTER_CLICK_ACTION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_CLICK_ACTION, ClutterClickActionClass))
#define CLUTTER_IS_CLICK_ACTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_CLICK_ACTION))
#define CLUTTER_CLICK_ACTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_CLICK_ACTION, ClutterClickActionClass))
#define CLUTTER_TYPE_CLICK_ACTION (clutter_click_action_get_type ())
typedef struct _ClutterClickAction ClutterClickAction;
typedef struct _ClutterClickActionPrivate ClutterClickActionPrivate;
typedef struct _ClutterClickActionClass ClutterClickActionClass;
CLUTTER_EXPORT
G_DECLARE_DERIVABLE_TYPE (ClutterClickAction, clutter_click_action,
CLUTTER, CLICK_ACTION, ClutterAction);
/**
* ClutterClickAction:
*
* The #ClutterClickAction structure contains
* only private data and should be accessed using the provided API
*
* Since: 1.4
*/
struct _ClutterClickAction
{
/*< private >*/
ClutterAction parent_instance;
ClutterClickActionPrivate *priv;
};
typedef struct _ClutterClickActionPrivate ClutterClickActionPrivate;
/**
* ClutterClickActionClass:
@ -97,9 +78,6 @@ struct _ClutterClickActionClass
void (* _clutter_click_action7) (void);
};
CLUTTER_EXPORT
GType clutter_click_action_get_type (void) G_GNUC_CONST;
CLUTTER_EXPORT
ClutterAction * clutter_click_action_new (void);

View File

@ -240,15 +240,14 @@ clutter_clone_has_overlaps (ClutterActor *actor)
static void
clutter_clone_allocate (ClutterActor *self,
const ClutterActorBox *box,
ClutterAllocationFlags flags)
const ClutterActorBox *box)
{
ClutterClonePrivate *priv = CLUTTER_CLONE (self)->priv;
ClutterActorClass *parent_class;
/* chain up */
parent_class = CLUTTER_ACTOR_CLASS (clutter_clone_parent_class);
parent_class->allocate (self, box, flags);
parent_class->allocate (self, box);
if (priv->clone_source == NULL)
return;
@ -258,7 +257,7 @@ clutter_clone_allocate (ClutterActor *self,
*/
if (clutter_actor_get_parent (priv->clone_source) != NULL &&
!clutter_actor_has_allocation (priv->clone_source))
clutter_actor_allocate_preferred_size (priv->clone_source, flags);
clutter_actor_allocate_preferred_size (priv->clone_source);
#if 0
/* XXX - this is wrong: ClutterClone cannot clone unparented
@ -273,7 +272,7 @@ clutter_clone_allocate (ClutterActor *self,
* paint cycle, we can safely give it as much size as it requires
*/
if (clutter_actor_get_parent (priv->clone_source) == NULL)
clutter_actor_allocate_preferred_size (priv->clone_source, flags);
clutter_actor_allocate_preferred_size (priv->clone_source);
#endif
}

View File

@ -0,0 +1,92 @@
/*
* Copyright (C) 2007,2008,2009,2010,2011 Intel Corporation.
* 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-build-config.h"
#include "clutter-damage-history.h"
#define DAMAGE_HISTORY_LENGTH 0x10
struct _ClutterDamageHistory
{
cairo_region_t *damages[DAMAGE_HISTORY_LENGTH];
int index;
};
ClutterDamageHistory *
clutter_damage_history_new (void)
{
ClutterDamageHistory *history;
history = g_new0 (ClutterDamageHistory, 1);
return history;
}
void
clutter_damage_history_free (ClutterDamageHistory *history)
{
int i;
for (i = 0; i < G_N_ELEMENTS (history->damages); i++)
g_clear_pointer (&history->damages[i], cairo_region_destroy);
g_free (history);
}
gboolean
clutter_damage_history_is_age_valid (ClutterDamageHistory *history,
int age)
{
if (age >= DAMAGE_HISTORY_LENGTH ||
age < 1)
return FALSE;
if (!clutter_damage_history_lookup (history, age))
return FALSE;
return TRUE;
}
void
clutter_damage_history_record (ClutterDamageHistory *history,
const cairo_region_t *damage)
{
g_clear_pointer (&history->damages[history->index], cairo_region_destroy);
history->damages[history->index] = cairo_region_copy (damage);
}
static inline int
step_damage_index (int current,
int diff)
{
return (current + diff) & (DAMAGE_HISTORY_LENGTH - 1);
}
void
clutter_damage_history_step (ClutterDamageHistory *history)
{
history->index = step_damage_index (history->index, 1);
}
const cairo_region_t *
clutter_damage_history_lookup (ClutterDamageHistory *history,
int age)
{
return history->damages[step_damage_index (history->index, -age)];
}

View File

@ -0,0 +1,42 @@
/*
* Copyright (C) 2007,2008,2009,2010,2011 Intel Corporation.
* 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_DAMAGE_HISTORY_H
#define CLUTTER_DAMAGE_HISTORY_H
#include <cairo.h>
#include <glib.h>
typedef struct _ClutterDamageHistory ClutterDamageHistory;
ClutterDamageHistory * clutter_damage_history_new (void);
void clutter_damage_history_free (ClutterDamageHistory *history);
gboolean clutter_damage_history_is_age_valid (ClutterDamageHistory *history,
int age);
void clutter_damage_history_record (ClutterDamageHistory *history,
const cairo_region_t *damage);
void clutter_damage_history_step (ClutterDamageHistory *history);
const cairo_region_t * clutter_damage_history_lookup (ClutterDamageHistory *history,
int age);
#endif /* CLUTTER_DAMAGE_HISTORY_H */

View File

@ -128,10 +128,9 @@ clutter_deform_effect_deform_vertex (ClutterDeformEffect *effect,
}
static void
vbo_invalidate (ClutterActor *actor,
const ClutterActorBox *allocation,
ClutterAllocationFlags flags,
ClutterDeformEffect *effect)
vbo_invalidate (ClutterActor *actor,
GParamSpec *pspec,
ClutterDeformEffect *effect)
{
effect->priv->is_dirty = TRUE;
}
@ -156,7 +155,7 @@ clutter_deform_effect_set_actor (ClutterActorMeta *meta,
* changes
*/
if (actor != NULL)
priv->allocation_id = g_signal_connect (actor, "allocation-changed",
priv->allocation_id = g_signal_connect (actor, "notify::allocation",
G_CALLBACK (vbo_invalidate),
meta);

View File

@ -4,14 +4,11 @@
#define __CLUTTER_DEPRECATED_H_INSIDE__
#include "deprecated/clutter-actor.h"
#include "deprecated/clutter-alpha.h"
#include "deprecated/clutter-animation.h"
#include "deprecated/clutter-box.h"
#include "deprecated/clutter-container.h"
#include "deprecated/clutter-group.h"
#include "deprecated/clutter-rectangle.h"
#include "deprecated/clutter-stage.h"
#include "deprecated/clutter-state.h"
#include "deprecated/clutter-timeline.h"
#undef __CLUTTER_DEPRECATED_H_INSIDE__

View File

@ -190,7 +190,7 @@ typedef enum /*< prefix=CLUTTER_REQUEST >*/
* @CLUTTER_ANIMATION_LAST: last animation mode, used as a guard for
* registered global alpha functions
*
* The animation modes used by #ClutterAlpha and #ClutterAnimation. This
* The animation modes used by #ClutterAnimatable. This
* enumeration can be expanded in later versions of Clutter.
*
* <figure id="easing-modes">
@ -554,32 +554,6 @@ typedef enum /*< prefix=CLUTTER_OFFSCREEN_REDIRECT >*/
CLUTTER_OFFSCREEN_REDIRECT_ON_IDLE = 1 << 2
} ClutterOffscreenRedirect;
/**
* ClutterAllocationFlags:
* @CLUTTER_ALLOCATION_NONE: No flag set
* @CLUTTER_ABSOLUTE_ORIGIN_CHANGED: Whether the absolute origin of the
* actor has changed; this implies that any ancestor of the actor has
* been moved.
* @CLUTTER_DELEGATE_LAYOUT: Whether the allocation should be delegated
* to the #ClutterLayoutManager instance stored inside the
* #ClutterActor:layout-manager property of #ClutterActor. This flag
* should only be used if you are subclassing #ClutterActor and
* overriding the #ClutterActorClass.allocate() virtual function, but
* you wish to use the default implementation of the virtual function
* inside #ClutterActor. Added in Clutter 1.10.
*
* Flags passed to the #ClutterActorClass.allocate() virtual function
* and to the clutter_actor_allocate() function.
*
* Since: 1.0
*/
typedef enum
{
CLUTTER_ALLOCATION_NONE = 0,
CLUTTER_ABSOLUTE_ORIGIN_CHANGED = 1 << 1,
CLUTTER_DELEGATE_LAYOUT = 1 << 2
} ClutterAllocationFlags;
/**
* ClutterAlignAxis:
* @CLUTTER_ALIGN_X_AXIS: Maintain the alignment on the X axis

View File

@ -131,8 +131,7 @@ clutter_fixed_layout_get_preferred_height (ClutterLayoutManager *manager,
static void
clutter_fixed_layout_allocate (ClutterLayoutManager *manager,
ClutterContainer *container,
const ClutterActorBox *allocation,
ClutterAllocationFlags flags)
const ClutterActorBox *allocation)
{
ClutterActor *child;
@ -140,7 +139,7 @@ clutter_fixed_layout_allocate (ClutterLayoutManager *manager,
child != NULL;
child = clutter_actor_get_next_sibling (child))
{
clutter_actor_allocate_preferred_size (child, flags);
clutter_actor_allocate_preferred_size (child);
}
}

View File

@ -566,8 +566,7 @@ clutter_flow_layout_get_preferred_height (ClutterLayoutManager *manager,
static void
clutter_flow_layout_allocate (ClutterLayoutManager *manager,
ClutterContainer *container,
const ClutterActorBox *allocation,
ClutterAllocationFlags flags)
const ClutterActorBox *allocation)
{
ClutterFlowLayoutPrivate *priv = CLUTTER_FLOW_LAYOUT (manager)->priv;
ClutterActor *actor, *child;
@ -729,7 +728,7 @@ clutter_flow_layout_allocate (ClutterLayoutManager *manager,
child_alloc.y1 = ceil (item_y);
child_alloc.x2 = ceil (child_alloc.x1 + item_width);
child_alloc.y2 = ceil (child_alloc.y1 + item_height);
clutter_actor_allocate (child, &child_alloc, flags);
clutter_actor_allocate (child, &child_alloc);
if (priv->orientation == CLUTTER_FLOW_HORIZONTAL)
item_x = new_x;

View File

@ -157,7 +157,8 @@ G_DEFINE_TYPE_WITH_PRIVATE (ClutterGestureAction, clutter_gesture_action, CLUTTE
static GesturePoint *
gesture_register_point (ClutterGestureAction *action, ClutterEvent *event)
{
ClutterGestureActionPrivate *priv = action->priv;
ClutterGestureActionPrivate *priv =
clutter_gesture_action_get_instance_private (action);
GesturePoint *point = NULL;
if (priv->points->len >= MAX_GESTURE_POINTS)
@ -190,7 +191,8 @@ gesture_find_point (ClutterGestureAction *action,
ClutterEvent *event,
gint *position)
{
ClutterGestureActionPrivate *priv = action->priv;
ClutterGestureActionPrivate *priv =
clutter_gesture_action_get_instance_private (action);
GesturePoint *point = NULL;
ClutterEventType type = clutter_event_type (event);
ClutterInputDevice *device = clutter_event_get_device (event);
@ -220,9 +222,10 @@ gesture_find_point (ClutterGestureAction *action,
static void
gesture_unregister_point (ClutterGestureAction *action, gint position)
{
ClutterGestureActionPrivate *priv = action->priv;
ClutterGestureActionPrivate *priv =
clutter_gesture_action_get_instance_private (action);
if (action->priv->points->len == 0)
if (priv->points->len == 0)
return;
g_array_remove_index (priv->points, position);
@ -303,7 +306,8 @@ gesture_point_unset (GesturePoint *point)
static void
cancel_gesture (ClutterGestureAction *action)
{
ClutterGestureActionPrivate *priv = action->priv;
ClutterGestureActionPrivate *priv =
clutter_gesture_action_get_instance_private (action);
ClutterActor *actor;
priv->in_gesture = FALSE;
@ -313,14 +317,15 @@ cancel_gesture (ClutterGestureAction *action)
actor = clutter_actor_meta_get_actor (CLUTTER_ACTOR_META (action));
g_signal_emit (action, gesture_signals[GESTURE_CANCEL], 0, actor);
g_array_set_size (action->priv->points, 0);
g_array_set_size (priv->points, 0);
}
static gboolean
begin_gesture (ClutterGestureAction *action,
ClutterActor *actor)
{
ClutterGestureActionPrivate *priv = action->priv;
ClutterGestureActionPrivate *priv =
clutter_gesture_action_get_instance_private (action);
gboolean return_value;
priv->in_gesture = TRUE;
@ -353,7 +358,8 @@ stage_captured_event_cb (ClutterActor *stage,
ClutterEvent *event,
ClutterGestureAction *action)
{
ClutterGestureActionPrivate *priv = action->priv;
ClutterGestureActionPrivate *priv =
clutter_gesture_action_get_instance_private (action);
ClutterActor *actor;
gint position;
float threshold_x, threshold_y;
@ -488,7 +494,8 @@ actor_captured_event_cb (ClutterActor *actor,
ClutterEvent *event,
ClutterGestureAction *action)
{
ClutterGestureActionPrivate *priv = action->priv;
ClutterGestureActionPrivate *priv =
clutter_gesture_action_get_instance_private (action);
GesturePoint *point G_GNUC_UNUSED;
if ((clutter_event_type (event) != CLUTTER_BUTTON_PRESS) &&
@ -522,7 +529,8 @@ static void
clutter_gesture_action_set_actor (ClutterActorMeta *meta,
ClutterActor *actor)
{
ClutterGestureActionPrivate *priv = CLUTTER_GESTURE_ACTION (meta)->priv;
ClutterGestureActionPrivate *priv =
clutter_gesture_action_get_instance_private (CLUTTER_GESTURE_ACTION (meta));
ClutterActorMetaClass *meta_class =
CLUTTER_ACTOR_META_CLASS (clutter_gesture_action_parent_class);
@ -563,7 +571,8 @@ clutter_gesture_action_set_enabled (ClutterActorMeta *meta,
ClutterActorMetaClass *meta_class =
CLUTTER_ACTOR_META_CLASS (clutter_gesture_action_parent_class);
ClutterGestureAction *gesture_action = CLUTTER_GESTURE_ACTION (meta);
ClutterGestureActionPrivate *priv = gesture_action->priv;
ClutterGestureActionPrivate *priv =
clutter_gesture_action_get_instance_private (gesture_action);
if (!is_enabled && priv->in_gesture)
cancel_gesture (gesture_action);
@ -585,6 +594,8 @@ clutter_gesture_action_set_property (GObject *gobject,
GParamSpec *pspec)
{
ClutterGestureAction *self = CLUTTER_GESTURE_ACTION (gobject);
ClutterGestureActionPrivate *priv =
clutter_gesture_action_get_instance_private (self);
switch (prop_id)
{
@ -597,11 +608,15 @@ clutter_gesture_action_set_property (GObject *gobject,
break;
case PROP_THRESHOLD_TRIGGER_DISTANCE_X:
clutter_gesture_action_set_threshold_trigger_distance (self, g_value_get_float (value), self->priv->distance_y);
clutter_gesture_action_set_threshold_trigger_distance (self,
g_value_get_float (value),
priv->distance_y);
break;
case PROP_THRESHOLD_TRIGGER_DISTANCE_Y:
clutter_gesture_action_set_threshold_trigger_distance (self, self->priv->distance_x, g_value_get_float (value));
clutter_gesture_action_set_threshold_trigger_distance (self,
priv->distance_x,
g_value_get_float (value));
break;
default:
@ -616,28 +631,29 @@ clutter_gesture_action_get_property (GObject *gobject,
GValue *value,
GParamSpec *pspec)
{
ClutterGestureAction *self = CLUTTER_GESTURE_ACTION (gobject);
ClutterGestureActionPrivate *priv =
clutter_gesture_action_get_instance_private (CLUTTER_GESTURE_ACTION (gobject));
switch (prop_id)
{
case PROP_N_TOUCH_POINTS:
g_value_set_int (value, self->priv->requested_nb_points);
g_value_set_int (value, priv->requested_nb_points);
break;
case PROP_THRESHOLD_TRIGGER_EDGE:
g_value_set_enum (value, self->priv->edge);
g_value_set_enum (value, priv->edge);
break;
case PROP_THRESHOLD_TRIGGER_DISTANCE_X:
if (self->priv->distance_x > 0.0)
g_value_set_float (value, self->priv->distance_x);
if (priv->distance_x > 0.0)
g_value_set_float (value, priv->distance_x);
else
g_value_set_float (value, gesture_get_default_threshold ());
break;
case PROP_THRESHOLD_TRIGGER_DISTANCE_Y:
if (self->priv->distance_y > 0.0)
g_value_set_float (value, self->priv->distance_y);
if (priv->distance_y > 0.0)
g_value_set_float (value, priv->distance_y);
else
g_value_set_float (value, gesture_get_default_threshold ());
break;
@ -651,7 +667,8 @@ clutter_gesture_action_get_property (GObject *gobject,
static void
clutter_gesture_action_finalize (GObject *gobject)
{
ClutterGestureActionPrivate *priv = CLUTTER_GESTURE_ACTION (gobject)->priv;
ClutterGestureActionPrivate *priv =
clutter_gesture_action_get_instance_private (CLUTTER_GESTURE_ACTION (gobject));
g_array_unref (priv->points);
@ -843,13 +860,14 @@ clutter_gesture_action_class_init (ClutterGestureActionClass *klass)
static void
clutter_gesture_action_init (ClutterGestureAction *self)
{
self->priv = clutter_gesture_action_get_instance_private (self);
ClutterGestureActionPrivate *priv =
clutter_gesture_action_get_instance_private (self);
self->priv->points = g_array_sized_new (FALSE, TRUE, sizeof (GesturePoint), 3);
g_array_set_clear_func (self->priv->points, (GDestroyNotify) gesture_point_unset);
priv->points = g_array_sized_new (FALSE, TRUE, sizeof (GesturePoint), 3);
g_array_set_clear_func (priv->points, (GDestroyNotify) gesture_point_unset);
self->priv->requested_nb_points = 1;
self->priv->edge = CLUTTER_GESTURE_TRIGGER_EDGE_NONE;
priv->requested_nb_points = 1;
priv->edge = CLUTTER_GESTURE_TRIGGER_EDGE_NONE;
}
/**
@ -888,16 +906,21 @@ clutter_gesture_action_get_press_coords (ClutterGestureAction *action,
gfloat *press_x,
gfloat *press_y)
{
ClutterGestureActionPrivate *priv;
g_return_if_fail (CLUTTER_IS_GESTURE_ACTION (action));
g_return_if_fail (action->priv->points->len > point);
priv = clutter_gesture_action_get_instance_private (action);
g_return_if_fail (priv->points->len > point);
if (press_x)
*press_x = g_array_index (action->priv->points,
*press_x = g_array_index (priv->points,
GesturePoint,
point).press_x;
if (press_y)
*press_y = g_array_index (action->priv->points,
*press_y = g_array_index (priv->points,
GesturePoint,
point).press_y;
}
@ -923,16 +946,21 @@ clutter_gesture_action_get_motion_coords (ClutterGestureAction *action,
gfloat *motion_x,
gfloat *motion_y)
{
ClutterGestureActionPrivate *priv;
g_return_if_fail (CLUTTER_IS_GESTURE_ACTION (action));
g_return_if_fail (action->priv->points->len > point);
priv = clutter_gesture_action_get_instance_private (action);
g_return_if_fail (priv->points->len > point);
if (motion_x)
*motion_x = g_array_index (action->priv->points,
*motion_x = g_array_index (priv->points,
GesturePoint,
point).last_motion_x;
if (motion_y)
*motion_y = g_array_index (action->priv->points,
*motion_y = g_array_index (priv->points,
GesturePoint,
point).last_motion_y;
}
@ -960,15 +988,19 @@ clutter_gesture_action_get_motion_delta (ClutterGestureAction *action,
gfloat *delta_x,
gfloat *delta_y)
{
ClutterGestureActionPrivate *priv;
gfloat d_x, d_y;
g_return_val_if_fail (CLUTTER_IS_GESTURE_ACTION (action), 0);
g_return_val_if_fail (action->priv->points->len > point, 0);
d_x = g_array_index (action->priv->points,
priv = clutter_gesture_action_get_instance_private (action);
g_return_val_if_fail (priv->points->len > point, 0);
d_x = g_array_index (priv->points,
GesturePoint,
point).last_delta_x;
d_y = g_array_index (action->priv->points,
d_y = g_array_index (priv->points,
GesturePoint,
point).last_delta_y;
@ -1002,16 +1034,21 @@ clutter_gesture_action_get_release_coords (ClutterGestureAction *action,
gfloat *release_x,
gfloat *release_y)
{
ClutterGestureActionPrivate *priv;
g_return_if_fail (CLUTTER_IS_GESTURE_ACTION (action));
g_return_if_fail (action->priv->points->len > point);
priv = clutter_gesture_action_get_instance_private (action);
g_return_if_fail (priv->points->len > point);
if (release_x)
*release_x = g_array_index (action->priv->points,
*release_x = g_array_index (priv->points,
GesturePoint,
point).release_x;
if (release_y)
*release_y = g_array_index (action->priv->points,
*release_y = g_array_index (priv->points,
GesturePoint,
point).release_y;
}
@ -1037,16 +1074,20 @@ clutter_gesture_action_get_velocity (ClutterGestureAction *action,
gfloat *velocity_x,
gfloat *velocity_y)
{
ClutterGestureActionPrivate *priv;
gfloat d_x, d_y, distance, velocity;
gint64 d_t;
g_return_val_if_fail (CLUTTER_IS_GESTURE_ACTION (action), 0);
g_return_val_if_fail (action->priv->points->len > point, 0);
priv = clutter_gesture_action_get_instance_private (action);
g_return_val_if_fail (priv->points->len > point, 0);
distance = clutter_gesture_action_get_motion_delta (action, point,
&d_x, &d_y);
d_t = g_array_index (action->priv->points,
d_t = g_array_index (priv->points,
GesturePoint,
point).last_delta_time;
@ -1073,9 +1114,13 @@ clutter_gesture_action_get_velocity (ClutterGestureAction *action,
gint
clutter_gesture_action_get_n_touch_points (ClutterGestureAction *action)
{
ClutterGestureActionPrivate *priv;
g_return_val_if_fail (CLUTTER_IS_GESTURE_ACTION (action), 0);
return action->priv->requested_nb_points;
priv = clutter_gesture_action_get_instance_private (action);
return priv->requested_nb_points;
}
/**
@ -1096,7 +1141,7 @@ clutter_gesture_action_set_n_touch_points (ClutterGestureAction *action,
g_return_if_fail (CLUTTER_IS_GESTURE_ACTION (action));
g_return_if_fail (nb_points >= 1);
priv = action->priv;
priv = clutter_gesture_action_get_instance_private (action);
if (priv->requested_nb_points == nb_points)
return;
@ -1150,9 +1195,13 @@ clutter_gesture_action_set_n_touch_points (ClutterGestureAction *action,
guint
clutter_gesture_action_get_n_current_points (ClutterGestureAction *action)
{
ClutterGestureActionPrivate *priv;
g_return_val_if_fail (CLUTTER_IS_GESTURE_ACTION (action), 0);
return action->priv->points->len;
priv = clutter_gesture_action_get_instance_private (action);
return priv->points->len;
}
/**
@ -1170,10 +1219,15 @@ ClutterEventSequence *
clutter_gesture_action_get_sequence (ClutterGestureAction *action,
guint point)
{
g_return_val_if_fail (CLUTTER_IS_GESTURE_ACTION (action), NULL);
g_return_val_if_fail (action->priv->points->len > point, NULL);
ClutterGestureActionPrivate *priv;
return g_array_index (action->priv->points, GesturePoint, point).sequence;
g_return_val_if_fail (CLUTTER_IS_GESTURE_ACTION (action), NULL);
priv = clutter_gesture_action_get_instance_private (action);
g_return_val_if_fail (priv->points->len > point, NULL);
return g_array_index (priv->points, GesturePoint, point).sequence;
}
/**
@ -1192,10 +1246,15 @@ ClutterInputDevice *
clutter_gesture_action_get_device (ClutterGestureAction *action,
guint point)
{
g_return_val_if_fail (CLUTTER_IS_GESTURE_ACTION (action), NULL);
g_return_val_if_fail (action->priv->points->len > point, NULL);
ClutterGestureActionPrivate *priv;
return g_array_index (action->priv->points, GesturePoint, point).device;
g_return_val_if_fail (CLUTTER_IS_GESTURE_ACTION (action), NULL);
priv = clutter_gesture_action_get_instance_private (action);
g_return_val_if_fail (priv->points->len > point, NULL);
return g_array_index (priv->points, GesturePoint, point).device;
}
/**
@ -1215,11 +1274,15 @@ clutter_gesture_action_get_last_event (ClutterGestureAction *action,
guint point)
{
GesturePoint *gesture_point;
ClutterGestureActionPrivate *priv;
g_return_val_if_fail (CLUTTER_IS_GESTURE_ACTION (action), NULL);
g_return_val_if_fail (action->priv->points->len > point, NULL);
gesture_point = &g_array_index (action->priv->points, GesturePoint, point);
priv = clutter_gesture_action_get_instance_private (action);
g_return_val_if_fail (priv->points->len > point, NULL);
gesture_point = &g_array_index (priv->points, GesturePoint, point);
return gesture_point->last_event;
}
@ -1256,12 +1319,16 @@ void
clutter_gesture_action_set_threshold_trigger_edge (ClutterGestureAction *action,
ClutterGestureTriggerEdge edge)
{
ClutterGestureActionPrivate *priv;
g_return_if_fail (CLUTTER_IS_GESTURE_ACTION (action));
if (action->priv->edge == edge)
priv = clutter_gesture_action_get_instance_private (action);
if (priv->edge == edge)
return;
action->priv->edge = edge;
priv->edge = edge;
g_object_notify_by_pspec (G_OBJECT (action), gesture_props[PROP_THRESHOLD_TRIGGER_EDGE]);
}
@ -1280,10 +1347,14 @@ clutter_gesture_action_set_threshold_trigger_edge (ClutterGestureAction *ac
ClutterGestureTriggerEdge
clutter_gesture_action_get_threshold_trigger_edge (ClutterGestureAction *action)
{
ClutterGestureActionPrivate *priv;
g_return_val_if_fail (CLUTTER_IS_GESTURE_ACTION (action),
CLUTTER_GESTURE_TRIGGER_EDGE_NONE);
return action->priv->edge;
priv = clutter_gesture_action_get_instance_private (action);
return priv->edge;
}
/**
@ -1323,17 +1394,21 @@ clutter_gesture_action_set_threshold_trigger_distance (ClutterGestureAction
float x,
float y)
{
ClutterGestureActionPrivate *priv;
g_return_if_fail (CLUTTER_IS_GESTURE_ACTION (action));
if (fabsf (x - action->priv->distance_x) > FLOAT_EPSILON)
priv = clutter_gesture_action_get_instance_private (action);
if (fabsf (x - priv->distance_x) > FLOAT_EPSILON)
{
action->priv->distance_x = x;
priv->distance_x = x;
g_object_notify_by_pspec (G_OBJECT (action), gesture_props[PROP_THRESHOLD_TRIGGER_DISTANCE_X]);
}
if (fabsf (y - action->priv->distance_y) > FLOAT_EPSILON)
if (fabsf (y - priv->distance_y) > FLOAT_EPSILON)
{
action->priv->distance_y = y;
priv->distance_y = y;
g_object_notify_by_pspec (G_OBJECT (action), gesture_props[PROP_THRESHOLD_TRIGGER_DISTANCE_Y]);
}
}
@ -1354,19 +1429,23 @@ clutter_gesture_action_get_threshold_trigger_distance (ClutterGestureAction *act
float *x,
float *y)
{
ClutterGestureActionPrivate *priv;
g_return_if_fail (CLUTTER_IS_GESTURE_ACTION (action));
priv = clutter_gesture_action_get_instance_private (action);
if (x != NULL)
{
if (action->priv->distance_x > 0.0)
*x = action->priv->distance_x;
if (priv->distance_x > 0.0)
*x = priv->distance_x;
else
*x = gesture_get_default_threshold ();
}
if (y != NULL)
{
if (action->priv->distance_y > 0.0)
*y = action->priv->distance_y;
if (priv->distance_y > 0.0)
*y = priv->distance_y;
else
*y = gesture_get_default_threshold ();
}

View File

@ -34,32 +34,13 @@
G_BEGIN_DECLS
#define CLUTTER_TYPE_GESTURE_ACTION (clutter_gesture_action_get_type ())
#define CLUTTER_GESTURE_ACTION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_GESTURE_ACTION, ClutterGestureAction))
#define CLUTTER_IS_GESTURE_ACTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_GESTURE_ACTION))
#define CLUTTER_GESTURE_ACTION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_GESTURE_ACTION, ClutterGestureActionClass))
#define CLUTTER_IS_GESTURE_ACTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_GESTURE_ACTION))
#define CLUTTER_GESTURE_ACTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_GESTURE_ACTION, ClutterGestureActionClass))
#define CLUTTER_TYPE_GESTURE_ACTION (clutter_gesture_action_get_type ())
typedef struct _ClutterGestureAction ClutterGestureAction;
typedef struct _ClutterGestureActionPrivate ClutterGestureActionPrivate;
typedef struct _ClutterGestureActionClass ClutterGestureActionClass;
CLUTTER_EXPORT
G_DECLARE_DERIVABLE_TYPE (ClutterGestureAction, clutter_gesture_action,
CLUTTER, GESTURE_ACTION, ClutterAction);
/**
* ClutterGestureAction:
*
* The #ClutterGestureAction structure contains
* only private data and should be accessed using the provided API
*
* Since: 1.8
*/
struct _ClutterGestureAction
{
/*< private >*/
ClutterAction parent_instance;
ClutterGestureActionPrivate *priv;
};
typedef struct _ClutterGestureActionPrivate ClutterGestureActionPrivate;
/**
* ClutterGestureActionClass:
@ -101,9 +82,6 @@ struct _ClutterGestureActionClass
void (* _clutter_gesture_action6) (void);
};
CLUTTER_EXPORT
GType clutter_gesture_action_get_type (void) G_GNUC_CONST;
CLUTTER_EXPORT
ClutterAction * clutter_gesture_action_new (void);

View File

@ -1391,8 +1391,7 @@ allocate_child (ClutterGridRequest *request,
static void
clutter_grid_layout_allocate (ClutterLayoutManager *layout,
ClutterContainer *container,
const ClutterActorBox *allocation,
ClutterAllocationFlags flags)
const ClutterActorBox *allocation)
{
ClutterGridLayout *self = CLUTTER_GRID_LAYOUT (layout);
ClutterOrientation orientation;
@ -1453,7 +1452,7 @@ clutter_grid_layout_allocate (ClutterLayoutManager *layout,
child_allocation.x2 = child_allocation.x1 + width;
child_allocation.y2 = child_allocation.y1 + height;
clutter_actor_allocate (child, &child_allocation, flags);
clutter_actor_allocate (child, &child_allocation);
}
}

View File

@ -37,9 +37,6 @@
* any object taking a reference on a #ClutterInterval instance should
* also take ownership of the interval by using g_object_ref_sink().
*
* #ClutterInterval is used by #ClutterAnimation to define the
* interval of values that an implicit animation should tween over.
*
* #ClutterInterval can be subclassed to override the validation
* and value computation.
*

View File

@ -136,7 +136,6 @@
#define CLUTTER_DISABLE_DEPRECATION_WARNINGS
#include "deprecated/clutter-container.h"
#include "deprecated/clutter-alpha.h"
#include "clutter-debug.h"
#include "clutter-layout-manager.h"
@ -164,7 +163,6 @@ G_DEFINE_ABSTRACT_TYPE (ClutterLayoutManager,
G_TYPE_INITIALLY_UNOWNED)
static GQuark quark_layout_meta = 0;
static GQuark quark_layout_alpha = 0;
static guint manager_signals[LAST_SIGNAL] = { 0, };
@ -255,8 +253,7 @@ layout_manager_real_get_preferred_height (ClutterLayoutManager *manager,
static void
layout_manager_real_allocate (ClutterLayoutManager *manager,
ClutterContainer *container,
const ClutterActorBox *allocation,
ClutterAllocationFlags flags)
const ClutterActorBox *allocation)
{
LAYOUT_MANAGER_WARN_NOT_IMPLEMENTED (manager, "allocate");
}
@ -301,96 +298,12 @@ layout_manager_real_get_child_meta_type (ClutterLayoutManager *manager)
return G_TYPE_INVALID;
}
/* XXX:2.0 - Remove */
static ClutterAlpha *
layout_manager_real_begin_animation (ClutterLayoutManager *manager,
guint duration,
gulong mode)
{
ClutterTimeline *timeline;
ClutterAlpha *alpha;
alpha = g_object_get_qdata (G_OBJECT (manager), quark_layout_alpha);
if (alpha != NULL)
{
clutter_alpha_set_mode (alpha, mode);
timeline = clutter_alpha_get_timeline (alpha);
clutter_timeline_set_duration (timeline, duration);
clutter_timeline_rewind (timeline);
return alpha;
};
timeline = clutter_timeline_new (duration);
alpha = clutter_alpha_new_full (timeline, mode);
/* let the alpha take ownership of the timeline */
g_object_unref (timeline);
g_signal_connect_swapped (timeline, "new-frame",
G_CALLBACK (clutter_layout_manager_layout_changed),
manager);
g_object_set_qdata_full (G_OBJECT (manager),
quark_layout_alpha, alpha,
(GDestroyNotify) g_object_unref);
clutter_timeline_start (timeline);
return alpha;
}
/* XXX:2.0 - Remove */
static gdouble
layout_manager_real_get_animation_progress (ClutterLayoutManager *manager)
{
ClutterAlpha *alpha;
alpha = g_object_get_qdata (G_OBJECT (manager), quark_layout_alpha);
if (alpha == NULL)
return 1.0;
return clutter_alpha_get_alpha (alpha);
}
/* XXX:2.0 - Remove */
static void
layout_manager_real_end_animation (ClutterLayoutManager *manager)
{
ClutterTimeline *timeline;
ClutterAlpha *alpha;
alpha = g_object_get_qdata (G_OBJECT (manager), quark_layout_alpha);
if (alpha == NULL)
return;
timeline = clutter_alpha_get_timeline (alpha);
g_assert (timeline != NULL);
if (clutter_timeline_is_playing (timeline))
clutter_timeline_stop (timeline);
g_signal_handlers_disconnect_by_func (timeline,
G_CALLBACK (clutter_layout_manager_layout_changed),
manager);
g_object_set_qdata (G_OBJECT (manager), quark_layout_alpha, NULL);
clutter_layout_manager_layout_changed (manager);
}
static void
clutter_layout_manager_class_init (ClutterLayoutManagerClass *klass)
{
quark_layout_meta =
g_quark_from_static_string ("clutter-layout-manager-child-meta");
/* XXX:2.0 - Remove */
quark_layout_alpha =
g_quark_from_static_string ("clutter-layout-manager-alpha");
klass->get_preferred_width = layout_manager_real_get_preferred_width;
klass->get_preferred_height = layout_manager_real_get_preferred_height;
klass->allocate = layout_manager_real_allocate;
@ -398,9 +311,6 @@ clutter_layout_manager_class_init (ClutterLayoutManagerClass *klass)
klass->get_child_meta_type = layout_manager_real_get_child_meta_type;
/* XXX:2.0 - Remove */
klass->begin_animation = layout_manager_real_begin_animation;
klass->get_animation_progress = layout_manager_real_get_animation_progress;
klass->end_animation = layout_manager_real_end_animation;
klass->set_container = layout_manager_real_set_container;
/**
@ -523,7 +433,6 @@ clutter_layout_manager_get_preferred_height (ClutterLayoutManager *manager,
* @container: the #ClutterContainer using @manager
* @allocation: the #ClutterActorBox containing the allocated area
* of @container
* @flags: the allocation flags
*
* Allocates the children of @container given an area
*
@ -534,8 +443,7 @@ clutter_layout_manager_get_preferred_height (ClutterLayoutManager *manager,
void
clutter_layout_manager_allocate (ClutterLayoutManager *manager,
ClutterContainer *container,
const ClutterActorBox *allocation,
ClutterAllocationFlags flags)
const ClutterActorBox *allocation)
{
ClutterLayoutManagerClass *klass;
@ -544,7 +452,7 @@ clutter_layout_manager_allocate (ClutterLayoutManager *manager,
g_return_if_fail (allocation != NULL);
klass = CLUTTER_LAYOUT_MANAGER_GET_CLASS (manager);
klass->allocate (manager, container, allocation, flags);
klass->allocate (manager, container, allocation);
}
/**

View File

@ -115,8 +115,7 @@ struct _ClutterLayoutManagerClass
gfloat *nat_height_p);
void (* allocate) (ClutterLayoutManager *manager,
ClutterContainer *container,
const ClutterActorBox *allocation,
ClutterAllocationFlags flags);
const ClutterActorBox *allocation);
void (* set_container) (ClutterLayoutManager *manager,
ClutterContainer *container);
@ -126,15 +125,6 @@ struct _ClutterLayoutManagerClass
ClutterContainer *container,
ClutterActor *actor);
/* deprecated */
ClutterAlpha * (* begin_animation) (ClutterLayoutManager *manager,
guint duration,
gulong mode);
/* deprecated */
gdouble (* get_animation_progress) (ClutterLayoutManager *manager);
/* deprecated */
void (* end_animation) (ClutterLayoutManager *manager);
void (* layout_changed) (ClutterLayoutManager *manager);
/*< private >*/
@ -167,8 +157,7 @@ void clutter_layout_manager_get_preferred_height (ClutterLayoutMa
CLUTTER_EXPORT
void clutter_layout_manager_allocate (ClutterLayoutManager *manager,
ClutterContainer *container,
const ClutterActorBox *allocation,
ClutterAllocationFlags flags);
const ClutterActorBox *allocation);
CLUTTER_EXPORT
void clutter_layout_manager_set_container (ClutterLayoutManager *manager,

View File

@ -199,7 +199,7 @@ master_clock_schedule_stage_updates (ClutterMasterClockDefault *master_clock)
stages = clutter_stage_manager_peek_stages (stage_manager);
for (l = stages; l != NULL; l = l->next)
_clutter_stage_schedule_update (l->data);
clutter_stage_schedule_update (l->data);
}
static GSList *
@ -252,7 +252,7 @@ master_clock_reschedule_stage_updates (ClutterMasterClockDefault *master_clock,
if (master_clock->timelines ||
_clutter_stage_has_queued_events (l->data) ||
_clutter_stage_needs_update (l->data))
_clutter_stage_schedule_update (l->data);
clutter_stage_schedule_update (l->data);
}
}

View File

@ -65,7 +65,6 @@ typedef struct _ClutterVertex4 ClutterVertex4;
#define CLUTTER_ACTOR_IS_TOPLEVEL(a) ((CLUTTER_PRIVATE_FLAGS (a) & CLUTTER_IS_TOPLEVEL) != FALSE)
#define CLUTTER_ACTOR_IN_DESTRUCTION(a) ((CLUTTER_PRIVATE_FLAGS (a) & CLUTTER_IN_DESTRUCTION) != FALSE)
#define CLUTTER_ACTOR_IN_REPARENT(a) ((CLUTTER_PRIVATE_FLAGS (a) & CLUTTER_IN_REPARENT) != FALSE)
#define CLUTTER_ACTOR_IN_PAINT(a) ((CLUTTER_PRIVATE_FLAGS (a) & CLUTTER_IN_PAINT) != FALSE)
#define CLUTTER_ACTOR_IN_PICK(a) ((CLUTTER_PRIVATE_FLAGS (a) & CLUTTER_IN_PICK) != FALSE)
#define CLUTTER_ACTOR_IN_RELAYOUT(a) ((CLUTTER_PRIVATE_FLAGS (a) & CLUTTER_IN_RELAYOUT) != FALSE)
@ -99,7 +98,6 @@ typedef enum
CLUTTER_IN_DESTRUCTION = 1 << 0,
CLUTTER_IS_TOPLEVEL = 1 << 1,
CLUTTER_IN_REPARENT = 1 << 2,
CLUTTER_IN_PREF_WIDTH = 1 << 3,
CLUTTER_IN_PREF_HEIGHT = 1 << 4,

View File

@ -34,7 +34,6 @@
#define CLUTTER_DISABLE_DEPRECATION_WARNINGS
#include "deprecated/clutter-container.h"
#include "deprecated/clutter-alpha.h"
#include "clutter-actor.h"
#include "clutter-debug.h"
@ -799,232 +798,6 @@ parse_signals (ClutterScript *script,
return retval;
}
static ClutterTimeline *
construct_timeline (ClutterScript *script,
JsonObject *object)
{
ClutterTimeline *retval = NULL;
ObjectInfo *oinfo;
GList *members, *l;
/* we fake an ObjectInfo so we can reuse clutter_script_construct_object()
* here; we do not save it inside the hash table, because if this had
* been a named object then we wouldn't have ended up here in the first
* place
*/
oinfo = g_slice_new0 (ObjectInfo);
oinfo->gtype = CLUTTER_TYPE_TIMELINE;
oinfo->id = g_strdup ("dummy");
members = json_object_get_members (object);
for (l = members; l != NULL; l = l->next)
{
const gchar *name = l->data;
JsonNode *node = json_object_get_member (object, name);
PropertyInfo *pinfo = g_slice_new0 (PropertyInfo);
pinfo->name = g_strdelimit (g_strdup (name), G_STR_DELIMITERS, '-');
pinfo->node = json_node_copy (node);
oinfo->properties = g_list_prepend (oinfo->properties, pinfo);
}
g_list_free (members);
_clutter_script_construct_object (script, oinfo);
_clutter_script_apply_properties (script, oinfo);
retval = CLUTTER_TIMELINE (oinfo->object);
/* we transfer ownership to the alpha function, so we ref before
* destroying the ObjectInfo to avoid the timeline going away
*/
g_object_ref (retval);
object_info_free (oinfo);
return retval;
}
/* define the names of the animation modes to match the ones
* that developers might be more accustomed to
*/
static const struct
{
const gchar *name;
ClutterAnimationMode mode;
} animation_modes[] = {
{ "linear", CLUTTER_LINEAR },
{ "easeInQuad", CLUTTER_EASE_IN_QUAD },
{ "easeOutQuad", CLUTTER_EASE_OUT_QUAD },
{ "easeInOutQuad", CLUTTER_EASE_IN_OUT_QUAD },
{ "easeInCubic", CLUTTER_EASE_IN_CUBIC },
{ "easeOutCubic", CLUTTER_EASE_OUT_CUBIC },
{ "easeInOutCubic", CLUTTER_EASE_IN_OUT_CUBIC },
{ "easeInQuart", CLUTTER_EASE_IN_QUART },
{ "easeOutQuart", CLUTTER_EASE_OUT_QUART },
{ "easeInOutQuart", CLUTTER_EASE_IN_OUT_QUART },
{ "easeInQuint", CLUTTER_EASE_IN_QUINT },
{ "easeOutQuint", CLUTTER_EASE_OUT_QUINT },
{ "easeInOutQuint", CLUTTER_EASE_IN_OUT_QUINT },
{ "easeInSine", CLUTTER_EASE_IN_SINE },
{ "easeOutSine", CLUTTER_EASE_OUT_SINE },
{ "easeInOutSine", CLUTTER_EASE_IN_OUT_SINE },
{ "easeInExpo", CLUTTER_EASE_IN_EXPO },
{ "easeOutExpo", CLUTTER_EASE_OUT_EXPO },
{ "easeInOutExpo", CLUTTER_EASE_IN_OUT_EXPO },
{ "easeInCirc", CLUTTER_EASE_IN_CIRC },
{ "easeOutCirc", CLUTTER_EASE_OUT_CIRC },
{ "easeInOutCirc", CLUTTER_EASE_IN_OUT_CIRC },
{ "easeInElastic", CLUTTER_EASE_IN_ELASTIC },
{ "easeOutElastic", CLUTTER_EASE_OUT_ELASTIC },
{ "easeInOutElastic", CLUTTER_EASE_IN_OUT_ELASTIC },
{ "easeInBack", CLUTTER_EASE_IN_BACK },
{ "easeOutBack", CLUTTER_EASE_OUT_BACK },
{ "easeInOutBack", CLUTTER_EASE_IN_OUT_BACK },
{ "easeInBounce", CLUTTER_EASE_IN_BOUNCE },
{ "easeOutBounce", CLUTTER_EASE_OUT_BOUNCE },
{ "easeInOutBounce", CLUTTER_EASE_IN_OUT_BOUNCE },
};
static const gint n_animation_modes = G_N_ELEMENTS (animation_modes);
gulong
_clutter_script_resolve_animation_mode (JsonNode *node)
{
gint i, res = CLUTTER_CUSTOM_MODE;
if (JSON_NODE_TYPE (node) != JSON_NODE_VALUE)
return CLUTTER_CUSTOM_MODE;
if (json_node_get_value_type (node) == G_TYPE_INT64)
return json_node_get_int (node);
if (json_node_get_value_type (node) == G_TYPE_STRING)
{
const gchar *name = json_node_get_string (node);
/* XXX - we might be able to optimize by changing the ordering
* of the animation_modes array, e.g.
* - special casing linear
* - tokenizing ('ease', 'In', 'Sine') and matching on token
* - binary searching?
*/
for (i = 0; i < n_animation_modes; i++)
{
if (strcmp (animation_modes[i].name, name) == 0)
return animation_modes[i].mode;
}
if (_clutter_script_enum_from_string (CLUTTER_TYPE_ANIMATION_MODE,
name,
&res))
return res;
g_warning ("Unable to find the animation mode '%s'", name);
}
return CLUTTER_CUSTOM_MODE;
}
static ClutterAlphaFunc
resolve_alpha_func (const gchar *name)
{
static GModule *module = NULL;
ClutterAlphaFunc func;
CLUTTER_NOTE (SCRIPT, "Looking up '%s' alpha function", name);
if (G_UNLIKELY (!module))
module = g_module_open (NULL, 0);
if (g_module_symbol (module, name, (gpointer) &func))
{
CLUTTER_NOTE (SCRIPT, "Found '%s' alpha function in the symbols table",
name);
return func;
}
return NULL;
}
GObject *
_clutter_script_parse_alpha (ClutterScript *script,
JsonNode *node)
{
GObject *retval = NULL;
JsonObject *object;
ClutterTimeline *timeline = NULL;
ClutterAlphaFunc alpha_func = NULL;
ClutterAnimationMode mode = CLUTTER_CUSTOM_MODE;
JsonNode *val;
gboolean unref_timeline = FALSE;
if (JSON_NODE_TYPE (node) != JSON_NODE_OBJECT)
return NULL;
object = json_node_get_object (node);
val = json_object_get_member (object, "timeline");
if (val)
{
if (JSON_NODE_TYPE (val) == JSON_NODE_VALUE &&
json_node_get_string (val) != NULL)
{
const gchar *id_ = json_node_get_string (val);
timeline =
CLUTTER_TIMELINE (clutter_script_get_object (script, id_));
}
else if (JSON_NODE_TYPE (val) == JSON_NODE_OBJECT)
{
timeline = construct_timeline (script, json_node_get_object (val));
unref_timeline = TRUE;
}
}
val = json_object_get_member (object, "mode");
if (val != NULL)
mode = _clutter_script_resolve_animation_mode (val);
if (mode == CLUTTER_CUSTOM_MODE)
{
val = json_object_get_member (object, "function");
if (val && json_node_get_string (val) != NULL)
{
alpha_func = resolve_alpha_func (json_node_get_string (val));
if (!alpha_func)
{
g_warning ("Unable to find the function '%s' in the "
"Clutter alpha functions or the symbols table",
json_node_get_string (val));
}
}
}
CLUTTER_NOTE (SCRIPT, "Parsed alpha: %s timeline (%p) (mode:%d, func:%p)",
unref_timeline ? "implicit" : "explicit",
timeline ? timeline : 0x0,
mode != CLUTTER_CUSTOM_MODE ? mode : 0,
alpha_func ? alpha_func : 0x0);
retval = g_object_new (CLUTTER_TYPE_ALPHA, NULL);
if (mode != CLUTTER_CUSTOM_MODE)
clutter_alpha_set_mode (CLUTTER_ALPHA (retval), mode);
if (alpha_func != NULL)
clutter_alpha_set_func (CLUTTER_ALPHA (retval), alpha_func, NULL, NULL);
clutter_alpha_set_timeline (CLUTTER_ALPHA (retval), timeline);
/* if we created an implicit timeline, the Alpha has full ownership
* of it now, since it won't be accessible from ClutterScript
*/
if (unref_timeline)
g_object_unref (timeline);
return retval;
}
static void
clutter_script_parser_object_end (JsonParser *json_parser,
JsonObject *object)

View File

@ -110,8 +110,6 @@ gboolean _clutter_script_parse_node (ClutterScript *script,
GType _clutter_script_get_type_from_symbol (const gchar *symbol);
GType _clutter_script_get_type_from_class (const gchar *name);
gulong _clutter_script_resolve_animation_mode (JsonNode *node);
gboolean _clutter_script_enum_from_string (GType gtype,
const gchar *string,
gint *enum_value);
@ -128,8 +126,6 @@ gboolean _clutter_script_parse_rect (ClutterScript *script,
gboolean _clutter_script_parse_color (ClutterScript *script,
JsonNode *node,
ClutterColor *color);
GObject *_clutter_script_parse_alpha (ClutterScript *script,
JsonNode *node);
gboolean _clutter_script_parse_point (ClutterScript *script,
JsonNode *node,
graphene_point_t *point);

View File

@ -98,49 +98,6 @@
* respectively) and the "object" string member for calling
* g_signal_connect_object() instead of g_signal_connect().
*
* Signals can also be directly attached to a specific state defined
* inside a #ClutterState instance, for instance:
*
* |[
* ...
* "signals" : [
* {
* "name" : "enter-event",
* "states" : "button-states",
* "target-state" : "hover"
* },
* {
* "name" : "leave-event",
* "states" : "button-states",
* "target-state" : "base"
* },
* {
* "name" : "button-press-event",
* "states" : "button-states",
* "target-state" : "active",
* },
* {
* "name" : "key-press-event",
* "states" : "button-states",
* "target-state" : "key-focus",
* "warp" : true
* }
* ],
* ...
* ]|
*
* The "states" key defines the #ClutterState instance to be used to
* resolve the "target-state" key; it can be either a script id for a
* #ClutterState built by the same #ClutterScript instance, or to a
* #ClutterState built in code and associated to the #ClutterScript
* instance through the clutter_script_add_states() function. If no
* "states" key is present, then the default #ClutterState associated to
* the #ClutterScript instance will be used; the default #ClutterState
* can be set using clutter_script_add_states() using a %NULL name. The
* "warp" key can be used to warp to a specific state instead of
* animating to it. State changes on signal emission will not affect
* the signal emission chain.
*
* Clutter reserves the following names, so classes defining properties
* through the usual GObject registration process should avoid using these
* names to avoid collisions:
@ -184,9 +141,7 @@
#include "clutter-private.h"
#include "clutter-debug.h"
#include "deprecated/clutter-alpha.h"
#include "deprecated/clutter-container.h"
#include "deprecated/clutter-state.h"
enum
{
@ -210,8 +165,6 @@ struct _ClutterScriptPrivate
ClutterScriptParser *parser;
GHashTable *states;
gchar **search_paths;
gchar *translation_domain;
@ -264,7 +217,6 @@ signal_info_free (gpointer data)
g_free (sinfo->name);
g_free (sinfo->handler);
g_free (sinfo->object);
g_free (sinfo->state);
g_free (sinfo->target);
g_slice_free (SignalInfo, sinfo);
@ -319,7 +271,6 @@ clutter_script_finalize (GObject *gobject)
g_hash_table_destroy (priv->objects);
g_strfreev (priv->search_paths);
g_free (priv->filename);
g_hash_table_destroy (priv->states);
g_free (priv->translation_domain);
G_OBJECT_CLASS (clutter_script_parent_class)->finalize (gobject);
@ -454,9 +405,6 @@ clutter_script_init (ClutterScript *script)
priv->objects = g_hash_table_new_full (g_str_hash, g_str_equal,
NULL,
object_info_free);
priv->states = g_hash_table_new_full (g_str_hash, g_str_equal,
g_free,
(GDestroyNotify) g_object_unref);
}
/**
@ -972,65 +920,12 @@ clutter_script_connect_signals (ClutterScript *script,
g_free (cd);
}
typedef struct {
ClutterState *state;
GObject *emitter;
gchar *target;
gulong signal_id;
gulong hook_id;
gboolean warp_to;
} HookData;
typedef struct {
ClutterScript *script;
ClutterScriptConnectFunc func;
gpointer user_data;
} SignalConnectData;
static void
hook_data_free (gpointer data)
{
if (G_LIKELY (data != NULL))
{
HookData *hook_data = data;
g_free (hook_data->target);
g_slice_free (HookData, hook_data);
}
}
static gboolean
clutter_script_state_change_hook (GSignalInvocationHint *ihint,
guint n_params,
const GValue *params,
gpointer user_data)
{
HookData *hook_data = user_data;
GObject *emitter;
emitter = g_value_get_object (&params[0]);
if (emitter == hook_data->emitter)
{
if (hook_data->warp_to)
clutter_state_warp_to_state (hook_data->state, hook_data->target);
else
clutter_state_set_state (hook_data->state, hook_data->target);
}
return TRUE;
}
static void
clutter_script_remove_state_change_hook (gpointer user_data,
GObject *object_p)
{
HookData *hook_data = user_data;
g_signal_remove_emission_hook (hook_data->signal_id,
hook_data->hook_id);
}
static void
connect_each_object (gpointer key,
gpointer value,
@ -1070,64 +965,7 @@ connect_each_object (gpointer key,
}
else
{
GObject *state_object = NULL;
const gchar *signal_name, *signal_detail;
gchar **components;
GQuark signal_quark;
guint signal_id;
HookData *hook_data;
if (sinfo->state == NULL)
state_object = (GObject *) clutter_script_get_states (script, NULL);
else
{
state_object = clutter_script_get_object (script, sinfo->state);
if (state_object == NULL)
state_object = (GObject *) clutter_script_get_states (script, sinfo->state);
}
if (state_object == NULL)
continue;
components = g_strsplit (sinfo->name, "::", 2);
if (g_strv_length (components) == 2)
{
signal_name = components[0];
signal_detail = components[1];
}
else
{
signal_name = components[0];
signal_detail = NULL;
}
signal_id = g_signal_lookup (signal_name, G_OBJECT_TYPE (object));
if (signal_id == 0)
{
g_strfreev (components);
continue;
}
if (signal_detail != NULL)
signal_quark = g_quark_from_string (signal_detail);
else
signal_quark = 0;
hook_data = g_slice_new (HookData);
hook_data->emitter = object;
hook_data->state = CLUTTER_STATE (state_object);
hook_data->target = g_strdup (sinfo->target);
hook_data->warp_to = sinfo->warp_to;
hook_data->signal_id = signal_id;
hook_data->hook_id =
g_signal_add_emission_hook (signal_id, signal_quark,
clutter_script_state_change_hook,
hook_data,
hook_data_free);
g_object_weak_ref (hook_data->emitter,
clutter_script_remove_state_change_hook,
hook_data);
g_warn_if_reached ();
}
signal_info_free (sinfo);
@ -1352,72 +1190,6 @@ clutter_script_list_objects (ClutterScript *script)
return retval;
}
/**
* clutter_script_add_states:
* @script: a #ClutterScript
* @name: (allow-none): a name for the @state, or %NULL to
* set the default #ClutterState
* @state: a #ClutterState
*
* Associates a #ClutterState to the #ClutterScript instance using the given
* name.
*
* The #ClutterScript instance will use @state to resolve target states when
* connecting signal handlers.
*
* The #ClutterScript instance will take a reference on the #ClutterState
* passed to this function.
*
* Since: 1.8
*
* Deprecated: 1.12
*/
void
clutter_script_add_states (ClutterScript *script,
const gchar *name,
ClutterState *state)
{
g_return_if_fail (CLUTTER_IS_SCRIPT (script));
g_return_if_fail (CLUTTER_IS_STATE (state));
if (name == NULL || *name == '\0')
name = "__clutter_script_default_state";
g_hash_table_replace (script->priv->states,
g_strdup (name),
g_object_ref (state));
}
/**
* clutter_script_get_states:
* @script: a #ClutterScript
* @name: (allow-none): the name of the #ClutterState, or %NULL
*
* Retrieves the #ClutterState for the given @state_name.
*
* If @name is %NULL, this function will return the default
* #ClutterState instance.
*
* Return value: (transfer none): a pointer to the #ClutterState for the
* given name. The #ClutterState is owned by the #ClutterScript instance
* and it should not be unreferenced
*
* Since: 1.8
*
* Deprecated: 1.12
*/
ClutterState *
clutter_script_get_states (ClutterScript *script,
const gchar *name)
{
g_return_val_if_fail (CLUTTER_IS_SCRIPT (script), NULL);
if (name == NULL || *name == '\0')
name = "__clutter_script_default_state";
return g_hash_table_lookup (script->priv->states, name);
}
/**
* clutter_script_set_translation_domain:
* @script: a #ClutterScript

View File

@ -179,15 +179,6 @@ void clutter_script_unmerge_objects (ClutterScript
CLUTTER_EXPORT
void clutter_script_ensure_objects (ClutterScript *script);
CLUTTER_DEPRECATED
void clutter_script_add_states (ClutterScript *script,
const gchar *name,
ClutterState *state);
CLUTTER_DEPRECATED
ClutterState * clutter_script_get_states (ClutterScript *script,
const gchar *name);
CLUTTER_EXPORT
void clutter_script_connect_signals (ClutterScript *script,
gpointer user_data);

View File

@ -74,7 +74,6 @@ void _clutter_stage_queue_event (ClutterStage *stage,
gboolean _clutter_stage_has_queued_events (ClutterStage *stage);
void _clutter_stage_process_queued_events (ClutterStage *stage);
void _clutter_stage_update_input_devices (ClutterStage *stage);
void _clutter_stage_schedule_update (ClutterStage *stage);
gint64 _clutter_stage_get_update_time (ClutterStage *stage);
void _clutter_stage_clear_update_time (ClutterStage *stage);
gboolean _clutter_stage_has_full_redraw_queued (ClutterStage *stage);

View File

@ -20,17 +20,28 @@
#include "clutter/clutter-stage-view.h"
void clutter_stage_view_after_paint (ClutterStageView *view);
void clutter_stage_view_after_paint (ClutterStageView *view,
cairo_region_t *redraw_clip);
void clutter_stage_view_before_swap_buffer (ClutterStageView *view,
const cairo_region_t *swap_region);
gboolean clutter_stage_view_is_dirty_viewport (ClutterStageView *view);
void clutter_stage_view_set_dirty_viewport (ClutterStageView *view,
gboolean dirty);
void clutter_stage_view_invalidate_viewport (ClutterStageView *view);
void clutter_stage_view_set_viewport (ClutterStageView *view,
float x,
float y,
float width,
float height);
gboolean clutter_stage_view_is_dirty_projection (ClutterStageView *view);
void clutter_stage_view_set_dirty_projection (ClutterStageView *view,
gboolean dirty);
void clutter_stage_view_invalidate_projection (ClutterStageView *view);
void clutter_stage_view_set_projection (ClutterStageView *view,
const CoglMatrix *matrix);
void clutter_stage_view_add_redraw_clip (ClutterStageView *view,
const cairo_rectangle_int_t *clip);
@ -45,4 +56,10 @@ cairo_region_t * clutter_stage_view_take_redraw_clip (ClutterStageView *view);
CoglScanout * clutter_stage_view_take_scanout (ClutterStageView *view);
void clutter_stage_view_transform_rect_to_onscreen (ClutterStageView *view,
const cairo_rectangle_int_t *src_rect,
int dst_width,
int dst_height,
cairo_rectangle_int_t *dst_rect);
#endif /* __CLUTTER_STAGE_VIEW_PRIVATE_H__ */

View File

@ -23,6 +23,7 @@
#include <cairo-gobject.h>
#include <math.h>
#include "clutter/clutter-damage-history.h"
#include "clutter/clutter-private.h"
#include "clutter/clutter-mutter.h"
#include "cogl/cogl.h"
@ -31,10 +32,11 @@ enum
{
PROP_0,
PROP_NAME,
PROP_LAYOUT,
PROP_FRAMEBUFFER,
PROP_OFFSCREEN,
PROP_SHADOWFB,
PROP_USE_SHADOWFB,
PROP_SCALE,
PROP_LAST
@ -44,6 +46,8 @@ static GParamSpec *obj_props[PROP_LAST];
typedef struct _ClutterStageViewPrivate
{
char *name;
cairo_rectangle_int_t layout;
float scale;
CoglFramebuffer *framebuffer;
@ -51,8 +55,16 @@ typedef struct _ClutterStageViewPrivate
CoglOffscreen *offscreen;
CoglPipeline *offscreen_pipeline;
CoglOffscreen *shadowfb;
CoglPipeline *shadowfb_pipeline;
gboolean use_shadowfb;
struct {
struct {
CoglDmaBufHandle *handles[2];
int current_idx;
ClutterDamageHistory *damage_history;
} dma_buf;
CoglOffscreen *framebuffer;
} shadow;
CoglScanout *next_scanout;
@ -91,8 +103,8 @@ clutter_stage_view_get_framebuffer (ClutterStageView *view)
if (priv->offscreen)
return priv->offscreen;
else if (priv->shadowfb)
return priv->shadowfb;
else if (priv->shadow.framebuffer)
return priv->shadow.framebuffer;
else
return priv->framebuffer;
}
@ -152,19 +164,6 @@ clutter_stage_view_ensure_offscreen_blit_pipeline (ClutterStageView *view)
view_class->setup_offscreen_blit_pipeline (view, priv->offscreen_pipeline);
}
static void
clutter_stage_view_ensure_shadowfb_blit_pipeline (ClutterStageView *view)
{
ClutterStageViewPrivate *priv =
clutter_stage_view_get_instance_private (view);
if (priv->shadowfb_pipeline)
return;
priv->shadowfb_pipeline =
clutter_stage_view_create_framebuffer_pipeline (priv->shadowfb);
}
void
clutter_stage_view_invalidate_offscreen_blit_pipeline (ClutterStageView *view)
{
@ -174,85 +173,563 @@ clutter_stage_view_invalidate_offscreen_blit_pipeline (ClutterStageView *view)
g_clear_pointer (&priv->offscreen_pipeline, cogl_object_unref);
}
void
clutter_stage_view_transform_rect_to_onscreen (ClutterStageView *view,
const cairo_rectangle_int_t *src_rect,
int dst_width,
int dst_height,
cairo_rectangle_int_t *dst_rect)
{
ClutterStageViewClass *view_class = CLUTTER_STAGE_VIEW_GET_CLASS (view);
return view_class->transform_rect_to_onscreen (view,
src_rect,
dst_width,
dst_height,
dst_rect);
}
static void
clutter_stage_view_copy_to_framebuffer (ClutterStageView *view,
CoglPipeline *pipeline,
CoglFramebuffer *src_framebuffer,
CoglFramebuffer *dst_framebuffer,
gboolean can_blit)
paint_transformed_framebuffer (ClutterStageView *view,
CoglPipeline *pipeline,
CoglFramebuffer *src_framebuffer,
CoglFramebuffer *dst_framebuffer,
const cairo_region_t *redraw_clip)
{
CoglMatrix matrix;
unsigned int n_rectangles, i;
int dst_width, dst_height;
cairo_rectangle_int_t view_layout;
cairo_rectangle_int_t onscreen_layout;
float view_scale;
float *coordinates;
/* First, try with blit */
if (can_blit)
{
if (cogl_blit_framebuffer (src_framebuffer,
dst_framebuffer,
0, 0,
0, 0,
cogl_framebuffer_get_width (dst_framebuffer),
cogl_framebuffer_get_height (dst_framebuffer),
NULL))
return;
}
dst_width = cogl_framebuffer_get_width (dst_framebuffer);
dst_height = cogl_framebuffer_get_height (dst_framebuffer);
clutter_stage_view_get_layout (view, &view_layout);
clutter_stage_view_transform_rect_to_onscreen (view,
&(cairo_rectangle_int_t) {
.width = view_layout.width,
.height = view_layout.height,
},
view_layout.width,
view_layout.height,
&onscreen_layout);
view_scale = clutter_stage_view_get_scale (view);
/* If blit fails, fallback to the slower painting method */
cogl_framebuffer_push_matrix (dst_framebuffer);
cogl_matrix_init_identity (&matrix);
cogl_matrix_translate (&matrix, -1, 1, 0);
cogl_matrix_scale (&matrix, 2, -2, 0);
cogl_matrix_scale (&matrix,
1.0 / (dst_width / 2.0),
-1.0 / (dst_height / 2.0), 0);
cogl_matrix_translate (&matrix,
-(dst_width / 2.0),
-(dst_height / 2.0), 0);
cogl_framebuffer_set_projection_matrix (dst_framebuffer, &matrix);
cogl_framebuffer_set_viewport (dst_framebuffer,
0, 0, dst_width, dst_height);
cogl_framebuffer_draw_rectangle (dst_framebuffer,
pipeline,
0, 0, 1, 1);
n_rectangles = cairo_region_num_rectangles (redraw_clip);
coordinates = g_newa (float, 2 * 4 * n_rectangles);
for (i = 0; i < n_rectangles; i++)
{
cairo_rectangle_int_t src_rect;
cairo_rectangle_int_t dst_rect;
cairo_region_get_rectangle (redraw_clip, i, &src_rect);
_clutter_util_rectangle_offset (&src_rect,
-view_layout.x,
-view_layout.y,
&src_rect);
clutter_stage_view_transform_rect_to_onscreen (view,
&src_rect,
onscreen_layout.width,
onscreen_layout.height,
&dst_rect);
coordinates[i * 8 + 0] = (float) dst_rect.x * view_scale;
coordinates[i * 8 + 1] = (float) dst_rect.y * view_scale;
coordinates[i * 8 + 2] = ((float) (dst_rect.x + dst_rect.width) *
view_scale);
coordinates[i * 8 + 3] = ((float) (dst_rect.y + dst_rect.height) *
view_scale);
coordinates[i * 8 + 4] = (((float) dst_rect.x / (float) dst_width) *
view_scale);
coordinates[i * 8 + 5] = (((float) dst_rect.y / (float) dst_height) *
view_scale);
coordinates[i * 8 + 6] = ((float) (dst_rect.x + dst_rect.width) /
(float) dst_width) * view_scale;
coordinates[i * 8 + 7] = ((float) (dst_rect.y + dst_rect.height) /
(float) dst_height) * view_scale;
}
cogl_framebuffer_draw_textured_rectangles (dst_framebuffer,
pipeline,
coordinates,
n_rectangles);
cogl_framebuffer_pop_matrix (dst_framebuffer);
}
static gboolean
is_shadowfb_double_buffered (ClutterStageView *view)
{
ClutterStageViewPrivate *priv =
clutter_stage_view_get_instance_private (view);
return priv->shadow.dma_buf.handles[0] && priv->shadow.dma_buf.handles[1];
}
static gboolean
init_dma_buf_shadowfbs (ClutterStageView *view,
CoglContext *cogl_context,
int width,
int height,
GError **error)
{
ClutterStageViewPrivate *priv =
clutter_stage_view_get_instance_private (view);
CoglRenderer *cogl_renderer = cogl_context_get_renderer (cogl_context);
CoglFramebuffer *initial_shadowfb;
if (!cogl_clutter_winsys_has_feature (COGL_WINSYS_FEATURE_BUFFER_AGE))
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
"Buffer age not supported");
return FALSE;
}
if (!cogl_is_onscreen (priv->framebuffer))
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
"Tried to use shadow buffer without onscreen");
return FALSE;
}
priv->shadow.dma_buf.handles[0] = cogl_renderer_create_dma_buf (cogl_renderer,
width, height,
error);
if (!priv->shadow.dma_buf.handles[0])
return FALSE;
priv->shadow.dma_buf.handles[1] = cogl_renderer_create_dma_buf (cogl_renderer,
width, height,
error);
if (!priv->shadow.dma_buf.handles[1])
{
g_clear_pointer (&priv->shadow.dma_buf.handles[0],
cogl_dma_buf_handle_free);
return FALSE;
}
priv->shadow.dma_buf.damage_history = clutter_damage_history_new ();
initial_shadowfb =
cogl_dma_buf_handle_get_framebuffer (priv->shadow.dma_buf.handles[0]);
priv->shadow.framebuffer = cogl_object_ref (initial_shadowfb);
return TRUE;
}
static CoglOffscreen *
create_offscreen_framebuffer (CoglContext *context,
int width,
int height,
GError **error)
{
CoglOffscreen *framebuffer;
CoglTexture2D *texture;
texture = cogl_texture_2d_new_with_size (context, width, height);
cogl_primitive_texture_set_auto_mipmap (COGL_PRIMITIVE_TEXTURE (texture),
FALSE);
if (!cogl_texture_allocate (COGL_TEXTURE (texture), error))
{
cogl_object_unref (texture);
return FALSE;
}
framebuffer = cogl_offscreen_new_with_texture (COGL_TEXTURE (texture));
cogl_object_unref (texture);
if (!cogl_framebuffer_allocate (COGL_FRAMEBUFFER (framebuffer), error))
{
cogl_object_unref (framebuffer);
return FALSE;
}
return framebuffer;
}
static gboolean
init_fallback_shadowfb (ClutterStageView *view,
CoglContext *cogl_context,
int width,
int height,
GError **error)
{
ClutterStageViewPrivate *priv =
clutter_stage_view_get_instance_private (view);
CoglOffscreen *offscreen;
offscreen = create_offscreen_framebuffer (cogl_context, width, height, error);
if (!offscreen)
return FALSE;
priv->shadow.framebuffer = offscreen;
return TRUE;
}
static void
init_shadowfb (ClutterStageView *view)
{
ClutterStageViewPrivate *priv =
clutter_stage_view_get_instance_private (view);
g_autoptr (GError) error = NULL;
int width;
int height;
CoglContext *cogl_context;
width = cogl_framebuffer_get_width (priv->framebuffer);
height = cogl_framebuffer_get_height (priv->framebuffer);
cogl_context = cogl_framebuffer_get_context (priv->framebuffer);
if (init_dma_buf_shadowfbs (view, cogl_context, width, height, &error))
{
g_message ("Initialized double buffered shadow fb for %s", priv->name);
return;
}
g_warning ("Failed to initialize double buffered shadow fb for %s: %s",
priv->name, error->message);
g_clear_error (&error);
if (!init_fallback_shadowfb (view, cogl_context, width, height, &error))
{
g_warning ("Failed to initialize single buffered shadow fb for %s: %s",
priv->name, error->message);
}
else
{
g_message ("Initialized single buffered shadow fb for %s", priv->name);
}
}
void
clutter_stage_view_after_paint (ClutterStageView *view)
clutter_stage_view_after_paint (ClutterStageView *view,
cairo_region_t *redraw_clip)
{
ClutterStageViewPrivate *priv =
clutter_stage_view_get_instance_private (view);
if (priv->offscreen)
{
gboolean can_blit;
CoglMatrix matrix;
clutter_stage_view_ensure_offscreen_blit_pipeline (view);
clutter_stage_view_get_offscreen_transformation_matrix (view, &matrix);
can_blit = cogl_matrix_is_identity (&matrix);
if (priv->shadowfb)
if (priv->shadow.framebuffer)
{
clutter_stage_view_copy_to_framebuffer (view,
priv->offscreen_pipeline,
priv->offscreen,
priv->shadowfb,
can_blit);
paint_transformed_framebuffer (view,
priv->offscreen_pipeline,
priv->offscreen,
priv->shadow.framebuffer,
redraw_clip);
}
else
{
clutter_stage_view_copy_to_framebuffer (view,
priv->offscreen_pipeline,
priv->offscreen,
priv->framebuffer,
can_blit);
paint_transformed_framebuffer (view,
priv->offscreen_pipeline,
priv->offscreen,
priv->framebuffer,
redraw_clip);
}
}
}
static gboolean
is_tile_dirty (cairo_rectangle_int_t *tile,
uint8_t *current_data,
uint8_t *prev_data,
int bpp,
int stride)
{
int y;
for (y = tile->y; y < tile->y + tile->height; y++)
{
if (memcmp (prev_data + y * stride + tile->x * bpp,
current_data + y * stride + tile->x * bpp,
tile->width * bpp) != 0)
return TRUE;
}
return FALSE;
}
static int
flip_dma_buf_idx (int idx)
{
return (idx + 1) % 2;
}
static cairo_region_t *
find_damaged_tiles (ClutterStageView *view,
const cairo_region_t *damage_region,
GError **error)
{
ClutterStageViewPrivate *priv =
clutter_stage_view_get_instance_private (view);
cairo_region_t *tile_damage_region;
cairo_rectangle_int_t damage_extents;
cairo_rectangle_int_t fb_rect;
int prev_dma_buf_idx;
CoglDmaBufHandle *prev_dma_buf_handle;
uint8_t *prev_data;
int current_dma_buf_idx;
CoglDmaBufHandle *current_dma_buf_handle;
uint8_t *current_data;
int width, height, stride, bpp;
int tile_x_min, tile_x_max;
int tile_y_min, tile_y_max;
int tile_x, tile_y;
const int tile_size = 16;
prev_dma_buf_idx = flip_dma_buf_idx (priv->shadow.dma_buf.current_idx);
prev_dma_buf_handle = priv->shadow.dma_buf.handles[prev_dma_buf_idx];
current_dma_buf_idx = priv->shadow.dma_buf.current_idx;
current_dma_buf_handle = priv->shadow.dma_buf.handles[current_dma_buf_idx];
width = cogl_dma_buf_handle_get_width (current_dma_buf_handle);
height = cogl_dma_buf_handle_get_height (current_dma_buf_handle);
stride = cogl_dma_buf_handle_get_stride (current_dma_buf_handle);
bpp = cogl_dma_buf_handle_get_bpp (current_dma_buf_handle);
cogl_framebuffer_finish (priv->shadow.framebuffer);
if (!cogl_dma_buf_handle_sync_read_start (prev_dma_buf_handle, error))
return NULL;
if (!cogl_dma_buf_handle_sync_read_start (current_dma_buf_handle, error))
goto err_sync_read_current;
prev_data = cogl_dma_buf_handle_mmap (prev_dma_buf_handle, error);
if (!prev_data)
goto err_mmap_prev;
current_data = cogl_dma_buf_handle_mmap (current_dma_buf_handle, error);
if (!current_data)
goto err_mmap_current;
fb_rect = (cairo_rectangle_int_t) {
.width = width,
.height = height,
};
cairo_region_get_extents (damage_region, &damage_extents);
tile_x_min = damage_extents.x / tile_size;
tile_x_max = ((damage_extents.x + damage_extents.width + tile_size - 1) /
tile_size);
tile_y_min = damage_extents.y / tile_size;
tile_y_max = ((damage_extents.y + damage_extents.height + tile_size - 1) /
tile_size);
tile_damage_region = cairo_region_create ();
for (tile_y = tile_y_min; tile_y <= tile_y_max; tile_y++)
{
for (tile_x = tile_x_min; tile_x <= tile_x_max; tile_x++)
{
cairo_rectangle_int_t tile = {
.x = tile_x * tile_size,
.y = tile_y * tile_size,
.width = tile_size,
.height = tile_size,
};
if (cairo_region_contains_rectangle (damage_region, &tile) ==
CAIRO_REGION_OVERLAP_OUT)
continue;
_clutter_util_rectangle_intersection (&tile, &fb_rect, &tile);
if (is_tile_dirty (&tile, current_data, prev_data, bpp, stride))
cairo_region_union_rectangle (tile_damage_region, &tile);
}
}
if (priv->shadowfb)
if (!cogl_dma_buf_handle_sync_read_end (prev_dma_buf_handle, error))
{
clutter_stage_view_ensure_shadowfb_blit_pipeline (view);
clutter_stage_view_copy_to_framebuffer (view,
priv->shadowfb_pipeline,
priv->shadowfb,
priv->framebuffer,
TRUE);
g_warning ("Failed to end DMA buffer read synchronization: %s",
(*error)->message);
g_clear_error (error);
}
if (!cogl_dma_buf_handle_sync_read_end (current_dma_buf_handle, error))
{
g_warning ("Failed to end DMA buffer read synchronization: %s",
(*error)->message);
g_clear_error (error);
}
cogl_dma_buf_handle_munmap (prev_dma_buf_handle, prev_data, NULL);
cogl_dma_buf_handle_munmap (current_dma_buf_handle, current_data, NULL);
cairo_region_intersect (tile_damage_region, damage_region);
return tile_damage_region;
err_mmap_current:
cogl_dma_buf_handle_munmap (prev_dma_buf_handle, prev_data, NULL);
err_mmap_prev:
cogl_dma_buf_handle_sync_read_end (current_dma_buf_handle, NULL);
err_sync_read_current:
cogl_dma_buf_handle_sync_read_end (prev_dma_buf_handle, NULL);
return NULL;
}
static void
swap_dma_buf_framebuffer (ClutterStageView *view)
{
ClutterStageViewPrivate *priv =
clutter_stage_view_get_instance_private (view);
int next_idx;
CoglDmaBufHandle *next_dma_buf_handle;
CoglOffscreen *next_framebuffer;
next_idx = ((priv->shadow.dma_buf.current_idx + 1) %
G_N_ELEMENTS (priv->shadow.dma_buf.handles));
priv->shadow.dma_buf.current_idx = next_idx;
next_dma_buf_handle = priv->shadow.dma_buf.handles[next_idx];
next_framebuffer =
cogl_dma_buf_handle_get_framebuffer (next_dma_buf_handle);
cogl_clear_object (&priv->shadow.framebuffer);
priv->shadow.framebuffer = cogl_object_ref (next_framebuffer);
}
static void
copy_shadowfb_to_onscreen (ClutterStageView *view,
const cairo_region_t *swap_region)
{
ClutterStageViewPrivate *priv =
clutter_stage_view_get_instance_private (view);
ClutterDamageHistory *damage_history = priv->shadow.dma_buf.damage_history;
cairo_region_t *damage_region;
int age;
int i;
if (cairo_region_is_empty (swap_region))
{
cairo_rectangle_int_t full_damage = {
.width = cogl_framebuffer_get_width (priv->framebuffer),
.height = cogl_framebuffer_get_height (priv->framebuffer),
};
damage_region = cairo_region_create_rectangle (&full_damage);
}
else
{
damage_region = cairo_region_copy (swap_region);
}
if (is_shadowfb_double_buffered (view))
{
CoglOnscreen *onscreen = COGL_ONSCREEN (priv->framebuffer);
cairo_region_t *changed_region;
if (cogl_onscreen_get_frame_counter (onscreen) >= 1)
{
g_autoptr (GError) error = NULL;
changed_region = find_damaged_tiles (view, damage_region, &error);
if (!changed_region)
{
int other_dma_buf_idx;
g_warning ("Disabling actual damage detection: %s",
error->message);
other_dma_buf_idx =
flip_dma_buf_idx (priv->shadow.dma_buf.current_idx);
g_clear_pointer (&priv->shadow.dma_buf.handles[other_dma_buf_idx],
cogl_dma_buf_handle_free);
}
}
else
{
changed_region = cairo_region_copy (damage_region);
}
if (changed_region)
{
int buffer_age;
clutter_damage_history_record (damage_history, changed_region);
buffer_age = cogl_onscreen_get_buffer_age (onscreen);
if (clutter_damage_history_is_age_valid (damage_history, buffer_age))
{
for (age = 1; age <= buffer_age; age++)
{
const cairo_region_t *old_damage;
old_damage = clutter_damage_history_lookup (damage_history, age);
cairo_region_union (changed_region, old_damage);
}
cairo_region_destroy (damage_region);
damage_region = g_steal_pointer (&changed_region);
}
else
{
cairo_region_destroy (changed_region);
}
clutter_damage_history_step (damage_history);
}
}
for (i = 0; i < cairo_region_num_rectangles (damage_region); i++)
{
g_autoptr (GError) error = NULL;
cairo_rectangle_int_t rect;
cairo_region_get_rectangle (damage_region, i, &rect);
if (!cogl_blit_framebuffer (priv->shadow.framebuffer,
priv->framebuffer,
rect.x, rect.y,
rect.x, rect.y,
rect.width, rect.height,
&error))
{
g_warning ("Failed to blit shadow buffer: %s", error->message);
cairo_region_destroy (damage_region);
return;
}
}
cairo_region_destroy (damage_region);
if (is_shadowfb_double_buffered (view))
swap_dma_buf_framebuffer (view);
}
void
clutter_stage_view_before_swap_buffer (ClutterStageView *view,
const cairo_region_t *swap_region)
{
ClutterStageViewPrivate *priv =
clutter_stage_view_get_instance_private (view);
if (priv->shadow.framebuffer)
copy_shadowfb_to_onscreen (view, swap_region);
}
float
@ -264,6 +741,47 @@ clutter_stage_view_get_scale (ClutterStageView *view)
return priv->scale;
}
typedef void (*FrontBufferCallback) (CoglFramebuffer *framebuffer,
gconstpointer user_data);
static void
clutter_stage_view_foreach_front_buffer (ClutterStageView *view,
FrontBufferCallback callback,
gconstpointer user_data)
{
ClutterStageViewPrivate *priv =
clutter_stage_view_get_instance_private (view);
if (priv->offscreen)
{
callback (priv->offscreen, user_data);
}
else if (priv->shadow.framebuffer)
{
if (is_shadowfb_double_buffered (view))
{
int i;
for (i = 0; i < G_N_ELEMENTS (priv->shadow.dma_buf.handles); i++)
{
CoglDmaBufHandle *handle = priv->shadow.dma_buf.handles[i];
CoglFramebuffer *framebuffer =
cogl_dma_buf_handle_get_framebuffer (handle);
callback (framebuffer, user_data);
}
}
else
{
callback (priv->shadow.framebuffer, user_data);
}
}
else
{
callback (priv->framebuffer, user_data);
}
}
gboolean
clutter_stage_view_is_dirty_viewport (ClutterStageView *view)
{
@ -274,13 +792,47 @@ clutter_stage_view_is_dirty_viewport (ClutterStageView *view)
}
void
clutter_stage_view_set_dirty_viewport (ClutterStageView *view,
gboolean dirty)
clutter_stage_view_invalidate_viewport (ClutterStageView *view)
{
ClutterStageViewPrivate *priv =
clutter_stage_view_get_instance_private (view);
priv->dirty_viewport = dirty;
priv->dirty_viewport = TRUE;
}
static void
set_framebuffer_viewport (CoglFramebuffer *framebuffer,
gconstpointer user_data)
{
const graphene_rect_t *rect = user_data;
cogl_framebuffer_set_viewport (framebuffer,
rect->origin.x,
rect->origin.y,
rect->size.width,
rect->size.height);
}
void
clutter_stage_view_set_viewport (ClutterStageView *view,
float x,
float y,
float width,
float height)
{
ClutterStageViewPrivate *priv =
clutter_stage_view_get_instance_private (view);
graphene_rect_t rect;
priv->dirty_viewport = FALSE;
rect = (graphene_rect_t) {
.origin = { .x = x, .y = y },
.size = { .width = width, .height = height },
};
clutter_stage_view_foreach_front_buffer (view,
set_framebuffer_viewport,
&rect);
}
gboolean
@ -292,14 +844,33 @@ clutter_stage_view_is_dirty_projection (ClutterStageView *view)
return priv->dirty_projection;
}
static void
set_framebuffer_projection_matrix (CoglFramebuffer *framebuffer,
gconstpointer user_data)
{
cogl_framebuffer_set_projection_matrix (framebuffer, user_data);
}
void
clutter_stage_view_set_dirty_projection (ClutterStageView *view,
gboolean dirty)
clutter_stage_view_invalidate_projection (ClutterStageView *view)
{
ClutterStageViewPrivate *priv =
clutter_stage_view_get_instance_private (view);
priv->dirty_projection = dirty;
priv->dirty_projection = TRUE;
}
void
clutter_stage_view_set_projection (ClutterStageView *view,
const CoglMatrix *matrix)
{
ClutterStageViewPrivate *priv =
clutter_stage_view_get_instance_private (view);
priv->dirty_projection = FALSE;
clutter_stage_view_foreach_front_buffer (view,
set_framebuffer_projection_matrix,
matrix);
}
void
@ -391,19 +962,6 @@ clutter_stage_view_take_redraw_clip (ClutterStageView *view)
return g_steal_pointer (&priv->redraw_clip);
}
void
clutter_stage_view_transform_to_onscreen (ClutterStageView *view,
gfloat *x,
gfloat *y)
{
gfloat z = 0, w = 1;
CoglMatrix matrix;
clutter_stage_view_get_offscreen_transformation_matrix (view, &matrix);
cogl_matrix_get_inverse (&matrix, &matrix);
cogl_matrix_transform_point (&matrix, x, y, &z, &w);
}
static void
clutter_stage_default_get_offscreen_transformation_matrix (ClutterStageView *view,
CoglMatrix *matrix)
@ -442,6 +1000,9 @@ clutter_stage_view_get_property (GObject *object,
switch (prop_id)
{
case PROP_NAME:
g_value_set_string (value, priv->name);
break;
case PROP_LAYOUT:
g_value_set_boxed (value, &priv->layout);
break;
@ -451,8 +1012,8 @@ clutter_stage_view_get_property (GObject *object,
case PROP_OFFSCREEN:
g_value_set_boxed (value, priv->offscreen);
break;
case PROP_SHADOWFB:
g_value_set_boxed (value, priv->shadowfb);
case PROP_USE_SHADOWFB:
g_value_set_boolean (value, priv->use_shadowfb);
break;
case PROP_SCALE:
g_value_set_float (value, priv->scale);
@ -475,6 +1036,9 @@ clutter_stage_view_set_property (GObject *object,
switch (prop_id)
{
case PROP_NAME:
priv->name = g_value_dup_string (value);
break;
case PROP_LAYOUT:
layout = g_value_get_boxed (value);
priv->layout = *layout;
@ -499,8 +1063,8 @@ clutter_stage_view_set_property (GObject *object,
case PROP_OFFSCREEN:
priv->offscreen = g_value_dup_boxed (value);
break;
case PROP_SHADOWFB:
priv->shadowfb = g_value_dup_boxed (value);
case PROP_USE_SHADOWFB:
priv->use_shadowfb = g_value_get_boolean (value);
break;
case PROP_SCALE:
priv->scale = g_value_get_float (value);
@ -511,17 +1075,40 @@ clutter_stage_view_set_property (GObject *object,
}
static void
clutter_stage_view_dispose (GObject *object)
clutter_stage_view_constructed (GObject *object)
{
ClutterStageView *view = CLUTTER_STAGE_VIEW (object);
ClutterStageViewPrivate *priv =
clutter_stage_view_get_instance_private (view);
if (priv->use_shadowfb)
init_shadowfb (view);
G_OBJECT_CLASS (clutter_stage_view_parent_class)->constructed (object);
}
static void
clutter_stage_view_dispose (GObject *object)
{
ClutterStageView *view = CLUTTER_STAGE_VIEW (object);
ClutterStageViewPrivate *priv =
clutter_stage_view_get_instance_private (view);
int i;
g_clear_pointer (&priv->name, g_free);
g_clear_pointer (&priv->framebuffer, cogl_object_unref);
g_clear_pointer (&priv->shadowfb, cogl_object_unref);
g_clear_pointer (&priv->shadow.framebuffer, cogl_object_unref);
for (i = 0; i < G_N_ELEMENTS (priv->shadow.dma_buf.handles); i++)
{
g_clear_pointer (&priv->shadow.dma_buf.handles[i],
cogl_dma_buf_handle_free);
}
g_clear_pointer (&priv->shadow.dma_buf.damage_history,
clutter_damage_history_free);
g_clear_pointer (&priv->offscreen, cogl_object_unref);
g_clear_pointer (&priv->offscreen_pipeline, cogl_object_unref);
g_clear_pointer (&priv->shadowfb_pipeline, cogl_object_unref);
g_clear_pointer (&priv->redraw_clip, cairo_region_destroy);
G_OBJECT_CLASS (clutter_stage_view_parent_class)->dispose (object);
@ -548,8 +1135,17 @@ clutter_stage_view_class_init (ClutterStageViewClass *klass)
object_class->get_property = clutter_stage_view_get_property;
object_class->set_property = clutter_stage_view_set_property;
object_class->constructed = clutter_stage_view_constructed;
object_class->dispose = clutter_stage_view_dispose;
obj_props[PROP_NAME] =
g_param_spec_string ("name",
"Name",
"Name of view",
NULL,
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS);
obj_props[PROP_LAYOUT] =
g_param_spec_boxed ("layout",
"View layout",
@ -577,14 +1173,14 @@ clutter_stage_view_class_init (ClutterStageViewClass *klass)
G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS);
obj_props[PROP_SHADOWFB] =
g_param_spec_boxed ("shadowfb",
"Shadow framebuffer",
"Framebuffer used as intermediate shadow buffer",
COGL_TYPE_HANDLE,
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS);
obj_props[PROP_USE_SHADOWFB] =
g_param_spec_boolean ("use-shadowfb",
"Use shadowfb",
"Whether to use one or more shadow framebuffers",
FALSE,
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS);
obj_props[PROP_SCALE] =
g_param_spec_float ("scale",

View File

@ -43,6 +43,12 @@ struct _ClutterStageViewClass
void (* get_offscreen_transformation_matrix) (ClutterStageView *view,
CoglMatrix *matrix);
void (* transform_rect_to_onscreen) (ClutterStageView *view,
const cairo_rectangle_int_t *src_rect,
int dst_width,
int dst_height,
cairo_rectangle_int_t *dst_rect);
};
CLUTTER_EXPORT
@ -56,11 +62,6 @@ CoglFramebuffer *clutter_stage_view_get_onscreen (ClutterStageView *view);
CLUTTER_EXPORT
void clutter_stage_view_invalidate_offscreen_blit_pipeline (ClutterStageView *view);
CLUTTER_EXPORT
void clutter_stage_view_transform_to_onscreen (ClutterStageView *view,
gfloat *x,
gfloat *y);
CLUTTER_EXPORT
float clutter_stage_view_get_scale (ClutterStageView *view);

View File

@ -142,6 +142,8 @@ struct _ClutterStagePrivate
int update_freeze_count;
gboolean needs_update;
guint redraw_pending : 1;
guint throttle_motion_events : 1;
guint min_size_changed : 1;
@ -613,8 +615,7 @@ stage_is_default (ClutterStage *stage)
static void
clutter_stage_allocate (ClutterActor *self,
const ClutterActorBox *box,
ClutterAllocationFlags flags)
const ClutterActorBox *box)
{
ClutterStagePrivate *priv = CLUTTER_STAGE (self)->priv;
ClutterActorBox alloc = CLUTTER_ACTOR_BOX_INIT_ZERO;
@ -622,6 +623,7 @@ clutter_stage_allocate (ClutterActor *self,
float new_width, new_height;
float width, height;
cairo_rectangle_int_t window_size;
ClutterLayoutManager *layout_manager = clutter_actor_get_layout_manager (self);
if (priv->impl == NULL)
return;
@ -643,15 +645,21 @@ clutter_stage_allocate (ClutterActor *self,
*/
if (!clutter_feature_available (CLUTTER_FEATURE_STAGE_STATIC))
{
CLUTTER_NOTE (LAYOUT,
"Following allocation to %.2fx%.2f (absolute origin %s)",
width, height,
(flags & CLUTTER_ABSOLUTE_ORIGIN_CHANGED)
? "changed"
: "not changed");
ClutterActorBox children_box;
clutter_actor_set_allocation (self, box,
flags | CLUTTER_DELEGATE_LAYOUT);
children_box.x1 = children_box.y1 = 0.f;
children_box.x2 = box->x2 - box->x1;
children_box.y2 = box->y2 - box->y1;
CLUTTER_NOTE (LAYOUT,
"Following allocation to %.2fx%.2f",
width, height);
clutter_actor_set_allocation (self, box);
clutter_layout_manager_allocate (layout_manager,
CLUTTER_CONTAINER (self),
&children_box);
/* Ensure the window is sized correctly */
if (priv->min_size_changed)
@ -699,16 +707,16 @@ clutter_stage_allocate (ClutterActor *self,
CLUTTER_NOTE (LAYOUT,
"Overriding original allocation of %.2fx%.2f "
"with %.2fx%.2f (absolute origin %s)",
"with %.2fx%.2f",
width, height,
override.x2, override.y2,
(flags & CLUTTER_ABSOLUTE_ORIGIN_CHANGED)
? "changed"
: "not changed");
override.x2, override.y2);
/* and store the overridden allocation */
clutter_actor_set_allocation (self, &override,
flags | CLUTTER_DELEGATE_LAYOUT);
clutter_actor_set_allocation (self, &override);
clutter_layout_manager_allocate (layout_manager,
CLUTTER_CONTAINER (self),
&override);
}
/* reset the viewport if the allocation effectively changed */
@ -1170,7 +1178,7 @@ _clutter_stage_queue_event (ClutterStage *stage,
{
ClutterMasterClock *master_clock = _clutter_master_clock_get_default ();
_clutter_master_clock_start_running (master_clock);
_clutter_stage_schedule_update (stage);
clutter_stage_schedule_update (stage);
}
}
@ -1302,7 +1310,9 @@ _clutter_stage_needs_update (ClutterStage *stage)
priv = stage->priv;
return priv->redraw_pending || g_hash_table_size (priv->pending_relayouts) > 0;
return (priv->redraw_pending ||
priv->needs_update ||
g_hash_table_size (priv->pending_relayouts) > 0);
}
void
@ -1312,7 +1322,7 @@ clutter_stage_queue_actor_relayout (ClutterStage *stage,
ClutterStagePrivate *priv = stage->priv;
if (g_hash_table_size (priv->pending_relayouts) == 0)
_clutter_stage_schedule_update (stage);
clutter_stage_schedule_update (stage);
g_hash_table_add (priv->pending_relayouts, g_object_ref (actor));
priv->pending_relayouts_version++;
@ -1359,8 +1369,7 @@ _clutter_stage_maybe_relayout (ClutterActor *actor)
CLUTTER_SET_PRIVATE_FLAGS (queued_actor, CLUTTER_IN_RELAYOUT);
old_version = priv->pending_relayouts_version;
clutter_actor_allocate_preferred_size (queued_actor,
CLUTTER_ALLOCATION_NONE);
clutter_actor_allocate_preferred_size (queued_actor);
CLUTTER_UNSET_PRIVATE_FLAGS (queued_actor, CLUTTER_IN_RELAYOUT);
@ -1494,6 +1503,8 @@ _clutter_stage_do_update (ClutterStage *stage)
priv->stage_was_relayout = FALSE;
priv->needs_update = FALSE;
/* if the stage is being destroyed, or if the destruction already
* happened and we don't have an StageWindow any more, then we
* should bail out
@ -2429,7 +2440,7 @@ _clutter_stage_dirty_projection (ClutterStage *stage)
{
ClutterStageView *view = l->data;
clutter_stage_view_set_dirty_projection (view, TRUE);
clutter_stage_view_invalidate_projection (view);
}
}
@ -2519,7 +2530,7 @@ _clutter_stage_dirty_viewport (ClutterStage *stage)
{
ClutterStageView *view = l->data;
clutter_stage_view_set_dirty_viewport (view, TRUE);
clutter_stage_view_invalidate_viewport (view);
}
}
@ -3142,7 +3153,6 @@ _clutter_stage_maybe_setup_viewport (ClutterStage *stage,
ClutterStageView *view)
{
ClutterStagePrivate *priv = stage->priv;
CoglFramebuffer *fb = clutter_stage_view_get_framebuffer (view);
if (clutter_stage_view_is_dirty_viewport (view))
{
@ -3169,19 +3179,14 @@ _clutter_stage_maybe_setup_viewport (ClutterStage *stage,
viewport_y = roundf (priv->viewport[1] * fb_scale - viewport_offset_y);
viewport_width = roundf (priv->viewport[2] * fb_scale);
viewport_height = roundf (priv->viewport[3] * fb_scale);
cogl_framebuffer_set_viewport (fb,
viewport_x, viewport_y,
viewport_width, viewport_height);
clutter_stage_view_set_dirty_viewport (view, FALSE);
clutter_stage_view_set_viewport (view,
viewport_x, viewport_y,
viewport_width, viewport_height);
}
if (clutter_stage_view_is_dirty_projection (view))
{
cogl_framebuffer_set_projection_matrix (fb, &priv->projection);
clutter_stage_view_set_dirty_projection (view, FALSE);
}
clutter_stage_view_set_projection (view, &priv->projection);
}
#undef _DEG_TO_RAD
@ -3209,7 +3214,7 @@ clutter_stage_ensure_redraw (ClutterStage *stage)
priv = stage->priv;
if (!_clutter_stage_needs_update (stage))
_clutter_stage_schedule_update (stage);
clutter_stage_schedule_update (stage);
priv->redraw_pending = TRUE;
@ -3437,13 +3442,13 @@ clutter_stage_get_minimum_size (ClutterStage *stage,
}
/**
* _clutter_stage_schedule_update:
* @window: a #ClutterStage actor
* clutter_stage_schedule_update:
* @stage: a #ClutterStage actor
*
* Schedules a redraw of the #ClutterStage at the next optimal timestamp.
*/
void
_clutter_stage_schedule_update (ClutterStage *stage)
clutter_stage_schedule_update (ClutterStage *stage)
{
ClutterStageWindow *stage_window;
@ -3454,6 +3459,8 @@ _clutter_stage_schedule_update (ClutterStage *stage)
if (stage_window == NULL)
return;
stage->priv->needs_update = TRUE;
return _clutter_stage_window_schedule_update (stage_window,
stage->priv->sync_delay);
}
@ -3463,7 +3470,7 @@ _clutter_stage_schedule_update (ClutterStage *stage)
* @stage: a #ClutterStage actor
*
* Returns the earliest time in which the stage is ready to update. The update
* time is set when _clutter_stage_schedule_update() is called. This can then
* time is set when clutter_stage_schedule_update() is called. This can then
* be used by e.g. the #ClutterMasterClock to know when the stage needs to be
* redrawn.
*
@ -3573,7 +3580,7 @@ _clutter_stage_queue_actor_redraw (ClutterStage *stage,
CLUTTER_NOTE (PAINT, "First redraw request");
_clutter_stage_schedule_update (stage);
clutter_stage_schedule_update (stage);
priv->redraw_pending = TRUE;
master_clock = _clutter_master_clock_get_default ();

View File

@ -209,6 +209,9 @@ CLUTTER_EXPORT
void clutter_stage_skip_sync_delay (ClutterStage *stage);
#endif
CLUTTER_EXPORT
void clutter_stage_schedule_update (ClutterStage *stage);
CLUTTER_EXPORT
gboolean clutter_stage_get_capture_final_size (ClutterStage *stage,
cairo_rectangle_int_t *rect,

View File

@ -3037,8 +3037,7 @@ clutter_text_get_preferred_height (ClutterActor *self,
static void
clutter_text_allocate (ClutterActor *self,
const ClutterActorBox *box,
ClutterAllocationFlags flags)
const ClutterActorBox *box)
{
ClutterText *text = CLUTTER_TEXT (self);
ClutterActorClass *parent_class;
@ -3058,7 +3057,7 @@ clutter_text_allocate (ClutterActor *self,
box->y2 - box->y1);
parent_class = CLUTTER_ACTOR_CLASS (clutter_text_parent_class);
parent_class->allocate (self, box, flags);
parent_class->allocate (self, box);
}
static gboolean
@ -4787,11 +4786,11 @@ clutter_text_queue_redraw_or_relayout (ClutterText *self)
clutter_text_get_preferred_height (actor, preferred_width, NULL, &preferred_height);
if (clutter_actor_has_allocation (actor) &&
(fabsf (preferred_width - clutter_actor_get_width (actor)) > 0.001 ||
fabsf (preferred_height - clutter_actor_get_height (actor)) > 0.001))
clutter_actor_queue_relayout (actor);
else
fabsf (preferred_width - clutter_actor_get_width (actor)) <= 0.001 &&
fabsf (preferred_height - clutter_actor_get_height (actor)) <= 0.001)
clutter_text_queue_redraw (actor);
else
clutter_actor_queue_relayout (actor);
}
static void

View File

@ -24,7 +24,6 @@
/**
* SECTION:clutter-timeline
* @short_description: A class for time-based events
* @see_also: #ClutterAnimation, #ClutterAnimator, #ClutterState
*
* #ClutterTimeline is a base class for managing time-based event that cause
* Clutter to redraw a stage, such as animations.
@ -71,7 +70,7 @@
* when reaching completion by using the #ClutterTimeline:auto-reverse property.
*
* Timelines are used in the Clutter animation framework by classes like
* #ClutterAnimation, #ClutterAnimator, and #ClutterState.
* #ClutterTransition.
*
* ## Defining Timelines in ClutterScript
*

View File

@ -79,10 +79,6 @@ typedef struct _ClutterKnot ClutterKnot;
typedef struct _ClutterMargin ClutterMargin;
typedef struct _ClutterPerspective ClutterPerspective;
typedef struct _ClutterAlpha ClutterAlpha;
typedef struct _ClutterAnimation ClutterAnimation;
typedef struct _ClutterState ClutterState;
typedef struct _ClutterInputDeviceTool ClutterInputDeviceTool;
typedef struct _ClutterInputDevice ClutterInputDevice;
typedef struct _ClutterVirtualInputDevice ClutterVirtualInputDevice;

View File

@ -38,6 +38,7 @@
#include "clutter-actor-private.h"
#include "clutter-backend-private.h"
#include "clutter-damage-history.h"
#include "clutter-debug.h"
#include "clutter-event.h"
#include "clutter-enum-types.h"
@ -51,13 +52,9 @@
typedef struct _ClutterStageViewCoglPrivate
{
/*
* List of previous damaged areas in stage view framebuffer coordinate space.
/* Damage history, in stage view render target framebuffer coordinate space.
*/
#define DAMAGE_HISTORY_MAX 16
#define DAMAGE_HISTORY(x) ((x) & (DAMAGE_HISTORY_MAX - 1))
cairo_region_t * damage_history[DAMAGE_HISTORY_MAX];
unsigned int damage_index;
ClutterDamageHistory *damage_history;
} ClutterStageViewCoglPrivate;
G_DEFINE_TYPE_WITH_PRIVATE (ClutterStageViewCogl, clutter_stage_view_cogl,
@ -288,26 +285,13 @@ clutter_stage_cogl_resize (ClutterStageWindow *stage_window,
{
}
static inline gboolean
valid_buffer_age (ClutterStageViewCogl *view_cogl,
int age)
{
ClutterStageViewCoglPrivate *view_priv =
clutter_stage_view_cogl_get_instance_private (view_cogl);
if (age <= 0)
return FALSE;
return age < MIN (view_priv->damage_index, DAMAGE_HISTORY_MAX);
}
static void
paint_damage_region (ClutterStageWindow *stage_window,
ClutterStageView *view,
cairo_region_t *swap_region,
cairo_region_t *queued_redraw_clip)
{
CoglFramebuffer *framebuffer = clutter_stage_view_get_onscreen (view);
CoglFramebuffer *framebuffer = clutter_stage_view_get_framebuffer (view);
CoglContext *ctx = cogl_framebuffer_get_context (framebuffer);
static CoglPipeline *overlay_blue = NULL;
ClutterStageCogl *stage_cogl = CLUTTER_STAGE_COGL (stage_window);
@ -378,24 +362,26 @@ swap_framebuffer (ClutterStageWindow *stage_window,
gboolean swap_with_damage)
{
CoglFramebuffer *framebuffer = clutter_stage_view_get_onscreen (view);
int *damage, n_rects, i;
n_rects = cairo_region_num_rectangles (swap_region);
damage = g_newa (int, n_rects * 4);
for (i = 0; i < n_rects; i++)
{
cairo_rectangle_int_t rect;
cairo_region_get_rectangle (swap_region, i, &rect);
damage[i * 4] = rect.x;
damage[i * 4 + 1] = rect.y;
damage[i * 4 + 2] = rect.width;
damage[i * 4 + 3] = rect.height;
}
clutter_stage_view_before_swap_buffer (view, swap_region);
if (cogl_is_onscreen (framebuffer))
{
CoglOnscreen *onscreen = COGL_ONSCREEN (framebuffer);
int *damage, n_rects, i;
n_rects = cairo_region_num_rectangles (swap_region);
damage = g_newa (int, n_rects * 4);
for (i = 0; i < n_rects; i++)
{
cairo_rectangle_int_t rect;
cairo_region_get_rectangle (swap_region, i, &rect);
damage[i * 4] = rect.x;
damage[i * 4 + 1] = rect.y;
damage[i * 4 + 2] = rect.width;
damage[i * 4 + 3] = rect.height;
}
/* push on the screen */
if (n_rects > 0 && !swap_with_damage)
@ -430,18 +416,6 @@ swap_framebuffer (ClutterStageWindow *stage_window,
}
}
static void
scale_and_clamp_rect (const graphene_rect_t *rect,
float scale,
cairo_rectangle_int_t *dest)
{
graphene_rect_t tmp = *rect;
graphene_rect_scale (&tmp, scale, scale, &tmp);
_clutter_util_rectangle_int_extents (&tmp, dest);
}
static cairo_region_t *
offset_scale_and_clamp_region (const cairo_region_t *region,
int offset_x,
@ -463,15 +437,52 @@ offset_scale_and_clamp_region (const cairo_region_t *region,
rects = freeme = g_new (cairo_rectangle_int_t, n_rects);
for (i = 0; i < n_rects; i++)
cairo_region_get_rectangle (region, i, &rects[i]);
{
cairo_rectangle_int_t *rect = &rects[i];
graphene_rect_t tmp;
cairo_region_get_rectangle (region, i, rect);
_clutter_util_rect_from_rectangle (rect, &tmp);
graphene_rect_offset (&tmp, offset_x, offset_y);
graphene_rect_scale (&tmp, scale, scale, &tmp);
_clutter_util_rectangle_int_extents (&tmp, rect);
}
return cairo_region_create_rectangles (rects, n_rects);
}
static cairo_region_t *
scale_offset_and_clamp_region (const cairo_region_t *region,
float scale,
int offset_x,
int offset_y)
{
int n_rects, i;
cairo_rectangle_int_t *rects;
g_autofree cairo_rectangle_int_t *freeme = NULL;
n_rects = cairo_region_num_rectangles (region);
if (n_rects == 0)
return cairo_region_create ();
if (n_rects < MAX_STACK_RECTS)
rects = g_newa (cairo_rectangle_int_t, n_rects);
else
rects = freeme = g_new (cairo_rectangle_int_t, n_rects);
for (i = 0; i < n_rects; i++)
{
cairo_rectangle_int_t *rect = &rects[i];
graphene_rect_t tmp;
_clutter_util_rect_from_rectangle (&rects[i], &tmp);
cairo_region_get_rectangle (region, i, rect);
_clutter_util_rect_from_rectangle (rect, &tmp);
graphene_rect_scale (&tmp, scale, scale, &tmp);
graphene_rect_offset (&tmp, offset_x, offset_y);
scale_and_clamp_rect (&tmp, scale, &rects[i]);
_clutter_util_rectangle_int_extents (&tmp, rect);
}
return cairo_region_create_rectangles (rects, n_rects);
@ -487,107 +498,38 @@ paint_stage (ClutterStageCogl *stage_cogl,
_clutter_stage_maybe_setup_viewport (stage, view);
clutter_stage_paint_view (stage, view, redraw_clip);
clutter_stage_view_after_paint (view);
}
static void
fill_current_damage_history (ClutterStageView *view,
cairo_region_t *damage)
{
ClutterStageViewCogl *view_cogl = CLUTTER_STAGE_VIEW_COGL (view);
ClutterStageViewCoglPrivate *view_priv =
clutter_stage_view_cogl_get_instance_private (view_cogl);
cairo_region_t **current_fb_damage;
current_fb_damage =
&view_priv->damage_history[DAMAGE_HISTORY (view_priv->damage_index)];
g_clear_pointer (current_fb_damage, cairo_region_destroy);
*current_fb_damage = cairo_region_copy (damage);
view_priv->damage_index++;
}
static void
fill_current_damage_history_rectangle (ClutterStageView *view,
const cairo_rectangle_int_t *rect)
{
cairo_region_t *damage;
damage = cairo_region_create_rectangle (rect);
fill_current_damage_history (view, damage);
cairo_region_destroy (damage);
clutter_stage_view_after_paint (view, redraw_clip);
}
static cairo_region_t *
transform_swap_region_to_onscreen (ClutterStageView *view,
cairo_region_t *swap_region)
{
CoglFramebuffer *framebuffer;
cairo_rectangle_int_t layout;
gint width, height;
CoglFramebuffer *onscreen = clutter_stage_view_get_onscreen (view);
int n_rects, i;
cairo_rectangle_int_t *rects;
cairo_region_t *transformed_region;
int width, height;
framebuffer = clutter_stage_view_get_onscreen (view);
clutter_stage_view_get_layout (view, &layout);
width = cogl_framebuffer_get_width (framebuffer);
height = cogl_framebuffer_get_height (framebuffer);
width = cogl_framebuffer_get_width (onscreen);
height = cogl_framebuffer_get_height (onscreen);
n_rects = cairo_region_num_rectangles (swap_region);
rects = g_newa (cairo_rectangle_int_t, n_rects);
for (i = 0; i < n_rects; i++)
{
gfloat x1, y1, x2, y2;
cairo_region_get_rectangle (swap_region, i, &rects[i]);
x1 = (float) rects[i].x / layout.width;
y1 = (float) rects[i].y / layout.height;
x2 = (float) (rects[i].x + rects[i].width) / layout.width;
y2 = (float) (rects[i].y + rects[i].height) / layout.height;
clutter_stage_view_transform_to_onscreen (view, &x1, &y1);
clutter_stage_view_transform_to_onscreen (view, &x2, &y2);
x1 = floor (x1 * width);
y1 = floor (height - (y1 * height));
x2 = ceil (x2 * width);
y2 = ceil (height - (y2 * height));
rects[i].x = x1;
rects[i].y = y1;
rects[i].width = x2 - x1;
rects[i].height = y2 - y1;
clutter_stage_view_transform_rect_to_onscreen (view,
&rects[i],
width,
height,
&rects[i]);
}
transformed_region = cairo_region_create_rectangles (rects, n_rects);
return transformed_region;
}
static void
calculate_scissor_region (cairo_rectangle_int_t *fb_clip_region,
int subpixel_compensation,
int fb_width,
int fb_height,
cairo_rectangle_int_t *out_scissor_rect)
{
*out_scissor_rect = *fb_clip_region;
if (subpixel_compensation == 0)
return;
if (fb_clip_region->x > 0)
out_scissor_rect->x += subpixel_compensation;
if (fb_clip_region->y > 0)
out_scissor_rect->y += subpixel_compensation;
if (fb_clip_region->x + fb_clip_region->width < fb_width)
out_scissor_rect->width -= 2 * subpixel_compensation;
if (fb_clip_region->y + fb_clip_region->height < fb_height)
out_scissor_rect->height -= 2 * subpixel_compensation;
}
static inline gboolean
is_buffer_age_enabled (void)
{
@ -606,27 +548,21 @@ clutter_stage_cogl_redraw_view (ClutterStageWindow *stage_window,
ClutterStageViewCoglPrivate *view_priv =
clutter_stage_view_cogl_get_instance_private (view_cogl);
CoglFramebuffer *fb = clutter_stage_view_get_framebuffer (view);
CoglFramebuffer *onscreen = clutter_stage_view_get_onscreen (view);
cairo_rectangle_int_t view_rect;
gboolean is_full_redraw;
gboolean may_use_clipped_redraw;
gboolean use_clipped_redraw;
gboolean can_blit_sub_buffer;
gboolean has_buffer_age;
gboolean do_swap_buffer;
gboolean swap_with_damage;
ClutterActor *wrapper;
cairo_region_t *redraw_clip;
cairo_region_t *queued_redraw_clip = NULL;
cairo_region_t *fb_clip_region;
cairo_region_t *swap_region;
cairo_rectangle_int_t redraw_rect;
gboolean clip_region_empty;
float fb_scale;
int subpixel_compensation = 0;
int fb_width, fb_height;
int buffer_age;
wrapper = CLUTTER_ACTOR (stage_cogl->wrapper);
gboolean res;
clutter_stage_view_get_layout (view, &view_rect);
fb_scale = clutter_stage_view_get_scale (view);
@ -634,10 +570,10 @@ clutter_stage_cogl_redraw_view (ClutterStageWindow *stage_window,
fb_height = cogl_framebuffer_get_height (fb);
can_blit_sub_buffer =
cogl_is_onscreen (fb) &&
cogl_is_onscreen (onscreen) &&
cogl_clutter_winsys_has_feature (COGL_WINSYS_FEATURE_SWAP_REGION);
has_buffer_age = cogl_is_onscreen (fb) && is_buffer_age_enabled ();
has_buffer_age = cogl_is_onscreen (onscreen) && is_buffer_age_enabled ();
redraw_clip = clutter_stage_view_take_redraw_clip (view);
if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_PAINT_DAMAGE_REGION))
@ -649,51 +585,35 @@ clutter_stage_cogl_redraw_view (ClutterStageWindow *stage_window,
else
is_full_redraw = FALSE;
may_use_clipped_redraw =
if (has_buffer_age)
{
buffer_age = cogl_onscreen_get_buffer_age (COGL_ONSCREEN (onscreen));
if (!clutter_damage_history_is_age_valid (view_priv->damage_history,
buffer_age))
{
CLUTTER_NOTE (CLIPPING,
"Invalid back buffer(age=%d): forcing full redraw\n",
buffer_age);
use_clipped_redraw = FALSE;
}
}
use_clipped_redraw =
use_clipped_redraw &&
!(clutter_paint_debug_flags & CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS) &&
_clutter_stage_window_can_clip_redraws (stage_window) &&
(can_blit_sub_buffer || has_buffer_age) &&
!is_full_redraw &&
/* some drivers struggle to get going and produce some junk
* frames when starting up... */
cogl_onscreen_get_frame_counter (COGL_ONSCREEN (fb)) > 3;
cogl_onscreen_get_frame_counter (COGL_ONSCREEN (onscreen)) > 3;
if (has_buffer_age)
{
buffer_age = cogl_onscreen_get_buffer_age (COGL_ONSCREEN (fb));
if (!valid_buffer_age (view_cogl, buffer_age))
{
CLUTTER_NOTE (CLIPPING, "Invalid back buffer(age=%d): forcing full redraw\n", buffer_age);
may_use_clipped_redraw = FALSE;
}
}
if (may_use_clipped_redraw)
if (use_clipped_redraw)
{
fb_clip_region = offset_scale_and_clamp_region (redraw_clip,
-view_rect.x,
-view_rect.y,
fb_scale);
if (fb_scale != floorf (fb_scale))
{
int n_rects, i;
cairo_rectangle_int_t *rects;
subpixel_compensation = ceilf (fb_scale);
n_rects = cairo_region_num_rectangles (fb_clip_region);
rects = g_newa (cairo_rectangle_int_t, n_rects);
for (i = 0; i < n_rects; i++)
{
cairo_region_get_rectangle (fb_clip_region, i, &rects[i]);
rects[i].x -= subpixel_compensation;
rects[i].y -= subpixel_compensation;
rects[i].width += 2 * subpixel_compensation;
rects[i].height += 2 * subpixel_compensation;
}
cairo_region_destroy (fb_clip_region);
fb_clip_region = cairo_region_create_rectangles (rects, n_rects);
}
}
else
{
@ -709,46 +629,40 @@ clutter_stage_cogl_redraw_view (ClutterStageWindow *stage_window,
redraw_clip = cairo_region_create_rectangle (&view_rect);
}
if (may_use_clipped_redraw &&
G_LIKELY (!(clutter_paint_debug_flags & CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS)))
use_clipped_redraw = TRUE;
else
use_clipped_redraw = FALSE;
clip_region_empty = may_use_clipped_redraw && cairo_region_is_empty (fb_clip_region);
g_return_val_if_fail (!cairo_region_is_empty (fb_clip_region), FALSE);
swap_with_damage = FALSE;
if (has_buffer_age)
{
if (use_clipped_redraw && !clip_region_empty)
clutter_damage_history_record (view_priv->damage_history,
fb_clip_region);
if (use_clipped_redraw)
{
cairo_region_t *fb_damage;
cairo_region_t *view_damage;
int i;
fill_current_damage_history (view, fb_clip_region);
int age;
fb_damage = cairo_region_create ();
for (i = 1; i <= buffer_age; i++)
for (age = 1; age <= buffer_age; age++)
{
int damage_index;
const cairo_region_t *old_damage;
damage_index = DAMAGE_HISTORY (view_priv->damage_index - i - 1);
cairo_region_union (fb_damage,
view_priv->damage_history[damage_index]);
old_damage =
clutter_damage_history_lookup (view_priv->damage_history, age);
cairo_region_union (fb_damage, old_damage);
}
/* Update the fb clip region with the extra damage. */
cairo_region_union (fb_clip_region, fb_damage);
view_damage = offset_scale_and_clamp_region (fb_damage,
0, 0,
1.0f / fb_scale);
cairo_region_translate (view_damage, view_rect.x, view_rect.y);
cairo_region_intersect_rectangle (view_damage, &view_rect);
/* Update the redraw clip with the extra damage done to the view */
view_damage = scale_offset_and_clamp_region (fb_damage,
1.0f / fb_scale,
view_rect.x,
view_rect.y);
/* Update the redraw clip region with the extra damage. */
cairo_region_union (redraw_clip, view_damage);
cairo_region_destroy (view_damage);
@ -760,55 +674,13 @@ clutter_stage_cogl_redraw_view (ClutterStageWindow *stage_window,
swap_with_damage = TRUE;
}
else if (!use_clipped_redraw)
{
cairo_rectangle_int_t fb_damage;
fb_damage = (cairo_rectangle_int_t) {
.x = 0,
.y = 0,
.width = ceilf (view_rect.width * fb_scale),
.height = ceilf (view_rect.height * fb_scale)
};
fill_current_damage_history_rectangle (view, &fb_damage);
}
clutter_damage_history_step (view_priv->damage_history);
}
if (use_clipped_redraw && clip_region_empty)
if (use_clipped_redraw)
{
CLUTTER_NOTE (CLIPPING, "Empty stage output paint\n");
}
else if (use_clipped_redraw)
{
cairo_rectangle_int_t clip_rect;
cairo_rectangle_int_t scissor_rect;
if (cairo_region_num_rectangles (fb_clip_region) == 1)
{
cairo_region_get_extents (fb_clip_region, &clip_rect);
calculate_scissor_region (&clip_rect,
subpixel_compensation,
fb_width, fb_height,
&scissor_rect);
CLUTTER_NOTE (CLIPPING,
"Stage clip pushed: x=%d, y=%d, width=%d, height=%d\n",
scissor_rect.x,
scissor_rect.y,
scissor_rect.width,
scissor_rect.height);
cogl_framebuffer_push_scissor_clip (fb,
scissor_rect.x,
scissor_rect.y,
scissor_rect.width,
scissor_rect.height);
}
else
{
cogl_framebuffer_push_region_clip (fb, fb_clip_region);
}
cogl_framebuffer_push_region_clip (fb, fb_clip_region);
paint_stage (stage_cogl, view, redraw_clip);
@ -818,77 +690,7 @@ clutter_stage_cogl_redraw_view (ClutterStageWindow *stage_window,
{
CLUTTER_NOTE (CLIPPING, "Unclipped stage paint\n");
/* If we are trying to debug redraw issues then we want to pass
* the redraw_clip so it can be visualized */
if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS) &&
may_use_clipped_redraw &&
!clip_region_empty)
{
cairo_rectangle_int_t clip_rect;
cairo_rectangle_int_t scissor_rect;
cairo_region_get_extents (fb_clip_region, &clip_rect);
calculate_scissor_region (&clip_rect,
subpixel_compensation,
fb_width, fb_height,
&scissor_rect);
cogl_framebuffer_push_scissor_clip (fb,
scissor_rect.x,
scissor_rect.y,
scissor_rect.width,
scissor_rect.height);
paint_stage (stage_cogl, view, redraw_clip);
cogl_framebuffer_pop_clip (fb);
}
else
{
paint_stage (stage_cogl, view, redraw_clip);
}
}
cairo_region_get_extents (redraw_clip, &redraw_rect);
if (may_use_clipped_redraw &&
G_UNLIKELY ((clutter_paint_debug_flags & CLUTTER_DEBUG_REDRAWS)))
{
CoglContext *ctx = cogl_framebuffer_get_context (fb);
static CoglPipeline *outline = NULL;
ClutterActor *actor = CLUTTER_ACTOR (wrapper);
float x_1 = redraw_rect.x;
float x_2 = redraw_rect.x + redraw_rect.width;
float y_1 = redraw_rect.y;
float y_2 = redraw_rect.y + redraw_rect.height;
CoglVertexP2 quad[4] = {
{ x_1, y_1 },
{ x_2, y_1 },
{ x_2, y_2 },
{ x_1, y_2 }
};
CoglPrimitive *prim;
CoglMatrix modelview;
if (outline == NULL)
{
outline = cogl_pipeline_new (ctx);
cogl_pipeline_set_color4ub (outline, 0xff, 0x00, 0x00, 0xff);
}
prim = cogl_primitive_new_p2 (ctx,
COGL_VERTICES_MODE_LINE_LOOP,
4, /* n_vertices */
quad);
cogl_framebuffer_push_matrix (fb);
cogl_matrix_init_identity (&modelview);
_clutter_actor_apply_modelview_transform (actor, &modelview);
cogl_framebuffer_set_modelview_matrix (fb, &modelview);
cogl_framebuffer_draw_primitive (fb, outline, prim);
cogl_framebuffer_pop_matrix (fb);
cogl_object_unref (prim);
paint_stage (stage_cogl, view, redraw_clip);
}
/* XXX: It seems there will be a race here in that the stage
@ -900,65 +702,42 @@ clutter_stage_cogl_redraw_view (ClutterStageWindow *stage_window,
* artefacts.
*/
if (use_clipped_redraw)
{
if (clip_region_empty)
{
do_swap_buffer = FALSE;
}
else
{
swap_region = cairo_region_copy (fb_clip_region);
do_swap_buffer = TRUE;
}
}
swap_region = cairo_region_copy (fb_clip_region);
else
{
swap_region = cairo_region_create ();
do_swap_buffer = TRUE;
}
swap_region = cairo_region_create ();
g_clear_pointer (&redraw_clip, cairo_region_destroy);
g_clear_pointer (&fb_clip_region, cairo_region_destroy);
if (do_swap_buffer)
COGL_TRACE_BEGIN_SCOPED (ClutterStageCoglRedrawViewSwapFramebuffer,
"Paint (swap framebuffer)");
if (clutter_stage_view_get_onscreen (view) !=
clutter_stage_view_get_framebuffer (view))
{
gboolean res;
COGL_TRACE_BEGIN_SCOPED (ClutterStageCoglRedrawViewSwapFramebuffer,
"Paint (swap framebuffer)");
if (clutter_stage_view_get_onscreen (view) !=
clutter_stage_view_get_framebuffer (view))
{
cairo_region_t *transformed_swap_region;
transformed_swap_region =
transform_swap_region_to_onscreen (view, swap_region);
cairo_region_destroy (swap_region);
swap_region = transformed_swap_region;
}
if (queued_redraw_clip)
{
paint_damage_region (stage_window, view,
swap_region, queued_redraw_clip);
cairo_region_destroy (queued_redraw_clip);
}
res = swap_framebuffer (stage_window,
view,
swap_region,
swap_with_damage);
cairo_region_t *transformed_swap_region;
transformed_swap_region =
transform_swap_region_to_onscreen (view, swap_region);
cairo_region_destroy (swap_region);
swap_region = transformed_swap_region;
}
return res;
}
else
if (queued_redraw_clip)
{
g_clear_pointer (&queued_redraw_clip, cairo_region_destroy);
return FALSE;
paint_damage_region (stage_window, view,
swap_region, queued_redraw_clip);
cairo_region_destroy (queued_redraw_clip);
}
res = swap_framebuffer (stage_window,
view,
swap_region,
swap_with_damage);
cairo_region_destroy (swap_region);
return res;
}
static void
@ -1083,12 +862,31 @@ _clutter_stage_cogl_init (ClutterStageCogl *stage)
stage->update_time = -1;
}
static void
clutter_stage_view_cogl_finalize (GObject *object)
{
ClutterStageViewCogl *view_cogl = CLUTTER_STAGE_VIEW_COGL (object);
ClutterStageViewCoglPrivate *view_priv =
clutter_stage_view_cogl_get_instance_private (view_cogl);
clutter_damage_history_free (view_priv->damage_history);
G_OBJECT_CLASS (clutter_stage_view_cogl_parent_class)->finalize (object);
}
static void
clutter_stage_view_cogl_init (ClutterStageViewCogl *view_cogl)
{
ClutterStageViewCoglPrivate *view_priv =
clutter_stage_view_cogl_get_instance_private (view_cogl);
view_priv->damage_history = clutter_damage_history_new ();
}
static void
clutter_stage_view_cogl_class_init (ClutterStageViewCoglClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->finalize = clutter_stage_view_cogl_finalize;
}

View File

@ -1,819 +0,0 @@
/*
* Clutter.
*
* An OpenGL based 'interactive canvas' library.
*
* Authored By Matthew Allum <mallum@openedhand.com>
* Jorn Baayen <jorn@openedhand.com>
* Emmanuele Bassi <ebassi@openedhand.com>
* Tomas Frydrych <tf@openedhand.com>
*
* Copyright (C) 2006, 2007, 2008 OpenedHand
* Copyright (C) 2009, 2010 Intel Corp.
*
* 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/>.
*/
/**
* SECTION:clutter-alpha
* @short_description: A class for calculating a value as a function of time
*
* #ClutterAlpha is a class for calculating an floating point value
* dependent only on the position of a #ClutterTimeline.
*
* For newly written code, it is recommended to use the
* #ClutterTimeline:progress-mode property of #ClutterTimeline, or the
* clutter_timeline_set_progress_func() function instead of #ClutterAlpha.
* The #ClutterAlpha class will be deprecated in the future, and will not
* be available any more in the next major version of Clutter.
*
* A #ClutterAlpha binds a #ClutterTimeline to a progress function which
* translates the time T into an adimensional factor alpha.
*
* You should provide a #ClutterTimeline and bind it to the #ClutterAlpha
* instance using clutter_alpha_set_timeline(). You should also set an
* "animation mode", by using the #ClutterAnimationMode values that
* Clutter provides.
*
* Instead of a #ClutterAnimationMode you may provide a function returning
* the alpha value depending on the progress of the timeline, using
* clutter_alpha_set_func() or clutter_alpha_set_closure(). The alpha
* function will be executed each time a new frame in the #ClutterTimeline
* is reached.
*
* Since the alpha function is controlled by the timeline instance, you can
* pause, stop or resume the #ClutterAlpha from calling the alpha function by
* using the appropriate functions of the #ClutterTimeline object.
*
* #ClutterAlpha is available since Clutter 0.2.
*
* #ClutterAlpha is deprecated since Clutter 1.12. #ClutterTimeline and
* the #ClutterTimeline:progress-mode property replace this whole class.
*
* ## ClutterAlpha custom properties for #ClutterScript
*
* #ClutterAlpha defines a custom `function` property for
* #ClutterScript which allows to reference a custom alpha function
* available in the source code. Setting the `function` property
* is equivalent to calling clutter_alpha_set_func() with the
* specified function name. No user data or #GDestroyNotify is
* available to be passed.
*
* The following JSON fragment defines a #ClutterAlpha
* using a #ClutterTimeline with id "sine-timeline" and an alpha
* function called `my_sine_alpha`.
*
* |[
* {
* "id" : "sine-alpha",
* "timeline" : {
* "id" : "sine-timeline",
* "duration" : 500,
* "loop" : true
* },
* "function" : "my_sine_alpha"
* }
* ]|
*/
#include "clutter-build-config.h"
#include <math.h>
#include <gmodule.h>
#define CLUTTER_DISABLE_DEPRECATION_WARNINGS
#include "clutter-alpha.h"
#include "clutter-debug.h"
#include "clutter-enum-types.h"
#include "clutter-easing.h"
#include "clutter-main.h"
#include "clutter-marshal.h"
#include "clutter-private.h"
#include "clutter-scriptable.h"
#include "clutter-script-private.h"
struct _ClutterAlphaPrivate
{
ClutterTimeline *timeline;
guint timeline_new_frame_id;
gdouble alpha;
GClosure *closure;
ClutterAlphaFunc func;
gpointer user_data;
GDestroyNotify notify;
gulong mode;
};
enum
{
PROP_0,
PROP_TIMELINE,
PROP_ALPHA,
PROP_MODE,
PROP_LAST
};
static GParamSpec *obj_props[PROP_LAST];
static void clutter_scriptable_iface_init (ClutterScriptableIface *iface);
G_DEFINE_TYPE_WITH_CODE (ClutterAlpha,
clutter_alpha,
G_TYPE_INITIALLY_UNOWNED,
G_ADD_PRIVATE (ClutterAlpha)
G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_SCRIPTABLE,
clutter_scriptable_iface_init));
static void
timeline_new_frame_cb (ClutterTimeline *timeline,
guint msecs,
ClutterAlpha *alpha)
{
ClutterAlphaPrivate *priv = alpha->priv;
/* Update alpha value and notify */
priv->alpha = clutter_alpha_get_alpha (alpha);
g_object_notify_by_pspec (G_OBJECT (alpha), obj_props[PROP_ALPHA]);
}
static void
clutter_alpha_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
ClutterAlpha *alpha = CLUTTER_ALPHA (object);
switch (prop_id)
{
case PROP_TIMELINE:
clutter_alpha_set_timeline (alpha, g_value_get_object (value));
break;
case PROP_MODE:
clutter_alpha_set_mode (alpha, g_value_get_ulong (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
clutter_alpha_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
ClutterAlphaPrivate *priv = CLUTTER_ALPHA (object)->priv;
switch (prop_id)
{
case PROP_TIMELINE:
g_value_set_object (value, priv->timeline);
break;
case PROP_ALPHA:
g_value_set_double (value, priv->alpha);
break;
case PROP_MODE:
g_value_set_ulong (value, priv->mode);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
clutter_alpha_finalize (GObject *object)
{
ClutterAlphaPrivate *priv = CLUTTER_ALPHA (object)->priv;
if (priv->notify != NULL)
priv->notify (priv->user_data);
else if (priv->closure != NULL)
g_closure_unref (priv->closure);
G_OBJECT_CLASS (clutter_alpha_parent_class)->finalize (object);
}
static void
clutter_alpha_dispose (GObject *object)
{
ClutterAlpha *self = CLUTTER_ALPHA(object);
clutter_alpha_set_timeline (self, NULL);
G_OBJECT_CLASS (clutter_alpha_parent_class)->dispose (object);
}
static ClutterAlphaFunc
resolve_alpha_func (const gchar *name)
{
static GModule *module = NULL;
ClutterAlphaFunc func;
CLUTTER_NOTE (SCRIPT, "Looking up '%s' alpha function", name);
if (G_UNLIKELY (module == NULL))
module = g_module_open (NULL, 0);
if (g_module_symbol (module, name, (gpointer) &func))
{
CLUTTER_NOTE (SCRIPT, "Found '%s' alpha function in the symbols table",
name);
return func;
}
return NULL;
}
static void
clutter_alpha_set_custom_property (ClutterScriptable *scriptable,
ClutterScript *script,
const gchar *name,
const GValue *value)
{
if (strncmp (name, "function", 8) == 0)
{
g_assert (G_VALUE_HOLDS (value, G_TYPE_POINTER));
if (g_value_get_pointer (value) != NULL)
{
clutter_alpha_set_func (CLUTTER_ALPHA (scriptable),
g_value_get_pointer (value),
NULL, NULL);
}
}
else
g_object_set_property (G_OBJECT (scriptable), name, value);
}
static gboolean
clutter_alpha_parse_custom_node (ClutterScriptable *scriptable,
ClutterScript *script,
GValue *value,
const gchar *name,
JsonNode *node)
{
if (strncmp (name, "function", 8) == 0)
{
const gchar *func_name = json_node_get_string (node);
g_value_init (value, G_TYPE_POINTER);
g_value_set_pointer (value, resolve_alpha_func (func_name));
return TRUE;
}
/* we need to do this because we use gulong in place
* of ClutterAnimationMode for ClutterAlpha:mode
*/
if (strncmp (name, "mode", 4) == 0)
{
gulong mode;
mode = _clutter_script_resolve_animation_mode (node);
g_value_init (value, G_TYPE_ULONG);
g_value_set_ulong (value, mode);
return TRUE;
}
return FALSE;
}
static void
clutter_scriptable_iface_init (ClutterScriptableIface *iface)
{
iface->parse_custom_node = clutter_alpha_parse_custom_node;
iface->set_custom_property = clutter_alpha_set_custom_property;
}
static void
clutter_alpha_class_init (ClutterAlphaClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->set_property = clutter_alpha_set_property;
object_class->get_property = clutter_alpha_get_property;
object_class->finalize = clutter_alpha_finalize;
object_class->dispose = clutter_alpha_dispose;
/**
* ClutterAlpha:timeline:
*
* A #ClutterTimeline instance used to drive the alpha function.
*
* Since: 0.2
*
* Deprecated: 1.12
*/
obj_props[PROP_TIMELINE] =
g_param_spec_object ("timeline",
P_("Timeline"),
P_("Timeline used by the alpha"),
CLUTTER_TYPE_TIMELINE,
CLUTTER_PARAM_READWRITE);
/**
* ClutterAlpha:alpha:
*
* The alpha value as computed by the alpha function. The linear
* interval is 0.0 to 1.0, but the Alpha allows overshooting by
* one unit in each direction, so the valid interval is -1.0 to 2.0.
*
* Since: 0.2
* Deprecated: 1.12: Use #ClutterTimeline::new-frame and
* clutter_timeline_get_progress() instead
*/
obj_props[PROP_ALPHA] =
g_param_spec_double ("alpha",
P_("Alpha value"),
P_("Alpha value as computed by the alpha"),
-1.0, 2.0,
0.0,
CLUTTER_PARAM_READABLE);
/**
* ClutterAlpha:mode:
*
* The progress function logical id - a value from the
* #ClutterAnimationMode enumeration.
*
* If %CLUTTER_CUSTOM_MODE is used then the function set using
* clutter_alpha_set_closure() or clutter_alpha_set_func()
* will be used.
*
* Since: 1.0
* Deprecated: 1.12: Use #ClutterTimeline:progress-mode
*/
obj_props[PROP_MODE] =
g_param_spec_ulong ("mode",
P_("Mode"),
P_("Progress mode"),
0, G_MAXULONG,
CLUTTER_CUSTOM_MODE,
G_PARAM_CONSTRUCT | CLUTTER_PARAM_READWRITE);
g_object_class_install_properties (object_class,
PROP_LAST,
obj_props);
}
static void
clutter_alpha_init (ClutterAlpha *self)
{
self->priv = clutter_alpha_get_instance_private (self);
self->priv->mode = CLUTTER_CUSTOM_MODE;
self->priv->alpha = 0.0;
}
/**
* clutter_alpha_get_alpha:
* @alpha: A #ClutterAlpha
*
* Query the current alpha value.
*
* Return Value: The current alpha value for the alpha
*
* Since: 0.2
*
* Deprecated: 1.12: Use clutter_timeline_get_progress()
*/
gdouble
clutter_alpha_get_alpha (ClutterAlpha *alpha)
{
ClutterAlphaPrivate *priv;
gdouble retval = 0;
g_return_val_if_fail (CLUTTER_IS_ALPHA (alpha), 0);
priv = alpha->priv;
if (G_LIKELY (priv->func))
{
return priv->func (alpha, priv->user_data);
}
else if (priv->closure)
{
GValue params = G_VALUE_INIT;
GValue result_value = G_VALUE_INIT;
g_object_ref (alpha);
g_value_init (&result_value, G_TYPE_DOUBLE);
g_value_init (&params, CLUTTER_TYPE_ALPHA);
g_value_set_object (&params, alpha);
g_closure_invoke (priv->closure, &result_value, 1, &params, NULL);
retval = g_value_get_double (&result_value);
g_value_unset (&result_value);
g_value_unset (&params);
g_object_unref (alpha);
}
return retval;
}
/*
* clutter_alpha_set_closure_internal:
* @alpha: a #ClutterAlpha
* @closure: a #GClosure
*
* Sets the @closure for @alpha. This function does not
* set the #ClutterAlpha:mode property and does not emit
* the #GObject::notify signal for it.
*/
static inline void
clutter_alpha_set_closure_internal (ClutterAlpha *alpha,
GClosure *closure)
{
ClutterAlphaPrivate *priv = alpha->priv;
if (priv->notify != NULL)
priv->notify (priv->user_data);
else if (priv->closure != NULL)
g_closure_unref (priv->closure);
priv->func = NULL;
priv->user_data = NULL;
priv->notify = NULL;
if (closure == NULL)
return;
/* need to take ownership of the closure before sinking it */
priv->closure = g_closure_ref (closure);
g_closure_sink (closure);
/* set the marshaller */
if (G_CLOSURE_NEEDS_MARSHAL (closure))
{
GClosureMarshal marshal = _clutter_marshal_DOUBLE__VOID;
g_closure_set_marshal (priv->closure, marshal);
}
}
/**
* clutter_alpha_set_closure:
* @alpha: A #ClutterAlpha
* @closure: A #GClosure
*
* Sets the #GClosure used to compute the alpha value at each
* frame of the #ClutterTimeline bound to @alpha.
*
* Since: 0.8
*
* Deprecated: 1.12: Use clutter_timeline_set_progress_func()
*/
void
clutter_alpha_set_closure (ClutterAlpha *alpha,
GClosure *closure)
{
ClutterAlphaPrivate *priv;
g_return_if_fail (CLUTTER_IS_ALPHA (alpha));
g_return_if_fail (closure != NULL);
priv = alpha->priv;
clutter_alpha_set_closure_internal (alpha, closure);
priv->mode = CLUTTER_CUSTOM_MODE;
g_object_notify_by_pspec (G_OBJECT (alpha), obj_props[PROP_MODE]);
}
/**
* clutter_alpha_set_func:
* @alpha: A #ClutterAlpha
* @func: A #ClutterAlphaFunc
* @data: user data to be passed to the alpha function, or %NULL
* @destroy: notify function used when disposing the alpha function
*
* Sets the #ClutterAlphaFunc function used to compute
* the alpha value at each frame of the #ClutterTimeline
* bound to @alpha.
*
* This function will not register @func as a global alpha function.
*
* Since: 0.2
*
* Deprecated: 1.12: Use clutter_timeline_set_progress_func()
*/
void
clutter_alpha_set_func (ClutterAlpha *alpha,
ClutterAlphaFunc func,
gpointer data,
GDestroyNotify destroy)
{
ClutterAlphaPrivate *priv;
g_return_if_fail (CLUTTER_IS_ALPHA (alpha));
g_return_if_fail (func != NULL);
priv = alpha->priv;
if (priv->notify != NULL)
{
priv->notify (priv->user_data);
}
else if (priv->closure != NULL)
{
g_closure_unref (priv->closure);
priv->closure = NULL;
}
priv->func = func;
priv->user_data = data;
priv->notify = destroy;
priv->mode = CLUTTER_CUSTOM_MODE;
g_object_notify_by_pspec (G_OBJECT (alpha), obj_props[PROP_MODE]);
}
/**
* clutter_alpha_set_timeline:
* @alpha: A #ClutterAlpha
* @timeline: A #ClutterTimeline
*
* Binds @alpha to @timeline.
*
* Since: 0.2
*
* Deprecated: 1.12: Use #ClutterTimeline directly
*/
void
clutter_alpha_set_timeline (ClutterAlpha *alpha,
ClutterTimeline *timeline)
{
ClutterAlphaPrivate *priv;
g_return_if_fail (CLUTTER_IS_ALPHA (alpha));
g_return_if_fail (timeline == NULL || CLUTTER_IS_TIMELINE (timeline));
priv = alpha->priv;
if (priv->timeline == timeline)
return;
if (priv->timeline)
{
g_signal_handlers_disconnect_by_func (priv->timeline,
timeline_new_frame_cb,
alpha);
g_object_unref (priv->timeline);
priv->timeline = NULL;
}
if (timeline)
{
priv->timeline = g_object_ref (timeline);
g_signal_connect (priv->timeline, "new-frame",
G_CALLBACK (timeline_new_frame_cb),
alpha);
}
g_object_notify_by_pspec (G_OBJECT (alpha), obj_props[PROP_TIMELINE]);
}
/**
* clutter_alpha_get_timeline:
* @alpha: A #ClutterAlpha
*
* Gets the #ClutterTimeline bound to @alpha.
*
* Return value: (transfer none): a #ClutterTimeline instance
*
* Since: 0.2
*
* Deprecated: 1.12: Use #ClutterTimeline directlry
*/
ClutterTimeline *
clutter_alpha_get_timeline (ClutterAlpha *alpha)
{
g_return_val_if_fail (CLUTTER_IS_ALPHA (alpha), NULL);
return alpha->priv->timeline;
}
/**
* clutter_alpha_new:
*
* Creates a new #ClutterAlpha instance. You must set a function
* to compute the alpha value using clutter_alpha_set_func() and
* bind a #ClutterTimeline object to the #ClutterAlpha instance
* using clutter_alpha_set_timeline().
*
* Return value: the newly created empty #ClutterAlpha instance.
*
* Since: 0.2
*
* Deprecated: 1.12: Use #ClutterTimeline instead
*/
ClutterAlpha *
clutter_alpha_new (void)
{
return g_object_new (CLUTTER_TYPE_ALPHA, NULL);
}
/**
* clutter_alpha_new_full:
* @timeline: #ClutterTimeline timeline
* @mode: animation mode
*
* Creates a new #ClutterAlpha instance and sets the timeline
* and animation mode.
*
* See also clutter_alpha_set_timeline() and clutter_alpha_set_mode().
*
* Return Value: the newly created #ClutterAlpha
*
* Since: 1.0
*
* Deprecated: 1.12: Use #ClutterTimeline instead
*/
ClutterAlpha *
clutter_alpha_new_full (ClutterTimeline *timeline,
gulong mode)
{
g_return_val_if_fail (CLUTTER_IS_TIMELINE (timeline), NULL);
g_return_val_if_fail (mode != CLUTTER_ANIMATION_LAST, NULL);
return g_object_new (CLUTTER_TYPE_ALPHA,
"timeline", timeline,
"mode", mode,
NULL);
}
/**
* clutter_alpha_get_mode:
* @alpha: a #ClutterAlpha
*
* Retrieves the #ClutterAnimationMode used by @alpha.
*
* Return value: the animation mode
*
* Since: 1.0
*
* Deprecated: 1.12: Use #ClutterTimeline instead
*/
gulong
clutter_alpha_get_mode (ClutterAlpha *alpha)
{
g_return_val_if_fail (CLUTTER_IS_ALPHA (alpha), CLUTTER_CUSTOM_MODE);
return alpha->priv->mode;
}
typedef struct _AlphaData {
guint closure_set : 1;
ClutterAlphaFunc func;
gpointer data;
GClosure *closure;
} AlphaData;
static GPtrArray *clutter_alphas = NULL;
static gdouble
clutter_alpha_easing_func (ClutterAlpha *alpha,
gpointer data G_GNUC_UNUSED)
{
ClutterAlphaPrivate *priv = alpha->priv;
ClutterTimeline *timeline = priv->timeline;
gdouble t, d;
if (G_UNLIKELY (priv->timeline == NULL))
return 0.0;
t = clutter_timeline_get_elapsed_time (timeline);
d = clutter_timeline_get_duration (timeline);
return clutter_easing_for_mode (priv->mode, t, d);
}
/**
* clutter_alpha_set_mode:
* @alpha: a #ClutterAlpha
* @mode: a #ClutterAnimationMode
*
* Sets the progress function of @alpha using the symbolic value
* of @mode, as taken by the #ClutterAnimationMode enumeration.
*
* Since: 1.0
*
* Deprecated: 1.12: Use #ClutterTimeline and
* clutter_timeline_set_progress_mode() instead
*/
void
clutter_alpha_set_mode (ClutterAlpha *alpha,
gulong mode)
{
ClutterAlphaPrivate *priv;
g_return_if_fail (CLUTTER_IS_ALPHA (alpha));
g_return_if_fail (mode != CLUTTER_ANIMATION_LAST);
priv = alpha->priv;
if (mode == CLUTTER_CUSTOM_MODE)
{
priv->mode = mode;
}
else if (mode < CLUTTER_ANIMATION_LAST)
{
if (priv->mode == mode)
return;
/* sanity check to avoid getting an out of sync
* enum/function mapping
*/
g_assert (clutter_get_easing_func_for_mode (mode) != NULL);
clutter_alpha_set_closure_internal (alpha, NULL);
priv->mode = mode;
CLUTTER_NOTE (ANIMATION, "New easing mode '%s'[%lu]\n",
clutter_get_easing_name_for_mode (priv->mode),
priv->mode);
priv->func = clutter_alpha_easing_func;
priv->user_data = NULL;
priv->notify = NULL;
}
else if (mode > CLUTTER_ANIMATION_LAST)
{
AlphaData *alpha_data = NULL;
gulong real_index = 0;
if (priv->mode == mode)
return;
if (G_UNLIKELY (clutter_alphas == NULL))
{
g_warning ("No alpha functions defined for ClutterAlpha to use. ");
return;
}
real_index = mode - CLUTTER_ANIMATION_LAST - 1;
alpha_data = g_ptr_array_index (clutter_alphas, real_index);
if (G_UNLIKELY (alpha_data == NULL))
{
g_warning ("No alpha function registered for mode %lu.",
mode);
return;
}
if (alpha_data->closure_set)
clutter_alpha_set_closure (alpha, alpha_data->closure);
else
{
clutter_alpha_set_closure_internal (alpha, NULL);
priv->func = alpha_data->func;
priv->user_data = alpha_data->data;
priv->notify = NULL;
}
priv->mode = mode;
}
else
g_assert_not_reached ();
g_object_notify_by_pspec (G_OBJECT (alpha), obj_props[PROP_MODE]);
}

View File

@ -1,138 +0,0 @@
/*
* Clutter.
*
* An OpenGL based 'interactive canvas' library.
*
* Authored By Matthew Allum <mallum@openedhand.com>
* Jorn Baayen <jorn@openedhand.com>
* Emmanuele Bassi <ebassi@openedhand.com>
* Tomas Frydrych <tf@openedhand.com>
*
* Copyright (C) 2006, 2007, 2008 OpenedHand
* Copyright (C) 2009 Intel Corp.
*
* 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/>.
*/
#if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION)
#error "Only <clutter/clutter.h> can be included directly."
#endif
#ifndef __CLUTTER_ALPHA_H__
#define __CLUTTER_ALPHA_H__
#include <clutter/clutter-timeline.h>
#include <clutter/clutter-types.h>
G_BEGIN_DECLS
#define CLUTTER_TYPE_ALPHA (clutter_alpha_get_type ())
#define CLUTTER_ALPHA(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_ALPHA, ClutterAlpha))
#define CLUTTER_ALPHA_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_ALPHA, ClutterAlphaClass))
#define CLUTTER_IS_ALPHA(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_ALPHA))
#define CLUTTER_IS_ALPHA_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_ALPHA))
#define CLUTTER_ALPHA_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_ALPHA, ClutterAlphaClass))
typedef struct _ClutterAlphaClass ClutterAlphaClass;
typedef struct _ClutterAlphaPrivate ClutterAlphaPrivate;
/**
* ClutterAlphaFunc:
* @alpha: a #ClutterAlpha
* @user_data: user data passed to the function
*
* A function returning a value depending on the position of
* the #ClutterTimeline bound to @alpha.
*
* Return value: a floating point value
*
* Since: 0.2
*
* Deprecated: 1.12: Use #ClutterTimelineProgressFunc instead.
*/
typedef gdouble (*ClutterAlphaFunc) (ClutterAlpha *alpha,
gpointer user_data);
/**
* ClutterAlpha:
*
* #ClutterAlpha combines a #ClutterTimeline and a function.
* The contents of the #ClutterAlpha structure are private and should
* only be accessed using the provided API.
*
* Since: 0.2
*
* Deprecated: 1.12: Use #ClutterTimeline instead
*/
struct _ClutterAlpha
{
/*< private >*/
GInitiallyUnowned parent;
ClutterAlphaPrivate *priv;
};
/**
* ClutterAlphaClass:
*
* Base class for #ClutterAlpha
*
* Since: 0.2
*
* Deprecated: 1.12: Use #ClutterTimeline instead
*/
struct _ClutterAlphaClass
{
/*< private >*/
GInitiallyUnownedClass parent_class;
void (*_clutter_alpha_1) (void);
void (*_clutter_alpha_2) (void);
void (*_clutter_alpha_3) (void);
void (*_clutter_alpha_4) (void);
void (*_clutter_alpha_5) (void);
};
CLUTTER_DEPRECATED
GType clutter_alpha_get_type (void) G_GNUC_CONST;
CLUTTER_DEPRECATED
ClutterAlpha * clutter_alpha_new (void);
CLUTTER_DEPRECATED
ClutterAlpha * clutter_alpha_new_full (ClutterTimeline *timeline,
gulong mode);
CLUTTER_DEPRECATED
gdouble clutter_alpha_get_alpha (ClutterAlpha *alpha);
CLUTTER_DEPRECATED
void clutter_alpha_set_func (ClutterAlpha *alpha,
ClutterAlphaFunc func,
gpointer data,
GDestroyNotify destroy);
CLUTTER_DEPRECATED
void clutter_alpha_set_closure (ClutterAlpha *alpha,
GClosure *closure);
CLUTTER_DEPRECATED
void clutter_alpha_set_timeline (ClutterAlpha *alpha,
ClutterTimeline *timeline);
CLUTTER_DEPRECATED
ClutterTimeline *clutter_alpha_get_timeline (ClutterAlpha *alpha);
CLUTTER_DEPRECATED
void clutter_alpha_set_mode (ClutterAlpha *alpha,
gulong mode);
CLUTTER_DEPRECATED
gulong clutter_alpha_get_mode (ClutterAlpha *alpha);
G_END_DECLS
#endif /* __CLUTTER_ALPHA_H__ */

File diff suppressed because it is too large Load Diff

View File

@ -1,152 +0,0 @@
/*
* Clutter.
*
* An OpenGL based 'interactive canvas' library.
*
* Copyright (C) 2008 Intel Corporation.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
* Author:
* Emmanuele Bassi <ebassi@linux.intel.com>
*/
#if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION)
#error "Only <clutter/clutter.h> can be included directly."
#endif
#ifndef __CLUTTER_ANIMATION_H__
#define __CLUTTER_ANIMATION_H__
#include <clutter/clutter-types.h>
G_BEGIN_DECLS
#define CLUTTER_TYPE_ANIMATION (clutter_animation_get_type ())
#define CLUTTER_ANIMATION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_ANIMATION, ClutterAnimation))
#define CLUTTER_IS_ANIMATION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_ANIMATION))
#define CLUTTER_ANIMATION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_ANIMATION, ClutterAnimationClass))
#define CLUTTER_IS_ANIMATION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_ANIMATION))
#define CLUTTER_ANIMATION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_ANIMATION, ClutterAnimationClass))
typedef struct _ClutterAnimationPrivate ClutterAnimationPrivate;
typedef struct _ClutterAnimationClass ClutterAnimationClass;
/**
* ClutterAnimation:
*
* The #ClutterAnimation structure contains only private data and should
* be accessed using the provided functions.
*
* Since: 1.0
*
* Deprecated: 1.12: Use the implicit animation on #ClutterActor
*/
struct _ClutterAnimation
{
/*< private >*/
GObject parent_instance;
ClutterAnimationPrivate *priv;
};
/**
* ClutterAnimationClass:
* @started: class handler for the #ClutterAnimation::started signal
* @completed: class handler for the #ClutterAnimation::completed signal
*
* The #ClutterAnimationClass structure contains only private data and
* should be accessed using the provided functions.
*
* Since: 1.0
*
* Deprecated: 1.12: Use the implicit animation on #ClutterActor
*/
struct _ClutterAnimationClass
{
/*< private >*/
GObjectClass parent_class;
/*< public >*/
void (* started) (ClutterAnimation *animation);
void (* completed) (ClutterAnimation *animation);
/*< private >*/
/* padding for future expansion */
void (*_clutter_reserved1) (void);
void (*_clutter_reserved2) (void);
void (*_clutter_reserved3) (void);
void (*_clutter_reserved4) (void);
void (*_clutter_reserved5) (void);
void (*_clutter_reserved6) (void);
void (*_clutter_reserved7) (void);
void (*_clutter_reserved8) (void);
};
CLUTTER_DEPRECATED
GType clutter_animation_get_type (void) G_GNUC_CONST;
CLUTTER_DEPRECATED_FOR(clutter_property_transition_new)
ClutterAnimation * clutter_animation_new (void);
CLUTTER_DEPRECATED_FOR(clutter_transition_set_animatable)
void clutter_animation_set_object (ClutterAnimation *animation,
GObject *object);
CLUTTER_DEPRECATED_FOR(clutter_timeline_set_progress_mode)
void clutter_animation_set_mode (ClutterAnimation *animation,
gulong mode);
CLUTTER_DEPRECATED_FOR(clutter_timeline_get_progress_mode)
gulong clutter_animation_get_mode (ClutterAnimation *animation);
CLUTTER_DEPRECATED_FOR(clutter_timeline_set_duration)
void clutter_animation_set_duration (ClutterAnimation *animation,
guint msecs);
CLUTTER_DEPRECATED_FOR(clutter_timeline_get_duration)
guint clutter_animation_get_duration (ClutterAnimation *animation);
CLUTTER_DEPRECATED_FOR(clutter_timeline_set_repeat_count)
void clutter_animation_set_loop (ClutterAnimation *animation,
gboolean loop);
CLUTTER_DEPRECATED_FOR(clutter_timeline_get_repeat_count)
gboolean clutter_animation_get_loop (ClutterAnimation *animation);
CLUTTER_DEPRECATED
void clutter_animation_set_timeline (ClutterAnimation *animation,
ClutterTimeline *timeline);
CLUTTER_DEPRECATED
ClutterTimeline * clutter_animation_get_timeline (ClutterAnimation *animation);
CLUTTER_DEPRECATED
gboolean clutter_animation_has_property (ClutterAnimation *animation,
const gchar *property_name);
CLUTTER_DEPRECATED
ClutterInterval * clutter_animation_get_interval (ClutterAnimation *animation,
const gchar *property_name);
/*
* ClutterActor API
*/
CLUTTER_DEPRECATED
ClutterAnimation * clutter_actor_animate (ClutterActor *actor,
gulong mode,
guint duration,
const gchar *first_property_name,
...) G_GNUC_NULL_TERMINATED;
CLUTTER_DEPRECATED
ClutterAnimation * clutter_actor_animate_with_timeline (ClutterActor *actor,
gulong mode,
ClutterTimeline *timeline,
const gchar *first_property_name,
...) G_GNUC_NULL_TERMINATED;
G_END_DECLS
#endif /* __CLUTTER_ANIMATION_DEPRECATED_H__ */

View File

@ -333,21 +333,20 @@ clutter_group_real_get_preferred_height (ClutterActor *actor,
static void
clutter_group_real_allocate (ClutterActor *actor,
const ClutterActorBox *allocation,
ClutterAllocationFlags flags)
const ClutterActorBox *allocation)
{
ClutterGroupPrivate *priv = CLUTTER_GROUP (actor)->priv;
ClutterActorClass *klass;
klass = CLUTTER_ACTOR_CLASS (clutter_group_parent_class);
klass->allocate (actor, allocation, flags);
klass->allocate (actor, allocation);
if (priv->children == NULL)
return;
clutter_layout_manager_allocate (priv->layout,
CLUTTER_CONTAINER (actor),
allocation, flags);
allocation);
}
static void

File diff suppressed because it is too large Load Diff

View File

@ -1,147 +0,0 @@
/*
* Clutter.
*
* An OpenGL based 'interactive canvas' library.
*
* Authored By Øyvind Kolås <pippin@linux.intel.com>
*
* Copyright (C) 2009 Intel Corporation
*
* 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_STATE_H__
#define __CLUTTER_STATE_H__
#include <clutter/clutter-types.h>
G_BEGIN_DECLS
#define CLUTTER_TYPE_STATE_KEY (clutter_state_key_get_type ())
#define CLUTTER_TYPE_STATE (clutter_state_get_type ())
#define CLUTTER_STATE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_STATE, ClutterState))
#define CLUTTER_STATE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_STATE, ClutterStateClass))
#define CLUTTER_IS_STATE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_STATE))
#define CLUTTER_IS_STATE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_STATE))
#define CLUTTER_STATE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_STATE, ClutterStateClass))
typedef struct _ClutterStatePrivate ClutterStatePrivate;
typedef struct _ClutterStateClass ClutterStateClass;
/**
* ClutterStateKey:
*
* #ClutterStateKey is an opaque structure whose
* members cannot be accessed directly
*
* Since: 1.4
*/
typedef struct _ClutterStateKey ClutterStateKey;
/**
* ClutterState:
*
* The #ClutterState structure contains only
* private data and should be accessed using the provided API
*
* Since: 1.4
*/
struct _ClutterState
{
/*< private >*/
GObject parent;
ClutterStatePrivate *priv;
};
/**
* ClutterStateClass:
* @completed: class handler for the #ClutterState::completed signal
*
* The #ClutterStateClass structure contains
* only private data
*
* Since: 1.4
*
* Deprecated: 1.12
*/
struct _ClutterStateClass
{
/*< private >*/
GObjectClass parent_class;
/*< public >*/
void (* completed) (ClutterState *state);
/*< private >*/
/* padding for future expansion */
gpointer _padding_dummy[8];
};
CLUTTER_DEPRECATED
GType clutter_state_get_type (void) G_GNUC_CONST;
CLUTTER_DEPRECATED
ClutterState *clutter_state_new (void);
CLUTTER_DEPRECATED
ClutterTimeline * clutter_state_set_state (ClutterState *state,
const gchar *target_state_name);
CLUTTER_DEPRECATED
ClutterTimeline * clutter_state_warp_to_state (ClutterState *state,
const gchar *target_state_name);
CLUTTER_DEPRECATED
ClutterState * clutter_state_set_key (ClutterState *state,
const gchar *source_state_name,
const gchar *target_state_name,
GObject *object,
const gchar *property_name,
guint mode,
const GValue *value,
gdouble pre_delay,
gdouble post_delay);
CLUTTER_DEPRECATED
void clutter_state_set_duration (ClutterState *state,
const gchar *source_state_name,
const gchar *target_state_name,
guint duration);
CLUTTER_DEPRECATED
guint clutter_state_get_duration (ClutterState *state,
const gchar *source_state_name,
const gchar *target_state_name);
CLUTTER_DEPRECATED
void clutter_state_set (ClutterState *state,
const gchar *source_state_name,
const gchar *target_state_name,
gpointer first_object,
const gchar *first_property_name,
gulong first_mode,
...) G_GNUC_NULL_TERMINATED;
CLUTTER_DEPRECATED
GList * clutter_state_get_states (ClutterState *state);
CLUTTER_DEPRECATED
const gchar * clutter_state_get_state (ClutterState *state);
/*
* ClutterStateKey
*/
CLUTTER_DEPRECATED
GType clutter_state_key_get_type (void) G_GNUC_CONST;
CLUTTER_DEPRECATED
GType clutter_state_key_get_property_type (const ClutterStateKey *key);
G_END_DECLS
#endif /* __CLUTTER_STATE_H__ */

View File

@ -114,6 +114,7 @@ clutter_sources = [
'clutter-constraint.c',
'clutter-container.c',
'clutter-content.c',
'clutter-damage-history.c',
'clutter-deform-effect.c',
'clutter-desaturate-effect.c',
'clutter-effect.c',
@ -185,6 +186,7 @@ clutter_private_headers = [
'clutter-bezier.h',
'clutter-constraint-private.h',
'clutter-content-private.h',
'clutter-damage-history.h',
'clutter-debug.h',
'clutter-easing.h',
'clutter-effect-private.h',
@ -219,24 +221,18 @@ clutter_nonintrospected_sources = [
clutter_deprecated_headers = [
'deprecated/clutter-actor.h',
'deprecated/clutter-alpha.h',
'deprecated/clutter-animation.h',
'deprecated/clutter-box.h',
'deprecated/clutter-container.h',
'deprecated/clutter-group.h',
'deprecated/clutter-rectangle.h',
'deprecated/clutter-stage.h',
'deprecated/clutter-state.h',
'deprecated/clutter-timeline.h',
]
clutter_deprecated_sources = [
'deprecated/clutter-alpha.c',
'deprecated/clutter-animation.c',
'deprecated/clutter-box.c',
'deprecated/clutter-group.c',
'deprecated/clutter-rectangle.c',
'deprecated/clutter-state.c',
]
clutter_backend_sources = []

View File

@ -158,7 +158,7 @@ _cogl_blit_framebuffer_begin (CoglBlitData *data)
supported. */
if ((_cogl_texture_get_format (data->src_tex) & COGL_PREMULT_BIT) !=
(_cogl_texture_get_format (data->dst_tex) & COGL_PREMULT_BIT) ||
!_cogl_has_private_feature (ctx, COGL_PRIVATE_FEATURE_BLIT_FRAMEBUFFER))
!cogl_has_feature (ctx, COGL_FEATURE_ID_BLIT_FRAMEBUFFER))
return FALSE;
dst_offscreen = _cogl_offscreen_new_with_texture_full

View File

@ -193,6 +193,8 @@ cogl_is_context (void *object);
* expected to return age values other than 0.
* @COGL_FEATURE_ID_PRESENTATION_TIME: Whether frame presentation
* time stamps will be recorded in #CoglFrameInfo objects.
* @COGL_FEATURE_ID_BLIT_FRAMEBUFFER: Whether blitting using
* cogl_blit_framebuffer() is supported.
*
* All the capabilities that can vary between different GPUs supported
* by Cogl. Applications that depend on any of these features should explicitly
@ -211,6 +213,7 @@ typedef enum _CoglFeatureID
COGL_FEATURE_ID_TEXTURE_RG,
COGL_FEATURE_ID_BUFFER_AGE,
COGL_FEATURE_ID_TEXTURE_EGL_IMAGE_EXTERNAL,
COGL_FEATURE_ID_BLIT_FRAMEBUFFER,
/*< private >*/
_COGL_N_FEATURE_IDS /*< skip >*/

View File

@ -34,12 +34,22 @@
#include "cogl-dma-buf-handle.h"
#include "cogl-object.h"
#include <errno.h>
#include <gio/gio.h>
#include <linux/dma-buf.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <unistd.h>
struct _CoglDmaBufHandle
{
CoglFramebuffer *framebuffer;
int dmabuf_fd;
int width;
int height;
int stride;
int offset;
int bpp;
gpointer user_data;
GDestroyNotify destroy_func;
};
@ -47,6 +57,11 @@ struct _CoglDmaBufHandle
CoglDmaBufHandle *
cogl_dma_buf_handle_new (CoglFramebuffer *framebuffer,
int dmabuf_fd,
int width,
int height,
int stride,
int offset,
int bpp,
gpointer user_data,
GDestroyNotify destroy_func)
{
@ -61,6 +76,12 @@ cogl_dma_buf_handle_new (CoglFramebuffer *framebuffer,
dmabuf_handle->user_data = user_data;
dmabuf_handle->destroy_func = destroy_func;
dmabuf_handle->width = width;
dmabuf_handle->height = height;
dmabuf_handle->stride = stride;
dmabuf_handle->offset = offset;
dmabuf_handle->bpp = bpp;
return dmabuf_handle;
}
@ -80,6 +101,93 @@ cogl_dma_buf_handle_free (CoglDmaBufHandle *dmabuf_handle)
g_free (dmabuf_handle);
}
static gboolean
sync_read (CoglDmaBufHandle *dmabuf_handle,
uint64_t start_or_end,
GError **error)
{
struct dma_buf_sync sync = { 0 };
sync.flags = start_or_end | DMA_BUF_SYNC_READ;
while (TRUE)
{
int ret;
ret = ioctl (dmabuf_handle->dmabuf_fd, DMA_BUF_IOCTL_SYNC, &sync);
if (ret == -1 && errno == EINTR)
{
continue;
}
else if (ret == -1)
{
g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errno),
"ioctl: %s", g_strerror (errno));
return FALSE;
}
else
{
break;
}
}
return TRUE;
}
gboolean
cogl_dma_buf_handle_sync_read_start (CoglDmaBufHandle *dmabuf_handle,
GError **error)
{
return sync_read (dmabuf_handle, DMA_BUF_SYNC_START, error);
}
gboolean
cogl_dma_buf_handle_sync_read_end (CoglDmaBufHandle *dmabuf_handle,
GError **error)
{
return sync_read (dmabuf_handle, DMA_BUF_SYNC_END, error);
}
gpointer
cogl_dma_buf_handle_mmap (CoglDmaBufHandle *dmabuf_handle,
GError **error)
{
size_t size;
gpointer data;
size = dmabuf_handle->height * dmabuf_handle->stride;
data = mmap (NULL, size, PROT_READ, MAP_PRIVATE,
dmabuf_handle->dmabuf_fd,
dmabuf_handle->offset);
if (data == MAP_FAILED)
{
g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errno),
"mmap failed: %s", g_strerror (errno));
return NULL;
}
return data;
}
gboolean
cogl_dma_buf_handle_munmap (CoglDmaBufHandle *dmabuf_handle,
gpointer data,
GError **error)
{
size_t size;
size = dmabuf_handle->height * dmabuf_handle->stride;
if (munmap (data, size) != 0)
{
g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errno),
"munmap failed: %s", g_strerror (errno));
return FALSE;
}
return TRUE;
}
CoglFramebuffer *
cogl_dma_buf_handle_get_framebuffer (CoglDmaBufHandle *dmabuf_handle)
{
@ -92,3 +200,32 @@ cogl_dma_buf_handle_get_fd (CoglDmaBufHandle *dmabuf_handle)
return dmabuf_handle->dmabuf_fd;
}
int
cogl_dma_buf_handle_get_width (CoglDmaBufHandle *dmabuf_handle)
{
return dmabuf_handle->width;
}
int
cogl_dma_buf_handle_get_height (CoglDmaBufHandle *dmabuf_handle)
{
return dmabuf_handle->height;
}
int
cogl_dma_buf_handle_get_stride (CoglDmaBufHandle *dmabuf_handle)
{
return dmabuf_handle->stride;
}
int
cogl_dma_buf_handle_get_offset (CoglDmaBufHandle *dmabuf_handle)
{
return dmabuf_handle->offset;
}
int
cogl_dma_buf_handle_get_bpp (CoglDmaBufHandle *dmabuf_handle)
{
return dmabuf_handle->bpp;
}

View File

@ -46,7 +46,12 @@
COGL_EXPORT CoglDmaBufHandle *
cogl_dma_buf_handle_new (CoglFramebuffer *framebuffer,
int dmabuf_fd,
gpointer data,
int width,
int height,
int stride,
int offset,
int bpp,
gpointer user_data,
GDestroyNotify destroy_func);
/**
@ -58,6 +63,23 @@ cogl_dma_buf_handle_new (CoglFramebuffer *framebuffer,
COGL_EXPORT void
cogl_dma_buf_handle_free (CoglDmaBufHandle *dmabuf_handle);
COGL_EXPORT gboolean
cogl_dma_buf_handle_sync_read_start (CoglDmaBufHandle *dmabuf_handle,
GError **error);
COGL_EXPORT gboolean
cogl_dma_buf_handle_sync_read_end (CoglDmaBufHandle *dmabuf_handle,
GError **error);
COGL_EXPORT gpointer
cogl_dma_buf_handle_mmap (CoglDmaBufHandle *dmabuf_handle,
GError **error);
COGL_EXPORT gboolean
cogl_dma_buf_handle_munmap (CoglDmaBufHandle *dmabuf_handle,
gpointer data,
GError **error);
/**
* cogl_dma_buf_handle_get_framebuffer: (skip)
*
@ -79,5 +101,44 @@ cogl_dma_buf_handle_get_framebuffer (CoglDmaBufHandle *dmabuf_handle);
COGL_EXPORT int
cogl_dma_buf_handle_get_fd (CoglDmaBufHandle *dmabuf_handle);
/**
* cogl_dmabuf_handle_get_width: (skip)
*
* Returns: the buffer width
*/
COGL_EXPORT int
cogl_dma_buf_handle_get_width (CoglDmaBufHandle *dmabuf_handle);
/**
* cogl_dmabuf_handle_get_height: (skip)
*
* Returns: the buffer height
*/
COGL_EXPORT int
cogl_dma_buf_handle_get_height (CoglDmaBufHandle *dmabuf_handle);
/**
* cogl_dmabuf_handle_get_stride: (skip)
*
* Returns: the buffer stride
*/
COGL_EXPORT int
cogl_dma_buf_handle_get_stride (CoglDmaBufHandle *dmabuf_handle);
/**
* cogl_dmabuf_handle_get_offset: (skip)
*
* Returns: the buffer offset
*/
COGL_EXPORT int
cogl_dma_buf_handle_get_offset (CoglDmaBufHandle *dmabuf_handle);
/**
* cogl_dmabuf_handle_get_bpp: (skip)
*
* Returns: the number of bytes per pixel
*/
COGL_EXPORT int
cogl_dma_buf_handle_get_bpp (CoglDmaBufHandle *dmabuf_handle);
#endif /* __COGL_DMA_BUF_HANDLE_H__ */

View File

@ -1292,7 +1292,7 @@ cogl_blit_framebuffer (CoglFramebuffer *src,
int src_x1, src_y1, src_x2, src_y2;
int dst_x1, dst_y1, dst_x2, dst_y2;
if (!_cogl_has_private_feature (ctx, COGL_PRIVATE_FEATURE_BLIT_FRAMEBUFFER))
if (!cogl_has_feature (ctx, COGL_FEATURE_ID_BLIT_FRAMEBUFFER))
{
g_set_error_literal (error, COGL_SYSTEM_ERROR,
COGL_SYSTEM_ERROR_UNSUPPORTED,

View File

@ -1509,7 +1509,7 @@ cogl_is_framebuffer (void *object);
*
* This blits a region of the color buffer of the source buffer
* to the destination buffer. This function should only be
* called if the COGL_PRIVATE_FEATURE_BLIT_FRAMEBUFFER feature is
* called if the COGL_FEATURE_ID_BLIT_FRAMEBUFFER feature is
* advertised.
*
* The source and destination rectangles are defined in offscreen

View File

@ -1361,6 +1361,17 @@ cogl_pipeline_set_layer_filters (CoglPipeline *pipeline,
sampler_state);
}
void
cogl_pipeline_set_layer_max_mipmap_level (CoglPipeline *pipeline,
int layer,
int max_level)
{
CoglTexture *texture = cogl_pipeline_get_layer_texture (pipeline, layer);
if (texture != NULL)
cogl_texture_set_max_level (texture, max_level);
}
const CoglSamplerCacheEntry *
_cogl_pipeline_layer_get_sampler_state (CoglPipelineLayer *layer)
{

View File

@ -568,6 +568,11 @@ cogl_pipeline_add_layer_snippet (CoglPipeline *pipeline,
int layer,
CoglSnippet *snippet);
COGL_EXPORT void
cogl_pipeline_set_layer_max_mipmap_level (CoglPipeline *pipeline,
int layer,
int max_level);
G_END_DECLS
#endif /* __COGL_PIPELINE_LAYER_STATE_H__ */

View File

@ -42,7 +42,6 @@ typedef enum
{
COGL_PRIVATE_FEATURE_TEXTURE_2D_FROM_EGL_IMAGE,
COGL_PRIVATE_FEATURE_MESA_PACK_INVERT,
COGL_PRIVATE_FEATURE_BLIT_FRAMEBUFFER,
COGL_PRIVATE_FEATURE_PBOS,
COGL_PRIVATE_FEATURE_EXT_PACKED_DEPTH_STENCIL,
COGL_PRIVATE_FEATURE_OES_PACKED_DEPTH_STENCIL,

View File

@ -204,7 +204,8 @@ struct _CoglTexture
CoglContext *context;
CoglTextureLoader *loader;
GList *framebuffers;
int max_level;
int max_level_set;
int max_level_requested;
int width;
int height;
gboolean allocated;
@ -377,6 +378,10 @@ _cogl_texture_needs_premult_conversion (CoglPixelFormat src_format,
int
_cogl_texture_get_n_levels (CoglTexture *texture);
void
cogl_texture_set_max_level (CoglTexture *texture,
int max_level);
void
_cogl_texture_get_level_size (CoglTexture *texture,
int level,

View File

@ -115,7 +115,8 @@ _cogl_texture_init (CoglTexture *texture,
const CoglTextureVtable *vtable)
{
texture->context = context;
texture->max_level = 0;
texture->max_level_set = 0;
texture->max_level_requested = 1000; /* OpenGL default GL_TEXTURE_MAX_LEVEL */
texture->width = width;
texture->height = height;
texture->allocated = FALSE;
@ -229,8 +230,16 @@ _cogl_texture_get_n_levels (CoglTexture *texture)
int width = cogl_texture_get_width (texture);
int height = cogl_texture_get_height (texture);
int max_dimension = MAX (width, height);
int n_levels = _cogl_util_fls (max_dimension);
return _cogl_util_fls (max_dimension);
return MIN (n_levels, texture->max_level_requested + 1);
}
void
cogl_texture_set_max_level (CoglTexture *texture,
int max_level)
{
texture->max_level_requested = max_level;
}
void

View File

@ -388,8 +388,8 @@ _cogl_framebuffer_gl_flush_state (CoglFramebuffer *draw_buffer,
{
/* NB: Currently we only take advantage of binding separate
* read/write buffers for framebuffer blit purposes. */
g_return_if_fail (_cogl_has_private_feature
(ctx, COGL_PRIVATE_FEATURE_BLIT_FRAMEBUFFER));
g_return_if_fail (cogl_has_feature
(ctx, COGL_FEATURE_ID_BLIT_FRAMEBUFFER));
_cogl_framebuffer_gl_bind (draw_buffer, GL_DRAW_FRAMEBUFFER);
_cogl_framebuffer_gl_bind (read_buffer, GL_READ_FRAMEBUFFER);

View File

@ -567,6 +567,9 @@ _cogl_texture_2d_gl_copy_from_bitmap (CoglTexture2D *tex_2d,
&gl_format,
&gl_type);
if (tex->max_level_set < level)
cogl_texture_gl_set_max_level (tex, level);
status = ctx->texture_driver->upload_subregion_to_gl (ctx,
tex,
src_x, src_y,
@ -580,8 +583,6 @@ _cogl_texture_2d_gl_copy_from_bitmap (CoglTexture2D *tex_2d,
cogl_object_unref (upload_bmp);
_cogl_texture_gl_maybe_update_max_level (tex, level);
return status;
}

View File

@ -53,8 +53,8 @@ _cogl_texture_gl_flush_legacy_texobj_filters (CoglTexture *texture,
unsigned int mag_filter);
void
_cogl_texture_gl_maybe_update_max_level (CoglTexture *texture,
int max_level);
cogl_texture_gl_set_max_level (CoglTexture *texture,
int max_level);
void
_cogl_texture_gl_generate_mipmaps (CoglTexture *texture);

View File

@ -97,32 +97,36 @@ _cogl_texture_gl_flush_legacy_texobj_filters (CoglTexture *texture,
min_filter, mag_filter);
}
/* GL and GLES3 have this by default, but GLES2 does not except via extension.
* So really it's probably always available. Even if we used it and it wasn't
* available in some driver then there are no adverse consequences to the
* command simply being ignored...
*/
#ifndef GL_TEXTURE_MAX_LEVEL
#define GL_TEXTURE_MAX_LEVEL 0x813D
#endif
void
_cogl_texture_gl_maybe_update_max_level (CoglTexture *texture,
int max_level)
cogl_texture_gl_set_max_level (CoglTexture *texture,
int max_level)
{
/* This isn't supported on GLES */
#ifdef HAVE_COGL_GL
CoglContext *ctx = texture->context;
if (_cogl_has_private_feature (ctx, COGL_PRIVATE_FEATURE_TEXTURE_MAX_LEVEL) &&
texture->max_level < max_level)
if (_cogl_has_private_feature (ctx, COGL_PRIVATE_FEATURE_TEXTURE_MAX_LEVEL))
{
CoglContext *ctx = texture->context;
GLuint gl_handle;
GLenum gl_target;
cogl_texture_get_gl_texture (texture, &gl_handle, &gl_target);
texture->max_level = max_level;
texture->max_level_set = max_level;
_cogl_bind_gl_texture_transient (gl_target,
gl_handle);
GE( ctx, glTexParameteri (gl_target,
GL_TEXTURE_MAX_LEVEL, texture->max_level));
GL_TEXTURE_MAX_LEVEL, texture->max_level_set));
}
#endif /* HAVE_COGL_GL */
}
void
@ -133,7 +137,8 @@ _cogl_texture_gl_generate_mipmaps (CoglTexture *texture)
GLuint gl_handle;
GLenum gl_target;
_cogl_texture_gl_maybe_update_max_level (texture, n_levels - 1);
if (texture->max_level_set != n_levels - 1)
cogl_texture_gl_set_max_level (texture, n_levels - 1);
cogl_texture_get_gl_texture (texture, &gl_handle, &gl_target);

View File

@ -455,8 +455,8 @@ _cogl_driver_update_features (CoglContext *ctx,
TRUE);
if (ctx->glBlitFramebuffer)
COGL_FLAGS_SET (private_features,
COGL_PRIVATE_FEATURE_BLIT_FRAMEBUFFER, TRUE);
COGL_FLAGS_SET (ctx->features,
COGL_FEATURE_ID_BLIT_FRAMEBUFFER, TRUE);
COGL_FLAGS_SET (private_features, COGL_PRIVATE_FEATURE_PBOS, TRUE);

View File

@ -255,7 +255,7 @@ _cogl_texture_driver_upload_subregion_to_gl (CoglContext *ctx,
* glTexImage2D first to assert that the storage for this
* level exists.
*/
if (texture->max_level < level)
if (texture->max_level_set < level)
{
ctx->glTexImage2D (gl_target,
level,

View File

@ -318,8 +318,8 @@ _cogl_driver_update_features (CoglContext *context,
COGL_FLAGS_SET (private_features, COGL_PRIVATE_FEATURE_SAMPLER_OBJECTS, TRUE);
if (context->glBlitFramebuffer)
COGL_FLAGS_SET (private_features,
COGL_PRIVATE_FEATURE_BLIT_FRAMEBUFFER, TRUE);
COGL_FLAGS_SET (context->features,
COGL_FEATURE_ID_BLIT_FRAMEBUFFER, TRUE);
if (_cogl_check_extension ("GL_OES_element_index_uint", gl_extensions))
{

View File

@ -303,7 +303,7 @@ _cogl_texture_driver_upload_subregion_to_gl (CoglContext *ctx,
* glTexImage2D first to assert that the storage for this
* level exists.
*/
if (texture->max_level < level)
if (texture->max_level_set < level)
{
ctx->glTexImage2D (gl_target,
level,

View File

@ -17,6 +17,7 @@ cogl_config_h = configure_file(
cogl_pkg_deps = [
glib_dep,
gio_dep,
gobject_dep,
graphene_dep,
]

View File

@ -1,5 +1,7 @@
#!/usr/bin/env bash
set -o pipefail
if test -z "$G_DEBUG"; then
G_DEBUG=fatal-warnings
else
@ -69,7 +71,12 @@ get_status()
run_test()
{
$("$TEST_BINARY" "$1" &> "$LOG")
if [ -n "${VERBOSE-}" ]; then
echo "running $TEST_BINARY $1:"
$TEST_BINARY $1 2>&1 | tee "$LOG"
else
$($TEST_BINARY $1 &> "$LOG")
fi
TMP=$?
var_name=$2_result
eval "$var_name=$TMP"

View File

@ -487,6 +487,7 @@ output = [
' Cogl tests............... ' + have_cogl_tests.to_string(),
' Clutter tests............ ' + have_clutter_tests.to_string(),
' Installed tests.......... ' + have_installed_tests.to_string(),
' Coverage................. ' + get_option('b_coverage').to_string(),
'',
' Now type \'ninja -C ' + meson.build_root() + '\' to build ' + meson.project_name(),
'',

View File

@ -108,6 +108,14 @@ struct _MetaBackendClass
void meta_init_backend (GType backend_gtype);
#ifdef HAVE_WAYLAND
MetaWaylandCompositor * meta_backend_get_wayland_compositor (MetaBackend *backend);
void meta_backend_init_wayland_display (MetaBackend *backend);
void meta_backend_init_wayland (MetaBackend *backend);
#endif
ClutterBackend * meta_backend_get_clutter_backend (MetaBackend *backend);
MetaIdleMonitor * meta_backend_get_idle_monitor (MetaBackend *backend,

View File

@ -54,4 +54,6 @@ typedef struct _MetaScreenCast MetaScreenCast;
typedef struct _MetaScreenCastSession MetaScreenCastSession;
typedef struct _MetaScreenCastStream MetaScreenCastStream;
typedef struct _MetaWaylandCompositor MetaWaylandCompositor;
#endif /* META_BACKEND_TYPE_H */

View File

@ -81,6 +81,10 @@
#include "backends/native/meta-backend-native.h"
#endif
#ifdef HAVE_WAYLAND
#include "wayland/meta-wayland.h"
#endif
enum
{
KEYMAP_CHANGED,
@ -130,6 +134,10 @@ struct _MetaBackendPrivate
MetaRemoteDesktop *remote_desktop;
#endif
#ifdef HAVE_WAYLAND
MetaWaylandCompositor *wayland_compositor;
#endif
#ifdef HAVE_PROFILER
MetaProfiler *profiler;
#endif
@ -864,6 +872,120 @@ system_bus_gotten_cb (GObject *object,
NULL);
}
#ifdef HAVE_WAYLAND
MetaWaylandCompositor *
meta_backend_get_wayland_compositor (MetaBackend *backend)
{
MetaBackendPrivate *priv = meta_backend_get_instance_private (backend);
return priv->wayland_compositor;
}
void
meta_backend_init_wayland_display (MetaBackend *backend)
{
MetaBackendPrivate *priv = meta_backend_get_instance_private (backend);
priv->wayland_compositor = meta_wayland_compositor_new (backend);
}
void
meta_backend_init_wayland (MetaBackend *backend)
{
MetaBackendPrivate *priv = meta_backend_get_instance_private (backend);
meta_wayland_compositor_setup (priv->wayland_compositor);
}
#endif
/* Mutter is responsible for pulling events off the X queue, so Clutter
* doesn't need (and shouldn't) run its normal event source which polls
* the X fd, but we do have to deal with dispatching events that accumulate
* in the clutter queue. This happens, for example, when clutter generate
* enter/leave events on mouse motion - several events are queued in the
* clutter queue but only one dispatched. It could also happen because of
* explicit calls to clutter_event_put(). We add a very simple custom
* event loop source which is simply responsible for pulling events off
* of the queue and dispatching them before we block for new events.
*/
static gboolean
clutter_source_prepare (GSource *source,
int *timeout)
{
*timeout = -1;
return clutter_events_pending ();
}
static gboolean
clutter_source_check (GSource *source)
{
return clutter_events_pending ();
}
static gboolean
clutter_source_dispatch (GSource *source,
GSourceFunc callback,
gpointer user_data)
{
ClutterEvent *event = clutter_event_get ();
if (event)
{
clutter_do_event (event);
clutter_event_free (event);
}
return TRUE;
}
static GSourceFuncs clutter_source_funcs = {
clutter_source_prepare,
clutter_source_check,
clutter_source_dispatch
};
static ClutterBackend *
meta_get_clutter_backend (void)
{
MetaBackend *backend = meta_get_backend ();
return meta_backend_get_clutter_backend (backend);
}
static gboolean
init_clutter (MetaBackend *backend,
GError **error)
{
GSource *source;
clutter_set_custom_backend_func (meta_get_clutter_backend);
if (clutter_init (NULL, NULL) != CLUTTER_INIT_SUCCESS)
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"Unable to initialize Clutter");
return FALSE;
}
source = g_source_new (&clutter_source_funcs, sizeof (GSource));
g_source_attach (source, NULL);
g_source_unref (source);
return TRUE;
}
static void
meta_backend_post_init (MetaBackend *backend)
{
MetaBackendPrivate *priv = meta_backend_get_instance_private (backend);
META_BACKEND_GET_CLASS (backend)->post_init (backend);
meta_settings_post_init (priv->settings);
}
static gboolean
meta_backend_initable_init (GInitable *initable,
GCancellable *cancellable,
@ -902,6 +1024,11 @@ meta_backend_initable_init (GInitable *initable,
priv->profiler = meta_profiler_new ();
#endif
if (!init_clutter (backend, error))
return FALSE;
meta_backend_post_init (backend);
return TRUE;
}
@ -917,16 +1044,6 @@ meta_backend_init (MetaBackend *backend)
_backend = backend;
}
static void
meta_backend_post_init (MetaBackend *backend)
{
MetaBackendPrivate *priv = meta_backend_get_instance_private (backend);
META_BACKEND_GET_CLASS (backend)->post_init (backend);
meta_settings_post_init (priv->settings);
}
/**
* meta_backend_get_idle_monitor: (skip)
*/
@ -1258,54 +1375,6 @@ meta_backend_set_client_pointer_constraint (MetaBackend *backend,
priv->client_pointer_constraint = g_object_ref (constraint);
}
/* Mutter is responsible for pulling events off the X queue, so Clutter
* doesn't need (and shouldn't) run its normal event source which polls
* the X fd, but we do have to deal with dispatching events that accumulate
* in the clutter queue. This happens, for example, when clutter generate
* enter/leave events on mouse motion - several events are queued in the
* clutter queue but only one dispatched. It could also happen because of
* explicit calls to clutter_event_put(). We add a very simple custom
* event loop source which is simply responsible for pulling events off
* of the queue and dispatching them before we block for new events.
*/
static gboolean
event_prepare (GSource *source,
gint *timeout_)
{
*timeout_ = -1;
return clutter_events_pending ();
}
static gboolean
event_check (GSource *source)
{
return clutter_events_pending ();
}
static gboolean
event_dispatch (GSource *source,
GSourceFunc callback,
gpointer user_data)
{
ClutterEvent *event = clutter_event_get ();
if (event)
{
clutter_do_event (event);
clutter_event_free (event);
}
return TRUE;
}
static GSourceFuncs event_funcs = {
event_prepare,
event_check,
event_dispatch
};
ClutterBackend *
meta_backend_get_clutter_backend (MetaBackend *backend)
{
@ -1320,14 +1389,6 @@ meta_backend_get_clutter_backend (MetaBackend *backend)
return priv->clutter_backend;
}
static ClutterBackend *
meta_get_clutter_backend (void)
{
MetaBackend *backend = meta_get_backend ();
return meta_backend_get_clutter_backend (backend);
}
void
meta_init_backend (GType backend_gtype)
{
@ -1344,29 +1405,6 @@ meta_init_backend (GType backend_gtype)
}
}
/**
* meta_clutter_init: (skip)
*/
void
meta_clutter_init (void)
{
GSource *source;
clutter_set_custom_backend_func (meta_get_clutter_backend);
if (clutter_init (NULL, NULL) != CLUTTER_INIT_SUCCESS)
{
g_warning ("Unable to initialize Clutter.\n");
exit (1);
}
source = g_source_new (&event_funcs, sizeof (GSource));
g_source_attach (source, NULL);
g_source_unref (source);
meta_backend_post_init (_backend);
}
/**
* meta_is_stage_views_enabled:
*

View File

@ -84,6 +84,7 @@ translate_meta_cursor (MetaCursor cursor)
return "crosshair";
case META_CURSOR_IBEAM:
return "xterm";
case META_CURSOR_BLANK:
case META_CURSOR_NONE:
case META_CURSOR_LAST:
break;
@ -93,6 +94,48 @@ translate_meta_cursor (MetaCursor cursor)
return NULL;
}
static Cursor
create_blank_cursor (Display *xdisplay)
{
Pixmap pixmap;
XColor color;
Cursor cursor;
XGCValues gc_values;
GC gc;
pixmap = XCreatePixmap (xdisplay, DefaultRootWindow (xdisplay), 1, 1, 1);
gc_values.foreground = BlackPixel (xdisplay, DefaultScreen (xdisplay));
gc = XCreateGC (xdisplay, pixmap, GCForeground, &gc_values);
XFillRectangle (xdisplay, pixmap, gc, 0, 0, 1, 1);
color.pixel = 0;
color.red = color.blue = color.green = 0;
cursor = XCreatePixmapCursor (xdisplay, pixmap, pixmap, &color, &color, 1, 1);
XFreeGC (xdisplay, gc);
XFreePixmap (xdisplay, pixmap);
return cursor;
}
static XcursorImages *
create_blank_cursor_images (void)
{
XcursorImages *images;
images = XcursorImagesCreate (1);
images->images[0] = XcursorImageCreate (1, 1);
images->images[0]->xhot = 0;
images->images[0]->yhot = 0;
memset (images->images[0]->pixels, 0, sizeof(int32_t));
return images;
}
MetaCursor
meta_cursor_sprite_xcursor_get_cursor (MetaCursorSpriteXcursor *sprite_xcursor)
{
@ -103,12 +146,18 @@ Cursor
meta_create_x_cursor (Display *xdisplay,
MetaCursor cursor)
{
if (cursor == META_CURSOR_BLANK)
return create_blank_cursor (xdisplay);
return XcursorLibraryLoadCursor (xdisplay, translate_meta_cursor (cursor));
}
static XcursorImages *
load_cursor_on_client (MetaCursor cursor, int scale)
{
if (cursor == META_CURSOR_BLANK)
return create_blank_cursor_images ();
return XcursorLibraryLoadImages (translate_meta_cursor (cursor),
meta_prefs_get_cursor_theme (),
meta_prefs_get_cursor_size () * scale);

View File

@ -54,8 +54,8 @@ meta_input_device_init (MetaInputDevice *input_device)
static void
meta_input_device_constructed (GObject *object)
{
MetaInputDevice *input_device = META_INPUT_DEVICE (object);
#ifdef HAVE_LIBWACOM
MetaInputDevice *input_device;
WacomDeviceDatabase *wacom_db;
MetaInputDevicePrivate *priv;
const char *node;
@ -64,6 +64,7 @@ meta_input_device_constructed (GObject *object)
G_OBJECT_CLASS (meta_input_device_parent_class)->constructed (object);
#ifdef HAVE_LIBWACOM
input_device = META_INPUT_DEVICE (object);
priv = meta_input_device_get_instance_private (input_device);
wacom_db = meta_backend_get_wacom_database (meta_get_backend ());
node = clutter_input_device_get_device_node (CLUTTER_INPUT_DEVICE (input_device));

View File

@ -90,6 +90,7 @@ float meta_logical_monitor_get_scale (MetaLogicalMonitor *logical_monitor);
MetaMonitorTransform meta_logical_monitor_get_transform (MetaLogicalMonitor *logical_monitor);
META_EXPORT_TEST
MetaRectangle meta_logical_monitor_get_layout (MetaLogicalMonitor *logical_monitor);
META_EXPORT_TEST

View File

@ -49,9 +49,10 @@ meta_monitor_transform_is_rotated (MetaMonitorTransform transform)
static inline gboolean
meta_monitor_transform_is_flipped (MetaMonitorTransform transform)
{
return (abs(transform) >= META_MONITOR_TRANSFORM_FLIPPED);
return (transform >= META_MONITOR_TRANSFORM_FLIPPED);
}
META_EXPORT_TEST
MetaMonitorTransform meta_monitor_transform_invert (MetaMonitorTransform transform);
META_EXPORT_TEST

View File

@ -35,6 +35,12 @@ meta_output_get_gpu (MetaOutput *output)
return output->gpu;
}
const char *
meta_output_get_name (MetaOutput *output)
{
return output->name;
}
void
meta_output_assign_crtc (MetaOutput *output,
MetaCrtc *crtc)

View File

@ -122,6 +122,8 @@ META_EXPORT_TEST G_DECLARE_FINAL_TYPE (MetaOutput, meta_output, META, OUTPUT, GO
META_EXPORT_TEST
MetaGpu * meta_output_get_gpu (MetaOutput *output);
const char * meta_output_get_name (MetaOutput *output);
META_EXPORT_TEST
void meta_output_assign_crtc (MetaOutput *output,
MetaCrtc *crtc);

View File

@ -55,6 +55,7 @@ struct _MetaRemoteDesktopSession
MetaScreenCastSession *screen_cast_session;
gulong screen_cast_session_closed_handler_id;
guint started : 1;
ClutterVirtualInputDevice *virtual_pointer;
ClutterVirtualInputDevice *virtual_keyboard;
@ -119,7 +120,7 @@ meta_remote_desktop_session_start (MetaRemoteDesktopSession *session,
ClutterBackend *backend = clutter_get_default_backend ();
ClutterSeat *seat = clutter_backend_get_default_seat (backend);
g_assert (!session->virtual_pointer && !session->virtual_keyboard);
g_assert (!session->started);
if (session->screen_cast_session)
{
@ -135,6 +136,7 @@ meta_remote_desktop_session_start (MetaRemoteDesktopSession *session,
clutter_seat_create_virtual_device (seat, CLUTTER_TOUCHSCREEN_DEVICE);
init_remote_access_handle (session);
session->started = TRUE;
return TRUE;
}
@ -145,6 +147,8 @@ meta_remote_desktop_session_close (MetaRemoteDesktopSession *session)
MetaDBusRemoteDesktopSession *skeleton =
META_DBUS_REMOTE_DESKTOP_SESSION (session);
session->started = FALSE;
if (session->screen_cast_session)
{
g_clear_signal_handler (&session->screen_cast_session_closed_handler_id,
@ -249,6 +253,37 @@ check_permission (MetaRemoteDesktopSession *session,
g_dbus_method_invocation_get_sender (invocation)) == 0;
}
static gboolean
meta_remote_desktop_session_check_can_notify (MetaRemoteDesktopSession *session,
GDBusMethodInvocation *invocation)
{
if (!session->started)
{
g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
G_DBUS_ERROR_FAILED,
"Session not started");
return FALSE;
}
if (!check_permission (session, invocation))
{
g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
G_DBUS_ERROR_ACCESS_DENIED,
"Permission denied");
return FALSE;
}
if (!session->screen_cast_session)
{
g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
G_DBUS_ERROR_FAILED,
"No screen cast active");
return FALSE;
}
return TRUE;
}
static gboolean
handle_start (MetaDBusRemoteDesktopSession *skeleton,
GDBusMethodInvocation *invocation)
@ -256,6 +291,14 @@ handle_start (MetaDBusRemoteDesktopSession *skeleton,
MetaRemoteDesktopSession *session = META_REMOTE_DESKTOP_SESSION (skeleton);
GError *error = NULL;
if (session->started)
{
g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
G_DBUS_ERROR_FAILED,
"Already started");
return TRUE;
}
if (!check_permission (session, invocation))
{
g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
@ -288,6 +331,14 @@ handle_stop (MetaDBusRemoteDesktopSession *skeleton,
{
MetaRemoteDesktopSession *session = META_REMOTE_DESKTOP_SESSION (skeleton);
if (!session->started)
{
g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
G_DBUS_ERROR_FAILED,
"Session not started");
return TRUE;
}
if (!check_permission (session, invocation))
{
g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
@ -312,13 +363,8 @@ handle_notify_keyboard_keycode (MetaDBusRemoteDesktopSession *skeleton,
MetaRemoteDesktopSession *session = META_REMOTE_DESKTOP_SESSION (skeleton);
ClutterKeyState state;
if (!check_permission (session, invocation))
{
g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
G_DBUS_ERROR_ACCESS_DENIED,
"Permission denied");
return TRUE;
}
if (!meta_remote_desktop_session_check_can_notify (session, invocation))
return TRUE;
if (pressed)
state = CLUTTER_KEY_STATE_PRESSED;
@ -344,13 +390,8 @@ handle_notify_keyboard_keysym (MetaDBusRemoteDesktopSession *skeleton,
MetaRemoteDesktopSession *session = META_REMOTE_DESKTOP_SESSION (skeleton);
ClutterKeyState state;
if (!check_permission (session, invocation))
{
g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
G_DBUS_ERROR_ACCESS_DENIED,
"Permission denied");
return TRUE;
}
if (!meta_remote_desktop_session_check_can_notify (session, invocation))
return TRUE;
if (pressed)
state = CLUTTER_KEY_STATE_PRESSED;
@ -398,13 +439,8 @@ handle_notify_pointer_button (MetaDBusRemoteDesktopSession *skeleton,
uint32_t button;
ClutterButtonState state;
if (!check_permission (session, invocation))
{
g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
G_DBUS_ERROR_ACCESS_DENIED,
"Permission denied");
return TRUE;
}
if (!meta_remote_desktop_session_check_can_notify (session, invocation))
return TRUE;
button = translate_to_clutter_button (button_code);
@ -434,13 +470,8 @@ handle_notify_pointer_axis (MetaDBusRemoteDesktopSession *skeleton,
MetaRemoteDesktopSession *session = META_REMOTE_DESKTOP_SESSION (skeleton);
ClutterScrollFinishFlags finish_flags = CLUTTER_SCROLL_FINISHED_NONE;
if (!check_permission (session, invocation))
{
g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
G_DBUS_ERROR_ACCESS_DENIED,
"Permission denied");
return TRUE;
}
if (!meta_remote_desktop_session_check_can_notify (session, invocation))
return TRUE;
if (flags & META_REMOTE_DESKTOP_NOTIFY_AXIS_FLAGS_FINISH)
{
@ -487,13 +518,8 @@ handle_notify_pointer_axis_discrete (MetaDBusRemoteDesktopSession *skeleton,
ClutterScrollDirection direction;
int step_count;
if (!check_permission (session, invocation))
{
g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
G_DBUS_ERROR_ACCESS_DENIED,
"Permission denied");
return TRUE;
}
if (!meta_remote_desktop_session_check_can_notify (session, invocation))
return TRUE;
if (axis > 1)
{
@ -538,13 +564,8 @@ handle_notify_pointer_motion_relative (MetaDBusRemoteDesktopSession *skeleton,
{
MetaRemoteDesktopSession *session = META_REMOTE_DESKTOP_SESSION (skeleton);
if (!check_permission (session, invocation))
{
g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
G_DBUS_ERROR_ACCESS_DENIED,
"Permission denied");
return TRUE;
}
if (!meta_remote_desktop_session_check_can_notify (session, invocation))
return TRUE;
clutter_virtual_input_device_notify_relative_motion (session->virtual_pointer,
CLUTTER_CURRENT_TIME,
@ -567,21 +588,8 @@ handle_notify_pointer_motion_absolute (MetaDBusRemoteDesktopSession *skeleton,
MetaScreenCastStream *stream;
double abs_x, abs_y;
if (!check_permission (session, invocation))
{
g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
G_DBUS_ERROR_ACCESS_DENIED,
"Permission denied");
return TRUE;
}
if (!session->screen_cast_session)
{
g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
G_DBUS_ERROR_FAILED,
"No screen cast active");
return TRUE;
}
if (!meta_remote_desktop_session_check_can_notify (session, invocation))
return TRUE;
stream = meta_screen_cast_session_get_stream (session->screen_cast_session,
stream_path);
@ -617,21 +625,8 @@ handle_notify_touch_down (MetaDBusRemoteDesktopSession *skeleton,
MetaScreenCastStream *stream;
double abs_x, abs_y;
if (!check_permission (session, invocation))
{
g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
G_DBUS_ERROR_ACCESS_DENIED,
"Permission denied");
return TRUE;
}
if (!session->screen_cast_session)
{
g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
G_DBUS_ERROR_FAILED,
"No screen cast active");
return TRUE;
}
if (!meta_remote_desktop_session_check_can_notify (session, invocation))
return TRUE;
stream = meta_screen_cast_session_get_stream (session->screen_cast_session,
stream_path);
@ -668,21 +663,8 @@ handle_notify_touch_motion (MetaDBusRemoteDesktopSession *skeleton,
MetaScreenCastStream *stream;
double abs_x, abs_y;
if (!check_permission (session, invocation))
{
g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
G_DBUS_ERROR_ACCESS_DENIED,
"Permission denied");
return TRUE;
}
if (!session->screen_cast_session)
{
g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
G_DBUS_ERROR_FAILED,
"No screen cast active");
return TRUE;
}
if (!meta_remote_desktop_session_check_can_notify (session, invocation))
return TRUE;
stream = meta_screen_cast_session_get_stream (session->screen_cast_session,
stream_path);
@ -714,13 +696,8 @@ handle_notify_touch_up (MetaDBusRemoteDesktopSession *skeleton,
{
MetaRemoteDesktopSession *session = META_REMOTE_DESKTOP_SESSION (skeleton);
if (!check_permission (session, invocation))
{
g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
G_DBUS_ERROR_ACCESS_DENIED,
"Permission denied");
return TRUE;
}
if (!meta_remote_desktop_session_check_can_notify (session, invocation))
return TRUE;
clutter_virtual_input_device_notify_touch_up (session->virtual_touchscreen,
CLUTTER_CURRENT_TIME,

View File

@ -34,6 +34,7 @@
#include "backends/meta-renderer.h"
#include "clutter/clutter-mutter.h"
#include "compositor/region-utils.h"
enum
{
@ -117,6 +118,25 @@ meta_renderer_view_setup_offscreen_blit_pipeline (ClutterStageView *view,
cogl_pipeline_set_layer_matrix (pipeline, 0, &matrix);
}
static void
meta_renderer_view_transform_rect_to_onscreen (ClutterStageView *view,
const cairo_rectangle_int_t *src_rect,
int dst_width,
int dst_height,
cairo_rectangle_int_t *dst_rect)
{
MetaRendererView *renderer_view = META_RENDERER_VIEW (view);
MetaMonitorTransform inverted_transform;
inverted_transform =
meta_monitor_transform_invert (renderer_view->transform);
return meta_rectangle_transform (src_rect,
inverted_transform,
dst_width,
dst_height,
dst_rect);
}
static void
meta_renderer_view_set_transform (MetaRendererView *view,
MetaMonitorTransform transform)
@ -181,6 +201,8 @@ meta_renderer_view_class_init (MetaRendererViewClass *klass)
meta_renderer_view_setup_offscreen_blit_pipeline;
view_class->get_offscreen_transformation_matrix =
meta_renderer_view_get_offscreen_transformation_matrix;
view_class->transform_rect_to_onscreen =
meta_renderer_view_transform_rect_to_onscreen;
object_class->get_property = meta_renderer_view_get_property;
object_class->set_property = meta_renderer_view_set_property;

View File

@ -160,14 +160,12 @@ meta_renderer_real_rebuild_views (MetaRenderer *renderer)
}
void
meta_renderer_set_legacy_view (MetaRenderer *renderer,
MetaRendererView *legacy_view)
meta_renderer_add_view (MetaRenderer *renderer,
MetaRendererView *view)
{
MetaRendererPrivate *priv = meta_renderer_get_instance_private (renderer);
g_assert (!priv->views);
priv->views = g_list_append (priv->views, legacy_view);
priv->views = g_list_append (priv->views, view);
}
/**

View File

@ -54,8 +54,8 @@ CoglRenderer * meta_renderer_create_cogl_renderer (MetaRenderer *renderer);
void meta_renderer_rebuild_views (MetaRenderer *renderer);
void meta_renderer_set_legacy_view (MetaRenderer *renderer,
MetaRendererView *legacy_view);
void meta_renderer_add_view (MetaRenderer *renderer,
MetaRendererView *view);
META_EXPORT_TEST
GList * meta_renderer_get_views (MetaRenderer *renderer);

View File

@ -68,6 +68,7 @@ typedef struct _MetaPipeWireSource
{
GSource base;
MetaScreenCastStreamSrc *src;
struct pw_loop *pipewire_loop;
} MetaPipeWireSource;
@ -81,6 +82,7 @@ typedef struct _MetaScreenCastStreamSrcPrivate
struct spa_hook pipewire_core_listener;
gboolean is_enabled;
gboolean emit_closed_after_dispatch;
struct pw_stream *pipewire_stream;
struct spa_hook pipewire_stream_listener;
@ -445,7 +447,8 @@ meta_screen_cast_stream_src_maybe_record_frame (MetaScreenCastStreamSrc *src)
uint64_t now_us;
now_us = g_get_monotonic_time ();
if (priv->last_frame_timestamp_us != 0 &&
if (priv->video_format.max_framerate.num > 0 &&
priv->last_frame_timestamp_us != 0 &&
(now_us - priv->last_frame_timestamp_us <
((1000000 * priv->video_format.max_framerate.denom) /
priv->video_format.max_framerate.num)))
@ -539,12 +542,6 @@ meta_screen_cast_stream_src_disable (MetaScreenCastStreamSrc *src)
priv->is_enabled = FALSE;
}
static void
meta_screen_cast_stream_src_notify_closed (MetaScreenCastStreamSrc *src)
{
g_signal_emit (src, signals[CLOSED], 0);
}
static void
on_stream_state_changed (void *data,
enum pw_stream_state old,
@ -559,7 +556,9 @@ on_stream_state_changed (void *data,
{
case PW_STREAM_STATE_ERROR:
g_warning ("pipewire stream error: %s", error_message);
meta_screen_cast_stream_src_notify_closed (src);
if (meta_screen_cast_stream_src_is_enabled (src))
meta_screen_cast_stream_src_disable (src);
priv->emit_closed_after_dispatch = TRUE;
break;
case PW_STREAM_STATE_PAUSED:
if (priv->node_id == SPA_ID_INVALID && priv->pipewire_stream)
@ -827,11 +826,17 @@ on_core_error (void *data,
const char *message)
{
MetaScreenCastStreamSrc *src = data;
MetaScreenCastStreamSrcPrivate *priv =
meta_screen_cast_stream_src_get_instance_private (src);
g_warning ("pipewire remote error: id:%u %s", id, message);
if (id == PW_ID_CORE && res == -EPIPE)
meta_screen_cast_stream_src_notify_closed (src);
{
if (meta_screen_cast_stream_src_is_enabled (src))
meta_screen_cast_stream_src_disable (src);
priv->emit_closed_after_dispatch = TRUE;
}
}
static gboolean
@ -848,12 +853,18 @@ pipewire_loop_source_dispatch (GSource *source,
gpointer user_data)
{
MetaPipeWireSource *pipewire_source = (MetaPipeWireSource *) source;
MetaScreenCastStreamSrc *src = pipewire_source->src;
MetaScreenCastStreamSrcPrivate *priv =
meta_screen_cast_stream_src_get_instance_private (src);
int result;
result = pw_loop_iterate (pipewire_source->pipewire_loop, 0);
if (result < 0)
g_warning ("pipewire_loop_iterate failed: %s", spa_strerror (result));
if (priv->emit_closed_after_dispatch)
g_signal_emit (src, signals[CLOSED], 0);
return TRUE;
}
@ -875,13 +886,14 @@ static GSourceFuncs pipewire_source_funcs =
};
static MetaPipeWireSource *
create_pipewire_source (void)
create_pipewire_source (MetaScreenCastStreamSrc *src)
{
MetaPipeWireSource *pipewire_source;
pipewire_source =
(MetaPipeWireSource *) g_source_new (&pipewire_source_funcs,
sizeof (MetaPipeWireSource));
pipewire_source->src = src;
pipewire_source->pipewire_loop = pw_loop_new (NULL);
if (!pipewire_source->pipewire_loop)
{
@ -913,7 +925,7 @@ meta_screen_cast_stream_src_initable_init (GInitable *initable,
MetaScreenCastStreamSrcPrivate *priv =
meta_screen_cast_stream_src_get_instance_private (src);
priv->pipewire_source = create_pipewire_source ();
priv->pipewire_source = create_pipewire_source (src);
if (!priv->pipewire_source)
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,

View File

@ -366,6 +366,10 @@ meta_backend_native_post_init (MetaBackend *backend)
if (retval != 0)
g_warning ("Failed to set RT scheduler: %m");
}
#ifdef HAVE_WAYLAND
meta_backend_init_wayland (backend);
#endif
}
static MetaMonitorManager *
@ -647,6 +651,10 @@ meta_backend_native_initable_init (GInitable *initable,
if (!native->launcher)
return FALSE;
#ifdef HAVE_WAYLAND
meta_backend_init_wayland_display (META_BACKEND (native));
#endif
native->udev = meta_udev_new (native);
native->barrier_manager = meta_barrier_manager_native_new ();

View File

@ -2169,6 +2169,9 @@ meta_renderer_native_create_dma_buf (CoglRenderer *cogl_renderer,
{
CoglFramebuffer *dmabuf_fb;
struct gbm_bo *new_bo;
int stride;
int offset;
int bpp;
int dmabuf_fd = -1;
new_bo = gbm_bo_create (renderer_gpu_data->gbm.device,
@ -2192,11 +2195,14 @@ meta_renderer_native_create_dma_buf (CoglRenderer *cogl_renderer,
return NULL;
}
stride = gbm_bo_get_stride (new_bo);
offset = gbm_bo_get_offset (new_bo, 0);
bpp = 4;
dmabuf_fb = create_dma_buf_framebuffer (renderer_native,
dmabuf_fd,
width, height,
gbm_bo_get_stride (new_bo),
gbm_bo_get_offset (new_bo, 0),
stride,
offset,
DRM_FORMAT_MOD_LINEAR,
DRM_FORMAT_XRGB8888,
error);
@ -2204,7 +2210,9 @@ meta_renderer_native_create_dma_buf (CoglRenderer *cogl_renderer,
if (!dmabuf_fb)
return NULL;
return cogl_dma_buf_handle_new (dmabuf_fb, dmabuf_fd, new_bo,
return cogl_dma_buf_handle_new (dmabuf_fb, dmabuf_fd,
width, height, stride, offset, bpp,
new_bo,
(GDestroyNotify) gbm_bo_destroy);
}
break;
@ -3097,12 +3105,17 @@ should_force_shadow_fb (MetaRendererNative *renderer_native,
MetaGpuKms *primary_gpu)
{
MetaRenderer *renderer = META_RENDERER (renderer_native);
CoglContext *cogl_context =
cogl_context_from_renderer_native (renderer_native);
int kms_fd;
uint64_t prefer_shadow = 0;
if (meta_renderer_is_hardware_accelerated (renderer))
return FALSE;
if (!cogl_has_feature (cogl_context, COGL_FEATURE_ID_BLIT_FRAMEBUFFER))
return FALSE;
kms_fd = meta_gpu_kms_get_fd (primary_gpu);
if (drmGetCap (kms_fd, DRM_CAP_DUMB_PREFER_SHADOW, &prefer_shadow) == 0)
{
@ -3142,7 +3155,7 @@ meta_renderer_native_create_view (MetaRenderer *renderer,
MetaMonitorTransform view_transform;
CoglOnscreen *onscreen = NULL;
CoglOffscreen *offscreen = NULL;
CoglOffscreen *shadowfb = NULL;
gboolean use_shadowfb;
float scale;
int onscreen_width;
int onscreen_height;
@ -3194,24 +3207,8 @@ meta_renderer_native_create_view (MetaRenderer *renderer,
g_error ("Failed to allocate back buffer texture: %s", error->message);
}
if (should_force_shadow_fb (renderer_native,
renderer_native->primary_gpu_kms))
{
int shadow_width;
int shadow_height;
/* The shadowfb must be the same size as the on-screen framebuffer */
shadow_width = cogl_framebuffer_get_width (COGL_FRAMEBUFFER (onscreen));
shadow_height = cogl_framebuffer_get_height (COGL_FRAMEBUFFER (onscreen));
shadowfb = meta_renderer_native_create_offscreen (renderer_native,
cogl_context,
shadow_width,
shadow_height,
&error);
if (!shadowfb)
g_error ("Failed to allocate shadow buffer texture: %s", error->message);
}
use_shadowfb = should_force_shadow_fb (renderer_native,
renderer_native->primary_gpu_kms);
if (meta_is_stage_views_scaled ())
scale = meta_logical_monitor_get_scale (logical_monitor);
@ -3222,15 +3219,15 @@ meta_renderer_native_create_view (MetaRenderer *renderer,
META_ROUNDING_STRATEGY_ROUND,
&view_layout);
view = g_object_new (META_TYPE_RENDERER_VIEW,
"name", meta_output_get_name (output),
"layout", &view_layout,
"scale", scale,
"framebuffer", onscreen,
"offscreen", offscreen,
"shadowfb", shadowfb,
"use-shadowfb", use_shadowfb,
"transform", view_transform,
NULL);
g_clear_pointer (&offscreen, cogl_object_unref);
g_clear_pointer (&shadowfb, cogl_object_unref);
meta_onscreen_native_set_view (onscreen, view);

View File

@ -148,6 +148,13 @@ meta_udev_list_drm_devices (MetaUdev *udev,
l = l_next;
}
if (!devices)
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"No DRM devices found");
return NULL;
}
return devices;
}

View File

@ -129,20 +129,25 @@ release_pressed_buttons (ClutterVirtualInputDevice *virtual_device)
switch (get_button_type (code))
{
case EVDEV_BUTTON_TYPE_KEY:
clutter_virtual_input_device_notify_key (virtual_device,
time_us,
code,
CLUTTER_KEY_STATE_RELEASED);
meta_seat_native_notify_key (virtual_evdev->seat,
virtual_evdev->device,
time_us,
code,
CLUTTER_KEY_STATE_RELEASED,
TRUE);
break;
case EVDEV_BUTTON_TYPE_BUTTON:
clutter_virtual_input_device_notify_button (virtual_device,
time_us,
code,
CLUTTER_BUTTON_STATE_RELEASED);
meta_seat_native_notify_button (virtual_evdev->seat,
virtual_evdev->device,
time_us,
code,
CLUTTER_BUTTON_STATE_RELEASED);
break;
case EVDEV_BUTTON_TYPE_NONE:
g_assert_not_reached ();
}
update_button_count (virtual_evdev, code, 0);
}
}

View File

@ -24,14 +24,76 @@
#include "backends/x11/cm/meta-renderer-x11-cm.h"
#include "backends/meta-renderer-view.h"
struct _MetaRendererX11Cm
{
MetaRendererX11 parent;
MetaRendererView *screen_view;
};
G_DEFINE_TYPE (MetaRendererX11Cm, meta_renderer_x11_cm,
META_TYPE_RENDERER_X11)
void
meta_renderer_x11_cm_ensure_screen_view (MetaRendererX11Cm *renderer_x11_cm,
int width,
int height)
{
cairo_rectangle_int_t view_layout;
if (renderer_x11_cm->screen_view)
return;
view_layout = (cairo_rectangle_int_t) {
.width = width,
.height = height,
};
renderer_x11_cm->screen_view = g_object_new (META_TYPE_RENDERER_VIEW,
"name", "X11 screen",
"layout", &view_layout,
NULL);
meta_renderer_add_view (META_RENDERER (renderer_x11_cm),
renderer_x11_cm->screen_view);
}
void
meta_renderer_x11_cm_resize (MetaRendererX11Cm *renderer_x11_cm,
int width,
int height)
{
cairo_rectangle_int_t view_layout;
view_layout = (cairo_rectangle_int_t) {
.width = width,
.height = height,
};
g_object_set (G_OBJECT (renderer_x11_cm->screen_view),
"layout", &view_layout,
NULL);
}
void
meta_renderer_x11_cm_set_onscreen (MetaRendererX11Cm *renderer_x11_cm,
CoglOnscreen *onscreen)
{
g_object_set (G_OBJECT (renderer_x11_cm->screen_view),
"framebuffer", onscreen,
NULL);
}
static void
meta_renderer_x11_cm_rebuild_views (MetaRenderer *renderer)
{
MetaRendererX11Cm *renderer_x11_cm = META_RENDERER_X11_CM (renderer);
g_return_if_fail (!meta_renderer_get_views (renderer));
meta_renderer_add_view (renderer, renderer_x11_cm->screen_view);
}
static void
meta_renderer_x11_cm_init (MetaRendererX11Cm *renderer_x11_cm)
{
@ -40,4 +102,7 @@ meta_renderer_x11_cm_init (MetaRendererX11Cm *renderer_x11_cm)
static void
meta_renderer_x11_cm_class_init (MetaRendererX11CmClass *klass)
{
MetaRendererClass *renderer_class = META_RENDERER_CLASS (klass);
renderer_class->rebuild_views = meta_renderer_x11_cm_rebuild_views;
}

View File

@ -30,4 +30,15 @@ G_DECLARE_FINAL_TYPE (MetaRendererX11Cm, meta_renderer_x11_cm,
META, RENDERER_X11_CM,
MetaRendererX11)
void meta_renderer_x11_cm_ensure_screen_view (MetaRendererX11Cm *renderer_x11_cm,
int width,
int height);
void meta_renderer_x11_cm_resize (MetaRendererX11Cm *renderer_x11_cm,
int width,
int height);
void meta_renderer_x11_cm_set_onscreen (MetaRendererX11Cm *renderer_x11_cm,
CoglOnscreen *onscreen);
#endif /* META_RENDERER_X11_CM_H */

View File

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

View File

@ -26,15 +26,17 @@
#include <unistd.h>
#endif
#include "backends/x11/cm/meta-backend-x11-cm.h"
#include "backends/x11/cm/meta-renderer-x11-cm.h"
#include "backends/x11/meta-backend-x11.h"
#include "backends/x11/meta-seat-x11.h"
#include "backends/x11/meta-stage-x11.h"
#include "clutter/clutter-mutter.h"
#include "clutter/x11/clutter-x11.h"
#include "clutter/x11/clutter-backend-x11.h"
#include "cogl/cogl.h"
#include "core/display-private.h"
#include "meta/meta-x11-errors.h"
#include "meta-backend-x11.h"
#include "meta-seat-x11.h"
#include "meta-stage-x11.h"
#define STAGE_X11_IS_MAPPED(s) ((((MetaStageX11 *) (s))->wm_state & STAGE_X11_WITHDRAWN) == 0)
@ -254,8 +256,6 @@ meta_stage_x11_unrealize (ClutterStageWindow *stage_window)
clutter_stage_window_parent_iface->unrealize (stage_window);
g_list_free (stage_x11->legacy_views);
g_clear_object (&stage_x11->legacy_view);
g_clear_pointer (&stage_x11->onscreen, cogl_object_unref);
}
@ -297,10 +297,13 @@ meta_stage_x11_realize (ClutterStageWindow *stage_window)
stage_cogl,
NULL);
if (stage_x11->legacy_view)
g_object_set (G_OBJECT (stage_x11->legacy_view),
"framebuffer", stage_x11->onscreen,
NULL);
if (META_IS_BACKEND_X11_CM (stage_x11->backend))
{
MetaRenderer *renderer = meta_backend_get_renderer (stage_x11->backend);
MetaRendererX11Cm *renderer_x11_cm = META_RENDERER_X11_CM (renderer);
meta_renderer_x11_cm_set_onscreen (renderer_x11_cm, stage_x11->onscreen);
}
/* We just created a window of the size of the actor. No need to fix
the size of the stage, just update it. */
@ -468,34 +471,13 @@ meta_stage_x11_can_clip_redraws (ClutterStageWindow *stage_window)
return stage_x11->clipped_redraws_cool_off == 0;
}
static void
ensure_legacy_view (ClutterStageWindow *stage_window)
{
MetaStageX11 *stage_x11 = META_STAGE_X11 (stage_window);
cairo_rectangle_int_t view_layout;
CoglFramebuffer *framebuffer;
if (stage_x11->legacy_view)
return;
_clutter_stage_window_get_geometry (stage_window, &view_layout);
framebuffer = COGL_FRAMEBUFFER (stage_x11->onscreen);
stage_x11->legacy_view = g_object_new (CLUTTER_TYPE_STAGE_VIEW_COGL,
"layout", &view_layout,
"framebuffer", framebuffer,
NULL);
stage_x11->legacy_views = g_list_append (stage_x11->legacy_views,
stage_x11->legacy_view);
}
static GList *
meta_stage_x11_get_views (ClutterStageWindow *stage_window)
{
MetaStageX11 *stage_x11 = META_STAGE_X11 (stage_window);
MetaRenderer *renderer = meta_backend_get_renderer (stage_x11->backend);
ensure_legacy_view (stage_window);
return stage_x11->legacy_views;
return meta_renderer_get_views (renderer);
}
static int64_t
@ -527,6 +509,9 @@ meta_stage_x11_class_init (MetaStageX11Class *klass)
static void
meta_stage_x11_init (MetaStageX11 *stage)
{
MetaRenderer *renderer;
MetaRendererX11Cm *renderer_x11_cm;
stage->xwin = None;
stage->xwin_width = 640;
stage->xwin_height = 480;
@ -534,6 +519,19 @@ meta_stage_x11_init (MetaStageX11 *stage)
stage->wm_state = STAGE_X11_WITHDRAWN;
stage->title = NULL;
stage->backend = meta_get_backend ();
g_assert (stage->backend);
if (META_IS_BACKEND_X11_CM (stage->backend))
{
renderer = meta_backend_get_renderer (stage->backend);
renderer_x11_cm = META_RENDERER_X11_CM (renderer);
meta_renderer_x11_cm_ensure_screen_view (renderer_x11_cm,
stage->xwin_width,
stage->xwin_height);
}
}
static void
@ -719,16 +717,16 @@ meta_stage_x11_translate_event (MetaStageX11 *stage_x11,
* X11 compositing manager, we need to reset the legacy
* stage view, now that it has a new size.
*/
if (stage_x11->legacy_view)
if (META_IS_BACKEND_X11_CM (stage_x11->backend))
{
cairo_rectangle_int_t view_layout = {
.width = stage_width,
.height = stage_height
};
MetaBackend *backend = stage_x11->backend;
MetaRenderer *renderer = meta_backend_get_renderer (backend);
MetaRendererX11Cm *renderer_x11_cm =
META_RENDERER_X11_CM (renderer);
g_object_set (G_OBJECT (stage_x11->legacy_view),
"layout", &view_layout,
NULL);
meta_renderer_x11_cm_resize (renderer_x11_cm,
stage_width,
stage_height);
}
}
}

View File

@ -25,6 +25,7 @@
#include <X11/Xlib.h>
#include <X11/Xatom.h>
#include "backends/meta-backend-private.h"
#include "clutter/clutter-mutter.h"
#include "clutter/x11/clutter-x11.h"
@ -51,14 +52,13 @@ struct _MetaStageX11
{
ClutterStageCogl parent_instance;
MetaBackend *backend;
CoglOnscreen *onscreen;
Window xwin;
gint xwin_width;
gint xwin_height; /* FIXME target_width / height */
ClutterStageView *legacy_view;
GList *legacy_views;
CoglFrameClosure *frame_closure;
gchar *title;

View File

@ -33,8 +33,16 @@ typedef struct _MetaBackendX11NestedPrivate
MetaGpu *gpu;
} MetaBackendX11NestedPrivate;
G_DEFINE_TYPE_WITH_PRIVATE (MetaBackendX11Nested, meta_backend_x11_nested,
META_TYPE_BACKEND_X11)
static GInitableIface *initable_parent_iface;
static void
initable_iface_init (GInitableIface *initable_iface);
G_DEFINE_TYPE_WITH_CODE (MetaBackendX11Nested, meta_backend_x11_nested,
META_TYPE_BACKEND_X11,
G_ADD_PRIVATE (MetaBackendX11Nested)
G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE,
initable_iface_init));
static MetaRenderer *
meta_backend_x11_nested_create_renderer (MetaBackend *backend,
@ -201,6 +209,39 @@ meta_backend_x11_nested_real_init_gpus (MetaBackendX11Nested *backend_x11_nested
meta_backend_add_gpu (META_BACKEND (backend_x11_nested), priv->gpu);
}
static void
meta_backend_x11_nested_post_init (MetaBackend *backend)
{
MetaBackendClass *backend_class =
META_BACKEND_CLASS (meta_backend_x11_nested_parent_class);
backend_class->post_init (backend);
#ifdef HAVE_WAYLAND
meta_backend_init_wayland (backend);
#endif
}
static gboolean
meta_backend_x11_nested_initable_init (GInitable *initable,
GCancellable *cancellable,
GError **error)
{
#ifdef HAVE_WAYLAND
meta_backend_init_wayland_display (META_BACKEND (initable));
#endif
return initable_parent_iface->init (initable, cancellable, error);
}
static void
initable_iface_init (GInitableIface *initable_iface)
{
initable_parent_iface = g_type_interface_peek_parent (initable_iface);
initable_iface->init = meta_backend_x11_nested_initable_init;
}
static void
meta_backend_x11_nested_constructed (GObject *object)
{
@ -229,6 +270,7 @@ meta_backend_x11_nested_class_init (MetaBackendX11NestedClass *klass)
object_class->constructed = meta_backend_x11_nested_constructed;
backend_class->post_init = meta_backend_x11_nested_post_init;
backend_class->create_renderer = meta_backend_x11_nested_create_renderer;
backend_class->create_monitor_manager = meta_backend_x11_nested_create_monitor_manager;
backend_class->create_cursor_renderer = meta_backend_x11_nested_create_cursor_renderer;

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