Compare commits

..

4 Commits

Author SHA1 Message Date
Carlos Garnacho
566e24d8a1 backends: Hook ClutterSeat::touch-mode to PanelOrientationManaged
We only want the panel autorotation to happen if the laptop has an
accelerometer, and is in tablet mode. Regular laptop mode should
lock the orientation, and let it be configured manually.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1311
2020-06-23 13:04:13 +02:00
Carlos Garnacho
a9cd81cb93 backends: Check panel autorotation state before applying autorotation
So far, we've expected this signal to not happen whenever autorotation
shouldn't apply (no accelerometer is a strong reason). In future commits
we'll add further checks to this policy, so prevent autorotation to
change the display configuration if the MetaOrientationManager signal
happens but it should be ignored.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1311
2020-06-23 13:04:13 +02:00
Carlos Garnacho
4bb880f8ac backends: Centralize panel autorotation in a DisplayConfig property
Instead of having everyone check net.hadess.SensorProxy themselves, have
this all controlled by the MetaOrientationManager, and proxied everywhere
else via a readonly property in org.gnome.Mutter.DisplayConfig.

We want to attach more complex policies here, and it seems better to
centralize the handling of the autorotation feature rather than
implementing policy changes all over the place.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1311
2020-06-23 13:04:13 +02:00
Carlos Garnacho
270892d9a6 backends: Add method/property to get accelerometer availability
https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1311
2020-06-23 13:04:13 +02:00
1032 changed files with 62607 additions and 88883 deletions

1
.gitignore vendored
View File

@ -103,4 +103,3 @@ doc/reference/meta.types
.dirstamp
**/tags.*
build/
subprojects/sysprof/

View File

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

27
.gitlab-ci/Dockerfile Normal file
View File

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

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

517
NEWS
View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -0,0 +1,147 @@
/* CALLY - The Clutter Accessibility Implementation Library
*
* Copyright (C) 2008 Igalia, S.L.
*
* Author: Alejandro Piñeiro Iglesias <apinheiro@igalia.com>
*
* Based on GailContainer from GAIL
* Copyright 2001, 2002, 2003 Sun Microsystems 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, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
/**
* SECTION:cally-group
* @Title: CallyGroup
* @short_description: Implementation of the ATK interfaces for a #ClutterGroup
* @see_also: #ClutterGroup
*
* #CallyGroup implements the required ATK interfaces of #ClutterGroup
* In particular it exposes each of the Clutter actors contained in the
* group.
*/
#include "clutter-build-config.h"
#include "cally-group.h"
#include "cally-actor-private.h"
static gint cally_group_get_n_children (AtkObject *obj);
static AtkObject* cally_group_ref_child (AtkObject *obj,
gint i);
static void cally_group_real_initialize (AtkObject *obj,
gpointer data);
G_DEFINE_TYPE (CallyGroup, cally_group, CALLY_TYPE_ACTOR)
static void
cally_group_class_init (CallyGroupClass *klass)
{
/* GObjectClass *gobject_class = G_OBJECT_CLASS (klass); */
AtkObjectClass *class = ATK_OBJECT_CLASS (klass);
class->get_n_children = cally_group_get_n_children;
class->ref_child = cally_group_ref_child;
class->initialize = cally_group_real_initialize;
}
static void
cally_group_init (CallyGroup *group)
{
/* nothing to do yet */
}
/**
* cally_group_new:
* @actor: a #ClutterGroup
*
* Creates a #CallyGroup for @actor
*
* Return value: the newly created #CallyGroup
*
* Since: 1.4
*/
AtkObject *
cally_group_new (ClutterActor *actor)
{
GObject *object = NULL;
AtkObject *accessible = NULL;
g_return_val_if_fail (CLUTTER_IS_GROUP (actor), NULL);
object = g_object_new (CALLY_TYPE_GROUP, NULL);
accessible = ATK_OBJECT (object);
atk_object_initialize (accessible, actor);
return accessible;
}
static gint
cally_group_get_n_children (AtkObject *obj)
{
ClutterActor *actor = NULL;
gint count = 0;
g_return_val_if_fail (CALLY_IS_GROUP (obj), count);
actor = CALLY_GET_CLUTTER_ACTOR (obj);
if (actor == NULL) /* defunct */
return 0;
g_return_val_if_fail (CLUTTER_IS_GROUP(actor), count);
count = clutter_actor_get_n_children (actor);
return count;
}
static AtkObject*
cally_group_ref_child (AtkObject *obj,
gint i)
{
AtkObject *accessible = NULL;
ClutterActor *actor = NULL;
ClutterActor *child = NULL;
g_return_val_if_fail (CALLY_IS_GROUP (obj), NULL);
g_return_val_if_fail ((i >= 0), NULL);
actor = CALLY_GET_CLUTTER_ACTOR (obj);
g_return_val_if_fail (CLUTTER_IS_GROUP(actor), NULL);
child = clutter_actor_get_child_at_index (actor, i);
if (!child)
return NULL;
accessible = clutter_actor_get_accessible (child);
if (accessible != NULL)
g_object_ref (accessible);
return accessible;
}
static void
cally_group_real_initialize (AtkObject *obj,
gpointer data)
{
ATK_OBJECT_CLASS (cally_group_parent_class)->initialize (obj, data);
obj->role = ATK_ROLE_PANEL;
}

View File

@ -0,0 +1,87 @@
/* CALLY - The Clutter Accessibility Implementation Library
*
* Copyright (C) 2008 Igalia, S.L.
*
* Author: Alejandro Piñeiro Iglesias <apinheiro@igalia.com>
*
* Based on GailContainer from GAIL
* Copyright 2001, 2002, 2003 Sun Microsystems 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 __CALLY_GROUP_H__
#define __CALLY_GROUP_H__
#if !defined(__CALLY_H_INSIDE__) && !defined(CLUTTER_COMPILATION)
#error "Only <cally/cally.h> can be included directly."
#endif
#include <cally/cally-actor.h>
#include <clutter/clutter.h>
G_BEGIN_DECLS
#define CALLY_TYPE_GROUP (cally_group_get_type ())
#define CALLY_GROUP(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CALLY_TYPE_GROUP, CallyGroup))
#define CALLY_GROUP_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CALLY_TYPE_GROUP, CallyGroupClass))
#define CALLY_IS_GROUP(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CALLY_TYPE_GROUP))
#define CALLY_IS_GROUP_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CALLY_TYPE_GROUP))
#define CALLY_GROUP_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CALLY_TYPE_GROUP, CallyGroupClass))
typedef struct _CallyGroup CallyGroup;
typedef struct _CallyGroupClass CallyGroupClass;
typedef struct _CallyGroupPrivate CallyGroupPrivate;
/**
* CallyGroup:
*
* The <structname>CallyGroup</structname> structure contains only
* private data and should be accessed using the provided API
*
* Since: 1.4
*/
struct _CallyGroup
{
/*< private >*/
CallyActor parent;
CallyGroupPrivate *priv;
};
/**
* CallyGroupClass:
*
* The <structname>CallyGroupClass</structname> structure contains only
* private data
*
* Since: 1.4
*/
struct _CallyGroupClass
{
/*< private >*/
CallyActorClass parent_class;
/* padding for future expansion */
gpointer _padding_dummy[8];
};
CLUTTER_EXPORT
GType cally_group_get_type (void) G_GNUC_CONST;
CLUTTER_EXPORT
AtkObject* cally_group_new (ClutterActor *actor);
G_END_DECLS
#endif /* __CALLY_GROUP_H__ */

View File

@ -0,0 +1,98 @@
/* CALLY - The Clutter Accessibility Implementation Library
*
* Copyright (C) 2009 Igalia, S.L.
*
* Author: Alejandro Piñeiro Iglesias <apinheiro@igalia.com>
*
* 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, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
/**
* SECTION:cally-rectangle
* @short_description: Implementation of the ATK interfaces for a #ClutterRectangle
* @see_also: #ClutterRectangle
*
* #CallyRectangle implements the required ATK interfaces of #ClutterRectangle
*
* In particular it sets a proper role for the rectangle.
*/
#include "clutter-build-config.h"
#define CLUTTER_DISABLE_DEPRECATION_WARNINGS
#include "cally-rectangle.h"
#include "cally-actor-private.h"
#include "clutter-color.h"
#include "deprecated/clutter-rectangle.h"
/* AtkObject */
static void cally_rectangle_real_initialize (AtkObject *obj,
gpointer data);
G_DEFINE_TYPE (CallyRectangle, cally_rectangle, CALLY_TYPE_ACTOR)
static void
cally_rectangle_class_init (CallyRectangleClass *klass)
{
/* GObjectClass *gobject_class = G_OBJECT_CLASS (klass); */
AtkObjectClass *class = ATK_OBJECT_CLASS (klass);
class->initialize = cally_rectangle_real_initialize;
}
static void
cally_rectangle_init (CallyRectangle *rectangle)
{
/* nothing to do yet */
}
/**
* cally_rectangle_new:
* @actor: a #ClutterActor
*
* Creates a new #CallyRectangle for the given @actor. @actor must be
* a #ClutterRectangle.
*
* Return value: the newly created #AtkObject
*
* Since: 1.4
*/
AtkObject*
cally_rectangle_new (ClutterActor *actor)
{
GObject *object = NULL;
AtkObject *accessible = NULL;
g_return_val_if_fail (CLUTTER_IS_RECTANGLE (actor), NULL);
object = g_object_new (CALLY_TYPE_RECTANGLE, NULL);
accessible = ATK_OBJECT (object);
atk_object_initialize (accessible, actor);
return accessible;
}
static void
cally_rectangle_real_initialize (AtkObject *obj,
gpointer data)
{
ATK_OBJECT_CLASS (cally_rectangle_parent_class)->initialize (obj, data);
obj->role = ATK_ROLE_IMAGE;
}

View File

@ -0,0 +1,84 @@
/* CALLY - The Clutter Accessibility Implementation Library
*
* Copyright (C) 2009 Igalia, S.L.
*
* Author: Alejandro Piñeiro Iglesias <apinheiro@igalia.com>
*
* 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 __CALLY_RECTANGLE_H__
#define __CALLY_RECTANGLE_H__
#if !defined(__CALLY_H_INSIDE__) && !defined(CLUTTER_COMPILATION)
#error "Only <cally/cally.h> can be included directly."
#endif
#include <cally/cally-actor.h>
#include <clutter/clutter.h>
G_BEGIN_DECLS
#define CALLY_TYPE_RECTANGLE (cally_rectangle_get_type ())
#define CALLY_RECTANGLE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CALLY_TYPE_RECTANGLE, CallyRectangle))
#define CALLY_RECTANGLE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CALLY_TYPE_RECTANGLE, CallyRectangleClass))
#define CALLY_IS_RECTANGLE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CALLY_TYPE_RECTANGLE))
#define CALLY_IS_RECTANGLE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CALLY_TYPE_RECTANGLE))
#define CALLY_RECTANGLE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CALLY_TYPE_RECTANGLE, CallyRectangleClass))
typedef struct _CallyRectangle CallyRectangle;
typedef struct _CallyRectangleClass CallyRectangleClass;
typedef struct _CallyRectanglePrivate CallyRectanglePrivate;
/**
* CallyRectangle:
*
* The <structname>CallyRectangle</structname> structure contains only private
* data and should be accessed using the provided API
*
* Since: 1.4
*/
struct _CallyRectangle
{
/*< private >*/
CallyActor parent;
CallyRectanglePrivate *priv;
};
/**
* CallyRectangleClass:
*
* The <structname>CallyRectangleClass</structname> structure contains
* only private data
*
* Since: 1.4
*/
struct _CallyRectangleClass
{
/*< private >*/
CallyActorClass parent_class;
/* padding for future expansion */
gpointer _padding_dummy[8];
};
CLUTTER_EXPORT
GType cally_rectangle_get_type (void) G_GNUC_CONST;
CLUTTER_EXPORT
AtkObject* cally_rectangle_new (ClutterActor *actor);
G_END_DECLS
#endif /* __CALLY_RECTANGLE_H__ */

View File

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

View File

