Compare commits
134 Commits
3.31.91
...
gbsneto/au
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
47a2e58d45 | ||
|
|
20d73be57d | ||
|
|
62233a4db4 | ||
|
|
4a7e2ddff5 | ||
|
|
fb737ebde0 | ||
|
|
bf77cb44e7 | ||
|
|
c72e2bb4a9 | ||
|
|
68c182b1df | ||
|
|
348d303794 | ||
|
|
ede0fd8660 | ||
|
|
187c2193e8 | ||
|
|
706bdd8059 | ||
|
|
436861edc8 | ||
|
|
9729a2e772 | ||
|
|
6b924c00c5 | ||
|
|
b90f4d29a4 | ||
|
|
47915f8c11 | ||
|
|
5dfdeaa4ea | ||
|
|
98a2a81f2a | ||
|
|
c4850027bc | ||
|
|
d4202e7f38 | ||
|
|
4f65283f31 | ||
|
|
d86d3bbe54 | ||
|
|
6f794738e8 | ||
|
|
ef7a93bb07 | ||
|
|
5197a992a6 | ||
|
|
49d8540f6d | ||
|
|
6e1a1f1a57 | ||
|
|
c73428247c | ||
|
|
fc2caf5794 | ||
|
|
b117826ada | ||
|
|
26b44b48ab | ||
|
|
6349f0feb1 | ||
|
|
2ae17cfb50 | ||
|
|
4785093a5c | ||
|
|
859aef78c4 | ||
|
|
20730a5465 | ||
|
|
fc5f687afc | ||
|
|
53e56f2395 | ||
|
|
da314aff79 | ||
|
|
fe89f7c5ac | ||
|
|
8b3be5e063 | ||
|
|
58dc538510 | ||
|
|
6cbef9355d | ||
|
|
22eac5c508 | ||
|
|
a2860e9c73 | ||
|
|
1c5258ab68 | ||
|
|
8641eaa538 | ||
|
|
88436383c0 | ||
|
|
affdcdcb0e | ||
|
|
06174be777 | ||
|
|
fde8401124 | ||
|
|
70ac33d58c | ||
|
|
5a897407d9 | ||
|
|
1b3c26364b | ||
|
|
ae07aa7864 | ||
|
|
fb80831269 | ||
|
|
561cecf383 | ||
|
|
60ccdc2deb | ||
|
|
d7d996b1d3 | ||
|
|
32b8bc39ac | ||
|
|
9dc99ad611 | ||
|
|
628cb4d553 | ||
|
|
ad80bce78d | ||
|
|
1c9d821aa2 | ||
|
|
510b060947 | ||
|
|
26e33ff093 | ||
|
|
5f2bd70690 | ||
|
|
6dfa550663 | ||
|
|
252e2420ad | ||
|
|
572d54981e | ||
|
|
61471f9fb4 | ||
|
|
4d0a742d64 | ||
|
|
5f4e0e5ff8 | ||
|
|
a4c159ecad | ||
|
|
b1f893e998 | ||
|
|
789dc165af | ||
|
|
115eda9650 | ||
|
|
d027e35cef | ||
|
|
b3e178af9d | ||
|
|
559ec8750a | ||
|
|
02c3980b83 | ||
|
|
6f027ee7dc | ||
|
|
6d6c2e5b99 | ||
|
|
4a4f752459 | ||
|
|
8f1fff1374 | ||
|
|
deead2af97 | ||
|
|
9e881ab637 | ||
|
|
b6ec02cef2 | ||
|
|
26e3ccda49 | ||
|
|
2bda79cb3a | ||
|
|
19c60ff5c5 | ||
|
|
e3c5c9a2e7 | ||
|
|
2c17c186b8 | ||
|
|
ef1697d00d | ||
|
|
40e7638a4b | ||
|
|
aaf69b2898 | ||
|
|
0464361ca5 | ||
|
|
420697693b | ||
|
|
37f53a42da | ||
|
|
5617ffc79c | ||
|
|
ca4d86e9e5 | ||
|
|
0141fef561 | ||
|
|
5d4a804c90 | ||
|
|
6bc3300e5a | ||
|
|
15f69bdc3b | ||
|
|
0bcf76970a | ||
|
|
03c4628cad | ||
|
|
9f4ae9618a | ||
|
|
3590af15bb | ||
|
|
c5de7fd20e | ||
|
|
7127fb1fa1 | ||
|
|
7cf11abefc | ||
|
|
d78b416e1a | ||
|
|
f5144ec899 | ||
|
|
08d1ebe7ee | ||
|
|
a665801e9f | ||
|
|
112e3b110b | ||
|
|
94a674c008 | ||
|
|
72be8eeb31 | ||
|
|
ad8690bb2e | ||
|
|
76cb08a72a | ||
|
|
2d4989e937 | ||
|
|
f248b91f82 | ||
|
|
d671eb1969 | ||
|
|
70f4906ca5 | ||
|
|
ffb9aa1ace | ||
|
|
823fd855cf | ||
|
|
f5ee225362 | ||
|
|
ff1ea4b1c9 | ||
|
|
779b5afa51 | ||
|
|
6d870f6ae4 | ||
|
|
d3926cbca9 | ||
|
|
a308804679 |
@@ -1,9 +1,18 @@
|
||||
stages:
|
||||
- review
|
||||
- source_check
|
||||
- build
|
||||
- test
|
||||
|
||||
variables:
|
||||
JS_LOG: "js-report.txt"
|
||||
POT_LOG: "pot-update.txt"
|
||||
|
||||
.only_default: &only_default
|
||||
only:
|
||||
- branches
|
||||
- tags
|
||||
- merge_requests
|
||||
|
||||
check_commit_log:
|
||||
image: registry.fedoraproject.org/fedora:latest
|
||||
@@ -16,17 +25,64 @@ check_commit_log:
|
||||
- merge_requests
|
||||
|
||||
js_check:
|
||||
image: registry.fedoraproject.org/fedora:latest
|
||||
image: registry.gitlab.gnome.org/gnome/gnome-shell/extension-ci:v1
|
||||
stage: source_check
|
||||
before_script:
|
||||
- dnf install -y findutils mozjs60-devel
|
||||
script:
|
||||
- find js -name '*.js' -exec js60 -c -s '{}' ';' 2>&1 | tee $JS_LOG
|
||||
- (! grep -q . $JS_LOG)
|
||||
<<: *only_default
|
||||
only:
|
||||
changes:
|
||||
- js/**/*
|
||||
artifacts:
|
||||
paths:
|
||||
- ${JS_LOG}
|
||||
when: on_failure
|
||||
only:
|
||||
- merge_requests
|
||||
- /^.*$/
|
||||
|
||||
build:
|
||||
image: registry.gitlab.gnome.org/gnome/gnome-shell/master:v1
|
||||
stage: build
|
||||
before_script:
|
||||
- .gitlab-ci/checkout-mutter.sh
|
||||
- meson mutter mutter/build --prefix=/usr -Dtests=false
|
||||
- ninja -C mutter/build install
|
||||
script:
|
||||
- meson . build -Dbuiltype=debugoptimized
|
||||
- ninja -C build
|
||||
- ninja -C build install
|
||||
<<: *only_default
|
||||
artifacts:
|
||||
expire_in: 1 day
|
||||
paths:
|
||||
- mutter
|
||||
- build
|
||||
|
||||
test:
|
||||
image: registry.gitlab.gnome.org/gnome/gnome-shell/master:v1
|
||||
stage: test
|
||||
before_script:
|
||||
- ninja -C mutter/build install
|
||||
script:
|
||||
- xvfb-run meson test -C build --no-rebuild
|
||||
<<: *only_default
|
||||
artifacts:
|
||||
expire_in: 1 day
|
||||
paths:
|
||||
- build/meson-logs/testlog.txt
|
||||
when: on_failure
|
||||
|
||||
test-pot:
|
||||
image: registry.gitlab.gnome.org/gnome/gnome-shell/master:v1
|
||||
stage: test
|
||||
before_script:
|
||||
- ninja -C mutter/build install
|
||||
script:
|
||||
# Check that pot files are generated correctly:
|
||||
# https://savannah.gnu.org/bugs/?50920#comment5
|
||||
- ninja -C build gnome-shell-pot 2>&1 | awk '
|
||||
BEGIN { start=0; }
|
||||
start==1 { print $0; }
|
||||
/gnome-shell-pot/ { start=1; }
|
||||
' | tee $POT_LOG
|
||||
- (! grep -q . $POT_LOG)
|
||||
<<: *only_default
|
||||
|
||||
19
.gitlab-ci/Dockerfile
Normal file
19
.gitlab-ci/Dockerfile
Normal file
@@ -0,0 +1,19 @@
|
||||
FROM registry.gitlab.gnome.org/gnome/mutter/master:v1
|
||||
|
||||
RUN dnf -y update && dnf -y upgrade && \
|
||||
dnf install -y 'dnf-command(copr)' && \
|
||||
dnf copr enable -y fmuellner/gnome-shell-ci && \
|
||||
dnf builddep -y gnome-shell --setopt=install_weak_deps=False && \
|
||||
|
||||
# bt only exports HAVE_BLUETOOTH to js, rest are outdated build-requires
|
||||
dnf remove -y gnome-bluetooth-libs-devel dbus-glib-devel \
|
||||
upower-devel python3-devel && \
|
||||
|
||||
# We'll build mutter ourselves
|
||||
dnf remove -y --noautoremove mutter mutter-devel && \
|
||||
|
||||
# Needed for tests
|
||||
dnf install -y '*/xvfb-run' gdm-lib accountsservice-libs && \
|
||||
|
||||
dnf clean all && \
|
||||
rm -rf /var/cache/dnf
|
||||
18
.gitlab-ci/Dockerfile.extension-ci
Normal file
18
.gitlab-ci/Dockerfile.extension-ci
Normal file
@@ -0,0 +1,18 @@
|
||||
FROM registry.fedoraproject.org/fedora:latest
|
||||
|
||||
RUN dnf -y update && dnf -y upgrade && \
|
||||
dnf install -y 'dnf-command(copr)' && \
|
||||
|
||||
# For syntax checks with `find . -name '*.js' -exec js60 -c -s '{}' ';'`
|
||||
dnf install -y findutils mozjs60-devel && \
|
||||
|
||||
# For static analysis with eslint
|
||||
dnf install -y nodejs && \
|
||||
npm install -g eslint && \
|
||||
|
||||
# Shameless plug for my own tooling; useful for generating zip
|
||||
dnf copr enable -y fmuellner/gnome-shell-ci && \
|
||||
dnf install -y gnome-extensions-tool meson && \
|
||||
|
||||
dnf clean all && \
|
||||
rm -rf /var/cache/dnf
|
||||
@@ -11,9 +11,21 @@ branch_point=$(git merge-base HEAD FETCH_HEAD)
|
||||
|
||||
commits=$(git log --format='format:%H' $branch_point..$CI_COMMIT_SHA)
|
||||
|
||||
test -z "$commits" && { echo Commit range empty; exit 1; }
|
||||
if [ -z "$commits" ]; then
|
||||
echo Commit range empty
|
||||
exit 1
|
||||
fi
|
||||
|
||||
function commit_message_has_url() {
|
||||
commit=$1
|
||||
commit_message=$(git show -s --format='format:%b' $commit)
|
||||
echo "$commit_message" | grep -qe "\($CI_MERGE_REQUEST_PROJECT_URL/\(issues\|merge_requests\)/[0-9]\+\|https://bugzilla.gnome.org/show_bug.cgi?id=[0-9]\+\)"
|
||||
return $?
|
||||
}
|
||||
|
||||
for commit in $commits; do
|
||||
git show -s --format='format:%b' $commit | grep -qe "\($CI_MERGE_REQUEST_PROJECT_URL/\(issues\|merge_requests\)/[0-9]\+\|https://bugzilla.gnome.org/show_bug.cgi?id=[0-9]\+\)" ||
|
||||
{ echo "Missing merge request or issue URL on commit $(echo $commit | cut -c -8)"; exit 1; }
|
||||
if ! commit_message_has_url $commit; then
|
||||
echo "Missing merge request or issue URL on commit $(echo $commit | cut -c -8)"
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
31
.gitlab-ci/checkout-mutter.sh
Executable file
31
.gitlab-ci/checkout-mutter.sh
Executable file
@@ -0,0 +1,31 @@
|
||||
#!/usr/bin/bash
|
||||
|
||||
shell_branch=$(git describe --contains --all HEAD)
|
||||
mutter_target=
|
||||
|
||||
git clone https://gitlab.gnome.org/GNOME/mutter.git
|
||||
|
||||
if [ $? -ne 0 ]; then
|
||||
echo Checkout failed
|
||||
exit 1
|
||||
fi
|
||||
|
||||
cd mutter
|
||||
|
||||
if [ "$CI_MERGE_REQUEST_TARGET_BRANCH_NAME" ]; then
|
||||
merge_request_remote=${CI_MERGE_REQUEST_SOURCE_PROJECT_URL//gnome-shell/mutter}
|
||||
merge_request_branch=$CI_MERGE_REQUEST_SOURCE_BRANCH_NAME
|
||||
|
||||
echo Looking for $merge_request_branch on remote ...
|
||||
if git fetch $merge_request_remote $merge_request_branch >/dev/null 2>&1; then
|
||||
mutter_target=FETCH_HEAD
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -z "$mutter_target" ]; then
|
||||
mutter_target=$(git branch -r -l $shell_branch)
|
||||
mutter_target=${mutter_target:-origin/master}
|
||||
echo Using $mutter_target instead
|
||||
fi
|
||||
|
||||
git checkout $mutter_target
|
||||
41
NEWS
41
NEWS
@@ -1,3 +1,44 @@
|
||||
3.32.0
|
||||
======
|
||||
* Fix sizing issues in on-screen-keyboard emoji panel [Carlos; !439]
|
||||
* Fix test linker failure on Debian/Ubuntu [Iain; !442]
|
||||
* Avoid assertion when sizing fallback app icons from CSS [Florian; #1027]
|
||||
* Fix mis-sized menu arrows after texture cache changes [Florian; !452]
|
||||
|
||||
Contributors:
|
||||
Carlos Garnacho, Iain Lane, Florian Müllner
|
||||
|
||||
Translators:
|
||||
Gábor Kelemen [hu], Victor Ibragimov [tg], Ryuta Fujii [ja], Piotr Drąg [af,
|
||||
tg], Mart Raudsepp [et]
|
||||
|
||||
3.31.92
|
||||
=======
|
||||
* Fix visual glitch in submenus [Alex; #987]
|
||||
* Support fractional scaling [Jonas, Marco; #765011, !5]
|
||||
* Only consider visible children for :first-child/:last-child [Florian; !312]
|
||||
* Hide trailing separator in search results [verdre; !311]
|
||||
* Remember choice in inhibit-shortcuts dialogue [Olivier; !382]
|
||||
* Don't toggle on-screen keyboard on every focus change [Carlos; !397]
|
||||
* Fix legacy tray icons not responding to events on wayland [Florian; #191]
|
||||
* Fix generating French OSK layout [Florian; #997]
|
||||
* Use borderless round user images [Florian; #811]
|
||||
* Misc. bug fixes and cleanups [Andrea, Robert, Florian, Marco, Niels,
|
||||
Benjamin; !414, !417, !420, #996, !408, !422, !425, #1006, !427, !315,
|
||||
#989, !430, !431, !432, #1015, !429, !423, !419, !434]
|
||||
|
||||
Contributors:
|
||||
Jonas Ådahl, Alan, Andrea Azzarone, Benjamin Berg, Olivier Fourdan,
|
||||
Carlos Garnacho, Niels De Graef, Robert Mader, Alex Monday, Florian Müllner,
|
||||
Marco Trevisan (Treviño), verdre
|
||||
|
||||
Translators:
|
||||
Carmen Bianca BAKKER [eo], Asier Sarasua Garmendia [eu], Stas Solovey [ru],
|
||||
Changwoo Ryu [ko], Julien Humbert [fr], Milo Casagrande [it],
|
||||
Марко Костић [sr], Ask Hjorth Larsen [da], Kukuh Syafaat [id],
|
||||
Daniel Șerbănescu [ro], Bernd Homuth [de], Trần Ngọc Quân [vi],
|
||||
Nathan Follens [nl], Rūdolfs Mazurs [lv], Aurimas Černius [lt]
|
||||
|
||||
3.31.91
|
||||
=======
|
||||
* Don't close on-screen-keyboard's language menu on hover [Florian; #171]
|
||||
|
||||
40
README.mdwn
Normal file
40
README.mdwn
Normal file
@@ -0,0 +1,40 @@
|
||||
cldr2json
|
||||
=========
|
||||
|
||||
This script converts Unicode CLDR android keyboard layouts to JSON usable by
|
||||
GNOME Shell.
|
||||
|
||||
CLDR keyboard layouts can be found at
|
||||
<http://www.unicode.org/Public/cldr/latest/keyboards.zip>
|
||||
|
||||
|
||||
Usage
|
||||
=====
|
||||
|
||||
./cldr2json <input file or directory> <output directory>
|
||||
|
||||
example:
|
||||
|
||||
./cldr2json cldr/keyboards/android/ json_layouts/
|
||||
|
||||
|
||||
Keyboard layout mapping
|
||||
=======================
|
||||
|
||||
Unicode CLDR layout identifiers are language codes, while XKB layout
|
||||
identifiers are... something else. The mapping between the two currently uses
|
||||
heuristic based on the layout descriptions, in this order:
|
||||
|
||||
- if the CLDR layout description matches an XKB layout description, chose its
|
||||
XKB identifier
|
||||
- if one word of the CLDR layout description matches an XKB layout
|
||||
description, chose its XKB identifier
|
||||
- if the CLDR layout description matches one word of an XKB layout description,
|
||||
chose its XKB identifier
|
||||
|
||||
That doesn't always work. For instance it fails for "en" language, that should
|
||||
match "us" XKB identifier. For such cases, there is a mapping in
|
||||
LOCALE_TO_XKB_OVERRIDES at the top of the script. If you discover a weird
|
||||
mapping of if you get a "failed to find XKB mapping for <locale>" warning then
|
||||
please consider adding an override there.
|
||||
|
||||
208
cldr2json.py
Executable file
208
cldr2json.py
Executable file
@@ -0,0 +1,208 @@
|
||||
#!/usr/bin/python3
|
||||
#
|
||||
# Copyright 2015 Daiki Ueno <dueno@src.gnome.org>
|
||||
# 2016 Parag Nemade <pnemade@redhat.com>
|
||||
# 2017 Alan <alan@boum.org>
|
||||
#
|
||||
# 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 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
|
||||
# Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public
|
||||
# License along with this program; if not, see
|
||||
# <http://www.gnu.org/licenses/>.
|
||||
|
||||
import glob
|
||||
import json
|
||||
import locale
|
||||
import logging
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
import xml.etree.ElementTree
|
||||
|
||||
import gi
|
||||
gi.require_version('GnomeDesktop', '3.0') # NOQA: E402
|
||||
from gi.repository import GnomeDesktop
|
||||
|
||||
ESCAPE_PATTERN = re.compile(r'\\u\{([0-9A-Fa-f]+?)\}')
|
||||
ISO_PATTERN = re.compile(r'[A-E]([0-9]+)')
|
||||
|
||||
LOCALE_TO_XKB_OVERRIDES = {
|
||||
'af': 'za',
|
||||
'en': 'us',
|
||||
'en-GB': 'uk',
|
||||
'es-US': 'latam',
|
||||
'fr-CA': 'ca',
|
||||
'hi': 'in+bolnagri',
|
||||
'ky': 'kg',
|
||||
'nl-BE': 'be',
|
||||
'zu': None
|
||||
}
|
||||
|
||||
|
||||
def parse_single_key(value):
|
||||
def unescape(m):
|
||||
return chr(int(m.group(1), 16))
|
||||
value = ESCAPE_PATTERN.sub(unescape, value)
|
||||
return value
|
||||
|
||||
|
||||
def parse_rows(keymap):
|
||||
unsorted_rows = {}
|
||||
for _map in keymap.iter('map'):
|
||||
value = _map.get('to')
|
||||
key = [parse_single_key(value)]
|
||||
iso = _map.get('iso')
|
||||
if not ISO_PATTERN.match(iso):
|
||||
sys.stderr.write('invalid ISO key name: %s\n' % iso)
|
||||
continue
|
||||
if not iso[0] in unsorted_rows:
|
||||
unsorted_rows[iso[0]] = []
|
||||
unsorted_rows[iso[0]].append((int(iso[1:]), key))
|
||||
# add subkeys
|
||||
longPress = _map.get('longPress')
|
||||
if longPress:
|
||||
for value in longPress.split(' '):
|
||||
subkey = parse_single_key(value)
|
||||
key.append(subkey)
|
||||
|
||||
rows = []
|
||||
for k, v in sorted(list(unsorted_rows.items()),
|
||||
key=lambda x: x[0],
|
||||
reverse=True):
|
||||
row = []
|
||||
for key in sorted(v, key=lambda x: x):
|
||||
row.append(key[1])
|
||||
rows.append(row)
|
||||
|
||||
return rows
|
||||
|
||||
|
||||
def convert_xml(tree):
|
||||
root = {}
|
||||
for xml_keyboard in tree.iter("keyboard"):
|
||||
locale_full = xml_keyboard.get("locale")
|
||||
locale, sep, end = locale_full.partition("-t-")
|
||||
root["locale"] = locale
|
||||
for xml_name in tree.iter("name"):
|
||||
name = xml_name.get("value")
|
||||
root["name"] = name
|
||||
root["levels"] = []
|
||||
# parse levels
|
||||
for index, keymap in enumerate(tree.iter('keyMap')):
|
||||
# FIXME: heuristics here
|
||||
modifiers = keymap.get('modifiers')
|
||||
if not modifiers:
|
||||
mode = 'default'
|
||||
modifiers = ''
|
||||
elif 'shift' in modifiers.split(' '):
|
||||
mode = 'latched'
|
||||
modifiers = 'shift'
|
||||
else:
|
||||
mode = 'locked'
|
||||
level = {}
|
||||
level["level"] = modifiers
|
||||
level["mode"] = mode
|
||||
level["rows"] = parse_rows(keymap)
|
||||
root["levels"].append(level)
|
||||
return root
|
||||
|
||||
|
||||
def locale_to_xkb(locale, name):
|
||||
if locale in sorted(LOCALE_TO_XKB_OVERRIDES.keys()):
|
||||
xkb = LOCALE_TO_XKB_OVERRIDES[locale]
|
||||
logging.debug("override for %s → %s",
|
||||
locale, xkb)
|
||||
if xkb:
|
||||
return xkb
|
||||
else:
|
||||
raise KeyError("layout %s explicitely disabled in overrides"
|
||||
% locale)
|
||||
xkb_names = sorted(name_to_xkb.keys())
|
||||
if name in xkb_names:
|
||||
return name_to_xkb[name]
|
||||
else:
|
||||
logging.debug("name %s failed" % name)
|
||||
for sub_name in name.split(' '):
|
||||
if sub_name in xkb_names:
|
||||
xkb = name_to_xkb[sub_name]
|
||||
logging.debug("dumb mapping failed but match with locale word: "
|
||||
"%s (%s) → %s (%s)",
|
||||
locale, name, xkb, sub_name)
|
||||
return xkb
|
||||
else:
|
||||
logging.debug("sub_name failed")
|
||||
for xkb_name in xkb_names:
|
||||
for xkb_sub_name in xkb_name.split(' '):
|
||||
if xkb_sub_name.strip('()') == name:
|
||||
xkb = name_to_xkb[xkb_name]
|
||||
logging.debug("dumb mapping failed but match with xkb word: "
|
||||
"%s (%s) → %s (%s)",
|
||||
locale, name, xkb, xkb_name)
|
||||
return xkb
|
||||
raise KeyError("failed to find XKB mapping for %s" % locale)
|
||||
|
||||
|
||||
def convert_file(source_file, destination_path):
|
||||
logging.info("Parsing %s", source_file)
|
||||
|
||||
itree = xml.etree.ElementTree.ElementTree()
|
||||
itree.parse(source_file)
|
||||
|
||||
root = convert_xml(itree)
|
||||
|
||||
try:
|
||||
xkb_name = locale_to_xkb(root["locale"], root["name"])
|
||||
except KeyError as e:
|
||||
logging.warn(e)
|
||||
return False
|
||||
destination_file = os.path.join(destination_path, xkb_name + ".json")
|
||||
|
||||
with open(destination_file, 'w', encoding="utf-8") as dest_fd:
|
||||
json.dump(root, dest_fd, ensure_ascii=False, indent=2, sort_keys=True)
|
||||
|
||||
logging.debug("written %s", destination_file)
|
||||
|
||||
|
||||
def load_xkb_mappings():
|
||||
xkb = GnomeDesktop.XkbInfo()
|
||||
layouts = xkb.get_all_layouts()
|
||||
name_to_xkb = {}
|
||||
|
||||
for layout in layouts:
|
||||
name = xkb.get_layout_info(layout).display_name
|
||||
name_to_xkb[name] = layout
|
||||
|
||||
return name_to_xkb
|
||||
|
||||
|
||||
locale.setlocale(locale.LC_ALL, "C")
|
||||
name_to_xkb = load_xkb_mappings()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
if "DEBUG" in os.environ:
|
||||
logging.basicConfig(level=logging.DEBUG)
|
||||
|
||||
if len(sys.argv) < 2:
|
||||
print("supply a CLDR keyboard file")
|
||||
sys.exit(1)
|
||||
|
||||
if len(sys.argv) < 3:
|
||||
print("supply an output directory")
|
||||
sys.exit(1)
|
||||
|
||||
source = sys.argv[1]
|
||||
destination = sys.argv[2]
|
||||
if os.path.isfile(source):
|
||||
convert_file(source, destination)
|
||||
elif os.path.isdir(source):
|
||||
for path in glob.glob(source + "/*-t-k0-android.xml"):
|
||||
convert_file(path, destination)
|
||||
@@ -34,6 +34,10 @@
|
||||
<arg type="u" direction="in" name="action"/>
|
||||
<arg type="b" direction="out" name="success"/>
|
||||
</method>
|
||||
<method name="UngrabAccelerators">
|
||||
<arg type="au" direction="in" name="action"/>
|
||||
<arg type="b" direction="out" name="success"/>
|
||||
</method>
|
||||
<signal name="AcceleratorActivated">
|
||||
<arg name="action" type="u"/>
|
||||
<arg name="parameters" type="a{sv}"/>
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
<file>be.json</file>
|
||||
<file>bg.json</file>
|
||||
<file>by.json</file>
|
||||
<file>ca.json</file>
|
||||
<file>cz.json</file>
|
||||
<file>de.json</file>
|
||||
<file>dk.json</file>
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<gresources>
|
||||
<gresource prefix="/org/gnome/shell/theme">
|
||||
<file>automatic-updates-off-symbolic.svg</file>
|
||||
<file>automatic-updates-on-symbolic.svg</file>
|
||||
<file>automatic-updates-scheduled-symbolic.svg</file>
|
||||
<file>calendar-today.svg</file>
|
||||
<file>checkbox-focused.svg</file>
|
||||
<file>checkbox-off-focused.svg</file>
|
||||
|
||||
599
data/osk-layouts/ca.json
Normal file
599
data/osk-layouts/ca.json
Normal file
@@ -0,0 +1,599 @@
|
||||
{
|
||||
"levels": [
|
||||
{
|
||||
"level": "",
|
||||
"mode": "default",
|
||||
"rows": [
|
||||
[
|
||||
[
|
||||
"q"
|
||||
],
|
||||
[
|
||||
"w"
|
||||
],
|
||||
[
|
||||
"e",
|
||||
"é",
|
||||
"è",
|
||||
"ê",
|
||||
"ë",
|
||||
"%",
|
||||
"ę",
|
||||
"ė",
|
||||
"ē"
|
||||
],
|
||||
[
|
||||
"r"
|
||||
],
|
||||
[
|
||||
"t"
|
||||
],
|
||||
[
|
||||
"y",
|
||||
"%",
|
||||
"ÿ"
|
||||
],
|
||||
[
|
||||
"u",
|
||||
"ù",
|
||||
"û",
|
||||
"%",
|
||||
"ü",
|
||||
"ú",
|
||||
"ū"
|
||||
],
|
||||
[
|
||||
"i",
|
||||
"î",
|
||||
"%",
|
||||
"ï",
|
||||
"ì",
|
||||
"í",
|
||||
"į",
|
||||
"ī"
|
||||
],
|
||||
[
|
||||
"o",
|
||||
"ô",
|
||||
"œ",
|
||||
"%",
|
||||
"ö",
|
||||
"ò",
|
||||
"ó",
|
||||
"õ",
|
||||
"ø",
|
||||
"ō",
|
||||
"º"
|
||||
],
|
||||
[
|
||||
"p"
|
||||
]
|
||||
],
|
||||
[
|
||||
[
|
||||
"a",
|
||||
"à",
|
||||
"â",
|
||||
"%",
|
||||
"æ",
|
||||
"á",
|
||||
"ä",
|
||||
"ã",
|
||||
"å",
|
||||
"ā",
|
||||
"ª"
|
||||
],
|
||||
[
|
||||
"s"
|
||||
],
|
||||
[
|
||||
"d"
|
||||
],
|
||||
[
|
||||
"f"
|
||||
],
|
||||
[
|
||||
"g"
|
||||
],
|
||||
[
|
||||
"h"
|
||||
],
|
||||
[
|
||||
"j"
|
||||
],
|
||||
[
|
||||
"k"
|
||||
],
|
||||
[
|
||||
"l"
|
||||
]
|
||||
],
|
||||
[
|
||||
[
|
||||
"z"
|
||||
],
|
||||
[
|
||||
"x"
|
||||
],
|
||||
[
|
||||
"c",
|
||||
"ç",
|
||||
"ć",
|
||||
"č"
|
||||
],
|
||||
[
|
||||
"v"
|
||||
],
|
||||
[
|
||||
"b"
|
||||
],
|
||||
[
|
||||
"n"
|
||||
],
|
||||
[
|
||||
"m"
|
||||
]
|
||||
],
|
||||
[
|
||||
[
|
||||
","
|
||||
],
|
||||
[
|
||||
" "
|
||||
],
|
||||
[
|
||||
".",
|
||||
"#",
|
||||
"!",
|
||||
",",
|
||||
"?",
|
||||
"-",
|
||||
":",
|
||||
"'",
|
||||
"@"
|
||||
]
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"level": "shift",
|
||||
"mode": "latched",
|
||||
"rows": [
|
||||
[
|
||||
[
|
||||
"Q"
|
||||
],
|
||||
[
|
||||
"W"
|
||||
],
|
||||
[
|
||||
"E",
|
||||
"É",
|
||||
"È",
|
||||
"Ê",
|
||||
"Ë",
|
||||
"%",
|
||||
"Ę",
|
||||
"Ė",
|
||||
"Ē"
|
||||
],
|
||||
[
|
||||
"R"
|
||||
],
|
||||
[
|
||||
"T"
|
||||
],
|
||||
[
|
||||
"Y",
|
||||
"%",
|
||||
"Ÿ"
|
||||
],
|
||||
[
|
||||
"U",
|
||||
"Ù",
|
||||
"Û",
|
||||
"%",
|
||||
"Ü",
|
||||
"Ú",
|
||||
"Ū"
|
||||
],
|
||||
[
|
||||
"I",
|
||||
"Î",
|
||||
"%",
|
||||
"Ï",
|
||||
"Ì",
|
||||
"Í",
|
||||
"Į",
|
||||
"Ī"
|
||||
],
|
||||
[
|
||||
"O",
|
||||
"Ô",
|
||||
"Œ",
|
||||
"%",
|
||||
"Ö",
|
||||
"Ò",
|
||||
"Ó",
|
||||
"Õ",
|
||||
"Ø",
|
||||
"Ō",
|
||||
"º"
|
||||
],
|
||||
[
|
||||
"P"
|
||||
]
|
||||
],
|
||||
[
|
||||
[
|
||||
"A",
|
||||
"À",
|
||||
"Â",
|
||||
"%",
|
||||
"Æ",
|
||||
"Á",
|
||||
"Ä",
|
||||
"Ã",
|
||||
"Å",
|
||||
"Ā",
|
||||
"ª"
|
||||
],
|
||||
[
|
||||
"S"
|
||||
],
|
||||
[
|
||||
"D"
|
||||
],
|
||||
[
|
||||
"F"
|
||||
],
|
||||
[
|
||||
"G"
|
||||
],
|
||||
[
|
||||
"H"
|
||||
],
|
||||
[
|
||||
"J"
|
||||
],
|
||||
[
|
||||
"K"
|
||||
],
|
||||
[
|
||||
"L"
|
||||
]
|
||||
],
|
||||
[
|
||||
[
|
||||
"Z"
|
||||
],
|
||||
[
|
||||
"X"
|
||||
],
|
||||
[
|
||||
"C",
|
||||
"Ç",
|
||||
"Ć",
|
||||
"Č"
|
||||
],
|
||||
[
|
||||
"V"
|
||||
],
|
||||
[
|
||||
"B"
|
||||
],
|
||||
[
|
||||
"N"
|
||||
],
|
||||
[
|
||||
"M"
|
||||
]
|
||||
],
|
||||
[
|
||||
[
|
||||
","
|
||||
],
|
||||
[
|
||||
" "
|
||||
],
|
||||
[
|
||||
".",
|
||||
"#",
|
||||
"!",
|
||||
",",
|
||||
"?",
|
||||
"-",
|
||||
":",
|
||||
"'",
|
||||
"@"
|
||||
]
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"level": "opt",
|
||||
"mode": "locked",
|
||||
"rows": [
|
||||
[
|
||||
[
|
||||
"1",
|
||||
"¹",
|
||||
"½",
|
||||
"⅓",
|
||||
"¼",
|
||||
"⅛"
|
||||
],
|
||||
[
|
||||
"2",
|
||||
"²",
|
||||
"⅔"
|
||||
],
|
||||
[
|
||||
"3",
|
||||
"³",
|
||||
"¾",
|
||||
"⅜"
|
||||
],
|
||||
[
|
||||
"4",
|
||||
"⁴"
|
||||
],
|
||||
[
|
||||
"5",
|
||||
"⅝"
|
||||
],
|
||||
[
|
||||
"6"
|
||||
],
|
||||
[
|
||||
"7",
|
||||
"⅞"
|
||||
],
|
||||
[
|
||||
"8"
|
||||
],
|
||||
[
|
||||
"9"
|
||||
],
|
||||
[
|
||||
"0",
|
||||
"ⁿ",
|
||||
"∅"
|
||||
]
|
||||
],
|
||||
[
|
||||
[
|
||||
"@"
|
||||
],
|
||||
[
|
||||
"#"
|
||||
],
|
||||
[
|
||||
"$",
|
||||
"¢",
|
||||
"£",
|
||||
"€",
|
||||
"¥",
|
||||
"₱"
|
||||
],
|
||||
[
|
||||
"%",
|
||||
"‰"
|
||||
],
|
||||
[
|
||||
"&"
|
||||
],
|
||||
[
|
||||
"-",
|
||||
"_",
|
||||
"–",
|
||||
"—",
|
||||
"·"
|
||||
],
|
||||
[
|
||||
"+",
|
||||
"±"
|
||||
],
|
||||
[
|
||||
"(",
|
||||
"<",
|
||||
"{",
|
||||
"["
|
||||
],
|
||||
[
|
||||
")",
|
||||
">",
|
||||
"}",
|
||||
"]"
|
||||
]
|
||||
],
|
||||
[
|
||||
[
|
||||
"*",
|
||||
"†",
|
||||
"‡",
|
||||
"★"
|
||||
],
|
||||
[
|
||||
"\"",
|
||||
"“",
|
||||
"”",
|
||||
"«",
|
||||
"»"
|
||||
],
|
||||
[
|
||||
"'",
|
||||
"‘",
|
||||
"’",
|
||||
"‹",
|
||||
"›"
|
||||
],
|
||||
[
|
||||
":"
|
||||
],
|
||||
[
|
||||
";"
|
||||
],
|
||||
[
|
||||
"!",
|
||||
"¡"
|
||||
],
|
||||
[
|
||||
"?",
|
||||
"¿"
|
||||
]
|
||||
],
|
||||
[
|
||||
[
|
||||
"_"
|
||||
],
|
||||
[
|
||||
"/"
|
||||
],
|
||||
[
|
||||
" "
|
||||
],
|
||||
[
|
||||
","
|
||||
],
|
||||
[
|
||||
".",
|
||||
"…"
|
||||
]
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"level": "opt+shift",
|
||||
"mode": "locked",
|
||||
"rows": [
|
||||
[
|
||||
[
|
||||
"~"
|
||||
],
|
||||
[
|
||||
"`"
|
||||
],
|
||||
[
|
||||
"|"
|
||||
],
|
||||
[
|
||||
"•",
|
||||
"♪",
|
||||
"♥",
|
||||
"♠",
|
||||
"♦",
|
||||
"♣"
|
||||
],
|
||||
[
|
||||
"√"
|
||||
],
|
||||
[
|
||||
"Π",
|
||||
"π"
|
||||
],
|
||||
[
|
||||
"÷"
|
||||
],
|
||||
[
|
||||
"×"
|
||||
],
|
||||
[
|
||||
"¶",
|
||||
"§"
|
||||
],
|
||||
[
|
||||
"∆"
|
||||
]
|
||||
],
|
||||
[
|
||||
[
|
||||
"£"
|
||||
],
|
||||
[
|
||||
"¢"
|
||||
],
|
||||
[
|
||||
"€"
|
||||
],
|
||||
[
|
||||
"¥"
|
||||
],
|
||||
[
|
||||
"^",
|
||||
"↑",
|
||||
"↓",
|
||||
"←",
|
||||
"→"
|
||||
],
|
||||
[
|
||||
"°",
|
||||
"′",
|
||||
"″"
|
||||
],
|
||||
[
|
||||
"=",
|
||||
"≠",
|
||||
"≈",
|
||||
"∞"
|
||||
],
|
||||
[
|
||||
"{"
|
||||
],
|
||||
[
|
||||
"}"
|
||||
]
|
||||
],
|
||||
[
|
||||
[
|
||||
"\\"
|
||||
],
|
||||
[
|
||||
"©"
|
||||
],
|
||||
[
|
||||
"®"
|
||||
],
|
||||
[
|
||||
"™"
|
||||
],
|
||||
[
|
||||
"℅"
|
||||
],
|
||||
[
|
||||
"["
|
||||
],
|
||||
[
|
||||
"]"
|
||||
]
|
||||
],
|
||||
[
|
||||
[
|
||||
"<",
|
||||
"‹",
|
||||
"≤",
|
||||
"«"
|
||||
],
|
||||
[
|
||||
">",
|
||||
"›",
|
||||
"≥",
|
||||
"»"
|
||||
],
|
||||
[
|
||||
" "
|
||||
],
|
||||
[
|
||||
","
|
||||
],
|
||||
[
|
||||
".",
|
||||
"…"
|
||||
]
|
||||
]
|
||||
]
|
||||
}
|
||||
],
|
||||
"locale": "fr-CA",
|
||||
"name": "French Canada"
|
||||
}
|
||||
@@ -6,10 +6,20 @@
|
||||
"rows": [
|
||||
[
|
||||
[
|
||||
"q"
|
||||
"a",
|
||||
"à",
|
||||
"â",
|
||||
"%",
|
||||
"æ",
|
||||
"á",
|
||||
"ä",
|
||||
"ã",
|
||||
"å",
|
||||
"ā",
|
||||
"ª"
|
||||
],
|
||||
[
|
||||
"w"
|
||||
"z"
|
||||
],
|
||||
[
|
||||
"e",
|
||||
@@ -71,17 +81,7 @@
|
||||
],
|
||||
[
|
||||
[
|
||||
"a",
|
||||
"à",
|
||||
"â",
|
||||
"%",
|
||||
"æ",
|
||||
"á",
|
||||
"ä",
|
||||
"ã",
|
||||
"å",
|
||||
"ā",
|
||||
"ª"
|
||||
"q"
|
||||
],
|
||||
[
|
||||
"s"
|
||||
@@ -106,11 +106,14 @@
|
||||
],
|
||||
[
|
||||
"l"
|
||||
],
|
||||
[
|
||||
"m"
|
||||
]
|
||||
],
|
||||
[
|
||||
[
|
||||
"z"
|
||||
"w"
|
||||
],
|
||||
[
|
||||
"x"
|
||||
@@ -131,7 +134,11 @@
|
||||
"n"
|
||||
],
|
||||
[
|
||||
"m"
|
||||
"'",
|
||||
"‘",
|
||||
"’",
|
||||
"‹",
|
||||
"›"
|
||||
]
|
||||
],
|
||||
[
|
||||
@@ -161,10 +168,20 @@
|
||||
"rows": [
|
||||
[
|
||||
[
|
||||
"Q"
|
||||
"A",
|
||||
"À",
|
||||
"Â",
|
||||
"%",
|
||||
"Æ",
|
||||
"Á",
|
||||
"Ä",
|
||||
"Ã",
|
||||
"Å",
|
||||
"Ā",
|
||||
"ª"
|
||||
],
|
||||
[
|
||||
"W"
|
||||
"Z"
|
||||
],
|
||||
[
|
||||
"E",
|
||||
@@ -226,17 +243,7 @@
|
||||
],
|
||||
[
|
||||
[
|
||||
"A",
|
||||
"À",
|
||||
"Â",
|
||||
"%",
|
||||
"Æ",
|
||||
"Á",
|
||||
"Ä",
|
||||
"Ã",
|
||||
"Å",
|
||||
"Ā",
|
||||
"ª"
|
||||
"Q"
|
||||
],
|
||||
[
|
||||
"S"
|
||||
@@ -261,11 +268,14 @@
|
||||
],
|
||||
[
|
||||
"L"
|
||||
],
|
||||
[
|
||||
"M"
|
||||
]
|
||||
],
|
||||
[
|
||||
[
|
||||
"Z"
|
||||
"W"
|
||||
],
|
||||
[
|
||||
"X"
|
||||
@@ -286,7 +296,11 @@
|
||||
"N"
|
||||
],
|
||||
[
|
||||
"M"
|
||||
"'",
|
||||
"‘",
|
||||
"’",
|
||||
"‹",
|
||||
"›"
|
||||
]
|
||||
],
|
||||
[
|
||||
@@ -369,10 +383,10 @@
|
||||
"#"
|
||||
],
|
||||
[
|
||||
"$",
|
||||
"€",
|
||||
"¢",
|
||||
"£",
|
||||
"€",
|
||||
"$",
|
||||
"¥",
|
||||
"₱"
|
||||
],
|
||||
@@ -511,13 +525,14 @@
|
||||
"£"
|
||||
],
|
||||
[
|
||||
"¥"
|
||||
],
|
||||
[
|
||||
"$",
|
||||
"¢"
|
||||
],
|
||||
[
|
||||
"€"
|
||||
],
|
||||
[
|
||||
"¥"
|
||||
"¢"
|
||||
],
|
||||
[
|
||||
"^",
|
||||
@@ -594,6 +609,6 @@
|
||||
]
|
||||
}
|
||||
],
|
||||
"locale": "fr-CA",
|
||||
"name": "French Canada"
|
||||
"locale": "fr",
|
||||
"name": "French"
|
||||
}
|
||||
1
data/theme/automatic-updates-off-symbolic.svg
Normal file
1
data/theme/automatic-updates-off-symbolic.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><title>EOS_symbolic-icons_v0.1auto-updates_OFF</title><path d="M11.03,10.074a.125.125,0,0,0-.086.213l1.347,1.35a5.733,5.733,0,0,1-4.238,1.9,5.6,5.6,0,0,1-2.282-.484l-1.11,1.11a7.024,7.024,0,0,0,3.392.875,7.3,7.3,0,0,0,5.3-2.339l1.357,1.36a.125.125,0,0,0,.213-.086L15,10Z" style="fill:#999"/><path d="M12.921,5.9a6.354,6.354,0,0,1,.326,1.863.248.248,0,0,0,.244.244h1a.261.261,0,0,0,.257-.265,7.543,7.543,0,0,0-.677-2.991Z" style="fill:#999"/><path d="M6.286,9.707a.994.994,0,0,0,.715.3H9a1,1,0,0,0,1-1v-2A.994.994,0,0,0,9.7,6.3l2.175-2.175,0,0L12.93,3.067l0,0,1.4-1.4a.25.25,0,0,0,0-.354L13.617.608a.25.25,0,0,0-.354,0L11.772,2.1A6.97,6.97,0,0,0,7.948.961,7.3,7.3,0,0,0,2.651,3.3L1.293,1.94a.125.125,0,0,0-.214.086L1,6l3.971-.074a.125.125,0,0,0,.086-.213L3.71,4.363a5.733,5.733,0,0,1,4.238-1.9,5.523,5.523,0,0,1,2.723.739L7.86,6.011H7a1,1,0,0,0-1,1V7.87L3.291,10.58a6,6,0,0,1-.537-2.346.248.248,0,0,0-.244-.245h-1a.261.261,0,0,0-.257.265A7.329,7.329,0,0,0,2.172,11.7L.608,13.263a.25.25,0,0,0,0,.354l.707.707a.25.25,0,0,0,.354,0l1.4-1.4,0,0,1.056-1.056,0,0Z" style="fill:#999"/></svg>
|
||||
|
After Width: | Height: | Size: 1.1 KiB |
1
data/theme/automatic-updates-on-symbolic.svg
Normal file
1
data/theme/automatic-updates-on-symbolic.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><title>EOS_symbolic-icons_v0.1auto-updates_ON</title><rect x="6.001" y="6.011" width="4" height="4" rx="1" ry="1" style="fill:#999"/><path d="M5.057,5.713,3.71,4.362a5.733,5.733,0,0,1,4.238-1.9,5.173,5.173,0,0,1,5.3,5.305.248.248,0,0,0,.244.244h1a.261.261,0,0,0,.257-.265A6.684,6.684,0,0,0,7.948.961,7.3,7.3,0,0,0,2.65,3.3L1.293,1.94a.125.125,0,0,0-.213.086L1,6l3.971-.074A.125.125,0,0,0,5.057,5.713Z" style="fill:#999"/><path d="M11.03,10.074a.125.125,0,0,0-.086.213l1.347,1.35a5.733,5.733,0,0,1-4.238,1.9,5.173,5.173,0,0,1-5.3-5.305.248.248,0,0,0-.244-.245h-1a.261.261,0,0,0-.257.265,6.684,6.684,0,0,0,6.8,6.785,7.3,7.3,0,0,0,5.3-2.339l1.357,1.36a.125.125,0,0,0,.214-.086L15,10Z" style="fill:#999"/></svg>
|
||||
|
After Width: | Height: | Size: 767 B |
1
data/theme/automatic-updates-scheduled-symbolic.svg
Normal file
1
data/theme/automatic-updates-scheduled-symbolic.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><title>EOS_symbolic-icons_v0.1update-scheduled_OUTLINE</title><path d="M7.99,15.054A6.7,6.7,0,0,1,1.06,8,6.7,6.7,0,0,1,7.99.954,6.71,6.71,0,0,1,14.948,8,6.71,6.71,0,0,1,7.99,15.054Zm0-12.6A5.2,5.2,0,0,0,2.56,8a5.2,5.2,0,0,0,5.43,5.55A5.215,5.215,0,0,0,13.448,8,5.216,5.216,0,0,0,7.99,2.454Z" style="fill:#999"/><path d="M9.209,10.443,7.2,8.437a.25.25,0,0,1-.073-.177l0-4.01A.25.25,0,0,1,7.379,4h1.25a.25.25,0,0,1,.25.25l0,3.283a.25.25,0,0,0,.073.177l1.5,1.494a.25.25,0,0,1,0,.354l-.883.884A.25.25,0,0,1,9.209,10.443Z" style="fill:#999"/></svg>
|
||||
|
After Width: | Height: | Size: 603 B |
@@ -16,7 +16,7 @@ $link_visited_color: if($variant == 'light', darken($selected_bg_color, 20%), li
|
||||
$top_hilight: $borders_edge;
|
||||
|
||||
$warning_color: #f57900;
|
||||
$error_color: #cc0000;
|
||||
$error_color: #ff8080;
|
||||
$success_color: if($variant == 'light', #33d17a, darken(#33d17a, 10%));
|
||||
$destructive_color: if($variant == 'light', #e01b24, darken(#e01b24, 10%));
|
||||
|
||||
|
||||
@@ -267,8 +267,7 @@ StScrollBar {
|
||||
}
|
||||
|
||||
.end-session-dialog-logout-icon {
|
||||
//border: 2px solid #8b8b8b;
|
||||
border-radius: 5px;
|
||||
border-radius: 99px;
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
background-size: contain;
|
||||
@@ -393,7 +392,7 @@ StScrollBar {
|
||||
|
||||
.prompt-dialog-error-label {
|
||||
font-size: 10pt;
|
||||
color: $error_color;
|
||||
color: $warning_color;
|
||||
padding-bottom: 8px;
|
||||
}
|
||||
|
||||
@@ -428,7 +427,7 @@ StScrollBar {
|
||||
}
|
||||
|
||||
.polkit-dialog-user-icon {
|
||||
border-radius: 5px;
|
||||
border-radius: 99px;
|
||||
background-size: contain;
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
@@ -508,6 +507,7 @@ StScrollBar {
|
||||
|
||||
.popup-menu-arrow { } //defined globally in the TOP BAR
|
||||
.popup-sub-menu {
|
||||
padding-bottom: 1px;
|
||||
background-color: darken($bg_color,2%);
|
||||
box-shadow: inset 0 -1px 0px lighten($borders_color,5%);
|
||||
}
|
||||
@@ -1031,6 +1031,11 @@ StScrollBar {
|
||||
-st-icon-style: symbolic;
|
||||
}
|
||||
|
||||
.message-icon-bin > .fallback-window-icon {
|
||||
width: 1.09em;
|
||||
height: 1.09em;
|
||||
}
|
||||
|
||||
.message-secondary-bin {
|
||||
padding: 0 0.82em;;
|
||||
}
|
||||
@@ -1138,7 +1143,7 @@ StScrollBar {
|
||||
.ripple-box:rtl { border-radius: 0 0 0 52px; } // just a simple change to the border radius position
|
||||
|
||||
// not really top bar only
|
||||
.popup-menu-arrow { width: 16px; height: 16px; }
|
||||
.popup-menu-arrow { icon-size: 1.09em; }
|
||||
.popup-menu-icon { icon-size: 1.09em; }
|
||||
|
||||
//close buttons
|
||||
@@ -1284,6 +1289,8 @@ StScrollBar {
|
||||
|
||||
.search-section-separator { height: 2px; background-color: rgba(255, 255, 255, 0.2); }
|
||||
|
||||
.search-section:last-child .search-section-separator { background-color: transparent; }
|
||||
|
||||
.list-search-result-content { spacing: 30px; }
|
||||
.list-search-result-title { color: darken($osd_fg_color,5%); spacing: 12px; }
|
||||
.list-search-result-description { color: transparentize(darken($osd_fg_color,15%), 0.5); }
|
||||
@@ -1446,13 +1453,13 @@ StScrollBar {
|
||||
height: 12px;
|
||||
background-color: transparent;
|
||||
border: 2px solid rgba(255, 255, 255, 0.4);
|
||||
border-radius:12px;
|
||||
border-radius: 12px;
|
||||
}
|
||||
|
||||
&:hover .page-indicator-icon { border-color: white; }
|
||||
&:active .page-indicator-icon { border: none; margin: 2px; background-color:#fff; }
|
||||
&:active .page-indicator-icon { border: none; margin: 2px; background-color: white; }
|
||||
&:checked .page-indicator-icon,
|
||||
&:checked:active { background-color: #fff;}
|
||||
&:checked:active .page-indicator-icon { background-color: white;}
|
||||
}
|
||||
|
||||
.no-frequent-applications-label { @extend %status_text; }
|
||||
@@ -1754,13 +1761,11 @@ StScrollBar {
|
||||
|
||||
/* Auth Dialogs & Screen Shield */
|
||||
|
||||
.framed-user-icon {
|
||||
.user-icon {
|
||||
background-size: contain;
|
||||
border: 2px solid $osd_fg_color;
|
||||
color: $osd_fg_color;
|
||||
border-radius: 3px;
|
||||
border-radius: 99px;
|
||||
&:hover {
|
||||
border-color: lighten($osd_fg_color,30%);
|
||||
color: lighten($osd_fg_color,30%);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,6 +40,7 @@ do
|
||||
done
|
||||
|
||||
cat >>$TMP_GRESOURCE_FILE <<EOF
|
||||
<file>emoji.json</file>
|
||||
</gresource>
|
||||
</gresources>
|
||||
EOF
|
||||
|
||||
@@ -481,6 +481,9 @@ var LoginDialog = GObject.registerClass({
|
||||
this._logoBin = new St.Widget({ style_class: 'login-dialog-logo-bin',
|
||||
x_align: Clutter.ActorAlign.CENTER,
|
||||
y_align: Clutter.ActorAlign.END });
|
||||
this._logoBin.connect('resource-scale-changed', () => {
|
||||
this._updateLogoTexture(this._textureCache, this._logoFile);
|
||||
});
|
||||
this.add_child(this._logoBin);
|
||||
this._updateLogo();
|
||||
|
||||
@@ -778,11 +781,12 @@ var LoginDialog = GObject.registerClass({
|
||||
return;
|
||||
|
||||
this._logoBin.destroy_all_children();
|
||||
if (this._logoFile) {
|
||||
if (this._logoFile && this._logoBin.resource_scale > 0) {
|
||||
let scaleFactor = St.ThemeContext.get_for_stage(global.stage).scale_factor;
|
||||
this._logoBin.add_child(this._textureCache.load_file_async(this._logoFile,
|
||||
-1, _LOGO_ICON_HEIGHT,
|
||||
scaleFactor));
|
||||
scaleFactor,
|
||||
this._logoBin.resource_scale));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
<file>gdm/realmd.js</file>
|
||||
<file>gdm/util.js</file>
|
||||
|
||||
<file>misc/updateManager.js</file>
|
||||
<file>misc/config.js</file>
|
||||
<file>misc/extensionUtils.js</file>
|
||||
<file>misc/fileUtils.js</file>
|
||||
@@ -116,9 +117,11 @@
|
||||
<file>ui/components/networkAgent.js</file>
|
||||
<file>ui/components/polkitAgent.js</file>
|
||||
<file>ui/components/telepathyClient.js</file>
|
||||
<file>ui/components/updates.js</file>
|
||||
<file>ui/components/keyring.js</file>
|
||||
|
||||
<file>ui/status/accessibility.js</file>
|
||||
<file>ui/status/automaticUpdates.js</file>
|
||||
<file>ui/status/brightness.js</file>
|
||||
<file>ui/status/location.js</file>
|
||||
<file>ui/status/keyboard.js</file>
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
const { Clutter, GObject, IBus } = imports.gi;
|
||||
const { Clutter, GLib, GObject, IBus } = imports.gi;
|
||||
|
||||
const Keyboard = imports.ui.status.keyboard;
|
||||
|
||||
var HIDE_PANEL_TIME = 50;
|
||||
|
||||
var InputMethod = GObject.registerClass(
|
||||
class InputMethod extends Clutter.InputMethod {
|
||||
_init() {
|
||||
@@ -13,6 +15,7 @@ class InputMethod extends Clutter.InputMethod {
|
||||
this._preeditStr = '';
|
||||
this._preeditPos = 0;
|
||||
this._preeditVisible = false;
|
||||
this._hidePanelId = 0;
|
||||
this._ibus = IBus.Bus.new_async();
|
||||
this._ibus.connect('connected', this._onConnected.bind(this));
|
||||
this._ibus.connect('disconnected', this._clear.bind(this));
|
||||
@@ -136,6 +139,11 @@ class InputMethod extends Clutter.InputMethod {
|
||||
this._updateCapabilities();
|
||||
this._emitRequestSurrounding();
|
||||
}
|
||||
|
||||
if (this._hidePanelId) {
|
||||
GLib.source_remove(this._hidePanelId);
|
||||
this._hidePanelId = 0;
|
||||
}
|
||||
}
|
||||
|
||||
vfunc_focus_out() {
|
||||
@@ -150,6 +158,12 @@ class InputMethod extends Clutter.InputMethod {
|
||||
this.set_preedit_text(null, 0);
|
||||
this._preeditStr = null;
|
||||
}
|
||||
|
||||
this._hidePanelId = GLib.timeout_add(GLib.PRIORITY_DEFAULT, HIDE_PANEL_TIME, () => {
|
||||
this.set_input_panel_state(Clutter.InputPanelState.OFF);
|
||||
this._hidePanelId = 0;
|
||||
return GLib.SOURCE_REMOVE;
|
||||
});
|
||||
}
|
||||
|
||||
vfunc_reset() {
|
||||
|
||||
338
js/misc/updateManager.js
Normal file
338
js/misc/updateManager.js
Normal file
@@ -0,0 +1,338 @@
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
//
|
||||
// Copyright (C) 2019 Endless Mobile, Inc.
|
||||
//
|
||||
// This is a GNOME Shell component to wrap the interactions over
|
||||
// D-Bus with the Mogwai system daemon.
|
||||
//
|
||||
// Licensed under the GNU General Public License Version 2
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 2
|
||||
// of the License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
const { Clutter, Gio, GLib,
|
||||
GObject, Gtk, NM, Shell, St } = imports.gi;
|
||||
|
||||
const NM_SETTING_AUTOMATIC_UPDATES_NOTIFICATION_TIME = "connection.automatic-updates-notification-time";
|
||||
const NM_SETTING_ALLOW_DOWNLOADS = 'connection.allow-downloads';
|
||||
const NM_SETTING_TARIFF_ENABLED = "connection.tariff-enabled";
|
||||
|
||||
const SchedulerInterface = '\
|
||||
<node> \
|
||||
<interface name="com.endlessm.DownloadManager1.Scheduler"> \
|
||||
<property name="ActiveEntryCount" type="u" access="read" /> \
|
||||
<property name="EntryCount" type="u" access="read" /> \
|
||||
</interface> \
|
||||
</node>';
|
||||
|
||||
const SchedulerProxy = Gio.DBusProxy.makeProxyWrapper(SchedulerInterface);
|
||||
|
||||
let _updateManager = null;
|
||||
|
||||
function getUpdateManager() {
|
||||
if (_updateManager == null)
|
||||
_updateManager = new UpdateManager();
|
||||
return _updateManager;
|
||||
}
|
||||
|
||||
var State = {
|
||||
UNKNOWN: 0,
|
||||
DISCONNECTED: 1,
|
||||
DISABLED: 2,
|
||||
IDLE: 3,
|
||||
SCHEDULED: 4,
|
||||
DOWNLOADING: 5
|
||||
};
|
||||
|
||||
function stateToIconName(state) {
|
||||
switch (state) {
|
||||
case State.UNKNOWN:
|
||||
case State.DISCONNECTED:
|
||||
return null;
|
||||
|
||||
case State.DISABLED:
|
||||
return 'resource:///org/gnome/shell/theme/automatic-updates-off-symbolic.svg';
|
||||
|
||||
case State.IDLE:
|
||||
case State.DOWNLOADING:
|
||||
return 'resource:///org/gnome/shell/theme/automatic-updates-on-symbolic.svg';
|
||||
|
||||
case State.SCHEDULED:
|
||||
return 'resource:///org/gnome/shell/theme/automatic-updates-scheduled-symbolic.svg';
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
var UpdateManager = GObject.registerClass ({
|
||||
Properties: {
|
||||
'last-notification-time': GObject.ParamSpec.int('last-notification-time',
|
||||
'last-notification-time',
|
||||
'last-notification-time',
|
||||
GObject.ParamFlags.READWRITE,
|
||||
null),
|
||||
'icon': GObject.ParamSpec.object('icon', 'icon', 'icon',
|
||||
GObject.ParamFlags.READABLE,
|
||||
Gio.Icon.$gtype),
|
||||
'state': GObject.ParamSpec.uint('state', 'state', 'state',
|
||||
GObject.ParamFlags.READABLE,
|
||||
null),
|
||||
},
|
||||
}, class UpdateManager extends GObject.Object {
|
||||
_init() {
|
||||
super._init();
|
||||
|
||||
this._activeConnection = null;
|
||||
this._settingChangedSignalId = 0;
|
||||
this._updateTimeoutId = 0;
|
||||
|
||||
this._state = State.UNKNOWN;
|
||||
|
||||
NM.Client.new_async(null, this._clientGot.bind(this));
|
||||
}
|
||||
|
||||
_clientGot(obj, result) {
|
||||
this._client = NM.Client.new_finish(result);
|
||||
|
||||
this._client.connect('notify::primary-connection', this._sync.bind(this));
|
||||
this._client.connect('notify::state', this._sync.bind(this));
|
||||
|
||||
// Start retrieving the Mogwai proxy
|
||||
this._proxy = new SchedulerProxy(Gio.DBus.system,
|
||||
'com.endlessm.MogwaiSchedule1',
|
||||
'/com/endlessm/DownloadManager1',
|
||||
(proxy, error) => {
|
||||
if (error) {
|
||||
log(error.message);
|
||||
return;
|
||||
}
|
||||
this._proxy.connect('g-properties-changed',
|
||||
this._sync.bind(this));
|
||||
this._updateStatus();
|
||||
});
|
||||
|
||||
this._sync();
|
||||
}
|
||||
|
||||
_sync() {
|
||||
if (!this._client || !this._proxy)
|
||||
return;
|
||||
|
||||
if (this._updateTimeoutId > 0) {
|
||||
GLib.source_remove(this._updateTimeoutId);
|
||||
this._updateTimeoutId = 0;
|
||||
}
|
||||
|
||||
// Intermediate states (connecting or disconnecting) must not trigger
|
||||
// any kind of state change.
|
||||
if (this._client.state == NM.State.CONNECTING || this._client.state == NM.State.DISCONNECTING)
|
||||
return;
|
||||
|
||||
// Use a timeout to avoid instantly throwing the notification at
|
||||
// the user's face, and to avoid a series of unecessary updates
|
||||
// that happen when NetworkManager is still figuring out details.
|
||||
this._updateTimeoutId = GLib.timeout_add_seconds(GLib.PRIORITY_DEFAULT,
|
||||
2,
|
||||
() => {
|
||||
this._updateStatus();
|
||||
this._updateTimeoutId = 0;
|
||||
return GLib.SOURCE_REMOVE;
|
||||
});
|
||||
GLib.Source.set_name_by_id(this._updateTimeoutId, '[update] updateStatus');
|
||||
}
|
||||
|
||||
_updateStatus() {
|
||||
// Update the current active connection. This will connect to the
|
||||
// NM.SettingUser signal to sync every time someone updates the
|
||||
// NM_SETTING_ALLOW_DOWNLOADS setting.
|
||||
this._updateActiveConnection();
|
||||
|
||||
let state = this._getState();
|
||||
if (state != this._state) {
|
||||
this._state = state;
|
||||
this.notify('state');
|
||||
|
||||
this._updateIcon();
|
||||
}
|
||||
}
|
||||
|
||||
_updateActiveConnection() {
|
||||
let currentActiveConnection = this._getActiveConnection();
|
||||
|
||||
if (this._activeConnection == currentActiveConnection)
|
||||
return;
|
||||
|
||||
// Disconnect from the previous active connection
|
||||
if (this._settingChangedSignalId > 0) {
|
||||
this._activeConnection.disconnect(this._settingChangedSignalId);
|
||||
this._settingChangedSignalId = 0;
|
||||
}
|
||||
|
||||
this._activeConnection = currentActiveConnection;
|
||||
|
||||
// Connect from the current active connection
|
||||
if (currentActiveConnection)
|
||||
this._settingChangedSignalId = currentActiveConnection.connect('changed', this._updateStatus.bind(this));
|
||||
}
|
||||
|
||||
_ensureUserSetting(connection) {
|
||||
let userSetting = connection.get_setting(NM.SettingUser.$gtype);
|
||||
if (!userSetting) {
|
||||
userSetting = new NM.SettingUser();
|
||||
connection.add_setting(userSetting);
|
||||
}
|
||||
return userSetting;
|
||||
}
|
||||
|
||||
_getState() {
|
||||
if (!this._activeConnection)
|
||||
return State.DISCONNECTED;
|
||||
|
||||
let userSetting = this._ensureUserSetting(this._activeConnection);
|
||||
|
||||
// We only return true when:
|
||||
// * Automatic Updates are on
|
||||
// * A schedule was set
|
||||
// * Something is being downloaded
|
||||
|
||||
let allowDownloadsValue = userSetting.get_data(NM_SETTING_ALLOW_DOWNLOADS);
|
||||
if (allowDownloadsValue) {
|
||||
let allowDownloads = (allowDownloadsValue === '1');
|
||||
|
||||
if (!allowDownloads)
|
||||
return State.DISABLED;
|
||||
} else {
|
||||
// Guess the default value from the metered state. Only return
|
||||
// if it's disabled - if it's not, we want to follow the regular
|
||||
// code paths and fetch the correct state
|
||||
let connectionSetting = this._activeConnection.get_setting_connection();
|
||||
|
||||
if (!connectionSetting)
|
||||
return State.DISABLED;
|
||||
|
||||
let metered = connectionSetting.get_metered();
|
||||
if (metered == NM.Metered.YES || metered == NM.Metered.GUESS_YES)
|
||||
return State.DISABLED;
|
||||
}
|
||||
|
||||
// Without the proxy, we can't really know the state
|
||||
if (!this._proxy)
|
||||
return State.UNKNOWN;
|
||||
|
||||
let scheduleSet = userSetting.get_data(NM_SETTING_TARIFF_ENABLED) === '1';
|
||||
if (!scheduleSet)
|
||||
return State.IDLE;
|
||||
|
||||
let downloading = this._proxy.ActiveEntryCount > 0;
|
||||
if (downloading)
|
||||
return State.DOWNLOADING;
|
||||
|
||||
// At this point we're not downloading anything, but something
|
||||
// might be queued
|
||||
let downloadsQueued = this._proxy.EntryCount > 0;
|
||||
if (downloadsQueued)
|
||||
return State.SCHEDULED;
|
||||
else
|
||||
return State.IDLE;
|
||||
}
|
||||
|
||||
_getActiveConnection() {
|
||||
let activeConnection = this._client.get_primary_connection();
|
||||
return activeConnection ? activeConnection.get_connection() : null;
|
||||
}
|
||||
|
||||
_updateIcon() {
|
||||
let state = this._state;
|
||||
let iconName = stateToIconName(state);
|
||||
|
||||
if (iconName) {
|
||||
let iconFile = Gio.File.new_for_uri(iconName);
|
||||
this._icon = new Gio.FileIcon({ file: iconFile });
|
||||
} else {
|
||||
this._icon = null;
|
||||
}
|
||||
|
||||
this.notify('icon');
|
||||
}
|
||||
|
||||
get state() {
|
||||
return this._state;
|
||||
}
|
||||
|
||||
get lastNotificationTime() {
|
||||
let connection = this._getActiveConnection();
|
||||
if (!connection)
|
||||
return -1;
|
||||
|
||||
let userSetting = connection.get_setting(NM.SettingUser.$gtype);
|
||||
if (!userSetting)
|
||||
return -1;
|
||||
|
||||
let time = userSetting.get_data(NM_SETTING_AUTOMATIC_UPDATES_NOTIFICATION_TIME);
|
||||
return time ? parseInt(time) : -1;
|
||||
}
|
||||
|
||||
set lastNotificationTime(time) {
|
||||
if (!this._activeConnection)
|
||||
return;
|
||||
|
||||
let userSetting = this._ensureUserSetting(this._activeConnection);
|
||||
userSetting.set_data(NM_SETTING_AUTOMATIC_UPDATES_NOTIFICATION_TIME,
|
||||
'%s'.format(time));
|
||||
|
||||
this._activeConnection.commit_changes(true, null);
|
||||
}
|
||||
|
||||
|
||||
get active() {
|
||||
return this._active;
|
||||
}
|
||||
|
||||
set active(_active) {
|
||||
if (this._active == _active)
|
||||
return;
|
||||
|
||||
this._active = _active;
|
||||
this.notify('active');
|
||||
}
|
||||
|
||||
get icon() {
|
||||
return this._icon;
|
||||
}
|
||||
|
||||
toggleAutomaticUpdates() {
|
||||
if (!this._activeConnection)
|
||||
return;
|
||||
|
||||
let userSetting = this._ensureUserSetting(this._activeConnection);
|
||||
|
||||
let state = this._getState();
|
||||
let value;
|
||||
|
||||
if (state == State.IDLE ||
|
||||
state == State.SCHEDULED ||
|
||||
state == State.DOWNLOADING) {
|
||||
value = '0';
|
||||
} else {
|
||||
value = '1';
|
||||
}
|
||||
|
||||
userSetting.set_data(NM_SETTING_ALLOW_DOWNLOADS, value);
|
||||
|
||||
this._activeConnection.commit_changes_async(true, null, (con, res, data) => {
|
||||
this._activeConnection.commit_changes_finish(res);
|
||||
this._updateStatus();
|
||||
});
|
||||
}
|
||||
});
|
||||
@@ -12,7 +12,16 @@ var SPINNER_ANIMATION_DELAY = 1.0;
|
||||
var Animation = class {
|
||||
constructor(file, width, height, speed) {
|
||||
this.actor = new St.Bin();
|
||||
this.actor.set_size(width, height);
|
||||
this.actor.connect('destroy', this._onDestroy.bind(this));
|
||||
this.actor.connect('notify::size', this._syncAnimationSize.bind(this));
|
||||
this.actor.connect('resource-scale-changed',
|
||||
this._loadFile.bind(this, file, width, height));
|
||||
|
||||
let themeContext = St.ThemeContext.get_for_stage(global.stage);
|
||||
this._scaleChangedId = themeContext.connect('notify::scale-factor',
|
||||
this._loadFile.bind(this, file, width, height));
|
||||
|
||||
this._speed = speed;
|
||||
|
||||
this._isLoaded = false;
|
||||
@@ -20,10 +29,7 @@ var Animation = class {
|
||||
this._timeoutId = 0;
|
||||
this._frame = 0;
|
||||
|
||||
let scaleFactor = St.ThemeContext.get_for_stage(global.stage).scale_factor;
|
||||
this._animations = St.TextureCache.get_default().load_sliced_image (file, width, height, scaleFactor,
|
||||
this._animationsLoaded.bind(this));
|
||||
this.actor.set_child(this._animations);
|
||||
this._loadFile(file, width, height);
|
||||
}
|
||||
|
||||
play() {
|
||||
@@ -47,6 +53,23 @@ var Animation = class {
|
||||
this._isPlaying = false;
|
||||
}
|
||||
|
||||
_loadFile(file, width, height) {
|
||||
let [validResourceScale, resourceScale] = this.actor.get_resource_scale();
|
||||
|
||||
this._isLoaded = false;
|
||||
this.actor.destroy_all_children();
|
||||
|
||||
if (!validResourceScale)
|
||||
return;
|
||||
|
||||
let texture_cache = St.TextureCache.get_default();
|
||||
let scaleFactor = St.ThemeContext.get_for_stage(global.stage).scale_factor;
|
||||
this._animations = texture_cache.load_sliced_image(file, width, height,
|
||||
scaleFactor, resourceScale,
|
||||
this._animationsLoaded.bind(this));
|
||||
this.actor.set_child(this._animations);
|
||||
}
|
||||
|
||||
_showFrame(frame) {
|
||||
let oldFrameActor = this._animations.get_child_at_index(this._frame);
|
||||
if (oldFrameActor)
|
||||
@@ -64,15 +87,32 @@ var Animation = class {
|
||||
return GLib.SOURCE_CONTINUE;
|
||||
}
|
||||
|
||||
_syncAnimationSize() {
|
||||
if (!this._isLoaded)
|
||||
return;
|
||||
|
||||
let [width, height] = this.actor.get_size();
|
||||
|
||||
for (let i = 0; i < this._animations.get_n_children(); ++i)
|
||||
this._animations.get_child_at_index(i).set_size(width, height);
|
||||
}
|
||||
|
||||
_animationsLoaded() {
|
||||
this._isLoaded = this._animations.get_n_children() > 0;
|
||||
|
||||
this._syncAnimationSize();
|
||||
|
||||
if (this._isPlaying)
|
||||
this.play();
|
||||
}
|
||||
|
||||
_onDestroy() {
|
||||
this.stop();
|
||||
|
||||
let themeContext = St.ThemeContext.get_for_stage(global.stage);
|
||||
if (this._scaleChangedId)
|
||||
themeContext.disconnect(this._scaleChangedId);
|
||||
this._scaleChangedId = 0;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -746,10 +746,8 @@ var BackgroundManager = class BackgroundManager {
|
||||
|
||||
this._container.add_child(backgroundActor);
|
||||
|
||||
let monitor = this._layoutManager.monitors[this._monitorIndex];
|
||||
|
||||
backgroundActor.set_size(monitor.width, monitor.height);
|
||||
if (this._controlPosition) {
|
||||
let monitor = this._layoutManager.monitors[this._monitorIndex];
|
||||
backgroundActor.set_position(monitor.x, monitor.y);
|
||||
backgroundActor.lower_bottom();
|
||||
}
|
||||
|
||||
@@ -93,10 +93,10 @@ var AutomountManager = class {
|
||||
if (!this._session.SessionIsActive)
|
||||
return;
|
||||
|
||||
let sound = global.display.get_sound();
|
||||
sound.play_from_theme('device-removed-media',
|
||||
_("External drive disconnected"),
|
||||
null);
|
||||
let player = global.display.get_sound_player();
|
||||
player.play_from_theme('device-removed-media',
|
||||
_("External drive disconnected"),
|
||||
null);
|
||||
}
|
||||
|
||||
_onDriveEjectButton(monitor, drive) {
|
||||
|
||||
135
js/ui/components/updates.js
Normal file
135
js/ui/components/updates.js
Normal file
@@ -0,0 +1,135 @@
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
//
|
||||
// Copyright (C) 2018 Endless Mobile, Inc.
|
||||
//
|
||||
// This is a GNOME Shell component to wrap the interactions over
|
||||
// D-Bus with the Mogwai system daemon.
|
||||
//
|
||||
// Licensed under the GNU General Public License Version 2
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 2
|
||||
// of the License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
const { Gio, GLib, Shell } = imports.gi;
|
||||
|
||||
const UpdateManager = imports.misc.updateManager;
|
||||
|
||||
const Main = imports.ui.main;
|
||||
const MessageTray = imports.ui.messageTray;
|
||||
|
||||
var UpdateComponent = class {
|
||||
constructor() {
|
||||
this._notification = null;
|
||||
this._state = UpdateManager.State.UNKNOWN;
|
||||
|
||||
this._manager = UpdateManager.getUpdateManager();
|
||||
this._manager.connect('notify::state', this._updateState.bind(this));
|
||||
|
||||
this._updateState();
|
||||
}
|
||||
|
||||
enable() {
|
||||
}
|
||||
|
||||
disable() {
|
||||
}
|
||||
|
||||
_updateState() {
|
||||
let newState = this._manager.state;
|
||||
|
||||
if (this._state == newState)
|
||||
return;
|
||||
|
||||
this._updateNotification(newState);
|
||||
this._state = newState;
|
||||
}
|
||||
|
||||
_updateNotification(newState) {
|
||||
// Don't notify when starting up
|
||||
if (this._manager.state == UpdateManager.State.UNKNOWN)
|
||||
return;
|
||||
|
||||
let alreadySentNotification = this._manager.lastNotificationTime != -1;
|
||||
|
||||
let wasDisconnected = this._state == UpdateManager.State.DISCONNECTED;
|
||||
let wasActive = this._state >= UpdateManager.State.IDLE;
|
||||
let isActive = newState >= UpdateManager.State.IDLE;
|
||||
|
||||
// The criteria to notify about the Automatic Updates setting is:
|
||||
// 1. If the user was disconnected and connects to a new network; or
|
||||
// 2. If the user was connected and connects to a network with different status;
|
||||
if ((wasDisconnected && alreadySentNotification) || (!wasDisconnected && isActive == wasActive))
|
||||
return;
|
||||
|
||||
if (this._notification)
|
||||
this._notification.destroy();
|
||||
|
||||
if (newState == UpdateManager.State.DISCONNECTED)
|
||||
return;
|
||||
|
||||
let source = new MessageTray.SystemNotificationSource();
|
||||
Main.messageTray.add(source);
|
||||
|
||||
// Figure out the title, subtitle and icon
|
||||
let title, subtitle, iconFile;
|
||||
|
||||
if (isActive) {
|
||||
title = _("Automatic updates on");
|
||||
subtitle = _("Your connection has unlimited data so automatic updates have been turned on.");
|
||||
iconFile = UpdateManager.stateToIconName(UpdateManager.State.IDLE);
|
||||
} else {
|
||||
title = _("Automatic updates are turned off to save your data");
|
||||
subtitle = _("You will need to choose which updates to apply when on this connection.");
|
||||
iconFile = UpdateManager.stateToIconName(UpdateManager.State.DISABLED);
|
||||
}
|
||||
|
||||
let gicon = new Gio.FileIcon({ file: Gio.File.new_for_uri(iconFile) });
|
||||
|
||||
// Create the notification.
|
||||
// The first time we notify the user for a given connection,
|
||||
// we set the urgency to critical so that we make sure the
|
||||
// user understands how we may be changing their settings.
|
||||
// On subsequent notifications for the given connection,
|
||||
// for instance if the user regularly switches between
|
||||
// metered and unmetered connections, we set the urgency
|
||||
// to normal so as not to be too obtrusive.
|
||||
this._notification = new MessageTray.Notification(source, title, subtitle, { gicon: gicon });
|
||||
this._notification.setUrgency(alreadySentNotification ?
|
||||
MessageTray.Urgency.NORMAL : MessageTray.Urgency.CRITICAL);
|
||||
this._notification.setTransient(false);
|
||||
|
||||
this._notification.addAction(_("Close"), () => {
|
||||
this._notification.destroy();
|
||||
});
|
||||
|
||||
this._notification.addAction(_("Change Settings…"), () => {
|
||||
// FIXME: this requires the Automatic Updates panel in GNOME
|
||||
// Settings. Going with the Network panel for now…
|
||||
let app = Shell.AppSystem.get_default().lookup_app('gnome-network-panel.desktop');
|
||||
Main.overview.hide();
|
||||
app.activate();
|
||||
});
|
||||
|
||||
source.notify(this._notification);
|
||||
|
||||
this._notification.connect('destroy', () => {
|
||||
this._notification = null;
|
||||
});
|
||||
|
||||
// Now that we first detected this connection, mark it as such
|
||||
this._manager.lastNotificationTime = GLib.get_real_time();
|
||||
}
|
||||
};
|
||||
|
||||
var Component = UpdateComponent;
|
||||
@@ -94,7 +94,9 @@ var CtrlAltTabManager = class CtrlAltTabManager {
|
||||
if (app)
|
||||
icon = app.create_icon_texture(POPUP_APPICON_SIZE);
|
||||
else
|
||||
icon = textureCache.bind_cairo_surface_property(windows[i], 'icon');
|
||||
icon = textureCache.bind_cairo_surface_property(windows[i],
|
||||
'icon',
|
||||
POPUP_APPICON_SIZE);
|
||||
}
|
||||
|
||||
items.push({ name: windows[i].title,
|
||||
|
||||
@@ -379,6 +379,7 @@ class IndicatorPad extends St.Widget {
|
||||
_init(actor) {
|
||||
this._source = actor;
|
||||
this._source.connect('notify::visible', () => { this.queue_relayout(); });
|
||||
this._source.connect('notify::size', () => { this.queue_relayout(); });
|
||||
super._init();
|
||||
}
|
||||
|
||||
|
||||
16
js/ui/dnd.js
16
js/ui/dnd.js
@@ -125,6 +125,16 @@ var _Draggable = class _Draggable {
|
||||
}
|
||||
|
||||
_onTouchEvent(actor, event) {
|
||||
// We only handle touch events here on wayland. On X11
|
||||
// we do get emulated pointer events, which already works
|
||||
// for single-touch cases. Besides, the X11 passive touch grab
|
||||
// set up by Mutter will make us see first the touch events
|
||||
// and later the pointer events, so it will look like two
|
||||
// unrelated series of events, we want to avoid double handling
|
||||
// in these cases.
|
||||
if (!Meta.is_wayland_compositor())
|
||||
return Clutter.EVENT_PROPAGATE;
|
||||
|
||||
if (event.type() != Clutter.EventType.TOUCH_BEGIN ||
|
||||
!global.display.is_pointer_emulating_sequence(event.get_event_sequence()))
|
||||
return Clutter.EVENT_PROPAGATE;
|
||||
@@ -296,6 +306,9 @@ var _Draggable = class _Draggable {
|
||||
* for the draggable.
|
||||
*/
|
||||
startDrag(stageX, stageY, time, sequence, device) {
|
||||
if (currentDraggable)
|
||||
return;
|
||||
|
||||
if (device == undefined) {
|
||||
let event = Clutter.get_current_event();
|
||||
|
||||
@@ -437,7 +450,8 @@ var _Draggable = class _Draggable {
|
||||
let [stageX, stageY] = event.get_coords();
|
||||
|
||||
// See if the user has moved the mouse enough to trigger a drag
|
||||
let threshold = St.Settings.get().drag_threshold;
|
||||
let scaleFactor = St.ThemeContext.get_for_stage(global.stage).scale_factor;
|
||||
let threshold = St.Settings.get().drag_threshold * scaleFactor;
|
||||
if (!currentDraggable &&
|
||||
(Math.abs(stageX - this._dragStartX) > threshold ||
|
||||
Math.abs(stageY - this._dragStartY) > threshold)) {
|
||||
|
||||
@@ -1,11 +1,16 @@
|
||||
const { Clutter, Gio, GObject, Gtk, Meta, Shell } = imports.gi;
|
||||
const { Clutter, Gio, GLib, GObject, Gtk, Meta, Shell } = imports.gi;
|
||||
|
||||
const Dialog = imports.ui.dialog;
|
||||
const ModalDialog = imports.ui.modalDialog;
|
||||
const PermissionStore = imports.misc.permissionStore;
|
||||
|
||||
const WAYLAND_KEYBINDINGS_SCHEMA = 'org.gnome.mutter.wayland.keybindings';
|
||||
|
||||
const APP_WHITELIST = ['gnome-control-center.desktop'];
|
||||
const APP_PERMISSIONS_TABLE = 'gnome';
|
||||
const APP_PERMISSIONS_ID = 'shortcuts-inhibitor';
|
||||
const GRANTED = 'GRANTED';
|
||||
const DENIED = 'DENIED';
|
||||
|
||||
var DialogResponse = Meta.InhibitShortcutsDialogResponse;
|
||||
|
||||
@@ -43,6 +48,29 @@ var InhibitShortcutsDialog = GObject.registerClass({
|
||||
Gtk.accelerator_parse(accel));
|
||||
}
|
||||
|
||||
_shouldUsePermStore() {
|
||||
return this._app && !this._app.is_window_backed();
|
||||
}
|
||||
|
||||
_saveToPermissionStore(grant) {
|
||||
if (!this._shouldUsePermStore() || this._permStore == null)
|
||||
return;
|
||||
|
||||
let permissions = {};
|
||||
permissions[this._app.get_id()] = [grant];
|
||||
let data = GLib.Variant.new('av', {});
|
||||
|
||||
this._permStore.SetRemote(APP_PERMISSIONS_TABLE,
|
||||
true,
|
||||
APP_PERMISSIONS_ID,
|
||||
permissions,
|
||||
data,
|
||||
(result, error) => {
|
||||
if (error != null)
|
||||
log(error.message);
|
||||
});
|
||||
}
|
||||
|
||||
_buildLayout() {
|
||||
let name = this._app ? this._app.get_name() : this._window.title;
|
||||
|
||||
@@ -64,12 +92,14 @@ var InhibitShortcutsDialog = GObject.registerClass({
|
||||
|
||||
this._dialog.addButton({ label: _("Deny"),
|
||||
action: () => {
|
||||
this._saveToPermissionStore(DENIED);
|
||||
this._emitResponse(DialogResponse.DENY);
|
||||
},
|
||||
key: Clutter.KEY_Escape });
|
||||
|
||||
this._dialog.addButton({ label: _("Allow"),
|
||||
action: () => {
|
||||
this._saveToPermissionStore(GRANTED);
|
||||
this._emitResponse(DialogResponse.ALLOW);
|
||||
},
|
||||
default: true });
|
||||
@@ -81,10 +111,43 @@ var InhibitShortcutsDialog = GObject.registerClass({
|
||||
}
|
||||
|
||||
vfunc_show() {
|
||||
if (this._app && APP_WHITELIST.indexOf(this._app.get_id()) != -1)
|
||||
if (this._app && APP_WHITELIST.indexOf(this._app.get_id()) != -1) {
|
||||
this._emitResponse(DialogResponse.ALLOW);
|
||||
else
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this._shouldUsePermStore()) {
|
||||
this._dialog.open();
|
||||
return;
|
||||
}
|
||||
|
||||
/* Check with the permission store */
|
||||
let appId = this._app.get_id();
|
||||
this._permStore = new PermissionStore.PermissionStore((proxy, error) => {
|
||||
if (error) {
|
||||
log(error.message);
|
||||
this._dialog.open();
|
||||
return;
|
||||
}
|
||||
|
||||
this._permStore.LookupRemote(APP_PERMISSIONS_TABLE,
|
||||
APP_PERMISSIONS_ID,
|
||||
(res, error) => {
|
||||
if (error) {
|
||||
this._dialog.open();
|
||||
log(error.message);
|
||||
return;
|
||||
}
|
||||
|
||||
let [permissions, data] = res;
|
||||
if (permissions[appId] === undefined) // Not found
|
||||
this._dialog.open();
|
||||
else if (permissions[appId] == GRANTED)
|
||||
this._emitResponse(DialogResponse.ALLOW);
|
||||
else
|
||||
this._emitResponse(DialogResponse.DENY);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
vfunc_hide() {
|
||||
|
||||
@@ -73,12 +73,9 @@ class AspectContainer extends St.Widget {
|
||||
box.x1 += Math.floor(diff / 2);
|
||||
box.x2 -= Math.ceil(diff / 2);
|
||||
} else {
|
||||
/* Restrict vertically */
|
||||
/* Restrict vertically, align to bottom */
|
||||
let height = box.get_width() / this._ratio;
|
||||
let diff = box.get_height() - height;
|
||||
|
||||
box.y1 += Math.floor(diff / 2);
|
||||
box.y2 -= Math.floor(diff / 2);
|
||||
box.y1 = box.y2 - Math.floor(height);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -884,7 +881,7 @@ var EmojiSelection = class EmojiSelection {
|
||||
this._pageIndicator.setReactive(false);
|
||||
|
||||
let bottomRow = this._createBottomRow();
|
||||
this.actor.add(bottomRow, { x_fill: true, y_fill: false });
|
||||
this.actor.add(bottomRow, { expand: true, x_fill: false, y_fill: false });
|
||||
|
||||
this._emojiPager.setCurrentPage(0);
|
||||
}
|
||||
@@ -973,7 +970,16 @@ var EmojiSelection = class EmojiSelection {
|
||||
row.appendKey(key.actor);
|
||||
row.layoutButtons();
|
||||
|
||||
return row;
|
||||
let actor = new AspectContainer({ layout_manager: new Clutter.BinLayout(),
|
||||
x_expand: true, y_expand: true });
|
||||
actor.add_child(row);
|
||||
/* Regular keyboard layouts are 11.5×4 grids, optimize for that
|
||||
* at the moment. Ideally this should be as wide as the current
|
||||
* keymap.
|
||||
*/
|
||||
actor.setRatio(11.5, 1);
|
||||
|
||||
return actor;
|
||||
}
|
||||
};
|
||||
Signals.addSignalMethods(EmojiSelection.prototype);
|
||||
|
||||
@@ -146,12 +146,13 @@ var MonitorConstraint = GObject.registerClass({
|
||||
});
|
||||
|
||||
var Monitor = class Monitor {
|
||||
constructor(index, geometry) {
|
||||
constructor(index, geometry, geometry_scale) {
|
||||
this.index = index;
|
||||
this.x = geometry.x;
|
||||
this.y = geometry.y;
|
||||
this.width = geometry.width;
|
||||
this.height = geometry.height;
|
||||
this.geometry_scale = geometry_scale;
|
||||
}
|
||||
|
||||
get inFullscreen() {
|
||||
@@ -159,6 +160,19 @@ var Monitor = class Monitor {
|
||||
}
|
||||
};
|
||||
|
||||
const UiActor = GObject.registerClass(
|
||||
class UiActor extends St.Widget {
|
||||
vfunc_get_preferred_width (forHeight) {
|
||||
let width = global.stage.width;
|
||||
return [width, width];
|
||||
}
|
||||
|
||||
vfunc_get_preferred_height (forWidth) {
|
||||
let height = global.stage.height;
|
||||
return [height, height];
|
||||
}
|
||||
});
|
||||
|
||||
const defaultParams = {
|
||||
trackFullscreen: false,
|
||||
affectsStruts: false,
|
||||
@@ -199,12 +213,8 @@ var LayoutManager = GObject.registerClass({
|
||||
global.stage.no_clear_hint = true;
|
||||
|
||||
// Set up stage hierarchy to group all UI actors under one container.
|
||||
this.uiGroup = new St.Widget({ name: 'uiGroup' });
|
||||
this.uiGroup = new UiActor({ name: 'uiGroup' });
|
||||
this.uiGroup.set_flags(Clutter.ActorFlags.NO_LAYOUT);
|
||||
this.uiGroup.add_constraint(new Clutter.BindConstraint({
|
||||
source: global.stage,
|
||||
coordinate: Clutter.BindCoordinate.ALL,
|
||||
}));
|
||||
|
||||
global.stage.remove_actor(global.window_group);
|
||||
this.uiGroup.add_actor(global.window_group);
|
||||
@@ -318,7 +328,9 @@ var LayoutManager = GObject.registerClass({
|
||||
this.monitors = [];
|
||||
let nMonitors = display.get_n_monitors();
|
||||
for (let i = 0; i < nMonitors; i++)
|
||||
this.monitors.push(new Monitor(i, display.get_monitor_geometry(i)));
|
||||
this.monitors.push(new Monitor(i,
|
||||
display.get_monitor_geometry(i),
|
||||
display.get_monitor_scale(i)));
|
||||
|
||||
if (nMonitors == 0) {
|
||||
this.primaryIndex = this.bottomIndex = -1;
|
||||
|
||||
@@ -382,6 +382,7 @@ var ObjInspector = class ObjInspector {
|
||||
}
|
||||
|
||||
button = new St.Button({ style_class: 'window-close' });
|
||||
button.add_actor(new St.Icon({ icon_name: 'window-close-symbolic' }));
|
||||
button.connect('clicked', this.close.bind(this));
|
||||
hbox.add(button);
|
||||
if (typeof(obj) == typeof({})) {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
|
||||
const { Atspi, Clutter, Cogl, GDesktopEnums,
|
||||
const { Atspi, Clutter, GDesktopEnums,
|
||||
Gio, GLib, GObject, Meta, Shell, St } = imports.gi;
|
||||
const Mainloop = imports.mainloop;
|
||||
const Signals = imports.signals;
|
||||
@@ -65,9 +65,7 @@ var MouseSpriteContent = GObject.registerClass({
|
||||
if (!this._texture)
|
||||
return;
|
||||
|
||||
let color = new Cogl.Color();
|
||||
color.init_from_4ub(0, 0, 0, 0);
|
||||
|
||||
let color = new Clutter.Color();
|
||||
let textureNode = new Clutter.TextureNode(this._texture,
|
||||
color,
|
||||
Clutter.ScalingFilter.NEAREST,
|
||||
|
||||
@@ -708,6 +708,12 @@ var Source = class Source {
|
||||
return this._policy;
|
||||
}
|
||||
|
||||
set policy(policy) {
|
||||
if (this._policy)
|
||||
this._policy.destroy();
|
||||
this._policy = policy;
|
||||
}
|
||||
|
||||
get count() {
|
||||
return this.notifications.length;
|
||||
}
|
||||
|
||||
@@ -110,9 +110,14 @@ class AppMenu extends PopupMenu.PopupMenu {
|
||||
});
|
||||
|
||||
this._appSystem.connect('installed-changed', () => {
|
||||
let sw = this._appSystem.lookup_app('org.gnome.Software.desktop');
|
||||
this._detailsItem.actor.visible = (sw != null);
|
||||
this._updateDetailsVisibility();
|
||||
});
|
||||
this._updateDetailsVisibility();
|
||||
}
|
||||
|
||||
_updateDetailsVisibility() {
|
||||
let sw = this._appSystem.lookup_app('org.gnome.Software.desktop');
|
||||
this._detailsItem.actor.visible = (sw != null);
|
||||
}
|
||||
|
||||
isEmpty() {
|
||||
@@ -729,7 +734,7 @@ class AggregateLayout extends Clutter.BoxLayout {
|
||||
let child = this._sizeChildren[i];
|
||||
let [childMin, childNat] = child.get_preferred_width(forHeight);
|
||||
minWidth = Math.max(minWidth, childMin);
|
||||
natWidth = Math.max(minWidth, childNat);
|
||||
natWidth = Math.max(natWidth, childNat);
|
||||
}
|
||||
return [minWidth, natWidth];
|
||||
}
|
||||
@@ -769,10 +774,17 @@ class AggregateMenu extends PanelMenu.Button {
|
||||
this._nightLight = new imports.ui.status.nightLight.Indicator();
|
||||
this._thunderbolt = new imports.ui.status.thunderbolt.Indicator();
|
||||
|
||||
if (Main.sessionMode.components.includes('updates'))
|
||||
this._automaticUpdates = new imports.ui.status.automaticUpdates.Indicator();
|
||||
else
|
||||
this._automaticUpdates = null;
|
||||
|
||||
this._indicators.add_child(this._thunderbolt.indicators);
|
||||
this._indicators.add_child(this._screencast.indicators);
|
||||
this._indicators.add_child(this._location.indicators);
|
||||
this._indicators.add_child(this._nightLight.indicators);
|
||||
if (this._automaticUpdates)
|
||||
this._indicators.add_child(this._automaticUpdates.indicators);
|
||||
if (this._network) {
|
||||
this._indicators.add_child(this._network.indicators);
|
||||
}
|
||||
@@ -791,6 +803,8 @@ class AggregateMenu extends PanelMenu.Button {
|
||||
if (this._network) {
|
||||
this.menu.addMenuItem(this._network.menu);
|
||||
}
|
||||
if (this._automaticUpdates)
|
||||
this.menu.addMenuItem(this._automaticUpdates.menu);
|
||||
if (this._bluetooth) {
|
||||
this.menu.addMenuItem(this._bluetooth.menu);
|
||||
}
|
||||
|
||||
@@ -92,9 +92,11 @@ const _modes = {
|
||||
unlockDialog: imports.ui.unlockDialog.UnlockDialog,
|
||||
components: Config.HAVE_NETWORKMANAGER ?
|
||||
['networkAgent', 'polkitAgent', 'telepathyClient',
|
||||
'keyring', 'autorunManager', 'automountManager'] :
|
||||
'keyring', 'autorunManager', 'automountManager',
|
||||
'updates'] :
|
||||
['polkitAgent', 'telepathyClient',
|
||||
'keyring', 'autorunManager', 'automountManager'],
|
||||
'keyring', 'autorunManager', 'automountManager',
|
||||
'updates'],
|
||||
|
||||
panel: {
|
||||
left: ['activities', 'appMenu'],
|
||||
|
||||
@@ -124,13 +124,20 @@ var GnomeShell = class {
|
||||
|
||||
UngrabAcceleratorAsync(params, invocation) {
|
||||
let [action] = params;
|
||||
let grabbedBy = this._grabbedAccelerators.get(action);
|
||||
if (invocation.get_sender() != grabbedBy)
|
||||
return invocation.return_value(GLib.Variant.new('(b)', [false]));
|
||||
let sender = invocation.get_sender();
|
||||
let ungrabSucceeded = this._ungrabAcceleratorForSender(action, sender);
|
||||
|
||||
return invocation.return_value(GLib.Variant.new('(b)', [ungrabSucceeded]));
|
||||
}
|
||||
|
||||
UngrabAcceleratorsAsync(params, invocation) {
|
||||
let [actions] = params;
|
||||
let sender = invocation.get_sender();
|
||||
let ungrabSucceeded = true;
|
||||
|
||||
for (let i = 0; i < actions.length; i++)
|
||||
ungrabSucceeded &= this._ungrabAcceleratorForSender(actions[i], sender);
|
||||
|
||||
let ungrabSucceeded = global.display.ungrab_accelerator(action);
|
||||
if (ungrabSucceeded)
|
||||
this._grabbedAccelerators.delete(action);
|
||||
return invocation.return_value(GLib.Variant.new('(b)', [ungrabSucceeded]));
|
||||
}
|
||||
|
||||
@@ -174,6 +181,16 @@ var GnomeShell = class {
|
||||
let ungrabSucceeded = global.display.ungrab_accelerator(action);
|
||||
if (ungrabSucceeded)
|
||||
this._grabbedAccelerators.delete(action);
|
||||
|
||||
return ungrabSucceeded;
|
||||
}
|
||||
|
||||
_ungrabAcceleratorForSender(action, sender) {
|
||||
let grabbedBy = this._grabbedAccelerators.get(action);
|
||||
if (sender != grabbedBy)
|
||||
return false;
|
||||
|
||||
return this._ungrabAccelerator(action);
|
||||
}
|
||||
|
||||
_onGrabberBusNameVanished(connection, name) {
|
||||
|
||||
144
js/ui/status/automaticUpdates.js
Normal file
144
js/ui/status/automaticUpdates.js
Normal file
@@ -0,0 +1,144 @@
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
//
|
||||
// Copyright (C) 2018 Endless Mobile, Inc.
|
||||
//
|
||||
// This is a GNOME Shell component to wrap the interactions over
|
||||
// D-Bus with the Mogwai system daemon.
|
||||
//
|
||||
// Licensed under the GNU General Public License Version 2
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 2
|
||||
// of the License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
const { Gio, GLib, Shell, St } = imports.gi;
|
||||
|
||||
const UpdateManager = imports.misc.updateManager;
|
||||
|
||||
const Main = imports.ui.main;
|
||||
const MessageTray = imports.ui.messageTray;
|
||||
const PanelMenu = imports.ui.panelMenu;
|
||||
const PopupMenu = imports.ui.popupMenu;
|
||||
|
||||
const NM_SETTING_AUTOMATIC_UPDATES_NOTIFICATION_TIME = "connection.automatic-updates-notification-time";
|
||||
const NM_SETTING_ALLOW_DOWNLOADS = 'connection.allow-downloads';
|
||||
const NM_SETTING_TARIFF_ENABLED = "connection.tariff-enabled";
|
||||
|
||||
const SchedulerInterface = '\
|
||||
<node> \
|
||||
<interface name="com.endlessm.DownloadManager1.Scheduler"> \
|
||||
<property name="ActiveEntryCount" type="u" access="read" /> \
|
||||
<property name="EntryCount" type="u" access="read" /> \
|
||||
</interface> \
|
||||
</node>';
|
||||
|
||||
const SchedulerProxy = Gio.DBusProxy.makeProxyWrapper(SchedulerInterface);
|
||||
|
||||
var Indicator = class extends PanelMenu.SystemIndicator {
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this._indicator = this._addIndicator();
|
||||
this._indicator.visible = false;
|
||||
|
||||
this._item = new PopupMenu.PopupSubMenuMenuItem("", true);
|
||||
this._toggleItem = this._item.menu.addAction("", this._toggleAutomaticUpdates.bind(this));
|
||||
this._item.menu.addAction(_("Updates Queue"), () => {
|
||||
let params = new GLib.Variant('(sava{sv})', [ 'set-mode', [ new GLib.Variant('s', 'updates') ], {} ]);
|
||||
Gio.DBus.session.call('org.gnome.Software',
|
||||
'/org/gnome/Software',
|
||||
'org.gtk.Actions',
|
||||
'Activate',
|
||||
params,
|
||||
null,
|
||||
Gio.DBusCallFlags.NONE,
|
||||
5000,
|
||||
null,
|
||||
(conn, result) => {
|
||||
try {
|
||||
conn.call_finish(result);
|
||||
} catch (e) {
|
||||
logError(e, 'Failed to start gnome-software');
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
this._item.menu.addSettingsAction(_("Set a Schedule"), 'gnome-updates-panel.desktop');
|
||||
this.menu.addMenuItem(this._item);
|
||||
|
||||
this._manager = UpdateManager.getUpdateManager();
|
||||
this._manager.connect('notify::state', this._updateState.bind(this));
|
||||
|
||||
this._updateState();
|
||||
}
|
||||
|
||||
_updateState() {
|
||||
this._updateStatus();
|
||||
}
|
||||
|
||||
_sessionUpdated() {
|
||||
let sensitive = !Main.sessionMode.isLocked && !Main.sessionMode.isGreeter;
|
||||
this.menu.setSensitive(sensitive);
|
||||
}
|
||||
|
||||
_updateStatus() {
|
||||
// Toggle item name
|
||||
this._updateItem();
|
||||
|
||||
// Icons
|
||||
let icon = this._getIcon()
|
||||
|
||||
this._item.icon.gicon = icon;
|
||||
this._indicator.gicon = icon;
|
||||
|
||||
// Only show the Automatic Updates icon at the bottom bar when it is
|
||||
// both enabled, and there are updates being downloaded or installed.
|
||||
this._updateVisibility();
|
||||
|
||||
// The status label
|
||||
this._item.label.text = _("Automatic Updates");
|
||||
}
|
||||
|
||||
_updateItem() {
|
||||
let state = this._manager.state;
|
||||
|
||||
if (state == UpdateManager.State.DISABLED)
|
||||
this._toggleItem.label.text = _("Turn On");
|
||||
else
|
||||
this._toggleItem.label.text = _("Turn Off");
|
||||
}
|
||||
|
||||
_toggleAutomaticUpdates() {
|
||||
this._manager.toggleAutomaticUpdates();
|
||||
}
|
||||
|
||||
_getIcon() {
|
||||
let state = this._manager.state;
|
||||
let iconName = UpdateManager.stateToIconName(state);
|
||||
|
||||
if (!iconName)
|
||||
return null;
|
||||
|
||||
let iconFile = Gio.File.new_for_uri(iconName);
|
||||
let gicon = new Gio.FileIcon({ file: iconFile });
|
||||
|
||||
return gicon;
|
||||
}
|
||||
|
||||
_updateVisibility() {
|
||||
let state = this._manager.state;
|
||||
|
||||
this._item.actor.visible = (state != UpdateManager.State.DISCONNECTED);
|
||||
this._indicator.visible = (state == UpdateManager.State.DOWNLOADING);
|
||||
}
|
||||
};
|
||||
@@ -1236,7 +1236,6 @@ var NMDeviceWireless = class {
|
||||
}
|
||||
|
||||
_dialogClosed() {
|
||||
this._dialog.destroy();
|
||||
this._dialog = null;
|
||||
}
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ var Avatar = class {
|
||||
this._user = user;
|
||||
params = Params.parse(params, { reactive: false,
|
||||
iconSize: AVATAR_ICON_SIZE,
|
||||
styleClass: 'framed-user-icon' });
|
||||
styleClass: 'user-icon' });
|
||||
this._iconSize = params.iconSize;
|
||||
|
||||
let scaleFactor = St.ThemeContext.get_for_stage(global.stage).scale_factor;
|
||||
@@ -46,15 +46,14 @@ var Avatar = class {
|
||||
if (iconFile) {
|
||||
let file = Gio.File.new_for_path(iconFile);
|
||||
this.actor.child = null;
|
||||
this.actor.style = 'background-image: url("%s");'.format(iconFile);
|
||||
this.actor.style = `
|
||||
background-image: url("${iconFile}");
|
||||
background-size: ${this._iconSize}px`;
|
||||
} else {
|
||||
this.actor.style = null;
|
||||
this.actor.child = new St.Icon({ icon_name: 'avatar-default-symbolic',
|
||||
icon_size: this._iconSize });
|
||||
}
|
||||
|
||||
let scaleFactor = St.ThemeContext.get_for_stage(global.stage).scale_factor;
|
||||
this.actor.set_size(this._iconSize * scaleFactor, this._iconSize * scaleFactor);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -101,6 +101,5 @@ var Source = class WindowAttentionSource extends MessageTray.Source {
|
||||
|
||||
open() {
|
||||
Main.activateWindow(this._window);
|
||||
this.destroy();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
project('gnome-shell', 'c',
|
||||
version: '3.31.91',
|
||||
version: '3.32.0',
|
||||
meson_version: '>= 0.47.0',
|
||||
license: 'GPLv2+'
|
||||
)
|
||||
@@ -20,10 +20,10 @@ gcr_req = '>= 3.7.5'
|
||||
gdesktop_req = '>= 3.7.90'
|
||||
gio_req = '>= 2.56.0'
|
||||
gi_req = '>= 1.49.1'
|
||||
gjs_req = '>= 1.47.0'
|
||||
gjs_req = '>= 1.54.0'
|
||||
gtk_req = '>= 3.15.0'
|
||||
json_glib_req = '>= 0.13.2'
|
||||
mutter_req = '>= 3.31.91'
|
||||
mutter_req = '>= 3.32.0'
|
||||
polkit_req = '>= 0.100'
|
||||
schemas_req = '>= 3.27.90'
|
||||
startup_req = '>= 0.11'
|
||||
|
||||
@@ -52,6 +52,7 @@ js/ui/search.js
|
||||
js/ui/shellEntry.js
|
||||
js/ui/shellMountOperation.js
|
||||
js/ui/status/accessibility.js
|
||||
js/ui/status/automaticUpdates.js
|
||||
js/ui/status/bluetooth.js
|
||||
js/ui/status/brightness.js
|
||||
js/ui/status/keyboard.js
|
||||
|
||||
2
po/af.po
2
po/af.po
@@ -330,7 +330,7 @@ msgstr "Netwerkaanmelding"
|
||||
#. Translators: Do NOT translate or transliterate this text (this is an icon file name)!
|
||||
#: data/org.gnome.Shell.PortalHelper.desktop.in.in:9
|
||||
msgid "network-workgroup"
|
||||
msgstr "netwerk-werkgroep"
|
||||
msgstr "network-workgroup"
|
||||
|
||||
#: js/extensionPrefs/main.js:120
|
||||
#, javascript-format
|
||||
|
||||
52
po/id.po
52
po/id.po
@@ -8,7 +8,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: gnome-shell master\n"
|
||||
"Report-Msgid-Bugs-To: https://gitlab.gnome.org/GNOME/gnome-shell/issues\n"
|
||||
"POT-Creation-Date: 2019-02-11 18:01+0000\n"
|
||||
"POT-Creation-Date: 2019-02-21 18:43+0000\n"
|
||||
"PO-Revision-Date: 2019-02-14 22:18+0700\n"
|
||||
"Last-Translator: Kukuh Syafaat <kukuhsyafaat@gnome.org>\n"
|
||||
"Language-Team: Indonesian <gnome-l10n-id@googlegroups.com>\n"
|
||||
@@ -480,7 +480,7 @@ msgstr "Jendela Log Masuk"
|
||||
|
||||
#: js/gdm/util.js:337
|
||||
msgid "Authentication error"
|
||||
msgstr "Galat otentikasi"
|
||||
msgstr "Galat autentikasi"
|
||||
|
||||
#. We don't show fingerprint messages directly since it's
|
||||
#. not the main auth service. Instead we use the messages
|
||||
@@ -748,12 +748,12 @@ msgstr "Tambah ke Favorit"
|
||||
msgid "Show Details"
|
||||
msgstr "Tampilkan Rincian"
|
||||
|
||||
#: js/ui/appFavorites.js:139
|
||||
#: js/ui/appFavorites.js:141
|
||||
#, javascript-format
|
||||
msgid "%s has been added to your favorites."
|
||||
msgstr "%s telah ditambahkan ke favorit Anda."
|
||||
|
||||
#: js/ui/appFavorites.js:173
|
||||
#: js/ui/appFavorites.js:175
|
||||
#, javascript-format
|
||||
msgid "%s has been removed from your favorites."
|
||||
msgstr "%s telah dihapus dari favorit Anda."
|
||||
@@ -791,7 +791,7 @@ msgid "Settings"
|
||||
msgstr "Pengaturan"
|
||||
|
||||
#. Translators: Enter 0-6 (Sunday-Saturday) for non-work days. Examples: "0" (Sunday) "6" (Saturday) "06" (Sunday and Saturday).
|
||||
#: js/ui/calendar.js:38
|
||||
#: js/ui/calendar.js:40
|
||||
msgctxt "calendar-no-work"
|
||||
msgid "06"
|
||||
msgstr "06"
|
||||
@@ -801,43 +801,43 @@ msgstr "06"
|
||||
#. * NOTE: These grid abbreviations are always shown together
|
||||
#. * and in order, e.g. "S M T W T F S".
|
||||
#.
|
||||
#: js/ui/calendar.js:67
|
||||
#: js/ui/calendar.js:69
|
||||
msgctxt "grid sunday"
|
||||
msgid "S"
|
||||
msgstr "M"
|
||||
|
||||
#. Translators: Calendar grid abbreviation for Monday
|
||||
#: js/ui/calendar.js:69
|
||||
#: js/ui/calendar.js:71
|
||||
msgctxt "grid monday"
|
||||
msgid "M"
|
||||
msgstr "S"
|
||||
|
||||
#. Translators: Calendar grid abbreviation for Tuesday
|
||||
#: js/ui/calendar.js:71
|
||||
#: js/ui/calendar.js:73
|
||||
msgctxt "grid tuesday"
|
||||
msgid "T"
|
||||
msgstr "S"
|
||||
|
||||
#. Translators: Calendar grid abbreviation for Wednesday
|
||||
#: js/ui/calendar.js:73
|
||||
#: js/ui/calendar.js:75
|
||||
msgctxt "grid wednesday"
|
||||
msgid "W"
|
||||
msgstr "R"
|
||||
|
||||
#. Translators: Calendar grid abbreviation for Thursday
|
||||
#: js/ui/calendar.js:75
|
||||
#: js/ui/calendar.js:77
|
||||
msgctxt "grid thursday"
|
||||
msgid "T"
|
||||
msgstr "K"
|
||||
|
||||
#. Translators: Calendar grid abbreviation for Friday
|
||||
#: js/ui/calendar.js:77
|
||||
#: js/ui/calendar.js:79
|
||||
msgctxt "grid friday"
|
||||
msgid "F"
|
||||
msgstr "J"
|
||||
|
||||
#. Translators: Calendar grid abbreviation for Saturday
|
||||
#: js/ui/calendar.js:79
|
||||
#: js/ui/calendar.js:81
|
||||
msgctxt "grid saturday"
|
||||
msgid "S"
|
||||
msgstr "S"
|
||||
@@ -848,7 +848,7 @@ msgstr "S"
|
||||
#. * "%OB" is the new format specifier introduced in glibc 2.27,
|
||||
#. * in most cases you should not change it.
|
||||
#.
|
||||
#: js/ui/calendar.js:342
|
||||
#: js/ui/calendar.js:332
|
||||
msgid "%OB"
|
||||
msgstr "%OB"
|
||||
|
||||
@@ -861,55 +861,55 @@ msgstr "%OB"
|
||||
#. * in most cases you should not use the old "%B" here unless you
|
||||
#. * absolutely know what you are doing.
|
||||
#.
|
||||
#: js/ui/calendar.js:352
|
||||
#: js/ui/calendar.js:342
|
||||
msgid "%OB %Y"
|
||||
msgstr "%OB %Y"
|
||||
|
||||
#: js/ui/calendar.js:409
|
||||
#: js/ui/calendar.js:399
|
||||
msgid "Previous month"
|
||||
msgstr "Bulan sebelumnya"
|
||||
|
||||
#: js/ui/calendar.js:420
|
||||
#: js/ui/calendar.js:410
|
||||
msgid "Next month"
|
||||
msgstr "Bulan selanjutnya"
|
||||
|
||||
#: js/ui/calendar.js:574
|
||||
#: js/ui/calendar.js:564
|
||||
#, no-javascript-format
|
||||
msgctxt "date day number format"
|
||||
msgid "%d"
|
||||
msgstr "%d"
|
||||
|
||||
#: js/ui/calendar.js:629
|
||||
#: js/ui/calendar.js:619
|
||||
msgid "Week %V"
|
||||
msgstr "Minggu %V"
|
||||
|
||||
#. Translators: Shown in calendar event list for all day events
|
||||
#. * Keep it short, best if you can use less then 10 characters
|
||||
#.
|
||||
#: js/ui/calendar.js:697
|
||||
#: js/ui/calendar.js:687
|
||||
msgctxt "event list time"
|
||||
msgid "All Day"
|
||||
msgstr "Sepanjang Hari"
|
||||
|
||||
#: js/ui/calendar.js:829
|
||||
#: js/ui/calendar.js:819
|
||||
msgctxt "calendar heading"
|
||||
msgid "%A, %B %-d"
|
||||
msgstr "%A, %d %B"
|
||||
|
||||
#: js/ui/calendar.js:833
|
||||
#: js/ui/calendar.js:823
|
||||
msgctxt "calendar heading"
|
||||
msgid "%A, %B %-d, %Y"
|
||||
msgstr "%A, %d %B %Y"
|
||||
|
||||
#: js/ui/calendar.js:1056
|
||||
#: js/ui/calendar.js:1046
|
||||
msgid "No Notifications"
|
||||
msgstr "Tak Ada Pemberitahuan"
|
||||
|
||||
#: js/ui/calendar.js:1059
|
||||
#: js/ui/calendar.js:1049
|
||||
msgid "No Events"
|
||||
msgstr "Tak Ada Kejadian"
|
||||
|
||||
#: js/ui/calendar.js:1085
|
||||
#: js/ui/calendar.js:1075
|
||||
msgid "Clear"
|
||||
msgstr "Bersihkan"
|
||||
|
||||
@@ -1045,7 +1045,7 @@ msgstr "Manajer Jaringan"
|
||||
|
||||
#: js/ui/components/polkitAgent.js:34
|
||||
msgid "Authentication Required"
|
||||
msgstr "Diperlukan Otentikasi"
|
||||
msgstr "Diperlukan Autentikasi"
|
||||
|
||||
#: js/ui/components/polkitAgent.js:62
|
||||
msgid "Administrator"
|
||||
@@ -2266,7 +2266,7 @@ msgstr "Sandi tidak boleh kosong"
|
||||
|
||||
#: src/shell-polkit-authentication-agent.c:348
|
||||
msgid "Authentication dialog was dismissed by the user"
|
||||
msgstr "Dialog otentikasi ditolak oleh pengguna"
|
||||
msgstr "Dialog autentikasi ditolak oleh pengguna"
|
||||
|
||||
#. translators:
|
||||
#. * The number of sound outputs on a particular device
|
||||
|
||||
@@ -21,6 +21,16 @@
|
||||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/*
|
||||
* GnomeShellPlugin is the entry point for for GNOME Shell into and out of
|
||||
* Mutter. By registering itself into Mutter using
|
||||
* meta_plugin_manager_set_plugin_type(), Mutter will call the vfuncs of the
|
||||
* plugin at the appropriate time.
|
||||
*
|
||||
* The funcions in in GnomeShellPlugin are all just stubs, which just call the
|
||||
* similar methods in GnomeShellWm.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
@@ -37,72 +47,10 @@
|
||||
#include "shell-perf-log.h"
|
||||
#include "shell-wm-private.h"
|
||||
|
||||
static void gnome_shell_plugin_start (MetaPlugin *plugin);
|
||||
static void gnome_shell_plugin_minimize (MetaPlugin *plugin,
|
||||
MetaWindowActor *actor);
|
||||
static void gnome_shell_plugin_unminimize (MetaPlugin *plugin,
|
||||
MetaWindowActor *actor);
|
||||
static void gnome_shell_plugin_size_changed (MetaPlugin *plugin,
|
||||
MetaWindowActor *actor);
|
||||
static void gnome_shell_plugin_size_change (MetaPlugin *plugin,
|
||||
MetaWindowActor *actor,
|
||||
MetaSizeChange which_change,
|
||||
MetaRectangle *old_frame_rect,
|
||||
MetaRectangle *old_buffer_rect);
|
||||
static void gnome_shell_plugin_map (MetaPlugin *plugin,
|
||||
MetaWindowActor *actor);
|
||||
static void gnome_shell_plugin_destroy (MetaPlugin *plugin,
|
||||
MetaWindowActor *actor);
|
||||
|
||||
static void gnome_shell_plugin_switch_workspace (MetaPlugin *plugin,
|
||||
gint from,
|
||||
gint to,
|
||||
MetaMotionDirection direction);
|
||||
|
||||
static void gnome_shell_plugin_kill_window_effects (MetaPlugin *plugin,
|
||||
MetaWindowActor *actor);
|
||||
static void gnome_shell_plugin_kill_switch_workspace (MetaPlugin *plugin);
|
||||
|
||||
static void gnome_shell_plugin_show_tile_preview (MetaPlugin *plugin,
|
||||
MetaWindow *window,
|
||||
MetaRectangle *tile_rect,
|
||||
int tile_monitor);
|
||||
static void gnome_shell_plugin_hide_tile_preview (MetaPlugin *plugin);
|
||||
static void gnome_shell_plugin_show_window_menu (MetaPlugin *plugin,
|
||||
MetaWindow *window,
|
||||
MetaWindowMenuType menu,
|
||||
int x,
|
||||
int y);
|
||||
static void gnome_shell_plugin_show_window_menu_for_rect (MetaPlugin *plugin,
|
||||
MetaWindow *window,
|
||||
MetaWindowMenuType menu,
|
||||
MetaRectangle *rect);
|
||||
|
||||
static gboolean gnome_shell_plugin_xevent_filter (MetaPlugin *plugin,
|
||||
XEvent *event);
|
||||
|
||||
static gboolean gnome_shell_plugin_keybinding_filter (MetaPlugin *plugin,
|
||||
MetaKeyBinding *binding);
|
||||
|
||||
static void gnome_shell_plugin_confirm_display_change (MetaPlugin *plugin);
|
||||
|
||||
static const MetaPluginInfo *gnome_shell_plugin_plugin_info (MetaPlugin *plugin);
|
||||
|
||||
static MetaCloseDialog * gnome_shell_plugin_create_close_dialog (MetaPlugin *plugin,
|
||||
MetaWindow *window);
|
||||
|
||||
static MetaInhibitShortcutsDialog * gnome_shell_plugin_create_inhibit_shortcuts_dialog (MetaPlugin *plugin,
|
||||
MetaWindow *window);
|
||||
|
||||
#define GNOME_TYPE_SHELL_PLUGIN (gnome_shell_plugin_get_type ())
|
||||
#define GNOME_SHELL_PLUGIN(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GNOME_TYPE_SHELL_PLUGIN, GnomeShellPlugin))
|
||||
#define GNOME_SHELL_PLUGIN_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GNOME_TYPE_SHELL_PLUGIN, GnomeShellPluginClass))
|
||||
#define GNOME_IS_SHELL_PLUGIN(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GNOME_SHELL_PLUGIN_TYPE))
|
||||
#define GNOME_IS_SHELL_PLUGIN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GNOME_TYPE_SHELL_PLUGIN))
|
||||
#define GNOME_SHELL_PLUGIN_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GNOME_TYPE_SHELL_PLUGIN, GnomeShellPluginClass))
|
||||
|
||||
typedef struct _GnomeShellPlugin GnomeShellPlugin;
|
||||
typedef struct _GnomeShellPluginClass GnomeShellPluginClass;
|
||||
#define GNOME_TYPE_SHELL_PLUGIN (gnome_shell_plugin_get_type ())
|
||||
G_DECLARE_FINAL_TYPE (GnomeShellPlugin, gnome_shell_plugin,
|
||||
GNOME, SHELL_PLUGIN,
|
||||
MetaPlugin)
|
||||
|
||||
struct _GnomeShellPlugin
|
||||
{
|
||||
@@ -116,54 +64,8 @@ struct _GnomeShellPlugin
|
||||
ShellGlobal *global;
|
||||
};
|
||||
|
||||
struct _GnomeShellPluginClass
|
||||
{
|
||||
MetaPluginClass parent_class;
|
||||
};
|
||||
|
||||
GType gnome_shell_plugin_get_type (void);
|
||||
|
||||
G_DEFINE_TYPE (GnomeShellPlugin, gnome_shell_plugin, META_TYPE_PLUGIN)
|
||||
|
||||
static void
|
||||
gnome_shell_plugin_class_init (GnomeShellPluginClass *klass)
|
||||
{
|
||||
MetaPluginClass *plugin_class = META_PLUGIN_CLASS (klass);
|
||||
|
||||
plugin_class->start = gnome_shell_plugin_start;
|
||||
plugin_class->map = gnome_shell_plugin_map;
|
||||
plugin_class->minimize = gnome_shell_plugin_minimize;
|
||||
plugin_class->unminimize = gnome_shell_plugin_unminimize;
|
||||
plugin_class->size_changed = gnome_shell_plugin_size_changed;
|
||||
plugin_class->size_change = gnome_shell_plugin_size_change;
|
||||
plugin_class->destroy = gnome_shell_plugin_destroy;
|
||||
|
||||
plugin_class->switch_workspace = gnome_shell_plugin_switch_workspace;
|
||||
|
||||
plugin_class->kill_window_effects = gnome_shell_plugin_kill_window_effects;
|
||||
plugin_class->kill_switch_workspace = gnome_shell_plugin_kill_switch_workspace;
|
||||
|
||||
plugin_class->show_tile_preview = gnome_shell_plugin_show_tile_preview;
|
||||
plugin_class->hide_tile_preview = gnome_shell_plugin_hide_tile_preview;
|
||||
plugin_class->show_window_menu = gnome_shell_plugin_show_window_menu;
|
||||
plugin_class->show_window_menu_for_rect = gnome_shell_plugin_show_window_menu_for_rect;
|
||||
|
||||
plugin_class->xevent_filter = gnome_shell_plugin_xevent_filter;
|
||||
plugin_class->keybinding_filter = gnome_shell_plugin_keybinding_filter;
|
||||
|
||||
plugin_class->confirm_display_change = gnome_shell_plugin_confirm_display_change;
|
||||
|
||||
plugin_class->plugin_info = gnome_shell_plugin_plugin_info;
|
||||
|
||||
plugin_class->create_close_dialog = gnome_shell_plugin_create_close_dialog;
|
||||
plugin_class->create_inhibit_shortcuts_dialog = gnome_shell_plugin_create_inhibit_shortcuts_dialog;
|
||||
}
|
||||
|
||||
static void
|
||||
gnome_shell_plugin_init (GnomeShellPlugin *shell_plugin)
|
||||
{
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gnome_shell_plugin_has_swap_event (GnomeShellPlugin *shell_plugin)
|
||||
{
|
||||
@@ -416,8 +318,8 @@ gnome_shell_plugin_confirm_display_change (MetaPlugin *plugin)
|
||||
_shell_wm_confirm_display_change (get_shell_wm ());
|
||||
}
|
||||
|
||||
static const
|
||||
MetaPluginInfo *gnome_shell_plugin_plugin_info (MetaPlugin *plugin)
|
||||
static const MetaPluginInfo *
|
||||
gnome_shell_plugin_plugin_info (MetaPlugin *plugin)
|
||||
{
|
||||
static const MetaPluginInfo info = {
|
||||
.name = "GNOME Shell",
|
||||
@@ -443,3 +345,42 @@ gnome_shell_plugin_create_inhibit_shortcuts_dialog (MetaPlugin *plugin,
|
||||
{
|
||||
return _shell_wm_create_inhibit_shortcuts_dialog (get_shell_wm (), window);
|
||||
}
|
||||
|
||||
static void
|
||||
gnome_shell_plugin_class_init (GnomeShellPluginClass *klass)
|
||||
{
|
||||
MetaPluginClass *plugin_class = META_PLUGIN_CLASS (klass);
|
||||
|
||||
plugin_class->start = gnome_shell_plugin_start;
|
||||
plugin_class->map = gnome_shell_plugin_map;
|
||||
plugin_class->minimize = gnome_shell_plugin_minimize;
|
||||
plugin_class->unminimize = gnome_shell_plugin_unminimize;
|
||||
plugin_class->size_changed = gnome_shell_plugin_size_changed;
|
||||
plugin_class->size_change = gnome_shell_plugin_size_change;
|
||||
plugin_class->destroy = gnome_shell_plugin_destroy;
|
||||
|
||||
plugin_class->switch_workspace = gnome_shell_plugin_switch_workspace;
|
||||
|
||||
plugin_class->kill_window_effects = gnome_shell_plugin_kill_window_effects;
|
||||
plugin_class->kill_switch_workspace = gnome_shell_plugin_kill_switch_workspace;
|
||||
|
||||
plugin_class->show_tile_preview = gnome_shell_plugin_show_tile_preview;
|
||||
plugin_class->hide_tile_preview = gnome_shell_plugin_hide_tile_preview;
|
||||
plugin_class->show_window_menu = gnome_shell_plugin_show_window_menu;
|
||||
plugin_class->show_window_menu_for_rect = gnome_shell_plugin_show_window_menu_for_rect;
|
||||
|
||||
plugin_class->xevent_filter = gnome_shell_plugin_xevent_filter;
|
||||
plugin_class->keybinding_filter = gnome_shell_plugin_keybinding_filter;
|
||||
|
||||
plugin_class->confirm_display_change = gnome_shell_plugin_confirm_display_change;
|
||||
|
||||
plugin_class->plugin_info = gnome_shell_plugin_plugin_info;
|
||||
|
||||
plugin_class->create_close_dialog = gnome_shell_plugin_create_close_dialog;
|
||||
plugin_class->create_inhibit_shortcuts_dialog = gnome_shell_plugin_create_inhibit_shortcuts_dialog;
|
||||
}
|
||||
|
||||
static void
|
||||
gnome_shell_plugin_init (GnomeShellPlugin *shell_plugin)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -184,7 +184,7 @@ window_backed_app_get_icon (ShellApp *app,
|
||||
int size)
|
||||
{
|
||||
MetaWindow *window = NULL;
|
||||
ClutterActor *actor;
|
||||
StWidget *widget;
|
||||
gint scale;
|
||||
ShellGlobal *global;
|
||||
StThemeContext *context;
|
||||
@@ -204,16 +204,20 @@ window_backed_app_get_icon (ShellApp *app,
|
||||
|
||||
if (window == NULL)
|
||||
{
|
||||
ClutterActor *actor;
|
||||
|
||||
actor = clutter_actor_new ();
|
||||
g_object_set (actor, "opacity", 0, "width", (float) size, "height", (float) size, NULL);
|
||||
return actor;
|
||||
}
|
||||
|
||||
actor = st_texture_cache_bind_cairo_surface_property (st_texture_cache_get_default (),
|
||||
G_OBJECT (window),
|
||||
"icon");
|
||||
g_object_set (actor, "width", (float) size, "height", (float) size, NULL);
|
||||
return actor;
|
||||
widget = st_texture_cache_bind_cairo_surface_property (st_texture_cache_get_default (),
|
||||
G_OBJECT (window),
|
||||
"icon",
|
||||
size);
|
||||
st_widget_add_style_class_name (widget, "fallback-app-icon");
|
||||
|
||||
return CLUTTER_ACTOR (widget);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
#include "shell-embedded-window-private.h"
|
||||
#include "shell-global.h"
|
||||
#include "shell-util.h"
|
||||
|
||||
#include <gdk/gdkx.h>
|
||||
#include <meta/display.h>
|
||||
@@ -94,6 +95,10 @@ shell_gtk_embed_window_created_cb (MetaDisplay *display,
|
||||
as a normal window */
|
||||
clutter_actor_set_opacity (window_actor, 0);
|
||||
|
||||
/* Also make sure it (or any of its children) doesn't block
|
||||
events on wayland */
|
||||
shell_util_set_hidden_from_pick (window_actor, TRUE);
|
||||
|
||||
/* Set an empty input shape on the window so that it can't get
|
||||
any input. This probably isn't the ideal way to achieve this.
|
||||
It would probably be better to force the window to go behind
|
||||
|
||||
@@ -51,6 +51,10 @@ struct _ShellRecorder {
|
||||
int stage_width;
|
||||
int stage_height;
|
||||
|
||||
int capture_width;
|
||||
int capture_height;
|
||||
float scale;
|
||||
|
||||
int pointer_x;
|
||||
int pointer_y;
|
||||
|
||||
@@ -430,10 +434,8 @@ recorder_record_frame (ShellRecorder *recorder,
|
||||
return;
|
||||
recorder->last_frame_time = now;
|
||||
|
||||
clutter_stage_capture (recorder->stage, paint, &recorder->area,
|
||||
&captures, &n_captures);
|
||||
|
||||
if (n_captures == 0)
|
||||
if (!clutter_stage_capture (recorder->stage, paint, &recorder->area,
|
||||
&captures, &n_captures))
|
||||
return;
|
||||
|
||||
if (n_captures == 1)
|
||||
@@ -443,8 +445,9 @@ recorder_record_frame (ShellRecorder *recorder,
|
||||
n_captures,
|
||||
recorder->area.x,
|
||||
recorder->area.y,
|
||||
recorder->area.width,
|
||||
recorder->area.height);
|
||||
recorder->capture_width,
|
||||
recorder->capture_height,
|
||||
recorder->scale);
|
||||
|
||||
data = cairo_image_surface_get_data (image);
|
||||
size = (cairo_image_surface_get_height (image) *
|
||||
@@ -500,6 +503,11 @@ recorder_update_size (ShellRecorder *recorder)
|
||||
recorder->area.y = 0;
|
||||
recorder->area.width = recorder->stage_width;
|
||||
recorder->area.height = recorder->stage_height;
|
||||
|
||||
clutter_stage_get_capture_final_size (recorder->stage, NULL,
|
||||
&recorder->capture_width,
|
||||
&recorder->capture_height,
|
||||
&recorder->scale);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -618,6 +626,8 @@ recorder_connect_stage_callbacks (ShellRecorder *recorder)
|
||||
G_CALLBACK (recorder_on_stage_notify_size), recorder);
|
||||
g_signal_connect (recorder->stage, "notify::height",
|
||||
G_CALLBACK (recorder_on_stage_notify_size), recorder);
|
||||
g_signal_connect (recorder->stage, "notify::resource-scale",
|
||||
G_CALLBACK (recorder_on_stage_notify_size), recorder);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -875,6 +885,7 @@ shell_recorder_class_init (ShellRecorderClass *klass)
|
||||
static void
|
||||
recorder_pipeline_set_caps (RecorderPipeline *pipeline)
|
||||
{
|
||||
ShellRecorder *recorder = pipeline->recorder;
|
||||
GstCaps *caps;
|
||||
|
||||
/* The data is always native-endian xRGB; videoconvert
|
||||
@@ -887,9 +898,9 @@ recorder_pipeline_set_caps (RecorderPipeline *pipeline)
|
||||
#else
|
||||
"format", G_TYPE_STRING, "xRGB",
|
||||
#endif
|
||||
"framerate", GST_TYPE_FRACTION, pipeline->recorder->framerate, 1,
|
||||
"width", G_TYPE_INT, pipeline->recorder->area.width,
|
||||
"height", G_TYPE_INT, pipeline->recorder->area.height,
|
||||
"framerate", GST_TYPE_FRACTION, recorder->framerate, 1,
|
||||
"width", G_TYPE_INT, recorder->capture_width,
|
||||
"height", G_TYPE_INT, recorder->capture_height,
|
||||
NULL);
|
||||
g_object_set (pipeline->src, "caps", caps, NULL);
|
||||
gst_caps_unref (caps);
|
||||
@@ -1496,6 +1507,11 @@ shell_recorder_set_area (ShellRecorder *recorder,
|
||||
recorder->area.height = CLAMP (height,
|
||||
0, recorder->stage_height - recorder->area.y);
|
||||
|
||||
clutter_stage_get_capture_final_size (recorder->stage, &recorder->area,
|
||||
&recorder->capture_width,
|
||||
&recorder->capture_height,
|
||||
&recorder->scale);
|
||||
|
||||
/* This breaks the recording but tweaking the GStreamer pipeline a bit
|
||||
* might make it work, at least if the codec can handle a stream where
|
||||
* the frame size changes in the middle.
|
||||
|
||||
@@ -40,6 +40,13 @@ struct _ShellScreenshotPrivate
|
||||
gboolean include_frame;
|
||||
};
|
||||
|
||||
typedef enum
|
||||
{
|
||||
SHELL_SCREENSHOT_SCREEN,
|
||||
SHELL_SCREENSHOT_WINDOW,
|
||||
SHELL_SCREENSHOT_AREA,
|
||||
} ShellScreenshotMode;
|
||||
|
||||
G_DEFINE_TYPE_WITH_PRIVATE (ShellScreenshot, shell_screenshot, G_TYPE_OBJECT);
|
||||
|
||||
static void
|
||||
@@ -222,29 +229,32 @@ do_grab_screenshot (ShellScreenshot *screenshot,
|
||||
int height)
|
||||
{
|
||||
ShellScreenshotPrivate *priv = screenshot->priv;
|
||||
cairo_rectangle_int_t screenshot_rect = { x, y, width, height };
|
||||
ClutterCapture *captures;
|
||||
int n_captures;
|
||||
int i;
|
||||
|
||||
clutter_stage_capture (stage, FALSE,
|
||||
&(cairo_rectangle_int_t) {
|
||||
.x = x,
|
||||
.y = y,
|
||||
.width = width,
|
||||
.height = height
|
||||
},
|
||||
&captures,
|
||||
&n_captures);
|
||||
|
||||
if (n_captures == 0)
|
||||
if (!clutter_stage_capture (stage, FALSE,
|
||||
&screenshot_rect,
|
||||
&captures,
|
||||
&n_captures))
|
||||
return;
|
||||
else if (n_captures == 1)
|
||||
|
||||
if (n_captures == 1)
|
||||
priv->image = cairo_surface_reference (captures[0].image);
|
||||
else
|
||||
priv->image = shell_util_composite_capture_images (captures,
|
||||
n_captures,
|
||||
x, y,
|
||||
width, height);
|
||||
{
|
||||
float target_scale;
|
||||
|
||||
clutter_stage_get_capture_final_size (stage, &screenshot_rect,
|
||||
&width, &height, &target_scale);
|
||||
priv->image = shell_util_composite_capture_images (captures,
|
||||
n_captures,
|
||||
x, y,
|
||||
width, height,
|
||||
target_scale);
|
||||
}
|
||||
|
||||
priv->datetime = g_date_time_new_now_local ();
|
||||
|
||||
for (i = 0; i < n_captures; i++)
|
||||
@@ -253,22 +263,41 @@ do_grab_screenshot (ShellScreenshot *screenshot,
|
||||
g_free (captures);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
should_draw_cursor_image (ShellScreenshotMode mode)
|
||||
{
|
||||
if (mode == SHELL_SCREENSHOT_WINDOW || !meta_is_wayland_compositor ())
|
||||
{
|
||||
g_autoptr (GSettings) settings = g_settings_new (A11Y_APPS_SCHEMA);
|
||||
|
||||
if (!g_settings_get_boolean (settings, MAGNIFIER_ACTIVE_KEY))
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
_draw_cursor_image (MetaCursorTracker *tracker,
|
||||
cairo_surface_t *surface,
|
||||
cairo_rectangle_int_t area)
|
||||
draw_cursor_image (cairo_surface_t *surface,
|
||||
cairo_rectangle_int_t area)
|
||||
{
|
||||
CoglTexture *texture;
|
||||
int width, height;
|
||||
int stride;
|
||||
guint8 *data;
|
||||
MetaDisplay *display;
|
||||
MetaCursorTracker *tracker;
|
||||
cairo_surface_t *cursor_surface;
|
||||
cairo_region_t *screenshot_region;
|
||||
cairo_t *cr;
|
||||
int x, y;
|
||||
int xhot, yhot;
|
||||
double xscale, yscale;
|
||||
|
||||
display = shell_global_get_display (shell_global_get ());
|
||||
tracker = meta_cursor_tracker_get_for_display (display);
|
||||
texture = meta_cursor_tracker_get_sprite (tracker);
|
||||
|
||||
if (!texture)
|
||||
return;
|
||||
|
||||
@@ -294,6 +323,22 @@ _draw_cursor_image (MetaCursorTracker *tracker,
|
||||
width, height,
|
||||
stride);
|
||||
|
||||
cairo_surface_get_device_scale (surface, &xscale, &yscale);
|
||||
|
||||
if (xscale != 1.0 || yscale != 1.0)
|
||||
{
|
||||
int monitor;
|
||||
float monitor_scale;
|
||||
MetaRectangle cursor_rect = {
|
||||
.x = x, .y = y, .width = width, .height = height
|
||||
};
|
||||
|
||||
monitor = meta_display_get_monitor_index_for_rect (display, &cursor_rect);
|
||||
monitor_scale = meta_display_get_monitor_scale (display, monitor);
|
||||
|
||||
cairo_surface_set_device_scale (cursor_surface, monitor_scale, monitor_scale);
|
||||
}
|
||||
|
||||
cr = cairo_create (surface);
|
||||
cairo_set_source_surface (cr,
|
||||
cursor_surface,
|
||||
@@ -312,9 +357,7 @@ grab_screenshot (ClutterActor *stage,
|
||||
GTask *result)
|
||||
{
|
||||
MetaDisplay *display;
|
||||
MetaCursorTracker *tracker;
|
||||
int width, height;
|
||||
GSettings *settings;
|
||||
ShellScreenshot *screenshot = g_task_get_source_object (result);
|
||||
ShellScreenshotPrivate *priv = screenshot->priv;
|
||||
GTask *task;
|
||||
@@ -368,14 +411,8 @@ grab_screenshot (ClutterActor *stage,
|
||||
priv->screenshot_area.width = width;
|
||||
priv->screenshot_area.height = height;
|
||||
|
||||
settings = g_settings_new (A11Y_APPS_SCHEMA);
|
||||
if (priv->include_cursor &&
|
||||
!g_settings_get_boolean (settings, MAGNIFIER_ACTIVE_KEY))
|
||||
{
|
||||
tracker = meta_cursor_tracker_get_for_display (display);
|
||||
_draw_cursor_image (tracker, priv->image, priv->screenshot_area);
|
||||
}
|
||||
g_object_unref (settings);
|
||||
if (priv->include_cursor)
|
||||
draw_cursor_image (priv->image, priv->screenshot_area);
|
||||
|
||||
g_signal_handlers_disconnect_by_func (stage, grab_screenshot, result);
|
||||
|
||||
@@ -412,9 +449,7 @@ grab_window_screenshot (ClutterActor *stage,
|
||||
ShellScreenshot *screenshot = g_task_get_source_object (result);
|
||||
ShellScreenshotPrivate *priv = screenshot->priv;
|
||||
GTask *task;
|
||||
GSettings *settings;
|
||||
MetaDisplay *display = shell_global_get_display (priv->global);
|
||||
MetaCursorTracker *tracker;
|
||||
MetaWindow *window = meta_display_get_focus_window (display);
|
||||
ClutterActor *window_actor;
|
||||
gfloat actor_x, actor_y;
|
||||
@@ -442,13 +477,19 @@ grab_window_screenshot (ClutterActor *stage,
|
||||
priv->image = meta_shaped_texture_get_image (stex, &clip);
|
||||
priv->datetime = g_date_time_new_now_local ();
|
||||
|
||||
settings = g_settings_new (A11Y_APPS_SCHEMA);
|
||||
if (priv->include_cursor && !g_settings_get_boolean (settings, MAGNIFIER_ACTIVE_KEY))
|
||||
if (priv->include_cursor)
|
||||
{
|
||||
tracker = meta_cursor_tracker_get_for_display (display);
|
||||
_draw_cursor_image (tracker, priv->image, priv->screenshot_area);
|
||||
if (meta_window_get_client_type (window) == META_WINDOW_CLIENT_TYPE_WAYLAND)
|
||||
{
|
||||
float resource_scale;
|
||||
if (!clutter_actor_get_resource_scale (window_actor, &resource_scale))
|
||||
resource_scale = 1.0f;
|
||||
|
||||
cairo_surface_set_device_scale (priv->image, resource_scale, resource_scale);
|
||||
}
|
||||
|
||||
draw_cursor_image (priv->image, priv->screenshot_area);
|
||||
}
|
||||
g_object_unref (settings);
|
||||
|
||||
g_signal_handlers_disconnect_by_func (stage, grab_window_screenshot, result);
|
||||
task = g_task_new (screenshot, NULL, on_screenshot_written, result);
|
||||
@@ -520,6 +561,7 @@ shell_screenshot_screenshot (ShellScreenshot *screenshot,
|
||||
{
|
||||
ClutterActor *stage;
|
||||
ShellScreenshotPrivate *priv = screenshot->priv;
|
||||
const char *paint_signal;
|
||||
GTask *result;
|
||||
|
||||
if (priv->filename != NULL) {
|
||||
@@ -539,13 +581,22 @@ shell_screenshot_screenshot (ShellScreenshot *screenshot,
|
||||
g_task_set_source_tag (result, shell_screenshot_screenshot);
|
||||
|
||||
priv->filename = g_strdup (filename);
|
||||
priv->include_cursor = include_cursor;
|
||||
priv->include_cursor = FALSE;
|
||||
|
||||
stage = CLUTTER_ACTOR (shell_global_get_stage (priv->global));
|
||||
paint_signal = "actors-painted";
|
||||
|
||||
meta_disable_unredirect_for_display (shell_global_get_display (priv->global));
|
||||
|
||||
g_signal_connect_after (stage, "paint", G_CALLBACK (grab_screenshot), result);
|
||||
if (include_cursor)
|
||||
{
|
||||
if (should_draw_cursor_image (SHELL_SCREENSHOT_SCREEN))
|
||||
priv->include_cursor = TRUE;
|
||||
else
|
||||
paint_signal = "paint";
|
||||
}
|
||||
|
||||
g_signal_connect_after (stage, paint_signal, G_CALLBACK (grab_screenshot), result);
|
||||
|
||||
clutter_actor_queue_redraw (stage);
|
||||
}
|
||||
@@ -634,7 +685,7 @@ shell_screenshot_screenshot_area (ShellScreenshot *screenshot,
|
||||
|
||||
meta_disable_unredirect_for_display (shell_global_get_display (shell_global_get ()));
|
||||
|
||||
g_signal_connect_after (stage, "paint", G_CALLBACK (grab_area_screenshot), result);
|
||||
g_signal_connect_after (stage, "actors-painted", G_CALLBACK (grab_area_screenshot), result);
|
||||
|
||||
clutter_actor_queue_redraw (stage);
|
||||
}
|
||||
@@ -713,13 +764,14 @@ shell_screenshot_screenshot_window (ShellScreenshot *screenshot,
|
||||
|
||||
priv->filename = g_strdup (filename);
|
||||
priv->include_frame = include_frame;
|
||||
priv->include_cursor = include_cursor;
|
||||
priv->include_cursor = include_cursor &&
|
||||
should_draw_cursor_image (SHELL_SCREENSHOT_WINDOW);
|
||||
|
||||
stage = CLUTTER_ACTOR (shell_global_get_stage (priv->global));
|
||||
|
||||
meta_disable_unredirect_for_display (shell_global_get_display (shell_global_get ()));
|
||||
|
||||
g_signal_connect_after (stage, "paint", G_CALLBACK (grab_window_screenshot), result);
|
||||
g_signal_connect_after (stage, "actors-painted", G_CALLBACK (grab_window_screenshot), result);
|
||||
|
||||
clutter_actor_queue_redraw (stage);
|
||||
}
|
||||
@@ -787,7 +839,7 @@ shell_screenshot_pick_color (ShellScreenshot *screenshot,
|
||||
|
||||
meta_disable_unredirect_for_display (display);
|
||||
|
||||
g_signal_connect_after (stage, "paint", G_CALLBACK (grab_pixel), result);
|
||||
g_signal_connect_after (stage, "actors-painted", G_CALLBACK (grab_pixel), result);
|
||||
|
||||
clutter_actor_queue_redraw (stage);
|
||||
}
|
||||
|
||||
@@ -77,13 +77,13 @@ shell_tray_icon_constructed (GObject *object)
|
||||
plug_xid = GDK_WINDOW_XID (icon_app_window);
|
||||
|
||||
display = gtk_widget_get_display (GTK_WIDGET (icon->priv->socket));
|
||||
gdk_error_trap_push ();
|
||||
gdk_x11_display_error_trap_push (display);
|
||||
_NET_WM_PID = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_PID");
|
||||
result = XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display), plug_xid,
|
||||
_NET_WM_PID, 0, G_MAXLONG, False, XA_CARDINAL,
|
||||
&type, &format, &nitems,
|
||||
&bytes_after, (guchar **)&val);
|
||||
if (!gdk_error_trap_pop () &&
|
||||
if (!gdk_x11_display_error_trap_pop (display) &&
|
||||
result == Success &&
|
||||
type == XA_CARDINAL &&
|
||||
nitems == 1)
|
||||
@@ -190,6 +190,7 @@ shell_tray_icon_click (ShellTrayIcon *icon,
|
||||
XKeyEvent xkevent;
|
||||
XButtonEvent xbevent;
|
||||
XCrossingEvent xcevent;
|
||||
GdkDisplay *display;
|
||||
GdkWindow *remote_window;
|
||||
GdkScreen *screen;
|
||||
int x_root, y_root;
|
||||
@@ -201,21 +202,23 @@ shell_tray_icon_click (ShellTrayIcon *icon,
|
||||
event_type == CLUTTER_KEY_PRESS ||
|
||||
event_type == CLUTTER_KEY_RELEASE);
|
||||
|
||||
gdk_error_trap_push ();
|
||||
|
||||
remote_window = gtk_socket_get_plug_window (GTK_SOCKET (icon->priv->socket));
|
||||
if (remote_window == NULL)
|
||||
{
|
||||
g_warning ("shell tray: plug window is gone");
|
||||
gdk_error_trap_pop_ignored ();
|
||||
return;
|
||||
}
|
||||
xwindow = GDK_WINDOW_XID (remote_window);
|
||||
xdisplay = GDK_WINDOW_XDISPLAY (remote_window);
|
||||
|
||||
display = gdk_x11_lookup_xdisplay (xdisplay);
|
||||
gdk_x11_display_error_trap_push (display);
|
||||
|
||||
xwindow = GDK_WINDOW_XID (remote_window);
|
||||
screen = gdk_window_get_screen (remote_window);
|
||||
xrootwindow = GDK_WINDOW_XID (gdk_screen_get_root_window (screen));
|
||||
gdk_window_get_origin (remote_window, &x_root, &y_root);
|
||||
|
||||
|
||||
/* First make the icon believe the pointer is inside it */
|
||||
xcevent.type = EnterNotify;
|
||||
xcevent.window = xwindow;
|
||||
@@ -287,5 +290,5 @@ shell_tray_icon_click (ShellTrayIcon *icon,
|
||||
xcevent.type = LeaveNotify;
|
||||
XSendEvent (xdisplay, xwindow, False, 0, (XEvent *)&xcevent);
|
||||
|
||||
gdk_error_trap_pop_ignored ();
|
||||
gdk_x11_display_error_trap_pop_ignored (display);
|
||||
}
|
||||
|
||||
@@ -212,13 +212,7 @@ void
|
||||
shell_tray_manager_manage_screen (ShellTrayManager *manager,
|
||||
StWidget *theme_widget)
|
||||
{
|
||||
GdkDisplay *display;
|
||||
GdkScreen *gdk_screen;
|
||||
|
||||
display = gdk_display_get_default ();
|
||||
gdk_screen = gdk_display_get_default_screen (display);
|
||||
|
||||
na_tray_manager_manage_screen (manager->priv->na_manager, gdk_screen);
|
||||
na_tray_manager_manage_screen (manager->priv->na_manager);
|
||||
|
||||
g_signal_connect_object (theme_widget, "style-changed",
|
||||
G_CALLBACK (shell_tray_manager_style_changed),
|
||||
@@ -245,8 +239,10 @@ shell_tray_manager_child_on_realize (GtkWidget *widget,
|
||||
bg_pattern = cairo_pattern_create_rgb (color.red / 255.,
|
||||
color.green / 255.,
|
||||
color.blue / 255.);
|
||||
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
|
||||
gdk_window_set_background_pattern (gtk_widget_get_window (widget),
|
||||
bg_pattern);
|
||||
G_GNUC_END_IGNORE_DEPRECATIONS
|
||||
|
||||
cairo_pattern_destroy (bg_pattern);
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include "config.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
@@ -434,14 +435,23 @@ shell_util_get_content_for_window_actor (MetaWindowActor *window_actor,
|
||||
cairo_surface_t *surface;
|
||||
cairo_rectangle_int_t clip;
|
||||
gfloat actor_x, actor_y;
|
||||
gfloat resource_scale;
|
||||
|
||||
texture = meta_window_actor_get_texture (window_actor);
|
||||
clutter_actor_get_position (CLUTTER_ACTOR (window_actor), &actor_x, &actor_y);
|
||||
|
||||
if (!clutter_actor_get_resource_scale (CLUTTER_ACTOR (window_actor),
|
||||
&resource_scale))
|
||||
{
|
||||
resource_scale = 1.0;
|
||||
g_warning ("Actor resource scale is not know at this point, "
|
||||
"falling back to default 1.0");
|
||||
}
|
||||
|
||||
clip.x = window_rect->x - (gint) actor_x;
|
||||
clip.y = window_rect->y - (gint) actor_y;
|
||||
clip.width = window_rect->width;
|
||||
clip.height = window_rect->height;
|
||||
clip.width = ceilf (window_rect->width * resource_scale);
|
||||
clip.height = ceilf (window_rect->height * resource_scale);
|
||||
|
||||
surface = meta_shaped_texture_get_image (META_SHAPED_TEXTURE (texture),
|
||||
&clip);
|
||||
@@ -462,31 +472,20 @@ shell_util_composite_capture_images (ClutterCapture *captures,
|
||||
int n_captures,
|
||||
int x,
|
||||
int y,
|
||||
int width,
|
||||
int height)
|
||||
int target_width,
|
||||
int target_height,
|
||||
float target_scale)
|
||||
{
|
||||
int i;
|
||||
double target_scale;
|
||||
cairo_format_t format;
|
||||
cairo_surface_t *image;
|
||||
cairo_t *cr;
|
||||
|
||||
g_assert (n_captures > 0);
|
||||
|
||||
target_scale = 0.0;
|
||||
for (i = 0; i < n_captures; i++)
|
||||
{
|
||||
ClutterCapture *capture = &captures[i];
|
||||
double capture_scale = 1.0;
|
||||
|
||||
cairo_surface_get_device_scale (capture->image, &capture_scale, NULL);
|
||||
target_scale = MAX (target_scale, capture_scale);
|
||||
}
|
||||
g_assert (target_scale > 0.0f);
|
||||
|
||||
format = cairo_image_surface_get_format (captures[0].image);
|
||||
image = cairo_image_surface_create (format,
|
||||
width * target_scale,
|
||||
height * target_scale);
|
||||
image = cairo_image_surface_create (format, target_width, target_height);
|
||||
cairo_surface_set_device_scale (image, target_scale, target_scale);
|
||||
|
||||
cr = cairo_create (image);
|
||||
|
||||
@@ -53,8 +53,9 @@ cairo_surface_t * shell_util_composite_capture_images (ClutterCapture *captures
|
||||
int n_captures,
|
||||
int x,
|
||||
int y,
|
||||
int width,
|
||||
int height);
|
||||
int target_width,
|
||||
int target_height,
|
||||
float target_scale);
|
||||
|
||||
void shell_util_check_cloexec_fds (void);
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ st_headers = [
|
||||
'st-generic-accessible.h',
|
||||
'st-icon.h',
|
||||
'st-icon-colors.h',
|
||||
'st-image-content.h',
|
||||
'st-label.h',
|
||||
'st-private.h',
|
||||
'st-scrollable.h',
|
||||
@@ -66,6 +67,7 @@ st_sources = [
|
||||
'st-generic-accessible.c',
|
||||
'st-icon.c',
|
||||
'st-icon-colors.c',
|
||||
'st-image-content.c',
|
||||
'st-label.c',
|
||||
'st-private.c',
|
||||
'st-scrollable.c',
|
||||
@@ -124,6 +126,7 @@ libst = shared_library('st-1.0',
|
||||
sources: st_gir_sources + st_non_gir_sources,
|
||||
c_args: st_cflags,
|
||||
dependencies: [clutter_dep, gtk_dep, croco_dep, x11_dep, m_dep],
|
||||
build_rpath: mutter_typelibdir,
|
||||
install_rpath: mutter_typelibdir,
|
||||
install_dir: pkglibdir,
|
||||
install: true
|
||||
@@ -137,9 +140,14 @@ test_theme = executable('test-theme',
|
||||
sources: 'test-theme.c',
|
||||
c_args: st_cflags,
|
||||
dependencies: [clutter_dep, gtk_dep],
|
||||
build_rpath: mutter_typelibdir,
|
||||
link_with: libst
|
||||
)
|
||||
|
||||
test('CSS styling support', test_theme,
|
||||
workdir: meson.current_source_dir()
|
||||
)
|
||||
|
||||
libst_gir = gnome.generate_gir(libst,
|
||||
sources: st_gir_sources,
|
||||
nsversion: '1.0',
|
||||
|
||||
@@ -58,32 +58,6 @@ static Atom __atom_clip = None;
|
||||
static Atom __utf8_string = None;
|
||||
static Atom __atom_targets = None;
|
||||
|
||||
static void
|
||||
st_clipboard_get_property (GObject *object,
|
||||
guint property_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
switch (property_id)
|
||||
{
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
st_clipboard_set_property (GObject *object,
|
||||
guint property_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
switch (property_id)
|
||||
{
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
st_clipboard_dispose (GObject *object)
|
||||
{
|
||||
@@ -180,8 +154,6 @@ st_clipboard_class_init (StClipboardClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
object_class->get_property = st_clipboard_get_property;
|
||||
object_class->set_property = st_clipboard_set_property;
|
||||
object_class->dispose = st_clipboard_dispose;
|
||||
object_class->finalize = st_clipboard_finalize;
|
||||
}
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
#include "st-drawing-area.h"
|
||||
|
||||
#include <cairo.h>
|
||||
#include <math.h>
|
||||
|
||||
typedef struct _StDrawingAreaPrivate StDrawingAreaPrivate;
|
||||
struct _StDrawingAreaPrivate {
|
||||
@@ -84,12 +85,22 @@ st_drawing_area_allocate (ClutterActor *self,
|
||||
ClutterContent *content = clutter_actor_get_content (self);
|
||||
ClutterActorBox content_box;
|
||||
int width, height;
|
||||
float resource_scale;
|
||||
|
||||
if (!st_widget_get_resource_scale (ST_WIDGET (self), &resource_scale))
|
||||
{
|
||||
ClutterActorBox empty = CLUTTER_ACTOR_BOX_INIT_ZERO;
|
||||
clutter_actor_set_allocation (self, &empty, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
clutter_actor_set_allocation (self, box, flags);
|
||||
st_theme_node_get_content_box (theme_node, box, &content_box);
|
||||
|
||||
width = (int)(0.5 + content_box.x2 - content_box.x1);
|
||||
height = (int)(0.5 + content_box.y2 - content_box.y1);
|
||||
|
||||
clutter_canvas_set_scale_factor (CLUTTER_CANVAS (content), resource_scale);
|
||||
clutter_canvas_set_size (CLUTTER_CANVAS (content), width, height);
|
||||
}
|
||||
|
||||
@@ -101,6 +112,16 @@ st_drawing_area_style_changed (StWidget *self)
|
||||
st_drawing_area_queue_repaint (ST_DRAWING_AREA (self));
|
||||
}
|
||||
|
||||
static void
|
||||
st_drawing_area_resource_scale_changed (StWidget *self)
|
||||
{
|
||||
float resource_scale;
|
||||
ClutterContent *content = clutter_actor_get_content (CLUTTER_ACTOR (self));
|
||||
|
||||
if (st_widget_get_resource_scale (ST_WIDGET (self), &resource_scale))
|
||||
clutter_canvas_set_scale_factor (CLUTTER_CANVAS (content), resource_scale);
|
||||
}
|
||||
|
||||
static void
|
||||
st_drawing_area_class_init (StDrawingAreaClass *klass)
|
||||
{
|
||||
@@ -109,6 +130,7 @@ st_drawing_area_class_init (StDrawingAreaClass *klass)
|
||||
|
||||
actor_class->allocate = st_drawing_area_allocate;
|
||||
widget_class->style_changed = st_drawing_area_style_changed;
|
||||
widget_class->resource_scale_changed = st_drawing_area_resource_scale_changed;
|
||||
|
||||
st_drawing_area_signals[REPAINT] =
|
||||
g_signal_new ("repaint",
|
||||
@@ -185,7 +207,7 @@ st_drawing_area_get_surface_size (StDrawingArea *area,
|
||||
{
|
||||
StDrawingAreaPrivate *priv;
|
||||
ClutterContent *content;
|
||||
float w, h;
|
||||
float w, h, resource_scale;
|
||||
|
||||
g_return_if_fail (ST_IS_DRAWING_AREA (area));
|
||||
|
||||
@@ -195,8 +217,18 @@ st_drawing_area_get_surface_size (StDrawingArea *area,
|
||||
content = clutter_actor_get_content (CLUTTER_ACTOR (area));
|
||||
clutter_content_get_preferred_size (content, &w, &h);
|
||||
|
||||
if (st_widget_get_resource_scale (ST_WIDGET (area), &resource_scale))
|
||||
{
|
||||
w /= resource_scale;
|
||||
h /= resource_scale;
|
||||
}
|
||||
else
|
||||
{
|
||||
w = h = 0.0f;
|
||||
}
|
||||
|
||||
if (width)
|
||||
*width = (guint)w;
|
||||
*width = ceilf (w);
|
||||
if (height)
|
||||
*height = (guint)h;
|
||||
*height = ceilf (h);
|
||||
}
|
||||
|
||||
@@ -210,6 +210,12 @@ st_icon_style_changed (StWidget *widget)
|
||||
st_icon_update (self);
|
||||
}
|
||||
|
||||
static void
|
||||
st_icon_resource_scale_changed (StWidget *widget)
|
||||
{
|
||||
st_icon_update (ST_ICON (widget));
|
||||
}
|
||||
|
||||
static void
|
||||
st_icon_class_init (StIconClass *klass)
|
||||
{
|
||||
@@ -226,6 +232,7 @@ st_icon_class_init (StIconClass *klass)
|
||||
actor_class->paint = st_icon_paint;
|
||||
|
||||
widget_class->style_changed = st_icon_style_changed;
|
||||
widget_class->resource_scale_changed = st_icon_resource_scale_changed;
|
||||
|
||||
pspec = g_param_spec_object ("gicon",
|
||||
"GIcon",
|
||||
@@ -344,6 +351,8 @@ st_icon_finish_update (StIcon *icon)
|
||||
g_signal_connect_object (priv->icon_texture, "notify::content",
|
||||
G_CALLBACK (on_content_changed), icon, 0);
|
||||
}
|
||||
|
||||
clutter_actor_queue_relayout (CLUTTER_ACTOR (icon));
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -366,9 +375,10 @@ st_icon_update (StIcon *icon)
|
||||
StIconPrivate *priv = icon->priv;
|
||||
StThemeNode *theme_node;
|
||||
StTextureCache *cache;
|
||||
gint scale;
|
||||
gint paint_scale;
|
||||
ClutterActor *stage;
|
||||
StThemeContext *context;
|
||||
float resource_scale;
|
||||
|
||||
if (priv->pending_texture)
|
||||
{
|
||||
@@ -378,13 +388,16 @@ st_icon_update (StIcon *icon)
|
||||
priv->opacity_handler_id = 0;
|
||||
}
|
||||
|
||||
if (!st_widget_get_resource_scale (ST_WIDGET (icon), &resource_scale))
|
||||
return;
|
||||
|
||||
theme_node = st_widget_peek_theme_node (ST_WIDGET (icon));
|
||||
if (theme_node == NULL)
|
||||
return;
|
||||
|
||||
stage = clutter_actor_get_stage (CLUTTER_ACTOR (icon));
|
||||
context = st_theme_context_get_for_stage (CLUTTER_STAGE (stage));
|
||||
g_object_get (context, "scale-factor", &scale, NULL);
|
||||
g_object_get (context, "scale-factor", &paint_scale, NULL);
|
||||
|
||||
cache = st_texture_cache_get_default ();
|
||||
|
||||
@@ -393,14 +406,16 @@ st_icon_update (StIcon *icon)
|
||||
theme_node,
|
||||
priv->gicon,
|
||||
priv->icon_size,
|
||||
scale);
|
||||
paint_scale,
|
||||
resource_scale);
|
||||
|
||||
if (priv->pending_texture == NULL && priv->fallback_gicon != NULL)
|
||||
priv->pending_texture = st_texture_cache_load_gicon (cache,
|
||||
theme_node,
|
||||
priv->fallback_gicon,
|
||||
priv->icon_size,
|
||||
scale);
|
||||
paint_scale,
|
||||
resource_scale);
|
||||
|
||||
if (priv->pending_texture)
|
||||
{
|
||||
|
||||
191
src/st/st-image-content.c
Normal file
191
src/st/st-image-content.c
Normal file
@@ -0,0 +1,191 @@
|
||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
||||
/*
|
||||
* st-image-content.h: A content image with scaling support
|
||||
*
|
||||
* Copyright 2019 Canonical, Ltd
|
||||
*
|
||||
* 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 2.1 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT ANY
|
||||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "st-image-content.h"
|
||||
|
||||
struct _StImageContent
|
||||
{
|
||||
/*< private >*/
|
||||
ClutterImage parent_instance;
|
||||
};
|
||||
|
||||
typedef struct _StImageContentPrivate StImageContentPrivate;
|
||||
struct _StImageContentPrivate
|
||||
{
|
||||
int width;
|
||||
int height;
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
PROP_PREFERRED_WIDTH,
|
||||
PROP_PREFERRED_HEIGHT,
|
||||
};
|
||||
|
||||
static void clutter_content_interface_init (ClutterContentInterface *iface);
|
||||
|
||||
G_DEFINE_TYPE_WITH_CODE (StImageContent, st_image_content, CLUTTER_TYPE_IMAGE,
|
||||
G_ADD_PRIVATE (StImageContent)
|
||||
G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_CONTENT,
|
||||
clutter_content_interface_init))
|
||||
|
||||
static void
|
||||
st_image_content_init (StImageContent *self)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
st_image_content_constructed (GObject *object)
|
||||
{
|
||||
StImageContent *self = ST_IMAGE_CONTENT (object);
|
||||
StImageContentPrivate *priv = st_image_content_get_instance_private (self);
|
||||
|
||||
if (priv->width < 0 || priv->height < 0)
|
||||
g_warning ("StImageContent initialized with invalid preferred size: %dx%d\n",
|
||||
priv->width, priv->height);
|
||||
}
|
||||
|
||||
static void
|
||||
st_image_content_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
StImageContent *self = ST_IMAGE_CONTENT (object);
|
||||
StImageContentPrivate *priv = st_image_content_get_instance_private (self);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_PREFERRED_WIDTH:
|
||||
g_value_set_int (value, priv->width);
|
||||
break;
|
||||
|
||||
case PROP_PREFERRED_HEIGHT:
|
||||
g_value_set_int (value, priv->height);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
st_image_content_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
StImageContent *self = ST_IMAGE_CONTENT (object);
|
||||
StImageContentPrivate *priv = st_image_content_get_instance_private (self);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_PREFERRED_WIDTH:
|
||||
priv->width = g_value_get_int (value);
|
||||
break;
|
||||
|
||||
case PROP_PREFERRED_HEIGHT:
|
||||
priv->height = g_value_get_int (value);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
st_image_content_class_init (StImageContentClass *klass)
|
||||
{
|
||||
GParamSpec *pspec;
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
object_class->constructed = st_image_content_constructed;
|
||||
object_class->get_property = st_image_content_get_property;
|
||||
object_class->set_property = st_image_content_set_property;
|
||||
|
||||
pspec = g_param_spec_int ("preferred-width",
|
||||
"Preferred Width",
|
||||
"Preferred Width of the Content when painted",
|
||||
-1, G_MAXINT, -1,
|
||||
G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE);
|
||||
g_object_class_install_property (object_class, PROP_PREFERRED_WIDTH, pspec);
|
||||
|
||||
pspec = g_param_spec_int ("preferred-height",
|
||||
"Preferred Height",
|
||||
"Preferred Height of the Content when painted",
|
||||
-1, G_MAXINT, -1,
|
||||
G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE);
|
||||
g_object_class_install_property (object_class, PROP_PREFERRED_HEIGHT, pspec);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
st_image_content_get_preferred_size (ClutterContent *content,
|
||||
float *width,
|
||||
float *height)
|
||||
{
|
||||
StImageContent *self = ST_IMAGE_CONTENT (content);
|
||||
StImageContentPrivate *priv = st_image_content_get_instance_private (self);
|
||||
ClutterTexture *texture;
|
||||
|
||||
texture = clutter_image_get_texture (CLUTTER_IMAGE (content));
|
||||
|
||||
if (texture == NULL)
|
||||
return FALSE;
|
||||
|
||||
g_assert_cmpint (priv->width, >, -1);
|
||||
g_assert_cmpint (priv->height, >, -1);
|
||||
|
||||
if (width != NULL)
|
||||
*width = (float) priv->width;
|
||||
|
||||
if (height != NULL)
|
||||
*height = (float) priv->height;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
clutter_content_interface_init (ClutterContentInterface *iface)
|
||||
{
|
||||
iface->get_preferred_size = st_image_content_get_preferred_size;
|
||||
}
|
||||
|
||||
/**
|
||||
* st_image_content_new_with_preferred_size:
|
||||
* @width: The preferred width to be used when drawing the content
|
||||
* @height: The preferred width to be used when drawing the content
|
||||
*
|
||||
* Creates a new #StImageContent, a simple content for sized images.
|
||||
*
|
||||
* Return value: (transfer full): the newly created #StImageContent content
|
||||
* Use g_object_unref() when done.
|
||||
*/
|
||||
ClutterContent *
|
||||
st_image_content_new_with_preferred_size (int width,
|
||||
int height)
|
||||
{
|
||||
return g_object_new (ST_TYPE_IMAGE_CONTENT,
|
||||
"preferred-width", width,
|
||||
"preferred-height", height,
|
||||
NULL);
|
||||
}
|
||||
33
src/st/st-image-content.h
Normal file
33
src/st/st-image-content.h
Normal file
@@ -0,0 +1,33 @@
|
||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
||||
/*
|
||||
* st-image-content.h: A content image with scaling support
|
||||
*
|
||||
* Copyright 2019 Canonical, Ltd
|
||||
*
|
||||
* 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 2.1 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT ANY
|
||||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __ST_IMAGE_CONTENT_H__
|
||||
#define __ST_IMAGE_CONTENT_H__
|
||||
|
||||
#include <clutter/clutter.h>
|
||||
|
||||
#define ST_TYPE_IMAGE_CONTENT (st_image_content_get_type ())
|
||||
G_DECLARE_FINAL_TYPE (StImageContent, st_image_content,
|
||||
ST, IMAGE_CONTENT, ClutterImage)
|
||||
|
||||
ClutterContent *st_image_content_new_with_preferred_size (int width,
|
||||
int height);
|
||||
|
||||
#endif /* __ST_IMAGE_CONTENT_H__ */
|
||||
@@ -197,34 +197,52 @@ st_label_paint (ClutterActor *actor)
|
||||
|
||||
if (shadow_spec)
|
||||
{
|
||||
ClutterActorBox allocation;
|
||||
float width, height;
|
||||
float resource_scale;
|
||||
|
||||
clutter_actor_get_allocation_box (priv->label, &allocation);
|
||||
clutter_actor_box_get_size (&allocation, &width, &height);
|
||||
|
||||
if (priv->text_shadow_pipeline == NULL ||
|
||||
width != priv->shadow_width ||
|
||||
height != priv->shadow_height)
|
||||
if (clutter_actor_get_resource_scale (priv->label, &resource_scale))
|
||||
{
|
||||
g_clear_pointer (&priv->text_shadow_pipeline, cogl_object_unref);
|
||||
ClutterActorBox allocation;
|
||||
float width, height;
|
||||
|
||||
priv->shadow_width = width;
|
||||
priv->shadow_height = height;
|
||||
priv->text_shadow_pipeline = _st_create_shadow_pipeline_from_actor (shadow_spec, priv->label);
|
||||
clutter_actor_get_allocation_box (priv->label, &allocation);
|
||||
clutter_actor_box_get_size (&allocation, &width, &height);
|
||||
|
||||
width *= resource_scale;
|
||||
height *= resource_scale;
|
||||
|
||||
if (priv->text_shadow_pipeline == NULL ||
|
||||
width != priv->shadow_width ||
|
||||
height != priv->shadow_height)
|
||||
{
|
||||
g_clear_pointer (&priv->text_shadow_pipeline, cogl_object_unref);
|
||||
|
||||
priv->shadow_width = width;
|
||||
priv->shadow_height = height;
|
||||
priv->text_shadow_pipeline =
|
||||
_st_create_shadow_pipeline_from_actor (shadow_spec,
|
||||
priv->label);
|
||||
}
|
||||
|
||||
if (priv->text_shadow_pipeline != NULL)
|
||||
_st_paint_shadow_with_opacity (shadow_spec,
|
||||
cogl_get_draw_framebuffer (),
|
||||
priv->text_shadow_pipeline,
|
||||
&allocation,
|
||||
clutter_actor_get_paint_opacity (priv->label));
|
||||
}
|
||||
|
||||
if (priv->text_shadow_pipeline != NULL)
|
||||
_st_paint_shadow_with_opacity (shadow_spec,
|
||||
cogl_get_draw_framebuffer (),
|
||||
priv->text_shadow_pipeline,
|
||||
&allocation,
|
||||
clutter_actor_get_paint_opacity (priv->label));
|
||||
}
|
||||
|
||||
clutter_actor_paint (priv->label);
|
||||
}
|
||||
|
||||
static void
|
||||
st_label_resource_scale_changed (StWidget *widget)
|
||||
{
|
||||
StLabelPrivate *priv = ST_LABEL (widget)->priv;
|
||||
|
||||
g_clear_pointer (&priv->text_shadow_pipeline, cogl_object_unref);
|
||||
}
|
||||
|
||||
static void
|
||||
st_label_class_init (StLabelClass *klass)
|
||||
{
|
||||
@@ -243,6 +261,7 @@ st_label_class_init (StLabelClass *klass)
|
||||
actor_class->get_preferred_height = st_label_get_preferred_height;
|
||||
|
||||
widget_class->style_changed = st_label_style_changed;
|
||||
widget_class->resource_scale_changed = st_label_resource_scale_changed;
|
||||
widget_class->get_accessible_type = st_label_accessible_get_type;
|
||||
|
||||
pspec = g_param_spec_object ("clutter-text",
|
||||
|
||||
@@ -359,7 +359,8 @@ blur_pixels (guchar *pixels_in,
|
||||
|
||||
CoglPipeline *
|
||||
_st_create_shadow_pipeline (StShadow *shadow_spec,
|
||||
CoglTexture *src_texture)
|
||||
CoglTexture *src_texture,
|
||||
float resource_scale)
|
||||
{
|
||||
ClutterBackend *backend = clutter_get_default_backend ();
|
||||
CoglContext *ctx = clutter_backend_get_cogl_context (backend);
|
||||
@@ -386,7 +387,7 @@ _st_create_shadow_pipeline (StShadow *shadow_spec,
|
||||
rowstride_in, pixels_in);
|
||||
|
||||
pixels_out = blur_pixels (pixels_in, width_in, height_in, rowstride_in,
|
||||
shadow_spec->blur,
|
||||
shadow_spec->blur * resource_scale,
|
||||
&width_out, &height_out, &rowstride_out);
|
||||
g_free (pixels_in);
|
||||
|
||||
@@ -431,6 +432,7 @@ _st_create_shadow_pipeline_from_actor (StShadow *shadow_spec,
|
||||
{
|
||||
ClutterContent *image = NULL;
|
||||
CoglPipeline *shadow_pipeline = NULL;
|
||||
float resource_scale;
|
||||
float width, height;
|
||||
|
||||
g_return_val_if_fail (clutter_actor_has_allocation (actor), NULL);
|
||||
@@ -440,6 +442,12 @@ _st_create_shadow_pipeline_from_actor (StShadow *shadow_spec,
|
||||
if (width == 0 || height == 0)
|
||||
return NULL;
|
||||
|
||||
if (!clutter_actor_get_resource_scale (actor, &resource_scale))
|
||||
return NULL;
|
||||
|
||||
width = ceilf (width * resource_scale);
|
||||
height = ceilf (height * resource_scale);
|
||||
|
||||
image = clutter_actor_get_content (actor);
|
||||
if (image && CLUTTER_IS_IMAGE (image))
|
||||
{
|
||||
@@ -449,7 +457,8 @@ _st_create_shadow_pipeline_from_actor (StShadow *shadow_spec,
|
||||
if (texture &&
|
||||
cogl_texture_get_width (texture) == width &&
|
||||
cogl_texture_get_height (texture) == height)
|
||||
shadow_pipeline = _st_create_shadow_pipeline (shadow_spec, texture);
|
||||
shadow_pipeline = _st_create_shadow_pipeline (shadow_spec, texture,
|
||||
resource_scale);
|
||||
}
|
||||
|
||||
if (shadow_pipeline == NULL)
|
||||
@@ -491,6 +500,7 @@ _st_create_shadow_pipeline_from_actor (StShadow *shadow_spec,
|
||||
cogl_framebuffer_clear (fb, COGL_BUFFER_BIT_COLOR, &clear_color);
|
||||
cogl_framebuffer_translate (fb, -x, -y, 0);
|
||||
cogl_framebuffer_orthographic (fb, 0, 0, width, height, 0, 1.0);
|
||||
cogl_framebuffer_scale (fb, resource_scale, resource_scale, 1);
|
||||
|
||||
clutter_actor_set_opacity_override (actor, 255);
|
||||
clutter_actor_paint (actor);
|
||||
@@ -502,7 +512,8 @@ _st_create_shadow_pipeline_from_actor (StShadow *shadow_spec,
|
||||
|
||||
cogl_object_unref (fb);
|
||||
|
||||
shadow_pipeline = _st_create_shadow_pipeline (shadow_spec, buffer);
|
||||
shadow_pipeline = _st_create_shadow_pipeline (shadow_spec, buffer,
|
||||
resource_scale);
|
||||
|
||||
cogl_object_unref (buffer);
|
||||
}
|
||||
@@ -528,9 +539,10 @@ _st_create_shadow_pipeline_from_actor (StShadow *shadow_spec,
|
||||
* the offset.
|
||||
*/
|
||||
cairo_pattern_t *
|
||||
_st_create_shadow_cairo_pattern (StShadow *shadow_spec,
|
||||
_st_create_shadow_cairo_pattern (StShadow *shadow_spec_in,
|
||||
cairo_pattern_t *src_pattern)
|
||||
{
|
||||
g_autoptr(StShadow) shadow_spec = NULL;
|
||||
static cairo_user_data_key_t shadow_pattern_user_data;
|
||||
cairo_t *cr;
|
||||
cairo_surface_t *src_surface;
|
||||
@@ -541,9 +553,10 @@ _st_create_shadow_cairo_pattern (StShadow *shadow_spec,
|
||||
gint width_in, height_in, rowstride_in;
|
||||
gint width_out, height_out, rowstride_out;
|
||||
cairo_matrix_t shadow_matrix;
|
||||
double xscale_in, yscale_in;
|
||||
int i, j;
|
||||
|
||||
g_return_val_if_fail (shadow_spec != NULL, NULL);
|
||||
g_return_val_if_fail (shadow_spec_in != NULL, NULL);
|
||||
g_return_val_if_fail (src_pattern != NULL, NULL);
|
||||
|
||||
if (cairo_pattern_get_surface (src_pattern, &src_surface) != CAIRO_STATUS_SUCCESS)
|
||||
@@ -556,6 +569,25 @@ _st_create_shadow_cairo_pattern (StShadow *shadow_spec,
|
||||
width_in = cairo_image_surface_get_width (src_surface);
|
||||
height_in = cairo_image_surface_get_height (src_surface);
|
||||
|
||||
cairo_surface_get_device_scale (src_surface, &xscale_in, &yscale_in);
|
||||
|
||||
if (xscale_in != 1.0 || yscale_in != 1.0)
|
||||
{
|
||||
/* Scale the shadow specifications in a temporary copy so that
|
||||
* we can work everywhere in absolute surface coordinates */
|
||||
double scale = (xscale_in + yscale_in) / 2.0;
|
||||
shadow_spec = st_shadow_new (&shadow_spec_in->color,
|
||||
shadow_spec_in->xoffset * xscale_in,
|
||||
shadow_spec_in->yoffset * yscale_in,
|
||||
shadow_spec_in->blur * scale,
|
||||
shadow_spec_in->spread * scale,
|
||||
shadow_spec_in->inset);
|
||||
}
|
||||
else
|
||||
{
|
||||
shadow_spec = st_shadow_ref (shadow_spec_in);
|
||||
}
|
||||
|
||||
/* We want the output to be a color agnostic alpha mask,
|
||||
* so we need to strip the color channels from the input
|
||||
*/
|
||||
@@ -598,6 +630,7 @@ _st_create_shadow_cairo_pattern (StShadow *shadow_spec,
|
||||
width_out,
|
||||
height_out,
|
||||
rowstride_out);
|
||||
cairo_surface_set_device_scale (surface_out, xscale_in, yscale_in);
|
||||
cairo_surface_set_user_data (surface_out, &shadow_pattern_user_data,
|
||||
pixels_out, (cairo_destroy_func_t) g_free);
|
||||
|
||||
@@ -608,6 +641,9 @@ _st_create_shadow_cairo_pattern (StShadow *shadow_spec,
|
||||
|
||||
if (shadow_spec->inset)
|
||||
{
|
||||
/* Scale the matrix in surface absolute coordinates */
|
||||
cairo_matrix_scale (&shadow_matrix, 1.0 / xscale_in, 1.0 / yscale_in);
|
||||
|
||||
/* For inset shadows, offsets and spread radius have already been
|
||||
* applied to the original pattern, so all left to do is shift the
|
||||
* blurred image left, so that it aligns centered under the
|
||||
@@ -616,6 +652,10 @@ _st_create_shadow_cairo_pattern (StShadow *shadow_spec,
|
||||
cairo_matrix_translate (&shadow_matrix,
|
||||
(width_out - width_in) / 2.0,
|
||||
(height_out - height_in) / 2.0);
|
||||
|
||||
/* Scale back the matrix in original coordinates */
|
||||
cairo_matrix_scale (&shadow_matrix, xscale_in, yscale_in);
|
||||
|
||||
cairo_pattern_set_matrix (dst_pattern, &shadow_matrix);
|
||||
return dst_pattern;
|
||||
}
|
||||
@@ -628,6 +668,9 @@ _st_create_shadow_cairo_pattern (StShadow *shadow_spec,
|
||||
/* 6. Invert the matrix back */
|
||||
cairo_matrix_invert (&shadow_matrix);
|
||||
|
||||
/* Scale the matrix in surface absolute coordinates */
|
||||
cairo_matrix_scale (&shadow_matrix, 1.0 / xscale_in, 1.0 / yscale_in);
|
||||
|
||||
/* 5. Adjust based on specified offsets */
|
||||
cairo_matrix_translate (&shadow_matrix,
|
||||
shadow_spec->xoffset,
|
||||
@@ -649,6 +692,9 @@ _st_create_shadow_cairo_pattern (StShadow *shadow_spec,
|
||||
- (width_out - width_in) / 2.0,
|
||||
- (height_out - height_in) / 2.0);
|
||||
|
||||
/* Scale back the matrix in scaled coordinates */
|
||||
cairo_matrix_scale (&shadow_matrix, xscale_in, yscale_in);
|
||||
|
||||
/* 1. Invert the matrix so we can work with it in pattern space
|
||||
*/
|
||||
cairo_matrix_invert (&shadow_matrix);
|
||||
|
||||
@@ -63,7 +63,8 @@ CoglPipeline * _st_create_texture_pipeline (CoglTexture *src_texture);
|
||||
|
||||
/* Helper for widgets which need to draw additional shadows */
|
||||
CoglPipeline * _st_create_shadow_pipeline (StShadow *shadow_spec,
|
||||
CoglTexture *src_texture);
|
||||
CoglTexture *src_texture,
|
||||
float resource_scale);
|
||||
CoglPipeline * _st_create_shadow_pipeline_from_actor (StShadow *shadow_spec,
|
||||
ClutterActor *actor);
|
||||
cairo_pattern_t *_st_create_shadow_cairo_pattern (StShadow *shadow_spec,
|
||||
|
||||
@@ -110,8 +110,8 @@ st_scroll_view_fade_paint_target (ClutterOffscreenEffect *effect)
|
||||
*/
|
||||
fade_area_topleft[0] = content_box.x1 + (verts[0].x - paint_box.x1);
|
||||
fade_area_topleft[1] = content_box.y1 + (verts[0].y - paint_box.y1);
|
||||
fade_area_bottomright[0] = content_box.x2 + (verts[3].x - paint_box.x2);
|
||||
fade_area_bottomright[1] = content_box.y2 + (verts[3].y - paint_box.y2);
|
||||
fade_area_bottomright[0] = content_box.x2 + (verts[3].x - paint_box.x2) + 1;
|
||||
fade_area_bottomright[1] = content_box.y2 + (verts[3].y - paint_box.y2) + 1;
|
||||
|
||||
g_object_get (ST_SCROLL_VIEW (self->actor),
|
||||
"hscrollbar-visible", &h_scroll_visible,
|
||||
|
||||
@@ -72,6 +72,8 @@ void st_shadow_get_box (StShadow *shadow,
|
||||
const ClutterActorBox *actor_box,
|
||||
ClutterActorBox *shadow_box);
|
||||
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC (StShadow, st_shadow_unref)
|
||||
|
||||
|
||||
GType st_shadow_helper_get_type (void) G_GNUC_CONST;
|
||||
|
||||
|
||||
@@ -21,10 +21,12 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "st-image-content.h"
|
||||
#include "st-texture-cache.h"
|
||||
#include "st-private.h"
|
||||
#include "st-settings.h"
|
||||
#include <gtk/gtk.h>
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
#include <glib.h>
|
||||
|
||||
@@ -284,7 +286,8 @@ typedef struct {
|
||||
|
||||
guint width;
|
||||
guint height;
|
||||
guint scale;
|
||||
guint paint_scale;
|
||||
gfloat resource_scale;
|
||||
GSList *actors;
|
||||
|
||||
GtkIconInfo *icon_info;
|
||||
@@ -312,7 +315,7 @@ texture_load_data_free (gpointer p)
|
||||
if (data->actors)
|
||||
g_slist_free_full (data->actors, (GDestroyNotify) g_object_unref);
|
||||
|
||||
g_free (data);
|
||||
g_slice_free (AsyncTextureLoadData, data);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -430,7 +433,8 @@ static GdkPixbuf *
|
||||
impl_load_pixbuf_file (GFile *file,
|
||||
int available_width,
|
||||
int available_height,
|
||||
int scale,
|
||||
int paint_scale,
|
||||
float resource_scale,
|
||||
GError **error)
|
||||
{
|
||||
GdkPixbuf *pixbuf = NULL;
|
||||
@@ -439,6 +443,7 @@ impl_load_pixbuf_file (GFile *file,
|
||||
|
||||
if (g_file_load_contents (file, NULL, &contents, &size, NULL, error))
|
||||
{
|
||||
int scale = ceilf (paint_scale * resource_scale);
|
||||
pixbuf = impl_load_pixbuf_data ((const guchar *) contents, size,
|
||||
available_width, available_height,
|
||||
scale,
|
||||
@@ -463,7 +468,9 @@ load_pixbuf_thread (GTask *result,
|
||||
g_assert (data != NULL);
|
||||
g_assert (data->file != NULL);
|
||||
|
||||
pixbuf = impl_load_pixbuf_file (data->file, data->width, data->height, data->scale, &error);
|
||||
pixbuf = impl_load_pixbuf_file (data->file, data->width, data->height,
|
||||
data->paint_scale, data->resource_scale,
|
||||
&error);
|
||||
|
||||
if (error != NULL)
|
||||
g_task_return_error (result, error);
|
||||
@@ -480,12 +487,26 @@ load_pixbuf_async_finish (StTextureCache *cache, GAsyncResult *result, GError **
|
||||
}
|
||||
|
||||
static ClutterContent *
|
||||
pixbuf_to_clutter_image (GdkPixbuf *pixbuf)
|
||||
pixbuf_to_st_content_image (GdkPixbuf *pixbuf,
|
||||
int width,
|
||||
int height,
|
||||
int paint_scale,
|
||||
float resource_scale)
|
||||
{
|
||||
ClutterContent *image;
|
||||
g_autoptr(GError) error = NULL;
|
||||
|
||||
image = clutter_image_new ();
|
||||
if (width < 0)
|
||||
width = ceilf (gdk_pixbuf_get_width (pixbuf) / resource_scale);
|
||||
else
|
||||
width *= paint_scale;
|
||||
|
||||
if (height < 0)
|
||||
height = ceilf (gdk_pixbuf_get_height (pixbuf) / resource_scale);
|
||||
else
|
||||
height *= paint_scale;
|
||||
|
||||
image = st_image_content_new_with_preferred_size (width, height);
|
||||
clutter_image_set_data (CLUTTER_IMAGE (image),
|
||||
gdk_pixbuf_get_pixels (pixbuf),
|
||||
gdk_pixbuf_get_has_alpha (pixbuf) ?
|
||||
@@ -547,7 +568,10 @@ finish_texture_load (AsyncTextureLoadData *data,
|
||||
if (!g_hash_table_lookup_extended (cache->priv->keyed_cache, data->key,
|
||||
&orig_key, &value))
|
||||
{
|
||||
image = pixbuf_to_clutter_image (pixbuf);
|
||||
image = pixbuf_to_st_content_image (pixbuf,
|
||||
data->width, data->height,
|
||||
data->paint_scale,
|
||||
data->resource_scale);
|
||||
if (!image)
|
||||
goto out;
|
||||
|
||||
@@ -561,7 +585,10 @@ finish_texture_load (AsyncTextureLoadData *data,
|
||||
}
|
||||
else
|
||||
{
|
||||
image = pixbuf_to_clutter_image (pixbuf);
|
||||
image = pixbuf_to_st_content_image (pixbuf,
|
||||
data->width, data->height,
|
||||
data->paint_scale,
|
||||
data->resource_scale);
|
||||
if (!image)
|
||||
goto out;
|
||||
}
|
||||
@@ -652,6 +679,7 @@ load_texture_async (StTextureCache *cache,
|
||||
typedef struct {
|
||||
StTextureCache *cache;
|
||||
ClutterActor *actor;
|
||||
gint size;
|
||||
GObject *source;
|
||||
guint notify_signal_id;
|
||||
gboolean weakref_active;
|
||||
@@ -672,10 +700,14 @@ st_texture_cache_reset_texture (StTextureCachePropertyBind *bind,
|
||||
{
|
||||
g_autoptr(ClutterContent) image = NULL;
|
||||
g_autoptr(GError) error = NULL;
|
||||
int size = bind->size;
|
||||
|
||||
if (size < 0)
|
||||
clutter_actor_get_preferred_width (bind->actor, -1, NULL, (float *)&size);
|
||||
|
||||
image = clutter_actor_get_content (bind->actor);
|
||||
if (!image || !CLUTTER_IS_IMAGE (image))
|
||||
image = clutter_image_new ();
|
||||
image = st_image_content_new_with_preferred_size (size, size);
|
||||
else
|
||||
g_object_ref (image);
|
||||
|
||||
@@ -723,7 +755,7 @@ st_texture_cache_free_bind (gpointer data)
|
||||
StTextureCachePropertyBind *bind = data;
|
||||
if (bind->weakref_active)
|
||||
g_object_weak_unref (G_OBJECT (bind->actor), st_texture_cache_bind_weak_notify, bind);
|
||||
g_free (bind);
|
||||
g_slice_free (StTextureCachePropertyBind, bind);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -739,24 +771,30 @@ st_texture_cache_free_bind (gpointer data)
|
||||
* If the source object is destroyed, the texture will continue to show the last
|
||||
* value of the property.
|
||||
*
|
||||
* Return value: (transfer none): A new #ClutterActor
|
||||
* Return value: (transfer none): A new #StWidget
|
||||
*/
|
||||
ClutterActor *
|
||||
StWidget *
|
||||
st_texture_cache_bind_cairo_surface_property (StTextureCache *cache,
|
||||
GObject *object,
|
||||
const char *property_name)
|
||||
const char *property_name,
|
||||
gint size)
|
||||
{
|
||||
ClutterActor *actor;
|
||||
StWidget *widget;
|
||||
gchar *notify_key;
|
||||
StTextureCachePropertyBind *bind;
|
||||
|
||||
actor = clutter_actor_new ();
|
||||
widget = g_object_new (ST_TYPE_WIDGET,
|
||||
"opacity", 0,
|
||||
"width", (float)size,
|
||||
"height", (float)size,
|
||||
NULL);
|
||||
|
||||
bind = g_new0 (StTextureCachePropertyBind, 1);
|
||||
bind = g_slice_new0 (StTextureCachePropertyBind);
|
||||
bind->cache = cache;
|
||||
bind->actor = actor;
|
||||
bind->actor = CLUTTER_ACTOR (widget);
|
||||
bind->size = size;
|
||||
bind->source = object;
|
||||
g_object_weak_ref (G_OBJECT (actor), st_texture_cache_bind_weak_notify, bind);
|
||||
g_object_weak_ref (G_OBJECT (widget), st_texture_cache_bind_weak_notify, bind);
|
||||
bind->weakref_active = TRUE;
|
||||
|
||||
st_texture_cache_reset_texture (bind, property_name);
|
||||
@@ -766,7 +804,7 @@ st_texture_cache_bind_cairo_surface_property (StTextureCache *cache,
|
||||
bind, (GClosureNotify)st_texture_cache_free_bind, 0);
|
||||
g_free (notify_key);
|
||||
|
||||
return actor;
|
||||
return widget;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -849,7 +887,7 @@ ensure_request (StTextureCache *cache,
|
||||
if (pending == NULL)
|
||||
{
|
||||
/* Not cached and no pending request, create it */
|
||||
*request = g_new0 (AsyncTextureLoadData, 1);
|
||||
*request = g_slice_new0 (AsyncTextureLoadData);
|
||||
if (policy != ST_TEXTURE_CACHE_POLICY_NONE)
|
||||
g_hash_table_insert (cache->priv->outstanding_requests, g_strdup (key), *request);
|
||||
}
|
||||
@@ -869,7 +907,8 @@ ensure_request (StTextureCache *cache,
|
||||
* if the icon must not be recolored
|
||||
* @icon: the #GIcon to load
|
||||
* @size: Size of themed
|
||||
* @scale: Scale factor of display
|
||||
* @paint_scale: Scale factor of display
|
||||
* @resource_scale: Resource scale factor
|
||||
*
|
||||
* This method returns a new #ClutterActor for a given #GIcon. If the
|
||||
* icon isn't loaded already, the texture will be filled
|
||||
@@ -882,12 +921,15 @@ st_texture_cache_load_gicon (StTextureCache *cache,
|
||||
StThemeNode *theme_node,
|
||||
GIcon *icon,
|
||||
gint size,
|
||||
gint scale)
|
||||
gint paint_scale,
|
||||
gfloat resource_scale)
|
||||
{
|
||||
AsyncTextureLoadData *request;
|
||||
ClutterActor *actor;
|
||||
gint scale;
|
||||
char *gicon_string;
|
||||
char *key;
|
||||
float actor_size;
|
||||
GtkIconTheme *theme;
|
||||
GtkIconInfo *info;
|
||||
StTextureCachePolicy policy;
|
||||
@@ -916,7 +958,10 @@ st_texture_cache_load_gicon (StTextureCache *cache,
|
||||
else
|
||||
lookup_flags |= GTK_ICON_LOOKUP_DIR_LTR;
|
||||
|
||||
info = gtk_icon_theme_lookup_by_gicon_for_scale (theme, icon, size, scale, lookup_flags);
|
||||
scale = ceilf (paint_scale * resource_scale);
|
||||
info = gtk_icon_theme_lookup_by_gicon_for_scale (theme, icon,
|
||||
size, scale,
|
||||
lookup_flags);
|
||||
if (info == NULL)
|
||||
return NULL;
|
||||
|
||||
@@ -945,8 +990,8 @@ st_texture_cache_load_gicon (StTextureCache *cache,
|
||||
g_free (gicon_string);
|
||||
|
||||
actor = create_invisible_actor ();
|
||||
clutter_actor_set_size (actor, size * scale, size * scale);
|
||||
|
||||
actor_size = size * paint_scale;
|
||||
clutter_actor_set_size (actor, actor_size, actor_size);
|
||||
if (ensure_request (cache, key, policy, &request, actor))
|
||||
{
|
||||
/* If there's an outstanding request, we've just added ourselves to it */
|
||||
@@ -964,7 +1009,8 @@ st_texture_cache_load_gicon (StTextureCache *cache,
|
||||
request->colors = colors ? st_icon_colors_ref (colors) : NULL;
|
||||
request->icon_info = info;
|
||||
request->width = request->height = size;
|
||||
request->scale = scale;
|
||||
request->paint_scale = paint_scale;
|
||||
request->resource_scale = resource_scale;
|
||||
|
||||
load_texture_async (cache, request);
|
||||
}
|
||||
@@ -973,17 +1019,18 @@ st_texture_cache_load_gicon (StTextureCache *cache,
|
||||
}
|
||||
|
||||
static ClutterActor *
|
||||
load_from_pixbuf (GdkPixbuf *pixbuf)
|
||||
load_from_pixbuf (GdkPixbuf *pixbuf,
|
||||
int paint_scale,
|
||||
float resource_scale)
|
||||
{
|
||||
g_autoptr(ClutterContent) image = NULL;
|
||||
ClutterActor *actor;
|
||||
int width = gdk_pixbuf_get_width (pixbuf);
|
||||
int height = gdk_pixbuf_get_height (pixbuf);
|
||||
|
||||
image = pixbuf_to_clutter_image (pixbuf);
|
||||
image = pixbuf_to_st_content_image (pixbuf, -1, -1, paint_scale, resource_scale);
|
||||
|
||||
actor = clutter_actor_new ();
|
||||
clutter_actor_set_size (actor, width, height);
|
||||
actor = g_object_new (CLUTTER_TYPE_ACTOR,
|
||||
"request-mode", CLUTTER_REQUEST_CONTENT_SIZE,
|
||||
NULL);
|
||||
clutter_actor_set_content (actor, image);
|
||||
|
||||
return actor;
|
||||
@@ -1041,8 +1088,10 @@ ensure_monitor_for_file (StTextureCache *cache,
|
||||
typedef struct {
|
||||
GFile *gfile;
|
||||
gint grid_width, grid_height;
|
||||
gint scale_factor;
|
||||
gint paint_scale;
|
||||
gfloat resource_scale;
|
||||
ClutterActor *actor;
|
||||
GCancellable *cancellable;
|
||||
GFunc load_callback;
|
||||
gpointer load_callback_data;
|
||||
} AsyncImageData;
|
||||
@@ -1053,7 +1102,18 @@ on_data_destroy (gpointer data)
|
||||
AsyncImageData *d = (AsyncImageData *)data;
|
||||
g_object_unref (d->gfile);
|
||||
g_object_unref (d->actor);
|
||||
g_free (d);
|
||||
g_object_unref (d->cancellable);
|
||||
g_slice_free (AsyncImageData, d);
|
||||
}
|
||||
|
||||
static void
|
||||
on_sliced_image_actor_destroyed (ClutterActor *actor,
|
||||
gpointer data)
|
||||
{
|
||||
GTask *task = data;
|
||||
GCancellable *cancellable = g_task_get_cancellable (task);
|
||||
|
||||
g_cancellable_cancel (cancellable);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -1066,20 +1126,26 @@ on_sliced_image_loaded (GObject *source_object,
|
||||
GTask *task = G_TASK (res);
|
||||
GList *list, *pixbufs;
|
||||
|
||||
if (g_task_had_error (task))
|
||||
if (g_task_had_error (task) || g_cancellable_is_cancelled (data->cancellable))
|
||||
return;
|
||||
|
||||
pixbufs = g_task_propagate_pointer (task, NULL);
|
||||
|
||||
for (list = pixbufs; list; list = list->next)
|
||||
{
|
||||
ClutterActor *actor = load_from_pixbuf (GDK_PIXBUF (list->data));
|
||||
ClutterActor *actor = load_from_pixbuf (GDK_PIXBUF (list->data),
|
||||
data->paint_scale,
|
||||
data->resource_scale);
|
||||
clutter_actor_hide (actor);
|
||||
clutter_actor_add_child (data->actor, actor);
|
||||
}
|
||||
|
||||
g_list_free_full (pixbufs, g_object_unref);
|
||||
|
||||
g_signal_handlers_disconnect_by_func (data->actor,
|
||||
on_sliced_image_actor_destroyed,
|
||||
task);
|
||||
|
||||
if (data->load_callback != NULL)
|
||||
data->load_callback (cache, data->load_callback_data);
|
||||
}
|
||||
@@ -1097,9 +1163,9 @@ on_loader_size_prepared (GdkPixbufLoader *loader,
|
||||
gpointer user_data)
|
||||
{
|
||||
AsyncImageData *data = user_data;
|
||||
gdk_pixbuf_loader_set_size (loader,
|
||||
width * data->scale_factor,
|
||||
height * data->scale_factor);
|
||||
int scale = ceilf (data->paint_scale * data->resource_scale);
|
||||
|
||||
gdk_pixbuf_loader_set_size (loader, width * scale, height * scale);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -1112,12 +1178,13 @@ load_sliced_image (GTask *result,
|
||||
GList *res = NULL;
|
||||
GdkPixbuf *pix;
|
||||
gint width, height, y, x;
|
||||
gint scale_factor;
|
||||
GdkPixbufLoader *loader;
|
||||
GError *error = NULL;
|
||||
gchar *buffer = NULL;
|
||||
gsize length;
|
||||
|
||||
g_assert (!cancellable);
|
||||
g_assert (cancellable);
|
||||
|
||||
data = task_data;
|
||||
g_assert (data);
|
||||
@@ -1125,7 +1192,7 @@ load_sliced_image (GTask *result,
|
||||
loader = gdk_pixbuf_loader_new ();
|
||||
g_signal_connect (loader, "size-prepared", G_CALLBACK (on_loader_size_prepared), data);
|
||||
|
||||
if (!g_file_load_contents (data->gfile, NULL, &buffer, &length, NULL, &error))
|
||||
if (!g_file_load_contents (data->gfile, cancellable, &buffer, &length, NULL, &error))
|
||||
{
|
||||
g_warning ("Failed to open sliced image: %s", error->message);
|
||||
goto out;
|
||||
@@ -1143,13 +1210,14 @@ load_sliced_image (GTask *result,
|
||||
pix = gdk_pixbuf_loader_get_pixbuf (loader);
|
||||
width = gdk_pixbuf_get_width (pix);
|
||||
height = gdk_pixbuf_get_height (pix);
|
||||
for (y = 0; y < height; y += data->grid_height * data->scale_factor)
|
||||
scale_factor = ceilf (data->paint_scale * data->resource_scale);
|
||||
for (y = 0; y < height; y += data->grid_height * scale_factor)
|
||||
{
|
||||
for (x = 0; x < width; x += data->grid_width * data->scale_factor)
|
||||
for (x = 0; x < width; x += data->grid_width * scale_factor)
|
||||
{
|
||||
GdkPixbuf *pixbuf = gdk_pixbuf_new_subpixbuf (pix, x, y,
|
||||
data->grid_width * data->scale_factor,
|
||||
data->grid_height * data->scale_factor);
|
||||
data->grid_width * scale_factor,
|
||||
data->grid_height * scale_factor);
|
||||
g_assert (pixbuf != NULL);
|
||||
res = g_list_append (res, pixbuf);
|
||||
}
|
||||
@@ -1170,13 +1238,13 @@ load_sliced_image (GTask *result,
|
||||
* @file: A #GFile
|
||||
* @grid_width: Width in pixels
|
||||
* @grid_height: Height in pixels
|
||||
* @scale: Scale factor of the display
|
||||
* @paint_scale: Scale factor of the display
|
||||
* @load_callback: (scope async) (nullable): Function called when the image is loaded, or %NULL
|
||||
* @user_data: Data to pass to the load callback
|
||||
*
|
||||
* This function reads a single image file which contains multiple images internally.
|
||||
* The image file will be divided using @grid_width and @grid_height;
|
||||
* note that the dimensions of the image loaded from @path
|
||||
* note that the dimensions of the image loaded from @path
|
||||
* should be a multiple of the specified grid dimensions.
|
||||
*
|
||||
* Returns: (transfer none): A new #ClutterActor
|
||||
@@ -1186,25 +1254,37 @@ st_texture_cache_load_sliced_image (StTextureCache *cache,
|
||||
GFile *file,
|
||||
gint grid_width,
|
||||
gint grid_height,
|
||||
gint scale,
|
||||
gint paint_scale,
|
||||
gfloat resource_scale,
|
||||
GFunc load_callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
AsyncImageData *data;
|
||||
GTask *result;
|
||||
ClutterActor *actor = clutter_actor_new ();
|
||||
GCancellable *cancellable = g_cancellable_new ();
|
||||
|
||||
data = g_new0 (AsyncImageData, 1);
|
||||
g_return_val_if_fail (G_IS_FILE (file), NULL);
|
||||
g_assert (paint_scale > 0);
|
||||
g_assert (resource_scale > 0);
|
||||
|
||||
data = g_slice_new0 (AsyncImageData);
|
||||
data->grid_width = grid_width;
|
||||
data->grid_height = grid_height;
|
||||
data->scale_factor = scale;
|
||||
data->paint_scale = paint_scale;
|
||||
data->resource_scale = resource_scale;
|
||||
data->gfile = g_object_ref (file);
|
||||
data->actor = actor;
|
||||
data->cancellable = cancellable;
|
||||
data->load_callback = load_callback;
|
||||
data->load_callback_data = user_data;
|
||||
g_object_ref (G_OBJECT (actor));
|
||||
|
||||
result = g_task_new (cache, NULL, on_sliced_image_loaded, data);
|
||||
result = g_task_new (cache, cancellable, on_sliced_image_loaded, data);
|
||||
|
||||
g_signal_connect (actor, "destroy",
|
||||
G_CALLBACK (on_sliced_image_actor_destroyed), result);
|
||||
|
||||
g_task_set_task_data (result, data, on_data_destroy);
|
||||
g_task_run_in_thread (result, load_sliced_image);
|
||||
|
||||
@@ -1219,7 +1299,8 @@ st_texture_cache_load_sliced_image (StTextureCache *cache,
|
||||
* @file: a #GFile of the image file from which to create a pixbuf
|
||||
* @available_width: available width for the image, can be -1 if not limited
|
||||
* @available_height: available height for the image, can be -1 if not limited
|
||||
* @scale: scale factor of the display
|
||||
* @paint_scale: scale factor of the display
|
||||
* @resource_scale: Resource scale factor
|
||||
*
|
||||
* Asynchronously load an image. Initially, the returned texture will have a natural
|
||||
* size of zero. At some later point, either the image will be loaded successfully
|
||||
@@ -1232,14 +1313,17 @@ st_texture_cache_load_file_async (StTextureCache *cache,
|
||||
GFile *file,
|
||||
int available_width,
|
||||
int available_height,
|
||||
int scale)
|
||||
int paint_scale,
|
||||
gfloat resource_scale)
|
||||
{
|
||||
ClutterActor *actor;
|
||||
AsyncTextureLoadData *request;
|
||||
StTextureCachePolicy policy;
|
||||
gchar *key;
|
||||
int scale;
|
||||
|
||||
key = g_strdup_printf (CACHE_PREFIX_FILE "%u", g_file_hash (file));
|
||||
scale = ceilf (paint_scale * resource_scale);
|
||||
key = g_strdup_printf (CACHE_PREFIX_FILE "%u%d", g_file_hash (file), scale);
|
||||
|
||||
policy = ST_TEXTURE_CACHE_POLICY_NONE; /* XXX */
|
||||
|
||||
@@ -1261,7 +1345,8 @@ st_texture_cache_load_file_async (StTextureCache *cache,
|
||||
request->policy = policy;
|
||||
request->width = available_width;
|
||||
request->height = available_height;
|
||||
request->scale = scale;
|
||||
request->paint_scale = paint_scale;
|
||||
request->resource_scale = resource_scale;
|
||||
|
||||
load_texture_async (cache, request);
|
||||
}
|
||||
@@ -1277,7 +1362,8 @@ st_texture_cache_load_file_sync_to_cogl_texture (StTextureCache *cache,
|
||||
GFile *file,
|
||||
int available_width,
|
||||
int available_height,
|
||||
int scale,
|
||||
int paint_scale,
|
||||
gfloat resource_scale,
|
||||
GError **error)
|
||||
{
|
||||
ClutterContent *image;
|
||||
@@ -1285,18 +1371,21 @@ st_texture_cache_load_file_sync_to_cogl_texture (StTextureCache *cache,
|
||||
GdkPixbuf *pixbuf;
|
||||
char *key;
|
||||
|
||||
key = g_strdup_printf (CACHE_PREFIX_FILE "%u", g_file_hash (file));
|
||||
key = g_strdup_printf (CACHE_PREFIX_FILE "%u%f", g_file_hash (file), resource_scale);
|
||||
|
||||
texdata = NULL;
|
||||
image = g_hash_table_lookup (cache->priv->keyed_cache, key);
|
||||
|
||||
if (image == NULL)
|
||||
{
|
||||
pixbuf = impl_load_pixbuf_file (file, available_width, available_height, scale, error);
|
||||
pixbuf = impl_load_pixbuf_file (file, available_width, available_height,
|
||||
paint_scale, resource_scale, error);
|
||||
if (!pixbuf)
|
||||
goto out;
|
||||
|
||||
image = pixbuf_to_clutter_image (pixbuf);
|
||||
image = pixbuf_to_st_content_image (pixbuf,
|
||||
available_height, available_width,
|
||||
paint_scale, resource_scale);
|
||||
g_object_unref (pixbuf);
|
||||
|
||||
if (!image)
|
||||
@@ -1325,20 +1414,22 @@ st_texture_cache_load_file_sync_to_cairo_surface (StTextureCache *cache,
|
||||
GFile *file,
|
||||
int available_width,
|
||||
int available_height,
|
||||
int scale,
|
||||
int paint_scale,
|
||||
gfloat resource_scale,
|
||||
GError **error)
|
||||
{
|
||||
cairo_surface_t *surface;
|
||||
GdkPixbuf *pixbuf;
|
||||
char *key;
|
||||
|
||||
key = g_strdup_printf (CACHE_PREFIX_FILE_FOR_CAIRO "%u", g_file_hash (file));
|
||||
key = g_strdup_printf (CACHE_PREFIX_FILE_FOR_CAIRO "%u%f", g_file_hash (file), resource_scale);
|
||||
|
||||
surface = g_hash_table_lookup (cache->priv->keyed_surface_cache, key);
|
||||
|
||||
if (surface == NULL)
|
||||
{
|
||||
pixbuf = impl_load_pixbuf_file (file, available_width, available_height, scale, error);
|
||||
pixbuf = impl_load_pixbuf_file (file, available_width, available_height,
|
||||
paint_scale, resource_scale, error);
|
||||
if (!pixbuf)
|
||||
goto out;
|
||||
|
||||
@@ -1366,7 +1457,8 @@ out:
|
||||
* st_texture_cache_load_file_to_cogl_texture: (skip)
|
||||
* @cache: A #StTextureCache
|
||||
* @file: A #GFile in supported image format
|
||||
* @scale: Scale factor of the display
|
||||
* @paint_scale: Scale factor of the display
|
||||
* @resource_scale: Resource scale factor
|
||||
*
|
||||
* This function synchronously loads the given file path
|
||||
* into a COGL texture. On error, a warning is emitted
|
||||
@@ -1377,13 +1469,15 @@ out:
|
||||
CoglTexture *
|
||||
st_texture_cache_load_file_to_cogl_texture (StTextureCache *cache,
|
||||
GFile *file,
|
||||
gint scale)
|
||||
gint paint_scale,
|
||||
gfloat resource_scale)
|
||||
{
|
||||
CoglTexture *texture;
|
||||
GError *error = NULL;
|
||||
|
||||
texture = st_texture_cache_load_file_sync_to_cogl_texture (cache, ST_TEXTURE_CACHE_POLICY_FOREVER,
|
||||
file, -1, -1, scale, &error);
|
||||
file, -1, -1, paint_scale, resource_scale,
|
||||
&error);
|
||||
|
||||
if (texture == NULL)
|
||||
{
|
||||
@@ -1400,7 +1494,8 @@ st_texture_cache_load_file_to_cogl_texture (StTextureCache *cache,
|
||||
* st_texture_cache_load_file_to_cairo_surface:
|
||||
* @cache: A #StTextureCache
|
||||
* @file: A #GFile in supported image format
|
||||
* @scale: Scale factor of the display
|
||||
* @paint_scale: Scale factor of the display
|
||||
* @resource_scale: Resource scale factor
|
||||
*
|
||||
* This function synchronously loads the given file path
|
||||
* into a cairo surface. On error, a warning is emitted
|
||||
@@ -1411,13 +1506,15 @@ st_texture_cache_load_file_to_cogl_texture (StTextureCache *cache,
|
||||
cairo_surface_t *
|
||||
st_texture_cache_load_file_to_cairo_surface (StTextureCache *cache,
|
||||
GFile *file,
|
||||
gint scale)
|
||||
gint paint_scale,
|
||||
gfloat resource_scale)
|
||||
{
|
||||
cairo_surface_t *surface;
|
||||
GError *error = NULL;
|
||||
|
||||
surface = st_texture_cache_load_file_sync_to_cairo_surface (cache, ST_TEXTURE_CACHE_POLICY_FOREVER,
|
||||
file, -1, -1, scale, &error);
|
||||
file, -1, -1, paint_scale, resource_scale,
|
||||
&error);
|
||||
|
||||
if (surface == NULL)
|
||||
{
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
|
||||
#include <st/st-types.h>
|
||||
#include <st/st-theme-node.h>
|
||||
#include <st/st-widget.h>
|
||||
|
||||
#define ST_TYPE_TEXTURE_CACHE (st_texture_cache_get_type ())
|
||||
G_DECLARE_FINAL_TYPE (StTextureCache, st_texture_cache,
|
||||
@@ -58,33 +59,39 @@ st_texture_cache_load_sliced_image (StTextureCache *cache,
|
||||
GFile *file,
|
||||
gint grid_width,
|
||||
gint grid_height,
|
||||
gint scale,
|
||||
gint paint_scale,
|
||||
gfloat resource_scale,
|
||||
GFunc load_callback,
|
||||
gpointer user_data);
|
||||
|
||||
ClutterActor *st_texture_cache_bind_cairo_surface_property (StTextureCache *cache,
|
||||
GObject *object,
|
||||
const char *property_name);
|
||||
StWidget *st_texture_cache_bind_cairo_surface_property (StTextureCache *cache,
|
||||
GObject *object,
|
||||
const char *property_name,
|
||||
gint size);
|
||||
|
||||
ClutterActor *st_texture_cache_load_gicon (StTextureCache *cache,
|
||||
StThemeNode *theme_node,
|
||||
GIcon *icon,
|
||||
gint size,
|
||||
gint scale);
|
||||
gint paint_scale,
|
||||
gfloat resource_scale);
|
||||
|
||||
ClutterActor *st_texture_cache_load_file_async (StTextureCache *cache,
|
||||
GFile *file,
|
||||
int available_width,
|
||||
int available_height,
|
||||
int scale);
|
||||
int paint_scale,
|
||||
gfloat resource_scale);
|
||||
|
||||
CoglTexture *st_texture_cache_load_file_to_cogl_texture (StTextureCache *cache,
|
||||
GFile *file,
|
||||
gint scale);
|
||||
gint paint_scale,
|
||||
gfloat resource_scale);
|
||||
|
||||
cairo_surface_t *st_texture_cache_load_file_to_cairo_surface (StTextureCache *cache,
|
||||
GFile *file,
|
||||
gint scale);
|
||||
gint paint_scale,
|
||||
gfloat resource_scale);
|
||||
|
||||
/**
|
||||
* StTextureCacheLoader: (skip)
|
||||
|
||||
@@ -48,6 +48,7 @@ typedef struct {
|
||||
guint radius;
|
||||
guint border_width_1;
|
||||
guint border_width_2;
|
||||
float resource_scale;
|
||||
} StCornerSpec;
|
||||
|
||||
static void
|
||||
@@ -78,10 +79,13 @@ create_corner_material (StCornerSpec *corner)
|
||||
guint rowstride;
|
||||
guint8 *data;
|
||||
guint size;
|
||||
guint logical_size;
|
||||
guint max_border_width;
|
||||
double device_scaling;
|
||||
|
||||
max_border_width = MAX(corner->border_width_2, corner->border_width_1);
|
||||
size = 2 * MAX(max_border_width, corner->radius);
|
||||
logical_size = 2 * MAX(max_border_width, corner->radius);
|
||||
size = ceilf (logical_size * corner->resource_scale);
|
||||
rowstride = size * 4;
|
||||
data = g_new0 (guint8, size * rowstride);
|
||||
|
||||
@@ -89,9 +93,11 @@ create_corner_material (StCornerSpec *corner)
|
||||
CAIRO_FORMAT_ARGB32,
|
||||
size, size,
|
||||
rowstride);
|
||||
device_scaling = (double) size / logical_size;
|
||||
cairo_surface_set_device_scale (surface, device_scaling, device_scaling);
|
||||
cr = cairo_create (surface);
|
||||
cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
|
||||
cairo_scale (cr, size, size);
|
||||
cairo_scale (cr, logical_size, logical_size);
|
||||
|
||||
if (max_border_width <= corner->radius)
|
||||
{
|
||||
@@ -189,13 +195,14 @@ create_corner_material (StCornerSpec *corner)
|
||||
static char *
|
||||
corner_to_string (StCornerSpec *corner)
|
||||
{
|
||||
return g_strdup_printf ("st-theme-node-corner:%02x%02x%02x%02x,%02x%02x%02x%02x,%02x%02x%02x%02x,%u,%u,%u",
|
||||
return g_strdup_printf ("st-theme-node-corner:%02x%02x%02x%02x,%02x%02x%02x%02x,%02x%02x%02x%02x,%u,%u,%u,%.4f",
|
||||
corner->color.red, corner->color.blue, corner->color.green, corner->color.alpha,
|
||||
corner->border_color_1.red, corner->border_color_1.green, corner->border_color_1.blue, corner->border_color_1.alpha,
|
||||
corner->border_color_2.red, corner->border_color_2.green, corner->border_color_2.blue, corner->border_color_2.alpha,
|
||||
corner->radius,
|
||||
corner->border_width_1,
|
||||
corner->border_width_2);
|
||||
corner->border_width_2,
|
||||
corner->resource_scale);
|
||||
}
|
||||
|
||||
static CoglTexture *
|
||||
@@ -352,6 +359,7 @@ static CoglPipeline *
|
||||
st_theme_node_lookup_corner (StThemeNode *node,
|
||||
float width,
|
||||
float height,
|
||||
float resource_scale,
|
||||
StCorner corner_id)
|
||||
{
|
||||
CoglTexture *texture = NULL;
|
||||
@@ -370,6 +378,7 @@ st_theme_node_lookup_corner (StThemeNode *node,
|
||||
|
||||
corner.radius = radius[corner_id];
|
||||
corner.color = node->background_color;
|
||||
corner.resource_scale = resource_scale;
|
||||
st_theme_node_get_corner_border_widths (node, corner_id,
|
||||
&corner.border_width_1,
|
||||
&corner.border_width_2);
|
||||
@@ -431,7 +440,7 @@ get_background_scale (StThemeNode *node,
|
||||
switch (node->background_size)
|
||||
{
|
||||
case ST_BACKGROUND_SIZE_AUTO:
|
||||
*scale_w = 1.0;
|
||||
*scale_w = 1.0f;
|
||||
break;
|
||||
case ST_BACKGROUND_SIZE_CONTAIN:
|
||||
*scale_w = MIN (painting_area_width / background_image_width,
|
||||
@@ -485,6 +494,7 @@ get_background_coordinates (StThemeNode *node,
|
||||
static void
|
||||
get_background_position (StThemeNode *self,
|
||||
const ClutterActorBox *allocation,
|
||||
float resource_scale,
|
||||
ClutterActorBox *result,
|
||||
ClutterActorBox *texture_coords)
|
||||
{
|
||||
@@ -497,6 +507,9 @@ get_background_position (StThemeNode *self,
|
||||
background_image_width = cogl_texture_get_width (self->background_texture);
|
||||
background_image_height = cogl_texture_get_height (self->background_texture);
|
||||
|
||||
background_image_width /= resource_scale;
|
||||
background_image_height /= resource_scale;
|
||||
|
||||
/* get the painting area size */
|
||||
painting_area_width = allocation->x2 - allocation->x1;
|
||||
painting_area_height = allocation->y2 - allocation->y1;
|
||||
@@ -506,6 +519,7 @@ get_background_position (StThemeNode *self,
|
||||
painting_area_width, painting_area_height,
|
||||
background_image_width, background_image_height,
|
||||
&scale_w, &scale_h);
|
||||
|
||||
background_image_width *= scale_w;
|
||||
background_image_height *= scale_h;
|
||||
|
||||
@@ -615,6 +629,7 @@ static cairo_pattern_t *
|
||||
create_cairo_pattern_of_background_image (StThemeNode *node,
|
||||
float width,
|
||||
float height,
|
||||
float resource_scale,
|
||||
gboolean *needs_background_fill)
|
||||
{
|
||||
cairo_surface_t *surface;
|
||||
@@ -635,7 +650,9 @@ create_cairo_pattern_of_background_image (StThemeNode *node,
|
||||
texture_cache = st_texture_cache_get_default ();
|
||||
|
||||
g_object_get (node->context, "scale-factor", &scale_factor, NULL);
|
||||
surface = st_texture_cache_load_file_to_cairo_surface (texture_cache, file, scale_factor);
|
||||
surface = st_texture_cache_load_file_to_cairo_surface (texture_cache, file,
|
||||
scale_factor,
|
||||
resource_scale);
|
||||
|
||||
if (surface == NULL)
|
||||
return NULL;
|
||||
@@ -652,12 +669,22 @@ create_cairo_pattern_of_background_image (StThemeNode *node,
|
||||
|
||||
cairo_matrix_init_identity (&matrix);
|
||||
|
||||
if (resource_scale != 1.0)
|
||||
{
|
||||
background_image_width /= resource_scale;
|
||||
background_image_height /= resource_scale;
|
||||
|
||||
cairo_matrix_scale (&matrix, resource_scale, resource_scale);
|
||||
}
|
||||
|
||||
get_background_scale (node,
|
||||
width, height,
|
||||
background_image_width, background_image_height,
|
||||
&scale_w, &scale_h);
|
||||
|
||||
if ((scale_w != 1) || (scale_h != 1))
|
||||
cairo_matrix_scale (&matrix, 1.0/scale_w, 1.0/scale_h);
|
||||
|
||||
background_image_width *= scale_w;
|
||||
background_image_height *= scale_h;
|
||||
|
||||
@@ -742,6 +769,7 @@ paint_shadow_pattern_to_cairo_context (StShadow *shadow_spec,
|
||||
{
|
||||
cairo_surface_t *surface;
|
||||
int width, height;
|
||||
double xscale, yscale;
|
||||
cairo_matrix_t matrix;
|
||||
|
||||
cairo_save (cr);
|
||||
@@ -758,11 +786,13 @@ paint_shadow_pattern_to_cairo_context (StShadow *shadow_spec,
|
||||
/* Something went wrong previously */
|
||||
goto no_surface;
|
||||
|
||||
cairo_surface_get_device_scale (surface, &xscale, &yscale);
|
||||
width = cairo_image_surface_get_width (surface);
|
||||
height = cairo_image_surface_get_height (surface);
|
||||
|
||||
cairo_pattern_get_matrix (pattern, &matrix);
|
||||
cairo_matrix_invert (&matrix);
|
||||
cairo_matrix_scale (&matrix, 1.0 / xscale, 1.0 / yscale);
|
||||
cairo_transform (cr, &matrix);
|
||||
|
||||
cairo_rectangle (cr, 0, height, width, - height);
|
||||
@@ -786,7 +816,8 @@ paint_background_image_shadow_to_cairo_context (StThemeNode *node,
|
||||
int x,
|
||||
int y,
|
||||
int width,
|
||||
int height)
|
||||
int height,
|
||||
float resource_scale)
|
||||
{
|
||||
cairo_pattern_t *shadow_pattern;
|
||||
|
||||
@@ -802,7 +833,10 @@ paint_background_image_shadow_to_cairo_context (StThemeNode *node,
|
||||
/* Prerender the pattern to a temporary surface,
|
||||
* so it's properly clipped before we create a shadow from it
|
||||
*/
|
||||
width = ceilf (width * resource_scale);
|
||||
height = ceilf (height * resource_scale);
|
||||
clipped_surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height);
|
||||
cairo_surface_set_device_scale (clipped_surface, resource_scale, resource_scale);
|
||||
temp_cr = cairo_create (clipped_surface);
|
||||
|
||||
cairo_set_operator (temp_cr, CAIRO_OPERATOR_CLEAR);
|
||||
@@ -866,6 +900,7 @@ path_extents (cairo_path_t *path,
|
||||
static void
|
||||
paint_inset_box_shadow_to_cairo_context (StThemeNode *node,
|
||||
StShadow *shadow_spec,
|
||||
float resource_scale,
|
||||
cairo_t *cr,
|
||||
cairo_path_t *shadow_outline)
|
||||
{
|
||||
@@ -906,8 +941,8 @@ paint_inset_box_shadow_to_cairo_context (StThemeNode *node,
|
||||
/* Bounds of temporary surface */
|
||||
int surface_x = floor (shrunk_extents_x1);
|
||||
int surface_y = floor (shrunk_extents_y1);
|
||||
int surface_width = ceil (shrunk_extents_x2) - surface_x;
|
||||
int surface_height = ceil (shrunk_extents_y2) - surface_y;
|
||||
int surface_width = ceil ((shrunk_extents_x2 - surface_x) * resource_scale);
|
||||
int surface_height = ceil ((shrunk_extents_y2 - surface_y) * resource_scale);
|
||||
|
||||
/* Center of the original path */
|
||||
double x_center = (extents_x1 + extents_x2) / 2;
|
||||
@@ -918,6 +953,7 @@ paint_inset_box_shadow_to_cairo_context (StThemeNode *node,
|
||||
cairo_matrix_t matrix;
|
||||
|
||||
shadow_surface = cairo_image_surface_create (CAIRO_FORMAT_A8, surface_width, surface_height);
|
||||
cairo_surface_set_device_scale (shadow_surface, resource_scale, resource_scale);
|
||||
temp_cr = cairo_create (shadow_surface);
|
||||
|
||||
/* Match the coordinates in the temporary context to the parent context */
|
||||
@@ -966,7 +1002,8 @@ paint_inset_box_shadow_to_cairo_context (StThemeNode *node,
|
||||
static CoglTexture *
|
||||
st_theme_node_prerender_background (StThemeNode *node,
|
||||
float actor_width,
|
||||
float actor_height)
|
||||
float actor_height,
|
||||
float resource_scale)
|
||||
{
|
||||
ClutterBackend *backend = clutter_get_default_backend ();
|
||||
CoglContext *ctx = clutter_backend_get_cogl_context (backend);
|
||||
@@ -994,6 +1031,8 @@ st_theme_node_prerender_background (StThemeNode *node,
|
||||
ClutterActorBox paint_box;
|
||||
cairo_path_t *interior_path = NULL;
|
||||
float width, height;
|
||||
int texture_width;
|
||||
int texture_height;
|
||||
|
||||
border_image = st_theme_node_get_border_image (node);
|
||||
|
||||
@@ -1021,8 +1060,11 @@ st_theme_node_prerender_background (StThemeNode *node,
|
||||
width = paint_box.x2 - paint_box.x1;
|
||||
height = paint_box.y2 - paint_box.y1;
|
||||
|
||||
rowstride = cairo_format_stride_for_width (CAIRO_FORMAT_ARGB32, width);
|
||||
data = g_new0 (guchar, height * rowstride);
|
||||
texture_width = ceilf (width * resource_scale);
|
||||
texture_height = ceilf (height * resource_scale);
|
||||
|
||||
rowstride = cairo_format_stride_for_width (CAIRO_FORMAT_ARGB32, texture_width);
|
||||
data = g_new0 (guchar, texture_height * rowstride);
|
||||
|
||||
/* We zero initialize the destination memory, so it's fully transparent
|
||||
* by default.
|
||||
@@ -1031,8 +1073,9 @@ st_theme_node_prerender_background (StThemeNode *node,
|
||||
|
||||
surface = cairo_image_surface_create_for_data (data,
|
||||
CAIRO_FORMAT_ARGB32,
|
||||
width, height,
|
||||
texture_width, texture_height,
|
||||
rowstride);
|
||||
cairo_surface_set_device_scale (surface, resource_scale, resource_scale);
|
||||
cr = cairo_create (surface);
|
||||
|
||||
/* TODO - support non-uniform border colors */
|
||||
@@ -1070,7 +1113,9 @@ st_theme_node_prerender_background (StThemeNode *node,
|
||||
|
||||
if (background_image != NULL)
|
||||
{
|
||||
pattern = create_cairo_pattern_of_background_image (node, width, height,
|
||||
pattern = create_cairo_pattern_of_background_image (node,
|
||||
width, height,
|
||||
resource_scale,
|
||||
&draw_solid_background);
|
||||
if (shadow_spec && pattern != NULL)
|
||||
draw_background_image_shadow = TRUE;
|
||||
@@ -1258,7 +1303,8 @@ st_theme_node_prerender_background (StThemeNode *node,
|
||||
has_visible_outline? outline_path : NULL,
|
||||
actor_box.x1,
|
||||
actor_box.y1,
|
||||
width, height);
|
||||
width, height,
|
||||
resource_scale);
|
||||
cairo_append_path (cr, outline_path);
|
||||
}
|
||||
|
||||
@@ -1275,6 +1321,7 @@ st_theme_node_prerender_background (StThemeNode *node,
|
||||
{
|
||||
paint_inset_box_shadow_to_cairo_context (node,
|
||||
box_shadow_spec,
|
||||
resource_scale,
|
||||
cr,
|
||||
interior_path ? interior_path
|
||||
: outline_path);
|
||||
@@ -1286,7 +1333,9 @@ st_theme_node_prerender_background (StThemeNode *node,
|
||||
if (interior_path != NULL)
|
||||
cairo_path_destroy (interior_path);
|
||||
|
||||
texture = COGL_TEXTURE (cogl_texture_2d_new_from_data (ctx, width, height,
|
||||
texture = COGL_TEXTURE (cogl_texture_2d_new_from_data (ctx,
|
||||
texture_width,
|
||||
texture_height,
|
||||
CLUTTER_CAIRO_FORMAT_ARGB32,
|
||||
rowstride,
|
||||
data,
|
||||
@@ -1318,7 +1367,8 @@ st_theme_node_invalidate_border_image (StThemeNode *node)
|
||||
}
|
||||
|
||||
static gboolean
|
||||
st_theme_node_load_border_image (StThemeNode *node)
|
||||
st_theme_node_load_border_image (StThemeNode *node,
|
||||
gfloat resource_scale)
|
||||
{
|
||||
if (node->border_slices_texture == NULL)
|
||||
{
|
||||
@@ -1335,7 +1385,8 @@ st_theme_node_load_border_image (StThemeNode *node)
|
||||
g_object_get (node->context, "scale-factor", &scale_factor, NULL);
|
||||
|
||||
node->border_slices_texture = st_texture_cache_load_file_to_cogl_texture (st_texture_cache_get_default (),
|
||||
file, scale_factor);
|
||||
file, scale_factor,
|
||||
resource_scale);
|
||||
if (node->border_slices_texture == NULL)
|
||||
goto out;
|
||||
|
||||
@@ -1355,7 +1406,8 @@ st_theme_node_invalidate_background_image (StThemeNode *node)
|
||||
}
|
||||
|
||||
static gboolean
|
||||
st_theme_node_load_background_image (StThemeNode *node)
|
||||
st_theme_node_load_background_image (StThemeNode *node,
|
||||
gfloat resource_scale)
|
||||
{
|
||||
if (node->background_texture == NULL)
|
||||
{
|
||||
@@ -1371,7 +1423,8 @@ st_theme_node_load_background_image (StThemeNode *node)
|
||||
|
||||
background_image_shadow_spec = st_theme_node_get_background_image_shadow (node);
|
||||
node->background_texture = st_texture_cache_load_file_to_cogl_texture (st_texture_cache_get_default (),
|
||||
background_image, scale_factor);
|
||||
background_image, scale_factor,
|
||||
resource_scale);
|
||||
if (node->background_texture == NULL)
|
||||
goto out;
|
||||
|
||||
@@ -1384,7 +1437,8 @@ st_theme_node_load_background_image (StThemeNode *node)
|
||||
if (background_image_shadow_spec)
|
||||
{
|
||||
node->background_shadow_pipeline = _st_create_shadow_pipeline (background_image_shadow_spec,
|
||||
node->background_texture);
|
||||
node->background_texture,
|
||||
resource_scale);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1424,7 +1478,8 @@ static void
|
||||
st_theme_node_render_resources (StThemeNodePaintState *state,
|
||||
StThemeNode *node,
|
||||
float width,
|
||||
float height)
|
||||
float height,
|
||||
float resource_scale)
|
||||
{
|
||||
gboolean has_border;
|
||||
gboolean has_border_radius;
|
||||
@@ -1443,6 +1498,7 @@ st_theme_node_render_resources (StThemeNodePaintState *state,
|
||||
st_theme_node_paint_state_set_node (state, node);
|
||||
state->alloc_width = width;
|
||||
state->alloc_height = height;
|
||||
state->resource_scale = resource_scale;
|
||||
|
||||
_st_theme_node_ensure_background (node);
|
||||
_st_theme_node_ensure_geometry (node);
|
||||
@@ -1488,13 +1544,13 @@ st_theme_node_render_resources (StThemeNodePaintState *state,
|
||||
}
|
||||
|
||||
state->corner_material[ST_CORNER_TOPLEFT] =
|
||||
st_theme_node_lookup_corner (node, width, height, ST_CORNER_TOPLEFT);
|
||||
st_theme_node_lookup_corner (node, width, height, resource_scale, ST_CORNER_TOPLEFT);
|
||||
state->corner_material[ST_CORNER_TOPRIGHT] =
|
||||
st_theme_node_lookup_corner (node, width, height, ST_CORNER_TOPRIGHT);
|
||||
st_theme_node_lookup_corner (node, width, height, resource_scale, ST_CORNER_TOPRIGHT);
|
||||
state->corner_material[ST_CORNER_BOTTOMRIGHT] =
|
||||
st_theme_node_lookup_corner (node, width, height, ST_CORNER_BOTTOMRIGHT);
|
||||
st_theme_node_lookup_corner (node, width, height, resource_scale, ST_CORNER_BOTTOMRIGHT);
|
||||
state->corner_material[ST_CORNER_BOTTOMLEFT] =
|
||||
st_theme_node_lookup_corner (node, width, height, ST_CORNER_BOTTOMLEFT);
|
||||
st_theme_node_lookup_corner (node, width, height, resource_scale, ST_CORNER_BOTTOMLEFT);
|
||||
|
||||
/* Use cairo to prerender the node if there is a gradient, or
|
||||
* background image with borders and/or rounded corners,
|
||||
@@ -1509,7 +1565,8 @@ st_theme_node_render_resources (StThemeNodePaintState *state,
|
||||
|| (has_inset_box_shadow && (has_border || node->background_color.alpha > 0))
|
||||
|| (st_theme_node_get_background_image (node) && (has_border || has_border_radius))
|
||||
|| has_large_corners)
|
||||
state->prerendered_texture = st_theme_node_prerender_background (node, width, height);
|
||||
state->prerendered_texture = st_theme_node_prerender_background (node, width, height,
|
||||
resource_scale);
|
||||
|
||||
if (state->prerendered_texture)
|
||||
state->prerendered_pipeline = _st_create_texture_pipeline (state->prerendered_texture);
|
||||
@@ -1518,12 +1575,14 @@ st_theme_node_render_resources (StThemeNodePaintState *state,
|
||||
|
||||
if (box_shadow_spec && !has_inset_box_shadow)
|
||||
{
|
||||
if (st_theme_node_load_border_image (node))
|
||||
if (st_theme_node_load_border_image (node, resource_scale))
|
||||
state->box_shadow_pipeline = _st_create_shadow_pipeline (box_shadow_spec,
|
||||
node->border_slices_texture);
|
||||
node->border_slices_texture,
|
||||
state->resource_scale);
|
||||
else if (state->prerendered_texture != NULL)
|
||||
state->box_shadow_pipeline = _st_create_shadow_pipeline (box_shadow_spec,
|
||||
state->prerendered_texture);
|
||||
state->prerendered_texture,
|
||||
state->resource_scale);
|
||||
else if (node->background_color.alpha > 0 || has_border)
|
||||
st_theme_node_prerender_shadow (state);
|
||||
}
|
||||
@@ -1546,7 +1605,8 @@ static void
|
||||
st_theme_node_update_resources (StThemeNodePaintState *state,
|
||||
StThemeNode *node,
|
||||
float width,
|
||||
float height)
|
||||
float height,
|
||||
float resource_scale)
|
||||
{
|
||||
gboolean had_prerendered_texture = FALSE;
|
||||
gboolean had_box_shadow = FALSE;
|
||||
@@ -1573,12 +1633,13 @@ st_theme_node_update_resources (StThemeNodePaintState *state,
|
||||
st_theme_node_paint_state_set_node (state, node);
|
||||
state->alloc_width = width;
|
||||
state->alloc_height = height;
|
||||
state->resource_scale = resource_scale;
|
||||
|
||||
box_shadow_spec = st_theme_node_get_box_shadow (node);
|
||||
|
||||
if (had_prerendered_texture)
|
||||
{
|
||||
state->prerendered_texture = st_theme_node_prerender_background (node, width, height);
|
||||
state->prerendered_texture = st_theme_node_prerender_background (node, width, height, resource_scale);
|
||||
state->prerendered_pipeline = _st_create_texture_pipeline (state->prerendered_texture);
|
||||
}
|
||||
else
|
||||
@@ -1588,12 +1649,13 @@ st_theme_node_update_resources (StThemeNodePaintState *state,
|
||||
for (corner_id = 0; corner_id < 4; corner_id++)
|
||||
if (state->corner_material[corner_id] == NULL)
|
||||
state->corner_material[corner_id] =
|
||||
st_theme_node_lookup_corner (node, width, height, corner_id);
|
||||
st_theme_node_lookup_corner (node, width, height, resource_scale, corner_id);
|
||||
}
|
||||
|
||||
if (had_box_shadow)
|
||||
state->box_shadow_pipeline = _st_create_shadow_pipeline (box_shadow_spec,
|
||||
state->prerendered_texture);
|
||||
state->prerendered_texture,
|
||||
state->resource_scale);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -2223,6 +2285,7 @@ st_theme_node_prerender_shadow (StThemeNodePaintState *state)
|
||||
guint border_radius[4];
|
||||
int max_borders[4];
|
||||
int center_radius, corner_id;
|
||||
int fb_width, fb_height;
|
||||
CoglTexture *buffer;
|
||||
CoglFramebuffer *offscreen = NULL;
|
||||
CoglError *error = NULL;
|
||||
@@ -2264,9 +2327,9 @@ st_theme_node_prerender_shadow (StThemeNodePaintState *state)
|
||||
}
|
||||
|
||||
/* Render offscreen */
|
||||
buffer = COGL_TEXTURE (cogl_texture_2d_new_with_size (ctx,
|
||||
state->box_shadow_width,
|
||||
state->box_shadow_height));
|
||||
fb_width = ceilf (state->box_shadow_width * state->resource_scale);
|
||||
fb_height = ceilf (state->box_shadow_height * state->resource_scale);
|
||||
buffer = COGL_TEXTURE (cogl_texture_2d_new_with_size (ctx, fb_width, fb_height));
|
||||
if (buffer == NULL)
|
||||
return;
|
||||
|
||||
@@ -2277,14 +2340,16 @@ st_theme_node_prerender_shadow (StThemeNodePaintState *state)
|
||||
ClutterActorBox box = { 0, 0, state->box_shadow_width, state->box_shadow_height};
|
||||
|
||||
cogl_framebuffer_orthographic (offscreen, 0, 0,
|
||||
state->box_shadow_width,
|
||||
state->box_shadow_height, 0, 1.0);
|
||||
fb_width, fb_height, 0, 1.0);
|
||||
cogl_framebuffer_scale (offscreen,
|
||||
state->resource_scale,
|
||||
state->resource_scale, 1);
|
||||
cogl_framebuffer_clear4f (offscreen, COGL_BUFFER_BIT_COLOR, 0, 0, 0, 0);
|
||||
|
||||
st_theme_node_paint_borders (state, offscreen, &box, 0xFF);
|
||||
|
||||
state->box_shadow_pipeline = _st_create_shadow_pipeline (st_theme_node_get_box_shadow (node),
|
||||
buffer);
|
||||
buffer, state->resource_scale);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -2457,11 +2522,16 @@ static gboolean
|
||||
st_theme_node_needs_new_box_shadow_for_size (StThemeNodePaintState *state,
|
||||
StThemeNode *node,
|
||||
float width,
|
||||
float height)
|
||||
float height,
|
||||
float resource_scale)
|
||||
{
|
||||
if (!node->rendered_once)
|
||||
return TRUE;
|
||||
|
||||
/* The resource scale changed, so need to recompute a new box-shadow */
|
||||
if (fabsf (state->resource_scale - resource_scale) > FLT_EPSILON)
|
||||
return TRUE;
|
||||
|
||||
/* The allocation hasn't changed, no need to recompute a new
|
||||
box-shadow. */
|
||||
if (state->alloc_width == width &&
|
||||
@@ -2495,7 +2565,8 @@ st_theme_node_paint (StThemeNode *node,
|
||||
StThemeNodePaintState *state,
|
||||
CoglFramebuffer *framebuffer,
|
||||
const ClutterActorBox *box,
|
||||
guint8 paint_opacity)
|
||||
guint8 paint_opacity,
|
||||
float resource_scale)
|
||||
{
|
||||
float width, height;
|
||||
ClutterActorBox allocation;
|
||||
@@ -2507,7 +2578,7 @@ st_theme_node_paint (StThemeNode *node,
|
||||
allocation.x2 = width;
|
||||
allocation.y2 = height;
|
||||
|
||||
if (width <= 0 || height <= 0)
|
||||
if (width <= 0 || height <= 0 || resource_scale <= 0.0f)
|
||||
return;
|
||||
|
||||
/* Check whether we need to recreate the textures of the paint
|
||||
@@ -2516,22 +2587,25 @@ st_theme_node_paint (StThemeNode *node,
|
||||
* 2) the allocation size change requires recreating textures
|
||||
*/
|
||||
if (state->node != node ||
|
||||
st_theme_node_needs_new_box_shadow_for_size (state, node, width, height))
|
||||
st_theme_node_needs_new_box_shadow_for_size (state, node, width, height,
|
||||
resource_scale))
|
||||
{
|
||||
/* If we had the ability to cache textures on the node, then we
|
||||
can just copy them over to the paint state and avoid all
|
||||
rendering. We end up sharing textures a cross different
|
||||
widgets. */
|
||||
if (node->rendered_once && node->cached_textures &&
|
||||
width >= node->box_shadow_min_width && height >= node->box_shadow_min_height)
|
||||
width >= node->box_shadow_min_width && height >= node->box_shadow_min_height &&
|
||||
fabsf (resource_scale - state->resource_scale) < FLT_EPSILON)
|
||||
st_theme_node_paint_state_copy (state, &node->cached_state);
|
||||
else
|
||||
st_theme_node_render_resources (state, node, width, height);
|
||||
st_theme_node_render_resources (state, node, width, height, resource_scale);
|
||||
|
||||
node->rendered_once = TRUE;
|
||||
}
|
||||
else if (state->alloc_width != width || state->alloc_height != height)
|
||||
st_theme_node_update_resources (state, node, width, height);
|
||||
else if (state->alloc_width != width || state->alloc_height != height ||
|
||||
fabsf (state->resource_scale - resource_scale) > FLT_EPSILON)
|
||||
st_theme_node_update_resources (state, node, width, height, resource_scale);
|
||||
|
||||
/* Rough notes about the relationship of borders and backgrounds in CSS3;
|
||||
* see http://www.w3.org/TR/css3-background/ for more accurate details.
|
||||
@@ -2576,7 +2650,7 @@ st_theme_node_paint (StThemeNode *node,
|
||||
}
|
||||
|
||||
if (state->prerendered_pipeline != NULL ||
|
||||
st_theme_node_load_border_image (node))
|
||||
st_theme_node_load_border_image (node, resource_scale))
|
||||
{
|
||||
if (state->prerendered_pipeline != NULL)
|
||||
{
|
||||
@@ -2604,7 +2678,7 @@ st_theme_node_paint (StThemeNode *node,
|
||||
st_theme_node_paint_outline (node, framebuffer, box, paint_opacity);
|
||||
|
||||
if (state->prerendered_pipeline == NULL &&
|
||||
st_theme_node_load_background_image (node))
|
||||
st_theme_node_load_background_image (node, resource_scale))
|
||||
{
|
||||
ClutterActorBox background_box;
|
||||
ClutterActorBox texture_coords;
|
||||
@@ -2616,7 +2690,8 @@ st_theme_node_paint (StThemeNode *node,
|
||||
*/
|
||||
has_visible_outline = st_theme_node_has_visible_outline (node);
|
||||
|
||||
get_background_position (node, &allocation, &background_box, &texture_coords);
|
||||
get_background_position (node, &allocation, resource_scale,
|
||||
&background_box, &texture_coords);
|
||||
|
||||
if (has_visible_outline || node->background_repeat)
|
||||
cogl_framebuffer_push_rectangle_clip (framebuffer,
|
||||
@@ -2707,6 +2782,7 @@ st_theme_node_paint_state_init (StThemeNodePaintState *state)
|
||||
|
||||
state->alloc_width = 0;
|
||||
state->alloc_height = 0;
|
||||
state->resource_scale = -1;
|
||||
state->node = NULL;
|
||||
state->box_shadow_pipeline = NULL;
|
||||
state->prerendered_texture = NULL;
|
||||
@@ -2731,6 +2807,7 @@ st_theme_node_paint_state_copy (StThemeNodePaintState *state,
|
||||
|
||||
state->alloc_width = other->alloc_width;
|
||||
state->alloc_height = other->alloc_height;
|
||||
state->resource_scale = other->resource_scale;
|
||||
state->box_shadow_width = other->box_shadow_width;
|
||||
state->box_shadow_height = other->box_shadow_height;
|
||||
|
||||
@@ -2750,6 +2827,7 @@ st_theme_node_paint_state_invalidate (StThemeNodePaintState *state)
|
||||
{
|
||||
state->alloc_width = 0;
|
||||
state->alloc_height = 0;
|
||||
state->resource_scale = -1.0f;
|
||||
}
|
||||
|
||||
gboolean
|
||||
|
||||
@@ -19,6 +19,8 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <math.h>
|
||||
|
||||
#include "st-theme-node-transition.h"
|
||||
|
||||
enum {
|
||||
@@ -117,6 +119,10 @@ st_theme_node_transition_new (StThemeNode *from_node,
|
||||
return transition;
|
||||
}
|
||||
|
||||
/**
|
||||
* st_theme_node_transition_get_new_paint_state: (skip)
|
||||
*
|
||||
*/
|
||||
StThemeNodePaintState *
|
||||
st_theme_node_transition_get_new_paint_state (StThemeNodeTransition *transition)
|
||||
{
|
||||
@@ -237,7 +243,8 @@ st_theme_node_transition_get_paint_box (StThemeNodeTransition *transition,
|
||||
|
||||
static gboolean
|
||||
setup_framebuffers (StThemeNodeTransition *transition,
|
||||
const ClutterActorBox *allocation)
|
||||
const ClutterActorBox *allocation,
|
||||
float resource_scale)
|
||||
{
|
||||
StThemeNodeTransitionPrivate *priv = transition->priv;
|
||||
CoglContext *ctx;
|
||||
@@ -248,8 +255,8 @@ setup_framebuffers (StThemeNodeTransition *transition,
|
||||
static CoglPipeline *material_template = NULL;
|
||||
|
||||
ctx = clutter_backend_get_cogl_context (clutter_get_default_backend ());
|
||||
width = priv->offscreen_box.x2 - priv->offscreen_box.x1;
|
||||
height = priv->offscreen_box.y2 - priv->offscreen_box.y1;
|
||||
width = ceilf ((priv->offscreen_box.x2 - priv->offscreen_box.x1) * resource_scale);
|
||||
height = ceilf ((priv->offscreen_box.y2 - priv->offscreen_box.y1) * resource_scale);
|
||||
|
||||
g_return_val_if_fail (width > 0, FALSE);
|
||||
g_return_val_if_fail (height > 0, FALSE);
|
||||
@@ -320,7 +327,7 @@ setup_framebuffers (StThemeNodeTransition *transition,
|
||||
priv->offscreen_box.y2, 0.0, 1.0);
|
||||
|
||||
st_theme_node_paint (priv->old_theme_node, &priv->old_paint_state,
|
||||
priv->old_offscreen, allocation, 255);
|
||||
priv->old_offscreen, allocation, 255, resource_scale);
|
||||
|
||||
cogl_framebuffer_clear4f (priv->new_offscreen, COGL_BUFFER_BIT_COLOR,
|
||||
0, 0, 0, 0);
|
||||
@@ -330,7 +337,7 @@ setup_framebuffers (StThemeNodeTransition *transition,
|
||||
priv->offscreen_box.x2,
|
||||
priv->offscreen_box.y2, 0.0, 1.0);
|
||||
st_theme_node_paint (priv->new_theme_node, &priv->new_paint_state,
|
||||
priv->new_offscreen, allocation, 255);
|
||||
priv->new_offscreen, allocation, 255, resource_scale);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
@@ -339,7 +346,8 @@ void
|
||||
st_theme_node_transition_paint (StThemeNodeTransition *transition,
|
||||
CoglFramebuffer *framebuffer,
|
||||
ClutterActorBox *allocation,
|
||||
guint8 paint_opacity)
|
||||
guint8 paint_opacity,
|
||||
float resource_scale)
|
||||
{
|
||||
StThemeNodeTransitionPrivate *priv = transition->priv;
|
||||
|
||||
@@ -360,7 +368,8 @@ st_theme_node_transition_paint (StThemeNodeTransition *transition,
|
||||
priv->last_allocation = *allocation;
|
||||
|
||||
calculate_offscreen_box (transition, allocation);
|
||||
priv->needs_setup = !setup_framebuffers (transition, allocation);
|
||||
priv->needs_setup = !setup_framebuffers (transition, allocation,
|
||||
resource_scale);
|
||||
|
||||
if (priv->needs_setup) /* setting up framebuffers failed */
|
||||
return;
|
||||
|
||||
@@ -43,7 +43,8 @@ void st_theme_node_transition_update (StThemeNodeTransition *transition,
|
||||
void st_theme_node_transition_paint (StThemeNodeTransition *transition,
|
||||
CoglFramebuffer *framebuffer,
|
||||
ClutterActorBox *allocation,
|
||||
guint8 paint_opacity);
|
||||
guint8 paint_opacity,
|
||||
float resource_scale);
|
||||
|
||||
void st_theme_node_transition_get_paint_box (StThemeNodeTransition *transition,
|
||||
const ClutterActorBox *allocation,
|
||||
|
||||
@@ -104,6 +104,8 @@ struct _StThemeNodePaintState {
|
||||
float box_shadow_width;
|
||||
float box_shadow_height;
|
||||
|
||||
float resource_scale;
|
||||
|
||||
CoglPipeline *box_shadow_pipeline;
|
||||
CoglPipeline *prerendered_texture;
|
||||
CoglPipeline *prerendered_pipeline;
|
||||
@@ -279,7 +281,8 @@ void st_theme_node_paint (StThemeNode *node,
|
||||
StThemeNodePaintState *state,
|
||||
CoglFramebuffer *framebuffer,
|
||||
const ClutterActorBox *box,
|
||||
guint8 paint_opacity);
|
||||
guint8 paint_opacity,
|
||||
float resource_scale);
|
||||
|
||||
void st_theme_node_invalidate_background_image (StThemeNode *node);
|
||||
void st_theme_node_invalidate_border_image (StThemeNode *node);
|
||||
|
||||
@@ -80,11 +80,8 @@ struct _StWidgetPrivate
|
||||
ClutterActor *label_actor;
|
||||
gchar *accessible_name;
|
||||
|
||||
/* Even though Clutter has first_child/last_child properties,
|
||||
* we need to keep track of the old first/last children so
|
||||
* that we can remove the pseudo classes on them. */
|
||||
StWidget *prev_last_child;
|
||||
StWidget *prev_first_child;
|
||||
StWidget *last_visible_child;
|
||||
StWidget *first_visible_child;
|
||||
|
||||
StThemeNodePaintState paint_states[2];
|
||||
int current_paint_state : 2;
|
||||
@@ -121,6 +118,7 @@ enum
|
||||
{
|
||||
STYLE_CHANGED,
|
||||
POPUP_MENU,
|
||||
RESOURCE_SCALE_CHANGED,
|
||||
|
||||
LAST_SIGNAL
|
||||
};
|
||||
@@ -321,8 +319,8 @@ st_widget_dispose (GObject *gobject)
|
||||
priv->texture_file_changed_id = 0;
|
||||
}
|
||||
|
||||
g_clear_object (&priv->prev_first_child);
|
||||
g_clear_object (&priv->prev_last_child);
|
||||
g_clear_object (&priv->first_visible_child);
|
||||
g_clear_object (&priv->last_visible_child);
|
||||
|
||||
G_OBJECT_CLASS (st_widget_parent_class)->dispose (gobject);
|
||||
}
|
||||
@@ -417,8 +415,12 @@ st_widget_paint_background (StWidget *widget)
|
||||
CoglFramebuffer *framebuffer;
|
||||
StThemeNode *theme_node;
|
||||
ClutterActorBox allocation;
|
||||
float resource_scale;
|
||||
guint8 opacity;
|
||||
|
||||
if (!st_widget_get_resource_scale (widget, &resource_scale))
|
||||
return;
|
||||
|
||||
framebuffer = cogl_get_draw_framebuffer ();
|
||||
theme_node = st_widget_get_theme_node (widget);
|
||||
|
||||
@@ -430,13 +432,15 @@ st_widget_paint_background (StWidget *widget)
|
||||
st_theme_node_transition_paint (priv->transition_animation,
|
||||
framebuffer,
|
||||
&allocation,
|
||||
opacity);
|
||||
opacity,
|
||||
resource_scale);
|
||||
else
|
||||
st_theme_node_paint (theme_node,
|
||||
current_paint_state (widget),
|
||||
framebuffer,
|
||||
&allocation,
|
||||
opacity);
|
||||
opacity,
|
||||
resource_scale);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -452,6 +456,7 @@ static void
|
||||
st_widget_parent_set (ClutterActor *widget,
|
||||
ClutterActor *old_parent)
|
||||
{
|
||||
StWidget *self = ST_WIDGET (widget);
|
||||
ClutterActorClass *parent_class;
|
||||
ClutterActor *new_parent;
|
||||
|
||||
@@ -463,7 +468,7 @@ st_widget_parent_set (ClutterActor *widget,
|
||||
|
||||
/* don't send the style changed signal if we no longer have a parent actor */
|
||||
if (new_parent)
|
||||
st_widget_style_changed (ST_WIDGET (widget));
|
||||
st_widget_style_changed (self);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -574,7 +579,11 @@ get_root_theme_node (ClutterStage *stage)
|
||||
StThemeNode *
|
||||
st_widget_get_theme_node (StWidget *widget)
|
||||
{
|
||||
StWidgetPrivate *priv = st_widget_get_instance_private (widget);
|
||||
StWidgetPrivate *priv;
|
||||
|
||||
g_return_val_if_fail (ST_IS_WIDGET (widget), NULL);
|
||||
|
||||
priv = st_widget_get_instance_private (widget);
|
||||
|
||||
if (priv->theme_node == NULL)
|
||||
{
|
||||
@@ -1019,6 +1028,21 @@ st_widget_class_init (StWidgetClass *klass)
|
||||
G_STRUCT_OFFSET (StWidgetClass, popup_menu),
|
||||
NULL, NULL, NULL,
|
||||
G_TYPE_NONE, 0);
|
||||
|
||||
/**
|
||||
* StWidget::resource-scale-changed:
|
||||
* @widget: the #StWidget
|
||||
*
|
||||
* Emitted when the paint scale that the widget will be painted as
|
||||
* changed.
|
||||
*/
|
||||
signals[RESOURCE_SCALE_CHANGED] =
|
||||
g_signal_new ("resource-scale-changed",
|
||||
G_TYPE_FROM_CLASS (klass),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
G_STRUCT_OFFSET (StWidgetClass, resource_scale_changed),
|
||||
NULL, NULL, NULL,
|
||||
G_TYPE_NONE, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1448,6 +1472,81 @@ st_widget_get_style (StWidget *actor)
|
||||
return ST_WIDGET_PRIVATE (actor)->inline_style;
|
||||
}
|
||||
|
||||
/**
|
||||
* st_widget_get_resource_scale:
|
||||
* @widget: A #StWidget
|
||||
* @resource_scale: (out): return location for the resource scale
|
||||
*
|
||||
* Retrieves the resource scale for this #StWidget, if available.
|
||||
*
|
||||
* The resource scale refers to the scale the actor should use for its resources.
|
||||
*/
|
||||
gboolean
|
||||
st_widget_get_resource_scale (StWidget *widget,
|
||||
float *resource_scale)
|
||||
{
|
||||
return clutter_actor_get_resource_scale (CLUTTER_ACTOR (widget),
|
||||
resource_scale);
|
||||
}
|
||||
|
||||
static void
|
||||
st_widget_set_first_visible_child (StWidget *widget,
|
||||
ClutterActor *actor)
|
||||
{
|
||||
StWidgetPrivate *priv = st_widget_get_instance_private (widget);
|
||||
|
||||
if (priv->first_visible_child == NULL && actor == NULL)
|
||||
return;
|
||||
|
||||
if (priv->first_visible_child != NULL &&
|
||||
CLUTTER_ACTOR (priv->first_visible_child) == actor)
|
||||
return;
|
||||
|
||||
if (priv->first_visible_child != NULL)
|
||||
{
|
||||
st_widget_remove_style_pseudo_class (priv->first_visible_child, "first-child");
|
||||
g_clear_object (&priv->first_visible_child);
|
||||
}
|
||||
|
||||
if (actor == NULL)
|
||||
return;
|
||||
|
||||
if (ST_IS_WIDGET (actor))
|
||||
{
|
||||
st_widget_add_style_pseudo_class (ST_WIDGET (actor), "first-child");
|
||||
priv->first_visible_child = g_object_ref (ST_WIDGET (actor));
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
st_widget_set_last_visible_child (StWidget *widget,
|
||||
ClutterActor *actor)
|
||||
{
|
||||
StWidgetPrivate *priv = st_widget_get_instance_private (widget);
|
||||
|
||||
if (priv->last_visible_child == NULL && actor == NULL)
|
||||
return;
|
||||
|
||||
if (priv->last_visible_child != NULL &&
|
||||
CLUTTER_ACTOR (priv->last_visible_child) == actor)
|
||||
return;
|
||||
|
||||
if (priv->last_visible_child != NULL)
|
||||
{
|
||||
st_widget_remove_style_pseudo_class (priv->last_visible_child, "last-child");
|
||||
g_clear_object (&priv->last_visible_child);
|
||||
}
|
||||
|
||||
if (actor == NULL)
|
||||
return;
|
||||
|
||||
if (ST_IS_WIDGET (actor))
|
||||
{
|
||||
st_widget_add_style_pseudo_class (ST_WIDGET (actor), "last-child");
|
||||
priv->last_visible_child = g_object_ref (ST_WIDGET (actor));
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
st_widget_name_notify (StWidget *widget,
|
||||
GParamSpec *pspec,
|
||||
@@ -1456,6 +1555,23 @@ st_widget_name_notify (StWidget *widget,
|
||||
st_widget_style_changed (widget);
|
||||
}
|
||||
|
||||
static void
|
||||
st_widget_resource_scale_notify (StWidget *widget,
|
||||
GParamSpec *pspec,
|
||||
gpointer data)
|
||||
{
|
||||
StWidgetPrivate *priv = st_widget_get_instance_private (widget);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < G_N_ELEMENTS (priv->paint_states); i++)
|
||||
st_theme_node_paint_state_invalidate (&priv->paint_states[i]);
|
||||
|
||||
g_signal_emit (widget, signals[RESOURCE_SCALE_CHANGED], 0);
|
||||
|
||||
if (clutter_actor_is_mapped (CLUTTER_ACTOR (widget)))
|
||||
clutter_actor_queue_redraw (CLUTTER_ACTOR (widget));
|
||||
}
|
||||
|
||||
static void
|
||||
st_widget_reactive_notify (StWidget *widget,
|
||||
GParamSpec *pspec,
|
||||
@@ -1472,30 +1588,78 @@ st_widget_reactive_notify (StWidget *widget,
|
||||
st_widget_sync_hover(widget);
|
||||
}
|
||||
|
||||
static ClutterActor *
|
||||
find_nearest_visible_backwards (ClutterActor *actor)
|
||||
{
|
||||
ClutterActor *prev = actor;
|
||||
|
||||
while (prev != NULL && !clutter_actor_is_visible (prev))
|
||||
prev = clutter_actor_get_previous_sibling (prev);
|
||||
return prev;
|
||||
}
|
||||
|
||||
static ClutterActor *
|
||||
find_nearest_visible_forward (ClutterActor *actor)
|
||||
{
|
||||
ClutterActor *next = actor;
|
||||
|
||||
while (next != NULL && !clutter_actor_is_visible (next))
|
||||
next = clutter_actor_get_next_sibling (next);
|
||||
return next;
|
||||
}
|
||||
|
||||
static void
|
||||
st_widget_visible_notify (StWidget *widget,
|
||||
GParamSpec *pspec,
|
||||
gpointer data)
|
||||
{
|
||||
ClutterActor *actor = CLUTTER_ACTOR (widget);
|
||||
ClutterActor *parent = clutter_actor_get_parent (actor);
|
||||
|
||||
if (parent == NULL || !ST_IS_WIDGET (parent))
|
||||
return;
|
||||
|
||||
if (clutter_actor_is_visible (actor))
|
||||
{
|
||||
ClutterActor *before, *after;
|
||||
|
||||
before = clutter_actor_get_previous_sibling (actor);
|
||||
if (find_nearest_visible_backwards (before) == NULL)
|
||||
st_widget_set_first_visible_child (ST_WIDGET (parent), actor);
|
||||
|
||||
after = clutter_actor_get_next_sibling (actor);
|
||||
if (find_nearest_visible_forward (after) == NULL)
|
||||
st_widget_set_last_visible_child (ST_WIDGET (parent), actor);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (st_widget_has_style_pseudo_class (widget, "first-child"))
|
||||
{
|
||||
ClutterActor *new_first;
|
||||
|
||||
new_first = find_nearest_visible_forward (CLUTTER_ACTOR (widget));
|
||||
st_widget_set_first_visible_child (ST_WIDGET (parent), new_first);
|
||||
}
|
||||
|
||||
if (st_widget_has_style_pseudo_class (widget, "last-child"))
|
||||
{
|
||||
ClutterActor *new_last;
|
||||
|
||||
new_last = find_nearest_visible_backwards (CLUTTER_ACTOR (widget));
|
||||
st_widget_set_last_visible_child (ST_WIDGET (parent), new_last);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
st_widget_first_child_notify (StWidget *widget,
|
||||
GParamSpec *pspec,
|
||||
gpointer data)
|
||||
{
|
||||
StWidgetPrivate *priv = st_widget_get_instance_private (widget);
|
||||
ClutterActor *first_child;
|
||||
|
||||
if (priv->prev_first_child != NULL)
|
||||
{
|
||||
st_widget_remove_style_pseudo_class (priv->prev_first_child, "first-child");
|
||||
g_clear_object (&priv->prev_first_child);
|
||||
}
|
||||
|
||||
first_child = clutter_actor_get_first_child (CLUTTER_ACTOR (widget));
|
||||
|
||||
if (first_child == NULL)
|
||||
return;
|
||||
|
||||
if (ST_IS_WIDGET (first_child))
|
||||
{
|
||||
st_widget_add_style_pseudo_class (ST_WIDGET (first_child), "first-child");
|
||||
priv->prev_first_child = g_object_ref (ST_WIDGET (first_child));
|
||||
}
|
||||
st_widget_set_first_visible_child (widget, find_nearest_visible_forward (first_child));
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -1503,25 +1667,10 @@ st_widget_last_child_notify (StWidget *widget,
|
||||
GParamSpec *pspec,
|
||||
gpointer data)
|
||||
{
|
||||
StWidgetPrivate *priv = st_widget_get_instance_private (widget);
|
||||
ClutterActor *last_child;
|
||||
|
||||
if (priv->prev_last_child != NULL)
|
||||
{
|
||||
st_widget_remove_style_pseudo_class (priv->prev_last_child, "last-child");
|
||||
g_clear_object (&priv->prev_last_child);
|
||||
}
|
||||
|
||||
last_child = clutter_actor_get_last_child (CLUTTER_ACTOR (widget));
|
||||
|
||||
if (last_child == NULL)
|
||||
return;
|
||||
|
||||
if (ST_IS_WIDGET (last_child))
|
||||
{
|
||||
st_widget_add_style_pseudo_class (ST_WIDGET (last_child), "last-child");
|
||||
priv->prev_last_child = g_object_ref (ST_WIDGET (last_child));
|
||||
}
|
||||
st_widget_set_last_visible_child (widget, find_nearest_visible_backwards (last_child));
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -1536,8 +1685,10 @@ st_widget_init (StWidget *actor)
|
||||
|
||||
/* connect style changed */
|
||||
g_signal_connect (actor, "notify::name", G_CALLBACK (st_widget_name_notify), NULL);
|
||||
g_signal_connect (actor, "notify::resource-scale", G_CALLBACK (st_widget_resource_scale_notify), NULL);
|
||||
g_signal_connect (actor, "notify::reactive", G_CALLBACK (st_widget_reactive_notify), NULL);
|
||||
|
||||
g_signal_connect (actor, "notify::visible", G_CALLBACK (st_widget_visible_notify), NULL);
|
||||
g_signal_connect (actor, "notify::first-child", G_CALLBACK (st_widget_first_child_notify), NULL);
|
||||
g_signal_connect (actor, "notify::last-child", G_CALLBACK (st_widget_last_child_notify), NULL);
|
||||
priv->texture_file_changed_id = g_signal_connect (st_texture_cache_get_default (), "texture-file-changed",
|
||||
|
||||
@@ -63,6 +63,7 @@ struct _StWidgetClass
|
||||
/* signals */
|
||||
void (* style_changed) (StWidget *self);
|
||||
void (* popup_menu) (StWidget *self);
|
||||
void (* resource_scale_changed) (StWidget *self);
|
||||
|
||||
/* vfuncs */
|
||||
|
||||
@@ -137,6 +138,8 @@ StThemeNode * st_widget_peek_theme_node (StWidget *widg
|
||||
|
||||
GList * st_widget_get_focus_chain (StWidget *widget);
|
||||
void st_widget_paint_background (StWidget *widget);
|
||||
gboolean st_widget_get_resource_scale (StWidget *widget,
|
||||
float *resource_scale);
|
||||
|
||||
/* debug methods */
|
||||
char *st_describe_actor (ClutterActor *actor);
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include "st-theme.h"
|
||||
#include "st-theme-context.h"
|
||||
#include "st-label.h"
|
||||
#include "st-button.h"
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
|
||||
@@ -37,7 +38,7 @@ static StThemeNode *group3;
|
||||
static StThemeNode *group4;
|
||||
static StThemeNode *group5;
|
||||
static StThemeNode *group6;
|
||||
static StThemeNode *cairo_texture;
|
||||
static StThemeNode *button;
|
||||
static gboolean fail;
|
||||
|
||||
static const char *test;
|
||||
@@ -280,7 +281,7 @@ test_classes (void)
|
||||
{
|
||||
test = "classes";
|
||||
/* .special-text class overrides size and style;
|
||||
* the ClutterTexture.special-text selector doesn't match */
|
||||
* the StBin.special-text selector doesn't match */
|
||||
assert_font (text1, "text1", "sans-serif Italic 32px");
|
||||
}
|
||||
|
||||
@@ -288,12 +289,12 @@ static void
|
||||
test_type_inheritance (void)
|
||||
{
|
||||
test = "type_inheritance";
|
||||
/* From ClutterTexture element selector */
|
||||
assert_length ("cairoTexture", "padding-top", 10.,
|
||||
st_theme_node_get_padding (cairo_texture, ST_SIDE_TOP));
|
||||
/* From ClutterCairoTexture element selector */
|
||||
assert_length ("cairoTexture", "padding-right", 20.,
|
||||
st_theme_node_get_padding (cairo_texture, ST_SIDE_RIGHT));
|
||||
/* From StBin element selector */
|
||||
assert_length ("button", "padding-top", 10.,
|
||||
st_theme_node_get_padding (button, ST_SIDE_TOP));
|
||||
/* From StButton element selector */
|
||||
assert_length ("button", "padding-right", 20.,
|
||||
st_theme_node_get_padding (button, ST_SIDE_RIGHT));
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -410,15 +411,15 @@ test_background (void)
|
||||
test = "background";
|
||||
/* group1 has a background: shortcut property setting color and image */
|
||||
assert_background_color (group1, "group1", 0xff0000ff);
|
||||
assert_background_image (group1, "group1", "st/some-background.png");
|
||||
assert_background_image (group1, "group1", "some-background.png");
|
||||
/* text1 inherits the background image but not the color */
|
||||
assert_background_color (text1, "text1", 0x00000000);
|
||||
assert_background_image (text1, "text1", "st/some-background.png");
|
||||
assert_background_image (text1, "text1", "some-background.png");
|
||||
/* text2 inherits both, but then background: none overrides both */
|
||||
assert_background_color (text2, "text2", 0x00000000);
|
||||
assert_background_image (text2, "text2", NULL);
|
||||
/* background-image property */
|
||||
assert_background_image (group2, "group2", "st/other-background.png");
|
||||
assert_background_image (group2, "group2", "other-background.png");
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -541,7 +542,10 @@ main (int argc, char **argv)
|
||||
if (clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS)
|
||||
return 1;
|
||||
|
||||
file = g_file_new_for_path ("st/test-theme.css");
|
||||
/* Make sure our assumptions about resolution are correct */
|
||||
g_object_set (clutter_settings_get_default (), "font-dpi", -1, NULL);
|
||||
|
||||
file = g_file_new_for_path ("test-theme.css");
|
||||
theme = st_theme_new (file, NULL, NULL);
|
||||
g_object_unref (file);
|
||||
|
||||
@@ -575,8 +579,8 @@ main (int argc, char **argv)
|
||||
CLUTTER_TYPE_TEXT, "text4", NULL, "visited hover", NULL);
|
||||
group3 = st_theme_node_new (context, group2, NULL,
|
||||
CLUTTER_TYPE_GROUP, "group3", NULL, "hover", NULL);
|
||||
cairo_texture = st_theme_node_new (context, root, NULL,
|
||||
CLUTTER_TYPE_CAIRO_TEXTURE, "cairoTexture", NULL, NULL, NULL);
|
||||
button = st_theme_node_new (context, root, NULL,
|
||||
ST_TYPE_BUTTON, "button", NULL, NULL, NULL);
|
||||
|
||||
test_defaults ();
|
||||
test_lengths ();
|
||||
@@ -592,7 +596,7 @@ main (int argc, char **argv)
|
||||
test_pseudo_class ();
|
||||
test_inline_style ();
|
||||
|
||||
g_object_unref (cairo_texture);
|
||||
g_object_unref (button);
|
||||
g_object_unref (group1);
|
||||
g_object_unref (group2);
|
||||
g_object_unref (group3);
|
||||
|
||||
@@ -26,7 +26,7 @@ stage {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
ClutterTexture.special-text {
|
||||
StBin.special-text {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
@@ -52,11 +52,11 @@ ClutterTexture.special-text {
|
||||
font-feature-settings: normal;
|
||||
}
|
||||
|
||||
ClutterTexture {
|
||||
StBin {
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
ClutterCairoTexture {
|
||||
StButton {
|
||||
padding-right: 20px;
|
||||
}
|
||||
|
||||
|
||||
@@ -52,7 +52,9 @@ na_tray_child_realize (GtkWidget *widget)
|
||||
|
||||
/* Set a transparent background */
|
||||
cairo_pattern_t *transparent = cairo_pattern_create_rgba (0, 0, 0, 0);
|
||||
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
|
||||
gdk_window_set_background_pattern (window, transparent);
|
||||
G_GNUC_END_IGNORE_DEPRECATIONS
|
||||
cairo_pattern_destroy (transparent);
|
||||
|
||||
child->parent_relative_bg = FALSE;
|
||||
@@ -61,7 +63,9 @@ na_tray_child_realize (GtkWidget *widget)
|
||||
{
|
||||
/* Otherwise, if the visual matches the visual of the parent window, we
|
||||
* can use a parent-relative background and fake transparency. */
|
||||
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
|
||||
gdk_window_set_background_pattern (window, NULL);
|
||||
G_GNUC_END_IGNORE_DEPRECATIONS
|
||||
|
||||
child->parent_relative_bg = TRUE;
|
||||
}
|
||||
@@ -242,6 +246,7 @@ na_tray_child_new (GdkScreen *screen,
|
||||
Window icon_window)
|
||||
{
|
||||
XWindowAttributes window_attributes;
|
||||
GdkDisplay *display;
|
||||
Display *xdisplay;
|
||||
NaTrayChild *child;
|
||||
GdkVisual *visual;
|
||||
@@ -253,15 +258,16 @@ na_tray_child_new (GdkScreen *screen,
|
||||
g_return_val_if_fail (icon_window != None, NULL);
|
||||
|
||||
xdisplay = GDK_SCREEN_XDISPLAY (screen);
|
||||
display = gdk_x11_lookup_xdisplay (xdisplay);
|
||||
|
||||
/* We need to determine the visual of the window we are embedding and create
|
||||
* the socket in the same visual.
|
||||
*/
|
||||
|
||||
gdk_error_trap_push ();
|
||||
gdk_x11_display_error_trap_push (display);
|
||||
result = XGetWindowAttributes (xdisplay, icon_window,
|
||||
&window_attributes);
|
||||
gdk_error_trap_pop_ignored ();
|
||||
gdk_x11_display_error_trap_pop_ignored (display);
|
||||
|
||||
if (!result) /* Window already gone */
|
||||
return NULL;
|
||||
@@ -308,7 +314,7 @@ na_tray_child_get_title (NaTrayChild *child)
|
||||
utf8_string = gdk_x11_get_xatom_by_name_for_display (display, "UTF8_STRING");
|
||||
atom = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_NAME");
|
||||
|
||||
gdk_error_trap_push ();
|
||||
gdk_x11_display_error_trap_push (display);
|
||||
|
||||
result = XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display),
|
||||
child->icon_window,
|
||||
@@ -318,7 +324,7 @@ na_tray_child_get_title (NaTrayChild *child)
|
||||
&type, &format, &nitems,
|
||||
&bytes_after, (guchar **)&val);
|
||||
|
||||
if (gdk_error_trap_pop () || result != Success)
|
||||
if (gdk_x11_display_error_trap_pop (display) || result != Success)
|
||||
return NULL;
|
||||
|
||||
if (type != utf8_string ||
|
||||
@@ -377,7 +383,8 @@ na_tray_child_force_redraw (NaTrayChild *child)
|
||||
* icon is expecting the server to clear-to-background before
|
||||
* the redraw. It should be ok for GtkStatusIcon or EggTrayIcon.
|
||||
*/
|
||||
Display *xdisplay = GDK_DISPLAY_XDISPLAY (gtk_widget_get_display (widget));
|
||||
GdkDisplay *display = gtk_widget_get_display (widget);
|
||||
Display *xdisplay = GDK_DISPLAY_XDISPLAY (display);
|
||||
XEvent xev;
|
||||
GdkWindow *plug_window;
|
||||
GtkAllocation allocation;
|
||||
@@ -393,12 +400,12 @@ na_tray_child_force_redraw (NaTrayChild *child)
|
||||
xev.xexpose.height = allocation.height;
|
||||
xev.xexpose.count = 0;
|
||||
|
||||
gdk_error_trap_push ();
|
||||
gdk_x11_display_error_trap_push (display);
|
||||
XSendEvent (xdisplay,
|
||||
xev.xexpose.window,
|
||||
False, ExposureMask,
|
||||
&xev);
|
||||
gdk_error_trap_pop_ignored ();
|
||||
gdk_x11_display_error_trap_pop_ignored (display);
|
||||
#else
|
||||
/* Hiding and showing is the safe way to do it, but can result in more
|
||||
* flickering.
|
||||
@@ -435,14 +442,16 @@ _get_wmclass (Display *xdisplay,
|
||||
char **res_class,
|
||||
char **res_name)
|
||||
{
|
||||
GdkDisplay *display;
|
||||
XClassHint ch;
|
||||
|
||||
ch.res_name = NULL;
|
||||
ch.res_class = NULL;
|
||||
|
||||
gdk_error_trap_push ();
|
||||
display = gdk_x11_lookup_xdisplay (xdisplay);
|
||||
gdk_x11_display_error_trap_push (display);
|
||||
XGetClassHint (xdisplay, xwindow, &ch);
|
||||
gdk_error_trap_pop_ignored ();
|
||||
gdk_x11_display_error_trap_pop_ignored (display);
|
||||
|
||||
if (res_class)
|
||||
*res_class = NULL;
|
||||
|
||||
@@ -70,7 +70,7 @@ static guint manager_signals[LAST_SIGNAL];
|
||||
#define SYSTEM_TRAY_ORIENTATION_VERT 1
|
||||
|
||||
#ifdef GDK_WINDOWING_X11
|
||||
static gboolean na_tray_manager_check_running_screen_x11 (GdkScreen *screen);
|
||||
static gboolean na_tray_manager_check_running_screen_x11 ();
|
||||
#endif
|
||||
|
||||
static void na_tray_manager_finalize (GObject *object);
|
||||
@@ -682,15 +682,15 @@ na_tray_manager_set_colors_property (NaTrayManager *manager)
|
||||
#ifdef GDK_WINDOWING_X11
|
||||
|
||||
static gboolean
|
||||
na_tray_manager_manage_screen_x11 (NaTrayManager *manager,
|
||||
GdkScreen *screen)
|
||||
na_tray_manager_manage_screen_x11 (NaTrayManager *manager)
|
||||
{
|
||||
GdkDisplay *display;
|
||||
Screen *xscreen;
|
||||
GtkWidget *invisible;
|
||||
GdkWindow *window;
|
||||
char *selection_atom_name;
|
||||
guint32 timestamp;
|
||||
GdkScreen *screen;
|
||||
Screen *xscreen;
|
||||
GtkWidget *invisible;
|
||||
GdkWindow *window;
|
||||
char *selection_atom_name;
|
||||
guint32 timestamp;
|
||||
|
||||
g_return_val_if_fail (NA_IS_TRAY_MANAGER (manager), FALSE);
|
||||
g_return_val_if_fail (manager->screen == NULL, FALSE);
|
||||
@@ -699,10 +699,11 @@ na_tray_manager_manage_screen_x11 (NaTrayManager *manager,
|
||||
* we can't create another one.
|
||||
*/
|
||||
#if 0
|
||||
if (na_tray_manager_check_running_screen_x11 (screen))
|
||||
if (na_tray_manager_check_running_screen_x11 ())
|
||||
return FALSE;
|
||||
#endif
|
||||
|
||||
screen = gdk_screen_get_default ();
|
||||
manager->screen = screen;
|
||||
|
||||
display = gdk_screen_get_display (screen);
|
||||
@@ -715,7 +716,7 @@ na_tray_manager_manage_screen_x11 (NaTrayManager *manager,
|
||||
GDK_PROPERTY_CHANGE_MASK | GDK_STRUCTURE_MASK);
|
||||
|
||||
selection_atom_name = g_strdup_printf ("_NET_SYSTEM_TRAY_S%d",
|
||||
gdk_screen_get_number (screen));
|
||||
gdk_x11_get_default_screen ());
|
||||
manager->selection_atom = gdk_atom_intern (selection_atom_name, FALSE);
|
||||
g_free (selection_atom_name);
|
||||
|
||||
@@ -793,14 +794,12 @@ na_tray_manager_manage_screen_x11 (NaTrayManager *manager,
|
||||
#endif
|
||||
|
||||
gboolean
|
||||
na_tray_manager_manage_screen (NaTrayManager *manager,
|
||||
GdkScreen *screen)
|
||||
na_tray_manager_manage_screen (NaTrayManager *manager)
|
||||
{
|
||||
g_return_val_if_fail (GDK_IS_SCREEN (screen), FALSE);
|
||||
g_return_val_if_fail (manager->screen == NULL, FALSE);
|
||||
|
||||
#ifdef GDK_WINDOWING_X11
|
||||
return na_tray_manager_manage_screen_x11 (manager, screen);
|
||||
return na_tray_manager_manage_screen_x11 (manager);
|
||||
#else
|
||||
return FALSE;
|
||||
#endif
|
||||
@@ -809,15 +808,17 @@ na_tray_manager_manage_screen (NaTrayManager *manager,
|
||||
#ifdef GDK_WINDOWING_X11
|
||||
|
||||
static gboolean
|
||||
na_tray_manager_check_running_screen_x11 (GdkScreen *screen)
|
||||
na_tray_manager_check_running_screen_x11 ()
|
||||
{
|
||||
GdkDisplay *display;
|
||||
Atom selection_atom;
|
||||
char *selection_atom_name;
|
||||
GdkScreen *screen;
|
||||
Atom selection_atom;
|
||||
char *selection_atom_name;
|
||||
|
||||
screen = gdk_screen_get_default ();
|
||||
display = gdk_screen_get_display (screen);
|
||||
selection_atom_name = g_strdup_printf ("_NET_SYSTEM_TRAY_S%d",
|
||||
gdk_screen_get_number (screen));
|
||||
gdk_x11_get_default_screen ());
|
||||
selection_atom = gdk_x11_get_xatom_by_name_for_display (display,
|
||||
selection_atom_name);
|
||||
g_free (selection_atom_name);
|
||||
@@ -832,12 +833,10 @@ na_tray_manager_check_running_screen_x11 (GdkScreen *screen)
|
||||
#endif
|
||||
|
||||
gboolean
|
||||
na_tray_manager_check_running (GdkScreen *screen)
|
||||
na_tray_manager_check_running ()
|
||||
{
|
||||
g_return_val_if_fail (GDK_IS_SCREEN (screen), FALSE);
|
||||
|
||||
#ifdef GDK_WINDOWING_X11
|
||||
return na_tray_manager_check_running_screen_x11 (screen);
|
||||
return na_tray_manager_check_running_screen_x11 ();
|
||||
#else
|
||||
return FALSE;
|
||||
#endif
|
||||
|
||||
@@ -88,10 +88,9 @@ struct _NaTrayManagerClass
|
||||
|
||||
GType na_tray_manager_get_type (void);
|
||||
|
||||
gboolean na_tray_manager_check_running (GdkScreen *screen);
|
||||
gboolean na_tray_manager_check_running (void);
|
||||
NaTrayManager *na_tray_manager_new (void);
|
||||
gboolean na_tray_manager_manage_screen (NaTrayManager *manager,
|
||||
GdkScreen *screen);
|
||||
gboolean na_tray_manager_manage_screen (NaTrayManager *manager);
|
||||
void na_tray_manager_set_orientation (NaTrayManager *manager,
|
||||
GtkOrientation orientation);
|
||||
GtkOrientation na_tray_manager_get_orientation (NaTrayManager *manager);
|
||||
|
||||
Submodule subprojects/gvc updated: 6a0ac9ba69...0e1b4bdafc
0
test/__init__.py
Normal file
0
test/__init__.py
Normal file
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user