Compare commits

..

36 Commits

Author SHA1 Message Date
Jonas Ådahl
9b2ee14eb1 tests/stacking: Add test checking the initial size
https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1171
2020-04-15 15:59:13 +02:00
Jonas Ådahl
0a8286e008 tests/stacking: Add test for checking restored positions
Going maximized -> unmaximized should restore the previous position. The
same for untiling, or going from tiled, to maximized, to floating.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1171
2020-04-15 15:59:13 +02:00
Jonas Ådahl
42fecdb60b tests/test-runner: Add 'move' and 'assert_position'
Make it possible for tests to move the windows, and check their
positions.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1171
2020-04-15 15:59:13 +02:00
Jonas Ådahl
f84ec95d2f tests/restore-size: Also test that untiling restores correctly
Tiling, then untiling should restore to the size prior to tiling.

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

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1171
2020-04-15 15:59:13 +02:00
Jonas Ådahl
4b4cf96de1 tests/test-runner: Add tile and untile commands
This allows test cases to tile windows to the right or left, and untile,
just as the keyboard shortcuts does.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1171
2020-04-15 15:59:13 +02:00
Jonas Ådahl
c413dd9078 window: Set fall-back tile monitor if not set
When tiling, we want to set the tile monitor. To not have to do this
from the call site, make meta_window_tile() fall back to the current
monitor if nothing set it prior to the call.

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

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1171
2020-04-15 15:59:13 +02:00
Jonas Ådahl
95f3fe7bd5 window: Add meta_window_untile()
It does the same as the untile keyboard shortcut does, i.e. handles
going back to saved maximized state. It's split out to be able to be
tested by the stacking tests.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1171
2020-04-15 15:59:13 +02:00
Jonas Ådahl
443dd146e1 tests/stacking: Test some maximize fullscreen interaction
https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1171
2020-04-15 15:59:13 +02:00
Jonas Ådahl
2d982b678e tests/test-client: Add 'fullscreen' and 'unfullscreen' commands
This needs some hand holding when calculating the "full" size of the
window, as the titlebar isn't actually shown.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1171
2020-04-15 15:59:13 +02:00
Jonas Ådahl
7cf61a392d tests/stacking: Check that unmaximize to new size works
A client that set a new fallback size while being maximized should not
restore to the one prior to being maximized.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1171
2020-04-15 15:59:12 +02:00
Jonas Ådahl
e190efb7af tests/stacking: Add test to verify we unmaximize correctly
The test tests that (for both X11 and Wayland) that:

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

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

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1171
2020-04-15 15:59:12 +02:00
Jonas Ådahl
b98ce96d09 tests/test-runner: Add 'assert_size' command
The 'assert_size' command checks that the size of the window, both
client side and compositor side, corresponds to an expected size set by
the test case.

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

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

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

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

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1171
2020-04-15 15:59:12 +02:00
Jonas Ådahl
d812cecc44 tests/test-client: Make 'resize' client command include the titlebar
To get some kind of consistency between what 'resize' means for the
compositor and the client, make the size correspond to the "frame rect"
of the window, i.e. the window geometry in the Wayland case, and the
window size including the titlebar in the X11 case.

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

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

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

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1171
2020-04-15 15:59:12 +02:00
Jonas Ådahl
92b1359d04 tests/test-runner: Plumb "resize" command
The test client could already understand the resize command, but they
could not be added to metatests as the command was not properly plumbed
via the test runner. Establish the plumbing for the resize command so
that resize tests can be added.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1171
2020-04-15 15:59:12 +02:00
Jonas Ådahl
c25fa19208 tests/test-client: Add commands to maximize/unmaximize
https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1171
2020-04-15 15:59:12 +02:00
Phillip Wood
ad500ef4e5 input-settings: fix device list iteration
Dereference the loop variable rather than the original list head. This
fixes a regression introduced in 4413b86a3 ("backends: Replace
ClutterDeviceManager usage in favor of ClutterSeat", 2019-10-04) which
broke button scrolling with trackballs.

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

(cherry picked from commit 3e967d731a)
2020-04-12 23:43:01 +02:00
Olivier Fourdan
9a2471db47 wayland: preserve xkb_state on VT switch
On VT switch, the devices are removed, which means for Wayland disabling
the keyboard.

When the keyboard is disabled, the associated `xkb_state` is freed and
recreated whenever the keyboard is re-enabled when switching back to the
compositor VT.

That means the `xkb_state` for Wayland is lost whereas the same for
clutter is kept, which causes to a discrepancy with locked modifiers on
VT switch.

To avoid that issue, preserve the XKB info only to dispose it when the
keyboard is eventually finalized.

Closes: https://gitlab.gnome.org/GNOME/mutter/issues/344
https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1185


(cherry picked from commit 5b30a52bbd)
2020-04-08 14:04:02 +00:00
Carlos Garnacho
db164bcfa2 wayland/xdnd: Add error traps around Xdnd* IPC
Make all of them spew criticals, except for XdndLeave as it's feasible
to expect the window we are sending the event to did disappear in the
way (eg. if the window is destroyed while the DnD operation is ongoing
and the pointer is over the window).

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

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1184
2020-04-07 20:38:02 +02:00
Jonas Troeger
83553e3f6e backends/native: Translate coordinates of absolute motion events
The motion events of tablets for example need to be mapped on the
selected screen area if the input device is configured to use only a
part of the active logical monitor.
To achieve this behavior each motion event is transformed using the
transformation matrix set for the input device.

Closes: https://gitlab.gnome.org/GNOME/mutter/-/issues/1118
2020-04-07 20:37:53 +02:00
Carlos Garnacho
3b2f6ae93d backends/x11: Fix access to WacomDevice
At some point we crossed the streams... In a short timespan we had
1f00aba92c merged, pushing WacomDevice to a common parent object,
and dcaa45fc0c implementing device grouping for X11.

The latter did not rely on the former, and just happened to
merge/compile without issues, but would promptly trigger a crash
whenever the API would be used.

Drop all traces of the WacomDevice internal to MetaInputDeviceX11.

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


(cherry picked from commit f0718c7d95)
2020-04-07 17:48:09 +00:00
Jonas Dreßler
bc47f0a1ac clutter/stage: Don't assume stage relayouts reallocate everything
With the introduction of "shallow" relayouts, we are now able to enter
allocation cycles not only at the stage but also deeper down the
hierarchy if we know an actors allocation isn't affected by its children
since the NO_LAYOUT flag is set.

Now that means when queuing relayouts it's possible that
`priv->needs_allocation` gets set to TRUE for some actors down the
hierarchy, but not for actors higher up in the hierarchy. An actor tree
where that happens could look like that:

stage -> container -> container2 (NO_LAYOUT) -> textActor

With that tree, if the "textActor" queues a relayout, "container2" will
be added to the relayout hashtable of the stage and the actors "stage"
and "container" will have `priv->needs_allocation` set to FALSE.

Now if another relayout on the stage actor is queued,
`clutter_stage_queue_actor_relayout()` currently removes all the other
hashtable entries in favour of the stage entry, (wrongly) assuming that
will allocate everything. It doesn't allocate everything because in the
example above "container" has `priv->needs_allocation` set to FALSE,
which makes clutter_actor_allocate() return early before allocating its
children, so in the end "container2" will never get a new allocation.

To fix this, stop flushing the relayout hashtable when queuing a
stage-relayout and still add new entries to the hashtable if a stage
relayout is already queued to make sure we still go through all the
previously queued "shallow" relayouts. That shouldn't hurt performance,
too, because as soon as an actor got allocated once, it doesn't need an
allocation anymore and should bail out in clutter_actor_allocate() as
long as it's absolute position didn't change.

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

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


(cherry picked from commit e74c2e42cf)
2020-04-07 16:47:32 +00:00
Jonas Ådahl
c8986d19e5 window: Check aliveness a bit less aggressively
Currently we check whether a window is alive everytime it's focused.
This means that an application that doesn't respond to the check-alive
event during startup always showing the "application froze" dialog,
without the user ever trying to interact with it.

An example where this tends to to happen is with games, and for this
particular scenario, it's purely an annoyance, as I never tried to
interact with the game window in the first place, so I don't care that
it's not responding - it's loading.

To avoid these unnecessary particular "app-is-frozen" popups, remove the
alive check from the focus function, and instead move it back to the
"meta_window_activate_full()" call. To also trigger it slightly more
often, also add it to the path that triggers the window focus when a
user actively clicks on the window.

This means that we currently check whether a window is alive on:

  * Any time the window is activated. This means e.g. alt-tab or
    selecting the window in the overview.
  * The user clicks on the window.

Note that the second only works for an already focused window on
Wayland, as on X11, we don't refocus it. This particular case isn't
changed with this commit, as we didn't call meta_window_focus() to begin
with here.

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


(cherry picked from commit 8df3b21a51)
2020-04-07 13:23:21 +00:00
Christian Rauch
7baabc7ed0 x11: fix compilation if 'libwacom=false'
https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1168


(cherry picked from commit a8f6cada88)
2020-04-06 14:57:57 +00:00
Dušan Kazik
b0709504ea Update Slovak translation 2020-04-05 20:22:08 +00:00
Jonas Ådahl
7e94311e2e window-actor: Set viewport when blitting to screencast fb
This fixes an issue where a non-maximized screen casted window would be
stretched to fill the whole screen cast stream, instead of just the crop
that corresponds to the current window size.

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


(cherry picked from commit a6f94696e2)
2020-04-03 16:30:26 +00:00
Simon McVittie
e339a57ddf cogl: Defend against empty or unallocated framebuffers
It isn't immediately obvious that this is impossible, because there's some
"action at a distance" going on with framebuffers that have their size
set lazily, after their textures get allocated; so let's make this a
critical warning rather than crashing.

In particular, this works around a crash when gnome-shell tries to blur a
background that hasn't yet had any space allocated for it - which it seems
is really an actor layout bug, but more robustness seems good to have.

Workaround for <https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/2538>.

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

Signed-off-by: Simon McVittie <smcv@debian.org>

(cherry picked from commit c389aadff9)
2020-04-03 13:49:34 +02:00
Simon McVittie
e3b2b90c72 cogl: Don't allow creating sized textures with 0 pixels
A texture with no pixels isn't a useful thing to have, and breaks
assumptions elsewhere. For example, CoglFramebuffer assumes that after
a texture has been allocated, it will have width and height both greater
than 0.

In particular, this works around a crash when gnome-shell tries to blur a
background that hasn't yet had any space allocated for it - which it seems
is really an actor layout bug, but more robustness seems good to have.

Workaround for <https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/2538>.

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

Signed-off-by: Simon McVittie <smcv@debian.org>

(cherry picked from commit 37eda498f2)
2020-04-03 13:48:46 +02:00
Daniel van Vugt
6f094bd399 clutter/master-clock-default: Sync timelines to hardware vsync
Previously clutter timelines advanced according to `g_source_get_time`.
But that meant the spatial stepping of animations was visibly sensitive to
any irregularities in the main loop. It also represented a time older [1]
than the intended presentation time of each frame.

Now we instead use `master_clock_get_next_presentation_time`. This ensures
we get the smoothness of hardware vsync as well as being closer to the
actual presentation time.

This means, for example, backends like Xorg that move the hardware cursor
independently of repaints will have their animations more closely matching
the hardware cursor position. So the cursor appears to stick more closely
when dragging windows or on the lock screen etc.

[1] "older" = (refresh_interval - sync_delay) = ~14ms for 60Hz

Closes: https://gitlab.gnome.org/GNOME/mutter/issues/25

https://gitlab.gnome.org/GNOME/mutter/merge_requests/724
2020-04-03 10:59:36 +00:00
Daniel van Vugt
2c805524b4 clutter/stage: Add API to get_next_presentation_time
https://gitlab.gnome.org/GNOME/mutter/merge_requests/724
2020-04-03 10:59:36 +00:00
Andre Moreira Magalhaes
95c1baf3d1 clutter/click-action: Do not process captured event if action is disabled
Disabling a click action after a button-press but before a
button-release is captured makes ClutterClickAction connect to
captured-event and never disconnect.

This change fixes it by making sure the captured-event is only
processed if the action is still enabled, otherwise releasing
the action (reset state) and propagating the event.

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


(cherry picked from commit 5f5ce08ba4)
2020-04-02 17:09:24 +00:00
Georges Basile Stavracas Neto
6f9b5edd4d tests/actor-pick: Allocate actor before picking
Picking now only happens on allocated actors, but the
callback in the actor-pick test is not waiting for the
stage to run an allocation cycle. Ideally, we'd wait
for this cycle, but for now, forcing an allocation works
as well.

Allocate the overlay actor in the actor-pick test.

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


(cherry picked from commit 7f488e3e1d)
2020-03-31 23:13:42 +00:00
Georges Basile Stavracas Neto
31809e1214 tests/actor-pick: Remove tabs
They're evil.

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


(cherry picked from commit 059d2144b2)
2020-03-31 23:13:15 +00:00
Andre Moreira Magalhaes
82f3bdd14e clutter/actor: Fix pick when actor is not allocated
When selecting the pick regions for an actor we were not considering
whether the actor was allocated and that was causing issues where the
preferred width/height of the actor was used when deciding whether
the actor should be considered as a pick target.

Check if the actor has a valid allocation, in addition to being mapped
and being in pick mode, in clutter_actor_should_pick_paint().

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


(cherry picked from commit 902302a174)
2020-03-31 23:12:44 +00:00
475 changed files with 30522 additions and 17569 deletions

View File

@@ -1,10 +1,9 @@
image: registry.gitlab.gnome.org/gnome/mutter/master:v4
image: registry.gitlab.gnome.org/gnome/mutter/master:v3
stages:
- review
- build
- test
- coverage
check-commit-log:
stage: review
@@ -18,7 +17,7 @@ check-commit-log:
build-mutter:
stage: build
script:
- meson . build -Dbuildtype=debugoptimized -Db_coverage=true -Degl_device=true -Dwayland_eglstream=true --werror --prefix /usr
- meson . build -Dbuildtype=debugoptimized -Degl_device=true -Dwayland_eglstream=true --werror --prefix /usr
- ninja -C build
- ninja -C build install
artifacts:
@@ -36,8 +35,9 @@ build-without-opengl-and-glx:
- ninja -C build
- ninja -C build install
artifacts:
expire_in: 1 day
paths:
- build/meson-logs
- build
only:
- merge_requests
- /^.*$/
@@ -49,8 +49,9 @@ build-without-native-backend-and-wayland:
- ninja -C build
- ninja -C build install
artifacts:
expire_in: 1 day
paths:
- build/meson-logs
- build
only:
- merge_requests
- /^.*$/
@@ -65,6 +66,7 @@ test-mutter:
G_SLICE: "always-malloc"
MALLOC_CHECK_: "3"
NO_AT_BRIDGE: "1"
MALLOC_PERTURB_: "123"
script:
- dconf update
- mkdir -m 700 $XDG_RUNTIME_DIR
@@ -72,30 +74,10 @@ test-mutter:
- >
dbus-run-session -- xvfb-run -s '+iglx -noreset'
meson test -C build --no-rebuild -t 10 --verbose --no-stdsplit --print-errorlogs --wrap catchsegv
artifacts:
expire_in: 1 day
paths:
- build
only:
- merge_requests
- /^.*$/
test-mutter-coverage:
stage: coverage
dependencies:
- test-mutter
script:
- ninja -C build coverage
- cat build/meson-logs/coverage.txt
artifacts:
paths:
- build/meson-logs
when: manual
except:
refs:
- tags
- master
can-build-gnome-shell:
stage: test
dependencies:

View File

@@ -1,27 +1,32 @@
# Rebuild and push with
#
# cd .gitlab-ci/
# podman build --format docker --no-cache -t registry.gitlab.gnome.org/gnome/mutter/master:v4 .
# podman push registry.gitlab.gnome.org/gnome/mutter/master:v4
# podman build --format docker --no-cache -t registry.gitlab.gnome.org/gnome/mutter/master:v3 .
# podman push registry.gitlab.gnome.org/gnome/mutter/master:v3
#
FROM fedora:32
FROM fedora:31
RUN dnf -y update && dnf -y upgrade && \
dnf install -y 'dnf-command(builddep)' && \
dnf install -y 'dnf-command(copr)' && \
dnf copr enable -y fmuellner/gnome-shell-ci && \
dnf copr enable -y jadahl/mutter-ci && \
dnf -y update && dnf -y upgrade && \
dnf builddep -y mutter --setopt=install_weak_deps=False && \
dnf builddep -y mutter && \
# Until Fedora catches up with new build-deps
dnf install -y 'pkgconfig(graphene-gobject-1.0)' 'pkgconfig(sysprof-capture-3)' && \
# For running unit tests
dnf install -y xorg-x11-server-Xvfb mesa-dri-drivers dbus dbus-x11 \
'*/xvfb-run' gdm-lib accountsservice-libs gnome-control-center gcovr \
--setopt=install_weak_deps=False && \
dnf install -y xorg-x11-server-Xvfb mesa-dri-drivers dbus dbus-x11 '*/xvfb-run' gdm-lib accountsservice-libs gnome-control-center && \
# GNOME Shell
dnf builddep -y gnome-shell --setopt=install_weak_deps=False && \
dnf remove -y gnome-bluetooth-libs-devel && \
dnf remove -y gnome-bluetooth-libs-devel dbus-glib-devel upower-devel python3-devel && \
dnf remove -y --noautoremove mutter mutter-devel && \
dnf upgrade -y 'pkgconfig(libpipewire-0.3)' && \
dnf clean all

91
NEWS
View File

@@ -1,62 +1,45 @@
3.37.2
3.36.1
======
* 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]
* Fix hardware cursor on GPU hotplpug [Pekka; !1097]
* Fix black areas around XWayland windows when resizing [Robert, Olivier; !1091]
* Fix applying wrong scale to monitors on X11 [Jonas; !1118]
* Fix moving/resizing windows via keyboard on wayland [Alynx; !997]
* Fix locate-pointer feature interfering with keybindings [Carlos; !1014]
* Add support for middle-click emulation [Andrew; !256]
* Fix freeze when moving cursor between scaled monitors [Robert; !1125]
* Fix popup misplacement with focus-follows-mouse [Jonas Å.; !1122]
* Fix misplaced cursor in preedit strings [Carlos; !1132]
* Support mirroring with proprietary Nvidia driver [Jonas Å.; !1098]
* Support tablets with multiple mode switch buttons in a group [Carlos; !970]
* Ignore foreground color for color glyphs (emojis) [Carlos; !1148]
* Allow pad mode switches while showing OSD [Carlos; !975]
* Fix positioning of OSD for display-attached tablets [Carlos; !971]
* Respect configured RANDR panning on X11 [Jonas Å.; !1085]
* Use correct texture filtering with scaled displays [Jonas; !1124]
* Fix cursor hotspots in virtual machines [Jonas Å.; !1136]
* Fix build with GLES and no GL [Georges; !1151]
* Work around Firefox bug when copying images on wayland [Robert; !1141]
* Fix wrong cursor rotation on rotated displays [Hans; !1153]
* Fix glitches in window screencasts [Georges; !1129]
* Fix IM support for deleting surrounding text [Takao, Carlos; #539]
* Fix map animation of maximized windows [Robert; !1164]
* Fixed crashes [Jonas Å., Carlos, Florian, Robert; !1120, !1121,
#917, #1132, #1083, !1147, #1147]
* Misc. bug fixes and cleanups [Jonas Å., Olivier, Mart, Sebastian, Corentin,
Andre, Daniel, Robert, Carlos, Peter, Georges, Jonas D., Florian, Christian;
!1115, !1102, !1104, !1106, !1117, !1119, !1101, !1123, #1124, !1130, !1131,
!1133, #1065, !1108, !1144, !1145, !1109, !1059, !1107, !999, !1152, #1128,
!1155, !1156, !1158, !1157, #1146, !1161, !1163]
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]
* Make window-aliveness checks less aggressive [Jonas Å.; !1182]
* Fix stylus coordinates when using screen rotation [Jonas T.; #1118]
* Preserve keyboard state on VT switch [Olivier; !1185]
* Remove Clutter's drag and drop actions [Jonas D.; !789]
* Cancel clicks/gestures actions on disable [Georges; !1188]
* Fix various clipboard issues [Carlos; !1186, !1198, !1203, !1204, !1206]
* Fix trackball button scrolling [Phillip; #1120]
* Fix tiled monitor support [Jonas; !1199]
* Support unredirecting fullscreen wayland surfaces [Jonas Å.; !798]
* Support area screencasts [Jonas Å.; !1207]
* Synchronize shadows to server-side decorations [Olivier; !1214]
* Allow inhibiting remote access [Jonas Å.; !1212]
* Fix overview key on X11 when using multiple keyboard layouts [Olivier; !1219]
* Fixed crashes [Jonas, D., Carlos; !1173, !1183, !1012]
* Misc. bug fixes and cleanups [Andre, Georges, Christian, Jonas Å., Andre,
Simon, Florian, Carlos, Adam, Marco, Thomas, Elias, Pekka, Jonas D.,
Laurent; !1169, !1168, !1166, !1170, !1167, !1172, !1175, !1176, !1184,
!1126, !1187, !1191, !1195, !1179, !1200, !1193, !1209, !1213, !1208,
#1074, !1223]
Contributors:
Marco Trevisan (Treviño), Elias Aebi, Thomas Hindoe Paaboel Andersen,
Laurent Bigonville, Jonas Dreßler, Olivier Fourdan, Carlos Garnacho,
Adam Jackson, Andre Moreira Magalhaes, Simon McVittie, Florian Müllner,
Georges Basile Stavracas Neto, Pekka Paalanen, Christian Rauch, Jonas Troeger,
Phillip Wood, Jonas Ådahl
Jonas Dreßler, Olivier Fourdan, Takao Fujiwara, Carlos Garnacho, Andrew Gaul,
Hans de Goede, Peter Hutterer, Sebastian Keller, Robert Mader,
Andre Moreira Magalhaes, Florian Müllner, Georges Basile Stavracas Neto,
Corentin Noël, Pekka Paalanen, Christian Rauch, Mart Raudsepp,
Daniel van Vugt, Alynx Zhou, Jonas Ådahl
Translators:
Dušan Kazik [sk], Christian Kirbach [de]
Марко Костић [sr], Daniel Șerbănescu [ro]
3.36.0
======

View File

@@ -60,6 +60,17 @@ static const gchar * cally_util_get_toolkit_name (void);
static const gchar * cally_util_get_toolkit_version (void);
/* private */
static void cally_util_simulate_snooper_install (void);
static void cally_util_simulate_snooper_remove (void);
static gboolean cally_key_snooper (ClutterActor *actor,
ClutterEvent *event,
gpointer user_data);
static void cally_util_stage_added_cb (ClutterStageManager *stage_manager,
ClutterStage *stage,
gpointer data);
static void cally_util_stage_removed_cb (ClutterStageManager *stage_manager,
ClutterStage *stage,
gpointer data);
static gboolean notify_hf (gpointer key,
gpointer value,
gpointer data);
@@ -142,8 +153,12 @@ cally_util_add_key_event_listener (AtkKeySnoopFunc listener,
CallyKeyEventInfo *event_info = NULL;
if (!key_listener_list)
{
key_listener_list = g_hash_table_new_full (NULL, NULL, NULL, g_free);
cally_util_simulate_snooper_install ();
}
event_info = g_new (CallyKeyEventInfo, 1);
event_info->listener = listener;
event_info->func_data = data;
@@ -164,11 +179,75 @@ cally_util_remove_key_event_listener (guint remove_listener)
{
g_hash_table_destroy (key_listener_list);
key_listener_list = NULL;
cally_util_simulate_snooper_remove ();
}
}
/* ------------------------------ PRIVATE FUNCTIONS ------------------------- */
/* Trying to emulate gtk_key_snooper install (a kind of wrapper). This
could be implemented without it, but I will maintain it in this
way, so if in the future clutter implements it natively it would be
easier the transition */
static void
cally_util_simulate_snooper_install (void)
{
ClutterStageManager *stage_manager = NULL;
ClutterStage *stage = NULL;
GSList *stage_list = NULL;
GSList *iter = NULL;
stage_manager = clutter_stage_manager_get_default ();
stage_list = clutter_stage_manager_list_stages (stage_manager);
for (iter = stage_list; iter != NULL; iter = g_slist_next (iter))
{
stage = CLUTTER_STAGE (iter->data);
g_signal_connect (G_OBJECT (stage), "captured-event",
G_CALLBACK (cally_key_snooper), NULL);
}
g_signal_connect (G_OBJECT (stage_manager), "stage-added",
G_CALLBACK (cally_util_stage_added_cb), cally_key_snooper);
g_signal_connect (G_OBJECT (stage_manager), "stage-removed",
G_CALLBACK (cally_util_stage_removed_cb), cally_key_snooper);
g_slist_free (stage_list);
}
static void
cally_util_simulate_snooper_remove (void)
{
ClutterStageManager *stage_manager = NULL;
ClutterStage *stage = NULL;
GSList *stage_list = NULL;
GSList *iter = NULL;
gint num = 0;
stage_manager = clutter_stage_manager_get_default ();
stage_list = clutter_stage_manager_list_stages (stage_manager);
for (iter = stage_list; iter != NULL; iter = g_slist_next (iter))
{
stage = CLUTTER_STAGE (iter->data);
num += g_signal_handlers_disconnect_by_func (stage, cally_key_snooper, NULL);
}
g_signal_handlers_disconnect_by_func (G_OBJECT (stage_manager),
G_CALLBACK (cally_util_stage_added_cb),
cally_key_snooper);
g_signal_handlers_disconnect_by_func (G_OBJECT (stage_manager),
G_CALLBACK (cally_util_stage_removed_cb),
cally_key_snooper);
#ifdef CALLY_DEBUG
g_print ("Number of snooper callbacks disconnected: %i\n", num);
#endif
}
static AtkKeyEventStruct *
atk_key_event_from_clutter_event_key (ClutterKeyEvent *clutter_event,
gunichar password_char)
@@ -305,34 +384,59 @@ check_key_visibility (ClutterEvent *event)
return DEFAULT_PASSWORD_CHAR;
}
gboolean
cally_snoop_key_event (ClutterKeyEvent *key)
static gboolean
cally_key_snooper (ClutterActor *actor,
ClutterEvent *event,
gpointer user_data)
{
ClutterEvent *event = (ClutterEvent *) key;
AtkKeyEventStruct *key_event = NULL;
gboolean consumed = FALSE;
gint consumed = 0;
gunichar password_char = 0;
/* filter key events */
if ((event->type != CLUTTER_KEY_PRESS) && (event->type != CLUTTER_KEY_RELEASE))
return FALSE;
{
return FALSE;
}
password_char = check_key_visibility (event);
if (key_listener_list)
{
GHashTable *new_hash = g_hash_table_new (NULL, NULL);
g_hash_table_foreach (key_listener_list, insert_hf, new_hash);
password_char = check_key_visibility (event);
key_event = atk_key_event_from_clutter_event_key (key, password_char);
key_event = atk_key_event_from_clutter_event_key ((ClutterKeyEvent *)event,
password_char);
/* func data is inside the hash table */
consumed = g_hash_table_foreach_steal (new_hash, notify_hf, key_event) > 0;
consumed = g_hash_table_foreach_steal (new_hash, notify_hf, key_event);
g_hash_table_destroy (new_hash);
g_free (key_event->string);
g_free (key_event);
}
return consumed;
return (consumed ? 1 : 0);
}
static void
cally_util_stage_added_cb (ClutterStageManager *stage_manager,
ClutterStage *stage,
gpointer data)
{
GCallback cally_key_snooper_cb = G_CALLBACK (data);
g_signal_connect (G_OBJECT (stage), "captured-event", cally_key_snooper_cb, NULL);
}
static void
cally_util_stage_removed_cb (ClutterStageManager *stage_manager,
ClutterStage *stage,
gpointer data)
{
GCallback cally_key_snooper_cb = G_CALLBACK (data);
g_signal_handlers_disconnect_by_func (stage, cally_key_snooper_cb, NULL);
}
void

View File

@@ -79,8 +79,6 @@ GType cally_util_get_type (void) G_GNUC_CONST;
void _cally_util_override_atk_util (void);
gboolean cally_snoop_key_event (ClutterKeyEvent *key);
G_END_DECLS
#endif /* __CALLY_UTIL_H__ */

View File

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

View File

@@ -615,32 +615,6 @@ clutter_actor_box_scale (ClutterActorBox *box,
box->y2 *= scale;
}
/**
* clutter_actor_box_is_initialized:
* @box: a #ClutterActorBox
*
* Checks if @box has been initialized, a #ClutterActorBox is uninitialized
* if it has a size of -1 at an origin of 0, 0.
*
* Returns: %TRUE if the box is uninitialized, %FALSE if it isn't
*/
gboolean
clutter_actor_box_is_initialized (ClutterActorBox *box)
{
gboolean x1_uninitialized, x2_uninitialized;
gboolean y1_uninitialized, y2_uninitialized;
g_return_val_if_fail (box != NULL, TRUE);
x1_uninitialized = isinf (box->x1);
x2_uninitialized = isinf (box->x2) && signbit (box->x2);
y1_uninitialized = isinf (box->y1);
y2_uninitialized = isinf (box->y2) && signbit (box->y2);
return !x1_uninitialized || !x2_uninitialized ||
!y1_uninitialized || !y2_uninitialized;
}
G_DEFINE_BOXED_TYPE_WITH_CODE (ClutterActorBox, clutter_actor_box,
clutter_actor_box_copy,
clutter_actor_box_free,

View File

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

View File

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

View File

@@ -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_clear_stage_views_recursive (ClutterActor *actor);
void _clutter_actor_queue_update_resource_scale_recursive (ClutterActor *actor);
gboolean _clutter_actor_get_real_resource_scale (ClutterActor *actor,
float *resource_scale);
@@ -321,8 +321,6 @@ 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__ */

File diff suppressed because it is too large Load Diff

View File

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

@@ -58,7 +58,6 @@ struct _ClutterAlignConstraint
ClutterActor *actor;
ClutterActor *source;
ClutterAlignAxis align_axis;
graphene_point_t pivot;
gfloat factor;
};
@@ -73,7 +72,6 @@ enum
PROP_SOURCE,
PROP_ALIGN_AXIS,
PROP_PIVOT_POINT,
PROP_FACTOR,
PROP_LAST
@@ -86,11 +84,13 @@ G_DEFINE_TYPE (ClutterAlignConstraint,
CLUTTER_TYPE_CONSTRAINT);
static void
source_queue_relayout (ClutterActor *actor,
ClutterAlignConstraint *align)
source_position_changed (ClutterActor *actor,
const ClutterActorBox *allocation,
ClutterAllocationFlags flags,
ClutterAlignConstraint *align)
{
if (align->actor != NULL)
_clutter_actor_queue_only_relayout (align->actor);
clutter_actor_queue_relayout (align->actor);
}
static void
@@ -135,41 +135,35 @@ clutter_align_constraint_update_allocation (ClutterConstraint *constraint,
ClutterAlignConstraint *align = CLUTTER_ALIGN_CONSTRAINT (constraint);
gfloat source_width, source_height;
gfloat actor_width, actor_height;
gfloat offset_x_start, offset_y_start;
gfloat pivot_x, pivot_y;
gfloat source_x, source_y;
if (align->source == NULL)
return;
clutter_actor_box_get_size (allocation, &actor_width, &actor_height);
clutter_actor_get_position (align->source, &source_x, &source_y);
clutter_actor_get_size (align->source, &source_width, &source_height);
pivot_x = align->pivot.x == -1.f
? align->factor
: align->pivot.x;
pivot_y = align->pivot.y == -1.f
? align->factor
: align->pivot.y;
offset_x_start = pivot_x * -actor_width;
offset_y_start = pivot_y * -actor_height;
switch (align->align_axis)
{
case CLUTTER_ALIGN_X_AXIS:
allocation->x1 += offset_x_start + (source_width * align->factor);
allocation->x1 = ((source_width - actor_width) * align->factor)
+ source_x;
allocation->x2 = allocation->x1 + actor_width;
break;
case CLUTTER_ALIGN_Y_AXIS:
allocation->y1 += offset_y_start + (source_height * align->factor);
allocation->y1 = ((source_height - actor_height) * align->factor)
+ source_y;
allocation->y2 = allocation->y1 + actor_height;
break;
case CLUTTER_ALIGN_BOTH:
allocation->x1 += offset_x_start + (source_width * align->factor);
allocation->y1 += offset_y_start + (source_height * align->factor);
allocation->x1 = ((source_width - actor_width) * align->factor)
+ source_x;
allocation->y1 = ((source_height - actor_height) * align->factor)
+ source_y;
allocation->x2 = allocation->x1 + actor_width;
allocation->y2 = allocation->y1 + actor_height;
break;
@@ -193,7 +187,7 @@ clutter_align_constraint_dispose (GObject *gobject)
G_CALLBACK (source_destroyed),
align);
g_signal_handlers_disconnect_by_func (align->source,
G_CALLBACK (source_queue_relayout),
G_CALLBACK (source_position_changed),
align);
align->source = NULL;
}
@@ -219,10 +213,6 @@ clutter_align_constraint_set_property (GObject *gobject,
clutter_align_constraint_set_align_axis (align, g_value_get_enum (value));
break;
case PROP_PIVOT_POINT:
clutter_align_constraint_set_pivot_point (align, g_value_get_boxed (value));
break;
case PROP_FACTOR:
clutter_align_constraint_set_factor (align, g_value_get_float (value));
break;
@@ -251,16 +241,6 @@ clutter_align_constraint_get_property (GObject *gobject,
g_value_set_enum (value, align->align_axis);
break;
case PROP_PIVOT_POINT:
{
graphene_point_t point;
clutter_align_constraint_get_pivot_point (align, &point);
g_value_set_boxed (value, &point);
}
break;
case PROP_FACTOR:
g_value_set_float (value, align->factor);
break;
@@ -314,30 +294,6 @@ clutter_align_constraint_class_init (ClutterAlignConstraintClass *klass)
CLUTTER_ALIGN_X_AXIS,
CLUTTER_PARAM_READWRITE | G_PARAM_CONSTRUCT);
/**
* ClutterAlignConstraint:pivot-point:
*
* The pivot point used by the constraint. The pivot point is the
* point in the constraint actor around which the aligning is applied,
* with (0, 0) being the top left corner of the actor and (1, 1) the
* bottom right corner of the actor.
*
* For example, setting the pivot point to (0.5, 0.5) and using a factor
* of 1 for both axes will align the actors horizontal and vertical
* center point with the bottom right corner of the source actor.
*
* By default, the pivot point is set to (-1, -1), which means it's not
* used and the constrained actor will be aligned to always stay inside
* the source actor.
*/
obj_props[PROP_PIVOT_POINT] =
g_param_spec_boxed ("pivot-point",
P_("Pivot point"),
P_("The pivot point"),
GRAPHENE_TYPE_POINT,
G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS);
/**
* ClutterAlignConstraint:factor:
*
@@ -370,8 +326,6 @@ clutter_align_constraint_init (ClutterAlignConstraint *self)
self->actor = NULL;
self->source = NULL;
self->align_axis = CLUTTER_ALIGN_X_AXIS;
self->pivot.x = -1.f;
self->pivot.y = -1.f;
self->factor = 0.0f;
}
@@ -449,15 +403,15 @@ clutter_align_constraint_set_source (ClutterAlignConstraint *align,
G_CALLBACK (source_destroyed),
align);
g_signal_handlers_disconnect_by_func (old_source,
G_CALLBACK (source_queue_relayout),
G_CALLBACK (source_position_changed),
align);
}
align->source = source;
if (align->source != NULL)
{
g_signal_connect (align->source, "queue-relayout",
G_CALLBACK (source_queue_relayout),
g_signal_connect (align->source, "allocation-changed",
G_CALLBACK (source_position_changed),
align);
g_signal_connect (align->source, "destroy",
G_CALLBACK (source_destroyed),
@@ -534,60 +488,6 @@ clutter_align_constraint_get_align_axis (ClutterAlignConstraint *align)
return align->align_axis;
}
/**
* clutter_align_constraint_set_pivot_point:
* @align: a #ClutterAlignConstraint
* @pivot_point: A #GraphenePoint
*
* Sets the pivot point used by the constraint, the pivot point is the
* point in the constraint actor around which the aligning is applied,
* with (0, 0) being the top left corner of the actor and (1, 1) the
* bottom right corner of the actor.
*
* If -1 is used, the pivot point is unset and the constrained actor
* will be aligned to always stay inside the source actor.
*/
void
clutter_align_constraint_set_pivot_point (ClutterAlignConstraint *align,
const graphene_point_t *pivot_point)
{
g_return_if_fail (CLUTTER_IS_ALIGN_CONSTRAINT (align));
g_return_if_fail (pivot_point != NULL);
g_return_if_fail (pivot_point->x == -1.f ||
(pivot_point->x >= 0.f && pivot_point->x <= 1.f));
g_return_if_fail (pivot_point->y == -1.f ||
(pivot_point->y >= 0.f && pivot_point->y <= 1.f));
if (graphene_point_equal (&align->pivot, pivot_point))
return;
align->pivot = *pivot_point;
if (align->actor != NULL)
clutter_actor_queue_relayout (align->actor);
g_object_notify_by_pspec (G_OBJECT (align), obj_props[PROP_PIVOT_POINT]);
}
/**
* clutter_align_constraint_get_pivot_point
* @align: a #ClutterAlignConstraint
* @pivot_point: (out caller-allocates): return location for a #GraphenePoint
*
* Gets the pivot point used by the constraint set with
* clutter_align_constraint_set_pivot_point(). If no custom pivot
* point is set, -1 is set.
*/
void
clutter_align_constraint_get_pivot_point (ClutterAlignConstraint *align,
graphene_point_t *pivot_point)
{
g_return_if_fail (CLUTTER_IS_ALIGN_CONSTRAINT (align));
g_return_if_fail (pivot_point != NULL);
*pivot_point = align->pivot;
}
/**
* clutter_align_constraint_set_factor:
* @align: a #ClutterAlignConstraint

View File

@@ -67,12 +67,6 @@ void clutter_align_constraint_set_align_axis (ClutterAlignConstrai
CLUTTER_EXPORT
ClutterAlignAxis clutter_align_constraint_get_align_axis (ClutterAlignConstraint *align);
CLUTTER_EXPORT
void clutter_align_constraint_set_pivot_point (ClutterAlignConstraint *align,
const graphene_point_t *pivot_point);
CLUTTER_EXPORT
void clutter_align_constraint_get_pivot_point (ClutterAlignConstraint *align,
graphene_point_t *pivot_point);
CLUTTER_EXPORT
void clutter_align_constraint_set_factor (ClutterAlignConstraint *align,
gfloat factor);
CLUTTER_EXPORT

View File

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

View File

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

View File

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

View File

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

View File

@@ -165,9 +165,6 @@ clutter_bind_constraint_update_preferred_size (ClutterConstraint *constraint,
bind->coordinate == CLUTTER_BIND_ALL))
return;
if (clutter_actor_contains (bind->source, actor))
return;
switch (direction)
{
case CLUTTER_ORIENTATION_HORIZONTAL:

File diff suppressed because it is too large Load Diff

View File

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

View File

@@ -159,8 +159,7 @@ static inline void
click_action_set_pressed (ClutterClickAction *action,
gboolean is_pressed)
{
ClutterClickActionPrivate *priv =
clutter_click_action_get_instance_private (action);
ClutterClickActionPrivate *priv = action->priv;
is_pressed = !!is_pressed;
@@ -175,8 +174,7 @@ static inline void
click_action_set_held (ClutterClickAction *action,
gboolean is_held)
{
ClutterClickActionPrivate *priv =
clutter_click_action_get_instance_private (action);
ClutterClickActionPrivate *priv = action->priv;
is_held = !!is_held;
@@ -191,8 +189,7 @@ static gboolean
click_action_emit_long_press (gpointer data)
{
ClutterClickAction *action = data;
ClutterClickActionPrivate *priv =
clutter_click_action_get_instance_private (action);
ClutterClickActionPrivate *priv = action->priv;
ClutterActor *actor;
gboolean result;
@@ -216,8 +213,7 @@ click_action_emit_long_press (gpointer data)
static inline void
click_action_query_long_press (ClutterClickAction *action)
{
ClutterClickActionPrivate *priv =
clutter_click_action_get_instance_private (action);
ClutterClickActionPrivate *priv = action->priv;
ClutterActor *actor;
gboolean result = FALSE;
gint timeout;
@@ -242,7 +238,6 @@ click_action_query_long_press (ClutterClickAction *action)
if (result)
{
g_clear_handle_id (&priv->long_press_id, g_source_remove);
priv->long_press_id =
clutter_threads_add_timeout (timeout,
click_action_emit_long_press,
@@ -253,8 +248,7 @@ click_action_query_long_press (ClutterClickAction *action)
static inline void
click_action_cancel_long_press (ClutterClickAction *action)
{
ClutterClickActionPrivate *priv =
clutter_click_action_get_instance_private (action);
ClutterClickActionPrivate *priv = action->priv;
if (priv->long_press_id != 0)
{
@@ -277,8 +271,7 @@ on_event (ClutterActor *actor,
ClutterEvent *event,
ClutterClickAction *action)
{
ClutterClickActionPrivate *priv =
clutter_click_action_get_instance_private (action);
ClutterClickActionPrivate *priv = action->priv;
gboolean has_button = TRUE;
if (!clutter_actor_meta_get_enabled (CLUTTER_ACTOR_META (action)))
@@ -348,12 +341,17 @@ on_captured_event (ClutterActor *stage,
ClutterEvent *event,
ClutterClickAction *action)
{
ClutterClickActionPrivate *priv =
clutter_click_action_get_instance_private (action);
ClutterClickActionPrivate *priv = action->priv;
ClutterActor *actor;
ClutterModifierType modifier_state;
gboolean has_button = TRUE;
if (!clutter_actor_meta_get_enabled (CLUTTER_ACTOR_META (action)))
{
clutter_click_action_release (action);
return CLUTTER_EVENT_PROPAGATE;
}
actor = clutter_actor_meta_get_actor (CLUTTER_ACTOR_META (action));
switch (clutter_event_type (event))
@@ -441,8 +439,7 @@ clutter_click_action_set_actor (ClutterActorMeta *meta,
ClutterActor *actor)
{
ClutterClickAction *action = CLUTTER_CLICK_ACTION (meta);
ClutterClickActionPrivate *priv =
clutter_click_action_get_instance_private (action);
ClutterClickActionPrivate *priv = action->priv;
if (priv->event_id != 0)
{
@@ -476,28 +473,13 @@ clutter_click_action_set_actor (ClutterActorMeta *meta,
CLUTTER_ACTOR_META_CLASS (clutter_click_action_parent_class)->set_actor (meta, actor);
}
static void
clutter_click_action_set_enabled (ClutterActorMeta *meta,
gboolean is_enabled)
{
ClutterClickAction *click_action = CLUTTER_CLICK_ACTION (meta);
ClutterActorMetaClass *parent_class =
CLUTTER_ACTOR_META_CLASS (clutter_click_action_parent_class);
if (!is_enabled)
clutter_click_action_release (click_action);
parent_class->set_enabled (meta, is_enabled);
}
static void
clutter_click_action_set_property (GObject *gobject,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
ClutterClickActionPrivate *priv =
clutter_click_action_get_instance_private (CLUTTER_CLICK_ACTION (gobject));
ClutterClickActionPrivate *priv = CLUTTER_CLICK_ACTION (gobject)->priv;
switch (prop_id)
{
@@ -521,8 +503,7 @@ clutter_click_action_get_property (GObject *gobject,
GValue *value,
GParamSpec *pspec)
{
ClutterClickActionPrivate *priv =
clutter_click_action_get_instance_private (CLUTTER_CLICK_ACTION (gobject));
ClutterClickActionPrivate *priv = CLUTTER_CLICK_ACTION (gobject)->priv;
switch (prop_id)
{
@@ -551,8 +532,7 @@ clutter_click_action_get_property (GObject *gobject,
static void
clutter_click_action_dispose (GObject *gobject)
{
ClutterClickActionPrivate *priv =
clutter_click_action_get_instance_private (CLUTTER_CLICK_ACTION (gobject));
ClutterClickActionPrivate *priv = CLUTTER_CLICK_ACTION (gobject)->priv;
g_clear_signal_handler (&priv->event_id,
clutter_actor_meta_get_actor (CLUTTER_ACTOR_META (gobject)));
@@ -572,7 +552,6 @@ clutter_click_action_class_init (ClutterClickActionClass *klass)
ClutterActorMetaClass *meta_class = CLUTTER_ACTOR_META_CLASS (klass);
meta_class->set_actor = clutter_click_action_set_actor;
meta_class->set_enabled = clutter_click_action_set_enabled;
gobject_class->dispose = clutter_click_action_dispose;
gobject_class->set_property = clutter_click_action_set_property;
@@ -710,11 +689,9 @@ clutter_click_action_class_init (ClutterClickActionClass *klass)
static void
clutter_click_action_init (ClutterClickAction *self)
{
ClutterClickActionPrivate *priv =
clutter_click_action_get_instance_private (self);
priv->long_press_threshold = -1;
priv->long_press_duration = -1;
self->priv = clutter_click_action_get_instance_private (self);
self->priv->long_press_threshold = -1;
self->priv->long_press_duration = -1;
}
/**
@@ -754,7 +731,7 @@ clutter_click_action_release (ClutterClickAction *action)
g_return_if_fail (CLUTTER_IS_CLICK_ACTION (action));
priv = clutter_click_action_get_instance_private (action);
priv = action->priv;
if (!priv->is_held)
return;
@@ -780,13 +757,9 @@ clutter_click_action_release (ClutterClickAction *action)
guint
clutter_click_action_get_button (ClutterClickAction *action)
{
ClutterClickActionPrivate *priv;
g_return_val_if_fail (CLUTTER_IS_CLICK_ACTION (action), 0);
priv = clutter_click_action_get_instance_private (action);
return priv->press_button;
return action->priv->press_button;
}
/**
@@ -802,13 +775,9 @@ clutter_click_action_get_button (ClutterClickAction *action)
ClutterModifierType
clutter_click_action_get_state (ClutterClickAction *action)
{
ClutterClickActionPrivate *priv;
g_return_val_if_fail (CLUTTER_IS_CLICK_ACTION (action), 0);
priv = clutter_click_action_get_instance_private (action);
return priv->modifier_state;
return action->priv->modifier_state;
}
/**
@@ -826,15 +795,11 @@ clutter_click_action_get_coords (ClutterClickAction *action,
gfloat *press_x,
gfloat *press_y)
{
ClutterClickActionPrivate *priv;
g_return_if_fail (CLUTTER_IS_ACTION (action));
priv = clutter_click_action_get_instance_private (action);
if (press_x != NULL)
*press_x = priv->press_x;
*press_x = action->priv->press_x;
if (press_y != NULL)
*press_y = priv->press_y;
*press_y = action->priv->press_y;
}

View File

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

View File

@@ -52,8 +52,6 @@
struct _ClutterClonePrivate
{
ClutterActor *clone_source;
float x_scale, y_scale;
gulong source_destroy_id;
};
@@ -124,6 +122,8 @@ static void
clutter_clone_apply_transform (ClutterActor *self, CoglMatrix *matrix)
{
ClutterClonePrivate *priv = CLUTTER_CLONE (self)->priv;
ClutterActorBox box, source_box;
gfloat x_scale, y_scale;
/* First chain up and apply all the standard ClutterActor
* transformations... */
@@ -134,7 +134,21 @@ clutter_clone_apply_transform (ClutterActor *self, CoglMatrix *matrix)
if (priv->clone_source == NULL)
return;
cogl_matrix_scale (matrix, priv->x_scale, priv->y_scale, 1.f);
/* get our allocated size */
clutter_actor_get_allocation_box (self, &box);
/* and get the allocated size of the source */
clutter_actor_get_allocation_box (priv->clone_source, &source_box);
/* We need to scale what the clone-source actor paints to fill our own
* allocation...
*/
x_scale = clutter_actor_box_get_width (&box)
/ clutter_actor_box_get_width (&source_box);
y_scale = clutter_actor_box_get_height (&box)
/ clutter_actor_box_get_height (&source_box);
cogl_matrix_scale (matrix, x_scale, y_scale, x_scale);
}
static void
@@ -226,16 +240,15 @@ clutter_clone_has_overlaps (ClutterActor *actor)
static void
clutter_clone_allocate (ClutterActor *self,
const ClutterActorBox *box)
const ClutterActorBox *box,
ClutterAllocationFlags flags)
{
ClutterClonePrivate *priv = CLUTTER_CLONE (self)->priv;
ClutterActorClass *parent_class;
ClutterActorBox source_box;
float x_scale, y_scale;
/* chain up */
parent_class = CLUTTER_ACTOR_CLASS (clutter_clone_parent_class);
parent_class->allocate (self, box);
parent_class->allocate (self, box, flags);
if (priv->clone_source == NULL)
return;
@@ -245,24 +258,7 @@ clutter_clone_allocate (ClutterActor *self,
*/
if (clutter_actor_get_parent (priv->clone_source) != NULL &&
!clutter_actor_has_allocation (priv->clone_source))
clutter_actor_allocate_preferred_size (priv->clone_source);
clutter_actor_get_allocation_box (priv->clone_source, &source_box);
/* We need to scale what the clone-source actor paints to fill our own
* allocation...
*/
x_scale = clutter_actor_box_get_width (box)
/ clutter_actor_box_get_width (&source_box);
y_scale = clutter_actor_box_get_height (box)
/ clutter_actor_box_get_height (&source_box);
if (!G_APPROX_VALUE (priv->x_scale, x_scale, FLT_EPSILON) ||
!G_APPROX_VALUE (priv->y_scale, y_scale, FLT_EPSILON))
{
priv->x_scale = x_scale;
priv->y_scale = y_scale;
}
clutter_actor_allocate_preferred_size (priv->clone_source, flags);
#if 0
/* XXX - this is wrong: ClutterClone cannot clone unparented
@@ -277,7 +273,7 @@ clutter_clone_allocate (ClutterActor *self,
* paint cycle, we can safely give it as much size as it requires
*/
if (clutter_actor_get_parent (priv->clone_source) == NULL)
clutter_actor_allocate_preferred_size (priv->clone_source);
clutter_actor_allocate_preferred_size (priv->clone_source, flags);
#endif
}
@@ -369,9 +365,6 @@ static void
clutter_clone_init (ClutterClone *self)
{
self->priv = clutter_clone_get_instance_private (self);
self->priv->x_scale = 1.f;
self->priv->y_scale = 1.f;
}
/**

View File

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

View File

@@ -160,26 +160,28 @@ constraint_update_preferred_size (ClutterConstraint *constraint,
}
static void
clutter_constraint_set_enabled (ClutterActorMeta *meta,
gboolean is_enabled)
clutter_constraint_notify (GObject *gobject,
GParamSpec *pspec)
{
ClutterActorMetaClass *parent_class =
CLUTTER_ACTOR_META_CLASS (clutter_constraint_parent_class);
ClutterActor *actor;
if (strcmp (pspec->name, "enabled") == 0)
{
ClutterActorMeta *meta = CLUTTER_ACTOR_META (gobject);
ClutterActor *actor = clutter_actor_meta_get_actor (meta);
actor = clutter_actor_meta_get_actor (meta);
if (actor)
clutter_actor_queue_relayout (actor);
if (actor != NULL)
clutter_actor_queue_relayout (actor);
}
parent_class->set_enabled (meta, is_enabled);
if (G_OBJECT_CLASS (clutter_constraint_parent_class)->notify != NULL)
G_OBJECT_CLASS (clutter_constraint_parent_class)->notify (gobject, pspec);
}
static void
clutter_constraint_class_init (ClutterConstraintClass *klass)
{
ClutterActorMetaClass *actor_meta_class = CLUTTER_ACTOR_META_CLASS (klass);
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
actor_meta_class->set_enabled = clutter_constraint_set_enabled;
gobject_class->notify = clutter_constraint_notify;
klass->update_allocation = constraint_update_allocation;
klass->update_preferred_size = constraint_update_preferred_size;

View File

@@ -1,92 +0,0 @@
/*
* Copyright (C) 2007,2008,2009,2010,2011 Intel Corporation.
* Copyright (C) 2020 Red Hat Inc
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include "clutter-build-config.h"
#include "clutter-damage-history.h"
#define DAMAGE_HISTORY_LENGTH 0x10
struct _ClutterDamageHistory
{
cairo_region_t *damages[DAMAGE_HISTORY_LENGTH];
int index;
};
ClutterDamageHistory *
clutter_damage_history_new (void)
{
ClutterDamageHistory *history;
history = g_new0 (ClutterDamageHistory, 1);
return history;
}
void
clutter_damage_history_free (ClutterDamageHistory *history)
{
int i;
for (i = 0; i < G_N_ELEMENTS (history->damages); i++)
g_clear_pointer (&history->damages[i], cairo_region_destroy);
g_free (history);
}
gboolean
clutter_damage_history_is_age_valid (ClutterDamageHistory *history,
int age)
{
if (age >= DAMAGE_HISTORY_LENGTH ||
age < 1)
return FALSE;
if (!clutter_damage_history_lookup (history, age))
return FALSE;
return TRUE;
}
void
clutter_damage_history_record (ClutterDamageHistory *history,
const cairo_region_t *damage)
{
g_clear_pointer (&history->damages[history->index], cairo_region_destroy);
history->damages[history->index] = cairo_region_copy (damage);
}
static inline int
step_damage_index (int current,
int diff)
{
return (current + diff) & (DAMAGE_HISTORY_LENGTH - 1);
}
void
clutter_damage_history_step (ClutterDamageHistory *history)
{
history->index = step_damage_index (history->index, 1);
}
const cairo_region_t *
clutter_damage_history_lookup (ClutterDamageHistory *history,
int age)
{
return history->damages[step_damage_index (history->index, -age)];
}

View File

@@ -1,42 +0,0 @@
/*
* Copyright (C) 2007,2008,2009,2010,2011 Intel Corporation.
* Copyright (C) 2020 Red Hat Inc
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef CLUTTER_DAMAGE_HISTORY_H
#define CLUTTER_DAMAGE_HISTORY_H
#include <cairo.h>
#include <glib.h>
typedef struct _ClutterDamageHistory ClutterDamageHistory;
ClutterDamageHistory * clutter_damage_history_new (void);
void clutter_damage_history_free (ClutterDamageHistory *history);
gboolean clutter_damage_history_is_age_valid (ClutterDamageHistory *history,
int age);
void clutter_damage_history_record (ClutterDamageHistory *history,
const cairo_region_t *damage);
void clutter_damage_history_step (ClutterDamageHistory *history);
const cairo_region_t * clutter_damage_history_lookup (ClutterDamageHistory *history,
int age);
#endif /* CLUTTER_DAMAGE_HISTORY_H */

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,152 @@
/*
* Clutter.
*
* An OpenGL based 'interactive canvas' library.
*
* Copyright (C) 2010 Intel Corporation.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
* Author:
* Emmanuele Bassi <ebassi@linux.intel.com>
*/
#ifndef __CLUTTER_DRAG_ACTION_H__
#define __CLUTTER_DRAG_ACTION_H__
#if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION)
#error "Only <clutter/clutter.h> can be included directly."
#endif
#include <clutter/clutter-action.h>
#include <clutter/clutter-event.h>
G_BEGIN_DECLS
#define CLUTTER_TYPE_DRAG_ACTION (clutter_drag_action_get_type ())
#define CLUTTER_DRAG_ACTION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_DRAG_ACTION, ClutterDragAction))
#define CLUTTER_IS_DRAG_ACTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_DRAG_ACTION))
#define CLUTTER_DRAG_ACTION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_DRAG_ACTION, ClutterDragActionClass))
#define CLUTTER_IS_DRAG_ACTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_DRAG_ACTION))
#define CLUTTER_DRAG_ACTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_DRAG_ACTION, ClutterDragActionClass))
typedef struct _ClutterDragAction ClutterDragAction;
typedef struct _ClutterDragActionPrivate ClutterDragActionPrivate;
typedef struct _ClutterDragActionClass ClutterDragActionClass;
/**
* ClutterDragAction:
*
* The #ClutterDragAction structure contains only
* private data and should be accessed using the provided API
*
* Since: 1.4
*/
struct _ClutterDragAction
{
/*< private >*/
ClutterAction parent_instance;
ClutterDragActionPrivate *priv;
};
/**
* ClutterDragActionClass:
* @drag_begin: class handler of the #ClutterDragAction::drag-begin signal
* @drag_motion: class handler of the #ClutterDragAction::drag-motion signal
* @drag_end: class handler of the #ClutterDragAction::drag-end signal
* @drag_progress: class handler of the #ClutterDragAction::drag-progress signal
*
* The #ClutterDragActionClass structure contains
* only private data
*
* Since: 1.4
*/
struct _ClutterDragActionClass
{
/*< private >*/
ClutterActionClass parent_class;
/*< public >*/
void (* drag_begin) (ClutterDragAction *action,
ClutterActor *actor,
gfloat event_x,
gfloat event_y,
ClutterModifierType modifiers);
void (* drag_motion) (ClutterDragAction *action,
ClutterActor *actor,
gfloat delta_x,
gfloat delta_y);
void (* drag_end) (ClutterDragAction *action,
ClutterActor *actor,
gfloat event_x,
gfloat event_y,
ClutterModifierType modifiers);
gboolean (* drag_progress) (ClutterDragAction *action,
ClutterActor *actor,
gfloat delta_x,
gfloat delta_y);
/*< private >*/
void (* _clutter_drag_action1) (void);
void (* _clutter_drag_action2) (void);
void (* _clutter_drag_action3) (void);
void (* _clutter_drag_action4) (void);
};
CLUTTER_EXPORT
GType clutter_drag_action_get_type (void) G_GNUC_CONST;
CLUTTER_EXPORT
ClutterAction * clutter_drag_action_new (void);
CLUTTER_EXPORT
void clutter_drag_action_set_drag_threshold (ClutterDragAction *action,
gint x_threshold,
gint y_threshold);
CLUTTER_EXPORT
void clutter_drag_action_get_drag_threshold (ClutterDragAction *action,
guint *x_threshold,
guint *y_threshold);
CLUTTER_EXPORT
void clutter_drag_action_set_drag_handle (ClutterDragAction *action,
ClutterActor *handle);
CLUTTER_EXPORT
ClutterActor * clutter_drag_action_get_drag_handle (ClutterDragAction *action);
CLUTTER_EXPORT
void clutter_drag_action_set_drag_axis (ClutterDragAction *action,
ClutterDragAxis axis);
CLUTTER_EXPORT
ClutterDragAxis clutter_drag_action_get_drag_axis (ClutterDragAction *action);
CLUTTER_EXPORT
void clutter_drag_action_get_press_coords (ClutterDragAction *action,
gfloat *press_x,
gfloat *press_y);
CLUTTER_EXPORT
void clutter_drag_action_get_motion_coords (ClutterDragAction *action,
gfloat *motion_x,
gfloat *motion_y);
CLUTTER_EXPORT
gboolean clutter_drag_action_get_drag_area (ClutterDragAction *action,
graphene_rect_t *drag_area);
CLUTTER_EXPORT
void clutter_drag_action_set_drag_area (ClutterDragAction *action,
const graphene_rect_t *drag_area);
G_END_DECLS
#endif /* __CLUTTER_DRAG_ACTION_H__ */

View File

@@ -0,0 +1,527 @@
/*
* Clutter.
*
* An OpenGL based 'interactive canvas' library.
*
* Copyright © 2011 Intel Corporation.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
* Author:
* Emmanuele Bassi <ebassi@linux.intel.com>
*/
/**
* SECTION:clutter-drop-action
* @Title: ClutterDropAction
* @short_description: An action for drop targets
*
* #ClutterDropAction is a #ClutterAction that allows a #ClutterActor
* implementation to control what happens when an actor dragged using
* a #ClutterDragAction crosses the target area or when a dragged actor
* is released (or "dropped") on the target area.
*
* A trivial use of #ClutterDropAction consists in connecting to the
* #ClutterDropAction::drop signal and handling the drop from there,
* for instance:
*
* |[<!-- language="C" -->
* ClutterAction *action = clutter_drop_action ();
*
* g_signal_connect (action, "drop", G_CALLBACK (on_drop), NULL);
* clutter_actor_add_action (an_actor, action);
* ]|
*
* The #ClutterDropAction::can-drop can be used to control whether the
* #ClutterDropAction::drop signal is going to be emitted; returning %FALSE
* from a handler connected to the #ClutterDropAction::can-drop signal will
* cause the #ClutterDropAction::drop signal to be skipped when the input
* device button is released.
*
* It's important to note that #ClutterDropAction will only work with
* actors dragged using #ClutterDragAction.
*
* See [drop-action.c](https://git.gnome.org/browse/clutter/tree/examples/drop-action.c?h=clutter-1.18)
* for an example of how to use #ClutterDropAction.
*
* #ClutterDropAction is available since Clutter 1.8
*/
#include "clutter-build-config.h"
#include "clutter-drop-action.h"
#include "clutter-actor-meta-private.h"
#include "clutter-actor-private.h"
#include "clutter-drag-action.h"
#include "clutter-main.h"
#include "clutter-marshal.h"
#include "clutter-stage-private.h"
struct _ClutterDropActionPrivate
{
ClutterActor *actor;
ClutterActor *stage;
gulong mapped_id;
};
typedef struct _DropTarget {
ClutterActor *stage;
gulong capture_id;
GHashTable *actions;
ClutterDropAction *last_action;
} DropTarget;
enum
{
CAN_DROP,
OVER_IN,
OVER_OUT,
DROP,
DROP_CANCEL,
LAST_SIGNAL
};
static guint drop_signals[LAST_SIGNAL] = { 0, };
G_DEFINE_TYPE_WITH_PRIVATE (ClutterDropAction, clutter_drop_action, CLUTTER_TYPE_ACTION)
static void
drop_target_free (gpointer _data)
{
DropTarget *data = _data;
g_clear_signal_handler (&data->capture_id, data->stage);
g_hash_table_destroy (data->actions);
g_free (data);
}
static gboolean
on_stage_capture (ClutterStage *stage,
ClutterEvent *event,
gpointer user_data)
{
DropTarget *data = user_data;
gfloat event_x, event_y;
ClutterActor *actor, *drag_actor;
ClutterDropAction *drop_action;
ClutterInputDevice *device;
gboolean was_reactive;
switch (clutter_event_type (event))
{
case CLUTTER_MOTION:
case CLUTTER_BUTTON_RELEASE:
if (clutter_event_type (event) == CLUTTER_MOTION &&
!(clutter_event_get_state (event) & CLUTTER_BUTTON1_MASK))
return CLUTTER_EVENT_PROPAGATE;
if (clutter_event_type (event) == CLUTTER_BUTTON_RELEASE &&
clutter_event_get_button (event) != CLUTTER_BUTTON_PRIMARY)
return CLUTTER_EVENT_PROPAGATE;
device = clutter_event_get_device (event);
drag_actor = _clutter_stage_get_pointer_drag_actor (stage, device);
if (drag_actor == NULL)
return CLUTTER_EVENT_PROPAGATE;
break;
case CLUTTER_TOUCH_UPDATE:
case CLUTTER_TOUCH_END:
drag_actor = _clutter_stage_get_touch_drag_actor (stage,
clutter_event_get_event_sequence (event));
if (drag_actor == NULL)
return CLUTTER_EVENT_PROPAGATE;
break;
default:
return CLUTTER_EVENT_PROPAGATE;
}
clutter_event_get_coords (event, &event_x, &event_y);
/* get the actor under the cursor, excluding the dragged actor; we
* use reactivity because it won't cause any scene invalidation
*/
was_reactive = clutter_actor_get_reactive (drag_actor);
clutter_actor_set_reactive (drag_actor, FALSE);
actor = clutter_stage_get_actor_at_pos (stage, CLUTTER_PICK_REACTIVE,
event_x,
event_y);
if (actor == NULL || actor == CLUTTER_ACTOR (stage))
{
if (data->last_action != NULL)
{
ClutterActorMeta *meta = CLUTTER_ACTOR_META (data->last_action);
g_signal_emit (data->last_action, drop_signals[OVER_OUT], 0,
clutter_actor_meta_get_actor (meta));
data->last_action = NULL;
}
goto out;
}
drop_action = g_hash_table_lookup (data->actions, actor);
if (drop_action == NULL)
{
if (data->last_action != NULL)
{
ClutterActorMeta *meta = CLUTTER_ACTOR_META (data->last_action);
g_signal_emit (data->last_action, drop_signals[OVER_OUT], 0,
clutter_actor_meta_get_actor (meta));
data->last_action = NULL;
}
goto out;
}
else
{
if (data->last_action != drop_action)
{
ClutterActorMeta *meta;
if (data->last_action != NULL)
{
meta = CLUTTER_ACTOR_META (data->last_action);
g_signal_emit (data->last_action, drop_signals[OVER_OUT], 0,
clutter_actor_meta_get_actor (meta));
}
meta = CLUTTER_ACTOR_META (drop_action);
g_signal_emit (drop_action, drop_signals[OVER_IN], 0,
clutter_actor_meta_get_actor (meta));
}
data->last_action = drop_action;
}
out:
if (clutter_event_type (event) == CLUTTER_BUTTON_RELEASE ||
clutter_event_type (event) == CLUTTER_TOUCH_END)
{
if (data->last_action != NULL)
{
ClutterActorMeta *meta = CLUTTER_ACTOR_META (data->last_action);
gboolean can_drop = FALSE;
g_signal_emit (data->last_action, drop_signals[CAN_DROP], 0,
clutter_actor_meta_get_actor (meta),
event_x, event_y,
&can_drop);
if (can_drop)
{
g_signal_emit (data->last_action, drop_signals[DROP], 0,
clutter_actor_meta_get_actor (meta),
event_x, event_y);
}
else
{
g_signal_emit (data->last_action, drop_signals[DROP_CANCEL], 0,
clutter_actor_meta_get_actor (meta),
event_x, event_y);
}
}
data->last_action = NULL;
}
if (drag_actor != NULL)
clutter_actor_set_reactive (drag_actor, was_reactive);
return CLUTTER_EVENT_PROPAGATE;
}
static void
drop_action_register (ClutterDropAction *self)
{
ClutterDropActionPrivate *priv = self->priv;
DropTarget *data;
g_assert (priv->stage != NULL);
data = g_object_get_data (G_OBJECT (priv->stage), "__clutter_drop_targets");
if (data == NULL)
{
data = g_new0 (DropTarget, 1);
data->stage = priv->stage;
data->actions = g_hash_table_new (NULL, NULL);
data->capture_id = g_signal_connect (priv->stage, "captured-event",
G_CALLBACK (on_stage_capture),
data);
g_object_set_data_full (G_OBJECT (priv->stage), "__clutter_drop_targets",
data,
drop_target_free);
}
g_hash_table_replace (data->actions, priv->actor, self);
}
static void
drop_action_unregister (ClutterDropAction *self)
{
ClutterDropActionPrivate *priv = self->priv;
DropTarget *data = NULL;
if (priv->stage != NULL)
data = g_object_get_data (G_OBJECT (priv->stage), "__clutter_drop_targets");
if (data == NULL)
return;
g_hash_table_remove (data->actions, priv->actor);
if (g_hash_table_size (data->actions) == 0)
g_object_set_data (G_OBJECT (data->stage), "__clutter_drop_targets", NULL);
}
static void
on_actor_mapped (ClutterActor *actor,
GParamSpec *pspec,
ClutterDropAction *self)
{
if (clutter_actor_is_mapped (actor))
{
if (self->priv->stage == NULL)
self->priv->stage = clutter_actor_get_stage (actor);
drop_action_register (self);
}
else
drop_action_unregister (self);
}
static void
clutter_drop_action_set_actor (ClutterActorMeta *meta,
ClutterActor *actor)
{
ClutterDropActionPrivate *priv = CLUTTER_DROP_ACTION (meta)->priv;
if (priv->actor != NULL)
{
drop_action_unregister (CLUTTER_DROP_ACTION (meta));
g_clear_signal_handler (&priv->mapped_id, priv->actor);
priv->stage = NULL;
priv->actor = NULL;
}
priv->actor = actor;
if (priv->actor != NULL)
{
priv->stage = clutter_actor_get_stage (actor);
priv->mapped_id = g_signal_connect (actor, "notify::mapped",
G_CALLBACK (on_actor_mapped),
meta);
if (priv->stage != NULL)
drop_action_register (CLUTTER_DROP_ACTION (meta));
}
CLUTTER_ACTOR_META_CLASS (clutter_drop_action_parent_class)->set_actor (meta, actor);
}
static gboolean
signal_accumulator (GSignalInvocationHint *ihint,
GValue *return_accu,
const GValue *handler_return,
gpointer user_data)
{
gboolean continue_emission;
continue_emission = g_value_get_boolean (handler_return);
g_value_set_boolean (return_accu, continue_emission);
return continue_emission;
}
static gboolean
clutter_drop_action_real_can_drop (ClutterDropAction *action,
ClutterActor *actor,
gfloat event_x,
gfloat event_y)
{
return TRUE;
}
static void
clutter_drop_action_class_init (ClutterDropActionClass *klass)
{
ClutterActorMetaClass *meta_class = CLUTTER_ACTOR_META_CLASS (klass);
meta_class->set_actor = clutter_drop_action_set_actor;
klass->can_drop = clutter_drop_action_real_can_drop;
/**
* ClutterDropAction::can-drop:
* @action: the #ClutterDropAction that emitted the signal
* @actor: the #ClutterActor attached to the @action
* @event_x: the X coordinate (in stage space) of the drop event
* @event_y: the Y coordinate (in stage space) of the drop event
*
* The ::can-drop signal is emitted when the dragged actor is dropped
* on @actor. The return value of the ::can-drop signal will determine
* whether or not the #ClutterDropAction::drop signal is going to be
* emitted on @action.
*
* The default implementation of #ClutterDropAction returns %TRUE for
* this signal.
*
* Return value: %TRUE if the drop is accepted, and %FALSE otherwise
*
* Since: 1.8
*/
drop_signals[CAN_DROP] =
g_signal_new (I_("can-drop"),
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (ClutterDropActionClass, can_drop),
signal_accumulator, NULL,
_clutter_marshal_BOOLEAN__OBJECT_FLOAT_FLOAT,
G_TYPE_BOOLEAN, 3,
CLUTTER_TYPE_ACTOR,
G_TYPE_FLOAT,
G_TYPE_FLOAT);
/**
* ClutterDropAction::over-in:
* @action: the #ClutterDropAction that emitted the signal
* @actor: the #ClutterActor attached to the @action
*
* The ::over-in signal is emitted when the dragged actor crosses
* into @actor.
*
* Since: 1.8
*/
drop_signals[OVER_IN] =
g_signal_new (I_("over-in"),
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (ClutterDropActionClass, over_in),
NULL, NULL, NULL,
G_TYPE_NONE, 1,
CLUTTER_TYPE_ACTOR);
/**
* ClutterDropAction::over-out:
* @action: the #ClutterDropAction that emitted the signal
* @actor: the #ClutterActor attached to the @action
*
* The ::over-out signal is emitted when the dragged actor crosses
* outside @actor.
*
* Since: 1.8
*/
drop_signals[OVER_OUT] =
g_signal_new (I_("over-out"),
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (ClutterDropActionClass, over_out),
NULL, NULL, NULL,
G_TYPE_NONE, 1,
CLUTTER_TYPE_ACTOR);
/**
* ClutterDropAction::drop:
* @action: the #ClutterDropAction that emitted the signal
* @actor: the #ClutterActor attached to the @action
* @event_x: the X coordinate (in stage space) of the drop event
* @event_y: the Y coordinate (in stage space) of the drop event
*
* The ::drop signal is emitted when the dragged actor is dropped
* on @actor. This signal is only emitted if at least an handler of
* #ClutterDropAction::can-drop returns %TRUE.
*
* Since: 1.8
*/
drop_signals[DROP] =
g_signal_new (I_("drop"),
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (ClutterDropActionClass, drop),
NULL, NULL,
_clutter_marshal_VOID__OBJECT_FLOAT_FLOAT,
G_TYPE_NONE, 3,
CLUTTER_TYPE_ACTOR,
G_TYPE_FLOAT,
G_TYPE_FLOAT);
/**
* ClutterDropAction::drop-cancel:
* @action: the #ClutterDropAction that emitted the signal
* @actor: the #ClutterActor attached to the @action
* @event_x: the X coordinate (in stage space) of the drop event
* @event_y: the Y coordinate (in stage space) of the drop event
*
* The ::drop-cancel signal is emitted when the drop is refused
* by an emission of the #ClutterDropAction::can-drop signal.
*
* After the ::drop-cancel signal is fired the active drag is
* terminated.
*
* Since: 1.12
*/
drop_signals[DROP_CANCEL] =
g_signal_new (I_("drop-cancel"),
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (ClutterDropActionClass, drop),
NULL, NULL,
_clutter_marshal_VOID__OBJECT_FLOAT_FLOAT,
G_TYPE_NONE, 3,
CLUTTER_TYPE_ACTOR,
G_TYPE_FLOAT,
G_TYPE_FLOAT);
}
static void
clutter_drop_action_init (ClutterDropAction *self)
{
self->priv = clutter_drop_action_get_instance_private (self);
}
/**
* clutter_drop_action_new:
*
* Creates a new #ClutterDropAction.
*
* Use clutter_actor_add_action() to add the action to a #ClutterActor.
*
* Return value: the newly created #ClutterDropAction
*
* Since: 1.8
*/
ClutterAction *
clutter_drop_action_new (void)
{
return g_object_new (CLUTTER_TYPE_DROP_ACTION, NULL);
}

View File

@@ -0,0 +1,115 @@
/*
* Clutter.
*
* An OpenGL based 'interactive canvas' library.
*
* Copyright © 2011 Intel Corporation.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
* Author:
* Emmanuele Bassi <ebassi@linux.intel.com>
*/
#ifndef __CLUTTER_DROP_ACTION_H__
#define __CLUTTER_DROP_ACTION_H__
#if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION)
#error "Only <clutter/clutter.h> can be directly included."
#endif
#include <clutter/clutter-action.h>
G_BEGIN_DECLS
#define CLUTTER_TYPE_DROP_ACTION (clutter_drop_action_get_type ())
#define CLUTTER_DROP_ACTION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_DROP_ACTION, ClutterDropAction))
#define CLUTTER_IS_DROP_ACTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_DROP_ACTION))
#define CLUTTER_DROP_ACTION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_DROP_ACTION, ClutterDropActionClass))
#define CLUTTER_IS_DROP_ACTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_DROP_ACTION))
#define CLUTTER_DROP_ACTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_DROP_ACTION, ClutterDropActionClass))
typedef struct _ClutterDropAction ClutterDropAction;
typedef struct _ClutterDropActionPrivate ClutterDropActionPrivate;
typedef struct _ClutterDropActionClass ClutterDropActionClass;
/**
* ClutterDropAction:
*
* The #ClutterDropAction structure contains only
* private data and should be accessed using the provided API.
*
* Since: 1.8
*/
struct _ClutterDropAction
{
/*< private >*/
ClutterAction parent_instance;
ClutterDropActionPrivate *priv;
};
/**
* ClutterDropActionClass:
* @can_drop: class handler for the #ClutterDropAction::can-drop signal
* @over_in: class handler for the #ClutterDropAction::over-in signal
* @over_out: class handler for the #ClutterDropAction::over-out signal
* @drop: class handler for the #ClutterDropAction::drop signal
*
* The #ClutterDropActionClass structure contains
* only private data.
*
* Since: 1.8
*/
struct _ClutterDropActionClass
{
/*< private >*/
ClutterActionClass parent_class;
/*< public >*/
gboolean (* can_drop) (ClutterDropAction *action,
ClutterActor *actor,
gfloat event_x,
gfloat event_y);
void (* over_in) (ClutterDropAction *action,
ClutterActor *actor);
void (* over_out) (ClutterDropAction *action,
ClutterActor *actor);
void (* drop) (ClutterDropAction *action,
ClutterActor *actor,
gfloat event_x,
gfloat event_y);
/*< private >*/
void (*_clutter_drop_action1) (void);
void (*_clutter_drop_action2) (void);
void (*_clutter_drop_action3) (void);
void (*_clutter_drop_action4) (void);
void (*_clutter_drop_action5) (void);
void (*_clutter_drop_action6) (void);
void (*_clutter_drop_action7) (void);
void (*_clutter_drop_action8) (void);
};
CLUTTER_EXPORT
GType clutter_drop_action_get_type (void) G_GNUC_CONST;
CLUTTER_EXPORT
ClutterAction * clutter_drop_action_new (void);
G_END_DECLS
#endif /* __CLUTTER_DROP_ACTION_H__ */

View File

@@ -230,26 +230,28 @@ clutter_effect_real_pick (ClutterEffect *effect,
}
static void
clutter_effect_set_enabled (ClutterActorMeta *meta,
gboolean is_enabled)
clutter_effect_notify (GObject *gobject,
GParamSpec *pspec)
{
ClutterActorMetaClass *parent_class =
CLUTTER_ACTOR_META_CLASS (clutter_effect_parent_class);
ClutterActor *actor;
if (strcmp (pspec->name, "enabled") == 0)
{
ClutterActorMeta *meta = CLUTTER_ACTOR_META (gobject);
ClutterActor *actor = clutter_actor_meta_get_actor (meta);
actor = clutter_actor_meta_get_actor (meta);
if (actor)
clutter_actor_queue_redraw (actor);
if (actor != NULL)
clutter_actor_queue_redraw (actor);
}
parent_class->set_enabled (meta, is_enabled);
if (G_OBJECT_CLASS (clutter_effect_parent_class)->notify != NULL)
G_OBJECT_CLASS (clutter_effect_parent_class)->notify (gobject, pspec);
}
static void
clutter_effect_class_init (ClutterEffectClass *klass)
{
ClutterActorMetaClass *actor_meta_class = CLUTTER_ACTOR_META_CLASS (klass);
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
actor_meta_class->set_enabled = clutter_effect_set_enabled;
gobject_class->notify = clutter_effect_notify;
klass->pre_paint = clutter_effect_real_pre_paint;
klass->post_paint = clutter_effect_real_post_paint;

View File

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

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -692,6 +692,20 @@ _clutter_input_device_free_touch_info (gpointer data)
g_slice_free (ClutterTouchInfo, data);
}
static ClutterActor *
_clutter_input_device_get_actor (ClutterInputDevice *device,
ClutterEventSequence *sequence)
{
ClutterTouchInfo *info;
if (sequence == NULL)
return device->cursor_actor;
info = g_hash_table_lookup (device->touch_sequences_info, sequence);
return info->actor;
}
static void
_clutter_input_device_associate_actor (ClutterInputDevice *device,
ClutterEventSequence *sequence,
@@ -801,7 +815,7 @@ _clutter_input_device_set_actor (ClutterInputDevice *device,
ClutterActor *actor,
gboolean emit_crossing)
{
ClutterActor *old_actor = clutter_input_device_get_actor (device, sequence);
ClutterActor *old_actor = _clutter_input_device_get_actor (device, sequence);
if (old_actor == actor)
return;
@@ -836,7 +850,7 @@ _clutter_input_device_set_actor (ClutterInputDevice *device,
}
/* processing the event might have destroyed the actor */
tmp_old_actor = clutter_input_device_get_actor (device, sequence);
tmp_old_actor = _clutter_input_device_get_actor (device, sequence);
_clutter_input_device_unassociate_actor (device,
old_actor,
tmp_old_actor == NULL);
@@ -1040,7 +1054,7 @@ clutter_input_device_update (ClutterInputDevice *device,
clutter_input_device_get_coords (device, sequence, &point);
old_cursor_actor = clutter_input_device_get_actor (device, sequence);
old_cursor_actor = _clutter_input_device_get_actor (device, sequence);
new_cursor_actor =
_clutter_stage_do_pick (stage, point.x, point.y, CLUTTER_PICK_REACTIVE);
@@ -1071,33 +1085,22 @@ clutter_input_device_update (ClutterInputDevice *device,
}
/**
* clutter_input_device_get_actor:
* @device: a #ClutterInputDevice
* @sequence: (allow-none): an optional #ClutterEventSequence
* clutter_input_device_get_pointer_actor:
* @device: a #ClutterInputDevice of type %CLUTTER_POINTER_DEVICE
*
* Retrieves the #ClutterActor underneath the pointer or touchpoint
* of @device and @sequence.
* Retrieves the #ClutterActor underneath the pointer of @device
*
* Return value: (transfer none): a pointer to the #ClutterActor or %NULL
*
* Since: 1.2
*/
ClutterActor *
clutter_input_device_get_actor (ClutterInputDevice *device,
ClutterEventSequence *sequence)
clutter_input_device_get_pointer_actor (ClutterInputDevice *device)
{
ClutterTouchInfo *info;
g_return_val_if_fail (CLUTTER_IS_INPUT_DEVICE (device), NULL);
g_return_val_if_fail (device->device_type == CLUTTER_POINTER_DEVICE, NULL);
if (sequence == NULL)
return device->cursor_actor;
info = g_hash_table_lookup (device->touch_sequences_info, sequence);
g_return_val_if_fail (info != NULL, NULL);
return info->actor;
return device->cursor_actor;
}
/**

View File

@@ -92,8 +92,7 @@ gboolean clutter_input_device_get_coords (ClutterInputDevi
CLUTTER_EXPORT
ClutterModifierType clutter_input_device_get_modifier_state (ClutterInputDevice *device);
CLUTTER_EXPORT
ClutterActor * clutter_input_device_get_actor (ClutterInputDevice *device,
ClutterEventSequence *sequence);
ClutterActor * clutter_input_device_get_pointer_actor (ClutterInputDevice *device);
CLUTTER_EXPORT
ClutterStage * clutter_input_device_get_pointer_stage (ClutterInputDevice *device);
CLUTTER_EXPORT

View File

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

View File

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

View File

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

View File

@@ -1653,8 +1653,6 @@ static inline void
emit_keyboard_event (ClutterEvent *event,
ClutterInputDevice *device)
{
cally_snoop_key_event ((ClutterKeyEvent *) event);
if (_clutter_event_process_filters (event))
return;
@@ -2051,8 +2049,7 @@ _clutter_process_event_details (ClutterActor *stage,
emit_touch_event (event, device);
if (event->type == CLUTTER_TOUCH_END ||
event->type == CLUTTER_TOUCH_CANCEL)
if (event->type == CLUTTER_TOUCH_END)
_clutter_input_device_remove_event_sequence (device, event);
break;
@@ -2087,8 +2084,7 @@ _clutter_process_event_details (ClutterActor *stage,
emit_touch_event (event, device);
if (event->type == CLUTTER_TOUCH_END ||
event->type == CLUTTER_TOUCH_CANCEL)
if (event->type == CLUTTER_TOUCH_END)
_clutter_input_device_remove_event_sequence (device, event);
break;
@@ -2396,7 +2392,8 @@ clutter_threads_add_repaint_func_full (ClutterRepaintFlags flags,
repaint_func->id = context->last_repaint_id++;
repaint_func->flags = flags;
/* 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->func = func;
repaint_func->data = data;
repaint_func->notify = notify;
@@ -2406,6 +2403,13 @@ 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

@@ -190,6 +190,26 @@ master_clock_get_swap_wait_time (ClutterMasterClockDefault *master_clock)
}
}
static int64_t
master_clock_get_next_presentation_time (ClutterMasterClockDefault *master_clock)
{
ClutterStageManager *stage_manager = clutter_stage_manager_get_default ();
const GSList *stages, *l;
int64_t earliest = -1;
stages = clutter_stage_manager_peek_stages (stage_manager);
for (l = stages; l != NULL; l = l->next)
{
gint64 t = _clutter_stage_get_next_presentation_time (l->data);
if (earliest == -1 || (t != -1 && t < earliest))
earliest = t;
}
return earliest;
}
static void
master_clock_schedule_stage_updates (ClutterMasterClockDefault *master_clock)
{
@@ -199,7 +219,7 @@ master_clock_schedule_stage_updates (ClutterMasterClockDefault *master_clock)
stages = clutter_stage_manager_peek_stages (stage_manager);
for (l = stages; l != NULL; l = l->next)
clutter_stage_schedule_update (l->data);
_clutter_stage_schedule_update (l->data);
}
static GSList *
@@ -252,7 +272,7 @@ master_clock_reschedule_stage_updates (ClutterMasterClockDefault *master_clock,
if (master_clock->timelines ||
_clutter_stage_has_queued_events (l->data) ||
_clutter_stage_needs_update (l->data))
clutter_stage_schedule_update (l->data);
_clutter_stage_schedule_update (l->data);
}
}
@@ -466,7 +486,11 @@ clutter_clock_dispatch (GSource *source,
COGL_TRACE_BEGIN (ClutterMasterClockTick, "Master Clock (tick)");
/* Get the time to use for this frame */
master_clock->cur_tick = g_source_get_time (source);
master_clock->cur_tick = master_clock_get_next_presentation_time (master_clock);
/* On the first frame the backend might not have an answer */
if (master_clock->cur_tick <= 0)
master_clock->cur_tick = g_source_get_time (source);
#ifdef CLUTTER_ENABLE_DEBUG
master_clock->remaining_budget = master_clock->frame_budget;

View File

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

View File

@@ -81,7 +81,7 @@
struct _ClutterOffscreenEffectPrivate
{
CoglHandle offscreen;
CoglPipeline *pipeline;
CoglPipeline *target;
CoglHandle texture;
ClutterActor *actor;
@@ -140,7 +140,7 @@ ensure_pipeline_filter_for_scale (ClutterOffscreenEffect *self,
{
CoglPipelineFilter filter;
if (!self->priv->pipeline)
if (!self->priv->target)
return;
/* If no fractional scaling is set, we're always going to render the texture
@@ -154,7 +154,7 @@ ensure_pipeline_filter_for_scale (ClutterOffscreenEffect *self,
else
filter = COGL_PIPELINE_FILTER_LINEAR;
cogl_pipeline_set_layer_filters (self->priv->pipeline, 0 /* layer_index */,
cogl_pipeline_set_layer_filters (self->priv->target, 0 /* layer_index */,
filter, filter);
}
@@ -185,12 +185,12 @@ update_fbo (ClutterEffect *effect,
return TRUE;
}
if (priv->pipeline == NULL)
if (priv->target == NULL)
{
CoglContext *ctx =
clutter_backend_get_cogl_context (clutter_get_default_backend ());
priv->pipeline = cogl_pipeline_new (ctx);
priv->target = cogl_pipeline_new (ctx);
ensure_pipeline_filter_for_scale (self, resource_scale);
}
@@ -202,7 +202,7 @@ update_fbo (ClutterEffect *effect,
if (priv->texture == NULL)
return FALSE;
cogl_pipeline_set_layer_texture (priv->pipeline, 0, priv->texture);
cogl_pipeline_set_layer_texture (priv->target, 0, priv->texture);
priv->target_width = target_width;
priv->target_height = target_height;
@@ -212,8 +212,8 @@ update_fbo (ClutterEffect *effect,
{
g_warning ("%s: Unable to create an Offscreen buffer", G_STRLOC);
cogl_object_unref (priv->pipeline);
priv->pipeline = NULL;
cogl_object_unref (priv->target);
priv->target = NULL;
priv->target_width = 0;
priv->target_height = 0;
@@ -380,7 +380,7 @@ clutter_offscreen_effect_real_paint_target (ClutterOffscreenEffect *effect,
paint_opacity = clutter_actor_get_paint_opacity (priv->actor);
cogl_pipeline_set_color4ub (priv->pipeline,
cogl_pipeline_set_color4ub (priv->target,
paint_opacity,
paint_opacity,
paint_opacity,
@@ -392,7 +392,7 @@ clutter_offscreen_effect_real_paint_target (ClutterOffscreenEffect *effect,
* hadn't been redirected offscreen.
*/
cogl_framebuffer_draw_textured_rectangle (framebuffer,
priv->pipeline,
priv->target,
0, 0,
cogl_texture_get_width (priv->texture),
cogl_texture_get_height (priv->texture),
@@ -446,16 +446,13 @@ clutter_offscreen_effect_post_paint (ClutterEffect *effect,
ClutterOffscreenEffectPrivate *priv = self->priv;
CoglFramebuffer *framebuffer;
g_warn_if_fail (priv->offscreen);
g_warn_if_fail (priv->pipeline);
g_warn_if_fail (priv->actor);
if (priv->offscreen == NULL ||
priv->target == NULL ||
priv->actor == NULL)
return;
/* Restore the previous opacity override */
if (priv->actor)
{
clutter_actor_set_opacity_override (priv->actor,
priv->old_opacity_override);
}
clutter_actor_set_opacity_override (priv->actor, priv->old_opacity_override);
framebuffer = clutter_paint_context_get_framebuffer (paint_context);
cogl_framebuffer_pop_matrix (framebuffer);
@@ -501,17 +498,16 @@ clutter_offscreen_effect_paint (ClutterEffect *effect,
}
static void
clutter_offscreen_effect_set_enabled (ClutterActorMeta *meta,
gboolean is_enabled)
clutter_offscreen_effect_notify (GObject *gobject,
GParamSpec *pspec)
{
ClutterActorMetaClass *parent_class =
CLUTTER_ACTOR_META_CLASS (clutter_offscreen_effect_parent_class);
ClutterOffscreenEffect *offscreen_effect = CLUTTER_OFFSCREEN_EFFECT (meta);
ClutterOffscreenEffect *offscreen_effect = CLUTTER_OFFSCREEN_EFFECT (gobject);
ClutterOffscreenEffectPrivate *priv = offscreen_effect->priv;
g_clear_pointer (&priv->offscreen, cogl_object_unref);
if (strcmp (pspec->name, "enabled") == 0)
g_clear_pointer (&priv->offscreen, cogl_object_unref);
parent_class->set_enabled (meta, is_enabled);
G_OBJECT_CLASS (clutter_offscreen_effect_parent_class)->notify (gobject, pspec);
}
static void
@@ -522,7 +518,7 @@ clutter_offscreen_effect_finalize (GObject *gobject)
g_clear_pointer (&priv->offscreen, cogl_object_unref);
g_clear_pointer (&priv->texture, cogl_object_unref);
g_clear_pointer (&priv->pipeline, cogl_object_unref);
g_clear_pointer (&priv->target, cogl_object_unref);
G_OBJECT_CLASS (clutter_offscreen_effect_parent_class)->finalize (gobject);
}
@@ -538,13 +534,13 @@ clutter_offscreen_effect_class_init (ClutterOffscreenEffectClass *klass)
klass->paint_target = clutter_offscreen_effect_real_paint_target;
meta_class->set_actor = clutter_offscreen_effect_set_actor;
meta_class->set_enabled = clutter_offscreen_effect_set_enabled;
effect_class->pre_paint = clutter_offscreen_effect_pre_paint;
effect_class->post_paint = clutter_offscreen_effect_post_paint;
effect_class->paint = clutter_offscreen_effect_paint;
gobject_class->finalize = clutter_offscreen_effect_finalize;
gobject_class->notify = clutter_offscreen_effect_notify;
}
static void
@@ -604,7 +600,7 @@ clutter_offscreen_effect_get_target (ClutterOffscreenEffect *effect)
g_return_val_if_fail (CLUTTER_IS_OFFSCREEN_EFFECT (effect),
NULL);
return (CoglMaterial *)effect->priv->pipeline;
return (CoglMaterial *)effect->priv->target;
}
/**

View File

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

View File

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

View File

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

View File

@@ -83,6 +83,7 @@ typedef enum
PAINT_OP_INVALID = 0,
PAINT_OP_TEX_RECT,
PAINT_OP_MULTITEX_RECT,
PAINT_OP_PATH,
PAINT_OP_PRIMITIVE
} PaintOpCode;
@@ -95,6 +96,8 @@ struct _ClutterPaintOperation
union {
float texrect[8];
CoglPath *path;
CoglPrimitive *primitive;
} op;
};

View File

@@ -782,6 +782,11 @@ clutter_paint_operation_clear (ClutterPaintOperation *op)
g_array_unref (op->multitex_coords);
break;
case PAINT_OP_PATH:
if (op->op.path != NULL)
cogl_object_unref (op->op.path);
break;
case PAINT_OP_PRIMITIVE:
if (op->op.primitive != NULL)
cogl_object_unref (op->op.primitive);
@@ -831,6 +836,16 @@ clutter_paint_op_init_multitex_rect (ClutterPaintOperation *op,
op->op.texrect[3] = rect->y2;
}
static inline void
clutter_paint_op_init_path (ClutterPaintOperation *op,
CoglPath *path)
{
clutter_paint_operation_clear (op);
op->opcode = PAINT_OP_PATH;
op->op.path = cogl_object_ref (path);
}
static inline void
clutter_paint_op_init_primitive (ClutterPaintOperation *op,
CoglPrimitive *primitive)
@@ -935,6 +950,34 @@ clutter_paint_node_add_multitexture_rectangle (ClutterPaintNode *node,
g_array_append_val (node->operations, operation);
}
/**
* clutter_paint_node_add_path: (skip)
* @node: a #ClutterPaintNode
* @path: a Cogl path
*
* Adds a region described as a path to the @node.
*
* This function acquires a reference on the passed @path, so it
* is safe to call cogl_object_unref() when it returns.
*
* Since: 1.10
* Stability: unstable
*/
void
clutter_paint_node_add_path (ClutterPaintNode *node,
CoglPath *path)
{
ClutterPaintOperation operation = PAINT_OP_INIT;
g_return_if_fail (CLUTTER_IS_PAINT_NODE (node));
g_return_if_fail (cogl_is_path (path));
clutter_paint_node_maybe_init_operations (node);
clutter_paint_op_init_path (&operation, path);
g_array_append_val (node->operations, operation);
}
/**
* clutter_paint_node_add_primitive: (skip)
* @node: a #ClutterPaintNode
@@ -1071,6 +1114,11 @@ clutter_paint_node_to_json (ClutterPaintNode *node)
json_builder_end_array (builder);
break;
case PAINT_OP_PATH:
json_builder_set_member_name (builder, "path");
json_builder_add_int_value (builder, (intptr_t) op->op.path);
break;
case PAINT_OP_PRIMITIVE:
json_builder_set_member_name (builder, "primitive");
json_builder_add_int_value (builder, (intptr_t) op->op.primitive);

View File

@@ -84,6 +84,9 @@ void clutter_paint_node_add_multitexture_rectangle (ClutterP
unsigned int text_coords_len);
CLUTTER_EXPORT
void clutter_paint_node_add_path (ClutterPaintNode *node,
CoglPath *path);
CLUTTER_EXPORT
void clutter_paint_node_add_primitive (ClutterPaintNode *node,
CoglPrimitive *primitive);

View File

@@ -477,6 +477,10 @@ clutter_pipeline_node_draw (ClutterPaintNode *node,
op->multitex_coords->len);
break;
case PAINT_OP_PATH:
cogl_framebuffer_fill_path (fb, pnode->pipeline, op->op.path);
break;
case PAINT_OP_PRIMITIVE:
cogl_framebuffer_draw_primitive (fb,
pnode->pipeline,
@@ -872,6 +876,7 @@ clutter_text_node_draw (ClutterPaintNode *node,
break;
case PAINT_OP_MULTITEX_RECT:
case PAINT_OP_PATH:
case PAINT_OP_PRIMITIVE:
case PAINT_OP_INVALID:
break;
@@ -1032,6 +1037,11 @@ clutter_clip_node_pre_draw (ClutterPaintNode *node,
retval = TRUE;
break;
case PAINT_OP_PATH:
cogl_framebuffer_push_path_clip (fb, op->op.path);
retval = TRUE;
break;
case PAINT_OP_MULTITEX_RECT:
case PAINT_OP_PRIMITIVE:
case PAINT_OP_INVALID:
@@ -1062,6 +1072,7 @@ clutter_clip_node_post_draw (ClutterPaintNode *node,
switch (op->opcode)
{
case PAINT_OP_PATH:
case PAINT_OP_TEX_RECT:
cogl_framebuffer_pop_clip (fb);
break;
@@ -1231,8 +1242,9 @@ struct _ClutterLayerNode
float fbo_width;
float fbo_height;
CoglPipeline *pipeline;
CoglPipeline *state;
CoglFramebuffer *offscreen;
CoglTexture *texture;
guint8 opacity;
};
@@ -1322,7 +1334,7 @@ clutter_layer_node_post_draw (ClutterPaintNode *node,
case PAINT_OP_TEX_RECT:
/* now we need to paint the texture */
cogl_framebuffer_draw_textured_rectangle (fb,
lnode->pipeline,
lnode->state,
op->op.texrect[0],
op->op.texrect[1],
op->op.texrect[2],
@@ -1335,7 +1347,7 @@ clutter_layer_node_post_draw (ClutterPaintNode *node,
case PAINT_OP_MULTITEX_RECT:
cogl_framebuffer_draw_multitextured_rectangle (fb,
lnode->pipeline,
lnode->state,
op->op.texrect[0],
op->op.texrect[1],
op->op.texrect[2],
@@ -1344,10 +1356,12 @@ clutter_layer_node_post_draw (ClutterPaintNode *node,
op->multitex_coords->len);
break;
case PAINT_OP_PATH:
cogl_framebuffer_fill_path (fb, lnode->state, op->op.path);
break;
case PAINT_OP_PRIMITIVE:
cogl_framebuffer_draw_primitive (fb,
lnode->pipeline,
op->op.primitive);
cogl_framebuffer_draw_primitive (fb, lnode->state, op->op.primitive);
break;
}
}
@@ -1358,8 +1372,8 @@ clutter_layer_node_finalize (ClutterPaintNode *node)
{
ClutterLayerNode *lnode = CLUTTER_LAYER_NODE (node);
if (lnode->pipeline != NULL)
cogl_object_unref (lnode->pipeline);
if (lnode->state != NULL)
cogl_object_unref (lnode->state);
if (lnode->offscreen != NULL)
cogl_object_unref (lnode->offscreen);
@@ -1411,8 +1425,6 @@ clutter_layer_node_new (const CoglMatrix *projection,
guint8 opacity)
{
ClutterLayerNode *res;
CoglContext *context;
CoglTexture *texture;
CoglColor color;
res = _clutter_paint_node_create (CLUTTER_TYPE_LAYER_NODE);
@@ -1424,17 +1436,19 @@ clutter_layer_node_new (const CoglMatrix *projection,
res->opacity = opacity;
/* the texture backing the FBO */
context = clutter_backend_get_cogl_context (clutter_get_default_backend ());
res->texture = cogl_texture_new_with_size (MAX (res->fbo_width, 1),
MAX (res->fbo_height, 1),
COGL_TEXTURE_NO_SLICING,
COGL_PIXEL_FORMAT_RGBA_8888_PRE);
texture = cogl_texture_2d_new_with_size (context,
MAX (res->fbo_width, 1),
MAX (res->fbo_height, 1));
cogl_texture_set_premultiplied (texture, TRUE);
res->offscreen = COGL_FRAMEBUFFER (cogl_offscreen_new_to_texture (texture));
res->offscreen = COGL_FRAMEBUFFER (cogl_offscreen_new_to_texture (res->texture));
if (res->offscreen == NULL)
{
g_critical ("%s: Unable to create an offscreen buffer", G_STRLOC);
cogl_object_unref (res->texture);
res->texture = NULL;
goto out;
}
@@ -1444,15 +1458,14 @@ clutter_layer_node_new (const CoglMatrix *projection,
* interpolation filters because the texture is always
* going to be painted at a 1:1 texel:pixel ratio
*/
res->pipeline = cogl_pipeline_copy (default_texture_pipeline);
cogl_pipeline_set_layer_filters (res->pipeline, 0,
res->state = cogl_pipeline_copy (default_texture_pipeline);
cogl_pipeline_set_layer_filters (res->state, 0,
COGL_PIPELINE_FILTER_NEAREST,
COGL_PIPELINE_FILTER_NEAREST);
cogl_pipeline_set_layer_texture (res->pipeline, 0, texture);
cogl_pipeline_set_color (res->pipeline, &color);
cogl_pipeline_set_layer_texture (res->state, 0, res->texture);
cogl_pipeline_set_color (res->state, &color);
cogl_object_unref (res->texture);
out:
cogl_object_unref (texture);
return (ClutterPaintNode *) res;
}

View File

@@ -136,8 +136,7 @@ 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,
@@ -157,18 +156,14 @@ 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)))
@@ -287,10 +282,7 @@ 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)
{
@@ -301,9 +293,7 @@ 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))
@@ -314,22 +304,17 @@ 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);
@@ -382,8 +367,7 @@ 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:
@@ -427,11 +411,9 @@ static void
clutter_pan_action_constructed (GObject *gobject)
{
ClutterGestureAction *gesture;
ClutterGestureTriggerEdge edge;
gesture = CLUTTER_GESTURE_ACTION (gobject);
edge = CLUTTER_GESTURE_TRIGGER_EDGE_AFTER;
clutter_gesture_action_set_threshold_trigger_edge (gesture, edge);
clutter_gesture_action_set_threshold_trigger_edge (gesture, CLUTTER_GESTURE_TRIGGER_EDGE_AFTER);
}
static void
@@ -460,8 +442,7 @@ 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);
}
@@ -899,9 +880,7 @@ 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

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -354,17 +354,6 @@ clutter_seat_get_keyboard (ClutterSeat *seat)
return CLUTTER_SEAT_GET_CLASS (seat)->get_keyboard (seat);
}
/**
* clutter_seat_peek_devices: (skip)
**/
const GList *
clutter_seat_peek_devices (ClutterSeat *seat)
{
g_return_val_if_fail (CLUTTER_IS_SEAT (seat), NULL);
return CLUTTER_SEAT_GET_CLASS (seat)->peek_devices (seat);
}
/**
* clutter_seat_list_devices:
* @seat: a #ClutterSeat
@@ -381,7 +370,7 @@ clutter_seat_list_devices (ClutterSeat *seat)
{
g_return_val_if_fail (CLUTTER_IS_SEAT (seat), NULL);
return g_list_copy ((GList *)clutter_seat_peek_devices (seat));
return CLUTTER_SEAT_GET_CLASS (seat)->list_devices (seat);
}
void
@@ -645,8 +634,8 @@ clutter_seat_create_virtual_device (ClutterSeat *seat,
}
/**
* clutter_seat_get_supported_virtual_device_types: (skip)
**/
* clutter_seat_supported_virtual_device_types: (skip)
*/
ClutterVirtualDeviceType
clutter_seat_get_supported_virtual_device_types (ClutterSeat *seat)
{
@@ -693,6 +682,7 @@ 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

@@ -96,7 +96,7 @@ struct _ClutterSeatClass
ClutterInputDevice * (* get_pointer) (ClutterSeat *seat);
ClutterInputDevice * (* get_keyboard) (ClutterSeat *seat);
const GList * (* peek_devices) (ClutterSeat *seat);
GList * (* list_devices) (ClutterSeat *seat);
void (* bell_notify) (ClutterSeat *seat);
@@ -133,7 +133,6 @@ CLUTTER_EXPORT
ClutterInputDevice * clutter_seat_get_keyboard (ClutterSeat *seat);
CLUTTER_EXPORT
GList * clutter_seat_list_devices (ClutterSeat *seat);
const GList * clutter_seat_peek_devices (ClutterSeat *seat);
CLUTTER_EXPORT
void clutter_seat_bell_notify (ClutterSeat *seat);

View File

@@ -50,6 +50,11 @@ 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,
@@ -69,9 +74,11 @@ void _clutter_stage_queue_event (ClutterStage *stage,
gboolean _clutter_stage_has_queued_events (ClutterStage *stage);
void _clutter_stage_process_queued_events (ClutterStage *stage);
void _clutter_stage_update_input_devices (ClutterStage *stage);
void _clutter_stage_schedule_update (ClutterStage *stage);
gint64 _clutter_stage_get_update_time (ClutterStage *stage);
void _clutter_stage_clear_update_time (ClutterStage *stage);
gboolean _clutter_stage_has_full_redraw_queued (ClutterStage *stage);
int64_t _clutter_stage_get_next_presentation_time (ClutterStage *stage);
void clutter_stage_log_pick (ClutterStage *stage,
const graphene_point_t *vertices,
@@ -125,17 +132,19 @@ 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,
ClutterFrameInfo *frame_info);
GList * _clutter_stage_peek_stage_views (ClutterStage *stage);
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

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

View File

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

View File

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

View File

@@ -62,6 +62,16 @@ _clutter_stage_window_set_title (ClutterStageWindow *window,
iface->set_title (window, title);
}
void
_clutter_stage_window_set_cursor_visible (ClutterStageWindow *window,
gboolean is_visible)
{
ClutterStageWindowInterface *iface = CLUTTER_STAGE_WINDOW_GET_IFACE (window);
if (iface->set_cursor_visible)
iface->set_cursor_visible (window, is_visible);
}
gboolean
_clutter_stage_window_realize (ClutterStageWindow *window)
{
@@ -168,6 +178,35 @@ _clutter_stage_window_clear_update_time (ClutterStageWindow *window)
iface->clear_update_time (window);
}
int64_t
_clutter_stage_window_get_next_presentation_time (ClutterStageWindow *window)
{
ClutterStageWindowInterface *iface;
g_return_val_if_fail (CLUTTER_IS_STAGE_WINDOW (window), 0);
iface = CLUTTER_STAGE_WINDOW_GET_IFACE (window);
/* If not implemented then just revert to the old behaviour... */
if (iface->get_next_presentation_time == NULL)
return _clutter_stage_window_get_update_time (window);
return iface->get_next_presentation_time (window);
}
void
_clutter_stage_window_set_accept_focus (ClutterStageWindow *window,
gboolean accept_focus)
{
ClutterStageWindowInterface *iface;
g_return_if_fail (CLUTTER_IS_STAGE_WINDOW (window));
iface = CLUTTER_STAGE_WINDOW_GET_IFACE (window);
if (iface->set_accept_focus)
iface->set_accept_focus (window, accept_focus);
}
void
_clutter_stage_window_redraw (ClutterStageWindow *window)
{

View File

@@ -30,6 +30,8 @@ struct _ClutterStageWindowInterface
void (* set_title) (ClutterStageWindow *stage_window,
const gchar *title);
void (* set_cursor_visible) (ClutterStageWindow *stage_window,
gboolean cursor_visible);
gboolean (* realize) (ClutterStageWindow *stage_window);
void (* unrealize) (ClutterStageWindow *stage_window);
@@ -49,6 +51,9 @@ struct _ClutterStageWindowInterface
gint64 (* get_update_time) (ClutterStageWindow *stage_window);
void (* clear_update_time) (ClutterStageWindow *stage_window);
void (* set_accept_focus) (ClutterStageWindow *stage_window,
gboolean accept_focus);
void (* redraw) (ClutterStageWindow *stage_window);
gboolean (* can_clip_redraws) (ClutterStageWindow *stage_window);
@@ -56,6 +61,8 @@ struct _ClutterStageWindowInterface
GList *(* get_views) (ClutterStageWindow *stage_window);
int64_t (* get_frame_counter) (ClutterStageWindow *stage_window);
void (* finish_frame) (ClutterStageWindow *stage_window);
int64_t (* get_next_presentation_time) (ClutterStageWindow *stage_window);
};
ClutterActor * _clutter_stage_window_get_wrapper (ClutterStageWindow *window);
@@ -96,6 +103,8 @@ void _clutter_stage_window_finish_frame (ClutterStageWin
int64_t _clutter_stage_window_get_frame_counter (ClutterStageWindow *window);
int64_t _clutter_stage_window_get_next_presentation_time (ClutterStageWindow *window);
G_END_DECLS
#endif /* __CLUTTER_STAGE_WINDOW_H__ */

File diff suppressed because it is too large Load Diff

View File

@@ -103,7 +103,8 @@ struct _ClutterStageClass
* @z_far: the distance from the viewer to the far clipping
* plane (always positive)
*
* Stage perspective definition.
* Stage perspective definition. #ClutterPerspective is only used by
* the fixed point version of clutter_stage_set_perspective().
*
* Since: 0.4
*/
@@ -139,10 +140,17 @@ GType clutter_stage_get_type (void) G_GNUC_CONST;
CLUTTER_EXPORT
ClutterActor * clutter_stage_new (void);
CLUTTER_EXPORT
void clutter_stage_set_perspective (ClutterStage *stage,
ClutterPerspective *perspective);
CLUTTER_EXPORT
void clutter_stage_get_perspective (ClutterStage *stage,
ClutterPerspective *perspective);
CLUTTER_EXPORT
void clutter_stage_show_cursor (ClutterStage *stage);
CLUTTER_EXPORT
void clutter_stage_hide_cursor (ClutterStage *stage);
CLUTTER_EXPORT
void clutter_stage_set_title (ClutterStage *stage,
const gchar *title);
CLUTTER_EXPORT
@@ -178,6 +186,11 @@ void clutter_stage_set_motion_events_enabled (ClutterStage
CLUTTER_EXPORT
gboolean clutter_stage_get_motion_events_enabled (ClutterStage *stage);
CLUTTER_EXPORT
void clutter_stage_set_accept_focus (ClutterStage *stage,
gboolean accept_focus);
CLUTTER_EXPORT
gboolean clutter_stage_get_accept_focus (ClutterStage *stage);
CLUTTER_EXPORT
gboolean clutter_stage_event (ClutterStage *stage,
ClutterEvent *event);
@@ -195,6 +208,8 @@ 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);
@@ -207,9 +222,6 @@ CLUTTER_EXPORT
void clutter_stage_skip_sync_delay (ClutterStage *stage);
#endif
CLUTTER_EXPORT
void clutter_stage_schedule_update (ClutterStage *stage);
CLUTTER_EXPORT
gboolean clutter_stage_get_capture_final_size (ClutterStage *stage,
cairo_rectangle_int_t *rect,

View File

@@ -1907,6 +1907,14 @@ clutter_text_foreach_selection_rectangle (ClutterText *self,
g_free (utf8);
}
static void
add_selection_rectangle_to_path (ClutterText *text,
const ClutterActorBox *box,
gpointer user_data)
{
cogl_path_rectangle (user_data, box->x1, box->y1, box->x2, box->y2);
}
static void
clutter_text_foreach_selection_rectangle_prescaled (ClutterText *self,
ClutterTextSelectionFunc func,
@@ -1915,60 +1923,6 @@ clutter_text_foreach_selection_rectangle_prescaled (ClutterText *se
clutter_text_foreach_selection_rectangle (self, 1.0f, func, user_data);
}
static void
paint_selection_rectangle (ClutterText *self,
const ClutterActorBox *box,
gpointer user_data)
{
CoglFramebuffer *fb = user_data;
ClutterTextPrivate *priv = self->priv;
ClutterActor *actor = CLUTTER_ACTOR (self);
guint8 paint_opacity = clutter_actor_get_paint_opacity (actor);
CoglPipeline *color_pipeline = cogl_pipeline_copy (default_color_pipeline);
PangoLayout *layout = clutter_text_get_layout (self);
CoglColor cogl_color = { 0, };
const ClutterColor *color;
/* Paint selection background */
if (priv->selection_color_set)
color = &priv->selection_color;
else if (priv->cursor_color_set)
color = &priv->cursor_color;
else
color = &priv->text_color;
cogl_color_init_from_4ub (&cogl_color,
color->red,
color->green,
color->blue,
paint_opacity * color->alpha / 255);
cogl_color_premultiply (&cogl_color);
cogl_pipeline_set_color (color_pipeline, &cogl_color);
cogl_framebuffer_push_rectangle_clip (fb,
box->x1, box->y1,
box->x2, box->y2);
cogl_framebuffer_draw_rectangle (fb, color_pipeline,
box->x1, box->y1,
box->x2, box->y2);
if (priv->selected_text_color_set)
color = &priv->selected_text_color;
else
color = &priv->text_color;
cogl_color_init_from_4ub (&cogl_color,
color->red,
color->green,
color->blue,
paint_opacity * color->alpha / 255);
cogl_pango_show_layout (fb, layout, priv->text_x, 0, &cogl_color);
cogl_framebuffer_pop_clip (fb);
cogl_object_unref (color_pipeline);
}
/* Draws the selected text, its background, and the cursor */
static void
selection_paint (ClutterText *self,
@@ -2011,9 +1965,52 @@ selection_paint (ClutterText *self,
}
else
{
/* Paint selection background first */
CoglPipeline *color_pipeline = cogl_pipeline_copy (default_color_pipeline);
PangoLayout *layout = clutter_text_get_layout (self);
CoglPath *selection_path = cogl_path_new ();
CoglColor cogl_color = { 0, };
/* Paint selection background */
if (priv->selection_color_set)
color = &priv->selection_color;
else if (priv->cursor_color_set)
color = &priv->cursor_color;
else
color = &priv->text_color;
cogl_color_init_from_4ub (&cogl_color,
color->red,
color->green,
color->blue,
paint_opacity * color->alpha / 255);
cogl_color_premultiply (&cogl_color);
cogl_pipeline_set_color (color_pipeline, &cogl_color);
clutter_text_foreach_selection_rectangle_prescaled (self,
paint_selection_rectangle,
fb);
add_selection_rectangle_to_path,
selection_path);
cogl_framebuffer_fill_path (fb, color_pipeline, selection_path);
/* Paint selected text */
cogl_framebuffer_push_path_clip (fb, selection_path);
cogl_object_unref (selection_path);
if (priv->selected_text_color_set)
color = &priv->selected_text_color;
else
color = &priv->text_color;
cogl_color_init_from_4ub (&cogl_color,
color->red,
color->green,
color->blue,
paint_opacity * color->alpha / 255);
cogl_pango_show_layout (fb, layout, priv->text_x, 0, &cogl_color);
cogl_framebuffer_pop_clip (fb);
}
}
@@ -3037,7 +3034,8 @@ clutter_text_get_preferred_height (ClutterActor *self,
static void
clutter_text_allocate (ClutterActor *self,
const ClutterActorBox *box)
const ClutterActorBox *box,
ClutterAllocationFlags flags)
{
ClutterText *text = CLUTTER_TEXT (self);
ClutterActorClass *parent_class;
@@ -3057,7 +3055,7 @@ clutter_text_allocate (ClutterActor *self,
box->y2 - box->y1);
parent_class = CLUTTER_ACTOR_CLASS (clutter_text_parent_class);
parent_class->allocate (self, box);
parent_class->allocate (self, box, flags);
}
static gboolean
@@ -4786,11 +4784,11 @@ clutter_text_queue_redraw_or_relayout (ClutterText *self)
clutter_text_get_preferred_height (actor, preferred_width, NULL, &preferred_height);
if (clutter_actor_has_allocation (actor) &&
fabsf (preferred_width - clutter_actor_get_width (actor)) <= 0.001 &&
fabsf (preferred_height - clutter_actor_get_height (actor)) <= 0.001)
clutter_text_queue_redraw (actor);
else
(fabsf (preferred_width - clutter_actor_get_width (actor)) > 0.001 ||
fabsf (preferred_height - clutter_actor_get_height (actor)) > 0.001))
clutter_actor_queue_relayout (actor);
else
clutter_text_queue_redraw (actor);
}
static void

View File

@@ -24,6 +24,7 @@
/**
* SECTION:clutter-timeline
* @short_description: A class for time-based events
* @see_also: #ClutterAnimation, #ClutterAnimator, #ClutterState
*
* #ClutterTimeline is a base class for managing time-based event that cause
* Clutter to redraw a stage, such as animations.
@@ -70,7 +71,7 @@
* when reaching completion by using the #ClutterTimeline:auto-reverse property.
*
* Timelines are used in the Clutter animation framework by classes like
* #ClutterTransition.
* #ClutterAnimation, #ClutterAnimator, and #ClutterState.
*
* ## Defining Timelines in ClutterScript
*
@@ -172,6 +173,7 @@ enum
{
PROP_0,
PROP_LOOP,
PROP_DELAY,
PROP_DURATION,
PROP_DIRECTION,
@@ -289,6 +291,23 @@ 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;
@@ -430,6 +449,10 @@ 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;
@@ -471,6 +494,10 @@ 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;
@@ -546,6 +573,25 @@ 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:
*
@@ -1206,6 +1252,45 @@ 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
@@ -1322,10 +1407,48 @@ clutter_timeline_is_playing (ClutterTimeline *timeline)
}
/**
* clutter_timeline_new:
* @duration_ms: Duration of the timeline in milliseconds
* clutter_timeline_clone:
* @timeline: #ClutterTimeline to duplicate.
*
* Creates a new #ClutterTimeline with a duration of @duration_ms milli seconds.
* 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
*
* Creates a new #ClutterTimeline with a duration of @msecs.
*
* Return value: the newly created #ClutterTimeline instance. Use
* g_object_unref() when done using it
@@ -1333,10 +1456,10 @@ clutter_timeline_is_playing (ClutterTimeline *timeline)
* Since: 0.6
*/
ClutterTimeline *
clutter_timeline_new (guint duration_ms)
clutter_timeline_new (guint msecs)
{
return g_object_new (CLUTTER_TYPE_TIMELINE,
"duration", duration_ms,
"duration", msecs,
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 duration_ms);
ClutterTimeline * clutter_timeline_new (guint msecs);
CLUTTER_EXPORT
guint clutter_timeline_get_duration (ClutterTimeline *timeline);

View File

@@ -79,6 +79,10 @@ typedef struct _ClutterKnot ClutterKnot;
typedef struct _ClutterMargin ClutterMargin;
typedef struct _ClutterPerspective ClutterPerspective;
typedef struct _ClutterAlpha ClutterAlpha;
typedef struct _ClutterAnimation ClutterAnimation;
typedef struct _ClutterState ClutterState;
typedef struct _ClutterInputDeviceTool ClutterInputDeviceTool;
typedef struct _ClutterInputDevice ClutterInputDevice;
typedef struct _ClutterVirtualInputDevice ClutterVirtualInputDevice;
@@ -174,20 +178,6 @@ struct _ClutterActorBox
*/
#define CLUTTER_ACTOR_BOX_INIT_ZERO CLUTTER_ACTOR_BOX_INIT (0.f, 0.f, 0.f, 0.f)
/**
* CLUTTER_ACTOR_BOX_UNINITIALIZED:
*
* A simple macro for creating a #ClutterActorBox with a size of -1 when
* declaring it, e.g.:
*
* |[
* ClutterActorBox box = CLUTTER_ACTOR_BOX_UNINITIALIZED;
* ]|
*/
#define CLUTTER_ACTOR_BOX_UNINITIALIZED { .x1 = INFINITY, .y1 = INFINITY, .x2 = -INFINITY, .y2 = -INFINITY }
CLUTTER_EXPORT
GType clutter_actor_box_get_type (void) G_GNUC_CONST;
CLUTTER_EXPORT
@@ -266,9 +256,6 @@ CLUTTER_EXPORT
void clutter_actor_box_scale (ClutterActorBox *box,
gfloat scale);
CLUTTER_EXPORT
gboolean clutter_actor_box_is_initialized (ClutterActorBox *box);
/**
* ClutterKnot:
* @x: X coordinate of the knot

View File

@@ -56,6 +56,8 @@
#include "clutter-content.h"
#include "clutter-deform-effect.h"
#include "clutter-desaturate-effect.h"
#include "clutter-drag-action.h"
#include "clutter-drop-action.h"
#include "clutter-effect.h"
#include "clutter-enums.h"
#include "clutter-enum-types.h"

View File

@@ -38,7 +38,6 @@
#include "clutter-actor-private.h"
#include "clutter-backend-private.h"
#include "clutter-damage-history.h"
#include "clutter-debug.h"
#include "clutter-event.h"
#include "clutter-enum-types.h"
@@ -52,9 +51,13 @@
typedef struct _ClutterStageViewCoglPrivate
{
/* Damage history, in stage view render target framebuffer coordinate space.
/*
* List of previous damaged areas in stage view framebuffer coordinate space.
*/
ClutterDamageHistory *damage_history;
#define DAMAGE_HISTORY_MAX 16
#define DAMAGE_HISTORY(x) ((x) & (DAMAGE_HISTORY_MAX - 1))
cairo_region_t * damage_history[DAMAGE_HISTORY_MAX];
unsigned int damage_index;
} ClutterStageViewCoglPrivate;
G_DEFINE_TYPE_WITH_PRIVATE (ClutterStageViewCogl, clutter_stage_view_cogl,
@@ -232,7 +235,12 @@ clutter_stage_cogl_schedule_update (ClutterStageWindow *stage_window,
stage_cogl->update_time = next_presentation_time - max_render_time_allowed;
if (stage_cogl->update_time == stage_cogl->last_update_time)
stage_cogl->update_time = stage_cogl->last_update_time + refresh_interval;
{
stage_cogl->update_time += refresh_interval;
next_presentation_time += refresh_interval;
}
stage_cogl->next_presentation_time = next_presentation_time;
}
static gint64
@@ -253,6 +261,29 @@ clutter_stage_cogl_clear_update_time (ClutterStageWindow *stage_window)
stage_cogl->last_update_time = stage_cogl->update_time;
stage_cogl->update_time = -1;
stage_cogl->next_presentation_time = -1;
}
static int64_t
clutter_stage_cogl_get_next_presentation_time (ClutterStageWindow *stage_window)
{
ClutterStageCogl *stage_cogl = CLUTTER_STAGE_COGL (stage_window);
int64_t now = g_get_monotonic_time ();
if (stage_cogl->next_presentation_time > 0 &&
stage_cogl->next_presentation_time <= now)
{
CLUTTER_NOTE (BACKEND,
"Missed some frames. Something blocked for over "
"%" G_GINT64_FORMAT "ms.",
(now - stage_cogl->next_presentation_time) / 1000);
stage_cogl->update_time = -1;
clutter_stage_cogl_schedule_update (stage_window,
stage_cogl->last_sync_delay);
}
return stage_cogl->next_presentation_time;
}
static ClutterActor *
@@ -285,13 +316,26 @@ clutter_stage_cogl_resize (ClutterStageWindow *stage_window,
{
}
static inline gboolean
valid_buffer_age (ClutterStageViewCogl *view_cogl,
int age)
{
ClutterStageViewCoglPrivate *view_priv =
clutter_stage_view_cogl_get_instance_private (view_cogl);
if (age <= 0)
return FALSE;
return age < MIN (view_priv->damage_index, DAMAGE_HISTORY_MAX);
}
static void
paint_damage_region (ClutterStageWindow *stage_window,
ClutterStageView *view,
cairo_region_t *swap_region,
cairo_region_t *queued_redraw_clip)
{
CoglFramebuffer *framebuffer = clutter_stage_view_get_framebuffer (view);
CoglFramebuffer *framebuffer = clutter_stage_view_get_onscreen (view);
CoglContext *ctx = cogl_framebuffer_get_context (framebuffer);
static CoglPipeline *overlay_blue = NULL;
ClutterStageCogl *stage_cogl = CLUTTER_STAGE_COGL (stage_window);
@@ -359,29 +403,31 @@ static gboolean
swap_framebuffer (ClutterStageWindow *stage_window,
ClutterStageView *view,
cairo_region_t *swap_region,
gboolean swap_with_damage)
gboolean swap_with_damage,
cairo_region_t *queued_redraw_clip)
{
CoglFramebuffer *framebuffer = clutter_stage_view_get_onscreen (view);
int *damage, n_rects, i;
clutter_stage_view_before_swap_buffer (view, swap_region);
if (G_UNLIKELY ((clutter_paint_debug_flags & CLUTTER_DEBUG_PAINT_DAMAGE_REGION)))
paint_damage_region (stage_window, view, swap_region, queued_redraw_clip);
n_rects = cairo_region_num_rectangles (swap_region);
damage = g_newa (int, n_rects * 4);
for (i = 0; i < n_rects; i++)
{
cairo_rectangle_int_t rect;
cairo_region_get_rectangle (swap_region, i, &rect);
damage[i * 4] = rect.x;
damage[i * 4 + 1] = rect.y;
damage[i * 4 + 2] = rect.width;
damage[i * 4 + 3] = rect.height;
}
if (cogl_is_onscreen (framebuffer))
{
CoglOnscreen *onscreen = COGL_ONSCREEN (framebuffer);
int *damage, n_rects, i;
n_rects = cairo_region_num_rectangles (swap_region);
damage = g_newa (int, n_rects * 4);
for (i = 0; i < n_rects; i++)
{
cairo_rectangle_int_t rect;
cairo_region_get_rectangle (swap_region, i, &rect);
damage[i * 4] = rect.x;
damage[i * 4 + 1] = rect.y;
damage[i * 4 + 2] = rect.width;
damage[i * 4 + 3] = rect.height;
}
/* push on the screen */
if (n_rects > 0 && !swap_with_damage)
@@ -416,6 +462,18 @@ swap_framebuffer (ClutterStageWindow *stage_window,
}
}
static void
scale_and_clamp_rect (const graphene_rect_t *rect,
float scale,
cairo_rectangle_int_t *dest)
{
graphene_rect_t tmp = *rect;
graphene_rect_scale (&tmp, scale, scale, &tmp);
_clutter_util_rectangle_int_extents (&tmp, dest);
}
static cairo_region_t *
offset_scale_and_clamp_region (const cairo_region_t *region,
int offset_x,
@@ -437,52 +495,15 @@ offset_scale_and_clamp_region (const cairo_region_t *region,
rects = freeme = g_new (cairo_rectangle_int_t, n_rects);
for (i = 0; i < n_rects; i++)
{
cairo_rectangle_int_t *rect = &rects[i];
graphene_rect_t tmp;
cairo_region_get_rectangle (region, i, rect);
_clutter_util_rect_from_rectangle (rect, &tmp);
graphene_rect_offset (&tmp, offset_x, offset_y);
graphene_rect_scale (&tmp, scale, scale, &tmp);
_clutter_util_rectangle_int_extents (&tmp, rect);
}
return cairo_region_create_rectangles (rects, n_rects);
}
static cairo_region_t *
scale_offset_and_clamp_region (const cairo_region_t *region,
float scale,
int offset_x,
int offset_y)
{
int n_rects, i;
cairo_rectangle_int_t *rects;
g_autofree cairo_rectangle_int_t *freeme = NULL;
n_rects = cairo_region_num_rectangles (region);
if (n_rects == 0)
return cairo_region_create ();
if (n_rects < MAX_STACK_RECTS)
rects = g_newa (cairo_rectangle_int_t, n_rects);
else
rects = freeme = g_new (cairo_rectangle_int_t, n_rects);
cairo_region_get_rectangle (region, i, &rects[i]);
for (i = 0; i < n_rects; i++)
{
cairo_rectangle_int_t *rect = &rects[i];
graphene_rect_t tmp;
cairo_region_get_rectangle (region, i, rect);
_clutter_util_rect_from_rectangle (rect, &tmp);
graphene_rect_scale (&tmp, scale, scale, &tmp);
_clutter_util_rect_from_rectangle (&rects[i], &tmp);
graphene_rect_offset (&tmp, offset_x, offset_y);
_clutter_util_rectangle_int_extents (&tmp, rect);
scale_and_clamp_rect (&tmp, scale, &rects[i]);
}
return cairo_region_create_rectangles (rects, n_rects);
@@ -498,38 +519,107 @@ paint_stage (ClutterStageCogl *stage_cogl,
_clutter_stage_maybe_setup_viewport (stage, view);
clutter_stage_paint_view (stage, view, redraw_clip);
clutter_stage_view_after_paint (view, redraw_clip);
clutter_stage_view_after_paint (view);
}
static void
fill_current_damage_history (ClutterStageView *view,
cairo_region_t *damage)
{
ClutterStageViewCogl *view_cogl = CLUTTER_STAGE_VIEW_COGL (view);
ClutterStageViewCoglPrivate *view_priv =
clutter_stage_view_cogl_get_instance_private (view_cogl);
cairo_region_t **current_fb_damage;
current_fb_damage =
&view_priv->damage_history[DAMAGE_HISTORY (view_priv->damage_index)];
g_clear_pointer (current_fb_damage, cairo_region_destroy);
*current_fb_damage = cairo_region_copy (damage);
view_priv->damage_index++;
}
static void
fill_current_damage_history_rectangle (ClutterStageView *view,
const cairo_rectangle_int_t *rect)
{
cairo_region_t *damage;
damage = cairo_region_create_rectangle (rect);
fill_current_damage_history (view, damage);
cairo_region_destroy (damage);
}
static cairo_region_t *
transform_swap_region_to_onscreen (ClutterStageView *view,
cairo_region_t *swap_region)
{
CoglFramebuffer *onscreen = clutter_stage_view_get_onscreen (view);
CoglFramebuffer *framebuffer;
cairo_rectangle_int_t layout;
gint width, height;
int n_rects, i;
cairo_rectangle_int_t *rects;
cairo_region_t *transformed_region;
int width, height;
width = cogl_framebuffer_get_width (onscreen);
height = cogl_framebuffer_get_height (onscreen);
framebuffer = clutter_stage_view_get_onscreen (view);
clutter_stage_view_get_layout (view, &layout);
width = cogl_framebuffer_get_width (framebuffer);
height = cogl_framebuffer_get_height (framebuffer);
n_rects = cairo_region_num_rectangles (swap_region);
rects = g_newa (cairo_rectangle_int_t, n_rects);
for (i = 0; i < n_rects; i++)
{
gfloat x1, y1, x2, y2;
cairo_region_get_rectangle (swap_region, i, &rects[i]);
clutter_stage_view_transform_rect_to_onscreen (view,
&rects[i],
width,
height,
&rects[i]);
x1 = (float) rects[i].x / layout.width;
y1 = (float) rects[i].y / layout.height;
x2 = (float) (rects[i].x + rects[i].width) / layout.width;
y2 = (float) (rects[i].y + rects[i].height) / layout.height;
clutter_stage_view_transform_to_onscreen (view, &x1, &y1);
clutter_stage_view_transform_to_onscreen (view, &x2, &y2);
x1 = floor (x1 * width);
y1 = floor (height - (y1 * height));
x2 = ceil (x2 * width);
y2 = ceil (height - (y2 * height));
rects[i].x = x1;
rects[i].y = y1;
rects[i].width = x2 - x1;
rects[i].height = y2 - y1;
}
transformed_region = cairo_region_create_rectangles (rects, n_rects);
return transformed_region;
}
static void
calculate_scissor_region (cairo_rectangle_int_t *fb_clip_region,
int subpixel_compensation,
int fb_width,
int fb_height,
cairo_rectangle_int_t *out_scissor_rect)
{
*out_scissor_rect = *fb_clip_region;
if (subpixel_compensation == 0)
return;
if (fb_clip_region->x > 0)
out_scissor_rect->x += subpixel_compensation;
if (fb_clip_region->y > 0)
out_scissor_rect->y += subpixel_compensation;
if (fb_clip_region->x + fb_clip_region->width < fb_width)
out_scissor_rect->width -= 2 * subpixel_compensation;
if (fb_clip_region->y + fb_clip_region->height < fb_height)
out_scissor_rect->height -= 2 * subpixel_compensation;
}
static inline gboolean
is_buffer_age_enabled (void)
{
@@ -548,21 +638,27 @@ clutter_stage_cogl_redraw_view (ClutterStageWindow *stage_window,
ClutterStageViewCoglPrivate *view_priv =
clutter_stage_view_cogl_get_instance_private (view_cogl);
CoglFramebuffer *fb = clutter_stage_view_get_framebuffer (view);
CoglFramebuffer *onscreen = clutter_stage_view_get_onscreen (view);
cairo_rectangle_int_t view_rect;
gboolean is_full_redraw;
gboolean use_clipped_redraw = TRUE;
gboolean may_use_clipped_redraw;
gboolean use_clipped_redraw;
gboolean can_blit_sub_buffer;
gboolean has_buffer_age;
gboolean do_swap_buffer;
gboolean swap_with_damage;
ClutterActor *wrapper;
cairo_region_t *redraw_clip;
cairo_region_t *queued_redraw_clip = NULL;
cairo_region_t *queued_redraw_clip;
cairo_region_t *fb_clip_region;
cairo_region_t *swap_region;
cairo_rectangle_int_t redraw_rect;
gboolean clip_region_empty;
float fb_scale;
int subpixel_compensation = 0;
int fb_width, fb_height;
int buffer_age = 0;
gboolean res;
int buffer_age;
wrapper = CLUTTER_ACTOR (stage_cogl->wrapper);
clutter_stage_view_get_layout (view, &view_rect);
fb_scale = clutter_stage_view_get_scale (view);
@@ -570,14 +666,12 @@ clutter_stage_cogl_redraw_view (ClutterStageWindow *stage_window,
fb_height = cogl_framebuffer_get_height (fb);
can_blit_sub_buffer =
cogl_is_onscreen (onscreen) &&
cogl_is_onscreen (fb) &&
cogl_clutter_winsys_has_feature (COGL_WINSYS_FEATURE_SWAP_REGION);
has_buffer_age = cogl_is_onscreen (onscreen) && is_buffer_age_enabled ();
has_buffer_age = cogl_is_onscreen (fb) && is_buffer_age_enabled ();
redraw_clip = clutter_stage_view_take_redraw_clip (view);
if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_PAINT_DAMAGE_REGION))
queued_redraw_clip = cairo_region_copy (redraw_clip);
/* NB: a NULL redraw clip == full stage redraw */
if (!redraw_clip)
@@ -585,35 +679,51 @@ clutter_stage_cogl_redraw_view (ClutterStageWindow *stage_window,
else
is_full_redraw = FALSE;
if (has_buffer_age)
{
buffer_age = cogl_onscreen_get_buffer_age (COGL_ONSCREEN (onscreen));
if (!clutter_damage_history_is_age_valid (view_priv->damage_history,
buffer_age))
{
CLUTTER_NOTE (CLIPPING,
"Invalid back buffer(age=%d): forcing full redraw\n",
buffer_age);
use_clipped_redraw = FALSE;
}
}
use_clipped_redraw =
use_clipped_redraw &&
!(clutter_paint_debug_flags & CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS) &&
may_use_clipped_redraw =
_clutter_stage_window_can_clip_redraws (stage_window) &&
(can_blit_sub_buffer || has_buffer_age) &&
!is_full_redraw &&
/* some drivers struggle to get going and produce some junk
* frames when starting up... */
cogl_onscreen_get_frame_counter (COGL_ONSCREEN (onscreen)) > 3;
cogl_onscreen_get_frame_counter (COGL_ONSCREEN (fb)) > 3;
if (use_clipped_redraw)
if (has_buffer_age)
{
buffer_age = cogl_onscreen_get_buffer_age (COGL_ONSCREEN (fb));
if (!valid_buffer_age (view_cogl, buffer_age))
{
CLUTTER_NOTE (CLIPPING, "Invalid back buffer(age=%d): forcing full redraw\n", buffer_age);
may_use_clipped_redraw = FALSE;
}
}
if (may_use_clipped_redraw)
{
fb_clip_region = offset_scale_and_clamp_region (redraw_clip,
-view_rect.x,
-view_rect.y,
fb_scale);
if (fb_scale != floorf (fb_scale))
{
int n_rects, i;
cairo_rectangle_int_t *rects;
subpixel_compensation = ceilf (fb_scale);
n_rects = cairo_region_num_rectangles (fb_clip_region);
rects = g_newa (cairo_rectangle_int_t, n_rects);
for (i = 0; i < n_rects; i++)
{
cairo_region_get_rectangle (fb_clip_region, i, &rects[i]);
rects[i].x -= subpixel_compensation;
rects[i].y -= subpixel_compensation;
rects[i].width += 2 * subpixel_compensation;
rects[i].height += 2 * subpixel_compensation;
}
cairo_region_destroy (fb_clip_region);
fb_clip_region = cairo_region_create_rectangles (rects, n_rects);
}
}
else
{
@@ -629,40 +739,48 @@ clutter_stage_cogl_redraw_view (ClutterStageWindow *stage_window,
redraw_clip = cairo_region_create_rectangle (&view_rect);
}
g_return_val_if_fail (!cairo_region_is_empty (fb_clip_region), FALSE);
queued_redraw_clip = cairo_region_copy (redraw_clip);
if (may_use_clipped_redraw &&
G_LIKELY (!(clutter_paint_debug_flags & CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS)))
use_clipped_redraw = TRUE;
else
use_clipped_redraw = FALSE;
clip_region_empty = may_use_clipped_redraw && cairo_region_is_empty (fb_clip_region);
swap_with_damage = FALSE;
if (has_buffer_age)
{
clutter_damage_history_record (view_priv->damage_history,
fb_clip_region);
if (use_clipped_redraw)
if (use_clipped_redraw && !clip_region_empty)
{
cairo_region_t *fb_damage;
cairo_region_t *view_damage;
int age;
int i;
fill_current_damage_history (view, fb_clip_region);
fb_damage = cairo_region_create ();
for (age = 1; age <= buffer_age; age++)
for (i = 1; i <= buffer_age; i++)
{
const cairo_region_t *old_damage;
int damage_index;
old_damage =
clutter_damage_history_lookup (view_priv->damage_history, age);
cairo_region_union (fb_damage, old_damage);
damage_index = DAMAGE_HISTORY (view_priv->damage_index - i - 1);
cairo_region_union (fb_damage,
view_priv->damage_history[damage_index]);
}
/* Update the fb clip region with the extra damage. */
cairo_region_union (fb_clip_region, fb_damage);
/* Update the redraw clip with the extra damage done to the view */
view_damage = scale_offset_and_clamp_region (fb_damage,
1.0f / fb_scale,
view_rect.x,
view_rect.y);
view_damage = offset_scale_and_clamp_region (fb_damage,
0, 0,
1.0f / fb_scale);
cairo_region_translate (view_damage, view_rect.x, view_rect.y);
cairo_region_intersect_rectangle (view_damage, &view_rect);
/* Update the redraw clip region with the extra damage. */
cairo_region_union (redraw_clip, view_damage);
cairo_region_destroy (view_damage);
@@ -674,13 +792,55 @@ clutter_stage_cogl_redraw_view (ClutterStageWindow *stage_window,
swap_with_damage = TRUE;
}
else if (!use_clipped_redraw)
{
cairo_rectangle_int_t fb_damage;
clutter_damage_history_step (view_priv->damage_history);
fb_damage = (cairo_rectangle_int_t) {
.x = 0,
.y = 0,
.width = ceilf (view_rect.width * fb_scale),
.height = ceilf (view_rect.height * fb_scale)
};
fill_current_damage_history_rectangle (view, &fb_damage);
}
}
if (use_clipped_redraw)
if (use_clipped_redraw && clip_region_empty)
{
cogl_framebuffer_push_region_clip (fb, fb_clip_region);
CLUTTER_NOTE (CLIPPING, "Empty stage output paint\n");
}
else if (use_clipped_redraw)
{
cairo_rectangle_int_t clip_rect;
cairo_rectangle_int_t scissor_rect;
if (cairo_region_num_rectangles (fb_clip_region) == 1)
{
cairo_region_get_extents (fb_clip_region, &clip_rect);
calculate_scissor_region (&clip_rect,
subpixel_compensation,
fb_width, fb_height,
&scissor_rect);
CLUTTER_NOTE (CLIPPING,
"Stage clip pushed: x=%d, y=%d, width=%d, height=%d\n",
scissor_rect.x,
scissor_rect.y,
scissor_rect.width,
scissor_rect.height);
cogl_framebuffer_push_scissor_clip (fb,
scissor_rect.x,
scissor_rect.y,
scissor_rect.width,
scissor_rect.height);
}
else
{
cogl_framebuffer_push_region_clip (fb, fb_clip_region);
}
paint_stage (stage_cogl, view, redraw_clip);
@@ -690,7 +850,77 @@ clutter_stage_cogl_redraw_view (ClutterStageWindow *stage_window,
{
CLUTTER_NOTE (CLIPPING, "Unclipped stage paint\n");
paint_stage (stage_cogl, view, redraw_clip);
/* If we are trying to debug redraw issues then we want to pass
* the redraw_clip so it can be visualized */
if (G_UNLIKELY (clutter_paint_debug_flags & CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS) &&
may_use_clipped_redraw &&
!clip_region_empty)
{
cairo_rectangle_int_t clip_rect;
cairo_rectangle_int_t scissor_rect;
cairo_region_get_extents (fb_clip_region, &clip_rect);
calculate_scissor_region (&clip_rect,
subpixel_compensation,
fb_width, fb_height,
&scissor_rect);
cogl_framebuffer_push_scissor_clip (fb,
scissor_rect.x,
scissor_rect.y,
scissor_rect.width,
scissor_rect.height);
paint_stage (stage_cogl, view, redraw_clip);
cogl_framebuffer_pop_clip (fb);
}
else
{
paint_stage (stage_cogl, view, redraw_clip);
}
}
cairo_region_get_extents (redraw_clip, &redraw_rect);
if (may_use_clipped_redraw &&
G_UNLIKELY ((clutter_paint_debug_flags & CLUTTER_DEBUG_REDRAWS)))
{
CoglContext *ctx = cogl_framebuffer_get_context (fb);
static CoglPipeline *outline = NULL;
ClutterActor *actor = CLUTTER_ACTOR (wrapper);
float x_1 = redraw_rect.x;
float x_2 = redraw_rect.x + redraw_rect.width;
float y_1 = redraw_rect.y;
float y_2 = redraw_rect.y + redraw_rect.height;
CoglVertexP2 quad[4] = {
{ x_1, y_1 },
{ x_2, y_1 },
{ x_2, y_2 },
{ x_1, y_2 }
};
CoglPrimitive *prim;
CoglMatrix modelview;
if (outline == NULL)
{
outline = cogl_pipeline_new (ctx);
cogl_pipeline_set_color4ub (outline, 0xff, 0x00, 0x00, 0xff);
}
prim = cogl_primitive_new_p2 (ctx,
COGL_VERTICES_MODE_LINE_LOOP,
4, /* n_vertices */
quad);
cogl_framebuffer_push_matrix (fb);
cogl_matrix_init_identity (&modelview);
_clutter_actor_apply_modelview_transform (actor, &modelview);
cogl_framebuffer_set_modelview_matrix (fb, &modelview);
cogl_framebuffer_draw_primitive (fb, outline, prim);
cogl_framebuffer_pop_matrix (fb);
cogl_object_unref (prim);
}
/* XXX: It seems there will be a race here in that the stage
@@ -702,56 +932,59 @@ clutter_stage_cogl_redraw_view (ClutterStageWindow *stage_window,
* artefacts.
*/
if (use_clipped_redraw)
swap_region = cairo_region_copy (fb_clip_region);
{
if (clip_region_empty)
{
do_swap_buffer = FALSE;
}
else
{
swap_region = cairo_region_copy (fb_clip_region);
do_swap_buffer = TRUE;
}
}
else
swap_region = cairo_region_create ();
{
swap_region = cairo_region_create ();
do_swap_buffer = TRUE;
}
g_clear_pointer (&redraw_clip, cairo_region_destroy);
g_clear_pointer (&queued_redraw_clip, cairo_region_destroy);
g_clear_pointer (&fb_clip_region, cairo_region_destroy);
COGL_TRACE_BEGIN_SCOPED (ClutterStageCoglRedrawViewSwapFramebuffer,
"Paint (swap framebuffer)");
if (clutter_stage_view_get_onscreen (view) !=
clutter_stage_view_get_framebuffer (view))
if (do_swap_buffer)
{
cairo_region_t *transformed_swap_region;
gboolean res;
COGL_TRACE_BEGIN_SCOPED (ClutterStageCoglRedrawViewSwapFramebuffer,
"Paint (swap framebuffer)");
if (clutter_stage_view_get_onscreen (view) !=
clutter_stage_view_get_framebuffer (view))
{
cairo_region_t *transformed_swap_region;
transformed_swap_region =
transform_swap_region_to_onscreen (view, swap_region);
cairo_region_destroy (swap_region);
swap_region = transformed_swap_region;
}
res = swap_framebuffer (stage_window,
view,
swap_region,
swap_with_damage,
queued_redraw_clip);
transformed_swap_region =
transform_swap_region_to_onscreen (view, swap_region);
cairo_region_destroy (swap_region);
swap_region = transformed_swap_region;
}
if (queued_redraw_clip)
return res;
}
else
{
paint_damage_region (stage_window, view,
swap_region, queued_redraw_clip);
cairo_region_destroy (queued_redraw_clip);
return FALSE;
}
res = swap_framebuffer (stage_window,
view,
swap_region,
swap_with_damage);
cairo_region_destroy (swap_region);
return res;
}
static void
clutter_stage_cogl_scanout_view (ClutterStageCogl *stage_cogl,
ClutterStageView *view,
CoglScanout *scanout)
{
CoglFramebuffer *framebuffer = clutter_stage_view_get_framebuffer (view);
CoglOnscreen *onscreen;
g_return_if_fail (cogl_is_onscreen (framebuffer));
onscreen = COGL_ONSCREEN (framebuffer);
cogl_onscreen_direct_scanout (onscreen, scanout);
}
static void
@@ -766,23 +999,11 @@ clutter_stage_cogl_redraw (ClutterStageWindow *stage_window)
for (l = _clutter_stage_window_get_views (stage_window); l; l = l->next)
{
ClutterStageView *view = l->data;
g_autoptr (CoglScanout) scanout = NULL;
if (!clutter_stage_view_has_redraw_clip (view))
continue;
scanout = clutter_stage_view_take_scanout (view);
if (scanout)
{
clutter_stage_cogl_scanout_view (stage_cogl,
view,
scanout);
swap_event = TRUE;
}
else
{
swap_event |= clutter_stage_cogl_redraw_view (stage_window, view);
}
swap_event |= clutter_stage_cogl_redraw_view (stage_window, view);
}
_clutter_stage_emit_after_paint (stage_cogl->wrapper);
@@ -815,6 +1036,7 @@ clutter_stage_window_iface_init (ClutterStageWindowInterface *iface)
iface->schedule_update = clutter_stage_cogl_schedule_update;
iface->get_update_time = clutter_stage_cogl_get_update_time;
iface->clear_update_time = clutter_stage_cogl_clear_update_time;
iface->get_next_presentation_time = clutter_stage_cogl_get_next_presentation_time;
iface->redraw = clutter_stage_cogl_redraw;
}
@@ -860,33 +1082,15 @@ _clutter_stage_cogl_init (ClutterStageCogl *stage)
stage->refresh_rate = 0.0;
stage->update_time = -1;
}
static void
clutter_stage_view_cogl_finalize (GObject *object)
{
ClutterStageViewCogl *view_cogl = CLUTTER_STAGE_VIEW_COGL (object);
ClutterStageViewCoglPrivate *view_priv =
clutter_stage_view_cogl_get_instance_private (view_cogl);
clutter_damage_history_free (view_priv->damage_history);
G_OBJECT_CLASS (clutter_stage_view_cogl_parent_class)->finalize (object);
stage->next_presentation_time = -1;
}
static void
clutter_stage_view_cogl_init (ClutterStageViewCogl *view_cogl)
{
ClutterStageViewCoglPrivate *view_priv =
clutter_stage_view_cogl_get_instance_private (view_cogl);
view_priv->damage_history = clutter_damage_history_new ();
}
static void
clutter_stage_view_cogl_class_init (ClutterStageViewCoglClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->finalize = clutter_stage_view_cogl_finalize;
}

View File

@@ -48,6 +48,7 @@ struct _ClutterStageCogl
gint64 last_presentation_time;
gint64 update_time;
int64_t last_update_time;
int64_t next_presentation_time;
/* We only enable clipped redraws after 2 frames, since we've seen
* a lot of drivers can struggle to get going and may output some

View File

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

View File

@@ -0,0 +1,138 @@
/*
* Clutter.
*
* An OpenGL based 'interactive canvas' library.
*
* Authored By Matthew Allum <mallum@openedhand.com>
* Jorn Baayen <jorn@openedhand.com>
* Emmanuele Bassi <ebassi@openedhand.com>
* Tomas Frydrych <tf@openedhand.com>
*
* Copyright (C) 2006, 2007, 2008 OpenedHand
* Copyright (C) 2009 Intel Corp.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION)
#error "Only <clutter/clutter.h> can be included directly."
#endif
#ifndef __CLUTTER_ALPHA_H__
#define __CLUTTER_ALPHA_H__
#include <clutter/clutter-timeline.h>
#include <clutter/clutter-types.h>
G_BEGIN_DECLS
#define CLUTTER_TYPE_ALPHA (clutter_alpha_get_type ())
#define CLUTTER_ALPHA(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_ALPHA, ClutterAlpha))
#define CLUTTER_ALPHA_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_ALPHA, ClutterAlphaClass))
#define CLUTTER_IS_ALPHA(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_ALPHA))
#define CLUTTER_IS_ALPHA_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_ALPHA))
#define CLUTTER_ALPHA_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_ALPHA, ClutterAlphaClass))
typedef struct _ClutterAlphaClass ClutterAlphaClass;
typedef struct _ClutterAlphaPrivate ClutterAlphaPrivate;
/**
* ClutterAlphaFunc:
* @alpha: a #ClutterAlpha
* @user_data: user data passed to the function
*
* A function returning a value depending on the position of
* the #ClutterTimeline bound to @alpha.
*
* Return value: a floating point value
*
* Since: 0.2
*
* Deprecated: 1.12: Use #ClutterTimelineProgressFunc instead.
*/
typedef gdouble (*ClutterAlphaFunc) (ClutterAlpha *alpha,
gpointer user_data);
/**
* ClutterAlpha:
*
* #ClutterAlpha combines a #ClutterTimeline and a function.
* The contents of the #ClutterAlpha structure are private and should
* only be accessed using the provided API.
*
* Since: 0.2
*
* Deprecated: 1.12: Use #ClutterTimeline instead
*/
struct _ClutterAlpha
{
/*< private >*/
GInitiallyUnowned parent;
ClutterAlphaPrivate *priv;
};
/**
* ClutterAlphaClass:
*
* Base class for #ClutterAlpha
*
* Since: 0.2
*
* Deprecated: 1.12: Use #ClutterTimeline instead
*/
struct _ClutterAlphaClass
{
/*< private >*/
GInitiallyUnownedClass parent_class;
void (*_clutter_alpha_1) (void);
void (*_clutter_alpha_2) (void);
void (*_clutter_alpha_3) (void);
void (*_clutter_alpha_4) (void);
void (*_clutter_alpha_5) (void);
};
CLUTTER_DEPRECATED
GType clutter_alpha_get_type (void) G_GNUC_CONST;
CLUTTER_DEPRECATED
ClutterAlpha * clutter_alpha_new (void);
CLUTTER_DEPRECATED
ClutterAlpha * clutter_alpha_new_full (ClutterTimeline *timeline,
gulong mode);
CLUTTER_DEPRECATED
gdouble clutter_alpha_get_alpha (ClutterAlpha *alpha);
CLUTTER_DEPRECATED
void clutter_alpha_set_func (ClutterAlpha *alpha,
ClutterAlphaFunc func,
gpointer data,
GDestroyNotify destroy);
CLUTTER_DEPRECATED
void clutter_alpha_set_closure (ClutterAlpha *alpha,
GClosure *closure);
CLUTTER_DEPRECATED
void clutter_alpha_set_timeline (ClutterAlpha *alpha,
ClutterTimeline *timeline);
CLUTTER_DEPRECATED
ClutterTimeline *clutter_alpha_get_timeline (ClutterAlpha *alpha);
CLUTTER_DEPRECATED
void clutter_alpha_set_mode (ClutterAlpha *alpha,
gulong mode);
CLUTTER_DEPRECATED
gulong clutter_alpha_get_mode (ClutterAlpha *alpha);
G_END_DECLS
#endif /* __CLUTTER_ALPHA_H__ */

File diff suppressed because it is too large Load Diff

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,147 @@
/*
* Clutter.
*
* An OpenGL based 'interactive canvas' library.
*
* Authored By Øyvind Kolås <pippin@linux.intel.com>
*
* Copyright (C) 2009 Intel Corporation
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __CLUTTER_STATE_H__
#define __CLUTTER_STATE_H__
#include <clutter/clutter-types.h>
G_BEGIN_DECLS
#define CLUTTER_TYPE_STATE_KEY (clutter_state_key_get_type ())
#define CLUTTER_TYPE_STATE (clutter_state_get_type ())
#define CLUTTER_STATE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_STATE, ClutterState))
#define CLUTTER_STATE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_STATE, ClutterStateClass))
#define CLUTTER_IS_STATE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_STATE))
#define CLUTTER_IS_STATE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_STATE))
#define CLUTTER_STATE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_STATE, ClutterStateClass))
typedef struct _ClutterStatePrivate ClutterStatePrivate;
typedef struct _ClutterStateClass ClutterStateClass;
/**
* ClutterStateKey:
*
* #ClutterStateKey is an opaque structure whose
* members cannot be accessed directly
*
* Since: 1.4
*/
typedef struct _ClutterStateKey ClutterStateKey;
/**
* ClutterState:
*
* The #ClutterState structure contains only
* private data and should be accessed using the provided API
*
* Since: 1.4
*/
struct _ClutterState
{
/*< private >*/
GObject parent;
ClutterStatePrivate *priv;
};
/**
* ClutterStateClass:
* @completed: class handler for the #ClutterState::completed signal
*
* The #ClutterStateClass structure contains
* only private data
*
* Since: 1.4
*
* Deprecated: 1.12
*/
struct _ClutterStateClass
{
/*< private >*/
GObjectClass parent_class;
/*< public >*/
void (* completed) (ClutterState *state);
/*< private >*/
/* padding for future expansion */
gpointer _padding_dummy[8];
};
CLUTTER_DEPRECATED
GType clutter_state_get_type (void) G_GNUC_CONST;
CLUTTER_DEPRECATED
ClutterState *clutter_state_new (void);
CLUTTER_DEPRECATED
ClutterTimeline * clutter_state_set_state (ClutterState *state,
const gchar *target_state_name);
CLUTTER_DEPRECATED
ClutterTimeline * clutter_state_warp_to_state (ClutterState *state,
const gchar *target_state_name);
CLUTTER_DEPRECATED
ClutterState * clutter_state_set_key (ClutterState *state,
const gchar *source_state_name,
const gchar *target_state_name,
GObject *object,
const gchar *property_name,
guint mode,
const GValue *value,
gdouble pre_delay,
gdouble post_delay);
CLUTTER_DEPRECATED
void clutter_state_set_duration (ClutterState *state,
const gchar *source_state_name,
const gchar *target_state_name,
guint duration);
CLUTTER_DEPRECATED
guint clutter_state_get_duration (ClutterState *state,
const gchar *source_state_name,
const gchar *target_state_name);
CLUTTER_DEPRECATED
void clutter_state_set (ClutterState *state,
const gchar *source_state_name,
const gchar *target_state_name,
gpointer first_object,
const gchar *first_property_name,
gulong first_mode,
...) G_GNUC_NULL_TERMINATED;
CLUTTER_DEPRECATED
GList * clutter_state_get_states (ClutterState *state);
CLUTTER_DEPRECATED
const gchar * clutter_state_get_state (ClutterState *state);
/*
* ClutterStateKey
*/
CLUTTER_DEPRECATED
GType clutter_state_key_get_type (void) G_GNUC_CONST;
CLUTTER_DEPRECATED
GType clutter_state_key_get_property_type (const ClutterStateKey *key);
G_END_DECLS
#endif /* __CLUTTER_STATE_H__ */

View File

@@ -26,6 +26,16 @@
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

@@ -30,6 +30,8 @@ clutter_headers = [
'clutter-deform-effect.h',
'clutter-deprecated.h',
'clutter-desaturate-effect.h',
'clutter-drag-action.h',
'clutter-drop-action.h',
'clutter-effect.h',
'clutter-enums.h',
'clutter-event.h',
@@ -114,9 +116,10 @@ clutter_sources = [
'clutter-constraint.c',
'clutter-container.c',
'clutter-content.c',
'clutter-damage-history.c',
'clutter-deform-effect.c',
'clutter-desaturate-effect.c',
'clutter-drag-action.c',
'clutter-drop-action.c',
'clutter-effect.c',
'clutter-event.c',
'clutter-feature.c',
@@ -186,7 +189,6 @@ clutter_private_headers = [
'clutter-bezier.h',
'clutter-constraint-private.h',
'clutter-content-private.h',
'clutter-damage-history.h',
'clutter-debug.h',
'clutter-easing.h',
'clutter-effect-private.h',
@@ -221,18 +223,24 @@ clutter_nonintrospected_sources = [
clutter_deprecated_headers = [
'deprecated/clutter-actor.h',
'deprecated/clutter-alpha.h',
'deprecated/clutter-animation.h',
'deprecated/clutter-box.h',
'deprecated/clutter-container.h',
'deprecated/clutter-group.h',
'deprecated/clutter-rectangle.h',
'deprecated/clutter-stage.h',
'deprecated/clutter-state.h',
'deprecated/clutter-timeline.h',
]
clutter_deprecated_sources = [
'deprecated/clutter-alpha.c',
'deprecated/clutter-animation.c',
'deprecated/clutter-box.c',
'deprecated/clutter-group.c',
'deprecated/clutter-rectangle.c',
'deprecated/clutter-state.c',
]
clutter_backend_sources = []
@@ -333,20 +341,35 @@ clutter_build_config_h = configure_file(
)
clutter_built_private_headers += clutter_build_config_h
cdata = configuration_data()
clutter_config_defines = []
if have_wayland
cdata.set10('CLUTTER_HAS_WAYLAND_COMPOSITOR_SUPPORT', true)
clutter_config_defines += [
'#define CLUTTER_HAS_WAYLAND_COMPOSITOR_SUPPORT 1',
]
endif
if have_x11
cdata.set_quoted('CLUTTER_WINDOWING_X11', 'x11')
cdata.set_quoted('CLUTTER_INPUT_X11', 'x11')
cdata.set_quoted('CLUTTER_WINDOWING_GLX', 'glx')
clutter_config_defines += [
'#define CLUTTER_WINDOWING_X11 "x11"',
'#define CLUTTER_INPUT_X11 "x11"',
'#define CLUTTER_WINDOWING_GLX "glx"',
]
endif
if have_native_backend
cdata.set_quoted('CLUTTER_WINDOWING_EGL', 'eglnative')
cdata.set_quoted('CLUTTER_INPUT_EVDEV', 'evdev')
clutter_config_defines += [
'#define CLUTTER_WINDOWING_EGL "eglnative"',
'#define CLUTTER_INPUT_EVDEV "evdev"',
]
endif
cdata.set_quoted('CLUTTER_INPUT_NULL', 'null')
clutter_config_defines += [
'#define CLUTTER_INPUT_NULL "null"',
]
clutter_config_defines_string = ''
foreach clutter_config_define : clutter_config_defines
clutter_config_defines_string += clutter_config_define + '\n'
endforeach
cdata = configuration_data()
cdata.set('CLUTTER_CONFIG_DEFINES', clutter_config_defines_string)
clutter_config_h = configure_file(
input: 'clutter-config.h.in',
@@ -406,6 +429,7 @@ libmutter_clutter = shared_library(libmutter_clutter_name,
link_with: [
libmutter_cogl,
libmutter_cogl_pango,
libmutter_cogl_path,
],
install_rpath: pkglibdir,
install_dir: pkglibdir,

2
cogl/.gitignore vendored
View File

@@ -36,6 +36,8 @@ cogl-egl-defines.h
cogl-enum-types.c
cogl-enum-types.h
cogl-gl-header.h
cogl-path-enum-types.c
cogl-path-enum-types.h
cogl-config.h
cogl-config.h.in
cogl-mutter-config.h

View File

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

View File

@@ -25,7 +25,7 @@ libmutter_cogl_pango = shared_library('mutter-cogl-pango-' + libmutter_api_versi
version: '0.0.0',
soversion: 0,
c_args: cogl_c_args,
include_directories: [cogl_includepath],
include_directories: [cogl_includepath, cogl_path_includepath],
gnu_symbol_visibility: 'hidden',
dependencies: [cogl_pango_deps],
install_rpath: pkglibdir,

View File

@@ -0,0 +1,48 @@
/*** BEGIN file-header ***/
#include "cogl-config.h"
/* We need to undefine this so that we will be sure to include
* cogl-path.h instead of cogl2-path.h when we include the framebuffer
* header. Otherwise it will include both headers and it won't
* compile. */
#undef COGL_ENABLE_EXPERIMENTAL_2_0_API
#include "cogl-path-enum-types.h"
/*** END file-header ***/
/*** BEGIN file-production ***/
/* enumerations from "@filename@" */
#include "@filename@"
/*** END file-production ***/
/*** BEGIN value-header ***/
GType
@enum_name@_get_type (void)
{
static volatile gsize g_enum_type_id__volatile = 0;
if (g_once_init_enter (&g_enum_type_id__volatile))
{
static const G@Type@Value values[] = {
/*** END value-header ***/
/*** BEGIN value-production ***/
{ @VALUENAME@, "@VALUENAME@", "@valuenick@" },
/*** END value-production ***/
/*** BEGIN value-tail ***/
{ 0, NULL, NULL }
};
GType g_enum_type_id;
g_enum_type_id =
g_@type@_register_static (g_intern_static_string ("@EnumName@"), values);
g_once_init_leave (&g_enum_type_id__volatile, g_enum_type_id);
}
return g_enum_type_id__volatile;
}
/*** END value-tail ***/

View File

@@ -0,0 +1,25 @@
/*** BEGIN file-header ***/
#ifndef __COGL_PATH_ENUM_TYPES_H__
#define __COGL_PATH_ENUM_TYPES_H__
#include <glib-object.h>
G_BEGIN_DECLS
/*** END file-header ***/
/*** BEGIN file-production ***/
/* enumerations from "@basename@" */
/*** END file-production ***/
/*** BEGIN file-tail ***/
G_END_DECLS
#endif /* __COGL_PATH_ENUM_TYPES_H__ */
/*** END file-tail ***/
/*** BEGIN value-header ***/
GType @enum_name@_get_type (void) G_GNUC_CONST;
#define COGL_TYPE_@ENUMSHORT@ (@enum_name@_get_type())
/*** END value-header ***/

View File

@@ -0,0 +1,487 @@
/*
* Cogl
*
* A Low Level GPU Graphics and Utilities API
*
* Copyright (C) 2008,2009,2013 Intel Corporation.
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*
*/
#if !defined(__COGL_H_INSIDE__) && !defined(COGL_COMPILATION)
#error "Only <cogl/cogl.h> can be included directly."
#endif
#ifndef __COGL_PATH_FUNCTIONS_H__
#define __COGL_PATH_FUNCTIONS_H__
#include <cogl/cogl-types.h>
#ifdef COGL_COMPILATION
#include "cogl-context.h"
#else
#include <cogl/cogl.h>
#endif
#include <glib-object.h>
G_BEGIN_DECLS
/**
* cogl_path_get_gtype:
*
* Returns: a #GType that can be used with the GLib type system.
*/
COGL_EXPORT
GType cogl_path_get_gtype (void);
#define cogl_path_new cogl2_path_new
/**
* cogl_path_new:
*
* Creates a new, empty path object. The default fill rule is
* %COGL_PATH_FILL_RULE_EVEN_ODD.
*
* Return value: A pointer to a newly allocated #CoglPath, which can
* be freed using cogl_object_unref().
*
* Since: 2.0
*/
COGL_EXPORT CoglPath *
cogl_path_new (void);
/**
* cogl_path_copy:
* @path: A #CoglPath object
*
* Returns a new copy of the path in @path. The new path has a
* reference count of 1 so you should unref it with
* cogl_object_unref() if you no longer need it.
*
* Internally the path will share the data until one of the paths is
* modified so copying paths should be relatively cheap.
*
* Return value: (transfer full): a copy of the path in @path.
*
* Since: 2.0
*/
COGL_EXPORT CoglPath *
cogl_path_copy (CoglPath *path);
/**
* cogl_is_path:
* @object: A #CoglObject
*
* Gets whether the given object references an existing path object.
*
* Return value: %TRUE if the object references a #CoglPath,
* %FALSE otherwise.
*
* Since: 2.0
*/
COGL_EXPORT gboolean
cogl_is_path (void *object);
#define cogl_path_move_to cogl2_path_move_to
/**
* cogl_path_move_to:
* @x: X coordinate of the pen location to move to.
* @y: Y coordinate of the pen location to move to.
*
* Moves the pen to the given location. If there is an existing path
* this will start a new disjoint subpath.
*
* Since: 2.0
*/
COGL_EXPORT void
cogl_path_move_to (CoglPath *path,
float x,
float y);
#define cogl_path_rel_move_to cogl2_path_rel_move_to
/**
* cogl_path_rel_move_to:
* @x: X offset from the current pen location to move the pen to.
* @y: Y offset from the current pen location to move the pen to.
*
* Moves the pen to the given offset relative to the current pen
* location. If there is an existing path this will start a new
* disjoint subpath.
*
* Since: 2.0
*/
COGL_EXPORT void
cogl_path_rel_move_to (CoglPath *path,
float x,
float y);
#define cogl_path_line_to cogl2_path_line_to
/**
* cogl_path_line_to:
* @x: X coordinate of the end line vertex
* @y: Y coordinate of the end line vertex
*
* Adds a straight line segment to the current path that ends at the
* given coordinates.
*
* Since: 2.0
*/
COGL_EXPORT void
cogl_path_line_to (CoglPath *path,
float x,
float y);
#define cogl_path_rel_line_to cogl2_path_rel_line_to
/**
* cogl_path_rel_line_to:
* @x: X offset from the current pen location of the end line vertex
* @y: Y offset from the current pen location of the end line vertex
*
* Adds a straight line segment to the current path that ends at the
* given coordinates relative to the current pen location.
*
* Since: 2.0
*/
COGL_EXPORT void
cogl_path_rel_line_to (CoglPath *path,
float x,
float y);
#define cogl_path_arc cogl2_path_arc
/**
* cogl_path_arc:
* @center_x: X coordinate of the elliptical arc center
* @center_y: Y coordinate of the elliptical arc center
* @radius_x: X radius of the elliptical arc
* @radius_y: Y radius of the elliptical arc
* @angle_1: Angle in degrees at which the arc begin
* @angle_2: Angle in degrees at which the arc ends
*
* Adds an elliptical arc segment to the current path. A straight line
* segment will link the current pen location with the first vertex
* of the arc. If you perform a move_to to the arcs start just before
* drawing it you create a free standing arc.
*
* The angles are measured in degrees where 0° is in the direction of
* the positive X axis and 90° is in the direction of the positive Y
* axis. The angle of the arc begins at @angle_1 and heads towards
* @angle_2 (so if @angle_2 is less than @angle_1 it will decrease,
* otherwise it will increase).
*
* Since: 2.0
*/
COGL_EXPORT void
cogl_path_arc (CoglPath *path,
float center_x,
float center_y,
float radius_x,
float radius_y,
float angle_1,
float angle_2);
#define cogl_path_curve_to cogl2_path_curve_to
/**
* cogl_path_curve_to:
* @x_1: X coordinate of the second bezier control point
* @y_1: Y coordinate of the second bezier control point
* @x_2: X coordinate of the third bezier control point
* @y_2: Y coordinate of the third bezier control point
* @x_3: X coordinate of the fourth bezier control point
* @y_3: Y coordinate of the fourth bezier control point
*
* Adds a cubic bezier curve segment to the current path with the given
* second, third and fourth control points and using current pen location
* as the first control point.
*
* Since: 2.0
*/
COGL_EXPORT void
cogl_path_curve_to (CoglPath *path,
float x_1,
float y_1,
float x_2,
float y_2,
float x_3,
float y_3);
#define cogl_path_rel_curve_to cogl2_path_rel_curve_to
/**
* cogl_path_rel_curve_to:
* @x_1: X coordinate of the second bezier control point
* @y_1: Y coordinate of the second bezier control point
* @x_2: X coordinate of the third bezier control point
* @y_2: Y coordinate of the third bezier control point
* @x_3: X coordinate of the fourth bezier control point
* @y_3: Y coordinate of the fourth bezier control point
*
* Adds a cubic bezier curve segment to the current path with the given
* second, third and fourth control points and using current pen location
* as the first control point. The given coordinates are relative to the
* current pen location.
*
* Since: 2.0
*/
COGL_EXPORT void
cogl_path_rel_curve_to (CoglPath *path,
float x_1,
float y_1,
float x_2,
float y_2,
float x_3,
float y_3);
#define cogl_path_close cogl2_path_close
/**
* cogl_path_close:
*
* Closes the path being constructed by adding a straight line segment
* to it that ends at the first vertex of the path.
*
* Since: 2.0
*/
COGL_EXPORT void
cogl_path_close (CoglPath *path);
#define cogl_path_line cogl2_path_line
/**
* cogl_path_line:
* @x_1: X coordinate of the start line vertex
* @y_1: Y coordinate of the start line vertex
* @x_2: X coordinate of the end line vertex
* @y_2: Y coordinate of the end line vertex
*
* Constructs a straight line shape starting and ending at the given
* coordinates. If there is an existing path this will start a new
* disjoint sub-path.
*
* Since: 2.0
*/
COGL_EXPORT void
cogl_path_line (CoglPath *path,
float x_1,
float y_1,
float x_2,
float y_2);
#define cogl_path_polyline cogl2_path_polyline
/**
* cogl_path_polyline:
* @coords: (in) (array) (transfer none): A pointer to the first element of an
* array of fixed-point values that specify the vertex coordinates.
* @num_points: The total number of vertices.
*
* Constructs a series of straight line segments, starting from the
* first given vertex coordinate. If there is an existing path this
* will start a new disjoint sub-path. Each subsequent segment starts
* where the previous one ended and ends at the next given vertex
* coordinate.
*
* The coords array must contain 2 * num_points values. The first value
* represents the X coordinate of the first vertex, the second value
* represents the Y coordinate of the first vertex, continuing in the same
* fashion for the rest of the vertices. (num_points - 1) segments will
* be constructed.
*
* Since: 2.0
*/
COGL_EXPORT void
cogl_path_polyline (CoglPath *path,
const float *coords,
int num_points);
#define cogl_path_polygon cogl2_path_polygon
/**
* cogl_path_polygon:
* @coords: (in) (array) (transfer none): A pointer to the first element of
* an array of fixed-point values that specify the vertex coordinates.
* @num_points: The total number of vertices.
*
* Constructs a polygonal shape of the given number of vertices. If
* there is an existing path this will start a new disjoint sub-path.
*
* The coords array must contain 2 * num_points values. The first value
* represents the X coordinate of the first vertex, the second value
* represents the Y coordinate of the first vertex, continuing in the same
* fashion for the rest of the vertices.
*
* Since: 2.0
*/
COGL_EXPORT void
cogl_path_polygon (CoglPath *path,
const float *coords,
int num_points);
#define cogl_path_rectangle cogl2_path_rectangle
/**
* cogl_path_rectangle:
* @x_1: X coordinate of the top-left corner.
* @y_1: Y coordinate of the top-left corner.
* @x_2: X coordinate of the bottom-right corner.
* @y_2: Y coordinate of the bottom-right corner.
*
* Constructs a rectangular shape at the given coordinates. If there
* is an existing path this will start a new disjoint sub-path.
*
* Since: 2.0
*/
COGL_EXPORT void
cogl_path_rectangle (CoglPath *path,
float x_1,
float y_1,
float x_2,
float y_2);
#define cogl_path_ellipse cogl2_path_ellipse
/**
* cogl_path_ellipse:
* @center_x: X coordinate of the ellipse center
* @center_y: Y coordinate of the ellipse center
* @radius_x: X radius of the ellipse
* @radius_y: Y radius of the ellipse
*
* Constructs an ellipse shape. If there is an existing path this will
* start a new disjoint sub-path.
*
* Since: 2.0
*/
COGL_EXPORT void
cogl_path_ellipse (CoglPath *path,
float center_x,
float center_y,
float radius_x,
float radius_y);
#define cogl_path_round_rectangle cogl2_path_round_rectangle
/**
* cogl_path_round_rectangle:
* @x_1: X coordinate of the top-left corner.
* @y_1: Y coordinate of the top-left corner.
* @x_2: X coordinate of the bottom-right corner.
* @y_2: Y coordinate of the bottom-right corner.
* @radius: Radius of the corner arcs.
* @arc_step: Angle increment resolution for subdivision of
* the corner arcs.
*
* Constructs a rectangular shape with rounded corners. If there is an
* existing path this will start a new disjoint sub-path.
*
* Since: 2.0
*/
COGL_EXPORT void
cogl_path_round_rectangle (CoglPath *path,
float x_1,
float y_1,
float x_2,
float y_2,
float radius,
float arc_step);
#define cogl_path_set_fill_rule cogl2_path_set_fill_rule
/**
* cogl_path_set_fill_rule:
* @fill_rule: The new fill rule.
*
* Sets the fill rule of the current path to @fill_rule. This will
* affect how the path is filled when cogl_path_fill() is later
* called. Note that the fill rule state is attached to the path so
* calling cogl_get_path() will preserve the fill rule and calling
* cogl_path_new() will reset the fill rule back to the default.
*
* Since: 2.0
*/
COGL_EXPORT void
cogl_path_set_fill_rule (CoglPath *path, CoglPathFillRule fill_rule);
#define cogl_path_get_fill_rule cogl2_path_get_fill_rule
/**
* cogl_path_get_fill_rule:
*
* Retrieves the fill rule set using cogl_path_set_fill_rule().
*
* Return value: the fill rule that is used for the current path.
*
* Since: 2.0
*/
COGL_EXPORT CoglPathFillRule
cogl_path_get_fill_rule (CoglPath *path);
/**
* cogl_framebuffer_fill_path:
* @framebuffer: A #CoglFramebuffer
* @pipeline: A #CoglPipeline to render with
* @path: The #CoglPath to fill
*
* Fills the interior of the path using the fragment operations
* defined by the pipeline.
*
* The interior of the shape is determined using the fill rule of the
* path. See %CoglPathFillRule for details.
*
* <note>The result of referencing sliced textures in your current
* pipeline when filling a path are undefined. You should pass
* the %COGL_TEXTURE_NO_SLICING flag when loading any texture you will
* use while filling a path.</note>
*
* Stability: unstable
*/
COGL_EXPORT void
cogl_framebuffer_fill_path (CoglFramebuffer *framebuffer,
CoglPipeline *pipeline,
CoglPath *path);
/**
* cogl_framebuffer_stroke_path:
* @framebuffer: A #CoglFramebuffer
* @pipeline: A #CoglPipeline to render with
* @path: The #CoglPath to stroke
*
* Strokes the edge of the path using the fragment operations defined
* by the pipeline. The stroke line will have a width of 1 pixel
* regardless of the current transformation matrix.
*
* Stability: unstable
*/
COGL_EXPORT void
cogl_framebuffer_stroke_path (CoglFramebuffer *framebuffer,
CoglPipeline *pipeline,
CoglPath *path);
/**
* cogl_framebuffer_push_path_clip:
* @framebuffer: A #CoglFramebuffer pointer
* @path: The path to clip with.
*
* Sets a new clipping area using the silhouette of the specified,
* filled @path. The clipping area is intersected with the previous
* clipping area. To restore the previous clipping area, call
* cogl_framebuffer_pop_clip().
*
* Since: 1.0
* Stability: unstable
*/
COGL_EXPORT void
cogl_framebuffer_push_path_clip (CoglFramebuffer *framebuffer,
CoglPath *path);
G_END_DECLS
#endif /* __COGL_PATH_FUNCTIONS_H__ */

View File

@@ -0,0 +1,126 @@
/*
* Cogl
*
* A Low Level GPU Graphics and Utilities API
*
* Copyright (C) 2010 Intel Corporation.
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*
*/
#ifndef __COGL_PATH_PRIVATE_H
#define __COGL_PATH_PRIVATE_H
#include "cogl-object.h"
#include "cogl-attribute-private.h"
typedef struct _floatVec2
{
float x;
float y;
} floatVec2;
typedef struct _CoglPathNode
{
float x;
float y;
unsigned int path_size;
} CoglPathNode;
typedef struct _CoglBezQuad
{
floatVec2 p1;
floatVec2 p2;
floatVec2 p3;
} CoglBezQuad;
typedef struct _CoglBezCubic
{
floatVec2 p1;
floatVec2 p2;
floatVec2 p3;
floatVec2 p4;
} CoglBezCubic;
typedef struct _CoglPathData CoglPathData;
struct _CoglPath
{
CoglObject _parent;
CoglPathData *data;
};
#define COGL_PATH_N_ATTRIBUTES 2
struct _CoglPathData
{
unsigned int ref_count;
CoglContext *context;
CoglPathFillRule fill_rule;
GArray *path_nodes;
floatVec2 path_start;
floatVec2 path_pen;
unsigned int last_path;
floatVec2 path_nodes_min;
floatVec2 path_nodes_max;
CoglAttributeBuffer *fill_attribute_buffer;
CoglIndices *fill_vbo_indices;
unsigned int fill_vbo_n_indices;
CoglAttribute *fill_attributes[COGL_PATH_N_ATTRIBUTES + 1];
CoglPrimitive *fill_primitive;
CoglAttributeBuffer *stroke_attribute_buffer;
CoglAttribute **stroke_attributes;
unsigned int stroke_n_attributes;
/* This is used as an optimisation for when the path contains a
single contour specified using cogl2_path_rectangle. Cogl is more
optimised to handle rectangles than paths so we can detect this
case and divert to the journal or a rectangle clip. If it is TRUE
then the entire path can be described by calling
_cogl_path_get_bounds */
gboolean is_rectangle;
};
void
_cogl_add_path_to_stencil_buffer (CoglPath *path,
gboolean merge,
gboolean need_clear);
void
_cogl_path_get_bounds (CoglPath *path,
float *min_x,
float *min_y,
float *max_x,
float *max_y);
gboolean
_cogl_path_is_rectangle (CoglPath *path);
#endif /* __COGL_PATH_PRIVATE_H */

View File

@@ -0,0 +1,86 @@
/*
* Cogl
*
* A Low Level GPU Graphics and Utilities API
*
* Copyright (C) 2008,2009,2013 Intel Corporation.
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*
*/
#if !defined(__COGL_H_INSIDE__) && !defined(COGL_COMPILATION)
#error "Only <cogl/cogl.h> can be included directly."
#endif
#ifndef __COGL_PATH_TYPES_H__
#define __COGL_PATH_TYPES_H__
#include <cogl/cogl-types.h>
G_BEGIN_DECLS
typedef struct _CoglPath CoglPath;
/**
* CoglPathFillRule:
* @COGL_PATH_FILL_RULE_NON_ZERO: Each time the line crosses an edge of
* the path from left to right one is added to a counter and each time
* it crosses from right to left the counter is decremented. If the
* counter is non-zero then the point will be filled. See <xref
* linkend="fill-rule-non-zero"/>.
* @COGL_PATH_FILL_RULE_EVEN_ODD: If the line crosses an edge of the
* path an odd number of times then the point will filled, otherwise
* it won't. See <xref linkend="fill-rule-even-odd"/>.
*
* #CoglPathFillRule is used to determine how a path is filled. There
* are two options - 'non-zero' and 'even-odd'. To work out whether any
* point will be filled imagine drawing an infinetely long line in any
* direction from that point. The number of times and the direction
* that the edges of the path crosses this line determines whether the
* line is filled as described below. Any open sub paths are treated
* as if there was an extra line joining the first point and the last
* point.
*
* The default fill rule when creating a path is %COGL_PATH_FILL_RULE_EVEN_ODD.
*
* <figure id="fill-rule-non-zero">
* <title>Example of filling various paths using the non-zero rule</title>
* <graphic fileref="fill-rule-non-zero.png" format="PNG"/>
* </figure>
*
* <figure id="fill-rule-even-odd">
* <title>Example of filling various paths using the even-odd rule</title>
* <graphic fileref="fill-rule-even-odd.png" format="PNG"/>
* </figure>
*
* Since: 1.4
*/
typedef enum
{
COGL_PATH_FILL_RULE_NON_ZERO,
COGL_PATH_FILL_RULE_EVEN_ODD
} CoglPathFillRule;
G_END_DECLS
#endif /* __COGL_PATH_TYPES_H__ */

1561
cogl/cogl-path/cogl-path.c Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,60 @@
/*
* Cogl
*
* A Low Level GPU Graphics and Utilities API
*
* Copyright (C) 2008,2009,2013 Intel Corporation.
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*
*/
#ifndef __COGL_PATH_H__
#define __COGL_PATH_H__
/**
* SECTION:cogl-paths
* @short_description: Functions for constructing and drawing 2D paths.
*
* There are two levels on which drawing with cogl-paths can be used.
* The highest level functions construct various simple primitive
* shapes to be either filled or stroked. Using a lower-level set of
* functions more complex and arbitrary paths can be constructed by
* concatenating straight line, bezier curve and arc segments.
*
* When constructing arbitrary paths, the current pen location is
* initialized using the move_to command. The subsequent path segments
* implicitly use the last pen location as their first vertex and move
* the pen location to the last vertex they produce at the end. Also
* there are special versions of functions that allow specifying the
* vertices of the path segments relative to the last pen location
* rather then in the absolute coordinates.
*/
#include <cogl/cogl-defines.h>
#include <cogl-path/cogl-path-enum-types.h>
#include <cogl-path/cogl-path-types.h>
#include <cogl-path/cogl-path-functions.h>
#endif /* __COGL_PATH_H__ */

View File

@@ -0,0 +1,59 @@
/* cogl1-path-functions.h */
cogl_clip_push_from_path
cogl_clip_push_from_path_preserve
cogl_get_path
cogl_is_path
cogl_path_arc
cogl_path_close
cogl_path_copy
cogl_path_curve_to
cogl_path_ellipse
cogl_path_fill
cogl_path_fill_preserve
cogl_path_get_fill_rule
#ifdef COGL_HAS_GTYPE_SUPPORT
cogl_path_get_gtype
#endif
cogl_path_line
cogl_path_line_to
cogl_path_move_to
cogl_path_new
cogl_path_polygon
cogl_path_polyline
cogl_path_rectangle
cogl_path_rel_curve_to
cogl_path_rel_line_to
cogl_path_rel_move_to
cogl_path_round_rectangle
cogl_path_set_fill_rule
cogl_path_stroke
cogl_path_stroke_preserve
cogl_set_path
/* cogl2-path-functions.h */
cogl_framebuffer_fill_path
cogl_framebuffer_push_path_clip
cogl_framebuffer_stroke_path
cogl2_clip_push_from_path
cogl2_path_arc
cogl2_path_close
cogl2_path_curve_to
cogl2_path_ellipse
cogl2_path_fill
cogl2_path_get_fill_rule
cogl2_path_line
cogl2_path_line_to
cogl2_path_move_to
cogl2_path_new
cogl2_path_polygon
cogl2_path_polyline
cogl2_path_rectangle
cogl2_path_rel_curve_to
cogl2_path_rel_line_to
cogl2_path_rel_move_to
cogl2_path_round_rectangle
cogl2_path_set_fill_rule
cogl2_path_stroke
/* cogl-path-enums.h-contents may change as header is generated */
cogl_path_fill_rule_get_type

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