@ -25,7 +25,7 @@
#error "Only <cally/cally.h> can be included directly."
#endif
#include <cally/cally-actor.h>
#include <cally/cally-group.h>
#include <clutter/clutter.h>
G_BEGIN_DECLS
@ -52,7 +52,7 @@ typedef struct _CallyStagePrivate CallyStagePrivate;
struct _CallyStage
{
/*< private >*/
CallyActor parent;
CallyGroup parent;
CallyStagePrivate *priv;
};
@ -68,7 +68,7 @@ struct _CallyStage
struct _CallyStageClass
{
/*< private >*/
CallyActorClass parent_class;
CallyGroupClass parent_class;
/* padding for future expansion */
gpointer _padding_dummy[16];

View File

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

View File

@ -36,8 +36,10 @@
#include "cally.h"
#include "cally-actor.h"
#include "cally-group.h"
#include "cally-stage.h"
#include "cally-text.h"
#include "cally-rectangle.h"
#include "cally-clone.h"
#include "cally-factory.h"
@ -50,8 +52,10 @@
/* factories initialization*/
CALLY_ACCESSIBLE_FACTORY (CALLY_TYPE_ACTOR, cally_actor, cally_actor_new)
CALLY_ACCESSIBLE_FACTORY (CALLY_TYPE_GROUP, cally_group, cally_group_new)
CALLY_ACCESSIBLE_FACTORY (CALLY_TYPE_STAGE, cally_stage, cally_stage_new)
CALLY_ACCESSIBLE_FACTORY (CALLY_TYPE_TEXT, cally_text, cally_text_new)
CALLY_ACCESSIBLE_FACTORY (CALLY_TYPE_RECTANGLE, cally_rectangle, cally_rectangle_new)
CALLY_ACCESSIBLE_FACTORY (CALLY_TYPE_CLONE, cally_clone, cally_clone_new)
/**
@ -69,8 +73,10 @@ cally_accessibility_init (void)
{
/* setting the factories */
CALLY_ACTOR_SET_FACTORY (CLUTTER_TYPE_ACTOR, cally_actor);
CALLY_ACTOR_SET_FACTORY (CLUTTER_TYPE_GROUP, cally_group);
CALLY_ACTOR_SET_FACTORY (CLUTTER_TYPE_STAGE, cally_stage);
CALLY_ACTOR_SET_FACTORY (CLUTTER_TYPE_TEXT, cally_text);
CALLY_ACTOR_SET_FACTORY (CLUTTER_TYPE_RECTANGLE, cally_rectangle);
CALLY_ACTOR_SET_FACTORY (CLUTTER_TYPE_CLONE, cally_clone);
/* Initialize the CallyUtility class */

View File

@ -26,7 +26,9 @@
#include "cally-actor.h"
#include "cally-clone.h"
#include "cally-factory.h"
#include "cally-group.h"
#include "cally-main.h"
#include "cally-rectangle.h"
#include "cally-root.h"
#include "cally-stage.h"
#include "cally-text.h"

View File

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

View File

@ -26,6 +26,23 @@
G_BEGIN_DECLS
/*< private >
* ClutterRedrawFlags:
* @CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION: Tells clutter the maximum
* extents of what needs to be redrawn lies within the actors
* current allocation. (Only use this for 2D actors though because
* any actor with depth may be projected outside of its allocation)
*
* Flags passed to the clutter_actor_queue_redraw_with_clip ()
* function
*
* Since: 1.6
*/
typedef enum
{
CLUTTER_REDRAW_CLIPPED_TO_ALLOCATION = 1 << 0
} ClutterRedrawFlags;
/*< private >
* ClutterActorTraverseFlags:
* CLUTTER_ACTOR_TRAVERSE_DEPTH_FIRST: Traverse the graph in
@ -93,12 +110,35 @@ typedef ClutterActorTraverseVisitFlags (*ClutterTraverseCallback) (ClutterActor
typedef gboolean (*ClutterForeachCallback) (ClutterActor *actor,
gpointer user_data);
typedef struct _AnchorCoord AnchorCoord;
typedef struct _SizeRequest SizeRequest;
typedef struct _ClutterLayoutInfo ClutterLayoutInfo;
typedef struct _ClutterTransformInfo ClutterTransformInfo;
typedef struct _ClutterAnimationInfo ClutterAnimationInfo;
/* Internal helper struct to represent a point that can be stored in
either direct pixel coordinates or as a fraction of the actor's
size. It is used for the anchor point, scale center and rotation
centers. */
struct _AnchorCoord
{
gboolean is_fractional;
union
{
/* Used when is_fractional == TRUE */
struct
{
gdouble x;
gdouble y;
} fraction;
/* Use when is_fractional == FALSE */
graphene_point3d_t units;
} v;
};
struct _SizeRequest
{
guint age;
@ -143,15 +183,24 @@ ClutterLayoutInfo * _clutter_actor_peek_layout_info
struct _ClutterTransformInfo
{
/* rotation */
/* rotation (angle and center) */
gdouble rx_angle;
AnchorCoord rx_center;
gdouble ry_angle;
AnchorCoord ry_center;
gdouble rz_angle;
AnchorCoord rz_center;
/* scaling */
gdouble scale_x;
gdouble scale_y;
gdouble scale_z;
AnchorCoord scale_center;
/* anchor point */
AnchorCoord anchor;
/* translation */
graphene_point3d_t translation;
@ -163,10 +212,10 @@ struct _ClutterTransformInfo
graphene_point_t pivot;
gfloat pivot_z;
graphene_matrix_t transform;
CoglMatrix transform;
guint transform_set : 1;
graphene_matrix_t child_transform;
CoglMatrix child_transform;
guint child_transform_set : 1;
};
@ -203,11 +252,11 @@ void _clutter_actor_traverse
gpointer user_data);
ClutterActor * _clutter_actor_get_stage_internal (ClutterActor *actor);
void _clutter_actor_apply_modelview_transform (ClutterActor *self,
graphene_matrix_t *matrix);
void _clutter_actor_apply_relative_transformation_matrix (ClutterActor *self,
ClutterActor *ancestor,
graphene_matrix_t *matrix);
void _clutter_actor_apply_modelview_transform (ClutterActor *self,
CoglMatrix *matrix);
void _clutter_actor_apply_relative_transformation_matrix (ClutterActor *self,
ClutterActor *ancestor,
CoglMatrix *matrix);
void _clutter_actor_rerealize (ClutterActor *self,
ClutterCallback callback,
@ -228,21 +277,30 @@ void _clutter_actor_set_has_pointer
void _clutter_actor_set_has_key_focus (ClutterActor *self,
gboolean has_key_focus);
void _clutter_actor_queue_redraw_with_clip (ClutterActor *self,
ClutterRedrawFlags flags,
const ClutterPaintVolume *clip_volume);
void _clutter_actor_queue_redraw_full (ClutterActor *self,
ClutterRedrawFlags flags,
const ClutterPaintVolume *volume,
ClutterEffect *effect);
void _clutter_actor_finish_queue_redraw (ClutterActor *self);
void _clutter_actor_finish_queue_redraw (ClutterActor *self,
ClutterPaintVolume *clip);
gboolean _clutter_actor_set_default_paint_volume (ClutterActor *self,
GType check_gtype,
ClutterPaintVolume *volume);
const char * _clutter_actor_get_debug_name (ClutterActor *self);
const gchar * _clutter_actor_get_debug_name (ClutterActor *self);
void _clutter_actor_push_clone_paint (void);
void _clutter_actor_pop_clone_paint (void);
void _clutter_actor_shader_pre_paint (ClutterActor *actor,
gboolean repeat);
void _clutter_actor_shader_post_paint (ClutterActor *actor);
ClutterActorAlign _clutter_actor_get_effective_x_align (ClutterActor *self);
void _clutter_actor_handle_event (ClutterActor *actor,
@ -252,24 +310,18 @@ void _clutter_actor_attach_clone
ClutterActor *clone);
void _clutter_actor_detach_clone (ClutterActor *actor,
ClutterActor *clone);
void _clutter_actor_queue_redraw_on_clones (ClutterActor *actor);
void _clutter_actor_queue_relayout_on_clones (ClutterActor *actor);
void _clutter_actor_queue_only_relayout (ClutterActor *actor);
void clutter_actor_clear_stage_views_recursive (ClutterActor *actor);
float clutter_actor_get_real_resource_scale (ClutterActor *actor);
gboolean _clutter_actor_get_real_resource_scale (ClutterActor *actor,
float *resource_scale);
ClutterPaintNode * clutter_actor_create_texture_paint_node (ClutterActor *self,
CoglTexture *texture);
void clutter_actor_finish_layout (ClutterActor *self,
int phase);
void clutter_actor_queue_immediate_relayout (ClutterActor *self);
gboolean clutter_actor_is_painting_unmapped (ClutterActor *self);
gboolean clutter_actor_get_redraw_clip (ClutterActor *self,
ClutterPaintVolume *dst_old_pv,
ClutterPaintVolume *dst_new_pv);
void clutter_actor_update_stage_views (ClutterActor *self);
G_END_DECLS

File diff suppressed because it is too large Load Diff

View File

@ -142,6 +142,11 @@ struct _ClutterActor
* ClutterActorClass:
* @show: signal class handler for #ClutterActor::show; it must chain
* up to the parent's implementation
* @show_all: virtual function for containers and composite actors, to
* determine which children should be shown when calling
* clutter_actor_show_all() on the actor. Defaults to calling
* clutter_actor_show(). This virtual function is deprecated and it
* should not be overridden.
* @hide: signal class handler for #ClutterActor::hide; it must chain
* up to the parent's implementation
* @hide_all: virtual function for containers and composite actors, to
@ -178,15 +183,13 @@ struct _ClutterActor
* implementation.
* @apply_transform: virtual function, used when applying the transformations
* to an actor before painting it or when transforming coordinates or
* the allocation; if the transformation calculated by this function may
* have changed, the cached transformation must be invalidated by calling
* clutter_actor_invalidate_transform(); it must chain up to the parent's
* implementation
* the allocation; it must chain up to the parent's implementation
* @parent_set: signal class handler for the #ClutterActor::parent-set
* @destroy: signal class handler for #ClutterActor::destroy. It must
* chain up to the parent's implementation
* @pick: virtual function, used to draw an outline of the actor with
* the given color
* @queue_redraw: class handler for #ClutterActor::queue-redraw
* @event: class handler for #ClutterActor::event
* @button_press_event: class handler for #ClutterActor::button-press-event
* @button_release_event: class handler for
@ -223,6 +226,7 @@ struct _ClutterActorClass
/*< public >*/
void (* show) (ClutterActor *self);
void (* show_all) (ClutterActor *self);
void (* hide) (ClutterActor *self);
void (* hide_all) (ClutterActor *self);
void (* realize) (ClutterActor *self);
@ -238,6 +242,10 @@ struct _ClutterActorClass
void (* pick) (ClutterActor *actor,
ClutterPickContext *pick_context);
gboolean (* queue_redraw) (ClutterActor *actor,
ClutterActor *leaf_that_queued,
ClutterPaintVolume *paint_volume);
/* size negotiation */
void (* get_preferred_width) (ClutterActor *self,
gfloat for_height,
@ -252,7 +260,7 @@ struct _ClutterActorClass
/* transformations */
void (* apply_transform) (ClutterActor *actor,
graphene_matrix_t *matrix);
ClutterMatrix *matrix);
/* event signals */
gboolean (* event) (ClutterActor *actor,
@ -294,9 +302,6 @@ struct _ClutterActorClass
gboolean (* touch_event) (ClutterActor *self,
ClutterTouchEvent *event);
gboolean (* has_accessible) (ClutterActor *self);
void (* resource_scale_changed) (ClutterActor *self);
float (* calculate_resource_scale) (ClutterActor *self,
int phase);
/*< private >*/
/* padding for future expansion */
@ -414,9 +419,7 @@ CLUTTER_EXPORT
void clutter_actor_allocate (ClutterActor *self,
const ClutterActorBox *box);
CLUTTER_EXPORT
void clutter_actor_allocate_preferred_size (ClutterActor *self,
float x,
float y);
void clutter_actor_allocate_preferred_size (ClutterActor *self);
CLUTTER_EXPORT
void clutter_actor_allocate_available_size (ClutterActor *self,
gfloat x,
@ -451,10 +454,6 @@ void clutter_actor_set_position
gfloat x,
gfloat y);
CLUTTER_EXPORT
gboolean clutter_actor_get_fixed_position (ClutterActor *self,
float *x,
float *y);
CLUTTER_EXPORT
void clutter_actor_get_position (ClutterActor *self,
gfloat *x,
gfloat *y);
@ -586,8 +585,7 @@ void clutter_actor_set_offscreen_redirect
CLUTTER_EXPORT
ClutterOffscreenRedirect clutter_actor_get_offscreen_redirect (ClutterActor *self);
CLUTTER_EXPORT
gboolean clutter_actor_should_pick (ClutterActor *self,
ClutterPickContext *pick_context);
gboolean clutter_actor_should_pick_paint (ClutterActor *self);
CLUTTER_EXPORT
gboolean clutter_actor_is_in_clone_paint (ClutterActor *self);
CLUTTER_EXPORT
@ -595,7 +593,8 @@ gboolean clutter_actor_get_paint_box
ClutterActorBox *box);
CLUTTER_EXPORT
float clutter_actor_get_resource_scale (ClutterActor *self);
gboolean clutter_actor_get_resource_scale (ClutterActor *self,
gfloat *resource_scale);
CLUTTER_EXPORT
gboolean clutter_actor_has_overlaps (ClutterActor *self);
@ -799,21 +798,16 @@ void clutter_actor_get_translation
gfloat *translate_z);
CLUTTER_EXPORT
void clutter_actor_set_transform (ClutterActor *self,
const graphene_matrix_t *transform);
const ClutterMatrix *transform);
CLUTTER_EXPORT
void clutter_actor_get_transform (ClutterActor *self,
graphene_matrix_t *transform);
ClutterMatrix *transform);
CLUTTER_EXPORT
void clutter_actor_set_child_transform (ClutterActor *self,
const graphene_matrix_t *transform);
const ClutterMatrix *transform);
CLUTTER_EXPORT
void clutter_actor_get_child_transform (ClutterActor *self,
graphene_matrix_t *transform);
CLUTTER_EXPORT
void clutter_actor_get_transformed_extents (ClutterActor *self,
graphene_rect_t *rect);
ClutterMatrix *transform);
CLUTTER_EXPORT
void clutter_actor_get_transformed_position (ClutterActor *self,
gfloat *x,
@ -928,12 +922,6 @@ void clutter_actor_pick_box (ClutterActor *self,
CLUTTER_EXPORT
GList * clutter_actor_peek_stage_views (ClutterActor *self);
CLUTTER_EXPORT
void clutter_actor_invalidate_transform (ClutterActor *self);
CLUTTER_EXPORT
void clutter_actor_invalidate_paint_volume (ClutterActor *self);
G_END_DECLS
#endif /* __CLUTTER_ACTOR_H__ */

View File

@ -194,25 +194,3 @@ clutter_animatable_interpolate_value (ClutterAnimatable *animatable,
else
return clutter_interval_compute_value (interval, progress, value);
}
/**
* clutter_animatable_get_actor:
* @animatable: a #ClutterAnimatable
*
* Get animated actor.
*
* Return value: (transfer none): a #ClutterActor
*/
ClutterActor *
clutter_animatable_get_actor (ClutterAnimatable *animatable)
{
ClutterAnimatableInterface *iface;
g_return_val_if_fail (CLUTTER_IS_ANIMATABLE (animatable), NULL);
iface = CLUTTER_ANIMATABLE_GET_IFACE (animatable);
g_return_val_if_fail (iface->get_actor, NULL);
return iface->get_actor (animatable);
}

View File

@ -50,7 +50,6 @@ G_DECLARE_INTERFACE (ClutterAnimatable, clutter_animatable,
* animatable property
* @interpolate_value: virtual function for interpolating the progress
* of a property
* @get_actor: virtual function for getting associated actor
*
* Since: 1.0
*/
@ -73,7 +72,6 @@ struct _ClutterAnimatableInterface
ClutterInterval *interval,
gdouble progress,
GValue *value);
ClutterActor * (* get_actor) (ClutterAnimatable *animatable);
};
CLUTTER_EXPORT
@ -94,9 +92,6 @@ gboolean clutter_animatable_interpolate_value (ClutterAnimatable *animatable,
gdouble progress,
GValue *value);
CLUTTER_EXPORT
ClutterActor * clutter_animatable_get_actor (ClutterAnimatable *animatable);
G_END_DECLS
#endif /* __CLUTTER_ANIMATABLE_H__ */

View File

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

View File

@ -53,8 +53,6 @@ struct _ClutterBackend
gfloat units_per_em;
gint32 units_serial;
float fallback_resource_scale;
ClutterStageWindow *stage_window;
ClutterInputMethod *input_method;
@ -73,6 +71,7 @@ struct _ClutterBackendClass
ClutterStageWindow * (* create_stage) (ClutterBackend *backend,
ClutterStage *wrapper,
GError **error);
void (* init_events) (ClutterBackend *backend);
void (* init_features) (ClutterBackend *backend);
void (* add_options) (ClutterBackend *backend,
GOptionGroup *group);
@ -92,8 +91,6 @@ struct _ClutterBackendClass
ClutterSeat * (* get_default_seat) (ClutterBackend *backend);
gboolean (* is_display_server) (ClutterBackend *backend);
/* signals */
void (* resolution_changed) (ClutterBackend *backend);
void (* font_changed) (ClutterBackend *backend);
@ -115,6 +112,12 @@ gboolean _clutter_backend_pre_parse (Clutter
gboolean _clutter_backend_post_parse (ClutterBackend *backend,
GError **error);
void _clutter_backend_init_events (ClutterBackend *backend);
void _clutter_backend_copy_event_data (ClutterBackend *backend,
const ClutterEvent *src,
ClutterEvent *dest);
void _clutter_backend_free_event_data (ClutterBackend *backend,
ClutterEvent *event);
CLUTTER_EXPORT
gboolean _clutter_backend_translate_event (ClutterBackend *backend,
gpointer native,
@ -131,17 +134,6 @@ void clutter_set_allowed_drivers (const c
CLUTTER_EXPORT
ClutterStageWindow * clutter_backend_get_stage_window (ClutterBackend *backend);
CLUTTER_EXPORT
void clutter_backend_set_fallback_resource_scale (ClutterBackend *backend,
float fallback_resource_scale);
float clutter_backend_get_fallback_resource_scale (ClutterBackend *backend);
gboolean clutter_backend_is_display_server (ClutterBackend *backend);
CLUTTER_EXPORT
void clutter_backend_destroy (ClutterBackend *backend);
G_END_DECLS
#endif /* __CLUTTER_BACKEND_PRIVATE_H__ */

View File

@ -40,6 +40,8 @@
#include "clutter-build-config.h"
#define CLUTTER_ENABLE_EXPERIMENTAL_API
#include "clutter-backend-private.h"
#include "clutter-debug.h"
#include "clutter-event-private.h"
@ -50,8 +52,25 @@
#include "clutter-stage-private.h"
#include "clutter-stage-window.h"
#ifdef CLUTTER_HAS_WAYLAND_COMPOSITOR_SUPPORT
#include "wayland/clutter-wayland-compositor.h"
#endif
#include <cogl/cogl.h>
#ifdef CLUTTER_INPUT_X11
#include "x11/clutter-backend-x11.h"
#endif
#ifdef CLUTTER_WINDOWING_EGL
#include "egl/clutter-backend-eglnative.h"
#endif
#ifdef CLUTTER_HAS_WAYLAND_COMPOSITOR_SUPPORT
#include <cogl/cogl-wayland-server.h>
#include <wayland-server.h>
#include "wayland/clutter-wayland-compositor.h"
#endif
#define DEFAULT_FONT_NAME "Sans 10"
enum
@ -67,6 +86,12 @@ G_DEFINE_ABSTRACT_TYPE (ClutterBackend, clutter_backend, G_TYPE_OBJECT)
static guint backend_signals[LAST_SIGNAL] = { 0, };
/* Global for being able to specify a compositor side wayland display
* pointer before clutter initialization */
#ifdef CLUTTER_HAS_WAYLAND_COMPOSITOR_SUPPORT
static struct wl_display *_wayland_compositor_display;
#endif
static void
clutter_backend_dispose (GObject *gobject)
{
@ -75,20 +100,28 @@ clutter_backend_dispose (GObject *gobject)
/* clear the events still in the queue of the main context */
_clutter_clear_events_queue ();
g_clear_object (&backend->dummy_onscreen);
g_clear_pointer (&backend->dummy_onscreen, cogl_object_unref);
if (backend->stage_window)
{
g_object_remove_weak_pointer (G_OBJECT (backend->stage_window),
(gpointer *) &backend->stage_window);
backend->stage_window = NULL;
}
g_clear_pointer (&backend->cogl_source, g_source_destroy);
g_clear_pointer (&backend->font_name, g_free);
g_clear_pointer (&backend->font_options, cairo_font_options_destroy);
G_OBJECT_CLASS (clutter_backend_parent_class)->dispose (gobject);
}
static void
clutter_backend_finalize (GObject *gobject)
{
ClutterBackend *backend = CLUTTER_BACKEND (gobject);
g_source_destroy (backend->cogl_source);
g_free (backend->font_name);
clutter_backend_set_font_options (backend, NULL);
g_clear_object (&backend->input_method);
G_OBJECT_CLASS (clutter_backend_parent_class)->dispose (gobject);
G_OBJECT_CLASS (clutter_backend_parent_class)->finalize (gobject);
}
static gfloat
@ -189,20 +222,22 @@ clutter_backend_do_real_create_context (ClutterBackend *backend,
{
ClutterBackendClass *klass;
CoglSwapChain *swap_chain;
GError *internal_error;
klass = CLUTTER_BACKEND_GET_CLASS (backend);
swap_chain = NULL;
internal_error = NULL;
CLUTTER_NOTE (BACKEND, "Creating Cogl renderer");
backend->cogl_renderer = klass->get_renderer (backend, error);
backend->cogl_renderer = klass->get_renderer (backend, &internal_error);
if (backend->cogl_renderer == NULL)
goto error;
CLUTTER_NOTE (BACKEND, "Connecting the renderer");
cogl_renderer_set_driver (backend->cogl_renderer, driver_id);
if (!cogl_renderer_connect (backend->cogl_renderer, error))
if (!cogl_renderer_connect (backend->cogl_renderer, &internal_error))
goto error;
CLUTTER_NOTE (BACKEND, "Creating Cogl swap chain");
@ -214,7 +249,7 @@ clutter_backend_do_real_create_context (ClutterBackend *backend,
backend->cogl_display = klass->get_display (backend,
backend->cogl_renderer,
swap_chain,
error);
&internal_error);
}
else
{
@ -230,7 +265,7 @@ clutter_backend_do_real_create_context (ClutterBackend *backend,
*/
res = cogl_renderer_check_onscreen_template (backend->cogl_renderer,
tmpl,
error);
&internal_error);
if (!res)
goto error;
@ -244,12 +279,17 @@ clutter_backend_do_real_create_context (ClutterBackend *backend,
if (backend->cogl_display == NULL)
goto error;
#ifdef CLUTTER_HAS_WAYLAND_COMPOSITOR_SUPPORT
cogl_wayland_display_set_compositor_display (backend->cogl_display,
_wayland_compositor_display);
#endif
CLUTTER_NOTE (BACKEND, "Setting up the display");
if (!cogl_display_setup (backend->cogl_display, error))
if (!cogl_display_setup (backend->cogl_display, &internal_error))
goto error;
CLUTTER_NOTE (BACKEND, "Creating the Cogl context");
backend->cogl_context = cogl_context_new (backend->cogl_display, error);
backend->cogl_context = cogl_context_new (backend->cogl_display, &internal_error);
if (backend->cogl_context == NULL)
goto error;
@ -382,6 +422,14 @@ clutter_backend_real_get_features (ClutterBackend *backend)
flags |= CLUTTER_FEATURE_STAGE_STATIC;
}
if (cogl_clutter_winsys_has_feature (COGL_WINSYS_FEATURE_SWAP_THROTTLE))
{
CLUTTER_NOTE (BACKEND, "Cogl supports swap buffers throttling");
flags |= CLUTTER_FEATURE_SWAP_THROTTLE;
}
else
CLUTTER_NOTE (BACKEND, "Cogl doesn't support swap buffers throttling");
if (cogl_clutter_winsys_has_feature (COGL_WINSYS_FEATURE_SWAP_BUFFERS_EVENT))
{
CLUTTER_NOTE (BACKEND, "Cogl supports swap buffers complete events");
@ -391,8 +439,23 @@ clutter_backend_real_get_features (ClutterBackend *backend)
return flags;
}
static const char *allowed_backends;
static ClutterBackend * (* custom_backend_func) (void);
static const struct {
const char *name;
ClutterBackend * (* create_backend) (void);
} available_backends[] = {
#ifdef CLUTTER_WINDOWING_X11
{ CLUTTER_WINDOWING_X11, clutter_backend_x11_new },
#endif
#ifdef CLUTTER_WINDOWING_EGL
{ CLUTTER_WINDOWING_EGL, clutter_backend_egl_native_new },
#endif
{ NULL, NULL },
};
void
clutter_set_custom_backend_func (ClutterBackend *(* func) (void))
{
@ -402,23 +465,75 @@ clutter_set_custom_backend_func (ClutterBackend *(* func) (void))
ClutterBackend *
_clutter_create_backend (void)
{
const char *backends_list;
ClutterBackend *retval;
gboolean allow_any;
char **backends;
int i;
g_return_val_if_fail (custom_backend_func, NULL);
if (custom_backend_func)
{
retval = custom_backend_func ();
retval = custom_backend_func ();
if (!retval)
g_error ("Failed to create custom backend.");
if (!retval)
g_error ("Failed to create custom backend.");
return retval;
}
if (allowed_backends == NULL)
allowed_backends = "*";
allow_any = strstr (allowed_backends, "*") != NULL;
backends_list = g_getenv ("CLUTTER_BACKEND");
if (backends_list == NULL)
backends_list = allowed_backends;
backends = g_strsplit (backends_list, ",", 0);
retval = NULL;
for (i = 0; retval == NULL && backends[i] != NULL; i++)
{
const char *backend = backends[i];
gboolean is_any = g_str_equal (backend, "*");
int j;
for (j = 0; available_backends[j].name != NULL; j++)
{
if ((is_any && allow_any) ||
(is_any && strstr (allowed_backends, available_backends[j].name)) ||
g_str_equal (backend, available_backends[j].name))
{
retval = available_backends[j].create_backend ();
if (retval != NULL)
break;
}
}
}
g_strfreev (backends);
if (retval == NULL)
g_error ("No default Clutter backend found.");
return retval;
}
static void
clutter_backend_real_init_events (ClutterBackend *backend)
{
g_error ("Unknown input backend");
}
static void
clutter_backend_class_init (ClutterBackendClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
gobject_class->dispose = clutter_backend_dispose;
gobject_class->finalize = clutter_backend_finalize;
/**
* ClutterBackend::resolution-changed:
@ -474,6 +589,7 @@ clutter_backend_class_init (ClutterBackendClass *klass)
klass->resolution_changed = clutter_backend_real_resolution_changed;
klass->font_changed = clutter_backend_real_font_changed;
klass->init_events = clutter_backend_real_init_events;
klass->create_context = clutter_backend_real_create_context;
klass->get_features = clutter_backend_real_get_features;
}
@ -485,8 +601,6 @@ clutter_backend_init (ClutterBackend *self)
self->units_serial = 1;
self->dummy_onscreen = NULL;
self->fallback_resource_scale = 1.f;
}
void
@ -612,6 +726,17 @@ _clutter_backend_get_features (ClutterBackend *backend)
return 0;
}
void
_clutter_backend_init_events (ClutterBackend *backend)
{
ClutterBackendClass *klass;
g_assert (CLUTTER_IS_BACKEND (backend));
klass = CLUTTER_BACKEND_GET_CLASS (backend);
klass->init_events (backend);
}
gfloat
_clutter_backend_get_units_per_em (ClutterBackend *backend,
PangoFontDescription *font_desc)
@ -626,6 +751,31 @@ _clutter_backend_get_units_per_em (ClutterBackend *backend,
return backend->units_per_em;
}
void
_clutter_backend_copy_event_data (ClutterBackend *backend,
const ClutterEvent *src,
ClutterEvent *dest)
{
ClutterSeatClass *seat_class;
ClutterSeat *seat;
seat = clutter_backend_get_default_seat (backend);
seat_class = CLUTTER_SEAT_GET_CLASS (seat);
seat_class->copy_event_data (seat, src, dest);
}
void
_clutter_backend_free_event_data (ClutterBackend *backend,
ClutterEvent *event)
{
ClutterSeatClass *seat_class;
ClutterSeat *seat;
seat = clutter_backend_get_default_seat (backend);
seat_class = CLUTTER_SEAT_GET_CLASS (seat);
seat_class->free_event_data (seat, event);
}
/**
* clutter_get_default_backend:
*
@ -795,6 +945,31 @@ clutter_backend_get_cogl_context (ClutterBackend *backend)
return backend->cogl_context;
}
#ifdef CLUTTER_HAS_WAYLAND_COMPOSITOR_SUPPORT
/**
* clutter_wayland_set_compositor_display:
* @display: A compositor side struct wl_display pointer
*
* This informs Clutter of your compositor side Wayland display
* object. This must be called before calling clutter_init().
*
* Since: 1.8
* Stability: unstable
*/
void
clutter_wayland_set_compositor_display (void *display)
{
if (_clutter_context_is_initialized ())
{
g_warning ("%s() can only be used before calling clutter_init()",
G_STRFUNC);
return;
}
_wayland_compositor_display = display;
}
#endif
void
clutter_set_allowed_drivers (const char *drivers)
{
@ -856,29 +1031,3 @@ clutter_backend_get_default_seat (ClutterBackend *backend)
return CLUTTER_BACKEND_GET_CLASS (backend)->get_default_seat (backend);
}
void
clutter_backend_set_fallback_resource_scale (ClutterBackend *backend,
float fallback_resource_scale)
{
backend->fallback_resource_scale = fallback_resource_scale;
}
float
clutter_backend_get_fallback_resource_scale (ClutterBackend *backend)
{
return backend->fallback_resource_scale;
}
gboolean
clutter_backend_is_display_server (ClutterBackend *backend)
{
return CLUTTER_BACKEND_GET_CLASS (backend)->is_display_server (backend);
}
void
clutter_backend_destroy (ClutterBackend *backend)
{
g_object_run_dispose (G_OBJECT (backend));
g_object_unref (backend);
}

View File

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

View File

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

View File

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

View File

@ -38,14 +38,12 @@
*
* |[<!-- language="C" -->
* // source
* rect[0] = clutter_actor_new ();
* clutter_actor_set_background_color (rect[0], &red_color);
* rect[0] = clutter_rectangle_new_with_color (&red_color);
* clutter_actor_set_position (rect[0], x_pos, y_pos);
* clutter_actor_set_size (rect[0], 100, 100);
*
* // second rectangle
* rect[1] = clutter_actor_new ();
* clutter_actor_set_background_color (rect[1], &green_color);
* rect[1] = clutter_rectangle_new_with_color (&green_color);
* clutter_actor_set_size (rect[1], 100, 100);
* clutter_actor_set_opacity (rect[1], 0);
*
@ -55,8 +53,7 @@
* clutter_actor_add_constraint_with_name (rect[1], "green-y", constraint);
*
* // third rectangle
* rect[2] = clutter_actor_new ();
* clutter_actor_set_background_color (rect[2], &blue_color);
* rect[2] = clutter_rectangle_new_with_color (&blue_color);
* clutter_actor_set_size (rect[2], 100, 100);
* clutter_actor_set_opacity (rect[2], 0);
*

View File

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

View File

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

View File

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

View File

@ -39,7 +39,7 @@
* #ClutterActor:y-expand are set, the available size
* - honours the #ClutterActor's #ClutterActor:x-align and #ClutterActor:y-align properties
* to fill the available size
* - if the #ClutterBoxLayout:homogeneous boolean property is set, then all widgets will
* - if the #ClutterBoxLayout:homogeneous boolean propert is set, then all widgets will
* get the same size, ignoring expand settings and the preferred sizes
*
* It is possible to control the spacing between children of a
@ -167,10 +167,8 @@ get_preferred_size_for_orientation (ClutterBoxLayout *self,
ClutterActor *child;
gint n_children = 0;
gfloat minimum, natural;
float largest_min_size, largest_nat_size;
minimum = natural = 0;
largest_min_size = largest_nat_size = 0;
clutter_actor_iter_init (&iter, container);
while (clutter_actor_iter_next (&iter, &child))
@ -185,22 +183,8 @@ get_preferred_size_for_orientation (ClutterBoxLayout *self,
get_child_size (child, priv->orientation,
for_size, &child_min, &child_nat);
if (priv->is_homogeneous)
{
largest_min_size = MAX (largest_min_size, child_min);
largest_nat_size = MAX (largest_nat_size, child_nat);
}
else
{
minimum += child_min;
natural += child_nat;
}
}
if (priv->is_homogeneous)
{
minimum = largest_min_size * n_children;
natural = largest_nat_size * n_children;
minimum += child_min;
natural += child_nat;
}
if (n_children > 1)
@ -331,8 +315,6 @@ get_preferred_size_for_opposite_orientation (ClutterBoxLayout *self,
}
else
{
size -= (nvis_children - 1) * priv->spacing;
/* Bring children up to size first */
if (isnormal (size) || size == 0)
{
@ -719,7 +701,7 @@ clutter_box_layout_allocate (ClutterLayoutManager *layout,
if (priv->is_homogeneous)
{
/* If were homogeneous we still need to run the above loop to get the
/* If were homogenous we still need to run the above loop to get the
* minimum sizes for children that are not going to fill
*/
if (priv->orientation == CLUTTER_ORIENTATION_VERTICAL)
@ -1218,7 +1200,7 @@ clutter_box_layout_get_homogeneous (ClutterBoxLayout *layout)
* @pack_start: %TRUE if the @layout should pack children at the
* beginning of the layout
*
* Sets whether children of @layout should be laid out by appending
* Sets whether children of @layout should be layed out by appending
* them or by prepending them
*
* Since: 1.2

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -3,7 +3,13 @@
#define __CLUTTER_DEPRECATED_H_INSIDE__
#include "deprecated/clutter-actor.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-timeline.h"
#undef __CLUTTER_DEPRECATED_H_INSIDE__

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -127,7 +127,7 @@ typedef enum /*< prefix=CLUTTER_REQUEST >*/
* @CLUTTER_EASE_IN_OUT_QUAD: quadratic tweening, combininig
* %CLUTTER_EASE_IN_QUAD and %CLUTTER_EASE_OUT_QUAD
* @CLUTTER_EASE_IN_CUBIC: cubic tweening
* @CLUTTER_EASE_OUT_CUBIC: cubic tweening, inverse of
* @CLUTTER_EASE_OUT_CUBIC: cubic tweening, invers of
* %CLUTTER_EASE_IN_CUBIC
* @CLUTTER_EASE_IN_OUT_CUBIC: cubic tweening, combining
* %CLUTTER_EASE_IN_CUBIC and %CLUTTER_EASE_OUT_CUBIC
@ -387,6 +387,44 @@ typedef enum
CLUTTER_MODIFIER_MASK = 0x5c001fff
} ClutterModifierType;
/**
* ClutterKeyboardA11yFlags:
* @CLUTTER_A11Y_KEYBOARD_ENABLED:
* @CLUTTER_A11Y_TIMEOUT_ENABLED:
* @CLUTTER_A11Y_MOUSE_KEYS_ENABLED:
* @CLUTTER_A11Y_SLOW_KEYS_ENABLED:
* @CLUTTER_A11Y_SLOW_KEYS_BEEP_PRESS:
* @CLUTTER_A11Y_SLOW_KEYS_BEEP_ACCEPT:
* @CLUTTER_A11Y_SLOW_KEYS_BEEP_REJECT:
* @CLUTTER_A11Y_BOUNCE_KEYS_ENABLED:
* @CLUTTER_A11Y_BOUNCE_KEYS_BEEP_REJECT:
* @CLUTTER_A11Y_TOGGLE_KEYS_ENABLED:
* @CLUTTER_A11Y_STICKY_KEYS_ENABLED:
* @CLUTTER_A11Y_STICKY_KEYS_TWO_KEY_OFF:
* @CLUTTER_A11Y_STICKY_KEYS_BEEP:
* @CLUTTER_A11Y_FEATURE_STATE_CHANGE_BEEP:
*
* Keyboard accessibility features applied to a ClutterInputDevice keyboard.
*
*/
typedef enum
{
CLUTTER_A11Y_KEYBOARD_ENABLED = 1 << 0,
CLUTTER_A11Y_TIMEOUT_ENABLED = 1 << 1,
CLUTTER_A11Y_MOUSE_KEYS_ENABLED = 1 << 2,
CLUTTER_A11Y_SLOW_KEYS_ENABLED = 1 << 3,
CLUTTER_A11Y_SLOW_KEYS_BEEP_PRESS = 1 << 4,
CLUTTER_A11Y_SLOW_KEYS_BEEP_ACCEPT = 1 << 5,
CLUTTER_A11Y_SLOW_KEYS_BEEP_REJECT = 1 << 6,
CLUTTER_A11Y_BOUNCE_KEYS_ENABLED = 1 << 7,
CLUTTER_A11Y_BOUNCE_KEYS_BEEP_REJECT = 1 << 8,
CLUTTER_A11Y_TOGGLE_KEYS_ENABLED = 1 << 9,
CLUTTER_A11Y_STICKY_KEYS_ENABLED = 1 << 10,
CLUTTER_A11Y_STICKY_KEYS_TWO_KEY_OFF = 1 << 11,
CLUTTER_A11Y_STICKY_KEYS_BEEP = 1 << 12,
CLUTTER_A11Y_FEATURE_STATE_CHANGE_BEEP = 1 << 13,
} ClutterKeyboardA11yFlags;
/**
* ClutterPointerA11yFlags:
* @CLUTTER_A11Y_POINTER_ENABLED:
@ -475,7 +513,7 @@ typedef enum {
* a toplevel, and all parents visible)
* @CLUTTER_ACTOR_REALIZED: the resources associated to the actor have been
* allocated
* @CLUTTER_ACTOR_REACTIVE: the actor 'reacts' to mouse events emitting event
* @CLUTTER_ACTOR_REACTIVE: the actor 'reacts' to mouse events emmitting event
* signals
* @CLUTTER_ACTOR_VISIBLE: the actor has been shown by the application program
* @CLUTTER_ACTOR_NO_LAYOUT: the actor provides an explicit layout management
@ -802,8 +840,7 @@ typedef enum /*< flags prefix=CLUTTER_EVENT >*/
CLUTTER_EVENT_NONE = 0,
CLUTTER_EVENT_FLAG_SYNTHETIC = 1 << 0,
CLUTTER_EVENT_FLAG_INPUT_METHOD = 1 << 1,
CLUTTER_EVENT_FLAG_REPEATED = 1 << 2,
CLUTTER_EVENT_FLAG_RELATIVE_MOTION = 1 << 3,
CLUTTER_EVENT_FLAG_REPEATED = 1 << 2
} ClutterEventFlags;
/**
@ -817,6 +854,10 @@ typedef enum /*< flags prefix=CLUTTER_EVENT >*/
* @CLUTTER_BUTTON_PRESS: Pointer button press event
* @CLUTTER_BUTTON_RELEASE: Pointer button release event
* @CLUTTER_SCROLL: Pointer scroll event
* @CLUTTER_STAGE_STATE: Stage state change event
* @CLUTTER_DESTROY_NOTIFY: Destroy notification event
* @CLUTTER_CLIENT_MESSAGE: Client message event
* @CLUTTER_DELETE: Stage delete event
* @CLUTTER_TOUCH_BEGIN: A new touch event sequence has started;
* event added in 1.10
* @CLUTTER_TOUCH_UPDATE: A touch event sequence has been updated;
@ -851,6 +892,10 @@ typedef enum /*< prefix=CLUTTER >*/
CLUTTER_BUTTON_PRESS,
CLUTTER_BUTTON_RELEASE,
CLUTTER_SCROLL,
CLUTTER_STAGE_STATE,
CLUTTER_DESTROY_NOTIFY,
CLUTTER_CLIENT_MESSAGE,
CLUTTER_DELETE,
CLUTTER_TOUCH_BEGIN,
CLUTTER_TOUCH_UPDATE,
CLUTTER_TOUCH_END,
@ -863,11 +908,6 @@ typedef enum /*< prefix=CLUTTER >*/
CLUTTER_PAD_BUTTON_RELEASE,
CLUTTER_PAD_STRIP,
CLUTTER_PAD_RING,
CLUTTER_DEVICE_ADDED,
CLUTTER_DEVICE_REMOVED,
CLUTTER_IM_COMMIT,
CLUTTER_IM_DELETE,
CLUTTER_IM_PREEDIT,
CLUTTER_EVENT_LAST /* helper */
} ClutterEventType;
@ -896,8 +936,22 @@ typedef enum /*< prefix=CLUTTER_SCROLL >*/
CLUTTER_SCROLL_SMOOTH
} ClutterScrollDirection;
/**
* ClutterStageState:
* @CLUTTER_STAGE_STATE_ACTIVATED: Activated mask
*
* Stage state masks, used by the #ClutterEvent of type %CLUTTER_STAGE_STATE.
*
* Since: 0.4
*/
typedef enum
{
CLUTTER_STAGE_STATE_ACTIVATED = (1 << 3)
} ClutterStageState;
/**
* ClutterFeatureFlags:
* @CLUTTER_FEATURE_SWAP_THROTTLE: Set if backend throttles buffer swaps.
* @CLUTTER_FEATURE_STAGE_STATIC: Set if stage size if fixed (i.e framebuffer)
* @CLUTTER_FEATURE_STAGE_CURSOR: Set if stage has a graphical cursor.
* @CLUTTER_FEATURE_SHADERS_GLSL: Set if the backend supports GLSL shaders.
@ -912,6 +966,7 @@ typedef enum /*< prefix=CLUTTER_SCROLL >*/
*/
typedef enum
{
CLUTTER_FEATURE_SWAP_THROTTLE = (1 << 3),
CLUTTER_FEATURE_STAGE_STATIC = (1 << 6),
CLUTTER_FEATURE_STAGE_CURSOR = (1 << 8),
CLUTTER_FEATURE_SHADERS_GLSL = (1 << 9),
@ -979,11 +1034,11 @@ typedef enum
/**
* ClutterInputMode:
* @CLUTTER_INPUT_MODE_LOGICAL: A logical, virtual device
* @CLUTTER_INPUT_MODE_PHYSICAL: A physical device, attached to
* a logical device
* @CLUTTER_INPUT_MODE_FLOATING: A physical device, not attached
* to a logical device
* @CLUTTER_INPUT_MODE_MASTER: A master, virtual device
* @CLUTTER_INPUT_MODE_SLAVE: A slave, physical device, attached to
* a master device
* @CLUTTER_INPUT_MODE_FLOATING: A slave, physical device, not attached
* to a master device
*
* The mode for input devices available.
*
@ -991,8 +1046,8 @@ typedef enum
*/
typedef enum
{
CLUTTER_INPUT_MODE_LOGICAL,
CLUTTER_INPUT_MODE_PHYSICAL,
CLUTTER_INPUT_MODE_MASTER,
CLUTTER_INPUT_MODE_SLAVE,
CLUTTER_INPUT_MODE_FLOATING
} ClutterInputMode;
@ -1032,20 +1087,6 @@ typedef enum
CLUTTER_INPUT_AXIS_LAST
} ClutterInputAxis;
typedef enum
{
CLUTTER_INPUT_AXIS_FLAG_NONE = 0,
CLUTTER_INPUT_AXIS_FLAG_X = 1 << CLUTTER_INPUT_AXIS_X,
CLUTTER_INPUT_AXIS_FLAG_Y = 1 << CLUTTER_INPUT_AXIS_Y,
CLUTTER_INPUT_AXIS_FLAG_PRESSURE = 1 << CLUTTER_INPUT_AXIS_PRESSURE,
CLUTTER_INPUT_AXIS_FLAG_XTILT = 1 << CLUTTER_INPUT_AXIS_XTILT,
CLUTTER_INPUT_AXIS_FLAG_YTILT = 1 << CLUTTER_INPUT_AXIS_YTILT,
CLUTTER_INPUT_AXIS_FLAG_WHEEL = 1 << CLUTTER_INPUT_AXIS_WHEEL,
CLUTTER_INPUT_AXIS_FLAG_DISTANCE = 1 << CLUTTER_INPUT_AXIS_DISTANCE,
CLUTTER_INPUT_AXIS_FLAG_ROTATION = 1 << CLUTTER_INPUT_AXIS_ROTATION,
CLUTTER_INPUT_AXIS_FLAG_SLIDER = 1 << CLUTTER_INPUT_AXIS_SLIDER,
} ClutterInputAxisFlags;
/**
* ClutterSnapEdge:
* @CLUTTER_SNAP_EDGE_TOP: the top edge
@ -1159,7 +1200,7 @@ typedef enum /*< prefix=CLUTTER_TEXTURE >*/
*
* Since: 0.8
*
* Deprecated: 1.22: The #ClutterTexture class was the only user of
* Deprecated: 1.22: The #ClutterTexture class was the only used ot
* this API; use #ClutterImage and clutter_actor_set_content_scaling_filters()
* instead.
*/
@ -1595,10 +1636,9 @@ typedef enum
typedef enum
{
CLUTTER_PAD_FEATURE_BUTTON,
CLUTTER_PAD_FEATURE_RING,
CLUTTER_PAD_FEATURE_STRIP,
} ClutterInputDevicePadFeature;
CLUTTER_INPUT_DEVICE_MAPPING_ABSOLUTE,
CLUTTER_INPUT_DEVICE_MAPPING_RELATIVE,
} ClutterInputDeviceMapping;
typedef enum
{
@ -1638,12 +1678,6 @@ typedef enum
CLUTTER_INPUT_PANEL_STATE_TOGGLE,
} ClutterInputPanelState;
typedef enum
{
CLUTTER_PREEDIT_RESET_CLEAR,
CLUTTER_PREEDIT_RESET_COMMIT,
} ClutterPreeditResetMode;
G_END_DECLS
#endif /* __CLUTTER_ENUMS_H__ */

View File

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

View File

@ -73,6 +73,8 @@ typedef struct _ClutterEventFilter {
gpointer user_data;
} ClutterEventFilter;
static GHashTable *all_events = NULL;
G_DEFINE_BOXED_TYPE (ClutterEvent, clutter_event,
clutter_event_copy,
clutter_event_free);
@ -94,6 +96,15 @@ G_DEFINE_BOXED_TYPE (ClutterEventSequence, clutter_event_sequence,
clutter_event_sequence_copy,
clutter_event_sequence_free);
static gboolean
is_event_allocated (const ClutterEvent *event)
{
if (all_events == NULL)
return FALSE;
return g_hash_table_lookup (all_events, event) != NULL;
}
/*
* _clutter_event_get_platform_data:
* @event: a #ClutterEvent
@ -107,6 +118,9 @@ G_DEFINE_BOXED_TYPE (ClutterEventSequence, clutter_event_sequence,
gpointer
_clutter_event_get_platform_data (const ClutterEvent *event)
{
if (!is_event_allocated (event))
return NULL;
return ((ClutterEventPrivate *) event)->platform_data;
}
@ -123,6 +137,9 @@ void
_clutter_event_set_platform_data (ClutterEvent *event,
gpointer data)
{
if (!is_event_allocated (event))
return;
((ClutterEventPrivate *) event)->platform_data = data;
}
@ -130,6 +147,9 @@ void
_clutter_event_set_pointer_emulated (ClutterEvent *event,
gboolean is_emulated)
{
if (!is_event_allocated (event))
return;
((ClutterEventPrivate *) event)->is_pointer_emulated = !!is_emulated;
}
@ -384,6 +404,10 @@ clutter_event_get_position (const ClutterEvent *event,
case CLUTTER_NOTHING:
case CLUTTER_KEY_PRESS:
case CLUTTER_KEY_RELEASE:
case CLUTTER_STAGE_STATE:
case CLUTTER_DESTROY_NOTIFY:
case CLUTTER_CLIENT_MESSAGE:
case CLUTTER_DELETE:
case CLUTTER_EVENT_LAST:
case CLUTTER_PROXIMITY_IN:
case CLUTTER_PROXIMITY_OUT:
@ -391,11 +415,6 @@ clutter_event_get_position (const ClutterEvent *event,
case CLUTTER_PAD_BUTTON_RELEASE:
case CLUTTER_PAD_STRIP:
case CLUTTER_PAD_RING:
case CLUTTER_DEVICE_ADDED:
case CLUTTER_DEVICE_REMOVED:
case CLUTTER_IM_COMMIT:
case CLUTTER_IM_DELETE:
case CLUTTER_IM_PREEDIT:
graphene_point_init (position, 0.f, 0.f);
break;
@ -459,6 +478,10 @@ clutter_event_set_coords (ClutterEvent *event,
case CLUTTER_NOTHING:
case CLUTTER_KEY_PRESS:
case CLUTTER_KEY_RELEASE:
case CLUTTER_STAGE_STATE:
case CLUTTER_DESTROY_NOTIFY:
case CLUTTER_CLIENT_MESSAGE:
case CLUTTER_DELETE:
case CLUTTER_EVENT_LAST:
case CLUTTER_PROXIMITY_IN:
case CLUTTER_PROXIMITY_OUT:
@ -466,11 +489,6 @@ clutter_event_set_coords (ClutterEvent *event,
case CLUTTER_PAD_BUTTON_RELEASE:
case CLUTTER_PAD_STRIP:
case CLUTTER_PAD_RING:
case CLUTTER_DEVICE_ADDED:
case CLUTTER_DEVICE_REMOVED:
case CLUTTER_IM_COMMIT:
case CLUTTER_IM_DELETE:
case CLUTTER_IM_PREEDIT:
break;
case CLUTTER_ENTER:
@ -697,6 +715,9 @@ clutter_event_set_scroll_delta (ClutterEvent *event,
g_return_if_fail (event != NULL);
g_return_if_fail (event->type == CLUTTER_SCROLL);
if (!is_event_allocated (event))
return;
event->scroll.direction = CLUTTER_SCROLL_SMOOTH;
((ClutterEventPrivate *) event)->delta_x = dx;
@ -727,8 +748,13 @@ clutter_event_get_scroll_delta (const ClutterEvent *event,
g_return_if_fail (event->type == CLUTTER_SCROLL);
g_return_if_fail (event->scroll.direction == CLUTTER_SCROLL_SMOOTH);
delta_x = ((ClutterEventPrivate *) event)->delta_x;
delta_y = ((ClutterEventPrivate *) event)->delta_y;
delta_x = delta_y = 0;
if (is_event_allocated (event))
{
delta_x = ((ClutterEventPrivate *) event)->delta_x;
delta_y = ((ClutterEventPrivate *) event)->delta_y;
}
if (dx != NULL)
*dx = delta_x;
@ -1002,6 +1028,29 @@ clutter_event_get_event_sequence (const ClutterEvent *event)
return NULL;
}
/**
* clutter_event_get_device_id:
* @event: a clutter event
*
* Retrieves the events device id if set.
*
* Return value: A unique identifier for the device or -1 if the event has
* no specific device set.
*/
gint
clutter_event_get_device_id (const ClutterEvent *event)
{
ClutterInputDevice *device = NULL;
g_return_val_if_fail (event != NULL, CLUTTER_POINTER_DEVICE);
device = clutter_event_get_device (event);
if (device != NULL)
return clutter_input_device_get_device_id (device);
return -1;
}
/**
* clutter_event_get_device_type:
* @event: a #ClutterEvent
@ -1040,20 +1089,24 @@ void
clutter_event_set_device (ClutterEvent *event,
ClutterInputDevice *device)
{
ClutterEventPrivate *real_event = (ClutterEventPrivate *) event;
g_return_if_fail (event != NULL);
g_return_if_fail (device == NULL || CLUTTER_IS_INPUT_DEVICE (device));
g_set_object (&real_event->device, device);
if (is_event_allocated (event))
{
ClutterEventPrivate *real_event = (ClutterEventPrivate *) event;
g_set_object (&real_event->device, device);
}
switch (event->type)
{
case CLUTTER_NOTHING:
case CLUTTER_STAGE_STATE:
case CLUTTER_DESTROY_NOTIFY:
case CLUTTER_CLIENT_MESSAGE:
case CLUTTER_DELETE:
case CLUTTER_EVENT_LAST:
case CLUTTER_IM_COMMIT:
case CLUTTER_IM_DELETE:
case CLUTTER_IM_PREEDIT:
break;
case CLUTTER_ENTER:
@ -1108,11 +1161,6 @@ clutter_event_set_device (ClutterEvent *event,
case CLUTTER_PAD_RING:
event->pad_ring.device = device;
break;
case CLUTTER_DEVICE_ADDED:
case CLUTTER_DEVICE_REMOVED:
event->device.device = device;
break;
}
}
@ -1137,19 +1185,24 @@ ClutterInputDevice *
clutter_event_get_device (const ClutterEvent *event)
{
ClutterInputDevice *device = NULL;
ClutterEventPrivate *real_event = (ClutterEventPrivate *) event;
g_return_val_if_fail (event != NULL, NULL);
if (real_event->device != NULL)
return real_event->device;
if (is_event_allocated (event))
{
ClutterEventPrivate *real_event = (ClutterEventPrivate *) event;
if (real_event->device != NULL)
return real_event->device;
}
switch (event->type)
{
case CLUTTER_NOTHING:
case CLUTTER_IM_COMMIT:
case CLUTTER_IM_DELETE:
case CLUTTER_IM_PREEDIT:
case CLUTTER_STAGE_STATE:
case CLUTTER_DESTROY_NOTIFY:
case CLUTTER_CLIENT_MESSAGE:
case CLUTTER_DELETE:
case CLUTTER_EVENT_LAST:
break;
@ -1205,11 +1258,6 @@ clutter_event_get_device (const ClutterEvent *event)
case CLUTTER_PAD_RING:
device = event->pad_ring.device;
break;
case CLUTTER_DEVICE_ADDED:
case CLUTTER_DEVICE_REMOVED:
device = event->device.device;
break;
}
return device;
@ -1228,11 +1276,14 @@ void
clutter_event_set_device_tool (ClutterEvent *event,
ClutterInputDeviceTool *tool)
{
ClutterEventPrivate *real_event = (ClutterEventPrivate *) event;
g_return_if_fail (event != NULL);
real_event->tool = tool;
if (is_event_allocated (event))
{
ClutterEventPrivate *real_event = (ClutterEventPrivate *) event;
real_event->tool = tool;
}
}
/**
@ -1248,11 +1299,16 @@ clutter_event_set_device_tool (ClutterEvent *event,
ClutterInputDeviceTool *
clutter_event_get_device_tool (const ClutterEvent *event)
{
ClutterEventPrivate *real_event = (ClutterEventPrivate *) event;
g_return_val_if_fail (event != NULL, NULL);
return real_event->tool;
if (is_event_allocated (event))
{
ClutterEventPrivate *real_event = (ClutterEventPrivate *) event;
return real_event->tool;
}
return NULL;
}
/**
@ -1269,11 +1325,16 @@ clutter_event_new (ClutterEventType type)
ClutterEvent *new_event;
ClutterEventPrivate *priv;
priv = g_new0 (ClutterEventPrivate, 1);
priv = g_slice_new0 (ClutterEventPrivate);
new_event = (ClutterEvent *) priv;
new_event->type = new_event->any.type = type;
if (G_UNLIKELY (all_events == NULL))
all_events = g_hash_table_new (NULL, NULL);
g_hash_table_replace (all_events, priv, GUINT_TO_POINTER (1));
return new_event;
}
@ -1290,7 +1351,8 @@ clutter_event_copy (const ClutterEvent *event)
{
ClutterEvent *new_event;
ClutterEventPrivate *new_real_event;
ClutterEventPrivate *real_event = (ClutterEventPrivate *) event;
ClutterInputDevice *device;
gint n_axes = 0;
g_return_val_if_fail (event != NULL, NULL);
@ -1299,45 +1361,45 @@ clutter_event_copy (const ClutterEvent *event)
*new_event = *event;
g_set_object (&new_real_event->device, real_event->device);
g_set_object (&new_real_event->source_device, real_event->source_device);
new_real_event->delta_x = real_event->delta_x;
new_real_event->delta_y = real_event->delta_y;
new_real_event->is_pointer_emulated = real_event->is_pointer_emulated;
new_real_event->base_state = real_event->base_state;
new_real_event->button_state = real_event->button_state;
new_real_event->latched_state = real_event->latched_state;
new_real_event->locked_state = real_event->locked_state;
new_real_event->tool = real_event->tool;
if (is_event_allocated (event))
{
ClutterEventPrivate *real_event = (ClutterEventPrivate *) event;
g_set_object (&new_real_event->device, real_event->device);
g_set_object (&new_real_event->source_device, real_event->source_device);
new_real_event->delta_x = real_event->delta_x;
new_real_event->delta_y = real_event->delta_y;
new_real_event->is_pointer_emulated = real_event->is_pointer_emulated;
new_real_event->base_state = real_event->base_state;
new_real_event->button_state = real_event->button_state;
new_real_event->latched_state = real_event->latched_state;
new_real_event->locked_state = real_event->locked_state;
new_real_event->tool = real_event->tool;
}
device = clutter_event_get_device (event);
if (device != NULL)
n_axes = clutter_input_device_get_n_axes (device);
switch (event->type)
{
case CLUTTER_BUTTON_PRESS:
case CLUTTER_BUTTON_RELEASE:
if (event->button.axes != NULL)
{
new_event->button.axes =
g_memdup2 (event->button.axes,
sizeof (double) * CLUTTER_INPUT_AXIS_LAST);
}
new_event->button.axes = g_memdup (event->button.axes,
sizeof (gdouble) * n_axes);
break;
case CLUTTER_SCROLL:
if (event->scroll.axes != NULL)
{
new_event->scroll.axes =
g_memdup2 (event->scroll.axes,
sizeof (double) * CLUTTER_INPUT_AXIS_LAST);
}
new_event->scroll.axes = g_memdup (event->scroll.axes,
sizeof (gdouble) * n_axes);
break;
case CLUTTER_MOTION:
if (event->motion.axes != NULL)
{
new_event->motion.axes =
g_memdup2 (event->motion.axes,
sizeof (double) * CLUTTER_INPUT_AXIS_LAST);
}
new_event->motion.axes = g_memdup (event->motion.axes,
sizeof (gdouble) * n_axes);
break;
case CLUTTER_TOUCH_BEGIN:
@ -1345,26 +1407,19 @@ clutter_event_copy (const ClutterEvent *event)
case CLUTTER_TOUCH_END:
case CLUTTER_TOUCH_CANCEL:
if (event->touch.axes != NULL)
{
new_event->touch.axes =
g_memdup2 (event->touch.axes,
sizeof (double) * CLUTTER_INPUT_AXIS_LAST);
}
break;
case CLUTTER_DEVICE_ADDED:
case CLUTTER_DEVICE_REMOVED:
new_event->device.device = event->device.device;
break;
case CLUTTER_IM_COMMIT:
case CLUTTER_IM_PREEDIT:
new_event->im.text = g_strdup (event->im.text);
new_event->touch.axes = g_memdup (event->touch.axes,
sizeof (gdouble) * n_axes);
break;
default:
break;
}
if (is_event_allocated (event))
_clutter_backend_copy_event_data (clutter_get_default_backend (),
event,
new_event);
return new_event;
}
@ -1379,10 +1434,15 @@ clutter_event_free (ClutterEvent *event)
{
if (G_LIKELY (event != NULL))
{
ClutterEventPrivate *real_event = (ClutterEventPrivate *) event;
_clutter_backend_free_event_data (clutter_get_default_backend (), event);
g_clear_object (&real_event->device);
g_clear_object (&real_event->source_device);
if (is_event_allocated (event))
{
ClutterEventPrivate *real_event = (ClutterEventPrivate *) event;
g_clear_object (&real_event->device);
g_clear_object (&real_event->source_device);
}
switch (event->type)
{
@ -1406,16 +1466,12 @@ clutter_event_free (ClutterEvent *event)
g_free (event->touch.axes);
break;
case CLUTTER_IM_COMMIT:
case CLUTTER_IM_PREEDIT:
g_free (event->im.text);
break;
default:
break;
}
g_free ((ClutterEventPrivate *) event);
g_hash_table_remove (all_events, event);
g_slice_free (ClutterEventPrivate, (ClutterEventPrivate *) event);
}
}
@ -1433,11 +1489,40 @@ ClutterEvent *
clutter_event_get (void)
{
ClutterMainContext *context = _clutter_context_get_default ();
ClutterEvent *event;
event = g_async_queue_try_pop (context->events_queue);
if (context->events_queue == NULL)
return NULL;
return event;
if (g_queue_is_empty (context->events_queue))
return NULL;
return g_queue_pop_tail (context->events_queue);
}
/**
* clutter_event_peek:
*
* Returns a pointer to the first event from the event queue but
* does not remove it.
*
* Return value: (transfer none): A #ClutterEvent or NULL if queue empty.
*
* Since: 0.4
*/
ClutterEvent *
clutter_event_peek (void)
{
ClutterMainContext *context = _clutter_context_get_default ();
g_return_val_if_fail (context != NULL, NULL);
if (context->events_queue == NULL)
return NULL;
if (g_queue_is_empty (context->events_queue))
return NULL;
return g_queue_peek_tail (context->events_queue);
}
void
@ -1445,9 +1530,21 @@ _clutter_event_push (const ClutterEvent *event,
gboolean do_copy)
{
ClutterMainContext *context = _clutter_context_get_default ();
ClutterInputDevice *device;
g_assert (context != NULL);
if (context->events_queue == NULL)
context->events_queue = g_queue_new ();
/* disabled devices don't propagate events */
device = clutter_event_get_device (event);
if (device != NULL)
{
if (!clutter_input_device_get_enabled (device))
return;
}
if (do_copy)
{
ClutterEvent *copy;
@ -1456,8 +1553,7 @@ _clutter_event_push (const ClutterEvent *event,
event = copy;
}
g_async_queue_push (context->events_queue, (gpointer) event);
g_main_context_wakeup (NULL);
g_queue_push_head (context->events_queue, (gpointer) event);
}
/**
@ -1494,7 +1590,10 @@ clutter_events_pending (void)
g_return_val_if_fail (context != NULL, FALSE);
return g_async_queue_length (context->events_queue) > 0;
if (context->events_queue == NULL)
return FALSE;
return g_queue_is_empty (context->events_queue) == FALSE;
}
/**
@ -1564,6 +1663,9 @@ clutter_event_get_source_device (const ClutterEvent *event)
{
ClutterEventPrivate *real_event;
if (!is_event_allocated (event))
return NULL;
real_event = (ClutterEventPrivate *) event;
if (real_event->source_device != NULL)
@ -1592,6 +1694,9 @@ clutter_event_set_source_device (ClutterEvent *event,
g_return_if_fail (event != NULL);
g_return_if_fail (device == NULL || CLUTTER_IS_INPUT_DEVICE (device));
if (!is_event_allocated (event))
return;
real_event = (ClutterEventPrivate *) event;
g_set_object (&real_event->source_device, device);
}
@ -1612,10 +1717,15 @@ clutter_event_get_axes (const ClutterEvent *event,
guint *n_axes)
{
gdouble *retval = NULL;
guint len = 0;
switch (event->type)
{
case CLUTTER_NOTHING:
case CLUTTER_STAGE_STATE:
case CLUTTER_DESTROY_NOTIFY:
case CLUTTER_CLIENT_MESSAGE:
case CLUTTER_DELETE:
case CLUTTER_ENTER:
case CLUTTER_LEAVE:
case CLUTTER_KEY_PRESS:
@ -1623,8 +1733,6 @@ clutter_event_get_axes (const ClutterEvent *event,
case CLUTTER_EVENT_LAST:
case CLUTTER_PROXIMITY_IN:
case CLUTTER_PROXIMITY_OUT:
case CLUTTER_DEVICE_ADDED:
case CLUTTER_DEVICE_REMOVED:
break;
case CLUTTER_SCROLL:
@ -1653,14 +1761,22 @@ clutter_event_get_axes (const ClutterEvent *event,
case CLUTTER_PAD_BUTTON_RELEASE:
case CLUTTER_PAD_STRIP:
case CLUTTER_PAD_RING:
case CLUTTER_IM_COMMIT:
case CLUTTER_IM_DELETE:
case CLUTTER_IM_PREEDIT:
break;
}
if (retval != NULL)
{
ClutterInputDevice *device;
device = clutter_event_get_device (event);
if (device != NULL)
len = clutter_input_device_get_n_axes (device);
else
retval = NULL;
}
if (n_axes)
*n_axes = CLUTTER_INPUT_AXIS_LAST;
*n_axes = len;
return retval;
}
@ -1779,6 +1895,9 @@ clutter_event_is_pointer_emulated (const ClutterEvent *event)
{
g_return_val_if_fail (event != NULL, FALSE);
if (!is_event_allocated (event))
return FALSE;
return ((ClutterEventPrivate *) event)->is_pointer_emulated;
}
@ -1830,7 +1949,7 @@ clutter_event_add_filter (ClutterStage *stage,
gpointer user_data)
{
ClutterMainContext *context = _clutter_context_get_default ();
ClutterEventFilter *event_filter = g_new0 (ClutterEventFilter, 1);
ClutterEventFilter *event_filter = g_slice_new (ClutterEventFilter);
static guint event_filter_id = 0;
event_filter->stage = stage;
@ -1871,7 +1990,7 @@ clutter_event_remove_filter (guint id)
event_filter->notify (event_filter->user_data);
context->event_filters = g_list_delete_link (context->event_filters, l);
g_free (event_filter);
g_slice_free (ClutterEventFilter, event_filter);
return;
}
}
@ -2007,42 +2126,6 @@ clutter_event_get_gesture_motion_delta (const ClutterEvent *event,
}
}
/**
* clutter_event_get_gesture_motion_delta_unaccelerated:
* @event: A clutter touchpad gesture event
* @dx: (out) (allow-none): the displacement relative to the pointer
* position in the X axis, or %NULL
* @dy: (out) (allow-none): the displacement relative to the pointer
* position in the Y axis, or %NULL
*
* Returns the unaccelerated gesture motion deltas relative to the current
* pointer position. Unlike clutter_event_get_gesture_motion_delta(),
* pointer acceleration is ignored.
**/
void
clutter_event_get_gesture_motion_delta_unaccelerated (const ClutterEvent *event,
gdouble *dx,
gdouble *dy)
{
g_return_if_fail (event != NULL);
g_return_if_fail (event->type == CLUTTER_TOUCHPAD_PINCH ||
event->type == CLUTTER_TOUCHPAD_SWIPE);
if (event->type == CLUTTER_TOUCHPAD_PINCH)
{
if (dx)
*dx = event->touchpad_pinch.dx_unaccel;
if (dy)
*dy = event->touchpad_pinch.dy_unaccel;
}
else if (event->type == CLUTTER_TOUCHPAD_SWIPE)
{
if (dx)
*dx = event->touchpad_swipe.dx_unaccel;
if (dy)
*dy = event->touchpad_swipe.dy_unaccel;
}
}
/**
* clutter_event_get_scroll_source:
* @event: an scroll event
@ -2163,58 +2246,3 @@ clutter_event_get_pad_event_details (const ClutterEvent *event,
return TRUE;
}
uint32_t
clutter_event_get_event_code (const ClutterEvent *event)
{
if (event->type == CLUTTER_KEY_PRESS ||
event->type == CLUTTER_KEY_RELEASE)
return event->key.evdev_code;
else if (event->type == CLUTTER_BUTTON_PRESS ||
event->type == CLUTTER_BUTTON_RELEASE)
return event->button.evdev_code;
return 0;
}
int32_t
clutter_event_sequence_get_slot (const ClutterEventSequence *sequence)
{
g_return_val_if_fail (sequence != NULL, -1);
return GPOINTER_TO_INT (sequence) - 1;
}
int64_t
clutter_event_get_time_us (const ClutterEvent *event)
{
if (event->type == CLUTTER_MOTION)
return event->motion.time_us;
return 0;
}
gboolean
clutter_event_get_relative_motion (const ClutterEvent *event,
double *dx,
double *dy,
double *dx_unaccel,
double *dy_unaccel)
{
if (event->type == CLUTTER_MOTION &&
event->motion.flags & CLUTTER_EVENT_FLAG_RELATIVE_MOTION)
{
if (dx)
*dx = event->motion.dx;
if (dy)
*dy = event->motion.dy;
if (dx_unaccel)
*dx_unaccel = event->motion.dx_unaccel;
if (dy_unaccel)
*dy_unaccel = event->motion.dy_unaccel;
return TRUE;
}
else
return FALSE;
}

View File

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

View File

@ -139,11 +139,7 @@ clutter_fixed_layout_allocate (ClutterLayoutManager *manager,
child != NULL;
child = clutter_actor_get_next_sibling (child))
{
float x = 0.f;
float y = 0.f;
clutter_actor_get_fixed_position (child, &x, &y);
clutter_actor_allocate_preferred_size (child, x, y);
clutter_actor_allocate_preferred_size (child);
}
}

View File

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

View File

@ -1,843 +0,0 @@
/*
* Copyright (C) 2019 Red Hat Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include "clutter-build-config.h"
#include "clutter/clutter-frame-clock.h"
#include "clutter/clutter-debug.h"
#include "clutter/clutter-main.h"
#include "clutter/clutter-private.h"
#include "clutter/clutter-timeline-private.h"
#include "cogl/cogl-trace.h"
enum
{
DESTROY,
N_SIGNALS
};
static guint signals[N_SIGNALS];
/* An estimate queue holds several int64_t values. Adding a new value to the
* queue overwrites the oldest value.
*/
#define ESTIMATE_QUEUE_LENGTH 16
typedef struct _EstimateQueue
{
int64_t values[ESTIMATE_QUEUE_LENGTH];
int next_index;
} EstimateQueue;
/* When heuristic render time is off,
* wait 2ms after vblank before starting to draw next frame.
*/
#define SYNC_DELAY_FALLBACK_US ms2us (2)
typedef struct _ClutterFrameListener
{
const ClutterFrameListenerIface *iface;
gpointer user_data;
} ClutterFrameListener;
typedef struct _ClutterClockSource
{
GSource source;
ClutterFrameClock *frame_clock;
} ClutterClockSource;
typedef enum _ClutterFrameClockState
{
CLUTTER_FRAME_CLOCK_STATE_INIT,
CLUTTER_FRAME_CLOCK_STATE_IDLE,
CLUTTER_FRAME_CLOCK_STATE_SCHEDULED,
CLUTTER_FRAME_CLOCK_STATE_DISPATCHING,
CLUTTER_FRAME_CLOCK_STATE_PENDING_PRESENTED,
} ClutterFrameClockState;
struct _ClutterFrameClock
{
GObject parent;
float refresh_rate;
int64_t refresh_interval_us;
ClutterFrameListener listener;
GSource *source;
int64_t frame_count;
ClutterFrameClockState state;
int64_t last_dispatch_time_us;
int64_t last_dispatch_lateness_us;
int64_t last_presentation_time_us;
gboolean is_next_presentation_time_valid;
int64_t next_presentation_time_us;
/* Buffer must be submitted to KMS and GPU rendering must be finished
* this amount of time before the next presentation time.
*/
int64_t vblank_duration_us;
/* Last KMS buffer submission time. */
int64_t last_flip_time_us;
/* Last few durations between dispatch start and buffer swap. */
EstimateQueue dispatch_to_swap_us;
/* Last few durations between buffer swap and GPU rendering finish. */
EstimateQueue swap_to_rendering_done_us;
/* Last few durations between buffer swap and KMS submission. */
EstimateQueue swap_to_flip_us;
/* If we got new measurements last frame. */
gboolean got_measurements_last_frame;
gboolean pending_reschedule;
gboolean pending_reschedule_now;
int inhibit_count;
GList *timelines;
};
G_DEFINE_TYPE (ClutterFrameClock, clutter_frame_clock,
G_TYPE_OBJECT)
static void
estimate_queue_add_value (EstimateQueue *queue,
int64_t value)
{
queue->values[queue->next_index] = value;
queue->next_index = (queue->next_index + 1) % ESTIMATE_QUEUE_LENGTH;
}
float
clutter_frame_clock_get_refresh_rate (ClutterFrameClock *frame_clock)
{
return frame_clock->refresh_rate;
}
static void
clutter_frame_clock_set_refresh_rate (ClutterFrameClock *frame_clock,
float refresh_rate)
{
frame_clock->refresh_rate = refresh_rate;
frame_clock->refresh_interval_us =
(int64_t) (0.5 + G_USEC_PER_SEC / refresh_rate);
}
void
clutter_frame_clock_add_timeline (ClutterFrameClock *frame_clock,
ClutterTimeline *timeline)
{
gboolean is_first;
if (g_list_find (frame_clock->timelines, timeline))
return;
is_first = !frame_clock->timelines;
frame_clock->timelines = g_list_prepend (frame_clock->timelines, timeline);
if (is_first)
clutter_frame_clock_schedule_update (frame_clock);
}
void
clutter_frame_clock_remove_timeline (ClutterFrameClock *frame_clock,
ClutterTimeline *timeline)
{
frame_clock->timelines = g_list_remove (frame_clock->timelines, timeline);
}
static void
advance_timelines (ClutterFrameClock *frame_clock,
int64_t time_us)
{
GList *timelines;
GList *l;
/* we protect ourselves from timelines being removed during
* the advancement by other timelines by copying the list of
* timelines, taking a reference on them, iterating over the
* copied list and then releasing the reference.
*
* we cannot simply take a reference on the timelines and still
* use the list held by the master clock because the do_tick()
* might result in the creation of a new timeline, which gets
* added at the end of the list with no reference increase and
* thus gets disposed at the end of the iteration.
*
* this implies that a newly added timeline will not be advanced
* by this clock iteration, which is perfectly fine since we're
* in its first cycle.
*
* we also cannot steal the frame clock timelines list because
* a timeline might be removed as the direct result of do_tick()
* and remove_timeline() would not find the timeline, failing
* and leaving a dangling pointer behind.
*/
timelines = g_list_copy (frame_clock->timelines);
g_list_foreach (timelines, (GFunc) g_object_ref, NULL);
for (l = timelines; l; l = l->next)
{
ClutterTimeline *timeline = l->data;
_clutter_timeline_do_tick (timeline, time_us / 1000);
}
g_list_free_full (timelines, g_object_unref);
}
static void
maybe_reschedule_update (ClutterFrameClock *frame_clock)
{
if (frame_clock->pending_reschedule ||
frame_clock->timelines)
{
frame_clock->pending_reschedule = FALSE;
if (frame_clock->pending_reschedule_now)
{
frame_clock->pending_reschedule_now = FALSE;
clutter_frame_clock_schedule_update_now (frame_clock);
}
else
{
clutter_frame_clock_schedule_update (frame_clock);
}
}
}
void
clutter_frame_clock_notify_presented (ClutterFrameClock *frame_clock,
ClutterFrameInfo *frame_info)
{
frame_clock->last_presentation_time_us = frame_info->presentation_time;
frame_clock->got_measurements_last_frame = FALSE;
if (frame_info->cpu_time_before_buffer_swap_us != 0 &&
frame_info->gpu_rendering_duration_ns != 0)
{
int64_t dispatch_to_swap_us, swap_to_rendering_done_us, swap_to_flip_us;
dispatch_to_swap_us =
frame_info->cpu_time_before_buffer_swap_us -
frame_clock->last_dispatch_time_us;
swap_to_rendering_done_us =
frame_info->gpu_rendering_duration_ns / 1000;
swap_to_flip_us =
frame_clock->last_flip_time_us -
frame_info->cpu_time_before_buffer_swap_us;
CLUTTER_NOTE (FRAME_TIMINGS,
"dispatch2swap %ld µs, swap2render %ld µs, swap2flip %ld µs",
dispatch_to_swap_us,
swap_to_rendering_done_us,
swap_to_flip_us);
estimate_queue_add_value (&frame_clock->dispatch_to_swap_us,
dispatch_to_swap_us);
estimate_queue_add_value (&frame_clock->swap_to_rendering_done_us,
swap_to_rendering_done_us);
estimate_queue_add_value (&frame_clock->swap_to_flip_us,
swap_to_flip_us);
frame_clock->got_measurements_last_frame = TRUE;
}
if (frame_info->refresh_rate > 1)
{
clutter_frame_clock_set_refresh_rate (frame_clock,
frame_info->refresh_rate);
}
switch (frame_clock->state)
{
case CLUTTER_FRAME_CLOCK_STATE_INIT:
case CLUTTER_FRAME_CLOCK_STATE_IDLE:
case CLUTTER_FRAME_CLOCK_STATE_SCHEDULED:
g_warn_if_reached ();
break;
case CLUTTER_FRAME_CLOCK_STATE_DISPATCHING:
case CLUTTER_FRAME_CLOCK_STATE_PENDING_PRESENTED:
frame_clock->state = CLUTTER_FRAME_CLOCK_STATE_IDLE;
maybe_reschedule_update (frame_clock);
break;
}
}
void
clutter_frame_clock_notify_ready (ClutterFrameClock *frame_clock)
{
switch (frame_clock->state)
{
case CLUTTER_FRAME_CLOCK_STATE_INIT:
case CLUTTER_FRAME_CLOCK_STATE_IDLE:
case CLUTTER_FRAME_CLOCK_STATE_SCHEDULED:
g_warn_if_reached ();
break;
case CLUTTER_FRAME_CLOCK_STATE_DISPATCHING:
case CLUTTER_FRAME_CLOCK_STATE_PENDING_PRESENTED:
frame_clock->state = CLUTTER_FRAME_CLOCK_STATE_IDLE;
maybe_reschedule_update (frame_clock);
break;
}
}
static int64_t
clutter_frame_clock_compute_max_render_time_us (ClutterFrameClock *frame_clock)
{
int64_t refresh_interval_us;
int64_t max_dispatch_to_swap_us = 0;
int64_t max_swap_to_rendering_done_us = 0;
int64_t max_swap_to_flip_us = 0;
int64_t max_render_time_us;
int i;
refresh_interval_us =
(int64_t) (0.5 + G_USEC_PER_SEC / frame_clock->refresh_rate);
if (!frame_clock->got_measurements_last_frame ||
G_UNLIKELY (clutter_paint_debug_flags &
CLUTTER_DEBUG_DISABLE_DYNAMIC_MAX_RENDER_TIME))
return refresh_interval_us - SYNC_DELAY_FALLBACK_US;
for (i = 0; i < ESTIMATE_QUEUE_LENGTH; ++i)
{
max_dispatch_to_swap_us =
MAX (max_dispatch_to_swap_us,
frame_clock->dispatch_to_swap_us.values[i]);
max_swap_to_rendering_done_us =
MAX (max_swap_to_rendering_done_us,
frame_clock->swap_to_rendering_done_us.values[i]);
max_swap_to_flip_us =
MAX (max_swap_to_flip_us,
frame_clock->swap_to_flip_us.values[i]);
}
/* Max render time shows how early the frame clock needs to be dispatched
* to make it to the predicted next presentation time. It is composed of:
* - An estimate of duration from dispatch start to buffer swap.
* - Maximum between estimates of duration from buffer swap to GPU rendering
* finish and duration from buffer swap to buffer submission to KMS. This
* is because both of these things need to happen before the vblank, and
* they are done in parallel.
* - Duration of the vblank.
* - A constant to account for variations in the above estimates.
*/
max_render_time_us =
max_dispatch_to_swap_us +
MAX (max_swap_to_rendering_done_us, max_swap_to_flip_us) +
frame_clock->vblank_duration_us +
clutter_max_render_time_constant_us;
max_render_time_us = CLAMP (max_render_time_us, 0, refresh_interval_us);
return max_render_time_us;
}
static void
calculate_next_update_time_us (ClutterFrameClock *frame_clock,
int64_t *out_next_update_time_us,
int64_t *out_next_presentation_time_us)
{
int64_t last_presentation_time_us;
int64_t now_us;
int64_t refresh_interval_us;
int64_t min_render_time_allowed_us;
int64_t max_render_time_allowed_us;
int64_t last_next_presentation_time_us;
int64_t time_since_last_next_presentation_time_us;
int64_t next_presentation_time_us;
int64_t next_update_time_us;
now_us = g_get_monotonic_time ();
refresh_interval_us = frame_clock->refresh_interval_us;
if (frame_clock->last_presentation_time_us == 0)
{
*out_next_update_time_us =
frame_clock->last_dispatch_time_us ?
((frame_clock->last_dispatch_time_us -
frame_clock->last_dispatch_lateness_us) + refresh_interval_us) :
now_us;
*out_next_presentation_time_us = 0;
return;
}
min_render_time_allowed_us = refresh_interval_us / 2;
max_render_time_allowed_us =
clutter_frame_clock_compute_max_render_time_us (frame_clock);
if (min_render_time_allowed_us > max_render_time_allowed_us)
min_render_time_allowed_us = max_render_time_allowed_us;
/*
* The common case is that the next presentation happens 1 refresh interval
* after the last presentation:
*
* last_presentation_time_us
* / next_presentation_time_us
* / /
* / /
* |--|--o----|-------|--> presentation times
* | | \ |
* | | now_us
* | \______/
* | refresh_interval_us
* |
* 0
*
*/
last_presentation_time_us = frame_clock->last_presentation_time_us;
next_presentation_time_us = last_presentation_time_us + refresh_interval_us;
/*
* However, the last presentation could have happened more than a frame ago.
* For example, due to idling (nothing on screen changed, so no need to
* redraw) or due to frames missing deadlines (GPU busy with heavy rendering).
* The following code adjusts next_presentation_time_us to be in the future,
* but still aligned to display presentation times. Instead of
* next presentation = last presentation + 1 * refresh interval, it will be
* next presentation = last presentation + N * refresh interval.
*/
if (next_presentation_time_us < now_us)
{
int64_t presentation_phase_us;
int64_t current_phase_us;
int64_t current_refresh_interval_start_us;
/*
* Let's say we're just past next_presentation_time_us.
*
* First, we compute presentation_phase_us. Real presentation times don't
* have to be exact multiples of refresh_interval_us and
* presentation_phase_us represents this difference. Next, we compute
* current phase and the refresh interval start corresponding to now_us.
* Finally, add presentation_phase_us and a refresh interval to get the
* next presentation after now_us.
*
* last_presentation_time_us
* / next_presentation_time_us
* / / now_us
* / / / new next_presentation_time_us
* |--|-------|---o---|-------|--> presentation times
* | __|
* | |presentation_phase_us
* | |
* | | now_us - presentation_phase_us
* | | /
* |-------|---o---|-------|-----> integer multiples of refresh_interval_us
* | \__/
* | |current_phase_us
* | \
* | current_refresh_interval_start_us
* 0
*
*/
presentation_phase_us = last_presentation_time_us % refresh_interval_us;
current_phase_us = (now_us - presentation_phase_us) % refresh_interval_us;
current_refresh_interval_start_us =
now_us - presentation_phase_us - current_phase_us;
next_presentation_time_us =
current_refresh_interval_start_us +
presentation_phase_us +
refresh_interval_us;
}
/*
* Skip one interval if we got an early presented event.
*
* last frame this was last_presentation_time
* / frame_clock->next_presentation_time_us
* / /
* |---|-o-----|-x----->
* | \
* \ next_presentation_time_us is thus right after the last one
* but got an unexpected early presentation
* \_/
* time_since_last_next_presentation_time_us
*
*/
last_next_presentation_time_us = frame_clock->next_presentation_time_us;
time_since_last_next_presentation_time_us =
next_presentation_time_us - last_next_presentation_time_us;
if (frame_clock->is_next_presentation_time_valid &&
time_since_last_next_presentation_time_us < (refresh_interval_us / 2))
{
next_presentation_time_us =
frame_clock->next_presentation_time_us + refresh_interval_us;
}
while (next_presentation_time_us < now_us + min_render_time_allowed_us)
next_presentation_time_us += refresh_interval_us;
next_update_time_us = next_presentation_time_us - max_render_time_allowed_us;
*out_next_update_time_us = next_update_time_us;
*out_next_presentation_time_us = next_presentation_time_us;
}
void
clutter_frame_clock_inhibit (ClutterFrameClock *frame_clock)
{
frame_clock->inhibit_count++;
if (frame_clock->inhibit_count == 1)
{
switch (frame_clock->state)
{
case CLUTTER_FRAME_CLOCK_STATE_INIT:
case CLUTTER_FRAME_CLOCK_STATE_IDLE:
break;
case CLUTTER_FRAME_CLOCK_STATE_SCHEDULED:
frame_clock->pending_reschedule = TRUE;
frame_clock->state = CLUTTER_FRAME_CLOCK_STATE_IDLE;
break;
case CLUTTER_FRAME_CLOCK_STATE_DISPATCHING:
case CLUTTER_FRAME_CLOCK_STATE_PENDING_PRESENTED:
break;
}
g_source_set_ready_time (frame_clock->source, -1);
}
}
void
clutter_frame_clock_uninhibit (ClutterFrameClock *frame_clock)
{
g_return_if_fail (frame_clock->inhibit_count > 0);
frame_clock->inhibit_count--;
if (frame_clock->inhibit_count == 0)
maybe_reschedule_update (frame_clock);
}
void
clutter_frame_clock_schedule_update_now (ClutterFrameClock *frame_clock)
{
int64_t next_update_time_us = -1;
if (frame_clock->inhibit_count > 0)
{
frame_clock->pending_reschedule = TRUE;
frame_clock->pending_reschedule_now = TRUE;
return;
}
switch (frame_clock->state)
{
case CLUTTER_FRAME_CLOCK_STATE_INIT:
case CLUTTER_FRAME_CLOCK_STATE_IDLE:
next_update_time_us = g_get_monotonic_time ();
break;
case CLUTTER_FRAME_CLOCK_STATE_SCHEDULED:
return;
case CLUTTER_FRAME_CLOCK_STATE_DISPATCHING:
case CLUTTER_FRAME_CLOCK_STATE_PENDING_PRESENTED:
frame_clock->pending_reschedule = TRUE;
frame_clock->pending_reschedule_now = TRUE;
return;
}
g_warn_if_fail (next_update_time_us != -1);
g_source_set_ready_time (frame_clock->source, next_update_time_us);
frame_clock->state = CLUTTER_FRAME_CLOCK_STATE_SCHEDULED;
frame_clock->is_next_presentation_time_valid = FALSE;
}
void
clutter_frame_clock_schedule_update (ClutterFrameClock *frame_clock)
{
int64_t next_update_time_us = -1;
if (frame_clock->inhibit_count > 0)
{
frame_clock->pending_reschedule = TRUE;
return;
}
switch (frame_clock->state)
{
case CLUTTER_FRAME_CLOCK_STATE_INIT:
next_update_time_us = g_get_monotonic_time ();
break;
case CLUTTER_FRAME_CLOCK_STATE_IDLE:
calculate_next_update_time_us (frame_clock,
&next_update_time_us,
&frame_clock->next_presentation_time_us);
frame_clock->is_next_presentation_time_valid =
(frame_clock->next_presentation_time_us != 0);
break;
case CLUTTER_FRAME_CLOCK_STATE_SCHEDULED:
return;
case CLUTTER_FRAME_CLOCK_STATE_DISPATCHING:
case CLUTTER_FRAME_CLOCK_STATE_PENDING_PRESENTED:
frame_clock->pending_reschedule = TRUE;
return;
}
g_warn_if_fail (next_update_time_us != -1);
g_source_set_ready_time (frame_clock->source, next_update_time_us);
frame_clock->state = CLUTTER_FRAME_CLOCK_STATE_SCHEDULED;
}
static void
clutter_frame_clock_dispatch (ClutterFrameClock *frame_clock,
int64_t time_us)
{
int64_t frame_count;
ClutterFrameResult result;
int64_t ideal_dispatch_time_us, lateness_us;
COGL_TRACE_BEGIN_SCOPED (ClutterFrameClockDispatch, "Frame Clock (dispatch)");
ideal_dispatch_time_us = (frame_clock->last_dispatch_time_us -
frame_clock->last_dispatch_lateness_us) +
frame_clock->refresh_interval_us;
lateness_us = time_us - ideal_dispatch_time_us;
if (lateness_us < 0 || lateness_us >= frame_clock->refresh_interval_us)
frame_clock->last_dispatch_lateness_us = 0;
else
frame_clock->last_dispatch_lateness_us = lateness_us;
frame_clock->last_dispatch_time_us = time_us;
g_source_set_ready_time (frame_clock->source, -1);
frame_clock->state = CLUTTER_FRAME_CLOCK_STATE_DISPATCHING;
frame_count = frame_clock->frame_count++;
COGL_TRACE_BEGIN (ClutterFrameClockEvents, "Frame Clock (before frame)");
if (frame_clock->listener.iface->before_frame)
{
frame_clock->listener.iface->before_frame (frame_clock,
frame_count,
frame_clock->listener.user_data);
}
COGL_TRACE_END (ClutterFrameClockEvents);
COGL_TRACE_BEGIN (ClutterFrameClockTimelines, "Frame Clock (timelines)");
advance_timelines (frame_clock, time_us);
COGL_TRACE_END (ClutterFrameClockTimelines);
COGL_TRACE_BEGIN (ClutterFrameClockFrame, "Frame Clock (frame)");
result = frame_clock->listener.iface->frame (frame_clock,
frame_count,
time_us,
frame_clock->listener.user_data);
COGL_TRACE_END (ClutterFrameClockFrame);
switch (frame_clock->state)
{
case CLUTTER_FRAME_CLOCK_STATE_INIT:
case CLUTTER_FRAME_CLOCK_STATE_PENDING_PRESENTED:
g_warn_if_reached ();
break;
case CLUTTER_FRAME_CLOCK_STATE_IDLE:
case CLUTTER_FRAME_CLOCK_STATE_SCHEDULED:
break;
case CLUTTER_FRAME_CLOCK_STATE_DISPATCHING:
switch (result)
{
case CLUTTER_FRAME_RESULT_PENDING_PRESENTED:
frame_clock->state = CLUTTER_FRAME_CLOCK_STATE_PENDING_PRESENTED;
break;
case CLUTTER_FRAME_RESULT_IDLE:
frame_clock->state = CLUTTER_FRAME_CLOCK_STATE_IDLE;
maybe_reschedule_update (frame_clock);
break;
}
break;
}
}
static gboolean
frame_clock_source_dispatch (GSource *source,
GSourceFunc callback,
gpointer user_data)
{
ClutterClockSource *clock_source = (ClutterClockSource *) source;
ClutterFrameClock *frame_clock = clock_source->frame_clock;
int64_t dispatch_time_us;
dispatch_time_us = g_source_get_time (source);
clutter_frame_clock_dispatch (frame_clock, dispatch_time_us);
return G_SOURCE_CONTINUE;
}
void
clutter_frame_clock_record_flip_time (ClutterFrameClock *frame_clock,
int64_t flip_time_us)
{
frame_clock->last_flip_time_us = flip_time_us;
}
GString *
clutter_frame_clock_get_max_render_time_debug_info (ClutterFrameClock *frame_clock)
{
int64_t max_dispatch_to_swap_us = 0;
int64_t max_swap_to_rendering_done_us = 0;
int64_t max_swap_to_flip_us = 0;
int i;
GString *string;
string = g_string_new (NULL);
g_string_append_printf (string, "Max render time: %ld µs",
clutter_frame_clock_compute_max_render_time_us (frame_clock));
if (frame_clock->got_measurements_last_frame)
g_string_append_printf (string, " =");
else
g_string_append_printf (string, " (no measurements last frame)");
for (i = 0; i < ESTIMATE_QUEUE_LENGTH; ++i)
{
max_dispatch_to_swap_us =
MAX (max_dispatch_to_swap_us,
frame_clock->dispatch_to_swap_us.values[i]);
max_swap_to_rendering_done_us =
MAX (max_swap_to_rendering_done_us,
frame_clock->swap_to_rendering_done_us.values[i]);
max_swap_to_flip_us =
MAX (max_swap_to_flip_us,
frame_clock->swap_to_flip_us.values[i]);
}
g_string_append_printf (string, "\nVblank duration: %ld µs +",
frame_clock->vblank_duration_us);
g_string_append_printf (string, "\nDispatch to swap: %ld µs +",
max_dispatch_to_swap_us);
g_string_append_printf (string, "\nmax(Swap to rendering done: %ld µs,",
max_swap_to_rendering_done_us);
g_string_append_printf (string, "\nSwap to flip: %ld µs) +",
max_swap_to_flip_us);
g_string_append_printf (string, "\nConstant: %d µs",
clutter_max_render_time_constant_us);
return string;
}
static GSourceFuncs frame_clock_source_funcs = {
NULL,
NULL,
frame_clock_source_dispatch,
NULL
};
static void
init_frame_clock_source (ClutterFrameClock *frame_clock)
{
GSource *source;
ClutterClockSource *clock_source;
g_autofree char *name = NULL;
source = g_source_new (&frame_clock_source_funcs, sizeof (ClutterClockSource));
clock_source = (ClutterClockSource *) source;
name = g_strdup_printf ("Clutter frame clock (%p)", frame_clock);
g_source_set_name (source, name);
g_source_set_priority (source, CLUTTER_PRIORITY_REDRAW);
g_source_set_can_recurse (source, FALSE);
clock_source->frame_clock = frame_clock;
frame_clock->source = source;
g_source_attach (source, NULL);
}
ClutterFrameClock *
clutter_frame_clock_new (float refresh_rate,
int64_t vblank_duration_us,
const ClutterFrameListenerIface *iface,
gpointer user_data)
{
ClutterFrameClock *frame_clock;
g_assert_cmpfloat (refresh_rate, >, 0.0);
frame_clock = g_object_new (CLUTTER_TYPE_FRAME_CLOCK, NULL);
frame_clock->listener.iface = iface;
frame_clock->listener.user_data = user_data;
init_frame_clock_source (frame_clock);
clutter_frame_clock_set_refresh_rate (frame_clock, refresh_rate);
frame_clock->vblank_duration_us = vblank_duration_us;
return frame_clock;
}
void
clutter_frame_clock_destroy (ClutterFrameClock *frame_clock)
{
g_object_run_dispose (G_OBJECT (frame_clock));
g_object_unref (frame_clock);
}
static void
clutter_frame_clock_dispose (GObject *object)
{
ClutterFrameClock *frame_clock = CLUTTER_FRAME_CLOCK (object);
if (frame_clock->source)
{
g_signal_emit (frame_clock, signals[DESTROY], 0);
g_source_destroy (frame_clock->source);
g_clear_pointer (&frame_clock->source, g_source_unref);
}
G_OBJECT_CLASS (clutter_frame_clock_parent_class)->dispose (object);
}
static void
clutter_frame_clock_init (ClutterFrameClock *frame_clock)
{
frame_clock->state = CLUTTER_FRAME_CLOCK_STATE_INIT;
}
static void
clutter_frame_clock_class_init (ClutterFrameClockClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->dispose = clutter_frame_clock_dispose;
signals[DESTROY] =
g_signal_new (I_("destroy"),
G_TYPE_FROM_CLASS (object_class),
G_SIGNAL_RUN_LAST,
0,
NULL, NULL, NULL,
G_TYPE_NONE,
0);
}

View File

@ -1,99 +0,0 @@
/*
* Copyright (C) 2019 Red Hat Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef CLUTTER_FRAME_CLOCK_H
#define CLUTTER_FRAME_CLOCK_H
#if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION)
#error "Only <clutter/clutter.h> can be included directly."
#endif
#include <glib.h>
#include <glib-object.h>
#include <stdint.h>
#include "clutter/clutter-types.h"
typedef enum _ClutterFrameResult
{
CLUTTER_FRAME_RESULT_PENDING_PRESENTED,
CLUTTER_FRAME_RESULT_IDLE,
} ClutterFrameResult;
#define CLUTTER_TYPE_FRAME_CLOCK (clutter_frame_clock_get_type ())
CLUTTER_EXPORT
G_DECLARE_FINAL_TYPE (ClutterFrameClock, clutter_frame_clock,
CLUTTER, FRAME_CLOCK,
GObject)
/**
* ClutterFrameListenerIface: (skip)
*/
typedef struct _ClutterFrameListenerIface
{
void (* before_frame) (ClutterFrameClock *frame_clock,
int64_t frame_count,
gpointer user_data);
ClutterFrameResult (* frame) (ClutterFrameClock *frame_clock,
int64_t frame_count,
int64_t time_us,
gpointer user_data);
} ClutterFrameListenerIface;
CLUTTER_EXPORT
ClutterFrameClock * clutter_frame_clock_new (float refresh_rate,
int64_t vblank_duration_us,
const ClutterFrameListenerIface *iface,
gpointer user_data);
CLUTTER_EXPORT
void clutter_frame_clock_destroy (ClutterFrameClock *frame_clock);
CLUTTER_EXPORT
void clutter_frame_clock_notify_presented (ClutterFrameClock *frame_clock,
ClutterFrameInfo *frame_info);
CLUTTER_EXPORT
void clutter_frame_clock_notify_ready (ClutterFrameClock *frame_clock);
CLUTTER_EXPORT
void clutter_frame_clock_schedule_update (ClutterFrameClock *frame_clock);
CLUTTER_EXPORT
void clutter_frame_clock_schedule_update_now (ClutterFrameClock *frame_clock);
CLUTTER_EXPORT
void clutter_frame_clock_inhibit (ClutterFrameClock *frame_clock);
CLUTTER_EXPORT
void clutter_frame_clock_uninhibit (ClutterFrameClock *frame_clock);
void clutter_frame_clock_add_timeline (ClutterFrameClock *frame_clock,
ClutterTimeline *timeline);
void clutter_frame_clock_remove_timeline (ClutterFrameClock *frame_clock,
ClutterTimeline *timeline);
CLUTTER_EXPORT
float clutter_frame_clock_get_refresh_rate (ClutterFrameClock *frame_clock);
void clutter_frame_clock_record_flip_time (ClutterFrameClock *frame_clock,
int64_t flip_time_us);
GString * clutter_frame_clock_get_max_render_time_debug_info (ClutterFrameClock *frame_clock);
#endif /* CLUTTER_FRAME_CLOCK_H */

View File

@ -1,33 +0,0 @@
/*
* Copyright (C) 2020 Red Hat Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef CLUTTER_FRAME_PRIVATE_H
#define CLUTTER_FRAME_PRIVATE_H
#include "clutter/clutter-frame.h"
struct _ClutterFrame
{
gboolean has_result;
ClutterFrameResult result;
};
#define CLUTTER_FRAME_INIT ((ClutterFrame) { 0 })
ClutterFrameResult clutter_frame_get_result (ClutterFrame *frame);
#endif /* CLUTTER_FRAME_PRIVATE_H */

View File

@ -1,42 +0,0 @@
/*
* Copyright (C) 2020 Red Hat Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include "clutter/clutter-frame-private.h"
ClutterFrameResult
clutter_frame_get_result (ClutterFrame *frame)
{
g_return_val_if_fail (frame->has_result, CLUTTER_FRAME_RESULT_IDLE);
return frame->result;
}
gboolean
clutter_frame_has_result (ClutterFrame *frame)
{
return frame->has_result;
}
void
clutter_frame_set_result (ClutterFrame *frame,
ClutterFrameResult result)
{
g_warn_if_fail (!frame->has_result);
frame->result = result;
frame->has_result = TRUE;
}

View File

@ -1,36 +0,0 @@
/*
* Copyright (C) 2020 Red Hat Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef CLUTTER_FRAME_H
#define CLUTTER_FRAME_H
#if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION)
#error "Only <clutter/clutter.h> can be included directly."
#endif
#include "clutter/clutter-frame-clock.h"
typedef struct _ClutterFrame ClutterFrame;
CLUTTER_EXPORT
void clutter_frame_set_result (ClutterFrame *frame,
ClutterFrameResult result);
CLUTTER_EXPORT
gboolean clutter_frame_has_result (ClutterFrame *frame);
#endif /* CLUTTER_FRAME_H */

View File

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

View File

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

View File

@ -0,0 +1,96 @@
/*
* Clutter.
*
* An OpenGL based 'interactive canvas' library.
*
* Authored By Matthew Allum <mallum@openedhand.com>
*
* Copyright (C) 2006 OpenedHand
*
* 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_GROUP_H__
#define __CLUTTER_GROUP_H__
#if !defined(__CLUTTER_H_INSIDE__) && !defined(CLUTTER_COMPILATION)
#error "Only <clutter/clutter.h> can be included directly."
#endif
#include <glib-object.h>
#include <clutter/clutter-types.h>
#include <clutter/clutter-actor.h>
G_BEGIN_DECLS
#define CLUTTER_TYPE_GROUP (clutter_group_get_type ())
#define CLUTTER_GROUP(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_GROUP, ClutterGroup))
#define CLUTTER_GROUP_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CLUTTER_TYPE_GROUP, ClutterGroupClass))
#define CLUTTER_IS_GROUP(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_GROUP))
#define CLUTTER_IS_GROUP_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CLUTTER_TYPE_GROUP))
#define CLUTTER_GROUP_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_GROUP, ClutterGroupClass))
/* XXX - ClutterGroup is to be considered fully deprecated; the only
* reason we keep this header is because ClutterStage inherits from
* ClutterGroup, and thus we need to have a structure definition for
* the Stage object to expand.
*/
typedef struct _ClutterGroup ClutterGroup;
typedef struct _ClutterGroupClass ClutterGroupClass;
typedef struct _ClutterGroupPrivate ClutterGroupPrivate;
/**
* ClutterGroup:
*
* The #ClutterGroup structure contains only private data
* and should be accessed using the provided API
*
* Since: 0.2
*/
struct _ClutterGroup
{
/*< private >*/
ClutterActor parent_instance;
ClutterGroupPrivate *priv;
};
/**
* ClutterGroupClass:
*
* The #ClutterGroupClass structure contains only private data
*
* Since: 0.2
*/
struct _ClutterGroupClass
{
/*< private >*/
ClutterActorClass parent_class;
/* 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);
};
CLUTTER_EXPORT
GType clutter_group_get_type (void) G_GNUC_CONST;
G_END_DECLS
#endif /* __CLUTTER_GROUP_H__ */

View File

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

View File

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

View File

@ -32,6 +32,44 @@
G_BEGIN_DECLS
typedef struct _ClutterAxisInfo
{
ClutterInputAxis axis;
double min_axis;
double max_axis;
double min_value;
double max_value;
double resolution;
} ClutterAxisInfo;
typedef struct _ClutterKeyInfo
{
guint keyval;
ClutterModifierType modifiers;
} ClutterKeyInfo;
typedef struct _ClutterScrollInfo
{
guint axis_id;
ClutterScrollDirection direction;
double increment;
double last_value;
guint last_value_valid : 1;
} ClutterScrollInfo;
typedef struct _ClutterTouchInfo
{
ClutterEventSequence *sequence;
ClutterActor *actor;
float current_x;
float current_y;
} ClutterTouchInfo;
typedef struct _ClutterPtrA11yData
{
int n_btn_pressed;
@ -53,6 +91,26 @@ struct _ClutterInputDevice
{
GObject parent_instance;
int id;
ClutterInputDeviceType device_type;
ClutterInputMode device_mode;
char *device_name;
ClutterSeat *seat;
ClutterBackend *backend;
/* the associated device */
ClutterInputDevice *associated;
GList *slaves;
/* the actor underneath the pointer */
ClutterActor *cursor_actor;
GHashTable *inv_touch_sequence_actors;
/* the actor that has a grab in place for the device */
ClutterActor *pointer_grab_actor;
ClutterActor *keyboard_grab_actor;
@ -61,17 +119,137 @@ struct _ClutterInputDevice
/* the current click count */
int click_count;
/* the stage the device is on */
ClutterStage *stage;
/* the current state */
float current_x;
float current_y;
uint32_t current_time;
int current_button_number;
ClutterModifierType current_state;
/* the current touch points states */
GHashTable *touch_sequences_info;
/* the previous state, used for click count generation */
int previous_x;
int previous_y;
uint32_t previous_time;
int previous_button_number;
ClutterModifierType previous_state;
GArray *axes;
guint n_keys;
GArray *keys;
GArray *scroll_info;
char *vendor_id;
char *product_id;
char *node_path;
GPtrArray *tools;
int n_rings;
int n_strips;
int n_mode_groups;
ClutterInputDeviceMapping mapping_mode;
guint has_cursor : 1;
guint is_enabled : 1;
/* Accessiblity */
ClutterVirtualInputDevice *accessibility_virtual_device;
ClutterPtrA11yData *ptr_a11y_data;
};
CLUTTER_EXPORT
void _clutter_input_device_set_associated_device (ClutterInputDevice *device,
ClutterInputDevice *associated);
CLUTTER_EXPORT
void _clutter_input_device_add_slave (ClutterInputDevice *master,
ClutterInputDevice *slave);
CLUTTER_EXPORT
void _clutter_input_device_remove_slave (ClutterInputDevice *master,
ClutterInputDevice *slave);
CLUTTER_EXPORT
void clutter_input_device_update_from_tool (ClutterInputDevice *device,
ClutterInputDeviceTool *tool);
CLUTTER_EXPORT
ClutterStage * _clutter_input_device_get_stage (ClutterInputDevice *device);
CLUTTER_EXPORT
void _clutter_input_device_set_stage (ClutterInputDevice *device,
ClutterStage *stage);
CLUTTER_EXPORT
void _clutter_input_device_set_coords (ClutterInputDevice *device,
ClutterEventSequence *sequence,
gfloat x,
gfloat y,
ClutterStage *stage);
CLUTTER_EXPORT
void _clutter_input_device_set_state (ClutterInputDevice *device,
ClutterModifierType state);
CLUTTER_EXPORT
void _clutter_input_device_set_time (ClutterInputDevice *device,
guint32 time_);
void _clutter_input_device_set_actor (ClutterInputDevice *device,
ClutterEventSequence *sequence,
ClutterActor *actor,
gboolean emit_crossing);
CLUTTER_EXPORT
ClutterActor * clutter_input_device_update (ClutterInputDevice *device,
ClutterEventSequence *sequence,
gboolean emit_crossing);
CLUTTER_EXPORT
void _clutter_input_device_add_event_sequence (ClutterInputDevice *device,
ClutterEvent *event);
CLUTTER_EXPORT
void _clutter_input_device_remove_event_sequence (ClutterInputDevice *device,
ClutterEvent *event);
CLUTTER_EXPORT
void _clutter_input_device_set_n_keys (ClutterInputDevice *device,
guint n_keys);
CLUTTER_EXPORT
gboolean _clutter_input_device_translate_axis (ClutterInputDevice *device,
guint index_,
gdouble value,
gdouble *axis_value);
CLUTTER_EXPORT
guint _clutter_input_device_add_axis (ClutterInputDevice *device,
ClutterInputAxis axis,
gdouble minimum,
gdouble maximum,
gdouble resolution);
CLUTTER_EXPORT
void _clutter_input_device_reset_axes (ClutterInputDevice *device);
CLUTTER_EXPORT
void _clutter_input_device_add_scroll_info (ClutterInputDevice *device,
guint index_,
ClutterScrollDirection direction,
gdouble increment);
CLUTTER_EXPORT
gboolean _clutter_input_device_get_scroll_delta (ClutterInputDevice *device,
guint index_,
gdouble value,
ClutterScrollDirection *direction_p,
gdouble *delta_p);
CLUTTER_EXPORT
void _clutter_input_device_reset_scroll_info (ClutterInputDevice *device);
CLUTTER_EXPORT
void clutter_input_device_add_tool (ClutterInputDevice *device,
ClutterInputDeviceTool *tool);
CLUTTER_EXPORT
ClutterInputDeviceTool *
clutter_input_device_lookup_tool (ClutterInputDevice *device,
guint64 serial,
ClutterInputDeviceToolType type);
#endif /* CLUTTER_INPUT_DEVICE_PRIVATE_H */

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

@ -34,10 +34,19 @@
G_BEGIN_DECLS
typedef void (*ClutterEmitInputDeviceEvent) (ClutterEvent *event,
ClutterInputDevice *device);
struct _ClutterInputDeviceClass
{
GObjectClass parent_class;
gboolean (* keycode_to_evdev) (ClutterInputDevice *device,
guint hardware_keycode,
guint *evdev_keycode);
void (* update_from_tool) (ClutterInputDevice *device,
ClutterInputDeviceTool *tool);
gboolean (* is_mode_switch_button) (ClutterInputDevice *device,
guint group,
guint button);
@ -47,9 +56,10 @@ struct _ClutterInputDeviceClass
gboolean (* is_grouped) (ClutterInputDevice *device,
ClutterInputDevice *other_device);
int (* get_pad_feature_group) (ClutterInputDevice *device,
ClutterInputDevicePadFeature feature,
int n_feature);
/* Keyboard accessbility */
void (* process_kbd_a11y_event) (ClutterEvent *event,
ClutterInputDevice *device,
ClutterEmitInputDeviceEvent emit_event_func);
};
#define CLUTTER_TYPE_INPUT_DEVICE (clutter_input_device_get_type ())
@ -72,13 +82,65 @@ GType clutter_input_device_get_type (void) G_GNUC_CONST;
CLUTTER_EXPORT
ClutterInputDeviceType clutter_input_device_get_device_type (ClutterInputDevice *device);
CLUTTER_EXPORT
gint clutter_input_device_get_device_id (ClutterInputDevice *device);
CLUTTER_EXPORT
gboolean clutter_input_device_get_coords (ClutterInputDevice *device,
ClutterEventSequence *sequence,
graphene_point_t *point);
CLUTTER_EXPORT
ClutterModifierType clutter_input_device_get_modifier_state (ClutterInputDevice *device);
CLUTTER_EXPORT
ClutterActor * clutter_input_device_get_actor (ClutterInputDevice *device,
ClutterEventSequence *sequence);
CLUTTER_EXPORT
ClutterStage * clutter_input_device_get_pointer_stage (ClutterInputDevice *device);
CLUTTER_EXPORT
const gchar * clutter_input_device_get_device_name (ClutterInputDevice *device);
CLUTTER_EXPORT
ClutterInputMode clutter_input_device_get_device_mode (ClutterInputDevice *device);
CLUTTER_EXPORT
gboolean clutter_input_device_get_has_cursor (ClutterInputDevice *device);
CLUTTER_EXPORT
void clutter_input_device_set_enabled (ClutterInputDevice *device,
gboolean enabled);
CLUTTER_EXPORT
gboolean clutter_input_device_get_enabled (ClutterInputDevice *device);
CLUTTER_EXPORT
guint clutter_input_device_get_n_axes (ClutterInputDevice *device);
CLUTTER_EXPORT
ClutterInputAxis clutter_input_device_get_axis (ClutterInputDevice *device,
guint index_);
CLUTTER_EXPORT
gboolean clutter_input_device_get_axis_value (ClutterInputDevice *device,
gdouble *axes,
ClutterInputAxis axis,
gdouble *value);
CLUTTER_EXPORT
guint clutter_input_device_get_n_keys (ClutterInputDevice *device);
CLUTTER_EXPORT
void clutter_input_device_set_key (ClutterInputDevice *device,
guint index_,
guint keyval,
ClutterModifierType modifiers);
CLUTTER_EXPORT
gboolean clutter_input_device_get_key (ClutterInputDevice *device,
guint index_,
guint *keyval,
ClutterModifierType *modifiers);
CLUTTER_EXPORT
ClutterInputDevice * clutter_input_device_get_associated_device (ClutterInputDevice *device);
CLUTTER_EXPORT
GList * clutter_input_device_get_slave_devices (ClutterInputDevice *device);
CLUTTER_EXPORT
void clutter_input_device_update_from_event (ClutterInputDevice *device,
ClutterEvent *event,
gboolean update_stage);
CLUTTER_EXPORT
void clutter_input_device_grab (ClutterInputDevice *device,
@ -99,6 +161,11 @@ CLUTTER_EXPORT
ClutterActor * clutter_input_device_sequence_get_grabbed_actor (ClutterInputDevice *device,
ClutterEventSequence *sequence);
CLUTTER_EXPORT
gboolean clutter_input_device_keycode_to_evdev (ClutterInputDevice *device,
guint hardware_keycode,
guint *evdev_keycode);
CLUTTER_EXPORT
const gchar * clutter_input_device_get_vendor_id (ClutterInputDevice *device);
CLUTTER_EXPORT
@ -110,9 +177,6 @@ CLUTTER_EXPORT
gint clutter_input_device_get_n_strips (ClutterInputDevice *device);
CLUTTER_EXPORT
gint clutter_input_device_get_n_mode_groups (ClutterInputDevice *device);
CLUTTER_EXPORT
int clutter_input_device_get_n_buttons (ClutterInputDevice *device);
CLUTTER_EXPORT
gint clutter_input_device_get_group_n_modes (ClutterInputDevice *device,
@ -129,17 +193,18 @@ gint clutter_input_device_get_mode_switch_button_group (Clutt
CLUTTER_EXPORT
const gchar * clutter_input_device_get_device_node (ClutterInputDevice *device);
CLUTTER_EXPORT
ClutterInputDeviceMapping clutter_input_device_get_mapping_mode (ClutterInputDevice *device);
CLUTTER_EXPORT
void clutter_input_device_set_mapping_mode (ClutterInputDevice *device,
ClutterInputDeviceMapping mapping);
CLUTTER_EXPORT
gboolean clutter_input_device_is_grouped (ClutterInputDevice *device,
ClutterInputDevice *other_device);
CLUTTER_EXPORT
ClutterSeat * clutter_input_device_get_seat (ClutterInputDevice *device);
CLUTTER_EXPORT
int clutter_input_device_get_pad_feature_group (ClutterInputDevice *device,
ClutterInputDevicePadFeature feature,
int n_feature);
G_END_DECLS
#endif /* __CLUTTER_INPUT_DEVICE_H__ */

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,31 +0,0 @@
/*
* Copyright (C) 2021 Red Hat
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*
*/
#ifndef CLUTTER_KEYMAP_PRIVATE_H
#define CLUTTER_KEYMAP_PRIVATE_H
#include "clutter/clutter-keymap.h"
CLUTTER_EXPORT
void clutter_keymap_set_lock_modifier_state (ClutterKeymap *keymap,
gboolean caps_lock_state,
gboolean num_lock_state);
#endif /* CLUTTER_KEYMAP_PRIVATE_H */

View File

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

View File

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

View File

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

View File

@ -32,7 +32,8 @@
* it has been paired, and it controls the allocation of its children.
*
* Any composite or container #ClutterActor subclass can delegate the
* layouting of its children to a #ClutterLayoutManager.
* layouting of its children to a #ClutterLayoutManager. Clutter provides
* a generic container using #ClutterLayoutManager called #ClutterBox.
*
* Clutter provides some simple #ClutterLayoutManager sub-classes, like
* #ClutterFlowLayout and #ClutterBinLayout.
@ -41,7 +42,7 @@
* The implementation of a layout manager does not differ from the
* implementation of the size requisition and allocation bits of
* #ClutterActor, so you should read the relative documentation
* for subclassing #ClutterActor.
* forr subclassing #ClutterActor.
*
* The layout manager implementation can hold a back pointer to the
* #ClutterContainer by implementing the #ClutterLayoutManagerClass.set_container()
@ -96,7 +97,7 @@
*
* |[
* {
* "type" : "ClutterActor",
* "type" : "ClutterBox",
* "layout-manager" : { "type" : "ClutterGridLayout" },
* "children" : [
* {

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

@ -0,0 +1,618 @@
/*
* Clutter.
*
* An OpenGL based 'interactive canvas' library.
*
* Authored By: Emmanuele Bassi <ebassi@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/>.
*/
/*
* SECTION:clutter-master-clock-default
* @short_description: The default master clock for all animations
*
* The #ClutterMasterClockDefault class is the default implementation
* of #ClutterMasterClock.
*/
#include "clutter-build-config.h"
#include <cogl/cogl.h>
#include "clutter-master-clock.h"
#include "clutter-master-clock-default.h"
#include "clutter-debug.h"
#include "clutter-private.h"
#include "clutter-stage-manager-private.h"
#include "clutter-stage-private.h"
#ifdef CLUTTER_ENABLE_DEBUG
#define clutter_warn_if_over_budget(master_clock,start_time,section) G_STMT_START { \
gint64 __delta = g_get_monotonic_time () - start_time; \
gint64 __budget = master_clock->remaining_budget; \
if (__budget > 0 && __delta >= __budget) { \
_clutter_diagnostic_message ("%s took %" G_GINT64_FORMAT " microseconds " \
"more than the remaining budget of %" G_GINT64_FORMAT \
" microseconds", \
section, __delta - __budget, __budget); \
} } G_STMT_END
#else
#define clutter_warn_if_over_budget(master_clock,start_time,section)
#endif
typedef struct _ClutterClockSource ClutterClockSource;
struct _ClutterMasterClockDefault
{
GObject parent_instance;
/* the list of timelines handled by the clock */
GSList *timelines;
/* the current state of the clock, in usecs */
gint64 cur_tick;
#ifdef CLUTTER_ENABLE_DEBUG
gint64 frame_budget;
gint64 remaining_budget;
#endif
/* an idle source, used by the Master Clock to queue
* a redraw on the stage and drive the animations
*/
GSource *source;
guint ensure_next_iteration : 1;
guint paused : 1;
};
struct _ClutterClockSource
{
GSource source;
ClutterMasterClockDefault *master_clock;
};
static gboolean clutter_clock_prepare (GSource *source,
gint *timeout);
static gboolean clutter_clock_check (GSource *source);
static gboolean clutter_clock_dispatch (GSource *source,
GSourceFunc callback,
gpointer user_data);
static GSourceFuncs clock_funcs = {
clutter_clock_prepare,
clutter_clock_check,
clutter_clock_dispatch,
NULL
};
static void
clutter_master_clock_iface_init (ClutterMasterClockInterface *iface);
#define clutter_master_clock_default_get_type _clutter_master_clock_default_get_type
G_DEFINE_TYPE_WITH_CODE (ClutterMasterClockDefault,
clutter_master_clock_default,
G_TYPE_OBJECT,
G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_MASTER_CLOCK,
clutter_master_clock_iface_init));
/*
* master_clock_is_running:
* @master_clock: a #ClutterMasterClock
*
* Checks if we should currently be advancing timelines or redrawing
* stages.
*
* Return value: %TRUE if the #ClutterMasterClock has at least
* one running timeline
*/
static gboolean
master_clock_is_running (ClutterMasterClockDefault *master_clock)
{
ClutterStageManager *stage_manager = clutter_stage_manager_get_default ();
const GSList *stages, *l;
stages = clutter_stage_manager_peek_stages (stage_manager);
if (master_clock->paused)
return FALSE;
if (master_clock->timelines)
return TRUE;
for (l = stages; l; l = l->next)
{
if (clutter_actor_is_mapped (l->data) &&
(_clutter_stage_has_queued_events (l->data) ||
_clutter_stage_needs_update (l->data)))
return TRUE;
}
if (master_clock->ensure_next_iteration)
{
master_clock->ensure_next_iteration = FALSE;
return TRUE;
}
return FALSE;
}
static gint
master_clock_get_swap_wait_time (ClutterMasterClockDefault *master_clock)
{
ClutterStageManager *stage_manager = clutter_stage_manager_get_default ();
const GSList *stages, *l;
gint64 min_update_time = -1;
stages = clutter_stage_manager_peek_stages (stage_manager);
for (l = stages; l != NULL; l = l->next)
{
gint64 update_time = _clutter_stage_get_update_time (l->data);
if (min_update_time == -1 ||
(update_time != -1 && update_time < min_update_time))
min_update_time = update_time;
}
if (min_update_time == -1)
{
return -1;
}
else
{
gint64 now = g_source_get_time (master_clock->source);
if (min_update_time < now)
{
return 0;
}
else
{
gint64 delay_us = min_update_time - now;
return (delay_us + 999) / 1000;
}
}
}
static void
master_clock_schedule_stage_updates (ClutterMasterClockDefault *master_clock)
{
ClutterStageManager *stage_manager = clutter_stage_manager_get_default ();
const GSList *stages, *l;
stages = clutter_stage_manager_peek_stages (stage_manager);
for (l = stages; l != NULL; l = l->next)
clutter_stage_schedule_update (l->data);
}
static GSList *
master_clock_list_ready_stages (ClutterMasterClockDefault *master_clock)
{
ClutterStageManager *stage_manager = clutter_stage_manager_get_default ();
const GSList *stages, *l;
GSList *result;
stages = clutter_stage_manager_peek_stages (stage_manager);
result = NULL;
for (l = stages; l != NULL; l = l->next)
{
gint64 update_time = _clutter_stage_get_update_time (l->data);
/* We carefully avoid to update stages that aren't mapped, because
* they have nothing to render and this could cause a deadlock with
* some of the SwapBuffers implementations (in particular
* GLX_INTEL_swap_event is not emitted if nothing was rendered).
*
* Also, if a stage has a swap-buffers pending we don't want to draw
* to it in case the driver may block the CPU while it waits for the
* next backbuffer to become available.
*
* TODO: We should be able to identify if we are running triple or N
* buffered and in these cases we can still draw if there is 1 swap
* pending so we can hopefully always be ready to swap for the next
* vblank and really match the vsync frequency.
*/
if (clutter_actor_is_mapped (l->data) &&
update_time != -1 && update_time <= master_clock->cur_tick)
result = g_slist_prepend (result, g_object_ref (l->data));
}
return g_slist_reverse (result);
}
static void
master_clock_reschedule_stage_updates (ClutterMasterClockDefault *master_clock,
GSList *stages)
{
const GSList *l;
for (l = stages; l != NULL; l = l->next)
{
/* Clear the old update time */
_clutter_stage_clear_update_time (l->data);
/* And if there is still work to be done, schedule a new one */
if (master_clock->timelines ||
_clutter_stage_has_queued_events (l->data) ||
_clutter_stage_needs_update (l->data))
clutter_stage_schedule_update (l->data);
}
}
/*
* master_clock_next_frame_delay:
* @master_clock: a #ClutterMasterClock
*
* Computes the number of delay before we need to draw the next frame.
*
* Return value: -1 if there is no next frame pending, otherwise the
* number of millseconds before the we need to draw the next frame
*/
static gint
master_clock_next_frame_delay (ClutterMasterClockDefault *master_clock)
{
if (!master_clock_is_running (master_clock))
return -1;
/* If all of the stages are busy waiting for a swap-buffers to complete
* then we wait for one to be ready.. */
return master_clock_get_swap_wait_time (master_clock);
}
static void
master_clock_process_events (ClutterMasterClockDefault *master_clock,
GSList *stages)
{
GSList *l;
#ifdef CLUTTER_ENABLE_DEBUG
gint64 start = g_get_monotonic_time ();
#endif
/* Process queued events */
for (l = stages; l != NULL; l = l->next)
_clutter_stage_process_queued_events (l->data);
#ifdef CLUTTER_ENABLE_DEBUG
if (_clutter_diagnostic_enabled ())
clutter_warn_if_over_budget (master_clock, start, "Event processing");
master_clock->remaining_budget -= (g_get_monotonic_time () - start);
#endif
}
/*
* master_clock_advance_timelines:
* @master_clock: a #ClutterMasterClock
*
* Advances all the timelines held by the master clock. This function
* should be called before calling _clutter_stage_do_update() to
* make sure that all the timelines are advanced and the scene is updated.
*/
static void
master_clock_advance_timelines (ClutterMasterClockDefault *master_clock)
{
GSList *timelines, *l;
#ifdef CLUTTER_ENABLE_DEBUG
gint64 start = g_get_monotonic_time ();
#endif
/* we protect ourselves from timelines being removed during
* the advancement by other timelines by copying the list of
* timelines, taking a reference on them, iterating over the
* copied list and then releasing the reference.
*
* we cannot simply take a reference on the timelines and still
* use the list held by the master clock because the do_tick()
* might result in the creation of a new timeline, which gets
* added at the end of the list with no reference increase and
* thus gets disposed at the end of the iteration.
*
* this implies that a newly added timeline will not be advanced
* by this clock iteration, which is perfectly fine since we're
* in its first cycle.
*
* we also cannot steal the master clock timelines list because
* a timeline might be removed as the direct result of do_tick()
* and remove_timeline() would not find the timeline, failing
* and leaving a dangling pointer behind.
*/
timelines = g_slist_copy (master_clock->timelines);
g_slist_foreach (timelines, (GFunc) g_object_ref, NULL);
for (l = timelines; l != NULL; l = l->next)
_clutter_timeline_do_tick (l->data, master_clock->cur_tick / 1000);
g_slist_free_full (timelines, g_object_unref);
#ifdef CLUTTER_ENABLE_DEBUG
if (_clutter_diagnostic_enabled ())
clutter_warn_if_over_budget (master_clock, start, "Animations");
master_clock->remaining_budget -= (g_get_monotonic_time () - start);
#endif
}
static gboolean
master_clock_update_stages (ClutterMasterClockDefault *master_clock,
GSList *stages)
{
gboolean stages_updated = FALSE;
GSList *l;
#ifdef CLUTTER_ENABLE_DEBUG
gint64 start = g_get_monotonic_time ();
#endif
_clutter_run_repaint_functions (CLUTTER_REPAINT_FLAGS_PRE_PAINT);
/* Update any stage that needs redraw/relayout after the clock
* is advanced.
*/
for (l = stages; l != NULL; l = l->next)
stages_updated |= _clutter_stage_do_update (l->data);
_clutter_run_repaint_functions (CLUTTER_REPAINT_FLAGS_POST_PAINT);
#ifdef CLUTTER_ENABLE_DEBUG
if (_clutter_diagnostic_enabled ())
clutter_warn_if_over_budget (master_clock, start, "Updating the stage");
master_clock->remaining_budget -= (g_get_monotonic_time () - start);
#endif
return stages_updated;
}
/*
* clutter_clock_source_new:
* @master_clock: a #ClutterMasterClock for the source
*
* The #ClutterClockSource is an idle GSource that will queue a redraw
* if @master_clock has at least a running #ClutterTimeline. The redraw
* will cause @master_clock to advance all timelines, thus advancing all
* animations as well.
*
* Return value: the newly created #GSource
*/
static GSource *
clutter_clock_source_new (ClutterMasterClockDefault *master_clock)
{
GSource *source = g_source_new (&clock_funcs, sizeof (ClutterClockSource));
ClutterClockSource *clock_source = (ClutterClockSource *) source;
g_source_set_name (source, "Clutter master clock");
g_source_set_priority (source, CLUTTER_PRIORITY_REDRAW);
g_source_set_can_recurse (source, FALSE);
clock_source->master_clock = master_clock;
return source;
}
static gboolean
clutter_clock_prepare (GSource *source,
gint *timeout)
{
ClutterClockSource *clock_source = (ClutterClockSource *) source;
ClutterMasterClockDefault *master_clock = clock_source->master_clock;
int delay;
_clutter_threads_acquire_lock ();
if (G_UNLIKELY (clutter_paint_debug_flags &
CLUTTER_DEBUG_CONTINUOUS_REDRAW))
{
ClutterStageManager *stage_manager = clutter_stage_manager_get_default ();
const GSList *stages, *l;
stages = clutter_stage_manager_peek_stages (stage_manager);
/* Queue a full redraw on all of the stages */
for (l = stages; l != NULL; l = l->next)
clutter_actor_queue_redraw (l->data);
}
delay = master_clock_next_frame_delay (master_clock);
_clutter_threads_release_lock ();
*timeout = delay;
return delay == 0;
}
static gboolean
clutter_clock_check (GSource *source)
{
ClutterClockSource *clock_source = (ClutterClockSource *) source;
ClutterMasterClockDefault *master_clock = clock_source->master_clock;
int delay;
_clutter_threads_acquire_lock ();
delay = master_clock_next_frame_delay (master_clock);
_clutter_threads_release_lock ();
return delay == 0;
}
static gboolean
clutter_clock_dispatch (GSource *source,
GSourceFunc callback,
gpointer user_data)
{
ClutterClockSource *clock_source = (ClutterClockSource *) source;
ClutterMasterClockDefault *master_clock = clock_source->master_clock;
GSList *stages;
CLUTTER_NOTE (SCHEDULER, "Master clock [tick]");
_clutter_threads_acquire_lock ();
COGL_TRACE_BEGIN (ClutterMasterClockTick, "Master Clock (tick)");
/* Get the time to use for this frame */
master_clock->cur_tick = g_source_get_time (source);
#ifdef CLUTTER_ENABLE_DEBUG
master_clock->remaining_budget = master_clock->frame_budget;
#endif
/* We need to protect ourselves against stages being destroyed during
* event handling - master_clock_list_ready_stages() returns a
* list of referenced that we'll unref afterwards.
*/
stages = master_clock_list_ready_stages (master_clock);
/* Each frame is split into three separate phases: */
/* 1. process all the events; each stage goes through its events queue
* and processes each event according to its type, then emits the
* various signals that are associated with the event
*/
master_clock_process_events (master_clock, stages);
/* 2. advance the timelines */
master_clock_advance_timelines (master_clock);
/* 3. relayout and redraw the stages */
master_clock_update_stages (master_clock, stages);
master_clock_reschedule_stage_updates (master_clock, stages);
g_slist_free_full (stages, g_object_unref);
COGL_TRACE_END (ClutterMasterClockTick);
_clutter_threads_release_lock ();
return TRUE;
}
static void
clutter_master_clock_default_finalize (GObject *gobject)
{
ClutterMasterClockDefault *master_clock = CLUTTER_MASTER_CLOCK_DEFAULT (gobject);
g_slist_free (master_clock->timelines);
G_OBJECT_CLASS (clutter_master_clock_default_parent_class)->finalize (gobject);
}
static void
clutter_master_clock_default_class_init (ClutterMasterClockDefaultClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
gobject_class->finalize = clutter_master_clock_default_finalize;
}
static void
clutter_master_clock_default_init (ClutterMasterClockDefault *self)
{
GSource *source;
source = clutter_clock_source_new (self);
self->source = source;
self->ensure_next_iteration = FALSE;
self->paused = FALSE;
#ifdef CLUTTER_ENABLE_DEBUG
self->frame_budget = G_USEC_PER_SEC / 60;
#endif
g_source_attach (source, NULL);
}
static void
clutter_master_clock_default_add_timeline (ClutterMasterClock *clock,
ClutterTimeline *timeline)
{
ClutterMasterClockDefault *master_clock = (ClutterMasterClockDefault *) clock;
gboolean is_first;
if (g_slist_find (master_clock->timelines, timeline))
return;
is_first = master_clock->timelines == NULL;
master_clock->timelines = g_slist_prepend (master_clock->timelines,
timeline);
if (is_first)
{
master_clock_schedule_stage_updates (master_clock);
_clutter_master_clock_start_running (clock);
}
}
static void
clutter_master_clock_default_remove_timeline (ClutterMasterClock *clock,
ClutterTimeline *timeline)
{
ClutterMasterClockDefault *master_clock = (ClutterMasterClockDefault *) clock;
master_clock->timelines = g_slist_remove (master_clock->timelines,
timeline);
}
static void
clutter_master_clock_default_start_running (ClutterMasterClock *master_clock)
{
/* If called from a different thread, we need to wake up the
* main loop to start running the timelines
*/
g_main_context_wakeup (NULL);
}
static void
clutter_master_clock_default_ensure_next_iteration (ClutterMasterClock *clock)
{
ClutterMasterClockDefault *master_clock = (ClutterMasterClockDefault *) clock;
master_clock->ensure_next_iteration = TRUE;
}
static void
clutter_master_clock_default_set_paused (ClutterMasterClock *clock,
gboolean paused)
{
ClutterMasterClockDefault *master_clock = (ClutterMasterClockDefault *) clock;
if (paused && !master_clock->paused)
{
g_clear_pointer (&master_clock->source, g_source_destroy);
}
else if (!paused && master_clock->paused)
{
master_clock->source = clutter_clock_source_new (master_clock);
g_source_attach (master_clock->source, NULL);
}
master_clock->paused = !!paused;
}
static void
clutter_master_clock_iface_init (ClutterMasterClockInterface *iface)
{
iface->add_timeline = clutter_master_clock_default_add_timeline;
iface->remove_timeline = clutter_master_clock_default_remove_timeline;
iface->start_running = clutter_master_clock_default_start_running;
iface->ensure_next_iteration = clutter_master_clock_default_ensure_next_iteration;
iface->set_paused = clutter_master_clock_default_set_paused;
}

View File

@ -0,0 +1,48 @@
/*
* Clutter.
*
* An OpenGL based 'interactive canvas' library.
*
* Authored By: Lionel Landwerlin <lionel.g.landwerlin@linux.intel.com>
*
* Copyright (C) 2015 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_MASTER_CLOCK_DEFAULT_H__
#define __CLUTTER_MASTER_CLOCK_DEFAULT_H__
#include <clutter/clutter-timeline.h>
G_BEGIN_DECLS
#define CLUTTER_TYPE_MASTER_CLOCK_DEFAULT (_clutter_master_clock_default_get_type ())
#define CLUTTER_MASTER_CLOCK_DEFAULT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_MASTER_CLOCK_DEFAULT, ClutterMasterClockDefault))
#define CLUTTER_IS_MASTER_CLOCK_DEFAULT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CLUTTER_TYPE_MASTER_CLOCK_DEFAULT))
#define CLUTTER_MASTER_CLOCK_DEFAULT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CLUTTER_TYPE_MASTER_CLOCK_DEFAULT, ClutterMasterClockDefaultClass))
typedef struct _ClutterMasterClockDefault ClutterMasterClockDefault;
typedef struct _ClutterMasterClockDefaultClass ClutterMasterClockDefaultClass;
struct _ClutterMasterClockDefaultClass
{
GObjectClass parent_class;
};
GType _clutter_master_clock_default_get_type (void) G_GNUC_CONST;
G_END_DECLS
#endif /* __CLUTTER_MASTER_CLOCK_DEFAULT_H__ */

View File

@ -0,0 +1,132 @@
/*
* Clutter.
*
* An OpenGL based 'interactive canvas' library.
*
* Authored By: Emmanuele Bassi <ebassi@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/>.
*/
/*
* SECTION:clutter-master-clock
* @short_description: The master clock for all animations
*
* The #ClutterMasterClock class is responsible for advancing all
* #ClutterTimelines when a stage is being redrawn. The master clock
* makes sure that the scenegraph is always integrally updated before
* painting it.
*/
#include "clutter-build-config.h"
#include "clutter-master-clock.h"
#include "clutter-master-clock-default.h"
#include "clutter-private.h"
G_DEFINE_INTERFACE (ClutterMasterClock, clutter_master_clock, G_TYPE_OBJECT)
static void
clutter_master_clock_default_init (ClutterMasterClockInterface *iface)
{
}
ClutterMasterClock *
_clutter_master_clock_get_default (void)
{
ClutterMainContext *context = _clutter_context_get_default ();
if (G_UNLIKELY (context->master_clock == NULL))
context->master_clock = g_object_new (CLUTTER_TYPE_MASTER_CLOCK_DEFAULT, NULL);
return context->master_clock;
}
/*
* _clutter_master_clock_add_timeline:
* @master_clock: a #ClutterMasterClock
* @timeline: a #ClutterTimeline
*
* Adds @timeline to the list of playing timelines held by the master
* clock.
*/
void
_clutter_master_clock_add_timeline (ClutterMasterClock *master_clock,
ClutterTimeline *timeline)
{
g_return_if_fail (CLUTTER_IS_MASTER_CLOCK (master_clock));
CLUTTER_MASTER_CLOCK_GET_IFACE (master_clock)->add_timeline (master_clock,
timeline);
}
/*
* _clutter_master_clock_remove_timeline:
* @master_clock: a #ClutterMasterClock
* @timeline: a #ClutterTimeline
*
* Removes @timeline from the list of playing timelines held by the
* master clock.
*/
void
_clutter_master_clock_remove_timeline (ClutterMasterClock *master_clock,
ClutterTimeline *timeline)
{
g_return_if_fail (CLUTTER_IS_MASTER_CLOCK (master_clock));
CLUTTER_MASTER_CLOCK_GET_IFACE (master_clock)->remove_timeline (master_clock,
timeline);
}
/*
* _clutter_master_clock_start_running:
* @master_clock: a #ClutterMasterClock
*
* Called when we have events or redraws to process; if the clock
* is stopped, does the processing necessary to wake it up again.
*/
void
_clutter_master_clock_start_running (ClutterMasterClock *master_clock)
{
g_return_if_fail (CLUTTER_IS_MASTER_CLOCK (master_clock));
CLUTTER_MASTER_CLOCK_GET_IFACE (master_clock)->start_running (master_clock);
}
/**
* _clutter_master_clock_ensure_next_iteration:
* @master_clock: a #ClutterMasterClock
*
* Ensures that the master clock will run at least one iteration
*/
void
_clutter_master_clock_ensure_next_iteration (ClutterMasterClock *master_clock)
{
g_return_if_fail (CLUTTER_IS_MASTER_CLOCK (master_clock));
CLUTTER_MASTER_CLOCK_GET_IFACE (master_clock)->ensure_next_iteration (master_clock);
}
void
_clutter_master_clock_set_paused (ClutterMasterClock *master_clock,
gboolean paused)
{
g_return_if_fail (CLUTTER_IS_MASTER_CLOCK (master_clock));
CLUTTER_MASTER_CLOCK_GET_IFACE (master_clock)->set_paused (master_clock,
!!paused);
}

View File

@ -0,0 +1,69 @@
/*
* Clutter.
*
* An OpenGL based 'interactive canvas' library.
*
* Authored By: Emmanuele Bassi <ebassi@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_MASTER_CLOCK_H__
#define __CLUTTER_MASTER_CLOCK_H__
#include <clutter/clutter-timeline.h>
G_BEGIN_DECLS
#define CLUTTER_TYPE_MASTER_CLOCK (clutter_master_clock_get_type ())
G_DECLARE_INTERFACE (ClutterMasterClock, clutter_master_clock,
CLUTTER, MASTER_CLOCK,
GObject)
struct _ClutterMasterClockInterface
{
/*< private >*/
GTypeInterface parent_iface;
void (* add_timeline) (ClutterMasterClock *master_clock,
ClutterTimeline *timeline);
void (* remove_timeline) (ClutterMasterClock *master_clock,
ClutterTimeline *timeline);
void (* start_running) (ClutterMasterClock *master_clock);
void (* ensure_next_iteration) (ClutterMasterClock *master_clock);
void (* set_paused) (ClutterMasterClock *master_clock,
gboolean paused);
};
ClutterMasterClock * _clutter_master_clock_get_default (void);
void _clutter_master_clock_add_timeline (ClutterMasterClock *master_clock,
ClutterTimeline *timeline);
void _clutter_master_clock_remove_timeline (ClutterMasterClock *master_clock,
ClutterTimeline *timeline);
void _clutter_master_clock_start_running (ClutterMasterClock *master_clock);
void _clutter_master_clock_ensure_next_iteration (ClutterMasterClock *master_clock);
void _clutter_master_clock_set_paused (ClutterMasterClock *master_clock,
gboolean paused);
void _clutter_timeline_advance (ClutterTimeline *timeline,
gint64 tick_time);
gint64 _clutter_timeline_get_delta (ClutterTimeline *timeline);
void _clutter_timeline_do_tick (ClutterTimeline *timeline,
gint64 tick_time);
G_END_DECLS
#endif /* __CLUTTER_MASTER_CLOCK_H__ */

View File

@ -26,8 +26,6 @@
#define __CLUTTER_H_INSIDE__
#include "clutter-backend.h"
#include "clutter-backend-private.h"
#include "clutter-damage-history.h"
#include "clutter-event-private.h"
#include "clutter-input-device-private.h"
#include "clutter-input-pointer-a11y-private.h"
@ -35,16 +33,12 @@
#include "clutter-private.h"
#include "clutter-stage-private.h"
#include "clutter-stage-view.h"
#include "clutter-stage-view-private.h"
#include "clutter.h"
#include "cogl/clutter-stage-cogl.h"
#include "clutter/x11/clutter-backend-x11.h"
CLUTTER_EXPORT
GList * clutter_stage_peek_stage_views (ClutterStage *stage);
CLUTTER_EXPORT
gboolean clutter_actor_is_effectively_on_stage_view (ClutterActor *self,
ClutterStageView *view);
CLUTTER_EXPORT
void clutter_set_custom_backend_func (ClutterBackend *(* func) (void));
@ -52,11 +46,33 @@ CLUTTER_EXPORT
int64_t clutter_stage_get_frame_counter (ClutterStage *stage);
CLUTTER_EXPORT
void clutter_stage_capture_view_into (ClutterStage *stage,
ClutterStageView *view,
cairo_rectangle_int_t *rect,
uint8_t *data,
int stride);
void clutter_stage_capture_into (ClutterStage *stage,
gboolean paint,
cairo_rectangle_int_t *rect,
uint8_t *data);
CLUTTER_EXPORT
void clutter_stage_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);
CLUTTER_EXPORT
void clutter_stage_thaw_updates (ClutterStage *stage);
CLUTTER_EXPORT
void clutter_stage_clear_stage_views (ClutterStage *stage);
@ -71,36 +87,6 @@ gboolean clutter_actor_has_damage (ClutterActor *actor);
CLUTTER_EXPORT
gboolean clutter_actor_has_transitions (ClutterActor *actor);
CLUTTER_EXPORT
ClutterFrameClock * clutter_actor_pick_frame_clock (ClutterActor *self,
ClutterActor **out_actor);
CLUTTER_EXPORT
gboolean clutter_seat_handle_event_post (ClutterSeat *seat,
const ClutterEvent *event);
CLUTTER_EXPORT
void clutter_stage_update_device (ClutterStage *stage,
ClutterInputDevice *device,
ClutterEventSequence *sequence,
graphene_point_t point,
uint32_t time,
ClutterActor *new_actor,
gboolean emit_crossing);
CLUTTER_EXPORT
void clutter_stage_get_device_coords (ClutterStage *stage,
ClutterInputDevice *device,
ClutterEventSequence *sequence,
graphene_point_t *coords);
CLUTTER_EXPORT
void clutter_stage_repick_device (ClutterStage *stage,
ClutterInputDevice *device);
CLUTTER_EXPORT
void clutter_get_debug_flags (ClutterDebugFlag *debug_flags,
ClutterDrawDebugFlag *draw_flags,
ClutterPickDebugFlag *pick_flags);
#undef __CLUTTER_H_INSIDE__
#endif /* __CLUTTER_MUTTER_H__ */

View File

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

View File

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

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