Compare commits

..

50 Commits
43.0 ... 40.9

Author SHA1 Message Date
Robert Ancell
735980860b 40.9 2022-02-14 11:18:34 +13:00
Boyuan Yang
6a9742986f Update Chinese (China) translation 2022-02-07 20:44:17 +00:00
Hui Wang
c95b557f3f sound: update the volume-slider after getting a valid stream
In the ubuntu 20.04, we met an issue about the output volume-slider
on the machine with the legacy HDA audio driver, the output device
is the Speaker first (analog-stereo pa sink), then we connect a hdmi
monitor, the HDMI audio is in the output combo-box, we select the
hdmi audio (hdmi-stereo pa sink) from the combo-box, the hdmi audio
becomes the active output device now, we adjust the output volume from
the volume-slider, the slider UI is changed, but the output sound
is not changed with the UI.

The root cause is when the speaker is active, the pulseaudio only
keeps the analog-stereo sink, the sink hdmi-stereo is unlinked, when
users select the hdmi audio from UI, the pulseaudio will unlink
analo-stereo sink and create hdmi-stereo sink, but before hdmi-stereo
is created, the output_device_changed_cb() is called and
gvc_mixer_control_get_stream_from_device() returns a NULL since the
hdmi-stereo sink is not created yet in the pulseaudio. Because stream
is NULL, the output_volume_slider->stream is NULL, users can't change
the output volume via the volume-slider.

To fix it, we add a output_volume_slider->stream check in the
device_update_cb(), if it is NULL, get the stream and set it to
volume-slider. In this function, the sink hdmi-stereo is created
already, so the stream is not NULL. And this change also applies to
input as well.

Signed-off-by: Hui Wang <hui.wang@canonical.com>
2022-01-31 12:32:26 +13:00
Hui Wang
3d23aa2d13 sound: clear the value on level_bar when stream is empty
We met an Input Device level_bar display issue on a machine which has
no internal mic. At first there is no external mic plugged, so the
Input Device list is empty and level_bar is gray color, after we plug
an external mic, the level_bar has red color ripples, then we unplug
the external mic, the Input Device list changes to empty and we
expect the level_bar changes back to gray color, but some bars are
still red color.

Here clear the self->value to 0 if the stream is empty, then the
level_bar will change back to gray color when Input/Output device
list is empty.

Signed-off-by: Hui Wang <hui.wang@canonical.com>
2022-01-31 12:25:38 +13:00
Jan Beich
740959f161 meson: drop unused argument for i18n.merge_file()
Ignored in Meson < 0.60.0, deprecated since 0.60.1 and fatal since 0.61.0.

panels/applications/meson.build:10:5: ERROR: Function does not take positional arguments.
panels/background/meson.build:10:5: ERROR: Function does not take positional arguments.
panels/camera/meson.build:10:5: ERROR: Function does not take positional arguments.
[...]
2022-01-31 12:25:33 +13:00
Robert Mader
aadf89b442 display-config: Do not invert order when constructing modes
Mutter sends modes in descending order of preference. By reverting
the order via `g_list_prepend`, we get unintended side effects
such as choosing the least preferred refresh rate by default (if
the selected mode is not marked as preferred).

Instead of adding complex logic in several places, make sure that
the assumption of descending preference is kept by simply not
inverting the order.

Closes https://gitlab.gnome.org/GNOME/gnome-control-center/-/issues/1562

(cherry picked from commit 6a4652bd35)
2022-01-05 23:27:21 +01:00
Robert Ancell
90cf8afd25 Post-release version bump 2021-12-03 15:58:30 +13:00
Robert Ancell
aa721dc9ac 40.7 2021-12-03 15:51:59 +13:00
Rafael Fontenelle
3c06c2e199 Update Brazilian Portuguese translation 2021-11-23 07:31:20 +00:00
Rafael Fontenelle
47fed006d7 Update Brazilian Portuguese translation 2021-11-03 17:27:19 +00:00
Robert Ancell
3ba0e1253b Post-release version bump 2021-10-29 16:41:09 +13:00
Robert Ancell
d3929cf3ed 40.6 2021-10-29 16:37:58 +13:00
Christian Kirbach
825a5b485b Update German translation 2021-09-22 20:30:31 +00:00
Georges Basile Stavracas Neto
d95957068b Post-release version bump 2021-09-17 18:36:42 -03:00
Georges Basile Stavracas Neto
32d3bb2d18 40.1 2021-09-17 18:33:59 -03:00
Jordan Petridis
b771b2dad8 ci: Use different images for the stable branch 2021-09-17 21:19:39 +00:00
Jordan Petridis
7f2ffcca2f ci: Refactor ci-template setup
Instead of building the image on a schedule, use a user-incrementable
tag and try to build the image on each pipeline.

If the image tag does not exist, a new one is built and pushed.
If its already built the job is a no-op and the existing image
is used.
2021-09-17 21:19:39 +00:00
Jordi Mas
a35e4aa214 Update Catalan translation 2021-09-06 22:03:03 +02:00
Jordi Mas
5a985d85a8 Update Catalan translation 2021-09-06 21:59:05 +02:00
Jordi Mas
9ced38ea65 Update Catalan translation 2021-08-30 20:58:45 +02:00
Maxim Britov
d9ea855408 panels: Fix build with NetworkManager disabled
Gentoo allows the user to disable NetworkManager integration at build time.
We use the existing HAVE_NETWORK_MANAGER preprocessor macro to guard
the uses of the mobile_switch_changed_cb and wifi_switch_changed_cb
functions that guard their definitions.

Bug: https://bugs.gentoo.org/783144
Closes: #1335
2021-07-28 15:03:14 +00:00
Bastien Nocera
022934bfb3 power: Fix D-Bus proxy leak 2021-07-21 12:28:16 +02:00
Ian Douglas Scott
ef683cafc0 location: Fix permission store table/id
Updates to match
https://gitlab.gnome.org/GNOME/gnome-shell/-/blob/master/js/ui/status/location.js

Should fix
https://gitlab.gnome.org/GNOME/gnome-control-center/-/issues/885.


(cherry picked from commit 996e46c620)
2021-07-02 19:27:04 +00:00
Quentin PAGÈS
6a61f969ac Update Occitan translation 2021-06-19 10:33:26 +00:00
Quentin PAGÈS
fa3afbf370 Update Occitan translation 2021-06-18 20:37:50 +00:00
Dušan Kazik
e480efa58e Update Slovak translation 2021-06-14 06:42:30 +00:00
Dušan Kazik
d8caedd80e Update Slovak translation 2021-06-11 06:28:44 +00:00
Marco Trevisan (Treviño)
daabfb5a8c build: Depend on gsettings-desktop-schemas 40
g-c-c requires now org.gnome.desktop.peripherals schemas that have been
added on schemas 40.alpha, so let's depend on that.


(cherry picked from commit ed46af7f24)
2021-06-07 21:33:30 +00:00
Cheng-Chia Tseng
c30358bea1 Update Chinese (Taiwan) translation 2021-06-03 01:51:07 +00:00
Quentin PAGÈS
cc75d32c62 Update Occitan translation 2021-05-30 10:23:34 +00:00
Jiri Grönroos
f2e1dfd161 Update Finnish translation 2021-05-26 06:51:09 +00:00
Philipp Kiemle
3bfc5f71d0 Update German translation 2021-05-22 20:58:56 +00:00
Ngọc Quân Trần
83f774f9ea Update Vietnamese translation 2021-05-22 01:34:45 +00:00
treysis
37bd61ccd6 network: display IPv6 gateway 2021-05-19 15:17:37 +12:00
treysis
db7c2b2cc5 Network: Show all IPv6 addresses for an interface
Fixes https://gitlab.gnome.org/GNOME/gnome-control-center/-/issues/1300
2021-05-19 15:16:56 +12:00
Hugo Carvalho
ac3839d0c9 Update Portuguese translation 2021-05-15 15:45:42 +00:00
Hugo Carvalho
5650a5f5c7 Update Portuguese translation 2021-05-14 12:10:20 +00:00
Hugo Carvalho
dfbeace734 Update Portuguese translation 2021-05-13 11:01:12 +00:00
Aurimas Černius
7c6e4d4174 Updated Lithuanian translation 2021-05-10 22:12:14 +03:00
Quentin PAGÈS
753ba80b3b Update Occitan translation 2021-05-09 19:26:07 +00:00
Daniel Șerbănescu
3e9d08287c Update Romanian translation 2021-05-08 21:25:27 +00:00
Pawan Chitrakar
815ed9169d Update Nepali translation 2021-05-01 13:04:42 +00:00
Pawan Chitrakar
c4a91dc613 Update Nepali translation 2021-05-01 04:45:44 +00:00
Pawan Chitrakar
7c04266599 Update Nepali translation 2021-04-23 17:41:48 +00:00
Hugo Carvalho
cdd1118add Update Portuguese translation 2021-04-23 14:10:18 +00:00
Carlos Garnacho
bd23f743d3 shell: Avoid handling map events from other windows
The CcWindow tries to unset the focus when first mapping the window.
However this pretty wide check intercepts mapping events from other
windows than the toplevel (e.g. subsurfaces, for popovers). This
causes the focus to move away from the popover, overriding its
modality.

Check that the event received is addressed to the CcWindow's
GDK window before unsetting the focus, so we don't mess with popover
focus.

Fixes: https://gitlab.gnome.org/GNOME/gnome-control-center/-/issues/1327


(cherry picked from commit 7196e8aaea)
2021-04-21 20:37:42 +00:00
Hugo Carvalho
0da2ef8b0b Update Portuguese translation 2021-04-15 09:59:46 +00:00
Hugo Carvalho
b5f191894c Update Portuguese translation 2021-04-14 17:57:27 +00:00
Kalev Lember
4c52d5b646 info-overview: Don't show GNOME micro version
With the new versioning scheme, GNOME just has major.minor versions
(e.g. 40.rc, 40.0) and micro versions are no longer used. Even if
gnome-desktop happens to get a micro version to fix a bug, it's not
something we should show in the UI.


(cherry picked from commit a64bb833ee)
2021-04-13 12:59:32 +00:00
Felipe Borges
44ee3e5fa2 mouse: Prevent direction change for primary mouse button box
In Right-to-left locales GNOME Settings presents a button on the
left with the translated label "Right" and a button on the right
with the translated label "Left".

These changes prevent the flip of the direction buttons in RTL
locales.

Fixes #1101
2021-04-13 13:41:14 +02:00
938 changed files with 209513 additions and 277086 deletions

View File

@@ -1,5 +1,5 @@
include:
- remote: 'https://gitlab.freedesktop.org/freedesktop/ci-templates/-/raw/34f4ade99434043f88e164933f570301fd18b125/templates/fedora.yml'
- remote: 'https://gitlab.freedesktop.org/freedesktop/ci-templates/-/raw/5888c7388134cbe4661600222fe9befb10441f6e/templates/fedora.yml'
variables:
FDO_UPSTREAM_REPO: gnome/gnome-control-center
@@ -40,11 +40,6 @@ stages:
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
@@ -52,8 +47,8 @@ stages:
# stable branch.
# Could probably also switch away from rawhide,
# to stable fedora branch as well.
FDO_DISTRIBUTION_TAG: '2022-03-29.0-main'
FDO_DISTRIBUTION_VERSION: rawhide
FDO_DISTRIBUTION_TAG: '2021-07-22.0-gnome-40'
FDO_DISTRIBUTION_VERSION: '34'
#############################################
# Create CI Docker Images #
@@ -92,18 +87,16 @@ build.container.fedora@x86_64:
gnome-bluetooth-libs-devel
gnome-desktop3-devel
gnome-online-accounts-devel
gnome-settings-daemon-devel
grilo-devel
gsettings-desktop-schemas-devel
gsound-devel
gtk3-devel ibus-devel
gtk4-devel
intltool
libadwaita-devel
libcanberra-devel
libgtop2-devel
libgudev-devel
libnma-devel
libnotify-devel
libpwquality-devel
libsmbclient-devel
libsoup-devel
@@ -122,56 +115,12 @@ build.container.fedora@x86_64:
xorg-x11-server-Xvfb
mesa-dri-drivers
libsecret-devel
geocode-glib-devel
libgweather-devel
lcms2-devel
geoclue2-devel
libnotify-devel
alsa-lib-devel
nss-devel
gcr-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 ..
##
@@ -222,7 +171,6 @@ test:
- build
script:
- dnf -y install setxkbmap
- *environment_information
- *run_tests
@@ -248,7 +196,7 @@ coverage:
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
@@ -288,7 +236,7 @@ pages:
paths:
- public
only:
- main@GNOME/gnome-control-center
- master@GNOME/gnome-control-center
except:
variables:
@@ -302,7 +250,7 @@ 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:
@@ -354,7 +302,7 @@ flatpak:
except:
- tags
- gnome-3-.*
- main@GNOME/gnome-control-center
- master@GNOME/gnome-control-center
# Runs the sanitizers [address, thread, undefined, and memory].
@@ -375,19 +323,18 @@ flatpak:
- $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:
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"
tsan:
extends:

View File

@@ -4,7 +4,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/CONTRIBUTING.md#communication-guideline
[1] https://gitlab.gnome.org/GNOME/gnome-control-center/blob/master/docs/CONTRIBUTING.md#communication-guideline
-->

View File

@@ -4,7 +4,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/CONTRIBUTING.md#communication-guideline
[1] https://gitlab.gnome.org/GNOME/gnome-control-center/blob/master/docs/CONTRIBUTING.md#communication-guideline
-->

3
.gitmodules vendored
View File

@@ -1,3 +1,6 @@
[submodule "subprojects/gvc"]
path = subprojects/gvc
url = https://gitlab.gnome.org/GNOME/libgnome-volume-control.git
[submodule "subprojects/libhandy"]
path = subprojects/libhandy
url = https://gitlab.gnome.org/GNOME/libhandy.git

222
NEWS
View File

@@ -1,239 +1,47 @@
================
Version 43.0
Version 40.9
================
- Drop unused argument for i18n.merge_file() in Meson rules
- Updated translations
================
Version 43.rc
================
- Fix initial AM/PM label value
- Remove no longer used icon
- Select panel only if non-folded when search is canceled
- Updated translations
Appearance
- Allow backgrounds to use any image format
Device Security
- Several UI improvements
Display
- Fix primary monitor selection
Info
- Improve dark theme support
Keyboard
- Fix activation of input source toggle button
- Improve handling of Shift shortcuts
Power
- Fix blank screen and power button behavior settings
Printers
- Show empty state after removing last printer
Search
- Fix Move Up and Move Down actions
- Do not invert order when constructing modes
Sound
- Fix sound alert selection
Wacom
- Better support Wacom Express Key Remote
- Update the volume-slider after getting a valid stream
- Clear level bar when stream is empty
================
Version 43.beta
Version 40.7
================
- Updated translations
Cellular
- Add WWAN 5G connection support
Device Security
- Polish failure messages
- Various style updates
Display
- Support privacy screens
Info
- Show build id in a separate row
Network
- Fix VPN empty state
Sound
- Update default sounds
User Accounts
- Fix back button not appearing sometimes
================
Version 43.alpha
================
- Improved accessibility in various panels
- New Device Security panel
- Updated translations
Date & Time
- Update visual style of the timezone map
Display
- Various visual improvements
Sound
- Remove dog barking sounds
================
Version 42.1
Version 40.6
================
- Updated translations
Display
- Various small behavior improvements
- Fix monitor labels
Network
- Improve handling of VPN connections
Online Accounts
- Fix behavior of helper application on X11
- Fix changes to online accounts services not applying correctly
User Accounts
- Various small polishments
Wacom
- Properly translate various strings
================
Version 42.0
Version 40.1
================
- Updated AppData screenshots
- Re-enable tests
- Updated translations
================
Version 42.rc
================
- Updated translations
Keyboard
- Restore _GNOME_WM_KEYBINDINGS support
User Accounts
- Bring back Fingerprint dialog
- Fix avatar loading
Wacom
- Bring back empty state
================
Version 42.beta
================
- Port to GTK4
- Various UI polish changes
- New symbolic icons for panels
- Updated translations
Application
- Implement new design
Background
- Introduce dark & light mode selector
- Rename to Appearance
Display
- Implement new design
Region & Language
- Implement new design
User Accounts
- New design for the User Accounts panel
Wacom
- Implement new design
================
Version 41.0
================
- Cleanup the development Flatpak manifest
- Updated translations
User Accounts
- Add parental controls keywords
================
Version 41.rc1
================
- Updated translations
Cellular
- Various translation fixes
User Accounts
- Improve parental controls behavior
================
Version 41.beta
================
- Introduce the new Cellular panel
- Introduce the new Multitasking panel
- Updated translations
About
- Fix a crash due to uninitialized variables
Bluetooth
- Fix Bluetooth switch transitions
- Don't show GNOME micro version
Location
- Fix permission store id (again)
- Fix permission store table and id
Network
- Show all IPv6 addresses for an interface
- Display IPv6 gateway
Power
- Polish power profiles section
================
Version 41.alpha
================
- Improve and fix the development Flatpak manifest
- Drop dependency on grilo
- Updated translations
About
- Don't show GNOME micro version number
- Look for dark and text distro logo variants
Accessibility
- Add "Enable Animations" option
Location
- Fix permission store id
Mouse & Touchpad
- Update artwork
Online Accounts
- Present all online accounts providers at once
Power
- Integrate with new power profiles daemon API
- Show more information about power profiles
- Cleanup some preferences
- Fix D-Bus proxy leak
================
Version 40

View File

