Compare commits

..

45 Commits

Author SHA1 Message Date
Matthias Clasen
0f2f5db449 constraint layout: Measure min/nat size separately
Only constraint the opposite direction if we
actually have a for_size, and measure natural
size after removing the edit constraints. With
these changes, the test that compares constraint
layout to grid layout passes.
2019-06-28 23:03:23 +00:00
Matthias Clasen
783ce4c870 constraint layout: Use stays for natural size
It makes more sense to treat the natural size
of both children and guides as stays, since
we want to meet these values as closely as we
can, under the circumstances.
2019-06-28 23:03:23 +00:00
Matthias Clasen
761e2ae5e0 constraint layout: Add debug output for guides
Print out the allocation we end up giving to
guides. This helps in making sense of the
allocations of the child widgets that these
guides relate to.
2019-06-28 23:03:23 +00:00
Matthias Clasen
013c18040a constraints demo: Give space a name
Lets call it 'space'.
2019-06-28 23:03:23 +00:00
Matthias Clasen
3e0d6bdd9a constraint guide: Add a name property
We need to be able to print meaningful debug messages
regarding these objects, and eventually present them
in the inspector too.
2019-06-28 23:03:23 +00:00
Matthias Clasen
129030a0dc constraint guide: Shorten names
Now that this is its own source file,
no need for these prefixes anymore.
2019-06-28 23:03:23 +00:00
Matthias Clasen
695b4a6cae constraint layout: Measure more correctly
Set up all constraints for minimum + natural
width + height when measuring, regardless
of the orientation we're measuring. Anything
else will lead to incorrect answers when
there are constraints that cut across
dimensions.
2019-06-28 23:03:23 +00:00
Matthias Clasen
7bfb369fa3 solver: Fix a copy/paste error 2019-06-28 23:03:23 +00:00
Matthias Clasen
85fbd2c3b7 Add a constraint layout test
This test produces a very simple layout and
checks that it produces the same numbers as
an equivalent grid layout. Currently, it fails,
since the constraint layout can't produce
minimum sizes that are different from natural
sizes.
2019-06-28 23:03:22 +00:00
Matthias Clasen
7e11df9154 constrainttree: Fix criticals
We don't want the edit constraints to be required,
since we want to violate them when the pointer moves
off the edge. Make them strong instead, and now
everything just works.
2019-06-28 17:10:44 +00:00
Matthias Clasen
aed7d32cde constrainttree: Make each drag a single edit
Repeat suggestions work now, so we can implement
this as it is intended to, and have a single
edit phase for the entire drag operation.
2019-06-28 17:09:38 +00:00
Matthias Clasen
49897bdce8 constraint solver: Fix repeat suggestions
We were not storing the previous value, causing
the first two suggestions to work, but not later
ones.

Fixes the test added in the previous commit.
2019-06-28 17:02:40 +00:00
Matthias Clasen
ad087634fd Amend a constraint solver test
Make the 'repeat edit' test make more than to
suggestions in a single edit phase. It turns out
that this does not work, whereas just doing
two in a row does.
2019-06-28 16:30:07 +00:00
Emmanuele Bassi
7a190da5f4 Do not try to pivot after an optimization error
Bail out of the optimization, instead.
2019-06-28 14:34:48 +01:00
Emmanuele Bassi
b236cab3ba Remove stray variable unref() in ConstraintSolver
The marker variables table does not acquire a reference on the
constraint variables it contains, as they are part of the constraint
used as the key, and will be released when the constraint is removed.
2019-06-28 14:22:53 +01:00
Matthias Clasen
1e46874eb0 Add an interactive constraint solver test
This is an example described in the original
Cassowary paper, reimplemented from scratch.
It exposes some instability and crashiness
in our solver.
2019-06-28 13:00:19 +00:00
Matthias Clasen
043fed8612 constraint solver: Add a hack for external linking
Make it possible to build tests which use
GtkConstraintSolver from inside and outside libgtk.
See the test added in the following commit for
how this is used.
2019-06-28 13:00:19 +00:00
Matthias Clasen
b0824a5784 demo: Use constraint guide api
Use proper api to create and set up
the guide, and also try max-width.
2019-06-28 13:00:19 +00:00
Matthias Clasen
469da877d7 Flesh out GtkConstraintGuide
This commit moves GtkConstraintGuide into its own
source files to avoid gtkconstraintlayout.c turning
too messy, adds max size properties and implements
getters and setters.
2019-06-28 12:59:12 +00:00
Matthias Clasen
6ecaa45fb8 Drop an indirection
This struct is not really useful for just
a single hash table, and it gets in the way
of moving the guide code to its own file.
2019-06-28 12:48:15 +00:00
Matthias Clasen
7beca2a33a Detach guides on unroot
We don't want to leave constraints behind.
2019-06-28 12:48:07 +00:00
Matthias Clasen
d5f77b10b9 Simplify the guide implementation
Store the values and constraints in
arrays, to facilitate treating them
uniformly.
2019-06-28 12:47:53 +00:00
Matthias Clasen
12d45c01b0 Add an interactive constraints demo 2019-06-28 13:11:22 +01:00
Matthias Clasen
fc3f4aafe5 Make the constraints demo more interesting
Add a max size to the buttons, to force the
space to open up.
2019-06-28 13:11:22 +01:00
Matthias Clasen
ffd8b19a87 Add GtkConstraintGuide
This is meant to be a flexible space.
2019-06-28 13:11:22 +01:00
Emmanuele Bassi
20c4a4bb21 Use generic pointers for constraint targets
Since GtkWidget implements GtkConstraintTarget, we can omit the explicit
cast, and validate the type at run time.
2019-06-28 13:11:22 +01:00
Matthias Clasen
f8647b02eb Redefine constraints with GtkConstraintTarget
This is in preparation for allowing non-widgets
to act as constraint targets.
2019-06-28 13:11:22 +01:00
Matthias Clasen
4b11e73be6 widget: Implement GtkConstraintTarget 2019-06-28 13:11:22 +01:00
Matthias Clasen
4de3e99fbe Add GtkConstraintTarget
This is an marker interface that we will
use to accept other things that widgets
in constraints.
2019-06-28 13:11:22 +01:00
Emmanuele Bassi
c81e04755d Notify a layout change when adding and removing constraints
Changing the set of constraints should cause a relayout.
2019-06-28 13:11:22 +01:00
Emmanuele Bassi
e4466dd4fe Fix the opposite size measurement in GtkConstraintLayout
We cannot use the given "for size" when querying our children, because
the constraint layout has no idea about the opposite size of its
children until the layout is complete.

Additionally, we should only suggest an opposite size for the layout if
we have one, instead of suggesting a weak zero size.
2019-06-28 13:11:22 +01:00
Emmanuele Bassi
19e7d412e3 Remove size constraints from ConstraintLayoutChild
The size constraints are transient to measurement and allocation, so
they don't really need to be stored inside the GtkLayoutChild subclass
created by a GtkConstraintLayout.
2019-06-27 17:38:02 +01:00
Matthias Clasen
80c27061c6 constraints: Make internal consistency required
The relations between left, right, width
and top, bottom, height are required for
internal consistency. It doesn't make sense
to ever drop these.

Changing the strength of these relations makes
my systems behave much more stable.
2019-06-27 17:38:02 +01:00
Matthias Clasen
bd5c558646 Add gtk_constraint_layout_remove_constraint
Otherwise, you can't do many interesting things.
2019-06-27 17:38:02 +01:00
Emmanuele Bassi
ad40630008 Do not release reference on the subject of an expression
We don't own the reference in the first place.
2019-06-27 17:38:02 +01:00
Matthias Clasen
f07ba4ac5b constraints solver: Avoid critials
When the solver is finalized with existing
constraints, we end up with criticals when
the constraints ref finalize code calls
back into the hash table. Avoid that by
emptying the hash table beforehand.
2019-06-27 17:38:02 +01:00
Matthias Clasen
391add73ec constraint solver: Fix thawing
There was an obviously wrong precondition here.
2019-06-27 17:38:02 +01:00
Emmanuele Bassi
a21562f270 Do not leak LayoutChild instances
Since the LayoutManager owns the LayoutChild it creates, it's also
responsible for mopping them up.
2019-06-27 17:38:02 +01:00
Emmanuele Bassi
124607d1e8 Add GtkConstraintLayout demo 2019-06-27 17:38:02 +01:00
Emmanuele Bassi
9756cb9482 Add GtkConstraintLayout
A layout manager using GtkConstraintSolver to measure and allocate
children.
2019-06-27 17:38:02 +01:00
Emmanuele Bassi
92f93a603b Propagate rooting and unrooting widgets to layout managers
Layout managers may need to get access to data attached to the root of a
scene graph.
2019-06-27 17:38:02 +01:00
Emmanuele Bassi
e7cd3d4633 window: Create a GtkConstraintSolver
Implement the GtkRoot getter for GtkConstraintSolver.
2019-06-27 17:38:02 +01:00
Emmanuele Bassi
5780ec4bf1 Assign a GtkConstraintSolver to each GtkRoot
Constraints need to work across different parents, so it's better to
have a single constraint solver per top level.
2019-06-27 17:38:02 +01:00
Emmanuele Bassi
ec14c1f605 Move the Root interface to a private header
We don't expect out of tree implementations of GtkRoot, and having the
interface structure private to the GTK code allows us to add virtual
functions involving private types.
2019-06-27 17:38:02 +01:00
Emmanuele Bassi
c09fada79e Add constraint solver
GtkConstraintSolver is an implementation of the Cassowary constraint
solving algorithm:

  http://constraints.cs.washington.edu/cassowary/

The Cassowary method allows to incrementally solve a tableau of linear
equations, in the form of:

  x = y × coefficient + constant

with different weights, or strengths, applied to each one.

These equations can be used to describe constraints applied to a layout
of UI elements, which allows layout managers using the Cassowary method
to quickly, and efficiently, lay out widgets in complex relations
between themselves and their parent container.
2019-06-27 17:38:02 +01:00
5962 changed files with 1652545 additions and 989713 deletions

View File

@@ -1,12 +0,0 @@
# See https://wiki.apertis.org/Guidelines/Coding_conventions#Code_formatting
BasedOnStyle: GNU
AlwaysBreakAfterDefinitionReturnType: All
BreakBeforeBinaryOperators: None
BinPackParameters: false
SpaceAfterCStyleCast: true
PointerAlignment: Right
# Our column limit is actually 80, but setting that results in clang-format
# making a lot of dubious hanging-indent choices; disable it and assume the
# developer will line wrap appropriately. clang-format will still check
# existing hanging indents.
ColumnLimit: 0

View File

@@ -1,32 +0,0 @@
# SPDX-FileCopyrightText: 2021 The GTK Authors
# SPDX-License-Identifier: CC0-1.0
root = true
[*]
charset = utf-8
end_of_line = lf
trim_trailing_whitespace = true
[*.[ch]]
indent_size = 2
indent_style = space
insert_final_newline = true
# For the legacy tabs which still exist in the code:
tab_width = 8
[*.ui]
indent_size = 2
indent_style = space
insert_final_newline = true
[*.xml]
indent_size = 2
indent_style = space
[meson.build]
indent_size = 2
indent_style = space
[*.md]
max_line_length = 80

View File

@@ -1,2 +0,0 @@
[flake8]
ignore = E501

1
.gitignore vendored
View File

@@ -1,2 +1 @@
/subprojects/*/
.flatpak-builder/

View File

@@ -1,14 +1,6 @@
include:
- project: 'gnome/citemplates'
file: 'flatpak/flatpak_ci_initiative.yml'
stages:
- check
- build
- analysis
- docs
- flatpak
- publish
- deploy
.cache-paths: &cache-paths
@@ -20,457 +12,109 @@ stages:
- subprojects/libepoxy/
- subprojects/pango/
# Common variables
variables:
COMMON_MESON_FLAGS: "-Dwerror=true -Dcairo:werror=false -Dgi-docgen:werror=false -Dgraphene:werror=false -Dlibepoxy:werror=false -Dlibsass:werror=false -Dpango:werror=false -Dsassc:werror=false -Dgdk-pixbuf:werror=false -Dglib:werror=false -Dlibcloudproviders:werror=false -Dlibpng:werror=false -Dlibtiff:werror=false -Dsysprof:werror=false -Dwayland-protocols:werror=false -Dharfbuzz:werror=false -Dfreetype2:werror=false -Dfontconfig:werror=false -Dfribidi:werror=false -Dlibffi:werror=false -Dlibjpeg-turbo:werror=false -Dmutest:werror=false -Dpixman:werror=false -Dproxy-libintl:werror=false"
BACKEND_FLAGS: "-Dx11-backend=true -Dwayland-backend=true -Dbroadway-backend=true"
FEATURE_FLAGS: "-Dvulkan=enabled -Dcloudproviders=enabled -Dbuild-testsuite=true -Dintrospection=enabled"
MESON_TEST_TIMEOUT_MULTIPLIER: 3
FEDORA_IMAGE: "registry.gitlab.gnome.org/gnome/gtk/fedora:v48"
workflow:
rules:
# run merge request pipelines
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
# do not run branch pipelines if corresponding merge requests exist...
# (this avoids duplicate pipelines)
- if: $CI_COMMIT_BRANCH && $CI_OPEN_MERGE_REQUESTS
when: never
# ...but otherwise run branch pipelines
- if: $CI_COMMIT_BRANCH
# run tag pipelines
- if: $CI_COMMIT_TAG
default:
retry:
max: 2
when:
- 'runner_system_failure'
- 'stuck_or_timeout_failure'
- 'scheduler_failure'
- 'api_failure'
interruptible: true
style-check-diff:
image: $FEDORA_IMAGE
stage: check
when: manual
fedora-x86_64:
image: registry.gitlab.gnome.org/gnome/gtk/master:v6
stage: build
script:
- .gitlab-ci/run-style-check-diff.sh
.build-fedora-default:
image: $FEDORA_IMAGE
- bash -x ./.gitlab-ci/test-docker.sh
artifacts:
when: always
reports:
junit:
- "${CI_PROJECT_DIR}/_build/report-x11.xml"
- "${CI_PROJECT_DIR}/_build/report-wayland.xml"
- "${CI_PROJECT_DIR}/_build/report-wayland_gles.xml"
- "${CI_PROJECT_DIR}/_build/report-broadway.xml"
- "${CI_PROJECT_DIR}/_build/report.xml"
name: "gtk-${CI_COMMIT_REF_NAME}"
paths:
- "${CI_PROJECT_DIR}/_build/meson-logs"
- "${CI_PROJECT_DIR}/_build/report*.xml"
- "${CI_PROJECT_DIR}/_build/report*.html"
- "${CI_PROJECT_DIR}/_build/testsuite/reftests/output/*/*.png"
- "${CI_PROJECT_DIR}/_build/testsuite/reftests/output/*/*.node"
- "${CI_PROJECT_DIR}/_build/testsuite/tools/output/*/*"
- "${CI_PROJECT_DIR}/_build/testsuite/gsk/compare/*/*/*.png"
- "${CI_PROJECT_DIR}/_build/testsuite/css/output/*/*.syscap"
- "${CI_PROJECT_DIR}/_build/testsuite/headless/*/*.log"
- "${CI_PROJECT_DIR}/_build_hello/meson-logs"
- "${CI_PROJECT_DIR}/_build/report.xml"
- "${CI_PROJECT_DIR}/_build/report.html"
- "${CI_PROJECT_DIR}/_build/testsuite/reftests/output/*.png"
- "${CI_PROJECT_DIR}/_build/testsuite/gsk/compare/*/*.png"
cache:
key: "$CI_JOB_NAME"
paths:
- _ccache/
<<: *cache-paths
fedora-x86_64:
extends: .build-fedora-default
stage: build
needs: []
variables:
EXTRA_MESON_FLAGS: "--buildtype=debug --default-library=both"
script:
- .gitlab-ci/show-info-linux.sh
- export PATH="$HOME/.local/bin:$PATH"
- meson subprojects download
- meson subprojects update --reset
- meson setup
${COMMON_MESON_FLAGS}
${EXTRA_MESON_FLAGS}
${BACKEND_FLAGS}
${FEATURE_FLAGS}
_build
- meson compile -C _build
- .gitlab-ci/run-tests.sh _build wayland
- .gitlab-ci/run-tests.sh _build wayland_gles
release-build:
extends: .build-fedora-default
stage: build
needs: []
variables:
EXTRA_MESON_FLAGS: "--buildtype=release"
script:
- .gitlab-ci/show-info-linux.sh
- export PATH="$HOME/.local/bin:$PATH"
- meson subprojects download
- meson subprojects update --reset
- mkdir _install
- meson setup
--prefix=${CI_PROJECT_DIR}/_install
${COMMON_MESON_FLAGS}
${EXTRA_MESON_FLAGS}
${BACKEND_FLAGS}
${FEATURE_FLAGS}
_build
- meson compile -C _build
- meson install -C _build
- PKG_CONFIG_PATH=${CI_PROJECT_DIR}/_install/lib64/pkgconfig:${CI_PROJECT_DIR}/_install/share/pkgconfig meson setup _build_hello examples/hello
- LD_LIBRARY_PATH=${CI_PROJECT_DIR}/_install/lib64 meson compile -C _build_hello
- .gitlab-ci/run-tests.sh _build x11
fedora-clang:
extends: .build-fedora-default
stage: build
needs: []
variables:
EXTRA_MESON_FLAGS: "--buildtype=release"
script:
- .gitlab-ci/show-info-linux.sh
- export PATH="$HOME/.local/bin:$PATH"
- export CC=clang
- meson subprojects download
- meson subprojects update --reset
- meson setup
${COMMON_MESON_FLAGS}
${EXTRA_MESON_FLAGS}
${BACKEND_FLAGS}
${FEATURE_FLAGS}
_build
- meson compile -C _build
fedora-mingw64:
extends: .build-fedora-default
stage: build
needs: []
before_script:
- sudo dnf install -y
mingw64-filesystem
mingw64-gcc
mingw64-binutils
mingw64-cairo
mingw64-gdk-pixbuf
mingw64-gstreamer1-plugins-bad-free
mingw64-glib2
mingw64-libepoxy
mingw64-pango
# mingw64-graphene (rawhide)
script:
- .gitlab-ci/show-info-linux.sh
- export PATH="$HOME/.local/bin:$PATH"
- pip3 install --user meson~=1.0
- meson subprojects download
- meson subprojects update --reset
- meson -Dintrospection=disabled -Dgraphene:introspection=disabled _build
- meson compile -C _build
.mingw-defaults:
.mingw-defaults: &mingw-defaults
stage: build
tags:
- win32-ps
- win32
script:
- C:\msys64\usr\bin\pacman --noconfirm -Syyuu
- C:\msys64\usr\bin\bash -lc "bash -x ./.gitlab-ci/test-msys2.sh"
cache:
key: "$CI_JOB_NAME"
paths:
- _ccache/
- subprojects/gdk-pixbuf/
- subprojects/glib/
- subprojects/graphene/
- subprojects/libepoxy/
- subprojects/pango/
key: "%CI_JOB_NAME%"
<<: *cache-paths
msys2-mingw64:
extends: .mingw-defaults
needs: []
msys2-mingw32:
variables:
MSYSTEM: "MINGW64"
MSYSTEM: "MINGW32"
CHERE_INVOKING: "yes"
artifacts:
when: always
expose_as: 'Windows_DLL_MSYS2_64_bit_toolchain'
paths:
- "${CI_PROJECT_DIR}/_build/gtkdll.tar.gz"
<<: *mingw-defaults
macos-x86_64:
rules:
# run merge request pipelines
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
# do not run in forks
- if: $CI_PROJECT_NAMESPACE == "GNOME"
stage: build
tags:
- macosintel
needs: []
variables:
MESON_FORCE_BACKTRACKE: 1
TMPDIR: /Users/Shared/work/tmp
SDKROOT: /opt/sdks/MacOSX10.13.4.sdk
CCACHE_DIR: /Users/Shared/work/ccache
PIP_CACHE_DIR: /Users/Shared/build/cache
PIPENV_CACHE_DIR: $PIP_CACHE_DIR
PYTHONPYCACHEPREFIX: $PIP_CACHE_DIR
before_script:
- bash .gitlab-ci/show-info-osx.sh
- python3 -m venv .venv
- ln -s /opt/cmake/CMake.app/Contents/bin/cmake .venv/bin
- ln -s /opt/ccache/ccache .venv/bin
- source .venv/bin/activate
- pip3 install meson==1.2.0
- pip3 install ninja==1.11.1
script:
- meson setup ${COMMON_MESON_FLAGS}
-Dx11-backend=false
-Dbroadway-backend=true
-Dmacos-backend=true
-Dmedia-gstreamer=disabled
-Dintrospection=disabled
-Dcpp_std=c++11
-Dpixman:tests=disabled
-Dlibjpeg-turbo:simd=disabled
-Dbuild-demos=false
-Dbuild-tests=false
-Dbuild-examples=false
-Dbuild-testsuite=false
_build
- meson compile -C _build
artifacts:
when: always
paths:
- "${CI_PROJECT_DIR}/_build/meson-logs"
vs2017-x64:
# TODO: Uncomment this when ready to merge.
# rules:
# - if: $CI_PROJECT_NAMESPACE == "GNOME"
stage: build
tags:
- win32-ps
needs: []
script:
- .gitlab-ci/test-msvc.bat
artifacts:
when: always
paths:
- "${CI_PROJECT_DIR}/_build/meson-logs"
.flatpak-defaults:
image: "quay.io/gnome_infrastructure/gnome-runtime-images:gnome-master"
.flatpak-defaults: &flatpak-defaults
image: registry.gitlab.gnome.org/gnome/gnome-runtime-images/gnome:master
stage: flatpak
allow_failure: true
tags:
- flatpak
artifacts:
paths:
- "${APPID}-dev.flatpak"
- 'repo.tar'
expire_in: 1 day
rules:
# Only build Flatpak bundles automatically on main
- if: $CI_COMMIT_BRANCH == "main"
- if: $CI_COMMIT_BRANCH != "main"
when: "manual"
script:
- bash -x ./.gitlab-ci/flatpak-build.sh "${APPID}"
flatpak:demo:
extends: '.flatpak-defaults'
needs: []
# Manual jobs, for branches and MRs
.flatpak-manual: &flatpak-manual
<<: *flatpak-defaults
when: manual
# Only build Flatpak bundles automatically on master
.flatpak-master: &flatpak-master
<<: *flatpak-defaults
only:
- master
flatpak-manual:demo:
variables:
APPID: org.gtk.Demo4
<<: *flatpak-manual
flatpak:demo:aarch64:
extends: '.flatpak-defaults'
needs: []
tags:
- flatpak-aarch64
flatpak-master:demo:
variables:
APPID: org.gtk.Demo4
<<: *flatpak-master
flatpak:widget-factory:
extends: '.flatpak-defaults'
needs: []
flatpak-manual:widget-factory:
variables:
APPID: org.gtk.WidgetFactory4
<<: *flatpak-manual
flatpak:widget-factory:aarch64:
extends: '.flatpak-defaults'
needs: []
tags:
- flatpak-aarch64
flatpak-master:widget-factory:
variables:
APPID: org.gtk.WidgetFactory4
<<: *flatpak-master
flatpak:icon-browser:
extends: '.flatpak-defaults'
needs: []
flatpak-manual:icon-browser:
variables:
APPID: org.gtk.IconBrowser4
<<: *flatpak-manual
flatpak:icon-browser:aarch64:
extends: '.flatpak-defaults'
needs: []
tags:
- flatpak-aarch64
flatpak-master:icon-browser:
variables:
APPID: org.gtk.IconBrowser4
<<: *flatpak-master
flatpak:node-editor:
extends: '.flatpak-defaults'
needs: []
variables:
APPID: org.gtk.gtk4.NodeEditor
flatpak:node-editor:aarch64:
extends: '.flatpak-defaults'
needs: []
tags:
- flatpak-aarch64
variables:
APPID: org.gtk.gtk4.NodeEditor
# Publish the demo apps to the GNOME Nightly repo
# https://wiki.gnome.org/Apps/Nightly
# https://gitlab.gnome.org/GNOME/Initiatives/-/wikis/DevOps-with-Flatpak
nightly demo:
extends: '.publish_nightly'
needs: ['flatpak:demo']
nightly demo aarch64:
extends: '.publish_nightly'
needs: ['flatpak:demo:aarch64']
nightly factory:
extends: '.publish_nightly'
needs: ['flatpak:widget-factory']
nightly factory aarch64:
extends: '.publish_nightly'
needs: ['flatpak:widget-factory:aarch64']
nightly icon-browser:
extends: '.publish_nightly'
needs: ['flatpak:icon-browser']
nightly icon-browser aarch64:
extends: '.publish_nightly'
needs: ['flatpak:icon-browser:aarch64']
nightly node-editor:
extends: '.publish_nightly'
needs: ['flatpak:node-editor']
nightly node-editor aarch64:
extends: '.publish_nightly'
needs: ['flatpak:node-editor:aarch64']
static-scan:
image: $FEDORA_IMAGE
stage: analysis
needs: []
variables:
EXTRA_MESON_FLAGS: "--buildtype=debug"
pages:
image: registry.gitlab.gnome.org/gnome/gtk/master:v6
stage: deploy
script:
- export PATH="$HOME/.local/bin:$PATH"
- meson setup
${COMMON_MESON_FLAGS}
${EXTRA_MESON_FLAGS}
${BACKEND_FLAGS}
${FEATURE_FLAGS}
_scan_build
- ninja -C _scan_build scan-build
artifacts:
paths:
- _scan_build/meson-logs
allow_failure: true
# Run tests with the address sanitizer. We need to turn off introspection
# and f16c, since they are incompatible with asan
asan-build:
image: $FEDORA_IMAGE
tags: [ asan ]
stage: analysis
needs: []
variables:
script:
- export PATH="$HOME/.local/bin:$PATH"
- CC=clang meson setup
--buildtype=debugoptimized
-Db_sanitize=address
-Db_lundef=false
-Dbuild-demos=false
-Dbuild-tests=false
-Dbuild-examples=false
-Dintrospection=disabled
-Df16c=disabled
_build
- meson -Ddocumentation=true _build .
- ninja -C _build
- .gitlab-ci/run-tests.sh _build wayland
- .gitlab-ci/run-tests.sh _build wayland_gles
- .gitlab-ci/run-tests.sh _build x11
artifacts:
when: always
paths:
- "${CI_PROJECT_DIR}/_build/meson-logs"
- ninja -C _build gdk4-doc gsk4-doc gtk4-doc
reference:
image: $FEDORA_IMAGE
stage: docs
needs: []
script:
- export PATH="$HOME/.local/bin:$PATH"
- meson setup
${COMMON_MESON_FLAGS}
--buildtype=release
--force-fallback-for=gdk-pixbuf,pango
-Dintrospection=enabled
-Ddocumentation=true
-Dgtk_doc=true
-Dgdk-pixbuf:gtk_doc=true
-Dpango:gtk_doc=true
-Dbuild-demos=false
-Dbuild-examples=false
-Dbuild-tests=false
-Dbuild-testsuite=false
_build
- meson compile -C _build
- mkdir -p _reference/
- mv _build/docs/reference/gdk/gdk4/ _reference/gdk4/
- mv _build/docs/reference/gdk/gdk4-x11/ _reference/gdk4-x11/
- mv _build/docs/reference/gdk/gdk4-wayland/ _reference/gdk4-wayland/
- mv _build/docs/reference/gsk/gsk4/ _reference/gsk4/
- mv _build/docs/reference/gtk/gtk4/ _reference/gtk4/
- mv _build/subprojects/pango/docs/Pango/ _reference/Pango/
- mv _build/subprojects/pango/docs/PangoCairo/ _reference/PangoCairo/
- mv _build/subprojects/pango/docs/PangoFc/ _reference/PangoFc/
- mv _build/subprojects/pango/docs/PangoFT2/ _reference/PangoFT2/
- mv _build/subprojects/pango/docs/PangoOT/ _reference/PangoOT/
- mv _build/subprojects/pango/docs/PangoXft/ _reference/PangoXft/
- mv _build/subprojects/gdk-pixbuf/docs/gdk-pixbuf/ _reference/gdk-pixbuf/
- mv _build/subprojects/gdk-pixbuf/docs/gdk-pixdata/ _reference/gdk-pixdata/
- mkdir -p public/
- mv _build/docs/reference/gtk/html/ public/gtk/
- mv _build/docs/reference/gdk/html/ public/gdk/
- mv _build/docs/reference/gsk/html/ public/gsk/
artifacts:
paths:
- _reference
publish-docs:
image: fedora:latest
stage: publish
interruptible: false
needs: ['reference']
script:
- "curl -X POST -F token=${PAGES_TRIGGER_TOKEN} -F ref=docs-gtk-org https://gitlab.gnome.org/api/v4/projects/665/trigger/pipeline"
rules:
- if: $CI_COMMIT_REF_NAME == "main"
- public
only:
- master

85
.gitlab-ci/Dockerfile Normal file
View File

@@ -0,0 +1,85 @@
FROM fedora:30
RUN dnf -y install \
hicolor-icon-theme \
adwaita-icon-theme \
atk-devel \
at-spi2-atk-devel \
avahi-gobject-devel \
cairo-devel \
cairo-gobject-devel \
ccache \
colord-devel \
cups-devel \
dbus-daemon \
dejavu-sans-mono-fonts \
desktop-file-utils \
elfutils-libelf-devel \
fribidi-devel \
gcc \
gcc-c++ \
gdk-pixbuf2-devel \
gdk-pixbuf2-modules \
gettext \
git \
glib2-devel \
glibc-devel \
glibc-headers \
gobject-introspection-devel \
graphene-devel \
gstreamer1-devel \
gstreamer1-plugins-good \
gstreamer1-plugins-bad-free-devel \
gstreamer1-plugins-base-devel \
gtk-doc \
iso-codes \
itstool \
json-glib-devel \
lcov \
libattr-devel \
libepoxy-devel \
libffi-devel \
libmount-devel \
librsvg2 \
libselinux-devel \
libXcomposite-devel \
libXcursor-devel \
libXcursor-devel \
libXdamage-devel \
libXfixes-devel \
libXi-devel \
libXinerama-devel \
libxkbcommon-devel \
libXrandr-devel \
libXrender-devel \
libxslt \
mesa-dri-drivers \
mesa-libEGL-devel \
mesa-libwayland-egl-devel \
ninja-build \
pango-devel \
pcre-devel \
python3 \
python3-jinja2 \
python3-pip \
python3-wheel \
redhat-rpm-config \
sassc \
systemtap-sdt-devel \
vulkan-devel \
wayland-devel \
wayland-protocols-devel \
which \
xorg-x11-server-Xvfb \
&& dnf clean all
RUN pip3 install meson==0.50.1
ARG HOST_USER_ID=5555
ENV HOST_USER_ID ${HOST_USER_ID}
RUN useradd -u $HOST_USER_ID -ms /bin/bash user
USER user
WORKDIR /home/user
ENV LANG C.UTF-8

View File

@@ -1,50 +0,0 @@
## GTK CI infrastructure
GTK uses different CI images depending on platform and jobs.
The CI images are Docker containers, generated either using `docker` or
`podman`, and pushed to the GitLab [container registry][registry].
Each Docker image has a tag composed of two parts:
- `${image}`: the base image for a given platform, like "fedora" or
"debian-stable"
- `${number}`: an incremental version number, or `latest`
See the [container registry][registry] for the available images for each
branch, as well as their available versions.
Note that using `latest` as version number will overwrite the most
recently uploaded image in the registry.
### Checklist for Updating a CI image
- [ ] Update the `${image}.Dockerfile` file with the dependencies
- [ ] Run `./run-docker.sh build --base ${image} --version ${number}`
- [ ] Run `./run-docker.sh push --base ${image} --version ${number}`
once the Docker image is built; you may need to log in by using
`docker login` or `podman login`
- [ ] Update the `image` keys in the `.gitlab-ci.yml` file with the new
image tag
- [ ] Open a merge request with your changes and let it run
### Checklist for Adding a new CI image
- [ ] Write a new `${image}.Dockerfile` with the instructions to set up
a build environment
- [ ] Add the `pip3 install meson` incantation
- [ ] Run `./run-docker.sh build --base ${image} --version ${number}`
- [ ] Run `./run-docker.sh push --base ${image} --version ${number}`
- [ ] Add the new job to `.gitlab-ci.yml` referencing the image
- [ ] Open a merge request with your changes and let it run
### Checklist for Adding a new dependency to a CI image
Our images are layered, and the base (called fedora-base) contains
all the rpm payload. Therefore, adding a new dependency is a 2-step
process:
1. [ ] Build and upload fedora-base:$version+1
1. [ ] Build and upload fedora:$version+1 based on fedora-base:version+1
[registry]: https://gitlab.gnome.org/GNOME/gtk/container_registry

View File

@@ -1,133 +0,0 @@
#!/usr/bin/env python3
#
# === clang-format-diff.py - ClangFormat Diff Reformatter ---*- python -*-=== #
#
# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
# See https://llvm.org/LICENSE.txt for license information.
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
#
# ===---------------------------------------------------------------------=== #
"""
This script reads input from a unified diff and reformats all the changed
lines. This is useful to reformat all the lines touched by a specific patch.
Example usage for git/svn users:
git diff -U0 --no-color HEAD^ | clang-format-diff.py -p1 -i
svn diff --diff-cmd=diff -x-U0 | clang-format-diff.py -i
"""
from __future__ import absolute_import, division, print_function
import argparse
import difflib
import re
import subprocess
import sys
if sys.version_info.major >= 3:
from io import StringIO
else:
from io import BytesIO as StringIO
def main():
parser = argparse.ArgumentParser(
description=__doc__,
formatter_class=argparse.RawDescriptionHelpFormatter)
parser.add_argument('-i', action='store_true', default=False,
help='apply edits to files instead of displaying a '
'diff')
parser.add_argument('-p', metavar='NUM', default=0,
help='strip the smallest prefix containing P slashes')
parser.add_argument('-regex', metavar='PATTERN', default=None,
help='custom pattern selecting file paths to reformat '
'(case sensitive, overrides -iregex)')
parser.add_argument('-iregex', metavar='PATTERN',
default=r'.*\.(cpp|cc|c\+\+|cxx|c|cl|h|hh|hpp|m|mm|inc'
r'|js|ts|proto|protodevel|java|cs)',
help='custom pattern selecting file paths to reformat '
'(case insensitive, overridden by -regex)')
parser.add_argument('-sort-includes', action='store_true', default=False,
help='let clang-format sort include blocks')
parser.add_argument('-v', '--verbose', action='store_true',
help='be more verbose, ineffective without -i')
parser.add_argument('-style',
help='formatting style to apply (LLVM, Google, '
'Chromium, Mozilla, WebKit)')
parser.add_argument('-binary', default='clang-format',
help='location of binary to use for clang-format')
args = parser.parse_args()
# Extract changed lines for each file.
filename = None
lines_by_file = {}
for line in sys.stdin:
match = re.search(r'^\+\+\+\ (.*?/){%s}(\S*)' % args.p, line)
if match:
filename = match.group(2)
if filename is None:
continue
if args.regex is not None:
if not re.match('^%s$' % args.regex, filename):
continue
else:
if not re.match('^%s$' % args.iregex, filename, re.IGNORECASE):
continue
match = re.search(r'^@@.*\+(\d+)(,(\d+))?', line)
if match:
start_line = int(match.group(1))
line_count = 1
if match.group(3):
line_count = int(match.group(3))
if line_count == 0:
continue
end_line = start_line + line_count - 1
lines_by_file.setdefault(filename, []).extend(
['-lines', str(start_line) + ':' + str(end_line)])
# Reformat files containing changes in place.
# We need to count amount of bytes generated in the output of
# clang-format-diff. If clang-format-diff doesn't generate any bytes it
# means there is nothing to format.
format_line_counter = 0
for filename, lines in lines_by_file.items():
if args.i and args.verbose:
print('Formatting {}'.format(filename))
command = [args.binary, filename]
if args.i:
command.append('-i')
if args.sort_includes:
command.append('-sort-includes')
command.extend(lines)
if args.style:
command.extend(['-style', args.style])
p = subprocess.Popen(command,
stdout=subprocess.PIPE,
stderr=None,
stdin=subprocess.PIPE,
universal_newlines=True)
stdout, _ = p.communicate()
if p.returncode != 0:
sys.exit(p.returncode)
if not args.i:
with open(filename) as f:
code = f.readlines()
formatted_code = StringIO(stdout).readlines()
diff = difflib.unified_diff(code, formatted_code,
filename, filename,
'(before formatting)',
'(after formatting)')
diff_string = ''.join(diff)
if diff_string:
format_line_counter += sys.stdout.write(diff_string)
if format_line_counter > 0:
sys.exit(1)
if __name__ == '__main__':
main()

View File

@@ -1,117 +0,0 @@
FROM fedora:38
RUN dnf -y install \
adwaita-icon-theme \
atk-devel \
at-spi2-atk-devel \
avahi-gobject-devel \
cairo-devel \
cairo-gobject-devel \
ccache \
clang \
clang-analyzer \
clang-tools-extra \
colord-devel \
cups-devel \
dbus-daemon \
dbus-x11 \
dejavu-sans-mono-fonts \
desktop-file-utils \
diffutils \
docbook-style-xsl \
elfutils-libelf-devel \
expat-devel \
fribidi-devel \
gcc \
gcc-c++ \
gdk-pixbuf2-devel \
gdk-pixbuf2-modules \
gettext \
git \
glib2-devel \
glib2-static \
glibc-devel \
glibc-headers \
glslc \
gnupg2 \
gobject-introspection-devel \
graphene-devel \
graphviz \
gstreamer1-devel \
gstreamer1-plugins-good \
gstreamer1-plugins-bad-free-devel \
gstreamer1-plugins-base-devel \
hicolor-icon-theme \
iso-codes \
itstool \
json-glib-devel \
lcov \
libasan \
libattr-devel \
libcloudproviders-devel \
libepoxy-devel \
libffi-devel \
libjpeg-turbo-devel \
libmount-devel \
libpng-devel \
librsvg2 \
libselinux-devel \
libtiff-devel \
libubsan \
libXcomposite-devel \
libXcursor-devel \
libXcursor-devel \
libXdamage-devel \
libXfixes-devel \
libXi-devel \
libXinerama-devel \
libxkbcommon-devel \
libXrandr-devel \
libXrender-devel \
libXtst-devel \
libxslt \
mesa-dri-drivers \
mesa-libEGL-devel \
mesa-libGLES-devel \
meson \
mutter \
ninja-build \
pango-devel \
pcre-devel \
pcre-static \
pipewire \
pipewire-gstreamer \
python3 \
python3-docutils \
python3-gobject \
python3-jinja2 \
python3-markdown \
python3-packaging \
python3-pip \
python3-pydbus \
python3-pygments \
python3-typogrify \
python3-wheel \
redhat-rpm-config \
sassc \
vulkan-devel \
wayland-devel \
wayland-protocols-devel \
weston \
weston-libs \
which \
wireplumber \
xorg-x11-server-Xvfb \
&& dnf clean all
# Enable sudo for wheel users
RUN sed -i -e 's/# %wheel/%wheel/' -e '0,/%wheel/{s/%wheel/# %wheel/}' /etc/sudoers
ARG HOST_USER_ID=5555
ENV HOST_USER_ID ${HOST_USER_ID}
RUN useradd -u $HOST_USER_ID -G wheel -ms /bin/bash user
USER user
WORKDIR /home/user
ENV LANG C.UTF-8

View File

@@ -4,33 +4,34 @@ set -e
appid=$1
builddir=flatpak_app
builddir=app
repodir=repo
flatpak-builder \
--user --disable-rofiles-fuse \
--stop-at=gtk \
${builddir} \
build-aux/flatpak/${appid}.json
flatpak build ${builddir} meson \
--prefix=/app \
--libdir=/app/lib \
--buildtype=debugoptimized \
flatpak-builder \
--run ${builddir} build-aux/flatpak/${appid}.json \
meson \
--prefix /app \
--libdir /app/lib \
--buildtype debug \
-Dx11-backend=true \
-Dwayland-backend=true \
-Dprint-backends=file \
-Dbuild-tests=false \
-Dbuild-testsuite=false \
-Dbuild-examples=false \
-Dintrospection=disabled \
-Dbuild-demos=true \
-Ddemo-profile=devel \
_flatpak_build
flatpak build ${builddir} ninja -C _flatpak_build install
-Dintrospection=false \
-Ddemos=true \
_build .
flatpak-builder \
--run ${builddir} build-aux/flatpak/${appid}.json \
ninja -C _build install
flatpak-builder \
--user --disable-rofiles-fuse \
--finish-only \
--repo=${repodir} \
${builddir} \
@@ -39,10 +40,5 @@ flatpak-builder \
flatpak build-bundle \
${repodir} \
${appid}-dev.flatpak \
--runtime-repo=https://nightly.gnome.org/gnome-nightly.flatpakrepo \
--runtime-repo=https://flathub.org/repo/flathub.flatpakrepo \
${appid}
# to be consumed by the nightly publish jobs
if [[ $CI_COMMIT_BRANCH == main ]]; then
tar cf repo.tar ${repodir}
fi

View File

@@ -138,26 +138,22 @@ ul.images li {
</head>
<body>
<header>
<h1>{{ report.project_name }}/{{ report.backend }}/{{ report.branch_name }} :: Test Reports</h1>
<h1>{{ report.project_name }} :: Test Reports</h1>
<div class="report-meta">
<p><strong>Branch:</strong> {{ report.branch_name }}</p>
<p><strong>Date:</strong> <time datetime="{{ report.date.isoformat() }}">{{ report.locale_date }}</time></p>
{% if report.job_id %}<p><strong>Job ID:</strong> {{ report.job_id }}</p>{% endif %}
</div>
</header>
<article>
<section>
<div class="report-meta">
<p><strong>Backend:</strong> {{ report.backend }}</p>
<p><strong>Branch:</strong> {{ report.branch_name }}</p>
<p><strong>Date:</strong> <time datetime="{{ report.date.isoformat() }}">{{ report.locale_date }}</time></p>
{% if report.job_id %}<p><strong>Job ID:</strong> {{ report.job_id }}</p>{% endif %}
</div>
</section>
<section>
<div class="summary">
<h3><a name="summary">Summary</a></h3>
<h3>Summary</h3>
<ul>
<li><strong>Total units:</strong> {{ report.total_units }}</li>
<li><strong>Failed:</strong> {{ report.total_failures }}</li>
<li><strong>Passed:</strong> {{ report.total_successes }}</li>
<li><strong>Failed:</strong> {{ report.total_failures }}</li>
</ul>
</div>
</section>
@@ -165,55 +161,36 @@ ul.images li {
{% for suite_result in report.results_list %}
<section>
<div class="result">
<h3><a name="results">Suite: {{ suite_result.suite_name }}</a></h3>
<h3>Suite: {{ suite_result.suite_name }}</h3>
<ul>
<li><strong>Units:</strong> {{ suite_result.n_units }}</li>
<li><strong>Failed:</strong> <a href="#{{ suite_result.suite_name }}-failed">{{ suite_result.n_failures }}</a></li>
<li><strong>Passed:</strong> <a href="#{{ suite_result.suite_name }}-passed">{{ suite_result.n_successes }}</a></li>
<li><strong>Passed:</strong> {{ suite_result.n_successes }}</li>
<li><strong>Failed:</strong> {{ suite_result.n_failures }}</li>
</ul>
<div class="failures">
<h4><a name="{{ suite_result.suite_name }}-failed">Failures</a></h4>
<ul class="failed">
{% for failure in suite_result.failures if failure.result in [ 'ERROR', 'FAIL', 'UNEXPECTEDPASS' ] %}
<li><a name="{{ failure.name }}">{{ failure.name }}</a> - result: <span class="result fail">{{ failure.result }}</span><br/>
{% if failure.stdout %}
Output: <pre>{{ failure.stdout }}</pre>
{% endif %}
{% if failure.image_data is defined %}
<ul class="images">
<li><img alt="ref" src="{{ failure.image_data.ref }}" /></li>
<li><img alt="out" src="{{ failure.image_data.out }}" /></li>
<li><img alt="diff" src="{{ failure.image_data.diff }}" /></li>
<li><a href="{{ failure.image_data.refnode }}">ref node</a></li>
<li><a href="{{ failure.image_data.outnode }}">out node</a></li>
</ul>
{% endif %}
</li>
{% else %}
<li>None</li>
{% endfor %}
</ul>
<h4><a name="{{ suite_result.suite_name }}-timed-out">Timed out</a></h4>
<ul class="failed">
{% for failure in suite_result.failures if failure.result == 'TIMEOUT' %}
<li><a name="{{ failure.name }}">{{ failure.name }}</a> - result: <span class="result fail">{{ failure.result }}</span><br/>
{% if failure.stdout %}
Output: <pre>{{ failure.stdout }}</pre>
{% endif %}
</li>
{% else %}
<li>None</li>
{% endfor %}
</ul>
</div>
<div class="successes">
<h4><a name="{{ suite_result.suite_name }}-expected-fail">Expected failures</a></h4>
<h4>Passed</h4>
<ul class="passed">
{% for success in suite_result.successes if success.result == 'OK' %}
<li>{{ success.name }} - result: <span class="result pass">{{ success.result }}</li>
{% else %}
<li>None</li>
{% endfor %}
</ul>
<h4>Skipped</h4>
<ul>
{% for success in suite_result.successes if success.result == 'SKIP' %}
<li>{{ success.name }} - result: <span class="result skip">{{ success.result }}</li>
{% else %}
<li>None</li>
{% endfor %}
</ul>
<h4>Expected failures</h4>
<ul>
{% for success in suite_result.successes if success.result == 'EXPECTEDFAIL' %}
<li><a name="{{ success.name }}">{{ success.name }}</a> - result: <span class="result xfail">{{ success.result }}</span><br/>
<li>{{ success.name }} - result: <span class="result xfail">{{ success.result }}</span><br/>
{% if success.stdout %}
Output: <pre>{{ success.stdout }}</pre>
{% endif %}
@@ -229,20 +206,37 @@ ul.images li {
<li>None</li>
{% endfor %}
</ul>
</div>
<h4><a name="{{ suite_result.suite_name }}-skipped">Skipped</a></h4>
<ul>
{% for success in suite_result.successes if success.result == 'SKIP' %}
<li>{{ success.name }} - result: <span class="result skip">{{ success.result }}</li>
<div class="failures">
<h4>Failed</h4>
<ul class="failed">
{% for failure in suite_result.failures if failure.result == 'FAIL' %}
<li>{{ failure.name }} - result: <span class="result fail">{{ failure.result }}</span><br/>
{% if failure.stdout %}
Output: <pre>{{ failure.stdout }}</pre>
{% endif %}
{% if failure.image_data is defined %}
<ul class="images">
<li><img alt="ref" src="{{ failure.image_data.ref }}" /></li>
<li><img alt="out" src="{{ failure.image_data.out }}" /></li>
<li><img alt="diff" src="{{ failure.image_data.diff }}" /></li>
</ul>
{% endif %}
</li>
{% else %}
<li>None</li>
{% endfor %}
</ul>
<h4><a name="{{ suite_result.suite_name }}-passed">Passed</a></h4>
<ul class="passed">
{% for success in suite_result.successes if success.result == 'OK' %}
<li>{{ success.name }} - result: <span class="result pass">{{ success.result }}</li>
<h4>Timed out</h4>
<ul class="failed">
{% for failure in suite_result.failures if failure.result == 'TIMEOUT' %}
<li>{{ failure.name }} - result: <span class="result fail">{{ failure.result }}</span><br/>
{% if failure.stdout %}
Output: <pre>{{ failure.stdout }}</pre>
{% endif %}
</li>
{% else %}
<li>None</li>
{% endfor %}
@@ -262,15 +256,12 @@ aparser = argparse.ArgumentParser(description='Turns a Meson test log into an HT
aparser.add_argument('--project-name', metavar='NAME',
help='The project name',
default='Unknown')
aparser.add_argument('--backend', metavar='NAME',
help='The used backend',
default='unknown')
aparser.add_argument('--job-id', metavar='ID',
help='The job ID for the report',
default=None)
aparser.add_argument('--branch', metavar='NAME',
help='Branch of the project being tested',
default='main')
default='master')
aparser.add_argument('--output', metavar='FILE',
help='The output HTML file, stdout by default',
type=argparse.FileType('w', encoding='UTF-8'),
@@ -313,8 +304,6 @@ for line in args.infile:
image_data = {
'ref': os.path.join(args.reftest_output_dir, '{}.ref.png'.format(basename)),
'out': os.path.join(args.reftest_output_dir, '{}.out.png'.format(basename)),
'refnode': os.path.join(args.reftest_output_dir, '{}.ref.node'.format(basename)),
'outnode': os.path.join(args.reftest_output_dir, '{}.out.node'.format(basename)),
'diff': os.path.join(args.reftest_output_dir, '{}.diff.png'.format(basename)),
}
@@ -327,7 +316,6 @@ report = {}
report['date'] = datetime.datetime.utcnow()
report['locale_date'] = report['date'].strftime("%c")
report['project_name'] = args.project_name
report['backend'] = args.backend
report['job_id'] = args.job_id
report['branch_name'] = args.branch
report['total_successes'] = 0
@@ -340,7 +328,7 @@ for name, units in suites.items():
print('Processing {} suite {}:'.format(project_name, suite_name))
def if_failed(unit):
if unit['result'] in ['FAIL', 'UNEXPECTEDPASS', 'TIMEOUT', 'ERROR',]:
if unit['result'] in ['FAIL', 'TIMEOUT']:
return True
return False

View File

@@ -19,15 +19,12 @@ aparser = argparse.ArgumentParser(description='Turns a Meson test log into a JUn
aparser.add_argument('--project-name', metavar='NAME',
help='The project name',
default='unknown')
aparser.add_argument('--backend', metavar='NAME',
help='The used backend',
default='unknown')
aparser.add_argument('--job-id', metavar='ID',
help='The job ID for the report',
default='Unknown')
aparser.add_argument('--branch', metavar='NAME',
help='Branch of the project being tested',
default='main')
default='master')
aparser.add_argument('--output', metavar='FILE',
help='The output file, stdout by default',
type=argparse.FileType('w', encoding='UTF-8'),
@@ -54,7 +51,6 @@ for line in args.infile:
duration = data['duration']
return_code = data['returncode']
result = data['result']
log = data['stdout']
unit = {
@@ -62,7 +58,6 @@ for line in args.infile:
'name': unit_name,
'duration': duration,
'returncode': return_code,
'result': result,
'stdout': log,
}
@@ -73,12 +68,12 @@ for name, units in suites.items():
print('Processing suite {} (units: {})'.format(name, len(units)))
def if_failed(unit):
if unit['result'] in ['ERROR', 'FAIL', 'UNEXPECTEDPASS', 'TIMEOUT']:
if unit['returncode'] != 0:
return True
return False
def if_succeded(unit):
if unit['result'] in ['OK', 'EXPECTEDFAIL', 'SKIP']:
if unit['returncode'] == 0:
return True
return False
@@ -95,18 +90,18 @@ for name, units in suites.items():
for unit in successes:
testcase = ET.SubElement(testsuite, 'testcase')
testcase.set('classname', '{}/{}'.format(args.project_name, unit['suite']))
testcase.set('name', '{}/{}'.format(args.backend, unit['name']))
testcase.set('name', unit['name'])
testcase.set('time', str(unit['duration']))
for unit in failures:
testcase = ET.SubElement(testsuite, 'testcase')
testcase.set('classname', '{}/{}'.format(args.project_name, unit['suite']))
testcase.set('name', '{}/{}'.format(args.backend, unit['name']))
testcase.set('name', unit['name'])
testcase.set('time', str(unit['duration']))
failure = ET.SubElement(testcase, 'failure')
failure.set('classname', '{}/{}'.format(args.project_name, unit['suite']))
testcase.set('name', '{}/{}'.format(args.backend, unit['name']))
failure.set('name', unit['name'])
failure.set('type', 'error')
failure.text = unit['stdout']

View File

@@ -1,154 +0,0 @@
/*
* SPDX-FileCopyrightText: 2021 GNOME Foundation
*
* SPDX-License-Identifier: LGPL-2.1-or-later
*/
/**
* RedHat Fonts taken from https://github.com/RedHatOfficial/RedHatFont
* License: SIL Open Font License 1.1 http://scripts.sil.org/OFL
*/
@import url('https://fonts.googleapis.com/css2?family=Noto+Serif:ital,wght@0,400;0,700;1,400;1,700&family=Red+Hat+Display:ital,wght@0,400;0,500;0,700;0,900;1,400;1,500;1,700;1,900&display=swap');
@import url('https://fonts.googleapis.com/css2?family=Noto+Serif:ital,wght@0,400;0,700;1,400;1,700&display=swap');
@import url('https://fonts.googleapis.com/css2?family=Source+Code+Pro:ital,wght@0,400;0,500;0,600;0,700;1,400;1,500;1,600&display=swap');
@font-face {
font-family: "RedHatDisplayWeb";
src: local('RedHatDisplayWeb'),
url("RedHatDisplay-Regular.woff2") format("woff2"),
url("RedHatDisplay-Regular.woff") format("woff");
font-style: normal;
font-weight: 400;
font-display: fallback;
}
@font-face {
font-family: "RedHatDisplayWeb";
src: local('RedHatDisplayWeb'),
url("RedHatDisplay-RegularItalic.woff2") format("woff2"),
url("RedHatDisplay-RegularItalic.woff") format("woff");
font-style: italic;
font-weight: 400;
font-display: fallback;
}
@font-face {
font-family: "RedHatDisplayWeb";
src: local('RedHatDisplayWeb'),
url("RedHatDisplay-Medium.woff2") format("woff2"),
url("RedHatDisplay-Medium.woff") format("woff");
font-style: normal;
font-weight: 500;
font-display: fallback;
}
@font-face {
font-family: "RedHatDisplayWeb";
src: local('RedHatDisplayWeb'),
url("RedHatDisplay-MediumItalic.woff2") format("woff2"),
url("RedHatDisplay-MediumItalic.woff") format("woff");
font-style: italic;
font-weight: 500;
font-display: fallback;
}
@font-face {
font-family: "RedHatDisplayWeb";
src: local('RedHatDisplayWeb'),
url("RedHatDisplay-Bold.woff2") format("woff2"),
url("RedHatDisplay-Bold.woff") format("woff");
font-style: normal;
font-weight: 700;
font-display: fallback;
}
@font-face {
font-family: "RedHatDisplayWeb";
src: local('RedHatDisplayWeb'),
url("RedHatDisplay-BoldItalic.woff2") format("woff2"),
url("RedHatDisplay-BoldItalic.woff") format("woff");
font-style: italic;
font-weight: 700;
font-display: fallback;
}
@font-face {
font-family: "RedHatDisplayWeb";
src: local('RedHatDisplayWeb'),
url("RedHatDisplay-Black.woff2") format("woff2"),
url("RedHatDisplay-Black.woff") format("woff");
font-style: normal;
font-weight: 900;
font-display: fallback;
}
@font-face {
font-family: "RedHatDisplayWeb";
src: local('RedHatDisplayWeb'),
url("RedHatDisplay-BlackItalic.woff2") format("woff2"),
url("RedHatDisplay-BlackItalic.woff") format("woff");
font-style: italic;
font-weight: 900;
font-display: fallback;
}
@font-face {
font-family: "RedHatTextWeb";
src: local('RedHatTextWeb'),
url("RedHatText-Regular.woff2") format("woff2"),
url("RedHatText-Regular.woff") format("woff");
font-style: normal;
font-weight: 400;
font-display: fallback;
}
@font-face {
font-family: "RedHatTextWeb";
src: local('RedHatTextWeb'),
url("RedHatText-RegularItalic.woff2") format("woff2"),
url("RedHatText-RegularItalic.woff") format("woff");
font-style: italic;
font-weight: 400;
font-display: fallback;
}
@font-face {
font-family: "RedHatTextWeb";
src: local('RedHatTextWeb'),
url("RedHatText-Medium.woff2") format("woff2"),
url("RedHatText-Medium.woff") format("woff");
font-style: normal;
font-weight: 700;
font-display: fallback;
}
@font-face {
font-family: "RedHatTextWeb";
src: local('RedHatTextWeb'),
url("RedHatText-MediumItalic.woff2") format("woff2"),
url("RedHatText-MediumItalic.woff") format("woff");
font-style: italic;
font-weight: 700;
font-display: fallback;
}
@font-face {
font-family: "RedHatTextWeb";
src: local('RedHatTextWeb'),
url("RedHatText-Bold.woff2") format("woff2"),
url("RedHatText-Bold.woff") format("woff");
font-style: normal;
font-weight: 900;
font-display: fallback;
}
@font-face {
font-family: "RedHatTextWeb";
src: local('RedHatTextWeb'),
url("RedHatText-BoldItalic.woff2") format("woff2"),
url("RedHatText-BoldItalic.woff") format("woff");
font-style: italic;
font-weight: 900;
font-display: fallback;
}

View File

@@ -1,138 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="128"
height="128"
id="svg6843"
sodipodi:version="0.32"
inkscape:version="0.92.4 5da689c313, 2019-01-14"
version="1.0"
sodipodi:docname="gtk-logo.svg"
inkscape:output_extension="org.inkscape.output.svg.inkscape"
inkscape:export-filename="/home/ebassi/Pictures/gtk-logo-256.png"
inkscape:export-xdpi="192"
inkscape:export-ydpi="192">
<defs
id="defs6845">
<inkscape:perspective
sodipodi:type="inkscape:persp3d"
inkscape:vp_x="-50 : 600 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_z="700 : 600 : 1"
inkscape:persp3d-origin="300 : 400 : 1"
id="perspective13" />
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:zoom="2.8284271"
inkscape:cx="69.874353"
inkscape:cy="64.313526"
inkscape:current-layer="layer1"
showgrid="false"
inkscape:document-units="px"
inkscape:grid-bbox="true"
width="128px"
height="128px"
showguides="true"
inkscape:guide-bbox="true"
inkscape:window-width="1920"
inkscape:window-height="1016"
inkscape:window-x="0"
inkscape:window-y="27"
inkscape:window-maximized="1">
<inkscape:grid
type="xygrid"
id="grid7947" />
</sodipodi:namedview>
<metadata
id="metadata6848">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
<dc:date />
<dc:creator>
<cc:Agent>
<dc:title />
</cc:Agent>
</dc:creator>
<dc:rights>
<cc:Agent>
<dc:title />
</cc:Agent>
</dc:rights>
<dc:publisher>
<cc:Agent>
<dc:title />
</cc:Agent>
</dc:publisher>
<dc:identifier />
<dc:source />
<dc:relation />
<dc:language />
<dc:subject>
<rdf:Bag />
</dc:subject>
<dc:coverage />
<dc:description />
<dc:contributor>
<cc:Agent>
<dc:title />
</cc:Agent>
</dc:contributor>
<cc:license
rdf:resource="" />
</cc:Work>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
</cc:Work>
</rdf:RDF>
</metadata>
<g
id="layer1"
inkscape:label="Layer 1"
inkscape:groupmode="layer">
<path
sodipodi:nodetypes="ccccc"
id="path6976"
d="M 20.88413,30.82696 L 53.816977,55.527708 L 107.33282,39.060543 L 70.587303,17.177763 L 20.88413,30.82696 z"
style="fill:#729fcf;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:2.12364459;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;display:inline" />
<path
id="path6978"
d="M 22.94243,82.287118 L 20.88413,30.82696 L 53.816977,55.527708 L 53.816977,111.10486 L 22.94243,82.287118 z"
style="fill:#e40000;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:2.12364459;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;display:inline" />
<path
id="path6980"
d="M 53.816977,111.10486 L 103.21619,90.5207 L 107.33282,39.060543 L 53.816977,55.527708 L 53.816977,111.10486 z"
style="fill:#7fe719;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:2.12364459;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;display:inline" />
<path
sodipodi:nodetypes="ccc"
id="path6982"
d="M 23.216626,81.319479 L 70.48573,67.361442 L 103.38422,90.444516"
style="opacity:1;fill:none;fill-rule:evenodd;stroke:#ffffff;stroke-width:1.25;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<path
sodipodi:nodetypes="cc"
id="path6984"
d="M 70.434539,17.875593 L 70.434539,66.984877"
style="opacity:1;fill:#babdb6;fill-rule:evenodd;stroke:#ffffff;stroke-width:1.25;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 4.8 KiB

View File

@@ -1,149 +0,0 @@
<!--
SPDX-FileCopyrightText: 2021 GNOME Foundation
SPDX-License-Identifier: LGPL-2.1-or-later
-->
<!DOCTYPE html>
<html lang="en">
<head>
<title>GTK Documentation</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta charset="utf-8" />
<meta property="og:site_name" content="https://docs.gtk.org"/>
<meta property="og:title" content="GTK Documentation"/>
<meta property="og:url" content="https://docs.gtk.org"/>
<meta property="og:type" content="website"/>
<meta property="og:description" content="API reference for GTK"/>
<meta name="twitter:title" content="GTK Documentation"/>
<meta name="twitter:url" content="https://docs.gtk.org"/>
<meta name="twitter:card" content="summary"/>
<link rel="canonical" href="https://docs.gtk.org"/>
<link rel="stylesheet" href="style.css" type="text/css" />
<script src="main.js"></script>
<!--[if IE]><script src="http://html5shiv.googlecode.com/svn/trunk/html5.js"></script><![endif]-->
</head>
<body>
<div id="body-wrapper" tabindex="-1">
<nav class="sidebar">
<div class="section">
<img src="gtk-logo.svg" class="logo"/>
</div>
<div class="section">
<h5>Sections</h5>
<div class="links">
<a href="#user-interface">User interface</a>
<a href="#core-libraries">Core libraries</a>
</div>
</div>
</nav>
<button id="btn-to-top" class="hidden"><span class="up-arrow"></span></button>
<section id="main" class="content">
<header>
<h1>GTK Documentation</h1>
</header>
<div class="toggle-wrapper">
<h4 id="user-interface">
User interface
<a href="#user-interface" class="anchor"></a>
</h4>
<div class="docblock">
<h5 id="gdk">GTK</h5>
<p>GTK is the primary library used to construct user interfaces. It
provides user interface controls and signal callbacks to respond to
user actions.</p>
<p><a href="https://docs.gtk.org/gtk4/">GTK API reference</a></p>
</div>
<div class="docblock">
<h5 id="gdk">GSK</h5>
<p>An intermediate layer which provides a rendering API implemented using Cairo, OpenGL or Vulkan.</p>
<p><a href="https://docs.gtk.org/gsk4/">GSK API reference</a></p>
</div>
<div class="docblock">
<h5 id="gdk">GDK</h5>
<p>An intermediate layer which isolates GTK from the details of the windowing system.</p>
<p><a href="https://docs.gtk.org/gdk4/">GDK API reference</a></p>
</div>
<div class="docblock">
<h5 id="pango">Pango</h5>
<p>Pango is the core text and font handling library used in GTK
applications. It has extensive support for the different writing
systems used throughout the world.</p>
<p><a href="https://docs.gtk.org/Pango/">Pango API reference</a></p>
</div>
<div class="docblock">
<h5 id="gdk-pixbuf">GdkPixbuf</h5>
<p>GdkPixbuf is a library for image loading and manipulation.</p>
<p><a href="https://docs.gtk.org/gdk-pixbuf/">GdkPixbuf API reference</a></p>
</div>
<div class="docblock">
<h5 id="cairo">Cairo</h5>
<p>Cairo is a 2D graphics library with support for multiple output
devices. It is designed to produce consistent, high quality output
on all media.</p>
<p><a href="https://www.cairographics.org/manual/" class="external">Cairo API reference</a></p>
</div>
</div>
<div class="toggle-wrapper">
<h4 id="core-libraries" style="display:flex;">
Core libraries
<a href="#core-libraries" class="anchor"></a>
</h4>
<div class="docblock">
<h5 id="glib">GLib</h5>
<p>GLib provides the core application building blocks for libraries
and applications written in C. It provides common data types
used in GTK, the main loop implementation, and a large set of
utility functions for strings and general portability across
different platforms.</p>
<p><a href="https://developer.gnome.org/glib/" class="external">GLib API reference</a></p>
</div>
<div class="docblock">
<h5 id="gobject">GObject</h5>
<p>GObject provides the object system used by GTK.</p>
<p><a href="https://developer.gnome.org/gobject/" class="external">GObject API reference</a></p>
</div>
<div class="docblock">
<h5 id="gio">GIO</h5>
<p>GIO provides a portable, modern and easy-to-use file system
abstraction API for accessing local and remote files; a set of
low and high level abstractions over the <a href="https://www.freedesktop.org/wiki/Software/dbus/" class="external">DBus</a>
IPC specification; an application settings API; portable networking
abstractions; and additional utilities for writing asynchronous
operations without blocking the user interface of your application.</p>
<p><a href="https://developer.gnome.org/gio/" class="external">GIO API reference</a></p>
</div>
</div>
</section>
<footer>
</footer>
</div>
</body>
</html>

View File

@@ -1,140 +0,0 @@
// SPDX-FileCopyrightText: 2021 GNOME Foundation
//
// SPDX-License-Identifier: LGPL-2.1-or-later
// eslint-disable-next-line no-unused-vars
function hasClass(elem, className) {
return elem && elem.classList && elem.classList.contains(className);
}
// eslint-disable-next-line no-unused-vars
function addClass(elem, className) {
if (!elem || !elem.classList) {
return;
}
elem.classList.add(className);
}
// eslint-disable-next-line no-unused-vars
function removeClass(elem, className) {
if (!elem || !elem.classList) {
return;
}
elem.classList.remove(className);
}
function insertAfter(newNode, referenceNode) {
referenceNode.parentNode.insertBefore(newNode, referenceNode.nextSibling);
}
function onEach(arr, func, reversed) {
if (arr && arr.length > 0 && func) {
var length = arr.length;
var i;
if (reversed !== true) {
for (i = 0; i < length; ++i) {
if (func(arr[i]) === true) {
return true;
}
}
} else {
for (i = length - 1; i >= 0; --i) {
if (func(arr[i]) === true) {
return true;
}
}
}
}
return false;
}
function onEachLazy(lazyArray, func, reversed) {
return onEach(
Array.prototype.slice.call(lazyArray),
func,
reversed);
}
// eslint-disable-next-line no-unused-vars
function hasOwnProperty(obj, property) {
return Object.prototype.hasOwnProperty.call(obj, property);
}
window.addEventListener("load", function() {
"use strict;"
var main = document.getElementById("main");
var btnToTop = document.getElementById("btn-to-top");
function labelForToggleButton(isCollapsed) {
if (isCollapsed) {
return "+";
}
return "\u2212";
}
function createToggle(isCollapsed) {
var toggle = document.createElement("a");
toggle.href = "javascript:void(0)";
toggle.className = "collapse-toggle";
toggle.innerHTML = "[<span class=\"inner\">"
+ labelForToggleButton(isCollapsed)
+ "</span>]";
return toggle;
}
function toggleClicked() {
if (hasClass(this, "collapsed")) {
removeClass(this, "collapsed");
this.innerHTML = "[<span class=\"inner\">"
+ labelForToggleButton(false)
+ "</span>]";
onEachLazy(this.parentNode.getElementsByClassName("docblock"), function(e) {
removeClass(e, "hidden");
});
} else {
addClass(this, "collapsed");
this.innerHTML = "[<span class=\"inner\">"
+ labelForToggleButton(true)
+ "</span>]";
onEachLazy(this.parentNode.getElementsByClassName("docblock"), function(e) {
addClass(e, "hidden");
});
}
}
onEachLazy(document.getElementsByClassName("toggle-wrapper"), function(e) {
let sectionHeader = e.querySelector(".section-header");
let fragmentMatches = sectionHeader !== null && location.hash === "#" + sectionHeader.getAttribute('id');
collapsedByDefault = hasClass(e, "default-hide") && !fragmentMatches;
var toggle = createToggle(collapsedByDefault);
toggle.onclick = toggleClicked;
e.insertBefore(toggle, e.firstChild);
if (collapsedByDefault) {
addClass(toggle, "collapsed");
onEachLazy(e.getElementsByClassName("docblock"), function(d) {
addClass(d, "hidden");
});
}
});
function scrollBackTop(e) {
e.preventDefault();
window.scroll({
top: 0,
behavior: 'smooth',
});
}
function toggleScrollButton() {
if (window.scrollY < 400) {
addClass(btnToTop, "hidden");
} else {
removeClass(btnToTop, "hidden");
}
}
window.onscroll = toggleScrollButton;
btnToTop.onclick = scrollBackTop;
}, false);

View File

@@ -1,747 +0,0 @@
/*
* SPDX-FileCopyrightText: 2021 GNOME Foundation
*
* SPDX-License-Identifier: LGPL-2.1-or-later
*/
@import url("fonts.css");
/*********************************
* LIGHT THEME
*********************************/
:root {
/* colors */
--text-color: #333;
--text-color-muted: #999;
--primary: rgb(28, 118, 228);
--body-bg: #fff;
--sidebar-primary: rgb(144, 194, 255);
--sidebar-bg: #151515;
--sidebar-selected-bg: var(--primary);
--sidebar-text-color: #fafafa;
--sidebar-padding: 1.5em;
/* boxes, e.g. code blocks */
--box-bg: rgba(135, 135, 135, 0.085);
--box-radius: 0.35rem;
--box-padding: 0.75rem;
--box-margin: 0.75rem 0;
--box-text-color: #111;
/* typography */
--body-font-family: "Noto Serif",-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";
--body-font-scale: 0.95;
--body-font-size: calc(var(--body-font-scale) * clamp(16px, 1vw, 20px));
--body-font-weight: normal;
--monospace-font-family: "Source Code Pro", monospace;
--monospace-font-size: calc(0.86 * var(--body-font-size)); /* Monospace fonts are very different in terms of font-sizes. Adjust this value to scale it */
--heading-font-family: "Red Hat Display", var(--body-font-family);
--heading-weight: 900;
--heading-font-scale: 1.05;
--heading-small-font-family: var(--heading-font-family);
--heading-small-weight: 600;
--heading-small-font-scale: 1;
--heading-table-font-family: var(--heading-font-family);
--heading-table-weight: 600;
--heading-docblock-color: #6d6d6d; /* docblocks have headings from source comments. we want them to differ.*/
--heading-docblock-scale: 0.9; /* docblocks have headings from source comments. we want them to differ.*/
--symbol-font-family: var(--heading-font-family);
--symbol-font-weight: 500;
--symbol-font-scale: 1;
--table-font-size: 0.92em; /* Tables often contain lots information. It's better to scale them down a big to get more sutff fitted inside */
/* misc */
--prefered-content-width: 90ch; /* The preferred width for the readable content */
--anchor-sign: "#";
}
/*********************************
* DARK THEME (overrides)
*********************************/
@media (prefers-color-scheme: dark) {
:root {
--primary: rgb(144, 194, 255);
--text-color: #f6f6f6;
--text-color-muted: #686868;
--body-bg: #121212;
--sidebar-primary: rgb(144, 194, 255);
--sidebar-bg: #1e1e1e;
--sidebar-selected-bg: rgb(17, 112, 228);
--sidebar-text-color: #fafafa;
--box-bg: rgba(135, 135, 135, 0.1);
--box-text-color: #fff;
--heading-docblock-color: #b7b7b7;
}
/* fix dark theme syntax highlighting with a filter (for now) */
.highlight pre span {
filter: brightness(6);
}
}
/*********************************
* GENERAL STYLING
*********************************/
*,
*:before,
*:after {
box-sizing: border-box;
}
::-moz-selection {
color: white;
background: var(--primary);
}
::selection {
color: white;
background: var(--primary);
}
::-webkit-scrollbar {
width: 8px;
height: 8px;
}
::-webkit-scrollbar-thumb {
border-radius: 10px;
background: rgba(128, 128, 128, 0.6);
}
::-webkit-scrollbar-thumb:hover {
background: rgba(128, 128, 128, 1);
}
::-webkit-scrollbar-track {
background: rgba(128, 128, 128, 0.15);
}
* {
scrollbar-width: initial;
}
body {
font: 16px/1.5 var(--body-font-family);
font-weight: var(--body-font-weight);
font-size: var(--body-font-size);
margin: 0;
padding: 0;
position: relative;
-webkit-font-feature-settings: "kern", "liga";
-moz-font-feature-settings: "kern", "liga";
font-feature-settings: "kern", "liga";
color: var(--text-color);
background: var(--body-bg);
}
h1, h2, h3, h4, h5, h6 {
font-family: var(--heading-font-family);
font-weight: var(--heading-weight);
margin: 1.75em 0 0.75em 0;
display: flex;
align-items: center;
}
h1 {
font-size: calc(1.75em * var(--heading-font-scale));
}
header h1 {
margin-top: 0;
}
h2 {
font-size: calc(1.4em * var(--heading-font-scale));
}
h3 {
font-size: calc(1.2em * var(--heading-font-scale));
}
header h3 {
color: var(--text-color-muted);
margin-bottom: 0;
}
h4, h5 {
font-size: calc(1em * var(--heading-font-scale));
}
h6 {
font-size: calc(1em * var(--heading-small-font-scale));
font-family: var(--heading-small-font-family);
font-weight: var(--heading-small-weight);
}
ol, ul {
padding-left: 1rem;
}
ul ul, ol ul, ul ol, ol ol {
margin-bottom: .6em;
}
p {
margin: 0 0 .6em 0;
}
a {
color: var(--primary);
text-decoration: none;
}
a:hover {
text-decoration: underline;
}
summary {
outline: none;
}
blockquote {
border-left: 3px solid var(--primary);
background: var(--box-bg);
padding: var(--box-padding);
border-radius: var(--box-radius);
margin: var(--box--margin);
}
code,
pre {
font-family: var(--monospace-font-family);
font-size: var(--monospace-font-size);
color: var(--box-text-color);
}
pre {
background: var(--box-bg);
padding: var(--box-padding);
border-radius: var(--box-radius);
overflow: auto;
}
code {
background: var(--box-bg);
padding: 0 0.35em;
border-radius: 0.35rem;
word-break: break-word;
}
a > code {
color: var(--primary);
}
pre pre,
pre code {
padding: 0;
margin: 0;
font-size: 1em;
background: none;
color: inherit;
}
h1 code, h2 code, h3 code, h4 code, h5 code, h6 code {
font-family: inherit;
font-weight: inherit;
font-size: 0.85em;
}
strong, b {
font-weight: 600;
}
/* fix unwanted margins in tables, code, lists and blockquotes */
li > *:first-child,
li > *:first-child > *:first-child,
li > *:first-child > *:first-child > *:first-child,
td > *:first-child,
td > *:first-child > *:first-child,
td > *:first-child > *:first-child > *:first-child,
pre > *:first-child,
pre > *:first-child > *:first-child,
pre > *:first-child > *:first-child > *:first-child,
blockquote > *:first-child,
blockquote > *:first-child > *:first-child,
blockquote > *:first-child > *:first-child > *:first-child {
margin-top: 0;
}
li > *:last-child,
li > *:last-child > *:last-child,
li > *:last-child > *:last-child > *:last-child,
td > *:last-child,
td > *:last-child > *:last-child,
td > *:last-child > *:last-child > *:last-child,
pre > *:last-child,
pre > *:last-child > *:last-child,
pre > *:last-child > *:last-child > *:last-child,
blockquote > *:last-child,
blockquote > *:last-child > *:last-child,
blockquote > *:last-child > *:last-child > *:last-child {
margin-bottom: 0;
}
/*********************************
* PAGE STRUCTURE
*********************************/
#body-wrapper {
display: flex;
flex-wrap: nowrap;
flex-direction: row;
}
#body-wrapper:focus {
outline: none;
}
#main {
position: relative;
flex-grow: 1;
min-width: 0;
box-shadow: 0 0 134px rgba(0, 0, 0, 0.1);
}
footer {
width: 100%;
display: none;
}
/*********************************
* Button
*********************************/
#btn-to-top {
position: fixed;
bottom: 12px;
right: 32px;
z-index: 1000;
border-radius: 50%;
width: 42px;
height: 42px;
border: 1px solid var(--primary);
background: var(--box-bg);
color: var(--text-color);
cursor: pointer;
text-transform: none;
}
#btn-to-top > .up-arrow:after {
content: "🡅"
}
/*********************************
* SIDEBAR
*********************************/
.sidebar {
scrollbar-width: thin;
background: var(--sidebar-bg);
border-right: 1px solid var(--sidebar-bg);
min-width: 40ch;
padding: var(--sidebar-padding);
color: var(--sidebar-text-color);
position: sticky;
top: 0;
z-index: 2;
height: 100vh;
overflow-y: auto;
}
.sidebar a,
.sidebar a:hover {
text-decoration: none;
}
.sidebar .logo {
display: block;
margin: 2rem auto 0 auto;
width: 70%;
}
.sidebar .section > ul > li {
margin-right: -10px;
}
.sidebar .section h3, .sidebar .section h5 {
text-align: left;
padding-left: 0.5rem;
padding-right: 0.5rem;
font-weight: var(--heading-weight);
}
.sidebar .section h5 {
font-size: 1em;
margin-bottom: 0.5em;
}
.sidebar .namespace > h3 {
margin-bottom: 0;
padding: 0;
font-size: 1.5em;
text-transform: uppercase;
font-weight: 900;
}
.sidebar .namespace > p {
font-size: 0.9em;
opacity: 0.8;
padding-left: 0.5rem;
}
.sidebar .section {
padding-left: 0.5rem;
padding-right: 0.5rem;
}
.sidebar .links {
margin-bottom: 1rem;
}
.sidebar .section a {
display: block;
text-overflow: ellipsis;
overflow: hidden;
transition: background-color 150ms ease;
color: var(--sidebar-primary);
border-radius: var(--box-radius);
padding: 0.2rem 0.5rem;
margin-bottom: 0.15rem;
}
.sidebar .section a:hover {
background-color: rgba(127, 127, 127, 0.2);
color: var(--sidebar-text-color);
}
.sidebar .section a.current {
background-color: var(--sidebar-selected-bg);
color: white;
}
.sidebar .search {
box-sizing: border-box;
text-align: center;
}
.sidebar .search input[type="text"] {
border-color: transparent;
width: 100%;
border: 1px solid #ccc;
border-radius: 50px;
padding: 6px 12px;
display: inline-block;
font-size: 80%;
box-shadow: inset 0 1px 3px #ddd;
transition: border .3s linear;
}
/*********************************
* ANCHORS & TOGGLERS
*********************************/
.anchor,
.md-anchor {
position: relative;
z-index: 1;
text-decoration: none;
padding: 0 0.5em;
color: var(--text-color-muted);
}
.anchor:hover,
.md-anchor:hover {
color: var(--primary);
}
.anchor:not([href]),
.md-anchor:not([href]) {
display: none;
}
.anchor:before,
.md-anchor:before {
content: var(--anchor-sign); /*'§'*/
}
.toggle-wrapper {
position: relative;
}
.collapse-toggle {
position: absolute;
right: 0;
left: -2em;
white-space: nowrap;
text-decoration: none;
font-size: 0.8em;
color: transparent;
}
.collapse-toggle > .inner {
width: 1rem;
height: 1rem;
border-radius: calc(0.75 * var(--box-radius));
display: inline-flex;
justify-content: center;
align-items: center;
text-align: center;
vertical-align: middle;
color: var(--box-text-color);
position: relative;
left: -0.25rem;
font-family: monospace;
font-size: 0.7rem;
font-weight: bold;
background: var(--box-bg);
}
/*********************************
* UTILITY
*********************************/
.deprecated > h6 > a {
opacity: 0.65;
}
.hidden {
display: none !important;
}
/*********************************
* CONTENT STYLING
*********************************/
.content {
padding: 2em 4em;
overflow: visible;
max-width: calc(var(--prefered-content-width) + 8em);
}
.content table:not(.table-display) {
border-spacing: 0 0.25rem;
}
.content td {
vertical-align: top;
}
.content td:first-child {
padding-right: 1rem;
}
.content td p:first-child {
margin-top: 0;
}
.content td h1, .content td h2 {
margin-left: 0;
font-size: 1.1em;
}
.content tr:first-child td {
border-top: 0;
}
kbd {
display: inline-block;
padding: 3px 5px;
font: 15px monospace;
line-height: 10px;
vertical-align: middle;
border: solid 1px;
border-radius: 3px;
box-shadow: inset 0 -1px 0;
cursor: default;
}
.content tr:first-child {
border-bottom: 1px solid rgba(0, 0, 0, 0.35);
}
.content td {
vertical-align: top;
}
.content td:first-child {
padding-right: 1rem;
}
.content td p:first-child {
margin-top: 0;
}
.content td h4, .content td h5 {
margin-left: 0;
font-size: 1.1em;
}
.content tr:first-child td {
border-top: 0;
}
.srclink {
color: var(--text-color-muted);
font-size: 1rem;
font-weight: var(--body-font-weight);
flex-grow: 0;
text-decoration: none;
margin-left: auto;
position: relative;
z-index: 1;
}
.meta tr > td:not(:first-child) {
width: 100%;
}
.meta tr > td:first-child {
white-space: nowrap;
}
/*********************************
* DOCBLOCK STYLING
*********************************/
.docblock {
position: relative;
text-align: left;
}
.docblock h1 {
font-size: calc(1.3em * var(--heading-docblock-scale) * var(--heading-font-scale));
}
.docblock h2 {
font-size: calc(1.2em * var(--heading-docblock-scale) * var(--heading-font-scale));
}
.docblock h3 {
font-size: calc(1.1em * var(--heading-docblock-scale) * var(--heading-font-scale));
}
.docblock h4 {
font-size: calc(1.05em * var(--heading-docblock-scale) * var(--heading-font-scale));
}
.docblock h1,
.docblock h2,
.docblock h3,
.docblock h4,
.docblock h5,
.docblock h6 {
color: var(--heading-docblock-color)
}
.docblock table {
margin: .25em 0;
max-width: 100%;
font-size: var(--table-font-size);
}
.docblock table td {
padding: .25em;
}
.docblock table th {
padding: .25em;
text-align: left;
font-family: var(--heading-table-font-family);
font-weight: var(--heading-table-weight);
}
.docblock table tr th:first-child,
.docblock table tr td:first-child {
padding-left: 0;
}
.docblock table tr th:last-child,
.docblock table tr td:last-child {
padding-right: 0;
}
table.enum-members,
table.results {
border-radius: var(--box-radius);
border: 1px solid var(--text-color-muted);
border-spacing: 0 0 !important;
font-size: 80%;
}
table.enum-members tr th,
table.results tr th {
border-top-color: var(--body-bg);
background-color: var(--box-bg);
border-bottom: 1px solid var(--text-color-muted);
}
table.enum-members tr th:first-child,
table.enum-members tr td:first-child {
min-width: 25em;
padding-left: .5em;
}
table.results tr th:first-child,
table.results tr td:first-child {
padding-left: .5em;
}
table.enum-members tr th:last-child,
table.enum-members tr td:last-child,
table.results tr th:last-child,
table.results tr td:last-child {
max-width: 35em;
padding-right: .5em;
}
table.results tr td code {
font-size: 100%;
}
.docblock ul li,
.docblock ol li {
padding-top: 0.15rem;
padding-bottom: 0.15rem;
}
.docblock ul.type {
list-style: none;
}
.docblock ul.type li::before {
content: "»";
color: var(--text-color);
display: inline-block;
width: 1em;
margin-left: -1em;
}
/**************************
RESPONSIVENESS
**************************/
@media (max-width: 700px) {
body {
padding-top: 0px;
}
#body-wrapper {
flex-direction: column;
overflow: hidden;
}
#main {
width: 100%;
padding: 2rem;
}
.sidebar {
position: static;
height: initial;
order: 1;
}
}

View File

@@ -1,148 +1,11 @@
#!/bin/bash
read_arg() {
# $1 = arg name
# $2 = arg value
# $3 = arg parameter
local rematch='^[^=]*=(.*)$'
if [[ $2 =~ $rematch ]]; then
read "$1" <<< "${BASH_REMATCH[1]}"
else
read "$1" <<< "$3"
# There is no way to shift our callers args, so
# return 1 to indicate they should do it instead.
return 1
fi
}
set -e
build=0
run=0
push=0
list=0
print_help=0
no_login=0
no_cache=0
TAG="registry.gitlab.gnome.org/gnome/gtk/master:v6"
while (($# > 0)); do
case "${1%%=*}" in
build) build=1;;
run) run=1;;
push) push=1;;
list) list=1;;
help) print_help=1;;
--base|-b) read_arg base "$@" || shift;;
--version|-v) read_arg base_version "$@" || shift;;
--no-login) no_login=1;;
--no-cache) no_cache=1;;
*) echo -e "\e[1;31mERROR\e[0m: Unknown option '$1'"; exit 1;;
esac
shift
done
if [ $print_help == 1 ]; then
echo "$0 - Build and run Docker images"
echo ""
echo "Usage: $0 <command> [options] [basename]"
echo ""
echo "Available commands"
echo ""
echo " build --base=<BASENAME> - Build Docker image <BASENAME>.Dockerfile"
echo " run --base=<BASENAME> - Run Docker image <BASENAME>"
echo " push --base=<BASENAME> - Push Docker image <BASENAME> to the registry"
echo " list - List available images"
echo " help - This help message"
echo ""
exit 0
fi
cd "$(dirname "$0")"
if [ $list == 1 ]; then
echo "Available Docker images:"
for f in *.Dockerfile; do
filename=$( basename -- "$f" )
basename="${filename%.*}"
echo -e " \e[1;39m$basename\e[0m"
done
exit 0
fi
# All commands after this require --base to be set
if [ -z $base ]; then
echo "Usage: $0 <command>"
exit 1
fi
if [ ! -f "$base.Dockerfile" ]; then
echo -e "\e[1;31mERROR\e[0m: Dockerfile for '$base' not found"
exit 1
fi
if [ -z $base_version ]; then
base_version="latest"
elif [ $base_version != "latest" ]; then
base_version="v$base_version"
fi
if [ ! -x "$(command -v docker)" ] || [ docker --help |& grep -q podman ]; then
# Docker is actually implemented by podman, and its OCI output
# is incompatible with some of the dockerd instances on GitLab
# CI runners.
echo "Using: Podman"
format="--format docker"
CMD="podman"
else
echo "Using: Docker"
format=""
CMD="sudo docker"
fi
REGISTRY="registry.gitlab.gnome.org"
TAG="${REGISTRY}/gnome/gtk/${base}:${base_version}"
if [ $build == 1 ]; then
echo -e "\e[1;32mBUILDING\e[0m: ${base} as ${TAG}"
if [ $no_cache == 0 ]; then
${CMD} build \
${format} \
--build-arg HOST_USER_ID="$UID" \
--tag "${TAG}" \
--file "${base}.Dockerfile" .
else
${CMD} build \
${format} \
--no-cache \
--build-arg HOST_USER_ID="$UID" \
--tag "${TAG}" \
--file "${base}.Dockerfile" .
fi
exit $?
fi
if [ $push == 1 ]; then
echo -e "\e[1;32mPUSHING\e[0m: ${base} as ${TAG}"
if [ $no_login == 0 ]; then
${CMD} login ${REGISTRY}
fi
${CMD} push ${TAG}
exit $?
fi
if [ $run == 1 ]; then
echo -e "\e[1;32mRUNNING\e[0m: ${base} as ${TAG}"
${CMD} run \
--rm \
--userns=keep-id \
--volume "$(pwd)/..:/home/user/app:rw,z" \
--workdir "/home/user/app" \
--tty \
--interactive "${TAG}" \
bash
exit $?
fi
sudo docker build --build-arg HOST_USER_ID="$UID" --tag "${TAG}" \
--file "Dockerfile" .
sudo docker run --rm --security-opt label=disable \
--volume "$(pwd)/..:/home/user/app" --workdir "/home/user/app" \
--tty --interactive "${TAG}" bash

View File

@@ -1,32 +0,0 @@
#!/usr/bin/sh
#
builddir=$1
suite=$2
unit=$3
echo "** builddir: ${builddir}"
echo "** suite: ${suite}"
echo "** unit: ${unit}"
export XDG_RUNTIME_DIR="$(mktemp -p $(pwd) -d xdg-runtime-XXXXXX)"
weston --backend=headless-backend.so --socket=wayland-5 --idle-time=0 &
compositor=$!
export WAYLAND_DISPLAY=wayland-5
meson test -C ${builddir} \
--print-errorlogs \
--setup=wayland \
--suite=${suite} \
--no-suite=failing \
--no-suite=flaky \
--no-suite=wayland_failing \
--no-suite=gsk-compare-broadway \
--verbose \
"${unit}"
exit_code=$?
kill ${compositor}
exit ${exit_code}

View File

@@ -1,62 +0,0 @@
#!/bin/bash
set -e
ancestor_horizon=31 # days (one month)
# Recently, git is picky about directory ownership. Tell it not to worry.
git config --global --add safe.directory "$PWD"
# We need to add a new remote for the upstream target branch, since this script
# could be running in a personal fork of the repository which has out of date
# branches.
#
# Limit the fetch to a certain date horizon to limit the amount of data we get.
# If the branch was forked from origin/main before this horizon, it should
# probably be rebased.
if ! git ls-remote --exit-code upstream >/dev/null 2>&1 ; then
git remote add upstream https://gitlab.gnome.org/GNOME/gtk.git
fi
# Work out the newest common ancestor between the detached HEAD that this CI job
# has checked out, and the upstream target branch (which will typically be
# `upstream/main` or `upstream/glib-2-62`).
# `${CI_MERGE_REQUEST_TARGET_BRANCH_NAME}` or `${CI_MERGE_REQUEST_SOURCE_BRANCH_NAME}`
# are only defined if were running in a merge request pipeline,
# fall back to `${CI_DEFAULT_BRANCH}` or `${CI_COMMIT_BRANCH}` respectively
# otherwise.
source_branch="${CI_MERGE_REQUEST_SOURCE_BRANCH_NAME:-${CI_COMMIT_BRANCH}}"
target_branch="${CI_MERGE_REQUEST_TARGET_BRANCH_NAME:-${CI_DEFAULT_BRANCH}}"
git fetch --shallow-since="$(date --date="${ancestor_horizon} days ago" +%Y-%m-%d)" origin "${source_branch}"
git fetch --shallow-since="$(date --date="${ancestor_horizon} days ago" +%Y-%m-%d)" upstream "${target_branch}"
newest_common_ancestor_sha=$(git merge-base upstream/${target_branch} origin/${source_branch})
if [ -z "${newest_common_ancestor_sha}" ]; then
echo "Couldnt find common ancestor with upstream main branch. This typically"
echo "happens if you branched from main a long time ago. Please update"
echo "your clone, rebase, and re-push your branch."
exit 1
fi
git diff -U0 --no-color "${newest_common_ancestor_sha}" | .gitlab-ci/clang-format-diff.py -binary "clang-format" -p1
exit_status=$?
# The style check is not infallible. The clang-format configuration cannot
# perfectly describe GTKs coding style: in particular, it cannot align
# function arguments. The documented coding style for GTK takes priority over
# clang-format suggestions. Hopefully we can eventually improve clang-format to
# be configurable enough for our coding style. Thats why this CI check is OK
# to fail: the idea is that people can look through the output and ignore it if
# its wrong. (That situation can also happen if someone touches pre-existing
# badly formatted code and it doesnt make sense to tidy up the wider coding
# style with the changes theyre making.)
echo ""
echo "Note that clang-format output is advisory and cannot always match the"
echo "GTK coding style, documented at:"
echo " https://gitlab.gnome.org/GNOME/gtk/blob/main/docs/CODING-STYLE.md"
echo "Warnings from this tool can be ignored in favour of the documented "
echo "coding style, or in favour of matching the style of existing"
echo "surrounding code."
exit ${exit_status}

View File

@@ -1,99 +0,0 @@
#!/bin/bash
set +x
set +e
srcdir=$( pwd )
builddir=$1
backend=$2
multiplier=${MESON_TEST_TIMEOUT_MULTIPLIER:-1}
# Ignore memory leaks lower in dependencies
export LSAN_OPTIONS=suppressions=$srcdir/lsan.supp:print_suppressions=0:detect_leaks=0:allocator_may_return_null=1
export G_SLICE=always-malloc
case "${backend}" in
x11)
xvfb-run -a -s "-screen 0 1024x768x24 -noreset" \
meson test -C ${builddir} \
--quiet \
--timeout-multiplier "${multiplier}" \
--print-errorlogs \
--setup=${backend} \
--suite=gtk \
--no-suite=failing \
--no-suite=flaky \
--no-suite=gsk-compare-broadway
# Store the exit code for the CI run, but always
# generate the reports
exit_code=$?
;;
wayland*)
export XDG_RUNTIME_DIR="$(mktemp -p $(pwd) -d xdg-runtime-XXXXXX)"
weston --backend=headless-backend.so --socket=wayland-5 --idle-time=0 &
compositor=$!
export WAYLAND_DISPLAY=wayland-5
meson test -C ${builddir} \
--quiet \
--timeout-multiplier "${multiplier}" \
--print-errorlogs \
--setup=${backend} \
--suite=gtk \
--no-suite=failing \
--no-suite=flaky \
--no-suite=${backend}_failing \
--no-suite=gsk-compare-broadway
exit_code=$?
kill ${compositor}
;;
broadway)
export XDG_RUNTIME_DIR="$(mktemp -p $(pwd) -d xdg-runtime-XXXXXX)"
${builddir}/gdk/broadway/gtk4-broadwayd :5 &
server=$!
export BROADWAY_DISPLAY=:5
meson test -C ${builddir} \
--quiet \
--timeout-multiplier "${multiplier}" \
--print-errorlogs \
--setup=${backend} \
--suite=gtk \
--no-suite=failing \
--no-suite=flaky \
--no-suite=gsk-compare-opengl
kill ${server}
;;
*)
echo "Failed to add ${backend} to .gitlab-ci/run-tests.sh"
exit 1
;;
esac
cd ${builddir}
$srcdir/.gitlab-ci/meson-junit-report.py \
--project-name=gtk \
--backend="${backend}" \
--job-id="${CI_JOB_NAME}" \
--output="report-${backend}.xml" \
"meson-logs/testlog-${backend}.json"
$srcdir/.gitlab-ci/meson-html-report.py \
--project-name=gtk \
--backend="${backend}" \
--job-id="${CI_JOB_NAME}" \
--reftest-output-dir="testsuite/reftests/output/${backend}" \
--output="report-${backend}.html" \
"meson-logs/testlog-${backend}.json"
exit $exit_code

View File

@@ -1,5 +0,0 @@
#! /bin/sh
. /etc/os-release
echo $PRETTY_NAME

View File

@@ -1,8 +0,0 @@
#!/bin/bash
set -eux -o pipefail
xcodebuild -version || :
xcodebuild -showsdks || :
system_profiler SPSoftwareDataType || :

View File

@@ -15,10 +15,8 @@ meson \
-Dx11-backend=true \
-Dwayland-backend=true \
-Dbroadway-backend=true \
-Dvulkan=enabled \
-Dprofiler=true \
-Dvulkan=yes \
--werror \
${EXTRA_MESON_FLAGS:-} \
_build $srcdir
unset CCACHE_DISABLE

View File

@@ -1,14 +0,0 @@
@echo on
:: vcvarsall.bat sets various env vars like PATH, INCLUDE, LIB, LIBPATH for the
:: specified build architecture
call "C:\Program Files (x86)\Microsoft Visual Studio\2017\BuildTools\VC\Auxiliary\Build\vcvarsall.bat" x64
@echo on
:: FIXME: make warnings fatal
pip3 install --upgrade --user meson~=0.64 || goto :error
meson setup -Dbackend_max_links=1 -Ddebug=false -Dmedia-gstreamer=disabled _build || goto :error
ninja -C _build || goto :error
goto :EOF
:error
exit /b 1

View File

@@ -15,9 +15,9 @@ pacman --noconfirm -Suy
pacman --noconfirm -S --needed \
base-devel \
git \
mingw-w64-$MSYS2_ARCH-cc \
mingw-w64-$MSYS2_ARCH-toolchain \
mingw-w64-$MSYS2_ARCH-ccache \
mingw-w64-$MSYS2_ARCH-pkgconf \
mingw-w64-$MSYS2_ARCH-pkg-config \
mingw-w64-$MSYS2_ARCH-gobject-introspection \
mingw-w64-$MSYS2_ARCH-meson \
mingw-w64-$MSYS2_ARCH-adwaita-icon-theme \
@@ -30,10 +30,8 @@ pacman --noconfirm -S --needed \
mingw-w64-$MSYS2_ARCH-libepoxy \
mingw-w64-$MSYS2_ARCH-pango \
mingw-w64-$MSYS2_ARCH-fribidi \
mingw-w64-$MSYS2_ARCH-gst-plugins-bad-libs \
mingw-w64-$MSYS2_ARCH-shared-mime-info \
mingw-w64-$MSYS2_ARCH-python-gobject \
mingw-w64-$MSYS2_ARCH-shaderc
mingw-w64-$MSYS2_ARCH-gst-plugins-bad \
mingw-w64-$MSYS2_ARCH-shared-mime-info
mkdir -p _ccache
export CCACHE_BASEDIR="$(pwd)"
@@ -47,13 +45,10 @@ meson \
-Dx11-backend=false \
-Dwayland-backend=false \
-Dwin32-backend=true \
-Dvulkan=disabled \
-Dintrospection=enabled \
-Dgtk:werror=true \
-Dvulkan=no \
--werror \
_build
unset CCACHE_DISABLE
ninja -C _build
ccache --show-stats
tar zcf _build/gtkdll.tar.gz _build/gtk/libgtk*.dll

View File

@@ -1,13 +1,4 @@
<!--
Please, read the CONTRIBUTING.md guide on how to file a new issue.
https://gitlab.gnome.org/GNOME/gtk/-/blob/main/CONTRIBUTING.md
-->
## Steps to reproduce
<!--
Please, explain the sequence of actions necessary to reproduce the
bug
-->
1. ...
2. ...
@@ -41,8 +32,5 @@
## Additional information
<!--
- Screenshots or screen recordings are useful for visual errors
- Attaching a screenshot or a video without explaining the current
behavior and the actions necessary to reproduce the bug will lead
to the bug being closed
- Please report any warning or message printed on the terminal
-->

View File

@@ -1,14 +1,4 @@
<!--
Please, read the CONTRIBUTING.md guide on how to file a new issue.
https://gitlab.gnome.org/GNOME/gtk/-/blob/main/CONTRIBUTING.md
-->
## Steps to reproduce
<!--
Please, explain the sequence of actions necessary to reproduce the
crash
-->
1. ...
2. ...

59
AUTHORS
View File

@@ -1,5 +1,5 @@
Please do not mail any of the authors listed here
asking questions about this version of GTK.
Please do not mail any of the authors listed here
asking questions about this version of GTK+.
Original Authors
----------------
@@ -7,8 +7,8 @@ Peter Mattis <petm@xcf.berkeley.edu>
Spencer Kimball <spencer@xcf.berkeley.edu>
Josh MacDonald <jmacd@xcf.berkeley.edu>
The team that build GTK 2 (in alphabetical order)
-------------------------------------------------
The GTK+ Team (in alphabetical order)
-------------------------------------
Shawn T. Amundson <amundson@gtk.org>
Jerome Bolliet <bolliet@gtk.org>
Damon Chaplin <damon@gtk.org>
@@ -28,45 +28,38 @@ Jay Painter <jpaint@gtk.org>
Manish Singh <manish@gtk.org>
Owen Taylor <otaylor@gtk.org>
The team that built GTK 3
-------------------------
Jonas Ådahl <jadahl@gmail.com>
Tim Bäder <mail@baedert.org>
Emmanuele Bassi <ebassi@gnome.org>
Chun-wei Fan <fanchunwei@src.gnome.org>
Matthias Clasen <mclasen@redhat.com>
Carlos Garnacho <mrgarnacho@gmail.com>
Alexander Larsson <alexl@redhat.com>
Benjamin Otte <otte@gnome.org>
The current team (GTK 4)
------------------------
Jonas Ådahl <jadahl@gmail.com>
Emmanuele Bassi <ebassi@gnome.org>
Christian Hergert <chergert@gnome.org>
Chun-wei Fan <fanchunwei@src.gnome.org>
Matthias Clasen <mclasen@redhat.com>
Carlos Garnacho <mrgarnacho@gmail.com>
Benjamin Otte <otte@gnome.org>
There are many others who have contributed patches; we thank them,
GTK is much better because of them.
GTK+ is much better because of them.
Over time, GTK has incorporated some pieces of software which
Over time, GTK+ has incorporated some pieces of software which
started as independent projects. We list the original authors here:
MS-Windows theme engine
-----------------------
Raymond Penners
Dom Lachowicz
Pixbuf theme engine
-------------------
Owen Taylor
IME input method
----------------
Takuro Ashie
Kazuki IWAMOTO
MacOS backend
-------------
Mac OS X backend
----------------
Anders Carlsson
GtkInspector (originally gtkparasite)
-------------------------------------
Christian Hammond
DirectFB backend
----------------
Denis Oliver Kropp
Sven Neumann
Mike Emmel

View File

@@ -21,8 +21,13 @@ many things that we value:
Please, do not use the issue tracker for support questions. If you have
questions on how to use GTK effectively, you can use:
- the `gtk` [room on matrix](https://matrix.to/#/#gtk:gnome.org)
- the [gtk tag on the GNOME Discourse instance](https://discourse.gnome.org/tag/gtk)
- the `#gtk` IRC channel on irc.gnome.org
- the [gtk](https://mail.gnome.org/mailman/listinfo/gtk-list) mailing list,
for general questions on GTK
- the [gtk-app-devel](https://mail.gnome.org/mailman/listinfo/gtk-app-devel-list)
mailing list, for questions on application development with GTK
- the [gtk-devel](https://mail.gnome.org/mailman/listinfo/gtk-devel-list)
mailing list, for questions on developing GTK itself
You can also look at the GTK tag on [Stack
Overflow](https://stackoverflow.com/questions/tagged/gtk).
@@ -44,7 +49,6 @@ If you're reporting a bug make sure to list:
0. which version of GTK are you using?
0. which operating system are you using?
0. what display and graphics driver are you using?
0. the necessary steps to reproduce the issue
0. the expected outcome
0. a description of the behavior; screenshots are also welcome
@@ -57,12 +61,6 @@ If the issue includes a crash, you should also include:
0. the eventual warnings printed on the terminal
0. a backtrace, obtained with tools such as GDB or LLDB
It is fine to include screenshots of screen recordings to demonstrate
an issue that is best to understand visually, but please don't just
dump screen recordings without further details into issues. It is
essential that the problem is described in enough detail to reproduce
it without watching a video.
For small issues, such as:
- spelling/grammar fixes in the documentation
@@ -176,7 +174,7 @@ maintainers review your contribution.
Each contribution is reviewed by the core developers of the GTK project.
The [CODEOWNERS](./docs/CODEOWNERS) document contains the list of core
The [CODE-OWNERS](./docs/CODE-OWNERS) document contains the list of core
contributors to GTK and the areas for which they are responsible; you
should ensure to receive their review and signoff on your changes.
@@ -257,7 +255,7 @@ people committing to GTK to follow a few rules:
0. Always write a meaningful commit message. Changes without a sufficient
commit message will be reverted.
0. Never push to the `main` branch, or any stable branches, directly; you
0. Never push to the `master` branch, or any stable branches, directly; you
should always go through a merge request, to ensure that the code is
tested on the CI infrastructure at the very least. A merge request is
also the proper place to get a comprehensive code review from the core

9938
NEWS

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,7 +1,7 @@
GTK — The GTK toolkit
=====================
[![Build status](https://gitlab.gnome.org/GNOME/gtk/badges/main/pipeline.svg)](https://gitlab.gnome.org/GNOME/gtk/-/commits/main)
[![Build Status](https://gitlab.gnome.org/GNOME/gtk/badges/master/build.svg)](https://gitlab.gnome.org/GNOME/gtk/pipelines)
General information
-------------------
@@ -10,16 +10,14 @@ GTK is a multi-platform toolkit for creating graphical user interfaces.
Offering a complete set of widgets, GTK is suitable for projects ranging
from small one-off projects to complete application suites.
GTK is a free and open-source software project. The licensing terms
for GTK, the GNU LGPL, allow it to be used by all developers, including those
developing proprietary software, without any license fees or royalties.
GTK is hosted by the GNOME project (thanks!) and used by a wide variety
of applications and projects.
GTK is free software and part of the GNU Project. However, the
licensing terms for GTK, the GNU LGPL, allow it to be used by all
developers, including those developing proprietary software, without any
license fees or royalties.
The official download location
- https://download.gnome.org/sources/gtk/
- https://download.gnome.org/sources/gtk+
The official web site
@@ -29,21 +27,14 @@ The official developers blog
- https://blog.gtk.org
Discussion forum
Information about mailing lists can be found at
- https://discourse.gnome.org/c/platform/core/
- http://www.gtk.org/mailing-lists.php
Nightly documentation can be found at
- Gtk: https://gnome.pages.gitlab.gnome.org/gtk/gtk4/
- Gdk: https://gnome.pages.gitlab.gnome.org/gtk/gdk4/
- Gsk: https://gnome.pages.gitlab.gnome.org/gtk/gsk4/
Nightly flatpaks of our demos can be installed from the
[GNOME Nightly](https://wiki.gnome.org/Apps/Nightly) repository:
- `flatpak remote-add --if-not-exists gnome-nightly https://nightly.gnome.org/gnome-nightly.flatpakrepo`
- `flatpak install gnome-nightly org.gtk.Demo4`
- `flatpak install gnome-nightly org.gtk.WidgetFactory4`
- `flatpak install gnome-nightly org.gtk.IconBrowser4`
- Gtk: https://gnome.pages.gitlab.gnome.org/gtk/gtk/
- Gdk: https://gnome.pages.gitlab.gnome.org/gtk/gdk/
- Gsk: https://gnome.pages.gitlab.gnome.org/gtk/gsk/
Building and installing
-----------------------
@@ -58,22 +49,16 @@ In order to build GTK you will need:
You will also need various dependencies, based on the platform you are
building for:
- [GLib](https://download.gnome.org/sources/glib/)
- [GdkPixbuf](https://download.gnome.org/sources/gdk-pixbuf/)
- [GObject-Introspection](https://download.gnome.org/sources/gobject-introspection/)
- [Cairo](https://www.cairographics.org/)
- [Pango](https://download.gnome.org/sources/pango/)
- [GLib](https://download.gnome.org/sources/glib)
- [GdkPixbuf](https://download.gnome.org/sources/gdk-pixbuf)
- [GObject-Introspection](https://download.gnome.org/sources/gobject-introspection)
- [Cairo](https://www.cairographics.org)
- [Pango](https://download.gnome.org/sources/pango)
- [Epoxy](https://github.com/anholt/libepoxy)
- [Graphene](https://github.com/ebassi/graphene)
- [ATK](https://download.gnome.org/sources/atk)
- [Xkb-common](https://github.com/xkbcommon/libxkbcommon)
If you are building the Wayland backend, you will also need:
- Wayland-client
- Wayland-protocols
- Wayland-cursor
- Wayland-EGL
If you are building the X11 backend, you will also need:
- Xlib, and the following X extensions:
@@ -85,42 +70,44 @@ If you are building the X11 backend, you will also need:
- xcursor
- xdamage
- xcomposite
- [atk-bridge-2.0](https://download.gnome.org/sources/at-spi2-atk)
If you are building the Wayland backend, you will also need:
- Wayland-client
- Wayland-protocols
- Wayland-cursor
- Wayland-EGL
Once you have all the necessary dependencies, you can build GTK by using
Meson:
```sh
$ meson setup _build
$ meson compile -C_build
$ meson _build .
$ cd _build
$ ninja
```
You can run the test suite using:
```sh
$ meson test -C_build
$ meson test
```
And, finally, you can install GTK using:
```
$ sudo meson install -C_build
$ sudo ninja install
```
Complete information about installing GTK and related libraries
Complete information about installing GTK+ and related libraries
can be found in the file:
```
docs/reference/gtk/html/gtk-building.html
```
Or [online](https://docs.gtk.org/gtk4/building.html)
Building from git
-----------------
The GTK sources are hosted on [gitlab.gnome.org](http://gitlab.gnome.org). The main
development branch is called `main`, and stable branches are named after their minor
version, for example `gtk-4-10`.
Or [online](https://developer.gnome.org/gtk4/stable/gtk-building.html)
How to report bugs
------------------
@@ -153,23 +140,14 @@ In the bug report please include:
* Further information such as stack traces may be useful, but
is not necessary.
Contributing to GTK
-------------------
Please, follow the [contribution guide](./CONTRIBUTING.md) to know how to
start contributing to GTK.
If you want to support GTK financially, please consider donating to
the GNOME project, which runs the infrastructure hosting GTK.
Release notes
-------------
The release notes for GTK are part of the migration guide in the API
reference. See:
- [3.x release notes](https://developer.gnome.org/gtk3/stable/gtk-migrating-2-to-3.html)
- [4.x release notes](https://docs.gtk.org/gtk4/migrating-3to4.html)
- [3.x release notes](https://developer.gnome.org/gtk3/unstable/gtk-migrating-2-to-3.html)
- [4.x release notes](https://developer.gnome.org/gtk4/unstable/gtk-migrating-3-to-4.html)
Licensing terms
---------------
@@ -178,8 +156,4 @@ GTK is released under the terms of the GNU Lesser General Public License,
version 2.1 or, at your option, any later version, as published by the Free
Software Foundation.
Please, see the [`COPYING`](./COPYING) file for further information.
GTK includes a small number of source files under the Apache license:
- A fork of the roaring bitmaps implementation in [gtk/roaring](./gtk/roaring)
- An adaptation of timsort from python in [gtk/timsort](./gtk/timsort)
Please, see the `COPYING` file for further information.

View File

@@ -1,43 +0,0 @@
diff -ur lua-5.1.4/src/Makefile lua-5.1.4-new/src/Makefile
--- lua-5.1.4/src/Makefile 2008-01-19 20:37:58.000000000 +0100
+++ lua-5.1.4-new/src/Makefile 2012-02-23 18:26:43.000000000 +0100
@@ -23,6 +23,7 @@
PLATS= aix ansi bsd freebsd generic linux macosx mingw posix solaris
LUA_A= liblua.a
+LUA_SO= liblua.so
CORE_O= lapi.o lcode.o ldebug.o ldo.o ldump.o lfunc.o lgc.o llex.o lmem.o \
lobject.o lopcodes.o lparser.o lstate.o lstring.o ltable.o ltm.o \
lundump.o lvm.o lzio.o
@@ -36,7 +37,7 @@
LUAC_O= luac.o print.o
ALL_O= $(CORE_O) $(LIB_O) $(LUA_O) $(LUAC_O)
-ALL_T= $(LUA_A) $(LUA_T) $(LUAC_T)
+ALL_T= $(LUA_A) $(LUA_SO) $(LUA_T) $(LUAC_T)
ALL_A= $(LUA_A)
default: $(PLAT)
@@ -51,6 +52,11 @@
$(AR) $@ $?
$(RANLIB) $@
+$(LUA_SO): $(CORE_O) $(LIB_O)
+ $(CC) -shared -ldl -Wl,-soname,$(LUA_SO).$(V) -o $@.$(R) $? -lm $(MYLDFLAGS)
+ ln -sf $(LUA_SO).$(R) $(LUA_SO).$(V)
+ ln -sf $(LUA_SO).$(R) $(LUA_SO)
+
$(LUA_T): $(LUA_O) $(LUA_A)
$(CC) -o $@ $(MYLDFLAGS) $(LUA_O) $(LUA_A) $(LIBS)
--- lua-5.1.4/Makefile 2008-08-12 02:40:48.000000000 +0200
+++ lua-5.1.4-new/Makefile 2012-02-23 19:06:32.000000000 +0100
@@ -53,7 +53,7 @@
all: $(PLAT)
$(PLATS) clean:
- cd src && $(MAKE) $@
+ cd src && $(MAKE) $@ V=$(V) R=$(R)
test: dummy
src/lua test/hello.lua

View File

@@ -1,206 +1,72 @@
{
"app-id" : "org.gtk.Demo4",
"runtime" : "org.gnome.Platform",
"runtime-version" : "master",
"sdk" : "org.gnome.Sdk",
"command" : "gtk4-demo",
"tags" : [
"devel",
"development",
"nightly"
],
"desktop-file-name-prefix" : "(Development) ",
"finish-args" : [
"app-id": "org.gtk.Demo4",
"runtime": "org.gnome.Platform",
"runtime-version": "master",
"sdk": "org.gnome.Sdk",
"command": "gtk4-demo",
"tags": ["devel", "development", "nightly"],
"desktop-file-name-prefix": "(Development) ",
"finish-args": [
"--device=dri",
"--share=ipc",
"--socket=fallback-x11",
"--socket=wayland",
"--talk-name=org.gtk.vfs",
"--talk-name=org.gtk.vfs.*"
"--talk-name=org.gtk.vfs", "--talk-name=org.gtk.vfs.*"
],
"cleanup" : [
"cleanup": [
"/include",
"/lib/pkgconfig",
"/share/pkgconfig",
"/lib/pkgconfig", "/share/pkgconfig",
"/share/aclocal",
"/man",
"/share/man",
"/share/gtk-doc",
"*.la",
".a",
"/man", "/share/man", "/share/gtk-doc",
"*.la", ".a",
"/lib/girepository-1.0",
"/share/gir-1.0",
"/share/doc"
],
"modules" : [
"modules": [
{
"name" : "wayland",
"buildsystem" : "meson",
"buildsystem" : "autotools",
"builddir" : true,
"config-opts" : [
"-Ddocumentation=false"
"--disable-documentation"
],
"sources" : [
{
"type" : "git",
"url" : "https://gitlab.freedesktop.org/wayland/wayland.git",
"branch" : "main"
"url" : "https://github.com/wayland-project/wayland.git"
}
]
},
{
"name" : "graphene",
"buildsystem" : "meson",
"builddir" : true,
"config-opts" : [
"name": "graphene",
"buildsystem": "meson",
"builddir": true,
"config-opts": [
"--libdir=/app/lib",
"-Dtests=false"
],
"sources" : [
{
"type" : "git",
"url" : "https://github.com/ebassi/graphene.git"
}
]
},
{
"name" : "libsass",
"buildsystem" : "meson",
"builddir" : true,
"config-opts" : [
"--libdir=/app/lib"
],
"sources" : [
{
"type" : "git",
"url" : "https://github.com/lazka/libsass.git",
"branch" : "meson"
}
]
},
{
"name" : "sassc",
"buildsystem" : "meson",
"builddir" : true,
"config-opts" : [
"--libdir=/app/lib"
],
"sources" : [
{
"type" : "git",
"url" : "https://github.com/lazka/sassc.git",
"branch" : "meson"
}
]
},
{
"name": "boost",
"buildsystem": "simple",
"build-commands": [
"./bootstrap.sh --prefix=/app --with-libraries=date_time,filesystem,iostreams,locale,regex,system,thread,python,program_options,test,serialization",
"./b2 --build-type=minimal link=shared -j $FLATPAK_BUILDER_N_JOBS",
"./b2 --build-type=minimal link=shared install"
],
"sources": [
{
"type": "archive",
"url": "https://boostorg.jfrog.io/artifactory/main/release/1.79.0/source/boost_1_79_0.tar.bz2",
"sha256": "475d589d51a7f8b3ba2ba4eda022b170e562ca3b760ee922c146b6c65856ef39"
}
]
},
{
"name": "lua-5.1",
"buildsystem": "simple",
"build-commands": [
"make -j $FLATPAK_BUILDER_N_JOBS CFLAGS=\"$CFLAGS -fPIC -DLUA_USE_LINUX\" linux",
"make INSTALL_TOP=$FLATPAK_DEST TO_LIB='liblua.a liblua.so.5.1.5' install",
"ln -sf liblua.so.5.1.5 $FLATPAK_DEST/lib/liblua.so",
"ln -sf liblua.so.5.1.5 $FLATPAK_DEST/lib/liblua.so.5.1",
"install -Dm0644 etc/lua.pc $FLATPAK_DEST/lib/pkgconfig/lua.pc",
"ln -sf lua.pc $FLATPAK_DEST/lib/pkgconfig/lua51.pc",
"ln -sf lua.pc $FLATPAK_DEST/lib/pkgconfig/lua5.1.pc",
"ln -sf lua.pc $FLATPAK_DEST/lib/pkgconfig/lua-5.1.pc"
"-Dtests=false",
"-Dbenchmarks=false"
],
"sources": [
{
"type": "archive",
"url": "https://www.lua.org/ftp/lua-5.1.5.tar.gz",
"sha256": "2640fc56a795f29d28ef15e13c34a47e223960b0240e8cb0a82d9b0738695333"
},
{
"type": "patch",
"path": "lua-5.1.5-so.patch"
},
{
"type": "shell",
"commands": [
"sed -i \"s|/usr/local|$FLATPAK_DEST|\" etc/lua.pc src/luaconf.h"
]
}
],
"cleanup": [
"*.a",
"/bin",
"/include",
"/lib/pkgconfig",
"/man"
]
},
{
"name" : "highlight",
"buildsystem" : "simple",
"builddir" : true,
"build-commands" : [
"sed -i -e 's#^PREFIX = /usr#PREFIX = /app#' makefile",
"make",
"make install"
],
"sources" : [
{
"type" : "archive",
"url" : "http://www.andre-simon.de/zip/highlight-4.0.tar.bz2",
"sha256" : "f40dcba26e011a2c67df874f4d9b0238c2c6b065163ce8de3d8371b9dfce864d"
"type": "git",
"url": "https://github.com/ebassi/graphene.git"
}
]
},
{
"name" : "pango",
"buildsystem" : "meson",
"builddir" : true,
"config-opts" : [
"name": "gtk",
"buildsystem": "meson",
"builddir": true,
"config-opts": [
"--libdir=/app/lib"
],
"sources" : [
"sources": [
{
"type" : "git",
"url" : "https://gitlab.gnome.org/GNOME/pango.git",
"branch" : "main"
}
]
},
{
"name" : "gtk",
"buildsystem" : "meson",
"builddir" : true,
"config-opts" : [
"--libdir=/app/lib",
"-Dvulkan=disabled",
"-Dbuildtype=debugoptimized",
"-Ddemo-profile=devel"
],
"sources" : [
{
"type" : "git",
"url" : "https://gitlab.gnome.org/GNOME/gtk.git",
"branch" : "main"
"type": "git",
"url": "https://gitlab.gnome.org/GNOME/gtk.git"
}
]
}
],
"build-options" : {
"env" : {
"GSK_RENDERER" : "opengl"
}
}
]
}

View File

@@ -1,134 +1,72 @@
{
"app-id" : "org.gtk.IconBrowser4",
"runtime" : "org.gnome.Platform",
"runtime-version" : "master",
"sdk" : "org.gnome.Sdk",
"command" : "gtk4-icon-browser",
"tags" : [
"devel",
"development",
"nightly"
],
"desktop-file-name-prefix" : "(Development) ",
"finish-args" : [
"app-id": "org.gtk.IconBrowser4",
"runtime": "org.gnome.Platform",
"runtime-version": "master",
"sdk": "org.gnome.Sdk",
"command": "gtk4-icon-browser",
"tags": ["devel", "development", "nightly"],
"desktop-file-name-prefix": "(Development) ",
"finish-args": [
"--device=dri",
"--share=ipc",
"--socket=fallback-x11",
"--socket=wayland",
"--talk-name=org.gtk.vfs",
"--talk-name=org.gtk.vfs.*"
"--talk-name=org.gtk.vfs", "--talk-name=org.gtk.vfs.*"
],
"cleanup" : [
"cleanup": [
"/include",
"/lib/pkgconfig",
"/share/pkgconfig",
"/lib/pkgconfig", "/share/pkgconfig",
"/share/aclocal",
"/man",
"/share/man",
"/share/gtk-doc",
"*.la",
".a",
"/man", "/share/man", "/share/gtk-doc",
"*.la", ".a",
"/lib/girepository-1.0",
"/share/gir-1.0",
"/share/doc"
],
"modules" : [
"modules": [
{
"name" : "wayland",
"buildsystem" : "meson",
"buildsystem" : "autotools",
"builddir" : true,
"config-opts" : [
"-Ddocumentation=false"
"--disable-documentation"
],
"sources" : [
{
"type" : "git",
"url" : "https://gitlab.freedesktop.org/wayland/wayland.git",
"branch" : "main"
"url" : "https://github.com/wayland-project/wayland.git"
}
]
},
{
"name" : "graphene",
"buildsystem" : "meson",
"builddir" : true,
"config-opts" : [
"name": "graphene",
"buildsystem": "meson",
"builddir": true,
"config-opts": [
"--libdir=/app/lib",
"-Dtests=false"
"-Dtests=false",
"-Dbenchmarks=false"
],
"sources" : [
"sources": [
{
"type" : "git",
"url" : "https://github.com/ebassi/graphene.git"
"type": "git",
"url": "https://github.com/ebassi/graphene.git"
}
]
},
{
"name" : "libsass",
"buildsystem" : "meson",
"builddir" : true,
"config-opts" : [
"name": "gtk",
"buildsystem": "meson",
"builddir": true,
"config-opts": [
"--libdir=/app/lib"
],
"sources" : [
"sources": [
{
"type" : "git",
"url" : "https://github.com/lazka/libsass.git",
"branch" : "meson"
}
]
},
{
"name" : "sassc",
"buildsystem" : "meson",
"builddir" : true,
"config-opts" : [
"--libdir=/app/lib"
],
"sources" : [
{
"type" : "git",
"url" : "https://github.com/lazka/sassc.git",
"branch" : "meson"
}
]
},
{
"name" : "pango",
"buildsystem" : "meson",
"builddir" : true,
"config-opts" : [
"--libdir=/app/lib"
],
"sources" : [
{
"type" : "git",
"url" : "https://gitlab.gnome.org/GNOME/pango.git",
"branch" : "main"
}
]
},
{
"name" : "gtk",
"buildsystem" : "meson",
"builddir" : true,
"config-opts" : [
"--libdir=/app/lib",
"-Dvulkan=disabled",
"-Dbuildtype=debugoptimized",
"-Ddemo-profile=devel"
],
"sources" : [
{
"type" : "git",
"url" : "https://gitlab.gnome.org/GNOME/gtk.git",
"branch" : "main"
"type": "git",
"url": "https://gitlab.gnome.org/GNOME/gtk.git"
}
]
}
],
"build-options" : {
"env" : {
}
}
]
}

View File

@@ -1,138 +1,72 @@
{
"app-id" : "org.gtk.WidgetFactory4",
"runtime" : "org.gnome.Platform",
"runtime-version" : "master",
"sdk" : "org.gnome.Sdk",
"command" : "gtk4-widget-factory",
"tags" : [
"devel",
"development",
"nightly"
],
"desktop-file-name-prefix" : "(Development) ",
"finish-args" : [
"app-id": "org.gtk.WidgetFactory4",
"runtime": "org.gnome.Platform",
"runtime-version": "master",
"sdk": "org.gnome.Sdk",
"command": "gtk4-widget-factory",
"tags": ["devel", "development", "nightly"],
"desktop-file-name-prefix": "(Development) ",
"finish-args": [
"--device=dri",
"--share=ipc",
"--socket=fallback-x11",
"--socket=wayland",
"--talk-name=org.gtk.vfs",
"--talk-name=org.gtk.vfs.*"
"--talk-name=org.gtk.vfs", "--talk-name=org.gtk.vfs.*"
],
"cleanup" : [
"cleanup": [
"/include",
"/lib/pkgconfig",
"/share/pkgconfig",
"/lib/pkgconfig", "/share/pkgconfig",
"/share/aclocal",
"/man",
"/share/man",
"/share/gtk-doc",
"*.la",
".a",
"/man", "/share/man", "/share/gtk-doc",
"*.la", ".a",
"/lib/girepository-1.0",
"/share/gir-1.0",
"/share/doc"
],
"modules" : [
"modules": [
{
"name" : "wayland",
"buildsystem" : "meson",
"buildsystem" : "autotools",
"builddir" : true,
"config-opts" : [
"-Ddocumentation=false"
"--disable-documentation"
],
"sources" : [
{
"type" : "git",
"url" : "https://gitlab.freedesktop.org/wayland/wayland.git",
"branch" : "main"
"url" : "https://github.com/wayland-project/wayland.git"
}
]
},
{
"name" : "graphene",
"buildsystem" : "meson",
"builddir" : true,
"config-opts" : [
"name": "graphene",
"buildsystem": "meson",
"builddir": true,
"config-opts": [
"--libdir=/app/lib",
"-Dtests=false"
"-Dtests=false",
"-Dbenchmarks=false"
],
"sources" : [
"sources": [
{
"type" : "git",
"url" : "https://github.com/ebassi/graphene.git"
"type": "git",
"url": "https://github.com/ebassi/graphene.git"
}
]
},
{
"name" : "libsass",
"buildsystem" : "meson",
"builddir" : true,
"config-opts" : [
"name": "gtk",
"buildsystem": "meson",
"builddir": true,
"config-opts": [
"--libdir=/app/lib"
],
"sources" : [
"sources": [
{
"type" : "git",
"url" : "https://github.com/lazka/libsass.git",
"branch" : "meson"
}
]
},
{
"name" : "sassc",
"buildsystem" : "meson",
"builddir" : true,
"config-opts" : [
"--libdir=/app/lib"
],
"sources" : [
{
"type" : "git",
"url" : "https://github.com/lazka/sassc.git",
"branch" : "meson"
}
]
},
{
"name" : "pango",
"buildsystem" : "meson",
"builddir" : true,
"config-opts" : [
"--libdir=/app/lib"
],
"sources" : [
{
"type" : "git",
"url" : "https://gitlab.gnome.org/GNOME/pango.git",
"branch" : "main"
}
]
},
{
"name" : "gtk",
"buildsystem" : "meson",
"builddir" : true,
"config-opts" : [
"--libdir=/app/lib",
"-Dvulkan=disabled",
"-Dbuildtype=debugoptimized",
"-Ddemo-profile=devel"
],
"sources" : [
{
"type" : "git",
"url" : "https://gitlab.gnome.org/GNOME/gtk.git",
"branch" : "main"
"type": "git",
"url": "https://gitlab.gnome.org/GNOME/gtk.git"
}
]
}
],
"build-options" : {
"env" : {
"DBUS_SESSION_BUS_ADDRESS" : "''",
"GSK_RENDERER" : "opengl",
"GDK_DEBUG" : "vulkan-disable",
"G_ENABLE_DEBUG" : "true"
}
}
]
}

View File

@@ -1,138 +0,0 @@
{
"app-id" : "org.gtk.gtk4.NodeEditor",
"runtime" : "org.gnome.Platform",
"runtime-version" : "master",
"sdk" : "org.gnome.Sdk",
"command" : "gtk4-node-editor",
"tags" : [
"devel",
"development",
"nightly"
],
"desktop-file-name-prefix" : "(Development) ",
"finish-args" : [
"--device=dri",
"--share=ipc",
"--socket=fallback-x11",
"--socket=wayland",
"--talk-name=org.gtk.vfs",
"--talk-name=org.gtk.vfs.*"
],
"cleanup" : [
"/include",
"/lib/pkgconfig",
"/share/pkgconfig",
"/share/aclocal",
"/man",
"/share/man",
"/share/gtk-doc",
"*.la",
".a",
"/lib/girepository-1.0",
"/share/gir-1.0",
"/share/doc"
],
"modules" : [
{
"name" : "wayland",
"buildsystem" : "meson",
"builddir" : true,
"config-opts" : [
"-Ddocumentation=false"
],
"sources" : [
{
"type" : "git",
"url" : "https://gitlab.freedesktop.org/wayland/wayland.git",
"branch" : "main"
}
]
},
{
"name" : "graphene",
"buildsystem" : "meson",
"builddir" : true,
"config-opts" : [
"--libdir=/app/lib",
"-Dtests=false"
],
"sources" : [
{
"type" : "git",
"url" : "https://github.com/ebassi/graphene.git"
}
]
},
{
"name" : "libsass",
"buildsystem" : "meson",
"builddir" : true,
"config-opts" : [
"--libdir=/app/lib"
],
"sources" : [
{
"type" : "git",
"url" : "https://github.com/lazka/libsass.git",
"branch" : "meson"
}
]
},
{
"name" : "sassc",
"buildsystem" : "meson",
"builddir" : true,
"config-opts" : [
"--libdir=/app/lib"
],
"sources" : [
{
"type" : "git",
"url" : "https://github.com/lazka/sassc.git",
"branch" : "meson"
}
]
},
{
"name" : "pango",
"buildsystem" : "meson",
"builddir" : true,
"config-opts" : [
"--libdir=/app/lib"
],
"sources" : [
{
"type" : "git",
"url" : "https://gitlab.gnome.org/GNOME/pango.git",
"branch" : "main"
}
]
},
{
"name" : "gtk",
"buildsystem" : "meson",
"builddir" : true,
"config-opts" : [
"--libdir=/app/lib",
"-Dvulkan=disabled",
"-Dbuildtype=debugoptimized",
"-Ddemo-profile=devel"
],
"sources" : [
{
"type" : "git",
"url" : "https://gitlab.gnome.org/GNOME/gtk.git",
"branch" : "main"
}
]
}
],
"build-options" : {
"env" : {
"DBUS_SESSION_BUS_ADDRESS" : "''",
"GSK_RENDERER" : "opengl",
"GDK_DEBUG" : "vulkan-disable",
"G_ENABLE_DEBUG" : "true"
}
}
}

View File

@@ -1,39 +0,0 @@
#!/usr/bin/env python3
import os
import shutil
import subprocess
from pathlib import PurePath
stylesheets = [
'gtk/theme/Default/Default-light.css',
'gtk/theme/Default/Default-dark.css',
'gtk/theme/Default/Default-hc.css',
'gtk/theme/Default/Default-hc-dark.css',
]
references = [
'docs/reference/gtk/gtk4',
'docs/reference/gsk/gsk4',
'docs/reference/gdk/gdk4',
'docs/reference/gdk/gdk4-wayland',
'docs/reference/gdk/gdk4-x11',
]
sourceroot = os.environ.get('MESON_SOURCE_ROOT')
buildroot = os.environ.get('MESON_BUILD_ROOT')
distroot = os.environ.get('MESON_DIST_ROOT')
for stylesheet in stylesheets:
stylesheet_path = PurePath(stylesheet)
src = PurePath(sourceroot, stylesheet_path.with_suffix('.scss'))
dst = PurePath(distroot, stylesheet_path)
subprocess.call(['sassc', '-a', '-M', '-t', 'compact', src, dst])
for reference in references:
src_path = os.path.join(buildroot, reference)
if os.path.isdir(src_path):
dst_path = os.path.join(distroot, reference)
shutil.copytree(src_path, dst_path)

View File

@@ -1,26 +0,0 @@
#!/usr/bin/env python3
import os
import subprocess
import sys
repodir = sys.argv[1]
profile = sys.argv[2]
sys.stdout.write("/* This file is auto-generated. Do not edit. */\n")
sys.stdout.write("#pragma once\n")
sys.stdout.write("\n")
sys.stdout.write(f"#define PROFILE \"{profile}\"\n")
short_sha = os.environ.get('CI_COMMIT_SHORT_SHA')
if short_sha is None:
cmd = ["git", "-C", repodir, "rev-parse", "--short", "HEAD"]
try:
with subprocess.Popen(cmd, stdout=subprocess.PIPE) as p:
short_sha = p.stdout.read().decode('utf-8').rstrip("\n")
except FileNotFoundError:
short_sha = ''
if profile != 'default':
short_sha = 'devel'
sys.stdout.write(f"#define VCS_TAG \"{short_sha}\"\n")

View File

@@ -1,201 +0,0 @@
#!/usr/bin/env python3
#
# SPDX-FileCopyrightText: 2022 Collabora Inc.
# 2023 Emmanuele Bassi
#
# SPDX-License-Identifier: LGPL-2.1-or-later
#
# Original author: Xavier Claessens <xclaesse@gmail.com>
import argparse
import textwrap
from pathlib import Path
# Disable line length warnings as wrapping the C code templates would be hard
# flake8: noqa: E501
def gen_versions_macros(args, current_major_version, current_minor_version, current_micro_version):
with args.out_path.open("w", encoding="utf-8") as ofile, args.in_path.open(
"r", encoding="utf-8"
) as ifile:
for line in ifile.readlines():
if "@GDK_VERSIONS@" in line:
ofile.write(
textwrap.dedent(
f"""\
/**
* GDK_MAJOR_VERSION:
*
* The major version component of the library's version, e.g. "1" for "1.2.3".
*/
#define GDK_MAJOR_VERSION ({current_major_version})
/**
* GDK_MINOR_VERSION:
*
* The minor version component of the library's version, e.g. "2" for "1.2.3".
*/
#define GDK_MINOR_VERSION ({current_minor_version})
/**
* GDK_MICRO_VERSION:
*
* The micro version component of the library's version, e.g. "3" for "1.2.3".
*/
#define GDK_MICRO_VERSION ({current_micro_version})
"""
)
)
for minor in range(0, current_minor_version + 2, 2):
ofile.write(
textwrap.dedent(
f"""\
/**
* GDK_VERSION_{current_major_version}_{minor}:
*
* A macro that evaluates to the {current_major_version}.{minor} version of GTK, in a format
* that can be used by the C pre-processor.
*
* Since: {current_major_version}.{minor}
*/
#define GDK_VERSION_{current_major_version}_{minor} (G_ENCODE_VERSION ({current_major_version}, {minor}))
"""
)
)
else:
ofile.write(line)
def gen_visibility_macros(args, current_major_version, current_minor_version, current_micro_version):
"""
Generates a set of macros for each minor stable version of GTK
- GDK_DEPRECATED
- GDK_DEPRECATED_IN_…
- GDK_DEPRECATED_MACRO_IN_…
- GDK_DEPRECATED_ENUMERATOR_IN_…
- GDK_DEPRECATED_TYPE_IN_…
- GDK_AVAILABLE_IN_ALL
- GDK_AVAILABLE_IN_…
- GDK_AVAILABLE_STATIC_INLINE_IN_…
- GDK_AVAILABLE_MACRO_IN_…
- GDK_AVAILABLE_ENUMERATOR_IN_…
- GDK_AVAILABLE_TYPE_IN_…
- GDK_UNAVAILABLE(maj,min)
- GDK_UNAVAILABLE_STATIC_INLINE(maj,min)
"""
ns = args.namespace
with args.out_path.open("w", encoding="utf-8") as f:
f.write(
textwrap.dedent(
f"""\
#pragma once
#if (defined(_WIN32) || defined(__CYGWIN__)) && !defined({ns}_STATIC_COMPILATION)
# define _{ns}_EXPORT __declspec(dllexport)
# define _{ns}_IMPORT __declspec(dllimport)
#elif __GNUC__ >= 4
# define _{ns}_EXPORT __attribute__((visibility("default")))
# define _{ns}_IMPORT
#else
# define _{ns}_EXPORT
# define _{ns}_IMPORT
#endif
#ifdef GTK_COMPILATION
# define _{ns}_API _{ns}_EXPORT
#else
# define _{ns}_API _{ns}_IMPORT
#endif
#define _{ns}_EXTERN _{ns}_API extern
#define {ns}_VAR _{ns}_EXTERN
#define {ns}_AVAILABLE_IN_ALL _{ns}_EXTERN
#ifdef GDK_DISABLE_DEPRECATION_WARNINGS
#define {ns}_DEPRECATED _{ns}_EXTERN
#define {ns}_DEPRECATED_FOR(f) _{ns}_EXTERN
#define {ns}_UNAVAILABLE(maj,min) _{ns}_EXTERN
#define {ns}_UNAVAILABLE_STATIC_INLINE(maj,min)
#else
#define {ns}_DEPRECATED G_DEPRECATED _{ns}_EXTERN
#define {ns}_DEPRECATED_FOR(f) G_DEPRECATED_FOR(f) _{ns}_EXTERN
#define {ns}_UNAVAILABLE(maj,min) G_UNAVAILABLE(maj,min) _{ns}_EXTERN
#define {ns}_UNAVAILABLE_STATIC_INLINE(maj,min) G_UNAVAILABLE(maj,min)
#endif
"""
)
)
for minor in range(0, current_minor_version + 2, 2):
f.write(
textwrap.dedent(
f"""
#if GDK_VERSION_MIN_REQUIRED >= GDK_VERSION_4_{minor}
#define {ns}_DEPRECATED_IN_{current_major_version}_{minor} {ns}_DEPRECATED
#define {ns}_DEPRECATED_IN_{current_major_version}_{minor}_FOR(f) {ns}_DEPRECATED_FOR (f)
#define {ns}_DEPRECATED_MACRO_IN_{current_major_version}_{minor} GDK_DEPRECATED_MACRO
#define {ns}_DEPRECATED_MACRO_IN_{current_major_version}_{minor}_FOR(f) GDK_DEPRECATED_MACRO_FOR (f)
#define {ns}_DEPRECATED_ENUMERATOR_IN_{current_major_version}_{minor} GDK_DEPRECATED_ENUMERATOR
#define {ns}_DEPRECATED_ENUMERATOR_IN_{current_major_version}_{minor}_FOR(f) GDK_DEPRECATED_ENUMERATOR_FOR (f)
#define {ns}_DEPRECATED_TYPE_IN_{current_major_version}_{minor} GDK_DEPRECATED_TYPE
#define {ns}_DEPRECATED_TYPE_IN_{current_major_version}_{minor}_FOR(f) GDK_DEPRECATED_TYPE_FOR (f)
#else
#define {ns}_DEPRECATED_IN_{current_major_version}_{minor} _{ns}_EXTERN
#define {ns}_DEPRECATED_IN_{current_major_version}_{minor}_FOR(f) _{ns}_EXTERN
#define {ns}_DEPRECATED_MACRO_IN_{current_major_version}_{minor}
#define {ns}_DEPRECATED_MACRO_IN_{current_major_version}_{minor}_FOR(f)
#define {ns}_DEPRECATED_ENUMERATOR_IN_{current_major_version}_{minor}
#define {ns}_DEPRECATED_ENUMERATOR_IN_{current_major_version}_{minor}_FOR(f)
#define {ns}_DEPRECATED_TYPE_IN_{current_major_version}_{minor}
#define {ns}_DEPRECATED_TYPE_IN_{current_major_version}_{minor}_FOR(f)
#endif
#if GDK_VERSION_MAX_ALLOWED < GDK_VERSION_{current_major_version}_{minor}
#define {ns}_AVAILABLE_IN_{current_major_version}_{minor} {ns}_UNAVAILABLE ({current_major_version}, {minor})
#define {ns}_AVAILABLE_STATIC_INLINE_IN_{current_major_version}_{minor} GDK_UNAVAILABLE_STATIC_INLINE ({current_major_version}, {minor})
#define {ns}_AVAILABLE_MACRO_IN_{current_major_version}_{minor} GDK_UNAVAILABLE_MACRO ({current_major_version}, {minor})
#define {ns}_AVAILABLE_ENUMERATOR_IN_{current_major_version}_{minor} GDK_UNAVAILABLE_ENUMERATOR ({current_major_version}, {minor})
#define {ns}_AVAILABLE_TYPE_IN_{current_major_version}_{minor} GDK_UNAVAILABLE_TYPE ({current_major_version}, {minor})
#else
#define {ns}_AVAILABLE_IN_{current_major_version}_{minor} _{ns}_EXTERN
#define {ns}_AVAILABLE_STATIC_INLINE_IN_{current_major_version}_{minor}
#define {ns}_AVAILABLE_MACRO_IN_{current_major_version}_{minor}
#define {ns}_AVAILABLE_ENUMERATOR_IN_{current_major_version}_{minor}
#define {ns}_AVAILABLE_TYPE_IN_{current_major_version}_{minor}
#endif
"""
)
)
def main():
parser = argparse.ArgumentParser()
parser.add_argument("gtk_version", help="Current GLib version")
subparsers = parser.add_subparsers()
versions_parser = subparsers.add_parser(
"versions-macros", help="Generate versions macros"
)
versions_parser.add_argument("in_path", help="input file", type=Path)
versions_parser.add_argument("out_path", help="output file", type=Path)
versions_parser.set_defaults(func=gen_versions_macros)
visibility_parser = subparsers.add_parser(
"visibility-macros", help="Generate visibility macros"
)
visibility_parser.add_argument("namespace", help="Macro namespace")
visibility_parser.add_argument("out_path", help="output file", type=Path)
visibility_parser.set_defaults(func=gen_visibility_macros)
args = parser.parse_args()
version = [int(i) for i in args.gtk_version.split(".")]
args.func(args, version[0], version[1], version[2])
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,31 @@
#!/usr/bin/env python3
import os
import sys
import subprocess
if 'DESTDIR' not in os.environ:
gtk_api_version = sys.argv[1]
gtk_abi_version = sys.argv[2]
gtk_libdir = sys.argv[3]
gtk_datadir = sys.argv[4]
gtk_moduledir = os.path.join(gtk_libdir, 'gtk-' + gtk_api_version, gtk_abi_version)
gtk_printmodule_dir = os.path.join(gtk_moduledir, 'printbackends')
gtk_immodule_dir = os.path.join(gtk_moduledir, 'immodules')
print('Compiling GSettings schemas...')
subprocess.call(['glib-compile-schemas',
os.path.join(gtk_datadir, 'glib-2.0', 'schemas')])
print('Updating icon cache...')
subprocess.call(['gtk4-update-icon-cache', '-q', '-t' ,'-f',
os.path.join(gtk_datadir, 'icons', 'hicolor')])
print('Updating module cache for print backends...')
os.makedirs(gtk_printmodule_dir, exist_ok=True)
subprocess.call(['gio-querymodules', gtk_printmodule_dir])
print('Updating module cache for input methods...')
os.makedirs(gtk_immodule_dir, exist_ok=True)
subprocess.call(['gio-querymodules', gtk_immodule_dir])

306
config.h.meson Normal file
View File

@@ -0,0 +1,306 @@
/* config.h.in. Generated from configure.ac by autoheader. */
/* always defined to indicate that i18n is enabled */
#define ENABLE_NLS 1
/* The prefix for our gettext translation domains. */
#mesondefine GETTEXT_PACKAGE
/* Disable deprecation warnings from glib */
#mesondefine GLIB_DISABLE_DEPRECATION_WARNINGS
/* Define the location where the catalogs will be installed */
#mesondefine GTK_LOCALEDIR
/* Define to 1 if you have the `bind_textdomain_codeset' function. */
#mesondefine HAVE_BIND_TEXTDOMAIN_CODESET
/* Have the cloudproviders library */
#mesondefine HAVE_CLOUDPROVIDERS
/* define if we have colord */
#mesondefine HAVE_COLORD
/* Define to 1 if you have the <crt_externs.h> header file. */
#mesondefine HAVE_CRT_EXTERNS_H
/* Define to 1 if you have the `dcgettext' function. */
#mesondefine HAVE_DCGETTEXT
/* Define to 1 if you have the declaration of `isinf', and to 0 if you don't.
*/
#mesondefine HAVE_DECL_ISINF
/* Define to 1 if you have the declaration of `isnan', and to 0 if you don't.
*/
#mesondefine HAVE_DECL_ISNAN
/* Define to 1 if you have the <dlfcn.h> header file. */
#mesondefine HAVE_DLFCN_H
/* Have the ffmpeg library */
#mesondefine HAVE_FFMPEG
/* Define to 1 if you have the <ftw.h> header file. */
#mesondefine HAVE_FTW_H
/* Define to 1 if you have the `getpagesize' function. */
#mesondefine HAVE_GETPAGESIZE
/* Define to 1 if you have the `getresuid' function. */
#mesondefine HAVE_GETRESUID
/* Define if gio-unix is available */
#mesondefine HAVE_GIO_UNIX
/* Define if GStreamer support is available */
#mesondefine HAVE_GSTREAMER
/* Define to 1 if you have the `httpGetAuthString' function. */
#mesondefine HAVE_HTTPGETAUTHSTRING
/* Define if cups http_t authstring field is accessible */
#mesondefine HAVE_HTTP_AUTHSTRING
/* Define to 1 if you have the <inttypes.h> header file. */
#mesondefine HAVE_INTTYPES_H
/* Define to 1 if the system has the type `IPrintDialogCallback'. */
#mesondefine HAVE_IPRINTDIALOGCALLBACK
/* Define to 1 if you have the <locale.h> header file. */
#mesondefine HAVE_LOCALE_H
/* Define to 1 if you have the `lstat' function. */
#mesondefine HAVE_LSTAT
/* Define to 1 if you have the `mallinfo' function. */
#mesondefine HAVE_MALLINFO
/* Define to 1 if you have the <memory.h> header file. */
#mesondefine HAVE_MEMORY_H
/* Define to 1 if you have the `mkstemp' function. */
#mesondefine HAVE_MKSTEMP
/* Define to 1 if you have a working `mmap' system call. */
#mesondefine HAVE_MMAP
/* Define to 1 if you have the `nearbyint' function. */
#mesondefine HAVE_NEARBYINT
/* Define to 1 if you have the `posix_fallocate' function. */
#mesondefine HAVE_POSIX_FALLOCATE
/* Have the Xrandr extension library */
#mesondefine HAVE_RANDR
/* Have the Xrandr 1.5 extension library */
#mesondefine HAVE_RANDR15
/* Define to 1 if you have the `rint' function. */
#mesondefine HAVE_RINT
/* Define to 1 if you have the `round' function. */
#mesondefine HAVE_ROUND
/* Define to 1 if you have the `sincos' function. */
#mesondefine HAVE_SINCOS
/* Define to 1 if you have the `log2` function */
#mesondefine HAVE_LOG2
/* Define to 1 if you ahve the `exp2` function */
#mesondefine HAVE_EXP2
/* Define to 1 if you have the <stdint.h> header file. */
#mesondefine HAVE_STDINT_H
/* Define to 1 if you have the <stdlib.h> header file. */
#mesondefine HAVE_STDLIB_H
/* Define to 1 if you have the <strings.h> header file. */
#mesondefine HAVE_STRINGS_H
/* Define to 1 if you have the <string.h> header file. */
#mesondefine HAVE_STRING_H
/* Define to 1 if you have the <sys/mman.h> header file. */
#mesondefine HAVE_SYS_MMAN_H
/* Define to 1 if you have the <sys/param.h> header file. */
#mesondefine HAVE_SYS_PARAM_H
/* Have the sysprof-capture library */
#mesondefine HAVE_SYSPROF_CAPTURE
/* Define to 1 if you have the <sys/stat.h> header file. */
#mesondefine HAVE_SYS_STAT_H
/* Define to 1 if you have the <sys/time.h> header file. */
#mesondefine HAVE_SYS_TIME_H
/* Define to 1 if you have the <sys/types.h> header file. */
#mesondefine HAVE_SYS_TYPES_H
/* Define to 1 if you have the <unistd.h> header file. */
#mesondefine HAVE_UNISTD_H
/* Have the XCOMPOSITE X extension */
#mesondefine HAVE_XCOMPOSITE
/* Have the Xcursor library */
#mesondefine HAVE_XCURSOR
/* Have the XDAMAGE X extension */
#mesondefine HAVE_XDAMAGE
/* Have the XFIXES X extension */
#mesondefine HAVE_XFIXES
/* Define to 1 if XFree Xinerama is available */
#mesondefine HAVE_XFREE_XINERAMA
/* Have XGenericEvent */
#mesondefine HAVE_XGENERICEVENTS
/* Define to use XKB extension */
#mesondefine HAVE_XKB
/* Have the SYNC extension library */
#mesondefine HAVE_XSYNC
/* Define to 1 if you have the `_lock_file' function */
#mesondefine HAVE__LOCK_FILE
/* Define to 1 if you have the `flockfile' function */
#mesondefine HAVE_FLOCKFILE
/* Define if _NL_MEASUREMENT_MEASUREMENT is available */
#mesondefine HAVE__NL_MEASUREMENT_MEASUREMENT
/* Define if _NL_PAPER_HEIGHT is available */
#mesondefine HAVE__NL_PAPER_HEIGHT
/* Define if _NL_PAPER_WIDTH is available */
#mesondefine HAVE__NL_PAPER_WIDTH
/* Define if _NL_TIME_FIRST_WEEKDAY is available */
#mesondefine HAVE__NL_TIME_FIRST_WEEKDAY
/* Define to the sub-directory where libtool stores uninstalled libraries. */
#mesondefine LT_OBJDIR
/* Define if <X11/extensions/XIproto.h> needed for xReply */
#mesondefine NEED_XIPROTO_H_FOR_XREPLY
/* Define to 1 if your C compiler doesn't accept -c and -o together. */
#mesondefine NO_MINUS_C_MINUS_O
/* Define to the address where bug reports for this package should be sent. */
#mesondefine PACKAGE_BUGREPORT
/* Define to the full name of this package. */
#mesondefine PACKAGE_NAME
/* Define to the full name and version of this package. */
#mesondefine PACKAGE_STRING
/* Define to the one symbol short name of this package. */
#mesondefine PACKAGE_TARNAME
/* Define to the home page for this package. */
#mesondefine PACKAGE_URL
/* Define to the version of this package. */
#mesondefine PACKAGE_VERSION
/* Use NSBundle functions to determine load paths for libraries, translations,
etc. */
#mesondefine QUARTZ_RELOCATION
/* Define to 1 if you have the ANSI C header files. */
#mesondefine STDC_HEADERS
/* Enable extensions on AIX 3, Interix. */
#ifndef _ALL_SOURCE
# undef _ALL_SOURCE
#endif
/* Enable GNU extensions on systems that have them. */
#ifndef _GNU_SOURCE
# undef _GNU_SOURCE
#endif
/* Enable threading extensions on Solaris. */
#ifndef _POSIX_PTHREAD_SEMANTICS
# undef _POSIX_PTHREAD_SEMANTICS
#endif
/* Enable extensions on HP NonStop. */
#ifndef _TANDEM_SOURCE
# undef _TANDEM_SOURCE
#endif
/* Enable general extensions on Solaris. */
#ifndef __EXTENSIONS__
# undef __EXTENSIONS__
#endif
/* Define to 1 if XInput 2.2 is available */
#mesondefine XINPUT_2_2
/* Define to 1 if the X Window System is missing or not being used. */
#mesondefine X_DISPLAY_MISSING
/* Enable large inode numbers on Mac OS X 10.5. */
#ifndef _DARWIN_USE_64_BIT_INODE
# define _DARWIN_USE_64_BIT_INODE 1
#endif
/* Number of bits in a file offset, on hosts where this is settable. */
#mesondefine _FILE_OFFSET_BITS
/* defines how to decorate public symbols while building */
#mesondefine _GDK_EXTERN
/* Define for large files, on AIX-style hosts. */
#mesondefine _LARGE_FILES
/* Define to 1 if on MINIX. */
#mesondefine _MINIX
/* Define to 2 if the system does not provide POSIX.1 features except with
this defined. */
#mesondefine _POSIX_1_SOURCE
/* Define to 1 if you need to in order for `stat' and other things to work. */
#mesondefine _POSIX_SOURCE
/* Define to `int' if <sys/types.h> doesn't define. */
#mesondefine gid_t
/* Define to `int' if <sys/types.h> doesn't define. */
#mesondefine uid_t
/* Define to 1 if linux/memfd.h exists */
#mesondefine HAVE_LINUX_MEMFD_H
#mesondefine HAVE_LINUX_INPUT_H
#mesondefine HAVE_DEV_EVDEV_INPUT_H
#mesondefine GTK_SYSCONFDIR
#mesondefine GTK_LOCALEDIR
#mesondefine GTK_DATADIR
#mesondefine GTK_LIBDIR
#mesondefine GTK_PRINT_BACKENDS
#mesondefine HAVE_CAIRO_SCRIPT_INTERPRETER
#mesondefine HAVE_HARFBUZZ
#mesondefine HAVE_PANGOFT
#mesondefine ISO_CODES_PREFIX

View File

@@ -1,115 +0,0 @@
/*
* Copyright © 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.1 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/>.
*
* Authors: Matthias Clasen
*/
#include "config.h"
#include "constraint-editor-application.h"
#include "constraint-editor-window.h"
struct _ConstraintEditorApplication
{
GtkApplication parent_instance;
};
G_DEFINE_TYPE(ConstraintEditorApplication, constraint_editor_application, GTK_TYPE_APPLICATION);
static void
constraint_editor_application_init (ConstraintEditorApplication *app)
{
}
static void
quit_activated (GSimpleAction *action,
GVariant *parameter,
gpointer data)
{
g_application_quit (G_APPLICATION (data));
}
static GActionEntry app_entries[] =
{
{ "quit", quit_activated, NULL, NULL, NULL }
};
static void
constraint_editor_application_startup (GApplication *app)
{
const char *quit_accels[2] = { "<Ctrl>Q", NULL };
const char *open_accels[2] = { "<Ctrl>O", NULL };
GtkCssProvider *provider;
G_APPLICATION_CLASS (constraint_editor_application_parent_class)->startup (app);
g_action_map_add_action_entries (G_ACTION_MAP (app),
app_entries, G_N_ELEMENTS (app_entries),
app);
gtk_application_set_accels_for_action (GTK_APPLICATION (app), "app.quit", quit_accels);
gtk_application_set_accels_for_action (GTK_APPLICATION (app), "win.open", open_accels);
provider = gtk_css_provider_new ();
gtk_css_provider_load_from_resource (provider, "/org/gtk/gtk4/constraint-editor/constraint-editor.css");
gtk_style_context_add_provider_for_display (gdk_display_get_default (),
GTK_STYLE_PROVIDER (provider),
GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
}
static void
constraint_editor_application_activate (GApplication *app)
{
ConstraintEditorWindow *win;
win = constraint_editor_window_new (CONSTRAINT_EDITOR_APPLICATION (app));
gtk_window_present (GTK_WINDOW (win));
}
static void
constraint_editor_application_open (GApplication *app,
GFile **files,
int n_files,
const char *hint)
{
ConstraintEditorWindow *win;
int i;
for (i = 0; i < n_files; i++)
{
win = constraint_editor_window_new (CONSTRAINT_EDITOR_APPLICATION (app));
constraint_editor_window_load (win, files[i]);
gtk_window_present (GTK_WINDOW (win));
}
}
static void
constraint_editor_application_class_init (ConstraintEditorApplicationClass *class)
{
GApplicationClass *application_class = G_APPLICATION_CLASS (class);
application_class->startup = constraint_editor_application_startup;
application_class->activate = constraint_editor_application_activate;
application_class->open = constraint_editor_application_open;
}
ConstraintEditorApplication *
constraint_editor_application_new (void)
{
return g_object_new (CONSTRAINT_EDITOR_APPLICATION_TYPE,
"application-id", "org.gtk.gtk4.ConstraintEditor",
"flags", G_APPLICATION_HANDLES_OPEN,
NULL);
}

View File

@@ -1,28 +0,0 @@
/*
* Copyright © 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.1 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/>.
*
* Authors: Matthias Clasen
*/
#pragma once
#include <gtk/gtk.h>
#define CONSTRAINT_EDITOR_APPLICATION_TYPE (constraint_editor_application_get_type ())
G_DECLARE_FINAL_TYPE (ConstraintEditorApplication, constraint_editor_application, CONSTRAINT, EDITOR_APPLICATION, GtkApplication)
ConstraintEditorApplication *constraint_editor_application_new (void);

View File

@@ -1,652 +0,0 @@
/*
* Copyright © 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.1 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/>.
*
* Authors: Matthias Clasen
*/
#include "config.h"
#include "constraint-editor-window.h"
#include "constraint-view.h"
#include "constraint-editor.h"
#include "guide-editor.h"
struct _ConstraintEditorWindow
{
GtkApplicationWindow parent_instance;
GtkWidget *paned;
GtkWidget *view;
GtkWidget *list;
};
G_DEFINE_TYPE(ConstraintEditorWindow, constraint_editor_window, GTK_TYPE_APPLICATION_WINDOW);
static GtkConstraintTarget *
find_target (GListModel *model,
GtkConstraintTarget *orig)
{
const char *name;
const char *model_name;
gpointer item;
int i;
if (orig == NULL)
return NULL;
if (GTK_IS_LABEL (orig))
name = gtk_label_get_label (GTK_LABEL (orig));
else if (GTK_IS_CONSTRAINT_GUIDE (orig))
name = gtk_constraint_guide_get_name (GTK_CONSTRAINT_GUIDE (orig));
else
{
g_warning ("Don't know how to handle %s targets", G_OBJECT_TYPE_NAME (orig));
return NULL;
}
for (i = 0; i < g_list_model_get_n_items (model); i++)
{
item = g_list_model_get_item (model, i);
g_object_unref (item);
if (GTK_IS_WIDGET (item))
model_name = gtk_widget_get_name (GTK_WIDGET (item));
else
model_name = gtk_constraint_guide_get_name (GTK_CONSTRAINT_GUIDE (item));
if (strcmp (name, model_name) == 0)
return GTK_CONSTRAINT_TARGET (item);
}
g_warning ("Failed to find target '%s'", name);
return NULL;
}
gboolean
constraint_editor_window_load (ConstraintEditorWindow *self,
GFile *file)
{
char *path;
GtkBuilder *builder;
GError *error = NULL;
GtkWidget *view;
GtkLayoutManager *layout;
GtkWidget *child;
const char *name;
gpointer item;
int i;
GListModel *list;
path = g_file_get_path (file);
builder = gtk_builder_new ();
if (!gtk_builder_add_from_file (builder, path, &error))
{
g_print ("Could not load %s: %s", path, error->message);
g_error_free (error);
g_free (path);
g_object_unref (builder);
return FALSE;
}
view = GTK_WIDGET (gtk_builder_get_object (builder, "view"));
if (!GTK_IS_BOX (view))
{
g_print ("Could not load %s: No GtkBox named 'view'", path);
g_free (path);
g_object_unref (builder);
return FALSE;
}
layout = gtk_widget_get_layout_manager (view);
if (!GTK_IS_CONSTRAINT_LAYOUT (layout))
{
g_print ("Could not load %s: Widget 'view' does not use GtkConstraintLayout", path);
g_free (path);
g_object_unref (builder);
return FALSE;
}
for (child = gtk_widget_get_first_child (view);
child;
child = gtk_widget_get_next_sibling (child))
{
if (!GTK_IS_LABEL (child))
{
g_print ("Skipping non-GtkLabel child\n");
continue;
}
name = gtk_label_get_label (GTK_LABEL (child));
constraint_view_add_child (CONSTRAINT_VIEW (self->view), name);
}
list = gtk_constraint_layout_observe_guides (GTK_CONSTRAINT_LAYOUT (layout));
for (i = 0; i < g_list_model_get_n_items (list); i++)
{
GtkConstraintGuide *guide, *clone;
int w, h;
item = g_list_model_get_item (list, i);
guide = GTK_CONSTRAINT_GUIDE (item);
/* need to clone here, to attach to the right targets */
clone = gtk_constraint_guide_new ();
gtk_constraint_guide_set_name (clone, gtk_constraint_guide_get_name (guide));
gtk_constraint_guide_set_strength (clone, gtk_constraint_guide_get_strength (guide));
gtk_constraint_guide_get_min_size (guide, &w, &h);
gtk_constraint_guide_set_min_size (clone, w, h);
gtk_constraint_guide_get_nat_size (guide, &w, &h);
gtk_constraint_guide_set_nat_size (clone, w, h);
gtk_constraint_guide_get_max_size (guide, &w, &h);
gtk_constraint_guide_set_max_size (clone, w, h);
constraint_view_add_guide (CONSTRAINT_VIEW (self->view), clone);
g_object_unref (guide);
g_object_unref (clone);
}
g_object_unref (list);
list = gtk_constraint_layout_observe_constraints (GTK_CONSTRAINT_LAYOUT (layout));
for (i = 0; i < g_list_model_get_n_items (list); i++)
{
GtkConstraint *constraint;
GtkConstraint *clone;
GtkConstraintTarget *target;
GtkConstraintTarget *source;
GtkConstraintAttribute source_attr;
item = g_list_model_get_item (list, i);
constraint = GTK_CONSTRAINT (item);
target = gtk_constraint_get_target (constraint);
source = gtk_constraint_get_source (constraint);
source_attr = gtk_constraint_get_source_attribute (constraint);
if (source == NULL && source_attr == GTK_CONSTRAINT_ATTRIBUTE_NONE)
clone = gtk_constraint_new_constant (find_target (constraint_view_get_model (CONSTRAINT_VIEW (self->view)), target),
gtk_constraint_get_target_attribute (constraint),
gtk_constraint_get_relation (constraint),
gtk_constraint_get_constant (constraint),
gtk_constraint_get_strength (constraint));
else
clone = gtk_constraint_new (find_target (constraint_view_get_model (CONSTRAINT_VIEW (self->view)), target),
gtk_constraint_get_target_attribute (constraint),
gtk_constraint_get_relation (constraint),
find_target (constraint_view_get_model (CONSTRAINT_VIEW (self->view)), source),
source_attr,
gtk_constraint_get_multiplier (constraint),
gtk_constraint_get_constant (constraint),
gtk_constraint_get_strength (constraint));
constraint_view_add_constraint (CONSTRAINT_VIEW (self->view), clone);
g_object_unref (constraint);
g_object_unref (clone);
}
g_object_unref (list);
g_free (path);
g_object_unref (builder);
return TRUE;
}
static void
open_response_cb (GObject *source,
GAsyncResult *result,
void *user_data)
{
GtkFileDialog *dialog = GTK_FILE_DIALOG (source);
ConstraintEditorWindow *self = user_data;
GFile *file;
file = gtk_file_dialog_open_finish (dialog, result, NULL);
if (file)
{
constraint_editor_window_load (self, file);
g_object_unref (file);
}
}
static void
open_cb (GtkWidget *button,
ConstraintEditorWindow *self)
{
GtkFileDialog *dialog;
GFile *cwd;
dialog = gtk_file_dialog_new ();
gtk_file_dialog_set_title (dialog, "Open file");
cwd = g_file_new_for_path (".");
gtk_file_dialog_set_initial_folder (dialog, cwd);
g_object_unref (cwd);
gtk_file_dialog_open (dialog, GTK_WINDOW (self), NULL, open_response_cb, self);
g_object_unref (dialog);
}
static void
serialize_child (GString *str,
int indent,
GtkWidget *child)
{
const char *name;
name = gtk_widget_get_name (child);
g_string_append_printf (str, "%*s<child>\n", indent, "");
g_string_append_printf (str, "%*s <object class=\"GtkLabel\" id=\"%s\">\n", indent, "", name);
g_string_append_printf (str, "%*s <property name=\"label\">%s</property>\n", indent, "", name);
g_string_append_printf (str, "%*s </object>\n", indent, "");
g_string_append_printf (str, "%*s</child>\n", indent, "");
}
static char *
serialize_model (GListModel *list)
{
GString *str = g_string_new ("");
int i;
g_string_append (str, "<interface>\n");
g_string_append (str, " <object class=\"GtkBox\" id=\"view\">\n");
g_string_append (str, " <property name=\"layout-manager\">\n");
g_string_append (str, " <object class=\"GtkConstraintLayout\">\n");
g_string_append (str, " <constraints>\n");
for (i = 0; i < g_list_model_get_n_items (list); i++)
{
gpointer item = g_list_model_get_item (list, i);
g_object_unref (item);
if (GTK_IS_CONSTRAINT (item))
constraint_editor_serialize_constraint (str, 10, GTK_CONSTRAINT (item));
else if (GTK_IS_CONSTRAINT_GUIDE (item))
guide_editor_serialize_guide (str, 10, GTK_CONSTRAINT_GUIDE (item));
}
g_string_append (str, " </constraints>\n");
g_string_append (str, " </object>\n");
g_string_append (str, " </property>\n");
for (i = 0; i < g_list_model_get_n_items (list); i++)
{
gpointer item = g_list_model_get_item (list, i);
g_object_unref (item);
if (GTK_IS_WIDGET (item))
serialize_child (str, 4, GTK_WIDGET (item));
}
g_string_append (str, " </object>\n");
g_string_append (str, "</interface>\n");
return g_string_free (str, FALSE);
}
static void
save_response_cb (GObject *source,
GAsyncResult *result,
void *user_data)
{
GtkFileDialog *dialog = GTK_FILE_DIALOG (source);
ConstraintEditorWindow *self = user_data;
GFile *file;
file = gtk_file_dialog_save_finish (dialog, result, NULL);
if (file)
{
GListModel *model;
char *text;
GError *error = NULL;
model = constraint_view_get_model (CONSTRAINT_VIEW (self->view));
text = serialize_model (model);
g_file_replace_contents (file, text, strlen (text),
NULL, FALSE,
G_FILE_CREATE_NONE,
NULL,
NULL,
&error);
if (error != NULL)
{
GtkAlertDialog *alert;
alert = gtk_alert_dialog_new ("Saving failed");
gtk_alert_dialog_set_detail (alert, error->message);
gtk_alert_dialog_show (alert,
GTK_WINDOW (gtk_widget_get_root (GTK_WIDGET (self))));
g_object_unref (alert);
g_error_free (error);
}
g_free (text);
g_object_unref (file);
}
}
static void
save_cb (GtkWidget *button,
ConstraintEditorWindow *self)
{
GtkFileDialog *dialog;
GFile *cwd;
dialog = gtk_file_dialog_new ();
gtk_file_dialog_set_title (dialog, "Save constraints");
cwd = g_file_new_for_path (".");
gtk_file_dialog_set_initial_folder (dialog, cwd);
g_object_unref (cwd);
gtk_file_dialog_save (dialog,
GTK_WINDOW (gtk_widget_get_root (GTK_WIDGET (button))),
NULL,
save_response_cb, self);
g_object_unref (dialog);
}
static void
constraint_editor_window_dispose (GObject *object)
{
gtk_widget_dispose_template (GTK_WIDGET (object), CONSTRAINT_EDITOR_WINDOW_TYPE);
G_OBJECT_CLASS (constraint_editor_window_parent_class)->dispose (object);
}
static int child_counter;
static int guide_counter;
static void
add_child (ConstraintEditorWindow *win)
{
char *name;
child_counter++;
name = g_strdup_printf ("Child %d", child_counter);
constraint_view_add_child (CONSTRAINT_VIEW (win->view), name);
g_free (name);
}
static void
add_guide (ConstraintEditorWindow *win)
{
char *name;
GtkConstraintGuide *guide;
guide_counter++;
name = g_strdup_printf ("Guide %d", guide_counter);
guide = gtk_constraint_guide_new ();
gtk_constraint_guide_set_name (guide, name);
g_free (name);
constraint_view_add_guide (CONSTRAINT_VIEW (win->view), guide);
}
static void
constraint_editor_done (ConstraintEditor *editor,
GtkConstraint *constraint,
ConstraintEditorWindow *win)
{
GtkConstraint *old_constraint;
g_object_get (editor, "constraint", &old_constraint, NULL);
if (old_constraint)
constraint_view_remove_constraint (CONSTRAINT_VIEW (win->view), old_constraint);
constraint_view_add_constraint (CONSTRAINT_VIEW (win->view), constraint);
g_clear_object (&old_constraint);
gtk_window_destroy (GTK_WINDOW (gtk_widget_get_ancestor (GTK_WIDGET (editor), GTK_TYPE_WINDOW)));
}
static void
edit_constraint (ConstraintEditorWindow *win,
GtkConstraint *constraint)
{
GtkWidget *window;
ConstraintEditor *editor;
GListModel *model;
window = gtk_window_new ();
gtk_window_set_transient_for (GTK_WINDOW (window), GTK_WINDOW (win));
gtk_window_set_resizable (GTK_WINDOW (window), FALSE);
if (constraint)
gtk_window_set_title (GTK_WINDOW (window), "Edit Constraint");
else
gtk_window_set_title (GTK_WINDOW (window), "Create Constraint");
model = constraint_view_get_model (CONSTRAINT_VIEW (win->view));
editor = constraint_editor_new (model, constraint);
gtk_window_set_child (GTK_WINDOW (window), GTK_WIDGET (editor));
g_signal_connect (editor, "done", G_CALLBACK (constraint_editor_done), win);
gtk_window_present (GTK_WINDOW (window));
}
static void
add_constraint (ConstraintEditorWindow *win)
{
edit_constraint (win, NULL);
}
static void
guide_editor_done (GuideEditor *editor,
GtkConstraintGuide *guide,
ConstraintEditorWindow *win)
{
gtk_window_destroy (GTK_WINDOW (gtk_widget_get_ancestor (GTK_WIDGET (editor), GTK_TYPE_WINDOW)));
}
static void
edit_guide (ConstraintEditorWindow *win,
GtkConstraintGuide *guide)
{
GtkWidget *window;
GuideEditor *editor;
window = gtk_window_new ();
gtk_window_set_resizable (GTK_WINDOW (window), FALSE);
gtk_window_set_transient_for (GTK_WINDOW (window), GTK_WINDOW (win));
gtk_window_set_title (GTK_WINDOW (window), "Edit Guide");
editor = guide_editor_new (guide);
gtk_window_set_child (GTK_WINDOW (window), GTK_WIDGET (editor));
g_signal_connect (editor, "done", G_CALLBACK (guide_editor_done), win);
gtk_window_present (GTK_WINDOW (window));
}
static void
row_activated (GtkListBox *list,
GtkListBoxRow *row,
ConstraintEditorWindow *win)
{
GObject *item;
item = G_OBJECT (g_object_get_data (G_OBJECT (row), "item"));
if (GTK_IS_CONSTRAINT (item))
edit_constraint (win, GTK_CONSTRAINT (item));
else if (GTK_IS_CONSTRAINT_GUIDE (item))
edit_guide (win, GTK_CONSTRAINT_GUIDE (item));
}
static void
constraint_editor_window_class_init (ConstraintEditorWindowClass *class)
{
GObjectClass *object_class = G_OBJECT_CLASS (class);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
g_type_ensure (CONSTRAINT_VIEW_TYPE);
object_class->dispose = constraint_editor_window_dispose;
gtk_widget_class_set_template_from_resource (widget_class,
"/org/gtk/gtk4/constraint-editor/constraint-editor-window.ui");
gtk_widget_class_bind_template_child (widget_class, ConstraintEditorWindow, paned);
gtk_widget_class_bind_template_child (widget_class, ConstraintEditorWindow, view);
gtk_widget_class_bind_template_child (widget_class, ConstraintEditorWindow, list);
gtk_widget_class_bind_template_callback (widget_class, open_cb);
gtk_widget_class_bind_template_callback (widget_class, save_cb);
gtk_widget_class_bind_template_callback (widget_class, add_child);
gtk_widget_class_bind_template_callback (widget_class, add_guide);
gtk_widget_class_bind_template_callback (widget_class, add_constraint);
gtk_widget_class_bind_template_callback (widget_class, row_activated);
}
static void
row_edit (GtkButton *button,
ConstraintEditorWindow *win)
{
GtkWidget *row;
GObject *item;
row = gtk_widget_get_ancestor (GTK_WIDGET (button), GTK_TYPE_LIST_BOX_ROW);
item = (GObject *)g_object_get_data (G_OBJECT (row), "item");
if (GTK_IS_CONSTRAINT (item))
edit_constraint (win, GTK_CONSTRAINT (item));
else if (GTK_IS_CONSTRAINT_GUIDE (item))
edit_guide (win, GTK_CONSTRAINT_GUIDE (item));
}
static void
mark_constraints_invalid (ConstraintEditorWindow *win,
gpointer removed)
{
GtkWidget *child;
GObject *item;
for (child = gtk_widget_get_first_child (win->list);
child;
child = gtk_widget_get_next_sibling (child))
{
item = (GObject *)g_object_get_data (G_OBJECT (child), "item");
if (GTK_IS_CONSTRAINT (item))
{
GtkConstraint *constraint = GTK_CONSTRAINT (item);
if (gtk_constraint_get_target (constraint) == (GtkConstraintTarget *)removed ||
gtk_constraint_get_source (constraint) == (GtkConstraintTarget *)removed)
{
GtkWidget *button;
button = (GtkWidget *)g_object_get_data (G_OBJECT (child), "edit");
gtk_button_set_icon_name (GTK_BUTTON (button), "dialog-warning-symbolic");
gtk_widget_set_tooltip_text (button, "Constraint is invalid");
}
}
}
}
static void
row_delete (GtkButton *button,
ConstraintEditorWindow *win)
{
GtkWidget *row;
GObject *item;
row = gtk_widget_get_ancestor (GTK_WIDGET (button), GTK_TYPE_LIST_BOX_ROW);
item = (GObject *)g_object_get_data (G_OBJECT (row), "item");
if (GTK_IS_CONSTRAINT (item))
constraint_view_remove_constraint (CONSTRAINT_VIEW (win->view),
GTK_CONSTRAINT (item));
else if (GTK_IS_CONSTRAINT_GUIDE (item))
{
mark_constraints_invalid (win, item);
constraint_view_remove_guide (CONSTRAINT_VIEW (win->view),
GTK_CONSTRAINT_GUIDE (item));
}
else if (GTK_IS_WIDGET (item))
{
mark_constraints_invalid (win, item);
constraint_view_remove_child (CONSTRAINT_VIEW (win->view),
GTK_WIDGET (item));
}
}
static GtkWidget *
create_widget_func (gpointer item,
gpointer user_data)
{
ConstraintEditorWindow *win = user_data;
const char *name;
char *freeme = NULL;
GtkWidget *row, *box, *label, *button;
if (GTK_IS_WIDGET (item))
name = gtk_widget_get_name (GTK_WIDGET (item));
else if (GTK_IS_CONSTRAINT_GUIDE (item))
name = gtk_constraint_guide_get_name (GTK_CONSTRAINT_GUIDE (item));
else if (GTK_IS_CONSTRAINT (item))
name = freeme = constraint_editor_constraint_to_string (GTK_CONSTRAINT (item));
else
name = "";
row = gtk_list_box_row_new ();
g_object_set_data_full (G_OBJECT (row), "item", g_object_ref (item), g_object_unref);
box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
label = gtk_label_new (name);
if (GTK_IS_WIDGET (item) || GTK_IS_CONSTRAINT_GUIDE (item))
g_object_bind_property (item, "name",
label, "label",
G_BINDING_DEFAULT);
gtk_widget_set_margin_start (label, 10);
gtk_widget_set_margin_end (label, 10);
gtk_widget_set_margin_top (label, 10);
gtk_widget_set_margin_bottom (label, 10);
gtk_label_set_xalign (GTK_LABEL (label), 0.0);
gtk_widget_set_hexpand (label, TRUE);
gtk_list_box_row_set_child (GTK_LIST_BOX_ROW (row), box);
gtk_box_append (GTK_BOX (box), label);
if (GTK_IS_CONSTRAINT (item) || GTK_IS_CONSTRAINT_GUIDE (item))
{
button = gtk_button_new_from_icon_name ("document-edit-symbolic");
gtk_button_set_has_frame (GTK_BUTTON (button), FALSE);
g_signal_connect (button, "clicked", G_CALLBACK (row_edit), win);
g_object_set_data (G_OBJECT (row), "edit", button);
gtk_box_append (GTK_BOX (box), button);
button = gtk_button_new_from_icon_name ("edit-delete-symbolic");
gtk_button_set_has_frame (GTK_BUTTON (button), FALSE);
g_signal_connect (button, "clicked", G_CALLBACK (row_delete), win);
gtk_box_append (GTK_BOX (box), button);
}
else if (GTK_IS_WIDGET (item))
{
button = gtk_button_new_from_icon_name ("edit-delete-symbolic");
gtk_button_set_has_frame (GTK_BUTTON (button), FALSE);
g_signal_connect (button, "clicked", G_CALLBACK (row_delete), win);
gtk_box_append (GTK_BOX (box), button);
}
g_free (freeme);
return row;
}
static void
constraint_editor_window_init (ConstraintEditorWindow *self)
{
gtk_widget_init_template (GTK_WIDGET (self));
gtk_list_box_bind_model (GTK_LIST_BOX (self->list),
constraint_view_get_model (CONSTRAINT_VIEW (self->view)),
create_widget_func,
self,
NULL);
}
ConstraintEditorWindow *
constraint_editor_window_new (ConstraintEditorApplication *application)
{
return g_object_new (CONSTRAINT_EDITOR_WINDOW_TYPE,
"application", application,
NULL);
}

View File

@@ -1,34 +0,0 @@
/*
* Copyright © 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.1 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/>.
*
* Authors: Matthias Clasen
*/
#pragma once
#include <gtk/gtk.h>
#include "constraint-editor-application.h"
#define CONSTRAINT_EDITOR_WINDOW_TYPE (constraint_editor_window_get_type ())
G_DECLARE_FINAL_TYPE (ConstraintEditorWindow, constraint_editor_window, CONSTRAINT, EDITOR_WINDOW, GtkApplicationWindow)
ConstraintEditorWindow * constraint_editor_window_new (ConstraintEditorApplication *application);
gboolean constraint_editor_window_load (ConstraintEditorWindow *self,
GFile *file);

View File

@@ -1,77 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<template class="ConstraintEditorWindow" parent="GtkApplicationWindow">
<property name="title" translatable="yes">GTK Constraint Editor</property>
<property name="default-width">1024</property>
<property name="default-height">768</property>
<child type="titlebar">
<object class="GtkHeaderBar" id="header">
<child type="start">
<object class="GtkButton">
<property name="icon-name">document-open-symbolic</property>
<property name="tooltip-text">Open ui file</property>
<signal name="clicked" handler="open_cb"/>
</object>
</child>
<child type="start">
<object class="GtkButton">
<property name="icon-name">document-save-symbolic</property>
<property name="tooltip-text">Save to ui file</property>
<signal name="clicked" handler="save_cb"/>
</object>
</child>
</object>
</child>
<child>
<object class="GtkPaned" id="paned">
<property name="orientation">horizontal</property>
<child>
<object class="GtkBox">
<property name="orientation">vertical</property>
<child>
<object class="GtkBox">
<property name="orientation">horizontal</property>
<child>
<object class="GtkButton">
<property name="label">Add Child</property>
<signal name="clicked" handler="add_child" swapped="yes"/>
</object>
</child>
<child>
<object class="GtkButton">
<property name="label">Add Guide</property>
<signal name="clicked" handler="add_guide" swapped="yes"/>
</object>
</child>
<child>
<object class="GtkButton">
<property name="label">Add Constraint</property>
<signal name="clicked" handler="add_constraint" swapped="yes"/>
</object>
</child>
</object>
</child>
<child>
<object class="GtkScrolledWindow">
<property name="hscrollbar-policy">never</property>
<property name="vscrollbar-policy">automatic</property>
<property name="vexpand">1</property>
<child>
<object class="GtkListBox" id="list">
<property name="show-separators">1</property>
<property name="selection-mode">none</property>
<signal name="row-activated" handler="row_activated"/>
</object>
</child>
</object>
</child>
</object>
</child>
<child>
<object class="ConstraintView" id="view">
</object>
</child>
</object>
</child>
</template>
</interface>

View File

@@ -1,716 +0,0 @@
/*
* Copyright © 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.1 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/>.
*
* Authors: Matthias Clasen
*/
#include "config.h"
#include "constraint-editor.h"
#include "constraint-view.h"
struct _ConstraintEditor
{
GtkWidget parent_instance;
GtkWidget *grid;
GtkWidget *target;
GtkWidget *target_attr;
GtkWidget *relation;
GtkWidget *source;
GtkWidget *source_attr;
GtkWidget *multiplier;
GtkWidget *constant;
GtkWidget *strength;
GtkWidget *preview;
GtkWidget *button;
GtkConstraint *constraint;
GListModel *model;
gboolean constructed;
};
enum {
PROP_MODEL = 1,
PROP_CONSTRAINT,
LAST_PROP
};
static GParamSpec *pspecs[LAST_PROP];
enum {
DONE,
LAST_SIGNAL
};
static guint signals[LAST_SIGNAL];
G_DEFINE_TYPE(ConstraintEditor, constraint_editor, GTK_TYPE_WIDGET);
static const char *
get_target_name (GtkConstraintTarget *target)
{
if (target == NULL)
return "Super";
else if (GTK_IS_WIDGET (target))
return gtk_widget_get_name (GTK_WIDGET (target));
else if (GTK_IS_CONSTRAINT_GUIDE (target))
return gtk_constraint_guide_get_name (GTK_CONSTRAINT_GUIDE (target));
else
return "";
}
static void
constraint_target_combo (GListModel *model,
GtkWidget *combo,
gboolean is_source)
{
GtkStringList *targets;
int i;
targets = gtk_string_list_new (NULL);
gtk_string_list_append (targets, "Super");
if (model)
{
for (i = 0; i < g_list_model_get_n_items (model); i++)
{
GObject *item = g_list_model_get_object (model, i);
if (GTK_IS_CONSTRAINT (item))
continue;
gtk_string_list_append (targets, get_target_name (GTK_CONSTRAINT_TARGET (item)));
g_object_unref (item);
}
}
gtk_drop_down_set_model (GTK_DROP_DOWN (combo), G_LIST_MODEL (targets));
g_object_unref (targets);
}
static gpointer
get_target (GListModel *model,
const char *id)
{
int i;
if (id == NULL)
return NULL;
if (strcmp ("Super", id) == 0)
return NULL;
for (i = 0; i < g_list_model_get_n_items (model); i++)
{
GObject *item = g_list_model_get_object (model, i);
g_object_unref (item);
if (GTK_IS_CONSTRAINT (item))
continue;
else if (GTK_IS_WIDGET (item))
{
if (strcmp (id, gtk_widget_get_name (GTK_WIDGET (item))) == 0)
return item;
}
else if (GTK_IS_CONSTRAINT_GUIDE (item))
{
if (strcmp (id, gtk_constraint_guide_get_name (GTK_CONSTRAINT_GUIDE (item))) == 0)
return item;
}
}
return NULL;
}
static void
select_target (GtkDropDown *combo,
const char *target_name)
{
GListModel *model = gtk_drop_down_get_model (combo);
for (unsigned int i = 0; i < g_list_model_get_n_items (model); i++)
{
GtkStringObject *s = g_list_model_get_item (model, i);
g_object_unref (s);
if (strcmp (target_name, gtk_string_object_get_string (s)) == 0)
{
gtk_drop_down_set_selected (GTK_DROP_DOWN (combo), i);
return;
}
}
}
static GtkConstraintAttribute
get_attr (unsigned int id)
{
switch (id)
{
case 0: return GTK_CONSTRAINT_ATTRIBUTE_NONE;
case 1: return GTK_CONSTRAINT_ATTRIBUTE_LEFT;
case 2: return GTK_CONSTRAINT_ATTRIBUTE_RIGHT;
case 3: return GTK_CONSTRAINT_ATTRIBUTE_TOP;
case 4: return GTK_CONSTRAINT_ATTRIBUTE_BOTTOM;
case 5: return GTK_CONSTRAINT_ATTRIBUTE_START;
case 6: return GTK_CONSTRAINT_ATTRIBUTE_END;
case 7: return GTK_CONSTRAINT_ATTRIBUTE_WIDTH;
case 8: return GTK_CONSTRAINT_ATTRIBUTE_HEIGHT;
case 9: return GTK_CONSTRAINT_ATTRIBUTE_CENTER_X;
case 10: return GTK_CONSTRAINT_ATTRIBUTE_CENTER_Y;
case 11: return GTK_CONSTRAINT_ATTRIBUTE_BASELINE;
default: g_assert_not_reached ();
}
}
static unsigned int
get_attr_id (GtkConstraintAttribute attr)
{
switch (attr)
{
case GTK_CONSTRAINT_ATTRIBUTE_NONE: return 0;
case GTK_CONSTRAINT_ATTRIBUTE_LEFT: return 1;
case GTK_CONSTRAINT_ATTRIBUTE_RIGHT: return 2;
case GTK_CONSTRAINT_ATTRIBUTE_TOP: return 3;
case GTK_CONSTRAINT_ATTRIBUTE_BOTTOM: return 4;
case GTK_CONSTRAINT_ATTRIBUTE_START: return 5;
case GTK_CONSTRAINT_ATTRIBUTE_END: return 6;
case GTK_CONSTRAINT_ATTRIBUTE_WIDTH: return 7;
case GTK_CONSTRAINT_ATTRIBUTE_HEIGHT: return 8;
case GTK_CONSTRAINT_ATTRIBUTE_CENTER_X: return 9;
case GTK_CONSTRAINT_ATTRIBUTE_CENTER_Y: return 10;
case GTK_CONSTRAINT_ATTRIBUTE_BASELINE: return 11;
default: g_assert_not_reached ();
}
}
static const char *
get_attr_nick (GtkConstraintAttribute attr)
{
GEnumClass *class = g_type_class_ref (GTK_TYPE_CONSTRAINT_ATTRIBUTE);
GEnumValue *value = g_enum_get_value (class, attr);
const char *nick = value->value_nick;
g_type_class_unref (class);
return nick;
}
static GtkConstraintRelation
get_relation (unsigned int id)
{
switch (id)
{
case 0: return GTK_CONSTRAINT_RELATION_LE;
case 1: return GTK_CONSTRAINT_RELATION_EQ;
case 2: return GTK_CONSTRAINT_RELATION_GE;
default: g_assert_not_reached ();
}
}
static unsigned int
get_relation_id (GtkConstraintRelation relation)
{
switch (relation)
{
case GTK_CONSTRAINT_RELATION_LE: return 0;
case GTK_CONSTRAINT_RELATION_EQ: return 1;
case GTK_CONSTRAINT_RELATION_GE: return 2;
default: g_assert_not_reached ();
}
}
static const char *
get_relation_nick (GtkConstraintRelation relation)
{
GEnumClass *class = g_type_class_ref (GTK_TYPE_CONSTRAINT_RELATION);
GEnumValue *value = g_enum_get_value (class, relation);
const char *nick = value->value_nick;
g_type_class_unref (class);
return nick;
}
static const char *
get_relation_display_name (GtkConstraintRelation relation)
{
switch (relation)
{
case GTK_CONSTRAINT_RELATION_LE:
return "";
case GTK_CONSTRAINT_RELATION_EQ:
return "=";
case GTK_CONSTRAINT_RELATION_GE:
return "";
default:
return "?";
}
}
static GtkConstraintStrength
get_strength (unsigned int id)
{
switch (id)
{
case 0: return GTK_CONSTRAINT_STRENGTH_WEAK;
case 1: return GTK_CONSTRAINT_STRENGTH_MEDIUM;
case 2: return GTK_CONSTRAINT_STRENGTH_STRONG;
case 3: return GTK_CONSTRAINT_STRENGTH_REQUIRED;
default: g_assert_not_reached ();
}
}
static unsigned int
get_strength_id (GtkConstraintStrength strength)
{
switch (strength)
{
case GTK_CONSTRAINT_STRENGTH_WEAK: return 0;
case GTK_CONSTRAINT_STRENGTH_MEDIUM: return 1;
case GTK_CONSTRAINT_STRENGTH_STRONG: return 2;
case GTK_CONSTRAINT_STRENGTH_REQUIRED: return 3;
default: g_assert_not_reached ();
}
}
static const char *
get_strength_nick (GtkConstraintStrength strength)
{
GEnumClass *class = g_type_class_ref (GTK_TYPE_CONSTRAINT_STRENGTH);
GEnumValue *value = g_enum_get_value (class, strength);
const char *nick = value->value_nick;
g_type_class_unref (class);
return nick;
}
void
constraint_editor_serialize_constraint (GString *str,
int indent,
GtkConstraint *constraint)
{
const char *target;
const char *target_attr;
const char *relation;
const char *source;
const char *source_attr;
double multiplier;
double constant;
const char *strength;
target = get_target_name (gtk_constraint_get_target (constraint));
target_attr = get_attr_nick (gtk_constraint_get_target_attribute (constraint));
relation = get_relation_nick (gtk_constraint_get_relation (constraint));
source = get_target_name (gtk_constraint_get_source (constraint));
source_attr = get_attr_nick (gtk_constraint_get_source_attribute (constraint));
multiplier = gtk_constraint_get_multiplier (constraint);
constant = gtk_constraint_get_constant (constraint);
strength = get_strength_nick (gtk_constraint_get_strength (constraint));
g_string_append_printf (str, "%*s<constraint target=\"%s\" target-attribute=\"%s\"\n", indent, "", target, target_attr);
g_string_append_printf (str, "%*s relation=\"%s\"\n", indent, "", relation);
if (strcmp (source_attr, "none") != 0)
{
g_string_append_printf (str, "%*s source=\"%s\" source-attribute=\"%s\"\n", indent, "", source, source_attr);
g_string_append_printf (str, "%*s multiplier=\"%g\"\n", indent, "", multiplier);
}
g_string_append_printf (str, "%*s constant=\"%g\"\n", indent, "", constant);
g_string_append_printf (str, "%*s strength=\"%s\" />\n", indent, "", strength);
}
static void
create_constraint (GtkButton *button,
ConstraintEditor *editor)
{
gpointer obj;
gpointer target;
GtkConstraintAttribute target_attr;
gpointer source;
GtkConstraintAttribute source_attr;
GtkConstraintRelation relation;
double multiplier;
double constant;
int strength;
GtkConstraint *constraint;
obj = gtk_drop_down_get_selected_item (GTK_DROP_DOWN (editor->target));
if (obj)
target = get_target (editor->model, gtk_string_object_get_string (GTK_STRING_OBJECT (obj)));
else
target = NULL;
target_attr = get_attr (gtk_drop_down_get_selected (GTK_DROP_DOWN (editor->target_attr)));
obj = gtk_drop_down_get_selected_item (GTK_DROP_DOWN (editor->source));
if (obj)
source = get_target (editor->model, gtk_string_object_get_string (GTK_STRING_OBJECT (obj)));
else
source = NULL;
source_attr = get_attr (gtk_drop_down_get_selected (GTK_DROP_DOWN(editor->source_attr)));
relation = get_relation (gtk_drop_down_get_selected (GTK_DROP_DOWN (editor->relation)));
multiplier = g_ascii_strtod (gtk_editable_get_text (GTK_EDITABLE (editor->multiplier)), NULL);
constant = g_ascii_strtod (gtk_editable_get_text (GTK_EDITABLE (editor->constant)), NULL);
strength = get_strength (gtk_drop_down_get_selected (GTK_DROP_DOWN (editor->strength)));
constraint = gtk_constraint_new (target, target_attr,
relation,
source, source_attr,
multiplier,
constant,
strength);
g_signal_emit (editor, signals[DONE], 0, constraint);
g_object_unref (constraint);
}
static void
source_attr_changed (ConstraintEditor *editor)
{
if (get_attr (gtk_drop_down_get_selected (GTK_DROP_DOWN (editor->source_attr))) == GTK_CONSTRAINT_ATTRIBUTE_NONE)
{
gtk_drop_down_set_selected (GTK_DROP_DOWN (editor->source), GTK_INVALID_LIST_POSITION);
gtk_editable_set_text (GTK_EDITABLE (editor->multiplier), "");
gtk_widget_set_sensitive (editor->source, FALSE);
gtk_widget_set_sensitive (editor->multiplier, FALSE);
}
else
{
gtk_widget_set_sensitive (editor->source, TRUE);
gtk_widget_set_sensitive (editor->multiplier, TRUE);
gtk_editable_set_text (GTK_EDITABLE (editor->multiplier), "1");
}
}
char *
constraint_editor_constraint_to_string (GtkConstraint *constraint)
{
GString *str;
const char *name;
const char *attr;
const char *relation;
double c, m;
str = g_string_new ("");
name = get_target_name (gtk_constraint_get_target (constraint));
attr = get_attr_nick (gtk_constraint_get_target_attribute (constraint));
relation = get_relation_display_name (gtk_constraint_get_relation (constraint));
if (name == NULL)
name = "[ ]";
g_string_append_printf (str, "%s.%s %s ", name, attr, relation);
c = gtk_constraint_get_constant (constraint);
attr = get_attr_nick (gtk_constraint_get_source_attribute (constraint));
if (strcmp (attr, "none") != 0)
{
name = get_target_name (gtk_constraint_get_source (constraint));
m = gtk_constraint_get_multiplier (constraint);
if (name == NULL)
name = "[ ]";
g_string_append_printf (str, "%s.%s", name, attr);
if (m != 1.0)
g_string_append_printf (str, " × %g", m);
if (c > 0.0)
g_string_append_printf (str, " + %g", c);
else if (c < 0.0)
g_string_append_printf (str, " - %g", -c);
}
else
g_string_append_printf (str, "%g", c);
return g_string_free (str, FALSE);
}
static void
update_preview (ConstraintEditor *editor)
{
GString *str;
const char *name;
const char *attr;
const char *relation;
const char *multiplier;
const char *constant;
double c, m;
if (!editor->constructed)
return;
str = g_string_new ("");
name = gtk_string_object_get_string (GTK_STRING_OBJECT (gtk_drop_down_get_selected_item (GTK_DROP_DOWN (editor->target))));
attr = get_attr_nick (get_attr (gtk_drop_down_get_selected ((GTK_DROP_DOWN (editor->target_attr)))));
relation = get_relation_nick (get_relation (gtk_drop_down_get_selected (GTK_DROP_DOWN (editor->relation))));
if (name == NULL)
name = "[ ]";
g_string_append_printf (str, "%s.%s %s ", name, attr, relation);
constant = gtk_editable_get_text (GTK_EDITABLE (editor->constant));
c = g_ascii_strtod (constant, NULL);
attr = get_attr_nick (get_attr (gtk_drop_down_get_selected (GTK_DROP_DOWN (editor->source_attr))));
if (strcmp (attr, "none") != 0)
{
name = gtk_string_object_get_string (GTK_STRING_OBJECT (gtk_drop_down_get_selected_item (GTK_DROP_DOWN (editor->source))));
multiplier = gtk_editable_get_text (GTK_EDITABLE (editor->multiplier));
m = g_ascii_strtod (multiplier, NULL);
if (name == NULL)
name = "[ ]";
g_string_append_printf (str, "%s.%s", name, attr);
if (m != 1.0)
g_string_append_printf (str, " × %g", m);
if (c > 0.0)
g_string_append_printf (str, " + %g", c);
else if (c < 0.0)
g_string_append_printf (str, " - %g", -c);
}
else
g_string_append_printf (str, "%g", c);
gtk_label_set_label (GTK_LABEL (editor->preview), str->str);
g_string_free (str, TRUE);
}
static void
update_button (ConstraintEditor *editor)
{
gpointer obj;
const char *target;
const char *source;
GtkConstraintAttribute source_attr = get_attr (gtk_drop_down_get_selected (GTK_DROP_DOWN (editor->source_attr)));
obj = gtk_drop_down_get_selected_item (GTK_DROP_DOWN (editor->target));
target = obj ? gtk_string_object_get_string (GTK_STRING_OBJECT (obj)) : NULL;
obj = gtk_drop_down_get_selected_item (GTK_DROP_DOWN (editor->source));
source = obj ? gtk_string_object_get_string (GTK_STRING_OBJECT (obj)) : NULL;
if (target && (source || (source_attr == GTK_CONSTRAINT_ATTRIBUTE_NONE)))
gtk_widget_set_sensitive (editor->button, TRUE);
else
gtk_widget_set_sensitive (editor->button, FALSE);
}
static void
constraint_editor_init (ConstraintEditor *editor)
{
gtk_widget_init_template (GTK_WIDGET (editor));
}
static void
constraint_editor_constructed (GObject *object)
{
ConstraintEditor *editor = CONSTRAINT_EDITOR (object);
constraint_target_combo (editor->model, editor->target, FALSE);
constraint_target_combo (editor->model, editor->source, TRUE);
if (editor->constraint)
{
GtkConstraintTarget *target;
GtkConstraintAttribute attr;
GtkConstraintRelation relation;
GtkConstraintStrength strength;
char *val;
double multiplier;
double constant;
target = gtk_constraint_get_target (editor->constraint);
select_target (GTK_DROP_DOWN (editor->target), get_target_name (target));
attr = gtk_constraint_get_target_attribute (editor->constraint);
gtk_drop_down_set_selected (GTK_DROP_DOWN (editor->target_attr), get_attr_id (attr));
target = gtk_constraint_get_source (editor->constraint);
select_target (GTK_DROP_DOWN (editor->source), get_target_name (target));
attr = gtk_constraint_get_source_attribute (editor->constraint);
gtk_drop_down_set_selected (GTK_DROP_DOWN (editor->source_attr), get_attr_id (attr));
relation = gtk_constraint_get_relation (editor->constraint);
gtk_drop_down_set_selected (GTK_DROP_DOWN (editor->relation), get_relation_id (relation));
multiplier = gtk_constraint_get_multiplier (editor->constraint);
val = g_strdup_printf ("%g", multiplier);
gtk_editable_set_text (GTK_EDITABLE (editor->multiplier), val);
g_free (val);
constant = gtk_constraint_get_constant (editor->constraint);
val = g_strdup_printf ("%g", constant);
gtk_editable_set_text (GTK_EDITABLE (editor->constant), val);
g_free (val);
strength = gtk_constraint_get_strength (editor->constraint);
gtk_drop_down_set_selected (GTK_DROP_DOWN (editor->strength), get_strength_id (strength));
gtk_button_set_label (GTK_BUTTON (editor->button), "Apply");
}
else
{
gtk_drop_down_set_selected (GTK_DROP_DOWN (editor->target_attr), get_attr_id (GTK_CONSTRAINT_ATTRIBUTE_LEFT));
gtk_drop_down_set_selected (GTK_DROP_DOWN (editor->source_attr), get_attr_id (GTK_CONSTRAINT_ATTRIBUTE_LEFT));
gtk_drop_down_set_selected (GTK_DROP_DOWN (editor->relation), get_relation_id (GTK_CONSTRAINT_RELATION_EQ));
gtk_drop_down_set_selected (GTK_DROP_DOWN (editor->strength), get_strength_id (GTK_CONSTRAINT_STRENGTH_REQUIRED));
gtk_editable_set_text (GTK_EDITABLE (editor->multiplier), "1.0");
gtk_editable_set_text (GTK_EDITABLE (editor->constant), "0.0");
gtk_button_set_label (GTK_BUTTON (editor->button), "Create");
}
editor->constructed = TRUE;
update_preview (editor);
update_button (editor);
}
static void
constraint_editor_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec)
{
ConstraintEditor *self = CONSTRAINT_EDITOR (object);
switch (property_id)
{
case PROP_MODEL:
self->model = g_value_dup_object (value);
break;
case PROP_CONSTRAINT:
self->constraint = g_value_dup_object (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
}
}
static void
constraint_editor_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec)
{
ConstraintEditor *self = CONSTRAINT_EDITOR (object);
switch (property_id)
{
case PROP_MODEL:
g_value_set_object (value, self->model);
break;
case PROP_CONSTRAINT:
g_value_set_object (value, self->constraint);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
}
}
static void
constraint_editor_dispose (GObject *object)
{
ConstraintEditor *self = (ConstraintEditor *)object;
g_clear_object (&self->model);
g_clear_object (&self->constraint);
gtk_widget_dispose_template (GTK_WIDGET (object), CONSTRAINT_EDITOR_TYPE);
G_OBJECT_CLASS (constraint_editor_parent_class)->dispose (object);
}
static void
constraint_editor_class_init (ConstraintEditorClass *class)
{
GObjectClass *object_class = G_OBJECT_CLASS (class);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
object_class->constructed = constraint_editor_constructed;
object_class->dispose = constraint_editor_dispose;
object_class->set_property = constraint_editor_set_property;
object_class->get_property = constraint_editor_get_property;
pspecs[PROP_CONSTRAINT] =
g_param_spec_object ("constraint", "constraint", "constraint",
GTK_TYPE_CONSTRAINT,
G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY);
pspecs[PROP_MODEL] =
g_param_spec_object ("model", "model", "model",
G_TYPE_LIST_MODEL,
G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY);
g_object_class_install_properties (object_class, LAST_PROP, pspecs);
signals[DONE] =
g_signal_new ("done",
G_TYPE_FROM_CLASS (object_class),
G_SIGNAL_RUN_LAST,
0,
NULL, NULL,
NULL,
G_TYPE_NONE, 1, GTK_TYPE_CONSTRAINT);
gtk_widget_class_set_layout_manager_type (widget_class, GTK_TYPE_BIN_LAYOUT);
gtk_widget_class_set_template_from_resource (widget_class,
"/org/gtk/gtk4/constraint-editor/constraint-editor.ui");
gtk_widget_class_bind_template_child (widget_class, ConstraintEditor, grid);
gtk_widget_class_bind_template_child (widget_class, ConstraintEditor, target);
gtk_widget_class_bind_template_child (widget_class, ConstraintEditor, target_attr);
gtk_widget_class_bind_template_child (widget_class, ConstraintEditor, relation);
gtk_widget_class_bind_template_child (widget_class, ConstraintEditor, source);
gtk_widget_class_bind_template_child (widget_class, ConstraintEditor, source_attr);
gtk_widget_class_bind_template_child (widget_class, ConstraintEditor, multiplier);
gtk_widget_class_bind_template_child (widget_class, ConstraintEditor, constant);
gtk_widget_class_bind_template_child (widget_class, ConstraintEditor, strength);
gtk_widget_class_bind_template_child (widget_class, ConstraintEditor, preview);
gtk_widget_class_bind_template_child (widget_class, ConstraintEditor, button);
gtk_widget_class_bind_template_callback (widget_class, update_preview);
gtk_widget_class_bind_template_callback (widget_class, update_button);
gtk_widget_class_bind_template_callback (widget_class, create_constraint);
gtk_widget_class_bind_template_callback (widget_class, source_attr_changed);
}
ConstraintEditor *
constraint_editor_new (GListModel *model,
GtkConstraint *constraint)
{
return g_object_new (CONSTRAINT_EDITOR_TYPE,
"model", model,
"constraint", constraint,
NULL);
}

View File

@@ -1,12 +0,0 @@
constraintview {
background: black;
color: white;
}
constraintview .child {
background: red;
}
constraintview .guide {
background: blue;
}

View File

@@ -1,9 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<gresources>
<gresource prefix="/org/gtk/gtk4/constraint-editor">
<file preprocess="xml-stripblanks">constraint-editor-window.ui</file>
<file preprocess="xml-stripblanks">constraint-editor.ui</file>
<file preprocess="xml-stripblanks">guide-editor.ui</file>
<file>constraint-editor.css</file>
</gresource>
</gresources>

View File

@@ -1,34 +0,0 @@
/*
* Copyright © 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.1 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/>.
*
* Authors: Matthias Clasen
*/
#pragma once
#include <gtk/gtk.h>
#define CONSTRAINT_EDITOR_TYPE (constraint_editor_get_type ())
G_DECLARE_FINAL_TYPE (ConstraintEditor, constraint_editor, CONSTRAINT, EDITOR, GtkWidget)
ConstraintEditor * constraint_editor_new (GListModel *model,
GtkConstraint *constraint);
void constraint_editor_serialize_constraint (GString *str,
int indent,
GtkConstraint *constraint);
char *constraint_editor_constraint_to_string (GtkConstraint *constraint);

View File

@@ -1,204 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<object class="GtkStringList" id="targets">
<items>
<item>None</item>
<item>Left</item>
<item>Right</item>
<item>Top</item>
<item>Bottom</item>
<item>Start</item>
<item>End</item>
<item>Width</item>
<item>Height</item>
<item>Center X</item>
<item>Center Y</item>
<item>Baseline</item>
</items>
</object>
<template class="ConstraintEditor" parent="GtkWidget">
<child>
<object class="GtkGrid" id="grid">
<property name="margin-start">20</property>
<property name="margin-end">20</property>
<property name="margin-top">20</property>
<property name="margin-bottom">20</property>
<property name="row-spacing">10</property>
<property name="column-spacing">10</property>
<child>
<object class="GtkLabel">
<property name="label">Target</property>
<layout>
<property name="column">0</property>
<property name="row">1</property>
</layout>
</object>
</child>
<child>
<object class="GtkDropDown" id="target">
<signal name="notify::selected" handler="update_preview" swapped="yes"/>
<signal name="notify::selected" handler="update_button" swapped="yes"/>
<layout>
<property name="column">1</property>
<property name="row">1</property>
</layout>
</object>
</child>
<child>
<object class="GtkDropDown" id="target_attr">
<property name="model">targets</property>
<signal name="notify::selected" handler="update_preview" swapped="yes"/>
<layout>
<property name="column">2</property>
<property name="row">1</property>
</layout>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="label">Relation</property>
<layout>
<property name="column">0</property>
<property name="row">2</property>
</layout>
</object>
</child>
<child>
<object class="GtkDropDown" id="relation">
<signal name="notify::selected" handler="update_preview" swapped="yes"/>
<property name="model">
<object class="GtkStringList">
<items>
<item>≤</item>
<item>=</item>
<item>≥</item>
</items>
</object>
</property>
<layout>
<property name="column">1</property>
<property name="row">2</property>
</layout>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="label">Source</property>
<layout>
<property name="column">0</property>
<property name="row">3</property>
</layout>
</object>
</child>
<child>
<object class="GtkDropDown" id="source">
<signal name="notify::selected" handler="update_preview" swapped="yes"/>
<signal name="notify::selected" handler="update_button" swapped="yes"/>
<layout>
<property name="column">1</property>
<property name="row">3</property>
</layout>
</object>
</child>
<child>
<object class="GtkDropDown" id="source_attr">
<property name="model">targets</property>
<signal name="notify::selected" handler="update_preview" swapped="yes"/>
<signal name="notify::selected" handler="source_attr_changed" swapped="yes"/>
<signal name="notify::selected" handler="update_button" swapped="yes"/>
<layout>
<property name="column">2</property>
<property name="row">3</property>
</layout>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="label">Multiplier</property>
<layout>
<property name="column">0</property>
<property name="row">4</property>
</layout>
</object>
</child>
<child>
<object class="GtkEntry" id="multiplier">
<signal name="changed" handler="update_preview" swapped="yes"/>
<layout>
<property name="column">1</property>
<property name="row">4</property>
</layout>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="label">Constant</property>
<layout>
<property name="column">0</property>
<property name="row">5</property>
</layout>
</object>
</child>
<child>
<object class="GtkEntry" id="constant">
<signal name="changed" handler="update_preview" swapped="yes"/>
<layout>
<property name="column">1</property>
<property name="row">5</property>
</layout>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="label">Strength</property>
<layout>
<property name="column">0</property>
<property name="row">6</property>
</layout>
</object>
</child>
<child>
<object class="GtkDropDown" id="strength">
<property name="model">
<object class="GtkStringList">
<items>
<item>Weak</item>
<item>Medium</item>
<item>Strong</item>
<item>Required</item>
</items>
</object>
</property>
<layout>
<property name="column">1</property>
<property name="row">6</property>
</layout>
</object>
</child>
<child>
<object class="GtkLabel" id="preview">
<property name="xalign">0</property>
<layout>
<property name="column">1</property>
<property name="row">7</property>
<property name="column-span">2</property>
</layout>
<attributes>
<attribute name="scale" value="1.44"/>
</attributes>
</object>
</child>
<child>
<object class="GtkButton" id="button">
<property name="label">Create</property>
<signal name="clicked" handler="create_constraint"/>
<layout>
<property name="column">2</property>
<property name="row">8</property>
</layout>
</object>
</child>
</object>
</child>
</template>
</interface>

View File

@@ -1,93 +0,0 @@
/*
* Copyright © 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.1 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/>.
*
* Authors: Matthias Clasen
*/
#include "constraint-view-child.h"
struct _ConstraintViewChild
{
GObject parent_instance;
char *name;
};
enum {
PROP_NAME = 1,
LAST_PROP
};
static GParamSpec props[LAST_PROP];
G_DEFINE_TYPE (ConstraintViewChild, constraint_view_child, G_TYPE_OBJECT)
static void
constraint_view_child_init (ConstraintViewChild *child)
{
}
static void
constraint_view_child_finalize (GObject *object)
{
ConstraintViewChild *child = CONSTRAINT_VIEW_CHILD (object);
g_free (child->name);
G_OBJECT_CLASS (constraint_view_child_parent_class)->finalize (object);
}
static void
constraint_view_child_set_property (GObject *object,
static void
constraint_view_child_class_init (ConstraintViewChildClass *class)
{
GObjectClass *object_class = G_OBJECT_CLASS (class);
object_class->finalize = constraint_view_child_finalize;
object_class->get_property = constraint_view_child_get_property;
object_class->set_property = constraint_view_child_set_property;
props[PROP_NAME] =
g_param_spec_string ("name", "name", "name",
NULL,
G_PARAM_READWRITE);
g_object_class_install_properties (object_class, LAST_PROP, props);
}
#define CONSTRAINT_VIEW_CHILD_TYPE (constraint_view_get_type ())
G_DECLARE_TYPE (ConstraintViewChild, constraint_view_child, CONSTRAINT, VIEW_CHILD, GObject)
#define CONSTRAINT_VIEW_WIDGET_TYPE (constraint_view_widget_get_type ())
G_DECLARE_FINAL_TYPE (ConstraintViewWidget, constraint_view_widget, CONSTRAINT, VIEW_WIDGET, ConstraintViewChild)
ConstraintViewWidget * constraint_view_widget_new (void);
#define CONSTRAINT_VIEW_GUIDE_TYPE (constraint_view_guide_get_type ())
G_DECLARE_FINAL_TYPE (ConstraintViewGuide, constraint_view_guide, CONSTRAINT, VIEW_GUIDE, ConstraintViewChild)
ConstraintViewGuide * constraint_view_guide_new (void);
#define CONSTRAINT_VIEW_CONSTRAINT_TYPE (constraint_view_constraint_get_type ())
G_DECLARE_FINAL_TYPE (ConstraintViewConstraint, constraint_view_constraint, CONSTRAINT, VIEW_CONSTRAINT, ConstraintViewChild)
ConstraintViewGuide * constraint_view_constraint_new (void);

View File

@@ -1,44 +0,0 @@
/*
* Copyright © 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.1 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/>.
*
* Authors: Matthias Clasen
*/
#pragma once
#include <gtk/gtk.h>
#define CONSTRAINT_VIEW_CHILD_TYPE (constraint_view_get_type ())
G_DECLARE_TYPE (ConstraintViewChild, constraint_view_child, CONSTRAINT, VIEW_CHILD, GObject)
#define CONSTRAINT_VIEW_WIDGET_TYPE (constraint_view_widget_get_type ())
G_DECLARE_FINAL_TYPE (ConstraintViewWidget, constraint_view_widget, CONSTRAINT, VIEW_WIDGET, ConstraintViewChild)
ConstraintViewWidget * constraint_view_widget_new (void);
#define CONSTRAINT_VIEW_GUIDE_TYPE (constraint_view_guide_get_type ())
G_DECLARE_FINAL_TYPE (ConstraintViewGuide, constraint_view_guide, CONSTRAINT, VIEW_GUIDE, ConstraintViewChild)
ConstraintViewGuide * constraint_view_guide_new (void);
#define CONSTRAINT_VIEW_CONSTRAINT_TYPE (constraint_view_constraint_get_type ())
G_DECLARE_FINAL_TYPE (ConstraintViewConstraint, constraint_view_constraint, CONSTRAINT, VIEW_CONSTRAINT, ConstraintViewChild)
ConstraintViewGuide * constraint_view_constraint_new (void);

View File

@@ -1,345 +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 <gtk/gtk.h>
#include "constraint-view.h"
struct _ConstraintView
{
GtkWidget parent;
GListModel *model;
GtkWidget *drag_widget;
};
G_DEFINE_TYPE (ConstraintView, constraint_view, GTK_TYPE_WIDGET);
static void
constraint_view_dispose (GObject *object)
{
ConstraintView *view = CONSTRAINT_VIEW (object);
GtkWidget *child;
while ((child = gtk_widget_get_first_child (GTK_WIDGET (view))) != NULL)
gtk_widget_unparent (child);
g_clear_object (&view->model);
G_OBJECT_CLASS (constraint_view_parent_class)->dispose (object);
}
static void
constraint_view_class_init (ConstraintViewClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
object_class->dispose = constraint_view_dispose;
gtk_widget_class_set_css_name (widget_class, "constraintview");
}
static void
update_weak_position (ConstraintView *self,
GtkWidget *child,
double x,
double y)
{
GtkLayoutManager *manager;
GtkConstraint *constraint;
manager = gtk_widget_get_layout_manager (GTK_WIDGET (self));
constraint = (GtkConstraint *)g_object_get_data (G_OBJECT (child), "x-constraint");
if (constraint)
{
gtk_constraint_layout_remove_constraint (GTK_CONSTRAINT_LAYOUT (manager),
constraint);
g_object_set_data (G_OBJECT (child), "x-constraint", NULL);
}
if (x != -100)
{
constraint = gtk_constraint_new_constant (child,
GTK_CONSTRAINT_ATTRIBUTE_CENTER_X,
GTK_CONSTRAINT_RELATION_EQ,
x,
GTK_CONSTRAINT_STRENGTH_WEAK);
g_object_set_data (G_OBJECT (constraint), "internal", (char *)"yes");
gtk_constraint_layout_add_constraint (GTK_CONSTRAINT_LAYOUT (manager),
constraint);
g_object_set_data (G_OBJECT (child), "x-constraint", constraint);
}
constraint = (GtkConstraint *)g_object_get_data (G_OBJECT (child), "y-constraint");
if (constraint)
{
gtk_constraint_layout_remove_constraint (GTK_CONSTRAINT_LAYOUT (manager),
constraint);
g_object_set_data (G_OBJECT (child), "y-constraint", NULL);
}
if (y != -100)
{
constraint = gtk_constraint_new_constant (child,
GTK_CONSTRAINT_ATTRIBUTE_CENTER_Y,
GTK_CONSTRAINT_RELATION_EQ,
y,
GTK_CONSTRAINT_STRENGTH_WEAK);
g_object_set_data (G_OBJECT (constraint), "internal", (char *)"yes");
gtk_constraint_layout_add_constraint (GTK_CONSTRAINT_LAYOUT (manager),
constraint);
g_object_set_data (G_OBJECT (child), "y-constraint", constraint);
}
}
static void
drag_begin (GtkGestureDrag *drag,
double start_x,
double start_y,
ConstraintView *self)
{
GtkWidget *widget;
widget = gtk_widget_pick (GTK_WIDGET (self), start_x, start_y, GTK_PICK_DEFAULT);
if (GTK_IS_LABEL (widget))
{
widget = gtk_widget_get_ancestor (widget, GTK_TYPE_FRAME);
if (widget &&
gtk_widget_get_parent (widget) == (GtkWidget *)self)
{
self->drag_widget = widget;
}
}
}
static void
drag_update (GtkGestureDrag *drag,
double offset_x,
double offset_y,
ConstraintView *self)
{
double x, y;
if (!self->drag_widget)
return;
gtk_gesture_drag_get_start_point (drag, &x, &y);
update_weak_position (self, self->drag_widget, x + offset_x, y + offset_y);
}
static void
drag_end (GtkGestureDrag *drag,
double offset_x,
double offset_y,
ConstraintView *self)
{
self->drag_widget = NULL;
}
static gboolean
omit_internal (gpointer item, gpointer user_data)
{
if (g_object_get_data (G_OBJECT (item), "internal"))
return FALSE;
return TRUE;
}
static void
constraint_view_init (ConstraintView *self)
{
GtkLayoutManager *manager;
GtkEventController *controller;
GListStore *list;
GListModel *all_children;
GListModel *all_constraints;
GListModel *guides;
GListModel *children;
GListModel *constraints;
GtkFilter *filter;
manager = gtk_constraint_layout_new ();
gtk_widget_set_layout_manager (GTK_WIDGET (self), manager);
guides = gtk_constraint_layout_observe_guides (GTK_CONSTRAINT_LAYOUT (manager));
all_constraints = gtk_constraint_layout_observe_constraints (GTK_CONSTRAINT_LAYOUT (manager));
filter = GTK_FILTER (gtk_custom_filter_new (omit_internal, NULL, NULL));
constraints = (GListModel *)gtk_filter_list_model_new (all_constraints, filter);
all_children = gtk_widget_observe_children (GTK_WIDGET (self));
filter = GTK_FILTER (gtk_custom_filter_new (omit_internal, NULL, NULL));
children = (GListModel *)gtk_filter_list_model_new (all_children, filter);
list = g_list_store_new (G_TYPE_LIST_MODEL);
g_list_store_append (list, children);
g_list_store_append (list, guides);
g_list_store_append (list, constraints);
g_object_unref (children);
g_object_unref (guides);
g_object_unref (constraints);
self->model = G_LIST_MODEL (gtk_flatten_list_model_new (G_LIST_MODEL (list)));
controller = (GtkEventController *)gtk_gesture_drag_new ();
g_signal_connect (controller, "drag-begin", G_CALLBACK (drag_begin), self);
g_signal_connect (controller, "drag-update", G_CALLBACK (drag_update), self);
g_signal_connect (controller, "drag-end", G_CALLBACK (drag_end), self);
gtk_widget_add_controller (GTK_WIDGET (self), controller);
}
ConstraintView *
constraint_view_new (void)
{
return g_object_new (CONSTRAINT_VIEW_TYPE, NULL);
}
void
constraint_view_add_child (ConstraintView *view,
const char *name)
{
GtkWidget *frame;
GtkWidget *label;
label = gtk_label_new (name);
frame = gtk_frame_new (NULL);
gtk_widget_add_css_class (frame, "child");
gtk_widget_set_name (frame, name);
gtk_frame_set_child (GTK_FRAME (frame), label);
gtk_widget_set_parent (frame, GTK_WIDGET (view));
update_weak_position (view, frame, 100, 100);
}
void
constraint_view_remove_child (ConstraintView *view,
GtkWidget *child)
{
update_weak_position (view, child, -100, -100);
gtk_widget_unparent (child);
}
void
constraint_view_add_guide (ConstraintView *view,
GtkConstraintGuide *guide)
{
GtkConstraintLayout *layout;
GtkWidget *frame;
GtkWidget *label;
const char *name;
GtkConstraint *constraint;
struct {
const char *name;
GtkConstraintAttribute attr;
} names[] = {
{ "left-constraint", GTK_CONSTRAINT_ATTRIBUTE_LEFT },
{ "top-constraint", GTK_CONSTRAINT_ATTRIBUTE_TOP },
{ "width-constraint", GTK_CONSTRAINT_ATTRIBUTE_WIDTH },
{ "height-constraint", GTK_CONSTRAINT_ATTRIBUTE_HEIGHT },
};
int i;
name = gtk_constraint_guide_get_name (guide);
label = gtk_label_new (name);
g_object_bind_property (guide, "name",
label, "label",
G_BINDING_DEFAULT);
frame = gtk_frame_new (NULL);
gtk_widget_add_css_class (frame, "guide");
g_object_set_data (G_OBJECT (frame), "internal", (char *)"yes");
gtk_frame_set_child (GTK_FRAME (frame), label);
gtk_widget_insert_after (frame, GTK_WIDGET (view), NULL);
g_object_set_data (G_OBJECT (guide), "frame", frame);
layout = GTK_CONSTRAINT_LAYOUT (gtk_widget_get_layout_manager (GTK_WIDGET (view)));
gtk_constraint_layout_add_guide (layout, g_object_ref (guide));
for (i = 0; i < G_N_ELEMENTS (names); i++)
{
constraint = gtk_constraint_new (frame,
names[i].attr,
GTK_CONSTRAINT_RELATION_EQ,
guide,
names[i].attr,
1.0, 0.0,
GTK_CONSTRAINT_STRENGTH_REQUIRED);
g_object_set_data (G_OBJECT (constraint), "internal", (char *)"yes");
gtk_constraint_layout_add_constraint (layout, constraint);
g_object_set_data (G_OBJECT (guide), names[i].name, constraint);
}
update_weak_position (view, frame, 150, 150);
}
void
constraint_view_remove_guide (ConstraintView *view,
GtkConstraintGuide *guide)
{
GtkConstraintLayout *layout;
GtkWidget *frame;
GtkConstraint *constraint;
const char *names[] = {
"left-constraint",
"top-constraint",
"width-constraint",
"height-constraint"
};
int i;
layout = GTK_CONSTRAINT_LAYOUT (gtk_widget_get_layout_manager (GTK_WIDGET (view)));
for (i = 0; i < G_N_ELEMENTS (names); i++)
{
constraint = (GtkConstraint*)g_object_get_data (G_OBJECT (guide), names[i]);
gtk_constraint_layout_remove_constraint (layout, constraint);
}
frame = (GtkWidget *)g_object_get_data (G_OBJECT (guide), "frame");
update_weak_position (view, frame, -100, -100);
gtk_widget_unparent (frame);
gtk_constraint_layout_remove_guide (layout, guide);
}
void
constraint_view_add_constraint (ConstraintView *view,
GtkConstraint *constraint)
{
GtkLayoutManager *manager;
manager = gtk_widget_get_layout_manager (GTK_WIDGET (view));
gtk_constraint_layout_add_constraint (GTK_CONSTRAINT_LAYOUT (manager),
g_object_ref (constraint));
}
void
constraint_view_remove_constraint (ConstraintView *view,
GtkConstraint *constraint)
{
GtkLayoutManager *manager;
manager = gtk_widget_get_layout_manager (GTK_WIDGET (view));
gtk_constraint_layout_remove_constraint (GTK_CONSTRAINT_LAYOUT (manager),
constraint);
}
GListModel *
constraint_view_get_model (ConstraintView *view)
{
return view->model;
}

View File

@@ -1,45 +0,0 @@
/*
* Copyright © 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.1 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/>.
*
* Authors: Matthias Clasen
*/
#pragma once
#include <gtk/gtk.h>
#define CONSTRAINT_VIEW_TYPE (constraint_view_get_type ())
G_MODULE_EXPORT
G_DECLARE_FINAL_TYPE (ConstraintView, constraint_view, CONSTRAINT, VIEW, GtkWidget)
ConstraintView * constraint_view_new (void);
void constraint_view_add_child (ConstraintView *view,
const char *name);
void constraint_view_remove_child (ConstraintView *view,
GtkWidget *child);
void constraint_view_add_guide (ConstraintView *view,
GtkConstraintGuide *guide);
void constraint_view_remove_guide (ConstraintView *view,
GtkConstraintGuide *guide);
void constraint_view_guide_changed (ConstraintView *view,
GtkConstraintGuide *guide);
void constraint_view_add_constraint (ConstraintView *view,
GtkConstraint *constraint);
void constraint_view_remove_constraint (ConstraintView *view,
GtkConstraint *constraint);
GListModel * constraint_view_get_model (ConstraintView *view);

View File

@@ -1,355 +0,0 @@
/*
* Copyright © 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.1 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/>.
*
* Authors: Matthias Clasen
*/
#include "config.h"
#include "guide-editor.h"
struct _GuideEditor
{
GtkWidget parent_instance;
GtkWidget *grid;
GtkWidget *name;
GtkWidget *min_width;
GtkWidget *min_height;
GtkWidget *nat_width;
GtkWidget *nat_height;
GtkWidget *max_width;
GtkWidget *max_height;
GtkWidget *strength;
GtkWidget *button;
GtkConstraintGuide *guide;
gboolean constructed;
};
enum {
PROP_GUIDE = 1,
LAST_PROP
};
static GParamSpec *pspecs[LAST_PROP];
enum {
DONE,
LAST_SIGNAL
};
static guint signals[LAST_SIGNAL];
G_DEFINE_TYPE(GuideEditor, guide_editor, GTK_TYPE_WIDGET);
static GtkConstraintStrength
get_strength (unsigned int id)
{
switch (id)
{
case 0: return GTK_CONSTRAINT_STRENGTH_WEAK;
case 1: return GTK_CONSTRAINT_STRENGTH_MEDIUM;
case 2: return GTK_CONSTRAINT_STRENGTH_STRONG;
case 3: return GTK_CONSTRAINT_STRENGTH_REQUIRED;
default: g_assert_not_reached ();
}
}
static unsigned int
get_strength_id (GtkConstraintStrength strength)
{
switch (strength)
{
case GTK_CONSTRAINT_STRENGTH_WEAK: return 0;
case GTK_CONSTRAINT_STRENGTH_MEDIUM: return 1;
case GTK_CONSTRAINT_STRENGTH_STRONG: return 2;
case GTK_CONSTRAINT_STRENGTH_REQUIRED: return 3;
default: g_assert_not_reached ();
}
}
static const char *
get_strength_nick (GtkConstraintStrength strength)
{
GEnumClass *class = g_type_class_ref (GTK_TYPE_CONSTRAINT_STRENGTH);
GEnumValue *value = g_enum_get_value (class, strength);
const char *nick = value->value_nick;
g_type_class_unref (class);
return nick;
}
void
guide_editor_serialize_guide (GString *str,
int indent,
GtkConstraintGuide *guide)
{
int min_width, min_height;
int nat_width, nat_height;
int max_width, max_height;
const char *name;
const char *strength;
gtk_constraint_guide_get_min_size (guide, &min_width, &min_height);
gtk_constraint_guide_get_nat_size (guide, &nat_width, &nat_height);
gtk_constraint_guide_get_max_size (guide, &max_width, &max_height);
name = gtk_constraint_guide_get_name (guide);
strength = get_strength_nick (gtk_constraint_guide_get_strength (guide));
g_string_append_printf (str, "%*s<guide min-width=\"%d\" min-height=\"%d\"\n", indent, "", min_width, min_height);
g_string_append_printf (str, "%*s nat-width=\"%d\" nat-height=\"%d\"\n", indent, "", nat_width, nat_height);
g_string_append_printf (str, "%*s max-width=\"%d\" max-height=\"%d\"\n", indent, "", max_width, max_height);
g_string_append_printf (str, "%*s name=\"%s\" strength=\"%s\" />\n", indent, "", name, strength);
}
static void
create_guide (GtkButton *button,
GuideEditor *editor)
{
int strength;
const char *name;
int w, h;
GtkConstraintGuide *guide;
unsigned int id;
if (editor->guide)
guide = g_object_ref (editor->guide);
else
guide = gtk_constraint_guide_new ();
name = gtk_editable_get_text (GTK_EDITABLE (editor->name));
gtk_constraint_guide_set_name (guide, name);
w = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (editor->min_width));
h = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (editor->min_height));
gtk_constraint_guide_set_min_size (guide, w, h);
w = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (editor->nat_width));
h = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (editor->nat_height));
gtk_constraint_guide_set_nat_size (guide, w, h);
w = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (editor->max_width));
h = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (editor->max_height));
gtk_constraint_guide_set_max_size (guide, w, h);
id = gtk_drop_down_get_selected (GTK_DROP_DOWN (editor->strength));
strength = get_strength (id);
gtk_constraint_guide_set_strength (guide, strength);
g_signal_emit (editor, signals[DONE], 0, guide);
g_object_unref (guide);
}
static void
guide_editor_init (GuideEditor *editor)
{
gtk_widget_init_template (GTK_WIDGET (editor));
}
static int guide_counter;
static int
min_input (GtkSpinButton *spin_button,
double *new_val)
{
if (strcmp (gtk_editable_get_text (GTK_EDITABLE (spin_button)), "") == 0)
{
*new_val = 0.0;
return TRUE;
}
return FALSE;
}
static int
max_input (GtkSpinButton *spin_button,
double *new_val)
{
if (strcmp (gtk_editable_get_text (GTK_EDITABLE (spin_button)), "") == 0)
{
*new_val = G_MAXINT;
return TRUE;
}
return FALSE;
}
static void
guide_editor_constructed (GObject *object)
{
GuideEditor *editor = GUIDE_EDITOR (object);
g_signal_connect (editor->min_width, "input", G_CALLBACK (min_input), NULL);
g_signal_connect (editor->min_height, "input", G_CALLBACK (min_input), NULL);
g_signal_connect (editor->max_width, "input", G_CALLBACK (max_input), NULL);
g_signal_connect (editor->max_height, "input", G_CALLBACK (max_input), NULL);
if (editor->guide)
{
GtkConstraintStrength strength;
const char *nick;
int w, h;
nick = gtk_constraint_guide_get_name (editor->guide);
if (nick)
gtk_editable_set_text (GTK_EDITABLE (editor->name), nick);
gtk_constraint_guide_get_min_size (editor->guide, &w, &h);
gtk_spin_button_set_value (GTK_SPIN_BUTTON (editor->min_width), w);
gtk_spin_button_set_value (GTK_SPIN_BUTTON (editor->min_height), h);
gtk_constraint_guide_get_nat_size (editor->guide, &w, &h);
gtk_spin_button_set_value (GTK_SPIN_BUTTON (editor->nat_width), w);
gtk_spin_button_set_value (GTK_SPIN_BUTTON (editor->nat_height), h);
gtk_constraint_guide_get_max_size (editor->guide, &w, &h);
gtk_spin_button_set_value (GTK_SPIN_BUTTON (editor->max_width), w);
gtk_spin_button_set_value (GTK_SPIN_BUTTON (editor->max_height), h);
strength = gtk_constraint_guide_get_strength (editor->guide);
gtk_drop_down_set_selected (GTK_DROP_DOWN (editor->strength), get_strength_id (strength));
gtk_button_set_label (GTK_BUTTON (editor->button), "Apply");
}
else
{
char *name;
guide_counter++;
name = g_strdup_printf ("Guide %d", guide_counter);
gtk_editable_set_text (GTK_EDITABLE (editor->name), name);
g_free (name);
gtk_spin_button_set_value (GTK_SPIN_BUTTON (editor->min_width), 0.0);
gtk_spin_button_set_value (GTK_SPIN_BUTTON (editor->min_height), 0.0);
gtk_spin_button_set_value (GTK_SPIN_BUTTON (editor->nat_width), 0.0);
gtk_spin_button_set_value (GTK_SPIN_BUTTON (editor->nat_height), 0.0);
gtk_spin_button_set_value (GTK_SPIN_BUTTON (editor->max_width), G_MAXINT);
gtk_spin_button_set_value (GTK_SPIN_BUTTON (editor->max_height), G_MAXINT);
gtk_drop_down_set_selected (GTK_DROP_DOWN (editor->strength), get_strength_id (GTK_CONSTRAINT_STRENGTH_MEDIUM));
gtk_button_set_label (GTK_BUTTON (editor->button), "Create");
}
editor->constructed = TRUE;
}
static void
guide_editor_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec)
{
GuideEditor *self = GUIDE_EDITOR (object);
switch (property_id)
{
case PROP_GUIDE:
self->guide = g_value_dup_object (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
}
}
static void
guide_editor_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec)
{
GuideEditor *self = GUIDE_EDITOR (object);
switch (property_id)
{
case PROP_GUIDE:
g_value_set_object (value, self->guide);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
}
}
static void
guide_editor_dispose (GObject *object)
{
GuideEditor *self = (GuideEditor *)object;
g_clear_object (&self->guide);
gtk_widget_dispose_template (GTK_WIDGET (self), GUIDE_EDITOR_TYPE);
G_OBJECT_CLASS (guide_editor_parent_class)->dispose (object);
}
static void
guide_editor_class_init (GuideEditorClass *class)
{
GObjectClass *object_class = G_OBJECT_CLASS (class);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
object_class->constructed = guide_editor_constructed;
object_class->dispose = guide_editor_dispose;
object_class->set_property = guide_editor_set_property;
object_class->get_property = guide_editor_get_property;
pspecs[PROP_GUIDE] =
g_param_spec_object ("guide", "guide", "guide",
GTK_TYPE_CONSTRAINT_GUIDE,
G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY);
g_object_class_install_properties (object_class, LAST_PROP, pspecs);
signals[DONE] =
g_signal_new ("done",
G_TYPE_FROM_CLASS (object_class),
G_SIGNAL_RUN_LAST,
0,
NULL, NULL,
NULL,
G_TYPE_NONE, 1, GTK_TYPE_CONSTRAINT_GUIDE);
gtk_widget_class_set_layout_manager_type (widget_class, GTK_TYPE_BIN_LAYOUT);
gtk_widget_class_set_template_from_resource (widget_class,
"/org/gtk/gtk4/constraint-editor/guide-editor.ui");
gtk_widget_class_bind_template_child (widget_class, GuideEditor, grid);
gtk_widget_class_bind_template_child (widget_class, GuideEditor, name);
gtk_widget_class_bind_template_child (widget_class, GuideEditor, min_width);
gtk_widget_class_bind_template_child (widget_class, GuideEditor, min_height);
gtk_widget_class_bind_template_child (widget_class, GuideEditor, nat_width);
gtk_widget_class_bind_template_child (widget_class, GuideEditor, nat_height);
gtk_widget_class_bind_template_child (widget_class, GuideEditor, max_width);
gtk_widget_class_bind_template_child (widget_class, GuideEditor, max_height);
gtk_widget_class_bind_template_child (widget_class, GuideEditor, strength);
gtk_widget_class_bind_template_child (widget_class, GuideEditor, button);
gtk_widget_class_bind_template_callback (widget_class, create_guide);
}
GuideEditor *
guide_editor_new (GtkConstraintGuide *guide)
{
return g_object_new (GUIDE_EDITOR_TYPE,
"guide", guide,
NULL);
}

View File

@@ -1,32 +0,0 @@
/*
* Copyright © 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.1 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/>.
*
* Authors: Matthias Clasen
*/
#pragma once
#include <gtk/gtk.h>
#define GUIDE_EDITOR_TYPE (guide_editor_get_type ())
G_DECLARE_FINAL_TYPE (GuideEditor, guide_editor, GUIDE, EDITOR, GtkWidget)
GuideEditor * guide_editor_new (GtkConstraintGuide *guide);
void guide_editor_serialize_guide (GString *str,
int indent,
GtkConstraintGuide *guide);

View File

@@ -1,201 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<object class="GtkAdjustment" id="min_width_adj">
<property name="lower">0</property>
<property name="upper">2147483647</property>
<property name="step-increment">1</property>
<property name="page-increment">10</property>
<property name="page-size">0</property>
</object>
<object class="GtkAdjustment" id="min_height_adj">
<property name="lower">0</property>
<property name="upper">2147483647</property>
<property name="step-increment">1</property>
<property name="page-increment">10</property>
<property name="page-size">0</property>
</object>
<object class="GtkAdjustment" id="nat_width_adj">
<property name="lower">0</property>
<property name="upper">2147483647</property>
<property name="step-increment">1</property>
<property name="page-increment">10</property>
<property name="page-size">0</property>
</object>
<object class="GtkAdjustment" id="nat_height_adj">
<property name="lower">0</property>
<property name="upper">2147483647</property>
<property name="step-increment">1</property>
<property name="page-increment">10</property>
<property name="page-size">0</property>
</object>
<object class="GtkAdjustment" id="max_width_adj">
<property name="lower">0</property>
<property name="upper">2147483647</property>
<property name="step-increment">1</property>
<property name="page-increment">10</property>
<property name="page-size">0</property>
</object>
<object class="GtkAdjustment" id="max_height_adj">
<property name="lower">0</property>
<property name="upper">2147483647</property>
<property name="step-increment">1</property>
<property name="page-increment">10</property>
<property name="page-size">0</property>
</object>
<template class="GuideEditor" parent="GtkWidget">
<child>
<object class="GtkGrid" id="grid">
<property name="margin-start">20</property>
<property name="margin-end">20</property>
<property name="margin-top">20</property>
<property name="margin-bottom">20</property>
<property name="row-spacing">10</property>
<property name="column-spacing">10</property>
<child>
<object class="GtkLabel">
<property name="label">Name</property>
<layout>
<property name="column">0</property>
<property name="row">0</property>
</layout>
</object>
</child>
<child>
<object class="GtkEntry" id="name">
<property name="max-width-chars">20</property>
<layout>
<property name="column">1</property>
<property name="row">0</property>
<property name="column-span">2</property>
</layout>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="label">Min Size</property>
<layout>
<property name="column">0</property>
<property name="row">1</property>
</layout>
</object>
</child>
<child>
<object class="GtkSpinButton" id="min_width">
<property name="adjustment">min_width_adj</property>
<property name="max-width-chars">5</property>
<layout>
<property name="column">1</property>
<property name="row">1</property>
</layout>
</object>
</child>
<child>
<object class="GtkSpinButton" id="min_height">
<property name="adjustment">min_height_adj</property>
<property name="max-width-chars">5</property>
<layout>
<property name="column">2</property>
<property name="row">1</property>
</layout>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="label">Nat Size</property>
<layout>
<property name="column">0</property>
<property name="row">2</property>
</layout>
</object>
</child>
<child>
<object class="GtkSpinButton" id="nat_width">
<property name="adjustment">nat_width_adj</property>
<property name="max-width-chars">5</property>
<layout>
<property name="column">1</property>
<property name="row">2</property>
</layout>
</object>
</child>
<child>
<object class="GtkSpinButton" id="nat_height">
<property name="adjustment">nat_height_adj</property>
<property name="max-width-chars">5</property>
<layout>
<property name="column">2</property>
<property name="row">2</property>
</layout>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="label">Max Size</property>
<layout>
<property name="column">0</property>
<property name="row">3</property>
</layout>
</object>
</child>
<child>
<object class="GtkSpinButton" id="max_width">
<property name="adjustment">max_width_adj</property>
<property name="max-width-chars">5</property>
<layout>
<property name="column">1</property>
<property name="row">3</property>
</layout>
</object>
</child>
<child>
<object class="GtkSpinButton" id="max_height">
<property name="adjustment">max_height_adj</property>
<property name="max-width-chars">5</property>
<layout>
<property name="column">2</property>
<property name="row">3</property>
</layout>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="label">Strength</property>
<layout>
<property name="column">0</property>
<property name="row">4</property>
</layout>
</object>
</child>
<child>
<object class="GtkDropDown" id="strength">
<property name="model">
<object class="GtkStringList">
<items>
<item>Weak</item>
<item>Medium</item>
<item>Strong</item>
<item>Required</item>
</items>
</object>
</property>
<layout>
<property name="column">1</property>
<property name="row">4</property>
<property name="column-span">2</property>
</layout>
</object>
</child>
<child>
<object class="GtkButton" id="button">
<property name="label">Create</property>
<signal name="clicked" handler="create_guide"/>
<layout>
<property name="column">2</property>
<property name="row">5</property>
</layout>
</object>
</child>
</object>
</child>
</template>
</interface>

View File

@@ -1,28 +0,0 @@
/*
* Copyright © 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.1 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/>.
*
* Authors: Matthias Clasen <mclasen@redhat.com>
*/
#include "config.h"
#include <constraint-editor-application.h>
int
main (int argc, char *argv[])
{
return g_application_run (G_APPLICATION (constraint_editor_application_new ()), argc, argv);
}

View File

@@ -1,23 +0,0 @@
constraint_editor_sources = [
'main.c',
'constraint-editor-application.c',
'constraint-editor-window.c',
'constraint-view.c',
'constraint-editor.c',
'guide-editor.c',
]
constraint_editor_resources = gnome.compile_resources('constraint_editor_resources',
'constraint-editor.gresource.xml',
source_dir: meson.current_source_dir(),
)
executable('gtk4-constraint-editor',
sources: [ constraint_editor_sources, constraint_editor_resources, ],
c_args: common_cflags,
dependencies: libgtk_dep,
include_directories: confinc,
win_subsystem: 'windows',
link_args: extra_demo_ldflags,
install: false,
)

View File

@@ -1,345 +0,0 @@
// Originally from: https://www.shadertoy.com/view/wsjBD3
// License CC0: A battered alien planet
// Been experimenting with space inspired shaders
#define PI 3.141592654
#define TAU (2.0*PI)
#define TOLERANCE 0.00001
#define MAX_ITER 65
#define MIN_DISTANCE 0.01
#define MAX_DISTANCE 9.0
const vec3 skyCol1 = vec3(0.35, 0.45, 0.6);
const vec3 skyCol2 = vec3(0.4, 0.7, 1.0);
const vec3 skyCol3 = pow(skyCol1, vec3(0.25));
const vec3 sunCol1 = vec3(1.0,0.6,0.4);
const vec3 sunCol2 = vec3(1.0,0.9,0.7);
const vec3 smallSunCol1 = vec3(1.0,0.5,0.25)*0.5;
const vec3 smallSunCol2 = vec3(1.0,0.5,0.25)*0.5;
const vec3 mountainColor = 1.0*sqrt(vec3(0.95, 0.65, 0.45));
const float cellWidth = 1.0;
const vec4 planet = vec4(80.0, -20.0, 100.0, 50.0)*1000.0;
void rot(inout vec2 p, float a) {
float c = cos(a);
float s = sin(a);
p = vec2(p.x*c + p.y*s, -p.x*s + p.y*c);
}
vec2 mod2(inout vec2 p, vec2 size) {
vec2 c = floor((p + size*0.5)/size);
p = mod(p + size*0.5,size) - size*0.5;
return c;
}
float circle(vec2 p, float r) {
return length(p) - r;
}
float egg(vec2 p, float ra, float rb) {
const float k = sqrt(3.0);
p.x = abs(p.x);
float r = ra - rb;
return ((p.y<0.0) ? length(vec2(p.x, p.y )) - r :
(k*(p.x+r)<p.y) ? length(vec2(p.x, p.y-k*r)) :
length(vec2(p.x+r,p.y )) - 2.0*r) - rb;
}
vec2 hash(vec2 p) {
p = vec2(dot (p, vec2 (127.1, 311.7)), dot (p, vec2 (269.5, 183.3)));
return -1. + 2.*fract (sin (p)*43758.5453123);
}
vec2 raySphere(vec3 ro, vec3 rd, vec4 sphere) {
vec3 center = sphere.xyz;
float radius = sphere.w;
vec3 m = ro - center.xyz;
float b = dot(m, rd);
float c = dot(m, m) - radius*radius;
if(c > 0.0 && b > 0.0) return vec2(-1.0, -1.0);
float discr = b * b - c;
if(discr < 0.0) return vec2(-1.0);
float normalMultiplier = 1.0;
float s = sqrt(discr);
float t0 = -b - s;
float t1 = -b + s;;
return vec2(t0, t1);
}
float noize1(vec2 p) {
vec2 n = mod2(p, vec2(cellWidth));
vec2 hh = hash(sqrt(2.0)*(n+1000.0));
hh.x *= hh.y;
float r = 0.225*cellWidth;
float d = circle(p, 2.0*r);
float h = hh.x*smoothstep(0.0, r, -d);
return h*0.25;
}
float noize2(vec2 p) {
vec2 n = mod2(p, vec2(cellWidth));
vec2 hh = hash(sqrt(2.0)*(n+1000.0));
hh.x *= hh.y;
rot(p, TAU*hh.y);
float r = 0.45*cellWidth;
// float d = circle(p, 1.0*r);
float d = egg(p, 0.75*r, 0.5*r*abs(hh.y));
float h = (hh.x)*smoothstep(0.0, r, -2.0*d);
return h*0.275;
}
float height(vec2 p, float dd, int mx) {
const float aa = 0.45;
const float ff = 2.03;
const float tt = 1.2;
const float oo = 3.93;
const float near = 0.25;
const float far = 0.65;
float a = 1.0;
float o = 0.2;
float s = 0.0;
float d = 0.0;
int i = 0;
for (; i < 4;++i) {
float nn = a*noize2(p);
s += nn;
d += abs(a);
p += o;
a *= aa;
p *= ff;
o *= oo;
rot(p, tt);
}
float lod = s/d;
float rdd = dd/MAX_DISTANCE;
mx = int(mix(float(4), float(mx), step(rdd, far)));
for (; i < mx; ++i) {
float nn = a*noize1(p);
s += nn;
d += abs(a);
p += o;
a *= aa;
p *= ff;
o *= oo;
rot(p, tt);
}
float hid = (s/d);
return mix(hid, lod, smoothstep(near, far, rdd));
}
float loheight(vec2 p, float d) {
return height(p, d, 0);
}
float height(vec2 p, float d) {
return height(p, d, 6);
}
float hiheight(vec2 p, float d) {
return height(p, d, 8);
}
vec3 normal(vec2 p, float d) {
vec2 eps = vec2(0.00125, 0.0);
vec3 n;
n.x = (hiheight(p - eps.xy, d) - hiheight(p + eps.xy, d));
n.y = 2.0*eps.x;
n.z = (hiheight(p - eps.yx, d) - hiheight(p + eps.yx, d));
return normalize(n);
}
const float stepLength[] = float[](0.9, 0.25);
float march(vec3 ro, vec3 rd, out int max_iter) {
float dt = 0.1;
float d = MIN_DISTANCE;
int currentStep = 0;
float lastd = d;
for (int i = 0; i < MAX_ITER; ++i)
{
vec3 p = ro + d*rd;
float h = height(p.xz, d);
if (d > MAX_DISTANCE) {
max_iter = i;
return MAX_DISTANCE;
}
float hd = p.y - h;
if (hd < TOLERANCE) {
++currentStep;
if (currentStep >= stepLength.length()) {
max_iter = i;
return d;
}
d = lastd;
continue;
}
float sl = stepLength[currentStep];
dt = max(hd, TOLERANCE)*sl + 0.0025*d;
lastd = d;
d += dt;
}
max_iter = MAX_ITER;
return MAX_DISTANCE;
}
vec3 sunDirection() {
return normalize(vec3(-0.5, 0.085, 1.0));
}
vec3 smallSunDirection() {
return normalize(vec3(-0.2, -0.05, 1.0));
}
float psin(float f) {
return 0.5 + 0.5*sin(f);
}
vec3 skyColor(vec3 ro, vec3 rd) {
vec3 sunDir = sunDirection();
vec3 smallSunDir = smallSunDirection();
float sunDot = max(dot(rd, sunDir), 0.0);
float smallSunDot = max(dot(rd, smallSunDir), 0.0);
float angle = atan(rd.y, length(rd.xz))*2.0/PI;
vec3 skyCol = mix(mix(skyCol1, skyCol2, max(0.0, angle)), skyCol3, clamp(-angle*2.0, 0.0, 1.0));
vec3 sunCol = 0.5*sunCol1*pow(sunDot, 20.0) + 8.0*sunCol2*pow(sunDot, 2000.0);
vec3 smallSunCol = 0.5*smallSunCol1*pow(smallSunDot, 200.0) + 8.0*smallSunCol2*pow(smallSunDot, 20000.0);
vec3 dust = pow(sunCol2*mountainColor, vec3(1.75))*smoothstep(0.05, -0.1, rd.y)*0.5;
vec2 si = raySphere(ro, rd, planet);
vec3 planetSurface = ro + si.x*rd;
vec3 planetNormal = normalize(planetSurface - planet.xyz);
float planetDiff = max(dot(planetNormal, sunDir), 0.0);
float planetBorder = max(dot(planetNormal, -rd), 0.0);
float planetLat = (planetSurface.x+planetSurface.y)*0.0005;
vec3 planetCol = mix(1.3*vec3(0.9, 0.8, 0.7), 0.3*vec3(0.9, 0.8, 0.7), pow(psin(planetLat+1.0)*psin(sqrt(2.0)*planetLat+2.0)*psin(sqrt(3.5)*planetLat+3.0), 0.5));
vec3 final = vec3(0.0);
final += step(0.0, si.x)*pow(planetDiff, 0.75)*planetCol*smoothstep(-0.075, 0.0, rd.y)*smoothstep(0.0, 0.1, planetBorder);
final += skyCol + sunCol + smallSunCol + dust;
return final;
}
vec3 getColor(vec3 ro, vec3 rd) {
int max_iter = 0;
vec3 skyCol = skyColor(ro, rd);
vec3 col = vec3(0);
float d = march(ro, rd, max_iter);
if (d < MAX_DISTANCE) {
vec3 sunDir = sunDirection();
vec3 osunDir = sunDir*vec3(-1.0, .0, -1.0);
vec3 p = ro + d*rd;
vec3 normal = normal(p.xz, d);
float amb = 0.2;
float dif1 = max(0.0, dot(sunDir, normal));
vec3 shd1 = sunCol2*mix(amb, 1.0, pow(dif1, 0.75));
float dif2 = max(0.0, dot(osunDir, normal));
vec3 shd2 = sunCol1*mix(amb, 1.0, pow(dif2, 0.75));
vec3 ref = reflect(rd, normal);
vec3 rcol = skyColor(p, ref);
col = mountainColor*amb*skyCol3;
col += mix(shd1, shd2, -0.5)*mountainColor;
float fre = max(dot(normal, -rd), 0.0);
fre = pow(1.0 - fre, 5.0);
col += rcol*fre*0.5;
col += (1.0*p.y);
col = tanh(col);
col = mix(col, skyCol, smoothstep(0.5*MAX_DISTANCE, 1.0*MAX_DISTANCE, d));
} else {
col = skyCol;
}
// col += vec3(1.1, 0.0, 0.0)* smoothstep(0.25, 1.0,(float(max_iter)/float(MAX_ITER)));
return col;
}
vec3 getSample1(vec2 p, float time) {
float off = 0.5*iTime;
vec3 ro = vec3(0.5, 1.0-0.25, -2.0 + off);
vec3 la = ro + vec3(0.0, -0.30, 2.0);
vec3 ww = normalize(la - ro);
vec3 uu = normalize(cross(vec3(0.0,1.0,0.0), ww));
vec3 vv = normalize(cross(ww, uu));
vec3 rd = normalize(p.x*uu + p.y*vv + 2.0*ww);
vec3 col = getColor(ro, rd) ;
return col;
}
vec3 getSample2(vec2 p, float time) {
p.y-=time*0.25;
float h = height(p, 0.0);
vec3 n = normal(p, 0.0);
vec3 lp = vec3(10.0, -1.2, 0.0);
vec3 ld = normalize(vec3(p.x, h, p.y)- lp);
float d = max(dot(ld, n), 0.0);
vec3 col = vec3(0.0);
col = vec3(1.0)*(h+0.1);
col += vec3(1.5)*pow(d, 0.75);
return col;
}
void mainImage(out vec4 fragColor, vec2 fragCoord) {
vec2 q = fragCoord.xy/iResolution.xy;
vec2 p = -1.0 + 2.0*q;
p.x *= iResolution.x/iResolution.y;
vec3 col = getSample1(p, iTime);
fragColor = vec4(col, 1.0);
}

View File

@@ -1,3 +1,4 @@
#include "config.h"
#include <gtk/gtk.h>
@@ -5,7 +6,6 @@
typedef GtkApplication DemoApplication;
typedef GtkApplicationClass DemoApplicationClass;
static GType demo_application_get_type (void);
G_DEFINE_TYPE (DemoApplication, demo_application, GTK_TYPE_APPLICATION)
typedef struct {
@@ -14,7 +14,7 @@ typedef struct {
GtkWidget *message;
GtkWidget *infobar;
GtkWidget *status;
GtkWidget *menubutton;
GtkWidget *menutool;
GMenuModel *toolmenu;
GtkTextBuffer *buffer;
@@ -25,7 +25,6 @@ typedef struct {
} DemoApplicationWindow;
typedef GtkApplicationWindowClass DemoApplicationWindowClass;
static GType demo_application_window_get_type (void);
G_DEFINE_TYPE (DemoApplicationWindow, demo_application_window, GTK_TYPE_APPLICATION_WINDOW)
static void create_window (GApplication *app, const char *contents);
@@ -33,12 +32,22 @@ static void create_window (GApplication *app, const char *contents);
static void
show_action_dialog (GSimpleAction *action)
{
GtkAlertDialog *dialog;
const gchar *name;
GtkWidget *dialog;
dialog = gtk_alert_dialog_new ("You activated action: \"%s\n",
g_action_get_name (G_ACTION (action)));
gtk_alert_dialog_show (dialog, NULL);
g_object_unref (dialog);
name = g_action_get_name (G_ACTION (action));
dialog = gtk_message_dialog_new (NULL,
GTK_DIALOG_DESTROY_WITH_PARENT,
GTK_MESSAGE_INFO,
GTK_BUTTONS_CLOSE,
"You activated action: \"%s\"",
name);
g_signal_connect (dialog, "response",
G_CALLBACK (gtk_widget_destroy), NULL);
gtk_widget_show (dialog);
}
static void
@@ -47,9 +56,9 @@ show_action_infobar (GSimpleAction *action,
gpointer data)
{
DemoApplicationWindow *window = data;
char *text;
const char *name;
const char *value;
gchar *text;
const gchar *name;
const gchar *value;
name = g_action_get_name (G_ACTION (action));
value = g_variant_get_string (parameter, NULL);
@@ -57,7 +66,7 @@ show_action_infobar (GSimpleAction *action,
text = g_strdup_printf ("You activated radio action: \"%s\".\n"
"Current value: %s", name, value);
gtk_label_set_text (GTK_LABEL (window->message), text);
gtk_widget_set_visible (window->infobar, TRUE);
gtk_widget_show (window->infobar);
g_free (text);
}
@@ -80,38 +89,43 @@ activate_new (GSimpleAction *action,
}
static void
open_response_cb (GObject *source,
GAsyncResult *result,
gpointer user_data)
open_response_cb (GtkNativeDialog *dialog,
gint response_id,
gpointer user_data)
{
GtkFileDialog *dialog = GTK_FILE_DIALOG (source);
GApplication *app = G_APPLICATION (user_data);
GtkFileChooserNative *native = user_data;
GApplication *app = g_object_get_data (G_OBJECT (native), "app");
GtkWidget *message_dialog;
GFile *file;
char *contents;
GError *error = NULL;
file = gtk_file_dialog_open_finish (dialog, result, &error);
if (file)
if (response_id == GTK_RESPONSE_ACCEPT)
{
char *contents;
file = gtk_file_chooser_get_file (GTK_FILE_CHOOSER (native));
if (g_file_load_contents (file, NULL, &contents, NULL, NULL, &error))
{
create_window (app, contents);
g_free (contents);
}
else
{
message_dialog = gtk_message_dialog_new (NULL,
GTK_DIALOG_DESTROY_WITH_PARENT,
GTK_MESSAGE_ERROR,
GTK_BUTTONS_CLOSE,
"Error loading file: \"%s\"",
error->message);
g_signal_connect (message_dialog, "response",
G_CALLBACK (gtk_widget_destroy), NULL);
gtk_widget_show (message_dialog);
g_error_free (error);
}
}
if (error)
{
GtkAlertDialog *alert;
alert = gtk_alert_dialog_new ("Error loading file: \"%s\"", error->message);
gtk_alert_dialog_show (alert, NULL);
g_object_unref (alert);
g_error_free (error);
}
g_object_unref (app);
gtk_native_dialog_destroy (GTK_NATIVE_DIALOG (native));
g_object_unref (native);
}
@@ -121,11 +135,21 @@ activate_open (GSimpleAction *action,
gpointer user_data)
{
GApplication *app = user_data;
GtkFileDialog *dialog;
GtkFileChooserNative *native;
dialog = gtk_file_dialog_new ();
gtk_file_dialog_open (dialog, NULL, NULL, open_response_cb, g_object_ref (app));
g_object_unref (dialog);
native = gtk_file_chooser_native_new ("Open File",
NULL,
GTK_FILE_CHOOSER_ACTION_OPEN,
"_Open",
"_Cancel");
g_object_set_data_full (G_OBJECT (native), "app", g_object_ref (app), g_object_unref);
g_signal_connect (native,
"response",
G_CALLBACK (open_response_cb),
native);
gtk_native_dialog_show (GTK_NATIVE_DIALOG (native));
}
static void
@@ -159,7 +183,7 @@ activate_about (GSimpleAction *action,
{
GtkWidget *window = user_data;
const char *authors[] = {
const gchar *authors[] = {
"Peter Mattis",
"Spencer Kimball",
"Josh MacDonald",
@@ -167,7 +191,7 @@ activate_about (GSimpleAction *action,
NULL
};
const char *documentors[] = {
const gchar *documentors[] = {
"Owen Taylor",
"Tony Gale",
"Matthias Clasen <mclasen@redhat.com>",
@@ -208,58 +232,23 @@ activate_quit (GSimpleAction *action,
win = list->data;
next = list->next;
gtk_window_destroy (GTK_WINDOW (win));
gtk_widget_destroy (GTK_WIDGET (win));
list = next;
}
}
static void
delete_messages (gpointer data)
{
g_list_free_full ((GList *)data, g_free);
}
static void
pop_message (GtkWidget *status)
{
GList *messages = (GList *) g_object_get_data (G_OBJECT (status), "messages");
if (messages)
{
char *message = messages->data;
messages = g_list_remove (messages, message);
g_object_set_data_full (G_OBJECT (status), "messages",
messages, delete_messages);
gtk_label_set_label (GTK_LABEL (status), message);
}
}
static void
push_message (GtkWidget *status,
const char *message)
{
GList *messages = (GList *) g_object_get_data (G_OBJECT (status), "messages");
gtk_label_set_label (GTK_LABEL (status), message);
messages = g_list_prepend (messages, g_strdup (message));
g_object_set_data_full (G_OBJECT (status), "messages",
messages, delete_messages);
}
static void
update_statusbar (GtkTextBuffer *buffer,
DemoApplicationWindow *window)
{
char *msg;
int row, col;
int count;
gchar *msg;
gint row, col;
gint count;
GtkTextIter iter;
/* clear any previous message, underflow is allowed */
pop_message (window->status);
gtk_statusbar_pop (GTK_STATUSBAR (window->status), 0);
count = gtk_text_buffer_get_char_count (buffer);
@@ -273,7 +262,7 @@ update_statusbar (GtkTextBuffer *buffer,
msg = g_strdup_printf ("Cursor at row %d column %d - %d chars in document",
row, col, count);
push_message (window->status, msg);
gtk_statusbar_push (GTK_STATUSBAR (window->status), 0, msg);
g_free (msg);
}
@@ -330,21 +319,26 @@ static GActionEntry win_entries[] = {
static void
clicked_cb (GtkWidget *widget, DemoApplicationWindow *window)
{
gtk_widget_set_visible (window->infobar, FALSE);
gtk_widget_hide (window->infobar);
}
static void
startup (GApplication *app)
{
GtkBuilder *builder;
GMenuModel *appmenu;
GMenuModel *menubar;
G_APPLICATION_CLASS (demo_application_parent_class)->startup (app);
builder = gtk_builder_new ();
gtk_builder_add_from_resource (builder, "/application_demo/menus.ui", NULL);
gtk_application_set_menubar (GTK_APPLICATION (app),
G_MENU_MODEL (gtk_builder_get_object (builder, "menubar")));
appmenu = (GMenuModel *)gtk_builder_get_object (builder, "appmenu");
menubar = (GMenuModel *)gtk_builder_get_object (builder, "menubar");
gtk_application_set_app_menu (GTK_APPLICATION (app), appmenu);
gtk_application_set_menubar (GTK_APPLICATION (app), menubar);
g_object_unref (builder);
}
@@ -357,7 +351,6 @@ create_window (GApplication *app,
window = (DemoApplicationWindow *)g_object_new (demo_application_window_get_type (),
"application", app,
"show-menubar", TRUE,
NULL);
if (content)
gtk_text_buffer_set_text (window->buffer, content, -1);
@@ -426,7 +419,7 @@ demo_application_window_load_state (DemoApplicationWindow *win)
static void
demo_application_window_init (DemoApplicationWindow *window)
{
GtkWidget *popover;
GtkWidget *menu;
window->width = -1;
window->height = -1;
@@ -435,8 +428,8 @@ demo_application_window_init (DemoApplicationWindow *window)
gtk_widget_init_template (GTK_WIDGET (window));
popover = gtk_popover_menu_new_from_model (window->toolmenu);
gtk_menu_button_set_popover (GTK_MENU_BUTTON (window->menubutton), popover);
menu = gtk_menu_new_from_model (window->toolmenu);
gtk_menu_tool_button_set_menu (GTK_MENU_TOOL_BUTTON (window->menutool), menu);
g_action_map_add_action_entries (G_ACTION_MAP (window),
win_entries, G_N_ELEMENTS (win_entries),
@@ -475,18 +468,18 @@ demo_application_window_size_allocate (GtkWidget *widget,
baseline);
if (!window->maximized && !window->fullscreen)
gtk_window_get_default_size (GTK_WINDOW (window), &window->width, &window->height);
gtk_window_get_size (GTK_WINDOW (window), &window->width, &window->height);
}
static void
surface_state_changed (GtkWidget *widget)
{
DemoApplicationWindow *window = (DemoApplicationWindow *)widget;
GdkToplevelState new_state;
GdkSurfaceState new_state;
new_state = gdk_toplevel_get_state (GDK_TOPLEVEL (gtk_native_get_surface (GTK_NATIVE (widget))));
window->maximized = (new_state & GDK_TOPLEVEL_STATE_MAXIMIZED) != 0;
window->fullscreen = (new_state & GDK_TOPLEVEL_STATE_FULLSCREEN) != 0;
new_state = gdk_surface_get_state (gtk_native_get_surface (GTK_NATIVE (widget)));
window->maximized = (new_state & GDK_SURFACE_STATE_MAXIMIZED) != 0;
window->fullscreen = (new_state & GDK_SURFACE_STATE_FULLSCREEN) != 0;
}
static void
@@ -508,15 +501,13 @@ demo_application_window_unrealize (GtkWidget *widget)
}
static void
demo_application_window_dispose (GObject *object)
demo_application_window_destroy (GtkWidget *widget)
{
DemoApplicationWindow *window = (DemoApplicationWindow *)object;
DemoApplicationWindow *window = (DemoApplicationWindow *)widget;
demo_application_window_store_state (window);
gtk_widget_dispose_template (GTK_WIDGET (window), demo_application_window_get_type ());
G_OBJECT_CLASS (demo_application_window_parent_class)->dispose (object);
GTK_WIDGET_CLASS (demo_application_window_parent_class)->destroy (widget);
}
static void
@@ -526,18 +517,18 @@ demo_application_window_class_init (DemoApplicationWindowClass *class)
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
object_class->constructed = demo_application_window_constructed;
object_class->dispose = demo_application_window_dispose;
widget_class->size_allocate = demo_application_window_size_allocate;
widget_class->realize = demo_application_window_realize;
widget_class->unrealize = demo_application_window_unrealize;
widget_class->destroy = demo_application_window_destroy;
gtk_widget_class_set_template_from_resource (widget_class, "/application_demo/application.ui");
gtk_widget_class_bind_template_child (widget_class, DemoApplicationWindow, message);
gtk_widget_class_bind_template_child (widget_class, DemoApplicationWindow, infobar);
gtk_widget_class_bind_template_child (widget_class, DemoApplicationWindow, status);
gtk_widget_class_bind_template_child (widget_class, DemoApplicationWindow, buffer);
gtk_widget_class_bind_template_child (widget_class, DemoApplicationWindow, menubutton);
gtk_widget_class_bind_template_child (widget_class, DemoApplicationWindow, menutool);
gtk_widget_class_bind_template_child (widget_class, DemoApplicationWindow, toolmenu);
gtk_widget_class_bind_template_callback (widget_class, clicked_cb);
gtk_widget_class_bind_template_callback (widget_class, update_statusbar);

View File

@@ -8,31 +8,34 @@
<child>
<object class="GtkGrid">
<child>
<object class="GtkBox">
<object class="GtkToolbar">
<property name="hexpand">1</property>
<style>
<class name="primary-toolbar"/>
</style>
<child>
<object class="GtkMenuButton" id="menubutton">
<object class="GtkMenuToolButton" id="menutool">
<property name="icon-name">document-open</property>
</object>
</child>
<child>
<object class="GtkButton">
<object class="GtkToolButton">
<property name="icon-name">application-exit</property>
<property name="action-name">app.quit</property>
</object>
</child>
<child>
<object class="GtkSeparator"/>
<object class="GtkSeparatorToolItem"/>
</child>
<child>
<object class="GtkButton">
<object class="GtkToolButton">
<property name="icon-name">applications-other</property>
<property name="action-name">win.logo</property>
</object>
</child>
<layout>
<property name="column">0</property>
<property name="row">0</property>
<property name="left-attach">0</property>
<property name="top-attach">0</property>
</layout>
</object>
</child>
@@ -40,28 +43,36 @@
<object class="GtkInfoBar" id="infobar">
<property name="visible">0</property>
<property name="hexpand">1</property>
<child>
<object class="GtkLabel" id="message">
<property name="hexpand">1</property>
<child internal-child="content_area">
<object class="GtkBox" id="content_area">
<child>
<object class="GtkLabel" id="message">
<property name="hexpand">1</property>
</object>
</child>
</object>
</child>
<child type="action">
<object class="GtkButton">
<property name="valign">center</property>
<property name="label" translatable="yes">_OK</property>
<property name="use-underline">1</property>
<signal name="clicked" handler="clicked_cb"/>
<child internal-child="action_area">
<object class="GtkBox">
<child>
<object class="GtkButton">
<property name="valign">center</property>
<property name="label" translatable="yes">_OK</property>
<property name="use-underline">1</property>
<signal name="clicked" handler="clicked_cb"/>
</object>
</child>
</object>
</child>
<layout>
<property name="column">0</property>
<property name="row">1</property>
<property name="left-attach">0</property>
<property name="top-attach">1</property>
</layout>
</object>
</child>
<child>
<object class="GtkScrolledWindow">
<property name="has-frame">1</property>
<property name="shadow-type">in</property>
<child>
<object class="GtkTextView">
<property name="hexpand">1</property>
@@ -70,22 +81,17 @@
</object>
</child>
<layout>
<property name="column">0</property>
<property name="row">2</property>
<property name="left-attach">0</property>
<property name="top-attach">2</property>
</layout>
</object>
</child>
<child>
<object class="GtkLabel" id="status">
<object class="GtkStatusbar" id="status">
<property name="hexpand">1</property>
<property name="xalign">0</property>
<property name="margin-start">2</property>
<property name="margin-end">2</property>
<property name="margin-top">2</property>
<property name="margin-bottom">2</property>
<layout>
<property name="column">0</property>
<property name="row">3</property>
<property name="left-attach">0</property>
<property name="top-attach">3</property>
</layout>
</object>
</child>

View File

@@ -16,8 +16,8 @@ static GtkWidget *placeholder;
static void
on_name_appeared (GDBusConnection *connection,
const char *name,
const char *name_owner,
const gchar *name,
const gchar *name_owner,
gpointer user_data)
{
name_seen = TRUE;
@@ -25,13 +25,18 @@ on_name_appeared (GDBusConnection *connection,
static void
on_name_vanished (GDBusConnection *connection,
const char *name,
const gchar *name,
gpointer user_data)
{
if (!name_seen)
return;
g_clear_object (&placeholder);
if (placeholder)
{
gtk_widget_destroy (placeholder);
g_object_unref (placeholder);
placeholder = NULL;
}
}
#ifdef G_OS_WIN32
@@ -55,7 +60,7 @@ do_application_demo (GtkWidget *toplevel)
if (placeholder == NULL)
{
const char *command;
const gchar *command;
GError *error = NULL;
if (g_file_test ("./gtk4-demo-application" APP_EXTENSION, G_FILE_TEST_IS_EXECUTABLE))

18
demos/gtk-demo/appmenu.ui Normal file
View File

@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<menu id="appmenu">
<section>
<item>
<attribute name="label" translatable="yes">About</attribute>
<attribute name="action">app.about</attribute>
</item>
</section>
<section>
<item>
<attribute name="label" translatable="yes">_Quit</attribute>
<attribute name="action">app.quit</attribute>
<attribute name="accel">&lt;Primary&gt;q</attribute>
</item>
</section>
</menu>
</interface>

View File

@@ -1,20 +1,19 @@
/* Assistant
*
* Demonstrates a sample multi-step assistant with GtkAssistant. Assistants
* are used to divide an operation into several simpler sequential steps,
* and to guide the user through these steps.
* Demonstrates a sample multi-step assistant. Assistants are used to divide
* an operation into several simpler sequential steps, and to guide the user
* through these steps.
*/
#include <gtk/gtk.h>
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
static GtkWidget *assistant = NULL;
static GtkWidget *progress_bar = NULL;
static gboolean
apply_changes_gradually (gpointer data)
{
double fraction;
gdouble fraction;
/* Work, work, work... */
fraction = gtk_progress_bar_get_fraction (GTK_PROGRESS_BAR (progress_bar));
@@ -28,7 +27,8 @@ apply_changes_gradually (gpointer data)
else
{
/* Close automatically once changes are fully applied. */
gtk_window_destroy (GTK_WINDOW (data));
gtk_widget_destroy (assistant);
assistant = NULL;
return G_SOURCE_REMOVE;
}
}
@@ -37,20 +37,23 @@ static void
on_assistant_apply (GtkWidget *widget, gpointer data)
{
/* Start a timer to simulate changes taking a few seconds to apply. */
g_timeout_add (100, apply_changes_gradually, widget);
g_timeout_add (100, apply_changes_gradually, NULL);
}
static void
on_assistant_close_cancel (GtkWidget *widget, gpointer data)
{
gtk_window_destroy (GTK_WINDOW (widget));
GtkWidget **assistant = (GtkWidget **) data;
gtk_widget_destroy (*assistant);
*assistant = NULL;
}
static void
on_assistant_prepare (GtkWidget *widget, GtkWidget *page, gpointer data)
{
int current_page, n_pages;
char *title;
gint current_page, n_pages;
gchar *title;
current_page = gtk_assistant_get_current_page (GTK_ASSISTANT (widget));
n_pages = gtk_assistant_get_n_pages (GTK_ASSISTANT (widget));
@@ -72,8 +75,8 @@ on_entry_changed (GtkWidget *widget, gpointer data)
{
GtkAssistant *assistant = GTK_ASSISTANT (data);
GtkWidget *current_page;
int page_number;
const char *text;
gint page_number;
const gchar *text;
page_number = gtk_assistant_get_current_page (assistant);
current_page = gtk_assistant_get_nth_page (assistant, page_number);
@@ -91,21 +94,14 @@ create_page1 (GtkWidget *assistant)
GtkWidget *box, *label, *entry;
box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12);
gtk_widget_set_margin_start (box, 12);
gtk_widget_set_margin_end (box, 12);
gtk_widget_set_margin_top (box, 12);
gtk_widget_set_margin_bottom (box, 12);
label = gtk_label_new ("You must fill out this entry to continue:");
gtk_box_append (GTK_BOX (box), label);
gtk_container_add (GTK_CONTAINER (box), label);
entry = gtk_entry_new ();
gtk_accessible_update_relation (GTK_ACCESSIBLE (entry),
GTK_ACCESSIBLE_RELATION_LABELLED_BY, label, NULL,
-1);
gtk_entry_set_activates_default (GTK_ENTRY (entry), TRUE);
gtk_widget_set_valign (entry, GTK_ALIGN_CENTER);
gtk_box_append (GTK_BOX (box), entry);
gtk_container_add (GTK_CONTAINER (box), entry);
g_signal_connect (G_OBJECT (entry), "changed",
G_CALLBACK (on_entry_changed), assistant);
@@ -119,16 +115,11 @@ create_page2 (GtkWidget *assistant)
{
GtkWidget *box, *checkbutton;
box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12);
gtk_widget_set_margin_start (box, 12);
gtk_widget_set_margin_end (box, 12);
gtk_widget_set_margin_top (box, 12);
gtk_widget_set_margin_bottom (box, 12);
box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
checkbutton = gtk_check_button_new_with_label ("This is optional data, you may continue "
"even if you do not check this");
gtk_widget_set_valign (checkbutton, GTK_ALIGN_CENTER);
gtk_box_append (GTK_BOX (box), checkbutton);
gtk_container_add (GTK_CONTAINER (box), checkbutton);
gtk_assistant_append_page (GTK_ASSISTANT (assistant), box);
gtk_assistant_set_page_complete (GTK_ASSISTANT (assistant), box, TRUE);
@@ -142,6 +133,7 @@ create_page3 (GtkWidget *assistant)
label = gtk_label_new ("This is a confirmation page, press 'Apply' to apply changes");
gtk_widget_show (label);
gtk_assistant_append_page (GTK_ASSISTANT (assistant), label);
gtk_assistant_set_page_type (GTK_ASSISTANT (assistant), label, GTK_ASSISTANT_PAGE_CONFIRM);
gtk_assistant_set_page_complete (GTK_ASSISTANT (assistant), label, TRUE);
@@ -158,14 +150,11 @@ create_page4 (GtkWidget *assistant)
gtk_widget_set_margin_start (progress_bar, 40);
gtk_widget_set_margin_end (progress_bar, 40);
gtk_widget_show (progress_bar);
gtk_assistant_append_page (GTK_ASSISTANT (assistant), progress_bar);
gtk_assistant_set_page_type (GTK_ASSISTANT (assistant), progress_bar, GTK_ASSISTANT_PAGE_PROGRESS);
gtk_assistant_set_page_title (GTK_ASSISTANT (assistant), progress_bar, "Applying changes");
gtk_accessible_update_property (GTK_ACCESSIBLE (progress_bar),
GTK_ACCESSIBLE_PROPERTY_LABEL, "Applying changes",
-1);
/* This prevents the assistant window from being
* closed while we're "busy" applying changes.
*/
@@ -175,8 +164,6 @@ create_page4 (GtkWidget *assistant)
GtkWidget*
do_assistant (GtkWidget *do_widget)
{
static GtkWidget *assistant;
if (!assistant)
{
assistant = gtk_assistant_new ();
@@ -185,7 +172,6 @@ do_assistant (GtkWidget *do_widget)
gtk_window_set_display (GTK_WINDOW (assistant),
gtk_widget_get_display (do_widget));
g_object_add_weak_pointer (G_OBJECT (assistant), (gpointer *)&assistant);
create_page1 (assistant);
create_page2 (assistant);
@@ -193,9 +179,9 @@ do_assistant (GtkWidget *do_widget)
create_page4 (assistant);
g_signal_connect (G_OBJECT (assistant), "cancel",
G_CALLBACK (on_assistant_close_cancel), NULL);
G_CALLBACK (on_assistant_close_cancel), &assistant);
g_signal_connect (G_OBJECT (assistant), "close",
G_CALLBACK (on_assistant_close_cancel), NULL);
G_CALLBACK (on_assistant_close_cancel), &assistant);
g_signal_connect (G_OBJECT (assistant), "apply",
G_CALLBACK (on_assistant_apply), NULL);
g_signal_connect (G_OBJECT (assistant), "prepare",
@@ -203,9 +189,12 @@ do_assistant (GtkWidget *do_widget)
}
if (!gtk_widget_get_visible (assistant))
gtk_widget_set_visible (assistant, TRUE);
gtk_widget_show (assistant);
else
gtk_window_destroy (GTK_WINDOW (assistant));
{
gtk_widget_destroy (assistant);
assistant = NULL;
}
return assistant;
}

View File

@@ -1,26 +0,0 @@
uniform float u_time;
void
mainImage(out vec4 fragColor, in vec2 fragCoord, in vec2 resolution, in vec2 uv)
{
vec2 pos = (fragCoord.xy * 2.0 - resolution.xy)/ min (resolution.x, resolution.y) ;
float t0 = sin ((u_time + 0.00)*1.0);
float t1 = sin ((u_time + 0.30)*0.4);
float t2 = cos ((u_time + 0.23)*0.9);
float t3 = cos ((u_time + 0.41)*0.6);
float t4 = cos ((u_time + 0.11)*0.3);
vec2 p0 = vec2 (t1, t0) ;
vec2 p1 = vec2 (t2, t3) ;
vec2 p2 = vec2 (t4, t3) ;
float r = 1.0/distance (pos, p0);
float g = 1.0/distance (pos, p1);
float b = 1.0/distance (pos, p2);
float sum = r + g + b;
float alpha = 1.0 - pow (1.0/(sum), 40.0)*pow (10.0, 40.0*0.7);
fragColor = vec4 (r*0.5, g*0.5, b*0.5, 1.0) * alpha;
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

View File

@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<requires lib="gtk+" version="3.20"/>
<object class="GtkWindow" id="window">
<property name="resizable">0</property>
<property name="title">CSS Blend Modes</property>
@@ -7,10 +8,6 @@
<property name="default-height">300</property>
<child>
<object class="GtkGrid">
<property name="margin-start">12</property>
<property name="margin-end">12</property>
<property name="margin-top">12</property>
<property name="margin-bottom">12</property>
<property name="row-spacing">12</property>
<property name="column-spacing">12</property>
<child>
@@ -21,19 +18,20 @@
<class name="dim-label"/>
</style>
<layout>
<property name="column">0</property>
<property name="row">0</property>
<property name="left-attach">0</property>
<property name="top-attach">0</property>
</layout>
</object>
</child>
<child>
<object class="GtkScrolledWindow" id="scrolledwindow">
<property name="can-focus">1</property>
<property name="vexpand">1</property>
<property name="has-frame">1</property>
<property name="shadow-type">in</property>
<property name="min-content-width">150</property>
<layout>
<property name="column">0</property>
<property name="row">1</property>
<property name="left-attach">0</property>
<property name="top-attach">1</property>
</layout>
</object>
</child>
@@ -43,8 +41,8 @@
<property name="hexpand">1</property>
<property name="stack">stack</property>
<layout>
<property name="column">1</property>
<property name="row">0</property>
<property name="left-attach">1</property>
<property name="top-attach">0</property>
</layout>
</object>
</child>
@@ -70,8 +68,8 @@
<object class="GtkLabel">
<property name="label" translatable="yes">Duck</property>
<layout>
<property name="column">0</property>
<property name="row">0</property>
<property name="left-attach">0</property>
<property name="top-attach">0</property>
</layout>
</object>
</child>
@@ -79,8 +77,8 @@
<object class="GtkLabel">
<property name="label" translatable="yes">Background</property>
<layout>
<property name="column">1</property>
<property name="row">0</property>
<property name="left-attach">1</property>
<property name="top-attach">0</property>
</layout>
</object>
</child>
@@ -90,8 +88,8 @@
<class name="duck"/>
</style>
<layout>
<property name="column">0</property>
<property name="row">1</property>
<property name="left-attach">0</property>
<property name="top-attach">1</property>
</layout>
</object>
</child>
@@ -101,8 +99,8 @@
<class name="gradient"/>
</style>
<layout>
<property name="column">1</property>
<property name="row">1</property>
<property name="left-attach">1</property>
<property name="top-attach">1</property>
</layout>
</object>
</child>
@@ -111,8 +109,8 @@
<property name="label" translatable="yes">
Blended picture</property>
<layout>
<property name="column">0</property>
<property name="row">2</property>
<property name="left-attach">0</property>
<property name="top-attach">2</property>
<property name="column-span">2</property>
</layout>
</object>
@@ -124,8 +122,8 @@ Blended picture</property>
<class name="blend0"/>
</style>
<layout>
<property name="column">0</property>
<property name="row">3</property>
<property name="left-attach">0</property>
<property name="top-attach">3</property>
<property name="column-span">2</property>
</layout>
</object>
@@ -149,8 +147,8 @@ Blended picture</property>
<object class="GtkLabel">
<property name="label" translatable="yes">Red</property>
<layout>
<property name="column">0</property>
<property name="row">0</property>
<property name="left-attach">0</property>
<property name="top-attach">0</property>
</layout>
</object>
</child>
@@ -158,8 +156,8 @@ Blended picture</property>
<object class="GtkLabel">
<property name="label" translatable="yes">Blue</property>
<layout>
<property name="column">1</property>
<property name="row">0</property>
<property name="left-attach">1</property>
<property name="top-attach">0</property>
</layout>
</object>
</child>
@@ -169,8 +167,8 @@ Blended picture</property>
<class name="red"/>
</style>
<layout>
<property name="column">0</property>
<property name="row">1</property>
<property name="left-attach">0</property>
<property name="top-attach">1</property>
</layout>
</object>
</child>
@@ -180,8 +178,8 @@ Blended picture</property>
<class name="blue"/>
</style>
<layout>
<property name="column">1</property>
<property name="row">1</property>
<property name="left-attach">1</property>
<property name="top-attach">1</property>
</layout>
</object>
</child>
@@ -190,8 +188,8 @@ Blended picture</property>
<property name="label" translatable="yes">
Blended picture</property>
<layout>
<property name="column">0</property>
<property name="row">2</property>
<property name="left-attach">0</property>
<property name="top-attach">2</property>
<property name="column-span">2</property>
</layout>
</object>
@@ -203,8 +201,8 @@ Blended picture</property>
<class name="blend1"/>
</style>
<layout>
<property name="column">0</property>
<property name="row">3</property>
<property name="left-attach">0</property>
<property name="top-attach">3</property>
<property name="column-span">2</property>
</layout>
</object>
@@ -231,8 +229,8 @@ Blended picture</property>
<class name="cyan"/>
</style>
<layout>
<property name="column">0</property>
<property name="row">1</property>
<property name="left-attach">0</property>
<property name="top-attach">1</property>
</layout>
</object>
</child>
@@ -242,8 +240,8 @@ Blended picture</property>
<class name="magenta"/>
</style>
<layout>
<property name="column">1</property>
<property name="row">1</property>
<property name="left-attach">1</property>
<property name="top-attach">1</property>
</layout>
</object>
</child>
@@ -253,8 +251,8 @@ Blended picture</property>
<class name="yellow"/>
</style>
<layout>
<property name="column">0</property>
<property name="row">3</property>
<property name="left-attach">0</property>
<property name="top-attach">3</property>
</layout>
</object>
</child>
@@ -265,8 +263,8 @@ Blended picture</property>
<class name="blend2"/>
</style>
<layout>
<property name="column">1</property>
<property name="row">3</property>
<property name="left-attach">1</property>
<property name="top-attach">3</property>
</layout>
</object>
</child>
@@ -278,8 +276,8 @@ Blended picture</property>
<class name="dim-label"/>
</style>
<layout>
<property name="column">0</property>
<property name="row">0</property>
<property name="left-attach">0</property>
<property name="top-attach">0</property>
</layout>
</object>
</child>
@@ -291,8 +289,8 @@ Blended picture</property>
<class name="dim-label"/>
</style>
<layout>
<property name="column">1</property>
<property name="row">0</property>
<property name="left-attach">1</property>
<property name="top-attach">0</property>
</layout>
</object>
</child>
@@ -304,8 +302,8 @@ Blended picture</property>
<class name="dim-label"/>
</style>
<layout>
<property name="column">0</property>
<property name="row">2</property>
<property name="left-attach">0</property>
<property name="top-attach">2</property>
</layout>
</object>
</child>
@@ -317,8 +315,8 @@ Blended picture</property>
<attribute name="weight" value="bold"></attribute>
</attributes>
<layout>
<property name="column">1</property>
<property name="row">2</property>
<property name="left-attach">1</property>
<property name="top-attach">2</property>
</layout>
</object>
</child>
@@ -327,8 +325,8 @@ Blended picture</property>
</object>
</child>
<layout>
<property name="column">1</property>
<property name="row">1</property>
<property name="left-attach">1</property>
<property name="top-attach">1</property>
</layout>
</object>
</child>

View File

@@ -39,7 +39,7 @@ enum {
static guint signals[LAST_SIGNAL] = { 0 };
static GQuark child_data_quark = 0;
G_DEFINE_TYPE (BlurOverlay, blur_overlay, GTK_TYPE_WIDGET)
G_DEFINE_TYPE (BlurOverlay, blur_overlay, GTK_TYPE_BIN)
static void
blur_overlay_set_overlay_child (GtkWidget *widget,
@@ -116,8 +116,7 @@ effective_align (GtkAlign align,
return direction == GTK_TEXT_DIR_RTL ? GTK_ALIGN_START : GTK_ALIGN_END;
case GTK_ALIGN_FILL:
case GTK_ALIGN_CENTER:
case GTK_ALIGN_BASELINE_FILL:
case GTK_ALIGN_BASELINE_CENTER:
case GTK_ALIGN_BASELINE:
default:
return align;
}
@@ -132,11 +131,13 @@ blur_overlay_child_update_style_classes (BlurOverlay *overlay,
GtkAlign valign, halign;
gboolean is_left, is_right, is_top, is_bottom;
gboolean has_left, has_right, has_top, has_bottom;
GtkStyleContext *context;
has_left = gtk_widget_has_css_class (child, "left");
has_right = gtk_widget_has_css_class (child, "right");
has_top = gtk_widget_has_css_class (child, "top");
has_bottom = gtk_widget_has_css_class (child, "bottom");
context = gtk_widget_get_style_context (child);
has_left = gtk_style_context_has_class (context, GTK_STYLE_CLASS_LEFT);
has_right = gtk_style_context_has_class (context, GTK_STYLE_CLASS_RIGHT);
has_top = gtk_style_context_has_class (context, GTK_STYLE_CLASS_TOP);
has_bottom = gtk_style_context_has_class (context, GTK_STYLE_CLASS_BOTTOM);
is_left = is_right = is_top = is_bottom = FALSE;
@@ -159,24 +160,24 @@ blur_overlay_child_update_style_classes (BlurOverlay *overlay,
is_bottom = (child_allocation->y + child_allocation->height == height);
if (has_left && !is_left)
gtk_widget_remove_css_class (child, "left");
gtk_style_context_remove_class (context, GTK_STYLE_CLASS_LEFT);
else if (!has_left && is_left)
gtk_widget_add_css_class (child, "left");
gtk_style_context_add_class (context, GTK_STYLE_CLASS_LEFT);
if (has_right && !is_right)
gtk_widget_remove_css_class (child, "right");
gtk_style_context_remove_class (context, GTK_STYLE_CLASS_RIGHT);
else if (!has_right && is_right)
gtk_widget_add_css_class (child, "right");
gtk_style_context_add_class (context, GTK_STYLE_CLASS_RIGHT);
if (has_top && !is_top)
gtk_widget_remove_css_class (child, "top");
gtk_style_context_remove_class (context, GTK_STYLE_CLASS_TOP);
else if (!has_top && is_top)
gtk_widget_add_css_class (child, "top");
gtk_style_context_add_class (context, GTK_STYLE_CLASS_TOP);
if (has_bottom && !is_bottom)
gtk_widget_remove_css_class (child, "bottom");
gtk_style_context_remove_class (context, GTK_STYLE_CLASS_BOTTOM);
else if (!has_bottom && is_bottom)
gtk_widget_add_css_class (child, "bottom");
gtk_style_context_add_class (context, GTK_STYLE_CLASS_BOTTOM);
}
static void
@@ -205,7 +206,7 @@ blur_overlay_size_allocate (GtkWidget *widget,
GtkWidget *child;
GtkWidget *main_widget;
main_widget = overlay->main_widget;
main_widget = gtk_bin_get_child (GTK_BIN (overlay));
if (main_widget && gtk_widget_get_visible (main_widget))
gtk_widget_size_allocate (main_widget,
&(GtkAllocation) {
@@ -259,8 +260,7 @@ blur_overlay_get_child_position (BlurOverlay *overlay,
case GTK_ALIGN_END:
alloc->x += width - alloc->width;
break;
case GTK_ALIGN_BASELINE_FILL:
case GTK_ALIGN_BASELINE_CENTER:
case GTK_ALIGN_BASELINE:
default:
g_assert_not_reached ();
break;
@@ -283,8 +283,7 @@ blur_overlay_get_child_position (BlurOverlay *overlay,
case GTK_ALIGN_END:
alloc->y += height - alloc->height;
break;
case GTK_ALIGN_BASELINE_FILL:
case GTK_ALIGN_BASELINE_CENTER:
case GTK_ALIGN_BASELINE:
default:
g_assert_not_reached ();
break;
@@ -293,6 +292,43 @@ blur_overlay_get_child_position (BlurOverlay *overlay,
return TRUE;
}
static void
blur_overlay_add (GtkContainer *container,
GtkWidget *widget)
{
BlurOverlay *overlay = BLUR_OVERLAY (container);
gtk_widget_insert_after (widget, GTK_WIDGET (container), NULL);
overlay->main_widget = widget;
}
static void
blur_overlay_remove (GtkContainer *container,
GtkWidget *widget)
{
BlurOverlay *overlay = BLUR_OVERLAY (container);
gtk_widget_unparent (widget);
if (overlay->main_widget == widget)
overlay->main_widget = NULL;
}
static void
blur_overlay_forall (GtkContainer *overlay,
GtkCallback callback,
gpointer callback_data)
{
GtkWidget *child;
child = gtk_widget_get_first_child (GTK_WIDGET (overlay));
while (child != NULL)
{
GtkWidget *next = gtk_widget_get_next_sibling (child);
(* callback) (child, callback_data);
child = next;
}
}
static void
blur_overlay_snapshot (GtkWidget *widget,
GtkSnapshot *snapshot)
@@ -300,13 +336,12 @@ blur_overlay_snapshot (GtkWidget *widget,
GtkWidget *main_widget;
GskRenderNode *main_widget_node = NULL;
GtkWidget *child;
int width, height;
GtkAllocation main_alloc;
cairo_region_t *clip = NULL;
int i;
main_widget = BLUR_OVERLAY (widget)->main_widget;
width = gtk_widget_get_width (widget);
height = gtk_widget_get_height (widget);
gtk_widget_get_allocation (widget, &main_alloc);
for (child = gtk_widget_get_first_child (widget);
child != NULL;
@@ -319,7 +354,7 @@ blur_overlay_snapshot (GtkWidget *widget,
if (blur > 0)
{
cairo_rectangle_int_t rect;
GtkAllocation alloc;
graphene_rect_t bounds;
if (main_widget_node == NULL)
@@ -331,8 +366,8 @@ blur_overlay_snapshot (GtkWidget *widget,
main_widget_node = gtk_snapshot_free_to_node (child_snapshot);
}
if (!gtk_widget_compute_bounds (child, gtk_widget_get_parent (child), &bounds))
graphene_rect_init (&bounds, 0, 0, 0, 0);
gtk_widget_get_allocation (child, &alloc);
graphene_rect_init (&bounds, alloc.x, alloc.y, alloc.width, alloc.height);
gtk_snapshot_push_blur (snapshot, blur);
gtk_snapshot_push_clip (snapshot, &bounds);
gtk_snapshot_append_node (snapshot, main_widget_node);
@@ -341,17 +376,13 @@ blur_overlay_snapshot (GtkWidget *widget,
if (clip == NULL)
{
cairo_rectangle_int_t rect;
rect.x = rect.y = 0;
rect.width = width;
rect.height = height;
rect.width = main_alloc.width;
rect.height = main_alloc.height;
clip = cairo_region_create_rectangle (&rect);
}
rect.x = floor (bounds.origin.x);
rect.y = floor (bounds.origin.y);
rect.width = ceil (bounds.origin.x + bounds.size.width - rect.x);
rect.height = ceil (bounds.origin.y + bounds.size.height - rect.y);
cairo_region_subtract_rectangle (clip, &rect);
cairo_region_subtract_rectangle (clip, (cairo_rectangle_int_t *)&alloc);
}
}
@@ -391,32 +422,21 @@ blur_overlay_snapshot (GtkWidget *widget,
gsk_render_node_unref (main_widget_node);
}
static void
blur_overlay_dispose (GObject *object)
{
BlurOverlay *overlay = BLUR_OVERLAY (object);
GtkWidget *child;
g_clear_pointer (&overlay->main_widget, gtk_widget_unparent);
while ((child = gtk_widget_get_first_child (GTK_WIDGET (overlay))))
gtk_widget_unparent (child);
G_OBJECT_CLASS (blur_overlay_parent_class)->dispose (object);
}
static void
blur_overlay_class_init (BlurOverlayClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
object_class->dispose = blur_overlay_dispose;
GtkContainerClass *container_class = GTK_CONTAINER_CLASS (klass);
widget_class->measure = blur_overlay_measure;
widget_class->size_allocate = blur_overlay_size_allocate;
widget_class->snapshot = blur_overlay_snapshot;
container_class->add = blur_overlay_add;
container_class->remove = blur_overlay_remove;
container_class->forall = blur_overlay_forall;
klass->get_child_position = blur_overlay_get_child_position;
signals[GET_CHILD_POSITION] =
@@ -459,11 +479,3 @@ blur_overlay_add_overlay (BlurOverlay *overlay,
blur_overlay_set_overlay_child (widget, child);
}
void
blur_overlay_set_child (BlurOverlay *overlay,
GtkWidget *widget)
{
gtk_widget_insert_after (widget, GTK_WIDGET (overlay), NULL);
overlay->main_widget = widget;
}

View File

@@ -37,27 +37,28 @@ typedef struct _BlurOverlayClass BlurOverlayClass;
struct _BlurOverlay
{
GtkWidget parent_instance;
GtkBin parent_instance;
GtkWidget *main_widget;
};
struct _BlurOverlayClass
{
GtkWidgetClass parent_class;
GtkBinClass parent_class;
gboolean (*get_child_position) (BlurOverlay *overlay,
GtkWidget *widget,
GtkAllocation *allocation);
};
GDK_AVAILABLE_IN_ALL
GType blur_overlay_get_type (void) G_GNUC_CONST;
GDK_AVAILABLE_IN_ALL
GtkWidget *blur_overlay_new (void);
GDK_AVAILABLE_IN_ALL
void blur_overlay_add_overlay (BlurOverlay *overlay,
GtkWidget *widget,
double blur);
void blur_overlay_set_child (BlurOverlay *overlay,
GtkWidget *widget);
G_END_DECLS

View File

@@ -1,8 +1,6 @@
/* Builder
* #Keywords: GMenu, GtkPopoverMenuBar, GtkBuilder, GtkShortcutController, toolbar
*
* Demonstrates a traditional interface, loaded from a XML description,
* and shows how to connect actions to the menu items and toolbar buttons.
* Demonstrates an interface loaded from a XML description.
*/
#include <gtk/gtk.h>
@@ -14,7 +12,7 @@ quit_activate (GSimpleAction *action,
{
GtkWidget *window = user_data;
gtk_window_destroy (GTK_WINDOW (window));
gtk_widget_destroy (window);
}
static void
@@ -23,46 +21,13 @@ about_activate (GSimpleAction *action,
gpointer user_data)
{
GtkWidget *window = user_data;
GtkBuilder *builder;
GtkWidget *about_dlg;
about_dlg = GTK_WIDGET (g_object_get_data (G_OBJECT (window), "about"));
gtk_window_present (GTK_WINDOW (about_dlg));
}
static void
remove_timeout (gpointer data)
{
guint id = GPOINTER_TO_UINT (data);
g_source_remove (id);
}
static int
pop_message (gpointer data)
{
GtkWidget *status = data;
gtk_label_set_label (GTK_LABEL (status), "");
g_object_set_data (G_OBJECT (status), "timeout", GUINT_TO_POINTER (0));
return G_SOURCE_REMOVE;
}
static void
status_message (GtkWidget *status,
const char *text)
{
guint id;
id = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (status), "timeout"));
if (id)
g_source_remove (id);
gtk_label_set_text (GTK_LABEL (status), text);
id = g_timeout_add (5000, pop_message, status);
g_object_set_data_full (G_OBJECT (status), "timeout", GUINT_TO_POINTER (id), remove_timeout);
builder = g_object_get_data (G_OBJECT (window), "builder");
about_dlg = GTK_WIDGET (gtk_builder_get_object (builder, "aboutdialog1"));
gtk_dialog_run (GTK_DIALOG (about_dlg));
gtk_widget_hide (about_dlg);
}
static void
@@ -70,34 +35,10 @@ help_activate (GSimpleAction *action,
GVariant *parameter,
gpointer user_data)
{
GtkWidget *status;
status = GTK_WIDGET (g_object_get_data (G_OBJECT (user_data), "status"));
status_message (status, "Help not available");
}
static void
not_implemented (GSimpleAction *action,
GVariant *parameter,
gpointer user_data)
{
GtkWidget *status;
char *text;
text = g_strdup_printf ("Action “%s” not implemented", g_action_get_name (G_ACTION (action)));
status = GTK_WIDGET (g_object_get_data (G_OBJECT (user_data), "status"));
status_message (status, text);
g_free (text);
g_print ("Help not available\n");
}
static GActionEntry win_entries[] = {
{ "new", not_implemented, NULL, NULL, NULL },
{ "open", not_implemented, NULL, NULL, NULL },
{ "save", not_implemented, NULL, NULL, NULL },
{ "save-as", not_implemented, NULL, NULL, NULL },
{ "copy", not_implemented, NULL, NULL, NULL },
{ "cut", not_implemented, NULL, NULL, NULL },
{ "paste", not_implemented, NULL, NULL, NULL },
{ "quit", quit_activate, NULL, NULL, NULL },
{ "about", about_activate, NULL, NULL, NULL },
{ "help", help_activate, NULL, NULL, NULL }
@@ -107,78 +48,77 @@ GtkWidget *
do_builder (GtkWidget *do_widget)
{
static GtkWidget *window = NULL;
GtkWidget *toolbar;
GActionGroup *actions;
GtkAccelGroup *accel_group;
GtkWidget *item;
if (!window)
{
GtkBuilder *builder;
GtkWidget *about;
GtkWidget *status;
GtkEventController *controller;
builder = gtk_builder_new_from_resource ("/builder/demo.ui");
gtk_builder_connect_signals (builder, NULL);
window = GTK_WIDGET (gtk_builder_get_object (builder, "window1"));
gtk_window_set_display (GTK_WINDOW (window),
gtk_widget_get_display (do_widget));
g_object_add_weak_pointer (G_OBJECT (window), (gpointer *)&window);
g_signal_connect (window, "destroy",
G_CALLBACK (gtk_widget_destroyed), &window);
toolbar = GTK_WIDGET (gtk_builder_get_object (builder, "toolbar1"));
gtk_style_context_add_class (gtk_widget_get_style_context (toolbar),
"primary-toolbar");
actions = (GActionGroup*)g_simple_action_group_new ();
g_action_map_add_action_entries (G_ACTION_MAP (actions),
win_entries, G_N_ELEMENTS (win_entries),
window);
gtk_widget_insert_action_group (window, "win", actions);
accel_group = gtk_accel_group_new ();
gtk_window_add_accel_group (GTK_WINDOW (window), accel_group);
controller = gtk_shortcut_controller_new ();
gtk_shortcut_controller_set_scope (GTK_SHORTCUT_CONTROLLER (controller),
GTK_SHORTCUT_SCOPE_GLOBAL);
gtk_widget_add_controller (window, controller);
gtk_shortcut_controller_add_shortcut (GTK_SHORTCUT_CONTROLLER (controller),
gtk_shortcut_new (gtk_keyval_trigger_new (GDK_KEY_n, GDK_CONTROL_MASK),
gtk_named_action_new ("win.new")));
gtk_shortcut_controller_add_shortcut (GTK_SHORTCUT_CONTROLLER (controller),
gtk_shortcut_new (gtk_keyval_trigger_new (GDK_KEY_o, GDK_CONTROL_MASK),
gtk_named_action_new ("win.open")));
gtk_shortcut_controller_add_shortcut (GTK_SHORTCUT_CONTROLLER (controller),
gtk_shortcut_new (gtk_keyval_trigger_new (GDK_KEY_s, GDK_CONTROL_MASK),
gtk_named_action_new ("win.save")));
gtk_shortcut_controller_add_shortcut (GTK_SHORTCUT_CONTROLLER (controller),
gtk_shortcut_new (gtk_keyval_trigger_new (GDK_KEY_s, GDK_CONTROL_MASK|GDK_SHIFT_MASK),
gtk_named_action_new ("win.save-as")));
gtk_shortcut_controller_add_shortcut (GTK_SHORTCUT_CONTROLLER (controller),
gtk_shortcut_new (gtk_keyval_trigger_new (GDK_KEY_q, GDK_CONTROL_MASK),
gtk_named_action_new ("win.quit")));
gtk_shortcut_controller_add_shortcut (GTK_SHORTCUT_CONTROLLER (controller),
gtk_shortcut_new (gtk_keyval_trigger_new (GDK_KEY_c, GDK_CONTROL_MASK),
gtk_named_action_new ("win.copy")));
gtk_shortcut_controller_add_shortcut (GTK_SHORTCUT_CONTROLLER (controller),
gtk_shortcut_new (gtk_keyval_trigger_new (GDK_KEY_x, GDK_CONTROL_MASK),
gtk_named_action_new ("win.cut")));
gtk_shortcut_controller_add_shortcut (GTK_SHORTCUT_CONTROLLER (controller),
gtk_shortcut_new (gtk_keyval_trigger_new (GDK_KEY_v, GDK_CONTROL_MASK),
gtk_named_action_new ("win.paste")));
gtk_shortcut_controller_add_shortcut (GTK_SHORTCUT_CONTROLLER (controller),
gtk_shortcut_new (gtk_keyval_trigger_new (GDK_KEY_F1, 0),
gtk_named_action_new ("win.help")));
gtk_shortcut_controller_add_shortcut (GTK_SHORTCUT_CONTROLLER (controller),
gtk_shortcut_new (gtk_keyval_trigger_new (GDK_KEY_F7, 0),
gtk_named_action_new ("win.about")));
item = (GtkWidget*)gtk_builder_get_object (builder, "new_item");
gtk_widget_add_accelerator (item, "activate", accel_group,
GDK_KEY_n, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE);
about = GTK_WIDGET (gtk_builder_get_object (builder, "aboutdialog1"));
gtk_window_set_transient_for (GTK_WINDOW (about), GTK_WINDOW (window));
gtk_window_set_hide_on_close (GTK_WINDOW (about), TRUE);
g_object_set_data_full (G_OBJECT (window), "about",
about, (GDestroyNotify)gtk_window_destroy);
item = (GtkWidget*)gtk_builder_get_object (builder, "open_item");
gtk_widget_add_accelerator (item, "activate", accel_group,
GDK_KEY_o, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE);
status = GTK_WIDGET (gtk_builder_get_object (builder, "statusbar1"));
g_object_set_data (G_OBJECT (window), "status", status);
item = (GtkWidget*)gtk_builder_get_object (builder, "save_item");
gtk_widget_add_accelerator (item, "activate", accel_group,
GDK_KEY_s, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE);
g_object_unref (builder);
item = (GtkWidget*)gtk_builder_get_object (builder, "quit_item");
gtk_widget_add_accelerator (item, "activate", accel_group,
GDK_KEY_q, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE);
item = (GtkWidget*)gtk_builder_get_object (builder, "copy_item");
gtk_widget_add_accelerator (item, "activate", accel_group,
GDK_KEY_c, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE);
item = (GtkWidget*)gtk_builder_get_object (builder, "cut_item");
gtk_widget_add_accelerator (item, "activate", accel_group,
GDK_KEY_x, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE);
item = (GtkWidget*)gtk_builder_get_object (builder, "paste_item");
gtk_widget_add_accelerator (item, "activate", accel_group,
GDK_KEY_v, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE);
item = (GtkWidget*)gtk_builder_get_object (builder, "help_item");
gtk_widget_add_accelerator (item, "activate", accel_group,
GDK_KEY_F1, 0, GTK_ACCEL_VISIBLE);
item = (GtkWidget*)gtk_builder_get_object (builder, "about_item");
gtk_widget_add_accelerator (item, "activate", accel_group,
GDK_KEY_F7, 0, GTK_ACCEL_VISIBLE);
g_object_set_data_full (G_OBJECT(window), "builder", builder, g_object_unref);
}
if (!gtk_widget_get_visible (window))
gtk_widget_set_visible (window, TRUE);
gtk_widget_show (window);
else
gtk_window_destroy (GTK_WINDOW (window));
gtk_widget_destroy (window);
return window;
}

View File

@@ -0,0 +1,551 @@
/* Change Display
*
* Demonstrates migrating a window between different displays.
* A display is a mouse and keyboard with some number of
* associated monitors. The neat thing about having multiple
* displays is that they can be on a completely separate
* computers, as long as there is a network connection to the
* computer where the application is running.
*
* Only some of the windowing systems where GTK runs have the
* concept of multiple displays. (The X Window System is the
* main example.) Other windowing systems can only handle one
* keyboard and mouse, and combine all monitors into
* a single display.
*
* This is a moderately complex example, and demonstrates:
*
* - Tracking the currently open displays
*
* - Changing the display for a window
*
* - Letting the user choose a window by clicking on it
*
* - Using GtkListStore and GtkTreeView
*
* - Using GtkDialog
*/
#include <string.h>
#include <glib/gi18n.h>
#include <gtk/gtk.h>
/* The ChangeDisplayInfo structure corresponds to a toplevel window and
* holds pointers to widgets inside the toplevel window along with other
* information about the contents of the window.
* This is a common organizational structure in real applications.
*/
typedef struct _ChangeDisplayInfo ChangeDisplayInfo;
struct _ChangeDisplayInfo
{
GtkWidget *window;
GtkSizeGroup *size_group;
GtkTreeModel *display_model;
GdkDisplay *current_display;
};
/* These enumerations provide symbolic names for the columns
* in the two GtkListStore models.
*/
enum
{
DISPLAY_COLUMN_NAME,
DISPLAY_COLUMN_DISPLAY,
DISPLAY_NUM_COLUMNS
};
enum
{
SCREEN_COLUMN_NUMBER,
SCREEN_COLUMN_SCREEN,
SCREEN_NUM_COLUMNS
};
/* Finds the toplevel window under the mouse pointer, if any.
*/
static GtkWidget *
find_toplevel_at_pointer (GdkDisplay *display)
{
GdkSurface *pointer_window;
GtkWidget *widget = NULL;
pointer_window = gdk_device_get_surface_at_position (gtk_get_current_event_device (), NULL, NULL);
if (pointer_window)
widget = GTK_WIDGET (gtk_native_get_for_surface (pointer_window));
return widget;
}
static void
released_cb (GtkGestureClick *gesture,
guint n_press,
gdouble x,
gdouble y,
gboolean *clicked)
{
*clicked = TRUE;
}
/* Asks the user to click on a window, then waits for them click
* the mouse. When the mouse is released, returns the toplevel
* window under the pointer, or NULL, if there is none.
*/
static GtkWidget *
query_for_toplevel (GdkDisplay *display,
const char *prompt)
{
GtkWidget *popup, *label, *frame;
GdkCursor *cursor;
GtkWidget *toplevel = NULL;
GdkDevice *device;
popup = gtk_window_new (GTK_WINDOW_POPUP);
gtk_window_set_display (GTK_WINDOW (popup), display);
gtk_window_set_modal (GTK_WINDOW (popup), TRUE);
frame = gtk_frame_new (NULL);
gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_OUT);
gtk_container_add (GTK_CONTAINER (popup), frame);
label = gtk_label_new (prompt);
g_object_set (label, "margin", 10, NULL);
gtk_container_add (GTK_CONTAINER (frame), label);
gtk_widget_show (popup);
cursor = gdk_cursor_new_from_name ("crosshair", NULL);
device = gtk_get_current_event_device ();
if (gdk_seat_grab (gdk_device_get_seat (device),
gtk_native_get_surface (GTK_NATIVE (popup)),
GDK_SEAT_CAPABILITY_ALL_POINTING,
FALSE, cursor, NULL, NULL, NULL) == GDK_GRAB_SUCCESS)
{
GtkGesture *gesture = gtk_gesture_click_new ();
gboolean clicked = FALSE;
g_signal_connect (gesture, "released",
G_CALLBACK (released_cb), &clicked);
gtk_widget_add_controller (popup, GTK_EVENT_CONTROLLER (gesture));
/* Process events until clicked is set by our button release event handler.
* We pass in may_block=TRUE since we want to wait if there
* are no events currently.
*/
while (!clicked)
g_main_context_iteration (NULL, TRUE);
gdk_seat_ungrab (gdk_device_get_seat (device));
toplevel = find_toplevel_at_pointer (display);
if (toplevel == popup)
toplevel = NULL;
}
g_object_unref (cursor);
gtk_widget_destroy (popup);
return toplevel;
}
/* Prompts the user for a toplevel window to move, and then moves
* that window to the currently selected display
*/
static void
query_change_display (ChangeDisplayInfo *info)
{
GdkDisplay *display = gtk_widget_get_display (info->window);
GtkWidget *toplevel;
toplevel = query_for_toplevel (display,
"Please select the toplevel\n"
"to move to the new display");
if (toplevel)
gtk_window_set_display (GTK_WINDOW (toplevel), info->current_display);
else
gdk_display_beep (display);
}
/* Called when the user clicks on a button in our dialog or
* closes the dialog through the window manager. Unless the
* "Change" button was clicked, we destroy the dialog.
*/
static void
response_cb (GtkDialog *dialog,
gint response_id,
ChangeDisplayInfo *info)
{
if (response_id == GTK_RESPONSE_OK)
query_change_display (info);
else
gtk_widget_destroy (GTK_WIDGET (dialog));
}
/* Called when the user clicks on "Open..." in the display
* frame. Prompts for a new display, and then opens a connection
* to that display.
*/
static void
open_display_cb (GtkWidget *button,
ChangeDisplayInfo *info)
{
GtkWidget *content_area;
GtkWidget *dialog;
GtkWidget *display_entry;
GtkWidget *dialog_label;
gchar *new_screen_name = NULL;
GdkDisplay *result = NULL;
dialog = gtk_dialog_new_with_buttons ("Open Display",
GTK_WINDOW (info->window),
GTK_DIALOG_MODAL,
_("_Cancel"), GTK_RESPONSE_CANCEL,
_("_OK"), GTK_RESPONSE_OK,
NULL);
gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
display_entry = gtk_entry_new ();
gtk_entry_set_activates_default (GTK_ENTRY (display_entry), TRUE);
dialog_label =
gtk_label_new ("Please enter the name of\nthe new display\n");
content_area = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
gtk_container_add (GTK_CONTAINER (content_area), dialog_label);
gtk_container_add (GTK_CONTAINER (content_area), display_entry);
gtk_widget_grab_focus (display_entry);
while (!result)
{
gint response_id = gtk_dialog_run (GTK_DIALOG (dialog));
if (response_id != GTK_RESPONSE_OK)
break;
new_screen_name = gtk_editable_get_chars (GTK_EDITABLE (display_entry),
0, -1);
if (strcmp (new_screen_name, "") != 0)
{
result = gdk_display_open (new_screen_name);
if (!result)
{
gchar *error_msg =
g_strdup_printf ("Can't open display:\n\t%s\nplease try another one\n",
new_screen_name);
gtk_label_set_text (GTK_LABEL (dialog_label), error_msg);
g_free (error_msg);
}
g_free (new_screen_name);
}
}
gtk_widget_destroy (dialog);
}
/* Called when the user clicks on the "Close" button in the
* "Display" frame. Closes the selected display.
*/
static void
close_display_cb (GtkWidget *button,
ChangeDisplayInfo *info)
{
if (info->current_display)
gdk_display_close (info->current_display);
}
/* Called when the selected row in the display list changes.
* Updates info->current_display, then refills the list of
* screens.
*/
static void
display_changed_cb (GtkTreeSelection *selection,
ChangeDisplayInfo *info)
{
GtkTreeModel *model;
GtkTreeIter iter;
if (info->current_display)
g_object_unref (info->current_display);
if (gtk_tree_selection_get_selected (selection, &model, &iter))
gtk_tree_model_get (model, &iter,
DISPLAY_COLUMN_DISPLAY, &info->current_display,
-1);
else
info->current_display = NULL;
}
/* This function is used both for creating the "Display" and
* "Screen" frames, since they have a similar structure. The
* caller hooks up the right context for the value returned
* in tree_view, and packs any relevant buttons into button_vbox.
*/
static void
create_frame (ChangeDisplayInfo *info,
const char *title,
GtkWidget **frame,
GtkWidget **tree_view,
GtkWidget **button_vbox)
{
GtkTreeSelection *selection;
GtkWidget *scrollwin;
GtkWidget *hbox;
*frame = gtk_frame_new (title);
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 8);
g_object_set (hbox, "margin", 8, NULL);
gtk_container_add (GTK_CONTAINER (*frame), hbox);
scrollwin = gtk_scrolled_window_new (NULL, NULL);
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrollwin),
GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrollwin),
GTK_SHADOW_IN);
gtk_container_add (GTK_CONTAINER (hbox), scrollwin);
*tree_view = gtk_tree_view_new ();
gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (*tree_view), FALSE);
gtk_container_add (GTK_CONTAINER (scrollwin), *tree_view);
selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (*tree_view));
gtk_tree_selection_set_mode (selection, GTK_SELECTION_BROWSE);
*button_vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 5);
gtk_container_add (GTK_CONTAINER (hbox), *button_vbox);
if (!info->size_group)
info->size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
gtk_size_group_add_widget (GTK_SIZE_GROUP (info->size_group), *button_vbox);
}
/* If we have a stack of buttons, it often looks better if their contents
* are left-aligned, rather than centered. This function creates a button
* and left-aligns it contents.
*/
GtkWidget *
left_align_button_new (const char *label)
{
GtkWidget *button = gtk_button_new_with_mnemonic (label);
GtkWidget *child = gtk_bin_get_child (GTK_BIN (button));
gtk_widget_set_halign (child, GTK_ALIGN_START);
gtk_widget_set_valign (child, GTK_ALIGN_CENTER);
return button;
}
/* Creates the "Display" frame in the main window.
*/
GtkWidget *
create_display_frame (ChangeDisplayInfo *info)
{
GtkWidget *frame;
GtkWidget *tree_view;
GtkWidget *button_vbox;
GtkTreeViewColumn *column;
GtkTreeSelection *selection;
GtkWidget *button;
create_frame (info, "Display", &frame, &tree_view, &button_vbox);
button = left_align_button_new ("_Open...");
g_signal_connect (button, "clicked", G_CALLBACK (open_display_cb), info);
gtk_container_add (GTK_CONTAINER (button_vbox), button);
button = left_align_button_new ("_Close");
g_signal_connect (button, "clicked", G_CALLBACK (close_display_cb), info);
gtk_container_add (GTK_CONTAINER (button_vbox), button);
info->display_model = (GtkTreeModel *)gtk_list_store_new (DISPLAY_NUM_COLUMNS,
G_TYPE_STRING,
GDK_TYPE_DISPLAY);
gtk_tree_view_set_model (GTK_TREE_VIEW (tree_view), info->display_model);
column = gtk_tree_view_column_new_with_attributes ("Name",
gtk_cell_renderer_text_new (),
"text", DISPLAY_COLUMN_NAME,
NULL);
gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view), column);
selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (tree_view));
g_signal_connect (selection, "changed",
G_CALLBACK (display_changed_cb), info);
return frame;
}
/* Called when one of the currently open displays is closed.
* Remove it from our list of displays.
*/
static void
display_closed_cb (GdkDisplay *display,
gboolean is_error,
ChangeDisplayInfo *info)
{
GtkTreeIter iter;
gboolean valid;
for (valid = gtk_tree_model_get_iter_first (info->display_model, &iter);
valid;
valid = gtk_tree_model_iter_next (info->display_model, &iter))
{
GdkDisplay *tmp_display;
gtk_tree_model_get (info->display_model, &iter,
DISPLAY_COLUMN_DISPLAY, &tmp_display,
-1);
if (tmp_display == display)
{
gtk_list_store_remove (GTK_LIST_STORE (info->display_model), &iter);
break;
}
}
}
/* Adds a new display to our list of displays, and connects
* to the "closed" signal so that we can remove it from the
* list of displays again.
*/
static void
add_display (ChangeDisplayInfo *info,
GdkDisplay *display)
{
const gchar *name = gdk_display_get_name (display);
GtkTreeIter iter;
gtk_list_store_append (GTK_LIST_STORE (info->display_model), &iter);
gtk_list_store_set (GTK_LIST_STORE (info->display_model), &iter,
DISPLAY_COLUMN_NAME, name,
DISPLAY_COLUMN_DISPLAY, display,
-1);
g_signal_connect (display, "closed",
G_CALLBACK (display_closed_cb), info);
}
/* Called when a new display is opened
*/
static void
display_opened_cb (GdkDisplayManager *manager,
GdkDisplay *display,
ChangeDisplayInfo *info)
{
add_display (info, display);
}
/* Adds all currently open displays to our list of displays,
* and set up a signal connection so that we'll be notified
* when displays are opened in the future as well.
*/
static void
initialize_displays (ChangeDisplayInfo *info)
{
GdkDisplayManager *manager = gdk_display_manager_get ();
GSList *displays = gdk_display_manager_list_displays (manager);
GSList *tmp_list;
for (tmp_list = displays; tmp_list; tmp_list = tmp_list->next)
add_display (info, tmp_list->data);
g_slist_free (tmp_list);
g_signal_connect (manager, "display-opened",
G_CALLBACK (display_opened_cb), info);
}
/* Cleans up when the toplevel is destroyed; we remove the
* connections we use to track currently open displays, then
* free the ChangeDisplayInfo structure.
*/
static void
destroy_info (ChangeDisplayInfo *info)
{
GdkDisplayManager *manager = gdk_display_manager_get ();
GSList *displays = gdk_display_manager_list_displays (manager);
GSList *tmp_list;
g_signal_handlers_disconnect_by_func (manager,
display_opened_cb,
info);
for (tmp_list = displays; tmp_list; tmp_list = tmp_list->next)
g_signal_handlers_disconnect_by_func (tmp_list->data,
display_closed_cb,
info);
g_slist_free (tmp_list);
g_object_unref (info->size_group);
g_object_unref (info->display_model);
if (info->current_display)
g_object_unref (info->current_display);
g_free (info);
}
static void
destroy_cb (GObject *object,
ChangeDisplayInfo **info)
{
destroy_info (*info);
*info = NULL;
}
/* Main entry point. If the dialog for this demo doesn't yet exist, creates
* it. Otherwise, destroys it.
*/
GtkWidget *
do_changedisplay (GtkWidget *do_widget)
{
static ChangeDisplayInfo *info = NULL;
if (!info)
{
GtkWidget *content_area;
GtkWidget *vbox;
GtkWidget *frame;
info = g_new0 (ChangeDisplayInfo, 1);
info->window = gtk_dialog_new_with_buttons ("Change Display",
GTK_WINDOW (do_widget),
0,
"Close", GTK_RESPONSE_CLOSE,
"Change", GTK_RESPONSE_OK,
NULL);
gtk_window_set_default_size (GTK_WINDOW (info->window), 300, 400);
g_signal_connect (info->window, "response",
G_CALLBACK (response_cb), info);
g_signal_connect (info->window, "destroy",
G_CALLBACK (destroy_cb), &info);
content_area = gtk_dialog_get_content_area (GTK_DIALOG (info->window));
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 5);
g_object_set (vbox, "margin", 8, NULL);
gtk_container_add (GTK_CONTAINER (content_area), vbox);
frame = create_display_frame (info);
gtk_container_add (GTK_CONTAINER (vbox), frame);
initialize_displays (info);
gtk_widget_show (info->window);
return info->window;
}
else
{
gtk_widget_destroy (info->window);
return NULL;
}
}

View File

@@ -1,413 +1,359 @@
/* Clipboard
* #Keywords: drag-and-drop, dnd
*
* GdkClipboard is used for clipboard handling. This demo shows how to
* copy and paste text, images, colors or files to and from the clipboard.
* copy and paste text to and from the clipboard.
*
* You can also use Drag-And-Drop to copy the data from the source to the
* target.
* It also shows how to transfer images via the clipboard or via
* drag-and-drop, and how to make clipboard contents persist after
* the application exits. Clipboard persistence requires a clipboard
* manager to run.
*/
#include <glib/gi18n.h>
#include <gtk/gtk.h>
#include <string.h>
#include "demoimage.h"
static void
copy_button_clicked (GtkStack *source_stack,
gpointer user_data)
static GtkWidget *window = NULL;
void
copy_button_clicked (GtkWidget *button,
gpointer user_data)
{
GtkWidget *entry;
GdkClipboard *clipboard;
const char *visible_child_name;
GtkWidget *visible_child;
clipboard = gtk_widget_get_clipboard (GTK_WIDGET (source_stack));
entry = GTK_WIDGET (user_data);
visible_child = gtk_stack_get_visible_child (source_stack);
visible_child_name = gtk_stack_get_visible_child_name (source_stack);
/* Get the clipboard object */
clipboard = gtk_widget_get_clipboard (entry);
if (strcmp (visible_child_name, "Text") == 0)
{
gdk_clipboard_set_text (clipboard, gtk_editable_get_text (GTK_EDITABLE (visible_child)));
}
else if (strcmp (visible_child_name, "Image") == 0)
{
GtkWidget *child;
for (child = gtk_widget_get_first_child (visible_child); child; child = gtk_widget_get_next_sibling (child))
{
if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (child)))
{
GtkWidget *image = gtk_widget_get_first_child (child);
GdkPaintable *paintable = gtk_image_get_paintable (GTK_IMAGE (image));
if (GDK_IS_TEXTURE (paintable))
gdk_clipboard_set (clipboard, GDK_TYPE_TEXTURE, paintable);
else
gdk_clipboard_set (clipboard, GDK_TYPE_PAINTABLE, paintable);
break;
}
}
}
else if (strcmp (visible_child_name, "Color") == 0)
{
const GdkRGBA *color;
color = gtk_color_dialog_button_get_rgba (GTK_COLOR_DIALOG_BUTTON (visible_child));
gdk_clipboard_set (clipboard, GDK_TYPE_RGBA, color);
}
else if (strcmp (visible_child_name, "File") == 0)
{
gdk_clipboard_set (clipboard, G_TYPE_FILE, g_object_get_data (G_OBJECT (visible_child), "file"), NULL);
}
else
{
g_print ("TODO");
}
/* Set clipboard text */
gdk_clipboard_set_text (clipboard, gtk_editable_get_text (GTK_EDITABLE (entry)));
}
static void
present_value (GtkStack *dest_stack,
const GValue *value)
{
GtkWidget *child;
if (G_VALUE_HOLDS (value, G_TYPE_FILE))
{
GFile *file;
gtk_stack_set_visible_child_name (dest_stack, "File");
child = gtk_stack_get_visible_child (dest_stack);
file = g_value_get_object (value);
g_object_set (child, "label", g_file_peek_path (file), NULL);
}
else if (G_VALUE_HOLDS (value, GDK_TYPE_RGBA))
{
GdkRGBA *color;
gtk_stack_set_visible_child_name (dest_stack, "Color");
child = gtk_widget_get_first_child (gtk_stack_get_visible_child (dest_stack));
color = g_value_get_boxed (value);
g_object_set (child, "rgba", color, NULL);
}
else if (G_VALUE_HOLDS (value, GDK_TYPE_TEXTURE) ||
G_VALUE_HOLDS (value, GDK_TYPE_PAINTABLE))
{
GdkPaintable *paintable;
gtk_stack_set_visible_child_name (dest_stack, "Image");
child = gtk_stack_get_visible_child (dest_stack);
paintable = g_value_get_object (value);
g_object_set (child, "paintable", paintable, NULL);
}
else if (G_VALUE_HOLDS (value, G_TYPE_STRING))
{
gtk_stack_set_visible_child_name (dest_stack, "Text");
child = gtk_stack_get_visible_child (dest_stack);
gtk_label_set_label (GTK_LABEL (child), g_value_get_string (value));
}
}
static void
void
paste_received (GObject *source_object,
GAsyncResult *result,
gpointer user_data)
{
GtkStack *dest_stack = user_data;
GdkClipboard *clipboard;
const GValue *value;
GtkWidget *entry;
char *text;
GError *error = NULL;
clipboard = GDK_CLIPBOARD (source_object);
entry = GTK_WIDGET (user_data);
value = gdk_clipboard_read_value_finish (clipboard, result, &error);
if (value)
/* Get the resulting text of the read operation */
text = gdk_clipboard_read_text_finish (clipboard, result, &error);
if (text)
{
present_value (dest_stack, value);
/* Set the entry text */
gtk_editable_set_text (GTK_EDITABLE (entry), text);
g_free (text);
}
else
{
g_print ("%s\n", error->message);
GtkWidget *dialog;
/* Show an error about why pasting failed.
* Usually you probably want to ignore such failures,
* but for demonstration purposes, we show the error.
*/
dialog = gtk_message_dialog_new (GTK_WINDOW (window),
GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_MODAL,
GTK_MESSAGE_ERROR,
GTK_BUTTONS_CLOSE,
"Could not paste text: %s",
error->message);
g_signal_connect (dialog, "response",
G_CALLBACK (gtk_widget_destroy), NULL);
gtk_widget_show (dialog);
g_error_free (error);
}
}
void
paste_button_clicked (GtkWidget *button,
gpointer user_data)
{
GtkWidget *entry;
GdkClipboard *clipboard;
entry = GTK_WIDGET (user_data);
/* Get the clipboard object */
clipboard = gtk_widget_get_clipboard (entry);
/* Request the contents of the clipboard, contents_received will be
called when we do get the contents.
*/
gdk_clipboard_read_text_async (clipboard, NULL, paste_received, entry);
}
static GdkPaintable *
get_image_paintable (GtkImage *image)
{
const gchar *icon_name;
GtkIconTheme *icon_theme;
GtkIconInfo *icon_info;
switch (gtk_image_get_storage_type (image))
{
case GTK_IMAGE_PAINTABLE:
return g_object_ref (gtk_image_get_paintable (image));
case GTK_IMAGE_ICON_NAME:
icon_name = gtk_image_get_icon_name (image);
icon_theme = gtk_icon_theme_get_for_display (gtk_widget_get_display (GTK_WIDGET (image)));
icon_info = gtk_icon_theme_lookup_icon (icon_theme, icon_name, 48, GTK_ICON_LOOKUP_GENERIC_FALLBACK);
if (icon_info == NULL)
return NULL;
return GDK_PAINTABLE (gtk_icon_info_load_texture (icon_info));
default:
g_warning ("Image storage type %d not handled",
gtk_image_get_storage_type (image));
return NULL;
}
}
static void
paste_button_clicked (GtkStack *dest_stack,
gpointer user_data)
drag_begin (GtkWidget *widget,
GdkDrag *drag,
gpointer data)
{
GdkPaintable *paintable;
paintable = get_image_paintable (GTK_IMAGE (widget));
if (paintable)
{
gtk_drag_set_icon_paintable (drag, paintable, -2, -2);
g_object_unref (paintable);
}
}
void
drag_data_get (GtkWidget *widget,
GdkDrag *drag,
GtkSelectionData *selection_data,
guint info,
gpointer data)
{
GdkPaintable *paintable;
paintable = get_image_paintable (GTK_IMAGE (widget));
if (GDK_IS_TEXTURE (paintable))
gtk_selection_data_set_texture (selection_data, GDK_TEXTURE (paintable));
}
static void
drag_data_received (GtkWidget *widget,
GdkDrop *drop,
GtkSelectionData *selection_data,
gpointer data)
{
if (gtk_selection_data_get_length (selection_data) > 0)
{
GdkTexture *texture;
texture = gtk_selection_data_get_texture (selection_data);
gtk_image_set_from_paintable (GTK_IMAGE (data), GDK_PAINTABLE (texture));
g_object_unref (texture);
}
}
static void
copy_image (GtkMenuItem *item,
gpointer data)
{
GdkClipboard *clipboard;
GdkContentFormats *formats;
GdkPaintable *paintable;
clipboard = gtk_widget_get_clipboard (GTK_WIDGET (dest_stack));
formats = gdk_clipboard_get_formats (clipboard);
clipboard = gtk_widget_get_clipboard (GTK_WIDGET (data));
paintable = get_image_paintable (GTK_IMAGE (data));
if (gdk_content_formats_contain_gtype (formats, GDK_TYPE_TEXTURE))
gdk_clipboard_read_value_async (clipboard, GDK_TYPE_TEXTURE, 0, NULL, paste_received, dest_stack);
else if (gdk_content_formats_contain_gtype (formats, GDK_TYPE_PAINTABLE))
gdk_clipboard_read_value_async (clipboard, GDK_TYPE_PAINTABLE, 0, NULL, paste_received, dest_stack);
else if (gdk_content_formats_contain_gtype (formats, GDK_TYPE_RGBA))
gdk_clipboard_read_value_async (clipboard, GDK_TYPE_RGBA, 0, NULL, paste_received, dest_stack);
else if (gdk_content_formats_contain_gtype (formats, G_TYPE_FILE))
gdk_clipboard_read_value_async (clipboard, G_TYPE_FILE, 0, NULL, paste_received, dest_stack);
else if (gdk_content_formats_contain_gtype (formats, G_TYPE_STRING))
gdk_clipboard_read_value_async (clipboard, G_TYPE_STRING, 0, NULL, paste_received, dest_stack);
if (GDK_IS_TEXTURE (paintable))
gdk_clipboard_set_texture (clipboard, GDK_TEXTURE (paintable));
if (paintable)
g_object_unref (paintable);
}
static void
update_copy_button_sensitivity (GtkWidget *source_stack)
paste_image_received (GObject *source,
GAsyncResult *result,
gpointer data)
{
GtkButton *copy_button;
const char *visible_child_name;
GtkWidget *visible_child;
gboolean sensitive;
GdkTexture *texture;
copy_button = GTK_BUTTON (g_object_get_data (G_OBJECT (source_stack), "copy-button"));
visible_child = gtk_stack_get_visible_child (GTK_STACK (source_stack));
visible_child_name = gtk_stack_get_visible_child_name (GTK_STACK (source_stack));
if (strcmp (visible_child_name, "Text") == 0)
{
sensitive = strlen (gtk_editable_get_text (GTK_EDITABLE (visible_child))) > 0;
}
else if (strcmp (visible_child_name, "Color") == 0 ||
strcmp (visible_child_name, "Image") == 0)
{
sensitive = TRUE;
}
else if (strcmp (visible_child_name, "File") == 0)
{
sensitive = g_object_get_data (G_OBJECT (visible_child), "file") != NULL;
}
else
{
sensitive = FALSE;
}
gtk_widget_set_sensitive (GTK_WIDGET (copy_button), sensitive);
texture = gdk_clipboard_read_texture_finish (GDK_CLIPBOARD (source), result, NULL);
if (texture == NULL)
return;
gtk_image_set_from_paintable (GTK_IMAGE (data), GDK_PAINTABLE (texture));
g_object_unref (texture);
}
static void
source_changed_cb (GtkButton *copy_button,
GParamSpec *pspec,
GtkWidget *source_stack)
paste_image (GtkMenuItem *item,
gpointer data)
{
update_copy_button_sensitivity (source_stack);
GdkClipboard *clipboard;
clipboard = gtk_widget_get_clipboard (GTK_WIDGET (data));
gdk_clipboard_read_texture_async (clipboard,
NULL,
paste_image_received,
data);
}
static void
text_changed_cb (GtkButton *copy_button,
GParamSpec *pspec,
GtkWidget *entry)
pressed_cb (GtkGesture *gesture,
int n_press,
double x,
double y,
GtkWidget *image)
{
update_copy_button_sensitivity (gtk_widget_get_ancestor (entry, GTK_TYPE_STACK));
}
GtkWidget *menu;
GtkWidget *item;
static void
file_button_set_file (GtkButton *button,
GFile *file)
{
gtk_label_set_label (GTK_LABEL (gtk_button_get_child (button)), g_file_peek_path (file));
g_object_set_data_full (G_OBJECT (button), "file", g_object_ref (file), g_object_unref);
}
menu = gtk_menu_new ();
static void
file_chooser_response (GObject *source,
GAsyncResult *result,
gpointer user_data)
{
GtkFileDialog *dialog = GTK_FILE_DIALOG (source);
GtkButton *button = GTK_BUTTON (user_data);
GFile *file;
item = gtk_menu_item_new_with_mnemonic (_("_Copy"));
g_signal_connect (item, "activate", G_CALLBACK (copy_image), image);
gtk_widget_show (item);
gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
file = gtk_file_dialog_open_finish (dialog, result, NULL);
if (file)
{
file_button_set_file (button, file);
g_object_unref (file);
item = gtk_menu_item_new_with_mnemonic (_("_Paste"));
g_signal_connect (item, "activate", G_CALLBACK (paste_image), image);
gtk_widget_show (item);
gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
update_copy_button_sensitivity (gtk_widget_get_ancestor (GTK_WIDGET (button), GTK_TYPE_STACK));
}
}
static void
open_file_cb (GtkWidget *button)
{
GtkFileDialog *dialog;
dialog = gtk_file_dialog_new ();
gtk_file_dialog_open (dialog,
GTK_WINDOW (gtk_widget_get_ancestor (button, GTK_TYPE_WINDOW)),
NULL,
file_chooser_response, button);
g_object_unref (dialog);
}
static void
folder_chooser_response (GObject *source,
GAsyncResult *result,
gpointer user_data)
{
GtkFileDialog *dialog = GTK_FILE_DIALOG (source);
GtkButton *button = GTK_BUTTON (user_data);
GFile *file;
file = gtk_file_dialog_select_folder_finish (dialog, result, NULL);
if (file)
{
file_button_set_file (button, file);
g_object_unref (file);
update_copy_button_sensitivity (gtk_widget_get_ancestor (GTK_WIDGET (button), GTK_TYPE_STACK));
}
}
static void
open_folder_cb (GtkWidget *button)
{
GtkFileDialog *dialog;
dialog = gtk_file_dialog_new ();
gtk_file_dialog_select_folder (dialog,
GTK_WINDOW (gtk_widget_get_ancestor (button, GTK_TYPE_WINDOW)),
NULL,
folder_chooser_response, button);
g_object_unref (dialog);
}
static void
update_paste_button_sensitivity (GdkClipboard *clipboard,
GtkWidget *paste_button)
{
GdkContentFormats *formats;
gboolean sensitive = FALSE;
formats = gdk_clipboard_get_formats (clipboard);
if (gdk_content_formats_contain_gtype (formats, G_TYPE_FILE) ||
gdk_content_formats_contain_gtype (formats, GDK_TYPE_RGBA) ||
gdk_content_formats_contain_gtype (formats, GDK_TYPE_TEXTURE) ||
gdk_content_formats_contain_gtype (formats, GDK_TYPE_PAINTABLE) ||
gdk_content_formats_contain_gtype (formats, G_TYPE_STRING))
sensitive = TRUE;
gtk_widget_set_sensitive (paste_button, sensitive);
}
static void
unset_clipboard_handler (gpointer data)
{
GdkClipboard *clipboard = gtk_widget_get_clipboard (GTK_WIDGET (data));
g_signal_handlers_disconnect_by_func (clipboard, update_paste_button_sensitivity, data);
}
static gboolean
on_drop (GtkStack *dest_stack,
const GValue *value,
double x,
double y,
gpointer data)
{
present_value (dest_stack, value);
return TRUE;
}
static GdkContentProvider *
drag_prepare (GtkDragSource *drag_source,
double x,
double y,
gpointer data)
{
GtkWidget *button;
GValue value = G_VALUE_INIT;
button = gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (drag_source));
if (GTK_IS_TOGGLE_BUTTON (button))
{
GtkWidget *image = gtk_widget_get_first_child (button);
GdkPaintable *paintable = gtk_image_get_paintable (GTK_IMAGE (image));
if (GDK_IS_TEXTURE (paintable))
{
g_value_init (&value, GDK_TYPE_TEXTURE);
g_value_set_object (&value, paintable);
}
else
{
g_value_init (&value, GDK_TYPE_PAINTABLE);
g_value_set_object (&value, paintable);
}
}
else
{
GFile *file = g_object_get_data (G_OBJECT (button), "file");
if (file)
{
g_value_init (&value, G_TYPE_FILE);
g_value_set_object (&value, file);
}
else
return NULL;
}
return gdk_content_provider_new_for_value (&value);
gtk_menu_popup_at_pointer (GTK_MENU (menu), NULL);
}
GtkWidget *
do_clipboard (GtkWidget *do_widget)
{
static GtkWidget *window = NULL;
if (!window)
{
GtkBuilderScope *scope;
GtkBuilder *builder;
GtkWidget *button;
GtkWidget *vbox, *hbox;
GtkWidget *label;
GtkWidget *entry, *button;
GtkWidget *image;
GtkGesture *gesture;
scope = gtk_builder_cscope_new ();
gtk_builder_cscope_add_callback (scope, copy_button_clicked);
gtk_builder_cscope_add_callback (scope, paste_button_clicked);
gtk_builder_cscope_add_callback (scope, source_changed_cb);
gtk_builder_cscope_add_callback (scope, text_changed_cb);
gtk_builder_cscope_add_callback (scope, open_file_cb);
gtk_builder_cscope_add_callback (scope, open_folder_cb);
gtk_builder_cscope_add_callback (scope, on_drop);
gtk_builder_cscope_add_callback (scope, drag_prepare);
builder = gtk_builder_new ();
gtk_builder_set_scope (builder, scope);
gtk_builder_add_from_resource (builder, "/clipboard/clipboard.ui", NULL);
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_display (GTK_WINDOW (window),
gtk_widget_get_display (do_widget));
gtk_window_set_title (GTK_WINDOW (window), "Clipboard");
window = GTK_WIDGET (gtk_builder_get_object (builder, "window"));
g_object_add_weak_pointer (G_OBJECT (window), (gpointer *)&window);
gtk_window_set_display (GTK_WINDOW (window), gtk_widget_get_display (do_widget));
g_signal_connect (window, "destroy",
G_CALLBACK (gtk_widget_destroyed), &window);
button = GTK_WIDGET (gtk_builder_get_object (builder, "copy_button"));
g_object_set_data (gtk_builder_get_object (builder, "source_stack"), "copy-button", button);
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
g_object_set (vbox, "margin", 8, NULL);
button = GTK_WIDGET (gtk_builder_get_object (builder, "paste_button"));
g_signal_connect (gtk_widget_get_clipboard (button), "changed",
G_CALLBACK (update_paste_button_sensitivity), button);
g_object_set_data_full (G_OBJECT (button), "clipboard-handler", button, unset_clipboard_handler);
gtk_container_add (GTK_CONTAINER (window), vbox);
g_object_unref (builder);
g_object_unref (scope);
label = gtk_label_new ("\"Copy\" will copy the text\nin the entry to the clipboard");
gtk_container_add (GTK_CONTAINER (vbox), label);
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 4);
g_object_set (hbox, "margin", 8, NULL);
gtk_container_add (GTK_CONTAINER (vbox), hbox);
/* Create the first entry */
entry = gtk_entry_new ();
gtk_container_add (GTK_CONTAINER (hbox), entry);
/* Create the button */
button = gtk_button_new_with_mnemonic (_("_Copy"));
gtk_container_add (GTK_CONTAINER (hbox), button);
g_signal_connect (button, "clicked",
G_CALLBACK (copy_button_clicked), entry);
label = gtk_label_new ("\"Paste\" will paste the text from the clipboard to the entry");
gtk_container_add (GTK_CONTAINER (vbox), label);
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 4);
g_object_set (hbox, "margin", 8, NULL);
gtk_container_add (GTK_CONTAINER (vbox), hbox);
/* Create the second entry */
entry = gtk_entry_new ();
gtk_container_add (GTK_CONTAINER (hbox), entry);
/* Create the button */
button = gtk_button_new_with_mnemonic (_("_Paste"));
gtk_container_add (GTK_CONTAINER (hbox), button);
g_signal_connect (button, "clicked",
G_CALLBACK (paste_button_clicked), entry);
label = gtk_label_new ("Images can be transferred via the clipboard, too");
gtk_container_add (GTK_CONTAINER (vbox), label);
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 4);
g_object_set (hbox, "margin", 8, NULL);
gtk_container_add (GTK_CONTAINER (vbox), hbox);
/* Create the first image */
image = gtk_image_new_from_icon_name ("dialog-warning");
gtk_container_add (GTK_CONTAINER (hbox), image);
/* make image a drag source */
gtk_drag_source_set (image, GDK_BUTTON1_MASK, NULL, GDK_ACTION_COPY);
gtk_drag_source_add_image_targets (image);
g_signal_connect (image, "drag-begin",
G_CALLBACK (drag_begin), image);
g_signal_connect (image, "drag-data-get",
G_CALLBACK (drag_data_get), image);
/* accept drops on image */
gtk_drag_dest_set (image, GTK_DEST_DEFAULT_ALL,
NULL, GDK_ACTION_COPY);
gtk_drag_dest_add_image_targets (image);
g_signal_connect (image, "drag-data-received",
G_CALLBACK (drag_data_received), image);
/* context menu on image */
gesture = gtk_gesture_click_new ();
gtk_gesture_single_set_button (GTK_GESTURE_SINGLE (gesture), GDK_BUTTON_SECONDARY);
g_signal_connect (gesture, "pressed", G_CALLBACK (pressed_cb), image);
gtk_widget_add_controller (image, GTK_EVENT_CONTROLLER (gesture));
/* Create the second image */
image = gtk_image_new_from_icon_name ("process-stop");
gtk_container_add (GTK_CONTAINER (hbox), image);
/* make image a drag source */
gtk_drag_source_set (image, GDK_BUTTON1_MASK, NULL, GDK_ACTION_COPY);
gtk_drag_source_add_image_targets (image);
g_signal_connect (image, "drag-begin",
G_CALLBACK (drag_begin), image);
g_signal_connect (image, "drag-data-get",
G_CALLBACK (drag_data_get), image);
/* accept drops on image */
gtk_drag_dest_set (image, GTK_DEST_DEFAULT_ALL,
NULL, GDK_ACTION_COPY);
gtk_drag_dest_add_image_targets (image);
g_signal_connect (image, "drag-data-received",
G_CALLBACK (drag_data_received), image);
/* context menu on image */
gesture = gtk_gesture_click_new ();
gtk_gesture_single_set_button (GTK_GESTURE_SINGLE (gesture), GDK_BUTTON_SECONDARY);
g_signal_connect (gesture, "pressed", G_CALLBACK (pressed_cb), image);
gtk_widget_add_controller (image, GTK_EVENT_CONTROLLER (gesture));
}
if (!gtk_widget_get_visible (window))
gtk_widget_set_visible (window, TRUE);
gtk_widget_show (window);
else
gtk_window_destroy (GTK_WINDOW (window));
gtk_widget_destroy (window);
return window;
}

View File

@@ -1,362 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<object class="GtkWindow" id="window">
<property name="resizable">1</property>
<property name="title">Clipboard</property>
<accessibility>
<relation name="described-by">label</relation>
</accessibility>
<child>
<object class="GtkBox">
<property name="orientation">vertical</property>
<property name="margin-start">12</property>
<property name="margin-end">12</property>
<property name="margin-top">12</property>
<property name="margin-bottom">12</property>
<property name="spacing">12</property>
<child>
<object class="GtkLabel" id="label">
<property name="label">“Copy” will copy the selected data the clipboard, “Paste” will show the current clipboard contents. You can also drag the data to the bottom.</property>
<property name="wrap">1</property>
<property name="max-width-chars">40</property>
</object>
</child>
<child>
<object class="GtkBox">
<property name="spacing">12</property>
<child>
<object class="GtkDropDown" id="source_chooser">
<accessibility>
<property name="label">Source Type</property>
</accessibility>
<property name="valign">center</property>
<property name="model">
<object class="GtkStringList">
<items>
<item>Text</item>
<item>Color</item>
<item>Image</item>
<item>File</item>
<item>Folder</item>
</items>
</object>
</property>
</object>
</child>
<child>
<object class="GtkStack" id="source_stack">
<signal name="notify::visible-child" handler="source_changed_cb" object="copy_button"/>
<property name="vexpand">1</property>
<binding name="visible-child-name">
<lookup name="string" type="GtkStringObject">
<lookup name="selected-item">
source_chooser
</lookup>
</lookup>
</binding>
<child>
<object class="GtkStackPage">
<property name="name">Text</property>
<property name="child">
<object class="GtkEntry" id="source_text">
<accessibility>
<property name="label">Text Drag Source</property>
</accessibility>
<property name="valign">center</property>
<signal name="notify::text" handler="text_changed_cb" object="copy_button"/>
<property name="text">Copy this!</property>
</object>
</property>
</object>
</child>
<child>
<object class="GtkStackPage">
<property name="name">Color</property>
<property name="child">
<object class="GtkColorDialogButton" id="source_color">
<accessibility>
<property name="label">Color Drag Source</property>
</accessibility>
<property name="dialog">
<object class="GtkColorDialog">
</object>
</property>
<property name="valign">center</property>
<property name="rgba">purple</property>
</object>
</property>
</object>
</child>
<child>
<object class="GtkStackPage">
<property name="name">Image</property>
<property name="child">
<object class="GtkBox">
<property name="valign">center</property>
<style>
<class name="linked"/>
</style>
<child>
<object class="GtkToggleButton" id="image_rose">
<accessibility>
<property name="label">Photo Drag Source</property>
</accessibility>
<property name="active">1</property>
<child>
</child>
<child>
<object class="GtkImage">
<accessibility>
<property name="label">Portland Rose Photo</property>
</accessibility>
<style>
<class name="large-icons"/>
</style>
<property name="paintable">resource:///transparent/portland-rose.jpg</property>
</object>
</child>
</object>
</child>
<child>
<object class="GtkToggleButton" id="image_floppy">
<accessibility>
<property name="label">Icon Drag Source</property>
</accessibility>
<property name="group">image_rose</property>
<child>
<object class="GtkDragSource">
<signal name="prepare" handler="drag_prepare"/>
</object>
</child>
<child>
<object class="GtkImage">
<accessibility>
<property name="label">Floppy Buddy Icon</property>
</accessibility>
<style>
<class name="large-icons"/>
</style>
<property name="paintable">resource:///images/floppybuddy.gif</property>
</object>
</child>
</object>
</child>
<child>
<object class="GtkToggleButton" id="image_logo">
<accessibility>
<property name="label">SVG Drag Source</property>
</accessibility>
<property name="group">image_floppy</property>
<child>
<object class="GtkDragSource">
<signal name="prepare" handler="drag_prepare"/>
</object>
</child>
<child>
<object class="GtkImage">
<accessibility>
<property name="label">gtk-demo logo</property>
</accessibility>
<style>
<class name="large-icons"/>
</style>
<property name="paintable">resource:///images/org.gtk.Demo4.svg</property>
</object>
</child>
</object>
</child>
</object>
</property>
</object>
</child>
<child>
<object class="GtkStackPage">
<property name="name">File</property>
<property name="child">
<object class="GtkButton" id="source_file">
<accessibility>
<property name="label">File Drag Source</property>
</accessibility>
<child>
<object class="GtkDragSource">
<property name="propagation-phase">capture</property>
<signal name="prepare" handler="drag_prepare"/>
</object>
</child>
<property name="valign">center</property>
<property name="child">
<object class="GtkLabel">
<property name="label">—</property>
<property name="xalign">0</property>
<property name="ellipsize">start</property>
</object>
</property>
<signal name="clicked" handler="open_file_cb"/>
</object>
</property>
</object>
</child>
<child>
<object class="GtkStackPage">
<property name="name">Folder</property>
<property name="child">
<object class="GtkButton" id="source_folder">
<accessibility>
<property name="label">Folder Drag Source</property>
</accessibility>
<child>
<object class="GtkDragSource">
<property name="propagation-phase">capture</property>
<signal name="prepare" handler="drag_prepare"/>
</object>
</child>
<property name="valign">center</property>
<property name="child">
<object class="GtkLabel">
<property name="label">—</property>
<property name="xalign">0</property>
<property name="ellipsize">start</property>
</object>
</property>
<signal name="clicked" handler="open_folder_cb"/>
</object>
</property>
</object>
</child>
</object>
</child>
<child>
<object class="GtkButton" id="copy_button">
<property name="valign">center</property>
<property name="label" translatable="yes">_Copy</property>
<signal name="clicked" handler="copy_button_clicked" object="source_stack"/>
<property name="use-underline">1</property>
</object>
</child>
</object>
</child>
<child>
<object class="GtkSeparator">
</object>
</child>
<child>
<object class="GtkBox">
<property name="spacing">12</property>
<child>
<object class="GtkDropTarget">
<property name="actions">copy</property>
<property name="formats">GdkTexture GdkPaintable GFile GdkRGBA gchararray</property>
<signal name="drop" handler="on_drop" object="dest_stack"/>
</object>
</child>
<child>
<object class="GtkButton" id="paste_button">
<property name="label" translatable="yes">_Paste</property>
<signal name="clicked" handler="paste_button_clicked" object="dest_stack"/>
<property name="use-underline">1</property>
</object>
</child>
<child>
<object class="GtkLabel" id="paste_label">
<property name="xalign">0</property>
<binding name="label">
<lookup name="visible-child-name" type="GtkStack">
dest_stack
</lookup>
</binding>
</object>
</child>
<child>
<object class="GtkStack" id="dest_stack">
<property name="halign">end</property>
<property name="valign">center</property>
<child>
<object class="GtkStackPage">
<property name="name"></property>
<property name="child">
<object class="GtkLabel">
</object>
</property>
</object>
</child>
<child>
<object class="GtkStackPage">
<property name="name">Text</property>
<property name="child">
<object class="GtkLabel">
<accessibility>
<relation name="labelled-by">paste_label</relation>
</accessibility>
<property name="halign">end</property>
<property name="valign">center</property>
<property name="xalign">0</property>
<property name="ellipsize">end</property>
</object>
</property>
</object>
</child>
<child>
<object class="GtkStackPage">
<property name="name">Image</property>
<property name="child">
<object class="GtkImage">
<accessibility>
<relation name="labelled-by">paste_label</relation>
</accessibility>
<property name="halign">end</property>
<property name="valign">center</property>
<style>
<class name="large-icons"/>
</style>
</object>
</property>
</object>
</child>
<child>
<object class="GtkStackPage">
<property name="name">Color</property>
<property name="child">
<object class="GtkBox">
<property name="halign">end</property>
<property name="valign">center</property>
<child>
<object class="GtkColorSwatch">
<accessibility>
<relation name="labelled-by">paste_label</relation>
</accessibility>
<property name="accessible-role">img</property>
<property name="can-focus">0</property>
<property name="selectable">0</property>
<property name="has-menu">0</property>
</object>
</child>
</object>
</property>
</object>
</child>
<child>
<object class="GtkStackPage">
<property name="name">File</property>
<property name="child">
<object class="GtkLabel">
<accessibility>
<relation name="labelled-by">paste_label</relation>
</accessibility>
<property name="halign">end</property>
<property name="valign">center</property>
<property name="xalign">0</property>
<property name="hexpand">1</property>
<property name="ellipsize">start</property>
</object>
</property>
</object>
</child>
</object>
</child>
</object>
</child>
</object>
</child>
</object>
</interface>

View File

@@ -1,224 +0,0 @@
// Originally from: https://www.shadertoy.com/view/3ljyDD
// License CC0: Hexagonal tiling + cog wheels
// Nothing fancy, just hexagonal tiling + cog wheels
#define PI 3.141592654
#define TAU (2.0*PI)
#define MROT(a) mat2(cos(a), sin(a), -sin(a), cos(a))
float hash(in vec2 co) {
return fract(sin(dot(co.xy ,vec2(12.9898,58.233))) * 13758.5453);
}
float pcos(float a) {
return 0.5 + 0.5*cos(a);
}
void rot(inout vec2 p, float a) {
float c = cos(a);
float s = sin(a);
p = vec2(c*p.x + s*p.y, -s*p.x + c*p.y);
}
float modPolar(inout vec2 p, float repetitions) {
float angle = 2.0*PI/repetitions;
float a = atan(p.y, p.x) + angle/2.;
float r = length(p);
float c = floor(a/angle);
a = mod(a,angle) - angle/2.;
p = vec2(cos(a), sin(a))*r;
// For an odd number of repetitions, fix cell index of the cell in -x direction
// (cell index would be e.g. -5 and 5 in the two halves of the cell):
if (abs(c) >= (repetitions/2.0)) c = abs(c);
return c;
}
float pmin(float a, float b, float k) {
float h = clamp( 0.5+0.5*(b-a)/k, 0.0, 1.0 );
return mix( b, a, h ) - k*h*(1.0-h);
}
const vec2 sz = vec2(1.0, sqrt(3.0));
const vec2 hsz = 0.5*sz;
const float smallCount = 16.0;
vec2 hextile(inout vec2 p) {
// See Art of Code: Hexagonal Tiling Explained!
// https://www.youtube.com/watch?v=VmrIDyYiJBA
vec2 p1 = mod(p, sz)-hsz;
vec2 p2 = mod(p - hsz*1.0, sz)-hsz;
vec2 p3 = mix(p2, p1, vec2(length(p1) < length(p2)));
vec2 n = p3 - p;
p = p3;
return n;
}
float circle(vec2 p, float r) {
return length(p) - r;
}
float box(vec2 p, vec2 b) {
vec2 d = abs(p)-b;
return length(max(d,0.0)) + min(max(d.x,d.y),0.0);
}
float unevenCapsule(vec2 p, float r1, float r2, float h) {
p.x = abs(p.x);
float b = (r1-r2)/h;
float a = sqrt(1.0-b*b);
float k = dot(p,vec2(-b,a));
if( k < 0.0 ) return length(p) - r1;
if( k > a*h ) return length(p-vec2(0.0,h)) - r2;
return dot(p, vec2(a,b) ) - r1;
}
float cogwheel(vec2 p, float innerRadius, float outerRadius, float cogs, float holes) {
float cogWidth = 0.25*innerRadius*TAU/cogs;
float d0 = circle(p, innerRadius);
vec2 icp = p;
modPolar(icp, holes);
icp -= vec2(innerRadius*0.55, 0.0);
float d1 = circle(icp, innerRadius*0.25);
vec2 cp = p;
modPolar(cp, cogs);
cp -= vec2(innerRadius, 0.0);
float d2 = unevenCapsule(cp.yx, cogWidth, cogWidth*0.75, (outerRadius-innerRadius));
float d3 = circle(p, innerRadius*0.20);
float d = 1E6;
d = min(d, d0);
d = pmin(d, d2, 0.5*cogWidth);
d = min(d, d2);
d = max(d, -d1);
d = max(d, -d3);
return d;
}
float ccell1(vec2 p, float r) {
float d = 1E6;
const float bigCount = 60.0;
vec2 cp0 = p;
rot(cp0, -iTime*TAU/bigCount);
float d0 = cogwheel(cp0, 0.36, 0.38, bigCount, 5.0);
vec2 cp1 = p;
float nm = modPolar(cp1, 6.0);
cp1 -= vec2(0.5, 0.0);
rot(cp1, 0.2+TAU*nm/2.0 + iTime*TAU/smallCount);
float d1 = cogwheel(cp1, 0.11, 0.125, smallCount, 5.0);
d = min(d, d0);
d = min(d, d1);
return d;
}
float ccell2(vec2 p, float r) {
float d = 1E6;
vec2 cp0 = p;
float nm = modPolar(cp0, 6.0);
vec2 cp1 = cp0;
const float off = 0.275;
const float count = smallCount + 2.0;
cp0 -= vec2(off, 0.0);
rot(cp0, 0.+TAU*nm/2.0 - iTime*TAU/count);
float d0 = cogwheel(cp0, 0.09, 0.105, count, 5.0);
cp1 -= vec2(0.5, 0.0);
rot(cp1, 0.2+TAU*nm/2.0 + iTime*TAU/smallCount);
float d1 = cogwheel(cp1, 0.11, 0.125, smallCount, 5.0);
float l = length(p);
float d2 = l - (off+0.055);
float d3 = d2 + 0.020;;
vec2 tp0 = p;
modPolar(tp0, 60.0);
tp0.x -= off;
float d4 = box(tp0, vec2(0.0125, 0.005));
float ctime = -(iTime*0.05 + r)*TAU;
vec2 tp1 = p;
rot(tp1, ctime*12.0);
tp1.x -= 0.13;
float d5 = box(tp1, vec2(0.125, 0.005));
vec2 tp2 = p;
rot(tp2, ctime);
tp2.x -= 0.13*0.5;
float d6 = box(tp2, vec2(0.125*0.5, 0.0075));
float d7 = l - 0.025;
float d8 = l - 0.0125;
d = min(d, d0);
d = min(d, d1);
d = min(d, d2);
d = max(d, -d3);
d = min(d, d4);
d = min(d, d5);
d = min(d, d6);
d = min(d, d7);
d = max(d, -d8);
return d;
}
float df(vec2 p, float scale, inout vec2 nn) {
p /= scale;
nn = hextile(p);
nn = floor(nn + 0.5);
float r = hash(nn);
float d;;
if (r < 0.5) {
d = ccell1(p, r);
} else {
d = ccell2(p, r);
}
return d*scale;
}
vec3 postProcess(vec3 col, vec2 q) {
//col = saturate(col);
col=pow(clamp(col,0.0,1.0),vec3(0.75));
col=col*0.6+0.4*col*col*(3.0-2.0*col); // contrast
col=mix(col, vec3(dot(col, vec3(0.33))), -0.4); // satuation
col*=0.5+0.5*pow(19.0*q.x*q.y*(1.0-q.x)*(1.0-q.y),0.7); // vigneting
return col;
}
void mainImage(out vec4 fragColor, vec2 fragCoord) {
vec2 q = fragCoord/iResolution.xy;
vec2 p = -1.0 + 2.0*q;
p.x *= iResolution.x/iResolution.y;
float tm = iTime*0.1;
p += vec2(cos(tm), sin(tm*sqrt(0.5)));
float z = mix(0.5, 1.0, pcos(tm*sqrt(0.3)));
float aa = 4.0 / iResolution.y;
vec2 nn = vec2(0.0);
float d = df(p, z, nn);
vec3 col = vec3(160.0)/vec3(255.0);
vec3 baseCol = vec3(0.3);
vec4 logoCol = vec4(baseCol, 1.0)*smoothstep(-aa, 0.0, -d);
col = mix(col, logoCol.xyz, pow(logoCol.w, 8.0));
col += 0.4*pow(abs(sin(20.0*d)), 0.6);
col = postProcess(col, q);
fragColor = vec4(col, 1.0);
}

View File

@@ -1,226 +0,0 @@
uniform float iTime;
// Originally from: https://www.shadertoy.com/view/3ljyDD
// License CC0: Hexagonal tiling + cog wheels
// Nothing fancy, just hexagonal tiling + cog wheels
#define PI 3.141592654
#define TAU (2.0*PI)
#define MROT(a) mat2(cos(a), sin(a), -sin(a), cos(a))
float hash(in vec2 co) {
return fract(sin(dot(co.xy ,vec2(12.9898,58.233))) * 13758.5453);
}
float pcos(float a) {
return 0.5 + 0.5*cos(a);
}
void rot(inout vec2 p, float a) {
float c = cos(a);
float s = sin(a);
p = vec2(c*p.x + s*p.y, -s*p.x + c*p.y);
}
float modPolar(inout vec2 p, float repetitions) {
float angle = 2.0*PI/repetitions;
float a = atan(p.y, p.x) + angle/2.;
float r = length(p);
float c = floor(a/angle);
a = mod(a,angle) - angle/2.;
p = vec2(cos(a), sin(a))*r;
// For an odd number of repetitions, fix cell index of the cell in -x direction
// (cell index would be e.g. -5 and 5 in the two halves of the cell):
if (abs(c) >= (repetitions/2.0)) c = abs(c);
return c;
}
float pmin(float a, float b, float k) {
float h = clamp( 0.5+0.5*(b-a)/k, 0.0, 1.0 );
return mix( b, a, h ) - k*h*(1.0-h);
}
const vec2 sz = vec2(1.0, sqrt(3.0));
const vec2 hsz = 0.5*sz;
const float smallCount = 16.0;
vec2 hextile(inout vec2 p) {
// See Art of Code: Hexagonal Tiling Explained!
// https://www.youtube.com/watch?v=VmrIDyYiJBA
vec2 p1 = mod(p, sz)-hsz;
vec2 p2 = mod(p - hsz*1.0, sz)-hsz;
vec2 p3 = mix(p2, p1, vec2(length(p1) < length(p2)));
vec2 n = p3 - p;
p = p3;
return n;
}
float circle(vec2 p, float r) {
return length(p) - r;
}
float box(vec2 p, vec2 b) {
vec2 d = abs(p)-b;
return length(max(d,0.0)) + min(max(d.x,d.y),0.0);
}
float unevenCapsule(vec2 p, float r1, float r2, float h) {
p.x = abs(p.x);
float b = (r1-r2)/h;
float a = sqrt(1.0-b*b);
float k = dot(p,vec2(-b,a));
if( k < 0.0 ) return length(p) - r1;
if( k > a*h ) return length(p-vec2(0.0,h)) - r2;
return dot(p, vec2(a,b) ) - r1;
}
float cogwheel(vec2 p, float innerRadius, float outerRadius, float cogs, float holes) {
float cogWidth = 0.25*innerRadius*TAU/cogs;
float d0 = circle(p, innerRadius);
vec2 icp = p;
modPolar(icp, holes);
icp -= vec2(innerRadius*0.55, 0.0);
float d1 = circle(icp, innerRadius*0.25);
vec2 cp = p;
modPolar(cp, cogs);
cp -= vec2(innerRadius, 0.0);
float d2 = unevenCapsule(cp.yx, cogWidth, cogWidth*0.75, (outerRadius-innerRadius));
float d3 = circle(p, innerRadius*0.20);
float d = 1E6;
d = min(d, d0);
d = pmin(d, d2, 0.5*cogWidth);
d = min(d, d2);
d = max(d, -d1);
d = max(d, -d3);
return d;
}
float ccell1(vec2 p, float r) {
float d = 1E6;
const float bigCount = 60.0;
vec2 cp0 = p;
rot(cp0, -iTime*TAU/bigCount);
float d0 = cogwheel(cp0, 0.36, 0.38, bigCount, 5.0);
vec2 cp1 = p;
float nm = modPolar(cp1, 6.0);
cp1 -= vec2(0.5, 0.0);
rot(cp1, 0.2+TAU*nm/2.0 + iTime*TAU/smallCount);
float d1 = cogwheel(cp1, 0.11, 0.125, smallCount, 5.0);
d = min(d, d0);
d = min(d, d1);
return d;
}
float ccell2(vec2 p, float r) {
float d = 1E6;
vec2 cp0 = p;
float nm = modPolar(cp0, 6.0);
vec2 cp1 = cp0;
const float off = 0.275;
const float count = smallCount + 2.0;
cp0 -= vec2(off, 0.0);
rot(cp0, 0.+TAU*nm/2.0 - iTime*TAU/count);
float d0 = cogwheel(cp0, 0.09, 0.105, count, 5.0);
cp1 -= vec2(0.5, 0.0);
rot(cp1, 0.2+TAU*nm/2.0 + iTime*TAU/smallCount);
float d1 = cogwheel(cp1, 0.11, 0.125, smallCount, 5.0);
float l = length(p);
float d2 = l - (off+0.055);
float d3 = d2 + 0.020;;
vec2 tp0 = p;
modPolar(tp0, 60.0);
tp0.x -= off;
float d4 = box(tp0, vec2(0.0125, 0.005));
float ctime = -(iTime*0.05 + r)*TAU;
vec2 tp1 = p;
rot(tp1, ctime*12.0);
tp1.x -= 0.13;
float d5 = box(tp1, vec2(0.125, 0.005));
vec2 tp2 = p;
rot(tp2, ctime);
tp2.x -= 0.13*0.5;
float d6 = box(tp2, vec2(0.125*0.5, 0.0075));
float d7 = l - 0.025;
float d8 = l - 0.0125;
d = min(d, d0);
d = min(d, d1);
d = min(d, d2);
d = max(d, -d3);
d = min(d, d4);
d = min(d, d5);
d = min(d, d6);
d = min(d, d7);
d = max(d, -d8);
return d;
}
float df(vec2 p, float scale, inout vec2 nn) {
p /= scale;
nn = hextile(p);
nn = floor(nn + 0.5);
float r = hash(nn);
float d;;
if (r < 0.5) {
d = ccell1(p, r);
} else {
d = ccell2(p, r);
}
return d*scale;
}
vec3 postProcess(vec3 col, vec2 q) {
//col = saturate(col);
col=pow(clamp(col,0.0,1.0),vec3(0.75));
col=col*0.6+0.4*col*col*(3.0-2.0*col); // contrast
col=mix(col, vec3(dot(col, vec3(0.33))), -0.4); // satuation
col*=0.5+0.5*pow(19.0*q.x*q.y*(1.0-q.x)*(1.0-q.y),0.7); // vigneting
return col;
}
void mainImage(out vec4 fragColor, in vec2 fragCoord, in vec2 resolution, in vec2 uv) {
vec2 q = fragCoord/resolution.xy;
vec2 p = -1.0 + 2.0*q;
p.x *= resolution.x/resolution.y;
float tm = iTime*0.1;
p += vec2(cos(tm), sin(tm*sqrt(0.5)));
float z = mix(0.5, 1.0, pcos(tm*sqrt(0.3)));
float aa = 4.0 / resolution.y;
vec2 nn = vec2(0.0);
float d = df(p, z, nn);
vec3 col = vec3(160.0)/vec3(255.0);
vec3 baseCol = vec3(0.3);
vec4 logoCol = vec4(baseCol, 1.0)*smoothstep(-aa, 0.0, -d);
col = mix(col, logoCol.xyz, pow(logoCol.w, 8.0));
col += 0.4*pow(abs(sin(20.0*d)), 0.6);
col = postProcess(col, q);
fragColor = vec4(col, 1.0);
}

File diff suppressed because it is too large Load Diff

116
demos/gtk-demo/colorsel.c Normal file
View File

@@ -0,0 +1,116 @@
/* Color Chooser
*
* A GtkColorChooser lets the user choose a color. There are several
* implementations of the GtkColorChooser interface in GTK. The
* GtkColorChooserDialog is a prebuilt dialog containing a
* GtkColorChooserWidget.
*/
#include <gtk/gtk.h>
static GtkWidget *window = NULL;
static GtkWidget *da;
static GdkRGBA color;
static GtkWidget *frame;
/* draw callback for the drawing area
*/
static void
draw_function (GtkDrawingArea *da,
cairo_t *cr,
int width,
int height,
gpointer data)
{
gdk_cairo_set_source_rgba (cr, &color);
cairo_paint (cr);
}
static void
response_cb (GtkDialog *dialog,
gint response_id,
gpointer user_data)
{
if (response_id == GTK_RESPONSE_OK)
{
gtk_color_chooser_get_rgba (GTK_COLOR_CHOOSER (dialog), &color);
gtk_widget_queue_draw (da);
}
gtk_widget_destroy (GTK_WIDGET (dialog));
}
static void
change_color_callback (GtkWidget *button,
gpointer data)
{
GtkWidget *dialog;
dialog = gtk_color_chooser_dialog_new ("Changing color", GTK_WINDOW (window));
gtk_window_set_modal (GTK_WINDOW (dialog), TRUE);
gtk_color_chooser_set_rgba (GTK_COLOR_CHOOSER (dialog), &color);
g_signal_connect (dialog, "response",
G_CALLBACK (response_cb), NULL);
gtk_widget_show (dialog);
}
GtkWidget *
do_colorsel (GtkWidget *do_widget)
{
GtkWidget *vbox;
GtkWidget *button;
if (!window)
{
color.red = 0;
color.blue = 1;
color.green = 0;
color.alpha = 1;
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_display (GTK_WINDOW (window),
gtk_widget_get_display (do_widget));
gtk_window_set_title (GTK_WINDOW (window), "Color Chooser");
gtk_window_set_resizable (GTK_WINDOW (window), FALSE);
g_signal_connect (window, "destroy",
G_CALLBACK (gtk_widget_destroyed), &window);
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 8);
g_object_set (vbox, "margin", 12, NULL);
gtk_container_add (GTK_CONTAINER (window), vbox);
/*
* Create the color swatch area
*/
frame = gtk_frame_new (NULL);
gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
gtk_container_add (GTK_CONTAINER (vbox), frame);
da = gtk_drawing_area_new ();
gtk_drawing_area_set_content_width (GTK_DRAWING_AREA (da), 200);
gtk_drawing_area_set_content_height (GTK_DRAWING_AREA (da), 200);
gtk_drawing_area_set_draw_func (GTK_DRAWING_AREA (da), draw_function, NULL, NULL);
gtk_container_add (GTK_CONTAINER (frame), da);
button = gtk_button_new_with_mnemonic ("_Change the above color");
gtk_widget_set_halign (button, GTK_ALIGN_END);
gtk_widget_set_valign (button, GTK_ALIGN_CENTER);
gtk_container_add (GTK_CONTAINER (vbox), button);
g_signal_connect (button, "clicked",
G_CALLBACK (change_color_callback), NULL);
}
if (!gtk_widget_get_visible (window))
gtk_widget_show (window);
else
gtk_widget_destroy (window);
return window;
}

View File

@@ -1,5 +1,4 @@
/* Combo Boxes
* #Keywords: GtkCellRenderer
*
* The GtkComboBox widget allows to select one option out of a list.
* The GtkComboBoxEntry additionally allows the user to enter a value
@@ -11,8 +10,6 @@
#include <glib/gi18n.h>
#include <gtk/gtk.h>
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
enum
{
ICON_NAME_COL,
@@ -22,7 +19,7 @@ enum
static GtkTreeModel *
create_icon_store (void)
{
const char *icon_names[6] = {
const gchar *icon_names[6] = {
"dialog-warning",
"process-stop",
"document-new",
@@ -30,7 +27,7 @@ create_icon_store (void)
NULL,
"document-open"
};
const char *labels[6] = {
const gchar *labels[6] = {
N_("Warning"),
N_("Stop"),
N_("New"),
@@ -41,7 +38,7 @@ create_icon_store (void)
GtkTreeIter iter;
GtkListStore *store;
int i;
gint i;
store = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_STRING);
@@ -80,7 +77,7 @@ set_sensitive (GtkCellLayout *cell_layout,
gpointer data)
{
GtkTreePath *path;
int *indices;
gint *indices;
gboolean sensitive;
path = gtk_tree_model_get_path (tree_model, iter);
@@ -114,8 +111,8 @@ static GtkTreeModel *
create_capital_store (void)
{
struct {
const char *group;
const char *capital;
gchar *group;
gchar *capital;
} capitals[] = {
{ "A - B", NULL },
{ NULL, "Albany" },
@@ -178,7 +175,7 @@ create_capital_store (void)
GtkTreeIter iter, iter2;
GtkTreeStore *store;
int i;
gint i;
store = gtk_tree_store_new (1, G_TYPE_STRING);
@@ -237,7 +234,7 @@ typedef struct _MaskEntry MaskEntry;
struct _MaskEntry
{
GtkEntry entry;
const char *mask;
gchar *mask;
};
typedef struct _MaskEntryClass MaskEntryClass;
@@ -249,7 +246,6 @@ struct _MaskEntryClass
static void mask_entry_editable_init (GtkEditableInterface *iface);
static GType mask_entry_get_type (void);
G_DEFINE_TYPE_WITH_CODE (MaskEntry, mask_entry, GTK_TYPE_ENTRY,
G_IMPLEMENT_INTERFACE (GTK_TYPE_EDITABLE,
mask_entry_editable_init));
@@ -314,36 +310,32 @@ do_combobox (GtkWidget *do_widget)
if (!window)
{
window = gtk_window_new ();
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_display (GTK_WINDOW (window),
gtk_widget_get_display (do_widget));
gtk_window_set_title (GTK_WINDOW (window), "Combo Boxes");
g_object_add_weak_pointer (G_OBJECT (window), (gpointer *)&window);
g_signal_connect (window, "destroy",
G_CALLBACK (gtk_widget_destroyed), &window);
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 2);
gtk_widget_set_margin_start (vbox, 10);
gtk_widget_set_margin_end (vbox, 10);
gtk_widget_set_margin_top (vbox, 10);
gtk_widget_set_margin_bottom (vbox, 10);
gtk_window_set_child (GTK_WINDOW (window), vbox);
g_object_set (vbox, "margin", 10, NULL);
gtk_container_add (GTK_CONTAINER (window), vbox);
/* A combobox demonstrating cell renderers, separators and
* insensitive rows
*/
frame = gtk_frame_new ("Items with icons");
gtk_box_append (GTK_BOX (vbox), frame);
gtk_container_add (GTK_CONTAINER (vbox), frame);
box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
gtk_widget_set_margin_start (box, 5);
gtk_widget_set_margin_end (box, 5);
gtk_widget_set_margin_top (box, 5);
gtk_widget_set_margin_bottom (box, 5);
gtk_frame_set_child (GTK_FRAME (frame), box);
g_object_set (box, "margin", 5, NULL);
gtk_container_add (GTK_CONTAINER (frame), box);
model = create_icon_store ();
combo = gtk_combo_box_new_with_model (model);
g_object_unref (model);
gtk_box_append (GTK_BOX (box), combo);
gtk_container_add (GTK_CONTAINER (box), combo);
renderer = gtk_cell_renderer_pixbuf_new ();
gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo), renderer, FALSE);
@@ -375,19 +367,16 @@ do_combobox (GtkWidget *do_widget)
/* A combobox demonstrating trees.
*/
frame = gtk_frame_new ("Where are we ?");
gtk_box_append (GTK_BOX (vbox), frame);
gtk_container_add (GTK_CONTAINER (vbox), frame);
box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
gtk_widget_set_margin_start (box, 5);
gtk_widget_set_margin_end (box, 5);
gtk_widget_set_margin_top (box, 5);
gtk_widget_set_margin_bottom (box, 5);
gtk_frame_set_child (GTK_FRAME (frame), box);
g_object_set (box, "margin", 5, NULL);
gtk_container_add (GTK_CONTAINER (frame), box);
model = create_capital_store ();
combo = gtk_combo_box_new_with_model (model);
g_object_unref (model);
gtk_box_append (GTK_BOX (box), combo);
gtk_container_add (GTK_CONTAINER (box), combo);
renderer = gtk_cell_renderer_text_new ();
gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo), renderer, TRUE);
@@ -406,52 +395,47 @@ do_combobox (GtkWidget *do_widget)
/* A GtkComboBoxEntry with validation */
frame = gtk_frame_new ("Editable");
gtk_box_append (GTK_BOX (vbox), frame);
gtk_container_add (GTK_CONTAINER (vbox), frame);
box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
gtk_widget_set_margin_start (box, 5);
gtk_widget_set_margin_end (box, 5);
gtk_widget_set_margin_top (box, 5);
gtk_widget_set_margin_bottom (box, 5);
gtk_frame_set_child (GTK_FRAME (frame), box);
g_object_set (box, "margin", 5, NULL);
gtk_container_add (GTK_CONTAINER (frame), box);
combo = gtk_combo_box_text_new_with_entry ();
fill_combo_entry (combo);
gtk_box_append (GTK_BOX (box), combo);
gtk_container_add (GTK_CONTAINER (box), combo);
entry = g_object_new (TYPE_MASK_ENTRY, NULL);
MASK_ENTRY (entry)->mask = "^([0-9]*|One|Two|2\302\275|Three)$";
gtk_combo_box_set_child (GTK_COMBO_BOX (combo), entry);
gtk_container_remove (GTK_CONTAINER (combo), gtk_bin_get_child (GTK_BIN (combo)));
gtk_container_add (GTK_CONTAINER (combo), entry);
/* A combobox with string IDs */
frame = gtk_frame_new ("String IDs");
gtk_box_append (GTK_BOX (vbox), frame);
gtk_container_add (GTK_CONTAINER (vbox), frame);
box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
gtk_widget_set_margin_start (box, 5);
gtk_widget_set_margin_end (box, 5);
gtk_widget_set_margin_top (box, 5);
gtk_widget_set_margin_bottom (box, 5);
gtk_frame_set_child (GTK_FRAME (frame), box);
g_object_set (box, "margin", 5, NULL);
gtk_container_add (GTK_CONTAINER (frame), box);
combo = gtk_combo_box_text_new ();
gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), "never", "Not visible");
gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), "when-active", "Visible when active");
gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), "always", "Always visible");
gtk_box_append (GTK_BOX (box), combo);
gtk_container_add (GTK_CONTAINER (box), combo);
entry = gtk_entry_new ();
g_object_bind_property (combo, "active-id",
entry, "text",
G_BINDING_BIDIRECTIONAL);
gtk_box_append (GTK_BOX (box), entry);
gtk_container_add (GTK_CONTAINER (box), entry);
}
if (!gtk_widget_get_visible (window))
gtk_widget_set_visible (window, TRUE);
gtk_widget_show (window);
else
gtk_window_destroy (GTK_WINDOW (window));
gtk_widget_destroy (window);
return window;
}

View File

@@ -1,16 +1,8 @@
/* Constraints/Simple Constraints
* #Keywords: GtkLayoutManager
/* Constraints/Simple
*
* GtkConstraintLayout provides a layout manager that uses relations
* between widgets (also known as constraints) to compute the position
* between widgets (also known as "constraints") to compute the position
* and size of each child.
*
* In addition to child widgets, the constraints can involve spacer
* objects (also known as “guides”). This example has a guide between
* the two buttons in the top row.
*
* Try resizing the window to see how the constraints react to update
* the layout.
*/
#include <glib/gi18n.h>
@@ -29,45 +21,43 @@ struct _SimpleGrid
G_DEFINE_TYPE (SimpleGrid, simple_grid, GTK_TYPE_WIDGET)
static void
simple_grid_dispose (GObject *object)
simple_grid_destroy (GtkWidget *widget)
{
SimpleGrid *self = SIMPLE_GRID (object);
SimpleGrid *self = SIMPLE_GRID (widget);
g_clear_pointer (&self->button1, gtk_widget_unparent);
g_clear_pointer (&self->button2, gtk_widget_unparent);
g_clear_pointer (&self->button3, gtk_widget_unparent);
g_clear_pointer (&self->button1, gtk_widget_destroy);
g_clear_pointer (&self->button2, gtk_widget_destroy);
g_clear_pointer (&self->button3, gtk_widget_destroy);
G_OBJECT_CLASS (simple_grid_parent_class)->dispose (object);
GTK_WIDGET_CLASS (simple_grid_parent_class)->destroy (widget);
}
static void
simple_grid_class_init (SimpleGridClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
object_class->dispose = simple_grid_dispose;
widget_class->destroy = simple_grid_destroy;
gtk_widget_class_set_layout_manager_type (widget_class, GTK_TYPE_CONSTRAINT_LAYOUT);
}
/* Layout:
*
* +-------------------------------------+
* | +-----------++-------++-----------+ |
* | | Child 1 || Space || Child 2 | |
* | +-----------++-------++-----------+ |
* | +---------------------------------+ |
* | | Child 3 | |
* | +---------------------------------+ |
* +-------------------------------------+
* +-----------------------------+
* | +-----------+ +-----------+ |
* | | Child 1 | | Child 2 | |
* | +-----------+ +-----------+ |
* | +-------------------------+ |
* | | Child 3 | |
* | +-------------------------+ |
* +-----------------------------+
*
* Constraints:
*
* super.start = child1.start - 8
* child1.width = child2.width
* child1.end = space.start
* space.end = child2.start
* child1.end = child2.start - 12
* child2.end = super.end - 8
* super.start = child3.start - 8
* child3.end = super.end - 8
@@ -79,12 +69,6 @@ simple_grid_class_init (SimpleGridClass *klass)
* child3.height = child2.height
* child3.bottom = super.bottom - 8
*
* To add some flexibility, we make the space
* stretchable:
*
* space.width >= 10
* space.width = 100
* space.width <= 200
*/
static void
build_constraints (SimpleGrid *self,
@@ -97,7 +81,6 @@ build_constraints (SimpleGrid *self,
gtk_constraint_guide_set_min_size (guide, 10, 10);
gtk_constraint_guide_set_nat_size (guide, 100, 10);
gtk_constraint_guide_set_max_size (guide, 200, 20);
gtk_constraint_guide_set_strength (guide, GTK_CONSTRAINT_STRENGTH_STRONG);
gtk_constraint_layout_add_guide (manager, guide);
gtk_constraint_layout_add_constraint (manager,
@@ -241,12 +224,15 @@ simple_grid_init (SimpleGrid *self)
self->button1 = gtk_button_new_with_label ("Child 1");
gtk_widget_set_parent (self->button1, widget);
gtk_widget_set_name (self->button1, "button1");
self->button2 = gtk_button_new_with_label ("Child 2");
gtk_widget_set_parent (self->button2, widget);
gtk_widget_set_name (self->button2, "button2");
self->button3 = gtk_button_new_with_label ("Child 3");
gtk_widget_set_parent (self->button3, widget);
gtk_widget_set_name (self->button3, "button3");
GtkLayoutManager *manager = gtk_widget_get_layout_manager (GTK_WIDGET (self));
build_constraints (self, GTK_CONSTRAINT_LAYOUT (manager));
@@ -259,27 +245,37 @@ do_constraints (GtkWidget *do_widget)
if (!window)
{
GtkWidget *box, *grid;
GtkWidget *header, *box, *grid, *button;
window = gtk_window_new ();
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_display (GTK_WINDOW (window), gtk_widget_get_display (do_widget));
gtk_window_set_title (GTK_WINDOW (window), "Simple Constraints");
gtk_window_set_default_size (GTK_WINDOW (window), 260, -1);
g_object_add_weak_pointer (G_OBJECT (window), (gpointer *)&window);
header = gtk_header_bar_new ();
gtk_header_bar_set_title (GTK_HEADER_BAR (header), "Constraints");
gtk_header_bar_set_show_title_buttons (GTK_HEADER_BAR (header), FALSE);
gtk_window_set_titlebar (GTK_WINDOW (window), header);
g_signal_connect (window, "destroy",
G_CALLBACK (gtk_widget_destroyed), &window);
box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
gtk_window_set_child (GTK_WINDOW (window), box);
gtk_container_add (GTK_CONTAINER (window), box);
grid = g_object_new (simple_grid_get_type (), NULL);
gtk_widget_set_hexpand (grid, TRUE);
gtk_widget_set_vexpand (grid, TRUE);
gtk_box_append (GTK_BOX (box), grid);
gtk_container_add (GTK_CONTAINER (box), grid);
button = gtk_button_new_with_label ("Close");
gtk_container_add (GTK_CONTAINER (box), button);
gtk_widget_set_hexpand (grid, TRUE);
g_signal_connect_swapped (button, "clicked",
G_CALLBACK (gtk_widget_destroy), window);
}
if (!gtk_widget_get_visible (window))
gtk_widget_set_visible (window, TRUE);
gtk_widget_show (window);
else
gtk_window_destroy (GTK_WINDOW (window));
gtk_widget_destroy (window);
return window;
}

View File

@@ -0,0 +1,245 @@
/* Constraints/Interactive
*
* Demonstrate how constraints can be updates during
* user interaction.
*/
#include <glib/gi18n.h>
#include <gtk/gtk.h>
G_DECLARE_FINAL_TYPE (InteractiveGrid, interactive_grid, INTERACTIVE, GRID, GtkWidget)
struct _InteractiveGrid
{
GtkWidget parent_instance;
GtkWidget *button1, *button2;
GtkWidget *button3;
GtkConstraintGuide *guide;
GtkConstraint *constraint;
};
G_DEFINE_TYPE (InteractiveGrid, interactive_grid, GTK_TYPE_WIDGET)
static void
interactive_grid_destroy (GtkWidget *widget)
{
InteractiveGrid *self = INTERACTIVE_GRID (widget);
g_clear_pointer (&self->button1, gtk_widget_destroy);
g_clear_pointer (&self->button2, gtk_widget_destroy);
g_clear_pointer (&self->button3, gtk_widget_destroy);
GTK_WIDGET_CLASS (interactive_grid_parent_class)->destroy (widget);
}
static void
interactive_grid_class_init (InteractiveGridClass *klass)
{
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
widget_class->destroy = interactive_grid_destroy;
gtk_widget_class_set_layout_manager_type (widget_class, GTK_TYPE_CONSTRAINT_LAYOUT);
}
static void
build_constraints (InteractiveGrid *self,
GtkConstraintLayout *manager)
{
self->guide = g_object_new (GTK_TYPE_CONSTRAINT_GUIDE, NULL);
gtk_constraint_layout_add_guide (manager, self->guide);
gtk_constraint_layout_add_constraint (manager,
gtk_constraint_new_constant (GTK_CONSTRAINT_TARGET (self->guide),
GTK_CONSTRAINT_ATTRIBUTE_WIDTH,
GTK_CONSTRAINT_RELATION_EQ,
0.0,
GTK_CONSTRAINT_STRENGTH_REQUIRED));
gtk_constraint_layout_add_constraint (manager,
gtk_constraint_new (NULL,
GTK_CONSTRAINT_ATTRIBUTE_START,
GTK_CONSTRAINT_RELATION_EQ,
GTK_CONSTRAINT_TARGET (self->button1),
GTK_CONSTRAINT_ATTRIBUTE_START,
1.0,
-8.0,
GTK_CONSTRAINT_STRENGTH_REQUIRED));
gtk_constraint_layout_add_constraint (manager,
gtk_constraint_new (GTK_CONSTRAINT_TARGET (self->button1),
GTK_CONSTRAINT_ATTRIBUTE_END,
GTK_CONSTRAINT_RELATION_EQ,
GTK_CONSTRAINT_TARGET (self->guide),
GTK_CONSTRAINT_ATTRIBUTE_START,
1.0,
0.0,
GTK_CONSTRAINT_STRENGTH_REQUIRED));
gtk_constraint_layout_add_constraint (manager,
gtk_constraint_new (GTK_CONSTRAINT_TARGET (self->button2),
GTK_CONSTRAINT_ATTRIBUTE_START,
GTK_CONSTRAINT_RELATION_EQ,
GTK_CONSTRAINT_TARGET (self->guide),
GTK_CONSTRAINT_ATTRIBUTE_END,
1.0,
0.0,
GTK_CONSTRAINT_STRENGTH_REQUIRED));
gtk_constraint_layout_add_constraint (manager,
gtk_constraint_new (GTK_CONSTRAINT_TARGET (self->button2),
GTK_CONSTRAINT_ATTRIBUTE_END,
GTK_CONSTRAINT_RELATION_EQ,
NULL,
GTK_CONSTRAINT_ATTRIBUTE_END,
1.0,
-8.0,
GTK_CONSTRAINT_STRENGTH_REQUIRED));
gtk_constraint_layout_add_constraint (manager,
gtk_constraint_new (NULL,
GTK_CONSTRAINT_ATTRIBUTE_START,
GTK_CONSTRAINT_RELATION_EQ,
GTK_CONSTRAINT_TARGET (self->button3),
GTK_CONSTRAINT_ATTRIBUTE_START,
1.0,
-8.0,
GTK_CONSTRAINT_STRENGTH_REQUIRED));
gtk_constraint_layout_add_constraint (manager,
gtk_constraint_new (GTK_CONSTRAINT_TARGET (self->button3),
GTK_CONSTRAINT_ATTRIBUTE_END,
GTK_CONSTRAINT_RELATION_EQ,
GTK_CONSTRAINT_TARGET (self->guide),
GTK_CONSTRAINT_ATTRIBUTE_START,
1.0,
0.0,
GTK_CONSTRAINT_STRENGTH_REQUIRED));
gtk_constraint_layout_add_constraint (manager,
gtk_constraint_new (NULL,
GTK_CONSTRAINT_ATTRIBUTE_TOP,
GTK_CONSTRAINT_RELATION_EQ,
GTK_CONSTRAINT_TARGET (self->button1),
GTK_CONSTRAINT_ATTRIBUTE_TOP,
1.0,
-8.0,
GTK_CONSTRAINT_STRENGTH_REQUIRED));
gtk_constraint_layout_add_constraint (manager,
gtk_constraint_new (GTK_CONSTRAINT_TARGET (self->button2),
GTK_CONSTRAINT_ATTRIBUTE_TOP,
GTK_CONSTRAINT_RELATION_EQ,
GTK_CONSTRAINT_TARGET (self->button1),
GTK_CONSTRAINT_ATTRIBUTE_BOTTOM,
1.0,
0.0,
GTK_CONSTRAINT_STRENGTH_REQUIRED));
gtk_constraint_layout_add_constraint (manager,
gtk_constraint_new (GTK_CONSTRAINT_TARGET (self->button3),
GTK_CONSTRAINT_ATTRIBUTE_TOP,
GTK_CONSTRAINT_RELATION_EQ,
GTK_CONSTRAINT_TARGET (self->button2),
GTK_CONSTRAINT_ATTRIBUTE_BOTTOM,
1.0,
0.0,
GTK_CONSTRAINT_STRENGTH_REQUIRED));
gtk_constraint_layout_add_constraint (manager,
gtk_constraint_new (GTK_CONSTRAINT_TARGET (self->button3),
GTK_CONSTRAINT_ATTRIBUTE_BOTTOM,
GTK_CONSTRAINT_RELATION_EQ,
NULL,
GTK_CONSTRAINT_ATTRIBUTE_BOTTOM,
1.0,
-8.0,
GTK_CONSTRAINT_STRENGTH_REQUIRED));
}
static void
drag_cb (GtkGestureDrag *drag,
double offset_x,
double offset_y,
InteractiveGrid *self)
{
GtkConstraintLayout *layout = GTK_CONSTRAINT_LAYOUT (gtk_widget_get_layout_manager (GTK_WIDGET (self)));
double x, y;
if (self->constraint)
{
gtk_constraint_layout_remove_constraint (layout, self->constraint);
g_clear_object (&self->constraint);
}
gtk_gesture_drag_get_start_point (drag, &x, &y);
self->constraint = gtk_constraint_new_constant (GTK_CONSTRAINT_TARGET (self->guide),
GTK_CONSTRAINT_ATTRIBUTE_LEFT,
GTK_CONSTRAINT_RELATION_EQ,
x + offset_x,
GTK_CONSTRAINT_STRENGTH_REQUIRED);
gtk_constraint_layout_add_constraint (layout, g_object_ref (self->constraint));
gtk_widget_queue_allocate (GTK_WIDGET (self));
}
static void
interactive_grid_init (InteractiveGrid *self)
{
GtkWidget *widget = GTK_WIDGET (self);
GtkGesture *drag;
self->button1 = gtk_button_new_with_label ("Child 1");
gtk_widget_set_parent (self->button1, widget);
gtk_widget_set_name (self->button1, "button1");
self->button2 = gtk_button_new_with_label ("Child 2");
gtk_widget_set_parent (self->button2, widget);
gtk_widget_set_name (self->button2, "button2");
self->button3 = gtk_button_new_with_label ("Child 3");
gtk_widget_set_parent (self->button3, widget);
gtk_widget_set_name (self->button3, "button3");
GtkLayoutManager *manager = gtk_widget_get_layout_manager (GTK_WIDGET (self));
build_constraints (self, GTK_CONSTRAINT_LAYOUT (manager));
drag = gtk_gesture_drag_new ();
g_signal_connect (drag, "drag-update", G_CALLBACK (drag_cb), self);
gtk_widget_add_controller (GTK_WIDGET (self), GTK_EVENT_CONTROLLER (drag));
}
GtkWidget *
do_constraints2 (GtkWidget *do_widget)
{
static GtkWidget *window;
if (!window)
{
GtkWidget *header, *box, *grid, *button;
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_display (GTK_WINDOW (window), gtk_widget_get_display (do_widget));
header = gtk_header_bar_new ();
gtk_header_bar_set_title (GTK_HEADER_BAR (header), "Constraints");
gtk_header_bar_set_show_title_buttons (GTK_HEADER_BAR (header), FALSE);
gtk_window_set_titlebar (GTK_WINDOW (window), header);
g_signal_connect (window, "destroy",
G_CALLBACK (gtk_widget_destroyed), &window);
box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
gtk_container_add (GTK_CONTAINER (window), box);
grid = g_object_new (interactive_grid_get_type (), NULL);
gtk_widget_set_hexpand (grid, TRUE);
gtk_widget_set_vexpand (grid, TRUE);
gtk_container_add (GTK_CONTAINER (box), grid);
button = gtk_button_new_with_label ("Close");
gtk_container_add (GTK_CONTAINER (box), button);
gtk_widget_set_hexpand (grid, TRUE);
g_signal_connect_swapped (button, "clicked",
G_CALLBACK (gtk_widget_destroy), window);
}
if (!gtk_widget_get_visible (window))
gtk_widget_show (window);
else
gtk_widget_destroy (window);
return window;
}

View File

@@ -1,74 +0,0 @@
/* Constraints/Builder
*
* GtkConstraintLayouts can be created in .ui files, and constraints can
* be set up at that time as well, as this example demonstrates. It shows
* various ways to do spacing and sizing with constraints.
*
* Make the window wider to see the rows react differently
*/
#include <glib/gi18n.h>
#include <gtk/gtk.h>
G_DECLARE_FINAL_TYPE (ConstraintsGrid, constraints_grid, CONSTRAINTS, GRID, GtkWidget)
struct _ConstraintsGrid
{
GtkWidget parent_instance;
};
G_DEFINE_TYPE (ConstraintsGrid, constraints_grid, GTK_TYPE_WIDGET)
static void
constraints_grid_init (ConstraintsGrid *grid)
{
}
static void
constraints_grid_dispose (GObject *object)
{
GtkWidget *widget = GTK_WIDGET (object);
GtkWidget *child;
while ((child = gtk_widget_get_first_child (widget)))
gtk_widget_unparent (child);
G_OBJECT_CLASS (constraints_grid_parent_class)->dispose (object);
}
static void
constraints_grid_class_init (ConstraintsGridClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->dispose = constraints_grid_dispose;
}
GtkWidget *
do_constraints_builder (GtkWidget *do_widget)
{
static GtkWidget *window;
if (!window)
{
GtkBuilder *builder;
g_type_ensure (constraints_grid_get_type ());
builder = gtk_builder_new_from_resource ("/constraints_builder/constraints_builder.ui");
window = GTK_WIDGET (gtk_builder_get_object (builder, "window1"));
gtk_window_set_display (GTK_WINDOW (window),
gtk_widget_get_display (do_widget));
g_object_add_weak_pointer (G_OBJECT (window), (gpointer *)&window);
g_object_unref (builder);
}
if (!gtk_widget_get_visible (window))
gtk_widget_set_visible (window, TRUE);
else
gtk_window_destroy (GTK_WINDOW (window));
return window;
}

View File

@@ -1,460 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<object class="GtkWindow" id="window1">
<property name="title" translatable="yes">ConstraintsBuilder</property>
<property name="default-width">260</property>
<child>
<object class="ConstraintsGrid">
<property name="halign">fill</property>
<property name="valign">fill</property>
<property name="margin-top">10</property>
<property name="margin-bottom">10</property>
<property name="margin-start">10</property>
<property name="margin-end">10</property>
<property name="layout-manager">
<object class="GtkConstraintLayout">
<constraints>
<guide name="guide1" min-width="10" nat-width="200" strength="weak"/>
<guide name="guide2" min-width="10" nat-width="200" strength="weak"/>
<guide name="guide3" min-width="10" nat-width="200" strength="weak"/>
<guide name="guide4" min-width="10" nat-width="200" strength="weak"/>
<guide name="guide5" min-width="10" nat-width="200" strength="weak"/>
<guide name="guide6" min-width="10" nat-width="200" strength="weak"/>
<guide name="guide7" min-width="10" nat-width="200" strength="weak"/>
<guide name="guide8" min-width="10" nat-width="200" strength="weak"/>
<guide name="guide9" min-width="0" nat-width="200" strength="weak"/>
<guide name="guide10" min-width="0" nat-width="200" strength="weak"/>
<guide name="barrier1" min-height="10"/>
<guide name="barrier2" min-height="10"/>
<guide name="barrier3" min-height="10"/>
<guide name="barrier4" min-height="10"/>
<!-- Spread Chain -->
<constraint target="super" target-attribute="top"
relation="eq"
source="button1" source-attribute="top"
strength="required"/>
<constraint target="super" target-attribute="top"
relation="eq"
source="button2" source-attribute="top"
strength="required"/>
<constraint target="super" target-attribute="top"
relation="eq"
source="button3" source-attribute="top"
strength="required"/>
<constraint target="super" target-attribute="left"
relation="eq"
source="guide1" source-attribute="left"
strength="required"/>
<constraint target="button1" target-attribute="left"
relation="eq"
source="guide1" source-attribute="right"
strength="required"/>
<constraint target="guide2" target-attribute="left"
relation="eq"
source="button1" source-attribute="right"
strength="required"/>
<constraint target="button2" target-attribute="left"
relation="eq"
source="guide2" source-attribute="right"
strength="required"/>
<constraint target="guide3" target-attribute="left"
relation="eq"
source="button2" source-attribute="right"
strength="required"/>
<constraint target="button3" target-attribute="left"
relation="eq"
source="guide3" source-attribute="right"
strength="required"/>
<constraint target="guide4" target-attribute="left"
relation="eq"
source="button3" source-attribute="right"
strength="required"/>
<constraint target="super" target-attribute="right"
relation="eq"
source="guide4" source-attribute="right"
strength="required"/>
<constraint target="guide1" target-attribute="width"
relation="eq"
source="guide2" source-attribute="width"
strength="required"/>
<constraint target="guide2" target-attribute="width"
relation="eq"
source="guide3" source-attribute="width"
strength="required"/>
<constraint target="guide3" target-attribute="width"
relation="eq"
source="guide4" source-attribute="width"
strength="required"/>
<constraint target="button1" target-attribute="width"
relation="eq"
source="button2" source-attribute="width"
strength="required"/>
<constraint target="button2" target-attribute="width"
relation="eq"
source="button3" source-attribute="width"
strength="required"/>
<constraint target="button1" target-attribute="bottom"
relation="eq"
source="barrier1" source-attribute="top"
strength="required"/>
<constraint target="button2" target-attribute="bottom"
relation="eq"
source="barrier1" source-attribute="top"
strength="required"/>
<constraint target="button3" target-attribute="bottom"
relation="eq"
source="barrier1" source-attribute="top"
strength="required"/>
<!-- Spread Inside Chain -->
<constraint target="super" target-attribute="left"
relation="eq"
source="button4" source-attribute="left"
strength="required"/>
<constraint target="guide5" target-attribute="left"
relation="eq"
source="button4" source-attribute="right"
strength="required"/>
<constraint target="button5" target-attribute="left"
relation="eq"
source="guide5" source-attribute="right"
strength="required"/>
<constraint target="guide6" target-attribute="left"
relation="eq"
source="button5" source-attribute="right"
strength="required"/>
<constraint target="button6" target-attribute="left"
relation="eq"
source="guide6" source-attribute="right"
strength="required"/>
<constraint target="super" target-attribute="right"
relation="eq"
source="button6" source-attribute="right"
strength="required"/>
<constraint target="guide5" target-attribute="width"
relation="eq"
source="guide6" source-attribute="width"
strength="required"/>
<constraint target="button4" target-attribute="width"
relation="eq"
source="button5" source-attribute="width"
strength="required"/>
<constraint target="button5" target-attribute="width"
relation="eq"
source="button6" source-attribute="width"
strength="required"/>
<constraint target="button4" target-attribute="top"
relation="eq"
source="barrier1" source-attribute="bottom"
strength="required"/>
<constraint target="button5" target-attribute="top"
relation="eq"
source="barrier1" source-attribute="bottom"
strength="required"/>
<constraint target="button6" target-attribute="top"
relation="eq"
source="barrier1" source-attribute="bottom"
strength="required"/>
<constraint target="button4" target-attribute="bottom"
relation="eq"
source="barrier2" source-attribute="top"
strength="required"/>
<constraint target="button5" target-attribute="bottom"
relation="eq"
source="barrier2" source-attribute="top"
strength="required"/>
<constraint target="button6" target-attribute="bottom"
relation="eq"
source="barrier2" source-attribute="top"
strength="required"/>
<!-- Weighted Chain -->
<constraint target="super" target-attribute="left"
relation="eq"
source="button7" source-attribute="left"
strength="required"/>
<constraint target="button8" target-attribute="left"
relation="eq"
source="button7" source-attribute="right"
constant="10"
strength="required"/>
<constraint target="button9" target-attribute="left"
relation="eq"
source="button8" source-attribute="right"
constant="10"
strength="required"/>
<constraint target="super" target-attribute="right"
relation="eq"
source="button9" source-attribute="right"
strength="required"/>
<constraint target="button8" target-attribute="width"
relation="eq"
source="button7" source-attribute="width"
multiplier="2"
strength="required"/>
<constraint target="button9" target-attribute="width"
relation="eq"
source="button7" source-attribute="width"
multiplier="3"
strength="required"/>
<constraint target="button7" target-attribute="top"
relation="eq"
source="barrier2" source-attribute="bottom"
strength="required"/>
<constraint target="button8" target-attribute="top"
relation="eq"
source="barrier2" source-attribute="bottom"
strength="required"/>
<constraint target="button9" target-attribute="top"
relation="eq"
source="barrier2" source-attribute="bottom"
strength="required"/>
<constraint target="button7" target-attribute="bottom"
relation="eq"
source="barrier3" source-attribute="top"
strength="required"/>
<constraint target="button8" target-attribute="bottom"
relation="eq"
source="barrier3" source-attribute="top"
strength="required"/>
<constraint target="button9" target-attribute="bottom"
relation="eq"
source="barrier3" source-attribute="top"
strength="required"/>
<!-- Packed Chain -->
<constraint target="super" target-attribute="left"
relation="eq"
source="guide7" source-attribute="left"
strength="required"/>
<constraint target="button10" target-attribute="left"
relation="eq"
source="guide7" source-attribute="right"
strength="required"/>
<constraint target="button11" target-attribute="left"
relation="eq"
source="button10" source-attribute="right"
constant="10"
strength="required"/>
<constraint target="button12" target-attribute="left"
relation="eq"
source="button11" source-attribute="right"
constant="10"
strength="required"/>
<constraint target="guide8" target-attribute="left"
relation="eq"
source="button12" source-attribute="right"
strength="required"/>
<constraint target="super" target-attribute="right"
relation="eq"
source="guide8" source-attribute="right"
strength="required"/>
<constraint target="guide7" target-attribute="width"
relation="eq"
source="guide8" source-attribute="width"
strength="required"/>
<constraint target="button10" target-attribute="width"
relation="eq"
source="button11" source-attribute="width"
strength="required"/>
<constraint target="button11" target-attribute="width"
relation="eq"
source="button12" source-attribute="width"
strength="required"/>
<constraint target="button10" target-attribute="top"
relation="eq"
source="barrier3" source-attribute="bottom"
strength="required"/>
<constraint target="button11" target-attribute="top"
relation="eq"
source="barrier3" source-attribute="bottom"
strength="required"/>
<constraint target="button12" target-attribute="top"
relation="eq"
source="barrier3" source-attribute="bottom"
strength="required"/>
<constraint target="button10" target-attribute="bottom"
relation="eq"
source="barrier4" source-attribute="top"
strength="required"/>
<constraint target="button11" target-attribute="bottom"
relation="eq"
source="barrier4" source-attribute="top"
strength="required"/>
<constraint target="button12" target-attribute="bottom"
relation="eq"
source="barrier4" source-attribute="top"
strength="required"/>
<!-- Packed Chain with Bias -->
<constraint target="super" target-attribute="left"
relation="eq"
source="guide9" source-attribute="left"
strength="required"/>
<constraint target="button13" target-attribute="left"
relation="eq"
source="guide9" source-attribute="right"
constant="10"
strength="required"/>
<constraint target="button14" target-attribute="left"
relation="eq"
source="button13" source-attribute="right"
constant="10"
strength="required"/>
<constraint target="button15" target-attribute="left"
relation="eq"
source="button14" source-attribute="right"
constant="10"
strength="required"/>
<constraint target="guide10" target-attribute="left"
relation="eq"
source="button15" source-attribute="right"
constant="10"
strength="required"/>
<constraint target="super" target-attribute="right"
relation="eq"
source="guide10" source-attribute="right"
strength="required"/>
<constraint target="guide9" target-attribute="width"
relation="eq"
source="guide10" source-attribute="width"
multiplier="4"
strength="required"/>
<constraint target="button13" target-attribute="width"
relation="eq"
source="button14" source-attribute="width"
strength="required"/>
<constraint target="button14" target-attribute="width"
relation="eq"
source="button15" source-attribute="width"
strength="required"/>
<constraint target="button13" target-attribute="top"
relation="eq"
source="barrier4" source-attribute="bottom"
strength="required"/>
<constraint target="button14" target-attribute="top"
relation="eq"
source="barrier4" source-attribute="bottom"
strength="required"/>
<constraint target="button15" target-attribute="top"
relation="eq"
source="barrier4" source-attribute="bottom"
strength="required"/>
<constraint target="super" target-attribute="bottom"
relation="ge"
source="button13" source-attribute="bottom"
strength="required"/>
<constraint target="super" target-attribute="bottom"
relation="ge"
source="button14" source-attribute="bottom"
strength="required"/>
<constraint target="super" target-attribute="bottom"
relation="ge"
source="button15" source-attribute="bottom"
strength="required"/>
</constraints>
</object>
</property>
<child>
<object class="GtkButton" id="button1">
<property name="label">A</property>
</object>
</child>
<child>
<object class="GtkButton" id="button2">
<property name="label">B</property>
</object>
</child>
<child>
<object class="GtkButton" id="button3">
<property name="label">C</property>
</object>
</child>
<child>
<object class="GtkButton" id="button4">
<property name="label">A</property>
</object>
</child>
<child>
<object class="GtkButton" id="button5">
<property name="label">B</property>
</object>
</child>
<child>
<object class="GtkButton" id="button6">
<property name="label">C</property>
</object>
</child>
<child>
<object class="GtkButton" id="button7">
<property name="label">A</property>
</object>
</child>
<child>
<object class="GtkButton" id="button8">
<property name="label">B</property>
</object>
</child>
<child>
<object class="GtkButton" id="button9">
<property name="label">C</property>
</object>
</child>
<child>
<object class="GtkButton" id="button10">
<property name="label">A</property>
</object>
</child>
<child>
<object class="GtkButton" id="button11">
<property name="label">B</property>
</object>
</child>
<child>
<object class="GtkButton" id="button12">
<property name="label">C</property>
</object>
</child>
<child>
<object class="GtkButton" id="button13">
<property name="label">A</property>
</object>
</child>
<child>
<object class="GtkButton" id="button14">
<property name="label">B</property>
</object>
</child>
<child>
<object class="GtkButton" id="button15">
<property name="label">C</property>
</object>
</child>
</object>
</child>
</object>
</interface>

View File

@@ -1,237 +0,0 @@
/* Constraints/Interactive Constraints
* #Keywords: GtkConstraintLayout
*
* This example shows how constraints can be updated during user interaction.
* The vertical edge between the buttons can be dragged with the mouse.
*/
#include <glib/gi18n.h>
#include <gtk/gtk.h>
G_DECLARE_FINAL_TYPE (InteractiveGrid, interactive_grid, INTERACTIVE, GRID, GtkWidget)
struct _InteractiveGrid
{
GtkWidget parent_instance;
GtkWidget *button1, *button2;
GtkWidget *button3;
GtkConstraintGuide *guide;
GtkConstraint *constraint;
};
G_DEFINE_TYPE (InteractiveGrid, interactive_grid, GTK_TYPE_WIDGET)
static void
interactive_grid_dispose (GObject *object)
{
InteractiveGrid *self = INTERACTIVE_GRID (object);
g_clear_pointer (&self->button1, gtk_widget_unparent);
g_clear_pointer (&self->button2, gtk_widget_unparent);
g_clear_pointer (&self->button3, gtk_widget_unparent);
G_OBJECT_CLASS (interactive_grid_parent_class)->dispose (object);
}
static void
interactive_grid_class_init (InteractiveGridClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
object_class->dispose = interactive_grid_dispose;
gtk_widget_class_set_layout_manager_type (widget_class, GTK_TYPE_CONSTRAINT_LAYOUT);
}
static void
build_constraints (InteractiveGrid *self,
GtkConstraintLayout *manager)
{
self->guide = g_object_new (GTK_TYPE_CONSTRAINT_GUIDE, NULL);
gtk_constraint_layout_add_guide (manager, self->guide);
gtk_constraint_layout_add_constraint (manager,
gtk_constraint_new_constant (GTK_CONSTRAINT_TARGET (self->guide),
GTK_CONSTRAINT_ATTRIBUTE_WIDTH,
GTK_CONSTRAINT_RELATION_EQ,
0.0,
GTK_CONSTRAINT_STRENGTH_REQUIRED));
gtk_constraint_layout_add_constraint (manager,
gtk_constraint_new (NULL,
GTK_CONSTRAINT_ATTRIBUTE_START,
GTK_CONSTRAINT_RELATION_EQ,
GTK_CONSTRAINT_TARGET (self->button1),
GTK_CONSTRAINT_ATTRIBUTE_START,
1.0,
-8.0,
GTK_CONSTRAINT_STRENGTH_REQUIRED));
gtk_constraint_layout_add_constraint (manager,
gtk_constraint_new (GTK_CONSTRAINT_TARGET (self->button1),
GTK_CONSTRAINT_ATTRIBUTE_END,
GTK_CONSTRAINT_RELATION_EQ,
GTK_CONSTRAINT_TARGET (self->guide),
GTK_CONSTRAINT_ATTRIBUTE_START,
1.0,
0.0,
GTK_CONSTRAINT_STRENGTH_REQUIRED));
gtk_constraint_layout_add_constraint (manager,
gtk_constraint_new (GTK_CONSTRAINT_TARGET (self->button2),
GTK_CONSTRAINT_ATTRIBUTE_START,
GTK_CONSTRAINT_RELATION_EQ,
GTK_CONSTRAINT_TARGET (self->guide),
GTK_CONSTRAINT_ATTRIBUTE_END,
1.0,
0.0,
GTK_CONSTRAINT_STRENGTH_REQUIRED));
gtk_constraint_layout_add_constraint (manager,
gtk_constraint_new (GTK_CONSTRAINT_TARGET (self->button2),
GTK_CONSTRAINT_ATTRIBUTE_END,
GTK_CONSTRAINT_RELATION_EQ,
NULL,
GTK_CONSTRAINT_ATTRIBUTE_END,
1.0,
-8.0,
GTK_CONSTRAINT_STRENGTH_REQUIRED));
gtk_constraint_layout_add_constraint (manager,
gtk_constraint_new (NULL,
GTK_CONSTRAINT_ATTRIBUTE_START,
GTK_CONSTRAINT_RELATION_EQ,
GTK_CONSTRAINT_TARGET (self->button3),
GTK_CONSTRAINT_ATTRIBUTE_START,
1.0,
-8.0,
GTK_CONSTRAINT_STRENGTH_REQUIRED));
gtk_constraint_layout_add_constraint (manager,
gtk_constraint_new (GTK_CONSTRAINT_TARGET (self->button3),
GTK_CONSTRAINT_ATTRIBUTE_END,
GTK_CONSTRAINT_RELATION_EQ,
GTK_CONSTRAINT_TARGET (self->guide),
GTK_CONSTRAINT_ATTRIBUTE_START,
1.0,
0.0,
GTK_CONSTRAINT_STRENGTH_REQUIRED));
gtk_constraint_layout_add_constraint (manager,
gtk_constraint_new (NULL,
GTK_CONSTRAINT_ATTRIBUTE_TOP,
GTK_CONSTRAINT_RELATION_EQ,
GTK_CONSTRAINT_TARGET (self->button1),
GTK_CONSTRAINT_ATTRIBUTE_TOP,
1.0,
-8.0,
GTK_CONSTRAINT_STRENGTH_REQUIRED));
gtk_constraint_layout_add_constraint (manager,
gtk_constraint_new (GTK_CONSTRAINT_TARGET (self->button2),
GTK_CONSTRAINT_ATTRIBUTE_TOP,
GTK_CONSTRAINT_RELATION_EQ,
GTK_CONSTRAINT_TARGET (self->button1),
GTK_CONSTRAINT_ATTRIBUTE_BOTTOM,
1.0,
0.0,
GTK_CONSTRAINT_STRENGTH_REQUIRED));
gtk_constraint_layout_add_constraint (manager,
gtk_constraint_new (GTK_CONSTRAINT_TARGET (self->button3),
GTK_CONSTRAINT_ATTRIBUTE_TOP,
GTK_CONSTRAINT_RELATION_EQ,
GTK_CONSTRAINT_TARGET (self->button2),
GTK_CONSTRAINT_ATTRIBUTE_BOTTOM,
1.0,
0.0,
GTK_CONSTRAINT_STRENGTH_REQUIRED));
gtk_constraint_layout_add_constraint (manager,
gtk_constraint_new (GTK_CONSTRAINT_TARGET (self->button3),
GTK_CONSTRAINT_ATTRIBUTE_BOTTOM,
GTK_CONSTRAINT_RELATION_EQ,
NULL,
GTK_CONSTRAINT_ATTRIBUTE_BOTTOM,
1.0,
-8.0,
GTK_CONSTRAINT_STRENGTH_REQUIRED));
}
static void
drag_cb (GtkGestureDrag *drag,
double offset_x,
double offset_y,
InteractiveGrid *self)
{
GtkConstraintLayout *layout = GTK_CONSTRAINT_LAYOUT (gtk_widget_get_layout_manager (GTK_WIDGET (self)));
double x, y;
if (self->constraint)
{
gtk_constraint_layout_remove_constraint (layout, self->constraint);
g_clear_object (&self->constraint);
}
gtk_gesture_drag_get_start_point (drag, &x, &y);
self->constraint = gtk_constraint_new_constant (GTK_CONSTRAINT_TARGET (self->guide),
GTK_CONSTRAINT_ATTRIBUTE_LEFT,
GTK_CONSTRAINT_RELATION_EQ,
x + offset_x,
GTK_CONSTRAINT_STRENGTH_REQUIRED);
gtk_constraint_layout_add_constraint (layout, g_object_ref (self->constraint));
gtk_widget_queue_allocate (GTK_WIDGET (self));
}
static void
interactive_grid_init (InteractiveGrid *self)
{
GtkWidget *widget = GTK_WIDGET (self);
GtkGesture *drag;
self->button1 = gtk_button_new_with_label ("Child 1");
gtk_widget_set_parent (self->button1, widget);
gtk_widget_set_name (self->button1, "button1");
self->button2 = gtk_button_new_with_label ("Child 2");
gtk_widget_set_parent (self->button2, widget);
gtk_widget_set_name (self->button2, "button2");
self->button3 = gtk_button_new_with_label ("Child 3");
gtk_widget_set_parent (self->button3, widget);
gtk_widget_set_name (self->button3, "button3");
GtkLayoutManager *manager = gtk_widget_get_layout_manager (GTK_WIDGET (self));
build_constraints (self, GTK_CONSTRAINT_LAYOUT (manager));
drag = gtk_gesture_drag_new ();
g_signal_connect (drag, "drag-update", G_CALLBACK (drag_cb), self);
gtk_widget_add_controller (GTK_WIDGET (self), GTK_EVENT_CONTROLLER (drag));
}
GtkWidget *
do_constraints_interactive (GtkWidget *do_widget)
{
static GtkWidget *window;
if (!window)
{
GtkWidget *box, *grid;
window = gtk_window_new ();
gtk_window_set_display (GTK_WINDOW (window), gtk_widget_get_display (do_widget));
gtk_window_set_title (GTK_WINDOW (window), "Interactive Constraints");
gtk_window_set_default_size (GTK_WINDOW (window), 260, -1);
g_object_add_weak_pointer (G_OBJECT (window), (gpointer *)&window);
box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
gtk_window_set_child (GTK_WINDOW (window), box);
grid = g_object_new (interactive_grid_get_type (), NULL);
gtk_widget_set_hexpand (grid, TRUE);
gtk_widget_set_vexpand (grid, TRUE);
gtk_box_append (GTK_BOX (box), grid);
}
if (!gtk_widget_get_visible (window))
gtk_widget_set_visible (window, TRUE);
else
gtk_window_destroy (GTK_WINDOW (window));
return window;
}

View File

@@ -1,160 +0,0 @@
/* Constraints/VFL
*
* GtkConstraintLayout allows defining constraints using a
* compact syntax called Visual Format Language, or VFL.
*
* A typical example of a VFL specification looks like this:
*
* H:|-[button1(==button2)]-12-[button2]-|
*/
#include <glib/gi18n.h>
#include <gtk/gtk.h>
G_DECLARE_FINAL_TYPE (VflGrid, vfl_grid, VFL, GRID, GtkWidget)
struct _VflGrid
{
GtkWidget parent_instance;
GtkWidget *button1, *button2;
GtkWidget *button3;
};
G_DEFINE_TYPE (VflGrid, vfl_grid, GTK_TYPE_WIDGET)
static void
vfl_grid_dispose (GObject *object)
{
VflGrid *self = VFL_GRID (object);
g_clear_pointer (&self->button1, gtk_widget_unparent);
g_clear_pointer (&self->button2, gtk_widget_unparent);
g_clear_pointer (&self->button3, gtk_widget_unparent);
G_OBJECT_CLASS (vfl_grid_parent_class)->dispose (object);
}
static void
vfl_grid_class_init (VflGridClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
object_class->dispose = vfl_grid_dispose;
gtk_widget_class_set_layout_manager_type (widget_class, GTK_TYPE_CONSTRAINT_LAYOUT);
}
/* Layout:
*
* +-----------------------------+
* | +-----------+ +-----------+ |
* | | Child 1 | | Child 2 | |
* | +-----------+ +-----------+ |
* | +-------------------------+ |
* | | Child 3 | |
* | +-------------------------+ |
* +-----------------------------+
*
* Constraints:
*
* super.start = child1.start - 8
* child1.width = child2.width
* child1.end = child2.start - 12
* child2.end = super.end - 8
* super.start = child3.start - 8
* child3.end = super.end - 8
* super.top = child1.top - 8
* super.top = child2.top - 8
* child1.bottom = child3.top - 12
* child2.bottom = child3.top - 12
* child3.height = child1.height
* child3.height = child2.height
* child3.bottom = super.bottom - 8
*
* Visual format:
*
* H:|-8-[view1(==view2)-12-[view2]-8-|
* H:|-8-[view3]-8-|
* V:|-8-[view1]-12-[view3(==view1)]-8-|
* V:|-8-[view2]-12-[view3(==view2)]-8-|
*/
static void
build_constraints (VflGrid *self,
GtkConstraintLayout *manager)
{
const char * const vfl[] = {
"H:|-[button1(==button2)]-12-[button2]-|",
"H:|-[button3]-|",
"V:|-[button1]-12-[button3(==button1)]-|",
"V:|-[button2]-12-[button3(==button2)]-|",
};
GError *error = NULL;
gtk_constraint_layout_add_constraints_from_description (manager, vfl, G_N_ELEMENTS (vfl),
8, 8,
&error,
"button1", self->button1,
"button2", self->button2,
"button3", self->button3,
NULL);
if (error != NULL)
{
g_printerr ("VFL parsing error:\n%s", error->message);
g_error_free (error);
}
}
static void
vfl_grid_init (VflGrid *self)
{
GtkWidget *widget = GTK_WIDGET (self);
self->button1 = gtk_button_new_with_label ("Child 1");
gtk_widget_set_parent (self->button1, widget);
gtk_widget_set_name (self->button1, "button1");
self->button2 = gtk_button_new_with_label ("Child 2");
gtk_widget_set_parent (self->button2, widget);
gtk_widget_set_name (self->button2, "button2");
self->button3 = gtk_button_new_with_label ("Child 3");
gtk_widget_set_parent (self->button3, widget);
gtk_widget_set_name (self->button3, "button3");
GtkLayoutManager *manager = gtk_widget_get_layout_manager (GTK_WIDGET (self));
build_constraints (self, GTK_CONSTRAINT_LAYOUT (manager));
}
GtkWidget *
do_constraints_vfl (GtkWidget *do_widget)
{
static GtkWidget *window;
if (!window)
{
GtkWidget *box, *grid;
window = gtk_window_new ();
gtk_window_set_display (GTK_WINDOW (window), gtk_widget_get_display (do_widget));
gtk_window_set_title (GTK_WINDOW (window), "ConstraintsVFL");
gtk_window_set_default_size (GTK_WINDOW (window), 260, -1);
g_object_add_weak_pointer (G_OBJECT (window), (gpointer *)&window);
box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
gtk_window_set_child (GTK_WINDOW (window), box);
grid = g_object_new (vfl_grid_get_type (), NULL);
gtk_widget_set_hexpand (grid, TRUE);
gtk_widget_set_vexpand (grid, TRUE);
gtk_box_append (GTK_BOX (box), grid);
}
if (!gtk_widget_get_visible (window))
gtk_widget_set_visible (window, TRUE);
else
gtk_window_destroy (GTK_WINDOW (window));
return window;
}

View File

@@ -1,27 +0,0 @@
uniform float progress;
uniform sampler2D u_texture1;
uniform sampler2D u_texture2;
vec4 getFromColor (vec2 uv) {
return GskTexture(u_texture1, uv);
}
vec4 getToColor (vec2 uv) {
return GskTexture(u_texture2, uv);
}
// Source: https://gl-transitions.com/editor/crosswarp
// Author: Eke Péter <peterekepeter@gmail.com>
// License: MIT
vec4 transition(vec2 p) {
float x = progress;
x=smoothstep(.0,1.0,(x*2.0+p.x-1.0));
return mix(getFromColor((p-.5)*(1.-x)+.5), getToColor((p-.5)*x+.5), x);
}
void mainImage(out vec4 fragColor, in vec2 fragCoord, in vec2 resolution, in vec2 uv)
{
fragColor = transition(uv);
}

View File

@@ -7,10 +7,11 @@
#include <gtk/gtk.h>
static void
destroy_provider (GtkWidget *window,
GtkStyleProvider *provider)
apply_css (GtkWidget *widget, GtkStyleProvider *provider)
{
gtk_style_context_remove_provider_for_display (gtk_widget_get_display (window), provider);
gtk_style_context_add_provider (gtk_widget_get_style_context (widget), provider, G_MAXUINT);
if (GTK_IS_CONTAINER (widget))
gtk_container_forall (GTK_CONTAINER (widget), (GtkCallback) apply_css, provider);
}
GtkWidget *
@@ -20,57 +21,49 @@ do_css_accordion (GtkWidget *do_widget)
if (!window)
{
GtkWidget *container, *styled_box, *child;
GtkCssProvider *provider;
GtkWidget *container, *child;
GtkStyleProvider *provider;
window = gtk_window_new ();
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_title (GTK_WINDOW (window), "CSS Accordion");
gtk_window_set_transient_for (GTK_WINDOW (window), GTK_WINDOW (do_widget));
gtk_window_set_default_size (GTK_WINDOW (window), 600, 300);
g_object_add_weak_pointer (G_OBJECT (window), (gpointer *)&window);
g_signal_connect (window, "destroy",
G_CALLBACK (gtk_widget_destroyed), &window);
styled_box = gtk_frame_new (NULL);
gtk_window_set_child (GTK_WINDOW (window), styled_box);
gtk_widget_add_css_class (styled_box, "accordion");
container = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
gtk_widget_set_halign (container, GTK_ALIGN_CENTER);
gtk_widget_set_valign (container, GTK_ALIGN_CENTER);
gtk_frame_set_child (GTK_FRAME (styled_box), container);
gtk_container_add (GTK_CONTAINER (window), container);
child = gtk_button_new_with_label ("This");
gtk_box_append (GTK_BOX (container), child);
gtk_container_add (GTK_CONTAINER (container), child);
child = gtk_button_new_with_label ("Is");
gtk_box_append (GTK_BOX (container), child);
gtk_container_add (GTK_CONTAINER (container), child);
child = gtk_button_new_with_label ("A");
gtk_box_append (GTK_BOX (container), child);
gtk_container_add (GTK_CONTAINER (container), child);
child = gtk_button_new_with_label ("CSS");
gtk_box_append (GTK_BOX (container), child);
gtk_container_add (GTK_CONTAINER (container), child);
child = gtk_button_new_with_label ("Accordion");
gtk_box_append (GTK_BOX (container), child);
gtk_container_add (GTK_CONTAINER (container), child);
child = gtk_button_new_with_label (":-)");
gtk_box_append (GTK_BOX (container), child);
gtk_container_add (GTK_CONTAINER (container), child);
provider = gtk_css_provider_new ();
gtk_css_provider_load_from_resource (provider, "/css_accordion/css_accordion.css");
provider = GTK_STYLE_PROVIDER (gtk_css_provider_new ());
gtk_css_provider_load_from_resource (GTK_CSS_PROVIDER (provider), "/css_accordion/css_accordion.css");
gtk_style_context_add_provider_for_display (gtk_widget_get_display (window),
GTK_STYLE_PROVIDER (provider),
GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
g_signal_connect (window, "destroy",
G_CALLBACK (destroy_provider), provider);
g_object_unref (provider);
apply_css (window, provider);
}
if (!gtk_widget_get_visible (window))
gtk_widget_set_visible (window, TRUE);
gtk_widget_show (window);
else
gtk_window_destroy (GTK_WINDOW (window));
gtk_widget_destroy (window);
return window;
}

View File

@@ -1,13 +1,13 @@
.accordion, .accordion * {
all: unset;
@import url("resource://css_accordion/reset.css");
* {
transition-property: color, background-color, border-color, background-image, padding, border-width;
transition-duration: 1s;
font: 20px Cantarell;
}
.accordion {
window {
background: linear-gradient(153deg, #151515, #151515 5px, transparent 5px) 0 0,
linear-gradient(333deg, #151515, #151515 5px, transparent 5px) 10px 5px,
linear-gradient(153deg, #222, #222 5px, transparent 5px) 0 5px,
@@ -18,7 +18,7 @@
background-size: 20px 20px;
}
.accordion button {
button {
color: black;
background-color: #bbb;
border-style: solid;
@@ -28,25 +28,25 @@
padding: 12px 4px;
}
.accordion button:first-child {
button:first-child {
border-radius: 5px 0 0 5px;
}
.accordion button:last-child {
button:last-child {
border-radius: 0 5px 5px 0;
border-width: 2px;
}
.accordion button:hover {
button:hover {
padding: 12px 48px;
background-color: #4870bc;
}
.accordion button *:hover {
button *:hover {
color: white;
}
.accordion button:hover:active,
.accordion button:active {
button:hover:active,
button:active {
background-color: #993401;
}

View File

@@ -1,7 +1,8 @@
/* Theming/CSS Basics
*
* GTK themes are written using CSS. Every widget is build of multiple items
* Gtk themes are written using CSS. Every widget is build of multiple items
* that you can style very similarly to a regular website.
*
*/
#include <gtk/gtk.h>
@@ -47,23 +48,16 @@ css_text_changed (GtkTextBuffer *buffer,
gtk_text_buffer_remove_all_tags (buffer, &start, &end);
text = gtk_text_buffer_get_text (buffer, &start, &end, FALSE);
gtk_css_provider_load_from_string (provider, text);
gtk_css_provider_load_from_data (provider, text, -1);
g_free (text);
}
static void
clear_provider (gpointer data)
{
GtkStyleProvider *provider = data;
gtk_style_context_remove_provider_for_display (gdk_display_get_default (), provider);
}
static void
apply_css (GtkWidget *widget, GtkStyleProvider *provider)
{
gtk_style_context_add_provider_for_display (gdk_display_get_default (), provider, G_MAXUINT);
g_object_set_data_full (G_OBJECT (widget), "provider", provider, clear_provider);
gtk_style_context_add_provider (gtk_widget_get_style_context (widget), provider, G_MAXUINT);
if (GTK_IS_CONTAINER (widget))
gtk_container_forall (GTK_CONTAINER (widget), (GtkCallback) apply_css, provider);
}
GtkWidget *
@@ -78,12 +72,12 @@ do_css_basics (GtkWidget *do_widget)
GtkTextBuffer *text;
GBytes *bytes;
window = gtk_window_new ();
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_title (GTK_WINDOW (window), "CSS Basics");
gtk_window_set_transient_for (GTK_WINDOW (window), GTK_WINDOW (do_widget));
gtk_window_set_default_size (GTK_WINDOW (window), 400, 300);
gtk_widget_add_css_class (window, "demo");
g_object_add_weak_pointer (G_OBJECT (window), (gpointer *)&window);
g_signal_connect (window, "destroy",
G_CALLBACK (gtk_widget_destroyed), &window);
text = gtk_text_buffer_new (NULL);
gtk_text_buffer_create_tag (text,
@@ -97,10 +91,10 @@ do_css_basics (GtkWidget *do_widget)
provider = GTK_STYLE_PROVIDER (gtk_css_provider_new ());
container = gtk_scrolled_window_new ();
gtk_window_set_child (GTK_WINDOW (window), container);
container = gtk_scrolled_window_new (NULL, NULL);
gtk_container_add (GTK_CONTAINER (window), container);
child = gtk_text_view_new_with_buffer (text);
gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (container), child);
gtk_container_add (GTK_CONTAINER (container), child);
g_signal_connect (text, "changed",
G_CALLBACK (css_text_changed), provider);
@@ -117,9 +111,9 @@ do_css_basics (GtkWidget *do_widget)
}
if (!gtk_widget_get_visible (window))
gtk_widget_set_visible (window, TRUE);
gtk_widget_show (window);
else
gtk_window_destroy (GTK_WINDOW (window));
gtk_widget_destroy (window);
return window;
}

View File

@@ -4,24 +4,19 @@
* anymore. :)
*/
/* This resets all properties to their defaults values
* and overrides all user settings and the theme in use
*/
@import url("resource://css_shadows/reset.css");
/* This CSS resets all properties to their defaults values
* and overrides all user settings and the theme in use */
@import url("resource://css_basics/reset.css");
/* Set a very futuristic style by default */
.demo * {
* {
color: green;
font-family: Monospace;
border: 1px solid;
}
window.demo {
background-color: white;
}
/* Make sure selections are visible */
.demo selection {
selection {
background-color: darkGreen;
color: black;
}

View File

@@ -11,8 +11,8 @@
* These are the available blend modes.
*/
struct {
const char *name;
const char *id;
gchar *name;
gchar *id;
} blend_modes[] =
{
{ "Color", "color" },
@@ -38,19 +38,19 @@ struct {
#pragma GCC diagnostic ignored "-Wformat-nonliteral"
static void
update_css_for_blend_mode (GtkCssProvider *provider,
const char *blend_mode)
const gchar *blend_mode)
{
GBytes *bytes;
char *css;
gchar *css;
bytes = g_resources_lookup_data ("/css_blendmodes/css_blendmodes.css", 0, NULL);
css = g_strdup_printf ((char *) g_bytes_get_data (bytes, NULL),
css = g_strdup_printf ((gchar*) g_bytes_get_data (bytes, NULL),
blend_mode,
blend_mode,
blend_mode);
gtk_css_provider_load_from_string (provider, css);
gtk_css_provider_load_from_data (provider, css, -1);
g_bytes_unref (bytes);
g_free (css);
@@ -62,7 +62,7 @@ row_activated (GtkListBox *listbox,
GtkListBoxRow *row,
GtkCssProvider *provider)
{
const char *blend_mode;
const gchar *blend_mode;
blend_mode = blend_modes[gtk_list_box_row_get_index (row)].id;
@@ -75,11 +75,11 @@ setup_listbox (GtkBuilder *builder,
{
GtkWidget *normal_row;
GtkWidget *listbox;
int i;
gint i;
normal_row = NULL;
listbox = gtk_list_box_new ();
gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (WID ("scrolledwindow")), listbox);
gtk_container_add (GTK_CONTAINER (WID ("scrolledwindow")), listbox);
g_signal_connect (listbox, "row-activated", G_CALLBACK (row_activated), provider);
@@ -95,8 +95,9 @@ setup_listbox (GtkBuilder *builder,
"xalign", 0.0,
NULL);
gtk_list_box_row_set_child (GTK_LIST_BOX_ROW (row), label);
gtk_list_box_insert (GTK_LIST_BOX (listbox), row, -1);
gtk_container_add (GTK_CONTAINER (row), label);
gtk_container_add (GTK_CONTAINER (listbox), row);
/* The first selected row is "normal" */
if (g_strcmp0 (blend_modes[i].id, "normal") == 0)
@@ -124,7 +125,7 @@ do_css_blendmodes (GtkWidget *do_widget)
window = WID ("window");
gtk_window_set_transient_for (GTK_WINDOW (window), GTK_WINDOW (do_widget));
g_object_add_weak_pointer (G_OBJECT (window), (gpointer *)&window);
g_signal_connect (window, "destroy", G_CALLBACK (gtk_widget_destroyed), &window);
/* Setup the CSS provider for window */
provider = GTK_STYLE_PROVIDER (gtk_css_provider_new ());
@@ -134,14 +135,12 @@ do_css_blendmodes (GtkWidget *do_widget)
GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
setup_listbox (builder, provider);
g_object_unref (builder);
}
if (!gtk_widget_get_visible (window))
gtk_widget_set_visible (window, TRUE);
gtk_widget_show (window);
else
gtk_window_destroy (GTK_WINDOW (window));
gtk_widget_destroy (window);
return window;
}

View File

@@ -1,7 +1,8 @@
/* Theming/Multiple Backgrounds
*
* GTK themes are written using CSS. Every widget is build of multiple items
* Gtk themes are written using CSS. Every widget is build of multiple items
* that you can style very similarly to a regular website.
*
*/
#include <gtk/gtk.h>
@@ -48,23 +49,29 @@ css_text_changed (GtkTextBuffer *buffer,
gtk_text_buffer_remove_all_tags (buffer, &start, &end);
text = gtk_text_buffer_get_text (buffer, &start, &end, FALSE);
gtk_css_provider_load_from_string (provider, text);
gtk_css_provider_load_from_data (provider, text, -1);
g_free (text);
}
static void
clear_provider (gpointer data)
drawing_area_draw (GtkDrawingArea *da,
cairo_t *cr,
int width,
int height,
gpointer data)
{
GtkStyleProvider *provider = data;
GtkStyleContext *context = gtk_widget_get_style_context (GTK_WIDGET (da));
gtk_style_context_remove_provider_for_display (gdk_display_get_default (), provider);
gtk_render_background (context, cr, 0, 0, width, height);
gtk_render_frame (context, cr, 0, 0, width, height);
}
static void
apply_css (GtkWidget *widget, GtkStyleProvider *provider)
{
gtk_style_context_add_provider_for_display (gdk_display_get_default (), provider, G_MAXUINT);
g_object_set_data_full (G_OBJECT (widget), "provider", provider, clear_provider);
gtk_style_context_add_provider (gtk_widget_get_style_context (widget), provider, G_MAXUINT);
if (GTK_IS_CONTAINER (widget))
gtk_container_forall (GTK_CONTAINER (widget), (GtkCallback) apply_css, provider);
}
GtkWidget *
@@ -74,41 +81,41 @@ do_css_multiplebgs (GtkWidget *do_widget)
if (!window)
{
GtkWidget *paned, *overlay, *child, *sw;
GtkWidget *paned, *container, *child;
GtkStyleProvider *provider;
GtkTextBuffer *text;
GBytes *bytes;
window = gtk_window_new ();
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_title (GTK_WINDOW (window), "Multiple Backgrounds");
gtk_window_set_transient_for (GTK_WINDOW (window), GTK_WINDOW (do_widget));
gtk_window_set_default_size (GTK_WINDOW (window), 400, 300);
gtk_widget_add_css_class (window, "demo");
g_object_add_weak_pointer (G_OBJECT (window), (gpointer *)&window);
g_signal_connect (window, "destroy",
G_CALLBACK (gtk_widget_destroyed), &window);
overlay = gtk_overlay_new ();
gtk_window_set_child (GTK_WINDOW (window), overlay);
container = gtk_overlay_new ();
gtk_container_add (GTK_CONTAINER (window), container);
child = gtk_drawing_area_new ();
/* Don't set a draw_func, since we are only interested in CSS drawing,
* which happens automatically.
*/
gtk_widget_set_name (child, "canvas");
gtk_overlay_set_child (GTK_OVERLAY (overlay), child);
gtk_drawing_area_set_draw_func (GTK_DRAWING_AREA (child),
drawing_area_draw,
NULL, NULL);
gtk_container_add (GTK_CONTAINER (container), child);
child = gtk_button_new ();
gtk_overlay_add_overlay (GTK_OVERLAY (overlay), child);
gtk_overlay_add_overlay (GTK_OVERLAY (container), child);
gtk_widget_set_name (child, "bricks-button");
gtk_widget_set_halign (child, GTK_ALIGN_CENTER);
gtk_widget_set_valign (child, GTK_ALIGN_CENTER);
gtk_widget_set_size_request (child, 250, 84);
paned = gtk_paned_new (GTK_ORIENTATION_VERTICAL);
gtk_overlay_add_overlay (GTK_OVERLAY (overlay), paned);
gtk_overlay_add_overlay (GTK_OVERLAY (container), paned);
/* Need a filler so we get a handle */
child = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
gtk_paned_set_start_child (GTK_PANED (paned), child);
gtk_container_add (GTK_CONTAINER (paned), child);
text = gtk_text_buffer_new (NULL);
gtk_text_buffer_create_tag (text,
@@ -122,10 +129,10 @@ do_css_multiplebgs (GtkWidget *do_widget)
provider = GTK_STYLE_PROVIDER (gtk_css_provider_new ());
sw = gtk_scrolled_window_new ();
gtk_paned_set_end_child (GTK_PANED (paned), sw);
container = gtk_scrolled_window_new (NULL, NULL);
gtk_container_add (GTK_CONTAINER (paned), container);
child = gtk_text_view_new_with_buffer (text);
gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (sw), child);
gtk_container_add (GTK_CONTAINER (container), child);
g_signal_connect (text,
"changed",
G_CALLBACK (css_text_changed),
@@ -144,9 +151,9 @@ do_css_multiplebgs (GtkWidget *do_widget)
}
if (!gtk_widget_get_visible (window))
gtk_widget_set_visible (window, TRUE);
gtk_widget_show (window);
else
gtk_window_destroy (GTK_WINDOW (window));
gtk_widget_destroy (window);
return window;
}

View File

@@ -1,7 +1,6 @@
/* Theming/Animated Backgrounds
*
* This demo is in honour of a classic Pixbufs demo.
*
* This demo is done in honour of the Pixbufs demo further down.
* It is done exclusively with CSS as the background of the window.
*/
@@ -49,23 +48,16 @@ css_text_changed (GtkTextBuffer *buffer,
gtk_text_buffer_remove_all_tags (buffer, &start, &end);
text = gtk_text_buffer_get_text (buffer, &start, &end, FALSE);
gtk_css_provider_load_from_string (provider, text);
gtk_css_provider_load_from_data (provider, text, -1);
g_free (text);
}
static void
clear_provider (gpointer data)
{
GtkStyleProvider *provider = data;
gtk_style_context_remove_provider_for_display (gdk_display_get_default (), provider);
}
static void
apply_css (GtkWidget *widget, GtkStyleProvider *provider)
{
gtk_style_context_add_provider_for_display (gdk_display_get_default (), provider, G_MAXUINT);
g_object_set_data_full (G_OBJECT (widget), "provider", provider, clear_provider);
gtk_style_context_add_provider (gtk_widget_get_style_context (widget), provider, G_MAXUINT);
if (GTK_IS_CONTAINER (widget))
gtk_container_forall (GTK_CONTAINER (widget), (GtkCallback) apply_css, provider);
}
GtkWidget *
@@ -80,19 +72,19 @@ do_css_pixbufs (GtkWidget *do_widget)
GtkTextBuffer *text;
GBytes *bytes;
window = gtk_window_new ();
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_title (GTK_WINDOW (window), "Animated Backgrounds");
gtk_window_set_transient_for (GTK_WINDOW (window), GTK_WINDOW (do_widget));
gtk_window_set_default_size (GTK_WINDOW (window), 400, 300);
gtk_widget_add_css_class (window, "demo");
g_object_add_weak_pointer (G_OBJECT (window), (gpointer *)&window);
g_signal_connect (window, "destroy",
G_CALLBACK (gtk_widget_destroyed), &window);
paned = gtk_paned_new (GTK_ORIENTATION_VERTICAL);
gtk_window_set_child (GTK_WINDOW (window), paned);
gtk_container_add (GTK_CONTAINER (window), paned);
/* Need a filler so we get a handle */
child = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
gtk_paned_set_start_child (GTK_PANED (paned), child);
gtk_container_add (GTK_CONTAINER (paned), child);
text = gtk_text_buffer_new (NULL);
gtk_text_buffer_create_tag (text,
@@ -106,10 +98,10 @@ do_css_pixbufs (GtkWidget *do_widget)
provider = GTK_STYLE_PROVIDER (gtk_css_provider_new ());
container = gtk_scrolled_window_new ();
gtk_paned_set_end_child (GTK_PANED (paned), container);
container = gtk_scrolled_window_new (NULL, NULL);
gtk_container_add (GTK_CONTAINER (paned), container);
child = gtk_text_view_new_with_buffer (text);
gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (container), child);
gtk_container_add (GTK_CONTAINER (container), child);
g_signal_connect (text, "changed",
G_CALLBACK (css_text_changed), provider);
@@ -126,9 +118,9 @@ do_css_pixbufs (GtkWidget *do_widget)
}
if (!gtk_widget_get_visible (window))
gtk_widget_set_visible (window, TRUE);
gtk_widget_show (window);
else
gtk_window_destroy (GTK_WINDOW (window));
gtk_widget_destroy (window);
return window;
}

View File

@@ -46,19 +46,19 @@
}
@keyframes size-the-image {
0% { background-size: 96px, 12px, 96px, 12px, 96px, 12px, 96px, 12px, auto; }
100% { background-size: 12px, 96px, 12px, 96px, 12px, 96px, 12px, 96px, auto; }
0% { background-size: 96px, 12px, 96px, 12px, 96px, 12px, 96px, 12px, auto }
100% { background-size: 12px, 96px, 12px, 96px, 12px, 96px, 12px, 96px, auto }
}
window.demo {
background-image: url("resource://css_pixbufs/images/apple-red.png"),
url("resource://css_pixbufs/images/gnome-applets.png"),
url("resource://css_pixbufs/images/gnome-calendar.png"),
url("resource://css_pixbufs/images/gnome-foot.png"),
url("resource://css_pixbufs/images/gnome-gmush.png"),
url("resource://css_pixbufs/images/gnome-gimp.png"),
url("resource://css_pixbufs/images/gnome-gsame.png"),
url("resource://css_pixbufs/images/gnu-keys.png"),
window {
background-image: url("resource://css_pixbufs/apple-red.png"),
url("resource://css_pixbufs/gnome-applets.png"),
url("resource://css_pixbufs/gnome-calendar.png"),
url("resource://css_pixbufs/gnome-foot.png"),
url("resource://css_pixbufs/gnome-gmush.png"),
url("resource://css_pixbufs/gnome-gimp.png"),
url("resource://css_pixbufs/gnome-gsame.png"),
url("resource://css_pixbufs/gnu-keys.png"),
url("resource://css_pixbufs/background.jpg");
background-position: 50.00% 75.00%, 67.68% 67.68%, 75.00% 50.00%, 67.68% 32.32%, 50.00% 25.00%, 32.32% 32.32%, 25.00% 50.00%, 32.32% 67.68%, 0% 0%;
background-repeat: no-repeat, no-repeat, no-repeat, no-repeat, no-repeat, no-repeat, no-repeat, no-repeat, repeat;
@@ -66,11 +66,11 @@ window.demo {
}
/* Make the text editor has a nice style */
window.demo .view, scrollbar, separator {
.view, scrollbar, separator {
color: black;
background-color: rgba(255,255,255,0.5);
}
window.demo .view:selected {
.view:selected {
background-color: rgba(127,127,255,0.5);
}

View File

@@ -46,42 +46,38 @@ css_text_changed (GtkTextBuffer *buffer,
gtk_text_buffer_remove_all_tags (buffer, &start, &end);
text = gtk_text_buffer_get_text (buffer, &start, &end, FALSE);
gtk_css_provider_load_from_string (provider, text);
gtk_css_provider_load_from_data (provider, text, -1);
g_free (text);
}
static void
clear_provider (gpointer data)
{
GtkStyleProvider *provider = data;
gtk_style_context_remove_provider_for_display (gdk_display_get_default (), provider);
}
static void
apply_css (GtkWidget *widget, GtkStyleProvider *provider)
{
gtk_style_context_add_provider_for_display (gdk_display_get_default (), provider, G_MAXUINT);
g_object_set_data_full (G_OBJECT (widget), "provider", provider, clear_provider);
gtk_style_context_add_provider (gtk_widget_get_style_context (widget), provider, G_MAXUINT);
if (GTK_IS_CONTAINER (widget))
gtk_container_forall (GTK_CONTAINER (widget), (GtkCallback) apply_css, provider);
}
static GtkWidget *
GtkWidget *
create_toolbar (void)
{
GtkWidget *toolbar;
GtkWidget *item;
GtkToolItem *item;
toolbar = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
toolbar = gtk_toolbar_new ();
gtk_widget_set_valign (toolbar, GTK_ALIGN_CENTER);
item = gtk_button_new_from_icon_name ("go-next");
gtk_box_append (GTK_BOX (toolbar), item);
item = gtk_tool_button_new (NULL, NULL);
gtk_tool_button_set_icon_name (GTK_TOOL_BUTTON (item), "go-next");
gtk_toolbar_insert (GTK_TOOLBAR (toolbar), item, -1);
item = gtk_button_new_from_icon_name ("go-previous");
gtk_box_append (GTK_BOX (toolbar), item);
item = gtk_tool_button_new (NULL, NULL);
gtk_tool_button_set_icon_name (GTK_TOOL_BUTTON (item), "go-previous");
gtk_toolbar_insert (GTK_TOOLBAR (toolbar), item, -1);
item = gtk_button_new_with_label ("Hello World");
gtk_box_append (GTK_BOX (toolbar), item);
item = gtk_tool_button_new (NULL, "Hello World");
gtk_tool_item_set_is_important (item, TRUE);
gtk_toolbar_insert (GTK_TOOLBAR (toolbar), item, -1);
return toolbar;
}
@@ -98,19 +94,18 @@ do_css_shadows (GtkWidget *do_widget)
GtkTextBuffer *text;
GBytes *bytes;
window = gtk_window_new ();
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_title (GTK_WINDOW (window), "Shadows");
gtk_window_set_transient_for (GTK_WINDOW (window), GTK_WINDOW (do_widget));
gtk_window_set_default_size (GTK_WINDOW (window), 400, 300);
gtk_widget_add_css_class (window, "demo");
g_object_add_weak_pointer (G_OBJECT (window), (gpointer *)&window);
g_signal_connect (window, "destroy",
G_CALLBACK (gtk_widget_destroyed), &window);
paned = gtk_paned_new (GTK_ORIENTATION_VERTICAL);
gtk_window_set_child (GTK_WINDOW (window), paned);
gtk_container_add (GTK_CONTAINER (window), paned);
child = create_toolbar ();
gtk_paned_set_start_child (GTK_PANED (paned), child);
gtk_paned_set_resize_start_child (GTK_PANED (paned), FALSE);
gtk_container_add (GTK_CONTAINER (paned), child);
text = gtk_text_buffer_new (NULL);
gtk_text_buffer_create_tag (text,
@@ -124,10 +119,10 @@ do_css_shadows (GtkWidget *do_widget)
provider = GTK_STYLE_PROVIDER (gtk_css_provider_new ());
container = gtk_scrolled_window_new ();
gtk_paned_set_end_child (GTK_PANED (paned), container);
container = gtk_scrolled_window_new (NULL, NULL);
gtk_container_add (GTK_CONTAINER (paned), container);
child = gtk_text_view_new_with_buffer (text);
gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (container), child);
gtk_container_add (GTK_CONTAINER (container), child);
g_signal_connect (text, "changed",
G_CALLBACK (css_text_changed), provider);
@@ -144,9 +139,9 @@ do_css_shadows (GtkWidget *do_widget)
}
if (!gtk_widget_get_visible (window))
gtk_window_present (GTK_WINDOW (window));
gtk_widget_show (window);
else
gtk_window_destroy (GTK_WINDOW (window));
gtk_widget_destroy (window);
return window;
}

View File

@@ -5,13 +5,12 @@
*/
/* This CSS resets all properties to their defaults values
* and overrides all user settings and the theme in use
*/
* and overrides all user settings and the theme in use */
@import url("resource://css_shadows/reset.css");
@import url("resource://css_shadows/cssview.css");
/* Get a nice background for the window */
window.demo.background {
.background {
background-color: #4870bc;
background-image: linear-gradient(to left, transparent, rgba(255,255,255,.07) 50%, transparent 50%),
linear-gradient(to left, transparent, rgba(255,255,255,.13) 50%, transparent 50%),
@@ -20,7 +19,7 @@ window.demo.background {
background-size: 29px, 59px, 73px, 109px;
}
window.demo button {
button {
color: black;
padding: 10px;
border-radius: 5px;
@@ -28,15 +27,18 @@ window.demo button {
border: 1px transparent solid;
}
window.demo button:hover {
button:hover {
text-shadow: 3px 3px 5px alpha(black, 0.75);
-gtk-icon-shadow: 3px 3px 5px alpha(black, 0.75);
box-shadow: 3px 3px 5px alpha(black, 0.5) inset;
border: solid 1px alpha(black, 0.75);
}
window.demo button:active {
button:active {
padding: 11px 9px 9px 11px;
text-shadow: 1px 1px 2.5px alpha(black, 0.6);
-gtk-icon-shadow: 1px 1px 2.5px alpha(black, 0.6);
}

View File

@@ -1,21 +1,21 @@
/* Make the text editor has a nice style */
window.demo .view {
.view {
color: #2e3436;
font-family: Monospace;
background-color: alpha(white, 0.30);
}
window.demo .view:selected {
.view:selected {
color: white;
background-color: #4a90d9;
}
window.demo scrollbar trough,
scrollbar trough,
.scrollbars-junction {
background-color: alpha(white, 0.80);
}
window.demo scrollbar slider {
scrollbar slider {
border-width: 3px;
border-style: solid;
border-radius: 10px;
@@ -24,11 +24,11 @@ window.demo scrollbar slider {
background-color: #999;
}
window.demo scrollbar slider:hover {
scrollbar slider:hover {
background-color: #555;
}
window.demo paned separator {
paned separator {
background-color: alpha(white, 0.80);
background-image: linear-gradient(transparent, transparent 1px, #999 1px, #999 4px, transparent 4px);
background-size: 40px auto;
@@ -36,6 +36,6 @@ window.demo paned separator {
background-position: center;
}
window.demo paned separator:hover {
paned separator:hover {
background-image: linear-gradient(transparent, transparent 1px, #555 1px, #555 4px, transparent 4px);
}

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