Compare commits

..

226 Commits

Author SHA1 Message Date
Simon McVittie
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
Jonas Dreßler
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
Jonas Ådahl
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
Jonas Ådahl
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
Jonas Ådahl
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
Jonas Ådahl
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
Jonas Ådahl
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
Jonas Ådahl
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
Jonas Dreßler
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
Jonas Ådahl
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
Jonas Ådahl
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
Jonas Ådahl
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
Jonas Ådahl
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
Jonas Ådahl
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
Jonas Ådahl
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
Jonas Ådahl
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
Jonas Ådahl
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
Jonas Ådahl
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
Jonas Ådahl
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
Jonas Ådahl
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
Jonas Ådahl
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
Jonas Ådahl
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
Jonas Ådahl
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
Jonas Ådahl
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
Jonas Ådahl
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
Jonas Ådahl
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
Jonas Ådahl
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
Jonas Ådahl
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
Jonas Ådahl
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
Jonas Ådahl
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
Jonas Dreßler
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
Jonas Dreßler
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
Jonas Dreßler
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
Jonas Dreßler
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
Jonas Dreßler
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
Jonas Ådahl
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
Florian Müllner
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
Jonas Dreßler
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
Jonas Dreßler
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
Jonas Ådahl
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
Jonas Ådahl
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
Jonas Ådahl
dfed5f6a11 stage-x11: Clean up include macros
https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1251
2020-05-22 00:15:48 +00:00
Jonas Ådahl
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
Jonas Ådahl
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
Jonas Ådahl
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
Jonas Ådahl
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
Jonas Dreßler
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
Jonas Dreßler
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
Jonas Dreßler
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
Jonas Dreßler
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
Jonas Dreßler
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
Jonas Dreßler
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
Florian Müllner
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
Florian Müllner
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
Florian Müllner
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
Florian Müllner
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
Jonas Dreßler
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
Jonas Dreßler
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
Jonas Dreßler
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
Jonas Dreßler
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
Jonas Dreßler
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
Jonas Dreßler
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
Jonas Dreßler
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
Jonas Dreßler
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
Jonas Dreßler
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
Jonas Dreßler
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
Carlos Garnacho
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
Carlos Garnacho
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
Jonas Dreßler
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
Daniel van Vugt
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
Robert Mader
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
Carlos Garnacho
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
Carlos Garnacho
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
Carlos Garnacho
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
Carlos Garnacho
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
Carlos Garnacho
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
Jonas Dreßler
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
Jonas Dreßler
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
Jonas Dreßler
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
Jonas Dreßler
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
Jonas Dreßler
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
Jonas Dreßler
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
Jonas Dreßler
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
Jonas Dreßler
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
Jonas Dreßler
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
Jonas Dreßler
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
Jonas Dreßler
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
Robert Mader
819f9afa31 shaped-texture: Fix typo in documentation
https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1252
2020-05-13 12:12:01 +02:00
Daniel van Vugt
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
Daniel van Vugt
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
Daniel van Vugt
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
Daniel van Vugt
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
Daniel van Vugt
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
Daniel van Vugt
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
Jonas Dreßler
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
Jonas Dreßler
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
Jonas Dreßler
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
Jonas Dreßler
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
Jonas Dreßler
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
Jonas Dreßler
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
Robert Mader
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
Niels De Graef
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
Jonas Dreßler
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
Jonas Dreßler
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
Jonas Dreßler
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
Akatsuki
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
Ting-Wei Lan
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
Robert Mader
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
Daniel van Vugt
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
Corentin Noël
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
Jonas Ådahl
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
Jonas Ådahl
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
Jonas Ådahl
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
Jonas Ådahl
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
Jonas Ådahl
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
Jonas Ådahl
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
Jonas Ådahl
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
Jonas Ådahl
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
Jonas Ådahl
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
Jonas Ådahl
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
Jonas Ådahl
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
Jonas Ådahl
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
Jonas Ådahl
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
Jonas Ådahl
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
Jonas Ådahl
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
Jonas Ådahl
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
Jonas Ådahl
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
Jonas Ådahl
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
Marco Trevisan (Treviño)
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
Marco Trevisan (Treviño)
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
Marco Trevisan (Treviño)
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
Marco Trevisan (Treviño)
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
Jonas Ådahl
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
Jonas Ådahl
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
Jonas Ådahl
da5be1fdea clutter/animatable: Remove left-over vfunc
https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1192
2020-05-07 20:04:07 +00:00
Jonas Ådahl
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
Jonas Ådahl
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
Jonas Ådahl
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
Jonas Ådahl
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
Jonas Ådahl
a55a286b15 clutter: Remove deprecated 'ClutterState'
https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1192
2020-05-07 20:04:07 +00:00
Ting-Wei Lan
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
Carlos Garnacho
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
Olivier Fourdan
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
Jonas Dreßler
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
Sergey Zigachev
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
Christian Rauch
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
Florian Müllner
5dfd86ebe7 Bump version to 3.37.1
Update NEWS.
2020-04-29 18:47:11 +02:00
Jonas Ådahl
9e41f687a0 remote-access-controller: Make it build with -Dremote_desktop=false
It'll be all no-ops, which is fine, since there is nothing to
inhibit/uninhibit.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1223
2020-04-28 22:00:11 +02:00
Olivier Fourdan
61356caa06 keybindings: Mask out the reserved modifiers mask
When switching layouts, special modifiers bits may be be set for
internal use by Xkb.

As we now ignore a set of modifiers when processing the special
modifiers keys, we ought to also mask out those reserved modifiers
otherwise we would discard the [Super] key after switching layouts
in X11.

Closes: https://gitlab.gnome.org/GNOME/mutter/issues/1144
https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1219
2020-04-27 15:51:47 +00:00
Jonas Ådahl
4300f1f91d remote-access-controller: Allow inhibiting remote access
Inhibiting remote access means any current remote access session is
terminated, and no new ones can be created, until remote access is
uninhibited. The inhibitation is ref counted, meaning there can be more
than one inhibitor.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1212
2020-04-27 14:31:06 +00:00
Laurent Bigonville
d26dc4ae44 compositor: Only include meta-window-actor-wayland.h when building with wayland
https://gitlab.gnome.org/GNOME/mutter/-/issues/1074
2020-04-27 13:28:28 +00:00
Olivier Fourdan
bd45a00fa3 window-actor/x11: Cache the frame bounds
When resizing an X11 window with client side decorations, the shadow is
clipped by the frame bounds so that we don't need to paint the shadow
under the opaque areas covered by the window and its frame.

When the X11 client uses the EMWH synchronization mechanism (like all
gtk-3 based clients), the actual window may not be updated so that the
actual window and it frame may be behind the expected window frame
bounds, which gives the impression of de-synchronized shadows.

To avoid the issue, keep a copy of the frame bounds as a cache and only
update it when the client is not frozen so that the clipping occurs on
the actual content.

Closes: https://gitlab.gnome.org/GNOME/mutter/issues/1178
https://gitlab.gnome.org/GNOME/mutter/merge_requests/1214
2020-04-27 13:04:38 +02:00
Jonas Dreßler
793a9d45e1 clutter/stage-cogl: Fix painting the redraw clip with the damage region
The redraw clip that's painted together with the damage region has to be
copied earlier than we do right now. That's because if
PAINT_DAMAGE_REGION is enabled, buffer age is disabled and thus
use_clipped_redraw is FALSE. That means the redraw_clip is updated and
set to the full view-rect. If we copy the queued_redraw_clip after that,
it's also going to be set to the full view-rect. So copy the redraw clip
a bit earlier to make sure we're actually passing the real redraw clip
to paint_damage_region().

Also keep the queued_redraw_clip around a bit longer so it can actually
be used by paint_damage_region() and isn't freed before that.

While at it, move paint_damage_region() from swap_framebuffer() into
clutter_stage_cogl_redraw_view() so we don't have to pass things to
swap_framebuffer() only for debugging.

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

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1208
2020-04-25 16:42:30 +02:00
Christian Kirbach
43295bdcc4 Update German translation
(cherry picked from commit bfe9b333c0)
2020-04-24 22:38:04 +00:00
Florian Müllner
43e12dab7b backend: Remove support for META_DUMMY_MONITORS variable
Forcing a dummy monitor manager is unexpected and has been broken
since commit 315a6f43d.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1213
2020-04-23 21:31:46 +02:00
Jonas Ådahl
c4535fdf85 screen-cast: Add RecordArea for screen cast arbitrary area
It takes coordinates in stage coordinate space, and will result in
a screen cast stream consisting of that area, but scaled up by the scale
factor of the view that overlaps with the area and has the highest scale
factor.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1207
2020-04-23 14:45:53 +00:00
Jonas Ådahl
d2c3272eb7 clutter/paint-context: Add 'no-cursors' paint flag
Will be used by the stage to not paint the overlays. We skip all
overlays since overlays are only ever used for pointer cursors when the
hardware cursors cannot or should not be used.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1207
2020-04-23 14:45:53 +00:00
Jonas Ådahl
90c4b6492f stage: Only invoke paint phase callbacks when painting views
These phase callbacks are not intended to be inovked when something
secondary is painting the stage, such as a screen cast stream, or
similar. Thus, only invoke the callbacks when there is a view associated
with the paint context, which will not be the case for offscreen
painting.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1207
2020-04-23 14:45:53 +00:00
Jonas Ådahl
b7bf42e778 clutter/stage: Add API to paint to a custom target
Either onto a framebuffer, or into a CPU memory buffer. The latter will
use an former API and then copy the result to CPU memory. The former
allocates an offscreen framebuffer, sets up the relevant framebuffer
matrices and paints part of the stage defined by the passed rectangle.

This will be used by a RecordArea screen cast API. The former to paint
directly onto PipeWire handled dma-buf framebuffers, and the latter for
PipeWire handled shared memory buffers.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1207
2020-04-23 14:45:53 +00:00
Jonas Ådahl
e849667be6 screen-cast-stream-src: Add getter for stride
https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1207
2020-04-23 14:45:53 +00:00
Jonas Ådahl
424016d66c stage: Pass paint context in phase callbacks
If there is a paint context available (i.e. for the phases that are
during the actual stage paint), pass it along the callbacks, so that
the callback implementations can change their operation depending on the
paint context state.