@@ -1,6 +1,6 @@
[![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/pipeline.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
====================
@@ -60,4 +60,4 @@ Note that GNOME Settings Flatpak will only work if you are running
the latest GNOME version in your host system.
[communication-guidelines]: https://gitlab.gnome.org/GNOME/gnome-control-center/blob/main/docs/CONTRIBUTING.md#communication-guidelines
[communication-guidelines]: https://gitlab.gnome.org/GNOME/gnome-control-center/blob/master/docs/CONTRIBUTING.md#communication-guidelines

View File

@@ -4,6 +4,7 @@
"runtime-version" : "master",
"sdk" : "org.gnome.Sdk",
"command" : "gnome-control-center",
"rename-desktop-file" : "gnome-control-center.desktop",
"tags" : [
"devel"
],
@@ -12,6 +13,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",
@@ -134,7 +136,7 @@
"sources" : [
{
"type" : "git",
"url" : "https://github.com/libusb/libusb.git"
"url" : "git://github.com/libusb/libusb.git"
}
]
},
@@ -149,8 +151,7 @@
"sources" : [
{
"type" : "git",
"url" : "https://github.com/hughsie/libgusb.git",
"branch" : "main"
"url" : "git://github.com/hughsie/libgusb.git"
}
]
},
@@ -182,7 +183,7 @@
"sources" : [
{
"type" : "git",
"url" : "https://github.com/gentoo/eudev.git"
"url" : "git://github.com/gentoo/eudev.git"
}
]
},
@@ -217,8 +218,7 @@
"sources" : [
{
"type" : "git",
"branch" : "main",
"url" : "https://github.com/hughsie/colord.git"
"url" : "git://github.com/hughsie/colord.git"
}
]
},
@@ -231,8 +231,7 @@
"sources" : [
{
"type" : "git",
"branch" : "main",
"url" : "https://github.com/hughsie/colord-gtk.git"
"url" : "git://github.com/hughsie/colord-gtk.git"
}
]
},
@@ -301,19 +300,19 @@
"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",
"buildsystem" : "autotools",
"config-opts" : [
"-Dsystemdsystemunitdir=/app/lib/systemd/system",
"-Dgtk-doc=false",
"-Dman=false",
"-Dintrospection=disabled"
"--prefix=/app",
"--with-systemdsystemunitdir=/app/lib/systemd/system",
"--disable-gtk-doc",
"--disable-man-pages",
"--disable-tests"
],
"sources" : [
{
@@ -324,11 +323,7 @@
},
{
"name" : "libwacom",
"buildsystem" : "meson",
"config-opts" : [
"-Ddocumentation=disabled",
"-Dtests=disabled"
],
"buildsystem" : "autotools",
"sources" : [
{
"type" : "git",
@@ -381,7 +376,6 @@
"sources" : [
{
"type" : "git",
"branch": "main",
"url" : "https://gitlab.freedesktop.org/NetworkManager/NetworkManager.git"
}
]
@@ -392,7 +386,6 @@
"sources" : [
{
"type" : "git",
"branch": "main",
"url" : "https://gitlab.gnome.org/GNOME/mobile-broadband-provider-info.git"
}
]
@@ -401,7 +394,6 @@
"name" : "libnma",
"buildsystem" : "meson",
"config-opts" : [
"-Dlibnma_gtk4=true",
"-Dgtk_doc=false",
"-Dintrospection=false",
"-Dvapi=false"
@@ -409,8 +401,7 @@
"sources" : [
{
"type" : "git",
"url" : "https://gitlab.gnome.org/GNOME/libnma.git",
"branch" : "main"
"url" : "https://gitlab.gnome.org/GNOME/libnma.git"
}
]
},
@@ -429,31 +420,25 @@
"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",
"-Dsystemdsystemunitdir=/app/lib/systemd/system",
"-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",
"--with-systemdsystemunitdir=/app/lib/systemd/system",
"--without-mbim",
"--without-qmi"
],
"sources" : [
{
"type" : "git",
"url" : "git://anongit.freedesktop.org/ModemManager/ModemManager",
"branch" : "main"
"url" : "git://anongit.freedesktop.org/ModemManager/ModemManager"
}
]
},
@@ -487,16 +472,6 @@
}
]
},
{
"name" : "gsound",
"buildsystem" : "meson",
"sources" : [
{
"type" : "git",
"url" : "https://gitlab.gnome.org/GNOME/gsound.git"
}
]
},
{
"name" : "gnome-bluetooth",
"buildsystem" : "meson",
@@ -510,6 +485,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",
@@ -518,9 +510,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"
}
]
},
@@ -560,28 +552,6 @@
}
]
},
{
"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",
@@ -590,17 +560,11 @@
"--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.11.0.tar.gz",
"sha256" : "6adf1c74afff1f3f7e14060cc5a36111a6721d644ea51ed1b22da46051e48e9c"
}
]
},
@@ -617,13 +581,207 @@
}
]
},
{
"name" : "cheese",
"buildsystem" : "meson",
"config-opts" : [
"-Dintrospection=false",
"-Dgtk_doc=false",
"-Dman=false"
],
"sources" : [
{
"type" : "git",
"url" : "https://gitlab.gnome.org/GNOME/cheese.git"
}
]
},
{
"name" : "libhandy",
"buildsystem" : "meson",
"config-opts" : [
"-Dexamples=false",
"-Dglade_catalog=disabled",
"-Dintrospection=disabled",
"-Dtests=false",
"-Dvapi=false"
],
"sources" : [
{
"type" : "git",
"url" : "https://gitlab.gnome.org/GNOME/libhandy.git"
}
]
},
{
"name" : "gsound",
"buildsystem" : "autotools",
"sources" : [
{
"type" : "git",
"url" : "https://gitlab.gnome.org/GNOME/gsound.git"
}
]
},
{
"name" : "libkmod",
"buildsystem" : "autotools",
"sources" : [
{
"type" : "archive",
"url" : "https://mirrors.edge.kernel.org/pub/linux/utils/kernel/kmod/kmod-25.tar.xz",
"sha256" : "7165e6496656159dcb909a91ed708a0fe273a4b128b4b1dc997ccb5189eef1cd"
}
]
},
{
"name" : "lvm2",
"buildsystem" : "autotools",
"config-opts" : [
"--prefix=/app",
"--enable-cmdlib",
"--enable-dmeventd",
"--enable-pkgconfig",
"--with-usrlibdir=/app/lib",
"--with-usrbindir=/app/bin",
"--with-staticdir=/app/bin"
],
"sources" : [
{
"type" : "archive",
"url" : "https://www.sourceware.org/pub/lvm2/LVM2.2.02.177.tgz",
"sha256" : "4025a23ec9b15c2cb7486d151c29dc953b75efc4d452cfe9dbbc7c0fac8e80f2"
}
],
"post-install" : [
"chmod 755 /app/sbin/dm*",
"chmod 755 /app/sbin/lvm*",
"chmod 755 /app/lib/libdevmapper-event-lvm2.so.2.02",
"chmod 755 /app/lib/libdevmapper-event-lvm2mirror.so",
"chmod 755 /app/lib/libdevmapper-event-lvm2raid.so",
"chmod 755 /app/lib/libdevmapper-event-lvm2snapshot.so",
"chmod 755 /app/lib/libdevmapper-event-lvm2thin.so",
"chmod 755 /app/lib/libdevmapper-event.so.1.02",
"chmod 755 /app/lib/libdevmapper.so.1.02",
"chmod 755 /app/lib/liblvm2cmd.so.2.02"
]
},
{
"name" : "parted",
"buildsystem" : "autotools",
"sources" : [
{
"type" : "archive",
"url" : "http://ftp.gnu.org/gnu/parted/parted-3.2.tar.xz",
"sha256" : "858b589c22297cacdf437f3baff6f04b333087521ab274f7ab677cb8c6bb78e4"
},
{
"type" : "patch",
"path" : "libparted-include.patch"
}
]
},
{
"name" : "mpfr",
"buildsystem" : "autotools",
"sources" : [
{
"type" : "archive",
"url" : "https://www.mpfr.org/mpfr-4.0.2/mpfr-4.0.2.tar.xz",
"sha256" : "1d3be708604eae0e42d578ba93b390c2a145f17743a744d8f3f8c2ad5855a38a"
}
]
},
{
"name" : "bytesize",
"buildsystem" : "autotools",
"config-opts" : [
"--with-gtk-doc=no"
],
"sources" : [
{
"type" : "git",
"url" : "https://github.com/storaged-project/libbytesize.git"
}
]
},
{
"name" : "cryptsetup",
"buildsystem" : "autotools",
"sources" : [
{
"type" : "archive",
"url" : "https://www.kernel.org/pub/linux/utils/cryptsetup/v1.7/cryptsetup-1.7.5.tar.xz",
"sha256" : "2b30cd1d0dd606a53ac77b406e1d37798d4b0762fa89de6ea546201906a251bd"
}
]
},
{
"name" : "swig",
"buildsystem" : "autotools",
"sources" : [
{
"type" : "git",
"url" : "https://github.com/swig/swig.git"
}
]
},
{
"name" : "volume-key",
"buildsystem" : "simple",
"build-commands" : [
"autoreconf -i",
"./configure --prefix=/app",
"make install"
],
"sources" : [
{
"type" : "archive",
"url" : "https://github.com/felixonmars/volume_key/archive/volume_key-0.3.11.tar.gz",
"sha256" : "92250506756eca19a0b6f50c16d3502eb5566ea4725645d7c5d87eb5cc8f3fd8"
}
]
},
{
"name" : "libblockdev",
"buildsystem" : "autotools",
"config-opts" : [
"--disable-tests",
"--with-btrfs=no",
"--with-dm=no",
"--with-gtk-doc=no",
"--with-kbd=no",
"--with-lvm=no",
"--with-lvm-dbus=no",
"--with-mpath=no",
"--with-nvdimm=no",
"--with-tools=no",
"--with-vdo=no"
],
"sources" : [
{
"type" : "git",
"url" : "https://github.com/storaged-project/libblockdev.git"
}
]
},
{
"name" : "atasmart",
"buildsystem" : "autotools",
"sources" : [
{
"type" : "archive",
"url" : "http://0pointer.de/public/libatasmart-0.19.tar.xz",
"sha256" : "61f0ea345f63d28ab2ff0dc352c22271661b66bf09642db3a4049ac9dbdb0f8d"
}
]
},
{
"name" : "udisks",
"buildsystem" : "autotools",
"config-opts" : [
"--disable-introspection",
"--disable-lvm2",
"--enable-daemon=no",
"--with-systemdsystemunitdir=/app/lib/systemd/system",
"--with-tmpfilesdir=/app/lib/tmpfiles.d"
],
@@ -640,7 +798,6 @@
"sources" : [
{
"type" : "git",
"branch": "main",
"url" : "https://gitlab.gnome.org/GNOME/gnome-backgrounds.git"
}
]

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

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

@@ -1,5 +1,13 @@
<?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">
<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>
<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"/>
<g fill="none">
<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" stroke="url(#a)" stroke-width="24" transform="matrix(1 0 0 1 -160 -172)"/>
<path d="m -58 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" stroke="#f6f5f4" stroke-width="20"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 3.5 KiB

After

Width:  |  Height:  |  Size: 4.1 KiB

View File

@@ -209,4 +209,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
[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

@@ -13,7 +13,7 @@
<category rdf:resource="http://api.gnome.org/doap-extensions#core" />
<programming-language>C</programming-language>
<!-- General, Multitasking -->
<!-- General -->
<maintainer>
<foaf:Person>
<foaf:name>Georges Basile Stavracas Neto</foaf:name>

View File

@@ -1,8 +1,8 @@
project(
'gnome-control-center', 'c',
version : '43.0',
version : '40.9',
license : 'GPL2+',
meson_version : '>= 0.57.0'
meson_version : '>= 0.53.0'
)
control_center_prefix = get_option('prefix')
@@ -50,17 +50,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',
@@ -110,28 +99,35 @@ libgvc = subproject(
)
libgvc_dep = libgvc.get_variable('libgvc_dep')
libhandy_dep = dependency('libhandy-1', version: '>= 1.0.0', required: false)
if not libhandy_dep.found()
libhandy = subproject(
'libhandy',
default_options: [
'examples=false',
'glade_catalog=disabled',
'introspection=disabled',
'tests=false',
'vapi=false',
]
)
libhandy_dep = libhandy.get_variable('libhandy_dep')
endif
goa_req_version = '>= 3.25.3'
pulse_req_version = '>= 2.0'
libadwaita_dep = dependency(
'libadwaita-1',
version: '>= 1.2.alpha',
fallback: ['libadwaita', 'libadwaita_dep'],
default_options: ['examples=false', 'introspection=disabled', 'tests=false', 'vapi=false'],
)
accounts_dep = dependency('accountsservice', version: '>= 0.6.39')
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.70.0')
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.56.0')
gnome_desktop_dep = dependency('gnome-desktop-3.0', version: '>= 3.33.4')
gnome_settings_dep = dependency('gnome-settings-daemon', version: '>= 3.27.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: '>= 40.alpha')
libxml_dep = dependency('libxml-2.0')
polkit_gobject_dep = dependency('polkit-gobject-1', version: '>= 0.114')
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')
@@ -139,8 +135,6 @@ gudev_dep = dependency('gudev-1.0', version: '>= 232')
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')
@@ -148,21 +142,12 @@ common_deps = [
gio_dep,
glib_dep,
gsettings_desktop_dep,
libadwaita_dep,
libhandy_dep,
dependency('gio-unix-2.0'),
dependency('gthread-2.0'),
dependency('gtk4', version: '>= 4.4'),
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')
@@ -187,6 +172,17 @@ 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
cheese_deps = [
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')
if enable_ibus
@@ -224,7 +220,7 @@ if host_is_linux
# network manager
network_manager_deps = [
dependency('libnm', version: '>= 1.24.0'),
dependency('libnma-gtk4', version: '>= 1.8.0'),
dependency('libnma', version: '>= 1.8.0'),
dependency('mm-glib', version: '>= 0.7')
]
endif
@@ -232,14 +228,10 @@ 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')
libwacom_dep = dependency('libwacom', version: '>= 0.7')
@@ -281,6 +273,7 @@ install_subdir(
top_inc = include_directories('.')
shell_inc = include_directories('shell')
subdir('build-aux')
subdir('data/icons')
subdir('po')
subdir('panels')
@@ -295,11 +288,6 @@ 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
@@ -319,6 +307,7 @@ summary({
}, section: 'Dependencies')
summary({
'Cheese': enable_cheese,
'IBus': enable_ibus,
'Snap': enable_snap,
'Malcontent': enable_malcontent,

View File

@@ -1,3 +1,4 @@
option('cheese', type: 'boolean', value: true, description: 'build with cheese webcam support')
option('documentation', type: 'boolean', value: false, description: 'build documentation')
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')
@@ -7,5 +8,3 @@ option('tracing', type: 'boolean', value: false, description: 'add extra debuggi
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')

View File

@@ -1,10 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<gresources>
<gresource prefix="/org/gnome/control-center/applications">
<file preprocess="xml-stripblanks">cc-action-row.ui</file>
<file preprocess="xml-stripblanks">cc-applications-panel.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>
<file preprocess="xml-stripblanks">cc-toggle-row.ui</file>
<file>cc-applications-panel.css</file>
</gresource>
</gresources>

View File

@@ -0,0 +1,218 @@
/* cc-action-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-action-row.h"
#include "cc-applications-resources.h"
struct _CcActionRow
{
GtkListBoxRow parent;
GtkWidget *title;
GtkWidget *subtitle;
GtkWidget *button;
};
G_DEFINE_TYPE (CcActionRow, cc_action_row, GTK_TYPE_LIST_BOX_ROW)
static int activated_signal;
enum
{
PROP_0,
PROP_TITLE,
PROP_SUBTITLE,
PROP_ACTION,
PROP_ENABLED,
PROP_DESTRUCTIVE
};
static void
clicked_cb (CcActionRow *row)
{
g_signal_emit (row, activated_signal, 0);
}
static void
cc_action_row_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
CcActionRow *row = CC_ACTION_ROW (object);
switch (prop_id)
{
case PROP_TITLE:
g_value_set_string (value, gtk_label_get_label (GTK_LABEL (row->title)));
break;
case PROP_SUBTITLE:
g_value_set_string (value, gtk_label_get_label (GTK_LABEL (row->subtitle)));
break;
case PROP_ACTION:
g_value_set_string (value, gtk_button_get_label (GTK_BUTTON (row->button)));
break;
case PROP_ENABLED:
g_value_set_boolean (value, gtk_widget_get_sensitive (row->button));
break;
case PROP_DESTRUCTIVE:
g_value_set_boolean (value,
gtk_style_context_has_class (gtk_widget_get_style_context (row->button), "destructive-action"));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
cc_action_row_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
CcActionRow *row = CC_ACTION_ROW (object);
switch (prop_id)
{
case PROP_TITLE:
gtk_label_set_label (GTK_LABEL (row->title), g_value_get_string (value));
break;
case PROP_SUBTITLE:
gtk_label_set_label (GTK_LABEL (row->subtitle), g_value_get_string (value));
gtk_widget_set_visible (row->subtitle, strlen (g_value_get_string (value)) > 0);
break;
case PROP_ACTION:
gtk_button_set_label (GTK_BUTTON (row->button), g_value_get_string (value));
break;
case PROP_ENABLED:
gtk_widget_set_sensitive (row->button, g_value_get_boolean (value));
break;
case PROP_DESTRUCTIVE:
if (g_value_get_boolean (value))
gtk_style_context_add_class (gtk_widget_get_style_context (row->button), "destructive-action");
else
gtk_style_context_remove_class (gtk_widget_get_style_context (row->button), "destructive-action");
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
cc_action_row_class_init (CcActionRowClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
object_class->get_property = cc_action_row_get_property;
object_class->set_property = cc_action_row_set_property;
g_object_class_install_property (object_class,
PROP_TITLE,
g_param_spec_string ("title", "title", "title",
NULL, G_PARAM_READWRITE));
g_object_class_install_property (object_class,
PROP_SUBTITLE,
g_param_spec_string ("subtitle", "subtitle", "subtitle",
NULL, G_PARAM_READWRITE));
g_object_class_install_property (object_class,
PROP_ACTION,
g_param_spec_string ("action", "action", "action",
NULL, G_PARAM_READWRITE));
g_object_class_install_property (object_class,
PROP_ENABLED,
g_param_spec_boolean ("enabled", "enabled", "enabled",
TRUE, G_PARAM_READWRITE));
g_object_class_install_property (object_class,
PROP_DESTRUCTIVE,
g_param_spec_boolean ("destructive", "destructive", "destructive",
FALSE, G_PARAM_READWRITE));
activated_signal = g_signal_new ("activated",
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_FIRST,
0,
NULL, NULL,
NULL,
G_TYPE_NONE, 0);
gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/control-center/applications/cc-action-row.ui");
gtk_widget_class_bind_template_child (widget_class, CcActionRow, title);
gtk_widget_class_bind_template_child (widget_class, CcActionRow, subtitle);
gtk_widget_class_bind_template_child (widget_class, CcActionRow, button);
gtk_widget_class_bind_template_callback (widget_class, clicked_cb);
}
static void
cc_action_row_init (CcActionRow *self)
{
gtk_widget_init_template (GTK_WIDGET (self));
}
CcActionRow *
cc_action_row_new (void)
{
return CC_ACTION_ROW (g_object_new (CC_TYPE_ACTION_ROW, NULL));
}
void
cc_action_row_set_title (CcActionRow *row,
const gchar *name)
{
gtk_label_set_label (GTK_LABEL (row->title), name);
}
void
cc_action_row_set_subtitle (CcActionRow *row,
const gchar *name)
{
gtk_label_set_label (GTK_LABEL (row->subtitle), name);
gtk_widget_set_visible (row->subtitle, strlen (name) > 0);
}
void
cc_action_row_set_action (CcActionRow *row,
const gchar *action,
gboolean sensitive)
{
gtk_button_set_label (GTK_BUTTON (row->button), action);
gtk_widget_set_sensitive (row->button, sensitive);
}

View File

@@ -1,7 +1,6 @@
/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* cc-list-row.h
/* cc-action-row.h
*
* Copyright 2020 Red Hat Inc
* 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
@@ -16,9 +15,6 @@
* 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(s):
* Bastien Nocera <hadess@hadess.net>
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
@@ -28,9 +24,19 @@
G_BEGIN_DECLS
#define CC_TYPE_POWER_PROFILE_INFO_ROW (cc_power_profile_info_row_get_type())
G_DECLARE_FINAL_TYPE (CcPowerProfileInfoRow, cc_power_profile_info_row, CC, POWER_PROFILE_INFO_ROW, GtkListBoxRow)
#define CC_TYPE_ACTION_ROW (cc_action_row_get_type())
G_DECLARE_FINAL_TYPE (CcActionRow, cc_action_row, CC, ACTION_ROW, GtkListBoxRow)
CcPowerProfileInfoRow *cc_power_profile_info_row_new (const char *text);
CcActionRow* cc_action_row_new (void);
void cc_action_row_set_title (CcActionRow *row,
const gchar *label);
void cc_action_row_set_subtitle (CcActionRow *row,
const gchar *label);
void cc_action_row_set_action (CcActionRow *row,
const gchar *action,
gboolean sensitive);
G_END_DECLS

View File

@@ -0,0 +1,51 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<template class="CcActionRow" parent="GtkListBoxRow">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="activatable">False</property>
<child>
<object class="GtkBox">
<property name="visible">1</property>
<property name="border-width">12</property>
<property name="spacing">12</property>
<child>
<object class="GtkBox">
<property name="visible">1</property>
<property name="orientation">vertical</property>
<property name="spacing">4</property>
<child>
<object class="GtkLabel" id="title">
<property name="visible">1</property>
<property name="xalign">0</property>
<property name="hexpand">1</property>
<property name="ellipsize">end</property>
</object>
<packing>
<property name="expand">1</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="subtitle">
<property name="visible">1</property>
<property name="xalign">0</property>
<property name="hexpand">1</property>
<property name="ellipsize">end</property>
<style>
<class name="dim-label"/>
</style>
</object>
</child>
</object>
</child>
<child>
<object class="GtkButton" id="button">
<property name="visible">1</property>
<property name="valign">center</property>
<signal name="clicked" handler="clicked_cb" swapped="yes"/>
</object>
</child>
</object>
</child>
</template>
</interface>

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,11 @@
.section-title {
font-weight: bold;
}
.section-subtitle {
opacity: 0.55;
}
.sidebar-icon.fullcolor {
opacity: 1;
}

View File

@@ -1,245 +1,407 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<template class="CcApplicationsPanel" parent="CcPanel">
<child type="titlebar">
<object class="AdwHeaderBar">
<property name="show-end-title-buttons">True</property>
<property name="show-start-title-buttons">False</property>
<child type="start">
<object class="GtkButton">
<property name="visible" bind-source="CcApplicationsPanel" bind-property="folded" bind-flags="default|sync-create" />
<property name="icon-name">go-previous-symbolic</property>
<property name="action-name">window.navigate</property>
<property name="action-target">0</property> <!-- 0: ADW_NAVIGATION_DIRECTION_BACK -->
</object>
</child>
<property name="title-widget">
<object class="AdwWindowTitle" id="header_title">
<property name="title" translatable="yes">Applications</property>
</object>
</property>
</object>
</child>
<child type="content">
<object class="GtkStack" id="stack">
<property name="visible">True</property>
<property name="can-focus">False</property>
<child>
<object class="GtkScrolledWindow" id="main_scroll">
<property name="visible">1</property>
<property name="hscrollbar-policy">never</property>
<child>
<object class="AdwStatusPage" id="empty_box">
<property name="icon-name">org.gnome.Software-symbolic</property>
<property name="title" translatable="yes">No applications</property>
<object class="HdyClamp">
<property name="visible">True</property>
<property name="margin_top">32</property>
<property name="margin_bottom">32</property>
<property name="margin_start">12</property>
<property name="margin_end">12</property>
<child>
<object class="GtkButton" id="install_button">
<property name="label" translatable="yes">Install some…</property>
<property name="halign">center</property>
<signal name="clicked" handler="open_software_cb" object="CcApplicationsPanel" swapped="yes"/>
<style>
<class name="pill" />
</style>
</object>
</child>
</object>
</child>
<child>
<object class="AdwPreferencesPage" id="settings_box">
<!-- App icon & buttons -->
<child>
<object class="AdwPreferencesGroup">
<object class="GtkStack" id="stack">
<property name="visible">1</property>
<child>
<object class="GtkBox">
<object class="GtkBox" id="empty_box">
<property name="visible">1</property>
<property name="orientation">vertical</property>
<property name="spacing">18</property>
<property name="valign">center</property>
<child>
<object class="GtkImage" id="app_icon_image">
<property name="icon-name">org.gnome.Software</property>
<property name="pixel-size">96</property>
<object class="GtkImage">
<property name="visible">1</property>
<property name="valign">start</property>
<property name="pixel-size">80</property>
<property name="icon-name">org.gnome.Software-symbolic</property>
<style>
<class name="icon-dropshadow" />
<class name="dim-label"/>
</style>
</object>
<packing>
<property name="fill">0</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="app_name_label">
<property name="wrap">True</property>
<object class="GtkLabel">
<property name="visible">1</property>
<property name="margin-bottom">15</property>
<property name="label" translatable="yes">No applications</property>
<style>
<class name="title" />
<class name="title-1" />
<class name="dim-label"/>
</style>
<attributes>
<attribute name="scale" value="1.2"/>
</attributes>
</object>
<packing>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkBox">
<object class="GtkButton" id="install_button">
<property name="label" translatable="yes">Install some…</property>
<property name="visible">1</property>
<property name="can-focus">1</property>
<property name="receives-default">1</property>
<property name="halign">center</property>
<property name="margin-top">12</property>
<property name="margin-bottom">12</property>
<property name="spacing">18</property>
<signal name="clicked" handler="open_software_cb" object="CcApplicationsPanel" swapped="yes"/>
</object>
<packing>
<property name="fill">0</property>
<property name="position">2</property>
</packing>
</child>
</object>
</child>
<child>
<object class="GtkBox" id="settings_box">
<property name="visible">1</property>
<property name="orientation">vertical</property>
<property name="spacing">24</property>
<property name="hexpand">1</property>
<child>
<object class="GtkBox" id="permission_section">
<property name="visible">1</property>
<property name="orientation">vertical</property>
<property name="spacing">12</property>
<style>
<class name="section"/>
</style>
<child>
<object class="GtkButton" id="launch_button">
<property name="label" translatable="yes">Open</property>
<signal name="clicked" handler="on_launch_button_clicked_cb" object="CcApplicationsPanel" swapped="no" />
<object class="GtkBox">
<property name="visible">1</property>
<property name="orientation">vertical</property>
<property name="spacing">6</property>
<child>
<object class="GtkLabel">
<property name="visible">1</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">Permissions &amp; Access</property>
<style>
<class name="section-title"/>
</style>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="visible">1</property>
<property name="xalign">0</property>
<property name="wrap">1</property>
<property name="max-width-chars">50</property>
<property name="label" translatable="yes">Data and services that this app has asked for access to and permissions that it requires.</property>
<style>
<class name="section-subtitle"/>
</style>
</object>
</child>
</object>
</child>
<child>
<object class="GtkListBox" id="permission_list">
<property name="visible">1</property>
<property name="selection-mode">none</property>
<signal name="row-activated" handler="permission_row_activated_cb" object="CcApplicationsPanel" swapped="yes"/>
<child>
<object class="CcToggleRow" id="camera">
<property name="title" translatable="yes">Camera</property>
<signal name="notify::allowed" handler="camera_cb" object="CcApplicationsPanel" swapped="yes"/>
</object>
</child>
<child>
<object class="CcInfoRow" id="no_camera">
<property name="title" translatable="yes">Camera</property>
<property name="info" translatable="yes">Disabled</property>
</object>
</child>
<child>
<object class="CcToggleRow" id="microphone">
<property name="title" translatable="yes">Microphone</property>
<signal name="notify::allowed" 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="info" translatable="yes">Disabled</property>
</object>
</child>
<child>
<object class="CcToggleRow" id="location">
<property name="title" translatable="yes">Location Services</property>
<signal name="notify::allowed" 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="info" translatable="yes">Disabled</property>
</object>
</child>
<child>
<object class="CcInfoRow" id="builtin">
<property name="title" translatable="yes">Built-in Permissions</property>
<property name="info" translatable="yes">Cannot be changed</property>
<property name="has-expander">True</property>
<property name="is-link">True</property>
</object>
</child>
<style>
<class name="pill" />
<class name="suggested-action" />
<class name="view"/>
<class name="frame"/>
</style>
</object>
</child>
<child>
<object class="GtkButton" id="view_details_button">
<property name="label" translatable="yes">View Details</property>
<object class="GtkLabel">
<property name="visible">1</property>
<property name="xalign">0</property>
<property name="wrap">1</property>
<property name="max-width-chars">50</property>
<property name="label" translatable="yes">Individual permissions for applications can be reviewed in the &lt;a href=&quot;privacy&quot;&gt;Privacy&lt;/a&gt; Settings.</property>
<property name="use-markup">1</property>
<signal name="activate-link" handler="privacy_link_cb" object="CcApplicationsPanel" swapped="yes"/>
</object>
</child>
</object>
</child>
<child>
<object class="GtkBox" id="integration_section">
<property name="visible">1</property>
<property name="orientation">vertical</property>
<property name="spacing">12</property>
<style>
<class name="section"/>
</style>
<child>
<object class="GtkBox">
<property name="visible">1</property>
<property name="orientation">vertical</property>
<property name="spacing">6</property>
<child>
<object class="GtkLabel">
<property name="visible">1</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">Integration</property>
<style>
<class name="section-title"/>
</style>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="visible">1</property>
<property name="xalign">0</property>
<property name="wrap">1</property>
<property name="max-width-chars">50</property>
<property name="label" translatable="yes">System features used by this application.</property>
<style>
<class name="section-subtitle"/>
</style>
</object>
</child>
</object>
</child>
<child>
<object class="GtkListBox" id="integration_list">
<property name="visible">1</property>
<property name="selection-mode">none</property>
<child>
<object class="CcToggleRow" id="search">
<property name="title" translatable="yes">Search</property>
<signal name="notify::allowed" 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="info" translatable="yes">Disabled</property>
</object>
</child>
<child>
<object class="CcToggleRow" id="notification">
<property name="title" translatable="yes">Notifications</property>
<signal name="notify::allowed" handler="notification_cb" object="CcApplicationsPanel" swapped="yes"/>
</object>
</child>
<child>
<object class="CcToggleRow" id="background">
<property name="title" translatable="yes">Run in background</property>
<signal name="notify::allowed" handler="background_cb" swapped="yes"/>
</object>
</child>
<child>
<object class="CcToggleRow" id="wallpaper">
<property name="title" translatable="yes">Set Desktop Background</property>
<signal name="notify::allowed" handler="wallpaper_cb" swapped="yes"/>
</object>
</child>
<child>
<object class="CcToggleRow" id="sound">
<property name="title" translatable="yes">Sounds</property>
<signal name="notify::allowed" handler="sound_cb" object="CcApplicationsPanel" swapped="yes"/>
</object>
</child>
<child>
<object class="CcInfoRow" id="no_sound">
<property name="title" translatable="yes">Sounds</property>
<property name="info" translatable="yes">Disabled</property>
</object>
</child>
<child>
<object class="CcToggleRow" id="shortcuts">
<property name="title" translatable="yes">Inhibit system keyboard shortcuts</property>
<signal name="notify::allowed" handler="shortcuts_cb" swapped="yes"/>
</object>
</child>
<style>
<class name="pill" />
<class name="view"/>
<class name="frame"/>
</style>
</object>
</child>
</object>
</child>
<child>
<object class="GtkBox" id="handler_section">
<property name="visible">1</property>
<property name="orientation">vertical</property>
<property name="spacing">12</property>
<style>
<class name="section"/>
</style>
<child>
<object class="GtkBox">
<property name="visible">1</property>
<property name="spacing">6</property>
<child>
<object class="GtkBox">
<property name="visible">1</property>
<property name="orientation">vertical</property>
<property name="spacing">6</property>
<child>
<object class="GtkLabel">
<property name="visible">1</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">Default Handlers</property>
<style>
<class name="section-title"/>
</style>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="visible">1</property>
<property name="xalign">0</property>
<property name="wrap">1</property>
<property name="max-width-chars">50</property>
<property name="label" translatable="yes">Types of files and links that this application opens.</property>
<style>
<class name="section-subtitle"/>
</style>
</object>
</child>
</object>
<packing>
<property name="expand">1</property>
</packing>
</child>
<child>
<object class="GtkButton" id="handler_reset">
<property name="visible">1</property>
<property name="halign">end</property>
<property name="valign">center</property>
<property name="label" translatable="yes">Reset</property>
<signal name="clicked" handler="handler_reset_cb" object="CcApplicationsPanel" swapped="yes"/>
</object>
</child>
</object>
</child>
<child>
<object class="GtkListBox" id="handler_list">
<property name="visible">1</property>
<property name="selection-mode">none</property>
<signal name="row-activated" handler="handler_row_activated_cb" object="CcApplicationsPanel" swapped="yes"/>
<style>
<class name="view"/>
<class name="frame"/>
</style>
</object>
</child>
</object>
</child>
<child>
<object class="GtkBox" id="usage_section">
<property name="visible">1</property>
<property name="orientation">vertical</property>
<property name="spacing">12</property>
<style>
<class name="section"/>
</style>
<child>
<object class="GtkBox">
<property name="visible">1</property>
<property name="orientation">vertical</property>
<property name="spacing">6</property>
<child>
<object class="GtkLabel">
<property name="visible">1</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">Usage</property>
<style>
<class name="section-title"/>
</style>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="visible">1</property>
<property name="xalign">0</property>
<property name="wrap">1</property>
<property name="max-width-chars">50</property>
<property name="label" translatable="yes">How much resources this application is using.</property>
<style>
<class name="section-subtitle"/>
</style>
</object>
</child>
</object>
</child>
<child>
<object class="GtkListBox" id="usage_list">
<property name="visible">1</property>
<property name="selection-mode">none</property>
<signal name="row-activated" handler="storage_row_activated_cb" object="CcApplicationsPanel" swapped="yes"/>
<child>
<object class="CcInfoRow" id="storage">
<property name="title" translatable="yes">Storage</property>
<property name="info">unknown</property>
<property name="has-expander">1</property>
<property name="is-link">1</property>
</object>
</child>
<style>
<class name="view"/>
<class name="frame"/>
</style>
</object>
</child>
</object>
</child>
</object>
</child>
</object>
</child>
<child>
<object class="AdwPreferencesGroup" id="integration_section">
<child>
<object class="CcToggleRow" id="search">
<property name="title" translatable="yes">Search</property>
<property name="subtitle" translatable="yes">Receive system searches and send results.</property>
<signal name="notify::allowed" 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="CcToggleRow" id="notification">
<property name="title" translatable="yes">Notifications</property>
<property name="subtitle" translatable="yes">Show system notifications.</property>
<signal name="notify::allowed" handler="notification_cb" object="CcApplicationsPanel" swapped="yes"/>
</object>
</child>
<child>
<object class="CcToggleRow" id="background">
<property name="title" translatable="yes">Run in Background</property>
<property name="subtitle" translatable="yes">Allow activity when the app is closed.</property>
<signal name="notify::allowed" handler="background_cb" swapped="yes"/>
</object>
</child>
<child>
<object class="CcToggleRow" id="screenshot">
<property name="title" translatable="yes">Screenshots</property>
<property name="subtitle" translatable="yes">Take pictures of the screen at any time.</property>
<signal name="notify::allowed" handler="screenshot_cb" object="CcApplicationsPanel" swapped="yes"/>
</object>
</child>
<child>
<object class="CcToggleRow" id="wallpaper">
<property name="title" translatable="yes">Change Wallpaper</property>
<property name="subtitle" translatable="yes">Change the desktop wallpaper.</property>
<signal name="notify::allowed" handler="wallpaper_cb" swapped="yes"/>
</object>
</child>
<child>
<object class="CcToggleRow" id="sound">
<property name="title" translatable="yes">Sounds</property>
<property name="subtitle" translatable="yes">Reproduce sounds.</property>
<signal name="notify::allowed" handler="sound_cb" object="CcApplicationsPanel" swapped="yes"/>
</object>
</child>
<child>
<object class="CcInfoRow" id="no_sound">
<property name="title" translatable="yes">Sounds</property>
<property name="subtitle" translatable="yes">Reproduce sounds.</property>
<property name="info" translatable="yes">Disabled</property>
</object>
</child>
<child>
<object class="CcToggleRow" id="shortcuts">
<property name="title" translatable="yes">Inhibit Shortcuts</property>
<property name="subtitle" translatable="yes">Block standard keyboard shortcuts.</property>
<signal name="notify::allowed" handler="shortcuts_cb" swapped="yes"/>
</object>
</child>
<child>
<object class="CcToggleRow" id="camera">
<property name="title" translatable="yes">Camera</property>
<property name="subtitle" translatable="yes">Take pictures with the camera.</property>
<signal name="notify::allowed" handler="camera_cb" object="CcApplicationsPanel" swapped="yes"/>
</object>
</child>
<child>
<object class="CcInfoRow" id="no_camera">
<property name="title" translatable="yes">Camera</property>
<property name="subtitle" translatable="yes">Take pictures with the camera.</property>
<property name="info" translatable="yes">Disabled</property>
</object>
</child>
<child>
<object class="CcToggleRow" id="microphone">
<property name="title" translatable="yes">Microphone</property>
<property name="subtitle" translatable="yes">Record audio with the microphone.</property>
<signal name="notify::allowed" 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="CcToggleRow" id="location">
<property name="title" translatable="yes">Location Services</property>
<property name="subtitle" translatable="yes">Access device location data.</property>
<signal name="notify::allowed" 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">Built-in Permissions</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="no" />
</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="no" />
</object>
</child>
<child>
<object class="CcInfoRow" id="storage">
<property name="title" translatable="yes">Storage</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="no" />
</object>
</child>
</object>
@@ -249,16 +411,29 @@
</object>
</child>
</template>
<object class="GtkLabel" id="title_label">
<property name="visible">1</property>
<property name="label" translatable="yes">Applications</property>
<style>
<class name="title"/>
</style>
</object>
<object class="GtkButton" id="header_button">
<property name="visible">1</property>
<property name="label" translatable="yes">Open in Software</property>
</object>
<!-- Sidebar -->
<object class="GtkBox" id="sidebar_box">
<property name="visible">True</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkSearchEntry" id="sidebar_search_entry">
<property name="margin-top">12</property>
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="has-focus">True</property>
<property name="margin">12</property>
<property name="margin-bottom">6</property>
<property name="margin-start">12</property>
<property name="margin-end">12</property>
<signal name="activate" handler="on_sidebar_search_entry_activated_cb" object="CcApplicationsPanel" swapped="yes" />
<signal name="search-changed" handler="on_sidebar_search_entry_search_changed_cb" object="CcApplicationsPanel" swapped="yes" />
<signal name="stop-search" handler="on_sidebar_search_entry_search_stopped_cb" object="CcApplicationsPanel" swapped="yes" />
@@ -266,27 +441,23 @@
</child>
<child>
<object class="GtkListBox" id="sidebar_listbox">
<property name="visible">True</property>
<property name="vexpand">True</property>
<property name="selection-mode">browse</property>
<style>
<class name="navigation-sidebar" />
</style>
<child type="placeholder">
<object class="GtkBox" id="empty_search_placeholder">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">center</property>
<property name="valign">center</property>
<property name="hexpand">True</property>
<property name="vexpand">True</property>
<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="expand">True</property>
<property name="border_width">18</property>
<property name="orientation">vertical</property>
<property name="spacing">6</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="pixel_size">64</property>
<property name="icon_name">edit-find-symbolic</property>
@@ -297,6 +468,7 @@
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">No results found</property>
<attributes>
@@ -307,6 +479,7 @@
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Try a different search</property>
<style>
@@ -325,78 +498,35 @@
<object class="GtkDialog" id="builtin_dialog">
<property name="title" translatable="yes">Built-in Permissions</property>
<property name="modal">1</property>
<property name="type-hint">dialog</property>
<property name="use-header-bar">1</property>
<property name="resizable">True</property>
<property name="hide-on-close">True</property>
<child>
<object class="AdwPreferencesPage">
<property name="resizable">0</property>
<property name="border-width">24</property>
<signal name="delete-event" handler="gtk_widget_hide_on_delete"/>
<child internal-child="vbox">
<object class="GtkBox">
<property name="visible">1</property>
<property name="orientation">vertical</property>
<property name="spacing">12</property>
<child>
<object class="AdwPreferencesGroup" id="builtin_group">
<child>
<object class="GtkListBox" id="builtin_list">
<property name="selection-mode">none</property>
<style>
<class name="boxed-list"/>
</style>
</object>
</child>
<object class="GtkLabel" id="builtin_label">
<property name="visible">1</property>
<property name="xalign">0</property>
<property name="wrap">1</property>
<property name="max-width-chars">50</property>
<property name="label">Yadda Yadda</property>
</object>
</child>
</object>
</child>
</object>
<!-- File & Link handlers dialog -->
<object class="GtkDialog" id="handler_dialog">
<property name="title" translatable="yes">File &amp; Link Associations</property>
<property name="modal">1</property>
<property name="use-header-bar">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>
<child>
<object class="AdwPreferencesPage">
<child>
<object class="AdwPreferencesGroup">
<child>
<object class="GtkLabel" id="handler_title_label">
<property name="wrap">True</property>
<property name="xalign">0.0</property>
</object>
</child>
<object class="GtkListBox" id="builtin_list">
<property name="visible">1</property>
<property name="selection-mode">none</property>
<style>
<class name="view"/>
<class name="frame"/>
</style>
</object>
</child>
<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>
<signal name="clicked" handler="handler_reset_cb" object="CcApplicationsPanel" swapped="yes"/>
<style>
<class name="destructive-action" />
</style>
</object>
</child>
</object>
</child>
</object>
</child>
</object>
@@ -405,16 +535,29 @@
<object class="GtkDialog" id="storage_dialog">
<property name="title" translatable="yes">Storage</property>
<property name="modal">1</property>
<property name="type-hint">dialog</property>
<property name="use-header-bar">1</property>
<property name="resizable">True</property>
<property name="hide-on-close">True</property>
<property name="default-width">420</property>
<property name="default-height">420</property>
<child>
<object class="AdwPreferencesPage">
<property name="resizable">0</property>
<property name="border-width">24</property>
<signal name="delete-event" handler="gtk_widget_hide_on_delete"/>
<child internal-child="vbox">
<object class="GtkBox">
<property name="visible">1</property>
<property name="orientation">vertical</property>
<property name="spacing">12</property>
<child>
<object class="AdwPreferencesGroup">
<property name="description" translatable="yes">How much disk space this application is occupying with app data and caches.</property>
<object class="GtkLabel">
<property name="visible">1</property>
<property name="xalign">0</property>
<property name="wrap">1</property>
<property name="max-width-chars">50</property>
<property name="label" translatable="yes">How much disk space this application is occupying with app data and caches.</property>
</object>
</child>
<child>
<object class="GtkListBox" id="storage_list">
<property name="visible">1</property>
<property name="selection-mode">none</property>
<child>
<object class="CcInfoRow" id="app">
<property name="title" translatable="yes">Application</property>
@@ -436,30 +579,32 @@
<child>
<object class="CcInfoRow" id="total">
<property name="title" translatable="yes">&lt;b&gt;Total&lt;/b&gt;</property>
<property name="use-markup">1</property>
<property name="info">Unknown</property>
</object>
</child>
<style>
<class name="view"/>
<class name="frame"/>
</style>
</object>
</child>
<child>
<object class="AdwPreferencesGroup">
<object class="GtkBox">
<property name="visible">1</property>
<child>
<object class="GtkButton" id="clear_cache_button">
<property name="visible">1</property>
<property name="label" translatable="yes">Clear Cache…</property>
<signal name="clicked" handler="clear_cache_cb" object="CcApplicationsPanel" swapped="yes"/>
</object>
<packing>
<property name="pack-type">end</property>
</packing>
</child>
</object>
</child>
</object>
</child>
</object>
<object class="GtkSizeGroup">
<property name="mode">horizontal</property>
<widgets>
<widget name="launch_button" />
<widget name="view_details_button" />
</widgets>
</object>
</interface>

View File

@@ -86,9 +86,9 @@ cc_applications_row_new (GAppInfo *info)
icon = g_app_info_get_icon (info);
if (icon != NULL)
gtk_image_set_from_gicon (GTK_IMAGE (self->image), g_app_info_get_icon (info));
gtk_image_set_from_gicon (GTK_IMAGE (self->image), g_app_info_get_icon (info), GTK_ICON_SIZE_BUTTON);
else
gtk_image_set_from_icon_name (GTK_IMAGE (self->image), "application-x-executable");
gtk_image_set_from_icon_name (GTK_IMAGE (self->image), "application-x-executable", GTK_ICON_SIZE_BUTTON);
gtk_label_set_label (GTK_LABEL (self->label), g_app_info_get_display_name (info));

View File

@@ -1,23 +1,27 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<template class="CcApplicationsRow" parent="GtkListBoxRow">
<property name="visible">True</property>
<property name="can-focus">True</property>
<child>
<object class="GtkBox" id="box">
<property name="margin-top">6</property>
<property name="margin-bottom">6</property>
<property name="margin-start">6</property>
<property name="margin-end">6</property>
<property name="visible">1</property>
<property name="border-width">6</property>
<property name="spacing">12</property>
<child>
<object class="GtkImage" id="image">
<property name="visible">1</property>
<property name="pixel-size">32</property>
<style>
<class name="sidebar-icon"/>
<class name="fullcolor"/>
<class name="lowres-icon"/>
</style>
</object>
</child>
<child>
<object class="GtkLabel" id="label">
<property name="visible">1</property>
<property name="xalign">0</property>
<property name="ellipsize">end</property>
</object>

View File

@@ -26,8 +26,9 @@
struct _CcInfoRow
{
AdwActionRow parent;
GtkListBoxRow parent;
GtkWidget *title;
GtkWidget *info;
GtkWidget *expander;
@@ -35,11 +36,13 @@ struct _CcInfoRow
gboolean link;
};
G_DEFINE_TYPE (CcInfoRow, cc_info_row, ADW_TYPE_ACTION_ROW)
G_DEFINE_TYPE (CcInfoRow, cc_info_row, GTK_TYPE_LIST_BOX_ROW)
enum
{
PROP_0,
PROP_TITLE,
PROP_USE_MARKUP,
PROP_INFO,
PROP_HAS_EXPANDER,
PROP_IS_LINK,
@@ -56,12 +59,18 @@ cc_info_row_get_property (GObject *object,
switch (prop_id)
{
case PROP_TITLE:
g_value_set_string (value, gtk_label_get_label (GTK_LABEL (row->title)));
break;
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_USE_MARKUP:
g_value_set_boolean (value, gtk_label_get_use_markup (GTK_LABEL (row->title)));
break;
case PROP_IS_LINK:
g_value_set_boolean (value, row->link);
break;
@@ -78,11 +87,11 @@ static void
update_expander (CcInfoRow *row)
{
if (row->link)
gtk_image_set_from_icon_name (GTK_IMAGE (row->expander), "go-next-symbolic");
gtk_image_set_from_icon_name (GTK_IMAGE (row->expander), "go-next-symbolic", GTK_ICON_SIZE_BUTTON);
else if (row->expanded)
gtk_image_set_from_icon_name (GTK_IMAGE (row->expander), "pan-down-symbolic");
gtk_image_set_from_icon_name (GTK_IMAGE (row->expander), "pan-down-symbolic", GTK_ICON_SIZE_BUTTON);
else
gtk_image_set_from_icon_name (GTK_IMAGE (row->expander), "pan-end-symbolic");
gtk_image_set_from_icon_name (GTK_IMAGE (row->expander), "pan-end-symbolic", GTK_ICON_SIZE_BUTTON);
}
static void
@@ -95,6 +104,10 @@ cc_info_row_set_property (GObject *object,
switch (prop_id)
{
case PROP_TITLE:
gtk_label_set_label (GTK_LABEL (row->title), g_value_get_string (value));
break;
case PROP_INFO:
gtk_label_set_label (GTK_LABEL (row->info), g_value_get_string (value));
break;
@@ -104,6 +117,10 @@ cc_info_row_set_property (GObject *object,
gtk_list_box_row_set_activatable (GTK_LIST_BOX_ROW (row), g_value_get_boolean (value));
break;
case PROP_USE_MARKUP:
gtk_label_set_use_markup (GTK_LABEL (row->title), g_value_get_boolean (value));
break;
case PROP_IS_LINK:
row->link = g_value_get_boolean (value);
update_expander (row);
@@ -130,11 +147,21 @@ cc_info_row_class_init (CcInfoRowClass *klass)
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_TITLE,
g_param_spec_string ("title", "title", "title",
NULL, G_PARAM_READWRITE));
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_USE_MARKUP,
g_param_spec_boolean ("use-markup", "use-markup", "use-markup",
FALSE, G_PARAM_READWRITE));
g_object_class_install_property (object_class,
PROP_HAS_EXPANDER,
g_param_spec_boolean ("has-expander", "has-expander", "has-expander",
@@ -150,6 +177,7 @@ cc_info_row_class_init (CcInfoRowClass *klass)
g_param_spec_boolean ("is-link", "is-link", "is-link",
FALSE, G_PARAM_READWRITE));
gtk_widget_class_bind_template_child (widget_class, CcInfoRow, title);
gtk_widget_class_bind_template_child (widget_class, CcInfoRow, info);
gtk_widget_class_bind_template_child (widget_class, CcInfoRow, expander);
}

View File

@@ -20,12 +20,12 @@
#pragma once
#include <adwaita.h>
#include <gtk/gtk.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)
G_DECLARE_FINAL_TYPE (CcInfoRow, cc_info_row, CC, INFO_ROW, GtkListBoxRow)
CcInfoRow* cc_info_row_new (void);

View File

@@ -1,19 +1,40 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<template class="CcInfoRow" parent="AdwActionRow">
<template class="CcInfoRow" parent="GtkListBoxRow">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="activatable">False</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 class="GtkBox">
<property name="visible">1</property>
<property name="border-width">12</property>
<property name="spacing">12</property>
<child>
<object class="GtkLabel" id="title">
<property name="visible">1</property>
<property name="xalign">0</property>
<property name="hexpand">1</property>
<property name="ellipsize">end</property>
</object>
</child>
<child>
<object class="GtkLabel" id="info">
<property name="visible">1</property>
<property name="valign">center</property>
<style>
<class name="dim-label"/>
</style>
</object>
</child>
<child>
<object class="GtkImage" id="expander">
<property name="valign">center</property>
<property name="icon-name">pan-end-symbolic</property>
<style>
<class name="dim-label"/>
</style>
</object>
</child>
</object>
</child>
</template>

View File

@@ -26,8 +26,9 @@
struct _CcSnapRow
{
AdwActionRow parent;
GtkListBoxRow parent;
GtkLabel *title_label;
GtkSwitch *slot_toggle;
GtkComboBox *slots_combo;
GtkListStore *slots_combo_model;
@@ -39,7 +40,7 @@ struct _CcSnapRow
GPtrArray *slots;
};
G_DEFINE_TYPE (CcSnapRow, cc_snap_row, ADW_TYPE_ACTION_ROW)
G_DEFINE_TYPE (CcSnapRow, cc_snap_row, GTK_TYPE_LIST_BOX_ROW)
typedef struct
{
@@ -244,6 +245,7 @@ cc_snap_row_class_init (CcSnapRowClass *klass)
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, title_label);
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);
@@ -293,7 +295,7 @@ cc_snap_row_new (GCancellable *cancellable, SnapdInterface *interface, SnapdPlug
label = snapd_interface_make_label (interface);
else
label = g_strdup (snapd_plug_get_interface (plug));
adw_preferences_row_set_title (ADW_PREFERENCES_ROW (self), label);
gtk_label_set_label (self->title_label, label);
/* Add option into combo box */
gtk_list_store_append (self->slots_combo_model, &iter);

View File

@@ -20,13 +20,13 @@
#pragma once
#include <adwaita.h>
#include <gtk/gtk.h>
#include <snapd-glib/snapd-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)
G_DECLARE_FINAL_TYPE (CcSnapRow, cc_snap_row, CC, SNAP_ROW, GtkListBoxRow)
CcSnapRow* cc_snap_row_new (GCancellable *cancellable,
SnapdInterface *interface,

View File

@@ -8,27 +8,45 @@
<column type="gchararray"/>
</columns>
</object>
<template class="CcSnapRow" parent="AdwActionRow">
<template class="CcSnapRow" parent="GtkListBoxRow">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="activatable">False</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"/>
<object class="GtkBox">
<property name="visible">True</property>
<property name="border-width">12</property>
<property name="spacing">12</property>
<child>
<object class="GtkCellRendererText">
<object class="GtkLabel" id="title_label">
<property name="visible">True</property>
<property name="xalign">0</property>
<property name="hexpand">1</property>
<property name="ellipsize">end</property>
</object>
<attributes>
<attribute name="text">1</attribute>
</attributes>
</child>
<child>
<object class="GtkSwitch" id="slot_toggle">
<property name="visible">True</property>
<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="visible">True</property>
<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>
</object>
</child>

View File

@@ -26,16 +26,18 @@
struct _CcToggleRow
{
AdwActionRow parent;
GtkListBoxRow parent;
GtkWidget *title;
GtkWidget *toggle;
};
G_DEFINE_TYPE (CcToggleRow, cc_toggle_row, ADW_TYPE_ACTION_ROW)
G_DEFINE_TYPE (CcToggleRow, cc_toggle_row, GTK_TYPE_LIST_BOX_ROW)
enum
{
PROP_0,
PROP_TITLE,
PROP_ALLOWED
};
@@ -55,6 +57,9 @@ cc_toggle_row_get_property (GObject *object,
switch (prop_id)
{
case PROP_TITLE:
g_value_set_string (value, gtk_label_get_label (GTK_LABEL (row->title)));
break;
case PROP_ALLOWED:
g_value_set_boolean (value, cc_toggle_row_get_allowed (row));
break;
@@ -74,6 +79,9 @@ cc_toggle_row_set_property (GObject *object,
switch (prop_id)
{
case PROP_TITLE:
gtk_label_set_label (GTK_LABEL (row->title), g_value_get_string (value));
break;
case PROP_ALLOWED:
cc_toggle_row_set_allowed (row, g_value_get_boolean (value));
break;
@@ -94,11 +102,17 @@ cc_toggle_row_class_init (CcToggleRowClass *klass)
gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/control-center/applications/cc-toggle-row.ui");
g_object_class_install_property (object_class,
PROP_TITLE,
g_param_spec_string ("title", "title", "title",
NULL, G_PARAM_READWRITE));
g_object_class_install_property (object_class,
PROP_ALLOWED,
g_param_spec_boolean ("allowed", "allowed", "allowed",
FALSE, G_PARAM_READWRITE));
gtk_widget_class_bind_template_child (widget_class, CcToggleRow, title);
gtk_widget_class_bind_template_child (widget_class, CcToggleRow, toggle);
gtk_widget_class_bind_template_callback (widget_class, changed_cb);

View File

@@ -20,12 +20,12 @@
#pragma once
#include <adwaita.h>
#include <gtk/gtk.h>
G_BEGIN_DECLS
#define CC_TYPE_TOGGLE_ROW (cc_toggle_row_get_type())
G_DECLARE_FINAL_TYPE (CcToggleRow, cc_toggle_row, CC, TOGGLE_ROW, AdwActionRow)
G_DECLARE_FINAL_TYPE (CcToggleRow, cc_toggle_row, CC, TOGGLE_ROW, GtkListBoxRow)
CcToggleRow* cc_toggle_row_new (void);

View File

@@ -1,11 +1,29 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<template class="CcToggleRow" parent="AdwActionRow">
<property name="activatable-widget">toggle</property>
<template class="CcToggleRow" parent="GtkListBoxRow">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="activatable">False</property>
<child>
<object class="GtkSwitch" id="toggle">
<property name="valign">center</property>
<signal name="notify::active" handler="changed_cb" swapped="yes"/>
<object class="GtkBox">
<property name="visible">1</property>
<property name="border-width">12</property>
<property name="spacing">12</property>
<child>
<object class="GtkLabel" id="title">
<property name="visible">1</property>
<property name="xalign">0</property>
<property name="hexpand">1</property>
<property name="ellipsize">end</property>
</object>
</child>
<child>
<object class="GtkSwitch" id="toggle">
<property name="visible">1</property>
<property name="valign">center</property>
<signal name="notify::active" handler="changed_cb" swapped="yes"/>
</object>
</child>
</object>
</child>
</template>

View File

@@ -4,13 +4,13 @@ Comment=Control various application 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
Icon=preferences-desktop-apps
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 Applications panel. Do NOT translate or localize the semicolons! The list MUST also end with a semicolon!
# Translators: Search terms to find the Privacy panel. Do NOT translate or localize the semicolons! The list MUST also end with a semicolon!
Keywords=application;flatpak;permission;setting;
X-GNOME-ControlCenter-HasSidebar=true
X-GNOME-ControlCenter-HasSidebar=true

View File

@@ -1,4 +0,0 @@
install_data(
'scalable/org.gnome.Settings-applications-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

@@ -21,6 +21,7 @@ sources = files(
'cc-applications-row.c',
'cc-toggle-row.c',
'cc-info-row.c',
'cc-action-row.c',
'globs.c',
'search.c',
'utils.c',
@@ -54,5 +55,3 @@ panels_libs += static_library(
dependencies : deps,
c_args : cflags
)
subdir('icons')

View File

@@ -143,12 +143,14 @@ file_size_finish (GFile *file,
}
void
listbox_remove_all (GtkListBox *listbox)
container_remove_all (GtkContainer *container)
{
GtkWidget *child;
g_autoptr(GList) children = NULL;
GList *l;
while ((child = gtk_widget_get_first_child (GTK_WIDGET (listbox))))
gtk_list_box_remove (listbox, child);
children = gtk_container_get_children (container);
for (l = children; l; l = l->next)
gtk_widget_destroy (GTK_WIDGET (l->data));
}
static gchar *
@@ -166,7 +168,7 @@ get_output_of (const gchar **argv)
&status, NULL))
return NULL;
if (!g_spawn_check_wait_status (status, NULL))
if (!g_spawn_check_exit_status (status, NULL))
return NULL;
return g_steal_pointer (&output);

View File

@@ -44,7 +44,7 @@ gboolean file_size_finish (GFile *file,
guint64 *size,
GError **error);
void listbox_remove_all (GtkListBox *listbox);
void container_remove_all (GtkContainer *container);
GKeyFile* get_flatpak_metadata (const gchar *app_id);

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

@@ -6,9 +6,4 @@
<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>
</gresource>
</gresources>

View File

@@ -0,0 +1,855 @@
/* 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;
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_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_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)
{
GListStore *store;
guint i;
store = bg_source_get_liststore (BG_SOURCE (bg_source));
for (i = 0; i < g_list_model_get_n_items (G_LIST_MODEL (store)); i++)
{
g_autoptr(CcBackgroundItem) item_n = NULL;
item_n = g_list_model_get_item (G_LIST_MODEL (store), i);
if (item_n == item)
{
g_list_store_remove (store, i);
break;
}
}
}
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 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
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;
GListStore *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);
/* insert the item into the liststore */
g_list_store_insert_sorted (store, item, sort_func, bg_source);
g_hash_table_insert (bg_source->known_items,
bg_pictures_source_get_unique_filename (uri),
GINT_TO_POINTER (TRUE));
g_clear_pointer (&surface, 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 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)
{
g_autoptr(CcBackgroundItem) item = NULL;
CcBackgroundItemFlags flags = 0;
g_autofree gchar *source_uri = NULL;
g_autofree gchar *uri = NULL;
gboolean needs_download;
gboolean retval = FALSE;
const gchar *pictures_path;
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_path = g_get_user_special_dir (G_USER_DIRECTORY_PICTURES);
if (pictures_path == NULL)
pictures_path = g_get_home_dir ();
pictures_dir = g_file_new_for_path (pictures_path);
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);
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:
return retval;
}
static gboolean
add_single_file_from_info (BgPicturesSource *bg_source,
GFile *file,
GFileInfo *info)
{
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);
}
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);
}
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);
return retval;
}
gboolean
bg_pictures_source_remove (BgPicturesSource *bg_source,
const char *uri)
{
GListStore *store;
gboolean retval;
guint i;
retval = FALSE;
store = bg_source_get_liststore (BG_SOURCE (bg_source));
for (i = 0; i < g_list_model_get_n_items (G_LIST_MODEL (store)); i++)
{
g_autoptr(CcBackgroundItem) tmp_item = NULL;
const char *tmp_uri;
tmp_item = g_list_model_get_item (G_LIST_MODEL (store), i);
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);
g_list_store_remove (store, i);
retval = TRUE;
break;
}
}
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);
}
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 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);
}
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 (BgPicturesSource *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:
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_object (monitor,
"changed",
G_CALLBACK (files_changed_cb),
self, G_CONNECT_SWAPPED);
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;
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_object (self->grl_miner, "media-found", G_CALLBACK (media_found_cb), self, G_CONNECT_SWAPPED);
cc_background_grilo_miner_start (self->grl_miner);
}
BgPicturesSource *
bg_pictures_source_new (GtkWidget *widget)
{
return g_object_new (BG_TYPE_PICTURES_SOURCE, "widget", widget, NULL);
}
const char * const *
bg_pictures_get_support_content_types (void)
{
return content_types;
}

View File

@@ -0,0 +1,46 @@
/* 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>
*
*/
#pragma once
#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 (GtkWidget *widget);
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

View File

@@ -41,6 +41,17 @@ struct _BgRecentSource
G_DEFINE_TYPE (BgRecentSource, bg_recent_source, BG_TYPE_SOURCE)
static const gchar * const content_types[] = {
"image/png",
"image/jp2",
"image/jpeg",
"image/bmp",
"image/svg+xml",
"image/x-portable-anymap",
NULL
};
static int
sort_func (gconstpointer a,
gconstpointer b,
@@ -78,7 +89,7 @@ add_file_from_info (BgRecentSource *self,
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/*"))
if (!content_type || !g_strv_contains (content_types, content_type))
return;
uri = g_file_get_uri (file);

View File

@@ -23,7 +23,7 @@
#include <cairo-gobject.h>
#define THUMBNAIL_WIDTH 144
#define THUMBNAIL_WIDTH 154
#define THUMBNAIL_HEIGHT (THUMBNAIL_WIDTH * 3 / 4)
typedef struct

View File

@@ -35,27 +35,6 @@ struct _BgWallpapersSource
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;
item_a = (CcBackgroundItem *) a;
item_b = (CcBackgroundItem *) b;
if (strcmp (cc_background_item_get_name (item_a), "Default Background") == 0)
return -1;
if (strcmp (cc_background_item_get_name (item_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,
@@ -69,7 +48,7 @@ load_wallpapers (gchar *key,
if (deleted)
return;
g_list_store_insert_sorted (store, item, sort_func, NULL);
g_list_store_append (store, item);
}
static void

View File

@@ -25,10 +25,10 @@
#include <libgnome-desktop/gnome-desktop-thumbnail.h>
#include "bg-colors-source.h"
#include "bg-pictures-source.h"
#include "bg-recent-source.h"
#include "bg-wallpapers-source.h"
#include "cc-background-chooser.h"
#include "cc-background-paintable.h"
struct _CcBackgroundChooser
{
@@ -85,63 +85,54 @@ on_delete_background_clicked_cb (GtkButton *button,
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;
g_autoptr(GdkPixbuf) pixbuf = NULL;
CcBackgroundItem *item;
GtkWidget *overlay;
GtkWidget *child;
GtkWidget *picture;
GtkWidget *image;
GtkWidget *icon;
GtkWidget *check;
GtkWidget *button = NULL;
BgSource *source;
source = BG_SOURCE (user_data);
item = CC_BACKGROUND_ITEM (model_item);
pixbuf = cc_background_item_get_thumbnail (item,
bg_source_get_thumbnail_factory (source),
bg_source_get_thumbnail_width (source),
bg_source_get_thumbnail_height (source),
bg_source_get_scale_factor (source));
image = gtk_image_new_from_gicon (G_ICON (pixbuf), GTK_ICON_SIZE_DIALOG);
gtk_widget_show (image);
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);
icon = gtk_image_new_from_icon_name("slideshow-emblem", GTK_ICON_SIZE_BUTTON);
gtk_image_set_pixel_size (GTK_IMAGE (icon), 16);
gtk_widget_set_margin_start (icon, 8);
gtk_widget_set_margin_end (icon, 8);
gtk_widget_set_margin_top (icon, 8);
gtk_widget_set_margin_bottom (icon, 8);
gtk_widget_set_halign (icon, GTK_ALIGN_END);
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");
gtk_style_context_add_class (gtk_widget_get_style_context (icon), "slideshow-emblem");
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");
button = gtk_button_new_from_icon_name ("window-close-symbolic", GTK_ICON_SIZE_BUTTON);
gtk_widget_set_halign (button, GTK_ALIGN_END);
gtk_widget_set_valign (button, GTK_ALIGN_START);
gtk_widget_set_margin_start (icon, 6);
gtk_widget_set_margin_end (icon, 6);
gtk_widget_set_margin_top (icon, 6);
gtk_widget_set_margin_bottom (icon, 6);
gtk_widget_show (button);
gtk_widget_add_css_class (button, "osd");
gtk_widget_add_css_class (button, "circular");
gtk_widget_add_css_class (button, "remove-button");
gtk_style_context_add_class (gtk_widget_get_style_context (button), "osd");
gtk_style_context_add_class (gtk_widget_get_style_context (button), "remove-button");
g_signal_connect (button,
"clicked",
@@ -150,23 +141,17 @@ create_widget_func (gpointer model_item,
}
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_container_add (GTK_CONTAINER (overlay), image);
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);
gtk_widget_show (overlay);
child = gtk_flow_box_child_new ();
child = gtk_flow_box_child_new();
gtk_widget_set_halign (child, GTK_ALIGN_CENTER);
gtk_widget_set_valign (child, GTK_ALIGN_CENTER);
gtk_flow_box_child_set_child (GTK_FLOW_BOX_CHILD (child), overlay);
gtk_container_add (GTK_CONTAINER (child), overlay);
gtk_widget_show (child);
g_object_set_data_full (G_OBJECT (child), "item", g_object_ref (item), g_object_unref);
@@ -234,20 +219,67 @@ on_file_chooser_response_cb (GtkDialog *filechooser,
{
if (response == GTK_RESPONSE_ACCEPT)
{
g_autoptr(GListModel) files = NULL;
guint i;
g_autoptr(GSList) filenames = NULL;
GSList *l;
files = gtk_file_chooser_get_files (GTK_FILE_CHOOSER (filechooser));
for (i = 0; i < g_list_model_get_n_items (files); i++)
filenames = gtk_file_chooser_get_filenames (GTK_FILE_CHOOSER (filechooser));
for (l = filenames; l != NULL; l = l->next)
{
g_autoptr(GFile) file = g_list_model_get_item (files, i);
g_autofree gchar *filename = g_file_get_path (file);
g_autofree gchar *filename = l->data;
bg_recent_source_add_file (self->recent_source, filename);
}
}
gtk_window_destroy (GTK_WINDOW (filechooser));
gtk_widget_destroy (GTK_WIDGET (filechooser));
}
static void
on_file_chooser_selection_changed_cb (GtkFileChooser *chooser,
GnomeDesktopThumbnailFactory *thumbnail_factory)
{
g_autofree gchar *uri = NULL;
uri = gtk_file_chooser_get_uri (chooser);
if (uri)
{
g_autoptr(GFileInfo) file_info = NULL;
g_autoptr(GdkPixbuf) pixbuf = NULL;
g_autofree gchar *mime_type = NULL;
g_autoptr(GFile) file = NULL;
GtkWidget *preview;
preview = gtk_file_chooser_get_preview_widget (chooser);
file = g_file_new_for_uri (uri);
file_info = g_file_query_info (file,
"standard::*",
G_FILE_QUERY_INFO_NONE,
NULL,
NULL);
if (file_info && g_file_info_get_file_type (file_info) != G_FILE_TYPE_DIRECTORY)
mime_type = g_strdup (g_file_info_get_content_type (file_info));
if (mime_type)
{
pixbuf = gnome_desktop_thumbnail_factory_generate_thumbnail (thumbnail_factory,
uri,
mime_type);
}
gtk_dialog_set_response_sensitive (GTK_DIALOG (chooser),
GTK_RESPONSE_ACCEPT,
pixbuf != NULL);
if (pixbuf)
gtk_image_set_from_pixbuf (GTK_IMAGE (preview), pixbuf);
else
gtk_image_set_from_icon_name (GTK_IMAGE (preview), "dialog-question", GTK_ICON_SIZE_DIALOG);
}
gtk_file_chooser_set_preview_widget_active (chooser, TRUE);
}
/* GObject overrides */
@@ -301,14 +333,15 @@ cc_background_chooser_init (CcBackgroundChooser *self)
void
cc_background_chooser_select_file (CcBackgroundChooser *self)
{
g_autoptr(GFile) pictures_folder = NULL;
g_autoptr(GnomeDesktopThumbnailFactory) factory = NULL;
GtkFileFilter *filter;
GtkWidget *filechooser;
GtkWindow *toplevel;
GtkWidget *preview;
g_return_if_fail (CC_IS_BACKGROUND_CHOOSER (self));
toplevel = (GtkWindow*) gtk_widget_get_native (GTK_WIDGET (self));
toplevel = (GtkWindow*) gtk_widget_get_toplevel (GTK_WIDGET (self));
filechooser = gtk_file_chooser_dialog_new (_("Select a picture"),
toplevel,
GTK_FILE_CHOOSER_ACTION_OPEN,
@@ -317,15 +350,30 @@ cc_background_chooser_select_file (CcBackgroundChooser *self)
NULL);
gtk_window_set_modal (GTK_WINDOW (filechooser), TRUE);
preview = gtk_image_new ();
gtk_widget_set_size_request (preview, 154, -1);
gtk_file_chooser_set_preview_widget (GTK_FILE_CHOOSER (filechooser), preview);
gtk_file_chooser_set_use_preview_label (GTK_FILE_CHOOSER (filechooser), FALSE);
gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (filechooser), TRUE);
gtk_widget_show (preview);
factory = gnome_desktop_thumbnail_factory_new (GNOME_DESKTOP_THUMBNAIL_SIZE_LARGE);
g_signal_connect_after (filechooser,
"selection-changed",
G_CALLBACK (on_file_chooser_selection_changed_cb),
factory);
g_object_set_data_full (G_OBJECT (filechooser),
"factory",
g_object_ref (factory),
g_object_unref);
filter = gtk_file_filter_new ();
gtk_file_filter_add_pixbuf_formats (filter);
gtk_file_chooser_set_filter (GTK_FILE_CHOOSER (filechooser), filter);
gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (filechooser), TRUE);
pictures_folder = g_file_new_for_path (g_get_user_special_dir (G_USER_DIRECTORY_PICTURES));
gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (filechooser),
pictures_folder,
NULL);
g_get_user_special_dir (G_USER_DIRECTORY_PICTURES));
g_signal_connect_object (filechooser,
"response",

View File

@@ -1,62 +1,88 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<template class="CcBackgroundChooser" parent="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<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="no" />
<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 class="GtkSeparator">
<property name="visible">True</property>
<property name="can_focus">False</property>
</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="no" />
<style>
<class name="background-flowbox"/>
</style>
<object class="GtkScrolledWindow">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="expand">True</property>
<property name="shadow-type">none</property>
<property name="hscrollbar-policy">never</property>
<property name="vscrollbar-policy">automatic</property>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<property name="expand">True</property>
<style>
<class name="view" />
</style>
<!-- Recent -->
<child>
<object class="GtkBox" id="recent_box">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="orientation">vertical</property>
<property name="halign">center</property>
<child>
<object class="GtkFlowBox" id="recent_flowbox">
<property name="visible">True</property>
<property name="margin">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="no" />
</object>
</child>
<child>
<object class="GtkSeparator">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="margin-top">12</property>
<property name="margin-bottom">12</property>
</object>
</child>
</object>
</child>
<child>
<object class="GtkFlowBox" id="flowbox">
<property name="visible">True</property>
<property name="margin">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="no" />
</object>
</child>
</object>
</child>
</object>
</child>

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

@@ -0,0 +1,31 @@
/*
* 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/>.
*/
#pragma once
#include <glib-object.h>
G_BEGIN_DECLS
#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);
CcBackgroundGriloMiner *cc_background_grilo_miner_new (void);
void cc_background_grilo_miner_start (CcBackgroundGriloMiner *self);
G_END_DECLS

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;
@@ -66,17 +57,19 @@ struct _CcBackgroundItem
int width;
int height;
GnomeBG *bg_dark;
CachedThumbnail cached_thumbnail;
CachedThumbnail cached_thumbnail_dark;
struct {
int width;
int height;
int frame;
int scale_factor;
GdkPixbuf *thumbnail;
} cached_thumbnail;
};
enum {
PROP_0,
PROP_NAME,
PROP_URI,
PROP_URI_DARK,
PROP_PLACEMENT,
PROP_SHADING,
PROP_PRIMARY_COLOR,
@@ -109,15 +102,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 +110,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 +125,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)
{
@@ -185,7 +156,11 @@ render_at_size (GnomeBG *bg,
GdkPixbuf *pixbuf;
pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE, 8, width, height);
#ifdef GNOME_DESKTOP_BG_API_BREAK
gnome_bg_draw (bg, pixbuf);
#else
gnome_bg_draw (bg, pixbuf, gdk_screen_get_default (), FALSE);
#endif
return pixbuf;
}
@@ -197,27 +172,21 @@ cc_background_item_get_frame_thumbnail (CcBackgroundItem *item,
int height,
int scale_factor,
int frame,
gboolean force_size,
gboolean dark)
gboolean force_size)
{
g_autoptr(GdkPixbuf) pixbuf = NULL;
g_autoptr(GdkPixbuf) retval = NULL;
CachedThumbnail *thumbnail;
GnomeBG *bg;
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);
if (item->cached_thumbnail.thumbnail &&
item->cached_thumbnail.width == width &&
item->cached_thumbnail.height == height &&
item->cached_thumbnail.scale_factor == scale_factor &&
item->cached_thumbnail.frame == frame)
return g_object_ref (item->cached_thumbnail.thumbnail);
set_bg_properties (item);
@@ -229,30 +198,19 @@ cc_background_item_get_frame_thumbnail (CcBackgroundItem *item,
* the slideshow frame though, so we can't do much better than this
* for now.
*/
pixbuf = render_at_size (bg, width, height);
pixbuf = render_at_size (item->bg, width, height);
} else {
g_autoptr(GdkMonitor) monitor = NULL;
GdkDisplay *display;
GListModel *monitors;
GdkRectangle monitor_layout;
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,
pixbuf = gnome_bg_create_frame_thumbnail (item->bg,
thumbs,
&monitor_layout,
gdk_screen_get_default (),
width,
height,
frame);
} else {
pixbuf = gnome_bg_create_thumbnail (bg,
pixbuf = gnome_bg_create_thumbnail (item->bg,
thumbs,
&monitor_layout,
gdk_screen_get_default (),
width,
height);
}
@@ -260,7 +218,7 @@ cc_background_item_get_frame_thumbnail (CcBackgroundItem *item,
retval = g_steal_pointer (&pixbuf);
gnome_bg_get_image_size (bg,
gnome_bg_get_image_size (item->bg,
thumbs,
width,
height,
@@ -270,11 +228,11 @@ cc_background_item_get_frame_thumbnail (CcBackgroundItem *item,
update_size (item);
/* Cache the new thumbnail */
g_set_object (&thumbnail->thumbnail, retval);
thumbnail->width = width;
thumbnail->height = height;
thumbnail->scale_factor = scale_factor;
thumbnail->frame = frame;
g_set_object (&item->cached_thumbnail.thumbnail, retval);
item->cached_thumbnail.width = width;
item->cached_thumbnail.height = height;
item->cached_thumbnail.scale_factor = scale_factor;
item->cached_thumbnail.frame = frame;
return g_steal_pointer (&retval);
}
@@ -285,10 +243,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, FALSE, dark);
return cc_background_item_get_frame_thumbnail (item, thumbs, width, height, scale_factor, -1, FALSE);
}
static void
@@ -398,21 +355,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)
{
@@ -421,14 +363,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)
@@ -600,9 +534,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;
@@ -653,12 +584,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;
@@ -736,13 +664,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",
@@ -839,7 +760,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;
@@ -863,7 +783,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);
@@ -873,8 +792,8 @@ 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_OBJECT_CLASS (cc_background_item_parent_class)->finalize (object);
}
@@ -1033,10 +952,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

@@ -23,7 +23,7 @@
#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 +35,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,30 +46,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 force_size,
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);

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

