Compare commits

...

66 Commits

Author SHA1 Message Date
9321249b8d wayland: Implement the "inputfd" wayland protocols
This allows lending control to applications of evdev devices,
and withdrawing it with focus.
2020-06-10 20:32:19 +02:00
932340a989 background-content: Shut up warning
https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1303
2020-06-10 10:42:18 +02:00
ca0156e9a7 background-content: Render background slices relative to actor box
The current code assumes that the actor will always have the same
size and position of the background texture, but part of the implicit
contract of being a ClutterContent is being able to render itself
at any given actor, at any given size.

For example, if the current code is given an actor with 0x0+100+100
as geometry, and no clipped region, it'll render not the whole
background, but the 0x0+100+100 rectangle of the background. In
practice, the actor geometry acts like a "clip mask" over the
background texture, due to the assumption that the actor will
always have the same size of the monitor.

Make the calculation of the texture slices relative to the actor
box.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1302
2020-06-09 17:07:02 -03:00
6d75b4fc53 background-content: Simplify method call
It's always passing the same pipeline and texture rect, simplify
by passing the MetaBackgroundContent instance itself.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1302
2020-06-09 17:07:02 -03:00
6bd382ad23 background-actor: Use MetaBackgroundContent
MetaBackgroundActor is still necessary for culling purposes,
but now the actual rendering of the background is delegated
to MetaBackgroundContent, as well as the sizing information.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1302
2020-06-09 17:07:02 -03:00
a1b3d1a2a7 Introduce MetaBackgroundContent
MetaBackgroundContent is a ClutterContent implementation
that can render a background to any attached actor. Right
now, it preserves all the properties and the rendering
model of MetaBackgroundActor.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1302
2020-06-09 17:07:02 -03:00
53f61f3778 stack-tracker: Don't log warnings on race conditions
X11 window stacking operations are by nature prone to race conditions.
For example, we might queue a "raise above" operation, but before it
actually takes place, the sibling the window was to be rased above, is
withdrawn.

In these cases we'd log warnings even though they are expected to
happen. Downgrade these warnings to debug messages, only printed when
MUTTER_VERBOSE is set.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1300
2020-06-09 18:46:38 +00:00
74c0d9140c stack-tracker: Fix coding style of meta_stack_op_apply()
Change tabs to spaces, clean up variable declarations.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1300
2020-06-09 18:46:38 +00:00
268336c21a clutter/actor: Allow animating content properties
ClutterActor allows animating effects, constraints, actions,
and the layout manager for property transitions. Extend this
functionality to the content as well.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1301
2020-06-09 15:09:26 -03:00
49e983b06e tests: Add a test for ClutterActors stage_views() API
Test that the stage-views list of ClutterActor is correct when moving an
actor, reparenting it, or hiding an actor up the hierarchy. Also test
that the "stage-views-changed" signal works as expected.

Don't test actor transforms for now because those aren't supported yet.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1196
2020-06-09 16:07:46 +00:00
0f97196d84 clutter/actor: Don't traverse whole actor tree for updating stage-views
We currently go through the whole tree of mapped actors on every paint
cycle to update the stage views actors are on. Even if no actors need
updating of their stage views, traversing the actor tree is still quite
expensive and shows up when using a profiler.

So tone down the amounts of full-tree traversals we have to do on every
paint cycle and only traverse a subtree if it includes an actor which
actually needs updating of its stage views.

We do that by setting the `needs_update_stage_views` flag to TRUE
recursively for all parents up to the stage when the stage-views list of
an actor gets invalidated. This way we end up updating a few more actors
than necessary, but can avoid searching the whole actor tree for actors
which have `needs_update_stage_views` set to TRUE.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1196
2020-06-09 16:07:46 +00:00
18c792d6f8 clutter/actor: Emit a signal when the stage-views an actor is on change
Add a new signal that's emitted when the stage views an actor being
painted on have changed, "stage-views-changed". For example this signal
can be helpful when tracking whether an actor is painted on multiple
stage views or only one.

Since we must clear the stage-views list when an actor leaves the stage
(actors that aren't attached to a stage don't get notified about the
stage views being changed/replaced), we also emit the new signal when an
actor gets detached from the stage (otherwise there would be an edge
case where no signal is emitted but it really should: An actor is
visible on a stage view, then detached from the stage, and then attached
again and immeditely moved outside the view).

Also skip the comparison of the old stage-views list and the new one if
nobody is listening to the signal to save some resources.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1196
2020-06-09 16:07:46 +00:00
675a97d58e clutter/actor: Add API to get the stage-views an actor is painted on
There are certain rendering techniques and optimizations, for example
the unredirection of non-fullscreen windows, where information about the
output/stage-view an actor is on is needed to determine whether the
optimization can be enabled.

So add a new method to ClutterActor that allows listing the stage-views
the actor is being painted on: clutter_actor_peek_stage_views()

With the way Clutter works, the only point where we can reliably get
this information is during or right before the paint phase, when the
layout phase of the stage has been completed and no more changes to the
actors transformation matrices happen. So to get the stage views the
actor is on, introduce a new step that's done on every master clock tick
between layout and paint cycle: Traversing through the actor tree and
updating the stage-views the mapped actors are going to be painted on.

We're doing this in a separate step instead of inside
clutter_actor_paint() itself for a few reasons: It keeps the code
separate from the painting code, making profiling easier and issues
easier to track down (hopefully), it allows for a new
"stage-views-changed" signal that doesn't interfere with painting, and
finally, it will make it very easy to update the resource scales in the
same step in the future.

Currently, this list is only invalidated on allocation changes of
actors, but not on changes to the transformation matrices. That's
because there's no proper API to invalidate the transformation matrices
ClutterActor implementations can apply through the apply_transform()
vfunc.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1196
2020-06-09 16:07:46 +00:00
8127494e52 clutter/stage: Rename update_resource_scales to clear_stage_views
When the stage views the stage is shown on are changed, ClutterStage
currently provides a clutter_stage_update_resource_scales() method
that allows invalidating the resource scales of all actors. With the new
stage-views API that's going to be added to ClutterActor, we also need a
method to invalidate the stage-views lists of actors in case the stage
views are rebuilt and fortunately we can re-use the infrastructure for
invalidating resource scales for that.

So since resource scales depend on the stage views an actor is on,
rename clutter_stage_update_resource_scales() and related methods to
clutter_stage_clear_stage_views(), which also covers resource scales.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1196
2020-06-09 16:07:46 +00:00
670f4f22fe clutter/stage: Remove _clutter_stage_get_max_view_scale_factor_for_rect
Since we now have _clutter_stage_get_views_for_rect(), we can easily
replace _clutter_stage_get_max_view_scale_factor_for_rect() with it and
remove that private method.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1196
2020-06-09 16:07:46 +00:00
e27d2702a8 clutter/stage: Add private method to get the stage-views of a rectangle
We'll need this method for implementing a new stage-views-on API for
ClutterActor which lists the stage views an actor is on.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1196
2020-06-09 16:07:46 +00:00
dfe33897db meson_options: Use libGLESv2.so.2 for COGL_DRIVER=gles2, not libGLESv2.so
The former is present on any system that supports OpenGL|ES 2. The latter
is just provided in developer packages. Since we access the library via
`g_module_open` it's safe to just rely on `libGLESv2.so.2`.

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

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1298
2020-06-09 18:32:01 +08:00
90c20b185b clutter/actor: Disconnect from "layout-changed" signal on destroy
While the layout manager of a ClutterActor does get properly unset when
destroying an actor, we currently forget to disconnect the
"layout-changed" signal from it.

So do that, and while at it, also switch to using the signal id for
disconnecting from the signal instead of
g_signal_handlers_disconnect_by_func(), which caused problems before
because it might traverse the signal handler list.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1281
2020-06-08 17:23:05 +00:00
4d7c8d68bc clutter/actor: Mark offscreen-redirect property as flag everywhere
We currently are confusing g_param_spec_enum and g_param_spec_flags for
the offscreen-redirect property of ClutterActor. Since it's actually a
flag, make it a flag everywhere.

Fun fact: This was already partly done with
d7814cf63e, but that commit missed the
setter.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1292
2020-06-08 15:25:11 +00:00
455de5d6d3 clutter/align-constraint: Listen to queue-relayout signal of source
Just like the ClutterBindConstraint, the ClutterAlignConstraint should
listen to "queue-relayout" of its source actor, not
"notify::allocation". That's because the latter will queue a relayout
during an allocation cycle and might cause relayout loops.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1296
2020-06-08 14:58:15 +00:00
99c9f4c1fa wayland/data-device: Don't create and leak unused memory on dnd
"offer" is overwritten with the result of meta_wayland_data_offer_new a
few lines later.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1293
2020-06-08 12:11:11 +00:00
dd32ff018a wayland: Free selection streams streams after transfer
They were only being closed but never freed.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1293
2020-06-08 12:11:11 +00:00
019643bad0 core: Free clipboard selection source on shutdown
The clipboard manager is the only code to ever set the display selection
source, so it should also be responsible for unsetting it when the
clipboard manager gets shut down.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1293
2020-06-08 12:11:11 +00:00
a031ac067e core: Fix memory selection source leak after clipboard owner disappears
When an app disappears after some data from it has been copied to the
clipboard, the owner of the clipboard selection becomes a new memory
selection source. The initial reference this new selection source is
never unref'ed, which leads to this being leaked on the next clipboard
selection owner change.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1293
2020-06-08 12:11:11 +00:00
f712387325 compositor: use XDG_CONFIG_HOME as initial lookup path for xkb
Using XDG_CONFIG_HOME allows users to place their keyboard configuration into
their home directory and have them loaded automatically.
libxkbcommon now defaults to XDG_CONFIG_HOME/xkb/ first, see
https://github.com/xkbcommon/libxkbcommon/pull/117

However - libxkbcommon uses secure_getenv() to obtain XDG_CONFIG_HOME and thus
fails to load this for the mutter context which has cap_sys_nice.
We need to manually add that search path as lookup path.

As we can only append paths to libxkbcommon's context, we need to start with
an empty search path set, add our custom path, then append the default search
paths.

The net effect is nil where a user doesn't have XDG_CONFIG_HOME/xkb/.

https://gitlab.gnome.org/GNOME/mutter/merge_requests/936
2020-06-08 11:29:30 +00:00
1eaf9e5f63 tests/clutter/timeline-interpolate: Maximize error tolerance
Simply to make it less flaky.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1291
2020-06-06 00:27:40 +02:00
7222bdde57 tests/clutter/timeline: Lower FPS even further
It's still flaky running in CI, lets run it even slower.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1291
2020-06-06 00:27:40 +02:00
007d27fa40 tests/conform: Use the clutter stage from mutter
The tests created their own stage, which caused various issues. Lets use
the one from mutter instead.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1289
2020-06-05 21:39:27 +00:00
01609de587 clutter/stage: Clear pick stack when hiding
Hiding a compositor stage is not something that's really supported, but
will still be used by tests, to get closer to a "fresh" stage for each
test case, when the tests eventually start using the mutter provided
stage.

It'll use that stage simply because creating standalone stages isn't
supported.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1289
2020-06-05 21:39:27 +00:00
83ee122fad cogl/frame-info: Stop passing the CoglOutput
It's unused, and if it would be, it'd be unreliable, as it'd only be
valid on the Xlib and GLX cogl backends.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1289
2020-06-05 21:39:27 +00:00
55302dbb38 cursor-renderer: Pass backend to constructor
Then use the backend passed instead of the global singleton.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1289
2020-06-05 21:39:27 +00:00
7876018755 backends/native: Get clutter backend from backend
https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1289
2020-06-05 21:39:27 +00:00
e3c332fa10 backend: Remove unused freeze/thaw functions
They are no longer used, so remove them.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1289
2020-06-05 21:39:27 +00:00
faa831f2f6 backend: Remove cursor renderer construction fallback
All backends have their own cursor renderer constuctors, so remove the
unused fallback.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1289
2020-06-05 21:39:27 +00:00
1a915f06cf clutter: Remove CLUTTER_REPAINT_FLAGS_QUEUE_REDRAW_ON_ADD
It was unused, and will simplify things when we're without a master
clock.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1289
2020-06-05 21:39:27 +00:00
6754195580 clutter/script-parser: Don't skip construct parameters when constructing
The script parser only included G_PARAM_CONSTRUCT_ONLY parameters when
constructing objects. This causes issues if an object requires a
parameter to be set during construction, but may also change after. Fix
this by including G_PARAM_CONSTRUCT parameters when constructing script
objects as well.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1289
2020-06-05 21:39:27 +00:00
25f9406e69 compositor: Get the stage via the backend
We would get the MetaDisplay from the backend singleton before creating
the MetaCompositor, then in MetaCompositor, get the backend singleton
again to get the stage. To get rid of the extra singleton fetching, just
pass the backend the MetaCompositor constructors, and fetch the stage
directly from the backend everytime it's needed.

This also makes it available earlier than before, as we didn't set our
instance private stage pointer until the manage() call.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1289
2020-06-05 21:39:27 +00:00
9fc428f2e7 clutter/stage: Remove unused function clutter_stage_ensure_redraw()
Not used by anything, and redraws are eventually not going to be stage
global anyway.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1289
2020-06-05 21:39:26 +00:00
a05dd813da clutter/timeline: Remove clutter_timeline_clone()
It was deprecated long ago, and users should switch to using te regular
constructors.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1289
2020-06-05 21:39:26 +00:00
08b30d6fe2 clutter/timeline: Remove deprecated 'loop' property
It was since long ago replaced by a 'repeat-count' property.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1289
2020-06-05 21:39:26 +00:00
84f55d38dd clutter/pan-action: Clean up line lengths
The file stood out and was hard to read because lines were very long
compared to the rest of clutter and mutter. Clean that up by cutting
lines into pieces where appropriate.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1289
2020-06-05 21:39:26 +00:00
75b5e079cf clutter/timeline: Add meaning to constructor argument variable name
Start follow the convention used in ClutterFrameClock by including the
meaning as well as time granularity in the variable name. The
constructor takes the intended duration of the constructed timeline in
milli seconds, so call the constructor argument `duration_ms`. This is
done in preparation for adding more constuctors.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1289
2020-06-05 21:39:26 +00:00
d742f9331c tests/clutter: Port timeline-rewind to current test suite
https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1289
2020-06-05 21:39:26 +00:00
420ca31f0b tests/clutter: Port timeline-progress to current test suite
https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1289
2020-06-05 21:39:26 +00:00
73da901cd3 tests/clutter: Port timeline-interpolate to current test suite
The error tolerance is increased dramatically to make the test less
flaky when running in CI.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1289
2020-06-05 21:39:26 +00:00
dd16fac0c7 tests/clutter: Port timeline tests to current test suite
Also fix a test that dependends on a specific element order in a list
that wasn't defined to have any particular order.

The frames per second is decreased from 30 to 10, to make the test less
flaky when running in CI.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1289
2020-06-05 21:39:26 +00:00
1b2af2891f tests/clutter/conform: Default to print test logs
To change to the old behavior, pass --quiet. The aim is to be make it
easier to debug issues only reproducing in the CI.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1289
2020-06-05 21:39:26 +00:00
050c21c24f tests/clutter/conform: Don't run tests in parallel
Might end up failing to acquire D-Bus names, resulting in warnings.
Avoid that by not running the tests in parallel.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1289
2020-06-05 21:39:26 +00:00
7b45de941b tests/test-client: Disable shadow for Wayland client too
The shadow was disabled for the X11 client as it was far to unreliable
when comparing sizes.

It seems that the Wayland backend has been somewhat unreliable as well,
where some race condition causing incorrect sizes thus a flaky test.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1288
2020-06-05 00:15:52 +02:00
8d84449941 test-runner: Wait before finding MetaWindow when showing
A "show" command calls gtk_window_show() and gdk_display_sync(), then
returns. This means that the X11 window objects are guaranteed to have
been created in the X11 server.

After that, the test runner will look up the window's associated
MetaWindow and wait for it to be shown.

What this doesn't account for is if mutter didn't get enough CPU time to
see the new window. When this happens, the 'default-size' stacking test
sometimes failed after hiding and showing the X11 window.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1288
2020-06-05 00:15:52 +02:00
f61d4b4e70 Bump version to 3.37.2
Update NEWS.
2020-06-03 01:11:15 +02:00
dcb42d3b25 clutter/actor: Sanity check new allocations
Apparently some shell extensions are setting invalid NaN allocations,
leading to weird crashes like
https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/1849.

Even though an implementation error like this probably deserves a crash,
those can be hard to debug since the crash can happen anywhere the
allocation is being used later. So let Clutter be the good guy and
prevent implementations from setting invalid allocations by
sanity-checking the ClutterActorBoxes using g_return_if_fail.

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

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1280
2020-06-02 20:53:12 +00:00
59a2bff8e2 cogl tests: Normally skip tests that are not expected to succeed
If a test is not expected to succeed, then running it could be considered
to be a waste of resources, particularly if the failure might manifest
as an indefinite hang (see cogl!11), or if the test is likely to dump core
and trigger "expensive" crash-reporting mechanisms like systemd-coredump,
corekeeper, abrt or apport.

Skip the tests that are expected to fail. They can still be requested via
an environment variable, which can be set after fixing a bug to check which
tests are now passing.

Originally cogl!15, adapted for mutter's fork of cogl to use gboolean
instead of CoglBool.

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

Signed-off-by: Simon McVittie <smcv@debian.org>
2020-06-02 20:15:26 +00:00
720360b07a clutter/actor: Don't allocate actors if only the absolute origin changed
For actors which don't have needs_allocation set to TRUE and where the
new allocation wouldn't be different from the old one, the allocate()
vfunc doesn't have to be called. We still did this in case a parent
actor was moved though (so the absolute origin changed), because we
needed to propagate the ABSOLUTE_ORIGIN_CHANGED allocation flag down to
all actors.

Since that flag is now removed and got replaced with a private property,
we can simply notify the children about the absolute allocation change
using the existing infrastructure and safely stop allocating children at
this point.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1247
2020-06-02 19:44:42 +00:00
9b39e37fee clutter/actor: Notify hidden actors about absolute allocation changes
With commit 0eab73dc2e we introduced an optimization of not doing
allocations for actors which are hidden. This broke the propagation of
absolute origin changes to hidden actors, so if an actor is moved while
its child is hidden, the child will not get
priv->needs_compute_resource_scale set to TRUE, which means the resource
scale won't be updated when the child gets mapped and shown again.

Since we now have priv->absolute_origin_changed, we can simply check
whether that is TRUE for our parent before bailing out of
clutter_actor_allocate() and if it is, notify the whole hidden sub-tree
about the absolute origin change.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1247
2020-06-02 19:44:42 +00:00
38104755a2 clutter/stage: Make set_viewport() a static method
Since clutter_stage_set_viewport() is only used inside clutter-stage.c
anyway, we can make it a static method. Also we can remove the x and y
arguments from it since they're always set to 0 anyway.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1247
2020-06-02 19:44:42 +00:00
7abf0f1e2d clutter/stage: Set viewport without getting the last allocation
When getting the last allocation using
clutter_actor_get_allocation_box(), Clutter will do an immediate
relayout of the stage in case an actor has an invalid allocation. Since
the allocation is always invalid when the allocate() vfunc is called,
clutter_stage_allocate() always forces another allocation cycle.

To fix that, stop comparing the old allocation to the new one to find
out whether the viewport changed, but instead use the existing check in
_clutter_stage_set_viewport() and implement the behavior of rounding the
viewport to the nearest int using roundf() (which should behave just as
CLUTTER_NEARBYINT()) since we're passing around floats anyway.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1247
2020-06-02 19:44:42 +00:00
0a37c32a72 clutter/actor: Update absolute_origin_changed inside set_allocation()
When manipulating the allocation of a ClutterActor from an allocate()
vfunc override, clutter_actor_set_allocation() is used to let Clutter
know about the changes.

If the actors allocation or its absolute origin did not change before
that, this can also affect the actors absolute_origin_changed property
used by the children to detect changes to their absolute position.