This also means we can get the current view from the paint context,
instead of the temporarily used field in the instance struct.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1207
2020-04-23 14:45:53 +00:00
Jonas Ådahl
a4f55d4986 clutter/paint-context: Allow passing redraw clip to offscreen paint context
So that we can mark the redraw clip of the part of the stage we're
painting.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1207
2020-04-23 14:45:53 +00:00
Jonas Ådahl
1b33a5a3a7 clutter/paint-context: Add paint flag
A paint flag affects a paint operation in ways defined by the flags.
Currently no flags are defined, so no semantical changes are defined
yet. Eventually a flag aiming to avoid painting of cursors is going to
be added, so that screen cast streams can decide whether to include a
cursor or not.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1207
2020-04-23 14:45:53 +00:00
Pekka Paalanen
36111270aa kms-impl/simple: Fix page_flip_data ref leak on fallback
If drmModePageFlip() or custom_page_flip_func fails, process_page_flip() was
forgetting to undo the ref taken for that call. This would leak page_flip_data.

The reference counting works like this:
- when created, ref count is 1
- when calling drmModePageFlip, ref count is increased to 2
- new: if flip failed, ref count is decreased back to 1
- if calling schedule_retry_page_flip(), it takes a ref internally
- if calling mode_set_fallback(), it takes a ref internally
- all return FALSE paths have an explicit unref
- return TRUE path has an explicit unref

This issue was found by code inspection and while debugging an unrelated issue
with debug prints sprinkled around. I am not aware of any end-user visible
issues being fixed by this, as the leak is small and probably very rare.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1209
2020-04-23 16:30:22 +03:00
Pekka Paalanen
6e0cfd3e55 kms: Make GSource ready by default
When testing a laptop with intel and DisplayLink devices, attempting to set the
DL output as the only active output resulted in GNOME/Wayland freezing. The
main event loop was running fine, but nothing on screen would get updated once
the DL output become the only one. This patch fixes that issue.

DisplayLink USB 3 devices use an out-of-tree kernel DRM driver called EVDI.
EVDI can sometimes fail drmModePageFlip(). For me, the flip fails reliably when
hotplugging the DL dock and when changing display configuration to DL only.
Mutter has a workaround for failing flips, it just calls drmModeSetCrtc() and
that succeeds.

What does not work reliably in the fallback path is Mutter keeping track of the
pageflip. Since drmModePageFlip() failed, there will not be a pageflip event
coming and instead Mutter queues a callback in its stead. When you have more
than one output, some other output repainting will attempt to swap buffers and
calls wait_for_pending_flips() which has the side-effect of dispatching any
queued flip callbacks. With multiple outputs, you don't get stuck (unless they
all fail the exact same way at the same time?). When you have only one output,
it cannot proceed to repaint and buffer swap because the pageflip is not marked
complete yet. Nothing dispatches the flip callback, leading to the freeze.

The flip callback is intended to be an idle callback, implemented with a
GSource. It is supposed to be called as soon as execution returns to the main
event loop. The setup of the GSource is incomplete, so it will never dispatch.

Fix the GSource setup by setting its ready-time to be always in the past. That
gets it dispatched on the next cycle of the main event loop. This is now the
default behavior for all sources created by meta_kms_add_source_in_impl().
Sources that need a delay continue to do that by overriding the ready-time
explicitly.

An alternative solution could have been to implement GSource prepare and check
callbacks returning TRUE. However, since meta_kms_add_source_in_impl() is used
by flip retry code as well, and that code needs a delay through the ready-time,
I was afraid I might break the flip retry code. Hence I decided to use
ready-time instead.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1209
2020-04-23 16:30:17 +03:00
Carlos Garnacho
5671f0a284 x11: Allow X11 clients to clear the selection
According to the XSetSelectionOwner libX11 documentation:

  [...] If the owner window it has specified in the request is later
  destroyed, the owner of the selection automatically reverts to None,
  but the last-change time is not affected.

This is indeed visible through the selection_timestamp field in
XFixesSelectionNotify events.

Use this to check whether the selection time is recent-ish (thus
likely coming from an explicit XSetSelectionOwner request) and honor
the client intent by setting a "NULL" owner. If the selection time
is too old, it's definitely an indication of the owner client being
closed, the scenario where we do want the clipboard manager to take
over.

This fixes two usecases:
- X11 LibreOffice / WPS clear the selection each time before copying
  its own content. Mutter's clipboard manager would see each of those
  as a hint to take over, competing with the client over selection
  ownership. This would simply no longer happen
- Password managers may want to clear the selection, which would be
  frustrated by our clipboard manager.

There's a slight window of opportunity for the heuristics to fail
though, if a X11 client sets the selection and closes within 50ms, we
would miss the clipboard manager taking over.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1206
2020-04-21 21:32:53 +00:00
Carlos Garnacho
a7e63bea6c x11: Generalize x11 selection owner checks
Shuffle things so the x11 selection can check the current owner directly,
instead of its type.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1206
2020-04-21 21:32:53 +00:00
Carlos Garnacho
94b3c334e5 x11: Clear X11 selection source after unsetting owner
The X11 selection source was being preserved after unsetting its
ownership. This is no leak as it would be eventually replaced by
another source, or destroyed on finalize. But it's pointless to
keep it.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1206
2020-04-21 21:32:53 +00:00
Jonas Dreßler
efb0addb62 tests/wayland: Add a test for meta-anonymous-file
Test the two modes of MetaAnonymousFile, MAPMODE_SHARED and
MAPMODE_PRIVATE and make sure they don't leak data to other FDs when
writing to an FD provided by `meta_anonymous_file_get_fd` even though
the data of both FDs is residing in the same chunk of memory.

We do all the reading tests using mmap instead of read() since using
read() on shared FDs is going to move the read cursor of the fd. That
means using read() once on the shared FD returned by
meta_anonymous_file_get_fd() in MAPMODE_PRIVATE breaks every subsequent
read() call.

Also test the fallback code of MetaAnonymousFile in case `memfd_create`
isn't used for the same issues.

https://gitlab.gnome.org/GNOME/mutter/merge_requests/1012
2020-04-21 17:52:08 +02:00
Jonas Dreßler
988da215c8 wayland/keyboard: Use MetaAnonymousFile to share keymap files
Since protocol version 7 clients must use MAP_PRIVATE to map the keymap
fd, that means we can use memfd_create() to create the fd by using
meta_anonymous_file_open_fd() with META_ANONYMOUS_FILE_MAPMODE_PRIVATE,
for older versions we use META_ANONYMOUS_FILE_MAPMODE_SHARED to be
compatibile with MAP_SHARED.

Pretty much all of this code was written for Weston by Sebastian Wick,
see https://gitlab.freedesktop.org/wayland/weston/merge_requests/240.

Co-authored-by: Sebastian Wick <sebastian@sebastianwick.net>

Fixes https://gitlab.gnome.org/GNOME/gnome-shell/issues/1734

https://gitlab.gnome.org/GNOME/mutter/merge_requests/1012
2020-04-21 17:52:08 +02:00
Jonas Dreßler
551a57ed7f Add read-only anonymous file abstraction MetaAnonymousFile
Add MetaAnonymousFile, an abstraction around anonymous read-only files.
Files can be created by calling meta_anonymous_file_new(), passing the
data of the file. Subsequent calls to meta_anonymous_file_open_fd()
return a fd that's ready to be sent over the socket.

When mapmode is META_ANONYMOUS_FILE_MAPMODE_PRIVATE the fd is only
guaranteed to be mmap-able readonly with MAP_PRIVATE but does not
require duplicating the file for each resource when memfd_create is
available. META_ANONYMOUS_FILE_MAPMODE_SHARED may be used when the
client must be able to map the file with MAP_SHARED but it also means
that the file has to be duplicated even when memfd_create is available.

Pretty much all of this code was written for weston by Sebastian Wick,
see https://gitlab.freedesktop.org/wayland/weston/merge_requests/240.

Co-authored-by: Sebastian Wick <sebastian@sebastianwick.net>

https://gitlab.gnome.org/GNOME/mutter/merge_requests/1012
2020-04-21 17:52:08 +02:00
Carlos Garnacho
b7366b5b53 wayland: Drop unused struct variable
https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1193
2020-04-17 00:51:00 +02:00
Carlos Garnacho
5e8d8b9ade wayland: Move the primary data device manager to its own file
Instead of having everything clumped at MetaWaylandDataManager,
split the primary selection to its own struct. This manager is
handled separately from wl_data_device_manager and other selection
managers, so they would be able to interoperate between them, even.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1193
2020-04-17 00:50:57 +02:00
Carlos Garnacho
4726f3d5d3 wayland: Move primary data offers to their own file
Following the MetaWaylandDataOffer split.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1193
2020-04-17 00:46:23 +02:00
Carlos Garnacho
91ef7515de wayland: Move MetaWaylandDataOffer to its own file
This is still an openly defined struct, as we will need accessed
by "subclasses". Same principle applies than with the
MetaWaylandDataSource refactor, this is not meant to introduce
functional changes, so just go with it.