@@ -35,18 +35,16 @@
#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;
@@ -55,135 +53,25 @@ struct _CcBackgroundPanel
GSettings *settings;
GSettings *lock_settings;
GSettings *interface_settings;
GnomeDesktopThumbnailFactory *thumb_factory;
GDBusProxy *proxy;
CcBackgroundItem *current_background;
CcBackgroundChooser *background_chooser;
CcBackgroundPreview *default_preview;
CcBackgroundPreview *dark_preview;
GtkToggleButton *default_toggle;
GtkToggleButton *dark_toggle;
GtkButton *add_picture_button;
CcBackgroundPreview *desktop_preview;
};
CC_PANEL_REGISTER (CcBackgroundPanel, cc_background_panel)
static void
load_custom_css (CcBackgroundPanel *self)
{
g_autoptr(GtkCssProvider) provider = NULL;
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 void
reload_color_scheme_toggles (CcBackgroundPanel *self)
{
GDesktopColorScheme scheme;
scheme = g_settings_get_enum (self->interface_settings, INTERFACE_COLOR_SCHEME_KEY);
if (scheme == G_DESKTOP_COLOR_SCHEME_DEFAULT)
{
gtk_toggle_button_set_active (self->default_toggle, TRUE);
}
else if (scheme == G_DESKTOP_COLOR_SCHEME_PREFER_DARK)
{
gtk_toggle_button_set_active (self->dark_toggle, TRUE);
}
else
{
gtk_toggle_button_set_active (self->default_toggle, FALSE);
gtk_toggle_button_set_active (self->dark_toggle, FALSE);
}
}
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 *panel)
{
CcBackgroundItem *current_background;
current_background = panel->current_background;
cc_background_preview_set_item (panel->default_preview, current_background);
cc_background_preview_set_item (panel->dark_preview, current_background);
cc_background_preview_set_item (panel->desktop_preview, current_background);
}
static gchar *
@@ -203,7 +91,6 @@ reload_current_bg (CcBackgroundPanel *panel)
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;
@@ -217,15 +104,12 @@ reload_current_bg (CcBackgroundPanel *panel)
if (uri && *uri == '\0')
g_clear_pointer (&uri, g_free);
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,
@@ -272,8 +156,7 @@ create_save_dir (void)
static void
set_background (CcBackgroundPanel *panel,
GSettings *settings,
CcBackgroundItem *item,
gboolean set_dark)
CcBackgroundItem *item)
{
GDesktopBackgroundStyle style;
CcBackgroundItemFlags flags;
@@ -288,18 +171,6 @@ set_background (CcBackgroundPanel *panel,
g_settings_set_string (settings, WP_URI_KEY, uri);
if (set_dark)
{
const char *uri_dark;
uri_dark = cc_background_item_get_uri_dark (item);
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);
}
/* Also set the placement if we have a URI and the previous value was none */
if (flags & CC_BACKGROUND_ITEM_HAS_PLACEMENT)
{
@@ -327,12 +198,13 @@ set_background (CcBackgroundPanel *panel,
cc_background_xml_save (panel->current_background, filename);
}
static void
on_chooser_background_chosen_cb (CcBackgroundPanel *self,
CcBackgroundItem *item)
on_chooser_background_chosen_cb (CcBackgroundPanel *self,
CcBackgroundItem *item)
{
set_background (self, self->settings, item, TRUE);
set_background (self, self->lock_settings, item, FALSE);
set_background (self, self->settings, item);
set_background (self, self->lock_settings, item);
}
static void
@@ -347,6 +219,20 @@ cc_background_panel_get_help_uri (CcPanel *panel)
return "help:gnome-help/look-background";
}
static void
cc_background_panel_constructed (GObject *object)
{
CcBackgroundPanel *self;
CcShell *shell;
self = CC_BACKGROUND_PANEL (object);
shell = cc_panel_get_shell (CC_PANEL (self));
cc_shell_embed_widget_in_header (shell, GTK_WIDGET (self->add_picture_button), GTK_POS_RIGHT);
G_OBJECT_CLASS (cc_background_panel_parent_class)->constructed (object);
}
static void
cc_background_panel_dispose (GObject *object)
{
@@ -354,9 +240,7 @@ cc_background_panel_dispose (GObject *object)
g_clear_object (&panel->settings);
g_clear_object (&panel->lock_settings);
g_clear_object (&panel->interface_settings);
g_clear_object (&panel->thumb_factory);
g_clear_object (&panel->proxy);
G_OBJECT_CLASS (cc_background_panel_parent_class)->dispose (object);
}
@@ -383,18 +267,16 @@ cc_background_panel_class_init (CcBackgroundPanelClass *klass)
panel_class->get_help_uri = cc_background_panel_get_help_uri;
object_class->constructed = cc_background_panel_constructed;
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, add_picture_button);
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_child (widget_class, CcBackgroundPanel, desktop_preview);
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);
}
@@ -423,33 +305,10 @@ cc_background_panel_init (CcBackgroundPanel *panel)
panel->lock_settings = g_settings_new (WP_LOCK_PATH_ID);
g_settings_delay (panel->lock_settings);
panel->interface_settings = g_settings_new (INTERFACE_PATH_ID);
/* Load the background */
reload_current_bg (panel);
update_preview (panel);
/* Background settings */
g_signal_connect_object (panel->settings, "changed", G_CALLBACK (on_settings_changed), panel, G_CONNECT_SWAPPED);
/* Interface settings */
reload_color_scheme_toggles (panel);
g_signal_connect_object (panel->interface_settings,
"changed::" INTERFACE_COLOR_SCHEME_KEY,
G_CALLBACK (reload_color_scheme_toggles),
panel,
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,
panel);
load_custom_css (panel);
}

