Compare commits
280 Commits
Author | SHA1 | Date | |
---|---|---|---|
ecea0218f2 | |||
3478715e6a | |||
cb6d9c9278 | |||
7f693ed2c4 | |||
44908cf470 | |||
7db7b7dcbd | |||
a8b457b52e | |||
cd678d86e8 | |||
384ef7e100 | |||
451c753e4a | |||
ebc74957c8 | |||
70f1f2d7be | |||
1be2102d29 | |||
114f371753 | |||
363d35a3eb | |||
26433c2cb7 | |||
db81ef3e95 | |||
091fb4ba2e | |||
54891a4cd0 | |||
31c9d2cf7a | |||
1b8bba5593 | |||
180a897588 | |||
95dba93046 | |||
35eddb3dfa | |||
aa08bd75d0 | |||
d104ebf612 | |||
e7ad9d7217 | |||
35e6a31982 | |||
4c1467196e | |||
7329721216 | |||
946ff3b380 | |||
0c584182d3 | |||
58ed983b65 | |||
6f2fc9fe14 | |||
185f003363 | |||
6734746707 | |||
65b9369aaf | |||
e1e4ce7049 | |||
812aa10119 | |||
b0fa5e5696 | |||
c7a8c372a1 | |||
73b7d9ace4 | |||
45c2627d4d | |||
635bdea284 | |||
22131d99ad | |||
4e22388089 | |||
c526413119 | |||
1336b197d8 | |||
4b99415215 | |||
1ed107a2bf | |||
cad5e06041 | |||
65d93eacd3 | |||
8369dc6b64 | |||
a0c31478c0 | |||
647c8df12f | |||
6ab045b9ad | |||
2ebac8c186 | |||
06478f242a | |||
6557ae0a2b | |||
adbec80596 | |||
2369ef1296 | |||
ce0ea0434e | |||
ede6ec2a28 | |||
b4b19b551d | |||
dc295927ed | |||
539cbf3593 | |||
b477d215a8 | |||
5de85c708f | |||
ad80cc8950 | |||
bc3a506e68 | |||
92d740ba21 | |||
d65199d2ac | |||
257b99ebd1 | |||
c8be854365 | |||
436b764952 | |||
86063f15ed | |||
716f209537 | |||
7bba7fbf37 | |||
a102c99c07 | |||
5761db5981 | |||
5d33820bd6 | |||
301acc920d | |||
495f9cba72 | |||
726fc1d4f7 | |||
dd6452fe2a | |||
19aa57454b | |||
c9555a3537 | |||
6f473a4f29 | |||
f785f4ad02 | |||
35d0ba4454 | |||
c3428f1efa | |||
9cc1e6b85c | |||
74e1058183 | |||
7c9f76944b | |||
d393ca4f09 | |||
a786f0bcd2 | |||
199bc85bce | |||
d15b46f5cb | |||
c0861b1227 | |||
f97a3522e5 | |||
577e261d1a | |||
33fcff8a1a | |||
cd30572b70 | |||
bc711b6dec | |||
01f5065b87 | |||
9c2bf17ad7 | |||
5385b36a81 | |||
72ed9da1fc | |||
d79924bdd1 | |||
3b7a4b08e2 | |||
09af4433b0 | |||
50df3084f7 | |||
e90734913d | |||
af18a0cf40 | |||
3d399796a6 | |||
60a2794c8b | |||
e039871298 | |||
e057333bf3 | |||
e0c0d9223e | |||
ada21c975f | |||
b4df747464 | |||
9a38011e1e | |||
e0f1fc2694 | |||
da5390340e | |||
3a6b41495a | |||
ce5875f365 | |||
4373d390dc | |||
9ed512e5c5 | |||
c5856196a7 | |||
afc3a8a7e7 | |||
4714c73f0f | |||
742155c384 | |||
2d814bfc5e | |||
8f8e512b37 | |||
3c828c8387 | |||
7c96b39bef | |||
64dbc8aa7f | |||
5649b9c64a | |||
3d0aab3b66 | |||
ce419da6ec | |||
63b49c65ab | |||
ff5bd0b925 | |||
0892220f63 | |||
1c95c9e3ff | |||
4b80cbe1cd | |||
46f3712421 | |||
18aa4ff30c | |||
8a75143a6e | |||
384a6e8684 | |||
a0008f7471 | |||
b53f95a9a0 | |||
1af88e52dd | |||
535028c9a7 | |||
df816368a5 | |||
f34202c3c8 | |||
28c61754a1 | |||
6e46166df4 | |||
15feaa1074 | |||
d7c532daee | |||
427ec6834d | |||
e594b30ead | |||
f43a8a75e4 | |||
645aa01efd | |||
252dce1ec2 | |||
da0066eb84 | |||
adc811ff8f | |||
5117ccdeef | |||
19816523c7 | |||
846e3f8243 | |||
d3c050b88d | |||
f3d1c78c7d | |||
c4f2bb5fe0 | |||
fec511c786 | |||
8a6157c7c1 | |||
d3bb7903e2 | |||
239b67eff6 | |||
0e0caee6ba | |||
62606c68b9 | |||
da831e894c | |||
4b166dcc79 | |||
796fdca5c5 | |||
c6f22826cf | |||
4e491b6f75 | |||
0569bb18f5 | |||
0353ebde5d | |||
b5130c5943 | |||
d54db8ffb3 | |||
0ff5fc8dbb | |||
32ec9959ef | |||
838721fc31 | |||
63e9c98248 | |||
6df30cbb64 | |||
c102a89962 | |||
ff5e39ab79 | |||
607b2efcce | |||
27d010110a | |||
e13602b896 | |||
6777670f0d | |||
b05739fa7e | |||
38854fb06a | |||
b091cfea80 | |||
a8955ffe05 | |||
475fd72ae1 | |||
31675d1812 | |||
cbb0c1c091 | |||
c1234f7793 | |||
1e6c44cb6b | |||
2202b9330f | |||
0b332fc019 | |||
4f4163eb05 | |||
649d360289 | |||
9bcdd9c274 | |||
fbc60199bc | |||
785c813771 | |||
75f8279a19 | |||
5d07832e96 | |||
7395aaf9b4 | |||
2c070d38fb | |||
2c5bc4a1a9 | |||
fa82af251f | |||
e08f2a4a04 | |||
30e17036e8 | |||
c75785efff | |||
3bf89055e3 | |||
a76869216a | |||
a9fd8bfa5e | |||
02a7b0dcfd | |||
dd8c06f2c5 | |||
c63b7f0c3f | |||
a46ea3f8a0 | |||
93071d9167 | |||
2b2e9d4098 | |||
0429aad8bf | |||
2e74920a64 | |||
b5bf82b5db | |||
98cdd44543 | |||
304b68eff9 | |||
18074951b9 | |||
0008ef70e1 | |||
c3cdbd0dac | |||
aefd61c3db | |||
f7752ac699 | |||
d017e6749c | |||
ddfdfaed78 | |||
a870a4d6de | |||
e6e786a19c | |||
01975b61f5 | |||
3c61bef92d | |||
050f2090fb | |||
7746f1a5c4 | |||
97a1cdbe7a | |||
b1dcea7cf1 | |||
9f6f48025d | |||
5e66ac2674 | |||
93c66b3537 | |||
e0d7d28c20 | |||
a82c564a73 | |||
6a40e72329 | |||
3737a9950c | |||
7784bc0905 | |||
49607e1313 | |||
a81f18592a | |||
2ff988ef37 | |||
5136369c18 | |||
7557207b47 | |||
f9d1e2fec0 | |||
f9a03f212c | |||
d200fb1d14 | |||
eb844b095a | |||
dc638c04a6 | |||
b3cbce97ed | |||
14a32c128d | |||
2e332ffd12 | |||
71d9d483f2 | |||
1ef6262139 | |||
da7db509e7 | |||
2a525bd8e8 | |||
51da2bf363 | |||
d2c0ade880 | |||
bcc3eccdab |
143
NEWS
143
NEWS
@ -1,3 +1,146 @@
|
||||
3.24.3
|
||||
======
|
||||
* Bypass proxies for captive portal [Bastien; #769692]
|
||||
* Fix missing icons in freedesktop notifications [Florian; #784245]
|
||||
* Fix blocked clicks in shutdown dialog [Florian; #781738]
|
||||
* Implement tablet rings/strips configuration [Carlos; #782033]
|
||||
* Misc. bug fixes [Matthias, Jeremy, Bastien, Florian; #780215, #782802,
|
||||
#783286, #784130, #784353, #781471]
|
||||
|
||||
Contributors:
|
||||
Jeremy Bicha, Carlos Garnacho, Matthias Liertzer, Florian Müllner,
|
||||
Bastien Nocera
|
||||
|
||||
Translations:
|
||||
Christian Stadelmann [de], Марко Костић [sr], Милош Поповић [sr@latin],
|
||||
Furkan Ahmet Kara [tr], Jeremy Bicha [es, he]
|
||||
|
||||
3.24.2
|
||||
======
|
||||
* Only fetch weather information when there's a valid location [Rares; #780404]
|
||||
* Handle extension errors during reload due to settings change [Emilio; #781728]
|
||||
* Fix StEntry::primary-icon-clicked emission [Florian; #782190]
|
||||
* Allow search providers to provide clipboard text for results [Daiki; #775099]
|
||||
* Misc. bug fixes [Florian; #781545]
|
||||
|
||||
Contributors:
|
||||
Florian Müllner, Emilio Pozuelo Monfort, Daiki Ueno, Rares Visalom
|
||||
|
||||
Translations:
|
||||
Milo Casagrande [it], Милош Поповић [sr], Khaled Hosny [ar]
|
||||
|
||||
3.24.1
|
||||
======
|
||||
* Close Wifi selection dialog on lock [Florian; #780054]
|
||||
* Fix DND over window previews in overview [Florian; #737166]
|
||||
* Do not lock the screen when disabled by lockdown settings [Florian; #780212]
|
||||
* Follow GNOME Weather's location permissions [Florian; #780252]
|
||||
* Fix portals that require a new window to be loaded [Catalin; #759044]
|
||||
* Fix restricting menus to screen height on HiDPI displays [Cosimo; #753305]
|
||||
* Misc. bug fixes and cleanups [Florian, Cosimo, Bastien, Catalin, Carlos;
|
||||
#780063, #780321, #780381, #780453, #758873, #780606, #642652]
|
||||
|
||||
Contributors:
|
||||
Cosimo Cecchi, Carlos Garnacho, Catalin Iacob, Florian Müllner, Bastien Nocera
|
||||
|
||||
Translations:
|
||||
Marek Cernocky [cs], Piotr Drąg [pl], Anders Jonsson [sv], Stas Solovey [ru],
|
||||
Rafael Fontenelle [pt_BR], Baurzhan Muftakhidinov [kk], Daniel Korostil [uk],
|
||||
Kukuh Syafaat [id], Milo Casagrande [it], Jiri Grönroos [fi],
|
||||
Daniel Mustieles [es], Balázs Úr [hu], Guillaume Bernard [fr],
|
||||
Changwoo Ryu [ko], Mario Blättermann [de], Fran Dieguez [gl],
|
||||
Dušan Kazik [sk], Yuras Shumovich [be], Fabio Tomat [fur],
|
||||
Kjartan Maraas [nb], Aurimas Černius [lt], Trần Ngọc Quân [vi],
|
||||
Rūdolfs Mazurs [lv], Ask Hjorth Larsen [da], Tom Tryfonidis [el], gogo [hr]
|
||||
|
||||
3.24.0
|
||||
======
|
||||
|
||||
Translations:
|
||||
GNOME Translation Robot [tg], Мирослав Николић [sr, sr@latin],
|
||||
Guillaume Bernard [fr], Rūdolfs Mazurs [lv], Emin Tufan Çetin [tr],
|
||||
sujiniku [ja], Daniel Korostil [uk]
|
||||
|
||||
3.23.92
|
||||
=======
|
||||
* Implement DND to overview on wayland [Hyungwon; #765003]
|
||||
* Make telepathy optional at runtime [Florian; #771721, #779878]
|
||||
* Don't show forecasts for NYC when geoclue gets stuck [Sebastian; #779898]
|
||||
* Add bottom edge drag gesture to bring up the OSK [Jan-Michael; #757712]
|
||||
* Allow switching between pads in the same group [Carlos; #779986]
|
||||
* Ignore showBanners policy for critical notifications [Florian; #779974]
|
||||
* Misc. bug fixes [Florian; #779435, #779819, #779820]
|
||||
|
||||
Contributors:
|
||||
Jan-Michael Brummer, Allan Day, Carlos Garnacho, Hyungwon Hwang,
|
||||
Sebastian Keller, Florian Müllner
|
||||
|
||||
Translations:
|
||||
Enrico Nicoletto [pt_BR], Jiri Grönroos [fi], Chao-Hsiung Liao [zh_TW],
|
||||
Piotr Drąg [pl], Piotr Drąg [he], Balázs Meskó [hu], Kris Thomsen [da],
|
||||
Yuras Shumovich [be], Sveinn í Felli [is], Inaki Larranaga Murgoitio [eu],
|
||||
Changwoo Ryu [ko], Jordi Mas [ca], Aurimas Černius [lt],
|
||||
Мирослав Николић [sr, sr@latin], Christian Kirbach [de], Anders Jonsson [sv],
|
||||
Fabio Tomat [fur], GNOME Translation Robot [gd], Dušan Kazik [sk],
|
||||
Kukuh Syafaat [id], Marek Černocký [cs], Stas Solovey [ru],
|
||||
Milo Casagrande [it], Fran Dieguez [gl], Daniel Boles [gl], A S Alam [pa],
|
||||
Daniel Mustieles [es]
|
||||
|
||||
3.23.91
|
||||
=======
|
||||
* Use the original timestamps for restored notifications [Florian; #766410]
|
||||
* Add weather information to date+time drop-down [Florian; #754031]
|
||||
* Refine message list layout in date+time drop-down [Florian; #775763]
|
||||
* Make next/prev media controls insensitive when unavailable [Florian; #773884]
|
||||
* Misc. bug fixes [Piotr, Bastien, Florian; #772210, #769546, #775799]
|
||||
|
||||
Contributors:
|
||||
Piotr Drąg, Carlos Garnacho, Florian Müllner, Bastien Nocera
|
||||
|
||||
Translations:
|
||||
Baurzhan Muftakhidinov [kk], Jordi Mas [ca], Ask Hjorth Larsen [da],
|
||||
Inaki Larranaga Murgoitio [eu], Daniel Mustieles [es], Dušan Kazik [sk],
|
||||
Aurimas Černius [lt], Jiri Grönroos [fi], Kjartan Maraas [nb],
|
||||
Piotr Drąg [pl], Daniel Korostil [uk], Kukuh Syafaat [id],
|
||||
Milo Casagrande [it], Fabio Tomat [fur], Rafael Fontenelle [pt_BR],
|
||||
Fran Dieguez [gl], Мирослав Николић [sr, sr@latin], Balázs Meskó [hu],
|
||||
Chao-Hsiung Liao [zh_TW]
|
||||
|
||||
3.23.90
|
||||
=======
|
||||
* Handle Ctrl+Q and Ctrl+W in portal window [Bastien; #764133]
|
||||
* Allow to scroll through ibus candidates with mouse [Peng; #776032]
|
||||
* Reload apps on .desktop file content changes [Adrian; #773636]
|
||||
* Use private data/cache directories in portal helper [Bastien; #775639]
|
||||
* Fix subsurfaces not showing up in previews [Rui; #756715]
|
||||
* Fix theme node transitions [Florian; #778145]
|
||||
* Update pad (o)leds on mode switches [Carlos; #776543]
|
||||
* Add security indicators to defend against malicious portals [Bastien; #749197]
|
||||
* Don't allow type ahead at the login screen [Ray; #766139]
|
||||
* Don't fail to load because of TLS errors [Bastien; #778253]
|
||||
* Ensure the network lists remains sorted on rename [Benjamin; #778686]
|
||||
* Toggle power-off/suspend button on long-press [Florian; #721173]
|
||||
* Add "kill-switch" for user extensions [Florian; #778664]
|
||||
* Add night light indicator to status area [Florian; #741224]
|
||||
* Misc. bug fixes [Michael, Bastien, Carlos, Rui, Florian, Alan, Philip, Jonas;
|
||||
#759793, #735233, #762444, #777784, #777934, #778158, #776199, #778425,
|
||||
#771098, #778552, #777317, #778660, #778661, #745626, #778672]
|
||||
|
||||
Contributors:
|
||||
Jonas Ådahl, Benjamin Berg, Michael Catanzaro, Philip Chimento,
|
||||
Alan Coopersmith, Piotr Drąg, Carlos Garnacho, Yuri Konotopov,
|
||||
Lionel Landwerlin, Rui Matos, Florian Müllner, Bastien Nocera,
|
||||
Adrian Perez de Castro, Robert Roth, Ray Strode, Peng Wu
|
||||
|
||||
Translations:
|
||||
Jiri Grönroos [fi], Balázs Meskó [hu], Gábor Kelemen [hu],
|
||||
Daniel Mustieles [es], Dušan Kazik [sk],
|
||||
Piotr Drąg [ar, eu, fa, hr, pa, pt, sr, sr@latin], Rafael Fontenelle [pt_BR],
|
||||
Jordi Mas [ca], Piotr Drąg [pl], Alexandre Franke [fr],
|
||||
Baurzhan Muftakhidinov [kk], Yuras Shumovich [be], Mandy Wang [zh_CN],
|
||||
Marek Černocký [cs], Kukuh Syafaat [id], Kjartan Maraas [nb],
|
||||
Daniel Korostil [uk]
|
||||
|
||||
3.23.3
|
||||
======
|
||||
* Fix replacing of GNotifications [Florian; #775149]
|
||||
|
26
autogen.sh
26
autogen.sh
@ -4,15 +4,17 @@
|
||||
srcdir=`dirname $0`
|
||||
test -z "$srcdir" && srcdir=.
|
||||
|
||||
(test -f $srcdir/configure.ac \
|
||||
&& test -d $srcdir/src) || {
|
||||
olddir="$(pwd)"
|
||||
|
||||
cd "${srcdir}"
|
||||
|
||||
(test -f configure.ac \
|
||||
&& test -d src) || {
|
||||
echo -n "**Error**: Directory "\`$srcdir\'" does not look like the"
|
||||
echo " top-level gnome-shell directory"
|
||||
exit 1
|
||||
}
|
||||
|
||||
pushd $srcdir
|
||||
|
||||
# Fetch submodules if needed
|
||||
if test ! -f src/gvc/Makefile.am || test ! -f data/theme/gnome-shell-sass/COPYING;
|
||||
then
|
||||
@ -21,11 +23,13 @@ then
|
||||
fi
|
||||
git submodule update
|
||||
|
||||
popd
|
||||
aclocal --install || exit 1
|
||||
gtkdocize --copy || exit 1
|
||||
intltoolize --force --copy --automake || exit 1
|
||||
autoreconf --verbose --force --install || exit 1
|
||||
|
||||
which gnome-autogen.sh || {
|
||||
echo "You need to install gnome-common from GNOME Git (or from"
|
||||
echo "your OS vendor's package manager)."
|
||||
exit 1
|
||||
}
|
||||
. gnome-autogen.sh
|
||||
cd "${olddir}"
|
||||
|
||||
if [ "$NOCONFIGURE" = "" ]; then
|
||||
"${srcdir}/configure" "$@" || exit 1
|
||||
fi
|
||||
|
35
configure.ac
35
configure.ac
@ -1,5 +1,5 @@
|
||||
AC_PREREQ(2.63)
|
||||
AC_INIT([gnome-shell],[3.23.3],[https://bugzilla.gnome.org/enter_bug.cgi?product=gnome-shell],[gnome-shell])
|
||||
AC_INIT([gnome-shell],[3.24.3],[https://bugzilla.gnome.org/enter_bug.cgi?product=gnome-shell],[gnome-shell])
|
||||
AX_IS_RELEASE([git-directory])
|
||||
|
||||
AC_CONFIG_HEADERS([config.h])
|
||||
@ -17,7 +17,6 @@ m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])])
|
||||
|
||||
# Checks for programs.
|
||||
AC_PROG_CC
|
||||
AC_PROG_CXX
|
||||
|
||||
# Initialize libtool
|
||||
LT_PREREQ([2.2.6])
|
||||
@ -42,6 +41,15 @@ GLIB_GSETTINGS
|
||||
AM_PATH_PYTHON([3])
|
||||
AC_SUBST(PYTHON)
|
||||
|
||||
# We depend on a specific version of the libmutter API. The mutter variants of
|
||||
# the Cogl and Clutter libraries also use this API version.
|
||||
LIBMUTTER_API_VERSION=0
|
||||
|
||||
LIBMUTTER=libmutter-$LIBMUTTER_API_VERSION
|
||||
LIBMUTTER_COGL=mutter-cogl-$LIBMUTTER_API_VERSION
|
||||
LIBMUTTER_COGL_PANGO=mutter-cogl-pango-$LIBMUTTER_API_VERSION
|
||||
LIBMUTTER_CLUTTER=mutter-clutter-$LIBMUTTER_API_VERSION
|
||||
|
||||
# We need at least this, since gst_plugin_register_static() was added
|
||||
# in 0.10.16, but nothing older than 0.10.21 has been tested.
|
||||
GSTREAMER_MIN_VERSION=0.11.92
|
||||
@ -53,7 +61,7 @@ if $PKG_CONFIG --exists gstreamer-1.0 '>=' $GSTREAMER_MIN_VERSION ; then
|
||||
AC_MSG_RESULT(yes)
|
||||
build_recorder=true
|
||||
recorder_modules="gstreamer-1.0 gstreamer-base-1.0 x11 gtk+-3.0"
|
||||
PKG_CHECK_MODULES(TEST_SHELL_RECORDER, $recorder_modules mutter-clutter-1.0)
|
||||
PKG_CHECK_MODULES(TEST_SHELL_RECORDER, $recorder_modules $LIBMUTTER_CLUTTER)
|
||||
else
|
||||
AC_MSG_RESULT(no)
|
||||
fi
|
||||
@ -75,15 +83,13 @@ AS_IF([test x$enable_systemd != xno], [
|
||||
|
||||
AC_MSG_RESULT($enable_systemd)
|
||||
|
||||
CLUTTER_MIN_VERSION=1.21.5
|
||||
GOBJECT_INTROSPECTION_MIN_VERSION=1.49.1
|
||||
GJS_MIN_VERSION=1.47.0
|
||||
MUTTER_MIN_VERSION=3.23.3
|
||||
MUTTER_MIN_VERSION=3.24.0
|
||||
GTK_MIN_VERSION=3.15.0
|
||||
GIO_MIN_VERSION=2.45.3
|
||||
LIBECAL_MIN_VERSION=3.5.3
|
||||
LIBEDATASERVER_MIN_VERSION=3.17.2
|
||||
TELEPATHY_GLIB_MIN_VERSION=0.17.5
|
||||
POLKIT_MIN_VERSION=0.100
|
||||
STARTUP_NOTIFICATION_MIN_VERSION=0.11
|
||||
GCR_MIN_VERSION=3.7.5
|
||||
@ -99,12 +105,11 @@ SHARED_PCS="gio-unix-2.0 >= $GIO_MIN_VERSION
|
||||
gjs-1.0 >= $GJS_MIN_VERSION
|
||||
$recorder_modules
|
||||
gdk-x11-3.0 libsoup-2.4
|
||||
mutter-clutter-1.0 >= $CLUTTER_MIN_VERSION
|
||||
mutter-cogl-pango-1.0
|
||||
$LIBMUTTER_CLUTTER >= $MUTTER_MIN_VERSION
|
||||
$LIBMUTTER_COGL_PANGO
|
||||
libstartup-notification-1.0 >= $STARTUP_NOTIFICATION_MIN_VERSION
|
||||
gobject-introspection-1.0 >= $GOBJECT_INTROSPECTION_MIN_VERSION
|
||||
libcanberra libcanberra-gtk3
|
||||
telepathy-glib >= $TELEPATHY_GLIB_MIN_VERSION
|
||||
polkit-agent-1 >= $POLKIT_MIN_VERSION
|
||||
gcr-base-3 >= $GCR_MIN_VERSION"
|
||||
if test x$have_systemd = xyes; then
|
||||
@ -112,16 +117,18 @@ if test x$have_systemd = xyes; then
|
||||
fi
|
||||
|
||||
PKG_CHECK_MODULES(GNOME_SHELL, $SHARED_PCS)
|
||||
PKG_CHECK_MODULES(MUTTER, libmutter >= $MUTTER_MIN_VERSION)
|
||||
PKG_CHECK_MODULES(MUTTER, $LIBMUTTER >= $MUTTER_MIN_VERSION)
|
||||
|
||||
PKG_CHECK_MODULES(GNOME_SHELL_JS, gio-2.0 gjs-1.0 >= $GJS_MIN_VERSION)
|
||||
PKG_CHECK_MODULES(ST, mutter-clutter-1.0 gtk+-3.0 libcroco-0.6 >= 0.6.8 x11)
|
||||
PKG_CHECK_MODULES(ST, $LIBMUTTER_CLUTTER gtk+-3.0 libcroco-0.6 >= 0.6.8 x11)
|
||||
PKG_CHECK_MODULES(SHELL_PERF_HELPER, gtk+-3.0 gio-2.0)
|
||||
PKG_CHECK_MODULES(SHELL_HOTPLUG_SNIFFER, gio-2.0 gdk-pixbuf-2.0)
|
||||
PKG_CHECK_MODULES(TRAY, mutter-clutter-1.0 gtk+-3.0)
|
||||
PKG_CHECK_MODULES(TRAY, $LIBMUTTER_CLUTTER gtk+-3.0)
|
||||
PKG_CHECK_MODULES(GVC, libpulse >= $PULSE_MIN_VERS libpulse-mainloop-glib gobject-2.0)
|
||||
PKG_CHECK_MODULES(DESKTOP_SCHEMAS, gsettings-desktop-schemas >= 3.21.3)
|
||||
|
||||
AC_SUBST(LIBMUTTER_API_VERSION)
|
||||
|
||||
AC_ARG_ENABLE(browser-plugin,
|
||||
[AS_HELP_STRING([--enable-browser-plugin],
|
||||
[Enable browser plugin [default=yes]])],,
|
||||
@ -146,10 +153,10 @@ AC_SUBST([GNOME_KEYBINDINGS_KEYSDIR])
|
||||
|
||||
GOBJECT_INTROSPECTION_CHECK([$GOBJECT_INTROSPECTION_MIN_VERSION])
|
||||
|
||||
MUTTER_GIR_DIR=`$PKG_CONFIG --variable=girdir libmutter`
|
||||
MUTTER_GIR_DIR=`$PKG_CONFIG --variable=girdir $LIBMUTTER`
|
||||
AC_SUBST(MUTTER_GIR_DIR)
|
||||
|
||||
MUTTER_TYPELIB_DIR=`$PKG_CONFIG --variable=typelibdir libmutter`
|
||||
MUTTER_TYPELIB_DIR=`$PKG_CONFIG --variable=typelibdir $LIBMUTTER`
|
||||
AC_SUBST(MUTTER_TYPELIB_DIR)
|
||||
|
||||
GJS_CONSOLE=`$PKG_CONFIG --variable=gjs_console gjs-1.0`
|
||||
|
@ -1,6 +1,6 @@
|
||||
[Desktop Entry]
|
||||
Type=Application
|
||||
Name=GNOME Shell Extension Preferences
|
||||
Name=Shell Extensions
|
||||
Comment=Configure GNOME Shell Extensions
|
||||
Exec=@bindir@/gnome-shell-extension-prefs %u
|
||||
X-GNOME-Bugzilla-Bugzilla=GNOME
|
||||
|
@ -21,6 +21,14 @@
|
||||
EnableExtension and DisableExtension D-Bus methods on org.gnome.Shell.
|
||||
</description>
|
||||
</key>
|
||||
<key name="disable-user-extensions" type="b">
|
||||
<default>false</default>
|
||||
<summary>Disable user extensions</summary>
|
||||
<description>
|
||||
Disable all extensions the user has enabled without affecting
|
||||
the “enabled-extension” setting.
|
||||
</description>
|
||||
</key>
|
||||
<key name="disable-extension-version-validation" type="b">
|
||||
<default>true</default>
|
||||
<summary>Disables the validation of extension version compatibility</summary>
|
||||
@ -56,9 +64,9 @@
|
||||
</key>
|
||||
<key name="always-show-log-out" type="b">
|
||||
<default>false</default>
|
||||
<summary>Always show the 'Log out' menu item in the user menu.</summary>
|
||||
<summary>Always show the “Log out” menu item in the user menu.</summary>
|
||||
<description>
|
||||
This key overrides the automatic hiding of the 'Log out'
|
||||
This key overrides the automatic hiding of the “Log out”
|
||||
menu item in single-user, single-session situations.
|
||||
</description>
|
||||
</key>
|
||||
@ -68,7 +76,7 @@
|
||||
<description>
|
||||
The shell will request a password when an encrypted device or a
|
||||
remote filesystem is mounted. If the password can be saved for
|
||||
future use a 'Remember Password' checkbox will be present.
|
||||
future use a “Remember Password” checkbox will be present.
|
||||
This key sets the default state of the checkbox.
|
||||
</description>
|
||||
</key>
|
||||
@ -97,9 +105,9 @@
|
||||
</key>
|
||||
<key name="toggle-application-view" type="as">
|
||||
<default>["<Super>a"]</default>
|
||||
<summary>Keybinding to open the "Show Applications" view</summary>
|
||||
<summary>Keybinding to open the “Show Applications” view</summary>
|
||||
<description>
|
||||
Keybinding to open the "Show Applications" view of the Activities
|
||||
Keybinding to open the “Show Applications” view of the Activities
|
||||
Overview.
|
||||
</description>
|
||||
</key>
|
||||
@ -168,8 +176,8 @@
|
||||
<summary>The application icon mode.</summary>
|
||||
<description>
|
||||
Configures how the windows are shown in the switcher. Valid possibilities
|
||||
are 'thumbnail-only' (shows a thumbnail of the window), 'app-icon-only'
|
||||
(shows only the application icon) or 'both'.
|
||||
are “thumbnail-only” (shows a thumbnail of the window), “app-icon-only”
|
||||
(shows only the application icon) or “both”.
|
||||
</description>
|
||||
</key>
|
||||
<key type="b" name="current-workspace-only">
|
||||
|
@ -566,6 +566,10 @@ StScrollBar {
|
||||
.pad-osd-window {
|
||||
padding: 32px;
|
||||
background-color: rgba(0, 0, 0, 0.8); }
|
||||
.pad-osd-window .pad-osd-title-box {
|
||||
spacing: 12px; }
|
||||
.pad-osd-window .pad-osd-title-menu-box {
|
||||
spacing: 6px; }
|
||||
|
||||
.combo-box-label {
|
||||
width: 15em; }
|
||||
@ -734,9 +738,20 @@ StScrollBar {
|
||||
.datemenu-displays-section {
|
||||
padding-bottom: 3em; }
|
||||
|
||||
.datemenu-displays-box {
|
||||
spacing: 1em; }
|
||||
|
||||
.datemenu-calendar-column {
|
||||
border: 0 solid #0d0d0d; }
|
||||
.datemenu-calendar-column:ltr {
|
||||
border-left-width: 1px; }
|
||||
.datemenu-calendar-column:rtl {
|
||||
border-right-width: 1px; }
|
||||
|
||||
.datemenu-today-button,
|
||||
.world-clocks-button,
|
||||
.message-list-section-title {
|
||||
.weather-button,
|
||||
.events-section-title {
|
||||
border-radius: 4px;
|
||||
padding: .4em; }
|
||||
|
||||
@ -749,12 +764,15 @@ StScrollBar {
|
||||
.datemenu-today-button:hover, .datemenu-today-button:focus,
|
||||
.world-clocks-button:hover,
|
||||
.world-clocks-button:focus,
|
||||
.message-list-section-title:hover,
|
||||
.message-list-section-title:focus {
|
||||
.weather-button:hover,
|
||||
.weather-button:focus,
|
||||
.events-section-title:hover,
|
||||
.events-section-title:focus {
|
||||
background-color: #0d0d0d; }
|
||||
.datemenu-today-button:active,
|
||||
.world-clocks-button:active,
|
||||
.message-list-section-title:active {
|
||||
.weather-button:active,
|
||||
.events-section-title:active {
|
||||
color: white;
|
||||
background-color: #215d9c; }
|
||||
|
||||
@ -762,13 +780,17 @@ StScrollBar {
|
||||
font-size: 1.5em; }
|
||||
|
||||
.world-clocks-header,
|
||||
.message-list-section-title {
|
||||
.weather-header,
|
||||
.events-section-title {
|
||||
color: #999999;
|
||||
font-weight: bold; }
|
||||
|
||||
.world-clocks-grid {
|
||||
spacing-rows: 0.4em; }
|
||||
|
||||
.weather-box {
|
||||
spacing: 0.4em; }
|
||||
|
||||
.calendar-month-label {
|
||||
color: #f2f2f2;
|
||||
font-weight: bold;
|
||||
@ -853,69 +875,68 @@ StScrollBar {
|
||||
.message-list {
|
||||
width: 31.5em; }
|
||||
|
||||
.message-list-clear-button.button {
|
||||
background-color: transparent;
|
||||
margin: 1.5em 1.5em 0; }
|
||||
.message-list-clear-button.button:hover, .message-list-clear-button.button:focus {
|
||||
background-color: #0d0d0d; }
|
||||
|
||||
.message-list-sections {
|
||||
spacing: 1.5em; }
|
||||
spacing: 1em; }
|
||||
|
||||
.message-list-section,
|
||||
.message-list-section-list {
|
||||
spacing: 0.7em; }
|
||||
|
||||
.message-list-section-title-box {
|
||||
spacing: 0.4em; }
|
||||
|
||||
.message-list-section-close > StIcon {
|
||||
icon-size: 16px;
|
||||
border-radius: 8px;
|
||||
color: #000;
|
||||
background-color: #666666; }
|
||||
|
||||
/* FIXME: how do you do this in sass? */
|
||||
.message-list-section-close:hover > StIcon,
|
||||
.message-list-section-close:focus > StIcon {
|
||||
background-color: #999999; }
|
||||
|
||||
.message {
|
||||
background-color: #0d0d0d;
|
||||
border-radius: 3px; }
|
||||
.message:hover, .message:focus {
|
||||
background-color: #262626; }
|
||||
background-color: #0d0d0d; }
|
||||
|
||||
.message-icon-bin {
|
||||
padding: 8px 0px 8px 8px; }
|
||||
padding: 10px 3px 10px 10px; }
|
||||
.message-icon-bin:rtl {
|
||||
padding: 8px 8px 8px 0px; }
|
||||
padding: 10px 10px 10px 3px; }
|
||||
|
||||
.message-icon-bin > StIcon {
|
||||
icon-size: 32px; }
|
||||
|
||||
.message-secondary-bin:ltr {
|
||||
padding-left: 8px; }
|
||||
.message-secondary-bin:rtl {
|
||||
padding-right: 8px; }
|
||||
color: #cccccc;
|
||||
icon-size: 16px;
|
||||
-st-icon-style: symbolic; }
|
||||
|
||||
.message-secondary-bin {
|
||||
color: #999999; }
|
||||
padding: 0 12px; }
|
||||
|
||||
.message-secondary-bin > .event-time {
|
||||
color: #999999;
|
||||
font-size: 0.7em;
|
||||
/* HACK: the label should be baseline-aligned with a 1em label,
|
||||
fake this with some bottom padding */
|
||||
padding-bottom: 0.13em; }
|
||||
|
||||
.message-secondary-bin > StIcon {
|
||||
icon-size: 16px; }
|
||||
|
||||
.message-title {
|
||||
font-weight: bold;
|
||||
font-size: 1.1em; }
|
||||
color: #f2f2f2; }
|
||||
|
||||
.message-content {
|
||||
padding: 8px;
|
||||
font-size: .9em; }
|
||||
color: #cccccc;
|
||||
padding: 10px; }
|
||||
|
||||
.message-media-control {
|
||||
padding: 6px; }
|
||||
padding: 12px;
|
||||
color: #cccccc; }
|
||||
.message-media-control:last-child:ltr {
|
||||
padding-right: 18px; }
|
||||
.message-media-control:last-child:rtl {
|
||||
padding-left: 18px; }
|
||||
.message-media-control:hover {
|
||||
color: #fff; }
|
||||
.message-media-control:insensitive {
|
||||
color: #999999; }
|
||||
|
||||
.media-message-cover-icon {
|
||||
icon-size: 32px; }
|
||||
icon-size: 48px !important; }
|
||||
.media-message-cover-icon.fallback {
|
||||
color: #1a1a1a;
|
||||
background-color: #000;
|
||||
|
Submodule data/theme/gnome-shell-sass updated: 50bbd0b50f...e94bce1fcf
@ -566,6 +566,10 @@ StScrollBar {
|
||||
.pad-osd-window {
|
||||
padding: 32px;
|
||||
background-color: rgba(0, 0, 0, 0.8); }
|
||||
.pad-osd-window .pad-osd-title-box {
|
||||
spacing: 12px; }
|
||||
.pad-osd-window .pad-osd-title-menu-box {
|
||||
spacing: 6px; }
|
||||
|
||||
.combo-box-label {
|
||||
width: 15em; }
|
||||
@ -734,9 +738,20 @@ StScrollBar {
|
||||
.datemenu-displays-section {
|
||||
padding-bottom: 3em; }
|
||||
|
||||
.datemenu-displays-box {
|
||||
spacing: 1em; }
|
||||
|
||||
.datemenu-calendar-column {
|
||||
border: 0 solid #454c4c; }
|
||||
.datemenu-calendar-column:ltr {
|
||||
border-left-width: 1px; }
|
||||
.datemenu-calendar-column:rtl {
|
||||
border-right-width: 1px; }
|
||||
|
||||
.datemenu-today-button,
|
||||
.world-clocks-button,
|
||||
.message-list-section-title {
|
||||
.weather-button,
|
||||
.events-section-title {
|
||||
border-radius: 4px;
|
||||
padding: .4em; }
|
||||
|
||||
@ -749,12 +764,15 @@ StScrollBar {
|
||||
.datemenu-today-button:hover, .datemenu-today-button:focus,
|
||||
.world-clocks-button:hover,
|
||||
.world-clocks-button:focus,
|
||||
.message-list-section-title:hover,
|
||||
.message-list-section-title:focus {
|
||||
.weather-button:hover,
|
||||
.weather-button:focus,
|
||||
.events-section-title:hover,
|
||||
.events-section-title:focus {
|
||||
background-color: #454c4c; }
|
||||
.datemenu-today-button:active,
|
||||
.world-clocks-button:active,
|
||||
.message-list-section-title:active {
|
||||
.weather-button:active,
|
||||
.events-section-title:active {
|
||||
color: white;
|
||||
background-color: #215d9c; }
|
||||
|
||||
@ -762,13 +780,17 @@ StScrollBar {
|
||||
font-size: 1.5em; }
|
||||
|
||||
.world-clocks-header,
|
||||
.message-list-section-title {
|
||||
.weather-header,
|
||||
.events-section-title {
|
||||
color: #8e8e80;
|
||||
font-weight: bold; }
|
||||
|
||||
.world-clocks-grid {
|
||||
spacing-rows: 0.4em; }
|
||||
|
||||
.weather-box {
|
||||
spacing: 0.4em; }
|
||||
|
||||
.calendar-month-label {
|
||||
color: #e2e2df;
|
||||
font-weight: bold;
|
||||
@ -853,69 +875,68 @@ StScrollBar {
|
||||
.message-list {
|
||||
width: 31.5em; }
|
||||
|
||||
.message-list-clear-button.button {
|
||||
background-color: transparent;
|
||||
margin: 1.5em 1.5em 0; }
|
||||
.message-list-clear-button.button:hover, .message-list-clear-button.button:focus {
|
||||
background-color: #454c4c; }
|
||||
|
||||
.message-list-sections {
|
||||
spacing: 1.5em; }
|
||||
spacing: 1em; }
|
||||
|
||||
.message-list-section,
|
||||
.message-list-section-list {
|
||||
spacing: 0.7em; }
|
||||
|
||||
.message-list-section-title-box {
|
||||
spacing: 0.4em; }
|
||||
|
||||
.message-list-section-close > StIcon {
|
||||
icon-size: 16px;
|
||||
border-radius: 8px;
|
||||
color: #393f3f;
|
||||
background-color: #59594f; }
|
||||
|
||||
/* FIXME: how do you do this in sass? */
|
||||
.message-list-section-close:hover > StIcon,
|
||||
.message-list-section-close:focus > StIcon {
|
||||
background-color: #8e8e80; }
|
||||
|
||||
.message {
|
||||
background-color: #454c4c;
|
||||
border-radius: 3px; }
|
||||
.message:hover, .message:focus {
|
||||
background-color: #5d6767; }
|
||||
background-color: #454c4c; }
|
||||
|
||||
.message-icon-bin {
|
||||
padding: 8px 0px 8px 8px; }
|
||||
padding: 10px 3px 10px 10px; }
|
||||
.message-icon-bin:rtl {
|
||||
padding: 8px 8px 8px 0px; }
|
||||
padding: 10px 10px 10px 3px; }
|
||||
|
||||
.message-icon-bin > StIcon {
|
||||
icon-size: 32px; }
|
||||
|
||||
.message-secondary-bin:ltr {
|
||||
padding-left: 8px; }
|
||||
.message-secondary-bin:rtl {
|
||||
padding-right: 8px; }
|
||||
color: #bebeb6;
|
||||
icon-size: 16px;
|
||||
-st-icon-style: symbolic; }
|
||||
|
||||
.message-secondary-bin {
|
||||
color: #8e8e80; }
|
||||
padding: 0 12px; }
|
||||
|
||||
.message-secondary-bin > .event-time {
|
||||
color: #8e8e80;
|
||||
font-size: 0.7em;
|
||||
/* HACK: the label should be baseline-aligned with a 1em label,
|
||||
fake this with some bottom padding */
|
||||
padding-bottom: 0.13em; }
|
||||
|
||||
.message-secondary-bin > StIcon {
|
||||
icon-size: 16px; }
|
||||
|
||||
.message-title {
|
||||
font-weight: bold;
|
||||
font-size: 1.1em; }
|
||||
color: #e2e2df; }
|
||||
|
||||
.message-content {
|
||||
padding: 8px;
|
||||
font-size: .9em; }
|
||||
color: #bebeb6;
|
||||
padding: 10px; }
|
||||
|
||||
.message-media-control {
|
||||
padding: 6px; }
|
||||
padding: 12px;
|
||||
color: #bebeb6; }
|
||||
.message-media-control:last-child:ltr {
|
||||
padding-right: 18px; }
|
||||
.message-media-control:last-child:rtl {
|
||||
padding-left: 18px; }
|
||||
.message-media-control:hover {
|
||||
color: #eeeeec; }
|
||||
.message-media-control:insensitive {
|
||||
color: #8e8e80; }
|
||||
|
||||
.media-message-cover-icon {
|
||||
icon-size: 32px; }
|
||||
icon-size: 48px !important; }
|
||||
.media-message-cover-icon.fallback {
|
||||
color: #515a5a;
|
||||
background-color: #393f3f;
|
||||
|
@ -125,7 +125,7 @@ EXTRA_DIST +=
|
||||
# Files not to distribute
|
||||
# for --rebuild-types in $(SCAN_OPTIONS), e.g. $(DOC_MODULE).types
|
||||
# for --rebuild-sections in $(SCAN_OPTIONS) e.g. $(DOC_MODULE)-sections.txt
|
||||
DISTCLEANFILES = $(DOC_MODULES).types
|
||||
DISTCLEANFILES = $(DOC_MODULE).types
|
||||
|
||||
# Comment this out if you want 'make check' to test you doc status
|
||||
# and run some sanity checks
|
||||
|
@ -50,7 +50,6 @@
|
||||
<xi:include href="xml/shell-util.xml"/>
|
||||
<xi:include href="xml/shell-mount-operation.xml"/>
|
||||
<xi:include href="xml/shell-polkit-authentication-agent.xml"/>
|
||||
<xi:include href="xml/shell-tp-client.xml"/>
|
||||
</chapter>
|
||||
<chapter id="object-tree">
|
||||
<title>Object Hierarchy</title>
|
||||
|
@ -11,6 +11,7 @@ misc/config.js: misc/config.js.in Makefile
|
||||
-e "s|[@]datadir@|$(datadir)|g" \
|
||||
-e "s|[@]libexecdir@|$(libexecdir)|g" \
|
||||
-e "s|[@]sysconfdir@|$(sysconfdir)|g" \
|
||||
-e "s|[@]LIBMUTTER_API_VERSION@|$(LIBMUTTER_API_VERSION)|g" \
|
||||
$< > $@
|
||||
|
||||
js_resource_files = $(shell $(GLIB_COMPILE_RESOURCES) --sourcedir=$(srcdir) --sourcedir=$(builddir) --generate-dependencies $(srcdir)/js-resources.gresource.xml)
|
||||
|
@ -5,6 +5,7 @@ const GLib = imports.gi.GLib;
|
||||
const GObject = imports.gi.GObject;
|
||||
const Gio = imports.gi.Gio;
|
||||
const Gtk = imports.gi.Gtk;
|
||||
const Gdk = imports.gi.Gdk;
|
||||
const Pango = imports.gi.Pango;
|
||||
const Format = imports.format;
|
||||
|
||||
@ -92,9 +93,11 @@ const Application = new Lang.Class({
|
||||
widget = this._buildErrorUI(extension, e);
|
||||
}
|
||||
|
||||
let dialog = new Gtk.Dialog({ use_header_bar: true,
|
||||
modal: true,
|
||||
title: extension.metadata.name });
|
||||
let dialog = new Gtk.Window({ modal: !this._skipMainWindow,
|
||||
type_hint: Gdk.WindowTypeHint.DIALOG });
|
||||
dialog.set_titlebar(new Gtk.HeaderBar({ show_close_button: true,
|
||||
title: extension.metadata.name,
|
||||
visible: true }));
|
||||
|
||||
if (this._skipMainWindow) {
|
||||
this.application.add_window(dialog);
|
||||
@ -107,7 +110,7 @@ const Application = new Lang.Class({
|
||||
}
|
||||
|
||||
dialog.set_default_size(600, 400);
|
||||
dialog.get_content_area().add(widget);
|
||||
dialog.add(widget);
|
||||
dialog.show();
|
||||
},
|
||||
|
||||
@ -143,17 +146,21 @@ const Application = new Lang.Class({
|
||||
this._window = new Gtk.ApplicationWindow({ application: app,
|
||||
window_position: Gtk.WindowPosition.CENTER });
|
||||
|
||||
this._window.set_size_request(800, 500);
|
||||
this._window.set_default_size(800, 500);
|
||||
|
||||
this._titlebar = new Gtk.HeaderBar({ show_close_button: true,
|
||||
title: _("GNOME Shell Extensions") });
|
||||
title: _("Shell Extensions") });
|
||||
this._window.set_titlebar(this._titlebar);
|
||||
|
||||
let scroll = new Gtk.ScrolledWindow({ hscrollbar_policy: Gtk.PolicyType.NEVER,
|
||||
shadow_type: Gtk.ShadowType.IN,
|
||||
halign: Gtk.Align.CENTER,
|
||||
propagate_natural_width: true,
|
||||
margin: 18 });
|
||||
let killSwitch = new Gtk.Switch({ valign: Gtk.Align.CENTER });
|
||||
this._titlebar.pack_end(killSwitch);
|
||||
|
||||
this._settings = new Gio.Settings({ schema_id: 'org.gnome.shell' });
|
||||
this._settings.bind('disable-user-extensions', killSwitch, 'active',
|
||||
Gio.SettingsBindFlags.DEFAULT |
|
||||
Gio.SettingsBindFlags.INVERT_BOOLEAN);
|
||||
|
||||
let scroll = new Gtk.ScrolledWindow({ hscrollbar_policy: Gtk.PolicyType.NEVER });
|
||||
this._window.add(scroll);
|
||||
|
||||
this._extensionSelector = new Gtk.ListBox({ selection_mode: Gtk.SelectionMode.NONE });
|
||||
@ -246,6 +253,18 @@ const Application = new Lang.Class({
|
||||
}
|
||||
});
|
||||
|
||||
const DescriptionLabel = new Lang.Class({
|
||||
Name: 'DescriptionLabel',
|
||||
Extends: Gtk.Label,
|
||||
|
||||
vfunc_get_preferred_height_for_width: function(width) {
|
||||
// Hack: Request the maximum height allowed by the line limit
|
||||
if (this.lines > 0)
|
||||
return this.parent(0);
|
||||
return this.parent(width);
|
||||
}
|
||||
});
|
||||
|
||||
const ExtensionRow = new Lang.Class({
|
||||
Name: 'ExtensionRow',
|
||||
Extends: Gtk.ListBoxRow,
|
||||
@ -264,6 +283,10 @@ const ExtensionRow = new Lang.Class({
|
||||
Lang.bind(this, function() {
|
||||
this._switch.sensitive = this._canEnable();
|
||||
}));
|
||||
this._settings.connect('changed::disable-user-extensions',
|
||||
Lang.bind(this, function() {
|
||||
this._switch.sensitive = this._canEnable();
|
||||
}));
|
||||
|
||||
this._buildUI();
|
||||
},
|
||||
@ -272,7 +295,8 @@ const ExtensionRow = new Lang.Class({
|
||||
let extension = ExtensionUtils.extensions[this.uuid];
|
||||
|
||||
let hbox = new Gtk.Box({ orientation: Gtk.Orientation.HORIZONTAL,
|
||||
hexpand: true, margin: 12, spacing: 6 });
|
||||
hexpand: true, margin_end: 24, spacing: 24,
|
||||
margin: 12 });
|
||||
this.add(hbox);
|
||||
|
||||
let vbox = new Gtk.Box({ orientation: Gtk.Orientation.VERTICAL,
|
||||
@ -286,9 +310,9 @@ const ExtensionRow = new Lang.Class({
|
||||
vbox.add(label);
|
||||
|
||||
let desc = extension.metadata.description.split('\n')[0];
|
||||
label = new Gtk.Label({ label: desc,
|
||||
ellipsize: Pango.EllipsizeMode.END,
|
||||
halign: Gtk.Align.START });
|
||||
label = new DescriptionLabel({ label: desc, wrap: true, lines: 2,
|
||||
ellipsize: Pango.EllipsizeMode.END,
|
||||
xalign: 0, yalign: 0 });
|
||||
vbox.add(label);
|
||||
|
||||
let button = new Gtk.Button({ valign: Gtk.Align.CENTER,
|
||||
@ -319,7 +343,8 @@ const ExtensionRow = new Lang.Class({
|
||||
let extension = ExtensionUtils.extensions[this.uuid];
|
||||
let checkVersion = !this._settings.get_boolean('disable-extension-version-validation');
|
||||
|
||||
return !(checkVersion && ExtensionUtils.isOutOfDate(extension));
|
||||
return !this._settings.get_boolean('disable-user-extensions') &&
|
||||
!(checkVersion && ExtensionUtils.isOutOfDate(extension));
|
||||
},
|
||||
|
||||
_isEnabled: function() {
|
||||
|
@ -23,6 +23,12 @@ function FprintManager() {
|
||||
g_object_path: '/net/reactivated/Fprint/Manager',
|
||||
g_flags: (Gio.DBusProxyFlags.DO_NOT_LOAD_PROPERTIES) });
|
||||
|
||||
self.init(null);
|
||||
try {
|
||||
self.init(null);
|
||||
} catch(e) {
|
||||
log('Failed to connect to Fprint service: ' + e.message);
|
||||
return null;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
@ -1225,7 +1225,7 @@ const LoginDialog = new Lang.Class({
|
||||
},
|
||||
|
||||
addCharacter: function(unichar) {
|
||||
this._authPrompt.addCharacter(unichar);
|
||||
// Don't allow type ahead at the login screen
|
||||
},
|
||||
|
||||
finish: function(onComplete) {
|
||||
|
@ -128,18 +128,22 @@ const ShellUserVerifier = new Lang.Class({
|
||||
|
||||
this._client = client;
|
||||
|
||||
this._defaultService = null;
|
||||
this._preemptingService = null;
|
||||
|
||||
this._settings = new Gio.Settings({ schema_id: LOGIN_SCREEN_SCHEMA });
|
||||
this._settings.connect('changed',
|
||||
Lang.bind(this, this._updateDefaultService));
|
||||
this._updateDefaultService();
|
||||
|
||||
this._fprintManager = new Fprint.FprintManager();
|
||||
this._fprintManager = Fprint.FprintManager();
|
||||
this._smartcardManager = SmartcardManager.getSmartcardManager();
|
||||
|
||||
// We check for smartcards right away, since an inserted smartcard
|
||||
// at startup should result in immediately initiating authentication.
|
||||
// This is different than fingeprint readers, where we only check them
|
||||
// after a user has been picked.
|
||||
this.smartcardDetected = false;
|
||||
this._checkForSmartcard();
|
||||
|
||||
this._smartcardInsertedId = this._smartcardManager.connect('smartcard-inserted',
|
||||
@ -293,7 +297,8 @@ const ShellUserVerifier = new Lang.Class({
|
||||
_checkForFingerprintReader: function() {
|
||||
this._haveFingerprintReader = false;
|
||||
|
||||
if (!this._settings.get_boolean(FINGERPRINT_AUTHENTICATION_KEY)) {
|
||||
if (!this._settings.get_boolean(FINGERPRINT_AUTHENTICATION_KEY) ||
|
||||
this._fprintManager == null) {
|
||||
this._updateDefaultService();
|
||||
return;
|
||||
}
|
||||
|
@ -23,8 +23,10 @@
|
||||
<file>misc/modemManager.js</file>
|
||||
<file>misc/objectManager.js</file>
|
||||
<file>misc/params.js</file>
|
||||
<file>misc/permissionStore.js</file>
|
||||
<file>misc/smartcardManager.js</file>
|
||||
<file>misc/util.js</file>
|
||||
<file>misc/weather.js</file>
|
||||
|
||||
<file>perf/core.js</file>
|
||||
<file>perf/hwtest.js</file>
|
||||
@ -117,6 +119,7 @@
|
||||
<file>ui/status/brightness.js</file>
|
||||
<file>ui/status/location.js</file>
|
||||
<file>ui/status/keyboard.js</file>
|
||||
<file>ui/status/nightLight.js</file>
|
||||
<file>ui/status/network.js</file>
|
||||
<file>ui/status/power.js</file>
|
||||
<file>ui/status/rfkill.js</file>
|
||||
|
@ -15,3 +15,5 @@ const LOCALEDIR = '@datadir@/locale';
|
||||
/* other standard directories */
|
||||
const LIBEXECDIR = '@libexecdir@';
|
||||
const SYSCONFDIR = '@sysconfdir@';
|
||||
/* g-i package versions */
|
||||
const LIBMUTTER_API_VERSION = '@LIBMUTTER_API_VERSION@'
|
||||
|
@ -69,7 +69,7 @@ const HistoryManager = new Lang.Class({
|
||||
this._indexChanged();
|
||||
}
|
||||
|
||||
return this._historyIndex[this._history.length];
|
||||
return this._historyIndex ? this._history[this._historyIndex -1] : null;
|
||||
},
|
||||
|
||||
addItem: function(input) {
|
||||
|
@ -6,10 +6,11 @@ const Lang = imports.lang;
|
||||
const Mainloop = imports.mainloop;
|
||||
const Signals = imports.signals;
|
||||
|
||||
let IBusCandidatePopup;
|
||||
try {
|
||||
var IBus = imports.gi.IBus;
|
||||
_checkIBusVersion(1, 5, 2);
|
||||
const IBusCandidatePopup = imports.ui.ibusCandidatePopup;
|
||||
IBusCandidatePopup = imports.ui.ibusCandidatePopup;
|
||||
} catch (e) {
|
||||
var IBus = null;
|
||||
log(e);
|
||||
@ -189,7 +190,7 @@ const IBusManager = new Lang.Class({
|
||||
},
|
||||
|
||||
getEngineDesc: function(id) {
|
||||
if (!IBus || !this._ready)
|
||||
if (!IBus || !this._ready || !this._engines.hasOwnProperty(id))
|
||||
return null;
|
||||
|
||||
return this._engines[id];
|
||||
|
@ -128,7 +128,8 @@ const KeyboardManager = new Lang.Class({
|
||||
if (!found)
|
||||
[, , id] = GnomeDesktop.get_input_source_from_locale(DEFAULT_LOCALE);
|
||||
|
||||
let [found, , , _layout, _variant] = this._xkbInfo.get_layout_info(id);
|
||||
let _layout, _variant;
|
||||
[found, , , _layout, _variant] = this._xkbInfo.get_layout_info(id);
|
||||
if (found)
|
||||
return { layout: _layout, variant: _variant };
|
||||
else
|
||||
|
37
js/misc/permissionStore.js
Normal file
37
js/misc/permissionStore.js
Normal file
@ -0,0 +1,37 @@
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
|
||||
const Gio = imports.gi.Gio;
|
||||
|
||||
const PermissionStoreIface = '<node> \
|
||||
<interface name="org.freedesktop.impl.portal.PermissionStore"> \
|
||||
<method name="Lookup"> \
|
||||
<arg name="table" type="s" direction="in"/> \
|
||||
<arg name="id" type="s" direction="in"/> \
|
||||
<arg name="permissions" type="a{sas}" direction="out"/> \
|
||||
<arg name="data" type="v" direction="out"/> \
|
||||
</method> \
|
||||
<method name="Set"> \
|
||||
<arg name="table" type="s" direction="in"/> \
|
||||
<arg name="create" type="b" direction="in"/> \
|
||||
<arg name="id" type="s" direction="in"/> \
|
||||
<arg name="app_permissions" type="a{sas}" direction="in"/> \
|
||||
<arg name="data" type="v" direction="in"/> \
|
||||
</method> \
|
||||
<signal name="Changed"> \
|
||||
<arg name="table" type="s" direction="out"/> \
|
||||
<arg name="id" type="s" direction="out"/> \
|
||||
<arg name="deleted" type="b" direction="out"/> \
|
||||
<arg name="data" type="v" direction="out"/> \
|
||||
<arg name="permissions" type="a{sas}" direction="out"/> \
|
||||
</signal> \
|
||||
</interface> \
|
||||
</node>';
|
||||
|
||||
const PermissionStoreProxy = Gio.DBusProxy.makeProxyWrapper(PermissionStoreIface);
|
||||
|
||||
function PermissionStore(initCallback, cancellable) {
|
||||
return new PermissionStoreProxy(Gio.DBus.session,
|
||||
'org.freedesktop.impl.portal.PermissionStore',
|
||||
'/org/freedesktop/impl/portal/PermissionStore',
|
||||
initCallback, cancellable);
|
||||
};
|
134
js/misc/util.js
134
js/misc/util.js
@ -1,9 +1,12 @@
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
|
||||
const Clutter = imports.gi.Clutter;
|
||||
const Gettext = imports.gettext;
|
||||
const Gio = imports.gi.Gio;
|
||||
const GLib = imports.gi.GLib;
|
||||
const Lang = imports.lang;
|
||||
const Mainloop = imports.mainloop;
|
||||
const Signals = imports.signals;
|
||||
const Shell = imports.gi.Shell;
|
||||
const St = imports.gi.St;
|
||||
|
||||
@ -161,6 +164,41 @@ function _handleSpawnError(command, err) {
|
||||
Main.notifyError(title, err.message);
|
||||
}
|
||||
|
||||
function formatTimeSpan(date) {
|
||||
let now = GLib.DateTime.new_now_local();
|
||||
|
||||
let timespan = now.difference(date);
|
||||
|
||||
let minutesAgo = timespan / GLib.TIME_SPAN_MINUTE;
|
||||
let hoursAgo = timespan / GLib.TIME_SPAN_HOUR;
|
||||
let daysAgo = timespan / GLib.TIME_SPAN_DAY;
|
||||
let weeksAgo = daysAgo / 7;
|
||||
let monthsAgo = daysAgo / 30;
|
||||
let yearsAgo = weeksAgo / 52;
|
||||
|
||||
if (minutesAgo < 5)
|
||||
return _("Just now");
|
||||
if (hoursAgo < 1)
|
||||
return Gettext.ngettext("%d minute ago",
|
||||
"%d minutes ago", minutesAgo).format(minutesAgo);
|
||||
if (daysAgo < 1)
|
||||
return Gettext.ngettext("%d hour ago",
|
||||
"%d hours ago", hoursAgo).format(hoursAgo);
|
||||
if (daysAgo < 2)
|
||||
return _("Yesterday");
|
||||
if (daysAgo < 15)
|
||||
return Gettext.ngettext("%d day ago",
|
||||
"%d days ago", daysAgo).format(daysAgo);
|
||||
if (weeksAgo < 8)
|
||||
return Gettext.ngettext("%d week ago",
|
||||
"%d weeks ago", weeksAgo).format(weeksAgo);
|
||||
if (yearsAgo < 1)
|
||||
return Gettext.ngettext("%d month ago",
|
||||
"%d months ago", monthsAgo).format(monthsAgo);
|
||||
return Gettext.ngettext("%d year ago",
|
||||
"%d years ago", yearsAgo).format(yearsAgo);
|
||||
}
|
||||
|
||||
function formatTime(time, params) {
|
||||
let date;
|
||||
// HACK: The built-in Date type sucks at timezones, which we need for the
|
||||
@ -243,7 +281,10 @@ function formatTime(time, params) {
|
||||
// xgettext:no-c-format
|
||||
format = N_("%B %d %Y, %l\u2236%M %p");
|
||||
}
|
||||
return date.format(Shell.util_translate_time_string(format));
|
||||
|
||||
let formattedTime = date.format(Shell.util_translate_time_string(format));
|
||||
// prepend LTR-mark to colon/ratio to force a text direction on times
|
||||
return formattedTime.replace(/([:\u2236])/g, '\u200e$1');
|
||||
}
|
||||
|
||||
function createTimeLabel(date, params) {
|
||||
@ -398,3 +439,94 @@ function ensureActorVisibleInScrollView(scrollView, actor) {
|
||||
time: SCROLL_TIME,
|
||||
transition: 'easeOutQuad' });
|
||||
}
|
||||
|
||||
const AppSettingsMonitor = new Lang.Class({
|
||||
Name: 'AppSettingsMonitor',
|
||||
|
||||
_init: function(appId, schemaId) {
|
||||
this._appId = appId;
|
||||
this._schemaId = schemaId;
|
||||
|
||||
this._app = null;
|
||||
this._settings = null;
|
||||
this._handlers = [];
|
||||
|
||||
this._schemaSource = Gio.SettingsSchemaSource.get_default();
|
||||
|
||||
this._appSystem = Shell.AppSystem.get_default();
|
||||
this._appSystem.connect('installed-changed',
|
||||
Lang.bind(this, this._onInstalledChanged));
|
||||
this._onInstalledChanged();
|
||||
},
|
||||
|
||||
get available() {
|
||||
return this._app != null && this._settings != null;
|
||||
},
|
||||
|
||||
activateApp: function() {
|
||||
if (this._app)
|
||||
this._app.activate();
|
||||
},
|
||||
|
||||
watchSetting: function(key, callback) {
|
||||
let handler = { id: 0, key: key, callback: callback };
|
||||
this._handlers.push(handler);
|
||||
|
||||
this._connectHandler(handler);
|
||||
},
|
||||
|
||||
_connectHandler: function(handler) {
|
||||
if (!this._settings || handler.id > 0)
|
||||
return;
|
||||
|
||||
handler.id = this._settings.connect('changed::' + handler.key,
|
||||
handler.callback);
|
||||
handler.callback(this._settings, handler.key);
|
||||
},
|
||||
|
||||
_disconnectHandler: function(handler) {
|
||||
if (this._settings && handler.id > 0)
|
||||
this._settings.disconnect(handler.id);
|
||||
handler.id = 0;
|
||||
},
|
||||
|
||||
_onInstalledChanged: function() {
|
||||
let hadApp = (this._app != null);
|
||||
this._app = this._appSystem.lookup_app(this._appId);
|
||||
let haveApp = (this._app != null);
|
||||
|
||||
if (hadApp == haveApp)
|
||||
return;
|
||||
|
||||
if (haveApp)
|
||||
this._checkSettings();
|
||||
else
|
||||
this._setSettings(null);
|
||||
},
|
||||
|
||||
_setSettings: function(settings) {
|
||||
this._handlers.forEach((handler) => { this._disconnectHandler(handler); });
|
||||
|
||||
let hadSettings = (this._settings != null);
|
||||
this._settings = settings;
|
||||
let haveSettings = (this._settings != null);
|
||||
|
||||
this._handlers.forEach((handler) => { this._connectHandler(handler); });
|
||||
|
||||
if (hadSettings != haveSettings)
|
||||
this.emit('available-changed');
|
||||
},
|
||||
|
||||
_checkSettings: function() {
|
||||
let schema = this._schemaSource.lookup(this._schemaId, true);
|
||||
if (schema) {
|
||||
this._setSettings(new Gio.Settings({ settings_schema: schema }));
|
||||
} else if (this._app) {
|
||||
Mainloop.timeout_add_seconds(1, () => {
|
||||
this._checkSettings();
|
||||
return GLib.SOURCE_REMOVE;
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
Signals.addSignalMethods(AppSettingsMonitor.prototype);
|
||||
|
247
js/misc/weather.js
Normal file
247
js/misc/weather.js
Normal file
@ -0,0 +1,247 @@
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
|
||||
const Geoclue = imports.gi.Geoclue;
|
||||
const Gio = imports.gi.Gio;
|
||||
const GLib = imports.gi.GLib;
|
||||
const GWeather = imports.gi.GWeather;
|
||||
const Lang = imports.lang;
|
||||
const Signals = imports.signals;
|
||||
|
||||
const PermissionStore = imports.misc.permissionStore;
|
||||
const Util = imports.misc.util;
|
||||
|
||||
// Minimum time between updates to show loading indication
|
||||
const UPDATE_THRESHOLD = 10 * GLib.TIME_SPAN_MINUTE;
|
||||
|
||||
const WeatherClient = new Lang.Class({
|
||||
Name: 'WeatherClient',
|
||||
|
||||
_init: function() {
|
||||
this._loading = false;
|
||||
this._locationValid = false;
|
||||
this._lastUpdate = GLib.DateTime.new_from_unix_local(0);
|
||||
|
||||
this._autoLocationRequested = false;
|
||||
this._mostRecentLocation = null;
|
||||
|
||||
this._gclueService = null;
|
||||
this._gclueStarted = false;
|
||||
this._gclueStarting = false;
|
||||
this._gclueLocationChangedId = 0;
|
||||
|
||||
this._weatherAuthorized = false;
|
||||
this._permStore = new PermissionStore.PermissionStore((proxy, error) => {
|
||||
if (error) {
|
||||
log('Failed to connect to permissionStore: ' + error.message);
|
||||
return;
|
||||
}
|
||||
|
||||
this._permStore.LookupRemote('gnome', 'geolocation', (res, error) => {
|
||||
if (error)
|
||||
log('Error looking up permission: ' + error.message);
|
||||
|
||||
let [perms, data] = error ? [{}, null] : res;
|
||||
let params = ['gnome', 'geolocation', false, data, perms];
|
||||
this._onPermStoreChanged(this._permStore, '', params);
|
||||
});
|
||||
});
|
||||
this._permStore.connectSignal('Changed',
|
||||
Lang.bind(this, this._onPermStoreChanged));
|
||||
|
||||
this._locationSettings = new Gio.Settings({ schema_id: 'org.gnome.system.location' });
|
||||
this._locationSettings.connect('changed::enabled',
|
||||
Lang.bind(this, this._updateAutoLocation));
|
||||
|
||||
this._world = GWeather.Location.get_world();
|
||||
|
||||
this._providers = GWeather.Provider.METAR |
|
||||
GWeather.Provider.YR_NO |
|
||||
GWeather.Provider.OWM;
|
||||
|
||||
this._weatherInfo = new GWeather.Info({ enabled_providers: 0 });
|
||||
this._weatherInfo.connect_after('updated', () => {
|
||||
this._lastUpdate = GLib.DateTime.new_now_local();
|
||||
this.emit('changed');
|
||||
});
|
||||
|
||||
this._weatherAppMon = new Util.AppSettingsMonitor('org.gnome.Weather.Application.desktop',
|
||||
'org.gnome.Weather.Application');
|
||||
this._weatherAppMon.connect('available-changed', () => { this.emit('changed'); });
|
||||
this._weatherAppMon.watchSetting('automatic-location',
|
||||
Lang.bind(this, this._onAutomaticLocationChanged));
|
||||
this._weatherAppMon.watchSetting('locations',
|
||||
Lang.bind(this, this._onLocationsChanged));
|
||||
},
|
||||
|
||||
get available() {
|
||||
return this._weatherAppMon.available;
|
||||
},
|
||||
|
||||
get loading() {
|
||||
return this._loading;
|
||||
},
|
||||
|
||||
get hasLocation() {
|
||||
return this._locationValid;
|
||||
},
|
||||
|
||||
get info() {
|
||||
return this._weatherInfo;
|
||||
},
|
||||
|
||||
activateApp: function() {
|
||||
this._weatherAppMon.activateApp();
|
||||
},
|
||||
|
||||
update: function() {
|
||||
if (!this._locationValid)
|
||||
return;
|
||||
|
||||
let now = GLib.DateTime.new_now_local();
|
||||
// Update without loading indication if the current info is recent enough
|
||||
if (this._weatherInfo.is_valid() &&
|
||||
now.difference(this._lastUpdate) < UPDATE_THRESHOLD)
|
||||
this._weatherInfo.update();
|
||||
else
|
||||
this._loadInfo();
|
||||
},
|
||||
|
||||
get _useAutoLocation() {
|
||||
return this._autoLocationRequested &&
|
||||
this._locationSettings.get_boolean('enabled') &&
|
||||
this._weatherAuthorized;
|
||||
},
|
||||
|
||||
_loadInfo: function() {
|
||||
let id = this._weatherInfo.connect('updated', () => {
|
||||
this._weatherInfo.disconnect(id);
|
||||
this._loading = false;
|
||||
});
|
||||
|
||||
this._loading = true;
|
||||
this.emit('changed');
|
||||
|
||||
this._weatherInfo.update();
|
||||
},
|
||||
|
||||
_locationsEqual: function(loc1, loc2) {
|
||||
if (loc1 == loc2)
|
||||
return true;
|
||||
|
||||
if (loc1 == null || loc2 == null)
|
||||
return false;
|
||||
|
||||
return loc1.equal(loc2);
|
||||
},
|
||||
|
||||
_setLocation: function(location) {
|
||||
if (this._locationsEqual(this._weatherInfo.location, location))
|
||||
return;
|
||||
|
||||
this._weatherInfo.abort();
|
||||
this._weatherInfo.set_location(location);
|
||||
this._locationValid = (location != null);
|
||||
|
||||
this._weatherInfo.set_enabled_providers(location ? this._providers : 0);
|
||||
|
||||
if (location)
|
||||
this._loadInfo();
|
||||
else
|
||||
this.emit('changed');
|
||||
},
|
||||
|
||||
_updateLocationMonitoring: function() {
|
||||
if (this._useAutoLocation) {
|
||||
if (this._gclueLocationChangedId != 0 || this._gclueService == null)
|
||||
return;
|
||||
|
||||
this._gclueLocationChangedId =
|
||||
this._gclueService.connect('notify::location',
|
||||
Lang.bind(this, this._onGClueLocationChanged));
|
||||
this._onGClueLocationChanged();
|
||||
} else {
|
||||
if (this._gclueLocationChangedId)
|
||||
this._gclueService.disconnect(this._gclueLocationChangedId);
|
||||
this._gclueLocationChangedId = 0;
|
||||
}
|
||||
},
|
||||
|
||||
_startGClueService: function() {
|
||||
if (this._gclueStarting)
|
||||
return;
|
||||
|
||||
this._gclueStarting = true;
|
||||
|
||||
Geoclue.Simple.new('org.gnome.Shell', Geoclue.AccuracyLevel.CITY, null,
|
||||
(o, res) => {
|
||||
try {
|
||||
this._gclueService = Geoclue.Simple.new_finish(res);
|
||||
} catch(e) {
|
||||
log('Failed to connect to Geoclue2 service: ' + e.message);
|
||||
this._setLocation(this._mostRecentLocation);
|
||||
return;
|
||||
}
|
||||
this._gclueStarted = true;
|
||||
this._gclueService.get_client().distance_threshold = 100;
|
||||
this._updateLocationMonitoring();
|
||||
});
|
||||
},
|
||||
|
||||
_onGClueLocationChanged: function() {
|
||||
let geoLocation = this._gclueService.location;
|
||||
let location = GWeather.Location.new_detached(geoLocation.description,
|
||||
null,
|
||||
geoLocation.latitude,
|
||||
geoLocation.longitude);
|
||||
this._setLocation(location);
|
||||
},
|
||||
|
||||
_onAutomaticLocationChanged: function(settings, key) {
|
||||
let useAutoLocation = settings.get_boolean(key);
|
||||
if (this._autoLocationRequested == useAutoLocation)
|
||||
return;
|
||||
|
||||
this._autoLocationRequested = useAutoLocation;
|
||||
|
||||
this._updateAutoLocation();
|
||||
},
|
||||
|
||||
_updateAutoLocation: function() {
|
||||
this._updateLocationMonitoring();
|
||||
|
||||
if (this._useAutoLocation)
|
||||
this._startGClueService();
|
||||
else
|
||||
this._setLocation(this._mostRecentLocation);
|
||||
},
|
||||
|
||||
_onLocationsChanged: function(settings, key) {
|
||||
let serialized = settings.get_value(key).deep_unpack().shift();
|
||||
let mostRecentLocation = null;
|
||||
|
||||
if (serialized)
|
||||
mostRecentLocation = this._world.deserialize(serialized);
|
||||
|
||||
if (this._locationsEqual(this._mostRecentLocation, mostRecentLocation))
|
||||
return;
|
||||
|
||||
this._mostRecentLocation = mostRecentLocation;
|
||||
|
||||
if (!this._useAutoLocation || !this._gclueStarted)
|
||||
this._setLocation(this._mostRecentLocation);
|
||||
},
|
||||
|
||||
_onPermStoreChanged: function(proxy, sender, params) {
|
||||
let [table, id, deleted, data, perms] = params;
|
||||
|
||||
if (table != 'gnome' || id != 'geolocation')
|
||||
return;
|
||||
|
||||
let permission = perms['org.gnome.Weather.Application'] || ['NONE'];
|
||||
let [accuracy] = permission;
|
||||
this._weatherAuthorized = accuracy != 'NONE';
|
||||
|
||||
this._updateAutoLocation();
|
||||
}
|
||||
});
|
||||
Signals.addSignalMethods(WeatherClient.prototype);
|
@ -19,6 +19,12 @@ const PortalHelperResult = {
|
||||
RECHECK: 2
|
||||
};
|
||||
|
||||
const PortalHelperSecurityLevel = {
|
||||
NOT_YET_DETERMINED: 0,
|
||||
SECURE: 1,
|
||||
INSECURE: 2
|
||||
};
|
||||
|
||||
const INACTIVITY_TIMEOUT = 30000; //ms
|
||||
const CONNECTIVITY_CHECK_HOST = 'nmcheck.gnome.org';
|
||||
const CONNECTIVITY_CHECK_URI = 'http://' + CONNECTIVITY_CHECK_HOST;
|
||||
@ -44,6 +50,71 @@ const HelperDBusInterface = '<node> \
|
||||
</interface> \
|
||||
</node>';
|
||||
|
||||
const PortalHeaderBar = new Lang.Class({
|
||||
Name: 'PortalHeaderBar',
|
||||
Extends: Gtk.HeaderBar,
|
||||
|
||||
_init: function() {
|
||||
this.parent({ show_close_button: true });
|
||||
|
||||
// See ephy-title-box.c in epiphany for the layout
|
||||
let vbox = new Gtk.Box({ orientation: Gtk.Orientation.VERTICAL,
|
||||
spacing: 0 });
|
||||
this.set_custom_title(vbox);
|
||||
|
||||
/* TRANSLATORS: this is the title of the wifi captive portal login window */
|
||||
let titleLabel = new Gtk.Label({ label: _("Hotspot Login"),
|
||||
wrap: false,
|
||||
single_line_mode: true,
|
||||
ellipsize: Pango.EllipsizeMode.END });
|
||||
titleLabel.get_style_context().add_class('title');
|
||||
vbox.add(titleLabel);
|
||||
|
||||
let hbox = new Gtk.Box({ orientation: Gtk.Orientation.HORIZONTAL,
|
||||
spacing: 4,
|
||||
halign: Gtk.Align.CENTER,
|
||||
valign: Gtk.Align.BASELINE });
|
||||
hbox.get_style_context().add_class('subtitle');
|
||||
vbox.add(hbox);
|
||||
|
||||
this._lockImage = new Gtk.Image({ icon_size: Gtk.IconSize.MENU,
|
||||
valign: Gtk.Align.BASELINE });
|
||||
hbox.add(this._lockImage);
|
||||
|
||||
this.subtitleLabel = new Gtk.Label({ wrap: false,
|
||||
single_line_mode: true,
|
||||
ellipsize: Pango.EllipsizeMode.END,
|
||||
valign: Gtk.Align.BASELINE,
|
||||
selectable: true});
|
||||
this.subtitleLabel.get_style_context().add_class('subtitle');
|
||||
hbox.add(this.subtitleLabel);
|
||||
|
||||
vbox.show_all();
|
||||
},
|
||||
|
||||
setSubtitle: function(label) {
|
||||
this.subtitleLabel.set_text(label);
|
||||
},
|
||||
|
||||
setSecurityIcon: function(securityLevel) {
|
||||
switch (securityLevel) {
|
||||
case PortalHelperSecurityLevel.NOT_YET_DETERMINED:
|
||||
this._lockImage.hide();
|
||||
break;
|
||||
case PortalHelperSecurityLevel.SECURE:
|
||||
this._lockImage.show();
|
||||
this._lockImage.set_from_icon_name("channel-secure-symbolic", Gtk.IconSize.MENU);
|
||||
this._lockImage.set_tooltip_text(null);
|
||||
break;
|
||||
case PortalHelperSecurityLevel.INSECURE:
|
||||
this._lockImage.show();
|
||||
this._lockImage.set_from_icon_name("channel-insecure-symbolic", Gtk.IconSize.MENU);
|
||||
this._lockImage.set_tooltip_text(_('Your connection to this hotspot login is not secure. Passwords or other information you enter on this page can be viewed by people nearby.'));
|
||||
break;
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
const PortalWindow = new Lang.Class({
|
||||
Name: 'PortalWindow',
|
||||
Extends: Gtk.ApplicationWindow,
|
||||
@ -51,6 +122,12 @@ const PortalWindow = new Lang.Class({
|
||||
_init: function(application, url, timestamp, doneCallback) {
|
||||
this.parent({ application: application });
|
||||
|
||||
this.connect('delete-event', Lang.bind(this, this.destroyWindow));
|
||||
this._headerBar = new PortalHeaderBar();
|
||||
this._headerBar.setSecurityIcon(PortalHelperSecurityLevel.NOT_YET_DETERMINED);
|
||||
this.set_titlebar(this._headerBar);
|
||||
this._headerBar.show();
|
||||
|
||||
if (!url) {
|
||||
url = CONNECTIVITY_CHECK_URI;
|
||||
this._originalUrlWasGnome = true;
|
||||
@ -64,28 +141,38 @@ const PortalWindow = new Lang.Class({
|
||||
this._lastRecheck = 0;
|
||||
this._recheckAtExit = false;
|
||||
|
||||
this._webView = new WebKit.WebView();
|
||||
this._webContext = WebKit.WebContext.new_ephemeral();
|
||||
this._webContext.set_cache_model(WebKit.CacheModel.DOCUMENT_VIEWER);
|
||||
this._webContext.set_network_proxy_settings(WebKit.NetworkProxyMode.NO_PROXY, null);
|
||||
|
||||
this._webView = WebKit.WebView.new_with_context(this._webContext);
|
||||
this._webView.connect('decide-policy', Lang.bind(this, this._onDecidePolicy));
|
||||
this._webView.connect('load-changed', Lang.bind(this, this._onLoadChanged));
|
||||
this._webView.connect('insecure-content-detected', Lang.bind(this, this._onInsecureContentDetected));
|
||||
this._webView.connect('load-failed-with-tls-errors', Lang.bind(this, this._onLoadFailedWithTlsErrors));
|
||||
this._webView.load_uri(url);
|
||||
this._webView.connect('notify::title', Lang.bind(this, this._syncTitle));
|
||||
this._syncTitle();
|
||||
this._webView.connect('notify::uri', Lang.bind(this, this._syncUri));
|
||||
this._syncUri();
|
||||
|
||||
this.add(this._webView);
|
||||
this._webView.show();
|
||||
this.set_size_request(600, 450);
|
||||
this.maximize();
|
||||
this.present_with_time(timestamp);
|
||||
|
||||
this.application.set_accels_for_action('app.quit', ['<Primary>q', '<Primary>w']);
|
||||
},
|
||||
|
||||
_syncTitle: function() {
|
||||
let title = this._webView.title;
|
||||
destroyWindow: function() {
|
||||
this.destroy();
|
||||
},
|
||||
|
||||
if (title) {
|
||||
this.title = title;
|
||||
} else {
|
||||
/* TRANSLATORS: this is the title of the wifi captive portal login
|
||||
* window, until we know the title of the actual login page */
|
||||
this.title = _("Web Authentication Redirect");
|
||||
}
|
||||
_syncUri: function() {
|
||||
let uri = this._webView.uri;
|
||||
if (uri)
|
||||
this._headerBar.setSubtitle(GLib.uri_unescape_string(uri, null));
|
||||
else
|
||||
this._headerBar.setSubtitle('');
|
||||
},
|
||||
|
||||
refresh: function() {
|
||||
@ -101,8 +188,46 @@ const PortalWindow = new Lang.Class({
|
||||
return false;
|
||||
},
|
||||
|
||||
_onLoadChanged: function(view, loadEvent) {
|
||||
if (loadEvent == WebKit.LoadEvent.STARTED) {
|
||||
this._headerBar.setSecurityIcon(PortalHelperSecurityLevel.NOT_YET_DETERMINED);
|
||||
} else if (loadEvent == WebKit.LoadEvent.COMMITTED) {
|
||||
let tlsInfo = this._webView.get_tls_info();
|
||||
let ret = tlsInfo[0];
|
||||
let flags = tlsInfo[2];
|
||||
if (ret && flags == 0)
|
||||
this._headerBar.setSecurityIcon(PortalHelperSecurityLevel.SECURE);
|
||||
else
|
||||
this._headerBar.setSecurityIcon(PortalHelperSecurityLevel.INSECURE);
|
||||
}
|
||||
},
|
||||
|
||||
_onInsecureContentDetected: function () {
|
||||
this._headerBar.setSecurityIcon(PortalHelperSecurityLevel.INSECURE);
|
||||
},
|
||||
|
||||
_onLoadFailedWithTlsErrors: function (view, failingURI, certificate, errors) {
|
||||
this._headerBar.setSecurityIcon(PortalHelperSecurityLevel.INSECURE);
|
||||
let uri = new Soup.URI(failingURI);
|
||||
this._webContext.allow_tls_certificate_for_host(certificate, uri.get_host());
|
||||
this._webView.load_uri(failingURI);
|
||||
return true;
|
||||
},
|
||||
|
||||
_onDecidePolicy: function(view, decision, type) {
|
||||
if (type == WebKit.PolicyDecisionType.NEW_WINDOW_ACTION) {
|
||||
let navigationAction = decision.get_navigation_action();
|
||||
if (navigationAction.is_user_gesture()) {
|
||||
// Even though the portal asks for a new window,
|
||||
// perform the navigation in the current one. Some
|
||||
// portals open a window as their last login step and
|
||||
// ignoring that window causes them to not let the
|
||||
// user go through. We don't risk popups taking over
|
||||
// the page because we check that the navigation is
|
||||
// user initiated.
|
||||
this._webView.load_request(navigationAction.get_request());
|
||||
}
|
||||
|
||||
decision.ignore();
|
||||
return true;
|
||||
}
|
||||
@ -168,6 +293,10 @@ const WebPortalHelper = new Lang.Class({
|
||||
|
||||
this._dbusImpl = Gio.DBusExportedObject.wrapJSObject(HelperDBusInterface, this);
|
||||
this._queue = [];
|
||||
|
||||
let action = new Gio.SimpleAction({ name: 'quit' });
|
||||
action.connect('activate', () => { this.active_window.destroyWindow(); });
|
||||
this.add_action(action);
|
||||
},
|
||||
|
||||
vfunc_dbus_register: function(connection, path) {
|
||||
@ -199,7 +328,7 @@ const WebPortalHelper = new Lang.Class({
|
||||
|
||||
if (obj.connection == connection) {
|
||||
if (obj.window)
|
||||
obj.window.destroy();
|
||||
obj.window.destroyWindow();
|
||||
this._queue.splice(i, 1);
|
||||
break;
|
||||
}
|
||||
@ -228,7 +357,7 @@ const WebPortalHelper = new Lang.Class({
|
||||
if (top.window != null)
|
||||
return;
|
||||
|
||||
top.window = new PortalWindow(this, top.uri, top.timestamp, Lang.bind(this, function(result) {
|
||||
top.window = new PortalWindow(this, top.url, top.timestamp, Lang.bind(this, function(result) {
|
||||
this._dbusImpl.emit_signal('Done', new GLib.Variant('(ou)', [top.connection, result]));
|
||||
}));
|
||||
},
|
||||
@ -241,6 +370,11 @@ function initEnvironment() {
|
||||
function main(argv) {
|
||||
initEnvironment();
|
||||
|
||||
if (!WebKit.WebContext.new_ephemeral) {
|
||||
log('WebKitGTK 2.16 is required for the portal-helper, see https://bugzilla.gnome.org/show_bug.cgi?id=780453');
|
||||
return 1;
|
||||
}
|
||||
|
||||
Gettext.bindtextdomain(Config.GETTEXT_PACKAGE, Config.LOCALEDIR);
|
||||
Gettext.textdomain(Config.GETTEXT_PACKAGE);
|
||||
|
||||
|
@ -33,10 +33,9 @@ const AppIconMode = {
|
||||
};
|
||||
|
||||
function _createWindowClone(window, size) {
|
||||
let windowTexture = window.get_texture();
|
||||
let [width, height] = windowTexture.get_size();
|
||||
let [width, height] = window.get_size();
|
||||
let scale = Math.min(1.0, size / width, size / height);
|
||||
return new Clutter.Clone({ source: windowTexture,
|
||||
return new Clutter.Clone({ source: window,
|
||||
width: width * scale,
|
||||
height: height * scale,
|
||||
x_align: Clutter.ActorAlign.CENTER,
|
||||
|
@ -899,6 +899,8 @@ const ControlsBoxLayout = Lang.Class({
|
||||
const ViewStackLayout = new Lang.Class({
|
||||
Name: 'ViewStackLayout',
|
||||
Extends: Clutter.BinLayout,
|
||||
Signals: { 'allocated-size-changed': { param_types: [GObject.TYPE_INT,
|
||||
GObject.TYPE_INT] } },
|
||||
|
||||
vfunc_allocate: function (actor, box, flags) {
|
||||
let availWidth = box.x2 - box.x1;
|
||||
@ -909,7 +911,6 @@ const ViewStackLayout = new Lang.Class({
|
||||
this.parent(actor, box, flags);
|
||||
}
|
||||
});
|
||||
Signals.addSignalMethods(ViewStackLayout.prototype);
|
||||
|
||||
const AppDisplay = new Lang.Class({
|
||||
Name: 'AppDisplay',
|
||||
@ -1082,6 +1083,8 @@ const AppSearchProvider = new Lang.Class({
|
||||
_init: function() {
|
||||
this._appSys = Shell.AppSystem.get_default();
|
||||
this.id = 'applications';
|
||||
this.isRemoteProvider = false;
|
||||
this.canLaunchSearch = false;
|
||||
},
|
||||
|
||||
getResultMetas: function(apps, callback) {
|
||||
@ -1250,6 +1253,7 @@ const FolderIcon = new Lang.Class({
|
||||
|
||||
_init: function(id, path, parentView) {
|
||||
this.id = id;
|
||||
this.name = '';
|
||||
this._parentView = parentView;
|
||||
|
||||
this._folder = new Gio.Settings({ schema_id: 'org.gnome.desktop.app-folders.folder',
|
||||
|
@ -21,8 +21,8 @@ const RENAMED_DESKTOP_IDS = {
|
||||
'gnibbles.desktop': 'org.gnome.Nibbles.desktop',
|
||||
'gnobots2.desktop': 'gnome-robots.desktop',
|
||||
'gnome-boxes.desktop': 'org.gnome.Boxes.desktop',
|
||||
'gnome-clocks.desktop': 'org.gnome.clocks.desktop',
|
||||
'gnome-calculator.desktop': 'org.gnome.Calculator.desktop',
|
||||
'gnome-clocks.desktop': 'org.gnome.clocks.desktop',
|
||||
'gnome-contacts.desktop': 'org.gnome.Contacts.desktop',
|
||||
'gnome-documents.desktop': 'org.gnome.Documents.desktop',
|
||||
'gnome-font-viewer.desktop': 'org.gnome.font-viewer.desktop',
|
||||
@ -59,12 +59,14 @@ const AppFavorites = new Lang.Class({
|
||||
|
||||
reload: function() {
|
||||
let ids = global.settings.get_strv(this.FAVORITE_APPS_KEY);
|
||||
let appSys = Shell.AppSystem.get_default();
|
||||
|
||||
// Map old desktop file names to the current ones
|
||||
let updated = false;
|
||||
ids = ids.map(function (id) {
|
||||
let newId = RENAMED_DESKTOP_IDS[id];
|
||||
if (newId !== undefined) {
|
||||
if (newId !== undefined &&
|
||||
appSys.lookup_app(newId) != null) {
|
||||
updated = true;
|
||||
return newId;
|
||||
}
|
||||
@ -74,7 +76,6 @@ const AppFavorites = new Lang.Class({
|
||||
if (updated)
|
||||
global.settings.set_strv(this.FAVORITE_APPS_KEY, ids);
|
||||
|
||||
let appSys = Shell.AppSystem.get_default();
|
||||
let apps = ids.map(function (id) {
|
||||
return appSys.lookup_app(id);
|
||||
}).filter(function (app) {
|
||||
|
@ -142,7 +142,6 @@ const BackgroundCache = new Lang.Class({
|
||||
Name: 'BackgroundCache',
|
||||
|
||||
_init: function() {
|
||||
this._pendingFileLoads = [];
|
||||
this._fileMonitors = {};
|
||||
this._backgroundSources = {};
|
||||
this._animations = {};
|
||||
@ -167,7 +166,8 @@ const BackgroundCache = new Lang.Class({
|
||||
settingsSchema: null,
|
||||
onLoaded: null });
|
||||
|
||||
if (this._animations[params.settingsSchema] && _fileEqual0(this._animationFile, params.file)) {
|
||||
let animation = this._animations[params.settingsSchema];
|
||||
if (animation && _fileEqual0(animation.file, params.file)) {
|
||||
if (params.onLoaded) {
|
||||
let id = GLib.idle_add(GLib.PRIORITY_DEFAULT, Lang.bind(this, function() {
|
||||
params.onLoaded(this._animations[params.settingsSchema]);
|
||||
@ -178,7 +178,7 @@ const BackgroundCache = new Lang.Class({
|
||||
return;
|
||||
}
|
||||
|
||||
let animation = new Animation({ file: params.file });
|
||||
animation = new Animation({ file: params.file });
|
||||
|
||||
animation.load(Lang.bind(this, function() {
|
||||
this._animations[params.settingsSchema] = animation;
|
||||
@ -255,7 +255,8 @@ const Background = new Lang.Class({
|
||||
this._loadAnimation(this._animation.file);
|
||||
}));
|
||||
|
||||
LoginManager.getLoginManager().connect('prepare-for-sleep',
|
||||
let loginManager = LoginManager.getLoginManager();
|
||||
this._prepareForSleepId = loginManager.connect('prepare-for-sleep',
|
||||
(lm, aboutToSuspend) => {
|
||||
if (aboutToSuspend)
|
||||
return;
|
||||
@ -284,6 +285,10 @@ const Background = new Lang.Class({
|
||||
this._clock.disconnect(this._timezoneChangedId);
|
||||
this._timezoneChangedId = 0;
|
||||
|
||||
if (this._prepareForSleepId != 0)
|
||||
LoginManager.getLoginManager().disconnect(this._prepareForSleepId);
|
||||
this._prepareForSleepId = 0;
|
||||
|
||||
if (this._settingsChangedSignalId != 0)
|
||||
this._settings.disconnect(this._settingsChangedSignalId);
|
||||
this._settingsChangedSignalId = 0;
|
||||
@ -377,11 +382,9 @@ const Background = new Lang.Class({
|
||||
|
||||
let cache = Meta.BackgroundImageCache.get_default();
|
||||
let numPendingImages = files.length;
|
||||
let images = [];
|
||||
for (let i = 0; i < files.length; i++) {
|
||||
this._watchFile(files[i]);
|
||||
let image = cache.load(files[i]);
|
||||
images.push(image);
|
||||
if (image.is_loaded()) {
|
||||
numPendingImages--;
|
||||
if (numPendingImages == 0)
|
||||
|
@ -20,7 +20,7 @@ const MSECS_IN_DAY = 24 * 60 * 60 * 1000;
|
||||
const SHOW_WEEKDATE_KEY = 'show-weekdate';
|
||||
const ELLIPSIS_CHAR = '\u2026';
|
||||
|
||||
const MESSAGE_ICON_SIZE = 32;
|
||||
const MESSAGE_ICON_SIZE = 16;
|
||||
|
||||
// alias to prevent xgettext from picking up strings translated in GTK+
|
||||
const gtk30_ = Gettext_gtk30.gettext;
|
||||
@ -706,6 +706,14 @@ const EventMessage = new Lang.Class({
|
||||
this._date = date;
|
||||
|
||||
this.parent(this._formatEventTime(), event.summary);
|
||||
|
||||
this._icon = new St.Icon({ icon_name: 'x-office-calendar-symbolic' });
|
||||
this.setIcon(this._icon);
|
||||
|
||||
this.actor.connect('style-changed', () => {
|
||||
let iconVisible = this.actor.get_parent().has_style_pseudo_class('first-child');
|
||||
this._icon.opacity = (iconVisible ? 255 : 0);
|
||||
});
|
||||
},
|
||||
|
||||
_formatEventTime: function() {
|
||||
@ -753,8 +761,8 @@ const NotificationMessage = new Lang.Class({
|
||||
_init: function(notification) {
|
||||
this.notification = notification;
|
||||
|
||||
this.setUseBodyMarkup(notification.bannerBodyMarkup);
|
||||
this.parent(notification.title, notification.bannerBodyText);
|
||||
this.setUseBodyMarkup(notification.bannerBodyMarkup);
|
||||
|
||||
this.setIcon(this._getIcon());
|
||||
|
||||
@ -811,7 +819,16 @@ const EventsSection = new Lang.Class({
|
||||
this._desktopSettings.connect('changed', Lang.bind(this, this._reloadEvents));
|
||||
this._eventSource = new EmptyEventSource();
|
||||
|
||||
this.parent('');
|
||||
this.parent();
|
||||
|
||||
this._title = new St.Button({ style_class: 'events-section-title',
|
||||
label: '',
|
||||
x_align: St.Align.START,
|
||||
can_focus: true });
|
||||
this.actor.insert_child_below(this._title, null);
|
||||
|
||||
this._title.connect('clicked', Lang.bind(this, this._onTitleClicked));
|
||||
this._title.connect('key-focus-in', Lang.bind(this, this._onKeyFocusIn));
|
||||
|
||||
Shell.AppSystem.get_default().connect('installed-changed',
|
||||
Lang.bind(this, this._appInstalledChanged));
|
||||
@ -832,10 +849,10 @@ const EventsSection = new Lang.Class({
|
||||
},
|
||||
|
||||
_updateTitle: function() {
|
||||
if (isToday(this._date)) {
|
||||
this._title.label = _("Events");
|
||||
this._title.visible = !isToday(this._date);
|
||||
|
||||
if (!this._title.visible)
|
||||
return;
|
||||
}
|
||||
|
||||
let dayFormat;
|
||||
let now = new Date();
|
||||
@ -897,7 +914,8 @@ const EventsSection = new Lang.Class({
|
||||
},
|
||||
|
||||
_onTitleClicked: function() {
|
||||
this.parent();
|
||||
Main.overview.hide();
|
||||
Main.panel.closeCalendar();
|
||||
|
||||
let app = this._getCalendarApp();
|
||||
if (app.get_id() == 'evolution.desktop')
|
||||
@ -928,7 +946,7 @@ const NotificationSection = new Lang.Class({
|
||||
Extends: MessageList.MessageListSection,
|
||||
|
||||
_init: function() {
|
||||
this.parent(_("Notifications"));
|
||||
this.parent();
|
||||
|
||||
this._sources = new Map();
|
||||
this._nUrgent = 0;
|
||||
@ -946,10 +964,14 @@ const NotificationSection = new Lang.Class({
|
||||
!Main.sessionMode.isGreeter;
|
||||
},
|
||||
|
||||
_createTimeLabel: function() {
|
||||
let label = Util.createTimeLabel(new Date());
|
||||
label.style_class = 'event-time',
|
||||
label.x_align = Clutter.ActorAlign.END;
|
||||
_createTimeLabel: function(datetime) {
|
||||
let label = new St.Label({ style_class: 'event-time',
|
||||
x_align: Clutter.ActorAlign.START,
|
||||
y_align: Clutter.ActorAlign.END });
|
||||
label.connect('notify::mapped', () => {
|
||||
if (label.mapped)
|
||||
label.text = Util.formatTimeSpan(datetime);
|
||||
});
|
||||
return label;
|
||||
},
|
||||
|
||||
@ -970,13 +992,13 @@ const NotificationSection = new Lang.Class({
|
||||
|
||||
_onNotificationAdded: function(source, notification) {
|
||||
let message = new NotificationMessage(notification);
|
||||
message.setSecondaryActor(this._createTimeLabel());
|
||||
message.setSecondaryActor(this._createTimeLabel(notification.datetime));
|
||||
|
||||
let isUrgent = notification.urgency == MessageTray.Urgency.CRITICAL;
|
||||
|
||||
let updatedId = notification.connect('updated', Lang.bind(this,
|
||||
function() {
|
||||
message.setSecondaryActor(this._createTimeLabel());
|
||||
message.setSecondaryActor(this._createTimeLabel(notification.datetime));
|
||||
this.moveMessage(message, isUrgent ? 0 : this._nUrgent, this.actor.mapped);
|
||||
}));
|
||||
let destroyId = notification.connect('destroy', Lang.bind(this,
|
||||
@ -1017,26 +1039,8 @@ const NotificationSection = new Lang.Class({
|
||||
message.notification.acknowledged = true;
|
||||
},
|
||||
|
||||
_onTitleClicked: function() {
|
||||
this.parent();
|
||||
|
||||
let app = Shell.AppSystem.get_default().lookup_app('gnome-notifications-panel.desktop');
|
||||
|
||||
if (!app) {
|
||||
log('Settings panel for desktop file ' + desktopFile + ' could not be loaded!');
|
||||
return;
|
||||
}
|
||||
|
||||
app.activate();
|
||||
},
|
||||
|
||||
_shouldShow: function() {
|
||||
return !this.empty && isToday(this._date);
|
||||
},
|
||||
|
||||
_sync: function() {
|
||||
this.parent();
|
||||
this._title.reactive = Main.sessionMode.allowSettings;
|
||||
}
|
||||
});
|
||||
|
||||
@ -1098,12 +1102,26 @@ const CalendarMessageList = new Lang.Class({
|
||||
this._placeholder = new Placeholder();
|
||||
this.actor.add_actor(this._placeholder.actor);
|
||||
|
||||
let box = new St.BoxLayout({ vertical: true,
|
||||
x_expand: true, y_expand: true });
|
||||
this.actor.add_actor(box);
|
||||
|
||||
this._scrollView = new St.ScrollView({ style_class: 'vfade',
|
||||
overlay_scrollbars: true,
|
||||
x_expand: true, y_expand: true,
|
||||
x_fill: true, y_fill: true });
|
||||
this._scrollView.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC);
|
||||
this.actor.add_actor(this._scrollView);
|
||||
box.add_actor(this._scrollView);
|
||||
|
||||
this._clearButton = new St.Button({ style_class: 'message-list-clear-button button',
|
||||
label: _("Clear All"),
|
||||
can_focus: true });
|
||||
this._clearButton.set_x_align(Clutter.ActorAlign.END);
|
||||
this._clearButton.connect('clicked', () => {
|
||||
let sections = [...this._sections.keys()];
|
||||
sections.forEach((s) => { s.clear(); });
|
||||
});
|
||||
box.add_actor(this._clearButton);
|
||||
|
||||
this._sectionList = new St.BoxLayout({ style_class: 'message-list-sections',
|
||||
vertical: true,
|
||||
@ -1129,6 +1147,7 @@ const CalendarMessageList = new Lang.Class({
|
||||
destroyId: 0,
|
||||
visibleId: 0,
|
||||
emptyChangedId: 0,
|
||||
canClearChangedId: 0,
|
||||
keyFocusId: 0
|
||||
};
|
||||
obj.destroyId = section.actor.connect('destroy', Lang.bind(this,
|
||||
@ -1139,6 +1158,8 @@ const CalendarMessageList = new Lang.Class({
|
||||
Lang.bind(this, this._sync));
|
||||
obj.emptyChangedId = section.connect('empty-changed',
|
||||
Lang.bind(this, this._sync));
|
||||
obj.canClearChangedId = section.connect('can-clear-changed',
|
||||
Lang.bind(this, this._sync));
|
||||
obj.keyFocusId = section.connect('key-focus-in',
|
||||
Lang.bind(this, this._onKeyFocusIn));
|
||||
|
||||
@ -1152,6 +1173,7 @@ const CalendarMessageList = new Lang.Class({
|
||||
section.actor.disconnect(obj.destroyId);
|
||||
section.actor.disconnect(obj.visibleId);
|
||||
section.disconnect(obj.emptyChangedId);
|
||||
section.disconnect(obj.canClearChangedId);
|
||||
section.disconnect(obj.keyFocusId);
|
||||
|
||||
this._sections.delete(section);
|
||||
@ -1172,10 +1194,16 @@ const CalendarMessageList = new Lang.Class({
|
||||
if (!visible)
|
||||
return;
|
||||
|
||||
let showPlaceholder = sections.every(function(s) {
|
||||
let empty = sections.every(function(s) {
|
||||
return s.empty || !s.actor.visible;
|
||||
});
|
||||
this._placeholder.actor.visible = showPlaceholder;
|
||||
this._placeholder.actor.visible = empty;
|
||||
this._clearButton.visible = !empty;
|
||||
|
||||
let canClear = sections.some(function(s) {
|
||||
return s.canClear && s.actor.visible;
|
||||
});
|
||||
this._clearButton.reactive = canClear;
|
||||
},
|
||||
|
||||
setEventSource: function(eventSource) {
|
||||
|
@ -298,7 +298,7 @@ const AuthenticationDialog = new Lang.Class({
|
||||
* requested authentication was not gained; this can happen
|
||||
* because of an authentication error (like invalid password),
|
||||
* for instance. */
|
||||
this._errorMessageLabel.set_text(_("Sorry, that didn\'t work. Please try again."));
|
||||
this._errorMessageLabel.set_text(_("Sorry, that didn’t work. Please try again."));
|
||||
this._errorMessageLabel.show();
|
||||
this._infoMessageLabel.hide();
|
||||
this._nullMessageLabel.hide();
|
||||
|
@ -6,11 +6,17 @@ const GLib = imports.gi.GLib;
|
||||
const Gtk = imports.gi.Gtk;
|
||||
const Lang = imports.lang;
|
||||
const Mainloop = imports.mainloop;
|
||||
const Shell = imports.gi.Shell;
|
||||
const Signals = imports.signals;
|
||||
const St = imports.gi.St;
|
||||
const Tpl = imports.gi.TelepathyLogger;
|
||||
const Tp = imports.gi.TelepathyGLib;
|
||||
|
||||
var Tpl = null;
|
||||
var Tp = null;
|
||||
try {
|
||||
Tpl = imports.gi.TelepathyLogger;
|
||||
Tp = imports.gi.TelepathyGLib;
|
||||
} catch(e) {
|
||||
log('Telepathy is not available, chat integration will be disabled.');
|
||||
}
|
||||
|
||||
const History = imports.misc.history;
|
||||
const Main = imports.ui.main;
|
||||
@ -20,6 +26,8 @@ const Params = imports.misc.params;
|
||||
const PopupMenu = imports.ui.popupMenu;
|
||||
const Util = imports.misc.util;
|
||||
|
||||
const HAVE_TP = (Tp != null && Tpl != null);
|
||||
|
||||
// See Notification.appendMessage
|
||||
const SCROLLBACK_IMMEDIATE_TIME = 3 * 60; // 3 minutes
|
||||
const SCROLLBACK_RECENT_TIME = 15 * 60; // 15 minutes
|
||||
@ -71,8 +79,43 @@ function makeMessageFromTplEvent(event) {
|
||||
};
|
||||
}
|
||||
|
||||
const TelepathyClient = new Lang.Class({
|
||||
const TelepathyComponent = new Lang.Class({
|
||||
Name: 'TelepathyComponent',
|
||||
|
||||
_init: function() {
|
||||
this._client = null;
|
||||
|
||||
if (!HAVE_TP)
|
||||
return; // Telepathy isn't available
|
||||
|
||||
this._client = new TelepathyClient();
|
||||
},
|
||||
|
||||
enable: function() {
|
||||
if (!this._client)
|
||||
return;
|
||||
|
||||
try {
|
||||
this._client.register();
|
||||
} catch (e) {
|
||||
throw new Error('Couldn\'t register Telepathy client. Error: \n' + e);
|
||||
}
|
||||
|
||||
if (!this._client.account_manager.is_prepared(Tp.AccountManager.get_feature_quark_core()))
|
||||
this._client.account_manager.prepare_async(null, null);
|
||||
},
|
||||
|
||||
disable: function() {
|
||||
if (!this._client)
|
||||
return;
|
||||
|
||||
this._client.unregister();
|
||||
}
|
||||
});
|
||||
|
||||
const TelepathyClient = HAVE_TP ? new Lang.Class({
|
||||
Name: 'TelepathyClient',
|
||||
Extends: Tp.BaseClient,
|
||||
|
||||
_init: function() {
|
||||
// channel path -> ChatSource
|
||||
@ -97,39 +140,28 @@ const TelepathyClient = new Lang.Class({
|
||||
// channel matching its filters is detected.
|
||||
// The second argument, recover, means _observeChannels will be run
|
||||
// for any existing channel as well.
|
||||
this._tpClient = new Shell.TpClient({ name: 'GnomeShell',
|
||||
account_manager: this._accountManager,
|
||||
uniquify_name: true });
|
||||
this._tpClient.set_observe_channels_func(
|
||||
Lang.bind(this, this._observeChannels));
|
||||
this._tpClient.set_approve_channels_func(
|
||||
Lang.bind(this, this._approveChannels));
|
||||
this._tpClient.set_handle_channels_func(
|
||||
Lang.bind(this, this._handleChannels));
|
||||
this.parent({ name: 'GnomeShell',
|
||||
account_manager: this._accountManager,
|
||||
uniquify_name: true });
|
||||
|
||||
// We only care about single-user text-based chats
|
||||
let filter = {};
|
||||
filter[Tp.PROP_CHANNEL_CHANNEL_TYPE] = Tp.IFACE_CHANNEL_TYPE_TEXT;
|
||||
filter[Tp.PROP_CHANNEL_TARGET_HANDLE_TYPE] = Tp.HandleType.CONTACT;
|
||||
|
||||
this.set_observer_recover(true);
|
||||
this.add_observer_filter(filter);
|
||||
this.add_approver_filter(filter);
|
||||
this.add_handler_filter(filter);
|
||||
|
||||
// Allow other clients (such as Empathy) to pre-empt our channels if
|
||||
// needed
|
||||
this._tpClient.set_delegated_channels_callback(
|
||||
this.set_delegated_channels_callback(
|
||||
Lang.bind(this, this._delegatedChannelsCb));
|
||||
},
|
||||
|
||||
enable: function() {
|
||||
try {
|
||||
this._tpClient.register();
|
||||
} catch (e) {
|
||||
throw new Error('Couldn\'t register Telepathy client. Error: \n' + e);
|
||||
}
|
||||
|
||||
if (!this._accountManager.is_prepared(Tp.AccountManager.get_feature_quark_core()))
|
||||
this._accountManager.prepare_async(null, null);
|
||||
},
|
||||
|
||||
disable: function() {
|
||||
this._tpClient.unregister();
|
||||
},
|
||||
|
||||
_observeChannels: function(observer, account, conn, channels,
|
||||
dispatchOp, requests, context) {
|
||||
vfunc_observe_channels: function(account, conn, channels,
|
||||
dispatchOp, requests, context) {
|
||||
let len = channels.length;
|
||||
for (let i = 0; i < len; i++) {
|
||||
let channel = channels[i];
|
||||
@ -153,7 +185,7 @@ const TelepathyClient = new Lang.Class({
|
||||
if (this._chatSources[channel.get_object_path()])
|
||||
return;
|
||||
|
||||
let source = new ChatSource(account, conn, channel, contact, this._tpClient);
|
||||
let source = new ChatSource(account, conn, channel, contact, this);
|
||||
|
||||
this._chatSources[channel.get_object_path()] = source;
|
||||
source.connect('destroy', Lang.bind(this,
|
||||
@ -162,8 +194,8 @@ const TelepathyClient = new Lang.Class({
|
||||
}));
|
||||
},
|
||||
|
||||
_handleChannels: function(handler, account, conn, channels,
|
||||
requests, user_action_time, context) {
|
||||
vfunc_handle_channels: function(account, conn, channels, requests,
|
||||
user_action_time, context) {
|
||||
this._handlingChannels(account, conn, channels, true);
|
||||
context.accept();
|
||||
},
|
||||
@ -193,7 +225,7 @@ const TelepathyClient = new Lang.Class({
|
||||
// Telepathy spec states that handlers must foreground channels
|
||||
// in HandleChannels calls which are already being handled.
|
||||
|
||||
if (notify && this._tpClient.is_handling_channel(channel)) {
|
||||
if (notify && this.is_handling_channel(channel)) {
|
||||
// We are already handling the channel, display the source
|
||||
let source = this._chatSources[channel.get_object_path()];
|
||||
if (source)
|
||||
@ -202,8 +234,8 @@ const TelepathyClient = new Lang.Class({
|
||||
}
|
||||
},
|
||||
|
||||
_approveChannels: function(approver, account, conn, channels,
|
||||
dispatchOp, context) {
|
||||
vfunc_add_dispatch_operation: function(account, conn, channels,
|
||||
dispatchOp, context) {
|
||||
let channel = channels[0];
|
||||
let chanType = channel.get_channel_type();
|
||||
|
||||
@ -230,7 +262,7 @@ const TelepathyClient = new Lang.Class({
|
||||
}
|
||||
|
||||
// Approve private text channels right away as we are going to handle it
|
||||
dispatchOp.claim_with_async(this._tpClient, Lang.bind(this, function(dispatchOp, result) {
|
||||
dispatchOp.claim_with_async(this, Lang.bind(this, function(dispatchOp, result) {
|
||||
try {
|
||||
dispatchOp.claim_with_finish(result);
|
||||
this._handlingChannels(account, conn, [channel], false);
|
||||
@ -246,7 +278,7 @@ const TelepathyClient = new Lang.Class({
|
||||
// Nothing to do as we don't make a distinction between observed and
|
||||
// handled channels.
|
||||
},
|
||||
});
|
||||
}) : null;
|
||||
|
||||
const ChatSource = new Lang.Class({
|
||||
Name: 'ChatSource',
|
||||
@ -660,7 +692,9 @@ const ChatNotification = new Lang.Class({
|
||||
}
|
||||
|
||||
if (message.direction == NotificationDirection.RECEIVED)
|
||||
this.update(this.source.title, messageBody, { bannerMarkup: true });
|
||||
this.update(this.source.title, messageBody,
|
||||
{ datetime: GLib.DateTime.new_from_unix_local (message.timestamp),
|
||||
bannerMarkup: true });
|
||||
|
||||
let group = (message.direction == NotificationDirection.RECEIVED ?
|
||||
'received' : 'sent');
|
||||
@ -962,4 +996,4 @@ const ChatNotificationBanner = new Lang.Class({
|
||||
}
|
||||
});
|
||||
|
||||
const Component = TelepathyClient;
|
||||
const Component = TelepathyComponent;
|
||||
|
@ -756,42 +756,44 @@ const Dash = new Lang.Class({
|
||||
let newIndex = 0;
|
||||
let oldIndex = 0;
|
||||
while (newIndex < newApps.length || oldIndex < oldApps.length) {
|
||||
let oldApp = oldApps.length > oldIndex ? oldApps[oldIndex] : null;
|
||||
let newApp = newApps.length > newIndex ? newApps[newIndex] : null;
|
||||
|
||||
// No change at oldIndex/newIndex
|
||||
if (oldApps[oldIndex] == newApps[newIndex]) {
|
||||
if (oldApp == newApp) {
|
||||
oldIndex++;
|
||||
newIndex++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// App removed at oldIndex
|
||||
if (oldApps[oldIndex] &&
|
||||
newApps.indexOf(oldApps[oldIndex]) == -1) {
|
||||
if (oldApp && newApps.indexOf(oldApp) == -1) {
|
||||
removedActors.push(children[oldIndex]);
|
||||
oldIndex++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// App added at newIndex
|
||||
if (newApps[newIndex] &&
|
||||
oldApps.indexOf(newApps[newIndex]) == -1) {
|
||||
addedItems.push({ app: newApps[newIndex],
|
||||
item: this._createAppItem(newApps[newIndex]),
|
||||
if (newApp && oldApps.indexOf(newApp) == -1) {
|
||||
addedItems.push({ app: newApp,
|
||||
item: this._createAppItem(newApp),
|
||||
pos: newIndex });
|
||||
newIndex++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// App moved
|
||||
let insertHere = newApps[newIndex + 1] &&
|
||||
newApps[newIndex + 1] == oldApps[oldIndex];
|
||||
let nextApp = newApps.length > newIndex + 1 ? newApps[newIndex + 1]
|
||||
: null;
|
||||
let insertHere = nextApp && nextApp == oldApp;
|
||||
let alreadyRemoved = removedActors.reduce(function(result, actor) {
|
||||
let removedApp = actor.child._delegate.app;
|
||||
return result || removedApp == newApps[newIndex];
|
||||
return result || removedApp == newApp;
|
||||
}, false);
|
||||
|
||||
if (insertHere || alreadyRemoved) {
|
||||
let newItem = this._createAppItem(newApps[newIndex]);
|
||||
addedItems.push({ app: newApps[newIndex],
|
||||
let newItem = this._createAppItem(newApp);
|
||||
addedItems.push({ app: newApp,
|
||||
item: newItem,
|
||||
pos: newIndex + removedActors.length });
|
||||
newIndex++;
|
||||
|
@ -8,6 +8,7 @@ const Gtk = imports.gi.Gtk;
|
||||
const GWeather = imports.gi.GWeather;
|
||||
const Lang = imports.lang;
|
||||
const Mainloop = imports.mainloop;
|
||||
const Pango = imports.gi.Pango;
|
||||
const Cairo = imports.cairo;
|
||||
const Clutter = imports.gi.Clutter;
|
||||
const Shell = imports.gi.Shell;
|
||||
@ -20,6 +21,7 @@ const Main = imports.ui.main;
|
||||
const PanelMenu = imports.ui.panelMenu;
|
||||
const PopupMenu = imports.ui.popupMenu;
|
||||
const Calendar = imports.ui.calendar;
|
||||
const Weather = imports.misc.weather;
|
||||
|
||||
function _isToday(date) {
|
||||
let now = new Date();
|
||||
@ -36,7 +38,7 @@ const TodayButton = new Lang.Class({
|
||||
// on the current date can be confusing. So don't make the button reactive
|
||||
// until the selected date changes.
|
||||
this.actor = new St.Button({ style_class: 'datemenu-today-button',
|
||||
x_align: St.Align.START,
|
||||
x_expand: true, x_align: St.Align.START,
|
||||
can_focus: true,
|
||||
reactive: false
|
||||
});
|
||||
@ -77,7 +79,7 @@ const TodayButton = new Lang.Class({
|
||||
* below the time in the shell; it should combine the weekday and the
|
||||
* date, e.g. "Tuesday February 17 2015".
|
||||
*/
|
||||
let dateFormat = Shell.util_translate_time_string (N_("%A %B %e %Y"));
|
||||
dateFormat = Shell.util_translate_time_string (N_("%A %B %e %Y"));
|
||||
this.actor.accessible_name = date.toLocaleFormat(dateFormat);
|
||||
}
|
||||
});
|
||||
@ -87,9 +89,7 @@ const WorldClocksSection = new Lang.Class({
|
||||
|
||||
_init: function() {
|
||||
this._clock = new GnomeDesktop.WallClock();
|
||||
this._settings = null;
|
||||
this._clockNotifyId = 0;
|
||||
this._changedId = 0;
|
||||
|
||||
this._locations = [];
|
||||
|
||||
@ -98,8 +98,7 @@ const WorldClocksSection = new Lang.Class({
|
||||
can_focus: true });
|
||||
this.actor.connect('clicked', Lang.bind(this,
|
||||
function() {
|
||||
let app = this._getClockApp();
|
||||
app.activate();
|
||||
this._clockAppMon.activateApp();
|
||||
|
||||
Main.overview.hide();
|
||||
Main.panel.closeCalendar();
|
||||
@ -112,40 +111,25 @@ const WorldClocksSection = new Lang.Class({
|
||||
|
||||
this.actor.child = this._grid;
|
||||
|
||||
Shell.AppSystem.get_default().connect('installed-changed',
|
||||
Lang.bind(this, this._sync));
|
||||
this._clockAppMon = new Util.AppSettingsMonitor('org.gnome.clocks.desktop',
|
||||
'org.gnome.clocks');
|
||||
this._clockAppMon.connect('available-changed',
|
||||
Lang.bind(this, this._sync));
|
||||
this._clockAppMon.watchSetting('world-clocks',
|
||||
Lang.bind(this, this._clocksChanged));
|
||||
this._sync();
|
||||
},
|
||||
|
||||
_getClockApp: function() {
|
||||
return Shell.AppSystem.get_default().lookup_app('org.gnome.clocks.desktop');
|
||||
},
|
||||
|
||||
_sync: function() {
|
||||
this.actor.visible = (this._getClockApp() != null);
|
||||
|
||||
if (this.actor.visible) {
|
||||
if (!this._settings) {
|
||||
this._settings = new Gio.Settings({ schema_id: 'org.gnome.clocks' });
|
||||
this._changedId =
|
||||
this._settings.connect('changed::world-clocks',
|
||||
Lang.bind(this, this._clocksChanged));
|
||||
this._clocksChanged();
|
||||
}
|
||||
} else {
|
||||
if (this._settings)
|
||||
this._settings.disconnect(this._changedId);
|
||||
this._settings = null;
|
||||
this._changedId = 0;
|
||||
}
|
||||
this.actor.visible = this._clockAppMon.available;
|
||||
},
|
||||
|
||||
_clocksChanged: function() {
|
||||
_clocksChanged: function(settings) {
|
||||
this._grid.destroy_all_children();
|
||||
this._locations = [];
|
||||
|
||||
let world = GWeather.Location.get_world();
|
||||
let clocks = this._settings.get_value('world-clocks').deep_unpack();
|
||||
let clocks = settings.get_value('world-clocks').deep_unpack();
|
||||
for (let i = 0; i < clocks.length; i++) {
|
||||
let l = world.deserialize(clocks[i].location);
|
||||
this._locations.push({ location: l });
|
||||
@ -210,6 +194,136 @@ const WorldClocksSection = new Lang.Class({
|
||||
}
|
||||
});
|
||||
|
||||
const WeatherSection = new Lang.Class({
|
||||
Name: 'WeatherSection',
|
||||
|
||||
_init: function() {
|
||||
this._weatherClient = new Weather.WeatherClient();
|
||||
|
||||
this.actor = new St.Button({ style_class: 'weather-button',
|
||||
x_fill: true,
|
||||
can_focus: true });
|
||||
this.actor.connect('clicked', () => {
|
||||
this._weatherClient.activateApp();
|
||||
|
||||
Main.overview.hide();
|
||||
Main.panel.closeCalendar();
|
||||
});
|
||||
this.actor.connect('notify::mapped', () => {
|
||||
if (this.actor.mapped)
|
||||
this._weatherClient.update();
|
||||
});
|
||||
|
||||
let box = new St.BoxLayout({ style_class: 'weather-box',
|
||||
vertical: true });
|
||||
|
||||
this.actor.child = box;
|
||||
|
||||
box.add_child(new St.Label({ style_class: 'weather-header',
|
||||
x_align: Clutter.ActorAlign.START,
|
||||
text: _("Weather") }));
|
||||
|
||||
this._conditionsLabel = new St.Label({ style_class: 'weather-conditions',
|
||||
x_align: Clutter.ActorAlign.START });
|
||||
this._conditionsLabel.clutter_text.ellipsize = Pango.EllipsizeMode.NONE;
|
||||
this._conditionsLabel.clutter_text.line_wrap = true;
|
||||
box.add_child(this._conditionsLabel);
|
||||
|
||||
this._weatherClient.connect('changed', Lang.bind(this, this._sync));
|
||||
this._sync();
|
||||
},
|
||||
|
||||
_getSummary: function(info) {
|
||||
let summary = info.get_conditions();
|
||||
if (summary == '-')
|
||||
return info.get_sky();
|
||||
return summary;
|
||||
},
|
||||
|
||||
_sameSummary: function(info1, info2) {
|
||||
let [ok1, phenom1, qualifier1] = info1.get_value_conditions();
|
||||
let [ok2, phenom2, qualifier2] = info2.get_value_conditions();
|
||||
if (ok1 || ok2)
|
||||
return ok1 == ok2 && phenom1 == phenom2 && qualifier1 == qualifier2;
|
||||
|
||||
let [, sky1] = info1.get_value_sky();
|
||||
let [, sky2] = info2.get_value_sky();
|
||||
return sky1 == sky2;
|
||||
},
|
||||
|
||||
_getSummaryText: function() {
|
||||
let info = this._weatherClient.info;
|
||||
let forecasts = info.get_forecast_list();
|
||||
if (forecasts.length == 0) // No forecasts, just current conditions
|
||||
return '%s.'.format(this._getSummary(info));
|
||||
|
||||
let current = info;
|
||||
let summaries = [this._getSummary(info)];
|
||||
for (let i = 0; i < forecasts.length; i++) {
|
||||
let [ok, timestamp] = forecasts[i].get_value_update();
|
||||
if (!_isToday(new Date(timestamp * 1000)))
|
||||
continue; // Ignore forecasts from other days
|
||||
|
||||
if (this._sameSummary(current, forecasts[i]))
|
||||
continue; // Ignore consecutive runs of equal summaries
|
||||
|
||||
current = forecasts[i];
|
||||
if (summaries.push(this._getSummary(current)) == 3)
|
||||
break; // Use a maximum of three summaries
|
||||
}
|
||||
|
||||
let fmt;
|
||||
switch(summaries.length) {
|
||||
/* Translators: %s is a weather condition like "Clear sky"; see
|
||||
libgweather for the possible condition strings. If at all
|
||||
possible, the sentence should match the grammatical case etc. of
|
||||
the inserted conditions. */
|
||||
case 1: fmt = _("%s all day."); break;
|
||||
|
||||
/* Translators: %s is a weather condition like "Clear sky"; see
|
||||
libgweather for the possible condition strings. If at all
|
||||
possible, the sentence should match the grammatical case etc. of
|
||||
the inserted conditions. */
|
||||
case 2: fmt = _("%s, then %s later."); break;
|
||||
|
||||
/* Translators: %s is a weather condition like "Clear sky"; see
|
||||
libgweather for the possible condition strings. If at all
|
||||
possible, the sentence should match the grammatical case etc. of
|
||||
the inserted conditions. */
|
||||
case 3: fmt = _("%s, then %s, followed by %s later."); break;
|
||||
}
|
||||
return String.prototype.format.apply(fmt, summaries);
|
||||
},
|
||||
|
||||
_getLabelText: function() {
|
||||
if (!this._weatherClient.hasLocation)
|
||||
return _("Select a location…");
|
||||
|
||||
if (this._weatherClient.loading)
|
||||
return _("Loading…");
|
||||
|
||||
let info = this._weatherClient.info;
|
||||
if (info.is_valid())
|
||||
return this._getSummaryText() + ' ' +
|
||||
/* Translators: %s is a temperature with unit, e.g. "23℃" */
|
||||
_("Feels like %s.").format(info.get_apparent());
|
||||
|
||||
if (info.network_error())
|
||||
return _("Go online for weather information");
|
||||
|
||||
return _("Weather information is currently unavailable");
|
||||
},
|
||||
|
||||
_sync: function() {
|
||||
this.actor.visible = this._weatherClient.available;
|
||||
|
||||
if (!this.actor.visible)
|
||||
return;
|
||||
|
||||
this._conditionsLabel.text = this._getLabelText();
|
||||
}
|
||||
});
|
||||
|
||||
const MessagesIndicator = new Lang.Class({
|
||||
Name: 'MessagesIndicator',
|
||||
|
||||
@ -256,8 +370,7 @@ const IndicatorPad = new Lang.Class({
|
||||
|
||||
_init: function(actor) {
|
||||
this._source = actor;
|
||||
this._source.connect('notify::visible',
|
||||
Lang.bind(this, this.queue_relayout));
|
||||
this._source.connect('notify::visible', () => { this.queue_relayout(); });
|
||||
this.parent();
|
||||
},
|
||||
|
||||
@ -297,14 +410,38 @@ const FreezableBinLayout = new Lang.Class({
|
||||
|
||||
vfunc_get_preferred_width: function(container, forHeight) {
|
||||
if (!this._frozen || this._savedWidth.some(isNaN))
|
||||
this._savedWidth = this.parent(container, forHeight);
|
||||
return this.parent(container, forHeight);
|
||||
return this._savedWidth;
|
||||
},
|
||||
|
||||
vfunc_get_preferred_height: function(container, forWidth) {
|
||||
if (!this._frozen || this._savedHeight.some(isNaN))
|
||||
this._savedHeight = this.parent(container, forWidth);
|
||||
return this.parent(container, forWidth);
|
||||
return this._savedHeight;
|
||||
},
|
||||
|
||||
vfunc_allocate: function(container, allocation, flags) {
|
||||
this.parent(container, allocation, flags);
|
||||
|
||||
let [width, height] = allocation.get_size();
|
||||
this._savedWidth = [width, width];
|
||||
this._savedHeight = [height, height];
|
||||
}
|
||||
});
|
||||
|
||||
const CalendarColumnLayout = new Lang.Class({
|
||||
Name: 'CalendarColumnLayout',
|
||||
Extends: Clutter.BoxLayout,
|
||||
|
||||
_init: function(actor) {
|
||||
this.parent({ orientation: Clutter.Orientation.VERTICAL });
|
||||
this._calActor = actor;
|
||||
},
|
||||
|
||||
vfunc_get_preferred_width: function(container, forHeight) {
|
||||
if (!this._calActor || this._calActor.get_parent() != container)
|
||||
return this.parent(container, forHeight);
|
||||
return this._calActor.get_preferred_width(forHeight);
|
||||
}
|
||||
});
|
||||
|
||||
@ -337,6 +474,8 @@ const DateMenuButton = new Lang.Class({
|
||||
|
||||
let layout = new FreezableBinLayout();
|
||||
let bin = new St.Widget({ layout_manager: layout });
|
||||
// For some minimal compatibility with PopupMenuItem
|
||||
bin._delegate = this;
|
||||
this.menu.box.add_child(bin);
|
||||
|
||||
hbox = new St.BoxLayout({ name: 'calendarArea' });
|
||||
@ -364,14 +503,16 @@ const DateMenuButton = new Lang.Class({
|
||||
hbox.add(this._messageList.actor, { expand: true, y_fill: false, y_align: St.Align.START });
|
||||
|
||||
// Fill up the second column
|
||||
vbox = new St.BoxLayout({ style_class: 'datemenu-calendar-column',
|
||||
vertical: true });
|
||||
let boxLayout = new CalendarColumnLayout(this._calendar.actor);
|
||||
vbox = new St.Widget({ style_class: 'datemenu-calendar-column',
|
||||
layout_manager: boxLayout });
|
||||
boxLayout.hookup_style(vbox);
|
||||
hbox.add(vbox);
|
||||
|
||||
this._date = new TodayButton(this._calendar);
|
||||
vbox.add_actor(this._date.actor);
|
||||
|
||||
vbox.add(this._calendar.actor);
|
||||
vbox.add_actor(this._calendar.actor);
|
||||
|
||||
this._displaysSection = new St.ScrollView({ style_class: 'datemenu-displays-section vfade',
|
||||
x_expand: true, x_fill: true,
|
||||
@ -386,6 +527,8 @@ const DateMenuButton = new Lang.Class({
|
||||
this._clocksItem = new WorldClocksSection();
|
||||
displaysBox.add(this._clocksItem.actor, { x_fill: true });
|
||||
|
||||
this._weatherItem = new WeatherSection();
|
||||
displaysBox.add(this._weatherItem.actor, { x_fill: true });
|
||||
|
||||
// Done with hbox for calendar and event list
|
||||
|
||||
|
@ -14,6 +14,7 @@ const DRAG_DISTANCE = 80;
|
||||
const EdgeDragAction = new Lang.Class({
|
||||
Name: 'EdgeDragAction',
|
||||
Extends: Clutter.GestureAction,
|
||||
Signals: { 'activated': {} },
|
||||
|
||||
_init : function(side, allowedModes) {
|
||||
this.parent();
|
||||
@ -81,4 +82,3 @@ const EdgeDragAction = new Lang.Class({
|
||||
this.emit('activated');
|
||||
}
|
||||
});
|
||||
Signals.addSignalMethods(EdgeDragAction.prototype);
|
||||
|
@ -457,7 +457,6 @@ const EndSessionDialog = new Lang.Class({
|
||||
_setLabelText(this._descriptionLabel, description);
|
||||
_setLabelText(this._subjectLabel, subject);
|
||||
|
||||
let dialogContent = DialogContent[this._type];
|
||||
if (dialogContent.iconName) {
|
||||
this._iconBin.child = new St.Icon({ icon_name: dialogContent.iconName,
|
||||
icon_size: _DIALOG_ICON_SIZE,
|
||||
|
@ -1,6 +1,8 @@
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
|
||||
imports.gi.versions.Clutter = '1.0';
|
||||
const Config = imports.misc.config;
|
||||
|
||||
imports.gi.versions.Clutter = Config.LIBMUTTER_API_VERSION;
|
||||
imports.gi.versions.Gio = '2.0';
|
||||
imports.gi.versions.Gdk = '3.0';
|
||||
imports.gi.versions.GdkPixbuf = '2.0';
|
||||
|
@ -252,7 +252,7 @@ const InstallExtensionDialog = new Lang.Class({
|
||||
return;
|
||||
}
|
||||
|
||||
invocation.return_value(GLib.Variant.new('(s)', 'successful'));
|
||||
invocation.return_value(GLib.Variant.new('(s)', ['successful']));
|
||||
}
|
||||
|
||||
_httpSession.queue_message(message, Lang.bind(this, function(session, message) {
|
||||
|
@ -38,6 +38,7 @@ const connect = Lang.bind(_signals, _signals.connect);
|
||||
const disconnect = Lang.bind(_signals, _signals.disconnect);
|
||||
|
||||
const ENABLED_EXTENSIONS_KEY = 'enabled-extensions';
|
||||
const DISABLE_USER_EXTENSIONS_KEY = 'disable-user-extensions';
|
||||
const EXTENSION_DISABLE_VERSION_CHECK_KEY = 'disable-extension-version-validation';
|
||||
|
||||
var initted = false;
|
||||
@ -238,11 +239,16 @@ function initExtension(uuid) {
|
||||
}
|
||||
|
||||
function getEnabledExtensions() {
|
||||
let extensions = global.settings.get_strv(ENABLED_EXTENSIONS_KEY);
|
||||
if (!Array.isArray(Main.sessionMode.enabledExtensions))
|
||||
let extensions;
|
||||
if (Array.isArray(Main.sessionMode.enabledExtensions))
|
||||
extensions = Main.sessionMode.enabledExtensions;
|
||||
else
|
||||
extensions = [];
|
||||
|
||||
if (global.settings.get_boolean(DISABLE_USER_EXTENSIONS_KEY))
|
||||
return extensions;
|
||||
|
||||
return Main.sessionMode.enabledExtensions.concat(extensions);
|
||||
return extensions.concat(global.settings.get_strv(ENABLED_EXTENSIONS_KEY));
|
||||
}
|
||||
|
||||
function onEnabledExtensionsChanged() {
|
||||
@ -276,18 +282,27 @@ function _onVersionValidationChanged() {
|
||||
// temporarily disable them all
|
||||
enabledExtensions = [];
|
||||
for (let uuid in ExtensionUtils.extensions)
|
||||
reloadExtension(ExtensionUtils.extensions[uuid]);
|
||||
try {
|
||||
reloadExtension(ExtensionUtils.extensions[uuid]);
|
||||
} catch(e) {
|
||||
logExtensionError(uuid, e);
|
||||
}
|
||||
enabledExtensions = getEnabledExtensions();
|
||||
|
||||
if (Main.sessionMode.allowExtensions) {
|
||||
enabledExtensions.forEach(function(uuid) {
|
||||
enableExtension(uuid);
|
||||
try {
|
||||
enableExtension(uuid);
|
||||
} catch(e) {
|
||||
logExtensionError(uuid, e);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function _loadExtensions() {
|
||||
global.settings.connect('changed::' + ENABLED_EXTENSIONS_KEY, onEnabledExtensionsChanged);
|
||||
global.settings.connect('changed::' + DISABLE_USER_EXTENSIONS_KEY, onEnabledExtensionsChanged);
|
||||
global.settings.connect('changed::' + EXTENSION_DISABLE_VERSION_CHECK_KEY, _onVersionValidationChanged);
|
||||
|
||||
enabledExtensions = getEnabledExtensions();
|
||||
|
@ -19,6 +19,7 @@ const CandidateArea = new Lang.Class({
|
||||
|
||||
_init: function() {
|
||||
this.actor = new St.BoxLayout({ vertical: true,
|
||||
reactive: true,
|
||||
visible: false });
|
||||
this._candidateBoxes = [];
|
||||
for (let i = 0; i < MAX_CANDIDATES_PER_PAGE; ++i) {
|
||||
@ -39,6 +40,19 @@ const CandidateArea = new Lang.Class({
|
||||
}));
|
||||
}
|
||||
|
||||
this.actor.connect('scroll-event', Lang.bind(this, function(actor, event) {
|
||||
let direction = event.get_scroll_direction();
|
||||
switch(direction) {
|
||||
case Clutter.ScrollDirection.UP:
|
||||
this.emit('cursor-up');
|
||||
break;
|
||||
case Clutter.ScrollDirection.DOWN:
|
||||
this.emit('cursor-down');
|
||||
break;
|
||||
};
|
||||
return Clutter.EVENT_PROPAGATE;
|
||||
}));
|
||||
|
||||
this._buttonBox = new St.BoxLayout({ style_class: 'candidate-page-button-box' });
|
||||
|
||||
this._previousButton = new St.Button({ style_class: 'candidate-page-button candidate-page-button-previous button' });
|
||||
@ -144,6 +158,14 @@ const CandidatePopup = new Lang.Class({
|
||||
this._candidateArea.connect('next-page', Lang.bind(this, function() {
|
||||
this._panelService.page_down();
|
||||
}));
|
||||
|
||||
this._candidateArea.connect('cursor-up', Lang.bind(this, function() {
|
||||
this._panelService.cursor_up();
|
||||
}));
|
||||
this._candidateArea.connect('cursor-down', Lang.bind(this, function() {
|
||||
this._panelService.cursor_down();
|
||||
}));
|
||||
|
||||
this._candidateArea.connect('candidate-clicked', Lang.bind(this, function(ca, index, button, state) {
|
||||
this._panelService.candidate_clicked(index, button, state);
|
||||
}));
|
||||
|
@ -570,7 +570,7 @@ const Keyboard = new Lang.Class({
|
||||
shouldTakeEvent: function(event) {
|
||||
let actor = event.get_source();
|
||||
return Main.layoutManager.keyboardBox.contains(actor) ||
|
||||
actor._extended_keys || actor.extended_key;
|
||||
!!actor._extended_keys || !!actor.extended_key;
|
||||
},
|
||||
|
||||
_clearKeyboardRestTimer: function() {
|
||||
|
@ -896,7 +896,10 @@ const LayoutManager = new Lang.Class({
|
||||
},
|
||||
|
||||
findMonitorForActor: function(actor) {
|
||||
return this.monitors[this.findIndexForActor(actor)];
|
||||
let index = this.findIndexForActor(actor);
|
||||
if (index >= 0 && index < this.monitors.length)
|
||||
return this.monitors[index];
|
||||
return null;
|
||||
},
|
||||
|
||||
_queueUpdateRegions: function() {
|
||||
@ -966,7 +969,11 @@ const LayoutManager = new Lang.Class({
|
||||
if (actorData.affectsInputRegion && wantsInputRegion && actorData.actor.get_paint_visibility())
|
||||
rects.push(new Meta.Rectangle({ x: x, y: y, width: w, height: h }));
|
||||
|
||||
if (actorData.affectsStruts) {
|
||||
let monitor = null;
|
||||
if (actorData.affectsStruts)
|
||||
monitor = this.findMonitorForActor(actorData.actor);
|
||||
|
||||
if (monitor) {
|
||||
// Limit struts to the size of the screen
|
||||
let x1 = Math.max(x, 0);
|
||||
let x2 = Math.min(x + w, global.screen_width);
|
||||
@ -983,7 +990,6 @@ const LayoutManager = new Lang.Class({
|
||||
// spans the width/height across the middle of the
|
||||
// screen, then we don't create a strut for it at all.
|
||||
|
||||
let monitor = this.findMonitorForActor(actorData.actor);
|
||||
let side;
|
||||
if (x1 <= monitor.x && x2 >= monitor.x + monitor.width) {
|
||||
if (y1 <= monitor.y)
|
||||
|
@ -33,7 +33,6 @@ var commandHeader = 'const Clutter = imports.gi.Clutter; ' +
|
||||
'const Mainloop = imports.mainloop; ' +
|
||||
'const Meta = imports.gi.Meta; ' +
|
||||
'const Shell = imports.gi.Shell; ' +
|
||||
'const Tp = imports.gi.TelepathyGLib; ' +
|
||||
'const Main = imports.ui.main; ' +
|
||||
'const Lang = imports.lang; ' +
|
||||
'const Tweener = imports.ui.tweener; ' +
|
||||
@ -784,6 +783,7 @@ const LookingGlass = new Lang.Class({
|
||||
|
||||
this._open = false;
|
||||
|
||||
this._it = null;
|
||||
this._offset = 0;
|
||||
this._results = [];
|
||||
|
||||
|
@ -165,6 +165,11 @@ const ScaleLayout = new Lang.Class({
|
||||
Name: 'ScaleLayout',
|
||||
Extends: Clutter.BinLayout,
|
||||
|
||||
_init: function(params) {
|
||||
this._container = null;
|
||||
this.parent(params);
|
||||
},
|
||||
|
||||
_connectContainer: function(container) {
|
||||
if (this._container == container)
|
||||
return;
|
||||
@ -299,6 +304,8 @@ const Message = new Lang.Class({
|
||||
_init: function(title, body) {
|
||||
this.expanded = false;
|
||||
|
||||
this._useBodyMarkup = false;
|
||||
|
||||
this.actor = new St.Button({ style_class: 'message',
|
||||
accessible_role: Atk.Role.NOTIFICATION,
|
||||
can_focus: true,
|
||||
@ -318,6 +325,7 @@ const Message = new Lang.Class({
|
||||
|
||||
this._iconBin = new St.Bin({ style_class: 'message-icon-bin',
|
||||
y_expand: true,
|
||||
y_align: St.Align.START,
|
||||
visible: false });
|
||||
hbox.add_actor(this._iconBin);
|
||||
|
||||
@ -331,18 +339,18 @@ const Message = new Lang.Class({
|
||||
let titleBox = new St.BoxLayout();
|
||||
contentBox.add_actor(titleBox);
|
||||
|
||||
this.titleLabel = new St.Label({ style_class: 'message-title',
|
||||
x_expand: true,
|
||||
x_align: Clutter.ActorAlign.START });
|
||||
this.titleLabel = new St.Label({ style_class: 'message-title' });
|
||||
this.setTitle(title);
|
||||
titleBox.add_actor(this.titleLabel);
|
||||
|
||||
this._secondaryBin = new St.Bin({ style_class: 'message-secondary-bin' });
|
||||
this._secondaryBin = new St.Bin({ style_class: 'message-secondary-bin',
|
||||
x_expand: true, y_expand: true,
|
||||
x_fill: true, y_fill: true });
|
||||
titleBox.add_actor(this._secondaryBin);
|
||||
|
||||
let closeIcon = new St.Icon({ icon_name: 'window-close-symbolic',
|
||||
icon_size: 16 });
|
||||
this._closeButton = new St.Button({ child: closeIcon, visible: false });
|
||||
this._closeButton = new St.Button({ child: closeIcon, opacity: 0 });
|
||||
titleBox.add_actor(this._closeButton);
|
||||
|
||||
this._bodyStack = new St.Widget({ x_expand: true });
|
||||
@ -493,9 +501,8 @@ const Message = new Lang.Class({
|
||||
},
|
||||
|
||||
_sync: function() {
|
||||
let hovered = this.actor.hover;
|
||||
this._closeButton.visible = hovered && this.canClose();
|
||||
this._secondaryBin.visible = !hovered;
|
||||
let visible = this.actor.hover && this.canClose();
|
||||
this._closeButton.opacity = visible ? 255 : 0;
|
||||
},
|
||||
|
||||
_onClicked: function() {
|
||||
@ -520,32 +527,10 @@ Signals.addSignalMethods(Message.prototype);
|
||||
const MessageListSection = new Lang.Class({
|
||||
Name: 'MessageListSection',
|
||||
|
||||
_init: function(title) {
|
||||
_init: function() {
|
||||
this.actor = new St.BoxLayout({ style_class: 'message-list-section',
|
||||
clip_to_allocation: true,
|
||||
x_expand: true, vertical: true });
|
||||
let titleBox = new St.BoxLayout({ style_class: 'message-list-section-title-box' });
|
||||
this.actor.add_actor(titleBox);
|
||||
|
||||
this._title = new St.Button({ style_class: 'message-list-section-title',
|
||||
label: title,
|
||||
can_focus: true,
|
||||
x_expand: true,
|
||||
x_align: St.Align.START });
|
||||
titleBox.add_actor(this._title);
|
||||
|
||||
this._title.connect('clicked', Lang.bind(this, this._onTitleClicked));
|
||||
this._title.connect('key-focus-in', Lang.bind(this, this._onKeyFocusIn));
|
||||
|
||||
let closeIcon = new St.Icon({ icon_name: 'window-close-symbolic' });
|
||||
this._closeButton = new St.Button({ style_class: 'message-list-section-close',
|
||||
child: closeIcon,
|
||||
accessible_name: _("Clear section"),
|
||||
can_focus: true });
|
||||
this._closeButton.set_x_align(Clutter.ActorAlign.END);
|
||||
titleBox.add_actor(this._closeButton);
|
||||
|
||||
this._closeButton.connect('clicked', Lang.bind(this, this.clear));
|
||||
|
||||
this._list = new St.BoxLayout({ style_class: 'message-list-section-list',
|
||||
vertical: true });
|
||||
@ -563,14 +548,10 @@ const MessageListSection = new Lang.Class({
|
||||
this._messages = new Map();
|
||||
this._date = new Date();
|
||||
this.empty = true;
|
||||
this.canClear = false;
|
||||
this._sync();
|
||||
},
|
||||
|
||||
_onTitleClicked: function() {
|
||||
Main.overview.hide();
|
||||
Main.panel.closeCalendar();
|
||||
},
|
||||
|
||||
_onKeyFocusIn: function(actor) {
|
||||
this.emit('key-focus-in', actor);
|
||||
},
|
||||
@ -719,7 +700,13 @@ const MessageListSection = new Lang.Class({
|
||||
if (changed)
|
||||
this.emit('empty-changed');
|
||||
|
||||
this._closeButton.visible = this._canClear();
|
||||
let canClear = this._canClear();
|
||||
changed = this.canClear !== canClear;
|
||||
this.canClear = canClear;
|
||||
|
||||
if (changed)
|
||||
this.emit('can-clear-changed');
|
||||
|
||||
this.actor.visible = this.allowed && this._shouldShow();
|
||||
}
|
||||
});
|
||||
|
@ -368,6 +368,7 @@ const Notification = new Lang.Class({
|
||||
secondaryGIcon: null,
|
||||
bannerMarkup: false,
|
||||
clear: false,
|
||||
datetime: null,
|
||||
soundName: null,
|
||||
soundFile: null });
|
||||
|
||||
@ -375,6 +376,11 @@ const Notification = new Lang.Class({
|
||||
this.bannerBodyText = banner;
|
||||
this.bannerBodyMarkup = params.bannerMarkup;
|
||||
|
||||
if (params.datetime)
|
||||
this.datetime = params.datetime;
|
||||
else
|
||||
this.datetime = GLib.DateTime.new_now_local();
|
||||
|
||||
if (params.gicon || params.clear)
|
||||
this.gicon = params.gicon;
|
||||
|
||||
@ -535,7 +541,8 @@ const NotificationBanner = new Lang.Class({
|
||||
|
||||
_addSecondaryIcon: function() {
|
||||
if (this.notification.secondaryGIcon) {
|
||||
let icon = new St.Icon({ gicon: this.notification.secondaryGIcon });
|
||||
let icon = new St.Icon({ gicon: this.notification.secondaryGIcon,
|
||||
x_align: Clutter.ActorAlign.END });
|
||||
this.setSecondaryActor(icon);
|
||||
}
|
||||
},
|
||||
@ -796,7 +803,7 @@ const Source = new Lang.Class({
|
||||
notification.acknowledged = false;
|
||||
this.pushNotification(notification);
|
||||
|
||||
if (this.policy.showBanners) {
|
||||
if (this.policy.showBanners || notification.urgency == Urgency.CRITICAL) {
|
||||
this.emit('notify', notification);
|
||||
} else {
|
||||
notification.playSound();
|
||||
@ -1224,7 +1231,7 @@ const MessageTray = new Lang.Class({
|
||||
if (this._notificationState == State.HIDDEN) {
|
||||
let nextNotification = this._notificationQueue[0] || null;
|
||||
if (hasNotifications && nextNotification) {
|
||||
let limited = this._busy || Main.layoutManager.bottomMonitor.inFullscreen;
|
||||
let limited = this._busy || Main.layoutManager.primaryMonitor.inFullscreen;
|
||||
let showNextNotification = (!limited || nextNotification.forFeedback || nextNotification.urgency == Urgency.CRITICAL);
|
||||
if (showNextNotification)
|
||||
this._showNotification();
|
||||
|
@ -36,6 +36,8 @@ const MprisPlayerIface = '<node> \
|
||||
<method name="PlayPause" /> \
|
||||
<method name="Next" /> \
|
||||
<method name="Previous" /> \
|
||||
<property name="CanGoNext" type="b" access="read" /> \
|
||||
<property name="CanGoPrevious" type="b" access="read" /> \
|
||||
<property name="CanPlay" type="b" access="read" /> \
|
||||
<property name="Metadata" type="a{sv}" access="read" /> \
|
||||
<property name="PlaybackStatus" type="s" access="read" /> \
|
||||
@ -57,7 +59,7 @@ const MediaMessage = new Lang.Class({
|
||||
this._icon = new St.Icon({ style_class: 'media-message-cover-icon' });
|
||||
this.setIcon(this._icon);
|
||||
|
||||
this.addMediaControl('media-skip-backward-symbolic',
|
||||
this._prevButton = this.addMediaControl('media-skip-backward-symbolic',
|
||||
Lang.bind(this, function() {
|
||||
this._player.previous();
|
||||
}));
|
||||
@ -67,7 +69,7 @@ const MediaMessage = new Lang.Class({
|
||||
this._player.playPause();
|
||||
}));
|
||||
|
||||
this.addMediaControl('media-skip-forward-symbolic',
|
||||
this._nextButton = this.addMediaControl('media-skip-forward-symbolic',
|
||||
Lang.bind(this, function() {
|
||||
this._player.next();
|
||||
}));
|
||||
@ -82,6 +84,10 @@ const MediaMessage = new Lang.Class({
|
||||
Main.panel.closeCalendar();
|
||||
},
|
||||
|
||||
_updateNavButton: function(button, sensitive) {
|
||||
button.reactive = sensitive;
|
||||
},
|
||||
|
||||
_update: function() {
|
||||
this.setTitle(this._player.trackArtists.join(', '));
|
||||
this.setBody(this._player.trackTitle);
|
||||
@ -99,6 +105,9 @@ const MediaMessage = new Lang.Class({
|
||||
let iconName = isPlaying ? 'media-playback-pause-symbolic'
|
||||
: 'media-playback-start-symbolic';
|
||||
this._playPauseButton.child.icon_name = iconName;
|
||||
|
||||
this._updateNavButton(this._prevButton, this._player.canGoPrevious);
|
||||
this._updateNavButton(this._nextButton, this._player.canGoNext);
|
||||
}
|
||||
});
|
||||
|
||||
@ -139,10 +148,18 @@ const MprisPlayer = new Lang.Class({
|
||||
this._playerProxy.PlayPauseRemote();
|
||||
},
|
||||
|
||||
get canGoNext() {
|
||||
return this._playerProxy.CanGoNext;
|
||||
},
|
||||
|
||||
next: function() {
|
||||
this._playerProxy.NextRemote();
|
||||
},
|
||||
|
||||
get canGoPrevious() {
|
||||
return this._playerProxy.CanGoPrevious;
|
||||
},
|
||||
|
||||
previous: function() {
|
||||
this._playerProxy.PreviousRemote();
|
||||
},
|
||||
@ -214,7 +231,7 @@ const MediaSection = new Lang.Class({
|
||||
Extends: MessageList.MessageListSection,
|
||||
|
||||
_init: function() {
|
||||
this.parent(_("Media"));
|
||||
this.parent();
|
||||
|
||||
this._players = new Map();
|
||||
|
||||
|
@ -128,10 +128,10 @@ const FdoNotificationDaemon = new Lang.Class({
|
||||
switch (hints.urgency) {
|
||||
case Urgency.LOW:
|
||||
case Urgency.NORMAL:
|
||||
stockIcon = 'gtk-dialog-info';
|
||||
stockIcon = 'dialog-information';
|
||||
break;
|
||||
case Urgency.CRITICAL:
|
||||
stockIcon = 'gtk-dialog-error';
|
||||
stockIcon = 'dialog-error';
|
||||
break;
|
||||
}
|
||||
return new Gio.ThemedIcon({ name: stockIcon });
|
||||
@ -186,7 +186,8 @@ const FdoNotificationDaemon = new Lang.Class({
|
||||
return source;
|
||||
}
|
||||
|
||||
let source = new FdoNotificationDaemonSource(title, pid, sender, ndata ? ndata.hints['desktop-entry'] : null);
|
||||
let appId = ndata ? ndata.hints['desktop-entry'] || null : null;
|
||||
source = new FdoNotificationDaemonSource(title, pid, sender, appId);
|
||||
|
||||
this._sources.push(source);
|
||||
source.connect('destroy', Lang.bind(this, function() {
|
||||
@ -391,10 +392,10 @@ const FdoNotificationDaemon = new Lang.Class({
|
||||
notification.setUrgency(MessageTray.Urgency.CRITICAL);
|
||||
break;
|
||||
}
|
||||
notification.setResident(hints.resident == true);
|
||||
notification.setResident(!!hints.resident);
|
||||
// 'transient' is a reserved keyword in JS, so we have to retrieve the value
|
||||
// of the 'transient' hint with hints['transient'] rather than hints.transient
|
||||
notification.setTransient(hints['transient'] == true);
|
||||
notification.setTransient(!!hints['transient']);
|
||||
|
||||
let sourceGIcon = source.useNotificationIcon ? gicon : null;
|
||||
source.processNotification(notification, sourceGIcon);
|
||||
@ -600,7 +601,8 @@ const GtkNotificationDaemonNotification = new Lang.Class({
|
||||
"priority": priority,
|
||||
"buttons": buttons,
|
||||
"default-action": defaultAction,
|
||||
"default-action-target": defaultActionTarget } = notification;
|
||||
"default-action-target": defaultActionTarget,
|
||||
"timestamp": time } = notification;
|
||||
|
||||
if (priority) {
|
||||
let urgency = PRIORITY_URGENCY_MAP[priority.unpack()];
|
||||
@ -623,7 +625,8 @@ const GtkNotificationDaemonNotification = new Lang.Class({
|
||||
this._defaultActionTarget = defaultActionTarget;
|
||||
|
||||
this.update(title.unpack(), body ? body.unpack() : null,
|
||||
{ gicon: gicon ? Gio.icon_deserialize(gicon) : null });
|
||||
{ gicon: gicon ? Gio.icon_deserialize(gicon) : null,
|
||||
datetime : time ? GLib.DateTime.new_from_unix_local(time.unpack()) : null });
|
||||
},
|
||||
|
||||
_activateAction: function(namespacedActionId, target) {
|
||||
@ -864,6 +867,9 @@ const GtkNotificationDaemon = new Lang.Class({
|
||||
return;
|
||||
}
|
||||
|
||||
let timestamp = GLib.DateTime.new_now_local().to_unix();
|
||||
notification['timestamp'] = new GLib.Variant('x', timestamp);
|
||||
|
||||
source.addNotification(notificationId, notification, true);
|
||||
|
||||
invocation.return_value(null);
|
||||
|
@ -107,9 +107,9 @@ const Overview = new Lang.Class({
|
||||
|
||||
this._overviewCreated = true;
|
||||
|
||||
/* Translators: This is the main view to select
|
||||
activities. See also note for "Activities" string. */
|
||||
this._overview = new St.BoxLayout({ name: 'overview',
|
||||
/* Translators: This is the main view to select
|
||||
activities. See also note for "Activities" string. */
|
||||
accessible_name: _("Overview"),
|
||||
vertical: true });
|
||||
this._overview.add_constraint(new LayoutManager.MonitorConstraint({ primary: true }));
|
||||
@ -378,7 +378,7 @@ const Overview = new Lang.Class({
|
||||
return null;
|
||||
|
||||
let window = windows[0];
|
||||
let clone = new Clutter.Clone({ source: window.get_texture(),
|
||||
let clone = new Clutter.Clone({ source: window,
|
||||
x: window.x, y: window.y });
|
||||
clone.source.connect('destroy', Lang.bind(this, function() {
|
||||
clone.destroy();
|
||||
|
309
js/ui/padOsd.js
309
js/ui/padOsd.js
@ -30,6 +30,72 @@ const CCW = 1;
|
||||
const UP = 0;
|
||||
const DOWN = 1;
|
||||
|
||||
const PadChooser = new Lang.Class({
|
||||
Name: 'PadChooser',
|
||||
|
||||
_init: function (device, groupDevices) {
|
||||
this.actor = new St.Button({ style_class: 'pad-chooser-button',
|
||||
toggle_mode: true,
|
||||
x_fill: false,
|
||||
y_fill: false,
|
||||
x_align: St.Align.MIDDLE,
|
||||
y_align: St.Align.MIDDLE });
|
||||
this.currentDevice = device;
|
||||
this._padChooserMenu = null;
|
||||
|
||||
let arrow = new St.Icon({ style_class: 'popup-menu-arrow',
|
||||
icon_name: 'pan-down-symbolic',
|
||||
accessible_role: Atk.Role.ARROW });
|
||||
this.actor.set_child(arrow);
|
||||
this._ensureMenu(groupDevices);
|
||||
|
||||
this.actor.connect('destroy', Lang.bind(this, this._onDestroy));
|
||||
this.actor.connect('clicked', Lang.bind(this, function (actor) {
|
||||
if (actor.get_checked()) {
|
||||
if (this._padChooserMenu != null)
|
||||
this._padChooserMenu.open(true);
|
||||
else
|
||||
this.set_checked(false);
|
||||
} else {
|
||||
this._padChooserMenu.close(true);
|
||||
}
|
||||
}));
|
||||
},
|
||||
|
||||
_ensureMenu: function (devices) {
|
||||
this._padChooserMenu = new PopupMenu.PopupMenu(this.actor, 0.5, St.Side.TOP);
|
||||
this._padChooserMenu.connect('menu-closed', Lang.bind(this, function() { this.actor.set_checked(false); }));
|
||||
this._padChooserMenu.actor.hide();
|
||||
Main.uiGroup.add_actor(this._padChooserMenu.actor);
|
||||
|
||||
for (let i = 0; i < devices.length; i++) {
|
||||
let device = devices[i];
|
||||
if (device == this.currentDevice)
|
||||
continue;
|
||||
|
||||
this._padChooserMenu.addAction(device.get_device_name(), () => {
|
||||
this.emit('pad-selected', device);
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
_onDestroy: function () {
|
||||
this._padChooserMenu.destroy();
|
||||
},
|
||||
|
||||
update: function (devices) {
|
||||
if (this._padChooserMenu)
|
||||
this._padChooserMenu.actor.destroy();
|
||||
this.actor.set_checked(false);
|
||||
this._ensureMenu(devices);
|
||||
},
|
||||
|
||||
destroy: function () {
|
||||
this.actor.destroy();
|
||||
},
|
||||
});
|
||||
Signals.addSignalMethods(PadChooser.prototype);
|
||||
|
||||
const KeybindingEntry = new Lang.Class({
|
||||
Name: 'KeybindingEntry',
|
||||
|
||||
@ -88,9 +154,16 @@ const ActionComboBox = new Lang.Class({
|
||||
this._actionLabels.set(GDesktopEnums.PadButtonAction.SWITCH_MONITOR, _("Switch monitor"));
|
||||
this._actionLabels.set(GDesktopEnums.PadButtonAction.KEYBINDING, _("Assign keystroke"));
|
||||
|
||||
this._buttonItems = [];
|
||||
|
||||
for (let [action, label] of this._actionLabels.entries()) {
|
||||
let selectedAction = action;
|
||||
this._editMenu.addAction(label, Lang.bind(this, function() { this._onActionSelected(selectedAction) }));
|
||||
let item = this._editMenu.addAction(label, Lang.bind(this, function() { this._onActionSelected(selectedAction) }));
|
||||
|
||||
/* These actions only apply to pad buttons */
|
||||
if (selectedAction == GDesktopEnums.PadButtonAction.HELP ||
|
||||
selectedAction == GDesktopEnums.PadButtonAction.SWITCH_MONITOR)
|
||||
this._buttonItems.push(item);
|
||||
}
|
||||
|
||||
this.setAction(GDesktopEnums.PadButtonAction.NONE);
|
||||
@ -119,6 +192,10 @@ const ActionComboBox = new Lang.Class({
|
||||
this.popup();
|
||||
else
|
||||
this.popdown();
|
||||
},
|
||||
|
||||
setButtonActionsActive: function (active) {
|
||||
this._buttonItems.forEach(item => { item.setSensitive(active); });
|
||||
}
|
||||
});
|
||||
Signals.addSignalMethods(ActionComboBox.prototype);
|
||||
@ -157,13 +234,16 @@ const ActionEditor = new Lang.Class({
|
||||
}
|
||||
},
|
||||
|
||||
setSettings: function (settings) {
|
||||
setSettings: function (settings, action) {
|
||||
this._buttonSettings = settings;
|
||||
|
||||
this._currentAction = this._buttonSettings.get_enum('action');
|
||||
this._currentKeybinding = this._buttonSettings.get_string('keybinding');
|
||||
this._actionComboBox.setAction(this._currentAction);
|
||||
this._updateKeybindingEntryState();
|
||||
|
||||
let isButton = (action == Meta.PadActionType.BUTTON);
|
||||
this._actionComboBox.setButtonActionsActive(isButton);
|
||||
},
|
||||
|
||||
close: function() {
|
||||
@ -227,6 +307,8 @@ const PadDiagram = new Lang.Class({
|
||||
_init: function (params) {
|
||||
let file = Gio.File.new_for_uri('resource:///org/gnome/shell/theme/pad-osd.css');
|
||||
let [success, css, etag] = file.load_contents(null);
|
||||
this._curEdited = null;
|
||||
this._prevEdited = null;
|
||||
this._css = css;
|
||||
this._labels = [];
|
||||
this._activeButtons = [];
|
||||
@ -484,25 +566,39 @@ const PadDiagram = new Lang.Class({
|
||||
this.add_actor(label);
|
||||
},
|
||||
|
||||
stopEdition: function (str) {
|
||||
_applyLabel: function(label, action, idx, dir, str) {
|
||||
if (str != null) {
|
||||
label.set_text(str);
|
||||
|
||||
let [found, x, y, arrangement] = this.getLabelCoords(action, idx, dir);
|
||||
this._allocateChild(label, x, y, arrangement);
|
||||
}
|
||||
label.show();
|
||||
},
|
||||
|
||||
stopEdition: function (continues, str) {
|
||||
this._editorActor.hide();
|
||||
|
||||
if (this._prevEdited) {
|
||||
let [label, action, idx, dir] = this._prevEdited;
|
||||
this._applyLabel(label, action, idx, dir, str);
|
||||
this._prevEdited = null;
|
||||
}
|
||||
|
||||
if (this._curEdited) {
|
||||
let [label, action, idx, dir] = this._curEdited;
|
||||
if (str != null) {
|
||||
label.set_text(str);
|
||||
|
||||
let [found, x, y, arrangement] = this.getLabelCoords(action, idx, dir);
|
||||
this._allocateChild(label, x, y, arrangement);
|
||||
}
|
||||
label.show();
|
||||
this._applyLabel(label, action, idx, dir, str);
|
||||
if (continues)
|
||||
this._prevEdited = this._curEdited;
|
||||
this._curEdited = null;
|
||||
}
|
||||
},
|
||||
|
||||
startEdition: function(action, idx, dir) {
|
||||
let editedLabel;
|
||||
this.stopEdition();
|
||||
|
||||
if (this._curEdited)
|
||||
return;
|
||||
|
||||
for (let i = 0; i < this._labels.length; i++) {
|
||||
let [label, itemAction, itemIdx, itemDir] = this._labels[i];
|
||||
@ -528,16 +624,39 @@ const PadOsd = new Lang.Class({
|
||||
|
||||
_init: function (padDevice, settings, imagePath, editionMode, monitorIndex) {
|
||||
this.padDevice = padDevice;
|
||||
this._groupPads = [ padDevice ];
|
||||
this._settings = settings;
|
||||
this._imagePath = imagePath;
|
||||
this._editionMode = editionMode;
|
||||
this._capturedEventId = global.stage.connect('captured-event', Lang.bind(this, this._onCapturedEvent));
|
||||
this._padChooser = null;
|
||||
|
||||
let deviceManager = Clutter.DeviceManager.get_default();
|
||||
this._deviceAddedId = deviceManager.connect('device-added', Lang.bind(this, function (manager, device) {
|
||||
if (device.get_device_type() == Clutter.InputDeviceType.PAD_DEVICE &&
|
||||
this.padDevice.is_grouped(device)) {
|
||||
this._groupPads.push(device);
|
||||
this._updatePadChooser();
|
||||
}
|
||||
}));
|
||||
this._deviceRemovedId = deviceManager.connect('device-removed', Lang.bind(this, function (manager, device) {
|
||||
// If the device is being removed, destroy the padOsd.
|
||||
if (device == this.padDevice)
|
||||
if (device == this.padDevice) {
|
||||
this.destroy();
|
||||
} else if (this._groupPads.indexOf(device) != -1) {
|
||||
// Or update the pad chooser if the device belongs to
|
||||
// the same group.
|
||||
this._groupPads.splice(this._groupPads.indexOf(device), 1);
|
||||
this._updatePadChooser();
|
||||
|
||||
}
|
||||
}));
|
||||
|
||||
deviceManager.list_devices().forEach(Lang.bind(this, function(device) {
|
||||
if (device != this.padDevice &&
|
||||
device.get_device_type() == Clutter.InputDeviceType.PAD_DEVICE &&
|
||||
this.padDevice.is_grouped(device))
|
||||
this._groupPads.push(device);
|
||||
}));
|
||||
|
||||
this.actor = new St.BoxLayout({ style_class: 'pad-osd-window',
|
||||
@ -552,16 +671,28 @@ const PadOsd = new Lang.Class({
|
||||
let constraint = new Layout.MonitorConstraint({ index: monitorIndex });
|
||||
this.actor.add_constraint(constraint);
|
||||
|
||||
this._titleBox = new St.BoxLayout({ style_class: 'pad-osd-title-box',
|
||||
vertical: false,
|
||||
x_expand: false,
|
||||
x_align: Clutter.ActorAlign.CENTER });
|
||||
this.actor.add_actor(this._titleBox);
|
||||
|
||||
let labelBox = new St.BoxLayout({ style_class: 'pad-osd-title-menu-box',
|
||||
vertical: true });
|
||||
this._titleBox.add_actor(labelBox);
|
||||
|
||||
this._titleLabel = new St.Label({ style: 'font-side: larger; font-weight: bold;',
|
||||
x_align: Clutter.ActorAlign.CENTER });
|
||||
this._titleLabel.clutter_text.set_text(padDevice.get_device_name());
|
||||
this.actor.add_actor(this._titleLabel);
|
||||
labelBox.add_actor(this._titleLabel);
|
||||
|
||||
this._tipLabel = new St.Label({ x_align: Clutter.ActorAlign.CENTER });
|
||||
this.actor.add_actor(this._tipLabel);
|
||||
labelBox.add_actor(this._tipLabel);
|
||||
|
||||
this._updatePadChooser();
|
||||
|
||||
this._actionEditor = new ActionEditor();
|
||||
this._actionEditor.connect('done', Lang.bind(this, this._endButtonActionEdition));
|
||||
this._actionEditor.connect('done', Lang.bind(this, this._endActionEdition));
|
||||
|
||||
this._padDiagram = new PadDiagram({ image: this._imagePath,
|
||||
left_handed: settings.get_boolean('left-handed'),
|
||||
@ -580,11 +711,17 @@ const PadOsd = new Lang.Class({
|
||||
}
|
||||
|
||||
for (i = 0; i < padDevice.get_n_rings(); i++) {
|
||||
let [found] = this._padDiagram.getRingLabelCoords(i, CW);
|
||||
if (!found)
|
||||
break;
|
||||
this._createLabel(Meta.PadActionType.RING, i, CW);
|
||||
this._createLabel(Meta.PadActionType.RING, i, CCW);
|
||||
}
|
||||
|
||||
for (i = 0; i < padDevice.get_n_strips(); i++) {
|
||||
let [found] = this._padDiagram.getStripLabelCoords(i, UP);
|
||||
if (!found)
|
||||
break;
|
||||
this._createLabel(Meta.PadActionType.STRIP, i, UP);
|
||||
this._createLabel(Meta.PadActionType.STRIP, i, DOWN);
|
||||
}
|
||||
@ -605,6 +742,33 @@ const PadOsd = new Lang.Class({
|
||||
Main.pushModal(this.actor);
|
||||
},
|
||||
|
||||
_updatePadChooser: function () {
|
||||
if (this._groupPads.length > 1) {
|
||||
if (this._padChooser == null) {
|
||||
this._padChooser = new PadChooser(this.padDevice, this._groupPads)
|
||||
this._padChooser.connect('pad-selected', Lang.bind(this, function (chooser, pad) {
|
||||
this._requestForOtherPad(pad);
|
||||
}));
|
||||
this._titleBox.add_child(this._padChooser.actor);
|
||||
} else {
|
||||
this._padChooser.update(this._groupPads);
|
||||
}
|
||||
} else if (this._padChooser != null) {
|
||||
this._padChooser.destroy();
|
||||
this._padChooser = null;
|
||||
}
|
||||
},
|
||||
|
||||
_requestForOtherPad: function (pad) {
|
||||
if (pad == this.padDevice ||
|
||||
this._groupPads.indexOf(pad) == -1)
|
||||
return;
|
||||
|
||||
let editionMode = this._editionMode;
|
||||
this.destroy();
|
||||
global.display.request_pad_osd(pad, editionMode);
|
||||
},
|
||||
|
||||
_createLabel: function (type, number, dir) {
|
||||
let str = global.display.get_pad_action_label(this.padDevice, type, number);
|
||||
let label = new St.Label({ text: str ? str : _("None") });
|
||||
@ -615,8 +779,10 @@ const PadOsd = new Lang.Class({
|
||||
if (event.type() == Clutter.EventType.PAD_BUTTON_PRESS &&
|
||||
event.get_source_device() == this.padDevice) {
|
||||
this._padDiagram.activateButton(event.get_button());
|
||||
let isModeSwitch = this.padDevice.get_mode_switch_button_group(event.get_button()) >= 0;
|
||||
|
||||
if (this._editionMode)
|
||||
/* Buttons that switch between modes cannot be edited */
|
||||
if (this._editionMode && !isModeSwitch)
|
||||
this._startButtonActionEdition(event.get_button());
|
||||
return Clutter.EVENT_STOP;
|
||||
} else if (event.type() == Clutter.EventType.PAD_BUTTON_RELEASE &&
|
||||
@ -625,11 +791,30 @@ const PadOsd = new Lang.Class({
|
||||
return Clutter.EVENT_STOP;
|
||||
} else if (event.type() == Clutter.EventType.KEY_PRESS &&
|
||||
(!this._editionMode || event.get_key_symbol() == Clutter.Escape)) {
|
||||
if (this._editingButtonAction != null)
|
||||
this._endButtonActionEdition();
|
||||
if (this._editedAction != null)
|
||||
this._endActionEdition();
|
||||
else
|
||||
this.destroy();
|
||||
return Clutter.EVENT_STOP;
|
||||
} else if (event.get_source_device() == this.padDevice &&
|
||||
event.type() == Clutter.EventType.PAD_STRIP) {
|
||||
if (this._editionMode) {
|
||||
let [retval, number, mode] = event.get_pad_event_details();
|
||||
this._startStripActionEdition(number, UP, mode);
|
||||
}
|
||||
} else if (event.get_source_device() == this.padDevice &&
|
||||
event.type() == Clutter.EventType.PAD_RING) {
|
||||
if (this._editionMode) {
|
||||
let [retval, number, mode] = event.get_pad_event_details();
|
||||
this._startRingActionEdition(number, CCW, mode);
|
||||
}
|
||||
}
|
||||
|
||||
// If the event comes from another pad in the same group,
|
||||
// show the OSD for it.
|
||||
if (this._groupPads.indexOf(event.get_source_device()) != -1) {
|
||||
this._requestForOtherPad(event.get_source_device());
|
||||
return Clutter.EVENT_STOP;
|
||||
}
|
||||
|
||||
return Clutter.EVENT_PROPAGATE;
|
||||
@ -655,33 +840,79 @@ const PadOsd = new Lang.Class({
|
||||
this._titleLabel.clutter_text.set_markup('<span size="larger"><b>' + title + '</b></span>');
|
||||
},
|
||||
|
||||
_endButtonActionEdition: function () {
|
||||
_isEditedAction: function (type, number, dir) {
|
||||
if (!this._editedAction)
|
||||
return false;
|
||||
|
||||
return (this._editedAction.type == type &&
|
||||
this._editedAction.number == number &&
|
||||
this._editedAction.dir == dir);
|
||||
},
|
||||
|
||||
_followUpActionEdition: function (str) {
|
||||
let { type, dir, number, mode } = this._editedAction;
|
||||
let hasNextAction = (type == Meta.PadActionType.RING && dir == CCW ||
|
||||
type == Meta.PadActionType.STRIP && dir == UP);
|
||||
if (!hasNextAction)
|
||||
return false;
|
||||
|
||||
this._padDiagram.stopEdition(true, str);
|
||||
this._editedAction = null;
|
||||
if (type == Meta.PadActionType.RING)
|
||||
this._startRingActionEdition(number, CW, mode);
|
||||
else
|
||||
this._startStripActionEdition(number, DOWN, mode);
|
||||
|
||||
return true;
|
||||
},
|
||||
|
||||
_endActionEdition: function () {
|
||||
this._actionEditor.close();
|
||||
|
||||
if (this._editingButtonAction != null) {
|
||||
if (this._editedAction != null) {
|
||||
let str = global.display.get_pad_action_label(this.padDevice,
|
||||
Meta.PadActionType.BUTTON,
|
||||
this._editingButtonAction);
|
||||
this._padDiagram.stopEdition(str ? str : _("None"))
|
||||
this._editingButtonAction = null;
|
||||
this._editedAction.type,
|
||||
this._editedAction.number);
|
||||
if (this._followUpActionEdition(str))
|
||||
return;
|
||||
|
||||
this._padDiagram.stopEdition(false, str ? str : _("None"))
|
||||
this._editedAction = null;
|
||||
}
|
||||
|
||||
this._editedButtonSettings = null;
|
||||
this._editedActionSettings = null;
|
||||
},
|
||||
|
||||
_startActionEdition: function (key, type, number, dir, mode) {
|
||||
if (this._isEditedAction(type, number, dir))
|
||||
return;
|
||||
|
||||
this._endActionEdition();
|
||||
this._editedAction = { type, number, dir, mode };
|
||||
|
||||
let settingsPath = this._settings.path + key + '/';
|
||||
this._editedActionSettings = Gio.Settings.new_with_path('org.gnome.desktop.peripherals.tablet.pad-button',
|
||||
settingsPath);
|
||||
this._actionEditor.setSettings(this._editedActionSettings, type);
|
||||
this._padDiagram.startEdition(type, number, dir);
|
||||
},
|
||||
|
||||
_startButtonActionEdition: function (button) {
|
||||
if (this._editingButtonAction == button)
|
||||
return;
|
||||
|
||||
this._endButtonActionEdition();
|
||||
this._editingButtonAction = button;
|
||||
|
||||
let ch = String.fromCharCode('A'.charCodeAt() + button);
|
||||
let settingsPath = this._settings.path + "button" + ch + '/';
|
||||
this._editedButtonSettings = Gio.Settings.new_with_path('org.gnome.desktop.peripherals.tablet.pad-button',
|
||||
settingsPath);
|
||||
this._actionEditor.setSettings(this._editedButtonSettings);
|
||||
this._padDiagram.startEdition(Meta.PadActionType.BUTTON, button);
|
||||
let key = 'button' + ch;
|
||||
this._startActionEdition(key, Meta.PadActionType.BUTTON, button);
|
||||
},
|
||||
|
||||
_startRingActionEdition: function (ring, dir, mode) {
|
||||
let ch = String.fromCharCode('A'.charCodeAt() + ring);
|
||||
let key = 'ring%s-%s-mode-%d'.format(ch, dir == CCW ? 'ccw' : 'cw', mode);
|
||||
this._startActionEdition(key, Meta.PadActionType.RING, ring, dir, mode);
|
||||
},
|
||||
|
||||
_startStripActionEdition: function (strip, dir, mode) {
|
||||
let ch = String.fromCharCode('A'.charCodeAt() + strip);
|
||||
let key = 'strip%s-%s-mode-%d'.format(ch, dir == UP ? 'up' : 'down', mode);
|
||||
this._startActionEdition(key, Meta.PadActionType.STRIP, strip, dir, mode);
|
||||
},
|
||||
|
||||
setEditionMode: function (editionMode) {
|
||||
@ -700,11 +931,15 @@ const PadOsd = new Lang.Class({
|
||||
Main.popModal(this.actor);
|
||||
this._actionEditor.close();
|
||||
|
||||
let deviceManager = Clutter.DeviceManager.get_default();
|
||||
if (this._deviceRemovedId != 0) {
|
||||
let deviceManager = Clutter.DeviceManager.get_default();
|
||||
deviceManager.disconnect(this._deviceRemovedId);
|
||||
this._deviceRemovedId = 0;
|
||||
}
|
||||
if (this._deviceAddedId != 0) {
|
||||
deviceManager.disconnect(this._deviceAddedId);
|
||||
this._deviceAddedId = 0;
|
||||
}
|
||||
|
||||
if (this._capturedEventId != 0) {
|
||||
global.stage.disconnect(this._capturedEventId);
|
||||
|
@ -719,9 +719,11 @@ const AggregateMenu = new Lang.Class({
|
||||
this._system = new imports.ui.status.system.Indicator();
|
||||
this._screencast = new imports.ui.status.screencast.Indicator();
|
||||
this._location = new imports.ui.status.location.Indicator();
|
||||
this._nightLight = new imports.ui.status.nightLight.Indicator();
|
||||
|
||||
this._indicators.add_child(this._screencast.indicators);
|
||||
this._indicators.add_child(this._location.indicators);
|
||||
this._indicators.add_child(this._nightLight.indicators);
|
||||
if (this._network) {
|
||||
this._indicators.add_child(this._network.indicators);
|
||||
}
|
||||
@ -745,6 +747,7 @@ const AggregateMenu = new Lang.Class({
|
||||
this.menu.addMenuItem(this._location.menu);
|
||||
this.menu.addMenuItem(this._rfkill.menu);
|
||||
this.menu.addMenuItem(this._power.menu);
|
||||
this.menu.addMenuItem(this._nightLight.menu);
|
||||
this.menu.addMenuItem(this._system.menu);
|
||||
|
||||
menuLayout.addSizeChild(this._location.menu.actor);
|
||||
@ -1101,7 +1104,7 @@ const Panel = new Lang.Class({
|
||||
},
|
||||
|
||||
_onMenuSet: function(indicator) {
|
||||
if (!indicator.menu || indicator.menu._openChangedId > 0)
|
||||
if (!indicator.menu || indicator.menu.hasOwnProperty('_openChangedId'))
|
||||
return;
|
||||
|
||||
indicator.menu._openChangedId = indicator.menu.connect('open-state-changed',
|
||||
|
@ -174,8 +174,14 @@ const Button = new Lang.Class({
|
||||
// menu is higher then the screen; it's useful if part of the menu is
|
||||
// scrollable so the minimum height is smaller than the natural height
|
||||
let workArea = Main.layoutManager.getWorkAreaForMonitor(Main.layoutManager.primaryIndex);
|
||||
let scaleFactor = St.ThemeContext.get_for_stage(global.stage).scale_factor;
|
||||
let verticalMargins = this.menu.actor.margin_top + this.menu.actor.margin_bottom;
|
||||
this.menu.actor.style = ('max-height: ' + Math.round(workArea.height - verticalMargins) + 'px;');
|
||||
|
||||
// The workarea and margin dimensions are in physical pixels, but CSS
|
||||
// measures are in logical pixels, so make sure to consider the scale
|
||||
// factor when computing max-height
|
||||
let maxHeight = Math.round((workArea.height - verticalMargins) / scaleFactor);
|
||||
this.menu.actor.style = ('max-height: %spx;').format(maxHeight);
|
||||
},
|
||||
|
||||
destroy: function() {
|
||||
|
@ -605,6 +605,24 @@ const PopupMenuBase = new Lang.Class({
|
||||
menuItem.actor.show();
|
||||
},
|
||||
|
||||
moveMenuItem: function(menuItem, position) {
|
||||
let items = this._getMenuItems();
|
||||
let i = 0;
|
||||
|
||||
while (i < items.length && position > 0) {
|
||||
if (items[i] != menuItem)
|
||||
position--;
|
||||
i++;
|
||||
}
|
||||
|
||||
if (i < items.length) {
|
||||
if (items[i] != menuItem)
|
||||
this.box.set_child_below_sibling(menuItem.actor, items[i].actor);
|
||||
} else {
|
||||
this.box.set_child_above_sibling(menuItem.actor, null);
|
||||
}
|
||||
},
|
||||
|
||||
addMenuItem: function(menuItem, position) {
|
||||
let before_item = null;
|
||||
if (position == undefined) {
|
||||
@ -767,6 +785,11 @@ const PopupMenu = new Lang.Class({
|
||||
},
|
||||
|
||||
_onKeyPress: function(actor, event) {
|
||||
// Disable toggling the menu by keyboard
|
||||
// when it cannot be toggled by pointer
|
||||
if (!actor.reactive)
|
||||
return Clutter.EVENT_PROPAGATE;
|
||||
|
||||
let navKey;
|
||||
switch (this._boxPointer.arrowSide) {
|
||||
case St.Side.TOP:
|
||||
|
@ -192,6 +192,10 @@ const RemoteMenu = new Lang.Class({
|
||||
_removeItem.bind(null, this));
|
||||
},
|
||||
|
||||
get actionGroup() {
|
||||
return this._actionGroup;
|
||||
},
|
||||
|
||||
destroy: function() {
|
||||
this._tracker.destroy();
|
||||
this.parent();
|
||||
|
@ -200,6 +200,7 @@ const RemoteSearchProvider = new Lang.Class({
|
||||
this.appInfo = appInfo;
|
||||
this.id = appInfo.get_id();
|
||||
this.isRemoteProvider = true;
|
||||
this.canLaunchSearch = false;
|
||||
},
|
||||
|
||||
createIcon: function(size, meta) {
|
||||
@ -278,7 +279,8 @@ const RemoteSearchProvider = new Lang.Class({
|
||||
name: metas[i]['name'],
|
||||
description: metas[i]['description'],
|
||||
createIcon: Lang.bind(this,
|
||||
this.createIcon, metas[i]) });
|
||||
this.createIcon, metas[i]),
|
||||
clipboardText: metas[i]['clipboardText'] });
|
||||
}
|
||||
callback(resultMetas);
|
||||
},
|
||||
|
@ -33,6 +33,9 @@ const SCREENSAVER_SCHEMA = 'org.gnome.desktop.screensaver';
|
||||
const LOCK_ENABLED_KEY = 'lock-enabled';
|
||||
const LOCK_DELAY_KEY = 'lock-delay';
|
||||
|
||||
const LOCKDOWN_SCHEMA = 'org.gnome.desktop.lockdown';
|
||||
const DISABLE_LOCK_KEY = 'disable-lock-screen';
|
||||
|
||||
const LOCKED_STATE_STR = 'screenShield.locked';
|
||||
// fraction of screen height the arrow must reach before completing
|
||||
// the slide up automatically
|
||||
@ -541,6 +544,9 @@ const ScreenShield = new Lang.Class({
|
||||
this._settings = new Gio.Settings({ schema_id: SCREENSAVER_SCHEMA });
|
||||
this._settings.connect('changed::' + LOCK_ENABLED_KEY, Lang.bind(this, this._syncInhibitor));
|
||||
|
||||
this._lockSettings = new Gio.Settings({ schema_id: LOCKDOWN_SCHEMA });
|
||||
this._lockSettings.connect('changed::' + DISABLE_LOCK_KEY, Lang.bind(this, this._syncInhibitor));
|
||||
|
||||
this._isModal = false;
|
||||
this._hasLockScreen = false;
|
||||
this._isGreeter = false;
|
||||
@ -701,8 +707,10 @@ const ScreenShield = new Lang.Class({
|
||||
},
|
||||
|
||||
_syncInhibitor: function() {
|
||||
let lockEnabled = this._settings.get_boolean(LOCK_ENABLED_KEY);
|
||||
let lockLocked = this._lockSettings.get_boolean(DISABLE_LOCK_KEY);
|
||||
let inhibit = (this._loginSession && this._loginSession.Active &&
|
||||
!this._isActive && this._settings.get_boolean(LOCK_ENABLED_KEY));
|
||||
!this._isActive && lockEnabled && !lockLocked);
|
||||
if (inhibit) {
|
||||
this._loginManager.inhibit(_("GNOME needs to lock the screen"),
|
||||
Lang.bind(this, function(inhibitor) {
|
||||
@ -1290,6 +1298,11 @@ const ScreenShield = new Lang.Class({
|
||||
},
|
||||
|
||||
lock: function(animate) {
|
||||
if (this._lockSettings.get_boolean(DISABLE_LOCK_KEY)) {
|
||||
log('Screen lock is locked down, not locking') // lock, lock - who's there?
|
||||
return;
|
||||
}
|
||||
|
||||
// Warn the user if we can't become modal
|
||||
if (!this._becomeModal()) {
|
||||
Main.notifyError(_("Unable to lock"),
|
||||
|
@ -152,6 +152,8 @@ const SearchResultsBase = new Lang.Class({
|
||||
|
||||
this._resultDisplays = {};
|
||||
|
||||
this._clipboard = St.Clipboard.get_default();
|
||||
|
||||
this._cancellable = new Gio.Cancellable();
|
||||
},
|
||||
|
||||
@ -181,6 +183,8 @@ const SearchResultsBase = new Lang.Class({
|
||||
|
||||
_activateResult: function(result, id) {
|
||||
this.provider.activateResult(id, this._terms);
|
||||
if (result.metaInfo.clipboardText)
|
||||
this._clipboard.set_text(St.ClipboardType.CLIPBOARD, result.metaInfo.clipboardText);
|
||||
Main.overview.toggle();
|
||||
},
|
||||
|
||||
|
@ -142,15 +142,15 @@ const GnomeShell = new Lang.Class({
|
||||
for (let param in params)
|
||||
params[param] = params[param].deep_unpack();
|
||||
|
||||
let monitorIndex = -1;
|
||||
if (params['monitor'] >= 0)
|
||||
monitorIndex = params['monitor'];
|
||||
let monitorIndex = params['monitor'] || -1;
|
||||
let label = params['label'] || undefined;
|
||||
let level = params['level'] || undefined;
|
||||
|
||||
let icon = null;
|
||||
if (params['icon'])
|
||||
icon = Gio.Icon.new_for_string(params['icon']);
|
||||
|
||||
Main.osdWindowManager.show(monitorIndex, icon, params['label'], params['level']);
|
||||
Main.osdWindowManager.show(monitorIndex, icon, label, level);
|
||||
},
|
||||
|
||||
FocusApp: function(id) {
|
||||
|
@ -380,7 +380,7 @@ const ShellMountPasswordDialog = new Lang.Class({
|
||||
this.setInitialKeyFocus(this._passwordEntry);
|
||||
|
||||
this._errorMessageLabel = new St.Label({ style_class: 'prompt-dialog-error-label',
|
||||
text: _("Sorry, that didn\'t work. Please try again.") });
|
||||
text: _("Sorry, that didn’t work. Please try again.") });
|
||||
this._errorMessageLabel.clutter_text.ellipsize = Pango.EllipsizeMode.NONE;
|
||||
this._errorMessageLabel.clutter_text.line_wrap = true;
|
||||
this._errorMessageLabel.hide();
|
||||
|
@ -102,8 +102,8 @@ const ATIndicator = new Lang.Class({
|
||||
if (this._syncMenuVisibilityIdle)
|
||||
return;
|
||||
|
||||
this._syncMenuVisbilityIdle = Mainloop.idle_add(Lang.bind(this, this._syncMenuVisibility));
|
||||
GLib.Source.set_name_by_id(this._syncMenuVisbilityIdle, '[gnome-shell] this._syncMenuVisibility');
|
||||
this._syncMenuVisibilityIdle = Mainloop.idle_add(Lang.bind(this, this._syncMenuVisibility));
|
||||
GLib.Source.set_name_by_id(this._syncMenuVisibilityIdle, '[gnome-shell] this._syncMenuVisibility');
|
||||
},
|
||||
|
||||
_buildItemExtended: function(string, initial_value, writable, on_set) {
|
||||
|
@ -9,6 +9,7 @@ const Main = imports.ui.main;
|
||||
const PanelMenu = imports.ui.panelMenu;
|
||||
const PopupMenu = imports.ui.popupMenu;
|
||||
const ModalDialog = imports.ui.modalDialog;
|
||||
const PermissionStore = imports.misc.permissionStore;
|
||||
const Shell = imports.gi.Shell;
|
||||
const Signals = imports.signals;
|
||||
const St = imports.gi.St;
|
||||
@ -62,26 +63,6 @@ var AgentIface = '<node> \
|
||||
</interface> \
|
||||
</node>';
|
||||
|
||||
var PermissionStoreIface = '<node> \
|
||||
<interface name="org.freedesktop.impl.portal.PermissionStore"> \
|
||||
<method name="Lookup"> \
|
||||
<arg name="table" type="s" direction="in"/> \
|
||||
<arg name="id" type="s" direction="in"/> \
|
||||
<arg name="permissions" type="a{sas}" direction="out"/> \
|
||||
<arg name="data" type="v" direction="out"/> \
|
||||
</method> \
|
||||
<method name="Set"> \
|
||||
<arg name="table" type="s" direction="in"/> \
|
||||
<arg name="create" type="b" direction="in"/> \
|
||||
<arg name="id" type="s" direction="in"/> \
|
||||
<arg name="app_permissions" type="a{sas}" direction="in"/> \
|
||||
<arg name="data" type="v" direction="in"/> \
|
||||
</method> \
|
||||
</interface> \
|
||||
</node>';
|
||||
|
||||
const PermissionStore = Gio.DBusProxy.makeProxyWrapper(PermissionStoreIface);
|
||||
|
||||
const Indicator = new Lang.Class({
|
||||
Name: 'LocationIndicator',
|
||||
Extends: PanelMenu.SystemIndicator,
|
||||
@ -253,10 +234,7 @@ const Indicator = new Lang.Class({
|
||||
|
||||
_connectToPermissionStore: function() {
|
||||
this._permStoreProxy = null;
|
||||
new PermissionStore(Gio.DBus.session,
|
||||
'org.freedesktop.impl.portal.PermissionStore',
|
||||
'/org/freedesktop/impl/portal/PermissionStore',
|
||||
Lang.bind(this, this._onPermStoreProxyReady));
|
||||
new PermissionStore.PermissionStore(Lang.bind(this, this._onPermStoreProxyReady), null);
|
||||
},
|
||||
|
||||
_onPermStoreProxyReady: function(proxy, error) {
|
||||
@ -284,6 +262,7 @@ const AppAuthorizer = new Lang.Class({
|
||||
this.reqAccuracyLevel = reqAccuracyLevel;
|
||||
this._permStoreProxy = permStoreProxy;
|
||||
this._maxAccuracyLevel = maxAccuracyLevel;
|
||||
this._permissions = {};
|
||||
|
||||
this._accuracyLevel = GeoclueAccuracyLevel.NONE;
|
||||
},
|
||||
|
@ -299,11 +299,22 @@ const NMConnectionSection = new Lang.Class({
|
||||
|
||||
let item = this._connectionItems.get(connection.get_uuid());
|
||||
if (item)
|
||||
item.updateForConnection(connection);
|
||||
this._updateForConnection(item, connection);
|
||||
else
|
||||
this._addConnection(connection);
|
||||
},
|
||||
|
||||
_updateForConnection: function(item, connection) {
|
||||
let pos = this._connections.indexOf(connection);
|
||||
|
||||
this._connections.splice(pos, 1);
|
||||
pos = Util.insertSorted(this._connections, connection, Lang.bind(this, this._connectionSortFunction));
|
||||
this._labelSection.moveMenuItem(item.labelItem, pos);
|
||||
this._radioSection.moveMenuItem(item.radioItem, pos);
|
||||
|
||||
item.updateForConnection(connection);
|
||||
},
|
||||
|
||||
_addConnection: function(connection) {
|
||||
let item = this._makeConnectionItem(connection);
|
||||
if (!item)
|
||||
@ -758,6 +769,14 @@ const NMWirelessDialog = new Lang.Class({
|
||||
this._scanTimeoutId = Mainloop.timeout_add_seconds(15, Lang.bind(this, this._onScanTimeout));
|
||||
GLib.Source.set_name_by_id(this._scanTimeoutId, '[gnome-shell] this._onScanTimeout');
|
||||
this._onScanTimeout();
|
||||
|
||||
let id = Main.sessionMode.connect('updated', () => {
|
||||
if (Main.sessionMode.allowSettings)
|
||||
return;
|
||||
|
||||
Main.sessionMode.disconnect(id);
|
||||
this.close();
|
||||
});
|
||||
},
|
||||
|
||||
destroy: function() {
|
||||
@ -1343,7 +1362,11 @@ const NMDeviceWireless = new Lang.Class({
|
||||
if (!this._device.active_connection)
|
||||
return false;
|
||||
|
||||
let connection = this._settings.get_connection_by_path(this._device.active_connection.connection);
|
||||
let connectionPath = this._device.active_connection.connection;
|
||||
if (!connectionPath)
|
||||
return false;
|
||||
|
||||
let connection = this._settings.get_connection_by_path(connectionPath);
|
||||
if (!connection)
|
||||
return false;
|
||||
|
||||
@ -1420,7 +1443,7 @@ const NMVPNConnectionItem = new Lang.Class({
|
||||
case NetworkManager.VPNConnectionState.PREPARE:
|
||||
case NetworkManager.VPNConnectionState.CONNECT:
|
||||
case NetworkManager.VPNConnectionState.IP_CONFIG_GET:
|
||||
return _("connecting...");
|
||||
return _("connecting…");
|
||||
case NetworkManager.VPNConnectionState.NEED_AUTH:
|
||||
/* Translators: this is for network connections that require some kind of key or password */
|
||||
return _("authentication required");
|
||||
@ -1543,8 +1566,10 @@ const NMVPNSection = new Lang.Class({
|
||||
item.setActiveConnection(null);
|
||||
}
|
||||
vpnConnections.forEach(Lang.bind(this, function(a) {
|
||||
let item = this._connectionItems.get(a._connection.get_uuid());
|
||||
item.setActiveConnection(a);
|
||||
if (a._connection) {
|
||||
let item = this._connectionItems.get(a._connection.get_uuid());
|
||||
item.setActiveConnection(a);
|
||||
}
|
||||
}));
|
||||
},
|
||||
|
||||
@ -1684,6 +1709,7 @@ const NMApplet = new Lang.Class({
|
||||
|
||||
this._mainConnection = null;
|
||||
this._mainConnectionIconChangedId = 0;
|
||||
this._mainConnectionStateChangedId = 0;
|
||||
|
||||
this._notification = null;
|
||||
|
||||
@ -2053,7 +2079,7 @@ const NMApplet = new Lang.Class({
|
||||
// (but in general we should only prompt a portal if we know there is a portal)
|
||||
if (GLib.getenv('GNOME_SHELL_CONNECTIVITY_TEST') != null)
|
||||
isPortal = isPortal || this._client.connectivity < NetworkManager.ConnectivityState.FULL;
|
||||
if (!isPortal)
|
||||
if (!isPortal || Main.sessionMode.isGreeter)
|
||||
return;
|
||||
|
||||
let path = this._mainConnection.get_path();
|
||||
|
74
js/ui/status/nightLight.js
Normal file
74
js/ui/status/nightLight.js
Normal file
@ -0,0 +1,74 @@
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
|
||||
const Gio = imports.gi.Gio;
|
||||
const Lang = imports.lang;
|
||||
|
||||
const Main = imports.ui.main;
|
||||
const PanelMenu = imports.ui.panelMenu;
|
||||
const PopupMenu = imports.ui.popupMenu;
|
||||
|
||||
const BUS_NAME = 'org.gnome.SettingsDaemon.Color';
|
||||
const OBJECT_PATH = '/org/gnome/SettingsDaemon/Color';
|
||||
|
||||
const ColorInterface = '<node> \
|
||||
<interface name="org.gnome.SettingsDaemon.Color"> \
|
||||
<property name="DisabledUntilTomorrow" type="b" access="readwrite"/> \
|
||||
<property name="NightLightActive" type="b" access="read"/> \
|
||||
</interface> \
|
||||
</node>';
|
||||
|
||||
const ColorProxy = Gio.DBusProxy.makeProxyWrapper(ColorInterface);
|
||||
|
||||
const Indicator = new Lang.Class({
|
||||
Name: 'NightLightIndicator',
|
||||
Extends: PanelMenu.SystemIndicator,
|
||||
|
||||
_init: function() {
|
||||
this.parent();
|
||||
|
||||
this._indicator = this._addIndicator();
|
||||
this._indicator.icon_name = 'night-light-symbolic';
|
||||
this._proxy = new ColorProxy(Gio.DBus.session, BUS_NAME, OBJECT_PATH,
|
||||
(proxy, error) => {
|
||||
if (error) {
|
||||
log(error.message);
|
||||
return;
|
||||
}
|
||||
this._proxy.connect('g-properties-changed',
|
||||
Lang.bind(this, this._sync));
|
||||
this._sync();
|
||||
});
|
||||
|
||||
this._item = new PopupMenu.PopupSubMenuMenuItem("", true);
|
||||
this._item.icon.icon_name = 'night-light-symbolic';
|
||||
this._disableItem = this._item.menu.addAction('', () => {
|
||||
this._proxy.DisabledUntilTomorrow = !this._proxy.DisabledUntilTomorrow;
|
||||
});
|
||||
this._item.menu.addAction(_("Turn Off"), () => {
|
||||
let settings = new Gio.Settings({ schema_id: 'org.gnome.settings-daemon.plugins.color' });
|
||||
settings.set_boolean('night-light-enabled', false);
|
||||
});
|
||||
this._item.menu.addSettingsAction(_("Display Settings"), 'gnome-display-panel.desktop');
|
||||
this.menu.addMenuItem(this._item);
|
||||
|
||||
Main.sessionMode.connect('updated', Lang.bind(this, this._sessionUpdated));
|
||||
this._sessionUpdated();
|
||||
this._sync();
|
||||
},
|
||||
|
||||
_sessionUpdated: function() {
|
||||
let sensitive = !Main.sessionMode.isLocked && !Main.sessionMode.isGreeter;
|
||||
this.menu.setSensitive(sensitive);
|
||||
},
|
||||
|
||||
_sync: function() {
|
||||
let visible = this._proxy.NightLightActive;
|
||||
let disabled = this._proxy.DisabledUntilTomorrow;
|
||||
|
||||
this._item.label.text = disabled ? _("Night Light Disabled")
|
||||
: _("Night Light On");
|
||||
this._disableItem.label.text = disabled ? _("Resume")
|
||||
: _("Disable Until Tomorrow");
|
||||
this._item.actor.visible = this._indicator.visible = visible;
|
||||
}
|
||||
});
|
@ -42,14 +42,26 @@ const AltSwitcher = new Lang.Class({
|
||||
_init: function(standard, alternate) {
|
||||
this._standard = standard;
|
||||
this._standard.connect('notify::visible', Lang.bind(this, this._sync));
|
||||
if (this._standard instanceof St.Button)
|
||||
this._standard.connect('clicked',
|
||||
() => { this._clickAction.release(); });
|
||||
|
||||
this._alternate = alternate;
|
||||
this._alternate.connect('notify::visible', Lang.bind(this, this._sync));
|
||||
if (this._alternate instanceof St.Button)
|
||||
this._alternate.connect('clicked',
|
||||
() => { this._clickAction.release(); });
|
||||
|
||||
this._capturedEventId = global.stage.connect('captured-event', Lang.bind(this, this._onCapturedEvent));
|
||||
|
||||
this._flipped = false;
|
||||
|
||||
this._clickAction = new Clutter.ClickAction();
|
||||
this._clickAction.connect('long-press', Lang.bind(this, this._onLongPress));
|
||||
|
||||
this.actor = new St.Bin();
|
||||
this.actor.connect('destroy', Lang.bind(this, this._onDestroy));
|
||||
this.actor.connect('notify::mapped', () => { this._flipped = false; });
|
||||
},
|
||||
|
||||
_sync: function() {
|
||||
@ -58,14 +70,25 @@ const AltSwitcher = new Lang.Class({
|
||||
if (this._standard.visible && this._alternate.visible) {
|
||||
let [x, y, mods] = global.get_pointer();
|
||||
let altPressed = (mods & Clutter.ModifierType.MOD1_MASK) != 0;
|
||||
childToShow = altPressed ? this._alternate : this._standard;
|
||||
if (this._flipped)
|
||||
childToShow = altPressed ? this._standard : this._alternate;
|
||||
else
|
||||
childToShow = altPressed ? this._alternate : this._standard;
|
||||
} else if (this._standard.visible) {
|
||||
childToShow = this._standard;
|
||||
} else if (this._alternate.visible) {
|
||||
childToShow = this._alternate;
|
||||
}
|
||||
|
||||
if (this.actor.get_child() != childToShow) {
|
||||
let childShown = this.actor.get_child();
|
||||
if (childShown != childToShow) {
|
||||
if (childShown) {
|
||||
if (childShown.fake_release)
|
||||
childShown.fake_release();
|
||||
childShown.remove_action(this._clickAction);
|
||||
}
|
||||
childToShow.add_action(this._clickAction);
|
||||
|
||||
let hasFocus = this.actor.contains(global.stage.get_key_focus());
|
||||
this.actor.set_child(childToShow);
|
||||
if (hasFocus)
|
||||
@ -96,6 +119,16 @@ const AltSwitcher = new Lang.Class({
|
||||
|
||||
return Clutter.EVENT_PROPAGATE;
|
||||
},
|
||||
|
||||
_onLongPress: function(action, actor, state) {
|
||||
if (state == Clutter.LongPressState.QUERY ||
|
||||
state == Clutter.LongPressState.CANCEL)
|
||||
return true;
|
||||
|
||||
this._flipped = !this._flipped;
|
||||
this._sync();
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
const Indicator = new Lang.Class({
|
||||
|
@ -10,6 +10,7 @@ const Signals = imports.signals;
|
||||
const Lang = imports.lang;
|
||||
const Shell = imports.gi.Shell;
|
||||
const St = imports.gi.St;
|
||||
const GObject = imports.gi.GObject;
|
||||
|
||||
const AppDisplay = imports.ui.appDisplay;
|
||||
const Main = imports.ui.main;
|
||||
@ -77,6 +78,7 @@ Signals.addSignalMethods(TouchpadShowOverviewAction.prototype);
|
||||
const ShowOverviewAction = new Lang.Class({
|
||||
Name: 'ShowOverviewAction',
|
||||
Extends: Clutter.GestureAction,
|
||||
Signals: { 'activated': { param_types: [GObject.TYPE_DOUBLE] } },
|
||||
|
||||
_init : function() {
|
||||
this.parent();
|
||||
@ -135,7 +137,6 @@ const ShowOverviewAction = new Lang.Class({
|
||||
this.emit('activated', areaDiff);
|
||||
}
|
||||
});
|
||||
Signals.addSignalMethods(ShowOverviewAction.prototype);
|
||||
|
||||
const ViewSelector = new Lang.Class({
|
||||
Name: 'ViewSelector',
|
||||
|
@ -18,6 +18,7 @@ const ModalDialog = imports.ui.modalDialog;
|
||||
const Tweener = imports.ui.tweener;
|
||||
const WindowMenu = imports.ui.windowMenu;
|
||||
const PadOsd = imports.ui.padOsd;
|
||||
const EdgeDragAction = imports.ui.edgeDragAction;
|
||||
|
||||
const SHELL_KEYBINDINGS_SCHEMA = 'org.gnome.shell.keybindings';
|
||||
const MINIMIZE_WINDOW_ANIMATION_TIME = 0.2;
|
||||
@ -33,6 +34,25 @@ const UNDIM_TIME = 0.250;
|
||||
const DISPLAY_REVERT_TIMEOUT = 20; // in seconds - keep in sync with mutter
|
||||
const ONE_SECOND = 1000; // in ms
|
||||
|
||||
const GSD_WACOM_BUS_NAME = 'org.gnome.SettingsDaemon.Wacom';
|
||||
const GSD_WACOM_OBJECT_PATH = '/org/gnome/SettingsDaemon/Wacom';
|
||||
|
||||
const GsdWacomIface = '<node name="/org/gnome/SettingsDaemon/Wacom"> \
|
||||
<interface name="org.gnome.SettingsDaemon.Wacom"> \
|
||||
<method name="SetGroupModeLED"> \
|
||||
<arg name="device_path" direction="in" type="s"/> \
|
||||
<arg name="group" direction="in" type="u"/> \
|
||||
<arg name="mode" direction="in" type="u"/> \
|
||||
</method> \
|
||||
<method name="SetOLEDLabels"> \
|
||||
<arg name="device_path" direction="in" type="s"/> \
|
||||
<arg name="labels" direction="in" type="as"/> \
|
||||
</method> \
|
||||
</interface> \
|
||||
</node>';
|
||||
|
||||
const GsdWacomProxy = Gio.DBusProxy.makeProxyWrapper(GsdWacomIface);
|
||||
|
||||
const DisplayChangeDialog = new Lang.Class({
|
||||
Name: 'DisplayChangeDialog',
|
||||
Extends: ModalDialog.ModalDialog,
|
||||
@ -535,6 +555,7 @@ Signals.addSignalMethods(TouchpadWorkspaceSwitchAction.prototype);
|
||||
const WorkspaceSwitchAction = new Lang.Class({
|
||||
Name: 'WorkspaceSwitchAction',
|
||||
Extends: Clutter.SwipeAction,
|
||||
Signals: { 'activated': { param_types: [Meta.MotionDirection.$gtype] } },
|
||||
|
||||
_init : function() {
|
||||
const MOTION_THRESHOLD = 50;
|
||||
@ -572,11 +593,11 @@ const WorkspaceSwitchAction = new Lang.Class({
|
||||
this.emit('activated', dir);
|
||||
}
|
||||
});
|
||||
Signals.addSignalMethods(WorkspaceSwitchAction.prototype);
|
||||
|
||||
const AppSwitchAction = new Lang.Class({
|
||||
Name: 'AppSwitchAction',
|
||||
Extends: Clutter.GestureAction,
|
||||
Signals: { 'activated': {} },
|
||||
|
||||
_init : function() {
|
||||
this.parent();
|
||||
@ -638,7 +659,6 @@ const AppSwitchAction = new Lang.Class({
|
||||
return true;
|
||||
}
|
||||
});
|
||||
Signals.addSignalMethods(AppSwitchAction.prototype);
|
||||
|
||||
const ResizePopup = new Lang.Class({
|
||||
Name: 'ResizePopup',
|
||||
@ -656,7 +676,7 @@ const ResizePopup = new Lang.Class({
|
||||
set: function(rect, displayW, displayH) {
|
||||
/* Translators: This represents the size of a window. The first number is
|
||||
* the width of the window and the second is the height. */
|
||||
let text = _("%d x %d").format(displayW, displayH);
|
||||
let text = _("%d × %d").format(displayW, displayH);
|
||||
this._label.set_text(text);
|
||||
|
||||
this._widget.set_position(rect.x, rect.y);
|
||||
@ -920,6 +940,34 @@ const WindowManager = new Lang.Class({
|
||||
|
||||
global.display.connect('show-resize-popup', Lang.bind(this, this._showResizePopup));
|
||||
global.display.connect('show-pad-osd', Lang.bind(this, this._showPadOsd));
|
||||
global.display.connect('show-osd', Lang.bind(this, function (display, monitorIndex, iconName, label) {
|
||||
let icon = Gio.Icon.new_for_string(iconName);
|
||||
Main.osdWindowManager.show(monitorIndex, icon, label, null);
|
||||
}));
|
||||
|
||||
this._gsdWacomProxy = new GsdWacomProxy(Gio.DBus.session, GSD_WACOM_BUS_NAME,
|
||||
GSD_WACOM_OBJECT_PATH,
|
||||
Lang.bind(this, function(proxy, error) {
|
||||
if (error) {
|
||||
log(error.message);
|
||||
return;
|
||||
}
|
||||
}));
|
||||
|
||||
global.display.connect('pad-mode-switch', Lang.bind(this, function (display, pad, group, mode) {
|
||||
let labels = [];
|
||||
|
||||
//FIXME: Fix num buttons
|
||||
for (let i = 0; i < 50; i++) {
|
||||
let str = display.get_pad_action_label(pad, Meta.PadActionType.BUTTON, i);
|
||||
labels.push(str ? str: '');
|
||||
}
|
||||
|
||||
if (this._gsdWacomProxy) {
|
||||
this._gsdWacomProxy.SetOLEDLabelsRemote(pad.get_device_node(), labels);
|
||||
this._gsdWacomProxy.SetGroupModeLEDRemote(pad.get_device_node(), group, mode);
|
||||
}
|
||||
}));
|
||||
|
||||
Main.overview.connect('showing', Lang.bind(this, function() {
|
||||
for (let i = 0; i < this._dimmedWindows.length; i++)
|
||||
@ -949,6 +997,12 @@ const WindowManager = new Lang.Class({
|
||||
gesture = new AppSwitchAction();
|
||||
gesture.connect('activated', Lang.bind(this, this._switchApp));
|
||||
global.stage.add_action(gesture);
|
||||
|
||||
gesture = new EdgeDragAction.EdgeDragAction(St.Side.BOTTOM, Shell.ActionMode.ALL);
|
||||
gesture.connect('activated', Lang.bind(this, function() {
|
||||
Main.keyboard.show(Main.layoutManager.bottomIndex);
|
||||
}));
|
||||
global.stage.add_action(gesture);
|
||||
},
|
||||
|
||||
_showPadOsd: function (display, device, settings, imagePath, editionMode, monitorIndex) {
|
||||
@ -1082,6 +1136,9 @@ const WindowManager = new Lang.Class({
|
||||
if (!this._shouldAnimate())
|
||||
return false;
|
||||
|
||||
if (!actor.get_texture())
|
||||
return false;
|
||||
|
||||
let type = actor.meta_window.get_window_type();
|
||||
return types.indexOf(type) >= 0;
|
||||
},
|
||||
@ -1286,6 +1343,8 @@ const WindowManager = new Lang.Class({
|
||||
_sizeChangedWindow: function(shellwm, actor) {
|
||||
if (!actor.__fullscreenInfo)
|
||||
return;
|
||||
if (this._resizing.indexOf(actor) != -1)
|
||||
return;
|
||||
|
||||
let actorClone = actor.__fullscreenInfo.clone;
|
||||
let targetRect = actor.meta_window.get_frame_rect();
|
||||
@ -1555,7 +1614,7 @@ const WindowManager = new Lang.Class({
|
||||
return;
|
||||
}
|
||||
|
||||
switch (actor._windowType) {
|
||||
switch (actor.meta_window.window_type) {
|
||||
case Meta.WindowType.NORMAL:
|
||||
actor.set_pivot_point(0.5, 0.5);
|
||||
this._destroying.push(actor);
|
||||
|
@ -97,8 +97,6 @@ const WindowMenu = new Lang.Class({
|
||||
if (window.is_always_on_all_workspaces())
|
||||
item.setSensitive(false);
|
||||
|
||||
let nWorkspaces = global.screen.n_workspaces;
|
||||
|
||||
if (!isSticky) {
|
||||
let workspace = window.get_workspace();
|
||||
if (workspace != workspace.get_neighbor(Meta.MotionDirection.LEFT)) {
|
||||
|
@ -111,7 +111,7 @@ const WindowClone = new Lang.Class({
|
||||
this.metaWindow._delegate = this;
|
||||
this._workspace = workspace;
|
||||
|
||||
this._windowClone = new Clutter.Clone({ source: realWindow.get_texture() });
|
||||
this._windowClone = new Clutter.Clone({ source: realWindow });
|
||||
// We expect this.actor to be used for all interaction rather than
|
||||
// this._windowClone; as the former is reactive and the latter
|
||||
// is not, this just works for most cases. However, for DND all
|
||||
@ -471,6 +471,10 @@ const WindowOverlay = new Lang.Class({
|
||||
this.title = title;
|
||||
this.closeButton = button;
|
||||
|
||||
// Don't block drop targets
|
||||
Shell.util_set_hidden_from_pick(this.title, true);
|
||||
Shell.util_set_hidden_from_pick(this.border, true);
|
||||
|
||||
parentActor.add_actor(this.title);
|
||||
parentActor.add_actor(this.border);
|
||||
parentActor.add_actor(this.closeButton);
|
||||
@ -1096,6 +1100,7 @@ const Workspace = new Lang.Class({
|
||||
_init : function(metaWorkspace, monitorIndex) {
|
||||
// When dragging a window, we use this slot for reserve space.
|
||||
this._reservedSlot = null;
|
||||
this._reservedSlotWindow = null;
|
||||
this.metaWorkspace = metaWorkspace;
|
||||
|
||||
// The full geometry is the geometry we should try and position
|
||||
|
@ -24,9 +24,10 @@ const XdndHandler = new Lang.Class({
|
||||
if (!Meta.is_wayland_compositor())
|
||||
global.init_xdnd();
|
||||
|
||||
global.connect('xdnd-enter', Lang.bind(this, this._onEnter));
|
||||
global.connect('xdnd-position-changed', Lang.bind(this, this._onPositionChanged));
|
||||
global.connect('xdnd-leave', Lang.bind(this, this._onLeave));
|
||||
var dnd = Meta.get_backend().get_dnd();
|
||||
dnd.connect('dnd-enter', Lang.bind(this, this._onEnter));
|
||||
dnd.connect('dnd-position-change', Lang.bind(this, this._onPositionChanged));
|
||||
dnd.connect('dnd-leave', Lang.bind(this, this._onLeave));
|
||||
|
||||
this._windowGroupVisibilityHandlerId = 0;
|
||||
},
|
||||
|
@ -53,6 +53,7 @@ js/ui/status/brightness.js
|
||||
js/ui/status/keyboard.js
|
||||
js/ui/status/location.js
|
||||
js/ui/status/network.js
|
||||
js/ui/status/nightLight.js
|
||||
js/ui/status/power.js
|
||||
js/ui/status/rfkill.js
|
||||
js/ui/status/system.js
|
||||
|
2
po/fa.po
2
po/fa.po
@ -1674,7 +1674,7 @@ msgstr "تقویم اوولوشن"
|
||||
#. Translators: Do NOT translate or transliterate this text (this is an icon file name)!
|
||||
#: src/calendar-server/evolution-calendar.desktop.in:6
|
||||
msgid "evolution"
|
||||
msgstr "اوولوشن"
|
||||
msgstr "evolution"
|
||||
|
||||
#. translators:
|
||||
#. * The number of sound outputs on a particular device
|
||||
|
357
po/gd.po
357
po/gd.po
@ -1,14 +1,14 @@
|
||||
# Scottish Gaelic translation for gnome-shell.
|
||||
# Copyright (C) 2015 gnome-shell's COPYRIGHT HOLDER
|
||||
# This file is distributed under the same license as the gnome-shell package.
|
||||
# GunChleoc <fios@foramnagaidhlig.net>, 2015, 2016.
|
||||
# GunChleoc <fios@foramnagaidhlig.net>, 2015, 2016, 2017.
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: gnome-shell master\n"
|
||||
"Report-Msgid-Bugs-To: http://bugzilla.gnome.org/enter_bug.cgi?product=gnome-"
|
||||
"shell&keywords=I18N+L10N&component=general\n"
|
||||
"POT-Creation-Date: 2016-09-12 23:57+0000\n"
|
||||
"PO-Revision-Date: 2016-09-13 10:47+0100\n"
|
||||
"Report-Msgid-Bugs-To: https://bugzilla.gnome.org/enter_bug.cgi?product"
|
||||
"=gnome-shell&keywords=I18N+L10N&component=general\n"
|
||||
"POT-Creation-Date: 2017-03-02 17:53+0000\n"
|
||||
"PO-Revision-Date: 2017-03-07 12:03+0100\n"
|
||||
"Last-Translator: GunChleoc <fios@foramnagaidhlig.net>\n"
|
||||
"Language-Team: Fòram na Gàidhlig\n"
|
||||
"Language: gd\n"
|
||||
@ -61,10 +61,136 @@ msgstr "Slige GNOME"
|
||||
msgid "Window management and application launching"
|
||||
msgstr "Stiùireadh uinneagan is tòiseachadh aplacaidean"
|
||||
|
||||
#: data/org.gnome.shell.gschema.xml.in:6
|
||||
msgid "Enable internal tools useful for developers and testers from Alt-F2"
|
||||
msgstr "Cuir an comas innealan an luchd-leasachaidh 's deuchainne o Alt-F2"
|
||||
|
||||
#: data/org.gnome.shell.gschema.xml.in:9
|
||||
msgid ""
|
||||
"Allows access to internal debugging and monitoring tools using the Alt-F2 "
|
||||
"dialog."
|
||||
msgstr ""
|
||||
"Ceadaich inntrigeadh dha na h-innealan a chum dì-bhugachaidh 's sgrùdaidh le "
|
||||
"còmhradh Alt-F2."
|
||||
|
||||
#: data/org.gnome.shell.gschema.xml.in:16
|
||||
msgid "UUIDs of extensions to enable"
|
||||
msgstr "UUIDs nan leudachan ri an cur an comas"
|
||||
|
||||
#: data/org.gnome.shell.gschema.xml.in:17
|
||||
msgid ""
|
||||
"GNOME Shell extensions have a UUID property; this key lists extensions which "
|
||||
"should be loaded. Any extension that wants to be loaded needs to be in this "
|
||||
"list. You can also manipulate this list with the EnableExtension and "
|
||||
"DisableExtension D-Bus methods on org.gnome.Shell."
|
||||
msgstr ""
|
||||
"Tha buadh UUID aig leudachain na Slige GNOME; seallaidh an iuchair sin na "
|
||||
"leudachain a bu chòir luchdadh. Feumaidh gach leudachan a tha ag iarraidh "
|
||||
"luchdadh a bhith air an liosta seo. 'S urrainn dhut an liosta seo "
|
||||
"atharrachadh cuideachd leis na modhan D-Bus EnableExtension agus "
|
||||
"DisableExtension air org.gnome.Shell."
|
||||
|
||||
#: data/org.gnome.shell.gschema.xml.in:26
|
||||
msgid "Disables the validation of extension version compatibility"
|
||||
msgstr ""
|
||||
"Cuiridh seo à comas dearbhadh na co-chòrdalachd airson tionndadh nan "
|
||||
"leudachan"
|
||||
|
||||
#: data/org.gnome.shell.gschema.xml.in:27
|
||||
msgid ""
|
||||
"GNOME Shell will only load extensions that claim to support the current "
|
||||
"running version. Enabling this option will disable this check and try to "
|
||||
"load all extensions regardless of the versions they claim to support."
|
||||
msgstr ""
|
||||
"Cha luchdaich an t-Slige GNOME ach leudachain a dh'innseas gu bheil iar co-"
|
||||
"chòrdail leis an tionndadh a tha 'ga ruith. Ma chuireas tu an roghainn seo "
|
||||
"an comas, thèid an dearbhadh a chur à comas agus feuchaidh sinn ris a h-uile "
|
||||
"leudachan a luchdadh ge b' e dè na tionndaidhean ris an cuir iad taic dhan "
|
||||
"rèir-san."
|
||||
|
||||
#: data/org.gnome.shell.gschema.xml.in:35
|
||||
msgid "List of desktop file IDs for favorite applications"
|
||||
msgstr ""
|
||||
"Liosta dhe IDan nam faidhlichean desktop airson nan aplacaidean as annsa "
|
||||
"leat"
|
||||
|
||||
#: data/org.gnome.shell.gschema.xml.in:36
|
||||
msgid ""
|
||||
"The applications corresponding to these identifiers will be displayed in the "
|
||||
"favorites area."
|
||||
msgstr ""
|
||||
"Thèid na h-aplacaidean a fhreagras ris na h-aithnichearan seo a shealltainn "
|
||||
"air raon nan annsachdan."
|
||||
|
||||
#: data/org.gnome.shell.gschema.xml.in:43
|
||||
msgid "App Picker View"
|
||||
msgstr "Sealladh roghnaichear nan aplacaid"
|
||||
|
||||
#: data/org.gnome.shell.gschema.xml.in:44
|
||||
msgid "Index of the currently selected view in the application picker."
|
||||
msgstr "Inneacs an t-seallaidh làithrich ann an roghnaichear nan aplacaid."
|
||||
|
||||
#: data/org.gnome.shell.gschema.xml.in:50
|
||||
msgid "History for command (Alt-F2) dialog"
|
||||
msgstr "Eachdraidh a' chòmhraidh-àithne (Alt-F2)"
|
||||
|
||||
#. Translators: looking glass is a debugger and inspector tool, see https://wiki.gnome.org/Projects/GnomeShell/LookingGlass
|
||||
#: data/org.gnome.shell.gschema.xml.in:55
|
||||
msgid "History for the looking glass dialog"
|
||||
msgstr "Eachdraidh a' chomhraidh aig looking glass"
|
||||
|
||||
#: data/org.gnome.shell.gschema.xml.in:59
|
||||
msgid "Always show the 'Log out' menu item in the user menu."
|
||||
msgstr ""
|
||||
"Seall nì \"Clàraich a-mach\" air clàr-taice a' chleachdaiche an-còmhnaidh."
|
||||
|
||||
#: data/org.gnome.shell.gschema.xml.in:60
|
||||
msgid ""
|
||||
"This key overrides the automatic hiding of the 'Log out' menu item in single-"
|
||||
"user, single-session situations."
|
||||
msgstr ""
|
||||
"Tar-àithnidh an iuchair seo am falach fèin-obrachail aig \"Clàraich a-mach\" "
|
||||
"air a' chlar-taice ann an suidheachaidhean le aon chleachdaiche 's aon "
|
||||
"seisean a-mhàin."
|
||||
|
||||
#: data/org.gnome.shell.gschema.xml.in:67
|
||||
msgid ""
|
||||
"Whether to remember password for mounting encrypted or remote filesystems"
|
||||
msgstr ""
|
||||
"Co-dhiù an dèid am facal-faire a chuimhneachadh airson munntachadh "
|
||||
"shiostaman-fhaidhlichean crioptaichte no cèine"
|
||||
|
||||
#: data/org.gnome.shell.gschema.xml.in:68
|
||||
msgid ""
|
||||
"The shell will request a password when an encrypted device or a remote "
|
||||
"filesystem is mounted. If the password can be saved for future use a "
|
||||
"'Remember Password' checkbox will be present. This key sets the default "
|
||||
"state of the checkbox."
|
||||
msgstr ""
|
||||
"Iarraidh an t-slige facal-fàire ort nuair a thèid siostam-fhaidhlichean "
|
||||
"crioptaichte no cèin a mhunntachadh. Ma ghabhas am facal-faire sàbhaladh "
|
||||
"airson na h-ama ri teachd, bidh bogsa-còmhraige \"Cuimhnich am facal-fàire\" "
|
||||
"ann. Suidhichidh an iuchair seo staid tùsail na bogsa-còmhraige ud."
|
||||
|
||||
#: data/org.gnome.shell.gschema.xml.in:77
|
||||
msgid ""
|
||||
"Whether the default Bluetooth adapter had set up devices associated to it"
|
||||
msgstr ""
|
||||
"Co-dhiù an robh uidheaman co-cheangailte ris an adaptar Bluetooth gus nach "
|
||||
"robh"
|
||||
|
||||
#: data/org.gnome.shell.gschema.xml.in:78
|
||||
msgid ""
|
||||
"The shell will only show a Bluetooth menu item if a Bluetooth adapter is "
|
||||
"powered, or if there were devices set up associated with the default "
|
||||
"adapter. This will be reset if the default adapter is ever seen not to have "
|
||||
"devices associated to it."
|
||||
msgstr ""
|
||||
"Cha seall an t-slige nì clàir-taice \"Bluetooth\" ach ma tha cumhachd aig "
|
||||
"adaptar Bluetooth na ma chaidh uidheaman co-cheangailte ris an adaptar "
|
||||
"tùsail roimhe. Thèid seo ath-shuidheachadh ma chithear an t-adaptar tùsail "
|
||||
"gun uidheam co-cheangailte ris."
|
||||
|
||||
#: data/org.gnome.shell.gschema.xml.in:93
|
||||
msgid "Keybinding to open the application menu"
|
||||
msgstr "Nasgadh iuchrach gus clàr-taice na h-aplacaid fhosgladh"
|
||||
@ -74,12 +200,10 @@ msgid "Keybinding to open the application menu."
|
||||
msgstr "Nasgadh iuchrach gus clàr-taice na h-aplacaid fhosgladh."
|
||||
|
||||
#: data/org.gnome.shell.gschema.xml.in:100
|
||||
#| msgid "Keybinding to open the application menu"
|
||||
msgid "Keybinding to open the \"Show Applications\" view"
|
||||
msgstr "Nasgadh iuchrach gus an sealladh \"Seall aplacaidean\" fhosgladh"
|
||||
|
||||
#: data/org.gnome.shell.gschema.xml.in:101
|
||||
#| msgid "Keybinding to open the application menu."
|
||||
msgid ""
|
||||
"Keybinding to open the \"Show Applications\" view of the Activities Overview."
|
||||
msgstr ""
|
||||
@ -87,23 +211,19 @@ msgstr ""
|
||||
"gnìomhachd fhosgladh."
|
||||
|
||||
#: data/org.gnome.shell.gschema.xml.in:108
|
||||
#| msgid "Keybinding to open the application menu"
|
||||
msgid "Keybinding to open the overview"
|
||||
msgstr "Nasgadh iuchrach gus am foir-shealladh fhosgladh"
|
||||
|
||||
#: data/org.gnome.shell.gschema.xml.in:109
|
||||
#| msgid "Keybinding to open the application menu."
|
||||
msgid "Keybinding to open the Activities Overview."
|
||||
msgstr "Nasgadh iuchrach gus foir-shealladh na gnìomhachd fhosgladh."
|
||||
|
||||
#: data/org.gnome.shell.gschema.xml.in:115
|
||||
#| msgid "Keybinding to focus the active notification"
|
||||
msgid "Keybinding to toggle the visibility of the notification list"
|
||||
msgstr ""
|
||||
"Nasgadh iuchrach gus an fhaicsinneachd air liosta nam brathan a thoglachadh"
|
||||
|
||||
#: data/org.gnome.shell.gschema.xml.in:116
|
||||
#| msgid "Keybinding to focus the active notification."
|
||||
msgid "Keybinding to toggle the visibility of the notification list."
|
||||
msgstr ""
|
||||
"Nasgadh iuchrach gus an fhaicsinneachd air liosta nam brathan a thoglachadh."
|
||||
@ -116,10 +236,94 @@ msgstr "Nasgadh iuchrach gus am fòcas a chur air a' bhrath ghnìomhach"
|
||||
msgid "Keybinding to focus the active notification."
|
||||
msgstr "Nasgadh iuchrach gus am fòcas a chur air a' bhrath ghnìomhach."
|
||||
|
||||
#: data/org.gnome.shell.gschema.xml.in:129
|
||||
msgid ""
|
||||
"Keybinding that pauses and resumes all running tweens, for debugging purposes"
|
||||
msgstr ""
|
||||
"Nasgadh iuchrach a chuir gach tween a tha 'ga ruith 'na stad 's a "
|
||||
"thòisicheas orra a-rithist a chum dì-bhugachaidh"
|
||||
|
||||
#: data/org.gnome.shell.gschema.xml.in:138
|
||||
msgid "Which keyboard to use"
|
||||
msgstr "Am meur-chlàr ri chleachdadh"
|
||||
|
||||
#: data/org.gnome.shell.gschema.xml.in:139
|
||||
msgid "The type of keyboard to use."
|
||||
msgstr "An seòrsa de mheur-chlàr a thèid a chleachdadh."
|
||||
|
||||
#: data/org.gnome.shell.gschema.xml.in:150
|
||||
#: data/org.gnome.shell.gschema.xml.in:177
|
||||
msgid "Limit switcher to current workspace."
|
||||
msgstr "Cuingich an t-suidsear air an rum-obrach làithreach."
|
||||
|
||||
#: data/org.gnome.shell.gschema.xml.in:151
|
||||
msgid ""
|
||||
"If true, only applications that have windows on the current workspace are "
|
||||
"shown in the switcher. Otherwise, all applications are included."
|
||||
msgstr ""
|
||||
"Mas e true a th' ann, cha dèid a shealltainn san t-suidsear ach na "
|
||||
"h-aplacaidean aig a bheil uinneag san rum-obrach làithreach. Mur e, thèid a "
|
||||
"h-uile aplacaid a ghabhail a-steach."
|
||||
|
||||
#: data/org.gnome.shell.gschema.xml.in:168
|
||||
msgid "The application icon mode."
|
||||
msgstr "Modh ìomhaigheag na h-aplacaid."
|
||||
|
||||
#: data/org.gnome.shell.gschema.xml.in:169
|
||||
msgid ""
|
||||
"Configures how the windows are shown in the switcher. Valid possibilities "
|
||||
"are 'thumbnail-only' (shows a thumbnail of the window), 'app-icon-"
|
||||
"only' (shows only the application icon) or 'both'."
|
||||
msgstr ""
|
||||
"Rèitichidh seo an dòigh sa thèid na h-uinneagan a shealltainn san "
|
||||
"t-suidsear. 'S e \"thumbnail-only\" (seallaidh seo dealbhag na h-uinneige), "
|
||||
"\"app-icon-only\" (seallaidh seo ìomhaigheag na h-aplacaid) no \"both\" "
|
||||
"(seallaidh seo an dà chuid dhiubh) a tha sna luachan dligheach."
|
||||
|
||||
#: data/org.gnome.shell.gschema.xml.in:178
|
||||
msgid ""
|
||||
"If true, only windows from the current workspace are shown in the switcher. "
|
||||
"Otherwise, all windows are included."
|
||||
msgstr ""
|
||||
"Mas e true a th' ann, cha dèid a shealltainn san t-suidsear ach na "
|
||||
"h-uinneagan a tha san rum-obrach làithreach. Mur e, thèid a h-uile uinneag a "
|
||||
"ghabhail a-steach."
|
||||
|
||||
#: data/org.gnome.shell.gschema.xml.in:189
|
||||
msgid "Attach modal dialog to the parent window"
|
||||
msgstr "Ceangail còmhradh mòdach ris an uinneag-pàraint"
|
||||
|
||||
#: data/org.gnome.shell.gschema.xml.in:190
|
||||
#: data/org.gnome.shell.gschema.xml.in:199
|
||||
#: data/org.gnome.shell.gschema.xml.in:207
|
||||
#: data/org.gnome.shell.gschema.xml.in:215
|
||||
#: data/org.gnome.shell.gschema.xml.in:223
|
||||
msgid ""
|
||||
"This key overrides the key in org.gnome.mutter when running GNOME Shell."
|
||||
msgstr ""
|
||||
"Tar-àithnidh an iuchair seo an iuchair ann an org.gnome.mutter nuair a thèid "
|
||||
"Slige GNOME a ruith."
|
||||
|
||||
#: data/org.gnome.shell.gschema.xml.in:198
|
||||
msgid "Enable edge tiling when dropping windows on screen edges"
|
||||
msgstr ""
|
||||
"Cuir leacadh nan oirean an comas nuair a thèid uinneagan a leigeil às aig "
|
||||
"oir na sgrìn"
|
||||
|
||||
#: data/org.gnome.shell.gschema.xml.in:206
|
||||
msgid "Workspaces are managed dynamically"
|
||||
msgstr "Thèid na rumannan-obrach a stiùireadh a làimh"
|
||||
|
||||
#: data/org.gnome.shell.gschema.xml.in:214
|
||||
msgid "Workspaces only on primary monitor"
|
||||
msgstr "Rumannan-obrach air a' phrìomh-sgrìn a-mhàin"
|
||||
|
||||
#: data/org.gnome.shell.gschema.xml.in:222
|
||||
msgid "Delay focus changes in mouse mode until the pointer stops moving"
|
||||
msgstr ""
|
||||
"Cuir dàil air atharraichean an fòcais ann am modh luchaige gus an sguir an "
|
||||
"tomhaire air gluasad"
|
||||
|
||||
#: data/org.gnome.Shell.PortalHelper.desktop.in.in:3
|
||||
msgid "Network Login"
|
||||
msgstr "Clàradh a-steach lìonraidh"
|
||||
@ -141,7 +345,7 @@ msgstr "Leudachain na Slige GNOME"
|
||||
#: js/gdm/authPrompt.js:147 js/ui/audioDeviceSelection.js:71
|
||||
#: js/ui/components/networkAgent.js:145 js/ui/components/polkitAgent.js:179
|
||||
#: js/ui/endSessionDialog.js:483 js/ui/extensionDownloader.js:195
|
||||
#: js/ui/shellMountOperation.js:399 js/ui/status/network.js:916
|
||||
#: js/ui/shellMountOperation.js:399 js/ui/status/network.js:926
|
||||
msgid "Cancel"
|
||||
msgstr "Sguir dheth"
|
||||
|
||||
@ -331,12 +535,12 @@ msgstr "Cuir ris na h-annsachdan"
|
||||
msgid "Show Details"
|
||||
msgstr "Seall am mion-fhiosrachadh"
|
||||
|
||||
#: js/ui/appFavorites.js:134
|
||||
#: js/ui/appFavorites.js:136
|
||||
#, javascript-format
|
||||
msgid "%s has been added to your favorites."
|
||||
msgstr "Chaidh %s a chur ris na h-annsachdan agad."
|
||||
|
||||
#: js/ui/appFavorites.js:168
|
||||
#: js/ui/appFavorites.js:170
|
||||
#, javascript-format
|
||||
msgid "%s has been removed from your favorites."
|
||||
msgstr "Chaidh %s a toirt air falbh o na h-annsachdan agad."
|
||||
@ -346,7 +550,6 @@ msgid "Select Audio Device"
|
||||
msgstr "Tagh uidheam fuaime"
|
||||
|
||||
#: js/ui/audioDeviceSelection.js:69
|
||||
#| msgid "Account Settings"
|
||||
msgid "Sound Settings"
|
||||
msgstr "Roghainnean fuaime"
|
||||
|
||||
@ -499,8 +702,8 @@ msgstr "Facal-faire:"
|
||||
msgid "Type again:"
|
||||
msgstr "Am facal-faire a-rithist:"
|
||||
|
||||
#: js/ui/components/networkAgent.js:140 js/ui/status/network.js:269
|
||||
#: js/ui/status/network.js:352 js/ui/status/network.js:919
|
||||
#: js/ui/components/networkAgent.js:140 js/ui/status/network.js:270
|
||||
#: js/ui/status/network.js:353 js/ui/status/network.js:929
|
||||
msgid "Connect"
|
||||
msgstr "Ceangail"
|
||||
|
||||
@ -528,11 +731,11 @@ msgstr "Facal-faire na h-iuchrach prìobhaidich: "
|
||||
msgid "Service: "
|
||||
msgstr "Seirbheis: "
|
||||
|
||||
#: js/ui/components/networkAgent.js:320 js/ui/components/networkAgent.js:658
|
||||
#: js/ui/components/networkAgent.js:320 js/ui/components/networkAgent.js:666
|
||||
msgid "Authentication required by wireless network"
|
||||
msgstr "Tha an lìonra uèirleas ag iarraidh dearbhadh"
|
||||
|
||||
#: js/ui/components/networkAgent.js:321 js/ui/components/networkAgent.js:659
|
||||
#: js/ui/components/networkAgent.js:321 js/ui/components/networkAgent.js:667
|
||||
#, javascript-format
|
||||
msgid ""
|
||||
"Passwords or encryption keys are required to access the wireless network "
|
||||
@ -541,7 +744,7 @@ msgstr ""
|
||||
"Tha feum air faclan-faire no iuchraichean crioptachaidh gus an lìonra "
|
||||
"uèirleas “%s” inntrigeadh."
|
||||
|
||||
#: js/ui/components/networkAgent.js:325 js/ui/components/networkAgent.js:662
|
||||
#: js/ui/components/networkAgent.js:325 js/ui/components/networkAgent.js:670
|
||||
msgid "Wired 802.1X authentication"
|
||||
msgstr "Dearbhadh Wired 802.1X"
|
||||
|
||||
@ -549,15 +752,15 @@ msgstr "Dearbhadh Wired 802.1X"
|
||||
msgid "Network name: "
|
||||
msgstr "Ainm an lìonraidh: "
|
||||
|
||||
#: js/ui/components/networkAgent.js:332 js/ui/components/networkAgent.js:666
|
||||
#: js/ui/components/networkAgent.js:332 js/ui/components/networkAgent.js:674
|
||||
msgid "DSL authentication"
|
||||
msgstr "Dearbhadh DSL"
|
||||
|
||||
#: js/ui/components/networkAgent.js:339 js/ui/components/networkAgent.js:672
|
||||
#: js/ui/components/networkAgent.js:339 js/ui/components/networkAgent.js:680
|
||||
msgid "PIN code required"
|
||||
msgstr "Tha feum air còd PIN"
|
||||
|
||||
#: js/ui/components/networkAgent.js:340 js/ui/components/networkAgent.js:673
|
||||
#: js/ui/components/networkAgent.js:340 js/ui/components/networkAgent.js:681
|
||||
msgid "PIN code is needed for the mobile broadband device"
|
||||
msgstr "Tha feum air còd PIN airson an inneil-làimhe banna-leathainn"
|
||||
|
||||
@ -565,17 +768,17 @@ msgstr "Tha feum air còd PIN airson an inneil-làimhe banna-leathainn"
|
||||
msgid "PIN: "
|
||||
msgstr "PIN: "
|
||||
|
||||
#: js/ui/components/networkAgent.js:348 js/ui/components/networkAgent.js:679
|
||||
#: js/ui/components/networkAgent.js:348 js/ui/components/networkAgent.js:687
|
||||
msgid "Mobile broadband network password"
|
||||
msgstr "Facal-faire a' bhanna-leathainn inneil-làimhe"
|
||||
|
||||
#: js/ui/components/networkAgent.js:349 js/ui/components/networkAgent.js:663
|
||||
#: js/ui/components/networkAgent.js:667 js/ui/components/networkAgent.js:680
|
||||
#: js/ui/components/networkAgent.js:349 js/ui/components/networkAgent.js:671
|
||||
#: js/ui/components/networkAgent.js:675 js/ui/components/networkAgent.js:688
|
||||
#, javascript-format
|
||||
msgid "A password is required to connect to “%s”."
|
||||
msgstr "tha feum air facal-faire airson ceangal ri “%s”."
|
||||
|
||||
#: js/ui/components/networkAgent.js:647 js/ui/status/network.js:1658
|
||||
#: js/ui/components/networkAgent.js:655 js/ui/status/network.js:1672
|
||||
msgid "Network Manager"
|
||||
msgstr "Manaidsear nan lìonra"
|
||||
|
||||
@ -769,8 +972,6 @@ msgid "Power off after updates are installed"
|
||||
msgstr "Cuir a' chumhachd dheth nuair a bhios na h-ùrachaidhean air an stàladh"
|
||||
|
||||
#: js/ui/endSessionDialog.js:137
|
||||
#| msgctxt "title"
|
||||
#| msgid "Restart & Install Updates"
|
||||
msgctxt "title"
|
||||
msgid "Restart & Install Upgrade"
|
||||
msgstr "Ath-thòisich ⁊ stàlaich an t-àrdachadh"
|
||||
@ -896,14 +1097,10 @@ msgid "System Information"
|
||||
msgstr "Fiosrachadh an t-siostaim"
|
||||
|
||||
#: js/ui/mpris.js:194
|
||||
#| msgctxt "program"
|
||||
#| msgid "Unknown"
|
||||
msgid "Unknown artist"
|
||||
msgstr "Neach-ciùil nach aithne dhuinn"
|
||||
|
||||
#: js/ui/mpris.js:195
|
||||
#| msgctxt "program"
|
||||
#| msgid "Unknown"
|
||||
msgid "Unknown title"
|
||||
msgstr "Tiotal nach aithne dhuinn"
|
||||
|
||||
@ -963,6 +1160,10 @@ msgstr "Cuir a-steach àithne"
|
||||
msgid "Close"
|
||||
msgstr "Dùin"
|
||||
|
||||
#: js/ui/runDialog.js:277
|
||||
msgid "Restart is not available on Wayland"
|
||||
msgstr "Chan eil ath-thòiseachadh ri làimh air Wayland"
|
||||
|
||||
#: js/ui/runDialog.js:282
|
||||
msgid "Restarting…"
|
||||
msgstr "'Ga thòiseachadh às ùr…"
|
||||
@ -1006,11 +1207,11 @@ msgstr "Feumaidh GNOME an sgrìn a glasadh"
|
||||
#.
|
||||
#. XXX: another option is to kick the user into the gdm login
|
||||
#. screen, where we're not affected by grabs
|
||||
#: js/ui/screenShield.js:825 js/ui/screenShield.js:1291
|
||||
#: js/ui/screenShield.js:825 js/ui/screenShield.js:1292
|
||||
msgid "Unable to lock"
|
||||
msgstr "Cha ghabh a ghlasadh"
|
||||
|
||||
#: js/ui/screenShield.js:826 js/ui/screenShield.js:1292
|
||||
#: js/ui/screenShield.js:826 js/ui/screenShield.js:1293
|
||||
msgid "Lock was blocked by an application"
|
||||
msgstr "Chaidh a' ghlas a bhacadh le aplacaid"
|
||||
|
||||
@ -1094,7 +1295,7 @@ msgstr "Teacsa mòr"
|
||||
msgid "Bluetooth"
|
||||
msgstr "Bluetooth"
|
||||
|
||||
#: js/ui/status/bluetooth.js:56 js/ui/status/network.js:624
|
||||
#: js/ui/status/bluetooth.js:56 js/ui/status/network.js:625
|
||||
msgid "Bluetooth Settings"
|
||||
msgstr "Roghainnean Bluetooth"
|
||||
|
||||
@ -1116,13 +1317,13 @@ msgstr "Dheth"
|
||||
msgid "Not In Use"
|
||||
msgstr "Chan eil e 'ga chleachdadh"
|
||||
|
||||
#: js/ui/status/bluetooth.js:142 js/ui/status/network.js:1279
|
||||
#: js/ui/status/bluetooth.js:142 js/ui/status/network.js:1289
|
||||
msgid "Turn On"
|
||||
msgstr "Cuir air"
|
||||
|
||||
#: js/ui/status/bluetooth.js:142 js/ui/status/network.js:178
|
||||
#: js/ui/status/network.js:353 js/ui/status/network.js:1279
|
||||
#: js/ui/status/network.js:1394 js/ui/status/rfkill.js:90
|
||||
#: js/ui/status/bluetooth.js:142 js/ui/status/network.js:179
|
||||
#: js/ui/status/network.js:354 js/ui/status/network.js:1289
|
||||
#: js/ui/status/network.js:1404 js/ui/status/rfkill.js:90
|
||||
#: js/ui/status/rfkill.js:117
|
||||
msgid "Turn Off"
|
||||
msgstr "Cuir dheth"
|
||||
@ -1171,18 +1372,18 @@ msgstr ""
|
||||
"'S urrainn dhut inntrigeadh an ionaid atharrachadh uair sam bith ann an "
|
||||
"roghainnean na prìobhaideachd."
|
||||
|
||||
#: js/ui/status/network.js:101
|
||||
#: js/ui/status/network.js:102
|
||||
msgid "<unknown>"
|
||||
msgstr "<neo-aithnichte>"
|
||||
|
||||
#. Translators: %s is a network identifier
|
||||
#: js/ui/status/network.js:451 js/ui/status/network.js:1308
|
||||
#: js/ui/status/network.js:452 js/ui/status/network.js:1318
|
||||
#, javascript-format
|
||||
msgid "%s Off"
|
||||
msgstr "%s dheth"
|
||||
|
||||
#. Translators: %s is a network identifier
|
||||
#: js/ui/status/network.js:454
|
||||
#: js/ui/status/network.js:455
|
||||
#, javascript-format
|
||||
msgid "%s Connected"
|
||||
msgstr "%s ceangailte"
|
||||
@ -1190,168 +1391,168 @@ msgstr "%s ceangailte"
|
||||
#. Translators: this is for network devices that are physically present but are not
|
||||
#. under NetworkManager's control (and thus cannot be used in the menu);
|
||||
#. %s is a network identifier
|
||||
#: js/ui/status/network.js:459
|
||||
#: js/ui/status/network.js:460
|
||||
#, javascript-format
|
||||
msgid "%s Unmanaged"
|
||||
msgstr "%s gun stiùireadh"
|
||||
|
||||
#. Translators: %s is a network identifier
|
||||
#: js/ui/status/network.js:462
|
||||
#: js/ui/status/network.js:463
|
||||
#, javascript-format
|
||||
msgid "%s Disconnecting"
|
||||
msgstr "A' dì-cheangal %s"
|
||||
|
||||
#. Translators: %s is a network identifier
|
||||
#: js/ui/status/network.js:469 js/ui/status/network.js:1300
|
||||
#: js/ui/status/network.js:470 js/ui/status/network.js:1310
|
||||
#, javascript-format
|
||||
msgid "%s Connecting"
|
||||
msgstr "A' ceangal %s"
|
||||
|
||||
#. Translators: this is for network connections that require some kind of key or password; %s is a network identifier
|
||||
#: js/ui/status/network.js:472
|
||||
#: js/ui/status/network.js:473
|
||||
#, javascript-format
|
||||
msgid "%s Requires Authentication"
|
||||
msgstr "Tha %s ag iarraidh dearbhadh"
|
||||
|
||||
#. Translators: this is for devices that require some kind of firmware or kernel
|
||||
#. module, which is missing; %s is a network identifier
|
||||
#: js/ui/status/network.js:480
|
||||
#: js/ui/status/network.js:481
|
||||
#, javascript-format
|
||||
msgid "Firmware Missing For %s"
|
||||
msgstr "Tha bathar-an-sàs a dhìth air %s"
|
||||
|
||||
#. Translators: this is for a network device that cannot be activated (for example it
|
||||
#. is disabled by rfkill, or it has no coverage; %s is a network identifier
|
||||
#: js/ui/status/network.js:484
|
||||
#: js/ui/status/network.js:485
|
||||
#, javascript-format
|
||||
msgid "%s Unavailable"
|
||||
msgstr "Chan eil %s ri fhaighinn"
|
||||
|
||||
#. Translators: %s is a network identifier
|
||||
#: js/ui/status/network.js:487
|
||||
#: js/ui/status/network.js:488
|
||||
#, javascript-format
|
||||
msgid "%s Connection Failed"
|
||||
msgstr "Dh'fhàillig le %s a cheangal"
|
||||
|
||||
#: js/ui/status/network.js:503
|
||||
#: js/ui/status/network.js:504
|
||||
msgid "Wired Settings"
|
||||
msgstr "Roghainnean le uèir"
|
||||
|
||||
#: js/ui/status/network.js:545
|
||||
#: js/ui/status/network.js:546
|
||||
msgid "Mobile Broadband Settings"
|
||||
msgstr "Roghainnean banna-leathainn inneal-làimhe"
|
||||
|
||||
#. Translators: %s is a network identifier
|
||||
#: js/ui/status/network.js:588 js/ui/status/network.js:1305
|
||||
#: js/ui/status/network.js:589 js/ui/status/network.js:1315
|
||||
#, javascript-format
|
||||
msgid "%s Hardware Disabled"
|
||||
msgstr "Tha bathar-cruaidh %s à comas"
|
||||
|
||||
#. Translators: this is for a network device that cannot be activated
|
||||
#. because it's disabled by rfkill (airplane mode); %s is a network identifier
|
||||
#: js/ui/status/network.js:592
|
||||
#: js/ui/status/network.js:593
|
||||
#, javascript-format
|
||||
msgid "%s Disabled"
|
||||
msgstr "%s à comas"
|
||||
|
||||
#: js/ui/status/network.js:632
|
||||
#: js/ui/status/network.js:633
|
||||
msgid "Connect to Internet"
|
||||
msgstr "Ceangail ris an eadar-lìon"
|
||||
|
||||
#: js/ui/status/network.js:813
|
||||
#: js/ui/status/network.js:823
|
||||
msgid "Airplane Mode is On"
|
||||
msgstr "Tha am modh itealain air"
|
||||
|
||||
#: js/ui/status/network.js:814
|
||||
#: js/ui/status/network.js:824
|
||||
msgid "Wi-Fi is disabled when airplane mode is on."
|
||||
msgstr "Tha WiFi à comas fhad 's a tha am modh itealain air."
|
||||
|
||||
#: js/ui/status/network.js:815
|
||||
#: js/ui/status/network.js:825
|
||||
msgid "Turn Off Airplane Mode"
|
||||
msgstr "Cuir am modh itealain dheth"
|
||||
|
||||
#: js/ui/status/network.js:824
|
||||
#: js/ui/status/network.js:834
|
||||
msgid "Wi-Fi is Off"
|
||||
msgstr "Tha WiFi dheth"
|
||||
|
||||
#: js/ui/status/network.js:825
|
||||
#: js/ui/status/network.js:835
|
||||
msgid "Wi-Fi needs to be turned on in order to connect to a network."
|
||||
msgstr "Feumaidh tu WiFi a chur air gus ceangal ri lìonra."
|
||||
|
||||
#: js/ui/status/network.js:826
|
||||
#: js/ui/status/network.js:836
|
||||
msgid "Turn On Wi-Fi"
|
||||
msgstr "Cuir WiFi air"
|
||||
|
||||
#: js/ui/status/network.js:851
|
||||
#: js/ui/status/network.js:861
|
||||
msgid "Wi-Fi Networks"
|
||||
msgstr "Lìonraidhean WiFi"
|
||||
|
||||
#: js/ui/status/network.js:853
|
||||
#: js/ui/status/network.js:863
|
||||
msgid "Select a network"
|
||||
msgstr "Tagh lìonra"
|
||||
|
||||
#: js/ui/status/network.js:883
|
||||
#: js/ui/status/network.js:893
|
||||
msgid "No Networks"
|
||||
msgstr "Chan eil lìonra ann"
|
||||
|
||||
#: js/ui/status/network.js:904 js/ui/status/rfkill.js:115
|
||||
#: js/ui/status/network.js:914 js/ui/status/rfkill.js:115
|
||||
msgid "Use hardware switch to turn off"
|
||||
msgstr "Cleachd suidse bathair-chruaidh gus a chur dheth"
|
||||
|
||||
#: js/ui/status/network.js:1171
|
||||
#: js/ui/status/network.js:1181
|
||||
msgid "Select Network"
|
||||
msgstr "Tagh lìonra"
|
||||
|
||||
#: js/ui/status/network.js:1177
|
||||
#: js/ui/status/network.js:1187
|
||||
msgid "Wi-Fi Settings"
|
||||
msgstr "Roghainnean WiFi"
|
||||
|
||||
#. Translators: %s is a network identifier
|
||||
#: js/ui/status/network.js:1296
|
||||
#: js/ui/status/network.js:1306
|
||||
#, javascript-format
|
||||
msgid "%s Hotspot Active"
|
||||
msgstr "Tha %s hotspot gnìomhach"
|
||||
|
||||
#. Translators: %s is a network identifier
|
||||
#: js/ui/status/network.js:1311
|
||||
#: js/ui/status/network.js:1321
|
||||
#, javascript-format
|
||||
msgid "%s Not Connected"
|
||||
msgstr "Chan eil %s ceangailte"
|
||||
|
||||
#: js/ui/status/network.js:1411
|
||||
#: js/ui/status/network.js:1421
|
||||
msgid "connecting..."
|
||||
msgstr "'ga cheangal..."
|
||||
|
||||
#. Translators: this is for network connections that require some kind of key or password
|
||||
#: js/ui/status/network.js:1414
|
||||
#: js/ui/status/network.js:1424
|
||||
msgid "authentication required"
|
||||
msgstr "tha feum air dearbhadh"
|
||||
|
||||
#: js/ui/status/network.js:1416
|
||||
#: js/ui/status/network.js:1426
|
||||
msgid "connection failed"
|
||||
msgstr "dh'fhàillig leis a' cheangal"
|
||||
|
||||
#: js/ui/status/network.js:1482 js/ui/status/rfkill.js:93
|
||||
#: js/ui/status/network.js:1492 js/ui/status/rfkill.js:93
|
||||
msgid "Network Settings"
|
||||
msgstr "Roghainnean an lìonraidh"
|
||||
|
||||
#: js/ui/status/network.js:1484
|
||||
#: js/ui/status/network.js:1494
|
||||
msgid "VPN Settings"
|
||||
msgstr "Roghainnean VPN"
|
||||
|
||||
#: js/ui/status/network.js:1503
|
||||
#: js/ui/status/network.js:1513
|
||||
msgid "VPN"
|
||||
msgstr "VPN"
|
||||
|
||||
#: js/ui/status/network.js:1513
|
||||
#: js/ui/status/network.js:1523
|
||||
msgid "VPN Off"
|
||||
msgstr "Tha VPN dheth"
|
||||
|
||||
#: js/ui/status/network.js:1697
|
||||
#: js/ui/status/network.js:1711
|
||||
msgid "Connection failed"
|
||||
msgstr "Dh'fhàillig leis a' cheangal"
|
||||
|
||||
#: js/ui/status/network.js:1698
|
||||
#: js/ui/status/network.js:1712
|
||||
msgid "Activation of network connection failed"
|
||||
msgstr "Dh'fhàillig gnìomhachadh a' cheangail ris an lìonra"
|
||||
|
||||
|
72
po/he.po
72
po/he.po
@ -1,10 +1,10 @@
|
||||
# Hebrew translation for gnome-shell.
|
||||
# Copyright (C) 2009 gnome-shell's COPYRIGHT HOLDER
|
||||
# This file is distributed under the same license as the gnome-shell package.
|
||||
# liel <lielft@gmail.com>, 2009.
|
||||
# Yaron Shahrabani <sh.yaron@gmail.com>, 2010.
|
||||
#
|
||||
# Yosef Or Boczko <yoseforb@gnome.org>, 2013, 2014.
|
||||
# Hebrew translation for gnome-shell.
|
||||
# Copyright (C) 2009 gnome-shell's COPYRIGHT HOLDER
|
||||
# This file is distributed under the same license as the gnome-shell package.
|
||||
# liel <lielft@gmail.com>, 2009.
|
||||
# Yaron Shahrabani <sh.yaron@gmail.com>, 2010.
|
||||
#
|
||||
# Yosef Or Boczko <yoseforb@gnome.org>, 2013, 2014.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
@ -1095,7 +1095,7 @@ msgstr "מופעל מחדש…"
|
||||
msgid "%A, %B %d"
|
||||
msgstr "%A, ה־%d ב%B"
|
||||
|
||||
|
||||
# javascript-format
|
||||
#: js/ui/screenShield.js:144
|
||||
#, javascript-format
|
||||
msgid "%d new message"
|
||||
@ -1103,7 +1103,7 @@ msgid_plural "%d new messages"
|
||||
msgstr[0] "הודעה חדשה אחת"
|
||||
msgstr[1] "%d הודעות חדשות"
|
||||
|
||||
|
||||
# javascript-format
|
||||
#: js/ui/screenShield.js:146
|
||||
#, javascript-format
|
||||
msgid "%d new notification"
|
||||
@ -1577,7 +1577,7 @@ msgstr "שחזור הגדרות"
|
||||
msgid "Keep Changes"
|
||||
msgstr "שמירת שינויים"
|
||||
|
||||
|
||||
# javascript-format
|
||||
#: js/ui/windowManager.js:103
|
||||
#, javascript-format
|
||||
msgid "Settings changes will revert in %d second"
|
||||
@ -1728,7 +1728,7 @@ msgstr "המשתמש בחר להתעלם מתיבת דו־שיח האימות"
|
||||
#~ msgid "System"
|
||||
#~ msgstr "מערכת"
|
||||
|
||||
|
||||
# javascript-format
|
||||
#~ msgid "Show the notification list"
|
||||
#~ msgstr "הצגת רשימת ההתרעות"
|
||||
|
||||
@ -1759,7 +1759,7 @@ msgstr "המשתמש בחר להתעלם מתיבת דו־שיח האימות"
|
||||
#~ msgid "GNOME Shell (wayland compositor)"
|
||||
#~ msgstr "GNOME Shell (מסדר wayland)"
|
||||
|
||||
|
||||
# javascript-format
|
||||
#~ msgid "%d Connected Device"
|
||||
#~ msgid_plural "%d Connected Devices"
|
||||
#~ msgstr[0] "התקן אחד מחובר"
|
||||
@ -2319,33 +2319,9 @@ msgstr "המשתמש בחר להתעלם מתיבת דו־שיח האימות"
|
||||
#~ msgid "Networking is disabled"
|
||||
#~ msgstr "תכונת הרשת מנוטרלת"
|
||||
|
||||
|
||||
#~ msgid "%d hour remaining"
|
||||
#~ msgid_plural "%d hours remaining"
|
||||
#~ msgstr[0] "נותרה שעה"
|
||||
#~ msgstr[1] "נותרו %d שעות"
|
||||
#~ msgstr[2] "נותרו שעתיים"
|
||||
#~ msgid "%d %s %d %s remaining"
|
||||
#~ msgstr "%d %s %d %s נותרו"
|
||||
|
||||
|
||||
#~ msgid "hour"
|
||||
#~ msgid_plural "hours"
|
||||
#~ msgstr[0] "שעה"
|
||||
#~ msgstr[1] "שעות"
|
||||
#~ msgstr[2] "שעתיים"
|
||||
|
||||
#~ msgid "minute"
|
||||
#~ msgid_plural "minutes"
|
||||
#~ msgstr[0] "דקה"
|
||||
#~ msgstr[1] "דקות"
|
||||
#~ msgstr[2] "דקות"
|
||||
|
||||
#~ msgid "%d minute remaining"
|
||||
#~ msgid_plural "%d minutes remaining"
|
||||
#~ msgstr[0] "דקה אחת נותרה"
|
||||
#~ msgstr[1] "%d דקות נותרו"
|
||||
#~ msgstr[2] "שתי דקות נותרו"
|
||||
#~ msgid "AC Adapter"
|
||||
#~ msgstr "מתאם חשמל"
|
||||
|
||||
@ -2611,30 +2587,6 @@ msgstr "המשתמש בחר להתעלם מתיבת דו־שיח האימות"
|
||||
#~ msgid "Less than a minute ago"
|
||||
#~ msgstr "לפני פחות מדקה"
|
||||
|
||||
|
||||
#~ msgid "%d minute ago"
|
||||
#~ msgid_plural "%d minutes ago"
|
||||
#~ msgstr[0] "לפני דקה"
|
||||
#~ msgstr[1] "לפני %d דקות"
|
||||
#~ msgstr[2] "לפני 2 דקות"
|
||||
|
||||
#~ msgid "%d hour ago"
|
||||
#~ msgid_plural "%d hours ago"
|
||||
#~ msgstr[0] "לפני שעה"
|
||||
#~ msgstr[1] "לפני %d שעות"
|
||||
#~ msgstr[2] "לפני שעתיים"
|
||||
|
||||
#~ msgid "%d day ago"
|
||||
#~ msgid_plural "%d days ago"
|
||||
#~ msgstr[0] "לפני יום"
|
||||
#~ msgstr[1] "לפני %d ימים"
|
||||
#~ msgstr[2] "לפני יומיים"
|
||||
|
||||
#~ msgid "%d week ago"
|
||||
#~ msgid_plural "%d weeks ago"
|
||||
#~ msgstr[0] "לפני שבוע"
|
||||
#~ msgstr[1] "לפני %d שבועות"
|
||||
#~ msgstr[2] "לפני שבועיים"
|
||||
#~ msgid "Shut Down"
|
||||
#~ msgstr "כיבוי"
|
||||
|
||||
|
4
po/pt.po
4
po/pt.po
@ -301,7 +301,7 @@ msgstr "Sessão na rede"
|
||||
#. 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 "Grupo de Trabalho na Rede"
|
||||
msgstr "network-workgroup"
|
||||
|
||||
#: js/extensionPrefs/main.js:117
|
||||
#, javascript-format
|
||||
@ -1685,7 +1685,7 @@ msgstr "Calendário do Evolution"
|
||||
#. Translators: Do NOT translate or transliterate this text (this is an icon file name)!
|
||||
#: src/calendar-server/evolution-calendar.desktop.in:6
|
||||
msgid "evolution"
|
||||
msgstr "Evolution"
|
||||
msgstr "evolution"
|
||||
|
||||
#. translators:
|
||||
#. * The number of sound outputs on a particular device
|
||||
|
712
po/pt_BR.po
712
po/pt_BR.po
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user