On the bright side, the interactions are now clearer, so it could
be made saner in the future.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1193
2020-04-17 00:46:23 +02:00
Carlos Garnacho
317f6c0910 wayland: Move MetaWaylandDataSourcePrimary to its own file
Following the MetaWaylandDataSource split, this goes next.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1193
2020-04-17 00:46:23 +02:00
Carlos Garnacho
6a3d521466 wayland: Split MetaWaylandDataSource into a separate file
The split wasn't 100% clean, and some extra private API had to be
added for it (but well, looking at the API, it's already evident
there's a cleanup/streamlining task due). This is meant to be a
refactor with no functional changes, so just go with it.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1193
2020-04-17 00:46:21 +02:00
Carlos Garnacho
1363246d44 wayland: Rely on MetaSelection::owner-changed for .selection event emission
We already have a signal callback that translates selection ownership changes to
data_device/primary .selection events. Given both will be run when a data source
is being replaced, and this event emission being deleted is kinda short sighted
in that in only knows about Wayland, rely entirely on MetaSelection::owner-changed
emission.

Fixes spurious .selection(null) events being sent when a compositor-local source
takes over the selection without the focus changing (eg. screenshot to clipboard).

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

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1204
2020-04-16 22:25:00 +00:00
Carlos Garnacho
0b6560fac4 wayland: Do not cancel old data source when setting new selection
This is taken care already by the MetaSelection machinery, by
deactivating the previous selection source when setting a new one.
That works across X11 and internal selection sources. This
only works when replacing one wayland source with another, and
actually results in doubly .cancelled events due to the other
paths.

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

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1203
2020-04-16 19:27:51 +00:00
Carlos Garnacho
d4c3870286 wayland: Shuffle wl_data_source.cancelled version checks on DnD
We are meant to send a .cancelled event after the drop is performed
in certain situations, but only for version>3 clients. Since this is
all version 3 business, only set the drop_performed flag for v3
clients. This drops the need to perform version checks at the time
of cancelling (which is present for other usecases in v1).

Fixes emission of wl_data_source.cancelled for v1 clients.

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

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1203
2020-04-16 19:27:51 +00:00
Carlos Garnacho
4bdf9a1e70 core: Cater for reading selection in chunks
For the cases where we read a fixed size from the selection (eg. imposing
limits for the clipboard manager), g_input_stream_read_bytes_async() might
not read up to this given size if the other side is spoonfeeding it content.

Cater for multiple read/write cycles here, until (maximum) transfer size is
reached.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1198
2020-04-16 16:26:04 +00:00
Carlos Garnacho
1909977a67 x11: Do not trust there is task in error paths
Flushing the X11 selection output stream may happen synchronously or
implicitly, in which case there is not a task to complete. Check there
is actually a task before returning errors. We additionally set the
pipe_error flag, so future operations will fail with an error, albeit
with a more generic message.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1198
2020-04-16 16:26:04 +00:00
Carlos Garnacho
655a783891 x11: Don't stall on write_async()
If a write_async() comes up while we are flushing on the background,
the task will be queued, but not deemed a reason on itself to keep
flushing (and finish the task) after a property delete event.

To fix this, do not ever queue up write_async tasks (this leaves
priv->pending_task only used for flush(), so the "flush to end"
behavior in the background is consistent). We only start a
background flush if there's reasons to do it, but the tasks are
immediately finished.

All data will still be ensured to be transfered on flush/close,
this makes the caller in this situation still able to reach to it.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1198
2020-04-16 16:26:04 +00:00
Carlos Garnacho
a4596becc4 x11: Fix iterative INCR property checks
It does not make sense to check for the stream not being closed,
this might happen multiple times during the lifetime of the stream
for a single transfer. We want to notify the INCR transfer just
once.

Check for the explicit conditions that we want, that the remaining
data is bigger than we can transfer at once, and that we are not
yet within the INCR transfer.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1198
2020-04-16 16:26:04 +00:00
Carlos Garnacho
7015bb3efd x11: Don't exceed transfer size in INCR chunks
The stream automatically flushes after data size exceeds the
size we deem for INCR chunks, but we still try to copy it all.
Actually limit the data we copy, and leave the rest for future
INCR chunks.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1198
2020-04-16 16:26:04 +00:00
Carlos Garnacho
d2c762cc66 x11: Don't invariably queue a pending delete request
We don't need doing this roundtrip for non-INCR transfers.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1198
2020-04-16 16:26:04 +00:00
Carlos Garnacho
04d429b743 x11: Finish INCR transfers properly
INCR transfers are mandated to finish with a final 0-size XChangeProperty
roundtrip after the final data chunk. Actually honor this and ensure we
iterate just once more for this.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1198
2020-04-16 16:26:04 +00:00
Carlos Garnacho
0b21dcfe08 x11: Wait till data is flushed before notifying on the pending task
It does not make sense to notify flushes mid-transfer. We should wait
till the data is actually finished before notifying on the pending
task.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1198
2020-04-16 16:26:04 +00:00
Carlos Garnacho
7c939d78c2 x11: Only send SelectionNotify on first INCR chunk
This should only be sent if the selection can be sent at once, or
if we are right about to notify on the first chunk of an INCR
transfer.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1198
2020-04-16 16:26:04 +00:00
Carlos Garnacho
8a2b82897d x11: Ensure flush() Flushes all output stream data
This seemed to work under the assumption that a flush() call can
only result in one INCR roundtrip. This is evidently not true, so
we should hold things off until all pending data is actually flushed.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1198
2020-04-16 16:26:04 +00:00
Carlos Garnacho
e95c365cf0 x11: Unset pending flush flag right before notifying on task
Together with some other state. We can do this altogether on task
notification, instead of lost somewhere in this function flow.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1198
2020-04-16 16:26:04 +00:00
Carlos Garnacho
a32cb7133b x11: Intern INCR atom
We want to use it, despite it not existing previously.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1198
2020-04-16 16:26:04 +00:00
Carlos Garnacho
967966cdee x11: Flag flushes despite having less than the element size
If say we want 32bit data, but have 2 bytes stored, we would simply
ignore flush requests. Allow (and don't clear) the needs_flush flag
if we have less than the element size accumulated.

Instead handle this in can_flush(), so it's triggered whenever we
have enough data to fill 1 element, or if the stream is closing
(seems a broken situation, but triggered by the caller).

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1198
2020-04-16 16:26:04 +00:00
Carlos Garnacho
06d67b6abf x11: XMaxRequestSize returns 4-byte units
XMaxRequestSize/XMaxExtendedRequestSize are documented to return
the maximum size in 4-byte units, whereas we are comparing this
to byte lenghts. We can afford 4x the data here.

Since I don't know the payload size of the XChangeProperty request,
be generous and allot 400 bytes for it, we have some to spare.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1198
2020-04-16 16:26:04 +00:00
Marco Trevisan (Treviño)
f15ce01e2b monitor-unit-tests: Ensure configuration is preserved in laptop with closed lid
https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1200
2020-04-16 15:14:03 +00:00
Marco Trevisan (Treviño)
e48516679c monitor-config-manager: Fallback to closed laptop lid configuration
When closing the lid of a laptop, we reconfigure all the monitors in order
to update the CRTCs and (if enabled) the global UI scaling factor.

To do this, we try first to reuse the current configuration for the usable
monitors, but if we have only monitor enabled and this one is on the laptop
lid we just end up creating a new configuration where the primary monitor is
the laptop one (as per find_primary_monitor() in MetaMonitorConfigManager),
but ignoring the user parameters.

In case the user selected a different resolution / scaling compared to the
default one, while the laptop lid is closed we might change the monitors
layout, causing applications to rescale or reposition.

To avoid this, when creating the monitors configuration from the current
current state, in case we have only one monitor available and that one is
the laptop panel, let's just reuse this configuration.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1200
2020-04-16 15:14:03 +00:00
Jonas Ådahl
65a6c4c361 compositor: Add support for direct scanout of Wayland surfaces
Try to bypass compositing if there is a fullscreen toplevel window with
a buffer compatible with the primary plane of the monitor it is
fullscreen on. Only non-mirrored is currently supported; as well as
fullscreened on a single monitor. It should be possible to extend with
more cases, but this starts small.

It does this by introducing a new MetaCompositor sub type
MetaCompositorNative specific to the native backend, which derives from
MetaCompositorServer, containing functionality only relevant for when
running on top of the native backend.

https://gitlab.gnome.org/GNOME/mutter/merge_requests/798
2020-04-16 15:05:52 +02:00
Jonas Ådahl
b51c468c0f later: Listen to MetaCompositor signal instead of clutter
We need to coordinate with MetaCompositor during pre-paint so that we
have control over whether MetaLater callbacks happen first, or the
MetaCompositor pre-paint logic.

In order to do so, make MetaLater listen to a new signal "pre-paint" on
MetaCompositor, that is called MetaCompositors own pre-paint handling.

This fixes an issue where the top window actor was calculated after the
MetaCompositor pre-paint handling, meaning the top actor being painted
was out-of-date.

https://gitlab.gnome.org/GNOME/mutter/merge_requests/798
2020-04-16 15:05:52 +02:00
Jonas Ådahl
2e7d02f1ce later: Make MetaCompositor the owner of the MetaLaters state
Since the order of destruction during MetaDisplay tear down is a bit
unordered, there are pieces that try to destruct its compositing
dependent pieces (i.e. queued MetaLater callbacks) after MetaCompositor
has been cleaned up, meaning we need to put some slightly awkward NULL
checks to avoid crashing.

https://gitlab.gnome.org/GNOME/mutter/merge_requests/798
2020-04-16 15:05:52 +02:00
Jonas Ådahl
dc4fe780f7 display: Initialize MetaCompositor in two steps
MetaCompositor is the place in mutter that manages the higher level
state of compositing, such as handling what happens before and after
paint. In order for other units that depend on having a compositor
instance active, but should be initialized before the X11 implementation
of MetaCompositor registers as a X11 compositing manager, split the
initialization of compositing into two steps:

 1) Instantiate the object - only construct the instance, making it
    possible for users to start listening to signals etc
 2) Manage - this e.g. establishes the compositor as the X11 compositing
    manager and similar things.

This will enable us to put compositing dependent scattered global
variables into a MetaCompositor owned object.

For now, compositor management is internally done by calling a new
`meta_compositor_do_manage()`, as right now we can't change the API of
`meta_compositor_manage()` as it is public. For the next version, manual
management of compositing will removed from the public API, and only
managed internally.

https://gitlab.gnome.org/GNOME/mutter/merge_requests/798
2020-04-16 15:05:52 +02:00
Jonas Ådahl
d682cdb078 util: Move MetaLater to its own file
While at it, fix some style inconsistencies, for now use a single
singleton struct instead of multiple static variables, and
other non-functional cleanups. Semantically, there is no changes
introduced.

https://gitlab.gnome.org/GNOME/mutter/merge_requests/798
2020-04-16 15:05:52 +02:00
Jonas Ådahl
ff7a42b8bc wayland: Add API to acquire a CoglScanout from a surface
This will check whether the current backing buffer is compatible with
the primary plane of the passed CoglOnscreen. Since this will extend the
time before a buffer is released, the MetaWaylandBufferRef is swapped
and orphaned if a new buffer is committed before the previous one was
released. It'll eventually be released, usually by the next page flip
callback.

Currently implemented for EGLImage and DMA-BUF buffer types.

https://gitlab.gnome.org/GNOME/mutter/merge_requests/798
2020-04-16 15:05:52 +02:00
Jonas Ådahl
4b1805c306 wayland/dma-buf: Handle getting dma-buf from detached buffer handle
We might still have a MetaWaylandBuffer for a wl_buffer that was
destroyed. Handle trying to fetch the MetaWaylandDmaBufBuffer from such
a buffer gracefully.