View File

@@ -1,134 +1,58 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<!-- interface-requires gtk+ 3.0 -->
<template class="CcBackgroundPanel" parent="CcPanel">
<child type="content">
<object class="AdwPreferencesPage">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<child>
<object class="AdwPreferencesGroup">
<property name="title" translatable="yes">Style</property>
<object class="HdyClamp">
<property name="visible">1</property>
<property name="maximum_size">300</property>
<property name="tightening_threshold">200</property>
<child>
<object class="AdwPreferencesRow">
<property name="activatable">False</property>
<property name="focusable">False</property>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="spacing">24</property>
<property name="margin-start">12</property>
<property name="margin-end">12</property>
<property name="margin-top">18</property>
<property name="margin-bottom">18</property>
<property name="hexpand">True</property>
<child>
<object class="AdwClamp">
<property name="maximum_size">400</property>
<property name="tightening_threshold">300</property>
<child>
<object class="GtkGrid">
<property name="column-homogeneous">True</property>
<property name="column-spacing">24</property>
<property name="row-spacing">12</property>
<property name="margin-start">12</property>
<property name="margin-end">12</property>
<property name="margin-top">18</property>
<property name="margin-bottom">12</property>
<property name="hexpand">True</property>
<child>
<object class="GtkToggleButton" id="default_toggle">
<accessibility>
<relation name="labelled-by">default_label</relation>
</accessibility>
<signal name="notify::active" handler="on_color_scheme_toggle_active_cb" swapped="true"/>
<child>
<object class="CcBackgroundPreview" id="default_preview"/>
</child>
<style>
<class name="background-preview-button"/>
</style>
<layout>
<property name="column">0</property>
<property name="row">0</property>
</layout>
</object>
</child>
<child>
<object class="GtkLabel" id="default_label">
<property name="label" translatable="yes">Default</property>
<layout>
<property name="column">0</property>
<property name="row">1</property>
</layout>
</object>
</child>
<child>
<object class="GtkToggleButton" id="dark_toggle">
<property name="group">default_toggle</property>
<accessibility>
<relation name="labelled-by">dark_label</relation>
</accessibility>
<signal name="notify::active" handler="on_color_scheme_toggle_active_cb" swapped="true"/>
<child>
<object class="CcBackgroundPreview" id="dark_preview">
<property name="is-dark">True</property>
</object>
</child>
<style>
<class name="background-preview-button"/>
</style>
<layout>
<property name="column">1</property>
<property name="row">0</property>
</layout>
</object>
</child>
<child>
<object class="GtkLabel" id="dark_label">
<property name="label" translatable="yes">Dark</property>
<layout>
<property name="column">1</property>
<property name="row">1</property>
</layout>
</object>
</child>
</object>
</child>
<object class="CcBackgroundPreview" id="desktop_preview">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="valign">center</property>
</object>
</child>
</object>
</child>
</object>
</child>
<child>
<object class="AdwPreferencesGroup">
<property name="title" translatable="yes">Background</property>
<property name="header-suffix">
<object class="GtkButton">
<child>
<object class="AdwButtonContent">
<property name="icon-name">list-add-symbolic</property>
<property name="label" translatable="yes">Add Picture…</property>
</object>
</child>
<signal name="clicked" handler="on_add_picture_button_clicked_cb" object="CcBackgroundPanel" swapped="yes" />
<style>
<class name="flat"/>
</style>
</object>
</property>
<child>
<object class="AdwBin">
<style>
<class name="card"/>
</style>
<child>
<object class="CcBackgroundChooser" id="background_chooser">
<property name="hexpand">True</property>
<signal name="background-chosen" handler="on_chooser_background_chosen_cb" object="CcBackgroundPanel" swapped="yes" />
</object>
</child>
</object>
</child>
<object class="CcBackgroundChooser" id="background_chooser">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="expand">True</property>
<signal name="background-chosen" handler="on_chooser_background_chosen_cb" object="CcBackgroundPanel" swapped="yes" />
</object>
</child>
</object>
</child>
</template>
<!-- Header button -->
<object class="GtkButton" id="add_picture_button">
<property name="visible">True</property>
<property name="label" translatable="yes">Add Picture…</property>
<signal name="clicked" handler="on_add_picture_button_clicked_cb" object="CcBackgroundPanel" swapped="yes" />
</object>
</interface>

View File

