Compare commits

..

25 Commits

Author SHA1 Message Date
Georges Basile Stavracas Neto
9bb655555e 3.30.1 2018-09-25 21:27:12 -03:00
Georges Basile Stavracas Neto
4cd05ea9fd object-cache: Fix function documentation name 2018-09-25 21:18:32 -03:00
Georges Basile Stavracas Neto
928ac108d5 object-cache: Add more debug messages
Enough to ask users to run Settings with "G_MESSAGES_DEBUG=all"
and get some meaningful output.
2018-09-25 21:18:22 -03:00
Georges Basile Stavracas Neto
22957ff55a object-cache: Assert task_data before using it
It is not useful to assert that task_data != NULL after
using it to build the D-Bus key.

Move the assertion to before it is first used and get
rid of this inconsistency.
2018-09-25 21:18:21 -03:00
Georges Basile Stavracas Neto
4002b06f3a object-cache: Declare singleton instance as static
Otherwise, it is visible for other compile units. This
is a theoretical problem though, there's nothing wrong
happening right now.
2018-09-25 21:18:20 -03:00
Andrea Azzarone
b54bb72cb9 object-storage: Check for cancellation before resulting in assert failure
As per doumentation: "It is a programming error to create an identical proxy
while asynchronously creating one. Not cancelling this operation will result in
an assertion failure when calling cc_object_storage_create_dbus_proxy_finish()."
In order to fullfill the second part we need to check for errors (including
cancellation ones) before we generate an assertion failure.

Fixes: https://gitlab.gnome.org/GNOME/gnome-control-center/issues/158
2018-09-25 21:18:17 -03:00
Benjamin Berg
e037fdf1a0 power: Handle cancelled kbd brightness proxy creation
The code must not access the passed panel if the operation to create the
keyboard proxy has been cancelled. This fixes a possible crash when
switching away from the power panel.


(cherry picked from commit 75556d7c5a)
2018-09-25 03:01:49 +00:00
Benjamin Berg
81dec85a2c sharing: Bind hostname_entry from UI
The entry was not bound. Due to this we could run into a segfault trying
to query the hostname_entry. This would only happen if avahi is not
running.

Fixes #178


(cherry picked from commit 2bd03bbb6d)
2018-09-21 18:21:02 +00:00
Emin Tufan Çetin
d3026098b0 Update Turkish translation 2018-09-21 16:24:37 +00:00
Emin Tufan Çetin
c89e088a71 Update Turkish translation 2018-09-21 16:16:46 +00:00
RyuzakiKK
230f659a39 flatpak: disable mobile-broadband-provider-info
Without this flag at false network-manager-applet requires the
mobile-broadband-provider-info dependency that is not listed in this
flatpak


(cherry picked from commit ec57ffcdd5)
2018-09-19 14:21:44 +00:00
RyuzakiKK
63378ac30d flatpak: bump NetworkManager to version 1.14.0
The build option `-ltinfo` is required, otherwise a few errors related
to libreadline.so will be thrown like:

libreadline.so: undefined reference to `tputs'
libreadline.so: undefined reference to `tgoto'
libreadline.so: undefined reference to `tgetflag'


(cherry picked from commit c84246f42c)
2018-09-19 14:21:19 +00:00
RyuzakiKK
84910f796c flatpak: add meson build system to gnome-desktop
(cherry picked from commit 5912de10e4)
2018-09-19 14:20:47 +00:00
Christian Stadelmann
16ac4761ab Update German translation 2018-09-18 09:39:15 +00:00
Takao Fujiwara
f049eaf36e region: Do not release locale keys in IM hash table
simple_locale is g_autofree and it should be duplicate for IM hash table.

https://gitlab.gnome.org/GNOME/gnome-control-center/issues/185
2018-09-18 08:10:48 +02:00
Kalev Lember
689b21f48b color: Fix fallout from the GtkTemplate port
Correct a typoed variable name so that calibration works again, instead
of crashing.

GLib-GObject-WARNING **: 15:52:50.561: invalid cast from 'GtkBox' to 'GtkEntry'


(cherry picked from commit edc52c170d)
2018-09-15 23:14:00 +00:00
Marek Cernocky
ebf0f702a6 Updated Czech translation 2018-09-15 09:39:25 +02:00
Adrien Plazas
0f5f0bd23a flatpak: Add mozjs52
It is required by polkit.


(cherry picked from commit 6ae351ff46)
2018-09-14 15:46:46 +00:00
Robert Ancell
8384c29510 region: Cancel async permission requests when panel is closed
(cherry picked from commit 37d02369b7)
2018-09-10 15:51:41 +00:00
Robert Ancell
c8d19ed0da region: Fix language section not being marked insensitive
This is due to the widget not being extracted from region.ui and was introduced
in 5c418b8983.


(cherry picked from commit d4340c4efc)
2018-09-10 15:01:29 +00:00
Robert Ancell
eb9235ef30 region: Replace tab characters with spaces
(cherry picked from commit 0bdeb39319)
2018-09-10 14:55:06 +00:00
Robert Ancell
11877d3da7 region: Don't leak GFile objects
Creating the restart file leaked GFile objects. It also stored the path in the
object, which is unnecessary as it can just be generated on demand.

This leak has was introduced when the feature was in
db551f1c5d


(cherry picked from commit b718a20713)
2018-09-10 14:48:30 +00:00
Georges Basile Stavracas Neto
b3b5aa2235 ci: Make armv8 and ppc64le manual jobs
They consume too much CI resources and take a long time
to run, which slows down the review and merge process.

Make them manual from now on.
2018-09-10 11:42:14 -03:00
Robert Ancell
84d7270df1 region: Remove duplicate cancellable code
There was a GCancellable used for IBus operations that was generated each time
an operation was done. The cancellable was only used to cancel such operations
when the panel is closed. We can just use the shared cancellable for this.


(cherry picked from commit f036b3a706)
2018-09-10 14:20:09 +00:00
Piotr Drąg
a24c28cbcd Fix icons in translations
Fixes https://gitlab.gnome.org/GNOME/gnome-control-center/issues/181
2018-09-10 02:19:11 +02:00
1529 changed files with 443782 additions and 612197 deletions

View File

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

5
.gitignore vendored
View File

@@ -1,6 +1,3 @@
__pycache__
_build/
**/*~
/subprojects/*
!/subprojects/*.wrap
.flatpak-builder/
**/*~

View File

@@ -1,14 +1,9 @@
include:
- remote: 'https://gitlab.freedesktop.org/freedesktop/ci-templates/-/raw/34f4ade99434043f88e164933f570301fd18b125/templates/fedora.yml'
variables:
FDO_UPSTREAM_REPO: gnome/gnome-control-center
image: claudioandre/settings:job-502.6_fedora.dev # temporarily pinned to old tag
stages:
- prepare
- build
- test
- manual
- review
- deploy
.Log files: &log_files [./*.log, _build/meson-logs/]
@@ -31,160 +26,13 @@ stages:
.Build procedure: &build_procedure
echo "== Building ==" &&
dnf install -y dnf5-plugins &&
git clone https://gitlab.gnome.org/GNOME/gtk.git &&
cd gtk &&
dnf5 builddep -y gtk4 &&
meson setup . _build -Dprefix=/usr -Dlibdir=lib64 &&
ninja -C _build install &&
cd .. &&
rm -rf _build/ &&
meson . _build ${BUILD_OPTS} -Dprofile=development &&
meson . _build ${BUILD_OPTS} &&
ninja -C _build 2>&1 | tee compilation.log
.Run Tests: &run_tests
echo "== Testing ==" &&
meson test -C _build --verbose --no-stdsplit
.fedora.container.common:
# As of 2022-03-07 runners not tagged with "crun" have broken seccomp rules
# affecting the close_range syscall and breaking g_spawn
# Note that "asan" tests are disabled for the same reason, see below.
# https://gitlab.gnome.org/Infrastructure/GitLab/-/issues/545
tags: [ crun ]
variables:
# When branching a stable release, change 'main'
# to the release number/branch to ensure that
# a new image will be created, tailored for the
# stable branch.
# Could probably also switch away from rawhide,
# to stable fedora branch as well.
FDO_DISTRIBUTION_TAG: '2023-06-07.0-main'
FDO_DISTRIBUTION_VERSION: rawhide
#############################################
# Create CI Docker Images #
#############################################
# See also https://gitlab.freedesktop.org/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:
# - gobject-introspection-devel is needed for gsettings-desktop-schemas
FDO_DISTRIBUTION_PACKAGES: >-
@c-development @development-tools
git
llvm clang libasan libtsan libubsan gcovr
meson
accountsservice-devel
cheese-libs-devel
chrpath
colord-devel colord-gtk-devel
cups-devel
desktop-file-utils
docbook-style-xsl
flatpak-devel
gdk-pixbuf2-devel
gettext
glib2-devel
gobject-introspection-devel
gnome-bluetooth-libs-devel
gnome-desktop3-devel
gnome-online-accounts-devel
grilo-devel
gsettings-desktop-schemas-devel
gsound-devel
gtk3-devel ibus-devel
gtk4-devel
intltool
appstream-devel
sassc
libadwaita-devel
libcanberra-devel
libgtop2-devel
libgudev-devel
libnma-devel
libnotify-devel
libpwquality-devel
libsmbclient-devel
libsoup3-devel
libudisks2-devel
libwacom-devel
libX11-devel
libXi-devel
libxml2-devel
libxslt
ModemManager-glib-devel
NetworkManager-libnm-devel
polkit-devel
pulseaudio-libs-devel
upower-devel
python3-dbusmock
xorg-x11-server-Xvfb
mesa-dri-drivers
libsecret-devel
geocode-glib2-devel
libgweather-devel
lcms2-devel
geoclue2-devel
libnotify-devel
alsa-lib-devel
nss-devel
gcr3-devel
gcr-devel
setxkbmap
appstream-devel
FDO_DISTRIBUTION_EXEC: |-
git clone https://gitlab.gnome.org/GNOME/gsettings-desktop-schemas.git && \
cd gsettings-desktop-schemas && \
meson . _build --prefix=/usr && \
ninja -C _build && \
ninja -C _build install && \
cd .. && \
git clone https://gitlab.gnome.org/GNOME/gnome-desktop.git && \
cd gnome-desktop && \
meson . _build --prefix=/usr -Ddesktop_docs=false && \
ninja -C _build && \
ninja -C _build install && \
cd .. && \
git clone https://gitlab.gnome.org/GNOME/gnome-bluetooth.git && \
cd gnome-bluetooth && \
meson . _build --prefix=/usr -Dsendto=false && \
ninja -C _build && \
ninja -C _build install && \
cd .. && \
git clone https://gitlab.gnome.org/GNOME/libnma.git && \
cd libnma && \
meson . _build --prefix=/usr -Dlibnma_gtk4=true -Dmobile_broadband_provider_info=false -Dgcr=false -Dgtk_doc=false && \
ninja -C _build && \
ninja -C _build install && \
cd .. && \
git clone https://github.com/hughsie/colord-gtk.git && \
cd colord-gtk && \
meson . _build --prefix=/usr -Dgtk4=true -Ddocs=false -Dtests=false -Dman=false && \
ninja -C _build && \
ninja -C _build install && \
cd .. && \
git clone https://gitlab.gnome.org/GNOME/libgweather.git && \
cd libgweather && \
meson . _build --prefix=/usr -Denable_vala=false -Dgtk_doc=false -Dintrospection=false && \
ninja -C _build && \
ninja -C _build install && \
cd .. && \
git clone https://gitlab.gnome.org/GNOME/gnome-settings-daemon.git && \
cd gnome-settings-daemon && \
meson . _build --prefix=/usr && \
ninja -C _build && \
ninja -C _build install && \
cd ..
ninja -C _build test
##
# Stage: Build
@@ -194,10 +42,6 @@ build.container.fedora@x86_64:
# any of them.
##
build:
extends:
- '.fdo.distribution-image@fedora'
- '.fedora.container.common'
<<: *save_untracked_files
stage: build
@@ -214,32 +58,12 @@ build:
# Save all but git-related files
- rm -rf .git .gitignore .gitmodules
except:
variables:
- $CI_PIPELINE_SOURCE == "schedule"
##
# Stage: Test
#
# Runs static checks.
# Runs the unit tests.
##
style-check-diff:
extends:
- '.fdo.distribution-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
test:
extends:
- '.fdo.distribution-image@fedora'
- '.fedora.container.common'
<<: *save_build_logs
stage: test
@@ -248,36 +72,31 @@ test:
script:
- *environment_information
- *build_procedure
- *run_tests
- |
if [[ -n "${CI_COMMIT_TAG}" ]]; then
*run_tests
echo "== Distro Test =="
ninja dist -C _build
else
echo "== Testing =="
meson test -C _build --verbose --no-stdsplit
fi
artifacts:
reports:
junit: "_build/meson-logs/testlog.junit.xml"
except:
variables:
- $CI_PIPELINE_SOURCE == "schedule"
- $CI_COMMIT_TITLE =~ /^Update.*translation$/
# Runs the coverage test.
coverage:
extends:
- '.fdo.distribution-image@fedora'
- '.fedora.container.common'
<<: *save_build_logs
stage: test
variables:
BUILD_OPTS: "-Db_coverage=true"
coverage: '/^Lines:.\d+.\d+.(\d+\.\d+\%)/'
only:
- main@GNOME/gnome-control-center
- master@GNOME/gnome-control-center
script:
- *environment_information
@@ -293,7 +112,6 @@ coverage:
except:
variables:
- $CI_PIPELINE_SOURCE == "schedule"
- $CI_COMMIT_TITLE =~ /^Update.*translation$/
# Runs the address sanitizer.
@@ -305,9 +123,6 @@ coverage:
# Publishes the Coverage Report generated above
##
pages:
extends:
- '.fdo.distribution-image@fedora'
- '.fedora.container.common'
stage: deploy
dependencies:
- coverage
@@ -317,7 +132,7 @@ pages:
paths:
- public
only:
- main@GNOME/gnome-control-center
- master@GNOME/gnome-control-center
except:
variables:
@@ -331,18 +146,19 @@ pages:
##
flatpak:
stage: manual
image: quay.io/gnome_infrastructure/gnome-runtime-images:gnome-master
image: registry.gitlab.gnome.org/gnome/gnome-runtime-images/gnome:master
artifacts:
name: package
paths:
- $(pwd)/*.flatpak
expire_in: 7 days
expire_in: 2 days
variables:
OLD_APPID: "org.gnome.Settings"
APPID: "org.gnome.SettingsDevel"
BUNDLE: "org.gnome.SettingsDevel.flatpak"
MANIFEST_PATH: "build-aux/flatpak/org.gnome.Settings.json"
MANIFEST_PATH: "org.gnome.Settings.json"
PATCHES: "build-aux/flatpak/*.patch"
PROJECT_FILE: "build-aux/flatpak/org.gnome.Settings.json"
PROJECT_ID: "org.gnome.Settings"
PROJECT_NAME: "gnome-control-center.git"
RUNTIME_REPO: "https://sdk.gnome.org/gnome-nightly.flatpakrepo"
@@ -350,6 +166,10 @@ flatpak:
script:
- echo "== Flatpak packaging =="
# Move needed files to the root folder
- cp ${PATCHES} . || true
- cp ${PROJECT_FILE} ${MANIFEST_PATH}
# Make it a develoment manifest
- sed -i -n "p; s/$PROJECT_NAME//p" ${MANIFEST_PATH}
- >
@@ -363,11 +183,7 @@ flatpak:
- 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-builder --bundle-sources --repo=devel build ${MANIFEST_PATH}
- flatpak build-bundle devel ${BUNDLE} --runtime-repo=${RUNTIME_REPO} ${APPID}
cache:
@@ -377,14 +193,42 @@ flatpak:
except:
- tags
- gnome-3-.*
- main@GNOME/gnome-control-center
- master@GNOME/gnome-control-center
review:
stage: review
dependencies:
- flatpak
when: manual
variables:
BUNDLE: "org.gnome.SettingsDevel.flatpak"
script:
- echo "Generating flatpak deployment"
artifacts:
paths:
- ${BUNDLE}
expire_in: 30 days
environment:
name: review/$CI_COMMIT_REF_NAME
url: https://gitlab.gnome.org/$CI_PROJECT_PATH/-/jobs/$CI_JOB_ID/artifacts/raw/${BUNDLE}
on_stop: stop_review
except:
- tags
- gnome-3-.*
- master@GNOME/gnome-control-center
stop_review:
stage: review
script:
- echo "Stopping flatpak deployment"
when: manual
environment:
name: review/$CI_COMMIT_REF_NAME
action: stop
# Runs the sanitizers [address, thread, undefined, and memory].
.sanitizer: &sanitizer
extends:
- '.fdo.distribution-image@fedora'
- '.fedora.container.common'
<<: *save_build_logs
stage: manual
when: manual
@@ -395,44 +239,135 @@ flatpak:
except:
variables:
- $CI_PIPELINE_SOURCE == "schedule"
- $CI_COMMIT_TITLE =~ /^Update.*translation$/
# Disabled because we currently need "crun" tagged runners, see above
#asan:
# extends:
# - '.fdo.distribution-image@fedora'
# - '.fedora.container.common'
# <<: *sanitizer
# # ASAN requires debugging capabilities
# tags: [ asan ]
# stage: manual
# when: manual
# variables:
# BUILD_OPTS: "-Db_sanitize=address"
# LSAN_OPTIONS: "suppressions=${CI_PROJECT_DIR}/build-aux/ci/lsan.supp"
asan:
<<: *sanitizer
stage: test
when: on_success
variables:
BUILD_OPTS: "-Db_sanitize=address"
LSAN_OPTIONS: "suppressions=${CI_PROJECT_DIR}/build-aux/ci/lsan.supp"
tsan:
extends:
- '.fdo.distribution-image@fedora'
- '.fedora.container.common'
<<: *sanitizer
variables:
BUILD_OPTS: "-Db_sanitize=thread"
ubsan:
extends:
- '.fdo.distribution-image@fedora'
- '.fedora.container.common'
<<: *sanitizer
variables:
BUILD_OPTS: "-Db_sanitize=undefined"
msan:
extends:
- '.fdo.distribution-image@fedora'
- '.fedora.container.common'
<<: *sanitizer
variables:
BUILD_OPTS: "-Db_sanitize=memory"
CC: "clang"
# Runs multiarch build test.
.qemu: &multiarch
<<: *save_build_logs
image: docker:latest
services:
- docker:dind
script:
# Register QEMU archs
- docker run --rm --privileged multiarch/qemu-user-static:register --reset
# Run the multiarch test job using QEMU
- 'docker run -v $(pwd):/cwd $IMAGE bash -e -c "cd /cwd &&
echo == Building == &&
rm -rf _build/ &&
meson . _build ${BUILD_OPTS} &&
ninja -C _build 2>&1 | tee compilation.log &&
echo == Testing == &&
ninja -C _build test"
'
except:
variables:
- $CI_COMMIT_TITLE =~ /^Update.*translation$/
armv8:
<<: *multiarch
stage: manual
when: manual
variables:
DOCKER_DRIVER: overlay
IMAGE: "claudioandre/settings:fedora.aarch64"
ppc64le:
<<: *multiarch
stage: manual
when: manual
allow_failure: true
variables:
DOCKER_DRIVER: overlay
IMAGE: "claudioandre/settings:fedora.ppc64le"
#############################################
# Create CI Docker Images #
#############################################
.Docker image template: &create_docker_image
image: docker:latest
stage: deploy
services:
- docker:dind
only:
variables:
- $CRON_TASK == "BUILD_CI_IMAGES"
script:
# Skip the build (if requested)
- |
if [[ -z "${CI_COMMIT_MESSAGE##*[skip images]*}" && -z "${CI_COMMIT_MESSAGE##*[$NAME]*}" ]]; then
echo "== Nothing to do =="
exit 0
fi
# Get multiarch stuff
- |
if [[ -n "${TARGET_ARCH}" ]]; then
docker run --rm --privileged multiarch/qemu-user-static:register --reset
wget https://github.com/multiarch/qemu-user-static/releases/download/v2.12.0/x86_64_qemu-${TARGET_ARCH}-static.tar.gz
fi
# Build using the Dockerfile
- docker build -f "$DOCKERFILE" -t "$CI_REGISTRY_IMAGE:$NAME" .
# Prepare to publish
- docker tag "$CI_REGISTRY_IMAGE:$NAME" "$CI_REGISTRY_IMAGE:job-"$CI_JOB_ID"_$NAME"
- docker images
- docker login ${CI_REGISTRY} -u ${CI_REGISTRY_USER} -p ${CI_REGISTRY_PASSWORD}
# Publish (if running on a schedule)
- |
if [[ "${CI_PIPELINE_SOURCE}" == "schedule" ]]; then
docker push "$CI_REGISTRY_IMAGE"
fi
fedora.dev:
<<: *create_docker_image
variables:
DOCKER_DRIVER: overlay
DOCKERFILE: "build-aux/ci/Dockerfile.fedora.rawhide"
NAME: "fedora.dev"
fedora.aarch64:
<<: *create_docker_image
variables:
DOCKER_DRIVER: overlay
DOCKERFILE: "build-aux/ci/Dockerfile.arm64v8.fedora.rawhide"
NAME: "fedora.aarch64"
TARGET_ARCH: "aarch64"
fedora.ppc64le:
<<: *create_docker_image
variables:
DOCKER_DRIVER: overlay
DOCKERFILE: "build-aux/ci/Dockerfile.ppc64le.fedora.rawhide"
NAME: "fedora.ppc64le"
TARGET_ARCH: "ppc64le"

View File

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

View File

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

View File

@@ -1,31 +1,7 @@
<!--
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://wiki.gnome.org/GettingInTouch/Bugzilla/GettingTraces -->
* Screenshots
## Steps to reproduce:
Steps to reproduce:
1. Open GNOME Settings
2. Change X to something else

View File

@@ -1,13 +1,3 @@
<!--
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 feature. Put as much information as you can.
Proposed Mockups:

1185
NEWS

File diff suppressed because it is too large Load Diff

View File

@@ -1,27 +1,53 @@
[![Build Status](https://gitlab.gnome.org/GNOME/gnome-control-center/badges/main/pipeline.svg)](https://gitlab.gnome.org/GNOME/gnome-control-center/pipelines)
[![Coverage report](https://gitlab.gnome.org/GNOME/gnome-control-center/badges/main/coverage.svg)](https://gnome.pages.gitlab.gnome.org/gnome-control-center/)
[![License](https://img.shields.io/badge/License-GPL%20v2-blue.svg)](https://gitlab.gnome.org/GNOME/gnome-control-center/blob/main/COPYING)
[![Build Status](https://gitlab.gnome.org/GNOME/gnome-control-center/badges/master/build.svg)](https://gitlab.gnome.org/GNOME/gnome-control-center/pipelines)
[![Coverage report](https://gitlab.gnome.org/GNOME/gnome-control-center/badges/master/coverage.svg)](https://gnome.pages.gitlab.gnome.org/gnome-control-center/)
[![License](https://img.shields.io/badge/License-GPL%20v2-blue.svg)](https://gitlab.gnome.org/GNOME/gnome-control-center/blob/master/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).
GNOME Settings is GNOME's main interface for configuration of various aspects of
your desktop.
## Contributing
See `docs/CONTRIBUTING.md` for details on the contribution process, and `docs/CODING_STYLE.md`
See `docs/CONTRIBUTING.md` for details on the contribution process, and `docs/HACKING.md`
for the coding style guidelines.
Visit the [Settings development wiki](https://gitlab.gnome.org/GNOME/gnome-control-center/-/wikis/home) for more information.
## Testing Unstable Settings
It is quite easy to test and give feedback about the development version of GNOME
Settings. Just access https://gitlab.gnome.org/GNOME/gnome-control-center/environments,
get the latest version, download it, double-click the file, install and run.
Note that GNOME Settings Flatpak will only work if you are running
the latest GNOME version in your host system.
## Reporting Bugs
Bugs should be reported to the GNOME bug tracking system under the product
gnome-control-center. It is available at [GitLab Issues](https://gitlab.gnome.org/GNOME/gnome-control-center/issues).
In the report please include the following information -
Operating system and version
For Linux, version of the C library
How to reproduce the bug if possible
If the bug was a crash, include the exact text that was printed out
A stacktrace where possible [see below]
### How to get a stack trace
If the crash is reproducible, it is possible to get a stack trace and
attach it to the bug report. The following steps are used to obtain a
stack trace -
Run the program in gdb [the GNU debugger] or any other debugger
ie. gdb gnome-keyboard-properties
Start the program
ie. (gdb) run
Reproduce the crash and the program will exit to the gdb prompt
Get the back trace
ie. (gdb) bt full
Once you have the backtrace, copy and paste this either into the
'Comments' field or attach a file with it included.

View File

@@ -0,0 +1,26 @@
FROM arm64v8/fedora:rawhide
MAINTAINER Claudio André (c) 2018 V1.0
LABEL architecture="aarch64"
LABEL version="1.0"
LABEL description="Multiarch Docker image to run CI for GNOME Settings."
ADD x86_64_qemu-aarch64-static.tar.gz /usr/bin
RUN dnf -y --nogpgcheck upgrade && \
dnf -y install \
@c-development @development-tools clang \
accountsservice-devel cheese-libs-devel chrpath clutter-gtk-devel colord-devel \
colord-gtk-devel cups-devel desktop-file-utils docbook-style-xsl gdk-pixbuf2-devel \
gettext git glib2-devel gnome-bluetooth-libs-devel gnome-desktop3-devel \
gnome-online-accounts-devel gnome-settings-daemon-devel grilo-devel \
gsettings-desktop-schemas-devel gtk3-devel ibus-devel intltool libcanberra-devel \
libgtop2-devel libgudev-devel libnma-devel libpwquality-devel libsmbclient-devel \
libsoup-devel libwacom-devel libX11-devel libXi-devel libxml2-devel libxslt \
libXxf86misc-devel meson ModemManager-glib-devel NetworkManager-libnm-devel \
polkit-devel pulseaudio-libs-devel upower-devel \
python3-dbusmock xorg-x11-server-Xvfb mesa-dri-drivers libsecret-devel && \
dnf -y clean all
CMD ["/bin/bash"]

View File

@@ -0,0 +1,24 @@
FROM fedora:rawhide
MAINTAINER Claudio André (c) 2018 V1.0
LABEL architecture="x86_64"
LABEL version="1.0"
LABEL description="Docker image to run CI for GNOME Settings."
RUN dnf -y --nogpgcheck upgrade && \
dnf -y install \
@c-development @development-tools clang \
accountsservice-devel cheese-libs-devel chrpath clutter-gtk-devel colord-devel \
colord-gtk-devel cups-devel desktop-file-utils docbook-style-xsl gdk-pixbuf2-devel \
gettext git glib2-devel gnome-bluetooth-libs-devel gnome-desktop3-devel \
gnome-online-accounts-devel gnome-settings-daemon-devel grilo-devel \
gsettings-desktop-schemas-devel gtk3-devel ibus-devel intltool libcanberra-devel \
libgtop2-devel libgudev-devel libnma-devel libpwquality-devel libsmbclient-devel \
libsoup-devel libwacom-devel libX11-devel libXi-devel libxml2-devel libxslt \
libXxf86misc-devel meson ModemManager-glib-devel NetworkManager-libnm-devel \
polkit-devel pulseaudio-libs-devel upower-devel \
python3-dbusmock xorg-x11-server-Xvfb mesa-dri-drivers libsecret-devel llvm && \
dnf -y clean all
CMD ["/bin/bash"]

View File

@@ -0,0 +1,26 @@
FROM ppc64le/fedora:rawhide
MAINTAINER Claudio André (c) 2018 V1.0
LABEL architecture="ppc64le"
LABEL version="1.0"
LABEL description="Multiarch Docker image to run CI for GNOME Settings."
ADD x86_64_qemu-ppc64le-static.tar.gz /usr/bin
RUN dnf -y --nogpgcheck upgrade && \
dnf -y install \
@c-development @development-tools clang \
accountsservice-devel cheese-libs-devel chrpath clutter-gtk-devel colord-devel \
colord-gtk-devel cups-devel desktop-file-utils docbook-style-xsl gdk-pixbuf2-devel \
gettext git glib2-devel gnome-bluetooth-libs-devel gnome-desktop3-devel \
gnome-online-accounts-devel gnome-settings-daemon-devel grilo-devel \
gsettings-desktop-schemas-devel gtk3-devel ibus-devel intltool libcanberra-devel \
libgtop2-devel libgudev-devel libnma-devel libpwquality-devel libsmbclient-devel \
libsoup-devel libwacom-devel libX11-devel libXi-devel libxml2-devel libxslt \
libXxf86misc-devel meson ModemManager-glib-devel NetworkManager-libnm-devel \
polkit-devel pulseaudio-libs-devel upower-devel \
python3-dbusmock xorg-x11-server-Xvfb mesa-dri-drivers libsecret-devel && \
dnf -y clean all
CMD ["/bin/bash"]

View File

@@ -3,7 +3,6 @@ leak:libfontconfig.so.1
# Unknown and unreported bugs
leak:__GI___vasprintf_chk
leak:__interceptor_malloc
leak:__alloc_dir
leak:libglib-2.0.so.0

View File

@@ -1,22 +0,0 @@
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

View File

@@ -1,9 +1,11 @@
{
"app-id" : "org.gnome.Settings",
"runtime" : "org.gnome.Sdk",
"runtime" : "org.gnome.Platform",
"runtime-version" : "master",
"sdk" : "org.gnome.Sdk",
"command" : "gnome-control-center",
"rename-desktop-file" : "gnome-control-center.desktop",
"rename-icon" : "gnome-control-center",
"tags" : [
"devel"
],
@@ -12,6 +14,7 @@
"--device=dri",
"--env=DCONF_USER_CONFIG_DIR=.config/dconf",
"--filesystem=host",
"--own-name=org.gnome.ControlCenter",
"--own-name=org.gnome.SessionManager",
"--share=ipc",
"--share=network",
@@ -26,10 +29,7 @@
"cxxflags" : "-O2 -g",
"env" : {
"V" : "1"
},
"build-args": [
"--share=network"
]
}
},
"x-run-args" : [
"--verbose"
@@ -49,7 +49,6 @@
"name" : "pwquality",
"buildsystem" : "autotools",
"config-opts" : [
"--disable-python-bindings"
],
"sources" : [
{
@@ -59,69 +58,67 @@
]
},
{
"name" : "intltool",
"cleanup" : [ "*" ],
"name" : "mozjs52",
"build-options" : {
"arch" : {
"i386" : {
"config-opts" : [
"--host=i586-unknown-linux-gnu"
]
},
"arm" : {
"config-opts" : [
"--host=arm-unknown-linux-gnueabi"
]
}
}
},
"config-opts": [
"--enable-posix-nspr-emulation",
"--with-system-zlib",
"--without-system-icu",
"--with-intl-api",
"--disable-jemalloc",
"AUTOCONF=autoconf"
],
"builddir" : true,
"subdir" : "js/src",
"sources" : [
{
"type" : "archive",
"url" : "https://launchpad.net/intltool/trunk/0.51.0/+download/intltool-0.51.0.tar.gz",
"sha256" : "67c74d94196b153b774ab9f89b2fa6c6ba79352407037c8c14d5aeb334e959cd"
"url" : "https://download.gnome.org/teams/releng/tarballs-needing-help/mozjs/mozjs-52.2.1gnome1.tar.gz",
"sha256" : "31697943b1dbbb51ba9aee35b8269a353c487d7af4d336010b90054dc4f9b0af"
}
],
"cleanup" : [
"libjs_static.ajs"
]
},
{
"name" : "polkit",
"buildsystem" : "autotools",
"config-opts" : [
"--disable-polkitd",
"--disable-man-pages",
"--disable-examples",
"--disable-gtk-doc",
"--disable-libelogind",
"--disable-libsystemd-login",
"--with-systemdsystemunitdir=no",
"--with-authdb=dummy",
"--with-authfw=none"
],
"rm-configure" : true,
"cleanup" : [
"/bin/*",
"/etc/pam.d",
"/etc/dbus-1",
"/share/dbus-1/system-services/*",
"/share/polkit-1",
"/lib/polkit-1"
],
"sources" : [
{
"type" : "archive",
"url" : "https://www.freedesktop.org/software/polkit/releases/polkit-0.116.tar.gz",
"sha256" : "88170c9e711e8db305a12fdb8234fac5706c61969b94e084d0f117d8ec5d34b1"
},
{
"type" : "patch",
"path" : "polkit-build-Add-option-to-build-without-polkitd.patch"
},
{
"type" : "file",
"path" : "polkit-autogen",
"dest-filename" : "autogen.sh"
}
]
},
{
"name" : "accountsservice",
"buildsystem" : "meson",
"config-opts" : [
"-Dsystemdsystemunitdir=no",
"-Dintrospection=false",
"-Dvapi=false"
"--disable-introspection",
"--disable-libelogind"
],
"sources" : [
{
"type" : "git",
"url" : "https://gitlab.freedesktop.org/accountsservice/accountsservice",
"branch" : "main"
"url" : "git://anongit.freedesktop.org/polkit"
}
]
},
{
"name" : "accountservice",
"buildsystem" : "autotools",
"config-opts" : [
"--disable-systemd",
"--disable-elogind"
],
"sources" : [
{
"type" : "git",
"url" : "git://anongit.freedesktop.org/accountsservice"
}
]
},
@@ -134,7 +131,7 @@
"sources" : [
{
"type" : "git",
"url" : "https://github.com/libusb/libusb.git"
"url" : "git://github.com/libusb/libusb.git"
}
]
},
@@ -149,8 +146,7 @@
"sources" : [
{
"type" : "git",
"url" : "https://github.com/hughsie/libgusb.git",
"branch" : "main"
"url" : "git://github.com/hughsie/libgusb.git"
}
]
},
@@ -182,7 +178,20 @@
"sources" : [
{
"type" : "git",
"url" : "https://github.com/gentoo/eudev.git"
"url" : "git://github.com/gentoo/eudev.git"
}
]
},
{
"name" : "gudev",
"buildsystem" : "autotools",
"config-opts" : [
"--disable-umockdev"
],
"sources" : [
{
"type" : "git",
"url" : "https://gitlab.gnome.org/GNOME/libgudev.git"
}
]
},
@@ -194,58 +203,47 @@
"-Dbash_completion=false",
"-Dman=false",
"-Dudev_rules=false",
"-Dsystemd=false",
"-Dvapi=false",
"-Ddocs=false",
"-Dtests=false",
"-Dinstalled_tests=false"
"-Dsystemd=false"
],
"sources" : [
{
"type" : "git",
"branch" : "main",
"url" : "https://github.com/hughsie/colord.git"
"url" : "git://github.com/hughsie/colord.git"
}
]
},
{
"name" : "colord-gtk",
"buildsystem" : "meson",
"buildsystem" : "autotools",
"config-opts" : [
"-Dman=false"
],
"sources" : [
{
"type" : "git",
"branch" : "main",
"url" : "https://github.com/hughsie/colord-gtk.git"
"url" : "git://github.com/hughsie/colord-gtk.git"
}
]
},
{
"name" : "rest",
"buildsystem" : "meson",
"config-opts" : [
"-Dgtk_doc=false"
],
"buildsystem" : "autotools",
"sources" : [
{
"type" : "git",
"branch" : "master",
"branch" : "librest-0-7",
"url" : "https://gitlab.gnome.org/GNOME/librest.git"
}
]
},
{
"name" : "gnome-online-accounts",
"buildsystem" : "meson",
"buildsystem" : "autotools",
"build-options" : {
"cflags" : "-Wno-error"
},
"config-opts" : [
"-Dgtk_doc=false",
"-Dintrospection=false",
"-Dvapi=false"
"--disable-telepathy",
"--disable-documentation"
],
"sources" : [
{
@@ -267,12 +265,6 @@
{
"name" : "geocode-glib",
"buildsystem" : "meson",
"config-opts" : [
"-Denable-installed-tests=false",
"-Denable-introspection=false",
"-Denable-gtk-doc=false",
"-Dsoup2=false"
],
"sources" : [
{
"type" : "git",
@@ -283,46 +275,26 @@
{
"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"
"url" : "https://gitlab.gnome.org/GNOME/libgweather.git"
}
]
},
{
"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"
],
"buildsystem" : "autotools",
"sources" : [
{
"type" : "git",
"url" : "https://gitlab.freedesktop.org/upower/upower.git",
"tag" : "v1.90.2"
"url" : "git://anongit.freedesktop.org/upower"
}
]
},
{
"name" : "libwacom",
"buildsystem" : "meson",
"config-opts" : [
"-Ddocumentation=disabled",
"-Dtests=disabled"
],
"buildsystem" : "autotools",
"sources" : [
{
"type" : "git",
@@ -336,7 +308,7 @@
"sources" : [
{
"type" : "archive",
"url" : "http://libndp.org/files/libndp-1.6.tar.gz",
"url" : " http://libndp.org/files/libndp-1.6.tar.gz",
"sha256" : "0c7dfa84e013bd5e569ef2c6292a6f72cfaf14f4ff77a77425e52edc33ffac0e"
}
]
@@ -351,10 +323,14 @@
"config-opts" : [
"-Dlibaudit=no",
"-Ddbus_conf_dir=/app/etc/dbus-1/system.d",
"-Ddbus_ifaces_dir=/app/share/dbus-1/interfaces",
"-Ddbus_sys_dir=/app/share/dbus-1/system.d",
"-Ddnsmasq=/usr/bin/true",
"-Ddocs=false",
"-Dintrospection=false",
"-Diptables=/usr/bin/true",
"-Djson_validation=false",
"-Dlibnm_glib=false",
"-Dlibpsl=false",
"-Dmodem_manager=false",
"-Dnmtui=false",
@@ -363,8 +339,7 @@
"-Dqt=false",
"-Dselinux=false",
"-Dsession_tracking=no",
"-Dsystemdsystemunitdir=/app/lib/systemd/system",
"-Dudev_dir=/app/lib/udev",
"-Dsystemdsystemunitdir='no'",
"-Dsystemd_journal=false",
"-Dtests=no",
"-Dvapi=false"
@@ -372,124 +347,56 @@
"sources" : [
{
"type" : "git",
"branch": "main",
"tag": "1.14.0",
"commit" : "2979c891c4af7584780924e92b6d448b7d6cd328",
"url" : "https://gitlab.freedesktop.org/NetworkManager/NetworkManager.git"
}
]
},
{
"name" : "mobile-broadband-provider-info",
"buildsystem" : "autotools",
"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",
"-Dgtk_doc=false",
"-Dintrospection=false",
"-Dlibnm_gtk=false",
"-Dselinux=false",
"-Dteam=false"
"-Dteam=false",
"-Dwwan=false",
"-Dmobile_broadband_provider_info=false"
],
"sources" : [
{
"type" : "git",
"url" : "https://gitlab.gnome.org/GNOME/network-manager-applet.git",
"branch" : "main"
"url" : "https://gitlab.gnome.org/GNOME/network-manager-applet.git"
}
]
},
{
"name" : "ModemManager",
"buildsystem" : "meson",
"buildsystem" : "autotools",
"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"
"--disable-introspection",
"--disable-vala",
"--with-udev-base-dir=/app/lib",
"--without-mbim",
"--without-qmi"
],
"sources" : [
{
"type" : "git",
"url" : "https://gitlab.freedesktop.org/mobile-broadband/ModemManager.git",
"branch" : "main"
"url" : "git://anongit.freedesktop.org/ModemManager/ModemManager"
}
]
},
{
"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"
}
]
},
{
@@ -505,6 +412,23 @@
}
]
},
{
"name" : "grilo",
"buildsystem" : "meson",
"config-opts" : [
"-Denable-grl-pls=false",
"-Denable-gtk-doc=false",
"-Denable-introspection=false",
"-Denable-test-ui=false",
"-Denable-vala=false"
],
"sources" : [
{
"type" : "git",
"url" : "https://gitlab.gnome.org/GNOME/grilo.git"
}
]
},
{
"name" : "openldap",
"buildsystem" : "autotools",
@@ -513,9 +437,9 @@
],
"sources" : [
{
"type": "archive",
"url": "https://www.openldap.org/software/download/OpenLDAP/openldap-release/openldap-2.6.1.tgz",
"sha256": "9d576ea6962d7db8a2e2808574e8c257c15aef55f403a1fb5a0faf35de70e6f3"
"type" : "archive",
"url" : "https://www.openldap.org/software/download/OpenLDAP/openldap-release/openldap-2.4.46.tgz",
"sha256" : "9a90dcb86b99ae790ccab93b7585a31fbcbeec8c94bf0f7ab0ca0a87ea0c4b2d"
}
]
},
@@ -525,8 +449,8 @@
"sources" : [
{
"type" : "archive",
"url" : "http://downloads.sourceforge.net/sourceforge/libtirpc/libtirpc-1.2.6.tar.bz2",
"sha256" : "4278e9a5181d5af9cd7885322fdecebc444f9a3da87c526e7d47f7a12a37d1cc"
"url" : "http://downloads.sourceforge.net/sourceforge/libtirpc/libtirpc-1.0.3.tar.bz2",
"sha256" : "86c3a78fc1bddefa96111dd233124c703b22a78884203c55c3e06b3be6a0fd5e"
}
]
},
@@ -541,61 +465,14 @@
}
]
},
{
"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.14.5.tar.gz",
"sha256" : "bb6ef5d2f16b85288d823578abc453d9a80514c42e5a2ea2c4e3c60dc42335c3"
"url" : "https://download.samba.org/pub/samba/stable/samba-4.8.1.tar.gz",
"sha256" : "8ef7367507f16b7a5e2f6aed5bcdbd1143feca79aa2a07c9b21292b17d7f789d"
}
]
},
@@ -613,216 +490,15 @@
]
},
{
"name" : "udisks",
"name" : "cheese",
"buildsystem" : "autotools",
"config-opts" : [
"--disable-introspection",
"--disable-lvm2",
"--enable-daemon=no",
"--with-systemdsystemunitdir=/app/lib/systemd/system",
"--with-tmpfilesdir=/app/lib/tmpfiles.d"
"--disable-introspection"
],
"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" : "mutter",
"buildsystem" : "meson",
"config-opts" : [
"-Dgles2=false",
"-Dglx=false",
"-Dxwayland=false",
"-Dwayland=false",
"-Dsystemd=false",
"-Dnative_backend=false",
"-Dremote_desktop=false",
"-Degl_device=false",
"-Dudev=false",
"-Dstartup_notification=false",
"-Dsm=false",
"-Dintrospection=true",
"-Ddocs=false",
"-Dtests=false",
"-Dnative_tests=false",
"-Dprofiler=false"
],
"sources" : [
{
"type" : "git",
"branch" : "main",
"url" : "https://gitlab.gnome.org/gnome/mutter.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",
"-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"
"url" : "https://gitlab.gnome.org/GNOME/cheese.git"
}
]
},
@@ -831,14 +507,12 @@
"buildsystem" : "meson",
"sources" : [
{
"type" : "dir",
"path" : "../../"
"type" : "git",
"url" : "https://gitlab.gnome.org/GNOME/gnome-control-center.git"
}
],
"config-opts" : [
"-Dsnap=false",
"-Dtests=false",
"-Dprofile=development"
"-Dtracing=true"
]
}
]

View File

@@ -1,4 +0,0 @@
#!/bin/sh
gtkdocize --flavour no-tmpl
autoreconf -if

View File

@@ -1,132 +0,0 @@
From 1073a44277316348d40d86ecec908f1d4812f360 Mon Sep 17 00:00:00 2001
From: Christian Hergert <chergert@redhat.com>
Date: Mon, 27 May 2019 11:49:09 -0700
Subject: [PATCH] flatpak: make polkit suitable for use within flatpak
This is based on patches from Patrick Griffis with additional fixes
to allow us to disable use of PAM within Flaptak.
---
configure.ac | 20 ++++++++++++++++----
src/Makefile.am | 6 +++++-
src/polkitagent/Makefile.am | 5 +++++
test/Makefile.am | 6 +++++-
4 files changed, 31 insertions(+), 6 deletions(-)
diff --git a/configure.ac b/configure.ac
index 5cedb4e..729d78d 100644
--- a/configure.ac
+++ b/configure.ac
@@ -79,11 +79,13 @@ PKG_CHECK_MODULES(GLIB, [gmodule-2.0 gio-unix-2.0 >= 2.30.0])
AC_SUBST(GLIB_CFLAGS)
AC_SUBST(GLIB_LIBS)
-PKG_CHECK_MODULES(LIBJS, [mozjs-60])
+AS_IF([test x${enable_polkitd} = yes], [
+ PKG_CHECK_MODULES(LIBJS, [mozjs-60])
-AC_SUBST(LIBJS_CFLAGS)
-AC_SUBST(LIBJS_CXXFLAGS)
-AC_SUBST(LIBJS_LIBS)
+ AC_SUBST(LIBJS_CFLAGS)
+ AC_SUBST(LIBJS_CXXFLAGS)
+ AC_SUBST(LIBJS_LIBS)
+])
EXPAT_LIB=""
AC_ARG_WITH(expat, [ --with-expat=<dir> Use expat from here],
@@ -236,6 +238,15 @@ if test "x$with_systemdsystemunitdir" != "xno"; then
fi
AM_CONDITIONAL(HAVE_SYSTEMD, [test -n "$systemdsystemunitdir"])
+dnl ---------------------------------------------------------------------------
+dnl - Disable polkitd when using library alone
+dnl ---------------------------------------------------------------------------
+
+AC_ARG_ENABLE([polkitd],
+ [AS_HELP_STRING([--disable-polkitd], [Do not build polkitd])],
+ [enable_polkitd=$enableval], [enable_polkitd=yes])
+AM_CONDITIONAL(BUILD_POLKITD, [test x${enable_polkitd} = yes])
+
dnl ---------------------------------------------------------------------------
dnl - User for running polkitd
dnl ---------------------------------------------------------------------------
@@ -579,6 +590,7 @@ echo "
Session tracking: ${SESSION_TRACKING}
PAM support: ${have_pam}
systemdsystemunitdir: ${systemdsystemunitdir}
+ polkitd: ${enable_polkitd}
polkitd user: ${POLKITD_USER}"
if test "$have_pam" = yes ; then
diff --git a/src/Makefile.am b/src/Makefile.am
index 09fc7b3..c6fe91b 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1,5 +1,9 @@
-SUBDIRS = polkit polkitbackend polkitagent programs
+SUBDIRS = polkit polkitagent programs
+
+if BUILD_POLKITD
+SUBDIRS += polkitbackend
+endif
if BUILD_EXAMPLES
SUBDIRS += examples
diff --git a/src/polkitagent/Makefile.am b/src/polkitagent/Makefile.am
index 49720db..633f9d4 100644
--- a/src/polkitagent/Makefile.am
+++ b/src/polkitagent/Makefile.am
@@ -79,6 +79,7 @@ libpolkit_agent_1_la_LIBADD = \
libpolkit_agent_1_la_LDFLAGS = -export-symbols-regex '(^polkit_.*)'
+if !POLKIT_AUTHFW_NONE
libprivdir = $(prefix)/lib/polkit-1
libpriv_PROGRAMS = polkit-agent-helper-1
@@ -113,6 +114,8 @@ polkit_agent_helper_1_LDFLAGS = \
$(AM_LDFLAGS) \
$(NULL)
+endif # !POLKIT_AUTHFW_NONE
+
if HAVE_INTROSPECTION
girdir = $(INTROSPECTION_GIRDIR)
@@ -142,6 +145,7 @@ include $(INTROSPECTION_MAKEFILE)
endif # HAVE_INTROSPECTION
+if !POLKIT_AUTHFW_NONE
# polkit-agent-helper-1 need to be setuid root because it's used to
# authenticate not only the invoking user, but possibly also root
# and/or other users.
@@ -149,6 +153,7 @@ endif # HAVE_INTROSPECTION
install-data-hook:
-chown root $(DESTDIR)$(libprivdir)/polkit-agent-helper-1
-chmod 4755 $(DESTDIR)$(libprivdir)/polkit-agent-helper-1
+endif # !POLKIT_AUTHFW_NONE
EXTRA_DIST = polkitagentmarshal.list polkitagentenumtypes.h.template polkitagentenumtypes.c.template
CLEANFILES = $(gir_DATA) $(typelibs_DATA)
diff --git a/test/Makefile.am b/test/Makefile.am
index 59d0680..d43b0fe 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -1,7 +1,11 @@
-SUBDIRS = mocklibc . polkit polkitbackend
+SUBDIRS = mocklibc . polkit
AM_CFLAGS = $(GLIB_CFLAGS)
+if BUILD_POLKITD
+SUBDIRS += polkitbackend
+endif
+
noinst_LTLIBRARIES = libpolkit-test-helper.la
libpolkit_test_helper_la_SOURCES = polkittesthelper.c polkittesthelper.h
libpolkit_test_helper_la_LIBADD = $(GLIB_LIBS)
--
2.21.0

5
build-aux/meson.build Normal file
View File

@@ -0,0 +1,5 @@
update_from_gsd = find_program('meson/update-from-gsd.sh')
update_from_gsd_in = files('meson/update-from-gsd.in')
update_from_nma_in = files('meson/update-from-nma.in')
meson.add_install_script('meson/meson_post_install.py', control_center_datadir)

View File

@@ -1,38 +0,0 @@
#!/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)

View File

@@ -0,0 +1,15 @@
#!/usr/bin/env python3
import os
import subprocess
import sys
gsettingsschemadir = os.path.join(sys.argv[1], 'glib-2.0', 'schemas')
icondir = os.path.join(sys.argv[1], 'icons', 'hicolor')
if not os.environ.get('DESTDIR'):
print('Compiling gsettings schemas...')
subprocess.call(['glib-compile-schemas', gsettingsschemadir])
print('Update icon cache...')
subprocess.call(['gtk-update-icon-cache', '-f', '-t', icondir])

View File

@@ -0,0 +1,10 @@
#!/bin/sh
cd @working_dir@
export FILES="@source_files@"
export DIR="@input_dir@"
@program@ &&
git add @source_files@ &&
git commit -m "@source_message@"

View File

@@ -0,0 +1,26 @@
#!/bin/bash
function die() {
echo $*
exit 1
}
if test -z "$DIR"; then
echo "Must set DIR"
exit 1
fi
if test -z "$FILES"; then
echo "Must set FILES"
exit 1
fi
for FILE in $FILES; do
if cmp -s $DIR/$FILE $FILE; then
echo "File $FILE is unchanged"
else
cp $DIR/$FILE $FILE || die "Could not move $DIR/$FILE to $FILE"
echo "Updated $FILE"
git add $FILE
fi
done

View File

@@ -0,0 +1,19 @@
#!/bin/sh
cd @working_dir@
export FILES="@source_files@"
export DIR="@input_dir@"
@program@ &&
patch -p4 < @source_patch@ &&
git add @source_files@ &&
git commit -m "@source_message@"
export FILES="@resource_data@"
export DIR="@input_dir@"
@program@ &&
patch -p4 < @resource_patch@ &&
git add @resource_data@ &&
git commit -m "@resource_message@"

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 533 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 819 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 109 KiB

View File

@@ -0,0 +1,32 @@
<?xml version='1.0' encoding='UTF-8'?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg xmlns:cc='http://creativecommons.org/ns#' xmlns:inkscape='http://www.inkscape.org/namespaces/inkscape' xmlns:svg='http://www.w3.org/2000/svg' id='svg7384' xmlns:sodipodi='http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd' sodipodi:docname='preferences-system-symbolic.svg' version='1.1' inkscape:version='0.48.1 r9760' height='16.000008' xmlns:dc='http://purl.org/dc/elements/1.1/' xmlns:rdf='http://www.w3.org/1999/02/22-rdf-syntax-ns#' xmlns='http://www.w3.org/2000/svg' width='16'>
<metadata id='metadata90'>
<rdf:RDF>
<cc:Work rdf:about=''>
<dc:format>image/svg+xml</dc:format>
<dc:type rdf:resource='http://purl.org/dc/dcmitype/StillImage'/>
<dc:title>Gnome Symbolic Icon Theme</dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<sodipodi:namedview inkscape:cy='7.8662795' pagecolor='#555753' borderopacity='1' showborder='false' inkscape:bbox-paths='false' guidetolerance='10' inkscape:object-paths='true' inkscape:window-width='1600' showguides='true' inkscape:object-nodes='true' inkscape:snap-bbox='true' inkscape:pageshadow='2' inkscape:guide-bbox='true' inkscape:snap-nodes='true' bordercolor='#666666' objecttolerance='10' id='namedview88' showgrid='false' inkscape:window-maximized='1' inkscape:window-x='0' inkscape:snap-global='true' inkscape:window-y='0' gridtolerance='10' inkscape:window-height='1168' inkscape:snap-others='false' inkscape:snap-to-guides='true' inkscape:current-layer='g4953' inkscape:snap-bbox-midpoints='false' inkscape:zoom='1' inkscape:cx='13.631831' inkscape:snap-grids='true' inkscape:pageopacity='1'>
<inkscape:grid spacingx='1px' spacingy='1px' id='grid4866' empspacing='2' enabled='true' type='xygrid' snapvisiblegridlinesonly='true' visible='true'/>
</sodipodi:namedview>
<title id='title9167'>Gnome Symbolic Icon Theme</title>
<defs id='defs7386'/>
<g inkscape:label='status' transform='translate(-442.0002,-462)' inkscape:groupmode='layer' id='layer9' style='display:inline'/>
<g inkscape:label='devices' transform='translate(-442.0002,-462)' inkscape:groupmode='layer' id='layer10'/>
<g inkscape:label='apps' transform='translate(-442.0002,-462)' inkscape:groupmode='layer' id='layer11'/>
<g inkscape:label='places' transform='translate(-442.0002,-462)' inkscape:groupmode='layer' id='layer13'/>
<g inkscape:label='mimetypes' transform='translate(-442.0002,-462)' inkscape:groupmode='layer' id='layer14'/>
<g inkscape:label='emblems' transform='translate(-442.0002,-462)' inkscape:groupmode='layer' id='layer15' style='display:inline'/>
<g inkscape:label='emotes' transform='translate(-442.0002,-462)' inkscape:groupmode='layer' id='g71291' style='display:inline'/>
<g inkscape:label='categories' transform='translate(-442.0002,-462)' inkscape:groupmode='layer' id='g4953' style='display:inline'>
<path inkscape:connector-curvature='0' d='m 445.54914,462.09056 c -0.39933,0 -0.78638,0.0916 -1.14329,0.21572 l 1.88488,1.87971 c 0.38735,0.38627 0.38735,1.00037 0,1.38667 l -0.71069,0.70874 c -0.38735,0.38628 -1.00314,0.38628 -1.39049,0 l -1.88488,-1.87971 c -0.12444,0.35591 -0.2163,0.74191 -0.2163,1.14015 0,1.90608 1.54944,3.45126 3.46077,3.45126 0.39933,0 0.78638,-0.0916 1.14329,-0.2157 l 1.17419,1.17097 a 2.4722239,2.4654407 0 0 1 0.0618,0 l 2.07028,-2.0646 -1.20509,-1.20178 c 0.12444,-0.35592 0.2163,-0.74191 0.2163,-1.14015 0,-1.90609 -1.54944,-3.45128 -3.46077,-3.45128 z m 6.55074,7.88863 -2.07029,2.06459 a 2.4722239,2.4654407 0 0 1 0.0309,0.0924 l 1.14329,1.14015 c -0.12444,0.35596 -0.2163,0.74196 -0.2163,1.14019 0,1.90609 1.54944,3.45129 3.46077,3.45129 0.43346,0 0.8536,-0.10141 1.23599,-0.24653 l -2.00848,-2.00297 c -0.38735,-0.38629 -0.38735,-1.03119 0,-1.41749 l 0.67979,-0.67792 c 0.19367,-0.19315 0.45794,-0.30816 0.71069,-0.30816 0.25276,0 0.51702,0.11501 0.7107,0.30816 l 1.94668,1.94133 c 0.10485,-0.32958 0.1854,-0.68351 0.1854,-1.04771 0,-1.90608 -1.54944,-3.45126 -3.46077,-3.45126 -0.39933,0 -0.78639,0.0916 -1.14329,0.2157 l -1.20509,-1.20179 z' id='path3908' style='font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:start;color:#000000;fill:#bebebe;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:3;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;font-family:Sans;-inkscape-font-specification:Sans'/>
<path inkscape:connector-curvature='0' d='m 455.85825,462 -1.54246,1.43753 c -0.45151,0.42079 -0.5292,1.14883 -0.2663,1.70647 l -5.88822,5.99575 a 1.4916729,1.4875773 0 0 0 -0.0311,2.5e-4 1.4916729,1.4875773 0 0 0 -0.84016,-0.1484 1.4916729,1.4875773 0 0 0 -0.86663,0.44059 l -3.9462,3.99734 a 1.4941171,1.4900149 0 1 0 2.12943,2.09068 l 3.9462,-3.99734 a 1.4916729,1.4875773 0 0 0 0.29713,-1.73771 l 5.88846,-5.96477 c 0.55782,0.24837 1.27325,0.14697 1.70681,-0.2922 L 457.86242,463.9677 455.85824,462 z' id='path3910' style='font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:start;color:#000000;fill:#bebebe;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:3;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;font-family:Sans;-inkscape-font-specification:Sans'/>
</g>
<g inkscape:label='actions' transform='translate(-442.0002,-462)' inkscape:groupmode='layer' id='layer12' style='display:inline'/>
</svg>

After

Width:  |  Height:  |  Size: 5.7 KiB

View File

@@ -1,109 +0,0 @@
<?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>

Before

Width:  |  Height:  |  Size: 15 KiB

View File

@@ -1,45 +0,0 @@
<?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>

Before

Width:  |  Height:  |  Size: 7.3 KiB

View File

@@ -1,5 +0,0 @@
<?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>

Before

Width:  |  Height:  |  Size: 3.5 KiB

View File

@@ -2,12 +2,3 @@ install_subdir(
'hicolor',
install_dir : control_center_icondir
)
if get_option('profile') == 'development'
icondir = join_paths('hicolor', 'scalable', 'apps')
install_data(
join_paths(icondir, 'org.gnome.Settings.Devel.svg'),
install_dir: join_paths(control_center_icondir, icondir),
rename: 'org.gnome.Settings.svg'
)
endif

View File

@@ -1,49 +0,0 @@
# 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
## 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

View File

@@ -1,184 +0,0 @@
# 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

View File

@@ -1,97 +1,75 @@
# Contributing
Thank you for considering contributing to Settings!
All code contributions are made using merge requests.
When contributing to the development of GNOME Settings, please first discuss the change you wish to
make via issue, email, or any other method with the maintainers before making a change.
Please note we have a Code of Conduct, please follow it in all your interactions with the project.
## Creating Merge Requests
## Pull Request Process
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.
1. Create a fork in GitLab and push your work to there
2. Open a Merge Request
1. Always allow maintainer edits
2. Mark the Merge Request as WIP if your work is not ready to be reviewed
3. Assign the correct maintainer to the Merge Request (see [`MAINTAINERS.md`][maintainers] to select
the correct maintainer)
4. Format commit messages as follows:
```
component: <summary>
A paragraph explaining the problem and its context.
Another one explaining how you solved that.
<link to the issue>
```
4. You may merge the pull request in once you have the sign-off of the maintainers, or if you
do not have permission to do that, you may request the second reviewer to merge it for you.
The following guidelines will help your change be successfully merged:
## Code of Conduct
* 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.
GNOME Settings is a project developed based on GNOME Code of Conduct. You can read it below:
Please format commit messages as follows:
### Summary
```
component: <summary>
GNOME creates software for a better world. We achieve this by behaving well towards
each other.
A paragraph explaining the problem and its context.
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.
Another one explaining how you solved that.
### Advice
<link to issue(s) this change fixes>
```
* **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.
## Bug Fixes
* **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".
Changes that fix bugs include:
* **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.
* Correcting code that crashes.
* Spelling mistakes in labels.
* Small layout issues (e.g. spacing).
* Use of deprecated APIs.
* Restructuring of code for improved safety.
* **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.
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.
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.
## User Experience Changes
### Attribution
Changes that impact the user experience of Settings require approval from the
[Design Team][design-team]. This includes:
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
available at [http://contributor-covenant.org/version/1/4][version]
* 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.
[homepage]: http://contributor-covenant.org
[version]: http://contributor-covenant.org/version/1/4/
[maintainers]: https://gitlab.gnome.org/GNOME/gnome-control-center/blob/master/docs/MAINTAINERS.md

View File

@@ -50,7 +50,7 @@ by being explicit. Suggested acceptance phrase:
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)
* On stable branches (or master right after a stable release)
* Symptoms:
* Always OR often reproducible; AND
* Crash; OR
@@ -59,4 +59,4 @@ criteria:
* 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
[doap]: https://gitlab.gnome.org/GNOME/gnome-control-center/blob/master/gnome-control-center.doap

View File

@@ -7,26 +7,26 @@
<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" />
<mailing-list rdf:resource="http://mail.gnome.org/mailman/listinfo/gnomecc-list" />
<download-page rdf:resource="http://download.gnome.org/sources/gnome-control-center/" />
<bug-database rdf:resource="http://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:name>Georges Basile Stavracas Neto</foaf:name>
<foaf:mbox rdf:resource="mailto:gbsneto@gnome.org" />
<gnome:userid>gbsneto</gnome:userid>
</foaf:Person>
</maintainer>
<!-- General -->
<!-- General, Region & Language -->
<maintainer>
<foaf:Person>
<foaf:name>Robert Ancell</foaf:name>
<foaf:mbox rdf:resource="mailto:robert.ancell@canonical.com" />
<foaf:mbox rdf:resource="mailto:rancell@gnome.org" />
<gnome:userid>rancell</gnome:userid>
</foaf:Person>
</maintainer>
@@ -40,11 +40,47 @@
</foaf:Person>
</maintainer>
<!-- Mouse & Touchpad, Printers -->
<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>
<!-- Online Accounts -->
<maintainer>
<foaf:Person>
<foaf:name>Debarshi Ray</foaf:name>
<foaf:mbox rdf:resource="mailto:debarshir@gnome.org" />
<gnome:userid>debarshir</gnome:userid>
</foaf:Person>
</maintainer>
<!-- Printers -->
<maintainer>
<foaf:Person>
<foaf:name>Marek Kašík</foaf:name>
<foaf:mbox rdf:resource="mailto:mkasik@redhat.com" />
<foaf:mbox rdf:resource="mailto:mkasik@gnome.org" />
</foaf:Person>
</maintainer>
<!-- Thunderbolt -->
<maintainer>
<foaf:Person>
<foaf:name>Christian Kellner</foaf:name>
<foaf:mbox rdf:resource="mailto:gicmo@gnome.org" />
<gnome:userid>gicmo</gnome:userid>
</foaf:Person>
</maintainer>
<!-- User Accounts -->
<maintainer>
<foaf:Person>
<foaf:name>Ondrej Holy</foaf:name>
<foaf:mbox rdf:resource="mailto:oholy@gnome.org" />
<gnome:userid>oholy</gnome:userid>
</foaf:Person>
</maintainer>

View File

@@ -115,9 +115,9 @@
</varlistentry>
<varlistentry>
<term><option>info-overview</option></term>
<term><option>info</option></term>
<listitem><para>The info-overview panel shows a general
<listitem><para>The info 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

View File

@@ -1,8 +1,8 @@
project(
'gnome-control-center', 'c',
version : '46.alpha',
version : '3.30.1',
license : 'GPL2+',
meson_version : '>= 0.58.0'
meson_version : '>= 0.43.0'
)
control_center_prefix = get_option('prefix')
@@ -25,19 +25,15 @@ host_is_linux_not_s390 = host_is_linux and not host_machine.cpu().contains('s390
cc = meson.get_compiler('c')
# Tracing
enable_tracing = get_option('tracing')
config_h = configuration_data()
py = import('python')
python = py.find_installation('python3')
py3 = import('python3')
python = py3.find_python()
config_h.set_quoted('TEST_NM_PYTHON', python.full_path())
if get_option('profile') == 'development'
profile = 'Devel'
else
profile = ''
endif
application_id = 'org.gnome.Settings@0@'.format(profile)
config_h.set_quoted('TEST_NM_PYTHON', python.path())
# defines
set_defines = [
@@ -45,7 +41,6 @@ set_defines = [
['PACKAGE', meson.project_name()],
['PACKAGE_VERSION', meson.project_version()],
['VERSION', meson.project_version()],
['PROFILE', get_option('profile')],
# i18n
['GETTEXT_PACKAGE', control_center_gettext]
]
@@ -54,17 +49,6 @@ 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',
@@ -73,15 +57,6 @@ config_h.set('USER_DIR_MODE', '0700',
# 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
@@ -117,8 +92,6 @@ libgvc = subproject(
default_options: [
'static=true',
'alsa=false',
'package_name=' + control_center_gettext,
'package_version=' + meson.project_version(),
]
)
libgvc_dep = libgvc.get_variable('libgvc_dep')
@@ -126,73 +99,23 @@ libgvc_dep = libgvc.get_variable('libgvc_dep')
goa_req_version = '>= 3.25.3'
pulse_req_version = '>= 2.0'
gtk_dep = dependency(
'gtk4',
version: '>= 4.11.2',
fallback: ['gtk', 'gtk_dep'],
default_options: [
'introspection=disabled',
'demos=false',
'build-testsuite=false',
'build-tests=false',
'build-examples=false',
]
)
libadwaita_dep = dependency(
'libadwaita-1',
version: '>= 1.4.alpha',
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 = subproject(
'libadwaita',
default_options: [
'examples=false',
'introspection=disabled',
'tests=false',
'vapi=false',
],
)
libadwaita_dep = libadwaita.get_variable('libadwaita_dep')
endif
tecla_dep = dependency(
'tecla',
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
accounts_dep = dependency('accountsservice', version: '>= 0.6.39')
clutter_gtk_dep = dependency('clutter-gtk-1.0', required: false)
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: '>= 41.0')
glib_dep = dependency('glib-2.0', version: '>= 2.53.0')
gnome_desktop_dep = dependency('gnome-desktop-3.0', version: '>= 3.27.90')
gnome_settings_dep = dependency('gnome-settings-daemon', version: '>= 3.25.90')
goa_dep = dependency('goa-1.0', version: goa_req_version)
gsettings_desktop_dep = dependency('gsettings-desktop-schemas', version: '>= 42.alpha')
gsettings_desktop_dep = dependency('gsettings-desktop-schemas', version: '>= 3.27.2')
libxml_dep = dependency('libxml-2.0')
polkit_gobject_dep = dependency('polkit-gobject-1', version: '>= 0.103')
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: '>= 0.99.8')
gudev_dep = dependency('gudev-1.0', version: '>= 232')
x11_dep = dependency('x11', version: '>= 1.8')
upower_glib_dep = dependency('upower-glib', version: '>= 0.99.6')
x11_dep = dependency('x11')
xi_dep = dependency('xi', version: '>= 1.2')
epoxy_dep = dependency('epoxy')
gcr_dep = dependency('gcr-base-3')
pwquality_dep = dependency('pwquality', version: '>= 1.2.2')
m_dep = cc.find_library('m')
@@ -200,21 +123,11 @@ common_deps = [
gio_dep,
glib_dep,
gsettings_desktop_dep,
libadwaita_dep,
dependency('gio-unix-2.0'),
dependency('gthread-2.0'),
gtk_dep,
dependency('gtk+-3.0', version: '>= 3.22.20')
]
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
# 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')
@@ -222,7 +135,7 @@ 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='
cups_cflags += '-D_PPD_DEPRECATED=""'
endif
# cups headers
@@ -235,9 +148,19 @@ 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')
# Optional dependency for the user accounts panel
enable_cheese = get_option('cheese')
if enable_cheese
assert(clutter_gtk_dep.found(), 'cheese support requested, but clutter-gtk library is not available. Use -Dcheese=false to build without it.')
cheese_deps = [
clutter_gtk_dep,
dependency('cheese', version: '>= 3.28.0'),
dependency('cheese-gtk', version: '>= 3.5.91')
]
endif
config_h.set('HAVE_CHEESE', enable_cheese,
description: 'Define to 1 to enable cheese webcam support')
# IBus support
enable_ibus = get_option('ibus')
@@ -247,57 +170,43 @@ 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
json_glib_dep = dependency('json-glib-1.0')
libsoup_dep = dependency('libsoup-3.0')
# wayland
enable_wayland = get_option('wayland')
if enable_wayland
wayland_deps = [
dependency('gdk-wayland-3.0'),
dependency('gudev-1.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')
config_h.set('HAVE_WAYLAND', enable_wayland,
description: 'Define to 1 if Wayland is enabled')
if host_is_linux
# ModemManager
mm_dep = dependency('mm-glib', version: '>= 0.7')
# NetworkManager
# network manager
network_manager_deps = [
dependency('libnm', version: '>= 1.24.0'),
dependency('libnma-gtk4', version: '>= 1.10.2'),
mm_dep,
dependency('libnm', version: '>= 1.10.0'),
dependency('libnma', version: '>= 1.8.0'),
dependency('mm-glib', version: '>= 0.7')
]
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')
gnome_bluetooth_dep = dependency('gnome-bluetooth-1.0', version: '>= 3.18.2')
# Wacom
assert(clutter_gtk_dep.found(), 'clutter-gtk library is required for wacom support, but is not available.')
libwacom_dep = dependency('libwacom', version: '>= 0.7')
wacom_deps = [
clutter_gtk_dep,
libwacom_dep,
dependency('clutter-1.0', version: '>= 1.11.3'),
]
config_h.set('HAVE_WACOM_3D_STYLUS', libwacom_dep.version().version_compare('>= 0.27'),
description: 'Define to 1 if libwacom provides definition for 3D styli')
@@ -316,12 +225,21 @@ config_h.set('HAVE_WACOM', host_is_linux_not_s390,
config_h.set('BUILD_THUNDERBOLT', host_is_linux_not_s390,
description: 'Define to 1 to build the Thunderbolt panel')
# Check for info panel
gnome_session_libexecdir = get_option('gnome_session_libexecdir')
if gnome_session_libexecdir == ''
gnome_session_libexecdir = control_center_libexecdir
endif
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')
desktop_conf = configuration_data()
desktop_conf.set('VERSION', meson.project_version())
po_dir = join_paths(meson.source_root(), 'po')
its_dir = join_paths(meson.source_root(), 'gettext')
install_subdir(
'gettext',
@@ -331,44 +249,37 @@ install_subdir(
top_inc = include_directories('.')
shell_inc = include_directories('shell')
subdir('build-aux')
subdir('data/icons')
subdir('po')
subdir('panels')
subdir('shell')
subdir('search-provider')
if get_option('tests')
subdir('tests')
endif
subdir('tests')
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,
})
output = ''
output += '\n ' + meson.project_name() + ' - ' + meson.project_version() + '\n'
output += ' ===================================\n'
output += ' Options \n'
output += ' Documentation .............................. ' + get_option('documentation').to_string() + '\n'
output += ' Tracing .................................... ' + enable_tracing.to_string() + '\n'
output += ' gnome-session libexecdir ................... ' + gnome_session_libexecdir + '\n'
output += ' Optimized .................................. ' + control_center_optimized.to_string() + '\n'
output += ' Panels \n'
output += ' GNOME Bluetooth (Bluetooth panel) .......... ' + host_is_linux_not_s390.to_string() + '\n'
output += ' Cheese (Users panel webcam support) ........ ' + enable_cheese.to_string() + '\n'
output += ' IBus (Region panel IBus support) ........... ' + enable_ibus.to_string() + '\n'
output += ' NetworkManager (Network panel) ............. ' + host_is_linux.to_string() + '\n'
output += ' Wacom (Wacom tablet panel) ................. ' + host_is_linux_not_s390.to_string() + '\n'
output += ' Wayland .................................... ' + enable_wayland.to_string() + '\n'
summary({
'GNOME Bluetooth': host_is_linux_not_s390,
'NetworkManager': host_is_linux,
'Wacom': host_is_linux_not_s390,
}, section: 'Dependencies')
summary({
'IBus': enable_ibus,
'Snap': enable_snap,
'Malcontent': enable_malcontent,
}, section: 'Optional Dependencies')
message(output)

View File

@@ -1,11 +1,6 @@
option('deprecated-declarations', type: 'feature', value: 'disabled', description: 'build with deprecated declaration warnings')
option('cheese', type: 'boolean', value: true, description: 'build with cheese webcam support')
option('documentation', type: 'boolean', value: false, description: 'build documentation')
option('gnome_session_libexecdir', type: 'string', value: '', description: 'Directory for gnome-session\'s libexecdir')
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')
option('tracing', type: 'boolean', value: false, description: 'add extra debugging information')
option('wayland', type: 'boolean', value: true, description: 'build with Wayland support')

View File

@@ -1,11 +0,0 @@
<?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-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-info-row.ui</file>
<file preprocess="xml-stripblanks">cc-snap-row.ui</file>
</gresource>
</gresources>

File diff suppressed because it is too large Load Diff

View File

@@ -1,30 +0,0 @@
/* 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

View File

@@ -1,599 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<template class="CcApplicationsPanel" parent="CcPanel">
<property name="child">
<object class="AdwNavigationView" id="navigation_view">
<!-- App Search Page (Main Ladning Page) -->
<child>
<object class="AdwNavigationPage">
<property name="title" translatable="yes">Apps</property>
<property name="child">
<object class="AdwToolbarView">
<child type="top">
<object class="AdwHeaderBar"/>
</child>
<property name="content">
<object class="AdwPreferencesPage" id="app_search_stack_page">
<!-- Searchbar -->
<child>
<object class="AdwPreferencesGroup">
<child>
<object class="AdwClamp">
<property name="maximum-size">280</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>
</child>
</object>
</child>
<!-- Default Apps Row -->
<child>
<object class="AdwPreferencesGroup">
<child>
<object class="CcListRow">
<property name="activatable">True</property>
<property name="title" translatable="yes">_Default Apps</property>
<property name="use-underline">True</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="GtkStack" id="app_listbox_stack">
<property name="vhomogeneous">False</property>
<child>
<!-- Empty search results placeholder -->
<object class="GtkBox" id="empty_search_placeholder">
<!--AdwStatusPage can't be used here, see: https://gitlab.gnome.org/GNOME/libadwaita/-/issues/697-->
<property name="orientation">vertical</property>
<property name="valign">center</property>
<!--Use AdwClamp like AdwStatusPage-->
<child>
<object class="AdwClamp">
<style>
<class name="status-page"/>
</style>
<property name="child">
<object class="GtkBox">
<property name="orientation">vertical</property>
<property name="valign">center</property>
<child>
<object class="GtkImage">
<property name="pixel_size">128</property>
<property name="icon_name">computer-fail-symbolic</property>
<style>
<class name="dim-label"/>
<class name="icon"/>
</style>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="label" translatable="yes">No Apps Found</property>
<property name="wrap">True</property>
<property name="wrap-mode">word-char</property>
<property name="justify">center</property>
<style>
<class name="title"/>
<class name="title-1"/>
</style>
</object>
</child>
<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>
</object>
</child>
<child>
<object class="GtkListBox" id="app_listbox">
<property name="selection-mode">none</property>
<style>
<class name="boxed-list" />
</style>
</object>
</child>
</object>
</child>
</object>
</child>
</object>
</property>
</object>
</property>
</object>
</child>
<!-- Default Apps Page -->
<child>
<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>
<!-- Removable Media Settings -->
<child>
<object class="CcRemovableMediaSettings" id="removable_media_settings" />
</child>
</object>
</property>
</object>
</property>
</object>
</child>
<!-- App Settings Page -->
<child>
<object class="AdwNavigationPage" id="app_settings_page">
<property name="title" translatable="yes">App Settings</property>
<property name="tag">settings-box</property>
<property name="child">
<object class="AdwToolbarView">
<child type="top">
<object class="AdwHeaderBar"/>
</child>
<property name="content">
<object class="AdwPreferencesPage" id="settings_box">
<!-- App icon & buttons -->
<child>
<object class="AdwPreferencesGroup">
<child>
<object class="GtkBox">
<property name="orientation">vertical</property>
<property name="spacing">18</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="wrap">True</property>
<style>
<class name="title" />
<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="integration_section">
<child>
<object class="AdwSwitchRow" id="search">
<property name="title" translatable="yes">_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="CcInfoRow" id="no_search">
<property name="title" translatable="yes">_Search</property>
<property name="subtitle" translatable="yes">Receive system searches and send results</property>
<property name="info" translatable="yes">Disabled</property>
</object>
</child>
<child>
<object class="AdwSwitchRow" id="notification">
<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">
<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="screenshot">
<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">
<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="sound">
<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="CcInfoRow" id="no_sound">
<property name="title" translatable="yes">So_unds</property>
<property name="subtitle" translatable="yes">Reproduce sounds</property>
<property name="info" translatable="yes">Disabled</property>
</object>
</child>
<child>
<object class="AdwSwitchRow" id="shortcuts">
<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">
<property name="title" translatable="yes">Camera</property>
<property name="subtitle" translatable="yes">Take pictures with the camera</property>
<signal name="notify::active" handler="camera_cb" object="CcApplicationsPanel" swapped="yes"/>
</object>
</child>
<child>
<object class="CcInfoRow" id="no_camera">
<property name="title" translatable="yes">C_amera</property>
<property name="subtitle" translatable="yes">Take pictures with the camera</property>
<property name="info" translatable="yes">Disabled</property>
</object>
</child>
<child>
<object class="AdwSwitchRow" id="microphone">
<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="CcInfoRow" id="no_microphone">
<property name="title" translatable="yes">_Microphone</property>
<property name="subtitle" translatable="yes">Record audio with the microphone</property>
<property name="info" translatable="yes">Disabled</property>
</object>
</child>
<child>
<object class="AdwSwitchRow" id="location">
<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="CcInfoRow" id="no_location">
<property name="title" translatable="yes">_Location Services</property>
<property name="subtitle" translatable="yes">Access device location data</property>
<property name="info" translatable="yes">Disabled</property>
</object>
</child>
</object>
</child>
<child>
<object class="AdwPreferencesGroup" id="usage_section">
<child>
<object class="CcInfoRow" id="builtin">
<property name="title" translatable="yes">Re_quired Access</property>
<property name="subtitle" translatable="yes">System access that is required by the app</property>
<property name="has-expander">True</property>
<property name="is-link">True</property>
<signal name="activated" handler="on_builtin_row_activated_cb" object="CcApplicationsPanel" swapped="yes" />
</object>
</child>
<child>
<object class="CcInfoRow" id="handler_row">
<property name="title" translatable="yes">_File &amp;amp; Link Associations</property>
<property name="has-expander">True</property>
<property name="is-link">True</property>
<signal name="activated" handler="on_handler_row_activated_cb" object="CcApplicationsPanel" swapped="yes" />
</object>
</child>
<child>
<object class="CcInfoRow" id="storage">
<property name="title" translatable="yes">S_torage</property>
<property name="has-expander">1</property>
<property name="is-link">1</property>
<signal name="activated" handler="on_storage_row_activated_cb" object="CcApplicationsPanel" swapped="yes" />
</object>
</child>
</object>
</child>
</object>
</property>
</object>
</property>
</object>
</child>
</object>
</property>
</template>
<!-- Built-in Permissions dialog -->
<object class="AdwWindow" id="builtin_dialog">
<property name="title" translatable="yes">Required Access</property>
<property name="modal">1</property>
<property name="resizable">True</property>
<property name="hide-on-close">True</property>
<property name="default-width">500</property>
<property name="default-height">400</property>
<property name="width-request">360</property>
<property name="height-request">294</property>
<child>
<object class="GtkShortcutController">
<property name="scope">managed</property>
<child>
<object class="GtkShortcut">
<property name="trigger">Escape</property>
<property name="action">action(window.close)</property>
</object>
</child>
</object>
</child>
<property name="content">
<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>
<!-- File & Link handlers dialog -->
<object class="AdwWindow" id="handler_dialog">
<property name="title" translatable="yes">File &amp; Link Associations</property>
<property name="modal">1</property>
<property name="resizable">True</property>
<property name="hide-on-close">True</property>
<property name="default-width">500</property>
<property name="default-height">400</property>
<property name="width-request">360</property>
<property name="height-request">294</property>
<child>
<object class="GtkShortcutController">
<property name="scope">managed</property>
<child>
<object class="GtkShortcut">
<property name="trigger">Escape</property>
<property name="action">action(window.close)</property>
</object>
</child>
</object>
</child>
<property name="content">
<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="GtkButton" id="handler_reset">
<property name="valign">center</property>
<property name="margin-top">12</property>
<property name="label" translatable="yes">_Reset</property>
<property name="use-underline">True</property>
<property name="halign">center</property>
<signal name="clicked" handler="handler_reset_cb" object="CcApplicationsPanel" swapped="yes"/>
<style>
<class name="destructive-action" />
<class name="pill" />
</style>
</object>
</child>
</object>
</child>
</object>
</property>
</object>
</property>
</object>
<!-- Storage dialog -->
<object class="AdwWindow" id="storage_dialog">
<property name="title" translatable="yes">Storage</property>
<property name="modal">1</property>
<property name="resizable">True</property>
<property name="hide-on-close">True</property>
<property name="default-width">420</property>
<property name="width-request">360</property>
<property name="height-request">294</property>
<child>
<object class="GtkShortcutController">
<property name="scope">managed</property>
<child>
<object class="GtkShortcut">
<property name="trigger">Escape</property>
<property name="action">action(window.close)</property>
</object>
</child>
</object>
</child>
<property name="content">
<object class="AdwToolbarView">
<child type="top">
<object class="AdwHeaderBar"/>
</child>
<property name="content">
<object class="AdwPreferencesPage">
<property name="description" translatable="yes">How much disk space this app is occupying with app data and caches.</property>
<child>
<object class="AdwPreferencesGroup">
<child>
<object class="CcInfoRow" id="app">
<property name="title" translatable="yes">App</property>
<property name="info">Unknown</property>
</object>
</child>
<child>
<object class="CcInfoRow" id="data">
<property name="title" translatable="yes">Data</property>
<property name="info">Unknown</property>
</object>
</child>
<child>
<object class="CcInfoRow" id="cache">
<property name="title" translatable="yes">Cache</property>
<property name="info">Unknown</property>
</object>
</child>
<child>
<object class="CcInfoRow" id="total">
<property name="title" translatable="yes">&lt;b&gt;Total&lt;/b&gt;</property>
<property name="info">Unknown</property>
</object>
</child>
</object>
</child>
<child>
<object class="AdwPreferencesGroup">
<child>
<object class="GtkButton" id="clear_cache_button">
<property name="label" translatable="yes">_Clear Cache</property>
<property name="use-underline">True</property>
<property name="halign">center</property>
<signal name="clicked" handler="clear_cache_cb" object="CcApplicationsPanel" swapped="yes"/>
<style>
<class name="pill" />
</style>
</object>
</child>
</object>
</child>
</object>
</property>
</object>
</property>
</object>
<object class="GtkSizeGroup">
<property name="mode">horizontal</property>
<widgets>
<widget name="launch_button" />
<widget name="view_details_button" />
</widgets>
</object>
</interface>

View File

@@ -1,95 +0,0 @@
/* 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_markup_escape_text (g_app_info_get_display_name (info), -1));
icon = g_app_info_get_icon (info);
if (icon != NULL)
g_object_ref (icon);
else
icon = g_themed_icon_new ("application-x-executable");
w = gtk_image_new_from_gicon (icon);
gtk_style_context_add_class (gtk_widget_get_style_context (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;
}

View File

@@ -1,35 +0,0 @@
/* 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

View File

@@ -1,12 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<template class="CcApplicationsRow" parent="AdwActionRow">
<child type="suffix">
<object class="GtkImage">
<property name="icon-name">go-next-symbolic</property>
</object>
</child>
</template>
</interface>

View File

@@ -1,130 +0,0 @@
/* -*- 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_class_init (CcDefaultAppsPageClass *klass)
{
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
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 ("CcObjectStorage::mm-manager"))
{
self->mm_manager = cc_object_storage_get_object ("CcObjectStorage::mm-manager");
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);
}

View File

@@ -1,77 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<template class="CcDefaultAppsPage" parent="AdwPreferencesGroup">
<property name="title" translatable="yes">Links &amp;amp; Files</property>
<property name="description" translatable="yes">Apps which are used to open common links and files</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>

View File

@@ -1,222 +0,0 @@
/* -*- 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 "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_strdup (g_value_get_string (value));
break;
case PROP_FILTERS:
self->filters = g_strdup (g_value_get_string (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void
cc_default_apps_row_constructed (GObject *object)
{
CcDefaultAppsRow *self;
g_autoptr (GAppInfo) default_app, app = NULL;
g_autoptr (GList) recommended_apps, l = NULL;
GtkExpression *name_expr;
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) {
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);
}
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;
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)
{
g_autoptr(GAppInfo) info = NULL;
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]);
}
}
}
}

View File

@@ -1,32 +0,0 @@
/* -*- 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

View File

@@ -1,187 +0,0 @@
/* cc-info-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-info-row.h"
#include "cc-applications-resources.h"
struct _CcInfoRow
{
AdwActionRow parent;
GtkWidget *info;
GtkWidget *expander;
gboolean expanded;
gboolean link;
};
G_DEFINE_TYPE (CcInfoRow, cc_info_row, ADW_TYPE_ACTION_ROW)
enum
{
PROP_0,
PROP_INFO,
PROP_HAS_EXPANDER,
PROP_IS_LINK,
PROP_EXPANDED
};
static void
cc_info_row_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
CcInfoRow *row = CC_INFO_ROW (object);
switch (prop_id)
{
case PROP_INFO:
g_value_set_string (value, gtk_label_get_label (GTK_LABEL (row->info)));
break;
case PROP_HAS_EXPANDER:
g_value_set_boolean (value, gtk_widget_get_visible (row->expander));
break;
case PROP_IS_LINK:
g_value_set_boolean (value, row->link);
break;
case PROP_EXPANDED:
g_value_set_boolean (value, cc_info_row_get_expanded (row));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
update_expander (CcInfoRow *row)
{
if (row->link)
gtk_image_set_from_icon_name (GTK_IMAGE (row->expander), "go-next-symbolic");
else if (row->expanded)
gtk_image_set_from_icon_name (GTK_IMAGE (row->expander), "pan-down-symbolic");
else
gtk_image_set_from_icon_name (GTK_IMAGE (row->expander), "pan-end-symbolic");
}
static void
cc_info_row_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
CcInfoRow *row = CC_INFO_ROW (object);
switch (prop_id)
{
case PROP_INFO:
gtk_label_set_label (GTK_LABEL (row->info), g_value_get_string (value));
break;
case PROP_HAS_EXPANDER:
gtk_widget_set_visible (row->expander, g_value_get_boolean (value));
gtk_list_box_row_set_activatable (GTK_LIST_BOX_ROW (row), g_value_get_boolean (value));
break;
case PROP_IS_LINK:
row->link = g_value_get_boolean (value);
update_expander (row);
break;
case PROP_EXPANDED:
cc_info_row_set_expanded (row, g_value_get_boolean (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
cc_info_row_class_init (CcInfoRowClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
object_class->get_property = cc_info_row_get_property;
object_class->set_property = cc_info_row_set_property;
gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/control-center/applications/cc-info-row.ui");
g_object_class_install_property (object_class,
PROP_INFO,
g_param_spec_string ("info", "info", "info",
NULL, G_PARAM_READWRITE));
g_object_class_install_property (object_class,
PROP_HAS_EXPANDER,
g_param_spec_boolean ("has-expander", "has-expander", "has-expander",
FALSE, G_PARAM_READWRITE));
g_object_class_install_property (object_class,
PROP_EXPANDED,
g_param_spec_boolean ("expanded", "expanded", "expanded",
FALSE, G_PARAM_READWRITE));
g_object_class_install_property (object_class,
PROP_IS_LINK,
g_param_spec_boolean ("is-link", "is-link", "is-link",
FALSE, G_PARAM_READWRITE));
gtk_widget_class_bind_template_child (widget_class, CcInfoRow, info);
gtk_widget_class_bind_template_child (widget_class, CcInfoRow, expander);
}
static void
cc_info_row_init (CcInfoRow *self)
{
gtk_widget_init_template (GTK_WIDGET (self));
}
CcInfoRow *
cc_info_row_new (void)
{
return CC_INFO_ROW (g_object_new (CC_TYPE_INFO_ROW, NULL));
}
gboolean
cc_info_row_get_expanded (CcInfoRow *row)
{
return row->expanded;
}
void
cc_info_row_set_expanded (CcInfoRow *row,
gboolean expanded)
{
if (row->expanded == expanded)
return;
row->expanded = expanded;
update_expander (row);
g_object_notify (G_OBJECT (row), "expanded");
}

View File

@@ -1,37 +0,0 @@
/* cc-info-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 <adwaita.h>
G_BEGIN_DECLS
#define CC_TYPE_INFO_ROW (cc_info_row_get_type())
G_DECLARE_FINAL_TYPE (CcInfoRow, cc_info_row, CC, INFO_ROW, AdwActionRow)
CcInfoRow* cc_info_row_new (void);
void cc_info_row_set_expanded (CcInfoRow *row,
gboolean expanded);
gboolean cc_info_row_get_expanded (CcInfoRow *row);
G_END_DECLS

View File

@@ -1,21 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<template class="CcInfoRow" parent="AdwActionRow">
<property name="use-underline">True</property>
<child>
<object class="GtkLabel" id="info">
<property name="valign">center</property>
<style>
<class name="dim-label"/>
</style>
</object>
</child>
<child>
<object class="GtkImage" id="expander">
<property name="visible">False</property>
<property name="valign">center</property>
<property name="icon-name">pan-end-symbolic</property>
</object>
</child>
</template>
</interface>

View File

@@ -1,588 +0,0 @@
/* -*- 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;
GtkWidget *cd_audio_row;
GtkWidget *dvd_video_row;
GtkWidget *music_player_row;
GtkWidget *photos_row;
GtkWidget *software_row;
GtkWidget *other_media_row;
GtkSwitch *autorun_never_switch;
GtkAppChooserButton *audio_cdda_chooser;
GtkAppChooserButton *dcf_chooser;
GtkAppChooserButton *music_player_chooser;
GtkDialog *other_type_dialog;
GtkLabel *other_action_label;
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);
gtk_label_set_mnemonic_widget (self->other_action_label, GTK_WIDGET (self->other_application_chooser));
}
static gboolean
on_extra_options_dialog_close_request (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)
{
GtkWidget *app_panel = gtk_widget_get_ancestor(GTK_WIDGET (self), CC_TYPE_APPLICATIONS_PANEL);
CcShell *shell = cc_panel_get_shell (CC_PANEL (app_panel));
GtkWidget *toplevel = cc_shell_get_toplevel (shell);
gtk_window_set_transient_for (GTK_WINDOW (self->other_type_dialog), GTK_WINDOW (toplevel));
gtk_window_set_modal (GTK_WINDOW (self->other_type_dialog), TRUE);
gtk_window_set_title (GTK_WINDOW (self->other_type_dialog), _("Other Media"));
/* update other_application_chooser */
on_other_type_combo_box_changed (self);
gtk_window_present (GTK_WINDOW (self->other_type_dialog));
}
#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->autorun_never_switch,
"active",
G_SETTINGS_BIND_DEFAULT);
g_settings_bind (self->settings,
PREF_MEDIA_AUTORUN_NEVER,
self->cd_audio_row,
"sensitive",
G_SETTINGS_BIND_INVERT_BOOLEAN);
g_settings_bind (self->settings,
PREF_MEDIA_AUTORUN_NEVER,
self->dvd_video_row,
"sensitive",
G_SETTINGS_BIND_INVERT_BOOLEAN);
g_settings_bind (self->settings,
PREF_MEDIA_AUTORUN_NEVER,
self->music_player_row,
"sensitive",
G_SETTINGS_BIND_INVERT_BOOLEAN);
g_settings_bind (self->settings,
PREF_MEDIA_AUTORUN_NEVER,
self->photos_row,
"sensitive",
G_SETTINGS_BIND_INVERT_BOOLEAN);
g_settings_bind (self->settings,
PREF_MEDIA_AUTORUN_NEVER,
self->software_row,
"sensitive",
G_SETTINGS_BIND_INVERT_BOOLEAN);
g_settings_bind (self->settings,
PREF_MEDIA_AUTORUN_NEVER,
self->other_media_row,
"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 ((GtkWindow **) &self->other_type_dialog, gtk_window_destroy);
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, autorun_never_switch);
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_box);
gtk_widget_class_bind_template_child (widget_class, CcRemovableMediaSettings, other_action_label);
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_child (widget_class, CcRemovableMediaSettings, cd_audio_row);
gtk_widget_class_bind_template_child (widget_class, CcRemovableMediaSettings, dvd_video_row);
gtk_widget_class_bind_template_child (widget_class, CcRemovableMediaSettings, music_player_row);
gtk_widget_class_bind_template_child (widget_class, CcRemovableMediaSettings, photos_row);
gtk_widget_class_bind_template_child (widget_class, CcRemovableMediaSettings, software_row);
gtk_widget_class_bind_template_child (widget_class, CcRemovableMediaSettings, other_media_row);
gtk_widget_class_bind_template_callback (widget_class, on_extra_options_dialog_close_request);
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);
}

View File

@@ -1,210 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<!-- interface-requires gtk+ 3.0 -->
<template class="CcRemovableMediaSettings" parent="AdwPreferencesGroup">
<property name="title" translatable="yes">Removable Media</property>
<property name="description" translatable="yes">Apps which are launched when media or drives are connected</property>
<child>
<object class="AdwActionRow" id="disable_autostart_row">
<property name="title" translatable="yes">D_isable Autostart</property>
<property name="subtitle" translatable="yes">Never prompt or start apps on media insertion</property>
<property name="use_underline">True</property>
<property name="activatable_widget">autorun_never_switch</property>
<child>
<object class="GtkSwitch" id="autorun_never_switch">
<property name="receives_default">False</property>
<property name="valign">center</property>
</object>
</child>
</object>
</child>
<child>
<object class="AdwActionRow" id="cd_audio_row">
<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" id="dvd_video_row">
<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" id="music_player_row">
<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" id="photos_row">
<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" id="software_row">
<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" id="other_media_row">
<property name="title" translatable="yes">_Other Media</property>
<property name="use_underline">True</property>
<property name="show-arrow">True</property>
<property name="subtitle" translatable="yes">Select how other media should be handled</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="AdwWindow" id="other_type_dialog">
<property name="resizable">False</property>
<property name="modal">True</property>
<property name="destroy_with_parent">True</property>
<property name="hide-on-close">True</property>
<signal name="close-request" handler="on_extra_options_dialog_close_request" object="CcRemovableMediaSettings" swapped="yes"/>
<child>
<object class="GtkShortcutController">
<property name="scope">managed</property>
<child>
<object class="GtkShortcut">
<property name="trigger">Escape</property>
<property name="action">action(window.close)</property>
</object>
</child>
</object>
</child>
<property name="content">
<object class="AdwToolbarView">
<child type="top">
<object class="AdwHeaderBar"/>
</child>
<property name="content">
<object class="GtkBox">
<property name="margin-top">18</property>
<property name="margin-bottom">18</property>
<property name="margin-start">18</property>
<property name="margin-end">18</property>
<property name="spacing">10</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkBox">
<property name="spacing">6</property>
<property name="margin-start">12</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkGrid">
<property name="column_spacing">6</property>
<property name="row_spacing">10</property>
<child>
<object class="GtkComboBox" id="other_type_combo_box">
<property name="model">other_type_list_store</property>
<signal name="changed" handler="on_other_type_combo_box_changed" object="CcRemovableMediaSettings" swapped="yes"/>
<layout>
<property name="column">1</property>
<property name="row">0</property>
</layout>
<child>
<object class="GtkCellRendererText"/>
<attributes>
<attribute name="text">0</attribute>
</attributes>
</child>
</object>
</child>
<child>
<object class="GtkLabel" id="other_action_label">
<property name="xalign">0</property>
<property name="label" translatable="yes">_Action:</property>
<property name="use_underline">True</property>
<layout>
<property name="column">0</property>
<property name="row">1</property>
</layout>
</object>
</child>
<child>
<object class="GtkBox" id="other_action_box">
<layout>
<property name="column">1</property>
<property name="row">1</property>
</layout>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="xalign">0</property>
<property name="label" translatable="yes">_Type:</property>
<property name="use_underline">True</property>
<property name="mnemonic_widget">other_type_combo_box</property>
<layout>
<property name="column">0</property>
<property name="row">0</property>
</layout>
</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>

View File

@@ -1,455 +0,0 @@
/* 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 = CC_SNAP_ROW (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;
}

View File

@@ -1,35 +0,0 @@
/* 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

View File

@@ -1,37 +0,0 @@
<?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>

View File

@@ -1,290 +0,0 @@
/* 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://locahost%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 CC_SNAPD_CLIENT (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);
}

View File

@@ -1,70 +0,0 @@
/* 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

View File

@@ -1,62 +0,0 @@
/* 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;
}

View File

@@ -1,29 +0,0 @@
/* 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

View File

@@ -1,15 +0,0 @@
[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;

View File

@@ -1,14 +0,0 @@
install_data(
'scalable/org.gnome.Settings-applications-symbolic.svg',
install_dir: join_paths(control_center_icondir, 'hicolor', 'scalable', 'apps')
)
install_data(
'scalable/org.gnome.Settings-default-apps-symbolic.svg',
install_dir: join_paths(control_center_icondir, 'hicolor', 'scalable', 'apps')
)
install_data(
'scalable/org.gnome.Settings-removable-media-symbolic.svg',
install_dir: join_paths(control_center_icondir, 'hicolor', 'scalable', 'apps')
)

View File

@@ -1,4 +0,0 @@
<?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>

Before

Width:  |  Height:  |  Size: 830 B

View File

@@ -1,4 +0,0 @@
<?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 7.988281 0.0078125 c -0.429687 0 -0.8125 0.2734375 -0.949219 0.6835935 l -1.449218 4.339844 l -4.589844 -0.015625 c -0.9804688 -0.003906 -1.382812 1.257813 -0.582031 1.820313 l 3.625 2.554687 l -1.5 4.285156 c -0.316407 0.902344 0.6875 1.691407 1.492187 1.171875 l 4.003906 -2.59375 l 3.894532 2.585938 c 0.800781 0.53125 1.816406 -0.257813 1.5 -1.160156 l -1.503906 -4.289063 l 3.644531 -2.578125 c 0.789062 -0.5625 0.394531 -1.808594 -0.574219 -1.8125 l -4.660156 -0.015625 l -1.402344 -4.285156 c -0.132812 -0.410157 -0.515625 -0.6875002 -0.949219 -0.6914065 z m 0 0" fill="#2e3436"/>
</svg>

Before

Width:  |  Height:  |  Size: 737 B

View File

@@ -1,4 +0,0 @@
<?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 12 6 v 5 c 0 2.210938 -1.789062 4 -4 4 s -4 -1.789062 -4 -4 v -5 c 0 -0.550781 0.449219 -1 1 -1 h 6 c 0.550781 0 1 0.449219 1 1 z m -7 -5.5 v 3.5 h 6 v -3.5 c 0 -0.277344 -0.222656 -0.5 -0.5 -0.5 h -5 c -0.277344 0 -0.5 0.222656 -0.5 0.5 z m 1 0.5 h 1 v 1 h -1 z m 3 0 h 1 v 1 h -1 z m 0 0" fill="#474747"/>
</svg>

Before

Width:  |  Height:  |  Size: 457 B

View File

@@ -1,62 +0,0 @@
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-info-row.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
)
deps = common_deps
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')

View File

@@ -1,133 +0,0 @@
/* 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;
}

View File

@@ -1,29 +0,0 @@
/* 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

View File

@@ -1,257 +0,0 @@
/* 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_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;
}

View File

@@ -1,55 +0,0 @@
/* 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

View File

@@ -1 +0,0 @@
<svg width="16" height="16" viewBox="0 0 4.233 4.233" xmlns="http://www.w3.org/2000/svg"><path d="M3.843.627a.397.397 0 0 0-.56.034L1.45 2.73l-.775-.763a.397.397 0 0 0-.56.004.397.397 0 0 0 .003.562L1.191 3.59a.397.397 0 0 0 .576-.02l2.11-2.382a.397.397 0 0 0-.034-.56Z" style="fill:#3d3846"/></svg>

Before

Width:  |  Height:  |  Size: 299 B

View File

@@ -1,14 +1,6 @@
<?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/icons/scalable/actions">
<file preprocess="xml-stripblanks">background-selected-symbolic.svg</file>
<file preprocess="xml-stripblanks">slideshow-symbolic.svg</file>
<file preprocess="xml-stripblanks">background.ui</file>
</gresource>
</gresources>

View File

@@ -0,0 +1,300 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<!-- interface-requires gtk+ 3.0 -->
<object class="GtkBox" id="background-panel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin">32</property>
<property name="spacing">12</property>
<property name="valign">center</property>
<child>
<object class="GtkBox" id="box1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="spacing">24</property>
<child>
<object class="GtkBox" id="vbox3">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">end</property>
<property name="valign">center</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkButton" id="background-set-button">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<child>
<object class="GtkBox" id="box2">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin">6</property>
<property name="spacing">6</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkDrawingArea" id="background-desktop-drawingarea">
<property name="width_request">310</property>
<property name="height_request">170</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="valign">center</property>
<property name="hexpand">True</property>
<property name="vexpand">True</property>
</object>
</child>
<child>
<object class="GtkLabel" id="label1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">_Background</property>
<property name="use_underline">True</property>
<property name="mnemonic_widget">background-set-button</property>
</object>
</child>
</object>
</child>
</object>
</child>
<child>
<object class="GtkBox" id="bottom-hbox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="spacing">12</property>
<child>
<object class="GtkBox" id="hbox2">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">center</property>
<property name="margin_top">12</property>
<property name="spacing">2</property>
<child>
<object class="GtkImage" id="slide_image">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="icon_name">slideshow-symbolic</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="strut">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label"> </property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="slide-label">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="xalign">0</property>
<property name="label" translatable="yes" comments="This refers to a slideshow background">Changes throughout the day</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkBox" id="vbox1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<property name="halign">start</property>
<property name="valign">center</property>
<child>
<object class="GtkButton" id="background-lock-set-button">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<child>
<object class="GtkBox" id="box3">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin">6</property>
<property name="spacing">6</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkDrawingArea" id="background-lock-drawingarea">
<property name="width_request">310</property>
<property name="height_request">170</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="valign">center</property>
<property name="hexpand">True</property>
<property name="vexpand">True</property>
</object>
</child>
<child>
<object class="GtkLabel" id="label2">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes" comments="To translators: This is a noun, not a verb">_Lock Screen</property>
<property name="use_underline">True</property>
<property name="mnemonic_widget">background-lock-set-button</property>
</object>
</child>
</object>
</child>
</object>
</child>
<child>
<object class="GtkBox" id="bottom-hbox1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="spacing">12</property>
<child>
<object class="GtkBox" id="hbox1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">center</property>
<property name="margin_top">12</property>
<property name="spacing">2</property>
<child>
<object class="GtkImage" id="slide_image1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="icon_name">slideshow-symbolic</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="strut1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label"> </property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="slide-label1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="xalign">0</property>
<property name="label" translatable="yes" comments="This refers to a slideshow background">Changes throughout the day</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
</object>
<object class="GtkListStore" id="sources-liststore">
<columns>
<!-- column-name source-name -->
<column type="gchararray"/>
<!-- column-name source-id -->
<column type="guint"/>
<!-- column-name source-pointer -->
<column type="gpointer"/>
</columns>
</object>
<object class="GtkListStore" id="style-liststore">
<columns>
<!-- column-name name -->
<column type="gchararray"/>
<!-- column-name value -->
<column type="gint"/>
</columns>
<data>
<row>
<col id="0" translatable="yes" context="background, style">Tile</col>
<col id="1">1</col>
</row>
<row>
<col id="0" translatable="yes" context="background, style">Zoom</col>
<col id="1">5</col>
</row>
<row>
<col id="0" translatable="yes" context="background, style">Center</col>
<col id="1">2</col>
</row>
<row>
<col id="0" translatable="yes" context="background, style">Scale</col>
<col id="1">3</col>
</row>
<row>
<col id="0" translatable="yes" context="background, style">Fill</col>
<col id="1">4</col>
</row>
<row>
<col id="0" translatable="yes" context="background, style">Span</col>
<col id="1">6</col>
</row>
</data>
</object>
<object class="GtkSizeGroup" id="sizegroup">
<property name="mode">vertical</property>
<widgets>
<widget name="slide-label"/>
<widget name="strut"/>
</widgets>
</object>
</interface>

View File

@@ -71,11 +71,21 @@ get_colors_dir (void)
static void
bg_colors_source_add_color (BgColorsSource *self,
GListStore *store,
const char *color)
GnomeDesktopThumbnailFactory *thumb_factory,
GtkListStore *store,
const char *color,
GtkTreeRowReference **ret_row_ref)
{
CcBackgroundItemFlags flags;
g_autoptr(CcBackgroundItem) item = NULL;
g_autoptr(GdkPixbuf) pixbuf = NULL;
cairo_surface_t *surface;
int scale_factor;
int thumbnail_height, thumbnail_width;
GtkTreeIter iter;
thumbnail_height = bg_source_get_thumbnail_height (BG_SOURCE (self));
thumbnail_width = bg_source_get_thumbnail_width (BG_SOURCE (self));
item = cc_background_item_new (NULL);
flags = CC_BACKGROUND_ITEM_HAS_PCOLOR |
@@ -96,24 +106,47 @@ bg_colors_source_add_color (BgColorsSource *self,
cc_background_item_load (item, NULL);
/* insert the item into the liststore */
g_list_store_append (store, item);
scale_factor = bg_source_get_scale_factor (BG_SOURCE (self));
pixbuf = cc_background_item_get_thumbnail (item,
thumb_factory,
thumbnail_width, thumbnail_height,
scale_factor);
surface = gdk_cairo_surface_create_from_pixbuf (pixbuf, scale_factor, NULL);
gtk_list_store_insert_with_values (store, &iter, 0,
0, surface,
1, item,
-1);
cairo_surface_destroy (surface);
if (ret_row_ref)
{
GtkTreePath *path;
path = gtk_tree_model_get_path (GTK_TREE_MODEL (store), &iter);
*ret_row_ref = gtk_tree_row_reference_new (GTK_TREE_MODEL (store), path);
gtk_tree_path_free (path);
}
}
static void
bg_colors_source_constructed (GObject *object)
{
BgColorsSource *self = BG_COLORS_SOURCE (object);
g_autoptr(GnomeDesktopThumbnailFactory) thumb_factory = NULL;
guint i;
GListStore *store;
GtkListStore *store;
g_autoptr(GKeyFile) keyfile = NULL;
g_autofree gchar *path = NULL;
G_OBJECT_CLASS (bg_colors_source_parent_class)->constructed (object);
store = bg_source_get_liststore (BG_SOURCE (self));
thumb_factory = gnome_desktop_thumbnail_factory_new (GNOME_DESKTOP_THUMBNAIL_SIZE_LARGE);
for (i = 0; i < G_N_ELEMENTS (items); i++)
bg_colors_source_add_color (self, store, items[i].pcolor);
{
bg_colors_source_add_color (self, thumb_factory, store, items[i].pcolor, NULL);
}
keyfile = g_key_file_new ();
path = get_colors_path ();
@@ -123,7 +156,9 @@ bg_colors_source_constructed (GObject *object)
colors = g_key_file_get_string_list (keyfile, "Colors", "custom-colors", NULL, NULL);
for (i = 0; colors != NULL && colors[i] != NULL; i++)
bg_colors_source_add_color (self, store, colors[i]);
{
bg_colors_source_add_color (self, thumb_factory, store, colors[i], NULL);
}
}
}
@@ -132,7 +167,8 @@ bg_colors_source_add (BgColorsSource *self,
GdkRGBA *rgba,
GtkTreeRowReference **ret_row_ref)
{
GListStore *store;
g_autoptr(GnomeDesktopThumbnailFactory) thumb_factory = NULL;
GtkListStore *store;
g_autofree gchar *c = NULL;
g_auto(GStrv) colors = NULL;
gsize len;
@@ -146,9 +182,10 @@ bg_colors_source_add (BgColorsSource *self,
(int)(255*rgba->green),
(int)(255*rgba->blue));
thumb_factory = gnome_desktop_thumbnail_factory_new (GNOME_DESKTOP_THUMBNAIL_SIZE_LARGE);
store = bg_source_get_liststore (BG_SOURCE (self));
bg_colors_source_add_color (self, store, c);
bg_colors_source_add_color (self, thumb_factory, store, c, ret_row_ref);
/* Save to the keyfile */
dir = get_colors_dir ();
@@ -212,8 +249,8 @@ bg_colors_source_class_init (BgColorsSourceClass *klass)
}
BgColorsSource *
bg_colors_source_new (GtkWidget *widget)
bg_colors_source_new (GtkWindow *window)
{
return g_object_new (BG_TYPE_COLORS_SOURCE, "widget", widget, NULL);
return g_object_new (BG_TYPE_COLORS_SOURCE, "window", window, NULL);
}

View File

@@ -19,7 +19,8 @@
*
*/
#pragma once
#ifndef _BG_COLORS_SOURCE_H
#define _BG_COLORS_SOURCE_H
#include <gtk/gtk.h>
#include "bg-source.h"
@@ -29,10 +30,12 @@ G_BEGIN_DECLS
#define BG_TYPE_COLORS_SOURCE (bg_colors_source_get_type ())
G_DECLARE_FINAL_TYPE (BgColorsSource, bg_colors_source, BG, COLORS_SOURCE, BgSource)
BgColorsSource *bg_colors_source_new (GtkWidget *widget);
BgColorsSource *bg_colors_source_new (GtkWindow *window);
gboolean bg_colors_source_add (BgColorsSource *self,
GdkRGBA *rgba,
GtkTreeRowReference **ret_row_ref);
G_END_DECLS
#endif /* _BG_COLORS_SOURCE_H */

View File

@@ -0,0 +1,997 @@
/* bg-pictures-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 <config.h>
#include "bg-pictures-source.h"
#include "cc-background-grilo-miner.h"
#include "cc-background-item.h"
#include <string.h>
#include <cairo-gobject.h>
#include <gio/gio.h>
#include <grilo.h>
#include <libgnome-desktop/gnome-desktop-thumbnail.h>
#include <gdesktop-enums.h>
#define ATTRIBUTES G_FILE_ATTRIBUTE_STANDARD_NAME "," \
G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE "," \
G_FILE_ATTRIBUTE_TIME_MODIFIED
struct _BgPicturesSource
{
BgSource parent_instance;
GCancellable *cancellable;
CcBackgroundGriloMiner *grl_miner;
GnomeDesktopThumbnailFactory *thumb_factory;
GFileMonitor *picture_dir_monitor;
GFileMonitor *cache_dir_monitor;
GHashTable *known_items;
};
G_DEFINE_TYPE (BgPicturesSource, bg_pictures_source, BG_TYPE_SOURCE)
const char * const content_types[] = {
"image/png",
"image/jp2",
"image/jpeg",
"image/bmp",
"image/svg+xml",
"image/x-portable-anymap",
NULL
};
const char * const screenshot_types[] = {
"image/png",
NULL
};
static char *bg_pictures_source_get_unique_filename (const char *uri);
static void picture_opened_for_read (GObject *source_object, GAsyncResult *res, gpointer user_data);
static void
bg_pictures_source_dispose (GObject *object)
{
BgPicturesSource *source = BG_PICTURES_SOURCE (object);
if (source->cancellable)
{
g_cancellable_cancel (source->cancellable);
g_clear_object (&source->cancellable);
}
g_clear_object (&source->grl_miner);
g_clear_object (&source->thumb_factory);
G_OBJECT_CLASS (bg_pictures_source_parent_class)->dispose (object);
}
static void
bg_pictures_source_finalize (GObject *object)
{
BgPicturesSource *bg_source = BG_PICTURES_SOURCE (object);
g_clear_object (&bg_source->thumb_factory);
g_clear_pointer (&bg_source->known_items, g_hash_table_destroy);
g_clear_object (&bg_source->picture_dir_monitor);
g_clear_object (&bg_source->cache_dir_monitor);
G_OBJECT_CLASS (bg_pictures_source_parent_class)->finalize (object);
}
static void
bg_pictures_source_class_init (BgPicturesSourceClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->dispose = bg_pictures_source_dispose;
object_class->finalize = bg_pictures_source_finalize;
}
static void
remove_placeholder (BgPicturesSource *bg_source, CcBackgroundItem *item)
{
GtkListStore *store;
GtkTreeIter iter;
GtkTreePath *path;
GtkTreeRowReference *row_ref;
store = bg_source_get_liststore (BG_SOURCE (bg_source));
row_ref = g_object_get_data (G_OBJECT (item), "row-ref");
if (row_ref == NULL)
return;
path = gtk_tree_row_reference_get_path (row_ref);
if (!gtk_tree_model_get_iter (GTK_TREE_MODEL (store), &iter, path))
return;
gtk_list_store_remove (store, &iter);
}
static gboolean
picture_needs_rotation (GdkPixbuf *pixbuf)
{
const gchar *str;
str = gdk_pixbuf_get_option (pixbuf, "orientation");
if (str == NULL)
return FALSE;
if (*str == '5' || *str == '6' || *str == '7' || *str == '8')
return TRUE;
return FALSE;
}
static GdkPixbuf *
swap_rotated_pixbuf (GdkPixbuf *pixbuf)
{
GdkPixbuf *tmp_pixbuf;
tmp_pixbuf = gdk_pixbuf_apply_embedded_orientation (pixbuf);
if (tmp_pixbuf == NULL)
return pixbuf;
g_object_unref (pixbuf);
return tmp_pixbuf;
}
static void
picture_scaled (GObject *source_object,
GAsyncResult *res,
gpointer user_data)
{
BgPicturesSource *bg_source;
CcBackgroundItem *item;
g_autoptr(GError) error = NULL;
g_autoptr(GdkPixbuf) pixbuf = NULL;
const char *software;
const char *uri;
GtkTreeIter iter;
GtkTreePath *path;
GtkTreeRowReference *row_ref;
GtkListStore *store;
cairo_surface_t *surface = NULL;
int scale_factor;
gboolean rotation_applied;
item = g_object_get_data (source_object, "item");
pixbuf = gdk_pixbuf_new_from_stream_finish (res, &error);
if (pixbuf == NULL)
{
if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
{
g_warning ("Failed to load image: %s", error->message);
remove_placeholder (BG_PICTURES_SOURCE (user_data), item);
}
return;
}
/* since we were not cancelled, we can now cast user_data
* back to BgPicturesSource.
*/
bg_source = BG_PICTURES_SOURCE (user_data);
store = bg_source_get_liststore (BG_SOURCE (bg_source));
uri = cc_background_item_get_uri (item);
if (uri == NULL)
uri = cc_background_item_get_source_url (item);
/* Ignore screenshots */
software = gdk_pixbuf_get_option (pixbuf, "tEXt::Software");
if (software != NULL &&
g_str_equal (software, "gnome-screenshot"))
{
g_debug ("Ignored URL '%s' as it's a screenshot from gnome-screenshot", uri);
remove_placeholder (BG_PICTURES_SOURCE (user_data), item);
return;
}
/* Process embedded orientation */
rotation_applied = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (item), "rotation-applied"));
if (!rotation_applied && picture_needs_rotation (pixbuf))
{
/* the width and height of pixbuf we requested are wrong for EXIF
* orientations 5, 6, 7 and 8. the file has to be reloaded. */
g_autoptr(GFile) file = NULL;
file = g_file_new_for_uri (uri);
g_object_set_data (G_OBJECT (item), "needs-rotation", GINT_TO_POINTER (TRUE));
g_object_set_data_full (G_OBJECT (file), "item", g_object_ref (item), g_object_unref);
g_file_read_async (G_FILE (file), G_PRIORITY_DEFAULT,
bg_source->cancellable,
picture_opened_for_read, bg_source);
return;
}
pixbuf = swap_rotated_pixbuf (pixbuf);
scale_factor = bg_source_get_scale_factor (BG_SOURCE (bg_source));
surface = gdk_cairo_surface_create_from_pixbuf (pixbuf, scale_factor, NULL);
cc_background_item_load (item, NULL);
row_ref = g_object_get_data (G_OBJECT (item), "row-ref");
if (row_ref == NULL)
{
/* insert the item into the liststore if it did not exist */
gtk_list_store_insert_with_values (store, NULL, -1,
0, surface,
1, item,
-1);
}
else
{
path = gtk_tree_row_reference_get_path (row_ref);
if (gtk_tree_model_get_iter (GTK_TREE_MODEL (store), &iter, path))
{
/* otherwise update the thumbnail */
gtk_list_store_set (store, &iter,
0, surface,
-1);
}
}
g_hash_table_insert (bg_source->known_items,
bg_pictures_source_get_unique_filename (uri),
GINT_TO_POINTER (TRUE));
g_clear_pointer (&surface, (GDestroyNotify) cairo_surface_destroy);
}
static void
picture_opened_for_read (GObject *source_object,
GAsyncResult *res,
gpointer user_data)
{
BgPicturesSource *bg_source;
CcBackgroundItem *item;
g_autoptr(GFileInputStream) stream = NULL;
g_autoptr(GError) error = NULL;
gint thumbnail_height;
gint thumbnail_width;
gboolean needs_rotation;
item = g_object_get_data (source_object, "item");
stream = g_file_read_finish (G_FILE (source_object), res, &error);
if (stream == NULL)
{
if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
{
g_autofree gchar *filename = g_file_get_path (G_FILE (source_object));
g_warning ("Failed to load picture '%s': %s", filename, error->message);
remove_placeholder (BG_PICTURES_SOURCE (user_data), item);
}
return;
}
/* since we were not cancelled, we can now cast user_data
* back to BgPicturesSource.
*/
bg_source = BG_PICTURES_SOURCE (user_data);
needs_rotation = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (item), "needs-rotation"));
if (needs_rotation)
{
/* swap width and height for EXIF orientations that need it */
thumbnail_width = bg_source_get_thumbnail_height (BG_SOURCE (bg_source));
thumbnail_height = bg_source_get_thumbnail_width (BG_SOURCE (bg_source));
g_object_set_data (G_OBJECT (item), "rotation-applied", GINT_TO_POINTER (TRUE));
}
else
{
thumbnail_width = bg_source_get_thumbnail_width (BG_SOURCE (bg_source));
thumbnail_height = bg_source_get_thumbnail_height (BG_SOURCE (bg_source));
}
g_object_set_data_full (G_OBJECT (stream), "item", g_object_ref (item), g_object_unref);
gdk_pixbuf_new_from_stream_at_scale_async (G_INPUT_STREAM (stream),
thumbnail_width, thumbnail_height,
TRUE,
bg_source->cancellable,
picture_scaled, bg_source);
}
static void
picture_copied_for_read (GObject *source_object,
GAsyncResult *res,
gpointer user_data)
{
BgPicturesSource *bg_source;
CcBackgroundItem *item;
g_autoptr(GError) error = NULL;
GFile *thumbnail_file = G_FILE (source_object);
GFile *native_file;
if (!g_file_copy_finish (thumbnail_file, res, &error))
{
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
return;
else if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_EXISTS))
{
g_autofree gchar *uri = NULL;
uri = g_file_get_uri (thumbnail_file);
g_warning ("Failed to download '%s': %s", uri, error->message);
return;
}
}
bg_source = BG_PICTURES_SOURCE (user_data);
native_file = g_object_get_data (G_OBJECT (thumbnail_file), "native-file");
item = g_object_get_data (G_OBJECT (thumbnail_file), "item");
g_object_set_data_full (G_OBJECT (native_file), "item", g_object_ref (item), g_object_unref);
g_file_read_async (native_file,
G_PRIORITY_DEFAULT,
bg_source->cancellable,
picture_opened_for_read,
bg_source);
}
static gboolean
in_content_types (const char *content_type)
{
guint i;
for (i = 0; content_types[i]; i++)
if (g_str_equal (content_types[i], content_type))
return TRUE;
return FALSE;
}
static gboolean
in_screenshot_types (const char *content_type)
{
guint i;
for (i = 0; screenshot_types[i]; i++)
if (g_str_equal (screenshot_types[i], content_type))
return TRUE;
return FALSE;
}
static cairo_surface_t *
get_content_loading_icon (BgSource *source)
{
GtkIconTheme *theme;
g_autoptr(GtkIconInfo) icon_info = NULL;
g_autoptr(GdkPixbuf) pixbuf = NULL;
g_autoptr(GdkPixbuf) ret = NULL;
g_autoptr(GError) error = NULL;
int scale_factor;
cairo_surface_t *surface;
int thumbnail_height;
int thumbnail_width;
theme = gtk_icon_theme_get_default ();
icon_info = gtk_icon_theme_lookup_icon (theme,
"content-loading-symbolic",
16,
GTK_ICON_LOOKUP_FORCE_SIZE | GTK_ICON_LOOKUP_GENERIC_FALLBACK);
if (icon_info == NULL)
{
g_warning ("Failed to find placeholder icon");
return NULL;
}
pixbuf = gtk_icon_info_load_icon (icon_info, &error);
if (pixbuf == NULL)
{
g_warning ("Failed to load placeholder icon: %s", error->message);
return NULL;
}
thumbnail_height = bg_source_get_thumbnail_height (source);
thumbnail_width = bg_source_get_thumbnail_width (source);
ret = gdk_pixbuf_new (GDK_COLORSPACE_RGB,
TRUE,
8, thumbnail_width, thumbnail_height);
gdk_pixbuf_fill (ret, 0x00000000);
/* Put the icon in the middle */
gdk_pixbuf_copy_area (pixbuf, 0, 0,
gdk_pixbuf_get_width (pixbuf), gdk_pixbuf_get_height (pixbuf),
ret,
(thumbnail_width - gdk_pixbuf_get_width (pixbuf)) / 2,
(thumbnail_height - gdk_pixbuf_get_height (pixbuf)) / 2);
scale_factor = bg_source_get_scale_factor (source);
surface = gdk_cairo_surface_create_from_pixbuf (ret, scale_factor, NULL);
return surface;
}
static GFile *
bg_pictures_source_get_cache_file (void)
{
g_autofree gchar *path = NULL;
GFile *file;
path = bg_pictures_source_get_cache_path ();
file = g_file_new_for_path (path);
return file;
}
static gboolean
add_single_file (BgPicturesSource *bg_source,
GFile *file,
const gchar *content_type,
guint64 mtime,
GtkTreeRowReference **ret_row_ref)
{
g_autoptr(CcBackgroundItem) item = NULL;
CcBackgroundItemFlags flags = 0;
GtkListStore *store;
GtkTreeIter iter;
GtkTreePath *path = NULL;
GtkTreeRowReference *row_ref = NULL;
cairo_surface_t *surface = NULL;
g_autofree gchar *source_uri = NULL;
g_autofree gchar *uri = NULL;
gboolean needs_download;
gboolean retval = FALSE;
g_autoptr(GFile) pictures_dir = NULL;
g_autoptr(GFile) cache_dir = NULL;
GrlMedia *media;
/* find png and jpeg files */
if (!content_type)
goto out;
if (!in_content_types (content_type))
goto out;
/* create a new CcBackgroundItem */
uri = g_file_get_uri (file);
pictures_dir = g_file_new_for_path (g_get_user_special_dir (G_USER_DIRECTORY_PICTURES));
cache_dir = bg_pictures_source_get_cache_file ();
needs_download = !g_file_has_parent (file, pictures_dir) &&
!g_file_has_parent (file, cache_dir);
if (!needs_download)
{
source_uri = g_strdup (uri);
flags |= CC_BACKGROUND_ITEM_HAS_URI;
}
else
{
source_uri = g_steal_pointer (&uri);
}
item = cc_background_item_new (uri);
flags |= CC_BACKGROUND_ITEM_HAS_SHADING | CC_BACKGROUND_ITEM_HAS_PLACEMENT;
g_object_set (G_OBJECT (item),
"flags", flags,
"shading", G_DESKTOP_BACKGROUND_SHADING_SOLID,
"placement", G_DESKTOP_BACKGROUND_STYLE_ZOOM,
"modified", mtime,
"needs-download", needs_download,
"source-url", source_uri,
NULL);
if (!ret_row_ref && in_screenshot_types (content_type))
goto read_file;
surface = get_content_loading_icon (BG_SOURCE (bg_source));
store = bg_source_get_liststore (BG_SOURCE (bg_source));
/* insert the item into the liststore */
gtk_list_store_insert_with_values (store, &iter, -1,
0, surface,
1, item,
-1);
path = gtk_tree_model_get_path (GTK_TREE_MODEL (store), &iter);
row_ref = gtk_tree_row_reference_new (GTK_TREE_MODEL (store), path);
g_object_set_data_full (G_OBJECT (item), "row-ref", row_ref, (GDestroyNotify) gtk_tree_row_reference_free);
read_file:
media = g_object_get_data (G_OBJECT (file), "grl-media");
if (media == NULL)
{
g_object_set_data_full (G_OBJECT (file), "item", g_object_ref (item), g_object_unref);
g_file_read_async (file, G_PRIORITY_DEFAULT,
bg_source->cancellable,
picture_opened_for_read, bg_source);
}
else
{
g_autoptr(GFile) native_file = NULL;
g_autoptr(GFile) thumbnail_file = NULL;
g_autofree gchar *native_dir = NULL;
g_autofree gchar *native_path = NULL;
const gchar *title;
const gchar *thumbnail_uri;
title = grl_media_get_title (media);
g_object_set (G_OBJECT (item), "name", title, NULL);
thumbnail_uri = grl_media_get_thumbnail (media);
thumbnail_file = g_file_new_for_uri (thumbnail_uri);
native_path = gnome_desktop_thumbnail_path_for_uri (source_uri, GNOME_DESKTOP_THUMBNAIL_SIZE_LARGE);
native_file = g_file_new_for_path (native_path);
native_dir = g_path_get_dirname (native_path);
g_mkdir_with_parents (native_dir, USER_DIR_MODE);
g_object_set_data_full (G_OBJECT (thumbnail_file), "item", g_object_ref (item), g_object_unref);
g_object_set_data_full (G_OBJECT (thumbnail_file),
"native-file",
g_object_ref (native_file),
g_object_unref);
g_file_copy_async (thumbnail_file,
native_file,
G_FILE_COPY_ALL_METADATA,
G_PRIORITY_DEFAULT,
bg_source->cancellable,
NULL,
NULL,
picture_copied_for_read,
bg_source);
}
retval = TRUE;
out:
if (ret_row_ref)
{
if (row_ref && retval != FALSE)
*ret_row_ref = gtk_tree_row_reference_copy (row_ref);
else
*ret_row_ref = NULL;
}
gtk_tree_path_free (path);
g_clear_pointer (&surface, (GDestroyNotify) cairo_surface_destroy);
return retval;
}
static gboolean
add_single_file_from_info (BgPicturesSource *bg_source,
GFile *file,
GFileInfo *info,
GtkTreeRowReference **ret_row_ref)
{
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);
return add_single_file (bg_source, file, content_type, mtime, ret_row_ref);
}
static gboolean
add_single_file_from_media (BgPicturesSource *bg_source,
GFile *file,
GrlMedia *media)
{
GDateTime *mtime;
const gchar *content_type;
gint64 mtime_unix;
content_type = grl_media_get_mime (media);
/* only GRL_METADATA_KEY_CREATION_DATE is implemented in the Flickr
* plugin, GRL_METADATA_KEY_MODIFICATION_DATE is not
*/
mtime = grl_media_get_creation_date (media);
if (!mtime)
mtime = grl_media_get_modification_date (media);
if (mtime)
mtime_unix = g_date_time_to_unix (mtime);
else
mtime_unix = g_get_real_time () / G_USEC_PER_SEC;
return add_single_file (bg_source, file, content_type, (guint64) mtime_unix, NULL);
}
gboolean
bg_pictures_source_add (BgPicturesSource *bg_source,
const char *uri,
GtkTreeRowReference **ret_row_ref)
{
g_autoptr(GFile) file = NULL;
GFileInfo *info;
gboolean retval;
file = g_file_new_for_uri (uri);
info = g_file_query_info (file, ATTRIBUTES, G_FILE_QUERY_INFO_NONE, NULL, NULL);
if (info == NULL)
return FALSE;
retval = add_single_file_from_info (bg_source, file, info, ret_row_ref);
return retval;
}
gboolean
bg_pictures_source_remove (BgPicturesSource *bg_source,
const char *uri)
{
GtkTreeModel *model;
GtkTreeIter iter;
gboolean cont;
gboolean retval;
retval = FALSE;
model = GTK_TREE_MODEL (bg_source_get_liststore (BG_SOURCE (bg_source)));
cont = gtk_tree_model_get_iter_first (model, &iter);
while (cont)
{
g_autoptr(CcBackgroundItem) tmp_item = NULL;
const char *tmp_uri;
gtk_tree_model_get (model, &iter, 1, &tmp_item, -1);
tmp_uri = cc_background_item_get_uri (tmp_item);
if (g_str_equal (tmp_uri, uri))
{
char *uuid;
uuid = bg_pictures_source_get_unique_filename (uri);
g_hash_table_insert (bg_source->known_items,
uuid, NULL);
gtk_list_store_remove (GTK_LIST_STORE (model), &iter);
retval = TRUE;
break;
}
cont = gtk_tree_model_iter_next (model, &iter);
}
return retval;
}
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 (GObject *source,
GAsyncResult *res,
gpointer user_data)
{
BgPicturesSource *bg_source;
GList *files, *l;
g_autoptr(GError) err = NULL;
GFile *parent;
files = g_file_enumerator_next_files_finish (G_FILE_ENUMERATOR (source),
res,
&err);
if (err)
{
if (!g_error_matches (err, G_IO_ERROR, G_IO_ERROR_CANCELLED))
g_warning ("Could not get pictures file information: %s", err->message);
g_list_foreach (files, (GFunc) g_object_unref, NULL);
g_list_free (files);
return;
}
bg_source = BG_PICTURES_SOURCE (user_data);
parent = g_file_enumerator_get_container (G_FILE_ENUMERATOR (source));
files = g_list_sort (files, file_sort_func);
/* iterate over the available files */
for (l = files; l; l = g_list_next (l))
{
GFileInfo *info = l->data;
g_autoptr(GFile) file = NULL;
file = g_file_get_child (parent, g_file_info_get_name (info));
add_single_file_from_info (bg_source, file, info, NULL);
}
g_list_foreach (files, (GFunc) g_object_unref, NULL);
g_list_free (files);
}
static void
dir_enum_async_ready (GObject *s,
GAsyncResult *res,
gpointer user_data)
{
BgPicturesSource *source = (BgPicturesSource *) user_data;
g_autoptr(GFileEnumerator) enumerator = NULL;
g_autoptr(GError) err = NULL;
enumerator = g_file_enumerate_children_finish (G_FILE (s), res, &err);
if (err)
{
if (!g_error_matches (err, G_IO_ERROR, G_IO_ERROR_CANCELLED))
g_warning ("Could not fill pictures source: %s", err->message);
return;
}
/* get the files */
g_file_enumerator_next_files_async (enumerator,
G_MAXINT,
G_PRIORITY_LOW,
source->cancellable,
file_info_async_ready,
user_data);
}
char *
bg_pictures_source_get_cache_path (void)
{
return g_build_filename (g_get_user_cache_dir (),
"gnome-control-center",
"backgrounds",
NULL);
}
static char *
bg_pictures_source_get_unique_filename (const char *uri)
{
g_autoptr(GChecksum) csum = NULL;
char *ret;
csum = g_checksum_new (G_CHECKSUM_SHA256);
g_checksum_update (csum, (guchar *) uri, -1);
ret = g_strdup (g_checksum_get_string (csum));
return ret;
}
char *
bg_pictures_source_get_unique_path (const char *uri)
{
g_autoptr(GFile) parent = NULL;
g_autoptr(GFile) file = NULL;
g_autofree gchar *cache_path = NULL;
g_autofree gchar *filename = NULL;
cache_path = bg_pictures_source_get_cache_path ();
parent = g_file_new_for_path (cache_path);
filename = bg_pictures_source_get_unique_filename (uri);
file = g_file_get_child (parent, filename);
return g_file_get_path (file);
}
gboolean
bg_pictures_source_is_known (BgPicturesSource *bg_source,
const char *uri)
{
g_autofree gchar *uuid = NULL;
uuid = bg_pictures_source_get_unique_filename (uri);
return GPOINTER_TO_INT (g_hash_table_lookup (bg_source->known_items, uuid));
}
static int
sort_func (GtkTreeModel *model,
GtkTreeIter *a,
GtkTreeIter *b,
BgPicturesSource *bg_source)
{
g_autoptr(CcBackgroundItem) item_a = NULL;
g_autoptr(CcBackgroundItem) item_b = NULL;
guint64 modified_a;
guint64 modified_b;
int retval;
gtk_tree_model_get (model, a,
1, &item_a,
-1);
gtk_tree_model_get (model, b,
1, &item_b,
-1);
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
file_info_ready (GObject *object,
GAsyncResult *res,
gpointer user_data)
{
GFileInfo *info;
GError *error = NULL;
GFile *file = G_FILE (object);
info = g_file_query_info_finish (file, res, &error);
if (!info)
{
if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
g_warning ("Problem looking up file info: %s", error->message);
g_clear_error (&error);
return;
}
add_single_file_from_info (BG_PICTURES_SOURCE (user_data), file, info, NULL);
}
static void
file_added (GFile *file,
BgPicturesSource *self)
{
g_autofree gchar *uri = NULL;
uri = g_file_get_uri (file);
if (!bg_pictures_source_is_known (self, uri))
{
g_file_query_info_async (file,
ATTRIBUTES,
G_FILE_QUERY_INFO_NONE,
G_PRIORITY_LOW,
NULL,
file_info_ready,
self);
}
}
static void
files_changed_cb (GFileMonitor *monitor,
GFile *file,
GFile *other_file,
GFileMonitorEvent event_type,
gpointer user_data)
{
BgPicturesSource *self = BG_PICTURES_SOURCE (user_data);
g_autofree gchar *uri = NULL;
switch (event_type)
{
case G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT:
file_added (file, self);
break;
case G_FILE_MONITOR_EVENT_DELETED:
uri = g_file_get_uri (file);
bg_pictures_source_remove (self, uri);
break;
default:
return;
}
}
static GFileMonitor *
monitor_path (BgPicturesSource *self,
const char *path)
{
GFileMonitor *monitor;
g_autoptr(GFile) dir = NULL;
g_mkdir_with_parents (path, USER_DIR_MODE);
dir = g_file_new_for_path (path);
g_file_enumerate_children_async (dir,
ATTRIBUTES,
G_FILE_QUERY_INFO_NONE,
G_PRIORITY_LOW, self->cancellable,
dir_enum_async_ready, self);
monitor = g_file_monitor_directory (dir,
G_FILE_MONITOR_NONE,
self->cancellable,
NULL);
if (monitor)
g_signal_connect (monitor,
"changed",
G_CALLBACK (files_changed_cb),
self);
return monitor;
}
static void
media_found_cb (BgPicturesSource *self, GrlMedia *media)
{
g_autoptr(GFile) file = NULL;
const gchar *uri;
uri = grl_media_get_url (media);
file = g_file_new_for_uri (uri);
g_object_set_data_full (G_OBJECT (file), "grl-media", g_object_ref (media), g_object_unref);
add_single_file_from_media (self, file, media);
}
static void
bg_pictures_source_init (BgPicturesSource *self)
{
const gchar *pictures_path;
g_autofree gchar *cache_path = NULL;
GtkListStore *store;
self->cancellable = g_cancellable_new ();
self->known_items = g_hash_table_new_full (g_str_hash,
g_str_equal,
(GDestroyNotify) g_free,
NULL);
pictures_path = g_get_user_special_dir (G_USER_DIRECTORY_PICTURES);
if (pictures_path == NULL)
pictures_path = g_get_home_dir ();
self->picture_dir_monitor = monitor_path (self, pictures_path);
cache_path = bg_pictures_source_get_cache_path ();
self->cache_dir_monitor = monitor_path (self, cache_path);
self->grl_miner = cc_background_grilo_miner_new ();
g_signal_connect_swapped (self->grl_miner, "media-found", G_CALLBACK (media_found_cb), self);
cc_background_grilo_miner_start (self->grl_miner);
self->thumb_factory =
gnome_desktop_thumbnail_factory_new (GNOME_DESKTOP_THUMBNAIL_SIZE_LARGE);
store = bg_source_get_liststore (BG_SOURCE (self));
gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (store),
1,
(GtkTreeIterCompareFunc)sort_func,
self,
NULL);
gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (store),
1,
GTK_SORT_ASCENDING);
}
BgPicturesSource *
bg_pictures_source_new (GtkWindow *window)
{
return g_object_new (BG_TYPE_PICTURES_SOURCE, "window", window, NULL);
}
const char * const *
bg_pictures_get_support_content_types (void)
{
return content_types;
}

View File

@@ -0,0 +1,50 @@
/* bg-pictures-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>
*
*/
#ifndef _BG_PICTURES_SOURCE_H
#define _BG_PICTURES_SOURCE_H
#include <gtk/gtk.h>
#include "bg-source.h"
#include "cc-background-item.h"
G_BEGIN_DECLS
#define BG_TYPE_PICTURES_SOURCE (bg_pictures_source_get_type ())
G_DECLARE_FINAL_TYPE (BgPicturesSource, bg_pictures_source, BG, PICTURES_SOURCE, BgSource)
BgPicturesSource *bg_pictures_source_new (GtkWindow *window);
char *bg_pictures_source_get_cache_path (void);
char *bg_pictures_source_get_unique_path(const char *uri);
gboolean bg_pictures_source_add (BgPicturesSource *bg_source,
const char *uri,
GtkTreeRowReference **ret_row_ref);
gboolean bg_pictures_source_remove (BgPicturesSource *bg_source,
const char *uri);
gboolean bg_pictures_source_is_known (BgPicturesSource *bg_source,
const char *uri);
const char * const * bg_pictures_get_support_content_types (void);
G_END_DECLS
#endif /* _BG_PICTURES_SOURCE_H */

View File

@@ -1,459 +0,0 @@
/* 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;
CcBackgroundItemFlags flags = 0;
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);
flags |= CC_BACKGROUND_ITEM_HAS_SHADING | CC_BACKGROUND_ITEM_HAS_PLACEMENT;
g_object_set (G_OBJECT (item),
"flags", flags,
"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 (GtkWidget *widget)
{
return g_object_new (BG_TYPE_RECENT_SOURCE,
"widget", widget,
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));
}

View File

@@ -1,39 +0,0 @@
/* 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 (GtkWidget *widget);
void bg_recent_source_add_file (BgRecentSource *self,
const gchar *path);
void bg_recent_source_remove_item (BgRecentSource *self,
CcBackgroundItem *item);
G_END_DECLS

View File

@@ -23,14 +23,13 @@
#include <cairo-gobject.h>
#define THUMBNAIL_WIDTH 144
#define THUMBNAIL_WIDTH 256
#define THUMBNAIL_HEIGHT (THUMBNAIL_WIDTH * 3 / 4)
typedef struct
{
GnomeDesktopThumbnailFactory *thumbnail_factory;
GListStore *store;
GtkWidget *widget;
GtkListStore *store;
GtkWidget *window;
gint thumbnail_height;
gint thumbnail_width;
} BgSourcePrivate;
@@ -40,7 +39,7 @@ G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (BgSource, bg_source, G_TYPE_OBJECT)
enum
{
PROP_LISTSTORE = 1,
PROP_WIDGET
PROP_WINDOW
};
@@ -53,10 +52,10 @@ bg_source_calculate_thumbnail_dimensions (BgSource *source)
priv->thumbnail_height = THUMBNAIL_HEIGHT;
priv->thumbnail_width = THUMBNAIL_WIDTH;
if (priv->widget == NULL)
if (priv->window == NULL)
return;
scale_factor = gtk_widget_get_scale_factor (priv->widget);
scale_factor = gtk_widget_get_scale_factor (priv->window);
if (scale_factor > 1)
{
priv->thumbnail_height *= scale_factor;
@@ -102,8 +101,8 @@ bg_source_set_property (GObject *object,
switch (property_id)
{
case PROP_WIDGET:
priv->widget = GTK_WIDGET (g_value_get_object (value));
case PROP_WINDOW:
priv->window = GTK_WIDGET (g_value_get_object (value));
break;
default:
@@ -117,7 +116,6 @@ bg_source_dispose (GObject *object)
BgSource *source = BG_SOURCE (object);
BgSourcePrivate *priv = bg_source_get_instance_private (source);
g_clear_object (&priv->thumbnail_factory);
g_clear_object (&priv->store);
G_OBJECT_CLASS (bg_source_parent_class)->dispose (object);
@@ -137,27 +135,26 @@ bg_source_class_init (BgSourceClass *klass)
pspec = g_param_spec_object ("liststore",
"Liststore",
"Liststore used in the source",
G_TYPE_LIST_STORE,
GTK_TYPE_LIST_STORE,
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
g_object_class_install_property (object_class, PROP_LISTSTORE, pspec);
pspec = g_param_spec_object ("widget",
"Widget",
"Widget used to view the source",
GTK_TYPE_WIDGET,
pspec = g_param_spec_object ("window",
"Window",
"Toplevel window used to view the source",
GTK_TYPE_WINDOW,
G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
g_object_class_install_property (object_class, PROP_WIDGET, pspec);
g_object_class_install_property (object_class, PROP_WINDOW, 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);
priv->thumbnail_factory = gnome_desktop_thumbnail_factory_new (GNOME_DESKTOP_THUMBNAIL_SIZE_LARGE);
priv->store = gtk_list_store_new (3, CAIRO_GOBJECT_TYPE_SURFACE, G_TYPE_OBJECT, G_TYPE_STRING);
}
GListStore*
GtkListStore*
bg_source_get_liststore (BgSource *source)
{
BgSourcePrivate *priv;
@@ -176,7 +173,7 @@ bg_source_get_scale_factor (BgSource *source)
g_return_val_if_fail (BG_IS_SOURCE (source), 1);
priv = bg_source_get_instance_private (source);
return gtk_widget_get_scale_factor (priv->widget);
return gtk_widget_get_scale_factor (priv->window);
}
gint
@@ -200,14 +197,3 @@ bg_source_get_thumbnail_width (BgSource *source)
priv = bg_source_get_instance_private (source);
return priv->thumbnail_width;
}
GnomeDesktopThumbnailFactory*
bg_source_get_thumbnail_factory (BgSource *source)
{
BgSourcePrivate *priv;
g_return_val_if_fail (BG_IS_SOURCE (source), NULL);
priv = bg_source_get_instance_private (source);
return priv->thumbnail_factory;
}

View File

@@ -18,10 +18,10 @@
*
*/
#pragma once
#ifndef _BG_SOURCE_H
#define _BG_SOURCE_H
#include <gtk/gtk.h>
#include <libgnome-desktop/gnome-desktop-thumbnail.h>
G_BEGIN_DECLS
@@ -33,7 +33,7 @@ struct _BgSourceClass
GObjectClass parent_class;
};
GListStore* bg_source_get_liststore (BgSource *source);
GtkListStore* bg_source_get_liststore (BgSource *source);
gint bg_source_get_scale_factor (BgSource *source);
@@ -41,6 +41,6 @@ gint bg_source_get_thumbnail_height (BgSource *source);
gint bg_source_get_thumbnail_width (BgSource *source);
GnomeDesktopThumbnailFactory* bg_source_get_thumbnail_factory (BgSource *source);
G_END_DECLS
#endif /* _BG_SOURCE_H */

View File

@@ -25,56 +25,55 @@
#include "cc-background-xml.h"
#include <cairo-gobject.h>
#include <libgnome-desktop/gnome-desktop-thumbnail.h>
#include <gio/gio.h>
struct _BgWallpapersSource
{
BgSource parent_instance;
GnomeDesktopThumbnailFactory *thumb_factory;
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));
GtkTreeIter iter;
g_autoptr(GdkPixbuf) pixbuf = NULL;
GtkListStore *store = bg_source_get_liststore (BG_SOURCE (source));
cairo_surface_t *surface;
gboolean deleted;
gint scale_factor;
gint thumbnail_height;
gint thumbnail_width;
g_object_get (G_OBJECT (item), "is-deleted", &deleted, NULL);
if (deleted)
return;
g_list_store_insert_sorted (store, item, sort_func, NULL);
gtk_list_store_append (store, &iter);
scale_factor = bg_source_get_scale_factor (BG_SOURCE (source));
thumbnail_height = bg_source_get_thumbnail_height (BG_SOURCE (source));
thumbnail_width = bg_source_get_thumbnail_width (BG_SOURCE (source));
pixbuf = cc_background_item_get_thumbnail (item, source->thumb_factory,
thumbnail_width, thumbnail_height,
scale_factor);
if (pixbuf == NULL)
return;
surface = gdk_cairo_surface_create_from_pixbuf (pixbuf, scale_factor, NULL);
gtk_list_store_set (store, &iter,
0, surface,
1, item,
2, cc_background_item_get_name (item),
-1);
g_clear_pointer (&surface, (GDestroyNotify) cairo_surface_destroy);
}
static void
@@ -88,8 +87,9 @@ list_load_cb (GObject *source_object,
}
static void
item_added (BgWallpapersSource *self,
CcBackgroundItem *item)
item_added (CcBackgroundXml *xml,
CcBackgroundItem *item,
BgWallpapersSource *self)
{
load_wallpapers (NULL, item, self);
}
@@ -122,8 +122,8 @@ bg_wallpapers_source_constructed (GObject *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);
g_signal_connect (G_OBJECT (self->xml), "added",
G_CALLBACK (item_added), self);
/* Try adding the default background first */
load_default_bg (self);
@@ -136,6 +136,7 @@ bg_wallpapers_source_dispose (GObject *object)
{
BgWallpapersSource *self = BG_WALLPAPERS_SOURCE (object);
g_clear_object (&self->thumb_factory);
g_clear_object (&self->xml);
G_OBJECT_CLASS (bg_wallpapers_source_parent_class)->dispose (object);
@@ -144,6 +145,8 @@ bg_wallpapers_source_dispose (GObject *object)
static void
bg_wallpapers_source_init (BgWallpapersSource *self)
{
self->thumb_factory =
gnome_desktop_thumbnail_factory_new (GNOME_DESKTOP_THUMBNAIL_SIZE_LARGE);
self->xml = cc_background_xml_new ();
}
@@ -157,8 +160,8 @@ bg_wallpapers_source_class_init (BgWallpapersSourceClass *klass)
}
BgWallpapersSource *
bg_wallpapers_source_new (GtkWidget *widget)
bg_wallpapers_source_new (GtkWindow *window)
{
return g_object_new (BG_TYPE_WALLPAPERS_SOURCE, "widget", widget, NULL);
return g_object_new (BG_TYPE_WALLPAPERS_SOURCE, "window", window, NULL);
}

View File

@@ -19,7 +19,9 @@
*
*/
#pragma once
#ifndef _BG_WALLPAPERS_SOURCE_H
#define _BG_WALLPAPERS_SOURCE_H
#include <gtk/gtk.h>
#include "bg-source.h"
@@ -29,6 +31,8 @@ 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 (GtkWidget *widget);
BgWallpapersSource *bg_wallpapers_source_new (GtkWindow *window);
G_END_DECLS
#endif /* _BG_WALLPAPERS_SOURCE_H */

View File

@@ -0,0 +1,616 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
*
* Copyright (C) 2012 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General
* Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
*
*/
#include "config.h"
#include <glib/gi18n-lib.h>
#include <gtk/gtk.h>
#include "cc-background-chooser-dialog.h"
#include "bg-wallpapers-source.h"
#include "bg-pictures-source.h"
#include "bg-colors-source.h"
#include "cc-background-item.h"
#include "cc-background-xml.h"
#define WP_PATH_ID "org.gnome.desktop.background"
#define WP_URI_KEY "picture-uri"
#define WP_OPTIONS_KEY "picture-options"
#define WP_SHADING_KEY "color-shading-type"
#define WP_PCOLOR_KEY "primary-color"
#define WP_SCOLOR_KEY "secondary-color"
enum
{
SOURCE_WALLPAPERS,
SOURCE_PICTURES,
SOURCE_COLORS,
};
struct _CcBackgroundChooserDialog
{
GtkDialog parent_instance;
GtkListStore *sources;
GtkWidget *stack;
GtkWidget *pictures_stack;
BgWallpapersSource *wallpapers_source;
BgPicturesSource *pictures_source;
BgColorsSource *colors_source;
GtkTreeRowReference *item_to_focus;
GnomeDesktopThumbnailFactory *thumb_factory;
GCancellable *copy_cancellable;
GtkWidget *spinner;
gulong row_inserted_id;
gulong row_deleted_id;
gulong row_modified_id;
};
G_DEFINE_TYPE (CcBackgroundChooserDialog, cc_background_chooser_dialog, GTK_TYPE_DIALOG)
enum
{
PROP_0,
};
enum
{
URI_LIST,
COLOR
};
static const GtkTargetEntry color_targets[] =
{
{ "application/x-color", 0, COLOR }
};
static void on_visible_child_notify (CcBackgroundChooserDialog *chooser);
static void
cc_background_chooser_dialog_realize (GtkWidget *widget)
{
CcBackgroundChooserDialog *chooser = CC_BACKGROUND_CHOOSER_DIALOG (widget);
GtkWindow *parent;
parent = gtk_window_get_transient_for (GTK_WINDOW (chooser));
if (parent == NULL)
{
gtk_window_set_default_size (GTK_WINDOW (chooser), -1, 550);
}
else
{
gint width;
gint height;
gtk_window_get_size (parent, &width, &height);
gtk_window_set_default_size (GTK_WINDOW (chooser), -1, (gint) (0.66 * height));
}
GTK_WIDGET_CLASS (cc_background_chooser_dialog_parent_class)->realize (widget);
}
static void
cc_background_chooser_dialog_dispose (GObject *object)
{
CcBackgroundChooserDialog *chooser = CC_BACKGROUND_CHOOSER_DIALOG (object);
if (chooser->copy_cancellable)
{
/* cancel any copy operation */
g_cancellable_cancel (chooser->copy_cancellable);
g_clear_object (&chooser->copy_cancellable);
}
/* GtkStack triggers notify::visible-child during dispose and this
* means that we have to explicitly disconnect the signal handler
* before calling up to the parent implementation, or
* on_visible_child_notify() will get called while we're in an
* inconsistent state.
*/
if (chooser->stack != NULL)
{
g_signal_handlers_disconnect_by_func (chooser->stack, on_visible_child_notify, chooser);
chooser->stack = NULL;
}
g_clear_pointer (&chooser->item_to_focus, gtk_tree_row_reference_free);
g_clear_object (&chooser->pictures_source);
g_clear_object (&chooser->colors_source);
g_clear_object (&chooser->wallpapers_source);
g_clear_object (&chooser->thumb_factory);
G_OBJECT_CLASS (cc_background_chooser_dialog_parent_class)->dispose (object);
}
static GtkWidget *
get_visible_view (CcBackgroundChooserDialog *chooser)
{
GtkWidget *visible;
GtkWidget *icon_view = NULL;
visible = gtk_stack_get_visible_child (GTK_STACK (chooser->stack));
if (GTK_IS_STACK (visible))
{
GtkWidget *sw;
sw = gtk_stack_get_child_by_name (GTK_STACK (visible), "view");
icon_view = gtk_bin_get_child (GTK_BIN (sw));
}
else if (GTK_IS_SCROLLED_WINDOW (visible))
{
icon_view = gtk_bin_get_child (GTK_BIN (visible));
}
else
{
g_assert_not_reached ();
}
return icon_view;
}
static void
possibly_show_empty_pictures_box (GtkTreeModel *model,
CcBackgroundChooserDialog *chooser)
{
GtkTreeIter iter;
if (gtk_tree_model_get_iter_first (model, &iter))
{
gtk_stack_set_visible_child_name (GTK_STACK (chooser->pictures_stack), "view");
}
else
{
gtk_stack_set_visible_child_name (GTK_STACK (chooser->pictures_stack), "empty");
}
}
static void
on_source_modified_cb (GtkTreeModel *tree_model,
GtkTreePath *path,
GtkTreeIter *iter,
gpointer user_data)
{
CcBackgroundChooserDialog *chooser = user_data;
GtkTreePath *to_focus_path;
GtkWidget *icon_view;
if (chooser->item_to_focus == NULL)
return;
to_focus_path = gtk_tree_row_reference_get_path (chooser->item_to_focus);
if (gtk_tree_path_compare (to_focus_path, path) != 0)
goto out;
/* Change source */
gtk_stack_set_visible_child_name (GTK_STACK (chooser->stack), "pictures");
/* And select the newly added item */
icon_view = get_visible_view (chooser);
gtk_icon_view_select_path (GTK_ICON_VIEW (icon_view), to_focus_path);
gtk_icon_view_scroll_to_path (GTK_ICON_VIEW (icon_view),
to_focus_path, TRUE, 1.0, 1.0);
g_clear_pointer (&chooser->item_to_focus, gtk_tree_row_reference_free);
out:
gtk_tree_path_free (to_focus_path);
}
static void
on_source_added_cb (GtkTreeModel *model,
GtkTreePath *path,
GtkTreeIter *iter,
gpointer user_data)
{
possibly_show_empty_pictures_box (model, CC_BACKGROUND_CHOOSER_DIALOG (user_data));
}
static void
on_source_removed_cb (GtkTreeModel *model,
GtkTreePath *path,
gpointer user_data)
{
possibly_show_empty_pictures_box (model, CC_BACKGROUND_CHOOSER_DIALOG (user_data));
}
static void
monitor_pictures_model (CcBackgroundChooserDialog *chooser)
{
GtkTreeModel *model;
model = GTK_TREE_MODEL (bg_source_get_liststore (BG_SOURCE (chooser->pictures_source)));
g_signal_connect (model, "row-inserted", G_CALLBACK (on_source_added_cb), chooser);
g_signal_connect (model, "row-deleted", G_CALLBACK (on_source_removed_cb), chooser);
g_signal_connect (model, "row-changed", G_CALLBACK (on_source_modified_cb), chooser);
possibly_show_empty_pictures_box (model, chooser);
}
static void
on_visible_child_notify (CcBackgroundChooserDialog *chooser)
{
GtkWidget *icon_view;
icon_view = get_visible_view (chooser);
gtk_icon_view_unselect_all (GTK_ICON_VIEW (icon_view));
gtk_dialog_set_response_sensitive (GTK_DIALOG (chooser), GTK_RESPONSE_OK, FALSE);
}
static void
on_selection_changed (GtkIconView *icon_view,
CcBackgroundChooserDialog *chooser)
{
GList *list;
list = gtk_icon_view_get_selected_items (icon_view);
gtk_dialog_set_response_sensitive (GTK_DIALOG (chooser),
GTK_RESPONSE_OK,
(list != NULL));
g_list_free_full (list, (GDestroyNotify) gtk_tree_path_free);
}
static void
on_item_activated (GtkIconView *icon_view,
GtkTreePath *path,
CcBackgroundChooserDialog *chooser)
{
gtk_dialog_response (GTK_DIALOG (chooser), GTK_RESPONSE_OK);
}
static void
add_custom_wallpaper (CcBackgroundChooserDialog *chooser,
const char *uri)
{
g_clear_pointer (&chooser->item_to_focus, gtk_tree_row_reference_free);
bg_pictures_source_add (chooser->pictures_source, uri, &chooser->item_to_focus);
/* and wait for the item to get added */
}
static gboolean
cc_background_panel_drag_color (CcBackgroundChooserDialog *chooser,
GtkSelectionData *data)
{
gint length;
guint16 *dropped;
GdkRGBA rgba;
GtkTreeRowReference *row_ref;
GtkTreePath *to_focus_path;
GtkWidget *icon_view;
length = gtk_selection_data_get_length (data);
if (length < 0)
return FALSE;
if (length != 8)
{
g_warning ("%s: Received invalid color data", G_STRFUNC);
return FALSE;
}
dropped = (guint16 *) gtk_selection_data_get_data (data);
rgba.red = dropped[0] / 65535.;
rgba.green = dropped[1] / 65535.;
rgba.blue = dropped[2] / 65535.;
rgba.alpha = dropped[3] / 65535.;
if (bg_colors_source_add (chooser->colors_source, &rgba, &row_ref) == FALSE)
return FALSE;
/* Change source */
gtk_stack_set_visible_child_name (GTK_STACK (chooser->stack), "colors");
/* And select the newly added item */
to_focus_path = gtk_tree_row_reference_get_path (row_ref);
icon_view = get_visible_view (chooser);
gtk_icon_view_select_path (GTK_ICON_VIEW (icon_view), to_focus_path);
gtk_icon_view_scroll_to_path (GTK_ICON_VIEW (icon_view),
to_focus_path, TRUE, 1.0, 1.0);
gtk_tree_row_reference_free (row_ref);
gtk_tree_path_free (to_focus_path);
return TRUE;
}
static void
cc_background_panel_drag_items (GtkWidget *widget,
GdkDragContext *context, gint x, gint y,
GtkSelectionData *data, guint info, guint time,
CcBackgroundChooserDialog *chooser)
{
gint i;
char *uri;
g_auto(GStrv) uris = NULL;
gboolean ret = FALSE;
if (info == COLOR)
{
ret = cc_background_panel_drag_color (chooser, data);
goto out;
}
uris = gtk_selection_data_get_uris (data);
if (!uris)
goto out;
for (i = 0; uris[i] != NULL; i++)
{
uri = uris[i];
if (!bg_pictures_source_is_known (chooser->pictures_source, uri))
{
add_custom_wallpaper (chooser, uri);
ret = TRUE;
}
}
out:
gtk_drag_finish (context, ret, FALSE, time);
}
static GtkWidget *
create_view (CcBackgroundChooserDialog *chooser, GtkTreeModel *model)
{
GtkCellRenderer *renderer;
GtkWidget *icon_view;
GtkWidget *sw;
sw = gtk_scrolled_window_new (NULL, NULL);
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
gtk_widget_set_hexpand (sw, TRUE);
gtk_widget_set_vexpand (sw, TRUE);
icon_view = gtk_icon_view_new ();
gtk_icon_view_set_model (GTK_ICON_VIEW (icon_view), model);
gtk_widget_set_hexpand (icon_view, TRUE);
gtk_container_add (GTK_CONTAINER (sw), icon_view);
g_signal_connect (icon_view, "selection-changed", G_CALLBACK (on_selection_changed), chooser);
g_signal_connect (icon_view, "item-activated", G_CALLBACK (on_item_activated), chooser);
gtk_icon_view_set_columns (GTK_ICON_VIEW (icon_view), 3);
renderer = gtk_cell_renderer_pixbuf_new ();
gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (icon_view),
renderer,
FALSE);
gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (icon_view),
renderer,
"surface", 0,
NULL);
return sw;
}
static void
cc_background_chooser_dialog_constructed (GObject *object)
{
CcBackgroundChooserDialog *chooser = CC_BACKGROUND_CHOOSER_DIALOG (object);
GtkListStore *model;
GtkWidget *sw;
GtkWidget *vbox;
G_OBJECT_CLASS (cc_background_chooser_dialog_parent_class)->constructed (object);
model = bg_source_get_liststore (BG_SOURCE (chooser->wallpapers_source));
sw = create_view (chooser, GTK_TREE_MODEL (model));
gtk_stack_add_titled (GTK_STACK (chooser->stack), sw, "wallpapers", _("Wallpapers"));
gtk_container_child_set (GTK_CONTAINER (chooser->stack), sw, "position", 0, NULL);
model = bg_source_get_liststore (BG_SOURCE (chooser->pictures_source));
sw = create_view (chooser, GTK_TREE_MODEL (model));
gtk_stack_add_named (GTK_STACK (chooser->pictures_stack), sw, "view");
model = bg_source_get_liststore (BG_SOURCE (chooser->colors_source));
sw = create_view (chooser, GTK_TREE_MODEL (model));
gtk_stack_add_titled (GTK_STACK (chooser->stack), sw, "colors", _("Colors"));
vbox = gtk_dialog_get_content_area (GTK_DIALOG (chooser));
gtk_widget_show_all (vbox);
gtk_stack_set_visible_child_name (GTK_STACK (chooser->stack), "wallpapers");
monitor_pictures_model (chooser);
}
static void
cc_background_chooser_dialog_init (CcBackgroundChooserDialog *chooser)
{
GtkWidget *empty_pictures_box;
GtkWidget *vbox;
GtkWidget *headerbar;
GtkWidget *img;
GtkWidget *labels_grid;
GtkWidget *label;
GtkWidget *switcher;
GtkStyleContext *context;
g_autofree gchar *markup = NULL;
g_autofree gchar *markup2 = NULL;
g_autofree gchar *href = NULL;
const gchar *pictures_dir;
g_autofree gchar *pictures_dir_basename = NULL;
g_autofree gchar *pictures_dir_uri = NULL;
GtkTargetList *target_list;
chooser->wallpapers_source = bg_wallpapers_source_new (GTK_WINDOW (chooser));
chooser->pictures_source = bg_pictures_source_new (GTK_WINDOW (chooser));
chooser->colors_source = bg_colors_source_new (GTK_WINDOW (chooser));
gtk_window_set_modal (GTK_WINDOW (chooser), TRUE);
gtk_window_set_resizable (GTK_WINDOW (chooser), FALSE);
/* translators: This is the title of the wallpaper chooser dialog. */
gtk_window_set_title (GTK_WINDOW (chooser), _("Select Background"));
vbox = gtk_dialog_get_content_area (GTK_DIALOG (chooser));
gtk_container_set_border_width (GTK_CONTAINER (vbox), 0);
chooser->stack = gtk_stack_new ();
gtk_stack_set_homogeneous (GTK_STACK (chooser->stack), TRUE);
gtk_container_add (GTK_CONTAINER (vbox), chooser->stack);
g_signal_connect_swapped (chooser->stack, "notify::visible-child", G_CALLBACK (on_visible_child_notify), chooser);
/* Add drag and drop support for bg images */
gtk_drag_dest_set (chooser->stack, GTK_DEST_DEFAULT_ALL, NULL, 0, GDK_ACTION_COPY);
target_list = gtk_target_list_new (NULL, 0);
gtk_target_list_add_uri_targets (target_list, URI_LIST);
gtk_target_list_add_table (target_list, color_targets, 1);
gtk_drag_dest_set_target_list (chooser->stack, target_list);
gtk_target_list_unref (target_list);
g_signal_connect (chooser->stack, "drag-data-received", G_CALLBACK (cc_background_panel_drag_items), chooser);
headerbar = gtk_dialog_get_header_bar (GTK_DIALOG (chooser));
switcher = gtk_stack_switcher_new ();
gtk_stack_switcher_set_stack (GTK_STACK_SWITCHER (switcher), GTK_STACK (chooser->stack));
gtk_header_bar_set_custom_title (GTK_HEADER_BAR (headerbar), switcher);
gtk_widget_show (switcher);
chooser->pictures_stack = gtk_stack_new ();
gtk_stack_set_homogeneous (GTK_STACK (chooser->pictures_stack), TRUE);
gtk_stack_add_titled (GTK_STACK (chooser->stack), chooser->pictures_stack, "pictures", _("Pictures"));
empty_pictures_box = gtk_grid_new ();
gtk_grid_set_column_spacing (GTK_GRID (empty_pictures_box), 12);
gtk_orientable_set_orientation (GTK_ORIENTABLE (empty_pictures_box),
GTK_ORIENTATION_HORIZONTAL);
context = gtk_widget_get_style_context (empty_pictures_box);
gtk_style_context_add_class (context, "dim-label");
gtk_stack_add_named (GTK_STACK (chooser->pictures_stack), empty_pictures_box, "empty");
img = gtk_image_new_from_icon_name ("emblem-photos-symbolic", GTK_ICON_SIZE_DIALOG);
gtk_image_set_pixel_size (GTK_IMAGE (img), 64);
gtk_widget_set_halign (img, GTK_ALIGN_END);
gtk_widget_set_valign (img, GTK_ALIGN_CENTER);
gtk_widget_set_hexpand (img, TRUE);
gtk_widget_set_vexpand (img, TRUE);
gtk_widget_show (img);
gtk_container_add (GTK_CONTAINER (empty_pictures_box), img);
labels_grid = gtk_grid_new ();
gtk_widget_set_halign (labels_grid, GTK_ALIGN_START);
gtk_widget_set_valign (labels_grid, GTK_ALIGN_CENTER);
gtk_widget_set_hexpand (labels_grid, TRUE);
gtk_widget_set_vexpand (labels_grid, TRUE);
gtk_grid_set_row_spacing (GTK_GRID (labels_grid), 6);
gtk_orientable_set_orientation (GTK_ORIENTABLE (labels_grid),
GTK_ORIENTATION_VERTICAL);
gtk_widget_show (labels_grid);
gtk_container_add (GTK_CONTAINER (empty_pictures_box), labels_grid);
label = gtk_label_new ("");
gtk_label_set_use_markup (GTK_LABEL (label), TRUE);
gtk_widget_set_halign (label, GTK_ALIGN_START);
markup = g_markup_printf_escaped ("<b><span size='large'>%s</span></b>",
/* translators: No pictures were found */
_("No Pictures Found"));
gtk_label_set_markup (GTK_LABEL (label), markup);
gtk_widget_show (label);
gtk_container_add (GTK_CONTAINER (labels_grid), label);
label = gtk_label_new ("");
gtk_label_set_max_width_chars (GTK_LABEL (label), 24);
gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
gtk_label_set_use_markup (GTK_LABEL (label), TRUE);
gtk_widget_set_halign (label, GTK_ALIGN_START);
pictures_dir = g_get_user_special_dir (G_USER_DIRECTORY_PICTURES);
if (pictures_dir == NULL)
{
pictures_dir = g_get_home_dir ();
/* translators: "Home" is used in place of the Pictures
* directory in the string below when XDG_PICTURES_DIR is
* undefined */
pictures_dir_basename = g_strdup (_("Home"));
}
else
pictures_dir_basename = g_path_get_basename (pictures_dir);
pictures_dir_uri = g_filename_to_uri (pictures_dir, NULL, NULL);
href = g_markup_printf_escaped ("<a href=\"%s\">%s</a>", pictures_dir_uri, pictures_dir_basename);
/* translators: %s here is the name of the Pictures directory, the string should be translated in
* the context "You can add images to your Pictures folder and they will show up here" */
markup2 = g_strdup_printf (_("You can add images to your %s folder and they will show up here"), href);
gtk_label_set_markup (GTK_LABEL (label), markup2);
gtk_widget_show (label);
gtk_container_add (GTK_CONTAINER (labels_grid), label);
gtk_dialog_add_button (GTK_DIALOG (chooser), _("_Cancel"), GTK_RESPONSE_CANCEL);
gtk_dialog_add_button (GTK_DIALOG (chooser), _("_Select"), GTK_RESPONSE_OK);
gtk_dialog_set_default_response (GTK_DIALOG (chooser), GTK_RESPONSE_OK);
gtk_dialog_set_response_sensitive (GTK_DIALOG (chooser), GTK_RESPONSE_OK, FALSE);
}
static void
cc_background_chooser_dialog_class_init (CcBackgroundChooserDialogClass *klass)
{
GObjectClass *object_class;
GtkWidgetClass *widget_class;
object_class = G_OBJECT_CLASS (klass);
object_class->constructed = cc_background_chooser_dialog_constructed;
object_class->dispose = cc_background_chooser_dialog_dispose;
widget_class = GTK_WIDGET_CLASS (klass);
widget_class->realize = cc_background_chooser_dialog_realize;
}
GtkWidget *
cc_background_chooser_dialog_new (GtkWindow *transient_for)
{
return g_object_new (CC_TYPE_BACKGROUND_CHOOSER_DIALOG,
"transient-for", transient_for,
"use-header-bar", TRUE,
NULL);
}
CcBackgroundItem *
cc_background_chooser_dialog_get_item (CcBackgroundChooserDialog *chooser)
{
GtkTreeIter iter;
GtkTreeModel *model;
GtkWidget *icon_view;
GList *list;
CcBackgroundItem *item;
item = NULL;
icon_view = get_visible_view (chooser);
list = gtk_icon_view_get_selected_items (GTK_ICON_VIEW (icon_view));
if (!list)
return NULL;
model = gtk_icon_view_get_model (GTK_ICON_VIEW (icon_view));
if (gtk_tree_model_get_iter (model, &iter, (GtkTreePath*) list->data) == FALSE)
goto bail;
gtk_tree_model_get (model, &iter, 1, &item, -1);
bail:
g_list_free_full (list, (GDestroyNotify) gtk_tree_path_free);
return item;
}

View File

@@ -1,6 +1,6 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/*
* Copyright 2020 Canonical Ltd.
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
*
* Copyright (C) 2012 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -14,19 +14,25 @@
*
* You should have received a copy of the GNU Lesser General
* Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
*
*/
#pragma once
#ifndef __CC_PANEL_CHOOSER_DIALOG_H__
#define __CC_PANEL_CHOOSER_DIALOG_H__
#include <gtk/gtk.h>
#include <adwaita.h>
#include "cc-background-item.h"
G_BEGIN_DECLS
G_DECLARE_FINAL_TYPE (CcOnlineAccountProviderRow, cc_online_account_provider_row, CC, ONLINE_ACCOUNT_PROVIDER_ROW, AdwActionRow)
#define CC_TYPE_BACKGROUND_CHOOSER_DIALOG (cc_background_chooser_dialog_get_type ())
G_DECLARE_FINAL_TYPE (CcBackgroundChooserDialog, cc_background_chooser_dialog, CC, BACKGROUND_CHOOSER_DIALOG, GtkDialog)
CcOnlineAccountProviderRow *cc_online_account_provider_row_new (GVariant *provider);
GtkWidget * cc_background_chooser_dialog_new (GtkWindow *transient_for);
GVariant *cc_online_account_provider_row_get_provider (CcOnlineAccountProviderRow *row);
CcBackgroundItem * cc_background_chooser_dialog_get_item (CcBackgroundChooserDialog *chooser);
G_END_DECLS
#endif /* __CC_BACKGROUND_CHOOSER_DIALOG_H__ */

View File

@@ -1,340 +0,0 @@
/* 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 <glib/gi18n.h>
#include <libgnome-desktop/gnome-desktop-thumbnail.h>
#include "bg-colors-source.h"
#include "bg-recent-source.h"
#include "bg-wallpapers-source.h"
#include "cc-background-chooser.h"
#include "cc-background-paintable.h"
struct _CcBackgroundChooser
{
GtkBox parent;
GtkFlowBox *flowbox;
GtkWidget *recent_box;
GtkFlowBox *recent_flowbox;
gboolean recent_selected;
BgWallpapersSource *wallpapers_source;
BgRecentSource *recent_source;
};
G_DEFINE_TYPE (CcBackgroundChooser, cc_background_chooser, GTK_TYPE_BOX)
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
on_delete_background_clicked_cb (GtkButton *button,
BgRecentSource *source)
{
GtkWidget *parent;
CcBackgroundItem *item;
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");
bg_recent_source_remove_item (source, item);
}
static void
direction_changed_cb (GtkWidget *widget,
GtkTextDirection *previous_direction,
GdkPaintable *paintable)
{
g_object_set (paintable,
"text-direction", gtk_widget_get_direction (widget),
NULL);
}
static GtkWidget*
create_widget_func (gpointer model_item,
gpointer user_data)
{
g_autoptr(CcBackgroundPaintable) paintable = NULL;
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);
paintable = cc_background_paintable_new (source, item);
picture = gtk_picture_new_for_paintable (GDK_PAINTABLE (paintable));
gtk_picture_set_can_shrink (GTK_PICTURE (picture), FALSE);
g_object_bind_property (picture, "scale-factor",
paintable, "scale-factor", G_BINDING_SYNC_CREATE);
g_signal_connect_object (picture, "direction-changed",
G_CALLBACK (direction_changed_cb), paintable, 0);
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 ("window-close-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);
gtk_accessible_update_property (GTK_ACCESSIBLE (overlay),
GTK_ACCESSIBLE_PROPERTY_LABEL,
cc_background_item_get_name (item),
-1);
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);
g_object_set_data_full (G_OBJECT (child), "item", g_object_ref (item), g_object_unref);
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_finalize (GObject *object)
{
CcBackgroundChooser *self = (CcBackgroundChooser *)object;
g_clear_object (&self->recent_source);
g_clear_object (&self->wallpapers_source);
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->finalize = cc_background_chooser_finalize;
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);
}
static void
cc_background_chooser_init (CcBackgroundChooser *self)
{
gtk_widget_init_template (GTK_WIDGET (self));
self->recent_source = bg_recent_source_new (GTK_WIDGET (self));
self->wallpapers_source = bg_wallpapers_source_new (GTK_WIDGET (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 a 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);
}

View File

@@ -1,32 +0,0 @@
/* 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>
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);
G_END_DECLS

View File

@@ -1,64 +0,0 @@
<?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>

View File

@@ -0,0 +1,315 @@
/*
* Copyright (C) 2014 Red Hat, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include <config.h>
#include <gio/gio.h>
#include <grilo.h>
#define GOA_API_IS_SUBJECT_TO_CHANGE
#include <goa/goa.h>
#include "bg-pictures-source.h"
#include "cc-background-grilo-miner.h"
struct _CcBackgroundGriloMiner
{
GObject parent_instance;
GCancellable *cancellable;
GList *accounts;
};
G_DEFINE_TYPE (CcBackgroundGriloMiner, cc_background_grilo_miner, G_TYPE_OBJECT)
enum
{
MEDIA_FOUND,
LAST_SIGNAL
};
static guint signals[LAST_SIGNAL] = { 0 };
#define REMOTE_ITEM_COUNT 50
static gchar *
get_grilo_id (GoaObject *goa_object)
{
GoaAccount *account;
account = goa_object_peek_account (goa_object);
return g_strdup_printf ("grl-flickr-%s", goa_account_get_id (account));
}
static void
is_online_data_cached (GObject *object,
GAsyncResult *res,
gpointer user_data)
{
CcBackgroundGriloMiner *self;
GError *error = NULL;
GFileInfo *info = NULL;
GFile *cache_file = G_FILE (object);
GrlMedia *media;
const gchar *uri;
info = g_file_query_info_finish (cache_file, res, &error);
if (info == NULL)
{
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
goto out;
}
self = CC_BACKGROUND_GRILO_MINER (user_data);
media = g_object_get_data (G_OBJECT (cache_file), "grl-media");
uri = grl_media_get_url (media);
if (info != NULL)
{
g_debug ("Ignored URL '%s' as it is already in the cache", uri);
goto out;
}
g_signal_emit (self, signals[MEDIA_FOUND], 0, media);
out:
g_clear_object (&info);
g_clear_error (&error);
}
static void
searched_online_source (GrlSource *source,
guint operation_id,
GrlMedia *media,
guint remaining,
gpointer user_data,
const GError *error)
{
CcBackgroundGriloMiner *self = CC_BACKGROUND_GRILO_MINER (user_data);
g_autoptr(GFile) cache_file = NULL;
const gchar *uri;
g_autofree gchar *cache_path = NULL;
if (error != NULL)
{
const gchar *source_id;
source_id = grl_source_get_id (source);
g_warning ("Error searching %s: %s", source_id, error->message);
grl_operation_cancel (operation_id);
remaining = 0;
goto out;
}
uri = grl_media_get_url (media);
cache_path = bg_pictures_source_get_unique_path (uri);
cache_file = g_file_new_for_path (cache_path);
g_object_set_data_full (G_OBJECT (cache_file), "grl-media", media, g_object_unref);
g_file_query_info_async (cache_file,
G_FILE_ATTRIBUTE_STANDARD_TYPE,
G_FILE_QUERY_INFO_NONE,
G_PRIORITY_DEFAULT,
self->cancellable,
is_online_data_cached,
self);
out:
if (remaining == 0)
g_object_unref (self);
}
static void
query_online_source (CcBackgroundGriloMiner *self, GrlSource *source)
{
const GList *keys;
GrlCaps *caps;
GrlOperationOptions *options;
keys = grl_source_supported_keys (source);
caps = grl_source_get_caps (source, GRL_OP_BROWSE);
options = grl_operation_options_new (caps);
grl_operation_options_set_count (options, REMOTE_ITEM_COUNT);
grl_operation_options_set_resolution_flags (options, GRL_RESOLVE_FAST_ONLY);
grl_operation_options_set_type_filter (options, GRL_TYPE_FILTER_IMAGE);
grl_source_search (source, NULL, keys, options, searched_online_source, g_object_ref (self));
g_object_unref (options);
}
static void
add_online_source_cb (CcBackgroundGriloMiner *self,
GrlSource *source)
{
GList *l;
gboolean found = FALSE;
const gchar *source_id;
source_id = grl_source_get_id (source);
for (l = self->accounts; l != NULL && !found; l = l->next)
{
GoaObject *goa_object = GOA_OBJECT (l->data);
g_autofree gchar *account_id = NULL;
account_id = get_grilo_id (goa_object);
if (g_strcmp0 (source_id, account_id) == 0)
{
query_online_source (self, source);
found = TRUE;
}
}
}
static void
client_async_ready (GObject *source,
GAsyncResult *res,
gpointer user_data)
{
CcBackgroundGriloMiner *self;
g_autoptr(GError) error = NULL;
GList *accounts = NULL;
GList *photo_accounts = NULL;
GList *l;
GoaClient *client = NULL;
GrlRegistry *registry;
client = goa_client_new_finish (res, &error);
if (client == NULL)
{
if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
g_warning ("Failed to create GoaClient: %s", error->message);
goto out;
}
self = CC_BACKGROUND_GRILO_MINER (user_data);
accounts = goa_client_get_accounts (client);
for (l = accounts; l != NULL; l = l->next)
{
GoaObject *goa_object = GOA_OBJECT (l->data);
GoaAccount *account;
GoaPhotos *photos;
const gchar *provider_type;
account = goa_object_peek_account (goa_object);
provider_type = goa_account_get_provider_type (account);
photos = goa_object_peek_photos (goa_object);
if (photos != NULL && g_strcmp0 (provider_type, "flickr") == 0)
photo_accounts = g_list_prepend (photo_accounts, g_object_ref (goa_object));
}
if (photo_accounts == NULL)
goto out;
registry = grl_registry_get_default ();
for (l = photo_accounts; l != NULL; l = l->next)
{
GoaObject *goa_object = GOA_OBJECT (l->data);
GrlSource *source;
g_autofree gchar *account_id = NULL;
account_id = get_grilo_id (goa_object);
source = grl_registry_lookup_source (registry, account_id);
if (source != NULL)
query_online_source (self, source);
}
self->accounts = photo_accounts;
photo_accounts = NULL;
g_signal_connect_object (registry, "source-added", G_CALLBACK (add_online_source_cb), self, G_CONNECT_SWAPPED);
out:
g_list_free_full (photo_accounts, g_object_unref);
g_list_free_full (accounts, g_object_unref);
g_clear_object (&client);
}
static void
setup_online_accounts (CcBackgroundGriloMiner *self)
{
goa_client_new (self->cancellable, client_async_ready, self);
}
static void
cc_background_grilo_miner_dispose (GObject *object)
{
CcBackgroundGriloMiner *self = CC_BACKGROUND_GRILO_MINER (object);
if (self->cancellable)
{
g_cancellable_cancel (self->cancellable);
g_clear_object (&self->cancellable);
}
if (self->accounts)
{
g_list_free_full (self->accounts, g_object_unref);
self->accounts = NULL;
}
G_OBJECT_CLASS (cc_background_grilo_miner_parent_class)->dispose (object);
}
static void
cc_background_grilo_miner_init (CcBackgroundGriloMiner *self)
{
self->cancellable = g_cancellable_new ();
}
static void
cc_background_grilo_miner_class_init (CcBackgroundGriloMinerClass *klass)
{
g_autoptr(GError) error = NULL;
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GrlRegistry *registry;
object_class->dispose = cc_background_grilo_miner_dispose;
signals[MEDIA_FOUND] = g_signal_new ("media-found",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST,
0, /* class_offset */
NULL, /* accumulator */
NULL, /* accu_data */
g_cclosure_marshal_VOID__OBJECT,
G_TYPE_NONE,
1,
GRL_TYPE_MEDIA);
grl_init (NULL, NULL);
registry = grl_registry_get_default ();
error = NULL;
if (!grl_registry_load_all_plugins (registry, FALSE, &error) ||
!grl_registry_activate_plugin_by_id (registry, "grl-flickr", &error))
g_warning ("%s", error->message);
}
CcBackgroundGriloMiner *
cc_background_grilo_miner_new (void)
{
return g_object_new (CC_TYPE_BACKGROUND_GRILO_MINER, NULL);
}
void
cc_background_grilo_miner_start (CcBackgroundGriloMiner *self)
{
setup_online_accounts (self);
}

View File

@@ -1,6 +1,5 @@
/* cc-keyboard-shortcut-dialog.h
*
* Copyright (C) 2020 System76, Inc.
/*
* Copyright (C) 2014 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
@@ -14,22 +13,23 @@
*
* 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 <adwaita.h>
#ifndef _CC_BACKGROUND_GRILO_MINER_H
#define _CC_BACKGROUND_GRILO_MINER_H
#include <glib-object.h>
G_BEGIN_DECLS
#define CC_TYPE_KEYBOARD_SHORTCUT_DIALOG (cc_keyboard_shortcut_dialog_get_type ())
#define CC_TYPE_BACKGROUND_GRILO_MINER (cc_background_grilo_miner_get_type ())
G_DECLARE_FINAL_TYPE (CcBackgroundGriloMiner, cc_background_grilo_miner, CC, BACKGROUND_GRILO_MINER, GObject);
G_DECLARE_FINAL_TYPE (CcKeyboardShortcutDialog, cc_keyboard_shortcut_dialog, CC, KEYBOARD_SHORTCUT_DIALOG, AdwWindow)
CcBackgroundGriloMiner *cc_background_grilo_miner_new (void);
GtkWidget* cc_keyboard_shortcut_dialog_new (void);
void cc_background_grilo_miner_start (CcBackgroundGriloMiner *self);
G_END_DECLS
#endif /* _CC_BACKGROUND_GRILO_MINER_H */

View File

@@ -26,20 +26,12 @@
#include <gio/gio.h>
#include <glib/gi18n-lib.h>
#include <gnome-bg/gnome-bg.h>
#include <libgnome-desktop/gnome-bg.h>
#include <gdesktop-enums.h>
#include "cc-background-item.h"
#include "gdesktop-enums-types.h"
typedef struct {
int width;
int height;
int frame;
int scale_factor;
GdkPixbuf *thumbnail;
} CachedThumbnail;
struct _CcBackgroundItem
{
GObject parent_instance;
@@ -47,7 +39,6 @@ struct _CcBackgroundItem
/* properties */
char *name;
char *uri;
char *uri_dark;
char *size;
GDesktopBackgroundStyle placement;
GDesktopBackgroundShading shading;
@@ -61,22 +52,17 @@ struct _CcBackgroundItem
guint64 modified;
/* internal */
GdkPixbuf *slideshow_emblem;
GnomeBG *bg;
char *mime_type;
int width;
int height;
GnomeBG *bg_dark;
CachedThumbnail cached_thumbnail;
CachedThumbnail cached_thumbnail_dark;
};
enum {
PROP_0,
PROP_NAME,
PROP_URI,
PROP_URI_DARK,
PROP_PLACEMENT,
PROP_SHADING,
PROP_PRIMARY_COLOR,
@@ -94,6 +80,64 @@ static void cc_background_item_finalize (GObject *object
G_DEFINE_TYPE (CcBackgroundItem, cc_background_item, G_TYPE_OBJECT)
static GdkPixbuf *slideshow_emblem = NULL;
static GdkPixbuf *
get_emblemed_pixbuf (CcBackgroundItem *item, GdkPixbuf *pixbuf, gint scale_factor)
{
int eh;
int ew;
int h;
int w;
int x;
int y;
if (item->slideshow_emblem == NULL) {
if (slideshow_emblem == NULL) {
g_autoptr(GIcon) icon = NULL;
GtkIconTheme *theme;
g_autoptr(GtkIconInfo) icon_info = NULL;
g_autoptr(GError) error = NULL;
icon = g_themed_icon_new ("slideshow-emblem");
theme = gtk_icon_theme_get_default ();
icon_info = gtk_icon_theme_lookup_by_gicon_for_scale (theme,
icon,
16,
scale_factor,
GTK_ICON_LOOKUP_FORCE_SIZE |
GTK_ICON_LOOKUP_USE_BUILTIN);
if (icon_info == NULL) {
g_warning ("Your icon theme is missing the slideshow-emblem icon, "
"please file a bug against it");
return g_object_ref (pixbuf);
}
slideshow_emblem = gtk_icon_info_load_icon (icon_info, &error);
if (slideshow_emblem == NULL) {
g_warning ("Failed to load slideshow emblem: %s", error->message);
return g_object_ref (pixbuf);
}
g_object_add_weak_pointer (G_OBJECT (slideshow_emblem), (gpointer *) (&slideshow_emblem));
item->slideshow_emblem = slideshow_emblem;
} else {
item->slideshow_emblem = g_object_ref (slideshow_emblem);
}
}
eh = gdk_pixbuf_get_height (slideshow_emblem);
ew = gdk_pixbuf_get_width (slideshow_emblem);
h = gdk_pixbuf_get_height (pixbuf);
w = gdk_pixbuf_get_width (pixbuf);
x = w - ew;
y = h - eh;
gdk_pixbuf_composite (slideshow_emblem, pixbuf, x, y, ew, eh, x, y, 1.0, 1.0, GDK_INTERP_BILINEAR, 255);
return g_object_ref (pixbuf);
}
static void
set_bg_properties (CcBackgroundItem *item)
{
@@ -109,15 +153,6 @@ set_bg_properties (CcBackgroundItem *item)
gnome_bg_set_filename (item->bg, filename);
}
if (item->uri_dark) {
g_autoptr(GFile) file = NULL;
g_autofree gchar *filename = NULL;
file = g_file_new_for_commandline_arg (item->uri_dark);
filename = g_file_get_path (file);
gnome_bg_set_filename (item->bg_dark, filename);
}
if (item->primary_color != NULL) {
gdk_rgba_parse (&pcolor, item->primary_color);
}
@@ -126,9 +161,7 @@ set_bg_properties (CcBackgroundItem *item)
}
gnome_bg_set_rgba (item->bg, item->shading, &pcolor, &scolor);
gnome_bg_set_rgba (item->bg_dark, item->shading, &pcolor, &scolor);
gnome_bg_set_placement (item->bg, item->placement);
gnome_bg_set_placement (item->bg_dark, item->placement);
}
@@ -143,20 +176,9 @@ cc_background_item_changes_with_time (CcBackgroundItem *item)
if (item->bg != NULL) {
changes = gnome_bg_changes_with_time (item->bg);
}
if (item->bg_dark != NULL) {
changes |= gnome_bg_changes_with_time (item->bg_dark);
}
return changes;
}
gboolean
cc_background_item_has_dark_version (CcBackgroundItem *item)
{
g_return_val_if_fail (CC_IS_BACKGROUND_ITEM (item), FALSE);
return item->uri && item->uri_dark;
}
static void
update_size (CcBackgroundItem *item)
{
@@ -168,9 +190,6 @@ update_size (CcBackgroundItem *item)
if (gnome_bg_has_multiple_sizes (item->bg) || gnome_bg_changes_with_time (item->bg)) {
item->size = g_strdup (_("multiple sizes"));
} else {
gdk_pixbuf_get_file_info (gnome_bg_get_filename (item->bg),
&item->width,
&item->height);
/* translators: 100 × 100px
* Note that this is not an "x", but U+00D7 MULTIPLICATION SIGN */
item->size = g_strdup_printf (_("%d × %d"),
@@ -180,6 +199,19 @@ update_size (CcBackgroundItem *item)
}
}
static GdkPixbuf *
render_at_size (GnomeBG *bg,
gint width,
gint height)
{
GdkPixbuf *pixbuf;
pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE, 8, width, height);
gnome_bg_draw (bg, pixbuf, gdk_screen_get_default (), FALSE);
return pixbuf;
}
GdkPixbuf *
cc_background_item_get_frame_thumbnail (CcBackgroundItem *item,
GnomeDesktopThumbnailFactory *thumbs,
@@ -187,62 +219,60 @@ cc_background_item_get_frame_thumbnail (CcBackgroundItem *item,
int height,
int scale_factor,
int frame,
gboolean dark)
gboolean force_size)
{
GdkPixbuf *pixbuf;
CachedThumbnail *thumbnail;
GnomeBG *bg;
g_autoptr(GdkMonitor) monitor = NULL;
GdkDisplay *display;
GListModel *monitors;
GdkRectangle monitor_layout;
g_autoptr(GdkPixbuf) pixbuf = NULL;
g_autoptr(GdkPixbuf) retval = NULL;
g_return_val_if_fail (CC_IS_BACKGROUND_ITEM (item), NULL);
g_return_val_if_fail (width > 0 && height > 0, NULL);
thumbnail = dark ? &item->cached_thumbnail_dark : &item->cached_thumbnail;
bg = dark ? item->bg_dark : item->bg;
/* Use the cached thumbnail if the sizes match */
if (thumbnail->thumbnail &&
thumbnail->width == width &&
thumbnail->height == height &&
thumbnail->scale_factor == scale_factor &&
thumbnail->frame == frame)
return g_object_ref (thumbnail->thumbnail);
set_bg_properties (item);
display = gdk_display_get_default ();
monitors = gdk_display_get_monitors (display);
monitor = g_list_model_get_item (monitors, 0);
gdk_monitor_get_geometry (monitor, &monitor_layout);
if (frame >= 0) {
pixbuf = gnome_bg_create_frame_thumbnail (bg,
thumbs,
&monitor_layout,
width,
height,
frame);
if (force_size) {
/* FIXME: this doesn't play nice with slideshow stepping at all,
* because it will always render the current slideshow frame, which
* might not be what we want.
* We're lacking an API to draw a high-res GnomeBG manually choosing
* the slideshow frame though, so we can't do much better than this
* for now.
*/
pixbuf = render_at_size (item->bg, width, height);
} else {
pixbuf = gnome_bg_create_thumbnail (bg,
thumbs,
&monitor_layout,
width,
height);
if (frame >= 0) {
pixbuf = gnome_bg_create_frame_thumbnail (item->bg,
thumbs,
gdk_screen_get_default (),
width,
height,
frame);
} else {
pixbuf = gnome_bg_create_thumbnail (item->bg,
thumbs,
gdk_screen_get_default (),
width,
height);
}
}
if (pixbuf != NULL
&& frame != -2
&& gnome_bg_changes_with_time (item->bg)) {
retval = get_emblemed_pixbuf (item, pixbuf, scale_factor);
} else {
retval = g_steal_pointer (&pixbuf);
}
gnome_bg_get_image_size (item->bg,
thumbs,
width,
height,
&item->width,
&item->height);
update_size (item);
/* Cache the new thumbnail */
g_set_object (&thumbnail->thumbnail, pixbuf);
thumbnail->width = width;
thumbnail->height = height;
thumbnail->scale_factor = scale_factor;
thumbnail->frame = frame;
return pixbuf;
return g_steal_pointer (&retval);
}
@@ -251,10 +281,9 @@ cc_background_item_get_thumbnail (CcBackgroundItem *item,
GnomeDesktopThumbnailFactory *thumbs,
int width,
int height,
int scale_factor,
gboolean dark)
int scale_factor)
{
return cc_background_item_get_frame_thumbnail (item, thumbs, width, height, scale_factor, -1, dark);
return cc_background_item_get_frame_thumbnail (item, thumbs, width, height, scale_factor, -1, FALSE);
}
static void
@@ -364,21 +393,6 @@ _set_uri (CcBackgroundItem *item,
}
}
static void
_set_uri_dark (CcBackgroundItem *item,
const char *value)
{
g_free (item->uri_dark);
if (value && *value == '\0') {
item->uri_dark = NULL;
} else {
if (value && strstr (value, "://") == NULL)
g_warning ("URI '%s' is invalid", value);
item->uri_dark = g_strdup (value);
}
}
const char *
cc_background_item_get_uri (CcBackgroundItem *item)
{
@@ -387,14 +401,6 @@ cc_background_item_get_uri (CcBackgroundItem *item)
return item->uri;
}
const char *
cc_background_item_get_uri_dark (CcBackgroundItem *item)
{
g_return_val_if_fail (CC_IS_BACKGROUND_ITEM (item), NULL);
return item->uri_dark;
}
static void
_set_placement (CcBackgroundItem *item,
GDesktopBackgroundStyle value)
@@ -566,9 +572,6 @@ cc_background_item_set_property (GObject *object,
case PROP_URI:
_set_uri (self, g_value_get_string (value));
break;
case PROP_URI_DARK:
_set_uri_dark (self, g_value_get_string (value));
break;
case PROP_PLACEMENT:
_set_placement (self, g_value_get_enum (value));
break;
@@ -619,12 +622,9 @@ cc_background_item_get_property (GObject *object,
case PROP_NAME:
g_value_set_string (value, self->name);
break;
case PROP_URI:
case PROP_URI:
g_value_set_string (value, self->uri);
break;
case PROP_URI_DARK:
g_value_set_string (value, self->uri_dark);
break;
case PROP_PLACEMENT:
g_value_set_enum (value, self->placement);
break;
@@ -702,13 +702,6 @@ cc_background_item_class_init (CcBackgroundItemClass *klass)
"uri",
NULL,
G_PARAM_READWRITE));
g_object_class_install_property (object_class,
PROP_URI_DARK,
g_param_spec_string ("uri-dark",
"uri-dark",
"uri-dark",
NULL,
G_PARAM_READWRITE));
g_object_class_install_property (object_class,
PROP_PLACEMENT,
g_param_spec_enum ("placement",
@@ -805,7 +798,6 @@ static void
cc_background_item_init (CcBackgroundItem *item)
{
item->bg = gnome_bg_new ();
item->bg_dark = gnome_bg_new ();
item->shading = G_DESKTOP_BACKGROUND_SHADING_SOLID;
item->placement = G_DESKTOP_BACKGROUND_STYLE_SCALED;
@@ -828,8 +820,6 @@ cc_background_item_finalize (GObject *object)
g_return_if_fail (item != NULL);
g_clear_object (&item->cached_thumbnail.thumbnail);
g_clear_object (&item->cached_thumbnail_dark.thumbnail);
g_free (item->name);
g_free (item->uri);
g_free (item->primary_color);
@@ -839,8 +829,10 @@ cc_background_item_finalize (GObject *object)
g_free (item->source_url);
g_free (item->source_xml);
g_clear_object (&item->bg);
g_clear_object (&item->bg_dark);
if (item->bg != NULL)
g_object_unref (item->bg);
g_clear_object (&item->slideshow_emblem);
G_OBJECT_CLASS (cc_background_item_parent_class)->finalize (object);
}
@@ -999,10 +991,6 @@ cc_background_item_compare (CcBackgroundItem *saved,
if (files_equal (saved->uri, configured->uri) == FALSE)
return FALSE;
}
if (flags & CC_BACKGROUND_ITEM_HAS_URI_DARK) {
if (files_equal (saved->uri_dark, configured->uri_dark) == FALSE)
return FALSE;
}
if (flags & CC_BACKGROUND_ITEM_HAS_SHADING) {
if (saved->shading != configured->shading)
return FALSE;

View File

@@ -17,13 +17,14 @@
*
*/
#pragma once
#ifndef __CC_BACKGROUND_ITEM_H
#define __CC_BACKGROUND_ITEM_H
#include <glib-object.h>
#include <gdk-pixbuf/gdk-pixbuf.h>
#include <libgnome-desktop/gnome-desktop-thumbnail.h>
#include <gdesktop-enums.h>
#include <gnome-bg/gnome-bg.h>
#include <libgnome-desktop/gnome-bg.h>
G_BEGIN_DECLS
@@ -35,8 +36,7 @@ typedef enum {
CC_BACKGROUND_ITEM_HAS_PLACEMENT = 1 << 1,
CC_BACKGROUND_ITEM_HAS_PCOLOR = 1 << 2,
CC_BACKGROUND_ITEM_HAS_SCOLOR = 1 << 3,
CC_BACKGROUND_ITEM_HAS_URI = 1 << 4,
CC_BACKGROUND_ITEM_HAS_URI_DARK = 1 << 5
CC_BACKGROUND_ITEM_HAS_URI = 1 << 4
} CcBackgroundItemFlags;
#define CC_BACKGROUND_ITEM_HAS_ALL (CC_BACKGROUND_ITEM_HAS_SHADING & \
@@ -47,29 +47,26 @@ typedef enum {
CcBackgroundItem * cc_background_item_new (const char *uri);
CcBackgroundItem * cc_background_item_copy (CcBackgroundItem *item);
gboolean cc_background_item_load (CcBackgroundItem *item,
GFileInfo *info);
gboolean cc_background_item_load (CcBackgroundItem *item,
GFileInfo *info);
gboolean cc_background_item_changes_with_time (CcBackgroundItem *item);
gboolean cc_background_item_has_dark_version (CcBackgroundItem *item);
GdkPixbuf * cc_background_item_get_thumbnail (CcBackgroundItem *item,
GnomeDesktopThumbnailFactory *thumbs,
int width,
int height,
int scale_factor,
gboolean dark);
int scale_factor);
GdkPixbuf * cc_background_item_get_frame_thumbnail (CcBackgroundItem *item,
GnomeDesktopThumbnailFactory *thumbs,
int width,
int height,
int scale_factor,
int frame,
gboolean dark);
gboolean force_size);
GDesktopBackgroundStyle cc_background_item_get_placement (CcBackgroundItem *item);
GDesktopBackgroundShading cc_background_item_get_shading (CcBackgroundItem *item);
const char * cc_background_item_get_uri (CcBackgroundItem *item);
const char * cc_background_item_get_uri_dark (CcBackgroundItem *item);
const char * cc_background_item_get_source_url (CcBackgroundItem *item);
const char * cc_background_item_get_source_xml (CcBackgroundItem *item);
CcBackgroundItemFlags cc_background_item_get_flags (CcBackgroundItem *item);
@@ -85,3 +82,5 @@ gboolean cc_background_item_compare (CcBackgroundItem *s
void cc_background_item_dump (CcBackgroundItem *item);
G_END_DECLS
#endif /* __CC_BACKGROUND_ITEM_H */

View File

@@ -1,314 +0,0 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
*
* Copyright (C) 2021 Alexander Mikhaylenko <alexm@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/>.
*
*/
#include <config.h>
#include "cc-background-paintable.h"
struct _CcBackgroundPaintable
{
GObject parent_instance;
BgSource *source;
CcBackgroundItem *item;
int scale_factor;
GtkTextDirection text_direction;
GdkPaintable *texture;
GdkPaintable *dark_texture;
};
enum
{
PROP_0,
PROP_SOURCE,
PROP_ITEM,
PROP_SCALE_FACTOR,
PROP_TEXT_DIRECTION,
N_PROPS
};
static GParamSpec *properties [N_PROPS];
static void cc_background_paintable_paintable_init (GdkPaintableInterface *iface);
G_DEFINE_TYPE_WITH_CODE (CcBackgroundPaintable, cc_background_paintable, G_TYPE_OBJECT,
G_IMPLEMENT_INTERFACE (GDK_TYPE_PAINTABLE,
cc_background_paintable_paintable_init))
static void
update_cache (CcBackgroundPaintable *self)
{
g_autoptr (GdkPixbuf) pixbuf = NULL;
GnomeDesktopThumbnailFactory *factory;
int width, height;
g_clear_object (&self->texture);
g_clear_object (&self->dark_texture);
factory = bg_source_get_thumbnail_factory (self->source);
width = bg_source_get_thumbnail_width (self->source);
height = bg_source_get_thumbnail_height (self->source);
pixbuf = cc_background_item_get_thumbnail (self->item,
factory,
width,
height,
self->scale_factor,
FALSE);
self->texture = GDK_PAINTABLE (gdk_texture_new_for_pixbuf (pixbuf));
if (cc_background_item_has_dark_version (self->item))
{
g_autoptr (GdkPixbuf) dark_pixbuf = NULL;
dark_pixbuf = cc_background_item_get_thumbnail (self->item,
factory,
width,
height,
self->scale_factor,
TRUE);
self->dark_texture = GDK_PAINTABLE (gdk_texture_new_for_pixbuf (dark_pixbuf));
}
gdk_paintable_invalidate_size (GDK_PAINTABLE (self));
}
static void
cc_background_paintable_dispose (GObject *object)
{
CcBackgroundPaintable *self = CC_BACKGROUND_PAINTABLE (object);
g_clear_object (&self->item);
g_clear_object (&self->source);
g_clear_object (&self->texture);
g_clear_object (&self->dark_texture);
G_OBJECT_CLASS (cc_background_paintable_parent_class)->dispose (object);
}
static void
cc_background_paintable_constructed (GObject *object)
{
CcBackgroundPaintable *self = CC_BACKGROUND_PAINTABLE (object);
G_OBJECT_CLASS (cc_background_paintable_parent_class)->constructed (object);
update_cache (self);
}
static void
cc_background_paintable_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
CcBackgroundPaintable *self = CC_BACKGROUND_PAINTABLE (object);
switch (prop_id)
{
case PROP_SOURCE:
g_value_set_object (value, self->source);
break;
case PROP_ITEM:
g_value_set_object (value, self->item);
break;
case PROP_SCALE_FACTOR:
g_value_set_int (value, self->scale_factor);
break;
case PROP_TEXT_DIRECTION:
g_value_set_enum (value, self->text_direction);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void
cc_background_paintable_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
CcBackgroundPaintable *self = CC_BACKGROUND_PAINTABLE (object);
switch (prop_id)
{
case PROP_SOURCE:
g_set_object (&self->source, g_value_get_object (value));
break;
case PROP_ITEM:
g_set_object (&self->item, g_value_get_object (value));
break;
case PROP_SCALE_FACTOR:
self->scale_factor = g_value_get_int (value);
update_cache (self);
break;
case PROP_TEXT_DIRECTION:
self->text_direction = g_value_get_enum (value);
gdk_paintable_invalidate_contents (GDK_PAINTABLE (self));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void
cc_background_paintable_class_init (CcBackgroundPaintableClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->dispose = cc_background_paintable_dispose;
object_class->constructed = cc_background_paintable_constructed;
object_class->get_property = cc_background_paintable_get_property;
object_class->set_property = cc_background_paintable_set_property;
properties[PROP_SOURCE] =
g_param_spec_object ("source",
"Source",
"Source",
BG_TYPE_SOURCE,
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS);
properties[PROP_ITEM] =
g_param_spec_object ("item",
"Item",
"Item",
CC_TYPE_BACKGROUND_ITEM,
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS);
properties[PROP_SCALE_FACTOR] =
g_param_spec_int ("scale-factor",
"Scale Factor",
"Scale Factor",
1, G_MAXINT, 1,
G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS);
properties[PROP_TEXT_DIRECTION] =
g_param_spec_enum ("text-direction",
"Text Direction",
"Text Direction",
GTK_TYPE_TEXT_DIRECTION,
GTK_TEXT_DIR_LTR,
G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS);
g_object_class_install_properties (object_class, N_PROPS, properties);
}
static void
cc_background_paintable_init (CcBackgroundPaintable *self)
{
self->scale_factor = 1;
self->text_direction = GTK_TEXT_DIR_LTR;
}
static void
cc_background_paintable_snapshot (GdkPaintable *paintable,
GdkSnapshot *snapshot,
double width,
double height)
{
CcBackgroundPaintable *self = CC_BACKGROUND_PAINTABLE (paintable);
gboolean is_rtl;
if (!self->dark_texture)
{
gdk_paintable_snapshot (self->texture, snapshot, width, height);
return;
}
is_rtl = self->text_direction == GTK_TEXT_DIR_RTL;
gtk_snapshot_push_clip (GTK_SNAPSHOT (snapshot),
&GRAPHENE_RECT_INIT (is_rtl ? width / 2.0f : 0.0f,
0.0f,
width / 2.0f,
height));
gdk_paintable_snapshot (self->texture, snapshot, width, height);
gtk_snapshot_pop (GTK_SNAPSHOT (snapshot));
gtk_snapshot_push_clip (GTK_SNAPSHOT (snapshot),
&GRAPHENE_RECT_INIT (is_rtl ? 0.0f : width / 2.0f,
0.0f,
width / 2.0f,
height));
gdk_paintable_snapshot (self->dark_texture, snapshot, width, height);
gtk_snapshot_pop (GTK_SNAPSHOT (snapshot));
}
static int
cc_background_paintable_get_intrinsic_width (GdkPaintable *paintable)
{
CcBackgroundPaintable *self = CC_BACKGROUND_PAINTABLE (paintable);
return gdk_paintable_get_intrinsic_width (self->texture) / self->scale_factor;
}
static int
cc_background_paintable_get_intrinsic_height (GdkPaintable *paintable)
{
CcBackgroundPaintable *self = CC_BACKGROUND_PAINTABLE (paintable);
return gdk_paintable_get_intrinsic_height (self->texture) / self->scale_factor;
}
static double
cc_background_paintable_get_intrinsic_aspect_ratio (GdkPaintable *paintable)
{
CcBackgroundPaintable *self = CC_BACKGROUND_PAINTABLE (paintable);
return gdk_paintable_get_intrinsic_aspect_ratio (self->texture);
}
static void
cc_background_paintable_paintable_init (GdkPaintableInterface *iface)
{
iface->snapshot = cc_background_paintable_snapshot;
iface->get_intrinsic_width = cc_background_paintable_get_intrinsic_width;
iface->get_intrinsic_height = cc_background_paintable_get_intrinsic_height;
iface->get_intrinsic_aspect_ratio = cc_background_paintable_get_intrinsic_aspect_ratio;
}
CcBackgroundPaintable *
cc_background_paintable_new (BgSource *source,
CcBackgroundItem *item)
{
g_return_val_if_fail (BG_IS_SOURCE (source), NULL);
g_return_val_if_fail (CC_IS_BACKGROUND_ITEM (item), NULL);
return g_object_new (CC_TYPE_BACKGROUND_PAINTABLE,
"source", source,
"item", item,
NULL);
}

View File

@@ -29,202 +29,266 @@
#include "cc-background-panel.h"
#include "cc-background-chooser.h"
#include "cc-background-chooser-dialog.h"
#include "cc-background-item.h"
#include "cc-background-preview.h"
#include "cc-background-resources.h"
#include "cc-background-xml.h"
#include "bg-pictures-source.h"
#define WP_PATH_ID "org.gnome.desktop.background"
#define WP_LOCK_PATH_ID "org.gnome.desktop.screensaver"
#define WP_URI_KEY "picture-uri"
#define WP_URI_DARK_KEY "picture-uri-dark"
#define WP_OPTIONS_KEY "picture-options"
#define WP_SHADING_KEY "color-shading-type"
#define WP_PCOLOR_KEY "primary-color"
#define WP_SCOLOR_KEY "secondary-color"
#define INTERFACE_PATH_ID "org.gnome.desktop.interface"
#define INTERFACE_COLOR_SCHEME_KEY "color-scheme"
struct _CcBackgroundPanel
{
CcPanel parent_instance;
GtkBuilder *builder;
GDBusConnection *connection;
GSettings *settings;
GSettings *lock_settings;
GSettings *interface_settings;
GDBusProxy *proxy;
GnomeDesktopThumbnailFactory *thumb_factory;
CcBackgroundItem *current_background;
CcBackgroundItem *current_lock_background;
CcBackgroundChooser *background_chooser;
CcBackgroundPreview *default_preview;
CcBackgroundPreview *dark_preview;
GtkToggleButton *default_toggle;
GtkToggleButton *dark_toggle;
GCancellable *copy_cancellable;
GtkWidget *spinner;
GtkWidget *chooser;
};
CC_PANEL_REGISTER (CcBackgroundPanel, cc_background_panel)
static void
load_custom_css (CcBackgroundPanel *self)
{
g_autoptr(GtkCssProvider) provider = NULL;
#define WID(y) (GtkWidget *) gtk_builder_get_object (panel->builder, y)
provider = gtk_css_provider_new ();
gtk_css_provider_load_from_resource (provider, "/org/gnome/control-center/background/preview.css");
gtk_style_context_add_provider_for_display (gdk_display_get_default (),
GTK_STYLE_PROVIDER (provider),
GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
static const char *
cc_background_panel_get_help_uri (CcPanel *panel)
{
return "help:gnome-help/look-background";
}
static void
reload_color_scheme_toggles (CcBackgroundPanel *self)
cc_background_panel_dispose (GObject *object)
{
GDesktopColorScheme scheme;
CcBackgroundPanel *panel = CC_BACKGROUND_PANEL (object);
scheme = g_settings_get_enum (self->interface_settings, INTERFACE_COLOR_SCHEME_KEY);
g_clear_object (&panel->builder);
if (scheme == G_DESKTOP_COLOR_SCHEME_DEFAULT)
/* destroying the builder object will also destroy the spinner */
panel->spinner = NULL;
g_clear_object (&panel->settings);
g_clear_object (&panel->lock_settings);
if (panel->copy_cancellable)
{
gtk_toggle_button_set_active (self->default_toggle, TRUE);
/* cancel any copy operation */
g_cancellable_cancel (panel->copy_cancellable);
g_clear_object (&panel->copy_cancellable);
}
else if (scheme == G_DESKTOP_COLOR_SCHEME_PREFER_DARK)
if (panel->chooser)
{
gtk_toggle_button_set_active (self->dark_toggle, TRUE);
gtk_widget_destroy (panel->chooser);
panel->chooser = NULL;
}
g_clear_object (&panel->thumb_factory);
G_OBJECT_CLASS (cc_background_panel_parent_class)->dispose (object);
}
static void
cc_background_panel_finalize (GObject *object)
{
CcBackgroundPanel *panel = CC_BACKGROUND_PANEL (object);
g_clear_object (&panel->current_background);
g_clear_object (&panel->current_lock_background);
G_OBJECT_CLASS (cc_background_panel_parent_class)->finalize (object);
}
static void
cc_background_panel_class_init (CcBackgroundPanelClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
CcPanelClass *panel_class = CC_PANEL_CLASS (klass);
panel_class->get_help_uri = cc_background_panel_get_help_uri;
object_class->dispose = cc_background_panel_dispose;
object_class->finalize = cc_background_panel_finalize;
}
static CcBackgroundItem *
get_current_background (CcBackgroundPanel *panel, GSettings *settings)
{
if (settings == panel->settings)
return panel->current_background;
else
return panel->current_lock_background;
}
static void
update_preview (CcBackgroundPanel *panel,
GSettings *settings,
CcBackgroundItem *item)
{
gboolean changes_with_time;
CcBackgroundItem *current_background;
current_background = get_current_background (panel, settings);
if (item && current_background)
{
g_object_unref (current_background);
current_background = cc_background_item_copy (item);
if (settings == panel->settings)
panel->current_background = current_background;
else
panel->current_lock_background = current_background;
cc_background_item_load (current_background, NULL);
}
changes_with_time = FALSE;
if (current_background)
{
changes_with_time = cc_background_item_changes_with_time (current_background);
}
if (settings == panel->settings)
{
gtk_widget_set_visible (WID ("slide_image"), changes_with_time);
gtk_widget_set_visible (WID ("slide-label"), changes_with_time);
gtk_widget_queue_draw (WID ("background-desktop-drawingarea"));
}
else
{
gtk_toggle_button_set_active (self->default_toggle, FALSE);
gtk_toggle_button_set_active (self->dark_toggle, FALSE);
gtk_widget_set_visible (WID ("slide_image1"), changes_with_time);
gtk_widget_set_visible (WID ("slide-label1"), changes_with_time);
gtk_widget_queue_draw (WID ("background-lock-drawingarea"));
}
}
static void
transition_screen (CcBackgroundPanel *self)
{
g_autoptr (GError) error = NULL;
if (!self->proxy)
return;
g_dbus_proxy_call_sync (self->proxy,
"ScreenTransition",
NULL,
G_DBUS_CALL_FLAGS_NONE,
-1,
NULL,
&error);
if (error)
g_warning ("Couldn't transition screen: %s", error->message);
}
static void
set_color_scheme (CcBackgroundPanel *self,
GDesktopColorScheme color_scheme)
{
GDesktopColorScheme scheme;
scheme = g_settings_get_enum (self->interface_settings,
INTERFACE_COLOR_SCHEME_KEY);
/* We have to check the equality manually to avoid starting an unnecessary
* screen transition */
if (color_scheme == scheme)
return;
transition_screen (self);
g_settings_set_enum (self->interface_settings,
INTERFACE_COLOR_SCHEME_KEY,
color_scheme);
}
/* Color schemes */
static void
on_color_scheme_toggle_active_cb (CcBackgroundPanel *self)
{
if (gtk_toggle_button_get_active (self->default_toggle))
set_color_scheme (self, G_DESKTOP_COLOR_SCHEME_DEFAULT);
else if (gtk_toggle_button_get_active (self->dark_toggle))
set_color_scheme (self, G_DESKTOP_COLOR_SCHEME_PREFER_DARK);
}
static void
got_transition_proxy_cb (GObject *source_object,
GAsyncResult *res,
gpointer data)
{
g_autoptr(GError) error = NULL;
CcBackgroundPanel *self = data;
self->proxy = g_dbus_proxy_new_for_bus_finish (res, &error);
if (self->proxy == NULL)
{
g_warning ("Error creating proxy: %s", error->message);
return;
}
}
/* Background */
static void
update_preview (CcBackgroundPanel *self)
{
CcBackgroundItem *current_background;
current_background = self->current_background;
cc_background_preview_set_item (self->default_preview, current_background);
cc_background_preview_set_item (self->dark_preview, current_background);
}
static gchar *
get_save_path (void)
get_save_path (CcBackgroundPanel *panel, GSettings *settings)
{
return g_build_filename (g_get_user_config_dir (),
"gnome-control-center",
"backgrounds",
"last-edited.xml",
settings == panel->settings ? "last-edited.xml" : "last-edited-lock.xml",
NULL);
}
static GdkPixbuf*
get_or_create_cached_pixbuf (CcBackgroundPanel *panel,
GtkWidget *widget,
CcBackgroundItem *background)
{
GtkAllocation allocation;
const gint preview_width = 309;
const gint preview_height = 168;
gint scale_factor;
GdkPixbuf *pixbuf;
pixbuf = g_object_get_data (G_OBJECT (background), "pixbuf");
if (pixbuf == NULL)
{
gtk_widget_get_allocation (widget, &allocation);
scale_factor = gtk_widget_get_scale_factor (widget);
pixbuf = cc_background_item_get_frame_thumbnail (background,
panel->thumb_factory,
preview_width,
preview_height,
scale_factor,
-2, TRUE);
g_object_set_data_full (G_OBJECT (background), "pixbuf", pixbuf, g_object_unref);
}
return pixbuf;
}
static void
reload_current_bg (CcBackgroundPanel *self)
update_display_preview (CcBackgroundPanel *panel,
GtkWidget *widget,
CcBackgroundItem *background)
{
GdkPixbuf *pixbuf;
cairo_t *cr;
pixbuf = get_or_create_cached_pixbuf (panel, widget, background);
cr = gdk_cairo_create (gtk_widget_get_window (widget));
gdk_cairo_set_source_pixbuf (cr,
pixbuf,
0, 0);
cairo_paint (cr);
cairo_destroy (cr);
}
static gboolean
on_preview_draw (GtkWidget *widget,
cairo_t *cr,
CcBackgroundPanel *panel)
{
update_display_preview (panel, widget, panel->current_background);
return TRUE;
}
static gboolean
on_lock_preview_draw (GtkWidget *widget,
cairo_t *cr,
CcBackgroundPanel *panel)
{
update_display_preview (panel, widget, panel->current_lock_background);
return TRUE;
}
static void
reload_current_bg (CcBackgroundPanel *panel,
GSettings *settings)
{
g_autoptr(CcBackgroundItem) saved = NULL;
CcBackgroundItem *configured;
GSettings *settings = NULL;
g_autofree gchar *uri = NULL;
g_autofree gchar *dark_uri = NULL;
g_autofree gchar *pcolor = NULL;
g_autofree gchar *scolor = NULL;
/* Load the saved configuration */
uri = get_save_path ();
uri = get_save_path (panel, settings);
saved = cc_background_xml_get_item (uri);
/* initalise the current background information from settings */
settings = self->settings;
uri = g_settings_get_string (settings, WP_URI_KEY);
if (uri && *uri == '\0')
g_clear_pointer (&uri, g_free);
{
g_clear_pointer (&uri, g_free);
}
else
{
g_autoptr(GFile) file = NULL;
file = g_file_new_for_commandline_arg (uri);
}
configured = cc_background_item_new (uri);
dark_uri = g_settings_get_string (settings, WP_URI_DARK_KEY);
pcolor = g_settings_get_string (settings, WP_PCOLOR_KEY);
scolor = g_settings_get_string (settings, WP_SCOLOR_KEY);
g_object_set (G_OBJECT (configured),
"name", _("Current background"),
"uri-dark", dark_uri,
"placement", g_settings_get_enum (settings, WP_OPTIONS_KEY),
"shading", g_settings_get_enum (settings, WP_SHADING_KEY),
"primary-color", pcolor,
@@ -246,8 +310,16 @@ reload_current_bg (CcBackgroundPanel *self)
NULL);
}
g_clear_object (&self->current_background);
self->current_background = configured;
if (settings == panel->settings)
{
g_clear_object (&panel->current_background);
panel->current_background = configured;
}
else
{
g_clear_object (&panel->current_lock_background);
panel->current_lock_background = configured;
}
cc_background_item_load (configured, NULL);
}
@@ -269,63 +341,64 @@ create_save_dir (void)
}
static void
reset_settings_if_defaults (CcBackgroundPanel *self,
GSettings *settings,
gboolean check_dark)
copy_finished_cb (GObject *source_object,
GAsyncResult *result,
gpointer pointer)
{
gsize i;
const char *keys[] = {
WP_URI_KEY, /* this key needs to be first */
WP_URI_DARK_KEY,
WP_OPTIONS_KEY,
WP_SHADING_KEY,
WP_PCOLOR_KEY,
WP_SCOLOR_KEY,
NULL
};
g_autoptr(GError) err = NULL;
g_autoptr(CcBackgroundPanel) panel = (CcBackgroundPanel *) pointer;
CcBackgroundItem *item;
CcBackgroundItem *current_background;
GSettings *settings;
for (i = 0; keys[i] != NULL; i++)
if (!g_file_copy_finish (G_FILE (source_object), result, &err))
{
g_autoptr (GVariant) default_value = NULL;
g_autoptr (GVariant) user_value = NULL;
gboolean setting_is_default;
if (!check_dark && g_str_equal (keys[i], WP_URI_DARK_KEY))
continue;
default_value = g_settings_get_default_value (settings, keys[i]);
user_value = g_settings_get_value (settings, keys[i]);
setting_is_default = g_variant_equal (default_value, user_value);
/* As a courtesy to distros that are a little lackadaisical about making sure
* schema defaults match the settings in the background item with the default
* picture, we only look at the URI to determine if we shouldn't clean out dconf.
*
* In otherwords, we still clean out the picture-uri key from dconf when a user
* selects the default background in control-center, even if after selecting it
* e.g., primary-color still mismatches with schema defaults.
*/
if (g_str_equal (keys[i], WP_URI_KEY) && !setting_is_default)
if (g_error_matches (err, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
return;
if (setting_is_default)
g_settings_reset (settings, keys[i]);
}
g_warning ("Failed to copy image to cache location: %s", err->message);
}
item = g_object_get_data (source_object, "item");
settings = g_object_get_data (source_object, "settings");
current_background = get_current_background (panel, settings);
g_settings_apply (settings);
/* the panel may have been destroyed before the callback is run, so be sure
* to check the widgets are not NULL */
if (panel->spinner)
{
gtk_widget_destroy (GTK_WIDGET (panel->spinner));
panel->spinner = NULL;
}
if (current_background)
cc_background_item_load (current_background, NULL);
if (panel->builder)
{
g_autofree gchar *filename = NULL;
update_preview (panel, settings, item);
current_background = get_current_background (panel, settings);
/* Save the source XML if there is one */
filename = get_save_path (panel, settings);
if (create_save_dir ())
cc_background_xml_save (current_background, filename);
}
}
static void
set_background (CcBackgroundPanel *self,
set_background (CcBackgroundPanel *panel,
GSettings *settings,
CcBackgroundItem *item,
gboolean set_dark)
CcBackgroundItem *item)
{
GDesktopBackgroundStyle style;
CcBackgroundItemFlags flags;
g_autofree gchar *filename = NULL;
gboolean save_settings = TRUE;
const char *uri;
CcBackgroundItemFlags flags;
if (item == NULL)
return;
@@ -333,18 +406,85 @@ set_background (CcBackgroundPanel *self,
uri = cc_background_item_get_uri (item);
flags = cc_background_item_get_flags (item);
g_settings_set_string (settings, WP_URI_KEY, uri);
if (set_dark)
if ((flags & CC_BACKGROUND_ITEM_HAS_URI) && uri == NULL)
{
const char *uri_dark;
g_settings_set_enum (settings, WP_OPTIONS_KEY, G_DESKTOP_BACKGROUND_STYLE_NONE);
g_settings_set_string (settings, WP_URI_KEY, "");
}
else if (cc_background_item_get_source_url (item) != NULL &&
cc_background_item_get_needs_download (item))
{
g_autoptr(GFile) source = NULL;
g_autoptr(GFile) dest = NULL;
g_autofree gchar *cache_path = NULL;
g_autofree gchar *basename = NULL;
g_autofree gchar *display_name = NULL;
g_autofree gchar *dest_path = NULL;
g_autofree gchar *dest_uri = NULL;
g_autoptr(GdkPixbuf) pixbuf = NULL;
uri_dark = cc_background_item_get_uri_dark (item);
cache_path = bg_pictures_source_get_cache_path ();
if (g_mkdir_with_parents (cache_path, USER_DIR_MODE) < 0)
{
g_warning ("Failed to create directory '%s'", cache_path);
return;
}
if (uri_dark && uri_dark[0])
g_settings_set_string (settings, WP_URI_DARK_KEY, uri_dark);
else
g_settings_set_string (settings, WP_URI_DARK_KEY, uri);
dest_path = bg_pictures_source_get_unique_path (cc_background_item_get_source_url (item));
dest = g_file_new_for_path (dest_path);
source = g_file_new_for_uri (cc_background_item_get_source_url (item));
basename = g_file_get_basename (source);
display_name = g_filename_display_name (basename);
dest_path = g_file_get_path (dest);
/* create a blank image to use until the source image is ready */
pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, 1, 1);
gdk_pixbuf_fill (pixbuf, 0x00000000);
gdk_pixbuf_save (pixbuf, dest_path, "png", NULL, NULL);
if (panel->copy_cancellable)
{
g_cancellable_cancel (panel->copy_cancellable);
g_cancellable_reset (panel->copy_cancellable);
}
if (panel->spinner)
{
gtk_widget_destroy (GTK_WIDGET (panel->spinner));
panel->spinner = NULL;
}
/* create a spinner while the file downloads */
panel->spinner = gtk_spinner_new ();
gtk_spinner_start (GTK_SPINNER (panel->spinner));
gtk_box_pack_start (GTK_BOX (WID ("bottom-hbox")), panel->spinner, FALSE,
FALSE, 6);
gtk_widget_show (panel->spinner);
/* reference the panel in case it is removed before the copy is
* finished */
g_object_ref (panel);
g_object_set_data_full (G_OBJECT (source), "item", g_object_ref (item), g_object_unref);
g_object_set_data (G_OBJECT (source), "settings", settings);
g_file_copy_async (source, dest, G_FILE_COPY_OVERWRITE,
G_PRIORITY_DEFAULT, panel->copy_cancellable,
NULL, NULL,
copy_finished_cb, panel);
dest_uri = g_file_get_uri (dest);
g_settings_set_string (settings, WP_URI_KEY, dest_uri);
g_object_set (G_OBJECT (item),
"uri", dest_uri,
"needs-download", FALSE,
"name", display_name,
NULL);
/* delay the updated drawing of the preview until the copy finishes */
save_settings = FALSE;
}
else
{
g_settings_set_string (settings, WP_URI_KEY, uri);
}
/* Also set the placement if we have a URI and the previous value was none */
@@ -365,138 +505,131 @@ set_background (CcBackgroundPanel *self,
g_settings_set_string (settings, WP_PCOLOR_KEY, cc_background_item_get_pcolor (item));
g_settings_set_string (settings, WP_SCOLOR_KEY, cc_background_item_get_scolor (item));
/* Apply all changes */
g_settings_apply (settings);
/* update the preview information */
if (save_settings != FALSE)
{
g_autofree gchar *filename = NULL;
/* Clean out dconf if the user went back to distro defaults */
reset_settings_if_defaults (self, settings, set_dark);
/* Apply all changes */
g_settings_apply (settings);
/* Save the source XML if there is one */
filename = get_save_path ();
if (create_save_dir ())
cc_background_xml_save (self->current_background, filename);
/* Save the source XML if there is one */
filename = get_save_path (panel, settings);
if (create_save_dir ())
cc_background_xml_save (get_current_background (panel, settings), filename);
}
}
static void
on_chooser_background_chosen_cb (CcBackgroundPanel *self,
CcBackgroundItem *item)
on_chooser_dialog_response (GtkDialog *dialog,
int response_id,
CcBackgroundPanel *panel)
{
set_background (self, self->settings, item, TRUE);
set_background (self, self->lock_settings, item, FALSE);
if (response_id == GTK_RESPONSE_OK)
{
g_autoptr(CcBackgroundItem) item = NULL;
item = cc_background_chooser_dialog_get_item (CC_BACKGROUND_CHOOSER_DIALOG (dialog));
if (item != NULL)
set_background (panel, g_object_get_data (G_OBJECT (dialog), "settings"), item);
}
gtk_widget_destroy (GTK_WIDGET (dialog));
}
static void
on_add_picture_button_clicked_cb (CcBackgroundPanel *self)
launch_chooser (CcBackgroundPanel *panel,
GSettings *settings)
{
cc_background_chooser_select_file (self->background_chooser);
}
GtkWidget *dialog;
static const char *
cc_background_panel_get_help_uri (CcPanel *panel)
{
return "help:gnome-help/look-background";
dialog = cc_background_chooser_dialog_new (GTK_WINDOW (gtk_widget_get_toplevel (WID ("background-panel"))));
g_object_set_data (G_OBJECT (dialog), "settings", settings);
gtk_widget_show (dialog);
g_signal_connect (dialog, "response", G_CALLBACK (on_chooser_dialog_response), panel);
panel->chooser = dialog;
g_object_add_weak_pointer (G_OBJECT (dialog), (gpointer *) &panel->chooser);
}
static void
cc_background_panel_dispose (GObject *object)
on_background_button_clicked (GtkButton *button,
CcBackgroundPanel *panel)
{
CcBackgroundPanel *self = CC_BACKGROUND_PANEL (object);
g_clear_object (&self->settings);
g_clear_object (&self->lock_settings);
g_clear_object (&self->interface_settings);
g_clear_object (&self->proxy);
G_OBJECT_CLASS (cc_background_panel_parent_class)->dispose (object);
launch_chooser (panel, panel->settings);
}
static void
cc_background_panel_finalize (GObject *object)
on_lock_button_clicked (GtkButton *button,
CcBackgroundPanel *panel)
{
CcBackgroundPanel *self = CC_BACKGROUND_PANEL (object);
g_clear_object (&self->current_background);
G_OBJECT_CLASS (cc_background_panel_parent_class)->finalize (object);
launch_chooser (panel, panel->lock_settings);
}
static void
cc_background_panel_class_init (CcBackgroundPanelClass *klass)
on_settings_changed (GSettings *settings,
gchar *key,
CcBackgroundPanel *panel)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
CcPanelClass *panel_class = CC_PANEL_CLASS (klass);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
g_type_ensure (CC_TYPE_BACKGROUND_CHOOSER);
g_type_ensure (CC_TYPE_BACKGROUND_PREVIEW);
panel_class->get_help_uri = cc_background_panel_get_help_uri;
object_class->dispose = cc_background_panel_dispose;
object_class->finalize = cc_background_panel_finalize;
gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/control-center/background/cc-background-panel.ui");
gtk_widget_class_bind_template_child (widget_class, CcBackgroundPanel, background_chooser);
gtk_widget_class_bind_template_child (widget_class, CcBackgroundPanel, default_preview);
gtk_widget_class_bind_template_child (widget_class, CcBackgroundPanel, dark_preview);
gtk_widget_class_bind_template_child (widget_class, CcBackgroundPanel, default_toggle);
gtk_widget_class_bind_template_child (widget_class, CcBackgroundPanel, dark_toggle);
gtk_widget_class_bind_template_callback (widget_class, on_color_scheme_toggle_active_cb);
gtk_widget_class_bind_template_callback (widget_class, on_chooser_background_chosen_cb);
gtk_widget_class_bind_template_callback (widget_class, on_add_picture_button_clicked_cb);
reload_current_bg (panel, settings);
update_preview (panel, settings, NULL);
}
static void
on_settings_changed (CcBackgroundPanel *self)
cc_background_panel_init (CcBackgroundPanel *panel)
{
reload_current_bg (self);
update_preview (self);
}
gchar *objects[] = {"background-panel", NULL };
g_autoptr(GError) err = NULL;
GtkWidget *widget;
static void
cc_background_panel_init (CcBackgroundPanel *self)
{
panel->connection = g_application_get_dbus_connection (g_application_get_default ());
g_resources_register (cc_background_get_resource ());
gtk_widget_init_template (GTK_WIDGET (self));
panel->builder = gtk_builder_new ();
gtk_builder_add_objects_from_resource (panel->builder,
"/org/gnome/control-center/background/background.ui",
objects, &err);
self->connection = g_application_get_dbus_connection (g_application_get_default ());
if (err)
{
g_warning ("Could not load ui: %s", err->message);
return;
}
self->settings = g_settings_new (WP_PATH_ID);
g_settings_delay (self->settings);
self->lock_settings = g_settings_new (WP_LOCK_PATH_ID);
g_settings_delay (self->lock_settings);
panel->settings = g_settings_new (WP_PATH_ID);
g_settings_delay (panel->settings);
self->interface_settings = g_settings_new (INTERFACE_PATH_ID);
panel->lock_settings = g_settings_new (WP_LOCK_PATH_ID);
g_settings_delay (panel->lock_settings);
/* Load the background */
reload_current_bg (self);
update_preview (self);
/* add the top level widget */
widget = WID ("background-panel");
gtk_container_add (GTK_CONTAINER (panel), widget);
gtk_widget_show_all (GTK_WIDGET (panel));
/* setup preview area */
widget = WID ("background-desktop-drawingarea");
g_signal_connect (widget, "draw", G_CALLBACK (on_preview_draw), panel);
widget = WID ("background-lock-drawingarea");
g_signal_connect (widget, "draw", G_CALLBACK (on_lock_preview_draw), panel);
panel->copy_cancellable = g_cancellable_new ();
panel->thumb_factory = gnome_desktop_thumbnail_factory_new (GNOME_DESKTOP_THUMBNAIL_SIZE_LARGE);
/* Load the backgrounds */
reload_current_bg (panel, panel->settings);
update_preview (panel, panel->settings, NULL);
reload_current_bg (panel, panel->lock_settings);
update_preview (panel, panel->lock_settings, NULL);
/* Background settings */
g_signal_connect_object (self->settings, "changed", G_CALLBACK (on_settings_changed), self, G_CONNECT_SWAPPED);
g_signal_connect (panel->settings, "changed", G_CALLBACK (on_settings_changed), panel);
g_signal_connect (panel->lock_settings, "changed", G_CALLBACK (on_settings_changed), panel);
/* Interface settings */
reload_color_scheme_toggles (self);
g_signal_connect_object (self->interface_settings,
"changed::" INTERFACE_COLOR_SCHEME_KEY,
G_CALLBACK (reload_color_scheme_toggles),
self,
G_CONNECT_SWAPPED);
g_dbus_proxy_new_for_bus (G_BUS_TYPE_SESSION,
G_DBUS_PROXY_FLAGS_NONE,
NULL,
"org.gnome.Shell",
"/org/gnome/Shell",
"org.gnome.Shell",
NULL,
got_transition_proxy_cb,
self);
load_custom_css (self);
/* Background buttons */
widget = WID ("background-set-button");
g_signal_connect (widget, "clicked", G_CALLBACK (on_background_button_clicked), panel);
widget = WID ("background-lock-set-button");
g_signal_connect (widget, "clicked", G_CALLBACK (on_lock_button_clicked), panel);
}

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