https://gitlab.gnome.org/GNOME/mutter/merge_requests/798
2020-04-16 15:05:52 +02:00
Jonas Ådahl
03c00e4944 wayland/dma-buf: Minor style fix
Indentation was off.

https://gitlab.gnome.org/GNOME/mutter/merge_requests/798
2020-04-16 15:05:52 +02:00
Jonas Ådahl
cb05b16414 wayland/dma-buf: Don't advertise modifier support by default
Advertising support for modifiers means we will most likely not not be
able to scan out client buffers directly, meaning it just as likely that
we won't be able to scan out even fullscreen windows without atomic KMS.

When we have atomic support, we should advertise support for modifiers
if atomic is used to drive the CRTCs, as we by then can check whether we
can scan out directly, place in an overlay plane, etc.

https://gitlab.gnome.org/GNOME/mutter/merge_requests/798
2020-04-16 15:05:52 +02:00
Jonas Ådahl
b9fe9c736a onscreen/native: Add API to check whether buffer is scanout compatible
While this is fairly incomplete, as to check things fully we need to use
TEST_ONLY in atomic to try out a complete assignment on the device, but
this works well enough for legacy non-modifier cases.

https://gitlab.gnome.org/GNOME/mutter/merge_requests/798
2020-04-16 15:05:52 +02:00
Jonas Ådahl
3dd8861fbf renderer/native: Add API to get primary GPU
Will be used when acquiring scanouts from Wayland buffers.

https://gitlab.gnome.org/GNOME/mutter/merge_requests/798
2020-04-16 15:05:52 +02:00
Jonas Ådahl
753066598f clutter/view: Make it possible to assign a temporary direct scanout
Make it possible to cause the next frame to scan out directly from the
passed CoglScannout. This makes it possible to completely bypass
compositing for the following frame.

https://gitlab.gnome.org/GNOME/mutter/merge_requests/798
2020-04-16 15:05:52 +02:00
Jonas Ådahl
3da8c1bfdc cogl/onscreen: Add API to scanout a buffer directly
Instead of always swapping buffers and flipping the back buffer, make it
possible to scan out a provided buffer directly without swapping any EGL
buffers.

A buffer is passed as an object implementing the empty CoglScanout
interface. It is only possible to do this in the native backend; and the
interface is implemented by MetaDrmBufferGbm. When directly scanned out,
instead of calling gbm_surface_lock_front_buffer() to get the gbm_bo and
fbid, get it directly from the MetaDrmBufferGbm, and use that to create
the page flip KMS update.

https://gitlab.gnome.org/GNOME/mutter/merge_requests/798
2020-04-16 15:05:15 +02:00
Jonas Ådahl
f8ee974628 wayland/buffer-ref: Add helpers for use count tracking
https://gitlab.gnome.org/GNOME/mutter/merge_requests/798
2020-04-16 14:08:19 +02:00
Jonas Ådahl
f36120757f wayland: Make MetaWaylandBufferRef reference counted
So that we can have a more dynamic ownership.

https://gitlab.gnome.org/GNOME/mutter/merge_requests/798
2020-04-16 14:08:19 +02:00
Jonas Ådahl
bc178b711f clutter/actor: Add semi-private API to check for transitions
Transitions are used for animating actors when e.g. going from/to
fullscreen, and the like. We need to know such things when deciding
whether to avoid compositing a window actor, so make add API visible to
mutter that checks whether there are any transitions active.

https://gitlab.gnome.org/GNOME/mutter/merge_requests/798
2020-04-16 14:08:19 +02:00
Jonas Ådahl
5dad87cfb9 surface-actor-x11: Move window related unredirect logic to MetaWindowX11
Better to have the relevant object figure out whether it is a good
position to be unredirectable other than the actor, which should be
responsible for being composited.

https://gitlab.gnome.org/GNOME/mutter/merge_requests/798
2020-04-16 14:08:19 +02:00
Jonas Ådahl
0f8f607e4c window/x11: Use G_DECLARE_DERIVABLE_TYPE()
This removes the MetaWindowX11::priv pointer. It is replaced with a
meta_window_x11_get_private() helper function, and another method to get
the client rect without going through MetaWindowX11Private.

https://gitlab.gnome.org/GNOME/mutter/merge_requests/798
2020-04-16 14:08:19 +02:00
Jonas Ådahl
282aada13a drm-buffer/gbm: Support both surface and standalone buffers
Surface buffers are created with meta_drm_buffer_new_acquire(), taking a
gbm_surface acquiring the gbm itself, and meta_drm_buffer_new_take()
that takes over ownership of a passed gbm_bo.

https://gitlab.gnome.org/GNOME/mutter/merge_requests/798
2020-04-16 14:08:19 +02:00
Jonas Ådahl
47002bf0cd wayland/surface: Put buffer reference on heap
Currently a buffer use count always reaches zero before it is replaced.
This is due to the fact that at the point a new buffer is attached, the
last potential user releases it (the stage) since the currently
displayed frame has a composited copy of the buffer.

This may however change, if a buffer is scanned out directly, meaning it
should not be released until the page flip callback is invoked.

Prepare for this by making the buffer reference a heap allocated struct,
enabling us to keep a pointer to it longer than the buffer is attached.

https://gitlab.gnome.org/GNOME/mutter/merge_requests/798
2020-04-16 10:43:34 +02:00
Jonas Ådahl
3d47c7edc1 cursor-renderer-native: Take CRTC transform into account
The CRTC level transform (not necessarily the hw transform) must be
taken into account when calculating the position of the CRTC in the
stage coordinate space, when placing the hw cursor, otherwise we'll
place the cursor as if the monitor was not rotated.

This wasn't a problem in the past, as with rotation, we always used the
OpenGL cursor, so the issue newer showed.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1199
2020-04-15 15:29:55 +00:00
Jonas Ådahl
bc350f37f5 renderer-native: Use CRTC layout in stage view
The port to per CRTC views was incomplete; we still used the logical
monitor layout as the stage view layout, while still using one view per
CRTC.

