Adding upstream version 1:48.2.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
This commit is contained in:
parent
446e9989ce
commit
0a49575b51
1390 changed files with 1508331 additions and 0 deletions
12
.clang-format
Normal file
12
.clang-format
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
# 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
|
7
.gitignore
vendored
Normal file
7
.gitignore
vendored
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
__pycache__
|
||||||
|
_build/
|
||||||
|
**/*~
|
||||||
|
/subprojects/*
|
||||||
|
!/subprojects/*.wrap
|
||||||
|
.flatpak-builder/
|
||||||
|
.cache/clangd/
|
369
.gitlab-ci.yml
Normal file
369
.gitlab-ci.yml
Normal file
|
@ -0,0 +1,369 @@
|
||||||
|
include:
|
||||||
|
- project: Infrastructure/freedesktop-ci-templates
|
||||||
|
file: templates/fedora.yml
|
||||||
|
ref: 765bb77a5e1274b0daeb14344e7caa6cd3876232
|
||||||
|
- component: gitlab.gnome.org/GNOME/citemplates/release-service@master
|
||||||
|
inputs:
|
||||||
|
dist-job-name: release-build
|
||||||
|
tarball-artifact-path: $TARBALL_ARTIFACT_PATH
|
||||||
|
|
||||||
|
variables:
|
||||||
|
FDO_UPSTREAM_REPO: gnome/gnome-control-center
|
||||||
|
MESON_BUILD_DIR: _build
|
||||||
|
TARBALL_ARTIFACT_PATH: "$MESON_BUILD_DIR/meson-dist/$CI_PROJECT_NAME-$CI_COMMIT_TAG.tar.xz"
|
||||||
|
|
||||||
|
stages:
|
||||||
|
- prepare
|
||||||
|
- build
|
||||||
|
- test
|
||||||
|
- manual
|
||||||
|
- deploy
|
||||||
|
|
||||||
|
.Build Logs: &build_logs
|
||||||
|
name: build_logs
|
||||||
|
when: always
|
||||||
|
paths:
|
||||||
|
- ./*.log
|
||||||
|
- $MESON_BUILD_DIR/meson-logs/
|
||||||
|
|
||||||
|
.Build Output: &build_output
|
||||||
|
artifacts:
|
||||||
|
name: build_output
|
||||||
|
when: always
|
||||||
|
paths:
|
||||||
|
- ./*.log
|
||||||
|
- $MESON_BUILD_DIR/
|
||||||
|
expire_in: 3h30min
|
||||||
|
|
||||||
|
.Show Info: &environment_information
|
||||||
|
build-aux/ci/ci-helper.sh "INFO" &&
|
||||||
|
build-aux/ci/ci-helper.sh "GIT_INFO"
|
||||||
|
|
||||||
|
.Build Procedure: &build_procedure
|
||||||
|
echo "== Building ==" &&
|
||||||
|
meson setup $MESON_BUILD_DIR ${BUILD_OPTS} -Dprofile=development -Dwarning_level=2 &&
|
||||||
|
meson compile -C $MESON_BUILD_DIR 2>&1 | tee compilation.log
|
||||||
|
|
||||||
|
.Run Tests: &run_tests
|
||||||
|
export GSK_RENDERER=ngl &&
|
||||||
|
echo "== Testing ==" &&
|
||||||
|
meson test -C $MESON_BUILD_DIR --verbose --no-stdsplit --no-rebuild
|
||||||
|
|
||||||
|
.fedora.container.common:
|
||||||
|
variables:
|
||||||
|
# When branching a stable release, change 'main' to the
|
||||||
|
# release branch name to ensure that a new image will
|
||||||
|
# be created, tailored for the stable branch.
|
||||||
|
# Should probably also switch away from 'rawhide',
|
||||||
|
# to stable fedora branch as well.
|
||||||
|
BRANCH_NAME: 'gnome-48'
|
||||||
|
CONTAINER_TAG: '2025-05-20.0'
|
||||||
|
FEDORA_VERSION: 42
|
||||||
|
# Derive FDO variables from this automatically.
|
||||||
|
# DO NOT edit, instead change the variables above
|
||||||
|
FDO_REPO_SUFFIX: '${BRANCH_NAME}'
|
||||||
|
FDO_DISTRIBUTION_TAG: '${CONTAINER_TAG}-fedora-${FEDORA_VERSION}'
|
||||||
|
FDO_DISTRIBUTION_VERSION: '${FEDORA_VERSION}'
|
||||||
|
|
||||||
|
#############################################
|
||||||
|
# Create CI Docker Images #
|
||||||
|
#############################################
|
||||||
|
|
||||||
|
# See also https://gitlab.gnome.org/Infrastructure/freedesktop-ci-templates
|
||||||
|
build.container.fedora@x86_64:
|
||||||
|
extends:
|
||||||
|
- '.fdo.container-build@fedora'
|
||||||
|
- '.fedora.container.common'
|
||||||
|
stage: 'prepare'
|
||||||
|
variables:
|
||||||
|
# no need to pull the whole tree for rebuilding the image
|
||||||
|
GIT_STRATEGY: none
|
||||||
|
# Expiry sets fdo.expires on the image
|
||||||
|
FDO_EXPIRES_AFTER: 8w
|
||||||
|
# NOTES:
|
||||||
|
# - most packages are needed for testing
|
||||||
|
# - glibc-langpack-en is needed for sorting in run-style-check-diff.sh
|
||||||
|
# - libsass-devel, sassc are often needed for building libadwaita, gtk, etc.
|
||||||
|
FDO_DISTRIBUTION_PACKAGES: >-
|
||||||
|
dnf5-plugins
|
||||||
|
gawk
|
||||||
|
git
|
||||||
|
llvm clang libasan libtsan libubsan compiler-rt gcovr
|
||||||
|
meson
|
||||||
|
clang-tools-extra
|
||||||
|
glibc-langpack-en
|
||||||
|
python3-dbusmock
|
||||||
|
xorg-x11-server-Xvfb
|
||||||
|
mesa-dri-drivers
|
||||||
|
libsass-devel sassc
|
||||||
|
FDO_DISTRIBUTION_EXEC: |-
|
||||||
|
dnf builddep -y gnome-control-center && \
|
||||||
|
dnf remove -y systemtap-runtime
|
||||||
|
|
||||||
|
##
|
||||||
|
# Stage: Build
|
||||||
|
#
|
||||||
|
# Checks if GNOME Control Center is properly building and installing. This is the
|
||||||
|
# most important stage of the CI, and no MR should ever be merged if it breaks
|
||||||
|
# any of them.
|
||||||
|
##
|
||||||
|
build:
|
||||||
|
extends:
|
||||||
|
- '.fdo.suffixed-image@fedora'
|
||||||
|
- '.fedora.container.common'
|
||||||
|
stage: build
|
||||||
|
|
||||||
|
script:
|
||||||
|
- *environment_information
|
||||||
|
- *build_procedure
|
||||||
|
|
||||||
|
- echo "== Installing =="
|
||||||
|
- meson install -C $MESON_BUILD_DIR
|
||||||
|
|
||||||
|
- echo "== Report =="
|
||||||
|
- build-aux/ci/ci-helper.sh "WARNINGS"
|
||||||
|
|
||||||
|
<<: *build_output
|
||||||
|
|
||||||
|
except:
|
||||||
|
variables:
|
||||||
|
- $CI_PIPELINE_SOURCE == "schedule"
|
||||||
|
|
||||||
|
# Same as build but with various off-by-default options enabled
|
||||||
|
conditional builds:
|
||||||
|
extends:
|
||||||
|
- build
|
||||||
|
artifacts:
|
||||||
|
# Only save build logs for these
|
||||||
|
<<: *build_logs
|
||||||
|
parallel:
|
||||||
|
matrix:
|
||||||
|
- BUILD_OPTS: '-Dmalcontent=true'
|
||||||
|
- BUILD_OPTS: '-Ddocumentation=true'
|
||||||
|
|
||||||
|
##
|
||||||
|
# Stage: Test
|
||||||
|
#
|
||||||
|
# Runs static checks.
|
||||||
|
# Runs the unit tests.
|
||||||
|
##
|
||||||
|
style-check-diff:
|
||||||
|
extends:
|
||||||
|
- '.fdo.suffixed-image@fedora'
|
||||||
|
- '.fedora.container.common'
|
||||||
|
needs:
|
||||||
|
- build.container.fedora@x86_64
|
||||||
|
stage: test
|
||||||
|
when: always
|
||||||
|
allow_failure: true
|
||||||
|
script:
|
||||||
|
- .gitlab-ci/run-style-check-diff.sh
|
||||||
|
|
||||||
|
check-potfiles:
|
||||||
|
extends:
|
||||||
|
- '.fdo.suffixed-image@fedora'
|
||||||
|
- '.fedora.container.common'
|
||||||
|
needs:
|
||||||
|
- build.container.fedora@x86_64
|
||||||
|
stage: test
|
||||||
|
when: always
|
||||||
|
variables:
|
||||||
|
GIT_SUBMODULE_STRATEGY: normal
|
||||||
|
script:
|
||||||
|
- .gitlab-ci/check-potfiles.sh
|
||||||
|
|
||||||
|
test:
|
||||||
|
extends:
|
||||||
|
- '.fdo.suffixed-image@fedora'
|
||||||
|
- '.fedora.container.common'
|
||||||
|
stage: test
|
||||||
|
|
||||||
|
needs:
|
||||||
|
- build
|
||||||
|
|
||||||
|
script:
|
||||||
|
- *environment_information
|
||||||
|
- *run_tests
|
||||||
|
|
||||||
|
artifacts:
|
||||||
|
<<: *build_logs
|
||||||
|
reports:
|
||||||
|
junit: '$MESON_BUILD_DIR/meson-logs/testlog.junit.xml'
|
||||||
|
|
||||||
|
except:
|
||||||
|
variables:
|
||||||
|
- $CI_PIPELINE_SOURCE == "schedule"
|
||||||
|
- $CI_COMMIT_TITLE =~ /^Update.*translation$/
|
||||||
|
|
||||||
|
release-build:
|
||||||
|
stage: build
|
||||||
|
extends:
|
||||||
|
- '.fdo.suffixed-image@fedora'
|
||||||
|
- '.fedora.container.common'
|
||||||
|
script:
|
||||||
|
- meson subprojects download gvc libgxdp
|
||||||
|
- meson setup $MESON_BUILD_DIR --wrap-mode=nodownload
|
||||||
|
- meson dist -C $MESON_BUILD_DIR --no-tests --include-subprojects
|
||||||
|
artifacts:
|
||||||
|
paths:
|
||||||
|
- $TARBALL_ARTIFACT_PATH
|
||||||
|
|
||||||
|
# Runs the coverage test.
|
||||||
|
coverage:
|
||||||
|
extends:
|
||||||
|
- '.fdo.suffixed-image@fedora'
|
||||||
|
- '.fedora.container.common'
|
||||||
|
dependencies:
|
||||||
|
- build.container.fedora@x86_64
|
||||||
|
stage: test
|
||||||
|
variables:
|
||||||
|
BUILD_OPTS: "-Db_coverage=true"
|
||||||
|
coverage: '/^Lines:.\d+.\d+.(\d+\.\d+\%)/'
|
||||||
|
only:
|
||||||
|
- main@GNOME/gnome-control-center
|
||||||
|
|
||||||
|
script:
|
||||||
|
- *environment_information
|
||||||
|
- *build_procedure
|
||||||
|
- *run_tests
|
||||||
|
|
||||||
|
- ninja -C $MESON_BUILD_DIR coverage-html
|
||||||
|
|
||||||
|
# Parse the report to get the coverage result
|
||||||
|
- |
|
||||||
|
echo == Coverage ==
|
||||||
|
sed -e 's/<[^>]*>//g' $MESON_BUILD_DIR/meson-logs/coveragereport/index.html | tr -d ' \t' | grep -A3 -P '^Lines:$' | tr '\n' ' '; echo
|
||||||
|
|
||||||
|
artifacts:
|
||||||
|
<<: *build_logs
|
||||||
|
|
||||||
|
except:
|
||||||
|
variables:
|
||||||
|
- $CI_PIPELINE_SOURCE == "schedule"
|
||||||
|
- $CI_COMMIT_TITLE =~ /^Update.*translation$/
|
||||||
|
|
||||||
|
##
|
||||||
|
# Stage: Deploy
|
||||||
|
#
|
||||||
|
# Publishes release artifacts and the Coverage Report generated above
|
||||||
|
##
|
||||||
|
pages:
|
||||||
|
extends:
|
||||||
|
- '.fdo.suffixed-image@fedora'
|
||||||
|
- '.fedora.container.common'
|
||||||
|
stage: deploy
|
||||||
|
dependencies:
|
||||||
|
- coverage
|
||||||
|
script:
|
||||||
|
- mv $MESON_BUILD_DIR/meson-logs/coveragereport/ public/
|
||||||
|
artifacts:
|
||||||
|
paths:
|
||||||
|
- public
|
||||||
|
only:
|
||||||
|
- main@GNOME/gnome-control-center
|
||||||
|
|
||||||
|
except:
|
||||||
|
variables:
|
||||||
|
- $CRON_TASK == "BUILD_CI_IMAGES"
|
||||||
|
- $CI_COMMIT_TITLE =~ /^Update.*translation$/
|
||||||
|
|
||||||
|
##
|
||||||
|
# Stage: Manual
|
||||||
|
#
|
||||||
|
# Creates a flatpak
|
||||||
|
##
|
||||||
|
flatpak:
|
||||||
|
stage: manual
|
||||||
|
image: quay.io/gnome_infrastructure/gnome-runtime-images:gnome-master
|
||||||
|
artifacts:
|
||||||
|
name: package
|
||||||
|
paths:
|
||||||
|
- $(pwd)/*.flatpak
|
||||||
|
expire_in: 7 days
|
||||||
|
|
||||||
|
variables:
|
||||||
|
OLD_APPID: "org.gnome.Settings"
|
||||||
|
APPID: "org.gnome.Settings.Devel"
|
||||||
|
BUNDLE: "org.gnome.Settings.Devel.flatpak"
|
||||||
|
MANIFEST_PATH: "build-aux/flatpak/org.gnome.Settings.Devel.json"
|
||||||
|
PROJECT_ID: "org.gnome.Settings"
|
||||||
|
PROJECT_NAME: "gnome-control-center.git"
|
||||||
|
RUNTIME_REPO: "https://sdk.gnome.org/gnome-nightly.flatpakrepo"
|
||||||
|
|
||||||
|
script:
|
||||||
|
- echo "== Flatpak packaging =="
|
||||||
|
|
||||||
|
# Make it a develoment manifest
|
||||||
|
- sed -i -n "p; s/$PROJECT_NAME//p" ${MANIFEST_PATH}
|
||||||
|
- >
|
||||||
|
sed -i "s,\"app-id\" : \"$PROJECT_ID\",\"app-id\" : \"<<ID>>\",g" ${MANIFEST_PATH}
|
||||||
|
- >
|
||||||
|
sed -i "s,\"url\" : \"https://gitlab.gnome.org/GNOME/$PROJECT_NAME\",\"branch\" : \"<<current>>\"\,,g" ${MANIFEST_PATH}
|
||||||
|
- >
|
||||||
|
sed -i "s,\"url\" : \"https://gitlab.gnome.org/GNOME/\",\"path\" : \".\",g" ${MANIFEST_PATH}
|
||||||
|
|
||||||
|
# Adjust the manifest to HEAD
|
||||||
|
- sed -i "s,<<ID>>,$APPID,g" ${MANIFEST_PATH}
|
||||||
|
- sed -i "s,<<current>>,origin/$CI_COMMIT_REF_NAME,g" ${MANIFEST_PATH}
|
||||||
|
|
||||||
|
# Update the icon name
|
||||||
|
- mv data/icons/hicolor/scalable/apps/$OLD_APPID.svg data/icons/hicolor/scalable/apps/$APPID.svg
|
||||||
|
- mv data/icons/hicolor/symbolic/apps/$OLD_APPID-symbolic.svg data/icons/hicolor/symbolic/apps/$APPID-symbolic.svg
|
||||||
|
|
||||||
|
- flatpak-builder --bundle-sources --disable-rofiles-fuse --repo=devel build ${MANIFEST_PATH}
|
||||||
|
- flatpak build-bundle devel ${BUNDLE} --runtime-repo=${RUNTIME_REPO} ${APPID}
|
||||||
|
|
||||||
|
cache:
|
||||||
|
paths:
|
||||||
|
- .flatpak-builder/cache
|
||||||
|
when: manual
|
||||||
|
except:
|
||||||
|
- tags
|
||||||
|
- gnome-3-.*
|
||||||
|
- main@GNOME/gnome-control-center
|
||||||
|
|
||||||
|
# Runs the sanitizers [address, thread, undefined, and memory].
|
||||||
|
.sanitizer: &sanitizer
|
||||||
|
extends:
|
||||||
|
- '.fdo.suffixed-image@fedora'
|
||||||
|
- '.fedora.container.common'
|
||||||
|
dependencies:
|
||||||
|
- build.container.fedora@x86_64
|
||||||
|
stage: manual
|
||||||
|
when: manual
|
||||||
|
script:
|
||||||
|
- *environment_information
|
||||||
|
- *build_procedure
|
||||||
|
- *run_tests
|
||||||
|
|
||||||
|
artifacts:
|
||||||
|
<<: *build_logs
|
||||||
|
|
||||||
|
except:
|
||||||
|
variables:
|
||||||
|
- $CI_PIPELINE_SOURCE == "schedule"
|
||||||
|
- $CI_COMMIT_TITLE =~ /^Update.*translation$/
|
||||||
|
|
||||||
|
asan:
|
||||||
|
<<: *sanitizer
|
||||||
|
# ASAN requires debugging capabilities
|
||||||
|
tags: [ asan ]
|
||||||
|
variables:
|
||||||
|
BUILD_OPTS: "-Db_sanitize=address"
|
||||||
|
LSAN_OPTIONS: "suppressions=${CI_PROJECT_DIR}/build-aux/ci/lsan.supp"
|
||||||
|
|
||||||
|
tsan:
|
||||||
|
<<: *sanitizer
|
||||||
|
variables:
|
||||||
|
BUILD_OPTS: "-Db_sanitize=thread"
|
||||||
|
|
||||||
|
ubsan:
|
||||||
|
<<: *sanitizer
|
||||||
|
variables:
|
||||||
|
BUILD_OPTS: "-Db_sanitize=undefined"
|
||||||
|
|
||||||
|
msan:
|
||||||
|
<<: *sanitizer
|
||||||
|
variables:
|
||||||
|
BUILD_OPTS: "-Db_sanitize=memory"
|
||||||
|
CC: "clang"
|
88
.gitlab-ci/check-potfiles.sh
Executable file
88
.gitlab-ci/check-potfiles.sh
Executable file
|
@ -0,0 +1,88 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
srcdirs="global-shortcuts-provider panels shell subprojects/gvc"
|
||||||
|
uidirs=$srcdirs
|
||||||
|
desktopdirs=$srcdirs
|
||||||
|
policydirs=$srcdirs
|
||||||
|
xmldirs=$srcdirs
|
||||||
|
|
||||||
|
# find source files that contain gettext functions with literal or GETTEXT_PACKAGE argument
|
||||||
|
files=$(grep -ElRs --include='*.c' 'gettext2? ?\(("|GETTEXT_PACKAGE,)' $srcdirs)
|
||||||
|
|
||||||
|
# find source files that contain gettext macros
|
||||||
|
files="$files "$(grep -lRs --include='*.c' --include='*.h' '[^I_)]_(' $srcdirs)
|
||||||
|
|
||||||
|
# find ui files that contain translatable string
|
||||||
|
files="$files "$(grep -lRis --include='*.ui' 'translatable="[ty1]' $uidirs)
|
||||||
|
|
||||||
|
# find .desktop files
|
||||||
|
files="$files "$(find $desktopdirs -name '*.desktop*')
|
||||||
|
|
||||||
|
# find .policy files
|
||||||
|
files="$files "$(find $policydirs -name '*.policy*')
|
||||||
|
|
||||||
|
# find .xml.in and .gschema.xml files
|
||||||
|
files="$files "$(find $xmldirs -not -name '*.gresource.xml*' \
|
||||||
|
-name '*.xml.in*' -o \
|
||||||
|
-name '*.gschema.xml')
|
||||||
|
|
||||||
|
# filter out excluded files
|
||||||
|
if [ -f po/POTFILES.skip ]; then
|
||||||
|
files=$(for f in $files; do
|
||||||
|
! grep -q "^$f" po/POTFILES.skip && echo "$f"
|
||||||
|
done)
|
||||||
|
fi
|
||||||
|
|
||||||
|
# find those that aren't listed in POTFILES.in
|
||||||
|
missing=$(for f in $files; do
|
||||||
|
! grep -q "^$f" po/POTFILES.in && echo "$f"
|
||||||
|
done)
|
||||||
|
|
||||||
|
# find those that are listed in POTFILES.in but do not contain translatable strings
|
||||||
|
invalid=$(while IFS= read -r f; do
|
||||||
|
! grep -q "$f" <<< "$files" && echo "$f"
|
||||||
|
done < <(grep '^[^#]' po/POTFILES.in))
|
||||||
|
|
||||||
|
# find out if POTFILES.in is sorted correctly, ignoring empty lines
|
||||||
|
sorted=$(grep '^[^#]' po/POTFILES.in | \
|
||||||
|
LC_ALL=en_US.UTF-8 sort -cu 2>&1 >/dev/null | \
|
||||||
|
awk -F ': *' '{print $5}')
|
||||||
|
|
||||||
|
if [ ${#missing} -eq 0 ] && [ ${#invalid} -eq 0 ] && [ ${#sorted} -eq 0 ]; then
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ ${#missing} -ne 0 ]; then
|
||||||
|
cat >&2 << EOT
|
||||||
|
|
||||||
|
The following files are missing from po/POTFILES.in or po/POTFILES.skip:
|
||||||
|
|
||||||
|
EOT
|
||||||
|
for f in $missing; do
|
||||||
|
echo " $f" >&2
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ ${#invalid} -ne 0 ]; then
|
||||||
|
cat >&2 << EOT
|
||||||
|
|
||||||
|
The following files are in po/POTFILES.in but are missing, skipped or not translatable:
|
||||||
|
|
||||||
|
EOT
|
||||||
|
for f in $invalid; do
|
||||||
|
echo " $f" >&2
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ ${#sorted} -ne 0 ]; then
|
||||||
|
cat >&2 << EOT
|
||||||
|
|
||||||
|
The following file is not sorted properly in po/POTFILES.in:
|
||||||
|
|
||||||
|
EOT
|
||||||
|
echo " $sorted" >&2
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo >&2
|
||||||
|
|
||||||
|
exit 1
|
133
.gitlab-ci/clang-format-diff.py
Executable file
133
.gitlab-ci/clang-format-diff.py
Executable file
|
@ -0,0 +1,133 @@
|
||||||
|
#!/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()
|
62
.gitlab-ci/run-style-check-diff.sh
Executable file
62
.gitlab-ci/run-style-check-diff.sh
Executable file
|
@ -0,0 +1,62 @@
|
||||||
|
#!/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/gnome-control-center.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 we’re 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 "Couldn’t 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 GNOME Settings’ coding style: in particular, it cannot align
|
||||||
|
# function arguments. The documented coding style for GNOME Settings takes priority over
|
||||||
|
# clang-format suggestions. Hopefully we can eventually improve clang-format to
|
||||||
|
# be configurable enough for our coding style. That’s why this CI check is OK
|
||||||
|
# to fail: the idea is that people can look through the output and ignore it if
|
||||||
|
# it’s wrong. (That situation can also happen if someone touches pre-existing
|
||||||
|
# badly formatted code and it doesn’t make sense to tidy up the wider coding
|
||||||
|
# style with the changes they’re making.)
|
||||||
|
echo ""
|
||||||
|
echo "Note that clang-format output is advisory and cannot always match the"
|
||||||
|
echo "GNOME Settings coding style, documented at:"
|
||||||
|
echo " https://gitlab.gnome.org/GNOME/gnome-control-center/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}
|
32
.gitlab/issue_templates/Bug.md
Normal file
32
.gitlab/issue_templates/Bug.md
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
<!--
|
||||||
|
|
||||||
|
Not following the communication guidelines [1] will mean your issue or comment
|
||||||
|
will be removed. Read it carefully before submitting this issue.
|
||||||
|
|
||||||
|
[1] https://gitlab.gnome.org/GNOME/gnome-control-center/blob/main/docs/CODE_OF_CONDUCT.md#communication-guidelines
|
||||||
|
|
||||||
|
Detailed description of the issue. Put as much information as you can, potentially
|
||||||
|
with images showing the issue.
|
||||||
|
-->
|
||||||
|
|
||||||
|
## Relevant information
|
||||||
|
|
||||||
|
* GNOME Settings version
|
||||||
|
<!-- Find with the command "gnome-control-center --version" -->
|
||||||
|
|
||||||
|
* Operating system (distribution)
|
||||||
|
<!-- Find with the command "cat /etc/os-release" -->
|
||||||
|
|
||||||
|
* Error message
|
||||||
|
<!-- Reproduce the issue while running with the command "G_MESSAGES_DEBUG=all gnome-control-center" -->
|
||||||
|
|
||||||
|
* Backtrace (if you are experiencing a crash)
|
||||||
|
<!-- Check for instructions at https://handbook.gnome.org/issues/stack-traces.html -->
|
||||||
|
|
||||||
|
* Screenshots
|
||||||
|
|
||||||
|
## Steps to reproduce:
|
||||||
|
|
||||||
|
1. Open GNOME Settings
|
||||||
|
2. Change X to something else
|
||||||
|
3. ...
|
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
[submodule "subprojects/gvc"]
|
||||||
|
path = subprojects/gvc
|
||||||
|
url = https://gitlab.gnome.org/GNOME/libgnome-volume-control.git
|
340
COPYING
Normal file
340
COPYING
Normal file
|
@ -0,0 +1,340 @@
|
||||||
|
GNU GENERAL PUBLIC LICENSE
|
||||||
|
Version 2, June 1991
|
||||||
|
|
||||||
|
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
|
||||||
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
Everyone is permitted to copy and distribute verbatim copies
|
||||||
|
of this license document, but changing it is not allowed.
|
||||||
|
|
||||||
|
Preamble
|
||||||
|
|
||||||
|
The licenses for most software are designed to take away your
|
||||||
|
freedom to share and change it. By contrast, the GNU General Public
|
||||||
|
License is intended to guarantee your freedom to share and change free
|
||||||
|
software--to make sure the software is free for all its users. This
|
||||||
|
General Public License applies to most of the Free Software
|
||||||
|
Foundation's software and to any other program whose authors commit to
|
||||||
|
using it. (Some other Free Software Foundation software is covered by
|
||||||
|
the GNU Lesser General Public License instead.) You can apply it to
|
||||||
|
your programs, too.
|
||||||
|
|
||||||
|
When we speak of free software, we are referring to freedom, not
|
||||||
|
price. Our General Public Licenses are designed to make sure that you
|
||||||
|
have the freedom to distribute copies of free software (and charge for
|
||||||
|
this service if you wish), that you receive source code or can get it
|
||||||
|
if you want it, that you can change the software or use pieces of it
|
||||||
|
in new free programs; and that you know you can do these things.
|
||||||
|
|
||||||
|
To protect your rights, we need to make restrictions that forbid
|
||||||
|
anyone to deny you these rights or to ask you to surrender the rights.
|
||||||
|
These restrictions translate to certain responsibilities for you if you
|
||||||
|
distribute copies of the software, or if you modify it.
|
||||||
|
|
||||||
|
For example, if you distribute copies of such a program, whether
|
||||||
|
gratis or for a fee, you must give the recipients all the rights that
|
||||||
|
you have. You must make sure that they, too, receive or can get the
|
||||||
|
source code. And you must show them these terms so they know their
|
||||||
|
rights.
|
||||||
|
|
||||||
|
We protect your rights with two steps: (1) copyright the software, and
|
||||||
|
(2) offer you this license which gives you legal permission to copy,
|
||||||
|
distribute and/or modify the software.
|
||||||
|
|
||||||
|
Also, for each author's protection and ours, we want to make certain
|
||||||
|
that everyone understands that there is no warranty for this free
|
||||||
|
software. If the software is modified by someone else and passed on, we
|
||||||
|
want its recipients to know that what they have is not the original, so
|
||||||
|
that any problems introduced by others will not reflect on the original
|
||||||
|
authors' reputations.
|
||||||
|
|
||||||
|
Finally, any free program is threatened constantly by software
|
||||||
|
patents. We wish to avoid the danger that redistributors of a free
|
||||||
|
program will individually obtain patent licenses, in effect making the
|
||||||
|
program proprietary. To prevent this, we have made it clear that any
|
||||||
|
patent must be licensed for everyone's free use or not licensed at all.
|
||||||
|
|
||||||
|
The precise terms and conditions for copying, distribution and
|
||||||
|
modification follow.
|
||||||
|
|
||||||
|
GNU GENERAL PUBLIC LICENSE
|
||||||
|
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||||
|
|
||||||
|
0. This License applies to any program or other work which contains
|
||||||
|
a notice placed by the copyright holder saying it may be distributed
|
||||||
|
under the terms of this General Public License. The "Program", below,
|
||||||
|
refers to any such program or work, and a "work based on the Program"
|
||||||
|
means either the Program or any derivative work under copyright law:
|
||||||
|
that is to say, a work containing the Program or a portion of it,
|
||||||
|
either verbatim or with modifications and/or translated into another
|
||||||
|
language. (Hereinafter, translation is included without limitation in
|
||||||
|
the term "modification".) Each licensee is addressed as "you".
|
||||||
|
|
||||||
|
Activities other than copying, distribution and modification are not
|
||||||
|
covered by this License; they are outside its scope. The act of
|
||||||
|
running the Program is not restricted, and the output from the Program
|
||||||
|
is covered only if its contents constitute a work based on the
|
||||||
|
Program (independent of having been made by running the Program).
|
||||||
|
Whether that is true depends on what the Program does.
|
||||||
|
|
||||||
|
1. You may copy and distribute verbatim copies of the Program's
|
||||||
|
source code as you receive it, in any medium, provided that you
|
||||||
|
conspicuously and appropriately publish on each copy an appropriate
|
||||||
|
copyright notice and disclaimer of warranty; keep intact all the
|
||||||
|
notices that refer to this License and to the absence of any warranty;
|
||||||
|
and give any other recipients of the Program a copy of this License
|
||||||
|
along with the Program.
|
||||||
|
|
||||||
|
You may charge a fee for the physical act of transferring a copy, and
|
||||||
|
you may at your option offer warranty protection in exchange for a fee.
|
||||||
|
|
||||||
|
2. You may modify your copy or copies of the Program or any portion
|
||||||
|
of it, thus forming a work based on the Program, and copy and
|
||||||
|
distribute such modifications or work under the terms of Section 1
|
||||||
|
above, provided that you also meet all of these conditions:
|
||||||
|
|
||||||
|
a) You must cause the modified files to carry prominent notices
|
||||||
|
stating that you changed the files and the date of any change.
|
||||||
|
|
||||||
|
b) You must cause any work that you distribute or publish, that in
|
||||||
|
whole or in part contains or is derived from the Program or any
|
||||||
|
part thereof, to be licensed as a whole at no charge to all third
|
||||||
|
parties under the terms of this License.
|
||||||
|
|
||||||
|
c) If the modified program normally reads commands interactively
|
||||||
|
when run, you must cause it, when started running for such
|
||||||
|
interactive use in the most ordinary way, to print or display an
|
||||||
|
announcement including an appropriate copyright notice and a
|
||||||
|
notice that there is no warranty (or else, saying that you provide
|
||||||
|
a warranty) and that users may redistribute the program under
|
||||||
|
these conditions, and telling the user how to view a copy of this
|
||||||
|
License. (Exception: if the Program itself is interactive but
|
||||||
|
does not normally print such an announcement, your work based on
|
||||||
|
the Program is not required to print an announcement.)
|
||||||
|
|
||||||
|
These requirements apply to the modified work as a whole. If
|
||||||
|
identifiable sections of that work are not derived from the Program,
|
||||||
|
and can be reasonably considered independent and separate works in
|
||||||
|
themselves, then this License, and its terms, do not apply to those
|
||||||
|
sections when you distribute them as separate works. But when you
|
||||||
|
distribute the same sections as part of a whole which is a work based
|
||||||
|
on the Program, the distribution of the whole must be on the terms of
|
||||||
|
this License, whose permissions for other licensees extend to the
|
||||||
|
entire whole, and thus to each and every part regardless of who wrote it.
|
||||||
|
|
||||||
|
Thus, it is not the intent of this section to claim rights or contest
|
||||||
|
your rights to work written entirely by you; rather, the intent is to
|
||||||
|
exercise the right to control the distribution of derivative or
|
||||||
|
collective works based on the Program.
|
||||||
|
|
||||||
|
In addition, mere aggregation of another work not based on the Program
|
||||||
|
with the Program (or with a work based on the Program) on a volume of
|
||||||
|
a storage or distribution medium does not bring the other work under
|
||||||
|
the scope of this License.
|
||||||
|
|
||||||
|
3. You may copy and distribute the Program (or a work based on it,
|
||||||
|
under Section 2) in object code or executable form under the terms of
|
||||||
|
Sections 1 and 2 above provided that you also do one of the following:
|
||||||
|
|
||||||
|
a) Accompany it with the complete corresponding machine-readable
|
||||||
|
source code, which must be distributed under the terms of Sections
|
||||||
|
1 and 2 above on a medium customarily used for software interchange; or,
|
||||||
|
|
||||||
|
b) Accompany it with a written offer, valid for at least three
|
||||||
|
years, to give any third party, for a charge no more than your
|
||||||
|
cost of physically performing source distribution, a complete
|
||||||
|
machine-readable copy of the corresponding source code, to be
|
||||||
|
distributed under the terms of Sections 1 and 2 above on a medium
|
||||||
|
customarily used for software interchange; or,
|
||||||
|
|
||||||
|
c) Accompany it with the information you received as to the offer
|
||||||
|
to distribute corresponding source code. (This alternative is
|
||||||
|
allowed only for noncommercial distribution and only if you
|
||||||
|
received the program in object code or executable form with such
|
||||||
|
an offer, in accord with Subsection b above.)
|
||||||
|
|
||||||
|
The source code for a work means the preferred form of the work for
|
||||||
|
making modifications to it. For an executable work, complete source
|
||||||
|
code means all the source code for all modules it contains, plus any
|
||||||
|
associated interface definition files, plus the scripts used to
|
||||||
|
control compilation and installation of the executable. However, as a
|
||||||
|
special exception, the source code distributed need not include
|
||||||
|
anything that is normally distributed (in either source or binary
|
||||||
|
form) with the major components (compiler, kernel, and so on) of the
|
||||||
|
operating system on which the executable runs, unless that component
|
||||||
|
itself accompanies the executable.
|
||||||
|
|
||||||
|
If distribution of executable or object code is made by offering
|
||||||
|
access to copy from a designated place, then offering equivalent
|
||||||
|
access to copy the source code from the same place counts as
|
||||||
|
distribution of the source code, even though third parties are not
|
||||||
|
compelled to copy the source along with the object code.
|
||||||
|
|
||||||
|
4. You may not copy, modify, sublicense, or distribute the Program
|
||||||
|
except as expressly provided under this License. Any attempt
|
||||||
|
otherwise to copy, modify, sublicense or distribute the Program is
|
||||||
|
void, and will automatically terminate your rights under this License.
|
||||||
|
However, parties who have received copies, or rights, from you under
|
||||||
|
this License will not have their licenses terminated so long as such
|
||||||
|
parties remain in full compliance.
|
||||||
|
|
||||||
|
5. You are not required to accept this License, since you have not
|
||||||
|
signed it. However, nothing else grants you permission to modify or
|
||||||
|
distribute the Program or its derivative works. These actions are
|
||||||
|
prohibited by law if you do not accept this License. Therefore, by
|
||||||
|
modifying or distributing the Program (or any work based on the
|
||||||
|
Program), you indicate your acceptance of this License to do so, and
|
||||||
|
all its terms and conditions for copying, distributing or modifying
|
||||||
|
the Program or works based on it.
|
||||||
|
|
||||||
|
6. Each time you redistribute the Program (or any work based on the
|
||||||
|
Program), the recipient automatically receives a license from the
|
||||||
|
original licensor to copy, distribute or modify the Program subject to
|
||||||
|
these terms and conditions. You may not impose any further
|
||||||
|
restrictions on the recipients' exercise of the rights granted herein.
|
||||||
|
You are not responsible for enforcing compliance by third parties to
|
||||||
|
this License.
|
||||||
|
|
||||||
|
7. If, as a consequence of a court judgment or allegation of patent
|
||||||
|
infringement or for any other reason (not limited to patent issues),
|
||||||
|
conditions are imposed on you (whether by court order, agreement or
|
||||||
|
otherwise) that contradict the conditions of this License, they do not
|
||||||
|
excuse you from the conditions of this License. If you cannot
|
||||||
|
distribute so as to satisfy simultaneously your obligations under this
|
||||||
|
License and any other pertinent obligations, then as a consequence you
|
||||||
|
may not distribute the Program at all. For example, if a patent
|
||||||
|
license would not permit royalty-free redistribution of the Program by
|
||||||
|
all those who receive copies directly or indirectly through you, then
|
||||||
|
the only way you could satisfy both it and this License would be to
|
||||||
|
refrain entirely from distribution of the Program.
|
||||||
|
|
||||||
|
If any portion of this section is held invalid or unenforceable under
|
||||||
|
any particular circumstance, the balance of the section is intended to
|
||||||
|
apply and the section as a whole is intended to apply in other
|
||||||
|
circumstances.
|
||||||
|
|
||||||
|
It is not the purpose of this section to induce you to infringe any
|
||||||
|
patents or other property right claims or to contest validity of any
|
||||||
|
such claims; this section has the sole purpose of protecting the
|
||||||
|
integrity of the free software distribution system, which is
|
||||||
|
implemented by public license practices. Many people have made
|
||||||
|
generous contributions to the wide range of software distributed
|
||||||
|
through that system in reliance on consistent application of that
|
||||||
|
system; it is up to the author/donor to decide if he or she is willing
|
||||||
|
to distribute software through any other system and a licensee cannot
|
||||||
|
impose that choice.
|
||||||
|
|
||||||
|
This section is intended to make thoroughly clear what is believed to
|
||||||
|
be a consequence of the rest of this License.
|
||||||
|
|
||||||
|
8. If the distribution and/or use of the Program is restricted in
|
||||||
|
certain countries either by patents or by copyrighted interfaces, the
|
||||||
|
original copyright holder who places the Program under this License
|
||||||
|
may add an explicit geographical distribution limitation excluding
|
||||||
|
those countries, so that distribution is permitted only in or among
|
||||||
|
countries not thus excluded. In such case, this License incorporates
|
||||||
|
the limitation as if written in the body of this License.
|
||||||
|
|
||||||
|
9. The Free Software Foundation may publish revised and/or new versions
|
||||||
|
of the General Public License from time to time. Such new versions will
|
||||||
|
be similar in spirit to the present version, but may differ in detail to
|
||||||
|
address new problems or concerns.
|
||||||
|
|
||||||
|
Each version is given a distinguishing version number. If the Program
|
||||||
|
specifies a version number of this License which applies to it and "any
|
||||||
|
later version", you have the option of following the terms and conditions
|
||||||
|
either of that version or of any later version published by the Free
|
||||||
|
Software Foundation. If the Program does not specify a version number of
|
||||||
|
this License, you may choose any version ever published by the Free Software
|
||||||
|
Foundation.
|
||||||
|
|
||||||
|
10. If you wish to incorporate parts of the Program into other free
|
||||||
|
programs whose distribution conditions are different, write to the author
|
||||||
|
to ask for permission. For software which is copyrighted by the Free
|
||||||
|
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||||
|
make exceptions for this. Our decision will be guided by the two goals
|
||||||
|
of preserving the free status of all derivatives of our free software and
|
||||||
|
of promoting the sharing and reuse of software generally.
|
||||||
|
|
||||||
|
NO WARRANTY
|
||||||
|
|
||||||
|
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||||
|
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||||
|
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||||
|
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||||
|
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||||
|
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||||
|
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||||
|
REPAIR OR CORRECTION.
|
||||||
|
|
||||||
|
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||||
|
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||||
|
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||||
|
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||||
|
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||||
|
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||||
|
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||||
|
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||||
|
POSSIBILITY OF SUCH DAMAGES.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
How to Apply These Terms to Your New Programs
|
||||||
|
|
||||||
|
If you develop a new program, and you want it to be of the greatest
|
||||||
|
possible use to the public, the best way to achieve this is to make it
|
||||||
|
free software which everyone can redistribute and change under these terms.
|
||||||
|
|
||||||
|
To do so, attach the following notices to the program. It is safest
|
||||||
|
to attach them to the start of each source file to most effectively
|
||||||
|
convey the exclusion of warranty; and each file should have at least
|
||||||
|
the "copyright" line and a pointer to where the full notice is found.
|
||||||
|
|
||||||
|
<one line to give the program's name and a brief idea of what it does.>
|
||||||
|
Copyright (C) <year> <name of author>
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License along
|
||||||
|
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
|
||||||
|
Also add information on how to contact you by electronic and paper mail.
|
||||||
|
|
||||||
|
If the program is interactive, make it output a short notice like this
|
||||||
|
when it starts in an interactive mode:
|
||||||
|
|
||||||
|
Gnomovision version 69, Copyright (C) year name of author
|
||||||
|
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||||
|
This is free software, and you are welcome to redistribute it
|
||||||
|
under certain conditions; type `show c' for details.
|
||||||
|
|
||||||
|
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||||
|
parts of the General Public License. Of course, the commands you use may
|
||||||
|
be called something other than `show w' and `show c'; they could even be
|
||||||
|
mouse-clicks or menu items--whatever suits your program.
|
||||||
|
|
||||||
|
You should also get your employer (if you work as a programmer) or your
|
||||||
|
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||||
|
necessary. Here is a sample; alter the names:
|
||||||
|
|
||||||
|
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||||
|
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||||
|
|
||||||
|
<signature of Ty Coon>, 1 April 1989
|
||||||
|
Ty Coon, President of Vice
|
||||||
|
|
||||||
|
This General Public License does not permit incorporating your program into
|
||||||
|
proprietary programs. If your program is a subroutine library, you may
|
||||||
|
consider it more useful to permit linking proprietary applications with the
|
||||||
|
library. If this is what you want to do, use the GNU Lesser General
|
||||||
|
Public License instead of this License.
|
||||||
|
|
27
README.md
Normal file
27
README.md
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
[](https://gitlab.gnome.org/GNOME/gnome-control-center/pipelines)
|
||||||
|
[](https://gnome.pages.gitlab.gnome.org/gnome-control-center/)
|
||||||
|
[](https://gitlab.gnome.org/GNOME/gnome-control-center/blob/main/COPYING)
|
||||||
|
|
||||||
|
GNOME Settings
|
||||||
|
====================
|
||||||
|
|
||||||
|
GNOME Settings is GNOME's main interface for configuration of various aspects of your desktop.
|
||||||
|
|
||||||
|
If you are looking for usage tips and instructions, you can find it at the [User Documentation](https://help.gnome.org/users/gnome-help/stable/prefs.html) (translated in various languages).
|
||||||
|
|
||||||
|
## Reporting Issues
|
||||||
|
|
||||||
|
Before reporting any bugs or opening feature requests, [read the communication guidelines](https://gitlab.gnome.org/GNOME/gnome-control-center/blob/main/docs/CODE_OF_CONDUCT.md#communication-guidelines).
|
||||||
|
|
||||||
|
Report issues to the [GNOME issue tracking system](https://gitlab.gnome.org/GNOME/gnome-control-center/issues).
|
||||||
|
|
||||||
|
## Feature Requests
|
||||||
|
|
||||||
|
For feature requests or conceptual changes, please start a topic on [GNOME Discourse](https://discourse.gnome.org/tags/settings).
|
||||||
|
|
||||||
|
## Contributing
|
||||||
|
|
||||||
|
See [`docs/CONTRIBUTING.md`](docs/CONTRIBUTING.md) for details on the contribution process, and [`docs/CODING_STYLE.md`](docs/CODING_STYLE.md)
|
||||||
|
for the coding style guidelines.
|
||||||
|
|
||||||
|
Visit the [Settings development wiki](https://gitlab.gnome.org/GNOME/gnome-control-center/-/wikis/home) for more information.
|
61
build-aux/ci/ci-helper.sh
Executable file
61
build-aux/ci/ci-helper.sh
Executable file
|
@ -0,0 +1,61 @@
|
||||||
|
#!/bin/bash -e
|
||||||
|
|
||||||
|
function do_print_labels(){
|
||||||
|
|
||||||
|
if [[ -n "${1}" ]]; then
|
||||||
|
label_len=${#1}
|
||||||
|
span=$(((54 - $label_len) / 2))
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "= ======================================================== ="
|
||||||
|
printf "%s %${span}s %s %${span}s %s\n" "=" "" "$1" "" "="
|
||||||
|
echo "= ======================================================== ="
|
||||||
|
else
|
||||||
|
echo "= ========================= Done ========================= ="
|
||||||
|
echo
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
function do_show_info(){
|
||||||
|
|
||||||
|
local compiler=gcc
|
||||||
|
|
||||||
|
echo -n "Processors: "; grep -c ^processor /proc/cpuinfo
|
||||||
|
grep ^MemTotal /proc/meminfo
|
||||||
|
id; uname -a
|
||||||
|
printenv
|
||||||
|
echo '-----------------------------------------'
|
||||||
|
cat /etc/*-release
|
||||||
|
echo '-----------------------------------------'
|
||||||
|
|
||||||
|
if [[ ! -z $CC ]]; then
|
||||||
|
compiler=$CC
|
||||||
|
fi
|
||||||
|
echo 'Compiler version'
|
||||||
|
$compiler --version
|
||||||
|
echo '-----------------------------------------'
|
||||||
|
$compiler -dM -E -x c /dev/null
|
||||||
|
echo '-----------------------------------------'
|
||||||
|
}
|
||||||
|
|
||||||
|
function do_check_warnings(){
|
||||||
|
|
||||||
|
cat compilation.log | grep "warning:" | awk '{total+=1}END{print "Total number of warnings: "total}'
|
||||||
|
}
|
||||||
|
|
||||||
|
# ----------- -----------
|
||||||
|
if [[ $1 == "INFO" ]]; then
|
||||||
|
do_print_labels 'Build environment '
|
||||||
|
do_show_info
|
||||||
|
do_print_labels
|
||||||
|
|
||||||
|
elif [[ $1 == "GIT_INFO" ]]; then
|
||||||
|
do_print_labels 'Commit'
|
||||||
|
git log --pretty=format:"%h %cd %s" -1; echo
|
||||||
|
do_print_labels
|
||||||
|
|
||||||
|
elif [[ $1 == "WARNINGS" ]]; then
|
||||||
|
do_print_labels 'Warning Report '
|
||||||
|
do_check_warnings
|
||||||
|
do_print_labels
|
||||||
|
fi
|
19
build-aux/ci/lsan.supp
Normal file
19
build-aux/ci/lsan.supp
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
# https://bugs.freedesktop.org/show_bug.cgi?id=105466
|
||||||
|
leak:libfontconfig.so.1
|
||||||
|
|
||||||
|
# Unknown and unreported bugs
|
||||||
|
leak:__GI___vasprintf_chk
|
||||||
|
leak:__interceptor_malloc
|
||||||
|
leak:__alloc_dir
|
||||||
|
leak:libglib-2.0.so.0
|
||||||
|
|
||||||
|
# Needing attention
|
||||||
|
leak:<unknown module>
|
||||||
|
leak:test_timezone_gfx
|
||||||
|
|
||||||
|
########
|
||||||
|
# __GI___vasprintf_chk /usr/src/debug/glibc-2.27.9000-432-g104502102c/debug/vasprintf_chk.c:80
|
||||||
|
# __alloc_dir ../sysdeps/posix/opendir.c:118
|
||||||
|
# g_malloc (/lib64/libglib-2.0.so.0+0x523c5)
|
||||||
|
# g_realloc (/lib64/libglib-2.0.so.0+0x5247d)
|
||||||
|
########
|
22
build-aux/flatpak/libparted-include.patch
Normal file
22
build-aux/flatpak/libparted-include.patch
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
From ba5e0451b51c983e40afd123b6e0d3eddb55e610 Mon Sep 17 00:00:00 2001
|
||||||
|
From: "Richard W.M. Jones" <rjones@redhat.com>
|
||||||
|
Date: Sat, 24 Mar 2018 17:37:02 +0000
|
||||||
|
Subject: linux: Include <sys/sysmacros.h> for major() macro.
|
||||||
|
|
||||||
|
Since glibc 2.27 this header is required.
|
||||||
|
---
|
||||||
|
libparted/arch/linux.c | 1 +
|
||||||
|
1 file changed, 1 insertion(+)
|
||||||
|
|
||||||
|
diff --git a/libparted/arch/linux.c b/libparted/arch/linux.c
|
||||||
|
index 31b98ab..7e86b51 100644
|
||||||
|
--- a/libparted/arch/linux.c
|
||||||
|
+++ b/libparted/arch/linux.c
|
||||||
|
@@ -41,6 +41,7 @@
|
||||||
|
#include <sys/utsname.h> /* for uname() */
|
||||||
|
#include <scsi/scsi.h>
|
||||||
|
#include <assert.h>
|
||||||
|
+#include <sys/sysmacros.h>
|
||||||
|
#ifdef ENABLE_DEVICE_MAPPER
|
||||||
|
#include <libdevmapper.h>
|
||||||
|
#endif
|
939
build-aux/flatpak/org.gnome.Settings.Devel.json
Normal file
939
build-aux/flatpak/org.gnome.Settings.Devel.json
Normal file
|
@ -0,0 +1,939 @@
|
||||||
|
{
|
||||||
|
"app-id" : "org.gnome.Settings.Devel",
|
||||||
|
"runtime" : "org.gnome.Sdk",
|
||||||
|
"runtime-version" : "master",
|
||||||
|
"sdk" : "org.gnome.Sdk",
|
||||||
|
"command" : "gnome-control-center",
|
||||||
|
"tags" : [
|
||||||
|
"devel"
|
||||||
|
],
|
||||||
|
"desktop-file-name-prefix" : "(Development) ",
|
||||||
|
"finish-args" : [
|
||||||
|
"--device=dri",
|
||||||
|
"--env=DCONF_USER_CONFIG_DIR=.config/dconf",
|
||||||
|
"--filesystem=host",
|
||||||
|
"--own-name=org.gnome.SessionManager",
|
||||||
|
"--share=ipc",
|
||||||
|
"--share=network",
|
||||||
|
"--socket=x11",
|
||||||
|
"--socket=pulseaudio",
|
||||||
|
"--socket=session-bus",
|
||||||
|
"--socket=system-bus",
|
||||||
|
"--socket=wayland"
|
||||||
|
],
|
||||||
|
"build-options" : {
|
||||||
|
"cflags" : "-O2 -g",
|
||||||
|
"cxxflags" : "-O2 -g",
|
||||||
|
"env" : {
|
||||||
|
"V" : "1"
|
||||||
|
},
|
||||||
|
"build-args": [
|
||||||
|
"--share=network"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"x-run-args" : [
|
||||||
|
"--verbose"
|
||||||
|
],
|
||||||
|
"cleanup" : [
|
||||||
|
"/include",
|
||||||
|
"/share/aclocal",
|
||||||
|
"/man",
|
||||||
|
"/share/man",
|
||||||
|
"/share/gtk-doc",
|
||||||
|
"/share/vala",
|
||||||
|
"*.la",
|
||||||
|
"*.a"
|
||||||
|
],
|
||||||
|
"modules" : [
|
||||||
|
{
|
||||||
|
"name" : "pwquality",
|
||||||
|
"buildsystem" : "autotools",
|
||||||
|
"config-opts" : [
|
||||||
|
"--disable-python-bindings"
|
||||||
|
],
|
||||||
|
"sources" : [
|
||||||
|
{
|
||||||
|
"type" : "git",
|
||||||
|
"url" : "https://github.com/libpwquality/libpwquality.git"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name" : "intltool",
|
||||||
|
"cleanup" : [ "*" ],
|
||||||
|
"sources" : [
|
||||||
|
{
|
||||||
|
"type" : "archive",
|
||||||
|
"url" : "https://launchpad.net/intltool/trunk/0.51.0/+download/intltool-0.51.0.tar.gz",
|
||||||
|
"sha256" : "67c74d94196b153b774ab9f89b2fa6c6ba79352407037c8c14d5aeb334e959cd"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name" : "polkit",
|
||||||
|
"buildsystem" : "meson",
|
||||||
|
"config-opts" : [
|
||||||
|
"-Dauthfw=shadow"
|
||||||
|
],
|
||||||
|
"rm-configure" : true,
|
||||||
|
"cleanup" : [
|
||||||
|
"/bin/*",
|
||||||
|
"/etc/pam.d",
|
||||||
|
"/etc/dbus-1",
|
||||||
|
"/share/dbus-1/system-services/*",
|
||||||
|
"/share/polkit-1",
|
||||||
|
"/lib/polkit-1"
|
||||||
|
],
|
||||||
|
"sources" : [
|
||||||
|
{
|
||||||
|
"type" : "git",
|
||||||
|
"url" : "https://gitlab.freedesktop.org/polkit/polkit.git",
|
||||||
|
"tag" : "124",
|
||||||
|
"commit" : "82f0924dc0eb23b9df68e88dbaf9e07c81940a5a"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name" : "json-c",
|
||||||
|
"buildsystem" : "cmake",
|
||||||
|
"sources" : [
|
||||||
|
{
|
||||||
|
"type" : "archive",
|
||||||
|
"url" : "https://github.com/json-c/json-c/archive/refs/tags/json-c-0.17-20230812.tar.gz",
|
||||||
|
"sha256" : "024d302a3aadcbf9f78735320a6d5aedf8b77876c8ac8bbb95081ca55054c7eb"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name" : "accountsservice",
|
||||||
|
"buildsystem" : "meson",
|
||||||
|
"config-opts" : [
|
||||||
|
"-Dsystemdsystemunitdir=no",
|
||||||
|
"-Dintrospection=false",
|
||||||
|
"-Dvapi=false"
|
||||||
|
],
|
||||||
|
"sources" : [
|
||||||
|
{
|
||||||
|
"type" : "git",
|
||||||
|
"url" : "https://gitlab.freedesktop.org/accountsservice/accountsservice",
|
||||||
|
"branch" : "main"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name" : "libusb1",
|
||||||
|
"buildsystem" : "autotools",
|
||||||
|
"config-opts" : [
|
||||||
|
"--disable-udev"
|
||||||
|
],
|
||||||
|
"sources" : [
|
||||||
|
{
|
||||||
|
"type" : "git",
|
||||||
|
"url" : "https://github.com/libusb/libusb.git"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name" : "gusb",
|
||||||
|
"buildsystem" : "meson",
|
||||||
|
"config-opts" : [
|
||||||
|
"-Ddocs=false",
|
||||||
|
"-Dtests=false",
|
||||||
|
"-Dvapi=false"
|
||||||
|
],
|
||||||
|
"sources" : [
|
||||||
|
{
|
||||||
|
"type" : "git",
|
||||||
|
"url" : "https://github.com/hughsie/libgusb.git",
|
||||||
|
"branch" : "main"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name" : "udev",
|
||||||
|
"config-opts" : [
|
||||||
|
"--disable-hwdb",
|
||||||
|
"--disable-logging",
|
||||||
|
"--disable-gudev",
|
||||||
|
"--disable-introspection",
|
||||||
|
"--disable-keymap",
|
||||||
|
"--disable-mtd_probe"
|
||||||
|
],
|
||||||
|
"cleanup" : [
|
||||||
|
"/include",
|
||||||
|
"/etc",
|
||||||
|
"/libexec",
|
||||||
|
"/sbin",
|
||||||
|
"/lib/pkgconfig",
|
||||||
|
"/man",
|
||||||
|
"/share/aclocal",
|
||||||
|
"/share/doc",
|
||||||
|
"/share/gtk-doc",
|
||||||
|
"/share/man",
|
||||||
|
"/share/pkgconfig",
|
||||||
|
"*.la",
|
||||||
|
"*.a"
|
||||||
|
],
|
||||||
|
"sources" : [
|
||||||
|
{
|
||||||
|
"type" : "git",
|
||||||
|
"url" : "https://github.com/gentoo/eudev.git"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name" : "colord",
|
||||||
|
"buildsystem" : "meson",
|
||||||
|
"config-opts" : [
|
||||||
|
"-Dargyllcms_sensor=false",
|
||||||
|
"-Dbash_completion=false",
|
||||||
|
"-Dman=false",
|
||||||
|
"-Dudev_rules=false",
|
||||||
|
"-Dsystemd=false",
|
||||||
|
"-Dvapi=false",
|
||||||
|
"-Ddocs=false",
|
||||||
|
"-Dtests=false",
|
||||||
|
"-Dinstalled_tests=false"
|
||||||
|
],
|
||||||
|
"sources" : [
|
||||||
|
{
|
||||||
|
"type" : "git",
|
||||||
|
"branch" : "main",
|
||||||
|
"url" : "https://github.com/hughsie/colord.git"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name" : "colord-gtk",
|
||||||
|
"buildsystem" : "meson",
|
||||||
|
"config-opts" : [
|
||||||
|
"-Dman=false"
|
||||||
|
],
|
||||||
|
"sources" : [
|
||||||
|
{
|
||||||
|
"type" : "git",
|
||||||
|
"branch" : "main",
|
||||||
|
"url" : "https://github.com/hughsie/colord-gtk.git"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name" : "rest",
|
||||||
|
"buildsystem" : "meson",
|
||||||
|
"config-opts" : [
|
||||||
|
"-Dgtk_doc=false"
|
||||||
|
],
|
||||||
|
"sources" : [
|
||||||
|
{
|
||||||
|
"type" : "git",
|
||||||
|
"branch" : "master",
|
||||||
|
"url" : "https://gitlab.gnome.org/GNOME/librest.git"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name" : "gnome-online-accounts",
|
||||||
|
"buildsystem" : "meson",
|
||||||
|
"build-options" : {
|
||||||
|
"cflags" : "-Wno-error"
|
||||||
|
},
|
||||||
|
"config-opts" : [
|
||||||
|
"-Ddocumentation=false",
|
||||||
|
"-Dintrospection=false",
|
||||||
|
"-Dvapi=false"
|
||||||
|
],
|
||||||
|
"sources" : [
|
||||||
|
{
|
||||||
|
"type" : "git",
|
||||||
|
"url" : "https://gitlab.gnome.org/GNOME/gnome-online-accounts.git"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"modules" : [
|
||||||
|
{
|
||||||
|
"name" : "keyutils",
|
||||||
|
"buildsystem" : "simple",
|
||||||
|
"build-commands" : [
|
||||||
|
"make NO_ARLIB=1 BINDIR=/app/bin SBINDIR=/app/sbin LIBDIR=/app/lib INCLUDEDIR=/app/include MANDIR=/app/share/man SHAREDIR=/app install"
|
||||||
|
],
|
||||||
|
"sources" : [
|
||||||
|
{
|
||||||
|
"type" : "git",
|
||||||
|
"url" : "https://git.kernel.org/pub/scm/linux/kernel/git/dhowells/keyutils.git"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name" : "gnome-desktop",
|
||||||
|
"buildsystem" : "meson",
|
||||||
|
"sources" : [
|
||||||
|
{
|
||||||
|
"type" : "git",
|
||||||
|
"url" : "https://gitlab.gnome.org/GNOME/gnome-desktop.git"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name" : "geocode-glib",
|
||||||
|
"buildsystem" : "meson",
|
||||||
|
"config-opts" : [
|
||||||
|
"-Denable-installed-tests=false",
|
||||||
|
"-Denable-introspection=false",
|
||||||
|
"-Denable-gtk-doc=false",
|
||||||
|
"-Dsoup2=false"
|
||||||
|
],
|
||||||
|
"sources" : [
|
||||||
|
{
|
||||||
|
"type" : "git",
|
||||||
|
"url" : "https://gitlab.gnome.org/GNOME/geocode-glib.git"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name" : "libgweather",
|
||||||
|
"buildsystem" : "meson",
|
||||||
|
"config-opts" : [
|
||||||
|
"-Denable_vala=false",
|
||||||
|
"-Dgtk_doc=false",
|
||||||
|
"-Dintrospection=false",
|
||||||
|
"-Dtests=false"
|
||||||
|
],
|
||||||
|
"sources" : [
|
||||||
|
{
|
||||||
|
"type" : "git",
|
||||||
|
"url" : "https://gitlab.gnome.org/GNOME/libgweather.git",
|
||||||
|
"branch" : "main"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name" : "upower",
|
||||||
|
"buildsystem" : "meson",
|
||||||
|
"config-opts" : [
|
||||||
|
"-Dsystemdsystemunitdir=/app/lib/systemd/system",
|
||||||
|
"-Dudevrulesdir=/app/lib/udev",
|
||||||
|
"-Dudevhwdbdir=/app/lib/udev",
|
||||||
|
"-Dgtk-doc=false",
|
||||||
|
"-Dman=false",
|
||||||
|
"-Dintrospection=disabled"
|
||||||
|
],
|
||||||
|
"sources" : [
|
||||||
|
{
|
||||||
|
"type" : "git",
|
||||||
|
"url" : "https://gitlab.freedesktop.org/upower/upower.git",
|
||||||
|
"tag" : "v1.90.6"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name" : "libwacom",
|
||||||
|
"buildsystem" : "meson",
|
||||||
|
"config-opts" : [
|
||||||
|
"-Ddocumentation=disabled",
|
||||||
|
"-Dtests=disabled"
|
||||||
|
],
|
||||||
|
"sources" : [
|
||||||
|
{
|
||||||
|
"type" : "git",
|
||||||
|
"url" : "https://github.com/linuxwacom/libwacom.git"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name" : "libndp",
|
||||||
|
"buildsystem" : "autotools",
|
||||||
|
"sources" : [
|
||||||
|
{
|
||||||
|
"type" : "archive",
|
||||||
|
"url" : "http://libndp.org/files/libndp-1.6.tar.gz",
|
||||||
|
"sha256" : "0c7dfa84e013bd5e569ef2c6292a6f72cfaf14f4ff77a77425e52edc33ffac0e"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name" : "NetworkManager",
|
||||||
|
"buildsystem" : "meson",
|
||||||
|
"build-options" : {
|
||||||
|
"cflags" : "-ltinfo",
|
||||||
|
"cxxflags" : "-ltinfo"
|
||||||
|
},
|
||||||
|
"config-opts" : [
|
||||||
|
"-Dlibaudit=no",
|
||||||
|
"-Ddbus_conf_dir=/app/etc/dbus-1/system.d",
|
||||||
|
"-Ddnsmasq=/usr/bin/true",
|
||||||
|
"-Ddocs=false",
|
||||||
|
"-Dintrospection=false",
|
||||||
|
"-Diptables=/usr/bin/true",
|
||||||
|
"-Dlibpsl=false",
|
||||||
|
"-Dmodem_manager=false",
|
||||||
|
"-Dnm_cloud_setup=false",
|
||||||
|
"-Dnmtui=false",
|
||||||
|
"-Dovs=false",
|
||||||
|
"-Dppp=false",
|
||||||
|
"-Dqt=false",
|
||||||
|
"-Dselinux=false",
|
||||||
|
"-Dsession_tracking=no",
|
||||||
|
"-Dsystemdsystemunitdir=/app/lib/systemd/system",
|
||||||
|
"-Dudev_dir=/app/lib/udev",
|
||||||
|
"-Dsystemd_journal=false",
|
||||||
|
"-Dtests=no",
|
||||||
|
"-Dvapi=false"
|
||||||
|
],
|
||||||
|
"sources" : [
|
||||||
|
{
|
||||||
|
"type" : "git",
|
||||||
|
"branch": "main",
|
||||||
|
"url" : "https://gitlab.freedesktop.org/NetworkManager/NetworkManager.git"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name" : "mobile-broadband-provider-info",
|
||||||
|
"buildsystem" : "meson",
|
||||||
|
"sources" : [
|
||||||
|
{
|
||||||
|
"type" : "git",
|
||||||
|
"branch": "main",
|
||||||
|
"url" : "https://gitlab.gnome.org/GNOME/mobile-broadband-provider-info.git"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name" : "libnma",
|
||||||
|
"buildsystem" : "meson",
|
||||||
|
"config-opts" : [
|
||||||
|
"-Dlibnma_gtk4=true",
|
||||||
|
"-Dgtk_doc=false",
|
||||||
|
"-Dintrospection=false",
|
||||||
|
"-Dvapi=false"
|
||||||
|
],
|
||||||
|
"sources" : [
|
||||||
|
{
|
||||||
|
"type" : "git",
|
||||||
|
"url" : "https://gitlab.gnome.org/GNOME/libnma.git",
|
||||||
|
"branch" : "main"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name" : "network-manager-applet",
|
||||||
|
"buildsystem" : "meson",
|
||||||
|
"config-opts" : [
|
||||||
|
"-Dappindicator=no",
|
||||||
|
"-Dwwan=false",
|
||||||
|
"-Dselinux=false",
|
||||||
|
"-Dteam=false"
|
||||||
|
],
|
||||||
|
"sources" : [
|
||||||
|
{
|
||||||
|
"type" : "git",
|
||||||
|
"url" : "https://gitlab.gnome.org/GNOME/network-manager-applet.git",
|
||||||
|
"branch" : "main"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name" : "NetworkManager-openvpn",
|
||||||
|
"config-opts" : [
|
||||||
|
"--with-gnome",
|
||||||
|
"--with-gtk4"
|
||||||
|
],
|
||||||
|
"sources" : [
|
||||||
|
{
|
||||||
|
"type" : "git",
|
||||||
|
"branch": "main",
|
||||||
|
"url" : "https://gitlab.gnome.org/GNOME/NetworkManager-openvpn.git"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name" : "NetworkManager-vpnc",
|
||||||
|
"config-opts" : [
|
||||||
|
"--with-gnome",
|
||||||
|
"--with-gtk4"
|
||||||
|
],
|
||||||
|
"sources" : [
|
||||||
|
{
|
||||||
|
"type" : "git",
|
||||||
|
"branch": "main",
|
||||||
|
"url" : "https://gitlab.gnome.org/GNOME/NetworkManager-vpnc.git"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name" : "ModemManager",
|
||||||
|
"buildsystem" : "meson",
|
||||||
|
"config-opts" : [
|
||||||
|
"-Dintrospection=false",
|
||||||
|
"-Dbash_completion=false",
|
||||||
|
"-Dudevdir=/app/lib/udev",
|
||||||
|
"-Dsystemdsystemunitdir=/app/lib/systemd/system",
|
||||||
|
"-Ddbus_policy_dir=/app/etc/dbus-1/system.d",
|
||||||
|
"-Dsystemd_journal=false",
|
||||||
|
"-Dtests=false",
|
||||||
|
"-Dman=false",
|
||||||
|
"-Dfuzzer=false",
|
||||||
|
"-Dexamples=false",
|
||||||
|
"-Dmbim=false",
|
||||||
|
"-Dplugin_dell=disabled",
|
||||||
|
"-Dplugin_foxconn=disabled",
|
||||||
|
"-Dplugin_fibocom=disabled",
|
||||||
|
"-Dqmi=false",
|
||||||
|
"-Dqrtr=false"
|
||||||
|
],
|
||||||
|
"sources" : [
|
||||||
|
{
|
||||||
|
"type" : "git",
|
||||||
|
"url" : "https://gitlab.freedesktop.org/mobile-broadband/ModemManager.git",
|
||||||
|
"branch" : "main"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name" : "gnome-settings-daemon",
|
||||||
|
"buildsystem" : "meson",
|
||||||
|
"config-opts" : [
|
||||||
|
"-Dudev_dir=/app/lib/udev",
|
||||||
|
"-Dsystemd=false"
|
||||||
|
],
|
||||||
|
"sources" : [
|
||||||
|
{
|
||||||
|
"type" : "git",
|
||||||
|
"url" : "https://gitlab.gnome.org/GNOME/gnome-settings-daemon.git"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"modules": [
|
||||||
|
{
|
||||||
|
"name": "libcanberra",
|
||||||
|
"sources": [
|
||||||
|
{
|
||||||
|
"type": "archive",
|
||||||
|
"url": "http://0pointer.de/lennart/projects/libcanberra/libcanberra-0.30.tar.xz",
|
||||||
|
"sha256": "c2b671e67e0c288a69fc33dc1b6f1b534d07882c2aceed37004bf48c601afa72"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"config-opts": [
|
||||||
|
"--disable-alsa",
|
||||||
|
"--disable-null",
|
||||||
|
"--disable-oss"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name" : "gsound",
|
||||||
|
"buildsystem" : "meson",
|
||||||
|
"sources" : [
|
||||||
|
{
|
||||||
|
"type" : "git",
|
||||||
|
"url" : "https://gitlab.gnome.org/GNOME/gsound.git"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name" : "gnome-bluetooth",
|
||||||
|
"buildsystem" : "meson",
|
||||||
|
"config-opts" : [
|
||||||
|
"-Dintrospection=false"
|
||||||
|
],
|
||||||
|
"sources" : [
|
||||||
|
{
|
||||||
|
"type" : "git",
|
||||||
|
"url" : "https://gitlab.gnome.org/GNOME/gnome-bluetooth.git"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name" : "openldap",
|
||||||
|
"buildsystem" : "autotools",
|
||||||
|
"config-opts" : [
|
||||||
|
"--disable-slapd"
|
||||||
|
],
|
||||||
|
"sources" : [
|
||||||
|
{
|
||||||
|
"type": "archive",
|
||||||
|
"url": "https://www.openldap.org/software/download/OpenLDAP/openldap-release/openldap-2.6.8.tgz",
|
||||||
|
"sha256": "48969323e94e3be3b03c6a132942dcba7ef8d545f2ad35401709019f696c3c4e"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name" : "libtirpc",
|
||||||
|
"buildsystem" : "autotools",
|
||||||
|
"sources" : [
|
||||||
|
{
|
||||||
|
"type" : "archive",
|
||||||
|
"url" : "http://downloads.sourceforge.net/sourceforge/libtirpc/libtirpc-1.2.6.tar.bz2",
|
||||||
|
"sha256" : "4278e9a5181d5af9cd7885322fdecebc444f9a3da87c526e7d47f7a12a37d1cc"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name" : "rpcsvc-proto",
|
||||||
|
"buildsystem" : "autotools",
|
||||||
|
"sources" : [
|
||||||
|
{
|
||||||
|
"type" : "archive",
|
||||||
|
"url" : "https://github.com/thkukuk/rpcsvc-proto/archive/v1.4.tar.gz",
|
||||||
|
"sha256" : "eaa227686b84e8ae20181d2119c0ccac29d82371441844008019a134dafe3613"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name" : "lmdb",
|
||||||
|
"buildsystem" : "simple",
|
||||||
|
"build-commands" : [
|
||||||
|
"cd libraries/liblmdb/ && make prefix=/app install"
|
||||||
|
],
|
||||||
|
"sources" : [
|
||||||
|
{
|
||||||
|
"type" : "archive",
|
||||||
|
"url" : "https://github.com/LMDB/lmdb/archive/LMDB_0.9.23.tar.gz",
|
||||||
|
"sha256" : "abf42e91f046787ed642d9eb21812a5c473f3ba5854124484d16eadbe0aa9c81"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "yapp-driver",
|
||||||
|
"buildsystem": "simple",
|
||||||
|
"build-commands": [
|
||||||
|
"perl Makefile.PL",
|
||||||
|
"make install -j1"
|
||||||
|
],
|
||||||
|
"build-options" : {
|
||||||
|
"env" : {
|
||||||
|
"PERL5LIB": "/app/lib/perl5/",
|
||||||
|
"PERL_MM_OPT": "INSTALL_BASE=/app"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"cleanup": [ "*" ],
|
||||||
|
"sources": [
|
||||||
|
{
|
||||||
|
"type": "archive",
|
||||||
|
"url": "https://cpan.metacpan.org/authors/id/W/WB/WBRASWELL/Parse-Yapp-1.21.tar.gz",
|
||||||
|
"sha256": "3810e998308fba2e0f4f26043035032b027ce51ce5c8a52a8b8e340ca65f13e5"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name" : "samba",
|
||||||
|
"buildsystem" : "autotools",
|
||||||
|
"config-opts" : [
|
||||||
|
"--without-json",
|
||||||
|
"--without-ad-dc",
|
||||||
|
"--without-pam"
|
||||||
|
],
|
||||||
|
"build-options" : {
|
||||||
|
"env" : {
|
||||||
|
"PERL5LIB": "/app/lib/perl5/",
|
||||||
|
"PERL_MM_OPT": "INSTALL_BASE=/app"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"sources" : [
|
||||||
|
{
|
||||||
|
"type" : "archive",
|
||||||
|
"url" : "https://download.samba.org/pub/samba/stable/samba-4.20.2.tar.gz",
|
||||||
|
"sha256" : "f969ffed58ccf3e85cbbcc0e33a1726d025c2b40f42a653b1125b82b92d2e0e5"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name" : "libgtop2",
|
||||||
|
"buildsystem" : "autotools",
|
||||||
|
"config-opts" : [
|
||||||
|
"--disable-introspection"
|
||||||
|
],
|
||||||
|
"sources" : [
|
||||||
|
{
|
||||||
|
"type" : "git",
|
||||||
|
"url" : "https://gitlab.gnome.org/GNOME/libgtop.git"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name" : "udisks",
|
||||||
|
"buildsystem" : "autotools",
|
||||||
|
"config-opts" : [
|
||||||
|
"--disable-introspection",
|
||||||
|
"--disable-lvm2",
|
||||||
|
"--enable-daemon=no",
|
||||||
|
"--with-systemdsystemunitdir=/app/lib/systemd/system",
|
||||||
|
"--with-tmpfilesdir=/app/lib/tmpfiles.d"
|
||||||
|
],
|
||||||
|
"sources" : [
|
||||||
|
{
|
||||||
|
"type" : "git",
|
||||||
|
"url" : "https://github.com/storaged-project/udisks.git"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "python3-jinja2",
|
||||||
|
"buildsystem": "simple",
|
||||||
|
"build-commands": [
|
||||||
|
"pip3 install --verbose --exists-action=i --no-index --find-links=\"file://${PWD}\" --prefix=${FLATPAK_DEST} \"jinja2\" --no-build-isolation"
|
||||||
|
],
|
||||||
|
"sources": [
|
||||||
|
{
|
||||||
|
"type": "file",
|
||||||
|
"url": "https://files.pythonhosted.org/packages/1d/97/2288fe498044284f39ab8950703e88abbac2abbdf65524d576157af70556/MarkupSafe-2.1.1.tar.gz",
|
||||||
|
"sha256": "7f91197cc9e48f989d12e4e6fbc46495c446636dfc81b9ccf50bb0ec74b91d4b"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "file",
|
||||||
|
"url": "https://files.pythonhosted.org/packages/bc/c3/f068337a370801f372f2f8f6bad74a5c140f6fda3d9de154052708dd3c65/Jinja2-3.1.2-py3-none-any.whl",
|
||||||
|
"sha256": "6088930bfe239f0e6710546ab9c19c9ef35e29792895fed6e6e31a023a182a61"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "python3-attrs",
|
||||||
|
"buildsystem": "simple",
|
||||||
|
"build-commands": [
|
||||||
|
"pip3 install --verbose --exists-action=i --no-index --find-links=\"file://${PWD}\" --prefix=${FLATPAK_DEST} \"attrs\" --no-build-isolation"
|
||||||
|
],
|
||||||
|
"sources": [
|
||||||
|
{
|
||||||
|
"type": "file",
|
||||||
|
"url": "https://files.pythonhosted.org/packages/f0/eb/fcb708c7bf5056045e9e98f62b93bd7467eb718b0202e7698eb11d66416c/attrs-23.1.0-py3-none-any.whl",
|
||||||
|
"sha256": "1f28b4522cdc2fb4256ac1a020c78acf9cba2c6b461ccd2c126f3aa8e8335d04"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name" : "libei",
|
||||||
|
"buildsystem" : "meson",
|
||||||
|
"config-opts" : [
|
||||||
|
"-Dliboeffis=disabled",
|
||||||
|
"-Dtests=disabled"
|
||||||
|
],
|
||||||
|
"sources" : [
|
||||||
|
{
|
||||||
|
"type" : "git",
|
||||||
|
"branch" : "main",
|
||||||
|
"url" : "https://gitlab.freedesktop.org/libinput/libei.git"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "python3-docutils",
|
||||||
|
"buildsystem": "simple",
|
||||||
|
"build-commands": [
|
||||||
|
"pip3 install --verbose --exists-action=i --no-index --find-links=\"file://${PWD}\" --prefix=${FLATPAK_DEST} \"docutils\" --no-build-isolation"
|
||||||
|
],
|
||||||
|
"sources": [
|
||||||
|
{
|
||||||
|
"type": "file",
|
||||||
|
"url": "https://files.pythonhosted.org/packages/8f/d7/9322c609343d929e75e7e5e6255e614fcc67572cfd083959cdef3b7aad79/docutils-0.21.2-py3-none-any.whl",
|
||||||
|
"sha256": "dafca5b9e384f0e419294eb4d2ff9fa826435bf15f15b7bd45723e8ad76811b2"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name" : "mutter",
|
||||||
|
"buildsystem" : "meson",
|
||||||
|
"config-opts" : [
|
||||||
|
"-Dgles2=false",
|
||||||
|
"-Dglx=false",
|
||||||
|
"-Dxwayland=false",
|
||||||
|
"-Dwayland=false",
|
||||||
|
"-Dlogind=false",
|
||||||
|
"-Dbash_completion=false",
|
||||||
|
"-Dnative_backend=false",
|
||||||
|
"-Dremote_desktop=false",
|
||||||
|
"-Degl_device=false",
|
||||||
|
"-Dudev=false",
|
||||||
|
"-Dstartup_notification=false",
|
||||||
|
"-Dsm=false",
|
||||||
|
"-Dintrospection=true",
|
||||||
|
"-Ddocs=false",
|
||||||
|
"-Dtests=disabled",
|
||||||
|
"-Dprofiler=false"
|
||||||
|
],
|
||||||
|
"sources" : [
|
||||||
|
{
|
||||||
|
"type" : "git",
|
||||||
|
"branch" : "main",
|
||||||
|
"url" : "https://gitlab.gnome.org/gnome/mutter.git"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"modules": [
|
||||||
|
{
|
||||||
|
"name" : "libdisplay-info",
|
||||||
|
"buildsystem" : "meson",
|
||||||
|
"sources" : [
|
||||||
|
{
|
||||||
|
"type" : "git",
|
||||||
|
"branch" : "main",
|
||||||
|
"url" : "https://gitlab.freedesktop.org/emersion/libdisplay-info.git"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"modules": [
|
||||||
|
{
|
||||||
|
"name" : "hwdata",
|
||||||
|
"config-opts" : [
|
||||||
|
"--prefix=/app",
|
||||||
|
"--datadir=/app/share",
|
||||||
|
"--disable-blacklist"
|
||||||
|
],
|
||||||
|
"sources" : [
|
||||||
|
{
|
||||||
|
"type" : "git",
|
||||||
|
"url" : "https://github.com/vcrhonek/hwdata.git"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name" : "libical",
|
||||||
|
"buildsystem" : "cmake",
|
||||||
|
"config-opts" : [
|
||||||
|
"-DICAL_BUILD_DOCS=false",
|
||||||
|
"-DICAL_GLIB=true",
|
||||||
|
"-DLIBICAL_BUILD_TESTING=false"
|
||||||
|
],
|
||||||
|
"sources" : [
|
||||||
|
{
|
||||||
|
"type" : "git",
|
||||||
|
"url" : "https://github.com/libical/libical.git"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name" : "evolution-data-server",
|
||||||
|
"buildsystem" : "cmake",
|
||||||
|
"config-opts" : [
|
||||||
|
"-DWITH_LIBDB=OFF"
|
||||||
|
],
|
||||||
|
"sources" : [
|
||||||
|
{
|
||||||
|
"type" : "git",
|
||||||
|
"url" : "https://gitlab.gnome.org/GNOME/evolution-data-server.git"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name" : "libstartup-notification",
|
||||||
|
"buildsystem" : "autotools",
|
||||||
|
"sources" : [
|
||||||
|
{
|
||||||
|
"type" : "git",
|
||||||
|
"url" : "https://gitlab.freedesktop.org/xdg/startup-notification.git"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name" : "sassc",
|
||||||
|
"buildsystem" : "simple",
|
||||||
|
"sources" : [
|
||||||
|
{
|
||||||
|
"type" : "git",
|
||||||
|
"url" : "https://github.com/sass/libsass"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type" : "git",
|
||||||
|
"url" : "https://github.com/sass/sassc.git",
|
||||||
|
"dest" : "sassc"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"build-commands" : [
|
||||||
|
"make -C sassc",
|
||||||
|
"PREFIX=/app make -C sassc install"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name" : "cogl",
|
||||||
|
"buildsystem" : "autotools",
|
||||||
|
"sources" : [
|
||||||
|
{
|
||||||
|
"type" : "git",
|
||||||
|
"tag" : "cogl-1.22",
|
||||||
|
"url" : "https://gitlab.gnome.org/Archive/cogl.git"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name" : "clutter",
|
||||||
|
"buildsystem" : "meson",
|
||||||
|
"config-opts" : [
|
||||||
|
"-Dbackends='system'",
|
||||||
|
"-Ddrivers='all'",
|
||||||
|
"-Dbuild_tests=false",
|
||||||
|
"-Dbuild_examples=false",
|
||||||
|
"-Ddocumentation=false",
|
||||||
|
"-Dintrospection=true",
|
||||||
|
"-Dpixbuf_tests=false"
|
||||||
|
],
|
||||||
|
"sources" : [
|
||||||
|
{
|
||||||
|
"type" : "git",
|
||||||
|
"url" : "https://gitlab.gnome.org/GNOME/clutter.git"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name" : "gnome-shell",
|
||||||
|
"buildsystem" : "meson",
|
||||||
|
"config-opts" : [
|
||||||
|
"-Dextensions_tool=false",
|
||||||
|
"-Dextensions_app=false",
|
||||||
|
"-Dgtk_doc=false",
|
||||||
|
"-Dman=false",
|
||||||
|
"-Dtests=false",
|
||||||
|
"-Dnetworkmanager=false",
|
||||||
|
"-Dportal_helper=false",
|
||||||
|
"-Dcamera_monitor=false",
|
||||||
|
"-Dsystemd=false"
|
||||||
|
],
|
||||||
|
"sources" : [
|
||||||
|
{
|
||||||
|
"type" : "git",
|
||||||
|
"branch" : "main",
|
||||||
|
"url" : "https://gitlab.gnome.org/GNOME/gnome-shell.git"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
"name" : "gnome-backgrounds",
|
||||||
|
"buildsystem" : "meson",
|
||||||
|
"sources" : [
|
||||||
|
{
|
||||||
|
"type" : "git",
|
||||||
|
"branch": "main",
|
||||||
|
"url" : "https://gitlab.gnome.org/GNOME/gnome-backgrounds.git"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name" : "tecla",
|
||||||
|
"buildsystem" : "meson",
|
||||||
|
"sources" : [
|
||||||
|
{
|
||||||
|
"type" : "git",
|
||||||
|
"branch": "main",
|
||||||
|
"url" : "https://gitlab.gnome.org/GNOME/tecla.git"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name" : "gnome-control-center",
|
||||||
|
"buildsystem" : "meson",
|
||||||
|
"sources" : [
|
||||||
|
{
|
||||||
|
"type" : "dir",
|
||||||
|
"path" : "../../"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"config-opts" : [
|
||||||
|
"-Dsnap=false",
|
||||||
|
"-Dtests=false",
|
||||||
|
"-Dprofile=development"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
38
build-aux/meson/find_xdg_file.py
Normal file
38
build-aux/meson/find_xdg_file.py
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
|
def usage():
|
||||||
|
print('Usage:')
|
||||||
|
print('find_xdg_file.py FILENAME')
|
||||||
|
print('')
|
||||||
|
print('Looks for FILENAME in the XDG data directories and returns if path if found')
|
||||||
|
|
||||||
|
if len(sys.argv) != 2:
|
||||||
|
usage()
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
filename = sys.argv[1]
|
||||||
|
|
||||||
|
data_home = os.getenv('XDG_DATA_HOME')
|
||||||
|
if not data_home or data_home == '':
|
||||||
|
data_home = os.path.join(os.path.expanduser("~"), "local", "share")
|
||||||
|
|
||||||
|
data_dirs_str = os.getenv('XDG_DATA_DIRS')
|
||||||
|
if not data_dirs_str or data_dirs_str == '':
|
||||||
|
data_dirs_str = '/usr/local/share/:/usr/share/'
|
||||||
|
|
||||||
|
dirs = []
|
||||||
|
dirs += [ data_home ]
|
||||||
|
for _dir in data_dirs_str.split(':'):
|
||||||
|
dirs += [ _dir ]
|
||||||
|
|
||||||
|
for _dir in dirs:
|
||||||
|
full_path = os.path.join(_dir, filename)
|
||||||
|
if os.path.exists(full_path):
|
||||||
|
print(full_path)
|
||||||
|
sys.exit(0)
|
||||||
|
|
||||||
|
print(f"'{filename}' not found in XDG data directories")
|
||||||
|
sys.exit(1)
|
109
data/icons/hicolor/scalable/apps/org.gnome.Settings.Devel.svg
Normal file
109
data/icons/hicolor/scalable/apps/org.gnome.Settings.Devel.svg
Normal file
|
@ -0,0 +1,109 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<svg height="128px" viewBox="0 0 128 128" width="128px" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||||
|
<linearGradient id="a" gradientUnits="userSpaceOnUse" x1="64" x2="64" y1="262.5" y2="232">
|
||||||
|
<stop offset="0" stop-color="#9a9996"/>
|
||||||
|
<stop offset="1" stop-color="#77767b"/>
|
||||||
|
</linearGradient>
|
||||||
|
<radialGradient id="b" cx="-243.066583" cy="-74.599978" gradientUnits="userSpaceOnUse" r="28.266656">
|
||||||
|
<stop offset="0" stop-color="#d5d3cf"/>
|
||||||
|
<stop offset="1" stop-color="#949390"/>
|
||||||
|
</radialGradient>
|
||||||
|
<linearGradient id="c" gradientUnits="userSpaceOnUse" x1="203.999985" x2="267.999985" y1="-64" y2="-64">
|
||||||
|
<stop offset="0" stop-color="#d5d3cf"/>
|
||||||
|
<stop offset="1" stop-color="#f6f5f4"/>
|
||||||
|
</linearGradient>
|
||||||
|
<clipPath id="d">
|
||||||
|
<rect height="128" width="128"/>
|
||||||
|
</clipPath>
|
||||||
|
<clipPath id="e">
|
||||||
|
<rect height="128" width="128"/>
|
||||||
|
</clipPath>
|
||||||
|
<filter id="f" height="100%" width="100%" x="0%" y="0%">
|
||||||
|
<feColorMatrix in="SourceGraphic" type="matrix" values="0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 1 0"/>
|
||||||
|
</filter>
|
||||||
|
<mask id="g">
|
||||||
|
<g clip-path="url(#e)" filter="url(#f)">
|
||||||
|
<g clip-path="url(#d)">
|
||||||
|
<path d="m 667 292 h -6 l -2 -16 h 10 z m 0 0" fill="#9a9996" stroke="#9a9996" stroke-linecap="round" stroke-linejoin="round" stroke-width="8" transform="matrix(1 0 0 1 -600 -170)"/>
|
||||||
|
<path d="m 661 180 h 6 l 2 16 h -10 z m 0 0" fill="#9a9996" stroke="#9a9996" stroke-linecap="round" stroke-linejoin="round" stroke-width="8" transform="matrix(1 0 0 1 -600 -170)"/>
|
||||||
|
<path d="m 667.000092 291.999908 h -6 l -2 -16 h 10 z m 0 0" fill="#9a9996" stroke="#9a9996" stroke-linecap="round" stroke-linejoin="round" stroke-width="8" transform="matrix(0 1 -1 0 299.999908 -598.000092)"/>
|
||||||
|
<path d="m 661.000092 179.999908 h 6 l 2 16 h -10 z m 0 0" fill="#9a9996" stroke="#9a9996" stroke-linecap="round" stroke-linejoin="round" stroke-width="8" transform="matrix(0 1 -1 0 299.999908 -598.000092)"/>
|
||||||
|
<path d="m 666.999051 291.998922 l -5.999272 -0.00042 l -2.001544 -15.998026 l 9.999915 0.000049 z m 0 0" fill="#9a9996" stroke="#9a9996" stroke-linecap="round" stroke-linejoin="round" stroke-width="8" transform="matrix(-0.5 0.866025 -0.866025 -0.5 600.381916 -391.041005)"/>
|
||||||
|
<path d="m 661.001107 180.000804 l 5.999273 0.000419 l 2.001544 15.998026 l -10.003298 0.001905 z m 0 0" fill="#9a9996" stroke="#9a9996" stroke-linecap="round" stroke-linejoin="round" stroke-width="8" transform="matrix(-0.5 0.866025 -0.866025 -0.5 600.381916 -391.041005)"/>
|
||||||
|
<path d="m 667.000347 291.998468 l -5.999273 0.00042 l -2.002482 -16.00035 l 10.003298 0.001905 z m 0 0" fill="#9a9996" stroke="#9a9996" stroke-linecap="round" stroke-linejoin="round" stroke-width="8" transform="matrix(-0.866025 0.5 -0.5 -0.866025 757.040822 -61.618176)"/>
|
||||||
|
<path d="m 660.999745 180.00119 l 5.999273 -0.00042 l 2.002481 16.00035 l -10.003298 -0.001904 z m 0 0" fill="#9a9996" stroke="#9a9996" stroke-linecap="round" stroke-linejoin="round" stroke-width="8" transform="matrix(-0.866025 0.5 -0.5 -0.866025 757.040822 -61.618176)"/>
|
||||||
|
<path d="m 666.999018 291.999047 l -5.999273 -0.00042 l -2.001544 -15.998026 l 10.003298 -0.001904 z m 0 0" fill="#9a9996" stroke="#9a9996" stroke-linecap="round" stroke-linejoin="round" stroke-width="8" transform="matrix(0.866025 0.5 -0.5 0.866025 -393.040914 -470.382008)"/>
|
||||||
|
<path d="m 661.001074 180.000929 l 5.999273 0.00042 l 2.001543 15.998025 l -10.003298 0.001905 z m 0 0" fill="#9a9996" stroke="#9a9996" stroke-linecap="round" stroke-linejoin="round" stroke-width="8" transform="matrix(0.866025 0.5 -0.5 0.866025 -393.040914 -470.382008)"/>
|
||||||
|
<path d="m 667.00038 291.998593 l -5.999273 0.00042 l -2.002481 -16.00035 l 10.003298 0.001905 z m 0 0" fill="#9a9996" stroke="#9a9996" stroke-linecap="round" stroke-linejoin="round" stroke-width="8" transform="matrix(0.5 0.866025 -0.866025 0.5 -63.618084 -627.040914)"/>
|
||||||
|
<path d="m 660.999779 180.001315 l 5.999272 -0.00042 l 1.999099 15.998397 l -9.999915 0.000049 z m 0 0" fill="#9a9996" stroke="#9a9996" stroke-linecap="round" stroke-linejoin="round" stroke-width="8" transform="matrix(0.5 0.866025 -0.866025 0.5 -63.618084 -627.040914)"/>
|
||||||
|
<path d="m 667 292 h -6 l -2 -16 h 10 z m 0 0" fill="#f6f5f4" stroke="#f6f5f4" stroke-linecap="round" stroke-linejoin="round" stroke-width="8" transform="matrix(1 0 0 1 -600 -172)"/>
|
||||||
|
<path d="m 661 180 h 6 l 2 16 h -10 z m 0 0" fill="#f6f5f4" stroke="#f6f5f4" stroke-linecap="round" stroke-linejoin="round" stroke-width="8" transform="matrix(1 0 0 1 -600 -172)"/>
|
||||||
|
<path d="m 667.000092 291.999908 h -6 l -2 -16 h 10 z m 0 0" fill="#f6f5f4" stroke="#f6f5f4" stroke-linecap="round" stroke-linejoin="round" stroke-width="8" transform="matrix(0 1 -1 0 299.999908 -600.000092)"/>
|
||||||
|
<path d="m 661.000092 179.999908 h 6 l 2 16 h -10 z m 0 0" fill="#f6f5f4" stroke="#f6f5f4" stroke-linecap="round" stroke-linejoin="round" stroke-width="8" transform="matrix(0 1 -1 0 299.999908 -600.000092)"/>
|
||||||
|
<path d="m 666.999051 291.998922 l -5.999272 -0.00042 l -2.001544 -15.998026 l 9.999915 0.000049 z m 0 0" fill="#f6f5f4" stroke="#f6f5f4" stroke-linecap="round" stroke-linejoin="round" stroke-width="8" transform="matrix(-0.5 0.866025 -0.866025 -0.5 600.381916 -393.041005)"/>
|
||||||
|
<path d="m 661.001107 180.000804 l 5.999273 0.000419 l 2.001544 15.998026 l -10.003298 0.001905 z m 0 0" fill="#f6f5f4" stroke="#f6f5f4" stroke-linecap="round" stroke-linejoin="round" stroke-width="8" transform="matrix(-0.5 0.866025 -0.866025 -0.5 600.381916 -393.041005)"/>
|
||||||
|
<path d="m 667.000347 291.998468 l -5.999273 0.00042 l -2.002482 -16.00035 l 10.003298 0.001905 z m 0 0" fill="#f6f5f4" stroke="#f6f5f4" stroke-linecap="round" stroke-linejoin="round" stroke-width="8" transform="matrix(-0.866025 0.5 -0.5 -0.866025 757.040822 -63.618176)"/>
|
||||||
|
<path d="m 660.999745 180.00119 l 5.999273 -0.00042 l 2.002481 16.00035 l -10.003298 -0.001904 z m 0 0" fill="#f6f5f4" stroke="#f6f5f4" stroke-linecap="round" stroke-linejoin="round" stroke-width="8" transform="matrix(-0.866025 0.5 -0.5 -0.866025 757.040822 -63.618176)"/>
|
||||||
|
<path d="m 666.999018 291.999047 l -5.999273 -0.00042 l -2.001544 -15.998026 l 10.003298 -0.001904 z m 0 0" fill="#f6f5f4" stroke="#f6f5f4" stroke-linecap="round" stroke-linejoin="round" stroke-width="8" transform="matrix(0.866025 0.5 -0.5 0.866025 -393.040914 -472.382008)"/>
|
||||||
|
<path d="m 661.001074 180.000929 l 5.999273 0.00042 l 2.001543 15.998025 l -10.003298 0.001905 z m 0 0" fill="#f6f5f4" stroke="#f6f5f4" stroke-linecap="round" stroke-linejoin="round" stroke-width="8" transform="matrix(0.866025 0.5 -0.5 0.866025 -393.040914 -472.382008)"/>
|
||||||
|
<path d="m 667.00038 291.998593 l -5.999273 0.00042 l -2.002481 -16.00035 l 10.003298 0.001905 z m 0 0" fill="#f6f5f4" stroke="#f6f5f4" stroke-linecap="round" stroke-linejoin="round" stroke-width="8" transform="matrix(0.5 0.866025 -0.866025 0.5 -63.618084 -629.040914)"/>
|
||||||
|
<path d="m 660.999779 180.001315 l 5.999272 -0.00042 l 1.999099 15.998397 l -9.999915 0.000049 z m 0 0" fill="#f6f5f4" stroke="#f6f5f4" stroke-linecap="round" stroke-linejoin="round" stroke-width="8" transform="matrix(0.5 0.866025 -0.866025 0.5 -63.618084 -629.040914)"/>
|
||||||
|
<path d="m 100 238 c 0 19.882812 -16.117188 36 -36 36 s -36 -16.117188 -36 -36 s 16.117188 -36 36 -36 s 36 16.117188 36 36 z m 0 0" fill="none" stroke="url(#a)" stroke-width="24" transform="matrix(1 0 0 1 0 -172)"/>
|
||||||
|
<path d="m 102 236 c 0 20.988281 -17.011719 38 -38 38 s -38 -17.011719 -38 -38 s 17.011719 -38 38 -38 s 38 17.011719 38 38 z m 0 0" fill="none" stroke="#f6f5f4" stroke-width="20" transform="matrix(1 0 0 1 0 -172)"/>
|
||||||
|
<path d="m -209.5 -64 c 0 14.636719 -11.863281 26.5 -26.5 26.5 s -26.5 -11.863281 -26.5 -26.5 s 11.863281 -26.5 26.5 -26.5 s 26.5 11.863281 26.5 26.5 z m 0 0" fill="none" stroke="url(#b)" stroke-linecap="square" stroke-linejoin="round" stroke-width="5" transform="matrix(0 -1 -1 0 0 -172)"/>
|
||||||
|
<path d="m 268 -64 c 0 17.671875 -14.328125 32 -32 32 s -32 -14.328125 -32 -32 s 14.328125 -32 32 -32 s 32 14.328125 32 32 z m 0 0" fill="none" stroke="url(#c)" stroke-linecap="square" stroke-linejoin="round" stroke-width="8" transform="matrix(0 1 -1 0 0 -172)"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</mask>
|
||||||
|
<mask id="h">
|
||||||
|
<g filter="url(#f)">
|
||||||
|
<rect fill-opacity="0.8" height="128" width="128"/>
|
||||||
|
</g>
|
||||||
|
</mask>
|
||||||
|
<linearGradient id="i" gradientTransform="matrix(0 0.37 -0.98462 0 295.38501 -30.360001)" gradientUnits="userSpaceOnUse" x1="300" x2="428" y1="235" y2="235">
|
||||||
|
<stop offset="0" stop-color="#f9f06b"/>
|
||||||
|
<stop offset="1" stop-color="#f5c211"/>
|
||||||
|
</linearGradient>
|
||||||
|
<clipPath id="j">
|
||||||
|
<rect height="128" width="128"/>
|
||||||
|
</clipPath>
|
||||||
|
<clipPath id="k">
|
||||||
|
<rect height="128" width="128"/>
|
||||||
|
</clipPath>
|
||||||
|
<g stroke-linecap="round" stroke-linejoin="round" stroke-width="8">
|
||||||
|
<path d="m 67 122 h -6 l -2 -16 h 10 z m 0 0" fill="#9a9996" stroke="#9a9996"/>
|
||||||
|
<path d="m 61 10 h 6 l 2 16 h -10 z m 0 0" fill="#9a9996" stroke="#9a9996"/>
|
||||||
|
<path d="m 667.000092 291.999908 h -6 l -2 -16 h 10 z m 0 0" fill="#9a9996" stroke="#9a9996" transform="matrix(0 1 -1 0 299.999908 -598.000092)"/>
|
||||||
|
<path d="m 661.000092 179.999908 h 6 l 2 16 h -10 z m 0 0" fill="#9a9996" stroke="#9a9996" transform="matrix(0 1 -1 0 299.999908 -598.000092)"/>
|
||||||
|
<path d="m 666.999051 291.998922 l -5.999272 -0.00042 l -2.001544 -15.998026 l 9.999915 0.000049 z m 0 0" fill="#9a9996" stroke="#9a9996" transform="matrix(-0.5 0.866025 -0.866025 -0.5 600.381916 -391.041005)"/>
|
||||||
|
<path d="m 661.001107 180.000804 l 5.999273 0.000419 l 2.001544 15.998026 l -10.003298 0.001905 z m 0 0" fill="#9a9996" stroke="#9a9996" transform="matrix(-0.5 0.866025 -0.866025 -0.5 600.381916 -391.041005)"/>
|
||||||
|
<path d="m 667.000347 291.998468 l -5.999273 0.00042 l -2.002482 -16.00035 l 10.003298 0.001905 z m 0 0" fill="#9a9996" stroke="#9a9996" transform="matrix(-0.866025 0.5 -0.5 -0.866025 757.040822 -61.618176)"/>
|
||||||
|
<path d="m 660.999745 180.00119 l 5.999273 -0.00042 l 2.002481 16.00035 l -10.003298 -0.001904 z m 0 0" fill="#9a9996" stroke="#9a9996" transform="matrix(-0.866025 0.5 -0.5 -0.866025 757.040822 -61.618176)"/>
|
||||||
|
<path d="m 666.999018 291.999047 l -5.999273 -0.00042 l -2.001544 -15.998026 l 10.003298 -0.001904 z m 0 0" fill="#9a9996" stroke="#9a9996" transform="matrix(0.866025 0.5 -0.5 0.866025 -393.040914 -470.382008)"/>
|
||||||
|
<path d="m 661.001074 180.000929 l 5.999273 0.00042 l 2.001543 15.998025 l -10.003298 0.001905 z m 0 0" fill="#9a9996" stroke="#9a9996" transform="matrix(0.866025 0.5 -0.5 0.866025 -393.040914 -470.382008)"/>
|
||||||
|
<path d="m 667.00038 291.998593 l -5.999273 0.00042 l -2.002481 -16.00035 l 10.003298 0.001905 z m 0 0" fill="#9a9996" stroke="#9a9996" transform="matrix(0.5 0.866025 -0.866025 0.5 -63.618084 -627.040914)"/>
|
||||||
|
<path d="m 660.999779 180.001315 l 5.999272 -0.00042 l 1.999099 15.998397 l -9.999915 0.000049 z m 0 0" fill="#9a9996" stroke="#9a9996" transform="matrix(0.5 0.866025 -0.866025 0.5 -63.618084 -627.040914)"/>
|
||||||
|
<path d="m 67 120 h -6 l -2 -16 h 10 z m 0 0" fill="#f6f5f4" stroke="#f6f5f4"/>
|
||||||
|
<path d="m 61 8 h 6 l 2 16 h -10 z m 0 0" fill="#f6f5f4" stroke="#f6f5f4"/>
|
||||||
|
<path d="m 667.000092 291.999908 h -6 l -2 -16 h 10 z m 0 0" fill="#f6f5f4" stroke="#f6f5f4" transform="matrix(0 1 -1 0 299.999908 -600.000092)"/>
|
||||||
|
<path d="m 661.000092 179.999908 h 6 l 2 16 h -10 z m 0 0" fill="#f6f5f4" stroke="#f6f5f4" transform="matrix(0 1 -1 0 299.999908 -600.000092)"/>
|
||||||
|
<path d="m 666.999051 291.998922 l -5.999272 -0.00042 l -2.001544 -15.998026 l 9.999915 0.000049 z m 0 0" fill="#f6f5f4" stroke="#f6f5f4" transform="matrix(-0.5 0.866025 -0.866025 -0.5 600.381916 -393.041005)"/>
|
||||||
|
<path d="m 661.001107 180.000804 l 5.999273 0.000419 l 2.001544 15.998026 l -10.003298 0.001905 z m 0 0" fill="#f6f5f4" stroke="#f6f5f4" transform="matrix(-0.5 0.866025 -0.866025 -0.5 600.381916 -393.041005)"/>
|
||||||
|
<path d="m 667.000347 291.998468 l -5.999273 0.00042 l -2.002482 -16.00035 l 10.003298 0.001905 z m 0 0" fill="#f6f5f4" stroke="#f6f5f4" transform="matrix(-0.866025 0.5 -0.5 -0.866025 757.040822 -63.618176)"/>
|
||||||
|
<path d="m 660.999745 180.00119 l 5.999273 -0.00042 l 2.002481 16.00035 l -10.003298 -0.001904 z m 0 0" fill="#f6f5f4" stroke="#f6f5f4" transform="matrix(-0.866025 0.5 -0.5 -0.866025 757.040822 -63.618176)"/>
|
||||||
|
<path d="m 666.999018 291.999047 l -5.999273 -0.00042 l -2.001544 -15.998026 l 10.003298 -0.001904 z m 0 0" fill="#f6f5f4" stroke="#f6f5f4" transform="matrix(0.866025 0.5 -0.5 0.866025 -393.040914 -472.382008)"/>
|
||||||
|
<path d="m 661.001074 180.000929 l 5.999273 0.00042 l 2.001543 15.998025 l -10.003298 0.001905 z m 0 0" fill="#f6f5f4" stroke="#f6f5f4" transform="matrix(0.866025 0.5 -0.5 0.866025 -393.040914 -472.382008)"/>
|
||||||
|
<path d="m 667.00038 291.998593 l -5.999273 0.00042 l -2.002481 -16.00035 l 10.003298 0.001905 z m 0 0" fill="#f6f5f4" stroke="#f6f5f4" transform="matrix(0.5 0.866025 -0.866025 0.5 -63.618084 -629.040914)"/>
|
||||||
|
<path d="m 660.999779 180.001315 l 5.999272 -0.00042 l 1.999099 15.998397 l -9.999915 0.000049 z m 0 0" fill="#f6f5f4" stroke="#f6f5f4" transform="matrix(0.5 0.866025 -0.866025 0.5 -63.618084 -629.040914)"/>
|
||||||
|
</g>
|
||||||
|
<path d="m 100 238 c 0 19.882812 -16.117188 36 -36 36 s -36 -16.117188 -36 -36 s 16.117188 -36 36 -36 s 36 16.117188 36 36 z m 0 0" fill="none" stroke="url(#a)" stroke-width="24" transform="matrix(1 0 0 1 0 -172)"/>
|
||||||
|
<path d="m 102 64 c 0 20.988281 -17.011719 38 -38 38 s -38 -17.011719 -38 -38 s 17.011719 -38 38 -38 s 38 17.011719 38 38 z m 0 0" fill="none" stroke="#f6f5f4" stroke-width="20"/>
|
||||||
|
<path d="m -209.5 -64 c 0 14.636719 -11.863281 26.5 -26.5 26.5 s -26.5 -11.863281 -26.5 -26.5 s 11.863281 -26.5 26.5 -26.5 s 26.5 11.863281 26.5 26.5 z m 0 0" fill="none" stroke="url(#b)" stroke-linecap="square" stroke-linejoin="round" stroke-width="5" transform="matrix(0 -1 -1 0 0 -172)"/>
|
||||||
|
<path d="m 268 -64 c 0 17.671875 -14.328125 32 -32 32 s -32 -14.328125 -32 -32 s 14.328125 -32 32 -32 s 32 14.328125 32 32 z m 0 0" fill="none" stroke="url(#c)" stroke-linecap="square" stroke-linejoin="round" stroke-width="8" transform="matrix(0 1 -1 0 0 -172)"/>
|
||||||
|
<g clip-path="url(#k)" mask="url(#g)">
|
||||||
|
<g clip-path="url(#j)" mask="url(#h)">
|
||||||
|
<path d="m 128 80.640625 v 47.359375 h -128 v -47.359375 z m 0 0" fill="url(#i)"/>
|
||||||
|
<path d="m 13.308594 80.640625 l 47.355468 47.359375 h 21.214844 l -47.359375 -47.359375 z m 42.421875 0 l 47.363281 47.359375 h 21.214844 l -47.363282 -47.359375 z m 42.429687 0 l 29.839844 29.839844 v -21.210938 l -8.628906 -8.628906 z m -98.160156 7.90625 v 21.214844 l 18.238281 18.238281 h 21.214844 z m 0 0"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 15 KiB |
45
data/icons/hicolor/scalable/apps/org.gnome.Settings.svg
Normal file
45
data/icons/hicolor/scalable/apps/org.gnome.Settings.svg
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<svg height="128px" viewBox="0 0 128 128" width="128px" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||||
|
<linearGradient id="a" gradientUnits="userSpaceOnUse" x1="64" x2="64" y1="262.5" y2="232">
|
||||||
|
<stop offset="0" stop-color="#9a9996"/>
|
||||||
|
<stop offset="1" stop-color="#77767b"/>
|
||||||
|
</linearGradient>
|
||||||
|
<radialGradient id="b" cx="-243.066583" cy="-74.599978" gradientUnits="userSpaceOnUse" r="28.266656">
|
||||||
|
<stop offset="0" stop-color="#d5d3cf"/>
|
||||||
|
<stop offset="1" stop-color="#949390"/>
|
||||||
|
</radialGradient>
|
||||||
|
<linearGradient id="c" gradientUnits="userSpaceOnUse" x1="203.999985" x2="267.999985" y1="-64" y2="-64">
|
||||||
|
<stop offset="0" stop-color="#d5d3cf"/>
|
||||||
|
<stop offset="1" stop-color="#f6f5f4"/>
|
||||||
|
</linearGradient>
|
||||||
|
<g stroke-width="8">
|
||||||
|
<path d="m 67 122 h -6 l -2 -16 h 10 z m 0 0" fill="#9a9996" stroke="#9a9996" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="m 61 10 h 6 l 2 16 h -10 z m 0 0" fill="#9a9996" stroke="#9a9996" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="m 667.000092 291.999908 h -6 l -2 -16 h 10 z m 0 0" fill="#9a9996" stroke="#9a9996" stroke-linecap="round" stroke-linejoin="round" transform="matrix(0 1 -1 0 299.999908 -598.000092)"/>
|
||||||
|
<path d="m 661.000092 179.999908 h 6 l 2 16 h -10 z m 0 0" fill="#9a9996" stroke="#9a9996" stroke-linecap="round" stroke-linejoin="round" transform="matrix(0 1 -1 0 299.999908 -598.000092)"/>
|
||||||
|
<path d="m 666.999051 291.998922 l -5.999272 -0.00042 l -2.001544 -15.998026 l 9.999915 0.000049 z m 0 0" fill="#9a9996" stroke="#9a9996" stroke-linecap="round" stroke-linejoin="round" transform="matrix(-0.5 0.866025 -0.866025 -0.5 600.381916 -391.041005)"/>
|
||||||
|
<path d="m 661.001107 180.000804 l 5.999273 0.000419 l 2.001544 15.998026 l -10.003298 0.001905 z m 0 0" fill="#9a9996" stroke="#9a9996" stroke-linecap="round" stroke-linejoin="round" transform="matrix(-0.5 0.866025 -0.866025 -0.5 600.381916 -391.041005)"/>
|
||||||
|
<path d="m 667.000347 291.998468 l -5.999273 0.00042 l -2.002482 -16.00035 l 10.003298 0.001905 z m 0 0" fill="#9a9996" stroke="#9a9996" stroke-linecap="round" stroke-linejoin="round" transform="matrix(-0.866025 0.5 -0.5 -0.866025 757.040822 -61.618176)"/>
|
||||||
|
<path d="m 660.999745 180.00119 l 5.999273 -0.00042 l 2.002481 16.00035 l -10.003298 -0.001904 z m 0 0" fill="#9a9996" stroke="#9a9996" stroke-linecap="round" stroke-linejoin="round" transform="matrix(-0.866025 0.5 -0.5 -0.866025 757.040822 -61.618176)"/>
|
||||||
|
<path d="m 666.999018 291.999047 l -5.999273 -0.00042 l -2.001544 -15.998026 l 10.003298 -0.001904 z m 0 0" fill="#9a9996" stroke="#9a9996" stroke-linecap="round" stroke-linejoin="round" transform="matrix(0.866025 0.5 -0.5 0.866025 -393.040914 -470.382008)"/>
|
||||||
|
<path d="m 661.001074 180.000929 l 5.999273 0.00042 l 2.001543 15.998025 l -10.003298 0.001905 z m 0 0" fill="#9a9996" stroke="#9a9996" stroke-linecap="round" stroke-linejoin="round" transform="matrix(0.866025 0.5 -0.5 0.866025 -393.040914 -470.382008)"/>
|
||||||
|
<path d="m 667.00038 291.998593 l -5.999273 0.00042 l -2.002481 -16.00035 l 10.003298 0.001905 z m 0 0" fill="#9a9996" stroke="#9a9996" stroke-linecap="round" stroke-linejoin="round" transform="matrix(0.5 0.866025 -0.866025 0.5 -63.618084 -627.040914)"/>
|
||||||
|
<path d="m 660.999779 180.001315 l 5.999272 -0.00042 l 1.999099 15.998397 l -9.999915 0.000049 z m 0 0" fill="#9a9996" stroke="#9a9996" stroke-linecap="round" stroke-linejoin="round" transform="matrix(0.5 0.866025 -0.866025 0.5 -63.618084 -627.040914)"/>
|
||||||
|
<path d="m 67 120 h -6 l -2 -16 h 10 z m 0 0" fill="#f6f5f4" stroke="#f6f5f4" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="m 61 8 h 6 l 2 16 h -10 z m 0 0" fill="#f6f5f4" stroke="#f6f5f4" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="m 667.000092 291.999908 h -6 l -2 -16 h 10 z m 0 0" fill="#f6f5f4" stroke="#f6f5f4" stroke-linecap="round" stroke-linejoin="round" transform="matrix(0 1 -1 0 299.999908 -600.000092)"/>
|
||||||
|
<path d="m 661.000092 179.999908 h 6 l 2 16 h -10 z m 0 0" fill="#f6f5f4" stroke="#f6f5f4" stroke-linecap="round" stroke-linejoin="round" transform="matrix(0 1 -1 0 299.999908 -600.000092)"/>
|
||||||
|
<path d="m 666.999051 291.998922 l -5.999272 -0.00042 l -2.001544 -15.998026 l 9.999915 0.000049 z m 0 0" fill="#f6f5f4" stroke="#f6f5f4" stroke-linecap="round" stroke-linejoin="round" transform="matrix(-0.5 0.866025 -0.866025 -0.5 600.381916 -393.041005)"/>
|
||||||
|
<path d="m 661.001107 180.000804 l 5.999273 0.000419 l 2.001544 15.998026 l -10.003298 0.001905 z m 0 0" fill="#f6f5f4" stroke="#f6f5f4" stroke-linecap="round" stroke-linejoin="round" transform="matrix(-0.5 0.866025 -0.866025 -0.5 600.381916 -393.041005)"/>
|
||||||
|
<path d="m 667.000347 291.998468 l -5.999273 0.00042 l -2.002482 -16.00035 l 10.003298 0.001905 z m 0 0" fill="#f6f5f4" stroke="#f6f5f4" stroke-linecap="round" stroke-linejoin="round" transform="matrix(-0.866025 0.5 -0.5 -0.866025 757.040822 -63.618176)"/>
|
||||||
|
<path d="m 660.999745 180.00119 l 5.999273 -0.00042 l 2.002481 16.00035 l -10.003298 -0.001904 z m 0 0" fill="#f6f5f4" stroke="#f6f5f4" stroke-linecap="round" stroke-linejoin="round" transform="matrix(-0.866025 0.5 -0.5 -0.866025 757.040822 -63.618176)"/>
|
||||||
|
<path d="m 666.999018 291.999047 l -5.999273 -0.00042 l -2.001544 -15.998026 l 10.003298 -0.001904 z m 0 0" fill="#f6f5f4" stroke="#f6f5f4" stroke-linecap="round" stroke-linejoin="round" transform="matrix(0.866025 0.5 -0.5 0.866025 -393.040914 -472.382008)"/>
|
||||||
|
<path d="m 661.001074 180.000929 l 5.999273 0.00042 l 2.001543 15.998025 l -10.003298 0.001905 z m 0 0" fill="#f6f5f4" stroke="#f6f5f4" stroke-linecap="round" stroke-linejoin="round" transform="matrix(0.866025 0.5 -0.5 0.866025 -393.040914 -472.382008)"/>
|
||||||
|
<path d="m 667.00038 291.998593 l -5.999273 0.00042 l -2.002481 -16.00035 l 10.003298 0.001905 z m 0 0" fill="#f6f5f4" stroke="#f6f5f4" stroke-linecap="round" stroke-linejoin="round" transform="matrix(0.5 0.866025 -0.866025 0.5 -63.618084 -629.040914)"/>
|
||||||
|
<path d="m 660.999779 180.001315 l 5.999272 -0.00042 l 1.999099 15.998397 l -9.999915 0.000049 z m 0 0" fill="#f6f5f4" stroke="#f6f5f4" stroke-linecap="round" stroke-linejoin="round" transform="matrix(0.5 0.866025 -0.866025 0.5 -63.618084 -629.040914)"/>
|
||||||
|
</g>
|
||||||
|
<path d="m 100 238 c 0 19.882812 -16.117188 36 -36 36 s -36 -16.117188 -36 -36 s 16.117188 -36 36 -36 s 36 16.117188 36 36 z m 0 0" fill="none" stroke="url(#a)" stroke-width="24" transform="matrix(1 0 0 1 0 -172)"/>
|
||||||
|
<path d="m 102 64 c 0 20.988281 -17.011719 38 -38 38 s -38 -17.011719 -38 -38 s 17.011719 -38 38 -38 s 38 17.011719 38 38 z m 0 0" fill="none" stroke="#f6f5f4" stroke-width="20"/>
|
||||||
|
<path d="m -209.5 -64 c 0 14.636719 -11.863281 26.5 -26.5 26.5 s -26.5 -11.863281 -26.5 -26.5 s 11.863281 -26.5 26.5 -26.5 s 26.5 11.863281 26.5 26.5 z m 0 0" fill="none" stroke="url(#b)" stroke-linecap="square" stroke-linejoin="round" stroke-width="5" transform="matrix(0 -1 -1 0 0 -172)"/>
|
||||||
|
<path d="m 268 -64 c 0 17.671875 -14.328125 32 -32 32 s -32 -14.328125 -32 -32 s 14.328125 -32 32 -32 s 32 14.328125 32 32 z m 0 0" fill="none" stroke="url(#c)" stroke-linecap="square" stroke-linejoin="round" stroke-width="8" transform="matrix(0 1 -1 0 0 -172)"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 7.3 KiB |
|
@ -0,0 +1,5 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<svg height="16px" viewBox="0 0 16 16" width="16px" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||||
|
<path d="m 7.480469 0.015625 h 1.066406 c 0.589844 0 1.066406 0.476563 1.066406 1.066406 v 1.066407 c 0 0.589843 -0.476562 1.066406 -1.066406 1.066406 h -1.066406 c -0.589844 0 -1.066407 -0.476563 -1.066407 -1.066406 v -1.066407 c 0 -0.589843 0.476563 -1.066406 1.066407 -1.066406 z m 0 12.796875 h 1.066406 c 0.589844 0 1.066406 0.476562 1.066406 1.070312 v 1.0625 c 0 0.59375 -0.476562 1.070313 -1.066406 1.070313 h -1.066406 c -0.589844 0 -1.066407 -0.476563 -1.066407 -1.070313 v -1.0625 c 0 -0.59375 0.476563 -1.070312 1.066407 -1.070312 z m -5.5 -10.078125 l 0.753906 -0.753906 c 0.199219 -0.199219 0.46875 -0.3125 0.753906 -0.3125 c 0.28125 0 0.554688 0.113281 0.753907 0.3125 l 0.753906 0.753906 c 0.417968 0.417969 0.417968 1.089844 0 1.507813 l -0.753906 0.753906 c -0.199219 0.203125 -0.472657 0.316406 -0.753907 0.316406 c -0.285156 0 -0.554687 -0.113281 -0.753906 -0.316406 l -0.753906 -0.753906 c -0.203125 -0.199219 -0.316407 -0.46875 -0.316407 -0.753907 c 0 -0.28125 0.113282 -0.554687 0.316407 -0.753906 z m 9.050781 9.050781 l 0.753906 -0.753906 c 0.199219 -0.199219 0.472656 -0.3125 0.753906 -0.3125 c 0.285157 0 0.554688 0.113281 0.753907 0.3125 l 0.753906 0.753906 c 0.417969 0.417969 0.417969 1.089844 0 1.507813 l -0.753906 0.753906 c -0.199219 0.203125 -0.46875 0.316406 -0.753907 0.316406 c -0.28125 0 -0.554687 -0.113281 -0.753906 -0.316406 l -0.753906 -0.753906 c -0.203125 -0.199219 -0.3125 -0.46875 -0.3125 -0.753907 c 0 -0.28125 0.109375 -0.554687 0.3125 -0.753906 z m -11.015625 -3.238281 v -1.066406 c 0 -0.589844 0.472656 -1.066407 1.066406 -1.066407 h 1.066407 c 0.589843 0 1.066406 0.476563 1.066406 1.066407 v 1.066406 c 0 0.589844 -0.476563 1.066406 -1.066406 1.066406 h -1.066407 c -0.59375 0 -1.066406 -0.476562 -1.066406 -1.066406 z m 12.796875 0 v -1.066406 c 0 -0.589844 0.476562 -1.066407 1.066406 -1.066407 h 1.066406 c 0.59375 0 1.070313 0.476563 1.070313 1.066407 v 1.066406 c 0 0.589844 -0.476563 1.066406 -1.070313 1.066406 h -1.066406 c -0.589844 0 -1.066406 -0.476562 -1.066406 -1.066406 z m -10.078125 5.5 l -0.753906 -0.753906 c -0.203125 -0.199219 -0.316407 -0.46875 -0.316407 -0.753907 c 0 -0.28125 0.113282 -0.554687 0.316407 -0.753906 l 0.753906 -0.753906 c 0.199219 -0.199219 0.46875 -0.3125 0.753906 -0.3125 c 0.28125 0 0.554688 0.113281 0.753907 0.3125 l 0.753906 0.753906 c 0.417968 0.417969 0.417968 1.089844 0 1.507813 l -0.753906 0.753906 c -0.199219 0.203125 -0.472657 0.316406 -0.753907 0.316406 c -0.285156 0 -0.554687 -0.113281 -0.753906 -0.316406 z m 9.050781 -9.050781 l -0.753906 -0.753906 c -0.203125 -0.199219 -0.3125 -0.46875 -0.3125 -0.753907 c 0 -0.28125 0.109375 -0.554687 0.3125 -0.753906 l 0.753906 -0.753906 c 0.199219 -0.199219 0.472656 -0.3125 0.753906 -0.3125 c 0.285157 0 0.554688 0.113281 0.753907 0.3125 l 0.753906 0.753906 c 0.417969 0.417969 0.417969 1.089844 0 1.507813 l -0.753906 0.753906 c -0.199219 0.203125 -0.46875 0.316406 -0.753907 0.316406 c -0.28125 0 -0.554687 -0.113281 -0.753906 -0.316406 z m 0 0" fill="#241f31"/>
|
||||||
|
<path d="m 8.015625 1.515625 c -3.574219 0 -6.5 2.925781 -6.5 6.5 c 0 3.570313 2.925781 6.5 6.5 6.5 c 3.570313 0 6.5 -2.929687 6.5 -6.5 c 0 -3.574219 -2.929687 -6.5 -6.5 -6.5 z m 0 3 c 1.949219 0 3.5 1.546875 3.5 3.5 c 0 1.949219 -1.550781 3.5 -3.5 3.5 c -1.953125 0 -3.5 -1.550781 -3.5 -3.5 c 0 -1.953125 1.546875 -3.5 3.5 -3.5 z m 0 0" fill="#241f31"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 3.5 KiB |
4
data/icons/meson.build
Normal file
4
data/icons/meson.build
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
install_subdir(
|
||||||
|
'hicolor',
|
||||||
|
install_dir : control_center_icondir
|
||||||
|
)
|
28
docs/BUILDING_WITH_FLATPAK_BUILDER.md
Normal file
28
docs/BUILDING_WITH_FLATPAK_BUILDER.md
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
# Building GNOME Settings as a Flatpak in GNOME Builder
|
||||||
|
|
||||||
|
An alternative way of building GNOME Settings is using [GNOME Builder](https://flathub.org/apps/org.gnome.Builder)'s Flatpak support. This allows for easily cloning the repository and automatically handling the build of dependencies.
|
||||||
|
|
||||||
|
> The Flatpak container sandbox prevents GNOME Settings from performing a few of its functions, so this method is only recommended for superficial changes such as updating strings, UI, and style. If you face issues with the Settings functionality while running it in Builder, [considering building GNOME settings in a Toolbx instead](https://gitlab.gnome.org/GNOME/gnome-control-center/-/wikis/build/Building-GNOME-Settings-in-a-Toolbx).
|
||||||
|
|
||||||
|
Follow the steps described at https://welcome.gnome.org/en-GB/app/Settings/#getting-the-app-to-build
|
||||||
|
|
||||||
|
## Known limitations in the Settings Flatpak
|
||||||
|
|
||||||
|
- Apps Settings
|
||||||
|
- The *Default Apps* settings won't get populated (your apps aren't visible inside the Flatpak sandbox)
|
||||||
|
- App list won't show apps that aren't part of the sandbox (only utilities that are part of the flatpak runtime/sdk)
|
||||||
|
- Notification Settings
|
||||||
|
- installed apps aren't visible inside the flatpak sandbox
|
||||||
|
- Search Settings
|
||||||
|
- The [shell search providers](https://developer.gnome.org/documentation/tutorials/search-provider.html) aren't visible from within the Flatpak sandbox
|
||||||
|
- Keyboard Settings
|
||||||
|
- Input sources list appears empty
|
||||||
|
- Printers Settings
|
||||||
|
- There's no way to unlock the panel (it is not possible to use polkit within the flatpak container)
|
||||||
|
- System > Users Settings
|
||||||
|
- There's no way to Unlock the panel (it is not possible to use polkit within the flatpak container)
|
||||||
|
- System -> Remote Desktop Settings
|
||||||
|
- The panel won't load because it requires the remote-session-helper to be installed in a prefix and with permissions that aren't available within the flatpak container
|
||||||
|
- System -> About Settings
|
||||||
|
- There's no way to change the "Device Name" because that requires escalating privileges with polkit (not possible within the flatpak container)
|
||||||
|
- The OS logo will fallback to the GNOME one (the distro provided one is not accessible from within the flatpak container)
|
75
docs/BUILDING_WITH_TOOLBX.md
Normal file
75
docs/BUILDING_WITH_TOOLBX.md
Normal file
|
@ -0,0 +1,75 @@
|
||||||
|
# Building GNOME Settings in a Toolbx
|
||||||
|
|
||||||
|
[Toolbx](https://containertoolbx.org/) provides a Fedora-based development container that is ideal for developing GNOME Settings without risking messing up with your host operating system.
|
||||||
|
|
||||||
|
## Create a Toolbx with:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
toolbox create --release <release-number>
|
||||||
|
```
|
||||||
|
(preferably choose the latest Fedora release)
|
||||||
|
|
||||||
|
After creation, you can enter your toolbx with
|
||||||
|
|
||||||
|
```bash
|
||||||
|
toolbox enter --release <release-number>
|
||||||
|
```
|
||||||
|
|
||||||
|
## Install development packages for GNOME Settings
|
||||||
|
|
||||||
|
To install the development dependencies in GNOME Settings you can use:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo dnf install -y gnome-desktop4-devel libgweather4-devel \
|
||||||
|
gnome-settings-daemon-devel libnma-gtk4-devel \
|
||||||
|
colord-gtk4-devel
|
||||||
|
sudo dnf builddep gnome-control-center
|
||||||
|
```
|
||||||
|
|
||||||
|
## Perform a local build
|
||||||
|
|
||||||
|
Inside the `gnome-control-center` repository you can prepare the build with:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
meson setup _build
|
||||||
|
```
|
||||||
|
|
||||||
|
If all dependencies were satisfied, you should be able to build the project from inside the `_build` folder.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd _build
|
||||||
|
ninja
|
||||||
|
```
|
||||||
|
|
||||||
|
At the first time you do this you should also run `sudo ninja install` so that gsettings and other resources are installed in system paths.
|
||||||
|
|
||||||
|
## Running
|
||||||
|
|
||||||
|
With that, you can run GNOME Settings from its executable:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./shell/gnome-control-center
|
||||||
|
```
|
||||||
|
## Tips
|
||||||
|
|
||||||
|
* If `meson _build` is still missing dependencies, you can check which dependencies we are using in our Fedora CI build for reference to what to install. See `FDO_DISTRIBUTION_PACKAGES` for the whole list of packages in https://gitlab.gnome.org/GNOME/gnome-control-center/-/blob/main/.gitlab-ci.yml#L88
|
||||||
|
|
||||||
|
|
||||||
|
## Additional packages for specific components
|
||||||
|
|
||||||
|
GNOME Settings should now open, but many components require additional packages inside the Toolbx to function properly.
|
||||||
|
|
||||||
|
- `rygel` and `gnome-user-share` for the Sharing Panel
|
||||||
|
- `gnome-shell` for Multitasking and the videos in Mouse
|
||||||
|
- `flatpak` for showing apps in Applications that are installed outside your Toolbx
|
||||||
|
- `gnome-backgrounds` and `fedora-workstation-backgrounds` to show some backgrounds in Appearance
|
||||||
|
- `NetworkManager-{vpnc,openvpn,openconnect,pptp,ssh}-gnome` for VPN functionality
|
||||||
|
- `yelp` and `gnome-user-docs` for showing help information (press F1)
|
||||||
|
|
||||||
|
To install all of these at once, you can use:
|
||||||
|
```bash
|
||||||
|
sudo dnf install -y rygel gnome-user-share gnome-shell flatpak \
|
||||||
|
gnome-backgrounds fedora-workstation-backgrounds \
|
||||||
|
NetworkManager-{vpnc,openvpn,openconnect,pptp,ssh}-gnome \
|
||||||
|
yelp gnome-user-docs
|
||||||
|
```
|
31
docs/CC_HOSTNAME.md
Normal file
31
docs/CC_HOSTNAME.md
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
# CcHostname
|
||||||
|
|
||||||
|
[CcHostname](https://gitlab.gnome.org/GNOME/gnome-control-center/-/blob/main/panels/common/cc-hostname.h?ref_type=heads) is a singleton class useful for obtaining information about the host system throughout systemd-hostnamed.
|
||||||
|
|
||||||
|
`CcHostname` contains a proxy to the `org.freedesktop.hostname1` interface over DBus.
|
||||||
|
|
||||||
|
The main `CcHostname` methods are:
|
||||||
|
|
||||||
|
# `CcHostname.get_display_hostname`
|
||||||
|
|
||||||
|
Obtains the system "Pretty Hostname". See https://www.freedesktop.org/software/systemd/man/latest/hostnamectl.html#hostname%20%5BNAME%5D
|
||||||
|
|
||||||
|
# `CcHostname.get_display_hostname`
|
||||||
|
|
||||||
|
Obtains the system "Static Hostname".
|
||||||
|
|
||||||
|
# `CcHostname.set_hostname`
|
||||||
|
|
||||||
|
Allows for setting the system "pretty" and "static" hostnames (SetPrettyHostname and SetStaticHostname).
|
||||||
|
|
||||||
|
# `CcHostname.get_chassis_type`
|
||||||
|
|
||||||
|
Useful for when we want to condition the behaviour based on whether the device running Settings is a laptop, desktop, server, tablet, handset, etc.... See https://www.freedesktop.org/software/systemd/man/latest/hostnamectl.html#chassis%20%5BTYPE%5D
|
||||||
|
|
||||||
|
# `CcHostname.is_vm_chassis`
|
||||||
|
|
||||||
|
A convenient function that calls `CcHostname.get_chassis_type` internally to determine whether Settings is running in a virtual machine environment.
|
||||||
|
|
||||||
|
# `CcHostname.get_property`
|
||||||
|
|
||||||
|
Allows for queying other systemd-hostnamed properties. See `hostnamectl status` to list the available options.
|
54
docs/CC_PANEL.md
Normal file
54
docs/CC_PANEL.md
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
# CcPanel
|
||||||
|
|
||||||
|
[CcPanel](https://gitlab.gnome.org/GNOME/gnome-control-center/-/blob/main/shell/cc-panel.c?ref_type=heads) is the base class for each settings panel implementation.
|
||||||
|
|
||||||
|
`CcPanel` provides convenient navigation features for static and runtime subpages.
|
||||||
|
|
||||||
|
Static subpages are top-level setting pages such as "Screen Lock", "Location", "Thunderbolt" (in the Privacy settings) or "Date & Time", "Region & Language" (in the System settings).
|
||||||
|
|
||||||
|
Runtime subpages are pages that aren't likely part of the main execution hot path. These are pages usually hidden behind a non-toplevel row or an option.
|
||||||
|
|
||||||
|
The main conveniences of `CcPanel` are:
|
||||||
|
|
||||||
|
## Child packing
|
||||||
|
|
||||||
|
### Panel Subpages
|
||||||
|
|
||||||
|
`AdwNavigationPage` child pages of `CcPanel` defined with `<child type="subpage">`, will be added as pages to `CcPanel.navigation`. For example:
|
||||||
|
|
||||||
|
```xml
|
||||||
|
<template class="CcPrivacyPanel" parent="CcPanel">
|
||||||
|
<child type="subpage">
|
||||||
|
<object class="AdwNavigationPage">
|
||||||
|
```
|
||||||
|
|
||||||
|
This will result in:
|
||||||
|
|
||||||
|
* ### CcPanel (AdwNavigationPage)
|
||||||
|
- #### CcPanel.navigation (AdwNavigationView)
|
||||||
|
- ##### CcPanel.navigation.children +=
|
||||||
|
- ###### **child (AdwNavigationPage)**
|
||||||
|
|
||||||
|
### Other widgets
|
||||||
|
|
||||||
|
Widgets of other types will overwrite `CcPanel.child` and avoid the navigation mechanism entirely. **This is the case for all panels that don't have subpages**.
|
||||||
|
|
||||||
|
## API
|
||||||
|
|
||||||
|
## `CcPanel.add_static_subpage`
|
||||||
|
|
||||||
|
Allows for panels to create subpages on demand, rather than create at panel initialization.
|
||||||
|
|
||||||
|
This is useful for hub panels (such as System and Privacy), where we don't want to load all subpages at startup, given that users might just visit one.
|
||||||
|
|
||||||
|
## `CcPanel.push_subpage`
|
||||||
|
|
||||||
|
Allows for panel implementations to simply add an `AdwNavigationPage` to the top of the `CcPanel` navigation.
|
||||||
|
|
||||||
|
## `CcPanel.pop_visible_subpage`
|
||||||
|
|
||||||
|
Allows for panels to pop the current visible subpage from the navigation view.
|
||||||
|
|
||||||
|
## `CcPanel.get_visible_subpage`
|
||||||
|
|
||||||
|
Allows for panels to query for the visible subpage. This is useful when the panel implementation has custom behaviour depending on the page that is shown. For example, in the Privacy settings we check the current visible subpage so that we can determine what's the best documentation page to offer.
|
52
docs/CODEOWNERS
Normal file
52
docs/CODEOWNERS
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
# These are the people responsible for Settings panels and domain-specific
|
||||||
|
# parts of the GNOME Settings codebase.
|
||||||
|
#
|
||||||
|
# If you open a merge request for files listed here, please add the following
|
||||||
|
# people to the list of reviewers.
|
||||||
|
|
||||||
|
# The syntax of this file is defined by GitLab:
|
||||||
|
# https://docs.gitlab.com/ee/user/project/code_owners.html
|
||||||
|
# Which, in turn, is similar to the .gitignore and .gitattributes files:
|
||||||
|
#
|
||||||
|
# - comments start with `#`
|
||||||
|
# - the first column contains paths and globs
|
||||||
|
# - the second column contains GitLab user names or email addresses,
|
||||||
|
# separated by spaces
|
||||||
|
#
|
||||||
|
# The last matching glob (rather than the union of *all* matching globs) gives
|
||||||
|
# the owners of a piece of code.
|
||||||
|
#
|
||||||
|
# If you want to be responsible for code reviews in specific sections of
|
||||||
|
# the GNOME Settings code base, add yourself here.
|
||||||
|
|
||||||
|
# General maintainers
|
||||||
|
* @felipeborges @robert_ancell
|
||||||
|
|
||||||
|
# Panels
|
||||||
|
## About
|
||||||
|
panels/info-overview/* @cyberphantom52
|
||||||
|
|
||||||
|
## Accessibility
|
||||||
|
panels/universal-access/* @pksadiq
|
||||||
|
|
||||||
|
## Appearance
|
||||||
|
panels/background/* @velsinki
|
||||||
|
|
||||||
|
## Apps
|
||||||
|
panels/applications/cc-default-apps-* @nishalkulkarni
|
||||||
|
panels/applications/cc-removable-media-settings* @nishalkulkarni
|
||||||
|
|
||||||
|
## Bluetooth
|
||||||
|
panels/bluetooth/* @hadess
|
||||||
|
|
||||||
|
## Printers
|
||||||
|
panels/printers/* @mkasik
|
||||||
|
|
||||||
|
## Sound
|
||||||
|
panels/sound/* @melix99
|
||||||
|
|
||||||
|
## Wacom
|
||||||
|
panels/wacom/* @carlosg
|
||||||
|
|
||||||
|
## WWAN (Cellular)
|
||||||
|
panels/wwan/* @pksadiq
|
184
docs/CODE_OF_CONDUCT.md
Normal file
184
docs/CODE_OF_CONDUCT.md
Normal file
|
@ -0,0 +1,184 @@
|
||||||
|
# Code of Conduct
|
||||||
|
|
||||||
|
GNOME Settings is a project developed based on GNOME Code of Conduct and GitHub's community
|
||||||
|
guidelines. You can read it below:
|
||||||
|
|
||||||
|
## Summary
|
||||||
|
|
||||||
|
GNOME creates software for a better world. We achieve this by behaving well towards
|
||||||
|
each other.
|
||||||
|
|
||||||
|
Therefore this document suggests what we consider ideal behaviour, so you know what
|
||||||
|
to expect when getting involved in GNOME. This is who we are and what we want to be.
|
||||||
|
There is no official enforcement of these principles, and this should not be interpreted
|
||||||
|
like a legal document.
|
||||||
|
|
||||||
|
## Advice
|
||||||
|
|
||||||
|
* **Be respectful and considerate**: Disagreement is no excuse for poor behaviour or personal
|
||||||
|
attacks. Remember that a community where people feel uncomfortable is not a productive one.
|
||||||
|
|
||||||
|
* **Be patient and generous**: If someone asks for help it is because they need it. Do politely
|
||||||
|
suggest specific documentation or more appropriate venues where appropriate, but avoid
|
||||||
|
aggressive or vague responses such as "RTFM".
|
||||||
|
|
||||||
|
* **Assume people mean well**: Remember that decisions are often a difficult choice between
|
||||||
|
competing priorities. If you disagree, please do so politely. If something seems outrageous,
|
||||||
|
check that you did not misinterpret it. Ask for clarification, but do not assume the worst.
|
||||||
|
|
||||||
|
* **Try to be concise**: Avoid repeating what has been said already. Making a conversation larger
|
||||||
|
makes it difficult to follow, and people often feel personally attacked if they receive multiple
|
||||||
|
messages telling them the same thing.
|
||||||
|
|
||||||
|
|
||||||
|
In the interest of fostering an open and welcoming environment, we as
|
||||||
|
contributors and maintainers pledge to making participation in our project and
|
||||||
|
our community a harassment-free experience for everyone, regardless of age, body
|
||||||
|
size, disability, ethnicity, gender identity and expression, level of experience,
|
||||||
|
nationality, personal appearance, race, religion, or sexual identity and
|
||||||
|
orientation.
|
||||||
|
|
||||||
|
## Communication Guidelines
|
||||||
|
|
||||||
|
It is of ultimate importance to maintain a community in which everyone feels free to express
|
||||||
|
themselves, review, and comment on each others ideas, both technical and otherwise. Correspondingly,
|
||||||
|
an environment in which individuals are silenced, berated, or are otherwise afraid to speak up is
|
||||||
|
unlikely to foster fruitful dialog.
|
||||||
|
|
||||||
|
Everyone interacting with members of the community should always keep in mind the asymmetry of
|
||||||
|
communication: while your interaction with community members (and in particular, maintainers and
|
||||||
|
long-term contributors) may be singular and fleeting, these members generally interact with a high
|
||||||
|
volume of individuals each day. Before writing a comment, opening a new issue, or engaging as part
|
||||||
|
of any forum or IRC discussion, please take a moment to appreciate that fact.
|
||||||
|
|
||||||
|
While communicating, it is expected that all involved participants be respectful and civil at all
|
||||||
|
times and refrain from personal attacks.
|
||||||
|
|
||||||
|
### Communication Rules
|
||||||
|
|
||||||
|
The following behavior will not be tolerated on any occasion:
|
||||||
|
|
||||||
|
* **Threats of violence**: You may not threaten violence towards others or use the site to organize,
|
||||||
|
promote, or incite acts of real-world violence or terrorism. Think carefully about the words you
|
||||||
|
use, the images you post, and even the software you write, and how they may be interpreted by
|
||||||
|
others. Even if you mean something as a joke, it might not be received that way. If you think
|
||||||
|
that someone else might interpret the content you post as a threat or as promoting violence or
|
||||||
|
terrorism, stop. Don't post it. In extraordinary cases, we may report threats of violence to law
|
||||||
|
enforcement if we think there may be a genuine risk of physical harm or a threat to public safety.
|
||||||
|
|
||||||
|
* **Hate speech and discrimination**: While it is not forbidden to broach topics such as age, body
|
||||||
|
size, disability, ethnicity, gender identity and expression, level of experience, nationality,
|
||||||
|
personal appearance, race, religion, or sexual identity and orientation, we do not tolerate speech
|
||||||
|
that attacks a person or group of people on the basis of who they are. When approached in an
|
||||||
|
aggressive or insulting manner these (and other) sensitive topics can make others feel unwelcome,
|
||||||
|
or perhaps even unsafe. While there's always the potential for misunderstandings, we expect our
|
||||||
|
community members to remain respectful and civil when discussing sensitive topics.
|
||||||
|
|
||||||
|
* **Bullying and harassment**: We do not tolerate bullying, harassment, or any other means of
|
||||||
|
habitual badgering or intimidation targeted at a specific person or group of people. In general,
|
||||||
|
if your actions are unwanted and you cease to terminate this form of engagement, there is a good
|
||||||
|
chance that your behavior will be classified as bullying or harassment.
|
||||||
|
|
||||||
|
* **Impersonation**: You may not seek to mislead others as to your identity by copying another
|
||||||
|
person's avatar, posting content under their email address, using a similar username, or otherwise
|
||||||
|
posing as someone else. Impersonation and identity theft is a form of harassment.
|
||||||
|
|
||||||
|
* **Doxxing and invasion of privacy**: Don't post other people's personal information, such as phone
|
||||||
|
numbers, private email addresses, physical addresses, credit card numbers, Social Security/National
|
||||||
|
Identity numbers, or passwords. Depending on the context, we may consider such behavior to be an
|
||||||
|
invasion of privacy, with particularly egregious examples potentially escalating to the point of
|
||||||
|
legal action, such as when the released material presents a safety risk to the subject.
|
||||||
|
|
||||||
|
* **Obscene content**: In essence, do not post pornography, gore, or any other depiction of violence.
|
||||||
|
|
||||||
|
### General Advice
|
||||||
|
|
||||||
|
The following advice will help to increase the efficiency of communication with community members:
|
||||||
|
|
||||||
|
* Do not post "me too" comments. Use the GitLab reactions instead, e.g. “thumbs up” or “thumbs down”.
|
||||||
|
* Avoid adding priority, time, or relevance hints if you are not involved with the development of
|
||||||
|
the application. For example, `“This is an urgent issue”`, or `“This should be fixed now”`, or
|
||||||
|
even `“The majority of users need this feature”`.
|
||||||
|
* Do not use passive-aggressive communication tactics.
|
||||||
|
* When reporting technical problems with the application, such as misbehavior or crashes, focus on
|
||||||
|
sharing as many details as possible and avoid adding non-technical information to it.
|
||||||
|
|
||||||
|
An example of a **good** issue report:
|
||||||
|
|
||||||
|
```
|
||||||
|
GNOME Settings crashes when opening the Wi-Fi panel with 3+ Wi-Fi adapters
|
||||||
|
|
||||||
|
Steps to reproduce (assuming 3+ Wi-Fi adapters are present):
|
||||||
|
|
||||||
|
1. Open GNOME Settings
|
||||||
|
2. Select the Wi-Fi panel
|
||||||
|
3. Observe the crash
|
||||||
|
|
||||||
|
This does not happen with 2 or less adapters. Here is a backtrace of the
|
||||||
|
crash: backtrace.txt
|
||||||
|
```
|
||||||
|
|
||||||
|
In contrast, here is an example of a **bad** issue report:
|
||||||
|
|
||||||
|
```
|
||||||
|
GNOME Settings crashed while I was trying to connect to the internet. How can such
|
||||||
|
a thing happen and nobody notice? Did you not test it before releasing it?
|
||||||
|
|
||||||
|
This should be fixed as quick as possible!
|
||||||
|
```
|
||||||
|
|
||||||
|
* When asking for new features, try and add as much information as possible to justify its relevance,
|
||||||
|
why should it not be implemented as an auxiliary program, what problems it would solve, and offer
|
||||||
|
suggestions about how you think it should be implemented.
|
||||||
|
|
||||||
|
Example of a **good** feature request:
|
||||||
|
|
||||||
|
```
|
||||||
|
GNOME Settings needs to expose IPv6 options
|
||||||
|
|
||||||
|
As of now, the connection editor dialog does not allow editing various IPv6
|
||||||
|
options. This is relevant because without some of these options, it is not
|
||||||
|
possible to have a valid IPv6 configuration and, consequently, not have access
|
||||||
|
to various websites and services.
|
||||||
|
|
||||||
|
The list of missing configurations that are essential is:
|
||||||
|
|
||||||
|
* <Feature A>
|
||||||
|
* <Feature B>
|
||||||
|
|
||||||
|
Optionally, the following configurations can also be added:
|
||||||
|
|
||||||
|
* <Feature C>
|
||||||
|
* <Feature D>
|
||||||
|
|
||||||
|
Here is a quick sketch I have made showing how I think these options
|
||||||
|
should be exposed as a user interface: sketch.png.
|
||||||
|
```
|
||||||
|
|
||||||
|
Example of a **bad** feature request:
|
||||||
|
|
||||||
|
```
|
||||||
|
Merge GNOME Tweaks in GNOME Settings
|
||||||
|
|
||||||
|
The options in GNOME Tweaks are absolutely essential to the majority of us
|
||||||
|
users. Why was it not merged already? This is an urgent issue and should
|
||||||
|
have been addressed years ago. You should allocate all your resources on
|
||||||
|
merging those two applications.
|
||||||
|
```
|
||||||
|
|
||||||
|
### What happens if someone breaks these rules or guidelines?
|
||||||
|
|
||||||
|
Actions that may be taken in response to an abusive comment include but are not limited to:
|
||||||
|
|
||||||
|
* Content removal (when breaking any of the guidelines or rules)
|
||||||
|
* Content blocking (when breaking any of the guidelines or rules)
|
||||||
|
* Formal report to the Code of Conduct Committee (when breaking any of the rules)
|
||||||
|
|
||||||
|
## Attribution
|
||||||
|
|
||||||
|
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
|
||||||
|
available at [http://contributor-covenant.org/version/1/4][version]
|
||||||
|
|
||||||
|
[homepage]: http://contributor-covenant.org
|
||||||
|
[version]: http://contributor-covenant.org/version/1/4/
|
||||||
|
[maintainers]: https://gitlab.gnome.org/GNOME/gnome-control-center/blob/main/docs/MAINTAINERS.md
|
290
docs/CODING_STYLE.md
Normal file
290
docs/CODING_STYLE.md
Normal file
|
@ -0,0 +1,290 @@
|
||||||
|
# Style
|
||||||
|
|
||||||
|
GNOME Settings has a coding style based on GTK Coding Style, but with a few more
|
||||||
|
rules. Please read them carefully and, if in doubt, ask a maintainer for directions.
|
||||||
|
|
||||||
|
## General
|
||||||
|
|
||||||
|
The most important rule is: **see the surrounding code, and copy its style**.
|
||||||
|
|
||||||
|
That said, GNOME Settings assumes:
|
||||||
|
|
||||||
|
* 2 spaces of indentation
|
||||||
|
* 120 columns of line width
|
||||||
|
* Newline before `{`
|
||||||
|
|
||||||
|
Another rule that applies to function declarations is that all parameters are
|
||||||
|
aligned by the last '*'. There are plenty of examples below.
|
||||||
|
|
||||||
|
## Comments
|
||||||
|
|
||||||
|
Comment blocks should be formatted as following:
|
||||||
|
|
||||||
|
```c
|
||||||
|
/* Single line comment */
|
||||||
|
|
||||||
|
/* Multiline comments start at the first line of the comment block,
|
||||||
|
* but have the closing slash a line after. Every line starts with
|
||||||
|
* an asterisk that is aligned with every the rest of the block.
|
||||||
|
*/
|
||||||
|
```
|
||||||
|
|
||||||
|
## Conditionals
|
||||||
|
|
||||||
|
Conditionals should either be all in one line, or one per line. Newlines inside
|
||||||
|
conditionals are aligned by the last parenthesis.
|
||||||
|
|
||||||
|
|
||||||
|
Some examples below:
|
||||||
|
|
||||||
|
```c
|
||||||
|
// Single line if
|
||||||
|
if (a || b || (c && d))
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Multiline if with nested parenthesis
|
||||||
|
if (long_boolean_variable_used_in_this_condition_a ||
|
||||||
|
long_boolean_variable_used_in_this_condition_b ||
|
||||||
|
(long_boolean_variable_used_in_this_condition_c &&
|
||||||
|
long_boolean_variable_used_in_this_condition_d))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Another single line example with do {} while (...)
|
||||||
|
do
|
||||||
|
{
|
||||||
|
/* something */
|
||||||
|
}
|
||||||
|
while (a || b || (c && d));
|
||||||
|
```
|
||||||
|
|
||||||
|
## Structs and Enums
|
||||||
|
|
||||||
|
Structures and enums are formatted as following:
|
||||||
|
|
||||||
|
```c
|
||||||
|
struct _FooBar
|
||||||
|
{
|
||||||
|
guint32 field_one;
|
||||||
|
gchar *text;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
FooParent parent;
|
||||||
|
|
||||||
|
guint32 field_one;
|
||||||
|
gchar *text;
|
||||||
|
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
CustomType *something;
|
||||||
|
guint something_else;
|
||||||
|
} inner_struct;
|
||||||
|
|
||||||
|
gboolean flag : 1;
|
||||||
|
} FooBar;
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
FIRST,
|
||||||
|
SECOND,
|
||||||
|
LAST,
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
FOO_BAR_FIRST,
|
||||||
|
FOO_BAR_SECOND,
|
||||||
|
FOO_BAR_LAST,
|
||||||
|
} FooEnumBar;
|
||||||
|
```
|
||||||
|
|
||||||
|
## Header (.h) files
|
||||||
|
|
||||||
|
It is organized by the following structure:
|
||||||
|
|
||||||
|
1. GPL header
|
||||||
|
2. Local includes
|
||||||
|
3. System includes
|
||||||
|
4. `G_BEGIN_DECLS`
|
||||||
|
5. `#defines`
|
||||||
|
6. `G_DECLARE_{FINAL,DERIVABLE}_TYPE`
|
||||||
|
7. Public API
|
||||||
|
8. `G_END_DECLS`
|
||||||
|
|
||||||
|
The following style rules apply:
|
||||||
|
|
||||||
|
* The '*' and the type come together, without any spaces in between.
|
||||||
|
* Function names are aligned by the widest return value.
|
||||||
|
* Parenthesis after function name is aligned by the widest function name
|
||||||
|
* The last '*' in parameters are aligned by the widest parameter type
|
||||||
|
* No new line at the end of the file
|
||||||
|
|
||||||
|
As an example, this is how a header file should look like (extracted from
|
||||||
|
the `cc-object-storage.h` file):
|
||||||
|
|
||||||
|
```c
|
||||||
|
/* cc-object-storage.h
|
||||||
|
*
|
||||||
|
* Copyright 2018 Georges Basile Stavracas Neto <georges.stavracas@gmail.com>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <glib-object.h>
|
||||||
|
#include <gio/gio.h>
|
||||||
|
|
||||||
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
|
/* Default storage keys */
|
||||||
|
#define CC_OBJECT_NMCLIENT "CcObjectStorage::nm-client"
|
||||||
|
|
||||||
|
|
||||||
|
#define CC_TYPE_OBJECT_STORAGE (cc_object_storage_get_type())
|
||||||
|
G_DECLARE_FINAL_TYPE (CcObjectStorage, cc_object_storage, CC, OBJECT_STORAGE, GObject)
|
||||||
|
|
||||||
|
gboolean cc_object_storage_has_object (const gchar *key);
|
||||||
|
|
||||||
|
void cc_object_storage_add_object (const gchar *key,
|
||||||
|
gpointer object);
|
||||||
|
|
||||||
|
gpointer cc_object_storage_get_object (const gchar *key);
|
||||||
|
|
||||||
|
gpointer cc_object_storage_create_dbus_proxy_sync (GBusType bus_type,
|
||||||
|
GDBusProxyFlags flags,
|
||||||
|
const gchar *name,
|
||||||
|
const gchar *path,
|
||||||
|
const gchar *interface,
|
||||||
|
GCancellable *cancellable,
|
||||||
|
GError **error);
|
||||||
|
|
||||||
|
void cc_object_storage_create_dbus_proxy (GBusType bus_type,
|
||||||
|
GDBusProxyFlags flags,
|
||||||
|
const gchar *name,
|
||||||
|
const gchar *path,
|
||||||
|
const gchar *interface,
|
||||||
|
GCancellable *cancellable,
|
||||||
|
GAsyncReadyCallback callback,
|
||||||
|
gpointer user_data);
|
||||||
|
|
||||||
|
G_END_DECLS
|
||||||
|
```
|
||||||
|
|
||||||
|
## Source code
|
||||||
|
|
||||||
|
The source file keeps an order of methods. The order will be as following:
|
||||||
|
|
||||||
|
1. GPL header
|
||||||
|
2. Structures
|
||||||
|
3. Function prototypes
|
||||||
|
4. G_DEFINE_TYPE()
|
||||||
|
5. Enums
|
||||||
|
6. Static variables
|
||||||
|
7. Auxiliary methods
|
||||||
|
8. Callbacks
|
||||||
|
9. Interface implementations
|
||||||
|
10. Parent class overrides
|
||||||
|
11. class_init and init
|
||||||
|
12. Public API
|
||||||
|
|
||||||
|
### Structures
|
||||||
|
|
||||||
|
The structures must have the first pointer asterisk aligned one space after the
|
||||||
|
widest type name. For example:
|
||||||
|
|
||||||
|
```c
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
GBusType bus_type;
|
||||||
|
GDBusProxyFlags flags;
|
||||||
|
gchar *name;
|
||||||
|
gchar *path;
|
||||||
|
gchar *interface;
|
||||||
|
gboolean cached;
|
||||||
|
} TaskData;
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
### Function Prototypes
|
||||||
|
|
||||||
|
Function prototypes must be formatted just like in header files.
|
||||||
|
|
||||||
|
### Auxiliary Methods
|
||||||
|
|
||||||
|
Auxiliary method names must have a verb in the dictionary form, and should always
|
||||||
|
perform an action over something. They don't have the `cc_` prefix. For example:
|
||||||
|
|
||||||
|
```c
|
||||||
|
static void
|
||||||
|
execute_something_on_data (Foo *data,
|
||||||
|
Bar *bar)
|
||||||
|
{
|
||||||
|
/* ... */
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Callbacks
|
||||||
|
|
||||||
|
* Callbacks always have the `_cb` suffix
|
||||||
|
* Signal callbacks always have the `on_<object_name>` prefix
|
||||||
|
* Callback names must have the name of the signal in the past
|
||||||
|
|
||||||
|
For example:
|
||||||
|
|
||||||
|
```c
|
||||||
|
static void
|
||||||
|
on_foo_size_allocated_cb (GtkWidget *widget,
|
||||||
|
GtkAllocation *allocation,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
/* ... */
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Line Splitting
|
||||||
|
|
||||||
|
Line splitting works following the GTK code style, but legibility comes over above
|
||||||
|
all. If a function call looks unbalanced following the GTK style, it is fine to
|
||||||
|
slightly escape the rules.
|
||||||
|
|
||||||
|
For example, this feels extremelly unbalanced:
|
||||||
|
|
||||||
|
```c
|
||||||
|
foo_bar_do_somthing_sync (a,
|
||||||
|
1,
|
||||||
|
object,
|
||||||
|
data,
|
||||||
|
something
|
||||||
|
cancellable,
|
||||||
|
&error);
|
||||||
|
```
|
||||||
|
|
||||||
|
Notice the empty space before the arguments, and how empty and odd it looks. In
|
||||||
|
comparison, it will look better if written like this:
|
||||||
|
|
||||||
|
```c
|
||||||
|
foo_bar_do_somthing_sync (a, 1, object, data,
|
||||||
|
something
|
||||||
|
cancellable,
|
||||||
|
&error);
|
||||||
|
```
|
||||||
|
|
||||||
|
# Contributing guidelines
|
||||||
|
|
||||||
|
See CONTRIBUTIONS.md file for the contribution guidelines, and the Code of Conduct
|
||||||
|
that contributors are expected to follow.
|
97
docs/CONTRIBUTING.md
Normal file
97
docs/CONTRIBUTING.md
Normal file
|
@ -0,0 +1,97 @@
|
||||||
|
# Contributing
|
||||||
|
|
||||||
|
Thank you for considering contributing to Settings!
|
||||||
|
|
||||||
|
All code contributions are made using merge requests.
|
||||||
|
|
||||||
|
Please note we have a Code of Conduct, please follow it in all your interactions with the project.
|
||||||
|
|
||||||
|
## Creating Merge Requests
|
||||||
|
|
||||||
|
To open a merge request fork the Settings project, and then create a branch for your change.
|
||||||
|
When the change is ready, submit a merge request.
|
||||||
|
|
||||||
|
The following guidelines will help your change be successfully merged:
|
||||||
|
|
||||||
|
* Keep the change as small as possible. If you can split it into multiple merge requests please do
|
||||||
|
so.
|
||||||
|
* Use multiple commits. This makes is easier to review and helps to diagnose bugs in the future.
|
||||||
|
* Use clear commit messages (see below).
|
||||||
|
* Attach screenshots of the change.
|
||||||
|
* Link to relevant issues this change is related to.
|
||||||
|
* Always set the merge request to allow maintainer edits - this makes it easier
|
||||||
|
for a maintainer to make small improvements to land the change faster.
|
||||||
|
|
||||||
|
Please format commit messages as follows:
|
||||||
|
|
||||||
|
```
|
||||||
|
component: <summary>
|
||||||
|
|
||||||
|
A paragraph explaining the problem and its context.
|
||||||
|
|
||||||
|
Another one explaining how you solved that.
|
||||||
|
|
||||||
|
<link to issue(s) this change fixes>
|
||||||
|
```
|
||||||
|
|
||||||
|
## Bug Fixes
|
||||||
|
|
||||||
|
Changes that fix bugs include:
|
||||||
|
|
||||||
|
* Correcting code that crashes.
|
||||||
|
* Spelling mistakes in labels.
|
||||||
|
* Small layout issues (e.g. spacing).
|
||||||
|
* Use of deprecated APIs.
|
||||||
|
* Restructuring of code for improved safety.
|
||||||
|
|
||||||
|
Please include clear information in the commit message(s) and merge request that indicate what is
|
||||||
|
being fixed by the change.
|
||||||
|
|
||||||
|
These changes will be reviewed for correctness, and then merged once this is complete.
|
||||||
|
|
||||||
|
## User Experience Changes
|
||||||
|
|
||||||
|
Changes that impact the user experience of Settings require approval from the
|
||||||
|
[Design Team][design-team]. This includes:
|
||||||
|
|
||||||
|
* Addition or removal of features in existing panels.
|
||||||
|
* Changes to the layout of panels.
|
||||||
|
* New panels.
|
||||||
|
|
||||||
|
Please include before/after screenshots in the merge request to show what is being changed.
|
||||||
|
|
||||||
|
For one of these changes to be merged one of the following is required:
|
||||||
|
|
||||||
|
* The change is shown in an existing mockup done by the design team (linked to in the merge request
|
||||||
|
or issue).
|
||||||
|
* A comment from a design team member in the merge request or issue approving the change.
|
||||||
|
|
||||||
|
If a merge request is opened without the above the "Needs Design" label attached to it and will not
|
||||||
|
be merged until design approval is received.
|
||||||
|
|
||||||
|
Once design approval is obtained, the change will be reviewed for correctness, and then merged once
|
||||||
|
this is complete.
|
||||||
|
If design approval is not obtained, the merge request will be closed.
|
||||||
|
|
||||||
|
[design-team]: https://gitlab.gnome.org/Teams/Design
|
||||||
|
|
||||||
|
## Reviews
|
||||||
|
|
||||||
|
All changes require approval from one or more Settings maintainers.
|
||||||
|
Reviews are likely to ask for changes to be made, please respond to these as soon as you are able
|
||||||
|
and ask for clarification if the requests are not clear.
|
||||||
|
|
||||||
|
When the change is ready to land a maintainer will mark it as approved.
|
||||||
|
Then the change can be merged by either a maintainer or the submitter if they have suitable
|
||||||
|
permissions.
|
||||||
|
|
||||||
|
## Draft Merge Requests
|
||||||
|
|
||||||
|
Merge requests marked as draft will not be reviewed by Settings maintainers or merged.
|
||||||
|
When the change is ready for review please mark the merge request as ready.
|
||||||
|
|
||||||
|
## Inactive Merge Requests
|
||||||
|
|
||||||
|
If a merge request has comments from maintainers that have not been responded to within 4 weeks this
|
||||||
|
merge request is considered to be inactive and will be closed. The reporter may re-open it at a
|
||||||
|
later date if they respond to the comments.
|
62
docs/MAINTAINERS.md
Normal file
62
docs/MAINTAINERS.md
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
This document describes how maintainership works on GNOME Settings. It is intended to be a guideline
|
||||||
|
for future reference.
|
||||||
|
|
||||||
|
The list of current maintainers can be found at the [gnome-control-center.doap][doap] DOAP file.
|
||||||
|
|
||||||
|
# General Rules
|
||||||
|
|
||||||
|
The purpose of the shared maintainership model in GNOME Settings is to avoid as much as possible
|
||||||
|
pushing unreviewed code in the main repository. Not only it is a good engineering practice, but it
|
||||||
|
also increases the code quality and reduces the number of bugs.
|
||||||
|
|
||||||
|
GNOME Settings has two types of maintainers:
|
||||||
|
|
||||||
|
* **General Maintainer**: take care of the whole codebase and of panels without a specific maintainer.
|
||||||
|
* **Panel Maintainer**: take care of a specific panel with a stronger authority over General
|
||||||
|
Maintainers.
|
||||||
|
|
||||||
|
|
||||||
|
## For Contributors
|
||||||
|
|
||||||
|
Panel Maintainers have a stronger authority over their panels than a General Maintainer. If you are
|
||||||
|
contributing to a specific panel, and that panel has a dedicate maintainer, they should be the main
|
||||||
|
point of contact.
|
||||||
|
|
||||||
|
In the rare case of Panel Maintainers not being responsive, it is allowed to contact General
|
||||||
|
Maintainers.
|
||||||
|
|
||||||
|
## For Maintainers
|
||||||
|
|
||||||
|
If you are a Panel Maintainer, your merge requests will be reviewed by General Maintainer. The
|
||||||
|
opposite is true as well - General Maintainers contributing to a specific panel will have their
|
||||||
|
merge requests reviewed by the Panel Maintainer of that panel.
|
||||||
|
|
||||||
|
If you are a General Maintainer contributing to an unmaintained panel, or to the main codebase, your
|
||||||
|
merge requests will be reviewed by another General Maintainer.
|
||||||
|
|
||||||
|
Avoid pushing commits without an explicit review, except in the following cases:
|
||||||
|
|
||||||
|
* The commit is a translation commit
|
||||||
|
* The commit is trivial
|
||||||
|
* The commit is urgent and no reviewers were available in time
|
||||||
|
|
||||||
|
When accepting a merge request and allowing the other maintainer to merge, avoid misunderstandings
|
||||||
|
by being explicit. Suggested acceptance phrase:
|
||||||
|
|
||||||
|
`I approve this merge request. You are allowed to merge it.`
|
||||||
|
|
||||||
|
### Urgency Commits
|
||||||
|
|
||||||
|
Urgency commits should never happen, but in case they're needed, they are defined by the following
|
||||||
|
criteria:
|
||||||
|
|
||||||
|
* On stable branches (or `main` right after a stable release)
|
||||||
|
* Symptoms:
|
||||||
|
* Always OR often reproducible; AND
|
||||||
|
* Crash; OR
|
||||||
|
* Data loss; OR
|
||||||
|
* System corruption
|
||||||
|
* Quickly followed by an emergency release (at most 2 days after the commit)
|
||||||
|
|
||||||
|
|
||||||
|
[doap]: https://gitlab.gnome.org/GNOME/gnome-control-center/blob/main/gnome-control-center.doap
|
7
docs/PRINTERS_TESTING.md
Normal file
7
docs/PRINTERS_TESTING.md
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
# Testing the Printers panel without a printer
|
||||||
|
|
||||||
|
The cups package in most distributions includes the lpadmin tool. With that you can create a "dummy" printer that redirects its output to /dev/null.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo lpadmin -p FakePrinter -E -v file:/dev/null
|
||||||
|
```
|
9
docs/RESET_LAST_VISITED_PANEL.md
Normal file
9
docs/RESET_LAST_VISITED_PANEL.md
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
# Workaround: A crashing panel preventing Settings from starting up
|
||||||
|
|
||||||
|
GNOME Settings saves the last opened panel when it is closed and attempts to start on that same panel when starting up again. If the panel has issues, you won't be able to start GNOME Settings.
|
||||||
|
|
||||||
|
To workaround the issue you can reset the last-opened setting with:
|
||||||
|
|
||||||
|
```gsettings reset org.gnome.Settings last-panel```
|
||||||
|
|
||||||
|
Please, try to [obtain a stack trace](https://wiki.gnome.org/GettingInTouch/Bugzilla/GettingTraces/Details) of the crashing panel and [report an issue](https://gitlab.gnome.org/GNOME/gnome-control-center/-/issues/new) attaching it.
|
6
docs/SIDEBAR_PANEL_LIST.md
Normal file
6
docs/SIDEBAR_PANEL_LIST.md
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
# Reordering the sidebar panel list
|
||||||
|
|
||||||
|
Since 46.alpha the order of panels in the sidebar as well as the position of the separators is defined in this array https://gitlab.gnome.org/GNOME/gnome-control-center/-/blob/main/shell/cc-panel-list.c#L350
|
||||||
|
|
||||||
|
* Use the string "separator" to introduce a separator between two rows
|
||||||
|
* A "separator" can't be the last row
|
5
docs/USERS_FINGERPRINT_MOCKING.md
Normal file
5
docs/USERS_FINGERPRINT_MOCKING.md
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
# Mocking fingerprint devices
|
||||||
|
|
||||||
|
To work in the fingerprint enrollment and manager in the User accounts, one might have to simulate device events.
|
||||||
|
|
||||||
|
For that, use https://gitlab.freedesktop.org/3v1n0/fprintd-mock-runner
|
61
docs/WACOM_TESTING.md
Normal file
61
docs/WACOM_TESTING.md
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
# Testing Wacom panel without a tablet or pen
|
||||||
|
|
||||||
|
## Setup
|
||||||
|
|
||||||
|
The `hid-replay` utility that can replay device events, simulating pen and touch behavior. This utility provides pre-built binaries ready for use on its [releases](https://github.com/hidutils/hid-replay/releases/) page, you can grab the `hid-replay.zip` file and run it with:
|
||||||
|
```
|
||||||
|
unzip hid-replay.zip
|
||||||
|
chmod +x hid-replay
|
||||||
|
sudo ./hid-replay <path-to-recording>
|
||||||
|
```
|
||||||
|
|
||||||
|
The tool can also be obtained from its source code with:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git clone https://github.com/hidutils/hid-replay/
|
||||||
|
```
|
||||||
|
|
||||||
|
To compile it use the `cargo` command after installing the required dependencies:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
dnf install llvm-devel clang-devel # on Fedora
|
||||||
|
apt install llvm-dev libclang-dev # on Debian/Ubuntu
|
||||||
|
|
||||||
|
cargo build
|
||||||
|
sudo CARGO_INSTALL_ROOT=/usr/local cargo install hid-replay
|
||||||
|
```
|
||||||
|
The last command will install `hid-replay` as `/usr/local/bin/hid-replay`.
|
||||||
|
|
||||||
|
Peter Hutterer kindly maintains a collection of Wacom device event recordings in a git repository that can be downloaded with:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git clone https://github.com/whot/wacom-recordings
|
||||||
|
```
|
||||||
|
|
||||||
|
## Playing device recordings
|
||||||
|
|
||||||
|
After setting up the environment, you can run the **hid-replay** tool (inside the hid-tools folder):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo hid-replay <path-to-recording>
|
||||||
|
```
|
||||||
|
|
||||||
|
(where \<path-to-recording\> is one of the `.hid` files in the **wacom-recordings** collection.
|
||||||
|
|
||||||
|
## Testing GNOME Settings Wacom panel
|
||||||
|
|
||||||
|
While the hid-replay tool runs in the background, you can open GNOME Settings -> Wacom and you will see the settings for the correspondent device of the recording.
|
||||||
|
|
||||||
|
For example:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo hid-replay wacom-recordings/Wacom\ Intuos\ Pro\ M/pen.pen-light-horizontal.hid
|
||||||
|
```
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
## Limitations
|
||||||
|
|
||||||
|
This setup currently doesn't work in a container (such as Toolbx) as it has insufficient permissions.
|
||||||
|
|
||||||
|
This was tested in Fedora Workstation 39.
|
15
docs/index.md
Normal file
15
docs/index.md
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
# GNOME Settings Developer Documentation
|
||||||
|
|
||||||
|
GNOME Settings, also known as gnome-control-center, is the central application for managing system and desktop configurations in the GNOME desktop environment.
|
||||||
|
|
||||||
|
This documentation is focused on developers, designers, and translators, contributing or interested in understanding the project internals.
|
||||||
|
|
||||||
|
## Guides/HowDoI
|
||||||
|
|
||||||
|
* [Building GNOME Settings with Toolbx](BUILDING_WITH_TOOLBX.md)
|
||||||
|
* [Building GNOME Settings with Flatpak/GNOME Builder](BUILDING_WITH_FLATPAK_BUILDER.md)
|
||||||
|
* [Testing the Printers panel without a printer](PRINTERS_TESTING.md)
|
||||||
|
* [Testing the Fingerprint settings without a fingerprint reader](USERS_FINGERPRINT_MOCKING.md)
|
||||||
|
* [Testing the Wacom settings without a tablet](WACOM_TESTING.md)
|
||||||
|
* [Reordering the panel list sidebar](SIDEBAR_PANEL_LIST.md)
|
||||||
|
* [Reset the last-visited panel setting](RESET_LAST_VISITED_PANEL.md)
|
15
gettext/its/gnome-keybindings.its
Normal file
15
gettext/its/gnome-keybindings.its
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
<?xml version="1.0"?>
|
||||||
|
<its:rules xmlns:its="http://www.w3.org/2005/11/its"
|
||||||
|
xmlns:gt="https://www.gnu.org/s/gettext/ns/its/extensions/1.0"
|
||||||
|
version="2.0">
|
||||||
|
<its:translateRule selector="/KeyListEntries" translate="no"/>
|
||||||
|
<its:translateRule selector="/KeyListEntries/@name" translate="yes"/>
|
||||||
|
<its:translateRule selector="//KeyListEntry" translate="yes"/>
|
||||||
|
<its:translateRule selector="//KeyListEntry/@description" translate="yes"/>
|
||||||
|
|
||||||
|
<gt:contextRule selector="//KeyListEntry[@msgctxt]" contextPointer="@msgctxt"/>
|
||||||
|
|
||||||
|
<!-- Extracted strings are consumed by the library and are never
|
||||||
|
merged back; we don't want to escape special characters. -->
|
||||||
|
<gt:escapeRule selector="/KeyListEntries" escape="no"/>
|
||||||
|
</its:rules>
|
6
gettext/its/gnome-keybindings.loc
Normal file
6
gettext/its/gnome-keybindings.loc
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
<?xml version="1.0"?>
|
||||||
|
<locatingRules>
|
||||||
|
<locatingRule name="GnomeKeybindings" pattern="*.xml">
|
||||||
|
<documentRule localName="KeyListEntries" target="gnome-keybindings.its"/>
|
||||||
|
</locatingRule>
|
||||||
|
</locatingRules>
|
6
gettext/its/sounds.its
Normal file
6
gettext/its/sounds.its
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
<?xml version="1.0"?>
|
||||||
|
<its:rules xmlns:its="http://www.w3.org/2005/11/its"
|
||||||
|
version="2.0">
|
||||||
|
<its:translateRule selector="/sounds" translate="no"/>
|
||||||
|
<its:translateRule selector="//name" translate="yes"/>
|
||||||
|
</its:rules>
|
6
gettext/its/sounds.loc
Normal file
6
gettext/its/sounds.loc
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
<?xml version="1.0"?>
|
||||||
|
<locatingRules>
|
||||||
|
<locatingRule name="sounds" pattern="*.xml">
|
||||||
|
<documentRule localName="sounds" target="sounds.its"/>
|
||||||
|
</locatingRule>
|
||||||
|
</locatingRules>
|
424
global-shortcuts-provider/cc-global-shortcut-dialog.c
Normal file
424
global-shortcuts-provider/cc-global-shortcut-dialog.c
Normal file
|
@ -0,0 +1,424 @@
|
||||||
|
/* cc-global-shortcut-dialog.c
|
||||||
|
*
|
||||||
|
* Copyright (C) 2010 Intel, Inc
|
||||||
|
* Copyright (C) 2016 Endless, Inc
|
||||||
|
* Copyright (C) 2020 System76, Inc.
|
||||||
|
* Copyright (C) 2022 Purism SPC
|
||||||
|
* Copyright © 2024 GNOME Foundation Inc.
|
||||||
|
* Copyright © 2024 Red Hat Inc.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Author: Thomas Wood <thomas.wood@intel.com>
|
||||||
|
* Georges Basile Stavracas Neto <gbsneto@gnome.org>
|
||||||
|
* Ian Douglas Scott <idscott@system76.com>
|
||||||
|
* Mohammed Sadiq <sadiq@sadiqpk.org>
|
||||||
|
* Dorota Czaplejewicz <gnome@dorotac.eu>
|
||||||
|
* Jonas Ådahl <jadahl@redhat.com>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <adwaita.h>
|
||||||
|
#include <config.h>
|
||||||
|
#include <glib/gi18n.h>
|
||||||
|
#include <gxdp.h>
|
||||||
|
|
||||||
|
#include "panels/keyboard/cc-keyboard-resources.h"
|
||||||
|
|
||||||
|
#include "cc-global-shortcut-dialog.h"
|
||||||
|
#include "cc-keyboard-shortcut-group.h"
|
||||||
|
#include "cc-util.h"
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
DONE,
|
||||||
|
|
||||||
|
N_SIGNALS
|
||||||
|
};
|
||||||
|
|
||||||
|
static guint signals[N_SIGNALS];
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
PROP_0,
|
||||||
|
PROP_APP_ID,
|
||||||
|
PROP_PARENT_WINDOW_HANDLE,
|
||||||
|
PROP_SHORTCUTS,
|
||||||
|
N_PROPS,
|
||||||
|
};
|
||||||
|
|
||||||
|
static GParamSpec *props[N_PROPS];
|
||||||
|
|
||||||
|
struct _CcGlobalShortcutDialog
|
||||||
|
{
|
||||||
|
AdwWindow parent_instance;
|
||||||
|
|
||||||
|
AdwPreferencesPage *shortcut_list;
|
||||||
|
GtkSizeGroup *accelerator_size_group;
|
||||||
|
|
||||||
|
GVariant *app_shortcuts;
|
||||||
|
|
||||||
|
/* Contains `CcKeyboardItem`s */
|
||||||
|
GListStore *shortcuts;
|
||||||
|
|
||||||
|
CcKeyboardManager *manager;
|
||||||
|
|
||||||
|
AdwPreferencesGroup *shortcuts_group;
|
||||||
|
|
||||||
|
char *app_id;
|
||||||
|
char *parent_window_handle;
|
||||||
|
GxdpExternalWindow *external_window;
|
||||||
|
|
||||||
|
gboolean has_new_shortcuts;
|
||||||
|
};
|
||||||
|
|
||||||
|
G_DEFINE_TYPE (CcGlobalShortcutDialog,
|
||||||
|
cc_global_shortcut_dialog,
|
||||||
|
ADW_TYPE_WINDOW)
|
||||||
|
|
||||||
|
static void
|
||||||
|
populate_shortcuts_model (CcGlobalShortcutDialog *self,
|
||||||
|
const char *section_id,
|
||||||
|
const char *section_title)
|
||||||
|
{
|
||||||
|
GtkWidget *shortcuts_group;
|
||||||
|
|
||||||
|
self->shortcuts = g_list_store_new (CC_TYPE_KEYBOARD_ITEM);
|
||||||
|
|
||||||
|
shortcuts_group =
|
||||||
|
cc_keyboard_shortcut_group_new (G_LIST_MODEL (self->shortcuts),
|
||||||
|
section_id, section_title,
|
||||||
|
self->manager,
|
||||||
|
self->accelerator_size_group);
|
||||||
|
self->shortcuts_group = ADW_PREFERENCES_GROUP (shortcuts_group);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
shortcut_added_cb (CcGlobalShortcutDialog *self,
|
||||||
|
CcKeyboardItem *item,
|
||||||
|
const char *section_id,
|
||||||
|
const char *section_title)
|
||||||
|
{
|
||||||
|
if (strcmp (section_id, self->app_id) == 0)
|
||||||
|
g_list_store_append (self->shortcuts, item);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
shortcuts_loaded_cb (CcGlobalShortcutDialog *self)
|
||||||
|
{
|
||||||
|
adw_preferences_page_add (self->shortcut_list, self->shortcuts_group);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
emit_done (CcGlobalShortcutDialog *self,
|
||||||
|
gboolean success)
|
||||||
|
{
|
||||||
|
g_autoptr(GVariant) response = NULL;
|
||||||
|
|
||||||
|
if (success)
|
||||||
|
{
|
||||||
|
cc_keyboard_manager_store_global_shortcuts (self->manager, self->app_id);
|
||||||
|
response = cc_keyboard_manager_get_global_shortcuts (self->manager,
|
||||||
|
self->app_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_signal_emit (self, signals[DONE], 0, response);
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
close_request_cb (CcGlobalShortcutDialog *self)
|
||||||
|
{
|
||||||
|
emit_done (self, FALSE);
|
||||||
|
return GDK_EVENT_STOP;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
on_add_button_clicked_cb (CcGlobalShortcutDialog *self)
|
||||||
|
{
|
||||||
|
emit_done (self, TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
cc_global_shortcut_dialog_finalize (GObject *object)
|
||||||
|
{
|
||||||
|
CcGlobalShortcutDialog *self = CC_GLOBAL_SHORTCUT_DIALOG (object);
|
||||||
|
|
||||||
|
g_clear_object (&self->external_window);
|
||||||
|
g_clear_object (&self->manager);
|
||||||
|
g_clear_object (&self->shortcut_list);
|
||||||
|
g_clear_object (&self->accelerator_size_group);
|
||||||
|
g_clear_pointer (&self->app_id, g_free);
|
||||||
|
g_clear_pointer (&self->parent_window_handle, g_free);
|
||||||
|
g_clear_pointer (&self->app_shortcuts, g_variant_unref);
|
||||||
|
|
||||||
|
G_OBJECT_CLASS (cc_global_shortcut_dialog_parent_class)->finalize (object);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
cc_global_shortcut_dialog_set_property (GObject *object,
|
||||||
|
guint prop_id,
|
||||||
|
const GValue *value,
|
||||||
|
GParamSpec *pspec)
|
||||||
|
{
|
||||||
|
CcGlobalShortcutDialog *self = CC_GLOBAL_SHORTCUT_DIALOG (object);
|
||||||
|
|
||||||
|
switch (prop_id)
|
||||||
|
{
|
||||||
|
case PROP_APP_ID:
|
||||||
|
self->app_id = g_value_dup_string (value);
|
||||||
|
break;
|
||||||
|
case PROP_PARENT_WINDOW_HANDLE:
|
||||||
|
self->parent_window_handle = g_value_dup_string (value);
|
||||||
|
break;
|
||||||
|
case PROP_SHORTCUTS:
|
||||||
|
self->app_shortcuts = g_value_dup_variant (value);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static GVariant *
|
||||||
|
lookup_in_settings_variant (GVariant *settings,
|
||||||
|
const char *shortcut_id)
|
||||||
|
{
|
||||||
|
GVariantIter iter;
|
||||||
|
g_autofree char *key = NULL;
|
||||||
|
g_autoptr(GVariant) value = NULL;
|
||||||
|
|
||||||
|
g_variant_iter_init (&iter, settings);
|
||||||
|
|
||||||
|
while (g_variant_iter_next (&iter, "(s@a{sv})", &key, &value))
|
||||||
|
{
|
||||||
|
g_autofree char *shortcut = g_steal_pointer (&key);
|
||||||
|
g_autoptr(GVariant) config = g_steal_pointer (&value);
|
||||||
|
|
||||||
|
if (g_strcmp0 (shortcut_id, shortcut) == 0)
|
||||||
|
return g_steal_pointer (&config);
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static GVariant *
|
||||||
|
app_shortcuts_to_settings_variant (GVariant *app_shortcuts,
|
||||||
|
GVariant *old_settings,
|
||||||
|
gboolean *has_new_shortcuts)
|
||||||
|
{
|
||||||
|
g_auto(GVariantBuilder) builder =
|
||||||
|
G_VARIANT_BUILDER_INIT (G_VARIANT_TYPE ("a(sa{sv})"));
|
||||||
|
g_autoptr(GVariant) value = NULL;
|
||||||
|
g_autofree char *key = NULL;
|
||||||
|
GVariantIter iter;
|
||||||
|
|
||||||
|
g_variant_iter_init (&iter, app_shortcuts);
|
||||||
|
|
||||||
|
while (g_variant_iter_next (&iter, "(s@a{sv})", &key, &value))
|
||||||
|
{
|
||||||
|
g_autofree char *shortcut_id = g_steal_pointer (&key);
|
||||||
|
g_autoptr(GVariant) prefs = g_steal_pointer (&value);
|
||||||
|
g_autoptr(GVariant) setting = NULL;
|
||||||
|
|
||||||
|
setting = lookup_in_settings_variant (old_settings, shortcut_id);
|
||||||
|
|
||||||
|
if (setting)
|
||||||
|
{
|
||||||
|
/* Shortcut was configured previously */
|
||||||
|
g_variant_builder_add (&builder, "(s@a{sv})", shortcut_id, setting);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
g_auto(GVariantBuilder) new_shortcut =
|
||||||
|
G_VARIANT_BUILDER_INIT (G_VARIANT_TYPE_VARDICT);
|
||||||
|
g_auto(GVariantDict) prefs_dict = G_VARIANT_DICT_INIT (prefs);
|
||||||
|
g_autoptr(GVariant) description = NULL, preferred_trigger = NULL;
|
||||||
|
g_autoptr(GVariant) shortcuts = NULL;
|
||||||
|
|
||||||
|
/* Extract app preferences for new shortcut */
|
||||||
|
description =
|
||||||
|
g_variant_dict_lookup_value (&prefs_dict, "description",
|
||||||
|
G_VARIANT_TYPE_STRING);
|
||||||
|
if (!description)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
g_variant_builder_add (&new_shortcut, "{sv}", "description",
|
||||||
|
g_variant_ref_sink (description));
|
||||||
|
preferred_trigger =
|
||||||
|
g_variant_dict_lookup_value (&prefs_dict, "preferred_trigger",
|
||||||
|
G_VARIANT_TYPE_STRING);
|
||||||
|
shortcuts = g_variant_new_array (G_VARIANT_TYPE_STRING,
|
||||||
|
preferred_trigger ? &preferred_trigger : NULL,
|
||||||
|
preferred_trigger ? 1 : 0);
|
||||||
|
g_variant_builder_add (&new_shortcut, "{sv}", "shortcuts",
|
||||||
|
g_variant_ref_sink (shortcuts));
|
||||||
|
|
||||||
|
g_variant_builder_add (&builder, "(s@a{sv})", shortcut_id,
|
||||||
|
g_variant_builder_end (&new_shortcut));
|
||||||
|
*has_new_shortcuts = TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return g_variant_builder_end (&builder);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
cc_global_shortcut_dialog_constructed (GObject *object)
|
||||||
|
{
|
||||||
|
CcGlobalShortcutDialog *self = CC_GLOBAL_SHORTCUT_DIALOG (object);
|
||||||
|
g_autoptr(GVariant) saved_shortcuts = NULL, shortcuts = NULL;
|
||||||
|
|
||||||
|
saved_shortcuts = cc_keyboard_manager_get_global_shortcuts (self->manager,
|
||||||
|
self->app_id);
|
||||||
|
|
||||||
|
shortcuts = app_shortcuts_to_settings_variant (self->app_shortcuts,
|
||||||
|
saved_shortcuts,
|
||||||
|
&self->has_new_shortcuts);
|
||||||
|
|
||||||
|
populate_shortcuts_model (self, self->app_id,
|
||||||
|
cc_util_app_id_to_display_name (self->app_id));
|
||||||
|
|
||||||
|
g_signal_connect_object (self->manager,
|
||||||
|
"shortcut-added",
|
||||||
|
G_CALLBACK (shortcut_added_cb),
|
||||||
|
self, G_CONNECT_SWAPPED);
|
||||||
|
/* Shortcuts can not get removed from this dialog,
|
||||||
|
* it's an offer, and offers don't change when you look away. */
|
||||||
|
g_signal_connect_object (self->manager,
|
||||||
|
"shortcuts-loaded",
|
||||||
|
G_CALLBACK (shortcuts_loaded_cb),
|
||||||
|
self, G_CONNECT_SWAPPED);
|
||||||
|
|
||||||
|
cc_keyboard_manager_load_global_shortcuts (self->manager,
|
||||||
|
self->app_id,
|
||||||
|
shortcuts);
|
||||||
|
|
||||||
|
G_OBJECT_CLASS (cc_global_shortcut_dialog_parent_class)->constructed (object);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
cc_global_shortcut_dialog_class_init (CcGlobalShortcutDialogClass *klass)
|
||||||
|
{
|
||||||
|
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||||
|
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
|
||||||
|
|
||||||
|
object_class->finalize = cc_global_shortcut_dialog_finalize;
|
||||||
|
object_class->set_property = cc_global_shortcut_dialog_set_property;
|
||||||
|
object_class->constructed = cc_global_shortcut_dialog_constructed;
|
||||||
|
|
||||||
|
props[PROP_APP_ID] =
|
||||||
|
g_param_spec_string ("app-id", NULL, NULL, NULL,
|
||||||
|
G_PARAM_WRITABLE |
|
||||||
|
G_PARAM_CONSTRUCT_ONLY |
|
||||||
|
G_PARAM_STATIC_STRINGS);
|
||||||
|
|
||||||
|
props[PROP_PARENT_WINDOW_HANDLE] =
|
||||||
|
g_param_spec_string ("parent-window-handle", NULL, NULL, NULL,
|
||||||
|
G_PARAM_WRITABLE |
|
||||||
|
G_PARAM_CONSTRUCT_ONLY |
|
||||||
|
G_PARAM_STATIC_STRINGS);
|
||||||
|
|
||||||
|
props[PROP_SHORTCUTS] =
|
||||||
|
g_param_spec_variant ("shortcuts", NULL, NULL,
|
||||||
|
G_VARIANT_TYPE ("a(sa{sv})"), NULL,
|
||||||
|
G_PARAM_WRITABLE |
|
||||||
|
G_PARAM_CONSTRUCT_ONLY |
|
||||||
|
G_PARAM_STATIC_STRINGS);
|
||||||
|
|
||||||
|
g_object_class_install_properties (object_class, N_PROPS, props);
|
||||||
|
|
||||||
|
signals[DONE] =
|
||||||
|
g_signal_new ("done",
|
||||||
|
G_TYPE_FROM_CLASS (object_class),
|
||||||
|
G_SIGNAL_RUN_LAST,
|
||||||
|
0, NULL, NULL, NULL,
|
||||||
|
G_TYPE_NONE, 1,
|
||||||
|
G_TYPE_VARIANT);
|
||||||
|
|
||||||
|
g_resources_register (cc_keyboard_get_resource ());
|
||||||
|
|
||||||
|
gtk_widget_class_set_template_from_resource (widget_class,
|
||||||
|
"/org/gnome/control-center/global-shortcuts-provider/"
|
||||||
|
"cc-global-shortcut-dialog.ui");
|
||||||
|
|
||||||
|
gtk_widget_class_bind_template_child (widget_class,
|
||||||
|
CcGlobalShortcutDialog,
|
||||||
|
shortcut_list);
|
||||||
|
gtk_widget_class_bind_template_child (widget_class,
|
||||||
|
CcGlobalShortcutDialog,
|
||||||
|
accelerator_size_group);
|
||||||
|
|
||||||
|
gtk_widget_class_bind_template_callback (widget_class,
|
||||||
|
on_add_button_clicked_cb);
|
||||||
|
|
||||||
|
gtk_widget_class_add_binding_action (widget_class,
|
||||||
|
GDK_KEY_Escape, 0,
|
||||||
|
"window.close", NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
cc_global_shortcut_dialog_init (CcGlobalShortcutDialog *self)
|
||||||
|
{
|
||||||
|
gtk_widget_init_template (GTK_WIDGET (self));
|
||||||
|
|
||||||
|
self->manager = cc_keyboard_manager_new ();
|
||||||
|
|
||||||
|
g_signal_connect (self, "close-request",
|
||||||
|
G_CALLBACK (close_request_cb), NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
CcGlobalShortcutDialog *
|
||||||
|
cc_global_shortcut_dialog_new (const char *app_id,
|
||||||
|
const char *parent_window,
|
||||||
|
GVariant *shortcuts)
|
||||||
|
{
|
||||||
|
return g_object_new (CC_TYPE_GLOBAL_SHORTCUT_DIALOG,
|
||||||
|
"app-id", app_id,
|
||||||
|
"parent-window-handle", parent_window,
|
||||||
|
"shortcuts", shortcuts,
|
||||||
|
NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
cc_global_shortcut_dialog_present (CcGlobalShortcutDialog *self)
|
||||||
|
{
|
||||||
|
if (!self->has_new_shortcuts)
|
||||||
|
{
|
||||||
|
emit_done (self, TRUE);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!gtk_widget_get_visible (GTK_WIDGET (self)))
|
||||||
|
{
|
||||||
|
self->external_window =
|
||||||
|
gxdp_external_window_new_from_handle (self->parent_window_handle);
|
||||||
|
|
||||||
|
if (self->external_window)
|
||||||
|
{
|
||||||
|
GtkNative *native;
|
||||||
|
GdkSurface *surface;
|
||||||
|
|
||||||
|
gtk_widget_realize (GTK_WIDGET (self));
|
||||||
|
|
||||||
|
native = gtk_widget_get_native (GTK_WIDGET (self));
|
||||||
|
surface = gtk_native_get_surface (native);
|
||||||
|
|
||||||
|
gxdp_external_window_set_parent_of (self->external_window,
|
||||||
|
surface);
|
||||||
|
}
|
||||||
|
|
||||||
|
gtk_window_present (GTK_WINDOW (self));
|
||||||
|
}
|
||||||
|
}
|
44
global-shortcuts-provider/cc-global-shortcut-dialog.h
Normal file
44
global-shortcuts-provider/cc-global-shortcut-dialog.h
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
/* cc-global-shortcut-dialog.h
|
||||||
|
*
|
||||||
|
* Copyright (C) 2020 System76, Inc.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Author: Ian Douglas Scott <idscott@system76.com>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "cc-keyboard-manager.h"
|
||||||
|
#include <adwaita.h>
|
||||||
|
#include <gio/gio.h>
|
||||||
|
|
||||||
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
|
#define CC_TYPE_GLOBAL_SHORTCUT_DIALOG (cc_global_shortcut_dialog_get_type ())
|
||||||
|
|
||||||
|
G_DECLARE_FINAL_TYPE (CcGlobalShortcutDialog,
|
||||||
|
cc_global_shortcut_dialog,
|
||||||
|
CC, GLOBAL_SHORTCUT_DIALOG,
|
||||||
|
AdwWindow)
|
||||||
|
|
||||||
|
CcGlobalShortcutDialog *cc_global_shortcut_dialog_new (const char *app_id,
|
||||||
|
const char *parent_window,
|
||||||
|
GVariant *shortcuts);
|
||||||
|
|
||||||
|
void cc_global_shortcut_dialog_present (CcGlobalShortcutDialog *dialog);
|
||||||
|
|
||||||
|
G_END_DECLS
|
44
global-shortcuts-provider/cc-global-shortcut-dialog.ui
Normal file
44
global-shortcuts-provider/cc-global-shortcut-dialog.ui
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<interface>
|
||||||
|
<template class="CcGlobalShortcutDialog" parent="AdwWindow">
|
||||||
|
<property name="modal">True</property>
|
||||||
|
<property name="default-width">480</property>
|
||||||
|
<property name="title" translatable="yes">Add Keyboard Shortcuts</property>
|
||||||
|
<child>
|
||||||
|
<object class="AdwToolbarView">
|
||||||
|
<child type="top">
|
||||||
|
<object class="AdwHeaderBar">
|
||||||
|
<property name="show-start-title-buttons">False</property>
|
||||||
|
<property name="show-end-title-buttons">False</property>
|
||||||
|
<child type="start">
|
||||||
|
<object class="GtkButton" id="cancel_button">
|
||||||
|
<property name="label" translatable="yes">_Cancel</property>
|
||||||
|
<property name="use-underline">True</property>
|
||||||
|
<property name="valign">center</property>
|
||||||
|
<property name="action-name">window.close</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child type="end">
|
||||||
|
<object class="GtkButton" id="add_button">
|
||||||
|
<property name="label" translatable="yes">_Add</property>
|
||||||
|
<property name="use-underline">True</property>
|
||||||
|
<property name="valign">center</property>
|
||||||
|
<signal name="clicked" handler="on_add_button_clicked_cb" object="CcGlobalShortcutDialog" swapped="yes" />
|
||||||
|
<style>
|
||||||
|
<class name="suggested-action"/>
|
||||||
|
</style>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<property name="content">
|
||||||
|
<object class="AdwPreferencesPage" id="shortcut_list">
|
||||||
|
<property name="description" translatable="yes">Added keyboard shortcuts will be available globally, and can be changed in the application’s panel in Settings</property>
|
||||||
|
<property name="description-centered">True</property>
|
||||||
|
</object>
|
||||||
|
</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</template>
|
||||||
|
<object class="GtkSizeGroup" id="accelerator_size_group"/>
|
||||||
|
</interface>
|
190
global-shortcuts-provider/cc-global-shortcuts-provider.c
Normal file
190
global-shortcuts-provider/cc-global-shortcuts-provider.c
Normal file
|
@ -0,0 +1,190 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2012 Giovanni Campagna <scampa.giovanni@gmail.com>
|
||||||
|
* Copyright © 2024 GNOME Foundation Inc.
|
||||||
|
*
|
||||||
|
* The Control Center is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by the
|
||||||
|
* Free Software Foundation; either version 2 of the License, or (at your
|
||||||
|
* option) any later version.
|
||||||
|
*
|
||||||
|
* The Control Center is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with the Control Center; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*
|
||||||
|
* Contributor: Dorota Czaplejewicz
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <config.h>
|
||||||
|
|
||||||
|
#include <gio/gdesktopappinfo.h>
|
||||||
|
#include <gio/gio.h>
|
||||||
|
#include <glib/gi18n.h>
|
||||||
|
#include <gtk/gtk.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "cc-keyboard-manager.h"
|
||||||
|
|
||||||
|
#include <shell/cc-panel-loader.h>
|
||||||
|
#include <shell/cc-panel.h>
|
||||||
|
#include <shell/cc-shell-model.h>
|
||||||
|
|
||||||
|
#include "cc-global-shortcut-dialog.h"
|
||||||
|
#include "cc-global-shortcuts-provider.h"
|
||||||
|
#include "cc-util.h"
|
||||||
|
#include "control-center-global-shortcuts-provider.h"
|
||||||
|
|
||||||
|
struct _CcGlobalShortcutsProvider
|
||||||
|
{
|
||||||
|
GObject parent;
|
||||||
|
|
||||||
|
CcSettingsGlobalShortcutsProvider *skeleton;
|
||||||
|
|
||||||
|
GtkApplication *app;
|
||||||
|
|
||||||
|
GHashTable *dialogs;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
MATCH_NONE,
|
||||||
|
MATCH_PREFIX,
|
||||||
|
MATCH_SUBSTRING
|
||||||
|
} PanelSearchMatch;
|
||||||
|
|
||||||
|
G_DEFINE_TYPE (CcGlobalShortcutsProvider,
|
||||||
|
cc_global_shortcuts_provider,
|
||||||
|
G_TYPE_OBJECT)
|
||||||
|
|
||||||
|
static void
|
||||||
|
handle_dialog_done (CcGlobalShortcutsProvider *self,
|
||||||
|
CcGlobalShortcutDialog *shortcut_dialog,
|
||||||
|
GVariant *response)
|
||||||
|
{
|
||||||
|
GDBusMethodInvocation *invocation;
|
||||||
|
|
||||||
|
invocation = g_hash_table_lookup (self->dialogs, shortcut_dialog);
|
||||||
|
|
||||||
|
if (response)
|
||||||
|
{
|
||||||
|
cc_settings_global_shortcuts_provider_complete_bind_shortcuts (self->skeleton,
|
||||||
|
invocation,
|
||||||
|
g_variant_ref_sink (response));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
g_dbus_method_invocation_return_error (invocation,
|
||||||
|
G_DBUS_ERROR,
|
||||||
|
G_DBUS_ERROR_ACCESS_DENIED,
|
||||||
|
"Access denied");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
on_dialog_done (CcGlobalShortcutDialog *shortcut_dialog,
|
||||||
|
GVariant *response,
|
||||||
|
CcGlobalShortcutsProvider *self)
|
||||||
|
{
|
||||||
|
handle_dialog_done (self, shortcut_dialog, response);
|
||||||
|
g_hash_table_remove (self->dialogs, shortcut_dialog);
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
handle_bind_shortcuts (CcGlobalShortcutsProvider *self,
|
||||||
|
GDBusMethodInvocation *invocation,
|
||||||
|
const char *app_id,
|
||||||
|
const char *parent_window,
|
||||||
|
GVariant *shortcuts)
|
||||||
|
{
|
||||||
|
g_autoptr(CcGlobalShortcutDialog) shortcut_dialog = NULL;
|
||||||
|
|
||||||
|
shortcut_dialog =
|
||||||
|
cc_global_shortcut_dialog_new (app_id,
|
||||||
|
parent_window,
|
||||||
|
shortcuts);
|
||||||
|
|
||||||
|
g_signal_connect (shortcut_dialog, "done",
|
||||||
|
G_CALLBACK (on_dialog_done),
|
||||||
|
self);
|
||||||
|
|
||||||
|
gtk_application_add_window (self->app, GTK_WINDOW (shortcut_dialog));
|
||||||
|
|
||||||
|
g_hash_table_insert (self->dialogs,
|
||||||
|
g_object_ref (shortcut_dialog),
|
||||||
|
g_object_ref (invocation));
|
||||||
|
|
||||||
|
cc_global_shortcut_dialog_present (shortcut_dialog);
|
||||||
|
|
||||||
|
return G_DBUS_METHOD_INVOCATION_HANDLED;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
cc_global_shortcuts_provider_init (CcGlobalShortcutsProvider *self)
|
||||||
|
{
|
||||||
|
self->dialogs = g_hash_table_new_full (NULL, NULL,
|
||||||
|
(GDestroyNotify) gtk_window_destroy,
|
||||||
|
(GDestroyNotify) g_object_unref);
|
||||||
|
self->skeleton = cc_settings_global_shortcuts_provider_skeleton_new ();
|
||||||
|
|
||||||
|
g_signal_connect_swapped (self->skeleton, "handle-bind-shortcuts",
|
||||||
|
G_CALLBACK (handle_bind_shortcuts), self);
|
||||||
|
}
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
cc_global_shortcuts_provider_dbus_register (CcGlobalShortcutsProvider *self,
|
||||||
|
GDBusConnection *connection,
|
||||||
|
const char *object_path,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
GDBusInterfaceSkeleton *skeleton =
|
||||||
|
G_DBUS_INTERFACE_SKELETON (self->skeleton);
|
||||||
|
|
||||||
|
return g_dbus_interface_skeleton_export (skeleton, connection, object_path, error);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
cc_global_shortcuts_provider_dbus_unregister (CcGlobalShortcutsProvider *self,
|
||||||
|
GDBusConnection *connection,
|
||||||
|
const char *object_path)
|
||||||
|
{
|
||||||
|
GDBusInterfaceSkeleton *skeleton =
|
||||||
|
G_DBUS_INTERFACE_SKELETON (self->skeleton);
|
||||||
|
|
||||||
|
if (g_dbus_interface_skeleton_has_connection (skeleton, connection))
|
||||||
|
g_dbus_interface_skeleton_unexport_from_connection (skeleton, connection);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
cc_global_shortcuts_provider_dispose (GObject *object)
|
||||||
|
{
|
||||||
|
CcGlobalShortcutsProvider *self =
|
||||||
|
CC_GLOBAL_SHORTCUTS_PROVIDER (object);
|
||||||
|
|
||||||
|
g_clear_object (&self->skeleton);
|
||||||
|
g_clear_pointer (&self->dialogs, g_hash_table_unref);
|
||||||
|
|
||||||
|
G_OBJECT_CLASS (cc_global_shortcuts_provider_parent_class)->dispose (object);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
cc_global_shortcuts_provider_class_init (CcGlobalShortcutsProviderClass *klass)
|
||||||
|
{
|
||||||
|
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||||
|
|
||||||
|
object_class->dispose = cc_global_shortcuts_provider_dispose;
|
||||||
|
}
|
||||||
|
|
||||||
|
CcGlobalShortcutsProvider *
|
||||||
|
cc_global_shortcuts_provider_new (GtkApplication *app)
|
||||||
|
{
|
||||||
|
CcGlobalShortcutsProvider *self;
|
||||||
|
|
||||||
|
self = g_object_new (CC_TYPE_GLOBAL_SHORTCUTS_PROVIDER, NULL);
|
||||||
|
self->app = app;
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
46
global-shortcuts-provider/cc-global-shortcuts-provider.h
Normal file
46
global-shortcuts-provider/cc-global-shortcuts-provider.h
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2012 Giovanni Campagna <scampa.giovanni@gmail.com>
|
||||||
|
*
|
||||||
|
* The Control Center is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by the
|
||||||
|
* Free Software Foundation; either version 2 of the License, or (at your
|
||||||
|
* option) any later version.
|
||||||
|
*
|
||||||
|
* The Control Center is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with the Control Center; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <gio/gio.h>
|
||||||
|
#include <glib-object.h>
|
||||||
|
#include <shell/cc-shell-model.h>
|
||||||
|
|
||||||
|
#include "cc-global-shortcuts-provider-generated.h"
|
||||||
|
|
||||||
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
|
#define CC_TYPE_GLOBAL_SHORTCUTS_PROVIDER (cc_global_shortcuts_provider_get_type ())
|
||||||
|
G_DECLARE_FINAL_TYPE (CcGlobalShortcutsProvider,
|
||||||
|
cc_global_shortcuts_provider,
|
||||||
|
CC, GLOBAL_SHORTCUTS_PROVIDER,
|
||||||
|
GObject)
|
||||||
|
|
||||||
|
CcGlobalShortcutsProvider *cc_global_shortcuts_provider_new (GtkApplication *app);
|
||||||
|
|
||||||
|
gboolean cc_global_shortcuts_provider_dbus_register (CcGlobalShortcutsProvider *provider,
|
||||||
|
GDBusConnection *connection,
|
||||||
|
const char *object_path,
|
||||||
|
GError **error);
|
||||||
|
void cc_global_shortcuts_provider_dbus_unregister (CcGlobalShortcutsProvider *provider,
|
||||||
|
GDBusConnection *connection,
|
||||||
|
const char *object_path);
|
||||||
|
|
||||||
|
G_END_DECLS
|
|
@ -0,0 +1,163 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2012 Giovanni Campagna <scampa.giovanni@gmail.com>
|
||||||
|
*
|
||||||
|
* The Control Center is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by the
|
||||||
|
* Free Software Foundation; either version 2 of the License, or (at your
|
||||||
|
* option) any later version.
|
||||||
|
*
|
||||||
|
* The Control Center is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with the Control Center; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#include <gio/gio.h>
|
||||||
|
#include <glib/gi18n.h>
|
||||||
|
#include <gxdp.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "control-center-global-shortcuts-provider.h"
|
||||||
|
#include <shell/cc-panel-loader.h>
|
||||||
|
#include <shell/cc-shell-model.h>
|
||||||
|
|
||||||
|
struct _CcGlobalShortcutsProviderApp
|
||||||
|
{
|
||||||
|
AdwApplication parent;
|
||||||
|
|
||||||
|
CcGlobalShortcutsProvider *global_shortcuts_provider;
|
||||||
|
};
|
||||||
|
|
||||||
|
G_DEFINE_TYPE (CcGlobalShortcutsProviderApp,
|
||||||
|
cc_global_shortcuts_provider_app,
|
||||||
|
ADW_TYPE_APPLICATION)
|
||||||
|
|
||||||
|
#define INACTIVITY_TIMEOUT 60 * 1000 /* One minute, in millisends */
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
cc_global_shortcuts_provider_app_dbus_register (GApplication *application,
|
||||||
|
GDBusConnection *connection,
|
||||||
|
const char *object_path,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
CcGlobalShortcutsProviderApp *self =
|
||||||
|
CC_GLOBAL_SHORTCUTS_PROVIDER_APP (application);
|
||||||
|
GApplicationClass *parent_class =
|
||||||
|
G_APPLICATION_CLASS (cc_global_shortcuts_provider_app_parent_class);
|
||||||
|
|
||||||
|
if (!parent_class->dbus_register (application,
|
||||||
|
connection,
|
||||||
|
object_path,
|
||||||
|
error))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
|
||||||
|
return cc_global_shortcuts_provider_dbus_register (self->global_shortcuts_provider,
|
||||||
|
connection,
|
||||||
|
object_path, error);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
cc_global_shortcuts_provider_app_dbus_unregister (GApplication *application,
|
||||||
|
GDBusConnection *connection,
|
||||||
|
const char *object_path)
|
||||||
|
{
|
||||||
|
CcGlobalShortcutsProviderApp *self =
|
||||||
|
CC_GLOBAL_SHORTCUTS_PROVIDER_APP (application);
|
||||||
|
GApplicationClass *parent_class =
|
||||||
|
G_APPLICATION_CLASS (cc_global_shortcuts_provider_app_parent_class);
|
||||||
|
|
||||||
|
if (self->global_shortcuts_provider)
|
||||||
|
{
|
||||||
|
cc_global_shortcuts_provider_dbus_unregister (self->global_shortcuts_provider,
|
||||||
|
connection,
|
||||||
|
object_path);
|
||||||
|
}
|
||||||
|
|
||||||
|
parent_class->dbus_unregister (application, connection, object_path);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
cc_global_shortcuts_provider_app_dispose (GObject *object)
|
||||||
|
{
|
||||||
|
CcGlobalShortcutsProviderApp *self =
|
||||||
|
CC_GLOBAL_SHORTCUTS_PROVIDER_APP (object);
|
||||||
|
|
||||||
|
g_clear_object (&self->global_shortcuts_provider);
|
||||||
|
|
||||||
|
G_OBJECT_CLASS (cc_global_shortcuts_provider_app_parent_class)->dispose (object);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
cc_global_shortcuts_provider_app_init (CcGlobalShortcutsProviderApp *self)
|
||||||
|
{
|
||||||
|
self->global_shortcuts_provider =
|
||||||
|
cc_global_shortcuts_provider_new (GTK_APPLICATION (self));
|
||||||
|
|
||||||
|
g_application_set_inactivity_timeout (G_APPLICATION (self),
|
||||||
|
INACTIVITY_TIMEOUT);
|
||||||
|
|
||||||
|
/* HACK: get the updated inactivity timeout started */
|
||||||
|
g_application_hold (G_APPLICATION (self));
|
||||||
|
g_application_release (G_APPLICATION (self));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
cc_global_shortcuts_provider_app_startup (GApplication *application)
|
||||||
|
{
|
||||||
|
G_APPLICATION_CLASS (cc_global_shortcuts_provider_app_parent_class)->startup (application);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
cc_global_shortcuts_provider_app_class_init (CcGlobalShortcutsProviderAppClass *klass)
|
||||||
|
{
|
||||||
|
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||||
|
GApplicationClass *app_class = G_APPLICATION_CLASS (klass);
|
||||||
|
|
||||||
|
object_class->dispose = cc_global_shortcuts_provider_app_dispose;
|
||||||
|
|
||||||
|
app_class->dbus_register = cc_global_shortcuts_provider_app_dbus_register;
|
||||||
|
app_class->dbus_unregister = cc_global_shortcuts_provider_app_dbus_unregister;
|
||||||
|
app_class->startup = cc_global_shortcuts_provider_app_startup;
|
||||||
|
}
|
||||||
|
|
||||||
|
CcGlobalShortcutsProviderApp *
|
||||||
|
cc_global_shortcuts_provider_app_get ()
|
||||||
|
{
|
||||||
|
static CcGlobalShortcutsProviderApp *singleton;
|
||||||
|
|
||||||
|
if (singleton)
|
||||||
|
return singleton;
|
||||||
|
|
||||||
|
singleton = g_object_new (CC_TYPE_GLOBAL_SHORTCUTS_PROVIDER_APP,
|
||||||
|
"application-id", "org.gnome.Settings.GlobalShortcutsProvider",
|
||||||
|
"flags", G_APPLICATION_IS_SERVICE,
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
return singleton;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main (int argc, char **argv)
|
||||||
|
{
|
||||||
|
GApplication *app;
|
||||||
|
g_autoptr (GError) error = NULL;
|
||||||
|
|
||||||
|
if (!gxdp_init_gtk (GXDP_SERVICE_CLIENT_TYPE_GLOBAL_SHORTCUTS,
|
||||||
|
&error))
|
||||||
|
{
|
||||||
|
g_warning ("Failed to initialize windowing system connection: %s",
|
||||||
|
error->message);
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
app = G_APPLICATION (cc_global_shortcuts_provider_app_get ());
|
||||||
|
return g_application_run (app, argc, argv);
|
||||||
|
}
|
|
@ -0,0 +1,37 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2012 Giovanni Campagna <scampa.giovanni@gmail.com>
|
||||||
|
*
|
||||||
|
* The Control Center is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by the
|
||||||
|
* Free Software Foundation; either version 2 of the License, or (at your
|
||||||
|
* option) any later version.
|
||||||
|
*
|
||||||
|
* The Control Center is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with the Control Center; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <gtk/gtk.h>
|
||||||
|
|
||||||
|
#include "cc-global-shortcuts-provider.h"
|
||||||
|
#include <shell/cc-shell-model.h>
|
||||||
|
|
||||||
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
|
#define CC_TYPE_GLOBAL_SHORTCUTS_PROVIDER_APP cc_global_shortcuts_provider_app_get_type ()
|
||||||
|
G_DECLARE_FINAL_TYPE (CcGlobalShortcutsProviderApp,
|
||||||
|
cc_global_shortcuts_provider_app,
|
||||||
|
CC, GLOBAL_SHORTCUTS_PROVIDER_APP,
|
||||||
|
AdwApplication)
|
||||||
|
|
||||||
|
CcGlobalShortcutsProviderApp *cc_global_shortcuts_provider_app_get (void);
|
||||||
|
|
||||||
|
G_END_DECLS
|
|
@ -0,0 +1,6 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<gresources>
|
||||||
|
<gresource prefix="/org/gnome/control-center/global-shortcuts-provider">
|
||||||
|
<file preprocess="xml-stripblanks">cc-global-shortcut-dialog.ui</file>
|
||||||
|
</gresource>
|
||||||
|
</gresources>
|
48
global-shortcuts-provider/meson.build
Normal file
48
global-shortcuts-provider/meson.build
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
service_conf = configuration_data()
|
||||||
|
service_conf.set('libexecdir', control_center_libexecdir)
|
||||||
|
|
||||||
|
service = 'org.gnome.Settings.GlobalShortcutsProvider.service'
|
||||||
|
|
||||||
|
configure_file(
|
||||||
|
input: service + '.in',
|
||||||
|
output: service,
|
||||||
|
install: true,
|
||||||
|
install_dir: join_paths(control_center_datadir, 'dbus-1', 'services'),
|
||||||
|
configuration: service_conf
|
||||||
|
)
|
||||||
|
|
||||||
|
sources = files(
|
||||||
|
'cc-global-shortcut-dialog.c',
|
||||||
|
'cc-global-shortcuts-provider.c',
|
||||||
|
'control-center-global-shortcuts-provider.c'
|
||||||
|
)
|
||||||
|
|
||||||
|
global_shortcuts_resources = gnome.compile_resources(
|
||||||
|
'cc-global-shortcuts-provider-resources',
|
||||||
|
'global-shortcuts-provider.gresource.xml',
|
||||||
|
c_name: 'cc_global_shortcut_provider',
|
||||||
|
export: true
|
||||||
|
)
|
||||||
|
|
||||||
|
sources += global_shortcuts_resources
|
||||||
|
|
||||||
|
sources += gnome.gdbus_codegen(
|
||||||
|
'cc-global-shortcuts-provider-generated',
|
||||||
|
'org.gnome.GlobalShortcutsProvider.xml',
|
||||||
|
interface_prefix: 'org.gnome.',
|
||||||
|
namespace: 'Cc'
|
||||||
|
)
|
||||||
|
|
||||||
|
executable(
|
||||||
|
'gnome-control-center-global-shortcuts-provider',
|
||||||
|
sources,
|
||||||
|
include_directories: [top_inc],
|
||||||
|
dependencies: [
|
||||||
|
shell_deps,
|
||||||
|
keyboard_panel_dep,
|
||||||
|
dependency('libgxdp'),
|
||||||
|
],
|
||||||
|
c_args: cflags,
|
||||||
|
install: true,
|
||||||
|
install_dir: control_center_libexecdir
|
||||||
|
)
|
|
@ -0,0 +1,54 @@
|
||||||
|
<!DOCTYPE node PUBLIC
|
||||||
|
'-//freedesktop//DTD D-BUS Object Introspection 1.0//EN'
|
||||||
|
'http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd'>
|
||||||
|
<node>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
org.gnome.Settings.GlobalShortcutsProvider:
|
||||||
|
@short_description: Global shortcuts portal permissions UI
|
||||||
|
|
||||||
|
Provides a UI for the GlobalShortcuts portal, stores preferences, and
|
||||||
|
notifies the compositor of changes.
|
||||||
|
-->
|
||||||
|
<interface name="org.gnome.Settings.GlobalShortcutsProvider">
|
||||||
|
<!--
|
||||||
|
BindShortcuts:
|
||||||
|
@app_id: Application ID
|
||||||
|
@parent_window: Parent window handle
|
||||||
|
@shortcuts: Shortcuts to bind
|
||||||
|
|
||||||
|
Presents a shortcuts dialog to the user, stores the preference,
|
||||||
|
and notifies about changes.
|
||||||
|
|
||||||
|
The @shortcuts array is made of tuples composed of a shortcut id, and
|
||||||
|
a vardict with the following keys:
|
||||||
|
|
||||||
|
* ``description`` (``s``)
|
||||||
|
|
||||||
|
User-readable text describing what the shortcut does. Optional.
|
||||||
|
|
||||||
|
* ``preferred_trigger``` (``s`` or ``as``)
|
||||||
|
|
||||||
|
An optional preferred shortcut, or a list of strings specifying the
|
||||||
|
shortcuts, for example: ``['<alt>C', '<ctrl>Q']``
|
||||||
|
|
||||||
|
The @results array is made of tuples composed of a shortcut id, and
|
||||||
|
a vardict with the following keys:
|
||||||
|
|
||||||
|
* ``description`` (``s``)
|
||||||
|
|
||||||
|
User-readable text describing what the shortcut does. Optional.
|
||||||
|
|
||||||
|
* ``shortcut`` (``as``)
|
||||||
|
|
||||||
|
A list of shortcuts to bind to the associated shortcut id, for
|
||||||
|
example: ``['<alt>C', '<ctrl>Q']``
|
||||||
|
-->
|
||||||
|
<method name="BindShortcuts">
|
||||||
|
<arg type="s" name="app_id" direction="in"/>
|
||||||
|
<arg type="s" name="parent_window" direction="in"/>
|
||||||
|
<arg type="a(sa{sv})" name="shortcuts" direction="in"/>
|
||||||
|
<arg type="a(sa{sv})" name="results" direction="out"/>
|
||||||
|
</method>
|
||||||
|
</interface>
|
||||||
|
</node>
|
|
@ -0,0 +1,3 @@
|
||||||
|
[D-BUS Service]
|
||||||
|
Name=org.gnome.Settings.GlobalShortcutsProvider
|
||||||
|
Exec=@libexecdir@/gnome-control-center-global-shortcuts-provider
|
59
gnome-control-center.doap
Normal file
59
gnome-control-center.doap
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
<Project xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#"
|
||||||
|
xmlns:foaf="http://xmlns.com/foaf/0.1/"
|
||||||
|
xmlns:gnome="http://api.gnome.org/doap-extensions#"
|
||||||
|
xmlns="http://usefulinc.com/ns/doap#">
|
||||||
|
|
||||||
|
<name xml:lang="en">GNOME Settings</name>
|
||||||
|
<shortdesc xml:lang="en">GNOME's main interface to configure various aspects of the desktop</shortdesc>
|
||||||
|
<description xml:lang="en">GNOME's main interface to configure various aspects of the desktop</description>
|
||||||
|
<support-forum rdf:resource="https://discourse.gnome.org/c/desktop/" />
|
||||||
|
<download-page rdf:resource="https://download.gnome.org/sources/gnome-control-center/" />
|
||||||
|
<bug-database rdf:resource="https://gitlab.gnome.org/GNOME/gnome-control-center/issues" />
|
||||||
|
<category rdf:resource="http://api.gnome.org/doap-extensions#core" />
|
||||||
|
<programming-language>C</programming-language>
|
||||||
|
|
||||||
|
<!-- General -->
|
||||||
|
<maintainer>
|
||||||
|
<foaf:Person>
|
||||||
|
<foaf:name>Felipe Borges</foaf:name>
|
||||||
|
<foaf:mbox rdf:resource="mailto:felipeborges@gnome.org" />
|
||||||
|
<gnome:userid>felipeborges</gnome:userid>
|
||||||
|
</foaf:Person>
|
||||||
|
</maintainer>
|
||||||
|
|
||||||
|
<maintainer>
|
||||||
|
<foaf:Person>
|
||||||
|
<foaf:name>Matthijs Velsink</foaf:name>
|
||||||
|
<foaf:mbox rdf:resource="mailto:mvelsink@gnome.org" />
|
||||||
|
<gnome:userid>mvelsink</gnome:userid>
|
||||||
|
</foaf:Person>
|
||||||
|
</maintainer>
|
||||||
|
|
||||||
|
<!-- Bluetooth -->
|
||||||
|
<maintainer>
|
||||||
|
<foaf:Person>
|
||||||
|
<foaf:name>Bastien Nocera</foaf:name>
|
||||||
|
<foaf:mbox rdf:resource="mailto:hadess@gnome.org" />
|
||||||
|
<gnome:userid>hadess</gnome:userid>
|
||||||
|
</foaf:Person>
|
||||||
|
</maintainer>
|
||||||
|
|
||||||
|
<!-- Printers -->
|
||||||
|
<maintainer>
|
||||||
|
<foaf:Person>
|
||||||
|
<foaf:name>Marek Kašík</foaf:name>
|
||||||
|
<foaf:mbox rdf:resource="mailto:mkasik@redhat.com" />
|
||||||
|
<gnome:userid>mkasik</gnome:userid>
|
||||||
|
</foaf:Person>
|
||||||
|
</maintainer>
|
||||||
|
|
||||||
|
<!-- Wacom -->
|
||||||
|
<maintainer>
|
||||||
|
<foaf:Person>
|
||||||
|
<foaf:name>Carlos Garnacho</foaf:name>
|
||||||
|
<foaf:mbox rdf:resource="mailto:carlosg@gnome.org" />
|
||||||
|
<gnome:userid>carlosg</gnome:userid>
|
||||||
|
</foaf:Person>
|
||||||
|
</maintainer>
|
||||||
|
</Project>
|
361
man/gnome-control-center.xml
Normal file
361
man/gnome-control-center.xml
Normal file
|
@ -0,0 +1,361 @@
|
||||||
|
<?xml version='1.0'?>
|
||||||
|
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
|
||||||
|
"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
|
||||||
|
|
||||||
|
<refentry id="gnome-control-center">
|
||||||
|
|
||||||
|
<refentryinfo>
|
||||||
|
<title>gnome-control-center</title>
|
||||||
|
<productname>GNOME</productname>
|
||||||
|
|
||||||
|
<authorgroup>
|
||||||
|
<author>
|
||||||
|
<contrib>Maintainer</contrib>
|
||||||
|
<firstname>Bastien</firstname>
|
||||||
|
<surname>Nocera</surname>
|
||||||
|
<email>hadess@hadess.net</email>
|
||||||
|
</author>
|
||||||
|
</authorgroup>
|
||||||
|
|
||||||
|
</refentryinfo>
|
||||||
|
|
||||||
|
<refmeta>
|
||||||
|
<refentrytitle>gnome-control-center</refentrytitle>
|
||||||
|
<manvolnum>1</manvolnum>
|
||||||
|
<refmiscinfo class="manual">User Commands</refmiscinfo>
|
||||||
|
</refmeta>
|
||||||
|
|
||||||
|
<refnamediv>
|
||||||
|
<refname>gnome-control-center</refname>
|
||||||
|
<refpurpose>Configure GNOME settings</refpurpose>
|
||||||
|
</refnamediv>
|
||||||
|
|
||||||
|
<refsynopsisdiv>
|
||||||
|
<cmdsynopsis>
|
||||||
|
<command>gnome-control-center <arg choice="opt" rep="repeat">OPTION</arg> <arg choice="opt">PANEL</arg> <arg choice="opt" rep="repeat">ARG</arg></command>
|
||||||
|
</cmdsynopsis>
|
||||||
|
</refsynopsisdiv>
|
||||||
|
|
||||||
|
<refsect1>
|
||||||
|
<title>Description</title>
|
||||||
|
|
||||||
|
<para><command>gnome-control-center</command> is a graphical
|
||||||
|
user interface to configure various aspects of GNOME.</para>
|
||||||
|
|
||||||
|
<para>When run without arguments, the shell displays the
|
||||||
|
<firstterm>overview</firstterm>, which shows all available
|
||||||
|
configuration panels. The overview allows to open individual
|
||||||
|
panels by clicking on them. It also has a search entry
|
||||||
|
to find panels by searching keywords.</para>
|
||||||
|
|
||||||
|
<para>It is also possible to specify a panel name
|
||||||
|
as commandline argument to go directly to that panel.
|
||||||
|
Individual panels may accept further arguments to specify
|
||||||
|
which tab to open (for multi-tabbed panels) or which
|
||||||
|
item to display (for panels with lists).</para>
|
||||||
|
|
||||||
|
<para>Note that <command>gnome-control-center</command>
|
||||||
|
is not meant to expose each and every setting that is
|
||||||
|
available. The settings that can be found here represent
|
||||||
|
what is considered useful and commonly needed options.
|
||||||
|
For more exotic or uncommon options, you can look at
|
||||||
|
<command>gnome-tweak-tool</command> or the
|
||||||
|
<command>gsettings</command> commandline utility.</para>
|
||||||
|
</refsect1>
|
||||||
|
|
||||||
|
<refsect1>
|
||||||
|
<title>Panels</title>
|
||||||
|
|
||||||
|
<para>The following panel names can be specified:</para>
|
||||||
|
|
||||||
|
<variablelist>
|
||||||
|
<varlistentry>
|
||||||
|
<term><option>background</option></term>
|
||||||
|
|
||||||
|
<listitem><para>The background panel lets you
|
||||||
|
set your desktop background.</para></listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term><option>bluetooth</option></term>
|
||||||
|
|
||||||
|
<listitem><para>The bluetooth panel lets you
|
||||||
|
configure your computer's Bluetooth adapter,
|
||||||
|
and pair the computer with Bluetooth keyboards,
|
||||||
|
phones, etc.</para></listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term><option>color</option></term>
|
||||||
|
|
||||||
|
<listitem><para>The color panel can calibrate
|
||||||
|
monitors, web cams and printers for accurate
|
||||||
|
color reproduction.</para></listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term><option>datetime</option></term>
|
||||||
|
|
||||||
|
<listitem><para>The datetime panel lets you
|
||||||
|
set the timezone and time format.</para>
|
||||||
|
<para>Some operations in this panel
|
||||||
|
affect all user accounts on the computer
|
||||||
|
and require privieges.</para></listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term><option>display</option></term>
|
||||||
|
|
||||||
|
<listitem><para>The display panel configures
|
||||||
|
the resolution and arrangement of monitors
|
||||||
|
and laptop panels. Note that monitors can be
|
||||||
|
rearranged by drag-and-drop, and you can change
|
||||||
|
which monitor is your main display by dragging
|
||||||
|
the black bar.</para></listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term><option>info-overview</option></term>
|
||||||
|
|
||||||
|
<listitem><para>The info-overview panel shows a general
|
||||||
|
overview of the system configuration. It also
|
||||||
|
lets you change the default applications for
|
||||||
|
various tasks and the handling of removable
|
||||||
|
media.</para></listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term><option>keyboard</option></term>
|
||||||
|
|
||||||
|
<listitem><para>The keyboard panel can
|
||||||
|
change how the keyboard reacts to key
|
||||||
|
presses and lets you change keyboard
|
||||||
|
shortcuts or create custom shortcuts.</para>
|
||||||
|
<para>You can open this panel on a
|
||||||
|
specific tab by passing <option>typing</option>
|
||||||
|
or <option>shortcuts</option> as extra
|
||||||
|
argument.</para></listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term><option>mouse</option></term>
|
||||||
|
|
||||||
|
<listitem><para>The mouse panel can change
|
||||||
|
how mice and touchpads react to user
|
||||||
|
input.</para></listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term><option>network</option></term>
|
||||||
|
|
||||||
|
<listitem><para>The network panel provides
|
||||||
|
a view of available network devices (wired,
|
||||||
|
wireless or mobile) and their current
|
||||||
|
configuration. It also provides a way to
|
||||||
|
create new VPN connections and configure
|
||||||
|
proxy settings.</para>
|
||||||
|
<para>You can open this panel on a
|
||||||
|
specific dialog by passing
|
||||||
|
<option>create-wifi</option>,
|
||||||
|
<option>connect-hidden-wifi</option>,
|
||||||
|
<option>connect-3g</option>,
|
||||||
|
<option>connect-8021x-wifi</option> or
|
||||||
|
<option>show-device</option> as extra
|
||||||
|
argument. The last three parameters
|
||||||
|
require an additional extra argument for
|
||||||
|
the network object in the form
|
||||||
|
<replaceable>/org/freedesktop/NetworkManager/Devices/0</replaceable>.
|
||||||
|
</para></listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term><option>notifications</option></term>
|
||||||
|
|
||||||
|
<listitem><para>The notifications panel provides
|
||||||
|
a way to control the display of notifications.
|
||||||
|
</para></listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term><option>online-accounts</option></term>
|
||||||
|
|
||||||
|
<listitem><para>The online-accounts panel
|
||||||
|
shows your configured online accounts and
|
||||||
|
lets you add or remove accounts.</para></listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term><option>power</option></term>
|
||||||
|
|
||||||
|
<listitem><para>The power panel shows
|
||||||
|
the fill level of batteries and can
|
||||||
|
configure what happens when the computer
|
||||||
|
is idle or runs out of battery.</para></listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term><option>printers</option></term>
|
||||||
|
|
||||||
|
<listitem><para>The printers panel shows
|
||||||
|
all known printers and their status. It is
|
||||||
|
possible to inspect queued print jobs and
|
||||||
|
add new printers.</para>
|
||||||
|
<para>Some operations in this panel require
|
||||||
|
privileges.</para></listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term><option>privacy</option></term>
|
||||||
|
|
||||||
|
<listitem><para>The privacy panel allows
|
||||||
|
to control visible file usage history, temporary
|
||||||
|
files, and name.
|
||||||
|
</para></listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term><option>region</option></term>
|
||||||
|
|
||||||
|
<listitem><para>The region panel
|
||||||
|
contains regional settings such as
|
||||||
|
the display language, formatting for
|
||||||
|
times, dates, numbers, and input sources.
|
||||||
|
</para></listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term><option>search</option></term>
|
||||||
|
|
||||||
|
<listitem><para>The search panel controls
|
||||||
|
the results visible in the overview, and the
|
||||||
|
files and folders to be indexed.
|
||||||
|
</para></listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term><option>screen</option></term>
|
||||||
|
|
||||||
|
<listitem><para>The screen panel contains
|
||||||
|
settings that control the screen brightness
|
||||||
|
and screen lock behavior.</para></listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term><option>sharing</option></term>
|
||||||
|
|
||||||
|
<listitem><para>The sharing panel contains
|
||||||
|
settings that control what is shared over the
|
||||||
|
network.</para></listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term><option>sound</option></term>
|
||||||
|
|
||||||
|
<listitem><para>The sound panel shows
|
||||||
|
all known sound devices and their configuration,
|
||||||
|
including volume and balance settings.</para>
|
||||||
|
<para>You can open this panel on a
|
||||||
|
specific tab by passing
|
||||||
|
<option>output</option>,
|
||||||
|
<option>input</option>,
|
||||||
|
<option>hardware</option>,
|
||||||
|
<option>effects</option> or
|
||||||
|
<option>applications</option> as extra
|
||||||
|
argument.</para></listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term><option>universal-access</option></term>
|
||||||
|
|
||||||
|
<listitem><para>The universal-access panel
|
||||||
|
contains settings for accessible technologies
|
||||||
|
such as the screen reader, magnifier, screen
|
||||||
|
keyboard and AccessX options.</para></listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term><option>user-accounts</option></term>
|
||||||
|
|
||||||
|
<listitem><para>The user-accounts panel
|
||||||
|
shows all user accounts that exist on the
|
||||||
|
computer and allows to change them in some
|
||||||
|
ways, such as changing the user name, password
|
||||||
|
or permissions. It also allows to create
|
||||||
|
or remove accounts.</para>
|
||||||
|
<para>Some operations in this panel require
|
||||||
|
privileges.</para></listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term><option>wacom</option></term>
|
||||||
|
|
||||||
|
<listitem><para>the wacom panel shows
|
||||||
|
connected Wacom graphics tablets and lets
|
||||||
|
you calibrate and configure such devices.</para></listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
</variablelist>
|
||||||
|
|
||||||
|
</refsect1>
|
||||||
|
|
||||||
|
<refsect1>
|
||||||
|
<title>Options</title>
|
||||||
|
|
||||||
|
<variablelist>
|
||||||
|
<varlistentry>
|
||||||
|
<term><option>-?</option>, <option>--help</option></term>
|
||||||
|
|
||||||
|
<listitem><para>Prints a short help
|
||||||
|
text and exits.</para></listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term><option>--version</option></term>
|
||||||
|
|
||||||
|
<listitem><para>Prints the program version
|
||||||
|
and exits.</para></listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term><option>-v</option>, <option>--verbose</option></term>
|
||||||
|
|
||||||
|
<listitem><para>Enables verbose mode.</para></listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term><option>-l</option>, <option>--list</option></term>
|
||||||
|
|
||||||
|
<listitem><para>Lists the available panels
|
||||||
|
and exits.</para></listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term><option>-o</option>, <option>--overview</option></term>
|
||||||
|
|
||||||
|
<listitem><para>Opens the overview.</para></listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term><option>-s</option> <replaceable>term</replaceable>, <option>--search</option> <replaceable>term</replaceable></term>
|
||||||
|
|
||||||
|
<listitem><para>Sets the following search term.</para></listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
</variablelist>
|
||||||
|
</refsect1>
|
||||||
|
|
||||||
|
<refsect1>
|
||||||
|
<title>Exit status</title>
|
||||||
|
|
||||||
|
<para>On success 0 is returned, a non-zero failure
|
||||||
|
code otherwise.</para>
|
||||||
|
</refsect1>
|
||||||
|
|
||||||
|
<refsect1>
|
||||||
|
<title>See Also</title>
|
||||||
|
<para>
|
||||||
|
<citerefentry><refentrytitle>gsettings</refentrytitle><manvolnum>1</manvolnum></citerefentry>
|
||||||
|
</para>
|
||||||
|
</refsect1>
|
||||||
|
|
||||||
|
</refentry>
|
26
man/meson.build
Normal file
26
man/meson.build
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
xsltproc = find_program('xsltproc', required: false)
|
||||||
|
assert(xsltproc.found(), 'xsltproc is required to build documentation')
|
||||||
|
|
||||||
|
xsltproc_cmd = [
|
||||||
|
xsltproc,
|
||||||
|
'--output', '@OUTPUT@',
|
||||||
|
'--nonet',
|
||||||
|
'--stringparam', 'man.output.quietly', '1',
|
||||||
|
'--stringparam', 'funcsynopsis.style', 'ansi',
|
||||||
|
'--stringparam', 'man.th.extra1.suppress', '1',
|
||||||
|
'--stringparam', 'man.authors.section.enabled', '0',
|
||||||
|
'--stringparam', 'man.copyright.section.enabled', '0',
|
||||||
|
'http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl',
|
||||||
|
'@INPUT@'
|
||||||
|
]
|
||||||
|
|
||||||
|
output = meson.project_name() + '.1'
|
||||||
|
|
||||||
|
custom_target(
|
||||||
|
output,
|
||||||
|
input : meson.project_name() + '.xml',
|
||||||
|
output : output,
|
||||||
|
command : xsltproc_cmd,
|
||||||
|
install : true,
|
||||||
|
install_dir : join_paths(control_center_mandir, 'man1')
|
||||||
|
)
|
404
meson.build
Normal file
404
meson.build
Normal file
|
@ -0,0 +1,404 @@
|
||||||
|
project(
|
||||||
|
'gnome-control-center', 'c',
|
||||||
|
version : '48.2',
|
||||||
|
license : 'GPL2+',
|
||||||
|
meson_version : '>= 0.58.0'
|
||||||
|
)
|
||||||
|
|
||||||
|
control_center_prefix = get_option('prefix')
|
||||||
|
control_center_bindir = join_paths(control_center_prefix, get_option('bindir'))
|
||||||
|
control_center_datadir = join_paths(control_center_prefix, get_option('datadir'))
|
||||||
|
control_center_libexecdir = join_paths(control_center_prefix, get_option('libexecdir'))
|
||||||
|
control_center_localedir = join_paths(control_center_prefix, get_option('localedir'))
|
||||||
|
control_center_mandir = join_paths(control_center_prefix, get_option('mandir'))
|
||||||
|
control_center_sysconfdir = join_paths(control_center_prefix, get_option('sysconfdir'))
|
||||||
|
|
||||||
|
control_center_pkgdatadir = join_paths(control_center_datadir, meson.project_name())
|
||||||
|
control_center_desktopdir = join_paths(control_center_datadir, 'applications')
|
||||||
|
control_center_icondir = join_paths(control_center_datadir, 'icons')
|
||||||
|
control_center_schemadir = join_paths (control_center_datadir, 'glib-2.0', 'schemas')
|
||||||
|
|
||||||
|
control_center_gettext = meson.project_name() + '-2.0'
|
||||||
|
|
||||||
|
host_is_linux = host_machine.system().contains('linux')
|
||||||
|
host_is_linux_not_s390 = host_is_linux and not host_machine.cpu().contains('s390')
|
||||||
|
|
||||||
|
cc = meson.get_compiler('c')
|
||||||
|
|
||||||
|
config_h = configuration_data()
|
||||||
|
|
||||||
|
py = import('python')
|
||||||
|
python = py.find_installation('python3')
|
||||||
|
|
||||||
|
config_h.set_quoted('TEST_NM_PYTHON', python.full_path())
|
||||||
|
|
||||||
|
application_id = 'org.gnome.Settings'
|
||||||
|
|
||||||
|
if get_option('profile') == 'development'
|
||||||
|
application_id += '.' + 'Devel'
|
||||||
|
endif
|
||||||
|
|
||||||
|
version_split = meson.project_version().split('.')
|
||||||
|
|
||||||
|
# defines
|
||||||
|
set_defines = [
|
||||||
|
# package
|
||||||
|
['APPLICATION_ID', application_id],
|
||||||
|
['PACKAGE', meson.project_name()],
|
||||||
|
['PACKAGE_VERSION', meson.project_version()],
|
||||||
|
['VERSION', meson.project_version()],
|
||||||
|
['MAJOR_VERSION', version_split[0]],
|
||||||
|
['PROFILE', get_option('profile')],
|
||||||
|
# i18n
|
||||||
|
['GETTEXT_PACKAGE', control_center_gettext]
|
||||||
|
]
|
||||||
|
|
||||||
|
foreach define: set_defines
|
||||||
|
config_h.set_quoted(define[0], define[1])
|
||||||
|
endforeach
|
||||||
|
|
||||||
|
distributor_logo = get_option('distributor_logo')
|
||||||
|
if (distributor_logo != '')
|
||||||
|
config_h.set_quoted('DISTRIBUTOR_LOGO', distributor_logo,
|
||||||
|
description: 'Define to absolute path of distributor logo')
|
||||||
|
dark_mode_distributor_logo = get_option('dark_mode_distributor_logo')
|
||||||
|
if (dark_mode_distributor_logo != '')
|
||||||
|
config_h.set_quoted('DARK_MODE_DISTRIBUTOR_LOGO', dark_mode_distributor_logo,
|
||||||
|
description: 'Define to absolute path of distributor logo for use in dark mode')
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
# meson does not support octal values, so it must be handled as a
|
||||||
|
# string. See: https://github.com/mesonbuild/meson/issues/2047
|
||||||
|
config_h.set('USER_DIR_MODE', '0700',
|
||||||
|
description: 'Permissions for creating the user\'s config, cache and data directories')
|
||||||
|
|
||||||
|
# compiler flags
|
||||||
|
common_flags = ['-DHAVE_CONFIG_H']
|
||||||
|
|
||||||
|
# We have so many deprecation warnings that it becomes impossible to notice any other useful
|
||||||
|
# warning, thus making the compiler output completely useless. Ideally, we should fix all
|
||||||
|
# of those but, until then, it's better to add this flag so that we avoid adding even more
|
||||||
|
# warnings by accident. If you want to fix some of those, just build Settings with:
|
||||||
|
# meson _build -Ddeprecated-declarions=enabled
|
||||||
|
if get_option('deprecated-declarations').disabled()
|
||||||
|
common_flags += '-Wno-deprecated-declarations'
|
||||||
|
endif
|
||||||
|
|
||||||
|
# Only add this when optimizing is enabled (default)
|
||||||
|
optimized_src = '''
|
||||||
|
#if __OPTIMIZE__ == 0
|
||||||
|
#error No optimization
|
||||||
|
#endif
|
||||||
|
'''
|
||||||
|
|
||||||
|
control_center_optimized = get_option('buildtype').contains('optimized') and cc.compiles(optimized_src)
|
||||||
|
|
||||||
|
if control_center_optimized
|
||||||
|
common_flags += '-Wp,-D_FORTIFY_SOURCE=2'
|
||||||
|
endif
|
||||||
|
|
||||||
|
if get_option('buildtype').contains('debug')
|
||||||
|
test_cflags = [
|
||||||
|
'-Wcast-align',
|
||||||
|
'-Wmissing-field-initializers',
|
||||||
|
'-Wmissing-declarations',
|
||||||
|
'-Wmissing-prototypes',
|
||||||
|
'-Wnested-externs',
|
||||||
|
'-Wno-strict-aliasing',
|
||||||
|
'-Wno-sign-compare'
|
||||||
|
]
|
||||||
|
|
||||||
|
common_flags += cc.get_supported_arguments(test_cflags)
|
||||||
|
endif
|
||||||
|
|
||||||
|
add_project_arguments(common_flags, language: 'c')
|
||||||
|
|
||||||
|
# Check that we meet the dependencies
|
||||||
|
libgvc = subproject(
|
||||||
|
'gvc',
|
||||||
|
default_options: [
|
||||||
|
'static=true',
|
||||||
|
'alsa=false',
|
||||||
|
'package_name=' + control_center_gettext,
|
||||||
|
'package_version=' + meson.project_version(),
|
||||||
|
]
|
||||||
|
)
|
||||||
|
libgvc_dep = libgvc.get_variable('libgvc_dep')
|
||||||
|
|
||||||
|
libadwaita_version = '>= 1.7.alpha'
|
||||||
|
goa_req_version = '>= 3.51.0'
|
||||||
|
pulse_req_version = '>= 2.0'
|
||||||
|
|
||||||
|
gtk_dep = dependency(
|
||||||
|
'gtk4',
|
||||||
|
version: '>= 4.15.2',
|
||||||
|
fallback: 'gtk',
|
||||||
|
default_options: [
|
||||||
|
'introspection=disabled',
|
||||||
|
'build-demos=false',
|
||||||
|
'build-testsuite=false',
|
||||||
|
'build-tests=false',
|
||||||
|
'build-examples=false',
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
libadwaita_dep = dependency(
|
||||||
|
'libadwaita-1',
|
||||||
|
version: libadwaita_version,
|
||||||
|
required: false
|
||||||
|
)
|
||||||
|
# FIXME: this is a workaround because interactive-tests don't work with libadwaita as a subproject. See !1754
|
||||||
|
libadwaita_is_subproject = not libadwaita_dep.found()
|
||||||
|
if libadwaita_is_subproject
|
||||||
|
libadwaita_dep = dependency(
|
||||||
|
'libadwaita-1',
|
||||||
|
version: libadwaita_version,
|
||||||
|
fallback: 'libadwaita',
|
||||||
|
default_options: [
|
||||||
|
'examples=false',
|
||||||
|
'introspection=disabled',
|
||||||
|
'tests=false',
|
||||||
|
'vapi=false',
|
||||||
|
],
|
||||||
|
)
|
||||||
|
endif
|
||||||
|
|
||||||
|
tecla_dep = dependency(
|
||||||
|
'tecla',
|
||||||
|
version: '>=47.0',
|
||||||
|
required: false
|
||||||
|
)
|
||||||
|
|
||||||
|
# Needs to be a subproject since tecla does not declare dependencies
|
||||||
|
tecla_is_subproject = not tecla_dep.found()
|
||||||
|
if tecla_is_subproject
|
||||||
|
tecla = subproject(
|
||||||
|
'tecla'
|
||||||
|
)
|
||||||
|
endif
|
||||||
|
|
||||||
|
subproject('libgxdp',
|
||||||
|
default_options: 'tests=false',
|
||||||
|
)
|
||||||
|
|
||||||
|
accounts_dep = dependency('accountsservice', version: '>= 23.11.69')
|
||||||
|
colord_dep = dependency('colord', version: '>= 0.1.34')
|
||||||
|
gdk_pixbuf_dep = dependency('gdk-pixbuf-2.0', version: '>= 2.23.0')
|
||||||
|
gio_dep = dependency('gio-2.0')
|
||||||
|
glib_dep = dependency('glib-2.0', version: '>= 2.76.6')
|
||||||
|
gnome_desktop_dep = dependency('gnome-desktop-4')
|
||||||
|
gnome_bg_dep = dependency('gnome-bg-4')
|
||||||
|
gnome_rr_dep = dependency('gnome-rr-4')
|
||||||
|
gnome_settings_dep = dependency('gnome-settings-daemon', version: '>= 48.rc', fallback: 'gsd')
|
||||||
|
goa_dep = dependency('goa-1.0', version: goa_req_version, fallback: 'goa')
|
||||||
|
gsettings_desktop_dep = dependency('gsettings-desktop-schemas', version: '>= 48.alpha') # actually requires commit 9d55553, just after alpha
|
||||||
|
libxml_dep = dependency('libxml-2.0')
|
||||||
|
pulse_dep = dependency('libpulse', version: pulse_req_version)
|
||||||
|
pulse_mainloop_dep = dependency('libpulse-mainloop-glib', version: pulse_req_version)
|
||||||
|
upower_glib_dep = dependency('upower-glib', version: '>= 1.90.6')
|
||||||
|
gudev_dep = dependency('gudev-1.0', version: '>= 232')
|
||||||
|
x11_dep = dependency('x11', version: '>= 1.8')
|
||||||
|
xi_dep = dependency('xi', version: '>= 1.2')
|
||||||
|
epoxy_dep = dependency('epoxy')
|
||||||
|
gcr_dep = dependency('gcr-4', version: '>= 4.1.0')
|
||||||
|
pwquality_dep = dependency('pwquality', version: '>= 1.2.2')
|
||||||
|
|
||||||
|
m_dep = cc.find_library('m')
|
||||||
|
|
||||||
|
common_deps = [
|
||||||
|
gio_dep,
|
||||||
|
glib_dep,
|
||||||
|
gsettings_desktop_dep,
|
||||||
|
libadwaita_dep,
|
||||||
|
dependency('gio-unix-2.0'),
|
||||||
|
dependency('gthread-2.0'),
|
||||||
|
gtk_dep,
|
||||||
|
]
|
||||||
|
|
||||||
|
polkit_gobject_dep = dependency('polkit-gobject-1', version: '>= 0.103')
|
||||||
|
# Also verify that polkit ITS files exist:
|
||||||
|
# https://gitlab.gnome.org/GNOME/gnome-control-center/-/issues/491
|
||||||
|
polkit_files = [ 'gettext/its/polkit.its', 'gettext/its/polkit.loc' ]
|
||||||
|
foreach polkit_file: polkit_files
|
||||||
|
r = run_command('build-aux/meson/find_xdg_file.py', polkit_file, check: true)
|
||||||
|
assert(r.returncode() == 0, 'ITS support missing from polkit, please upgrade or contact your distribution')
|
||||||
|
endforeach
|
||||||
|
|
||||||
|
# Localisation API
|
||||||
|
if cc.has_header_symbol('langinfo.h', '_NL_TIME_FIRST_WEEKDAY')
|
||||||
|
config_h.set('HAVE__NL_TIME_FIRST_WEEKDAY', 1,
|
||||||
|
description: 'Define if langinfo.h supports _NL_TIME_FIRST_WEEKDAY')
|
||||||
|
endif
|
||||||
|
|
||||||
|
# Check for CUPS 1.4 or newer
|
||||||
|
cups_dep = dependency('cups', version : '>= 1.4', required: false)
|
||||||
|
assert(cups_dep.found(), 'CUPS 1.4 or newer not found')
|
||||||
|
|
||||||
|
# https://bugzilla.gnome.org/show_bug.cgi?id=696766
|
||||||
|
cups_cflags = []
|
||||||
|
if cups_dep.version().version_compare('>= 1.6')
|
||||||
|
cups_cflags += '-D_PPD_DEPRECATED='
|
||||||
|
endif
|
||||||
|
|
||||||
|
# cups headers
|
||||||
|
check_headers = [
|
||||||
|
['HAVE_CUPS_CUPS_H', 'cups/cups.h'],
|
||||||
|
['HAVE_CUPS_PPD_H', 'cups/ppd.h']
|
||||||
|
]
|
||||||
|
|
||||||
|
foreach header: check_headers
|
||||||
|
assert(cc.has_header(header[1], args: cups_cflags), 'CUPS headers not found: ' + header[1])
|
||||||
|
endforeach
|
||||||
|
|
||||||
|
config_h.set10('HAVE_CUPS_HTTPCONNECT2',
|
||||||
|
cc.has_function('httpConnect2', dependencies: cups_dep),
|
||||||
|
description: 'Define if httpConnect2() is available in CUPS')
|
||||||
|
|
||||||
|
# IBus support
|
||||||
|
enable_ibus = get_option('ibus')
|
||||||
|
if enable_ibus
|
||||||
|
ibus_dep = dependency('ibus-1.0', version: '>= 1.5.2')
|
||||||
|
endif
|
||||||
|
config_h.set('HAVE_IBUS', enable_ibus,
|
||||||
|
description: 'Defined if IBus support is enabled')
|
||||||
|
|
||||||
|
# thunderbolt
|
||||||
|
config_h.set10('HAVE_FN_EXPLICIT_BZERO',
|
||||||
|
cc.has_function('explicit_bzero', prefix: '''#include <string.h>'''),
|
||||||
|
description: 'Define if explicit_bzero is available')
|
||||||
|
|
||||||
|
# Snap support
|
||||||
|
enable_snap = get_option('snap')
|
||||||
|
if enable_snap
|
||||||
|
libsoup_dep = dependency('libsoup-3.0')
|
||||||
|
endif
|
||||||
|
config_h.set('HAVE_SNAP', enable_snap,
|
||||||
|
description: 'Define to 1 if Snap support is enabled')
|
||||||
|
|
||||||
|
# malcontent support
|
||||||
|
enable_malcontent = get_option('malcontent')
|
||||||
|
if enable_malcontent
|
||||||
|
malcontent_dep = dependency('malcontent-0', version: '>= 0.7.0')
|
||||||
|
config_h.set('HAVE_MALCONTENT_0_10', malcontent_dep.version().version_compare('>= 0.10.0'),
|
||||||
|
description: 'Define to 1 if malcontent ≥ 0.10.0')
|
||||||
|
endif
|
||||||
|
config_h.set('HAVE_MALCONTENT', enable_malcontent,
|
||||||
|
description: 'Define to 1 if malcontent support is enabled')
|
||||||
|
|
||||||
|
# location services support
|
||||||
|
location_services = get_option('location-services')
|
||||||
|
config_h.set('HAVE_LOCATION_SERVICES', location_services.enabled(),
|
||||||
|
description: 'Whether location services is enabled')
|
||||||
|
|
||||||
|
# Snap support and wellbeing panel
|
||||||
|
json_glib_dep = dependency('json-glib-1.0')
|
||||||
|
|
||||||
|
if host_is_linux
|
||||||
|
# ModemManager
|
||||||
|
mm_dep = dependency('mm-glib', version: '>= 0.7')
|
||||||
|
# NetworkManager
|
||||||
|
network_manager_deps = [
|
||||||
|
dependency('libnm', version: '>= 1.24.0'),
|
||||||
|
dependency('libnma-gtk4', version: '>= 1.10.2'),
|
||||||
|
mm_dep,
|
||||||
|
]
|
||||||
|
endif
|
||||||
|
config_h.set('BUILD_NETWORK', host_is_linux,
|
||||||
|
description: 'Define to 1 to build the Network panel')
|
||||||
|
config_h.set('HAVE_NETWORK_MANAGER', host_is_linux,
|
||||||
|
description: 'Define to 1 if NetworkManager is available')
|
||||||
|
config_h.set('BUILD_WWAN', host_is_linux,
|
||||||
|
description: 'Define to 1 to build the WWan panel')
|
||||||
|
config_h.set('HAVE_WWAN', host_is_linux,
|
||||||
|
description: 'Define to 1 if WWan is available')
|
||||||
|
|
||||||
|
if host_is_linux_not_s390
|
||||||
|
# gnome-bluetooth
|
||||||
|
gnome_bluetooth_dep = dependency('gnome-bluetooth-ui-3.0')
|
||||||
|
|
||||||
|
libwacom_dep = dependency('libwacom', version: '>= 1.4')
|
||||||
|
|
||||||
|
wacom_deps = [
|
||||||
|
libwacom_dep,
|
||||||
|
]
|
||||||
|
else
|
||||||
|
message('Bluetooth and Wacom panels will not be built (no USB support on this platform)')
|
||||||
|
message('Thunderbolt panel will not be built (not supported on this platform)')
|
||||||
|
endif
|
||||||
|
config_h.set('BUILD_BLUETOOTH', host_is_linux_not_s390,
|
||||||
|
description: 'Define to 1 to build the Bluetooth panel')
|
||||||
|
config_h.set('HAVE_BLUETOOTH', host_is_linux_not_s390,
|
||||||
|
description: 'Define to 1 if bluetooth support is available')
|
||||||
|
config_h.set('BUILD_WACOM', host_is_linux_not_s390,
|
||||||
|
description: 'Define to 1 to build the Wacom panel')
|
||||||
|
config_h.set('HAVE_WACOM', host_is_linux_not_s390,
|
||||||
|
description: 'Define to 1 if Wacom is supportted')
|
||||||
|
config_h.set('BUILD_THUNDERBOLT', host_is_linux_not_s390,
|
||||||
|
description: 'Define to 1 to build the Thunderbolt panel')
|
||||||
|
|
||||||
|
gnome = import('gnome')
|
||||||
|
i18n = import('i18n')
|
||||||
|
pkg = import('pkgconfig')
|
||||||
|
|
||||||
|
po_dir = join_paths(meson.project_source_root(), 'po')
|
||||||
|
its_dir = join_paths(meson.project_source_root(), 'gettext')
|
||||||
|
|
||||||
|
install_subdir(
|
||||||
|
'gettext',
|
||||||
|
install_dir: control_center_datadir
|
||||||
|
)
|
||||||
|
|
||||||
|
top_inc = include_directories('.')
|
||||||
|
shell_inc = include_directories('shell')
|
||||||
|
|
||||||
|
subdir('data/icons')
|
||||||
|
subdir('po')
|
||||||
|
subdir('panels')
|
||||||
|
subdir('shell')
|
||||||
|
subdir('global-shortcuts-provider')
|
||||||
|
subdir('search-provider')
|
||||||
|
|
||||||
|
if get_option('tests')
|
||||||
|
subdir('tests')
|
||||||
|
endif
|
||||||
|
|
||||||
|
if get_option('documentation')
|
||||||
|
subdir('man')
|
||||||
|
endif
|
||||||
|
|
||||||
|
gnome.post_install(
|
||||||
|
glib_compile_schemas: true,
|
||||||
|
gtk_update_icon_cache: true,
|
||||||
|
)
|
||||||
|
|
||||||
|
configure_file(
|
||||||
|
output: 'config.h',
|
||||||
|
configuration: config_h
|
||||||
|
)
|
||||||
|
|
||||||
|
summary({
|
||||||
|
'Documentation': get_option('documentation'),
|
||||||
|
'Tests': get_option('tests'),
|
||||||
|
'Optimized': control_center_optimized,
|
||||||
|
},
|
||||||
|
bool_yn: true,
|
||||||
|
)
|
||||||
|
|
||||||
|
summary({
|
||||||
|
'GNOME Bluetooth': host_is_linux_not_s390,
|
||||||
|
'NetworkManager': host_is_linux,
|
||||||
|
'Wacom': host_is_linux_not_s390,
|
||||||
|
},
|
||||||
|
section: 'Dependencies',
|
||||||
|
bool_yn: true,
|
||||||
|
)
|
||||||
|
|
||||||
|
summary({
|
||||||
|
'IBus': enable_ibus,
|
||||||
|
'Snap': enable_snap,
|
||||||
|
'Malcontent': enable_malcontent,
|
||||||
|
},
|
||||||
|
section: 'Optional Dependencies',
|
||||||
|
bool_yn: true,
|
||||||
|
)
|
12
meson_options.txt
Normal file
12
meson_options.txt
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
option('deprecated-declarations', type: 'feature', value: 'disabled', description: 'build with deprecated declaration warnings')
|
||||||
|
option('documentation', type: 'boolean', value: false, description: 'build documentation')
|
||||||
|
option('location-services', type: 'feature', value: 'enabled', description: 'build with location services')
|
||||||
|
option('ibus', type: 'boolean', value: true, description: 'build with IBus support')
|
||||||
|
option('privileged_group', type: 'string', value: 'wheel', description: 'name of group that has elevated permissions')
|
||||||
|
option('snap', type: 'boolean', value: true, description: 'build with Snap support')
|
||||||
|
option('tests', type: 'boolean', value: true, description: 'build tests')
|
||||||
|
option('wayland', type: 'boolean', value: true, description: 'build with Wayland support')
|
||||||
|
option('profile', type: 'combo', choices: ['default','development'], value: 'default')
|
||||||
|
option('malcontent', type: 'boolean', value: false, description: 'build with malcontent support')
|
||||||
|
option('distributor_logo', type: 'string', description: 'absolute path to distributor logo for the About panel')
|
||||||
|
option('dark_mode_distributor_logo', type: 'string', description: 'absolute path to distributor logo dark mode variant')
|
11
panels/applications/applications.gresource.xml
Normal file
11
panels/applications/applications.gresource.xml
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<gresources>
|
||||||
|
<gresource prefix="/org/gnome/control-center/applications">
|
||||||
|
<file preprocess="xml-stripblanks">cc-applications-panel.ui</file>
|
||||||
|
<file preprocess="xml-stripblanks">cc-application-shortcut-dialog.ui</file>
|
||||||
|
<file preprocess="xml-stripblanks">cc-default-apps-page.ui</file>
|
||||||
|
<file preprocess="xml-stripblanks">cc-removable-media-settings.ui</file>
|
||||||
|
<file preprocess="xml-stripblanks">cc-applications-row.ui</file>
|
||||||
|
<file preprocess="xml-stripblanks">cc-snap-row.ui</file>
|
||||||
|
</gresource>
|
||||||
|
</gresources>
|
269
panels/applications/cc-application-shortcut-dialog.c
Normal file
269
panels/applications/cc-application-shortcut-dialog.c
Normal file
|
@ -0,0 +1,269 @@
|
||||||
|
/* cc-global-shortcut-dialog.c
|
||||||
|
*
|
||||||
|
* Copyright (C) 2010 Intel, Inc
|
||||||
|
* Copyright (C) 2016 Endless, Inc
|
||||||
|
* Copyright (C) 2020 System76, Inc.
|
||||||
|
* Copyright (C) 2022 Purism SPC
|
||||||
|
* Copyright © 2024 GNOME Foundation Inc.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Author: Thomas Wood <thomas.wood@intel.com>
|
||||||
|
* Georges Basile Stavracas Neto <gbsneto@gnome.org>
|
||||||
|
* Ian Douglas Scott <idscott@system76.com>
|
||||||
|
* Mohammed Sadiq <sadiq@sadiqpk.org>
|
||||||
|
* Dorota Czaplejewicz <gnome@dorotac.eu>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <adwaita.h>
|
||||||
|
#include <config.h>
|
||||||
|
#include <glib/gi18n.h>
|
||||||
|
|
||||||
|
#include "cc-application-shortcut-dialog.h"
|
||||||
|
#include "cc-global-shortcuts-rebind-generated.h"
|
||||||
|
#include "cc-keyboard-shortcut-group.h"
|
||||||
|
#include "cc-util.h"
|
||||||
|
|
||||||
|
struct _CcApplicationShortcutDialog
|
||||||
|
{
|
||||||
|
AdwDialog parent_instance;
|
||||||
|
|
||||||
|
AdwPreferencesPage *shortcut_list;
|
||||||
|
GtkSizeGroup *accelerator_size_group;
|
||||||
|
|
||||||
|
/* Contains `CcKeyboardItem`s */
|
||||||
|
GListStore *shortcuts;
|
||||||
|
AdwPreferencesGroup *group;
|
||||||
|
|
||||||
|
CcKeyboardManager *manager;
|
||||||
|
|
||||||
|
const char *app_id;
|
||||||
|
};
|
||||||
|
|
||||||
|
G_DEFINE_TYPE (CcApplicationShortcutDialog,
|
||||||
|
cc_application_shortcut_dialog,
|
||||||
|
ADW_TYPE_DIALOG)
|
||||||
|
|
||||||
|
static void
|
||||||
|
populate_shortcuts_model (CcApplicationShortcutDialog *self,
|
||||||
|
const char *section_id,
|
||||||
|
const char *section_title)
|
||||||
|
{
|
||||||
|
GtkWidget *group;
|
||||||
|
|
||||||
|
self->shortcuts = g_list_store_new (CC_TYPE_KEYBOARD_ITEM);
|
||||||
|
group = cc_keyboard_shortcut_group_new (G_LIST_MODEL (self->shortcuts),
|
||||||
|
section_id, NULL,
|
||||||
|
self->manager,
|
||||||
|
self->accelerator_size_group);
|
||||||
|
self->group = ADW_PREFERENCES_GROUP (group);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
shortcut_changed_cb (CcApplicationShortcutDialog *self)
|
||||||
|
{
|
||||||
|
GVariant *shortcuts;
|
||||||
|
g_autoptr(GError) error = NULL;
|
||||||
|
g_autoptr(CcGlobalShortcutsRebind) proxy = NULL;
|
||||||
|
|
||||||
|
cc_keyboard_manager_store_global_shortcuts (self->manager, self->app_id);
|
||||||
|
shortcuts = cc_keyboard_manager_get_global_shortcuts (self->manager, self->app_id);
|
||||||
|
proxy =
|
||||||
|
cc_global_shortcuts_rebind_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION,
|
||||||
|
G_DBUS_PROXY_FLAGS_NONE,
|
||||||
|
"org.freedesktop.impl.portal.desktop.gnome",
|
||||||
|
"/org/gnome/globalshortcuts",
|
||||||
|
NULL,
|
||||||
|
&error);
|
||||||
|
if (!proxy)
|
||||||
|
{
|
||||||
|
g_warning ("Can't connect to Global Shortcuts Rebind service: %s",
|
||||||
|
error->message);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
cc_global_shortcuts_rebind_call_rebind_shortcuts_sync (proxy,
|
||||||
|
self->app_id,
|
||||||
|
shortcuts,
|
||||||
|
NULL,
|
||||||
|
&error);
|
||||||
|
if (error)
|
||||||
|
{
|
||||||
|
g_warning ("Can't connect to Global Shortcuts Rebind service: %s",
|
||||||
|
error->message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
shortcut_added_cb (CcApplicationShortcutDialog *self,
|
||||||
|
CcKeyboardItem *item,
|
||||||
|
const char *section_id,
|
||||||
|
const char *section_title)
|
||||||
|
{
|
||||||
|
if (strcmp (section_id, self->app_id) != 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
g_list_store_append (self->shortcuts, item);
|
||||||
|
g_signal_connect_object (item,
|
||||||
|
"notify::key-combos",
|
||||||
|
G_CALLBACK (shortcut_changed_cb),
|
||||||
|
self, G_CONNECT_SWAPPED);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
on_remove_dialog_response_cb (CcApplicationShortcutDialog *self,
|
||||||
|
char *response,
|
||||||
|
AdwMessageDialog *dialog)
|
||||||
|
{
|
||||||
|
if (g_strcmp0 (response, "remove") == 0)
|
||||||
|
{
|
||||||
|
cc_keyboard_manager_reset_global_shortcuts (self->manager, self->app_id);
|
||||||
|
adw_dialog_close (ADW_DIALOG (self));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
reset_all_activated_cb (CcApplicationShortcutDialog *self)
|
||||||
|
{
|
||||||
|
AdwAlertDialog *dialog;
|
||||||
|
|
||||||
|
dialog = ADW_ALERT_DIALOG (adw_alert_dialog_new (_("Remove All Shortcuts?"),
|
||||||
|
NULL));
|
||||||
|
|
||||||
|
/* TRANSLATORS: %s is an app name. */
|
||||||
|
adw_alert_dialog_format_body (dialog,
|
||||||
|
_ ("All actions from %s that have been registered for global shortcuts will be removed."),
|
||||||
|
cc_util_app_id_to_display_name (self->app_id));
|
||||||
|
|
||||||
|
adw_alert_dialog_add_responses (dialog,
|
||||||
|
"cancel", _("_Cancel"),
|
||||||
|
"remove", _("_Remove"),
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
adw_alert_dialog_set_response_appearance (dialog,
|
||||||
|
"remove",
|
||||||
|
ADW_RESPONSE_DESTRUCTIVE);
|
||||||
|
|
||||||
|
adw_alert_dialog_set_default_response (dialog,
|
||||||
|
"cancel");
|
||||||
|
|
||||||
|
adw_alert_dialog_set_close_response (dialog,
|
||||||
|
"cancel");
|
||||||
|
|
||||||
|
g_signal_connect_swapped (GTK_WIDGET (dialog),
|
||||||
|
"response",
|
||||||
|
G_CALLBACK (on_remove_dialog_response_cb),
|
||||||
|
self);
|
||||||
|
|
||||||
|
adw_dialog_present (ADW_DIALOG (dialog), GTK_WIDGET (self));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
shortcuts_loaded_cb (CcApplicationShortcutDialog *self)
|
||||||
|
{
|
||||||
|
GtkWidget *group, *reset_button = NULL;
|
||||||
|
|
||||||
|
adw_preferences_page_add (self->shortcut_list, ADW_PREFERENCES_GROUP (self->group));
|
||||||
|
|
||||||
|
group = adw_preferences_group_new ();
|
||||||
|
reset_button = g_object_new (ADW_TYPE_BUTTON_ROW,
|
||||||
|
"title", _("_Remove All Shortcuts"),
|
||||||
|
"use-underline", TRUE,
|
||||||
|
NULL);
|
||||||
|
g_signal_connect_object (reset_button, "activated",
|
||||||
|
G_CALLBACK (reset_all_activated_cb),
|
||||||
|
self,
|
||||||
|
G_CONNECT_SWAPPED);
|
||||||
|
gtk_widget_add_css_class (reset_button, "destructive-action");
|
||||||
|
|
||||||
|
adw_preferences_group_add (ADW_PREFERENCES_GROUP (group), reset_button);
|
||||||
|
adw_preferences_page_add (self->shortcut_list, ADW_PREFERENCES_GROUP (group));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
cc_application_shortcut_dialog_finalize (GObject *object)
|
||||||
|
{
|
||||||
|
CcApplicationShortcutDialog *self = CC_APPLICATION_SHORTCUT_DIALOG (object);
|
||||||
|
|
||||||
|
g_clear_object (&self->manager);
|
||||||
|
g_clear_object (&self->shortcut_list);
|
||||||
|
g_clear_object (&self->accelerator_size_group);
|
||||||
|
|
||||||
|
G_OBJECT_CLASS (cc_application_shortcut_dialog_parent_class)->finalize (object);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
cc_application_shortcut_dialog_class_init (CcApplicationShortcutDialogClass *klass)
|
||||||
|
{
|
||||||
|
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||||
|
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
|
||||||
|
|
||||||
|
object_class->finalize = cc_application_shortcut_dialog_finalize;
|
||||||
|
|
||||||
|
gtk_widget_class_set_template_from_resource (widget_class,
|
||||||
|
"/org/gnome/control-center/applications/"
|
||||||
|
"cc-application-shortcut-dialog.ui");
|
||||||
|
|
||||||
|
gtk_widget_class_bind_template_child (widget_class, CcApplicationShortcutDialog, shortcut_list);
|
||||||
|
gtk_widget_class_bind_template_child (widget_class, CcApplicationShortcutDialog, accelerator_size_group);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
cc_application_shortcut_dialog_init (CcApplicationShortcutDialog *self)
|
||||||
|
{
|
||||||
|
gtk_widget_init_template (GTK_WIDGET (self));
|
||||||
|
|
||||||
|
self->manager = cc_keyboard_manager_new ();
|
||||||
|
|
||||||
|
g_signal_connect_object (self->manager,
|
||||||
|
"shortcut-added",
|
||||||
|
G_CALLBACK (shortcut_added_cb),
|
||||||
|
self, G_CONNECT_SWAPPED);
|
||||||
|
g_signal_connect_object (self->manager,
|
||||||
|
"shortcut-changed",
|
||||||
|
G_CALLBACK (shortcut_changed_cb),
|
||||||
|
self, G_CONNECT_SWAPPED);
|
||||||
|
/* Shortcuts can not get individually removed from this dialog,
|
||||||
|
* they get rejected in batches */
|
||||||
|
g_signal_connect_object (self->manager,
|
||||||
|
"shortcuts-loaded",
|
||||||
|
G_CALLBACK (shortcuts_loaded_cb),
|
||||||
|
self, G_CONNECT_SWAPPED);
|
||||||
|
}
|
||||||
|
|
||||||
|
CcApplicationShortcutDialog *
|
||||||
|
cc_application_shortcut_dialog_new (const char *app_id)
|
||||||
|
{
|
||||||
|
CcApplicationShortcutDialog *dialog;
|
||||||
|
g_autofree char *explanation_str = NULL;
|
||||||
|
g_autofree char *formatted_name = NULL;
|
||||||
|
g_autofree char *name = NULL;
|
||||||
|
|
||||||
|
dialog = g_object_new (CC_TYPE_APPLICATION_SHORTCUT_DIALOG, NULL);
|
||||||
|
dialog->app_id = app_id;
|
||||||
|
populate_shortcuts_model (dialog, app_id, app_id);
|
||||||
|
cc_keyboard_manager_load_shortcuts (dialog->manager);
|
||||||
|
|
||||||
|
name = cc_util_app_id_to_display_name (app_id);
|
||||||
|
|
||||||
|
formatted_name = g_strdup_printf ("<b>%s</b>", name);
|
||||||
|
/* TRANSLATORS: %s is an app name. */
|
||||||
|
explanation_str =
|
||||||
|
g_strdup_printf (_("%s has registered the following global shortcuts"), formatted_name);
|
||||||
|
adw_preferences_page_set_description (dialog->shortcut_list, explanation_str);
|
||||||
|
|
||||||
|
return dialog;
|
||||||
|
}
|
37
panels/applications/cc-application-shortcut-dialog.h
Normal file
37
panels/applications/cc-application-shortcut-dialog.h
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
/* cc-global-shortcut-dialog.h
|
||||||
|
*
|
||||||
|
* Copyright (C) 2020 System76, Inc.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Author: Ian Douglas Scott <idscott@system76.com>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "keyboard-shortcuts.h"
|
||||||
|
#include <adwaita.h>
|
||||||
|
#include <gio/gio.h>
|
||||||
|
|
||||||
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
|
#define CC_TYPE_APPLICATION_SHORTCUT_DIALOG (cc_application_shortcut_dialog_get_type ())
|
||||||
|
|
||||||
|
G_DECLARE_FINAL_TYPE (CcApplicationShortcutDialog, cc_application_shortcut_dialog, CC, APPLICATION_SHORTCUT_DIALOG, AdwDialog)
|
||||||
|
|
||||||
|
CcApplicationShortcutDialog *cc_application_shortcut_dialog_new (const char *app_id);
|
||||||
|
|
||||||
|
G_END_DECLS
|
20
panels/applications/cc-application-shortcut-dialog.ui
Normal file
20
panels/applications/cc-application-shortcut-dialog.ui
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<interface>
|
||||||
|
<template class="CcApplicationShortcutDialog" parent="AdwDialog">
|
||||||
|
<property name="content-width">480</property>
|
||||||
|
<property name="title" translatable="yes">Global Shortcuts</property>
|
||||||
|
<property name="child">
|
||||||
|
<object class="AdwToolbarView">
|
||||||
|
<child type="top">
|
||||||
|
<object class="AdwHeaderBar" />
|
||||||
|
</child>
|
||||||
|
<property name="content">
|
||||||
|
<object class="AdwPreferencesPage" id="shortcut_list">
|
||||||
|
<property name="description-centered">True</property>
|
||||||
|
</object>
|
||||||
|
</property>
|
||||||
|
</object>
|
||||||
|
</property>
|
||||||
|
</template>
|
||||||
|
<object class="GtkSizeGroup" id="accelerator_size_group"/>
|
||||||
|
</interface>
|
2011
panels/applications/cc-applications-panel.c
Normal file
2011
panels/applications/cc-applications-panel.c
Normal file
File diff suppressed because it is too large
Load diff
30
panels/applications/cc-applications-panel.h
Normal file
30
panels/applications/cc-applications-panel.h
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
/* cc-applications-panel.h
|
||||||
|
*
|
||||||
|
* Copyright 2018 Georges Basile Stavracas Neto <georges.stavracas@gmail.com>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <shell/cc-panel.h>
|
||||||
|
|
||||||
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
|
#define CC_TYPE_APPLICATIONS_PANEL (cc_applications_panel_get_type())
|
||||||
|
G_DECLARE_FINAL_TYPE (CcApplicationsPanel, cc_applications_panel, CC, APPLICATIONS_PANEL, CcPanel)
|
||||||
|
|
||||||
|
G_END_DECLS
|
602
panels/applications/cc-applications-panel.ui
Normal file
602
panels/applications/cc-applications-panel.ui
Normal file
|
@ -0,0 +1,602 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<interface>
|
||||||
|
<template class="CcApplicationsPanel" parent="CcPanel">
|
||||||
|
<!-- App Search Page (Main Landing Page) -->
|
||||||
|
<child type="subpage">
|
||||||
|
<object class="AdwNavigationPage">
|
||||||
|
<property name="title" translatable="yes">Apps</property>
|
||||||
|
<property name="child">
|
||||||
|
<object class="AdwToolbarView">
|
||||||
|
<child type="top">
|
||||||
|
<object class="AdwHeaderBar"/>
|
||||||
|
</child>
|
||||||
|
|
||||||
|
<!-- Searchbar -->
|
||||||
|
<child type="top">
|
||||||
|
<object class="GtkSearchBar">
|
||||||
|
<property name="search-mode-enabled">True</property>
|
||||||
|
<property name="child">
|
||||||
|
<object class="AdwClamp">
|
||||||
|
<property name="margin-start">6</property>
|
||||||
|
<property name="margin-end">6</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkSearchEntry" id="app_search_entry">
|
||||||
|
<property name="placeholder_text" translatable="yes">Search apps</property>
|
||||||
|
<signal name="activate" handler="on_app_search_entry_activated_cb" object="CcApplicationsPanel" swapped="yes" />
|
||||||
|
<signal name="search-changed" handler="on_app_search_entry_search_changed_cb" object="CcApplicationsPanel" swapped="yes" />
|
||||||
|
<signal name="stop-search" handler="on_app_search_entry_search_stopped_cb" object="CcApplicationsPanel" swapped="yes" />
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
|
||||||
|
<property name="content">
|
||||||
|
<object class="GtkStack" id="main_page_stack">
|
||||||
|
|
||||||
|
<child>
|
||||||
|
<object class="GtkStackPage">
|
||||||
|
<property name="name">apps-page</property>
|
||||||
|
<property name="child">
|
||||||
|
<object class="AdwPreferencesPage">
|
||||||
|
|
||||||
|
<!-- Default Apps Row -->
|
||||||
|
<child>
|
||||||
|
<object class="AdwPreferencesGroup">
|
||||||
|
<child>
|
||||||
|
<object class="CcListRow">
|
||||||
|
<property name="title" translatable="yes">_Default Apps</property>
|
||||||
|
<property name="subtitle" translatable="yes">Set which apps open links, files, and media</property>
|
||||||
|
<property name="show-arrow">True</property>
|
||||||
|
<property name="action-name">navigation.push</property>
|
||||||
|
<property name="action-target">'default-apps'</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
|
||||||
|
<!-- Apps List -->
|
||||||
|
<child>
|
||||||
|
<object class="AdwPreferencesGroup">
|
||||||
|
<child>
|
||||||
|
<object class="GtkListBox" id="app_listbox">
|
||||||
|
<property name="selection-mode">none</property>
|
||||||
|
<style>
|
||||||
|
<class name="boxed-list" />
|
||||||
|
</style>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
|
||||||
|
</object>
|
||||||
|
</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
|
||||||
|
<child>
|
||||||
|
<object class="GtkStackPage">
|
||||||
|
<property name="name">no-search-results-page</property>
|
||||||
|
<property name="child">
|
||||||
|
<object class="AdwStatusPage">
|
||||||
|
<property name="icon-name">edit-find-symbolic</property>
|
||||||
|
<property name="title" translatable="yes">No Results Found</property>
|
||||||
|
<property name="description" translatable="yes">Try a different search</property>
|
||||||
|
</object>
|
||||||
|
</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
|
||||||
|
<child>
|
||||||
|
<object class="GtkStackPage">
|
||||||
|
<property name="name">no-apps-found-page</property>
|
||||||
|
<property name="child">
|
||||||
|
<object class="AdwStatusPage">
|
||||||
|
<property name="icon-name">computer-fail-symbolic</property>
|
||||||
|
<property name="title" translatable="yes">No Apps Found</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkButton" id="install_button">
|
||||||
|
<property name="label" translatable="yes">_Find in Software</property>
|
||||||
|
<property name="use_underline">True</property>
|
||||||
|
<property name="halign">center</property>
|
||||||
|
<signal name="clicked" handler="open_software_cb" object="CcApplicationsPanel" swapped="yes"/>
|
||||||
|
<style>
|
||||||
|
<class name="pill"/>
|
||||||
|
<class name="suggested-action"/>
|
||||||
|
</style>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
|
||||||
|
<child>
|
||||||
|
<object class="GtkStackPage">
|
||||||
|
<property name="name">malcontent-not-found-page</property>
|
||||||
|
<property name="child">
|
||||||
|
<object class="AdwStatusPage">
|
||||||
|
<property name="icon-name">dialog-error-symbolic</property>
|
||||||
|
<property name="title" translatable="yes">Unable to List Apps</property>
|
||||||
|
<property name="description" translatable="yes" comments="Translators: Parental Controls here refers to the features provided by 'malcontent'">An error has occurred and apps cannot be listed.
|
||||||
|
Error details: Parental Controls are not installed.</property>
|
||||||
|
</object>
|
||||||
|
</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
|
||||||
|
</object>
|
||||||
|
</property>
|
||||||
|
</object>
|
||||||
|
</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
|
||||||
|
<!-- Default Apps Page -->
|
||||||
|
<child type="subpage">
|
||||||
|
<object class="AdwNavigationPage">
|
||||||
|
<property name="title" translatable="yes">Default Apps</property>
|
||||||
|
<property name="tag">default-apps</property>
|
||||||
|
<property name="child">
|
||||||
|
<object class="AdwToolbarView">
|
||||||
|
<child type="top">
|
||||||
|
<object class="AdwHeaderBar"/>
|
||||||
|
</child>
|
||||||
|
|
||||||
|
<property name="content">
|
||||||
|
<object class="AdwPreferencesPage">
|
||||||
|
<!-- Default Apps Settings -->
|
||||||
|
<child>
|
||||||
|
<object class="CcDefaultAppsPage" id="default_apps_page" />
|
||||||
|
</child>
|
||||||
|
|
||||||
|
<!-- "Automatically Launch Apps" row -->
|
||||||
|
<child>
|
||||||
|
<object class="AdwPreferencesGroup">
|
||||||
|
<property name="title" translatable="yes">Removable Media</property>
|
||||||
|
<child>
|
||||||
|
<object class="AdwSwitchRow" id="autorun_never_row">
|
||||||
|
<property name="title" translatable="yes">Med_ia Autostart</property>
|
||||||
|
<property name="subtitle" translatable="yes">Start apps or prompt when media is connected</property>
|
||||||
|
<property name="use_underline">True</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
|
||||||
|
<!-- Removable Media Settings -->
|
||||||
|
<child>
|
||||||
|
<object class="CcRemovableMediaSettings" id="removable_media_settings" />
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</property>
|
||||||
|
</object>
|
||||||
|
</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
|
||||||
|
<!-- App Settings Page -->
|
||||||
|
<child type="subpage">
|
||||||
|
<object class="AdwNavigationPage" id="app_settings_page">
|
||||||
|
<property name="title" translatable="yes">App Settings</property>
|
||||||
|
<property name="child">
|
||||||
|
<object class="AdwToolbarView">
|
||||||
|
<child type="top">
|
||||||
|
<object class="AdwHeaderBar"/>
|
||||||
|
</child>
|
||||||
|
<property name="content">
|
||||||
|
<object class="GtkBox">
|
||||||
|
<property name="orientation">vertical</property>
|
||||||
|
<child>
|
||||||
|
<object class="AdwBanner" id="sandbox_banner">
|
||||||
|
<property name="visible">False</property>
|
||||||
|
<property name="revealed">True</property>
|
||||||
|
<property name="title" translatable="yes">App is not sandboxed</property>
|
||||||
|
<child>
|
||||||
|
<object class="CcListRowInfoButton" id="sandbox_info_button">
|
||||||
|
<property name="visible" bind-source="sandbox_banner" bind-property="visible" bind-flags="sync-create|default"/>
|
||||||
|
<property name="halign">end</property>
|
||||||
|
<property name="valign">center</property>
|
||||||
|
<property name="margin-end">3</property>
|
||||||
|
<property name="text" translatable="yes">App settings cannot be fully enforced for apps which are not sandboxed. These apps may use permissions which are not shown.</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="AdwPreferencesPage">
|
||||||
|
<!-- App icon & buttons -->
|
||||||
|
<child>
|
||||||
|
<object class="AdwPreferencesGroup">
|
||||||
|
|
||||||
|
<child>
|
||||||
|
<object class="GtkBox">
|
||||||
|
<property name="orientation">vertical</property>
|
||||||
|
<property name="spacing">6</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkImage" id="app_icon_image">
|
||||||
|
<property name="icon-name">org.gnome.Software</property>
|
||||||
|
<property name="pixel-size">96</property>
|
||||||
|
<style>
|
||||||
|
<class name="icon-dropshadow" />
|
||||||
|
</style>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel" id="app_name_label">
|
||||||
|
<property name="justify">center</property>
|
||||||
|
<property name="wrap">True</property>
|
||||||
|
<style>
|
||||||
|
<class name="title-1" />
|
||||||
|
</style>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
|
||||||
|
<child>
|
||||||
|
<object class="GtkBox">
|
||||||
|
<property name="halign">center</property>
|
||||||
|
<property name="margin-top">12</property>
|
||||||
|
<property name="margin-bottom">12</property>
|
||||||
|
<property name="spacing">18</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkButton" id="launch_button">
|
||||||
|
<property name="label" translatable="yes">_Open</property>
|
||||||
|
<property name="use-underline">True</property>
|
||||||
|
<property name="can-shrink">True</property>
|
||||||
|
<signal name="clicked" handler="on_launch_button_clicked_cb" object="CcApplicationsPanel" swapped="yes" />
|
||||||
|
<style>
|
||||||
|
<class name="pill" />
|
||||||
|
<class name="suggested-action" />
|
||||||
|
</style>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkButton" id="view_details_button">
|
||||||
|
<property name="label" translatable="yes">App _Details</property>
|
||||||
|
<property name="use-underline">True</property>
|
||||||
|
<property name="can-shrink">True</property>
|
||||||
|
<style>
|
||||||
|
<class name="pill" />
|
||||||
|
</style>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
|
||||||
|
<child>
|
||||||
|
<object class="AdwPreferencesGroup" id="permissions_group">
|
||||||
|
<property name="title" translatable="yes">Permissions</property>
|
||||||
|
<child>
|
||||||
|
<object class="AdwSwitchRow" id="search_row">
|
||||||
|
<property name="title" translatable="yes" comments="Translators: This row shows/sets whether the app shown in this page can add results to the GNOME Shell search results. Internally this enables/disables the app's Shell Search Provider">_Search</property>
|
||||||
|
<property name="subtitle" translatable="yes">Receive system searches and send results</property>
|
||||||
|
<property name="use-underline">True</property>
|
||||||
|
<signal name="notify::active" handler="search_cb" object="CcApplicationsPanel" swapped="yes"/>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="CcListRow" id="no_search_row">
|
||||||
|
<property name="title" bind-source="search_row" bind-property="title" bind-flags="sync-create"/>
|
||||||
|
<property name="subtitle" bind-source="search_row" bind-property="subtitle" bind-flags="sync-create"/>
|
||||||
|
<property name="secondary-label" translatable="yes">Disabled</property>
|
||||||
|
<property name="activatable">False</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="AdwSwitchRow" id="notifications_row">
|
||||||
|
<property name="title" translatable="yes">_Notifications</property>
|
||||||
|
<property name="subtitle" translatable="yes">Show system notifications</property>
|
||||||
|
<property name="use-underline">True</property>
|
||||||
|
<signal name="notify::active" handler="notification_cb" object="CcApplicationsPanel" swapped="yes"/>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="AdwSwitchRow" id="background_row">
|
||||||
|
<property name="title" translatable="yes">_Run in Background</property>
|
||||||
|
<property name="subtitle" translatable="yes">Allow activity when the app is closed</property>
|
||||||
|
<property name="use-underline">True</property>
|
||||||
|
<signal name="notify::active" handler="background_cb" swapped="yes"/>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="AdwSwitchRow" id="screenshots_row">
|
||||||
|
<property name="title" translatable="yes">Scr_eenshots</property>
|
||||||
|
<property name="subtitle" translatable="yes">Take pictures of the screen at any time</property>
|
||||||
|
<property name="use-underline">True</property>
|
||||||
|
<signal name="notify::active" handler="screenshot_cb" object="CcApplicationsPanel" swapped="yes"/>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="AdwSwitchRow" id="wallpaper_row">
|
||||||
|
<property name="title" translatable="yes">Change _Wallpaper</property>
|
||||||
|
<property name="subtitle" translatable="yes">Change the desktop wallpaper</property>
|
||||||
|
<property name="use-underline">True</property>
|
||||||
|
<signal name="notify::active" handler="wallpaper_cb" swapped="yes"/>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="AdwSwitchRow" id="sounds_row">
|
||||||
|
<property name="title" translatable="yes">So_unds</property>
|
||||||
|
<property name="subtitle" translatable="yes">Reproduce sounds</property>
|
||||||
|
<property name="use-underline">True</property>
|
||||||
|
<signal name="notify::active" handler="sound_cb" object="CcApplicationsPanel" swapped="yes"/>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="CcListRow" id="no_sounds_row">
|
||||||
|
<property name="title" translatable="yes">Sounds</property>
|
||||||
|
<property name="subtitle" translatable="yes">Reproduce sounds</property>
|
||||||
|
<property name="secondary-label" translatable="yes">Disabled</property>
|
||||||
|
<property name="activatable">False</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="AdwSwitchRow" id="shortcuts_row">
|
||||||
|
<property name="title" translatable="yes">_Inhibit Shortcuts</property>
|
||||||
|
<property name="subtitle" translatable="yes">Block standard keyboard shortcuts</property>
|
||||||
|
<property name="use-underline">True</property>
|
||||||
|
<signal name="notify::active" handler="shortcuts_cb" swapped="yes"/>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="AdwSwitchRow" id="camera_row">
|
||||||
|
<property name="title" translatable="yes">C_amera</property>
|
||||||
|
<property name="subtitle" translatable="yes">Take pictures with the camera</property>
|
||||||
|
<property name="use-underline">True</property>
|
||||||
|
<signal name="notify::active" handler="camera_cb" object="CcApplicationsPanel" swapped="yes"/>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="CcListRow" id="no_camera_row">
|
||||||
|
<property name="title" translatable="yes">Camera</property>
|
||||||
|
<property name="subtitle" translatable="yes">Take pictures with the camera</property>
|
||||||
|
<property name="secondary-label" translatable="yes">Disabled</property>
|
||||||
|
<property name="activatable">False</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="AdwSwitchRow" id="microphone_row">
|
||||||
|
<property name="title" translatable="yes">_Microphone</property>
|
||||||
|
<property name="subtitle" translatable="yes">Record audio with the microphone</property>
|
||||||
|
<property name="use-underline">True</property>
|
||||||
|
<signal name="notify::active" handler="microphone_cb" object="CcApplicationsPanel" swapped="yes"/>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="CcListRow" id="no_microphone_row">
|
||||||
|
<property name="title" translatable="yes">Microphone</property>
|
||||||
|
<property name="subtitle" translatable="yes">Record audio with the microphone</property>
|
||||||
|
<property name="secondary-label" translatable="yes">Disabled</property>
|
||||||
|
<property name="activatable">False</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="AdwSwitchRow" id="location_row">
|
||||||
|
<property name="title" translatable="yes">_Location Services</property>
|
||||||
|
<property name="subtitle" translatable="yes">Access device location data</property>
|
||||||
|
<property name="use-underline">True</property>
|
||||||
|
<signal name="notify::active" handler="location_cb" object="CcApplicationsPanel" swapped="yes"/>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="CcListRow" id="no_location_row">
|
||||||
|
<property name="title" translatable="yes">Location Services</property>
|
||||||
|
<property name="subtitle" translatable="yes">Access device location data</property>
|
||||||
|
<property name="secondary-label" translatable="yes">Disabled</property>
|
||||||
|
<property name="activatable">False</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
|
||||||
|
<child>
|
||||||
|
<object class="AdwPreferencesGroup" id="required_permissions_group">
|
||||||
|
<child>
|
||||||
|
<object class="CcListRow" id="builtin_row">
|
||||||
|
<property name="title" translatable="yes">Re_quired Permissions</property>
|
||||||
|
<property name="subtitle" translatable="yes">System permissions that the app requires</property>
|
||||||
|
<property name="show-arrow">True</property>
|
||||||
|
<property name="action-name">navigation.push</property>
|
||||||
|
<property name="action-target">'builtin-page'</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="CcListRow" id="global_shortcuts_row">
|
||||||
|
<property name="title" translatable="yes">Global S_hortcuts</property>
|
||||||
|
<property name="subtitle" translatable="yes">Global actions that have been registered for use</property>
|
||||||
|
<property name="show-arrow">True</property>
|
||||||
|
<signal name="activated" handler="global_shortcuts_cb" object="CcApplicationsPanel" swapped="yes" />
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
|
||||||
|
<child>
|
||||||
|
<object class="AdwPreferencesGroup" id="general_group">
|
||||||
|
<property name="title" translatable="yes">General</property>
|
||||||
|
<child>
|
||||||
|
<object class="CcListRow" id="handler_row">
|
||||||
|
<property name="title" translatable="yes">_Files &amp; Links</property>
|
||||||
|
<property name="subtitle" translatable="yes">File and link types that are opened by the app</property>
|
||||||
|
<property name="show-arrow">True</property>
|
||||||
|
<property name="action-name">navigation.push</property>
|
||||||
|
<property name="action-target">'handler-page'</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="CcListRow" id="storage_row">
|
||||||
|
<property name="title" translatable="yes">S_torage</property>
|
||||||
|
<property name="subtitle" translatable="yes">Disk space being used</property>
|
||||||
|
<property name="show-arrow">True</property>
|
||||||
|
<property name="action-name">navigation.push</property>
|
||||||
|
<property name="action-target">'storage-page'</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</property>
|
||||||
|
</object>
|
||||||
|
</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
|
||||||
|
<!-- Required Permissions page -->
|
||||||
|
<child type="subpage">
|
||||||
|
<object class="AdwNavigationPage">
|
||||||
|
<property name="title" translatable="yes">Required Permissions</property>
|
||||||
|
<property name="tag">builtin-page</property>
|
||||||
|
<property name="child">
|
||||||
|
<object class="AdwToolbarView">
|
||||||
|
<child type="top">
|
||||||
|
<object class="AdwHeaderBar"/>
|
||||||
|
</child>
|
||||||
|
<property name="content">
|
||||||
|
<object class="AdwPreferencesPage" id="builtin_page">
|
||||||
|
<child>
|
||||||
|
<object class="AdwPreferencesGroup">
|
||||||
|
<child>
|
||||||
|
<object class="GtkListBox" id="builtin_list">
|
||||||
|
<property name="selection-mode">none</property>
|
||||||
|
<style>
|
||||||
|
<class name="boxed-list"/>
|
||||||
|
</style>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</property>
|
||||||
|
</object>
|
||||||
|
</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
|
||||||
|
<!-- File & Link Associations page -->
|
||||||
|
<child type="subpage">
|
||||||
|
<object class="AdwNavigationPage">
|
||||||
|
<property name="title" translatable="yes">Files & Links</property>
|
||||||
|
<property name="tag">handler-page</property>
|
||||||
|
<property name="child">
|
||||||
|
<object class="AdwToolbarView">
|
||||||
|
<child type="top">
|
||||||
|
<object class="AdwHeaderBar"/>
|
||||||
|
</child>
|
||||||
|
<property name="content">
|
||||||
|
<object class="AdwPreferencesPage" id="handler_page">
|
||||||
|
<child>
|
||||||
|
<object class="AdwPreferencesGroup" id="handler_file_group">
|
||||||
|
<property name="title" translatable="yes">File Types</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="AdwPreferencesGroup" id="handler_link_group">
|
||||||
|
<property name="title" translatable="yes">Link Types</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="AdwPreferencesGroup">
|
||||||
|
<child>
|
||||||
|
<object class="AdwButtonRow" id="handler_reset_button_row">
|
||||||
|
<property name="title" translatable="yes">_Reset</property>
|
||||||
|
<property name="use-underline">True</property>
|
||||||
|
<signal name="activated" handler="handler_reset_cb" object="CcApplicationsPanel" swapped="yes"/>
|
||||||
|
<style>
|
||||||
|
<class name="destructive-action"/>
|
||||||
|
</style>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</property>
|
||||||
|
</object>
|
||||||
|
</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
|
||||||
|
<!-- Storage page -->
|
||||||
|
<child type="subpage">
|
||||||
|
<object class="AdwNavigationPage">
|
||||||
|
<property name="title" translatable="yes">Storage</property>
|
||||||
|
<property name="tag">storage-page</property>
|
||||||
|
<property name="child">
|
||||||
|
<object class="AdwToolbarView">
|
||||||
|
<child type="top">
|
||||||
|
<object class="AdwHeaderBar"/>
|
||||||
|
</child>
|
||||||
|
<property name="content">
|
||||||
|
<object class="AdwPreferencesPage" id="storage_page">
|
||||||
|
<child>
|
||||||
|
<object class="AdwPreferencesGroup">
|
||||||
|
<child>
|
||||||
|
<object class="AdwActionRow" id="storage_page_app_row">
|
||||||
|
<property name="title" translatable="yes">App</property>
|
||||||
|
<style>
|
||||||
|
<class name="property"/>
|
||||||
|
</style>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="AdwActionRow" id="storage_page_data_row">
|
||||||
|
<property name="title" translatable="yes">Data</property>
|
||||||
|
<style>
|
||||||
|
<class name="property"/>
|
||||||
|
</style>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="AdwActionRow" id="storage_page_cache_row">
|
||||||
|
<property name="title" translatable="yes">Cache</property>
|
||||||
|
<style>
|
||||||
|
<class name="property"/>
|
||||||
|
</style>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="AdwActionRow" id="storage_page_total_row">
|
||||||
|
<property name="title" translatable="yes">Total</property>
|
||||||
|
<style>
|
||||||
|
<class name="property"/>
|
||||||
|
</style>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="AdwPreferencesGroup">
|
||||||
|
<child>
|
||||||
|
<object class="AdwButtonRow" id="clear_cache_button_row">
|
||||||
|
<property name="title" translatable="yes">_Clear Cache</property>
|
||||||
|
<property name="use-underline">True</property>
|
||||||
|
<signal name="activated" handler="clear_cache_cb" object="CcApplicationsPanel" swapped="yes"/>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</property>
|
||||||
|
</object>
|
||||||
|
</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<object class="GtkSizeGroup">
|
||||||
|
<property name="mode">horizontal</property>
|
||||||
|
<widgets>
|
||||||
|
<widget name="launch_button" />
|
||||||
|
<widget name="view_details_button" />
|
||||||
|
</widgets>
|
||||||
|
</object>
|
||||||
|
</interface>
|
98
panels/applications/cc-applications-row.c
Normal file
98
panels/applications/cc-applications-row.c
Normal file
|
@ -0,0 +1,98 @@
|
||||||
|
/* cc-applications-row.c
|
||||||
|
*
|
||||||
|
* Copyright 2018 Matthias Clasen <matthias.clasen@gmail.com>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <config.h>
|
||||||
|
#include <glib/gi18n.h>
|
||||||
|
|
||||||
|
#include "cc-applications-row.h"
|
||||||
|
#include "cc-applications-resources.h"
|
||||||
|
|
||||||
|
struct _CcApplicationsRow
|
||||||
|
{
|
||||||
|
AdwActionRow parent;
|
||||||
|
|
||||||
|
GAppInfo *info;
|
||||||
|
};
|
||||||
|
|
||||||
|
G_DEFINE_TYPE (CcApplicationsRow, cc_applications_row, ADW_TYPE_ACTION_ROW)
|
||||||
|
|
||||||
|
static void
|
||||||
|
cc_applications_row_finalize (GObject *object)
|
||||||
|
{
|
||||||
|
CcApplicationsRow *self = CC_APPLICATIONS_ROW (object);
|
||||||
|
|
||||||
|
g_object_unref (self->info);
|
||||||
|
|
||||||
|
G_OBJECT_CLASS (cc_applications_row_parent_class)->finalize (object);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
cc_applications_row_class_init (CcApplicationsRowClass *klass)
|
||||||
|
{
|
||||||
|
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||||
|
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
|
||||||
|
|
||||||
|
object_class->finalize = cc_applications_row_finalize;
|
||||||
|
|
||||||
|
gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/control-center/applications/cc-applications-row.ui");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
cc_applications_row_init (CcApplicationsRow *self)
|
||||||
|
{
|
||||||
|
gtk_widget_init_template (GTK_WIDGET (self));
|
||||||
|
}
|
||||||
|
|
||||||
|
CcApplicationsRow *
|
||||||
|
cc_applications_row_new (GAppInfo *info)
|
||||||
|
{
|
||||||
|
CcApplicationsRow *self;
|
||||||
|
g_autoptr(GIcon) icon = NULL;
|
||||||
|
GtkWidget *w;
|
||||||
|
|
||||||
|
self = g_object_new (CC_TYPE_APPLICATIONS_ROW, NULL);
|
||||||
|
|
||||||
|
self->info = g_object_ref (info);
|
||||||
|
|
||||||
|
gtk_list_box_row_set_activatable (GTK_LIST_BOX_ROW (self), TRUE);
|
||||||
|
adw_preferences_row_set_title (ADW_PREFERENCES_ROW (self), g_app_info_get_display_name (info));
|
||||||
|
|
||||||
|
icon = g_app_info_get_icon (info);
|
||||||
|
if (icon != NULL)
|
||||||
|
g_object_ref (icon);
|
||||||
|
else
|
||||||
|
icon = g_themed_icon_new ("application-x-executable");
|
||||||
|
w = g_object_new (GTK_TYPE_IMAGE,
|
||||||
|
"accessible-role", GTK_ACCESSIBLE_ROLE_PRESENTATION,
|
||||||
|
"gicon", icon,
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
gtk_widget_add_css_class (w, "lowres-icon");
|
||||||
|
gtk_image_set_icon_size (GTK_IMAGE (w), GTK_ICON_SIZE_LARGE);
|
||||||
|
adw_action_row_add_prefix (ADW_ACTION_ROW (self), w);
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
GAppInfo *
|
||||||
|
cc_applications_row_get_info (CcApplicationsRow *self)
|
||||||
|
{
|
||||||
|
return self->info;
|
||||||
|
}
|
35
panels/applications/cc-applications-row.h
Normal file
35
panels/applications/cc-applications-row.h
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
/* cc-applications-row.h
|
||||||
|
*
|
||||||
|
* Copyright 2018 Matthias Clasen <matthias.clasen@gmail.com>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <gtk/gtk.h>
|
||||||
|
#include <adwaita.h>
|
||||||
|
|
||||||
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
|
#define CC_TYPE_APPLICATIONS_ROW (cc_applications_row_get_type())
|
||||||
|
G_DECLARE_FINAL_TYPE (CcApplicationsRow, cc_applications_row, CC, APPLICATIONS_ROW, AdwActionRow)
|
||||||
|
|
||||||
|
CcApplicationsRow* cc_applications_row_new (GAppInfo *info);
|
||||||
|
|
||||||
|
GAppInfo* cc_applications_row_get_info (CcApplicationsRow *row);
|
||||||
|
|
||||||
|
G_END_DECLS
|
14
panels/applications/cc-applications-row.ui
Normal file
14
panels/applications/cc-applications-row.ui
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<interface>
|
||||||
|
<template class="CcApplicationsRow" parent="AdwActionRow">
|
||||||
|
<property name="use-markup">False</property>
|
||||||
|
|
||||||
|
<child type="suffix">
|
||||||
|
<object class="GtkImage">
|
||||||
|
<property name="icon-name">go-next-symbolic</property>
|
||||||
|
<property name="accessible-role">presentation</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
|
||||||
|
</template>
|
||||||
|
</interface>
|
146
panels/applications/cc-default-apps-page.c
Normal file
146
panels/applications/cc-default-apps-page.c
Normal file
|
@ -0,0 +1,146 @@
|
||||||
|
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
|
||||||
|
*
|
||||||
|
* Copyright (C) 2017 Mohammed Sadiq <sadiq@sadiqpk.org>
|
||||||
|
* Copyright (C) 2010 Red Hat, Inc
|
||||||
|
* Copyright (C) 2008 William Jon McCann <jmccann@redhat.com>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <config.h>
|
||||||
|
#ifdef BUILD_WWAN
|
||||||
|
#include <libmm-glib.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "cc-default-apps-page.h"
|
||||||
|
#include "cc-default-apps-row.h"
|
||||||
|
|
||||||
|
#include "shell/cc-object-storage.h"
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
const char *content_type;
|
||||||
|
/* Patterns used to filter supported mime types
|
||||||
|
when changing preferred applications. NULL
|
||||||
|
means no other types should be changed */
|
||||||
|
const char *extra_type_filter;
|
||||||
|
} DefaultAppData;
|
||||||
|
|
||||||
|
struct _CcDefaultAppsPage
|
||||||
|
{
|
||||||
|
AdwPreferencesGroup parent;
|
||||||
|
|
||||||
|
GtkWidget *web_row;
|
||||||
|
GtkWidget *mail_row;
|
||||||
|
GtkWidget *calendar_row;
|
||||||
|
GtkWidget *music_row;
|
||||||
|
GtkWidget *video_row;
|
||||||
|
GtkWidget *photos_row;
|
||||||
|
GtkWidget *calls_row;
|
||||||
|
GtkWidget *sms_row;
|
||||||
|
|
||||||
|
#ifdef BUILD_WWAN
|
||||||
|
MMManager *mm_manager;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
G_DEFINE_TYPE (CcDefaultAppsPage, cc_default_apps_page, ADW_TYPE_PREFERENCES_GROUP)
|
||||||
|
|
||||||
|
#ifdef BUILD_WWAN
|
||||||
|
static void
|
||||||
|
update_modem_apps_visibility (CcDefaultAppsPage *self)
|
||||||
|
{
|
||||||
|
GList *devices;
|
||||||
|
gboolean has_mm_objects;
|
||||||
|
|
||||||
|
devices = g_dbus_object_manager_get_objects (G_DBUS_OBJECT_MANAGER (self->mm_manager));
|
||||||
|
has_mm_objects = g_list_length (devices) > 0;
|
||||||
|
|
||||||
|
gtk_widget_set_visible (self->calls_row, has_mm_objects);
|
||||||
|
gtk_widget_set_visible (self->sms_row, has_mm_objects);
|
||||||
|
|
||||||
|
g_list_free_full (devices, (GDestroyNotify)g_object_unref);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static void
|
||||||
|
on_row_selected_item_changed (CcDefaultAppsRow *row)
|
||||||
|
{
|
||||||
|
cc_default_apps_row_update_default_app (row);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
cc_default_apps_page_dispose (GObject *object)
|
||||||
|
{
|
||||||
|
#ifdef BUILD_WWAN
|
||||||
|
CcDefaultAppsPage *self = CC_DEFAULT_APPS_PAGE (object);
|
||||||
|
|
||||||
|
g_clear_object (&self->mm_manager);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
G_OBJECT_CLASS (cc_default_apps_page_parent_class)->dispose (object);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
cc_default_apps_page_class_init (CcDefaultAppsPageClass *klass)
|
||||||
|
{
|
||||||
|
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
|
||||||
|
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||||
|
|
||||||
|
object_class->dispose = cc_default_apps_page_dispose;
|
||||||
|
|
||||||
|
gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/control-center/applications/cc-default-apps-page.ui");
|
||||||
|
gtk_widget_class_bind_template_child (widget_class, CcDefaultAppsPage, web_row);
|
||||||
|
gtk_widget_class_bind_template_child (widget_class, CcDefaultAppsPage, mail_row);
|
||||||
|
gtk_widget_class_bind_template_child (widget_class, CcDefaultAppsPage, calendar_row);
|
||||||
|
gtk_widget_class_bind_template_child (widget_class, CcDefaultAppsPage, music_row);
|
||||||
|
gtk_widget_class_bind_template_child (widget_class, CcDefaultAppsPage, video_row);
|
||||||
|
gtk_widget_class_bind_template_child (widget_class, CcDefaultAppsPage, photos_row);
|
||||||
|
gtk_widget_class_bind_template_child (widget_class, CcDefaultAppsPage, calls_row);
|
||||||
|
gtk_widget_class_bind_template_child (widget_class, CcDefaultAppsPage, sms_row);
|
||||||
|
|
||||||
|
gtk_widget_class_bind_template_callback (widget_class, on_row_selected_item_changed);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
cc_default_apps_page_init (CcDefaultAppsPage *self)
|
||||||
|
{
|
||||||
|
g_type_ensure (CC_TYPE_DEFAULT_APPS_ROW);
|
||||||
|
|
||||||
|
gtk_widget_init_template (GTK_WIDGET (self));
|
||||||
|
|
||||||
|
#ifdef BUILD_WWAN
|
||||||
|
if (cc_object_storage_has_object (CC_OBJECT_MMMANAGER))
|
||||||
|
{
|
||||||
|
self->mm_manager = cc_object_storage_get_object (CC_OBJECT_MMMANAGER);
|
||||||
|
|
||||||
|
g_signal_connect_swapped (self->mm_manager, "object-added",
|
||||||
|
G_CALLBACK (update_modem_apps_visibility), self);
|
||||||
|
g_signal_connect_swapped (self->mm_manager, "object-removed",
|
||||||
|
G_CALLBACK (update_modem_apps_visibility), self);
|
||||||
|
|
||||||
|
update_modem_apps_visibility (self);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
CcDefaultAppsPage *
|
||||||
|
cc_default_apps_page_new (void)
|
||||||
|
{
|
||||||
|
return g_object_new (CC_TYPE_DEFAULT_APPS_PAGE,
|
||||||
|
NULL);
|
||||||
|
}
|
31
panels/applications/cc-default-apps-page.h
Normal file
31
panels/applications/cc-default-apps-page.h
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
|
||||||
|
*
|
||||||
|
* Copyright (C) 2017 Mohammed Sadiq <sadiq@sadiqpk.org>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <adwaita.h>
|
||||||
|
|
||||||
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
|
#define CC_TYPE_DEFAULT_APPS_PAGE (cc_default_apps_page_get_type ())
|
||||||
|
G_DECLARE_FINAL_TYPE (CcDefaultAppsPage, cc_default_apps_page, CC, DEFAULT_APPS_PAGE, AdwPreferencesGroup)
|
||||||
|
|
||||||
|
CcDefaultAppsPage *cc_default_apps_page_new (void);
|
||||||
|
|
||||||
|
G_END_DECLS
|
76
panels/applications/cc-default-apps-page.ui
Normal file
76
panels/applications/cc-default-apps-page.ui
Normal file
|
@ -0,0 +1,76 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<interface>
|
||||||
|
<template class="CcDefaultAppsPage" parent="AdwPreferencesGroup">
|
||||||
|
<property name="title" translatable="yes">Default Apps</property>
|
||||||
|
<child>
|
||||||
|
<object class="CcDefaultAppsRow" id="web_row">
|
||||||
|
<property name="title" translatable="yes">_Web</property>
|
||||||
|
<property name="use-underline">True</property>
|
||||||
|
<property name="content-type">x-scheme-handler/http</property>
|
||||||
|
<property name="filters">text/html;application/xhtml+xml;x-scheme-handler/https</property>
|
||||||
|
<signal name="notify::selected-item" handler="on_row_selected_item_changed"/>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="CcDefaultAppsRow" id="mail_row">
|
||||||
|
<property name="title" translatable="yes">_Mail</property>
|
||||||
|
<property name="use_underline">True</property>
|
||||||
|
<property name="content-type">x-scheme-handler/mailto</property>
|
||||||
|
<signal name="notify::selected-item" handler="on_row_selected_item_changed"/>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="CcDefaultAppsRow" id="calendar_row">
|
||||||
|
<property name="title" translatable="yes">_Calendar</property>
|
||||||
|
<property name="use-underline">True</property>
|
||||||
|
<property name="content-type">text/calendar</property>
|
||||||
|
<signal name="notify::selected-item" handler="on_row_selected_item_changed"/>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="CcDefaultAppsRow" id="music_row">
|
||||||
|
<property name="title" translatable="yes">M_usic</property>
|
||||||
|
<property name="use-underline">True</property>
|
||||||
|
<property name="content-type">audio/x-vorbis+ogg</property>
|
||||||
|
<property name="filters">audio/*</property>
|
||||||
|
<signal name="notify::selected-item" handler="on_row_selected_item_changed"/>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="CcDefaultAppsRow" id="video_row">
|
||||||
|
<property name="title" translatable="yes">_Video</property>
|
||||||
|
<property name="use-underline">True</property>
|
||||||
|
<property name="content-type">video/x-ogm+ogg</property>
|
||||||
|
<property name="filters">video/*</property>
|
||||||
|
<signal name="notify::selected-item" handler="on_row_selected_item_changed"/>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="CcDefaultAppsRow" id="photos_row">
|
||||||
|
<property name="title" translatable="yes">_Photos</property>
|
||||||
|
<property name="use-underline">True</property>
|
||||||
|
<property name="content-type">image/jpeg</property>
|
||||||
|
<property name="filters">image/*</property>
|
||||||
|
<signal name="notify::selected-item" handler="on_row_selected_item_changed"/>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="CcDefaultAppsRow" id="calls_row">
|
||||||
|
<property name="visible">False</property>
|
||||||
|
<property name="title" translatable="yes" comments="Translators: This is a telephone call">Ca_lls</property>
|
||||||
|
<property name="use-underline">True</property>
|
||||||
|
<property name="content-type">x-scheme-handler/tel</property>
|
||||||
|
<signal name="notify::selected-item" handler="on_row_selected_item_changed"/>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="CcDefaultAppsRow" id="sms_row">
|
||||||
|
<property name="visible">False</property>
|
||||||
|
<property name="title" translatable="yes">_SMS</property>
|
||||||
|
<property name="use-underline">True</property>
|
||||||
|
<property name="content-type">x-scheme-handler/sms</property>
|
||||||
|
<signal name="notify::selected-item" handler="on_row_selected_item_changed"/>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</template>
|
||||||
|
</interface>
|
246
panels/applications/cc-default-apps-row.c
Normal file
246
panels/applications/cc-default-apps-row.c
Normal file
|
@ -0,0 +1,246 @@
|
||||||
|
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
|
||||||
|
*
|
||||||
|
* Copyright 2022 Christopher Davis <christopherdavis@gnome.org>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <glib/gi18n.h>
|
||||||
|
|
||||||
|
#include "cc-default-apps-row.h"
|
||||||
|
|
||||||
|
struct _CcDefaultAppsRow
|
||||||
|
{
|
||||||
|
AdwComboRow parent_instance;
|
||||||
|
|
||||||
|
char *content_type;
|
||||||
|
char *filters;
|
||||||
|
|
||||||
|
GListStore *model;
|
||||||
|
};
|
||||||
|
|
||||||
|
G_DEFINE_FINAL_TYPE (CcDefaultAppsRow, cc_default_apps_row, ADW_TYPE_COMBO_ROW)
|
||||||
|
|
||||||
|
enum {
|
||||||
|
PROP_0,
|
||||||
|
PROP_CONTENT_TYPE,
|
||||||
|
PROP_FILTERS,
|
||||||
|
N_PROPS
|
||||||
|
};
|
||||||
|
|
||||||
|
static GParamSpec *properties [N_PROPS];
|
||||||
|
|
||||||
|
static char *
|
||||||
|
get_app_display_name (GAppInfo *info)
|
||||||
|
{
|
||||||
|
return g_strdup (g_app_info_get_display_name (info));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
cc_default_apps_row_get_property (GObject *object,
|
||||||
|
guint prop_id,
|
||||||
|
GValue *value,
|
||||||
|
GParamSpec *pspec)
|
||||||
|
{
|
||||||
|
CcDefaultAppsRow *self = CC_DEFAULT_APPS_ROW (object);
|
||||||
|
|
||||||
|
switch (prop_id)
|
||||||
|
{
|
||||||
|
case PROP_CONTENT_TYPE:
|
||||||
|
g_value_set_string (value, self->content_type);
|
||||||
|
break;
|
||||||
|
case PROP_FILTERS:
|
||||||
|
g_value_set_string (value, self->filters);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
cc_default_apps_row_set_property (GObject *object,
|
||||||
|
guint prop_id,
|
||||||
|
const GValue *value,
|
||||||
|
GParamSpec *pspec)
|
||||||
|
{
|
||||||
|
CcDefaultAppsRow *self = CC_DEFAULT_APPS_ROW (object);
|
||||||
|
|
||||||
|
switch (prop_id)
|
||||||
|
{
|
||||||
|
case PROP_CONTENT_TYPE:
|
||||||
|
self->content_type = g_value_dup_string (value);
|
||||||
|
break;
|
||||||
|
case PROP_FILTERS:
|
||||||
|
self->filters = g_value_dup_string (value);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
cc_default_apps_row_finalize (GObject *object)
|
||||||
|
{
|
||||||
|
CcDefaultAppsRow *self = CC_DEFAULT_APPS_ROW (object);
|
||||||
|
|
||||||
|
g_clear_pointer (&self->content_type, g_free);
|
||||||
|
g_clear_pointer (&self->filters, g_free);
|
||||||
|
|
||||||
|
G_OBJECT_CLASS (cc_default_apps_row_parent_class)->finalize (object);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
cc_default_apps_row_constructed (GObject *object)
|
||||||
|
{
|
||||||
|
CcDefaultAppsRow *self;
|
||||||
|
g_autoptr(GAppInfo) default_app = NULL;
|
||||||
|
g_autolist(GAppInfo) recommended_apps = NULL;
|
||||||
|
GList *l;
|
||||||
|
g_autoptr(GtkExpression) name_expr = NULL;
|
||||||
|
|
||||||
|
G_OBJECT_CLASS (cc_default_apps_row_parent_class)->constructed (object);
|
||||||
|
|
||||||
|
self = CC_DEFAULT_APPS_ROW (object);
|
||||||
|
default_app = g_app_info_get_default_for_type (self->content_type, FALSE);
|
||||||
|
recommended_apps = g_app_info_get_recommended_for_type (self->content_type);
|
||||||
|
self->model = g_list_store_new (G_TYPE_APP_INFO);
|
||||||
|
|
||||||
|
/* Add the default separately because it may not be in the list of recommended apps */
|
||||||
|
if (G_IS_APP_INFO (default_app))
|
||||||
|
g_list_store_append (self->model, default_app);
|
||||||
|
|
||||||
|
for (l = recommended_apps; l != NULL; l = l->next) {
|
||||||
|
GAppInfo *app = l->data;
|
||||||
|
|
||||||
|
if (!G_IS_APP_INFO (app) || (default_app != NULL && g_app_info_equal (app, default_app)))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
g_list_store_append (self->model, app);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (g_list_model_get_n_items (G_LIST_MODEL (self->model)) == 0)
|
||||||
|
{
|
||||||
|
GtkWidget *no_apps_label;
|
||||||
|
|
||||||
|
no_apps_label = gtk_label_new (_("No Apps Available"));
|
||||||
|
gtk_widget_add_css_class (no_apps_label, "dim-label");
|
||||||
|
adw_action_row_add_suffix (ADW_ACTION_ROW (self), no_apps_label);
|
||||||
|
}
|
||||||
|
|
||||||
|
adw_combo_row_set_model (ADW_COMBO_ROW (self), G_LIST_MODEL (self->model));
|
||||||
|
|
||||||
|
name_expr = gtk_cclosure_expression_new (G_TYPE_STRING, NULL,
|
||||||
|
0, NULL,
|
||||||
|
G_CALLBACK (get_app_display_name),
|
||||||
|
NULL, NULL);
|
||||||
|
adw_combo_row_set_expression (ADW_COMBO_ROW (self), name_expr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
cc_default_apps_row_class_init (CcDefaultAppsRowClass *klass)
|
||||||
|
{
|
||||||
|
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||||
|
|
||||||
|
object_class->get_property = cc_default_apps_row_get_property;
|
||||||
|
object_class->set_property = cc_default_apps_row_set_property;
|
||||||
|
object_class->constructed = cc_default_apps_row_constructed;
|
||||||
|
object_class->finalize = cc_default_apps_row_finalize;
|
||||||
|
|
||||||
|
properties[PROP_CONTENT_TYPE] =
|
||||||
|
g_param_spec_string ("content-type",
|
||||||
|
NULL, NULL, NULL,
|
||||||
|
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
|
||||||
|
properties[PROP_FILTERS] =
|
||||||
|
g_param_spec_string ("filters",
|
||||||
|
NULL, NULL, NULL,
|
||||||
|
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
|
||||||
|
|
||||||
|
g_object_class_install_properties (object_class, N_PROPS, properties);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
cc_default_apps_row_init (CcDefaultAppsRow *self)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
cc_default_apps_row_update_default_app (CcDefaultAppsRow *self)
|
||||||
|
{
|
||||||
|
GAppInfo *info;
|
||||||
|
g_autoptr(GError) error = NULL;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
info = G_APP_INFO (adw_combo_row_get_selected_item (ADW_COMBO_ROW (self)));
|
||||||
|
|
||||||
|
if (!info)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (g_app_info_set_as_default_for_type (info, self->content_type, &error) == FALSE)
|
||||||
|
{
|
||||||
|
g_warning ("Failed to set '%s' as the default app for '%s': %s",
|
||||||
|
g_app_info_get_name (info), self->content_type, error->message);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
g_debug ("Set '%s' as the default handler for '%s'",
|
||||||
|
g_app_info_get_name (info), self->content_type);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (self->filters)
|
||||||
|
{
|
||||||
|
g_auto(GStrv) entries = NULL;
|
||||||
|
const char *const *mime_types;
|
||||||
|
g_autoptr(GPtrArray) patterns = NULL;
|
||||||
|
|
||||||
|
entries = g_strsplit (self->filters, ";", -1);
|
||||||
|
patterns = g_ptr_array_new_with_free_func ((GDestroyNotify) g_pattern_spec_free);
|
||||||
|
for (i = 0; entries[i] != NULL; i++)
|
||||||
|
{
|
||||||
|
GPatternSpec *pattern = g_pattern_spec_new (entries[i]);
|
||||||
|
g_ptr_array_add (patterns, pattern);
|
||||||
|
}
|
||||||
|
|
||||||
|
mime_types = g_app_info_get_supported_types (info);
|
||||||
|
for (i = 0; mime_types && mime_types[i]; i++)
|
||||||
|
{
|
||||||
|
int j;
|
||||||
|
gboolean matched = FALSE;
|
||||||
|
g_autoptr(GError) local_error = NULL;
|
||||||
|
|
||||||
|
for (j = 0; j < patterns->len; j++)
|
||||||
|
{
|
||||||
|
GPatternSpec *pattern = g_ptr_array_index (patterns, j);
|
||||||
|
if (g_pattern_spec_match_string (pattern, mime_types[i]))
|
||||||
|
matched = TRUE;
|
||||||
|
}
|
||||||
|
if (!matched)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (g_app_info_set_as_default_for_type (info, mime_types[i], &local_error) == FALSE)
|
||||||
|
{
|
||||||
|
g_warning ("Failed to set '%s' as the default app for secondary "
|
||||||
|
"content type '%s': %s",
|
||||||
|
g_app_info_get_name (info), mime_types[i], local_error->message);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
g_debug ("Set '%s' as the default handler for '%s'",
|
||||||
|
g_app_info_get_name (info), mime_types[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
32
panels/applications/cc-default-apps-row.h
Normal file
32
panels/applications/cc-default-apps-row.h
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
|
||||||
|
*
|
||||||
|
* Copyright 2022 Christopher Davis <christopherdavis@gnome.org>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <adwaita.h>
|
||||||
|
|
||||||
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
|
#define CC_TYPE_DEFAULT_APPS_ROW (cc_default_apps_row_get_type ())
|
||||||
|
G_DECLARE_FINAL_TYPE (CcDefaultAppsRow, cc_default_apps_row, CC, DEFAULT_APPS_ROW, AdwComboRow)
|
||||||
|
|
||||||
|
void cc_default_apps_row_update_default_app (CcDefaultAppsRow *self);
|
||||||
|
|
||||||
|
G_END_DECLS
|
529
panels/applications/cc-removable-media-settings.c
Normal file
529
panels/applications/cc-removable-media-settings.c
Normal file
|
@ -0,0 +1,529 @@
|
||||||
|
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
|
||||||
|
*
|
||||||
|
* Copyright (C) 2017 Mohammed Sadiq <sadiq@sadiqpk.org>
|
||||||
|
* Copyright (C) 2010 Red Hat, Inc
|
||||||
|
* Copyright (C) 2008 William Jon McCann <jmccann@redhat.com>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <config.h>
|
||||||
|
|
||||||
|
#include <glib.h>
|
||||||
|
#include <glib/gi18n.h>
|
||||||
|
|
||||||
|
#include <shell/cc-panel.h>
|
||||||
|
|
||||||
|
#include "cc-applications-panel.h"
|
||||||
|
#include "cc-removable-media-settings.h"
|
||||||
|
|
||||||
|
/* Autorun options */
|
||||||
|
#define PREF_MEDIA_AUTORUN_NEVER "autorun-never"
|
||||||
|
#define PREF_MEDIA_AUTORUN_X_CONTENT_START_APP "autorun-x-content-start-app"
|
||||||
|
#define PREF_MEDIA_AUTORUN_X_CONTENT_IGNORE "autorun-x-content-ignore"
|
||||||
|
#define PREF_MEDIA_AUTORUN_X_CONTENT_OPEN_FOLDER "autorun-x-content-open-folder"
|
||||||
|
|
||||||
|
#define CUSTOM_ITEM_ASK "cc-item-ask"
|
||||||
|
#define CUSTOM_ITEM_DO_NOTHING "cc-item-do-nothing"
|
||||||
|
#define CUSTOM_ITEM_OPEN_FOLDER "cc-item-open-folder"
|
||||||
|
|
||||||
|
#define MEDIA_HANDLING_SCHEMA "org.gnome.desktop.media-handling"
|
||||||
|
|
||||||
|
struct _CcRemovableMediaSettings
|
||||||
|
{
|
||||||
|
AdwPreferencesGroup parent;
|
||||||
|
|
||||||
|
GtkAppChooserButton *audio_cdda_chooser;
|
||||||
|
GtkAppChooserButton *dcf_chooser;
|
||||||
|
GtkAppChooserButton *music_player_chooser;
|
||||||
|
AdwDialog *other_type_dialog;
|
||||||
|
AdwActionRow *other_action_row;
|
||||||
|
GtkBox *other_action_box;
|
||||||
|
GtkComboBox *other_type_combo_box;
|
||||||
|
GtkListStore *other_type_list_store;
|
||||||
|
GtkAppChooserButton *software_chooser;
|
||||||
|
GtkAppChooserButton *video_dvd_chooser;
|
||||||
|
|
||||||
|
GtkAppChooserButton *other_application_chooser;
|
||||||
|
GSettings *settings;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
G_DEFINE_TYPE (CcRemovableMediaSettings, cc_removable_media_settings, ADW_TYPE_PREFERENCES_GROUP)
|
||||||
|
|
||||||
|
static char **
|
||||||
|
remove_elem_from_str_array (char **v,
|
||||||
|
const char *s)
|
||||||
|
{
|
||||||
|
GPtrArray *array;
|
||||||
|
guint idx;
|
||||||
|
|
||||||
|
array = g_ptr_array_new ();
|
||||||
|
|
||||||
|
for (idx = 0; v[idx] != NULL; idx++) {
|
||||||
|
if (g_strcmp0 (v[idx], s) == 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_ptr_array_add (array, v[idx]);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_ptr_array_add (array, NULL);
|
||||||
|
|
||||||
|
g_free (v);
|
||||||
|
|
||||||
|
return (char **) g_ptr_array_free (array, FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static char **
|
||||||
|
add_elem_to_str_array (char **v,
|
||||||
|
const char *s)
|
||||||
|
{
|
||||||
|
GPtrArray *array;
|
||||||
|
guint idx;
|
||||||
|
|
||||||
|
array = g_ptr_array_new ();
|
||||||
|
|
||||||
|
for (idx = 0; v[idx] != NULL; idx++) {
|
||||||
|
g_ptr_array_add (array, v[idx]);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_ptr_array_add (array, g_strdup (s));
|
||||||
|
g_ptr_array_add (array, NULL);
|
||||||
|
|
||||||
|
g_free (v);
|
||||||
|
|
||||||
|
return (char **) g_ptr_array_free (array, FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
autorun_get_preferences (CcRemovableMediaSettings *self,
|
||||||
|
const char *x_content_type,
|
||||||
|
gboolean *pref_start_app,
|
||||||
|
gboolean *pref_ignore,
|
||||||
|
gboolean *pref_open_folder)
|
||||||
|
{
|
||||||
|
g_auto(GStrv) x_content_start_app = NULL;
|
||||||
|
g_auto(GStrv) x_content_ignore = NULL;
|
||||||
|
g_auto(GStrv) x_content_open_folder = NULL;
|
||||||
|
|
||||||
|
g_return_if_fail (pref_start_app != NULL);
|
||||||
|
g_return_if_fail (pref_ignore != NULL);
|
||||||
|
g_return_if_fail (pref_open_folder != NULL);
|
||||||
|
|
||||||
|
*pref_start_app = FALSE;
|
||||||
|
*pref_ignore = FALSE;
|
||||||
|
*pref_open_folder = FALSE;
|
||||||
|
x_content_start_app = g_settings_get_strv (self->settings,
|
||||||
|
PREF_MEDIA_AUTORUN_X_CONTENT_START_APP);
|
||||||
|
x_content_ignore = g_settings_get_strv (self->settings,
|
||||||
|
PREF_MEDIA_AUTORUN_X_CONTENT_IGNORE);
|
||||||
|
x_content_open_folder = g_settings_get_strv (self->settings,
|
||||||
|
PREF_MEDIA_AUTORUN_X_CONTENT_OPEN_FOLDER);
|
||||||
|
if (x_content_start_app != NULL) {
|
||||||
|
*pref_start_app = g_strv_contains ((const gchar * const *) x_content_start_app, x_content_type);
|
||||||
|
}
|
||||||
|
if (x_content_ignore != NULL) {
|
||||||
|
*pref_ignore = g_strv_contains ((const gchar * const *) x_content_ignore, x_content_type);
|
||||||
|
}
|
||||||
|
if (x_content_open_folder != NULL) {
|
||||||
|
*pref_open_folder = g_strv_contains ((const gchar * const *) x_content_open_folder, x_content_type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
autorun_set_preferences (CcRemovableMediaSettings *self,
|
||||||
|
const char *x_content_type,
|
||||||
|
gboolean pref_start_app,
|
||||||
|
gboolean pref_ignore,
|
||||||
|
gboolean pref_open_folder)
|
||||||
|
{
|
||||||
|
g_auto(GStrv) x_content_start_app = NULL;
|
||||||
|
g_auto(GStrv) x_content_ignore = NULL;
|
||||||
|
g_auto(GStrv) x_content_open_folder = NULL;
|
||||||
|
|
||||||
|
g_assert (x_content_type != NULL);
|
||||||
|
|
||||||
|
x_content_start_app = g_settings_get_strv (self->settings,
|
||||||
|
PREF_MEDIA_AUTORUN_X_CONTENT_START_APP);
|
||||||
|
x_content_ignore = g_settings_get_strv (self->settings,
|
||||||
|
PREF_MEDIA_AUTORUN_X_CONTENT_IGNORE);
|
||||||
|
x_content_open_folder = g_settings_get_strv (self->settings,
|
||||||
|
PREF_MEDIA_AUTORUN_X_CONTENT_OPEN_FOLDER);
|
||||||
|
|
||||||
|
x_content_start_app = remove_elem_from_str_array (x_content_start_app, x_content_type);
|
||||||
|
if (pref_start_app) {
|
||||||
|
x_content_start_app = add_elem_to_str_array (x_content_start_app, x_content_type);
|
||||||
|
}
|
||||||
|
g_settings_set_strv (self->settings,
|
||||||
|
PREF_MEDIA_AUTORUN_X_CONTENT_START_APP, (const gchar * const*) x_content_start_app);
|
||||||
|
|
||||||
|
x_content_ignore = remove_elem_from_str_array (x_content_ignore, x_content_type);
|
||||||
|
if (pref_ignore) {
|
||||||
|
x_content_ignore = add_elem_to_str_array (x_content_ignore, x_content_type);
|
||||||
|
}
|
||||||
|
g_settings_set_strv (self->settings,
|
||||||
|
PREF_MEDIA_AUTORUN_X_CONTENT_IGNORE, (const gchar * const*) x_content_ignore);
|
||||||
|
|
||||||
|
x_content_open_folder = remove_elem_from_str_array (x_content_open_folder, x_content_type);
|
||||||
|
if (pref_open_folder) {
|
||||||
|
x_content_open_folder = add_elem_to_str_array (x_content_open_folder, x_content_type);
|
||||||
|
}
|
||||||
|
g_settings_set_strv (self->settings,
|
||||||
|
PREF_MEDIA_AUTORUN_X_CONTENT_OPEN_FOLDER, (const gchar * const*) x_content_open_folder);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
on_custom_item_activated_cb (CcRemovableMediaSettings *self,
|
||||||
|
const gchar *item,
|
||||||
|
GtkAppChooser *app_chooser)
|
||||||
|
{
|
||||||
|
g_autofree gchar *content_type = NULL;
|
||||||
|
|
||||||
|
content_type = gtk_app_chooser_get_content_type (app_chooser);
|
||||||
|
|
||||||
|
if (g_strcmp0 (item, CUSTOM_ITEM_ASK) == 0) {
|
||||||
|
autorun_set_preferences (self, content_type,
|
||||||
|
FALSE, FALSE, FALSE);
|
||||||
|
} else if (g_strcmp0 (item, CUSTOM_ITEM_OPEN_FOLDER) == 0) {
|
||||||
|
autorun_set_preferences (self, content_type,
|
||||||
|
FALSE, FALSE, TRUE);
|
||||||
|
} else if (g_strcmp0 (item, CUSTOM_ITEM_DO_NOTHING) == 0) {
|
||||||
|
autorun_set_preferences (self, content_type,
|
||||||
|
FALSE, TRUE, FALSE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
on_chooser_changed_cb (CcRemovableMediaSettings *self,
|
||||||
|
GtkAppChooser *chooser)
|
||||||
|
{
|
||||||
|
g_autoptr(GAppInfo) info = NULL;
|
||||||
|
g_autofree gchar *content_type = NULL;
|
||||||
|
|
||||||
|
info = gtk_app_chooser_get_app_info (chooser);
|
||||||
|
|
||||||
|
if (info == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
content_type = gtk_app_chooser_get_content_type (chooser);
|
||||||
|
autorun_set_preferences (self, content_type,
|
||||||
|
TRUE, FALSE, FALSE);
|
||||||
|
g_app_info_set_as_default_for_type (info, content_type, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* FIXME: Port away from GtkAppChooserButton entirely */
|
||||||
|
static void
|
||||||
|
ellipsize_app_chooser (GtkAppChooserButton *button)
|
||||||
|
{
|
||||||
|
GtkWidget *child;
|
||||||
|
g_autoptr (GList) cells = NULL;
|
||||||
|
GtkCellRenderer *renderer;
|
||||||
|
|
||||||
|
g_assert (GTK_IS_APP_CHOOSER_BUTTON (button));
|
||||||
|
|
||||||
|
child = gtk_widget_get_first_child (GTK_WIDGET (button));
|
||||||
|
|
||||||
|
g_assert (GTK_IS_CELL_LAYOUT (child));
|
||||||
|
|
||||||
|
cells = gtk_cell_layout_get_cells (GTK_CELL_LAYOUT (child));
|
||||||
|
|
||||||
|
g_assert (g_list_length (cells) > 0);
|
||||||
|
|
||||||
|
renderer = g_list_last (cells)->data;
|
||||||
|
|
||||||
|
g_assert (GTK_IS_CELL_RENDERER_TEXT (renderer));
|
||||||
|
|
||||||
|
g_object_set (renderer, "ellipsize", PANGO_ELLIPSIZE_END, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
prepare_chooser (CcRemovableMediaSettings *self,
|
||||||
|
GtkAppChooserButton *button,
|
||||||
|
const gchar *heading)
|
||||||
|
{
|
||||||
|
gboolean pref_ask;
|
||||||
|
gboolean pref_start_app;
|
||||||
|
gboolean pref_ignore;
|
||||||
|
gboolean pref_open_folder;
|
||||||
|
g_autoptr(GAppInfo) info = NULL;
|
||||||
|
g_autofree gchar *content_type = NULL;
|
||||||
|
|
||||||
|
content_type = gtk_app_chooser_get_content_type (GTK_APP_CHOOSER (button));
|
||||||
|
|
||||||
|
/* fetch preferences for this content type */
|
||||||
|
autorun_get_preferences (self, content_type,
|
||||||
|
&pref_start_app, &pref_ignore, &pref_open_folder);
|
||||||
|
pref_ask = !pref_start_app && !pref_ignore && !pref_open_folder;
|
||||||
|
|
||||||
|
info = gtk_app_chooser_get_app_info (GTK_APP_CHOOSER (button));
|
||||||
|
|
||||||
|
/* append the separator only if we have >= 1 apps in the chooser */
|
||||||
|
if (info != NULL) {
|
||||||
|
gtk_app_chooser_button_append_separator (button);
|
||||||
|
}
|
||||||
|
|
||||||
|
gtk_app_chooser_button_append_custom_item (button, CUSTOM_ITEM_ASK,
|
||||||
|
_("Ask what to do"),
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
gtk_app_chooser_button_append_custom_item (button, CUSTOM_ITEM_DO_NOTHING,
|
||||||
|
_("Do nothing"),
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
gtk_app_chooser_button_append_custom_item (button, CUSTOM_ITEM_OPEN_FOLDER,
|
||||||
|
_("Open folder"),
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
gtk_app_chooser_button_set_show_dialog_item (button, TRUE);
|
||||||
|
|
||||||
|
if (heading)
|
||||||
|
gtk_app_chooser_button_set_heading (button, _(heading));
|
||||||
|
|
||||||
|
if (pref_ask) {
|
||||||
|
gtk_app_chooser_button_set_active_custom_item (button, CUSTOM_ITEM_ASK);
|
||||||
|
} else if (pref_ignore) {
|
||||||
|
gtk_app_chooser_button_set_active_custom_item (button, CUSTOM_ITEM_DO_NOTHING);
|
||||||
|
} else if (pref_open_folder) {
|
||||||
|
gtk_app_chooser_button_set_active_custom_item (button, CUSTOM_ITEM_OPEN_FOLDER);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_signal_connect_object (button, "changed",
|
||||||
|
G_CALLBACK (on_chooser_changed_cb), self, G_CONNECT_SWAPPED);
|
||||||
|
g_signal_connect_object (button, "custom-item-activated",
|
||||||
|
G_CALLBACK (on_custom_item_activated_cb), self, G_CONNECT_SWAPPED);
|
||||||
|
|
||||||
|
ellipsize_app_chooser (button);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
on_other_type_combo_box_changed (CcRemovableMediaSettings *self)
|
||||||
|
{
|
||||||
|
GtkTreeIter iter;
|
||||||
|
g_autofree gchar *x_content_type = NULL;
|
||||||
|
|
||||||
|
if (!gtk_combo_box_get_active_iter (self->other_type_combo_box, &iter)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
gtk_tree_model_get (GTK_TREE_MODEL (self->other_type_list_store), &iter,
|
||||||
|
1, &x_content_type,
|
||||||
|
-1);
|
||||||
|
|
||||||
|
if (self->other_application_chooser != NULL) {
|
||||||
|
gtk_box_remove (self->other_action_box, GTK_WIDGET (self->other_application_chooser));
|
||||||
|
self->other_application_chooser = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
self->other_application_chooser = GTK_APP_CHOOSER_BUTTON (gtk_app_chooser_button_new (x_content_type));
|
||||||
|
gtk_box_append (self->other_action_box, GTK_WIDGET (self->other_application_chooser));
|
||||||
|
prepare_chooser (self, self->other_application_chooser, NULL);
|
||||||
|
|
||||||
|
adw_action_row_set_activatable_widget (self->other_action_row, GTK_WIDGET (self->other_application_chooser));
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
on_extra_options_dialog_close_attempt (CcRemovableMediaSettings *self)
|
||||||
|
{
|
||||||
|
gtk_widget_set_visible (GTK_WIDGET (self->other_type_dialog), FALSE);
|
||||||
|
|
||||||
|
if (self->other_application_chooser != NULL) {
|
||||||
|
gtk_box_remove (self->other_action_box, GTK_WIDGET (self->other_application_chooser));
|
||||||
|
self->other_application_chooser = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return GDK_EVENT_PROPAGATE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
on_extra_options_button_clicked (CcRemovableMediaSettings *self)
|
||||||
|
{
|
||||||
|
/* update other_application_chooser */
|
||||||
|
on_other_type_combo_box_changed (self);
|
||||||
|
adw_dialog_present (self->other_type_dialog, GTK_WIDGET (self));
|
||||||
|
}
|
||||||
|
|
||||||
|
#define OFFSET(x) (G_STRUCT_OFFSET (CcRemovableMediaSettings, x))
|
||||||
|
#define WIDGET_FROM_OFFSET(x) (G_STRUCT_MEMBER (GtkWidget*, self, x))
|
||||||
|
|
||||||
|
static void
|
||||||
|
info_panel_setup_media (CcRemovableMediaSettings *self)
|
||||||
|
{
|
||||||
|
guint n;
|
||||||
|
GList *l, *content_types;
|
||||||
|
GtkTreeIter iter;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
gint widget_offset;
|
||||||
|
const gchar *content_type;
|
||||||
|
const gchar *heading;
|
||||||
|
} const defs[] = {
|
||||||
|
{ OFFSET (audio_cdda_chooser), "x-content/audio-cdda", N_("Select an app for audio CDs") },
|
||||||
|
{ OFFSET (video_dvd_chooser), "x-content/video-dvd", N_("Select an app for video DVDs") },
|
||||||
|
{ OFFSET (music_player_chooser), "x-content/audio-player", N_("Select an app to run when a music player is connected") },
|
||||||
|
{ OFFSET (dcf_chooser), "x-content/image-dcf", N_("Select an app to run when a camera is connected") },
|
||||||
|
{ OFFSET (software_chooser), "x-content/unix-software", N_("Select an app for software CDs") },
|
||||||
|
};
|
||||||
|
|
||||||
|
struct {
|
||||||
|
const gchar *content_type;
|
||||||
|
const gchar *description;
|
||||||
|
} const other_defs[] = {
|
||||||
|
/* translators: these strings are duplicates of shared-mime-info
|
||||||
|
* strings, just here to fix capitalization of the English originals.
|
||||||
|
* If the shared-mime-info translation works for your language,
|
||||||
|
* simply leave these untranslated.
|
||||||
|
*/
|
||||||
|
{ "x-content/audio-dvd", N_("audio DVD") },
|
||||||
|
{ "x-content/blank-bd", N_("blank Blu-ray disc") },
|
||||||
|
{ "x-content/blank-cd", N_("blank CD disc") },
|
||||||
|
{ "x-content/blank-dvd", N_("blank DVD disc") },
|
||||||
|
{ "x-content/blank-hddvd", N_("blank HD DVD disc") },
|
||||||
|
{ "x-content/video-bluray", N_("Blu-ray video disc") },
|
||||||
|
{ "x-content/ebook-reader", N_("e-book reader") },
|
||||||
|
{ "x-content/video-hddvd", N_("HD DVD video disc") },
|
||||||
|
{ "x-content/image-picturecd", N_("Picture CD") },
|
||||||
|
{ "x-content/video-svcd", N_("Super Video CD") },
|
||||||
|
{ "x-content/video-vcd", N_("Video CD") },
|
||||||
|
{ "x-content/win32-software", N_("Windows software") },
|
||||||
|
};
|
||||||
|
|
||||||
|
for (n = 0; n < G_N_ELEMENTS (defs); n++) {
|
||||||
|
prepare_chooser (self,
|
||||||
|
GTK_APP_CHOOSER_BUTTON (WIDGET_FROM_OFFSET (defs[n].widget_offset)),
|
||||||
|
defs[n].heading);
|
||||||
|
}
|
||||||
|
|
||||||
|
gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (self->other_type_list_store),
|
||||||
|
1, GTK_SORT_ASCENDING);
|
||||||
|
|
||||||
|
|
||||||
|
content_types = g_content_types_get_registered ();
|
||||||
|
|
||||||
|
for (l = content_types; l != NULL; l = l->next) {
|
||||||
|
char *content_type = l->data;
|
||||||
|
g_autofree char *description = NULL;
|
||||||
|
|
||||||
|
if (!g_str_has_prefix (content_type, "x-content/"))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
for (n = 0; n < G_N_ELEMENTS (defs); n++) {
|
||||||
|
if (g_content_type_is_a (content_type, defs[n].content_type)) {
|
||||||
|
goto skip;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (n = 0; n < G_N_ELEMENTS (other_defs); n++) {
|
||||||
|
if (strcmp (content_type, other_defs[n].content_type) == 0) {
|
||||||
|
const gchar *s = other_defs[n].description;
|
||||||
|
if (s == _(s))
|
||||||
|
description = g_content_type_get_description (content_type);
|
||||||
|
else
|
||||||
|
description = g_strdup (_(s));
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (description == NULL) {
|
||||||
|
g_debug ("Content type '%s' is missing from the info panel", content_type);
|
||||||
|
description = g_content_type_get_description (content_type);
|
||||||
|
}
|
||||||
|
|
||||||
|
gtk_list_store_append (self->other_type_list_store, &iter);
|
||||||
|
|
||||||
|
gtk_list_store_set (self->other_type_list_store, &iter,
|
||||||
|
0, description,
|
||||||
|
1, content_type,
|
||||||
|
-1);
|
||||||
|
skip:
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_list_free_full (content_types, g_free);
|
||||||
|
|
||||||
|
gtk_combo_box_set_active (self->other_type_combo_box, 0);
|
||||||
|
|
||||||
|
g_settings_bind (self->settings,
|
||||||
|
PREF_MEDIA_AUTORUN_NEVER,
|
||||||
|
self,
|
||||||
|
"sensitive",
|
||||||
|
G_SETTINGS_BIND_INVERT_BOOLEAN);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
cc_removable_media_settings_finalize (GObject *object)
|
||||||
|
{
|
||||||
|
CcRemovableMediaSettings *self = CC_REMOVABLE_MEDIA_SETTINGS (object);
|
||||||
|
|
||||||
|
g_clear_object (&self->settings);
|
||||||
|
|
||||||
|
G_OBJECT_CLASS (cc_removable_media_settings_parent_class)->finalize (object);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
cc_removable_media_settings_dispose (GObject *object)
|
||||||
|
{
|
||||||
|
CcRemovableMediaSettings *self = CC_REMOVABLE_MEDIA_SETTINGS (object);
|
||||||
|
|
||||||
|
g_clear_pointer ((AdwDialog **) &self->other_type_dialog, adw_dialog_force_close);
|
||||||
|
|
||||||
|
G_OBJECT_CLASS (cc_removable_media_settings_parent_class)->dispose (object);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
cc_removable_media_settings_class_init (CcRemovableMediaSettingsClass *klass)
|
||||||
|
{
|
||||||
|
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||||
|
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
|
||||||
|
|
||||||
|
object_class->finalize = cc_removable_media_settings_finalize;
|
||||||
|
object_class->dispose = cc_removable_media_settings_dispose;
|
||||||
|
|
||||||
|
gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/control-center/applications/cc-removable-media-settings.ui");
|
||||||
|
|
||||||
|
gtk_widget_class_bind_template_child (widget_class, CcRemovableMediaSettings, audio_cdda_chooser);
|
||||||
|
gtk_widget_class_bind_template_child (widget_class, CcRemovableMediaSettings, dcf_chooser);
|
||||||
|
gtk_widget_class_bind_template_child (widget_class, CcRemovableMediaSettings, music_player_chooser);
|
||||||
|
gtk_widget_class_bind_template_child (widget_class, CcRemovableMediaSettings, other_type_dialog);
|
||||||
|
gtk_widget_class_bind_template_child (widget_class, CcRemovableMediaSettings, other_action_row);
|
||||||
|
gtk_widget_class_bind_template_child (widget_class, CcRemovableMediaSettings, other_action_box);
|
||||||
|
gtk_widget_class_bind_template_child (widget_class, CcRemovableMediaSettings, other_type_combo_box);
|
||||||
|
gtk_widget_class_bind_template_child (widget_class, CcRemovableMediaSettings, other_type_list_store);
|
||||||
|
gtk_widget_class_bind_template_child (widget_class, CcRemovableMediaSettings, software_chooser);
|
||||||
|
gtk_widget_class_bind_template_child (widget_class, CcRemovableMediaSettings, video_dvd_chooser);
|
||||||
|
|
||||||
|
gtk_widget_class_bind_template_callback (widget_class, on_extra_options_dialog_close_attempt);
|
||||||
|
gtk_widget_class_bind_template_callback (widget_class, on_extra_options_button_clicked);
|
||||||
|
gtk_widget_class_bind_template_callback (widget_class, on_other_type_combo_box_changed);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
cc_removable_media_settings_init (CcRemovableMediaSettings *self)
|
||||||
|
{
|
||||||
|
gtk_widget_init_template (GTK_WIDGET (self));
|
||||||
|
self->settings = g_settings_new (MEDIA_HANDLING_SCHEMA);
|
||||||
|
|
||||||
|
info_panel_setup_media (self);
|
||||||
|
}
|
||||||
|
|
||||||
|
CcRemovableMediaSettings *
|
||||||
|
cc_removable_media_settings_new (void)
|
||||||
|
{
|
||||||
|
return g_object_new (CC_TYPE_REMOVABLE_MEDIA_SETTINGS,
|
||||||
|
NULL);
|
||||||
|
}
|
31
panels/applications/cc-removable-media-settings.h
Normal file
31
panels/applications/cc-removable-media-settings.h
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
|
||||||
|
*
|
||||||
|
* Copyright (C) 2017 Mohammed Sadiq <sadiq@sadiqpk.org>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <adwaita.h>
|
||||||
|
|
||||||
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
|
#define CC_TYPE_REMOVABLE_MEDIA_SETTINGS (cc_removable_media_settings_get_type ())
|
||||||
|
G_DECLARE_FINAL_TYPE (CcRemovableMediaSettings, cc_removable_media_settings, CC, REMOVABLE_MEDIA_SETTINGS, AdwPreferencesGroup)
|
||||||
|
|
||||||
|
CcRemovableMediaSettings* cc_removable_media_settings_new (void);
|
||||||
|
|
||||||
|
G_END_DECLS
|
148
panels/applications/cc-removable-media-settings.ui
Normal file
148
panels/applications/cc-removable-media-settings.ui
Normal file
|
@ -0,0 +1,148 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<interface>
|
||||||
|
<template class="CcRemovableMediaSettings" parent="AdwPreferencesGroup">
|
||||||
|
<child>
|
||||||
|
<object class="AdwActionRow">
|
||||||
|
<property name="title" translatable="yes">CD _Audio</property>
|
||||||
|
<property name="use_underline">True</property>
|
||||||
|
<property name="activatable_widget">audio_cdda_chooser</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkAppChooserButton" id="audio_cdda_chooser">
|
||||||
|
<property name="valign">center</property>
|
||||||
|
<property name="content_type">x-content/audio-cdda</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="AdwActionRow">
|
||||||
|
<property name="title" translatable="yes">_DVD Video</property>
|
||||||
|
<property name="use_underline">True</property>
|
||||||
|
<property name="activatable_widget">video_dvd_chooser</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkAppChooserButton" id="video_dvd_chooser">
|
||||||
|
<property name="valign">center</property>
|
||||||
|
<property name="content_type">x-content/video-dvd</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="AdwActionRow">
|
||||||
|
<property name="title" translatable="yes">Music Pla_yer</property>
|
||||||
|
<property name="use_underline">True</property>
|
||||||
|
<property name="activatable_widget">music_player_chooser</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkAppChooserButton" id="music_player_chooser">
|
||||||
|
<property name="valign">center</property>
|
||||||
|
<property name="content_type">x-content/audio-player</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="AdwActionRow">
|
||||||
|
<property name="title" translatable="yes">P_hotos</property>
|
||||||
|
<property name="use_underline">True</property>
|
||||||
|
<property name="activatable_widget">dcf_chooser</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkAppChooserButton" id="dcf_chooser">
|
||||||
|
<property name="valign">center</property>
|
||||||
|
<property name="content_type">x-content/image-dcf</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="AdwActionRow">
|
||||||
|
<property name="title" translatable="yes">Sof_tware</property>
|
||||||
|
<property name="use_underline">True</property>
|
||||||
|
<property name="activatable_widget">software_chooser</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkAppChooserButton" id="software_chooser">
|
||||||
|
<property name="valign">center</property>
|
||||||
|
<property name="content_type">x-content/unix-software</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="CcListRow">
|
||||||
|
<property name="title" translatable="yes">_Other Media Types</property>
|
||||||
|
<property name="show-arrow">True</property>
|
||||||
|
<signal name="activated" handler="on_extra_options_button_clicked" object="CcRemovableMediaSettings"/>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<object class="GtkSizeGroup">
|
||||||
|
<widgets>
|
||||||
|
<widget name="audio_cdda_chooser"/>
|
||||||
|
<widget name="video_dvd_chooser"/>
|
||||||
|
<widget name="music_player_chooser"/>
|
||||||
|
<widget name="dcf_chooser"/>
|
||||||
|
<widget name="software_chooser"/>
|
||||||
|
</widgets>
|
||||||
|
</object>
|
||||||
|
|
||||||
|
<object class="AdwDialog" id="other_type_dialog">
|
||||||
|
<property name="title" translatable="yes">Other Media Types</property>
|
||||||
|
<property name="content-width">360</property>
|
||||||
|
<property name="content-height">294</property>
|
||||||
|
<signal name="close-attempt" handler="on_extra_options_dialog_close_attempt" object="CcRemovableMediaSettings" swapped="yes"/>
|
||||||
|
<property name="child">
|
||||||
|
<object class="AdwToolbarView">
|
||||||
|
<child type="top">
|
||||||
|
<object class="AdwHeaderBar"/>
|
||||||
|
</child>
|
||||||
|
<property name="content">
|
||||||
|
<object class="AdwPreferencesPage">
|
||||||
|
<child>
|
||||||
|
<object class="AdwPreferencesGroup">
|
||||||
|
<child>
|
||||||
|
<object class="AdwActionRow">
|
||||||
|
<property name="title" translatable="yes">_Type</property>
|
||||||
|
<property name="use-underline">True</property>
|
||||||
|
<property name="activatable-widget">other_type_combo_box</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkComboBox" id="other_type_combo_box">
|
||||||
|
<property name="model">other_type_list_store</property>
|
||||||
|
<property name="valign">center</property>
|
||||||
|
<signal name="changed" handler="on_other_type_combo_box_changed" object="CcRemovableMediaSettings" swapped="yes"/>
|
||||||
|
<child>
|
||||||
|
<object class="GtkCellRendererText"/>
|
||||||
|
<attributes>
|
||||||
|
<attribute name="text">0</attribute>
|
||||||
|
</attributes>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="AdwActionRow" id="other_action_row">
|
||||||
|
<property name="title" translatable="yes">_Action</property>
|
||||||
|
<property name="use-underline">True</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkBox" id="other_action_box">
|
||||||
|
<property name="valign">center</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</property>
|
||||||
|
</object>
|
||||||
|
</property>
|
||||||
|
</object>
|
||||||
|
<object class="GtkListStore" id="other_type_list_store">
|
||||||
|
<columns>
|
||||||
|
<!-- column-name description -->
|
||||||
|
<column type="gchararray"/>
|
||||||
|
<!-- column-name content-type -->
|
||||||
|
<column type="gchararray"/>
|
||||||
|
</columns>
|
||||||
|
</object>
|
||||||
|
</interface>
|
455
panels/applications/cc-snap-row.c
Normal file
455
panels/applications/cc-snap-row.c
Normal file
|
@ -0,0 +1,455 @@
|
||||||
|
/* cc-snap-row.c
|
||||||
|
*
|
||||||
|
* Copyright 2019 Canonical Ltd.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <config.h>
|
||||||
|
#include <glib/gi18n.h>
|
||||||
|
|
||||||
|
#include "cc-snap-row.h"
|
||||||
|
#include "cc-applications-resources.h"
|
||||||
|
#include "cc-snapd-client.h"
|
||||||
|
|
||||||
|
#define CHANGE_POLL_TIME 100
|
||||||
|
|
||||||
|
struct _CcSnapRow
|
||||||
|
{
|
||||||
|
AdwActionRow parent;
|
||||||
|
|
||||||
|
GtkSwitch *slot_toggle;
|
||||||
|
GtkComboBox *slots_combo;
|
||||||
|
GtkListStore *slots_combo_model;
|
||||||
|
|
||||||
|
GCancellable *cancellable;
|
||||||
|
|
||||||
|
CcSnapdClient *client;
|
||||||
|
JsonObject *plug;
|
||||||
|
JsonObject *connected_slot;
|
||||||
|
JsonArray *slots;
|
||||||
|
JsonObject *target_slot;
|
||||||
|
|
||||||
|
gchar *change_id;
|
||||||
|
guint change_timeout;
|
||||||
|
};
|
||||||
|
|
||||||
|
G_DEFINE_TYPE (CcSnapRow, cc_snap_row, ADW_TYPE_ACTION_ROW)
|
||||||
|
|
||||||
|
static void
|
||||||
|
update_state (CcSnapRow *self)
|
||||||
|
{
|
||||||
|
gboolean have_single_option;
|
||||||
|
GtkTreeIter iter;
|
||||||
|
|
||||||
|
have_single_option = json_array_get_length (self->slots) == 1;
|
||||||
|
gtk_widget_set_visible (GTK_WIDGET (self->slot_toggle), have_single_option);
|
||||||
|
gtk_widget_set_visible (GTK_WIDGET (self->slots_combo), !have_single_option);
|
||||||
|
|
||||||
|
gtk_switch_set_active (self->slot_toggle, self->connected_slot != NULL);
|
||||||
|
|
||||||
|
if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (self->slots_combo_model), &iter))
|
||||||
|
{
|
||||||
|
do
|
||||||
|
{
|
||||||
|
JsonObject *slot;
|
||||||
|
|
||||||
|
gtk_tree_model_get (GTK_TREE_MODEL (self->slots_combo_model), &iter, 0, &slot, -1);
|
||||||
|
if (slot == self->connected_slot)
|
||||||
|
gtk_combo_box_set_active_iter (self->slots_combo, &iter);
|
||||||
|
} while (gtk_tree_model_iter_next (GTK_TREE_MODEL (self->slots_combo_model), &iter));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
disable_controls (CcSnapRow *self)
|
||||||
|
{
|
||||||
|
gtk_widget_set_sensitive (GTK_WIDGET (self->slot_toggle), FALSE);
|
||||||
|
gtk_widget_set_sensitive (GTK_WIDGET (self->slots_combo), FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
enable_controls (CcSnapRow *self)
|
||||||
|
{
|
||||||
|
gtk_widget_set_sensitive (GTK_WIDGET (self->slot_toggle), TRUE);
|
||||||
|
gtk_widget_set_sensitive (GTK_WIDGET (self->slots_combo), TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
change_complete (CcSnapRow *self)
|
||||||
|
{
|
||||||
|
g_clear_object (&self->client);
|
||||||
|
g_clear_pointer (&self->target_slot, json_object_unref);
|
||||||
|
g_clear_pointer (&self->change_id, g_free);
|
||||||
|
g_clear_handle_id (&self->change_timeout, g_source_remove);
|
||||||
|
|
||||||
|
update_state (self);
|
||||||
|
enable_controls (self);
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
poll_change_cb (gpointer user_data)
|
||||||
|
{
|
||||||
|
CcSnapRow *self = user_data;
|
||||||
|
g_autoptr(JsonObject) change = NULL;
|
||||||
|
g_autoptr(GError) error = NULL;
|
||||||
|
|
||||||
|
change = cc_snapd_client_get_change_sync (self->client, self->change_id, self->cancellable, &error);
|
||||||
|
if (change == NULL)
|
||||||
|
{
|
||||||
|
g_warning ("Failed to monitor change %s: %s", self->change_id, error->message);
|
||||||
|
change_complete (self);
|
||||||
|
return G_SOURCE_REMOVE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (json_object_get_boolean_member (change, "ready"))
|
||||||
|
{
|
||||||
|
const gchar *status = json_object_get_string_member (change, "status");
|
||||||
|
|
||||||
|
if (g_strcmp0 (status, "Done") == 0)
|
||||||
|
{
|
||||||
|
g_clear_pointer (&self->connected_slot, json_object_unref);
|
||||||
|
self->connected_slot = self->target_slot ? json_object_ref (self->target_slot) : NULL;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
g_warning ("Change completed with status %s", status);
|
||||||
|
}
|
||||||
|
|
||||||
|
change_complete (self);
|
||||||
|
return G_SOURCE_REMOVE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return G_SOURCE_CONTINUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
monitor_change (CcSnapRow *self, const gchar *change_id)
|
||||||
|
{
|
||||||
|
g_free (self->change_id);
|
||||||
|
self->change_id = g_strdup (change_id);
|
||||||
|
g_clear_handle_id (&self->change_timeout, g_source_remove);
|
||||||
|
self->change_timeout = g_timeout_add (CHANGE_POLL_TIME, poll_change_cb, self);
|
||||||
|
}
|
||||||
|
|
||||||
|
static CcSnapdClient *
|
||||||
|
get_client(CcSnapRow *self)
|
||||||
|
{
|
||||||
|
if (self->client == NULL)
|
||||||
|
self->client = cc_snapd_client_new ();
|
||||||
|
return self->client;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
connect_plug (CcSnapRow *self, JsonObject *slot)
|
||||||
|
{
|
||||||
|
g_autofree gchar *change_id = NULL;
|
||||||
|
g_autoptr(GError) error = NULL;
|
||||||
|
|
||||||
|
/* already connected */
|
||||||
|
if (self->connected_slot != NULL &&
|
||||||
|
g_strcmp0 (json_object_get_string_member (self->connected_slot, "snap"),
|
||||||
|
json_object_get_string_member (slot, "snap")) == 0 &&
|
||||||
|
g_strcmp0 (json_object_get_string_member (self->connected_slot, "slot"),
|
||||||
|
json_object_get_string_member (slot, "slot")) == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
disable_controls (self);
|
||||||
|
|
||||||
|
change_id = cc_snapd_client_connect_interface_sync (get_client (self),
|
||||||
|
json_object_get_string_member (self->plug, "snap"),
|
||||||
|
json_object_get_string_member (self->plug, "plug"),
|
||||||
|
json_object_get_string_member (slot, "snap"),
|
||||||
|
json_object_get_string_member (slot, "slot"),
|
||||||
|
self->cancellable,
|
||||||
|
&error);
|
||||||
|
if (change_id == NULL)
|
||||||
|
{
|
||||||
|
g_warning ("Failed to connect plug: %s", error->message);
|
||||||
|
change_complete (self);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_clear_pointer (&self->target_slot, json_object_unref);
|
||||||
|
self->target_slot = json_object_ref (slot);
|
||||||
|
monitor_change (self, change_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
disconnect_plug (CcSnapRow *self)
|
||||||
|
{
|
||||||
|
g_autofree gchar *change_id = NULL;
|
||||||
|
g_autoptr(GError) error = NULL;
|
||||||
|
|
||||||
|
/* already disconnected */
|
||||||
|
if (self->connected_slot == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
disable_controls (self);
|
||||||
|
|
||||||
|
change_id = cc_snapd_client_disconnect_interface_sync (get_client (self),
|
||||||
|
json_object_get_string_member (self->plug, "snap"),
|
||||||
|
json_object_get_string_member (self->plug, "plug"),
|
||||||
|
"", "",
|
||||||
|
self->cancellable, &error);
|
||||||
|
if (change_id == NULL)
|
||||||
|
{
|
||||||
|
g_warning ("Failed to disconnect plug: %s", error->message);
|
||||||
|
change_complete (self);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_clear_pointer (&self->target_slot, json_object_unref);
|
||||||
|
monitor_change (self, change_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
switch_changed_cb (CcSnapRow *self)
|
||||||
|
{
|
||||||
|
if (gtk_switch_get_active (self->slot_toggle))
|
||||||
|
{
|
||||||
|
if (json_array_get_length (self->slots) == 1)
|
||||||
|
connect_plug (self, json_array_get_object_element (self->slots, 0));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
disconnect_plug (self);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
combo_changed_cb (CcSnapRow *self)
|
||||||
|
{
|
||||||
|
GtkTreeIter iter;
|
||||||
|
JsonObject *slot = NULL;
|
||||||
|
|
||||||
|
if (!gtk_combo_box_get_active_iter (self->slots_combo, &iter))
|
||||||
|
return;
|
||||||
|
|
||||||
|
gtk_tree_model_get (GTK_TREE_MODEL (self->slots_combo_model), &iter, 0, &slot, -1);
|
||||||
|
if (slot != NULL)
|
||||||
|
connect_plug (self, slot);
|
||||||
|
else
|
||||||
|
disconnect_plug (self);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const gchar *
|
||||||
|
make_interface_label (const gchar *interface_name)
|
||||||
|
{
|
||||||
|
if (strcmp (interface_name, "account-control") == 0)
|
||||||
|
return _("Add user accounts and change passwords");
|
||||||
|
else if (strcmp (interface_name, "alsa") == 0)
|
||||||
|
return _("Play and record sound");
|
||||||
|
else if (strcmp (interface_name, "audio-playback") == 0)
|
||||||
|
return _("Play audio");
|
||||||
|
else if (strcmp (interface_name, "audio-record") == 0)
|
||||||
|
return _("Record audio");
|
||||||
|
else if (strcmp (interface_name, "avahi-observe") == 0)
|
||||||
|
return _("Detect network devices using mDNS/DNS-SD (Bonjour/zeroconf)");
|
||||||
|
else if (strcmp (interface_name, "bluetooth-control") == 0)
|
||||||
|
return _("Access bluetooth hardware directly");
|
||||||
|
else if (strcmp (interface_name, "bluez") == 0)
|
||||||
|
return _("Use bluetooth devices");
|
||||||
|
else if (strcmp (interface_name, "camera") == 0)
|
||||||
|
return _("Use your camera");
|
||||||
|
else if (strcmp (interface_name, "cups-control") == 0)
|
||||||
|
return _("Print documents");
|
||||||
|
else if (strcmp (interface_name, "joystick") == 0)
|
||||||
|
return _("Use any connected joystick");
|
||||||
|
else if (strcmp (interface_name, "docker") == 0)
|
||||||
|
return _("Allow connecting to the Docker service");
|
||||||
|
else if (strcmp (interface_name, "firewall-control") == 0)
|
||||||
|
return _("Configure network firewall");
|
||||||
|
else if (strcmp (interface_name, "fuse-support") == 0)
|
||||||
|
return _("Setup and use privileged FUSE filesystems");
|
||||||
|
else if (strcmp (interface_name, "fwupd") == 0)
|
||||||
|
return _("Update firmware on this device");
|
||||||
|
else if (strcmp (interface_name, "hardware-observe") == 0)
|
||||||
|
return _("Access hardware information");
|
||||||
|
else if (strcmp (interface_name, "hardware-random-control") == 0)
|
||||||
|
return _("Provide entropy to hardware random number generator");
|
||||||
|
else if (strcmp (interface_name, "hardware-random-observe") == 0)
|
||||||
|
return _("Use hardware-generated random numbers");
|
||||||
|
else if (strcmp (interface_name, "home") == 0)
|
||||||
|
return _("Access files in your home folder");
|
||||||
|
else if (strcmp (interface_name, "libvirt") == 0)
|
||||||
|
return _("Access libvirt service");
|
||||||
|
else if (strcmp (interface_name, "locale-control") == 0)
|
||||||
|
return _("Change system language and region settings");
|
||||||
|
else if (strcmp (interface_name, "location-control") == 0)
|
||||||
|
return _("Change location settings and providers");
|
||||||
|
else if (strcmp (interface_name, "location-observe") == 0)
|
||||||
|
return _("Access your location");
|
||||||
|
else if (strcmp (interface_name, "log-observe") == 0)
|
||||||
|
return _("Read system and application logs");
|
||||||
|
else if (strcmp (interface_name, "lxd") == 0)
|
||||||
|
return _("Access LXD service");
|
||||||
|
else if (strcmp (interface_name, "modem-manager") == 0)
|
||||||
|
return _("Use and configure modems");
|
||||||
|
else if (strcmp (interface_name, "mount-observe") == 0)
|
||||||
|
return _("Read system mount information and disk quotas");
|
||||||
|
else if (strcmp (interface_name, "mpris") == 0)
|
||||||
|
return _("Control music and video players");
|
||||||
|
else if (strcmp (interface_name, "network-control") == 0)
|
||||||
|
return _("Change low-level network settings");
|
||||||
|
else if (strcmp (interface_name, "network-manager") == 0)
|
||||||
|
return _("Access the NetworkManager service to read and change network settings");
|
||||||
|
else if (strcmp (interface_name, "network-observe") == 0)
|
||||||
|
return _("Read access to network settings");
|
||||||
|
else if (strcmp (interface_name, "network-setup-control") == 0)
|
||||||
|
return _("Change network settings");
|
||||||
|
else if (strcmp (interface_name, "network-setup-observe") == 0)
|
||||||
|
return _("Read network settings");
|
||||||
|
else if (strcmp (interface_name, "ofono") == 0)
|
||||||
|
return _("Access the ofono service to read and change network settings for mobile telephony");
|
||||||
|
else if (strcmp (interface_name, "openvswitch") == 0)
|
||||||
|
return _("Control Open vSwitch hardware");
|
||||||
|
else if (strcmp (interface_name, "optical-drive") == 0)
|
||||||
|
return _("Read from CD/DVD");
|
||||||
|
else if (strcmp (interface_name, "password-manager-service") == 0)
|
||||||
|
return _("Read, add, change, or remove saved passwords");
|
||||||
|
else if (strcmp (interface_name, "ppp") == 0)
|
||||||
|
return _("Access pppd and ppp devices for configuring Point-to-Point Protocol connections");
|
||||||
|
else if (strcmp (interface_name, "process-control") == 0)
|
||||||
|
return _("Pause or end any process on the system");
|
||||||
|
else if (strcmp (interface_name, "pulseaudio") == 0)
|
||||||
|
return _("Play and record sound");
|
||||||
|
else if (strcmp (interface_name, "raw-usb") == 0)
|
||||||
|
return _("Access USB hardware directly");
|
||||||
|
else if (strcmp (interface_name, "removable-media") == 0)
|
||||||
|
return _("Read/write files on removable storage devices");
|
||||||
|
else if (strcmp (interface_name, "screen-inhibit-control") == 0)
|
||||||
|
return _("Prevent screen sleep/lock");
|
||||||
|
else if (strcmp (interface_name, "serial-port") == 0)
|
||||||
|
return _("Access serial port hardware");
|
||||||
|
else if (strcmp (interface_name, "shutdown") == 0)
|
||||||
|
return _("Restart or power off the device");
|
||||||
|
else if (strcmp (interface_name, "snapd-control") == 0)
|
||||||
|
return _("Install, remove and configure software");
|
||||||
|
else if (strcmp (interface_name, "storage-framework-service") == 0)
|
||||||
|
return _("Access Storage Framework service");
|
||||||
|
else if (strcmp (interface_name, "system-observe") == 0)
|
||||||
|
return _("Read process and system information");
|
||||||
|
else if (strcmp (interface_name, "system-trace") == 0)
|
||||||
|
return _("Monitor and control any running program");
|
||||||
|
else if (strcmp (interface_name, "time-control") == 0)
|
||||||
|
return _("Change the date and time");
|
||||||
|
else if (strcmp (interface_name, "timeserver-control") == 0)
|
||||||
|
return _("Change time server settings");
|
||||||
|
else if (strcmp (interface_name, "timezone-control") == 0)
|
||||||
|
return _("Change the time zone");
|
||||||
|
else if (strcmp (interface_name, "udisks2") == 0)
|
||||||
|
return _("Access the UDisks2 service for configuring disks and removable media");
|
||||||
|
else if (strcmp (interface_name, "upower-observe") == 0)
|
||||||
|
return _("Access energy usage data");
|
||||||
|
else if (strcmp (interface_name, "u2f-devices") == 0)
|
||||||
|
return _("Read/write access to U2F devices exposed");
|
||||||
|
else
|
||||||
|
return interface_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
cc_snap_row_finalize (GObject *object)
|
||||||
|
{
|
||||||
|
CcSnapRow *self = CC_SNAP_ROW (object);
|
||||||
|
|
||||||
|
g_clear_object (&self->cancellable);
|
||||||
|
g_clear_object (&self->client);
|
||||||
|
g_clear_pointer (&self->plug, json_object_unref);
|
||||||
|
g_clear_pointer (&self->slots, json_array_unref);
|
||||||
|
g_clear_pointer (&self->target_slot, json_object_unref);
|
||||||
|
g_clear_pointer (&self->change_id, g_free);
|
||||||
|
g_clear_handle_id (&self->change_timeout, g_source_remove);
|
||||||
|
self->change_timeout = 0;
|
||||||
|
|
||||||
|
G_OBJECT_CLASS (cc_snap_row_parent_class)->finalize (object);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
cc_snap_row_class_init (CcSnapRowClass *klass)
|
||||||
|
{
|
||||||
|
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||||
|
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
|
||||||
|
|
||||||
|
object_class->finalize = cc_snap_row_finalize;
|
||||||
|
|
||||||
|
gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/control-center/applications/cc-snap-row.ui");
|
||||||
|
|
||||||
|
gtk_widget_class_bind_template_child (widget_class, CcSnapRow, slot_toggle);
|
||||||
|
gtk_widget_class_bind_template_child (widget_class, CcSnapRow, slots_combo);
|
||||||
|
gtk_widget_class_bind_template_child (widget_class, CcSnapRow, slots_combo_model);
|
||||||
|
|
||||||
|
gtk_widget_class_bind_template_callback (widget_class, combo_changed_cb);
|
||||||
|
gtk_widget_class_bind_template_callback (widget_class, switch_changed_cb);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
cc_snap_row_init (CcSnapRow *self)
|
||||||
|
{
|
||||||
|
gtk_widget_init_template (GTK_WIDGET (self));
|
||||||
|
}
|
||||||
|
|
||||||
|
CcSnapRow *
|
||||||
|
cc_snap_row_new (GCancellable *cancellable, JsonObject *plug, JsonArray *slots)
|
||||||
|
{
|
||||||
|
CcSnapRow *self;
|
||||||
|
const gchar *label = NULL;
|
||||||
|
GtkTreeIter iter;
|
||||||
|
|
||||||
|
self = g_object_new (CC_TYPE_SNAP_ROW, NULL);
|
||||||
|
|
||||||
|
self->cancellable = g_object_ref (cancellable);
|
||||||
|
self->plug = json_object_ref (plug);
|
||||||
|
self->slots = json_array_ref (slots);
|
||||||
|
|
||||||
|
if (json_object_has_member (plug, "connections"))
|
||||||
|
{
|
||||||
|
JsonArray *connected_slots = json_object_get_array_member (plug, "connections");
|
||||||
|
JsonObject *connected_slot_ref = json_array_get_object_element (connected_slots, 0);
|
||||||
|
|
||||||
|
for (guint i = 0; i < json_array_get_length (slots); i++)
|
||||||
|
{
|
||||||
|
JsonObject *slot = json_array_get_object_element (slots, i);
|
||||||
|
|
||||||
|
if (g_strcmp0 (json_object_get_string_member (slot, "snap"),
|
||||||
|
json_object_get_string_member (connected_slot_ref, "snap")) == 0 &&
|
||||||
|
g_strcmp0 (json_object_get_string_member (slot, "slot"),
|
||||||
|
json_object_get_string_member (connected_slot_ref, "slot")) == 0)
|
||||||
|
self->connected_slot = slot;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
label = make_interface_label (json_object_get_string_member (plug, "interface"));
|
||||||
|
adw_preferences_row_set_title (ADW_PREFERENCES_ROW (self), label);
|
||||||
|
|
||||||
|
/* Add option into combo box */
|
||||||
|
gtk_list_store_append (self->slots_combo_model, &iter);
|
||||||
|
gtk_list_store_set (self->slots_combo_model, &iter, 1, "--", -1);
|
||||||
|
for (guint i = 0; i < json_array_get_length (slots); i++)
|
||||||
|
{
|
||||||
|
JsonObject *slot = json_array_get_object_element (slots, i);
|
||||||
|
g_autofree gchar *label = NULL;
|
||||||
|
|
||||||
|
label = g_strdup_printf ("%s:%s", json_object_get_string_member (slot, "snap"),
|
||||||
|
json_object_get_string_member (slot, "slot"));
|
||||||
|
gtk_list_store_append (self->slots_combo_model, &iter);
|
||||||
|
gtk_list_store_set (self->slots_combo_model, &iter, 0, slot, 1, label, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
update_state (self);
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
35
panels/applications/cc-snap-row.h
Normal file
35
panels/applications/cc-snap-row.h
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
/* cc-snap-row.h
|
||||||
|
*
|
||||||
|
* Copyright 2019 Canonical Ltd.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <adwaita.h>
|
||||||
|
#include <json-glib/json-glib.h>
|
||||||
|
|
||||||
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
|
#define CC_TYPE_SNAP_ROW (cc_snap_row_get_type())
|
||||||
|
G_DECLARE_FINAL_TYPE (CcSnapRow, cc_snap_row, CC, SNAP_ROW, AdwActionRow)
|
||||||
|
|
||||||
|
CcSnapRow* cc_snap_row_new (GCancellable *cancellable,
|
||||||
|
JsonObject *plug,
|
||||||
|
JsonArray *slots);
|
||||||
|
|
||||||
|
G_END_DECLS
|
37
panels/applications/cc-snap-row.ui
Normal file
37
panels/applications/cc-snap-row.ui
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<interface>
|
||||||
|
<object class="GtkListStore" id="slots_combo_model">
|
||||||
|
<columns>
|
||||||
|
<!-- column-name slot -->
|
||||||
|
<column type="JsonObject"/>
|
||||||
|
<!-- column-name label -->
|
||||||
|
<column type="gchararray"/>
|
||||||
|
</columns>
|
||||||
|
</object>
|
||||||
|
<template class="CcSnapRow" parent="AdwActionRow">
|
||||||
|
<property name="can-focus">True</property>
|
||||||
|
<property name="activatable">False</property>
|
||||||
|
<property name="activatable-widget">slot_toggle</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkSwitch" id="slot_toggle">
|
||||||
|
<property name="valign">center</property>
|
||||||
|
<signal name="notify::active" handler="switch_changed_cb" swapped="yes"/>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkComboBox" id="slots_combo">
|
||||||
|
<property name="valign">center</property>
|
||||||
|
<property name="model">slots_combo_model</property>
|
||||||
|
<signal name="changed" handler="combo_changed_cb" swapped="yes"/>
|
||||||
|
<child>
|
||||||
|
<object class="GtkCellRendererText">
|
||||||
|
<property name="ellipsize">end</property>
|
||||||
|
</object>
|
||||||
|
<attributes>
|
||||||
|
<attribute name="text">1</attribute>
|
||||||
|
</attributes>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</template>
|
||||||
|
</interface>
|
290
panels/applications/cc-snapd-client.c
Normal file
290
panels/applications/cc-snapd-client.c
Normal file
|
@ -0,0 +1,290 @@
|
||||||
|
/* cc-snapd-client.c
|
||||||
|
*
|
||||||
|
* Copyright 2023 Canonical Ltd.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <libsoup/soup.h>
|
||||||
|
|
||||||
|
#include "cc-snapd-client.h"
|
||||||
|
|
||||||
|
// Unix socket that snapd communicates on.
|
||||||
|
#define SNAPD_SOCKET_PATH "/var/run/snapd.socket"
|
||||||
|
|
||||||
|
struct _CcSnapdClient
|
||||||
|
{
|
||||||
|
GObject parent;
|
||||||
|
|
||||||
|
// HTTP connection to snapd.
|
||||||
|
SoupSession *session;
|
||||||
|
};
|
||||||
|
|
||||||
|
G_DEFINE_TYPE (CcSnapdClient, cc_snapd_client, G_TYPE_OBJECT)
|
||||||
|
|
||||||
|
// Make an HTTP request to send to snapd.
|
||||||
|
static SoupMessage *
|
||||||
|
make_message (const gchar *method, const gchar *path, JsonNode *request_body)
|
||||||
|
{
|
||||||
|
g_autofree gchar *uri = NULL;
|
||||||
|
SoupMessage *msg;
|
||||||
|
SoupMessageHeaders *request_headers;
|
||||||
|
|
||||||
|
uri = g_strdup_printf("http://localhost%s", path);
|
||||||
|
msg = soup_message_new (method, uri);
|
||||||
|
request_headers = soup_message_get_request_headers (msg);
|
||||||
|
// Allow authentication via polkit.
|
||||||
|
soup_message_headers_append (request_headers, "X-Allow-Interaction", "true");
|
||||||
|
if (request_body != NULL)
|
||||||
|
{
|
||||||
|
g_autoptr(JsonGenerator) generator = NULL;
|
||||||
|
g_autofree gchar *body_text = NULL;
|
||||||
|
gsize body_length;
|
||||||
|
g_autoptr(GBytes) body_bytes = NULL;
|
||||||
|
|
||||||
|
generator = json_generator_new ();
|
||||||
|
json_generator_set_root (generator, request_body);
|
||||||
|
body_text = json_generator_to_data (generator, &body_length);
|
||||||
|
body_bytes = g_bytes_new (body_text, body_length);
|
||||||
|
soup_message_set_request_body_from_bytes (msg, "application/json", body_bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
return msg;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process an HTTP response recveived from snapd.
|
||||||
|
static JsonObject *
|
||||||
|
process_body (SoupMessage *msg, GBytes *body, GError **error)
|
||||||
|
{
|
||||||
|
const gchar *content_type;
|
||||||
|
g_autoptr(JsonParser) parser = NULL;
|
||||||
|
const gchar *body_data;
|
||||||
|
size_t body_length;
|
||||||
|
JsonNode *root;
|
||||||
|
JsonObject *response;
|
||||||
|
gint64 status_code;
|
||||||
|
g_autoptr(GError) internal_error = NULL;
|
||||||
|
|
||||||
|
content_type = soup_message_headers_get_one (soup_message_get_response_headers (msg), "Content-Type");
|
||||||
|
if (g_strcmp0 (content_type, "application/json") != 0)
|
||||||
|
{
|
||||||
|
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||||
|
"Invalid content type %s returned", content_type);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
parser = json_parser_new ();
|
||||||
|
body_data = g_bytes_get_data (body, &body_length);
|
||||||
|
if (!json_parser_load_from_data (parser, body_data, body_length, &internal_error))
|
||||||
|
{
|
||||||
|
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||||
|
"Failed to decode JSON content: %s", internal_error->message);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
root = json_parser_get_root (parser);
|
||||||
|
if (!JSON_NODE_HOLDS_OBJECT (root))
|
||||||
|
{
|
||||||
|
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "Returned JSON not an object");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
response = json_node_get_object (root);
|
||||||
|
status_code = json_object_get_int_member (response, "status-code");
|
||||||
|
if (status_code != SOUP_STATUS_OK && status_code != SOUP_STATUS_ACCEPTED)
|
||||||
|
{
|
||||||
|
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "Invalid status code %" G_GINT64_FORMAT, status_code);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return json_object_ref (response);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send an HTTP request to snapd and process the response.
|
||||||
|
static JsonObject *
|
||||||
|
call_sync (CcSnapdClient *self,
|
||||||
|
const gchar *method, const gchar *path, JsonNode *request_body,
|
||||||
|
GCancellable *cancellable, GError **error)
|
||||||
|
{
|
||||||
|
g_autoptr(SoupMessage) msg = NULL;
|
||||||
|
g_autoptr(GBytes) response_body = NULL;
|
||||||
|
|
||||||
|
msg = make_message (method, path, request_body);
|
||||||
|
response_body = soup_session_send_and_read (self->session, msg, cancellable, error);
|
||||||
|
if (response_body == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return process_body (msg, response_body, error);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Perform a snap interface action.
|
||||||
|
static gchar *
|
||||||
|
call_interfaces_sync (CcSnapdClient *self,
|
||||||
|
const gchar *action,
|
||||||
|
const gchar *plug_snap, const gchar *plug_name,
|
||||||
|
const gchar *slot_snap, const gchar *slot_name,
|
||||||
|
GCancellable *cancellable, GError **error)
|
||||||
|
{
|
||||||
|
g_autoptr(JsonBuilder) builder = NULL;
|
||||||
|
g_autoptr(JsonObject) response = NULL;
|
||||||
|
const gchar *change_id;
|
||||||
|
|
||||||
|
builder = json_builder_new();
|
||||||
|
json_builder_begin_object (builder);
|
||||||
|
json_builder_set_member_name (builder, "action");
|
||||||
|
json_builder_add_string_value (builder, action);
|
||||||
|
json_builder_set_member_name (builder, "plugs");
|
||||||
|
json_builder_begin_array (builder);
|
||||||
|
json_builder_begin_object (builder);
|
||||||
|
json_builder_set_member_name (builder, "snap");
|
||||||
|
json_builder_add_string_value (builder, plug_snap);
|
||||||
|
json_builder_set_member_name (builder, "plug");
|
||||||
|
json_builder_add_string_value (builder, plug_name);
|
||||||
|
json_builder_end_object (builder);
|
||||||
|
json_builder_end_array (builder);
|
||||||
|
json_builder_set_member_name (builder, "slots");
|
||||||
|
json_builder_begin_array (builder);
|
||||||
|
json_builder_begin_object (builder);
|
||||||
|
json_builder_set_member_name (builder, "snap");
|
||||||
|
json_builder_add_string_value (builder, slot_snap);
|
||||||
|
json_builder_set_member_name (builder, "slot");
|
||||||
|
json_builder_add_string_value (builder, slot_name);
|
||||||
|
json_builder_end_object (builder);
|
||||||
|
json_builder_end_array (builder);
|
||||||
|
json_builder_end_object (builder);
|
||||||
|
|
||||||
|
response = call_sync (self, "POST", "/v2/interfaces",
|
||||||
|
json_builder_get_root (builder), cancellable, error);
|
||||||
|
if (response == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
change_id = json_object_get_string_member (response, "change");
|
||||||
|
|
||||||
|
return g_strdup (change_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
cc_snapd_client_dispose (GObject *object)
|
||||||
|
{
|
||||||
|
CcSnapdClient *self = CC_SNAPD_CLIENT (object);
|
||||||
|
|
||||||
|
g_clear_object(&self->session);
|
||||||
|
|
||||||
|
G_OBJECT_CLASS (cc_snapd_client_parent_class)->dispose (object);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
cc_snapd_client_class_init (CcSnapdClientClass *klass)
|
||||||
|
{
|
||||||
|
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||||
|
|
||||||
|
object_class->dispose = cc_snapd_client_dispose;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
cc_snapd_client_init (CcSnapdClient *self)
|
||||||
|
{
|
||||||
|
g_autoptr(GSocketAddress) address = g_unix_socket_address_new (SNAPD_SOCKET_PATH);
|
||||||
|
self->session = soup_session_new_with_options ("remote-connectable", address, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
CcSnapdClient *
|
||||||
|
cc_snapd_client_new (void)
|
||||||
|
{
|
||||||
|
return g_object_new (CC_TYPE_SNAPD_CLIENT, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
JsonObject *
|
||||||
|
cc_snapd_client_get_snap_sync (CcSnapdClient *self, const gchar *name, GCancellable *cancellable, GError **error)
|
||||||
|
{
|
||||||
|
g_autofree gchar *path = NULL;
|
||||||
|
g_autoptr(JsonObject) response = NULL;
|
||||||
|
JsonObject *result;
|
||||||
|
|
||||||
|
path = g_strdup_printf ("/v2/snaps/%s", name);
|
||||||
|
response = call_sync (self, "GET", path, NULL, cancellable, error);
|
||||||
|
if (response == NULL)
|
||||||
|
return NULL;
|
||||||
|
result = json_object_get_object_member (response, "result");
|
||||||
|
if (result == NULL)
|
||||||
|
{
|
||||||
|
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "Invalid response to %s", path);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return json_object_ref (result);
|
||||||
|
}
|
||||||
|
|
||||||
|
JsonObject *
|
||||||
|
cc_snapd_client_get_change_sync (CcSnapdClient *self, const gchar *change_id, GCancellable *cancellable, GError **error)
|
||||||
|
{
|
||||||
|
g_autofree gchar *path = NULL;
|
||||||
|
g_autoptr(JsonObject) response = NULL;
|
||||||
|
JsonObject *result;
|
||||||
|
|
||||||
|
path = g_strdup_printf ("/v2/changes/%s", change_id);
|
||||||
|
response = call_sync (self, "GET", path, NULL, cancellable, error);
|
||||||
|
if (response == NULL)
|
||||||
|
return NULL;
|
||||||
|
result = json_object_get_object_member (response, "result");
|
||||||
|
if (result == NULL)
|
||||||
|
{
|
||||||
|
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "Invalid response to %s", path);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return json_object_ref (result);
|
||||||
|
}
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
cc_snapd_client_get_all_connections_sync (CcSnapdClient *self,
|
||||||
|
JsonArray **plugs, JsonArray **slots,
|
||||||
|
GCancellable *cancellable, GError **error)
|
||||||
|
{
|
||||||
|
g_autoptr(JsonObject) response = NULL;
|
||||||
|
JsonObject *result;
|
||||||
|
|
||||||
|
response = call_sync (self, "GET", "/v2/connections?select=all", NULL, cancellable, error);
|
||||||
|
if (response == NULL)
|
||||||
|
return FALSE;
|
||||||
|
result = json_object_get_object_member (response, "result");
|
||||||
|
if (result == NULL)
|
||||||
|
{
|
||||||
|
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "Invalid response to /v2/connections");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
*plugs = json_array_ref (json_object_get_array_member (result, "plugs"));
|
||||||
|
*slots = json_array_ref (json_object_get_array_member (result, "slots"));
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
gchar *
|
||||||
|
cc_snapd_client_connect_interface_sync (CcSnapdClient *self,
|
||||||
|
const gchar *plug_snap, const gchar *plug_name,
|
||||||
|
const gchar *slot_snap, const gchar *slot_name,
|
||||||
|
GCancellable *cancellable, GError **error)
|
||||||
|
{
|
||||||
|
return call_interfaces_sync (self, "connect", plug_snap, plug_name, slot_snap, slot_name, cancellable, error);
|
||||||
|
}
|
||||||
|
|
||||||
|
gchar *
|
||||||
|
cc_snapd_client_disconnect_interface_sync (CcSnapdClient *self,
|
||||||
|
const gchar *plug_snap, const gchar *plug_name,
|
||||||
|
const gchar *slot_snap, const gchar *slot_name,
|
||||||
|
GCancellable *cancellable, GError **error)
|
||||||
|
{
|
||||||
|
return call_interfaces_sync (self, "disconnect", plug_snap, plug_name, slot_snap, slot_name, cancellable, error);
|
||||||
|
}
|
70
panels/applications/cc-snapd-client.h
Normal file
70
panels/applications/cc-snapd-client.h
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
/* cc-snapd-client.h
|
||||||
|
*
|
||||||
|
* Copyright 2023 Canonical Ltd.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <json-glib/json-glib.h>
|
||||||
|
|
||||||
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
|
#define CC_TYPE_SNAPD_CLIENT (cc_snapd_client_get_type())
|
||||||
|
G_DECLARE_FINAL_TYPE (CcSnapdClient, cc_snapd_client, CC, SNAPD_CLIENT, GObject)
|
||||||
|
|
||||||
|
// Creates a client to contact snapd.
|
||||||
|
CcSnapdClient *cc_snapd_client_new (void);
|
||||||
|
|
||||||
|
// Get information on an installed snap.
|
||||||
|
JsonObject *cc_snapd_client_get_snap_sync (CcSnapdClient *client,
|
||||||
|
const gchar *name,
|
||||||
|
GCancellable *cancellable,
|
||||||
|
GError **error);
|
||||||
|
|
||||||
|
// Get information on a snap change.
|
||||||
|
JsonObject *cc_snapd_client_get_change_sync (CcSnapdClient *client,
|
||||||
|
const gchar *change_id,
|
||||||
|
GCancellable *cancellable,
|
||||||
|
GError **error);
|
||||||
|
|
||||||
|
// Get the state of the snap interface connections.
|
||||||
|
gboolean cc_snapd_client_get_all_connections_sync (CcSnapdClient *client,
|
||||||
|
JsonArray **plugs,
|
||||||
|
JsonArray **slots,
|
||||||
|
GCancellable *cancellable,
|
||||||
|
GError **error);
|
||||||
|
|
||||||
|
// Connect a plug to a slot. Returns the change ID to monitor for completion of this task.
|
||||||
|
gchar *cc_snapd_client_connect_interface_sync (CcSnapdClient *client,
|
||||||
|
const gchar *plug_snap,
|
||||||
|
const gchar *plug_name,
|
||||||
|
const gchar *slot_snap,
|
||||||
|
const gchar *slot_name,
|
||||||
|
GCancellable *cancellable,
|
||||||
|
GError **error);
|
||||||
|
|
||||||
|
// Disconnect a plug to a slot. Returns the change ID to monitor for completion of this task.
|
||||||
|
gchar *cc_snapd_client_disconnect_interface_sync (CcSnapdClient *client,
|
||||||
|
const gchar *plug_snap,
|
||||||
|
const gchar *plug_name,
|
||||||
|
const gchar *slot_snap,
|
||||||
|
const gchar *slot_name,
|
||||||
|
GCancellable *cancellable,
|
||||||
|
GError **error);
|
||||||
|
|
||||||
|
G_END_DECLS
|
62
panels/applications/globs.c
Normal file
62
panels/applications/globs.c
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
/* globs.c
|
||||||
|
*
|
||||||
|
* Copyright 2018 Matthias Clasen <matthias.clasen@gmail.com>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <config.h>
|
||||||
|
|
||||||
|
#include "globs.h"
|
||||||
|
|
||||||
|
/* parse mime/globs and return a string->string hash table */
|
||||||
|
GHashTable *
|
||||||
|
parse_globs (void)
|
||||||
|
{
|
||||||
|
GHashTable *globs;
|
||||||
|
const gchar * const *dirs;
|
||||||
|
gint i;
|
||||||
|
|
||||||
|
globs = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
|
||||||
|
|
||||||
|
dirs = g_get_system_data_dirs ();
|
||||||
|
|
||||||
|
for (i = 0; dirs[i]; i++)
|
||||||
|
{
|
||||||
|
g_autofree gchar *file = g_build_filename (dirs[i], "mime", "globs", NULL);
|
||||||
|
g_autofree gchar *contents = NULL;
|
||||||
|
|
||||||
|
if (g_file_get_contents (file, &contents, NULL, NULL))
|
||||||
|
{
|
||||||
|
g_auto(GStrv) strv = NULL;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
strv = g_strsplit (contents, "\n", 0);
|
||||||
|
for (i = 0; strv[i]; i++)
|
||||||
|
{
|
||||||
|
g_auto(GStrv) parts = NULL;
|
||||||
|
|
||||||
|
if (strv[i][0] == '#' || strv[i][0] == '\0')
|
||||||
|
continue;
|
||||||
|
|
||||||
|
parts = g_strsplit (strv[i], ":", 2);
|
||||||
|
g_hash_table_insert (globs, g_strdup (parts[0]), g_strdup (parts[1]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return globs;
|
||||||
|
}
|
29
panels/applications/globs.h
Normal file
29
panels/applications/globs.h
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
/* globs.h
|
||||||
|
*
|
||||||
|
* Copyright 2018 Matthias Clasen <matthias.clasen@gmail.com>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <gio/gio.h>
|
||||||
|
|
||||||
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
|
GHashTable* parse_globs (void);
|
||||||
|
|
||||||
|
G_END_DECLS
|
15
panels/applications/gnome-applications-panel.desktop.in
Normal file
15
panels/applications/gnome-applications-panel.desktop.in
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
[Desktop Entry]
|
||||||
|
Name=Apps
|
||||||
|
Comment=Control various app permissions and settings
|
||||||
|
Exec=gnome-control-center applications
|
||||||
|
# FIXME
|
||||||
|
# Translators: Do NOT translate or transliterate this text (this is an icon file name)!
|
||||||
|
Icon=org.gnome.Settings-applications-symbolic
|
||||||
|
Terminal=false
|
||||||
|
Type=Application
|
||||||
|
NoDisplay=true
|
||||||
|
StartupNotify=true
|
||||||
|
Categories=GNOME;GTK;Settings;DesktopSettings;X-GNOME-Settings-Panel;X-GNOME-AccountSettings;
|
||||||
|
OnlyShowIn=GNOME;Unity;
|
||||||
|
# Translators: Search terms to find the Apps panel. Do NOT translate or localize the semicolons! The list MUST also end with a semicolon!
|
||||||
|
Keywords=application;flatpak;permission;setting;default;preferred;media;autorun;cd;dvd;usb;audio;video;disc;removable;device;system;
|
4
panels/applications/icons/meson.build
Normal file
4
panels/applications/icons/meson.build
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
install_data(
|
||||||
|
'scalable/org.gnome.Settings-applications-symbolic.svg',
|
||||||
|
install_dir: join_paths(control_center_icondir, 'hicolor', 'scalable', 'apps')
|
||||||
|
)
|
|
@ -0,0 +1,4 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<svg height="16px" viewBox="0 0 16 16" width="16px" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="m 2 0 c -1.089844 0 -2 0.910156 -2 2 v 3 c 0 1.089844 0.910156 2 2 2 h 3 c 1.089844 0 2 -0.910156 2 -2 v -3 c 0 -1.089844 -0.910156 -2 -2 -2 z m 8 0 c -1.089844 0 -2 0.910156 -2 2 v 3 c 0 1.089844 0.910156 2 2 2 h 3 c 1.089844 0 2 -0.910156 2 -2 v -3 c 0 -1.089844 -0.910156 -2 -2 -2 z m -8 2 h 3 v 3 h -3 z m 8 0 h 3 v 3 h -3 z m -8 6 c -1.089844 0 -2 0.910156 -2 2 v 3 c 0 1.089844 0.910156 2 2 2 h 3 c 1.089844 0 2 -0.910156 2 -2 v -3 c 0 -1.089844 -0.910156 -2 -2 -2 z m 8 0 c -1.089844 0 -2 0.910156 -2 2 v 3 c 0 1.089844 0.910156 2 2 2 h 3 c 1.089844 0 2 -0.910156 2 -2 v -3 c 0 -1.089844 -0.910156 -2 -2 -2 z m -8 2 h 3 v 3 h -3 z m 8 0 h 3 v 3 h -3 z m 0 0" fill="#2e3436"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 830 B |
74
panels/applications/meson.build
Normal file
74
panels/applications/meson.build
Normal file
|
@ -0,0 +1,74 @@
|
||||||
|
panels_list += cappletname
|
||||||
|
desktop = 'gnome-@0@-panel.desktop'.format(cappletname)
|
||||||
|
|
||||||
|
i18n.merge_file(
|
||||||
|
type : 'desktop',
|
||||||
|
input : desktop + '.in',
|
||||||
|
output : desktop,
|
||||||
|
po_dir : po_dir,
|
||||||
|
install : true,
|
||||||
|
install_dir : control_center_desktopdir
|
||||||
|
)
|
||||||
|
|
||||||
|
sources = files(
|
||||||
|
'cc-applications-panel.c',
|
||||||
|
'cc-applications-row.c',
|
||||||
|
'cc-application-shortcut-dialog.c',
|
||||||
|
'cc-default-apps-page.c',
|
||||||
|
'cc-default-apps-row.c',
|
||||||
|
'cc-removable-media-settings.c',
|
||||||
|
'globs.c',
|
||||||
|
'search.c',
|
||||||
|
'utils.c',
|
||||||
|
)
|
||||||
|
|
||||||
|
resource_data = files(
|
||||||
|
'cc-applications-panel.ui',
|
||||||
|
'cc-default-apps-page.ui',
|
||||||
|
'cc-removable-media-settings.ui',
|
||||||
|
)
|
||||||
|
|
||||||
|
sources += gnome.compile_resources(
|
||||||
|
'cc-' + cappletname + '-resources',
|
||||||
|
cappletname + '.gresource.xml',
|
||||||
|
c_name : 'cc_' + cappletname,
|
||||||
|
dependencies: resource_data,
|
||||||
|
export : true
|
||||||
|
)
|
||||||
|
|
||||||
|
sources += gnome.gdbus_codegen(
|
||||||
|
'cc-global-shortcuts-rebind-generated',
|
||||||
|
'org.gnome.GlobalShortcutsRebind.xml',
|
||||||
|
interface_prefix : 'org.gnome.',
|
||||||
|
namespace : 'Cc'
|
||||||
|
)
|
||||||
|
|
||||||
|
install_data(
|
||||||
|
'org.gnome.GlobalShortcutsRebind.xml',
|
||||||
|
install_dir : control_center_datadir + '/dbus-1/interfaces',
|
||||||
|
)
|
||||||
|
|
||||||
|
deps = common_deps + keyboard_shortcuts_dep
|
||||||
|
|
||||||
|
if host_is_linux
|
||||||
|
deps += mm_dep
|
||||||
|
endif
|
||||||
|
|
||||||
|
if enable_snap
|
||||||
|
deps += [ json_glib_dep, libsoup_dep ]
|
||||||
|
sources += [ 'cc-snap-row.c', 'cc-snapd-client.c' ]
|
||||||
|
endif
|
||||||
|
|
||||||
|
if enable_malcontent
|
||||||
|
deps += malcontent_dep
|
||||||
|
endif
|
||||||
|
|
||||||
|
panels_libs += static_library(
|
||||||
|
cappletname,
|
||||||
|
sources : sources,
|
||||||
|
include_directories : [ top_inc, common_inc ],
|
||||||
|
dependencies : deps,
|
||||||
|
c_args : cflags
|
||||||
|
)
|
||||||
|
|
||||||
|
subdir('icons')
|
37
panels/applications/org.gnome.GlobalShortcutsRebind.xml
Normal file
37
panels/applications/org.gnome.GlobalShortcutsRebind.xml
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
<!DOCTYPE node PUBLIC
|
||||||
|
'-//freedesktop//DTD D-BUS Object Introspection 1.0//EN'
|
||||||
|
'http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd'>
|
||||||
|
<node>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
org.gnome.GlobalShortcutsRebind:
|
||||||
|
@short_description: Global shortcuts portal rebind service
|
||||||
|
|
||||||
|
Propagates GlobalShortcuts changes requested by user, to the
|
||||||
|
portal backend and active clients.
|
||||||
|
-->
|
||||||
|
<interface name="org.gnome.GlobalShortcutsRebind">
|
||||||
|
<!--
|
||||||
|
RebindShortcuts:
|
||||||
|
@app_id: Application ID
|
||||||
|
@shortcuts: Rebound shortcuts
|
||||||
|
|
||||||
|
Changes current bindings.
|
||||||
|
|
||||||
|
The @shortcuts array is made of tuples composed of a shortcut id, and
|
||||||
|
a vardict with the following keys:
|
||||||
|
|
||||||
|
* ``description`` (``s``)
|
||||||
|
|
||||||
|
User-readable text describing what the shortcut does. Optional.
|
||||||
|
|
||||||
|
* ``shortcuts`` (``as``)
|
||||||
|
|
||||||
|
The new shortcut binding, for example: ``['<alt>C', '<ctrl>Q']``
|
||||||
|
-->
|
||||||
|
<method name="RebindShortcuts">
|
||||||
|
<arg type="s" name="app_id" direction="in"/>
|
||||||
|
<arg type="a(sa{sv})" name="shortcuts" direction="in"/>
|
||||||
|
</method>
|
||||||
|
</interface>
|
||||||
|
</node>
|
133
panels/applications/search.c
Normal file
133
panels/applications/search.c
Normal file
|
@ -0,0 +1,133 @@
|
||||||
|
/* search.c
|
||||||
|
*
|
||||||
|
* Copyright 2018 Matthias Clasen <matthias.clasen@gmail.com>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <config.h>
|
||||||
|
|
||||||
|
#include "search.h"
|
||||||
|
|
||||||
|
|
||||||
|
#define SHELL_PROVIDER_GROUP "Shell Search Provider"
|
||||||
|
|
||||||
|
static void
|
||||||
|
add_one_provider (GHashTable *search_providers,
|
||||||
|
GFile *file)
|
||||||
|
{
|
||||||
|
g_autoptr(GKeyFile) keyfile = NULL;
|
||||||
|
g_autoptr(GError) error = NULL;
|
||||||
|
g_autofree gchar *app_id = NULL;
|
||||||
|
g_autofree gchar *path = NULL;
|
||||||
|
gboolean default_disabled;
|
||||||
|
|
||||||
|
path = g_file_get_path (file);
|
||||||
|
keyfile = g_key_file_new ();
|
||||||
|
g_key_file_load_from_file (keyfile, path, G_KEY_FILE_NONE, &error);
|
||||||
|
|
||||||
|
if (error != NULL)
|
||||||
|
{
|
||||||
|
g_warning ("Error loading %s: %s - search provider will be ignored",
|
||||||
|
path, error->message);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!g_key_file_has_group (keyfile, SHELL_PROVIDER_GROUP))
|
||||||
|
{
|
||||||
|
g_debug ("Shell search provider group missing from '%s', ignoring", path);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
app_id = g_key_file_get_string (keyfile, SHELL_PROVIDER_GROUP, "DesktopId", &error);
|
||||||
|
|
||||||
|
if (error != NULL)
|
||||||
|
{
|
||||||
|
g_warning ("Unable to read desktop ID from %s: %s - search provider will be ignored",
|
||||||
|
path, error->message);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (g_str_has_suffix (app_id, ".desktop"))
|
||||||
|
app_id[strlen (app_id) - strlen (".desktop")] = '\0';
|
||||||
|
|
||||||
|
default_disabled = g_key_file_get_boolean (keyfile, SHELL_PROVIDER_GROUP, "DefaultDisabled", NULL);
|
||||||
|
|
||||||
|
g_hash_table_insert (search_providers, g_strdup (app_id), GINT_TO_POINTER (default_disabled));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
parse_search_providers_one_dir (GHashTable *search_providers,
|
||||||
|
const gchar *system_dir)
|
||||||
|
{
|
||||||
|
g_autoptr(GFileEnumerator) enumerator = NULL;
|
||||||
|
g_autoptr(GError) error = NULL;
|
||||||
|
g_autoptr(GFile) providers_location = NULL;
|
||||||
|
g_autofree gchar *providers_path = NULL;
|
||||||
|
|
||||||
|
providers_path = g_build_filename (system_dir, "gnome-shell", "search-providers", NULL);
|
||||||
|
providers_location = g_file_new_for_path (providers_path);
|
||||||
|
|
||||||
|
enumerator = g_file_enumerate_children (providers_location,
|
||||||
|
"standard::type,standard::name,standard::content-type",
|
||||||
|
G_FILE_QUERY_INFO_NONE,
|
||||||
|
NULL, &error);
|
||||||
|
|
||||||
|
if (error != NULL)
|
||||||
|
{
|
||||||
|
if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND) &&
|
||||||
|
!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
|
||||||
|
g_warning ("Error opening %s: %s - search provider configuration won't be possible",
|
||||||
|
providers_path, error->message);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (TRUE)
|
||||||
|
{
|
||||||
|
GFile *provider = NULL;
|
||||||
|
|
||||||
|
if (!g_file_enumerator_iterate (enumerator, NULL, &provider, NULL, &error))
|
||||||
|
{
|
||||||
|
g_warning ("Error while reading %s: %s - search provider configuration won't be possible",
|
||||||
|
providers_path, error->message);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (provider == NULL)
|
||||||
|
break;
|
||||||
|
|
||||||
|
add_one_provider (search_providers, provider);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* parse gnome-shell/search-provider files and return a string->boolean hash table */
|
||||||
|
GHashTable *
|
||||||
|
parse_search_providers (void)
|
||||||
|
{
|
||||||
|
GHashTable *search_providers;
|
||||||
|
const gchar * const *dirs;
|
||||||
|
gint i;
|
||||||
|
|
||||||
|
search_providers = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
|
||||||
|
|
||||||
|
dirs = g_get_system_data_dirs ();
|
||||||
|
|
||||||
|
for (i = 0; dirs[i]; i++)
|
||||||
|
parse_search_providers_one_dir (search_providers, dirs[i]);
|
||||||
|
|
||||||
|
return search_providers;
|
||||||
|
}
|
||||||
|
|
29
panels/applications/search.h
Normal file
29
panels/applications/search.h
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
/* globs.h
|
||||||
|
*
|
||||||
|
* Copyright 2018 Matthias Clasen <matthias.clasen@gmail.com>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <gio/gio.h>
|
||||||
|
|
||||||
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
|
GHashTable* parse_search_providers (void);
|
||||||
|
|
||||||
|
G_END_DECLS
|
257
panels/applications/utils.c
Normal file
257
panels/applications/utils.c
Normal file
|
@ -0,0 +1,257 @@
|
||||||
|
/* utils.c
|
||||||
|
*
|
||||||
|
* Copyright 2018 Matthias Clasen <matthias.clasen@gmail.com>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _XOPEN_SOURCE
|
||||||
|
#define _XOPEN_SOURCE 600
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <config.h>
|
||||||
|
#include <glib/gi18n.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
|
||||||
|
#include <ftw.h>
|
||||||
|
|
||||||
|
#include "utils.h"
|
||||||
|
#ifdef HAVE_SNAP
|
||||||
|
#include "cc-snapd-client.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static gint
|
||||||
|
ftw_remove_cb (const gchar *path,
|
||||||
|
const struct stat *sb,
|
||||||
|
gint typeflags,
|
||||||
|
struct FTW *ftwbuf)
|
||||||
|
{
|
||||||
|
remove (path);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
file_remove_thread_func (GTask *task,
|
||||||
|
gpointer source_object,
|
||||||
|
gpointer task_data,
|
||||||
|
GCancellable *cancellable)
|
||||||
|
{
|
||||||
|
GFile *file = source_object;
|
||||||
|
g_autofree gchar *path = g_file_get_path (file);
|
||||||
|
|
||||||
|
nftw (path, ftw_remove_cb, 20, FTW_PHYS | FTW_DEPTH);
|
||||||
|
|
||||||
|
if (g_task_set_return_on_cancel (task, FALSE))
|
||||||
|
g_task_return_boolean (task, TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
file_remove_async (GFile *file,
|
||||||
|
GCancellable *cancellable,
|
||||||
|
GAsyncReadyCallback callback,
|
||||||
|
gpointer data)
|
||||||
|
{
|
||||||
|
g_autoptr(GTask) task = g_task_new (file, cancellable, callback, data);
|
||||||
|
g_task_set_return_on_cancel (task, TRUE);
|
||||||
|
g_task_run_in_thread (task, file_remove_thread_func);
|
||||||
|
}
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
file_remove_finish (GFile *file,
|
||||||
|
GAsyncResult *result,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
g_return_val_if_fail (g_task_is_valid (result, file), FALSE);
|
||||||
|
return g_task_propagate_boolean (G_TASK (result), error);
|
||||||
|
}
|
||||||
|
|
||||||
|
static GPrivate size_key = G_PRIVATE_INIT (g_free);
|
||||||
|
|
||||||
|
static gint
|
||||||
|
ftw_size_cb (const gchar *path,
|
||||||
|
const struct stat *sb,
|
||||||
|
gint typeflags,
|
||||||
|
struct FTW *ftwbuf)
|
||||||
|
{
|
||||||
|
guint64 *size = (guint64*)g_private_get (&size_key);
|
||||||
|
if (typeflags == FTW_F)
|
||||||
|
*size += sb->st_size;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
file_size_thread_func (GTask *task,
|
||||||
|
gpointer source_object,
|
||||||
|
gpointer task_data,
|
||||||
|
GCancellable *cancellable)
|
||||||
|
{
|
||||||
|
GFile *file = source_object;
|
||||||
|
g_autofree gchar *path = g_file_get_path (file);
|
||||||
|
guint64 *total;
|
||||||
|
|
||||||
|
g_private_replace (&size_key, g_new0 (guint64, 1));
|
||||||
|
|
||||||
|
nftw (path, ftw_size_cb, 20, FTW_PHYS | FTW_DEPTH);
|
||||||
|
|
||||||
|
total = g_new0 (guint64, 1);
|
||||||
|
*total = *(guint64*)g_private_get (&size_key);
|
||||||
|
|
||||||
|
if (g_task_set_return_on_cancel (task, FALSE))
|
||||||
|
g_task_return_pointer (task, total, g_free);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
file_size_async (GFile *file,
|
||||||
|
GCancellable *cancellable,
|
||||||
|
GAsyncReadyCallback callback,
|
||||||
|
gpointer data)
|
||||||
|
{
|
||||||
|
g_autoptr(GTask) task = g_task_new (file, cancellable, callback, data);
|
||||||
|
g_task_set_return_on_cancel (task, TRUE);
|
||||||
|
g_task_run_in_thread (task, file_size_thread_func);
|
||||||
|
}
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
file_size_finish (GFile *file,
|
||||||
|
GAsyncResult *result,
|
||||||
|
guint64 *size,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
g_autofree guint64 *data = NULL;
|
||||||
|
|
||||||
|
g_return_val_if_fail (g_task_is_valid (result, file), FALSE);
|
||||||
|
data = g_task_propagate_pointer (G_TASK (result), error);
|
||||||
|
if (data == NULL)
|
||||||
|
return FALSE;
|
||||||
|
if (size != NULL)
|
||||||
|
*size = *data;
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gchar *
|
||||||
|
get_output_of (const gchar **argv)
|
||||||
|
{
|
||||||
|
g_autofree gchar *output = NULL;
|
||||||
|
int status;
|
||||||
|
|
||||||
|
if (!g_spawn_sync (NULL,
|
||||||
|
(gchar**) argv,
|
||||||
|
NULL,
|
||||||
|
G_SPAWN_SEARCH_PATH,
|
||||||
|
NULL, NULL,
|
||||||
|
&output, NULL,
|
||||||
|
&status, NULL))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (!g_spawn_check_wait_status (status, NULL))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return g_steal_pointer (&output);
|
||||||
|
}
|
||||||
|
|
||||||
|
GKeyFile *
|
||||||
|
get_flatpak_metadata (const gchar *app_id)
|
||||||
|
{
|
||||||
|
const gchar *argv[5] = { "flatpak", "info", "-m", "app", NULL };
|
||||||
|
g_autofree gchar *data = NULL;
|
||||||
|
g_autoptr(GError) error = NULL;
|
||||||
|
g_autoptr(GKeyFile) keyfile = NULL;
|
||||||
|
|
||||||
|
argv[3] = app_id;
|
||||||
|
|
||||||
|
data = get_output_of (argv);
|
||||||
|
if (data == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
keyfile = g_key_file_new ();
|
||||||
|
if (!g_key_file_load_from_data (keyfile, data, -1, 0, &error))
|
||||||
|
{
|
||||||
|
g_warning ("%s", error->message);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return g_steal_pointer (&keyfile);
|
||||||
|
}
|
||||||
|
|
||||||
|
guint64
|
||||||
|
get_flatpak_app_size (const gchar *app_id)
|
||||||
|
{
|
||||||
|
const gchar *argv[5] = { "flatpak", "info", "-s", "app", NULL };
|
||||||
|
g_autofree gchar *data = NULL;
|
||||||
|
guint64 factor;
|
||||||
|
double val;
|
||||||
|
|
||||||
|
argv[3] = app_id;
|
||||||
|
|
||||||
|
data = get_output_of (argv);
|
||||||
|
if (data == NULL)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
data = g_strstrip (data);
|
||||||
|
|
||||||
|
if (g_str_has_suffix (data, "kB") || g_str_has_suffix (data, "kb"))
|
||||||
|
factor = 1000;
|
||||||
|
else if (g_str_has_suffix (data, "MB") || g_str_has_suffix (data, "Mb"))
|
||||||
|
factor = 1000 * 1000;
|
||||||
|
else if (g_str_has_suffix (data, "GB") || g_str_has_suffix (data, "Gb"))
|
||||||
|
factor = 1000 * 1000 * 1000;
|
||||||
|
else if (g_str_has_suffix (data, "KiB") || g_str_has_suffix (data, "Kib"))
|
||||||
|
factor = 1024;
|
||||||
|
else if (g_str_has_suffix (data, "MiB") || g_str_has_suffix (data, "Mib"))
|
||||||
|
factor = 1024 * 1024;
|
||||||
|
else if (g_str_has_suffix (data, "GiB") || g_str_has_suffix (data, "Gib"))
|
||||||
|
factor = 1024 * 1024 * 1024;
|
||||||
|
else
|
||||||
|
factor = 1;
|
||||||
|
|
||||||
|
val = g_ascii_strtod (data, NULL);
|
||||||
|
|
||||||
|
return (guint64)(val * factor);
|
||||||
|
}
|
||||||
|
|
||||||
|
guint64
|
||||||
|
get_snap_app_size (const gchar *snap_name)
|
||||||
|
{
|
||||||
|
#ifdef HAVE_SNAP
|
||||||
|
g_autoptr(CcSnapdClient) client = NULL;
|
||||||
|
g_autoptr(JsonObject) snap = NULL;
|
||||||
|
g_autoptr(GError) error = NULL;
|
||||||
|
|
||||||
|
client = cc_snapd_client_new ();
|
||||||
|
snap = cc_snapd_client_get_snap_sync (client, snap_name, NULL, &error);
|
||||||
|
if (snap == NULL)
|
||||||
|
{
|
||||||
|
g_warning ("Failed to get snap size: %s", error->message);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return json_object_get_int_member (snap, "installed-size");
|
||||||
|
#else
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
char *
|
||||||
|
get_app_id (GAppInfo *info)
|
||||||
|
{
|
||||||
|
gchar *app_id = g_strdup (g_app_info_get_id (info));
|
||||||
|
|
||||||
|
if (g_str_has_suffix (app_id, ".desktop"))
|
||||||
|
app_id[strlen (app_id) - strlen (".desktop")] = '\0';
|
||||||
|
|
||||||
|
return app_id;
|
||||||
|
}
|
55
panels/applications/utils.h
Normal file
55
panels/applications/utils.h
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
/* utils.h
|
||||||
|
*
|
||||||
|
* Copyright 2018 Matthias Clasen <matthias.clasen@gmail.com>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <gio/gio.h>
|
||||||
|
#include <gtk/gtk.h>
|
||||||
|
|
||||||
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
|
void file_remove_async (GFile *file,
|
||||||
|
GCancellable *cancellable,
|
||||||
|
GAsyncReadyCallback callback,
|
||||||
|
gpointer data);
|
||||||
|
|
||||||
|
gboolean file_remove_finish (GFile *file,
|
||||||
|
GAsyncResult *result,
|
||||||
|
GError **error);
|
||||||
|
|
||||||
|
void file_size_async (GFile *file,
|
||||||
|
GCancellable *cancellable,
|
||||||
|
GAsyncReadyCallback callback,
|
||||||
|
gpointer data);
|
||||||
|
|
||||||
|
gboolean file_size_finish (GFile *file,
|
||||||
|
GAsyncResult *result,
|
||||||
|
guint64 *size,
|
||||||
|
GError **error);
|
||||||
|
|
||||||
|
GKeyFile* get_flatpak_metadata (const gchar *app_id);
|
||||||
|
|
||||||
|
guint64 get_flatpak_app_size (const gchar *app_id);
|
||||||
|
|
||||||
|
guint64 get_snap_app_size (const gchar *snap_name);
|
||||||
|
|
||||||
|
gchar* get_app_id (GAppInfo *info);
|
||||||
|
|
||||||
|
G_END_DECLS
|
14
panels/background/background.gresource.xml
Normal file
14
panels/background/background.gresource.xml
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<gresources>
|
||||||
|
<gresource prefix="/org/gnome/control-center/background">
|
||||||
|
<file preprocess="xml-stripblanks">cc-background-chooser.ui</file>
|
||||||
|
<file preprocess="xml-stripblanks">cc-background-panel.ui</file>
|
||||||
|
<file preprocess="xml-stripblanks">cc-background-preview.ui</file>
|
||||||
|
<file>preview.css</file>
|
||||||
|
</gresource>
|
||||||
|
|
||||||
|
<gresource prefix="/org/gnome/Settings">
|
||||||
|
<file preprocess="xml-stripblanks">icons/scalable/actions/background-selected-symbolic.svg</file>
|
||||||
|
<file preprocess="xml-stripblanks">icons/scalable/actions/slideshow-symbolic.svg</file>
|
||||||
|
</gresource>
|
||||||
|
</gresources>
|
454
panels/background/bg-recent-source.c
Normal file
454
panels/background/bg-recent-source.c
Normal file
|
@ -0,0 +1,454 @@
|
||||||
|
/* bg-recent-source.c
|
||||||
|
*
|
||||||
|
* Copyright 2019 Georges Basile Stavracas Neto <georges.stavracas@gmail.com>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*/
|
||||||
|
|
||||||
|
#undef G_LOG_DOMAIN
|
||||||
|
#define G_LOG_DOMAIN "bg-recent-source"
|
||||||
|
|
||||||
|
#include "bg-recent-source.h"
|
||||||
|
#include "cc-background-item.h"
|
||||||
|
|
||||||
|
#define ATTRIBUTES G_FILE_ATTRIBUTE_STANDARD_NAME "," \
|
||||||
|
G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE "," \
|
||||||
|
G_FILE_ATTRIBUTE_TIME_MODIFIED
|
||||||
|
|
||||||
|
struct _BgRecentSource
|
||||||
|
{
|
||||||
|
BgSource parent;
|
||||||
|
|
||||||
|
GFile *backgrounds_folder;
|
||||||
|
GFileMonitor *monitor;
|
||||||
|
|
||||||
|
GCancellable *cancellable;
|
||||||
|
GHashTable *items;
|
||||||
|
};
|
||||||
|
|
||||||
|
G_DEFINE_TYPE (BgRecentSource, bg_recent_source, BG_TYPE_SOURCE)
|
||||||
|
|
||||||
|
static int
|
||||||
|
sort_func (gconstpointer a,
|
||||||
|
gconstpointer b,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
CcBackgroundItem *item_a;
|
||||||
|
CcBackgroundItem *item_b;
|
||||||
|
guint64 modified_a;
|
||||||
|
guint64 modified_b;
|
||||||
|
int retval;
|
||||||
|
|
||||||
|
item_a = (CcBackgroundItem *) a;
|
||||||
|
item_b = (CcBackgroundItem *) b;
|
||||||
|
modified_a = cc_background_item_get_modified (item_a);
|
||||||
|
modified_b = cc_background_item_get_modified (item_b);
|
||||||
|
|
||||||
|
retval = modified_b - modified_a;
|
||||||
|
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
add_file_from_info (BgRecentSource *self,
|
||||||
|
GFile *file,
|
||||||
|
GFileInfo *info)
|
||||||
|
{
|
||||||
|
g_autoptr(CcBackgroundItem) item = NULL;
|
||||||
|
g_autofree gchar *source_uri = NULL;
|
||||||
|
g_autofree gchar *uri = NULL;
|
||||||
|
GListStore *store;
|
||||||
|
const gchar *content_type;
|
||||||
|
guint64 mtime;
|
||||||
|
|
||||||
|
content_type = g_file_info_get_content_type (info);
|
||||||
|
mtime = g_file_info_get_attribute_uint64 (info, G_FILE_ATTRIBUTE_TIME_MODIFIED);
|
||||||
|
|
||||||
|
if (!content_type || !g_content_type_is_a (content_type, "image/*"))
|
||||||
|
return;
|
||||||
|
|
||||||
|
uri = g_file_get_uri (file);
|
||||||
|
item = cc_background_item_new (uri);
|
||||||
|
g_object_set (G_OBJECT (item),
|
||||||
|
"shading", G_DESKTOP_BACKGROUND_SHADING_SOLID,
|
||||||
|
"placement", G_DESKTOP_BACKGROUND_STYLE_ZOOM,
|
||||||
|
"modified", mtime,
|
||||||
|
"needs-download", FALSE,
|
||||||
|
"source-url", source_uri,
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
store = bg_source_get_liststore (BG_SOURCE (self));
|
||||||
|
g_list_store_insert_sorted (store, item, sort_func, self);
|
||||||
|
|
||||||
|
g_hash_table_insert (self->items, g_strdup (uri), g_object_ref (item));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
remove_item (BgRecentSource *self,
|
||||||
|
CcBackgroundItem *item)
|
||||||
|
{
|
||||||
|
GListStore *store;
|
||||||
|
const gchar *uri;
|
||||||
|
guint i;
|
||||||
|
|
||||||
|
g_return_if_fail (BG_IS_RECENT_SOURCE (self));
|
||||||
|
g_return_if_fail (CC_IS_BACKGROUND_ITEM (item));
|
||||||
|
|
||||||
|
uri = cc_background_item_get_uri (item);
|
||||||
|
store = bg_source_get_liststore (BG_SOURCE (self));
|
||||||
|
|
||||||
|
g_debug ("Removing wallpaper %s", uri);
|
||||||
|
|
||||||
|
for (i = 0; i < g_list_model_get_n_items (G_LIST_MODEL (store)); i++)
|
||||||
|
{
|
||||||
|
g_autoptr(CcBackgroundItem) tmp = NULL;
|
||||||
|
|
||||||
|
tmp = g_list_model_get_item (G_LIST_MODEL (store), i);
|
||||||
|
|
||||||
|
if (tmp == item)
|
||||||
|
{
|
||||||
|
g_list_store_remove (store, i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
g_hash_table_remove (self->items, cc_background_item_get_uri (item));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
query_info_finished_cb (GObject *source,
|
||||||
|
GAsyncResult *result,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
BgRecentSource *self;
|
||||||
|
g_autoptr(GFileInfo) file_info = NULL;
|
||||||
|
g_autoptr(GError) error = NULL;
|
||||||
|
GFile *file = NULL;
|
||||||
|
|
||||||
|
file = G_FILE (source);
|
||||||
|
file_info = g_file_query_info_finish (file, result, &error);
|
||||||
|
if (error)
|
||||||
|
{
|
||||||
|
if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
|
||||||
|
g_warning ("Could not get pictures file information: %s", error->message);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
self = BG_RECENT_SOURCE (user_data);
|
||||||
|
|
||||||
|
g_debug ("Adding wallpaper %s (%d)",
|
||||||
|
g_file_info_get_name (file_info),
|
||||||
|
G_IS_FILE (self->backgrounds_folder));
|
||||||
|
|
||||||
|
add_file_from_info (self, file, file_info);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
on_file_changed_cb (BgRecentSource *self,
|
||||||
|
GFile *file,
|
||||||
|
GFile *other_file,
|
||||||
|
GFileMonitorEvent event_type)
|
||||||
|
{
|
||||||
|
g_autofree gchar *uri = NULL;
|
||||||
|
|
||||||
|
switch (event_type)
|
||||||
|
{
|
||||||
|
case G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT:
|
||||||
|
g_file_query_info_async (file,
|
||||||
|
ATTRIBUTES,
|
||||||
|
G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
|
||||||
|
G_PRIORITY_DEFAULT,
|
||||||
|
self->cancellable,
|
||||||
|
query_info_finished_cb,
|
||||||
|
self);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case G_FILE_MONITOR_EVENT_DELETED:
|
||||||
|
uri = g_file_get_uri (file);
|
||||||
|
remove_item (self, g_hash_table_lookup (self->items, uri));
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
file_sort_func (gconstpointer a,
|
||||||
|
gconstpointer b)
|
||||||
|
{
|
||||||
|
GFileInfo *file_a = G_FILE_INFO (a);
|
||||||
|
GFileInfo *file_b = G_FILE_INFO (b);
|
||||||
|
guint64 modified_a, modified_b;
|
||||||
|
|
||||||
|
modified_a = g_file_info_get_attribute_uint64 (file_a, G_FILE_ATTRIBUTE_TIME_MODIFIED);
|
||||||
|
modified_b = g_file_info_get_attribute_uint64 (file_b, G_FILE_ATTRIBUTE_TIME_MODIFIED);
|
||||||
|
|
||||||
|
return modified_b - modified_a;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
file_info_async_ready_cb (GObject *source,
|
||||||
|
GAsyncResult *result,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
BgRecentSource *self;
|
||||||
|
g_autolist(GFileInfo) file_infos = NULL;
|
||||||
|
g_autoptr(GError) error = NULL;
|
||||||
|
GFile *parent = NULL;
|
||||||
|
GList *l;
|
||||||
|
|
||||||
|
file_infos = g_file_enumerator_next_files_finish (G_FILE_ENUMERATOR (source),
|
||||||
|
result,
|
||||||
|
&error);
|
||||||
|
if (error)
|
||||||
|
{
|
||||||
|
if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
|
||||||
|
g_warning ("Could not get pictures file information: %s", error->message);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
self = BG_RECENT_SOURCE (user_data);
|
||||||
|
parent = g_file_enumerator_get_container (G_FILE_ENUMERATOR (source));
|
||||||
|
|
||||||
|
file_infos = g_list_sort (file_infos, file_sort_func);
|
||||||
|
|
||||||
|
for (l = file_infos; l; l = l->next)
|
||||||
|
{
|
||||||
|
g_autoptr(GFile) file = NULL;
|
||||||
|
GFileInfo *info;
|
||||||
|
|
||||||
|
info = l->data;
|
||||||
|
file = g_file_get_child (parent, g_file_info_get_name (info));
|
||||||
|
|
||||||
|
g_debug ("Found recent wallpaper %s", g_file_info_get_name (info));
|
||||||
|
|
||||||
|
add_file_from_info (self, file, info);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_file_enumerator_close (G_FILE_ENUMERATOR (source), self->cancellable, &error);
|
||||||
|
|
||||||
|
if (error)
|
||||||
|
g_warning ("Error closing file enumerator: %s", error->message);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
enumerate_children_finished_cb (GObject *source,
|
||||||
|
GAsyncResult *result,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
BgRecentSource *self;
|
||||||
|
g_autoptr(GFileEnumerator) enumerator = NULL;
|
||||||
|
g_autoptr(GError) error = NULL;
|
||||||
|
|
||||||
|
enumerator = g_file_enumerate_children_finish (G_FILE (source), result, &error);
|
||||||
|
|
||||||
|
if (error)
|
||||||
|
{
|
||||||
|
if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
|
||||||
|
g_warning ("Could not fill pictures source: %s", error->message);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
self = BG_RECENT_SOURCE (user_data);
|
||||||
|
g_file_enumerator_next_files_async (enumerator,
|
||||||
|
G_MAXINT,
|
||||||
|
G_PRIORITY_DEFAULT,
|
||||||
|
self->cancellable,
|
||||||
|
file_info_async_ready_cb,
|
||||||
|
self);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
load_backgrounds (BgRecentSource *self)
|
||||||
|
{
|
||||||
|
g_autofree gchar *backgrounds_path = NULL;
|
||||||
|
g_autoptr(GError) error = NULL;
|
||||||
|
|
||||||
|
if (!g_file_make_directory_with_parents (self->backgrounds_folder, self->cancellable, &error) &&
|
||||||
|
!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_EXISTS))
|
||||||
|
{
|
||||||
|
g_critical ("Failed to create local background directory: %s", error->message);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
backgrounds_path = g_file_get_path (self->backgrounds_folder);
|
||||||
|
g_debug ("Enumerating wallpapers under %s", backgrounds_path);
|
||||||
|
|
||||||
|
g_file_enumerate_children_async (self->backgrounds_folder,
|
||||||
|
ATTRIBUTES,
|
||||||
|
G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
|
||||||
|
G_PRIORITY_DEFAULT,
|
||||||
|
self->cancellable,
|
||||||
|
enumerate_children_finished_cb,
|
||||||
|
self);
|
||||||
|
|
||||||
|
self->monitor = g_file_monitor_directory (self->backgrounds_folder,
|
||||||
|
G_FILE_MONITOR_WATCH_MOVES,
|
||||||
|
self->cancellable,
|
||||||
|
&error);
|
||||||
|
|
||||||
|
if (!self->monitor)
|
||||||
|
{
|
||||||
|
g_critical ("Failed to monitor background directory: %s", error->message);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_signal_connect_object (self->monitor, "changed", G_CALLBACK (on_file_changed_cb), self, G_CONNECT_SWAPPED);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Callbacks */
|
||||||
|
|
||||||
|
static void
|
||||||
|
on_file_copied_cb (GObject *source,
|
||||||
|
GAsyncResult *result,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
g_autoptr(BgRecentSource) self = BG_RECENT_SOURCE (user_data);
|
||||||
|
g_autofree gchar *original_file = NULL;
|
||||||
|
g_autoptr(GError) error = NULL;
|
||||||
|
|
||||||
|
g_file_copy_finish (G_FILE (source), result, &error);
|
||||||
|
|
||||||
|
if (error)
|
||||||
|
{
|
||||||
|
if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
|
||||||
|
g_critical ("Failed to copy file: %s", error->message);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
original_file = g_file_get_path (G_FILE (source));
|
||||||
|
g_debug ("Successfully copied wallpaper: %s", original_file);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
on_file_deleted_cb (GObject *source,
|
||||||
|
GAsyncResult *result,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
g_autoptr(BgRecentSource) self = BG_RECENT_SOURCE (user_data);
|
||||||
|
g_autofree gchar *original_file = NULL;
|
||||||
|
g_autoptr(GError) error = NULL;
|
||||||
|
|
||||||
|
g_file_delete_finish (G_FILE (source), result, &error);
|
||||||
|
|
||||||
|
if (error)
|
||||||
|
{
|
||||||
|
if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
|
||||||
|
g_critical ("Failed to delete wallpaper: %s", error->message);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
original_file = g_file_get_path (G_FILE (source));
|
||||||
|
g_debug ("Successfully deleted wallpaper: %s", original_file);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* GObject overrides */
|
||||||
|
|
||||||
|
static void
|
||||||
|
bg_recent_source_finalize (GObject *object)
|
||||||
|
{
|
||||||
|
BgRecentSource *self = (BgRecentSource *)object;
|
||||||
|
|
||||||
|
g_cancellable_cancel (self->cancellable);
|
||||||
|
g_clear_object (&self->cancellable);
|
||||||
|
g_clear_object (&self->monitor);
|
||||||
|
|
||||||
|
G_OBJECT_CLASS (bg_recent_source_parent_class)->finalize (object);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
bg_recent_source_class_init (BgRecentSourceClass *klass)
|
||||||
|
{
|
||||||
|
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||||
|
|
||||||
|
object_class->finalize = bg_recent_source_finalize;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
bg_recent_source_init (BgRecentSource *self)
|
||||||
|
{
|
||||||
|
g_autofree gchar *backgrounds_path = NULL;
|
||||||
|
|
||||||
|
backgrounds_path = g_build_filename (g_get_user_data_dir (), "backgrounds", NULL);
|
||||||
|
|
||||||
|
self->items = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref);
|
||||||
|
self->cancellable = g_cancellable_new ();
|
||||||
|
self->backgrounds_folder = g_file_new_for_path (backgrounds_path);
|
||||||
|
|
||||||
|
load_backgrounds (self);
|
||||||
|
}
|
||||||
|
|
||||||
|
BgRecentSource*
|
||||||
|
bg_recent_source_new (void)
|
||||||
|
{
|
||||||
|
return g_object_new (BG_TYPE_RECENT_SOURCE, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
bg_recent_source_add_file (BgRecentSource *self,
|
||||||
|
const gchar *path)
|
||||||
|
{
|
||||||
|
g_autoptr(GDateTime) now = NULL;
|
||||||
|
g_autofree gchar *destination_name = NULL;
|
||||||
|
g_autofree gchar *formatted_now = NULL;
|
||||||
|
g_autofree gchar *basename = NULL;
|
||||||
|
g_autoptr(GFile) destination = NULL;
|
||||||
|
g_autoptr(GFile) file = NULL;
|
||||||
|
|
||||||
|
g_return_if_fail (BG_IS_RECENT_SOURCE (self));
|
||||||
|
g_return_if_fail (path && *path);
|
||||||
|
|
||||||
|
g_debug ("Importing wallpaper %s", path);
|
||||||
|
|
||||||
|
now = g_date_time_new_now_local ();
|
||||||
|
formatted_now = g_date_time_format (now, "%Y-%m-%d-%H-%M-%S");
|
||||||
|
|
||||||
|
file = g_file_new_for_path (path);
|
||||||
|
|
||||||
|
basename = g_file_get_basename (file);
|
||||||
|
destination_name = g_strdup_printf ("%s-%s", formatted_now, basename);
|
||||||
|
destination = g_file_get_child (self->backgrounds_folder, destination_name);
|
||||||
|
|
||||||
|
g_file_copy_async (file,
|
||||||
|
destination,
|
||||||
|
G_FILE_COPY_NONE,
|
||||||
|
G_PRIORITY_DEFAULT,
|
||||||
|
self->cancellable,
|
||||||
|
NULL, NULL,
|
||||||
|
on_file_copied_cb,
|
||||||
|
g_object_ref (self));
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
bg_recent_source_remove_item (BgRecentSource *self,
|
||||||
|
CcBackgroundItem *item)
|
||||||
|
{
|
||||||
|
g_autoptr(GFile) file = NULL;
|
||||||
|
const gchar *uri;
|
||||||
|
|
||||||
|
g_return_if_fail (BG_IS_RECENT_SOURCE (self));
|
||||||
|
g_return_if_fail (CC_IS_BACKGROUND_ITEM (item));
|
||||||
|
|
||||||
|
uri = cc_background_item_get_uri (item);
|
||||||
|
file = g_file_new_for_uri (uri);
|
||||||
|
|
||||||
|
g_file_delete_async (file,
|
||||||
|
G_PRIORITY_DEFAULT,
|
||||||
|
self->cancellable,
|
||||||
|
on_file_deleted_cb,
|
||||||
|
g_object_ref (self));
|
||||||
|
}
|
39
panels/background/bg-recent-source.h
Normal file
39
panels/background/bg-recent-source.h
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
/* bg-recent-source.h
|
||||||
|
*
|
||||||
|
* Copyright 2019 Georges Basile Stavracas Neto <georges.stavracas@gmail.com>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "bg-source.h"
|
||||||
|
#include "cc-background-item.h"
|
||||||
|
|
||||||
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
|
#define BG_TYPE_RECENT_SOURCE (bg_recent_source_get_type())
|
||||||
|
G_DECLARE_FINAL_TYPE (BgRecentSource, bg_recent_source, BG, RECENT_SOURCE, BgSource)
|
||||||
|
|
||||||
|
BgRecentSource* bg_recent_source_new (void);
|
||||||
|
|
||||||
|
void bg_recent_source_add_file (BgRecentSource *self,
|
||||||
|
const gchar *path);
|
||||||
|
|
||||||
|
void bg_recent_source_remove_item (BgRecentSource *self,
|
||||||
|
CcBackgroundItem *item);
|
||||||
|
|
||||||
|
G_END_DECLS
|
102
panels/background/bg-source.c
Normal file
102
panels/background/bg-source.c
Normal file
|
@ -0,0 +1,102 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2010 Intel, Inc
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Author: Thomas Wood <thomas.wood@intel.com>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "bg-source.h"
|
||||||
|
#include "cc-background-item.h"
|
||||||
|
|
||||||
|
#include <cairo-gobject.h>
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
GListStore *store;
|
||||||
|
} BgSourcePrivate;
|
||||||
|
|
||||||
|
G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (BgSource, bg_source, G_TYPE_OBJECT)
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
PROP_0,
|
||||||
|
PROP_LISTSTORE
|
||||||
|
};
|
||||||
|
|
||||||
|
static void
|
||||||
|
bg_source_get_property (GObject *object,
|
||||||
|
guint property_id,
|
||||||
|
GValue *value,
|
||||||
|
GParamSpec *pspec)
|
||||||
|
{
|
||||||
|
BgSource *source = BG_SOURCE (object);
|
||||||
|
|
||||||
|
switch (property_id)
|
||||||
|
{
|
||||||
|
case PROP_LISTSTORE:
|
||||||
|
g_value_set_object (value, bg_source_get_liststore (source));
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
bg_source_dispose (GObject *object)
|
||||||
|
{
|
||||||
|
BgSource *source = BG_SOURCE (object);
|
||||||
|
BgSourcePrivate *priv = bg_source_get_instance_private (source);
|
||||||
|
|
||||||
|
g_clear_object (&priv->store);
|
||||||
|
|
||||||
|
G_OBJECT_CLASS (bg_source_parent_class)->dispose (object);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
bg_source_class_init (BgSourceClass *klass)
|
||||||
|
{
|
||||||
|
GParamSpec *pspec;
|
||||||
|
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||||
|
|
||||||
|
object_class->get_property = bg_source_get_property;
|
||||||
|
object_class->dispose = bg_source_dispose;
|
||||||
|
|
||||||
|
pspec = g_param_spec_object ("liststore",
|
||||||
|
"Liststore",
|
||||||
|
"Liststore used in the source",
|
||||||
|
G_TYPE_LIST_STORE,
|
||||||
|
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
|
||||||
|
g_object_class_install_property (object_class, PROP_LISTSTORE, pspec);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
bg_source_init (BgSource *self)
|
||||||
|
{
|
||||||
|
BgSourcePrivate *priv = bg_source_get_instance_private (self);
|
||||||
|
priv->store = g_list_store_new (CC_TYPE_BACKGROUND_ITEM);
|
||||||
|
}
|
||||||
|
|
||||||
|
GListStore*
|
||||||
|
bg_source_get_liststore (BgSource *source)
|
||||||
|
{
|
||||||
|
BgSourcePrivate *priv;
|
||||||
|
|
||||||
|
g_return_val_if_fail (BG_IS_SOURCE (source), NULL);
|
||||||
|
|
||||||
|
priv = bg_source_get_instance_private (source);
|
||||||
|
return priv->store;
|
||||||
|
}
|
38
panels/background/bg-source.h
Normal file
38
panels/background/bg-source.h
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2010 Intel, Inc
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Author: Thomas Wood <thomas.wood@intel.com>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <gtk/gtk.h>
|
||||||
|
#include <libgnome-desktop/gnome-desktop-thumbnail.h>
|
||||||
|
|
||||||
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
|
#define BG_TYPE_SOURCE (bg_source_get_type ())
|
||||||
|
G_DECLARE_DERIVABLE_TYPE (BgSource, bg_source, BG, SOURCE, GObject)
|
||||||
|
|
||||||
|
struct _BgSourceClass
|
||||||
|
{
|
||||||
|
GObjectClass parent_class;
|
||||||
|
};
|
||||||
|
|
||||||
|
GListStore* bg_source_get_liststore (BgSource *source);
|
||||||
|
|
||||||
|
G_END_DECLS
|
163
panels/background/bg-wallpapers-source.c
Normal file
163
panels/background/bg-wallpapers-source.c
Normal file
|
@ -0,0 +1,163 @@
|
||||||
|
/* bg-wallpapers-source.c */
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2010 Intel, Inc
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Author: Thomas Wood <thomas.wood@intel.com>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "bg-wallpapers-source.h"
|
||||||
|
|
||||||
|
#include "cc-background-item.h"
|
||||||
|
#include "cc-background-xml.h"
|
||||||
|
|
||||||
|
#include <cairo-gobject.h>
|
||||||
|
#include <gio/gio.h>
|
||||||
|
|
||||||
|
struct _BgWallpapersSource
|
||||||
|
{
|
||||||
|
BgSource parent_instance;
|
||||||
|
CcBackgroundXml *xml;
|
||||||
|
};
|
||||||
|
|
||||||
|
G_DEFINE_TYPE (BgWallpapersSource, bg_wallpapers_source, BG_TYPE_SOURCE)
|
||||||
|
|
||||||
|
static int
|
||||||
|
sort_func (gconstpointer a,
|
||||||
|
gconstpointer b,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
CcBackgroundItem *item_a;
|
||||||
|
CcBackgroundItem *item_b;
|
||||||
|
const char *name_a;
|
||||||
|
const char *name_b;
|
||||||
|
|
||||||
|
item_a = (CcBackgroundItem *) a;
|
||||||
|
item_b = (CcBackgroundItem *) b;
|
||||||
|
|
||||||
|
name_a = cc_background_item_get_name (item_a);
|
||||||
|
name_b = cc_background_item_get_name (item_b);
|
||||||
|
|
||||||
|
if (name_a && strcmp (name_a, "Default Background") == 0)
|
||||||
|
return -1;
|
||||||
|
if (name_b && strcmp (name_b, "Default Background") == 0)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
|
||||||
|
return strcmp (cc_background_item_get_name (item_a),
|
||||||
|
cc_background_item_get_name (item_b));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
load_wallpapers (gchar *key,
|
||||||
|
CcBackgroundItem *item,
|
||||||
|
BgWallpapersSource *source)
|
||||||
|
{
|
||||||
|
GListStore *store = bg_source_get_liststore (BG_SOURCE (source));
|
||||||
|
gboolean deleted;
|
||||||
|
|
||||||
|
g_object_get (G_OBJECT (item), "is-deleted", &deleted, NULL);
|
||||||
|
|
||||||
|
if (deleted)
|
||||||
|
return;
|
||||||
|
|
||||||
|
g_list_store_insert_sorted (store, item, sort_func, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
list_load_cb (GObject *source_object,
|
||||||
|
GAsyncResult *res,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
g_autoptr(GError) error = NULL;
|
||||||
|
if (!cc_background_xml_load_list_finish (CC_BACKGROUND_XML (source_object), res, &error))
|
||||||
|
g_warning ("Failed to load background list: %s", error->message);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
item_added (BgWallpapersSource *self,
|
||||||
|
CcBackgroundItem *item)
|
||||||
|
{
|
||||||
|
load_wallpapers (NULL, item, self);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
load_default_bg (BgWallpapersSource *self)
|
||||||
|
{
|
||||||
|
const char * const *system_data_dirs;
|
||||||
|
guint i;
|
||||||
|
|
||||||
|
/* FIXME We could do this nicer if we had the XML source in GSettings */
|
||||||
|
|
||||||
|
system_data_dirs = g_get_system_data_dirs ();
|
||||||
|
for (i = 0; system_data_dirs[i]; i++) {
|
||||||
|
g_autofree gchar *filename = NULL;
|
||||||
|
|
||||||
|
filename = g_build_filename (system_data_dirs[i],
|
||||||
|
"gnome-background-properties",
|
||||||
|
"adwaita.xml",
|
||||||
|
NULL);
|
||||||
|
if (cc_background_xml_load_xml (self->xml, filename))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
bg_wallpapers_source_constructed (GObject *object)
|
||||||
|
{
|
||||||
|
BgWallpapersSource *self = BG_WALLPAPERS_SOURCE (object);
|
||||||
|
|
||||||
|
G_OBJECT_CLASS (bg_wallpapers_source_parent_class)->constructed (object);
|
||||||
|
|
||||||
|
g_signal_connect_object (G_OBJECT (self->xml), "added",
|
||||||
|
G_CALLBACK (item_added), self, G_CONNECT_SWAPPED);
|
||||||
|
|
||||||
|
/* Try adding the default background first */
|
||||||
|
load_default_bg (self);
|
||||||
|
|
||||||
|
cc_background_xml_load_list_async (self->xml, NULL, list_load_cb, self);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
bg_wallpapers_source_dispose (GObject *object)
|
||||||
|
{
|
||||||
|
BgWallpapersSource *self = BG_WALLPAPERS_SOURCE (object);
|
||||||
|
|
||||||
|
g_clear_object (&self->xml);
|
||||||
|
|
||||||
|
G_OBJECT_CLASS (bg_wallpapers_source_parent_class)->dispose (object);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
bg_wallpapers_source_init (BgWallpapersSource *self)
|
||||||
|
{
|
||||||
|
self->xml = cc_background_xml_new ();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
bg_wallpapers_source_class_init (BgWallpapersSourceClass *klass)
|
||||||
|
{
|
||||||
|
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||||
|
|
||||||
|
object_class->constructed = bg_wallpapers_source_constructed;
|
||||||
|
object_class->dispose = bg_wallpapers_source_dispose;
|
||||||
|
}
|
||||||
|
|
||||||
|
BgWallpapersSource *
|
||||||
|
bg_wallpapers_source_new (void)
|
||||||
|
{
|
||||||
|
return g_object_new (BG_TYPE_WALLPAPERS_SOURCE, NULL);
|
||||||
|
}
|
34
panels/background/bg-wallpapers-source.h
Normal file
34
panels/background/bg-wallpapers-source.h
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
/* bg-wallpapers-source.h */
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2010 Intel, Inc
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Author: Thomas Wood <thomas.wood@intel.com>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <gtk/gtk.h>
|
||||||
|
#include "bg-source.h"
|
||||||
|
|
||||||
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
|
#define BG_TYPE_WALLPAPERS_SOURCE (bg_wallpapers_source_get_type ())
|
||||||
|
G_DECLARE_FINAL_TYPE (BgWallpapersSource, bg_wallpapers_source, BG, WALLPAPERS_SOURCE, BgSource)
|
||||||
|
|
||||||
|
BgWallpapersSource *bg_wallpapers_source_new (void);
|
||||||
|
|
||||||
|
G_END_DECLS
|
527
panels/background/cc-background-chooser.c
Normal file
527
panels/background/cc-background-chooser.c
Normal file
|
@ -0,0 +1,527 @@
|
||||||
|
/* cc-background-chooser.c
|
||||||
|
*
|
||||||
|
* Copyright 2019 Georges Basile Stavracas Neto <georges.stavracas@gmail.com>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*/
|
||||||
|
|
||||||
|
#undef G_LOG_DOMAIN
|
||||||
|
#define G_LOG_DOMAIN "cc-background-chooser"
|
||||||
|
|
||||||
|
#include <adwaita.h>
|
||||||
|
#include <glib/gi18n.h>
|
||||||
|
#include <libgnome-desktop/gnome-desktop-thumbnail.h>
|
||||||
|
|
||||||
|
#include "bg-recent-source.h"
|
||||||
|
#include "bg-wallpapers-source.h"
|
||||||
|
#include "cc-background-chooser.h"
|
||||||
|
#include "cc-background-paintable.h"
|
||||||
|
#include "cc-background-item.h"
|
||||||
|
|
||||||
|
#define THUMBNAIL_WIDTH 144
|
||||||
|
#define THUMBNAIL_HEIGHT (THUMBNAIL_WIDTH * 3 / 4)
|
||||||
|
|
||||||
|
struct _CcBackgroundChooser
|
||||||
|
{
|
||||||
|
GtkBox parent;
|
||||||
|
|
||||||
|
GtkFlowBox *flowbox;
|
||||||
|
GtkWidget *recent_box;
|
||||||
|
GtkFlowBox *recent_flowbox;
|
||||||
|
|
||||||
|
gboolean recent_selected;
|
||||||
|
|
||||||
|
BgWallpapersSource *wallpapers_source;
|
||||||
|
BgRecentSource *recent_source;
|
||||||
|
|
||||||
|
CcBackgroundItem *active_item;
|
||||||
|
|
||||||
|
GnomeDesktopThumbnailFactory *thumbnail_factory;
|
||||||
|
|
||||||
|
AdwToastOverlay *toast_overlay;
|
||||||
|
AdwToast *toast;
|
||||||
|
GPtrArray *removed_backgrounds;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
BgRecentSource *recent_source;
|
||||||
|
CcBackgroundItem *item;
|
||||||
|
GtkWidget *parent;
|
||||||
|
} UndoData;
|
||||||
|
|
||||||
|
G_DEFINE_TYPE (CcBackgroundChooser, cc_background_chooser, GTK_TYPE_BOX)
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
PROP_0,
|
||||||
|
PROP_TOAST_OVERLAY,
|
||||||
|
N_PROPS
|
||||||
|
};
|
||||||
|
|
||||||
|
static GParamSpec *properties [N_PROPS];
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
BACKGROUND_CHOSEN,
|
||||||
|
N_SIGNALS,
|
||||||
|
};
|
||||||
|
|
||||||
|
static guint signals [N_SIGNALS];
|
||||||
|
|
||||||
|
static void
|
||||||
|
emit_background_chosen (CcBackgroundChooser *self)
|
||||||
|
{
|
||||||
|
g_autoptr(GList) list = NULL;
|
||||||
|
CcBackgroundItem *item;
|
||||||
|
GtkFlowBox *flowbox;
|
||||||
|
|
||||||
|
flowbox = self->recent_selected ? self->recent_flowbox : self->flowbox;
|
||||||
|
list = gtk_flow_box_get_selected_children (flowbox);
|
||||||
|
g_assert (g_list_length (list) == 1);
|
||||||
|
|
||||||
|
item = g_object_get_data (list->data, "item");
|
||||||
|
|
||||||
|
g_signal_emit (self, signals[BACKGROUND_CHOSEN], 0, item);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
really_delete_background (gpointer data)
|
||||||
|
{
|
||||||
|
UndoData *undo_data = data;
|
||||||
|
|
||||||
|
bg_recent_source_remove_item (undo_data->recent_source, undo_data->item);
|
||||||
|
g_free (undo_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
undo_remove (gpointer data)
|
||||||
|
{
|
||||||
|
UndoData *undo_data = data;
|
||||||
|
|
||||||
|
gtk_widget_set_visible (undo_data->parent, TRUE);
|
||||||
|
g_free (undo_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
on_removed_backgrounds_undo (CcBackgroundChooser *self)
|
||||||
|
{
|
||||||
|
g_ptr_array_set_free_func (self->removed_backgrounds, undo_remove);
|
||||||
|
gtk_widget_set_visible (self->recent_box, TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
on_removed_backgrounds_dismissed (CcBackgroundChooser *self)
|
||||||
|
{
|
||||||
|
self->toast = NULL;
|
||||||
|
g_clear_pointer (&self->removed_backgrounds, g_ptr_array_unref);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
on_delete_background_clicked_cb (GtkButton *button,
|
||||||
|
BgRecentSource *source)
|
||||||
|
{
|
||||||
|
GtkWidget *parent;
|
||||||
|
CcBackgroundChooser *self;
|
||||||
|
CcBackgroundItem *item;
|
||||||
|
UndoData *undo_data;
|
||||||
|
GListStore *store;
|
||||||
|
|
||||||
|
parent = gtk_widget_get_parent (gtk_widget_get_parent (GTK_WIDGET (button)));
|
||||||
|
g_assert (GTK_IS_FLOW_BOX_CHILD (parent));
|
||||||
|
|
||||||
|
item = g_object_get_data (G_OBJECT (parent), "item");
|
||||||
|
self = g_object_get_data (G_OBJECT (source), "background-chooser");
|
||||||
|
|
||||||
|
gtk_widget_set_visible (parent, FALSE);
|
||||||
|
|
||||||
|
/* Add background to the array of rows to be handled by the undo toast */
|
||||||
|
if (!self->removed_backgrounds)
|
||||||
|
self->removed_backgrounds = g_ptr_array_new_with_free_func (really_delete_background);
|
||||||
|
|
||||||
|
undo_data = g_new (UndoData, 1);
|
||||||
|
undo_data->recent_source = source;
|
||||||
|
undo_data->item = item;
|
||||||
|
undo_data->parent = parent;
|
||||||
|
|
||||||
|
g_ptr_array_add (self->removed_backgrounds, undo_data);
|
||||||
|
|
||||||
|
/* Recent flowbox should be hidden if all backgrounds are to be removed */
|
||||||
|
store = bg_source_get_liststore (BG_SOURCE (self->recent_source));
|
||||||
|
|
||||||
|
if (self->removed_backgrounds->len == g_list_model_get_n_items (G_LIST_MODEL (store)))
|
||||||
|
gtk_widget_set_visible (self->recent_box, FALSE);
|
||||||
|
|
||||||
|
if (!self->toast)
|
||||||
|
{
|
||||||
|
self->toast = adw_toast_new (_("Background removed"));
|
||||||
|
adw_toast_set_button_label (self->toast, _("_Undo"));
|
||||||
|
|
||||||
|
g_signal_connect_swapped (self->toast,
|
||||||
|
"button-clicked",
|
||||||
|
G_CALLBACK (on_removed_backgrounds_undo),
|
||||||
|
self);
|
||||||
|
g_signal_connect_swapped (self->toast,
|
||||||
|
"dismissed",
|
||||||
|
G_CALLBACK (on_removed_backgrounds_dismissed),
|
||||||
|
self);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
g_autofree gchar *message = NULL;
|
||||||
|
|
||||||
|
/* Translators: %d is the number of backgrounds deleted. */
|
||||||
|
message = g_strdup_printf (ngettext ("%d background removed",
|
||||||
|
"%d backgrounds removed",
|
||||||
|
self->removed_backgrounds->len),
|
||||||
|
self->removed_backgrounds->len);
|
||||||
|
|
||||||
|
adw_toast_set_title (self->toast, message);
|
||||||
|
|
||||||
|
g_object_ref (self->toast);
|
||||||
|
}
|
||||||
|
|
||||||
|
adw_toast_overlay_add_toast (self->toast_overlay, self->toast);
|
||||||
|
}
|
||||||
|
|
||||||
|
static GtkWidget*
|
||||||
|
create_widget_func (gpointer model_item,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
g_autoptr(CcBackgroundPaintable) paintable = NULL;
|
||||||
|
CcBackgroundChooser *self;
|
||||||
|
CcBackgroundItem *item;
|
||||||
|
GtkWidget *overlay;
|
||||||
|
GtkWidget *child;
|
||||||
|
GtkWidget *picture;
|
||||||
|
GtkWidget *icon;
|
||||||
|
GtkWidget *check;
|
||||||
|
GtkWidget *button = NULL;
|
||||||
|
BgSource *source;
|
||||||
|
|
||||||
|
source = BG_SOURCE (user_data);
|
||||||
|
item = CC_BACKGROUND_ITEM (model_item);
|
||||||
|
|
||||||
|
self = g_object_get_data (G_OBJECT (source), "background-chooser");
|
||||||
|
|
||||||
|
paintable = cc_background_paintable_new (self->thumbnail_factory,
|
||||||
|
item,
|
||||||
|
CC_BACKGROUND_PAINT_LIGHT_DARK,
|
||||||
|
THUMBNAIL_WIDTH,
|
||||||
|
THUMBNAIL_HEIGHT,
|
||||||
|
GTK_WIDGET (self));
|
||||||
|
|
||||||
|
picture = gtk_picture_new_for_paintable (GDK_PAINTABLE (paintable));
|
||||||
|
gtk_picture_set_can_shrink (GTK_PICTURE (picture), FALSE);
|
||||||
|
|
||||||
|
icon = gtk_image_new_from_icon_name ("slideshow-symbolic");
|
||||||
|
gtk_widget_set_halign (icon, GTK_ALIGN_START);
|
||||||
|
gtk_widget_set_valign (icon, GTK_ALIGN_END);
|
||||||
|
gtk_widget_set_visible (icon, cc_background_item_changes_with_time (item));
|
||||||
|
gtk_widget_add_css_class (icon, "slideshow-icon");
|
||||||
|
|
||||||
|
check = gtk_image_new_from_icon_name ("background-selected-symbolic");
|
||||||
|
gtk_widget_set_halign (check, GTK_ALIGN_END);
|
||||||
|
gtk_widget_set_valign (check, GTK_ALIGN_END);
|
||||||
|
gtk_widget_add_css_class (check, "selected-check");
|
||||||
|
|
||||||
|
if (BG_IS_RECENT_SOURCE (source))
|
||||||
|
{
|
||||||
|
button = gtk_button_new_from_icon_name ("cross-small-symbolic");
|
||||||
|
gtk_widget_set_halign (button, GTK_ALIGN_END);
|
||||||
|
gtk_widget_set_valign (button, GTK_ALIGN_START);
|
||||||
|
|
||||||
|
gtk_widget_add_css_class (button, "osd");
|
||||||
|
gtk_widget_add_css_class (button, "circular");
|
||||||
|
gtk_widget_add_css_class (button, "remove-button");
|
||||||
|
|
||||||
|
gtk_widget_set_tooltip_text (GTK_WIDGET (button), _("Remove Background"));
|
||||||
|
|
||||||
|
g_signal_connect (button,
|
||||||
|
"clicked",
|
||||||
|
G_CALLBACK (on_delete_background_clicked_cb),
|
||||||
|
source);
|
||||||
|
}
|
||||||
|
|
||||||
|
overlay = gtk_overlay_new ();
|
||||||
|
gtk_widget_set_overflow (overlay, GTK_OVERFLOW_HIDDEN);
|
||||||
|
gtk_widget_add_css_class (overlay, "background-thumbnail");
|
||||||
|
gtk_overlay_set_child (GTK_OVERLAY (overlay), picture);
|
||||||
|
gtk_overlay_add_overlay (GTK_OVERLAY (overlay), icon);
|
||||||
|
gtk_overlay_add_overlay (GTK_OVERLAY (overlay), check);
|
||||||
|
if (button)
|
||||||
|
gtk_overlay_add_overlay (GTK_OVERLAY (overlay), button);
|
||||||
|
|
||||||
|
child = gtk_flow_box_child_new ();
|
||||||
|
gtk_widget_set_halign (child, GTK_ALIGN_CENTER);
|
||||||
|
gtk_widget_set_valign (child, GTK_ALIGN_CENTER);
|
||||||
|
gtk_flow_box_child_set_child (GTK_FLOW_BOX_CHILD (child), overlay);
|
||||||
|
gtk_accessible_update_property (GTK_ACCESSIBLE (child),
|
||||||
|
GTK_ACCESSIBLE_PROPERTY_LABEL,
|
||||||
|
cc_background_item_get_name (item),
|
||||||
|
-1);
|
||||||
|
|
||||||
|
g_object_set_data_full (G_OBJECT (child), "item", g_object_ref (item), g_object_unref);
|
||||||
|
|
||||||
|
if (self->active_item && cc_background_item_compare (item, self->active_item))
|
||||||
|
{
|
||||||
|
gtk_widget_add_css_class (GTK_WIDGET (child), "active-item");
|
||||||
|
gtk_accessible_update_state (GTK_ACCESSIBLE (child),
|
||||||
|
GTK_ACCESSIBLE_STATE_CHECKED, TRUE,
|
||||||
|
-1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
gtk_accessible_update_state (GTK_ACCESSIBLE (child),
|
||||||
|
GTK_ACCESSIBLE_STATE_CHECKED, FALSE,
|
||||||
|
-1);
|
||||||
|
|
||||||
|
return child;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
update_recent_visibility (CcBackgroundChooser *self)
|
||||||
|
{
|
||||||
|
GListStore *store;
|
||||||
|
gboolean has_items;
|
||||||
|
|
||||||
|
store = bg_source_get_liststore (BG_SOURCE (self->recent_source));
|
||||||
|
has_items = g_list_model_get_n_items (G_LIST_MODEL (store)) != 0;
|
||||||
|
|
||||||
|
gtk_widget_set_visible (self->recent_box, has_items);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
setup_flowbox (CcBackgroundChooser *self)
|
||||||
|
{
|
||||||
|
GListStore *store;
|
||||||
|
|
||||||
|
store = bg_source_get_liststore (BG_SOURCE (self->wallpapers_source));
|
||||||
|
|
||||||
|
gtk_flow_box_bind_model (self->flowbox,
|
||||||
|
G_LIST_MODEL (store),
|
||||||
|
create_widget_func,
|
||||||
|
self->wallpapers_source,
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
store = bg_source_get_liststore (BG_SOURCE (self->recent_source));
|
||||||
|
|
||||||
|
gtk_flow_box_bind_model (self->recent_flowbox,
|
||||||
|
G_LIST_MODEL (store),
|
||||||
|
create_widget_func,
|
||||||
|
self->recent_source,
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
update_recent_visibility (self);
|
||||||
|
g_signal_connect_object (store,
|
||||||
|
"items-changed",
|
||||||
|
G_CALLBACK (update_recent_visibility),
|
||||||
|
self,
|
||||||
|
G_CONNECT_SWAPPED);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
on_item_activated_cb (CcBackgroundChooser *self,
|
||||||
|
GtkFlowBoxChild *child,
|
||||||
|
GtkFlowBox *flowbox)
|
||||||
|
{
|
||||||
|
self->recent_selected = flowbox == self->recent_flowbox;
|
||||||
|
if (self->recent_selected)
|
||||||
|
gtk_flow_box_unselect_all (self->flowbox);
|
||||||
|
else
|
||||||
|
gtk_flow_box_unselect_all (self->recent_flowbox);
|
||||||
|
emit_background_chosen (self);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
file_dialog_open_cb (GObject *source_object,
|
||||||
|
GAsyncResult *res,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
CcBackgroundChooser *self = CC_BACKGROUND_CHOOSER (user_data);
|
||||||
|
GtkFileDialog *file_dialog = GTK_FILE_DIALOG (source_object);
|
||||||
|
g_autoptr(GListModel) files = NULL;
|
||||||
|
g_autoptr(GError) error = NULL;
|
||||||
|
guint i;
|
||||||
|
|
||||||
|
files = gtk_file_dialog_open_multiple_finish (file_dialog, res, &error);
|
||||||
|
|
||||||
|
if (error != NULL)
|
||||||
|
{
|
||||||
|
g_warning ("Failed to pick backgrounds: %s", error->message);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < g_list_model_get_n_items (files); i++)
|
||||||
|
{
|
||||||
|
g_autoptr(GFile) file = g_list_model_get_item (files, i);
|
||||||
|
g_autofree gchar *filename = g_file_get_path (file);
|
||||||
|
|
||||||
|
bg_recent_source_add_file (self->recent_source, filename);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* GObject overrides */
|
||||||
|
|
||||||
|
static void
|
||||||
|
cc_background_chooser_set_property (GObject *object,
|
||||||
|
guint prop_id,
|
||||||
|
const GValue *value,
|
||||||
|
GParamSpec *pspec)
|
||||||
|
{
|
||||||
|
CcBackgroundChooser *self = CC_BACKGROUND_CHOOSER (object);
|
||||||
|
|
||||||
|
switch (prop_id)
|
||||||
|
{
|
||||||
|
case PROP_TOAST_OVERLAY:
|
||||||
|
self->toast_overlay = g_value_get_object (value);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
cc_background_chooser_finalize (GObject *object)
|
||||||
|
{
|
||||||
|
CcBackgroundChooser *self = (CcBackgroundChooser *)object;
|
||||||
|
|
||||||
|
g_clear_object (&self->recent_source);
|
||||||
|
g_clear_object (&self->wallpapers_source);
|
||||||
|
g_clear_object (&self->thumbnail_factory);
|
||||||
|
|
||||||
|
G_OBJECT_CLASS (cc_background_chooser_parent_class)->finalize (object);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
cc_background_chooser_class_init (CcBackgroundChooserClass *klass)
|
||||||
|
{
|
||||||
|
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||||
|
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
|
||||||
|
|
||||||
|
object_class->set_property = cc_background_chooser_set_property;
|
||||||
|
object_class->finalize = cc_background_chooser_finalize;
|
||||||
|
|
||||||
|
properties[PROP_TOAST_OVERLAY] = g_param_spec_object ("toast-overlay", NULL, NULL,
|
||||||
|
ADW_TYPE_TOAST_OVERLAY,
|
||||||
|
G_PARAM_WRITABLE |
|
||||||
|
G_PARAM_STATIC_STRINGS);
|
||||||
|
|
||||||
|
signals[BACKGROUND_CHOSEN] = g_signal_new ("background-chosen",
|
||||||
|
CC_TYPE_BACKGROUND_CHOOSER,
|
||||||
|
G_SIGNAL_RUN_FIRST,
|
||||||
|
0, NULL, NULL, NULL,
|
||||||
|
G_TYPE_NONE,
|
||||||
|
1,
|
||||||
|
CC_TYPE_BACKGROUND_ITEM);
|
||||||
|
|
||||||
|
gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/control-center/background/cc-background-chooser.ui");
|
||||||
|
|
||||||
|
gtk_widget_class_bind_template_child (widget_class, CcBackgroundChooser, flowbox);
|
||||||
|
gtk_widget_class_bind_template_child (widget_class, CcBackgroundChooser, recent_box);
|
||||||
|
gtk_widget_class_bind_template_child (widget_class, CcBackgroundChooser, recent_flowbox);
|
||||||
|
|
||||||
|
gtk_widget_class_bind_template_callback (widget_class, on_item_activated_cb);
|
||||||
|
|
||||||
|
g_object_class_install_properties (object_class, N_PROPS, properties);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
cc_background_chooser_init (CcBackgroundChooser *self)
|
||||||
|
{
|
||||||
|
gtk_widget_init_template (GTK_WIDGET (self));
|
||||||
|
|
||||||
|
self->recent_source = bg_recent_source_new ();
|
||||||
|
self->wallpapers_source = bg_wallpapers_source_new ();
|
||||||
|
|
||||||
|
self->thumbnail_factory = gnome_desktop_thumbnail_factory_new (GNOME_DESKTOP_THUMBNAIL_SIZE_LARGE);
|
||||||
|
g_object_set_data (G_OBJECT (self->recent_source), "background-chooser", self);
|
||||||
|
g_object_set_data (G_OBJECT (self->wallpapers_source), "background-chooser", self);
|
||||||
|
|
||||||
|
setup_flowbox (self);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
cc_background_chooser_select_file (CcBackgroundChooser *self)
|
||||||
|
{
|
||||||
|
g_autoptr(GFile) pictures_folder = NULL;
|
||||||
|
GtkFileFilter *filter;
|
||||||
|
GtkFileDialog *file_dialog;
|
||||||
|
GtkWindow *toplevel;
|
||||||
|
GListStore *filters;
|
||||||
|
|
||||||
|
g_return_if_fail (CC_IS_BACKGROUND_CHOOSER (self));
|
||||||
|
|
||||||
|
toplevel = (GtkWindow*) gtk_widget_get_native (GTK_WIDGET (self));
|
||||||
|
|
||||||
|
file_dialog = gtk_file_dialog_new ();
|
||||||
|
gtk_file_dialog_set_title (file_dialog, _("Select Picture"));
|
||||||
|
gtk_file_dialog_set_modal (file_dialog, TRUE);
|
||||||
|
|
||||||
|
filter = gtk_file_filter_new ();
|
||||||
|
gtk_file_filter_add_pixbuf_formats (filter);
|
||||||
|
|
||||||
|
filters = g_list_store_new (GTK_TYPE_FILE_FILTER);
|
||||||
|
g_list_store_append (filters, filter);
|
||||||
|
gtk_file_dialog_set_filters (file_dialog, G_LIST_MODEL (filters));
|
||||||
|
|
||||||
|
pictures_folder = g_file_new_for_path (g_get_user_special_dir (G_USER_DIRECTORY_PICTURES));
|
||||||
|
gtk_file_dialog_set_initial_folder (file_dialog, pictures_folder);
|
||||||
|
|
||||||
|
gtk_file_dialog_open_multiple (file_dialog,
|
||||||
|
toplevel,
|
||||||
|
NULL,
|
||||||
|
file_dialog_open_cb,
|
||||||
|
self);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void flow_box_set_active_item (GtkFlowBox *flowbox, CcBackgroundItem *active_item)
|
||||||
|
{
|
||||||
|
GtkFlowBoxChild *child = NULL;
|
||||||
|
CcBackgroundItem *item;
|
||||||
|
int idx = 0;
|
||||||
|
|
||||||
|
while ((child = gtk_flow_box_get_child_at_index (flowbox, idx++)))
|
||||||
|
{
|
||||||
|
item = g_object_get_data (G_OBJECT (child), "item");
|
||||||
|
|
||||||
|
if (cc_background_item_compare (item, active_item))
|
||||||
|
{
|
||||||
|
gtk_widget_add_css_class (GTK_WIDGET (child), "active-item");
|
||||||
|
gtk_accessible_update_state (GTK_ACCESSIBLE (child),
|
||||||
|
GTK_ACCESSIBLE_STATE_CHECKED, TRUE,
|
||||||
|
-1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
gtk_widget_remove_css_class (GTK_WIDGET (child), "active-item");
|
||||||
|
gtk_accessible_update_state (GTK_ACCESSIBLE (child),
|
||||||
|
GTK_ACCESSIBLE_STATE_CHECKED, FALSE,
|
||||||
|
-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
cc_background_chooser_set_active_item (CcBackgroundChooser *self, CcBackgroundItem *active_item)
|
||||||
|
{
|
||||||
|
g_return_if_fail (CC_IS_BACKGROUND_CHOOSER (self));
|
||||||
|
g_return_if_fail (CC_IS_BACKGROUND_ITEM (active_item));
|
||||||
|
|
||||||
|
self->active_item = active_item;
|
||||||
|
|
||||||
|
flow_box_set_active_item (self->flowbox, active_item);
|
||||||
|
flow_box_set_active_item (self->recent_flowbox, active_item);
|
||||||
|
}
|
35
panels/background/cc-background-chooser.h
Normal file
35
panels/background/cc-background-chooser.h
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
/* cc-background-chooser.h
|
||||||
|
*
|
||||||
|
* Copyright 2019 Georges Basile Stavracas Neto <georges.stavracas@gmail.com>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <gtk/gtk.h>
|
||||||
|
#include "cc-background-item.h"
|
||||||
|
|
||||||
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
|
#define CC_TYPE_BACKGROUND_CHOOSER (cc_background_chooser_get_type())
|
||||||
|
G_DECLARE_FINAL_TYPE (CcBackgroundChooser, cc_background_chooser, CC, BACKGROUND_CHOOSER, GtkBox)
|
||||||
|
|
||||||
|
void cc_background_chooser_select_file (CcBackgroundChooser *self);
|
||||||
|
void cc_background_chooser_set_active_item (CcBackgroundChooser *self,
|
||||||
|
CcBackgroundItem *active_item);
|
||||||
|
|
||||||
|
G_END_DECLS
|
64
panels/background/cc-background-chooser.ui
Normal file
64
panels/background/cc-background-chooser.ui
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<interface>
|
||||||
|
<template class="CcBackgroundChooser" parent="GtkBox">
|
||||||
|
<property name="orientation">vertical</property>
|
||||||
|
|
||||||
|
<!-- Recent -->
|
||||||
|
<child>
|
||||||
|
<object class="GtkBox" id="recent_box">
|
||||||
|
<property name="orientation">vertical</property>
|
||||||
|
<property name="halign">center</property>
|
||||||
|
|
||||||
|
<child>
|
||||||
|
<object class="GtkFlowBox" id="recent_flowbox">
|
||||||
|
<property name="margin-top">12</property>
|
||||||
|
<property name="margin-bottom">12</property>
|
||||||
|
<property name="margin-start">12</property>
|
||||||
|
<property name="margin-end">12</property>
|
||||||
|
<property name="column-spacing">12</property>
|
||||||
|
<property name="row-spacing">12</property>
|
||||||
|
<property name="homogeneous">True</property>
|
||||||
|
<property name="halign">center</property>
|
||||||
|
<property name="min-children-per-line">1</property>
|
||||||
|
<property name="max-children-per-line">8</property>
|
||||||
|
<property name="activate-on-single-click">True</property>
|
||||||
|
<property name="selection-mode">single</property>
|
||||||
|
<signal name="child-activated" handler="on_item_activated_cb" object="CcBackgroundChooser" swapped="yes" />
|
||||||
|
<style>
|
||||||
|
<class name="background-flowbox"/>
|
||||||
|
</style>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
|
||||||
|
<child>
|
||||||
|
<object class="GtkSeparator">
|
||||||
|
<property name="margin-top">12</property>
|
||||||
|
<property name="margin-bottom">12</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
|
||||||
|
<child>
|
||||||
|
<object class="GtkFlowBox" id="flowbox">
|
||||||
|
<property name="margin-top">12</property>
|
||||||
|
<property name="margin-bottom">12</property>
|
||||||
|
<property name="margin-start">12</property>
|
||||||
|
<property name="margin-end">12</property>
|
||||||
|
<property name="column-spacing">12</property>
|
||||||
|
<property name="row-spacing">12</property>
|
||||||
|
<property name="homogeneous">True</property>
|
||||||
|
<property name="halign">center</property>
|
||||||
|
<property name="min-children-per-line">1</property>
|
||||||
|
<property name="max-children-per-line">8</property>
|
||||||
|
<property name="activate-on-single-click">True</property>
|
||||||
|
<property name="selection-mode">single</property>
|
||||||
|
<signal name="child-activated" handler="on_item_activated_cb" object="CcBackgroundChooser" swapped="yes" />
|
||||||
|
<style>
|
||||||
|
<class name="background-flowbox"/>
|
||||||
|
</style>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
|
||||||
|
</template>
|
||||||
|
</interface>
|
1134
panels/background/cc-background-item.c
Normal file
1134
panels/background/cc-background-item.c
Normal file
File diff suppressed because it is too large
Load diff
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue