Compare commits
15 Commits
3.11.3
...
wip/deskto
Author | SHA1 | Date | |
---|---|---|---|
45797a977b | |||
884b94233e | |||
74d3e3139f | |||
77b5385cc3 | |||
d749d646be | |||
fa8224d7b5 | |||
f687197ccc | |||
28a6aefb6c | |||
96c2a90e11 | |||
63cf46e49b | |||
200a9ef1af | |||
6050ca6e0c | |||
8bd7db9227 | |||
982feb85c1 | |||
f165cc23c0 |
2
.gitignore
vendored
2
.gitignore
vendored
@ -43,8 +43,6 @@ docs/reference/*/xml/
|
||||
docs/reference/shell/doc-gen-*
|
||||
gtk-doc.make
|
||||
js/misc/config.js
|
||||
js/js-resources.c
|
||||
js/js-resources.h
|
||||
intltool-extract.in
|
||||
intltool-merge.in
|
||||
intltool-update.in
|
||||
|
@ -1,11 +1,7 @@
|
||||
# Point to our macro directory and pick up user flags from the environment
|
||||
ACLOCAL_AMFLAGS = -I m4 ${ACLOCAL_FLAGS}
|
||||
|
||||
SUBDIRS = data js src tests po docs
|
||||
|
||||
if BUILD_BROWSER_PLUGIN
|
||||
SUBDIRS += browser-plugin
|
||||
endif
|
||||
SUBDIRS = data js src browser-plugin tests po docs
|
||||
|
||||
if ENABLE_MAN
|
||||
SUBDIRS += man
|
||||
|
119
NEWS
119
NEWS
@ -1,122 +1,3 @@
|
||||
3.11.3
|
||||
======
|
||||
* Fix fade effect of desktop icons [Florian; #707671]
|
||||
* Fix issues with background management code [Jasper; #709313]
|
||||
* Use new Glib facilities for application search [Jasper; #711631]
|
||||
* Add focus indication to session menu button [Sebastien; #710539]
|
||||
* Fix hover tracking for StEntries [Jasper; #706749]
|
||||
* Fix reentrancy issue in message tray [Jasper; #711694]
|
||||
* Tone down zoom animation on login/unlock [Jasper; #712362]
|
||||
* Allow specifying monitor for OSD [Carlos; #712664]
|
||||
* Fix resetting prompt on user switch [Ray; #710456]
|
||||
* Stop using gnome-bluetooth-applet [Bastien; #719341]
|
||||
* Add support for EAP-FAST password requests [Dan; #719813]
|
||||
* Fix entry focus of chat notifications [Jasper; #709853]
|
||||
* Make window previews keyboard navigatable [Jasper; #644306]
|
||||
* Fix app switcher order with dialog windows [Florian; #719824]
|
||||
* Allow remote search providers without icons [Debarshi; #719965]
|
||||
* Fix various alignment issues in RTL locales [Yosef; #712638, #712596,
|
||||
#712594, #712600, #712579]
|
||||
* Misc. bug fixes and cleanups [Jasper, Florian, Giovanni, Dan; #712727,
|
||||
#712753, #719378, #719730, #719803, #710115, #720017, #719815, #719567,
|
||||
#720298]
|
||||
|
||||
Contributors:
|
||||
Giovanni Campagna, Carlos Garnacho, Sebastien Lafargue, Tim Lunn,
|
||||
Florian Müllner, Bastien Nocera, Yosef Or Boczko, Debarshi Ray,
|
||||
Jasper St. Pierre, Ray Strode, Dan Williams
|
||||
|
||||
Translations:
|
||||
Kjartan Maraas [nb], Reinout van Schouwen [nl], Rafael Ferreira [pt_BR],
|
||||
Mattias Põldaru [et], Emin Tufan Çetin [tr], Jiri Grönroos [fi],
|
||||
Khaled Hosny [ar], Fran Diéguez [gl], Victor Ibragimov [tg],
|
||||
Daniel Mustieles [es]
|
||||
|
||||
3.11.2
|
||||
======
|
||||
* Cache search result display actors [Jasper; #704912]
|
||||
* Use username in userWidget if real name doesn't fit [Jasper; #706851]
|
||||
* Support shell_global_reexec_self() on OpenBSD [Antoine; #709571]
|
||||
* Support disabling browser plugin [Colin; #711218]
|
||||
* Restore support for 'disable-restart-buttons' [Florian; #711244]
|
||||
* Validate parameters of exposed DBus methods [Florian; #699752]
|
||||
* Connect applications to systemd journal if available [Colin; #711626]
|
||||
* Misc bug fixes and cleanups [Florian, Jasper; #711205, #698486, #711416,
|
||||
#644306, #711555, #709806, #711631, #711732]
|
||||
|
||||
Contributors:
|
||||
Cosimo Cecchi, Antoine Jacoutot, Florian Müllner, Jasper St. Pierre,
|
||||
Rico Tzschichholz, Colin Walters
|
||||
|
||||
Translations:
|
||||
Yuri Myasoedov [ru], Kjartan Maraas [nb], Efstathios Iosifidis [el],
|
||||
Benjamin Steinwender [de], eternalhui [zh_CN], Shantha kumar [ta]
|
||||
|
||||
3.11.1
|
||||
======
|
||||
* power: Use UPower directly instead of gnome-settings-daemon [Bastien; #710273]
|
||||
* Implement support for new GTK+ notification API [Jasper, Giovanni, Florian;
|
||||
#710137, #710596]
|
||||
* gdm: Don't allow user-list to fill up the entire screen [Florian; #710555]
|
||||
* Don't autostart remote search providers at login [Giovanni; #708830]
|
||||
* Fix spacing in end-session dialog [Sebastien; #710543]
|
||||
* Prepare for js24 [Tim; #711052]
|
||||
* Misc bug fixes and cleanups [Jasper, Florian, Adel, Tim, Sebastien; #710347,
|
||||
#710144, #710541, #691409, #710745, #688331, #704912]
|
||||
|
||||
Contributors:
|
||||
Giovanni Campagna, Adel Gadllah, Sebastien Lafargue, Tim Lunn,
|
||||
Florian Müllner, Bastien Nocera, Jasper St. Pierre, Rico Tzschichholz
|
||||
|
||||
Translations:
|
||||
Stas Solovey [ru], Yosef Or Boczko [he], Rafael Ferreira [pt_BR]
|
||||
|
||||
3.10.1
|
||||
======
|
||||
* Make sure lock screen is drawn once before switching user [Giovanni; #708051]
|
||||
* Fix signal strength indicators in network selector [Jasper; #708442]
|
||||
* Scroll search results when focusing provider icons [Jasper; #708868]
|
||||
* Add separate hover/active states to page indicators [Carlos; #708852]
|
||||
* Tweak appearance of user name and avatar [Yash; #702309]
|
||||
* Hide "Turn On" in network menu when disabled by hardware [Giovanni; #709635]
|
||||
* Cancel open keyring prompts when the screen is locked [Florian; #708910]
|
||||
* Differentiate "Not Connected" and "Off" in network menu [Giovanni; #709043]
|
||||
* Make network settings items point to the right device [Giovanni; #709246]
|
||||
* Remove animation of window preview titles [Sebastien; #709392]
|
||||
* Add 'Notifications' switch to tray menu [Florian; #707073]
|
||||
* Make dropdown arrows consistent [Carlos; #709564]
|
||||
* power: Use icon from primary device for status [Jasper; #709925]
|
||||
* Fix XDND drags to overview [Adel; #708887]
|
||||
* Fix workspace switcher disappearing with too many workspaces [Jasper; #694881]
|
||||
* Handle search results with 'special:' prefix specially [Giovanni; #707055]
|
||||
* gdm: Support pre-authenticated logins from oVirt [Vinzenz; #702162]
|
||||
* Use ARROW role for labels representing arrows [Alejandro; #710120]
|
||||
* Make selected view in app picker persistent [Florian; #710042]
|
||||
* Make network selector navigable by keyboard [Alejandro; #710144]
|
||||
* Misc bug fixes [Florian, Adel, Jasper, Aleksander, Giovanni, Dan, Michael,
|
||||
Tim; #709034, #709263, #698486, #709286, #709248, #709543, #696564, #703265,
|
||||
#709638, #709866, #709998, #710019, #710104, #710115]
|
||||
|
||||
Contributors:
|
||||
Giovanni Campagna, Michael Catanzaro, Vinzenz Feenstra, Adel Gadllah,
|
||||
Yash Girdhar, Sebastien Lafargue, Tim Lunn, Aleksander Morgado,
|
||||
Florian Müllner, Alejandro Piñeiro, Carlos Soriano, Jasper St. Pierre,
|
||||
Dieter Verfaillie, Dan Winship
|
||||
|
||||
Translations:
|
||||
Inaki Larranaga Murgoitio [eu], Christian Kirbach [de], Muhammet Kara [tr],
|
||||
Aurimas Černius [lt], Ryan Lortie [eo], Rūdolfs Mazurs [lv],
|
||||
Dušan Kazik [sk], Fran Diéguez [gl], Enrico Nicoletto [pt_BR],
|
||||
Kjartan Maraas [nb], Victor Ibragimov [tg], Matej Urbančič [sl],
|
||||
A S Alam [pa], Nilamdyuti Goswami [as], Daniel Mustieles [es],
|
||||
Cheng-Chia Tseng [zh_HK, zh_TW], Mattias Põldaru [et], Kenneth Nielsen [da],
|
||||
Milo Casagrande [it], Marek Černocký [cs], Ihar Hrachyshka [be],
|
||||
Мирослав Николић [sr, sr@latin], Arash Mousavi [fa], Yuri Myasoedov [ru],
|
||||
Gil Forcada [ca], Carles Ferrando [ca@valencia], Andika Triwidada [id],
|
||||
Timo Jyrinki [fi], Piotr Drąg [pl], Rafael Ferreira [pt_BR],
|
||||
Gabor Kelemen [hu], Yosef Or Boczko [he], Daniel Korostil [uk],
|
||||
Wouter Bolsterlee [nl], António Lima [pt]
|
||||
|
||||
3.10.0.1
|
||||
=========
|
||||
* Fix login screen [Ray; #708691]
|
||||
|
54
configure.ac
54
configure.ac
@ -1,5 +1,5 @@
|
||||
AC_PREREQ(2.63)
|
||||
AC_INIT([gnome-shell],[3.11.3],[https://bugzilla.gnome.org/enter_bug.cgi?product=gnome-shell],[gnome-shell])
|
||||
AC_INIT([gnome-shell],[3.10.0.1],[https://bugzilla.gnome.org/enter_bug.cgi?product=gnome-shell],[gnome-shell])
|
||||
|
||||
AC_CONFIG_HEADERS([config.h])
|
||||
AC_CONFIG_SRCDIR([src/shell-global.c])
|
||||
@ -16,7 +16,6 @@ m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])])
|
||||
|
||||
# Checks for programs.
|
||||
AC_PROG_CC
|
||||
AC_PROG_CXX
|
||||
|
||||
# Initialize libtool
|
||||
LT_PREREQ([2.2.6])
|
||||
@ -58,25 +57,10 @@ fi
|
||||
|
||||
AM_CONDITIONAL(BUILD_RECORDER, $build_recorder)
|
||||
|
||||
AC_ARG_ENABLE([systemd],
|
||||
AS_HELP_STRING([--enable-systemd], [Use systemd]),
|
||||
[enable_systemd=$enableval],
|
||||
[enable_systemd=auto])
|
||||
AS_IF([test x$enable_systemd != xno], [
|
||||
AC_MSG_CHECKING([for libsystemd-journal])
|
||||
PKG_CHECK_EXISTS([libsystemd-journal],
|
||||
[have_systemd=yes
|
||||
AC_DEFINE([HAVE_SYSTEMD], [1], [Define if we have systemd])],
|
||||
[have_systemd=no])
|
||||
AC_MSG_RESULT($have_systemd)
|
||||
])
|
||||
|
||||
AC_MSG_RESULT($enable_systemd)
|
||||
|
||||
CLUTTER_MIN_VERSION=1.13.4
|
||||
GOBJECT_INTROSPECTION_MIN_VERSION=0.10.1
|
||||
GJS_MIN_VERSION=1.39.0
|
||||
MUTTER_MIN_VERSION=3.11.1
|
||||
GJS_MIN_VERSION=1.35.4
|
||||
MUTTER_MIN_VERSION=3.10.0
|
||||
GTK_MIN_VERSION=3.7.9
|
||||
GIO_MIN_VERSION=2.37.0
|
||||
LIBECAL_MIN_VERSION=3.5.3
|
||||
@ -108,9 +92,6 @@ SHARED_PCS="gio-unix-2.0 >= $GIO_MIN_VERSION
|
||||
libnm-glib libnm-util >= $NETWORKMANAGER_MIN_VERSION
|
||||
libnm-gtk >= $NETWORKMANAGER_MIN_VERSION
|
||||
libsecret-unstable gcr-base-3 >= $GCR_MIN_VERSION"
|
||||
if test x$have_systemd = xyes; then
|
||||
SHARED_PCS="${SHARED_PCS} libsystemd-journal"
|
||||
fi
|
||||
|
||||
PKG_CHECK_MODULES(GNOME_SHELL, $SHARED_PCS)
|
||||
PKG_CHECK_MODULES(MUTTER, libmutter >= $MUTTER_MIN_VERSION)
|
||||
@ -126,25 +107,25 @@ PKG_CHECK_MODULES(GNOME_SHELL_JS, gio-2.0 gjs-internals-1.0 >= $GJS_MIN_VERSION)
|
||||
PKG_CHECK_MODULES(ST, clutter-1.0 gtk+-3.0 libcroco-0.6 >= 0.6.8 x11)
|
||||
PKG_CHECK_MODULES(SHELL_PERF_HELPER, gtk+-3.0 gio-2.0)
|
||||
PKG_CHECK_MODULES(SHELL_HOTPLUG_SNIFFER, gio-2.0 gdk-pixbuf-2.0)
|
||||
PKG_CHECK_MODULES(BROWSER_PLUGIN, gio-2.0 >= $GIO_MIN_VERSION json-glib-1.0 >= 0.13.2)
|
||||
PKG_CHECK_MODULES(TRAY, gtk+-3.0)
|
||||
PKG_CHECK_MODULES(GVC, libpulse >= $PULSE_MIN_VERS libpulse-mainloop-glib gobject-2.0)
|
||||
PKG_CHECK_MODULES(DESKTOP_SCHEMAS, gsettings-desktop-schemas >= 3.7.4)
|
||||
PKG_CHECK_MODULES(CARIBOU, caribou-1.0 >= 0.4.8)
|
||||
|
||||
AC_ARG_ENABLE(browser-plugin,
|
||||
[AS_HELP_STRING([--enable-browser-plugin],
|
||||
[Enable browser plugin [default=yes]])],,
|
||||
enable_browser_plugin=yes)
|
||||
AS_IF([test x$enable_browser_plugin = xyes], [
|
||||
PKG_CHECK_MODULES(BROWSER_PLUGIN, gio-2.0 >= $GIO_MIN_VERSION json-glib-1.0 >= 0.13.2)
|
||||
])
|
||||
AM_CONDITIONAL(BUILD_BROWSER_PLUGIN, test x$enable_browser_plugin = xyes)
|
||||
|
||||
PKG_CHECK_MODULES(BLUETOOTH, gnome-bluetooth-1.0 >= 3.9.0,
|
||||
[AC_DEFINE([HAVE_BLUETOOTH],[1],[Define if you have libgnome-bluetooth-applet])
|
||||
AC_SUBST([HAVE_BLUETOOTH],[1])],
|
||||
AC_MSG_CHECKING([for bluetooth support])
|
||||
PKG_CHECK_EXISTS([gnome-bluetooth-1.0 >= 3.9.0],
|
||||
[BLUETOOTH_DIR=`$PKG_CONFIG --variable=applet_libdir gnome-bluetooth-1.0`
|
||||
BLUETOOTH_LIBS=`$PKG_CONFIG --variable=applet_libs gnome-bluetooth-1.0`
|
||||
AC_SUBST([BLUETOOTH_LIBS],["$BLUETOOTH_LIBS"])
|
||||
AC_SUBST([BLUETOOTH_DIR],["$BLUETOOTH_DIR"])
|
||||
AC_DEFINE_UNQUOTED([BLUETOOTH_DIR],["$BLUETOOTH_DIR"],[Path to installed GnomeBluetooth typelib and library])
|
||||
AC_DEFINE([HAVE_BLUETOOTH],[1],[Define if you have libgnome-bluetooth-applet])
|
||||
AC_SUBST([HAVE_BLUETOOTH],[1])
|
||||
AC_MSG_RESULT([yes])],
|
||||
[AC_DEFINE([HAVE_BLUETOOTH],[0])
|
||||
AC_SUBST([HAVE_BLUETOOTH],[0])])
|
||||
AC_SUBST([HAVE_BLUETOOTH],[0])
|
||||
AC_MSG_RESULT([no])])
|
||||
|
||||
PKG_CHECK_MODULES(CALENDAR_SERVER, libecal-1.2 >= $LIBECAL_MIN_VERSION libedataserver-1.2 >= $LIBEDATASERVER_MIN_VERSION gio-2.0)
|
||||
AC_SUBST(CALENDAR_SERVER_CFLAGS)
|
||||
@ -164,9 +145,6 @@ AC_SUBST(MUTTER_TYPELIB_DIR)
|
||||
GJS_CONSOLE=`$PKG_CONFIG --variable=gjs_console gjs-1.0`
|
||||
AC_SUBST(GJS_CONSOLE)
|
||||
|
||||
GLIB_COMPILE_RESOURCES=`$PKG_CONFIG --variable glib_compile_resources gio-2.0`
|
||||
AC_SUBST(GLIB_COMPILE_RESOURCES)
|
||||
|
||||
AC_CHECK_FUNCS(fdwalk)
|
||||
AC_CHECK_FUNCS(mallinfo)
|
||||
AC_CHECK_HEADERS([sys/resource.h])
|
||||
|
@ -1,3 +1,6 @@
|
||||
wandadir = $(pkgdatadir)
|
||||
dist_wanda_DATA = wanda.png
|
||||
|
||||
desktopdir=$(datadir)/applications
|
||||
desktop_DATA = gnome-shell.desktop gnome-shell-extension-prefs.desktop
|
||||
if HAVE_MUTTER_WAYLAND
|
||||
|
@ -37,13 +37,6 @@
|
||||
application view, rather than being displayed inline in the main view.
|
||||
</_description>
|
||||
</key>
|
||||
<key name="app-picker-view" type="u">
|
||||
<default>0</default>
|
||||
<summary>App Picker View</summary>
|
||||
<description>
|
||||
Index of the currently selected view in the application picker.
|
||||
</description>
|
||||
</key>
|
||||
<key name="command-history" type="as">
|
||||
<default>[]</default>
|
||||
<_summary>History for command (Alt-F2) dialog</_summary>
|
||||
|
@ -157,7 +157,7 @@ StScrollBar StButton#vhandle:active {
|
||||
min-width: 200px;
|
||||
}
|
||||
|
||||
.unicode-arrow {
|
||||
.popup-submenu-menu-item-triangle {
|
||||
font-size: 120%;
|
||||
}
|
||||
|
||||
@ -306,13 +306,16 @@ StScrollBar StButton#vhandle:active {
|
||||
font-size: 12pt;
|
||||
border-bottom: 1px solid #666;
|
||||
padding: 12px;
|
||||
spacing: 20px;
|
||||
}
|
||||
|
||||
.nm-dialog-item:selected {
|
||||
.nm-dialog-item:checked {
|
||||
background-color: #333;
|
||||
}
|
||||
|
||||
.nm-dialog-item-box {
|
||||
spacing: 20px;
|
||||
}
|
||||
|
||||
.nm-dialog-icons {
|
||||
spacing: .5em;
|
||||
}
|
||||
@ -690,9 +693,7 @@ StScrollBar StButton#vhandle:active {
|
||||
padding-bottom: 32px;
|
||||
}
|
||||
|
||||
.workspace-thumbnails {
|
||||
spacing: 11px;
|
||||
visible-width: 32px; /* Amount visible before hovering */
|
||||
.workspace-thumbnails-background {
|
||||
border: 1px solid rgba(128, 128, 128, 0.4);
|
||||
border-right: 0px;
|
||||
border-radius: 9px 0px 0px 9px;
|
||||
@ -700,13 +701,18 @@ StScrollBar StButton#vhandle:active {
|
||||
padding: 11px 7px 11px 11px;
|
||||
}
|
||||
|
||||
.workspace-thumbnails:rtl {
|
||||
.workspace-thumbnails-background:rtl {
|
||||
border-right: 1px;
|
||||
border-left: 0px;
|
||||
border-radius: 0px 9px 9px 0px;
|
||||
padding: 11px 11px 11px 7px;
|
||||
}
|
||||
|
||||
.workspace-thumbnails {
|
||||
spacing: 11px;
|
||||
visible-width: 32px; /* Amount visible before hovering */
|
||||
}
|
||||
|
||||
.workspace-thumbnail-indicator {
|
||||
border: 4px solid rgba(255,255,255,0.7);
|
||||
border-radius: 4px;
|
||||
@ -1944,7 +1950,6 @@ StScrollBar StButton#vhandle:active {
|
||||
|
||||
.end-session-dialog-description:rtl {
|
||||
padding-right: 17px;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.end-session-dialog-logout-icon {
|
||||
@ -1968,19 +1973,10 @@ StScrollBar StButton#vhandle:active {
|
||||
padding-left: 50px;
|
||||
}
|
||||
|
||||
.end-session-dialog-session-list,
|
||||
.end-session-dialog-app-list {
|
||||
spacing: 1em;
|
||||
}
|
||||
|
||||
.end-session-dialog-list-header {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.end-session-dialog-list-header:rtl {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.end-session-dialog-app-list-item,
|
||||
.end-session-dialog-session-list-item {
|
||||
spacing: 1em;
|
||||
@ -2100,10 +2096,6 @@ StScrollBar StButton#vhandle:active {
|
||||
color: #666666;
|
||||
}
|
||||
|
||||
.prompt-dialog-description:rtl {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.prompt-dialog-password-box {
|
||||
spacing: 1em;
|
||||
padding-bottom: 1em;
|
||||
@ -2284,7 +2276,7 @@ StScrollBar StButton#vhandle:active {
|
||||
|
||||
.framed-user-icon {
|
||||
border: 2px solid #8b8b8b;
|
||||
border-radius: 3px;
|
||||
border-radius: 5px;
|
||||
background-size: contain;
|
||||
}
|
||||
|
||||
@ -2328,10 +2320,8 @@ StScrollBar StButton#vhandle:active {
|
||||
}
|
||||
|
||||
.login-dialog-user-list-item {
|
||||
border-radius: 5px;
|
||||
border-radius: 10px;
|
||||
padding: .2em;
|
||||
color: #bfbfbf;
|
||||
text-shadow: black 0px 2px 2px;
|
||||
}
|
||||
|
||||
.login-dialog-user-list-item:ltr {
|
||||
@ -2342,6 +2332,23 @@ StScrollBar StButton#vhandle:active {
|
||||
padding-left: 1em;
|
||||
}
|
||||
|
||||
.login-dialog-user-list-item .login-dialog-user-list-item-name {
|
||||
font-size: 20pt;
|
||||
padding-left: 9px;
|
||||
}
|
||||
|
||||
.login-dialog-user-list:expanded .login-dialog-user-list-item {
|
||||
color: #666666;
|
||||
}
|
||||
|
||||
.login-dialog-user-list-item,
|
||||
.login-dialog-user-list-item:hover .login-dialog-user-list-item-name,
|
||||
.login-dialog-user-list:expanded .login-dialog-user-list-item:focus .login-dialog-user-list-item-name,
|
||||
.login-dialog-user-list:expanded .login-dialog-user-list-item:logged-in {
|
||||
color: white;
|
||||
text-shadow: black 0px 2px 2px;
|
||||
}
|
||||
|
||||
.login-dialog-user-list-item:hover {
|
||||
background-color: rgba(255,255,255,0.1);
|
||||
}
|
||||
@ -2368,6 +2375,13 @@ StScrollBar StButton#vhandle:active {
|
||||
background-color: #8b8b8b;
|
||||
}
|
||||
|
||||
.login-dialog-user-list-item-icon {
|
||||
border: 2px solid #8b8b8b;
|
||||
border-radius: 8px;
|
||||
width: 64px;
|
||||
height: 64px;
|
||||
}
|
||||
|
||||
.login-dialog-not-listed-label {
|
||||
font-size: 10.5pt;
|
||||
font-weight: bold;
|
||||
@ -2375,10 +2389,6 @@ StScrollBar StButton#vhandle:active {
|
||||
padding-top: 1em;
|
||||
}
|
||||
|
||||
.login-dialog-user-selection-box {
|
||||
padding: 100px 0;
|
||||
}
|
||||
|
||||
.login-dialog-user-selection-box .login-dialog-not-listed-label {
|
||||
padding-left: 2px;
|
||||
}
|
||||
@ -2418,7 +2428,6 @@ StScrollBar StButton#vhandle:active {
|
||||
}
|
||||
|
||||
.login-dialog-session-list-button:hover,
|
||||
.login-dialog-session-list-button:focus,
|
||||
.login-dialog-session-list-button:active {
|
||||
color: white;
|
||||
}
|
||||
@ -2485,21 +2494,13 @@ StScrollBar StButton#vhandle:active {
|
||||
}
|
||||
|
||||
.user-widget-label {
|
||||
font-size: 20px;
|
||||
font-size: 16pt;
|
||||
font-weight: bold;
|
||||
text-align: left;
|
||||
color:white;
|
||||
padding-left: 15px;
|
||||
text-shadow: black 0px 4px 3px 0px;
|
||||
}
|
||||
|
||||
.user-widget-label:ltr {
|
||||
padding-left: 18px;
|
||||
}
|
||||
|
||||
.user-widget-label:rtl {
|
||||
padding-right: 18px;
|
||||
}
|
||||
|
||||
/* Screen shield */
|
||||
|
||||
#panel.lock-screen,
|
||||
|
BIN
data/wanda.png
Normal file
BIN
data/wanda.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 13 KiB |
@ -112,7 +112,7 @@ expand_content_files=
|
||||
# e.g. GTKDOC_CFLAGS=-I$(top_srcdir) -I$(top_builddir) $(GTK_DEBUG_FLAGS)
|
||||
# e.g. GTKDOC_LIBS=$(top_builddir)/gtk/$(gtktargetlib)
|
||||
GTKDOC_CFLAGS=$(GNOME_SHELL_CFLAGS)
|
||||
GTKDOC_LIBS=$(GNOME_SHELL_LIBS) $(top_builddir)/src/libgnome-shell-menu.la $(top_builddir)/src/libgnome-shell-base.la $(top_builddir)/src/libgnome-shell.la
|
||||
GTKDOC_LIBS=$(GNOME_SHELL_LIBS) $(BLUETOOTH_LIBS) $(top_builddir)/src/libgnome-shell-menu.la $(top_builddir)/src/libgnome-shell-base.la $(top_builddir)/src/libgnome-shell.la
|
||||
|
||||
# This includes the standard gtk-doc make rules, copied by gtkdocize.
|
||||
include $(top_srcdir)/gtk-doc.make
|
||||
|
131
js/Makefile.am
131
js/Makefile.am
@ -1,5 +1,7 @@
|
||||
NULL =
|
||||
BUILT_SOURCES =
|
||||
|
||||
EXTRA_DIST = misc/config.js.in
|
||||
CLEANFILES = misc/config.js
|
||||
|
||||
misc/config.js: misc/config.js.in Makefile
|
||||
[ -d $(@D) ] || $(mkdir_p) $(@D) ; \
|
||||
@ -12,26 +14,111 @@ misc/config.js: misc/config.js.in Makefile
|
||||
-e "s|[@]sysconfdir@|$(sysconfdir)|g" \
|
||||
$< > $@
|
||||
|
||||
js_resource_files = $(shell $(GLIB_COMPILE_RESOURCES) --sourcedir=$(srcdir) --generate-dependencies $(srcdir)/js-resources.gresource.xml)
|
||||
js-resources.h: js-resources.gresource.xml $(js_resource_files) misc/config.js
|
||||
$(AM_V_GEN) $(GLIB_COMPILE_RESOURCES) --target=$@ --sourcedir=$(srcdir) --sourcedir=$(builddir) --generate --c-name shell_js_resources $<
|
||||
js-resources.c: js-resources.gresource.xml $(js_resource_files) misc/config.js
|
||||
$(AM_V_GEN) $(GLIB_COMPILE_RESOURCES) --target=$@ --sourcedir=$(srcdir) --sourcedir=$(builddir) --generate --c-name shell_js_resources $<
|
||||
jsdir = $(pkgdatadir)/js
|
||||
|
||||
js_built_sources = js-resources.c js-resources.h
|
||||
|
||||
BUILT_SOURCES += $(js_built_sources)
|
||||
|
||||
all-local: $(js_built_sources)
|
||||
|
||||
js_resource_dist_files = $(filter-out misc/config.js, $(js_resource_files))
|
||||
|
||||
EXTRA_DIST = \
|
||||
$(js_resource_dist_files) \
|
||||
js-resources.gresource.xml \
|
||||
misc/config.js.in \
|
||||
$(NULL)
|
||||
|
||||
CLEANFILES = \
|
||||
$(js_built_sources) \
|
||||
nobase_dist_js_DATA = \
|
||||
gdm/authPrompt.js \
|
||||
gdm/batch.js \
|
||||
gdm/fingerprint.js \
|
||||
gdm/loginDialog.js \
|
||||
gdm/realmd.js \
|
||||
gdm/util.js \
|
||||
extensionPrefs/main.js \
|
||||
misc/config.js \
|
||||
misc/extensionUtils.js \
|
||||
misc/fileUtils.js \
|
||||
misc/gnomeSession.js \
|
||||
misc/hash.js \
|
||||
misc/history.js \
|
||||
misc/jsParse.js \
|
||||
misc/loginManager.js \
|
||||
misc/modemManager.js \
|
||||
misc/objectManager.js \
|
||||
misc/params.js \
|
||||
misc/smartcardManager.js \
|
||||
misc/util.js \
|
||||
perf/core.js \
|
||||
ui/altTab.js \
|
||||
ui/animation.js \
|
||||
ui/appDisplay.js \
|
||||
ui/appFavorites.js \
|
||||
ui/backgroundMenu.js \
|
||||
ui/background.js \
|
||||
ui/boxpointer.js \
|
||||
ui/calendar.js \
|
||||
ui/checkBox.js \
|
||||
ui/ctrlAltTab.js \
|
||||
ui/dash.js \
|
||||
ui/dateMenu.js \
|
||||
ui/dnd.js \
|
||||
ui/endSessionDialog.js \
|
||||
ui/extensionSystem.js \
|
||||
ui/extensionDownloader.js \
|
||||
ui/environment.js \
|
||||
ui/focusCaretTracker.js\
|
||||
ui/ibusCandidatePopup.js\
|
||||
ui/grabHelper.js \
|
||||
ui/iconGrid.js \
|
||||
ui/keyboard.js \
|
||||
ui/layout.js \
|
||||
ui/lightbox.js \
|
||||
ui/lookingGlass.js \
|
||||
ui/magnifier.js \
|
||||
ui/magnifierDBus.js \
|
||||
ui/main.js \
|
||||
ui/messageTray.js \
|
||||
ui/modalDialog.js \
|
||||
ui/separator.js \
|
||||
ui/sessionMode.js \
|
||||
ui/shellEntry.js \
|
||||
ui/shellMountOperation.js \
|
||||
ui/slider.js \
|
||||
ui/notificationDaemon.js \
|
||||
ui/osdWindow.js \
|
||||
ui/overview.js \
|
||||
ui/overviewControls.js \
|
||||
ui/panel.js \
|
||||
ui/panelMenu.js \
|
||||
ui/pointerWatcher.js \
|
||||
ui/popupMenu.js \
|
||||
ui/remoteSearch.js \
|
||||
ui/remoteMenu.js \
|
||||
ui/runDialog.js \
|
||||
ui/screencast.js \
|
||||
ui/screenshot.js \
|
||||
ui/screenShield.js \
|
||||
ui/scripting.js \
|
||||
ui/search.js \
|
||||
ui/searchDisplay.js \
|
||||
ui/shellDBus.js \
|
||||
ui/status/accessibility.js \
|
||||
ui/status/brightness.js \
|
||||
ui/status/keyboard.js \
|
||||
ui/status/network.js \
|
||||
ui/status/power.js \
|
||||
ui/status/rfkill.js \
|
||||
ui/status/volume.js \
|
||||
ui/status/bluetooth.js \
|
||||
ui/status/screencast.js \
|
||||
ui/status/system.js \
|
||||
ui/switcherPopup.js \
|
||||
ui/tweener.js \
|
||||
ui/unlockDialog.js \
|
||||
ui/userWidget.js \
|
||||
ui/viewSelector.js \
|
||||
ui/wanda.js \
|
||||
ui/windowAttentionHandler.js \
|
||||
ui/windowManager.js \
|
||||
ui/workspace.js \
|
||||
ui/workspaceThumbnail.js \
|
||||
ui/workspacesView.js \
|
||||
ui/workspaceSwitcherPopup.js \
|
||||
ui/xdndHandler.js \
|
||||
ui/components/__init__.js \
|
||||
ui/components/autorunManager.js \
|
||||
ui/components/automountManager.js \
|
||||
ui/components/networkAgent.js \
|
||||
ui/components/polkitAgent.js \
|
||||
ui/components/telepathyClient.js \
|
||||
ui/components/keyring.js \
|
||||
$(NULL)
|
||||
|
@ -13,15 +13,13 @@ const _ = Gettext.gettext;
|
||||
const Config = imports.misc.config;
|
||||
const ExtensionUtils = imports.misc.extensionUtils;
|
||||
|
||||
const GnomeShellIface = '<node> \
|
||||
<interface name="org.gnome.Shell.Extensions"> \
|
||||
<signal name="ExtensionStatusChanged"> \
|
||||
<arg type="s" name="uuid"/> \
|
||||
<arg type="i" name="state"/> \
|
||||
<arg type="s" name="error"/> \
|
||||
</signal> \
|
||||
</interface> \
|
||||
</node>';
|
||||
const GnomeShellIface = <interface name="org.gnome.Shell.Extensions">
|
||||
<signal name="ExtensionStatusChanged">
|
||||
<arg type="s" name="uuid"/>
|
||||
<arg type="i" name="state"/>
|
||||
<arg type="s" name="error"/>
|
||||
</signal>
|
||||
</interface>;
|
||||
|
||||
const GnomeShellProxy = Gio.DBusProxy.makeProxyWrapper(GnomeShellIface);
|
||||
|
||||
@ -206,11 +204,11 @@ const Application = new Lang.Class({
|
||||
_scanExtensions: function() {
|
||||
let finder = new ExtensionUtils.ExtensionFinder();
|
||||
finder.connect('extension-found', Lang.bind(this, this._extensionFound));
|
||||
finder.connect('extensions-loaded', Lang.bind(this, this._extensionsLoaded));
|
||||
finder.scanExtensions();
|
||||
this._extensionsLoaded();
|
||||
},
|
||||
|
||||
_extensionFound: function(finder, extension) {
|
||||
_extensionFound: function(signals, extension) {
|
||||
let iter = this._model.append();
|
||||
this._model.set(iter, [0, 1], [extension.uuid, extension.metadata.name]);
|
||||
this._extensionIters[extension.uuid] = iter;
|
||||
|
@ -59,7 +59,6 @@ const AuthPrompt = new Lang.Class({
|
||||
this._userVerifier.connect('verification-complete', Lang.bind(this, this._onVerificationComplete));
|
||||
this._userVerifier.connect('reset', Lang.bind(this, this._onReset));
|
||||
this._userVerifier.connect('smartcard-status-changed', Lang.bind(this, this._onSmartcardStatusChanged));
|
||||
this._userVerifier.connect('ovirt-user-authenticated', Lang.bind(this, this._onOVirtUserAuthenticated));
|
||||
this.smartcardDetected = this._userVerifier.smartcardDetected;
|
||||
|
||||
this.connect('next', Lang.bind(this, function() {
|
||||
@ -80,7 +79,6 @@ const AuthPrompt = new Lang.Class({
|
||||
if (event.get_key_symbol() == Clutter.KEY_Escape) {
|
||||
this.cancel();
|
||||
}
|
||||
return Clutter.EVENT_PROPAGATE;
|
||||
}));
|
||||
|
||||
this._userWell = new St.Bin({ x_fill: true,
|
||||
@ -94,7 +92,7 @@ const AuthPrompt = new Lang.Class({
|
||||
|
||||
this.actor.add(this._label,
|
||||
{ expand: true,
|
||||
x_fill: false,
|
||||
x_fill: true,
|
||||
y_fill: true,
|
||||
x_align: St.Align.START });
|
||||
this._entry = new St.Entry({ style_class: 'login-dialog-prompt-entry',
|
||||
@ -112,7 +110,7 @@ const AuthPrompt = new Lang.Class({
|
||||
this._message = new St.Label({ opacity: 0,
|
||||
styleClass: 'login-dialog-message' });
|
||||
this._message.clutter_text.line_wrap = true;
|
||||
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: true, y_align: St.Align.START });
|
||||
|
||||
this._buttonBox = new St.BoxLayout({ style_class: 'login-dialog-button-box',
|
||||
vertical: false });
|
||||
@ -221,11 +219,6 @@ const AuthPrompt = new Lang.Class({
|
||||
this.emit('prompted');
|
||||
},
|
||||
|
||||
_onOVirtUserAuthenticated: function() {
|
||||
if (this.verificationStatus != AuthPromptStatus.VERIFICATION_SUCCEEDED)
|
||||
this.reset();
|
||||
},
|
||||
|
||||
_onSmartcardStatusChanged: function() {
|
||||
this.smartcardDetected = this._userVerifier.smartcardDetected;
|
||||
|
||||
@ -264,8 +257,10 @@ const AuthPrompt = new Lang.Class({
|
||||
},
|
||||
|
||||
_onReset: function() {
|
||||
this.verificationStatus = AuthPromptStatus.NOT_VERIFYING;
|
||||
this.reset();
|
||||
if (this.verificationStatus != AuthPromptStatus.VERIFICATION_SUCCEEDED) {
|
||||
this.verificationStatus = AuthPromptStatus.NOT_VERIFYING;
|
||||
this.reset();
|
||||
}
|
||||
},
|
||||
|
||||
addActorToDefaultButtonWell: function(actor) {
|
||||
@ -449,11 +444,10 @@ const AuthPrompt = new Lang.Class({
|
||||
// The user is constant at the unlock screen, so it will immediately
|
||||
// respond to the request with the username
|
||||
beginRequestType = BeginRequestType.PROVIDE_USERNAME;
|
||||
} else if (this._userVerifier.serviceIsForeground(GdmUtil.OVIRT_SERVICE_NAME) ||
|
||||
(this.smartcardDetected &&
|
||||
this._userVerifier.serviceIsForeground(GdmUtil.SMARTCARD_SERVICE_NAME))) {
|
||||
} else if (this.smartcardDetected &&
|
||||
this._userVerifier.serviceIsForeground(GdmUtil.SMARTCARD_SERVICE_NAME)) {
|
||||
// We don't need to know the username if the user preempted the login screen
|
||||
// with a smartcard or with preauthenticated oVirt credentials
|
||||
// with a smartcard.
|
||||
beginRequestType = BeginRequestType.DONT_PROVIDE_USERNAME;
|
||||
} else {
|
||||
// In all other cases, we should get the username up front.
|
||||
|
@ -5,13 +5,11 @@ const Lang = imports.lang;
|
||||
const Shell = imports.gi.Shell;
|
||||
const Signals = imports.signals;
|
||||
|
||||
const FprintManagerIface = '<node> \
|
||||
<interface name="net.reactivated.Fprint.Manager"> \
|
||||
<method name="GetDefaultDevice"> \
|
||||
<arg type="o" direction="out" /> \
|
||||
</method> \
|
||||
</interface> \
|
||||
</node>';
|
||||
const FprintManagerIface = <interface name='net.reactivated.Fprint.Manager'>
|
||||
<method name='GetDefaultDevice'>
|
||||
<arg type='o' direction='out' />
|
||||
</method>
|
||||
</interface>;
|
||||
|
||||
const FprintManagerInfo = Gio.DBusInterfaceInfo.new_for_xml(FprintManagerIface);
|
||||
|
||||
|
@ -59,7 +59,7 @@ const UserListItem = new Lang.Class({
|
||||
this._userChangedId = this.user.connect('changed',
|
||||
Lang.bind(this, this._onUserChanged));
|
||||
|
||||
let layout = new St.BoxLayout({ vertical: true });
|
||||
let layout = new St.BoxLayout({ vertical: false });
|
||||
this.actor = new St.Button({ style_class: 'login-dialog-user-list-item',
|
||||
button_mask: St.ButtonMask.ONE | St.ButtonMask.THREE,
|
||||
can_focus: true,
|
||||
@ -68,18 +68,39 @@ const UserListItem = new Lang.Class({
|
||||
x_align: St.Align.START,
|
||||
x_fill: true });
|
||||
|
||||
this._userWidget = new UserWidget.UserWidget(this.user);
|
||||
layout.add(this._userWidget.actor);
|
||||
this._userAvatar = new UserWidget.Avatar(this.user,
|
||||
{ styleClass: 'login-dialog-user-list-item-icon' });
|
||||
layout.add(this._userAvatar.actor);
|
||||
let textLayout = new St.BoxLayout({ style_class: 'login-dialog-user-list-item-text-box',
|
||||
vertical: true });
|
||||
layout.add(textLayout, { expand: true });
|
||||
|
||||
this._nameLabel = new St.Label({ style_class: 'login-dialog-user-list-item-name' });
|
||||
this.actor.label_actor = this._nameLabel;
|
||||
textLayout.add(this._nameLabel,
|
||||
{ y_fill: false,
|
||||
y_align: St.Align.MIDDLE,
|
||||
expand: true });
|
||||
|
||||
this._timedLoginIndicator = new St.Bin({ style_class: 'login-dialog-timed-login-indicator',
|
||||
scale_x: 0 });
|
||||
layout.add(this._timedLoginIndicator);
|
||||
textLayout.add(this._timedLoginIndicator,
|
||||
{ x_fill: true,
|
||||
x_align: St.Align.MIDDLE,
|
||||
y_fill: false,
|
||||
y_align: St.Align.END });
|
||||
|
||||
this.actor.connect('clicked', Lang.bind(this, this._onClicked));
|
||||
this._onUserChanged();
|
||||
},
|
||||
|
||||
_onUserChanged: function() {
|
||||
this._nameLabel.set_text(this.user.get_real_name());
|
||||
this._userAvatar.update();
|
||||
this._updateLoggedIn();
|
||||
},
|
||||
|
||||
syncStyleClasses: function() {
|
||||
this._updateLoggedIn();
|
||||
},
|
||||
|
||||
@ -168,6 +189,7 @@ const UserList = new Lang.Class({
|
||||
for (let userName in this._items) {
|
||||
let item = this._items[userName];
|
||||
item.actor.sync_hover();
|
||||
item.syncStyleClasses();
|
||||
}
|
||||
},
|
||||
|
||||
@ -644,7 +666,7 @@ const LoginDialog = new Lang.Class({
|
||||
onComplete: function() {
|
||||
Mainloop.idle_add(Lang.bind(this, function() {
|
||||
this._greeter.call_start_session_when_ready_sync(serviceName, true, null);
|
||||
return GLib.SOURCE_REMOVE;
|
||||
return false;
|
||||
}));
|
||||
},
|
||||
onCompleteScope: this });
|
||||
@ -699,7 +721,6 @@ const LoginDialog = new Lang.Class({
|
||||
function() {
|
||||
this._timedLoginAnimationTime -= _TIMED_LOGIN_IDLE_THRESHOLD;
|
||||
hold.release();
|
||||
return GLib.SOURCE_REMOVE;
|
||||
});
|
||||
return hold;
|
||||
},
|
||||
@ -764,7 +785,7 @@ const LoginDialog = new Lang.Class({
|
||||
global.stage.connect('captured-event',
|
||||
Lang.bind(this, function(actor, event) {
|
||||
if (this._timedLoginDelay == undefined)
|
||||
return Clutter.EVENT_PROPAGATE;
|
||||
return false;
|
||||
|
||||
if (event.type() == Clutter.EventType.KEY_PRESS ||
|
||||
event.type() == Clutter.EventType.BUTTON_PRESS) {
|
||||
@ -777,7 +798,7 @@ const LoginDialog = new Lang.Class({
|
||||
this._resetTimedLogin();
|
||||
}
|
||||
|
||||
return Clutter.EVENT_PROPAGATE;
|
||||
return false;
|
||||
}));
|
||||
},
|
||||
|
||||
@ -886,10 +907,6 @@ const LoginDialog = new Lang.Class({
|
||||
Main.ctrlAltTabManager.removeGroup(this.dialogLayout);
|
||||
},
|
||||
|
||||
cancel: function() {
|
||||
this._authPrompt.cancel();
|
||||
},
|
||||
|
||||
addCharacter: function(unichar) {
|
||||
this._authPrompt.addCharacter(unichar);
|
||||
},
|
||||
|
@ -1,64 +0,0 @@
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
|
||||
const Gio = imports.gi.Gio;
|
||||
const Lang = imports.lang;
|
||||
const Signals = imports.signals;
|
||||
|
||||
const OVirtCredentialsIface = '<node> \
|
||||
<interface name="org.ovirt.vdsm.Credentials"> \
|
||||
<signal name="UserAuthenticated"> \
|
||||
<arg type="s" name="token"/> \
|
||||
</signal> \
|
||||
</interface> \
|
||||
</node>';
|
||||
|
||||
const OVirtCredentialsInfo = Gio.DBusInterfaceInfo.new_for_xml(OVirtCredentialsIface);
|
||||
|
||||
let _oVirtCredentialsManager = null;
|
||||
|
||||
function OVirtCredentials() {
|
||||
var self = new Gio.DBusProxy({ g_connection: Gio.DBus.system,
|
||||
g_interface_name: OVirtCredentialsInfo.name,
|
||||
g_interface_info: OVirtCredentialsInfo,
|
||||
g_name: 'org.ovirt.vdsm.Credentials',
|
||||
g_object_path: '/org/ovirt/vdsm/Credentials',
|
||||
g_flags: (Gio.DBusProxyFlags.DO_NOT_LOAD_PROPERTIES) });
|
||||
self.init(null);
|
||||
return self;
|
||||
}
|
||||
|
||||
const OVirtCredentialsManager = new Lang.Class({
|
||||
Name: 'OVirtCredentialsManager',
|
||||
_init: function() {
|
||||
this._token = null;
|
||||
|
||||
this._credentials = new OVirtCredentials();
|
||||
this._credentials.connectSignal('UserAuthenticated',
|
||||
Lang.bind(this, this._onUserAuthenticated));
|
||||
},
|
||||
|
||||
_onUserAuthenticated: function(proxy, sender, [token]) {
|
||||
this._token = token;
|
||||
this.emit('user-authenticated', token);
|
||||
},
|
||||
|
||||
hasToken: function() {
|
||||
return this._token != null;
|
||||
},
|
||||
|
||||
getToken: function() {
|
||||
return this._token;
|
||||
},
|
||||
|
||||
resetToken: function() {
|
||||
this._token = null;
|
||||
}
|
||||
});
|
||||
Signals.addSignalMethods(OVirtCredentialsManager.prototype);
|
||||
|
||||
function getOVirtCredentialsManager() {
|
||||
if (!_oVirtCredentialsManager)
|
||||
_oVirtCredentialsManager = new OVirtCredentialsManager();
|
||||
|
||||
return _oVirtCredentialsManager;
|
||||
}
|
@ -5,58 +5,52 @@ const Lang = imports.lang;
|
||||
const Shell = imports.gi.Shell;
|
||||
const Signals = imports.signals;
|
||||
|
||||
const ProviderIface = '<node> \
|
||||
<interface name="org.freedesktop.realmd.Provider"> \
|
||||
<property name="Name" type="s" access="read"/> \
|
||||
<property name="Version" type="s" access="read"/> \
|
||||
<property name="Realms" type="ao" access="read"/> \
|
||||
<method name="Discover"> \
|
||||
<arg name="string" type="s" direction="in"/> \
|
||||
<arg name="options" type="a{sv}" direction="in"/> \
|
||||
<arg name="relevance" type="i" direction="out"/> \
|
||||
<arg name="realm" type="ao" direction="out"/> \
|
||||
</method> \
|
||||
</interface> \
|
||||
</node>';
|
||||
const ProviderIface = <interface name='org.freedesktop.realmd.Provider'>
|
||||
<property name="Name" type="s" access="read"/>
|
||||
<property name="Version" type="s" access="read"/>
|
||||
<property name="Realms" type="ao" access="read"/>
|
||||
<method name="Discover">
|
||||
<arg name="string" type="s" direction="in"/>
|
||||
<arg name="options" type="a{sv}" direction="in"/>
|
||||
<arg name="relevance" type="i" direction="out"/>
|
||||
<arg name="realm" type="ao" direction="out"/>
|
||||
</method>
|
||||
</interface>;
|
||||
const Provider = Gio.DBusProxy.makeProxyWrapper(ProviderIface);
|
||||
|
||||
const ServiceIface = '<node> \
|
||||
<interface name="org.freedesktop.realmd.Service"> \
|
||||
<method name="Cancel"> \
|
||||
<arg name="operation" type="s" direction="in"/> \
|
||||
</method> \
|
||||
<method name="Release" /> \
|
||||
<method name="SetLocale"> \
|
||||
<arg name="locale" type="s" direction="in"/> \
|
||||
</method> \
|
||||
<signal name="Diagnostics"> \
|
||||
<arg name="data" type="s"/> \
|
||||
<arg name="operation" type="s"/> \
|
||||
</signal> \
|
||||
</interface> \
|
||||
</node>';
|
||||
const ServiceIface = <interface name="org.freedesktop.realmd.Service">
|
||||
<method name="Cancel">
|
||||
<arg name="operation" type="s" direction="in"/>
|
||||
</method>
|
||||
<method name="Release" />
|
||||
<method name="SetLocale">
|
||||
<arg name="locale" type="s" direction="in"/>
|
||||
</method>
|
||||
<signal name="Diagnostics">
|
||||
<arg name="data" type="s"/>
|
||||
<arg name="operation" type="s"/>
|
||||
</signal>
|
||||
</interface>;
|
||||
const Service = Gio.DBusProxy.makeProxyWrapper(ServiceIface);
|
||||
|
||||
const RealmIface = '<node> \
|
||||
<interface name="org.freedesktop.realmd.Realm"> \
|
||||
<property name="Name" type="s" access="read"/> \
|
||||
<property name="Configured" type="s" access="read"/> \
|
||||
<property name="Details" type="a(ss)" access="read"/> \
|
||||
<property name="LoginFormats" type="as" access="read"/> \
|
||||
<property name="LoginPolicy" type="s" access="read"/> \
|
||||
<property name="PermittedLogins" type="as" access="read"/> \
|
||||
<property name="SupportedInterfaces" type="as" access="read"/> \
|
||||
<method name="ChangeLoginPolicy"> \
|
||||
<arg name="login_policy" type="s" direction="in"/> \
|
||||
<arg name="permitted_add" type="as" direction="in"/> \
|
||||
<arg name="permitted_remove" type="as" direction="in"/> \
|
||||
<arg name="options" type="a{sv}" direction="in"/> \
|
||||
</method> \
|
||||
<method name="Deconfigure"> \
|
||||
<arg name="options" type="a{sv}" direction="in"/> \
|
||||
</method> \
|
||||
</interface> \
|
||||
</node>';
|
||||
const RealmIface = <interface name="org.freedesktop.realmd.Realm">
|
||||
<property name="Name" type="s" access="read"/>
|
||||
<property name="Configured" type="s" access="read"/>
|
||||
<property name="Details" type="a(ss)" access="read"/>
|
||||
<property name="LoginFormats" type="as" access="read"/>
|
||||
<property name="LoginPolicy" type="s" access="read"/>
|
||||
<property name="PermittedLogins" type="as" access="read"/>
|
||||
<property name="SupportedInterfaces" type="as" access="read"/>
|
||||
<method name="ChangeLoginPolicy">
|
||||
<arg name="login_policy" type="s" direction="in"/>
|
||||
<arg name="permitted_add" type="as" direction="in"/>
|
||||
<arg name="permitted_remove" type="as" direction="in"/>
|
||||
<arg name="options" type="a{sv}" direction="in"/>
|
||||
</method>
|
||||
<method name="Deconfigure">
|
||||
<arg name="options" type="a{sv}" direction="in"/>
|
||||
</method>
|
||||
</interface>;
|
||||
const Realm = Gio.DBusProxy.makeProxyWrapper(RealmIface);
|
||||
|
||||
const Manager = new Lang.Class({
|
||||
|
@ -10,7 +10,6 @@ const St = imports.gi.St;
|
||||
|
||||
const Batch = imports.gdm.batch;
|
||||
const Fprint = imports.gdm.fingerprint;
|
||||
const OVirt = imports.gdm.oVirt;
|
||||
const Main = imports.ui.main;
|
||||
const Params = imports.misc.params;
|
||||
const ShellEntry = imports.ui.shellEntry;
|
||||
@ -20,7 +19,6 @@ const Tweener = imports.ui.tweener;
|
||||
const PASSWORD_SERVICE_NAME = 'gdm-password';
|
||||
const FINGERPRINT_SERVICE_NAME = 'gdm-fingerprint';
|
||||
const SMARTCARD_SERVICE_NAME = 'gdm-smartcard';
|
||||
const OVIRT_SERVICE_NAME = 'gdm-ovirtcred';
|
||||
const FADE_ANIMATION_TIME = 0.16;
|
||||
const CLONE_FADE_ANIMATION_TIME = 0.25;
|
||||
|
||||
@ -153,14 +151,6 @@ const ShellUserVerifier = new Lang.Class({
|
||||
this.reauthenticating = false;
|
||||
|
||||
this._failCounter = 0;
|
||||
|
||||
this._oVirtCredentialsManager = OVirt.getOVirtCredentialsManager();
|
||||
|
||||
if (this._oVirtCredentialsManager.hasToken())
|
||||
this._oVirtUserAuthenticated(this._oVirtCredentialsManager.getToken());
|
||||
|
||||
this._oVirtCredentialsManager.connect('user-authenticated',
|
||||
Lang.bind(this, this._oVirtUserAuthenticated));
|
||||
},
|
||||
|
||||
begin: function(userName, hold) {
|
||||
@ -250,7 +240,6 @@ const ShellUserVerifier = new Lang.Class({
|
||||
Lang.bind(this, function() {
|
||||
this._messageQueueTimeoutId = 0;
|
||||
this._queueMessageTimeout();
|
||||
return GLib.SOURCE_REMOVE;
|
||||
}));
|
||||
},
|
||||
|
||||
@ -288,11 +277,6 @@ const ShellUserVerifier = new Lang.Class({
|
||||
}));
|
||||
},
|
||||
|
||||
_oVirtUserAuthenticated: function(token) {
|
||||
this._preemptingService = OVIRT_SERVICE_NAME;
|
||||
this.emit('ovirt-user-authenticated');
|
||||
},
|
||||
|
||||
_checkForSmartcard: function() {
|
||||
let smartcardDetected;
|
||||
|
||||
@ -471,12 +455,6 @@ const ShellUserVerifier = new Lang.Class({
|
||||
if (!this.serviceIsForeground(serviceName))
|
||||
return;
|
||||
|
||||
if (serviceName == OVIRT_SERVICE_NAME) {
|
||||
// The only question asked by this service is "Token?"
|
||||
this.answerQuery(serviceName, this._oVirtCredentialsManager.getToken());
|
||||
return;
|
||||
}
|
||||
|
||||
this.emit('ask-question', serviceName, secretQuestion, '\u25cf');
|
||||
},
|
||||
|
||||
@ -537,16 +515,6 @@ const ShellUserVerifier = new Lang.Class({
|
||||
},
|
||||
|
||||
_onConversationStopped: function(client, serviceName) {
|
||||
// If the login failed with the preauthenticated oVirt credentials
|
||||
// then discard the credentials and revert to default authentication
|
||||
// mechanism.
|
||||
if (this.serviceIsForeground(OVIRT_SERVICE_NAME)) {
|
||||
this._oVirtCredentialsManager.resetToken();
|
||||
this._preemptingService = null;
|
||||
this._verificationFailed(false);
|
||||
return;
|
||||
}
|
||||
|
||||
// if the password service fails, then cancel everything.
|
||||
// But if, e.g., fingerprint fails, still give
|
||||
// password authentication a chance to succeed
|
||||
|
@ -1,114 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<gresources>
|
||||
<gresource prefix="/org/gnome/shell">
|
||||
<file>gdm/authPrompt.js</file>
|
||||
<file>gdm/batch.js</file>
|
||||
<file>gdm/fingerprint.js</file>
|
||||
<file>gdm/loginDialog.js</file>
|
||||
<file>gdm/oVirt.js</file>
|
||||
<file>gdm/realmd.js</file>
|
||||
<file>gdm/util.js</file>
|
||||
|
||||
<file>extensionPrefs/main.js</file>
|
||||
|
||||
<file>misc/config.js</file>
|
||||
<file>misc/extensionUtils.js</file>
|
||||
<file>misc/fileUtils.js</file>
|
||||
<file>misc/gnomeSession.js</file>
|
||||
<file>misc/hash.js</file>
|
||||
<file>misc/history.js</file>
|
||||
<file>misc/jsParse.js</file>
|
||||
<file>misc/loginManager.js</file>
|
||||
<file>misc/modemManager.js</file>
|
||||
<file>misc/objectManager.js</file>
|
||||
<file>misc/params.js</file>
|
||||
<file>misc/smartcardManager.js</file>
|
||||
<file>misc/util.js</file>
|
||||
|
||||
<file>perf/core.js</file>
|
||||
|
||||
<file>ui/altTab.js</file>
|
||||
<file>ui/animation.js</file>
|
||||
<file>ui/appDisplay.js</file>
|
||||
<file>ui/appFavorites.js</file>
|
||||
<file>ui/backgroundMenu.js</file>
|
||||
<file>ui/background.js</file>
|
||||
<file>ui/boxpointer.js</file>
|
||||
<file>ui/calendar.js</file>
|
||||
<file>ui/checkBox.js</file>
|
||||
<file>ui/ctrlAltTab.js</file>
|
||||
<file>ui/dash.js</file>
|
||||
<file>ui/dateMenu.js</file>
|
||||
<file>ui/dnd.js</file>
|
||||
<file>ui/endSessionDialog.js</file>
|
||||
<file>ui/environment.js</file>
|
||||
<file>ui/extensionDownloader.js</file>
|
||||
<file>ui/extensionSystem.js</file>
|
||||
<file>ui/focusCaretTracker.js</file>
|
||||
<file>ui/grabHelper.js</file>
|
||||
<file>ui/ibusCandidatePopup.js</file>
|
||||
<file>ui/iconGrid.js</file>
|
||||
<file>ui/keyboard.js</file>
|
||||
<file>ui/layout.js</file>
|
||||
<file>ui/lightbox.js</file>
|
||||
<file>ui/lookingGlass.js</file>
|
||||
<file>ui/magnifier.js</file>
|
||||
<file>ui/magnifierDBus.js</file>
|
||||
<file>ui/main.js</file>
|
||||
<file>ui/messageTray.js</file>
|
||||
<file>ui/modalDialog.js</file>
|
||||
<file>ui/notificationDaemon.js</file>
|
||||
<file>ui/osdWindow.js</file>
|
||||
<file>ui/overview.js</file>
|
||||
<file>ui/overviewControls.js</file>
|
||||
<file>ui/panel.js</file>
|
||||
<file>ui/panelMenu.js</file>
|
||||
<file>ui/pointerWatcher.js</file>
|
||||
<file>ui/popupMenu.js</file>
|
||||
<file>ui/remoteMenu.js</file>
|
||||
<file>ui/remoteSearch.js</file>
|
||||
<file>ui/runDialog.js</file>
|
||||
<file>ui/screenShield.js</file>
|
||||
<file>ui/screencast.js</file>
|
||||
<file>ui/screenshot.js</file>
|
||||
<file>ui/scripting.js</file>
|
||||
<file>ui/search.js</file>
|
||||
<file>ui/separator.js</file>
|
||||
<file>ui/sessionMode.js</file>
|
||||
<file>ui/shellDBus.js</file>
|
||||
<file>ui/shellEntry.js</file>
|
||||
<file>ui/shellMountOperation.js</file>
|
||||
<file>ui/slider.js</file>
|
||||
<file>ui/switcherPopup.js</file>
|
||||
<file>ui/tweener.js</file>
|
||||
<file>ui/unlockDialog.js</file>
|
||||
<file>ui/userWidget.js</file>
|
||||
<file>ui/viewSelector.js</file>
|
||||
<file>ui/windowAttentionHandler.js</file>
|
||||
<file>ui/windowManager.js</file>
|
||||
<file>ui/workspace.js</file>
|
||||
<file>ui/workspaceSwitcherPopup.js</file>
|
||||
<file>ui/workspaceThumbnail.js</file>
|
||||
<file>ui/workspacesView.js</file>
|
||||
<file>ui/xdndHandler.js</file>
|
||||
|
||||
<file>ui/components/__init__.js</file>
|
||||
<file>ui/components/autorunManager.js</file>
|
||||
<file>ui/components/automountManager.js</file>
|
||||
<file>ui/components/networkAgent.js</file>
|
||||
<file>ui/components/polkitAgent.js</file>
|
||||
<file>ui/components/telepathyClient.js</file>
|
||||
<file>ui/components/keyring.js</file>
|
||||
|
||||
<file>ui/status/accessibility.js</file>
|
||||
<file>ui/status/brightness.js</file>
|
||||
<file>ui/status/keyboard.js</file>
|
||||
<file>ui/status/network.js</file>
|
||||
<file>ui/status/power.js</file>
|
||||
<file>ui/status/rfkill.js</file>
|
||||
<file>ui/status/volume.js</file>
|
||||
<file>ui/status/bluetooth.js</file>
|
||||
<file>ui/status/screencast.js</file>
|
||||
<file>ui/status/system.js</file>
|
||||
</gresource>
|
||||
</gresources>
|
@ -174,9 +174,17 @@ const ExtensionFinder = new Lang.Class({
|
||||
this.emit('extension-found', extension);
|
||||
},
|
||||
|
||||
_extensionsLoaded: function() {
|
||||
this.emit('extensions-loaded');
|
||||
},
|
||||
|
||||
scanExtensions: function() {
|
||||
let perUserDir = Gio.File.new_for_path(global.userdatadir);
|
||||
FileUtils.collectFromDatadirs('extensions', true, Lang.bind(this, this._loadExtension, perUserDir));
|
||||
FileUtils.collectFromDatadirsAsync('extensions',
|
||||
{ processFile: Lang.bind(this, this._loadExtension),
|
||||
loadedCallback: Lang.bind(this, this._extensionsLoaded),
|
||||
includeUserDir: true,
|
||||
data: perUserDir });
|
||||
}
|
||||
});
|
||||
Signals.addSignalMethods(ExtensionFinder.prototype);
|
||||
|
@ -25,27 +25,60 @@ function listDirAsync(file, callback) {
|
||||
});
|
||||
}
|
||||
|
||||
function collectFromDatadirs(subdir, includeUserDir, processFile) {
|
||||
function _collectFromDirectoryAsync(dir, loadState) {
|
||||
function done() {
|
||||
loadState.numLoading--;
|
||||
if (loadState.loadedCallback &&
|
||||
loadState.numLoading == 0)
|
||||
loadState.loadedCallback(loadState.data);
|
||||
}
|
||||
|
||||
dir.query_info_async('standard::type', Gio.FileQueryInfoFlags.NONE,
|
||||
GLib.PRIORITY_DEFAULT, null, function(object, res) {
|
||||
try {
|
||||
object.query_info_finish(res);
|
||||
} catch (e) {
|
||||
if (!e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.NOT_FOUND))
|
||||
log(e.message);
|
||||
done();
|
||||
return;
|
||||
}
|
||||
|
||||
listDirAsync(dir, Lang.bind(this, function(infos) {
|
||||
for (let i = 0; i < infos.length; i++)
|
||||
loadState.processFile(dir.get_child(infos[i].get_name()),
|
||||
infos[i], loadState.data);
|
||||
done();
|
||||
}));
|
||||
});
|
||||
}
|
||||
|
||||
function collectFromDatadirsAsync(subdir, params) {
|
||||
params = Params.parse(params, { includeUserDir: false,
|
||||
processFile: null,
|
||||
loadedCallback: null,
|
||||
data: null });
|
||||
let loadState = { data: params.data,
|
||||
numLoading: 0,
|
||||
loadedCallback: params.loadedCallback,
|
||||
processFile: params.processFile };
|
||||
|
||||
if (params.processFile == null) {
|
||||
if (params.loadedCallback)
|
||||
params.loadedCallback(params.data);
|
||||
return;
|
||||
}
|
||||
|
||||
let dataDirs = GLib.get_system_data_dirs();
|
||||
if (includeUserDir)
|
||||
if (params.includeUserDir)
|
||||
dataDirs.unshift(GLib.get_user_data_dir());
|
||||
loadState.numLoading = dataDirs.length;
|
||||
|
||||
for (let i = 0; i < dataDirs.length; i++) {
|
||||
let path = GLib.build_filenamev([dataDirs[i], 'gnome-shell', subdir]);
|
||||
let dir = Gio.File.new_for_path(path);
|
||||
|
||||
let fileEnum;
|
||||
try {
|
||||
fileEnum = dir.enumerate_children('standard::name,standard::type',
|
||||
Gio.FileQueryInfoFlags.NONE, null);
|
||||
} catch (e) {
|
||||
fileEnum = null;
|
||||
}
|
||||
if (fileEnum != null) {
|
||||
let info;
|
||||
while ((info = fileEnum.next_file(null)))
|
||||
processFile(fileEnum.get_child(info), info);
|
||||
}
|
||||
_collectFromDirectoryAsync(dir, loadState);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4,17 +4,15 @@ const Gio = imports.gi.Gio;
|
||||
const Lang = imports.lang;
|
||||
const Signals = imports.signals;
|
||||
|
||||
const PresenceIface = '<node> \
|
||||
<interface name="org.gnome.SessionManager.Presence"> \
|
||||
<method name="SetStatus"> \
|
||||
<arg type="u" direction="in"/> \
|
||||
</method> \
|
||||
<property name="status" type="u" access="readwrite"/> \
|
||||
<signal name="StatusChanged"> \
|
||||
<arg type="u" direction="out"/> \
|
||||
</signal> \
|
||||
</interface> \
|
||||
</node>';
|
||||
const PresenceIface = <interface name="org.gnome.SessionManager.Presence">
|
||||
<method name="SetStatus">
|
||||
<arg type="u" direction="in"/>
|
||||
</method>
|
||||
<property name="status" type="u" access="readwrite"/>
|
||||
<signal name="StatusChanged">
|
||||
<arg type="u" direction="out"/>
|
||||
</signal>
|
||||
</interface>;
|
||||
|
||||
const PresenceStatus = {
|
||||
AVAILABLE: 0,
|
||||
@ -32,16 +30,14 @@ function Presence(initCallback, cancellable) {
|
||||
// Note inhibitors are immutable objects, so they don't
|
||||
// change at runtime (changes always come in the form
|
||||
// of new inhibitors)
|
||||
const InhibitorIface = '<node> \
|
||||
<interface name="org.gnome.SessionManager.Inhibitor"> \
|
||||
<method name="GetAppId"> \
|
||||
<arg type="s" direction="out" /> \
|
||||
</method> \
|
||||
<method name="GetReason"> \
|
||||
<arg type="s" direction="out" /> \
|
||||
</method> \
|
||||
</interface> \
|
||||
</node>';
|
||||
const InhibitorIface = <interface name="org.gnome.SessionManager.Inhibitor">
|
||||
<method name="GetAppId">
|
||||
<arg type="s" direction="out" />
|
||||
</method>
|
||||
<method name="GetReason">
|
||||
<arg type="s" direction="out" />
|
||||
</method>
|
||||
</interface>;
|
||||
|
||||
var InhibitorProxy = Gio.DBusProxy.makeProxyWrapper(InhibitorIface);
|
||||
function Inhibitor(objectPath, initCallback, cancellable) {
|
||||
@ -49,29 +45,27 @@ function Inhibitor(objectPath, initCallback, cancellable) {
|
||||
}
|
||||
|
||||
// Not the full interface, only the methods we use
|
||||
const SessionManagerIface = '<node> \
|
||||
<interface name="org.gnome.SessionManager"> \
|
||||
<method name="Logout"> \
|
||||
<arg type="u" direction="in" /> \
|
||||
</method> \
|
||||
<method name="Shutdown" /> \
|
||||
<method name="Reboot" /> \
|
||||
<method name="CanShutdown"> \
|
||||
<arg type="b" direction="out" /> \
|
||||
</method> \
|
||||
<method name="IsInhibited"> \
|
||||
<arg type="u" direction="in" /> \
|
||||
<arg type="b" direction="out" /> \
|
||||
</method> \
|
||||
<property name="SessionIsActive" type="b" access="read"/> \
|
||||
<signal name="InhibitorAdded"> \
|
||||
<arg type="o" direction="out"/> \
|
||||
</signal> \
|
||||
<signal name="InhibitorRemoved"> \
|
||||
<arg type="o" direction="out"/> \
|
||||
</signal> \
|
||||
</interface> \
|
||||
</node>';
|
||||
const SessionManagerIface = <interface name="org.gnome.SessionManager">
|
||||
<method name="Logout">
|
||||
<arg type="u" direction="in" />
|
||||
</method>
|
||||
<method name="Shutdown" />
|
||||
<method name="Reboot" />
|
||||
<method name="CanShutdown">
|
||||
<arg type="b" direction="out" />
|
||||
</method>
|
||||
<method name="IsInhibited">
|
||||
<arg type="u" direction="in" />
|
||||
<arg type="b" direction="out" />
|
||||
</method>
|
||||
<property name="SessionIsActive" type="b" access="read"/>
|
||||
<signal name="InhibitorAdded">
|
||||
<arg type="o" direction="out"/>
|
||||
</signal>
|
||||
<signal name="InhibitorRemoved">
|
||||
<arg type="o" direction="out"/>
|
||||
</signal>
|
||||
</interface>;
|
||||
|
||||
var SessionManagerProxy = Gio.DBusProxy.makeProxyWrapper(SessionManagerIface);
|
||||
function SessionManager(initCallback, cancellable) {
|
||||
|
@ -89,7 +89,7 @@ const HistoryManager = new Lang.Class({
|
||||
} else if (symbol == Clutter.KEY_Down) {
|
||||
return this._setNextItem(entry.get_text());
|
||||
}
|
||||
return Clutter.EVENT_PROPAGATE;
|
||||
return false;
|
||||
},
|
||||
|
||||
_indexChanged: function() {
|
||||
|
@ -7,66 +7,58 @@ const Mainloop = imports.mainloop;
|
||||
const Shell = imports.gi.Shell;
|
||||
const Signals = imports.signals;
|
||||
|
||||
const SystemdLoginManagerIface = '<node> \
|
||||
<interface name="org.freedesktop.login1.Manager"> \
|
||||
<method name="Suspend"> \
|
||||
<arg type="b" direction="in"/> \
|
||||
</method> \
|
||||
<method name="CanSuspend"> \
|
||||
<arg type="s" direction="out"/> \
|
||||
</method> \
|
||||
<method name="Inhibit"> \
|
||||
<arg type="s" direction="in"/> \
|
||||
<arg type="s" direction="in"/> \
|
||||
<arg type="s" direction="in"/> \
|
||||
<arg type="s" direction="in"/> \
|
||||
<arg type="h" direction="out"/> \
|
||||
</method> \
|
||||
<method name="GetSession"> \
|
||||
<arg type="s" direction="in"/> \
|
||||
<arg type="o" direction="out"/> \
|
||||
</method> \
|
||||
<method name="ListSessions"> \
|
||||
<arg name="sessions" type="a(susso)" direction="out"/> \
|
||||
</method> \
|
||||
<signal name="PrepareForSleep"> \
|
||||
<arg type="b" direction="out"/> \
|
||||
</signal> \
|
||||
</interface> \
|
||||
</node>';
|
||||
const SystemdLoginManagerIface = <interface name='org.freedesktop.login1.Manager'>
|
||||
<method name='Suspend'>
|
||||
<arg type='b' direction='in'/>
|
||||
</method>
|
||||
<method name='CanSuspend'>
|
||||
<arg type='s' direction='out'/>
|
||||
</method>
|
||||
<method name='Inhibit'>
|
||||
<arg type='s' direction='in'/>
|
||||
<arg type='s' direction='in'/>
|
||||
<arg type='s' direction='in'/>
|
||||
<arg type='s' direction='in'/>
|
||||
<arg type='h' direction='out'/>
|
||||
</method>
|
||||
<method name='GetSession'>
|
||||
<arg type='s' direction='in'/>
|
||||
<arg type='o' direction='out'/>
|
||||
</method>
|
||||
<method name='ListSessions'>
|
||||
<arg name='sessions' type='a(susso)' direction='out'/>
|
||||
</method>
|
||||
<signal name='PrepareForSleep'>
|
||||
<arg type='b' direction='out'/>
|
||||
</signal>
|
||||
</interface>;
|
||||
|
||||
const SystemdLoginSessionIface = '<node> \
|
||||
<interface name="org.freedesktop.login1.Session"> \
|
||||
<signal name="Lock" /> \
|
||||
<signal name="Unlock" /> \
|
||||
</interface> \
|
||||
</node>';
|
||||
const SystemdLoginSessionIface = <interface name='org.freedesktop.login1.Session'>
|
||||
<signal name='Lock' />
|
||||
<signal name='Unlock' />
|
||||
</interface>;
|
||||
|
||||
const SystemdLoginManager = Gio.DBusProxy.makeProxyWrapper(SystemdLoginManagerIface);
|
||||
const SystemdLoginSession = Gio.DBusProxy.makeProxyWrapper(SystemdLoginSessionIface);
|
||||
|
||||
const ConsoleKitManagerIface = '<node> \
|
||||
<interface name="org.freedesktop.ConsoleKit.Manager"> \
|
||||
<method name="CanRestart"> \
|
||||
<arg type="b" direction="out"/> \
|
||||
</method> \
|
||||
<method name="CanStop"> \
|
||||
<arg type="b" direction="out"/> \
|
||||
</method> \
|
||||
<method name="Restart" /> \
|
||||
<method name="Stop" /> \
|
||||
<method name="GetCurrentSession"> \
|
||||
<arg type="o" direction="out" /> \
|
||||
</method> \
|
||||
</interface> \
|
||||
</node>';
|
||||
const ConsoleKitManagerIface = <interface name='org.freedesktop.ConsoleKit.Manager'>
|
||||
<method name='CanRestart'>
|
||||
<arg type='b' direction='out'/>
|
||||
</method>
|
||||
<method name='CanStop'>
|
||||
<arg type='b' direction='out'/>
|
||||
</method>
|
||||
<method name='Restart' />
|
||||
<method name='Stop' />
|
||||
<method name='GetCurrentSession'>
|
||||
<arg type='o' direction='out' />
|
||||
</method>
|
||||
</interface>;
|
||||
|
||||
const ConsoleKitSessionIface = '<node> \
|
||||
<interface name="org.freedesktop.ConsoleKit.Session"> \
|
||||
<signal name="Lock" /> \
|
||||
<signal name="Unlock" /> \
|
||||
</interface> \
|
||||
</node>';
|
||||
const ConsoleKitSessionIface = <interface name='org.freedesktop.ConsoleKit.Session'>
|
||||
<signal name='Lock' />
|
||||
<signal name='Unlock' />
|
||||
</interface>;
|
||||
|
||||
const ConsoleKitSession = Gio.DBusProxy.makeProxyWrapper(ConsoleKitSessionIface);
|
||||
const ConsoleKitManager = Gio.DBusProxy.makeProxyWrapper(ConsoleKitManagerIface);
|
||||
|
@ -92,41 +92,37 @@ function _findProviderForSid(sid) {
|
||||
// The following are not the complete interfaces, just the methods we need
|
||||
// (or may need in the future)
|
||||
|
||||
const ModemGsmNetworkInterface = '<node> \
|
||||
<interface name="org.freedesktop.ModemManager.Modem.Gsm.Network"> \
|
||||
<method name="GetRegistrationInfo"> \
|
||||
<arg type="(uss)" direction="out" /> \
|
||||
</method> \
|
||||
<method name="GetSignalQuality"> \
|
||||
<arg type="u" direction="out" /> \
|
||||
</method> \
|
||||
<property name="AccessTechnology" type="u" access="read" /> \
|
||||
<signal name="SignalQuality"> \
|
||||
<arg type="u" direction="out" /> \
|
||||
</signal> \
|
||||
<signal name="RegistrationInfo"> \
|
||||
<arg type="u" direction="out" /> \
|
||||
<arg type="s" direction="out" /> \
|
||||
<arg type="s" direction="out" /> \
|
||||
</signal> \
|
||||
</interface> \
|
||||
</node>';
|
||||
const ModemGsmNetworkInterface = <interface name="org.freedesktop.ModemManager.Modem.Gsm.Network">
|
||||
<method name="GetRegistrationInfo">
|
||||
<arg type="(uss)" direction="out" />
|
||||
</method>
|
||||
<method name="GetSignalQuality">
|
||||
<arg type="u" direction="out" />
|
||||
</method>
|
||||
<property name="AccessTechnology" type="u" access="read" />
|
||||
<signal name="SignalQuality">
|
||||
<arg type="u" direction="out" />
|
||||
</signal>
|
||||
<signal name="RegistrationInfo">
|
||||
<arg type="u" direction="out" />
|
||||
<arg type="s" direction="out" />
|
||||
<arg type="s" direction="out" />
|
||||
</signal>
|
||||
</interface>;
|
||||
|
||||
const ModemGsmNetworkProxy = Gio.DBusProxy.makeProxyWrapper(ModemGsmNetworkInterface);
|
||||
|
||||
const ModemCdmaInterface = '<node> \
|
||||
<interface name="org.freedesktop.ModemManager.Modem.Cdma"> \
|
||||
<method name="GetSignalQuality"> \
|
||||
<arg type="u" direction="out" /> \
|
||||
</method> \
|
||||
<method name="GetServingSystem"> \
|
||||
<arg type="(usu)" direction="out" /> \
|
||||
</method> \
|
||||
<signal name="SignalQuality"> \
|
||||
<arg type="u" direction="out" /> \
|
||||
</signal> \
|
||||
</interface> \
|
||||
</node>';
|
||||
const ModemCdmaInterface = <interface name="org.freedesktop.ModemManager.Modem.Cdma">
|
||||
<method name="GetSignalQuality">
|
||||
<arg type="u" direction="out" />
|
||||
</method>
|
||||
<method name="GetServingSystem">
|
||||
<arg type="(usu)" direction="out" />
|
||||
</method>
|
||||
<signal name="SignalQuality">
|
||||
<arg type="u" direction="out" />
|
||||
</signal>
|
||||
</interface>;
|
||||
|
||||
const ModemCdmaProxy = Gio.DBusProxy.makeProxyWrapper(ModemCdmaInterface);
|
||||
|
||||
@ -222,26 +218,20 @@ Signals.addSignalMethods(ModemCdma.prototype);
|
||||
// Support for the new ModemManager1 interface (MM >= 0.7)
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
const BroadbandModemInterface = '<node> \
|
||||
<interface name="org.freedesktop.ModemManager1.Modem"> \
|
||||
<property name="SignalQuality" type="(ub)" access="read" /> \
|
||||
</interface> \
|
||||
</node>';
|
||||
const BroadbandModemInterface = <interface name="org.freedesktop.ModemManager1.Modem">
|
||||
<property name="SignalQuality" type="(ub)" access="read" />
|
||||
</interface>;
|
||||
const BroadbandModemProxy = Gio.DBusProxy.makeProxyWrapper(BroadbandModemInterface);
|
||||
|
||||
const BroadbandModem3gppInterface = '<node> \
|
||||
<interface name="org.freedesktop.ModemManager1.Modem.Modem3gpp"> \
|
||||
<property name="OperatorCode" type="s" access="read" /> \
|
||||
<property name="OperatorName" type="s" access="read" /> \
|
||||
</interface> \
|
||||
</node>';
|
||||
const BroadbandModem3gppInterface = <interface name="org.freedesktop.ModemManager1.Modem.Modem3gpp">
|
||||
<property name="OperatorCode" type="s" access="read" />
|
||||
<property name="OperatorName" type="s" access="read" />
|
||||
</interface>;
|
||||
const BroadbandModem3gppProxy = Gio.DBusProxy.makeProxyWrapper(BroadbandModem3gppInterface);
|
||||
|
||||
const BroadbandModemCdmaInterface = '<node> \
|
||||
<interface name="org.freedesktop.ModemManager1.Modem.ModemCdma"> \
|
||||
<property name="Sid" type="u" access="read" /> \
|
||||
</interface> \
|
||||
</node>';
|
||||
const BroadbandModemCdmaInterface = <interface name="org.freedesktop.ModemManager1.Modem.ModemCdma">
|
||||
<property name="Sid" type="u" access="read" />
|
||||
</interface>;
|
||||
const BroadbandModemCdmaProxy = Gio.DBusProxy.makeProxyWrapper(BroadbandModemCdmaInterface);
|
||||
|
||||
const BroadbandModem = new Lang.Class({
|
||||
|
@ -8,21 +8,19 @@ const Signals = imports.signals;
|
||||
|
||||
// Specified in the D-Bus specification here:
|
||||
// http://dbus.freedesktop.org/doc/dbus-specification.html#standard-interfaces-objectmanager
|
||||
const ObjectManagerIface = '<node> \
|
||||
<interface name="org.freedesktop.DBus.ObjectManager"> \
|
||||
<method name="GetManagedObjects"> \
|
||||
<arg name="objects" type="a{oa{sa{sv}}}" direction="out"/> \
|
||||
</method> \
|
||||
<signal name="InterfacesAdded"> \
|
||||
<arg name="objectPath" type="o"/> \
|
||||
<arg name="interfaces" type="a{sa{sv}}" /> \
|
||||
</signal> \
|
||||
<signal name="InterfacesRemoved"> \
|
||||
<arg name="objectPath" type="o"/> \
|
||||
<arg name="interfaces" type="as" /> \
|
||||
</signal> \
|
||||
</interface> \
|
||||
</node>';
|
||||
const ObjectManagerIface = <interface name="org.freedesktop.DBus.ObjectManager">
|
||||
<method name="GetManagedObjects">
|
||||
<arg name="objects" type="a{oa{sa{sv}}}" direction="out"/>
|
||||
</method>
|
||||
<signal name="InterfacesAdded">
|
||||
<arg name="objectPath" type="o"/>
|
||||
<arg name="interfaces" type="a{sa{sv}}" />
|
||||
</signal>
|
||||
<signal name="InterfacesRemoved">
|
||||
<arg name="objectPath" type="o"/>
|
||||
<arg name="interfaces" type="as" />
|
||||
</signal>
|
||||
</interface>;
|
||||
|
||||
const ObjectManagerInfo = Gio.DBusInterfaceInfo.new_for_xml(ObjectManagerIface);
|
||||
|
||||
|
@ -7,14 +7,12 @@ const Signals = imports.signals;
|
||||
|
||||
const ObjectManager = imports.misc.objectManager;
|
||||
|
||||
const SmartcardTokenIface = '<node> \
|
||||
<interface name="org.gnome.SettingsDaemon.Smartcard.Token"> \
|
||||
<property name="Name" type="s" access="read"/> \
|
||||
<property name="Driver" type="o" access="read"/> \
|
||||
<property name="IsInserted" type="b" access="read"/> \
|
||||
<property name="UsedToLogin" type="b" access="read"/> \
|
||||
</interface> \
|
||||
</node>';
|
||||
const SmartcardTokenIface = <interface name="org.gnome.SettingsDaemon.Smartcard.Token">
|
||||
<property name="Name" type="s" access="read"/>
|
||||
<property name="Driver" type="o" access="read"/>
|
||||
<property name="IsInserted" type="b" access="read"/>
|
||||
<property name="UsedToLogin" type="b" access="read"/>
|
||||
</interface>;
|
||||
|
||||
let _smartcardManager = null;
|
||||
|
||||
|
@ -1,7 +1,6 @@
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
|
||||
const Clutter = imports.gi.Clutter;
|
||||
const Gio = imports.gi.Gio;
|
||||
const GLib = imports.gi.GLib;
|
||||
const Lang = imports.lang;
|
||||
const St = imports.gi.St;
|
||||
@ -80,22 +79,6 @@ function spawnCommandLine(command_line) {
|
||||
}
|
||||
}
|
||||
|
||||
// spawnApp:
|
||||
// @argv: an argv array
|
||||
//
|
||||
// Runs @argv as if it was an application, handling startup notification
|
||||
function spawnApp(argv) {
|
||||
try {
|
||||
let app = Gio.AppInfo.create_from_commandline(argv.join(' '), null,
|
||||
Gio.AppInfoCreateFlags.SUPPORTS_STARTUP_NOTIFICATION);
|
||||
|
||||
let context = global.create_app_launch_context();
|
||||
app.launch([], context);
|
||||
} catch(err) {
|
||||
_handleSpawnError(argv[0], err);
|
||||
}
|
||||
}
|
||||
|
||||
// trySpawn:
|
||||
// @argv: an argv array
|
||||
//
|
||||
|
@ -2,7 +2,6 @@
|
||||
|
||||
const Clutter = imports.gi.Clutter;
|
||||
const Gio = imports.gi.Gio;
|
||||
const GLib = imports.gi.GLib;
|
||||
const Lang = imports.lang;
|
||||
const Mainloop = imports.mainloop;
|
||||
const Meta = imports.gi.Meta;
|
||||
@ -107,8 +106,6 @@ const AppSwitcherPopup = new Lang.Class({
|
||||
|
||||
this._switcherList = new AppSwitcher(apps, this);
|
||||
this._items = this._switcherList.icons;
|
||||
if (this._items.length == 0)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
},
|
||||
@ -313,7 +310,7 @@ const AppSwitcherPopup = new Lang.Class({
|
||||
this._createThumbnails();
|
||||
this._thumbnailTimeoutId = 0;
|
||||
this._thumbnailsFocused = false;
|
||||
return GLib.SOURCE_REMOVE;
|
||||
return false;
|
||||
},
|
||||
|
||||
_destroyThumbnails : function() {
|
||||
@ -378,9 +375,6 @@ const WindowSwitcherPopup = new Lang.Class({
|
||||
this._switcherList = new WindowList(windows, mode);
|
||||
this._items = this._switcherList.icons;
|
||||
|
||||
if (this._items.length == 0)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
},
|
||||
|
||||
@ -548,7 +542,7 @@ const AppSwitcher = new Lang.Class({
|
||||
Lang.bind(this, function () {
|
||||
this._enterItem(index);
|
||||
this._mouseTimeOutId = 0;
|
||||
return GLib.SOURCE_REMOVE;
|
||||
return false;
|
||||
}));
|
||||
} else
|
||||
this._itemEntered(index);
|
||||
|
@ -1,6 +1,5 @@
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
|
||||
const GLib = imports.gi.GLib;
|
||||
const Lang = imports.lang;
|
||||
const Mainloop = imports.mainloop;
|
||||
const St = imports.gi.St;
|
||||
@ -60,7 +59,7 @@ const Animation = new Lang.Class({
|
||||
|
||||
_update: function() {
|
||||
this._showFrame(this._frame + 1);
|
||||
return GLib.SOURCE_CONTINUE;
|
||||
return true;
|
||||
},
|
||||
|
||||
_animationsLoaded: function() {
|
||||
|
@ -92,7 +92,7 @@ const BaseAppView = new Lang.Class({
|
||||
},
|
||||
|
||||
removeAll: function() {
|
||||
this._grid.destroyAll();
|
||||
this._grid.removeAll();
|
||||
this._items = {};
|
||||
this._allItems = [];
|
||||
},
|
||||
@ -415,7 +415,7 @@ const AllView = new Lang.Class({
|
||||
|
||||
_onScroll: function(actor, event) {
|
||||
if (this._displayingPopup)
|
||||
return Clutter.EVENT_STOP;
|
||||
return true;
|
||||
|
||||
let direction = event.get_scroll_direction();
|
||||
if (direction == Clutter.ScrollDirection.UP)
|
||||
@ -423,7 +423,7 @@ const AllView = new Lang.Class({
|
||||
else if (direction == Clutter.ScrollDirection.DOWN)
|
||||
this.goToPage(this._currentPage + 1);
|
||||
|
||||
return Clutter.EVENT_STOP;
|
||||
return true;
|
||||
},
|
||||
|
||||
_onPan: function(action) {
|
||||
@ -454,17 +454,17 @@ const AllView = new Lang.Class({
|
||||
|
||||
_onKeyPressEvent: function(actor, event) {
|
||||
if (this._displayingPopup)
|
||||
return Clutter.EVENT_STOP;
|
||||
return true;
|
||||
|
||||
if (event.get_key_symbol() == Clutter.Page_Up) {
|
||||
this.goToPage(this._currentPage - 1);
|
||||
return Clutter.EVENT_STOP;
|
||||
return true;
|
||||
} else if (event.get_key_symbol() == Clutter.Page_Down) {
|
||||
this.goToPage(this._currentPage + 1);
|
||||
return Clutter.EVENT_STOP;
|
||||
return true;
|
||||
}
|
||||
|
||||
return Clutter.EVENT_PROPAGATE;
|
||||
return false;
|
||||
},
|
||||
|
||||
_getItemId: function(item) {
|
||||
@ -613,10 +613,6 @@ const FrequentView = new Lang.Class({
|
||||
return this._usage.get_most_used("").length >= MIN_FREQUENT_APPS_COUNT;
|
||||
},
|
||||
|
||||
removeAll: function() {
|
||||
this._grid.destroyAll();
|
||||
},
|
||||
|
||||
loadApps: function() {
|
||||
let mostUsed = this._usage.get_most_used ("");
|
||||
let hasUsefulData = this.hasUsefulData();
|
||||
@ -747,15 +743,10 @@ const AppDisplay = new Lang.Class({
|
||||
this._views[i].control.connect('clicked', Lang.bind(this,
|
||||
function(actor) {
|
||||
this._showView(viewIndex);
|
||||
global.settings.set_uint('app-picker-view', viewIndex);
|
||||
}));
|
||||
}
|
||||
let initialView = Math.min(global.settings.get_uint('app-picker-view'),
|
||||
this._views.length - 1);
|
||||
let frequentUseful = this._views[Views.FREQUENT].view.hasUsefulData();
|
||||
if (initialView == Views.FREQUENT && !frequentUseful)
|
||||
initialView = Views.ALL;
|
||||
this._showView(initialView);
|
||||
this._showView(frequentUseful ? Views.FREQUENT : Views.ALL);
|
||||
this._updateFrequentVisibility();
|
||||
|
||||
// We need a dummy actor to catch the keyboard focus if the
|
||||
@ -884,29 +875,19 @@ const AppSearchProvider = new Lang.Class({
|
||||
callback(metas);
|
||||
},
|
||||
|
||||
filterResults: function(results, maxNumber) {
|
||||
return results.slice(0, maxNumber);
|
||||
},
|
||||
|
||||
getInitialResultSet: function(terms, callback, cancellable) {
|
||||
let query = terms.join(' ');
|
||||
let groups = Gio.DesktopAppInfo.search(query);
|
||||
_compareResults: function(a, b) {
|
||||
let usage = Shell.AppUsage.get_default();
|
||||
let results = [];
|
||||
groups.forEach(function(group) {
|
||||
group = group.filter(function(appID) {
|
||||
let app = Gio.DesktopAppInfo.new(appID);
|
||||
return app && app.should_show();
|
||||
});
|
||||
results = results.concat(group.sort(function(a, b) {
|
||||
return usage.compare('', a, b);
|
||||
}));
|
||||
});
|
||||
callback(results);
|
||||
return usage.compare('', a, b);
|
||||
},
|
||||
|
||||
getSubsearchResultSet: function(previousResults, terms, callback, cancellable) {
|
||||
this.getInitialResultSet(terms, callback, cancellable);
|
||||
getInitialResultSet: function(terms) {
|
||||
let query = terms.join(' ');
|
||||
let results = Gio.DesktopAppInfo.search(query, Lang.bind(this, this._compareResults), MAX_COLUMNS);
|
||||
this.searchSystem.setResults(this, results);
|
||||
},
|
||||
|
||||
getSubsearchResultSet: function(previousResults, terms) {
|
||||
this.getInitialResultSet(terms);
|
||||
},
|
||||
|
||||
activateResult: function(result) {
|
||||
@ -929,7 +910,7 @@ const AppSearchProvider = new Lang.Class({
|
||||
app.open_new_window(workspace);
|
||||
},
|
||||
|
||||
createResultObject: function (resultMeta) {
|
||||
createResultObject: function (resultMeta, terms) {
|
||||
let app = this._appSys.lookup_app(resultMeta['id']);
|
||||
return new AppIcon(app);
|
||||
}
|
||||
@ -1223,13 +1204,13 @@ const AppFolderPopup = new Lang.Class({
|
||||
|
||||
_onKeyPress: function(actor, event) {
|
||||
if (!this._isOpen)
|
||||
return Clutter.EVENT_PROPAGATE;
|
||||
return false;
|
||||
|
||||
if (event.get_key_symbol() != Clutter.KEY_Escape)
|
||||
return Clutter.EVENT_PROPAGATE;
|
||||
return false;
|
||||
|
||||
this.popdown();
|
||||
return Clutter.EVENT_STOP;
|
||||
return true;
|
||||
},
|
||||
|
||||
toggle: function() {
|
||||
@ -1368,15 +1349,13 @@ const AppIcon = new Lang.Class({
|
||||
this._removeMenuTimeout();
|
||||
this._menuTimeoutId = Mainloop.timeout_add(MENU_POPUP_TIMEOUT,
|
||||
Lang.bind(this, function() {
|
||||
this._menuTimeoutId = 0;
|
||||
this.popupMenu();
|
||||
return GLib.SOURCE_REMOVE;
|
||||
}));
|
||||
} else if (button == 3) {
|
||||
this.popupMenu();
|
||||
return Clutter.EVENT_STOP;
|
||||
return true;
|
||||
}
|
||||
return Clutter.EVENT_PROPAGATE;
|
||||
return false;
|
||||
},
|
||||
|
||||
_onClicked: function(actor, button) {
|
||||
@ -1388,6 +1367,7 @@ const AppIcon = new Lang.Class({
|
||||
// Last workspace is always empty
|
||||
let launchWorkspace = global.screen.get_workspace_by_index(global.screen.n_workspaces - 1);
|
||||
launchWorkspace.activate(global.get_current_time());
|
||||
this.emit('launching');
|
||||
this.app.open_new_window(-1);
|
||||
Main.overview.hide();
|
||||
}
|
||||
@ -1446,6 +1426,7 @@ const AppIcon = new Lang.Class({
|
||||
},
|
||||
|
||||
_onActivate: function (event) {
|
||||
this.emit('launching');
|
||||
let modifiers = event.get_state();
|
||||
|
||||
if (modifiers & Clutter.ModifierType.CONTROL_MASK
|
||||
@ -1514,9 +1495,7 @@ const AppIconMenu = new Lang.Class({
|
||||
_redisplay: function() {
|
||||
this.removeAll();
|
||||
|
||||
let windows = this._source.app.get_windows().filter(function(w) {
|
||||
return Shell.WindowTracker.is_window_interesting(w);
|
||||
});
|
||||
let windows = this._source.app.get_windows();
|
||||
|
||||
// Display the app windows menu items and the separator between windows
|
||||
// of the current desktop and other windows.
|
||||
|
@ -50,9 +50,11 @@ const BackgroundCache = new Lang.Class({
|
||||
effects: Meta.BackgroundEffects.NONE });
|
||||
|
||||
let content = null;
|
||||
|
||||
let candidateContent = null;
|
||||
for (let i = 0; i < this._patterns.length; i++) {
|
||||
if (!this._patterns[i])
|
||||
continue;
|
||||
|
||||
if (this._patterns[i].get_shading() != params.shadingType)
|
||||
continue;
|
||||
|
||||
@ -86,6 +88,7 @@ const BackgroundCache = new Lang.Class({
|
||||
}
|
||||
|
||||
this._patterns.push(content);
|
||||
|
||||
return content;
|
||||
},
|
||||
|
||||
@ -113,9 +116,9 @@ const BackgroundCache = new Lang.Class({
|
||||
|
||||
_removeContent: function(contentList, content) {
|
||||
let index = contentList.indexOf(content);
|
||||
if (index < 0)
|
||||
throw new Error("Trying to remove invalid content: " + content);
|
||||
contentList.splice(index, 1);
|
||||
|
||||
if (index >= 0)
|
||||
contentList.splice(index, 1);
|
||||
},
|
||||
|
||||
removePatternContent: function(content) {
|
||||
@ -125,8 +128,7 @@ const BackgroundCache = new Lang.Class({
|
||||
removeImageContent: function(content) {
|
||||
let filename = content.get_filename();
|
||||
|
||||
let hasOtherUsers = this._images.some(function(content) { return filename == content.get_filename(); });
|
||||
if (!hasOtherUsers)
|
||||
if (filename && this._fileMonitors[filename])
|
||||
delete this._fileMonitors[filename];
|
||||
|
||||
this._removeContent(this._images, content);
|
||||
@ -184,17 +186,13 @@ const BackgroundCache = new Lang.Class({
|
||||
|
||||
for (let j = 0; j < pendingLoad.callers.length; j++) {
|
||||
if (pendingLoad.callers[j].onFinished) {
|
||||
let newContent;
|
||||
|
||||
if (content && pendingLoad.callers[j].shouldCopy) {
|
||||
newContent = content.copy(pendingLoad.callers[j].monitorIndex,
|
||||
pendingLoad.callers[j].effects);
|
||||
this._images.push(newContent);
|
||||
} else {
|
||||
newContent = content;
|
||||
content = object.copy(pendingLoad.callers[j].monitorIndex,
|
||||
pendingLoad.callers[j].effects);
|
||||
|
||||
}
|
||||
|
||||
pendingLoad.callers[j].onFinished(newContent);
|
||||
pendingLoad.callers[j].onFinished(content);
|
||||
}
|
||||
}
|
||||
|
||||
@ -212,9 +210,11 @@ const BackgroundCache = new Lang.Class({
|
||||
onFinished: null });
|
||||
|
||||
let content = null;
|
||||
|
||||
let candidateContent = null;
|
||||
for (let i = 0; i < this._images.length; i++) {
|
||||
if (!this._images[i])
|
||||
continue;
|
||||
|
||||
if (this._images[i].get_style() != params.style)
|
||||
continue;
|
||||
|
||||
@ -222,7 +222,7 @@ const BackgroundCache = new Lang.Class({
|
||||
continue;
|
||||
|
||||
if (params.style == GDesktopEnums.BackgroundStyle.SPANNED &&
|
||||
this._images[i].monitor != params.monitorIndex)
|
||||
this._images[i].monitor_index != this._monitorIndex)
|
||||
continue;
|
||||
|
||||
candidateContent = this._images[i];
|
||||
@ -262,7 +262,6 @@ const BackgroundCache = new Lang.Class({
|
||||
if (params.onLoaded) {
|
||||
GLib.idle_add(GLib.PRIORITY_DEFAULT, Lang.bind(this, function() {
|
||||
params.onLoaded(this._animation);
|
||||
return GLib.SOURCE_REMOVE;
|
||||
}));
|
||||
}
|
||||
}
|
||||
@ -277,7 +276,6 @@ const BackgroundCache = new Lang.Class({
|
||||
if (params.onLoaded) {
|
||||
GLib.idle_add(GLib.PRIORITY_DEFAULT, Lang.bind(this, function() {
|
||||
params.onLoaded(this._animation);
|
||||
return GLib.SOURCE_REMOVE;
|
||||
}));
|
||||
}
|
||||
}));
|
||||
@ -317,6 +315,7 @@ const Background = new Lang.Class({
|
||||
|
||||
this._brightness = 1.0;
|
||||
this._vignetteSharpness = 0.2;
|
||||
this._saturation = 1.0;
|
||||
this._cancellable = new Gio.Cancellable();
|
||||
this.isLoaded = false;
|
||||
|
||||
@ -377,7 +376,7 @@ const Background = new Lang.Class({
|
||||
|
||||
GLib.idle_add(GLib.PRIORITY_DEFAULT, Lang.bind(this, function() {
|
||||
this.emit('loaded');
|
||||
return GLib.SOURCE_REMOVE;
|
||||
return false;
|
||||
}));
|
||||
},
|
||||
|
||||
@ -416,26 +415,29 @@ const Background = new Lang.Class({
|
||||
this._fileWatches[filename] = signalId;
|
||||
},
|
||||
|
||||
_ensureImage: function(index) {
|
||||
if (this._images[index])
|
||||
return;
|
||||
_addImage: function(content, index, filename) {
|
||||
content.saturation = this._saturation;
|
||||
content.brightness = this._brightness;
|
||||
content.vignette_sharpness = this._vignetteSharpness;
|
||||
|
||||
let actor = new Meta.BackgroundActor();
|
||||
actor.content = content;
|
||||
|
||||
// The background pattern is the first actor in
|
||||
// the group, and all images should be above that.
|
||||
this.actor.insert_child_at_index(actor, index + 1);
|
||||
|
||||
this._images[index] = actor;
|
||||
this._watchCacheFile(filename);
|
||||
},
|
||||
|
||||
_updateImage: function(index, content, filename) {
|
||||
_updateImage: function(content, index, filename) {
|
||||
content.saturation = this._saturation;
|
||||
content.brightness = this._brightness;
|
||||
content.vignette_sharpness = this._vignetteSharpness;
|
||||
|
||||
let image = this._images[index];
|
||||
if (image.content)
|
||||
this._cache.removeImageContent(content);
|
||||
image.content = content;
|
||||
this._cache.removeImageContent(this._images[index].content);
|
||||
this._images[index].content = content;
|
||||
this._watchCacheFile(filename);
|
||||
},
|
||||
|
||||
@ -483,8 +485,11 @@ const Background = new Lang.Class({
|
||||
return;
|
||||
}
|
||||
|
||||
this._ensureImage(i);
|
||||
this._updateImage(i, content, files[i]);
|
||||
if (!this._images[i]) {
|
||||
this._addImage(content, i, files[i]);
|
||||
} else {
|
||||
this._updateImage(content, i, files[i]);
|
||||
}
|
||||
|
||||
if (numPendingImages == 0) {
|
||||
this._setLoaded();
|
||||
@ -519,7 +524,7 @@ const Background = new Lang.Class({
|
||||
Lang.bind(this, function() {
|
||||
this._updateAnimationTimeoutId = 0;
|
||||
this._updateAnimation();
|
||||
return GLib.SOURCE_REMOVE;
|
||||
return false;
|
||||
}));
|
||||
},
|
||||
|
||||
@ -539,27 +544,24 @@ const Background = new Lang.Class({
|
||||
});
|
||||
},
|
||||
|
||||
_loadImage: function(filename) {
|
||||
_loadFile: function(filename) {
|
||||
this._cache.getImageContent({ monitorIndex: this._monitorIndex,
|
||||
effects: this._effects,
|
||||
style: this._style,
|
||||
filename: filename,
|
||||
cancellable: this._cancellable,
|
||||
onFinished: Lang.bind(this, function(content) {
|
||||
if (content) {
|
||||
this._ensureImage(0);
|
||||
this._updateImage(0, content, filename);
|
||||
if (!content) {
|
||||
if (!this._cancellable.is_cancelled())
|
||||
this._loadAnimation(filename);
|
||||
return;
|
||||
}
|
||||
|
||||
this._addImage(content, 0, filename);
|
||||
this._setLoaded();
|
||||
})
|
||||
});
|
||||
},
|
||||
|
||||
_loadFile: function(filename) {
|
||||
if (filename.endsWith('.xml'))
|
||||
this._loadAnimation(filename);
|
||||
else
|
||||
this._loadImage(filename);
|
||||
},
|
||||
|
||||
_load: function () {
|
||||
@ -588,6 +590,24 @@ const Background = new Lang.Class({
|
||||
this._loadFile(filename);
|
||||
},
|
||||
|
||||
get saturation() {
|
||||
return this._saturation;
|
||||
},
|
||||
|
||||
set saturation(saturation) {
|
||||
this._saturation = saturation;
|
||||
|
||||
if (this._pattern && this._pattern.content)
|
||||
this._pattern.content.saturation = saturation;
|
||||
|
||||
let keys = Object.keys(this._images);
|
||||
for (let i = 0; i < keys.length; i++) {
|
||||
let image = this._images[keys[i]];
|
||||
if (image && image.content)
|
||||
image.content.saturation = saturation;
|
||||
}
|
||||
},
|
||||
|
||||
get brightness() {
|
||||
return this._brightness;
|
||||
},
|
||||
@ -639,13 +659,7 @@ const SystemBackground = new Lang.Class({
|
||||
this.emit('loaded');
|
||||
})
|
||||
});
|
||||
|
||||
this.actor.connect('destroy', Lang.bind(this, this._onDestroy));
|
||||
},
|
||||
|
||||
_onDestroy: function() {
|
||||
this._cache.removeImageContent(this.actor.content);
|
||||
},
|
||||
}
|
||||
});
|
||||
Signals.addSignalMethods(SystemBackground.prototype);
|
||||
|
||||
@ -733,10 +747,11 @@ const BackgroundManager = new Lang.Class({
|
||||
}
|
||||
},
|
||||
|
||||
_updateBackground: function(background) {
|
||||
let newBackground = this._createBackground();
|
||||
_updateBackground: function(background, monitorIndex) {
|
||||
let newBackground = this._createBackground(monitorIndex);
|
||||
newBackground.vignetteSharpness = background.vignetteSharpness;
|
||||
newBackground.brightness = background.brightness;
|
||||
newBackground.saturation = background.saturation;
|
||||
newBackground.visible = background.visible;
|
||||
|
||||
newBackground.loadedSignalId = newBackground.connect('loaded',
|
||||
@ -783,7 +798,7 @@ const BackgroundManager = new Lang.Class({
|
||||
background.changeSignalId = background.connect('changed', Lang.bind(this, function() {
|
||||
background.disconnect(background.changeSignalId);
|
||||
background.changeSignalId = 0;
|
||||
this._updateBackground(background);
|
||||
this._updateBackground(background, this._monitorIndex);
|
||||
}));
|
||||
|
||||
background.actor.connect('destroy', Lang.bind(this, function() {
|
||||
|
@ -13,7 +13,7 @@ const BackgroundMenu = new Lang.Class({
|
||||
Name: 'BackgroundMenu',
|
||||
Extends: PopupMenu.PopupMenu,
|
||||
|
||||
_init: function(source, layoutManager) {
|
||||
_init: function(source) {
|
||||
this.parent(source, 0, St.Side.TOP);
|
||||
|
||||
this.addSettingsAction(_("Settings"), 'gnome-control-center.desktop');
|
||||
@ -22,17 +22,17 @@ const BackgroundMenu = new Lang.Class({
|
||||
|
||||
this.actor.add_style_class_name('background-menu');
|
||||
|
||||
layoutManager.uiGroup.add_actor(this.actor);
|
||||
Main.uiGroup.add_actor(this.actor);
|
||||
this.actor.hide();
|
||||
}
|
||||
});
|
||||
|
||||
function addBackgroundMenu(actor, layoutManager) {
|
||||
function addBackgroundMenu(actor) {
|
||||
let cursor = new St.Bin({ opacity: 0 });
|
||||
layoutManager.uiGroup.add_actor(cursor);
|
||||
Main.uiGroup.add_actor(cursor);
|
||||
|
||||
actor.reactive = true;
|
||||
actor._backgroundMenu = new BackgroundMenu(cursor, layoutManager);
|
||||
actor._backgroundMenu = new BackgroundMenu(cursor);
|
||||
actor._backgroundManager = new PopupMenu.PopupMenuManager({ actor: actor });
|
||||
actor._backgroundManager.addMenu(actor._backgroundMenu);
|
||||
|
||||
|
@ -69,7 +69,7 @@ const BoxPointer = new Lang.Class({
|
||||
_muteInput: function() {
|
||||
if (this._capturedEventId == 0)
|
||||
this._capturedEventId = this.actor.connect('captured-event',
|
||||
function() { return Clutter.EVENT_STOP; });
|
||||
function() { return true; });
|
||||
},
|
||||
|
||||
_unmuteInput: function() {
|
||||
@ -121,9 +121,6 @@ const BoxPointer = new Lang.Class({
|
||||
},
|
||||
|
||||
hide: function(animate, onComplete) {
|
||||
if (!this.actor.visible)
|
||||
return;
|
||||
|
||||
let xOffset = 0;
|
||||
let yOffset = 0;
|
||||
let themeNode = this.actor.get_theme_node();
|
||||
@ -188,9 +185,7 @@ const BoxPointer = new Lang.Class({
|
||||
},
|
||||
|
||||
_getPreferredHeight: function(actor, forWidth, alloc) {
|
||||
let themeNode = this.actor.get_theme_node();
|
||||
let borderWidth = themeNode.get_length('-arrow-border-width');
|
||||
let [minSize, naturalSize] = this.bin.get_preferred_height(forWidth - 2 * borderWidth);
|
||||
let [minSize, naturalSize] = this.bin.get_preferred_height(forWidth);
|
||||
alloc.min_size = minSize;
|
||||
alloc.natural_size = naturalSize;
|
||||
this._adjustAllocationForArrow(false, alloc);
|
||||
|
@ -17,18 +17,16 @@ const SHOW_WEEKDATE_KEY = 'show-weekdate';
|
||||
// in org.gnome.desktop.interface
|
||||
const CLOCK_FORMAT_KEY = 'clock-format';
|
||||
|
||||
function _sameDay(dateA, dateB) {
|
||||
return (dateA.getDate() == dateB.getDate() &&
|
||||
dateA.getMonth() == dateB.getMonth() &&
|
||||
dateA.getYear() == dateB.getYear());
|
||||
}
|
||||
|
||||
function _sameYear(dateA, dateB) {
|
||||
return (dateA.getYear() == dateB.getYear());
|
||||
}
|
||||
|
||||
function _sameMonth(dateA, dateB) {
|
||||
return _sameYear(dateA, dateB) && (dateA.getMonth() == dateB.getMonth());
|
||||
}
|
||||
|
||||
function _sameDay(dateA, dateB) {
|
||||
return _sameMonth(dateA, dateB) && (dateA.getDate() == dateB.getDate());
|
||||
}
|
||||
|
||||
/* TODO: maybe needs config - right now we assume that Saturday and
|
||||
* Sunday are non-work days (not true in e.g. Israel, it's Sunday and
|
||||
* Monday there)
|
||||
@ -192,18 +190,16 @@ const EmptyEventSource = new Lang.Class({
|
||||
});
|
||||
Signals.addSignalMethods(EmptyEventSource.prototype);
|
||||
|
||||
const CalendarServerIface = '<node> \
|
||||
<interface name="org.gnome.Shell.CalendarServer"> \
|
||||
<method name="GetEvents"> \
|
||||
<arg type="x" direction="in" /> \
|
||||
<arg type="x" direction="in" /> \
|
||||
<arg type="b" direction="in" /> \
|
||||
<arg type="a(sssbxxa{sv})" direction="out" /> \
|
||||
</method> \
|
||||
<property name="HasCalendars" type="b" access="read" /> \
|
||||
<signal name="Changed" /> \
|
||||
</interface> \
|
||||
</node>';
|
||||
const CalendarServerIface = <interface name="org.gnome.Shell.CalendarServer">
|
||||
<method name="GetEvents">
|
||||
<arg type="x" direction="in" />
|
||||
<arg type="x" direction="in" />
|
||||
<arg type="b" direction="in" />
|
||||
<arg type="a(sssbxxa{sv})" direction="out" />
|
||||
</method>
|
||||
<property name="HasCalendars" type="b" access="read" />
|
||||
<signal name="Changed" />
|
||||
</interface>;
|
||||
|
||||
const CalendarServerInfo = Gio.DBusInterfaceInfo.new_for_xml(CalendarServerIface);
|
||||
|
||||
@ -331,22 +327,25 @@ const DBusEventSource = new Lang.Class({
|
||||
return;
|
||||
|
||||
if (this._curRequestBegin && this._curRequestEnd){
|
||||
let callFlags = Gio.DBusCallFlags.NO_AUTO_START;
|
||||
if (forceReload)
|
||||
callFlags = Gio.DBusCallFlags.NONE;
|
||||
this._dbusProxy.GetEventsRemote(this._curRequestBegin.getTime() / 1000,
|
||||
this._curRequestEnd.getTime() / 1000,
|
||||
forceReload,
|
||||
Lang.bind(this, this._onEventsReceived),
|
||||
Gio.DBusCallFlags.NONE);
|
||||
callFlags);
|
||||
}
|
||||
},
|
||||
|
||||
requestRange: function(begin, end) {
|
||||
if (!(_datesEqual(begin, this._lastRequestBegin) && _datesEqual(end, this._lastRequestEnd))) {
|
||||
requestRange: function(begin, end, forceReload) {
|
||||
if (forceReload || !(_datesEqual(begin, this._lastRequestBegin) && _datesEqual(end, this._lastRequestEnd))) {
|
||||
this.isLoading = true;
|
||||
this._lastRequestBegin = begin;
|
||||
this._lastRequestEnd = end;
|
||||
this._curRequestBegin = begin;
|
||||
this._curRequestEnd = end;
|
||||
this._loadEvents(false);
|
||||
this._loadEvents(forceReload);
|
||||
}
|
||||
},
|
||||
|
||||
@ -418,19 +417,21 @@ const Calendar = new Lang.Class({
|
||||
setEventSource: function(eventSource) {
|
||||
this._eventSource = eventSource;
|
||||
this._eventSource.connect('changed', Lang.bind(this, function() {
|
||||
this._update();
|
||||
this._update(false);
|
||||
}));
|
||||
this._update();
|
||||
this._update(true);
|
||||
},
|
||||
|
||||
// Sets the calendar to show a specific date
|
||||
setDate: function(date) {
|
||||
if (_sameDay(date, this._selectedDate))
|
||||
return;
|
||||
|
||||
this._selectedDate = date;
|
||||
this._update();
|
||||
this.emit('selected-date-changed', new Date(this._selectedDate));
|
||||
setDate: function(date, forceReload) {
|
||||
if (!_sameDay(date, this._selectedDate)) {
|
||||
this._selectedDate = date;
|
||||
this._update(forceReload);
|
||||
this.emit('selected-date-changed', new Date(this._selectedDate));
|
||||
} else {
|
||||
if (forceReload)
|
||||
this._update(forceReload);
|
||||
}
|
||||
},
|
||||
|
||||
_buildHeader: function() {
|
||||
@ -494,7 +495,6 @@ const Calendar = new Lang.Class({
|
||||
this._onNextMonthButtonClicked();
|
||||
break;
|
||||
}
|
||||
return Clutter.EVENT_PROPAGATE;
|
||||
},
|
||||
|
||||
_onPrevMonthButtonClicked: function() {
|
||||
@ -518,7 +518,7 @@ const Calendar = new Lang.Class({
|
||||
|
||||
this._backButton.grab_key_focus();
|
||||
|
||||
this.setDate(newDate);
|
||||
this.setDate(newDate, false);
|
||||
},
|
||||
|
||||
_onNextMonthButtonClicked: function() {
|
||||
@ -542,25 +542,28 @@ const Calendar = new Lang.Class({
|
||||
|
||||
this._forwardButton.grab_key_focus();
|
||||
|
||||
this.setDate(newDate);
|
||||
this.setDate(newDate, false);
|
||||
},
|
||||
|
||||
_onSettingsChange: function() {
|
||||
this._useWeekdate = this._settings.get_boolean(SHOW_WEEKDATE_KEY);
|
||||
this._buildHeader();
|
||||
this._update();
|
||||
this._update(false);
|
||||
},
|
||||
|
||||
_rebuildCalendar: function() {
|
||||
_update: function(forceReload) {
|
||||
let now = new Date();
|
||||
|
||||
if (_sameYear(this._selectedDate, now))
|
||||
this._monthLabel.text = this._selectedDate.toLocaleFormat(this._headerFormatWithoutYear);
|
||||
else
|
||||
this._monthLabel.text = this._selectedDate.toLocaleFormat(this._headerFormat);
|
||||
|
||||
// Remove everything but the topBox and the weekday labels
|
||||
let children = this.actor.get_children();
|
||||
for (let i = this._firstDayIndex; i < children.length; i++)
|
||||
children[i].destroy();
|
||||
|
||||
this._buttons = [];
|
||||
|
||||
// Start at the beginning of the week before the start of the month
|
||||
//
|
||||
// We want to show always 6 weeks (to keep the calendar menu at the same
|
||||
@ -578,13 +581,11 @@ const Calendar = new Lang.Class({
|
||||
// Actually computing the number of weeks is complex, but we know that the
|
||||
// problematic categories (2 and 4) always start on week start, and that
|
||||
// all months at the end have 6 weeks.
|
||||
|
||||
let beginDate = new Date(this._selectedDate);
|
||||
beginDate.setDate(1);
|
||||
beginDate.setSeconds(0);
|
||||
beginDate.setHours(12);
|
||||
|
||||
this._calendarBegin = new Date(beginDate);
|
||||
|
||||
let year = beginDate.getYear();
|
||||
|
||||
let daysToWeekStart = (7 + beginDate.getDay() - this._weekStart) % 7;
|
||||
@ -605,18 +606,23 @@ const Calendar = new Lang.Class({
|
||||
if (this._eventSource.isDummy)
|
||||
button.reactive = false;
|
||||
|
||||
button._date = new Date(iter);
|
||||
let iterStr = iter.toUTCString();
|
||||
button.connect('clicked', Lang.bind(this, function() {
|
||||
this.setDate(button._date);
|
||||
this._shouldDateGrabFocus = true;
|
||||
|
||||
let newlySelectedDate = new Date(iterStr);
|
||||
this.setDate(newlySelectedDate, false);
|
||||
|
||||
this._shouldDateGrabFocus = false;
|
||||
}));
|
||||
|
||||
let hasEvents = this._eventSource.hasEvents(iter);
|
||||
let styleClass = 'calendar-day-base calendar-day';
|
||||
|
||||
if (_isWorkDay(iter))
|
||||
styleClass += ' calendar-work-day';
|
||||
styleClass += ' calendar-work-day'
|
||||
else
|
||||
styleClass += ' calendar-nonwork-day';
|
||||
styleClass += ' calendar-nonwork-day'
|
||||
|
||||
// Hack used in lieu of border-collapse - see gnome-shell.css
|
||||
if (row == 2)
|
||||
@ -633,7 +639,7 @@ const Calendar = new Lang.Class({
|
||||
styleClass += ' calendar-other-month-day';
|
||||
|
||||
if (hasEvents)
|
||||
styleClass += ' calendar-day-with-events';
|
||||
styleClass += ' calendar-day-with-events'
|
||||
|
||||
button.style_class = styleClass;
|
||||
|
||||
@ -641,7 +647,12 @@ const Calendar = new Lang.Class({
|
||||
this.actor.add(button,
|
||||
{ row: row, col: offsetCols + (7 + iter.getDay() - this._weekStart) % 7 });
|
||||
|
||||
this._buttons.push(button);
|
||||
if (_sameDay(this._selectedDate, iter)) {
|
||||
button.add_style_pseudo_class('active');
|
||||
|
||||
if (this._shouldDateGrabFocus)
|
||||
button.grab_key_focus();
|
||||
}
|
||||
|
||||
if (this._useWeekdate && iter.getDay() == 4) {
|
||||
let label = new St.Label({ text: _getCalendarWeekForDate(iter).toString(),
|
||||
@ -655,29 +666,9 @@ const Calendar = new Lang.Class({
|
||||
if (iter.getDay() == this._weekStart)
|
||||
row++;
|
||||
}
|
||||
|
||||
// Signal to the event source that we are interested in events
|
||||
// only from this date range
|
||||
this._eventSource.requestRange(beginDate, iter);
|
||||
},
|
||||
|
||||
_update: function() {
|
||||
let now = new Date();
|
||||
|
||||
if (_sameYear(this._selectedDate, now))
|
||||
this._monthLabel.text = this._selectedDate.toLocaleFormat(this._headerFormatWithoutYear);
|
||||
else
|
||||
this._monthLabel.text = this._selectedDate.toLocaleFormat(this._headerFormat);
|
||||
|
||||
if (!this._calendarBegin || !_sameMonth(this._selectedDate, this._calendarBegin))
|
||||
this._rebuildCalendar();
|
||||
|
||||
this._buttons.forEach(Lang.bind(this, function(button) {
|
||||
if (_sameDay(button._date, this._selectedDate))
|
||||
button.add_style_pseudo_class('active');
|
||||
else
|
||||
button.remove_style_pseudo_class('active');
|
||||
}));
|
||||
this._eventSource.requestRange(beginDate, iter, forceReload);
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -77,7 +77,7 @@ const AutomountManager = new Lang.Class({
|
||||
}));
|
||||
|
||||
this._mountAllId = 0;
|
||||
return GLib.SOURCE_REMOVE;
|
||||
return false;
|
||||
},
|
||||
|
||||
_onDriveConnected: function() {
|
||||
@ -236,7 +236,7 @@ const AutomountManager = new Lang.Class({
|
||||
_allowAutorunExpire: function(volume) {
|
||||
Mainloop.timeout_add_seconds(AUTORUN_EXPIRE_TIMEOUT_SECS, function() {
|
||||
volume.allowAutorun = false;
|
||||
return GLib.SOURCE_REMOVE;
|
||||
return false;
|
||||
});
|
||||
}
|
||||
});
|
||||
|
@ -75,14 +75,12 @@ function startAppForMount(app, mount) {
|
||||
|
||||
/******************************************/
|
||||
|
||||
const HotplugSnifferIface = '<node> \
|
||||
<interface name="org.gnome.Shell.HotplugSniffer"> \
|
||||
<method name="SniffURI"> \
|
||||
<arg type="s" direction="in" /> \
|
||||
<arg type="as" direction="out" /> \
|
||||
</method> \
|
||||
</interface> \
|
||||
</node>';
|
||||
const HotplugSnifferIface = <interface name="org.gnome.Shell.HotplugSniffer">
|
||||
<method name="SniffURI">
|
||||
<arg type="s" direction="in" />
|
||||
<arg type="as" direction="out" />
|
||||
</method>
|
||||
</interface>;
|
||||
|
||||
const HotplugSnifferProxy = Gio.DBusProxy.makeProxyWrapper(HotplugSnifferIface);
|
||||
function HotplugSniffer() {
|
||||
|
@ -13,6 +13,8 @@ const ModalDialog = imports.ui.modalDialog;
|
||||
const ShellEntry = imports.ui.shellEntry;
|
||||
const CheckBox = imports.ui.checkBox;
|
||||
|
||||
let prompter = null;
|
||||
|
||||
const KeyringDialog = new Lang.Class({
|
||||
Name: 'KeyringDialog',
|
||||
Extends: ModalDialog.ModalDialog,
|
||||
@ -45,9 +47,7 @@ const KeyringDialog = new Lang.Class({
|
||||
this.prompt.bind_property('message', subject, 'text', GObject.BindingFlags.SYNC_CREATE);
|
||||
|
||||
this._messageBox.add(subject,
|
||||
{ x_fill: false,
|
||||
y_fill: false,
|
||||
x_align: St.Align.START,
|
||||
{ y_fill: false,
|
||||
y_align: St.Align.START });
|
||||
|
||||
let description = new St.Label({ style_class: 'prompt-dialog-description' });
|
||||
@ -138,7 +138,6 @@ const KeyringDialog = new Lang.Class({
|
||||
warning.clutter_text.ellipsize = Pango.EllipsizeMode.NONE;
|
||||
warning.clutter_text.line_wrap = true;
|
||||
layout.pack(warning, 1, row);
|
||||
layout.child_set(warning, { x_fill: false, x_align: Clutter.TableAlignment.START });
|
||||
this.prompt.bind_property('warning-visible', warning, 'visible', GObject.BindingFlags.SYNC_CREATE);
|
||||
this.prompt.bind_property('warning', warning, 'text', GObject.BindingFlags.SYNC_CREATE);
|
||||
|
||||
@ -249,13 +248,11 @@ const KeyringPrompter = new Lang.Class({
|
||||
function() {
|
||||
let dialog = this._enabled ? new KeyringDialog()
|
||||
: new KeyringDummyDialog();
|
||||
this._currentPrompt = dialog.prompt;
|
||||
return this._currentPrompt;
|
||||
return dialog.prompt;
|
||||
}));
|
||||
this._dbusId = null;
|
||||
this._registered = false;
|
||||
this._enabled = false;
|
||||
this._currentPrompt = null;
|
||||
},
|
||||
|
||||
enable: function() {
|
||||
@ -270,10 +267,6 @@ const KeyringPrompter = new Lang.Class({
|
||||
|
||||
disable: function() {
|
||||
this._enabled = false;
|
||||
|
||||
if (this._prompter.prompting)
|
||||
this._currentPrompt.cancel();
|
||||
this._currentPrompt = null;
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -138,8 +138,6 @@ const NetworkSecretDialog = new Lang.Class({
|
||||
key: Clutter.KEY_Escape,
|
||||
},
|
||||
this._okButton]);
|
||||
|
||||
this._updateOkButton();
|
||||
},
|
||||
|
||||
_updateOkButton: function() {
|
||||
@ -255,7 +253,6 @@ const NetworkSecretDialog = new Lang.Class({
|
||||
case 'leap':
|
||||
case 'ttls':
|
||||
case 'peap':
|
||||
case 'fast':
|
||||
// TTLS and PEAP are actually much more complicated, but this complication
|
||||
// is not visible here since we only care about phase2 authentication
|
||||
// (and don't even care of which one)
|
||||
@ -435,7 +432,6 @@ const VPNRequestHandler = new Lang.Class({
|
||||
},
|
||||
|
||||
_vpnChildFinished: function(pid, status, requestObj) {
|
||||
this._childWatch = 0;
|
||||
if (this._newStylePlugin) {
|
||||
// For new style plugin, all work is done in the async reading functions
|
||||
// Just reap the process here
|
||||
|
@ -54,9 +54,7 @@ const AuthenticationDialog = new Lang.Class({
|
||||
text: _("Authentication Required") });
|
||||
|
||||
messageBox.add(this._subjectLabel,
|
||||
{ x_fill: false,
|
||||
y_fill: false,
|
||||
x_align: St.Align.START,
|
||||
{ y_fill: false,
|
||||
y_align: St.Align.START });
|
||||
|
||||
this._descriptionLabel = new St.Label({ style_class: 'prompt-dialog-description',
|
||||
@ -65,9 +63,7 @@ const AuthenticationDialog = new Lang.Class({
|
||||
this._descriptionLabel.clutter_text.line_wrap = true;
|
||||
|
||||
messageBox.add(this._descriptionLabel,
|
||||
{ x_fill: false,
|
||||
y_fill: true,
|
||||
x_align: St.Align.START,
|
||||
{ y_fill: true,
|
||||
y_align: St.Align.START });
|
||||
|
||||
if (userNames.length > 1) {
|
||||
@ -99,8 +95,7 @@ const AuthenticationDialog = new Lang.Class({
|
||||
if (userIsRoot) {
|
||||
let userLabel = new St.Label(({ style_class: 'polkit-dialog-user-root-label',
|
||||
text: userRealName }));
|
||||
messageBox.add(userLabel, { x_fill: false,
|
||||
x_align: St.Align.START });
|
||||
messageBox.add(userLabel);
|
||||
} else {
|
||||
let userBox = new St.BoxLayout({ style_class: 'polkit-dialog-user-layout',
|
||||
vertical: false });
|
||||
@ -142,7 +137,7 @@ const AuthenticationDialog = new Lang.Class({
|
||||
this._errorMessageLabel = new St.Label({ style_class: 'prompt-dialog-error-label' });
|
||||
this._errorMessageLabel.clutter_text.ellipsize = Pango.EllipsizeMode.NONE;
|
||||
this._errorMessageLabel.clutter_text.line_wrap = true;
|
||||
messageBox.add(this._errorMessageLabel, { x_fill: false, x_align: St.Align.START });
|
||||
messageBox.add(this._errorMessageLabel);
|
||||
this._errorMessageLabel.hide();
|
||||
|
||||
this._infoMessageLabel = new St.Label({ style_class: 'prompt-dialog-info-label' });
|
||||
|
@ -13,6 +13,7 @@ const Tp = imports.gi.TelepathyGLib;
|
||||
const History = imports.misc.history;
|
||||
const Main = imports.ui.main;
|
||||
const MessageTray = imports.ui.messageTray;
|
||||
const NotificationDaemon = imports.ui.notificationDaemon;
|
||||
const Params = imports.misc.params;
|
||||
const PopupMenu = imports.ui.popupMenu;
|
||||
|
||||
@ -415,7 +416,7 @@ const TelepathyClient = new Lang.Class({
|
||||
_ensureAppSource: function() {
|
||||
if (this._appSource == null) {
|
||||
this._appSource = new MessageTray.Source(_("Chat"), 'empathy');
|
||||
this._appSource.policy = new MessageTray.NotificationApplicationPolicy('empathy');
|
||||
this._appSource.policy = new NotificationDaemon.NotificationApplicationPolicy('empathy');
|
||||
|
||||
Main.messageTray.add(this._appSource);
|
||||
this._appSource.connect('destroy', Lang.bind(this, function () {
|
||||
@ -446,7 +447,6 @@ const ChatSource = new Lang.Class({
|
||||
this._closedId = this._channel.connect('invalidated', Lang.bind(this, this._channelClosed));
|
||||
|
||||
this._notification = new ChatNotification(this);
|
||||
this._notification.connect('clicked', Lang.bind(this, this.open));
|
||||
this._notification.setUrgency(MessageTray.Urgency.HIGH);
|
||||
this._notifyTimeoutId = 0;
|
||||
|
||||
@ -488,7 +488,7 @@ const ChatSource = new Lang.Class({
|
||||
},
|
||||
|
||||
_createPolicy: function() {
|
||||
return new MessageTray.NotificationApplicationPolicy('empathy');
|
||||
return new NotificationDaemon.NotificationApplicationPolicy('empathy');
|
||||
},
|
||||
|
||||
_updateAlias: function() {
|
||||
@ -545,19 +545,20 @@ const ChatSource = new Lang.Class({
|
||||
this._notification.update(this._notification.title, null, { customContent: true });
|
||||
},
|
||||
|
||||
open: function() {
|
||||
if (this._client.is_handling_channel(this._channel)) {
|
||||
// We are handling the channel, try to pass it to Empathy
|
||||
this._client.delegate_channels_async([this._channel],
|
||||
global.get_current_time(),
|
||||
'org.freedesktop.Telepathy.Client.Empathy.Chat', null);
|
||||
} else {
|
||||
// We are not the handler, just ask to present the channel
|
||||
let dbus = Tp.DBusDaemon.dup();
|
||||
let cd = Tp.ChannelDispatcher.new(dbus);
|
||||
open: function(notification) {
|
||||
if (this._client.is_handling_channel(this._channel)) {
|
||||
// We are handling the channel, try to pass it to Empathy
|
||||
this._client.delegate_channels_async([this._channel],
|
||||
global.get_current_time(),
|
||||
'org.freedesktop.Telepathy.Client.Empathy.Chat', null);
|
||||
}
|
||||
else {
|
||||
// We are not the handler, just ask to present the channel
|
||||
let dbus = Tp.DBusDaemon.dup();
|
||||
let cd = Tp.ChannelDispatcher.new(dbus);
|
||||
|
||||
cd.present_channel_async(this._channel, global.get_current_time(), null);
|
||||
}
|
||||
cd.present_channel_async(this._channel, global.get_current_time(), null);
|
||||
}
|
||||
},
|
||||
|
||||
_getLogMessages: function() {
|
||||
@ -675,7 +676,7 @@ const ChatSource = new Lang.Class({
|
||||
|
||||
this._notifyTimeoutId = 0;
|
||||
|
||||
return GLib.SOURCE_REMOVE;
|
||||
return false;
|
||||
},
|
||||
|
||||
// This is called for both messages we send from
|
||||
@ -960,8 +961,6 @@ const ChatNotification = new Lang.Class({
|
||||
},
|
||||
|
||||
appendTimestamp: function() {
|
||||
this._timestampTimeoutId = 0;
|
||||
|
||||
let lastMessageTime = this._history[0].time;
|
||||
let lastMessageDate = new Date(lastMessageTime * 1000);
|
||||
|
||||
@ -975,7 +974,7 @@ const ChatNotification = new Lang.Class({
|
||||
|
||||
this._filterMessages();
|
||||
|
||||
return GLib.SOURCE_REMOVE;
|
||||
return false;
|
||||
},
|
||||
|
||||
appendAliasChange: function(oldAlias, newAlias) {
|
||||
@ -1013,7 +1012,7 @@ const ChatNotification = new Lang.Class({
|
||||
|
||||
this.source.setChatState(Tp.ChannelChatState.PAUSED);
|
||||
|
||||
return GLib.SOURCE_REMOVE;
|
||||
return false;
|
||||
},
|
||||
|
||||
_onEntryChanged: function() {
|
||||
@ -1062,7 +1061,7 @@ const ApproverSource = new Lang.Class({
|
||||
},
|
||||
|
||||
_createPolicy: function() {
|
||||
return new MessageTray.NotificationApplicationPolicy('empathy');
|
||||
return new NotificationDaemon.NotificationApplicationPolicy('empathy');
|
||||
},
|
||||
|
||||
destroy: function() {
|
||||
@ -1097,16 +1096,22 @@ const RoomInviteNotification = new Lang.Class({
|
||||
* for example. */
|
||||
this.addBody(_("%s is inviting you to join %s").format(inviter.get_alias(), channel.get_identifier()));
|
||||
|
||||
this.addAction(_("Decline"), Lang.bind(this, function() {
|
||||
dispatchOp.leave_channels_async(Tp.ChannelGroupChangeReason.NONE, '', function(src, result) {
|
||||
src.leave_channels_finish(result);
|
||||
});
|
||||
this.destroy();
|
||||
}));
|
||||
this.addAction(_("Accept"), Lang.bind(this, function() {
|
||||
dispatchOp.handle_with_time_async('', global.get_current_time(), function(src, result) {
|
||||
src.handle_with_time_finish(result);
|
||||
});
|
||||
this.addButton('decline', _("Decline"));
|
||||
this.addButton('accept', _("Accept"));
|
||||
|
||||
this.connect('action-invoked', Lang.bind(this, function(self, action) {
|
||||
switch (action) {
|
||||
case 'decline':
|
||||
dispatchOp.leave_channels_async(Tp.ChannelGroupChangeReason.NONE,
|
||||
'', function(src, result) {
|
||||
src.leave_channels_finish(result)});
|
||||
break;
|
||||
case 'accept':
|
||||
dispatchOp.handle_with_time_async('', global.get_current_time(),
|
||||
function(src, result) {
|
||||
src.handle_with_time_finish(result)});
|
||||
break;
|
||||
}
|
||||
this.destroy();
|
||||
}));
|
||||
}
|
||||
@ -1132,17 +1137,23 @@ const AudioVideoNotification = new Lang.Class({
|
||||
|
||||
this.setUrgency(MessageTray.Urgency.CRITICAL);
|
||||
|
||||
this.addAction(_("Decline"), Lang.bind(this, function() {
|
||||
dispatchOp.leave_channels_async(Tp.ChannelGroupChangeReason.NONE, '', function(src, result) {
|
||||
src.leave_channels_finish(result);
|
||||
});
|
||||
this.destroy();
|
||||
}));
|
||||
this.addButton('reject', _("Decline"));
|
||||
/* translators: this is a button label (verb), not a noun */
|
||||
this.addAction(_("Answer"), Lang.bind(this, function() {
|
||||
dispatchOp.handle_with_time_async('', global.get_current_time(), function(src, result) {
|
||||
src.handle_with_time_finish(result);
|
||||
});
|
||||
this.addButton('answer', _("Answer"));
|
||||
|
||||
this.connect('action-invoked', Lang.bind(this, function(self, action) {
|
||||
switch (action) {
|
||||
case 'reject':
|
||||
dispatchOp.leave_channels_async(Tp.ChannelGroupChangeReason.NONE,
|
||||
'', function(src, result) {
|
||||
src.leave_channels_finish(result)});
|
||||
break;
|
||||
case 'answer':
|
||||
dispatchOp.handle_with_time_async('', global.get_current_time(),
|
||||
function(src, result) {
|
||||
src.handle_with_time_finish(result)});
|
||||
break;
|
||||
}
|
||||
this.destroy();
|
||||
}));
|
||||
}
|
||||
@ -1166,16 +1177,22 @@ const FileTransferNotification = new Lang.Class({
|
||||
{ customContent: true });
|
||||
this.setResident(true);
|
||||
|
||||
this.addAction(_("Decline"), Lang.bind(this, function() {
|
||||
dispatchOp.leave_channels_async(Tp.ChannelGroupChangeReason.NONE, '', function(src, result) {
|
||||
src.leave_channels_finish(result);
|
||||
});
|
||||
this.destroy();
|
||||
}));
|
||||
this.addAction(_("Accept"), Lang.bind(this, function() {
|
||||
dispatchOp.handle_with_time_async('', global.get_current_time(), function(src, result) {
|
||||
src.handle_with_time_finish(result);
|
||||
});
|
||||
this.addButton('decline', _("Decline"));
|
||||
this.addButton('accept', _("Accept"));
|
||||
|
||||
this.connect('action-invoked', Lang.bind(this, function(self, action) {
|
||||
switch (action) {
|
||||
case 'decline':
|
||||
dispatchOp.leave_channels_async(Tp.ChannelGroupChangeReason.NONE,
|
||||
'', function(src, result) {
|
||||
src.leave_channels_finish(result)});
|
||||
break;
|
||||
case 'accept':
|
||||
dispatchOp.handle_with_time_async('', global.get_current_time(),
|
||||
function(src, result) {
|
||||
src.handle_with_time_finish(result)});
|
||||
break;
|
||||
}
|
||||
this.destroy();
|
||||
}));
|
||||
}
|
||||
@ -1223,20 +1240,27 @@ const SubscriptionRequestNotification = new Lang.Class({
|
||||
|
||||
this.addActor(layout);
|
||||
|
||||
this.addAction(_("Decline"), Lang.bind(this, function() {
|
||||
contact.remove_async(function(src, result) {
|
||||
src.remove_finish(result);
|
||||
});
|
||||
}));
|
||||
this.addAction(_("Accept"), Lang.bind(this, function() {
|
||||
// Authorize the contact and request to see his status as well
|
||||
contact.authorize_publication_async(function(src, result) {
|
||||
src.authorize_publication_finish(result);
|
||||
});
|
||||
this.addButton('decline', _("Decline"));
|
||||
this.addButton('accept', _("Accept"));
|
||||
|
||||
contact.request_subscription_async('', function(src, result) {
|
||||
src.request_subscription_finish(result);
|
||||
});
|
||||
this.connect('action-invoked', Lang.bind(this, function(self, action) {
|
||||
switch (action) {
|
||||
case 'decline':
|
||||
contact.remove_async(function(src, result) {
|
||||
src.remove_finish(result)});
|
||||
break;
|
||||
case 'accept':
|
||||
// Authorize the contact and request to see his status as well
|
||||
contact.authorize_publication_async(function(src, result) {
|
||||
src.authorize_publication_finish(result)});
|
||||
|
||||
contact.request_subscription_async('', function(src, result) {
|
||||
src.request_subscription_finish(result)});
|
||||
break;
|
||||
}
|
||||
|
||||
// rely on _subscriptionStatesChangedCb to destroy the
|
||||
// notification
|
||||
}));
|
||||
|
||||
this._changedId = contact.connect('subscription-states-changed',
|
||||
@ -1335,11 +1359,18 @@ const AccountNotification = new Lang.Class({
|
||||
|
||||
this._account = account;
|
||||
|
||||
this.addAction(_("View account"), Lang.bind(this, function() {
|
||||
let cmd = 'empathy-accounts --select-account=' +
|
||||
account.get_path_suffix();
|
||||
let app_info = Gio.app_info_create_from_commandline(cmd, null, 0);
|
||||
app_info.launch([], global.create_app_launch_context());
|
||||
this.addButton('view', _("View account"));
|
||||
|
||||
this.connect('action-invoked', Lang.bind(this, function(self, action) {
|
||||
switch (action) {
|
||||
case 'view':
|
||||
let cmd = 'empathy-accounts --select-account=' +
|
||||
account.get_path_suffix();
|
||||
let app_info = Gio.app_info_create_from_commandline(cmd, null, 0);
|
||||
app_info.launch([], global.create_app_launch_context());
|
||||
break;
|
||||
}
|
||||
this.destroy();
|
||||
}));
|
||||
|
||||
this._enabledId = account.connect('notify::enabled',
|
||||
|
@ -1,7 +1,6 @@
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
|
||||
const Clutter = imports.gi.Clutter;
|
||||
const GLib = imports.gi.GLib;
|
||||
const Signals = imports.signals;
|
||||
const Lang = imports.lang;
|
||||
const Meta = imports.gi.Meta;
|
||||
@ -577,8 +576,7 @@ const Dash = new Lang.Class({
|
||||
Lang.bind(this, function() {
|
||||
this._labelShowing = true;
|
||||
item.showLabel();
|
||||
this._showLabelTimeoutId = 0;
|
||||
return GLib.SOURCE_REMOVE;
|
||||
return false;
|
||||
}));
|
||||
if (this._resetHoverTimeoutId > 0) {
|
||||
Mainloop.source_remove(this._resetHoverTimeoutId);
|
||||
@ -594,8 +592,7 @@ const Dash = new Lang.Class({
|
||||
this._resetHoverTimeoutId = Mainloop.timeout_add(DASH_ITEM_HOVER_TIMEOUT,
|
||||
Lang.bind(this, function() {
|
||||
this._labelShowing = false;
|
||||
this._resetHoverTimeoutId = 0;
|
||||
return GLib.SOURCE_REMOVE;
|
||||
return false;
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
@ -113,7 +113,22 @@ const DateMenuButton = new Lang.Class({
|
||||
this.menu.connect('open-state-changed', Lang.bind(this, function(menu, isOpen) {
|
||||
if (isOpen) {
|
||||
let now = new Date();
|
||||
this._calendar.setDate(now);
|
||||
/* Passing true to setDate() forces events to be reloaded. We
|
||||
* want this behavior, because
|
||||
*
|
||||
* o It will cause activation of the calendar server which is
|
||||
* useful if it has crashed
|
||||
*
|
||||
* o It will cause the calendar server to reload events which
|
||||
* is useful if dynamic updates are not supported or not
|
||||
* properly working
|
||||
*
|
||||
* Since this only happens when the menu is opened, the cost
|
||||
* isn't very big.
|
||||
*/
|
||||
this._calendar.setDate(now, true);
|
||||
// No need to update this._eventList as ::selected-date-changed
|
||||
// signal will fire
|
||||
}
|
||||
}));
|
||||
|
||||
|
31
js/ui/dnd.js
31
js/ui/dnd.js
@ -106,10 +106,10 @@ const _Draggable = new Lang.Class({
|
||||
|
||||
_onButtonPress : function (actor, event) {
|
||||
if (event.get_button() != 1)
|
||||
return Clutter.EVENT_PROPAGATE;
|
||||
return false;
|
||||
|
||||
if (Tweener.getTweenCount(actor))
|
||||
return Clutter.EVENT_PROPAGATE;
|
||||
return false;
|
||||
|
||||
this._buttonDown = true;
|
||||
this._grabActor();
|
||||
@ -118,7 +118,7 @@ const _Draggable = new Lang.Class({
|
||||
this._dragStartX = stageX;
|
||||
this._dragStartY = stageY;
|
||||
|
||||
return Clutter.EVENT_PROPAGATE;
|
||||
return false;
|
||||
},
|
||||
|
||||
_grabActor: function() {
|
||||
@ -164,11 +164,11 @@ const _Draggable = new Lang.Class({
|
||||
} else if (this._dragActor != null && !this._animationInProgress) {
|
||||
// Drag must have been cancelled with Esc.
|
||||
this._dragComplete();
|
||||
return Clutter.EVENT_STOP;
|
||||
return true;
|
||||
} else {
|
||||
// Drag has never started.
|
||||
this._ungrabActor();
|
||||
return Clutter.EVENT_PROPAGATE;
|
||||
return false;
|
||||
}
|
||||
// We intercept MOTION event to figure out if the drag has started and to draw
|
||||
// this._dragActor under the pointer when dragging is in progress
|
||||
@ -184,11 +184,11 @@ const _Draggable = new Lang.Class({
|
||||
let symbol = event.get_key_symbol();
|
||||
if (symbol == Clutter.Escape) {
|
||||
this._cancelDrag(event.get_time());
|
||||
return Clutter.EVENT_STOP;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return Clutter.EVENT_PROPAGATE;
|
||||
return false;
|
||||
},
|
||||
|
||||
/**
|
||||
@ -236,7 +236,7 @@ const _Draggable = new Lang.Class({
|
||||
|
||||
if (this.actor._delegate && this.actor._delegate.getDragActor) {
|
||||
this._dragActor = this.actor._delegate.getDragActor();
|
||||
Main.uiGroup.add_child(this._dragActor);
|
||||
this._dragActor.reparent(Main.uiGroup);
|
||||
this._dragActor.raise_top();
|
||||
Shell.util_set_hidden_from_pick(this._dragActor, true);
|
||||
|
||||
@ -285,8 +285,7 @@ const _Draggable = new Lang.Class({
|
||||
this._dragOffsetX = actorStageX - this._dragStartX;
|
||||
this._dragOffsetY = actorStageY - this._dragStartY;
|
||||
|
||||
this._dragOrigParent.remove_actor(this._dragActor);
|
||||
Main.uiGroup.add_child(this._dragActor);
|
||||
this._dragActor.reparent(Main.uiGroup);
|
||||
this._dragActor.raise_top();
|
||||
Shell.util_set_hidden_from_pick(this._dragActor, true);
|
||||
}
|
||||
@ -346,7 +345,6 @@ const _Draggable = new Lang.Class({
|
||||
},
|
||||
|
||||
_updateDragHover : function () {
|
||||
this._updateHoverId = 0;
|
||||
let target = this._dragActor.get_stage().get_actor_at_pos(Clutter.PickMode.ALL,
|
||||
this._dragX, this._dragY);
|
||||
let dragEvent = {
|
||||
@ -362,7 +360,7 @@ const _Draggable = new Lang.Class({
|
||||
let result = motionFunc(dragEvent);
|
||||
if (result != DragMotionResult.CONTINUE) {
|
||||
global.screen.set_cursor(DRAG_CURSOR_MAP[result]);
|
||||
return GLib.SOURCE_REMOVE;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -380,18 +378,18 @@ const _Draggable = new Lang.Class({
|
||||
0);
|
||||
if (result != DragMotionResult.CONTINUE) {
|
||||
global.screen.set_cursor(DRAG_CURSOR_MAP[result]);
|
||||
return GLib.SOURCE_REMOVE;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
target = target.get_parent();
|
||||
}
|
||||
global.screen.set_cursor(Meta.Cursor.DND_IN_DRAG);
|
||||
return GLib.SOURCE_REMOVE;
|
||||
return false;
|
||||
},
|
||||
|
||||
_queueUpdateDragHover: function() {
|
||||
if (this._updateHoverId)
|
||||
return;
|
||||
GLib.source_remove(this._updateHoverId);
|
||||
|
||||
this._updateHoverId = GLib.idle_add(GLib.PRIORITY_DEFAULT,
|
||||
Lang.bind(this, this._updateDragHover));
|
||||
@ -557,8 +555,7 @@ const _Draggable = new Lang.Class({
|
||||
|
||||
_onAnimationComplete : function (dragActor, eventTime) {
|
||||
if (this._dragOrigParent) {
|
||||
Main.uiGroup.remove_child(this._dragActor);
|
||||
this._dragOrigParent.add_actor(this._dragActor);
|
||||
dragActor.reparent(this._dragOrigParent);
|
||||
dragActor.set_scale(this._dragOrigScale, this._dragOrigScale);
|
||||
dragActor.set_position(this._dragOrigX, this._dragOrigY);
|
||||
} else {
|
||||
|
@ -43,22 +43,20 @@ const _DIALOG_ICON_SIZE = 32;
|
||||
|
||||
const GSM_SESSION_MANAGER_LOGOUT_FORCE = 2;
|
||||
|
||||
const EndSessionDialogIface = '<node> \
|
||||
<interface name="org.gnome.SessionManager.EndSessionDialog"> \
|
||||
<method name="Open"> \
|
||||
<arg type="u" direction="in" /> \
|
||||
<arg type="u" direction="in" /> \
|
||||
<arg type="u" direction="in" /> \
|
||||
<arg type="ao" direction="in" /> \
|
||||
</method> \
|
||||
<method name="Close" /> \
|
||||
<signal name="ConfirmedLogout" /> \
|
||||
<signal name="ConfirmedReboot" /> \
|
||||
<signal name="ConfirmedShutdown" /> \
|
||||
<signal name="Canceled" /> \
|
||||
<signal name="Closed" /> \
|
||||
</interface> \
|
||||
</node>';
|
||||
const EndSessionDialogIface = <interface name="org.gnome.SessionManager.EndSessionDialog">
|
||||
<method name="Open">
|
||||
<arg type="u" direction="in" />
|
||||
<arg type="u" direction="in" />
|
||||
<arg type="u" direction="in" />
|
||||
<arg type="ao" direction="in" />
|
||||
</method>
|
||||
<method name="Close" />
|
||||
<signal name="ConfirmedLogout" />
|
||||
<signal name="ConfirmedReboot" />
|
||||
<signal name="ConfirmedShutdown" />
|
||||
<signal name="Canceled" />
|
||||
<signal name="Closed" />
|
||||
</interface>;
|
||||
|
||||
const logoutDialogContent = {
|
||||
subjectWithUser: C_("title", "Log Out %s"),
|
||||
@ -133,15 +131,13 @@ const DialogContent = {
|
||||
|
||||
const MAX_USERS_IN_SESSION_DIALOG = 5;
|
||||
|
||||
const LogindSessionIface = '<node> \
|
||||
<interface name="org.freedesktop.login1.Session"> \
|
||||
<property name="Id" type="s" access="read"/> \
|
||||
<property name="Remote" type="b" access="read"/> \
|
||||
<property name="Class" type="s" access="read"/> \
|
||||
<property name="Type" type="s" access="read"/> \
|
||||
<property name="State" type="s" access="read"/> \
|
||||
</interface> \
|
||||
</node>';
|
||||
const LogindSessionIface = <interface name='org.freedesktop.login1.Session'>
|
||||
<property name="Id" type="s" access="read"/>
|
||||
<property name="Remote" type="b" access="read"/>
|
||||
<property name="Class" type="s" access="read"/>
|
||||
<property name="Type" type="s" access="read"/>
|
||||
<property name="State" type="s" access="read"/>
|
||||
</interface>;
|
||||
|
||||
const LogindSession = Gio.DBusProxy.makeProxyWrapper(LogindSessionIface);
|
||||
|
||||
@ -249,9 +245,7 @@ const EndSessionDialog = new Lang.Class({
|
||||
this._subjectLabel = new St.Label({ style_class: 'end-session-dialog-subject' });
|
||||
|
||||
messageLayout.add(this._subjectLabel,
|
||||
{ x_fill: false,
|
||||
y_fill: false,
|
||||
x_align: St.Align.START,
|
||||
{ y_fill: false,
|
||||
y_align: St.Align.START });
|
||||
|
||||
this._descriptionLabel = new St.Label({ style_class: 'end-session-dialog-description' });
|
||||
@ -275,15 +269,13 @@ const EndSessionDialog = new Lang.Class({
|
||||
|
||||
this._applicationHeader = new St.Label({ style_class: 'end-session-dialog-list-header',
|
||||
text: _("Some applications are busy or have unsaved work.") });
|
||||
this._applicationList = new St.BoxLayout({ style_class: 'end-session-dialog-app-list',
|
||||
vertical: true });
|
||||
this._applicationList = new St.BoxLayout({ vertical: true });
|
||||
this._inhibitorSection.add_actor(this._applicationHeader);
|
||||
this._inhibitorSection.add_actor(this._applicationList);
|
||||
|
||||
this._sessionHeader = new St.Label({ style_class: 'end-session-dialog-list-header',
|
||||
text: _("Other users are logged in.") });
|
||||
this._sessionList = new St.BoxLayout({ style_class: 'end-session-dialog-session-list',
|
||||
vertical: true });
|
||||
this._sessionList = new St.BoxLayout({ vertical: true });
|
||||
this._inhibitorSection.add_actor(this._sessionHeader);
|
||||
this._inhibitorSection.add_actor(this._sessionList);
|
||||
|
||||
@ -411,15 +403,14 @@ const EndSessionDialog = new Lang.Class({
|
||||
this._secondsLeft = this._totalSecondsToStayOpen - secondsElapsed;
|
||||
if (this._secondsLeft > 0) {
|
||||
this._sync();
|
||||
return GLib.SOURCE_CONTINUE;
|
||||
return true;
|
||||
}
|
||||
|
||||
let dialogContent = DialogContent[this._type];
|
||||
let button = dialogContent.confirmButtons[dialogContent.confirmButtons.length - 1];
|
||||
this._confirm(button.signal);
|
||||
this._timerId = 0;
|
||||
|
||||
return GLib.SOURCE_REMOVE;
|
||||
return false;
|
||||
}));
|
||||
},
|
||||
|
||||
|
@ -76,11 +76,7 @@ function disableExtension(uuid) {
|
||||
theme.unload_stylesheet(extension.stylesheet.get_path());
|
||||
}
|
||||
|
||||
try {
|
||||
extension.stateObj.disable();
|
||||
} catch(e) {
|
||||
logExtensionError(uuid, e);
|
||||
}
|
||||
extension.stateObj.disable();
|
||||
|
||||
for (let i = 0; i < order.length; i++) {
|
||||
let uuid = order[i];
|
||||
@ -93,10 +89,8 @@ function disableExtension(uuid) {
|
||||
|
||||
extensionOrder.splice(orderIdx, 1);
|
||||
|
||||
if ( extension.state != ExtensionState.ERROR ) {
|
||||
extension.state = ExtensionState.DISABLED;
|
||||
_signals.emit('extension-state-changed', extension);
|
||||
}
|
||||
extension.state = ExtensionState.DISABLED;
|
||||
_signals.emit('extension-state-changed', extension);
|
||||
}
|
||||
|
||||
function enableExtension(uuid) {
|
||||
@ -123,15 +117,10 @@ function enableExtension(uuid) {
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
extension.stateObj.enable();
|
||||
extension.state = ExtensionState.ENABLED;
|
||||
_signals.emit('extension-state-changed', extension);
|
||||
return;
|
||||
} catch(e) {
|
||||
logExtensionError(uuid, e);
|
||||
return;
|
||||
}
|
||||
extension.stateObj.enable();
|
||||
|
||||
extension.state = ExtensionState.ENABLED;
|
||||
_signals.emit('extension-state-changed', extension);
|
||||
}
|
||||
|
||||
function logExtensionError(uuid, error) {
|
||||
@ -161,8 +150,7 @@ function loadExtension(extension) {
|
||||
} else {
|
||||
let enabled = enabledExtensions.indexOf(extension.uuid) != -1;
|
||||
if (enabled) {
|
||||
if (!initExtension(extension.uuid))
|
||||
return;
|
||||
initExtension(extension.uuid);
|
||||
if (extension.state == ExtensionState.DISABLED)
|
||||
enableExtension(extension.uuid);
|
||||
} else {
|
||||
@ -217,12 +205,7 @@ function initExtension(uuid) {
|
||||
extensionModule = extension.imports.extension;
|
||||
|
||||
if (extensionModule.init) {
|
||||
try {
|
||||
extensionState = extensionModule.init(extension);
|
||||
} catch(e) {
|
||||
logExtensionError(uuid, e);
|
||||
return false;
|
||||
}
|
||||
extensionState = extensionModule.init(extension);
|
||||
}
|
||||
|
||||
if (!extensionState)
|
||||
@ -231,7 +214,6 @@ function initExtension(uuid) {
|
||||
|
||||
extension.state = ExtensionState.DISABLED;
|
||||
_signals.emit('extension-loaded', uuid);
|
||||
return true;
|
||||
}
|
||||
|
||||
function getEnabledExtensions() {
|
||||
@ -253,7 +235,11 @@ function onEnabledExtensionsChanged() {
|
||||
newEnabledExtensions.filter(function(uuid) {
|
||||
return enabledExtensions.indexOf(uuid) == -1;
|
||||
}).forEach(function(uuid) {
|
||||
enableExtension(uuid);
|
||||
try {
|
||||
enableExtension(uuid);
|
||||
} catch(e) {
|
||||
logExtensionError(uuid, e);
|
||||
}
|
||||
});
|
||||
|
||||
// Find and disable all the newly disabled extensions: UUIDs found in the
|
||||
@ -261,7 +247,11 @@ function onEnabledExtensionsChanged() {
|
||||
enabledExtensions.filter(function(item) {
|
||||
return newEnabledExtensions.indexOf(item) == -1;
|
||||
}).forEach(function(uuid) {
|
||||
disableExtension(uuid);
|
||||
try {
|
||||
disableExtension(uuid);
|
||||
} catch(e) {
|
||||
logExtensionError(uuid, e);
|
||||
}
|
||||
});
|
||||
|
||||
enabledExtensions = newEnabledExtensions;
|
||||
@ -272,8 +262,12 @@ function _loadExtensions() {
|
||||
enabledExtensions = getEnabledExtensions();
|
||||
|
||||
let finder = new ExtensionUtils.ExtensionFinder();
|
||||
finder.connect('extension-found', function(finder, extension) {
|
||||
loadExtension(extension);
|
||||
finder.connect('extension-found', function(signals, extension) {
|
||||
try {
|
||||
loadExtension(extension);
|
||||
} catch(e) {
|
||||
logExtensionError(extension.uuid, e);
|
||||
}
|
||||
});
|
||||
finder.scanExtensions();
|
||||
}
|
||||
|
@ -280,7 +280,7 @@ const GrabHelper = new Lang.Class({
|
||||
if (type == Clutter.EventType.KEY_PRESS &&
|
||||
event.get_key_symbol() == Clutter.KEY_Escape) {
|
||||
this.ungrab({ isUser: true });
|
||||
return Clutter.EVENT_STOP;
|
||||
return true;
|
||||
}
|
||||
|
||||
let press = type == Clutter.EventType.BUTTON_PRESS;
|
||||
@ -289,14 +289,14 @@ const GrabHelper = new Lang.Class({
|
||||
|
||||
if (release && this._ignoreRelease) {
|
||||
this._ignoreRelease = false;
|
||||
return Clutter.EVENT_STOP;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (this._isWithinGrabbedActor(event.get_source()))
|
||||
return Clutter.EVENT_PROPAGATE;
|
||||
return false;
|
||||
|
||||
if (Main.keyboard.shouldTakeEvent(event))
|
||||
return Clutter.EVENT_PROPAGATE;
|
||||
return false;
|
||||
|
||||
if (button) {
|
||||
// If we have a press event, ignore the next event,
|
||||
@ -305,9 +305,9 @@ const GrabHelper = new Lang.Class({
|
||||
this._ignoreRelease = true;
|
||||
let i = this._actorInGrabStack(event.get_source()) + 1;
|
||||
this.ungrab({ actor: this._grabStack[i].actor, isUser: true });
|
||||
return Clutter.EVENT_STOP;
|
||||
return true;
|
||||
}
|
||||
|
||||
return Clutter.EVENT_STOP;
|
||||
return true;
|
||||
},
|
||||
});
|
||||
|
@ -32,7 +32,6 @@ const CandidateArea = new Lang.Class({
|
||||
let j = i;
|
||||
box.connect('button-release-event', Lang.bind(this, function(actor, event) {
|
||||
this.emit('candidate-clicked', j, event.get_button(), event.get_state());
|
||||
return Clutter.EVENT_PROPAGATE;
|
||||
}));
|
||||
}
|
||||
|
||||
|
@ -413,18 +413,15 @@ const IconGrid = new Lang.Class({
|
||||
},
|
||||
|
||||
removeAll: function() {
|
||||
this._items = [];
|
||||
this._grid.remove_all_children();
|
||||
},
|
||||
|
||||
destroyAll: function() {
|
||||
this._items = [];
|
||||
this._grid.destroy_all_children();
|
||||
},
|
||||
|
||||
addItem: function(item, index) {
|
||||
if (!item.icon instanceof BaseIcon)
|
||||
throw new Error('Only items with a BaseIcon icon property can be added to IconGrid');
|
||||
if (!item.icon || !item.icon instanceof BaseIcon) {
|
||||
log('Only items with a BaseIcon icon property can be added to IconGrid');
|
||||
return;
|
||||
}
|
||||
|
||||
this._items.push(item);
|
||||
if (index !== undefined)
|
||||
|
@ -23,29 +23,27 @@ const KEYBOARD_TYPE = 'keyboard-type';
|
||||
const A11Y_APPLICATIONS_SCHEMA = 'org.gnome.desktop.a11y.applications';
|
||||
const SHOW_KEYBOARD = 'screen-keyboard-enabled';
|
||||
|
||||
const CaribouKeyboardIface = '<node> \
|
||||
<interface name="org.gnome.Caribou.Keyboard"> \
|
||||
<method name="Show"> \
|
||||
<arg type="u" direction="in" /> \
|
||||
</method> \
|
||||
<method name="Hide"> \
|
||||
<arg type="u" direction="in" /> \
|
||||
</method> \
|
||||
<method name="SetCursorLocation"> \
|
||||
<arg type="i" direction="in" /> \
|
||||
<arg type="i" direction="in" /> \
|
||||
<arg type="i" direction="in" /> \
|
||||
<arg type="i" direction="in" /> \
|
||||
</method> \
|
||||
<method name="SetEntryLocation"> \
|
||||
<arg type="i" direction="in" /> \
|
||||
<arg type="i" direction="in" /> \
|
||||
<arg type="i" direction="in" /> \
|
||||
<arg type="i" direction="in" /> \
|
||||
</method> \
|
||||
<property name="Name" access="read" type="s" /> \
|
||||
</interface> \
|
||||
</node>';
|
||||
const CaribouKeyboardIface = <interface name='org.gnome.Caribou.Keyboard'>
|
||||
<method name='Show'>
|
||||
<arg type='u' direction='in' />
|
||||
</method>
|
||||
<method name='Hide'>
|
||||
<arg type='u' direction='in' />
|
||||
</method>
|
||||
<method name='SetCursorLocation'>
|
||||
<arg type='i' direction='in' />
|
||||
<arg type='i' direction='in' />
|
||||
<arg type='i' direction='in' />
|
||||
<arg type='i' direction='in' />
|
||||
</method>
|
||||
<method name='SetEntryLocation'>
|
||||
<arg type='i' direction='in' />
|
||||
<arg type='i' direction='in' />
|
||||
<arg type='i' direction='in' />
|
||||
<arg type='i' direction='in' />
|
||||
</method>
|
||||
<property name='Name' access='read' type='s' />
|
||||
</interface>;
|
||||
|
||||
const Key = new Lang.Class({
|
||||
Name: 'Key',
|
||||
@ -82,16 +80,8 @@ const Key = new Lang.Class({
|
||||
style_class: 'keyboard-key' });
|
||||
|
||||
button.key_width = this._key.width;
|
||||
button.connect('button-press-event', Lang.bind(this,
|
||||
function () {
|
||||
this._key.press();
|
||||
return Clutter.EVENT_PROPAGATE;
|
||||
}));
|
||||
button.connect('button-release-event', Lang.bind(this,
|
||||
function () {
|
||||
this._key.release();
|
||||
return Clutter.EVENT_PROPAGATE;
|
||||
}));
|
||||
button.connect('button-press-event', Lang.bind(this, function () { this._key.press(); }));
|
||||
button.connect('button-release-event', Lang.bind(this, function () { this._key.release(); }));
|
||||
|
||||
return button;
|
||||
},
|
||||
@ -114,16 +104,8 @@ const Key = new Lang.Class({
|
||||
let label = this._getUnichar(extended_key);
|
||||
let key = new St.Button({ label: label, style_class: 'keyboard-key' });
|
||||
key.extended_key = extended_key;
|
||||
key.connect('button-press-event', Lang.bind(this,
|
||||
function () {
|
||||
extended_key.press();
|
||||
return Clutter.EVENT_PROPAGATE;
|
||||
}));
|
||||
key.connect('button-release-event', Lang.bind(this,
|
||||
function () {
|
||||
extended_key.release();
|
||||
return Clutter.EVENT_PROPAGATE;
|
||||
}));
|
||||
key.connect('button-press-event', Lang.bind(this, function () { extended_key.press(); }));
|
||||
key.connect('button-release-event', Lang.bind(this, function () { extended_key.release(); }));
|
||||
this._extended_keyboard.add(key);
|
||||
}
|
||||
this._boxPointer.bin.add_actor(this._extended_keyboard);
|
||||
@ -268,10 +250,7 @@ const Keyboard = new Lang.Class({
|
||||
|
||||
if (!this._showIdleId)
|
||||
this._showIdleId = GLib.idle_add(GLib.PRIORITY_DEFAULT_IDLE,
|
||||
Lang.bind(this, function() {
|
||||
this.Show(time);
|
||||
return GLib.SOURCE_REMOVE;
|
||||
}));
|
||||
Lang.bind(this, function() { this.Show(time); }));
|
||||
},
|
||||
|
||||
_createLayersForGroup: function (gname) {
|
||||
@ -313,7 +292,7 @@ const Keyboard = new Lang.Class({
|
||||
else if (release && this._capturedPress)
|
||||
this._hideSubkeys();
|
||||
|
||||
return Clutter.EVENT_STOP;
|
||||
return true;
|
||||
},
|
||||
|
||||
_addRows : function (keys, layout) {
|
||||
@ -457,6 +436,7 @@ const Keyboard = new Lang.Class({
|
||||
_createSource: function () {
|
||||
if (this._source == null) {
|
||||
this._source = new KeyboardSource(this);
|
||||
this._source.setTransient(true);
|
||||
Main.messageTray.add(this._source);
|
||||
}
|
||||
},
|
||||
@ -498,7 +478,6 @@ const Keyboard = new Lang.Class({
|
||||
Lang.bind(this, function() {
|
||||
this._clearKeyboardRestTimer();
|
||||
this._show(monitor);
|
||||
return GLib.SOURCE_REMOVE;
|
||||
}));
|
||||
},
|
||||
|
||||
@ -524,7 +503,6 @@ const Keyboard = new Lang.Class({
|
||||
Lang.bind(this, function() {
|
||||
this._clearKeyboardRestTimer();
|
||||
this._hide();
|
||||
return GLib.SOURCE_REMOVE;
|
||||
}));
|
||||
},
|
||||
|
||||
|
@ -251,7 +251,7 @@ const LayoutManager = new Lang.Class({
|
||||
|
||||
this._inOverview = true;
|
||||
this._updateVisibility();
|
||||
this._updateRegions();
|
||||
this._queueUpdateRegions();
|
||||
},
|
||||
|
||||
hideOverview: function() {
|
||||
@ -352,26 +352,26 @@ const LayoutManager = new Lang.Class({
|
||||
this.emit('hot-corners-changed');
|
||||
},
|
||||
|
||||
_addBackgroundMenu: function(bgManager) {
|
||||
BackgroundMenu.addBackgroundMenu(bgManager.background.actor, this);
|
||||
},
|
||||
|
||||
_createBackgroundManager: function(monitorIndex) {
|
||||
_createBackground: function(monitorIndex) {
|
||||
let bgManager = new Background.BackgroundManager({ container: this._backgroundGroup,
|
||||
layoutManager: this,
|
||||
monitorIndex: monitorIndex });
|
||||
BackgroundMenu.addBackgroundMenu(bgManager.background.actor);
|
||||
|
||||
bgManager.connect('changed', Lang.bind(this, this._addBackgroundMenu));
|
||||
this._addBackgroundMenu(bgManager);
|
||||
bgManager.connect('changed', Lang.bind(this, function() {
|
||||
BackgroundMenu.addBackgroundMenu(bgManager.background.actor);
|
||||
}));
|
||||
|
||||
return bgManager;
|
||||
this._bgManagers[monitorIndex] = bgManager;
|
||||
|
||||
return bgManager.background;
|
||||
},
|
||||
|
||||
_showSecondaryBackgrounds: function() {
|
||||
_createSecondaryBackgrounds: function() {
|
||||
for (let i = 0; i < this.monitors.length; i++) {
|
||||
if (i != this.primaryIndex) {
|
||||
let background = this._bgManagers[i].background;
|
||||
background.actor.show();
|
||||
let background = this._createBackground(i);
|
||||
|
||||
background.actor.opacity = 0;
|
||||
Tweener.addTween(background.actor,
|
||||
{ opacity: 255,
|
||||
@ -381,6 +381,10 @@ const LayoutManager = new Lang.Class({
|
||||
}
|
||||
},
|
||||
|
||||
_createPrimaryBackground: function() {
|
||||
this._createBackground(this.primaryIndex);
|
||||
},
|
||||
|
||||
_updateBackgrounds: function() {
|
||||
let i;
|
||||
for (i = 0; i < this._bgManagers.length; i++)
|
||||
@ -391,12 +395,11 @@ const LayoutManager = new Lang.Class({
|
||||
if (Main.sessionMode.isGreeter)
|
||||
return;
|
||||
|
||||
for (let i = 0; i < this.monitors.length; i++) {
|
||||
let bgManager = this._createBackgroundManager(i);
|
||||
this._bgManagers.push(bgManager);
|
||||
if (this._startingUp)
|
||||
return;
|
||||
|
||||
if (i != this.primaryIndex && this._startingUp)
|
||||
bgManager.background.actor.hide();
|
||||
for (let i = 0; i < this.monitors.length; i++) {
|
||||
this._createBackground(i);
|
||||
}
|
||||
},
|
||||
|
||||
@ -592,7 +595,7 @@ const LayoutManager = new Lang.Class({
|
||||
if (Main.sessionMode.isGreeter) {
|
||||
this.panelBox.translation_y = -this.panelBox.height;
|
||||
} else {
|
||||
this._updateBackgrounds();
|
||||
this._createPrimaryBackground();
|
||||
|
||||
// We need to force an update of the regions now before we scale
|
||||
// the UI group to get the coorect allocation for the struts.
|
||||
@ -607,7 +610,7 @@ const LayoutManager = new Lang.Class({
|
||||
|
||||
this.uiGroup.set_pivot_point(x / global.screen_width,
|
||||
y / global.screen_height);
|
||||
this.uiGroup.scale_x = this.uiGroup.scale_y = 0.75;
|
||||
this.uiGroup.scale_x = this.uiGroup.scale_y = 0.5;
|
||||
this.uiGroup.opacity = 0;
|
||||
global.window_group.set_clip(monitor.x, monitor.y, monitor.width, monitor.height);
|
||||
}
|
||||
@ -622,7 +625,7 @@ const LayoutManager = new Lang.Class({
|
||||
// when the system is bogged down
|
||||
GLib.idle_add(GLib.PRIORITY_LOW, Lang.bind(this, function() {
|
||||
this._startupAnimation();
|
||||
return GLib.SOURCE_REMOVE;
|
||||
return false;
|
||||
}));
|
||||
},
|
||||
|
||||
@ -670,7 +673,7 @@ const LayoutManager = new Lang.Class({
|
||||
this.keyboardBox.show();
|
||||
|
||||
if (!Main.sessionMode.isGreeter) {
|
||||
this._showSecondaryBackgrounds();
|
||||
this._createSecondaryBackgrounds();
|
||||
global.window_group.remove_clip();
|
||||
}
|
||||
|
||||
@ -1039,7 +1042,7 @@ const LayoutManager = new Lang.Class({
|
||||
workspace.set_builtin_struts(struts);
|
||||
}
|
||||
|
||||
return GLib.SOURCE_REMOVE;
|
||||
return false;
|
||||
}
|
||||
});
|
||||
Signals.addSignalMethods(LayoutManager.prototype);
|
||||
@ -1226,20 +1229,20 @@ const HotCorner = new Lang.Class({
|
||||
this._entered = true;
|
||||
this._toggleOverview();
|
||||
}
|
||||
return Clutter.EVENT_PROPAGATE;
|
||||
return false;
|
||||
},
|
||||
|
||||
_onCornerLeft : function(actor, event) {
|
||||
if (event.get_related() != this.actor)
|
||||
this._entered = false;
|
||||
// Consume event, otherwise this will confuse onEnvironsLeft
|
||||
return Clutter.EVENT_STOP;
|
||||
return true;
|
||||
},
|
||||
|
||||
_onEnvironsLeft : function(actor, event) {
|
||||
if (event.get_related() != this._corner)
|
||||
this._entered = false;
|
||||
return Clutter.EVENT_PROPAGATE;
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -109,7 +109,6 @@ const AutoComplete = new Lang.Class({
|
||||
}
|
||||
this._lastTabTime = currTime;
|
||||
}
|
||||
return Clutter.EVENT_PROPAGATE;
|
||||
},
|
||||
|
||||
// Insert characters of text not already included in head at cursor position. i.e., if text="abc" and head="a",
|
||||
@ -559,7 +558,7 @@ const Inspector = new Lang.Class({
|
||||
_onKeyPressEvent: function (actor, event) {
|
||||
if (event.get_key_symbol() == Clutter.Escape)
|
||||
this._close();
|
||||
return Clutter.EVENT_STOP;
|
||||
return true;
|
||||
},
|
||||
|
||||
_onButtonPressEvent: function (actor, event) {
|
||||
@ -568,7 +567,7 @@ const Inspector = new Lang.Class({
|
||||
this.emit('target', this._target, stageX, stageY);
|
||||
}
|
||||
this._close();
|
||||
return Clutter.EVENT_STOP;
|
||||
return true;
|
||||
},
|
||||
|
||||
_onScrollEvent: function (actor, event) {
|
||||
@ -602,12 +601,12 @@ const Inspector = new Lang.Class({
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return Clutter.EVENT_STOP;
|
||||
return true;
|
||||
},
|
||||
|
||||
_onMotionEvent: function (actor, event) {
|
||||
this._update(event);
|
||||
return Clutter.EVENT_STOP;
|
||||
return true;
|
||||
},
|
||||
|
||||
_update: function(event) {
|
||||
@ -630,6 +629,55 @@ const Inspector = new Lang.Class({
|
||||
|
||||
Signals.addSignalMethods(Inspector.prototype);
|
||||
|
||||
const Memory = new Lang.Class({
|
||||
Name: 'Memory',
|
||||
|
||||
_init: function() {
|
||||
this.actor = new St.BoxLayout({ vertical: true });
|
||||
this._glibc_uordblks = new St.Label();
|
||||
this.actor.add(this._glibc_uordblks);
|
||||
|
||||
this._js_bytes = new St.Label();
|
||||
this.actor.add(this._js_bytes);
|
||||
|
||||
this._gjs_boxed = new St.Label();
|
||||
this.actor.add(this._gjs_boxed);
|
||||
|
||||
this._gjs_gobject = new St.Label();
|
||||
this.actor.add(this._gjs_gobject);
|
||||
|
||||
this._gjs_function = new St.Label();
|
||||
this.actor.add(this._gjs_function);
|
||||
|
||||
this._gjs_closure = new St.Label();
|
||||
this.actor.add(this._gjs_closure);
|
||||
|
||||
this._last_gc_seconds_ago = new St.Label();
|
||||
this.actor.add(this._last_gc_seconds_ago);
|
||||
|
||||
this._gcbutton = new St.Button({ label: 'Full GC',
|
||||
style_class: 'lg-obj-inspector-button' });
|
||||
this._gcbutton.connect('clicked', Lang.bind(this, function () { System.gc(); this._renderText(); }));
|
||||
this.actor.add(this._gcbutton, { x_align: St.Align.START,
|
||||
x_fill: false });
|
||||
|
||||
this.actor.connect('notify::mapped', Lang.bind(this, this._renderText));
|
||||
},
|
||||
|
||||
_renderText: function() {
|
||||
if (!this.actor.mapped)
|
||||
return;
|
||||
let memInfo = global.get_memory_info();
|
||||
this._glibc_uordblks.text = 'glibc_uordblks: ' + memInfo.glibc_uordblks;
|
||||
this._js_bytes.text = 'js bytes: ' + memInfo.js_bytes;
|
||||
this._gjs_boxed.text = 'gjs_boxed: ' + memInfo.gjs_boxed;
|
||||
this._gjs_gobject.text = 'gjs_gobject: ' + memInfo.gjs_gobject;
|
||||
this._gjs_function.text = 'gjs_function: ' + memInfo.gjs_function;
|
||||
this._gjs_closure.text = 'gjs_closure: ' + memInfo.gjs_closure;
|
||||
this._last_gc_seconds_ago.text = 'last_gc_seconds_ago: ' + memInfo.last_gc_seconds_ago;
|
||||
}
|
||||
});
|
||||
|
||||
const Extensions = new Lang.Class({
|
||||
Name: 'Extensions',
|
||||
|
||||
@ -829,22 +877,7 @@ const LookingGlass = new Lang.Class({
|
||||
global.stage.set_key_focus(this._entry);
|
||||
}));
|
||||
this.actor.hide();
|
||||
return Clutter.EVENT_STOP;
|
||||
}));
|
||||
|
||||
let gcIcon = new St.Icon({ icon_name: 'gnome-fs-trash-full',
|
||||
icon_size: 24 });
|
||||
toolbar.add_actor(gcIcon);
|
||||
gcIcon.reactive = true;
|
||||
gcIcon.connect('button-press-event', Lang.bind(this, function () {
|
||||
gcIcon.icon_name = 'gnome-fs-trash-empty';
|
||||
System.gc();
|
||||
this._timeoutId = Mainloop.timeout_add(500, Lang.bind(this, function () {
|
||||
gcIcon.icon_name = 'gnome-fs-trash-full';
|
||||
Mainloop.source_remove(this._timeoutId);
|
||||
return GLib.SOURCE_REMOVE;
|
||||
}));
|
||||
return Clutter.EVENT_PROPAGATE;
|
||||
return true;
|
||||
}));
|
||||
|
||||
let notebook = new Notebook();
|
||||
@ -874,6 +907,9 @@ const LookingGlass = new Lang.Class({
|
||||
this._windowList = new WindowList(this);
|
||||
notebook.appendPage('Windows', this._windowList.actor);
|
||||
|
||||
this._memory = new Memory();
|
||||
notebook.appendPage('Memory', this._memory.actor);
|
||||
|
||||
this._extensions = new Extensions(this);
|
||||
notebook.appendPage('Extensions', this._extensions.actor);
|
||||
|
||||
@ -1066,7 +1102,7 @@ const LookingGlass = new Lang.Class({
|
||||
} else {
|
||||
this.close();
|
||||
}
|
||||
return Clutter.EVENT_STOP;
|
||||
return true;
|
||||
}
|
||||
// Ctrl+PgUp and Ctrl+PgDown switches tabs in the notebook view
|
||||
if (modifierState & Clutter.ModifierType.CONTROL_MASK) {
|
||||
@ -1076,7 +1112,7 @@ const LookingGlass = new Lang.Class({
|
||||
this._notebook.nextTab();
|
||||
}
|
||||
}
|
||||
return Clutter.EVENT_PROPAGATE;
|
||||
return false;
|
||||
},
|
||||
|
||||
open : function() {
|
||||
|
@ -9,89 +9,85 @@ const ZOOM_SERVICE_PATH = '/org/gnome/Magnifier/ZoomRegion';
|
||||
|
||||
// Subset of gnome-mag's Magnifier dbus interface -- to be expanded. See:
|
||||
// http://git.gnome.org/browse/gnome-mag/tree/xml/...Magnifier.xml
|
||||
const MagnifierIface = '<node> \
|
||||
<interface name="org.gnome.Magnifier"> \
|
||||
<method name="setActive"> \
|
||||
<arg type="b" direction="in" /> \
|
||||
</method> \
|
||||
<method name="isActive"> \
|
||||
<arg type="b" direction="out" /> \
|
||||
</method> \
|
||||
<method name="showCursor" /> \
|
||||
<method name="hideCursor" /> \
|
||||
<method name="createZoomRegion"> \
|
||||
<arg type="d" direction="in" /> \
|
||||
<arg type="d" direction="in" /> \
|
||||
<arg type="ai" direction="in" /> \
|
||||
<arg type="ai" direction="in" /> \
|
||||
<arg type="o" direction="out" /> \
|
||||
</method> \
|
||||
<method name="addZoomRegion"> \
|
||||
<arg type="o" direction="in" /> \
|
||||
<arg type="b" direction="out" /> \
|
||||
</method> \
|
||||
<method name="getZoomRegions"> \
|
||||
<arg type="ao" direction="out" /> \
|
||||
</method> \
|
||||
<method name="clearAllZoomRegions" /> \
|
||||
<method name="fullScreenCapable"> \
|
||||
<arg type="b" direction="out" /> \
|
||||
</method> \
|
||||
<method name="setCrosswireSize"> \
|
||||
<arg type="i" direction="in" /> \
|
||||
</method> \
|
||||
<method name="getCrosswireSize"> \
|
||||
<arg type="i" direction="out" /> \
|
||||
</method> \
|
||||
<method name="setCrosswireLength"> \
|
||||
<arg type="i" direction="in" /> \
|
||||
</method> \
|
||||
<method name="getCrosswireLength"> \
|
||||
<arg type="i" direction="out" /> \
|
||||
</method> \
|
||||
<method name="setCrosswireClip"> \
|
||||
<arg type="b" direction="in" /> \
|
||||
</method> \
|
||||
<method name="getCrosswireClip"> \
|
||||
<arg type="b" direction="out" /> \
|
||||
</method> \
|
||||
<method name="setCrosswireColor"> \
|
||||
<arg type="u" direction="in" /> \
|
||||
</method> \
|
||||
<method name="getCrosswireColor"> \
|
||||
<arg type="u" direction="out" /> \
|
||||
</method> \
|
||||
</interface> \
|
||||
</node>';
|
||||
const MagnifierIface = <interface name="org.gnome.Magnifier">
|
||||
<method name="setActive">
|
||||
<arg type="b" direction="in" />
|
||||
</method>
|
||||
<method name="isActive">
|
||||
<arg type="b" direction="out" />
|
||||
</method>
|
||||
<method name="showCursor" />
|
||||
<method name="hideCursor" />
|
||||
<method name="createZoomRegion">
|
||||
<arg type="d" direction="in" />
|
||||
<arg type="d" direction="in" />
|
||||
<arg type="ai" direction="in" />
|
||||
<arg type="ai" direction="in" />
|
||||
<arg type="o" direction="out" />
|
||||
</method>
|
||||
<method name="addZoomRegion">
|
||||
<arg type="o" direction="in" />
|
||||
<arg type="b" direction="out" />
|
||||
</method>
|
||||
<method name="getZoomRegions">
|
||||
<arg type="ao" direction="out" />
|
||||
</method>
|
||||
<method name="clearAllZoomRegions" />
|
||||
<method name="fullScreenCapable">
|
||||
<arg type="b" direction="out" />
|
||||
</method>
|
||||
<method name="setCrosswireSize">
|
||||
<arg type="i" direction="in" />
|
||||
</method>
|
||||
<method name="getCrosswireSize">
|
||||
<arg type="i" direction="out" />
|
||||
</method>
|
||||
<method name="setCrosswireLength">
|
||||
<arg type="i" direction="in" />
|
||||
</method>
|
||||
<method name="getCrosswireLength">
|
||||
<arg type="i" direction="out" />
|
||||
</method>
|
||||
<method name="setCrosswireClip">
|
||||
<arg type="b" direction="in" />
|
||||
</method>
|
||||
<method name="getCrosswireClip">
|
||||
<arg type="b" direction="out" />
|
||||
</method>
|
||||
<method name="setCrosswireColor">
|
||||
<arg type="u" direction="in" />
|
||||
</method>
|
||||
<method name="getCrosswireColor">
|
||||
<arg type="u" direction="out" />
|
||||
</method>
|
||||
</interface>;
|
||||
|
||||
// Subset of gnome-mag's ZoomRegion dbus interface -- to be expanded. See:
|
||||
// http://git.gnome.org/browse/gnome-mag/tree/xml/...ZoomRegion.xml
|
||||
const ZoomRegionIface = '<node> \
|
||||
<interface name="org.gnome.Magnifier.ZoomRegion"> \
|
||||
<method name="setMagFactor"> \
|
||||
<arg type="d" direction="in" /> \
|
||||
<arg type="d" direction="in" /> \
|
||||
</method> \
|
||||
<method name="getMagFactor"> \
|
||||
<arg type="d" direction="out" /> \
|
||||
<arg type="d" direction="out" /> \
|
||||
</method> \
|
||||
<method name="setRoi"> \
|
||||
<arg type="ai" direction="in" /> \
|
||||
</method> \
|
||||
<method name="getRoi"> \
|
||||
<arg type="ai" direction="out" /> \
|
||||
</method> \
|
||||
<method name="shiftContentsTo"> \
|
||||
<arg type="i" direction="in" /> \
|
||||
<arg type="i" direction="in" /> \
|
||||
<arg type="b" direction="out" /> \
|
||||
</method> \
|
||||
<method name="moveResize"> \
|
||||
<arg type="ai" direction="in" /> \
|
||||
</method> \
|
||||
</interface> \
|
||||
</node>';
|
||||
const ZoomRegionIface = <interface name="org.gnome.Magnifier.ZoomRegion">
|
||||
<method name="setMagFactor">
|
||||
<arg type="d" direction="in" />
|
||||
<arg type="d" direction="in" />
|
||||
</method>
|
||||
<method name="getMagFactor">
|
||||
<arg type="d" direction="out" />
|
||||
<arg type="d" direction="out" />
|
||||
</method>
|
||||
<method name="setRoi">
|
||||
<arg type="ai" direction="in" />
|
||||
</method>
|
||||
<method name="getRoi">
|
||||
<arg type="ai" direction="out" />
|
||||
</method>
|
||||
<method name="shiftContentsTo">
|
||||
<arg type="i" direction="in" />
|
||||
<arg type="i" direction="in" />
|
||||
<arg type="b" direction="out" />
|
||||
</method>
|
||||
<method name="moveResize">
|
||||
<arg type="ai" direction="in" />
|
||||
</method>
|
||||
</interface>;
|
||||
|
||||
// For making unique ZoomRegion DBus proxy object paths of the form:
|
||||
// '/org/gnome/Magnifier/ZoomRegion/zoomer0',
|
||||
|
@ -112,6 +112,11 @@ function start() {
|
||||
Gio.DesktopAppInfo.set_desktop_env('GNOME');
|
||||
|
||||
sessionMode = new SessionMode.SessionMode();
|
||||
sessionMode.connect('sessions-loaded', _sessionsLoaded);
|
||||
sessionMode.init();
|
||||
}
|
||||
|
||||
function _sessionsLoaded() {
|
||||
sessionMode.connect('updated', _sessionUpdated);
|
||||
_initializePrefs();
|
||||
_initializeUI();
|
||||
@ -609,7 +614,7 @@ function queueDeferredWork(workId) {
|
||||
_deferredTimeoutId = Mainloop.timeout_add_seconds(DEFERRED_TIMEOUT_SECONDS, function () {
|
||||
_runAllDeferredWork();
|
||||
_deferredTimeoutId = 0;
|
||||
return GLib.SOURCE_REMOVE;
|
||||
return false;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -76,7 +76,7 @@ const Urgency = {
|
||||
NORMAL: 1,
|
||||
HIGH: 2,
|
||||
CRITICAL: 3
|
||||
};
|
||||
}
|
||||
|
||||
function _fixMarkup(text, allowMarkup) {
|
||||
if (allowMarkup) {
|
||||
@ -187,7 +187,7 @@ const URLHighlighter = new Lang.Class({
|
||||
// The MessageTray doesn't actually hide us, so
|
||||
// we need to check for paint opacities as well.
|
||||
if (!actor.visible || actor.get_paint_opacity() == 0)
|
||||
return Clutter.EVENT_PROPAGATE;
|
||||
return false;
|
||||
|
||||
// Keep Notification.actor from seeing this and taking
|
||||
// a pointer grab, which would block our button-release-event
|
||||
@ -196,7 +196,7 @@ const URLHighlighter = new Lang.Class({
|
||||
}));
|
||||
this.actor.connect('button-release-event', Lang.bind(this, function (actor, event) {
|
||||
if (!actor.visible || actor.get_paint_opacity() == 0)
|
||||
return Clutter.EVENT_PROPAGATE;
|
||||
return false;
|
||||
|
||||
let urlId = this._findUrlAtPos(event);
|
||||
if (urlId != -1) {
|
||||
@ -205,13 +205,13 @@ const URLHighlighter = new Lang.Class({
|
||||
url = 'http://' + url;
|
||||
|
||||
Gio.app_info_launch_default_for_uri(url, global.create_app_launch_context());
|
||||
return Clutter.EVENT_STOP;
|
||||
return true;
|
||||
}
|
||||
return Clutter.EVENT_PROPAGATE;
|
||||
return false;
|
||||
}));
|
||||
this.actor.connect('motion-event', Lang.bind(this, function(actor, event) {
|
||||
if (!actor.visible || actor.get_paint_opacity() == 0)
|
||||
return Clutter.EVENT_PROPAGATE;
|
||||
return false;
|
||||
|
||||
let urlId = this._findUrlAtPos(event);
|
||||
if (urlId != -1 && !this._cursorChanged) {
|
||||
@ -221,17 +221,16 @@ const URLHighlighter = new Lang.Class({
|
||||
global.screen.set_cursor(Meta.Cursor.DEFAULT);
|
||||
this._cursorChanged = false;
|
||||
}
|
||||
return Clutter.EVENT_PROPAGATE;
|
||||
return false;
|
||||
}));
|
||||
this.actor.connect('leave-event', Lang.bind(this, function() {
|
||||
if (!this.actor.visible || this.actor.get_paint_opacity() == 0)
|
||||
return Clutter.EVENT_PROPAGATE;
|
||||
return;
|
||||
|
||||
if (this._cursorChanged) {
|
||||
this._cursorChanged = false;
|
||||
global.screen.set_cursor(Meta.Cursor.DEFAULT);
|
||||
}
|
||||
return Clutter.EVENT_PROPAGATE;
|
||||
}));
|
||||
},
|
||||
|
||||
@ -281,6 +280,10 @@ const URLHighlighter = new Lang.Class({
|
||||
}
|
||||
});
|
||||
|
||||
function strHasSuffix(string, suffix) {
|
||||
return string.substr(-suffix.length) == suffix;
|
||||
}
|
||||
|
||||
// NotificationPolicy:
|
||||
// An object that holds all bits of configurable policy related to a notification
|
||||
// source, such as whether to play sound or honour the critical bit.
|
||||
@ -307,126 +310,6 @@ const NotificationPolicy = new Lang.Class({
|
||||
});
|
||||
Signals.addSignalMethods(NotificationPolicy.prototype);
|
||||
|
||||
const NotificationGenericPolicy = new Lang.Class({
|
||||
Name: 'NotificationGenericPolicy',
|
||||
Extends: NotificationPolicy,
|
||||
|
||||
_init: function() {
|
||||
// Don't chain to parent, it would try setting
|
||||
// our properties to the defaults
|
||||
|
||||
this.id = 'generic';
|
||||
|
||||
this._masterSettings = new Gio.Settings({ schema: 'org.gnome.desktop.notifications' });
|
||||
this._masterSettings.connect('changed', Lang.bind(this, this._changed));
|
||||
},
|
||||
|
||||
store: function() { },
|
||||
|
||||
destroy: function() {
|
||||
this._masterSettings.run_dispose();
|
||||
},
|
||||
|
||||
_changed: function(settings, key) {
|
||||
this.emit('policy-changed', key);
|
||||
},
|
||||
|
||||
get enable() {
|
||||
return true;
|
||||
},
|
||||
|
||||
get enableSound() {
|
||||
return true;
|
||||
},
|
||||
|
||||
get showBanners() {
|
||||
return this._masterSettings.get_boolean('show-banners');
|
||||
},
|
||||
|
||||
get forceExpanded() {
|
||||
return false;
|
||||
},
|
||||
|
||||
get showInLockScreen() {
|
||||
return this._masterSettings.get_boolean('show-in-lock-screen');
|
||||
},
|
||||
|
||||
get detailsInLockScreen() {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
const NotificationApplicationPolicy = new Lang.Class({
|
||||
Name: 'NotificationApplicationPolicy',
|
||||
Extends: NotificationPolicy,
|
||||
|
||||
_init: function(id) {
|
||||
// Don't chain to parent, it would try setting
|
||||
// our properties to the defaults
|
||||
|
||||
this.id = id;
|
||||
this._canonicalId = this._canonicalizeId(id);
|
||||
|
||||
this._masterSettings = new Gio.Settings({ schema: 'org.gnome.desktop.notifications' });
|
||||
this._settings = new Gio.Settings({ schema: 'org.gnome.desktop.notifications.application',
|
||||
path: '/org/gnome/desktop/notifications/application/' + this._canonicalId + '/' });
|
||||
|
||||
this._masterSettings.connect('changed', Lang.bind(this, this._changed));
|
||||
this._settings.connect('changed', Lang.bind(this, this._changed));
|
||||
},
|
||||
|
||||
store: function() {
|
||||
this._settings.set_string('application-id', this.id + '.desktop');
|
||||
|
||||
let apps = this._masterSettings.get_strv('application-children');
|
||||
if (apps.indexOf(this._canonicalId) < 0) {
|
||||
apps.push(this._canonicalId);
|
||||
this._masterSettings.set_strv('application-children', apps);
|
||||
}
|
||||
},
|
||||
|
||||
destroy: function() {
|
||||
this._masterSettings.run_dispose();
|
||||
this._settings.run_dispose();
|
||||
},
|
||||
|
||||
_changed: function(settings, key) {
|
||||
this.emit('policy-changed', key);
|
||||
},
|
||||
|
||||
_canonicalizeId: function(id) {
|
||||
// Keys are restricted to lowercase alphanumeric characters and dash,
|
||||
// and two dashes cannot be in succession
|
||||
return id.toLowerCase().replace(/[^a-z0-9\-]/g, '-').replace(/--+/g, '-');
|
||||
},
|
||||
|
||||
get enable() {
|
||||
return this._settings.get_boolean('enable');
|
||||
},
|
||||
|
||||
get enableSound() {
|
||||
return this._settings.get_boolean('enable-sound-alerts');
|
||||
},
|
||||
|
||||
get showBanners() {
|
||||
return this._masterSettings.get_boolean('show-banners') &&
|
||||
this._settings.get_boolean('show-banners');
|
||||
},
|
||||
|
||||
get forceExpanded() {
|
||||
return this._settings.get_boolean('force-expanded');
|
||||
},
|
||||
|
||||
get showInLockScreen() {
|
||||
return this._masterSettings.get_boolean('show-in-lock-screen') &&
|
||||
this._settings.get_boolean('show-in-lock-screen');
|
||||
},
|
||||
|
||||
get detailsInLockScreen() {
|
||||
return this._settings.get_boolean('details-in-lock-screen');
|
||||
}
|
||||
});
|
||||
|
||||
// Notification:
|
||||
// @source: the notification's Source
|
||||
// @title: the title
|
||||
@ -500,6 +383,7 @@ const Notification = new Lang.Class({
|
||||
this.focused = false;
|
||||
this.acknowledged = false;
|
||||
this._destroyed = false;
|
||||
this._useActionIcons = false;
|
||||
this._customContent = false;
|
||||
this.bannerBodyText = null;
|
||||
this.bannerBodyMarkup = false;
|
||||
@ -554,12 +438,7 @@ const Notification = new Lang.Class({
|
||||
this._bannerLabel = this._bannerUrlHighlighter.actor;
|
||||
this._bannerBox.add_actor(this._bannerLabel);
|
||||
|
||||
// If called with only one argument we assume the caller
|
||||
// will call .update() later on. This is the case of
|
||||
// NotificationDaemon, which wants to use the same code
|
||||
// for new and updated notifications
|
||||
if (arguments.length != 1)
|
||||
this.update(title, banner, params);
|
||||
this.update(title, banner, params);
|
||||
},
|
||||
|
||||
// update:
|
||||
@ -832,8 +711,19 @@ const Notification = new Lang.Class({
|
||||
}
|
||||
},
|
||||
|
||||
addButton: function(button, callback) {
|
||||
// addButton:
|
||||
// @id: the action ID
|
||||
// @label: the label for the action's button
|
||||
//
|
||||
// Adds a button with the given @label to the notification. All
|
||||
// action buttons will appear in a single row at the bottom of
|
||||
// the notification.
|
||||
//
|
||||
// If the button is clicked, the notification will emit the
|
||||
// %action-invoked signal with @id as a parameter
|
||||
addButton: function(id, label) {
|
||||
if (!this._buttonBox) {
|
||||
|
||||
let box = new St.BoxLayout({ style_class: 'notification-actions' });
|
||||
this.setActionArea(box, { x_expand: false,
|
||||
y_expand: false,
|
||||
@ -841,40 +731,49 @@ const Notification = new Lang.Class({
|
||||
y_fill: false,
|
||||
x_align: St.Align.END });
|
||||
this._buttonBox = box;
|
||||
global.focus_manager.add_group(this._buttonBox);
|
||||
}
|
||||
|
||||
this._buttonBox.add(button);
|
||||
button.connect('clicked', Lang.bind(this, function() {
|
||||
callback();
|
||||
let button = new St.Button({ can_focus: true });
|
||||
button._actionId = id;
|
||||
|
||||
if (!this.resident) {
|
||||
// We don't hide a resident notification when the user invokes one of its actions,
|
||||
// because it is common for such notifications to update themselves with new
|
||||
// information based on the action. We'd like to display the updated information
|
||||
// in place, rather than pop-up a new notification.
|
||||
this.emit('done-displaying');
|
||||
this.destroy();
|
||||
}
|
||||
}));
|
||||
let iconName = strHasSuffix(id, '-symbolic') ? id : id + '-symbolic';
|
||||
if (this._useActionIcons && Gtk.IconTheme.get_default().has_icon(iconName)) {
|
||||
button.add_style_class_name('notification-icon-button');
|
||||
button.child = new St.Icon({ icon_name: iconName });
|
||||
} else {
|
||||
button.add_style_class_name('notification-button');
|
||||
button.label = label;
|
||||
}
|
||||
|
||||
if (this._buttonBox.get_n_children() > 0)
|
||||
global.focus_manager.remove_group(this._buttonBox);
|
||||
|
||||
this._buttonBox.add(button);
|
||||
global.focus_manager.add_group(this._buttonBox);
|
||||
button.connect('clicked', Lang.bind(this, this._onActionInvoked, id));
|
||||
|
||||
this.updated();
|
||||
return button;
|
||||
},
|
||||
|
||||
// addAction:
|
||||
// @label: the label for the action's button
|
||||
// @callback: the callback for the action
|
||||
// setButtonSensitive:
|
||||
// @id: the action ID
|
||||
// @sensitive: whether the button should be sensitive
|
||||
//
|
||||
// Adds a button with the given @label to the notification. All
|
||||
// action buttons will appear in a single row at the bottom of
|
||||
// the notification.
|
||||
addAction: function(label, callback) {
|
||||
let button = new St.Button({ style_class: 'notification-button',
|
||||
label: label,
|
||||
can_focus: true });
|
||||
// If the notification contains a button with action ID @id,
|
||||
// its sensitivity will be set to @sensitive. Insensitive
|
||||
// buttons cannot be clicked.
|
||||
setButtonSensitive: function(id, sensitive) {
|
||||
if (!this._buttonBox)
|
||||
return;
|
||||
|
||||
return this.addButton(button, callback);
|
||||
let button = this._buttonBox.get_children().filter(function(b) {
|
||||
return b._actionId == id;
|
||||
})[0];
|
||||
|
||||
if (!button || button.reactive == sensitive)
|
||||
return;
|
||||
|
||||
button.reactive = sensitive;
|
||||
},
|
||||
|
||||
setUrgency: function(urgency) {
|
||||
@ -893,6 +792,10 @@ const Notification = new Lang.Class({
|
||||
this.forFeedback = forFeedback;
|
||||
},
|
||||
|
||||
setUseActionIcons: function(useIcons) {
|
||||
this._useActionIcons = useIcons;
|
||||
},
|
||||
|
||||
_styleChanged: function() {
|
||||
this._spacing = this._table.get_theme_node().get_length('spacing-columns');
|
||||
},
|
||||
@ -1117,6 +1020,18 @@ const Notification = new Lang.Class({
|
||||
this.actor.add_style_class_name('notification-unexpanded');
|
||||
},
|
||||
|
||||
_onActionInvoked: function(actor, mouseButtonClicked, id) {
|
||||
this.emit('action-invoked', id);
|
||||
if (!this.resident) {
|
||||
// We don't hide a resident notification when the user invokes one of its actions,
|
||||
// because it is common for such notifications to update themselves with new
|
||||
// information based on the action. We'd like to display the updated information
|
||||
// in place, rather than pop-up a new notification.
|
||||
this.emit('done-displaying');
|
||||
this.destroy();
|
||||
}
|
||||
},
|
||||
|
||||
_onClicked: function() {
|
||||
this.emit('clicked');
|
||||
// We hide all types of notifications once the user clicks on them because the common
|
||||
@ -1160,7 +1075,7 @@ const SourceActor = new Lang.Class({
|
||||
}));
|
||||
this._actorDestroyed = false;
|
||||
|
||||
this._counterLabel = new St.Label({ x_align: Clutter.ActorAlign.CENTER,
|
||||
this._counterLabel = new St.Label( {x_align: Clutter.ActorAlign.CENTER,
|
||||
x_expand: true,
|
||||
y_align: Clutter.ActorAlign.CENTER,
|
||||
y_expand: true });
|
||||
@ -1264,6 +1179,7 @@ const Source = new Lang.Class({
|
||||
this.title = title;
|
||||
this.iconName = iconName;
|
||||
|
||||
this.isTransient = false;
|
||||
this.isChat = false;
|
||||
this.isMuted = false;
|
||||
this.keepTrayOnSummaryClick = false;
|
||||
@ -1290,10 +1206,6 @@ const Source = new Lang.Class({
|
||||
return this.count > 1;
|
||||
},
|
||||
|
||||
get isClearable() {
|
||||
return !this.trayIcon && !this.isChat && !this.resident;
|
||||
},
|
||||
|
||||
countUpdated: function() {
|
||||
this.emit('count-updated');
|
||||
},
|
||||
@ -1323,6 +1235,10 @@ const Source = new Lang.Class({
|
||||
return rightClickMenu;
|
||||
},
|
||||
|
||||
setTransient: function(isTransient) {
|
||||
this.isTransient = isTransient;
|
||||
},
|
||||
|
||||
setTitle: function(newTitle) {
|
||||
this.title = newTitle;
|
||||
this.emit('title-changed');
|
||||
@ -1361,25 +1277,25 @@ const Source = new Lang.Class({
|
||||
return this._mainIcon.actor;
|
||||
},
|
||||
|
||||
_onNotificationDestroy: function(notification) {
|
||||
let index = this.notifications.indexOf(notification);
|
||||
if (index < 0)
|
||||
return;
|
||||
|
||||
this.notifications.splice(index, 1);
|
||||
if (this.notifications.length == 0)
|
||||
this._lastNotificationRemoved();
|
||||
|
||||
this.countUpdated();
|
||||
},
|
||||
|
||||
pushNotification: function(notification) {
|
||||
if (this.notifications.indexOf(notification) >= 0)
|
||||
return;
|
||||
if (this.notifications.indexOf(notification) < 0) {
|
||||
this.notifications.push(notification);
|
||||
this.emit('notification-added', notification);
|
||||
}
|
||||
|
||||
notification.connect('destroy', Lang.bind(this, this._onNotificationDestroy));
|
||||
this.notifications.push(notification);
|
||||
this.emit('notification-added', notification);
|
||||
notification.connect('clicked', Lang.bind(this, this.open));
|
||||
notification.connect('destroy', Lang.bind(this,
|
||||
function () {
|
||||
let index = this.notifications.indexOf(notification);
|
||||
if (index < 0)
|
||||
return;
|
||||
|
||||
this.notifications.splice(index, 1);
|
||||
if (this.notifications.length == 0)
|
||||
this._lastNotificationRemoved();
|
||||
|
||||
this.countUpdated();
|
||||
}));
|
||||
|
||||
this.countUpdated();
|
||||
},
|
||||
@ -1524,9 +1440,9 @@ const SummaryItem = new Lang.Class({
|
||||
_onKeyPress: function(actor, event) {
|
||||
if (event.get_key_symbol() == Clutter.KEY_Up) {
|
||||
actor.emit('clicked', 1);
|
||||
return Clutter.EVENT_STOP;
|
||||
return true;
|
||||
}
|
||||
return Clutter.EVENT_PROPAGATE;
|
||||
return false;
|
||||
},
|
||||
|
||||
prepareNotificationStackForShowing: function() {
|
||||
@ -1591,42 +1507,26 @@ const MessageTrayMenu = new Lang.Class({
|
||||
|
||||
this._tray = tray;
|
||||
|
||||
this._presence = new GnomeSession.Presence(Lang.bind(this, function(proxy, error) {
|
||||
if (error) {
|
||||
logError(error, 'Error while reading gnome-session presence');
|
||||
return;
|
||||
}
|
||||
|
||||
this._onStatusChanged(proxy.status);
|
||||
}));
|
||||
this._presence.connectSignal('StatusChanged', Lang.bind(this, function(proxy, senderName, [status]) {
|
||||
this._onStatusChanged(status);
|
||||
}));
|
||||
|
||||
this._accountManager = Tp.AccountManager.dup();
|
||||
this._accountManager.connect('most-available-presence-changed',
|
||||
Lang.bind(this, this._onIMPresenceChanged));
|
||||
this._accountManager.prepare_async(null, Lang.bind(this, this._onIMPresenceChanged));
|
||||
|
||||
this.actor.hide();
|
||||
Main.layoutManager.addChrome(this.actor);
|
||||
|
||||
this._busyItem = new PopupMenu.PopupSwitchMenuItem(_("Notifications"));
|
||||
this._busyItem.connect('toggled', Lang.bind(this, this._updatePresence));
|
||||
this.addMenuItem(this._busyItem);
|
||||
|
||||
let separator = new PopupMenu.PopupSeparatorMenuItem();
|
||||
this.addMenuItem(separator);
|
||||
|
||||
this._clearItem = this.addAction(_("Clear Messages"), function() {
|
||||
let toDestroy = tray.getSources().filter(function(source) {
|
||||
return source.isClearable;
|
||||
});
|
||||
let toDestroy = [];
|
||||
let sources = tray.getSources();
|
||||
for (let i = 0; i < sources.length; i++) {
|
||||
// We exclude trayIcons, chat and resident sources
|
||||
if (sources[i].trayIcon ||
|
||||
sources[i].isChat ||
|
||||
sources[i].resident)
|
||||
continue;
|
||||
toDestroy.push(sources[i]);
|
||||
}
|
||||
|
||||
toDestroy.forEach(function(source) {
|
||||
source.destroy();
|
||||
});
|
||||
for (let i = 0; i < toDestroy.length; i++) {
|
||||
toDestroy[i].destroy();
|
||||
}
|
||||
|
||||
toDestroy = null;
|
||||
tray.close();
|
||||
});
|
||||
|
||||
@ -1641,43 +1541,9 @@ const MessageTrayMenu = new Lang.Class({
|
||||
settingsItem.connect('activate', function() { tray.close(); });
|
||||
},
|
||||
|
||||
_onStatusChanged: function(status) {
|
||||
this._sessionStatus = status;
|
||||
this._busyItem.setToggleState(status != GnomeSession.PresenceStatus.BUSY);
|
||||
},
|
||||
|
||||
_onIMPresenceChanged: function(am, type) {
|
||||
if (type == Tp.ConnectionPresenceType.AVAILABLE &&
|
||||
this._sessionStatus == GnomeSession.PresenceStatus.BUSY)
|
||||
this._presence.SetStatusRemote(GnomeSession.PresenceStatus.AVAILABLE);
|
||||
},
|
||||
|
||||
_updateClearSensitivity: function() {
|
||||
this._clearItem.setSensitive(this._tray.clearableCount > 0);
|
||||
},
|
||||
|
||||
_updatePresence: function(item, state) {
|
||||
let status = state ? GnomeSession.PresenceStatus.AVAILABLE
|
||||
: GnomeSession.PresenceStatus.BUSY;
|
||||
this._presence.SetStatusRemote(status);
|
||||
|
||||
let [type, s ,msg] = this._accountManager.get_most_available_presence();
|
||||
let newType = 0;
|
||||
let newStatus;
|
||||
if (status == GnomeSession.PresenceStatus.BUSY &&
|
||||
type == Tp.ConnectionPresenceType.AVAILABLE) {
|
||||
newType = Tp.ConnectionPresenceType.BUSY;
|
||||
newStatus = 'busy';
|
||||
} else if (status == GnomeSession.PresenceStatus.AVAILABLE &&
|
||||
type == Tp.ConnectionPresenceType.BUSY) {
|
||||
newType = Tp.ConnectionPresenceType.AVAILABLE;
|
||||
newStatus = 'available';
|
||||
}
|
||||
|
||||
if (newType > 0)
|
||||
this._accountManager.set_all_requested_presences(newType,
|
||||
newStatus, msg);
|
||||
}
|
||||
});
|
||||
|
||||
const MessageTrayMenuButton = new Lang.Class({
|
||||
@ -1784,7 +1650,6 @@ const MessageTray = new Lang.Class({
|
||||
this._setClickedSummaryItem(null);
|
||||
this._updateState();
|
||||
actor.grab_key_focus();
|
||||
return Clutter.EVENT_PROPAGATE;
|
||||
}));
|
||||
global.focus_manager.add_group(this.actor);
|
||||
this._summary = new St.BoxLayout({ style_class: 'message-tray-summary',
|
||||
@ -1990,32 +1855,32 @@ const MessageTray = new Lang.Class({
|
||||
this._trayDwellTimeoutId = 0;
|
||||
|
||||
if (Main.layoutManager.bottomMonitor.inFullscreen)
|
||||
return GLib.SOURCE_REMOVE;
|
||||
return false;
|
||||
|
||||
// We don't want to open the tray when a modal dialog
|
||||
// is up, so we check the modal count for that. When we are in the
|
||||
// overview we have to take the overview's modal push into account
|
||||
if (Main.modalCount > (Main.overview.visible ? 1 : 0))
|
||||
return GLib.SOURCE_REMOVE;
|
||||
return false;
|
||||
|
||||
// If the user interacted with the focus window since we started the tray
|
||||
// dwell (by clicking or typing), don't activate the message tray
|
||||
let focusWindow = global.display.focus_window;
|
||||
let currentUserTime = focusWindow ? focusWindow.user_time : 0;
|
||||
if (currentUserTime != this._trayDwellUserTime)
|
||||
return GLib.SOURCE_REMOVE;
|
||||
return false;
|
||||
|
||||
this.openTray();
|
||||
return GLib.SOURCE_REMOVE;
|
||||
return false;
|
||||
},
|
||||
|
||||
_onNotificationKeyRelease: function(actor, event) {
|
||||
if (event.get_key_symbol() == Clutter.KEY_Escape && event.get_state() == 0) {
|
||||
this._closeNotification();
|
||||
return Clutter.EVENT_STOP;
|
||||
return true;
|
||||
}
|
||||
|
||||
return Clutter.EVENT_PROPAGATE;
|
||||
return false;
|
||||
},
|
||||
|
||||
_closeNotification: function() {
|
||||
@ -2061,7 +1926,7 @@ const MessageTray = new Lang.Class({
|
||||
this._summary.insert_child_at_index(summaryItem.actor, this._chatSummaryItemsCount);
|
||||
}
|
||||
|
||||
if (source.isClearable)
|
||||
if (!source.trayIcon && !source.isChat && !source.resident)
|
||||
this.clearableCount++;
|
||||
|
||||
this._sources.set(source, obj);
|
||||
@ -2105,7 +1970,7 @@ const MessageTray = new Lang.Class({
|
||||
if (source.isChat)
|
||||
this._chatSummaryItemsCount--;
|
||||
|
||||
if (source.isClearable)
|
||||
if (!source.trayIcon && !source.isChat && !source.resident)
|
||||
this.clearableCount--;
|
||||
|
||||
source.disconnect(obj.notifyId);
|
||||
@ -2170,10 +2035,7 @@ const MessageTray = new Lang.Class({
|
||||
},
|
||||
|
||||
toggleAndNavigate: function() {
|
||||
if (!this.toggle())
|
||||
return;
|
||||
|
||||
if (this._traySummoned)
|
||||
if (this.toggle())
|
||||
this._summary.navigate_focus(null, Gtk.DirectionType.TAB_FORWARD, false);
|
||||
},
|
||||
|
||||
@ -2336,7 +2198,7 @@ const MessageTray = new Lang.Class({
|
||||
this._updateNotificationTimeout(0);
|
||||
this._updateState();
|
||||
}
|
||||
return GLib.SOURCE_REMOVE;
|
||||
return false;
|
||||
},
|
||||
|
||||
_escapeTray: function() {
|
||||
@ -2353,13 +2215,6 @@ const MessageTray = new Lang.Class({
|
||||
// _updateState() figures out what (if anything) needs to be done
|
||||
// at the present time.
|
||||
_updateState: function() {
|
||||
// If our state changes caused _updateState to be called,
|
||||
// just exit now to prevent reentrancy issues.
|
||||
if (this._updatingState)
|
||||
return;
|
||||
|
||||
this._updatingState = true;
|
||||
|
||||
// Filter out acknowledged notifications.
|
||||
this._notificationQueue = this._notificationQueue.filter(function(n) {
|
||||
return !n.acknowledged;
|
||||
@ -2377,9 +2232,10 @@ const MessageTray = new Lang.Class({
|
||||
this._showNotification();
|
||||
}
|
||||
} else if (this._notificationState == State.SHOWN) {
|
||||
let pinned = this._pointerInNotification && !this._notificationRemoved;
|
||||
let expired = (this._userActiveWhileNotificationShown &&
|
||||
this._notificationTimeoutId == 0 &&
|
||||
this._notification.urgency != Urgency.CRITICAL &&
|
||||
!(this._notification.urgency == Urgency.CRITICAL) &&
|
||||
!this._notification.focused &&
|
||||
!this._pointerInNotification);
|
||||
let mustClose = (this._notificationRemoved || !hasNotifications || expired || this._traySummoned);
|
||||
@ -2387,9 +2243,9 @@ const MessageTray = new Lang.Class({
|
||||
if (mustClose) {
|
||||
let animate = hasNotifications && !this._notificationRemoved;
|
||||
this._hideNotification(animate);
|
||||
} else if (this._pointerInNotification && !this._notification.expanded) {
|
||||
} else if (pinned && !this._notification.expanded) {
|
||||
this._expandNotification(false);
|
||||
} else if (this._pointerInNotification) {
|
||||
} else if (pinned) {
|
||||
this._ensureNotificationFocused();
|
||||
}
|
||||
}
|
||||
@ -2436,12 +2292,11 @@ const MessageTray = new Lang.Class({
|
||||
this._desktopCloneState == State.SHOWN);
|
||||
let desktopCloneShouldBeVisible = (trayShouldBeVisible);
|
||||
|
||||
if (!desktopCloneIsVisible && desktopCloneShouldBeVisible)
|
||||
if (!desktopCloneIsVisible && desktopCloneShouldBeVisible) {
|
||||
this._showDesktopClone();
|
||||
else if (desktopCloneIsVisible && !desktopCloneShouldBeVisible)
|
||||
} else if (desktopCloneIsVisible && !desktopCloneShouldBeVisible) {
|
||||
this._hideDesktopClone();
|
||||
|
||||
this._updatingState = false;
|
||||
}
|
||||
},
|
||||
|
||||
_tween: function(actor, statevar, value, params) {
|
||||
@ -2669,7 +2524,7 @@ const MessageTray = new Lang.Class({
|
||||
|
||||
this._lastSeenMouseX = x;
|
||||
this._lastSeenMouseY = y;
|
||||
return GLib.SOURCE_REMOVE;
|
||||
return false;
|
||||
},
|
||||
|
||||
_hideNotification: function(animate) {
|
||||
@ -2760,12 +2615,12 @@ const MessageTray = new Lang.Class({
|
||||
} else if (this._notification.y != expandedY) {
|
||||
// Tween also opacity here, to override a possible tween that's
|
||||
// currently hiding the notification.
|
||||
Tweener.addTween(this._notificationWidget,
|
||||
{ y: expandedY,
|
||||
opacity: 255,
|
||||
time: ANIMATION_TIME,
|
||||
transition: 'easeOutQuad'
|
||||
});
|
||||
this._tween(this._notificationWidget, '_notificationState', State.SHOWN,
|
||||
{ y: expandedY,
|
||||
opacity: 255,
|
||||
time: ANIMATION_TIME,
|
||||
transition: 'easeOutQuad'
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
@ -2806,13 +2661,13 @@ const MessageTray = new Lang.Class({
|
||||
Lang.bind(this, this._onSourceDoneDisplayingContent));
|
||||
|
||||
this._summaryBoxPointer.bin.child = child;
|
||||
this._grabHelper.grab({ actor: this._summaryBoxPointer.bin.child,
|
||||
onUngrab: Lang.bind(this, this._onSummaryBoxPointerUngrabbed) });
|
||||
|
||||
this._summaryBoxPointer.actor.opacity = 0;
|
||||
this._summaryBoxPointer.actor.show();
|
||||
this._adjustSummaryBoxPointerPosition();
|
||||
|
||||
this._grabHelper.grab({ actor: this._summaryBoxPointer.bin.child,
|
||||
onUngrab: Lang.bind(this, this._onSummaryBoxPointerUngrabbed) });
|
||||
|
||||
this._summaryBoxPointerState = State.SHOWING;
|
||||
this._summaryBoxPointer.show(BoxPointer.PopupAnimation.FULL, Lang.bind(this, function() {
|
||||
this._summaryBoxPointerState = State.SHOWN;
|
||||
@ -2867,13 +2722,13 @@ const MessageTray = new Lang.Class({
|
||||
case Clutter.KEY_Escape:
|
||||
this._setClickedSummaryItem(null);
|
||||
this._updateState();
|
||||
return Clutter.EVENT_STOP;
|
||||
return true;
|
||||
case Clutter.KEY_Delete:
|
||||
this._clickedSummaryItem.source.destroy();
|
||||
this._escapeTray();
|
||||
return Clutter.EVENT_STOP;
|
||||
return true;
|
||||
}
|
||||
return Clutter.EVENT_PROPAGATE;
|
||||
return false;
|
||||
},
|
||||
|
||||
_onSummaryBoxPointerUngrabbed: function() {
|
||||
@ -2911,6 +2766,8 @@ const MessageTray = new Lang.Class({
|
||||
this._summaryBoxPointerItem.doneShowingNotificationStack();
|
||||
this._summaryBoxPointerItem = null;
|
||||
|
||||
if (source.isTransient && !this._reNotifyAfterHideNotification)
|
||||
source.destroy(NotificationDestroyedReason.EXPIRED);
|
||||
if (this._reNotifyAfterHideNotification) {
|
||||
this._onNotify(this._reNotifyAfterHideNotification.source, this._reNotifyAfterHideNotification);
|
||||
this._reNotifyAfterHideNotification = null;
|
||||
@ -2929,6 +2786,7 @@ const SystemNotificationSource = new Lang.Class({
|
||||
|
||||
_init: function() {
|
||||
this.parent(_("System Information"), 'dialog-information-symbolic');
|
||||
this.setTransient(true);
|
||||
},
|
||||
|
||||
open: function() {
|
||||
|
@ -229,7 +229,6 @@ const ModalDialog = new Lang.Class({
|
||||
|
||||
_onKeyPressEvent: function(object, event) {
|
||||
this._pressedKey = event.get_key_symbol();
|
||||
return Clutter.EVENT_PROPAGATE;
|
||||
},
|
||||
|
||||
_onKeyReleaseEvent: function(object, event) {
|
||||
@ -238,21 +237,21 @@ const ModalDialog = new Lang.Class({
|
||||
|
||||
let symbol = event.get_key_symbol();
|
||||
if (symbol != pressedKey)
|
||||
return Clutter.EVENT_PROPAGATE;
|
||||
return false;
|
||||
|
||||
let buttonInfo = this._buttonKeys[symbol];
|
||||
if (!buttonInfo)
|
||||
return Clutter.EVENT_PROPAGATE;
|
||||
return false;
|
||||
|
||||
let button = buttonInfo['button'];
|
||||
let action = buttonInfo['action'];
|
||||
|
||||
if (action && button.reactive) {
|
||||
action();
|
||||
return Clutter.EVENT_STOP;
|
||||
return true;
|
||||
}
|
||||
|
||||
return Clutter.EVENT_PROPAGATE;
|
||||
return false;
|
||||
},
|
||||
|
||||
_onGroupDestroy: function() {
|
||||
|
@ -4,7 +4,6 @@ const Clutter = imports.gi.Clutter;
|
||||
const GdkPixbuf = imports.gi.GdkPixbuf;
|
||||
const Gio = imports.gi.Gio;
|
||||
const GLib = imports.gi.GLib;
|
||||
const Gtk = imports.gi.Gtk;
|
||||
const Lang = imports.lang;
|
||||
const Shell = imports.gi.Shell;
|
||||
const Mainloop = imports.mainloop;
|
||||
@ -16,56 +15,54 @@ const MessageTray = imports.ui.messageTray;
|
||||
const Params = imports.misc.params;
|
||||
const Util = imports.misc.util;
|
||||
|
||||
let nextNotificationId = 1;
|
||||
|
||||
// Should really be defined in Gio.js
|
||||
const BusIface = '<node> \
|
||||
<interface name="org.freedesktop.DBus"> \
|
||||
<method name="GetConnectionUnixProcessID"> \
|
||||
<arg type="s" direction="in" /> \
|
||||
<arg type="u" direction="out" /> \
|
||||
</method> \
|
||||
</interface> \
|
||||
</node>';
|
||||
const BusIface = <interface name="org.freedesktop.DBus">
|
||||
<method name="GetConnectionUnixProcessID">
|
||||
<arg type="s" direction="in" />
|
||||
<arg type="u" direction="out" />
|
||||
</method>
|
||||
</interface>;
|
||||
|
||||
var BusProxy = Gio.DBusProxy.makeProxyWrapper(BusIface);
|
||||
function Bus() {
|
||||
return new BusProxy(Gio.DBus.session, 'org.freedesktop.DBus', '/org/freedesktop/DBus');
|
||||
}
|
||||
|
||||
const FdoNotificationsIface = '<node> \
|
||||
<interface name="org.freedesktop.Notifications"> \
|
||||
<method name="Notify"> \
|
||||
<arg type="s" direction="in"/> \
|
||||
<arg type="u" direction="in"/> \
|
||||
<arg type="s" direction="in"/> \
|
||||
<arg type="s" direction="in"/> \
|
||||
<arg type="s" direction="in"/> \
|
||||
<arg type="as" direction="in"/> \
|
||||
<arg type="a{sv}" direction="in"/> \
|
||||
<arg type="i" direction="in"/> \
|
||||
<arg type="u" direction="out"/> \
|
||||
</method> \
|
||||
<method name="CloseNotification"> \
|
||||
<arg type="u" direction="in"/> \
|
||||
</method> \
|
||||
<method name="GetCapabilities"> \
|
||||
<arg type="as" direction="out"/> \
|
||||
</method> \
|
||||
<method name="GetServerInformation"> \
|
||||
<arg type="s" direction="out"/> \
|
||||
<arg type="s" direction="out"/> \
|
||||
<arg type="s" direction="out"/> \
|
||||
<arg type="s" direction="out"/> \
|
||||
</method> \
|
||||
<signal name="NotificationClosed"> \
|
||||
<arg type="u"/> \
|
||||
<arg type="u"/> \
|
||||
</signal> \
|
||||
<signal name="ActionInvoked"> \
|
||||
<arg type="u"/> \
|
||||
<arg type="s"/> \
|
||||
</signal> \
|
||||
</interface> \
|
||||
</node>';
|
||||
const NotificationDaemonIface = <interface name="org.freedesktop.Notifications">
|
||||
<method name="Notify">
|
||||
<arg type="s" direction="in"/>
|
||||
<arg type="u" direction="in"/>
|
||||
<arg type="s" direction="in"/>
|
||||
<arg type="s" direction="in"/>
|
||||
<arg type="s" direction="in"/>
|
||||
<arg type="as" direction="in"/>
|
||||
<arg type="a{sv}" direction="in"/>
|
||||
<arg type="i" direction="in"/>
|
||||
<arg type="u" direction="out"/>
|
||||
</method>
|
||||
<method name="CloseNotification">
|
||||
<arg type="u" direction="in"/>
|
||||
</method>
|
||||
<method name="GetCapabilities">
|
||||
<arg type="as" direction="out"/>
|
||||
</method>
|
||||
<method name="GetServerInformation">
|
||||
<arg type="s" direction="out"/>
|
||||
<arg type="s" direction="out"/>
|
||||
<arg type="s" direction="out"/>
|
||||
<arg type="s" direction="out"/>
|
||||
</method>
|
||||
<signal name="NotificationClosed">
|
||||
<arg type="u"/>
|
||||
<arg type="u"/>
|
||||
</signal>
|
||||
<signal name="ActionInvoked">
|
||||
<arg type="u"/>
|
||||
<arg type="s"/>
|
||||
</signal>
|
||||
</interface>;
|
||||
|
||||
const NotificationClosedReason = {
|
||||
EXPIRED: 1,
|
||||
@ -106,11 +103,131 @@ const STANDARD_TRAY_ICON_IMPLEMENTATIONS = {
|
||||
'ibus-ui-gtk': 'keyboard'
|
||||
};
|
||||
|
||||
const FdoNotificationDaemon = new Lang.Class({
|
||||
Name: 'FdoNotificationDaemon',
|
||||
const NotificationGenericPolicy = new Lang.Class({
|
||||
Name: 'NotificationGenericPolicy',
|
||||
Extends: MessageTray.NotificationPolicy,
|
||||
|
||||
_init: function() {
|
||||
this._dbusImpl = Gio.DBusExportedObject.wrapJSObject(FdoNotificationsIface, this);
|
||||
// Don't chain to parent, it would try setting
|
||||
// our properties to the defaults
|
||||
|
||||
this.id = 'generic';
|
||||
|
||||
this._masterSettings = new Gio.Settings({ schema: 'org.gnome.desktop.notifications' });
|
||||
this._masterSettings.connect('changed', Lang.bind(this, this._changed));
|
||||
},
|
||||
|
||||
store: function() { },
|
||||
|
||||
destroy: function() {
|
||||
this._masterSettings.run_dispose();
|
||||
},
|
||||
|
||||
_changed: function(settings, key) {
|
||||
this.emit('policy-changed', key);
|
||||
},
|
||||
|
||||
get enable() {
|
||||
return true;
|
||||
},
|
||||
|
||||
get enableSound() {
|
||||
return true;
|
||||
},
|
||||
|
||||
get showBanners() {
|
||||
return this._masterSettings.get_boolean('show-banners');
|
||||
},
|
||||
|
||||
get forceExpanded() {
|
||||
return false;
|
||||
},
|
||||
|
||||
get showInLockScreen() {
|
||||
return this._masterSettings.get_boolean('show-in-lock-screen');
|
||||
},
|
||||
|
||||
get detailsInLockScreen() {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
const NotificationApplicationPolicy = new Lang.Class({
|
||||
Name: 'NotificationApplicationPolicy',
|
||||
Extends: MessageTray.NotificationPolicy,
|
||||
|
||||
_init: function(id) {
|
||||
// Don't chain to parent, it would try setting
|
||||
// our properties to the defaults
|
||||
|
||||
this.id = id;
|
||||
this._canonicalId = this._canonicalizeId(id)
|
||||
|
||||
this._masterSettings = new Gio.Settings({ schema: 'org.gnome.desktop.notifications' });
|
||||
this._settings = new Gio.Settings({ schema: 'org.gnome.desktop.notifications.application',
|
||||
path: '/org/gnome/desktop/notifications/application/' + this._canonicalId + '/' });
|
||||
|
||||
this._masterSettings.connect('changed', Lang.bind(this, this._changed));
|
||||
this._settings.connect('changed', Lang.bind(this, this._changed));
|
||||
},
|
||||
|
||||
store: function() {
|
||||
this._settings.set_string('application-id', this.id + '.desktop');
|
||||
|
||||
let apps = this._masterSettings.get_strv('application-children');
|
||||
if (apps.indexOf(this._canonicalId) < 0) {
|
||||
apps.push(this._canonicalId);
|
||||
this._masterSettings.set_strv('application-children', apps);
|
||||
}
|
||||
},
|
||||
|
||||
destroy: function() {
|
||||
this._masterSettings.run_dispose();
|
||||
this._settings.run_dispose();
|
||||
},
|
||||
|
||||
_changed: function(settings, key) {
|
||||
this.emit('policy-changed', key);
|
||||
},
|
||||
|
||||
_canonicalizeId: function(id) {
|
||||
// Keys are restricted to lowercase alphanumeric characters and dash,
|
||||
// and two dashes cannot be in succession
|
||||
return id.toLowerCase().replace(/[^a-z0-9\-]/g, '-').replace(/--+/g, '-');
|
||||
},
|
||||
|
||||
get enable() {
|
||||
return this._settings.get_boolean('enable');
|
||||
},
|
||||
|
||||
get enableSound() {
|
||||
return this._settings.get_boolean('enable-sound-alerts');
|
||||
},
|
||||
|
||||
get showBanners() {
|
||||
return this._masterSettings.get_boolean('show-banners') &&
|
||||
this._settings.get_boolean('show-banners');
|
||||
},
|
||||
|
||||
get forceExpanded() {
|
||||
return this._settings.get_boolean('force-expanded');
|
||||
},
|
||||
|
||||
get showInLockScreen() {
|
||||
return this._masterSettings.get_boolean('show-in-lock-screen') &&
|
||||
this._settings.get_boolean('show-in-lock-screen');
|
||||
},
|
||||
|
||||
get detailsInLockScreen() {
|
||||
return this._settings.get_boolean('details-in-lock-screen');
|
||||
}
|
||||
});
|
||||
|
||||
const NotificationDaemon = new Lang.Class({
|
||||
Name: 'NotificationDaemon',
|
||||
|
||||
_init: function() {
|
||||
this._dbusImpl = Gio.DBusExportedObject.wrapJSObject(NotificationDaemonIface, this);
|
||||
this._dbusImpl.export(Gio.DBus.session, '/org/freedesktop/Notifications');
|
||||
|
||||
this._sources = [];
|
||||
@ -118,8 +235,6 @@ const FdoNotificationDaemon = new Lang.Class({
|
||||
this._notifications = {};
|
||||
this._busProxy = new Bus();
|
||||
|
||||
this._nextNotificationId = 1;
|
||||
|
||||
this._trayManager = new Shell.TrayManager();
|
||||
this._trayIconAddedId = this._trayManager.connect('tray-icon-added', Lang.bind(this, this._onTrayIconAdded));
|
||||
this._trayIconRemovedId = this._trayManager.connect('tray-icon-removed', Lang.bind(this, this._onTrayIconRemoved));
|
||||
@ -181,10 +296,12 @@ const FdoNotificationDaemon = new Lang.Class({
|
||||
},
|
||||
|
||||
// Returns the source associated with ndata.notification if it is set.
|
||||
// If the existing or requested source is associated with a tray icon
|
||||
// and passed in pid matches a pid of an existing source, the title
|
||||
// match is ignored to enable representing a tray icon and notifications
|
||||
// from the same application with a single source.
|
||||
// Otherwise, returns the source associated with the title and pid if
|
||||
// such source is stored in this._sources and the notification is not
|
||||
// transient. If the existing or requested source is associated with
|
||||
// a tray icon and passed in pid matches a pid of an existing source,
|
||||
// the title match is ignored to enable representing a tray icon and
|
||||
// notifications from the same application with a single source.
|
||||
//
|
||||
// If no existing source is found, a new source is created as long as
|
||||
// pid is provided.
|
||||
@ -202,20 +319,32 @@ const FdoNotificationDaemon = new Lang.Class({
|
||||
if (ndata && ndata.notification)
|
||||
return ndata.notification.source;
|
||||
|
||||
let source = this._lookupSource(title, pid, trayIcon);
|
||||
if (source) {
|
||||
source.setTitle(title);
|
||||
return source;
|
||||
let isForTransientNotification = (ndata && ndata.hints['transient'] == true);
|
||||
|
||||
// We don't want to override a persistent notification
|
||||
// with a transient one from the same sender, so we
|
||||
// always create a new source object for new transient notifications
|
||||
// and never add it to this._sources .
|
||||
if (!isForTransientNotification) {
|
||||
let source = this._lookupSource(title, pid, trayIcon);
|
||||
if (source) {
|
||||
source.setTitle(title);
|
||||
return source;
|
||||
}
|
||||
}
|
||||
|
||||
let source = new FdoNotificationDaemonSource(title, pid, sender, trayIcon, ndata ? ndata.hints['desktop-entry'] : null);
|
||||
let source = new Source(title, pid, sender, trayIcon, ndata ? ndata.hints['desktop-entry'] : null);
|
||||
source.setTransient(isForTransientNotification);
|
||||
|
||||
this._sources.push(source);
|
||||
source.connect('destroy', Lang.bind(this, function() {
|
||||
let index = this._sources.indexOf(source);
|
||||
if (index >= 0)
|
||||
this._sources.splice(index, 1);
|
||||
}));
|
||||
if (!isForTransientNotification) {
|
||||
this._sources.push(source);
|
||||
source.connect('destroy', Lang.bind(this,
|
||||
function() {
|
||||
let index = this._sources.indexOf(source);
|
||||
if (index >= 0)
|
||||
this._sources.splice(index, 1);
|
||||
}));
|
||||
}
|
||||
|
||||
Main.messageTray.add(source);
|
||||
return source;
|
||||
@ -243,11 +372,11 @@ const FdoNotificationDaemon = new Lang.Class({
|
||||
hints['category'] == 'presence.offline')) {
|
||||
// Ignore replacesId since we already sent back a
|
||||
// NotificationClosed for that id.
|
||||
id = this._nextNotificationId++;
|
||||
id = nextNotificationId++;
|
||||
Mainloop.idle_add(Lang.bind(this,
|
||||
function () {
|
||||
this._emitNotificationClosed(id, NotificationClosedReason.DISMISSED);
|
||||
return GLib.SOURCE_REMOVE;
|
||||
return false;
|
||||
}));
|
||||
return invocation.return_value(GLib.Variant.new('(u)', [id]));
|
||||
}
|
||||
@ -267,13 +396,12 @@ const FdoNotificationDaemon = new Lang.Class({
|
||||
if (!hints['image-path'] && hints['image_path'])
|
||||
hints['image-path'] = hints['image_path']; // version 1.1 of the spec
|
||||
|
||||
if (!hints['image-data']) {
|
||||
if (!hints['image-data'])
|
||||
if (hints['image_data'])
|
||||
hints['image-data'] = hints['image_data']; // version 1.1 of the spec
|
||||
else if (hints['icon_data'] && !hints['image-path'])
|
||||
// early versions of the spec; 'icon_data' should only be used if 'image-path' is not available
|
||||
hints['image-data'] = hints['icon_data'];
|
||||
}
|
||||
|
||||
let ndata = { appName: appName,
|
||||
icon: icon,
|
||||
@ -287,7 +415,7 @@ const FdoNotificationDaemon = new Lang.Class({
|
||||
ndata.notification = this._notifications[replacesId].notification;
|
||||
} else {
|
||||
replacesId = 0;
|
||||
ndata.id = id = this._nextNotificationId++;
|
||||
ndata.id = id = nextNotificationId++;
|
||||
}
|
||||
this._notifications[id] = ndata;
|
||||
|
||||
@ -322,29 +450,26 @@ const FdoNotificationDaemon = new Lang.Class({
|
||||
let [pid] = result;
|
||||
source = this._getSource(appName, pid, ndata, sender, null);
|
||||
|
||||
this._senderToPid[sender] = pid;
|
||||
source.connect('destroy', Lang.bind(this, function() {
|
||||
delete this._senderToPid[sender];
|
||||
}));
|
||||
// We only store sender-pid entries for persistent sources.
|
||||
// Removing the entries once the source is destroyed
|
||||
// would result in the entries associated with transient
|
||||
// sources removed once the notification is shown anyway.
|
||||
// However, keeping these pairs would mean that we would
|
||||
// possibly remove an entry associated with a persistent
|
||||
// source when a transient source for the same sender is
|
||||
// distroyed.
|
||||
if (!source.isTransient) {
|
||||
this._senderToPid[sender] = pid;
|
||||
source.connect('destroy', Lang.bind(this, function() {
|
||||
delete this._senderToPid[sender];
|
||||
}));
|
||||
}
|
||||
this._notifyForSource(source, ndata);
|
||||
}));
|
||||
|
||||
return invocation.return_value(GLib.Variant.new('(u)', [id]));
|
||||
},
|
||||
|
||||
_makeButton: function(id, label, useActionIcons) {
|
||||
let button = new St.Button({ can_focus: true });
|
||||
let iconName = id.endsWith('-symbolic') ? id : id + '-symbolic';
|
||||
if (useActionIcons && Gtk.IconTheme.get_default().has_icon(iconName)) {
|
||||
button.add_style_class_name('notification-icon-button');
|
||||
button.child = new St.Icon({ icon_name: iconName });
|
||||
} else {
|
||||
button.add_style_class_name('notification-button');
|
||||
button.label = label;
|
||||
}
|
||||
return button;
|
||||
},
|
||||
|
||||
_notifyForSource: function(source, ndata) {
|
||||
let [id, icon, summary, body, actions, hints, notification] =
|
||||
[ndata.id, ndata.icon, ndata.summary, ndata.body,
|
||||
@ -370,6 +495,10 @@ const FdoNotificationDaemon = new Lang.Class({
|
||||
}
|
||||
this._emitNotificationClosed(ndata.id, notificationClosedReason);
|
||||
}));
|
||||
notification.connect('action-invoked', Lang.bind(this,
|
||||
function(n, actionId) {
|
||||
this._emitActionInvoked(ndata.id, actionId);
|
||||
}));
|
||||
}
|
||||
|
||||
// Mark music notifications so they can be shown in the screen shield
|
||||
@ -403,33 +532,18 @@ const FdoNotificationDaemon = new Lang.Class({
|
||||
soundName: hints['sound-name'] });
|
||||
notification.setImage(image);
|
||||
|
||||
let hasDefaultAction = false;
|
||||
|
||||
if (actions.length) {
|
||||
let useActionIcons = (hints['action-icons'] == true);
|
||||
|
||||
notification.setUseActionIcons(hints['action-icons'] == true);
|
||||
for (let i = 0; i < actions.length - 1; i += 2) {
|
||||
let [actionId, label] = [actions[i], actions[i+1]];
|
||||
if (actionId == 'default') {
|
||||
hasDefaultAction = true;
|
||||
} else {
|
||||
notification.addButton(this._makeButton(actionId, label, useActionIcons), Lang.bind(this, function() {
|
||||
this._emitActionInvoked(ndata.id, actionId);
|
||||
}));
|
||||
}
|
||||
if (actions[i] == 'default')
|
||||
notification.connect('clicked', Lang.bind(this,
|
||||
function() {
|
||||
this._emitActionInvoked(ndata.id, "default");
|
||||
}));
|
||||
else
|
||||
notification.addButton(actions[i], actions[i + 1]);
|
||||
}
|
||||
}
|
||||
|
||||
if (hasDefaultAction) {
|
||||
notification.connect('clicked', Lang.bind(this, function() {
|
||||
this._emitActionInvoked(ndata.id, 'default');
|
||||
}));
|
||||
} else {
|
||||
notification.connect('clicked', Lang.bind(this, function() {
|
||||
source.open();
|
||||
}));
|
||||
}
|
||||
|
||||
switch (hints.urgency) {
|
||||
case Urgency.LOW:
|
||||
notification.setUrgency(MessageTray.Urgency.LOW);
|
||||
@ -522,8 +636,8 @@ const FdoNotificationDaemon = new Lang.Class({
|
||||
}
|
||||
});
|
||||
|
||||
const FdoNotificationDaemonSource = new Lang.Class({
|
||||
Name: 'FdoNotificationDaemonSource',
|
||||
const Source = new Lang.Class({
|
||||
Name: 'NotificationDaemonSource',
|
||||
Extends: MessageTray.Source,
|
||||
|
||||
_init: function(title, pid, sender, trayIcon, appId) {
|
||||
@ -558,11 +672,11 @@ const FdoNotificationDaemonSource = new Lang.Class({
|
||||
},
|
||||
|
||||
_createPolicy: function() {
|
||||
if (this.app && this.app.get_app_info()) {
|
||||
if (this.app) {
|
||||
let id = this.app.get_id().replace(/\.desktop$/,'');
|
||||
return new MessageTray.NotificationApplicationPolicy(id);
|
||||
return new NotificationApplicationPolicy(id);
|
||||
} else {
|
||||
return new MessageTray.NotificationGenericPolicy();
|
||||
return new NotificationGenericPolicy();
|
||||
}
|
||||
},
|
||||
|
||||
@ -638,6 +752,22 @@ const FdoNotificationDaemonSource = new Lang.Class({
|
||||
return null;
|
||||
},
|
||||
|
||||
_setApp: function(appId) {
|
||||
if (this.app)
|
||||
return;
|
||||
|
||||
this.app = this._getApp(appId);
|
||||
if (!this.app)
|
||||
return;
|
||||
|
||||
// Only override the icon if we were previously using
|
||||
// notification-based icons (ie, not a trayicon) or if it was unset before
|
||||
if (!this.trayIcon) {
|
||||
this.useNotificationIcon = false;
|
||||
this.iconUpdated();
|
||||
}
|
||||
},
|
||||
|
||||
setTitle: function(title) {
|
||||
// Do nothing if .app is set, we don't want to override the
|
||||
// app name with whatever is provided through libnotify (usually
|
||||
@ -648,9 +778,9 @@ const FdoNotificationDaemonSource = new Lang.Class({
|
||||
this.parent(title);
|
||||
},
|
||||
|
||||
open: function() {
|
||||
this.openApp();
|
||||
open: function(notification) {
|
||||
this.destroyNonResidentNotifications();
|
||||
this.openApp();
|
||||
},
|
||||
|
||||
_lastNotificationRemoved: function() {
|
||||
@ -662,8 +792,11 @@ const FdoNotificationDaemonSource = new Lang.Class({
|
||||
if (this.app == null)
|
||||
return;
|
||||
|
||||
this.app.activate();
|
||||
Main.overview.hide();
|
||||
let windows = this.app.get_windows();
|
||||
if (windows.length > 0) {
|
||||
let mostRecentWindow = windows[0];
|
||||
Main.activateWindow(mostRecentWindow);
|
||||
}
|
||||
},
|
||||
|
||||
destroy: function() {
|
||||
@ -690,276 +823,3 @@ const FdoNotificationDaemonSource = new Lang.Class({
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
const GtkNotificationDaemonNotification = new Lang.Class({
|
||||
Name: 'GtkNotificationDaemonNotification',
|
||||
Extends: MessageTray.Notification,
|
||||
|
||||
_init: function(source, notification) {
|
||||
this.parent(source);
|
||||
this._serialized = GLib.Variant.new('a{sv}', notification);
|
||||
|
||||
let { "title": title,
|
||||
"body": body,
|
||||
"icon": gicon,
|
||||
"urgent": urgent,
|
||||
"buttons": buttons,
|
||||
"default-action": defaultAction,
|
||||
"default-action-target": defaultActionTarget } = notification;
|
||||
|
||||
this.setUrgency(urgent.unpack() ? MessageTray.Urgency.CRITICAL
|
||||
: MessageTray.Urgency.NORMAL);
|
||||
|
||||
if (buttons) {
|
||||
buttons.deep_unpack().forEach(Lang.bind(this, function(button) {
|
||||
this.addAction(button.label.unpack(),
|
||||
Lang.bind(this, this._onButtonClicked, button));
|
||||
}));
|
||||
}
|
||||
|
||||
this._defaultAction = defaultAction ? defaultAction.unpack() : null;
|
||||
this._defaultActionTarget = defaultActionTarget;
|
||||
|
||||
this.update(title.unpack(), body ? body.unpack() : null,
|
||||
{ gicon: gicon ? Gio.icon_deserialize(gicon) : null });
|
||||
},
|
||||
|
||||
_activateAction: function(namespacedActionId, target) {
|
||||
if (namespacedActionId) {
|
||||
if (namespacedActionId.startsWith('app.')) {
|
||||
let actionId = namespacedActionId.slice('app.'.length);
|
||||
this.source.activateAction(actionId, target);
|
||||
}
|
||||
} else {
|
||||
this.source.open();
|
||||
}
|
||||
},
|
||||
|
||||
_onButtonClicked: function(button) {
|
||||
let { 'action': action, 'target': actionTarget } = button;
|
||||
this._activateAction(action.unpack(), actionTarget);
|
||||
},
|
||||
|
||||
_onClicked: function() {
|
||||
this._activateAction(this._defaultAction, this._defaultActionTarget);
|
||||
this.parent();
|
||||
},
|
||||
|
||||
serialize: function() {
|
||||
return this._serialized;
|
||||
},
|
||||
});
|
||||
|
||||
const FdoApplicationIface = '<node> \
|
||||
<interface name="org.freedesktop.Application"> \
|
||||
<method name="ActivateAction"> \
|
||||
<arg type="s" direction="in" /> \
|
||||
<arg type="av" direction="in" /> \
|
||||
<arg type="a{sv}" direction="in" /> \
|
||||
</method> \
|
||||
<method name="Activate"> \
|
||||
<arg type="a{sv}" direction="in" /> \
|
||||
</method> \
|
||||
</interface> \
|
||||
</node>';
|
||||
const FdoApplicationProxy = Gio.DBusProxy.makeProxyWrapper(FdoApplicationIface);
|
||||
|
||||
function objectPathFromAppId(appId) {
|
||||
return '/' + appId.replace(/\./g, '/');
|
||||
}
|
||||
|
||||
function getPlatformData() {
|
||||
let startupId = GLib.Variant.new('s', '_TIME' + global.get_current_time());
|
||||
return { "desktop-startup-id": startupId };
|
||||
}
|
||||
|
||||
function InvalidAppError() {}
|
||||
|
||||
const GtkNotificationDaemonAppSource = new Lang.Class({
|
||||
Name: 'GtkNotificationDaemonAppSource',
|
||||
Extends: MessageTray.Source,
|
||||
|
||||
_init: function(appId) {
|
||||
this._appId = appId;
|
||||
this._objectPath = objectPathFromAppId(appId);
|
||||
|
||||
this._app = Shell.AppSystem.get_default().lookup_app(appId + '.desktop');
|
||||
if (!this._app)
|
||||
throw new InvalidAppError();
|
||||
|
||||
this._notifications = {};
|
||||
|
||||
this.parent(this._app.get_name());
|
||||
},
|
||||
|
||||
createIcon: function(size) {
|
||||
return this._app.create_icon_texture(size);
|
||||
},
|
||||
|
||||
_createPolicy: function() {
|
||||
return new MessageTray.NotificationApplicationPolicy(this._appId);
|
||||
},
|
||||
|
||||
_createApp: function() {
|
||||
return new FdoApplicationProxy(Gio.DBus.session, this._appId, this._objectPath);
|
||||
},
|
||||
|
||||
activateAction: function(actionId, target) {
|
||||
let app = this._createApp();
|
||||
app.ActivateActionRemote(actionId, target ? [target] : [], getPlatformData());
|
||||
},
|
||||
|
||||
open: function() {
|
||||
let app = this._createApp();
|
||||
app.ActivateRemote(getPlatformData());
|
||||
},
|
||||
|
||||
addNotification: function(notificationId, notificationParams, showBanner) {
|
||||
if (this._notifications[notificationId])
|
||||
this._notifications[notificationId].destroy();
|
||||
|
||||
let notification = new GtkNotificationDaemonNotification(this, notificationParams);
|
||||
notification.connect('destroy', Lang.bind(this, function() {
|
||||
delete this._notifications[notificationId];
|
||||
}));
|
||||
this._notifications[notificationId] = notification;
|
||||
|
||||
if (showBanner)
|
||||
this.notify(notification);
|
||||
else
|
||||
this.pushNotification(notification);
|
||||
},
|
||||
|
||||
removeNotification: function(notificationId) {
|
||||
if (this._notifications[notificationId])
|
||||
this._notifications[notificationId].destroy(MessageTray.NotificationDestroyedReason.SOURCE_CLOSED);
|
||||
},
|
||||
|
||||
serialize: function() {
|
||||
let notifications = [];
|
||||
for (let notificationId in this._notifications) {
|
||||
let notification = this._notifications[notificationId];
|
||||
notifications.push([notificationId, notification.serialize()]);
|
||||
}
|
||||
return [this._appId, notifications];
|
||||
},
|
||||
});
|
||||
|
||||
const GtkNotificationsIface = '<node> \
|
||||
<interface name="org.gtk.Notifications"> \
|
||||
<method name="AddNotification"> \
|
||||
<arg type="s" direction="in" /> \
|
||||
<arg type="s" direction="in" /> \
|
||||
<arg type="a{sv}" direction="in" /> \
|
||||
</method> \
|
||||
<method name="RemoveNotification"> \
|
||||
<arg type="s" direction="in" /> \
|
||||
<arg type="s" direction="in" /> \
|
||||
</method> \
|
||||
</interface> \
|
||||
</node>';
|
||||
|
||||
const GtkNotificationDaemon = new Lang.Class({
|
||||
Name: 'GtkNotificationDaemon',
|
||||
|
||||
_init: function() {
|
||||
this._sources = {};
|
||||
|
||||
this._loadNotifications();
|
||||
|
||||
this._dbusImpl = Gio.DBusExportedObject.wrapJSObject(GtkNotificationsIface, this);
|
||||
this._dbusImpl.export(Gio.DBus.session, '/org/gtk/Notifications');
|
||||
|
||||
Gio.DBus.session.own_name('org.gtk.Notifications', Gio.BusNameOwnerFlags.REPLACE, null, null);
|
||||
},
|
||||
|
||||
_ensureAppSource: function(appId) {
|
||||
if (this._sources[appId])
|
||||
return this._sources[appId];
|
||||
|
||||
let source = new GtkNotificationDaemonAppSource(appId);
|
||||
|
||||
source.connect('destroy', Lang.bind(this, function() {
|
||||
delete this._sources[appId];
|
||||
this._saveNotifications();
|
||||
}));
|
||||
source.connect('count-updated', Lang.bind(this, this._saveNotifications));
|
||||
Main.messageTray.add(source);
|
||||
this._sources[appId] = source;
|
||||
return source;
|
||||
},
|
||||
|
||||
_loadNotifications: function() {
|
||||
this._isLoading = true;
|
||||
|
||||
let value = global.get_persistent_state('a(sa(sv))', 'notifications');
|
||||
if (value) {
|
||||
let sources = value.deep_unpack();
|
||||
sources.forEach(Lang.bind(this, function([appId, notifications]) {
|
||||
if (notifications.length == 0)
|
||||
return;
|
||||
|
||||
let source;
|
||||
try {
|
||||
source = this._ensureAppSource(appId);
|
||||
} catch(e if e instanceof InvalidAppError) {
|
||||
return;
|
||||
}
|
||||
|
||||
notifications.forEach(function([notificationId, notification]) {
|
||||
source.addNotification(notificationId, notification.deep_unpack(), false);
|
||||
});
|
||||
}));
|
||||
}
|
||||
|
||||
this._isLoading = false;
|
||||
},
|
||||
|
||||
_saveNotifications: function() {
|
||||
if (this._isLoading)
|
||||
return;
|
||||
|
||||
let sources = [];
|
||||
for (let appId in this._sources) {
|
||||
let source = this._sources[appId];
|
||||
sources.push(source.serialize());
|
||||
}
|
||||
|
||||
global.set_persistent_state('notifications', new GLib.Variant('a(sa(sv))', sources));
|
||||
},
|
||||
|
||||
AddNotificationAsync: function(params, invocation) {
|
||||
let [appId, notificationId, notification] = params;
|
||||
|
||||
let source;
|
||||
try {
|
||||
source = this._ensureAppSource(appId);
|
||||
} catch(e if e instanceof InvalidAppError) {
|
||||
invocation.return_dbus_error('org.gtk.Notifications.InvalidApp', 'The app by ID "%s" could not be found'.format(appId));
|
||||
return;
|
||||
}
|
||||
|
||||
source.addNotification(notificationId, notification, true);
|
||||
|
||||
invocation.return_value(null);
|
||||
},
|
||||
|
||||
RemoveNotificationAsync: function(params, invocation) {
|
||||
let [appId, notificationId] = params;
|
||||
let source = this._sources[appId];
|
||||
if (source)
|
||||
source.removeNotification(notificationId);
|
||||
|
||||
invocation.return_value(null);
|
||||
},
|
||||
});
|
||||
|
||||
const NotificationDaemon = new Lang.Class({
|
||||
Name: 'NotificationDaemon',
|
||||
|
||||
_init: function() {
|
||||
this._fdoNotificationDaemon = new FdoNotificationDaemon();
|
||||
this._gtkNotificationDaemon = new GtkNotificationDaemon();
|
||||
},
|
||||
});
|
||||
|
@ -1,7 +1,6 @@
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
|
||||
const Clutter = imports.gi.Clutter;
|
||||
const GLib = imports.gi.GLib;
|
||||
const St = imports.gi.St;
|
||||
|
||||
const Lang = imports.lang;
|
||||
@ -78,8 +77,7 @@ const OsdWindow = new Lang.Class({
|
||||
y_expand: true,
|
||||
x_align: Clutter.ActorAlign.CENTER,
|
||||
y_align: Clutter.ActorAlign.CENTER });
|
||||
this._currentMonitor = undefined;
|
||||
this.setMonitor (-1);
|
||||
this.actor.add_constraint(new Layout.MonitorConstraint({ primary: true }));
|
||||
this._box = new St.BoxLayout({ style_class: 'osd-window',
|
||||
vertical: true });
|
||||
this.actor.add_actor(this._box);
|
||||
@ -174,7 +172,6 @@ const OsdWindow = new Lang.Class({
|
||||
Meta.enable_unredirect_for_screen(global.screen);
|
||||
})
|
||||
});
|
||||
return GLib.SOURCE_REMOVE;
|
||||
},
|
||||
|
||||
_reset: function() {
|
||||
@ -185,13 +182,7 @@ const OsdWindow = new Lang.Class({
|
||||
|
||||
_monitorsChanged: function() {
|
||||
/* assume 110x110 on a 640x480 display and scale from there */
|
||||
let monitor;
|
||||
|
||||
if (this._currentMonitor >= 0)
|
||||
monitor = Main.layoutManager.monitors[this._currentMonitor];
|
||||
else
|
||||
monitor = Main.layoutManager.primaryMonitor;
|
||||
|
||||
let monitor = Main.layoutManager.primaryMonitor;
|
||||
let scalew = monitor.width / 640.0;
|
||||
let scaleh = monitor.height / 480.0;
|
||||
let scale = Math.min(scalew, scaleh);
|
||||
@ -215,23 +206,5 @@ const OsdWindow = new Lang.Class({
|
||||
let minHeight = this._popupSize - horizontalPadding - topBorder - bottomBorder;
|
||||
|
||||
this._box.style = 'min-height: %dpx;'.format(Math.max(minWidth, minHeight));
|
||||
},
|
||||
|
||||
setMonitor: function(index) {
|
||||
let constraint;
|
||||
|
||||
if (index < 0)
|
||||
index = -1;
|
||||
if (this._currentMonitor == index)
|
||||
return;
|
||||
|
||||
if (index < 0)
|
||||
constraint = new Layout.MonitorConstraint({ primary: true });
|
||||
else
|
||||
constraint = new Layout.MonitorConstraint({ index: index });
|
||||
|
||||
this.actor.clear_constraints();
|
||||
this.actor.add_constraint(constraint);
|
||||
this._currentMonitor = index;
|
||||
}
|
||||
});
|
||||
|
@ -1,7 +1,6 @@
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
|
||||
const Clutter = imports.gi.Clutter;
|
||||
const GLib = imports.gi.GLib;
|
||||
const Gtk = imports.gi.Gtk;
|
||||
const Meta = imports.gi.Meta;
|
||||
const Mainloop = imports.mainloop;
|
||||
@ -79,8 +78,10 @@ const ShellInfo = new Lang.Class({
|
||||
}
|
||||
|
||||
this._undoCallback = undoCallback;
|
||||
if (undoCallback)
|
||||
notification.addAction(_("Undo"), Lang.bind(this, this._onUndoClicked));
|
||||
if (undoCallback) {
|
||||
notification.addButton('system-undo', _("Undo"));
|
||||
notification.connect('action-invoked', Lang.bind(this, this._onUndoClicked));
|
||||
}
|
||||
|
||||
this._source.notify(notification);
|
||||
}
|
||||
@ -113,6 +114,9 @@ const Overview = new Lang.Class({
|
||||
// rendering options without duplicating the texture data.
|
||||
let monitor = Main.layoutManager.primaryMonitor;
|
||||
|
||||
this._desktopFade = new St.Bin();
|
||||
Main.layoutManager.overviewGroup.add_child(this._desktopFade);
|
||||
|
||||
let layout = new Clutter.BinLayout();
|
||||
this._stack = new Clutter.Actor({ layout_manager: layout });
|
||||
this._stack.add_constraint(new LayoutManager.MonitorConstraint({ primary: true }));
|
||||
@ -131,9 +135,6 @@ const Overview = new Lang.Class({
|
||||
Main.layoutManager.overviewGroup.add_child(this._backgroundGroup);
|
||||
this._bgManagers = [];
|
||||
|
||||
this._desktopFade = new St.Bin();
|
||||
Main.layoutManager.overviewGroup.add_child(this._desktopFade);
|
||||
|
||||
this._activationTime = 0;
|
||||
|
||||
this.visible = false; // animating to overview, in overview, animating out
|
||||
@ -148,7 +149,7 @@ const Overview = new Lang.Class({
|
||||
this._coverPane = new Clutter.Actor({ opacity: 0,
|
||||
reactive: true });
|
||||
Main.layoutManager.overviewGroup.add_child(this._coverPane);
|
||||
this._coverPane.connect('event', Lang.bind(this, function (actor, event) { return Clutter.EVENT_STOP; }));
|
||||
this._coverPane.connect('event', Lang.bind(this, function (actor, event) { return true; }));
|
||||
|
||||
this._stack.add_actor(this._overview);
|
||||
Main.layoutManager.overviewGroup.add_child(this._stack);
|
||||
@ -312,6 +313,9 @@ const Overview = new Lang.Class({
|
||||
},
|
||||
|
||||
_onDragEnd: function(time) {
|
||||
if (this.animationInProgress)
|
||||
return;
|
||||
|
||||
this._inXdndDrag = false;
|
||||
|
||||
// In case the drag was canceled while in the overview
|
||||
@ -364,13 +368,11 @@ const Overview = new Lang.Class({
|
||||
this._lastHoveredWindow = dragEvent.targetActor._delegate.metaWindow;
|
||||
this._windowSwitchTimeoutId = Mainloop.timeout_add(DND_WINDOW_SWITCH_TIMEOUT,
|
||||
Lang.bind(this, function() {
|
||||
this._windowSwitchTimeoutId = 0;
|
||||
this._needsFakePointerEvent = true;
|
||||
Main.activateWindow(dragEvent.targetActor._delegate.metaWindow,
|
||||
this._windowSwitchTimestamp);
|
||||
this.hide();
|
||||
this._lastHoveredWindow = null;
|
||||
return GLib.SOURCE_REMOVE;
|
||||
}));
|
||||
}
|
||||
|
||||
@ -379,7 +381,6 @@ const Overview = new Lang.Class({
|
||||
|
||||
_onScrollEvent: function(actor, event) {
|
||||
this.emit('scroll-event', event);
|
||||
return Clutter.EVENT_PROPAGATE;
|
||||
},
|
||||
|
||||
addAction: function(action) {
|
||||
@ -447,17 +448,17 @@ const Overview = new Lang.Class({
|
||||
this._inDrag = false;
|
||||
},
|
||||
|
||||
beginWindowDrag: function(clone) {
|
||||
this.emit('window-drag-begin', clone);
|
||||
beginWindowDrag: function(source) {
|
||||
this.emit('window-drag-begin');
|
||||
this._inDrag = true;
|
||||
},
|
||||
|
||||
cancelledWindowDrag: function(clone) {
|
||||
this.emit('window-drag-cancelled', clone);
|
||||
cancelledWindowDrag: function(source) {
|
||||
this.emit('window-drag-cancelled');
|
||||
},
|
||||
|
||||
endWindowDrag: function(clone) {
|
||||
this.emit('window-drag-end', clone);
|
||||
endWindowDrag: function(source) {
|
||||
this.emit('window-drag-end');
|
||||
this._inDrag = false;
|
||||
},
|
||||
|
||||
|
@ -36,7 +36,6 @@ const SlideLayout = new Lang.Class({
|
||||
|
||||
_init: function(params) {
|
||||
this._slideX = 1;
|
||||
this._translationX = 0;
|
||||
this._direction = SlideDirection.LEFT;
|
||||
|
||||
this.parent(params);
|
||||
@ -56,21 +55,18 @@ const SlideLayout = new Lang.Class({
|
||||
vfunc_allocate: function(container, box, flags) {
|
||||
let child = container.get_first_child();
|
||||
|
||||
let [, , natWidth, natHeight] = child.get_preferred_size();
|
||||
let availWidth = Math.round(box.x2 - box.x1);
|
||||
let availHeight = Math.round(box.y2 - box.y1);
|
||||
let [, natWidth] = child.get_preferred_width(availHeight);
|
||||
|
||||
// Align the actor inside the clipped box, as the actor's alignment
|
||||
// flags only determine what to do if the allocated box is bigger
|
||||
// than the actor's box.
|
||||
let realDirection = getRtlSlideDirection(this._direction, child);
|
||||
let alignX = (realDirection == SlideDirection.LEFT) ? (availWidth - natWidth) : 0;
|
||||
let translationX = (realDirection == SlideDirection.LEFT) ?
|
||||
(availWidth - natWidth) : (natWidth - availWidth);
|
||||
|
||||
let actorBox = new Clutter.ActorBox();
|
||||
actorBox.x1 = box.x1 + alignX + this._translationX;
|
||||
actorBox.x2 = actorBox.x1 + (child.x_expand ? availWidth : natWidth);
|
||||
actorBox.y1 = box.y1;
|
||||
actorBox.y2 = actorBox.y1 + availHeight;
|
||||
let actorBox = new Clutter.ActorBox({ x1: translationX,
|
||||
y1: 0,
|
||||
x2: child.x_expand ? availWidth : natWidth,
|
||||
y2: child.y_expand ? availHeight : natHeight });
|
||||
|
||||
child.allocate(actorBox, flags);
|
||||
},
|
||||
@ -91,16 +87,7 @@ const SlideLayout = new Lang.Class({
|
||||
|
||||
get slideDirection() {
|
||||
return this._direction;
|
||||
},
|
||||
|
||||
set translationX(value) {
|
||||
this._translationX = value;
|
||||
this.layout_changed();
|
||||
},
|
||||
|
||||
get translationX() {
|
||||
return this._translationX;
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
const SlidingControl = new Lang.Class({
|
||||
@ -109,8 +96,8 @@ const SlidingControl = new Lang.Class({
|
||||
_init: function(params) {
|
||||
params = Params.parse(params, { slideDirection: SlideDirection.LEFT });
|
||||
|
||||
this._visible = true;
|
||||
this._inDrag = false;
|
||||
this.visible = true;
|
||||
this.inDrag = false;
|
||||
|
||||
this.layout = new SlideLayout();
|
||||
this.layout.slideDirection = params.slideDirection;
|
||||
@ -119,7 +106,6 @@ const SlidingControl = new Lang.Class({
|
||||
clip_to_allocation: true });
|
||||
|
||||
Main.overview.connect('showing', Lang.bind(this, this._onOverviewShowing));
|
||||
Main.overview.connect('hiding', Lang.bind(this, this._onOverviewHiding));
|
||||
|
||||
Main.overview.connect('item-drag-begin', Lang.bind(this, this._onDragBegin));
|
||||
Main.overview.connect('item-drag-end', Lang.bind(this, this._onDragEnd));
|
||||
@ -130,12 +116,12 @@ const SlidingControl = new Lang.Class({
|
||||
Main.overview.connect('window-drag-end', Lang.bind(this, this._onWindowDragEnd));
|
||||
},
|
||||
|
||||
_getSlide: function() {
|
||||
getSlide: function() {
|
||||
throw new Error('getSlide() must be overridden');
|
||||
},
|
||||
|
||||
_updateSlide: function() {
|
||||
Tweener.addTween(this.layout, { slideX: this._getSlide(),
|
||||
updateSlide: function() {
|
||||
Tweener.addTween(this.layout, { slideX: this.getSlide(),
|
||||
time: SIDE_CONTROLS_ANIMATION_TIME,
|
||||
transition: 'easeOutQuad' });
|
||||
},
|
||||
@ -162,30 +148,28 @@ const SlidingControl = new Lang.Class({
|
||||
let translationEnd = 0;
|
||||
let translation = this._getTranslation();
|
||||
|
||||
if (this._visible) {
|
||||
if (this.visible) {
|
||||
translationStart = translation;
|
||||
} else {
|
||||
translationEnd = translation;
|
||||
}
|
||||
|
||||
if (this.layout.translationX == translationEnd)
|
||||
if (this.actor.translation_x == translationEnd)
|
||||
return;
|
||||
|
||||
this.layout.translationX = translationStart;
|
||||
Tweener.addTween(this.layout, { translationX: translationEnd,
|
||||
time: SIDE_CONTROLS_ANIMATION_TIME,
|
||||
transition: 'easeOutQuad' });
|
||||
this.actor.translation_x = translationStart;
|
||||
Tweener.addTween(this.actor, { translation_x: translationEnd,
|
||||
time: SIDE_CONTROLS_ANIMATION_TIME,
|
||||
transition: 'easeOutQuad'
|
||||
});
|
||||
},
|
||||
|
||||
_onOverviewShowing: function() {
|
||||
this._visible = true;
|
||||
this.layout.slideX = this._getSlide();
|
||||
this.layout.translationX = this._getTranslation();
|
||||
this.slideIn();
|
||||
},
|
||||
|
||||
_onOverviewHiding: function() {
|
||||
this.slideOut();
|
||||
// reset any translation and make sure the actor is visible when
|
||||
// entering the overview
|
||||
this.visible = true;
|
||||
this.layout.slideX = this.getSlide();
|
||||
this.actor.translation_x = 0;
|
||||
},
|
||||
|
||||
_onWindowDragBegin: function() {
|
||||
@ -197,14 +181,14 @@ const SlidingControl = new Lang.Class({
|
||||
},
|
||||
|
||||
_onDragBegin: function() {
|
||||
this._inDrag = true;
|
||||
this.layout.translationX = 0;
|
||||
this._updateSlide();
|
||||
this.inDrag = true;
|
||||
this.actor.translation_x = 0;
|
||||
this.updateSlide();
|
||||
},
|
||||
|
||||
_onDragEnd: function() {
|
||||
this._inDrag = false;
|
||||
this._updateSlide();
|
||||
this.inDrag = false;
|
||||
this.updateSlide();
|
||||
},
|
||||
|
||||
fadeIn: function() {
|
||||
@ -222,13 +206,13 @@ const SlidingControl = new Lang.Class({
|
||||
},
|
||||
|
||||
slideIn: function() {
|
||||
this._visible = true;
|
||||
this.visible = true;
|
||||
this._updateTranslation();
|
||||
// we will update slideX and the translation from pageEmpty
|
||||
},
|
||||
|
||||
slideOut: function() {
|
||||
this._visible = false;
|
||||
this.visible = false;
|
||||
this._updateTranslation();
|
||||
// we will update slideX from pageEmpty
|
||||
},
|
||||
@ -238,7 +222,7 @@ const SlidingControl = new Lang.Class({
|
||||
// selector; this means we can now safely set the full slide for
|
||||
// the next page, since slideIn or slideOut might have been called,
|
||||
// changing the visiblity
|
||||
this.layout.slideX = this._getSlide();
|
||||
this.layout.slideX = this.getSlide();
|
||||
this._updateTranslation();
|
||||
}
|
||||
});
|
||||
@ -252,20 +236,26 @@ const ThumbnailsSlider = new Lang.Class({
|
||||
|
||||
this._thumbnailsBox = thumbnailsBox;
|
||||
|
||||
// SlideLayout reads the actor's expand flags to decide
|
||||
// whether to allocate the natural size to its child, or the whole
|
||||
// available allocation
|
||||
this._thumbnailsBox.actor.y_expand = true;
|
||||
|
||||
this.actor.request_mode = Clutter.RequestMode.WIDTH_FOR_HEIGHT;
|
||||
this.actor.reactive = true;
|
||||
this.actor.track_hover = true;
|
||||
this.actor.add_actor(this._thumbnailsBox.actor);
|
||||
|
||||
Main.layoutManager.connect('monitors-changed', Lang.bind(this, this._updateSlide));
|
||||
this.actor.connect('notify::hover', Lang.bind(this, this._updateSlide));
|
||||
Main.layoutManager.connect('monitors-changed', Lang.bind(this, this.updateSlide));
|
||||
Main.overview.connect('hiding', Lang.bind(this, this.slideOut));
|
||||
this.actor.connect('notify::hover', Lang.bind(this, this.updateSlide));
|
||||
this._thumbnailsBox.actor.bind_property('visible', this.actor, 'visible', GObject.BindingFlags.SYNC_CREATE);
|
||||
},
|
||||
|
||||
_getAlwaysZoomOut: function() {
|
||||
// Always show the pager when hover, during a drag, or if workspaces are
|
||||
// actually used, e.g. there are windows on more than one
|
||||
let alwaysZoomOut = this.actor.hover || this._inDrag || !Meta.prefs_get_dynamic_workspaces() || global.screen.n_workspaces > 2;
|
||||
let alwaysZoomOut = this.actor.hover || this.inDrag || !Meta.prefs_get_dynamic_workspaces() || global.screen.n_workspaces > 2;
|
||||
|
||||
if (!alwaysZoomOut) {
|
||||
let monitors = Main.layoutManager.monitors;
|
||||
@ -285,13 +275,20 @@ const ThumbnailsSlider = new Lang.Class({
|
||||
return alwaysZoomOut;
|
||||
},
|
||||
|
||||
_onOverviewShowing: function() {
|
||||
this.visible = true;
|
||||
this.layout.slideX = this.getSlide();
|
||||
this.actor.translation_x = this._getTranslation();
|
||||
this.slideIn();
|
||||
},
|
||||
|
||||
getNonExpandedWidth: function() {
|
||||
let child = this.actor.get_first_child();
|
||||
return child.get_theme_node().get_length('visible-width');
|
||||
},
|
||||
|
||||
_getSlide: function() {
|
||||
if (!this._visible)
|
||||
getSlide: function() {
|
||||
if (!this.visible)
|
||||
return 0;
|
||||
|
||||
let alwaysZoomOut = this._getAlwaysZoomOut();
|
||||
@ -327,23 +324,31 @@ const DashSlider = new Lang.Class({
|
||||
// whether to allocate the natural size to its child, or the whole
|
||||
// available allocation
|
||||
this._dash.actor.x_expand = true;
|
||||
this._dash.actor.y_expand = true;
|
||||
|
||||
this.actor.x_expand = true;
|
||||
this.actor.x_align = Clutter.ActorAlign.START;
|
||||
this.actor.y_expand = true;
|
||||
|
||||
this.actor.add_actor(this._dash.actor);
|
||||
|
||||
this._dash.connect('icon-size-changed', Lang.bind(this, this._updateSlide));
|
||||
this._dash.connect('icon-size-changed', Lang.bind(this, this.updateSlide));
|
||||
Main.overview.connect('hiding', Lang.bind(this, this.slideOut));
|
||||
},
|
||||
|
||||
_getSlide: function() {
|
||||
if (this._visible || this._inDrag)
|
||||
getSlide: function() {
|
||||
if (this.visible || this.inDrag)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
},
|
||||
|
||||
_onOverviewShowing: function() {
|
||||
this.visible = true;
|
||||
this.layout.slideX = this.getSlide();
|
||||
this.actor.translation_x = this._getTranslation();
|
||||
this.slideIn();
|
||||
},
|
||||
|
||||
_onWindowDragBegin: function() {
|
||||
this.fadeHalf();
|
||||
},
|
||||
@ -460,6 +465,9 @@ const MessagesIndicator = new Lang.Class({
|
||||
if (source.trayIcon)
|
||||
return;
|
||||
|
||||
if (source.isTransient)
|
||||
return;
|
||||
|
||||
source.connect('count-updated', Lang.bind(this, this._updateCount));
|
||||
this._sources.push(source);
|
||||
this._updateCount();
|
||||
|
@ -213,7 +213,9 @@ const AppMenuButton = new Lang.Class({
|
||||
this._label = new TextShadower();
|
||||
this._label.actor.y_align = Clutter.ActorAlign.CENTER;
|
||||
this._hbox.add_actor(this._label.actor);
|
||||
this._arrow = PopupMenu.unicodeArrow(St.Side.BOTTOM);
|
||||
this._arrow = new St.Label({ text: '\u25BE',
|
||||
y_expand: true,
|
||||
y_align: Clutter.ActorAlign.CENTER });
|
||||
this._hbox.add_actor(this._arrow);
|
||||
|
||||
this._iconBottomClip = 0;
|
||||
@ -602,15 +604,14 @@ const ActivitiesButton = new Lang.Class({
|
||||
_onCapturedEvent: function(actor, event) {
|
||||
if (event.type() == Clutter.EventType.BUTTON_PRESS) {
|
||||
if (!Main.overview.shouldToggleByCornerOrButton())
|
||||
return Clutter.EVENT_STOP;
|
||||
return true;
|
||||
}
|
||||
return Clutter.EVENT_PROPAGATE;
|
||||
return false;
|
||||
},
|
||||
|
||||
_onButtonRelease: function() {
|
||||
Main.overview.toggle();
|
||||
this.menu.close();
|
||||
return Clutter.EVENT_PROPAGATE;
|
||||
},
|
||||
|
||||
_onKeyRelease: function(actor, event) {
|
||||
@ -618,7 +619,6 @@ const ActivitiesButton = new Lang.Class({
|
||||
if (symbol == Clutter.KEY_Return || symbol == Clutter.KEY_space) {
|
||||
Main.overview.toggle();
|
||||
}
|
||||
return Clutter.EVENT_PROPAGATE;
|
||||
},
|
||||
|
||||
_xdndToggleOverview: function(actor) {
|
||||
@ -630,7 +630,6 @@ const ActivitiesButton = new Lang.Class({
|
||||
|
||||
Mainloop.source_remove(this._xdndTimeOut);
|
||||
this._xdndTimeOut = 0;
|
||||
return GLib.SOURCE_REMOVE;
|
||||
}
|
||||
});
|
||||
|
||||
@ -834,7 +833,9 @@ const AggregateMenu = new Lang.Class({
|
||||
this._indicators.add_child(this._rfkill.indicators);
|
||||
this._indicators.add_child(this._volume.indicators);
|
||||
this._indicators.add_child(this._power.indicators);
|
||||
this._indicators.add_child(PopupMenu.unicodeArrow(St.Side.BOTTOM));
|
||||
this._indicators.add_child(new St.Label({ text: '\u25BE',
|
||||
y_expand: true,
|
||||
y_align: Clutter.ActorAlign.CENTER }));
|
||||
|
||||
this.menu.addMenuItem(this._volume.menu);
|
||||
this.menu.addMenuItem(this._brightness.menu);
|
||||
@ -986,23 +987,23 @@ const Panel = new Lang.Class({
|
||||
|
||||
_onButtonPress: function(actor, event) {
|
||||
if (Main.modalCount > 0)
|
||||
return Clutter.EVENT_PROPAGATE;
|
||||
return false;
|
||||
|
||||
if (event.get_source() != actor)
|
||||
return Clutter.EVENT_PROPAGATE;
|
||||
return false;
|
||||
|
||||
let button = event.get_button();
|
||||
if (button != 1)
|
||||
return Clutter.EVENT_PROPAGATE;
|
||||
return false;
|
||||
|
||||
let focusWindow = global.display.focus_window;
|
||||
if (!focusWindow)
|
||||
return Clutter.EVENT_PROPAGATE;
|
||||
return false;
|
||||
|
||||
let dragWindow = focusWindow.is_attached_dialog() ? focusWindow.get_transient_for()
|
||||
: focusWindow;
|
||||
if (!dragWindow)
|
||||
return Clutter.EVENT_PROPAGATE;
|
||||
return false;
|
||||
|
||||
let rect = dragWindow.get_outer_rect();
|
||||
let [stageX, stageY] = event.get_coords();
|
||||
@ -1011,7 +1012,7 @@ const Panel = new Lang.Class({
|
||||
stageX > rect.x && stageX < rect.x + rect.width;
|
||||
|
||||
if (!allowDrag)
|
||||
return Clutter.EVENT_PROPAGATE;
|
||||
return false;
|
||||
|
||||
global.display.begin_grab_op(global.screen,
|
||||
dragWindow,
|
||||
@ -1023,7 +1024,7 @@ const Panel = new Lang.Class({
|
||||
event.get_time(),
|
||||
stageX, stageY);
|
||||
|
||||
return Clutter.EVENT_STOP;
|
||||
return true;
|
||||
},
|
||||
|
||||
toggleAppMenu: function() {
|
||||
|
@ -137,30 +137,29 @@ const Button = new Lang.Class({
|
||||
|
||||
_onButtonPress: function(actor, event) {
|
||||
if (!this.menu)
|
||||
return Clutter.EVENT_PROPAGATE;
|
||||
return;
|
||||
|
||||
this.menu.toggle();
|
||||
return Clutter.EVENT_PROPAGATE;
|
||||
},
|
||||
|
||||
_onSourceKeyPress: function(actor, event) {
|
||||
if (!this.menu)
|
||||
return Clutter.EVENT_PROPAGATE;
|
||||
return false;
|
||||
|
||||
let symbol = event.get_key_symbol();
|
||||
if (symbol == Clutter.KEY_space || symbol == Clutter.KEY_Return) {
|
||||
this.menu.toggle();
|
||||
return Clutter.EVENT_STOP;
|
||||
return true;
|
||||
} else if (symbol == Clutter.KEY_Escape && this.menu.isOpen) {
|
||||
this.menu.close();
|
||||
return Clutter.EVENT_STOP;
|
||||
return true;
|
||||
} else if (symbol == Clutter.KEY_Down) {
|
||||
if (!this.menu.isOpen)
|
||||
this.menu.toggle();
|
||||
this.menu.actor.navigate_focus(this.actor, Gtk.DirectionType.DOWN, false);
|
||||
return Clutter.EVENT_STOP;
|
||||
return true;
|
||||
} else
|
||||
return Clutter.EVENT_PROPAGATE;
|
||||
return false;
|
||||
},
|
||||
|
||||
_onVisibilityChanged: function() {
|
||||
@ -173,7 +172,7 @@ const Button = new Lang.Class({
|
||||
|
||||
_onMenuKeyPress: function(actor, event) {
|
||||
if (global.focus_manager.navigate_from_event(event))
|
||||
return Clutter.EVENT_STOP;
|
||||
return true;
|
||||
|
||||
let symbol = event.get_key_symbol();
|
||||
if (symbol == Clutter.KEY_Left || symbol == Clutter.KEY_Right) {
|
||||
@ -181,10 +180,10 @@ const Button = new Lang.Class({
|
||||
if (group) {
|
||||
let direction = (symbol == Clutter.KEY_Left) ? Gtk.DirectionType.LEFT : Gtk.DirectionType.RIGHT;
|
||||
group.navigate_focus(this.actor, direction, false);
|
||||
return Clutter.EVENT_STOP;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return Clutter.EVENT_PROPAGATE;
|
||||
return false;
|
||||
},
|
||||
|
||||
_onOpenStateChanged: function(menu, open) {
|
||||
|
@ -1,6 +1,5 @@
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
|
||||
const GLib = imports.gi.GLib;
|
||||
const Lang = imports.lang;
|
||||
const Mainloop = imports.mainloop;
|
||||
const Meta = imports.gi.Meta;
|
||||
@ -111,7 +110,7 @@ const PointerWatcher = new Lang.Class({
|
||||
|
||||
_onTimeout: function() {
|
||||
this._updatePointer();
|
||||
return GLib.SOURCE_CONTINUE;
|
||||
return true;
|
||||
},
|
||||
|
||||
_updatePointer: function() {
|
||||
|
@ -42,33 +42,6 @@ function isPopupMenuItemVisible(child) {
|
||||
return child.visible;
|
||||
}
|
||||
|
||||
/**
|
||||
* @side Side to which the arrow points.
|
||||
*/
|
||||
function unicodeArrow(side) {
|
||||
let arrowChar;
|
||||
switch (side) {
|
||||
case St.Side.TOP:
|
||||
arrowChar = '\u25B4';
|
||||
break;
|
||||
case St.Side.RIGHT:
|
||||
arrowChar = '\u25B8';
|
||||
break;
|
||||
case St.Side.BOTTOM:
|
||||
arrowChar = '\u25BE';
|
||||
break;
|
||||
case St.Side.LEFT:
|
||||
arrowChar = '\u25C2';
|
||||
break;
|
||||
}
|
||||
|
||||
return new St.Label({ text: arrowChar,
|
||||
style_class: 'unicode-arrow',
|
||||
accessible_role: Atk.Role.ARROW,
|
||||
y_expand: true,
|
||||
y_align: Clutter.ActorAlign.CENTER });
|
||||
}
|
||||
|
||||
const PopupBaseMenuItem = new Lang.Class({
|
||||
Name: 'PopupBaseMenuItem',
|
||||
|
||||
@ -126,7 +99,7 @@ const PopupBaseMenuItem = new Lang.Class({
|
||||
|
||||
_onButtonReleaseEvent: function (actor, event) {
|
||||
this.activate(event);
|
||||
return Clutter.EVENT_STOP;
|
||||
return true;
|
||||
},
|
||||
|
||||
_onKeyPressEvent: function (actor, event) {
|
||||
@ -134,9 +107,9 @@ const PopupBaseMenuItem = new Lang.Class({
|
||||
|
||||
if (symbol == Clutter.KEY_space || symbol == Clutter.KEY_Return) {
|
||||
this.activate(event);
|
||||
return Clutter.EVENT_STOP;
|
||||
return true;
|
||||
}
|
||||
return Clutter.EVENT_PROPAGATE;
|
||||
return false;
|
||||
},
|
||||
|
||||
_onKeyFocusIn: function (actor) {
|
||||
@ -928,10 +901,10 @@ const PopupSubMenu = new Lang.Class({
|
||||
if (this.isOpen && event.get_key_symbol() == Clutter.KEY_Left) {
|
||||
this.close(BoxPointer.PopupAnimation.FULL);
|
||||
this.sourceActor._delegate.setActive(true);
|
||||
return Clutter.EVENT_STOP;
|
||||
return true;
|
||||
}
|
||||
|
||||
return Clutter.EVENT_PROPAGATE;
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
@ -989,7 +962,8 @@ const PopupSubMenuMenuItem = new Lang.Class({
|
||||
y_align: Clutter.ActorAlign.CENTER });
|
||||
this.actor.add_child(this.status);
|
||||
|
||||
this._triangle = unicodeArrow(St.Side.RIGHT);
|
||||
this._triangle = new St.Label({ text: '\u25B8',
|
||||
style_class: 'popup-submenu-menu-item-triangle' });
|
||||
this._triangle.pivot_point = new Clutter.Point({ x: 0.5, y: 0.6 });
|
||||
|
||||
this._triangleBin = new St.Widget({ y_expand: true,
|
||||
@ -1056,10 +1030,10 @@ const PopupSubMenuMenuItem = new Lang.Class({
|
||||
if (symbol == Clutter.KEY_Right) {
|
||||
this._setOpenState(true);
|
||||
this.menu.actor.navigate_focus(null, Gtk.DirectionType.DOWN, false);
|
||||
return Clutter.EVENT_STOP;
|
||||
return true;
|
||||
} else if (symbol == Clutter.KEY_Left && this._getOpenState()) {
|
||||
this._setOpenState(false);
|
||||
return Clutter.EVENT_STOP;
|
||||
return true;
|
||||
}
|
||||
|
||||
return this.parent(actor, event);
|
||||
@ -1071,7 +1045,6 @@ const PopupSubMenuMenuItem = new Lang.Class({
|
||||
|
||||
_onButtonReleaseEvent: function(actor) {
|
||||
this._setOpenState(!this._getOpenState());
|
||||
return Clutter.EVENT_PROPAGATE;
|
||||
}
|
||||
});
|
||||
|
||||
@ -1103,7 +1076,7 @@ const PopupMenuManager = new Lang.Class({
|
||||
if (source) {
|
||||
if (!menu.blockSourceEvents)
|
||||
this._grabHelper.addActor(source);
|
||||
menudata.enterId = source.connect('enter-event', Lang.bind(this, function() { return this._onMenuSourceEnter(menu); }));
|
||||
menudata.enterId = source.connect('enter-event', Lang.bind(this, function() { this._onMenuSourceEnter(menu); }));
|
||||
menudata.focusInId = source.connect('key-focus-in', Lang.bind(this, function() { this._onMenuSourceEnter(menu); }));
|
||||
}
|
||||
|
||||
@ -1115,7 +1088,7 @@ const PopupMenuManager = new Lang.Class({
|
||||
|
||||
removeMenu: function(menu) {
|
||||
if (menu == this.activeMenu)
|
||||
this._closeMenu(false, menu);
|
||||
this._closeMenu(menu);
|
||||
|
||||
let position = this._findMenu(menu);
|
||||
if (position == -1) // not a menu we manage
|
||||
@ -1165,13 +1138,13 @@ const PopupMenuManager = new Lang.Class({
|
||||
|
||||
_onMenuSourceEnter: function(menu) {
|
||||
if (!this._grabHelper.grabbed)
|
||||
return Clutter.EVENT_PROPAGATE;
|
||||
return false;
|
||||
|
||||
if (this._grabHelper.isActorGrabbed(menu.actor))
|
||||
return Clutter.EVENT_PROPAGATE;
|
||||
return false;
|
||||
|
||||
this._changeMenu(menu);
|
||||
return Clutter.EVENT_PROPAGATE;
|
||||
return false;
|
||||
},
|
||||
|
||||
_onMenuDestroy: function(menu) {
|
||||
|
@ -7,63 +7,58 @@ const Lang = imports.lang;
|
||||
const St = imports.gi.St;
|
||||
const Shell = imports.gi.Shell;
|
||||
|
||||
const FileUtils = imports.misc.fileUtils;
|
||||
const Search = imports.ui.search;
|
||||
|
||||
const KEY_FILE_GROUP = 'Shell Search Provider';
|
||||
|
||||
const SearchProviderIface = '<node> \
|
||||
<interface name="org.gnome.Shell.SearchProvider"> \
|
||||
<method name="GetInitialResultSet"> \
|
||||
<arg type="as" direction="in" /> \
|
||||
<arg type="as" direction="out" /> \
|
||||
</method> \
|
||||
<method name="GetSubsearchResultSet"> \
|
||||
<arg type="as" direction="in" /> \
|
||||
<arg type="as" direction="in" /> \
|
||||
<arg type="as" direction="out" /> \
|
||||
</method> \
|
||||
<method name="GetResultMetas"> \
|
||||
<arg type="as" direction="in" /> \
|
||||
<arg type="aa{sv}" direction="out" /> \
|
||||
</method> \
|
||||
<method name="ActivateResult"> \
|
||||
<arg type="s" direction="in" /> \
|
||||
</method> \
|
||||
</interface> \
|
||||
</node>';
|
||||
const SearchProviderIface = <interface name="org.gnome.Shell.SearchProvider">
|
||||
<method name="GetInitialResultSet">
|
||||
<arg type="as" direction="in" />
|
||||
<arg type="as" direction="out" />
|
||||
</method>
|
||||
<method name="GetSubsearchResultSet">
|
||||
<arg type="as" direction="in" />
|
||||
<arg type="as" direction="in" />
|
||||
<arg type="as" direction="out" />
|
||||
</method>
|
||||
<method name="GetResultMetas">
|
||||
<arg type="as" direction="in" />
|
||||
<arg type="aa{sv}" direction="out" />
|
||||
</method>
|
||||
<method name="ActivateResult">
|
||||
<arg type="s" direction="in" />
|
||||
</method>
|
||||
</interface>;
|
||||
|
||||
const SearchProvider2Iface = '<node> \
|
||||
<interface name="org.gnome.Shell.SearchProvider2"> \
|
||||
<method name="GetInitialResultSet"> \
|
||||
<arg type="as" direction="in" /> \
|
||||
<arg type="as" direction="out" /> \
|
||||
</method> \
|
||||
<method name="GetSubsearchResultSet"> \
|
||||
<arg type="as" direction="in" /> \
|
||||
<arg type="as" direction="in" /> \
|
||||
<arg type="as" direction="out" /> \
|
||||
</method> \
|
||||
<method name="GetResultMetas"> \
|
||||
<arg type="as" direction="in" /> \
|
||||
<arg type="aa{sv}" direction="out" /> \
|
||||
</method> \
|
||||
<method name="ActivateResult"> \
|
||||
<arg type="s" direction="in" /> \
|
||||
<arg type="as" direction="in" /> \
|
||||
<arg type="u" direction="in" /> \
|
||||
</method> \
|
||||
<method name="LaunchSearch"> \
|
||||
<arg type="as" direction="in" /> \
|
||||
<arg type="u" direction="in" /> \
|
||||
</method> \
|
||||
</interface> \
|
||||
</node>';
|
||||
const SearchProvider2Iface = <interface name="org.gnome.Shell.SearchProvider2">
|
||||
<method name="GetInitialResultSet">
|
||||
<arg type="as" direction="in" />
|
||||
<arg type="as" direction="out" />
|
||||
</method>
|
||||
<method name="GetSubsearchResultSet">
|
||||
<arg type="as" direction="in" />
|
||||
<arg type="as" direction="in" />
|
||||
<arg type="as" direction="out" />
|
||||
</method>
|
||||
<method name="GetResultMetas">
|
||||
<arg type="as" direction="in" />
|
||||
<arg type="aa{sv}" direction="out" />
|
||||
</method>
|
||||
<method name="ActivateResult">
|
||||
<arg type="s" direction="in" />
|
||||
<arg type="as" direction="in" />
|
||||
<arg type="u" direction="in" />
|
||||
</method>
|
||||
<method name="LaunchSearch">
|
||||
<arg type="as" direction="in" />
|
||||
<arg type="u" direction="in" />
|
||||
</method>
|
||||
</interface>;
|
||||
|
||||
var SearchProviderProxyInfo = Gio.DBusInterfaceInfo.new_for_xml(SearchProviderIface);
|
||||
var SearchProvider2ProxyInfo = Gio.DBusInterfaceInfo.new_for_xml(SearchProvider2Iface);
|
||||
var SearchProviderProxy = Gio.DBusProxy.makeProxyWrapper(SearchProviderIface);
|
||||
var SearchProvider2Proxy = Gio.DBusProxy.makeProxyWrapper(SearchProvider2Iface);
|
||||
|
||||
function loadRemoteSearchProviders(callback) {
|
||||
function loadRemoteSearchProviders(addProviderCallback) {
|
||||
let objectPaths = {};
|
||||
let loadedProviders = [];
|
||||
|
||||
@ -117,25 +112,30 @@ function loadRemoteSearchProviders(callback) {
|
||||
}
|
||||
}
|
||||
|
||||
let dataDirs = GLib.get_system_data_dirs();
|
||||
dataDirs.forEach(function(dataDir) {
|
||||
let path = GLib.build_filenamev([dataDir, 'gnome-shell', 'search-providers']);
|
||||
let dir = Gio.File.new_for_path(path);
|
||||
let fileEnum;
|
||||
try {
|
||||
fileEnum = dir.enumerate_children('standard::name,standard::type',
|
||||
Gio.FileQueryInfoFlags.NONE, null);
|
||||
} catch (e) {
|
||||
fileEnum = null;
|
||||
}
|
||||
if (fileEnum != null) {
|
||||
let info;
|
||||
while ((info = fileEnum.next_file(null)))
|
||||
loadRemoteSearchProvider(fileEnum.get_child(info));
|
||||
}
|
||||
});
|
||||
|
||||
let searchSettings = new Gio.Settings({ schema: Search.SEARCH_PROVIDERS_SCHEMA });
|
||||
if (searchSettings.get_boolean('disable-external')) {
|
||||
callback([]);
|
||||
return;
|
||||
}
|
||||
|
||||
FileUtils.collectFromDatadirs('search-providers', false, loadRemoteSearchProvider);
|
||||
|
||||
let sortOrder = searchSettings.get_strv('sort-order');
|
||||
|
||||
// Special case gnome-control-center to be always active and always first
|
||||
sortOrder.unshift('gnome-control-center.desktop');
|
||||
|
||||
loadedProviders = loadedProviders.filter(function(provider) {
|
||||
let appId = provider.appInfo.get_id();
|
||||
let disabled = searchSettings.get_strv('disabled');
|
||||
return disabled.indexOf(appId) == -1;
|
||||
});
|
||||
|
||||
loadedProviders.sort(function(providerA, providerB) {
|
||||
let idxA, idxB;
|
||||
let appIdA, appIdB;
|
||||
@ -166,34 +166,32 @@ function loadRemoteSearchProviders(callback) {
|
||||
return (idxA - idxB);
|
||||
});
|
||||
|
||||
callback(loadedProviders);
|
||||
loadedProviders.forEach(addProviderCallback);
|
||||
}
|
||||
|
||||
const RemoteSearchProvider = new Lang.Class({
|
||||
Name: 'RemoteSearchProvider',
|
||||
|
||||
_init: function(appInfo, dbusName, dbusPath, proxyInfo) {
|
||||
if (!proxyInfo)
|
||||
proxyInfo = SearchProviderProxyInfo;
|
||||
_init: function(appInfo, dbusName, dbusPath, proxyType) {
|
||||
if (!proxyType)
|
||||
proxyType = SearchProviderProxy;
|
||||
|
||||
this.proxy = new Gio.DBusProxy({ g_bus_type: Gio.BusType.SESSION,
|
||||
g_name: dbusName,
|
||||
g_object_path: dbusPath,
|
||||
g_interface_info: proxyInfo,
|
||||
g_interface_name: proxyInfo.name,
|
||||
g_flags: (Gio.DBusProxyFlags.DO_NOT_AUTO_START_AT_CONSTRUCTION |
|
||||
Gio.DBusProxyFlags.DO_NOT_LOAD_PROPERTIES) });
|
||||
this.proxy.init_async(GLib.PRIORITY_DEFAULT, null, null);
|
||||
this.proxy = new proxyType(Gio.DBus.session,
|
||||
dbusName, dbusPath, Lang.bind(this, this._onProxyConstructed));
|
||||
|
||||
this.appInfo = appInfo;
|
||||
this.id = appInfo.get_id();
|
||||
this.isRemoteProvider = true;
|
||||
|
||||
this._cancellable = new Gio.Cancellable();
|
||||
},
|
||||
|
||||
_onProxyConstructed: function(proxy) {
|
||||
// Do nothing
|
||||
},
|
||||
|
||||
createIcon: function(size, meta) {
|
||||
let gicon = null;
|
||||
let icon = null;
|
||||
|
||||
let gicon;
|
||||
if (meta['icon']) {
|
||||
gicon = Gio.icon_deserialize(meta['icon']);
|
||||
} else if (meta['gicon']) {
|
||||
@ -205,49 +203,44 @@ const RemoteSearchProvider = new Lang.Class({
|
||||
bitsPerSample, width, height, rowStride);
|
||||
}
|
||||
|
||||
if (gicon)
|
||||
icon = new St.Icon({ gicon: gicon,
|
||||
icon_size: size });
|
||||
return icon;
|
||||
return new St.Icon({ gicon: gicon,
|
||||
icon_size: size });
|
||||
},
|
||||
|
||||
filterResults: function(results, maxNumber) {
|
||||
if (results.length <= maxNumber)
|
||||
return results;
|
||||
|
||||
let regularResults = results.filter(function(r) { return !r.startsWith('special:'); });
|
||||
let specialResults = results.filter(function(r) { return r.startsWith('special:'); });
|
||||
|
||||
return regularResults.slice(0, maxNumber).concat(specialResults.slice(0, maxNumber));
|
||||
},
|
||||
|
||||
_getResultsFinished: function(results, error, callback) {
|
||||
if (error) {
|
||||
if (!error.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED))
|
||||
log('Received error from DBus search provider %s: %s'.format(this.id, String(error)));
|
||||
callback([]);
|
||||
_getResultsFinished: function(results, error) {
|
||||
if (error)
|
||||
return;
|
||||
this.searchSystem.setResults(this, results[0]);
|
||||
},
|
||||
|
||||
getInitialResultSet: function(terms) {
|
||||
this._cancellable.cancel();
|
||||
this._cancellable.reset();
|
||||
try {
|
||||
this.proxy.GetInitialResultSetRemote(terms,
|
||||
Lang.bind(this, this._getResultsFinished),
|
||||
this._cancellable);
|
||||
} catch(e) {
|
||||
log('Error calling GetInitialResultSet for provider %s: %s'.format(this.id, e.toString()));
|
||||
this.searchSystem.setResults(this, []);
|
||||
}
|
||||
|
||||
callback(results[0]);
|
||||
},
|
||||
|
||||
getInitialResultSet: function(terms, callback, cancellable) {
|
||||
this.proxy.GetInitialResultSetRemote(terms,
|
||||
Lang.bind(this, this._getResultsFinished, callback),
|
||||
cancellable);
|
||||
},
|
||||
|
||||
getSubsearchResultSet: function(previousResults, newTerms, callback, cancellable) {
|
||||
this.proxy.GetSubsearchResultSetRemote(previousResults, newTerms,
|
||||
Lang.bind(this, this._getResultsFinished, callback),
|
||||
cancellable);
|
||||
getSubsearchResultSet: function(previousResults, newTerms) {
|
||||
this._cancellable.cancel();
|
||||
this._cancellable.reset();
|
||||
try {
|
||||
this.proxy.GetSubsearchResultSetRemote(previousResults, newTerms,
|
||||
Lang.bind(this, this._getResultsFinished),
|
||||
this._cancellable);
|
||||
} catch(e) {
|
||||
log('Error calling GetSubsearchResultSet for provider %s: %s'.format(this.id, e.toString()));
|
||||
this.searchSystem.setResults(this, []);
|
||||
}
|
||||
},
|
||||
|
||||
_getResultMetasFinished: function(results, error, callback) {
|
||||
if (error) {
|
||||
if (!error.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED))
|
||||
log('Received error from DBus search provider %s during GetResultMetas: %s'.format(this.id, String(error)));
|
||||
callback([]);
|
||||
return;
|
||||
}
|
||||
@ -269,10 +262,17 @@ const RemoteSearchProvider = new Lang.Class({
|
||||
callback(resultMetas);
|
||||
},
|
||||
|
||||
getResultMetas: function(ids, callback, cancellable) {
|
||||
this.proxy.GetResultMetasRemote(ids,
|
||||
Lang.bind(this, this._getResultMetasFinished, callback),
|
||||
cancellable);
|
||||
getResultMetas: function(ids, callback) {
|
||||
this._cancellable.cancel();
|
||||
this._cancellable.reset();
|
||||
try {
|
||||
this.proxy.GetResultMetasRemote(ids,
|
||||
Lang.bind(this, this._getResultMetasFinished, callback),
|
||||
this._cancellable);
|
||||
} catch(e) {
|
||||
log('Error calling GetResultMetas for provider %s: %s'.format(this.id, e.toString()));
|
||||
callback([]);
|
||||
}
|
||||
},
|
||||
|
||||
activateResult: function(id) {
|
||||
@ -292,7 +292,7 @@ const RemoteSearchProvider2 = new Lang.Class({
|
||||
Extends: RemoteSearchProvider,
|
||||
|
||||
_init: function(appInfo, dbusName, dbusPath) {
|
||||
this.parent(appInfo, dbusName, dbusPath, SearchProvider2ProxyInfo);
|
||||
this.parent(appInfo, dbusName, dbusPath, SearchProvider2Proxy);
|
||||
|
||||
this.canLaunchSearch = true;
|
||||
},
|
||||
|
@ -73,9 +73,7 @@ const RunDialog = new Lang.Class({
|
||||
let label = new St.Label({ style_class: 'run-dialog-label',
|
||||
text: _("Enter a Command") });
|
||||
|
||||
this.contentLayout.add(label, { x_fill: false,
|
||||
x_align: St.Align.START,
|
||||
y_align: St.Align.START });
|
||||
this.contentLayout.add(label, { y_align: St.Align.START });
|
||||
|
||||
let entry = new St.Entry({ style_class: 'run-dialog-entry',
|
||||
can_focus: true });
|
||||
@ -103,8 +101,6 @@ const RunDialog = new Lang.Class({
|
||||
this._errorMessage.clutter_text.line_wrap = true;
|
||||
|
||||
this._errorBox.add(this._errorMessage, { expand: true,
|
||||
x_align: St.Align.START,
|
||||
x_fill: false,
|
||||
y_align: St.Align.MIDDLE,
|
||||
y_fill: false });
|
||||
|
||||
@ -128,7 +124,7 @@ const RunDialog = new Lang.Class({
|
||||
!this.pushModal())
|
||||
this.close();
|
||||
|
||||
return Clutter.EVENT_STOP;
|
||||
return true;
|
||||
}
|
||||
if (symbol == Clutter.Tab) {
|
||||
let text = o.get_text();
|
||||
@ -142,9 +138,9 @@ const RunDialog = new Lang.Class({
|
||||
o.insert_text(postfix, -1);
|
||||
o.set_cursor_position(text.length + postfix.length);
|
||||
}
|
||||
return Clutter.EVENT_STOP;
|
||||
return true;
|
||||
}
|
||||
return Clutter.EVENT_PROPAGATE;
|
||||
return false;
|
||||
}));
|
||||
},
|
||||
|
||||
|
@ -19,7 +19,6 @@ const Background = imports.ui.background;
|
||||
const GnomeSession = imports.misc.gnomeSession;
|
||||
const Hash = imports.misc.hash;
|
||||
const Layout = imports.ui.layout;
|
||||
const OVirt = imports.gdm.oVirt;
|
||||
const LoginManager = imports.misc.loginManager;
|
||||
const Lightbox = imports.ui.lightbox;
|
||||
const Main = imports.ui.main;
|
||||
@ -198,8 +197,8 @@ const NotificationsBox = new Lang.Class({
|
||||
|
||||
let body = '';
|
||||
if (n.bannerBodyText) {
|
||||
body = n.bannerBodyMarkup ? n.bannerBodyText
|
||||
: GLib.markup_escape_text(n.bannerBodyText, -1);
|
||||
body = n.bannerBodyMarkup ? n.bannerBodyText :
|
||||
GLib.markup_escape_text(n.bannerBodyMarkup, -1);
|
||||
}
|
||||
|
||||
let label = new St.Label({ style_class: 'screen-shield-notification-count-text' });
|
||||
@ -240,6 +239,10 @@ const NotificationsBox = new Lang.Class({
|
||||
},
|
||||
|
||||
_sourceAdded: function(tray, source, initial) {
|
||||
// Ignore transient sources
|
||||
if (source.isTransient)
|
||||
return;
|
||||
|
||||
let obj = {
|
||||
visible: source.policy.showInLockScreen,
|
||||
detailed: source.policy.detailsInLockScreen,
|
||||
@ -542,13 +545,6 @@ const ScreenShield = new Lang.Class({
|
||||
this._liftShield(true, 0);
|
||||
}));
|
||||
|
||||
this._oVirtCredentialsManager = OVirt.getOVirtCredentialsManager();
|
||||
this._oVirtCredentialsManager.connect('user-authenticated',
|
||||
Lang.bind(this, function() {
|
||||
if (this._isLocked)
|
||||
this._liftShield(true, 0);
|
||||
}));
|
||||
|
||||
this._inhibitor = null;
|
||||
this._aboutToSuspend = false;
|
||||
this._loginManager = LoginManager.getLoginManager();
|
||||
@ -669,11 +665,11 @@ const ScreenShield = new Lang.Class({
|
||||
// down after cancel.
|
||||
|
||||
if (this._lockScreenState != MessageTray.State.SHOWN)
|
||||
return Clutter.EVENT_PROPAGATE;
|
||||
return false;
|
||||
|
||||
let isEnter = (symbol == Clutter.KEY_Return || symbol == Clutter.KEY_KP_Enter);
|
||||
if (!isEnter && !(GLib.unichar_isprint(unichar) || symbol == Clutter.KEY_Escape))
|
||||
return Clutter.EVENT_PROPAGATE;
|
||||
return false;
|
||||
|
||||
if (this._isLocked &&
|
||||
this._ensureUnlockDialog(true, true) &&
|
||||
@ -681,12 +677,12 @@ const ScreenShield = new Lang.Class({
|
||||
this._dialog.addCharacter(unichar);
|
||||
|
||||
this._liftShield(true, 0);
|
||||
return Clutter.EVENT_STOP;
|
||||
return true;
|
||||
},
|
||||
|
||||
_onLockScreenScroll: function(actor, event) {
|
||||
if (this._lockScreenState != MessageTray.State.SHOWN)
|
||||
return Clutter.EVENT_PROPAGATE;
|
||||
return false;
|
||||
|
||||
let delta = 0;
|
||||
if (event.get_scroll_direction() == Clutter.ScrollDirection.UP)
|
||||
@ -701,7 +697,7 @@ const ScreenShield = new Lang.Class({
|
||||
this._liftShield(true, 0);
|
||||
}
|
||||
|
||||
return Clutter.EVENT_STOP;
|
||||
return true;
|
||||
},
|
||||
|
||||
_inhibitSuspend: function() {
|
||||
@ -752,7 +748,7 @@ const ScreenShield = new Lang.Class({
|
||||
});
|
||||
}
|
||||
|
||||
return GLib.SOURCE_CONTINUE;
|
||||
return true;
|
||||
},
|
||||
|
||||
_onDragBegin: function() {
|
||||
@ -848,7 +844,7 @@ const ScreenShield = new Lang.Class({
|
||||
Lang.bind(this, function() {
|
||||
this._lockTimeoutId = 0;
|
||||
this.lock(false);
|
||||
return GLib.SOURCE_REMOVE;
|
||||
return false;
|
||||
}));
|
||||
}
|
||||
|
||||
@ -1097,7 +1093,7 @@ const ScreenShield = new Lang.Class({
|
||||
global.stage.disconnect(motionId);
|
||||
}
|
||||
|
||||
return Clutter.EVENT_PROPAGATE;
|
||||
return false;
|
||||
}));
|
||||
this._cursorTracker.set_pointer_visible(false);
|
||||
|
||||
@ -1110,7 +1106,6 @@ const ScreenShield = new Lang.Class({
|
||||
|
||||
Mainloop.timeout_add(1000 * MANUAL_FADE_TIME, Lang.bind(this, function() {
|
||||
this._activateFade(this._shortLightbox, MANUAL_FADE_TIME);
|
||||
return GLib.SOURCE_REMOVE;
|
||||
}));
|
||||
} else {
|
||||
if (params.fadeToBlack)
|
||||
|
@ -9,29 +9,27 @@ const Signals = imports.signals;
|
||||
const Hash = imports.misc.hash;
|
||||
const Main = imports.ui.main;
|
||||
|
||||
const ScreencastIface = '<node> \
|
||||
<interface name="org.gnome.Shell.Screencast"> \
|
||||
<method name="Screencast"> \
|
||||
<arg type="s" direction="in" name="file_template"/> \
|
||||
<arg type="a{sv}" direction="in" name="options"/> \
|
||||
<arg type="b" direction="out" name="success"/> \
|
||||
<arg type="s" direction="out" name="filename_used"/> \
|
||||
</method> \
|
||||
<method name="ScreencastArea"> \
|
||||
<arg type="i" direction="in" name="x"/> \
|
||||
<arg type="i" direction="in" name="y"/> \
|
||||
<arg type="i" direction="in" name="width"/> \
|
||||
<arg type="i" direction="in" name="height"/> \
|
||||
<arg type="s" direction="in" name="file_template"/> \
|
||||
<arg type="a{sv}" direction="in" name="options"/> \
|
||||
<arg type="b" direction="out" name="success"/> \
|
||||
<arg type="s" direction="out" name="filename_used"/> \
|
||||
</method> \
|
||||
<method name="StopScreencast"> \
|
||||
<arg type="b" direction="out" name="success"/> \
|
||||
</method> \
|
||||
</interface> \
|
||||
</node>';
|
||||
const ScreencastIface = <interface name="org.gnome.Shell.Screencast">
|
||||
<method name="Screencast">
|
||||
<arg type="s" direction="in" name="file_template"/>
|
||||
<arg type="a{sv}" direction="in" name="options"/>
|
||||
<arg type="b" direction="out" name="success"/>
|
||||
<arg type="s" direction="out" name="filename_used"/>
|
||||
</method>
|
||||
<method name="ScreencastArea">
|
||||
<arg type="i" direction="in" name="x"/>
|
||||
<arg type="i" direction="in" name="y"/>
|
||||
<arg type="i" direction="in" name="width"/>
|
||||
<arg type="i" direction="in" name="height"/>
|
||||
<arg type="s" direction="in" name="file_template"/>
|
||||
<arg type="a{sv}" direction="in" name="options"/>
|
||||
<arg type="b" direction="out" name="success"/>
|
||||
<arg type="s" direction="out" name="filename_used"/>
|
||||
</method>
|
||||
<method name="StopScreencast">
|
||||
<arg type="b" direction="out" name="success"/>
|
||||
</method>
|
||||
</interface>;
|
||||
|
||||
const ScreencastService = new Lang.Class({
|
||||
Name: 'ScreencastService',
|
||||
@ -105,10 +103,8 @@ const ScreencastService = new Lang.Class({
|
||||
|
||||
ScreencastAsync: function(params, invocation) {
|
||||
let returnValue = [false, ''];
|
||||
if (!Main.sessionMode.allowScreencast) {
|
||||
if (!Main.sessionMode.allowScreencast)
|
||||
invocation.return_value(GLib.Variant.new('(bs)', returnValue));
|
||||
return;
|
||||
}
|
||||
|
||||
let sender = invocation.get_sender();
|
||||
let recorder = this._ensureRecorderForSender(sender);
|
||||
@ -126,10 +122,8 @@ const ScreencastService = new Lang.Class({
|
||||
|
||||
ScreencastAreaAsync: function(params, invocation) {
|
||||
let returnValue = [false, ''];
|
||||
if (!Main.sessionMode.allowScreencast) {
|
||||
if (!Main.sessionMode.allowScreencast)
|
||||
invocation.return_value(GLib.Variant.new('(bs)', returnValue));
|
||||
return;
|
||||
}
|
||||
|
||||
let sender = invocation.get_sender();
|
||||
let recorder = this._ensureRecorderForSender(sender);
|
||||
@ -137,16 +131,6 @@ const ScreencastService = new Lang.Class({
|
||||
if (!recorder.is_recording()) {
|
||||
let [x, y, width, height, fileTemplate, options] = params;
|
||||
|
||||
if (x < 0 || y < 0 ||
|
||||
width <= 0 || height <= 0 ||
|
||||
x + width > global.screen_width ||
|
||||
y + height > global.screen_height) {
|
||||
invocation.return_error_literal(Gio.IOErrorEnum,
|
||||
Gio.IOErrorEnum.CANCELLED,
|
||||
"Invalid params");
|
||||
return;
|
||||
}
|
||||
|
||||
recorder.set_file_template(fileTemplate);
|
||||
recorder.set_area(x, y, width, height);
|
||||
this._applyOptionalParameters(recorder, options);
|
||||
|
@ -15,47 +15,45 @@ const Lightbox = imports.ui.lightbox;
|
||||
const Main = imports.ui.main;
|
||||
const Tweener = imports.ui.tweener;
|
||||
|
||||
const ScreenshotIface = '<node> \
|
||||
<interface name="org.gnome.Shell.Screenshot"> \
|
||||
<method name="ScreenshotArea"> \
|
||||
<arg type="i" direction="in" name="x"/> \
|
||||
<arg type="i" direction="in" name="y"/> \
|
||||
<arg type="i" direction="in" name="width"/> \
|
||||
<arg type="i" direction="in" name="height"/> \
|
||||
<arg type="b" direction="in" name="flash"/> \
|
||||
<arg type="s" direction="in" name="filename"/> \
|
||||
<arg type="b" direction="out" name="success"/> \
|
||||
<arg type="s" direction="out" name="filename_used"/> \
|
||||
</method> \
|
||||
<method name="ScreenshotWindow"> \
|
||||
<arg type="b" direction="in" name="include_frame"/> \
|
||||
<arg type="b" direction="in" name="include_cursor"/> \
|
||||
<arg type="b" direction="in" name="flash"/> \
|
||||
<arg type="s" direction="in" name="filename"/> \
|
||||
<arg type="b" direction="out" name="success"/> \
|
||||
<arg type="s" direction="out" name="filename_used"/> \
|
||||
</method> \
|
||||
<method name="Screenshot"> \
|
||||
<arg type="b" direction="in" name="include_cursor"/> \
|
||||
<arg type="b" direction="in" name="flash"/> \
|
||||
<arg type="s" direction="in" name="filename"/> \
|
||||
<arg type="b" direction="out" name="success"/> \
|
||||
<arg type="s" direction="out" name="filename_used"/> \
|
||||
</method> \
|
||||
<method name="SelectArea"> \
|
||||
<arg type="i" direction="out" name="x"/> \
|
||||
<arg type="i" direction="out" name="y"/> \
|
||||
<arg type="i" direction="out" name="width"/> \
|
||||
<arg type="i" direction="out" name="height"/> \
|
||||
</method> \
|
||||
<method name="FlashArea"> \
|
||||
<arg type="i" direction="in" name="x"/> \
|
||||
<arg type="i" direction="in" name="y"/> \
|
||||
<arg type="i" direction="in" name="width"/> \
|
||||
<arg type="i" direction="in" name="height"/> \
|
||||
</method> \
|
||||
</interface> \
|
||||
</node>';
|
||||
const ScreenshotIface = <interface name="org.gnome.Shell.Screenshot">
|
||||
<method name="ScreenshotArea">
|
||||
<arg type="i" direction="in" name="x"/>
|
||||
<arg type="i" direction="in" name="y"/>
|
||||
<arg type="i" direction="in" name="width"/>
|
||||
<arg type="i" direction="in" name="height"/>
|
||||
<arg type="b" direction="in" name="flash"/>
|
||||
<arg type="s" direction="in" name="filename"/>
|
||||
<arg type="b" direction="out" name="success"/>
|
||||
<arg type="s" direction="out" name="filename_used"/>
|
||||
</method>
|
||||
<method name="ScreenshotWindow">
|
||||
<arg type="b" direction="in" name="include_frame"/>
|
||||
<arg type="b" direction="in" name="include_cursor"/>
|
||||
<arg type="b" direction="in" name="flash"/>
|
||||
<arg type="s" direction="in" name="filename"/>
|
||||
<arg type="b" direction="out" name="success"/>
|
||||
<arg type="s" direction="out" name="filename_used"/>
|
||||
</method>
|
||||
<method name="Screenshot">
|
||||
<arg type="b" direction="in" name="include_cursor"/>
|
||||
<arg type="b" direction="in" name="flash"/>
|
||||
<arg type="s" direction="in" name="filename"/>
|
||||
<arg type="b" direction="out" name="success"/>
|
||||
<arg type="s" direction="out" name="filename_used"/>
|
||||
</method>
|
||||
<method name="SelectArea">
|
||||
<arg type="i" direction="out" name="x"/>
|
||||
<arg type="i" direction="out" name="y"/>
|
||||
<arg type="i" direction="out" name="width"/>
|
||||
<arg type="i" direction="out" name="height"/>
|
||||
</method>
|
||||
<method name="FlashArea">
|
||||
<arg type="i" direction="in" name="x"/>
|
||||
<arg type="i" direction="in" name="y"/>
|
||||
<arg type="i" direction="in" name="width"/>
|
||||
<arg type="i" direction="in" name="height"/>
|
||||
</method>
|
||||
</interface>;
|
||||
|
||||
const ScreenshotService = new Lang.Class({
|
||||
Name: 'ScreenshotService',
|
||||
@ -79,9 +77,7 @@ const ScreenshotService = new Lang.Class({
|
||||
|
||||
ScreenshotAreaAsync : function (params, invocation) {
|
||||
let [x, y, width, height, flash, filename, callback] = params;
|
||||
if (x < 0 || y < 0 ||
|
||||
width <= 0 || height <= 0 ||
|
||||
x + width > global.screen_width || y + height > global.screen_height) {
|
||||
if (height <= 0 || width <= 0) {
|
||||
invocation.return_error_literal(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED,
|
||||
"Invalid params");
|
||||
return;
|
||||
@ -206,12 +202,12 @@ const SelectArea = new Lang.Class({
|
||||
if (event.get_key_symbol() == Clutter.Escape)
|
||||
this._destroy(null, false);
|
||||
|
||||
return Clutter.EVENT_PROPAGATE;
|
||||
return;
|
||||
},
|
||||
|
||||
_onMotionEvent: function(actor, event) {
|
||||
if (this._startX == -1 || this._startY == -1)
|
||||
return Clutter.EVENT_PROPAGATE;
|
||||
return false;
|
||||
|
||||
[this._lastX, this._lastY] = event.get_coords();
|
||||
let geometry = this._getGeometry();
|
||||
@ -219,19 +215,19 @@ const SelectArea = new Lang.Class({
|
||||
this._rubberband.set_position(geometry.x, geometry.y);
|
||||
this._rubberband.set_size(geometry.width, geometry.height);
|
||||
|
||||
return Clutter.EVENT_PROPAGATE;
|
||||
return false;
|
||||
},
|
||||
|
||||
_onButtonPress: function(actor, event) {
|
||||
[this._startX, this._startY] = event.get_coords();
|
||||
this._rubberband.set_position(this._startX, this._startY);
|
||||
|
||||
return Clutter.EVENT_PROPAGATE;
|
||||
return false;
|
||||
},
|
||||
|
||||
_onButtonRelease: function(actor, event) {
|
||||
this._destroy(this._getGeometry(), true);
|
||||
return Clutter.EVENT_PROPAGATE;
|
||||
return false;
|
||||
},
|
||||
|
||||
_destroy: function(geometry, fade) {
|
||||
|
@ -1,7 +1,6 @@
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
|
||||
const Gio = imports.gi.Gio;
|
||||
const GLib = imports.gi.GLib;
|
||||
const Mainloop = imports.mainloop;
|
||||
const Meta = imports.gi.Meta;
|
||||
const Shell = imports.gi.Shell;
|
||||
@ -42,7 +41,7 @@ function sleep(milliseconds) {
|
||||
Mainloop.timeout_add(milliseconds, function() {
|
||||
if (cb)
|
||||
cb();
|
||||
return GLib.SOURCE_REMOVE;
|
||||
return false;
|
||||
});
|
||||
|
||||
return function(callback) {
|
||||
@ -70,18 +69,16 @@ function waitLeisure() {
|
||||
};
|
||||
}
|
||||
|
||||
const PerfHelperIface = '<node> \
|
||||
<interface name="org.gnome.Shell.PerfHelper"> \
|
||||
<method name="CreateWindow"> \
|
||||
<arg type="i" direction="in" /> \
|
||||
<arg type="i" direction="in" /> \
|
||||
<arg type="b" direction="in" /> \
|
||||
<arg type="b" direction="in" /> \
|
||||
</method> \
|
||||
<method name="WaitWindows" /> \
|
||||
<method name="DestroyWindows" /> \
|
||||
</interface> \
|
||||
</node>';
|
||||
const PerfHelperIface = <interface name="org.gnome.Shell.PerfHelper">
|
||||
<method name="CreateWindow">
|
||||
<arg type="i" direction="in" />
|
||||
<arg type="i" direction="in" />
|
||||
<arg type="b" direction="in" />
|
||||
<arg type="b" direction="in" />
|
||||
</method>
|
||||
<method name="WaitWindows" />
|
||||
<method name="DestroyWindows" />
|
||||
</interface>;
|
||||
|
||||
var PerfHelperProxy = Gio.DBusProxy.makeProxyWrapper(PerfHelperIface);
|
||||
function PerfHelper() {
|
||||
|
717
js/ui/search.js
717
js/ui/search.js
@ -1,706 +1,105 @@
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
|
||||
const Clutter = imports.gi.Clutter;
|
||||
const Lang = imports.lang;
|
||||
const Gio = imports.gi.Gio;
|
||||
const Gtk = imports.gi.Gtk;
|
||||
const Meta = imports.gi.Meta;
|
||||
const Signals = imports.signals;
|
||||
const St = imports.gi.St;
|
||||
const Atk = imports.gi.Atk;
|
||||
|
||||
const AppDisplay = imports.ui.appDisplay;
|
||||
const DND = imports.ui.dnd;
|
||||
const IconGrid = imports.ui.iconGrid;
|
||||
const Main = imports.ui.main;
|
||||
const Overview = imports.ui.overview;
|
||||
const RemoteSearch = imports.ui.remoteSearch;
|
||||
const Separator = imports.ui.separator;
|
||||
const Util = imports.misc.util;
|
||||
|
||||
const SEARCH_PROVIDERS_SCHEMA = 'org.gnome.desktop.search-providers';
|
||||
|
||||
const MAX_LIST_SEARCH_RESULTS_ROWS = 3;
|
||||
const MAX_GRID_SEARCH_RESULTS_ROWS = 1;
|
||||
|
||||
const SearchSystem = new Lang.Class({
|
||||
Name: 'SearchSystem',
|
||||
|
||||
_init: function() {
|
||||
this._providers = [];
|
||||
|
||||
this._registerProvider(new AppDisplay.AppSearchProvider());
|
||||
|
||||
this._searchSettings = new Gio.Settings({ schema: SEARCH_PROVIDERS_SCHEMA });
|
||||
this._searchSettings.connect('changed::disabled', Lang.bind(this, this._reloadRemoteProviders));
|
||||
this._searchSettings.connect('changed::disable-external', Lang.bind(this, this._reloadRemoteProviders));
|
||||
this._searchSettings.connect('changed::sort-order', Lang.bind(this, this._reloadRemoteProviders));
|
||||
|
||||
this._reloadRemoteProviders();
|
||||
|
||||
this._cancellable = new Gio.Cancellable();
|
||||
this._remoteProviders = [];
|
||||
this.reset();
|
||||
},
|
||||
|
||||
addProvider: function(provider) {
|
||||
registerProvider: function (provider) {
|
||||
provider.searchSystem = this;
|
||||
this._providers.push(provider);
|
||||
this.emit('providers-changed');
|
||||
|
||||
if (provider.isRemoteProvider)
|
||||
this._remoteProviders.push(provider);
|
||||
},
|
||||
|
||||
_reloadRemoteProviders: function() {
|
||||
let remoteProviders = this._providers.filter(function(provider) {
|
||||
return provider.isRemoteProvider;
|
||||
});
|
||||
remoteProviders.forEach(Lang.bind(this, function(provider) {
|
||||
this._unregisterProvider(provider);
|
||||
}));
|
||||
|
||||
RemoteSearch.loadRemoteSearchProviders(Lang.bind(this, function(providers) {
|
||||
providers.forEach(Lang.bind(this, this._registerProvider));
|
||||
}));
|
||||
|
||||
this.emit('providers-changed');
|
||||
},
|
||||
|
||||
_registerProvider: function (provider) {
|
||||
this._providers.push(provider);
|
||||
},
|
||||
|
||||
_unregisterProvider: function (provider) {
|
||||
unregisterProvider: function (provider) {
|
||||
let index = this._providers.indexOf(provider);
|
||||
if (index == -1)
|
||||
return;
|
||||
provider.searchSystem = null;
|
||||
this._providers.splice(index, 1);
|
||||
|
||||
let remoteIndex = this._remoteProviders.indexOf(provider);
|
||||
if (remoteIndex != -1)
|
||||
this._remoteProviders.splice(remoteIndex, 1);
|
||||
},
|
||||
|
||||
getProviders: function() {
|
||||
return this._providers;
|
||||
},
|
||||
|
||||
getRemoteProviders: function() {
|
||||
return this._remoteProviders;
|
||||
},
|
||||
|
||||
getTerms: function() {
|
||||
return this._terms;
|
||||
return this._previousTerms;
|
||||
},
|
||||
|
||||
reset: function() {
|
||||
this._terms = [];
|
||||
this._results = {};
|
||||
this._previousTerms = [];
|
||||
this._previousResults = [];
|
||||
},
|
||||
|
||||
_gotResults: function(results, provider) {
|
||||
this._results[provider.id] = results;
|
||||
this.emit('search-updated', provider, results);
|
||||
setResults: function(provider, results) {
|
||||
let i = this._providers.indexOf(provider);
|
||||
if (i == -1)
|
||||
return;
|
||||
|
||||
this._previousResults[i] = [provider, results];
|
||||
this.emit('search-updated', this._previousResults[i]);
|
||||
},
|
||||
|
||||
setTerms: function(terms) {
|
||||
this._cancellable.cancel();
|
||||
this._cancellable.reset();
|
||||
|
||||
let previousResults = this._results;
|
||||
let previousTerms = this._terms;
|
||||
this.reset();
|
||||
|
||||
updateSearchResults: function(terms) {
|
||||
if (!terms)
|
||||
return;
|
||||
|
||||
let searchString = terms.join(' ');
|
||||
let previousSearchString = previousTerms.join(' ');
|
||||
let previousSearchString = this._previousTerms.join(' ');
|
||||
if (searchString == previousSearchString)
|
||||
return;
|
||||
|
||||
let isSubSearch = false;
|
||||
if (previousTerms.length > 0)
|
||||
if (this._previousTerms.length > 0)
|
||||
isSubSearch = searchString.indexOf(previousSearchString) == 0;
|
||||
|
||||
this._terms = terms;
|
||||
let previousResultsArr = this._previousResults;
|
||||
|
||||
this._providers.forEach(Lang.bind(this, function(provider) {
|
||||
let previousProviderResults = previousResults[provider.id];
|
||||
if (isSubSearch && previousProviderResults)
|
||||
provider.getSubsearchResultSet(previousProviderResults, terms, Lang.bind(this, this._gotResults, provider), this._cancellable);
|
||||
else
|
||||
provider.getInitialResultSet(terms, Lang.bind(this, this._gotResults, provider), this._cancellable);
|
||||
}));
|
||||
let results = [];
|
||||
this._previousTerms = terms;
|
||||
this._previousResults = results;
|
||||
|
||||
if (isSubSearch) {
|
||||
for (let i = 0; i < this._providers.length; i++) {
|
||||
let [provider, previousResults] = previousResultsArr[i];
|
||||
try {
|
||||
results.push([provider, []]);
|
||||
provider.getSubsearchResultSet(previousResults, terms);
|
||||
} catch (error) {
|
||||
log('A ' + error.name + ' has occured in ' + provider.id + ': ' + error.message);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (let i = 0; i < this._providers.length; i++) {
|
||||
let provider = this._providers[i];
|
||||
try {
|
||||
results.push([provider, []]);
|
||||
provider.getInitialResultSet(terms);
|
||||
} catch (error) {
|
||||
log('A ' + error.name + ' has occured in ' + provider.id + ': ' + error.message);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
Signals.addSignalMethods(SearchSystem.prototype);
|
||||
|
||||
const MaxWidthBin = new Lang.Class({
|
||||
Name: 'MaxWidthBin',
|
||||
Extends: St.Bin,
|
||||
|
||||
vfunc_allocate: function(box, flags) {
|
||||
let themeNode = this.get_theme_node();
|
||||
let maxWidth = themeNode.get_max_width();
|
||||
let availWidth = box.x2 - box.x1;
|
||||
let adjustedBox = box;
|
||||
|
||||
if (availWidth > maxWidth) {
|
||||
let excessWidth = availWidth - maxWidth;
|
||||
adjustedBox.x1 += Math.floor(excessWidth / 2);
|
||||
adjustedBox.x2 -= Math.floor(excessWidth / 2);
|
||||
}
|
||||
|
||||
this.parent(adjustedBox, flags);
|
||||
}
|
||||
});
|
||||
|
||||
const SearchResult = new Lang.Class({
|
||||
Name: 'SearchResult',
|
||||
|
||||
_init: function(provider, metaInfo) {
|
||||
this.provider = provider;
|
||||
this.metaInfo = metaInfo;
|
||||
|
||||
this.actor = new St.Button({ reactive: true,
|
||||
can_focus: true,
|
||||
track_hover: true,
|
||||
x_align: St.Align.START,
|
||||
y_fill: true });
|
||||
|
||||
this.actor._delegate = this;
|
||||
this.actor.connect('clicked', Lang.bind(this, this.activate));
|
||||
},
|
||||
|
||||
activate: function() {
|
||||
this.emit('activate', this.metaInfo.id);
|
||||
},
|
||||
|
||||
setSelected: function(selected) {
|
||||
if (selected)
|
||||
this.actor.add_style_pseudo_class('selected');
|
||||
else
|
||||
this.actor.remove_style_pseudo_class('selected');
|
||||
}
|
||||
});
|
||||
Signals.addSignalMethods(SearchResult.prototype);
|
||||
|
||||
const ListSearchResult = new Lang.Class({
|
||||
Name: 'ListSearchResult',
|
||||
Extends: SearchResult,
|
||||
|
||||
ICON_SIZE: 64,
|
||||
|
||||
_init: function(provider, metaInfo) {
|
||||
this.parent(provider, metaInfo);
|
||||
|
||||
this.actor.style_class = 'list-search-result';
|
||||
this.actor.x_fill = true;
|
||||
|
||||
let content = new St.BoxLayout({ style_class: 'list-search-result-content',
|
||||
vertical: false });
|
||||
this.actor.set_child(content);
|
||||
|
||||
// An icon for, or thumbnail of, content
|
||||
let icon = this.metaInfo['createIcon'](this.ICON_SIZE);
|
||||
if (icon) {
|
||||
content.add(icon);
|
||||
}
|
||||
|
||||
let details = new St.BoxLayout({ vertical: true });
|
||||
content.add(details, { x_fill: true,
|
||||
y_fill: false,
|
||||
x_align: St.Align.START,
|
||||
y_align: St.Align.MIDDLE });
|
||||
|
||||
let title = new St.Label({ style_class: 'list-search-result-title',
|
||||
text: this.metaInfo['name'] })
|
||||
details.add(title, { x_fill: false,
|
||||
y_fill: false,
|
||||
x_align: St.Align.START,
|
||||
y_align: St.Align.START });
|
||||
this.actor.label_actor = title;
|
||||
|
||||
if (this.metaInfo['description']) {
|
||||
let description = new St.Label({ style_class: 'list-search-result-description' });
|
||||
description.clutter_text.set_markup(this.metaInfo['description']);
|
||||
details.add(description, { x_fill: false,
|
||||
y_fill: false,
|
||||
x_align: St.Align.START,
|
||||
y_align: St.Align.END });
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const GridSearchResult = new Lang.Class({
|
||||
Name: 'GridSearchResult',
|
||||
Extends: SearchResult,
|
||||
|
||||
_init: function(provider, metaInfo) {
|
||||
this.parent(provider, metaInfo);
|
||||
|
||||
this.actor.style_class = 'grid-search-result';
|
||||
|
||||
let content = provider.createResultObject(metaInfo);
|
||||
let dragSource = null;
|
||||
|
||||
if (content == null) {
|
||||
let actor = new St.Bin();
|
||||
let icon = new IconGrid.BaseIcon(this.metaInfo['name'],
|
||||
{ createIcon: this.metaInfo['createIcon'] });
|
||||
actor.set_child(icon.actor);
|
||||
actor.label_actor = icon.label;
|
||||
dragSource = icon.icon;
|
||||
content = { actor: actor, icon: icon };
|
||||
} else {
|
||||
if (content._delegate && content._delegate.getDragActorSource)
|
||||
dragSource = content._delegate.getDragActorSource();
|
||||
}
|
||||
|
||||
this.actor.set_child(content.actor);
|
||||
this.actor.label_actor = content.actor.label_actor;
|
||||
this.icon = content.icon;
|
||||
|
||||
let draggable = DND.makeDraggable(this.actor);
|
||||
draggable.connect('drag-begin',
|
||||
Lang.bind(this, function() {
|
||||
Main.overview.beginItemDrag(this);
|
||||
}));
|
||||
draggable.connect('drag-cancelled',
|
||||
Lang.bind(this, function() {
|
||||
Main.overview.cancelledItemDrag(this);
|
||||
}));
|
||||
draggable.connect('drag-end',
|
||||
Lang.bind(this, function() {
|
||||
Main.overview.endItemDrag(this);
|
||||
}));
|
||||
|
||||
if (!dragSource)
|
||||
// not exactly right, but alignment problems are hard to notice
|
||||
dragSource = content;
|
||||
this._dragActorSource = dragSource;
|
||||
},
|
||||
|
||||
getDragActorSource: function() {
|
||||
return this._dragActorSource;
|
||||
},
|
||||
|
||||
getDragActor: function() {
|
||||
return this.metaInfo['createIcon'](Main.overview.dashIconSize);
|
||||
},
|
||||
|
||||
shellWorkspaceLaunch: function(params) {
|
||||
if (this.provider.dragActivateResult)
|
||||
this.provider.dragActivateResult(this.metaInfo.id, params);
|
||||
else
|
||||
this.provider.activateResult(this.metaInfo.id, this.terms);
|
||||
}
|
||||
});
|
||||
|
||||
const SearchResultsBase = new Lang.Class({
|
||||
Name: 'SearchResultsBase',
|
||||
|
||||
_init: function(provider) {
|
||||
this.provider = provider;
|
||||
|
||||
this._terms = [];
|
||||
|
||||
this.actor = new St.BoxLayout({ style_class: 'search-section',
|
||||
vertical: true });
|
||||
|
||||
this._resultDisplayBin = new St.Bin({ x_fill: true,
|
||||
y_fill: true });
|
||||
this.actor.add(this._resultDisplayBin, { expand: true });
|
||||
|
||||
let separator = new Separator.HorizontalSeparator({ style_class: 'search-section-separator' });
|
||||
this.actor.add(separator.actor);
|
||||
|
||||
this._resultDisplays = {};
|
||||
|
||||
this._cancellable = new Gio.Cancellable();
|
||||
},
|
||||
|
||||
destroy: function() {
|
||||
this.actor.destroy();
|
||||
this._terms = [];
|
||||
},
|
||||
|
||||
_clearResultDisplay: function() {
|
||||
},
|
||||
|
||||
clear: function() {
|
||||
this._resultDisplays = {};
|
||||
this._clearResultDisplay();
|
||||
this.actor.hide();
|
||||
},
|
||||
|
||||
_keyFocusIn: function(actor) {
|
||||
this.emit('key-focus-in', actor);
|
||||
},
|
||||
|
||||
_activateResult: function(result, id) {
|
||||
this.provider.activateResult(id, this._terms);
|
||||
Main.overview.toggle();
|
||||
},
|
||||
|
||||
_setMoreIconVisible: function(visible) {
|
||||
},
|
||||
|
||||
_ensureResultActors: function(results, callback) {
|
||||
let metasNeeded = results.filter(Lang.bind(this, function(resultId) {
|
||||
return this._resultDisplays[resultId] === undefined;
|
||||
}));
|
||||
|
||||
if (metasNeeded.length === 0) {
|
||||
callback();
|
||||
} else {
|
||||
this._cancellable.cancel();
|
||||
this._cancellable.reset();
|
||||
|
||||
this.provider.getResultMetas(metasNeeded, Lang.bind(this, function(metas) {
|
||||
metasNeeded.forEach(Lang.bind(this, function(resultId, i) {
|
||||
let meta = metas[i];
|
||||
let display = this._createResultDisplay(meta);
|
||||
display.connect('activate', Lang.bind(this, this._activateResult));
|
||||
display.actor.connect('key-focus-in', Lang.bind(this, this._keyFocusIn));
|
||||
this._resultDisplays[resultId] = display;
|
||||
}));
|
||||
callback();
|
||||
}), this._cancellable);
|
||||
}
|
||||
},
|
||||
|
||||
updateSearch: function(providerResults, terms, callback) {
|
||||
this._terms = terms;
|
||||
|
||||
if (providerResults.length == 0) {
|
||||
this._clearResultDisplay();
|
||||
this.actor.hide();
|
||||
callback();
|
||||
} else {
|
||||
let maxResults = this._getMaxDisplayedResults();
|
||||
let results = this.provider.filterResults(providerResults, maxResults);
|
||||
let hasMoreResults = results.length < providerResults.length;
|
||||
|
||||
this._ensureResultActors(results, Lang.bind(this, function() {
|
||||
this._clearResultDisplay();
|
||||
|
||||
// To avoid CSS transitions causing flickering when
|
||||
// the first search result stays the same, we hide the
|
||||
// content while filling in the results.
|
||||
this.actor.hide();
|
||||
this._clearResultDisplay();
|
||||
results.forEach(Lang.bind(this, function(resultId) {
|
||||
this._addItem(this._resultDisplays[resultId]);
|
||||
}));
|
||||
this._setMoreIconVisible(hasMoreResults && this.provider.canLaunchSearch);
|
||||
this.actor.show();
|
||||
callback();
|
||||
}));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const ListSearchResults = new Lang.Class({
|
||||
Name: 'ListSearchResults',
|
||||
Extends: SearchResultsBase,
|
||||
|
||||
_init: function(provider) {
|
||||
this.parent(provider);
|
||||
|
||||
this._container = new St.BoxLayout({ style_class: 'search-section-content' });
|
||||
this.providerIcon = new ProviderIcon(provider);
|
||||
this.providerIcon.connect('key-focus-in', Lang.bind(this, this._keyFocusIn));
|
||||
this.providerIcon.connect('clicked', Lang.bind(this,
|
||||
function() {
|
||||
provider.launchSearch(this._terms);
|
||||
Main.overview.toggle();
|
||||
}));
|
||||
|
||||
this._container.add(this.providerIcon, { x_fill: false,
|
||||
y_fill: false,
|
||||
x_align: St.Align.START,
|
||||
y_align: St.Align.START });
|
||||
|
||||
this._content = new St.BoxLayout({ style_class: 'list-search-results',
|
||||
vertical: true });
|
||||
this._container.add(this._content, { expand: true });
|
||||
|
||||
this._resultDisplayBin.set_child(this._container);
|
||||
},
|
||||
|
||||
_setMoreIconVisible: function(visible) {
|
||||
this.providerIcon.moreIcon.visible = true;
|
||||
},
|
||||
|
||||
_getMaxDisplayedResults: function() {
|
||||
return MAX_LIST_SEARCH_RESULTS_ROWS;
|
||||
},
|
||||
|
||||
_clearResultDisplay: function () {
|
||||
this._content.remove_all_children();
|
||||
},
|
||||
|
||||
_createResultDisplay: function(meta) {
|
||||
return new ListSearchResult(this.provider, meta);
|
||||
},
|
||||
|
||||
_addItem: function(display) {
|
||||
this._content.add_actor(display.actor);
|
||||
},
|
||||
|
||||
getFirstResult: function() {
|
||||
if (this._content.get_n_children() > 0)
|
||||
return this._content.get_child_at_index(0)._delegate;
|
||||
else
|
||||
return null;
|
||||
}
|
||||
});
|
||||
Signals.addSignalMethods(ListSearchResults.prototype);
|
||||
|
||||
const GridSearchResults = new Lang.Class({
|
||||
Name: 'GridSearchResults',
|
||||
Extends: SearchResultsBase,
|
||||
|
||||
_init: function(provider) {
|
||||
this.parent(provider);
|
||||
|
||||
this._grid = new IconGrid.IconGrid({ rowLimit: MAX_GRID_SEARCH_RESULTS_ROWS,
|
||||
xAlign: St.Align.START });
|
||||
this._bin = new St.Bin({ x_align: St.Align.MIDDLE });
|
||||
this._bin.set_child(this._grid.actor);
|
||||
|
||||
this._resultDisplayBin.set_child(this._bin);
|
||||
},
|
||||
|
||||
_getMaxDisplayedResults: function() {
|
||||
return this._grid.columnsForWidth(this._bin.width) * this._grid.getRowLimit();
|
||||
},
|
||||
|
||||
_renderResults: function(metas) {
|
||||
for (let i = 0; i < metas.length; i++) {
|
||||
let display = new GridSearchResult(this.provider, metas[i]);
|
||||
display.connect('activate', Lang.bind(this, this._activateResult));
|
||||
display.actor.connect('key-focus-in', Lang.bind(this, this._keyFocusIn));
|
||||
this._grid.addItem(display);
|
||||
}
|
||||
},
|
||||
|
||||
_clearResultDisplay: function () {
|
||||
this._grid.removeAll();
|
||||
},
|
||||
|
||||
_createResultDisplay: function(meta) {
|
||||
return new GridSearchResult(this.provider, meta);
|
||||
},
|
||||
|
||||
_addItem: function(display) {
|
||||
this._grid.addItem(display);
|
||||
},
|
||||
|
||||
getFirstResult: function() {
|
||||
if (this._grid.visibleItemsCount() > 0)
|
||||
return this._grid.getItemAtIndex(0)._delegate;
|
||||
else
|
||||
return null;
|
||||
}
|
||||
});
|
||||
Signals.addSignalMethods(GridSearchResults.prototype);
|
||||
|
||||
const SearchResults = new Lang.Class({
|
||||
Name: 'SearchResults',
|
||||
|
||||
_init: function() {
|
||||
this.actor = new St.BoxLayout({ name: 'searchResults',
|
||||
vertical: true });
|
||||
|
||||
this._content = new St.BoxLayout({ name: 'searchResultsContent',
|
||||
vertical: true });
|
||||
this._contentBin = new MaxWidthBin({ name: 'searchResultsBin',
|
||||
x_fill: true,
|
||||
y_fill: true,
|
||||
child: this._content });
|
||||
|
||||
let scrollChild = new St.BoxLayout();
|
||||
scrollChild.add(this._contentBin, { expand: true });
|
||||
|
||||
this._scrollView = new St.ScrollView({ x_fill: true,
|
||||
y_fill: false,
|
||||
overlay_scrollbars: true,
|
||||
style_class: 'search-display vfade' });
|
||||
this._scrollView.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC);
|
||||
this._scrollView.add_actor(scrollChild);
|
||||
let action = new Clutter.PanAction({ interpolate: true });
|
||||
action.connect('pan', Lang.bind(this, this._onPan));
|
||||
this._scrollView.add_action(action);
|
||||
|
||||
this.actor.add(this._scrollView, { x_fill: true,
|
||||
y_fill: true,
|
||||
expand: true,
|
||||
x_align: St.Align.START,
|
||||
y_align: St.Align.START });
|
||||
|
||||
this._statusText = new St.Label({ style_class: 'search-statustext' });
|
||||
this._statusBin = new St.Bin({ x_align: St.Align.MIDDLE,
|
||||
y_align: St.Align.MIDDLE });
|
||||
this._content.add(this._statusBin, { expand: true });
|
||||
this._statusBin.add_actor(this._statusText);
|
||||
|
||||
this._highlightDefault = false;
|
||||
this._defaultResult = null;
|
||||
|
||||
this._searchSystem = new SearchSystem();
|
||||
this._searchSystem.connect('search-updated', Lang.bind(this, this._updateResults));
|
||||
this._searchSystem.connect('providers-changed', Lang.bind(this, this._updateProviderDisplays));
|
||||
this._updateProviderDisplays();
|
||||
},
|
||||
|
||||
_onPan: function(action) {
|
||||
let [dist, dx, dy] = action.get_motion_delta(0);
|
||||
let adjustment = this._scrollView.vscroll.adjustment;
|
||||
adjustment.value -= (dy / this.actor.height) * adjustment.page_size;
|
||||
return false;
|
||||
},
|
||||
|
||||
_keyFocusIn: function(provider, actor) {
|
||||
Util.ensureActorVisibleInScrollView(this._scrollView, actor);
|
||||
},
|
||||
|
||||
_ensureProviderDisplay: function(provider) {
|
||||
if (provider.display)
|
||||
return;
|
||||
|
||||
let providerDisplay;
|
||||
if (provider.appInfo)
|
||||
providerDisplay = new ListSearchResults(provider);
|
||||
else
|
||||
providerDisplay = new GridSearchResults(provider);
|
||||
|
||||
providerDisplay.connect('key-focus-in', Lang.bind(this, this._keyFocusIn));
|
||||
this._content.add(providerDisplay.actor);
|
||||
provider.display = providerDisplay;
|
||||
},
|
||||
|
||||
_updateProviderDisplays: function() {
|
||||
this._searchSystem.getProviders().forEach(Lang.bind(this, this._ensureProviderDisplay));
|
||||
},
|
||||
|
||||
_clearDisplay: function() {
|
||||
this._searchSystem.getProviders().forEach(function(provider) {
|
||||
provider.display.clear();
|
||||
});
|
||||
},
|
||||
|
||||
reset: function() {
|
||||
this._searchSystem.reset();
|
||||
this._statusBin.hide();
|
||||
this._clearDisplay();
|
||||
this._defaultResult = null;
|
||||
},
|
||||
|
||||
startingSearch: function() {
|
||||
this.reset();
|
||||
this._statusText.set_text(_("Searching…"));
|
||||
this._statusBin.show();
|
||||
},
|
||||
|
||||
setTerms: function(terms) {
|
||||
this._searchSystem.setTerms(terms);
|
||||
},
|
||||
|
||||
_maybeSetInitialSelection: function() {
|
||||
let newDefaultResult = null;
|
||||
|
||||
let providers = this._searchSystem.getProviders();
|
||||
for (let i = 0; i < providers.length; i++) {
|
||||
let provider = providers[i];
|
||||
let display = provider.display;
|
||||
|
||||
if (!display.actor.visible)
|
||||
continue;
|
||||
|
||||
let firstResult = display.getFirstResult();
|
||||
if (firstResult) {
|
||||
newDefaultResult = firstResult;
|
||||
break; // select this one!
|
||||
}
|
||||
}
|
||||
|
||||
if (newDefaultResult != this._defaultResult) {
|
||||
if (this._defaultResult)
|
||||
this._defaultResult.setSelected(false);
|
||||
if (newDefaultResult)
|
||||
newDefaultResult.setSelected(this._highlightDefault);
|
||||
|
||||
this._defaultResult = newDefaultResult;
|
||||
}
|
||||
},
|
||||
|
||||
_updateStatusText: function () {
|
||||
let haveResults = this._searchSystem.getProviders().some(function(provider) {
|
||||
let display = provider.display;
|
||||
return (display.getFirstResult() != null);
|
||||
});
|
||||
|
||||
if (!haveResults) {
|
||||
this._statusText.set_text(_("No results."));
|
||||
this._statusBin.show();
|
||||
} else {
|
||||
this._statusBin.hide();
|
||||
}
|
||||
},
|
||||
|
||||
_updateResults: function(searchSystem, provider, results) {
|
||||
let terms = searchSystem.getTerms();
|
||||
let display = provider.display;
|
||||
|
||||
display.updateSearch(results, terms, Lang.bind(this, function() {
|
||||
this._maybeSetInitialSelection();
|
||||
this._updateStatusText();
|
||||
}));
|
||||
},
|
||||
|
||||
activateDefault: function() {
|
||||
if (this._defaultResult)
|
||||
this._defaultResult.activate();
|
||||
},
|
||||
|
||||
highlightDefault: function(highlight) {
|
||||
this._highlightDefault = highlight;
|
||||
if (this._defaultResult)
|
||||
this._defaultResult.setSelected(highlight);
|
||||
},
|
||||
|
||||
navigateFocus: function(direction) {
|
||||
let rtl = this.actor.get_text_direction() == Clutter.TextDirection.RTL;
|
||||
if (direction == Gtk.DirectionType.TAB_BACKWARD ||
|
||||
direction == (rtl ? Gtk.DirectionType.RIGHT
|
||||
: Gtk.DirectionType.LEFT) ||
|
||||
direction == Gtk.DirectionType.UP) {
|
||||
this.actor.navigate_focus(null, direction, false);
|
||||
return;
|
||||
}
|
||||
|
||||
let from = this._defaultResult ? this._defaultResult.actor : null;
|
||||
this.actor.navigate_focus(from, direction, false);
|
||||
}
|
||||
});
|
||||
|
||||
const ProviderIcon = new Lang.Class({
|
||||
Name: 'ProviderIcon',
|
||||
Extends: St.Button,
|
||||
|
||||
PROVIDER_ICON_SIZE: 48,
|
||||
|
||||
_init: function(provider) {
|
||||
this.provider = provider;
|
||||
this.parent({ style_class: 'search-provider-icon',
|
||||
reactive: true,
|
||||
can_focus: true,
|
||||
accessible_name: provider.appInfo.get_name(),
|
||||
track_hover: true });
|
||||
|
||||
this._content = new St.Widget({ layout_manager: new Clutter.BinLayout() });
|
||||
this.set_child(this._content);
|
||||
|
||||
let rtl = (this.get_text_direction() == Clutter.TextDirection.RTL);
|
||||
|
||||
this.moreIcon = new St.Widget({ style_class: 'search-provider-icon-more',
|
||||
visible: false,
|
||||
x_align: rtl ? Clutter.ActorAlign.START : Clutter.ActorAlign.END,
|
||||
y_align: Clutter.ActorAlign.END,
|
||||
x_expand: true,
|
||||
y_expand: true });
|
||||
|
||||
let icon = new St.Icon({ icon_size: this.PROVIDER_ICON_SIZE,
|
||||
gicon: provider.appInfo.get_icon() });
|
||||
this._content.add_actor(icon);
|
||||
this._content.add_actor(this.moreIcon);
|
||||
}
|
||||
});
|
||||
|
567
js/ui/searchDisplay.js
Normal file
567
js/ui/searchDisplay.js
Normal file
@ -0,0 +1,567 @@
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
|
||||
const Clutter = imports.gi.Clutter;
|
||||
const Lang = imports.lang;
|
||||
const Gtk = imports.gi.Gtk;
|
||||
const Meta = imports.gi.Meta;
|
||||
const Signals = imports.signals;
|
||||
const St = imports.gi.St;
|
||||
const Atk = imports.gi.Atk;
|
||||
|
||||
const DND = imports.ui.dnd;
|
||||
const IconGrid = imports.ui.iconGrid;
|
||||
const Main = imports.ui.main;
|
||||
const Overview = imports.ui.overview;
|
||||
const Separator = imports.ui.separator;
|
||||
const Search = imports.ui.search;
|
||||
const Util = imports.misc.util;
|
||||
|
||||
const MAX_LIST_SEARCH_RESULTS_ROWS = 3;
|
||||
const MAX_GRID_SEARCH_RESULTS_ROWS = 1;
|
||||
|
||||
const MaxWidthBin = new Lang.Class({
|
||||
Name: 'MaxWidthBin',
|
||||
Extends: St.Bin,
|
||||
|
||||
vfunc_allocate: function(box, flags) {
|
||||
let themeNode = this.get_theme_node();
|
||||
let maxWidth = themeNode.get_max_width();
|
||||
let availWidth = box.x2 - box.x1;
|
||||
let adjustedBox = box;
|
||||
|
||||
if (availWidth > maxWidth) {
|
||||
let excessWidth = availWidth - maxWidth;
|
||||
adjustedBox.x1 += Math.floor(excessWidth / 2);
|
||||
adjustedBox.x2 -= Math.floor(excessWidth / 2);
|
||||
}
|
||||
|
||||
this.parent(adjustedBox, flags);
|
||||
}
|
||||
});
|
||||
|
||||
const SearchResult = new Lang.Class({
|
||||
Name: 'SearchResult',
|
||||
|
||||
_init: function(provider, metaInfo, terms) {
|
||||
this.provider = provider;
|
||||
this.metaInfo = metaInfo;
|
||||
this.terms = terms;
|
||||
|
||||
this.actor = new St.Button({ reactive: true,
|
||||
can_focus: true,
|
||||
track_hover: true,
|
||||
x_align: St.Align.START,
|
||||
y_fill: true });
|
||||
|
||||
this.actor._delegate = this;
|
||||
this.actor.connect('clicked', Lang.bind(this, this.activate));
|
||||
},
|
||||
|
||||
activate: function() {
|
||||
this.provider.activateResult(this.metaInfo.id, this.terms);
|
||||
Main.overview.toggle();
|
||||
},
|
||||
|
||||
setSelected: function(selected) {
|
||||
if (selected)
|
||||
this.actor.add_style_pseudo_class('selected');
|
||||
else
|
||||
this.actor.remove_style_pseudo_class('selected');
|
||||
}
|
||||
});
|
||||
|
||||
const ListSearchResult = new Lang.Class({
|
||||
Name: 'ListSearchResult',
|
||||
Extends: SearchResult,
|
||||
|
||||
ICON_SIZE: 64,
|
||||
|
||||
_init: function(provider, metaInfo, terms) {
|
||||
this.parent(provider, metaInfo, terms);
|
||||
|
||||
this.actor.style_class = 'list-search-result';
|
||||
this.actor.x_fill = true;
|
||||
|
||||
let content = new St.BoxLayout({ style_class: 'list-search-result-content',
|
||||
vertical: false });
|
||||
this.actor.set_child(content);
|
||||
|
||||
// An icon for, or thumbnail of, content
|
||||
let icon = this.metaInfo['createIcon'](this.ICON_SIZE);
|
||||
if (icon) {
|
||||
content.add(icon);
|
||||
}
|
||||
|
||||
let details = new St.BoxLayout({ vertical: true });
|
||||
content.add(details, { x_fill: true,
|
||||
y_fill: false,
|
||||
x_align: St.Align.START,
|
||||
y_align: St.Align.MIDDLE });
|
||||
|
||||
let title = new St.Label({ style_class: 'list-search-result-title',
|
||||
text: this.metaInfo['name'] })
|
||||
details.add(title, { x_fill: false,
|
||||
y_fill: false,
|
||||
x_align: St.Align.START,
|
||||
y_align: St.Align.START });
|
||||
this.actor.label_actor = title;
|
||||
|
||||
if (this.metaInfo['description']) {
|
||||
let description = new St.Label({ style_class: 'list-search-result-description' });
|
||||
description.clutter_text.set_markup(this.metaInfo['description']);
|
||||
details.add(description, { x_fill: false,
|
||||
y_fill: false,
|
||||
x_align: St.Align.START,
|
||||
y_align: St.Align.END });
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const GridSearchResult = new Lang.Class({
|
||||
Name: 'GridSearchResult',
|
||||
Extends: SearchResult,
|
||||
|
||||
_init: function(provider, metaInfo, terms) {
|
||||
this.parent(provider, metaInfo, terms);
|
||||
|
||||
this.actor.style_class = 'grid-search-result';
|
||||
|
||||
let content = provider.createResultObject(metaInfo, terms);
|
||||
let dragSource = null;
|
||||
|
||||
if (content == null) {
|
||||
let actor = new St.Bin();
|
||||
let icon = new IconGrid.BaseIcon(this.metaInfo['name'],
|
||||
{ createIcon: this.metaInfo['createIcon'] });
|
||||
actor.set_child(icon.actor);
|
||||
actor.label_actor = icon.label;
|
||||
dragSource = icon.icon;
|
||||
content = { actor: actor, icon: icon };
|
||||
} else {
|
||||
if (content._delegate && content._delegate.getDragActorSource)
|
||||
dragSource = content._delegate.getDragActorSource();
|
||||
}
|
||||
|
||||
this.actor.set_child(content.actor);
|
||||
this.actor.label_actor = content.actor.label_actor;
|
||||
this.icon = content.icon;
|
||||
|
||||
let draggable = DND.makeDraggable(this.actor);
|
||||
draggable.connect('drag-begin',
|
||||
Lang.bind(this, function() {
|
||||
Main.overview.beginItemDrag(this);
|
||||
}));
|
||||
draggable.connect('drag-cancelled',
|
||||
Lang.bind(this, function() {
|
||||
Main.overview.cancelledItemDrag(this);
|
||||
}));
|
||||
draggable.connect('drag-end',
|
||||
Lang.bind(this, function() {
|
||||
Main.overview.endItemDrag(this);
|
||||
}));
|
||||
|
||||
if (!dragSource)
|
||||
// not exactly right, but alignment problems are hard to notice
|
||||
dragSource = content;
|
||||
this._dragActorSource = dragSource;
|
||||
},
|
||||
|
||||
getDragActorSource: function() {
|
||||
return this._dragActorSource;
|
||||
},
|
||||
|
||||
getDragActor: function() {
|
||||
return this.metaInfo['createIcon'](Main.overview.dashIconSize);
|
||||
},
|
||||
|
||||
shellWorkspaceLaunch: function(params) {
|
||||
if (this.provider.dragActivateResult)
|
||||
this.provider.dragActivateResult(this.metaInfo.id, params);
|
||||
else
|
||||
this.provider.activateResult(this.metaInfo.id, this.terms);
|
||||
}
|
||||
});
|
||||
|
||||
const SearchResultsBase = new Lang.Class({
|
||||
Name: 'SearchResultsBase',
|
||||
|
||||
_init: function(provider) {
|
||||
this.provider = provider;
|
||||
|
||||
this._terms = [];
|
||||
|
||||
this.actor = new St.BoxLayout({ style_class: 'search-section',
|
||||
vertical: true });
|
||||
|
||||
this._resultDisplayBin = new St.Bin({ x_fill: true,
|
||||
y_fill: true });
|
||||
this.actor.add(this._resultDisplayBin, { expand: true });
|
||||
|
||||
let separator = new Separator.HorizontalSeparator({ style_class: 'search-section-separator' });
|
||||
this.actor.add(separator.actor);
|
||||
},
|
||||
|
||||
destroy: function() {
|
||||
this.actor.destroy();
|
||||
this._terms = [];
|
||||
},
|
||||
|
||||
_clearResultDisplay: function() {
|
||||
},
|
||||
|
||||
clear: function() {
|
||||
this._clearResultDisplay();
|
||||
this.actor.hide();
|
||||
},
|
||||
|
||||
_keyFocusIn: function(actor) {
|
||||
this.emit('key-focus-in', actor);
|
||||
},
|
||||
|
||||
_setMoreIconVisible: function(visible) {
|
||||
},
|
||||
|
||||
updateSearch: function(providerResults, terms, callback) {
|
||||
this._terms = terms;
|
||||
|
||||
if (providerResults.length == 0) {
|
||||
this._clearResultDisplay();
|
||||
this.actor.hide();
|
||||
callback();
|
||||
} else {
|
||||
let maxResults = this._getMaxDisplayedResults();
|
||||
let results = providerResults.slice(0, maxResults);
|
||||
let hasMoreResults = results.length < providerResults.length;
|
||||
|
||||
this.provider.getResultMetas(results, Lang.bind(this, function(metas) {
|
||||
this.clear();
|
||||
|
||||
// To avoid CSS transitions causing flickering when
|
||||
// the first search result stays the same, we hide the
|
||||
// content while filling in the results.
|
||||
this.actor.hide();
|
||||
this._clearResultDisplay();
|
||||
this._renderResults(metas);
|
||||
this._setMoreIconVisible(hasMoreResults && this.provider.canLaunchSearch);
|
||||
this.actor.show();
|
||||
callback();
|
||||
}));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const ListSearchResults = new Lang.Class({
|
||||
Name: 'ListSearchResults',
|
||||
Extends: SearchResultsBase,
|
||||
|
||||
_init: function(provider) {
|
||||
this.parent(provider);
|
||||
|
||||
this._container = new St.BoxLayout({ style_class: 'search-section-content' });
|
||||
this.providerIcon = new ProviderIcon(provider);
|
||||
this.providerIcon.connect('key-focus-in', Lang.bind(this, this._keyFocusIn));
|
||||
this.providerIcon.connect('clicked', Lang.bind(this,
|
||||
function() {
|
||||
provider.launchSearch(this._terms);
|
||||
Main.overview.toggle();
|
||||
}));
|
||||
|
||||
this._container.add(this.providerIcon, { x_fill: false,
|
||||
y_fill: false,
|
||||
x_align: St.Align.START,
|
||||
y_align: St.Align.START });
|
||||
|
||||
this._content = new St.BoxLayout({ style_class: 'list-search-results',
|
||||
vertical: true });
|
||||
this._container.add(this._content, { expand: true });
|
||||
|
||||
this._resultDisplayBin.set_child(this._container);
|
||||
},
|
||||
|
||||
_setMoreIconVisible: function(visible) {
|
||||
this.providerIcon.moreIcon.visible = true;
|
||||
},
|
||||
|
||||
_getMaxDisplayedResults: function() {
|
||||
return MAX_LIST_SEARCH_RESULTS_ROWS;
|
||||
},
|
||||
|
||||
_renderResults: function(metas) {
|
||||
for (let i = 0; i < metas.length; i++) {
|
||||
let display = new ListSearchResult(this.provider, metas[i], this._terms);
|
||||
display.actor.connect('key-focus-in', Lang.bind(this, this._keyFocusIn));
|
||||
this._content.add_actor(display.actor);
|
||||
}
|
||||
},
|
||||
|
||||
_clearResultDisplay: function () {
|
||||
this._content.destroy_all_children();
|
||||
},
|
||||
|
||||
getFirstResult: function() {
|
||||
if (this._content.get_n_children() > 0)
|
||||
return this._content.get_child_at_index(0)._delegate;
|
||||
else
|
||||
return null;
|
||||
}
|
||||
});
|
||||
Signals.addSignalMethods(ListSearchResults.prototype);
|
||||
|
||||
const GridSearchResults = new Lang.Class({
|
||||
Name: 'GridSearchResults',
|
||||
Extends: SearchResultsBase,
|
||||
|
||||
_init: function(provider) {
|
||||
this.parent(provider);
|
||||
|
||||
this._grid = new IconGrid.IconGrid({ rowLimit: MAX_GRID_SEARCH_RESULTS_ROWS,
|
||||
xAlign: St.Align.START });
|
||||
this._bin = new St.Bin({ x_align: St.Align.MIDDLE });
|
||||
this._bin.set_child(this._grid.actor);
|
||||
|
||||
this._resultDisplayBin.set_child(this._bin);
|
||||
},
|
||||
|
||||
_getMaxDisplayedResults: function() {
|
||||
return this._grid.columnsForWidth(this._bin.width) * this._grid.getRowLimit();
|
||||
},
|
||||
|
||||
_renderResults: function(metas) {
|
||||
for (let i = 0; i < metas.length; i++) {
|
||||
let display = new GridSearchResult(this.provider, metas[i], this._terms);
|
||||
display.actor.connect('key-focus-in', Lang.bind(this, this._keyFocusIn));
|
||||
this._grid.addItem(display);
|
||||
}
|
||||
},
|
||||
|
||||
_clearResultDisplay: function () {
|
||||
this._grid.removeAll();
|
||||
},
|
||||
|
||||
getFirstResult: function() {
|
||||
if (this._grid.visibleItemsCount() > 0)
|
||||
return this._grid.getItemAtIndex(0)._delegate;
|
||||
else
|
||||
return null;
|
||||
}
|
||||
});
|
||||
Signals.addSignalMethods(GridSearchResults.prototype);
|
||||
|
||||
const SearchResults = new Lang.Class({
|
||||
Name: 'SearchResults',
|
||||
|
||||
_init: function(searchSystem) {
|
||||
this._searchSystem = searchSystem;
|
||||
this._searchSystem.connect('search-updated', Lang.bind(this, this._updateResults));
|
||||
|
||||
this.actor = new St.BoxLayout({ name: 'searchResults',
|
||||
vertical: true });
|
||||
|
||||
this._content = new St.BoxLayout({ name: 'searchResultsContent',
|
||||
vertical: true });
|
||||
this._contentBin = new MaxWidthBin({ name: 'searchResultsBin',
|
||||
x_fill: true,
|
||||
y_fill: true,
|
||||
child: this._content });
|
||||
|
||||
let scrollChild = new St.BoxLayout();
|
||||
scrollChild.add(this._contentBin, { expand: true });
|
||||
|
||||
this._scrollView = new St.ScrollView({ x_fill: true,
|
||||
y_fill: false,
|
||||
overlay_scrollbars: true,
|
||||
style_class: 'search-display vfade' });
|
||||
this._scrollView.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC);
|
||||
this._scrollView.add_actor(scrollChild);
|
||||
let action = new Clutter.PanAction({ interpolate: true });
|
||||
action.connect('pan', Lang.bind(this, this._onPan));
|
||||
this._scrollView.add_action(action);
|
||||
|
||||
this.actor.add(this._scrollView, { x_fill: true,
|
||||
y_fill: true,
|
||||
expand: true,
|
||||
x_align: St.Align.START,
|
||||
y_align: St.Align.START });
|
||||
|
||||
this._statusText = new St.Label({ style_class: 'search-statustext' });
|
||||
this._statusBin = new St.Bin({ x_align: St.Align.MIDDLE,
|
||||
y_align: St.Align.MIDDLE });
|
||||
this._content.add(this._statusBin, { expand: true });
|
||||
this._statusBin.add_actor(this._statusText);
|
||||
this._providers = this._searchSystem.getProviders();
|
||||
this._providerDisplays = {};
|
||||
for (let i = 0; i < this._providers.length; i++) {
|
||||
this.createProviderDisplay(this._providers[i]);
|
||||
}
|
||||
|
||||
this._highlightDefault = false;
|
||||
this._defaultResult = null;
|
||||
},
|
||||
|
||||
_onPan: function(action) {
|
||||
let [dist, dx, dy] = action.get_motion_delta(0);
|
||||
let adjustment = this._scrollView.vscroll.adjustment;
|
||||
adjustment.value -= (dy / this.actor.height) * adjustment.page_size;
|
||||
return false;
|
||||
},
|
||||
|
||||
_keyFocusIn: function(provider, actor) {
|
||||
Util.ensureActorVisibleInScrollView(this._scrollView, actor);
|
||||
},
|
||||
|
||||
createProviderDisplay: function(provider) {
|
||||
let providerDisplay = null;
|
||||
|
||||
if (provider.appInfo) {
|
||||
providerDisplay = new ListSearchResults(provider);
|
||||
} else {
|
||||
providerDisplay = new GridSearchResults(provider);
|
||||
}
|
||||
|
||||
providerDisplay.connect('key-focus-in', Lang.bind(this, this._keyFocusIn));
|
||||
this._providerDisplays[provider.id] = providerDisplay;
|
||||
this._content.add(providerDisplay.actor);
|
||||
},
|
||||
|
||||
destroyProviderDisplay: function(provider) {
|
||||
this._providerDisplays[provider.id].destroy();
|
||||
delete this._providerDisplays[provider.id];
|
||||
},
|
||||
|
||||
_clearDisplay: function() {
|
||||
for (let i = 0; i < this._providers.length; i++) {
|
||||
let provider = this._providers[i];
|
||||
let providerDisplay = this._providerDisplays[provider.id];
|
||||
providerDisplay.clear();
|
||||
}
|
||||
},
|
||||
|
||||
reset: function() {
|
||||
this._searchSystem.reset();
|
||||
this._statusBin.hide();
|
||||
this._clearDisplay();
|
||||
this._defaultResult = null;
|
||||
},
|
||||
|
||||
startingSearch: function() {
|
||||
this.reset();
|
||||
this._statusText.set_text(_("Searching…"));
|
||||
this._statusBin.show();
|
||||
},
|
||||
|
||||
_maybeSetInitialSelection: function() {
|
||||
let newDefaultResult = null;
|
||||
|
||||
for (let i = 0; i < this._providers.length; i++) {
|
||||
let provider = this._providers[i];
|
||||
let display = this._providerDisplays[provider.id];
|
||||
|
||||
if (!display.actor.visible)
|
||||
continue;
|
||||
|
||||
let firstResult = display.getFirstResult();
|
||||
if (firstResult) {
|
||||
newDefaultResult = firstResult;
|
||||
break; // select this one!
|
||||
}
|
||||
}
|
||||
|
||||
if (newDefaultResult != this._defaultResult) {
|
||||
if (this._defaultResult)
|
||||
this._defaultResult.setSelected(false);
|
||||
if (newDefaultResult)
|
||||
newDefaultResult.setSelected(this._highlightDefault);
|
||||
|
||||
this._defaultResult = newDefaultResult;
|
||||
}
|
||||
},
|
||||
|
||||
_updateStatusText: function () {
|
||||
let haveResults = false;
|
||||
|
||||
for (let i = 0; i < this._providers.length; i++) {
|
||||
let provider = this._providers[i];
|
||||
let display = this._providerDisplays[provider.id];
|
||||
if (display.getFirstResult()) {
|
||||
haveResults = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!haveResults) {
|
||||
this._statusText.set_text(_("No results."));
|
||||
this._statusBin.show();
|
||||
} else {
|
||||
this._statusBin.hide();
|
||||
}
|
||||
},
|
||||
|
||||
_updateResults: function(searchSystem, results) {
|
||||
let terms = searchSystem.getTerms();
|
||||
let [provider, providerResults] = results;
|
||||
let display = this._providerDisplays[provider.id];
|
||||
|
||||
display.updateSearch(providerResults, terms, Lang.bind(this, function() {
|
||||
this._maybeSetInitialSelection();
|
||||
this._updateStatusText();
|
||||
}));
|
||||
},
|
||||
|
||||
activateDefault: function() {
|
||||
if (this._defaultResult)
|
||||
this._defaultResult.activate();
|
||||
},
|
||||
|
||||
highlightDefault: function(highlight) {
|
||||
this._highlightDefault = highlight;
|
||||
if (this._defaultResult)
|
||||
this._defaultResult.setSelected(highlight);
|
||||
},
|
||||
|
||||
navigateFocus: function(direction) {
|
||||
let rtl = this.actor.get_text_direction() == Clutter.TextDirection.RTL;
|
||||
if (direction == Gtk.DirectionType.TAB_BACKWARD ||
|
||||
direction == (rtl ? Gtk.DirectionType.RIGHT
|
||||
: Gtk.DirectionType.LEFT) ||
|
||||
direction == Gtk.DirectionType.UP) {
|
||||
this.actor.navigate_focus(null, direction, false);
|
||||
return;
|
||||
}
|
||||
|
||||
let from = this._defaultResult ? this._defaultResult.actor : null;
|
||||
this.actor.navigate_focus(from, direction, false);
|
||||
}
|
||||
});
|
||||
|
||||
const ProviderIcon = new Lang.Class({
|
||||
Name: 'ProviderIcon',
|
||||
Extends: St.Button,
|
||||
|
||||
PROVIDER_ICON_SIZE: 48,
|
||||
|
||||
_init: function(provider) {
|
||||
this.provider = provider;
|
||||
this.parent({ style_class: 'search-provider-icon',
|
||||
reactive: true,
|
||||
can_focus: true,
|
||||
accessible_name: provider.appInfo.get_name(),
|
||||
track_hover: true });
|
||||
|
||||
this._content = new St.Widget({ layout_manager: new Clutter.BinLayout() });
|
||||
this.set_child(this._content);
|
||||
|
||||
let rtl = (this.get_text_direction() == Clutter.TextDirection.RTL);
|
||||
|
||||
this.moreIcon = new St.Widget({ style_class: 'search-provider-icon-more',
|
||||
visible: false,
|
||||
x_align: rtl ? Clutter.ActorAlign.START : Clutter.ActorAlign.END,
|
||||
y_align: Clutter.ActorAlign.END,
|
||||
x_expand: true,
|
||||
y_expand: true });
|
||||
|
||||
let icon = new St.Icon({ icon_size: this.PROVIDER_ICON_SIZE,
|
||||
gicon: provider.appInfo.get_icon() });
|
||||
this._content.add_actor(icon);
|
||||
this._content.add_actor(this.moreIcon);
|
||||
}
|
||||
});
|
@ -102,12 +102,19 @@ const _modes = {
|
||||
}
|
||||
};
|
||||
|
||||
function _loadMode(file, info) {
|
||||
function _getModes(modesLoadedCallback) {
|
||||
FileUtils.collectFromDatadirsAsync('modes',
|
||||
{ processFile: _loadMode,
|
||||
loadedCallback: modesLoadedCallback,
|
||||
data: _modes });
|
||||
}
|
||||
|
||||
function _loadMode(file, info, loadedData) {
|
||||
let name = info.get_name();
|
||||
let suffix = name.indexOf('.json');
|
||||
let modeName = suffix == -1 ? name : name.slice(name, suffix);
|
||||
|
||||
if (_modes.hasOwnProperty(modeName))
|
||||
if (loadedData.hasOwnProperty(modeName))
|
||||
return;
|
||||
|
||||
let fileContent, success, tag, newMode;
|
||||
@ -118,24 +125,19 @@ function _loadMode(file, info) {
|
||||
return;
|
||||
}
|
||||
|
||||
_modes[modeName] = {};
|
||||
loadedData[modeName] = {};
|
||||
let propBlacklist = ['unlockDialog'];
|
||||
for (let prop in _modes[DEFAULT_MODE]) {
|
||||
for (let prop in loadedData[DEFAULT_MODE]) {
|
||||
if (newMode[prop] !== undefined &&
|
||||
propBlacklist.indexOf(prop) == -1)
|
||||
_modes[modeName][prop] = newMode[prop];
|
||||
loadedData[modeName][prop]= newMode[prop];
|
||||
}
|
||||
_modes[modeName]['isPrimary'] = true;
|
||||
}
|
||||
|
||||
function _loadModes() {
|
||||
FileUtils.collectFromDatadirs('modes', false, _loadMode);
|
||||
loadedData[modeName]['isPrimary'] = true;
|
||||
}
|
||||
|
||||
function listModes() {
|
||||
_loadModes();
|
||||
Mainloop.idle_add(function() {
|
||||
let names = Object.getOwnPropertyNames(_modes);
|
||||
_getModes(function(modes) {
|
||||
let names = Object.getOwnPropertyNames(modes);
|
||||
for (let i = 0; i < names.length; i++)
|
||||
if (_modes[names[i]].isPrimary)
|
||||
print(names[i]);
|
||||
@ -147,13 +149,17 @@ function listModes() {
|
||||
const SessionMode = new Lang.Class({
|
||||
Name: 'SessionMode',
|
||||
|
||||
_init: function() {
|
||||
_loadModes();
|
||||
let isPrimary = (_modes[global.session_mode] &&
|
||||
_modes[global.session_mode].isPrimary);
|
||||
let mode = isPrimary ? global.session_mode : 'user';
|
||||
this._modeStack = [mode];
|
||||
this._sync();
|
||||
init: function() {
|
||||
_getModes(Lang.bind(this, function(modes) {
|
||||
this._modes = modes;
|
||||
let primary = modes[global.session_mode] &&
|
||||
modes[global.session_mode].isPrimary;
|
||||
let mode = primary ? global.session_mode : 'user';
|
||||
this._modeStack = [mode];
|
||||
this._sync();
|
||||
|
||||
this.emit('sessions-loaded');
|
||||
}));
|
||||
},
|
||||
|
||||
pushMode: function(mode) {
|
||||
@ -180,13 +186,13 @@ const SessionMode = new Lang.Class({
|
||||
},
|
||||
|
||||
_sync: function() {
|
||||
let params = _modes[this.currentMode];
|
||||
let params = this._modes[this.currentMode];
|
||||
let defaults;
|
||||
if (params.parentMode)
|
||||
defaults = Params.parse(_modes[params.parentMode],
|
||||
_modes[DEFAULT_MODE]);
|
||||
defaults = Params.parse(this._modes[params.parentMode],
|
||||
this._modes[DEFAULT_MODE]);
|
||||
else
|
||||
defaults = _modes[DEFAULT_MODE];
|
||||
defaults = this._modes[DEFAULT_MODE];
|
||||
params = Params.parse(params, defaults);
|
||||
|
||||
// A simplified version of Lang.copyProperties, handles
|
||||
|
@ -15,63 +15,59 @@ const Main = imports.ui.main;
|
||||
const Screenshot = imports.ui.screenshot;
|
||||
const ViewSelector = imports.ui.viewSelector;
|
||||
|
||||
const GnomeShellIface = '<node> \
|
||||
<interface name="org.gnome.Shell"> \
|
||||
<method name="Eval"> \
|
||||
<arg type="s" direction="in" name="script" /> \
|
||||
<arg type="b" direction="out" name="success" /> \
|
||||
<arg type="s" direction="out" name="result" /> \
|
||||
</method> \
|
||||
<method name="FocusSearch"/> \
|
||||
<method name="ShowOSD"> \
|
||||
<arg type="a{sv}" direction="in" name="params"/> \
|
||||
</method> \
|
||||
<method name="FocusApp"> \
|
||||
<arg type="s" direction="in" name="id"/> \
|
||||
</method> \
|
||||
<method name="ShowApplications" /> \
|
||||
<method name="GrabAccelerator"> \
|
||||
<arg type="s" direction="in" name="accelerator"/> \
|
||||
<arg type="u" direction="in" name="flags"/> \
|
||||
<arg type="u" direction="out" name="action"/> \
|
||||
</method> \
|
||||
<method name="GrabAccelerators"> \
|
||||
<arg type="a(su)" direction="in" name="accelerators"/> \
|
||||
<arg type="au" direction="out" name="actions"/> \
|
||||
</method> \
|
||||
<method name="UngrabAccelerator"> \
|
||||
<arg type="u" direction="in" name="action"/> \
|
||||
<arg type="b" direction="out" name="success"/> \
|
||||
</method> \
|
||||
<signal name="AcceleratorActivated"> \
|
||||
<arg name="action" type="u" /> \
|
||||
<arg name="deviceid" type="u" /> \
|
||||
<arg name="timestamp" type="u" /> \
|
||||
</signal> \
|
||||
<property name="Mode" type="s" access="read" /> \
|
||||
<property name="OverviewActive" type="b" access="readwrite" /> \
|
||||
<property name="ShellVersion" type="s" access="read" /> \
|
||||
</interface> \
|
||||
</node>';
|
||||
const GnomeShellIface = <interface name="org.gnome.Shell">
|
||||
<method name="Eval">
|
||||
<arg type="s" direction="in" name="script" />
|
||||
<arg type="b" direction="out" name="success" />
|
||||
<arg type="s" direction="out" name="result" />
|
||||
</method>
|
||||
<method name="FocusSearch"/>
|
||||
<method name="ShowOSD">
|
||||
<arg type="a{sv}" direction="in" name="params"/>
|
||||
</method>
|
||||
<method name="FocusApp">
|
||||
<arg type="s" direction="in" name="id"/>
|
||||
</method>
|
||||
<method name="ShowApplications" />
|
||||
<method name="GrabAccelerator">
|
||||
<arg type="s" direction="in" name="accelerator"/>
|
||||
<arg type="u" direction="in" name="flags"/>
|
||||
<arg type="u" direction="out" name="action"/>
|
||||
</method>
|
||||
<method name="GrabAccelerators">
|
||||
<arg type="a(su)" direction="in" name="accelerators"/>
|
||||
<arg type="au" direction="out" name="actions"/>
|
||||
</method>
|
||||
<method name="UngrabAccelerator">
|
||||
<arg type="u" direction="in" name="action"/>
|
||||
<arg type="b" direction="out" name="success"/>
|
||||
</method>
|
||||
<signal name="AcceleratorActivated">
|
||||
<arg name="action" type="u" />
|
||||
<arg name="deviceid" type="u" />
|
||||
<arg name="timestamp" type="u" />
|
||||
</signal>
|
||||
<property name="Mode" type="s" access="read" />
|
||||
<property name="OverviewActive" type="b" access="readwrite" />
|
||||
<property name="ShellVersion" type="s" access="read" />
|
||||
</interface>;
|
||||
|
||||
const ScreenSaverIface = '<node> \
|
||||
<interface name="org.gnome.ScreenSaver"> \
|
||||
<method name="Lock"> \
|
||||
</method> \
|
||||
<method name="GetActive"> \
|
||||
<arg name="active" direction="out" type="b" /> \
|
||||
</method> \
|
||||
<method name="SetActive"> \
|
||||
<arg name="value" direction="in" type="b" /> \
|
||||
</method> \
|
||||
<method name="GetActiveTime"> \
|
||||
<arg name="value" direction="out" type="u" /> \
|
||||
</method> \
|
||||
<signal name="ActiveChanged"> \
|
||||
<arg name="new_value" type="b" /> \
|
||||
</signal> \
|
||||
</interface> \
|
||||
</node>';
|
||||
const ScreenSaverIface = <interface name="org.gnome.ScreenSaver">
|
||||
<method name="Lock">
|
||||
</method>
|
||||
<method name="GetActive">
|
||||
<arg name="active" direction="out" type="b" />
|
||||
</method>
|
||||
<method name="SetActive">
|
||||
<arg name="value" direction="in" type="b" />
|
||||
</method>
|
||||
<method name="GetActiveTime">
|
||||
<arg name="value" direction="out" type="u" />
|
||||
</method>
|
||||
<signal name="ActiveChanged">
|
||||
<arg name="new_value" type="b" />
|
||||
</signal>
|
||||
</interface>;
|
||||
|
||||
const GnomeShell = new Lang.Class({
|
||||
Name: 'GnomeShellDBus',
|
||||
@ -119,7 +115,7 @@ const GnomeShell = new Lang.Class({
|
||||
returnValue = '';
|
||||
success = true;
|
||||
} catch (e) {
|
||||
returnValue = '' + e;
|
||||
returnValue = JSON.stringify(e);
|
||||
success = false;
|
||||
}
|
||||
return [success, returnValue];
|
||||
@ -133,16 +129,11 @@ const GnomeShell = new Lang.Class({
|
||||
for (let param in params)
|
||||
params[param] = params[param].deep_unpack();
|
||||
|
||||
let monitorIndex = -1;
|
||||
if (params['monitor'])
|
||||
monitorIndex = params['monitor'];
|
||||
|
||||
let icon = null;
|
||||
if (params['icon'])
|
||||
icon = Gio.Icon.new_for_string(params['icon']);
|
||||
|
||||
Main.osdWindow.setIcon(icon);
|
||||
Main.osdWindow.setMonitor (monitorIndex);
|
||||
Main.osdWindow.setLabel(params['label']);
|
||||
Main.osdWindow.setLevel(params['level']);
|
||||
|
||||
@ -255,43 +246,41 @@ const GnomeShell = new Lang.Class({
|
||||
ShellVersion: Config.PACKAGE_VERSION
|
||||
});
|
||||
|
||||
const GnomeShellExtensionsIface = '<node> \
|
||||
<interface name="org.gnome.Shell.Extensions"> \
|
||||
<method name="ListExtensions"> \
|
||||
<arg type="a{sa{sv}}" direction="out" name="extensions" /> \
|
||||
</method> \
|
||||
<method name="GetExtensionInfo"> \
|
||||
<arg type="s" direction="in" name="extension" /> \
|
||||
<arg type="a{sv}" direction="out" name="info" /> \
|
||||
</method> \
|
||||
<method name="GetExtensionErrors"> \
|
||||
<arg type="s" direction="in" name="extension" /> \
|
||||
<arg type="as" direction="out" name="errors" /> \
|
||||
</method> \
|
||||
<signal name="ExtensionStatusChanged"> \
|
||||
<arg type="s" name="uuid"/> \
|
||||
<arg type="i" name="state"/> \
|
||||
<arg type="s" name="error"/> \
|
||||
</signal> \
|
||||
<method name="InstallRemoteExtension"> \
|
||||
<arg type="s" direction="in" name="uuid"/> \
|
||||
<arg type="s" direction="out" name="result"/> \
|
||||
</method> \
|
||||
<method name="UninstallExtension"> \
|
||||
<arg type="s" direction="in" name="uuid"/> \
|
||||
<arg type="b" direction="out" name="success"/> \
|
||||
</method> \
|
||||
<method name="LaunchExtensionPrefs"> \
|
||||
<arg type="s" direction="in" name="uuid"/> \
|
||||
</method> \
|
||||
<method name="ReloadExtension"> \
|
||||
<arg type="s" direction="in" name="uuid"/> \
|
||||
</method> \
|
||||
<method name="CheckForUpdates"> \
|
||||
</method> \
|
||||
<property name="ShellVersion" type="s" access="read" /> \
|
||||
</interface> \
|
||||
</node>';
|
||||
const GnomeShellExtensionsIface = <interface name="org.gnome.Shell.Extensions">
|
||||
<method name="ListExtensions">
|
||||
<arg type="a{sa{sv}}" direction="out" name="extensions" />
|
||||
</method>
|
||||
<method name="GetExtensionInfo">
|
||||
<arg type="s" direction="in" name="extension" />
|
||||
<arg type="a{sv}" direction="out" name="info" />
|
||||
</method>
|
||||
<method name="GetExtensionErrors">
|
||||
<arg type="s" direction="in" name="extension" />
|
||||
<arg type="as" direction="out" name="errors" />
|
||||
</method>
|
||||
<signal name="ExtensionStatusChanged">
|
||||
<arg type="s" name="uuid"/>
|
||||
<arg type="i" name="state"/>
|
||||
<arg type="s" name="error"/>
|
||||
</signal>
|
||||
<method name="InstallRemoteExtension">
|
||||
<arg type="s" direction="in" name="uuid"/>
|
||||
<arg type="s" direction="out" name="result"/>
|
||||
</method>
|
||||
<method name="UninstallExtension">
|
||||
<arg type="s" direction="in" name="uuid"/>
|
||||
<arg type="b" direction="out" name="success"/>
|
||||
</method>
|
||||
<method name="LaunchExtensionPrefs">
|
||||
<arg type="s" direction="in" name="uuid"/>
|
||||
</method>
|
||||
<method name="ReloadExtension">
|
||||
<arg type="s" direction="in" name="uuid"/>
|
||||
</method>
|
||||
<method name="CheckForUpdates">
|
||||
</method>
|
||||
<property name="ShellVersion" type="s" access="read" />
|
||||
</interface>;
|
||||
|
||||
const GnomeShellExtensions = new Lang.Class({
|
||||
Name: 'GnomeShellExtensionsDBus',
|
||||
|
@ -132,14 +132,14 @@ function _setMenuAlignment(entry, stageX) {
|
||||
function _onButtonPressEvent(actor, event, entry) {
|
||||
if (entry.menu.isOpen) {
|
||||
entry.menu.close(BoxPointer.PopupAnimation.FULL);
|
||||
return Clutter.EVENT_STOP;
|
||||
return true;
|
||||
} else if (event.get_button() == 3) {
|
||||
let [stageX, stageY] = event.get_coords();
|
||||
_setMenuAlignment(entry, stageX);
|
||||
entry.menu.open(BoxPointer.PopupAnimation.FULL);
|
||||
return Clutter.EVENT_STOP;
|
||||
return true;
|
||||
}
|
||||
return Clutter.EVENT_PROPAGATE;
|
||||
return false;
|
||||
};
|
||||
|
||||
function _onPopup(actor, entry) {
|
||||
|
@ -521,38 +521,36 @@ const ShellProcessesDialog = new Lang.Class({
|
||||
});
|
||||
Signals.addSignalMethods(ShellProcessesDialog.prototype);
|
||||
|
||||
const GnomeShellMountOpIface = '<node> \
|
||||
<interface name="org.Gtk.MountOperationHandler"> \
|
||||
<method name="AskPassword"> \
|
||||
<arg type="s" direction="in" name="object_id"/> \
|
||||
<arg type="s" direction="in" name="message"/> \
|
||||
<arg type="s" direction="in" name="icon_name"/> \
|
||||
<arg type="s" direction="in" name="default_user"/> \
|
||||
<arg type="s" direction="in" name="default_domain"/> \
|
||||
<arg type="u" direction="in" name="flags"/> \
|
||||
<arg type="u" direction="out" name="response"/> \
|
||||
<arg type="a{sv}" direction="out" name="response_details"/> \
|
||||
</method> \
|
||||
<method name="AskQuestion"> \
|
||||
<arg type="s" direction="in" name="object_id"/> \
|
||||
<arg type="s" direction="in" name="message"/> \
|
||||
<arg type="s" direction="in" name="icon_name"/> \
|
||||
<arg type="as" direction="in" name="choices"/> \
|
||||
<arg type="u" direction="out" name="response"/> \
|
||||
<arg type="a{sv}" direction="out" name="response_details"/> \
|
||||
</method> \
|
||||
<method name="ShowProcesses"> \
|
||||
<arg type="s" direction="in" name="object_id"/> \
|
||||
<arg type="s" direction="in" name="message"/> \
|
||||
<arg type="s" direction="in" name="icon_name"/> \
|
||||
<arg type="ai" direction="in" name="application_pids"/> \
|
||||
<arg type="as" direction="in" name="choices"/> \
|
||||
<arg type="u" direction="out" name="response"/> \
|
||||
<arg type="a{sv}" direction="out" name="response_details"/> \
|
||||
</method> \
|
||||
<method name="Close"/> \
|
||||
</interface> \
|
||||
</node>';
|
||||
const GnomeShellMountOpIface = <interface name="org.Gtk.MountOperationHandler">
|
||||
<method name="AskPassword">
|
||||
<arg type="s" direction="in" name="object_id"/>
|
||||
<arg type="s" direction="in" name="message"/>
|
||||
<arg type="s" direction="in" name="icon_name"/>
|
||||
<arg type="s" direction="in" name="default_user"/>
|
||||
<arg type="s" direction="in" name="default_domain"/>
|
||||
<arg type="u" direction="in" name="flags"/>
|
||||
<arg type="u" direction="out" name="response"/>
|
||||
<arg type="a{sv}" direction="out" name="response_details"/>
|
||||
</method>
|
||||
<method name="AskQuestion">
|
||||
<arg type="s" direction="in" name="object_id"/>
|
||||
<arg type="s" direction="in" name="message"/>
|
||||
<arg type="s" direction="in" name="icon_name"/>
|
||||
<arg type="as" direction="in" name="choices"/>
|
||||
<arg type="u" direction="out" name="response"/>
|
||||
<arg type="a{sv}" direction="out" name="response_details"/>
|
||||
</method>
|
||||
<method name="ShowProcesses">
|
||||
<arg type="s" direction="in" name="object_id"/>
|
||||
<arg type="s" direction="in" name="message"/>
|
||||
<arg type="s" direction="in" name="icon_name"/>
|
||||
<arg type="ai" direction="in" name="application_pids"/>
|
||||
<arg type="as" direction="in" name="choices"/>
|
||||
<arg type="u" direction="out" name="response"/>
|
||||
<arg type="a{sv}" direction="out" name="response_details"/>
|
||||
</method>
|
||||
<method name="Close"/>
|
||||
</interface>;
|
||||
|
||||
const ShellMountOperationType = {
|
||||
NONE: 0,
|
||||
|
@ -111,12 +111,12 @@ const Slider = new Lang.Class({
|
||||
},
|
||||
|
||||
_startDragging: function(actor, event) {
|
||||
return this.startDragging(event);
|
||||
this.startDragging(event);
|
||||
},
|
||||
|
||||
startDragging: function(event) {
|
||||
if (this._dragging)
|
||||
return Clutter.EVENT_PROPAGATE;
|
||||
return false;
|
||||
|
||||
this._dragging = true;
|
||||
|
||||
@ -129,7 +129,7 @@ const Slider = new Lang.Class({
|
||||
let absX, absY;
|
||||
[absX, absY] = event.get_coords();
|
||||
this._moveHandle(absX, absY);
|
||||
return Clutter.EVENT_STOP;
|
||||
return true;
|
||||
},
|
||||
|
||||
_endDragging: function() {
|
||||
@ -143,7 +143,7 @@ const Slider = new Lang.Class({
|
||||
|
||||
this.emit('drag-end');
|
||||
}
|
||||
return Clutter.EVENT_STOP;
|
||||
return true;
|
||||
},
|
||||
|
||||
scroll: function(event) {
|
||||
@ -151,7 +151,7 @@ const Slider = new Lang.Class({
|
||||
let delta;
|
||||
|
||||
if (event.is_pointer_emulated())
|
||||
return Clutter.EVENT_PROPAGATE;
|
||||
return;
|
||||
|
||||
if (direction == Clutter.ScrollDirection.DOWN) {
|
||||
delta = -SLIDER_SCROLL_STEP;
|
||||
@ -168,18 +168,17 @@ const Slider = new Lang.Class({
|
||||
|
||||
this.actor.queue_repaint();
|
||||
this.emit('value-changed', this._value);
|
||||
return Clutter.EVENT_STOP;
|
||||
},
|
||||
|
||||
_onScrollEvent: function(actor, event) {
|
||||
return this.scroll(event);
|
||||
this.scroll(event);
|
||||
},
|
||||
|
||||
_motionEvent: function(actor, event) {
|
||||
let absX, absY;
|
||||
[absX, absY] = event.get_coords();
|
||||
this._moveHandle(absX, absY);
|
||||
return Clutter.EVENT_STOP;
|
||||
return true;
|
||||
},
|
||||
|
||||
onKeyPressEvent: function (actor, event) {
|
||||
@ -190,9 +189,9 @@ const Slider = new Lang.Class({
|
||||
this.actor.queue_repaint();
|
||||
this.emit('value-changed', this._value);
|
||||
this.emit('drag-end');
|
||||
return Clutter.EVENT_STOP;
|
||||
return true;
|
||||
}
|
||||
return Clutter.EVENT_PROPAGATE;
|
||||
return false;
|
||||
},
|
||||
|
||||
_moveHandle: function(absX, absY) {
|
||||
|
@ -2,7 +2,6 @@
|
||||
|
||||
const Clutter = imports.gi.Clutter;
|
||||
const Gio = imports.gi.Gio;
|
||||
const GLib = imports.gi.GLib;
|
||||
const Lang = imports.lang;
|
||||
const Mainloop = imports.mainloop;
|
||||
const St = imports.gi.St;
|
||||
@ -44,7 +43,9 @@ const ATIndicator = new Lang.Class({
|
||||
this._hbox = new St.BoxLayout({ style_class: 'panel-status-menu-box' });
|
||||
this._hbox.add_child(new St.Icon({ style_class: 'system-status-icon',
|
||||
icon_name: 'preferences-desktop-accessibility-symbolic' }));
|
||||
this._hbox.add_child(PopupMenu.unicodeArrow(St.Side.BOTTOM));
|
||||
this._hbox.add_child(new St.Label({ text: '\u25BE',
|
||||
y_expand: true,
|
||||
y_align: Clutter.ActorAlign.CENTER }));
|
||||
|
||||
this.actor.add_child(this._hbox);
|
||||
|
||||
@ -95,7 +96,7 @@ const ATIndicator = new Lang.Class({
|
||||
|
||||
this.actor.visible = alwaysShow || items.some(function(f) { return !!f.state; });
|
||||
|
||||
return GLib.SOURCE_REMOVE;
|
||||
return false;
|
||||
},
|
||||
|
||||
_queueSyncMenuVisibility: function() {
|
||||
|
@ -2,26 +2,17 @@
|
||||
|
||||
const Clutter = imports.gi.Clutter;
|
||||
const GLib = imports.gi.GLib;
|
||||
const Gio = imports.gi.Gio;
|
||||
const GnomeBluetoothApplet = imports.gi.GnomeBluetoothApplet;
|
||||
const GnomeBluetooth = imports.gi.GnomeBluetooth;
|
||||
const Lang = imports.lang;
|
||||
const St = imports.gi.St;
|
||||
|
||||
const Main = imports.ui.main;
|
||||
const MessageTray = imports.ui.messageTray;
|
||||
const NotificationDaemon = imports.ui.notificationDaemon;
|
||||
const PanelMenu = imports.ui.panelMenu;
|
||||
const PopupMenu = imports.ui.popupMenu;
|
||||
|
||||
const BUS_NAME = 'org.gnome.SettingsDaemon.Rfkill';
|
||||
const OBJECT_PATH = '/org/gnome/SettingsDaemon/Rfkill';
|
||||
|
||||
const RfkillManagerInterface = '<node> \
|
||||
<interface name="org.gnome.SettingsDaemon.Rfkill"> \
|
||||
<property name="BluetoothAirplaneMode" type="b" access="readwrite" /> \
|
||||
</interface> \
|
||||
</node>';
|
||||
|
||||
const RfkillManagerProxy = Gio.DBusProxy.makeProxyWrapper(RfkillManagerInterface);
|
||||
|
||||
const Indicator = new Lang.Class({
|
||||
Name: 'BTIndicator',
|
||||
Extends: PanelMenu.SystemIndicator,
|
||||
@ -32,69 +23,237 @@ const Indicator = new Lang.Class({
|
||||
this._indicator = this._addIndicator();
|
||||
this._indicator.icon_name = 'bluetooth-active-symbolic';
|
||||
|
||||
this._proxy = new RfkillManagerProxy(Gio.DBus.session, BUS_NAME, OBJECT_PATH,
|
||||
Lang.bind(this, function(proxy, error) {
|
||||
if (error) {
|
||||
log(error.message);
|
||||
return;
|
||||
}
|
||||
}));
|
||||
|
||||
// The Bluetooth menu only appears when Bluetooth is in use,
|
||||
// so just statically build it with a "Turn Off" menu item.
|
||||
this._item = new PopupMenu.PopupSubMenuMenuItem(_("Bluetooth"), true);
|
||||
this._item.icon.icon_name = 'bluetooth-active-symbolic';
|
||||
this._item.menu.addAction(_("Turn Off"), Lang.bind(this, function() {
|
||||
this._proxy.BluetoothAirplaneMode = true;
|
||||
this._applet.killswitch_state = GnomeBluetooth.KillswitchState.SOFT_BLOCKED;
|
||||
}));
|
||||
this._item.menu.addSettingsAction(_("Bluetooth Settings"), 'gnome-bluetooth-panel.desktop');
|
||||
this.menu.addMenuItem(this._item);
|
||||
|
||||
this._client = new GnomeBluetooth.Client();
|
||||
this._model = this._client.get_model();
|
||||
this._model.connect('row-changed', Lang.bind(this, this._sync));
|
||||
this._model.connect('row-deleted', Lang.bind(this, this._sync));
|
||||
this._model.connect('row-inserted', Lang.bind(this, this._sync));
|
||||
this._applet = new GnomeBluetoothApplet.Applet();
|
||||
this._applet.connect('devices-changed', Lang.bind(this, this._sync));
|
||||
this._sync();
|
||||
},
|
||||
|
||||
_getDefaultAdapter: function() {
|
||||
let [ret, iter] = this._model.get_iter_first();
|
||||
while (ret) {
|
||||
let isDefault = this._model.get_value(iter,
|
||||
GnomeBluetooth.Column.DEFAULT);
|
||||
if (isDefault)
|
||||
return iter;
|
||||
ret = this._model.iter_next(iter);
|
||||
}
|
||||
return null;
|
||||
},
|
||||
|
||||
_getNConnectedDevices: function() {
|
||||
let adapter = this._getDefaultAdapter();
|
||||
if (!adapter)
|
||||
return 0;
|
||||
|
||||
let nDevices = 0;
|
||||
let [ret, iter] = this._model.iter_children(adapter);
|
||||
while (ret) {
|
||||
let isConnected = this._model.get_value(iter,
|
||||
GnomeBluetooth.Column.CONNECTED);
|
||||
if (isConnected)
|
||||
nDevices++;
|
||||
ret = this._model.iter_next(iter);
|
||||
}
|
||||
return nDevices;
|
||||
this._applet.connect('pincode-request', Lang.bind(this, this._pinRequest));
|
||||
this._applet.connect('confirm-request', Lang.bind(this, this._confirmRequest));
|
||||
this._applet.connect('auth-request', Lang.bind(this, this._authRequest));
|
||||
this._applet.connect('auth-service-request', Lang.bind(this, this._authServiceRequest));
|
||||
this._applet.connect('cancel-request', Lang.bind(this, this._cancelRequest));
|
||||
},
|
||||
|
||||
_sync: function() {
|
||||
let nDevices = this._getNConnectedDevices();
|
||||
let connectedDevices = this._applet.get_devices().filter(function(device) {
|
||||
return device.connected;
|
||||
});
|
||||
let nDevices = connectedDevices.length;
|
||||
|
||||
let on = nDevices > 0;
|
||||
this._indicator.visible = on;
|
||||
this._item.actor.visible = on;
|
||||
|
||||
if (on)
|
||||
this._item.status.text = ngettext("%d Connected Device", "%d Connected Devices", nDevices).format(nDevices);
|
||||
this._item.status.text = ngettext("%d Connected Device", "%d Connected Devices").format(nDevices);
|
||||
},
|
||||
|
||||
_ensureSource: function() {
|
||||
if (!this._source) {
|
||||
this._source = new MessageTray.Source(_("Bluetooth"), 'bluetooth-active');
|
||||
this._source.policy = new NotificationDaemon.NotificationApplicationPolicy('gnome-bluetooth-panel');
|
||||
Main.messageTray.add(this._source);
|
||||
}
|
||||
},
|
||||
|
||||
_authRequest: function(applet, device_path, name, long_name) {
|
||||
this._ensureSource();
|
||||
this._source.notify(new AuthNotification(this._source, this._applet, device_path, name, long_name));
|
||||
},
|
||||
|
||||
_authServiceRequest: function(applet, device_path, name, long_name, uuid) {
|
||||
this._ensureSource();
|
||||
this._source.notify(new AuthServiceNotification(this._source, this._applet, device_path, name, long_name, uuid));
|
||||
},
|
||||
|
||||
_confirmRequest: function(applet, device_path, name, long_name, pin) {
|
||||
this._ensureSource();
|
||||
this._source.notify(new ConfirmNotification(this._source, this._applet, device_path, name, long_name, pin));
|
||||
},
|
||||
|
||||
_pinRequest: function(applet, device_path, name, long_name, numeric) {
|
||||
this._ensureSource();
|
||||
this._source.notify(new PinNotification(this._source, this._applet, device_path, name, long_name, numeric));
|
||||
},
|
||||
|
||||
_cancelRequest: function() {
|
||||
this._source.destroy();
|
||||
}
|
||||
});
|
||||
|
||||
const AuthNotification = new Lang.Class({
|
||||
Name: 'AuthNotification',
|
||||
Extends: MessageTray.Notification,
|
||||
|
||||
_init: function(source, applet, device_path, name, long_name) {
|
||||
this.parent(source,
|
||||
_("Bluetooth"),
|
||||
_("Authorization request from %s").format(name),
|
||||
{ customContent: true });
|
||||
this.setResident(true);
|
||||
|
||||
this._applet = applet;
|
||||
this._devicePath = device_path;
|
||||
this.addBody(_("Device %s wants to pair with this computer").format(long_name));
|
||||
|
||||
this.addButton('allow', _("Allow"));
|
||||
this.addButton('deny', _("Deny"));
|
||||
|
||||
this.connect('action-invoked', Lang.bind(this, function(self, action) {
|
||||
if (action == 'allow')
|
||||
this._applet.agent_reply_confirm(this._devicePath, true);
|
||||
else
|
||||
this._applet.agent_reply_confirm(this._devicePath, false);
|
||||
this.destroy();
|
||||
}));
|
||||
}
|
||||
});
|
||||
|
||||
const AuthServiceNotification = new Lang.Class({
|
||||
Name: 'AuthServiceNotification',
|
||||
Extends: MessageTray.Notification,
|
||||
|
||||
_init: function(source, applet, device_path, name, long_name, uuid) {
|
||||
this.parent(source,
|
||||
_("Bluetooth"),
|
||||
_("Authorization request from %s").format(name),
|
||||
{ customContent: true });
|
||||
this.setResident(true);
|
||||
|
||||
this._applet = applet;
|
||||
this._devicePath = device_path;
|
||||
this.addBody(_("Device %s wants access to the service '%s'").format(long_name, uuid));
|
||||
|
||||
this.addButton('always-grant', _("Always grant access"));
|
||||
this.addButton('grant', _("Grant this time only"));
|
||||
this.addButton('reject', _("Reject"));
|
||||
|
||||
this.connect('action-invoked', Lang.bind(this, function(self, action) {
|
||||
switch (action) {
|
||||
case 'always-grant':
|
||||
this._applet.agent_reply_auth_service(this._devicePath, true, true);
|
||||
break;
|
||||
case 'grant':
|
||||
this._applet.agent_reply_auth_service(this._devicePath, true, false);
|
||||
break;
|
||||
case 'reject':
|
||||
default:
|
||||
this._applet.agent_reply_auth_service(this._devicePath, false, false);
|
||||
}
|
||||
this.destroy();
|
||||
}));
|
||||
}
|
||||
});
|
||||
|
||||
const ConfirmNotification = new Lang.Class({
|
||||
Name: 'ConfirmNotification',
|
||||
Extends: MessageTray.Notification,
|
||||
|
||||
_init: function(source, applet, device_path, name, long_name, pin) {
|
||||
this.parent(source,
|
||||
_("Bluetooth"),
|
||||
/* Translators: argument is the device short name */
|
||||
_("Pairing confirmation for %s").format(name),
|
||||
{ customContent: true });
|
||||
this.setResident(true);
|
||||
|
||||
this._applet = applet;
|
||||
this._devicePath = device_path;
|
||||
this.addBody(_("Device %s wants to pair with this computer").format(long_name));
|
||||
this.addBody(_("Please confirm whether the Passkey '%06d' matches the one on the device.").format(pin));
|
||||
|
||||
/* Translators: this is the verb, not the noun */
|
||||
this.addButton('matches', _("Matches"));
|
||||
this.addButton('does-not-match', _("Does not match"));
|
||||
|
||||
this.connect('action-invoked', Lang.bind(this, function(self, action) {
|
||||
if (action == 'matches')
|
||||
this._applet.agent_reply_confirm(this._devicePath, true);
|
||||
else
|
||||
this._applet.agent_reply_confirm(this._devicePath, false);
|
||||
this.destroy();
|
||||
}));
|
||||
}
|
||||
});
|
||||
|
||||
const PinNotification = new Lang.Class({
|
||||
Name: 'PinNotification',
|
||||
Extends: MessageTray.Notification,
|
||||
|
||||
_init: function(source, applet, device_path, name, long_name, numeric) {
|
||||
this.parent(source,
|
||||
_("Bluetooth"),
|
||||
_("Pairing request for %s").format(name),
|
||||
{ customContent: true });
|
||||
this.setResident(true);
|
||||
|
||||
this._applet = applet;
|
||||
this._devicePath = device_path;
|
||||
this._numeric = numeric;
|
||||
this.addBody(_("Device %s wants to pair with this computer").format(long_name));
|
||||
this.addBody(_("Please enter the PIN mentioned on the device."));
|
||||
|
||||
this._entry = new St.Entry();
|
||||
this._entry.connect('key-release-event', Lang.bind(this, function(entry, event) {
|
||||
let key = event.get_key_symbol();
|
||||
if (key == Clutter.KEY_Return) {
|
||||
if (this._canActivateOkButton())
|
||||
this.emit('action-invoked', 'ok');
|
||||
return true;
|
||||
} else if (key == Clutter.KEY_Escape) {
|
||||
this.emit('action-invoked', 'cancel');
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}));
|
||||
this.addActor(this._entry);
|
||||
|
||||
this.addButton('ok', _("OK"));
|
||||
this.addButton('cancel', _("Cancel"));
|
||||
|
||||
this.setButtonSensitive('ok', this._canActivateOkButton());
|
||||
this._entry.clutter_text.connect('text-changed', Lang.bind(this,
|
||||
function() {
|
||||
this.setButtonSensitive('ok', this._canActivateOkButton());
|
||||
}));
|
||||
|
||||
this.connect('action-invoked', Lang.bind(this, function(self, action) {
|
||||
if (action == 'ok') {
|
||||
if (this._numeric) {
|
||||
let num = parseInt(this._entry.text);
|
||||
if (isNaN(num)) {
|
||||
// user reply was empty, or was invalid
|
||||
// cancel the operation
|
||||
num = -1;
|
||||
}
|
||||
this._applet.agent_reply_passkey(this._devicePath, num);
|
||||
} else
|
||||
this._applet.agent_reply_pincode(this._devicePath, this._entry.text);
|
||||
} else {
|
||||
if (this._numeric)
|
||||
this._applet.agent_reply_passkey(this._devicePath, -1);
|
||||
else
|
||||
this._applet.agent_reply_pincode(this._devicePath, null);
|
||||
}
|
||||
this.destroy();
|
||||
}));
|
||||
},
|
||||
|
||||
_canActivateOkButton: function() {
|
||||
// PINs have a fixed length of 6
|
||||
if (this._numeric)
|
||||
return this._entry.clutter_text.text.length == 6;
|
||||
else
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
@ -11,11 +11,9 @@ const Slider = imports.ui.slider;
|
||||
const BUS_NAME = 'org.gnome.SettingsDaemon.Power';
|
||||
const OBJECT_PATH = '/org/gnome/SettingsDaemon/Power';
|
||||
|
||||
const BrightnessInterface = '<node> \
|
||||
<interface name="org.gnome.SettingsDaemon.Power.Screen"> \
|
||||
<property name="Brightness" type="i" access="readwrite"/> \
|
||||
</interface> \
|
||||
</node>';
|
||||
const BrightnessInterface = <interface name="org.gnome.SettingsDaemon.Power.Screen">
|
||||
<property name='Brightness' type='i' access='readwrite'/>
|
||||
</interface>;
|
||||
|
||||
const BrightnessProxy = Gio.DBusProxy.makeProxyWrapper(BrightnessInterface);
|
||||
|
||||
@ -48,7 +46,7 @@ const Indicator = new Lang.Class({
|
||||
this._item.actor.add(icon);
|
||||
this._item.actor.add(this._slider.actor, { expand: true });
|
||||
this._item.actor.connect('button-press-event', Lang.bind(this, function(actor, event) {
|
||||
return this._slider.startDragging(event);
|
||||
this._slider.startDragging(event);
|
||||
}));
|
||||
this._item.actor.connect('key-press-event', Lang.bind(this, function(actor, event) {
|
||||
return this._slider.onKeyPressEvent(actor, event);
|
||||
|
@ -41,13 +41,11 @@ const MAX_INPUT_SOURCE_ACTIVATION_TIME = 4000; // ms
|
||||
const BUS_NAME = 'org.gnome.SettingsDaemon.Keyboard';
|
||||
const OBJECT_PATH = '/org/gnome/SettingsDaemon/Keyboard';
|
||||
|
||||
const KeyboardManagerInterface = '<node> \
|
||||
<interface name="org.gnome.SettingsDaemon.Keyboard"> \
|
||||
<method name="SetInputSource"> \
|
||||
<arg type="u" direction="in" /> \
|
||||
</method> \
|
||||
</interface> \
|
||||
</node>';
|
||||
const KeyboardManagerInterface = <interface name="org.gnome.SettingsDaemon.Keyboard">
|
||||
<method name="SetInputSource">
|
||||
<arg type="u" direction="in" />
|
||||
</method>
|
||||
</interface>;
|
||||
|
||||
const KeyboardManagerProxy = Gio.DBusProxy.makeProxyWrapper(KeyboardManagerInterface);
|
||||
|
||||
@ -341,7 +339,9 @@ const InputSourceIndicator = new Lang.Class({
|
||||
|
||||
this._hbox = new St.BoxLayout({ style_class: 'panel-status-menu-box' });
|
||||
this._hbox.add_child(this._container);
|
||||
this._hbox.add_child(PopupMenu.unicodeArrow(St.Side.BOTTOM));
|
||||
this._hbox.add_child(new St.Label({ text: '\u25BE',
|
||||
y_expand: true,
|
||||
y_align: Clutter.ActorAlign.CENTER }));
|
||||
|
||||
this.actor.add_child(this._hbox);
|
||||
this.actor.add_style_class_name('panel-status-button');
|
||||
|
@ -16,6 +16,7 @@ const Main = imports.ui.main;
|
||||
const PanelMenu = imports.ui.panelMenu;
|
||||
const PopupMenu = imports.ui.popupMenu;
|
||||
const MessageTray = imports.ui.messageTray;
|
||||
const NotificationDaemon = imports.ui.notificationDaemon;
|
||||
const ModalDialog = imports.ui.modalDialog;
|
||||
const ModemManager = imports.misc.modemManager;
|
||||
const Util = imports.misc.util;
|
||||
@ -72,27 +73,6 @@ function ssidToLabel(ssid) {
|
||||
return label;
|
||||
}
|
||||
|
||||
function ensureActiveConnectionProps(active, settings) {
|
||||
if (!active._connection) {
|
||||
active._connection = settings.get_connection_by_path(active.connection);
|
||||
|
||||
// This list is guaranteed to have only one device in it.
|
||||
let device = active.get_devices()[0]._delegate;
|
||||
active._primaryDevice = device;
|
||||
}
|
||||
}
|
||||
|
||||
function createSettingsAction(label, device) {
|
||||
let item = new PopupMenu.PopupMenuItem(label);
|
||||
|
||||
item.connect('activate', function() {
|
||||
Util.spawnApp(['gnome-control-center', 'network', 'show-device',
|
||||
device.get_path()]);
|
||||
});
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
const NMConnectionItem = new Lang.Class({
|
||||
Name: 'NMConnectionItem',
|
||||
|
||||
@ -190,7 +170,8 @@ const NMConnectionSection = new Lang.Class({
|
||||
},
|
||||
|
||||
destroy: function() {
|
||||
this.item.destroy();
|
||||
this.statusItem.destroy();
|
||||
this.section.destroy();
|
||||
},
|
||||
|
||||
_sync: function() {
|
||||
@ -287,12 +268,12 @@ const NMConnectionDevice = new Lang.Class({
|
||||
Extends: NMConnectionSection,
|
||||
Abstract: true,
|
||||
|
||||
_init: function(client, device, settings) {
|
||||
_init: function(client, device) {
|
||||
this.parent(client);
|
||||
this._device = device;
|
||||
this._settings = settings;
|
||||
|
||||
this._autoConnectItem = this.item.menu.addAction(_("Connect"), Lang.bind(this, this._autoConnect));
|
||||
this.item.menu.addSettingsAction(_("Network Settings"), 'gnome-network-panel.desktop');
|
||||
|
||||
this._stateChangedId = this._device.connect('state-changed', Lang.bind(this, this._deviceStateChanged));
|
||||
this._activeConnectionChangedId = this._device.connect('notify::active-connection', Lang.bind(this, this._activeConnectionChanged));
|
||||
@ -320,7 +301,6 @@ const NMConnectionDevice = new Lang.Class({
|
||||
this._activeConnection = this._device.active_connection;
|
||||
|
||||
if (this._activeConnection) {
|
||||
ensureActiveConnectionProps(this._activeConnection, this._settings);
|
||||
let item = this._connectionItems.get(this._activeConnection._connection.get_uuid());
|
||||
item.setActiveConnection(this._activeConnection);
|
||||
}
|
||||
@ -376,9 +356,8 @@ const NMConnectionDevice = new Lang.Class({
|
||||
|
||||
switch(this._device.state) {
|
||||
case NetworkManager.DeviceState.DISCONNECTED:
|
||||
return _("Off");
|
||||
case NetworkManager.DeviceState.ACTIVATED:
|
||||
return this.parent();
|
||||
return '';
|
||||
case NetworkManager.DeviceState.UNMANAGED:
|
||||
/* 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) */
|
||||
@ -420,11 +399,8 @@ const NMDeviceModem = new Lang.Class({
|
||||
Extends: NMConnectionDevice,
|
||||
category: NMConnectionCategory.WWAN,
|
||||
|
||||
_init: function(client, device, settings) {
|
||||
this.parent(client, device, settings);
|
||||
|
||||
this.item.menu.addMenuItem(createSettingsAction(_("Mobile Broadband Settings"), device));
|
||||
|
||||
_init: function(client, device) {
|
||||
this.parent(client, device);
|
||||
this._mobileDevice = null;
|
||||
|
||||
let capabilities = device.current_capabilities;
|
||||
@ -438,7 +414,16 @@ const NMDeviceModem = new Lang.Class({
|
||||
this._mobileDevice = new ModemManager.ModemGsm(device.udi);
|
||||
|
||||
if (this._mobileDevice) {
|
||||
this._operatorNameId = this._mobileDevice.connect('notify::operator-name', Lang.bind(this, this._sync));
|
||||
this._operatorNameId = this._mobileDevice.connect('notify::operator-name', Lang.bind(this, function() {
|
||||
if (this._operatorItem) {
|
||||
let name = this._mobileDevice.operator_name;
|
||||
if (name) {
|
||||
this._operatorItem.label.text = name;
|
||||
this._operatorItem.actor.show();
|
||||
} else
|
||||
this._operatorItem.actor.hide();
|
||||
}
|
||||
}));
|
||||
this._signalQualityId = this._mobileDevice.connect('notify::signal-quality', Lang.bind(this, function() {
|
||||
this.emit('icon-changed');
|
||||
}));
|
||||
@ -463,20 +448,6 @@ const NMDeviceModem = new Lang.Class({
|
||||
this.parent();
|
||||
},
|
||||
|
||||
_getStatus: function() {
|
||||
if (!this._client.wwan_hardware_enabled)
|
||||
return _("Hardware Disabled");
|
||||
else if (!this._client.wwan_enabled)
|
||||
/* Translators: this is for a network device that cannot be activated
|
||||
because it's disabled by rfkill (airplane mode) */
|
||||
return _("Disabled");
|
||||
else if (this._device.state == NetworkManager.DeviceState.ACTIVATED &&
|
||||
this._mobileDevice && this._mobileDevice.operator_name)
|
||||
return this._mobileDevice.operator_name;
|
||||
else
|
||||
return this.parent();
|
||||
},
|
||||
|
||||
_getMenuIcon: function() {
|
||||
if (this._device.active_connection)
|
||||
return this.getIndicatorIcon();
|
||||
@ -506,12 +477,6 @@ const NMDeviceBluetooth = new Lang.Class({
|
||||
Extends: NMConnectionDevice,
|
||||
category: NMConnectionCategory.WWAN,
|
||||
|
||||
_init: function(client, device, settings) {
|
||||
this.parent(client, device, settings);
|
||||
|
||||
this.item.menu.addMenuItem(createSettingsAction(_("Mobile Broadband Settings"), device));
|
||||
},
|
||||
|
||||
_autoConnect: function() {
|
||||
// FIXME: DUN devices are configured like modems, so
|
||||
// We need to spawn the mobile wizard
|
||||
@ -549,30 +514,31 @@ const NMWirelessDialogItem = new Lang.Class({
|
||||
this._network = network;
|
||||
this._ap = network.accessPoints[0];
|
||||
|
||||
this.actor = new St.BoxLayout({ style_class: 'nm-dialog-item',
|
||||
can_focus: true,
|
||||
reactive: true });
|
||||
this.actor = new St.Button({ style_class: 'nm-dialog-item',
|
||||
can_focus: true,
|
||||
x_fill: true });
|
||||
this.actor.connect('key-focus-in', Lang.bind(this, function() {
|
||||
this.emit('selected');
|
||||
}));
|
||||
let action = new Clutter.ClickAction();
|
||||
action.connect('clicked', Lang.bind(this, function() {
|
||||
this.actor.connect('clicked', Lang.bind(this, function() {
|
||||
this.actor.grab_key_focus();
|
||||
}));
|
||||
this.actor.add_action(action);
|
||||
|
||||
this._content = new St.BoxLayout({ style_class: 'nm-dialog-item-box' });
|
||||
this.actor.set_child(this._content);
|
||||
|
||||
let title = ssidToLabel(this._ap.get_ssid());
|
||||
this._label = new St.Label({ text: title });
|
||||
|
||||
this.actor.label_actor = this._label;
|
||||
this.actor.add(this._label, { x_align: St.Align.START });
|
||||
this._content.add(this._label, { x_align: St.Align.START });
|
||||
|
||||
this._selectedIcon = new St.Icon({ style_class: 'nm-dialog-icon',
|
||||
icon_name: 'object-select-symbolic' });
|
||||
this.actor.add(this._selectedIcon);
|
||||
this._content.add(this._selectedIcon);
|
||||
|
||||
this._icons = new St.BoxLayout({ style_class: 'nm-dialog-icons' });
|
||||
this.actor.add(this._icons, { expand: true, x_fill: false, x_align: St.Align.END });
|
||||
this._content.add(this._icons, { expand: true, x_fill: false, x_align: St.Align.END });
|
||||
|
||||
this._secureIcon = new St.Icon({ style_class: 'nm-dialog-icon' });
|
||||
if (this._ap._secType != NMAccessPointSecurity.NONE)
|
||||
@ -955,13 +921,13 @@ const NMWirelessDialog = new Lang.Class({
|
||||
|
||||
_selectNetwork: function(network) {
|
||||
if (this._selectedNetwork)
|
||||
this._selectedNetwork.item.actor.remove_style_pseudo_class('selected');
|
||||
this._selectedNetwork.item.actor.checked = false;
|
||||
|
||||
this._selectedNetwork = network;
|
||||
this._updateSensitivity();
|
||||
|
||||
if (this._selectedNetwork)
|
||||
this._selectedNetwork.item.actor.add_style_pseudo_class('selected');
|
||||
this._selectedNetwork.item.actor.checked = true;
|
||||
},
|
||||
|
||||
_createNetworkItem: function(network) {
|
||||
@ -992,10 +958,9 @@ const NMDeviceWireless = new Lang.Class({
|
||||
this._toggleItem.connect('activate', Lang.bind(this, this._toggleWifi));
|
||||
this.item.menu.addMenuItem(this._toggleItem);
|
||||
|
||||
this.item.menu.addMenuItem(createSettingsAction(_("Wi-Fi Settings"), device));
|
||||
this.item.menu.addSettingsAction(_("Network Settings"), 'gnome-network-panel.desktop');
|
||||
|
||||
this._wirelessEnabledChangedId = this._client.connect('notify::wireless-enabled', Lang.bind(this, this._sync));
|
||||
this._wirelessHwEnabledChangedId = this._client.connect('notify::wireless-hardware-enabled', Lang.bind(this, this._sync));
|
||||
this._wirelessEnabledChangedId = this._device.connect('notify::wireless-enabled', Lang.bind(this, this._sync));
|
||||
this._activeApChangedId = this._device.connect('notify::active-access-point', Lang.bind(this, this._activeApChanged));
|
||||
this._stateChangedId = this._device.connect('state-changed', Lang.bind(this, this._deviceStateChanged));
|
||||
|
||||
@ -1015,14 +980,6 @@ const NMDeviceWireless = new Lang.Class({
|
||||
this._activeAccessPoint.disconnect(this._strengthChangedId);
|
||||
this._strengthChangedId = 0;
|
||||
}
|
||||
if (this._wirelessEnabledChangedId) {
|
||||
this._client.disconnect(this._wirelessEnabledChangedId);
|
||||
this._wirelessEnabledChangedId = 0;
|
||||
}
|
||||
if (this._wirelessHwEnabledChangedId) {
|
||||
this._client.disconnect(this._wirelessHwEnabledChangedId);
|
||||
this._wirelessHwEnabledChangedId = 0;
|
||||
}
|
||||
|
||||
this.item.destroy();
|
||||
},
|
||||
@ -1081,7 +1038,6 @@ const NMDeviceWireless = new Lang.Class({
|
||||
|
||||
_sync: function() {
|
||||
this._toggleItem.label.text = this._client.wireless_enabled ? _("Turn Off") : _("Turn On");
|
||||
this._toggleItem.actor.visible = this._client.wireless_hardware_enabled;
|
||||
|
||||
this.item.status.text = this._getStatus();
|
||||
this.item.icon.icon_name = this._getMenuIcon();
|
||||
@ -1095,17 +1051,10 @@ const NMDeviceWireless = new Lang.Class({
|
||||
|
||||
_getStatus: function() {
|
||||
let ap = this._device.active_access_point;
|
||||
if (!ap)
|
||||
return _("Off"); // XXX -- interpret actual status
|
||||
|
||||
if (ap)
|
||||
return ssidToLabel(ap.get_ssid());
|
||||
else if (!this._client.wireless_hardware_enabled)
|
||||
return _("Hardware Disabled");
|
||||
else if (!this._client.wireless_enabled)
|
||||
return _("Off");
|
||||
else if (this._device.state == NetworkManager.DeviceState.DISCONNECTED)
|
||||
return _("Not Connected");
|
||||
else
|
||||
return '';
|
||||
return ssidToLabel(ap.get_ssid());
|
||||
},
|
||||
|
||||
_getMenuIcon: function() {
|
||||
@ -1116,8 +1065,7 @@ const NMDeviceWireless = new Lang.Class({
|
||||
},
|
||||
|
||||
getIndicatorIcon: function() {
|
||||
if (this._device.state >= NetworkManager.DeviceState.PREPARE &&
|
||||
this._device.state < NetworkManager.DeviceState.ACTIVATED)
|
||||
if (this._device.active_connection.state == NetworkManager.ActiveConnectionState.ACTIVATING)
|
||||
return 'network-wireless-acquiring-symbolic';
|
||||
|
||||
let ap = this._device.active_access_point;
|
||||
@ -1365,7 +1313,7 @@ const NMApplet = new Lang.Class({
|
||||
if (!this._source) {
|
||||
this._source = new MessageTray.Source(_("Network Manager"),
|
||||
'network-transmit-receive');
|
||||
this._source.policy = new MessageTray.NotificationApplicationPolicy('gnome-network-panel');
|
||||
this._source.policy = new NotificationDaemon.NotificationApplicationPolicy('gnome-network-panel');
|
||||
|
||||
this._source.connect('destroy', Lang.bind(this, function() {
|
||||
this._source = null;
|
||||
@ -1477,18 +1425,28 @@ const NMApplet = new Lang.Class({
|
||||
devices.splice(pos, 1);
|
||||
},
|
||||
|
||||
_ensureActiveConnectionProps: function(a) {
|
||||
if (!a._connection) {
|
||||
a._connection = this._settings.get_connection_by_path(a.connection);
|
||||
|
||||
// This list is guaranteed to have only one device in it.
|
||||
let device = a.get_devices()[0]._delegate;
|
||||
a._primaryDevice = device;
|
||||
}
|
||||
},
|
||||
|
||||
_getMainConnection: function() {
|
||||
let connection;
|
||||
|
||||
connection = this._client.get_primary_connection();
|
||||
if (connection) {
|
||||
ensureActiveConnectionProps(connection, this._settings);
|
||||
this._ensureActiveConnectionProps(connection);
|
||||
return connection;
|
||||
}
|
||||
|
||||
connection = this._client.get_activating_connection();
|
||||
if (connection) {
|
||||
ensureActiveConnectionProps(connection, this._settings);
|
||||
this._ensureActiveConnectionProps(connection);
|
||||
return connection;
|
||||
}
|
||||
|
||||
@ -1524,7 +1482,7 @@ const NMApplet = new Lang.Class({
|
||||
return (a instanceof NMClient.VPNConnection);
|
||||
});
|
||||
vpnConnections.forEach(Lang.bind(this, function(a) {
|
||||
ensureActiveConnectionProps(a, this._settings);
|
||||
this._ensureActiveConnectionProps(a);
|
||||
}));
|
||||
this._vpnSection.setActiveConnections(vpnConnections);
|
||||
|
||||
@ -1627,7 +1585,6 @@ const NMApplet = new Lang.Class({
|
||||
_updateIcon: function() {
|
||||
if (!this._client.networking_enabled || !this._mainConnection) {
|
||||
this._primaryIndicator.icon_name = 'network-offline-symbolic';
|
||||
this._primaryIndicator.visible = true;
|
||||
} else {
|
||||
let dev = this._mainConnection._primaryDevice;
|
||||
this._primaryIndicator.visible = (dev != null);
|
||||
|
@ -8,22 +8,20 @@ const Main = imports.ui.main;
|
||||
const PanelMenu = imports.ui.panelMenu;
|
||||
const PopupMenu = imports.ui.popupMenu;
|
||||
|
||||
const BUS_NAME = 'org.freedesktop.UPower';
|
||||
const OBJECT_PATH = '/org/freedesktop/UPower/devices/DisplayDevice';
|
||||
const BUS_NAME = 'org.gnome.SettingsDaemon.Power';
|
||||
const OBJECT_PATH = '/org/gnome/SettingsDaemon/Power';
|
||||
|
||||
const DisplayDeviceInterface = '<node> \
|
||||
<interface name="org.freedesktop.UPower.Device"> \
|
||||
<property name="Type" type="u" access="read"/> \
|
||||
<property name="State" type="u" access="read"/> \
|
||||
<property name="Percentage" type="d" access="read"/> \
|
||||
<property name="TimeToEmpty" type="x" access="read"/> \
|
||||
<property name="TimeToFull" type="x" access="read"/> \
|
||||
<property name="IsPresent" type="b" access="read"/> \
|
||||
<property name="IconName" type="s" access="read"/> \
|
||||
</interface> \
|
||||
</node>';
|
||||
const PowerManagerInterface = <interface name="org.gnome.SettingsDaemon.Power">
|
||||
<method name="GetDevices">
|
||||
<arg type="a(susdut)" direction="out" />
|
||||
</method>
|
||||
<method name="GetPrimaryDevice">
|
||||
<arg type="(susdut)" direction="out" />
|
||||
</method>
|
||||
<property name="Icon" type="s" access="read" />
|
||||
</interface>;
|
||||
|
||||
const PowerManagerProxy = Gio.DBusProxy.makeProxyWrapper(DisplayDeviceInterface);
|
||||
const PowerManagerProxy = Gio.DBusProxy.makeProxyWrapper(PowerManagerInterface);
|
||||
|
||||
const Indicator = new Lang.Class({
|
||||
Name: 'PowerIndicator',
|
||||
@ -34,7 +32,7 @@ const Indicator = new Lang.Class({
|
||||
|
||||
this._indicator = this._addIndicator();
|
||||
|
||||
this._proxy = new PowerManagerProxy(Gio.DBus.system, BUS_NAME, OBJECT_PATH,
|
||||
this._proxy = new PowerManagerProxy(Gio.DBus.session, BUS_NAME, OBJECT_PATH,
|
||||
Lang.bind(this, function(proxy, error) {
|
||||
if (error) {
|
||||
log(error.message);
|
||||
@ -45,7 +43,7 @@ const Indicator = new Lang.Class({
|
||||
this._sync();
|
||||
}));
|
||||
|
||||
this._item = new PopupMenu.PopupSubMenuMenuItem("", true);
|
||||
this._item = new PopupMenu.PopupSubMenuMenuItem(_("Battery"), true);
|
||||
this._item.menu.addSettingsAction(_("Power Settings"), 'gnome-power-panel.desktop');
|
||||
this.menu.addMenuItem(this._item);
|
||||
|
||||
@ -58,18 +56,11 @@ const Indicator = new Lang.Class({
|
||||
this.menu.setSensitive(sensitive);
|
||||
},
|
||||
|
||||
_getStatus: function() {
|
||||
let seconds = 0;
|
||||
_statusForDevice: function(device) {
|
||||
let [device_id, device_type, icon, percentage, state, seconds] = device;
|
||||
|
||||
if (this._proxy.State == UPower.DeviceState.FULLY_CHARGED)
|
||||
if (state == UPower.DeviceState.FULLY_CHARGED)
|
||||
return _("Fully Charged");
|
||||
else if (this._proxy.State == UPower.DeviceState.CHARGING)
|
||||
seconds = this._proxy.TimeToFull;
|
||||
else if (this._proxy.State == UPower.DeviceState.DISCHARGING)
|
||||
seconds = this._proxy.TimeToEmpty;
|
||||
// state is one of PENDING_CHARGING, PENDING_DISCHARGING
|
||||
else
|
||||
return _("Estimating…");
|
||||
|
||||
let time = Math.round(seconds / 60);
|
||||
if (time == 0) {
|
||||
@ -81,43 +72,52 @@ const Indicator = new Lang.Class({
|
||||
let minutes = time % 60;
|
||||
let hours = Math.floor(time / 60);
|
||||
|
||||
if (this._proxy.State == UPower.DeviceState.DISCHARGING) {
|
||||
if (state == UPower.DeviceState.DISCHARGING) {
|
||||
// Translators: this is <hours>:<minutes> Remaining (<percentage>)
|
||||
return _("%d\u2236%02d Remaining (%d%%)").format(hours, minutes, this._proxy.Percentage);
|
||||
return _("%d\u2236%02d Remaining (%d%%)").format(hours, minutes, percentage);
|
||||
}
|
||||
|
||||
if (this._proxy.State == UPower.DeviceState.CHARGING) {
|
||||
if (state == UPower.DeviceState.CHARGING) {
|
||||
// Translators: this is <hours>:<minutes> Until Full (<percentage>)
|
||||
return _("%d\u2236%02d Until Full (%d%%)").format(hours, minutes, this._proxy.Percentage);
|
||||
return _("%d\u2236%02d Until Full (%d%%)").format(hours, minutes, percentage);
|
||||
}
|
||||
|
||||
return null;
|
||||
// state is one of PENDING_CHARGING, PENDING_DISCHARGING
|
||||
return _("Estimating…");
|
||||
},
|
||||
|
||||
_syncStatusLabel: function() {
|
||||
this._proxy.GetPrimaryDeviceRemote(Lang.bind(this, function(result, error) {
|
||||
if (error) {
|
||||
this._item.actor.hide();
|
||||
return;
|
||||
}
|
||||
|
||||
let [device] = result;
|
||||
let [device_id, device_type] = device;
|
||||
if (device_type == UPower.DeviceKind.BATTERY) {
|
||||
this._item.status.text = this._statusForDevice(device);
|
||||
this._item.actor.show();
|
||||
} else {
|
||||
this._item.actor.hide();
|
||||
}
|
||||
}));
|
||||
},
|
||||
|
||||
_syncIcon: function() {
|
||||
let icon = this._proxy.Icon;
|
||||
if (icon) {
|
||||
let gicon = Gio.icon_new_for_string(icon);
|
||||
this._indicator.gicon = gicon;
|
||||
this._item.icon.gicon = gicon;
|
||||
} else {
|
||||
// If there's no battery, then we use the power icon.
|
||||
this._indicator.icon_name = 'system-shutdown-symbolic';
|
||||
}
|
||||
},
|
||||
|
||||
_sync: function() {
|
||||
// Do we have batteries or a UPS?
|
||||
let visible = this._proxy.IsPresent;
|
||||
if (visible) {
|
||||
this._item.actor.show();
|
||||
} else {
|
||||
// If there's no battery, then we use the power icon.
|
||||
this._item.actor.hide();
|
||||
this._indicator.icon_name = 'system-shutdown-symbolic';
|
||||
return;
|
||||
}
|
||||
|
||||
// The icons
|
||||
let icon = this._proxy.IconName;
|
||||
this._indicator.icon_name = icon;
|
||||
this._item.icon.icon_name = icon;
|
||||
|
||||
// The status label
|
||||
this._item.status.text = this._getStatus();
|
||||
|
||||
// The sub-menu heading
|
||||
if (this._proxy.Type == UPower.DeviceKind.UPS)
|
||||
this._item.label.text = _("UPS");
|
||||
else
|
||||
this._item.label.text = _("Battery");
|
||||
},
|
||||
this._syncIcon();
|
||||
this._syncStatusLabel();
|
||||
}
|
||||
});
|
||||
|
@ -9,11 +9,9 @@ const PopupMenu = imports.ui.popupMenu;
|
||||
const BUS_NAME = 'org.gnome.SettingsDaemon.Rfkill';
|
||||
const OBJECT_PATH = '/org/gnome/SettingsDaemon/Rfkill';
|
||||
|
||||
const RfkillManagerInterface = '<node> \
|
||||
<interface name="org.gnome.SettingsDaemon.Rfkill"> \
|
||||
<property name="AirplaneMode" type="b" access="readwrite" /> \
|
||||
</interface> \
|
||||
</node>';
|
||||
const RfkillManagerInterface = <interface name="org.gnome.SettingsDaemon.Rfkill">
|
||||
<property name="AirplaneMode" type="b" access="readwrite" />
|
||||
</interface>;
|
||||
|
||||
const RfkillManagerProxy = Gio.DBusProxy.makeProxyWrapper(RfkillManagerInterface);
|
||||
|
||||
|
@ -18,12 +18,10 @@ const PopupMenu = imports.ui.popupMenu;
|
||||
|
||||
const LOCKDOWN_SCHEMA = 'org.gnome.desktop.lockdown';
|
||||
const SCREENSAVER_SCHEMA = 'org.gnome.desktop.screensaver';
|
||||
const LOGIN_SCREEN_SCHEMA = 'org.gnome.login-screen';
|
||||
const PRIVACY_SCHEMA = 'org.gnome.desktop.privacy'
|
||||
const DISABLE_USER_SWITCH_KEY = 'disable-user-switching';
|
||||
const DISABLE_LOCK_SCREEN_KEY = 'disable-lock-screen';
|
||||
const DISABLE_LOG_OUT_KEY = 'disable-log-out';
|
||||
const DISABLE_RESTART_KEY = 'disable-restart-buttons';
|
||||
const ALWAYS_SHOW_LOG_OUT_KEY = 'always-show-log-out';
|
||||
|
||||
const AltSwitcher = new Lang.Class({
|
||||
@ -81,7 +79,7 @@ const AltSwitcher = new Lang.Class({
|
||||
this._sync();
|
||||
}
|
||||
|
||||
return Clutter.EVENT_PROPAGATE;
|
||||
return false;
|
||||
},
|
||||
});
|
||||
|
||||
@ -93,7 +91,6 @@ const Indicator = new Lang.Class({
|
||||
this.parent();
|
||||
|
||||
this._screenSaverSettings = new Gio.Settings({ schema: SCREENSAVER_SCHEMA });
|
||||
this._loginScreenSettings = new Gio.Settings({ schema: LOGIN_SCREEN_SCHEMA });
|
||||
this._lockdownSettings = new Gio.Settings({ schema: LOCKDOWN_SCHEMA });
|
||||
this._privacySettings = new Gio.Settings({ schema: PRIVACY_SCHEMA });
|
||||
this._orientationSettings = new Gio.Settings({ schema: 'org.gnome.settings-daemon.peripherals.touchscreen' });
|
||||
@ -264,10 +261,7 @@ const Indicator = new Lang.Class({
|
||||
},
|
||||
|
||||
_updatePowerOff: function() {
|
||||
let disabled = Main.sessionMode.isLocked ||
|
||||
(Main.sessionMode.isGreeter &&
|
||||
this._loginScreenSettings.get_boolean(DISABLE_RESTART_KEY));
|
||||
this._powerOffAction.visible = this._haveShutdown && !disabled;
|
||||
this._powerOffAction.visible = this._haveShutdown && !Main.sessionMode.isLocked;
|
||||
this._updateActionsVisibility();
|
||||
},
|
||||
|
||||
@ -279,10 +273,7 @@ const Indicator = new Lang.Class({
|
||||
},
|
||||
|
||||
_updateSuspend: function() {
|
||||
let disabled = Main.sessionMode.isLocked ||
|
||||
(Main.sessionMode.isGreeter &&
|
||||
this._loginScreenSettings.get_boolean(DISABLE_RESTART_KEY));
|
||||
this._suspendAction.visible = this._haveShutdown && !disabled;
|
||||
this._suspendAction.visible = this._haveSuspend && !Main.sessionMode.isLocked;
|
||||
this._updateActionsVisibility();
|
||||
},
|
||||
|
||||
|
@ -42,7 +42,7 @@ const StreamSlider = new Lang.Class({
|
||||
this.item.actor.add(this._icon);
|
||||
this.item.actor.add(this._slider.actor, { expand: true });
|
||||
this.item.actor.connect('button-press-event', Lang.bind(this, function(actor, event) {
|
||||
return this._slider.startDragging(event);
|
||||
this._slider.startDragging(event);
|
||||
}));
|
||||
this.item.actor.connect('key-press-event', Lang.bind(this, function(actor, event) {
|
||||
return this._slider.onKeyPressEvent(actor, event);
|
||||
@ -94,7 +94,7 @@ const StreamSlider = new Lang.Class({
|
||||
},
|
||||
|
||||
scroll: function(event) {
|
||||
return this._slider.scroll(event);
|
||||
this._slider.scroll(event);
|
||||
},
|
||||
|
||||
setValue: function(value) {
|
||||
@ -276,7 +276,7 @@ const VolumeMenu = new Lang.Class({
|
||||
},
|
||||
|
||||
scroll: function(event) {
|
||||
return this._output.scroll(event);
|
||||
this._output.scroll(event);
|
||||
},
|
||||
|
||||
_onControlStateChanged: function() {
|
||||
@ -329,6 +329,6 @@ const Indicator = new Lang.Class({
|
||||
},
|
||||
|
||||
_onScrollEvent: function(actor, event) {
|
||||
return this._volumeMenu.scroll(event);
|
||||
this._volumeMenu.scroll(event);
|
||||
}
|
||||
});
|
||||
|
@ -1,7 +1,6 @@
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
|
||||
const Clutter = imports.gi.Clutter;
|
||||
const GLib = imports.gi.GLib;
|
||||
const Gtk = imports.gi.Gtk;
|
||||
const Lang = imports.lang;
|
||||
const Mainloop = imports.mainloop;
|
||||
@ -164,7 +163,6 @@ const SwitcherPopup = new Lang.Class({
|
||||
Main.osdWindow.cancel();
|
||||
this.actor.opacity = 255;
|
||||
this._initialDelayTimeoutId = 0;
|
||||
return GLib.SOURCE_REMOVE;
|
||||
}));
|
||||
return true;
|
||||
},
|
||||
@ -194,7 +192,7 @@ const SwitcherPopup = new Lang.Class({
|
||||
else
|
||||
this._keyPressHandler(keysym, backwards, action);
|
||||
|
||||
return Clutter.EVENT_STOP;
|
||||
return true;
|
||||
},
|
||||
|
||||
_keyReleaseEvent: function(actor, event) {
|
||||
@ -204,12 +202,11 @@ const SwitcherPopup = new Lang.Class({
|
||||
if (state == 0)
|
||||
this._finish(event.get_time());
|
||||
|
||||
return Clutter.EVENT_STOP;
|
||||
return true;
|
||||
},
|
||||
|
||||
_clickedOutside: function(actor, event) {
|
||||
this.destroy();
|
||||
return Clutter.EVENT_PROPAGATE;
|
||||
},
|
||||
|
||||
_scrollHandler: function(direction) {
|
||||
@ -221,7 +218,6 @@ const SwitcherPopup = new Lang.Class({
|
||||
|
||||
_scrollEvent: function(actor, event) {
|
||||
this._scrollHandler(event.get_scroll_direction());
|
||||
return Clutter.EVENT_PROPAGATE;
|
||||
},
|
||||
|
||||
_itemActivatedHandler: function(n) {
|
||||
@ -255,7 +251,6 @@ const SwitcherPopup = new Lang.Class({
|
||||
_mouseTimedOut: function() {
|
||||
this._motionTimeoutId = 0;
|
||||
this.mouseActive = true;
|
||||
return GLib.SOURCE_REMOVE;
|
||||
},
|
||||
|
||||
_popModal: function() {
|
||||
@ -405,7 +400,6 @@ const SwitcherList = new Lang.Class({
|
||||
|
||||
_onItemEnter: function (index) {
|
||||
this._itemEntered(index);
|
||||
return Clutter.EVENT_PROPAGATE;
|
||||
},
|
||||
|
||||
highlight: function(index, justOutline) {
|
||||
|
@ -11,8 +11,29 @@ const Signals = imports.signals;
|
||||
const Tweener = imports.tweener.tweener;
|
||||
|
||||
// This is a wrapper around imports.tweener.tweener that adds a bit of
|
||||
// Clutter integration. If the tweening target is a Clutter.Actor, then
|
||||
// the tweenings will automatically be removed if the actor is destroyed.
|
||||
// Clutter integration and some additional callbacks:
|
||||
//
|
||||
// 1. If the tweening target is a Clutter.Actor, then the tweenings
|
||||
// will automatically be removed if the actor is destroyed
|
||||
//
|
||||
// 2. If target._delegate.onAnimationStart() exists, it will be
|
||||
// called when the target starts being animated.
|
||||
//
|
||||
// 3. If target._delegate.onAnimationComplete() exists, it will be
|
||||
// called once the target is no longer being animated.
|
||||
//
|
||||
// The onAnimationStart() and onAnimationComplete() callbacks differ
|
||||
// from the tweener onStart and onComplete parameters, in that (1)
|
||||
// they track whether or not the target has *any* tweens attached to
|
||||
// it, as opposed to be called for *each* tween, and (2)
|
||||
// onAnimationComplete() is always called when the object stops being
|
||||
// animated, regardless of whether it stopped normally or abnormally.
|
||||
//
|
||||
// onAnimationComplete() is called at idle time, which means that if a
|
||||
// tween completes and then another is added before returning to the
|
||||
// main loop, the complete callback will not be called (until the new
|
||||
// tween finishes).
|
||||
|
||||
|
||||
// ActionScript Tweener methods that imports.tweener.tweener doesn't
|
||||
// currently implement: getTweens, getVersion, registerTransition,
|
||||
@ -56,6 +77,7 @@ function _wrapTweening(target, tweeningParameters) {
|
||||
if (!Gtk.Settings.get_default().gtk_enable_animations)
|
||||
tweeningParameters['time'] = 0.000001;
|
||||
|
||||
_addHandler(target, tweeningParameters, 'onStart', _tweenStarted);
|
||||
_addHandler(target, tweeningParameters, 'onComplete', _tweenCompleted);
|
||||
}
|
||||
|
||||
@ -63,7 +85,7 @@ function _getTweenState(target) {
|
||||
// If we were paranoid, we could keep a plist mapping targets to
|
||||
// states... but we're not that paranoid.
|
||||
if (!target.__ShellTweenerState)
|
||||
target.__ShellTweenerState = {};
|
||||
_resetTweenState(target);
|
||||
return target.__ShellTweenerState;
|
||||
}
|
||||
|
||||
@ -73,6 +95,8 @@ function _resetTweenState(target) {
|
||||
if (state) {
|
||||
if (state.destroyedId)
|
||||
state.actor.disconnect(state.destroyedId);
|
||||
if (state.idleCompletedId)
|
||||
Mainloop.source_remove(state.idleCompletedId);
|
||||
}
|
||||
|
||||
target.__ShellTweenerState = {};
|
||||
@ -98,9 +122,32 @@ function _actorDestroyed(target) {
|
||||
Tweener.removeTweens(target);
|
||||
}
|
||||
|
||||
function _tweenStarted(target) {
|
||||
let state = _getTweenState(target);
|
||||
let delegate = target._delegate;
|
||||
|
||||
if (!state.running && delegate && delegate.onAnimationStart)
|
||||
delegate.onAnimationStart();
|
||||
state.running = true;
|
||||
}
|
||||
|
||||
function _tweenCompleted(target) {
|
||||
if (!isTweening(target))
|
||||
let state = _getTweenState(target);
|
||||
|
||||
if (!state.idleCompletedId)
|
||||
state.idleCompletedId = Mainloop.idle_add(Lang.bind(null, _idleCompleted, target));
|
||||
}
|
||||
|
||||
function _idleCompleted(target) {
|
||||
let state = _getTweenState(target);
|
||||
let delegate = target._delegate;
|
||||
|
||||
if (!isTweening(target)) {
|
||||
_resetTweenState(target);
|
||||
if (delegate && delegate.onAnimationComplete)
|
||||
delegate.onAnimationComplete();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function getTweenCount(scope) {
|
||||
|
@ -71,7 +71,7 @@ const UnlockDialog = new Lang.Class({
|
||||
child: otherUserLabel,
|
||||
reactive: true,
|
||||
x_align: St.Align.START,
|
||||
x_fill: false });
|
||||
x_fill: true });
|
||||
this._otherUserButton.connect('clicked', Lang.bind(this, this._otherUserClicked));
|
||||
this._promptBox.add_child(this._otherUserButton);
|
||||
} else {
|
||||
|
@ -1,8 +1,7 @@
|
||||
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
//
|
||||
// A widget showing the user avatar and name
|
||||
|
||||
const Clutter = imports.gi.Clutter;
|
||||
const AccountsService = imports.gi.AccountsService;
|
||||
const GLib = imports.gi.GLib;
|
||||
const Gio = imports.gi.Gio;
|
||||
@ -57,90 +56,6 @@ const Avatar = new Lang.Class({
|
||||
}
|
||||
});
|
||||
|
||||
const UserWidgetLabel = new Lang.Class({
|
||||
Name: 'UserWidgetLabel',
|
||||
Extends: St.Widget,
|
||||
|
||||
_init: function(user) {
|
||||
this.parent({ layout_manager: new Clutter.BinLayout() });
|
||||
|
||||
this._user = user;
|
||||
|
||||
this._realNameLabel = new St.Label({ style_class: 'user-widget-label',
|
||||
y_align: Clutter.ActorAlign.CENTER });
|
||||
this.add_child(this._realNameLabel);
|
||||
|
||||
this._userNameLabel = new St.Label({ style_class: 'user-widget-label',
|
||||
y_align: Clutter.ActorAlign.CENTER });
|
||||
this.add_child(this._userNameLabel);
|
||||
|
||||
this._currentLabel = null;
|
||||
|
||||
this._userLoadedId = this._user.connect('notify::is-loaded', Lang.bind(this, this._updateUser));
|
||||
this._userChangedId = this._user.connect('changed', Lang.bind(this, this._updateUser));
|
||||
this._updateUser();
|
||||
|
||||
// We can't override the destroy vfunc because that might be called during
|
||||
// object finalization, and we can't call any JS inside a GC finalize callback,
|
||||
// so we use a signal, that will be disconnected by GObject the first time
|
||||
// the actor is destroyed (which is guaranteed to be as part of a normal
|
||||
// destroy() call from JS, possibly from some ancestor)
|
||||
this.connect('destroy', Lang.bind(this, this._onDestroy));
|
||||
},
|
||||
|
||||
_onDestroy: function() {
|
||||
if (this._userLoadedId != 0) {
|
||||
this._user.disconnect(this._userLoadedId);
|
||||
this._userLoadedId = 0;
|
||||
}
|
||||
|
||||
if (this._userChangedId != 0) {
|
||||
this._user.disconnect(this._userChangedId);
|
||||
this._userChangedId = 0;
|
||||
}
|
||||
},
|
||||
|
||||
vfunc_allocate: function(box, flags) {
|
||||
this.set_allocation(box, flags);
|
||||
|
||||
let availWidth = box.x2 - box.x1;
|
||||
let availHeight = box.y2 - box.y1;
|
||||
|
||||
let [minRealNameWidth, minRealNameHeight,
|
||||
natRealNameWidth, natRealNameHeight] = this._realNameLabel.get_preferred_size();
|
||||
|
||||
let [minUserNameWidth, minUserNameHeight,
|
||||
natUserNameWidth, natUserNameHeight] = this._userNameLabel.get_preferred_size();
|
||||
|
||||
if (natRealNameWidth <= availWidth)
|
||||
this._currentLabel = this._realNameLabel;
|
||||
else
|
||||
this._currentLabel = this._userNameLabel;
|
||||
|
||||
let childBox = new Clutter.ActorBox();
|
||||
childBox.x1 = 0;
|
||||
childBox.y1 = 0;
|
||||
childBox.x2 = availWidth;
|
||||
childBox.y2 = availHeight;
|
||||
|
||||
this._currentLabel.allocate(childBox, flags);
|
||||
},
|
||||
|
||||
vfunc_paint: function() {
|
||||
this._currentLabel.paint();
|
||||
},
|
||||
|
||||
_updateUser: function() {
|
||||
if (this._user.is_loaded) {
|
||||
this._realNameLabel.text = this._user.get_real_name();
|
||||
this._userNameLabel.text = this._user.get_user_name();
|
||||
} else {
|
||||
this._realNameLabel.text = '';
|
||||
this._userNameLabel.text = '';
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
const UserWidget = new Lang.Class({
|
||||
Name: 'UserWidget',
|
||||
|
||||
@ -152,14 +67,22 @@ const UserWidget = new Lang.Class({
|
||||
this.actor.connect('destroy', Lang.bind(this, this._onDestroy));
|
||||
|
||||
this._avatar = new Avatar(user);
|
||||
this.actor.add_child(this._avatar.actor);
|
||||
this.actor.add(this._avatar.actor,
|
||||
{ x_fill: true, y_fill: true });
|
||||
|
||||
this._label = new UserWidgetLabel(user);
|
||||
this.actor.add_child(this._label);
|
||||
this._label = new St.Label({ style_class: 'user-widget-label' });
|
||||
this.actor.add(this._label,
|
||||
{ expand: true,
|
||||
x_fill: true,
|
||||
y_fill: false,
|
||||
y_align: St.Align.MIDDLE });
|
||||
|
||||
this._userLoadedId = this._user.connect('notify::is-loaded', Lang.bind(this, this._updateUser));
|
||||
this._userChangedId = this._user.connect('changed', Lang.bind(this, this._updateUser));
|
||||
this._updateUser();
|
||||
this._userLoadedId = this._user.connect('notify::is-loaded',
|
||||
Lang.bind(this, this._updateUser));
|
||||
this._userChangedId = this._user.connect('changed',
|
||||
Lang.bind(this, this._updateUser));
|
||||
if (this._user.is_loaded)
|
||||
this._updateUser();
|
||||
},
|
||||
|
||||
_onDestroy: function() {
|
||||
@ -175,6 +98,11 @@ const UserWidget = new Lang.Class({
|
||||
},
|
||||
|
||||
_updateUser: function() {
|
||||
if (this._user.is_loaded)
|
||||
this._label.text = this._user.get_real_name();
|
||||
else
|
||||
this._label.text = '';
|
||||
|
||||
this._avatar.update();
|
||||
}
|
||||
});
|
||||
|
@ -2,7 +2,6 @@
|
||||
|
||||
const Clutter = imports.gi.Clutter;
|
||||
const Gio = imports.gi.Gio;
|
||||
const GLib = imports.gi.GLib;
|
||||
const Gtk = imports.gi.Gtk;
|
||||
const Mainloop = imports.mainloop;
|
||||
const Meta = imports.gi.Meta;
|
||||
@ -15,9 +14,12 @@ const AppDisplay = imports.ui.appDisplay;
|
||||
const Main = imports.ui.main;
|
||||
const OverviewControls = imports.ui.overviewControls;
|
||||
const Params = imports.misc.params;
|
||||
const RemoteSearch = imports.ui.remoteSearch;
|
||||
const Search = imports.ui.search;
|
||||
const SearchDisplay = imports.ui.searchDisplay;
|
||||
const ShellEntry = imports.ui.shellEntry;
|
||||
const Tweener = imports.ui.tweener;
|
||||
const Wanda = imports.ui.wanda;
|
||||
const WorkspacesView = imports.ui.workspacesView;
|
||||
|
||||
const SHELL_KEYBINDINGS_SCHEMA = 'org.gnome.shell.keybindings';
|
||||
@ -64,6 +66,8 @@ const ViewSelector = new Lang.Class({
|
||||
this._searchActive = false;
|
||||
this._searchTimeoutId = 0;
|
||||
|
||||
this._searchSystem = new Search.SearchSystem();
|
||||
|
||||
this._entry = searchEntry;
|
||||
ShellEntry.addContextMenu(this._entry);
|
||||
|
||||
@ -99,11 +103,24 @@ const ViewSelector = new Lang.Class({
|
||||
this._appsPage = this._addPage(this.appDisplay.actor,
|
||||
_("Applications"), 'view-grid-symbolic');
|
||||
|
||||
this._searchResults = new Search.SearchResults();
|
||||
this._searchResults = new SearchDisplay.SearchResults(this._searchSystem);
|
||||
this._searchPage = this._addPage(this._searchResults.actor,
|
||||
_("Search"), 'edit-find-symbolic',
|
||||
{ a11yFocus: this._entry });
|
||||
|
||||
this._searchSettings = new Gio.Settings({ schema: Search.SEARCH_PROVIDERS_SCHEMA });
|
||||
this._searchSettings.connect('changed::disabled', Lang.bind(this, this._reloadRemoteProviders));
|
||||
this._searchSettings.connect('changed::disable-external', Lang.bind(this, this._reloadRemoteProviders));
|
||||
this._searchSettings.connect('changed::sort-order', Lang.bind(this, this._reloadRemoteProviders));
|
||||
|
||||
// Default search providers
|
||||
// Wanda comes obviously first
|
||||
this.addSearchProvider(new Wanda.WandaSearchProvider());
|
||||
this.addSearchProvider(new AppDisplay.AppSearchProvider());
|
||||
|
||||
// Load remote search providers provided by applications
|
||||
RemoteSearch.loadRemoteSearchProviders(Lang.bind(this, this.addSearchProvider));
|
||||
|
||||
// Since the entry isn't inside the results container we install this
|
||||
// dummy widget as the last results container child so that we can
|
||||
// include the entry in the keynav tab path
|
||||
@ -158,14 +175,17 @@ const ViewSelector = new Lang.Class({
|
||||
},
|
||||
|
||||
show: function() {
|
||||
this.reset();
|
||||
this._activePage = this._workspacesPage;
|
||||
|
||||
this.reset();
|
||||
this._appsPage.hide();
|
||||
this._searchPage.hide();
|
||||
this._workspacesDisplay.show();
|
||||
this._activePage = null;
|
||||
this._showPage(this._workspacesPage);
|
||||
|
||||
if (!this._workspacesDisplay.activeWorkspaceHasMaximizedWindows())
|
||||
Main.overview.fadeOutDesktop();
|
||||
|
||||
this._showPage(this._workspacesPage, true);
|
||||
},
|
||||
|
||||
zoomFromOverview: function() {
|
||||
@ -187,7 +207,6 @@ const ViewSelector = new Lang.Class({
|
||||
params = Params.parse(params, { a11yFocus: null });
|
||||
|
||||
let page = new St.Bin({ child: actor,
|
||||
visible: false,
|
||||
x_align: St.Align.START,
|
||||
y_align: St.Align.START,
|
||||
x_fill: true,
|
||||
@ -202,7 +221,6 @@ const ViewSelector = new Lang.Class({
|
||||
this._a11yFocusPage(page);
|
||||
})
|
||||
});;
|
||||
page.hide();
|
||||
this.actor.add_actor(page);
|
||||
return page;
|
||||
},
|
||||
@ -212,7 +230,7 @@ const ViewSelector = new Lang.Class({
|
||||
oldPage.hide();
|
||||
|
||||
this.emit('page-empty');
|
||||
this._activePage.navigate_focus(null, Gtk.DirectionType.TAB_FORWARD, false);
|
||||
|
||||
this._activePage.show();
|
||||
Tweener.addTween(this._activePage,
|
||||
{ opacity: 255,
|
||||
@ -268,7 +286,7 @@ const ViewSelector = new Lang.Class({
|
||||
// Ignore events while anything but the overview has
|
||||
// pushed a modal (system modals, looking glass, ...)
|
||||
if (Main.modalCount > 1)
|
||||
return Clutter.EVENT_PROPAGATE;
|
||||
return false;
|
||||
|
||||
let modifiers = event.get_state();
|
||||
let symbol = event.get_key_symbol();
|
||||
@ -280,11 +298,19 @@ const ViewSelector = new Lang.Class({
|
||||
this._showAppsButton.checked = false;
|
||||
else
|
||||
Main.overview.hide();
|
||||
return Clutter.EVENT_STOP;
|
||||
return true;
|
||||
} else if (this._shouldTriggerSearch(symbol)) {
|
||||
this.startSearch(event);
|
||||
} else if (!this._searchActive) {
|
||||
if (symbol == Clutter.Tab || symbol == Clutter.Down) {
|
||||
this._activePage.navigate_focus(null, Gtk.DirectionType.TAB_FORWARD, false);
|
||||
return true;
|
||||
} else if (symbol == Clutter.ISO_Left_Tab) {
|
||||
this._activePage.navigate_focus(null, Gtk.DirectionType.TAB_BACKWARD, false);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return Clutter.EVENT_PROPAGATE;
|
||||
return false;
|
||||
},
|
||||
|
||||
_searchCancelled: function() {
|
||||
@ -400,7 +426,7 @@ const ViewSelector = new Lang.Class({
|
||||
if (symbol == Clutter.Escape) {
|
||||
if (this._isActivated()) {
|
||||
this.reset();
|
||||
return Clutter.EVENT_STOP;
|
||||
return true;
|
||||
}
|
||||
} else if (this._searchActive) {
|
||||
let arrowNext, nextDirection;
|
||||
@ -414,18 +440,18 @@ const ViewSelector = new Lang.Class({
|
||||
|
||||
if (symbol == Clutter.Tab) {
|
||||
this._searchResults.navigateFocus(Gtk.DirectionType.TAB_FORWARD);
|
||||
return Clutter.EVENT_STOP;
|
||||
return true;
|
||||
} else if (symbol == Clutter.ISO_Left_Tab) {
|
||||
this._focusTrap.can_focus = false;
|
||||
this._searchResults.navigateFocus(Gtk.DirectionType.TAB_BACKWARD);
|
||||
this._focusTrap.can_focus = true;
|
||||
return Clutter.EVENT_STOP;
|
||||
return true;
|
||||
} else if (symbol == Clutter.Down) {
|
||||
this._searchResults.navigateFocus(Gtk.DirectionType.DOWN);
|
||||
return Clutter.EVENT_STOP;
|
||||
return true;
|
||||
} else if (symbol == arrowNext && this._text.position == -1) {
|
||||
this._searchResults.navigateFocus(nextDirection);
|
||||
return Clutter.EVENT_STOP;
|
||||
return true;
|
||||
} else if (symbol == Clutter.Return || symbol == Clutter.KP_Enter) {
|
||||
// We can't connect to 'activate' here because search providers
|
||||
// might want to do something with the modifiers in activateDefault.
|
||||
@ -434,10 +460,10 @@ const ViewSelector = new Lang.Class({
|
||||
this._doSearch();
|
||||
}
|
||||
this._searchResults.activateDefault();
|
||||
return Clutter.EVENT_STOP;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return Clutter.EVENT_PROPAGATE;
|
||||
return false;
|
||||
},
|
||||
|
||||
_onCapturedEvent: function(actor, event) {
|
||||
@ -452,7 +478,7 @@ const ViewSelector = new Lang.Class({
|
||||
}
|
||||
}
|
||||
|
||||
return Clutter.EVENT_PROPAGATE;
|
||||
return false;
|
||||
},
|
||||
|
||||
_doSearch: function () {
|
||||
@ -460,10 +486,43 @@ const ViewSelector = new Lang.Class({
|
||||
|
||||
let terms = getTermsForSearchString(this._entry.get_text());
|
||||
|
||||
this._searchResults.setTerms(terms);
|
||||
this._searchSystem.updateSearchResults(terms);
|
||||
this._showPage(this._searchPage);
|
||||
},
|
||||
|
||||
return GLib.SOURCE_REMOVE;
|
||||
_shouldUseSearchProvider: function(provider) {
|
||||
// the disable-external GSetting only affects remote providers
|
||||
if (!provider.isRemoteProvider)
|
||||
return true;
|
||||
|
||||
if (this._searchSettings.get_boolean('disable-external'))
|
||||
return false;
|
||||
|
||||
let appId = provider.appInfo.get_id();
|
||||
let disable = this._searchSettings.get_strv('disabled');
|
||||
return disable.indexOf(appId) == -1;
|
||||
},
|
||||
|
||||
_reloadRemoteProviders: function() {
|
||||
// removeSearchProvider() modifies the provider list we iterate on,
|
||||
// so make a copy first
|
||||
let remoteProviders = this._searchSystem.getRemoteProviders().slice(0);
|
||||
|
||||
remoteProviders.forEach(Lang.bind(this, this.removeSearchProvider));
|
||||
RemoteSearch.loadRemoteSearchProviders(Lang.bind(this, this.addSearchProvider));
|
||||
},
|
||||
|
||||
addSearchProvider: function(provider) {
|
||||
if (!this._shouldUseSearchProvider(provider))
|
||||
return;
|
||||
|
||||
this._searchSystem.registerProvider(provider);
|
||||
this._searchResults.createProviderDisplay(provider);
|
||||
},
|
||||
|
||||
removeSearchProvider: function(provider) {
|
||||
this._searchSystem.unregisterProvider(provider);
|
||||
this._searchResults.destroyProviderDisplay(provider);
|
||||
},
|
||||
|
||||
getActivePage: function() {
|
||||
|
156
js/ui/wanda.js
Normal file
156
js/ui/wanda.js
Normal file
@ -0,0 +1,156 @@
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
|
||||
const GdkPixbuf = imports.gi.GdkPixbuf;
|
||||
const GLib = imports.gi.GLib;
|
||||
const Gio = imports.gi.Gio;
|
||||
const Lang = imports.lang;
|
||||
const St = imports.gi.St;
|
||||
|
||||
const IconGrid = imports.ui.iconGrid;
|
||||
const Layout = imports.ui.layout;
|
||||
const Main = imports.ui.main;
|
||||
const Panel = imports.ui.panel;
|
||||
|
||||
const FISH_NAME = 'wanda';
|
||||
const FISH_FILENAME = 'wanda.png';
|
||||
const FISH_SPEED = 300;
|
||||
const FISH_COMMAND = 'fortune';
|
||||
// The size of an individual frame in the animation
|
||||
const FISH_HEIGHT = 22;
|
||||
const FISH_WIDTH = 36;
|
||||
|
||||
const FISH_GROUP = 'Fish Animation';
|
||||
|
||||
const MAGIC_FISH_KEY = 'free the fish';
|
||||
|
||||
const WandaIcon = new Lang.Class({
|
||||
Name: 'WandaIcon',
|
||||
Extends: IconGrid.BaseIcon,
|
||||
|
||||
_init : function(fish, label, params) {
|
||||
this.parent(label, params);
|
||||
|
||||
this._fish = fish;
|
||||
this._imageFile = GLib.build_filenamev([global.datadir, fish + '.png']);
|
||||
|
||||
this._imgHeight = FISH_HEIGHT;
|
||||
this._imgWidth = FISH_WIDTH;
|
||||
},
|
||||
|
||||
createIcon: function(iconSize) {
|
||||
this._animations = new Panel.Animation(this._imageFile, this._imgWidth, this._imgHeight, FISH_SPEED);
|
||||
this._animations.play();
|
||||
return this._animations.actor;
|
||||
},
|
||||
|
||||
_createIconTexture: function(size) {
|
||||
if (size == this.iconSize)
|
||||
return;
|
||||
|
||||
this.parent(size);
|
||||
}
|
||||
});
|
||||
|
||||
const WandaIconBin = new Lang.Class({
|
||||
Name: 'WandaIconBin',
|
||||
|
||||
_init: function(fish, label, params) {
|
||||
this.actor = new St.Bin({ reactive: true,
|
||||
track_hover: true });
|
||||
this.icon = new WandaIcon(fish, label, params);
|
||||
|
||||
this.actor.child = this.icon.actor;
|
||||
this.actor.label_actor = this.icon.label;
|
||||
},
|
||||
});
|
||||
|
||||
const FortuneDialog = new Lang.Class({
|
||||
Name: 'FortuneDialog',
|
||||
|
||||
_init: function(name, command) {
|
||||
let text;
|
||||
|
||||
try {
|
||||
let [res, stdout, stderr, status] = GLib.spawn_command_line_sync(command);
|
||||
text = String.fromCharCode.apply(null, stdout);
|
||||
} catch(e) {
|
||||
text = _("Sorry, no wisdom for you today:\n%s").format(e.message);
|
||||
}
|
||||
|
||||
this._title = new St.Label({ style_class: 'prompt-dialog-headline',
|
||||
text: _("%s the Oracle says").format(name) });
|
||||
this._label = new St.Label({ style_class: 'prompt-dialog-description',
|
||||
text: text });
|
||||
this._label.clutter_text.line_wrap = true;
|
||||
|
||||
this._box = new St.BoxLayout({ vertical: true,
|
||||
style_class: 'prompt-dialog' // this is just to force a reasonable width
|
||||
});
|
||||
this._box.add(this._title, { align: St.Align.MIDDLE });
|
||||
this._box.add(this._label, { expand: true });
|
||||
|
||||
this._button = new St.Button({ button_mask: St.ButtonMask.ONE,
|
||||
style_class: 'modal-dialog',
|
||||
reactive: true });
|
||||
this._button.connect('clicked', Lang.bind(this, this.destroy));
|
||||
this._button.child = this._box;
|
||||
|
||||
this._bin = new St.Bin({ x_align: St.Align.MIDDLE,
|
||||
y_align: St.Align.MIDDLE });
|
||||
this._bin.add_constraint(new Layout.MonitorConstraint({ primary: true }));
|
||||
this._bin.add_actor(this._button);
|
||||
|
||||
Main.layoutManager.addChrome(this._bin);
|
||||
|
||||
GLib.timeout_add_seconds(GLib.PRIORITY_DEFAULT, 10, Lang.bind(this, this.destroy));
|
||||
},
|
||||
|
||||
destroy: function() {
|
||||
this._bin.destroy();
|
||||
}
|
||||
});
|
||||
|
||||
function capitalize(str) {
|
||||
return str[0].toUpperCase() + str.substring(1, str.length);
|
||||
}
|
||||
|
||||
const WandaSearchProvider = new Lang.Class({
|
||||
Name: 'WandaSearchProvider',
|
||||
|
||||
_init: function() {
|
||||
this.id = 'wanda';
|
||||
},
|
||||
|
||||
getResultMetas: function(fish, callback) {
|
||||
callback([{ 'id': fish[0], // there may be many fish in the sea, but
|
||||
// only one which speaks the truth!
|
||||
'name': capitalize(fish[0]),
|
||||
'createIcon': function(iconSize) {
|
||||
return new St.Icon({ gicon: Gio.icon_new_for_string('face-smile'),
|
||||
icon_size: iconSize });
|
||||
}
|
||||
}]);
|
||||
},
|
||||
|
||||
getInitialResultSet: function(terms) {
|
||||
if (terms.join(' ') == MAGIC_FISH_KEY) {
|
||||
this.searchSystem.setResults(this, [ FISH_NAME ]);
|
||||
} else {
|
||||
this.searchSystem.setResults(this, []);
|
||||
}
|
||||
},
|
||||
|
||||
getSubsearchResultSet: function(previousResults, terms) {
|
||||
this.getInitialResultSet(terms);
|
||||
},
|
||||
|
||||
activateResult: function(fish) {
|
||||
if (this._dialog)
|
||||
this._dialog.destroy();
|
||||
this._dialog = new FortuneDialog(capitalize(fish), FISH_COMMAND);
|
||||
},
|
||||
|
||||
createResultObject: function (resultMeta, terms) {
|
||||
return new WandaIconBin(resultMeta.id, resultMeta.name);
|
||||
}
|
||||
});
|
@ -39,9 +39,6 @@ const WindowAttentionHandler = new Lang.Class({
|
||||
let [title, banner] = this._getTitleAndBanner(app, window);
|
||||
|
||||
let notification = new MessageTray.Notification(source, title, banner);
|
||||
notification.connect('clicked', function() {
|
||||
source.open();
|
||||
});
|
||||
notification.setForFeedback(true);
|
||||
|
||||
source.notify(notification);
|
||||
@ -82,7 +79,7 @@ const Source = new Lang.Class({
|
||||
return this._app.create_icon_texture(size);
|
||||
},
|
||||
|
||||
open: function() {
|
||||
open : function(notification) {
|
||||
Main.activateWindow(this._window);
|
||||
this.destroy();
|
||||
}
|
||||
|
@ -106,11 +106,11 @@ const DisplayChangeDialog = new Lang.Class({
|
||||
/* mutter already takes care of failing at timeout */
|
||||
this._timeoutId = 0;
|
||||
this.close();
|
||||
return GLib.SOURCE_REMOVE;
|
||||
return false;
|
||||
}
|
||||
|
||||
this._descriptionLabel.text = this._formatCountDown();
|
||||
return GLib.SOURCE_CONTINUE;
|
||||
return true;
|
||||
},
|
||||
|
||||
_onFailure: function() {
|
||||
@ -232,13 +232,12 @@ const WorkspaceTracker = new Lang.Class({
|
||||
|
||||
let windows = global.get_window_actors();
|
||||
for (i = 0; i < windows.length; i++) {
|
||||
let actor = windows[i];
|
||||
let win = actor.get_meta_window();
|
||||
let win = windows[i];
|
||||
|
||||
if (win.is_on_all_workspaces())
|
||||
if (win.get_meta_window().is_on_all_workspaces())
|
||||
continue;
|
||||
|
||||
let workspaceIndex = win.get_workspace().index();
|
||||
let workspaceIndex = win.get_workspace();
|
||||
emptyWorkspaces[workspaceIndex] = false;
|
||||
}
|
||||
|
||||
@ -279,7 +278,7 @@ const WorkspaceTracker = new Lang.Class({
|
||||
workspace._keepAliveId = Mainloop.timeout_add(duration, Lang.bind(this, function() {
|
||||
workspace._keepAliveId = 0;
|
||||
this._queueCheckWorkspaces();
|
||||
return GLib.SOURCE_REMOVE;
|
||||
return false;
|
||||
}));
|
||||
},
|
||||
|
||||
@ -291,7 +290,7 @@ const WorkspaceTracker = new Lang.Class({
|
||||
workspace._lastRemovedWindow = null;
|
||||
this._queueCheckWorkspaces();
|
||||
}
|
||||
return GLib.SOURCE_REMOVE;
|
||||
return false;
|
||||
}));
|
||||
},
|
||||
|
||||
@ -976,29 +975,25 @@ const WindowManager = new Lang.Class({
|
||||
wgroup.add_actor(switchData.movingWindowBin);
|
||||
|
||||
for (let i = 0; i < windows.length; i++) {
|
||||
let actor = windows[i];
|
||||
let window = actor.get_meta_window();
|
||||
let window = windows[i];
|
||||
|
||||
if (!window.showing_on_its_workspace())
|
||||
if (!window.meta_window.showing_on_its_workspace())
|
||||
continue;
|
||||
|
||||
if (window.is_on_all_workspaces())
|
||||
continue;
|
||||
|
||||
let record = { window: actor,
|
||||
parent: actor.get_parent() };
|
||||
|
||||
if (this._movingWindow && window == this._movingWindow) {
|
||||
switchData.movingWindow = record;
|
||||
if (this._movingWindow && window.meta_window == this._movingWindow) {
|
||||
switchData.movingWindow = { window: window,
|
||||
parent: window.get_parent() };
|
||||
switchData.windows.push(switchData.movingWindow);
|
||||
actor.reparent(switchData.movingWindowBin);
|
||||
} else if (window.get_workspace().index() == from) {
|
||||
switchData.windows.push(record);
|
||||
actor.reparent(switchData.outGroup);
|
||||
} else if (window.get_workspace().index() == to) {
|
||||
switchData.windows.push(record);
|
||||
actor.reparent(switchData.inGroup);
|
||||
actor.show();
|
||||
window.reparent(switchData.movingWindowBin);
|
||||
} else if (window.get_workspace() == from) {
|
||||
switchData.windows.push({ window: window,
|
||||
parent: window.get_parent() });
|
||||
window.reparent(switchData.outGroup);
|
||||
} else if (window.get_workspace() == to) {
|
||||
switchData.windows.push({ window: window,
|
||||
parent: window.get_parent() });
|
||||
window.reparent(switchData.inGroup);
|
||||
window.show();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,6 @@
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
|
||||
const Clutter = imports.gi.Clutter;
|
||||
const GLib = imports.gi.GLib;
|
||||
const Lang = imports.lang;
|
||||
const Mainloop = imports.mainloop;
|
||||
const Meta = imports.gi.Meta;
|
||||
@ -11,14 +10,19 @@ const St = imports.gi.St;
|
||||
const Signals = imports.signals;
|
||||
|
||||
const DND = imports.ui.dnd;
|
||||
const Lightbox = imports.ui.lightbox;
|
||||
const Main = imports.ui.main;
|
||||
const Overview = imports.ui.overview;
|
||||
const Panel = imports.ui.panel;
|
||||
const Tweener = imports.ui.tweener;
|
||||
|
||||
const FOCUS_ANIMATION_TIME = 0.15;
|
||||
|
||||
const WINDOW_DND_SIZE = 256;
|
||||
|
||||
const WINDOW_CLONE_MAXIMUM_SCALE = 0.7;
|
||||
|
||||
const LIGHTBOX_FADE_TIME = 0.1;
|
||||
const CLOSE_BUTTON_FADE_TIME = 0.1;
|
||||
|
||||
const DRAGGING_WINDOW_OPACITY = 100;
|
||||
@ -64,12 +68,11 @@ const WindowClone = new Lang.Class({
|
||||
// the invisible border; this is inconvenient; rather than trying
|
||||
// to compensate all over the place we insert a ClutterActor into
|
||||
// the hierarchy that is sized to only the visible portion.
|
||||
this.actor = new St.Widget({ reactive: true,
|
||||
can_focus: true,
|
||||
x: this.origX,
|
||||
y: this.origY,
|
||||
width: outerRect.width,
|
||||
height: outerRect.height });
|
||||
this.actor = new Clutter.Actor({ reactive: true,
|
||||
x: this.origX,
|
||||
y: this.origY,
|
||||
width: outerRect.width,
|
||||
height: outerRect.height });
|
||||
|
||||
this.actor.add_child(this._windowClone);
|
||||
|
||||
@ -87,10 +90,10 @@ const WindowClone = new Lang.Class({
|
||||
let clickAction = new Clutter.ClickAction();
|
||||
clickAction.connect('clicked', Lang.bind(this, this._onClicked));
|
||||
clickAction.connect('long-press', Lang.bind(this, this._onLongPress));
|
||||
|
||||
this.actor.add_action(clickAction);
|
||||
|
||||
this.actor.connect('destroy', Lang.bind(this, this._onDestroy));
|
||||
this.actor.connect('key-press-event', Lang.bind(this, this._onKeyPress));
|
||||
this.actor.connect('enter-event', Lang.bind(this, this._onEnter));
|
||||
|
||||
this._draggable = DND.makeDraggable(this.actor,
|
||||
{ restoreOnSuccess: true,
|
||||
@ -199,30 +202,11 @@ const WindowClone = new Lang.Class({
|
||||
this.disconnectAll();
|
||||
},
|
||||
|
||||
_activate: function() {
|
||||
_onClicked: function(action, actor) {
|
||||
this._selected = true;
|
||||
this.emit('selected', global.get_current_time());
|
||||
},
|
||||
|
||||
_onKeyPress: function(actor, event) {
|
||||
let symbol = event.get_key_symbol();
|
||||
let isEnter = (symbol == Clutter.KEY_Return || symbol == Clutter.KEY_KP_Enter);
|
||||
if (isEnter) {
|
||||
this._activate();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
},
|
||||
|
||||
_onEnter: function() {
|
||||
this.actor.grab_key_focus();
|
||||
},
|
||||
|
||||
_onClicked: function(action, actor) {
|
||||
this._activate();
|
||||
},
|
||||
|
||||
_onLongPress: function(action, actor, state) {
|
||||
// Take advantage of the Clutter policy to consider
|
||||
// a long-press canceled when the pointer movement
|
||||
@ -322,10 +306,6 @@ const WindowOverlay = new Lang.Class({
|
||||
Lang.bind(this, this._onEnter));
|
||||
windowClone.actor.connect('leave-event',
|
||||
Lang.bind(this, this._onLeave));
|
||||
windowClone.actor.connect('key-focus-in',
|
||||
Lang.bind(this, this._onEnter));
|
||||
windowClone.actor.connect('key-focus-out',
|
||||
Lang.bind(this, this._onLeave));
|
||||
|
||||
this._windowAddedId = 0;
|
||||
|
||||
@ -363,6 +343,19 @@ const WindowOverlay = new Lang.Class({
|
||||
this._animateVisible();
|
||||
},
|
||||
|
||||
fadeIn: function() {
|
||||
if (!this._hidden)
|
||||
return;
|
||||
|
||||
this.show();
|
||||
this.title.opacity = 0;
|
||||
this._parentActor.raise_top();
|
||||
Tweener.addTween(this.title,
|
||||
{ opacity: 255,
|
||||
time: CLOSE_BUTTON_FADE_TIME,
|
||||
transition: 'easeOutQuad' });
|
||||
},
|
||||
|
||||
chromeHeights: function () {
|
||||
return [Math.max(this.borderSize, this.closeButton.height - this.closeButton._overlap),
|
||||
this.title.height + this.title._spacing];
|
||||
@ -379,6 +372,7 @@ const WindowOverlay = new Lang.Class({
|
||||
let border = this.border;
|
||||
|
||||
Tweener.removeTweens(button);
|
||||
Tweener.removeTweens(title);
|
||||
Tweener.removeTweens(border);
|
||||
|
||||
let [cloneX, cloneY, cloneWidth, cloneHeight] = this._windowClone.slot;
|
||||
@ -473,7 +467,7 @@ const WindowOverlay = new Lang.Class({
|
||||
Mainloop.idle_add(Lang.bind(this,
|
||||
function() {
|
||||
this._windowClone.emit('selected');
|
||||
return GLib.SOURCE_REMOVE;
|
||||
return false;
|
||||
}));
|
||||
}
|
||||
},
|
||||
@ -537,17 +531,15 @@ const WindowOverlay = new Lang.Class({
|
||||
// as the close button will be shown as needed when the overlays
|
||||
// are shown again
|
||||
if (this._hidden)
|
||||
return Clutter.EVENT_PROPAGATE;
|
||||
return;
|
||||
|
||||
this._animateVisible();
|
||||
this.emit('show-close-button');
|
||||
return Clutter.EVENT_PROPAGATE;
|
||||
},
|
||||
|
||||
_onLeave: function() {
|
||||
if (this._idleToggleCloseId == 0)
|
||||
this._idleToggleCloseId = Mainloop.timeout_add(750, Lang.bind(this, this._idleToggleCloseButton));
|
||||
return Clutter.EVENT_PROPAGATE;
|
||||
},
|
||||
|
||||
_idleToggleCloseButton: function() {
|
||||
@ -557,7 +549,7 @@ const WindowOverlay = new Lang.Class({
|
||||
!this.closeButton.has_pointer)
|
||||
this._animateInvisible();
|
||||
|
||||
return GLib.SOURCE_REMOVE;
|
||||
return false;
|
||||
},
|
||||
|
||||
hideCloseButton: function() {
|
||||
@ -914,19 +906,6 @@ function padArea(area, padding) {
|
||||
};
|
||||
}
|
||||
|
||||
function rectEqual(one, two) {
|
||||
if (one == two)
|
||||
return true;
|
||||
|
||||
if (!one || !two)
|
||||
return false;
|
||||
|
||||
return (one.x == two.x &&
|
||||
one.y == two.y &&
|
||||
one.width == two.width &&
|
||||
one.height == two.height);
|
||||
}
|
||||
|
||||
/**
|
||||
* @metaWorkspace: a #Meta.Workspace, or null
|
||||
*/
|
||||
@ -1002,17 +981,11 @@ const Workspace = new Lang.Class({
|
||||
},
|
||||
|
||||
setFullGeometry: function(geom) {
|
||||
if (rectEqual(this._fullGeometry, geom))
|
||||
return;
|
||||
|
||||
this._fullGeometry = geom;
|
||||
this._recalculateWindowPositions(WindowPositionFlags.NONE);
|
||||
},
|
||||
|
||||
setActualGeometry: function(geom) {
|
||||
if (rectEqual(this._actualGeometry, geom))
|
||||
return;
|
||||
|
||||
this._actualGeometry = geom;
|
||||
|
||||
if (this._actualGeometryLater)
|
||||
@ -1169,7 +1142,7 @@ const Workspace = new Lang.Class({
|
||||
clone.actor.set_scale(scale, scale);
|
||||
clone.actor.set_opacity(255);
|
||||
clone.overlay.relayout(false);
|
||||
this._showWindowOverlay(clone, overlay);
|
||||
this._showWindowOverlay(clone, overlay, isOnCurrentWorkspace);
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -1199,19 +1172,23 @@ const Workspace = new Lang.Class({
|
||||
time: Overview.ANIMATION_TIME,
|
||||
transition: 'easeOutQuad',
|
||||
onComplete: Lang.bind(this, function() {
|
||||
this._showWindowOverlay(clone, overlay);
|
||||
this._showWindowOverlay(clone, overlay, true);
|
||||
})
|
||||
});
|
||||
|
||||
clone.overlay.relayout(true);
|
||||
},
|
||||
|
||||
_showWindowOverlay: function(clone, overlay) {
|
||||
_showWindowOverlay: function(clone, overlay, fade) {
|
||||
if (clone.inDrag)
|
||||
return;
|
||||
|
||||
if (overlay && overlay._hidden)
|
||||
if (overlay) {
|
||||
if (fade)
|
||||
overlay.fadeIn();
|
||||
else
|
||||
overlay.show();
|
||||
}
|
||||
},
|
||||
|
||||
_delayedWindowRepositioning: function() {
|
||||
@ -1225,18 +1202,17 @@ const Workspace = new Lang.Class({
|
||||
// store current cursor position
|
||||
this._cursorX = x;
|
||||
this._cursorY = y;
|
||||
return GLib.SOURCE_CONTINUE;
|
||||
return true;
|
||||
}
|
||||
|
||||
let actorUnderPointer = global.stage.get_actor_at_pos(Clutter.PickMode.REACTIVE, x, y);
|
||||
for (let i = 0; i < this._windows.length; i++) {
|
||||
if (this._windows[i].actor == actorUnderPointer)
|
||||
return GLib.SOURCE_CONTINUE;
|
||||
return true;
|
||||
}
|
||||
|
||||
this._recalculateWindowPositions(WindowPositionFlags.ANIMATE);
|
||||
this._repositionWindowsId = 0;
|
||||
return GLib.SOURCE_REMOVE;
|
||||
return false;
|
||||
},
|
||||
|
||||
_doRemoveWindow : function(metaWin) {
|
||||
@ -1311,7 +1287,7 @@ const Workspace = new Lang.Class({
|
||||
metaWin.get_compositor_private() &&
|
||||
metaWin.get_workspace() == this.metaWorkspace)
|
||||
this._doAddWindow(metaWin);
|
||||
return GLib.SOURCE_REMOVE;
|
||||
return false;
|
||||
}));
|
||||
return;
|
||||
}
|
||||
@ -1491,17 +1467,17 @@ const Workspace = new Lang.Class({
|
||||
clone.connect('selected',
|
||||
Lang.bind(this, this._onCloneSelected));
|
||||
clone.connect('drag-begin',
|
||||
Lang.bind(this, function() {
|
||||
Main.overview.beginWindowDrag(clone);
|
||||
Lang.bind(this, function(clone) {
|
||||
Main.overview.beginWindowDrag();
|
||||
overlay.hide();
|
||||
}));
|
||||
clone.connect('drag-cancelled',
|
||||
Lang.bind(this, function() {
|
||||
Main.overview.cancelledWindowDrag(clone);
|
||||
Lang.bind(this, function(clone) {
|
||||
Main.overview.cancelledWindowDrag();
|
||||
}));
|
||||
clone.connect('drag-end',
|
||||
Lang.bind(this, function() {
|
||||
Main.overview.endWindowDrag(clone);
|
||||
Lang.bind(this, function(clone) {
|
||||
Main.overview.endWindowDrag();
|
||||
overlay.show();
|
||||
}));
|
||||
clone.connect('size-changed',
|
||||
@ -1663,7 +1639,9 @@ const Workspace = new Lang.Class({
|
||||
metaWindow.move_to_monitor(this.monitorIndex);
|
||||
|
||||
let index = this.metaWorkspace ? this.metaWorkspace.index() : global.screen.get_active_workspace_index();
|
||||
metaWindow.change_workspace_by_index(index, false);
|
||||
metaWindow.change_workspace_by_index(index,
|
||||
false, // don't create workspace
|
||||
time);
|
||||
return true;
|
||||
} else if (source.shellWorkspaceLaunch) {
|
||||
source.shellWorkspaceLaunch({ workspace: this.metaWorkspace ? this.metaWorkspace.index() : -1,
|
||||
|
@ -1,7 +1,6 @@
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
|
||||
const Clutter = imports.gi.Clutter;
|
||||
const GLib = imports.gi.GLib;
|
||||
const Lang = imports.lang;
|
||||
const Mainloop = imports.mainloop;
|
||||
const Meta = imports.gi.Meta;
|
||||
@ -157,7 +156,6 @@ const WorkspaceSwitcherPopup = new Lang.Class({
|
||||
onComplete: function() { this.destroy(); },
|
||||
onCompleteScope: this
|
||||
});
|
||||
return GLib.SOURCE_REMOVE;
|
||||
},
|
||||
|
||||
destroy: function() {
|
||||
|
@ -2,7 +2,6 @@
|
||||
|
||||
const Clutter = imports.gi.Clutter;
|
||||
const Gio = imports.gi.Gio;
|
||||
const GLib = imports.gi.GLib;
|
||||
const Lang = imports.lang;
|
||||
const Mainloop = imports.mainloop;
|
||||
const Meta = imports.gi.Meta;
|
||||
@ -131,7 +130,7 @@ const WindowClone = new Lang.Class({
|
||||
_onButtonRelease : function (actor, event) {
|
||||
this.emit('selected', event.get_time());
|
||||
|
||||
return Clutter.EVENT_STOP;
|
||||
return true;
|
||||
},
|
||||
|
||||
_onDragBegin : function (draggable, time) {
|
||||
@ -326,7 +325,7 @@ const WorkspaceThumbnail = new Lang.Class({
|
||||
metaWin.get_compositor_private() &&
|
||||
metaWin.get_workspace() == this.metaWorkspace)
|
||||
this._doAddWindow(metaWin);
|
||||
return GLib.SOURCE_REMOVE;
|
||||
return false;
|
||||
}));
|
||||
return;
|
||||
}
|
||||
@ -439,16 +438,16 @@ const WorkspaceThumbnail = new Lang.Class({
|
||||
this.activate(time);
|
||||
}));
|
||||
clone.connect('drag-begin',
|
||||
Lang.bind(this, function() {
|
||||
Main.overview.beginWindowDrag(clone);
|
||||
Lang.bind(this, function(clone) {
|
||||
Main.overview.beginWindowDrag();
|
||||
}));
|
||||
clone.connect('drag-cancelled',
|
||||
Lang.bind(this, function() {
|
||||
Main.overview.cancelledWindowDrag(clone);
|
||||
Lang.bind(this, function(clone) {
|
||||
Main.overview.cancelledWindowDrag();
|
||||
}));
|
||||
clone.connect('drag-end',
|
||||
Lang.bind(this, function() {
|
||||
Main.overview.endWindowDrag(clone);
|
||||
Lang.bind(this, function(clone) {
|
||||
Main.overview.endWindowDrag();
|
||||
}));
|
||||
this._contents.add_actor(clone.actor);
|
||||
|
||||
@ -508,7 +507,9 @@ const WorkspaceThumbnail = new Lang.Class({
|
||||
if (metaWindow.get_monitor() != this.monitorIndex)
|
||||
metaWindow.move_to_monitor(this.monitorIndex);
|
||||
|
||||
metaWindow.change_workspace_by_index(this.metaWorkspace.index(), false);
|
||||
metaWindow.change_workspace_by_index(this.metaWorkspace.index(),
|
||||
false, // don't create workspace
|
||||
time);
|
||||
return true;
|
||||
} else if (source.shellWorkspaceLaunch) {
|
||||
source.shellWorkspaceLaunch({ workspace: this.metaWorkspace ? this.metaWorkspace.index() : -1,
|
||||
@ -535,6 +536,20 @@ const ThumbnailsBox = new Lang.Class({
|
||||
this.actor.connect('allocate', Lang.bind(this, this._allocate));
|
||||
this.actor._delegate = this;
|
||||
|
||||
// When we animate the scale, we don't animate the requested size of the thumbnails, rather
|
||||
// we ask for our final size and then animate within that size. This slightly simplifies the
|
||||
// interaction with the main workspace windows (instead of constantly reallocating them
|
||||
// to a new size, they get a new size once, then use the standard window animation code
|
||||
// allocate the windows to their new positions), however it causes problems for drawing
|
||||
// the background and border wrapped around the thumbnail as we animate - we can't just pack
|
||||
// the container into a box and set style properties on the box since that box would wrap
|
||||
// around the final size not the animating size. So instead we fake the background with
|
||||
// an actor underneath the content and adjust the allocation of our children to leave space
|
||||
// for the border and padding of the background actor.
|
||||
this._background = new St.Bin({ style_class: 'workspace-thumbnails-background' });
|
||||
|
||||
this.actor.add_actor(this._background);
|
||||
|
||||
let indicator = new St.Bin({ style_class: 'workspace-thumbnail-indicator' });
|
||||
|
||||
// We don't want the indicator to affect drag-and-drop
|
||||
@ -562,7 +577,7 @@ const ThumbnailsBox = new Lang.Class({
|
||||
|
||||
this._thumbnails = [];
|
||||
|
||||
this.actor.connect('button-press-event', function() { return Clutter.EVENT_STOP; });
|
||||
this.actor.connect('button-press-event', function() { return true; });
|
||||
this.actor.connect('button-release-event', Lang.bind(this, this._onButtonRelease));
|
||||
|
||||
Main.overview.connect('showing',
|
||||
@ -607,7 +622,7 @@ const ThumbnailsBox = new Lang.Class({
|
||||
}
|
||||
}
|
||||
|
||||
return Clutter.EVENT_STOP;
|
||||
return true;
|
||||
},
|
||||
|
||||
_onDragBegin: function() {
|
||||
@ -738,12 +753,14 @@ const ThumbnailsBox = new Lang.Class({
|
||||
|
||||
// ... move them down one.
|
||||
windows.forEach(function(win) {
|
||||
win.meta_window.change_workspace_by_index(win.get_workspace() + 1, true);
|
||||
win.meta_window.change_workspace_by_index(win.get_workspace() + 1,
|
||||
true, time);
|
||||
});
|
||||
|
||||
if (isWindow)
|
||||
// ... and bam, a workspace, good as new.
|
||||
source.metaWindow.change_workspace_by_index(newWorkspaceIndex, true);
|
||||
source.metaWindow.change_workspace_by_index(newWorkspaceIndex,
|
||||
true, time);
|
||||
else if (source.shellWorkspaceLaunch) {
|
||||
source.shellWorkspaceLaunch({ workspace: newWorkspaceIndex,
|
||||
timestamp: time });
|
||||
@ -1025,6 +1042,9 @@ const ThumbnailsBox = new Lang.Class({
|
||||
},
|
||||
|
||||
_getPreferredHeight: function(actor, forWidth, alloc) {
|
||||
// See comment about this._background in _init()
|
||||
let themeNode = this._background.get_theme_node();
|
||||
|
||||
// Note that for getPreferredWidth/Height we cheat a bit and skip propagating
|
||||
// the size request to our children because we know how big they are and know
|
||||
// that the actors aren't depending on the virtual functions being called.
|
||||
@ -1032,21 +1052,24 @@ const ThumbnailsBox = new Lang.Class({
|
||||
if (this._thumbnails.length == 0)
|
||||
return;
|
||||
|
||||
let themeNode = this.actor.get_theme_node();
|
||||
|
||||
let spacing = themeNode.get_length('spacing');
|
||||
let spacing = this.actor.get_theme_node().get_length('spacing');
|
||||
let nWorkspaces = global.screen.n_workspaces;
|
||||
let totalSpacing = (nWorkspaces - 1) * spacing;
|
||||
|
||||
alloc.min_size = totalSpacing;
|
||||
alloc.natural_size = totalSpacing + nWorkspaces * this._porthole.height * MAX_THUMBNAIL_SCALE;
|
||||
[alloc.min_size, alloc.natural_size] =
|
||||
themeNode.adjust_preferred_height(totalSpacing,
|
||||
totalSpacing + nWorkspaces * this._porthole.height * MAX_THUMBNAIL_SCALE);
|
||||
},
|
||||
|
||||
_getPreferredWidth: function(actor, forHeight, alloc) {
|
||||
// See comment about this._background in _init()
|
||||
let themeNode = this._background.get_theme_node();
|
||||
|
||||
if (this._thumbnails.length == 0)
|
||||
return;
|
||||
|
||||
let themeNode = this.actor.get_theme_node();
|
||||
// We don't animate our preferred width, which is always reported according
|
||||
// to the actual number of current workspaces, we just animate within that
|
||||
|
||||
let spacing = this.actor.get_theme_node().get_length('spacing');
|
||||
let nWorkspaces = global.screen.n_workspaces;
|
||||
@ -1058,26 +1081,28 @@ const ThumbnailsBox = new Lang.Class({
|
||||
scale = Math.min(scale, MAX_THUMBNAIL_SCALE);
|
||||
|
||||
let width = Math.round(this._porthole.width * scale);
|
||||
alloc.min_size = width;
|
||||
alloc.natural_size = width;
|
||||
[alloc.min_size, alloc.natural_size] =
|
||||
themeNode.adjust_preferred_width(width, width);
|
||||
},
|
||||
|
||||
_allocate: function(actor, box, flags) {
|
||||
let rtl = (Clutter.get_default_text_direction () == Clutter.TextDirection.RTL);
|
||||
|
||||
// See comment about this._background in _init()
|
||||
let themeNode = this._background.get_theme_node();
|
||||
let contentBox = themeNode.get_content_box(box);
|
||||
|
||||
if (this._thumbnails.length == 0) // not visible
|
||||
return;
|
||||
|
||||
let themeNode = this.actor.get_theme_node();
|
||||
|
||||
let portholeWidth = this._porthole.width;
|
||||
let portholeHeight = this._porthole.height;
|
||||
let spacing = themeNode.get_length('spacing');
|
||||
let spacing = this.actor.get_theme_node().get_length('spacing');
|
||||
|
||||
// Compute the scale we'll need once everything is updated
|
||||
let nWorkspaces = global.screen.n_workspaces;
|
||||
let totalSpacing = (nWorkspaces - 1) * spacing;
|
||||
let avail = (box.y2 - box.y1) - totalSpacing;
|
||||
let avail = (contentBox.y2 - contentBox.y1) - totalSpacing;
|
||||
|
||||
let newScale = (avail / nWorkspaces) / portholeHeight;
|
||||
newScale = Math.min(newScale, MAX_THUMBNAIL_SCALE);
|
||||
@ -1106,6 +1131,21 @@ const ThumbnailsBox = new Lang.Class({
|
||||
else
|
||||
slideOffset = thumbnailWidth + themeNode.get_padding(St.Side.RIGHT);
|
||||
|
||||
let childBox = new Clutter.ActorBox();
|
||||
|
||||
// The background is horizontally restricted to correspond to the current thumbnail size
|
||||
// but otherwise covers the entire allocation
|
||||
if (rtl) {
|
||||
childBox.x1 = box.x1;
|
||||
childBox.x2 = box.x2 - ((contentBox.x2 - contentBox.x1) - thumbnailWidth);
|
||||
} else {
|
||||
childBox.x1 = box.x1 + ((contentBox.x2 - contentBox.x1) - thumbnailWidth);
|
||||
childBox.x2 = box.x2;
|
||||
}
|
||||
childBox.y1 = box.y1;
|
||||
childBox.y2 = box.y2;
|
||||
this._background.allocate(childBox, flags);
|
||||
|
||||
let indicatorY1 = this._indicatorY;
|
||||
let indicatorY2;
|
||||
// when not animating, the workspace position overrides this._indicatorY
|
||||
@ -1117,7 +1157,7 @@ const ThumbnailsBox = new Lang.Class({
|
||||
let indicatorLeftFullBorder = indicatorThemeNode.get_padding(St.Side.LEFT) + indicatorThemeNode.get_border_width(St.Side.LEFT);
|
||||
let indicatorRightFullBorder = indicatorThemeNode.get_padding(St.Side.RIGHT) + indicatorThemeNode.get_border_width(St.Side.RIGHT);
|
||||
|
||||
let y = box.y1;
|
||||
let y = contentBox.y1;
|
||||
|
||||
if (this._dropPlaceholderPos == -1) {
|
||||
Meta.later_add(Meta.LaterType.BEFORE_REDRAW, Lang.bind(this, function() {
|
||||
@ -1125,8 +1165,6 @@ const ThumbnailsBox = new Lang.Class({
|
||||
}));
|
||||
}
|
||||
|
||||
let childBox = new Clutter.ActorBox();
|
||||
|
||||
for (let i = 0; i < this._thumbnails.length; i++) {
|
||||
let thumbnail = this._thumbnails[i];
|
||||
|
||||
@ -1135,10 +1173,10 @@ const ThumbnailsBox = new Lang.Class({
|
||||
|
||||
let x1, x2;
|
||||
if (rtl) {
|
||||
x1 = box.x1 + slideOffset * thumbnail.slidePosition;
|
||||
x1 = contentBox.x1 + slideOffset * thumbnail.slidePosition;
|
||||
x2 = x1 + thumbnailWidth;
|
||||
} else {
|
||||
x1 = box.x2 - thumbnailWidth + slideOffset * thumbnail.slidePosition;
|
||||
x1 = contentBox.x2 - thumbnailWidth + slideOffset * thumbnail.slidePosition;
|
||||
x2 = x1 + thumbnailWidth;
|
||||
}
|
||||
|
||||
@ -1185,11 +1223,11 @@ const ThumbnailsBox = new Lang.Class({
|
||||
}
|
||||
|
||||
if (rtl) {
|
||||
childBox.x1 = box.x1;
|
||||
childBox.x2 = box.x1 + thumbnailWidth;
|
||||
childBox.x1 = contentBox.x1;
|
||||
childBox.x2 = contentBox.x1 + thumbnailWidth;
|
||||
} else {
|
||||
childBox.x1 = box.x2 - thumbnailWidth;
|
||||
childBox.x2 = box.x2;
|
||||
childBox.x1 = contentBox.x2 - thumbnailWidth;
|
||||
childBox.x2 = contentBox.x2;
|
||||
}
|
||||
childBox.x1 -= indicatorLeftFullBorder;
|
||||
childBox.x2 += indicatorRightFullBorder;
|
||||
|
@ -23,93 +23,75 @@ const MAX_WORKSPACES = 16;
|
||||
|
||||
const OVERRIDE_SCHEMA = 'org.gnome.shell.overrides';
|
||||
|
||||
const WorkspacesViewBase = new Lang.Class({
|
||||
Name: 'WorkspacesViewBase',
|
||||
function rectEqual(one, two) {
|
||||
if (one == two)
|
||||
return true;
|
||||
|
||||
_init: function(monitorIndex) {
|
||||
if (!one || !two)
|
||||
return false;
|
||||
|
||||
return (one.x == two.x &&
|
||||
one.y == two.y &&
|
||||
one.width == two.width &&
|
||||
one.height == two.height);
|
||||
}
|
||||
|
||||
const WorkspacesView = new Lang.Class({
|
||||
Name: 'WorkspacesView',
|
||||
|
||||
_init: function(workspaces) {
|
||||
this.actor = new St.Widget({ style_class: 'workspaces-view',
|
||||
reactive: true });
|
||||
this.actor.connect('destroy', Lang.bind(this, this._onDestroy));
|
||||
global.focus_manager.add_group(this.actor);
|
||||
|
||||
// The actor itself isn't a drop target, so we don't want to pick on its area
|
||||
this.actor.set_size(0, 0);
|
||||
|
||||
this._monitorIndex = monitorIndex;
|
||||
this.actor.connect('destroy', Lang.bind(this, this._onDestroy));
|
||||
|
||||
this.actor.connect('style-changed', Lang.bind(this,
|
||||
function() {
|
||||
let node = this.actor.get_theme_node();
|
||||
this._spacing = node.get_length('spacing');
|
||||
this._updateWorkspaceActors(false);
|
||||
}));
|
||||
|
||||
this._fullGeometry = null;
|
||||
this._actualGeometry = null;
|
||||
|
||||
this._inDrag = false;
|
||||
this._windowDragBeginId = Main.overview.connect('window-drag-begin', Lang.bind(this, this._dragBegin));
|
||||
this._windowDragEndId = Main.overview.connect('window-drag-end', Lang.bind(this, this._dragEnd));
|
||||
},
|
||||
|
||||
_onDestroy: function() {
|
||||
this._dragEnd();
|
||||
|
||||
if (this._windowDragBeginId > 0) {
|
||||
Main.overview.disconnect(this._windowDragBeginId);
|
||||
this._windowDragBeginId = 0;
|
||||
}
|
||||
if (this._windowDragEndId > 0) {
|
||||
Main.overview.disconnect(this._windowDragEndId);
|
||||
this._windowDragEndId = 0;
|
||||
}
|
||||
},
|
||||
|
||||
_dragBegin: function(overview, clone) {
|
||||
this._inDrag = true;
|
||||
this._setReservedSlot(clone);
|
||||
},
|
||||
|
||||
_dragEnd: function() {
|
||||
this._inDrag = false;
|
||||
this._setReservedSlot(null);
|
||||
},
|
||||
|
||||
destroy: function() {
|
||||
this.actor.destroy();
|
||||
},
|
||||
|
||||
setFullGeometry: function(geom) {
|
||||
this._fullGeometry = geom;
|
||||
this._syncGeometry();
|
||||
},
|
||||
|
||||
setActualGeometry: function(geom) {
|
||||
this._actualGeometry = geom;
|
||||
this._syncGeometry();
|
||||
},
|
||||
});
|
||||
|
||||
const WorkspacesView = new Lang.Class({
|
||||
Name: 'WorkspacesView',
|
||||
Extends: WorkspacesViewBase,
|
||||
|
||||
_init: function(monitorIndex) {
|
||||
this.parent(monitorIndex);
|
||||
|
||||
this._spacing = 0;
|
||||
this._animating = false; // tweening
|
||||
this._scrolling = false; // swipe-scrolling
|
||||
this._animatingScroll = false; // programatically updating the adjustment
|
||||
this._inDrag = false; // dragging a window
|
||||
|
||||
this._settings = new Gio.Settings({ schema: OVERRIDE_SCHEMA });
|
||||
this._updateExtraWorkspacesId =
|
||||
this._settings.connect('changed::workspaces-only-on-primary',
|
||||
Lang.bind(this, this._updateExtraWorkspaces));
|
||||
|
||||
let activeWorkspaceIndex = global.screen.get_active_workspace_index();
|
||||
this.scrollAdjustment = new St.Adjustment({ value: activeWorkspaceIndex,
|
||||
lower: 0,
|
||||
page_increment: 1,
|
||||
page_size: 1,
|
||||
step_increment: 0,
|
||||
upper: 0 });
|
||||
this.scrollAdjustment.connect('notify::value',
|
||||
Lang.bind(this, this._onScroll));
|
||||
this._workspaces = workspaces;
|
||||
|
||||
this._workspaces = [];
|
||||
this._updateWorkspaces();
|
||||
this._updateWorkspacesId = global.screen.connect('notify::n-workspaces', Lang.bind(this, this._updateWorkspaces));
|
||||
// Add workspace actors
|
||||
for (let w = 0; w < global.screen.n_workspaces; w++)
|
||||
this.actor.add_actor(this._workspaces[w].actor);
|
||||
this._workspaces[activeWorkspaceIndex].actor.raise_top();
|
||||
|
||||
this._extraWorkspaces = [];
|
||||
this._updateExtraWorkspaces();
|
||||
|
||||
// Position/scale the desktop windows and their children after the
|
||||
// workspaces have been created. This cannot be done first because
|
||||
// window movement depends on the Workspaces object being accessible
|
||||
// as an Overview member.
|
||||
this._overviewShowingId =
|
||||
Main.overview.connect('showing',
|
||||
Lang.bind(this, function() {
|
||||
for (let w = 0; w < this._workspaces.length; w++)
|
||||
this._workspaces[w].zoomToOverview();
|
||||
for (let w = 0; w < this._extraWorkspaces.length; w++)
|
||||
this._extraWorkspaces[w].zoomToOverview();
|
||||
}));
|
||||
this._overviewShownId =
|
||||
Main.overview.connect('shown',
|
||||
Lang.bind(this, function() {
|
||||
@ -117,21 +99,72 @@ const WorkspacesView = new Lang.Class({
|
||||
this._fullGeometry.width, this._fullGeometry.height);
|
||||
}));
|
||||
|
||||
this.scrollAdjustment = new St.Adjustment({ value: activeWorkspaceIndex,
|
||||
lower: 0,
|
||||
page_increment: 1,
|
||||
page_size: 1,
|
||||
step_increment: 0,
|
||||
upper: this._workspaces.length });
|
||||
this.scrollAdjustment.connect('notify::value',
|
||||
Lang.bind(this, this._onScroll));
|
||||
|
||||
this._switchWorkspaceNotifyId =
|
||||
global.window_manager.connect('switch-workspace',
|
||||
Lang.bind(this, this._activeWorkspaceChanged));
|
||||
|
||||
this._itemDragBeginId = Main.overview.connect('item-drag-begin',
|
||||
Lang.bind(this, this._dragBegin));
|
||||
this._itemDragEndId = Main.overview.connect('item-drag-end',
|
||||
Lang.bind(this, this._dragEnd));
|
||||
this._windowDragBeginId = Main.overview.connect('window-drag-begin',
|
||||
Lang.bind(this, this._dragBegin));
|
||||
this._windowDragEndId = Main.overview.connect('window-drag-end',
|
||||
Lang.bind(this, this._dragEnd));
|
||||
},
|
||||
|
||||
_setReservedSlot: function(clone) {
|
||||
for (let i = 0; i < this._workspaces.length; i++)
|
||||
this._workspaces[i].setReservedSlot(clone);
|
||||
_updateExtraWorkspaces: function() {
|
||||
this._destroyExtraWorkspaces();
|
||||
|
||||
if (!this._settings.get_boolean('workspaces-only-on-primary'))
|
||||
return;
|
||||
|
||||
let monitors = Main.layoutManager.monitors;
|
||||
for (let i = 0; i < monitors.length; i++) {
|
||||
if (i == Main.layoutManager.primaryIndex)
|
||||
continue;
|
||||
|
||||
let ws = new Workspace.Workspace(null, i);
|
||||
ws.setFullGeometry(monitors[i]);
|
||||
ws.setActualGeometry(monitors[i]);
|
||||
Main.layoutManager.overviewGroup.add_actor(ws.actor);
|
||||
this._extraWorkspaces.push(ws);
|
||||
}
|
||||
},
|
||||
|
||||
_syncGeometry: function() {
|
||||
_destroyExtraWorkspaces: function() {
|
||||
for (let m = 0; m < this._extraWorkspaces.length; m++)
|
||||
this._extraWorkspaces[m].destroy();
|
||||
this._extraWorkspaces = [];
|
||||
},
|
||||
|
||||
setFullGeometry: function(geom) {
|
||||
if (rectEqual(this._fullGeometry, geom))
|
||||
return;
|
||||
|
||||
this._fullGeometry = geom;
|
||||
|
||||
for (let i = 0; i < this._workspaces.length; i++)
|
||||
this._workspaces[i].setFullGeometry(this._fullGeometry);
|
||||
this._workspaces[i].setFullGeometry(geom);
|
||||
},
|
||||
|
||||
setActualGeometry: function(geom) {
|
||||
if (rectEqual(this._actualGeometry, geom))
|
||||
return;
|
||||
|
||||
this._actualGeometry = geom;
|
||||
|
||||
for (let i = 0; i < this._workspaces.length; i++)
|
||||
this._workspaces[i].setActualGeometry(this._actualGeometry);
|
||||
this._workspaces[i].setActualGeometry(geom);
|
||||
},
|
||||
|
||||
getActiveWorkspace: function() {
|
||||
@ -139,22 +172,29 @@ const WorkspacesView = new Lang.Class({
|
||||
return this._workspaces[active];
|
||||
},
|
||||
|
||||
zoomToOverview: function() {
|
||||
for (let w = 0; w < this._workspaces.length; w++)
|
||||
this._workspaces[w].zoomToOverview();
|
||||
this._updateWorkspaceActors(false);
|
||||
},
|
||||
hide: function() {
|
||||
let activeWorkspaceIndex = global.screen.get_active_workspace_index();
|
||||
let activeWorkspace = this._workspaces[activeWorkspaceIndex];
|
||||
|
||||
activeWorkspace.actor.raise_top();
|
||||
|
||||
zoomFromOverview: function() {
|
||||
this.actor.remove_clip();
|
||||
|
||||
for (let w = 0; w < this._workspaces.length; w++)
|
||||
this._workspaces[w].zoomFromOverview();
|
||||
for (let w = 0; w < this._extraWorkspaces.length; w++)
|
||||
this._extraWorkspaces[w].zoomFromOverview();
|
||||
},
|
||||
|
||||
destroy: function() {
|
||||
this.actor.destroy();
|
||||
},
|
||||
|
||||
syncStacking: function(stackIndices) {
|
||||
for (let i = 0; i < this._workspaces.length; i++)
|
||||
this._workspaces[i].syncStacking(stackIndices);
|
||||
for (let i = 0; i < this._extraWorkspaces.length; i++)
|
||||
this._extraWorkspaces[i].syncStacking(stackIndices);
|
||||
},
|
||||
|
||||
_scrollToActive: function() {
|
||||
@ -176,7 +216,7 @@ const WorkspacesView = new Lang.Class({
|
||||
|
||||
Tweener.removeTweens(workspace.actor);
|
||||
|
||||
let y = (w - active) * this._fullGeometry.height;
|
||||
let y = (w - active) * (this._fullGeometry.height + this._spacing);
|
||||
|
||||
if (showAnimation) {
|
||||
let params = { y: y,
|
||||
@ -236,31 +276,25 @@ const WorkspacesView = new Lang.Class({
|
||||
});
|
||||
},
|
||||
|
||||
_updateWorkspaces: function() {
|
||||
let oldNumWorkspaces = this._workspaces.length;
|
||||
let newNumWorkspaces = global.screen.n_workspaces;
|
||||
updateWorkspaces: function(oldNumWorkspaces, newNumWorkspaces) {
|
||||
let active = global.screen.get_active_workspace_index();
|
||||
|
||||
this.scrollAdjustment.upper = newNumWorkspaces;
|
||||
Tweener.addTween(this.scrollAdjustment,
|
||||
{ upper: newNumWorkspaces,
|
||||
time: WORKSPACE_SWITCH_TIME,
|
||||
transition: 'easeOutQuad'
|
||||
});
|
||||
|
||||
if (newNumWorkspaces > oldNumWorkspaces) {
|
||||
for (let w = oldNumWorkspaces; w < newNumWorkspaces; w++) {
|
||||
let metaWorkspace = global.screen.get_workspace_by_index(w);
|
||||
let workspace = new Workspace.Workspace(metaWorkspace, this._monitorIndex);
|
||||
this._workspaces.push(workspace);
|
||||
this.actor.add_actor(workspace.actor);
|
||||
this._workspaces[w].setFullGeometry(this._fullGeometry);
|
||||
if (this._actualGeometry)
|
||||
this._workspaces[w].setActualGeometry(this._actualGeometry);
|
||||
this.actor.add_actor(this._workspaces[w].actor);
|
||||
}
|
||||
|
||||
if (this._fullGeometry)
|
||||
this._updateWorkspaceActors(false);
|
||||
} else if (newNumWorkspaces < oldNumWorkspaces) {
|
||||
let nRemoved = (newNumWorkspaces - oldNumWorkspaces);
|
||||
let removed = this._workspaces.splice(oldNumWorkspaces, nRemoved);
|
||||
removed.forEach(function(workspace) {
|
||||
workspace.destroy();
|
||||
});
|
||||
this._updateWorkspaceActors(false);
|
||||
}
|
||||
|
||||
this._syncGeometry();
|
||||
},
|
||||
|
||||
_activeWorkspaceChanged: function(wm, from, to, direction) {
|
||||
@ -271,12 +305,70 @@ const WorkspacesView = new Lang.Class({
|
||||
},
|
||||
|
||||
_onDestroy: function() {
|
||||
this.parent();
|
||||
|
||||
this._destroyExtraWorkspaces();
|
||||
this.scrollAdjustment.run_dispose();
|
||||
Main.overview.disconnect(this._overviewShowingId);
|
||||
Main.overview.disconnect(this._overviewShownId);
|
||||
global.window_manager.disconnect(this._switchWorkspaceNotifyId);
|
||||
global.screen.disconnect(this._updateWorkspacesId);
|
||||
this._settings.disconnect(this._updateExtraWorkspacesId);
|
||||
|
||||
if (this._inDrag)
|
||||
this._dragEnd();
|
||||
|
||||
if (this._itemDragBeginId > 0) {
|
||||
Main.overview.disconnect(this._itemDragBeginId);
|
||||
this._itemDragBeginId = 0;
|
||||
}
|
||||
if (this._itemDragEndId > 0) {
|
||||
Main.overview.disconnect(this._itemDragEndId);
|
||||
this._itemDragEndId = 0;
|
||||
}
|
||||
if (this._windowDragBeginId > 0) {
|
||||
Main.overview.disconnect(this._windowDragBeginId);
|
||||
this._windowDragBeginId = 0;
|
||||
}
|
||||
if (this._windowDragEndId > 0) {
|
||||
Main.overview.disconnect(this._windowDragEndId);
|
||||
this._windowDragEndId = 0;
|
||||
}
|
||||
},
|
||||
|
||||
_dragBegin: function() {
|
||||
if (this._scrolling)
|
||||
return;
|
||||
|
||||
this._inDrag = true;
|
||||
this._firstDragMotion = true;
|
||||
|
||||
this._dragMonitor = {
|
||||
dragMotion: Lang.bind(this, this._onDragMotion)
|
||||
};
|
||||
DND.addDragMonitor(this._dragMonitor);
|
||||
},
|
||||
|
||||
_onDragMotion: function(dragEvent) {
|
||||
if (Main.overview.animationInProgress)
|
||||
return DND.DragMotionResult.CONTINUE;
|
||||
|
||||
if (this._firstDragMotion) {
|
||||
this._firstDragMotion = false;
|
||||
for (let i = 0; i < this._workspaces.length; i++)
|
||||
this._workspaces[i].setReservedSlot(dragEvent.dragActor._delegate);
|
||||
for (let i = 0; i < this._extraWorkspaces.length; i++)
|
||||
this._extraWorkspaces[i].setReservedSlot(dragEvent.dragActor._delegate);
|
||||
}
|
||||
|
||||
return DND.DragMotionResult.CONTINUE;
|
||||
},
|
||||
|
||||
_dragEnd: function() {
|
||||
DND.removeDragMonitor(this._dragMonitor);
|
||||
this._inDrag = false;
|
||||
|
||||
for (let i = 0; i < this._workspaces.length; i++)
|
||||
this._workspaces[i].setReservedSlot(null);
|
||||
for (let i = 0; i < this._extraWorkspaces.length; i++)
|
||||
this._extraWorkspaces[i].setReservedSlot(null);
|
||||
},
|
||||
|
||||
startSwipeScroll: function() {
|
||||
@ -335,58 +427,12 @@ const WorkspacesView = new Lang.Class({
|
||||
});
|
||||
Signals.addSignalMethods(WorkspacesView.prototype);
|
||||
|
||||
const ExtraWorkspaceView = new Lang.Class({
|
||||
Name: 'ExtraWorkspaceView',
|
||||
Extends: WorkspacesViewBase,
|
||||
|
||||
_init: function(monitorIndex) {
|
||||
this.parent(monitorIndex);
|
||||
this._workspace = new Workspace.Workspace(null, monitorIndex);
|
||||
this.actor.add_actor(this._workspace.actor);
|
||||
},
|
||||
|
||||
_setReservedSlot: function(clone) {
|
||||
this._workspace.setReservedSlot(clone);
|
||||
},
|
||||
|
||||
_syncGeometry: function() {
|
||||
this._workspace.setFullGeometry(this._fullGeometry);
|
||||
this._workspace.setActualGeometry(this._actualGeometry);
|
||||
},
|
||||
|
||||
zoomToOverview: function() {
|
||||
this._workspace.zoomToOverview();
|
||||
},
|
||||
|
||||
zoomFromOverview: function() {
|
||||
this._workspace.zoomFromOverview();
|
||||
},
|
||||
|
||||
syncStacking: function(stackIndices) {
|
||||
this._workspace.syncStacking(stackIndices);
|
||||
},
|
||||
|
||||
startSwipeScroll: function() {
|
||||
},
|
||||
endSwipeScroll: function() {
|
||||
},
|
||||
});
|
||||
|
||||
const DelegateFocusNavigator = new Lang.Class({
|
||||
Name: 'DelegateFocusNavigator',
|
||||
Extends: St.Widget,
|
||||
|
||||
vfunc_navigate_focus: function(from, direction) {
|
||||
return this._delegate.navigateFocus(from, direction);
|
||||
},
|
||||
});
|
||||
|
||||
const WorkspacesDisplay = new Lang.Class({
|
||||
Name: 'WorkspacesDisplay',
|
||||
|
||||
_init: function() {
|
||||
this.actor = new DelegateFocusNavigator({ clip_to_allocation: true });
|
||||
this.actor._delegate = this;
|
||||
this.actor = new St.Widget({ clip_to_allocation: true });
|
||||
this.actor.connect('notify::allocation', Lang.bind(this, this._updateWorkspacesActualGeometry));
|
||||
this.actor.connect('parent-set', Lang.bind(this, this._parentSet));
|
||||
|
||||
@ -425,6 +471,7 @@ const WorkspacesDisplay = new Lang.Class({
|
||||
this._primaryIndex = Main.layoutManager.primaryIndex;
|
||||
|
||||
this._workspacesViews = [];
|
||||
this._workspaces = [];
|
||||
this._primaryScrollAdjustment = null;
|
||||
|
||||
this._settings = new Gio.Settings({ schema: OVERRIDE_SCHEMA });
|
||||
@ -433,6 +480,9 @@ const WorkspacesDisplay = new Lang.Class({
|
||||
this._workspacesOnlyOnPrimaryChanged));
|
||||
this._workspacesOnlyOnPrimaryChanged();
|
||||
|
||||
global.screen.connect('notify::n-workspaces',
|
||||
Lang.bind(this, this._workspacesChanged));
|
||||
|
||||
this._switchWorkspaceNotifyId = 0;
|
||||
|
||||
this._notifyOpacityId = 0;
|
||||
@ -448,14 +498,8 @@ const WorkspacesDisplay = new Lang.Class({
|
||||
return false;
|
||||
},
|
||||
|
||||
navigateFocus: function(from, direction) {
|
||||
return this._getPrimaryView().actor.navigate_focus(from, direction, false);
|
||||
},
|
||||
|
||||
show: function() {
|
||||
this._updateWorkspacesViews();
|
||||
for (let i = 0; i < this._workspacesViews.length; i++)
|
||||
this._workspacesViews[i].zoomToOverview();
|
||||
|
||||
this._restackedNotifyId =
|
||||
Main.overview.connect('windows-restacked',
|
||||
@ -465,8 +509,9 @@ const WorkspacesDisplay = new Lang.Class({
|
||||
},
|
||||
|
||||
zoomFromOverview: function() {
|
||||
for (let i = 0; i < this._workspacesViews.length; i++)
|
||||
this._workspacesViews[i].zoomFromOverview();
|
||||
for (let i = 0; i < this._workspacesViews.length; i++) {
|
||||
this._workspacesViews[i].hide();
|
||||
}
|
||||
},
|
||||
|
||||
hide: function() {
|
||||
@ -498,38 +543,46 @@ const WorkspacesDisplay = new Lang.Class({
|
||||
this._workspacesViews[i].destroy();
|
||||
|
||||
this._workspacesViews = [];
|
||||
this._workspaces = [];
|
||||
let monitors = Main.layoutManager.monitors;
|
||||
for (let i = 0; i < monitors.length; i++) {
|
||||
let view;
|
||||
if (this._workspacesOnlyOnPrimary && i != this._primaryIndex)
|
||||
view = new ExtraWorkspaceView(i);
|
||||
else
|
||||
view = new WorkspacesView(i);
|
||||
continue; // we are only interested in the primary monitor
|
||||
|
||||
let monitorWorkspaces = [];
|
||||
for (let w = 0; w < global.screen.n_workspaces; w++) {
|
||||
let metaWorkspace = global.screen.get_workspace_by_index(w);
|
||||
monitorWorkspaces.push(new Workspace.Workspace(metaWorkspace, i));
|
||||
}
|
||||
|
||||
this._workspaces.push(monitorWorkspaces);
|
||||
|
||||
let view = new WorkspacesView(monitorWorkspaces);
|
||||
view.actor.connect('scroll-event', Lang.bind(this, this._onScrollEvent));
|
||||
if (i == this._primaryIndex) {
|
||||
if (this._workspacesOnlyOnPrimary || i == this._primaryIndex) {
|
||||
this._scrollAdjustment = view.scrollAdjustment;
|
||||
this._scrollAdjustment.connect('notify::value',
|
||||
Lang.bind(this, this._scrollValueChanged));
|
||||
}
|
||||
|
||||
this._workspacesViews.push(view);
|
||||
Main.layoutManager.overviewGroup.add_actor(view.actor);
|
||||
}
|
||||
|
||||
this._updateWorkspacesFullGeometry();
|
||||
this._updateWorkspacesActualGeometry();
|
||||
|
||||
for (let i = 0; i < this._workspacesViews.length; i++)
|
||||
Main.layoutManager.overviewGroup.add_actor(this._workspacesViews[i].actor);
|
||||
},
|
||||
|
||||
_scrollValueChanged: function() {
|
||||
if (this._workspacesOnlyOnPrimary)
|
||||
return;
|
||||
|
||||
for (let i = 0; i < this._workspacesViews.length; i++) {
|
||||
if (i == this._primaryIndex)
|
||||
continue;
|
||||
|
||||
let adjustment = this._workspacesViews[i].scrollAdjustment;
|
||||
if (!adjustment)
|
||||
continue;
|
||||
|
||||
// the adjustments work in terms of workspaces, so the
|
||||
// values map directly
|
||||
adjustment.value = this._scrollAdjustment.value;
|
||||
@ -539,7 +592,10 @@ const WorkspacesDisplay = new Lang.Class({
|
||||
_getPrimaryView: function() {
|
||||
if (!this._workspacesViews.length)
|
||||
return null;
|
||||
return this._workspacesViews[this._primaryIndex];
|
||||
if (this._workspacesOnlyOnPrimary)
|
||||
return this._workspacesViews[0];
|
||||
else
|
||||
return this._workspacesViews[this._primaryIndex];
|
||||
},
|
||||
|
||||
activeWorkspaceHasMaximizedWindows: function() {
|
||||
@ -585,9 +641,15 @@ const WorkspacesDisplay = new Lang.Class({
|
||||
return;
|
||||
|
||||
let monitors = Main.layoutManager.monitors;
|
||||
let m = 0;
|
||||
for (let i = 0; i < monitors.length; i++) {
|
||||
let geometry = (i == this._primaryIndex) ? this._fullGeometry : monitors[i];
|
||||
this._workspacesViews[i].setFullGeometry(geometry);
|
||||
if (i == this._primaryIndex) {
|
||||
this._workspacesViews[m].setFullGeometry(this._fullGeometry);
|
||||
m++;
|
||||
} else if (!this._workspacesOnlyOnPrimary) {
|
||||
this._workspacesViews[m].setFullGeometry(monitors[i]);
|
||||
m++;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@ -598,12 +660,18 @@ const WorkspacesDisplay = new Lang.Class({
|
||||
let [x, y] = this.actor.get_transformed_position();
|
||||
let width = this.actor.allocation.x2 - this.actor.allocation.x1;
|
||||
let height = this.actor.allocation.y2 - this.actor.allocation.y1;
|
||||
let primaryGeometry = { x: x, y: y, width: width, height: height };
|
||||
let geometry = { x: x, y: y, width: width, height: height };
|
||||
|
||||
let monitors = Main.layoutManager.monitors;
|
||||
let m = 0;
|
||||
for (let i = 0; i < monitors.length; i++) {
|
||||
let geometry = (i == this._primaryIndex) ? primaryGeometry : monitors[i];
|
||||
this._workspacesViews[i].setActualGeometry(geometry);
|
||||
if (i == this._primaryIndex) {
|
||||
this._workspacesViews[m].setActualGeometry(geometry);
|
||||
m++;
|
||||
} else if (!this._workspacesOnlyOnPrimary) {
|
||||
this._workspacesViews[m].setActualGeometry(monitors[i]);
|
||||
m++;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@ -612,9 +680,63 @@ const WorkspacesDisplay = new Lang.Class({
|
||||
this._workspacesViews[i].syncStacking(stackIndices);
|
||||
},
|
||||
|
||||
_workspacesChanged: function() {
|
||||
if (!this._workspacesViews.length)
|
||||
return;
|
||||
|
||||
let oldNumWorkspaces = this._workspaces[0].length;
|
||||
let newNumWorkspaces = global.screen.n_workspaces;
|
||||
let active = global.screen.get_active_workspace_index();
|
||||
|
||||
let lostWorkspaces = [];
|
||||
if (newNumWorkspaces > oldNumWorkspaces) {
|
||||
let monitors = Main.layoutManager.monitors;
|
||||
let m = 0;
|
||||
for (let i = 0; i < monitors.length; i++) {
|
||||
if (this._workspacesOnlyOnPrimary &&
|
||||
i != this._primaryIndex)
|
||||
continue;
|
||||
|
||||
// Assume workspaces are only added at the end
|
||||
for (let w = oldNumWorkspaces; w < newNumWorkspaces; w++) {
|
||||
let metaWorkspace = global.screen.get_workspace_by_index(w);
|
||||
this._workspaces[m][w] =
|
||||
new Workspace.Workspace(metaWorkspace, i);
|
||||
}
|
||||
m++;
|
||||
}
|
||||
} else {
|
||||
// Assume workspaces are only removed sequentially
|
||||
// (e.g. 2,3,4 - not 2,4,7)
|
||||
let removedIndex;
|
||||
let removedNum = oldNumWorkspaces - newNumWorkspaces;
|
||||
for (let w = 0; w < oldNumWorkspaces; w++) {
|
||||
let metaWorkspace = global.screen.get_workspace_by_index(w);
|
||||
if (this._workspaces[0][w].metaWorkspace != metaWorkspace) {
|
||||
removedIndex = w;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (let i = 0; i < this._workspaces.length; i++) {
|
||||
lostWorkspaces = this._workspaces[i].splice(removedIndex,
|
||||
removedNum);
|
||||
|
||||
for (let l = 0; l < lostWorkspaces.length; l++) {
|
||||
lostWorkspaces[l].disconnectAll();
|
||||
lostWorkspaces[l].destroy();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (let i = 0; i < this._workspacesViews.length; i++)
|
||||
this._workspacesViews[i].updateWorkspaces(oldNumWorkspaces,
|
||||
newNumWorkspaces);
|
||||
},
|
||||
|
||||
_onScrollEvent: function(actor, event) {
|
||||
if (!this.actor.mapped)
|
||||
return Clutter.EVENT_PROPAGATE;
|
||||
return false;
|
||||
let activeWs = global.screen.get_active_workspace();
|
||||
let ws;
|
||||
switch (event.get_scroll_direction()) {
|
||||
@ -625,10 +747,10 @@ const WorkspacesDisplay = new Lang.Class({
|
||||
ws = activeWs.get_neighbor(Meta.MotionDirection.DOWN);
|
||||
break;
|
||||
default:
|
||||
return Clutter.EVENT_PROPAGATE;
|
||||
return false;
|
||||
}
|
||||
Main.wm.actionMoveWorkspace(ws);
|
||||
return Clutter.EVENT_STOP;
|
||||
return true;
|
||||
}
|
||||
});
|
||||
Signals.addSignalMethods(WorkspacesDisplay.prototype);
|
||||
|
@ -62,7 +62,7 @@ const XdndHandler = new Lang.Class({
|
||||
let cursorWindow = windows[windows.length - 1];
|
||||
|
||||
// FIXME: more reliable way?
|
||||
if (!cursorWindow.get_meta_window().is_override_redirect())
|
||||
if (!cursorWindow.is_override_redirect())
|
||||
return;
|
||||
|
||||
let constraint_position = new Clutter.BindConstraint({ coordinate : Clutter.BindCoordinate.POSITION,
|
||||
|
@ -38,7 +38,7 @@ js/ui/panel.js
|
||||
js/ui/popupMenu.js
|
||||
js/ui/runDialog.js
|
||||
js/ui/screenShield.js
|
||||
js/ui/search.js
|
||||
js/ui/searchDisplay.js
|
||||
js/ui/shellEntry.js
|
||||
js/ui/shellMountOperation.js
|
||||
js/ui/status/accessibility.js
|
||||
@ -52,6 +52,7 @@ js/ui/status/system.js
|
||||
js/ui/status/volume.js
|
||||
js/ui/unlockDialog.js
|
||||
js/ui/viewSelector.js
|
||||
js/ui/wanda.js
|
||||
js/ui/windowAttentionHandler.js
|
||||
js/ui/windowManager.js
|
||||
src/calendar-server/evolution-calendar.desktop.in.in
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user