This worked fine for most cases, e.g. regular monitors, tiled or
non-tiled, transformed or non-transformed. Where it broke, however, was
when a monitor consists of multiple CRTCs. We already have the layout a
CRTC corresponds to on the stage kept with the CRTC metadata, so use
this directly.

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

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1199`
2020-04-15 15:29:55 +00:00
Jonas Ådahl
b55e2e1df9 tests/monitor-unit-tests: Test non-hw-transform rotated tiled monitors
Should affect the assigned transform, but not the layout, as that is the
layout on the stage, not the coordinates in any buffer.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1199
2020-04-15 15:29:55 +00:00
Jonas Ådahl
43baf643d4 monitor-config-manager: Only use crtc transform for assignment
The CRTC level transform (i.e. not necessarily the one set on the
hardware) is what is relevant for calculating the layout the CRTC will
have on the stage, so only use the one that can be handled by the
hardware for the CRTC assignment.

This makes the CRTC layout valid for tiled monitors.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1199
2020-04-15 15:29:55 +00:00
Jonas Ådahl
21b8ae10b8 monitor: Fix tile coordinate calculation
Previously the tile coordinate was used to offset a CRTC scanout
coordinate within a larger framebuffer. Since 3.36 we're always
scanning out from (0, 0) as we always have one framebuffer per CRTC; we
instead use the tile coordinate to calculate the coordinate the tile has
in the stage view. Adapt calculation to fulfil this promise instead of
the old one.

This also corrects the tiled custom monitor test case.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1199
2020-04-15 15:29:55 +00:00
Elias Aebi
425a10de11 clutter: Use #mesondefine
Use #mesondefine instead of manual concatenation.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1179
2020-04-15 12:56:34 +00:00
Thomas Hindoe Paaboel Andersen
d0ef660ff6 clutter: fix memleak in test error path
If clutter_init fails then we will not free state.

https://gitlab.gnome.org/GNOME/mutter/merge_requests/1195
2020-04-12 21:40:20 +00:00
Marco Trevisan (Treviño)
506e06589b test-utils: Only initialize client when we're returning it
test_client_new might return early if conditions are not met, leaving some
allocated data around without freeing it.

Since we're not using the client before, there's no need to initialize it early
and just initialize it when it's going to be returned.

https://gitlab.gnome.org/GNOME/mutter/merge_requests/1195
2020-04-12 21:40:20 +00:00
Marco Trevisan (Treviño)
1d75d5aa2f group: Free group if returning early
If we get an error when fetching the window attributes, the group isn't ever
free'd, so use an autopointer instead, releasing the stolen one.

https://gitlab.gnome.org/GNOME/mutter/merge_requests/1195
2020-04-12 21:40:20 +00:00
Marco Trevisan (Treviño)
645d596f9d cogl: Use autopointers to free structs on return
This is a potential leak discovered by static analysis, in fact if
_COGL_GET_CONTEXT returns, the newly allocated struct isn't released.

https://gitlab.gnome.org/GNOME/mutter/merge_requests/1195
2020-04-12 21:40:20 +00:00
280 changed files with 11504 additions and 13123 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

33
NEWS
View File

@@ -1,3 +1,36 @@
3.37.1
======
* Fix screencasting non-maximized windows [Jonas Å.; !1174]
* Make window-aliveness checks less aggressive [Jonas Å.; !1182]
* Fix stylus coordinates when using screen rotation [Jonas T.; #1118]
* Preserve keyboard state on VT switch [Olivier; !1185]
* Remove Clutter's drag and drop actions [Jonas D.; !789]
* Cancel clicks/gestures actions on disable [Georges; !1188]
* Fix various clipboard issues [Carlos; !1186, !1198, !1203, !1204, !1206]
* Fix trackball button scrolling [Phillip; #1120]
* Fix tiled monitor support [Jonas; !1199]
* Support unredirecting fullscreen wayland surfaces [Jonas Å.; !798]
* Support area screencasts [Jonas Å.; !1207]
* Synchronize shadows to server-side decorations [Olivier; !1214]
* Allow inhibiting remote access [Jonas Å.; !1212]
* Fix overview key on X11 when using multiple keyboard layouts [Olivier; !1219]
* Fixed crashes [Jonas, D., Carlos; !1173, !1183, !1012]
* Misc. bug fixes and cleanups [Andre, Georges, Christian, Jonas Å., Andre,
Simon, Florian, Carlos, Adam, Marco, Thomas, Elias, Pekka, Jonas D.,
Laurent; !1169, !1168, !1166, !1170, !1167, !1172, !1175, !1176, !1184,
!1126, !1187, !1191, !1195, !1179, !1200, !1193, !1209, !1213, !1208,
#1074, !1223]
Contributors:
Marco Trevisan (Treviño), Elias Aebi, Thomas Hindoe Paaboel Andersen,
Laurent Bigonville, Jonas Dreßler, Olivier Fourdan, Carlos Garnacho,
Adam Jackson, Andre Moreira Magalhaes, Simon McVittie, Florian Müllner,
Georges Basile Stavracas Neto, Pekka Paalanen, Christian Rauch, Jonas Troeger,
Phillip Wood, Jonas Ådahl
Translators:
Dušan Kazik [sk], Christian Kirbach [de]
3.36.0
======
* Fix placement of popup windows in multi-monitor setups [Jonas; !1110]

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;
@@ -19960,6 +19613,23 @@ clutter_actor_get_transition (ClutterActor *self,
return clos->transition;
}
/**
* clutter_actor_has_transitions: (skip)
*/
gboolean
clutter_actor_has_transitions (ClutterActor *self)
{
const ClutterAnimationInfo *info;
g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
info = _clutter_actor_get_animation_info_or_defaults (self);
if (info->transitions == NULL)
return FALSE;
return g_hash_table_size (info->transitions) > 0;
}
/**
* clutter_actor_save_easing_state:
* @self: a #ClutterActor
@@ -21029,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

@@ -9,7 +9,13 @@
G_BEGIN_DECLS
@CLUTTER_CONFIG_DEFINES@
#mesondefine CLUTTER_HAS_WAYLAND_COMPOSITOR_SUPPORT
#mesondefine CLUTTER_WINDOWING_X11
#mesondefine CLUTTER_INPUT_X11
#mesondefine CLUTTER_WINDOWING_GLX
#mesondefine CLUTTER_WINDOWING_EGL
#mesondefine CLUTTER_INPUT_EVDEV
#mesondefine CLUTTER_INPUT_NULL
G_END_DECLS

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

@@ -36,6 +36,9 @@
#include "cogl/clutter-stage-cogl.h"
#include "clutter/x11/clutter-backend-x11.h"
CLUTTER_EXPORT
GList * clutter_stage_peek_stage_views (ClutterStage *stage);
CLUTTER_EXPORT
void clutter_set_custom_backend_func (ClutterBackend *(* func) (void));
@@ -48,6 +51,23 @@ void clutter_stage_capture_into (ClutterStage *stage,
cairo_rectangle_int_t *rect,
uint8_t *data);
CLUTTER_EXPORT
void clutter_stage_paint_to_framebuffer (ClutterStage *stage,
CoglFramebuffer *framebuffer,
const cairo_rectangle_int_t *rect,
float scale,
ClutterPaintFlag paint_flags);
CLUTTER_EXPORT
gboolean clutter_stage_paint_to_buffer (ClutterStage *stage,
const cairo_rectangle_int_t *rect,
float scale,
uint8_t *data,
int stride,
CoglPixelFormat format,
ClutterPaintFlag paint_flags,
GError **error);
CLUTTER_EXPORT
void clutter_stage_freeze_updates (ClutterStage *stage);
@@ -57,9 +77,16 @@ void clutter_stage_thaw_updates (ClutterStage *stage);
CLUTTER_EXPORT
void clutter_stage_update_resource_scales (ClutterStage *stage);
CLUTTER_EXPORT
void clutter_stage_view_assign_next_scanout (ClutterStageView *stage_view,
CoglScanout *scanout);
CLUTTER_EXPORT
gboolean clutter_actor_has_damage (ClutterActor *actor);
CLUTTER_EXPORT
gboolean clutter_actor_has_transitions (ClutterActor *actor);
#undef __CLUTTER_H_INSIDE__
#endif /* __CLUTTER_MUTTER_H__ */

View File

@@ -21,7 +21,8 @@
#include "clutter-paint-context.h"
ClutterPaintContext * clutter_paint_context_new_for_view (ClutterStageView *view,
const cairo_region_t *redraw_clip);
const cairo_region_t *redraw_clip,
ClutterPaintFlag paint_flags);
gboolean clutter_paint_context_is_drawing_off_stage (ClutterPaintContext *paint_context);

View File

@@ -23,6 +23,8 @@ struct _ClutterPaintContext
{
grefcount ref_count;
ClutterPaintFlag paint_flags;
GList *framebuffers;
ClutterStageView *view;
@@ -36,7 +38,8 @@ G_DEFINE_BOXED_TYPE (ClutterPaintContext, clutter_paint_context,
ClutterPaintContext *
clutter_paint_context_new_for_view (ClutterStageView *view,
const cairo_region_t *redraw_clip)
const cairo_region_t *redraw_clip,
ClutterPaintFlag paint_flags)
{
ClutterPaintContext *paint_context;
CoglFramebuffer *framebuffer;
@@ -45,6 +48,7 @@ clutter_paint_context_new_for_view (ClutterStageView *view,
g_ref_count_init (&paint_context->ref_count);
paint_context->view = view;
paint_context->redraw_clip = cairo_region_copy (redraw_clip);
paint_context->paint_flags = paint_flags;
framebuffer = clutter_stage_view_get_framebuffer (view);
clutter_paint_context_push_framebuffer (paint_context, framebuffer);
@@ -56,12 +60,16 @@ clutter_paint_context_new_for_view (ClutterStageView *view,
* clutter_paint_context_new_for_framebuffer: (skip)
*/
ClutterPaintContext *
clutter_paint_context_new_for_framebuffer (CoglFramebuffer *framebuffer)
clutter_paint_context_new_for_framebuffer (CoglFramebuffer *framebuffer,
const cairo_region_t *redraw_clip,
ClutterPaintFlag paint_flags)
{
ClutterPaintContext *paint_context;
paint_context = g_new0 (ClutterPaintContext, 1);
g_ref_count_init (&paint_context->ref_count);
paint_context->redraw_clip = cairo_region_copy (redraw_clip);
paint_context->paint_flags = paint_flags;
clutter_paint_context_push_framebuffer (paint_context, framebuffer);
@@ -170,3 +178,12 @@ clutter_paint_context_is_drawing_off_stage (ClutterPaintContext *paint_context)
return !paint_context->view;
}
/**
* clutter_paint_context_get_paint_flags: (skip)
*/
ClutterPaintFlag
clutter_paint_context_get_paint_flags (ClutterPaintContext *paint_context)
{
return paint_context->paint_flags;
}

View File

@@ -29,13 +29,21 @@
typedef struct _ClutterPaintContext ClutterPaintContext;
typedef enum _ClutterPaintFlag
{
CLUTTER_PAINT_FLAG_NONE = 0,
CLUTTER_PAINT_FLAG_NO_CURSORS = 1 << 0,
} ClutterPaintFlag;
#define CLUTTER_TYPE_PAINT_CONTEXT (clutter_paint_context_get_type ())
CLUTTER_EXPORT
GType clutter_paint_context_get_type (void);
CLUTTER_EXPORT
ClutterPaintContext * clutter_paint_context_new_for_framebuffer (CoglFramebuffer *framebuffer);
ClutterPaintContext * clutter_paint_context_new_for_framebuffer (CoglFramebuffer *framebuffer,
const cairo_region_t *redraw_clip,
ClutterPaintFlag paint_flags);
CLUTTER_EXPORT
ClutterPaintContext * clutter_paint_context_ref (ClutterPaintContext *paint_context);
@@ -62,4 +70,7 @@ void clutter_paint_context_pop_framebuffer (ClutterPaintContext *paint_context);
CLUTTER_EXPORT
const cairo_region_t * clutter_paint_context_get_redraw_clip (ClutterPaintContext *paint_context);
CLUTTER_EXPORT
ClutterPaintFlag clutter_paint_context_get_paint_flags (ClutterPaintContext *paint_context);
#endif /* CLUTTER_PAINT_CONTEXT_H */

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);
@@ -139,8 +138,6 @@ void _clutter_stage_presented (ClutterStage *stag
CoglFrameEvent frame_event,
ClutterFrameInfo *frame_info);
GList * _clutter_stage_peek_stage_views (ClutterStage *stage);
void clutter_stage_queue_actor_relayout (ClutterStage *stage,
ClutterActor *actor);

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);
@@ -43,4 +54,12 @@ const cairo_region_t * clutter_stage_view_peek_redraw_clip (ClutterStageView *vi
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,16 +23,20 @@
#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"
enum
{
PROP_0,
PROP_NAME,
PROP_LAYOUT,
PROP_FRAMEBUFFER,
PROP_OFFSCREEN,
PROP_SHADOWFB,
PROP_USE_SHADOWFB,
PROP_SCALE,
PROP_LAST
@@ -42,6 +46,8 @@ static GParamSpec *obj_props[PROP_LAST];
typedef struct _ClutterStageViewPrivate
{
char *name;
cairo_rectangle_int_t layout;
float scale;
CoglFramebuffer *framebuffer;
@@ -49,8 +55,18 @@ 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;
gboolean has_redraw_clip;
cairo_region_t *redraw_clip;
@@ -87,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;
}
@@ -148,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)
{
@@ -170,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
@@ -260,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)
{
@@ -270,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
@@ -288,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
@@ -387,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)
@@ -407,6 +969,25 @@ clutter_stage_default_get_offscreen_transformation_matrix (ClutterStageView *vie
cogl_matrix_init_identity (matrix);
}
void
clutter_stage_view_assign_next_scanout (ClutterStageView *view,
CoglScanout *scanout)
{
ClutterStageViewPrivate *priv =
clutter_stage_view_get_instance_private (view);
g_set_object (&priv->next_scanout, scanout);
}
CoglScanout *
clutter_stage_view_take_scanout (ClutterStageView *view)
{
ClutterStageViewPrivate *priv =
clutter_stage_view_get_instance_private (view);
return g_steal_pointer (&priv->next_scanout);
}
static void
clutter_stage_view_get_property (GObject *object,
guint prop_id,
@@ -419,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;
@@ -428,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);
@@ -452,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;
@@ -476,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);
@@ -488,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);
@@ -525,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",
@@ -554,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;
@@ -552,7 +554,7 @@ clutter_stage_add_redraw_clip (ClutterStage *stage,
{
GList *l;
for (l = _clutter_stage_peek_stage_views (stage); l; l = l->next)
for (l = clutter_stage_peek_stage_views (stage); l; l = l->next)
{
ClutterStageView *view = l->data;
@@ -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 */
@@ -924,7 +932,8 @@ clutter_stage_do_paint_view (ClutterStage *stage,
ClutterPaintContext *paint_context;
cairo_rectangle_int_t clip_rect;
paint_context = clutter_paint_context_new_for_view (view, redraw_clip);
paint_context = clutter_paint_context_new_for_view (view, redraw_clip,
CLUTTER_PAINT_FLAG_NONE);
cairo_region_get_extents (redraw_clip, &clip_rect);
setup_view_for_pick_or_paint (stage, view, &clip_rect);
@@ -1169,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);
}
}
@@ -1301,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
@@ -1311,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++;
@@ -1358,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);
@@ -1493,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
@@ -1572,7 +1584,7 @@ is_full_stage_redraw_queued (ClutterStage *stage)
{
GList *l;
for (l = _clutter_stage_peek_stage_views (stage); l; l = l->next)
for (l = clutter_stage_peek_stage_views (stage); l; l = l->next)
{
ClutterStageView *view = l->data;
@@ -2428,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);
}
}
@@ -2518,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);
}
}
@@ -3141,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))
{
@@ -3168,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
@@ -3208,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;
@@ -3436,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;
@@ -3453,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);
}
@@ -3462,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.
*
@@ -3572,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 ();
@@ -4163,6 +4171,97 @@ clutter_stage_get_capture_final_size (ClutterStage *stage,
return TRUE;
}
void
clutter_stage_paint_to_framebuffer (ClutterStage *stage,
CoglFramebuffer *framebuffer,
const cairo_rectangle_int_t *rect,
float scale,
ClutterPaintFlag paint_flags)
{
ClutterStagePrivate *priv = stage->priv;
ClutterPaintContext *paint_context;
cairo_region_t *redraw_clip;
redraw_clip = cairo_region_create_rectangle (rect);
paint_context =
clutter_paint_context_new_for_framebuffer (framebuffer,
redraw_clip,
paint_flags);
cairo_region_destroy (redraw_clip);
cogl_framebuffer_push_matrix (framebuffer);
cogl_framebuffer_set_projection_matrix (framebuffer, &priv->projection);
cogl_framebuffer_set_viewport (framebuffer,
-(rect->x * scale),
-(rect->y * scale),
priv->viewport[2] * scale,
priv->viewport[3] * scale);
clutter_actor_paint (CLUTTER_ACTOR (stage), paint_context);
cogl_framebuffer_pop_matrix (framebuffer);
clutter_paint_context_destroy (paint_context);
}
gboolean
clutter_stage_paint_to_buffer (ClutterStage *stage,
const cairo_rectangle_int_t *rect,
float scale,
uint8_t *data,
int stride,
CoglPixelFormat format,
ClutterPaintFlag paint_flags,
GError **error)
{
ClutterBackend *clutter_backend = clutter_get_default_backend ();
CoglContext *cogl_context =
clutter_backend_get_cogl_context (clutter_backend);
int texture_width, texture_height;
CoglTexture2D *texture;
CoglOffscreen *offscreen;
CoglFramebuffer *framebuffer;
CoglBitmap *bitmap;
texture_width = (int) ceilf (rect->width * scale);
texture_height = (int) ceilf (rect->height * scale);
texture = cogl_texture_2d_new_with_size (cogl_context,
texture_width,
texture_height);
if (!texture)
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"Failed to create %dx%d texture",
texture_width, texture_height);
return FALSE;
}
offscreen = cogl_offscreen_new_with_texture (COGL_TEXTURE (texture));
framebuffer = COGL_FRAMEBUFFER (offscreen);
cogl_object_unref (texture);
if (!cogl_framebuffer_allocate (framebuffer, error))
return FALSE;
clutter_stage_paint_to_framebuffer (stage, framebuffer,
rect, scale, paint_flags);
bitmap = cogl_bitmap_new_for_data (cogl_context,
texture_width, texture_height,
format,
stride,
data);
cogl_framebuffer_read_pixels_into_bitmap (framebuffer,
0, 0,
COGL_READ_PIXELS_COLOR_BUFFER,
bitmap);
cogl_object_unref (bitmap);
cogl_object_unref (framebuffer);
return TRUE;
}
static void
capture_view_into (ClutterStage *stage,
gboolean paint,
@@ -4310,8 +4409,11 @@ clutter_stage_thaw_updates (ClutterStage *stage)
}
}
/**
* clutter_stage_peek_stage_views: (skip)
*/
GList *
_clutter_stage_peek_stage_views (ClutterStage *stage)
clutter_stage_peek_stage_views (ClutterStage *stage)
{
ClutterStagePrivate *priv = stage->priv;

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);
@@ -375,31 +359,29 @@ static gboolean
swap_framebuffer (ClutterStageWindow *stage_window,
ClutterStageView *view,
cairo_region_t *swap_region,
gboolean swap_with_damage,
cairo_region_t *queued_redraw_clip)
gboolean swap_with_damage)
{
CoglFramebuffer *framebuffer = clutter_stage_view_get_onscreen (view);
int *damage, n_rects, i;
if (G_UNLIKELY ((clutter_paint_debug_flags & CLUTTER_DEBUG_PAINT_DAMAGE_REGION)))
paint_damage_region (stage_window, view, swap_region, queued_redraw_clip);
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)
@@ -434,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,
@@ -467,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);
@@ -491,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)
{
@@ -610,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;
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);
@@ -638,12 +570,14 @@ 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))
queued_redraw_clip = cairo_region_copy (redraw_clip);
/* NB: a NULL redraw clip == full stage redraw */
if (!redraw_clip)
@@ -651,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
{
@@ -711,48 +629,40 @@ clutter_stage_cogl_redraw_view (ClutterStageWindow *stage_window,
redraw_clip = cairo_region_create_rectangle (&view_rect);
}
queued_redraw_clip = cairo_region_copy (redraw_clip);
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);
@@ -764,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);
@@ -822,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
@@ -904,59 +702,56 @@ 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 (&queued_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;
}
res = swap_framebuffer (stage_window,
view,
swap_region,
swap_with_damage,
queued_redraw_clip);
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)
{
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
clutter_stage_cogl_scanout_view (ClutterStageCogl *stage_cogl,
ClutterStageView *view,
CoglScanout *scanout)
{
CoglFramebuffer *framebuffer = clutter_stage_view_get_framebuffer (view);
CoglOnscreen *onscreen;
g_return_if_fail (cogl_is_onscreen (framebuffer));
onscreen = COGL_ONSCREEN (framebuffer);
cogl_onscreen_direct_scanout (onscreen, scanout);
}
static void
@@ -971,11 +766,23 @@ clutter_stage_cogl_redraw (ClutterStageWindow *stage_window)
for (l = _clutter_stage_window_get_views (stage_window); l; l = l->next)
{
ClutterStageView *view = l->data;
g_autoptr (CoglScanout) scanout = NULL;
if (!clutter_stage_view_has_redraw_clip (view))
continue;
swap_event |= clutter_stage_cogl_redraw_view (stage_window, view);
scanout = clutter_stage_view_take_scanout (view);
if (scanout)
{
clutter_stage_cogl_scanout_view (stage_cogl,
view,
scanout);
swap_event = TRUE;
}
else
{
swap_event |= clutter_stage_cogl_redraw_view (stage_window, view);
}
}
_clutter_stage_emit_after_paint (stage_cogl->wrapper);
@@ -1055,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 = []
@@ -337,35 +333,20 @@ clutter_build_config_h = configure_file(
)
clutter_built_private_headers += clutter_build_config_h
clutter_config_defines = []
cdata = configuration_data()
if have_wayland
clutter_config_defines += [
'#define CLUTTER_HAS_WAYLAND_COMPOSITOR_SUPPORT 1',
]
cdata.set10('CLUTTER_HAS_WAYLAND_COMPOSITOR_SUPPORT', true)
endif
if have_x11
clutter_config_defines += [
'#define CLUTTER_WINDOWING_X11 "x11"',
'#define CLUTTER_INPUT_X11 "x11"',
'#define CLUTTER_WINDOWING_GLX "glx"',
]
cdata.set_quoted('CLUTTER_WINDOWING_X11', 'x11')
cdata.set_quoted('CLUTTER_INPUT_X11', 'x11')
cdata.set_quoted('CLUTTER_WINDOWING_GLX', 'glx')
endif
if have_native_backend
clutter_config_defines += [
'#define CLUTTER_WINDOWING_EGL "eglnative"',
'#define CLUTTER_INPUT_EVDEV "evdev"',
]
cdata.set_quoted('CLUTTER_WINDOWING_EGL', 'eglnative')
cdata.set_quoted('CLUTTER_INPUT_EVDEV', 'evdev')
endif
clutter_config_defines += [
'#define CLUTTER_INPUT_NULL "null"',
]
clutter_config_defines_string = ''
foreach clutter_config_define : clutter_config_defines
clutter_config_defines_string += clutter_config_define + '\n'
endforeach
cdata = configuration_data()
cdata.set('CLUTTER_CONFIG_DEFINES', clutter_config_defines_string)
cdata.set_quoted('CLUTTER_INPUT_NULL', 'null')
clutter_config_h = configure_file(
input: 'clutter-config.h.in',

View File

@@ -74,7 +74,7 @@ PangoFontMap *
cogl_pango_font_map_new (void)
{
PangoFontMap *fm = pango_cairo_font_map_new ();
CoglPangoFontMapPriv *priv = g_new0 (CoglPangoFontMapPriv, 1);
g_autofree CoglPangoFontMapPriv *priv = g_new0 (CoglPangoFontMapPriv, 1);
_COGL_GET_CONTEXT (context, NULL);
@@ -85,7 +85,7 @@ cogl_pango_font_map_new (void)
* for now. */
g_object_set_qdata_full (G_OBJECT (fm),
cogl_pango_font_map_get_priv_key (),
priv,
g_steal_pointer (&priv),
free_priv);
return fm;

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

@@ -93,10 +93,12 @@ _cogl_onscreen_init_from_template (CoglOnscreen *onscreen,
CoglOnscreen *
_cogl_onscreen_new (void)
{
CoglOnscreen *onscreen = g_new0 (CoglOnscreen, 1);
g_autofree CoglOnscreen *onscreen_ptr = g_new0 (CoglOnscreen, 1);
CoglOnscreen *onscreen;
_COGL_GET_CONTEXT (ctx, NULL);
onscreen = g_steal_pointer (&onscreen_ptr);
_cogl_framebuffer_init (COGL_FRAMEBUFFER (onscreen),
ctx,
COGL_FRAMEBUFFER_TYPE_ONSCREEN,
@@ -403,6 +405,27 @@ cogl_onscreen_get_buffer_age (CoglOnscreen *onscreen)
return winsys->onscreen_get_buffer_age (onscreen);
}
void
cogl_onscreen_direct_scanout (CoglOnscreen *onscreen,
CoglScanout *scanout)
{
CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
const CoglWinsysVtable *winsys;
CoglFrameInfo *info;
g_return_if_fail (framebuffer->type == COGL_FRAMEBUFFER_TYPE_ONSCREEN);
g_return_if_fail (_cogl_winsys_has_feature (COGL_WINSYS_FEATURE_SYNC_AND_COMPLETE_EVENT));
info = _cogl_frame_info_new ();
info->frame_counter = onscreen->frame_counter;
g_queue_push_tail (&onscreen->pending_frame_infos, info);
winsys = _cogl_framebuffer_get_winsys (framebuffer);
winsys->onscreen_direct_scanout (onscreen, scanout);
onscreen->frame_counter++;
}
#ifdef COGL_HAS_X11_SUPPORT
uint32_t
cogl_x11_onscreen_get_window_xid (CoglOnscreen *onscreen)

View File

@@ -50,6 +50,8 @@ G_BEGIN_DECLS
typedef struct _CoglOnscreen CoglOnscreen;
#define COGL_ONSCREEN(X) ((CoglOnscreen *)(X))
typedef struct _CoglScanout CoglScanout;
/**
* cogl_onscreen_get_gtype:
*
@@ -284,6 +286,13 @@ cogl_onscreen_swap_buffers_with_damage (CoglOnscreen *onscreen,
const int *rectangles,
int n_rectangles);
/**
* cogl_onscreen_direct_scanout: (skip)
*/
COGL_EXPORT void
cogl_onscreen_direct_scanout (CoglOnscreen *onscreen,
CoglScanout *scanout);
/**
* cogl_onscreen_swap_region:
* @onscreen: A #CoglOnscreen framebuffer

View File

@@ -50,7 +50,7 @@ struct _CoglPipelineCache
CoglPipelineCache *
_cogl_pipeline_cache_new (void)
{
CoglPipelineCache *cache = g_new (CoglPipelineCache, 1);
g_autofree CoglPipelineCache *cache = g_new (CoglPipelineCache, 1);
unsigned long vertex_state;
unsigned long layer_vertex_state;
unsigned int fragment_state;
@@ -80,7 +80,7 @@ _cogl_pipeline_cache_new (void)
layer_vertex_state | layer_fragment_state,
"programs");
return cache;
return g_steal_pointer (&cache);
}
void

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,

27
cogl/cogl/cogl-scanout.c Normal file
View File

@@ -0,0 +1,27 @@
/*
* Copyright (C) 2019 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 "cogl-config.h"
#include "cogl-scanout.h"
G_DEFINE_INTERFACE (CoglScanout, cogl_scanout, G_TYPE_OBJECT)
static void
cogl_scanout_default_init (CoglScanoutInterface *iface)
{
}

35
cogl/cogl/cogl-scanout.h Normal file
View File

@@ -0,0 +1,35 @@
/*
* Copyright (C) 2019 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 COGL_SCANOUT_H
#define COGL_SCANOUT_H
#include "cogl/cogl-types.h"
#include <glib-object.h>
#define COGL_TYPE_SCANOUT (cogl_scanout_get_type ())
COGL_EXPORT
G_DECLARE_INTERFACE (CoglScanout, cogl_scanout,
COGL, SCANOUT, GObject)
struct _CoglScanoutInterface
{
GTypeInterface parent_iface;
};
#endif /* COGL_SCANOUT_H */

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

@@ -122,6 +122,7 @@
#include <cogl/cogl-fence.h>
#include <cogl/cogl-glib-source.h>
#include <cogl/cogl-trace.h>
#include <cogl/cogl-scanout.h>
/* XXX: This will definitly go away once all the Clutter winsys
* code has been migrated down into Cogl! */
#include <cogl/deprecated/cogl-clutter.h>

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

@@ -122,6 +122,7 @@ cogl_nonintrospected_headers = [
'cogl-version.h',
'cogl-gtype-private.h',
'cogl-glib-source.h',
'cogl-scanout.h',
]
cogl_nodist_headers = [
@@ -347,6 +348,7 @@ cogl_sources = [
'cogl-closure-list.c',
'cogl-fence.c',
'cogl-fence-private.h',
'cogl-scanout.c',
'deprecated/cogl-material-compat.c',
'deprecated/cogl-program.c',
'deprecated/cogl-program-private.h',

View File

@@ -33,6 +33,7 @@
#include "cogl-renderer.h"
#include "cogl-onscreen.h"
#include "cogl-scanout.h"
#ifdef COGL_HAS_XLIB_SUPPORT
#include "cogl-texture-pixmap-x11-private.h"
@@ -117,6 +118,10 @@ typedef struct _CoglWinsysVtable
const int *rectangles,
int n_rectangles);
void
(*onscreen_direct_scanout) (CoglOnscreen *onscreen,
CoglScanout *scanout);
void
(*onscreen_set_visibility) (CoglOnscreen *onscreen,
gboolean visibility);

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

@@ -70,3 +70,12 @@
/* Whether Xwayland has -initfd option */
#mesondefine HAVE_XWAYLAND_INITFD
/* Whether the mkostemp function exists */
#mesondefine HAVE_MKOSTEMP
/* Whether the posix_fallocate function exists */
#mesondefine HAVE_POSIX_FALLOCATE
/* Whether the memfd_create function exists */
#mesondefine HAVE_MEMFD_CREATE

View File

@@ -1,5 +1,5 @@
project('mutter', 'c',
version: '3.37.0',
version: '3.37.1',
meson_version: '>= 0.50.0',
license: 'GPLv2+'
)
@@ -408,6 +408,20 @@ if have_wayland
endif
endif
optional_functions = [
'mkostemp',
'posix_fallocate',
'memfd_create',
]
foreach function : optional_functions
if cc.has_function(function)
cdata.set('HAVE_' + function.to_upper(), 1)
else
message('Optional function ' + function + ' missing')
endif
endforeach
xwayland_grab_default_access_rules = get_option('xwayland_grab_default_access_rules')
cdata.set_quoted('XWAYLAND_GRAB_DEFAULT_ACCESS_RULES',
xwayland_grab_default_access_rules)
@@ -473,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

@@ -13,8 +13,8 @@ msgid ""
msgstr ""
"Project-Id-Version: mutter master\n"
"Report-Msgid-Bugs-To: https://gitlab.gnome.org/GNOME/mutter/issues\n"
"POT-Creation-Date: 2019-08-06 00:49+0000\n"
"PO-Revision-Date: 2019-09-05 23:42+0200\n"
"POT-Creation-Date: 2020-03-30 20:11+0000\n"
"PO-Revision-Date: 2020-04-06 23:13+0200\n"
"Last-Translator: Christian Kirbach <christian.kirbach@gmail.com>\n"
"Language-Team: Deutsch <gnome-de@gnome.org>\n"
"Language: de\n"
@@ -22,7 +22,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
"X-Generator: Poedit 2.2.1\n"
"X-Generator: Poedit 2.3\n"
#: data/50-mutter-navigation.xml:6
msgid "Navigation"
@@ -435,20 +435,33 @@ msgstr "Zusatztaste zum Finden des Zeigers"
msgid "This key will initiate the “locate pointer” action."
msgstr "Diese Taste wird die Aktion »Zeiger finden« auslösen."
#: data/org.gnome.mutter.gschema.xml.in:155
#: data/org.gnome.mutter.gschema.xml.in:142
msgid "Timeout for check-alive ping"
msgstr "Reaktionsschwellwert bei Kontaktkontrolle"
#: data/org.gnome.mutter.gschema.xml.in:143
msgid ""
"Number of milliseconds a client has to respond to a ping request in order to "
"not be detected as frozen. Using 0 will disable the alive check completely."
msgstr ""
"Zeit in Millisekunden, innerhalb welcher ein Client auf eine "
"Kontaktkontrolle antworten muss, um nicht als abgestürzt zu gelten. »0« "
"bedeutet, dass die Kontaktkontrolle ausgeschaltet wird."
#: data/org.gnome.mutter.gschema.xml.in:165
msgid "Select window from tab popup"
msgstr "Fenster aus Tab-Anzeige auswählen"
#: data/org.gnome.mutter.gschema.xml.in:160
#: data/org.gnome.mutter.gschema.xml.in:170
msgid "Cancel tab popup"
msgstr "Tab-Anzeige abbrechen"
#: data/org.gnome.mutter.gschema.xml.in:165
#: data/org.gnome.mutter.gschema.xml.in:175
msgid "Switch monitor configurations"
msgstr "Bildschirmkonfigurationen wechseln"
# Ich denke nicht, dass »rotate« hier die Bildschirmdrehung meint, sondern eher eine Liste aus Konfigurationen rotiert (d.h. umgewälzt) wird.
#: data/org.gnome.mutter.gschema.xml.in:170
#: data/org.gnome.mutter.gschema.xml.in:180
msgid "Rotates the built-in monitor configuration"
msgstr "Wechselt die Konfiguration des eingebauten Bildschirms"
@@ -569,7 +582,7 @@ msgstr ""
#. TRANSLATORS: This string refers to a button that switches between
#. * different modes.
#.
#: src/backends/meta-input-settings.c:2531
#: src/backends/meta-input-settings.c:2631
#, c-format
msgid "Mode Switch (Group %d)"
msgstr "Moduswechsel (Gruppe %d)"
@@ -577,34 +590,34 @@ msgstr "Moduswechsel (Gruppe %d)"
#. TRANSLATORS: This string refers to an action, cycles drawing tablets'
#. * mapping through the available outputs.
#.
#: src/backends/meta-input-settings.c:2554
#: src/backends/meta-input-settings.c:2654
msgid "Switch monitor"
msgstr "Bildschirm wechseln"
#: src/backends/meta-input-settings.c:2556
#: src/backends/meta-input-settings.c:2656
msgid "Show on-screen help"
msgstr "Bildschirmhilfe anzeigen"
#: src/backends/meta-monitor.c:223
#: src/backends/meta-monitor.c:226
msgid "Built-in display"
msgstr "Eingebaute Anzeige"
#: src/backends/meta-monitor.c:252
#: src/backends/meta-monitor.c:255
msgid "Unknown"
msgstr "Unbekannt"
#: src/backends/meta-monitor.c:254
#: src/backends/meta-monitor.c:257
msgid "Unknown Display"
msgstr "Unbekannte Anzeige"
#: src/backends/meta-monitor.c:262
#: src/backends/meta-monitor.c:265
#, c-format
msgctxt ""
"This is a monitor vendor name, followed by a size in inches, like 'Dell 15\"'"
msgid "%s %s"
msgstr "%s %s"
#: src/backends/meta-monitor.c:270
#: src/backends/meta-monitor.c:273
#, c-format
msgctxt ""
"This is a monitor vendor name followed by product/model name where size in "
@@ -614,13 +627,13 @@ msgstr "%s %s"
# https://de.wikipedia.org/wiki/Composition-Manager
#. Translators: this string will appear in Sysprof
#: src/backends/meta-profiler.c:82
#: src/backends/meta-profiler.c:79
msgid "Compositor"
msgstr "Compositor"
#. This probably means that a non-WM compositor like xcompmgr is running;
#. * we have no way to get it to exit
#: src/compositor/compositor.c:510
#: src/compositor/compositor.c:533
#, c-format
msgid ""
"Another compositing manager is already running on screen %i on display “%s”."
@@ -632,47 +645,47 @@ msgstr ""
msgid "Bell event"
msgstr "Klangereignis"
#: src/core/main.c:185
#: src/core/main.c:190
msgid "Disable connection to session manager"
msgstr "Verbindung zur Sitzungsverwaltung deaktivieren"
#: src/core/main.c:191
#: src/core/main.c:196
msgid "Replace the running window manager"
msgstr "Den aktuellen Fensterverwalter ersetzen"
#: src/core/main.c:197
#: src/core/main.c:202
msgid "Specify session management ID"
msgstr "Kennung der Sitzungsverwaltung angeben"
#: src/core/main.c:202
#: src/core/main.c:207
msgid "X Display to use"
msgstr "Zu verwendende X-Anzeige"
#: src/core/main.c:208
#: src/core/main.c:213
msgid "Initialize session from savefile"
msgstr "Sitzung anhand gespeicherter Datei starten"
#: src/core/main.c:214
#: src/core/main.c:219
msgid "Make X calls synchronous"
msgstr "X-Aufrufe abgleichen"
#: src/core/main.c:221
#: src/core/main.c:226
msgid "Run as a wayland compositor"
msgstr "Als Wayland-Compositor ausführen"
#: src/core/main.c:227
#: src/core/main.c:232
msgid "Run as a nested compositor"
msgstr "Als eingebetteten Compositor ausführen"
#: src/core/main.c:233
#: src/core/main.c:238
msgid "Run wayland compositor without starting Xwayland"
msgstr "Wayland-Compositor ausführen, ohne Xwayland zu starten"
#: src/core/main.c:241
#: src/core/main.c:246
msgid "Run as a full display server, rather than nested"
msgstr "Als vollwertigen Display-Server verwenden (nicht eingebettet)"
#: src/core/main.c:247
#: src/core/main.c:252
msgid "Run with X11 backend"
msgstr "Mit X11-Backend ausführen"
@@ -728,21 +741,21 @@ msgstr "Version ausgeben"
msgid "Mutter plugin to use"
msgstr "Zu benutzendes Mutter-Plugin"
#: src/core/prefs.c:1849
#: src/core/prefs.c:1911
#, c-format
msgid "Workspace %d"
msgstr "Arbeitsfläche %d"
#: src/core/util.c:121
#: src/core/util.c:122
msgid "Mutter was compiled without support for verbose mode\n"
msgstr "Mutter wurde ohne Unterstützung für den redseligen Modus kompiliert\n"
#: src/wayland/meta-wayland-tablet-pad.c:567
#: src/wayland/meta-wayland-tablet-pad.c:568
#, c-format
msgid "Mode Switch: Mode %d"
msgstr "Moduswechsel: Modus %d"
#: src/x11/meta-x11-display.c:671
#: src/x11/meta-x11-display.c:676
#, c-format
msgid ""
"Display “%s” already has a window manager; try using the --replace option to "
@@ -751,21 +764,21 @@ msgstr ""
"Bildschirm »%s« hat bereits einen Fensterverwalter. Versuchen Sie die Option "
"»--replace«, um den aktuellen Fensterverwalter zu ersetzen."
#: src/x11/meta-x11-display.c:1032
#: src/x11/meta-x11-display.c:1089
msgid "Failed to initialize GDK\n"
msgstr "GDK konnte nicht initialisiert werden\n"
#: src/x11/meta-x11-display.c:1056
#: src/x11/meta-x11-display.c:1113
#, c-format
msgid "Failed to open X Window System display “%s”\n"
msgstr "X-Window-Systemanzeige »%s« konnte nicht geöffnet werden\n"
#: src/x11/meta-x11-display.c:1140
#: src/x11/meta-x11-display.c:1196
#, c-format
msgid "Screen %d on display “%s” is invalid\n"
msgstr "Bildschirm %d auf Anzeige »%s« ist ungültig\n"
#: src/x11/meta-x11-selection-input-stream.c:445
#: src/x11/meta-x11-selection-input-stream.c:460
#, c-format
msgid "Format %s not supported"
msgstr "Format %s wird nicht unterstützt"

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

@@ -49,8 +49,11 @@ typedef struct _MetaTileInfo MetaTileInfo;
typedef struct _MetaRenderer MetaRenderer;
typedef struct _MetaRendererView MetaRendererView;
typedef struct _MetaRemoteDesktop MetaRemoteDesktop;
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
@@ -552,12 +560,12 @@ meta_backend_real_post_init (MetaBackend *backend)
}
#ifdef HAVE_REMOTE_DESKTOP
priv->remote_access_controller =
g_object_new (META_TYPE_REMOTE_ACCESS_CONTROLLER, NULL);
priv->dbus_session_watcher = g_object_new (META_TYPE_DBUS_SESSION_WATCHER, NULL);
priv->screen_cast = meta_screen_cast_new (backend,
priv->dbus_session_watcher);
priv->remote_desktop = meta_remote_desktop_new (priv->dbus_session_watcher);
priv->remote_access_controller =
meta_remote_access_controller_new (priv->remote_desktop, priv->screen_cast);
#endif /* HAVE_REMOTE_DESKTOP */
if (!meta_monitor_manager_is_headless (priv->monitor_manager))
@@ -809,9 +817,6 @@ static MetaMonitorManager *
meta_backend_create_monitor_manager (MetaBackend *backend,
GError **error)
{
if (g_getenv ("META_DUMMY_MONITORS"))
return g_object_new (META_TYPE_MONITOR_MANAGER_DUMMY, NULL);
return META_BACKEND_GET_CLASS (backend)->create_monitor_manager (backend,
error);
}
@@ -867,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,
@@ -905,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;
}
@@ -920,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)
*/
@@ -1261,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)
{
@@ -1323,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)
{
@@ -1347,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

@@ -172,6 +172,7 @@ assign_monitor_crtc (MetaMonitor *monitor,
MetaCrtc *crtc;
MetaMonitorTransform transform;
MetaMonitorTransform crtc_transform;
MetaMonitorTransform crtc_hw_transform;
int crtc_x, crtc_y;
float x_offset, y_offset;
float scale = 0.0;
@@ -200,10 +201,12 @@ assign_monitor_crtc (MetaMonitor *monitor,
transform = data->logical_monitor_config->transform;
crtc_transform = meta_monitor_logical_to_crtc_transform (monitor, transform);
if (!meta_monitor_manager_is_transform_handled (data->monitor_manager,
crtc,
crtc_transform))
crtc_transform = META_MONITOR_TRANSFORM_NORMAL;
if (meta_monitor_manager_is_transform_handled (data->monitor_manager,
crtc,
crtc_transform))
crtc_hw_transform = crtc_transform;
else
crtc_hw_transform = META_MONITOR_TRANSFORM_NORMAL;
meta_monitor_calculate_crtc_pos (monitor, mode, output, crtc_transform,
&crtc_x, &crtc_y);
@@ -244,7 +247,7 @@ assign_monitor_crtc (MetaMonitor *monitor,
.crtc = crtc,
.mode = crtc_mode,
.layout = crtc_layout,
.transform = crtc_transform,
.transform = crtc_hw_transform,
.outputs = g_ptr_array_new ()
};
g_ptr_array_add (crtc_info->outputs, output);
@@ -443,23 +446,35 @@ MetaMonitorsConfigKey *
meta_create_monitors_config_key_for_current_state (MetaMonitorManager *monitor_manager)
{
MetaMonitorsConfigKey *config_key;
MetaMonitorSpec *laptop_monitor_spec;
GList *l;
GList *monitor_specs;
laptop_monitor_spec = NULL;
monitor_specs = NULL;
for (l = monitor_manager->monitors; l; l = l->next)
{
MetaMonitor *monitor = l->data;
MetaMonitorSpec *monitor_spec;
if (meta_monitor_is_laptop_panel (monitor) &&
is_lid_closed (monitor_manager))
continue;
if (meta_monitor_is_laptop_panel (monitor))
{
laptop_monitor_spec = meta_monitor_get_spec (monitor);
if (is_lid_closed (monitor_manager))
continue;
}
monitor_spec = meta_monitor_spec_clone (meta_monitor_get_spec (monitor));
monitor_specs = g_list_prepend (monitor_specs, monitor_spec);
}
if (!monitor_specs && laptop_monitor_spec)
{
monitor_specs =
g_list_prepend (NULL, meta_monitor_spec_clone (laptop_monitor_spec));
}
if (!monitor_specs)
return NULL;

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