@@ -24,105 +24,180 @@
struct _CcBackgroundPreview
{
GtkWidget parent;
GtkBox parent;
GtkWidget *drawing_area;
GtkWidget *light_dark_window;
GtkWidget *dark_window;
GtkImage *animated_background_icon;
GtkLabel *desktop_clock_label;
GtkFrame *desktop_frame;
GtkDrawingArea *drawing_area;
GtkFrame *lock_frame;
GtkLabel *lock_screen_label;
GtkStack *stack;
GnomeDesktopThumbnailFactory *thumbnail_factory;
gboolean is_dark;
CcBackgroundItem *item;
GSettings *desktop_settings;
guint lock_screen_time_timeout_id;
gboolean is_lock_screen;
GDateTime *previous_time;
gboolean is_24h_format;
};
G_DEFINE_TYPE (CcBackgroundPreview, cc_background_preview, GTK_TYPE_WIDGET)
G_DEFINE_TYPE (CcBackgroundPreview, cc_background_preview, GTK_TYPE_BOX)
enum
{
PROP_0,
PROP_IS_DARK,
PROP_IS_LOCK_SCREEN,
PROP_ITEM,
N_PROPS
};
static GParamSpec *properties [N_PROPS];
/* Callbacks */
/* Auxiliary methods */
static void
draw_preview_func (GtkDrawingArea *drawing_area,
cairo_t *cr,
gint width,
gint height,
gpointer user_data)
update_lock_screen_label (CcBackgroundPreview *self,
gboolean force)
{
g_autoptr(GDateTime) now = NULL;
g_autofree gchar *label = NULL;
now = g_date_time_new_now_local ();
/* Don't update the label if the hour:minute pair did not change */
if (!force && self->previous_time &&
g_date_time_get_hour (now) == g_date_time_get_hour (self->previous_time) &&
g_date_time_get_minute (now) == g_date_time_get_minute (self->previous_time))
{
return;
}
if (self->is_24h_format)
label = g_date_time_format (now, "%R");
else
label = g_date_time_format (now, "%I:%M %p");
gtk_label_set_label (self->lock_screen_label, label);
gtk_label_set_label (self->desktop_clock_label, label);
g_clear_pointer (&self->previous_time, g_date_time_unref);
self->previous_time = g_steal_pointer (&now);
}
static void
update_clock_format (CcBackgroundPreview *self)
{
g_autofree gchar *clock_format = NULL;
gboolean is_24h_format;
clock_format = g_settings_get_string (self->desktop_settings, "clock-format");
is_24h_format = g_strcmp0 (clock_format, "24h") == 0;
if (is_24h_format != self->is_24h_format)
{
self->is_24h_format = is_24h_format;
update_lock_screen_label (self, TRUE);
}
}
static void
load_custom_css (CcBackgroundPreview *self)
{
g_autoptr(GtkCssProvider) provider = NULL;
/* use custom CSS */
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_screen (gdk_screen_get_default (),
GTK_STYLE_PROVIDER (provider),
GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
}
static gboolean
update_clock_cb (gpointer data)
{
CcBackgroundPreview *self = data;
update_lock_screen_label (self, FALSE);
return G_SOURCE_CONTINUE;
}
static void
start_monitor_time (CcBackgroundPreview *self)
{
if (self->lock_screen_time_timeout_id > 0)
return;
self->lock_screen_time_timeout_id = g_timeout_add_seconds (1,
update_clock_cb,
self);
}
static void
stop_monitor_time (CcBackgroundPreview *self)
{
if (self->lock_screen_time_timeout_id > 0)
{
g_source_remove (self->lock_screen_time_timeout_id);
self->lock_screen_time_timeout_id = 0;
}
}
/* Callbacks */
static gboolean
on_preview_draw_cb (CcBackgroundPreview *self,
cairo_t *cr)
{
CcBackgroundPreview *self = CC_BACKGROUND_PREVIEW (user_data);
g_autoptr(GdkPixbuf) pixbuf = NULL;
GtkAllocation allocation;
gint scale_factor;
if (!self->item)
return;
return FALSE;
scale_factor = gtk_widget_get_scale_factor (GTK_WIDGET (drawing_area));
scale_factor = gtk_widget_get_scale_factor (GTK_WIDGET (self->drawing_area));
gtk_widget_get_allocation (GTK_WIDGET (self->drawing_area), &allocation);
pixbuf = cc_background_item_get_frame_thumbnail (self->item,
self->thumbnail_factory,
width,
height,
allocation.width,
allocation.height,
scale_factor,
0,
TRUE,
self->is_dark &&
cc_background_item_has_dark_version (self->item));
TRUE);
gdk_cairo_set_source_pixbuf (cr, pixbuf, 0, 0);
cairo_paint (cr);
return TRUE;
}
/* GObject overrides */
static void
cc_background_preview_dispose (GObject *object)
{
CcBackgroundPreview *self = (CcBackgroundPreview *)object;
g_clear_pointer (&self->drawing_area, gtk_widget_unparent);
g_clear_pointer (&self->light_dark_window, gtk_widget_unparent);
g_clear_pointer (&self->dark_window, gtk_widget_unparent);
G_OBJECT_CLASS (cc_background_preview_parent_class)->dispose (object);
}
static void
cc_background_preview_finalize (GObject *object)
{
CcBackgroundPreview *self = (CcBackgroundPreview *)object;
g_clear_object (&self->desktop_settings);
g_clear_object (&self->item);
g_clear_object (&self->thumbnail_factory);
g_clear_pointer (&self->previous_time, g_date_time_unref);
stop_monitor_time (self);
G_OBJECT_CLASS (cc_background_preview_parent_class)->finalize (object);
}
static void
set_is_dark (CcBackgroundPreview *self,
gboolean is_dark)
{
self->is_dark = is_dark;
if (self->is_dark)
{
gtk_widget_add_css_class (self->light_dark_window, "dark");
gtk_widget_remove_css_class (self->light_dark_window, "light");
}
else
{
gtk_widget_add_css_class (self->light_dark_window, "light");
gtk_widget_remove_css_class (self->light_dark_window, "dark");
}
}
static void
cc_background_preview_get_property (GObject *object,
guint prop_id,
@@ -133,8 +208,8 @@ cc_background_preview_get_property (GObject *object,
switch (prop_id)
{
case PROP_IS_DARK:
g_value_set_boolean (value, self->is_dark);
case PROP_IS_LOCK_SCREEN:
g_value_set_boolean (value, self->is_lock_screen);
break;
case PROP_ITEM:
@@ -156,8 +231,10 @@ cc_background_preview_set_property (GObject *object,
switch (prop_id)
{
case PROP_IS_DARK:
set_is_dark (self, g_value_get_boolean (value));
case PROP_IS_LOCK_SCREEN:
self->is_lock_screen = g_value_get_boolean (value);
gtk_stack_set_visible_child (self->stack,
self->is_lock_screen ? GTK_WIDGET (self->lock_frame) : GTK_WIDGET (self->desktop_frame));
break;
case PROP_ITEM:
@@ -175,108 +252,47 @@ cc_background_preview_get_request_mode (GtkWidget *widget)
return GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH;
}
static void
get_primary_monitor_geometry (int *width, int *height)
static gfloat
get_primary_monitor_aspect_ratio (void)
{
GdkDisplay *display;
GListModel *monitors;
GdkMonitor *primary_monitor;
gfloat aspect_ratio;
display = gdk_display_get_default ();
primary_monitor = gdk_display_get_primary_monitor (display);
aspect_ratio = 16.0 / 9.0;
monitors = gdk_display_get_monitors (display);
if (monitors)
if (primary_monitor)
{
g_autoptr(GdkMonitor) primary_monitor = NULL;
GdkRectangle monitor_layout;
primary_monitor = g_list_model_get_item (monitors, 0);
gdk_monitor_get_geometry (primary_monitor, &monitor_layout);
if (width)
*width = monitor_layout.width;
if (height)
*height = monitor_layout.height;
return;
aspect_ratio = monitor_layout.width / (gfloat) monitor_layout.height;
}
if (width)
*width = 1920;
if (height)
*height = 1080;
return aspect_ratio;
}
static void
cc_background_preview_measure (GtkWidget *widget,
GtkOrientation orientation,
gint for_size,
gint *minimum,
gint *natural,
gint *minimum_baseline,
gint *natural_baseline)
cc_background_preview_get_preferred_height_for_width (GtkWidget *widget,
gint width,
gint *minimum,
gint *natural)
{
GtkWidget *child;
int width;
gfloat aspect_ratio = get_primary_monitor_aspect_ratio ();
get_primary_monitor_geometry (&width, NULL);
if (orientation == GTK_ORIENTATION_HORIZONTAL)
*natural = width;
else if (for_size < 0)
*natural = 0;
else
*natural = floor ((double) for_size * 0.75); /* 4:3 aspect ratio */
if (orientation == GTK_ORIENTATION_VERTICAL)
*minimum = *natural;
else
*minimum = 0;
for (child = gtk_widget_get_first_child (widget);
child;
child = gtk_widget_get_next_sibling (child))
{
int child_min, child_nat;
gtk_widget_measure (child, orientation, for_size,
&child_min, &child_nat, NULL, NULL);
*minimum = MAX (*minimum, child_min);
*natural = MAX (*natural, child_nat);
}
*minimum = *natural = MAX (2, width / aspect_ratio);
}
static void
cc_background_preview_size_allocate (GtkWidget *widget,
gint width,
gint height,
gint baseline)
cc_background_preview_get_preferred_width_for_height (GtkWidget *widget,
gint height,
gint *minimum,
gint *natural)
{
CcBackgroundPreview *self = CC_BACKGROUND_PREVIEW (widget);
int window_width, window_height, margin_x, margin_y;
int opposite_margin_x, opposite_margin_y;
GskTransform *front_transform, *back_transform;
gboolean is_rtl;
gfloat aspect_ratio = get_primary_monitor_aspect_ratio ();
window_width = ceil (width * 0.5);
window_height = ceil (height * 0.5);
margin_x = floor (width * 0.15);
margin_y = floor (height * 0.15);
opposite_margin_x = width - window_width - margin_x;
opposite_margin_y = height - window_height - margin_y;
is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
front_transform =
gsk_transform_translate (NULL, &GRAPHENE_POINT_INIT (is_rtl ? opposite_margin_x : margin_x,
opposite_margin_y));
back_transform =
gsk_transform_translate (NULL, &GRAPHENE_POINT_INIT (is_rtl ? margin_x : opposite_margin_x,
margin_y));
gtk_widget_allocate (self->drawing_area, width, height, baseline, NULL);
gtk_widget_allocate (self->dark_window, window_width, window_height,
baseline, back_transform);
gtk_widget_allocate (self->light_dark_window, window_width, window_height,
baseline, front_transform);
*minimum = *natural = MAX (2, height * aspect_ratio);
}
static void
@@ -285,20 +301,19 @@ cc_background_preview_class_init (CcBackgroundPreviewClass *klass)
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
object_class->dispose = cc_background_preview_dispose;
object_class->finalize = cc_background_preview_finalize;
object_class->get_property = cc_background_preview_get_property;
object_class->set_property = cc_background_preview_set_property;
widget_class->get_request_mode = cc_background_preview_get_request_mode;
widget_class->measure = cc_background_preview_measure;
widget_class->size_allocate = cc_background_preview_size_allocate;
widget_class->get_preferred_height_for_width = cc_background_preview_get_preferred_height_for_width;
widget_class->get_preferred_width_for_height = cc_background_preview_get_preferred_width_for_height;
properties[PROP_IS_DARK] = g_param_spec_boolean ("is-dark",
"Is dark",
"Whether the preview is dark",
FALSE,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
properties[PROP_IS_LOCK_SCREEN] = g_param_spec_boolean ("is-lock-screen",
"Lock screen",
"Whether the preview is of the lock screen",
FALSE,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
properties[PROP_ITEM] = g_param_spec_object ("item",
"Item",
@@ -310,11 +325,15 @@ cc_background_preview_class_init (CcBackgroundPreviewClass *klass)
gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/control-center/background/cc-background-preview.ui");
gtk_widget_class_bind_template_child (widget_class, CcBackgroundPreview, animated_background_icon);
gtk_widget_class_bind_template_child (widget_class, CcBackgroundPreview, desktop_clock_label);
gtk_widget_class_bind_template_child (widget_class, CcBackgroundPreview, desktop_frame);
gtk_widget_class_bind_template_child (widget_class, CcBackgroundPreview, drawing_area);
gtk_widget_class_bind_template_child (widget_class, CcBackgroundPreview, light_dark_window);
gtk_widget_class_bind_template_child (widget_class, CcBackgroundPreview, dark_window);
gtk_widget_class_bind_template_child (widget_class, CcBackgroundPreview, lock_frame);
gtk_widget_class_bind_template_child (widget_class, CcBackgroundPreview, lock_screen_label);
gtk_widget_class_bind_template_child (widget_class, CcBackgroundPreview, stack);
gtk_widget_class_set_css_name (widget_class, "background-preview");
gtk_widget_class_bind_template_callback (widget_class, on_preview_draw_cb);
}
static void
@@ -323,6 +342,17 @@ cc_background_preview_init (CcBackgroundPreview *self)
gtk_widget_init_template (GTK_WIDGET (self));
self->thumbnail_factory = gnome_desktop_thumbnail_factory_new (GNOME_DESKTOP_THUMBNAIL_SIZE_LARGE);
self->desktop_settings = g_settings_new ("org.gnome.desktop.interface");
g_signal_connect_object (self->desktop_settings,
"changed::clock-format",
G_CALLBACK (update_clock_format),
self,
G_CONNECT_SWAPPED);
update_clock_format (self);
load_custom_css (self);
start_monitor_time (self);
}
CcBackgroundItem*
@@ -343,9 +373,10 @@ cc_background_preview_set_item (CcBackgroundPreview *self,
if (!g_set_object (&self->item, item))
return;
gtk_drawing_area_set_draw_func (GTK_DRAWING_AREA (self->drawing_area),
draw_preview_func, self, NULL);
gtk_widget_queue_draw (self->drawing_area);
gtk_widget_set_visible (GTK_WIDGET (self->animated_background_icon),
cc_background_item_changes_with_time (item));
gtk_widget_queue_draw (GTK_WIDGET (self->drawing_area));
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_ITEM]);
}

View File

@@ -27,7 +27,7 @@
G_BEGIN_DECLS
#define CC_TYPE_BACKGROUND_PREVIEW (cc_background_preview_get_type())
G_DECLARE_FINAL_TYPE (CcBackgroundPreview, cc_background_preview, CC, BACKGROUND_PREVIEW, GtkWidget)
G_DECLARE_FINAL_TYPE (CcBackgroundPreview, cc_background_preview, CC, BACKGROUND_PREVIEW, GtkBox)
CcBackgroundItem* cc_background_preview_get_item (CcBackgroundPreview *self);
void cc_background_preview_set_item (CcBackgroundPreview *self,

View File

@@ -1,55 +1,152 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<!-- interface-requires gtk+ 3.0 -->
<template class="CcBackgroundPreview" parent="GtkWidget">
<property name="overflow">hidden</property>
<property name="width-request">2</property>
<property name="height-request">2</property>
<template class="CcBackgroundPreview" parent="GtkBox">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="hexpand">True</property>
<property name="vexpand">False</property>
<style>
<class name="frame" />
</style>
<!-- Wallpaper -->
<child>
<object class="GtkDrawingArea" id="drawing_area"/>
</child>
<object class="GtkOverlay">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="hexpand">True</property>
<!-- Always dark window -->
<child>
<object class="AdwBin" id="dark_window">
<property name="overflow">hidden</property>
<style>
<class name="window"/>
<class name="back"/>
<class name="dark"/>
</style>
<!-- Wallpaper -->
<child>
<object class="AdwBin">
<style>
<class name="header-bar"/>
</style>
<property name="valign">start</property>
<object class="GtkDrawingArea" id="drawing_area">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="expand">True</property>
<signal name="draw" handler="on_preview_draw_cb" object="CcBackgroundPreview" swapped="yes" />
</object>
</child>
</object>
</child>
<!-- Light/dark window -->
<child>
<object class="AdwBin" id="light_dark_window">
<property name="overflow">hidden</property>
<style>
<class name="window"/>
<class name="front"/>
<class name="light"/>
</style>
<child>
<object class="AdwBin">
<style>
<class name="header-bar"/>
</style>
<property name="valign">start</property>
<!-- Desktop / Lock Screen widgets -->
<child type="overlay">
<object class="GtkStack" id="stack">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="expand">True</property>
<child>
<object class="GtkFrame" id="desktop_frame">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="shadow-type">none</property>
<property name="valign">start</property>
<style>
<class name="desktop-preview" />
</style>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can-focus">False</property>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">Activities</property>
</object>
</child>
<child type="center">
<object class="GtkLabel" id="desktop_clock_label">
<property name="visible">True</property>
<property name="can-focus">False</property>
</object>
</child>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="spacing">4</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="icon-name">network-wireless-symbolic</property>
<property name="pixel-size">6</property>
</object>
</child>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="icon-name">audio-volume-high-symbolic</property>
<property name="pixel-size">6</property>
</object>
</child>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="icon-name">battery-low-symbolic</property>
<property name="pixel-size">6</property>
</object>
</child>
</object>
<packing>
<property name="pack-type">end</property>
</packing>
</child>
</object>
</child>
</object>
</child>
<child>
<object class="GtkFrame" id="lock_frame">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="shadow-type">none</property>
<child>
<object class="GtkLabel" id="lock_screen_label">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="expand">True</property>
<property name="xalign">0.5</property>
<property name="yalign">0.5</property>
</object>
</child>
<style>
<class name="lock-screen-preview" />
</style>
</object>
</child>
</object>
</child>
<!-- Wallpaper -->
<child type="overlay">
<object class="GtkImage" id="animated_background_icon">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="halign">end</property>
<property name="valign">end</property>
<property name="margin-end">8</property>
<property name="margin-bottom">8</property>
<property name="pixel-size">16</property>
<property name="icon-name">slideshow-emblem</property>
<style>
<class name="slideshow-icon" />
</style>
</object>
</child>
</object>
</child>
</template>
</interface>

View File

@@ -210,27 +210,6 @@ cc_background_xml_load_xml_internal (CcBackgroundXml *xml,
} else {
break;
}
} else if (!strcmp ((gchar *)wpa->name, "filename-dark")) {
if (wpa->last != NULL && wpa->last->content != NULL) {
gchar *content = g_strstrip ((gchar *)wpa->last->content);
g_autofree gchar *bg_uri = NULL;
/* FIXME same rubbish as in other parts of the code */
if (strcmp (content, NONE) == 0) {
bg_uri = NULL;
} else {
g_autoptr(GFile) file = NULL;
g_autofree gchar *dirname = NULL;
dirname = g_path_get_dirname (filename);
file = g_file_new_for_commandline_arg_and_cwd (content, dirname);
bg_uri = g_file_get_uri (file);
}
SET_FLAG(CC_BACKGROUND_ITEM_HAS_URI_DARK);
g_object_set (G_OBJECT (item), "uri-dark", bg_uri, NULL);
} else {
break;
}
} else if (!strcmp ((gchar *)wpa->name, "name")) {
if (wpa->last != NULL && wpa->last->content != NULL) {
g_autofree gchar *name = NULL;

View File

@@ -1,14 +1,14 @@
[Desktop Entry]
Name=Appearance
Comment=Change your background image or the UI colors
Name=Background
Comment=Change your background image to a wallpaper or photo
Exec=gnome-control-center background
# Translators: Do NOT translate or transliterate this text (this is an icon file name)!
Icon=org.gnome.Settings-appearance-symbolic
Icon=preferences-desktop-wallpaper
Terminal=false
Type=Application
NoDisplay=true
StartupNotify=true
Categories=GNOME;GTK;Settings;DesktopSettings;X-GNOME-Settings-Panel;X-GNOME-PersonalizationSettings;
OnlyShowIn=GNOME;
# Translators: Search terms to find the Appearance panel. Do NOT translate or localize the semicolons! The list MUST also end with a semicolon!
Keywords=Background;Wallpaper;Screen;Desktop;Style;Light;Dark;Appearance;
# Translators: Search terms to find the Background panel. Do NOT translate or localize the semicolons! The list MUST also end with a semicolon!
Keywords=Wallpaper;Screen;Desktop;

View File

@@ -1,4 +0,0 @@
install_data(
'scalable/org.gnome.Settings-appearance-symbolic.svg',
install_dir: join_paths(control_center_icondir, 'hicolor', 'scalable', 'apps')
)

View File

@@ -1,9 +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">
<g fill="#2e3436">
<path d="m 3.011719 1 c -1.644531 0 -3.0000002 1.355469 -3.0000002 3 v 6 c 0 1.644531 1.3554692 3 3.0000002 3 h 10 c 1.644531 0 3 -1.355469 3 -3 v -6 c 0 -0.570312 -0.167969 -1.101562 -0.449219 -1.558594 l -1.550781 1.554688 v 6.003906 c 0 0.570312 -0.429688 1 -1 1 h -10 c -0.570313 0 -1 -0.429688 -1 -1 v -6 c 0 -0.570312 0.429687 -1 1 -1 h 5.96875 l 2.007812 -2 z m 0 0"/>
<path d="m 11.011719 7 c 0 1.65625 -1.339844 3.007812 -3 3 h -3 v -3 c 0 -1.660156 1.34375 -3 3 -3 c 1.660156 0 3 1.339844 3 3 z m 0 0"/>
<path d="m 13.410156 0 l -3.46875 3.457031 c 0.683594 0.355469 1.234375 0.910157 1.589844 1.589844 l 0.171875 -0.171875 l 0.007813 0.007812 l 4.300781 -4.300781 v -0.582031 z m 0 0"/>
<path d="m 5.011719 14 c -1.105469 0 -2 0.894531 -2 2 h 10 c 0 -1.105469 -0.894531 -2 -2 -2 z m 0 0"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 999 B

View File

@@ -16,6 +16,16 @@ i18n.merge_file(
install_dir: control_center_desktopdir
)
install_data(
'slideshow-symbolic.svg',
install_dir: join_paths(control_center_icondir, 'hicolor', 'scalable', 'categories')
)
install_data(
'slideshow-emblem.svg',
install_dir: join_paths(control_center_icondir, 'hicolor', 'scalable', 'emblems')
)
install_data(
'noise-texture-light.png',
install_dir: join_paths(control_center_pkgdatadir, 'pixmaps')
@@ -65,12 +75,13 @@ common_sources += gnome.compile_resources(
sources = common_sources + files(
'bg-colors-source.c',
'bg-pictures-source.c',
'bg-recent-source.c',
'bg-source.c',
'bg-wallpapers-source.c',
'cc-background-chooser.c',
'cc-background-grilo-miner.c',
'cc-background-item.c',
'cc-background-paintable.c',
'cc-background-panel.c',
'cc-background-preview.c',
'cc-background-xml.c',
@@ -78,9 +89,11 @@ sources = common_sources + files(
deps = common_deps + [
gdk_pixbuf_dep,
gnome_bg_dep,
gnome_desktop_dep,
goa_dep,
libxml_dep,
dependency('cairo-gobject'),
dependency('grilo-0.3', version: '>= 0.3.0')
]
cflags += [
@@ -88,6 +101,10 @@ cflags += [
'-DGNOME_DESKTOP_USE_UNSTABLE_API'
]
if gnome_desktop_dep.version().version_compare('>=3.35.4')
cflags += '-DGNOME_DESKTOP_BG_API_BREAK'
endif
panels_libs += static_library(
cappletname,
sources: sources,
@@ -95,5 +112,3 @@ panels_libs += static_library(
dependencies: deps,
c_args: cflags,
)
subdir('icons')

View File

@@ -1,96 +1,40 @@
background-preview {
border-radius: 6px;
frame.desktop-preview {
min-height: 10px;
padding: 0 4px;
background-color: black;
}
background-preview .window {
border-radius: 6px;
box-shadow: 0 1px 4px 1px alpha(black, 0.13),
0 1px 10px 5px alpha(black, 0.09),
0 3px 16px 8px alpha(black, 0.04),
0 0 0 1px alpha(black, .05);
}
background-preview .window .header-bar {
min-height: 15px;
}
background-preview .window.light {
background-color: #fafafa;
color: alpha(black, .8);
}
background-preview .window.light .header-bar {
box-shadow: inset 0 -1px alpha(black, .07);
}
background-preview .window.front.light .header-bar {
background-color: #ebebeb;
}
background-preview .window.dark {
background-color: #242424;
frame.desktop-preview image {
color: white;
}
background-preview .window.dark .header-bar {
box-shadow: inset 0 -1px alpha(black, .36);
frame.desktop-preview label {
color: white;
font-weight: bold;
font-size: 6px;
}
background-preview .window.front.dark .header-bar {
background-color: #303030;
frame.lock-screen-preview {
border: solid rgba(0, 0, 0, 0.33);
border-width: 10px 0 0 0;
}
.background-preview-button {
background: none;
border-radius: 9px;
padding: 3px;
box-shadow: none;
outline: none;
frame.lock-screen-preview label {
color: white;
font-weight: bold;
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.6);
font-size: 1.2em;
}
.background-preview-button:checked {
box-shadow: 0 0 0 3px @accent_color;
}
.background-preview-button:focus:focus-visible {
box-shadow: 0 0 0 3px alpha(@accent_color, .3);
}
.background-preview-button:checked:focus:focus-visible {
box-shadow: 0 0 0 3px @accent_color, 0 0 0 6px alpha(@accent_color, .3);
}
.background-flowbox > flowboxchild {
background: none;
border-radius: 9px;
}
.background-thumbnail {
border-radius: 6px;
}
.slideshow-icon {
image.slideshow-icon {
color: white;
-gtk-icon-shadow: 0 1px 2px rgba(0, 0, 0, 0.33);
margin: 8px;
}
.selected-check {
color: @accent_fg_color;
background: @accent_bg_color;
border-radius: 100px;
padding: 2px;
opacity: 0;
margin: 6px;
}
flowboxchild:selected .selected-check {
opacity: 1;
}
.remove-button {
padding: 2px;
min-width: 0;
min-height: 0;
margin: 6px;
button.remove-button {
border-radius: 9999px;
-gtk-outline-radius: 9999px;
padding: 1px 0px; /* circles instead of ellipses */
background-origin: padding-box, border-box;
background-clip: padding-box, border-box;
}

View File

@@ -0,0 +1,104 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="128"
height="128"
id="svg4978"
version="1.1"
inkscape:version="0.48.0 r9654"
sodipodi:docname="slideshow-emblem.svg">
<defs
id="defs4980" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="0.98994949"
inkscape:cx="41.944792"
inkscape:cy="39.155574"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
inkscape:window-width="962"
inkscape:window-height="817"
inkscape:window-x="4"
inkscape:window-y="51"
inkscape:window-maximized="0" />
<metadata
id="metadata4983">
<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 />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(0,-924.36215)">
<g
style="display:inline"
id="g14317"
transform="matrix(7.1989829,0,0,7.1989829,-772.01578,-783.40043)">
<g
style="stroke:#000000;stroke-opacity:1"
transform="translate(69,-449)"
id="g14258"
inkscape:label="document-open-recent">
<path
sodipodi:type="arc"
style="color:#000000;fill:none;stroke:#000000;stroke-width:2.15384626;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
id="path14260"
sodipodi:cx="48"
sodipodi:cy="696"
sodipodi:rx="7"
sodipodi:ry="7"
d="m 55,696 c 0,3.86599 -3.134007,7 -7,7 -3.865993,0 -7,-3.13401 -7,-7 0,-3.86599 3.134007,-7 7,-7 3.865993,0 7,3.13401 7,7 z"
transform="matrix(0.92857143,0,0,0.92857143,2.9285714,49.21429)" />
<path
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
d="m 45.5,693.5 2,2 3,-3"
id="path14262"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccc" />
</g>
<g
inkscape:label="document-open-recent"
id="g4692"
transform="translate(69,-450)">
<path
transform="matrix(0.92857143,0,0,0.92857143,2.9285714,49.21429)"
d="m 55,696 c 0,3.86599 -3.134007,7 -7,7 -3.865993,0 -7,-3.13401 -7,-7 0,-3.86599 3.134007,-7 7,-7 3.865993,0 7,3.13401 7,7 z"
sodipodi:ry="7"
sodipodi:rx="7"
sodipodi:cy="696"
sodipodi:cx="48"
id="path3869"
style="color:#000000;fill:none;stroke:#ffffff;stroke-width:2.15384626;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
sodipodi:type="arc" />
<path
sodipodi:nodetypes="ccc"
inkscape:connector-curvature="0"
id="path4639"
d="m 45.5,693.5 2,2 3,-3"
style="fill:none;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.9 KiB

View File

@@ -1 +1,70 @@
<svg width="16" height="16" xmlns="http://www.w3.org/2000/svg"><path d="M7.486.02A7.492 7.492 0 0 0 0 7.508a7.492 7.492 0 0 0 7.486 7.484 7.492 7.492 0 0 0 7.487-7.484A7.492 7.492 0 0 0 7.486.02zm0 1.972A5.508 5.508 0 0 1 13 7.508a5.508 5.508 0 0 1-5.514 5.512 5.508 5.508 0 0 1-5.513-5.512 5.508 5.508 0 0 1 5.513-5.516zm3.01 2.01a.5.5 0 0 0-.103.006.5.5 0 0 0-.25.154L7.486 6.818 5.83 5.162a.5.5 0 1 0-.687.688l2 2a.5.5 0 0 0 .687 0l3-3a.5.5 0 0 0-.334-.848z" style="fill:#000"/></svg>
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="16"
height="16"
id="svg5594"
version="1.1"
inkscape:version="0.48.0 r9654"
sodipodi:docname="slideshow-emblem-symbolic.svg">
<defs
id="defs5596" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="22.4"
inkscape:cx="10.858512"
inkscape:cy="10.780448"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
inkscape:window-width="789"
inkscape:window-height="774"
inkscape:window-x="4"
inkscape:window-y="51"
inkscape:window-maximized="0" />
<metadata
id="metadata5599">
<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 />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(0,-1036.3622)">
<g
id="g3763"
transform="matrix(0.86221939,0,0,0.86221939,1.0303599,144.13347)">
<path
inkscape:connector-curvature="0"
id="path14584"
d="m 7.9642862,1038.3322 c -3.3085937,0 -5.9942603,2.6857 -5.9942603,5.9943 0,3.3086 2.6856666,5.9942 5.9942603,5.9942 3.3085938,0 5.9942608,-2.6856 5.9942608,-5.9942 0,-3.3086 -2.685667,-5.9943 -5.9942608,-5.9943 z m 0,0.8457 c 2.8454368,0 5.1485968,2.3031 5.1485968,5.1486 0,2.8454 -2.30316,5.1486 -5.1485968,5.1486 -2.8454368,0 -5.148597,-2.3032 -5.148597,-5.1486 0,-2.8455 2.3031602,-5.1486 5.148597,-5.1486 z"
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;baseline-shift:baseline;color:#000000;fill:#808080;fill-opacity:1;stroke:none;stroke-width:1.0767436;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;font-family:Sans;-inkscape-font-specification:Sans" />
<path
inkscape:connector-curvature="0"
id="path14586"
d="m 10.5,1041.3125 a 0.42854288,0.42854288 0 0 0 -0.28125,0.125 l -2.25,2.2813 -1.40625,-1.4063 a 0.4310176,0.4310176 0 1 0 -0.625,0.5937 l 1.71875,1.7188 a 0.42854288,0.42854288 0 0 0 0.625,0 l 2.5625,-2.5625 a 0.42854288,0.42854288 0 0 0 -0.34375,-0.75 z"
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;baseline-shift:baseline;color:#000000;fill:#999999;fill-opacity:1;stroke:none;stroke-width:0.85700005;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;font-family:Sans;-inkscape-font-specification:Sans" />
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 487 B

After

Width:  |  Height:  |  Size: 3.6 KiB

View File

@@ -1,226 +0,0 @@
#!/usr/bin/env python3
# Copyright (C) 2021 Red Hat Inc.
#
# Author: Bastien Nocera <hadess@hadess.net>
#
# SPDX-License-Identifier: GPL-2.0-or-later
import dbus
import sys
import os
import fcntl
import gi
import subprocess
import time
from collections import OrderedDict
from dbusmock import DBusTestCase, mockobject
from dbus.mainloop.glib import DBusGMainLoop
from consolemenu import *
from consolemenu.items import *
from gi.repository import Gio
from gi.repository import GLib
DBusGMainLoop(set_as_default=True)
def set_nonblock(fd):
'''Set a file object to non-blocking'''
flags = fcntl.fcntl(fd, fcntl.F_GETFL)
fcntl.fcntl(fd, fcntl.F_SETFL, flags | os.O_NONBLOCK)
def get_templates_dir():
return os.path.join(os.path.dirname(__file__), 'dbusmock-templates')
def get_template_path(template_name):
return os.path.join(get_templates_dir(), template_name + '.py')
class GccDBusTestCase(DBusTestCase):
@classmethod
def setUpClass(klass):
klass.mocks = OrderedDict()
# Start system bus
DBusTestCase.setUpClass()
klass.test_bus = Gio.TestDBus.new(Gio.TestDBusFlags.NONE)
klass.test_bus.up()
os.environ['DBUS_SYSTEM_BUS_ADDRESS'] = klass.test_bus.get_bus_address()
# Start session bus
klass.session_test_bus = Gio.TestDBus.new(Gio.TestDBusFlags.NONE)
klass.session_test_bus.up()
os.environ['DBUS_SESSION_BUS_ADDRESS'] = klass.session_test_bus.get_bus_address()
# process = subprocess.Popen(['gdbus', 'monitor', '--session', '--dest', 'org.gnome.SettingsDaemon.Rfkill'])
# process = subprocess.Popen(['gdbus', 'monitor', '--system', '--dest', 'org.bluez'])
# Start bluez and gsd-rfkill
klass.start_from_template('bluez5')
klass.start_from_local_template(
'gsd_rfkill', {'templates-dir': get_templates_dir()})
klass.system_bus = Gio.bus_get_sync(Gio.BusType.SYSTEM, None)
@classmethod
def tearDownClass(klass):
for (mock_server, mock_obj) in reversed(klass.mocks.values()):
mock_server.terminate()
mock_server.wait()
DBusTestCase.tearDownClass()
@classmethod
def start_from_template(klass, template, params={}):
mock_server, mock_obj = \
klass.spawn_server_template(template,
params,
stdout=subprocess.PIPE)
set_nonblock(mock_server.stdout)
mocks = (mock_server, mock_obj)
assert klass.mocks.setdefault(template, mocks) == mocks
return mocks
@classmethod
def start_from_local_template(klass, template_file_name, params={}):
template = get_template_path(template_file_name)
ret = klass.start_from_template(template, params)
klass.mocks.setdefault(template_file_name, ret)
return ret
def __init__(self):
self.devices = {}
self.rfkill = self.mocks['gsd_rfkill'][1]
self.bluez_mock = self.mocks['bluez5'][1]
self.hci0_powered = True
self.hci0_plugged_in = True
self.add_adapter()
bus = dbus.SystemBus()
self.hci0_props = dbus.Interface(bus.get_object('org.bluez', '/org/bluez/hci0'), 'org.freedesktop.DBus.Properties')
def adapter_exists(self):
try:
self.get_dbus(True).get_object('org.bluez', '/org/bluez/hci0').Get('org.bluez.Adapter1', 'Name')
except:
return False
return True
def add_adapter(self):
if self.adapter_exists():
return
self.bluez_mock.AddAdapter('hci0', 'hci0')
adapter = self.get_dbus(True).get_object('org.bluez', '/org/bluez/hci0')
adapter.AddProperties('org.bluez.Adapter1',
{'Blocked': dbus.Boolean(not self.hci0_powered, variant_level=1)})
adapter.UpdateProperties('org.bluez.Adapter1',
{'Powered': dbus.Boolean(self.hci0_powered, variant_level=1)})
self.devices = []
self.add_device('hci0', '22:33:44:55:66:77', "Bastienʼs mouse", True, 0x580, 'input-mouse')
self.add_device('hci0', '22:33:44:55:66:78', 'Bloutouf keyboard & keys', True, 0x540, 'input-keyboard')
self.add_device('hci0', '60:8B:0E:55:66:79', 'iPhoone 19S', True, 0x20C, 'phone')
# Uncategorised audio device
self.add_device('hci0', '22:33:44:55:66:79', 'MEGA Speakers', True, 0x200400, 'audio-card')
self.add_device('hci0', '22:33:44:55:66:80', 'Ski-bi dibby dib yo da dub dub Yo da dub dub Ski-bi dibby dib yo da dub dub Yo da dub dub (I\'m the Scatman) Ski-bi dibby dib yo da dub dub Yo da dub dub Ski-bi dibby dib yo da dub dub Yo da dub dub Ba-da-ba-da-ba-be bop bop bodda bope Bop ba bodda bope Be bop ba bodda bope Bop ba bodda Ba-da-ba-da-ba-be bop ba bodda bope Bop ba bodda bope Be bop ba bodda bope Bop ba bodda bope', True, 0x80C, '')
self.rfkill.Set('org.gnome.SettingsDaemon.Rfkill', 'BluetoothHasAirplaneMode', dbus.Boolean(True))
def remove_adapter(self):
if not self.adapter_exists():
return
for dev in self.devices:
adapter = self.get_dbus(True).get_object('org.bluez', '/org/bluez/hci0')
adapter.RemoveDevice(dev)
self.devices = []
self.bluez_mock.RemoveAdapter('hci0')
if self.rfkill.Get('org.gnome.SettingsDaemon.Rfkill', 'BluetoothHardwareAirplaneMode') == 0:
self.rfkill.Set('org.gnome.SettingsDaemon.Rfkill', 'BluetoothHasAirplaneMode', dbus.Boolean(False))
def add_device(self, adapter, address, name, paired, klass, icon):
dev_path = self.bluez_mock.AddDevice(adapter, address, name)
dev = self.get_dbus(True).get_object('org.bluez', str(dev_path))
dev.UpdateProperties('org.bluez.Device1',
{'Paired': dbus.Boolean(paired, variant_level=1),
'Class': dbus.UInt32(klass, variant_level=1),
'Icon': dbus.String(icon, variant_level=1)})
self.devices.append(dev)
def get_rfkill_prop(self, prop_name):
return self.rfkill.Get('org.gnome.SettingsDaemon.Rfkill', prop_name)
def toggle_hw_rfkill(self):
if self.rfkill.Get('org.gnome.SettingsDaemon.Rfkill', 'BluetoothHardwareAirplaneMode') == 0:
self.rfkill.Set('org.gnome.SettingsDaemon.Rfkill', 'BluetoothHardwareAirplaneMode', dbus.Boolean(True))
if self.adapter_exists():
self.remove_adapter()
else:
self.rfkill.Set('org.gnome.SettingsDaemon.Rfkill', 'BluetoothHardwareAirplaneMode', dbus.Boolean(False))
if not self.adapter_exists():
self.add_adapter()
def set_unpowered(self):
if self.hci0_powered:
print('hci0 will now default to unpowered')
self.hci0_powered = False
else:
print('hci0 will now default to powered')
self.hci0_powered = True
def unplug_default_adapter(self):
if self.hci0_plugged_in:
print('default adapter is unplugged')
self.hci0_plugged_in = False
self.remove_adapter()
else:
print('default adapter is plugged in')
self.hci0_plugged_in = True
self.add_adapter()
def toggle_airplane_mode(self):
if self.rfkill.Get('org.gnome.SettingsDaemon.Rfkill', 'AirplaneMode') == 0:
self.rfkill.Set('org.gnome.SettingsDaemon.Rfkill', 'AirplaneMode', dbus.Boolean(True))
self.rfkill.Set('org.gnome.SettingsDaemon.Rfkill', 'BluetoothAirplaneMode', dbus.Boolean(True))
else:
self.rfkill.Set('org.gnome.SettingsDaemon.Rfkill', 'AirplaneMode', dbus.Boolean(False))
self.rfkill.Set('org.gnome.SettingsDaemon.Rfkill', 'BluetoothAirplaneMode', dbus.Boolean(False))
def start_menu(self):
menu = ConsoleMenu("Bluetooth Panel", "Scenario Tester", clear_screen = False)
function_item = FunctionItem("Toggle Bluetooth hardware rfkill", self.toggle_hw_rfkill)
menu.append_item(function_item)
function_item = FunctionItem("Toggle default adapter unpowered", self.set_unpowered)
menu.append_item(function_item)
function_item = FunctionItem("Unplug/plug default adapter", self.unplug_default_adapter)
menu.append_item(function_item)
function_item = FunctionItem("Toggle airplane mode", self.toggle_airplane_mode)
menu.append_item(function_item)
menu.start(show_exit_option=False)
def wrap_call(self):
os.environ['GSETTINGS_BACKEND'] = 'memory'
wrapper = os.environ.get('META_DBUS_RUNNER_WRAPPER')
args = ['gnome-control-center', '-v', 'bluetooth']
if wrapper == 'gdb':
args = ['gdb', '-ex', 'r', '-ex', 'bt full', '--args'] + args
elif wrapper:
args = wrapper.split(' ') + args
p = subprocess.Popen(args, env=os.environ)
p.wait()
if __name__ == '__main__':
#if 'umockdev' not in os.environ.get('LD_PRELOAD', ''):
# os.execvp('umockdev-wrapper', ['umockdev-wrapper'] + sys.argv)
GccDBusTestCase.setUpClass()
test_case = GccDBusTestCase()
test_case.start_menu()
try:
test_case.wrap_call()
finally:
GccDBusTestCase.tearDownClass()

View File

@@ -22,8 +22,6 @@
#include <config.h>
#endif
#include <adwaita.h>
#include <shell/cc-shell.h>
#include <shell/cc-object-storage.h>
#include <bluetooth-settings-widget.h>
@@ -34,12 +32,12 @@
struct _CcBluetoothPanel {
CcPanel parent_instance;
AdwStatusPage *airplane_page;
AdwStatusPage *disabled_page;
GtkBox *airplane_box;
GtkBox *disabled_box;
GtkSwitch *enable_switch;
GtkBox *header_box;
AdwStatusPage *hw_airplane_page;
AdwStatusPage *no_devices_page;
GtkBox *hw_airplane_box;
GtkBox *no_devices_box;
BluetoothSettingsWidget *settings_widget;
GtkStack *stack;
@@ -74,33 +72,23 @@ cc_bluetooth_panel_finalize (GObject *object)
}
static void
airplane_mode_changed_cb (GObject *source_object,
GAsyncResult *res,
gpointer user_data)
cc_bluetooth_panel_constructed (GObject *object)
{
g_autoptr(GVariant) ret = NULL;
g_autoptr(GError) error = NULL;
gboolean state = GPOINTER_TO_UINT (user_data);
CcBluetoothPanel *self = CC_BLUETOOTH_PANEL (object);
if (!g_dbus_proxy_call_finish (G_DBUS_PROXY (source_object),
res, &error)) {
if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
g_warning ("Failed to change Bluetooth killswitch state to %s: %s",
state ? "on" : "off", error->message);
} else {
CcBluetoothPanel *self = user_data;
G_OBJECT_CLASS (cc_bluetooth_panel_parent_class)->constructed (object);
g_debug ("Changed Bluetooth killswitch state to %s",
state ? "on" : "off");
if (!bluetooth_settings_widget_get_default_adapter_powered (self->settings_widget))
bluetooth_settings_widget_set_default_adapter_powered(self->settings_widget, TRUE);
}
/* add kill switch widgets */
cc_shell_embed_widget_in_header (cc_panel_get_shell (CC_PANEL (self)),
GTK_WIDGET (self->header_box), GTK_POS_RIGHT);
}
static void
enable_switch_state_set_cb (CcBluetoothPanel *self, gboolean state)
enable_switch_changed_cb (CcBluetoothPanel *self)
{
gboolean state;
state = gtk_switch_get_active (self->enable_switch);
g_debug ("Power switched to %s", state ? "on" : "off");
g_dbus_proxy_call (self->properties,
"Set",
@@ -109,42 +97,43 @@ enable_switch_state_set_cb (CcBluetoothPanel *self, gboolean state)
G_DBUS_CALL_FLAGS_NONE,
-1,
cc_panel_get_cancellable (CC_PANEL (self)),
airplane_mode_changed_cb, self);
NULL, NULL);
}
static void
adapter_status_changed_cb (CcBluetoothPanel *self)
{
GtkAlign valign;
gboolean sensitive, powered;
gboolean sensitive, powered, change_powered;
GtkWidget *page;
g_debug ("Updating airplane mode: BluetoothHasAirplaneMode %d, BluetoothHardwareAirplaneMode %d, BluetoothAirplaneMode %d, AirplaneMode %d",
self->has_airplane_mode, self->hardware_airplane_mode, self->bt_airplane_mode, self->airplane_mode);
change_powered = TRUE;
valign = GTK_ALIGN_CENTER;
if (self->has_airplane_mode == FALSE) {
g_debug ("No Bluetooth available");
sensitive = FALSE;
powered = FALSE;
page = GTK_WIDGET (self->no_devices_page);
page = GTK_WIDGET (self->no_devices_box);
} else if (self->hardware_airplane_mode) {
g_debug ("Bluetooth is Hard blocked");
sensitive = FALSE;
powered = FALSE;
page = GTK_WIDGET (self->hw_airplane_page);
page = GTK_WIDGET (self->hw_airplane_box);
} else if (self->airplane_mode) {
g_debug ("Airplane mode is on, Wi-Fi and Bluetooth are disabled");
sensitive = FALSE;
powered = FALSE;
page = GTK_WIDGET (self->airplane_page);
page = GTK_WIDGET (self->airplane_box);
} else if (self->bt_airplane_mode ||
!bluetooth_settings_widget_get_default_adapter_powered (self->settings_widget)) {
g_debug ("Default adapter is unpowered");
g_debug ("Default adapter is unpowered, but should be available");
sensitive = TRUE;
powered = FALSE;
page = GTK_WIDGET (self->disabled_page);
change_powered = FALSE;
page = GTK_WIDGET (self->disabled_box);
} else {
g_debug ("Bluetooth is available and powered");
sensitive = TRUE;
@@ -155,9 +144,12 @@ adapter_status_changed_cb (CcBluetoothPanel *self)
gtk_widget_set_valign (GTK_WIDGET (self->stack), valign);
gtk_widget_set_sensitive (GTK_WIDGET (self->header_box), sensitive);
g_signal_handlers_block_by_func (self->enable_switch, enable_switch_state_set_cb, self);
gtk_switch_set_state (self->enable_switch, powered);
g_signal_handlers_unblock_by_func (self->enable_switch, enable_switch_state_set_cb, self);
if (change_powered) {
g_signal_handlers_block_by_func (self->enable_switch, enable_switch_changed_cb, self);
gtk_switch_set_active (self->enable_switch, powered);
g_signal_handlers_unblock_by_func (self->enable_switch, enable_switch_changed_cb, self);
}
gtk_stack_set_visible_child (self->stack, page);
}
@@ -177,7 +169,6 @@ airplane_mode_changed (CcBluetoothPanel *self)
self->bt_airplane_mode = g_variant_get_boolean (bluetooth_airplane_mode);
bluetooth_hardware_airplane_mode = g_dbus_proxy_get_cached_property (self->rfkill, "BluetoothHardwareAirplaneMode");
g_message ("BluetoothHardwareAirplaneMode: %d", self->hardware_airplane_mode);
self->hardware_airplane_mode = g_variant_get_boolean (bluetooth_hardware_airplane_mode);
bluetooth_has_airplane_mode = g_dbus_proxy_get_cached_property (self->rfkill, "BluetoothHasAirplaneMode");
@@ -220,24 +211,25 @@ cc_bluetooth_panel_class_init (CcBluetoothPanelClass *klass)
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
CcPanelClass *panel_class = CC_PANEL_CLASS (klass);
object_class->constructed = cc_bluetooth_panel_constructed;
object_class->finalize = cc_bluetooth_panel_finalize;
panel_class->get_help_uri = cc_bluetooth_panel_get_help_uri;
gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/control-center/bluetooth/cc-bluetooth-panel.ui");
gtk_widget_class_bind_template_child (widget_class, CcBluetoothPanel, airplane_page);
gtk_widget_class_bind_template_child (widget_class, CcBluetoothPanel, disabled_page);
gtk_widget_class_bind_template_child (widget_class, CcBluetoothPanel, airplane_box);
gtk_widget_class_bind_template_child (widget_class, CcBluetoothPanel, disabled_box);
gtk_widget_class_bind_template_child (widget_class, CcBluetoothPanel, enable_switch);
gtk_widget_class_bind_template_child (widget_class, CcBluetoothPanel, header_box);
gtk_widget_class_bind_template_child (widget_class, CcBluetoothPanel, no_devices_page);
gtk_widget_class_bind_template_child (widget_class, CcBluetoothPanel, hw_airplane_page);
gtk_widget_class_bind_template_child (widget_class, CcBluetoothPanel, no_devices_box);
gtk_widget_class_bind_template_child (widget_class, CcBluetoothPanel, hw_airplane_box);
gtk_widget_class_bind_template_child (widget_class, CcBluetoothPanel, settings_widget);
gtk_widget_class_bind_template_child (widget_class, CcBluetoothPanel, stack);
gtk_widget_class_bind_template_callback (widget_class, adapter_status_changed_cb);
gtk_widget_class_bind_template_callback (widget_class, airplane_mode_off_button_clicked_cb);
gtk_widget_class_bind_template_callback (widget_class, enable_switch_state_set_cb);
gtk_widget_class_bind_template_callback (widget_class, enable_switch_changed_cb);
gtk_widget_class_bind_template_callback (widget_class, panel_changed_cb);
}

View File

@@ -1,64 +1,175 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<!-- interface-requires gtk+ 3.0 -->
<template class="CcBluetoothPanel" parent="CcPanel">
<child type="titlebar-end">
<object class="GtkBox" id="header_box">
<child>
<object class="GtkSwitch" id="enable_switch">
<property name="valign">center</property>
<accessibility>
<property name="label" translatable="yes">Enable</property>
</accessibility>
<signal name="state-set" handler="enable_switch_state_set_cb" object="CcBluetoothPanel" swapped="yes"/>
</object>
</child>
</object>
</child>
<child type="content">
<property name="visible">True</property>
<child>
<object class="GtkStack" id="stack">
<property name="visible">True</property>
<child>
<object class="AdwStatusPage" id="no_devices_page">
<property name="icon-name">bluetooth-active-symbolic</property>
<property name="title" translatable="yes">No Bluetooth Found</property>
<property name="description" translatable="yes">Plug in a dongle to use Bluetooth.</property>
<object class="GtkBox" id="no_devices_box">
<property name="visible">True</property>
<property name="orientation">vertical</property>
<property name="margin_top">64</property>
<property name="margin_bottom">64</property>
<property name="margin_start">12</property>
<property name="margin_end">12</property>
<property name="spacing">24</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="icon_name">bluetooth-active-symbolic</property>
<property name="pixel_size">192</property>
<style>
<class name="dim-label"/>
</style>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="label" translatable="yes">No Bluetooth Found</property>
<attributes>
<attribute name="weight" value="bold"/>
<attribute name="scale" value="1.2"/>
</attributes>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="wrap">True</property>
<property name="label" translatable="yes">Plug in a dongle to use Bluetooth.</property>
</object>
</child>
</object>
</child>
<child>
<object class="AdwStatusPage" id="disabled_page">
<property name="icon-name">bluetooth-active-symbolic</property>
<property name="title" translatable="yes">Bluetooth Turned Off</property>
<property name="description" translatable="yes">Turn on to connect devices and receive file transfers.</property>
<object class="GtkBox" id="disabled_box">
<property name="visible">True</property>
<property name="orientation">vertical</property>
<property name="margin_top">64</property>
<property name="margin_bottom">64</property>
<property name="margin_start">12</property>
<property name="margin_end">12</property>
<property name="spacing">24</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="icon_name">bluetooth-active-symbolic</property>
<property name="pixel_size">192</property>
<style>
<class name="dim-label"/>
</style>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="label" translatable="yes">Bluetooth Turned Off</property>
<attributes>
<attribute name="weight" value="bold"/>
<attribute name="scale" value="1.2"/>
</attributes>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="wrap">True</property>
<property name="label" translatable="yes">Turn on to connect devices and receive file transfers.</property>
</object>
</child>
</object>
</child>
<child>
<object class="AdwStatusPage" id="airplane_page">
<property name="icon-name">airplane-mode-symbolic</property>
<property name="title" translatable="yes">Airplane Mode is On</property>
<property name="description" translatable="yes">Bluetooth is disabled when airplane mode is on.</property>
<property name="child">
<object class="GtkBox" id="airplane_box">
<property name="visible">True</property>
<property name="orientation">vertical</property>
<property name="margin_top">64</property>
<property name="margin_bottom">64</property>
<property name="margin_start">12</property>
<property name="margin_end">12</property>
<property name="spacing">24</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="icon_name">airplane-mode-symbolic</property>
<property name="pixel_size">192</property>
<style>
<class name="dim-label"/>
</style>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="label" translatable="yes">Airplane Mode is on</property>
<attributes>
<attribute name="weight" value="bold"/>
<attribute name="scale" value="1.2"/>
</attributes>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="wrap">True</property>
<property name="label" translatable="yes">Bluetooth is disabled when airplane mode is on.</property>
</object>
</child>
<child>
<object class="GtkButton">
<property name="visible">True</property>
<property name="label" translatable="yes">Turn Off Airplane Mode</property>
<property name="halign">center</property>
<property name="valign">center</property>
<signal name="clicked" handler="airplane_mode_off_button_clicked_cb" object="CcBluetoothPanel" swapped="yes"/>
<style>
<class name="pill"/>
</style>
</object>
</property>
</child>
</object>
</child>
<child>
<object class="AdwStatusPage" id="hw_airplane_page">
<property name="icon-name">airplane-mode-symbolic</property>
<property name="title" translatable="yes">Hardware Airplane Mode is On</property>
<property name="description" translatable="yes">Turn off the Airplane mode switch to enable Bluetooth.</property>
<object class="GtkBox" id="hw_airplane_box">
<property name="visible">True</property>
<property name="orientation">vertical</property>
<property name="margin_top">64</property>
<property name="margin_bottom">64</property>
<property name="margin_start">12</property>
<property name="margin_end">12</property>
<property name="spacing">24</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="icon_name">airplane-mode-symbolic</property>
<property name="pixel_size">192</property>
<style>
<class name="dim-label"/>
</style>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="label" translatable="yes">Hardware Airplane Mode is on</property>
<attributes>
<attribute name="weight" value="bold"/>
<attribute name="scale" value="1.2"/>
</attributes>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="wrap">True</property>
<property name="label" translatable="yes">Turn off the Airplane mode switch to enable Bluetooth.</property>
</object>
</child>
</object>
</child>
<child>
<object class="BluetoothSettingsWidget" id="settings_widget">
<property name="visible">True</property>
<signal name="panel-changed" handler="panel_changed_cb" object="CcBluetoothPanel" swapped="yes"/>
<signal name="adapter-status-changed" handler="adapter_status_changed_cb" object="CcBluetoothPanel" swapped="yes"/>
</object>
@@ -66,4 +177,24 @@
</object>
</child>
</template>
<object class="GtkBox" id="header_box">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkSwitch" id="enable_switch">
<property name="use_action_appearance">False</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="valign">center</property>
<signal name="notify::active" handler="enable_switch_changed_cb" object="CcBluetoothPanel" swapped="yes"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="padding">4</property>
<property name="pack_type">end</property>
<property name="position">2</property>
</packing>
</child>
</object>
</interface>

View File

@@ -1,75 +0,0 @@
'''gsd-rfkill mock template
This creates the expected methods and properties of the main
org.gnome.SettingsDaemon.Rfkill object.
'''
# This program 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 3 of the License, or (at your option) any
# later version. See http://www.gnu.org/copyleft/lgpl.html for the full text
# of the license.
__author__ = 'Bastien Nocera'
__copyright__ = '(c) 2022, Red Hat Inc.'
import dbus
import os
from dbusmock import mockobject
BUS_NAME = 'org.gnome.SettingsDaemon.Rfkill'
MAIN_OBJ = '/org/gnome/SettingsDaemon/Rfkill'
MAIN_IFACE = 'org.gnome.SettingsDaemon.Rfkill'
SYSTEM_BUS = False
ADAPTER_IFACE = 'org.bluez.Adapter1'
def rfkill_changed(*args, **kwargs):
[iface, changed, _invalidated] = args
rfkill = mockobject.objects[MAIN_OBJ]
adapter = dbus.bus.BusConnection(os.environ['DBUS_SYSTEM_BUS_ADDRESS']).get_object('org.bluez', '/org/bluez/hci0')
try:
adapter.Get(ADAPTER_IFACE, 'Name')
except:
adapter = None
if 'BluetoothAirplaneMode' in changed:
if adapter and rfkill.props[MAIN_IFACE]['BluetoothAirplaneMode'] == 1:
adapter.UpdateProperties(ADAPTER_IFACE,
{'Powered': dbus.Boolean(False),
'Blocked': dbus.Boolean(True)})
elif adapter:
adapter.UpdateProperties(ADAPTER_IFACE,
{'Blocked': dbus.Boolean(False)})
if 'BluetoothHardwareAirplaneMode' in changed:
if rfkill.props[MAIN_IFACE]['BluetoothAirplaneMode'] == 0:
rfkill.Set(MAIN_IFACE, 'BluetoothAirplaneMode', dbus.Boolean(False))
def load(mock, parameters):
# Loaded!
mock.loaded = True
props = {
'AirplaneMode': parameters.get('AirplaneMode', dbus.Boolean(False)),
'HardwareAirplaneMode': parameters.get('HardwareAirplaneMode', dbus.Boolean(False)),
'HasAirplaneMode': parameters.get('HasAirplaneMode', dbus.Boolean(True)),
# True if not desktop, server, vm or container
'ShouldShowAirplaneMode': parameters.get('ShouldShowAirplaneMode', dbus.Boolean(True)),
'BluetoothAirplaneMode': parameters.get('BluetoothAirplaneMode', dbus.Boolean(False)),
'BluetoothHardwareAirplaneMode': parameters.get('BluetoothAirplaneMode', dbus.Boolean(False)),
'BluetoothHasAirplaneMode': parameters.get('BluetoothHasAirplaneMode', dbus.Boolean(True)),
'WwanAirplaneMode': parameters.get('WwanAirplaneMode', dbus.Boolean(False)),
'WwanHardwareAirplaneMode': parameters.get('WwanHardwareAirplaneMode', dbus.Boolean(False)),
'WwanHasAirplaneMode': parameters.get('WwanHasAirplaneMode', dbus.Boolean(False)),
}
mock.AddProperties(MAIN_IFACE, dbus.Dictionary(props, signature='sv'))
rfkill = mockobject.objects[MAIN_OBJ]
rfkill.hci0_power = True
session_bus = dbus.SessionBus()
session_bus.add_signal_receiver(rfkill_changed,
signal_name='PropertiesChanged',
path=MAIN_OBJ,
dbus_interface='org.freedesktop.DBus.Properties')

View File

@@ -2,7 +2,7 @@
Name=Bluetooth
Comment=Turn Bluetooth on and off and connect your devices
# Translators: Do NOT translate or transliterate this text (this is an icon file name)!
Icon=org.gnome.Settings-bluetooth-symbolic
Icon=bluetooth
Exec=gnome-control-center bluetooth
Terminal=false
Type=Application

View File

@@ -1,4 +0,0 @@
install_data(
'scalable/org.gnome.Settings-bluetooth-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 7.585938 0.0898438 c -0.355469 0.1640622 -0.585938 0.5195312 -0.585938 0.9101562 v 5.296875 l -2.34375 -2.046875 c -0.414062 -0.363281 -1.042969 -0.324219 -1.40625 0.089844 c -0.363281 0.417968 -0.324219 1.046875 0.09375 1.410156 l 2.566406 2.25 l -2.566406 2.25 c -0.417969 0.363281 -0.457031 0.992188 -0.09375 1.40625 c 0.363281 0.417969 0.992188 0.457031 1.40625 0.09375 l 2.34375 -2.046875 v 5.296875 c 0 0.390625 0.230469 0.746094 0.585938 0.910156 c 0.359374 0.160156 0.777343 0.101563 1.070312 -0.160156 l 4 -3.5 c 0.21875 -0.1875 0.34375 -0.460938 0.34375 -0.75 s -0.125 -0.5625 -0.34375 -0.75 l -3.140625 -2.75 l 3.140625 -2.75 c 0.21875 -0.1875 0.34375 -0.460938 0.34375 -0.75 s -0.125 -0.5625 -0.34375 -0.75 l -4 -3.5 c -0.292969 -0.2617188 -0.710938 -0.3242188 -1.070312 -0.1601562 z m 1.414062 3.1132812 l 1.484375 1.296875 l -1.484375 1.296875 z m 0 7 l 1.484375 1.296875 l -1.484375 1.296875 z m 0 0" fill="#2e3436"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -37,5 +37,3 @@ panels_libs += static_library(
dependencies: deps,
c_args: cflags
)
subdir('icons')

View File

@@ -18,11 +18,11 @@
* Author: Matthias Clasen <mclasen@redhat.com>
*/
#include "list-box-helper.h"
#include "cc-camera-panel.h"
#include "cc-camera-resources.h"
#include "cc-util.h"
#include <adwaita.h>
#include <gio/gdesktopappinfo.h>
#include <glib/gi18n.h>
@@ -35,7 +35,6 @@ struct _CcCameraPanel
GtkStack *stack;
GtkListBox *camera_apps_list_box;
GtkSwitch *main_switch;
GSettings *privacy_settings;
@@ -159,7 +158,7 @@ add_camera_app (CcCameraPanel *self,
g_autofree gchar *desktop_id = NULL;
CameraAppStateData *data;
GDesktopAppInfo *app_info;
GtkWidget *row, *w;
GtkWidget *box, *row, *w;
GIcon *icon;
w = g_hash_table_lookup (self->camera_app_switches, app_id);
@@ -174,22 +173,41 @@ add_camera_app (CcCameraPanel *self,
if (!app_info)
return;
row = adw_action_row_new ();
gtk_list_box_append (self->camera_apps_list_box, row);
row = gtk_list_box_row_new ();
gtk_widget_show (row);
box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
gtk_widget_show (box);
gtk_widget_set_margin_start (box, 12);
gtk_widget_set_margin_end (box, 6);
gtk_widget_set_margin_top (box, 12);
gtk_widget_set_margin_bottom (box, 12);
gtk_container_add (GTK_CONTAINER (row), box);
gtk_widget_set_hexpand (box, TRUE);
gtk_container_add (GTK_CONTAINER (self->camera_apps_list_box), row);
icon = g_app_info_get_icon (G_APP_INFO (app_info));
w = gtk_image_new_from_gicon (icon);
w = gtk_image_new_from_gicon (icon, GTK_ICON_SIZE_LARGE_TOOLBAR);
gtk_widget_show (w);
gtk_widget_set_halign (w, GTK_ALIGN_CENTER);
gtk_widget_set_valign (w, GTK_ALIGN_CENTER);
gtk_size_group_add_widget (self->camera_icon_size_group, w);
adw_action_row_add_prefix (ADW_ACTION_ROW (row), w);
gtk_box_pack_start (GTK_BOX (box), w, FALSE, FALSE, 0);
adw_preferences_row_set_title (ADW_PREFERENCES_ROW (row),
g_app_info_get_name (G_APP_INFO (app_info)));
w = gtk_label_new (g_app_info_get_name (G_APP_INFO (app_info)));
gtk_widget_show (w);
gtk_widget_set_margin_start (w, 12);
gtk_widget_set_margin_end (w, 12);
gtk_widget_set_halign (w, GTK_ALIGN_START);
gtk_widget_set_valign (w, GTK_ALIGN_CENTER);
gtk_label_set_xalign (GTK_LABEL (w), 0);
gtk_box_pack_start (GTK_BOX (box), w, TRUE, TRUE, 0);
w = gtk_switch_new ();
gtk_widget_show (w);
gtk_switch_set_active (GTK_SWITCH (w), enabled);
gtk_widget_set_halign (w, GTK_ALIGN_END);
gtk_widget_set_valign (w, GTK_ALIGN_CENTER);
adw_action_row_add_suffix (ADW_ACTION_ROW (row), w);
gtk_box_pack_start (GTK_BOX (box), w, FALSE, FALSE, 0);
g_settings_bind (self->privacy_settings,
"disable-camera",
w,
@@ -359,6 +377,37 @@ cc_camera_panel_get_help_uri (CcPanel *panel)
return "help:gnome-help/camera";
}
static void
cc_camera_panel_constructed (GObject *object)
{
CcCameraPanel *self = CC_CAMERA_PANEL (object);
GtkWidget *box, *widget;
G_OBJECT_CLASS (cc_camera_panel_parent_class)->constructed (object);
box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
gtk_widget_show (box);
widget = gtk_switch_new ();
gtk_widget_show (widget);
gtk_widget_set_valign (widget, GTK_ALIGN_CENTER);
gtk_box_pack_start (GTK_BOX (box), widget, FALSE, FALSE, 4);
g_settings_bind (self->privacy_settings, "disable-camera",
widget, "active",
G_SETTINGS_BIND_INVERT_BOOLEAN);
g_object_bind_property_full (widget, "active",
self->stack, "visible-child-name",
G_BINDING_SYNC_CREATE,
to_child_name,
NULL,
NULL, NULL);
cc_shell_embed_widget_in_header (cc_panel_get_shell (CC_PANEL (self)),
box,
GTK_POS_RIGHT);
}
static void
cc_camera_panel_class_init (CcCameraPanelClass *klass)
{
@@ -369,12 +418,12 @@ cc_camera_panel_class_init (CcCameraPanelClass *klass)
panel_class->get_help_uri = cc_camera_panel_get_help_uri;
object_class->finalize = cc_camera_panel_finalize;
object_class->constructed = cc_camera_panel_constructed;
gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/control-center/camera/cc-camera-panel.ui");
gtk_widget_class_bind_template_child (widget_class, CcCameraPanel, stack);
gtk_widget_class_bind_template_child (widget_class, CcCameraPanel, camera_apps_list_box);
gtk_widget_class_bind_template_child (widget_class, CcCameraPanel, main_switch);
}
static void
@@ -384,20 +433,14 @@ cc_camera_panel_init (CcCameraPanel *self)
gtk_widget_init_template (GTK_WIDGET (self));
gtk_list_box_set_header_func (self->camera_apps_list_box,
cc_list_box_update_header_func,
NULL,
NULL);
self->camera_icon_size_group = gtk_size_group_new (GTK_SIZE_GROUP_BOTH);
self->privacy_settings = g_settings_new ("org.gnome.desktop.privacy");
g_settings_bind (self->privacy_settings, "disable-camera",
self->main_switch, "active",
G_SETTINGS_BIND_INVERT_BOOLEAN);
g_object_bind_property_full (self->main_switch, "active",
self->stack, "visible-child-name",
G_BINDING_SYNC_CREATE,
to_child_name,
NULL,
NULL, NULL);
self->camera_app_switches = g_hash_table_new_full (g_str_hash,
g_str_equal,

View File

@@ -1,57 +1,107 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.18.1 -->
<interface>
<requires lib="gtk+" version="3.14"/>
<template class="CcCameraPanel" parent="CcPanel">
<child type="titlebar-end">
<object class="GtkSwitch" id="main_switch">
<accessibility>
<property name="label" translatable="yes">Enable</property>
</accessibility>
<property name="valign">center</property>
</object>
</child>
<child type="content">
<property name="visible">True</property>
<child>
<object class="GtkStack" id="stack">
<!-- Empty page -->
<property name="visible">true</property>
<child>
<object class="GtkStackPage">
<property name="name">empty</property>
<property name="child">
<object class="AdwStatusPage">
<object class="GtkBox">
<property name="visible">true</property>
<property name="orientation">vertical</property>
<property name="valign">center</property>
<child>
<object class="GtkImage">
<property name="visible">true</property>
<property name="valign">start</property>
<property name="pixel-size">96</property>
<property name="icon-name">camera-disabled-symbolic</property>
<property name="title" translatable="yes">Camera is Turned Off</property>
<property name="description" translatable="yes">No applications can capture photos or video.</property>
<style>
<class name="dim-label"/>
</style>
</object>
</property>
<packing>
<property name="fill">0</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">true</property>
<property name="margin-top">20</property>
<property name="margin-bottom">15</property>
<property name="label" translatable="yes">Camera is turned off</property>
<attributes>
<attribute name="scale" value="1.44"/>
</attributes>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="visible">true</property>
<property name="label" translatable="yes">No applications can capture photos or video.</property>
<style>
<class name="dim-label"/>
</style>
</object>
</child>
</object>
<packing>
<property name="name">empty</property>
</packing>
</child>
<!-- Cameras -->
<child>
<object class="GtkStackPage">
<property name="name">content</property>
<property name="child">
<object class="AdwPreferencesPage">
<child>
<object class="AdwPreferencesGroup">
<property name="description" translatable="yes">Use of the camera allows applications to capture photos and video. Disabling the camera may cause some applications to not function properly.
<object class="GtkScrolledWindow">
<property name="visible">true</property>
<property name="hscrollbar-policy">never</property>
<child>
<object class="HdyClamp">
<property name="visible">True</property>
<property name="margin_top">32</property>
<property name="margin_bottom">32</property>
<property name="margin_start">12</property>
<property name="margin_end">12</property>
Allow the applications below to use your camera.</property>
<child>
<object class="GtkBox">
<property name="visible">true</property>
<property name="orientation">vertical</property>
<property name="hexpand">1</property>
<child>
<object class="GtkLabel">
<property name="visible">true</property>
<property name="margin-bottom">12</property>
<property name="label" translatable="yes">Use of the camera allows applications to capture photos and video. Disabling the camera may cause some applications to not function properly.</property>
<property name="wrap">1</property>
<property name="max-width-chars">50</property>
<property name="xalign">0</property>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="visible">true</property>
<property name="margin-bottom">12</property>
<property name="label" translatable="yes">Allow the applications below to use your camera.</property>
<property name="wrap">1</property>
<property name="max-width-chars">50</property>
<property name="xalign">0</property>
</object>
</child>
<child>
<object class="GtkListBox" id="camera_apps_list_box">
<property name="visible">true</property>
<property name="can-focus">1</property>
<property name="selection-mode">none</property>
<style>
<class name="boxed-list"/>
<class name="view"/>
<class name="frame"/>
</style>
<child type="placeholder">
<object class="GtkLabel">
<property name="margin-start">18</property>
<property name="margin-end">18</property>
<property name="margin-top">18</property>
<property name="margin-bottom">18</property>
<property name="visible">true</property>
<property name="margin">18</property>
<property name="label" translatable="yes">No Applications Have Asked for Camera Access</property>
<property name="wrap">true</property>
<property name="max-width-chars">50</property>
@@ -64,11 +114,14 @@ Allow the applications below to use your camera.</property>
</child>
</object>
</child>
</object>
</property>
</object>
</child>
</object>
</child>
</object>
<packing>
<property name="name">content</property>
</packing>
</child>
</object>
</child>
</template>

View File

@@ -4,7 +4,7 @@ Comment=Protect your pictures
Exec=gnome-control-center camera
# FIXME
# Translators: Do NOT translate or transliterate this text (this is an icon file name)!
Icon=org.gnome.Settings-camera-symbolic
Icon=camera-photo
Terminal=false
Type=Application
NoDisplay=true
@@ -15,5 +15,5 @@ X-GNOME-Bugzilla-Bugzilla=GNOME
X-GNOME-Bugzilla-Product=gnome-control-center
X-GNOME-Bugzilla-Component=privacy
X-GNOME-Bugzilla-Version=@VERSION@
# Translators: Search terms to find the Camera panel. Do NOT translate or localize the semicolons! The list MUST also end with a semicolon!
Keywords=camera;photos;video;webcam;lock;private;privacy;
# Translators: Search terms to find the Privacy panel. Do NOT translate or localize the semicolons! The list MUST also end with a semicolon!
Keywords=screen;lock;diagnostics;crash;private;recent;temporary;tmp;index;name;network;identity;

View File

@@ -1,4 +0,0 @@
install_data(
'scalable/org.gnome.Settings-camera-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 6.414062 0 c -0.265624 0 -0.519531 0.105469 -0.707031 0.292969 l -1.707031 1.707031 h -1.085938 c -1.644531 0 -2.9999995 1.355469 -2.9999995 3 v 7 c 0 1.644531 1.3554685 3 2.9999995 3 h 10 c 1.644532 0 3 -1.355469 3 -3 v -7 c 0 -1.644531 -1.355468 -3 -3 -3 h -1.085937 l -1.707031 -1.707031 c -0.1875 -0.1875 -0.441406 -0.292969 -0.707032 -0.292969 z m 0.414063 2 h 2.171875 l 1.707031 1.707031 c 0.1875 0.1875 0.441407 0.292969 0.707031 0.292969 h 1.5 c 0.570313 0 1 0.429688 1 1 v 7 c 0 0.570312 -0.429687 1 -1 1 h -10 c -0.570312 0 -1 -0.429688 -1 -1 v -7 c 0 -0.570312 0.429688 -1 1 -1 h 1.5 c 0.265626 0 0.519532 -0.105469 0.707032 -0.292969 z m 1.085937 3 c -1.644531 0 -3 1.355469 -3 3 s 1.585938 3 3 3 c 1.414063 0 3 -1.355469 3 -3 s -1.355468 -3 -3 -3 z m 0 2 c 0.5625 0 1 0.4375 1 1 s -0.4375 1 -1 1 s -1 -0.4375 -1 -1 s 0.4375 -1 1 -1 z m 0 0" fill="#2e3434"/>
</svg>

Before

Width:  |  Height:  |  Size: 1021 B

View File

@@ -37,5 +37,3 @@ panels_libs += static_library(
dependencies: common_deps,
c_args: cflags
)
subdir('icons')

View File

@@ -29,7 +29,7 @@
#include <colord-session/cd-session.h>
#define GNOME_DESKTOP_USE_UNSTABLE_API
#include <gnome-rr/gnome-rr.h>
#include <libgnome-desktop/gnome-rr.h>
#include "cc-color-calibrate.h"
@@ -170,7 +170,7 @@ cc_color_calibrate_calib_setup_screen (CcColorCalibrate *calibrate,
gboolean ret = TRUE;
/* get screen */
calibrate->x11_screen = gnome_rr_screen_new (gdk_display_get_default (), error);
calibrate->x11_screen = gnome_rr_screen_new (gdk_screen_get_default (), error);
if (calibrate->x11_screen == NULL)
{
ret = FALSE;
@@ -603,6 +603,94 @@ cc_color_calibrate_cancel (CcColorCalibrate *calibrate)
g_main_loop_quit (calibrate->loop);
}
static gboolean
cc_color_calibrate_move_and_resize_window (GtkWindow *window,
CdDevice *device,
GError **error)
{
const gchar *xrandr_name;
gboolean ret = TRUE;
GdkRectangle rect;
GdkDisplay *display;
GdkMonitor *monitor;
gint i;
gint monitor_num = -1;
gint num_monitors;
/* find the monitor num of the device output */
display = gdk_display_get_default ();
num_monitors = gdk_display_get_n_monitors (display);
xrandr_name = cd_device_get_metadata_item (device, CD_DEVICE_METADATA_XRANDR_NAME);
for (i = 0; i < num_monitors; i++)
{
const gchar *plug_name;
monitor = gdk_display_get_monitor (display, i);
plug_name = gdk_monitor_get_model (monitor);
if (g_strcmp0 (plug_name, xrandr_name) == 0)
monitor_num = i;
}
if (monitor_num == -1)
{
ret = FALSE;
g_set_error (error,
CD_SESSION_ERROR,
CD_SESSION_ERROR_INTERNAL,
"failed to find output %s",
xrandr_name);
goto out;
}
/* move the window, and set it to the right size */
monitor = gdk_display_get_monitor (display, monitor_num);
gdk_monitor_get_geometry (monitor, &rect);
gtk_window_move (window, rect.x, rect.y);
gtk_window_resize (window, rect.width, rect.height);
g_debug ("Setting window to %ix%i with size %ix%i",
rect.x, rect.y, rect.width, rect.height);
out:
return ret;
}
static void
cc_color_calibrate_window_realize_cb (CcColorCalibrate *self)
{
GtkWidget *widget;
widget = GTK_WIDGET (gtk_builder_get_object (self->builder,
"dialog_calibrate"));
gtk_window_fullscreen (GTK_WINDOW (widget));
gtk_window_maximize (GTK_WINDOW (widget));
}
static gboolean
cc_color_calibrate_window_state_cb (CcColorCalibrate *calibrate,
GdkEvent *event)
{
gboolean ret;
g_autoptr(GError) error = NULL;
GdkEventWindowState *event_state = (GdkEventWindowState *) event;
GtkWindow *window;
window = GTK_WINDOW (gtk_builder_get_object (calibrate->builder,
"dialog_calibrate"));
/* check event */
if (event->type != GDK_WINDOW_STATE)
return TRUE;
if (event_state->changed_mask != GDK_WINDOW_STATE_FULLSCREEN)
return TRUE;
/* resize to the correct screen */
ret = cc_color_calibrate_move_and_resize_window (window,
calibrate->device,
&error);
if (!ret)
g_warning ("Failed to resize window: %s", error->message);
return TRUE;
}
static void
cc_color_calibrate_button_done_cb (CcColorCalibrate *calibrate)
{
@@ -642,7 +730,6 @@ cc_color_calibrate_button_cancel_cb (CcColorCalibrate *calibrate)
cc_color_calibrate_cancel (calibrate);
}
#if 0
static gboolean
cc_color_calibrate_alpha_window_draw (CcColorCalibrate *calibrate, cairo_t *cr)
{
@@ -682,7 +769,6 @@ cc_color_calibrate_alpha_screen_changed_cb (CcColorCalibrate *calibrate)
visual = gdk_screen_get_system_visual (screen);
gtk_widget_set_visual (GTK_WIDGET (window), visual);
}
#endif
static void
cc_color_calibrate_uninhibit (CcColorCalibrate *calibrate)
@@ -899,12 +985,20 @@ cc_color_calibrate_start (CcColorCalibrate *calibrate,
return TRUE;
}
static gboolean
cc_color_calibrate_delete_event_cb (CcColorCalibrate *calibrate)
{
/* do not destroy the window */
cc_color_calibrate_cancel (calibrate);
return TRUE;
}
static void
cc_color_calibrate_finalize (GObject *object)
{
CcColorCalibrate *calibrate = CC_COLOR_CALIBRATE (object);
g_clear_pointer (&calibrate->window, gtk_window_destroy);
g_clear_pointer ((GtkWidget **)&calibrate->window, gtk_widget_destroy);
g_clear_object (&calibrate->builder);
g_clear_object (&calibrate->device);
g_clear_object (&calibrate->proxy_helper);
@@ -950,7 +1044,8 @@ cc_color_calibrate_init (CcColorCalibrate *calibrate)
"vbox_status"));
calibrate->sample_widget = cd_sample_widget_new ();
gtk_widget_set_size_request (calibrate->sample_widget, 400, 400);
gtk_box_prepend (box, calibrate->sample_widget);
gtk_box_pack_start (box, calibrate->sample_widget, FALSE, FALSE, 0);
gtk_box_reorder_child (box, calibrate->sample_widget, 0);
gtk_widget_set_vexpand (calibrate->sample_widget, FALSE);
gtk_widget_set_hexpand (calibrate->sample_widget, FALSE);
@@ -981,6 +1076,19 @@ cc_color_calibrate_init (CcColorCalibrate *calibrate)
/* setup the specialist calibration window */
window = GTK_WINDOW (gtk_builder_get_object (calibrate->builder,
"dialog_calibrate"));
g_signal_connect_object (window, "draw",
G_CALLBACK (cc_color_calibrate_alpha_window_draw), calibrate, G_CONNECT_SWAPPED);
g_signal_connect_object (window, "realize",
G_CALLBACK (cc_color_calibrate_window_realize_cb), calibrate, G_CONNECT_SWAPPED);
g_signal_connect_object (window, "window-state-event",
G_CALLBACK (cc_color_calibrate_window_state_cb), calibrate, G_CONNECT_SWAPPED);
g_signal_connect_object (window, "delete-event",
G_CALLBACK (cc_color_calibrate_delete_event_cb), calibrate, G_CONNECT_SWAPPED);
gtk_widget_set_app_paintable (GTK_WIDGET (window), TRUE);
gtk_window_set_keep_above (window, TRUE);
cc_color_calibrate_alpha_screen_changed_cb (calibrate);
g_signal_connect_object (window, "screen-changed",
G_CALLBACK (cc_color_calibrate_alpha_screen_changed_cb), calibrate, G_CONNECT_SWAPPED);
calibrate->window = window;
}

View File

@@ -2,65 +2,114 @@
<interface>
<!-- interface-requires gtk+ 3.0 -->
<object class="GtkDialog" id="dialog_calibrate">
<property name="margin_top">32</property>
<property name="margin_bottom">32</property>
<property name="margin_start">12</property>
<property name="margin_end">12</property>
<property name="can_focus">False</property>
<property name="border_width">12</property>
<property name="title" translatable="yes">Display Calibration</property>
<property name="hide_titlebar_when_maximized">True</property>
<property name="type_hint">dialog</property>
<property name="deletable">False</property>
<style>
<class name="osd"/>
</style>
<child>
<child internal-child="vbox">
<object class="GtkBox" id="dialog-vbox4">
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<property name="spacing">12</property>
<child internal-child="action_area">
<object class="GtkBox" id="dialog-action_area1">
<object class="GtkButtonBox" id="dialog-action_area1">
<property name="can_focus">False</property>
<property name="layout_style">end</property>
<child>
<object class="GtkButton" id="button_cancel">
<property name="label" translatable="yes">_Cancel</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="use_underline">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
<property name="secondary">True</property>
</packing>
</child>
<child>
<object class="GtkButton" id="button_start">
<property name="label" translatable="yes" comments="This starts the calibration process">_Start</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="use_underline">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkButton" id="button_resume">
<property name="label" translatable="yes" comments="This resumes the calibration process">_Resume</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="use_underline">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
<child>
<object class="GtkButton" id="button_done">
<property name="label" translatable="yes" comments="This button returns the user back to the color control panel">_Done</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="use_underline">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">3</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="pack_type">end</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkBox" id="vbox_status">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">center</property>
<property name="valign">center</property>
<property name="hexpand">True</property>
<property name="vexpand">True</property>
<property name="orientation">vertical</property>
<property name="spacing">15</property>
<child>
<object class="GtkImage" id="image_status">
<property name="valign">end</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="yalign">1</property>
<property name="pixel_size">192</property>
<property name="icon_name">address-book-new</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label_status">
<property name="valign">start</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="yalign">0</property>
<property name="label">Do not disturb the calibration device while in progress</property>
<property name="justify">center</property>
<property name="wrap">True</property>
@@ -69,12 +118,30 @@
<attribute name="foreground" value="#ffffffffffff"/>
</attributes>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkProgressBar" id="progressbar_status">
<property name="visible">True</property>
<property name="can_focus">False</property>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="padding">25</property>
<property name="position">2</property>
</packing>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">False</property>
<property name="position">1</property>
</packing>
</child>
</object>
</child>

View File

@@ -77,12 +77,12 @@ cc_color_cell_renderer_text_set_property (GObject *object, guint param_id,
}
static void
cc_color_cell_renderer_snapshot (GtkCellRenderer *cell,
GtkSnapshot *snapshot,
GtkWidget *widget,
const GdkRectangle *background_area,
const GdkRectangle *cell_area,
GtkCellRendererState flags)
cc_color_cell_renderer_render (GtkCellRenderer *cell,
cairo_t *cr,
GtkWidget *widget,
const GdkRectangle *background_area,
const GdkRectangle *cell_area,
GtkCellRendererState flags)
{
CcColorCellRendererText *renderer;
GtkStyleContext *context;
@@ -94,9 +94,9 @@ cc_color_cell_renderer_snapshot (GtkCellRenderer *cell,
gtk_style_context_add_class (context, "dim-label");
else
gtk_style_context_remove_class (context, "dim-label");
GTK_CELL_RENDERER_CLASS (parent_class)->snapshot (cell, snapshot, widget,
background_area,
cell_area, flags);
GTK_CELL_RENDERER_CLASS (parent_class)->render (cell, cr, widget,
background_area,
cell_area, flags);
gtk_style_context_restore (context);
}
@@ -105,7 +105,7 @@ cc_color_cell_renderer_text_class_init (CcColorCellRendererTextClass *class)
{
GObjectClass *object_class = G_OBJECT_CLASS (class);
GtkCellRendererClass *object_class_gcr = GTK_CELL_RENDERER_CLASS (class);
object_class_gcr->snapshot = cc_color_cell_renderer_snapshot;
object_class_gcr->render = cc_color_cell_renderer_render;
parent_class = g_type_class_peek_parent (class);

View File

@@ -63,6 +63,7 @@ cc_color_device_refresh (CcColorDevice *color_device)
{
g_autofree gchar *title = NULL;
g_autoptr(GPtrArray) profiles = NULL;
AtkObject *accessible;
g_autofree gchar *name1 = NULL;
g_autofree gchar *name2 = NULL;
@@ -78,21 +79,20 @@ cc_color_device_refresh (CcColorDevice *color_device)
gtk_widget_set_visible (color_device->widget_switch, profiles->len > 0);
gtk_widget_set_visible (color_device->widget_button, profiles->len > 0);
gtk_image_set_from_icon_name (GTK_IMAGE (color_device->widget_arrow),
color_device->expanded ? "pan-down-symbolic" : "pan-end-symbolic");
color_device->expanded ? "pan-down-symbolic" : "pan-end-symbolic",
GTK_ICON_SIZE_BUTTON);
gtk_widget_set_visible (color_device->widget_nocalib, profiles->len == 0);
gtk_widget_set_sensitive (color_device->widget_button, cd_device_get_enabled (color_device->device));
gtk_switch_set_active (GTK_SWITCH (color_device->widget_switch),
cd_device_get_enabled (color_device->device));
accessible = gtk_widget_get_accessible (color_device->widget_switch);
name1 = g_strdup_printf (_("Enable color management for %s"), title);
gtk_accessible_update_property (GTK_ACCESSIBLE (color_device->widget_switch),
GTK_ACCESSIBLE_PROPERTY_LABEL, name1,
-1);
atk_object_set_name (accessible, name1);
name2 = g_strdup_printf (_("Show color profiles for %s"), title);
gtk_accessible_update_property (GTK_ACCESSIBLE (color_device->widget_button),
GTK_ACCESSIBLE_PROPERTY_LABEL, name2,
-1);
accessible = gtk_widget_get_accessible (color_device->widget_button);
atk_object_set_name (accessible, name2);
}
CdDevice *
@@ -263,40 +263,41 @@ cc_color_device_init (CcColorDevice *color_device)
gtk_widget_set_margin_top (color_device->widget_description, 12);
gtk_widget_set_margin_bottom (color_device->widget_description, 12);
gtk_widget_set_halign (color_device->widget_description, GTK_ALIGN_START);
gtk_widget_set_hexpand (color_device->widget_description, TRUE);
gtk_label_set_ellipsize (GTK_LABEL (color_device->widget_description), PANGO_ELLIPSIZE_END);
gtk_label_set_xalign (GTK_LABEL (color_device->widget_description), 0);
gtk_box_append (GTK_BOX (box), color_device->widget_description);
gtk_box_pack_start (GTK_BOX (box), color_device->widget_description, TRUE, TRUE, 0);
/* switch */
color_device->widget_switch = gtk_switch_new ();
gtk_widget_set_valign (color_device->widget_switch, GTK_ALIGN_CENTER);
gtk_box_append (GTK_BOX (box), color_device->widget_switch);
gtk_box_pack_start (GTK_BOX (box), color_device->widget_switch, FALSE, FALSE, 0);
/* arrow button */
color_device->widget_arrow = gtk_image_new_from_icon_name ("pan-end-symbolic");
color_device->widget_arrow = gtk_image_new_from_icon_name ("pan-end-symbolic",
GTK_ICON_SIZE_BUTTON);
color_device->widget_button = gtk_button_new ();
g_signal_connect_object (color_device->widget_button, "clicked",
G_CALLBACK (cc_color_device_clicked_expander_cb),
color_device, G_CONNECT_SWAPPED);
gtk_widget_set_valign (color_device->widget_button, GTK_ALIGN_CENTER);
gtk_widget_add_css_class (color_device->widget_button, "flat");
gtk_button_set_child (GTK_BUTTON (color_device->widget_button), color_device->widget_arrow);
gtk_button_set_relief (GTK_BUTTON (color_device->widget_button), GTK_RELIEF_NONE);
gtk_container_add (GTK_CONTAINER (color_device->widget_button), color_device->widget_arrow);
gtk_widget_set_visible (color_device->widget_arrow, TRUE);
gtk_widget_set_margin_top (color_device->widget_button, 9);
gtk_widget_set_margin_bottom (color_device->widget_button, 9);
gtk_widget_set_margin_end (color_device->widget_button, 12);
gtk_box_append (GTK_BOX (box), color_device->widget_button);
gtk_box_pack_start (GTK_BOX (box), color_device->widget_button, FALSE, FALSE, 0);
/* not calibrated */
color_device->widget_nocalib = gtk_label_new (_("Not calibrated"));
context = gtk_widget_get_style_context (color_device->widget_nocalib);
gtk_style_context_add_class (context, "dim-label");
gtk_widget_set_margin_end (color_device->widget_nocalib, 18);
gtk_box_append (GTK_BOX (box), color_device->widget_nocalib);
gtk_box_pack_start (GTK_BOX (box), color_device->widget_nocalib, FALSE, FALSE, 0);
/* refresh */
gtk_list_box_row_set_child (GTK_LIST_BOX_ROW (color_device), box);
gtk_container_add (GTK_CONTAINER (color_device), box);
gtk_widget_set_visible (box, TRUE);
}
GtkWidget *

View File

@@ -23,8 +23,10 @@
#include <glib/gi18n.h>
#include <colord.h>
#include <gtk/gtk.h>
#include <gdk/x11/gdkx.h>
#include <gdk/gdkx.h>
#include <libsoup/soup.h>
#include "list-box-helper.h"
#include "cc-color-calibrate.h"
#include "cc-color-cell-renderer-text.h"
#include "cc-color-panel.h"
@@ -53,17 +55,22 @@ struct _CcColorPanel
GtkWidget *box_calib_temp;
GtkWidget *box_calib_title;
GtkWidget *box_devices;
GtkWidget *button_assign_cancel;
GtkWidget *button_assign_import;
GtkWidget *button_assign_ok;
GtkWidget *button_calib_export;
GtkWidget *button_calib_upload;
GtkWidget *dialog_assign;
GtkWidget *entry_calib_title;
GtkWidget *frame_devices;
GtkWidget *label_assign_warning;
GtkWidget *label_calib_summary_message;
GtkWidget *label_calib_upload_location;
GtkWidget *label_no_devices;
GtkTreeModel *liststore_assign;
GtkTreeModel *liststore_calib_kind;
GtkTreeModel *liststore_calib_sensor;
GtkWidget *main_window;
GtkWidget *toolbar_devices;
GtkWidget *toolbutton_device_calibrate;
GtkWidget *toolbutton_device_default;
@@ -215,62 +222,9 @@ gcm_prefs_default_cb (CcColorPanel *prefs)
error->message);
}
typedef struct
{
GtkResponseType response;
GMainLoop *mainloop;
} DialogRunData;
static void
dialog_response_cb (GtkDialog *dialog,
GtkResponseType response,
DialogRunData *run_data)
{
run_data->response = response;
g_main_loop_quit (run_data->mainloop);
}
static gboolean
dialog_close_cb (GtkDialog *dialog,
GtkResponseType response,
DialogRunData *run_data)
{
g_main_loop_quit (run_data->mainloop);
return GDK_EVENT_PROPAGATE;
}
static GtkResponseType
run_dialog (GtkDialog *dialog)
{
g_autoptr(GMainLoop) mainloop = NULL;
DialogRunData run_data;
guint response_id;
guint close_id;
mainloop = g_main_loop_new (NULL, FALSE);
run_data = (DialogRunData) {
.response = GTK_RESPONSE_DELETE_EVENT,
.mainloop = mainloop,
};
response_id = g_signal_connect (dialog, "response", G_CALLBACK (dialog_response_cb), &run_data);
close_id = g_signal_connect (dialog, "close-request", G_CALLBACK (dialog_close_cb), &run_data);
gtk_window_present (GTK_WINDOW (dialog));
g_main_loop_run (mainloop);
g_signal_handler_disconnect (dialog, response_id);
g_signal_handler_disconnect (dialog, close_id);
return run_data.response;
}
static GFile *
gcm_prefs_file_chooser_get_icc_profile (CcColorPanel *prefs)
{
g_autoptr(GFile) current_folder = NULL;
GtkWindow *window;
GtkWidget *dialog;
GFile *file = NULL;
@@ -284,9 +238,9 @@ gcm_prefs_file_chooser_get_icc_profile (CcColorPanel *prefs)
_("_Cancel"), GTK_RESPONSE_CANCEL,
_("_Import"), GTK_RESPONSE_ACCEPT,
NULL);
current_folder = g_file_new_for_path (g_get_home_dir ());
gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER(dialog), current_folder, NULL);
gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER(dialog), g_get_home_dir ());
gtk_file_chooser_set_create_folders (GTK_FILE_CHOOSER(dialog), FALSE);
gtk_file_chooser_set_local_only (GTK_FILE_CHOOSER(dialog), FALSE);
/* setup the filter */
filter = gtk_file_filter_new ();
@@ -304,11 +258,11 @@ gcm_prefs_file_chooser_get_icc_profile (CcColorPanel *prefs)
gtk_file_chooser_add_filter (GTK_FILE_CHOOSER(dialog), filter);
/* did user choose file */
if (run_dialog (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT)
if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT)
file = gtk_file_chooser_get_file (GTK_FILE_CHOOSER(dialog));
/* we're done */
gtk_window_destroy (GTK_WINDOW (dialog));
gtk_widget_destroy (dialog);
/* or NULL for missing */
return file;
@@ -357,6 +311,7 @@ gcm_prefs_calib_apply_cb (CcColorPanel *prefs)
GtkWindow *window = NULL;
/* setup the calibration object with items that can fail */
gtk_widget_show (prefs->button_calib_upload);
ret = cc_color_calibrate_setup (prefs->calibrate,
&error);
if (!ret)
@@ -383,6 +338,14 @@ gcm_prefs_calib_apply_cb (CcColorPanel *prefs)
gtk_widget_hide (GTK_WIDGET (window));
}
static gboolean
gcm_prefs_calib_delete_event_cb (CcColorPanel *prefs)
{
/* do not destroy the window */
gcm_prefs_calib_cancel_cb (prefs);
return TRUE;
}
static void
gcm_prefs_calib_temp_treeview_clicked_cb (CcColorPanel *prefs,
GtkTreeSelection *selection)
@@ -584,7 +547,7 @@ gcm_prefs_calibrate_display (CcColorPanel *prefs)
tmp = cd_device_get_vendor (prefs->current_device);
if (tmp == NULL)
tmp = _("Screen");
gtk_editable_set_text (GTK_EDITABLE (prefs->entry_calib_title), tmp);
gtk_entry_set_text (GTK_ENTRY (prefs->entry_calib_title), tmp);
cc_color_calibrate_set_title (prefs->calibrate, tmp);
/* set the display whitepoint to D65 by default */
@@ -592,7 +555,7 @@ gcm_prefs_calibrate_display (CcColorPanel *prefs)
/* show ui */
gtk_window_set_transient_for (GTK_WINDOW (prefs->assistant_calib),
GTK_WINDOW (gtk_widget_get_native (GTK_WIDGET (prefs))));
GTK_WINDOW (prefs->main_window));
gtk_widget_show (prefs->assistant_calib);
}
@@ -603,7 +566,7 @@ gcm_prefs_title_entry_changed_cb (CcColorPanel *prefs)
const gchar *value;
assistant = GTK_ASSISTANT (prefs->assistant_calib);
value = gtk_editable_get_text (GTK_EDITABLE (prefs->entry_calib_title));
value = gtk_entry_get_text (GTK_ENTRY (prefs->entry_calib_title));
cc_color_calibrate_set_title (prefs->calibrate, value);
gtk_assistant_set_page_complete (assistant, prefs->box_calib_title, value[0] != '\0');
}
@@ -611,11 +574,9 @@ gcm_prefs_title_entry_changed_cb (CcColorPanel *prefs)
static void
gcm_prefs_calibrate_cb (CcColorPanel *prefs)
{
GtkNative *native;
GdkSurface *surface;
gboolean ret;
g_autoptr(GError) error = NULL;
guint xid = 0;
guint xid;
g_autoptr(GPtrArray) argv = NULL;
/* use the new-style calibration helper */
@@ -626,11 +587,7 @@ gcm_prefs_calibrate_cb (CcColorPanel *prefs)
}
/* get xid */
native = gtk_widget_get_native (GTK_WIDGET (prefs));
surface = gtk_native_get_surface (native);
if (GDK_IS_X11_SURFACE (surface))
xid = gdk_x11_surface_get_xid (GDK_X11_SURFACE (surface));
xid = gdk_x11_window_get_xid (gtk_widget_get_window (GTK_WIDGET (prefs->main_window)));
/* run with modal set */
argv = g_ptr_array_new_with_free_func (g_free);
@@ -818,6 +775,91 @@ gcm_prefs_add_profiles_suitable_for_devices (CcColorPanel *prefs,
}
}
static void
gcm_prefs_calib_upload_cb (CcColorPanel *prefs)
{
CdProfile *profile;
const gchar *uri;
gboolean ret;
g_autofree gchar *upload_uri = NULL;
g_autofree gchar *msg_result = NULL;
g_autofree gchar *data = NULL;
g_autoptr(GError) error = NULL;
gsize length;
guint status_code;
g_autoptr(SoupBuffer) buffer = NULL;
g_autoptr(SoupMessage) msg = NULL;
g_autoptr(SoupMultipart) multipart = NULL;
g_autoptr(SoupSession) session = NULL;
profile = cc_color_calibrate_get_profile (prefs->calibrate);
ret = cd_profile_connect_sync (profile, NULL, &error);
if (!ret)
{
g_warning ("Failed to get imported profile: %s", error->message);
return;
}
/* read file */
ret = g_file_get_contents (cd_profile_get_filename (profile),
&data,
&length,
&error);
if (!ret)
{
g_warning ("Failed to read file: %s", error->message);
return;
}
/* setup the session */
session = soup_session_new_with_options (SOUP_SESSION_USER_AGENT, "gnome-control-center",
SOUP_SESSION_TIMEOUT, 5000,
NULL);
if (session == NULL)
{
g_warning ("Failed to setup networking");
return;
}
soup_session_add_feature_by_type (session, SOUP_TYPE_PROXY_RESOLVER_DEFAULT);
/* create multipart form and upload file */
multipart = soup_multipart_new (SOUP_FORM_MIME_TYPE_MULTIPART);
buffer = soup_buffer_new (SOUP_MEMORY_STATIC, data, length);
soup_multipart_append_form_file (multipart,
"upload",
cd_profile_get_filename (profile),
NULL,
buffer);
upload_uri = g_settings_get_string (prefs->settings_colord, "profile-upload-uri");
msg = soup_form_request_new_from_multipart (upload_uri, multipart);
status_code = soup_session_send_message (session, msg);
if (status_code != 201)
{
/* TRANSLATORS: this is when the upload of the profile failed */
msg_result = g_strdup_printf (_("Failed to upload file: %s"), msg->reason_phrase),
gtk_label_set_label (GTK_LABEL (prefs->label_calib_upload_location), msg_result);
gtk_widget_show (prefs->label_calib_upload_location);
return;
}
/* show instructions to the user */
uri = soup_message_headers_get_one (msg->response_headers, "Location");
msg_result = g_strdup_printf ("%s %s\n\n• %s\n• %s\n• %s",
/* TRANSLATORS: these are instructions on how to recover
* the ICC profile on the native operating system and are
* only shown when the user uses a LiveCD to calibrate */
_("The profile has been uploaded to:"),
uri,
_("Write down this URL."),
_("Restart this computer and boot your normal operating system."),
_("Type the URL into your browser to download and install the profile.")),
gtk_label_set_label (GTK_LABEL (prefs->label_calib_upload_location), msg_result);
gtk_widget_show (prefs->label_calib_upload_location);
/* hide the upload button as duplicate uploads will fail */
gtk_widget_hide (prefs->button_calib_upload);
}
static void
gcm_prefs_calib_export_cb (CcColorPanel *prefs)
{
@@ -839,16 +881,17 @@ gcm_prefs_calib_export_cb (CcColorPanel *prefs)
/* TRANSLATORS: this is the dialog to save the ICC profile */
dialog = gtk_file_chooser_dialog_new (_("Save Profile"),
GTK_WINDOW (gtk_widget_get_native (GTK_WIDGET (prefs))),
GTK_WINDOW (prefs->main_window),
GTK_FILE_CHOOSER_ACTION_SAVE,
_("_Cancel"), GTK_RESPONSE_CANCEL,
_("_Save"), GTK_RESPONSE_ACCEPT,
NULL);
gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (dialog), TRUE);
default_name = g_strdup_printf ("%s.icc", cd_profile_get_title (profile));
gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (dialog), default_name);
if (run_dialog (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT)
if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT)
{
source = g_file_new_for_path (cd_profile_get_filename (profile));
destination = gtk_file_chooser_get_file (GTK_FILE_CHOOSER (dialog));
@@ -863,16 +906,17 @@ gcm_prefs_calib_export_cb (CcColorPanel *prefs)
g_warning ("Failed to copy profile: %s", error->message);
}
gtk_window_destroy (GTK_WINDOW (dialog));
gtk_widget_destroy (dialog);
}
static void
gcm_prefs_calib_export_link_cb (CcColorPanel *prefs,
const gchar *url)
{
gtk_show_uri (GTK_WINDOW (gtk_widget_get_native (GTK_WIDGET (prefs))),
"help:gnome-help/color-howtoimport",
GDK_CURRENT_TIME);
gtk_show_uri_on_window (GTK_WINDOW (prefs->main_window),
"help:gnome-help/color-howtoimport",
GDK_CURRENT_TIME,
NULL);
}
static void
@@ -888,10 +932,8 @@ gcm_prefs_profile_add_cb (CcColorPanel *prefs)
gtk_widget_set_sensitive (prefs->button_assign_ok, FALSE);
/* show the dialog */
gtk_window_set_transient_for (GTK_WINDOW (prefs->dialog_assign),
GTK_WINDOW (gtk_widget_get_native (GTK_WIDGET (prefs))));
gtk_widget_show (prefs->dialog_assign);
gtk_window_set_transient_for (GTK_WINDOW (prefs->dialog_assign), GTK_WINDOW (prefs->main_window));
}
static void
@@ -977,19 +1019,13 @@ gcm_prefs_device_profile_enable_cb (CcColorPanel *prefs)
static void
gcm_prefs_profile_view (CcColorPanel *prefs, CdProfile *profile)
{
GtkNative *native;
GdkSurface *surface;
g_autoptr(GPtrArray) argv = NULL;
guint xid = 0;
guint xid;
gboolean ret;
g_autoptr(GError) error = NULL;
/* get xid */
native = gtk_widget_get_native (GTK_WIDGET (prefs));
surface = gtk_native_get_surface (native);
if (GDK_IS_X11_SURFACE (surface))
xid = gdk_x11_surface_get_xid (GDK_X11_SURFACE (surface));
xid = gdk_x11_window_get_xid (gtk_widget_get_window (GTK_WIDGET (prefs->main_window)));
/* open up gcm-viewer as a info pane */
argv = g_ptr_array_new_with_free_func (g_free);
@@ -1048,6 +1084,12 @@ gcm_prefs_profile_view_cb (CcColorPanel *prefs)
gcm_prefs_profile_view (prefs, profile);
}
static void
gcm_prefs_button_assign_cancel_cb (CcColorPanel *prefs)
{
gtk_widget_hide (prefs->dialog_assign);
}
static void
gcm_prefs_button_assign_ok_cb (CcColorPanel *prefs)
{
@@ -1109,6 +1151,13 @@ gcm_prefs_button_assign_ok_cb (CcColorPanel *prefs)
prefs);
}
static gboolean
gcm_prefs_profile_delete_event_cb (CcColorPanel *prefs)
{
gcm_prefs_button_assign_cancel_cb (prefs);
return TRUE;
}
static void
gcm_prefs_add_profiles_columns (CcColorPanel *prefs,
GtkTreeView *treeview)
@@ -1128,6 +1177,7 @@ gcm_prefs_add_profiles_columns (CcColorPanel *prefs,
/* image */
column = gtk_tree_view_column_new ();
renderer = gtk_cell_renderer_pixbuf_new ();
g_object_set (renderer, "stock-size", GTK_ICON_SIZE_MENU, NULL);
gtk_tree_view_column_pack_start (column, renderer, FALSE);
gtk_tree_view_column_add_attribute (column, renderer,
"icon-name", GCM_PREFS_COMBO_COLUMN_WARNING_FILENAME);
@@ -1400,7 +1450,8 @@ gcm_prefs_add_device_profile (CcColorPanel *prefs,
/* add to listbox */
widget = cc_color_profile_new (device, profile, is_default);
gtk_list_box_append (prefs->list_box, widget);
gtk_widget_show (widget);
gtk_container_add (GTK_CONTAINER (prefs->list_box), widget);
gtk_size_group_add_widget (prefs->list_box_size, widget);
}
@@ -1476,47 +1527,37 @@ gcm_prefs_find_widget_by_object_path (GList *list,
static void
gcm_prefs_device_changed_cb (CcColorPanel *prefs, CdDevice *device)
{
GtkWidget *child;
CdDevice *device_tmp;
CdProfile *profile_tmp;
gboolean ret;
GList *l;
g_autoptr(GList) list = NULL;
GPtrArray *profiles;
guint i;
/* remove anything in the list view that's not in Device.Profiles */
profiles = cd_device_get_profiles (device);
child = gtk_widget_get_first_child (GTK_WIDGET (prefs->list_box));
while (child)
list = gtk_container_get_children (GTK_CONTAINER (prefs->list_box));
for (l = list; l != NULL; l = l->next)
{
GtkWidget *next = gtk_widget_get_next_sibling (child);
if (!CC_IS_COLOR_PROFILE (child))
{
list = g_list_prepend (list, child);
goto next;
}
if (!CC_IS_COLOR_PROFILE (l->data))
continue;
/* correct device ? */
device_tmp = cc_color_profile_get_device (CC_COLOR_PROFILE (child));
device_tmp = cc_color_profile_get_device (CC_COLOR_PROFILE (l->data));
if (g_strcmp0 (cd_device_get_id (device),
cd_device_get_id (device_tmp)) != 0)
{
list = g_list_prepend (list, child);
goto next;
}
continue;
/* if profile is not in Device.Profiles then remove */
profile_tmp = cc_color_profile_get_profile (CC_COLOR_PROFILE (child));
profile_tmp = cc_color_profile_get_profile (CC_COLOR_PROFILE (l->data));
ret = gcm_prefs_find_profile_by_object_path (profiles,
cd_profile_get_object_path (profile_tmp));
if (!ret)
gtk_list_box_remove (prefs->list_box, child);
else
list = g_list_prepend (list, child);
next:
child = next;
if (!ret) {
gtk_widget_destroy (GTK_WIDGET (l->data));
/* Don't look at the destroyed widget below */
l->data = NULL;
}
}
/* add anything in Device.Profiles that's not in the list view */
@@ -1546,20 +1587,20 @@ gcm_prefs_device_expanded_changed_cb (CcColorPanel *prefs,
g_free (prefs->list_box_filter);
if (is_expanded)
{
GtkWidget *child;
g_autoptr(GList) list = NULL;
GList *l;
prefs->list_box_filter = g_strdup (cd_device_get_id (cc_color_device_get_device (widget)));
/* unexpand other device widgets */
list = gtk_container_get_children (GTK_CONTAINER (prefs->list_box));
prefs->model_is_changing = TRUE;
for (child = gtk_widget_get_first_child (GTK_WIDGET (prefs->list_box));
child != NULL;
child = gtk_widget_get_next_sibling (child))
for (l = list; l != NULL; l = l->next)
{
if (!CC_IS_COLOR_DEVICE (child))
if (!CC_IS_COLOR_DEVICE (l->data))
continue;
if (CC_COLOR_DEVICE (child) != widget)
cc_color_device_set_expanded (CC_COLOR_DEVICE (child), FALSE);
if (l->data != widget)
cc_color_device_set_expanded (CC_COLOR_DEVICE (l->data), FALSE);
}
prefs->model_is_changing = FALSE;
}
@@ -1589,7 +1630,8 @@ gcm_prefs_add_device (CcColorPanel *prefs, CdDevice *device)
widget = cc_color_device_new (device);
g_signal_connect_object (widget, "expanded-changed",
G_CALLBACK (gcm_prefs_device_expanded_changed_cb), prefs, G_CONNECT_SWAPPED);
gtk_list_box_append (prefs->list_box, widget);
gtk_widget_show (widget);
gtk_container_add (GTK_CONTAINER (prefs->list_box), widget);
gtk_size_group_add_widget (prefs->list_box_size, widget);
/* add profiles */
@@ -1605,25 +1647,22 @@ gcm_prefs_add_device (CcColorPanel *prefs, CdDevice *device)
static void
gcm_prefs_remove_device (CcColorPanel *prefs, CdDevice *device)
{
GtkWidget *child;
CdDevice *device_tmp;
GList *l;
g_autoptr(GList) list = NULL;
child = gtk_widget_get_first_child (GTK_WIDGET (prefs->list_box));
while (child)
list = gtk_container_get_children (GTK_CONTAINER (prefs->list_box));
for (l = list; l != NULL; l = l->next)
{
GtkWidget *next = gtk_widget_get_next_sibling (child);
if (CC_IS_COLOR_DEVICE (child))
device_tmp = cc_color_device_get_device (CC_COLOR_DEVICE (child));
if (CC_IS_COLOR_DEVICE (l->data))
device_tmp = cc_color_device_get_device (CC_COLOR_DEVICE (l->data));
else
device_tmp = cc_color_profile_get_device (CC_COLOR_PROFILE (child));
device_tmp = cc_color_profile_get_device (CC_COLOR_PROFILE (l->data));
if (g_strcmp0 (cd_device_get_object_path (device),
cd_device_get_object_path (device_tmp)) == 0)
{
gtk_list_box_remove (prefs->list_box, child);
gtk_widget_destroy (GTK_WIDGET (l->data));
}
child = next;
}
g_signal_handlers_disconnect_by_func (device,
G_CALLBACK (gcm_prefs_device_changed_cb),
@@ -1634,16 +1673,18 @@ gcm_prefs_remove_device (CcColorPanel *prefs, CdDevice *device)
static void
gcm_prefs_update_device_list_extra_entry (CcColorPanel *prefs)
{
GtkListBoxRow *first_row;
g_autoptr(GList) device_widgets = NULL;
guint number_of_devices;
/* any devices to show? */
first_row = gtk_list_box_get_row_at_index (prefs->list_box, 0);
gtk_widget_set_visible (prefs->label_no_devices, first_row == NULL);
gtk_widget_set_visible (prefs->box_devices, first_row != NULL);
device_widgets = gtk_container_get_children (GTK_CONTAINER (prefs->list_box));
number_of_devices = g_list_length (device_widgets);
gtk_widget_set_visible (prefs->label_no_devices, number_of_devices == 0);
gtk_widget_set_visible (prefs->box_devices, number_of_devices > 0);
/* if we have only one device expand it by default */
if (gtk_list_box_get_row_at_index (prefs->list_box, 1) == NULL)
cc_color_device_set_expanded (CC_COLOR_DEVICE (first_row), TRUE);
if (number_of_devices == 1)
cc_color_device_set_expanded (CC_COLOR_DEVICE (device_widgets->data), TRUE);
}
static void
@@ -1704,9 +1745,6 @@ static void
gcm_prefs_list_box_row_selected_cb (CcColorPanel *panel,
GtkListBoxRow *row)
{
if (gtk_widget_in_destruction (panel->toolbar_devices))
return;
gcm_prefs_refresh_toolbar_buttons (panel);
}
@@ -1827,6 +1865,12 @@ gcm_prefs_is_livecd (void)
#endif
}
static void
gcm_prefs_window_realize_cb (CcColorPanel *prefs)
{
prefs->main_window = gtk_widget_get_toplevel (GTK_WIDGET (prefs));
}
static const char *
cc_color_panel_get_help_uri (CcPanel *panel)
{
@@ -1873,7 +1917,7 @@ cc_color_panel_dispose (GObject *object)
g_clear_object (&prefs->list_box_size);
g_clear_pointer (&prefs->sensors, g_ptr_array_unref);
g_clear_pointer (&prefs->list_box_filter, g_free);
g_clear_pointer ((GtkWindow **)&prefs->dialog_assign, gtk_window_destroy);
g_clear_pointer (&prefs->dialog_assign, gtk_widget_destroy);
G_OBJECT_CLASS (cc_color_panel_parent_class)->dispose (object);
}
@@ -1909,15 +1953,18 @@ cc_color_panel_class_init (CcColorPanelClass *klass)
gtk_widget_class_bind_template_child (widget_class, CcColorPanel, box_calib_temp);
gtk_widget_class_bind_template_child (widget_class, CcColorPanel, box_calib_title);
gtk_widget_class_bind_template_child (widget_class, CcColorPanel, box_devices);
gtk_widget_class_bind_template_child (widget_class, CcColorPanel, button_assign_cancel);
gtk_widget_class_bind_template_child (widget_class, CcColorPanel, button_assign_import);
gtk_widget_class_bind_template_child (widget_class, CcColorPanel, button_assign_ok);
gtk_widget_class_bind_template_child (widget_class, CcColorPanel, button_calib_export);
gtk_widget_class_bind_template_child (widget_class, CcColorPanel, button_calib_upload);
gtk_widget_class_bind_template_child (widget_class, CcColorPanel, dialog_assign);
gtk_widget_class_bind_template_child (widget_class, CcColorPanel, entry_calib_title);
gtk_widget_class_bind_template_child (widget_class, CcColorPanel, frame_devices);
gtk_widget_class_bind_template_child (widget_class, CcColorPanel, label_assign_warning);
gtk_widget_class_bind_template_child (widget_class, CcColorPanel, label_calib_summary_message);
gtk_widget_class_bind_template_child (widget_class, CcColorPanel, label_calib_upload_location);
gtk_widget_class_bind_template_child (widget_class, CcColorPanel, label_no_devices);
gtk_widget_class_bind_template_child (widget_class, CcColorPanel, list_box);
gtk_widget_class_bind_template_child (widget_class, CcColorPanel, liststore_assign);
gtk_widget_class_bind_template_child (widget_class, CcColorPanel, liststore_calib_kind);
gtk_widget_class_bind_template_child (widget_class, CcColorPanel, liststore_calib_sensor);
@@ -1992,6 +2039,7 @@ static void
cc_color_panel_init (CcColorPanel *prefs)
{
GtkCellRenderer *renderer;
GtkStyleContext *context;
GtkTreeModel *model;
GtkTreeModel *model_filter;
GtkTreeSelection *selection;
@@ -2040,7 +2088,16 @@ cc_color_panel_init (CcColorPanel *prefs)
g_signal_connect_object (prefs->toolbutton_device_calibrate, "clicked",
G_CALLBACK (gcm_prefs_calibrate_cb), prefs, G_CONNECT_SWAPPED);
context = gtk_widget_get_style_context (prefs->toolbar_devices);
gtk_style_context_add_class (context, GTK_STYLE_CLASS_INLINE_TOOLBAR);
gtk_style_context_set_junction_sides (context, GTK_JUNCTION_TOP);
/* set up assign dialog */
g_signal_connect_object (prefs->dialog_assign, "delete-event",
G_CALLBACK (gcm_prefs_profile_delete_event_cb), prefs, G_CONNECT_SWAPPED);
g_signal_connect_object (prefs->button_assign_cancel, "clicked",
G_CALLBACK (gcm_prefs_button_assign_cancel_cb), prefs, G_CONNECT_SWAPPED);
g_signal_connect_object (prefs->button_assign_ok, "clicked",
G_CALLBACK (gcm_prefs_button_assign_ok_cb), prefs, G_CONNECT_SWAPPED);
@@ -2049,6 +2106,9 @@ cc_color_panel_init (CcColorPanel *prefs)
G_CALLBACK (gcm_prefs_button_assign_import_cb), prefs, G_CONNECT_SWAPPED);
/* setup the calibration helper */
g_signal_connect_object (prefs->assistant_calib, "delete-event",
G_CALLBACK (gcm_prefs_calib_delete_event_cb),
prefs, G_CONNECT_SWAPPED);
g_signal_connect_object (prefs->assistant_calib, "apply",
G_CALLBACK (gcm_prefs_calib_apply_cb),
prefs, G_CONNECT_SWAPPED);
@@ -2164,6 +2224,7 @@ cc_color_panel_init (CcColorPanel *prefs)
G_CALLBACK (gcm_prefs_device_removed_cb), prefs, 0);
/* use a listbox for the main UI */
prefs->list_box = GTK_LIST_BOX (gtk_list_box_new ());
gtk_list_box_set_filter_func (prefs->list_box,
cc_color_panel_filter_func,
prefs,
@@ -2172,6 +2233,12 @@ cc_color_panel_init (CcColorPanel *prefs)
cc_color_panel_sort_func,
prefs,
NULL);
gtk_list_box_set_header_func (prefs->list_box,
cc_list_box_update_header_func,
prefs, NULL);
gtk_list_box_set_selection_mode (prefs->list_box,
GTK_SELECTION_SINGLE);
gtk_list_box_set_activate_on_single_click (prefs->list_box, FALSE);
g_signal_connect_object (prefs->list_box, "row-selected",
G_CALLBACK (gcm_prefs_list_box_row_selected_cb),
prefs, G_CONNECT_SWAPPED);
@@ -2180,6 +2247,9 @@ cc_color_panel_init (CcColorPanel *prefs)
prefs, G_CONNECT_SWAPPED);
prefs->list_box_size = gtk_size_group_new (GTK_SIZE_GROUP_VERTICAL);
gtk_container_add (GTK_CONTAINER (prefs->frame_devices), GTK_WIDGET (prefs->list_box));
gtk_widget_show (GTK_WIDGET (prefs->list_box));
/* connect to colord */
cd_client_connect (prefs->client,
cc_panel_get_cancellable (CC_PANEL (prefs)),
@@ -2202,6 +2272,12 @@ cc_color_panel_init (CcColorPanel *prefs)
gtk_widget_set_visible (prefs->box_calib_summary, prefs->is_live_cd);
g_signal_connect_object (prefs->button_calib_export, "clicked",
G_CALLBACK (gcm_prefs_calib_export_cb), prefs, G_CONNECT_SWAPPED);
g_signal_connect_object (prefs->button_calib_upload, "clicked",
G_CALLBACK (gcm_prefs_calib_upload_cb), prefs, G_CONNECT_SWAPPED);
g_signal_connect_object (prefs->label_calib_summary_message, "activate-link",
G_CALLBACK (gcm_prefs_calib_export_link_cb), prefs, G_CONNECT_SWAPPED);
g_signal_connect (prefs, "realize",
G_CALLBACK (gcm_prefs_window_realize_cb),
NULL);
}

File diff suppressed because it is too large Load Diff

View File

@@ -435,10 +435,10 @@ cc_color_profile_init (CcColorProfile *color_profile)
box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 9);
/* default tick */
color_profile->widget_image = gtk_image_new_from_icon_name ("object-select-symbolic");
color_profile->widget_image = gtk_image_new_from_icon_name ("object-select-symbolic", GTK_ICON_SIZE_MENU);
gtk_widget_set_margin_start (color_profile->widget_image, IMAGE_WIDGET_PADDING);
gtk_widget_set_margin_end (color_profile->widget_image, IMAGE_WIDGET_PADDING);
gtk_box_append (GTK_BOX (box), color_profile->widget_image);
gtk_box_pack_start (GTK_BOX (box), color_profile->widget_image, FALSE, FALSE, 0);
/* description */
color_profile->widget_description = gtk_label_new ("");
@@ -447,18 +447,18 @@ cc_color_profile_init (CcColorProfile *color_profile)
gtk_widget_set_halign (color_profile->widget_description, GTK_ALIGN_START);
gtk_label_set_ellipsize (GTK_LABEL (color_profile->widget_description), PANGO_ELLIPSIZE_END);
gtk_label_set_xalign (GTK_LABEL (color_profile->widget_description), 0);
gtk_widget_set_hexpand (color_profile->widget_description, TRUE);
gtk_widget_set_vexpand (color_profile->widget_description, TRUE);
gtk_box_append (GTK_BOX (box), color_profile->widget_description);
gtk_box_pack_start (GTK_BOX (box), color_profile->widget_description, TRUE, TRUE, 0);
gtk_widget_show (color_profile->widget_description);
/* profile warnings/info */
color_profile->widget_info = gtk_image_new_from_icon_name ("dialog-information-symbolic");
color_profile->widget_info = gtk_image_new_from_icon_name ("dialog-information-symbolic", GTK_ICON_SIZE_MENU);
gtk_widget_set_margin_start (color_profile->widget_info, IMAGE_WIDGET_PADDING);
gtk_widget_set_margin_end (color_profile->widget_info, IMAGE_WIDGET_PADDING);
gtk_box_append (GTK_BOX (box), color_profile->widget_info);
gtk_box_pack_start (GTK_BOX (box), color_profile->widget_info, FALSE, FALSE, 0);
/* refresh */
gtk_list_box_row_set_child (GTK_LIST_BOX_ROW (color_profile), box);
gtk_container_add (GTK_CONTAINER (color_profile), box);
gtk_widget_set_visible (box, TRUE);
}
GtkWidget *

View File

@@ -3,7 +3,7 @@ Name=Color
Comment=Calibrate the color of your devices, such as displays, cameras or printers
Exec=gnome-control-center color
# Translators: Do NOT translate or transliterate this text (this is an icon file name)!
Icon=org.gnome.Settings-color-symbolic
Icon=preferences-color
Terminal=false
Type=Application
NoDisplay=true
@@ -17,4 +17,4 @@ X-GNOME-Bugzilla-Version=@VERSION@
# Translators: Search terms to find the Color panel. Do NOT translate or localize the semicolons! The list MUST also end with a semicolon!
Keywords=Color;ICC;Profile;Calibrate;Printer;Display;
# Notifications are emitted by gnome-settings-daemon
X-GNOME-UsesNotifications=true
X-GNOME-UsesNotifications=true

Binary file not shown.

After

Width:  |  Height:  |  Size: 837 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

View File

@@ -1,4 +1,21 @@
icon_sizes = [
'16x16',
'22x22',
'24x24',
'32x32',
'48x48',
'64x64',
'256x256'
]
foreach icon_size: icon_sizes
install_data(
join_paths(icon_size, 'preferences-color.png'),
install_dir: join_paths(control_center_icondir, 'hicolor', icon_size, 'apps')
)
endforeach
install_data(
'scalable/org.gnome.Settings-color-symbolic.svg',
'scalable/preferences-color.svg',
install_dir: join_paths(control_center_icondir, 'hicolor', 'scalable', 'apps')
)

View File

@@ -0,0 +1,149 @@
#!/usr/bin/env python
import os
import sys
import xml.sax
import subprocess
INKSCAPE = '/usr/bin/inkscape'
SRC = os.path.join('.', 'src')
inkscape_process = None
def wait_for_prompt(process, command=None):
if command is not None:
process.stdin.write(command+'\n')
output = process.stdout.read(1)
output += process.stdout.read(1)
while output != "\n>":
output = output[-1:]
output += process.stdout.read(1)
def start_inkscape():
process = subprocess.Popen([INKSCAPE, '--shell'], bufsize=0, stdin=subprocess.PIPE, stdout=subprocess.PIPE)
wait_for_prompt(process)
return process
def inkscape_render_rect(icon_file, rect, output_file):
global inkscape_process
if inkscape_process is None:
inkscape_process = start_inkscape()
wait_for_prompt(inkscape_process, '%s -i %s -e %s' % (icon_file, rect, output_file))
class ContentHandler(xml.sax.ContentHandler):
ROOT = 0
SVG = 1
LAYER = 2
OTHER = 3
TEXT = 4
def __init__(self, path, force=False):
self.stack = [self.ROOT]
self.inside = [self.ROOT]
self.path = path
self.rects = []
self.state = self.ROOT
self.chars = ""
self.force = force
def endDocument(self):
pass
def startElement(self, name, attrs):
if self.inside[-1] == self.ROOT:
if name == "svg":
self.stack.append(self.SVG)
self.inside.append(self.SVG)
return
elif self.inside[-1] == self.SVG:
if (name == "g" and attrs.has_key('inkscape:groupmode') and attrs.has_key('inkscape:label')
and attrs['inkscape:groupmode'] == 'layer' and attrs['inkscape:label'].startswith('baseplate')):
self.stack.append(self.LAYER)
self.inside.append(self.LAYER)
self.context = None
self.icon_name = None
self.rects = []
return
elif self.inside[-1] == self.LAYER:
if name == "text" and attrs.has_key('inkscape:label') and attrs['inkscape:label'] == 'context':
self.stack.append(self.TEXT)
self.inside.append(self.TEXT)
self.text='context'
self.chars = ""
return
elif name == "text" and attrs.has_key('inkscape:label') and attrs['inkscape:label'] == 'icon-name':
self.stack.append(self.TEXT)
self.inside.append(self.TEXT)
self.text='icon-name'
self.chars = ""
return
elif name == "rect":
self.rects.append(attrs)
self.stack.append(self.OTHER)
def endElement(self, name):
stacked = self.stack.pop()
if self.inside[-1] == stacked:
self.inside.pop()
if stacked == self.TEXT and self.text is not None:
assert self.text in ['context', 'icon-name']
if self.text == 'context':
self.context = self.chars
elif self.text == 'icon-name':
self.icon_name = self.chars
self.text = None
elif stacked == self.LAYER:
assert self.icon_name
assert self.context
print '%s %s' % (self.context, self.icon_name)
for rect in self.rects:
width = rect['width']
height = rect['height']
id = rect['id']
dir = os.path.join("icons", "%sx%s" % (width, height), self.context)
outfile = os.path.join(dir, self.icon_name+'.png')
if not os.path.exists(dir):
os.makedirs(dir)
# Do a time based check!
if self.force or not os.path.exists(outfile):
inkscape_render_rect(self.path, id, outfile)
sys.stdout.write('.')
else:
stat_in = os.stat(self.path)
stat_out = os.stat(outfile)
if stat_in.st_mtime > stat_out.st_mtime:
inkscape_render_rect(self.path, id, outfile)
sys.stdout.write('.')
else:
sys.stdout.write('-')
sys.stdout.flush()
sys.stdout.write('\n')
sys.stdout.flush()
def characters(self, chars):
self.chars += chars.strip()
if len(sys.argv) == 1:
if not os.path.exists('icons'):
os.mkdir('icons')
print 'Rendering from SVGs in %s' % SRC
for file in os.listdir(SRC):
if file[-4:] == '.svg':
file = os.path.join(SRC, file)
handler = ContentHandler(file)
xml.sax.parse(open(file), handler)
else:
file = os.path.join(SRC, sys.argv[1] + '.svg')
if os.path.exists(os.path.join(file)):
handler = ContentHandler(file, True)
xml.sax.parse(open(file), handler)
else:
print "Error: No such file %s" % file
sys.exit(1)

View File

@@ -1,9 +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">
<g fill="#2e3434">
<path d="m 8.085938 0.015625 c -2.203126 0 -4 1.796875 -4 4 s 1.796874 4 4 4 c 2.203124 0 4 -1.796875 4 -4 s -1.796876 -4 -4 -4 z m 0 1.972656 c 1.121093 -0.003906 2.03125 0.90625 2.027343 2.027344 c 0.003907 1.121094 -0.90625 2.03125 -2.027343 2.027344 c -1.121094 0.003906 -2.027344 -0.90625 -2.027344 -2.027344 s 0.90625 -2.03125 2.027344 -2.027344 z m 0 0"/>
<path d="m 4.070312 7.015625 c -2.21875 0 -4.0312495 1.8125 -4.0312495 4.03125 s 1.8124995 4.03125 4.0312495 4.03125 c 2.222657 0 4.03125 -1.8125 4.03125 -4.03125 s -1.808593 -4.03125 -4.03125 -4.03125 z m 0 1.988281 c 1.132813 -0.003906 2.046876 0.914063 2.042969 2.042969 c 0.003907 1.128906 -0.910156 2.046875 -2.042969 2.042969 c -1.128906 0.003906 -2.042968 -0.914063 -2.042968 -2.042969 s 0.914062 -2.046875 2.042968 -2.042969 z m 0 0"/>
<path d="m 15.992188 11 c 0 2.207031 -1.789063 4 -4 4 c -2.207032 0 -4 -1.789062 -4 -4 s 1.792968 -4 4 -4 c 2.210937 0 4 1.792969 4 4 z m 0 0"/>
<path d="m 6.898438 11 c 0 1.554688 -1.257813 2.8125 -2.8125 2.8125 c -1.550782 0 -2.8125 -1.257812 -2.8125 -2.8125 s 1.261718 -2.8125 2.8125 -2.8125 c 1.554687 0 2.8125 1.257812 2.8125 2.8125 z m 0 0" fill-opacity="0.5"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1.3 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 100 KiB

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