So fix this bug (which luckily didn't seem to affect us so far) and set
priv->absolute_origin_changed to TRUE in case the origin changes inside
clutter_actor_set_allocation_internal(). Since this function is always
called when our allocation changes, we no longer need to update
absolute_origin_changed in clutter_actor_allocate() now.

Since a change to the absolute origin always affects the resource scale,
too, we also need to move that check from clutter_actor_allocate() here
to make sure we update the resource scale.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1247
2020-06-02 19:44:42 +00:00
9f121a211d clutter/actor: Always reset absolute_origin_changed after relayout
Since the introduction of the shallow relayout functionality it's
possible to start an allocation cycle at any point in the tree, not only
at the stage. Now when starting an allocation at an actor that's not the
stage, we'd still look at the absolute_origin_changed property of this
actors parent, which might still be set to TRUE from the parents last
allocation.

So avoid using the parents absolute_origin_changed property from the
last allocation in case a shallow relayout is being done and always
reset the absolute_origin_changed property to FALSE after the allocation
cycle.

This broke with the removal of the ABSOLUTE_ORIGIN_CHANGED
ClutterAllocationFlag that was done in commit dc8e5c7f.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1247
2020-06-02 19:44:42 +00:00
c823b5ddba renderer-native: Don't leak DMA buffer CoglFramebuffer
When we created the DMA buffer backed CoglFramebuffer, we handed it over
to CoglDmaBufHandle which took its own reference. What we failed to do
was to release our own reference to it, effectively leaking it.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1283
2020-06-02 18:39:27 +02:00
97175f8fa1 screen-cast-src: Destroy hash dmabuf table after stream
The stream will clean up the buffers, so let it do that before we
destroy them under its feet. Note that it'll only do this after the
following PipeWire commit:

    commit fbaa4ddedd84afdffca16f090dcc4b0db8ccfc29
    Author: Wim Taymans <wtaymans@redhat.com>
    Date:   Mon Jun 1 15:36:09 2020 +0200

        stream: allow NULL param and 0 buffers in disconnect

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1283
2020-06-02 18:39:23 +02:00
c5b1bdc0fe tests/stacking/restore-position: Always use wait_reconfigure
wait_reconfigure ensures that the whole configure back and forth
completes before continuing. Doing this after every state change ensures
that we always end up with the expected state, thus fixes flakyness of
the restore-position stacking test.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1279
2020-05-29 14:47:10 +00:00
f8e2234ce5 backends/native: Drop external keyboard detection for ::touch-mode
This cannot be made to work reliably. Some factoids:

- Internal devices may be connected via USB.
- The ACPI spec provides the _PLD (Physical location of device) hook to
  determine how is an USB device connected, with an anecdotal success
  rate. Internal devices may be seen as external and vice-versa, there is
  also an "unknown" value that is widely used.
- There may be non-USB keyboards, the old "AT Translated Set 2 Keyboard"
  interface does not change on hotplugging.
- Libinput has an internal series of quirks to classify keyboards as
  internal of external, also with an "unknown" value.

These heuristics are kinda hopeless to get right by our own hand. Drop
this external keyboard detection in the hope that there will be something
more deterministic to rely on in the future (e.g. the libinput quirks
made available to us directly or indirectly).

Fixes: https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/2378
Related: https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/2353

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1277
2020-05-29 14:37:21 +00:00
38bbd9593b backends/x11: Implement ClutterSeat::touch-mode for the X11 backend
This only checks touchscreen availability as we have no access to
tablet-mode switch events as we do on the native backend.

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

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1278
2020-05-29 12:39:59 +00:00
a3cc62c285 cogl tests: Force defined behaviour for 24-bit left-shifts
When r is 128 or more, running tests compiled with the undefined behaviour
sanitizer (ubsan) reports:

test-utils.c:312:45: runtime error: left shift of 128 by 24 places cannot be represented in type 'int'

which indeed it cannot. Force the type to be unsigned 32-bit so that we
get defined behaviour.

Similarly, in test-atlas-migration, the left-shifted guint8 is promoted
to int, which again does not have enough non-sign bits available to
left-shift a value >= 128 by 24 bits. Again, force the shift to be done
in unsigned 32-bit space.

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

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

Signed-off-by: Simon McVittie <smcv@debian.org>
2020-05-27 21:26:49 +00:00
c3bf10d19a cogl test-premult: Don't free texture data until CoglBitmap is freed
According to the cogl_bitmap_new_for_data documentation, the data is not
copied, so the application must keep the buffer alive for the lifetime
of the CoglBitmap. Freeing it too early led to a use-after-free in the
cogl unit tests. With that fixed, the test passes, so remove the known
failure annotation.

This AddressSanitizer trace is from the original cogl, but the bug and
fix apply equally to mutter's fork of cogl:

==6223==ERROR: AddressSanitizer: heap-use-after-free on address 0x62100001a500 at pc 0x7f3e2d4e7f4e bp 0x7ffcd9c41f30 sp 0x7ffcd9c416e0
READ of size 4096 at 0x62100001a500 thread T0
    #0 0x7f3e2d4e7f4d  (/usr/lib/x86_64-linux-gnu/libasan.so.5+0x96f4d)
    #1 0x7f3e260c7f6b in util_copy_box ../src/gallium/auxiliary/util/u_surface.c:131
    #2 0x7f3e268c6c10 in u_default_texture_subdata ../src/gallium/auxiliary/util/u_transfer.c:67
    #3 0x7f3e26486459 in st_TexSubImage ../src/mesa/state_tracker/st_cb_texture.c:1480
    #4 0x7f3e26487029 in st_TexImage ../src/mesa/state_tracker/st_cb_texture.c:1709
    #5 0x7f3e26487029 in st_TexImage ../src/mesa/state_tracker/st_cb_texture.c:1691
    #6 0x7f3e2644bdba in teximage ../src/mesa/main/teximage.c:3105
    #7 0x7f3e2644bdba in teximage_err ../src/mesa/main/teximage.c:3132
    #8 0x7f3e2644d84f in _mesa_TexImage2D ../src/mesa/main/teximage.c:3170
    #9 0x7f3e2cd1f7df in _cogl_texture_driver_upload_to_gl driver/gl/gl/cogl-texture-driver-gl.c:347
    #10 0x7f3e2ccd441b in allocate_from_bitmap driver/gl/cogl-texture-2d-gl.c:255
    #11 0x7f3e2ccd441b in _cogl_texture_2d_gl_allocate driver/gl/cogl-texture-2d-gl.c:462
    #12 0x7f3e2ce3a6c0 in cogl_texture_allocate cogl/cogl-texture.c:1398
    #13 0x7f3e2ce3e116 in _cogl_texture_pre_paint cogl/cogl-texture.c:359
    #14 0x7f3e2cdee177 in _cogl_pipeline_layer_pre_paint cogl/cogl-pipeline-layer.c:864
    #15 0x7f3e2cd574af in _cogl_rectangles_validate_layer_cb cogl/cogl-primitives.c:542
    #16 0x7f3e2cdd742f in cogl_pipeline_foreach_layer cogl/cogl-pipeline.c:735
    #17 0x7f3e2cd5c8b0 in _cogl_framebuffer_draw_multitextured_rectangles cogl/cogl-primitives.c:658
    #18 0x7f3e2cd60152 in cogl_rectangle cogl/cogl-primitives.c:858
    #19 0x5570a71ed6a0 in check_texture tests/conform/test-premult.c:103
    #20 0x5570a71ed946 in test_premult tests/conform/test-premult.c:159
    #21 0x5570a71df0d6 in main tests/conform/test-conform-main.c:58
    #22 0x7f3e2bcd809a in __libc_start_main ../csu/libc-start.c:308
    #23 0x5570a71e0869 in _start (/home/smcv/src/debian/cogl/tests/conform/.libs/test-conformance+0x33869)

0x62100001a500 is located 0 bytes inside of 4096-byte region [0x62100001a500,0x62100001b500)
freed by thread T0 here:
    #0 0x7f3e2d5581d7 in __interceptor_free (/usr/lib/x86_64-linux-gnu/libasan.so.5+0x1071d7)
    #1 0x5570a71ed58b in make_texture tests/conform/test-premult.c:69

previously allocated by thread T0 here:
    #0 0x7f3e2d558588 in malloc (/usr/lib/x86_64-linux-gnu/libasan.so.5+0x107588)
    #1 0x7f3e2d384500 in g_malloc ../../../glib/gmem.c:99

This was originally cogl!12.

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

Signed-off-by: Simon McVittie <smcv@debian.org>
2020-05-27 15:50:36 +01:00
114 changed files with 3583 additions and 1624 deletions

27
NEWS
View File

@ -1,3 +1,30 @@
3.37.2
======
* Fix move-to-center keybinding with multiple monitors [Sergey; #1073]
* Fix stuck buttons when a virtual device is destroyed [Carlos; !1239]
* Use workarea when centering new windows [Akatsuki; #964]
* Limit mipmap levels when rendering background [Daniel; !1003]
* Broadcast clipboard/primary offers [Carlos; !1253]
* Support primary-selection protocol from wayland-protocols [Carlos; !1255]
* Fix monitor screen cast on X11 [Jonas Å.; !1251]
* Support a "blank" cursor type [Florian; !1244]
* Improve stage view damage tracking [Jonas Å.; !1237]
* Implement touch-mode detecation for the X11 backend [Carlos; !1278]
* Drop external keyboard detection from touch-mode heuristics [Carlos; !1277]
* Optimize actor allocations [Jonas D.; !1247]
* Fixed crashes [Daniel, Carlos, Jonas Å., Jonas D.; !1256, !1258, !1217, !1280]
* Misc. bug fixes and cleanups [Christian, Jonas D., Olivier, Ting-Wei,
Jonas Å., Marco, Corentin, Daniel, Robert, Niels, Florian, Simon; !1231,
!1228, !1238, !1229, !1192, !1236, !1171, !1134, #1126, !1234, !1230, !1210,
!1242, !1243, !1252, !1113, !1232, !1259, !1245, !1265, !1180, !1261, !788,
!1264, !1235, !1218, !1150, !1274, !1271, !1279, !1283, !1272]
Contributors:
Marco Trevisan (Treviño), Akatsuki, Jonas Dreßler, Olivier Fourdan,
Carlos Garnacho, Niels De Graef, Ting-Wei Lan, Robert Mader, Simon McVittie,
Florian Müllner, Corentin Noël, Christian Rauch, Daniel van Vugt,
Sergey Zigachev, Jonas Ådahl
3.37.1
======
* Fix screencasting non-maximized windows [Jonas Å.; !1174]

View File

@ -313,7 +313,7 @@ void _clutter_actor_detach_clone
void _clutter_actor_queue_redraw_on_clones (ClutterActor *actor);
void _clutter_actor_queue_relayout_on_clones (ClutterActor *actor);
void _clutter_actor_queue_only_relayout (ClutterActor *actor);
void _clutter_actor_queue_update_resource_scale_recursive (ClutterActor *actor);
void clutter_actor_clear_stage_views_recursive (ClutterActor *actor);
gboolean _clutter_actor_get_real_resource_scale (ClutterActor *actor,
float *resource_scale);
@ -321,6 +321,8 @@ gboolean _clutter_actor_get_real_resource_scale
ClutterPaintNode * clutter_actor_create_texture_paint_node (ClutterActor *self,
CoglTexture *texture);
void clutter_actor_update_stage_views (ClutterActor *self);
G_END_DECLS
#endif /* __CLUTTER_ACTOR_PRIVATE_H__ */

View File

@ -446,7 +446,8 @@
* ]|
*
* - the initial `@` is mandatory
* - the `section` fragment can be one between "actions", "constraints" and "effects"
* - the `section` fragment can be one between "actions", "constraints", "content",
* and "effects"
* - the `meta-name` fragment is the name of the action, effect, or constraint, as
* specified by the #ClutterActorMeta:name property of #ClutterActorMeta
* - the `property-name` fragment is the name of the action, effect, or constraint
@ -811,6 +812,9 @@ struct _ClutterActorPrivate
gulong resolution_changed_id;
gulong font_changed_id;
gulong layout_changed_id;
GList *stage_views;
/* bitfields: KEEP AT THE END */
@ -854,6 +858,7 @@ struct _ClutterActorPrivate
guint had_effects_on_last_paint_volume_update : 1;
guint needs_compute_resource_scale : 1;
guint absolute_origin_changed : 1;
guint needs_update_stage_views : 1;
};
enum
@ -1016,6 +1021,7 @@ enum
TRANSITIONS_COMPLETED,
TOUCH_EVENT,
TRANSITION_STOPPED,
STAGE_VIEWS_CHANGED,
LAST_SIGNAL
};
@ -1613,6 +1619,22 @@ clutter_actor_update_map_state (ClutterActor *self,
#endif
}
static void
queue_update_stage_views (ClutterActor *actor)
{
while (actor && !actor->priv->needs_update_stage_views)
{
actor->priv->needs_update_stage_views = TRUE;
/* We don't really need to update the stage-views of the actors up the
* hierarchy, we set the flag anyway though so we can avoid traversing
* the whole scenegraph when looking for actors which need an update
* in clutter_actor_update_stage_views().
*/
actor = actor->priv->parent;
}
}
static void
clutter_actor_real_map (ClutterActor *self)
{
@ -1627,6 +1649,18 @@ clutter_actor_real_map (ClutterActor *self)
self->priv->needs_paint_volume_update = TRUE;
/* We skip unmapped actors when updating the stage-views list, so if
* an actors list got invalidated while it was unmapped make sure to
* set priv->needs_update_stage_views to TRUE for all actors up the
* hierarchy now.
*/
if (self->priv->needs_update_stage_views)
{
/* Avoid the early return in queue_update_stage_views() */
self->priv->needs_update_stage_views = FALSE;
queue_update_stage_views (self);
}
clutter_actor_ensure_resource_scale (self);
/* notify on parent mapped before potentially mapping
@ -2560,6 +2594,23 @@ clutter_actor_notify_if_geometry_changed (ClutterActor *self,
g_object_thaw_notify (obj);
}
static void
absolute_allocation_changed (ClutterActor *actor)
{
actor->priv->needs_compute_resource_scale = TRUE;
queue_update_stage_views (actor);
}
static ClutterActorTraverseVisitFlags
absolute_allocation_changed_cb (ClutterActor *actor,
int depth,
gpointer user_data)
{
absolute_allocation_changed (actor);
return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
}
/*< private >
* clutter_actor_set_allocation_internal:
* @self: a #ClutterActor
@ -2585,6 +2636,9 @@ clutter_actor_set_allocation_internal (ClutterActor *self,
gboolean x1_changed, y1_changed, x2_changed, y2_changed;
ClutterActorBox old_alloc = { 0, };
g_return_if_fail (!isnan (box->x1) && !isnan (box->x2) &&
!isnan (box->y1) && !isnan (box->y2));
obj = G_OBJECT (self);
g_object_freeze_notify (obj);
@ -2603,6 +2657,11 @@ clutter_actor_set_allocation_internal (ClutterActor *self,
priv->needs_height_request = FALSE;
priv->needs_allocation = FALSE;
priv->absolute_origin_changed |= x1_changed || y1_changed;
if (priv->absolute_origin_changed || x2_changed || y2_changed)
absolute_allocation_changed (self);
if (x1_changed ||
y1_changed ||
x2_changed ||
@ -4257,6 +4316,7 @@ typedef enum
REMOVE_CHILD_FLUSH_QUEUE = 1 << 4,
REMOVE_CHILD_NOTIFY_FIRST_LAST = 1 << 5,
REMOVE_CHILD_STOP_TRANSITIONS = 1 << 6,
REMOVE_CHILD_CLEAR_STAGE_VIEWS = 1 << 7,
/* default flags for public API */
REMOVE_CHILD_DEFAULT_FLAGS = REMOVE_CHILD_STOP_TRANSITIONS |
@ -4265,14 +4325,16 @@ typedef enum
REMOVE_CHILD_EMIT_ACTOR_REMOVED |
REMOVE_CHILD_CHECK_STATE |
REMOVE_CHILD_FLUSH_QUEUE |
REMOVE_CHILD_NOTIFY_FIRST_LAST,
REMOVE_CHILD_NOTIFY_FIRST_LAST |
REMOVE_CHILD_CLEAR_STAGE_VIEWS,
/* flags for legacy/deprecated API */
REMOVE_CHILD_LEGACY_FLAGS = REMOVE_CHILD_STOP_TRANSITIONS |
REMOVE_CHILD_CHECK_STATE |
REMOVE_CHILD_FLUSH_QUEUE |
REMOVE_CHILD_EMIT_PARENT_SET |
REMOVE_CHILD_NOTIFY_FIRST_LAST
REMOVE_CHILD_NOTIFY_FIRST_LAST |
REMOVE_CHILD_CLEAR_STAGE_VIEWS
} ClutterActorRemoveChildFlags;
/*< private >
@ -4294,6 +4356,7 @@ clutter_actor_remove_child_internal (ClutterActor *self,
gboolean notify_first_last;
gboolean was_mapped;
gboolean stop_transitions;
gboolean clear_stage_views;
GObject *obj;
if (self == child)
@ -4310,6 +4373,7 @@ clutter_actor_remove_child_internal (ClutterActor *self,
flush_queue = (flags & REMOVE_CHILD_FLUSH_QUEUE) != 0;
notify_first_last = (flags & REMOVE_CHILD_NOTIFY_FIRST_LAST) != 0;
stop_transitions = (flags & REMOVE_CHILD_STOP_TRANSITIONS) != 0;
clear_stage_views = (flags & REMOVE_CHILD_CLEAR_STAGE_VIEWS) != 0;
obj = G_OBJECT (self);
g_object_freeze_notify (obj);
@ -4383,6 +4447,13 @@ clutter_actor_remove_child_internal (ClutterActor *self,
clutter_actor_queue_compute_expand (self);
}
/* Only actors which are attached to a stage get notified about changes
* to the stage views, so make sure all the stage-views lists are
* cleared as the child and its children leave the actor tree.
*/
if (clear_stage_views && !CLUTTER_ACTOR_IN_DESTRUCTION (child))
clutter_actor_clear_stage_views_recursive (child);
if (emit_parent_set && !CLUTTER_ACTOR_IN_DESTRUCTION (child))
{
child->priv->needs_compute_resource_scale = TRUE;
@ -5173,7 +5244,7 @@ clutter_actor_set_property (GObject *object,
break;
case PROP_OFFSCREEN_REDIRECT:
clutter_actor_set_offscreen_redirect (actor, g_value_get_enum (value));
clutter_actor_set_offscreen_redirect (actor, g_value_get_flags (value));
break;
case PROP_NAME:
@ -6038,6 +6109,7 @@ clutter_actor_dispose (GObject *object)
if (priv->layout_manager != NULL)
{
g_clear_signal_handler (&priv->layout_changed_id, priv->layout_manager);
clutter_layout_manager_set_container (priv->layout_manager, NULL);
g_clear_object (&priv->layout_manager);
}
@ -6054,6 +6126,8 @@ clutter_actor_dispose (GObject *object)
priv->clones = NULL;
}
g_clear_pointer (&priv->stage_views, g_list_free);
G_OBJECT_CLASS (clutter_actor_parent_class)->dispose (object);
}
@ -8590,6 +8664,27 @@ clutter_actor_class_init (ClutterActorClass *klass)
g_signal_set_va_marshaller (actor_signals[TOUCH_EVENT],
G_TYPE_FROM_CLASS (object_class),
_clutter_marshal_BOOLEAN__BOXEDv);
/**
* ClutterActor::stage-views-changed:
* @actor: a #ClutterActor
*
* The ::stage-views-changed signal is emitted when the position or
* size an actor is being painted at have changed so that it's visible
* on different stage views.
*
* This signal is also emitted when the actor gets detached from the stage
* or when the views of the stage have been invalidated and will be
* replaced; it's not emitted when the actor gets hidden.
*/
actor_signals[STAGE_VIEWS_CHANGED] =
g_signal_new (I_("stage-views-changed"),
G_TYPE_FROM_CLASS (object_class),
G_SIGNAL_RUN_LAST,
0,
NULL, NULL, NULL,
G_TYPE_NONE, 0);
}
static void
@ -8608,6 +8703,7 @@ clutter_actor_init (ClutterActor *self)
priv->needs_allocation = TRUE;
priv->needs_paint_volume_update = TRUE;
priv->needs_compute_resource_scale = TRUE;
priv->needs_update_stage_views = TRUE;
priv->cached_width_age = 1;
priv->cached_height_age = 1;
@ -10094,7 +10190,6 @@ clutter_actor_allocate (ClutterActor *self,
{
ClutterActorBox old_allocation, real_allocation;
gboolean origin_changed, size_changed;
gboolean stage_allocation_changed;
ClutterActorPrivate *priv;
g_return_if_fail (CLUTTER_IS_ACTOR (self));
@ -10106,14 +10201,34 @@ clutter_actor_allocate (ClutterActor *self,
return;
}
if (!clutter_actor_is_visible (self))
return;
priv = self->priv;
priv->absolute_origin_changed = priv->parent
? priv->parent->priv->absolute_origin_changed
: FALSE;
if (!CLUTTER_ACTOR_IS_VISIBLE (self))
{
if (priv->absolute_origin_changed)
{
_clutter_actor_traverse (self,
CLUTTER_ACTOR_TRAVERSE_DEPTH_FIRST,
absolute_allocation_changed_cb,
NULL,
NULL);
}
goto out;
}
old_allocation = priv->allocation;
real_allocation = *box;
g_return_if_fail (!isnan (real_allocation.x1) &&
!isnan (real_allocation.x2) &&
!isnan (real_allocation.y1) &&
!isnan (real_allocation.y2));
/* constraints are allowed to modify the allocation only here; we do
* this prior to all the other checks so that we can bail out if the
* allocation did not change
@ -10142,49 +10257,46 @@ clutter_actor_allocate (ClutterActor *self,
size_changed = (real_allocation.x2 != old_allocation.x2 ||
real_allocation.y2 != old_allocation.y2);
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
* ignore it. But if we have needs_allocation set,
* we want to guarantee that allocate() virtual
* method is always called, i.e. that queue_relayout()
* always results in an allocate() invocation on
* an actor.
/* When needs_allocation is set but we didn't move nor resize, we still
* want to call the allocate() vfunc because a child probably called
* queue_relayout() and needs a new allocation.
*
* The optimization here is to avoid re-allocating
* actors that did not queue relayout and were
* not moved.
* In case needs_allocation isn't set and we didn't move nor resize, we
* can safely stop allocating, but we need to notify the sub-tree in case
* our absolute origin changed.
*/
if (!priv->needs_allocation && !stage_allocation_changed)
if (!priv->needs_allocation && !origin_changed && !size_changed)
{
if (priv->absolute_origin_changed)
{
_clutter_actor_traverse (self,
CLUTTER_ACTOR_TRAVERSE_DEPTH_FIRST,
absolute_allocation_changed_cb,
NULL,
NULL);
}
CLUTTER_NOTE (LAYOUT, "No allocation needed");
return;
goto out;
}
if (CLUTTER_ACTOR_IS_MAPPED (self))
self->priv->needs_paint_volume_update = TRUE;
if (stage_allocation_changed)
priv->needs_compute_resource_scale = TRUE;
if (!stage_allocation_changed)
if (!origin_changed && !size_changed)
{
/* If the actor didn't move but needs_allocation is set, we just
* need to allocate the children */
* need to allocate the children (see comment above) */
clutter_actor_allocate_internal (self, &real_allocation);
return;
goto out;
}
_clutter_actor_create_transition (self, obj_props[PROP_ALLOCATION],
&priv->allocation,
&real_allocation);
out:
priv->absolute_origin_changed = FALSE;
}
/**
@ -14511,6 +14623,37 @@ get_layout_from_animation_property (ClutterActor *actor,
return TRUE;
}
static gboolean
get_content_from_animation_property (ClutterActor *actor,
const gchar *name,
gchar **name_p)
{
g_auto (GStrv) tokens = NULL;
if (!g_str_has_prefix (name, "@content"))
return FALSE;
if (!actor->priv->content)
{
CLUTTER_NOTE (ANIMATION, "No ClutterContent available for '%s'",
name + 1);
return FALSE;
}
tokens = g_strsplit (name, ".", -1);
if (tokens == NULL || g_strv_length (tokens) != 2)
{
CLUTTER_NOTE (ANIMATION, "Invalid property name '%s'",
name + 1);
return FALSE;
}
if (name_p != NULL)
*name_p = g_strdup (tokens[1]);
return TRUE;
}
static ClutterActorMeta *
get_meta_from_animation_property (ClutterActor *actor,
const gchar *name,
@ -14578,6 +14721,7 @@ clutter_actor_find_property (ClutterAnimatable *animatable,
GObjectClass *klass = NULL;
GParamSpec *pspec = NULL;
gchar *p_name = NULL;
gboolean use_content = FALSE;
gboolean use_layout;
use_layout = get_layout_from_animation_property (actor,
@ -14585,6 +14729,11 @@ clutter_actor_find_property (ClutterAnimatable *animatable,
&p_name);
if (!use_layout)
use_content = get_content_from_animation_property (actor,
property_name,
&p_name);
if (!use_layout && !use_content)
meta = get_meta_from_animation_property (actor,
property_name,
&p_name);
@ -14599,6 +14748,12 @@ clutter_actor_find_property (ClutterAnimatable *animatable,
{
klass = G_OBJECT_GET_CLASS (actor->priv->layout_manager);
pspec = g_object_class_find_property (klass, p_name);
}
else if (use_content)
{
klass = G_OBJECT_GET_CLASS (actor->priv->content);
pspec = g_object_class_find_property (klass, p_name);
}
else
@ -14621,6 +14776,7 @@ clutter_actor_get_initial_state (ClutterAnimatable *animatable,
ClutterActor *actor = CLUTTER_ACTOR (animatable);
ClutterActorMeta *meta = NULL;
gchar *p_name = NULL;
gboolean use_content = FALSE;
gboolean use_layout;
use_layout = get_layout_from_animation_property (actor,
@ -14628,6 +14784,11 @@ clutter_actor_get_initial_state (ClutterAnimatable *animatable,
&p_name);
if (!use_layout)
use_content = get_content_from_animation_property (actor,
property_name,
&p_name);
if (!use_layout && !use_content)
meta = get_meta_from_animation_property (actor,
property_name,
&p_name);
@ -14636,6 +14797,8 @@ clutter_actor_get_initial_state (ClutterAnimatable *animatable,
g_object_get_property (G_OBJECT (meta), p_name, initial);
else if (use_layout)
g_object_get_property (G_OBJECT (actor->priv->layout_manager), p_name, initial);
else if (use_content)
g_object_get_property (G_OBJECT (actor->priv->content), p_name, initial);
else
g_object_get_property (G_OBJECT (animatable), property_name, initial);
@ -14786,6 +14949,7 @@ clutter_actor_set_final_state (ClutterAnimatable *animatable,
ClutterActor *actor = CLUTTER_ACTOR (animatable);
ClutterActorMeta *meta = NULL;
gchar *p_name = NULL;
gboolean use_content = FALSE;
gboolean use_layout;
use_layout = get_layout_from_animation_property (actor,
@ -14793,6 +14957,11 @@ clutter_actor_set_final_state (ClutterAnimatable *animatable,
&p_name);
if (!use_layout)
use_content = get_content_from_animation_property (actor,
property_name,
&p_name);
if (!use_layout && !use_content)
meta = get_meta_from_animation_property (actor,
property_name,
&p_name);
@ -14801,6 +14970,8 @@ clutter_actor_set_final_state (ClutterAnimatable *animatable,
g_object_set_property (G_OBJECT (meta), p_name, final);
else if (use_layout)
g_object_set_property (G_OBJECT (actor->priv->layout_manager), p_name, final);
else if (use_content)
g_object_set_property (G_OBJECT (actor->priv->content), p_name, final);
else
{
GObjectClass *obj_class = G_OBJECT_GET_CLASS (animatable);
@ -17379,17 +17550,27 @@ _clutter_actor_get_resource_scale_for_rect (ClutterActor *self,
float *resource_scale)
{
ClutterActor *stage;
g_autoptr (GList) views = NULL;
GList *l;
float max_scale = 0;
stage = _clutter_actor_get_stage_internal (self);
if (!stage)
return FALSE;
if (!_clutter_stage_get_max_view_scale_factor_for_rect (CLUTTER_STAGE (stage),
bounding_rect,
&max_scale))
views = clutter_stage_get_views_for_rect (CLUTTER_STAGE (stage),
bounding_rect);
if (!views)
return FALSE;
for (l = views; l; l = l->next)
{
ClutterStageView *view = l->data;
max_scale = MAX (clutter_stage_view_get_scale (view), max_scale);
}
*resource_scale = max_scale;
return TRUE;
@ -17465,20 +17646,29 @@ _clutter_actor_compute_resource_scale (ClutterActor *self,
}
static ClutterActorTraverseVisitFlags
queue_update_resource_scale_cb (ClutterActor *actor,
int depth,
void *user_data)
clear_stage_views_cb (ClutterActor *actor,
int depth,
gpointer user_data)
{
g_autoptr (GList) old_stage_views = NULL;
actor->priv->needs_update_stage_views = TRUE;
actor->priv->needs_compute_resource_scale = TRUE;
old_stage_views = g_steal_pointer (&actor->priv->stage_views);
if (old_stage_views)
g_signal_emit (actor, actor_signals[STAGE_VIEWS_CHANGED], 0);
return CLUTTER_ACTOR_TRAVERSE_VISIT_CONTINUE;
}
void
_clutter_actor_queue_update_resource_scale_recursive (ClutterActor *self)
clutter_actor_clear_stage_views_recursive (ClutterActor *self)
{
_clutter_actor_traverse (self,
CLUTTER_ACTOR_TRAVERSE_DEPTH_FIRST,
queue_update_resource_scale_cb,
clear_stage_views_cb,
NULL,
NULL);
}
@ -17570,6 +17760,125 @@ clutter_actor_get_resource_scale (ClutterActor *self,
return FALSE;
}
static gboolean
sorted_lists_equal (GList *list_a,
GList *list_b)
{
GList *a, *b;
if (!list_a && !list_b)
return TRUE;
for (a = list_a, b = list_b;
a && b;
a = a->next, b = b->next)
{
if (a->data != b->data)
break;
if (!a->next && !b->next)
return TRUE;
}
return FALSE;
}
static void
update_stage_views (ClutterActor *self)
{
ClutterActorPrivate *priv = self->priv;
g_autoptr (GList) old_stage_views = NULL;
ClutterStage *stage;
graphene_rect_t bounding_rect;
old_stage_views = g_steal_pointer (&priv->stage_views);
if (priv->needs_allocation)
{
g_warning ("Can't update stage views actor %s is on because it needs an "
"allocation.", _clutter_actor_get_debug_name (self));
goto out;
}
stage = CLUTTER_STAGE (_clutter_actor_get_stage_internal (self));
g_return_if_fail (stage);
clutter_actor_get_transformed_position (self,
&bounding_rect.origin.x,
&bounding_rect.origin.y);
clutter_actor_get_transformed_size (self,
&bounding_rect.size.width,
&bounding_rect.size.height);
if (bounding_rect.size.width == 0.0 ||
bounding_rect.size.height == 0.0)
goto out;
priv->stage_views = clutter_stage_get_views_for_rect (stage,
&bounding_rect);
out:
if (g_signal_has_handler_pending (self, actor_signals[STAGE_VIEWS_CHANGED],
0, TRUE))
{
if (!sorted_lists_equal (old_stage_views, priv->stage_views))
g_signal_emit (self, actor_signals[STAGE_VIEWS_CHANGED], 0);
}
}
void
clutter_actor_update_stage_views (ClutterActor *self)
{
ClutterActorPrivate *priv = self->priv;
ClutterActor *child;
if (!CLUTTER_ACTOR_IS_MAPPED (self) ||
CLUTTER_ACTOR_IN_DESTRUCTION (self))
return;
if (!priv->needs_update_stage_views)
return;
update_stage_views (self);
priv->needs_update_stage_views = FALSE;
for (child = priv->first_child; child; child = child->priv->next_sibling)
clutter_actor_update_stage_views (child);
}
/**
* clutter_actor_peek_stage_views:
* @self: A #ClutterActor
*
* Retrieves the list of #ClutterStageView<!-- -->s the actor is being
* painted on.
*
* If this function is called during the paint cycle, the list is guaranteed
* to be up-to-date, if called outside the paint cycle, the list will
* contain the views the actor was painted on last.
*
* The list returned by this function is not updated when the actors
* visibility changes: If an actor gets hidden and is not being painted
* anymore, this function will return the list of views the actor was
* painted on last.
*
* If an actor is not attached to a stage (realized), this function will
* always return an empty list.
*
* Returns: (transfer none) (element-type Clutter.StageView): The list of
* #ClutterStageView<!-- -->s the actor is being painted on. The list and
* its contents are owned by the #ClutterActor and the list may not be
* freed or modified.
*/
GList *
clutter_actor_peek_stage_views (ClutterActor *self)
{
g_return_val_if_fail (CLUTTER_IS_ACTOR (self), FALSE);
return self->priv->stage_views;
}
/**
* clutter_actor_has_overlaps:
* @self: A #ClutterActor
@ -17931,9 +18240,7 @@ clutter_actor_set_layout_manager (ClutterActor *self,
if (priv->layout_manager != NULL)
{
g_signal_handlers_disconnect_by_func (priv->layout_manager,
G_CALLBACK (on_layout_manager_changed),
self);
g_clear_signal_handler (&priv->layout_changed_id, priv->layout_manager);
clutter_layout_manager_set_container (priv->layout_manager, NULL);
g_clear_object (&priv->layout_manager);
}
@ -17945,9 +18252,10 @@ clutter_actor_set_layout_manager (ClutterActor *self,
g_object_ref_sink (priv->layout_manager);
clutter_layout_manager_set_container (priv->layout_manager,
CLUTTER_CONTAINER (self));
g_signal_connect (priv->layout_manager, "layout-changed",
G_CALLBACK (on_layout_manager_changed),
self);
priv->layout_changed_id =
g_signal_connect (priv->layout_manager, "layout-changed",
G_CALLBACK (on_layout_manager_changed),
self);
}
clutter_actor_queue_relayout (self);

View File

@ -919,6 +919,9 @@ void clutter_actor_pick_box (ClutterActor *self,
ClutterPickContext *pick_context,
const ClutterActorBox *box);
CLUTTER_EXPORT
GList * clutter_actor_peek_stage_views (ClutterActor *self);
G_END_DECLS
#endif /* __CLUTTER_ACTOR_H__ */

View File

@ -84,12 +84,11 @@ G_DEFINE_TYPE (ClutterAlignConstraint,
CLUTTER_TYPE_CONSTRAINT);
static void
source_position_changed (ClutterActor *actor,
GParamSpec *pspec,
ClutterAlignConstraint *align)
source_queue_relayout (ClutterActor *actor,
ClutterAlignConstraint *align)
{
if (align->actor != NULL)
clutter_actor_queue_relayout (align->actor);
_clutter_actor_queue_only_relayout (align->actor);
}
static void
@ -186,7 +185,7 @@ clutter_align_constraint_dispose (GObject *gobject)
G_CALLBACK (source_destroyed),
align);
g_signal_handlers_disconnect_by_func (align->source,
G_CALLBACK (source_position_changed),
G_CALLBACK (source_queue_relayout),
align);
align->source = NULL;
}
@ -402,15 +401,15 @@ clutter_align_constraint_set_source (ClutterAlignConstraint *align,
G_CALLBACK (source_destroyed),
align);
g_signal_handlers_disconnect_by_func (old_source,
G_CALLBACK (source_position_changed),
G_CALLBACK (source_queue_relayout),
align);
}
align->source = source;
if (align->source != NULL)
{
g_signal_connect (align->source, "notify::allocation",
G_CALLBACK (source_position_changed),
g_signal_connect (align->source, "queue-relayout",
G_CALLBACK (source_queue_relayout),
align);
g_signal_connect (align->source, "destroy",
G_CALLBACK (source_destroyed),

View File

@ -1317,8 +1317,6 @@ typedef enum
* painting the stages
* @CLUTTER_REPAINT_FLAGS_POST_PAINT: Run the repaint function after
* painting the stages
* @CLUTTER_REPAINT_FLAGS_QUEUE_REDRAW_ON_ADD: Ensure that a new frame
* is queued after adding the repaint function
*
* Flags to pass to clutter_threads_add_repaint_func_full().
*
@ -1328,7 +1326,6 @@ typedef enum
{
CLUTTER_REPAINT_FLAGS_PRE_PAINT = 1 << 0,
CLUTTER_REPAINT_FLAGS_POST_PAINT = 1 << 1,
CLUTTER_REPAINT_FLAGS_QUEUE_REDRAW_ON_ADD = 1 << 2
} ClutterRepaintFlags;
/**

View File

@ -2392,8 +2392,7 @@ clutter_threads_add_repaint_func_full (ClutterRepaintFlags flags,
repaint_func->id = context->last_repaint_id++;
/* mask out QUEUE_REDRAW_ON_ADD, since we're going to consume it */
repaint_func->flags = flags & ~CLUTTER_REPAINT_FLAGS_QUEUE_REDRAW_ON_ADD;
repaint_func->flags = flags;
repaint_func->func = func;
repaint_func->data = data;
repaint_func->notify = notify;
@ -2403,13 +2402,6 @@ clutter_threads_add_repaint_func_full (ClutterRepaintFlags flags,
_clutter_context_unlock ();
if ((flags & CLUTTER_REPAINT_FLAGS_QUEUE_REDRAW_ON_ADD) != 0)
{
ClutterMasterClock *master_clock = _clutter_master_clock_get_default ();
_clutter_master_clock_ensure_next_iteration (master_clock);
}
return repaint_func->id;
}

View File

@ -75,7 +75,7 @@ CLUTTER_EXPORT
void clutter_stage_thaw_updates (ClutterStage *stage);
CLUTTER_EXPORT
void clutter_stage_update_resource_scales (ClutterStage *stage);
void clutter_stage_clear_stage_views (ClutterStage *stage);
CLUTTER_EXPORT
void clutter_stage_view_assign_next_scanout (ClutterStageView *stage_view,

View File

@ -136,7 +136,8 @@ enum
static guint pan_signals[LAST_SIGNAL] = { 0, };
G_DEFINE_TYPE_WITH_PRIVATE (ClutterPanAction, clutter_pan_action, CLUTTER_TYPE_GESTURE_ACTION)
G_DEFINE_TYPE_WITH_PRIVATE (ClutterPanAction, clutter_pan_action,
CLUTTER_TYPE_GESTURE_ACTION)
static void
emit_pan (ClutterPanAction *self,
@ -156,14 +157,18 @@ emit_pan (ClutterPanAction *self,
gfloat scroll_threshold = G_PI_4/2;
gfloat drag_angle;
clutter_gesture_action_get_motion_delta (CLUTTER_GESTURE_ACTION (self), 0, &delta_x, &delta_y);
clutter_gesture_action_get_motion_delta (CLUTTER_GESTURE_ACTION (self),
0,
&delta_x,
&delta_y);
if (delta_x != 0.0f)
drag_angle = atanf (delta_y / delta_x);
else
drag_angle = G_PI_2;
if ((drag_angle > -scroll_threshold) && (drag_angle < scroll_threshold))
if ((drag_angle > -scroll_threshold) &&
(drag_angle < scroll_threshold))
priv->pin_state = SCROLL_PINNED_HORIZONTAL;
else if ((drag_angle > (G_PI_2 - scroll_threshold)) ||
(drag_angle < -(G_PI_2 - scroll_threshold)))
@ -282,7 +287,10 @@ gesture_end (ClutterGestureAction *gesture,
gfloat tau;
gint duration;
clutter_gesture_action_get_release_coords (CLUTTER_GESTURE_ACTION (self), 0, &priv->release_x, &priv->release_y);
clutter_gesture_action_get_release_coords (CLUTTER_GESTURE_ACTION (self),
0,
&priv->release_x,
&priv->release_y);
if (!priv->should_interpolate)
{
@ -293,7 +301,9 @@ gesture_end (ClutterGestureAction *gesture,
priv->state = PAN_STATE_INTERPOLATING;
clutter_gesture_action_get_motion_delta (gesture, 0, &delta_x, &delta_y);
velocity = clutter_gesture_action_get_velocity (gesture, 0, &velocity_x, &velocity_y);
velocity = clutter_gesture_action_get_velocity (gesture, 0,
&velocity_x,
&velocity_y);
/* Exponential timing constant v(t) = v(0) * exp(-t/tau)
* tau = 1000ms / (frame_per_second * - ln(decay_per_frame))
@ -304,17 +314,22 @@ gesture_end (ClutterGestureAction *gesture,
/* See where the decreasing velocity reaches $min_velocity px/ms
* v(t) = v(0) * exp(-t/tau) = min_velocity
* t = - tau * ln( min_velocity / |v(0)|) */
duration = - tau * logf (min_velocity / (ABS (velocity) * priv->acceleration_factor));
duration = - tau * logf (min_velocity / (ABS (velocity) *
priv->acceleration_factor));
/* Target point: x(t) = v(0) * tau * [1 - exp(-t/tau)] */
priv->target_x = velocity_x * priv->acceleration_factor * tau * (1 - exp ((float)-duration / tau));
priv->target_y = velocity_y * priv->acceleration_factor * tau * (1 - exp ((float)-duration / tau));
priv->target_x = (velocity_x * priv->acceleration_factor * tau *
(1 - exp ((float)-duration / tau)));
priv->target_y = (velocity_y * priv->acceleration_factor * tau *
(1 - exp ((float)-duration / tau)));
if (ABS (velocity) * priv->acceleration_factor > min_velocity && duration > FLOAT_EPSILON)
if (ABS (velocity) * priv->acceleration_factor > min_velocity &&
duration > FLOAT_EPSILON)
{
priv->interpolated_x = priv->interpolated_y = 0.0f;
priv->deceleration_timeline = clutter_timeline_new (duration);
clutter_timeline_set_progress_mode (priv->deceleration_timeline, CLUTTER_EASE_OUT_EXPO);
clutter_timeline_set_progress_mode (priv->deceleration_timeline,
CLUTTER_EASE_OUT_EXPO);
g_signal_connect (priv->deceleration_timeline, "new_frame",
G_CALLBACK (on_deceleration_new_frame), self);
@ -367,7 +382,8 @@ clutter_pan_action_set_property (GObject *gobject,
break;
case PROP_ACCELERATION_FACTOR :
clutter_pan_action_set_acceleration_factor (self, g_value_get_double (value));
clutter_pan_action_set_acceleration_factor (self,
g_value_get_double (value));
break;
default:
@ -411,9 +427,11 @@ static void
clutter_pan_action_constructed (GObject *gobject)
{
ClutterGestureAction *gesture;
ClutterGestureTriggerEdge edge;
gesture = CLUTTER_GESTURE_ACTION (gobject);
clutter_gesture_action_set_threshold_trigger_edge (gesture, CLUTTER_GESTURE_TRIGGER_EDGE_AFTER);
edge = CLUTTER_GESTURE_TRIGGER_EDGE_AFTER;
clutter_gesture_action_set_threshold_trigger_edge (gesture, edge);
}
static void
@ -442,7 +460,8 @@ clutter_pan_action_set_actor (ClutterActorMeta *meta,
g_clear_object (&priv->deceleration_timeline);
}
CLUTTER_ACTOR_META_CLASS (clutter_pan_action_parent_class)->set_actor (meta, actor);
CLUTTER_ACTOR_META_CLASS (clutter_pan_action_parent_class)->set_actor (meta,
actor);
}
@ -880,7 +899,9 @@ clutter_pan_action_get_constrained_motion_delta (ClutterPanAction *self,
priv = self->priv;
distance = clutter_pan_action_get_motion_delta (self, point, &delta_x, &delta_y);
distance = clutter_pan_action_get_motion_delta (self, point,
&delta_x,
&delta_y);
switch (priv->pan_axis)
{

View File

@ -1523,7 +1523,7 @@ clutter_script_construct_parameters (ClutterScript *script,
continue;
}
if (!(pspec->flags & G_PARAM_CONSTRUCT_ONLY))
if (!(pspec->flags & (G_PARAM_CONSTRUCT | G_PARAM_CONSTRUCT_ONLY)))
{
unparsed = g_list_prepend (unparsed, pinfo);
continue;

View File

@ -682,7 +682,6 @@ clutter_seat_warp_pointer (ClutterSeat *seat,
* requirements are fulfilled:
*
* - A touchscreen is available
* - No external keyboard is attached to the device
* - A tablet mode switch, if present, is enabled
*
* Returns: %TRUE if the device is a tablet that doesn't have an external

View File

@ -50,11 +50,6 @@ ClutterStageWindow *_clutter_stage_get_window (ClutterStage
void _clutter_stage_get_projection_matrix (ClutterStage *stage,
CoglMatrix *projection);
void _clutter_stage_dirty_projection (ClutterStage *stage);
void _clutter_stage_set_viewport (ClutterStage *stage,
float x,
float y,
float width,
float height);
void _clutter_stage_get_viewport (ClutterStage *stage,
float *x,
float *y,
@ -130,9 +125,6 @@ gboolean _clutter_stage_update_state (ClutterStage *stag
void _clutter_stage_set_scale_factor (ClutterStage *stage,
int factor);
gboolean _clutter_stage_get_max_view_scale_factor_for_rect (ClutterStage *stage,
graphene_rect_t *rect,
float *view_scale);
void _clutter_stage_presented (ClutterStage *stage,
CoglFrameEvent frame_event,
@ -141,6 +133,9 @@ void _clutter_stage_presented (ClutterStage *stag
void clutter_stage_queue_actor_relayout (ClutterStage *stage,
ClutterActor *actor);
GList * clutter_stage_get_views_for_rect (ClutterStage *stage,
const graphene_rect_t *rect);
G_END_DECLS
#endif /* __CLUTTER_STAGE_PRIVATE_H__ */

View File

@ -189,6 +189,9 @@ static void capture_view_into (ClutterStage *stage,
uint8_t *data,
int stride);
static void clutter_stage_update_view_perspective (ClutterStage *stage);
static void clutter_stage_set_viewport (ClutterStage *stage,
float width,
float height);
static void clutter_container_iface_init (ClutterContainerIface *iface);
@ -619,7 +622,6 @@ clutter_stage_allocate (ClutterActor *self,
{
ClutterStagePrivate *priv = CLUTTER_STAGE (self)->priv;
ClutterActorBox alloc = CLUTTER_ACTOR_BOX_INIT_ZERO;
float old_width, old_height;
float new_width, new_height;
float width, height;
cairo_rectangle_int_t window_size;
@ -628,10 +630,6 @@ clutter_stage_allocate (ClutterActor *self,
if (priv->impl == NULL)
return;
/* our old allocation */
clutter_actor_get_allocation_box (self, &alloc);
clutter_actor_box_get_size (&alloc, &old_width, &old_height);
/* the current allocation */
clutter_actor_box_get_size (box, &width, &height);
@ -719,27 +717,11 @@ clutter_stage_allocate (ClutterActor *self,
&override);
}
/* reset the viewport if the allocation effectively changed */
/* set the viewport to the new allocation */
clutter_actor_get_allocation_box (self, &alloc);
clutter_actor_box_get_size (&alloc, &new_width, &new_height);
if (CLUTTER_NEARBYINT (old_width) != CLUTTER_NEARBYINT (new_width) ||
CLUTTER_NEARBYINT (old_height) != CLUTTER_NEARBYINT (new_height))
{
int real_width = CLUTTER_NEARBYINT (new_width);
int real_height = CLUTTER_NEARBYINT (new_height);
_clutter_stage_set_viewport (CLUTTER_STAGE (self),
0, 0,
real_width,
real_height);
/* Note: we don't assume that set_viewport will queue a full redraw
* since it may bail-out early if something preemptively set the
* viewport before the stage was really allocated its new size.
*/
queue_full_redraw (CLUTTER_STAGE (self));
}
clutter_stage_set_viewport (CLUTTER_STAGE (self), new_width, new_height);
}
typedef struct _Vector4
@ -1089,6 +1071,7 @@ clutter_stage_hide (ClutterActor *self)
ClutterStagePrivate *priv = CLUTTER_STAGE (self)->priv;
g_assert (priv->impl != NULL);
_clutter_stage_clear_pick_stack (CLUTTER_STAGE (self));
_clutter_stage_window_hide (priv->impl);
CLUTTER_ACTOR_CLASS (clutter_stage_parent_class)->hide (self);
@ -1486,6 +1469,14 @@ _clutter_stage_check_updated_pointers (ClutterStage *stage)
return updating;
}
static void
update_actor_stage_views (ClutterStage *stage)
{
ClutterActor *actor = CLUTTER_ACTOR (stage);
clutter_actor_update_stage_views (actor);
}
/**
* _clutter_stage_do_update:
* @stage: A #ClutterStage
@ -1533,6 +1524,10 @@ _clutter_stage_do_update (ClutterStage *stage)
if (stage_was_relayout)
pointers = _clutter_stage_check_updated_pointers (stage);
COGL_TRACE_BEGIN (ClutterStageUpdateActorStageViews, "Actor stage-views");
update_actor_stage_views (stage);
COGL_TRACE_END (ClutterStageUpdateActorStageViews);
COGL_TRACE_BEGIN (ClutterStagePaint, "Paint");
clutter_stage_maybe_finish_queue_redraws (stage);
@ -2257,10 +2252,7 @@ clutter_stage_init (ClutterStage *self)
g_signal_connect (self, "notify::min-height",
G_CALLBACK (clutter_stage_notify_min_size), NULL);
_clutter_stage_set_viewport (self,
0, 0,
geom.width,
geom.height);
clutter_stage_set_viewport (self, geom.width, geom.height);
priv->paint_volume_stack =
g_array_new (FALSE, FALSE, sizeof (ClutterPaintVolume));
@ -2447,8 +2439,6 @@ _clutter_stage_dirty_projection (ClutterStage *stage)
/*
* clutter_stage_set_viewport:
* @stage: A #ClutterStage
* @x: The X postition to render the stage at, in window coordinates
* @y: The Y position to render the stage at, in window coordinates
* @width: The width to render the stage at, in window coordinates
* @height: The height to render the stage at, in window coordinates
*
@ -2481,19 +2471,22 @@ _clutter_stage_dirty_projection (ClutterStage *stage)
*
* Since: 1.6
*/
void
_clutter_stage_set_viewport (ClutterStage *stage,
float x,
float y,
float width,
float height)
static void
clutter_stage_set_viewport (ClutterStage *stage,
float width,
float height)
{
ClutterStagePrivate *priv;
float x, y;
g_return_if_fail (CLUTTER_IS_STAGE (stage));
priv = stage->priv;
x = 0.f;
y = 0.f;
width = roundf (width);
height = roundf (height);
if (x == priv->viewport[0] &&
y == priv->viewport[1] &&
@ -3191,37 +3184,6 @@ _clutter_stage_maybe_setup_viewport (ClutterStage *stage,
#undef _DEG_TO_RAD
/**
* clutter_stage_ensure_redraw:
* @stage: a #ClutterStage
*
* Ensures that @stage is redrawn
*
* This function should not be called by applications: it is
* used when embedding a #ClutterStage into a toolkit with
* another windowing system, like GTK+.
*
* Since: 1.0
*/
void
clutter_stage_ensure_redraw (ClutterStage *stage)
{
ClutterMasterClock *master_clock;
ClutterStagePrivate *priv;
g_return_if_fail (CLUTTER_IS_STAGE (stage));
priv = stage->priv;
if (!_clutter_stage_needs_update (stage))
clutter_stage_schedule_update (stage);
priv->redraw_pending = TRUE;
master_clock = _clutter_master_clock_get_default ();
_clutter_master_clock_start_running (master_clock);
}
/**
* clutter_stage_is_redraw_queued: (skip)
*/
@ -4127,20 +4089,29 @@ clutter_stage_get_capture_final_size (ClutterStage *stage,
int *out_height,
float *out_scale)
{
float max_scale;
float max_scale = 1.0;
g_return_val_if_fail (CLUTTER_IS_STAGE (stage), FALSE);
if (rect)
{
graphene_rect_t capture_rect;
g_autoptr (GList) views = NULL;
GList *l;
_clutter_util_rect_from_rectangle (rect, &capture_rect);
if (!_clutter_stage_get_max_view_scale_factor_for_rect (stage,
&capture_rect,
&max_scale))
views = clutter_stage_get_views_for_rect (stage, &capture_rect);
if (!views)
return FALSE;
for (l = views; l; l = l->next)
{
ClutterStageView *view = l->data;
max_scale = MAX (clutter_stage_view_get_scale (view), max_scale);
}
if (out_width)
*out_width = (gint) roundf (rect->width * max_scale);
@ -4421,18 +4392,17 @@ clutter_stage_peek_stage_views (ClutterStage *stage)
}
void
clutter_stage_update_resource_scales (ClutterStage *stage)
clutter_stage_clear_stage_views (ClutterStage *stage)
{
_clutter_actor_queue_update_resource_scale_recursive (CLUTTER_ACTOR (stage));
clutter_actor_clear_stage_views_recursive (CLUTTER_ACTOR (stage));
}
gboolean
_clutter_stage_get_max_view_scale_factor_for_rect (ClutterStage *stage,
graphene_rect_t *rect,
float *view_scale)
GList *
clutter_stage_get_views_for_rect (ClutterStage *stage,
const graphene_rect_t *rect)
{
ClutterStagePrivate *priv = stage->priv;
float scale = 0.0f;
GList *views_for_rect = NULL;
GList *l;
for (l = _clutter_stage_window_get_views (priv->impl); l; l = l->next)
@ -4445,12 +4415,8 @@ _clutter_stage_get_max_view_scale_factor_for_rect (ClutterStage *stage,
_clutter_util_rect_from_rectangle (&view_layout, &view_rect);
if (graphene_rect_intersection (&view_rect, rect, NULL))
scale = MAX (clutter_stage_view_get_scale (view), scale);
views_for_rect = g_list_prepend (views_for_rect, view);
}
if (scale == 0.0)
return FALSE;
*view_scale = scale;
return TRUE;
return views_for_rect;
}

View File

@ -195,8 +195,6 @@ guchar * clutter_stage_read_pixels (ClutterStage
CLUTTER_EXPORT
void clutter_stage_ensure_viewport (ClutterStage *stage);
CLUTTER_EXPORT
void clutter_stage_ensure_redraw (ClutterStage *stage);
CLUTTER_EXPORT
gboolean clutter_stage_is_redraw_queued (ClutterStage *stage);

View File

@ -172,7 +172,6 @@ enum
{
PROP_0,
PROP_LOOP,
PROP_DELAY,
PROP_DURATION,
PROP_DIRECTION,
@ -290,23 +289,6 @@ clutter_timeline_add_marker_internal (ClutterTimeline *timeline,
g_hash_table_insert (priv->markers_by_name, marker->name, marker);
}
static inline void
clutter_timeline_set_loop_internal (ClutterTimeline *timeline,
gboolean loop)
{
gint old_repeat_count;
old_repeat_count = timeline->priv->repeat_count;
if (loop)
clutter_timeline_set_repeat_count (timeline, -1);
else
clutter_timeline_set_repeat_count (timeline, 0);
if (old_repeat_count != timeline->priv->repeat_count)
g_object_notify_by_pspec (G_OBJECT (timeline), obj_props[PROP_LOOP]);
}
/* Scriptable */
typedef struct _ParseClosure {
ClutterTimeline *timeline;
@ -448,10 +430,6 @@ clutter_timeline_set_property (GObject *object,
switch (prop_id)
{
case PROP_LOOP:
clutter_timeline_set_loop_internal (timeline, g_value_get_boolean (value));
break;
case PROP_DELAY:
clutter_timeline_set_delay (timeline, g_value_get_uint (value));
break;
@ -493,10 +471,6 @@ clutter_timeline_get_property (GObject *object,
switch (prop_id)
{
case PROP_LOOP:
g_value_set_boolean (value, priv->repeat_count != 0);
break;
case PROP_DELAY:
g_value_set_uint (value, priv->delay);
break;
@ -572,25 +546,6 @@ clutter_timeline_class_init (ClutterTimelineClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
/**
* ClutterTimeline:loop:
*
* Whether the timeline should automatically rewind and restart.
*
* As a side effect, setting this property to %TRUE will set the
* #ClutterTimeline:repeat-count property to -1, while setting this
* property to %FALSE will set the #ClutterTimeline:repeat-count
* property to 0.
*
* Deprecated: 1.10: Use the #ClutterTimeline:repeat-count property instead.
*/
obj_props[PROP_LOOP] =
g_param_spec_boolean ("loop",
P_("Loop"),
P_("Should the timeline automatically restart"),
FALSE,
CLUTTER_PARAM_READWRITE | G_PARAM_DEPRECATED);
/**
* ClutterTimeline:delay:
*
@ -1251,45 +1206,6 @@ clutter_timeline_stop (ClutterTimeline *timeline)
g_signal_emit (timeline, timeline_signals[STOPPED], 0, FALSE);
}
/**
* clutter_timeline_set_loop:
* @timeline: a #ClutterTimeline
* @loop: %TRUE for enable looping
*
* Sets whether @timeline should loop.
*
* This function is equivalent to calling clutter_timeline_set_repeat_count()
* with -1 if @loop is %TRUE, and with 0 if @loop is %FALSE.
*
* Deprecated: 1.10: Use clutter_timeline_set_repeat_count() instead.
*/
void
clutter_timeline_set_loop (ClutterTimeline *timeline,
gboolean loop)
{
g_return_if_fail (CLUTTER_IS_TIMELINE (timeline));
clutter_timeline_set_loop_internal (timeline, loop);
}
/**
* clutter_timeline_get_loop:
* @timeline: a #ClutterTimeline
*
* Gets whether @timeline is looping
*
* Return value: %TRUE if the timeline is looping
*
* Deprecated: 1.10: Use clutter_timeline_get_repeat_count() instead.
*/
gboolean
clutter_timeline_get_loop (ClutterTimeline *timeline)
{
g_return_val_if_fail (CLUTTER_IS_TIMELINE (timeline), FALSE);
return timeline->priv->repeat_count != 0;
}
/**
* clutter_timeline_rewind:
* @timeline: A #ClutterTimeline
@ -1405,49 +1321,11 @@ clutter_timeline_is_playing (ClutterTimeline *timeline)
return timeline->priv->is_playing;
}
/**
* clutter_timeline_clone:
* @timeline: #ClutterTimeline to duplicate.
*
* Create a new #ClutterTimeline instance which has property values
* matching that of supplied timeline. The cloned timeline will not
* be started and will not be positioned to the current position of
* the original @timeline: you will have to start it with
* clutter_timeline_start().
*
* The only cloned properties are:
*
* - #ClutterTimeline:duration
* - #ClutterTimeline:loop
* - #ClutterTimeline:delay
* - #ClutterTimeline:direction
*
* Return value: (transfer full): a new #ClutterTimeline, cloned
* from @timeline
*
* Since: 0.4
*
* Deprecated: 1.10: Use clutter_timeline_new() or g_object_new()
* instead
*/
ClutterTimeline *
clutter_timeline_clone (ClutterTimeline *timeline)
{
g_return_val_if_fail (CLUTTER_IS_TIMELINE (timeline), NULL);
return g_object_new (CLUTTER_TYPE_TIMELINE,
"duration", timeline->priv->duration,
"loop", timeline->priv->repeat_count != 0,
"delay", timeline->priv->delay,
"direction", timeline->priv->direction,
NULL);
}
/**
* clutter_timeline_new:
* @msecs: Duration of the timeline in milliseconds
* @duration_ms: Duration of the timeline in milliseconds
*
* Creates a new #ClutterTimeline with a duration of @msecs.
* Creates a new #ClutterTimeline with a duration of @duration_ms milli seconds.
*
* Return value: the newly created #ClutterTimeline instance. Use
* g_object_unref() when done using it
@ -1455,10 +1333,10 @@ clutter_timeline_clone (ClutterTimeline *timeline)
* Since: 0.6
*/
ClutterTimeline *
clutter_timeline_new (guint msecs)
clutter_timeline_new (guint duration_ms)
{
return g_object_new (CLUTTER_TYPE_TIMELINE,
"duration", msecs,
"duration", duration_ms,
NULL);
}

View File

@ -119,7 +119,7 @@ CLUTTER_EXPORT
GType clutter_timeline_get_type (void) G_GNUC_CONST;
CLUTTER_EXPORT
ClutterTimeline * clutter_timeline_new (guint msecs);
ClutterTimeline * clutter_timeline_new (guint duration_ms);
CLUTTER_EXPORT
guint clutter_timeline_get_duration (ClutterTimeline *timeline);

View File

@ -26,16 +26,6 @@
G_BEGIN_DECLS
CLUTTER_DEPRECATED_FOR(clutter_timeline_new)
ClutterTimeline * clutter_timeline_clone (ClutterTimeline *timeline);
CLUTTER_DEPRECATED_FOR(clutter_timeline_set_repeat_count)
void clutter_timeline_set_loop (ClutterTimeline *timeline,
gboolean loop);
CLUTTER_DEPRECATED_FOR(clutter_timeline_get_repeat_count)
gboolean clutter_timeline_get_loop (ClutterTimeline *timeline);
G_END_DECLS
#endif /* __CLUTTER_TIMELINE_PRIVATE_H__ */

View File

@ -43,8 +43,6 @@ struct _CoglFrameInfo
float refresh_rate;
int64_t global_frame_counter;
CoglOutput *output;
};
CoglFrameInfo *_cogl_frame_info_new (void);

View File

@ -72,12 +72,6 @@ cogl_frame_info_get_refresh_rate (CoglFrameInfo *info)
return info->refresh_rate;
}
CoglOutput *
cogl_frame_info_get_output (CoglFrameInfo *info)
{
return info->output;
}
int64_t
cogl_frame_info_get_global_frame_counter (CoglFrameInfo *info)
{

View File

@ -126,20 +126,6 @@ int64_t cogl_frame_info_get_presentation_time (CoglFrameInfo *info);
COGL_EXPORT
float cogl_frame_info_get_refresh_rate (CoglFrameInfo *info);
/**
* cogl_frame_info_get_output:
* @info: a #CoglFrameInfo object
*
* Gets the #CoglOutput that the swapped frame was presented to.
*
* Return value: (transfer none): The #CoglOutput that the frame was
* presented to, or %NULL if this could not be determined.
* Since: 1.14
* Stability: unstable
*/
COGL_EXPORT CoglOutput *
cogl_frame_info_get_output (CoglFrameInfo *info);
/**
* cogl_frame_info_get_global_frame_counter: (skip)
*/

View File

@ -1662,8 +1662,6 @@ set_frame_info_output (CoglOnscreen *onscreen,
{
CoglFrameInfo *info = g_queue_peek_tail (&onscreen->pending_frame_infos);
info->output = output;
if (output)
{
float refresh_rate = cogl_output_get_refresh_rate (output);

View File

@ -77,7 +77,7 @@ is_boolean_env_set (const char *variable)
return ret;
}
void
gboolean
test_utils_init (TestFlags requirement_flags,
TestFlags known_failure_flags)
{
@ -156,6 +156,8 @@ test_utils_init (TestFlags requirement_flags,
g_print ("WARNING: Missing required feature[s] for this test\n");
else if (known_failure)
g_print ("WARNING: Test is known to fail\n");
return (!missing_requirement && !known_failure);
}
void
@ -250,7 +252,17 @@ void
test_utils_check_pixel_rgb (CoglFramebuffer *test_fb,
int x, int y, int r, int g, int b)
{
test_utils_check_pixel (test_fb, x, y, (r << 24) | (g << 16) | (b << 8));
g_return_if_fail (r >= 0);
g_return_if_fail (g >= 0);
g_return_if_fail (b >= 0);
g_return_if_fail (r <= 0xFF);
g_return_if_fail (g <= 0xFF);
g_return_if_fail (b <= 0xFF);
test_utils_check_pixel (test_fb, x, y,
(((guint32) r) << 24) |
(((guint32) g) << 16) |
(((guint32) b) << 8));
}
void

View File

@ -68,7 +68,7 @@ typedef enum
extern CoglContext *test_ctx;
extern CoglFramebuffer *test_fb;
void
gboolean
test_utils_init (TestFlags requirement_flags,
TestFlags known_failure_flags);

View File

@ -99,9 +99,9 @@ verify_texture (CoglTexture *texture, int size)
};
test_utils_compare_pixel (p,
(real_color.red << 24) |
(real_color.green << 16) |
(real_color.blue << 8) |
(((guint32) real_color.red) << 24) |
(((guint32) real_color.green) << 16) |
(((guint32) real_color.blue) << 8) |
opacity);
g_assert_cmpint (p[3], ==, opacity);

View File

@ -15,10 +15,17 @@
G_STMT_START { \
if (strcmp (#FUNC, argv[1]) == 0) \
{ \
test_utils_init (REQUIREMENTS, KNOWN_FAIL_REQUIREMENTS); \
FUNC (); \
test_utils_fini (); \
exit (0); \
if (test_utils_init (REQUIREMENTS, KNOWN_FAIL_REQUIREMENTS) \
|| g_getenv ("COGL_TEST_TRY_EVERYTHING") != NULL) \
{ \
FUNC (); \
test_utils_fini (); \
exit (0); \
} \
else \
{ \
exit (1); \
} \
} \
} G_STMT_END
@ -55,7 +62,7 @@ main (int argc, char **argv)
ADD_TEST (test_pipeline_user_matrix, 0, 0);
ADD_TEST (test_blend_strings, 0, 0);
ADD_TEST (test_blend, 0, 0);
ADD_TEST (test_premult, 0, TEST_KNOWN_FAILURE);
ADD_TEST (test_premult, 0, 0);
UNPORTED_TEST (test_readpixels);
ADD_TEST (test_depth_test, 0, 0);
ADD_TEST (test_backface_culling, 0, TEST_REQUIREMENT_NPOT);

View File

@ -50,6 +50,7 @@ make_texture (uint32_t color,
CoglPixelFormat src_format,
MakeTextureFlags flags)
{
static CoglUserDataKey bitmap_free_key;
CoglTexture2D *tex_2d;
guchar *tex_data = gen_tex_data (color);
CoglBitmap *bmp = cogl_bitmap_new_for_data (test_ctx,
@ -58,6 +59,10 @@ make_texture (uint32_t color,
src_format,
QUAD_WIDTH * 4,
tex_data);
cogl_object_set_user_data (COGL_OBJECT (bmp),
&bitmap_free_key,
tex_data,
g_free);
tex_2d = cogl_texture_2d_new_from_bitmap (bmp);
@ -67,7 +72,6 @@ make_texture (uint32_t color,
cogl_texture_set_premultiplied (tex_2d, FALSE);
cogl_object_unref (bmp);
g_free (tex_data);
return tex_2d;
}

View File

@ -36,10 +36,16 @@ main (int argc, char **argv)
return 1;
}
test_utils_init (unit_test->requirement_flags,
unit_test->known_failure_flags);
unit_test->run ();
test_utils_fini ();
return 0;
if (test_utils_init (unit_test->requirement_flags,
unit_test->known_failure_flags)
|| g_getenv ("COGL_TEST_TRY_EVERYTHING") != NULL)
{
unit_test->run ();
test_utils_fini ();
return 0;
}
else
{
return 1;
}
}

View File

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

View File

@ -12,7 +12,7 @@ option('opengl_libname',
option('gles2_libname',
type: 'string',
value: 'libGLESv2.so',
value: 'libGLESv2.so.2',
description: 'GLESv2 library file name'
)

View File

@ -156,10 +156,6 @@ xkb_layout_index_t meta_backend_get_keymap_layout_group (MetaBackend *backend);
gboolean meta_backend_is_lid_closed (MetaBackend *backend);
void meta_backend_freeze_updates (MetaBackend *backend);
void meta_backend_thaw_updates (MetaBackend *backend);
void meta_backend_update_last_device (MetaBackend *backend,
ClutterInputDevice *device);

View File

@ -21,6 +21,8 @@
#ifndef META_BACKEND_TYPE_H
#define META_BACKEND_TYPE_H
typedef struct _MetaBackend MetaBackend;
typedef struct _MetaMonitorManager MetaMonitorManager;
typedef struct _MetaMonitorConfigManager MetaMonitorConfigManager;

View File

@ -575,12 +575,6 @@ meta_backend_real_post_init (MetaBackend *backend)
}
}
static MetaCursorRenderer *
meta_backend_real_create_cursor_renderer (MetaBackend *backend)
{
return meta_cursor_renderer_new ();
}
static gboolean
meta_backend_real_grab_device (MetaBackend *backend,
int device_id,
@ -762,7 +756,6 @@ meta_backend_class_init (MetaBackendClass *klass)
object_class->constructed = meta_backend_constructed;
klass->post_init = meta_backend_real_post_init;
klass->create_cursor_renderer = meta_backend_real_create_cursor_renderer;
klass->grab_device = meta_backend_real_grab_device;
klass->ungrab_device = meta_backend_real_ungrab_device;
klass->select_stage_events = meta_backend_real_select_stage_events;
@ -1275,24 +1268,6 @@ meta_backend_get_stage (MetaBackend *backend)
return priv->stage;
}
void
meta_backend_freeze_updates (MetaBackend *backend)
{
ClutterStage *stage;
stage = CLUTTER_STAGE (meta_backend_get_stage (backend));
clutter_stage_freeze_updates (stage);
}
void
meta_backend_thaw_updates (MetaBackend *backend)
{
ClutterStage *stage;
stage = CLUTTER_STAGE (meta_backend_get_stage (backend));
clutter_stage_thaw_updates (stage);
}
static gboolean
update_last_device (MetaBackend *backend)
{

View File

@ -38,8 +38,21 @@
G_DEFINE_INTERFACE (MetaHwCursorInhibitor, meta_hw_cursor_inhibitor,
G_TYPE_OBJECT)
enum
{
PROP_0,
PROP_BACKEND,
N_PROPS
};
static GParamSpec *obj_props[N_PROPS];
struct _MetaCursorRendererPrivate
{
MetaBackend *backend;
float current_x;
float current_y;
@ -89,8 +102,7 @@ align_cursor_position (MetaCursorRenderer *renderer,
{
MetaCursorRendererPrivate *priv =
meta_cursor_renderer_get_instance_private (renderer);
MetaBackend *backend = meta_get_backend ();
ClutterActor *stage = meta_backend_get_stage (backend);
ClutterActor *stage = meta_backend_get_stage (priv->backend);
ClutterStageView *view;
cairo_rectangle_int_t view_layout;
float view_scale;
@ -115,8 +127,7 @@ queue_redraw (MetaCursorRenderer *renderer,
MetaCursorSprite *cursor_sprite)
{
MetaCursorRendererPrivate *priv = meta_cursor_renderer_get_instance_private (renderer);
MetaBackend *backend = meta_get_backend ();
ClutterActor *stage = meta_backend_get_stage (backend);
ClutterActor *stage = meta_backend_get_stage (priv->backend);
CoglTexture *texture;
graphene_rect_t rect = GRAPHENE_RECT_INIT_ZERO;
@ -165,13 +176,54 @@ meta_cursor_renderer_real_update_cursor (MetaCursorRenderer *renderer,
return FALSE;
}
static void
meta_cursor_renderer_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
MetaCursorRenderer *renderer = META_CURSOR_RENDERER (object);
MetaCursorRendererPrivate *priv =
meta_cursor_renderer_get_instance_private (renderer);
switch (prop_id)
{
case PROP_BACKEND:
g_value_set_object (value, priv->backend);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
meta_cursor_renderer_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
MetaCursorRenderer *renderer = META_CURSOR_RENDERER (object);
MetaCursorRendererPrivate *priv =
meta_cursor_renderer_get_instance_private (renderer);
switch (prop_id)
{
case PROP_BACKEND:
priv->backend = g_value_get_object (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
meta_cursor_renderer_finalize (GObject *object)
{
MetaCursorRenderer *renderer = META_CURSOR_RENDERER (object);
MetaCursorRendererPrivate *priv = meta_cursor_renderer_get_instance_private (renderer);
MetaBackend *backend = meta_get_backend ();
ClutterActor *stage = meta_backend_get_stage (backend);
ClutterActor *stage = meta_backend_get_stage (priv->backend);
if (priv->stage_overlay)
meta_stage_remove_cursor_overlay (META_STAGE (stage), priv->stage_overlay);
@ -186,9 +238,21 @@ meta_cursor_renderer_class_init (MetaCursorRendererClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->get_property = meta_cursor_renderer_get_property;
object_class->set_property = meta_cursor_renderer_set_property;
object_class->finalize = meta_cursor_renderer_finalize;
klass->update_cursor = meta_cursor_renderer_real_update_cursor;
obj_props[PROP_BACKEND] =
g_param_spec_object ("backend",
"backend",
"MetaBackend",
META_TYPE_BACKEND,
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS);
g_object_class_install_properties (object_class, N_PROPS, obj_props);
signals[CURSOR_PAINTED] = g_signal_new ("cursor-painted",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST,
@ -273,9 +337,11 @@ meta_cursor_renderer_update_cursor (MetaCursorRenderer *renderer,
}
MetaCursorRenderer *
meta_cursor_renderer_new (void)
meta_cursor_renderer_new (MetaBackend *backend)
{
return g_object_new (META_TYPE_CURSOR_RENDERER, NULL);
return g_object_new (META_TYPE_CURSOR_RENDERER,
"backend", backend,
NULL);
}
void

View File

@ -54,7 +54,7 @@ struct _MetaCursorRendererClass
MetaCursorSprite *cursor_sprite);
};
MetaCursorRenderer * meta_cursor_renderer_new (void);
MetaCursorRenderer * meta_cursor_renderer_new (MetaBackend *backend);
void meta_cursor_renderer_set_cursor (MetaCursorRenderer *renderer,
MetaCursorSprite *cursor_sprite);

View File

@ -0,0 +1,56 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/*
* Utilities for use with libxkbcommon
*
* Copyright 2019 Red Hat, Inc.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include "config.h"
#include "backends/meta-keymap-utils.h"
#include <glib.h>
#include <limits.h>
struct xkb_context *
meta_create_xkb_context (void)
{
struct xkb_context *ctx;
char xdg[PATH_MAX] = {0};
const char *env;
/*
* We can only append search paths in libxkbcommon, so we start with an
* emtpy set, then add the XDG dir, then add the default search paths.
*/
ctx = xkb_context_new (XKB_CONTEXT_NO_DEFAULT_INCLUDES);
env = g_getenv ("XDG_CONFIG_HOME");
if (env)
{
g_snprintf (xdg, sizeof xdg, "%s/xkb", env);
}
else if ((env = g_getenv ("HOME")))
{
g_snprintf (xdg, sizeof xdg, "%s/.config/xkb", env);
}
if (env)
xkb_context_include_path_append (ctx, xdg);
xkb_context_include_path_append_default (ctx);
return ctx;
}

View File

@ -0,0 +1,28 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/*
* Utilities for use with libxkbcommon
*
* Copyright 2020 Red Hat, Inc.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef META_KEYMAP_UTILS_H
#define META_KEYMAP_UTILS_H
#include <xkbcommon/xkbcommon.h>
struct xkb_context * meta_create_xkb_context (void);
#endif /* META_KEYMAP_UTILS_H */

View File

@ -996,8 +996,8 @@ meta_screen_cast_stream_src_finalize (GObject *object)
if (meta_screen_cast_stream_src_is_enabled (src))
meta_screen_cast_stream_src_disable (src);
g_clear_pointer (&priv->dmabuf_handles, g_hash_table_destroy);
g_clear_pointer (&priv->pipewire_stream, pw_stream_destroy);
g_clear_pointer (&priv->dmabuf_handles, g_hash_table_destroy);
g_clear_pointer (&priv->pipewire_core, pw_core_disconnect);
g_clear_pointer (&priv->pipewire_context, pw_context_destroy);
g_source_destroy (&priv->pipewire_source->base);

View File

@ -42,6 +42,7 @@
#include "backends/meta-cursor-tracker-private.h"
#include "backends/meta-idle-monitor-private.h"
#include "backends/meta-keymap-utils.h"
#include "backends/meta-logical-monitor.h"
#include "backends/meta-monitor-manager-private.h"
#include "backends/meta-pointer-constraint.h"
@ -340,7 +341,7 @@ meta_backend_native_create_clutter_backend (MetaBackend *backend)
static void
meta_backend_native_post_init (MetaBackend *backend)
{
ClutterBackend *clutter_backend = clutter_get_default_backend ();
ClutterBackend *clutter_backend = meta_backend_get_clutter_backend (backend);
ClutterSeat *seat = clutter_backend_get_default_seat (clutter_backend);
MetaSettings *settings = meta_backend_get_settings (backend);
@ -425,6 +426,7 @@ meta_backend_native_set_keymap (MetaBackend *backend,
const char *variants,
const char *options)
{
ClutterBackend *clutter_backend = meta_backend_get_clutter_backend (backend);
struct xkb_rule_names names;
struct xkb_keymap *keymap;
struct xkb_context *context;
@ -436,11 +438,11 @@ meta_backend_native_set_keymap (MetaBackend *backend,
names.variant = variants;
names.options = options;
context = xkb_context_new (XKB_CONTEXT_NO_FLAGS);
context = meta_create_xkb_context ();
keymap = xkb_keymap_new_from_names (context, &names, XKB_KEYMAP_COMPILE_NO_FLAGS);
xkb_context_unref (context);
seat = clutter_backend_get_default_seat (clutter_get_default_backend ());
seat = clutter_backend_get_default_seat (clutter_backend);
meta_seat_native_set_keyboard_map (META_SEAT_NATIVE (seat), keymap);
meta_backend_notify_keymap_changed (backend);
@ -451,18 +453,20 @@ meta_backend_native_set_keymap (MetaBackend *backend,
static struct xkb_keymap *
meta_backend_native_get_keymap (MetaBackend *backend)
{
ClutterBackend *clutter_backend = meta_backend_get_clutter_backend (backend);
ClutterSeat *seat;
seat = clutter_backend_get_default_seat (clutter_get_default_backend ());
seat = clutter_backend_get_default_seat (clutter_backend);
return meta_seat_native_get_keyboard_map (META_SEAT_NATIVE (seat));
}
static xkb_layout_index_t
meta_backend_native_get_keymap_layout_group (MetaBackend *backend)
{
ClutterBackend *clutter_backend = meta_backend_get_clutter_backend (backend);
ClutterSeat *seat;
seat = clutter_backend_get_default_seat (clutter_get_default_backend ());
seat = clutter_backend_get_default_seat (clutter_backend);
return meta_seat_native_get_keyboard_layout_index (META_SEAT_NATIVE (seat));
}
@ -470,6 +474,7 @@ static void
meta_backend_native_lock_layout_group (MetaBackend *backend,
guint idx)
{
ClutterBackend *clutter_backend = meta_backend_get_clutter_backend (backend);
xkb_layout_index_t old_idx;
ClutterSeat *seat;
@ -477,7 +482,7 @@ meta_backend_native_lock_layout_group (MetaBackend *backend,
if (old_idx == idx)
return;
seat = clutter_backend_get_default_seat (clutter_get_default_backend ());
seat = clutter_backend_get_default_seat (clutter_backend);
meta_seat_native_set_keyboard_layout_index (META_SEAT_NATIVE (seat), idx);
meta_backend_notify_keymap_layout_group_changed (backend, idx);
}
@ -486,9 +491,10 @@ static void
meta_backend_native_set_numlock (MetaBackend *backend,
gboolean numlock_state)
{
ClutterBackend *clutter_backend = meta_backend_get_clutter_backend (backend);
ClutterSeat *seat;
seat = clutter_backend_get_default_seat (clutter_get_default_backend ());
seat = clutter_backend_get_default_seat (clutter_backend);
meta_seat_native_set_keyboard_numlock (META_SEAT_NATIVE (seat),
numlock_state);
}
@ -780,7 +786,7 @@ meta_backend_native_pause (MetaBackendNative *native)
meta_backend_get_monitor_manager (backend);
MetaMonitorManagerKms *monitor_manager_kms =
META_MONITOR_MANAGER_KMS (monitor_manager);
ClutterBackend *clutter_backend = clutter_get_default_backend ();
ClutterBackend *clutter_backend = meta_backend_get_clutter_backend (backend);
MetaSeatNative *seat =
META_SEAT_NATIVE (clutter_backend_get_default_seat (clutter_backend));
@ -805,7 +811,7 @@ void meta_backend_native_resume (MetaBackendNative *native)
META_MONITOR_MANAGER_KMS (monitor_manager);
MetaInputSettings *input_settings;
MetaIdleMonitor *idle_monitor;
ClutterBackend *clutter_backend = clutter_get_default_backend ();
ClutterBackend *clutter_backend = meta_backend_get_clutter_backend (backend);
MetaSeatNative *seat =
META_SEAT_NATIVE (clutter_backend_get_default_seat (clutter_backend));

View File

@ -1719,8 +1719,9 @@ meta_cursor_renderer_native_new (MetaBackend *backend)
MetaCursorRendererNative *cursor_renderer_native;
MetaCursorRendererNativePrivate *priv;
cursor_renderer_native =
g_object_new (META_TYPE_CURSOR_RENDERER_NATIVE, NULL);
cursor_renderer_native = g_object_new (META_TYPE_CURSOR_RENDERER_NATIVE,
"backend", backend,
NULL);
priv =
meta_cursor_renderer_native_get_instance_private (cursor_renderer_native);

View File

@ -21,6 +21,7 @@
#include "config.h"
#include "backends/meta-keymap-utils.h"
#include "backends/native/meta-keymap-native.h"
#include "backends/native/meta-seat-native.h"
@ -111,7 +112,7 @@ meta_keymap_native_init (MetaKeymapNative *keymap)
names.variant = option_xkb_variant;
names.options = option_xkb_options;
ctx = xkb_context_new (XKB_CONTEXT_NO_FLAGS);
ctx = meta_create_xkb_context ();
g_assert (ctx);
keymap->keymap = xkb_keymap_new_from_names (ctx, &names, 0);
xkb_context_unref (ctx);

View File

@ -2168,6 +2168,7 @@ meta_renderer_native_create_dma_buf (CoglRenderer *cogl_renderer,
case META_RENDERER_NATIVE_MODE_GBM:
{
CoglFramebuffer *dmabuf_fb;
CoglDmaBufHandle *dmabuf_handle;
struct gbm_bo *new_bo;
int stride;
int offset;
@ -2210,10 +2211,13 @@ meta_renderer_native_create_dma_buf (CoglRenderer *cogl_renderer,
if (!dmabuf_fb)
return NULL;
return cogl_dma_buf_handle_new (dmabuf_fb, dmabuf_fd,
width, height, stride, offset, bpp,
new_bo,
(GDestroyNotify) gbm_bo_destroy);
dmabuf_handle =
cogl_dma_buf_handle_new (dmabuf_fb, dmabuf_fd,
width, height, stride, offset, bpp,
new_bo,
(GDestroyNotify) gbm_bo_destroy);
cogl_object_unref (dmabuf_fb);
return dmabuf_handle;
}
break;
#ifdef HAVE_EGL_DEVICE

View File

@ -1380,35 +1380,6 @@ has_touchscreen (MetaSeatNative *seat)
return FALSE;
}
static gboolean
has_external_keyboard (MetaSeatNative *seat)
{
GList *devices, *l;
gboolean has_external = FALSE;
devices = g_udev_client_query_by_subsystem (seat->udev_client, "input");
for (l = devices; l; l = l->next)
{
if (!g_udev_device_has_property (l->data, "ID_INPUT_KEYBOARD"))
continue;
/* May be "hid" or something else, we don't care. This property
* will not be present in virtual "AT Translated Set 2 keyboard"
* devices.
*/
if (!g_udev_device_has_property (l->data, "ID_TYPE"))
break;
has_external = TRUE;
break;
}
g_list_free_full (devices, g_object_unref);
return has_external;
}
static void
update_touch_mode (MetaSeatNative *seat)
{
@ -1421,10 +1392,10 @@ update_touch_mode (MetaSeatNative *seat)
else if (seat->has_tablet_switch && !seat->tablet_mode_switch_state)
touch_mode = FALSE;
/* If tablet mode is enabled, or if there is no tablet mode switch
* (eg. kiosk machines), check availability of external keyboards.
* (eg. kiosk machines), assume touch-mode.
*/
else
touch_mode = !seat->has_external_keyboard;
touch_mode = TRUE;
if (seat->touch_mode != touch_mode)
{
@ -1465,12 +1436,7 @@ evdev_add_device (MetaSeatNative *seat,
g_signal_emit_by_name (seat, "device-added", device);
if (type == CLUTTER_KEYBOARD_DEVICE)
{
seat->has_external_keyboard = has_external_keyboard (seat);
check_touch_mode = TRUE;
}
else if (type == CLUTTER_TOUCHSCREEN_DEVICE)
if (type == CLUTTER_TOUCHSCREEN_DEVICE)
{
seat->has_touchscreen = TRUE;
check_touch_mode = TRUE;
@ -1503,12 +1469,7 @@ evdev_remove_device (MetaSeatNative *seat,
device_type = clutter_input_device_get_device_type (device);
if (device_type == CLUTTER_KEYBOARD_DEVICE)
{
seat->has_external_keyboard = has_external_keyboard (seat);
update_touch_mode (seat);
}
else if (device_type == CLUTTER_TOUCHSCREEN_DEVICE)
if (device_type == CLUTTER_TOUCHSCREEN_DEVICE)
{
seat->has_touchscreen = has_touchscreen (seat);
update_touch_mode (seat);
@ -2553,7 +2514,6 @@ meta_seat_native_constructed (GObject *object)
xkb_keymap_led_get_index (xkb_keymap, XKB_LED_NAME_SCROLL);
}
seat->has_external_keyboard = has_external_keyboard (seat);
seat->has_touchscreen = has_touchscreen (seat);
update_touch_mode (seat);

View File

@ -120,7 +120,6 @@ struct _MetaSeatNative
GUdevClient *udev_client;
guint tablet_mode_switch_state : 1;
guint has_external_keyboard : 1;
guint has_touchscreen : 1;
guint has_tablet_switch : 1;
guint touch_mode : 1;

View File

@ -140,7 +140,7 @@ meta_stage_native_rebuild_views (MetaStageNative *stage_native)
ClutterActor *stage = meta_backend_get_stage (backend);
meta_renderer_rebuild_views (renderer);
clutter_stage_update_resource_scales (CLUTTER_STAGE (stage));
clutter_stage_clear_stage_views (CLUTTER_STAGE (stage));
ensure_frame_callbacks (stage_native);
}

View File

@ -117,7 +117,9 @@ meta_backend_x11_cm_create_monitor_manager (MetaBackend *backend,
static MetaCursorRenderer *
meta_backend_x11_cm_create_cursor_renderer (MetaBackend *backend)
{
return g_object_new (META_TYPE_CURSOR_RENDERER_X11, NULL);
return g_object_new (META_TYPE_CURSOR_RENDERER_X11,
"backend", backend,
NULL);
}
static MetaInputSettings *

View File

@ -43,6 +43,7 @@
#include <xkbcommon/xkbcommon-x11.h>
#include "backends/meta-idle-monitor-private.h"
#include "backends/meta-keymap-utils.h"
#include "backends/meta-stage-private.h"
#include "backends/x11/meta-clutter-backend-x11.h"
#include "backends/x11/meta-event-x11.h"
@ -704,7 +705,7 @@ meta_backend_x11_get_keymap (MetaBackend *backend)
if (priv->keymap == NULL)
{
struct xkb_context *context = xkb_context_new (XKB_CONTEXT_NO_FLAGS);
struct xkb_context *context = meta_create_xkb_context ();
priv->keymap = xkb_x11_keymap_new_from_device (context,
priv->xcb,
xkb_x11_get_core_keyboard_device_id (priv->xcb),

View File

@ -38,7 +38,10 @@ enum
PROP_OPCODE,
PROP_POINTER_ID,
PROP_KEYBOARD_ID,
N_PROPS
N_PROPS,
/* This property is overridden */
PROP_TOUCH_MODE,
};
struct _MetaSeatX11
@ -54,6 +57,8 @@ struct _MetaSeatX11
int pointer_id;
int keyboard_id;
int opcode;
guint has_touchscreens : 1;
guint touch_mode : 1;
};
static GParamSpec *props[N_PROPS] = { 0 };
@ -605,6 +610,20 @@ pad_passive_button_grab (ClutterInputDevice *device)
g_free (xi_event_mask.mask);
}
static void
update_touch_mode (MetaSeatX11 *seat_x11)
{
gboolean touch_mode;
touch_mode = seat_x11->has_touchscreens;
if (seat_x11->touch_mode == touch_mode)
return;
seat_x11->touch_mode = touch_mode;
g_object_notify (G_OBJECT (seat_x11), "touch-mode");
}
static ClutterInputDevice *
add_device (MetaSeatX11 *seat_x11,
ClutterBackend *backend,
@ -635,6 +654,8 @@ add_device (MetaSeatX11 *seat_x11,
info->attachment == seat_x11->keyboard_id))
{
seat_x11->devices = g_list_prepend (seat_x11->devices, device);
seat_x11->has_touchscreens |=
clutter_input_device_get_device_type (device) == CLUTTER_TOUCHSCREEN_DEVICE;
}
else
{
@ -663,18 +684,38 @@ add_device (MetaSeatX11 *seat_x11,
}
}
update_touch_mode (seat_x11);
return device;
}
static gboolean
has_touchscreens (MetaSeatX11 *seat_x11)
{
GList *l;
for (l = seat_x11->devices; l; l = l->next)
{
if (clutter_input_device_get_device_type (l->data) == CLUTTER_TOUCHSCREEN_DEVICE)
return TRUE;
}
return FALSE;
}
static void
remove_device (MetaSeatX11 *seat_x11,
int device_id)
{
ClutterInputDevice *device;
gboolean check_touchscreens = FALSE;
device = g_hash_table_lookup (seat_x11->devices_by_id,
GINT_TO_POINTER (device_id));
if (clutter_input_device_get_device_type (device) == CLUTTER_TOUCHSCREEN_DEVICE)
check_touchscreens = TRUE;
if (device != NULL)
{
if (seat_x11->core_pointer == device)
@ -695,6 +736,12 @@ remove_device (MetaSeatX11 *seat_x11,
g_hash_table_remove (seat_x11->devices_by_id,
GINT_TO_POINTER (device_id));
}
if (check_touchscreens)
{
seat_x11->has_touchscreens = has_touchscreens (seat_x11);
update_touch_mode (seat_x11);
}
}
static void
@ -1272,6 +1319,7 @@ meta_seat_x11_set_property (GObject *object,
case PROP_KEYBOARD_ID:
seat_x11->keyboard_id = g_value_get_int (value);
break;
case PROP_TOUCH_MODE:
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
@ -1296,6 +1344,9 @@ meta_seat_x11_get_property (GObject *object,
case PROP_KEYBOARD_ID:
g_value_set_int (value, seat_x11->keyboard_id);
break;
case PROP_TOUCH_MODE:
g_value_set_boolean (value, seat_x11->touch_mode);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
@ -1547,6 +1598,9 @@ meta_seat_x11_class_init (MetaSeatX11Class *klass)
G_PARAM_CONSTRUCT_ONLY);
g_object_class_install_properties (object_class, N_PROPS, props);
g_object_class_override_property (object_class, PROP_TOUCH_MODE,
"touch-mode");
}
static void

View File

@ -65,7 +65,9 @@ meta_backend_x11_nested_create_monitor_manager (MetaBackend *backend,
static MetaCursorRenderer *
meta_backend_x11_nested_create_cursor_renderer (MetaBackend *backend)
{
return g_object_new (META_TYPE_CURSOR_RENDERER_X11_NESTED, NULL);
return g_object_new (META_TYPE_CURSOR_RENDERER_X11_NESTED,
"backend", backend,
NULL);
}
static MetaInputSettings *
@ -85,7 +87,7 @@ meta_backend_x11_nested_update_screen_size (MetaBackend *backend,
if (meta_is_stage_views_enabled ())
{
meta_renderer_rebuild_views (renderer);
clutter_stage_update_resource_scales (CLUTTER_STAGE (stage));
clutter_stage_clear_stage_views (CLUTTER_STAGE (stage));
}
clutter_actor_set_size (stage, width, height);
}

View File

@ -91,6 +91,7 @@ enum
PROP_0,
PROP_DISPLAY,
PROP_BACKEND,
N_PROPS
};
@ -111,6 +112,7 @@ typedef struct _MetaCompositorPrivate
GObject parent;
MetaDisplay *display;
MetaBackend *backend;
guint pre_paint_func_id;
guint post_paint_func_id;
@ -231,7 +233,7 @@ meta_get_stage_for_display (MetaDisplay *display)
g_return_val_if_fail (compositor, NULL);
priv = meta_compositor_get_instance_private (compositor);
return priv->stage;
return meta_backend_get_stage (priv->backend);
}
/**
@ -564,12 +566,11 @@ meta_compositor_do_manage (MetaCompositor *compositor,
MetaCompositorPrivate *priv =
meta_compositor_get_instance_private (compositor);
MetaDisplay *display = priv->display;
MetaBackend *backend = meta_get_backend ();
priv->stage = meta_backend_get_stage (backend);
MetaBackend *backend = priv->backend;
ClutterActor *stage = meta_backend_get_stage (backend);
priv->stage_presented_id =
g_signal_connect (priv->stage, "presented",
g_signal_connect (stage, "presented",
G_CALLBACK (on_presented),
compositor);
@ -582,18 +583,18 @@ meta_compositor_do_manage (MetaCompositor *compositor,
* matter.
*/
priv->stage_after_paint_id =
g_signal_connect_after (priv->stage, "after-paint",
g_signal_connect_after (stage, "after-paint",
G_CALLBACK (after_stage_paint), compositor);
clutter_stage_set_sync_delay (CLUTTER_STAGE (priv->stage), META_SYNC_DELAY);
clutter_stage_set_sync_delay (CLUTTER_STAGE (stage), META_SYNC_DELAY);
priv->window_group = meta_window_group_new (display);
priv->top_window_group = meta_window_group_new (display);
priv->feedback_group = meta_window_group_new (display);
clutter_actor_add_child (priv->stage, priv->window_group);
clutter_actor_add_child (priv->stage, priv->top_window_group);
clutter_actor_add_child (priv->stage, priv->feedback_group);
clutter_actor_add_child (stage, priv->window_group);
clutter_actor_add_child (stage, priv->top_window_group);
clutter_actor_add_child (stage, priv->feedback_group);
if (!META_COMPOSITOR_GET_CLASS (compositor)->manage (compositor, error))
return FALSE;
@ -1162,7 +1163,7 @@ meta_compositor_real_post_paint (MetaCompositor *compositor)
case COGL_GRAPHICS_RESET_STATUS_PURGED_CONTEXT_RESET:
g_signal_emit_by_name (priv->display, "gl-video-memory-purged");
clutter_actor_queue_redraw (CLUTTER_ACTOR (priv->stage));
clutter_actor_queue_redraw (meta_backend_get_stage (priv->backend));
break;
default:
@ -1211,6 +1212,9 @@ meta_compositor_set_property (GObject *object,
case PROP_DISPLAY:
priv->display = g_value_get_object (value);
break;
case PROP_BACKEND:
priv->backend = g_value_get_object (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
@ -1231,6 +1235,9 @@ meta_compositor_get_property (GObject *object,
case PROP_DISPLAY:
g_value_set_object (value, priv->display);
break;
case PROP_BACKEND:
g_value_set_object (value, priv->backend);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
@ -1266,11 +1273,12 @@ meta_compositor_dispose (GObject *object)
MetaCompositor *compositor = META_COMPOSITOR (object);
MetaCompositorPrivate *priv =
meta_compositor_get_instance_private (compositor);
ClutterActor *stage = meta_backend_get_stage (priv->backend);
g_clear_pointer (&priv->laters, meta_laters_free);
g_clear_signal_handler (&priv->stage_after_paint_id, priv->stage);
g_clear_signal_handler (&priv->stage_presented_id, priv->stage);
g_clear_signal_handler (&priv->stage_after_paint_id, stage);
g_clear_signal_handler (&priv->stage_presented_id, stage);
g_clear_handle_id (&priv->pre_paint_func_id,
clutter_threads_remove_repaint_func);
@ -1309,6 +1317,14 @@ meta_compositor_class_init (MetaCompositorClass *klass)
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS);
obj_props[PROP_BACKEND] =
g_param_spec_object ("backend",
"backend",
"MetaBackend",
META_TYPE_BACKEND,
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS);
g_object_class_install_properties (object_class, N_PROPS, obj_props);
signals[PRE_PAINT] =
@ -1615,7 +1631,7 @@ meta_compositor_get_stage (MetaCompositor *compositor)
MetaCompositorPrivate *priv =
meta_compositor_get_instance_private (compositor);
return CLUTTER_STAGE (priv->stage);
return CLUTTER_STAGE (meta_backend_get_stage (priv->backend));
}
MetaWindowActor *

View File

@ -19,142 +19,19 @@
* Portions adapted from gnome-shell/src/shell-global.c
*/
/**
* SECTION:meta-background-actor
* @title: MetaBackgroundActor
* @short_description: Actor for painting the root window background
*
*/
/*
* The overall model drawing model of this widget is that we have one
* texture, or two interpolated textures, possibly with alpha or
* margins that let the underlying background show through, blended
* over a solid color or a gradient. The result of that combination
* can then be affected by a "vignette" that darkens the background
* away from a central point (or as a no-GLSL fallback, simply darkens
* the background) and by overall opacity.
*
* As of GNOME 3.14, GNOME is only using a fraction of this when the
* user sets the background through the control center - what can be
* set is:
*
* A single image without a border
* An animation of images without a border that blend together,
* with the blend changing every 4-5 minutes
* A solid color with a repeated noise texture blended over it
*
* This all is pretty easy to do in a fragment shader, except when:
*
* A) We don't have GLSL - in this case, the operation of
* interpolating the two textures and blending the result over the
* background can't be expressed with Cogl's fixed-function layer
* combining (which is confined to what GL's texture environment
* combining can do) So we can only handle the above directly if
* there are no margins or alpha.
*
* B) The image textures are sliced. Texture size limits on older
* hardware (pre-965 intel hardware, r300, etc.) is often 2048,
* and it would be common to use a texture larger than this for a
* background and expect it to be scaled down. Cogl can compensate
* for this by breaking the texture up into multiple textures, but
* can't multitexture with sliced textures. So we can only handle
* the above if there's a single texture.
*
* However, even when we *can* represent everything in a single pass,
* it's not necessarily efficient. If we want to draw a 1024x768
* background, it's pretty inefficient to bilinearly texture from
* two 2560x1440 images and mix that. So the drawing model we take
* here is that MetaBackground generates a single texture (which
* might be a 1x1 texture for a solid color, or a 1x2 texture for a
* gradient, or a repeated texture for wallpaper, or a pre-rendered
* texture the size of the screen), and we draw with that, possibly
* adding the vignette and opacity.
*/
#include "config.h"
#include "compositor/meta-background-actor-private.h"
#include "compositor/meta-background-content-private.h"
#include "clutter/clutter.h"
#include "compositor/clutter-utils.h"
#include "compositor/cogl-utils.h"
#include "compositor/meta-background-private.h"
#include "compositor/meta-cullable.h"
#include "meta/display.h"
#include "meta/meta-x11-errors.h"
enum
{
PROP_META_DISPLAY = 1,
PROP_MONITOR,
PROP_BACKGROUND,
PROP_GRADIENT,
PROP_GRADIENT_HEIGHT,
PROP_GRADIENT_MAX_DARKNESS,
PROP_VIGNETTE,
PROP_VIGNETTE_SHARPNESS,
PROP_VIGNETTE_BRIGHTNESS
};
typedef enum
{
CHANGED_BACKGROUND = 1 << 0,
CHANGED_EFFECTS = 1 << 2,
CHANGED_VIGNETTE_PARAMETERS = 1 << 3,
CHANGED_GRADIENT_PARAMETERS = 1 << 4,
CHANGED_ALL = 0xFFFF
} ChangedFlags;
#define GRADIENT_VERTEX_SHADER_DECLARATIONS \
"uniform vec2 scale;\n" \
"varying vec2 position;\n" \
#define GRADIENT_VERTEX_SHADER_CODE \
"position = cogl_tex_coord0_in.xy * scale;\n" \
#define GRADIENT_FRAGMENT_SHADER_DECLARATIONS \
"uniform float gradient_height_perc;\n" \
"uniform float gradient_max_darkness;\n" \
"varying vec2 position;\n" \
#define GRADIENT_FRAGMENT_SHADER_CODE \
"float min_brightness = 1.0 - gradient_max_darkness;\n" \
"float gradient_y_pos = min(position.y, gradient_height_perc) / gradient_height_perc;\n" \
"float pixel_brightness = (1.0 - min_brightness) * gradient_y_pos + min_brightness;\n" \
"cogl_color_out.rgb = cogl_color_out.rgb * pixel_brightness;\n" \
#define VIGNETTE_VERTEX_SHADER_DECLARATIONS \
"uniform vec2 scale;\n" \
"uniform vec2 offset;\n" \
"varying vec2 position;\n" \
#define VIGNETTE_VERTEX_SHADER_CODE \
"position = cogl_tex_coord0_in.xy * scale + offset;\n" \
#define VIGNETTE_SQRT_2 "1.4142"
#define VIGNETTE_FRAGMENT_SHADER_DECLARATIONS \
"uniform float vignette_sharpness;\n" \
"varying vec2 position;\n" \
"float rand(vec2 p) { return fract(sin(dot(p, vec2(12.9898, 78.233))) * 43758.5453123); }\n" \
#define VIGNETTE_FRAGMENT_SHADER_CODE \
"float t = " VIGNETTE_SQRT_2 " * length(position);\n" \
"t = min(t, 1.0);\n" \
"float pixel_brightness = 1.0 - t * vignette_sharpness;\n" \
"cogl_color_out.rgb = cogl_color_out.rgb * pixel_brightness;\n" \
"cogl_color_out.rgb += (rand(position) - 0.5) / 255.0;\n" \
typedef struct _MetaBackgroundLayer MetaBackgroundLayer;
typedef enum
{
PIPELINE_VIGNETTE = (1 << 0),
PIPELINE_BLEND = (1 << 1),
PIPELINE_GRADIENT = (1 << 2),
} PipelineFlags;
struct _MetaBackgroundActor
{
ClutterActor parent;
@ -162,24 +39,7 @@ struct _MetaBackgroundActor
MetaDisplay *display;
int monitor;
MetaBackground *background;
gboolean gradient;
double gradient_max_darkness;
int gradient_height;
gboolean vignette;
double vignette_brightness;
double vignette_sharpness;
ChangedFlags changed;
CoglPipeline *pipeline;
PipelineFlags pipeline_flags;
cairo_rectangle_int_t texture_area;
gboolean force_bilinear;
cairo_region_t *clip_region;
cairo_region_t *unobscured_region;
MetaBackgroundContent *content;
};
static void cullable_iface_init (MetaCullableInterface *iface);
@ -188,407 +48,16 @@ G_DEFINE_TYPE_WITH_CODE (MetaBackgroundActor, meta_background_actor, CLUTTER_TYP
G_IMPLEMENT_INTERFACE (META_TYPE_CULLABLE, cullable_iface_init));
static void
set_clip_region (MetaBackgroundActor *self,
cairo_region_t *clip_region)
maybe_create_content (MetaBackgroundActor *self)
{
g_clear_pointer (&self->clip_region, cairo_region_destroy);
if (clip_region)
{
if (cairo_region_is_empty (clip_region))
self->clip_region = cairo_region_reference (clip_region);
else
self->clip_region = cairo_region_copy (clip_region);
}
}
g_autoptr (ClutterContent) content = NULL;
static void
set_unobscured_region (MetaBackgroundActor *self,
cairo_region_t *unobscured_region)
{
g_clear_pointer (&self->unobscured_region, cairo_region_destroy);
if (unobscured_region)
{
if (cairo_region_is_empty (unobscured_region))
self->unobscured_region = cairo_region_reference (unobscured_region);
else
self->unobscured_region = cairo_region_copy (unobscured_region);
}
}
static void
meta_background_actor_dispose (GObject *object)
{
MetaBackgroundActor *self = META_BACKGROUND_ACTOR (object);
set_clip_region (self, NULL);
set_unobscured_region (self, NULL);
meta_background_actor_set_background (self, NULL);
if (self->pipeline)
{
cogl_object_unref (self->pipeline);
self->pipeline = NULL;
}
G_OBJECT_CLASS (meta_background_actor_parent_class)->dispose (object);
}
static void
get_preferred_size (MetaBackgroundActor *self,
gfloat *width,
gfloat *height)
{
MetaRectangle monitor_geometry;
meta_display_get_monitor_geometry (self->display,
self->monitor,
&monitor_geometry);
if (width != NULL)
*width = monitor_geometry.width;
if (height != NULL)
*height = monitor_geometry.height;
}
static void
meta_background_actor_get_preferred_width (ClutterActor *actor,
gfloat for_height,
gfloat *min_width_p,
gfloat *natural_width_p)
{
gfloat width;
get_preferred_size (META_BACKGROUND_ACTOR (actor), &width, NULL);
if (min_width_p)
*min_width_p = width;
if (natural_width_p)
*natural_width_p = width;
}
static void
meta_background_actor_get_preferred_height (ClutterActor *actor,
gfloat for_width,
gfloat *min_height_p,
gfloat *natural_height_p)
{
gfloat height;
get_preferred_size (META_BACKGROUND_ACTOR (actor), NULL, &height);
if (min_height_p)
*min_height_p = height;
if (natural_height_p)
*natural_height_p = height;
}
static CoglPipeline *
make_pipeline (PipelineFlags pipeline_flags)
{
static CoglPipeline *templates[8];
CoglPipeline **templatep;
templatep = &templates[pipeline_flags];
if (*templatep == NULL)
{
/* Cogl automatically caches pipelines with no eviction policy,
* so we need to prevent identical pipelines from getting cached
* separately, by reusing the same shader snippets.
*/
*templatep = COGL_PIPELINE (meta_create_texture_pipeline (NULL));
if ((pipeline_flags & PIPELINE_VIGNETTE) != 0)
{
static CoglSnippet *vignette_vertex_snippet;
static CoglSnippet *vignette_fragment_snippet;
if (!vignette_vertex_snippet)
vignette_vertex_snippet = cogl_snippet_new (COGL_SNIPPET_HOOK_VERTEX,
VIGNETTE_VERTEX_SHADER_DECLARATIONS,
VIGNETTE_VERTEX_SHADER_CODE);
cogl_pipeline_add_snippet (*templatep, vignette_vertex_snippet);
if (!vignette_fragment_snippet)
vignette_fragment_snippet = cogl_snippet_new (COGL_SNIPPET_HOOK_FRAGMENT,
VIGNETTE_FRAGMENT_SHADER_DECLARATIONS,
VIGNETTE_FRAGMENT_SHADER_CODE);
cogl_pipeline_add_snippet (*templatep, vignette_fragment_snippet);
}
if ((pipeline_flags & PIPELINE_GRADIENT) != 0)
{
static CoglSnippet *gradient_vertex_snippet;
static CoglSnippet *gradient_fragment_snippet;
if (!gradient_vertex_snippet)
gradient_vertex_snippet = cogl_snippet_new (COGL_SNIPPET_HOOK_VERTEX,
GRADIENT_VERTEX_SHADER_DECLARATIONS,
GRADIENT_VERTEX_SHADER_CODE);
cogl_pipeline_add_snippet (*templatep, gradient_vertex_snippet);
if (!gradient_fragment_snippet)
gradient_fragment_snippet = cogl_snippet_new (COGL_SNIPPET_HOOK_FRAGMENT,
GRADIENT_FRAGMENT_SHADER_DECLARATIONS,
GRADIENT_FRAGMENT_SHADER_CODE);
cogl_pipeline_add_snippet (*templatep, gradient_fragment_snippet);
}
if ((pipeline_flags & PIPELINE_BLEND) == 0)
cogl_pipeline_set_blend (*templatep, "RGBA = ADD (SRC_COLOR, 0)", NULL);
}
return cogl_pipeline_copy (*templatep);
}
static void
setup_pipeline (MetaBackgroundActor *self,
ClutterPaintContext *paint_context,
cairo_rectangle_int_t *actor_pixel_rect)
{
PipelineFlags pipeline_flags = 0;
guint8 opacity;
float color_component;
CoglFramebuffer *fb;
CoglPipelineFilter filter;
opacity = clutter_actor_get_paint_opacity (CLUTTER_ACTOR (self));
if (opacity < 255)
pipeline_flags |= PIPELINE_BLEND;
if (self->vignette && clutter_feature_available (CLUTTER_FEATURE_SHADERS_GLSL))
pipeline_flags |= PIPELINE_VIGNETTE;
if (self->gradient && clutter_feature_available (CLUTTER_FEATURE_SHADERS_GLSL))
pipeline_flags |= PIPELINE_GRADIENT;
if (self->pipeline &&
pipeline_flags != self->pipeline_flags)
{
cogl_object_unref (self->pipeline);
self->pipeline = NULL;
}
if (self->pipeline == NULL)
{
self->pipeline_flags = pipeline_flags;
self->pipeline = make_pipeline (pipeline_flags);
self->changed = CHANGED_ALL;
}
if ((self->changed & CHANGED_BACKGROUND) != 0)
{
CoglPipelineWrapMode wrap_mode;
CoglTexture *texture = meta_background_get_texture (self->background,
self->monitor,
&self->texture_area,
&wrap_mode);
self->force_bilinear = texture &&
(self->texture_area.width != (int)cogl_texture_get_width (texture) ||
self->texture_area.height != (int)cogl_texture_get_height (texture));
cogl_pipeline_set_layer_texture (self->pipeline, 0, texture);
cogl_pipeline_set_layer_wrap_mode (self->pipeline, 0, wrap_mode);
self->changed &= ~CHANGED_BACKGROUND;
}
if ((self->changed & CHANGED_VIGNETTE_PARAMETERS) != 0)
{
cogl_pipeline_set_uniform_1f (self->pipeline,
cogl_pipeline_get_uniform_location (self->pipeline,
"vignette_sharpness"),
self->vignette_sharpness);
self->changed &= ~CHANGED_VIGNETTE_PARAMETERS;
}
if ((self->changed & CHANGED_GRADIENT_PARAMETERS) != 0)
{
MetaRectangle monitor_geometry;
float gradient_height_perc;
meta_display_get_monitor_geometry (self->display,
self->monitor, &monitor_geometry);
gradient_height_perc = MAX (0.0001, self->gradient_height / (float)monitor_geometry.height);
cogl_pipeline_set_uniform_1f (self->pipeline,
cogl_pipeline_get_uniform_location (self->pipeline,
"gradient_height_perc"),
gradient_height_perc);
cogl_pipeline_set_uniform_1f (self->pipeline,
cogl_pipeline_get_uniform_location (self->pipeline,
"gradient_max_darkness"),
self->gradient_max_darkness);
self->changed &= ~CHANGED_GRADIENT_PARAMETERS;
}
if (self->vignette)
{
color_component = self->vignette_brightness * opacity / 255.;
if (!clutter_feature_available (CLUTTER_FEATURE_SHADERS_GLSL))
{
/* Darken everything to match the average brightness that would
* be there if we were drawing the vignette, which is
* (1 - (pi/12.) * vignette_sharpness) [exercise for the reader :]
*/
color_component *= (1 - 0.74 * self->vignette_sharpness);
}
}
else
color_component = opacity / 255.;
cogl_pipeline_set_color4f (self->pipeline,
color_component,
color_component,
color_component,
opacity / 255.);
fb = clutter_paint_context_get_framebuffer (paint_context);
if (!self->force_bilinear &&
meta_actor_painting_untransformed (fb,
actor_pixel_rect->width,
actor_pixel_rect->height,
actor_pixel_rect->width,
actor_pixel_rect->height,
NULL, NULL))
filter = COGL_PIPELINE_FILTER_NEAREST;
else
filter = COGL_PIPELINE_FILTER_LINEAR;
cogl_pipeline_set_layer_filters (self->pipeline, 0, filter, filter);
}
static void
set_glsl_parameters (MetaBackgroundActor *self,
cairo_rectangle_int_t *actor_pixel_rect)
{
float scale[2];
float offset[2];
/* Compute a scale and offset for transforming texture coordinates to the
* coordinate system from [-0.5 to 0.5] across the area of the actor
*/
scale[0] = self->texture_area.width / (float)actor_pixel_rect->width;
scale[1] = self->texture_area.height / (float)actor_pixel_rect->height;
offset[0] = self->texture_area.x / (float)actor_pixel_rect->width - 0.5;
offset[1] = self->texture_area.y / (float)actor_pixel_rect->height - 0.5;
cogl_pipeline_set_uniform_float (self->pipeline,
cogl_pipeline_get_uniform_location (self->pipeline,
"scale"),
2, 1, scale);
cogl_pipeline_set_uniform_float (self->pipeline,
cogl_pipeline_get_uniform_location (self->pipeline,
"offset"),
2, 1, offset);
}
static void
paint_clipped_rectangle (CoglFramebuffer *fb,
CoglPipeline *pipeline,
cairo_rectangle_int_t *rect,
cairo_rectangle_int_t *texture_area)
{
float x1, y1, x2, y2;
float tx1, ty1, tx2, ty2;
x1 = rect->x;
y1 = rect->y;
x2 = rect->x + rect->width;
y2 = rect->y + rect->height;
tx1 = (x1 - texture_area->x) / texture_area->width;
ty1 = (y1 - texture_area->y) / texture_area->height;
tx2 = (x2 - texture_area->x) / texture_area->width;
ty2 = (y2 - texture_area->y) / texture_area->height;
cogl_framebuffer_draw_textured_rectangle (fb, pipeline,
x1, y1, x2, y2,
tx1, ty1, tx2, ty2);
}
static gboolean
meta_background_actor_get_paint_volume (ClutterActor *actor,
ClutterPaintVolume *volume)
{
return clutter_paint_volume_set_from_allocation (volume, actor);
}
static void
meta_background_actor_paint (ClutterActor *actor,
ClutterPaintContext *paint_context)
{
MetaBackgroundActor *self = META_BACKGROUND_ACTOR (actor);
ClutterActorBox actor_box;
cairo_rectangle_int_t actor_pixel_rect;
CoglFramebuffer *fb;
cairo_region_t *region;
int i, n_rects;
if ((self->clip_region && cairo_region_is_empty (self->clip_region)))
return;
clutter_actor_get_content_box (actor, &actor_box);
actor_pixel_rect.x = actor_box.x1;
actor_pixel_rect.y = actor_box.y1;
actor_pixel_rect.width = actor_box.x2 - actor_box.x1;
actor_pixel_rect.height = actor_box.y2 - actor_box.y1;
setup_pipeline (self, paint_context, &actor_pixel_rect);
set_glsl_parameters (self, &actor_pixel_rect);
/* Limit to how many separate rectangles we'll draw; beyond this just
* fall back and draw the whole thing */
#define MAX_RECTS 64
fb = clutter_paint_context_get_framebuffer (paint_context);
/* Now figure out what to actually paint.
*/
if (self->clip_region)
{
region = cairo_region_copy (self->clip_region);
cairo_region_intersect_rectangle (region, &actor_pixel_rect);
}
else
{
region = cairo_region_create_rectangle (&actor_pixel_rect);
}
if (self->unobscured_region)
cairo_region_intersect (region, self->unobscured_region);
if (cairo_region_is_empty (region))
{
cairo_region_destroy (region);
if (self->content || !self->display || self->monitor == -1)
return;
}
n_rects = cairo_region_num_rectangles (region);
if (n_rects <= MAX_RECTS)
{
for (i = 0; i < n_rects; i++)
{
cairo_rectangle_int_t rect;
cairo_region_get_rectangle (region, i, &rect);
paint_clipped_rectangle (fb, self->pipeline, &rect,
&self->texture_area);
}
}
else
{
cairo_rectangle_int_t rect;
cairo_region_get_extents (region, &rect);
paint_clipped_rectangle (fb, self->pipeline, &rect,
&self->texture_area);
}
cairo_region_destroy (region);
content = meta_background_content_new (self->display, self->monitor);
self->content = META_BACKGROUND_CONTENT (content);
clutter_actor_set_content (CLUTTER_ACTOR (self), content);
}
static void
@ -603,48 +72,11 @@ meta_background_actor_set_property (GObject *object,
{
case PROP_META_DISPLAY:
self->display = g_value_get_object (value);
maybe_create_content (self);
break;
case PROP_MONITOR:
meta_background_actor_set_monitor (self, g_value_get_int (value));
break;
case PROP_BACKGROUND:
meta_background_actor_set_background (self, g_value_get_object (value));
break;
case PROP_GRADIENT:
meta_background_actor_set_gradient (self,
g_value_get_boolean (value),
self->gradient_height,
self->gradient_max_darkness);
break;
case PROP_GRADIENT_HEIGHT:
meta_background_actor_set_gradient (self,
self->gradient,
g_value_get_int (value),
self->gradient_max_darkness);
break;
case PROP_GRADIENT_MAX_DARKNESS:
meta_background_actor_set_gradient (self,
self->gradient,
self->gradient_height,
g_value_get_double (value));
break;
case PROP_VIGNETTE:
meta_background_actor_set_vignette (self,
g_value_get_boolean (value),
self->vignette_brightness,
self->vignette_sharpness);
break;
case PROP_VIGNETTE_SHARPNESS:
meta_background_actor_set_vignette (self,
self->vignette,
self->vignette_brightness,
g_value_get_double (value));
break;
case PROP_VIGNETTE_BRIGHTNESS:
meta_background_actor_set_vignette (self,
self->vignette,
g_value_get_double (value),
self->vignette_sharpness);
self->monitor = g_value_get_int (value);
maybe_create_content (self);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@ -668,27 +100,6 @@ meta_background_actor_get_property (GObject *object,
case PROP_MONITOR:
g_value_set_int (value, self->monitor);
break;
case PROP_BACKGROUND:
g_value_set_object (value, self->background);
break;
case PROP_GRADIENT:
g_value_set_boolean (value, self->gradient);
break;
case PROP_GRADIENT_HEIGHT:
g_value_set_int (value, self->gradient_height);
break;
case PROP_GRADIENT_MAX_DARKNESS:
g_value_set_double (value, self->gradient_max_darkness);
break;
case PROP_VIGNETTE:
g_value_set_boolean (value, self->vignette);
break;
case PROP_VIGNETTE_BRIGHTNESS:
g_value_set_double (value, self->vignette_brightness);
break;
case PROP_VIGNETTE_SHARPNESS:
g_value_set_double (value, self->vignette_sharpness);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@ -699,18 +110,11 @@ static void
meta_background_actor_class_init (MetaBackgroundActorClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
GParamSpec *param_spec;
object_class->dispose = meta_background_actor_dispose;
object_class->set_property = meta_background_actor_set_property;
object_class->get_property = meta_background_actor_get_property;
actor_class->get_preferred_width = meta_background_actor_get_preferred_width;
actor_class->get_preferred_height = meta_background_actor_get_preferred_height;
actor_class->get_paint_volume = meta_background_actor_get_paint_volume;
actor_class->paint = meta_background_actor_paint;
param_spec = g_param_spec_object ("meta-display",
"MetaDisplay",
"MetaDisplay",
@ -730,88 +134,15 @@ meta_background_actor_class_init (MetaBackgroundActorClass *klass)
g_object_class_install_property (object_class,
PROP_MONITOR,
param_spec);
param_spec = g_param_spec_object ("background",
"Background",
"MetaBackground object holding background parameters",
META_TYPE_BACKGROUND,
G_PARAM_READWRITE);
g_object_class_install_property (object_class,
PROP_BACKGROUND,
param_spec);
param_spec = g_param_spec_boolean ("gradient",
"Gradient",
"Whether gradient effect is enabled",
FALSE,
G_PARAM_READWRITE);
g_object_class_install_property (object_class,
PROP_GRADIENT,
param_spec);
param_spec = g_param_spec_int ("gradient-height",
"Gradient Height",
"Height of gradient effect",
0, G_MAXINT, 0,
G_PARAM_READWRITE);
g_object_class_install_property (object_class,
PROP_GRADIENT_HEIGHT,
param_spec);
param_spec = g_param_spec_double ("gradient-max-darkness",
"Gradient Max Darkness",
"How dark is the gradient initially",
0.0, 1.0, 0.0,
G_PARAM_READWRITE);
g_object_class_install_property (object_class,
PROP_GRADIENT_MAX_DARKNESS,
param_spec);
param_spec = g_param_spec_boolean ("vignette",
"Vignette",
"Whether vignette effect is enabled",
FALSE,
G_PARAM_READWRITE);
g_object_class_install_property (object_class,
PROP_VIGNETTE,
param_spec);
param_spec = g_param_spec_double ("brightness",
"Vignette Brightness",
"Brightness of vignette effect",
0.0, 1.0, 1.0,
G_PARAM_READWRITE);
g_object_class_install_property (object_class,
PROP_VIGNETTE_BRIGHTNESS,
param_spec);
param_spec = g_param_spec_double ("vignette-sharpness",
"Vignette Sharpness",
"Sharpness of vignette effect",
0.0, G_MAXDOUBLE, 0.0,
G_PARAM_READWRITE);
g_object_class_install_property (object_class,
PROP_VIGNETTE_SHARPNESS,
param_spec);
}
static void
meta_background_actor_init (MetaBackgroundActor *self)
{
self->gradient = FALSE;
self->gradient_height = 0;
self->gradient_max_darkness = 0.0;
self->monitor = -1;
self->vignette = FALSE;
self->vignette_brightness = 1.0;
self->vignette_sharpness = 0.0;
clutter_actor_set_request_mode (CLUTTER_ACTOR (self),
CLUTTER_REQUEST_CONTENT_SIZE);
}
/**
@ -843,8 +174,12 @@ meta_background_actor_cull_out (MetaCullable *cullable,
{
MetaBackgroundActor *self = META_BACKGROUND_ACTOR (cullable);
set_unobscured_region (self, unobscured_region);
set_clip_region (self, clip_region);
if (!self->content)
return;
meta_background_content_cull_out (self->content,
unobscured_region,
clip_region);
}
static void
@ -852,8 +187,10 @@ meta_background_actor_reset_culling (MetaCullable *cullable)
{
MetaBackgroundActor *self = META_BACKGROUND_ACTOR (cullable);
set_unobscured_region (self, NULL);
set_clip_region (self, NULL);
if (!self->content)
return;
meta_background_content_reset_culling (self->content);
}
static void
@ -874,135 +211,8 @@ cullable_iface_init (MetaCullableInterface *iface)
cairo_region_t *
meta_background_actor_get_clip_region (MetaBackgroundActor *self)
{
return self->clip_region;
}
static void
invalidate_pipeline (MetaBackgroundActor *self,
ChangedFlags changed)
{
self->changed |= changed;
}
static void
on_background_changed (MetaBackground *background,
MetaBackgroundActor *self)
{
invalidate_pipeline (self, CHANGED_BACKGROUND);
clutter_actor_queue_redraw (CLUTTER_ACTOR (self));
}
void
meta_background_actor_set_background (MetaBackgroundActor *self,
MetaBackground *background)
{
g_return_if_fail (META_IS_BACKGROUND_ACTOR (self));
g_return_if_fail (background == NULL || META_IS_BACKGROUND (background));
if (background == self->background)
return;
if (self->background)
{
g_signal_handlers_disconnect_by_func (self->background,
(gpointer)on_background_changed,
self);
g_object_unref (self->background);
self->background = NULL;
}
if (background)
{
self->background = g_object_ref (background);
g_signal_connect (self->background, "changed",
G_CALLBACK (on_background_changed), self);
}
invalidate_pipeline (self, CHANGED_BACKGROUND);
clutter_actor_queue_redraw (CLUTTER_ACTOR (self));
}
void
meta_background_actor_set_gradient (MetaBackgroundActor *self,
gboolean enabled,
int height,
double max_darkness)
{
gboolean changed = FALSE;
g_return_if_fail (META_IS_BACKGROUND_ACTOR (self));
g_return_if_fail (height >= 0);
g_return_if_fail (max_darkness >= 0. && max_darkness <= 1.);
enabled = enabled != FALSE && height != 0;
if (enabled != self->gradient)
{
self->gradient = enabled;
invalidate_pipeline (self, CHANGED_EFFECTS);
changed = TRUE;
}
if (height != self->gradient_height || max_darkness != self->gradient_max_darkness)
{
self->gradient_height = height;
self->gradient_max_darkness = max_darkness;
invalidate_pipeline (self, CHANGED_GRADIENT_PARAMETERS);
changed = TRUE;
}
if (changed)
clutter_actor_queue_redraw (CLUTTER_ACTOR (self));
}
void
meta_background_actor_set_monitor (MetaBackgroundActor *self,
int monitor)
{
MetaRectangle old_monitor_geometry;
MetaRectangle new_monitor_geometry;
MetaDisplay *display = self->display;
if(self->monitor == monitor)
return;
meta_display_get_monitor_geometry (display, self->monitor, &old_monitor_geometry);
meta_display_get_monitor_geometry (display, monitor, &new_monitor_geometry);
if(old_monitor_geometry.height != new_monitor_geometry.height)
invalidate_pipeline (self, CHANGED_GRADIENT_PARAMETERS);
self->monitor = monitor;
}
void
meta_background_actor_set_vignette (MetaBackgroundActor *self,
gboolean enabled,
double brightness,
double sharpness)
{
gboolean changed = FALSE;
g_return_if_fail (META_IS_BACKGROUND_ACTOR (self));
g_return_if_fail (brightness >= 0. && brightness <= 1.);
g_return_if_fail (sharpness >= 0.);
enabled = enabled != FALSE;
if (enabled != self->vignette)
{
self->vignette = enabled;
invalidate_pipeline (self, CHANGED_EFFECTS);
changed = TRUE;
}
if (brightness != self->vignette_brightness || sharpness != self->vignette_sharpness)
{
self->vignette_brightness = brightness;
self->vignette_sharpness = sharpness;
invalidate_pipeline (self, CHANGED_VIGNETTE_PARAMETERS);
changed = TRUE;
}
if (changed)
clutter_actor_queue_redraw (CLUTTER_ACTOR (self));
if (!self->content)
return NULL;
return meta_background_content_get_clip_region (self->content);
}

View File

@ -0,0 +1,16 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
#ifndef META_BACKGROUND_CONTENT_PRIVATE_H
#define META_BACKGROUND_CONTENT_PRIVATE_H
#include "meta/meta-background-content.h"
cairo_region_t *meta_background_content_get_clip_region (MetaBackgroundContent *self);
void meta_background_content_cull_out (MetaBackgroundContent *self,
cairo_region_t *unobscured_region,
cairo_region_t *clip_region);
void meta_background_content_reset_culling (MetaBackgroundContent *self);
#endif /* META_BACKGROUND_CONTENT_PRIVATE_H */

View File

@ -0,0 +1,937 @@
/*
* Copyright 2009 Sander Dijkhuis
* Copyright 2014 Red Hat, Inc.
* Copyright 2020 Endless Foundation.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*
* Portions adapted from gnome-shell/src/shell-global.c
*/
/**
* SECTION:meta-background-content
* @title: MetaBackgroundContent
* @short_description: ClutterContent for painting the root window background
*
*/
/*
* The overall model drawing model of this content is that we have one
* texture, or two interpolated textures, possibly with alpha or
* margins that let the underlying background show through, blended
* over a solid color or a gradient. The result of that combination
* can then be affected by a "vignette" that darkens the background
* away from a central point (or as a no-GLSL fallback, simply darkens
* the background) and by overall opacity.
*
* As of GNOME 3.14, GNOME is only using a fraction of this when the
* user sets the background through the control center - what can be
* set is:
*
* A single image without a border
* An animation of images without a border that blend together,
* with the blend changing every 4-5 minutes
* A solid color with a repeated noise texture blended over it
*
* This all is pretty easy to do in a fragment shader, except when:
*
* A) We don't have GLSL - in this case, the operation of
* interpolating the two textures and blending the result over the
* background can't be expressed with Cogl's fixed-function layer
* combining (which is confined to what GL's texture environment
* combining can do) So we can only handle the above directly if
* there are no margins or alpha.
*
* B) The image textures are sliced. Texture size limits on older
* hardware (pre-965 intel hardware, r300, etc.) is often 2048,
* and it would be common to use a texture larger than this for a
* background and expect it to be scaled down. Cogl can compensate
* for this by breaking the texture up into multiple textures, but
* can't multitexture with sliced textures. So we can only handle
* the above if there's a single texture.
*
* However, even when we *can* represent everything in a single pass,
* it's not necessarily efficient. If we want to draw a 1024x768
* background, it's pretty inefficient to bilinearly texture from
* two 2560x1440 images and mix that. So the drawing model we take
* here is that MetaBackground generates a single texture (which
* might be a 1x1 texture for a solid color, or a 1x2 texture for a
* gradient, or a repeated texture for wallpaper, or a pre-rendered
* texture the size of the screen), and we draw with that, possibly
* adding the vignette and opacity.
*/
#include "config.h"
#include "compositor/meta-background-content-private.h"
#include "clutter/clutter.h"
#include "compositor/clutter-utils.h"
#include "compositor/cogl-utils.h"
#include "compositor/meta-background-private.h"
#include "compositor/meta-cullable.h"
#include "meta/display.h"
typedef enum
{
CHANGED_BACKGROUND = 1 << 0,
CHANGED_EFFECTS = 1 << 2,
CHANGED_VIGNETTE_PARAMETERS = 1 << 3,
CHANGED_GRADIENT_PARAMETERS = 1 << 4,
CHANGED_ALL = 0xFFFF
} ChangedFlags;
#define GRADIENT_VERTEX_SHADER_DECLARATIONS \
"uniform vec2 scale;\n" \
"varying vec2 position;\n" \
#define GRADIENT_VERTEX_SHADER_CODE \
"position = cogl_tex_coord0_in.xy * scale;\n" \
#define GRADIENT_FRAGMENT_SHADER_DECLARATIONS \
"uniform float gradient_height_perc;\n" \
"uniform float gradient_max_darkness;\n" \
"varying vec2 position;\n" \
#define GRADIENT_FRAGMENT_SHADER_CODE \
"float min_brightness = 1.0 - gradient_max_darkness;\n" \
"float gradient_y_pos = min(position.y, gradient_height_perc) / gradient_height_perc;\n" \
"float pixel_brightness = (1.0 - min_brightness) * gradient_y_pos + min_brightness;\n" \
"cogl_color_out.rgb = cogl_color_out.rgb * pixel_brightness;\n" \
#define VIGNETTE_VERTEX_SHADER_DECLARATIONS \
"uniform vec2 scale;\n" \
"uniform vec2 offset;\n" \
"varying vec2 position;\n" \
#define VIGNETTE_VERTEX_SHADER_CODE \
"position = cogl_tex_coord0_in.xy * scale + offset;\n" \
#define VIGNETTE_SQRT_2 "1.4142"
#define VIGNETTE_FRAGMENT_SHADER_DECLARATIONS \
"uniform float vignette_sharpness;\n" \
"varying vec2 position;\n" \
"float rand(vec2 p) { return fract(sin(dot(p, vec2(12.9898, 78.233))) * 43758.5453123); }\n" \
#define VIGNETTE_FRAGMENT_SHADER_CODE \
"float t = " VIGNETTE_SQRT_2 " * length(position);\n" \
"t = min(t, 1.0);\n" \
"float pixel_brightness = 1.0 - t * vignette_sharpness;\n" \
"cogl_color_out.rgb = cogl_color_out.rgb * pixel_brightness;\n" \
"cogl_color_out.rgb += (rand(position) - 0.5) / 255.0;\n" \
typedef struct _MetaBackgroundLayer MetaBackgroundLayer;
typedef enum
{
PIPELINE_VIGNETTE = (1 << 0),
PIPELINE_BLEND = (1 << 1),
PIPELINE_GRADIENT = (1 << 2),
} PipelineFlags;
struct _MetaBackgroundContent
{
GObject parent;
MetaDisplay *display;
int monitor;
MetaBackground *background;
gboolean gradient;
double gradient_max_darkness;
int gradient_height;
gboolean vignette;
double vignette_brightness;
double vignette_sharpness;
ChangedFlags changed;
CoglPipeline *pipeline;
PipelineFlags pipeline_flags;
cairo_rectangle_int_t texture_area;
gboolean force_bilinear;
cairo_region_t *clip_region;
cairo_region_t *unobscured_region;
};
static void clutter_content_iface_init (ClutterContentInterface *iface);
G_DEFINE_TYPE_WITH_CODE (MetaBackgroundContent,
meta_background_content,
G_TYPE_OBJECT,
G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_CONTENT,
clutter_content_iface_init));
enum
{
PROP_0,
PROP_META_DISPLAY,
PROP_MONITOR,
PROP_BACKGROUND,
PROP_GRADIENT,
PROP_GRADIENT_HEIGHT,
PROP_GRADIENT_MAX_DARKNESS,
PROP_VIGNETTE,
PROP_VIGNETTE_SHARPNESS,
PROP_VIGNETTE_BRIGHTNESS,
N_PROPS,
};
static GParamSpec *properties[N_PROPS] = { NULL, };
static void
set_clip_region (MetaBackgroundContent *self,
cairo_region_t *clip_region)
{
g_clear_pointer (&self->clip_region, cairo_region_destroy);
if (clip_region)
{
if (cairo_region_is_empty (clip_region))
self->clip_region = cairo_region_reference (clip_region);
else
self->clip_region = cairo_region_copy (clip_region);
}
}
static void
set_unobscured_region (MetaBackgroundContent *self,
cairo_region_t *unobscured_region)
{
g_clear_pointer (&self->unobscured_region, cairo_region_destroy);
if (unobscured_region)
{
if (cairo_region_is_empty (unobscured_region))
self->unobscured_region = cairo_region_reference (unobscured_region);
else
self->unobscured_region = cairo_region_copy (unobscured_region);
}
}
static void
invalidate_pipeline (MetaBackgroundContent *self,
ChangedFlags changed)
{
self->changed |= changed;
}
static void
on_background_changed (MetaBackground *background,
MetaBackgroundContent *self)
{
invalidate_pipeline (self, CHANGED_BACKGROUND);
clutter_content_invalidate (CLUTTER_CONTENT (self));
}
static CoglPipeline *
make_pipeline (PipelineFlags pipeline_flags)
{
static CoglPipeline *templates[8];
CoglPipeline **templatep;
templatep = &templates[pipeline_flags];
if (*templatep == NULL)
{
/* Cogl automatically caches pipelines with no eviction policy,
* so we need to prevent identical pipelines from getting cached
* separately, by reusing the same shader snippets.
*/
*templatep = COGL_PIPELINE (meta_create_texture_pipeline (NULL));
if ((pipeline_flags & PIPELINE_VIGNETTE) != 0)
{
static CoglSnippet *vignette_vertex_snippet;
static CoglSnippet *vignette_fragment_snippet;
if (!vignette_vertex_snippet)
vignette_vertex_snippet = cogl_snippet_new (COGL_SNIPPET_HOOK_VERTEX,
VIGNETTE_VERTEX_SHADER_DECLARATIONS,
VIGNETTE_VERTEX_SHADER_CODE);
cogl_pipeline_add_snippet (*templatep, vignette_vertex_snippet);
if (!vignette_fragment_snippet)
vignette_fragment_snippet = cogl_snippet_new (COGL_SNIPPET_HOOK_FRAGMENT,
VIGNETTE_FRAGMENT_SHADER_DECLARATIONS,
VIGNETTE_FRAGMENT_SHADER_CODE);
cogl_pipeline_add_snippet (*templatep, vignette_fragment_snippet);
}
if ((pipeline_flags & PIPELINE_GRADIENT) != 0)
{
static CoglSnippet *gradient_vertex_snippet;
static CoglSnippet *gradient_fragment_snippet;
if (!gradient_vertex_snippet)
gradient_vertex_snippet = cogl_snippet_new (COGL_SNIPPET_HOOK_VERTEX,
GRADIENT_VERTEX_SHADER_DECLARATIONS,
GRADIENT_VERTEX_SHADER_CODE);
cogl_pipeline_add_snippet (*templatep, gradient_vertex_snippet);
if (!gradient_fragment_snippet)
gradient_fragment_snippet = cogl_snippet_new (COGL_SNIPPET_HOOK_FRAGMENT,
GRADIENT_FRAGMENT_SHADER_DECLARATIONS,
GRADIENT_FRAGMENT_SHADER_CODE);
cogl_pipeline_add_snippet (*templatep, gradient_fragment_snippet);
}
if ((pipeline_flags & PIPELINE_BLEND) == 0)
cogl_pipeline_set_blend (*templatep, "RGBA = ADD (SRC_COLOR, 0)", NULL);
}
return cogl_pipeline_copy (*templatep);
}
static void
setup_pipeline (MetaBackgroundContent *self,
ClutterActor *actor,
ClutterPaintContext *paint_context,
cairo_rectangle_int_t *actor_pixel_rect)
{
PipelineFlags pipeline_flags = 0;
guint8 opacity;
float color_component;
CoglFramebuffer *fb;
CoglPipelineFilter filter;
opacity = clutter_actor_get_paint_opacity (actor);
if (opacity < 255)
pipeline_flags |= PIPELINE_BLEND;
if (self->vignette && clutter_feature_available (CLUTTER_FEATURE_SHADERS_GLSL))
pipeline_flags |= PIPELINE_VIGNETTE;
if (self->gradient && clutter_feature_available (CLUTTER_FEATURE_SHADERS_GLSL))
pipeline_flags |= PIPELINE_GRADIENT;
if (pipeline_flags != self->pipeline_flags)
g_clear_pointer (&self->pipeline, cogl_object_unref);
if (self->pipeline == NULL)
{
self->pipeline_flags = pipeline_flags;
self->pipeline = make_pipeline (pipeline_flags);
self->changed = CHANGED_ALL;
}
if (self->changed & CHANGED_BACKGROUND)
{
CoglPipelineWrapMode wrap_mode;
CoglTexture *texture = meta_background_get_texture (self->background,
self->monitor,
&self->texture_area,
&wrap_mode);
self->force_bilinear = texture &&
(self->texture_area.width != (int)cogl_texture_get_width (texture) ||
self->texture_area.height != (int)cogl_texture_get_height (texture));
cogl_pipeline_set_layer_texture (self->pipeline, 0, texture);
cogl_pipeline_set_layer_wrap_mode (self->pipeline, 0, wrap_mode);
self->changed &= ~CHANGED_BACKGROUND;
}
if (self->changed & CHANGED_VIGNETTE_PARAMETERS)
{
cogl_pipeline_set_uniform_1f (self->pipeline,
cogl_pipeline_get_uniform_location (self->pipeline,
"vignette_sharpness"),
self->vignette_sharpness);
self->changed &= ~CHANGED_VIGNETTE_PARAMETERS;
}
if (self->changed & CHANGED_GRADIENT_PARAMETERS)
{
MetaRectangle monitor_geometry;
float gradient_height_perc;
meta_display_get_monitor_geometry (self->display,
self->monitor, &monitor_geometry);
gradient_height_perc = MAX (0.0001, self->gradient_height / (float)monitor_geometry.height);
cogl_pipeline_set_uniform_1f (self->pipeline,
cogl_pipeline_get_uniform_location (self->pipeline,
"gradient_height_perc"),
gradient_height_perc);
cogl_pipeline_set_uniform_1f (self->pipeline,
cogl_pipeline_get_uniform_location (self->pipeline,
"gradient_max_darkness"),
self->gradient_max_darkness);
self->changed &= ~CHANGED_GRADIENT_PARAMETERS;
}
if (self->vignette)
{
color_component = self->vignette_brightness * opacity / 255.;
if (!clutter_feature_available (CLUTTER_FEATURE_SHADERS_GLSL))
{
/* Darken everything to match the average brightness that would
* be there if we were drawing the vignette, which is
* (1 - (pi/12.) * vignette_sharpness) [exercise for the reader :]
*/
color_component *= (1 - 0.74 * self->vignette_sharpness);
}
}
else
{
color_component = opacity / 255.;
}
cogl_pipeline_set_color4f (self->pipeline,
color_component,
color_component,
color_component,
opacity / 255.);
fb = clutter_paint_context_get_framebuffer (paint_context);
if (!self->force_bilinear &&
meta_actor_painting_untransformed (fb,
actor_pixel_rect->width,
actor_pixel_rect->height,
actor_pixel_rect->width,
actor_pixel_rect->height,
NULL, NULL))
filter = COGL_PIPELINE_FILTER_NEAREST;
else
filter = COGL_PIPELINE_FILTER_LINEAR;
cogl_pipeline_set_layer_filters (self->pipeline, 0, filter, filter);
}
static void
set_glsl_parameters (MetaBackgroundContent *self,
cairo_rectangle_int_t *actor_pixel_rect)
{
float scale[2];
float offset[2];
/* Compute a scale and offset for transforming texture coordinates to the
* coordinate system from [-0.5 to 0.5] across the area of the actor
*/
scale[0] = self->texture_area.width / (float)actor_pixel_rect->width;
scale[1] = self->texture_area.height / (float)actor_pixel_rect->height;
offset[0] = self->texture_area.x / (float)actor_pixel_rect->width - 0.5;
offset[1] = self->texture_area.y / (float)actor_pixel_rect->height - 0.5;
cogl_pipeline_set_uniform_float (self->pipeline,
cogl_pipeline_get_uniform_location (self->pipeline,
"scale"),
2, 1, scale);
cogl_pipeline_set_uniform_float (self->pipeline,
cogl_pipeline_get_uniform_location (self->pipeline,
"offset"),
2, 1, offset);
}
static void
paint_clipped_rectangle (MetaBackgroundContent *self,
ClutterPaintNode *node,
ClutterActorBox *actor_box,
cairo_rectangle_int_t *rect)
{
g_autoptr (ClutterPaintNode) pipeline_node = NULL;
float h_scale, v_scale;
float x1, y1, x2, y2;
float tx1, ty1, tx2, ty2;
h_scale = self->texture_area.width / clutter_actor_box_get_width (actor_box);
v_scale = self->texture_area.height / clutter_actor_box_get_height (actor_box);
x1 = rect->x;
y1 = rect->y;
x2 = rect->x + rect->width;
y2 = rect->y + rect->height;
tx1 = (x1 * h_scale - self->texture_area.x) / (float)self->texture_area.width;
ty1 = (y1 * v_scale - self->texture_area.y) / (float)self->texture_area.height;
tx2 = (x2 * h_scale - self->texture_area.x) / (float)self->texture_area.width;
ty2 = (y2 * v_scale - self->texture_area.y) / (float)self->texture_area.height;
pipeline_node = clutter_pipeline_node_new (self->pipeline);
clutter_paint_node_set_name (pipeline_node, "MetaBackgroundContent (Slice)");
clutter_paint_node_add_texture_rectangle (pipeline_node,
&(ClutterActorBox) {
.x1 = x1,
.y1 = y1,
.x2 = x2,
.y2 = y2,
},
tx1, ty1,
tx2, ty2);
clutter_paint_node_add_child (node, pipeline_node);
}
static void
meta_background_content_paint_content (ClutterContent *content,
ClutterActor *actor,
ClutterPaintNode *node,
ClutterPaintContext *paint_context)
{
MetaBackgroundContent *self = META_BACKGROUND_CONTENT (content);
ClutterActorBox actor_box;
cairo_rectangle_int_t actor_pixel_rect;
cairo_region_t *region;
int i, n_rects;
if ((self->clip_region && cairo_region_is_empty (self->clip_region)))
return;
clutter_actor_get_content_box (actor, &actor_box);
actor_pixel_rect.x = actor_box.x1;
actor_pixel_rect.y = actor_box.x1;
actor_pixel_rect.width = actor_box.x2 - actor_box.x1;
actor_pixel_rect.height = actor_box.y2 - actor_box.y1;
setup_pipeline (self, actor, paint_context, &actor_pixel_rect);
set_glsl_parameters (self, &actor_pixel_rect);
/* Limit to how many separate rectangles we'll draw; beyond this just
* fall back and draw the whole thing */
#define MAX_RECTS 64
/* Now figure out what to actually paint */
if (self->clip_region)
{
region = cairo_region_copy (self->clip_region);
cairo_region_intersect_rectangle (region, &actor_pixel_rect);
}
else
{
region = cairo_region_create_rectangle (&actor_pixel_rect);
}
if (self->unobscured_region)
cairo_region_intersect (region, self->unobscured_region);
if (cairo_region_is_empty (region))
{
cairo_region_destroy (region);
return;
}
n_rects = cairo_region_num_rectangles (region);
if (n_rects <= MAX_RECTS)
{
for (i = 0; i < n_rects; i++)
{
cairo_rectangle_int_t rect;
cairo_region_get_rectangle (region, i, &rect);
paint_clipped_rectangle (self, node, &actor_box, &rect);
}
}
else
{
cairo_rectangle_int_t rect;
cairo_region_get_extents (region, &rect);
paint_clipped_rectangle (self, node, &actor_box, &rect);
}
cairo_region_destroy (region);
}
static gboolean
meta_background_content_get_preferred_size (ClutterContent *content,
float *width,
float *height)
{
MetaBackgroundContent *background_content = META_BACKGROUND_CONTENT (content);
MetaRectangle monitor_geometry;
meta_display_get_monitor_geometry (background_content->display,
background_content->monitor,
&monitor_geometry);
if (width)
*width = monitor_geometry.width;
if (height)
*height = monitor_geometry.height;
return TRUE;
}
static void
clutter_content_iface_init (ClutterContentInterface *iface)
{
iface->paint_content = meta_background_content_paint_content;
iface->get_preferred_size = meta_background_content_get_preferred_size;
}
static void
set_monitor (MetaBackgroundContent *self,
int monitor)
{
MetaRectangle old_monitor_geometry;
MetaRectangle new_monitor_geometry;
MetaDisplay *display = self->display;
if(self->monitor == monitor)
return;
meta_display_get_monitor_geometry (display, self->monitor, &old_monitor_geometry);
meta_display_get_monitor_geometry (display, monitor, &new_monitor_geometry);
if(old_monitor_geometry.height != new_monitor_geometry.height)
invalidate_pipeline (self, CHANGED_GRADIENT_PARAMETERS);
self->monitor = monitor;
}
static void
meta_background_content_dispose (GObject *object)
{
MetaBackgroundContent *self = META_BACKGROUND_CONTENT (object);
set_clip_region (self, NULL);
set_unobscured_region (self, NULL);
meta_background_content_set_background (self, NULL);
g_clear_pointer (&self->pipeline, cogl_object_unref);
G_OBJECT_CLASS (meta_background_content_parent_class)->dispose (object);
}
static void
meta_background_content_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
MetaBackgroundContent *self = META_BACKGROUND_CONTENT (object);
switch (prop_id)
{
case PROP_META_DISPLAY:
self->display = g_value_get_object (value);
break;
case PROP_MONITOR:
set_monitor (self, g_value_get_int (value));
break;
case PROP_BACKGROUND:
meta_background_content_set_background (self, g_value_get_object (value));
break;
case PROP_GRADIENT:
meta_background_content_set_gradient (self,
g_value_get_boolean (value),
self->gradient_height,
self->gradient_max_darkness);
break;
case PROP_GRADIENT_HEIGHT:
meta_background_content_set_gradient (self,
self->gradient,
g_value_get_int (value),
self->gradient_max_darkness);
break;
case PROP_GRADIENT_MAX_DARKNESS:
meta_background_content_set_gradient (self,
self->gradient,
self->gradient_height,
g_value_get_double (value));
break;
case PROP_VIGNETTE:
meta_background_content_set_vignette (self,
g_value_get_boolean (value),
self->vignette_brightness,
self->vignette_sharpness);
break;
case PROP_VIGNETTE_SHARPNESS:
meta_background_content_set_vignette (self,
self->vignette,
self->vignette_brightness,
g_value_get_double (value));
break;
case PROP_VIGNETTE_BRIGHTNESS:
meta_background_content_set_vignette (self,
self->vignette,
g_value_get_double (value),
self->vignette_sharpness);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
meta_background_content_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
MetaBackgroundContent *self = META_BACKGROUND_CONTENT (object);
switch (prop_id)
{
case PROP_META_DISPLAY:
g_value_set_object (value, self->display);
break;
case PROP_MONITOR:
g_value_set_int (value, self->monitor);
break;
case PROP_BACKGROUND:
g_value_set_object (value, self->background);
break;
case PROP_GRADIENT:
g_value_set_boolean (value, self->gradient);
break;
case PROP_GRADIENT_HEIGHT:
g_value_set_int (value, self->gradient_height);
break;
case PROP_GRADIENT_MAX_DARKNESS:
g_value_set_double (value, self->gradient_max_darkness);
break;
case PROP_VIGNETTE:
g_value_set_boolean (value, self->vignette);
break;
case PROP_VIGNETTE_BRIGHTNESS:
g_value_set_double (value, self->vignette_brightness);
break;
case PROP_VIGNETTE_SHARPNESS:
g_value_set_double (value, self->vignette_sharpness);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
meta_background_content_class_init (MetaBackgroundContentClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->dispose = meta_background_content_dispose;
object_class->set_property = meta_background_content_set_property;
object_class->get_property = meta_background_content_get_property;
properties[PROP_META_DISPLAY] =
g_param_spec_object ("meta-display",
"MetaDisplay",
"MetaDisplay",
META_TYPE_DISPLAY,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
properties[PROP_MONITOR] =
g_param_spec_int ("monitor",
"monitor",
"monitor",
0, G_MAXINT, 0,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
properties[PROP_BACKGROUND] =
g_param_spec_object ("background",
"Background",
"MetaBackground object holding background parameters",
META_TYPE_BACKGROUND,
G_PARAM_READWRITE);
properties[PROP_GRADIENT] =
g_param_spec_boolean ("gradient",
"Gradient",
"Whether gradient effect is enabled",
FALSE,
G_PARAM_READWRITE);
properties[PROP_GRADIENT_HEIGHT] =
g_param_spec_int ("gradient-height",
"Gradient Height",
"Height of gradient effect",
0, G_MAXINT, 0,
G_PARAM_READWRITE);
properties[PROP_GRADIENT_MAX_DARKNESS] =
g_param_spec_double ("gradient-max-darkness",
"Gradient Max Darkness",
"How dark is the gradient initially",
0.0, 1.0, 0.0,
G_PARAM_READWRITE);
properties[PROP_VIGNETTE] =
g_param_spec_boolean ("vignette",
"Vignette",
"Whether vignette effect is enabled",
FALSE,
G_PARAM_READWRITE);
properties[PROP_VIGNETTE_BRIGHTNESS] =
g_param_spec_double ("brightness",
"Vignette Brightness",
"Brightness of vignette effect",
0.0, 1.0, 1.0,
G_PARAM_READWRITE);
properties[PROP_VIGNETTE_SHARPNESS] =
g_param_spec_double ("vignette-sharpness",
"Vignette Sharpness",
"Sharpness of vignette effect",
0.0, G_MAXDOUBLE, 0.0,
G_PARAM_READWRITE);
g_object_class_install_properties (object_class, N_PROPS, properties);
}
static void
meta_background_content_init (MetaBackgroundContent *self)
{
self->gradient = FALSE;
self->gradient_height = 0;
self->gradient_max_darkness = 0.0;
self->vignette = FALSE;
self->vignette_brightness = 1.0;
self->vignette_sharpness = 0.0;
}
/**
* meta_background_content_new:
* @monitor: Index of the monitor for which to draw the background
*
* Creates a new actor to draw the background for the given monitor.
*
* Return value: (transfer full): the newly created background actor
*/
ClutterContent *
meta_background_content_new (MetaDisplay *display,
int monitor)
{
return g_object_new (META_TYPE_BACKGROUND_CONTENT,
"meta-display", display,
"monitor", monitor,
NULL);
}
void
meta_background_content_set_background (MetaBackgroundContent *self,
MetaBackground *background)
{
g_return_if_fail (META_IS_BACKGROUND_CONTENT (self));
g_return_if_fail (background == NULL || META_IS_BACKGROUND (background));
if (background == self->background)
return;
if (self->background)
{
g_signal_handlers_disconnect_by_func (self->background,
(gpointer)on_background_changed,
self);
g_clear_object (&self->background);
}
if (background)
{
self->background = g_object_ref (background);
g_signal_connect (self->background, "changed",
G_CALLBACK (on_background_changed), self);
}
invalidate_pipeline (self, CHANGED_BACKGROUND);
clutter_content_invalidate (CLUTTER_CONTENT (self));
}
void
meta_background_content_set_gradient (MetaBackgroundContent *self,
gboolean enabled,
int height,
double max_darkness)
{
gboolean changed = FALSE;
g_return_if_fail (META_IS_BACKGROUND_CONTENT (self));
g_return_if_fail (height >= 0);
g_return_if_fail (max_darkness >= 0. && max_darkness <= 1.);
enabled = enabled != FALSE && height != 0;
if (enabled != self->gradient)
{
self->gradient = enabled;
invalidate_pipeline (self, CHANGED_EFFECTS);
changed = TRUE;
}
if (height != self->gradient_height || max_darkness != self->gradient_max_darkness)
{
self->gradient_height = height;
self->gradient_max_darkness = max_darkness;
invalidate_pipeline (self, CHANGED_GRADIENT_PARAMETERS);
changed = TRUE;
}
if (changed)
clutter_content_invalidate (CLUTTER_CONTENT (self));
}
void
meta_background_content_set_vignette (MetaBackgroundContent *self,
gboolean enabled,
double brightness,
double sharpness)
{
gboolean changed = FALSE;
g_return_if_fail (META_IS_BACKGROUND_CONTENT (self));
g_return_if_fail (brightness >= 0. && brightness <= 1.);
g_return_if_fail (sharpness >= 0.);
enabled = enabled != FALSE;
if (enabled != self->vignette)
{
self->vignette = enabled;
invalidate_pipeline (self, CHANGED_EFFECTS);
changed = TRUE;
}
if (brightness != self->vignette_brightness || sharpness != self->vignette_sharpness)
{
self->vignette_brightness = brightness;
self->vignette_sharpness = sharpness;
invalidate_pipeline (self, CHANGED_VIGNETTE_PARAMETERS);
changed = TRUE;
}
if (changed)
clutter_content_invalidate (CLUTTER_CONTENT (self));
}
cairo_region_t *
meta_background_content_get_clip_region (MetaBackgroundContent *self)
{
return self->clip_region;
}
void
meta_background_content_cull_out (MetaBackgroundContent *self,
cairo_region_t *unobscured_region,
cairo_region_t *clip_region)
{
set_unobscured_region (self, unobscured_region);
set_clip_region (self, clip_region);
}
void
meta_background_content_reset_culling (MetaBackgroundContent *self)
{
set_unobscured_region (self, NULL);
set_clip_region (self, NULL);
}

View File

@ -127,10 +127,12 @@ meta_compositor_native_pre_paint (MetaCompositor *compositor)
}
MetaCompositorNative *
meta_compositor_native_new (MetaDisplay *display)
meta_compositor_native_new (MetaDisplay *display,
MetaBackend *backend)
{
return g_object_new (META_TYPE_COMPOSITOR_NATIVE,
"display", display,
"backend", backend,
NULL);
}

View File

@ -27,6 +27,7 @@
G_DECLARE_FINAL_TYPE (MetaCompositorNative, meta_compositor_native,
META, COMPOSITOR_NATIVE, MetaCompositor)
MetaCompositorNative * meta_compositor_native_new (MetaDisplay *display);
MetaCompositorNative * meta_compositor_native_new (MetaDisplay *display,
MetaBackend *backend);
#endif /* META_COMPOSITOR_NATIVE_H */

View File

@ -37,10 +37,12 @@ meta_compositor_server_unmanage (MetaCompositor *compositor)
}
MetaCompositorServer *
meta_compositor_server_new (MetaDisplay *display)
meta_compositor_server_new (MetaDisplay *display,
MetaBackend *backend)
{
return g_object_new (META_TYPE_COMPOSITOR_SERVER,
"display", display,
"backend", backend,
NULL);
}

View File

@ -32,6 +32,7 @@ struct _MetaCompositorServerClass
MetaCompositorClass parent_class;
};
MetaCompositorServer * meta_compositor_server_new (MetaDisplay *display);
MetaCompositorServer * meta_compositor_server_new (MetaDisplay *display,
MetaBackend *backend);
#endif /* META_COMPOSITOR_SERVER_H */

View File

@ -371,10 +371,12 @@ meta_compositor_x11_get_output_xwindow (MetaCompositorX11 *compositor_x11)
}
MetaCompositorX11 *
meta_compositor_x11_new (MetaDisplay *display)
meta_compositor_x11_new (MetaDisplay *display,
MetaBackend *backend)
{
return g_object_new (META_TYPE_COMPOSITOR_X11,
"display", display,
"backend", backend,
NULL);
}

View File

@ -27,7 +27,8 @@
G_DECLARE_FINAL_TYPE (MetaCompositorX11, meta_compositor_x11,
META, COMPOSITOR_X11, MetaCompositor)
MetaCompositorX11 * meta_compositor_x11_new (MetaDisplay *display);
MetaCompositorX11 * meta_compositor_x11_new (MetaDisplay *display,
MetaBackend *backend);
void meta_compositor_x11_process_xevent (MetaCompositorX11 *compositor_x11,
XEvent *xevent,

View File

@ -30,6 +30,7 @@
#include "clutter/clutter.h"
#include "meta/meta-backend.h"
#include "meta/meta-background-actor.h"
#include "meta/meta-background-content.h"
#include "meta/meta-background-group.h"
#include "meta/meta-monitor-manager.h"
#include "meta/meta-plugin.h"
@ -332,6 +333,8 @@ on_monitors_changed (MetaMonitorManager *monitor_manager,
n = meta_display_get_n_monitors (display);
for (i = 0; i < n; i++)
{
MetaBackgroundContent *background_content;
ClutterContent *content;
MetaRectangle rect;
ClutterActor *background_actor;
MetaBackground *background;
@ -340,6 +343,8 @@ on_monitors_changed (MetaMonitorManager *monitor_manager,
meta_display_get_monitor_geometry (display, i, &rect);
background_actor = meta_background_actor_new (display, i);
content = clutter_actor_get_content (background_actor);
background_content = META_BACKGROUND_CONTENT (content);
clutter_actor_set_position (background_actor, rect.x, rect.y);
clutter_actor_set_size (background_actor, rect.width, rect.height);
@ -356,13 +361,10 @@ on_monitors_changed (MetaMonitorManager *monitor_manager,
background = meta_background_new (display);
meta_background_set_color (background, &color);
meta_background_actor_set_background (META_BACKGROUND_ACTOR (background_actor), background);
meta_background_content_set_background (background_content, background);
g_object_unref (background);
meta_background_actor_set_vignette (META_BACKGROUND_ACTOR (background_actor),
TRUE,
0.5,
0.5);
meta_background_content_set_vignette (background_content, TRUE, 0.5, 0.5);
clutter_actor_add_child (self->priv->background_group, background_actor);
}

View File

@ -573,17 +573,17 @@ meta_display_remove_pending_pings_for_window (MetaDisplay *display,
static MetaCompositor *
create_compositor (MetaDisplay *display)
{
#ifdef HAVE_WAYLAND
MetaBackend *backend = meta_get_backend ();
#ifdef HAVE_WAYLAND
#ifdef HAVE_NATIVE_BACKEND
if (META_IS_BACKEND_NATIVE (backend))
return META_COMPOSITOR (meta_compositor_native_new (display));
return META_COMPOSITOR (meta_compositor_native_new (display, backend));
#endif
if (META_IS_BACKEND_X11_NESTED (backend))
return META_COMPOSITOR (meta_compositor_server_new (display));
return META_COMPOSITOR (meta_compositor_server_new (display, backend));
#endif
return META_COMPOSITOR (meta_compositor_x11_new (display));
return META_COMPOSITOR (meta_compositor_x11_new (display, backend));
}
static void

View File

@ -30,6 +30,7 @@
#include "config.h"
#include "backends/meta-backend-private.h"
#include "backends/meta-keymap-utils.h"
#include "backends/meta-logical-monitor.h"
#include "backends/meta-monitor-manager-private.h"
#include "backends/x11/meta-backend-x11.h"
@ -741,7 +742,7 @@ create_us_layout (void)
names.variant = "";
names.options = "";
context = xkb_context_new (XKB_CONTEXT_NO_FLAGS);
context = meta_create_xkb_context ();
keymap = xkb_keymap_new_from_names (context, &names, XKB_KEYMAP_COMPILE_NO_FLAGS);
xkb_context_unref (context);

View File

@ -152,6 +152,7 @@ owner_changed_cb (MetaSelection *selection,
display->saved_clipboard);
g_set_object (&display->selection_source, new_owner);
meta_selection_set_owner (selection, selection_type, new_owner);
g_object_unref (new_owner);
}
}
@ -170,6 +171,7 @@ meta_clipboard_manager_shutdown (MetaDisplay *display)
{
MetaSelection *selection;
g_clear_object (&display->selection_source);
g_clear_pointer (&display->saved_clipboard, g_bytes_unref);
g_clear_pointer (&display->saved_clipboard_mimetype, g_free);
selection = meta_display_get_selection (display);

View File

@ -365,103 +365,119 @@ move_window_above (GArray *stack,
static gboolean
meta_stack_op_apply (MetaStackTracker *tracker,
MetaStackOp *op,
GArray *stack,
GArray *stack,
ApplyFlags apply_flags)
{
switch (op->any.type)
{
case STACK_OP_ADD:
{
int old_pos;
if (META_STACK_ID_IS_X11 (op->add.window) &&
(apply_flags & NO_RESTACK_X_WINDOWS) != 0)
return FALSE;
int old_pos = find_window (stack, op->add.window);
if (old_pos >= 0)
{
g_warning ("STACK_OP_ADD: window %s already in stack",
get_window_desc (tracker, op->add.window));
return FALSE;
}
old_pos = find_window (stack, op->add.window);
if (old_pos >= 0)
{
meta_topic (META_DEBUG_STACK,
"STACK_OP_ADD: window %s already in stack",
get_window_desc (tracker, op->add.window));
return FALSE;
}
g_array_append_val (stack, op->add.window);
return TRUE;
g_array_append_val (stack, op->add.window);
return TRUE;
}
case STACK_OP_REMOVE:
{
int old_pos;
if (META_STACK_ID_IS_X11 (op->remove.window) &&
(apply_flags & NO_RESTACK_X_WINDOWS) != 0)
return FALSE;
int old_pos = find_window (stack, op->remove.window);
if (old_pos < 0)
{
g_warning ("STACK_OP_REMOVE: window %s not in stack",
get_window_desc (tracker, op->remove.window));
return FALSE;
}
old_pos = find_window (stack, op->remove.window);
if (old_pos < 0)
{
meta_topic (META_DEBUG_STACK,
"STACK_OP_REMOVE: window %s not in stack",
get_window_desc (tracker, op->remove.window));
return FALSE;
}
g_array_remove_index (stack, old_pos);
return TRUE;
g_array_remove_index (stack, old_pos);
return TRUE;
}
case STACK_OP_RAISE_ABOVE:
{
int old_pos = find_window (stack, op->raise_above.window);
int above_pos;
if (old_pos < 0)
{
g_warning ("STACK_OP_RAISE_ABOVE: window %s not in stack",
get_window_desc (tracker, op->raise_above.window));
return FALSE;
}
int old_pos;
int above_pos;
old_pos = find_window (stack, op->raise_above.window);
if (old_pos < 0)
{
meta_topic (META_DEBUG_STACK,
"STACK_OP_RAISE_ABOVE: window %s not in stack",
get_window_desc (tracker, op->raise_above.window));
return FALSE;
}
if (op->raise_above.sibling)
{
above_pos = find_window (stack, op->raise_above.sibling);
if (above_pos < 0)
{
g_warning ("STACK_OP_RAISE_ABOVE: sibling window %s not in stack",
get_window_desc (tracker, op->raise_above.sibling));
return FALSE;
}
}
else
{
above_pos = -1;
}
{
above_pos = find_window (stack, op->raise_above.sibling);
if (above_pos < 0)
{
meta_topic (META_DEBUG_STACK,
"STACK_OP_RAISE_ABOVE: sibling window %s not in stack",
get_window_desc (tracker, op->raise_above.sibling));
return FALSE;
}
}
else
{
above_pos = -1;
}
return move_window_above (stack, op->raise_above.window, old_pos, above_pos,
return move_window_above (stack, op->raise_above.window, old_pos, above_pos,
apply_flags);
}
case STACK_OP_LOWER_BELOW:
{
int old_pos = find_window (stack, op->lower_below.window);
int above_pos;
if (old_pos < 0)
{
g_warning ("STACK_OP_LOWER_BELOW: window %s not in stack",
get_window_desc (tracker, op->lower_below.window));
return FALSE;
}
int old_pos;
int above_pos;
old_pos = find_window (stack, op->raise_above.window);
if (old_pos < 0)
{
meta_topic (META_DEBUG_STACK,
"STACK_OP_LOWER_BELOW: window %s not in stack",
get_window_desc (tracker, op->lower_below.window));
return FALSE;
}
if (op->lower_below.sibling)
{
int below_pos = find_window (stack, op->lower_below.sibling);
if (below_pos < 0)
{
g_warning ("STACK_OP_LOWER_BELOW: sibling window %s not in stack",
get_window_desc (tracker, op->lower_below.sibling));
return FALSE;
}
{
int below_pos;
above_pos = below_pos - 1;
}
else
{
above_pos = stack->len - 1;
}
below_pos = find_window (stack, op->lower_below.sibling);
if (below_pos < 0)
{
meta_topic (META_DEBUG_STACK,
"STACK_OP_LOWER_BELOW: sibling window %s not in stack",
get_window_desc (tracker, op->lower_below.sibling));
return FALSE;
}
return move_window_above (stack, op->lower_below.window, old_pos, above_pos,
above_pos = below_pos - 1;
}
else
{
above_pos = stack->len - 1;
}
return move_window_above (stack, op->lower_below.window, old_pos, above_pos,
apply_flags);
}
}

View File

@ -195,6 +195,8 @@ mutter_sources = [
'backends/meta-input-mapper-private.h',
'backends/meta-input-settings.c',
'backends/meta-input-settings-private.h',
'backends/meta-keymap-utils.c',
'backends/meta-keymap-utils.h',
'backends/meta-logical-monitor.c',
'backends/meta-logical-monitor.h',
'backends/meta-monitor.c',
@ -287,6 +289,8 @@ mutter_sources = [
'compositor/compositor-private.h',
'compositor/meta-background-actor.c',
'compositor/meta-background-actor-private.h',
'compositor/meta-background-content.c',
'compositor/meta-background-content-private.h',
'compositor/meta-background.c',
'compositor/meta-background-group.c',
'compositor/meta-background-image.c',
@ -529,6 +533,12 @@ if have_wayland
'wayland/meta-wayland-inhibit-shortcuts-dialog.c',
'wayland/meta-wayland-inhibit-shortcuts-dialog.h',
'wayland/meta-wayland-inhibit-shortcuts.h',
'wayland/meta-wayland-inputfd-evdev-device.c',
'wayland/meta-wayland-inputfd-evdev-device.h',
'wayland/meta-wayland-inputfd-manager.c',
'wayland/meta-wayland-inputfd-manager.h',
'wayland/meta-wayland-inputfd-seat.c',
'wayland/meta-wayland-inputfd-seat.h',
'wayland/meta-wayland-input-device.c',
'wayland/meta-wayland-input-device.h',
'wayland/meta-wayland-keyboard.c',
@ -810,6 +820,7 @@ if have_wayland
['gtk-primary-selection', 'private', ],
['gtk-shell', 'private', ],
['gtk-text-input', 'private', ],
['inputfd', 'unstable', 'v1', ],
['keyboard-shortcuts-inhibit', 'unstable', 'v1', ],
['linux-dmabuf', 'unstable', 'v1', ],
['pointer-constraints', 'unstable', 'v1', ],

View File

@ -11,6 +11,7 @@ mutter_public_headers = [
'meta-backend.h',
'meta-background.h',
'meta-background-actor.h',
'meta-background-content.h',
'meta-background-group.h',
'meta-background-image.h',
'meta-close-dialog.h',

View File

@ -47,24 +47,4 @@ META_EXPORT
ClutterActor *meta_background_actor_new (MetaDisplay *display,
int monitor);
META_EXPORT
void meta_background_actor_set_background (MetaBackgroundActor *self,
MetaBackground *background);
META_EXPORT
void meta_background_actor_set_gradient (MetaBackgroundActor *self,
gboolean enabled,
int height,
double tone_start);
META_EXPORT
void meta_background_actor_set_monitor (MetaBackgroundActor *self,
int monitor);
META_EXPORT
void meta_background_actor_set_vignette (MetaBackgroundActor *self,
gboolean enabled,
double brightness,
double sharpness);
#endif /* META_BACKGROUND_ACTOR_H */

View File

@ -0,0 +1,66 @@
/*
* meta-background-content.h: ClutterContent for painting the wallpaper
*
* Copyright 2010 Red Hat, Inc.
* Copyright 2020 Endless Foundation
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef META_BACKGROUND_CONTENT_H
#define META_BACKGROUND_CONTENT_H
#include <gsettings-desktop-schemas/gdesktop-enums.h>
#include "clutter/clutter.h"
#include "meta/meta-background.h"
/**
* MetaBackgroundContent:
*
* This class handles tracking and painting the root window background.
* By integrating with #MetaWindowGroup we can avoid painting parts of
* the background that are obscured by other windows.
*/
#define META_TYPE_BACKGROUND_CONTENT (meta_background_content_get_type ())
META_EXPORT
G_DECLARE_FINAL_TYPE (MetaBackgroundContent,
meta_background_content,
META, BACKGROUND_CONTENT,
GObject)
META_EXPORT
ClutterContent *meta_background_content_new (MetaDisplay *display,
int monitor);
META_EXPORT
void meta_background_content_set_background (MetaBackgroundContent *self,
MetaBackground *background);
META_EXPORT
void meta_background_content_set_gradient (MetaBackgroundContent *self,
gboolean enabled,
int height,
double tone_start);
META_EXPORT
void meta_background_content_set_vignette (MetaBackgroundContent *self,
gboolean enabled,
double brightness,
double sharpness);
#endif /* META_BACKGROUND_CONTENT_H */

View File

@ -5,8 +5,6 @@
#include <clutter/clutter.h>
typedef struct {
ClutterActor *stage;
guint no_display : 1;
} ClutterTestEnvironment;
@ -98,18 +96,9 @@ out:
ClutterActor *
clutter_test_get_stage (void)
{
g_assert (test_environ != NULL);
MetaBackend *backend = meta_get_backend ();
if (test_environ->stage == NULL)
{
/* create a stage, and ensure that it goes away at the end */
test_environ->stage = clutter_stage_new ();
clutter_actor_set_name (test_environ->stage, "Test Stage");
g_object_add_weak_pointer (G_OBJECT (test_environ->stage),
(gpointer *) &test_environ->stage);
}
return test_environ->stage;
return meta_backend_get_stage (backend);
}
typedef struct {
@ -122,11 +111,13 @@ static void
clutter_test_func_wrapper (gconstpointer data_)
{
const ClutterTestData *data = data_;
ClutterActor *stage;
g_test_log_set_fatal_handler (log_func, NULL);
/* ensure that the previous test state has been cleaned up */
g_assert_null (test_environ->stage);
stage = clutter_test_get_stage ();
g_assert_false (clutter_actor_is_mapped (stage));
if (test_environ->no_display)
{
@ -151,11 +142,8 @@ out:
if (data->test_notify != NULL)
data->test_notify (data->test_data);
if (test_environ->stage != NULL)
{
clutter_actor_destroy (test_environ->stage);
g_assert_null (test_environ->stage);
}
clutter_actor_remove_all_children (stage);
clutter_actor_hide (stage);
}
/**

View File

@ -132,7 +132,7 @@ check_coords (TestState *state,
gint y_2,
const graphene_point3d_t *verts)
{
if (g_test_verbose ())
if (!g_test_quiet ())
g_print ("checking that (%i,%i,%i,%i) \xe2\x89\x88 (%i,%i,%i,%i): %s\n",
x_1, y_1, x_2, y_2,
(int) (verts[0].x),
@ -200,7 +200,7 @@ test_anchor_point (TestState *state)
/* Change the anchor point with each of the gravities */
for (i = 0; i < G_N_ELEMENTS (gravities); i++)
{
if (g_test_verbose ())
if (!g_test_quiet ())
{
GEnumClass *gravity_class = g_type_class_ref (CLUTTER_TYPE_GRAVITY);
GEnumValue *value = g_enum_get_value (gravity_class,
@ -356,7 +356,7 @@ test_scale_center (TestState *state)
/* Change the anchor point with each of the gravities */
for (i = 0; i < G_N_ELEMENTS (gravities); i++)
{
if (g_test_verbose ())
if (!g_test_quiet ())
{
GEnumClass *gravity_class = g_type_class_ref (CLUTTER_TYPE_GRAVITY);
GEnumValue *value = g_enum_get_value (gravity_class,
@ -472,7 +472,7 @@ test_rotate_center (TestState *state)
char prop_name[] = "rotation-angle- ";
prop_name[sizeof (prop_name) - 2] = i - CLUTTER_X_AXIS + 'x';
if (g_test_verbose ())
if (!g_test_quiet ())
g_print ("Setting %s to 90 degrees\n", prop_name);
g_object_set (rect, prop_name, 90.0, NULL);
@ -531,7 +531,7 @@ test_rotate_center (TestState *state)
char prop_name[] = "rotation-angle- ";
prop_name[sizeof (prop_name) - 2] = i - CLUTTER_X_AXIS + 'x';
if (g_test_verbose ())
if (!g_test_quiet ())
g_print ("Setting %s to 90 degrees with center 10,20,0\n", prop_name);
clutter_actor_set_rotation (rect, i, 90.0, 10, 20, 0);
@ -605,7 +605,7 @@ test_rotate_center (TestState *state)
/* Try rotating the z with all of the gravities */
for (i = 0; i < G_N_ELEMENTS (gravities); i++)
{
if (g_test_verbose ())
if (!g_test_quiet ())
{
GEnumClass *gravity_class = g_type_class_ref (CLUTTER_TYPE_GRAVITY);
GEnumValue *value = g_enum_get_value (gravity_class,

View File

@ -39,7 +39,7 @@ test_destroy_add (ClutterContainer *container,
{
TestDestroy *self = TEST_DESTROY (container);
if (g_test_verbose ())
if (!g_test_quiet ())
g_print ("Adding '%s' (type:%s)\n",
clutter_actor_get_name (actor),
G_OBJECT_TYPE_NAME (actor));
@ -54,7 +54,7 @@ test_destroy_remove (ClutterContainer *container,
{
TestDestroy *self = TEST_DESTROY (container);
if (g_test_verbose ())
if (!g_test_quiet ())
g_print ("Removing '%s' (type:%s)\n",
clutter_actor_get_name (actor),
G_OBJECT_TYPE_NAME (actor));
@ -81,7 +81,7 @@ test_destroy_destroy (ClutterActor *self)
if (test->bg != NULL)
{
if (g_test_verbose ())
if (!g_test_quiet ())
g_print ("Destroying '%s' (type:%s)\n",
clutter_actor_get_name (test->bg),
G_OBJECT_TYPE_NAME (test->bg));
@ -92,7 +92,7 @@ test_destroy_destroy (ClutterActor *self)
if (test->label != NULL)
{
if (g_test_verbose ())
if (!g_test_quiet ())
g_print ("Destroying '%s' (type:%s)\n",
clutter_actor_get_name (test->label),
G_OBJECT_TYPE_NAME (test->label));
@ -174,7 +174,7 @@ actor_destruction (void)
g_object_add_weak_pointer (G_OBJECT (test), (gpointer *) &test);
g_object_add_weak_pointer (G_OBJECT (child), (gpointer *) &child);
if (g_test_verbose ())
if (!g_test_quiet ())
g_print ("Adding external child...\n");
clutter_actor_set_name (child, "Child");
@ -184,7 +184,7 @@ actor_destruction (void)
g_signal_connect (child, "notify", G_CALLBACK (on_notify), &property_changed);
g_signal_connect (child, "destroy", G_CALLBACK (on_destroy), &destroy_called);
if (g_test_verbose ())
if (!g_test_quiet ())
g_print ("Calling destroy()...\n");
clutter_actor_destroy (test);

View File

@ -408,7 +408,7 @@ actor_added (ClutterContainer *container,
int *counter = data;
ClutterActor *old_child;
if (g_test_verbose ())
if (!g_test_quiet ())
g_print ("Adding actor '%s'\n", clutter_actor_get_name (child));
old_child = clutter_actor_get_child_at_index (actor, 0);
@ -425,7 +425,7 @@ actor_removed (ClutterContainer *container,
{
int *counter = data;
if (g_test_verbose ())
if (!g_test_quiet ())
g_print ("Removing actor '%s'\n", clutter_actor_get_name (child));
*counter += 1;

View File

@ -15,7 +15,7 @@ actor_initial_state (void)
g_object_ref_sink (actor);
g_object_add_weak_pointer (G_OBJECT (actor), (gpointer *) &actor);
if (g_test_verbose ())
if (!g_test_quiet ())
g_print ("initial state - visible: %s, realized: %s, mapped: %s\n",
CLUTTER_ACTOR_IS_VISIBLE (actor) ? "yes" : "no",
CLUTTER_ACTOR_IS_REALIZED (actor) ? "yes" : "no",
@ -40,7 +40,7 @@ actor_shown_not_parented (void)
clutter_actor_show (actor);
if (g_test_verbose ())
if (!g_test_quiet ())
g_print ("show without a parent - visible: %s, realized: %s, mapped: %s\n",
CLUTTER_ACTOR_IS_VISIBLE (actor) ? "yes" : "no",
CLUTTER_ACTOR_IS_REALIZED (actor) ? "yes" : "no",
@ -92,7 +92,7 @@ actor_mapped (void)
clutter_actor_add_child (stage, actor);
if (g_test_verbose ())
if (!g_test_quiet ())
g_print ("adding to a container should map - "
"visible: %s, realized: %s, mapped: %s\n",
CLUTTER_ACTOR_IS_VISIBLE (actor) ? "yes" : "no",
@ -105,7 +105,7 @@ actor_mapped (void)
clutter_actor_hide (actor);
if (g_test_verbose ())
if (!g_test_quiet ())
g_print ("hiding should unmap - "
"visible: %s, realized: %s, mapped: %s\n",
CLUTTER_ACTOR_IS_VISIBLE (actor) ? "yes" : "no",

View File

@ -40,7 +40,7 @@ actor_iter_traverse_children (void)
g_assert (CLUTTER_IS_ACTOR (child));
g_assert (clutter_actor_get_parent (child) == actor);
if (g_test_verbose ())
if (!g_test_quiet ())
g_print ("actor %d = '%s'\n", i, clutter_actor_get_name (child));
if (i == 0)
@ -63,7 +63,7 @@ actor_iter_traverse_children (void)
g_assert (CLUTTER_IS_ACTOR (child));
g_assert (clutter_actor_get_parent (child) == actor);
if (g_test_verbose ())
if (!g_test_quiet ())
g_print ("actor %d = '%s'\n", i, clutter_actor_get_name (child));
if (i == 0)
@ -115,7 +115,7 @@ actor_iter_traverse_remove (void)
g_assert (CLUTTER_IS_ACTOR (child));
g_assert (clutter_actor_get_parent (child) == actor);
if (g_test_verbose ())
if (!g_test_quiet ())
g_print ("actor %d = '%s'\n", i, clutter_actor_get_name (child));
if (i == 0)
@ -176,7 +176,7 @@ actor_iter_assignment (void)
g_assert (CLUTTER_IS_ACTOR (child));
g_assert (clutter_actor_get_parent (child) == actor);
if (g_test_verbose ())
if (!g_test_quiet ())
g_print ("actor %2d = '%s'\n", i, clutter_actor_get_name (child));
if (i == 0)
@ -196,7 +196,7 @@ actor_iter_assignment (void)
{
g_assert (clutter_actor_get_parent (child) == actor);
if (g_test_verbose ())
if (!g_test_quiet ())
g_print ("actor %2d = '%s'\n", i, clutter_actor_get_name (child));
if (i == n_actors - 1)

View File

@ -16,7 +16,7 @@ opacity_label (void)
label = clutter_text_new_with_text ("Sans 18px", "Label, 50% opacity");
clutter_text_set_color (CLUTTER_TEXT (label), &label_color);
if (g_test_verbose ())
if (!g_test_quiet ())
g_print ("label 50%%.get_color()/1\n");
clutter_text_get_color (CLUTTER_TEXT (label), &color_check);
g_assert (color_check.alpha == label_color.alpha);
@ -24,16 +24,16 @@ opacity_label (void)
clutter_actor_add_child (stage, label);
clutter_actor_set_position (label, 10, 10);
if (g_test_verbose ())
if (!g_test_quiet ())
g_print ("label 50%%.get_color()/2\n");
clutter_text_get_color (CLUTTER_TEXT (label), &color_check);
g_assert (color_check.alpha == label_color.alpha);
if (g_test_verbose ())
if (!g_test_quiet ())
g_print ("label 50%%.get_paint_opacity()/1\n");
g_assert (clutter_actor_get_paint_opacity (label) == 255);
if (g_test_verbose ())
if (!g_test_quiet ())
g_print ("label 50%%.get_paint_opacity()/2\n");
clutter_actor_set_opacity (label, 128);
g_assert (clutter_actor_get_paint_opacity (label) == 128);
@ -54,19 +54,19 @@ opacity_rectangle (void)
clutter_actor_set_size (rect, 128, 128);
clutter_actor_set_position (rect, 150, 90);
if (g_test_verbose ())
if (!g_test_quiet ())
g_print ("rect 100%%.get_color()/1\n");
clutter_rectangle_get_color (CLUTTER_RECTANGLE (rect), &color_check);
g_assert (color_check.alpha == rect_color.alpha);
clutter_actor_add_child (stage, rect);
if (g_test_verbose ())
if (!g_test_quiet ())
g_print ("rect 100%%.get_color()/2\n");
clutter_rectangle_get_color (CLUTTER_RECTANGLE (rect), &color_check);
g_assert (color_check.alpha == rect_color.alpha);
if (g_test_verbose ())
if (!g_test_quiet ())
g_print ("rect 100%%.get_paint_opacity()\n");
g_assert (clutter_actor_get_paint_opacity (rect) == 255);
}
@ -93,19 +93,19 @@ opacity_paint (void)
label = clutter_text_new_with_text ("Sans 18px", "Label+Group, 25% opacity");
clutter_text_set_color (CLUTTER_TEXT (label), &label_color);
if (g_test_verbose ())
if (!g_test_quiet ())
g_print ("label 50%% + group 50%%.get_color()/1\n");
clutter_text_get_color (CLUTTER_TEXT (label), &color_check);
g_assert (color_check.alpha == label_color.alpha);
clutter_container_add (CLUTTER_CONTAINER (group1), label, NULL);
if (g_test_verbose ())
if (!g_test_quiet ())
g_print ("label 50%% + group 50%%.get_color()/2\n");
clutter_text_get_color (CLUTTER_TEXT (label), &color_check);
g_assert (color_check.alpha == label_color.alpha);
if (g_test_verbose ())
if (!g_test_quiet ())
g_print ("label 50%% + group 50%%.get_paint_opacity() = 128\n");
g_assert (clutter_actor_get_paint_opacity (label) == 128);
@ -118,19 +118,19 @@ opacity_paint (void)
rect = clutter_rectangle_new_with_color (&rect_color);
clutter_actor_set_size (rect, 128, 128);
if (g_test_verbose ())
if (!g_test_quiet ())
g_print ("rect 100%% + group 100%% + group 50%%.get_color()/1\n");
clutter_rectangle_get_color (CLUTTER_RECTANGLE (rect), &color_check);
g_assert (color_check.alpha == rect_color.alpha);
clutter_container_add (CLUTTER_CONTAINER (group2), rect, NULL);
if (g_test_verbose ())
if (!g_test_quiet ())
g_print ("rect 100%% + group 100%% + group 50%%.get_color()/2\n");
clutter_rectangle_get_color (CLUTTER_RECTANGLE (rect), &color_check);
g_assert (color_check.alpha == rect_color.alpha);
if (g_test_verbose ())
if (!g_test_quiet ())
g_print ("rect 100%%.get_paint_opacity()\n");
g_assert (clutter_actor_get_paint_opacity (rect) == 128);
}

View File

@ -49,7 +49,7 @@ on_timeout (gpointer data)
{
if (test_num == 0)
{
if (g_test_verbose ())
if (!g_test_quiet ())
g_print ("No covering actor:\n");
}
if (test_num == 1)
@ -62,7 +62,7 @@ on_timeout (gpointer data)
clutter_actor_add_child (state->stage, over_actor);
clutter_actor_hide (over_actor);
if (g_test_verbose ())
if (!g_test_quiet ())
g_print ("Invisible covering actor:\n");
}
else if (test_num == 2)
@ -84,7 +84,7 @@ on_timeout (gpointer data)
*/
clutter_actor_allocate (over_actor, &over_actor_box);
if (g_test_verbose ())
if (!g_test_quiet ())
g_print ("Clipped covering actor:\n");
}
else if (test_num == 3)
@ -98,7 +98,7 @@ on_timeout (gpointer data)
"blur",
clutter_blur_effect_new ());
if (g_test_verbose ())
if (!g_test_quiet ())
g_print ("With blur effect:\n");
}
@ -121,13 +121,13 @@ on_timeout (gpointer data)
y * state->actor_height
+ state->actor_height / 2);
if (g_test_verbose ())
if (!g_test_quiet ())
g_print ("% 3i,% 3i / %p -> ",
x, y, state->actors[y * ACTORS_X + x]);
if (actor == NULL)
{
if (g_test_verbose ())
if (!g_test_quiet ())
g_print ("NULL: FAIL\n");
}
else if (actor == over_actor)
@ -137,7 +137,7 @@ on_timeout (gpointer data)
&& y >= 2 && y < ACTORS_Y - 2)
pass = TRUE;
if (g_test_verbose ())
if (!g_test_quiet ())
g_print ("over_actor: %s\n", pass ? "pass" : "FAIL");
}
else
@ -148,7 +148,7 @@ on_timeout (gpointer data)
|| y < 2 || y >= ACTORS_Y - 2))
pass = TRUE;
if (g_test_verbose ())
if (!g_test_quiet ())
g_print ("%p: %s\n", actor, pass ? "pass" : "FAIL");
}
@ -206,7 +206,7 @@ actor_pick (void)
clutter_main ();
if (g_test_verbose ())
if (!g_test_quiet ())
{
if (!state.pass)
g_test_message ("Failed pass: %s[%d], actor index: %d [%p]\n",

View File

@ -260,7 +260,7 @@ actor_shader_effect (void)
if (!clutter_feature_available (CLUTTER_FEATURE_SHADERS_GLSL))
return;
stage = clutter_stage_new ();
stage = clutter_test_get_stage ();
rect = make_actor (foo_old_shader_effect_get_type ());
clutter_container_add_actor (CLUTTER_CONTAINER (stage), rect);

View File

@ -91,7 +91,7 @@ actor_preferred_size (void)
test = g_object_new (TEST_TYPE_ACTOR, NULL);
self = (TestActor *) test;
if (g_test_verbose ())
if (!g_test_quiet ())
g_print ("Preferred size\n");
clutter_actor_get_preferred_size (test,
@ -105,7 +105,7 @@ actor_preferred_size (void)
g_assert_cmpfloat (nat_width, ==, min_width);
g_assert_cmpfloat (nat_height, ==, min_height);
if (g_test_verbose ())
if (!g_test_quiet ())
g_print ("Preferred width\n");
self->preferred_width_called = FALSE;
clutter_actor_get_preferred_width (test, 10, &min_width, &nat_width);
@ -113,7 +113,7 @@ actor_preferred_size (void)
g_assert_cmpfloat (min_width, ==, 10);
g_assert_cmpfloat (nat_width, ==, 100);
if (g_test_verbose ())
if (!g_test_quiet ())
g_print ("Preferred height\n");
self->preferred_height_called = FALSE;
clutter_actor_get_preferred_height (test, 200, &min_height, &nat_height);
@ -121,7 +121,7 @@ actor_preferred_size (void)
g_assert_cmpfloat (min_height, !=, 10);
g_assert_cmpfloat (nat_height, ==, 100);
if (g_test_verbose ())
if (!g_test_quiet ())
g_print ("Preferred width (cached)\n");
self->preferred_width_called = FALSE;
clutter_actor_get_preferred_width (test, 10, &min_width, &nat_width);
@ -129,7 +129,7 @@ actor_preferred_size (void)
g_assert_cmpfloat (min_width, ==, 10);
g_assert_cmpfloat (nat_width, ==, 100);
if (g_test_verbose ())
if (!g_test_quiet ())
g_print ("Preferred height (cache eviction)\n");
self->preferred_height_called = FALSE;
clutter_actor_get_preferred_height (test, 10, &min_height, &nat_height);
@ -152,7 +152,7 @@ actor_fixed_size (void)
rect = clutter_actor_new ();
g_object_ref_sink (rect);
if (g_test_verbose ())
if (!g_test_quiet ())
g_print ("Initial size is 0\n");
g_assert_cmpfloat (clutter_actor_get_width (rect), ==, 0);
@ -160,7 +160,7 @@ actor_fixed_size (void)
clutter_actor_set_size (rect, 100, 100);
if (g_test_verbose ())
if (!g_test_quiet ())
g_print ("Explicit size set\n");
g_assert_cmpfloat (clutter_actor_get_width (rect), ==, 100);
@ -173,7 +173,7 @@ actor_fixed_size (void)
"natural-height-set", &nat_height_set,
NULL);
if (g_test_verbose ())
if (!g_test_quiet ())
g_print ("Notification properties\n");
g_assert (min_width_set && nat_width_set);
@ -183,7 +183,7 @@ actor_fixed_size (void)
&min_width, &min_height,
&nat_width, &nat_height);
if (g_test_verbose ())
if (!g_test_quiet ())
g_print ("Preferred size\n");
g_assert_cmpfloat (min_width, ==, 100);
@ -193,7 +193,7 @@ actor_fixed_size (void)
clutter_actor_set_size (rect, -1, -1);
if (g_test_verbose ())
if (!g_test_quiet ())
g_print ("Explicit size unset\n");
g_object_get (G_OBJECT (rect),

View File

@ -107,7 +107,7 @@ check_result (CallbackData *data)
if (g_strcmp0 (expected_text, text) != 0)
{
if (g_test_verbose ())
if (!g_test_quiet ())
g_print ("text value differs %s vs %s\n", expected_text, text);
fail = TRUE;
}
@ -116,7 +116,7 @@ check_result (CallbackData *data)
expected_char = g_utf8_get_char (g_utf8_offset_to_pointer (text, data->offset));
if (expected_char != unichar)
{
if (g_test_verbose ())
if (!g_test_quiet ())
g_print ("text af offset differs\n");
fail = TRUE;
}
@ -125,25 +125,25 @@ check_result (CallbackData *data)
ATK_XY_WINDOW);
if (x != data->extents_x)
{
if (g_test_verbose ())
if (!g_test_quiet ())
g_print ("extents x position at index 0 differs (current value=%d)\n", x);
fail = TRUE;
}
if (y != data->extents_y)
{
if (g_test_verbose ())
if (!g_test_quiet ())
g_print ("extents y position at index 0 differs (current value=%d)\n", y);
fail = TRUE;
}
if (width != data->extents_width)
{
if (g_test_verbose ())
if (!g_test_quiet ())
g_print ("extents width at index 0 differs (current value=%d)\n", width);
fail = TRUE;
}
if (height != data->extents_height)
{
if (g_test_verbose ())
if (!g_test_quiet ())
g_print ("extents height at index 0 differs (current value=%d)\n", height);
fail = TRUE;
}
@ -151,7 +151,7 @@ check_result (CallbackData *data)
pos = atk_text_get_offset_at_point (cally_text, x, y, ATK_XY_WINDOW);
if (pos != data->offset)
{
if (g_test_verbose ())
if (!g_test_quiet ())
g_print ("offset at position (%d, %d) differs (current value=%d)\n", x,
y, pos);
fail = TRUE;
@ -161,20 +161,20 @@ check_result (CallbackData *data)
&start, &end);
if (start != 0)
{
if (g_test_verbose ())
if (!g_test_quiet ())
g_print ("run attributes start offset is not 0: %d\n", start);
fail = TRUE;
}
if (end != g_utf8_strlen (text, -1))
{
if (g_test_verbose ())
if (!g_test_quiet ())
g_print ("run attributes end offset is not text length: %d\n", end);
fail = TRUE;
}
attrs = (GSList*) at_set;
fail = compare_lists (attrs, data->run_attributes);
if (fail && g_test_verbose ())
if (fail && !g_test_quiet ())
{
g_print ("run attributes mismatch\n");
dump_attribute_set (attrs);
@ -183,7 +183,7 @@ check_result (CallbackData *data)
at_set = atk_text_get_default_attributes (cally_text);
attrs = (GSList*) at_set;
fail = compare_lists (attrs, data->default_attributes);
if (fail && g_test_verbose ())
if (fail && !g_test_quiet ())
{
g_print ("default attributes mismatch\n");
dump_attribute_set (attrs);
@ -194,11 +194,11 @@ check_result (CallbackData *data)
if (fail)
{
if (g_test_verbose ())
if (!g_test_quiet ())
g_print ("FAIL\n");
data->test_failed = TRUE;
}
else if (g_test_verbose ())
else if (!g_test_quiet ())
g_print ("pass\n");
return fail;
@ -319,10 +319,10 @@ cally_text (void)
clutter_actor_destroy (data.stage);
if (g_test_verbose ())
if (!g_test_quiet ())
g_print ("\nOverall result: ");
if (g_test_verbose ())
if (!g_test_quiet ())
{
if (data.test_failed)
g_print ("FAIL\n");

View File

@ -18,7 +18,7 @@ color_hls_roundtrip (void)
g_assert_cmpfloat (hue, ==, 0.0);
g_assert (luminance >= 0.0 && luminance <= 1.0);
g_assert_cmpfloat (saturation, ==, 0.0);
if (g_test_verbose ())
if (!g_test_quiet ())
{
g_print ("RGB = { %x, %x, %x }, HLS = { %.2f, %.2f, %.2f }\n",
color.red,
@ -48,7 +48,7 @@ color_hls_roundtrip (void)
g_assert (hue >= 0.0 && hue < 360.0);
g_assert (luminance >= 0.0 && luminance <= 1.0);
g_assert (saturation >= 0.0 && saturation <= 1.0);
if (g_test_verbose ())
if (!g_test_quiet ())
{
g_print ("RGB = { %x, %x, %x }, HLS = { %.2f, %.2f, %.2f }\n",
color.red,
@ -92,7 +92,7 @@ color_from_string_valid (void)
ClutterColor color;
g_assert (clutter_color_from_string (&color, "#ff0000ff"));
if (g_test_verbose ())
if (!g_test_quiet ())
{
g_print ("color = { %x, %x, %x, %x }, expected = { 0xff, 0, 0, 0xff }\n",
color.red,
@ -106,7 +106,7 @@ color_from_string_valid (void)
g_assert_cmpuint (color.alpha, ==, 0xff);
g_assert (clutter_color_from_string (&color, "#0f0f"));
if (g_test_verbose ())
if (!g_test_quiet ())
{
g_print ("color = { %x, %x, %x, %x }, expected = { 0, 0xff, 0, 0xff }\n",
color.red,
@ -120,7 +120,7 @@ color_from_string_valid (void)
g_assert_cmpuint (color.alpha, ==, 0xff);
g_assert (clutter_color_from_string (&color, "#0000ff"));
if (g_test_verbose ())
if (!g_test_quiet ())
{
g_print ("color = { %x, %x, %x, %x }, expected = { 0, 0, 0xff, 0xff }\n",
color.red,
@ -134,7 +134,7 @@ color_from_string_valid (void)
g_assert_cmpuint (color.alpha, ==, 0xff);
g_assert (clutter_color_from_string (&color, "#abc"));
if (g_test_verbose ())
if (!g_test_quiet ())
{
g_print ("color = { %x, %x, %x, %x }, expected = { 0xaa, 0xbb, 0xcc, 0xff }\n",
color.red,
@ -148,7 +148,7 @@ color_from_string_valid (void)
g_assert_cmpuint (color.alpha, ==, 0xff);
g_assert (clutter_color_from_string (&color, "#123abc"));
if (g_test_verbose ())
if (!g_test_quiet ())
{
g_print ("color = { %x, %x, %x, %x }, expected = { 0x12, 0x3a, 0xbc, 0xff }\n",
color.red,
@ -162,7 +162,7 @@ color_from_string_valid (void)
g_assert (color.alpha == 0xff);
g_assert (clutter_color_from_string (&color, "rgb(255, 128, 64)"));
if (g_test_verbose ())
if (!g_test_quiet ())
{
g_print ("color = { %x, %x, %x, %x }, expected = { 255, 128, 64, 255 }\n",
color.red,
@ -176,7 +176,7 @@ color_from_string_valid (void)
g_assert_cmpuint (color.alpha, ==, 255);
g_assert (clutter_color_from_string (&color, "rgba ( 30%, 0, 25%, 0.5 ) "));
if (g_test_verbose ())
if (!g_test_quiet ())
{
g_print ("color = { %x, %x, %x, %x }, expected = { %.1f, 0, %.1f, 128 }\n",
color.red,
@ -192,7 +192,7 @@ color_from_string_valid (void)
g_assert_cmpuint (color.alpha, ==, 127);
g_assert (clutter_color_from_string (&color, "rgb( 50%, -50%, 150% )"));
if (g_test_verbose ())
if (!g_test_quiet ())
{
g_print ("color = { %x, %x, %x, %x }, expected = { 127, 0, 255, 255 }\n",
color.red,
@ -206,7 +206,7 @@ color_from_string_valid (void)
g_assert_cmpuint (color.alpha, ==, 255);
g_assert (clutter_color_from_string (&color, "hsl( 0, 100%, 50% )"));
if (g_test_verbose ())
if (!g_test_quiet ())
{
g_print ("color = { %x, %x, %x, %x }, expected = { 255, 0, 0, 255 }\n",
color.red,
@ -222,7 +222,7 @@ color_from_string_valid (void)
g_assert (clutter_color_from_string (&color, "hsl( 0, 100%, 50% )"));
g_assert (clutter_color_from_string (&color, "hsla( 0, 100%, 50%, 0.5 )"));
if (g_test_verbose ())
if (!g_test_quiet ())
{
g_print ("color = { %x, %x, %x, %x }, expected = { 255, 0, 0, 127 }\n",
color.red,
@ -274,7 +274,7 @@ color_operators (void)
g_assert_cmpuint (op2.blue, ==, 0);
g_assert_cmpuint (op2.alpha, ==, 0xff);
if (g_test_verbose ())
if (!g_test_quiet ())
g_print ("Adding %x, %x; expected result: %x\n",
clutter_color_to_pixel (&op1),
clutter_color_to_pixel (&op2),
@ -283,7 +283,7 @@ color_operators (void)
clutter_color_add (&op1, &op2, &res);
g_assert_cmpuint (clutter_color_to_pixel (&res), ==, 0xffff00ff);
if (g_test_verbose ())
if (!g_test_quiet ())
g_print ("Checking alpha channel on color add\n");
op1.alpha = 0xdd;
@ -294,7 +294,7 @@ color_operators (void)
clutter_color_from_pixel (&op1, 0xffffffff);
clutter_color_from_pixel (&op2, 0xff00ffff);
if (g_test_verbose ())
if (!g_test_quiet ())
g_print ("Subtracting %x, %x; expected result: %x\n",
clutter_color_to_pixel (&op1),
clutter_color_to_pixel (&op2),
@ -303,7 +303,7 @@ color_operators (void)
clutter_color_subtract (&op1, &op2, &res);
g_assert_cmpuint (clutter_color_to_pixel (&res), ==, 0x00ff00ff);
if (g_test_verbose ())
if (!g_test_quiet ())
g_print ("Checking alpha channel on color subtract\n");
op1.alpha = 0xdd;

View File

@ -81,21 +81,21 @@ interval_from_script (void)
"test-script-interval.json",
NULL);
clutter_script_load_from_file (script, test_file, &error);
if (g_test_verbose () && error)
if (!g_test_quiet () && error)
g_printerr ("\tError: %s", error->message);
g_assert_no_error (error);
interval = CLUTTER_INTERVAL (clutter_script_get_object (script, "int-1"));
initial = clutter_interval_peek_initial_value (interval);
if (g_test_verbose ())
if (!g_test_quiet ())
g_test_message ("\tinitial ['%s'] = '%.2f'",
g_type_name (G_VALUE_TYPE (initial)),
g_value_get_float (initial));
g_assert (G_VALUE_HOLDS (initial, G_TYPE_FLOAT));
g_assert_cmpfloat (g_value_get_float (initial), ==, 23.3f);
final = clutter_interval_peek_final_value (interval);
if (g_test_verbose ())
if (!g_test_quiet ())
g_test_message ("\tfinal ['%s'] = '%.2f'",
g_type_name (G_VALUE_TYPE (final)),
g_value_get_float (final));

View File

@ -33,6 +33,10 @@ clutter_conform_tests_general_tests = [
'color',
'interval',
'script-parser',
'timeline',
'timeline-interpolate',
'timeline-progress',
'timeline-rewind',
'units',
]
@ -73,6 +77,7 @@ foreach test : clutter_conform_tests
test(test, test_executable,
suite: ['clutter', 'clutter/conform'],
env: test_env
env: test_env,
is_parallel: false,
)
endforeach

View File

@ -556,7 +556,7 @@ path_test_get_length (CallbackData *data)
if (!(fabs (approx_length - 46340.f) / 46340.f <= 0.15f))
{
if (g_test_verbose ())
if (!g_test_quiet ())
g_print ("M 0 0 L 46340 0 - Expected 46340, got %d instead.", approx_length);
return FALSE;
@ -567,7 +567,7 @@ path_test_get_length (CallbackData *data)
if (!(fabs (approx_length - 46341.f) / 46341.f <= 0.15f))
{
if (g_test_verbose ())
if (!g_test_quiet ())
g_print ("M 0 0 L 46341 0 - Expected 46341, got %d instead.", approx_length);
return FALSE;
@ -580,7 +580,7 @@ path_test_get_length (CallbackData *data)
/* Allow 15% margin of error */
if (!(fabs (approx_length - actual_length) / (float) actual_length <= 0.15f))
{
if (g_test_verbose ())
if (!g_test_quiet ())
g_print ("Expected %g, got %d instead.\n", actual_length, approx_length);
return FALSE;
@ -724,12 +724,12 @@ path_base (TestConformSimpleFixture *fixture,
{
gboolean succeeded;
if (g_test_verbose ())
if (!g_test_quiet ())
g_print ("%s... ", path_tests[i].desc);
succeeded = path_tests[i].func (&data) && compare_nodes (&data);
if (g_test_verbose ())
if (!g_test_quiet ())
g_print ("%s\n", succeeded ? "ok" : "FAIL");
g_assert (succeeded);

View File

@ -131,7 +131,7 @@ script_child (void)
test_file = g_test_build_filename (G_TEST_DIST, "scripts", "test-script-child.json", NULL);
clutter_script_load_from_file (script, test_file, &error);
if (g_test_verbose () && error)
if (!g_test_quiet () && error)
g_print ("Error: %s", error->message);
g_assert_no_error (error);
@ -177,7 +177,7 @@ script_single (void)
test_file = g_test_build_filename (G_TEST_DIST, "scripts", "test-script-single.json", NULL);
clutter_script_load_from_file (script, test_file, &error);
if (g_test_verbose () && error)
if (!g_test_quiet () && error)
g_print ("Error: %s", error->message);
g_assert_no_error (error);
@ -209,7 +209,7 @@ script_object_property (void)
test_file = g_test_build_filename (G_TEST_DIST, "scripts", "test-script-object-property.json", NULL);
clutter_script_load_from_file (script, test_file, &error);
if (g_test_verbose () && error)
if (!g_test_quiet () && error)
g_print ("Error: %s", error->message);
g_assert_no_error (error);
@ -235,7 +235,7 @@ script_named_object (void)
test_file = g_test_build_filename (G_TEST_DIST, "scripts", "test-script-named-object.json", NULL);
clutter_script_load_from_file (script, test_file, &error);
if (g_test_verbose () && error)
if (!g_test_quiet () && error)
g_print ("Error: %s", error->message);
g_assert_no_error (error);
@ -261,7 +261,7 @@ script_margin (void)
test_file = g_test_build_filename (G_TEST_DIST, "scripts", "test-script-margin.json", NULL);
clutter_script_load_from_file (script, test_file, &error);
if (g_test_verbose () && error)
if (!g_test_quiet () && error)
g_print ("Error: %s", error->message);
g_assert_no_error (error);

View File

@ -68,7 +68,7 @@ check_result (CallbackData *data, const char *note,
PangoRectangle test_extents;
gboolean fail = FALSE;
if (g_test_verbose ())
if (!g_test_quiet ())
g_print ("%s: ", note);
/* Force a redraw to get the on_paint handler to run */
@ -79,7 +79,7 @@ check_result (CallbackData *data, const char *note,
pango_layout_get_extents (data->test_layout, NULL, &test_extents);
if (memcmp (&test_extents, &data->label_extents, sizeof (PangoRectangle)))
{
if (g_test_verbose ())
if (!g_test_quiet ())
g_print ("extents are different: expected: %d, %d, %d, %d "
"-> text: %d, %d, %d, %d\n",
test_extents.x / 1024,
@ -95,18 +95,18 @@ check_result (CallbackData *data, const char *note,
}
else
{
if (g_test_verbose ())
if (!g_test_quiet ())
g_print ("extents are the same, ");
}
if (data->layout_changed)
{
if (g_test_verbose ())
if (!g_test_quiet ())
g_print ("layout changed, ");
}
else
{
if (g_test_verbose ())
if (!g_test_quiet ())
g_print ("layout did not change, ");
}
@ -115,14 +115,14 @@ check_result (CallbackData *data, const char *note,
if (fail)
{
if (g_test_verbose ())
if (!g_test_quiet ())
g_print ("FAIL\n");
data->test_failed = TRUE;
}
else
{
if (g_test_verbose ())
if (!g_test_quiet ())
g_print ("pass\n");
}
@ -283,10 +283,10 @@ text_cache (void)
clutter_actor_destroy (data.stage);
if (g_test_verbose ())
if (!g_test_quiet ())
g_print ("\nOverall result: ");
if (g_test_verbose ())
if (!g_test_quiet ())
{
if (data.test_failed)
g_print ("FAIL\n");

View File

@ -214,12 +214,12 @@ text_delete_chars (void)
for (j = 0; j < 4; j++)
clutter_text_insert_unichar (text, t->unichar);
if (g_test_verbose ())
if (!g_test_quiet ())
g_print ("text: %s\n", clutter_text_get_text (text));
clutter_text_set_cursor_position (text, 2);
clutter_text_delete_chars (text, 1);
if (g_test_verbose ())
if (!g_test_quiet ())
g_print ("text: %s (cursor at: %d)\n",
clutter_text_get_text (text),
clutter_text_get_cursor_position (text));
@ -229,7 +229,7 @@ text_delete_chars (void)
clutter_text_set_cursor_position (text, 2);
clutter_text_delete_chars (text, 1);
if (g_test_verbose ())
if (!g_test_quiet ())
g_print ("text: %s (cursor at: %d)\n",
clutter_text_get_text (text),
clutter_text_get_cursor_position (text));
@ -503,7 +503,7 @@ text_idempotent_use_markup (void)
int bar_end_index = bar_start_index + strlen ("bar");
/* case 1: text -> use_markup */
if (g_test_verbose ())
if (!g_test_quiet ())
g_print ("text: '%s' -> use-markup: TRUE\n", contents);
text = g_object_new (CLUTTER_TYPE_TEXT,
@ -511,7 +511,7 @@ text_idempotent_use_markup (void)
NULL);
g_object_ref_sink (text);
if (g_test_verbose ())
if (!g_test_quiet ())
g_print ("Contents: '%s' (expected: '%s')\n",
clutter_text_get_text (text),
display);
@ -526,14 +526,14 @@ text_idempotent_use_markup (void)
clutter_actor_destroy (CLUTTER_ACTOR (text));
/* case 2: use_markup -> text */
if (g_test_verbose ())
if (!g_test_quiet ())
g_print ("use-markup: TRUE -> text: '%s'\n", contents);
text = g_object_new (CLUTTER_TYPE_TEXT,
"use-markup", TRUE, "text", contents,
NULL);
if (g_test_verbose ())
if (!g_test_quiet ())
g_print ("Contents: '%s' (expected: '%s')\n",
clutter_text_get_text (text),
display);

View File

@ -116,24 +116,24 @@ validate_result (TestState *state)
{
int ypos = 0;
if (g_test_verbose ())
if (!g_test_quiet ())
g_print ("Testing onscreen clone...\n");
validate_part (state, SOURCE_SIZE, ypos * SOURCE_SIZE, 0);
ypos++;
#if 0 /* this doesn't work */
if (g_test_verbose ())
if (!g_test_quiet ())
g_print ("Testing offscreen clone...\n");
validate_part (state, SOURCE_SIZE, ypos * SOURCE_SIZE, 0);
#endif
ypos++;
if (g_test_verbose ())
if (!g_test_quiet ())
g_print ("Testing onscreen clone with rectangular clip...\n");
validate_part (state, SOURCE_SIZE, ypos * SOURCE_SIZE, ~1);
ypos++;
if (g_test_verbose ())
if (!g_test_quiet ())
g_print ("Testing onscreen clone with path clip...\n");
validate_part (state, SOURCE_SIZE, ypos * SOURCE_SIZE, 1);
ypos++;

View File

@ -1,8 +1,9 @@
#define CLUTTER_DISABLE_DEPRECATION_WARNINGS
#include <stdlib.h>
#include <glib.h>
#include <clutter/clutter.h>
#include "test-conform-common.h"
#include "tests/clutter-test-utils.h"
/* We ask for 1 frame per millisecond.
* Whenever this rate can't be achieved then the timeline
@ -12,8 +13,13 @@
#define TEST_TIMELINE_DURATION 5000
/* We are at the mercy of the system scheduler so this
* may not be a very reliable tolerance. */
#define TEST_ERROR_TOLERANCE 20
* may not be a very reliable tolerance.
*
* It's set as very tolerable (1 ms shorter than the frame interval) as
* otherwise CI, which are very prone to not get CPU time scheduled, tend to
* often fail.
*/
#define TEST_ERROR_TOLERANCE ((TEST_TIMELINE_FPS / 4) - 1)
typedef struct _TestState
{
@ -118,26 +124,23 @@ completed_cb (ClutterTimeline *timeline,
if (state->completion_count == 2)
{
if (state->passed)
{
g_test_message ("Passed\n");
clutter_main_quit ();
}
clutter_main_quit ();
else
{
g_test_message ("Failed\n");
exit (EXIT_FAILURE);
}
g_assert_not_reached ();
}
}
void
static void
timeline_interpolation (void)
{
ClutterActor *stage;
TestState state;
stage = clutter_test_get_stage ();
state.timeline =
clutter_timeline_new (TEST_TIMELINE_DURATION);
clutter_timeline_set_loop (state.timeline, TRUE);
clutter_timeline_set_repeat_count (state.timeline, -1);
g_signal_connect (G_OBJECT(state.timeline),
"new-frame",
G_CALLBACK(new_frame_cb),
@ -152,6 +155,8 @@ timeline_interpolation (void)
state.passed = TRUE;
state.expected_frame = 0;
clutter_actor_show (stage);
state.start_time = g_get_real_time ();
clutter_timeline_start (state.timeline);
@ -159,3 +164,7 @@ timeline_interpolation (void)
g_object_unref (state.timeline);
}
CLUTTER_TEST_SUITE (
CLUTTER_TEST_UNIT ("/timeline/interpolate", timeline_interpolation)
)

View File

@ -1,16 +1,17 @@
#define CLUTTER_DISABLE_DEPRECATION_WARNINGS
#include <glib.h>
#include <clutter/clutter.h>
#include "test-conform-common.h"
void
timeline_progress_step (TestConformSimpleFixture *fixture G_GNUC_UNUSED,
gconstpointer dummy G_GNUC_UNUSED)
#include "tests/clutter-test-utils.h"
static void
timeline_progress_step (void)
{
ClutterTimeline *timeline;
timeline = clutter_timeline_new (1000);
if (g_test_verbose ())
if (!g_test_quiet ())
g_print ("mode: step(3, end)\n");
clutter_timeline_rewind (timeline);
@ -45,7 +46,7 @@ timeline_progress_step (TestConformSimpleFixture *fixture G_GNUC_UNUSED,
clutter_timeline_advance (timeline, 1000);
g_assert_cmpfloat (clutter_timeline_get_progress (timeline), ==, 1.0);
if (g_test_verbose ())
if (!g_test_quiet ())
g_print ("mode: step-start\n");
clutter_timeline_rewind (timeline);
@ -64,7 +65,7 @@ timeline_progress_step (TestConformSimpleFixture *fixture G_GNUC_UNUSED,
clutter_timeline_advance (timeline, 1000);
g_assert_cmpfloat (clutter_timeline_get_progress (timeline), ==, 1.0);
if (g_test_verbose ())
if (!g_test_quiet ())
g_print ("mode: step-end\n");
clutter_timeline_rewind (timeline);
@ -86,9 +87,8 @@ timeline_progress_step (TestConformSimpleFixture *fixture G_GNUC_UNUSED,
g_object_unref (timeline);
}
void
timeline_progress_mode (TestConformSimpleFixture *fixture G_GNUC_UNUSED,
gconstpointer dummy G_GNUC_UNUSED)
static void
timeline_progress_mode (void)
{
ClutterTimeline *timeline;
@ -108,3 +108,8 @@ timeline_progress_mode (TestConformSimpleFixture *fixture G_GNUC_UNUSED,
g_object_unref (timeline);
}
CLUTTER_TEST_SUITE (
CLUTTER_TEST_UNIT ("/timeline/progress/step", timeline_progress_step);
CLUTTER_TEST_UNIT ("/timeline/progress/mode", timeline_progress_mode)
)

View File

@ -1,8 +1,9 @@
#define CLUTTER_DISABLE_DEPRECATION_WARNINGS
#include <stdlib.h>
#include <glib.h>
#include <clutter/clutter.h>
#include "test-conform-common.h"
#include "tests/clutter-test-utils.h"
#define TEST_TIMELINE_DURATION 500
#define TEST_WATCHDOG_KICK_IN_SECONDS 10
@ -66,11 +67,14 @@ new_frame_cb (ClutterTimeline *timeline,
}
}
void
static void
timeline_rewind (void)
{
ClutterActor *stage;
TestState state;
stage = clutter_test_get_stage ();
state.timeline =
clutter_timeline_new (TEST_TIMELINE_DURATION);
g_signal_connect (G_OBJECT(state.timeline),
@ -84,9 +88,15 @@ timeline_rewind (void)
&state);
state.rewind_count = 0;
clutter_actor_show (stage);
clutter_timeline_start (state.timeline);
clutter_main();
g_object_unref (state.timeline);
}
CLUTTER_TEST_SUITE (
CLUTTER_TEST_UNIT ("/timeline/rewind", timeline_rewind)
)

View File

@ -1,11 +1,12 @@
#define CLUTTER_DISABLE_DEPRECATION_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <clutter/clutter.h>
#include "test-conform-common.h"
#include "tests/clutter-test-utils.h"
/* This test runs three timelines at 30 fps with 10 frames. Some of
/* This test runs three timelines at 6 fps with 10 frames. Some of
the timelines have markers. Once the timelines are run it then
checks that all of the frames were hit, all of the markers were hit
and that the completed signal was fired. The timelines are then run
@ -15,7 +16,7 @@
for. */
#define FRAME_COUNT 10
#define FPS 30
#define FPS 6
typedef struct _TimelineData TimelineData;
@ -45,7 +46,7 @@ static void
timeline_complete_cb (ClutterTimeline *timeline,
TimelineData *data)
{
if (g_test_verbose ())
if (!g_test_quiet ())
g_print ("%i: Completed\n", data->timeline_num);
data->completed_count++;
@ -61,7 +62,7 @@ timeline_new_frame_cb (ClutterTimeline *timeline,
int frame_no = ((msec * FRAME_COUNT + (FRAME_COUNT * 1000 / FPS) / 2)
/ (FRAME_COUNT * 1000 / FPS));
if (g_test_verbose ())
if (!g_test_quiet ())
g_print ("%i: Doing frame %d, delta = %i\n",
data->timeline_num, frame_no,
clutter_timeline_get_delta (timeline));
@ -77,7 +78,7 @@ timeline_marker_reached_cb (ClutterTimeline *timeline,
guint frame_num,
TimelineData *data)
{
if (g_test_verbose ())
if (!g_test_quiet ())
g_print ("%i: Marker '%s' (%d) reached, delta = %i\n",
data->timeline_num, marker_name, frame_num,
clutter_timeline_get_delta (timeline));
@ -117,7 +118,7 @@ check_timeline (ClutterTimeline *timeline,
marker_reached_count[i]++;
else
{
if (g_test_verbose ())
if (!g_test_quiet ())
g_print ("FAIL: unknown marker '%s' hit for timeline %i\n",
(char *) node->data, data->timeline_num);
succeeded = FALSE;
@ -127,7 +128,7 @@ check_timeline (ClutterTimeline *timeline,
for (i = 0; i < n_markers; i++)
if (marker_reached_count[i] != 1)
{
if (g_test_verbose ())
if (!g_test_quiet ())
g_print ("FAIL: marker '%s' hit %i times for timeline %i\n",
markers[i], marker_reached_count[i], data->timeline_num);
succeeded = FALSE;
@ -141,7 +142,7 @@ check_timeline (ClutterTimeline *timeline,
if (missed_frame_count)
{
if (g_test_verbose ())
if (!g_test_quiet ())
g_print ("FAIL: missed %i frame%s for timeline %i\n",
missed_frame_count, missed_frame_count == 1 ? "" : "s",
data->timeline_num);
@ -151,7 +152,7 @@ check_timeline (ClutterTimeline *timeline,
if (data->completed_count != 1)
{
if (g_test_verbose ())
if (!g_test_quiet ())
g_print ("FAIL: timeline %i completed %i times\n",
data->timeline_num, data->completed_count);
succeeded = FALSE;
@ -180,10 +181,10 @@ delay_cb (gpointer data)
return TRUE;
}
void
timeline_base (TestConformSimpleFixture *fixture,
gconstpointer data)
static void
timeline_base (void)
{
ClutterActor *stage;
ClutterTimeline *timeline_1;
TimelineData data_1;
ClutterTimeline *timeline_2;
@ -194,9 +195,7 @@ timeline_base (TestConformSimpleFixture *fixture,
gsize n_markers;
guint delay_tag;
/* NB: We have to ensure a stage is instantiated else the master
* clock wont run... */
ClutterActor *stage = clutter_stage_new ();
stage = clutter_test_get_stage ();
timeline_data_init (&data_1, 1);
timeline_1 = clutter_timeline_new (FRAME_COUNT * 1000 / FPS);
@ -216,7 +215,7 @@ timeline_base (TestConformSimpleFixture *fixture,
g_strfreev (markers);
timeline_data_init (&data_2, 2);
timeline_2 = clutter_timeline_clone (timeline_1);
timeline_2 = clutter_timeline_new (FRAME_COUNT * 1000 / FPS);
clutter_timeline_add_marker_at_time (timeline_2, "bar", 2 * 1000 / FPS);
markers = clutter_timeline_list_markers (timeline_2, -1, &n_markers);
g_assert (markers != NULL);
@ -225,7 +224,7 @@ timeline_base (TestConformSimpleFixture *fixture,
g_strfreev (markers);
timeline_data_init (&data_3, 3);
timeline_3 = clutter_timeline_clone (timeline_1);
timeline_3 = clutter_timeline_new (FRAME_COUNT * 1000 / FPS);
clutter_timeline_set_direction (timeline_3, CLUTTER_TIMELINE_BACKWARD);
clutter_timeline_add_marker_at_time (timeline_3, "start-marker",
FRAME_COUNT * 1000 / FPS);
@ -267,7 +266,9 @@ timeline_base (TestConformSimpleFixture *fixture,
"completed", G_CALLBACK (timeline_complete_cb),
&data_3);
if (g_test_verbose ())
clutter_actor_show (stage);
if (!g_test_quiet ())
g_print ("Without delay...\n");
clutter_timeline_start (timeline_1);
@ -282,7 +283,7 @@ timeline_base (TestConformSimpleFixture *fixture,
g_assert (check_timeline (timeline_2, &data_2, TRUE));
g_assert (check_timeline (timeline_3, &data_3, TRUE));
if (g_test_verbose ())
if (!g_test_quiet ())
g_print ("With delay...\n");
timeline_data_destroy (&data_1);
@ -314,13 +315,10 @@ timeline_base (TestConformSimpleFixture *fixture,
timeline_data_destroy (&data_3);
g_clear_handle_id (&delay_tag, g_source_remove);
clutter_actor_destroy (stage);
}
void
timeline_markers_from_script (TestConformSimpleFixture *fixture,
gconstpointer data)
static void
timeline_markers_from_script (void)
{
ClutterScript *script = clutter_script_new ();
ClutterTimeline *timeline;
@ -329,9 +327,12 @@ timeline_markers_from_script (TestConformSimpleFixture *fixture,
gchar **markers;
gsize n_markers;
test_file = clutter_test_get_data_file ("test-script-timeline-markers.json");
test_file = g_test_build_filename (G_TEST_DIST,
"scripts",
"test-script-timeline-markers.json",
NULL);
clutter_script_load_from_file (script, test_file, &error);
if (g_test_verbose () && error != NULL)
if (!g_test_quiet () && error != NULL)
g_print ("Error: %s", error->message);
g_assert_no_error (error);
@ -351,11 +352,16 @@ timeline_markers_from_script (TestConformSimpleFixture *fixture,
markers = clutter_timeline_list_markers (timeline, 500, &n_markers);
g_assert_cmpint (n_markers, ==, 2);
g_assert (markers != NULL);
g_assert_cmpstr (markers[0], ==, "marker3");
g_assert_cmpstr (markers[1], ==, "marker1");
g_assert (g_strv_contains ((const char * const *) markers, "marker1"));
g_assert (g_strv_contains ((const char * const *) markers, "marker3"));
g_strfreev (markers);
g_object_unref (script);
g_free (test_file);
}
CLUTTER_TEST_SUITE (
CLUTTER_TEST_UNIT ("/timeline/base", timeline_base);
CLUTTER_TEST_UNIT ("/timeline/markers-from-script", timeline_markers_from_script)
)

View File

@ -410,7 +410,7 @@ test_cogl_tex_polygon_main (int argc, char *argv[])
/* Timeline for animation */
timeline = clutter_timeline_new (6000);
clutter_timeline_set_loop (timeline, TRUE);
clutter_timeline_set_repeat_count (timeline, -1);
g_signal_connect (timeline, "new-frame", G_CALLBACK (frame_cb), coglbox);
clutter_timeline_start (timeline);

View File

@ -216,7 +216,7 @@ test_cogl_tex_tile_main (int argc, char *argv[])
/* Timeline for animation */
timeline = clutter_timeline_new (6000); /* 6 second duration */
clutter_timeline_set_loop (timeline, TRUE);
clutter_timeline_set_repeat_count (timeline, -1);
g_signal_connect (timeline, "new-frame", G_CALLBACK (frame_cb), coglbox);
clutter_timeline_start (timeline);

View File

@ -123,6 +123,27 @@ headless_start_test = executable('mutter-headless-start-test',
install_dir: mutter_installed_tests_libexecdir,
)
stage_view_tests = executable('mutter-stage-view-tests',
sources: [
'meta-backend-test.c',
'meta-backend-test.h',
'meta-gpu-test.c',
'meta-gpu-test.h',
'meta-monitor-manager-test.c',
'meta-monitor-manager-test.h',
'monitor-test-utils.c',
'monitor-test-utils.h',
'stage-view-tests.c',
'test-utils.c',
'test-utils.h',
],
include_directories: tests_includepath,
c_args: tests_c_args,
dependencies: [tests_deps],
install: have_installed_tests,
install_dir: mutter_installed_tests_libexecdir,
)
stacking_tests = [
'basic-x11',
'basic-wayland',
@ -173,3 +194,10 @@ test('headless-start', headless_start_test,
is_parallel: false,
timeout: 60,
)
test('stage-view', stage_view_tests,
suite: ['core', 'mutter/unit'],
env: test_env,
is_parallel: false,
timeout: 60,
)

View File

@ -16,11 +16,11 @@ wait_reconfigure
assert_position x/1 100 100
tile x/1 left
wait
wait_reconfigure
assert_position x/1 0 0
untile x/1
wait
wait_reconfigure
assert_position x/1 100 100
tile x/1 left
@ -57,11 +57,11 @@ wait_reconfigure
assert_position w/1 0 0
untile w/1
wait
wait_reconfigure
assert_position w/1 100 100
tile w/1 left
wait
wait_reconfigure
assert_position w/1 0 0
maximize w/1

View File

@ -0,0 +1,504 @@
/*
* Copyright (C) 2020 Jonas Dreßler
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include "config.h"
#include "compositor/meta-plugin-manager.h"
#include "core/main-private.h"
#include "meta/main.h"
#include "tests/meta-backend-test.h"
#include "tests/monitor-test-utils.h"
#include "tests/test-utils.h"
#define FRAME_WARNING "Frame has assigned frame counter but no frame drawn time"
static gboolean
run_tests (gpointer data)
{
MetaBackend *backend = meta_get_backend ();
MetaSettings *settings = meta_backend_get_settings (backend);
gboolean ret;
g_test_log_set_fatal_handler (NULL, NULL);
meta_settings_override_experimental_features (settings);
meta_settings_enable_experimental_feature (
settings,
META_EXPERIMENTAL_FEATURE_SCALE_MONITOR_FRAMEBUFFER);
ret = g_test_run ();
meta_quit (ret != 0);
return G_SOURCE_REMOVE;
}
static gboolean
ignore_frame_counter_warning (const gchar *log_domain,
GLogLevelFlags log_level,
const gchar *message,
gpointer user_data)
{
if ((log_level & G_LOG_LEVEL_WARNING) &&
g_strcmp0 (log_domain, "mutter") == 0 &&
g_str_has_suffix (message, FRAME_WARNING))
return FALSE;
return TRUE;
}
static MonitorTestCaseSetup initial_test_case_setup = {
.modes = {
{
.width = 1024,
.height = 768,
.refresh_rate = 60.0
}
},
.n_modes = 1,
.outputs = {
{
.crtc = 0,
.modes = { 0 },
.n_modes = 1,
.preferred_mode = 0,
.possible_crtcs = { 0 },
.n_possible_crtcs = 1,
.width_mm = 222,
.height_mm = 125
},
{
.crtc = 1,
.modes = { 0 },
.n_modes = 1,
.preferred_mode = 0,
.possible_crtcs = { 1 },
.n_possible_crtcs = 1,
.width_mm = 220,
.height_mm = 124
}
},
.n_outputs = 2,
.crtcs = {
{
.current_mode = 0
},
{
.current_mode = 0
}
},
.n_crtcs = 2
};
static void
meta_test_stage_views_exist (void)
{
MetaBackend *backend = meta_get_backend ();
ClutterActor *stage;
GList *stage_views;
stage = meta_backend_get_stage (backend);
g_assert_cmpint (clutter_actor_get_width (stage), ==, 1024 * 2);
g_assert_cmpint (clutter_actor_get_height (stage), ==, 768);
stage_views = clutter_stage_peek_stage_views (CLUTTER_STAGE (stage));
g_assert_cmpint (g_list_length (stage_views), ==, 2);
}
static void
on_after_paint (ClutterStage *stage,
gboolean *was_painted)
{
*was_painted = TRUE;
}
static void
wait_for_paint (ClutterActor *stage)
{
gboolean was_painted = FALSE;
gulong was_painted_id;
was_painted_id = g_signal_connect (CLUTTER_STAGE (stage),
"after-paint",
G_CALLBACK (on_after_paint),
&was_painted);
while (!was_painted)
g_main_context_iteration (NULL, FALSE);
g_signal_handler_disconnect (stage, was_painted_id);
}
static void
on_stage_views_changed (ClutterActor *actor,
gboolean *stage_views_changed)
{
*stage_views_changed = TRUE;
}
static void
is_on_stage_views (ClutterActor *actor,
unsigned int n_views,
...)
{
va_list valist;
int i = 0;
GList *stage_views = clutter_actor_peek_stage_views (actor);
va_start (valist, n_views);
for (i = 0; i < n_views; i++)
{
ClutterStageView *view = va_arg (valist, ClutterStageView*);
g_assert_nonnull (g_list_find (stage_views, view));
}
va_end (valist);
g_assert (g_list_length (stage_views) == n_views);
}
static void
meta_test_actor_stage_views (void)
{
MetaBackend *backend = meta_get_backend ();
ClutterActor *stage, *container, *test_actor;
GList *stage_views;
gboolean stage_views_changed_container = FALSE;
gboolean stage_views_changed_test_actor = FALSE;
gboolean *stage_views_changed_container_ptr =
&stage_views_changed_container;
gboolean *stage_views_changed_test_actor_ptr =
&stage_views_changed_test_actor;
stage = meta_backend_get_stage (backend);
stage_views = clutter_stage_peek_stage_views (CLUTTER_STAGE (stage));
container = clutter_actor_new ();
clutter_actor_set_size (container, 100, 100);
clutter_actor_add_child (stage, container);
test_actor = clutter_actor_new ();
clutter_actor_set_size (test_actor, 50, 50);
clutter_actor_add_child (container, test_actor);
g_signal_connect (container, "stage-views-changed",
G_CALLBACK (on_stage_views_changed),
stage_views_changed_container_ptr);
g_signal_connect (test_actor, "stage-views-changed",
G_CALLBACK (on_stage_views_changed),
stage_views_changed_test_actor_ptr);
clutter_actor_show (stage);
wait_for_paint (stage);
is_on_stage_views (container, 1, stage_views->data);
is_on_stage_views (test_actor, 1, stage_views->data);
/* The signal was emitted for the initial change */
g_assert (stage_views_changed_container);
g_assert (stage_views_changed_test_actor);
stage_views_changed_container = FALSE;
stage_views_changed_test_actor = FALSE;
/* Move the container to the second stage view */
clutter_actor_set_x (container, 1040);
wait_for_paint (stage);
is_on_stage_views (container, 1, stage_views->next->data);
is_on_stage_views (test_actor, 1, stage_views->next->data);
/* The signal was emitted again */
g_assert (stage_views_changed_container);
g_assert (stage_views_changed_test_actor);
stage_views_changed_container = FALSE;
stage_views_changed_test_actor = FALSE;
/* Move the container so it's on both stage views while the test_actor
* is only on the first one.
*/
clutter_actor_set_x (container, 940);
wait_for_paint (stage);
is_on_stage_views (container, 2, stage_views->data, stage_views->next->data);
is_on_stage_views (test_actor, 1, stage_views->data);
/* The signal was emitted again */
g_assert (stage_views_changed_container);
g_assert (stage_views_changed_test_actor);
g_signal_handlers_disconnect_by_func (container, on_stage_views_changed,
stage_views_changed_container_ptr);
g_signal_handlers_disconnect_by_func (test_actor, on_stage_views_changed,
stage_views_changed_test_actor_ptr);
clutter_actor_destroy (container);
}
static void
meta_test_actor_stage_views_reparent (void)
{
MetaBackend *backend = meta_get_backend ();
ClutterActor *stage, *container, *test_actor;
GList *stage_views;
gboolean stage_views_changed_container = FALSE;
gboolean stage_views_changed_test_actor = FALSE;
gboolean *stage_views_changed_container_ptr =
&stage_views_changed_container;
gboolean *stage_views_changed_test_actor_ptr =
&stage_views_changed_test_actor;
stage = meta_backend_get_stage (backend);
stage_views = clutter_stage_peek_stage_views (CLUTTER_STAGE (stage));
container = clutter_actor_new ();
clutter_actor_set_size (container, 100, 100);
clutter_actor_set_x (container, 1020);
clutter_actor_add_child (stage, container);
test_actor = clutter_actor_new ();
clutter_actor_set_size (test_actor, 20, 20);
clutter_actor_add_child (container, test_actor);
g_signal_connect (container, "stage-views-changed",
G_CALLBACK (on_stage_views_changed),
stage_views_changed_container_ptr);
g_signal_connect (test_actor, "stage-views-changed",
G_CALLBACK (on_stage_views_changed),
stage_views_changed_test_actor_ptr);
clutter_actor_show (stage);
wait_for_paint (stage);
is_on_stage_views (container, 2, stage_views->data, stage_views->next->data);
is_on_stage_views (test_actor, 2, stage_views->data, stage_views->next->data);
/* The signal was emitted for both actors */
g_assert (stage_views_changed_container);
g_assert (stage_views_changed_test_actor);
stage_views_changed_container = FALSE;
stage_views_changed_test_actor = FALSE;
/* Remove the test_actor from the scene-graph */
g_object_ref (test_actor);
clutter_actor_remove_child (container, test_actor);
/* While the test_actor is not on stage, it must be on no stage views */
is_on_stage_views (test_actor, 0);
/* When the test_actor left the stage, the signal was emitted */
g_assert (!stage_views_changed_container);
g_assert (stage_views_changed_test_actor);
stage_views_changed_test_actor = FALSE;
/* Add the test_actor again as a child of the stage */
clutter_actor_add_child (stage, test_actor);
g_object_unref (test_actor);
wait_for_paint (stage);
/* The container is still on both stage views... */
is_on_stage_views (container, 2, stage_views->data, stage_views->next->data);
/* ...while the test_actor is only on the first one now */
is_on_stage_views (test_actor, 1, stage_views->data);
/* The signal was emitted for the test_actor again */
g_assert (!stage_views_changed_container);
g_assert (stage_views_changed_test_actor);
stage_views_changed_test_actor = FALSE;
/* Move the container out of the stage... */
clutter_actor_set_y (container, 2000);
g_object_ref (test_actor);
clutter_actor_remove_child (stage, test_actor);
/* When the test_actor left the stage, the signal was emitted */
g_assert (!stage_views_changed_container);
g_assert (stage_views_changed_test_actor);
stage_views_changed_test_actor = FALSE;
/* ...and reparent the test_actor to the container again */
clutter_actor_add_child (container, test_actor);
g_object_unref (test_actor);
wait_for_paint (stage);
/* Now both actors are on no stage views */
is_on_stage_views (container, 0);
is_on_stage_views (test_actor, 0);
/* The signal was emitted only for the container, the test_actor already
* has no stage-views.
*/
g_assert (stage_views_changed_container);
g_assert (!stage_views_changed_test_actor);
g_signal_handlers_disconnect_by_func (container, on_stage_views_changed,
stage_views_changed_container_ptr);
g_signal_handlers_disconnect_by_func (test_actor, on_stage_views_changed,
stage_views_changed_test_actor_ptr);
clutter_actor_destroy (container);
}
static void
meta_test_actor_stage_views_hide_parent (void)
{
MetaBackend *backend = meta_get_backend ();
ClutterActor *stage, *outer_container, *inner_container, *test_actor;
GList *stage_views;
gboolean stage_views_changed_outer_container = FALSE;
gboolean stage_views_changed_inner_container = FALSE;
gboolean stage_views_changed_test_actor = FALSE;
gboolean *stage_views_changed_outer_container_ptr =
&stage_views_changed_outer_container;
gboolean *stage_views_changed_inner_container_ptr =
&stage_views_changed_inner_container;
gboolean *stage_views_changed_test_actor_ptr =
&stage_views_changed_test_actor;
stage = meta_backend_get_stage (backend);
stage_views = clutter_stage_peek_stage_views (CLUTTER_STAGE (stage));
outer_container = clutter_actor_new ();
clutter_actor_add_child (stage, outer_container);
inner_container = clutter_actor_new ();
clutter_actor_add_child (outer_container, inner_container);
test_actor = clutter_actor_new ();
clutter_actor_set_size (test_actor, 20, 20);
clutter_actor_add_child (inner_container, test_actor);
g_signal_connect (outer_container, "stage-views-changed",
G_CALLBACK (on_stage_views_changed),
stage_views_changed_outer_container_ptr);
g_signal_connect (inner_container, "stage-views-changed",
G_CALLBACK (on_stage_views_changed),
stage_views_changed_inner_container_ptr);
g_signal_connect (test_actor, "stage-views-changed",
G_CALLBACK (on_stage_views_changed),
stage_views_changed_test_actor_ptr);
clutter_actor_show (stage);
wait_for_paint (stage);
/* The containers and the test_actor are on all on the first view */
is_on_stage_views (outer_container, 1, stage_views->data);
is_on_stage_views (inner_container, 1, stage_views->data);
is_on_stage_views (test_actor, 1, stage_views->data);
/* The signal was emitted for all three */
g_assert (stage_views_changed_outer_container);
g_assert (stage_views_changed_inner_container);
g_assert (stage_views_changed_test_actor);
stage_views_changed_outer_container = FALSE;
stage_views_changed_inner_container = FALSE;
stage_views_changed_test_actor = FALSE;
/* Hide the inner_container */
clutter_actor_hide (inner_container);
/* Move the outer_container so it's still on the first view */
clutter_actor_set_x (outer_container, 1023);
wait_for_paint (stage);
/* The outer_container is still expanded so it should be on both views */
is_on_stage_views (outer_container, 2,
stage_views->data, stage_views->next->data);
/* The inner_container and test_actor aren't updated because they're hidden */
is_on_stage_views (inner_container, 1, stage_views->data);
is_on_stage_views (test_actor, 1, stage_views->data);
/* The signal was emitted for the outer_container */
g_assert (stage_views_changed_outer_container);
g_assert (!stage_views_changed_inner_container);
g_assert (!stage_views_changed_test_actor);
stage_views_changed_outer_container = FALSE;
/* Show the inner_container again */
clutter_actor_show (inner_container);
wait_for_paint (stage);
/* All actors are on both views now */
is_on_stage_views (outer_container, 2,
stage_views->data, stage_views->next->data);
is_on_stage_views (inner_container, 2,
stage_views->data, stage_views->next->data);
is_on_stage_views (test_actor, 2,
stage_views->data, stage_views->next->data);
/* The signal was emitted for the inner_container and test_actor */
g_assert (!stage_views_changed_outer_container);
g_assert (stage_views_changed_inner_container);
g_assert (stage_views_changed_test_actor);
g_signal_handlers_disconnect_by_func (outer_container, on_stage_views_changed,
stage_views_changed_outer_container_ptr);
g_signal_handlers_disconnect_by_func (inner_container, on_stage_views_changed,
stage_views_changed_inner_container_ptr);
g_signal_handlers_disconnect_by_func (test_actor, on_stage_views_changed,
stage_views_changed_test_actor_ptr);
clutter_actor_destroy (outer_container);
}
static void
init_tests (int argc, char **argv)
{
MetaMonitorTestSetup *test_setup;
test_setup = create_monitor_test_setup (&initial_test_case_setup,
MONITOR_TEST_FLAG_NO_STORED);
meta_monitor_manager_test_init_test_setup (test_setup);
g_test_add_func ("/stage-view/stage-views-exist",
meta_test_stage_views_exist);
g_test_add_func ("/stage-views/actor-stage-views",
meta_test_actor_stage_views);
g_test_add_func ("/stage-views/actor-stage-views-reparent",
meta_test_actor_stage_views_reparent);
g_test_add_func ("/stage-views/actor-stage-views-hide-parent",
meta_test_actor_stage_views_hide_parent);
}
int
main (int argc, char *argv[])
{
test_init (&argc, &argv);
init_tests (argc, argv);
meta_plugin_manager_load (test_get_plugin_name ());
meta_override_compositor_configuration (META_COMPOSITOR_TYPE_WAYLAND,
META_TYPE_BACKEND_TEST);
meta_init ();
meta_register_with_session ();
g_test_log_set_fatal_handler (ignore_frame_counter_warning, NULL);
g_idle_add (run_tests, NULL);
return meta_run ();
}

View File

@ -858,6 +858,8 @@ int
main(int argc, char **argv)
{
GOptionContext *context = g_option_context_new (NULL);
GdkScreen *screen;
GtkCssProvider *provider;
GError *error = NULL;
g_option_context_add_main_entries (context, options, NULL);
@ -876,31 +878,25 @@ main(int argc, char **argv)
gtk_init (NULL, NULL);
if (!wayland)
screen = gdk_screen_get_default ();
provider = gtk_css_provider_new ();
static const char *no_decoration_css =
"decoration {"
" border-radius: 0 0 0 0;"
" border-width: 0;"
" box-shadow: 0 0 0 0 rgba(0, 0, 0, 0), 0 0 0 0 rgba(0, 0, 0, 0);"
" margin: 0px;"
"}";
if (!gtk_css_provider_load_from_data (provider,
no_decoration_css,
strlen (no_decoration_css),
&error))
{
GdkScreen *screen;
GtkCssProvider *provider;
screen = gdk_screen_get_default ();
provider = gtk_css_provider_new ();
static const char *no_decoration_css =
"decoration {"
" border-radius: 0 0 0 0;"
" border-width: 0;"
" box-shadow: 0 0 0 0 rgba(0, 0, 0, 0), 0 0 0 0 rgba(0, 0, 0, 0);"
" margin: 0px;"
"}";
if (!gtk_css_provider_load_from_data (provider,
no_decoration_css,
strlen (no_decoration_css),
&error))
{
g_printerr ("%s", error->message);
return 1;
}
gtk_style_context_add_provider_for_screen (screen, GTK_STYLE_PROVIDER (provider),
GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
g_printerr ("%s", error->message);
return 1;
}
gtk_style_context_add_provider_for_screen (screen, GTK_STYLE_PROVIDER (provider),
GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
windows = g_hash_table_new_full (g_str_hash, g_str_equal,
g_free, NULL);

View File

@ -572,6 +572,9 @@ test_case_do (TestCase *test,
if (!test_client_do (client, error, argv[0], window_id, NULL))
return FALSE;
if (!test_case_wait (test, error))
return FALSE;
MetaWindow *window = test_client_find_window (client, window_id, error);
if (!window)
return FALSE;

View File

@ -94,7 +94,7 @@ static struct wl_resource *
create_and_send_dnd_offer (MetaWaylandDataSource *source,
struct wl_resource *target)
{
MetaWaylandDataOffer *offer = g_slice_new0 (MetaWaylandDataOffer);
MetaWaylandDataOffer *offer;
struct wl_array *mime_types;
struct wl_resource *resource;
char **p;

View File

@ -51,6 +51,7 @@ transfer_cb (MetaSelection *selection,
}
g_output_stream_close (stream, NULL, NULL);
g_object_unref (stream);
}
static void

View File

@ -51,6 +51,7 @@ transfer_cb (MetaSelection *selection,
}
g_output_stream_close (stream, NULL, NULL);
g_object_unref (stream);
}
static void

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