Compare commits
264 Commits
Author | SHA1 | Date | |
---|---|---|---|
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 | |||
e581e249ad | |||
c131c44ef6 | |||
cdd23d9cc7 | |||
dc110db4e0 | |||
678670bf1b | |||
07fc15a1eb | |||
83005e27da | |||
56b20ef779 | |||
04adeec8f5 | |||
62d640cd9e | |||
9d7ad6748c | |||
accd24e379 | |||
75d797a0ac | |||
e1e321d3a7 | |||
f14f238150 | |||
ab3200019a | |||
28c028f7ac | |||
08a159d0d8 | |||
26aa32c6cc | |||
09e6bb5d56 | |||
e661d904de | |||
407d51e871 | |||
c4a07fad83 | |||
9ea8fdc1d1 | |||
3d6bf43649 | |||
7bc1d57ad7 | |||
68b671a4f4 | |||
1de1fd44c5 | |||
e5101eb407 | |||
48e0d86340 | |||
c64cf30160 | |||
ff9d777c01 | |||
d8c33deb33 | |||
c03ff0bd4f | |||
d597633d8f | |||
4f6eb49be3 | |||
d23bd4c4a6 | |||
7f12265685 | |||
250023b823 | |||
3b52691ab4 | |||
b6cd548186 | |||
b3fabf11b1 | |||
15be562fdf | |||
599fa0b76c | |||
c520eb4de0 | |||
e33c68a415 | |||
97bd224261 | |||
503e086c56 | |||
7dd6b7f04f | |||
0b05b7a527 | |||
7e5274619a | |||
900957d658 | |||
e006b9b400 | |||
d042dd73aa | |||
347972e45f | |||
7e803fdf23 | |||
ccacb5f6de | |||
5117139add | |||
d5c0514e21 | |||
d81a6bdf41 | |||
2812afed22 | |||
f5bd86fa11 | |||
b625f1692c | |||
36ac1f8902 | |||
bec4b5c127 | |||
78cd8b9f9a | |||
205880e74e | |||
009d021e4f | |||
39a840e2c3 | |||
56d0d7253b | |||
7a29cc47d4 | |||
d769b72c43 | |||
a3439a5230 | |||
9f45161133 | |||
ed99bef458 | |||
c9ad54cd82 | |||
d7e42d5d6e | |||
5b339c8371 | |||
9c6e68f3e7 | |||
70526a8025 | |||
c405081d89 | |||
384e01b368 | |||
f819654ec8 | |||
4670db6629 |
144
NEWS
144
NEWS
@ -1,3 +1,147 @@
|
|||||||
|
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]
|
||||||
|
* Prepare for mozjs31 GJS [Philip; #775374]
|
||||||
|
* Misc. bug fixes [Niels, Jonas; #775507, #776130]
|
||||||
|
|
||||||
|
Contributors:
|
||||||
|
Jonas Ådahl, Michael Catanzaro, Philip Chimento, Niels De Graef,
|
||||||
|
Carlos Garnacho, Florian Müllner
|
||||||
|
|
||||||
|
Translations:
|
||||||
|
Muhammet Kara [tr], Christian Kirbach [de], Baurzhan Muftakhidinov [kk],
|
||||||
|
Cheng-Chia Tseng [zh_TW], A S Alam [pa], Gianvito Cavasoli [it]
|
||||||
|
|
||||||
|
3.23.2
|
||||||
|
======
|
||||||
|
* Implement Pad configuration OSD [Carlos; #771067]
|
||||||
|
* Show overview on three-finger touchpad pinch [Carlos; #765937]
|
||||||
|
* Summarize network sections with too many devices [Florian; #773892]
|
||||||
|
* Always show primary network icon when connected [Florian; #773890]
|
||||||
|
* Fix fullscreen transitions on wayland [Rui; #770345]
|
||||||
|
* Work around portal failures by using a URL without HTPPS redirect [Debarshi; #769940]
|
||||||
|
* Fix app view hiding when no usage data is available [Florian, Xiaoguang; #774381]
|
||||||
|
* Misc. bug fixes [Florian, Ray; #773875, #740043, #773893, #774643, #774805]
|
||||||
|
|
||||||
|
Contributors:
|
||||||
|
Carlos Garnacho, Rui Matos, Florian Müllner, Debarshi Ray, Ray Strode,
|
||||||
|
Xiaoguang Wang
|
||||||
|
|
||||||
|
Translations:
|
||||||
|
Balázs Meskó [hu], Fabio Tomat [fur], Marek Cernocky [cs], Stas Solovey [ru],
|
||||||
|
Daniel Mustieles [es], Marek Černocký [cs], Piotr Drąg [pl],
|
||||||
|
Rafael Fontenelle [pt_BR], Baurzhan Muftakhidinov [kk], Jiri Grönroos [fi],
|
||||||
|
Kjartan Maraas [nb]
|
||||||
|
|
||||||
|
3.23.1
|
||||||
|
======
|
||||||
|
* Request periodic scans while WiFi list is open [Dan; #767918]
|
||||||
|
* Include extension UUID in structured log metadata [Jonh; #770717]
|
||||||
|
* Line-wrap PAM messages on login screen [Tao; #764445]
|
||||||
|
* Add a way to launch an app on the discrete GPU [Bastien; #773117]
|
||||||
|
* Only allow graphs to lift screen shield when locked [Florian; #773328]
|
||||||
|
* Add reload option to gnome-shell-extension-tool [Jonh; #772593]
|
||||||
|
* Update background animations when resuming from suspend [Florian; #773265]
|
||||||
|
* Misc. bug fixes [Cosimo, Bastien, Florian, Philip, Carlos; #772723, #772287,
|
||||||
|
#756432, #772386, #772386, #773085, #773634]
|
||||||
|
|
||||||
|
Contributors:
|
||||||
|
Cosimo Cecchi, Philip Chimento, Carlos Garcia Campos, Florian Müllner,
|
||||||
|
Bastien Nocera, Jonh Wendell, Dan Williams, Tao Yang
|
||||||
|
|
||||||
|
Translations:
|
||||||
|
Fabio Tomat [fur], Philip Chimento [zh_CN], YunQiang Su [zh_CN],
|
||||||
|
Jordi Mas [ca], Piotr Drąg [pl], Muhammet Kara [tr], Marek Černocký [cs],
|
||||||
|
Daniel Korostil [uk], Dušan Kazik [sk]
|
||||||
|
|
||||||
3.22.1
|
3.22.1
|
||||||
======
|
======
|
||||||
* Fix hidden network indicator on startup [Florian; #772249]
|
* Fix hidden network indicator on startup [Florian; #772249]
|
||||||
|
22
autogen.sh
22
autogen.sh
@ -4,8 +4,10 @@
|
|||||||
srcdir=`dirname $0`
|
srcdir=`dirname $0`
|
||||||
test -z "$srcdir" && srcdir=.
|
test -z "$srcdir" && srcdir=.
|
||||||
|
|
||||||
(test -f $srcdir/configure.ac \
|
pushd $srcdir
|
||||||
&& test -d $srcdir/src) || {
|
|
||||||
|
(test -f configure.ac \
|
||||||
|
&& test -d src) || {
|
||||||
echo -n "**Error**: Directory "\`$srcdir\'" does not look like the"
|
echo -n "**Error**: Directory "\`$srcdir\'" does not look like the"
|
||||||
echo " top-level gnome-shell directory"
|
echo " top-level gnome-shell directory"
|
||||||
exit 1
|
exit 1
|
||||||
@ -19,9 +21,13 @@ then
|
|||||||
fi
|
fi
|
||||||
git submodule update
|
git submodule update
|
||||||
|
|
||||||
which gnome-autogen.sh || {
|
aclocal --install || exit 1
|
||||||
echo "You need to install gnome-common from GNOME Git (or from"
|
gtkdocize --copy || exit 1
|
||||||
echo "your OS vendor's package manager)."
|
intltoolize --force --copy --automake || exit 1
|
||||||
exit 1
|
autoreconf --verbose --force --install || exit 1
|
||||||
}
|
|
||||||
. gnome-autogen.sh
|
popd
|
||||||
|
|
||||||
|
if [ "$NOCONFIGURE" = "" ]; then
|
||||||
|
$srcdir/configure "$@" || exit 1
|
||||||
|
fi
|
||||||
|
@ -1029,6 +1029,7 @@ NPP_GetValue(NPP instance,
|
|||||||
if (!instance->pdata)
|
if (!instance->pdata)
|
||||||
return NPERR_INVALID_INSTANCE_ERROR;
|
return NPERR_INVALID_INSTANCE_ERROR;
|
||||||
|
|
||||||
|
funcs.retainobject (instance->pdata);
|
||||||
*(NPObject**)value = instance->pdata;
|
*(NPObject**)value = instance->pdata;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
41
configure.ac
41
configure.ac
@ -1,5 +1,5 @@
|
|||||||
AC_PREREQ(2.63)
|
AC_PREREQ(2.63)
|
||||||
AC_INIT([gnome-shell],[3.22.1],[https://bugzilla.gnome.org/enter_bug.cgi?product=gnome-shell],[gnome-shell])
|
AC_INIT([gnome-shell],[3.24.0],[https://bugzilla.gnome.org/enter_bug.cgi?product=gnome-shell],[gnome-shell])
|
||||||
AX_IS_RELEASE([git-directory])
|
AX_IS_RELEASE([git-directory])
|
||||||
|
|
||||||
AC_CONFIG_HEADERS([config.h])
|
AC_CONFIG_HEADERS([config.h])
|
||||||
@ -17,7 +17,6 @@ m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])])
|
|||||||
|
|
||||||
# Checks for programs.
|
# Checks for programs.
|
||||||
AC_PROG_CC
|
AC_PROG_CC
|
||||||
AC_PROG_CXX
|
|
||||||
|
|
||||||
# Initialize libtool
|
# Initialize libtool
|
||||||
LT_PREREQ([2.2.6])
|
LT_PREREQ([2.2.6])
|
||||||
@ -42,6 +41,15 @@ GLIB_GSETTINGS
|
|||||||
AM_PATH_PYTHON([3])
|
AM_PATH_PYTHON([3])
|
||||||
AC_SUBST(PYTHON)
|
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
|
# 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.
|
# in 0.10.16, but nothing older than 0.10.21 has been tested.
|
||||||
GSTREAMER_MIN_VERSION=0.11.92
|
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)
|
AC_MSG_RESULT(yes)
|
||||||
build_recorder=true
|
build_recorder=true
|
||||||
recorder_modules="gstreamer-1.0 gstreamer-base-1.0 x11 gtk+-3.0"
|
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
|
else
|
||||||
AC_MSG_RESULT(no)
|
AC_MSG_RESULT(no)
|
||||||
fi
|
fi
|
||||||
@ -75,15 +83,13 @@ AS_IF([test x$enable_systemd != xno], [
|
|||||||
|
|
||||||
AC_MSG_RESULT($enable_systemd)
|
AC_MSG_RESULT($enable_systemd)
|
||||||
|
|
||||||
CLUTTER_MIN_VERSION=1.21.5
|
|
||||||
GOBJECT_INTROSPECTION_MIN_VERSION=1.49.1
|
GOBJECT_INTROSPECTION_MIN_VERSION=1.49.1
|
||||||
GJS_MIN_VERSION=1.39.0
|
GJS_MIN_VERSION=1.47.0
|
||||||
MUTTER_MIN_VERSION=3.22.1
|
MUTTER_MIN_VERSION=3.24.0
|
||||||
GTK_MIN_VERSION=3.15.0
|
GTK_MIN_VERSION=3.15.0
|
||||||
GIO_MIN_VERSION=2.45.3
|
GIO_MIN_VERSION=2.45.3
|
||||||
LIBECAL_MIN_VERSION=3.5.3
|
LIBECAL_MIN_VERSION=3.5.3
|
||||||
LIBEDATASERVER_MIN_VERSION=3.17.2
|
LIBEDATASERVER_MIN_VERSION=3.17.2
|
||||||
TELEPATHY_GLIB_MIN_VERSION=0.17.5
|
|
||||||
POLKIT_MIN_VERSION=0.100
|
POLKIT_MIN_VERSION=0.100
|
||||||
STARTUP_NOTIFICATION_MIN_VERSION=0.11
|
STARTUP_NOTIFICATION_MIN_VERSION=0.11
|
||||||
GCR_MIN_VERSION=3.7.5
|
GCR_MIN_VERSION=3.7.5
|
||||||
@ -96,15 +102,14 @@ SHARED_PCS="gio-unix-2.0 >= $GIO_MIN_VERSION
|
|||||||
libxml-2.0
|
libxml-2.0
|
||||||
gtk+-3.0 >= $GTK_MIN_VERSION
|
gtk+-3.0 >= $GTK_MIN_VERSION
|
||||||
atk-bridge-2.0
|
atk-bridge-2.0
|
||||||
gjs-internals-1.0 >= $GJS_MIN_VERSION
|
gjs-1.0 >= $GJS_MIN_VERSION
|
||||||
$recorder_modules
|
$recorder_modules
|
||||||
gdk-x11-3.0 libsoup-2.4
|
gdk-x11-3.0 libsoup-2.4
|
||||||
mutter-clutter-1.0 >= $CLUTTER_MIN_VERSION
|
$LIBMUTTER_CLUTTER >= $MUTTER_MIN_VERSION
|
||||||
mutter-cogl-pango-1.0
|
$LIBMUTTER_COGL_PANGO
|
||||||
libstartup-notification-1.0 >= $STARTUP_NOTIFICATION_MIN_VERSION
|
libstartup-notification-1.0 >= $STARTUP_NOTIFICATION_MIN_VERSION
|
||||||
gobject-introspection-1.0 >= $GOBJECT_INTROSPECTION_MIN_VERSION
|
gobject-introspection-1.0 >= $GOBJECT_INTROSPECTION_MIN_VERSION
|
||||||
libcanberra libcanberra-gtk3
|
libcanberra libcanberra-gtk3
|
||||||
telepathy-glib >= $TELEPATHY_GLIB_MIN_VERSION
|
|
||||||
polkit-agent-1 >= $POLKIT_MIN_VERSION
|
polkit-agent-1 >= $POLKIT_MIN_VERSION
|
||||||
gcr-base-3 >= $GCR_MIN_VERSION"
|
gcr-base-3 >= $GCR_MIN_VERSION"
|
||||||
if test x$have_systemd = xyes; then
|
if test x$have_systemd = xyes; then
|
||||||
@ -112,16 +117,18 @@ if test x$have_systemd = xyes; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
PKG_CHECK_MODULES(GNOME_SHELL, $SHARED_PCS)
|
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-internals-1.0 >= $GJS_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_PERF_HELPER, gtk+-3.0 gio-2.0)
|
||||||
PKG_CHECK_MODULES(SHELL_HOTPLUG_SNIFFER, gio-2.0 gdk-pixbuf-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(GVC, libpulse >= $PULSE_MIN_VERS libpulse-mainloop-glib gobject-2.0)
|
||||||
PKG_CHECK_MODULES(DESKTOP_SCHEMAS, gsettings-desktop-schemas >= 3.21.3)
|
PKG_CHECK_MODULES(DESKTOP_SCHEMAS, gsettings-desktop-schemas >= 3.21.3)
|
||||||
|
|
||||||
|
AC_SUBST(LIBMUTTER_API_VERSION)
|
||||||
|
|
||||||
AC_ARG_ENABLE(browser-plugin,
|
AC_ARG_ENABLE(browser-plugin,
|
||||||
[AS_HELP_STRING([--enable-browser-plugin],
|
[AS_HELP_STRING([--enable-browser-plugin],
|
||||||
[Enable browser plugin [default=yes]])],,
|
[Enable browser plugin [default=yes]])],,
|
||||||
@ -146,10 +153,10 @@ AC_SUBST([GNOME_KEYBINDINGS_KEYSDIR])
|
|||||||
|
|
||||||
GOBJECT_INTROSPECTION_CHECK([$GOBJECT_INTROSPECTION_MIN_VERSION])
|
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)
|
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)
|
AC_SUBST(MUTTER_TYPELIB_DIR)
|
||||||
|
|
||||||
GJS_CONSOLE=`$PKG_CONFIG --variable=gjs_console gjs-1.0`
|
GJS_CONSOLE=`$PKG_CONFIG --variable=gjs_console gjs-1.0`
|
||||||
|
@ -38,6 +38,7 @@ endif
|
|||||||
|
|
||||||
introspectiondir = $(datadir)/dbus-1/interfaces
|
introspectiondir = $(datadir)/dbus-1/interfaces
|
||||||
introspection_DATA = \
|
introspection_DATA = \
|
||||||
|
org.gnome.Shell.PadOsd.xml \
|
||||||
org.gnome.Shell.Screencast.xml \
|
org.gnome.Shell.Screencast.xml \
|
||||||
org.gnome.Shell.Screenshot.xml \
|
org.gnome.Shell.Screenshot.xml \
|
||||||
org.gnome.ShellSearchProvider.xml \
|
org.gnome.ShellSearchProvider.xml \
|
||||||
@ -63,6 +64,7 @@ dist_theme_files = \
|
|||||||
theme/gnome-shell-sass/NEWS \
|
theme/gnome-shell-sass/NEWS \
|
||||||
theme/gnome-shell-sass/README \
|
theme/gnome-shell-sass/README \
|
||||||
theme/gnome-shell-sass/gnome-shell-sass.doap \
|
theme/gnome-shell-sass/gnome-shell-sass.doap \
|
||||||
|
theme/pad-osd.css \
|
||||||
theme/parse-sass.sh \
|
theme/parse-sass.sh \
|
||||||
$(NULL)
|
$(NULL)
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
[Desktop Entry]
|
[Desktop Entry]
|
||||||
Type=Application
|
Type=Application
|
||||||
Name=GNOME Shell Extension Preferences
|
Name=Shell Extensions
|
||||||
Comment=Configure GNOME Shell Extensions
|
Comment=Configure GNOME Shell Extensions
|
||||||
Exec=@bindir@/gnome-shell-extension-prefs %u
|
Exec=@bindir@/gnome-shell-extension-prefs %u
|
||||||
X-GNOME-Bugzilla-Bugzilla=GNOME
|
X-GNOME-Bugzilla-Bugzilla=GNOME
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
<file>no-events.svg</file>
|
<file>no-events.svg</file>
|
||||||
<file>no-notifications.svg</file>
|
<file>no-notifications.svg</file>
|
||||||
<file>noise-texture.png</file>
|
<file>noise-texture.png</file>
|
||||||
|
<file>pad-osd.css</file>
|
||||||
<file>page-indicator-active.svg</file>
|
<file>page-indicator-active.svg</file>
|
||||||
<file>page-indicator-inactive.svg</file>
|
<file>page-indicator-inactive.svg</file>
|
||||||
<file>page-indicator-checked.svg</file>
|
<file>page-indicator-checked.svg</file>
|
||||||
|
28
data/org.gnome.Shell.PadOsd.xml
Normal file
28
data/org.gnome.Shell.PadOsd.xml
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
<!DOCTYPE node PUBLIC
|
||||||
|
'-//freedesktop//DTD D-BUS Object Introspection 1.0//EN'
|
||||||
|
'http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd'>
|
||||||
|
<node>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
org.gnome.Shell.PadOSD:
|
||||||
|
@short_description: Pad OSD interface
|
||||||
|
|
||||||
|
The interface used to show button map OSD on pad devices.
|
||||||
|
-->
|
||||||
|
<interface name='org.gnome.Shell.Wacom.PadOsd'>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Show:
|
||||||
|
@device_node: device node file, usually in /dev/input/...
|
||||||
|
@edition_mode: whether toggling edition mode on when showing
|
||||||
|
|
||||||
|
Shows the pad button map OSD for the requested device, the OSD
|
||||||
|
will be shown according the current device settings (output
|
||||||
|
mapping, left handed mode, ...)
|
||||||
|
-->
|
||||||
|
<method name='Show'>
|
||||||
|
<arg name='device_node' direction='in' type='o'/>
|
||||||
|
<arg name='edition_mode' direction='in' type='b'/>
|
||||||
|
</method>
|
||||||
|
</interface>
|
||||||
|
</node>
|
@ -21,6 +21,14 @@
|
|||||||
EnableExtension and DisableExtension D-Bus methods on org.gnome.Shell.
|
EnableExtension and DisableExtension D-Bus methods on org.gnome.Shell.
|
||||||
</description>
|
</description>
|
||||||
</key>
|
</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">
|
<key name="disable-extension-version-validation" type="b">
|
||||||
<default>true</default>
|
<default>true</default>
|
||||||
<summary>Disables the validation of extension version compatibility</summary>
|
<summary>Disables the validation of extension version compatibility</summary>
|
||||||
@ -56,9 +64,9 @@
|
|||||||
</key>
|
</key>
|
||||||
<key name="always-show-log-out" type="b">
|
<key name="always-show-log-out" type="b">
|
||||||
<default>false</default>
|
<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>
|
<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.
|
menu item in single-user, single-session situations.
|
||||||
</description>
|
</description>
|
||||||
</key>
|
</key>
|
||||||
@ -68,7 +76,7 @@
|
|||||||
<description>
|
<description>
|
||||||
The shell will request a password when an encrypted device or a
|
The shell will request a password when an encrypted device or a
|
||||||
remote filesystem is mounted. If the password can be saved for
|
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.
|
This key sets the default state of the checkbox.
|
||||||
</description>
|
</description>
|
||||||
</key>
|
</key>
|
||||||
@ -97,9 +105,9 @@
|
|||||||
</key>
|
</key>
|
||||||
<key name="toggle-application-view" type="as">
|
<key name="toggle-application-view" type="as">
|
||||||
<default>["<Super>a"]</default>
|
<default>["<Super>a"]</default>
|
||||||
<summary>Keybinding to open the "Show Applications" view</summary>
|
<summary>Keybinding to open the “Show Applications” view</summary>
|
||||||
<description>
|
<description>
|
||||||
Keybinding to open the "Show Applications" view of the Activities
|
Keybinding to open the “Show Applications” view of the Activities
|
||||||
Overview.
|
Overview.
|
||||||
</description>
|
</description>
|
||||||
</key>
|
</key>
|
||||||
@ -168,8 +176,8 @@
|
|||||||
<summary>The application icon mode.</summary>
|
<summary>The application icon mode.</summary>
|
||||||
<description>
|
<description>
|
||||||
Configures how the windows are shown in the switcher. Valid possibilities
|
Configures how the windows are shown in the switcher. Valid possibilities
|
||||||
are 'thumbnail-only' (shows a thumbnail of the window), 'app-icon-only'
|
are “thumbnail-only” (shows a thumbnail of the window), “app-icon-only”
|
||||||
(shows only the application icon) or 'both'.
|
(shows only the application icon) or “both”.
|
||||||
</description>
|
</description>
|
||||||
</key>
|
</key>
|
||||||
<key type="b" name="current-workspace-only">
|
<key type="b" name="current-workspace-only">
|
||||||
|
@ -562,6 +562,18 @@ StScrollBar {
|
|||||||
background-color: #eeeeec;
|
background-color: #eeeeec;
|
||||||
border-radius: 0.3em; }
|
border-radius: 0.3em; }
|
||||||
|
|
||||||
|
/* Pad OSD */
|
||||||
|
.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; }
|
||||||
|
|
||||||
/* App Switcher */
|
/* App Switcher */
|
||||||
.switcher-popup {
|
.switcher-popup {
|
||||||
padding: 8px;
|
padding: 8px;
|
||||||
@ -726,9 +738,20 @@ StScrollBar {
|
|||||||
.datemenu-displays-section {
|
.datemenu-displays-section {
|
||||||
padding-bottom: 3em; }
|
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,
|
.datemenu-today-button,
|
||||||
.world-clocks-button,
|
.world-clocks-button,
|
||||||
.message-list-section-title {
|
.weather-button,
|
||||||
|
.events-section-title {
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
padding: .4em; }
|
padding: .4em; }
|
||||||
|
|
||||||
@ -741,12 +764,15 @@ StScrollBar {
|
|||||||
.datemenu-today-button:hover, .datemenu-today-button:focus,
|
.datemenu-today-button:hover, .datemenu-today-button:focus,
|
||||||
.world-clocks-button:hover,
|
.world-clocks-button:hover,
|
||||||
.world-clocks-button:focus,
|
.world-clocks-button:focus,
|
||||||
.message-list-section-title:hover,
|
.weather-button:hover,
|
||||||
.message-list-section-title:focus {
|
.weather-button:focus,
|
||||||
|
.events-section-title:hover,
|
||||||
|
.events-section-title:focus {
|
||||||
background-color: #0d0d0d; }
|
background-color: #0d0d0d; }
|
||||||
.datemenu-today-button:active,
|
.datemenu-today-button:active,
|
||||||
.world-clocks-button:active,
|
.world-clocks-button:active,
|
||||||
.message-list-section-title:active {
|
.weather-button:active,
|
||||||
|
.events-section-title:active {
|
||||||
color: white;
|
color: white;
|
||||||
background-color: #215d9c; }
|
background-color: #215d9c; }
|
||||||
|
|
||||||
@ -754,13 +780,17 @@ StScrollBar {
|
|||||||
font-size: 1.5em; }
|
font-size: 1.5em; }
|
||||||
|
|
||||||
.world-clocks-header,
|
.world-clocks-header,
|
||||||
.message-list-section-title {
|
.weather-header,
|
||||||
|
.events-section-title {
|
||||||
color: #999999;
|
color: #999999;
|
||||||
font-weight: bold; }
|
font-weight: bold; }
|
||||||
|
|
||||||
.world-clocks-grid {
|
.world-clocks-grid {
|
||||||
spacing-rows: 0.4em; }
|
spacing-rows: 0.4em; }
|
||||||
|
|
||||||
|
.weather-box {
|
||||||
|
spacing: 0.4em; }
|
||||||
|
|
||||||
.calendar-month-label {
|
.calendar-month-label {
|
||||||
color: #f2f2f2;
|
color: #f2f2f2;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
@ -845,69 +875,68 @@ StScrollBar {
|
|||||||
.message-list {
|
.message-list {
|
||||||
width: 31.5em; }
|
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 {
|
.message-list-sections {
|
||||||
spacing: 1.5em; }
|
spacing: 1em; }
|
||||||
|
|
||||||
.message-list-section,
|
.message-list-section,
|
||||||
.message-list-section-list {
|
.message-list-section-list {
|
||||||
spacing: 0.7em; }
|
|
||||||
|
|
||||||
.message-list-section-title-box {
|
|
||||||
spacing: 0.4em; }
|
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 {
|
.message {
|
||||||
background-color: #0d0d0d;
|
|
||||||
border-radius: 3px; }
|
border-radius: 3px; }
|
||||||
.message:hover, .message:focus {
|
.message:hover, .message:focus {
|
||||||
background-color: #262626; }
|
background-color: #0d0d0d; }
|
||||||
|
|
||||||
.message-icon-bin {
|
.message-icon-bin {
|
||||||
padding: 8px 0px 8px 8px; }
|
padding: 10px 3px 10px 10px; }
|
||||||
.message-icon-bin:rtl {
|
.message-icon-bin:rtl {
|
||||||
padding: 8px 8px 8px 0px; }
|
padding: 10px 10px 10px 3px; }
|
||||||
|
|
||||||
.message-icon-bin > StIcon {
|
.message-icon-bin > StIcon {
|
||||||
icon-size: 32px; }
|
color: #cccccc;
|
||||||
|
icon-size: 16px;
|
||||||
.message-secondary-bin:ltr {
|
-st-icon-style: symbolic; }
|
||||||
padding-left: 8px; }
|
|
||||||
.message-secondary-bin:rtl {
|
|
||||||
padding-right: 8px; }
|
|
||||||
|
|
||||||
.message-secondary-bin {
|
.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 {
|
.message-secondary-bin > StIcon {
|
||||||
icon-size: 16px; }
|
icon-size: 16px; }
|
||||||
|
|
||||||
.message-title {
|
.message-title {
|
||||||
font-weight: bold;
|
color: #f2f2f2; }
|
||||||
font-size: 1.1em; }
|
|
||||||
|
|
||||||
.message-content {
|
.message-content {
|
||||||
padding: 8px;
|
color: #cccccc;
|
||||||
font-size: .9em; }
|
padding: 10px; }
|
||||||
|
|
||||||
.message-media-control {
|
.message-media-control {
|
||||||
padding: 6px; }
|
padding: 12px;
|
||||||
|
color: #cccccc; }
|
||||||
.message-media-control:last-child:ltr {
|
.message-media-control:last-child:ltr {
|
||||||
padding-right: 18px; }
|
padding-right: 18px; }
|
||||||
.message-media-control:last-child:rtl {
|
.message-media-control:last-child:rtl {
|
||||||
padding-left: 18px; }
|
padding-left: 18px; }
|
||||||
|
.message-media-control:hover {
|
||||||
|
color: #fff; }
|
||||||
|
.message-media-control:insensitive {
|
||||||
|
color: #999999; }
|
||||||
|
|
||||||
.media-message-cover-icon {
|
.media-message-cover-icon {
|
||||||
icon-size: 32px; }
|
icon-size: 48px !important; }
|
||||||
.media-message-cover-icon.fallback {
|
.media-message-cover-icon.fallback {
|
||||||
color: #1a1a1a;
|
color: #1a1a1a;
|
||||||
background-color: #000;
|
background-color: #000;
|
||||||
|
Submodule data/theme/gnome-shell-sass updated: b2190083c2...e94bce1fcf
@ -562,6 +562,18 @@ StScrollBar {
|
|||||||
background-color: #eeeeec;
|
background-color: #eeeeec;
|
||||||
border-radius: 0.3em; }
|
border-radius: 0.3em; }
|
||||||
|
|
||||||
|
/* Pad OSD */
|
||||||
|
.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; }
|
||||||
|
|
||||||
/* App Switcher */
|
/* App Switcher */
|
||||||
.switcher-popup {
|
.switcher-popup {
|
||||||
padding: 8px;
|
padding: 8px;
|
||||||
@ -726,9 +738,20 @@ StScrollBar {
|
|||||||
.datemenu-displays-section {
|
.datemenu-displays-section {
|
||||||
padding-bottom: 3em; }
|
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,
|
.datemenu-today-button,
|
||||||
.world-clocks-button,
|
.world-clocks-button,
|
||||||
.message-list-section-title {
|
.weather-button,
|
||||||
|
.events-section-title {
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
padding: .4em; }
|
padding: .4em; }
|
||||||
|
|
||||||
@ -741,12 +764,15 @@ StScrollBar {
|
|||||||
.datemenu-today-button:hover, .datemenu-today-button:focus,
|
.datemenu-today-button:hover, .datemenu-today-button:focus,
|
||||||
.world-clocks-button:hover,
|
.world-clocks-button:hover,
|
||||||
.world-clocks-button:focus,
|
.world-clocks-button:focus,
|
||||||
.message-list-section-title:hover,
|
.weather-button:hover,
|
||||||
.message-list-section-title:focus {
|
.weather-button:focus,
|
||||||
|
.events-section-title:hover,
|
||||||
|
.events-section-title:focus {
|
||||||
background-color: #454c4c; }
|
background-color: #454c4c; }
|
||||||
.datemenu-today-button:active,
|
.datemenu-today-button:active,
|
||||||
.world-clocks-button:active,
|
.world-clocks-button:active,
|
||||||
.message-list-section-title:active {
|
.weather-button:active,
|
||||||
|
.events-section-title:active {
|
||||||
color: white;
|
color: white;
|
||||||
background-color: #215d9c; }
|
background-color: #215d9c; }
|
||||||
|
|
||||||
@ -754,13 +780,17 @@ StScrollBar {
|
|||||||
font-size: 1.5em; }
|
font-size: 1.5em; }
|
||||||
|
|
||||||
.world-clocks-header,
|
.world-clocks-header,
|
||||||
.message-list-section-title {
|
.weather-header,
|
||||||
|
.events-section-title {
|
||||||
color: #8e8e80;
|
color: #8e8e80;
|
||||||
font-weight: bold; }
|
font-weight: bold; }
|
||||||
|
|
||||||
.world-clocks-grid {
|
.world-clocks-grid {
|
||||||
spacing-rows: 0.4em; }
|
spacing-rows: 0.4em; }
|
||||||
|
|
||||||
|
.weather-box {
|
||||||
|
spacing: 0.4em; }
|
||||||
|
|
||||||
.calendar-month-label {
|
.calendar-month-label {
|
||||||
color: #e2e2df;
|
color: #e2e2df;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
@ -845,69 +875,68 @@ StScrollBar {
|
|||||||
.message-list {
|
.message-list {
|
||||||
width: 31.5em; }
|
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 {
|
.message-list-sections {
|
||||||
spacing: 1.5em; }
|
spacing: 1em; }
|
||||||
|
|
||||||
.message-list-section,
|
.message-list-section,
|
||||||
.message-list-section-list {
|
.message-list-section-list {
|
||||||
spacing: 0.7em; }
|
|
||||||
|
|
||||||
.message-list-section-title-box {
|
|
||||||
spacing: 0.4em; }
|
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 {
|
.message {
|
||||||
background-color: #454c4c;
|
|
||||||
border-radius: 3px; }
|
border-radius: 3px; }
|
||||||
.message:hover, .message:focus {
|
.message:hover, .message:focus {
|
||||||
background-color: #5d6767; }
|
background-color: #454c4c; }
|
||||||
|
|
||||||
.message-icon-bin {
|
.message-icon-bin {
|
||||||
padding: 8px 0px 8px 8px; }
|
padding: 10px 3px 10px 10px; }
|
||||||
.message-icon-bin:rtl {
|
.message-icon-bin:rtl {
|
||||||
padding: 8px 8px 8px 0px; }
|
padding: 10px 10px 10px 3px; }
|
||||||
|
|
||||||
.message-icon-bin > StIcon {
|
.message-icon-bin > StIcon {
|
||||||
icon-size: 32px; }
|
color: #bebeb6;
|
||||||
|
icon-size: 16px;
|
||||||
.message-secondary-bin:ltr {
|
-st-icon-style: symbolic; }
|
||||||
padding-left: 8px; }
|
|
||||||
.message-secondary-bin:rtl {
|
|
||||||
padding-right: 8px; }
|
|
||||||
|
|
||||||
.message-secondary-bin {
|
.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 {
|
.message-secondary-bin > StIcon {
|
||||||
icon-size: 16px; }
|
icon-size: 16px; }
|
||||||
|
|
||||||
.message-title {
|
.message-title {
|
||||||
font-weight: bold;
|
color: #e2e2df; }
|
||||||
font-size: 1.1em; }
|
|
||||||
|
|
||||||
.message-content {
|
.message-content {
|
||||||
padding: 8px;
|
color: #bebeb6;
|
||||||
font-size: .9em; }
|
padding: 10px; }
|
||||||
|
|
||||||
.message-media-control {
|
.message-media-control {
|
||||||
padding: 6px; }
|
padding: 12px;
|
||||||
|
color: #bebeb6; }
|
||||||
.message-media-control:last-child:ltr {
|
.message-media-control:last-child:ltr {
|
||||||
padding-right: 18px; }
|
padding-right: 18px; }
|
||||||
.message-media-control:last-child:rtl {
|
.message-media-control:last-child:rtl {
|
||||||
padding-left: 18px; }
|
padding-left: 18px; }
|
||||||
|
.message-media-control:hover {
|
||||||
|
color: #eeeeec; }
|
||||||
|
.message-media-control:insensitive {
|
||||||
|
color: #8e8e80; }
|
||||||
|
|
||||||
.media-message-cover-icon {
|
.media-message-cover-icon {
|
||||||
icon-size: 32px; }
|
icon-size: 48px !important; }
|
||||||
.media-message-cover-icon.fallback {
|
.media-message-cover-icon.fallback {
|
||||||
color: #515a5a;
|
color: #515a5a;
|
||||||
background-color: #393f3f;
|
background-color: #393f3f;
|
||||||
|
30
data/theme/pad-osd.css
Normal file
30
data/theme/pad-osd.css
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
.Leader {
|
||||||
|
stroke-width: .5 !important;
|
||||||
|
stroke: #535353;
|
||||||
|
fill: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Button {
|
||||||
|
stroke-width: .25;
|
||||||
|
stroke: #ededed;
|
||||||
|
fill: #ededed;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Ring {
|
||||||
|
stroke-width: .5 !important;
|
||||||
|
stroke: #535353 !important;
|
||||||
|
fill: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Label {
|
||||||
|
stroke: none !important;
|
||||||
|
stroke-width: .1 !important;
|
||||||
|
font-size: .1 !important;
|
||||||
|
fill: transparent !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.TouchStrip, .TouchRing {
|
||||||
|
stroke-width: .1 !important;
|
||||||
|
stroke: #ededed !important;
|
||||||
|
fill: #535353 !important;
|
||||||
|
}
|
@ -50,7 +50,6 @@
|
|||||||
<xi:include href="xml/shell-util.xml"/>
|
<xi:include href="xml/shell-util.xml"/>
|
||||||
<xi:include href="xml/shell-mount-operation.xml"/>
|
<xi:include href="xml/shell-mount-operation.xml"/>
|
||||||
<xi:include href="xml/shell-polkit-authentication-agent.xml"/>
|
<xi:include href="xml/shell-polkit-authentication-agent.xml"/>
|
||||||
<xi:include href="xml/shell-tp-client.xml"/>
|
|
||||||
</chapter>
|
</chapter>
|
||||||
<chapter id="object-tree">
|
<chapter id="object-tree">
|
||||||
<title>Object Hierarchy</title>
|
<title>Object Hierarchy</title>
|
||||||
|
@ -11,6 +11,7 @@ misc/config.js: misc/config.js.in Makefile
|
|||||||
-e "s|[@]datadir@|$(datadir)|g" \
|
-e "s|[@]datadir@|$(datadir)|g" \
|
||||||
-e "s|[@]libexecdir@|$(libexecdir)|g" \
|
-e "s|[@]libexecdir@|$(libexecdir)|g" \
|
||||||
-e "s|[@]sysconfdir@|$(sysconfdir)|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)
|
js_resource_files = $(shell $(GLIB_COMPILE_RESOURCES) --sourcedir=$(srcdir) --sourcedir=$(builddir) --generate-dependencies $(srcdir)/js-resources.gresource.xml)
|
||||||
|
@ -143,17 +143,21 @@ const Application = new Lang.Class({
|
|||||||
this._window = new Gtk.ApplicationWindow({ application: app,
|
this._window = new Gtk.ApplicationWindow({ application: app,
|
||||||
window_position: Gtk.WindowPosition.CENTER });
|
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,
|
this._titlebar = new Gtk.HeaderBar({ show_close_button: true,
|
||||||
title: _("GNOME Shell Extensions") });
|
title: _("Shell Extensions") });
|
||||||
this._window.set_titlebar(this._titlebar);
|
this._window.set_titlebar(this._titlebar);
|
||||||
|
|
||||||
let scroll = new Gtk.ScrolledWindow({ hscrollbar_policy: Gtk.PolicyType.NEVER,
|
let killSwitch = new Gtk.Switch({ valign: Gtk.Align.CENTER });
|
||||||
shadow_type: Gtk.ShadowType.IN,
|
this._titlebar.pack_end(killSwitch);
|
||||||
halign: Gtk.Align.CENTER,
|
|
||||||
propagate_natural_width: true,
|
this._settings = new Gio.Settings({ schema_id: 'org.gnome.shell' });
|
||||||
margin: 18 });
|
this._settings.bind('disable-user-extensions', killSwitch, 'active',
|
||||||
|
Gio.SettingsBindFlags.BIND_DEFAULT |
|
||||||
|
Gio.SettingsBindFlags.INVERT_BOOLEAN);
|
||||||
|
|
||||||
|
let scroll = new Gtk.ScrolledWindow({ hscrollbar_policy: Gtk.PolicyType.NEVER });
|
||||||
this._window.add(scroll);
|
this._window.add(scroll);
|
||||||
|
|
||||||
this._extensionSelector = new Gtk.ListBox({ selection_mode: Gtk.SelectionMode.NONE });
|
this._extensionSelector = new Gtk.ListBox({ selection_mode: Gtk.SelectionMode.NONE });
|
||||||
@ -246,6 +250,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({
|
const ExtensionRow = new Lang.Class({
|
||||||
Name: 'ExtensionRow',
|
Name: 'ExtensionRow',
|
||||||
Extends: Gtk.ListBoxRow,
|
Extends: Gtk.ListBoxRow,
|
||||||
@ -264,6 +280,10 @@ const ExtensionRow = new Lang.Class({
|
|||||||
Lang.bind(this, function() {
|
Lang.bind(this, function() {
|
||||||
this._switch.sensitive = this._canEnable();
|
this._switch.sensitive = this._canEnable();
|
||||||
}));
|
}));
|
||||||
|
this._settings.connect('changed::disable-user-extensions',
|
||||||
|
Lang.bind(this, function() {
|
||||||
|
this._switch.sensitive = this._canEnable();
|
||||||
|
}));
|
||||||
|
|
||||||
this._buildUI();
|
this._buildUI();
|
||||||
},
|
},
|
||||||
@ -272,7 +292,8 @@ const ExtensionRow = new Lang.Class({
|
|||||||
let extension = ExtensionUtils.extensions[this.uuid];
|
let extension = ExtensionUtils.extensions[this.uuid];
|
||||||
|
|
||||||
let hbox = new Gtk.Box({ orientation: Gtk.Orientation.HORIZONTAL,
|
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);
|
this.add(hbox);
|
||||||
|
|
||||||
let vbox = new Gtk.Box({ orientation: Gtk.Orientation.VERTICAL,
|
let vbox = new Gtk.Box({ orientation: Gtk.Orientation.VERTICAL,
|
||||||
@ -286,9 +307,9 @@ const ExtensionRow = new Lang.Class({
|
|||||||
vbox.add(label);
|
vbox.add(label);
|
||||||
|
|
||||||
let desc = extension.metadata.description.split('\n')[0];
|
let desc = extension.metadata.description.split('\n')[0];
|
||||||
label = new Gtk.Label({ label: desc,
|
label = new DescriptionLabel({ label: desc, wrap: true, lines: 2,
|
||||||
ellipsize: Pango.EllipsizeMode.END,
|
ellipsize: Pango.EllipsizeMode.END,
|
||||||
halign: Gtk.Align.START });
|
xalign: 0, yalign: 0 });
|
||||||
vbox.add(label);
|
vbox.add(label);
|
||||||
|
|
||||||
let button = new Gtk.Button({ valign: Gtk.Align.CENTER,
|
let button = new Gtk.Button({ valign: Gtk.Align.CENTER,
|
||||||
@ -319,7 +340,8 @@ const ExtensionRow = new Lang.Class({
|
|||||||
let extension = ExtensionUtils.extensions[this.uuid];
|
let extension = ExtensionUtils.extensions[this.uuid];
|
||||||
let checkVersion = !this._settings.get_boolean('disable-extension-version-validation');
|
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() {
|
_isEnabled: function() {
|
||||||
|
@ -13,6 +13,7 @@ const Params = imports.misc.params;
|
|||||||
const ShellEntry = imports.ui.shellEntry;
|
const ShellEntry = imports.ui.shellEntry;
|
||||||
const Tweener = imports.ui.tweener;
|
const Tweener = imports.ui.tweener;
|
||||||
const UserWidget = imports.ui.userWidget;
|
const UserWidget = imports.ui.userWidget;
|
||||||
|
const Pango = imports.gi.Pango;
|
||||||
|
|
||||||
const DEFAULT_BUTTON_WELL_ICON_SIZE = 16;
|
const DEFAULT_BUTTON_WELL_ICON_SIZE = 16;
|
||||||
const DEFAULT_BUTTON_WELL_ANIMATION_DELAY = 1.0;
|
const DEFAULT_BUTTON_WELL_ANIMATION_DELAY = 1.0;
|
||||||
@ -113,6 +114,7 @@ const AuthPrompt = new Lang.Class({
|
|||||||
this._message = new St.Label({ opacity: 0,
|
this._message = new St.Label({ opacity: 0,
|
||||||
styleClass: 'login-dialog-message' });
|
styleClass: 'login-dialog-message' });
|
||||||
this._message.clutter_text.line_wrap = true;
|
this._message.clutter_text.line_wrap = true;
|
||||||
|
this._message.clutter_text.ellipsize = Pango.EllipsizeMode.NONE;
|
||||||
this.actor.add(this._message, { x_fill: false, x_align: St.Align.START, y_align: St.Align.START });
|
this.actor.add(this._message, { x_fill: false, x_align: St.Align.START, y_align: St.Align.START });
|
||||||
|
|
||||||
this._buttonBox = new St.BoxLayout({ style_class: 'login-dialog-button-box',
|
this._buttonBox = new St.BoxLayout({ style_class: 'login-dialog-button-box',
|
||||||
|
@ -1225,7 +1225,7 @@ const LoginDialog = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
addCharacter: function(unichar) {
|
addCharacter: function(unichar) {
|
||||||
this._authPrompt.addCharacter(unichar);
|
// Don't allow type ahead at the login screen
|
||||||
},
|
},
|
||||||
|
|
||||||
finish: function(onComplete) {
|
finish: function(onComplete) {
|
||||||
|
@ -25,6 +25,7 @@
|
|||||||
<file>misc/params.js</file>
|
<file>misc/params.js</file>
|
||||||
<file>misc/smartcardManager.js</file>
|
<file>misc/smartcardManager.js</file>
|
||||||
<file>misc/util.js</file>
|
<file>misc/util.js</file>
|
||||||
|
<file>misc/weather.js</file>
|
||||||
|
|
||||||
<file>perf/core.js</file>
|
<file>perf/core.js</file>
|
||||||
<file>perf/hwtest.js</file>
|
<file>perf/hwtest.js</file>
|
||||||
@ -72,6 +73,7 @@
|
|||||||
<file>ui/osdMonitorLabeler.js</file>
|
<file>ui/osdMonitorLabeler.js</file>
|
||||||
<file>ui/overview.js</file>
|
<file>ui/overview.js</file>
|
||||||
<file>ui/overviewControls.js</file>
|
<file>ui/overviewControls.js</file>
|
||||||
|
<file>ui/padOsd.js</file>
|
||||||
<file>ui/panel.js</file>
|
<file>ui/panel.js</file>
|
||||||
<file>ui/panelMenu.js</file>
|
<file>ui/panelMenu.js</file>
|
||||||
<file>ui/pointerWatcher.js</file>
|
<file>ui/pointerWatcher.js</file>
|
||||||
@ -116,6 +118,7 @@
|
|||||||
<file>ui/status/brightness.js</file>
|
<file>ui/status/brightness.js</file>
|
||||||
<file>ui/status/location.js</file>
|
<file>ui/status/location.js</file>
|
||||||
<file>ui/status/keyboard.js</file>
|
<file>ui/status/keyboard.js</file>
|
||||||
|
<file>ui/status/nightLight.js</file>
|
||||||
<file>ui/status/network.js</file>
|
<file>ui/status/network.js</file>
|
||||||
<file>ui/status/power.js</file>
|
<file>ui/status/power.js</file>
|
||||||
<file>ui/status/rfkill.js</file>
|
<file>ui/status/rfkill.js</file>
|
||||||
|
@ -15,3 +15,5 @@ const LOCALEDIR = '@datadir@/locale';
|
|||||||
/* other standard directories */
|
/* other standard directories */
|
||||||
const LIBEXECDIR = '@libexecdir@';
|
const LIBEXECDIR = '@libexecdir@';
|
||||||
const SYSCONFDIR = '@sysconfdir@';
|
const SYSCONFDIR = '@sysconfdir@';
|
||||||
|
/* g-i package versions */
|
||||||
|
const LIBMUTTER_API_VERSION = '@LIBMUTTER_API_VERSION@'
|
||||||
|
@ -6,9 +6,7 @@
|
|||||||
const Lang = imports.lang;
|
const Lang = imports.lang;
|
||||||
const Signals = imports.signals;
|
const Signals = imports.signals;
|
||||||
|
|
||||||
const GLib = imports.gi.GLib;
|
|
||||||
const Gio = imports.gi.Gio;
|
const Gio = imports.gi.Gio;
|
||||||
const ShellJS = imports.gi.ShellJS;
|
|
||||||
|
|
||||||
const Config = imports.misc.config;
|
const Config = imports.misc.config;
|
||||||
const FileUtils = imports.misc.fileUtils;
|
const FileUtils = imports.misc.fileUtils;
|
||||||
@ -21,14 +19,25 @@ const ExtensionType = {
|
|||||||
// Maps uuid -> metadata object
|
// Maps uuid -> metadata object
|
||||||
const extensions = {};
|
const extensions = {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* getCurrentExtension:
|
||||||
|
*
|
||||||
|
* Returns the current extension, or null if not called from an extension.
|
||||||
|
*/
|
||||||
function getCurrentExtension() {
|
function getCurrentExtension() {
|
||||||
let stack = (new Error()).stack;
|
let stack = (new Error()).stack.split('\n');
|
||||||
|
let extensionStackLine;
|
||||||
|
|
||||||
// Assuming we're importing this directly from an extension (and we shouldn't
|
// Search for an occurrence of an extension stack frame
|
||||||
// ever not be), its UUID should be directly in the path here.
|
// Start at 1 because 0 is the stack frame of this function
|
||||||
let extensionStackLine = stack.split('\n')[1];
|
for (let i = 1; i < stack.length; i++) {
|
||||||
|
if (stack[i].indexOf('/gnome-shell/extensions/') > -1) {
|
||||||
|
extensionStackLine = stack[i];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
if (!extensionStackLine)
|
if (!extensionStackLine)
|
||||||
throw new Error('Could not find current extension');
|
return null;
|
||||||
|
|
||||||
// The stack line is like:
|
// The stack line is like:
|
||||||
// init([object Object])@/home/user/data/gnome-shell/extensions/u@u.id/prefs.js:8
|
// init([object Object])@/home/user/data/gnome-shell/extensions/u@u.id/prefs.js:8
|
||||||
@ -38,7 +47,7 @@ function getCurrentExtension() {
|
|||||||
// @/home/user/data/gnome-shell/extensions/u@u.id/prefs.js:8
|
// @/home/user/data/gnome-shell/extensions/u@u.id/prefs.js:8
|
||||||
let match = new RegExp('@(.+):\\d+').exec(extensionStackLine);
|
let match = new RegExp('@(.+):\\d+').exec(extensionStackLine);
|
||||||
if (!match)
|
if (!match)
|
||||||
throw new Error('Could not find current extension');
|
return null;
|
||||||
|
|
||||||
let path = match[1];
|
let path = match[1];
|
||||||
let file = Gio.File.new_for_path(path);
|
let file = Gio.File.new_for_path(path);
|
||||||
@ -52,7 +61,7 @@ function getCurrentExtension() {
|
|||||||
file = file.get_parent();
|
file = file.get_parent();
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new Error('Could not find current extension');
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -140,12 +149,13 @@ function createExtensionObject(uuid, dir, type) {
|
|||||||
return extension;
|
return extension;
|
||||||
}
|
}
|
||||||
|
|
||||||
var _extension = null;
|
|
||||||
|
|
||||||
function installImporter(extension) {
|
function installImporter(extension) {
|
||||||
_extension = extension;
|
let oldSearchPath = imports.searchPath.slice(); // make a copy
|
||||||
ShellJS.add_extension_importer('imports.misc.extensionUtils._extension', 'imports', extension.path);
|
imports.searchPath = [extension.dir.get_parent().get_path()];
|
||||||
_extension = null;
|
// importing a "subdir" creates a new importer object that doesn't affect
|
||||||
|
// the global one
|
||||||
|
extension.imports = imports[extension.uuid];
|
||||||
|
imports.searchPath = oldSearchPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
const ExtensionFinder = new Lang.Class({
|
const ExtensionFinder = new Lang.Class({
|
||||||
|
@ -6,10 +6,11 @@ const Lang = imports.lang;
|
|||||||
const Mainloop = imports.mainloop;
|
const Mainloop = imports.mainloop;
|
||||||
const Signals = imports.signals;
|
const Signals = imports.signals;
|
||||||
|
|
||||||
|
let IBusCandidatePopup;
|
||||||
try {
|
try {
|
||||||
var IBus = imports.gi.IBus;
|
var IBus = imports.gi.IBus;
|
||||||
_checkIBusVersion(1, 5, 2);
|
_checkIBusVersion(1, 5, 2);
|
||||||
const IBusCandidatePopup = imports.ui.ibusCandidatePopup;
|
IBusCandidatePopup = imports.ui.ibusCandidatePopup;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
var IBus = null;
|
var IBus = null;
|
||||||
log(e);
|
log(e);
|
||||||
|
@ -128,7 +128,8 @@ const KeyboardManager = new Lang.Class({
|
|||||||
if (!found)
|
if (!found)
|
||||||
[, , id] = GnomeDesktop.get_input_source_from_locale(DEFAULT_LOCALE);
|
[, , 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)
|
if (found)
|
||||||
return { layout: _layout, variant: _variant };
|
return { layout: _layout, variant: _variant };
|
||||||
else
|
else
|
||||||
|
131
js/misc/util.js
131
js/misc/util.js
@ -1,9 +1,12 @@
|
|||||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||||
|
|
||||||
const Clutter = imports.gi.Clutter;
|
const Clutter = imports.gi.Clutter;
|
||||||
|
const Gettext = imports.gettext;
|
||||||
const Gio = imports.gi.Gio;
|
const Gio = imports.gi.Gio;
|
||||||
const GLib = imports.gi.GLib;
|
const GLib = imports.gi.GLib;
|
||||||
const Lang = imports.lang;
|
const Lang = imports.lang;
|
||||||
|
const Mainloop = imports.mainloop;
|
||||||
|
const Signals = imports.signals;
|
||||||
const Shell = imports.gi.Shell;
|
const Shell = imports.gi.Shell;
|
||||||
const St = imports.gi.St;
|
const St = imports.gi.St;
|
||||||
|
|
||||||
@ -94,7 +97,7 @@ function spawnApp(argv) {
|
|||||||
Gio.AppInfoCreateFlags.SUPPORTS_STARTUP_NOTIFICATION);
|
Gio.AppInfoCreateFlags.SUPPORTS_STARTUP_NOTIFICATION);
|
||||||
|
|
||||||
let context = global.create_app_launch_context(0, -1);
|
let context = global.create_app_launch_context(0, -1);
|
||||||
app.launch([], context);
|
app.launch([], context, false);
|
||||||
} catch(err) {
|
} catch(err) {
|
||||||
_handleSpawnError(argv[0], err);
|
_handleSpawnError(argv[0], err);
|
||||||
}
|
}
|
||||||
@ -161,6 +164,41 @@ function _handleSpawnError(command, err) {
|
|||||||
Main.notifyError(title, err.message);
|
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) {
|
function formatTime(time, params) {
|
||||||
let date;
|
let date;
|
||||||
// HACK: The built-in Date type sucks at timezones, which we need for the
|
// HACK: The built-in Date type sucks at timezones, which we need for the
|
||||||
@ -398,3 +436,94 @@ function ensureActorVisibleInScrollView(scrollView, actor) {
|
|||||||
time: SCROLL_TIME,
|
time: SCROLL_TIME,
|
||||||
transition: 'easeOutQuad' });
|
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);
|
||||||
|
188
js/misc/weather.js
Normal file
188
js/misc/weather.js
Normal file
@ -0,0 +1,188 @@
|
|||||||
|
// -*- 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 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._lastUpdate = GLib.DateTime.new_from_unix_local(0);
|
||||||
|
|
||||||
|
this._useAutoLocation = false;
|
||||||
|
this._mostRecentLocation = null;
|
||||||
|
|
||||||
|
this._gclueService = null;
|
||||||
|
this._gclueStarted = false;
|
||||||
|
this._gclueStarting = false;
|
||||||
|
this._gclueLocationChangedId = 0;
|
||||||
|
|
||||||
|
this._world = GWeather.Location.get_world();
|
||||||
|
|
||||||
|
let providers = GWeather.Provider.METAR |
|
||||||
|
GWeather.Provider.YR_NO |
|
||||||
|
GWeather.Provider.OWM;
|
||||||
|
this._weatherInfo = new GWeather.Info({ enabled_providers: providers });
|
||||||
|
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 info() {
|
||||||
|
return this._weatherInfo;
|
||||||
|
},
|
||||||
|
|
||||||
|
activateApp: function() {
|
||||||
|
this._weatherAppMon.activateApp();
|
||||||
|
},
|
||||||
|
|
||||||
|
update: function() {
|
||||||
|
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();
|
||||||
|
},
|
||||||
|
|
||||||
|
_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);
|
||||||
|
|
||||||
|
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._useAutoLocation == useAutoLocation)
|
||||||
|
return;
|
||||||
|
|
||||||
|
this._useAutoLocation = useAutoLocation;
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
Signals.addSignalMethods(WeatherClient.prototype);
|
@ -12,6 +12,7 @@ const WebKit = imports.gi.WebKit2;
|
|||||||
const _ = Gettext.gettext;
|
const _ = Gettext.gettext;
|
||||||
|
|
||||||
const Config = imports.misc.config;
|
const Config = imports.misc.config;
|
||||||
|
const FileUtils = imports.misc.fileUtils;
|
||||||
|
|
||||||
const PortalHelperResult = {
|
const PortalHelperResult = {
|
||||||
CANCELLED: 0,
|
CANCELLED: 0,
|
||||||
@ -19,7 +20,15 @@ const PortalHelperResult = {
|
|||||||
RECHECK: 2
|
RECHECK: 2
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const PortalHelperSecurityLevel = {
|
||||||
|
NOT_YET_DETERMINED: 0,
|
||||||
|
SECURE: 1,
|
||||||
|
INSECURE: 2
|
||||||
|
};
|
||||||
|
|
||||||
const INACTIVITY_TIMEOUT = 30000; //ms
|
const INACTIVITY_TIMEOUT = 30000; //ms
|
||||||
|
const CONNECTIVITY_CHECK_HOST = 'nmcheck.gnome.org';
|
||||||
|
const CONNECTIVITY_CHECK_URI = 'http://' + CONNECTIVITY_CHECK_HOST;
|
||||||
const CONNECTIVITY_RECHECK_RATELIMIT_TIMEOUT = 30 * GLib.USEC_PER_SEC;
|
const CONNECTIVITY_RECHECK_RATELIMIT_TIMEOUT = 30 * GLib.USEC_PER_SEC;
|
||||||
|
|
||||||
const HelperDBusInterface = '<node> \
|
const HelperDBusInterface = '<node> \
|
||||||
@ -42,6 +51,71 @@ const HelperDBusInterface = '<node> \
|
|||||||
</interface> \
|
</interface> \
|
||||||
</node>';
|
</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({
|
const PortalWindow = new Lang.Class({
|
||||||
Name: 'PortalWindow',
|
Name: 'PortalWindow',
|
||||||
Extends: Gtk.ApplicationWindow,
|
Extends: Gtk.ApplicationWindow,
|
||||||
@ -49,8 +123,14 @@ const PortalWindow = new Lang.Class({
|
|||||||
_init: function(application, url, timestamp, doneCallback) {
|
_init: function(application, url, timestamp, doneCallback) {
|
||||||
this.parent({ application: application });
|
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) {
|
if (!url) {
|
||||||
url = 'http://www.gnome.org';
|
url = CONNECTIVITY_CHECK_URI;
|
||||||
this._originalUrlWasGnome = true;
|
this._originalUrlWasGnome = true;
|
||||||
} else {
|
} else {
|
||||||
this._originalUrlWasGnome = false;
|
this._originalUrlWasGnome = false;
|
||||||
@ -61,29 +141,43 @@ const PortalWindow = new Lang.Class({
|
|||||||
this._doneCallback = doneCallback;
|
this._doneCallback = doneCallback;
|
||||||
this._lastRecheck = 0;
|
this._lastRecheck = 0;
|
||||||
this._recheckAtExit = false;
|
this._recheckAtExit = false;
|
||||||
|
let cacheDir = GLib.Dir.make_tmp("gnome-shell-portal-helper-XXXXXXXX");
|
||||||
|
this._cacheDir = Gio.File.new_for_path(cacheDir);
|
||||||
|
|
||||||
this._webView = new WebKit.WebView();
|
let dataManager = new WebKit.WebsiteDataManager({ base_data_directory: cacheDir,
|
||||||
|
base_cache_directory: cacheDir });
|
||||||
|
this._webContext = new WebKit.WebContext({ website_data_manager: dataManager });
|
||||||
|
this._webContext.set_cache_model(WebKit.CacheModel.DOCUMENT_VIEWER);
|
||||||
|
|
||||||
|
this._webView = WebKit.WebView.new_with_context(this._webContext);
|
||||||
this._webView.connect('decide-policy', Lang.bind(this, this._onDecidePolicy));
|
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.load_uri(url);
|
||||||
this._webView.connect('notify::title', Lang.bind(this, this._syncTitle));
|
this._webView.connect('notify::uri', Lang.bind(this, this._syncUri));
|
||||||
this._syncTitle();
|
this._syncUri();
|
||||||
|
|
||||||
this.add(this._webView);
|
this.add(this._webView);
|
||||||
this._webView.show();
|
this._webView.show();
|
||||||
|
this.set_size_request(600, 450);
|
||||||
this.maximize();
|
this.maximize();
|
||||||
this.present_with_time(timestamp);
|
this.present_with_time(timestamp);
|
||||||
|
|
||||||
|
this.application.set_accels_for_action('app.quit', ['<Primary>q', '<Primary>w']);
|
||||||
},
|
},
|
||||||
|
|
||||||
_syncTitle: function() {
|
destroyWindow: function() {
|
||||||
let title = this._webView.title;
|
this.destroy();
|
||||||
|
FileUtils.recursivelyDeleteDir(this._cacheDir, true);
|
||||||
|
},
|
||||||
|
|
||||||
if (title) {
|
_syncUri: function() {
|
||||||
this.title = title;
|
let uri = this._webView.uri;
|
||||||
} else {
|
if (uri)
|
||||||
/* TRANSLATORS: this is the title of the wifi captive portal login
|
this._headerBar.setSubtitle(GLib.uri_unescape_string(uri, null));
|
||||||
* window, until we know the title of the actual login page */
|
else
|
||||||
this.title = _("Web Authentication Redirect");
|
this._headerBar.setSubtitle('');
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
refresh: function() {
|
refresh: function() {
|
||||||
@ -99,6 +193,32 @@ const PortalWindow = new Lang.Class({
|
|||||||
return false;
|
return false;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_onLoadChanged: function(view, loadEvent) {
|
||||||
|
if (loadEvent == WebKit.LOAD_STARTED) {
|
||||||
|
this._headerBar.setSecurityIcon(PortalHelperSecurityLevel.NOT_YET_DETERMINED);
|
||||||
|
} else if (loadEvent == WebKit.LOAD_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) {
|
_onDecidePolicy: function(view, decision, type) {
|
||||||
if (type == WebKit.PolicyDecisionType.NEW_WINDOW_ACTION) {
|
if (type == WebKit.PolicyDecisionType.NEW_WINDOW_ACTION) {
|
||||||
decision.ignore();
|
decision.ignore();
|
||||||
@ -112,12 +232,12 @@ const PortalWindow = new Lang.Class({
|
|||||||
let uri = new Soup.URI(request.get_uri());
|
let uri = new Soup.URI(request.get_uri());
|
||||||
|
|
||||||
if (!uri.host_equal(this._uri) && this._originalUrlWasGnome) {
|
if (!uri.host_equal(this._uri) && this._originalUrlWasGnome) {
|
||||||
if (uri.get_host() == 'www.gnome.org' && this._everSeenRedirect) {
|
if (uri.get_host() == CONNECTIVITY_CHECK_HOST && this._everSeenRedirect) {
|
||||||
// Yay, we got to gnome!
|
// Yay, we got to gnome!
|
||||||
decision.ignore();
|
decision.ignore();
|
||||||
this._doneCallback(PortalHelperResult.COMPLETED);
|
this._doneCallback(PortalHelperResult.COMPLETED);
|
||||||
return true;
|
return true;
|
||||||
} else if (uri.get_host() != 'www.gnome.org') {
|
} else if (uri.get_host() != CONNECTIVITY_CHECK_HOST) {
|
||||||
this._everSeenRedirect = true;
|
this._everSeenRedirect = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -166,6 +286,10 @@ const WebPortalHelper = new Lang.Class({
|
|||||||
|
|
||||||
this._dbusImpl = Gio.DBusExportedObject.wrapJSObject(HelperDBusInterface, this);
|
this._dbusImpl = Gio.DBusExportedObject.wrapJSObject(HelperDBusInterface, this);
|
||||||
this._queue = [];
|
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) {
|
vfunc_dbus_register: function(connection, path) {
|
||||||
@ -197,7 +321,7 @@ const WebPortalHelper = new Lang.Class({
|
|||||||
|
|
||||||
if (obj.connection == connection) {
|
if (obj.connection == connection) {
|
||||||
if (obj.window)
|
if (obj.window)
|
||||||
obj.window.destroy();
|
obj.window.destroyWindow();
|
||||||
this._queue.splice(i, 1);
|
this._queue.splice(i, 1);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -33,10 +33,9 @@ const AppIconMode = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
function _createWindowClone(window, size) {
|
function _createWindowClone(window, size) {
|
||||||
let windowTexture = window.get_texture();
|
let [width, height] = window.get_size();
|
||||||
let [width, height] = windowTexture.get_size();
|
|
||||||
let scale = Math.min(1.0, size / width, size / height);
|
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,
|
width: width * scale,
|
||||||
height: height * scale,
|
height: height * scale,
|
||||||
x_align: Clutter.ActorAlign.CENTER,
|
x_align: Clutter.ActorAlign.CENTER,
|
||||||
|
@ -67,7 +67,7 @@ const Animation = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
_animationsLoaded: function() {
|
_animationsLoaded: function() {
|
||||||
this._isLoaded = true;
|
this._isLoaded = this._animations.get_n_children() > 0;
|
||||||
|
|
||||||
if (this._isPlaying)
|
if (this._isPlaying)
|
||||||
this.play();
|
this.play();
|
||||||
|
@ -60,6 +60,18 @@ const PAGE_SWITCH_TIME = 0.3;
|
|||||||
const VIEWS_SWITCH_TIME = 0.4;
|
const VIEWS_SWITCH_TIME = 0.4;
|
||||||
const VIEWS_SWITCH_ANIMATION_DELAY = 0.1;
|
const VIEWS_SWITCH_ANIMATION_DELAY = 0.1;
|
||||||
|
|
||||||
|
const SWITCHEROO_BUS_NAME = 'net.hadess.SwitcherooControl';
|
||||||
|
const SWITCHEROO_OBJECT_PATH = '/net/hadess/SwitcherooControl';
|
||||||
|
|
||||||
|
const SwitcherooProxyInterface = '<node> \
|
||||||
|
<interface name="net.hadess.SwitcherooControl"> \
|
||||||
|
<property name="HasDualGpu" type="b" access="read"/> \
|
||||||
|
</interface> \
|
||||||
|
</node>';
|
||||||
|
|
||||||
|
const SwitcherooProxy = Gio.DBusProxy.makeProxyWrapper(SwitcherooProxyInterface);
|
||||||
|
let discreteGpuAvailable = false;
|
||||||
|
|
||||||
function _getCategories(info) {
|
function _getCategories(info) {
|
||||||
let categoriesStr = info.get_categories();
|
let categoriesStr = info.get_categories();
|
||||||
if (!categoriesStr)
|
if (!categoriesStr)
|
||||||
@ -198,6 +210,14 @@ const BaseAppView = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
animate: function(animationDirection, onComplete) {
|
animate: function(animationDirection, onComplete) {
|
||||||
|
if (onComplete) {
|
||||||
|
let animationDoneId = this._grid.connect('animation-done', Lang.bind(this,
|
||||||
|
function () {
|
||||||
|
this._grid.disconnect(animationDoneId);
|
||||||
|
onComplete();
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
if (animationDirection == IconGrid.AnimationDirection.IN) {
|
if (animationDirection == IconGrid.AnimationDirection.IN) {
|
||||||
let toAnimate = this._grid.actor.connect('notify::allocation', Lang.bind(this,
|
let toAnimate = this._grid.actor.connect('notify::allocation', Lang.bind(this,
|
||||||
function() {
|
function() {
|
||||||
@ -213,14 +233,6 @@ const BaseAppView = new Lang.Class({
|
|||||||
} else {
|
} else {
|
||||||
this._doSpringAnimation(animationDirection);
|
this._doSpringAnimation(animationDirection);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (onComplete) {
|
|
||||||
let animationDoneId = this._grid.connect('animation-done', Lang.bind(this,
|
|
||||||
function () {
|
|
||||||
this._grid.disconnect(animationDoneId);
|
|
||||||
onComplete();
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
animateSwitch: function(animationDirection) {
|
animateSwitch: function(animationDirection) {
|
||||||
@ -887,6 +899,8 @@ const ControlsBoxLayout = Lang.Class({
|
|||||||
const ViewStackLayout = new Lang.Class({
|
const ViewStackLayout = new Lang.Class({
|
||||||
Name: 'ViewStackLayout',
|
Name: 'ViewStackLayout',
|
||||||
Extends: Clutter.BinLayout,
|
Extends: Clutter.BinLayout,
|
||||||
|
Signals: { 'allocated-size-changed': { param_types: [GObject.TYPE_INT,
|
||||||
|
GObject.TYPE_INT] } },
|
||||||
|
|
||||||
vfunc_allocate: function (actor, box, flags) {
|
vfunc_allocate: function (actor, box, flags) {
|
||||||
let availWidth = box.x2 - box.x1;
|
let availWidth = box.x2 - box.x1;
|
||||||
@ -897,7 +911,6 @@ const ViewStackLayout = new Lang.Class({
|
|||||||
this.parent(actor, box, flags);
|
this.parent(actor, box, flags);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
Signals.addSignalMethods(ViewStackLayout.prototype);
|
|
||||||
|
|
||||||
const AppDisplay = new Lang.Class({
|
const AppDisplay = new Lang.Class({
|
||||||
Name: 'AppDisplay',
|
Name: 'AppDisplay',
|
||||||
@ -969,10 +982,36 @@ const AppDisplay = new Lang.Class({
|
|||||||
initialView = Views.ALL;
|
initialView = Views.ALL;
|
||||||
this._showView(initialView);
|
this._showView(initialView);
|
||||||
this._updateFrequentVisibility();
|
this._updateFrequentVisibility();
|
||||||
|
|
||||||
|
Gio.DBus.system.watch_name(SWITCHEROO_BUS_NAME,
|
||||||
|
Gio.BusNameWatcherFlags.NONE,
|
||||||
|
Lang.bind(this, this._switcherooProxyAppeared),
|
||||||
|
Lang.bind(this, function() {
|
||||||
|
this._switcherooProxy = null;
|
||||||
|
this._updateDiscreteGpuAvailable();
|
||||||
|
}));
|
||||||
|
},
|
||||||
|
|
||||||
|
_updateDiscreteGpuAvailable: function() {
|
||||||
|
if (!this._switcherooProxy)
|
||||||
|
discreteGpuAvailable = false;
|
||||||
|
else
|
||||||
|
discreteGpuAvailable = this._switcherooProxy.HasDualGpu;
|
||||||
|
},
|
||||||
|
|
||||||
|
_switcherooProxyAppeared: function() {
|
||||||
|
this._switcherooProxy = new SwitcherooProxy(Gio.DBus.system, SWITCHEROO_BUS_NAME, SWITCHEROO_OBJECT_PATH,
|
||||||
|
Lang.bind(this, function(proxy, error) {
|
||||||
|
if (error) {
|
||||||
|
log(error.message);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this._updateDiscreteGpuAvailable();
|
||||||
|
}));
|
||||||
},
|
},
|
||||||
|
|
||||||
animate: function(animationDirection, onComplete) {
|
animate: function(animationDirection, onComplete) {
|
||||||
let currentView = this._views[global.settings.get_uint('app-picker-view')].view;
|
let currentView = this._views.filter(v => v.control.has_style_pseudo_class('checked')).pop().view;
|
||||||
|
|
||||||
// Animate controls opacity using iconGrid animation time, since
|
// Animate controls opacity using iconGrid animation time, since
|
||||||
// it will be the time the AllView or FrequentView takes to show
|
// it will be the time the AllView or FrequentView takes to show
|
||||||
@ -1861,6 +1900,19 @@ const AppIconMenu = new Lang.Class({
|
|||||||
this._appendSeparator();
|
this._appendSeparator();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (discreteGpuAvailable &&
|
||||||
|
this._source.app.state == Shell.AppState.STOPPED &&
|
||||||
|
actions.indexOf('activate-discrete-gpu') == -1) {
|
||||||
|
this._onDiscreteGpuMenuItem = this._appendMenuItem(_("Launch using Dedicated Graphics Card"));
|
||||||
|
this._onDiscreteGpuMenuItem.connect('activate', Lang.bind(this, function() {
|
||||||
|
if (this._source.app.state == Shell.AppState.STOPPED)
|
||||||
|
this._source.animateLaunch();
|
||||||
|
|
||||||
|
this._source.app.launch(0, -1, true);
|
||||||
|
this.emit('activate-window', null);
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
for (let i = 0; i < actions.length; i++) {
|
for (let i = 0; i < actions.length; i++) {
|
||||||
let action = actions[i];
|
let action = actions[i];
|
||||||
let item = this._appendMenuItem(appInfo.get_action_name(action));
|
let item = this._appendMenuItem(appInfo.get_action_name(action));
|
||||||
|
@ -10,8 +10,10 @@ const RENAMED_DESKTOP_IDS = {
|
|||||||
'baobab.desktop': 'org.gnome.baobab.desktop',
|
'baobab.desktop': 'org.gnome.baobab.desktop',
|
||||||
'cheese.desktop': 'org.gnome.Cheese.desktop',
|
'cheese.desktop': 'org.gnome.Cheese.desktop',
|
||||||
'dconf-editor.desktop': 'ca.desrt.dconf-editor.desktop',
|
'dconf-editor.desktop': 'ca.desrt.dconf-editor.desktop',
|
||||||
|
'epiphany.desktop': 'org.gnome.Epiphany.desktop',
|
||||||
'file-roller.desktop': 'org.gnome.FileRoller.desktop',
|
'file-roller.desktop': 'org.gnome.FileRoller.desktop',
|
||||||
'gcalctool.desktop': 'gnome-calculator.desktop',
|
'gcalctool.desktop': 'org.gnome.Calculator.desktop',
|
||||||
|
'geary.desktop': 'org.gnome.Geary.desktop',
|
||||||
'gedit.desktop': 'org.gnome.gedit.desktop',
|
'gedit.desktop': 'org.gnome.gedit.desktop',
|
||||||
'glchess.desktop': 'gnome-chess.desktop',
|
'glchess.desktop': 'gnome-chess.desktop',
|
||||||
'glines.desktop': 'five-or-more.desktop',
|
'glines.desktop': 'five-or-more.desktop',
|
||||||
@ -19,6 +21,7 @@ const RENAMED_DESKTOP_IDS = {
|
|||||||
'gnibbles.desktop': 'org.gnome.Nibbles.desktop',
|
'gnibbles.desktop': 'org.gnome.Nibbles.desktop',
|
||||||
'gnobots2.desktop': 'gnome-robots.desktop',
|
'gnobots2.desktop': 'gnome-robots.desktop',
|
||||||
'gnome-boxes.desktop': 'org.gnome.Boxes.desktop',
|
'gnome-boxes.desktop': 'org.gnome.Boxes.desktop',
|
||||||
|
'gnome-calculator.desktop': 'org.gnome.Calculator.desktop',
|
||||||
'gnome-clocks.desktop': 'org.gnome.clocks.desktop',
|
'gnome-clocks.desktop': 'org.gnome.clocks.desktop',
|
||||||
'gnome-contacts.desktop': 'org.gnome.Contacts.desktop',
|
'gnome-contacts.desktop': 'org.gnome.Contacts.desktop',
|
||||||
'gnome-documents.desktop': 'org.gnome.Documents.desktop',
|
'gnome-documents.desktop': 'org.gnome.Documents.desktop',
|
||||||
@ -56,12 +59,14 @@ const AppFavorites = new Lang.Class({
|
|||||||
|
|
||||||
reload: function() {
|
reload: function() {
|
||||||
let ids = global.settings.get_strv(this.FAVORITE_APPS_KEY);
|
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
|
// Map old desktop file names to the current ones
|
||||||
let updated = false;
|
let updated = false;
|
||||||
ids = ids.map(function (id) {
|
ids = ids.map(function (id) {
|
||||||
let newId = RENAMED_DESKTOP_IDS[id];
|
let newId = RENAMED_DESKTOP_IDS[id];
|
||||||
if (newId !== undefined) {
|
if (newId !== undefined &&
|
||||||
|
appSys.lookup_app(newId) != null) {
|
||||||
updated = true;
|
updated = true;
|
||||||
return newId;
|
return newId;
|
||||||
}
|
}
|
||||||
@ -71,7 +76,6 @@ const AppFavorites = new Lang.Class({
|
|||||||
if (updated)
|
if (updated)
|
||||||
global.settings.set_strv(this.FAVORITE_APPS_KEY, ids);
|
global.settings.set_strv(this.FAVORITE_APPS_KEY, ids);
|
||||||
|
|
||||||
let appSys = Shell.AppSystem.get_default();
|
|
||||||
let apps = ids.map(function (id) {
|
let apps = ids.map(function (id) {
|
||||||
return appSys.lookup_app(id);
|
return appSys.lookup_app(id);
|
||||||
}).filter(function (app) {
|
}).filter(function (app) {
|
||||||
|
@ -102,6 +102,7 @@ const Lang = imports.lang;
|
|||||||
const Meta = imports.gi.Meta;
|
const Meta = imports.gi.Meta;
|
||||||
const Signals = imports.signals;
|
const Signals = imports.signals;
|
||||||
|
|
||||||
|
const LoginManager = imports.misc.loginManager;
|
||||||
const Main = imports.ui.main;
|
const Main = imports.ui.main;
|
||||||
const Params = imports.misc.params;
|
const Params = imports.misc.params;
|
||||||
const Tweener = imports.ui.tweener;
|
const Tweener = imports.ui.tweener;
|
||||||
@ -141,7 +142,6 @@ const BackgroundCache = new Lang.Class({
|
|||||||
Name: 'BackgroundCache',
|
Name: 'BackgroundCache',
|
||||||
|
|
||||||
_init: function() {
|
_init: function() {
|
||||||
this._pendingFileLoads = [];
|
|
||||||
this._fileMonitors = {};
|
this._fileMonitors = {};
|
||||||
this._backgroundSources = {};
|
this._backgroundSources = {};
|
||||||
this._animations = {};
|
this._animations = {};
|
||||||
@ -254,6 +254,14 @@ const Background = new Lang.Class({
|
|||||||
this._loadAnimation(this._animation.file);
|
this._loadAnimation(this._animation.file);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
let loginManager = LoginManager.getLoginManager();
|
||||||
|
this._prepareForSleepId = loginManager.connect('prepare-for-sleep',
|
||||||
|
(lm, aboutToSuspend) => {
|
||||||
|
if (aboutToSuspend)
|
||||||
|
return;
|
||||||
|
this._refreshAnimation();
|
||||||
|
});
|
||||||
|
|
||||||
this._settingsChangedSignalId = this._settings.connect('changed', Lang.bind(this, function() {
|
this._settingsChangedSignalId = this._settings.connect('changed', Lang.bind(this, function() {
|
||||||
this.emit('changed');
|
this.emit('changed');
|
||||||
}));
|
}));
|
||||||
@ -276,16 +284,26 @@ const Background = new Lang.Class({
|
|||||||
this._clock.disconnect(this._timezoneChangedId);
|
this._clock.disconnect(this._timezoneChangedId);
|
||||||
this._timezoneChangedId = 0;
|
this._timezoneChangedId = 0;
|
||||||
|
|
||||||
|
if (this._prepareForSleepId != 0)
|
||||||
|
LoginManager.getLoginManager().disconnect(this._prepareForSleepId);
|
||||||
|
this._prepareForSleepId = 0;
|
||||||
|
|
||||||
if (this._settingsChangedSignalId != 0)
|
if (this._settingsChangedSignalId != 0)
|
||||||
this._settings.disconnect(this._settingsChangedSignalId);
|
this._settings.disconnect(this._settingsChangedSignalId);
|
||||||
this._settingsChangedSignalId = 0;
|
this._settingsChangedSignalId = 0;
|
||||||
},
|
},
|
||||||
|
|
||||||
updateResolution: function() {
|
updateResolution: function() {
|
||||||
if (this._animation) {
|
if (this._animation)
|
||||||
this._removeAnimationTimeout();
|
this._refreshAnimation();
|
||||||
this._updateAnimation();
|
},
|
||||||
}
|
|
||||||
|
_refreshAnimation: function() {
|
||||||
|
if (!this._animation)
|
||||||
|
return;
|
||||||
|
|
||||||
|
this._removeAnimationTimeout();
|
||||||
|
this._updateAnimation();
|
||||||
},
|
},
|
||||||
|
|
||||||
_setLoaded: function() {
|
_setLoaded: function() {
|
||||||
@ -363,11 +381,9 @@ const Background = new Lang.Class({
|
|||||||
|
|
||||||
let cache = Meta.BackgroundImageCache.get_default();
|
let cache = Meta.BackgroundImageCache.get_default();
|
||||||
let numPendingImages = files.length;
|
let numPendingImages = files.length;
|
||||||
let images = [];
|
|
||||||
for (let i = 0; i < files.length; i++) {
|
for (let i = 0; i < files.length; i++) {
|
||||||
this._watchFile(files[i]);
|
this._watchFile(files[i]);
|
||||||
let image = cache.load(files[i]);
|
let image = cache.load(files[i]);
|
||||||
images.push(image);
|
|
||||||
if (image.is_loaded()) {
|
if (image.is_loaded()) {
|
||||||
numPendingImages--;
|
numPendingImages--;
|
||||||
if (numPendingImages == 0)
|
if (numPendingImages == 0)
|
||||||
|
@ -20,7 +20,7 @@ const MSECS_IN_DAY = 24 * 60 * 60 * 1000;
|
|||||||
const SHOW_WEEKDATE_KEY = 'show-weekdate';
|
const SHOW_WEEKDATE_KEY = 'show-weekdate';
|
||||||
const ELLIPSIS_CHAR = '\u2026';
|
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+
|
// alias to prevent xgettext from picking up strings translated in GTK+
|
||||||
const gtk30_ = Gettext_gtk30.gettext;
|
const gtk30_ = Gettext_gtk30.gettext;
|
||||||
@ -706,6 +706,14 @@ const EventMessage = new Lang.Class({
|
|||||||
this._date = date;
|
this._date = date;
|
||||||
|
|
||||||
this.parent(this._formatEventTime(), event.summary);
|
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() {
|
_formatEventTime: function() {
|
||||||
@ -811,7 +819,16 @@ const EventsSection = new Lang.Class({
|
|||||||
this._desktopSettings.connect('changed', Lang.bind(this, this._reloadEvents));
|
this._desktopSettings.connect('changed', Lang.bind(this, this._reloadEvents));
|
||||||
this._eventSource = new EmptyEventSource();
|
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',
|
Shell.AppSystem.get_default().connect('installed-changed',
|
||||||
Lang.bind(this, this._appInstalledChanged));
|
Lang.bind(this, this._appInstalledChanged));
|
||||||
@ -832,10 +849,10 @@ const EventsSection = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
_updateTitle: function() {
|
_updateTitle: function() {
|
||||||
if (isToday(this._date)) {
|
this._title.visible = !isToday(this._date);
|
||||||
this._title.label = _("Events");
|
|
||||||
|
if (!this._title.visible)
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
let dayFormat;
|
let dayFormat;
|
||||||
let now = new Date();
|
let now = new Date();
|
||||||
@ -897,12 +914,13 @@ const EventsSection = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
_onTitleClicked: function() {
|
_onTitleClicked: function() {
|
||||||
this.parent();
|
Main.overview.hide();
|
||||||
|
Main.panel.closeCalendar();
|
||||||
|
|
||||||
let app = this._getCalendarApp();
|
let app = this._getCalendarApp();
|
||||||
if (app.get_id() == 'evolution.desktop')
|
if (app.get_id() == 'evolution.desktop')
|
||||||
app = Gio.DesktopAppInfo.new('evolution-calendar.desktop');
|
app = Gio.DesktopAppInfo.new('evolution-calendar.desktop');
|
||||||
app.launch([], global.create_app_launch_context(0, -1));
|
app.launch([], global.create_app_launch_context(0, -1), false);
|
||||||
},
|
},
|
||||||
|
|
||||||
setDate: function(date) {
|
setDate: function(date) {
|
||||||
@ -928,7 +946,7 @@ const NotificationSection = new Lang.Class({
|
|||||||
Extends: MessageList.MessageListSection,
|
Extends: MessageList.MessageListSection,
|
||||||
|
|
||||||
_init: function() {
|
_init: function() {
|
||||||
this.parent(_("Notifications"));
|
this.parent();
|
||||||
|
|
||||||
this._sources = new Map();
|
this._sources = new Map();
|
||||||
this._nUrgent = 0;
|
this._nUrgent = 0;
|
||||||
@ -946,10 +964,14 @@ const NotificationSection = new Lang.Class({
|
|||||||
!Main.sessionMode.isGreeter;
|
!Main.sessionMode.isGreeter;
|
||||||
},
|
},
|
||||||
|
|
||||||
_createTimeLabel: function() {
|
_createTimeLabel: function(datetime) {
|
||||||
let label = Util.createTimeLabel(new Date());
|
let label = new St.Label({ style_class: 'event-time',
|
||||||
label.style_class = 'event-time',
|
x_align: Clutter.ActorAlign.START,
|
||||||
label.x_align = Clutter.ActorAlign.END;
|
y_align: Clutter.ActorAlign.END });
|
||||||
|
label.connect('notify::mapped', () => {
|
||||||
|
if (label.mapped)
|
||||||
|
label.text = Util.formatTimeSpan(datetime);
|
||||||
|
});
|
||||||
return label;
|
return label;
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -970,13 +992,13 @@ const NotificationSection = new Lang.Class({
|
|||||||
|
|
||||||
_onNotificationAdded: function(source, notification) {
|
_onNotificationAdded: function(source, notification) {
|
||||||
let message = new NotificationMessage(notification);
|
let message = new NotificationMessage(notification);
|
||||||
message.setSecondaryActor(this._createTimeLabel());
|
message.setSecondaryActor(this._createTimeLabel(notification.datetime));
|
||||||
|
|
||||||
let isUrgent = notification.urgency == MessageTray.Urgency.CRITICAL;
|
let isUrgent = notification.urgency == MessageTray.Urgency.CRITICAL;
|
||||||
|
|
||||||
let updatedId = notification.connect('updated', Lang.bind(this,
|
let updatedId = notification.connect('updated', Lang.bind(this,
|
||||||
function() {
|
function() {
|
||||||
message.setSecondaryActor(this._createTimeLabel());
|
message.setSecondaryActor(this._createTimeLabel(notification.datetime));
|
||||||
this.moveMessage(message, isUrgent ? 0 : this._nUrgent, this.actor.mapped);
|
this.moveMessage(message, isUrgent ? 0 : this._nUrgent, this.actor.mapped);
|
||||||
}));
|
}));
|
||||||
let destroyId = notification.connect('destroy', Lang.bind(this,
|
let destroyId = notification.connect('destroy', Lang.bind(this,
|
||||||
@ -1017,26 +1039,8 @@ const NotificationSection = new Lang.Class({
|
|||||||
message.notification.acknowledged = true;
|
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() {
|
_shouldShow: function() {
|
||||||
return !this.empty && isToday(this._date);
|
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._placeholder = new Placeholder();
|
||||||
this.actor.add_actor(this._placeholder.actor);
|
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',
|
this._scrollView = new St.ScrollView({ style_class: 'vfade',
|
||||||
overlay_scrollbars: true,
|
overlay_scrollbars: true,
|
||||||
x_expand: true, y_expand: true,
|
x_expand: true, y_expand: true,
|
||||||
x_fill: true, y_fill: true });
|
x_fill: true, y_fill: true });
|
||||||
this._scrollView.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC);
|
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',
|
this._sectionList = new St.BoxLayout({ style_class: 'message-list-sections',
|
||||||
vertical: true,
|
vertical: true,
|
||||||
@ -1129,6 +1147,7 @@ const CalendarMessageList = new Lang.Class({
|
|||||||
destroyId: 0,
|
destroyId: 0,
|
||||||
visibleId: 0,
|
visibleId: 0,
|
||||||
emptyChangedId: 0,
|
emptyChangedId: 0,
|
||||||
|
canClearChangedId: 0,
|
||||||
keyFocusId: 0
|
keyFocusId: 0
|
||||||
};
|
};
|
||||||
obj.destroyId = section.actor.connect('destroy', Lang.bind(this,
|
obj.destroyId = section.actor.connect('destroy', Lang.bind(this,
|
||||||
@ -1139,6 +1158,8 @@ const CalendarMessageList = new Lang.Class({
|
|||||||
Lang.bind(this, this._sync));
|
Lang.bind(this, this._sync));
|
||||||
obj.emptyChangedId = section.connect('empty-changed',
|
obj.emptyChangedId = section.connect('empty-changed',
|
||||||
Lang.bind(this, this._sync));
|
Lang.bind(this, this._sync));
|
||||||
|
obj.canClearChangedId = section.connect('can-clear-changed',
|
||||||
|
Lang.bind(this, this._sync));
|
||||||
obj.keyFocusId = section.connect('key-focus-in',
|
obj.keyFocusId = section.connect('key-focus-in',
|
||||||
Lang.bind(this, this._onKeyFocusIn));
|
Lang.bind(this, this._onKeyFocusIn));
|
||||||
|
|
||||||
@ -1152,6 +1173,7 @@ const CalendarMessageList = new Lang.Class({
|
|||||||
section.actor.disconnect(obj.destroyId);
|
section.actor.disconnect(obj.destroyId);
|
||||||
section.actor.disconnect(obj.visibleId);
|
section.actor.disconnect(obj.visibleId);
|
||||||
section.disconnect(obj.emptyChangedId);
|
section.disconnect(obj.emptyChangedId);
|
||||||
|
section.disconnect(obj.canClearChangedId);
|
||||||
section.disconnect(obj.keyFocusId);
|
section.disconnect(obj.keyFocusId);
|
||||||
|
|
||||||
this._sections.delete(section);
|
this._sections.delete(section);
|
||||||
@ -1172,10 +1194,16 @@ const CalendarMessageList = new Lang.Class({
|
|||||||
if (!visible)
|
if (!visible)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
let showPlaceholder = sections.every(function(s) {
|
let empty = sections.every(function(s) {
|
||||||
return s.empty || !s.actor.visible;
|
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) {
|
setEventSource: function(eventSource) {
|
||||||
|
@ -64,7 +64,8 @@ function startAppForMount(app, mount) {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
retval = app.launch(files,
|
retval = app.launch(files,
|
||||||
global.create_app_launch_context(0, -1))
|
global.create_app_launch_context(0, -1),
|
||||||
|
false)
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
log('Unable to launch the application ' + app.get_name()
|
log('Unable to launch the application ' + app.get_name()
|
||||||
+ ': ' + e.toString());
|
+ ': ' + e.toString());
|
||||||
|
@ -615,6 +615,14 @@ const NetworkAgent = new Lang.Class({
|
|||||||
this._vpnRequests = { };
|
this._vpnRequests = { };
|
||||||
this._notifications = { };
|
this._notifications = { };
|
||||||
|
|
||||||
|
this._pluginDir = Gio.file_new_for_path(GLib.build_filenamev([Config.SYSCONFDIR, 'NetworkManager/VPN']));
|
||||||
|
try {
|
||||||
|
let monitor = this._pluginDir.monitor(Gio.FileMonitorFlags.NONE, null);
|
||||||
|
monitor.connect('changed', () => { this._vpnCacheBuilt = false; });
|
||||||
|
} catch(e) {
|
||||||
|
log('Failed to create monitor for VPN plugin dir: ' + e.message);
|
||||||
|
}
|
||||||
|
|
||||||
this._native.connect('new-request', Lang.bind(this, this._newRequest));
|
this._native.connect('new-request', Lang.bind(this, this._newRequest));
|
||||||
this._native.connect('cancel-request', Lang.bind(this, this._cancelRequest));
|
this._native.connect('cancel-request', Lang.bind(this, this._cancelRequest));
|
||||||
|
|
||||||
@ -765,9 +773,8 @@ const NetworkAgent = new Lang.Class({
|
|||||||
this._vpnCacheBuilt = true;
|
this._vpnCacheBuilt = true;
|
||||||
this._vpnBinaries = { };
|
this._vpnBinaries = { };
|
||||||
|
|
||||||
let dir = Gio.file_new_for_path(GLib.build_filenamev([Config.SYSCONFDIR, 'NetworkManager/VPN']));
|
|
||||||
try {
|
try {
|
||||||
let fileEnum = dir.enumerate_children('standard::name', Gio.FileQueryInfoFlags.NONE, null);
|
let fileEnum = this._pluginDir.enumerate_children('standard::name', Gio.FileQueryInfoFlags.NONE, null);
|
||||||
let info;
|
let info;
|
||||||
|
|
||||||
while ((info = fileEnum.next_file(null))) {
|
while ((info = fileEnum.next_file(null))) {
|
||||||
@ -777,7 +784,7 @@ const NetworkAgent = new Lang.Class({
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
let keyfile = new GLib.KeyFile();
|
let keyfile = new GLib.KeyFile();
|
||||||
keyfile.load_from_file(dir.get_child(name).get_path(), GLib.KeyFileFlags.NONE);
|
keyfile.load_from_file(this._pluginDir.get_child(name).get_path(), GLib.KeyFileFlags.NONE);
|
||||||
let service = keyfile.get_string('VPN Connection', 'service');
|
let service = keyfile.get_string('VPN Connection', 'service');
|
||||||
let binary = keyfile.get_string('GNOME', 'auth-dialog');
|
let binary = keyfile.get_string('GNOME', 'auth-dialog');
|
||||||
let externalUIMode = false;
|
let externalUIMode = false;
|
||||||
@ -810,7 +817,7 @@ const NetworkAgent = new Lang.Class({
|
|||||||
}
|
}
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
log('Error \'%s\' while processing VPN keyfile \'%s\''.
|
log('Error \'%s\' while processing VPN keyfile \'%s\''.
|
||||||
format(e.message, dir.get_child(name).get_path()));
|
format(e.message, this._pluginDir.get_child(name).get_path()));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -298,7 +298,7 @@ const AuthenticationDialog = new Lang.Class({
|
|||||||
* requested authentication was not gained; this can happen
|
* requested authentication was not gained; this can happen
|
||||||
* because of an authentication error (like invalid password),
|
* because of an authentication error (like invalid password),
|
||||||
* for instance. */
|
* 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._errorMessageLabel.show();
|
||||||
this._infoMessageLabel.hide();
|
this._infoMessageLabel.hide();
|
||||||
this._nullMessageLabel.hide();
|
this._nullMessageLabel.hide();
|
||||||
|
@ -6,11 +6,17 @@ const GLib = imports.gi.GLib;
|
|||||||
const Gtk = imports.gi.Gtk;
|
const Gtk = imports.gi.Gtk;
|
||||||
const Lang = imports.lang;
|
const Lang = imports.lang;
|
||||||
const Mainloop = imports.mainloop;
|
const Mainloop = imports.mainloop;
|
||||||
const Shell = imports.gi.Shell;
|
|
||||||
const Signals = imports.signals;
|
const Signals = imports.signals;
|
||||||
const St = imports.gi.St;
|
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 History = imports.misc.history;
|
||||||
const Main = imports.ui.main;
|
const Main = imports.ui.main;
|
||||||
@ -20,6 +26,8 @@ const Params = imports.misc.params;
|
|||||||
const PopupMenu = imports.ui.popupMenu;
|
const PopupMenu = imports.ui.popupMenu;
|
||||||
const Util = imports.misc.util;
|
const Util = imports.misc.util;
|
||||||
|
|
||||||
|
const HAVE_TP = (Tp != null && Tpl != null);
|
||||||
|
|
||||||
// See Notification.appendMessage
|
// See Notification.appendMessage
|
||||||
const SCROLLBACK_IMMEDIATE_TIME = 3 * 60; // 3 minutes
|
const SCROLLBACK_IMMEDIATE_TIME = 3 * 60; // 3 minutes
|
||||||
const SCROLLBACK_RECENT_TIME = 15 * 60; // 15 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',
|
Name: 'TelepathyClient',
|
||||||
|
Extends: Tp.BaseClient,
|
||||||
|
|
||||||
_init: function() {
|
_init: function() {
|
||||||
// channel path -> ChatSource
|
// channel path -> ChatSource
|
||||||
@ -97,39 +140,28 @@ const TelepathyClient = new Lang.Class({
|
|||||||
// channel matching its filters is detected.
|
// channel matching its filters is detected.
|
||||||
// The second argument, recover, means _observeChannels will be run
|
// The second argument, recover, means _observeChannels will be run
|
||||||
// for any existing channel as well.
|
// for any existing channel as well.
|
||||||
this._tpClient = new Shell.TpClient({ name: 'GnomeShell',
|
this.parent({ name: 'GnomeShell',
|
||||||
account_manager: this._accountManager,
|
account_manager: this._accountManager,
|
||||||
uniquify_name: true });
|
uniquify_name: true });
|
||||||
this._tpClient.set_observe_channels_func(
|
|
||||||
Lang.bind(this, this._observeChannels));
|
// We only care about single-user text-based chats
|
||||||
this._tpClient.set_approve_channels_func(
|
let filter = {};
|
||||||
Lang.bind(this, this._approveChannels));
|
filter[Tp.PROP_CHANNEL_CHANNEL_TYPE] = Tp.IFACE_CHANNEL_TYPE_TEXT;
|
||||||
this._tpClient.set_handle_channels_func(
|
filter[Tp.PROP_CHANNEL_TARGET_HANDLE_TYPE] = Tp.HandleType.CONTACT;
|
||||||
Lang.bind(this, this._handleChannels));
|
|
||||||
|
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
|
// Allow other clients (such as Empathy) to pre-empt our channels if
|
||||||
// needed
|
// needed
|
||||||
this._tpClient.set_delegated_channels_callback(
|
this.set_delegated_channels_callback(
|
||||||
Lang.bind(this, this._delegatedChannelsCb));
|
Lang.bind(this, this._delegatedChannelsCb));
|
||||||
},
|
},
|
||||||
|
|
||||||
enable: function() {
|
vfunc_observe_channels: function(account, conn, channels,
|
||||||
try {
|
dispatchOp, requests, context) {
|
||||||
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) {
|
|
||||||
let len = channels.length;
|
let len = channels.length;
|
||||||
for (let i = 0; i < len; i++) {
|
for (let i = 0; i < len; i++) {
|
||||||
let channel = channels[i];
|
let channel = channels[i];
|
||||||
@ -153,7 +185,7 @@ const TelepathyClient = new Lang.Class({
|
|||||||
if (this._chatSources[channel.get_object_path()])
|
if (this._chatSources[channel.get_object_path()])
|
||||||
return;
|
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;
|
this._chatSources[channel.get_object_path()] = source;
|
||||||
source.connect('destroy', Lang.bind(this,
|
source.connect('destroy', Lang.bind(this,
|
||||||
@ -162,8 +194,8 @@ const TelepathyClient = new Lang.Class({
|
|||||||
}));
|
}));
|
||||||
},
|
},
|
||||||
|
|
||||||
_handleChannels: function(handler, account, conn, channels,
|
vfunc_handle_channels: function(account, conn, channels, requests,
|
||||||
requests, user_action_time, context) {
|
user_action_time, context) {
|
||||||
this._handlingChannels(account, conn, channels, true);
|
this._handlingChannels(account, conn, channels, true);
|
||||||
context.accept();
|
context.accept();
|
||||||
},
|
},
|
||||||
@ -193,7 +225,7 @@ const TelepathyClient = new Lang.Class({
|
|||||||
// Telepathy spec states that handlers must foreground channels
|
// Telepathy spec states that handlers must foreground channels
|
||||||
// in HandleChannels calls which are already being handled.
|
// 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
|
// We are already handling the channel, display the source
|
||||||
let source = this._chatSources[channel.get_object_path()];
|
let source = this._chatSources[channel.get_object_path()];
|
||||||
if (source)
|
if (source)
|
||||||
@ -202,8 +234,8 @@ const TelepathyClient = new Lang.Class({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
_approveChannels: function(approver, account, conn, channels,
|
vfunc_add_dispatch_operation: function(account, conn, channels,
|
||||||
dispatchOp, context) {
|
dispatchOp, context) {
|
||||||
let channel = channels[0];
|
let channel = channels[0];
|
||||||
let chanType = channel.get_channel_type();
|
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
|
// 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 {
|
try {
|
||||||
dispatchOp.claim_with_finish(result);
|
dispatchOp.claim_with_finish(result);
|
||||||
this._handlingChannels(account, conn, [channel], false);
|
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
|
// Nothing to do as we don't make a distinction between observed and
|
||||||
// handled channels.
|
// handled channels.
|
||||||
},
|
},
|
||||||
});
|
}) : null;
|
||||||
|
|
||||||
const ChatSource = new Lang.Class({
|
const ChatSource = new Lang.Class({
|
||||||
Name: 'ChatSource',
|
Name: 'ChatSource',
|
||||||
@ -660,7 +692,9 @@ const ChatNotification = new Lang.Class({
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (message.direction == NotificationDirection.RECEIVED)
|
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 ?
|
let group = (message.direction == NotificationDirection.RECEIVED ?
|
||||||
'received' : 'sent');
|
'received' : 'sent');
|
||||||
@ -962,4 +996,4 @@ const ChatNotificationBanner = new Lang.Class({
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const Component = TelepathyClient;
|
const Component = TelepathyComponent;
|
||||||
|
@ -8,6 +8,7 @@ const Gtk = imports.gi.Gtk;
|
|||||||
const GWeather = imports.gi.GWeather;
|
const GWeather = imports.gi.GWeather;
|
||||||
const Lang = imports.lang;
|
const Lang = imports.lang;
|
||||||
const Mainloop = imports.mainloop;
|
const Mainloop = imports.mainloop;
|
||||||
|
const Pango = imports.gi.Pango;
|
||||||
const Cairo = imports.cairo;
|
const Cairo = imports.cairo;
|
||||||
const Clutter = imports.gi.Clutter;
|
const Clutter = imports.gi.Clutter;
|
||||||
const Shell = imports.gi.Shell;
|
const Shell = imports.gi.Shell;
|
||||||
@ -20,6 +21,7 @@ const Main = imports.ui.main;
|
|||||||
const PanelMenu = imports.ui.panelMenu;
|
const PanelMenu = imports.ui.panelMenu;
|
||||||
const PopupMenu = imports.ui.popupMenu;
|
const PopupMenu = imports.ui.popupMenu;
|
||||||
const Calendar = imports.ui.calendar;
|
const Calendar = imports.ui.calendar;
|
||||||
|
const Weather = imports.misc.weather;
|
||||||
|
|
||||||
function _isToday(date) {
|
function _isToday(date) {
|
||||||
let now = new 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
|
// on the current date can be confusing. So don't make the button reactive
|
||||||
// until the selected date changes.
|
// until the selected date changes.
|
||||||
this.actor = new St.Button({ style_class: 'datemenu-today-button',
|
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,
|
can_focus: true,
|
||||||
reactive: false
|
reactive: false
|
||||||
});
|
});
|
||||||
@ -77,7 +79,7 @@ const TodayButton = new Lang.Class({
|
|||||||
* below the time in the shell; it should combine the weekday and the
|
* below the time in the shell; it should combine the weekday and the
|
||||||
* date, e.g. "Tuesday February 17 2015".
|
* 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);
|
this.actor.accessible_name = date.toLocaleFormat(dateFormat);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -87,9 +89,7 @@ const WorldClocksSection = new Lang.Class({
|
|||||||
|
|
||||||
_init: function() {
|
_init: function() {
|
||||||
this._clock = new GnomeDesktop.WallClock();
|
this._clock = new GnomeDesktop.WallClock();
|
||||||
this._settings = null;
|
|
||||||
this._clockNotifyId = 0;
|
this._clockNotifyId = 0;
|
||||||
this._changedId = 0;
|
|
||||||
|
|
||||||
this._locations = [];
|
this._locations = [];
|
||||||
|
|
||||||
@ -98,8 +98,7 @@ const WorldClocksSection = new Lang.Class({
|
|||||||
can_focus: true });
|
can_focus: true });
|
||||||
this.actor.connect('clicked', Lang.bind(this,
|
this.actor.connect('clicked', Lang.bind(this,
|
||||||
function() {
|
function() {
|
||||||
let app = this._getClockApp();
|
this._clockAppMon.activateApp();
|
||||||
app.activate();
|
|
||||||
|
|
||||||
Main.overview.hide();
|
Main.overview.hide();
|
||||||
Main.panel.closeCalendar();
|
Main.panel.closeCalendar();
|
||||||
@ -112,40 +111,25 @@ const WorldClocksSection = new Lang.Class({
|
|||||||
|
|
||||||
this.actor.child = this._grid;
|
this.actor.child = this._grid;
|
||||||
|
|
||||||
Shell.AppSystem.get_default().connect('installed-changed',
|
this._clockAppMon = new Util.AppSettingsMonitor('org.gnome.clocks.desktop',
|
||||||
Lang.bind(this, this._sync));
|
'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();
|
this._sync();
|
||||||
},
|
},
|
||||||
|
|
||||||
_getClockApp: function() {
|
|
||||||
return Shell.AppSystem.get_default().lookup_app('org.gnome.clocks.desktop');
|
|
||||||
},
|
|
||||||
|
|
||||||
_sync: function() {
|
_sync: function() {
|
||||||
this.actor.visible = (this._getClockApp() != null);
|
this.actor.visible = this._clockAppMon.available;
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_clocksChanged: function() {
|
_clocksChanged: function(settings) {
|
||||||
this._grid.destroy_all_children();
|
this._grid.destroy_all_children();
|
||||||
this._locations = [];
|
this._locations = [];
|
||||||
|
|
||||||
let world = GWeather.Location.get_world();
|
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++) {
|
for (let i = 0; i < clocks.length; i++) {
|
||||||
let l = world.deserialize(clocks[i].location);
|
let l = world.deserialize(clocks[i].location);
|
||||||
this._locations.push({ location: l });
|
this._locations.push({ location: l });
|
||||||
@ -210,6 +194,133 @@ 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.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({
|
const MessagesIndicator = new Lang.Class({
|
||||||
Name: 'MessagesIndicator',
|
Name: 'MessagesIndicator',
|
||||||
|
|
||||||
@ -297,14 +408,38 @@ const FreezableBinLayout = new Lang.Class({
|
|||||||
|
|
||||||
vfunc_get_preferred_width: function(container, forHeight) {
|
vfunc_get_preferred_width: function(container, forHeight) {
|
||||||
if (!this._frozen || this._savedWidth.some(isNaN))
|
if (!this._frozen || this._savedWidth.some(isNaN))
|
||||||
this._savedWidth = this.parent(container, forHeight);
|
return this.parent(container, forHeight);
|
||||||
return this._savedWidth;
|
return this._savedWidth;
|
||||||
},
|
},
|
||||||
|
|
||||||
vfunc_get_preferred_height: function(container, forWidth) {
|
vfunc_get_preferred_height: function(container, forWidth) {
|
||||||
if (!this._frozen || this._savedHeight.some(isNaN))
|
if (!this._frozen || this._savedHeight.some(isNaN))
|
||||||
this._savedHeight = this.parent(container, forWidth);
|
return this.parent(container, forWidth);
|
||||||
return this._savedHeight;
|
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);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -364,14 +499,16 @@ const DateMenuButton = new Lang.Class({
|
|||||||
hbox.add(this._messageList.actor, { expand: true, y_fill: false, y_align: St.Align.START });
|
hbox.add(this._messageList.actor, { expand: true, y_fill: false, y_align: St.Align.START });
|
||||||
|
|
||||||
// Fill up the second column
|
// Fill up the second column
|
||||||
vbox = new St.BoxLayout({ style_class: 'datemenu-calendar-column',
|
let boxLayout = new CalendarColumnLayout(this._calendar.actor);
|
||||||
vertical: true });
|
vbox = new St.Widget({ style_class: 'datemenu-calendar-column',
|
||||||
|
layout_manager: boxLayout });
|
||||||
|
boxLayout.hookup_style(vbox);
|
||||||
hbox.add(vbox);
|
hbox.add(vbox);
|
||||||
|
|
||||||
this._date = new TodayButton(this._calendar);
|
this._date = new TodayButton(this._calendar);
|
||||||
vbox.add_actor(this._date.actor);
|
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',
|
this._displaysSection = new St.ScrollView({ style_class: 'datemenu-displays-section vfade',
|
||||||
x_expand: true, x_fill: true,
|
x_expand: true, x_fill: true,
|
||||||
@ -386,6 +523,8 @@ const DateMenuButton = new Lang.Class({
|
|||||||
this._clocksItem = new WorldClocksSection();
|
this._clocksItem = new WorldClocksSection();
|
||||||
displaysBox.add(this._clocksItem.actor, { x_fill: true });
|
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
|
// Done with hbox for calendar and event list
|
||||||
|
|
||||||
|
@ -14,6 +14,7 @@ const DRAG_DISTANCE = 80;
|
|||||||
const EdgeDragAction = new Lang.Class({
|
const EdgeDragAction = new Lang.Class({
|
||||||
Name: 'EdgeDragAction',
|
Name: 'EdgeDragAction',
|
||||||
Extends: Clutter.GestureAction,
|
Extends: Clutter.GestureAction,
|
||||||
|
Signals: { 'activated': {} },
|
||||||
|
|
||||||
_init : function(side, allowedModes) {
|
_init : function(side, allowedModes) {
|
||||||
this.parent();
|
this.parent();
|
||||||
@ -81,4 +82,3 @@ const EdgeDragAction = new Lang.Class({
|
|||||||
this.emit('activated');
|
this.emit('activated');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
Signals.addSignalMethods(EdgeDragAction.prototype);
|
|
||||||
|
@ -457,7 +457,6 @@ const EndSessionDialog = new Lang.Class({
|
|||||||
_setLabelText(this._descriptionLabel, description);
|
_setLabelText(this._descriptionLabel, description);
|
||||||
_setLabelText(this._subjectLabel, subject);
|
_setLabelText(this._subjectLabel, subject);
|
||||||
|
|
||||||
let dialogContent = DialogContent[this._type];
|
|
||||||
if (dialogContent.iconName) {
|
if (dialogContent.iconName) {
|
||||||
this._iconBin.child = new St.Icon({ icon_name: dialogContent.iconName,
|
this._iconBin.child = new St.Icon({ icon_name: dialogContent.iconName,
|
||||||
icon_size: _DIALOG_ICON_SIZE,
|
icon_size: _DIALOG_ICON_SIZE,
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
// -*- 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.Gio = '2.0';
|
||||||
imports.gi.versions.Gdk = '3.0';
|
imports.gi.versions.Gdk = '3.0';
|
||||||
imports.gi.versions.GdkPixbuf = '2.0';
|
imports.gi.versions.GdkPixbuf = '2.0';
|
||||||
@ -61,10 +63,19 @@ function _patchLayoutClass(layoutClass, styleProps) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function _makeLoggingFunc(func) {
|
function _loggingFunc() {
|
||||||
return function() {
|
let fields = {'MESSAGE': [].join.call(arguments, ', ')};
|
||||||
return func([].join.call(arguments, ', '));
|
let domain = "GNOME Shell";
|
||||||
};
|
|
||||||
|
// If the caller is an extension, add it as metadata
|
||||||
|
let extension = imports.misc.extensionUtils.getCurrentExtension();
|
||||||
|
if (extension != null) {
|
||||||
|
domain = extension.metadata.name;
|
||||||
|
fields['GNOME_SHELL_EXTENSION_UUID'] = extension.uuid;
|
||||||
|
fields['GNOME_SHELL_EXTENSION_NAME'] = extension.metadata.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
GLib.log_structured(domain, GLib.LogLevelFlags.LEVEL_MESSAGE, fields);
|
||||||
}
|
}
|
||||||
|
|
||||||
function init() {
|
function init() {
|
||||||
@ -72,7 +83,7 @@ function init() {
|
|||||||
// browser convention of having that namespace be called 'window'.)
|
// browser convention of having that namespace be called 'window'.)
|
||||||
window.global = Shell.Global.get();
|
window.global = Shell.Global.get();
|
||||||
|
|
||||||
window.log = _makeLoggingFunc(window.log);
|
window.log = _loggingFunc;
|
||||||
|
|
||||||
window._ = Gettext.gettext;
|
window._ = Gettext.gettext;
|
||||||
window.C_ = Gettext.pgettext;
|
window.C_ = Gettext.pgettext;
|
||||||
|
@ -252,7 +252,7 @@ const InstallExtensionDialog = new Lang.Class({
|
|||||||
return;
|
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) {
|
_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 disconnect = Lang.bind(_signals, _signals.disconnect);
|
||||||
|
|
||||||
const ENABLED_EXTENSIONS_KEY = 'enabled-extensions';
|
const ENABLED_EXTENSIONS_KEY = 'enabled-extensions';
|
||||||
|
const DISABLE_USER_EXTENSIONS_KEY = 'disable-user-extensions';
|
||||||
const EXTENSION_DISABLE_VERSION_CHECK_KEY = 'disable-extension-version-validation';
|
const EXTENSION_DISABLE_VERSION_CHECK_KEY = 'disable-extension-version-validation';
|
||||||
|
|
||||||
var initted = false;
|
var initted = false;
|
||||||
@ -238,11 +239,16 @@ function initExtension(uuid) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function getEnabledExtensions() {
|
function getEnabledExtensions() {
|
||||||
let extensions = global.settings.get_strv(ENABLED_EXTENSIONS_KEY);
|
let extensions;
|
||||||
if (!Array.isArray(Main.sessionMode.enabledExtensions))
|
if (Array.isArray(Main.sessionMode.enabledExtensions))
|
||||||
|
extensions = Main.sessionMode.enabledExtensions;
|
||||||
|
else
|
||||||
|
extensions = [];
|
||||||
|
|
||||||
|
if (global.settings.get_boolean(DISABLE_USER_EXTENSIONS_KEY))
|
||||||
return extensions;
|
return extensions;
|
||||||
|
|
||||||
return Main.sessionMode.enabledExtensions.concat(extensions);
|
return extensions.concat(global.settings.get_strv(ENABLED_EXTENSIONS_KEY));
|
||||||
}
|
}
|
||||||
|
|
||||||
function onEnabledExtensionsChanged() {
|
function onEnabledExtensionsChanged() {
|
||||||
@ -288,6 +294,7 @@ function _onVersionValidationChanged() {
|
|||||||
|
|
||||||
function _loadExtensions() {
|
function _loadExtensions() {
|
||||||
global.settings.connect('changed::' + ENABLED_EXTENSIONS_KEY, onEnabledExtensionsChanged);
|
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);
|
global.settings.connect('changed::' + EXTENSION_DISABLE_VERSION_CHECK_KEY, _onVersionValidationChanged);
|
||||||
|
|
||||||
enabledExtensions = getEnabledExtensions();
|
enabledExtensions = getEnabledExtensions();
|
||||||
|
@ -19,6 +19,7 @@ const CandidateArea = new Lang.Class({
|
|||||||
|
|
||||||
_init: function() {
|
_init: function() {
|
||||||
this.actor = new St.BoxLayout({ vertical: true,
|
this.actor = new St.BoxLayout({ vertical: true,
|
||||||
|
reactive: true,
|
||||||
visible: false });
|
visible: false });
|
||||||
this._candidateBoxes = [];
|
this._candidateBoxes = [];
|
||||||
for (let i = 0; i < MAX_CANDIDATES_PER_PAGE; ++i) {
|
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._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' });
|
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._candidateArea.connect('next-page', Lang.bind(this, function() {
|
||||||
this._panelService.page_down();
|
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._candidateArea.connect('candidate-clicked', Lang.bind(this, function(ca, index, button, state) {
|
||||||
this._panelService.candidate_clicked(index, button, state);
|
this._panelService.candidate_clicked(index, button, state);
|
||||||
}));
|
}));
|
||||||
|
@ -33,7 +33,6 @@ var commandHeader = 'const Clutter = imports.gi.Clutter; ' +
|
|||||||
'const Mainloop = imports.mainloop; ' +
|
'const Mainloop = imports.mainloop; ' +
|
||||||
'const Meta = imports.gi.Meta; ' +
|
'const Meta = imports.gi.Meta; ' +
|
||||||
'const Shell = imports.gi.Shell; ' +
|
'const Shell = imports.gi.Shell; ' +
|
||||||
'const Tp = imports.gi.TelepathyGLib; ' +
|
|
||||||
'const Main = imports.ui.main; ' +
|
'const Main = imports.ui.main; ' +
|
||||||
'const Lang = imports.lang; ' +
|
'const Lang = imports.lang; ' +
|
||||||
'const Tweener = imports.ui.tweener; ' +
|
'const Tweener = imports.ui.tweener; ' +
|
||||||
|
@ -26,6 +26,7 @@ const ModalDialog = imports.ui.modalDialog;
|
|||||||
const OsdWindow = imports.ui.osdWindow;
|
const OsdWindow = imports.ui.osdWindow;
|
||||||
const OsdMonitorLabeler = imports.ui.osdMonitorLabeler;
|
const OsdMonitorLabeler = imports.ui.osdMonitorLabeler;
|
||||||
const Overview = imports.ui.overview;
|
const Overview = imports.ui.overview;
|
||||||
|
const PadOsd = imports.ui.padOsd;
|
||||||
const Panel = imports.ui.panel;
|
const Panel = imports.ui.panel;
|
||||||
const Params = imports.misc.params;
|
const Params = imports.misc.params;
|
||||||
const RunDialog = imports.ui.runDialog;
|
const RunDialog = imports.ui.runDialog;
|
||||||
@ -61,6 +62,7 @@ let screenShield = null;
|
|||||||
let notificationDaemon = null;
|
let notificationDaemon = null;
|
||||||
let windowAttentionHandler = null;
|
let windowAttentionHandler = null;
|
||||||
let ctrlAltTabManager = null;
|
let ctrlAltTabManager = null;
|
||||||
|
let padOsdService = null;
|
||||||
let osdWindowManager = null;
|
let osdWindowManager = null;
|
||||||
let osdMonitorLabeler = null;
|
let osdMonitorLabeler = null;
|
||||||
let sessionMode = null;
|
let sessionMode = null;
|
||||||
@ -155,6 +157,7 @@ function _initializeUI() {
|
|||||||
// working until it's updated.
|
// working until it's updated.
|
||||||
uiGroup = layoutManager.uiGroup;
|
uiGroup = layoutManager.uiGroup;
|
||||||
|
|
||||||
|
padOsdService = new PadOsd.PadOsdService();
|
||||||
screencastService = new Screencast.ScreencastService();
|
screencastService = new Screencast.ScreencastService();
|
||||||
xdndHandler = new XdndHandler.XdndHandler();
|
xdndHandler = new XdndHandler.XdndHandler();
|
||||||
ctrlAltTabManager = new CtrlAltTab.CtrlAltTabManager();
|
ctrlAltTabManager = new CtrlAltTab.CtrlAltTabManager();
|
||||||
|
@ -318,6 +318,7 @@ const Message = new Lang.Class({
|
|||||||
|
|
||||||
this._iconBin = new St.Bin({ style_class: 'message-icon-bin',
|
this._iconBin = new St.Bin({ style_class: 'message-icon-bin',
|
||||||
y_expand: true,
|
y_expand: true,
|
||||||
|
y_align: St.Align.START,
|
||||||
visible: false });
|
visible: false });
|
||||||
hbox.add_actor(this._iconBin);
|
hbox.add_actor(this._iconBin);
|
||||||
|
|
||||||
@ -331,18 +332,18 @@ const Message = new Lang.Class({
|
|||||||
let titleBox = new St.BoxLayout();
|
let titleBox = new St.BoxLayout();
|
||||||
contentBox.add_actor(titleBox);
|
contentBox.add_actor(titleBox);
|
||||||
|
|
||||||
this.titleLabel = new St.Label({ style_class: 'message-title',
|
this.titleLabel = new St.Label({ style_class: 'message-title' });
|
||||||
x_expand: true,
|
|
||||||
x_align: Clutter.ActorAlign.START });
|
|
||||||
this.setTitle(title);
|
this.setTitle(title);
|
||||||
titleBox.add_actor(this.titleLabel);
|
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);
|
titleBox.add_actor(this._secondaryBin);
|
||||||
|
|
||||||
let closeIcon = new St.Icon({ icon_name: 'window-close-symbolic',
|
let closeIcon = new St.Icon({ icon_name: 'window-close-symbolic',
|
||||||
icon_size: 16 });
|
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);
|
titleBox.add_actor(this._closeButton);
|
||||||
|
|
||||||
this._bodyStack = new St.Widget({ x_expand: true });
|
this._bodyStack = new St.Widget({ x_expand: true });
|
||||||
@ -493,9 +494,8 @@ const Message = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
_sync: function() {
|
_sync: function() {
|
||||||
let hovered = this.actor.hover;
|
let visible = this.actor.hover && this.canClose();
|
||||||
this._closeButton.visible = hovered && this.canClose();
|
this._closeButton.opacity = visible ? 255 : 0;
|
||||||
this._secondaryBin.visible = !hovered;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_onClicked: function() {
|
_onClicked: function() {
|
||||||
@ -520,32 +520,10 @@ Signals.addSignalMethods(Message.prototype);
|
|||||||
const MessageListSection = new Lang.Class({
|
const MessageListSection = new Lang.Class({
|
||||||
Name: 'MessageListSection',
|
Name: 'MessageListSection',
|
||||||
|
|
||||||
_init: function(title) {
|
_init: function() {
|
||||||
this.actor = new St.BoxLayout({ style_class: 'message-list-section',
|
this.actor = new St.BoxLayout({ style_class: 'message-list-section',
|
||||||
clip_to_allocation: true,
|
clip_to_allocation: true,
|
||||||
x_expand: true, vertical: 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',
|
this._list = new St.BoxLayout({ style_class: 'message-list-section-list',
|
||||||
vertical: true });
|
vertical: true });
|
||||||
@ -563,14 +541,10 @@ const MessageListSection = new Lang.Class({
|
|||||||
this._messages = new Map();
|
this._messages = new Map();
|
||||||
this._date = new Date();
|
this._date = new Date();
|
||||||
this.empty = true;
|
this.empty = true;
|
||||||
|
this.canClear = false;
|
||||||
this._sync();
|
this._sync();
|
||||||
},
|
},
|
||||||
|
|
||||||
_onTitleClicked: function() {
|
|
||||||
Main.overview.hide();
|
|
||||||
Main.panel.closeCalendar();
|
|
||||||
},
|
|
||||||
|
|
||||||
_onKeyFocusIn: function(actor) {
|
_onKeyFocusIn: function(actor) {
|
||||||
this.emit('key-focus-in', actor);
|
this.emit('key-focus-in', actor);
|
||||||
},
|
},
|
||||||
@ -719,7 +693,13 @@ const MessageListSection = new Lang.Class({
|
|||||||
if (changed)
|
if (changed)
|
||||||
this.emit('empty-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();
|
this.actor.visible = this.allowed && this._shouldShow();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -368,6 +368,7 @@ const Notification = new Lang.Class({
|
|||||||
secondaryGIcon: null,
|
secondaryGIcon: null,
|
||||||
bannerMarkup: false,
|
bannerMarkup: false,
|
||||||
clear: false,
|
clear: false,
|
||||||
|
datetime: null,
|
||||||
soundName: null,
|
soundName: null,
|
||||||
soundFile: null });
|
soundFile: null });
|
||||||
|
|
||||||
@ -375,6 +376,11 @@ const Notification = new Lang.Class({
|
|||||||
this.bannerBodyText = banner;
|
this.bannerBodyText = banner;
|
||||||
this.bannerBodyMarkup = params.bannerMarkup;
|
this.bannerBodyMarkup = params.bannerMarkup;
|
||||||
|
|
||||||
|
if (params.datetime)
|
||||||
|
this.datetime = params.datetime;
|
||||||
|
else
|
||||||
|
this.datetime = GLib.DateTime.new_now_local();
|
||||||
|
|
||||||
if (params.gicon || params.clear)
|
if (params.gicon || params.clear)
|
||||||
this.gicon = params.gicon;
|
this.gicon = params.gicon;
|
||||||
|
|
||||||
@ -535,7 +541,8 @@ const NotificationBanner = new Lang.Class({
|
|||||||
|
|
||||||
_addSecondaryIcon: function() {
|
_addSecondaryIcon: function() {
|
||||||
if (this.notification.secondaryGIcon) {
|
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);
|
this.setSecondaryActor(icon);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -796,7 +803,7 @@ const Source = new Lang.Class({
|
|||||||
notification.acknowledged = false;
|
notification.acknowledged = false;
|
||||||
this.pushNotification(notification);
|
this.pushNotification(notification);
|
||||||
|
|
||||||
if (this.policy.showBanners) {
|
if (this.policy.showBanners || notification.urgency == Urgency.CRITICAL) {
|
||||||
this.emit('notify', notification);
|
this.emit('notify', notification);
|
||||||
} else {
|
} else {
|
||||||
notification.playSound();
|
notification.playSound();
|
||||||
@ -1224,7 +1231,7 @@ const MessageTray = new Lang.Class({
|
|||||||
if (this._notificationState == State.HIDDEN) {
|
if (this._notificationState == State.HIDDEN) {
|
||||||
let nextNotification = this._notificationQueue[0] || null;
|
let nextNotification = this._notificationQueue[0] || null;
|
||||||
if (hasNotifications && nextNotification) {
|
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);
|
let showNextNotification = (!limited || nextNotification.forFeedback || nextNotification.urgency == Urgency.CRITICAL);
|
||||||
if (showNextNotification)
|
if (showNextNotification)
|
||||||
this._showNotification();
|
this._showNotification();
|
||||||
|
@ -36,6 +36,8 @@ const MprisPlayerIface = '<node> \
|
|||||||
<method name="PlayPause" /> \
|
<method name="PlayPause" /> \
|
||||||
<method name="Next" /> \
|
<method name="Next" /> \
|
||||||
<method name="Previous" /> \
|
<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="CanPlay" type="b" access="read" /> \
|
||||||
<property name="Metadata" type="a{sv}" access="read" /> \
|
<property name="Metadata" type="a{sv}" access="read" /> \
|
||||||
<property name="PlaybackStatus" type="s" 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._icon = new St.Icon({ style_class: 'media-message-cover-icon' });
|
||||||
this.setIcon(this._icon);
|
this.setIcon(this._icon);
|
||||||
|
|
||||||
this.addMediaControl('media-skip-backward-symbolic',
|
this._prevButton = this.addMediaControl('media-skip-backward-symbolic',
|
||||||
Lang.bind(this, function() {
|
Lang.bind(this, function() {
|
||||||
this._player.previous();
|
this._player.previous();
|
||||||
}));
|
}));
|
||||||
@ -67,7 +69,7 @@ const MediaMessage = new Lang.Class({
|
|||||||
this._player.playPause();
|
this._player.playPause();
|
||||||
}));
|
}));
|
||||||
|
|
||||||
this.addMediaControl('media-skip-forward-symbolic',
|
this._nextButton = this.addMediaControl('media-skip-forward-symbolic',
|
||||||
Lang.bind(this, function() {
|
Lang.bind(this, function() {
|
||||||
this._player.next();
|
this._player.next();
|
||||||
}));
|
}));
|
||||||
@ -82,6 +84,10 @@ const MediaMessage = new Lang.Class({
|
|||||||
Main.panel.closeCalendar();
|
Main.panel.closeCalendar();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_updateNavButton: function(button, sensitive) {
|
||||||
|
button.reactive = sensitive;
|
||||||
|
},
|
||||||
|
|
||||||
_update: function() {
|
_update: function() {
|
||||||
this.setTitle(this._player.trackArtists.join(', '));
|
this.setTitle(this._player.trackArtists.join(', '));
|
||||||
this.setBody(this._player.trackTitle);
|
this.setBody(this._player.trackTitle);
|
||||||
@ -99,6 +105,9 @@ const MediaMessage = new Lang.Class({
|
|||||||
let iconName = isPlaying ? 'media-playback-pause-symbolic'
|
let iconName = isPlaying ? 'media-playback-pause-symbolic'
|
||||||
: 'media-playback-start-symbolic';
|
: 'media-playback-start-symbolic';
|
||||||
this._playPauseButton.child.icon_name = iconName;
|
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();
|
this._playerProxy.PlayPauseRemote();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
get canGoNext() {
|
||||||
|
return this._playerProxy.CanGoNext;
|
||||||
|
},
|
||||||
|
|
||||||
next: function() {
|
next: function() {
|
||||||
this._playerProxy.NextRemote();
|
this._playerProxy.NextRemote();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
get canGoPrevious() {
|
||||||
|
return this._playerProxy.CanGoPrevious;
|
||||||
|
},
|
||||||
|
|
||||||
previous: function() {
|
previous: function() {
|
||||||
this._playerProxy.PreviousRemote();
|
this._playerProxy.PreviousRemote();
|
||||||
},
|
},
|
||||||
@ -214,7 +231,7 @@ const MediaSection = new Lang.Class({
|
|||||||
Extends: MessageList.MessageListSection,
|
Extends: MessageList.MessageListSection,
|
||||||
|
|
||||||
_init: function() {
|
_init: function() {
|
||||||
this.parent(_("Media"));
|
this.parent();
|
||||||
|
|
||||||
this._players = new Map();
|
this._players = new Map();
|
||||||
|
|
||||||
|
@ -186,7 +186,7 @@ const FdoNotificationDaemon = new Lang.Class({
|
|||||||
return source;
|
return source;
|
||||||
}
|
}
|
||||||
|
|
||||||
let source = new FdoNotificationDaemonSource(title, pid, sender, ndata ? ndata.hints['desktop-entry'] : null);
|
source = new FdoNotificationDaemonSource(title, pid, sender, ndata ? ndata.hints['desktop-entry'] : null);
|
||||||
|
|
||||||
this._sources.push(source);
|
this._sources.push(source);
|
||||||
source.connect('destroy', Lang.bind(this, function() {
|
source.connect('destroy', Lang.bind(this, function() {
|
||||||
@ -600,7 +600,8 @@ const GtkNotificationDaemonNotification = new Lang.Class({
|
|||||||
"priority": priority,
|
"priority": priority,
|
||||||
"buttons": buttons,
|
"buttons": buttons,
|
||||||
"default-action": defaultAction,
|
"default-action": defaultAction,
|
||||||
"default-action-target": defaultActionTarget } = notification;
|
"default-action-target": defaultActionTarget,
|
||||||
|
"timestamp": time } = notification;
|
||||||
|
|
||||||
if (priority) {
|
if (priority) {
|
||||||
let urgency = PRIORITY_URGENCY_MAP[priority.unpack()];
|
let urgency = PRIORITY_URGENCY_MAP[priority.unpack()];
|
||||||
@ -623,7 +624,8 @@ const GtkNotificationDaemonNotification = new Lang.Class({
|
|||||||
this._defaultActionTarget = defaultActionTarget;
|
this._defaultActionTarget = defaultActionTarget;
|
||||||
|
|
||||||
this.update(title.unpack(), body ? body.unpack() : null,
|
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) {
|
_activateAction: function(namespacedActionId, target) {
|
||||||
@ -690,6 +692,7 @@ const GtkNotificationDaemonAppSource = new Lang.Class({
|
|||||||
throw new InvalidAppError();
|
throw new InvalidAppError();
|
||||||
|
|
||||||
this._notifications = {};
|
this._notifications = {};
|
||||||
|
this._notificationPending = false;
|
||||||
|
|
||||||
this.parent(this._app.get_name());
|
this.parent(this._app.get_name());
|
||||||
},
|
},
|
||||||
@ -702,27 +705,35 @@ const GtkNotificationDaemonAppSource = new Lang.Class({
|
|||||||
return new MessageTray.NotificationApplicationPolicy(this._appId);
|
return new MessageTray.NotificationApplicationPolicy(this._appId);
|
||||||
},
|
},
|
||||||
|
|
||||||
_createApp: function() {
|
_createApp: function(callback) {
|
||||||
return new FdoApplicationProxy(Gio.DBus.session, this._appId, this._objectPath);
|
return new FdoApplicationProxy(Gio.DBus.session, this._appId, this._objectPath, callback);
|
||||||
},
|
},
|
||||||
|
|
||||||
activateAction: function(actionId, target) {
|
activateAction: function(actionId, target) {
|
||||||
let app = this._createApp();
|
this._createApp(function (app, error) {
|
||||||
app.ActivateActionRemote(actionId, target ? [target] : [], getPlatformData());
|
if (error == null)
|
||||||
|
app.ActivateActionRemote(actionId, target ? [target] : [], getPlatformData());
|
||||||
|
else
|
||||||
|
logError(error, 'Failed to activate application proxy');
|
||||||
|
});
|
||||||
Main.overview.hide();
|
Main.overview.hide();
|
||||||
Main.panel.closeCalendar();
|
Main.panel.closeCalendar();
|
||||||
},
|
},
|
||||||
|
|
||||||
open: function() {
|
open: function() {
|
||||||
let app = this._createApp();
|
this._createApp(function (app, error) {
|
||||||
app.ActivateRemote(getPlatformData());
|
if (error == null)
|
||||||
|
app.ActivateRemote(getPlatformData());
|
||||||
|
else
|
||||||
|
logError(error, 'Failed to open application proxy');
|
||||||
|
});
|
||||||
Main.overview.hide();
|
Main.overview.hide();
|
||||||
Main.panel.closeCalendar();
|
Main.panel.closeCalendar();
|
||||||
},
|
},
|
||||||
|
|
||||||
addNotification: function(notificationId, notificationParams, showBanner) {
|
addNotification: function(notificationId, notificationParams, showBanner) {
|
||||||
|
this._notificationPending = true;
|
||||||
|
|
||||||
if (this._notifications[notificationId])
|
if (this._notifications[notificationId])
|
||||||
this._notifications[notificationId].destroy();
|
this._notifications[notificationId].destroy();
|
||||||
|
|
||||||
@ -736,6 +747,14 @@ const GtkNotificationDaemonAppSource = new Lang.Class({
|
|||||||
this.notify(notification);
|
this.notify(notification);
|
||||||
else
|
else
|
||||||
this.pushNotification(notification);
|
this.pushNotification(notification);
|
||||||
|
|
||||||
|
this._notificationPending = false;
|
||||||
|
},
|
||||||
|
|
||||||
|
destroy: function(reason) {
|
||||||
|
if (this._notificationPending)
|
||||||
|
return;
|
||||||
|
this.parent(reason);
|
||||||
},
|
},
|
||||||
|
|
||||||
removeNotification: function(notificationId) {
|
removeNotification: function(notificationId) {
|
||||||
@ -847,6 +866,9 @@ const GtkNotificationDaemon = new Lang.Class({
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let timestamp = GLib.DateTime.new_now_local().to_unix();
|
||||||
|
notification['timestamp'] = new GLib.Variant('x', timestamp);
|
||||||
|
|
||||||
source.addNotification(notificationId, notification, true);
|
source.addNotification(notificationId, notification, true);
|
||||||
|
|
||||||
invocation.return_value(null);
|
invocation.return_value(null);
|
||||||
|
@ -72,8 +72,8 @@ const OsdWindowConstraint = new Lang.Class({
|
|||||||
|
|
||||||
// Recenter
|
// Recenter
|
||||||
let [x, y] = actorBox.get_origin();
|
let [x, y] = actorBox.get_origin();
|
||||||
actorBox.set_origin(Math.floor(x + width / 2 - size / 2),
|
actorBox.set_origin(Math.ceil(x + width / 2 - size / 2),
|
||||||
Math.floor(y + height / 2 - size / 2));
|
Math.ceil(y + height / 2 - size / 2));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -109,8 +109,11 @@ const OsdWindow = new Lang.Class({
|
|||||||
this._reset();
|
this._reset();
|
||||||
|
|
||||||
Main.layoutManager.connect('monitors-changed',
|
Main.layoutManager.connect('monitors-changed',
|
||||||
Lang.bind(this, this._monitorsChanged));
|
Lang.bind(this, this._relayout));
|
||||||
this._monitorsChanged();
|
let themeContext = St.ThemeContext.get_for_stage(global.stage);
|
||||||
|
themeContext.connect('notify::scale-factor',
|
||||||
|
Lang.bind(this, this._relayout));
|
||||||
|
this._relayout();
|
||||||
Main.uiGroup.add_child(this.actor);
|
Main.uiGroup.add_child(this.actor);
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -188,7 +191,7 @@ const OsdWindow = new Lang.Class({
|
|||||||
this.setLevel(null);
|
this.setLevel(null);
|
||||||
},
|
},
|
||||||
|
|
||||||
_monitorsChanged: function() {
|
_relayout: function() {
|
||||||
/* assume 110x110 on a 640x480 display and scale from there */
|
/* assume 110x110 on a 640x480 display and scale from there */
|
||||||
let monitor = Main.layoutManager.monitors[this._monitorIndex];
|
let monitor = Main.layoutManager.monitors[this._monitorIndex];
|
||||||
if (!monitor)
|
if (!monitor)
|
||||||
|
@ -107,9 +107,9 @@ const Overview = new Lang.Class({
|
|||||||
|
|
||||||
this._overviewCreated = true;
|
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',
|
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"),
|
accessible_name: _("Overview"),
|
||||||
vertical: true });
|
vertical: true });
|
||||||
this._overview.add_constraint(new LayoutManager.MonitorConstraint({ primary: true }));
|
this._overview.add_constraint(new LayoutManager.MonitorConstraint({ primary: true }));
|
||||||
@ -378,7 +378,7 @@ const Overview = new Lang.Class({
|
|||||||
return null;
|
return null;
|
||||||
|
|
||||||
let window = windows[0];
|
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 });
|
x: window.x, y: window.y });
|
||||||
clone.source.connect('destroy', Lang.bind(this, function() {
|
clone.source.connect('destroy', Lang.bind(this, function() {
|
||||||
clone.destroy();
|
clone.destroy();
|
||||||
|
900
js/ui/padOsd.js
Normal file
900
js/ui/padOsd.js
Normal file
@ -0,0 +1,900 @@
|
|||||||
|
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||||
|
|
||||||
|
const Lang = imports.lang;
|
||||||
|
const Meta = imports.gi.Meta;
|
||||||
|
const Shell = imports.gi.Shell;
|
||||||
|
const Clutter = imports.gi.Clutter;
|
||||||
|
const St = imports.gi.St;
|
||||||
|
const Rsvg = imports.gi.Rsvg;
|
||||||
|
const GObject = imports.gi.GObject;
|
||||||
|
const GLib = imports.gi.GLib;
|
||||||
|
const Gtk = imports.gi.Gtk;
|
||||||
|
const Gio = imports.gi.Gio;
|
||||||
|
const GDesktopEnums = imports.gi.GDesktopEnums;
|
||||||
|
const Atk = imports.gi.Atk;
|
||||||
|
const Cairo = imports.cairo;
|
||||||
|
const Signals = imports.signals;
|
||||||
|
|
||||||
|
const Main = imports.ui.main;
|
||||||
|
const PopupMenu = imports.ui.popupMenu;
|
||||||
|
const Layout = imports.ui.layout;
|
||||||
|
|
||||||
|
const ACTIVE_COLOR = "#729fcf";
|
||||||
|
|
||||||
|
const LTR = 0;
|
||||||
|
const RTL = 1;
|
||||||
|
|
||||||
|
const CW = 0;
|
||||||
|
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',
|
||||||
|
|
||||||
|
_init: function () {
|
||||||
|
this.actor = new St.Entry({ hint_text: _("New shortcut…"),
|
||||||
|
style: 'width: 10em' });
|
||||||
|
this.actor.connect('captured-event', Lang.bind(this, this._onCapturedEvent));
|
||||||
|
},
|
||||||
|
|
||||||
|
_onCapturedEvent: function (actor, event) {
|
||||||
|
if (event.type() != Clutter.EventType.KEY_PRESS)
|
||||||
|
return Clutter.EVENT_PROPAGATE;
|
||||||
|
|
||||||
|
let str = Gtk.accelerator_name_with_keycode(null,
|
||||||
|
event.get_key_symbol(),
|
||||||
|
event.get_key_code(),
|
||||||
|
event.get_state());
|
||||||
|
this.actor.set_text(str);
|
||||||
|
this.emit('keybinding-edited', str);
|
||||||
|
return Clutter.EVENT_STOP;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
Signals.addSignalMethods(KeybindingEntry.prototype);
|
||||||
|
|
||||||
|
const ActionComboBox = new Lang.Class({
|
||||||
|
Name: 'ActionComboBox',
|
||||||
|
|
||||||
|
_init: function () {
|
||||||
|
this.actor = new St.Button({ style_class: 'button' });
|
||||||
|
this.actor.connect('clicked', Lang.bind(this, this._onButtonClicked));
|
||||||
|
this.actor.set_toggle_mode(true);
|
||||||
|
|
||||||
|
let boxLayout = new Clutter.BoxLayout({ orientation: Clutter.Orientation.HORIZONTAL,
|
||||||
|
spacing: 6 });
|
||||||
|
let box = new St.Widget({ layout_manager: boxLayout });
|
||||||
|
this.actor.set_child(box);
|
||||||
|
|
||||||
|
this._label = new St.Label({ style_class: 'combo-box-label' });
|
||||||
|
box.add_child(this._label)
|
||||||
|
|
||||||
|
let arrow = new St.Icon({ style_class: 'popup-menu-arrow',
|
||||||
|
icon_name: 'pan-down-symbolic',
|
||||||
|
accessible_role: Atk.Role.ARROW,
|
||||||
|
y_expand: true,
|
||||||
|
y_align: Clutter.ActorAlign.CENTER });
|
||||||
|
box.add_child(arrow);
|
||||||
|
|
||||||
|
this._editMenu = new PopupMenu.PopupMenu(this.actor, 0, St.Side.TOP);
|
||||||
|
this._editMenu.connect('menu-closed', Lang.bind(this, function() { this.actor.set_checked(false); }));
|
||||||
|
this._editMenu.actor.hide();
|
||||||
|
Main.uiGroup.add_actor(this._editMenu.actor);
|
||||||
|
|
||||||
|
this._actionLabels = new Map();
|
||||||
|
this._actionLabels.set(GDesktopEnums.PadButtonAction.NONE, _("Application defined"));
|
||||||
|
this._actionLabels.set(GDesktopEnums.PadButtonAction.HELP, _("Show on-screen help"));
|
||||||
|
this._actionLabels.set(GDesktopEnums.PadButtonAction.SWITCH_MONITOR, _("Switch monitor"));
|
||||||
|
this._actionLabels.set(GDesktopEnums.PadButtonAction.KEYBINDING, _("Assign keystroke"));
|
||||||
|
|
||||||
|
for (let [action, label] of this._actionLabels.entries()) {
|
||||||
|
let selectedAction = action;
|
||||||
|
this._editMenu.addAction(label, Lang.bind(this, function() { this._onActionSelected(selectedAction) }));
|
||||||
|
}
|
||||||
|
|
||||||
|
this.setAction(GDesktopEnums.PadButtonAction.NONE);
|
||||||
|
},
|
||||||
|
|
||||||
|
_onActionSelected: function (action) {
|
||||||
|
this.setAction(action);
|
||||||
|
this.popdown();
|
||||||
|
this.emit('action-selected', action);
|
||||||
|
},
|
||||||
|
|
||||||
|
setAction: function (action) {
|
||||||
|
this._label.set_text(this._actionLabels.get(action));
|
||||||
|
},
|
||||||
|
|
||||||
|
popup: function () {
|
||||||
|
this._editMenu.open(true);
|
||||||
|
},
|
||||||
|
|
||||||
|
popdown: function () {
|
||||||
|
this._editMenu.close(true);
|
||||||
|
},
|
||||||
|
|
||||||
|
_onButtonClicked: function () {
|
||||||
|
if (this.actor.get_checked())
|
||||||
|
this.popup();
|
||||||
|
else
|
||||||
|
this.popdown();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
Signals.addSignalMethods(ActionComboBox.prototype);
|
||||||
|
|
||||||
|
const ActionEditor = new Lang.Class({
|
||||||
|
Name: 'ActionEditor',
|
||||||
|
|
||||||
|
_init: function () {
|
||||||
|
let boxLayout = new Clutter.BoxLayout({ orientation: Clutter.Orientation.HORIZONTAL,
|
||||||
|
spacing: 12 });
|
||||||
|
|
||||||
|
this.actor = new St.Widget({ layout_manager: boxLayout });
|
||||||
|
|
||||||
|
this._actionComboBox = new ActionComboBox();
|
||||||
|
this._actionComboBox.connect('action-selected', Lang.bind(this, this._onActionSelected));
|
||||||
|
this.actor.add_actor(this._actionComboBox.actor);
|
||||||
|
|
||||||
|
this._keybindingEdit = new KeybindingEntry();
|
||||||
|
this._keybindingEdit.connect('keybinding-edited', Lang.bind(this, this._onKeybindingEdited));
|
||||||
|
this.actor.add_actor(this._keybindingEdit.actor);
|
||||||
|
|
||||||
|
this._doneButton = new St.Button({ label: _("Done"),
|
||||||
|
style_class: 'button',
|
||||||
|
x_expand: false});
|
||||||
|
this._doneButton.connect('clicked', Lang.bind(this, this._onEditingDone));
|
||||||
|
this.actor.add_actor(this._doneButton);
|
||||||
|
},
|
||||||
|
|
||||||
|
_updateKeybindingEntryState: function () {
|
||||||
|
if (this._currentAction == GDesktopEnums.PadButtonAction.KEYBINDING) {
|
||||||
|
this._keybindingEdit.actor.set_text(this._currentKeybinding);
|
||||||
|
this._keybindingEdit.actor.show();
|
||||||
|
this._keybindingEdit.actor.grab_key_focus();
|
||||||
|
} else {
|
||||||
|
this._keybindingEdit.actor.hide();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
setSettings: function (settings) {
|
||||||
|
this._buttonSettings = settings;
|
||||||
|
|
||||||
|
this._currentAction = this._buttonSettings.get_enum('action');
|
||||||
|
this._currentKeybinding = this._buttonSettings.get_string('keybinding');
|
||||||
|
this._actionComboBox.setAction(this._currentAction);
|
||||||
|
this._updateKeybindingEntryState();
|
||||||
|
},
|
||||||
|
|
||||||
|
close: function() {
|
||||||
|
this._actionComboBox.popdown();
|
||||||
|
this.actor.hide();
|
||||||
|
},
|
||||||
|
|
||||||
|
_onKeybindingEdited: function (entry, keybinding) {
|
||||||
|
this._currentKeybinding = keybinding;
|
||||||
|
},
|
||||||
|
|
||||||
|
_onActionSelected: function (menu, action) {
|
||||||
|
this._currentAction = action;
|
||||||
|
this._updateKeybindingEntryState();
|
||||||
|
},
|
||||||
|
|
||||||
|
_storeSettings: function () {
|
||||||
|
if (!this._buttonSettings)
|
||||||
|
return;
|
||||||
|
|
||||||
|
let keybinding = null;
|
||||||
|
|
||||||
|
if (this._currentAction == GDesktopEnums.PadButtonAction.KEYBINDING)
|
||||||
|
keybinding = this._currentKeybinding;
|
||||||
|
|
||||||
|
this._buttonSettings.set_enum('action', this._currentAction);
|
||||||
|
|
||||||
|
if (keybinding)
|
||||||
|
this._buttonSettings.set_string('keybinding', keybinding);
|
||||||
|
else
|
||||||
|
this._buttonSettings.reset('keybinding');
|
||||||
|
},
|
||||||
|
|
||||||
|
_onEditingDone: function () {
|
||||||
|
this._storeSettings();
|
||||||
|
this.close();
|
||||||
|
this.emit('done');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
Signals.addSignalMethods(ActionEditor.prototype);
|
||||||
|
|
||||||
|
const PadDiagram = new Lang.Class({
|
||||||
|
Name: 'PadDiagram',
|
||||||
|
Extends: St.DrawingArea,
|
||||||
|
Properties: { 'left-handed': GObject.ParamSpec.boolean('left-handed',
|
||||||
|
'left-handed', 'Left handed',
|
||||||
|
GObject.ParamFlags.READWRITE |
|
||||||
|
GObject.ParamFlags.CONSTRUCT_ONLY,
|
||||||
|
false),
|
||||||
|
'image': GObject.ParamSpec.string('image', 'image', 'Image',
|
||||||
|
GObject.ParamFlags.READWRITE |
|
||||||
|
GObject.ParamFlags.CONSTRUCT_ONLY,
|
||||||
|
null),
|
||||||
|
'editor-actor': GObject.ParamSpec.object('editor-actor',
|
||||||
|
'editor-actor',
|
||||||
|
'Editor actor',
|
||||||
|
GObject.ParamFlags.READWRITE |
|
||||||
|
GObject.ParamFlags.CONSTRUCT_ONLY,
|
||||||
|
Clutter.Actor.$gtype) },
|
||||||
|
|
||||||
|
_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._css = css;
|
||||||
|
this._labels = [];
|
||||||
|
this._activeButtons = [];
|
||||||
|
this.parent(params);
|
||||||
|
},
|
||||||
|
|
||||||
|
get left_handed() {
|
||||||
|
return this._leftHanded;
|
||||||
|
},
|
||||||
|
|
||||||
|
set left_handed(leftHanded) {
|
||||||
|
this._leftHanded = leftHanded;
|
||||||
|
},
|
||||||
|
|
||||||
|
get image() {
|
||||||
|
return this._imagePath;
|
||||||
|
},
|
||||||
|
|
||||||
|
set image(imagePath) {
|
||||||
|
let originalHandle = Rsvg.Handle.new_from_file(imagePath);
|
||||||
|
let dimensions = originalHandle.get_dimensions();
|
||||||
|
this._imageWidth = dimensions.width;
|
||||||
|
this._imageHeight = dimensions.height;
|
||||||
|
|
||||||
|
this._imagePath = imagePath;
|
||||||
|
this._handle = this._composeStyledDiagram();
|
||||||
|
},
|
||||||
|
|
||||||
|
get editor_actor() {
|
||||||
|
return this._editorActor;
|
||||||
|
},
|
||||||
|
|
||||||
|
set editor_actor(actor) {
|
||||||
|
actor.hide();
|
||||||
|
this._editorActor = actor;
|
||||||
|
this.add_actor(actor);
|
||||||
|
},
|
||||||
|
|
||||||
|
_wrappingSvgHeader: function () {
|
||||||
|
return ('<?xml version="1.0" encoding="UTF-8" standalone="no"?>' +
|
||||||
|
'<svg version="1.1" xmlns="http://www.w3.org/2000/svg" ' +
|
||||||
|
'xmlns:xi="http://www.w3.org/2001/XInclude" ' +
|
||||||
|
'width="' + this._imageWidth + '" height="' + this._imageHeight + '"> ' +
|
||||||
|
'<style type="text/css">');
|
||||||
|
},
|
||||||
|
|
||||||
|
_wrappingSvgFooter: function () {
|
||||||
|
return ('</style>' +
|
||||||
|
'<xi:include href="' + this._imagePath + '" />' +
|
||||||
|
'</svg>');
|
||||||
|
},
|
||||||
|
|
||||||
|
_cssString: function () {
|
||||||
|
let css = this._css;
|
||||||
|
|
||||||
|
for (let i = 0; i < this._activeButtons.length; i++) {
|
||||||
|
let ch = String.fromCharCode('A'.charCodeAt() + this._activeButtons[i]);
|
||||||
|
css += ('.' + ch + ' { ' +
|
||||||
|
' stroke: ' + ACTIVE_COLOR + ' !important; ' +
|
||||||
|
' fill: ' + ACTIVE_COLOR + ' !important; ' +
|
||||||
|
'} ');
|
||||||
|
}
|
||||||
|
|
||||||
|
return css;
|
||||||
|
},
|
||||||
|
|
||||||
|
_composeStyledDiagram: function () {
|
||||||
|
let svgData = '';
|
||||||
|
|
||||||
|
if (!GLib.file_test(this._imagePath, GLib.FileTest.EXISTS))
|
||||||
|
return null;
|
||||||
|
|
||||||
|
svgData += this._wrappingSvgHeader();
|
||||||
|
svgData += this._cssString();
|
||||||
|
svgData += this._wrappingSvgFooter();
|
||||||
|
|
||||||
|
let handle = new Rsvg.Handle();
|
||||||
|
handle.set_base_uri(GLib.path_get_dirname(this._imagePath));
|
||||||
|
handle.write(svgData);
|
||||||
|
handle.close();
|
||||||
|
|
||||||
|
return handle;
|
||||||
|
},
|
||||||
|
|
||||||
|
_updateDiagramScale: function () {
|
||||||
|
if (this._handle == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
[this._actorWidth, this._actorHeight] = this.get_size();
|
||||||
|
let dimensions = this._handle.get_dimensions();
|
||||||
|
let scaleX = this._actorWidth / dimensions.width;
|
||||||
|
let scaleY = this._actorHeight / dimensions.height;
|
||||||
|
this._scale = Math.min(scaleX, scaleY);
|
||||||
|
},
|
||||||
|
|
||||||
|
_allocateChild: function (child, x, y, direction) {
|
||||||
|
let [prefHeight, natHeight] = child.get_preferred_height(-1);
|
||||||
|
let [prefWidth, natWidth] = child.get_preferred_width(natHeight);
|
||||||
|
let childBox = new Clutter.ActorBox();
|
||||||
|
|
||||||
|
if (direction == LTR) {
|
||||||
|
childBox.x1 = x;
|
||||||
|
childBox.x2 = x + natWidth;
|
||||||
|
} else {
|
||||||
|
childBox.x1 = x - natWidth;
|
||||||
|
childBox.x2 = x;
|
||||||
|
}
|
||||||
|
|
||||||
|
childBox.y1 = y - natHeight / 2;
|
||||||
|
childBox.y2 = y + natHeight / 2;
|
||||||
|
child.allocate(childBox, 0);
|
||||||
|
},
|
||||||
|
|
||||||
|
vfunc_allocate: function (box, flags) {
|
||||||
|
this.parent(box, flags);
|
||||||
|
this._updateDiagramScale();
|
||||||
|
|
||||||
|
for (let i = 0; i < this._labels.length; i++) {
|
||||||
|
let [label, action, idx, dir] = this._labels[i];
|
||||||
|
let [found, x, y, arrangement] = this.getLabelCoords(action, idx, dir);
|
||||||
|
this._allocateChild(label, x, y, arrangement);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this._editorActor && this._curEdited) {
|
||||||
|
let [label, action, idx, dir] = this._curEdited;
|
||||||
|
let [found, x, y, arrangement] = this.getLabelCoords(action, idx, dir);
|
||||||
|
this._allocateChild(this._editorActor, x, y, arrangement);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
vfunc_repaint: function () {
|
||||||
|
if (this._handle == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (this._scale == null)
|
||||||
|
this._updateDiagramScale();
|
||||||
|
|
||||||
|
let [width, height] = this.get_surface_size();
|
||||||
|
let dimensions = this._handle.get_dimensions();
|
||||||
|
let cr = this.get_context();
|
||||||
|
|
||||||
|
cr.save();
|
||||||
|
cr.translate(width/2, height/2);
|
||||||
|
cr.scale(this._scale, this._scale);
|
||||||
|
if (this._leftHanded)
|
||||||
|
cr.rotate(Math.PI);
|
||||||
|
cr.translate(-dimensions.width/2, -dimensions.height/2);
|
||||||
|
this._handle.render_cairo(cr);
|
||||||
|
cr.restore();
|
||||||
|
cr.$dispose();
|
||||||
|
},
|
||||||
|
|
||||||
|
_transformPoint: function (x, y) {
|
||||||
|
if (this._handle == null || this._scale == null)
|
||||||
|
return [x, y];
|
||||||
|
|
||||||
|
// I miss Cairo.Matrix
|
||||||
|
let dimensions = this._handle.get_dimensions();
|
||||||
|
x = x * this._scale + this._actorWidth / 2 - dimensions.width / 2 * this._scale;
|
||||||
|
y = y * this._scale + this._actorHeight / 2 - dimensions.height / 2 * this._scale;;
|
||||||
|
return [Math.round(x), Math.round(y)];
|
||||||
|
},
|
||||||
|
|
||||||
|
_getItemLabelCoords: function (labelName, leaderName) {
|
||||||
|
if (this._handle == null)
|
||||||
|
return [false];
|
||||||
|
|
||||||
|
let leaderPos, leaderSize, pos;
|
||||||
|
let found, direction;
|
||||||
|
|
||||||
|
[found, pos] = this._handle.get_position_sub('#' + labelName);
|
||||||
|
if (!found)
|
||||||
|
return [false];
|
||||||
|
|
||||||
|
[found, leaderPos] = this._handle.get_position_sub('#' + leaderName);
|
||||||
|
[found, leaderSize] = this._handle.get_dimensions_sub('#' + leaderName);
|
||||||
|
if (!found)
|
||||||
|
return [false];
|
||||||
|
|
||||||
|
if (pos.x > leaderPos.x + leaderSize.width)
|
||||||
|
direction = LTR;
|
||||||
|
else
|
||||||
|
direction = RTL;
|
||||||
|
|
||||||
|
if (this._leftHanded) {
|
||||||
|
direction = 1 - direction;
|
||||||
|
pos.x = this._imageWidth - pos.x;
|
||||||
|
pos.y = this._imageHeight - pos.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
let [x, y] = this._transformPoint(pos.x, pos.y)
|
||||||
|
|
||||||
|
return [true, x, y, direction];
|
||||||
|
},
|
||||||
|
|
||||||
|
getButtonLabelCoords: function (button) {
|
||||||
|
let ch = String.fromCharCode('A'.charCodeAt() + button);
|
||||||
|
let labelName = 'Label' + ch;
|
||||||
|
let leaderName = 'Leader' + ch;
|
||||||
|
|
||||||
|
return this._getItemLabelCoords(labelName, leaderName);
|
||||||
|
},
|
||||||
|
|
||||||
|
getRingLabelCoords: function (number, dir) {
|
||||||
|
let numStr = number > 0 ? number.toString() : '';
|
||||||
|
let dirStr = dir == CW ? 'CW' : 'CCW';
|
||||||
|
let labelName = 'LabelRing' + numStr + dirStr;
|
||||||
|
let leaderName = 'LeaderRing' + numStr + dirStr;
|
||||||
|
|
||||||
|
return this._getItemLabelCoords(labelName, leaderName);
|
||||||
|
},
|
||||||
|
|
||||||
|
getStripLabelCoords: function (number, dir) {
|
||||||
|
let numStr = number > 0 ? (number + 1).toString() : '';
|
||||||
|
let dirStr = dir == UP ? 'Up' : 'Down';
|
||||||
|
let labelName = 'LabelStrip' + numStr + dirStr;
|
||||||
|
let leaderName = 'LeaderStrip' + numStr + dirStr;
|
||||||
|
|
||||||
|
return this._getItemLabelCoords(labelName, leaderName);
|
||||||
|
},
|
||||||
|
|
||||||
|
getLabelCoords: function (action, idx, dir) {
|
||||||
|
if (action == Meta.PadActionType.BUTTON)
|
||||||
|
return this.getButtonLabelCoords(idx);
|
||||||
|
else if (action == Meta.PadActionType.RING)
|
||||||
|
return this.getRingLabelCoords(idx, dir);
|
||||||
|
else if (action == Meta.PadActionType.STRIP)
|
||||||
|
return this.getStripLabelCoords(idx, dir);
|
||||||
|
|
||||||
|
return [false];
|
||||||
|
},
|
||||||
|
|
||||||
|
_invalidateSvg: function () {
|
||||||
|
if (this._handle == null)
|
||||||
|
return;
|
||||||
|
this._handle = this._composeStyledDiagram();
|
||||||
|
this.queue_repaint();
|
||||||
|
},
|
||||||
|
|
||||||
|
activateButton: function (button) {
|
||||||
|
this._activeButtons.push(button);
|
||||||
|
this._invalidateSvg();
|
||||||
|
},
|
||||||
|
|
||||||
|
deactivateButton: function (button) {
|
||||||
|
for (let i = 0; i < this._activeButtons.length; i++) {
|
||||||
|
if (this._activeButtons[i] == button)
|
||||||
|
this._activeButtons.splice(i, 1);
|
||||||
|
}
|
||||||
|
this._invalidateSvg();
|
||||||
|
},
|
||||||
|
|
||||||
|
addLabel: function (label, type, idx, dir) {
|
||||||
|
this._labels.push([label, type, idx, dir]);
|
||||||
|
this.add_actor(label);
|
||||||
|
},
|
||||||
|
|
||||||
|
stopEdition: function (str) {
|
||||||
|
this._editorActor.hide();
|
||||||
|
|
||||||
|
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._curEdited = null;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
startEdition: function(action, idx, dir) {
|
||||||
|
let editedLabel;
|
||||||
|
this.stopEdition();
|
||||||
|
|
||||||
|
for (let i = 0; i < this._labels.length; i++) {
|
||||||
|
let [label, itemAction, itemIdx, itemDir] = this._labels[i];
|
||||||
|
if (action == itemAction && idx == itemIdx && dir == itemDir) {
|
||||||
|
this._curEdited = this._labels[i];
|
||||||
|
editedLabel = label;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this._curEdited == null)
|
||||||
|
return;
|
||||||
|
let [found] = this.getLabelCoords(action, idx, dir);
|
||||||
|
if (!found)
|
||||||
|
return;
|
||||||
|
this._editorActor.show();
|
||||||
|
editedLabel.hide();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const PadOsd = new Lang.Class({
|
||||||
|
Name: 'PadOsd',
|
||||||
|
|
||||||
|
_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) {
|
||||||
|
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',
|
||||||
|
x_expand: true,
|
||||||
|
y_expand: true,
|
||||||
|
vertical: true,
|
||||||
|
reactive: true });
|
||||||
|
this.actor.connect('destroy', Lang.bind(this, this._onDestroy));
|
||||||
|
Main.uiGroup.add_actor(this.actor);
|
||||||
|
|
||||||
|
this._monitorIndex = monitorIndex;
|
||||||
|
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());
|
||||||
|
labelBox.add_actor(this._titleLabel);
|
||||||
|
|
||||||
|
this._tipLabel = new St.Label({ x_align: Clutter.ActorAlign.CENTER });
|
||||||
|
labelBox.add_actor(this._tipLabel);
|
||||||
|
|
||||||
|
this._updatePadChooser();
|
||||||
|
|
||||||
|
this._actionEditor = new ActionEditor();
|
||||||
|
this._actionEditor.connect('done', Lang.bind(this, this._endButtonActionEdition));
|
||||||
|
|
||||||
|
this._padDiagram = new PadDiagram({ image: this._imagePath,
|
||||||
|
left_handed: settings.get_boolean('left-handed'),
|
||||||
|
editor_actor: this._actionEditor.actor,
|
||||||
|
x_expand: true,
|
||||||
|
y_expand: true });
|
||||||
|
this.actor.add_actor(this._padDiagram);
|
||||||
|
|
||||||
|
// FIXME: Fix num buttons.
|
||||||
|
let i = 0;
|
||||||
|
for (i = 0; i < 50; i++) {
|
||||||
|
let [found] = this._padDiagram.getButtonLabelCoords(i);
|
||||||
|
if (!found)
|
||||||
|
break;
|
||||||
|
this._createLabel(Meta.PadActionType.BUTTON, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < padDevice.get_n_rings(); i++) {
|
||||||
|
this._createLabel(Meta.PadActionType.RING, i, CW);
|
||||||
|
this._createLabel(Meta.PadActionType.RING, i, CCW);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < padDevice.get_n_strips(); i++) {
|
||||||
|
this._createLabel(Meta.PadActionType.STRIP, i, UP);
|
||||||
|
this._createLabel(Meta.PadActionType.STRIP, i, DOWN);
|
||||||
|
}
|
||||||
|
|
||||||
|
let buttonBox = new St.Widget({ layout_manager: new Clutter.BinLayout(),
|
||||||
|
x_expand: true,
|
||||||
|
x_align: Clutter.ActorAlign.CENTER,
|
||||||
|
y_align: Clutter.ActorAlign.CENTER });
|
||||||
|
this.actor.add_actor(buttonBox);
|
||||||
|
this._editButton = new St.Button({ label: _("Edit…"),
|
||||||
|
style_class: 'button',
|
||||||
|
x_align: Clutter.ActorAlign.CENTER,
|
||||||
|
can_focus: true });
|
||||||
|
this._editButton.connect('clicked', Lang.bind(this, function () { this.setEditionMode(true) }));
|
||||||
|
buttonBox.add_actor(this._editButton);
|
||||||
|
|
||||||
|
this._syncEditionMode();
|
||||||
|
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") });
|
||||||
|
this._padDiagram.addLabel(label, type, number, dir);
|
||||||
|
},
|
||||||
|
|
||||||
|
_onCapturedEvent : function (actor, event) {
|
||||||
|
if (event.type() == Clutter.EventType.PAD_BUTTON_PRESS &&
|
||||||
|
event.get_source_device() == this.padDevice) {
|
||||||
|
this._padDiagram.activateButton(event.get_button());
|
||||||
|
|
||||||
|
if (this._editionMode)
|
||||||
|
this._startButtonActionEdition(event.get_button());
|
||||||
|
return Clutter.EVENT_STOP;
|
||||||
|
} else if (event.type() == Clutter.EventType.PAD_BUTTON_RELEASE &&
|
||||||
|
event.get_source_device() == this.padDevice) {
|
||||||
|
this._padDiagram.deactivateButton(event.get_button());
|
||||||
|
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();
|
||||||
|
else
|
||||||
|
this.destroy();
|
||||||
|
return Clutter.EVENT_STOP;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
},
|
||||||
|
|
||||||
|
_syncEditionMode: function () {
|
||||||
|
this._editButton.set_reactive(!this._editionMode);
|
||||||
|
this._editButton.save_easing_state();
|
||||||
|
this._editButton.set_easing_duration(200);
|
||||||
|
this._editButton.set_opacity(this._editionMode ? 128 : 255);
|
||||||
|
this._editButton.restore_easing_state();
|
||||||
|
|
||||||
|
let title;
|
||||||
|
|
||||||
|
if (this._editionMode) {
|
||||||
|
title = _("Press a button to configure");
|
||||||
|
this._tipLabel.set_text(_("Press Esc to exit"));
|
||||||
|
} else {
|
||||||
|
title = this.padDevice.get_device_name();
|
||||||
|
this._tipLabel.set_text(_("Press any key to exit"));
|
||||||
|
}
|
||||||
|
|
||||||
|
this._titleLabel.clutter_text.set_markup('<span size="larger"><b>' + title + '</b></span>');
|
||||||
|
},
|
||||||
|
|
||||||
|
_endButtonActionEdition: function () {
|
||||||
|
this._actionEditor.close();
|
||||||
|
|
||||||
|
if (this._editingButtonAction != 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._editedButtonSettings = null;
|
||||||
|
},
|
||||||
|
|
||||||
|
_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);
|
||||||
|
},
|
||||||
|
|
||||||
|
setEditionMode: function (editionMode) {
|
||||||
|
if (this._editionMode == editionMode)
|
||||||
|
return;
|
||||||
|
|
||||||
|
this._editionMode = editionMode;
|
||||||
|
this._syncEditionMode();
|
||||||
|
},
|
||||||
|
|
||||||
|
destroy: function () {
|
||||||
|
this.actor.destroy();
|
||||||
|
},
|
||||||
|
|
||||||
|
_onDestroy: function () {
|
||||||
|
Main.popModal(this.actor);
|
||||||
|
this._actionEditor.close();
|
||||||
|
|
||||||
|
let deviceManager = Clutter.DeviceManager.get_default();
|
||||||
|
if (this._deviceRemovedId != 0) {
|
||||||
|
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);
|
||||||
|
this._capturedEventId = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.actor = null;
|
||||||
|
this.emit('closed');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
Signals.addSignalMethods(PadOsd.prototype);
|
||||||
|
|
||||||
|
const PadOsdIface = '<node> \
|
||||||
|
<interface name="org.gnome.Shell.Wacom.PadOsd"> \
|
||||||
|
<method name="Show"> \
|
||||||
|
<arg name="device_node" direction="in" type="o"/> \
|
||||||
|
<arg name="edition_mode" direction="in" type="b"/> \
|
||||||
|
</method> \
|
||||||
|
</interface> \
|
||||||
|
</node>';
|
||||||
|
|
||||||
|
const PadOsdService = new Lang.Class({
|
||||||
|
Name: 'PadOsdService',
|
||||||
|
|
||||||
|
_init: function() {
|
||||||
|
this._dbusImpl = Gio.DBusExportedObject.wrapJSObject(PadOsdIface, this);
|
||||||
|
this._dbusImpl.export(Gio.DBus.session, '/org/gnome/Shell/Wacom');
|
||||||
|
Gio.DBus.session.own_name('org.gnome.Shell.Wacom.PadOsd', Gio.BusNameOwnerFlags.REPLACE, null, null);
|
||||||
|
},
|
||||||
|
|
||||||
|
ShowAsync: function(params, invocation) {
|
||||||
|
let [deviceNode, editionMode] = params;
|
||||||
|
let deviceManager = Clutter.DeviceManager.get_default();
|
||||||
|
let devices = deviceManager.list_devices();
|
||||||
|
let padDevice = null;
|
||||||
|
|
||||||
|
devices.forEach(Lang.bind(this, function(device) {
|
||||||
|
if (deviceNode == device.get_device_node())
|
||||||
|
padDevice = device;
|
||||||
|
}));
|
||||||
|
|
||||||
|
if (padDevice == null ||
|
||||||
|
padDevice.get_device_type() != Clutter.InputDeviceType.PAD_DEVICE) {
|
||||||
|
invocation.return_error_literal(Gio.IOErrorEnum,
|
||||||
|
Gio.IOErrorEnum.CANCELLED,
|
||||||
|
"Invalid params");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
global.display.request_pad_osd(padDevice, editionMode);
|
||||||
|
invocation.return_value(null);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
Signals.addSignalMethods(PadOsdService.prototype);
|
@ -719,9 +719,11 @@ const AggregateMenu = new Lang.Class({
|
|||||||
this._system = new imports.ui.status.system.Indicator();
|
this._system = new imports.ui.status.system.Indicator();
|
||||||
this._screencast = new imports.ui.status.screencast.Indicator();
|
this._screencast = new imports.ui.status.screencast.Indicator();
|
||||||
this._location = new imports.ui.status.location.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._screencast.indicators);
|
||||||
this._indicators.add_child(this._location.indicators);
|
this._indicators.add_child(this._location.indicators);
|
||||||
|
this._indicators.add_child(this._nightLight.indicators);
|
||||||
if (this._network) {
|
if (this._network) {
|
||||||
this._indicators.add_child(this._network.indicators);
|
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._location.menu);
|
||||||
this.menu.addMenuItem(this._rfkill.menu);
|
this.menu.addMenuItem(this._rfkill.menu);
|
||||||
this.menu.addMenuItem(this._power.menu);
|
this.menu.addMenuItem(this._power.menu);
|
||||||
|
this.menu.addMenuItem(this._nightLight.menu);
|
||||||
this.menu.addMenuItem(this._system.menu);
|
this.menu.addMenuItem(this._system.menu);
|
||||||
|
|
||||||
menuLayout.addSizeChild(this._location.menu.actor);
|
menuLayout.addSizeChild(this._location.menu.actor);
|
||||||
|
@ -605,6 +605,24 @@ const PopupMenuBase = new Lang.Class({
|
|||||||
menuItem.actor.show();
|
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) {
|
addMenuItem: function(menuItem, position) {
|
||||||
let before_item = null;
|
let before_item = null;
|
||||||
if (position == undefined) {
|
if (position == undefined) {
|
||||||
@ -783,6 +801,16 @@ const PopupMenu = new Lang.Class({
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let state = event.get_state();
|
||||||
|
|
||||||
|
// if user has a modifier down (except capslock)
|
||||||
|
// then don't handle the key press here
|
||||||
|
state &= ~Clutter.ModifierType.LOCK_MASK;
|
||||||
|
state &= Clutter.ModifierType.MODIFIER_MASK;
|
||||||
|
|
||||||
|
if (state)
|
||||||
|
return Clutter.EVENT_PROPAGATE;
|
||||||
|
|
||||||
let symbol = event.get_key_symbol();
|
let symbol = event.get_key_symbol();
|
||||||
if (symbol == Clutter.KEY_space || symbol == Clutter.KEY_Return) {
|
if (symbol == Clutter.KEY_space || symbol == Clutter.KEY_Return) {
|
||||||
this.toggle();
|
this.toggle();
|
||||||
|
@ -297,7 +297,7 @@ const RemoteSearchProvider = new Lang.Class({
|
|||||||
// the provider is not compatible with the new version of the interface, launch
|
// the provider is not compatible with the new version of the interface, launch
|
||||||
// the app itself but warn so we can catch the error in logs
|
// the app itself but warn so we can catch the error in logs
|
||||||
log('Search provider ' + this.appInfo.get_id() + ' does not implement LaunchSearch');
|
log('Search provider ' + this.appInfo.get_id() + ' does not implement LaunchSearch');
|
||||||
this.appInfo.launch([], global.create_app_launch_context(0, -1));
|
this.appInfo.launch([], global.create_app_launch_context(0, -1), false);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -274,7 +274,7 @@ const RunDialog = new Lang.Class({
|
|||||||
|
|
||||||
_restart: function() {
|
_restart: function() {
|
||||||
if (Meta.is_wayland_compositor()) {
|
if (Meta.is_wayland_compositor()) {
|
||||||
this._showError('Restart is not available on Wayland');
|
this._showError(_("Restart is not available on Wayland"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this._shouldFadeOut = false;
|
this._shouldFadeOut = false;
|
||||||
|
@ -665,7 +665,10 @@ const ScreenShield = new Lang.Class({
|
|||||||
let isEnter = (symbol == Clutter.KEY_Return ||
|
let isEnter = (symbol == Clutter.KEY_Return ||
|
||||||
symbol == Clutter.KEY_KP_Enter ||
|
symbol == Clutter.KEY_KP_Enter ||
|
||||||
symbol == Clutter.KEY_ISO_Enter);
|
symbol == Clutter.KEY_ISO_Enter);
|
||||||
if (!isEnter && !(GLib.unichar_isprint(unichar) || symbol == Clutter.KEY_Escape))
|
let isEscape = (symbol == Clutter.KEY_Escape);
|
||||||
|
let isLiftChar = (GLib.unichar_isprint(unichar) &&
|
||||||
|
(this._isLocked || !GLib.unichar_isgraph(unichar)));
|
||||||
|
if (!isEnter && !isEscape && !isLiftChar)
|
||||||
return Clutter.EVENT_PROPAGATE;
|
return Clutter.EVENT_PROPAGATE;
|
||||||
|
|
||||||
if (this._isLocked &&
|
if (this._isLocked &&
|
||||||
@ -847,6 +850,7 @@ const ScreenShield = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
_activateFade: function(lightbox, time) {
|
_activateFade: function(lightbox, time) {
|
||||||
|
Main.uiGroup.set_child_above_sibling(lightbox.actor, null);
|
||||||
lightbox.show(time);
|
lightbox.show(time);
|
||||||
|
|
||||||
if (this._becameActiveId == 0)
|
if (this._becameActiveId == 0)
|
||||||
|
@ -380,7 +380,7 @@ const ShellMountPasswordDialog = new Lang.Class({
|
|||||||
this.setInitialKeyFocus(this._passwordEntry);
|
this.setInitialKeyFocus(this._passwordEntry);
|
||||||
|
|
||||||
this._errorMessageLabel = new St.Label({ style_class: 'prompt-dialog-error-label',
|
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.ellipsize = Pango.EllipsizeMode.NONE;
|
||||||
this._errorMessageLabel.clutter_text.line_wrap = true;
|
this._errorMessageLabel.clutter_text.line_wrap = true;
|
||||||
this._errorMessageLabel.hide();
|
this._errorMessageLabel.hide();
|
||||||
|
@ -137,7 +137,7 @@ const Indicator = new Lang.Class({
|
|||||||
else if (nConnectedDevices == -1)
|
else if (nConnectedDevices == -1)
|
||||||
this._item.label.text = _("Off");
|
this._item.label.text = _("Off");
|
||||||
else
|
else
|
||||||
this._item.label.text = _("Not In Use");
|
this._item.label.text = _("On");
|
||||||
|
|
||||||
this._toggleItem.label.text = this._proxy.BluetoothAirplaneMode ? _("Turn On") : _("Turn Off");
|
this._toggleItem.label.text = this._proxy.BluetoothAirplaneMode ? _("Turn On") : _("Turn Off");
|
||||||
},
|
},
|
||||||
|
@ -284,6 +284,7 @@ const AppAuthorizer = new Lang.Class({
|
|||||||
this.reqAccuracyLevel = reqAccuracyLevel;
|
this.reqAccuracyLevel = reqAccuracyLevel;
|
||||||
this._permStoreProxy = permStoreProxy;
|
this._permStoreProxy = permStoreProxy;
|
||||||
this._maxAccuracyLevel = maxAccuracyLevel;
|
this._maxAccuracyLevel = maxAccuracyLevel;
|
||||||
|
this._permissions = {};
|
||||||
|
|
||||||
this._accuracyLevel = GeoclueAccuracyLevel.NONE;
|
this._accuracyLevel = GeoclueAccuracyLevel.NONE;
|
||||||
},
|
},
|
||||||
|
@ -5,6 +5,7 @@ const GObject = imports.gi.GObject;
|
|||||||
const Gio = imports.gi.Gio;
|
const Gio = imports.gi.Gio;
|
||||||
const Gtk = imports.gi.Gtk;
|
const Gtk = imports.gi.Gtk;
|
||||||
const Lang = imports.lang;
|
const Lang = imports.lang;
|
||||||
|
const Mainloop = imports.mainloop;
|
||||||
const NetworkManager = imports.gi.NetworkManager;
|
const NetworkManager = imports.gi.NetworkManager;
|
||||||
const NMClient = imports.gi.NMClient;
|
const NMClient = imports.gi.NMClient;
|
||||||
const NMGtk = imports.gi.NMGtk;
|
const NMGtk = imports.gi.NMGtk;
|
||||||
@ -39,6 +40,8 @@ const NMAccessPointSecurity = {
|
|||||||
WPA2_ENT: 6
|
WPA2_ENT: 6
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const MAX_DEVICE_ITEMS = 4;
|
||||||
|
|
||||||
// small optimization, to avoid using [] all the time
|
// small optimization, to avoid using [] all the time
|
||||||
const NM80211Mode = NetworkManager['80211Mode'];
|
const NM80211Mode = NetworkManager['80211Mode'];
|
||||||
const NM80211ApFlags = NetworkManager['80211ApFlags'];
|
const NM80211ApFlags = NetworkManager['80211ApFlags'];
|
||||||
@ -296,11 +299,22 @@ const NMConnectionSection = new Lang.Class({
|
|||||||
|
|
||||||
let item = this._connectionItems.get(connection.get_uuid());
|
let item = this._connectionItems.get(connection.get_uuid());
|
||||||
if (item)
|
if (item)
|
||||||
item.updateForConnection(connection);
|
this._updateForConnection(item, connection);
|
||||||
else
|
else
|
||||||
this._addConnection(connection);
|
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) {
|
_addConnection: function(connection) {
|
||||||
let item = this._makeConnectionItem(connection);
|
let item = this._makeConnectionItem(connection);
|
||||||
if (!item)
|
if (!item)
|
||||||
@ -752,10 +766,9 @@ const NMWirelessDialog = new Lang.Class({
|
|||||||
this._updateSensitivity();
|
this._updateSensitivity();
|
||||||
this._syncView();
|
this._syncView();
|
||||||
|
|
||||||
if (accessPoints.length == 0) {
|
this._scanTimeoutId = Mainloop.timeout_add_seconds(15, Lang.bind(this, this._onScanTimeout));
|
||||||
/* If there are no visible access points, request a scan */
|
GLib.Source.set_name_by_id(this._scanTimeoutId, '[gnome-shell] this._onScanTimeout');
|
||||||
this._device.request_scan_simple(null);
|
this._onScanTimeout();
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
destroy: function() {
|
destroy: function() {
|
||||||
@ -780,9 +793,19 @@ const NMWirelessDialog = new Lang.Class({
|
|||||||
this._airplaneModeChangedId = 0;
|
this._airplaneModeChangedId = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this._scanTimeoutId) {
|
||||||
|
Mainloop.source_remove(this._scanTimeoutId);
|
||||||
|
this._scanTimeoutId = 0;
|
||||||
|
}
|
||||||
|
|
||||||
this.parent();
|
this.parent();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_onScanTimeout: function() {
|
||||||
|
this._device.request_scan_simple(null);
|
||||||
|
return GLib.SOURCE_CONTINUE;
|
||||||
|
},
|
||||||
|
|
||||||
_activeApChanged: function() {
|
_activeApChanged: function() {
|
||||||
if (this._activeNetwork)
|
if (this._activeNetwork)
|
||||||
this._activeNetwork.item.setActive(false);
|
this._activeNetwork.item.setActive(false);
|
||||||
@ -1408,7 +1431,7 @@ const NMVPNConnectionItem = new Lang.Class({
|
|||||||
case NetworkManager.VPNConnectionState.PREPARE:
|
case NetworkManager.VPNConnectionState.PREPARE:
|
||||||
case NetworkManager.VPNConnectionState.CONNECT:
|
case NetworkManager.VPNConnectionState.CONNECT:
|
||||||
case NetworkManager.VPNConnectionState.IP_CONFIG_GET:
|
case NetworkManager.VPNConnectionState.IP_CONFIG_GET:
|
||||||
return _("connecting...");
|
return _("connecting…");
|
||||||
case NetworkManager.VPNConnectionState.NEED_AUTH:
|
case NetworkManager.VPNConnectionState.NEED_AUTH:
|
||||||
/* Translators: this is for network connections that require some kind of key or password */
|
/* Translators: this is for network connections that require some kind of key or password */
|
||||||
return _("authentication required");
|
return _("authentication required");
|
||||||
@ -1491,7 +1514,7 @@ const NMVPNSection = new Lang.Class({
|
|||||||
if (nItems > 1) {
|
if (nItems > 1) {
|
||||||
let appSys = Shell.AppSystem.get_default();
|
let appSys = Shell.AppSystem.get_default();
|
||||||
let app = appSys.lookup_app('gnome-network-panel.desktop');
|
let app = appSys.lookup_app('gnome-network-panel.desktop');
|
||||||
app.launch(0, -1);
|
app.launch(0, -1, false);
|
||||||
} else {
|
} else {
|
||||||
let connection = this._connections[0];
|
let connection = this._connections[0];
|
||||||
Util.spawnApp(['gnome-control-center', 'network', 'show-device',
|
Util.spawnApp(['gnome-control-center', 'network', 'show-device',
|
||||||
@ -1531,8 +1554,10 @@ const NMVPNSection = new Lang.Class({
|
|||||||
item.setActiveConnection(null);
|
item.setActiveConnection(null);
|
||||||
}
|
}
|
||||||
vpnConnections.forEach(Lang.bind(this, function(a) {
|
vpnConnections.forEach(Lang.bind(this, function(a) {
|
||||||
let item = this._connectionItems.get(a._connection.get_uuid());
|
if (a._connection) {
|
||||||
item.setActiveConnection(a);
|
let item = this._connectionItems.get(a._connection.get_uuid());
|
||||||
|
item.setActiveConnection(a);
|
||||||
|
}
|
||||||
}));
|
}));
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -1552,6 +1577,73 @@ const NMVPNSection = new Lang.Class({
|
|||||||
});
|
});
|
||||||
Signals.addSignalMethods(NMVPNSection.prototype);
|
Signals.addSignalMethods(NMVPNSection.prototype);
|
||||||
|
|
||||||
|
const DeviceCategory = new Lang.Class({
|
||||||
|
Name: 'DeviceCategory',
|
||||||
|
Extends: PopupMenu.PopupMenuSection,
|
||||||
|
|
||||||
|
_init: function(category) {
|
||||||
|
this.parent();
|
||||||
|
|
||||||
|
this._category = category;
|
||||||
|
|
||||||
|
this.devices = [];
|
||||||
|
|
||||||
|
this.section = new PopupMenu.PopupMenuSection();
|
||||||
|
this.section.box.connect('actor-added', Lang.bind(this, this._sync));
|
||||||
|
this.section.box.connect('actor-removed', Lang.bind(this, this._sync));
|
||||||
|
this.addMenuItem(this.section);
|
||||||
|
|
||||||
|
this._summaryItem = new PopupMenu.PopupSubMenuMenuItem('', true);
|
||||||
|
this._summaryItem.icon.icon_name = this._getSummaryIcon();
|
||||||
|
this.addMenuItem(this._summaryItem);
|
||||||
|
|
||||||
|
this._summaryItem.menu.addSettingsAction(_('Network Settings'),
|
||||||
|
'gnome-network-panel.desktop');
|
||||||
|
this._summaryItem.actor.hide();
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
_sync: function() {
|
||||||
|
let nDevices = this.section.box.get_children().reduce(
|
||||||
|
function(prev, child) {
|
||||||
|
return prev + (child.visible ? 1 : 0);
|
||||||
|
}, 0);
|
||||||
|
this._summaryItem.label.text = this._getSummaryLabel(nDevices);
|
||||||
|
let shouldSummarize = nDevices > MAX_DEVICE_ITEMS;
|
||||||
|
this._summaryItem.actor.visible = shouldSummarize;
|
||||||
|
this.section.actor.visible = !shouldSummarize;
|
||||||
|
},
|
||||||
|
|
||||||
|
_getSummaryIcon: function() {
|
||||||
|
switch(this._category) {
|
||||||
|
case NMConnectionCategory.WIRED:
|
||||||
|
return 'network-wired-symbolic';
|
||||||
|
case NMConnectionCategory.WIRELESS:
|
||||||
|
case NMConnectionCategory.WWAN:
|
||||||
|
return 'network-wireless-symbolic';
|
||||||
|
}
|
||||||
|
return '';
|
||||||
|
},
|
||||||
|
|
||||||
|
_getSummaryLabel: function(nDevices) {
|
||||||
|
switch(this._category) {
|
||||||
|
case NMConnectionCategory.WIRED:
|
||||||
|
return ngettext("%s Wired Connection",
|
||||||
|
"%s Wired Connections",
|
||||||
|
nDevices).format(nDevices);
|
||||||
|
case NMConnectionCategory.WIRELESS:
|
||||||
|
return ngettext("%s Wi-Fi Connection",
|
||||||
|
"%s Wi-Fi Connections",
|
||||||
|
nDevices).format(nDevices);
|
||||||
|
case NMConnectionCategory.WWAN:
|
||||||
|
return ngettext("%s Modem Connection",
|
||||||
|
"%s Modem Connections",
|
||||||
|
nDevices).format(nDevices);
|
||||||
|
}
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
const NMApplet = new Lang.Class({
|
const NMApplet = new Lang.Class({
|
||||||
Name: 'NMApplet',
|
Name: 'NMApplet',
|
||||||
Extends: PanelMenu.SystemIndicator,
|
Extends: PanelMenu.SystemIndicator,
|
||||||
@ -1595,15 +1687,6 @@ const NMApplet = new Lang.Class({
|
|||||||
this._tryLateInit();
|
this._tryLateInit();
|
||||||
},
|
},
|
||||||
|
|
||||||
_createDeviceCategory: function() {
|
|
||||||
let category = {
|
|
||||||
section: new PopupMenu.PopupMenuSection(),
|
|
||||||
devices: [ ],
|
|
||||||
};
|
|
||||||
this.menu.addMenuItem(category.section);
|
|
||||||
return category;
|
|
||||||
},
|
|
||||||
|
|
||||||
_tryLateInit: function() {
|
_tryLateInit: function() {
|
||||||
if (!this._client || !this._settings)
|
if (!this._client || !this._settings)
|
||||||
return;
|
return;
|
||||||
@ -1620,9 +1703,13 @@ const NMApplet = new Lang.Class({
|
|||||||
this._nmDevices = [];
|
this._nmDevices = [];
|
||||||
this._devices = { };
|
this._devices = { };
|
||||||
|
|
||||||
this._devices.wired = this._createDeviceCategory();
|
let categories = [NMConnectionCategory.WIRED,
|
||||||
this._devices.wireless = this._createDeviceCategory();
|
NMConnectionCategory.WIRELESS,
|
||||||
this._devices.wwan = this._createDeviceCategory();
|
NMConnectionCategory.WWAN];
|
||||||
|
for (let category of categories) {
|
||||||
|
this._devices[category] = new DeviceCategory(category);
|
||||||
|
this.menu.addMenuItem(this._devices[category]);
|
||||||
|
}
|
||||||
|
|
||||||
this._vpnSection = new NMVPNSection(this._client);
|
this._vpnSection = new NMVPNSection(this._client);
|
||||||
this._vpnSection.connect('activation-failed', Lang.bind(this, this._onActivationFailed));
|
this._vpnSection.connect('activation-failed', Lang.bind(this, this._onActivationFailed));
|
||||||
@ -1979,7 +2066,7 @@ const NMApplet = new Lang.Class({
|
|||||||
// (but in general we should only prompt a portal if we know there is a portal)
|
// (but in general we should only prompt a portal if we know there is a portal)
|
||||||
if (GLib.getenv('GNOME_SHELL_CONNECTIVITY_TEST') != null)
|
if (GLib.getenv('GNOME_SHELL_CONNECTIVITY_TEST') != null)
|
||||||
isPortal = isPortal || this._client.connectivity < NetworkManager.ConnectivityState.FULL;
|
isPortal = isPortal || this._client.connectivity < NetworkManager.ConnectivityState.FULL;
|
||||||
if (!isPortal)
|
if (!isPortal || Main.sessionMode.isGreeter)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
let path = this._mainConnection.get_path();
|
let path = this._mainConnection.get_path();
|
||||||
@ -2010,13 +2097,24 @@ const NMApplet = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
_updateIcon: function() {
|
_updateIcon: function() {
|
||||||
if (!this._client.networking_enabled || !this._mainConnection) {
|
if (!this._client.networking_enabled) {
|
||||||
this._primaryIndicator.visible = false;
|
this._primaryIndicator.visible = false;
|
||||||
} else {
|
} else {
|
||||||
let dev = this._mainConnection._primaryDevice;
|
let dev = null;
|
||||||
this._primaryIndicator.visible = (dev != null);
|
if (this._mainConnection)
|
||||||
if (dev)
|
dev = this._mainConnection._primaryDevice;
|
||||||
|
|
||||||
|
let state = this._client.get_state();
|
||||||
|
let connected = state == NetworkManager.State.CONNECTED_GLOBAL;
|
||||||
|
this._primaryIndicator.visible = (dev != null) || connected;
|
||||||
|
if (dev) {
|
||||||
this._primaryIndicator.icon_name = dev.getIndicatorIcon();
|
this._primaryIndicator.icon_name = dev.getIndicatorIcon();
|
||||||
|
} else if (connected) {
|
||||||
|
if (this._client.connectivity == NetworkManager.ConnectivityState.FULL)
|
||||||
|
this._primaryIndicator.icon_name = 'network-wired-symbolic';
|
||||||
|
else
|
||||||
|
this._primaryIndicator.icon_name = 'network-wired-no-route-symbolic';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this._vpnIndicator.icon_name = this._vpnSection.getIndicatorIcon();
|
this._vpnIndicator.icon_name = this._vpnSection.getIndicatorIcon();
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
});
|
@ -48,8 +48,14 @@ const AltSwitcher = new Lang.Class({
|
|||||||
|
|
||||||
this._capturedEventId = global.stage.connect('captured-event', Lang.bind(this, this._onCapturedEvent));
|
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 = new St.Bin();
|
||||||
this.actor.connect('destroy', Lang.bind(this, this._onDestroy));
|
this.actor.connect('destroy', Lang.bind(this, this._onDestroy));
|
||||||
|
this.actor.connect('notify::mapped', () => { this._flipped = false; });
|
||||||
},
|
},
|
||||||
|
|
||||||
_sync: function() {
|
_sync: function() {
|
||||||
@ -58,14 +64,25 @@ const AltSwitcher = new Lang.Class({
|
|||||||
if (this._standard.visible && this._alternate.visible) {
|
if (this._standard.visible && this._alternate.visible) {
|
||||||
let [x, y, mods] = global.get_pointer();
|
let [x, y, mods] = global.get_pointer();
|
||||||
let altPressed = (mods & Clutter.ModifierType.MOD1_MASK) != 0;
|
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) {
|
} else if (this._standard.visible) {
|
||||||
childToShow = this._standard;
|
childToShow = this._standard;
|
||||||
} else if (this._alternate.visible) {
|
} else if (this._alternate.visible) {
|
||||||
childToShow = this._alternate;
|
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());
|
let hasFocus = this.actor.contains(global.stage.get_key_focus());
|
||||||
this.actor.set_child(childToShow);
|
this.actor.set_child(childToShow);
|
||||||
if (hasFocus)
|
if (hasFocus)
|
||||||
@ -96,6 +113,16 @@ const AltSwitcher = new Lang.Class({
|
|||||||
|
|
||||||
return Clutter.EVENT_PROPAGATE;
|
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({
|
const Indicator = new Lang.Class({
|
||||||
|
@ -23,6 +23,7 @@ const EdgeDragAction = imports.ui.edgeDragAction;
|
|||||||
const IconGrid = imports.ui.iconGrid;
|
const IconGrid = imports.ui.iconGrid;
|
||||||
|
|
||||||
const SHELL_KEYBINDINGS_SCHEMA = 'org.gnome.shell.keybindings';
|
const SHELL_KEYBINDINGS_SCHEMA = 'org.gnome.shell.keybindings';
|
||||||
|
const PINCH_GESTURE_THRESHOLD = 0.7;
|
||||||
|
|
||||||
const ViewPage = {
|
const ViewPage = {
|
||||||
WINDOWS: 1,
|
WINDOWS: 1,
|
||||||
@ -51,9 +52,32 @@ function getTermsForSearchString(searchString) {
|
|||||||
return terms;
|
return terms;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const TouchpadShowOverviewAction = new Lang.Class({
|
||||||
|
Name: 'TouchpadShowOverviewAction',
|
||||||
|
|
||||||
|
_init: function(actor) {
|
||||||
|
actor.connect('captured-event', Lang.bind(this, this._handleEvent));
|
||||||
|
},
|
||||||
|
|
||||||
|
_handleEvent: function(actor, event) {
|
||||||
|
if (event.type() != Clutter.EventType.TOUCHPAD_PINCH)
|
||||||
|
return Clutter.EVENT_PROPAGATE;
|
||||||
|
|
||||||
|
if (event.get_touchpad_gesture_finger_count() != 3)
|
||||||
|
return Clutter.EVENT_PROPAGATE;
|
||||||
|
|
||||||
|
if (event.get_gesture_phase() == Clutter.TouchpadGesturePhase.END)
|
||||||
|
this.emit('activated', event.get_gesture_pinch_scale ());
|
||||||
|
|
||||||
|
return Clutter.EVENT_STOP;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
Signals.addSignalMethods(TouchpadShowOverviewAction.prototype);
|
||||||
|
|
||||||
const ShowOverviewAction = new Lang.Class({
|
const ShowOverviewAction = new Lang.Class({
|
||||||
Name: 'ShowOverviewAction',
|
Name: 'ShowOverviewAction',
|
||||||
Extends: Clutter.GestureAction,
|
Extends: Clutter.GestureAction,
|
||||||
|
Signals: { 'activated': {} },
|
||||||
|
|
||||||
_init : function() {
|
_init : function() {
|
||||||
this.parent();
|
this.parent();
|
||||||
@ -112,7 +136,6 @@ const ShowOverviewAction = new Lang.Class({
|
|||||||
this.emit('activated', areaDiff);
|
this.emit('activated', areaDiff);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
Signals.addSignalMethods(ShowOverviewAction.prototype);
|
|
||||||
|
|
||||||
const ViewSelector = new Lang.Class({
|
const ViewSelector = new Lang.Class({
|
||||||
Name: 'ViewSelector',
|
Name: 'ViewSelector',
|
||||||
@ -230,11 +253,16 @@ const ViewSelector = new Lang.Class({
|
|||||||
global.stage.add_action(gesture);
|
global.stage.add_action(gesture);
|
||||||
|
|
||||||
gesture = new ShowOverviewAction();
|
gesture = new ShowOverviewAction();
|
||||||
gesture.connect('activated', Lang.bind(this, function(action, areaDiff) {
|
gesture.connect('activated', Lang.bind(this, this._pinchGestureActivated));
|
||||||
if (areaDiff < 0.7)
|
|
||||||
Main.overview.show();
|
|
||||||
}));
|
|
||||||
global.stage.add_action(gesture);
|
global.stage.add_action(gesture);
|
||||||
|
|
||||||
|
gesture = new TouchpadShowOverviewAction(global.stage);
|
||||||
|
gesture.connect('activated', Lang.bind(this, this._pinchGestureActivated));
|
||||||
|
},
|
||||||
|
|
||||||
|
_pinchGestureActivated: function(action, scale) {
|
||||||
|
if (scale < PINCH_GESTURE_THRESHOLD)
|
||||||
|
Main.overview.show();
|
||||||
},
|
},
|
||||||
|
|
||||||
_toggleAppsPage: function() {
|
_toggleAppsPage: function() {
|
||||||
|
@ -17,6 +17,8 @@ const Main = imports.ui.main;
|
|||||||
const ModalDialog = imports.ui.modalDialog;
|
const ModalDialog = imports.ui.modalDialog;
|
||||||
const Tweener = imports.ui.tweener;
|
const Tweener = imports.ui.tweener;
|
||||||
const WindowMenu = imports.ui.windowMenu;
|
const WindowMenu = imports.ui.windowMenu;
|
||||||
|
const PadOsd = imports.ui.padOsd;
|
||||||
|
const EdgeDragAction = imports.ui.edgeDragAction;
|
||||||
|
|
||||||
const SHELL_KEYBINDINGS_SCHEMA = 'org.gnome.shell.keybindings';
|
const SHELL_KEYBINDINGS_SCHEMA = 'org.gnome.shell.keybindings';
|
||||||
const MINIMIZE_WINDOW_ANIMATION_TIME = 0.2;
|
const MINIMIZE_WINDOW_ANIMATION_TIME = 0.2;
|
||||||
@ -32,6 +34,25 @@ const UNDIM_TIME = 0.250;
|
|||||||
const DISPLAY_REVERT_TIMEOUT = 20; // in seconds - keep in sync with mutter
|
const DISPLAY_REVERT_TIMEOUT = 20; // in seconds - keep in sync with mutter
|
||||||
const ONE_SECOND = 1000; // in ms
|
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({
|
const DisplayChangeDialog = new Lang.Class({
|
||||||
Name: 'DisplayChangeDialog',
|
Name: 'DisplayChangeDialog',
|
||||||
Extends: ModalDialog.ModalDialog,
|
Extends: ModalDialog.ModalDialog,
|
||||||
@ -510,7 +531,7 @@ const TouchpadWorkspaceSwitchAction = new Lang.Class({
|
|||||||
if (event.type() != Clutter.EventType.TOUCHPAD_SWIPE)
|
if (event.type() != Clutter.EventType.TOUCHPAD_SWIPE)
|
||||||
return Clutter.EVENT_PROPAGATE;
|
return Clutter.EVENT_PROPAGATE;
|
||||||
|
|
||||||
if (event.get_gesture_swipe_finger_count() != 4)
|
if (event.get_touchpad_gesture_finger_count() != 4)
|
||||||
return Clutter.EVENT_PROPAGATE;
|
return Clutter.EVENT_PROPAGATE;
|
||||||
|
|
||||||
if (event.get_gesture_phase() == Clutter.TouchpadGesturePhase.UPDATE) {
|
if (event.get_gesture_phase() == Clutter.TouchpadGesturePhase.UPDATE) {
|
||||||
@ -534,6 +555,7 @@ Signals.addSignalMethods(TouchpadWorkspaceSwitchAction.prototype);
|
|||||||
const WorkspaceSwitchAction = new Lang.Class({
|
const WorkspaceSwitchAction = new Lang.Class({
|
||||||
Name: 'WorkspaceSwitchAction',
|
Name: 'WorkspaceSwitchAction',
|
||||||
Extends: Clutter.SwipeAction,
|
Extends: Clutter.SwipeAction,
|
||||||
|
Signals: { 'activated': { param_types: [Meta.MotionDirection.$gtype] } },
|
||||||
|
|
||||||
_init : function() {
|
_init : function() {
|
||||||
const MOTION_THRESHOLD = 50;
|
const MOTION_THRESHOLD = 50;
|
||||||
@ -571,11 +593,11 @@ const WorkspaceSwitchAction = new Lang.Class({
|
|||||||
this.emit('activated', dir);
|
this.emit('activated', dir);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
Signals.addSignalMethods(WorkspaceSwitchAction.prototype);
|
|
||||||
|
|
||||||
const AppSwitchAction = new Lang.Class({
|
const AppSwitchAction = new Lang.Class({
|
||||||
Name: 'AppSwitchAction',
|
Name: 'AppSwitchAction',
|
||||||
Extends: Clutter.GestureAction,
|
Extends: Clutter.GestureAction,
|
||||||
|
Signals: { 'activated': {} },
|
||||||
|
|
||||||
_init : function() {
|
_init : function() {
|
||||||
this.parent();
|
this.parent();
|
||||||
@ -637,7 +659,6 @@ const AppSwitchAction = new Lang.Class({
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
Signals.addSignalMethods(AppSwitchAction.prototype);
|
|
||||||
|
|
||||||
const ResizePopup = new Lang.Class({
|
const ResizePopup = new Lang.Class({
|
||||||
Name: 'ResizePopup',
|
Name: 'ResizePopup',
|
||||||
@ -655,7 +676,7 @@ const ResizePopup = new Lang.Class({
|
|||||||
set: function(rect, displayW, displayH) {
|
set: function(rect, displayW, displayH) {
|
||||||
/* Translators: This represents the size of a window. The first number is
|
/* Translators: This represents the size of a window. The first number is
|
||||||
* the width of the window and the second is the height. */
|
* 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._label.set_text(text);
|
||||||
|
|
||||||
this._widget.set_position(rect.x, rect.y);
|
this._widget.set_position(rect.x, rect.y);
|
||||||
@ -705,6 +726,7 @@ const WindowManager = new Lang.Class({
|
|||||||
this._shellwm.connect('minimize', Lang.bind(this, this._minimizeWindow));
|
this._shellwm.connect('minimize', Lang.bind(this, this._minimizeWindow));
|
||||||
this._shellwm.connect('unminimize', Lang.bind(this, this._unminimizeWindow));
|
this._shellwm.connect('unminimize', Lang.bind(this, this._unminimizeWindow));
|
||||||
this._shellwm.connect('size-change', Lang.bind(this, this._sizeChangeWindow));
|
this._shellwm.connect('size-change', Lang.bind(this, this._sizeChangeWindow));
|
||||||
|
this._shellwm.connect('size-changed', Lang.bind(this, this._sizeChangedWindow));
|
||||||
this._shellwm.connect('map', Lang.bind(this, this._mapWindow));
|
this._shellwm.connect('map', Lang.bind(this, this._mapWindow));
|
||||||
this._shellwm.connect('destroy', Lang.bind(this, this._destroyWindow));
|
this._shellwm.connect('destroy', Lang.bind(this, this._destroyWindow));
|
||||||
this._shellwm.connect('filter-keybinding', Lang.bind(this, this._filterKeybinding));
|
this._shellwm.connect('filter-keybinding', Lang.bind(this, this._filterKeybinding));
|
||||||
@ -917,6 +939,35 @@ const WindowManager = new Lang.Class({
|
|||||||
Lang.bind(this, this._toggleCalendar));
|
Lang.bind(this, this._toggleCalendar));
|
||||||
|
|
||||||
global.display.connect('show-resize-popup', Lang.bind(this, this._showResizePopup));
|
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() {
|
Main.overview.connect('showing', Lang.bind(this, function() {
|
||||||
for (let i = 0; i < this._dimmedWindows.length; i++)
|
for (let i = 0; i < this._dimmedWindows.length; i++)
|
||||||
@ -947,6 +998,18 @@ const WindowManager = new Lang.Class({
|
|||||||
gesture.connect('activated', Lang.bind(this, this._switchApp));
|
gesture.connect('activated', Lang.bind(this, this._switchApp));
|
||||||
global.stage.add_action(gesture);
|
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) {
|
||||||
|
this._currentPadOsd = new PadOsd.PadOsd(device, settings, imagePath, editionMode, monitorIndex);
|
||||||
|
this._currentPadOsd.connect('closed', Lang.bind(this, function() { this._currentPadOsd = null }));
|
||||||
|
|
||||||
|
return this._currentPadOsd.actor;
|
||||||
},
|
},
|
||||||
|
|
||||||
_actionSwitchWorkspace: function(action, direction) {
|
_actionSwitchWorkspace: function(action, direction) {
|
||||||
@ -1073,6 +1136,9 @@ const WindowManager = new Lang.Class({
|
|||||||
if (!this._shouldAnimate())
|
if (!this._shouldAnimate())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
if (!actor.get_texture())
|
||||||
|
return false;
|
||||||
|
|
||||||
let type = actor.meta_window.get_window_type();
|
let type = actor.meta_window.get_window_type();
|
||||||
return types.indexOf(type) >= 0;
|
return types.indexOf(type) >= 0;
|
||||||
},
|
},
|
||||||
@ -1247,37 +1313,17 @@ const WindowManager = new Lang.Class({
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (whichChange == Meta.SizeChange.FULLSCREEN)
|
if ((whichChange == Meta.SizeChange.FULLSCREEN ||
|
||||||
this._fullscreenWindow(shellwm, actor, oldFrameRect, oldBufferRect);
|
whichChange == Meta.SizeChange.UNFULLSCREEN) &&
|
||||||
else if (whichChange == Meta.SizeChange.UNFULLSCREEN)
|
oldFrameRect.width > 0 && oldFrameRect.height > 0)
|
||||||
this._unfullscreenWindow(shellwm, actor, oldFrameRect, oldBufferRect);
|
this._fullscreenAnimation(shellwm, actor, oldFrameRect, whichChange);
|
||||||
else
|
else
|
||||||
shellwm.completed_size_change(actor);
|
shellwm.completed_size_change(actor);
|
||||||
},
|
},
|
||||||
|
|
||||||
_fullscreenWindow: function(shellwm, actor, oldFrameRect, oldBufferRect) {
|
_fullscreenAnimation: function(shellwm, actor, oldFrameRect, change) {
|
||||||
let monitor = Main.layoutManager.monitors[actor.meta_window.get_monitor()];
|
|
||||||
actor.translation_x = oldFrameRect.x - monitor.x;
|
|
||||||
actor.translation_y = oldFrameRect.y - monitor.y;
|
|
||||||
this._fullscreenAnimation(shellwm, actor, oldFrameRect);
|
|
||||||
},
|
|
||||||
|
|
||||||
_unfullscreenWindow: function(shellwm, actor, oldFrameRect, oldBufferRect) {
|
|
||||||
let targetRect = actor.meta_window.get_frame_rect();
|
|
||||||
let monitor = Main.layoutManager.monitors[actor.meta_window.get_monitor()];
|
|
||||||
actor.translation_x = -(targetRect.x - monitor.x);
|
|
||||||
actor.translation_y = -(targetRect.y - monitor.y);
|
|
||||||
this._fullscreenAnimation(shellwm, actor, oldFrameRect);
|
|
||||||
},
|
|
||||||
|
|
||||||
_fullscreenAnimation: function(shellwm, actor, oldFrameRect) {
|
|
||||||
this._resizing.push(actor);
|
|
||||||
|
|
||||||
// Position a clone of the window on top of the old position,
|
// Position a clone of the window on top of the old position,
|
||||||
// while actor updates are frozen.
|
// while actor updates are frozen.
|
||||||
// Note that the MetaWindow has up to date sizing information for
|
|
||||||
// the new geometry already.
|
|
||||||
let targetRect = actor.meta_window.get_frame_rect();
|
|
||||||
let actorContent = Shell.util_get_content_for_window_actor(actor, oldFrameRect);
|
let actorContent = Shell.util_get_content_for_window_actor(actor, oldFrameRect);
|
||||||
let actorClone = new St.Widget({ content: actorContent });
|
let actorClone = new St.Widget({ content: actorContent });
|
||||||
actorClone.set_offscreen_redirect(Clutter.OffscreenRedirect.ALWAYS);
|
actorClone.set_offscreen_redirect(Clutter.OffscreenRedirect.ALWAYS);
|
||||||
@ -1285,10 +1331,28 @@ const WindowManager = new Lang.Class({
|
|||||||
actorClone.set_size(oldFrameRect.width, oldFrameRect.height);
|
actorClone.set_size(oldFrameRect.width, oldFrameRect.height);
|
||||||
Main.uiGroup.add_actor(actorClone);
|
Main.uiGroup.add_actor(actorClone);
|
||||||
|
|
||||||
actor.__fullscreenClone = actorClone;
|
let rect = change == Meta.SizeChange.FULLSCREEN ? oldFrameRect : null;
|
||||||
|
|
||||||
let scaleX = targetRect.width / oldFrameRect.width;
|
if (this._clearFullscreenInfo(actor))
|
||||||
let scaleY = targetRect.height / oldFrameRect.height;
|
this._shellwm.completed_size_change(actor);
|
||||||
|
|
||||||
|
actor.__fullscreenInfo = { clone: actorClone,
|
||||||
|
oldRect: rect };
|
||||||
|
},
|
||||||
|
|
||||||
|
_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();
|
||||||
|
|
||||||
|
let scaleX = targetRect.width / actorClone.width;
|
||||||
|
let scaleY = targetRect.height / actorClone.height;
|
||||||
|
|
||||||
|
this._resizing.push(actor);
|
||||||
|
|
||||||
// Now scale and fade out the clone
|
// Now scale and fade out the clone
|
||||||
Tweener.addTween(actorClone,
|
Tweener.addTween(actorClone,
|
||||||
@ -1301,9 +1365,17 @@ const WindowManager = new Lang.Class({
|
|||||||
transition: 'easeOutQuad'
|
transition: 'easeOutQuad'
|
||||||
});
|
});
|
||||||
|
|
||||||
|
let monitor = Main.layoutManager.monitors[actor.meta_window.get_monitor()];
|
||||||
|
let oldRect = actor.__fullscreenInfo.oldRect;
|
||||||
|
if (oldRect) {
|
||||||
|
actor.translation_x = oldRect.x - monitor.x;
|
||||||
|
actor.translation_y = oldRect.y - monitor.y;
|
||||||
|
} else {
|
||||||
|
actor.translation_x = -(targetRect.x - monitor.x);
|
||||||
|
actor.translation_y = -(targetRect.y - monitor.y);
|
||||||
|
}
|
||||||
|
|
||||||
// Now set scale the actor to size it as the clone.
|
// Now set scale the actor to size it as the clone.
|
||||||
// Note that the caller of this function already set a translation
|
|
||||||
// on the actor.
|
|
||||||
actor.scale_x = 1 / scaleX;
|
actor.scale_x = 1 / scaleX;
|
||||||
actor.scale_y = 1 / scaleY;
|
actor.scale_y = 1 / scaleY;
|
||||||
|
|
||||||
@ -1329,6 +1401,15 @@ const WindowManager = new Lang.Class({
|
|||||||
shellwm.completed_size_change(actor);
|
shellwm.completed_size_change(actor);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_clearFullscreenInfo: function(actor) {
|
||||||
|
if (actor.__fullscreenInfo) {
|
||||||
|
actor.__fullscreenInfo.clone.destroy();
|
||||||
|
delete actor.__fullscreenInfo;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
|
||||||
_sizeChangeWindowDone: function(shellwm, actor) {
|
_sizeChangeWindowDone: function(shellwm, actor) {
|
||||||
if (this._removeEffect(this._resizing, actor)) {
|
if (this._removeEffect(this._resizing, actor)) {
|
||||||
Tweener.removeTweens(actor);
|
Tweener.removeTweens(actor);
|
||||||
@ -1336,23 +1417,13 @@ const WindowManager = new Lang.Class({
|
|||||||
actor.scale_y = 1.0;
|
actor.scale_y = 1.0;
|
||||||
actor.translation_x = 0;
|
actor.translation_x = 0;
|
||||||
actor.translation_y = 0;
|
actor.translation_y = 0;
|
||||||
|
this._clearFullscreenInfo(actor);
|
||||||
let actorClone = actor.__fullscreenClone;
|
|
||||||
if (actorClone) {
|
|
||||||
actorClone.destroy();
|
|
||||||
delete actor.__fullscreenClone;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
_sizeChangeWindowOverwritten: function(shellwm, actor) {
|
_sizeChangeWindowOverwritten: function(shellwm, actor) {
|
||||||
if (this._removeEffect(this._resizing, actor)) {
|
if (this._removeEffect(this._resizing, actor))
|
||||||
let actorClone = actor.__fullscreenClone;
|
this._clearFullscreenInfo(actor);
|
||||||
if (actorClone) {
|
|
||||||
actorClone.destroy();
|
|
||||||
delete actor.__fullscreenClone;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_hasAttachedDialogs: function(window, ignoreWindow) {
|
_hasAttachedDialogs: function(window, ignoreWindow) {
|
||||||
|
@ -97,8 +97,6 @@ const WindowMenu = new Lang.Class({
|
|||||||
if (window.is_always_on_all_workspaces())
|
if (window.is_always_on_all_workspaces())
|
||||||
item.setSensitive(false);
|
item.setSensitive(false);
|
||||||
|
|
||||||
let nWorkspaces = global.screen.n_workspaces;
|
|
||||||
|
|
||||||
if (!isSticky) {
|
if (!isSticky) {
|
||||||
let workspace = window.get_workspace();
|
let workspace = window.get_workspace();
|
||||||
if (workspace != workspace.get_neighbor(Meta.MotionDirection.LEFT)) {
|
if (workspace != workspace.get_neighbor(Meta.MotionDirection.LEFT)) {
|
||||||
|
@ -111,7 +111,7 @@ const WindowClone = new Lang.Class({
|
|||||||
this.metaWindow._delegate = this;
|
this.metaWindow._delegate = this;
|
||||||
this._workspace = workspace;
|
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
|
// We expect this.actor to be used for all interaction rather than
|
||||||
// this._windowClone; as the former is reactive and the latter
|
// this._windowClone; as the former is reactive and the latter
|
||||||
// is not, this just works for most cases. However, for DND all
|
// is not, this just works for most cases. However, for DND all
|
||||||
|
@ -24,9 +24,10 @@ const XdndHandler = new Lang.Class({
|
|||||||
if (!Meta.is_wayland_compositor())
|
if (!Meta.is_wayland_compositor())
|
||||||
global.init_xdnd();
|
global.init_xdnd();
|
||||||
|
|
||||||
global.connect('xdnd-enter', Lang.bind(this, this._onEnter));
|
var dnd = Meta.get_backend().get_dnd();
|
||||||
global.connect('xdnd-position-changed', Lang.bind(this, this._onPositionChanged));
|
dnd.connect('dnd-enter', Lang.bind(this, this._onEnter));
|
||||||
global.connect('xdnd-leave', Lang.bind(this, this._onLeave));
|
dnd.connect('dnd-position-change', Lang.bind(this, this._onPositionChanged));
|
||||||
|
dnd.connect('dnd-leave', Lang.bind(this, this._onLeave));
|
||||||
|
|
||||||
this._windowGroupVisibilityHandlerId = 0;
|
this._windowGroupVisibilityHandlerId = 0;
|
||||||
},
|
},
|
||||||
|
@ -39,6 +39,7 @@ js/ui/mpris.js
|
|||||||
js/ui/notificationDaemon.js
|
js/ui/notificationDaemon.js
|
||||||
js/ui/overviewControls.js
|
js/ui/overviewControls.js
|
||||||
js/ui/overview.js
|
js/ui/overview.js
|
||||||
|
js/ui/padOsd.js
|
||||||
js/ui/panel.js
|
js/ui/panel.js
|
||||||
js/ui/popupMenu.js
|
js/ui/popupMenu.js
|
||||||
js/ui/runDialog.js
|
js/ui/runDialog.js
|
||||||
@ -52,6 +53,7 @@ js/ui/status/brightness.js
|
|||||||
js/ui/status/keyboard.js
|
js/ui/status/keyboard.js
|
||||||
js/ui/status/location.js
|
js/ui/status/location.js
|
||||||
js/ui/status/network.js
|
js/ui/status/network.js
|
||||||
|
js/ui/status/nightLight.js
|
||||||
js/ui/status/power.js
|
js/ui/status/power.js
|
||||||
js/ui/status/rfkill.js
|
js/ui/status/rfkill.js
|
||||||
js/ui/status/system.js
|
js/ui/status/system.js
|
||||||
|
2
po/ar.po
2
po/ar.po
@ -1688,7 +1688,7 @@ msgstr "تقويم إيفُليوشِن"
|
|||||||
#. Translators: Do NOT translate or transliterate this text (this is an icon file name)!
|
#. Translators: Do NOT translate or transliterate this text (this is an icon file name)!
|
||||||
#: src/calendar-server/evolution-calendar.desktop.in:6
|
#: src/calendar-server/evolution-calendar.desktop.in:6
|
||||||
msgid "evolution"
|
msgid "evolution"
|
||||||
msgstr "إيفُليوشن"
|
msgstr "evolution"
|
||||||
|
|
||||||
#. translators:
|
#. translators:
|
||||||
#. * The number of sound outputs on a particular device
|
#. * The number of sound outputs on a particular device
|
||||||
|
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)!
|
#. Translators: Do NOT translate or transliterate this text (this is an icon file name)!
|
||||||
#: src/calendar-server/evolution-calendar.desktop.in:6
|
#: src/calendar-server/evolution-calendar.desktop.in:6
|
||||||
msgid "evolution"
|
msgid "evolution"
|
||||||
msgstr "اوولوشن"
|
msgstr "evolution"
|
||||||
|
|
||||||
#. translators:
|
#. translators:
|
||||||
#. * The number of sound outputs on a particular device
|
#. * 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.
|
# Scottish Gaelic translation for gnome-shell.
|
||||||
# Copyright (C) 2015 gnome-shell's COPYRIGHT HOLDER
|
# Copyright (C) 2015 gnome-shell's COPYRIGHT HOLDER
|
||||||
# This file is distributed under the same license as the gnome-shell package.
|
# 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 ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: gnome-shell master\n"
|
"Project-Id-Version: gnome-shell master\n"
|
||||||
"Report-Msgid-Bugs-To: http://bugzilla.gnome.org/enter_bug.cgi?product=gnome-"
|
"Report-Msgid-Bugs-To: https://bugzilla.gnome.org/enter_bug.cgi?product"
|
||||||
"shell&keywords=I18N+L10N&component=general\n"
|
"=gnome-shell&keywords=I18N+L10N&component=general\n"
|
||||||
"POT-Creation-Date: 2016-09-12 23:57+0000\n"
|
"POT-Creation-Date: 2017-03-02 17:53+0000\n"
|
||||||
"PO-Revision-Date: 2016-09-13 10:47+0100\n"
|
"PO-Revision-Date: 2017-03-07 12:03+0100\n"
|
||||||
"Last-Translator: GunChleoc <fios@foramnagaidhlig.net>\n"
|
"Last-Translator: GunChleoc <fios@foramnagaidhlig.net>\n"
|
||||||
"Language-Team: Fòram na Gàidhlig\n"
|
"Language-Team: Fòram na Gàidhlig\n"
|
||||||
"Language: gd\n"
|
"Language: gd\n"
|
||||||
@ -61,10 +61,136 @@ msgstr "Slige GNOME"
|
|||||||
msgid "Window management and application launching"
|
msgid "Window management and application launching"
|
||||||
msgstr "Stiùireadh uinneagan is tòiseachadh aplacaidean"
|
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
|
#: data/org.gnome.shell.gschema.xml.in:16
|
||||||
msgid "UUIDs of extensions to enable"
|
msgid "UUIDs of extensions to enable"
|
||||||
msgstr "UUIDs nan leudachan ri an cur an comas"
|
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
|
#: data/org.gnome.shell.gschema.xml.in:93
|
||||||
msgid "Keybinding to open the application menu"
|
msgid "Keybinding to open the application menu"
|
||||||
msgstr "Nasgadh iuchrach gus clàr-taice na h-aplacaid fhosgladh"
|
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."
|
msgstr "Nasgadh iuchrach gus clàr-taice na h-aplacaid fhosgladh."
|
||||||
|
|
||||||
#: data/org.gnome.shell.gschema.xml.in:100
|
#: data/org.gnome.shell.gschema.xml.in:100
|
||||||
#| msgid "Keybinding to open the application menu"
|
|
||||||
msgid "Keybinding to open the \"Show Applications\" view"
|
msgid "Keybinding to open the \"Show Applications\" view"
|
||||||
msgstr "Nasgadh iuchrach gus an sealladh \"Seall aplacaidean\" fhosgladh"
|
msgstr "Nasgadh iuchrach gus an sealladh \"Seall aplacaidean\" fhosgladh"
|
||||||
|
|
||||||
#: data/org.gnome.shell.gschema.xml.in:101
|
#: data/org.gnome.shell.gschema.xml.in:101
|
||||||
#| msgid "Keybinding to open the application menu."
|
|
||||||
msgid ""
|
msgid ""
|
||||||
"Keybinding to open the \"Show Applications\" view of the Activities Overview."
|
"Keybinding to open the \"Show Applications\" view of the Activities Overview."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@ -87,23 +211,19 @@ msgstr ""
|
|||||||
"gnìomhachd fhosgladh."
|
"gnìomhachd fhosgladh."
|
||||||
|
|
||||||
#: data/org.gnome.shell.gschema.xml.in:108
|
#: data/org.gnome.shell.gschema.xml.in:108
|
||||||
#| msgid "Keybinding to open the application menu"
|
|
||||||
msgid "Keybinding to open the overview"
|
msgid "Keybinding to open the overview"
|
||||||
msgstr "Nasgadh iuchrach gus am foir-shealladh fhosgladh"
|
msgstr "Nasgadh iuchrach gus am foir-shealladh fhosgladh"
|
||||||
|
|
||||||
#: data/org.gnome.shell.gschema.xml.in:109
|
#: data/org.gnome.shell.gschema.xml.in:109
|
||||||
#| msgid "Keybinding to open the application menu."
|
|
||||||
msgid "Keybinding to open the Activities Overview."
|
msgid "Keybinding to open the Activities Overview."
|
||||||
msgstr "Nasgadh iuchrach gus foir-shealladh na gnìomhachd fhosgladh."
|
msgstr "Nasgadh iuchrach gus foir-shealladh na gnìomhachd fhosgladh."
|
||||||
|
|
||||||
#: data/org.gnome.shell.gschema.xml.in:115
|
#: 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"
|
msgid "Keybinding to toggle the visibility of the notification list"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Nasgadh iuchrach gus an fhaicsinneachd air liosta nam brathan a thoglachadh"
|
"Nasgadh iuchrach gus an fhaicsinneachd air liosta nam brathan a thoglachadh"
|
||||||
|
|
||||||
#: data/org.gnome.shell.gschema.xml.in:116
|
#: 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."
|
msgid "Keybinding to toggle the visibility of the notification list."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Nasgadh iuchrach gus an fhaicsinneachd air liosta nam brathan a thoglachadh."
|
"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."
|
msgid "Keybinding to focus the active notification."
|
||||||
msgstr "Nasgadh iuchrach gus am fòcas a chur air a' bhrath ghnìomhach."
|
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
|
#: data/org.gnome.shell.gschema.xml.in:168
|
||||||
msgid "The application icon mode."
|
msgid "The application icon mode."
|
||||||
msgstr "Modh ìomhaigheag na h-aplacaid."
|
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
|
#: data/org.gnome.Shell.PortalHelper.desktop.in.in:3
|
||||||
msgid "Network Login"
|
msgid "Network Login"
|
||||||
msgstr "Clàradh a-steach lìonraidh"
|
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/gdm/authPrompt.js:147 js/ui/audioDeviceSelection.js:71
|
||||||
#: js/ui/components/networkAgent.js:145 js/ui/components/polkitAgent.js:179
|
#: js/ui/components/networkAgent.js:145 js/ui/components/polkitAgent.js:179
|
||||||
#: js/ui/endSessionDialog.js:483 js/ui/extensionDownloader.js:195
|
#: 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"
|
msgid "Cancel"
|
||||||
msgstr "Sguir dheth"
|
msgstr "Sguir dheth"
|
||||||
|
|
||||||
@ -331,12 +535,12 @@ msgstr "Cuir ris na h-annsachdan"
|
|||||||
msgid "Show Details"
|
msgid "Show Details"
|
||||||
msgstr "Seall am mion-fhiosrachadh"
|
msgstr "Seall am mion-fhiosrachadh"
|
||||||
|
|
||||||
#: js/ui/appFavorites.js:134
|
#: js/ui/appFavorites.js:136
|
||||||
#, javascript-format
|
#, javascript-format
|
||||||
msgid "%s has been added to your favorites."
|
msgid "%s has been added to your favorites."
|
||||||
msgstr "Chaidh %s a chur ris na h-annsachdan agad."
|
msgstr "Chaidh %s a chur ris na h-annsachdan agad."
|
||||||
|
|
||||||
#: js/ui/appFavorites.js:168
|
#: js/ui/appFavorites.js:170
|
||||||
#, javascript-format
|
#, javascript-format
|
||||||
msgid "%s has been removed from your favorites."
|
msgid "%s has been removed from your favorites."
|
||||||
msgstr "Chaidh %s a toirt air falbh o na h-annsachdan agad."
|
msgstr "Chaidh %s a toirt air falbh o na h-annsachdan agad."
|
||||||
@ -346,7 +550,6 @@ msgid "Select Audio Device"
|
|||||||
msgstr "Tagh uidheam fuaime"
|
msgstr "Tagh uidheam fuaime"
|
||||||
|
|
||||||
#: js/ui/audioDeviceSelection.js:69
|
#: js/ui/audioDeviceSelection.js:69
|
||||||
#| msgid "Account Settings"
|
|
||||||
msgid "Sound Settings"
|
msgid "Sound Settings"
|
||||||
msgstr "Roghainnean fuaime"
|
msgstr "Roghainnean fuaime"
|
||||||
|
|
||||||
@ -499,8 +702,8 @@ msgstr "Facal-faire:"
|
|||||||
msgid "Type again:"
|
msgid "Type again:"
|
||||||
msgstr "Am facal-faire a-rithist:"
|
msgstr "Am facal-faire a-rithist:"
|
||||||
|
|
||||||
#: js/ui/components/networkAgent.js:140 js/ui/status/network.js:269
|
#: js/ui/components/networkAgent.js:140 js/ui/status/network.js:270
|
||||||
#: js/ui/status/network.js:352 js/ui/status/network.js:919
|
#: js/ui/status/network.js:353 js/ui/status/network.js:929
|
||||||
msgid "Connect"
|
msgid "Connect"
|
||||||
msgstr "Ceangail"
|
msgstr "Ceangail"
|
||||||
|
|
||||||
@ -528,11 +731,11 @@ msgstr "Facal-faire na h-iuchrach prìobhaidich: "
|
|||||||
msgid "Service: "
|
msgid "Service: "
|
||||||
msgstr "Seirbheis: "
|
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"
|
msgid "Authentication required by wireless network"
|
||||||
msgstr "Tha an lìonra uèirleas ag iarraidh dearbhadh"
|
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
|
#, javascript-format
|
||||||
msgid ""
|
msgid ""
|
||||||
"Passwords or encryption keys are required to access the wireless network "
|
"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 "
|
"Tha feum air faclan-faire no iuchraichean crioptachaidh gus an lìonra "
|
||||||
"uèirleas “%s” inntrigeadh."
|
"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"
|
msgid "Wired 802.1X authentication"
|
||||||
msgstr "Dearbhadh Wired 802.1X"
|
msgstr "Dearbhadh Wired 802.1X"
|
||||||
|
|
||||||
@ -549,15 +752,15 @@ msgstr "Dearbhadh Wired 802.1X"
|
|||||||
msgid "Network name: "
|
msgid "Network name: "
|
||||||
msgstr "Ainm an lìonraidh: "
|
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"
|
msgid "DSL authentication"
|
||||||
msgstr "Dearbhadh DSL"
|
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"
|
msgid "PIN code required"
|
||||||
msgstr "Tha feum air còd PIN"
|
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"
|
msgid "PIN code is needed for the mobile broadband device"
|
||||||
msgstr "Tha feum air còd PIN airson an inneil-làimhe banna-leathainn"
|
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: "
|
msgid "PIN: "
|
||||||
msgstr "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"
|
msgid "Mobile broadband network password"
|
||||||
msgstr "Facal-faire a' bhanna-leathainn inneil-làimhe"
|
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:349 js/ui/components/networkAgent.js:671
|
||||||
#: js/ui/components/networkAgent.js:667 js/ui/components/networkAgent.js:680
|
#: js/ui/components/networkAgent.js:675 js/ui/components/networkAgent.js:688
|
||||||
#, javascript-format
|
#, javascript-format
|
||||||
msgid "A password is required to connect to “%s”."
|
msgid "A password is required to connect to “%s”."
|
||||||
msgstr "tha feum air facal-faire airson ceangal ri “%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"
|
msgid "Network Manager"
|
||||||
msgstr "Manaidsear nan lìonra"
|
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"
|
msgstr "Cuir a' chumhachd dheth nuair a bhios na h-ùrachaidhean air an stàladh"
|
||||||
|
|
||||||
#: js/ui/endSessionDialog.js:137
|
#: js/ui/endSessionDialog.js:137
|
||||||
#| msgctxt "title"
|
|
||||||
#| msgid "Restart & Install Updates"
|
|
||||||
msgctxt "title"
|
msgctxt "title"
|
||||||
msgid "Restart & Install Upgrade"
|
msgid "Restart & Install Upgrade"
|
||||||
msgstr "Ath-thòisich ⁊ stàlaich an t-àrdachadh"
|
msgstr "Ath-thòisich ⁊ stàlaich an t-àrdachadh"
|
||||||
@ -896,14 +1097,10 @@ msgid "System Information"
|
|||||||
msgstr "Fiosrachadh an t-siostaim"
|
msgstr "Fiosrachadh an t-siostaim"
|
||||||
|
|
||||||
#: js/ui/mpris.js:194
|
#: js/ui/mpris.js:194
|
||||||
#| msgctxt "program"
|
|
||||||
#| msgid "Unknown"
|
|
||||||
msgid "Unknown artist"
|
msgid "Unknown artist"
|
||||||
msgstr "Neach-ciùil nach aithne dhuinn"
|
msgstr "Neach-ciùil nach aithne dhuinn"
|
||||||
|
|
||||||
#: js/ui/mpris.js:195
|
#: js/ui/mpris.js:195
|
||||||
#| msgctxt "program"
|
|
||||||
#| msgid "Unknown"
|
|
||||||
msgid "Unknown title"
|
msgid "Unknown title"
|
||||||
msgstr "Tiotal nach aithne dhuinn"
|
msgstr "Tiotal nach aithne dhuinn"
|
||||||
|
|
||||||
@ -963,6 +1160,10 @@ msgstr "Cuir a-steach àithne"
|
|||||||
msgid "Close"
|
msgid "Close"
|
||||||
msgstr "Dùin"
|
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
|
#: js/ui/runDialog.js:282
|
||||||
msgid "Restarting…"
|
msgid "Restarting…"
|
||||||
msgstr "'Ga thòiseachadh às ùr…"
|
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
|
#. XXX: another option is to kick the user into the gdm login
|
||||||
#. screen, where we're not affected by grabs
|
#. 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"
|
msgid "Unable to lock"
|
||||||
msgstr "Cha ghabh a ghlasadh"
|
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"
|
msgid "Lock was blocked by an application"
|
||||||
msgstr "Chaidh a' ghlas a bhacadh le aplacaid"
|
msgstr "Chaidh a' ghlas a bhacadh le aplacaid"
|
||||||
|
|
||||||
@ -1094,7 +1295,7 @@ msgstr "Teacsa mòr"
|
|||||||
msgid "Bluetooth"
|
msgid "Bluetooth"
|
||||||
msgstr "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"
|
msgid "Bluetooth Settings"
|
||||||
msgstr "Roghainnean Bluetooth"
|
msgstr "Roghainnean Bluetooth"
|
||||||
|
|
||||||
@ -1116,13 +1317,13 @@ msgstr "Dheth"
|
|||||||
msgid "Not In Use"
|
msgid "Not In Use"
|
||||||
msgstr "Chan eil e 'ga chleachdadh"
|
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"
|
msgid "Turn On"
|
||||||
msgstr "Cuir air"
|
msgstr "Cuir air"
|
||||||
|
|
||||||
#: js/ui/status/bluetooth.js:142 js/ui/status/network.js:178
|
#: js/ui/status/bluetooth.js:142 js/ui/status/network.js:179
|
||||||
#: js/ui/status/network.js:353 js/ui/status/network.js:1279
|
#: js/ui/status/network.js:354 js/ui/status/network.js:1289
|
||||||
#: js/ui/status/network.js:1394 js/ui/status/rfkill.js:90
|
#: js/ui/status/network.js:1404 js/ui/status/rfkill.js:90
|
||||||
#: js/ui/status/rfkill.js:117
|
#: js/ui/status/rfkill.js:117
|
||||||
msgid "Turn Off"
|
msgid "Turn Off"
|
||||||
msgstr "Cuir dheth"
|
msgstr "Cuir dheth"
|
||||||
@ -1171,18 +1372,18 @@ msgstr ""
|
|||||||
"'S urrainn dhut inntrigeadh an ionaid atharrachadh uair sam bith ann an "
|
"'S urrainn dhut inntrigeadh an ionaid atharrachadh uair sam bith ann an "
|
||||||
"roghainnean na prìobhaideachd."
|
"roghainnean na prìobhaideachd."
|
||||||
|
|
||||||
#: js/ui/status/network.js:101
|
#: js/ui/status/network.js:102
|
||||||
msgid "<unknown>"
|
msgid "<unknown>"
|
||||||
msgstr "<neo-aithnichte>"
|
msgstr "<neo-aithnichte>"
|
||||||
|
|
||||||
#. Translators: %s is a network identifier
|
#. 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
|
#, javascript-format
|
||||||
msgid "%s Off"
|
msgid "%s Off"
|
||||||
msgstr "%s dheth"
|
msgstr "%s dheth"
|
||||||
|
|
||||||
#. Translators: %s is a network identifier
|
#. Translators: %s is a network identifier
|
||||||
#: js/ui/status/network.js:454
|
#: js/ui/status/network.js:455
|
||||||
#, javascript-format
|
#, javascript-format
|
||||||
msgid "%s Connected"
|
msgid "%s Connected"
|
||||||
msgstr "%s ceangailte"
|
msgstr "%s ceangailte"
|
||||||
@ -1190,168 +1391,168 @@ msgstr "%s ceangailte"
|
|||||||
#. Translators: this is for network devices that are physically present but are not
|
#. 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);
|
#. under NetworkManager's control (and thus cannot be used in the menu);
|
||||||
#. %s is a network identifier
|
#. %s is a network identifier
|
||||||
#: js/ui/status/network.js:459
|
#: js/ui/status/network.js:460
|
||||||
#, javascript-format
|
#, javascript-format
|
||||||
msgid "%s Unmanaged"
|
msgid "%s Unmanaged"
|
||||||
msgstr "%s gun stiùireadh"
|
msgstr "%s gun stiùireadh"
|
||||||
|
|
||||||
#. Translators: %s is a network identifier
|
#. Translators: %s is a network identifier
|
||||||
#: js/ui/status/network.js:462
|
#: js/ui/status/network.js:463
|
||||||
#, javascript-format
|
#, javascript-format
|
||||||
msgid "%s Disconnecting"
|
msgid "%s Disconnecting"
|
||||||
msgstr "A' dì-cheangal %s"
|
msgstr "A' dì-cheangal %s"
|
||||||
|
|
||||||
#. Translators: %s is a network identifier
|
#. 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
|
#, javascript-format
|
||||||
msgid "%s Connecting"
|
msgid "%s Connecting"
|
||||||
msgstr "A' ceangal %s"
|
msgstr "A' ceangal %s"
|
||||||
|
|
||||||
#. Translators: this is for network connections that require some kind of key or password; %s is a network identifier
|
#. 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
|
#, javascript-format
|
||||||
msgid "%s Requires Authentication"
|
msgid "%s Requires Authentication"
|
||||||
msgstr "Tha %s ag iarraidh dearbhadh"
|
msgstr "Tha %s ag iarraidh dearbhadh"
|
||||||
|
|
||||||
#. Translators: this is for devices that require some kind of firmware or kernel
|
#. Translators: this is for devices that require some kind of firmware or kernel
|
||||||
#. module, which is missing; %s is a network identifier
|
#. module, which is missing; %s is a network identifier
|
||||||
#: js/ui/status/network.js:480
|
#: js/ui/status/network.js:481
|
||||||
#, javascript-format
|
#, javascript-format
|
||||||
msgid "Firmware Missing For %s"
|
msgid "Firmware Missing For %s"
|
||||||
msgstr "Tha bathar-an-sàs a dhìth air %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
|
#. 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
|
#. 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
|
#, javascript-format
|
||||||
msgid "%s Unavailable"
|
msgid "%s Unavailable"
|
||||||
msgstr "Chan eil %s ri fhaighinn"
|
msgstr "Chan eil %s ri fhaighinn"
|
||||||
|
|
||||||
#. Translators: %s is a network identifier
|
#. Translators: %s is a network identifier
|
||||||
#: js/ui/status/network.js:487
|
#: js/ui/status/network.js:488
|
||||||
#, javascript-format
|
#, javascript-format
|
||||||
msgid "%s Connection Failed"
|
msgid "%s Connection Failed"
|
||||||
msgstr "Dh'fhàillig le %s a cheangal"
|
msgstr "Dh'fhàillig le %s a cheangal"
|
||||||
|
|
||||||
#: js/ui/status/network.js:503
|
#: js/ui/status/network.js:504
|
||||||
msgid "Wired Settings"
|
msgid "Wired Settings"
|
||||||
msgstr "Roghainnean le uèir"
|
msgstr "Roghainnean le uèir"
|
||||||
|
|
||||||
#: js/ui/status/network.js:545
|
#: js/ui/status/network.js:546
|
||||||
msgid "Mobile Broadband Settings"
|
msgid "Mobile Broadband Settings"
|
||||||
msgstr "Roghainnean banna-leathainn inneal-làimhe"
|
msgstr "Roghainnean banna-leathainn inneal-làimhe"
|
||||||
|
|
||||||
#. Translators: %s is a network identifier
|
#. 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
|
#, javascript-format
|
||||||
msgid "%s Hardware Disabled"
|
msgid "%s Hardware Disabled"
|
||||||
msgstr "Tha bathar-cruaidh %s à comas"
|
msgstr "Tha bathar-cruaidh %s à comas"
|
||||||
|
|
||||||
#. Translators: this is for a network device that cannot be activated
|
#. Translators: this is for a network device that cannot be activated
|
||||||
#. because it's disabled by rfkill (airplane mode); %s is a network identifier
|
#. 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
|
#, javascript-format
|
||||||
msgid "%s Disabled"
|
msgid "%s Disabled"
|
||||||
msgstr "%s à comas"
|
msgstr "%s à comas"
|
||||||
|
|
||||||
#: js/ui/status/network.js:632
|
#: js/ui/status/network.js:633
|
||||||
msgid "Connect to Internet"
|
msgid "Connect to Internet"
|
||||||
msgstr "Ceangail ris an eadar-lìon"
|
msgstr "Ceangail ris an eadar-lìon"
|
||||||
|
|
||||||
#: js/ui/status/network.js:813
|
#: js/ui/status/network.js:823
|
||||||
msgid "Airplane Mode is On"
|
msgid "Airplane Mode is On"
|
||||||
msgstr "Tha am modh itealain air"
|
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."
|
msgid "Wi-Fi is disabled when airplane mode is on."
|
||||||
msgstr "Tha WiFi à comas fhad 's a tha am modh itealain air."
|
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"
|
msgid "Turn Off Airplane Mode"
|
||||||
msgstr "Cuir am modh itealain dheth"
|
msgstr "Cuir am modh itealain dheth"
|
||||||
|
|
||||||
#: js/ui/status/network.js:824
|
#: js/ui/status/network.js:834
|
||||||
msgid "Wi-Fi is Off"
|
msgid "Wi-Fi is Off"
|
||||||
msgstr "Tha WiFi dheth"
|
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."
|
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."
|
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"
|
msgid "Turn On Wi-Fi"
|
||||||
msgstr "Cuir WiFi air"
|
msgstr "Cuir WiFi air"
|
||||||
|
|
||||||
#: js/ui/status/network.js:851
|
#: js/ui/status/network.js:861
|
||||||
msgid "Wi-Fi Networks"
|
msgid "Wi-Fi Networks"
|
||||||
msgstr "Lìonraidhean WiFi"
|
msgstr "Lìonraidhean WiFi"
|
||||||
|
|
||||||
#: js/ui/status/network.js:853
|
#: js/ui/status/network.js:863
|
||||||
msgid "Select a network"
|
msgid "Select a network"
|
||||||
msgstr "Tagh lìonra"
|
msgstr "Tagh lìonra"
|
||||||
|
|
||||||
#: js/ui/status/network.js:883
|
#: js/ui/status/network.js:893
|
||||||
msgid "No Networks"
|
msgid "No Networks"
|
||||||
msgstr "Chan eil lìonra ann"
|
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"
|
msgid "Use hardware switch to turn off"
|
||||||
msgstr "Cleachd suidse bathair-chruaidh gus a chur dheth"
|
msgstr "Cleachd suidse bathair-chruaidh gus a chur dheth"
|
||||||
|
|
||||||
#: js/ui/status/network.js:1171
|
#: js/ui/status/network.js:1181
|
||||||
msgid "Select Network"
|
msgid "Select Network"
|
||||||
msgstr "Tagh lìonra"
|
msgstr "Tagh lìonra"
|
||||||
|
|
||||||
#: js/ui/status/network.js:1177
|
#: js/ui/status/network.js:1187
|
||||||
msgid "Wi-Fi Settings"
|
msgid "Wi-Fi Settings"
|
||||||
msgstr "Roghainnean WiFi"
|
msgstr "Roghainnean WiFi"
|
||||||
|
|
||||||
#. Translators: %s is a network identifier
|
#. Translators: %s is a network identifier
|
||||||
#: js/ui/status/network.js:1296
|
#: js/ui/status/network.js:1306
|
||||||
#, javascript-format
|
#, javascript-format
|
||||||
msgid "%s Hotspot Active"
|
msgid "%s Hotspot Active"
|
||||||
msgstr "Tha %s hotspot gnìomhach"
|
msgstr "Tha %s hotspot gnìomhach"
|
||||||
|
|
||||||
#. Translators: %s is a network identifier
|
#. Translators: %s is a network identifier
|
||||||
#: js/ui/status/network.js:1311
|
#: js/ui/status/network.js:1321
|
||||||
#, javascript-format
|
#, javascript-format
|
||||||
msgid "%s Not Connected"
|
msgid "%s Not Connected"
|
||||||
msgstr "Chan eil %s ceangailte"
|
msgstr "Chan eil %s ceangailte"
|
||||||
|
|
||||||
#: js/ui/status/network.js:1411
|
#: js/ui/status/network.js:1421
|
||||||
msgid "connecting..."
|
msgid "connecting..."
|
||||||
msgstr "'ga cheangal..."
|
msgstr "'ga cheangal..."
|
||||||
|
|
||||||
#. Translators: this is for network connections that require some kind of key or password
|
#. 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"
|
msgid "authentication required"
|
||||||
msgstr "tha feum air dearbhadh"
|
msgstr "tha feum air dearbhadh"
|
||||||
|
|
||||||
#: js/ui/status/network.js:1416
|
#: js/ui/status/network.js:1426
|
||||||
msgid "connection failed"
|
msgid "connection failed"
|
||||||
msgstr "dh'fhàillig leis a' cheangal"
|
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"
|
msgid "Network Settings"
|
||||||
msgstr "Roghainnean an lìonraidh"
|
msgstr "Roghainnean an lìonraidh"
|
||||||
|
|
||||||
#: js/ui/status/network.js:1484
|
#: js/ui/status/network.js:1494
|
||||||
msgid "VPN Settings"
|
msgid "VPN Settings"
|
||||||
msgstr "Roghainnean VPN"
|
msgstr "Roghainnean VPN"
|
||||||
|
|
||||||
#: js/ui/status/network.js:1503
|
#: js/ui/status/network.js:1513
|
||||||
msgid "VPN"
|
msgid "VPN"
|
||||||
msgstr "VPN"
|
msgstr "VPN"
|
||||||
|
|
||||||
#: js/ui/status/network.js:1513
|
#: js/ui/status/network.js:1523
|
||||||
msgid "VPN Off"
|
msgid "VPN Off"
|
||||||
msgstr "Tha VPN dheth"
|
msgstr "Tha VPN dheth"
|
||||||
|
|
||||||
#: js/ui/status/network.js:1697
|
#: js/ui/status/network.js:1711
|
||||||
msgid "Connection failed"
|
msgid "Connection failed"
|
||||||
msgstr "Dh'fhàillig leis a' cheangal"
|
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"
|
msgid "Activation of network connection failed"
|
||||||
msgstr "Dh'fhàillig gnìomhachadh a' cheangail ris an lìonra"
|
msgstr "Dh'fhàillig gnìomhachadh a' cheangail ris an lìonra"
|
||||||
|
|
||||||
|
48
po/he.po
48
po/he.po
@ -2319,33 +2319,9 @@ msgstr "המשתמש בחר להתעלם מתיבת דו־שיח האימות"
|
|||||||
|
|
||||||
#~ msgid "Networking is disabled"
|
#~ msgid "Networking is disabled"
|
||||||
#~ msgstr "תכונת הרשת מנוטרלת"
|
#~ msgstr "תכונת הרשת מנוטרלת"
|
||||||
|
|
||||||
#~ msgid "%d hour remaining"
|
|
||||||
#~ msgid_plural "%d hours remaining"
|
|
||||||
#~ msgstr[0] "נותרה שעה"
|
|
||||||
#~ msgstr[1] "נותרו %d שעות"
|
|
||||||
#~ msgstr[2] "נותרו שעתיים"
|
|
||||||
|
|
||||||
#~ msgid "%d %s %d %s remaining"
|
#~ msgid "%d %s %d %s remaining"
|
||||||
#~ msgstr "%d %s %d %s נותרו"
|
#~ 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"
|
#~ msgid "AC Adapter"
|
||||||
#~ msgstr "מתאם חשמל"
|
#~ msgstr "מתאם חשמל"
|
||||||
@ -2611,30 +2587,6 @@ msgstr "המשתמש בחר להתעלם מתיבת דו־שיח האימות"
|
|||||||
|
|
||||||
#~ msgid "Less than a minute ago"
|
#~ msgid "Less than a minute ago"
|
||||||
#~ msgstr "לפני פחות מדקה"
|
#~ 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"
|
#~ msgid "Shut Down"
|
||||||
#~ msgstr "כיבוי"
|
#~ msgstr "כיבוי"
|
||||||
|
2
po/hr.po
2
po/hr.po
@ -313,7 +313,7 @@ msgstr "Mrežna prijava"
|
|||||||
#. Translators: Do NOT translate or transliterate this text (this is an icon file name)!
|
#. Translators: Do NOT translate or transliterate this text (this is an icon file name)!
|
||||||
#: data/org.gnome.Shell.PortalHelper.desktop.in.in:9
|
#: data/org.gnome.Shell.PortalHelper.desktop.in.in:9
|
||||||
msgid "network-workgroup"
|
msgid "network-workgroup"
|
||||||
msgstr "mreža-radnagrupa"
|
msgstr "network-workgroup"
|
||||||
|
|
||||||
#: js/extensionPrefs/main.js:117
|
#: js/extensionPrefs/main.js:117
|
||||||
#, javascript-format
|
#, javascript-format
|
||||||
|
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)!
|
#. Translators: Do NOT translate or transliterate this text (this is an icon file name)!
|
||||||
#: data/org.gnome.Shell.PortalHelper.desktop.in.in:9
|
#: data/org.gnome.Shell.PortalHelper.desktop.in.in:9
|
||||||
msgid "network-workgroup"
|
msgid "network-workgroup"
|
||||||
msgstr "Grupo de Trabalho na Rede"
|
msgstr "network-workgroup"
|
||||||
|
|
||||||
#: js/extensionPrefs/main.js:117
|
#: js/extensionPrefs/main.js:117
|
||||||
#, javascript-format
|
#, 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)!
|
#. Translators: Do NOT translate or transliterate this text (this is an icon file name)!
|
||||||
#: src/calendar-server/evolution-calendar.desktop.in:6
|
#: src/calendar-server/evolution-calendar.desktop.in:6
|
||||||
msgid "evolution"
|
msgid "evolution"
|
||||||
msgstr "Evolution"
|
msgstr "evolution"
|
||||||
|
|
||||||
#. translators:
|
#. translators:
|
||||||
#. * The number of sound outputs on a particular device
|
#. * The number of sound outputs on a particular device
|
||||||
|
931
po/pt_BR.po
931
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