Compare commits
2 Commits
wip/gcampa
...
3.7.3.1-br
Author | SHA1 | Date | |
---|---|---|---|
7d598b7725 | |||
9f890982b2 |
152
NEWS
152
NEWS
@ -1,154 +1,6 @@
|
||||
3.7.90
|
||||
======
|
||||
* Let GNOME Shell work on EGL and GLES2 [Neil; #693225, #693438, #693339]
|
||||
* Implement middle-click paste [Jasper; #645019]
|
||||
* Fix top bar transition between session modes [Rui; #692966]
|
||||
* Trigger the message tray with downward pressure [Jasper; #677215]
|
||||
* Don't ask for a password on shutdown [Adel; #693385]
|
||||
* Add a context menu to the message tray [Adel; #691035, #693887]
|
||||
* Use unicode formatting in the date menu [Matthias; #689251]
|
||||
* Use proper ellipsis instead of three dots [Jeremy; #689542]
|
||||
* Tweak screen shield animation [Giovanni; #691964]
|
||||
* Always hide the OSK when showing the message tray [Florian; #662687]
|
||||
* Support sound in notifications [Giovanni; #642831]
|
||||
* Place application popup menus above chrome [Jasper; #633620]
|
||||
* Hide overview elements while searching [Cosimo; #682050]
|
||||
* Implement updated IBus candidate popup designs [Rui; #691902]
|
||||
* Add support for enable-animations preference [Cosimo; #655746]
|
||||
* Don't always show the message tray in the overview [Cosimo; #693987]
|
||||
* Improve arrangement of window previews [Adel; #690313]
|
||||
* Remove builtin settings provider [Giovanni; #690824]
|
||||
* Minimize fullscreen windows when they end up in the background [Adel; #693991]
|
||||
* Add context menu to the background actor [Jasper; #681540]
|
||||
* Handle backgrounds in the shell, improve startup animation [Ray; #682429]
|
||||
* Hide universal access menu when not needed [Giovanni; #681528]
|
||||
* Implement updated app picker designs [Florian; #694192]
|
||||
* Improve login manager -> session transition [Ray; #694062]
|
||||
* Don't use a grid layout in window picker [Adel; #694210]
|
||||
* Use scroll wheel for workspace switching rather than zoom [Florian; #686639]
|
||||
* Misc bug fixes and cleanups: [Jasper, Florian, Debarshi, Adel, Matthias,
|
||||
Giovanni, Daiki, Rico, Bastien, Cosimo, Ray, Allan, Antonio; #693284,
|
||||
#692680, #691746, #693303, #693162, #693161, #693522, #693385, #691715,
|
||||
#688915, #689106, #682429, #693570, #693737, #693458, #692845, 693836,
|
||||
#681540, #679925, #688227, #692773, #693909, #683288, #693854, #693746,
|
||||
#693931, #693924, #693940, #693970, #693935, #693937, #693974, #693936,
|
||||
#693975, #693822, #694030, #685849, #694052, #694035, #694038, #694079,
|
||||
#694064, #681735, #694100, #694057, #694070, #693572, #693896, #686984,
|
||||
#694123, #694125, #693756, #693757, #687556, #694215, 694062, #694227,
|
||||
#694240, #694234, #694264, 694276, 694282, #694241, #689394, #694202,
|
||||
#694265, #694289, #691806, #694290, #694296]
|
||||
|
||||
Contributors:
|
||||
Jeremy Bicha, Giovanni Campagna, Cosimo Cecchi, Matthias Clasen, Allan Day,
|
||||
António Fernandes, Adel Gadllah, Rui Matos, Florian Müllner, Bastien Nocera,
|
||||
Debarshi Ray, Neil Roberts, Jasper St. Pierre, Ray Strode, Rico Tzschichholz,
|
||||
Daiki Ueno
|
||||
|
||||
Translations:
|
||||
Yasumichi Akahoshi [ja], Yoji TOYODA [ja], Dušan Kazik [sk],
|
||||
Wouter Bolsterlee [nl], Matej Urbančič [sl], Gheyret Kenji [ug],
|
||||
Ivaylo Valkov [bg], Daniel Korostil [uk], Gheyret Kenji [ug],
|
||||
Daniel Mustieles [es], Anish A [ml], Gil Forcada [ca],
|
||||
Carles Ferrando [ca@valencia], Мирослав Николић [sr, sr@latin],
|
||||
Aurimas Černius [lt], Rafael Ferreira [pt_BR], Fran Diéguez [gl],
|
||||
Piotr Drąg [pl], Luca Ferretti [it], A S Alam [pa]
|
||||
|
||||
3.7.5
|
||||
=====
|
||||
* MessageTray: pass keyboard events to tray icons [Giovanni; #687425]
|
||||
* network: add support for virtual devices (vlan, bond, bridge) [Dan; #677144]
|
||||
* gdm: Allow right-clicking buttons for left-handed users [Jasper; #688748]
|
||||
* Make list search results span all available horizontal space [Tanner; #691967]
|
||||
* Make Show-Applications button depress when held down [Hashem; #692319]
|
||||
* Set a max width on search results [Cosimo; #692453]
|
||||
* Reserve scrollbar allocation for automatic policy [Cosimo; #686881]
|
||||
* Improve scaling algorithm for window thumbnails [Jasper; #686944]
|
||||
* Fix launching settings panels after g-c-c changes [Jasper; #692483]
|
||||
* Stop launching applications from empty searches [Hashem; #692391]
|
||||
* Implement per-source notification filtering [Giovanni; #685926]
|
||||
* ScreenShield: Omit ActiveChanged() signal at end of fade [Giovanni; #691964]
|
||||
* ScreenShield: Lower the shield on idle before locking [Giovanni; #692560]
|
||||
* Make previews of minimized windows translucent in overview [Florian; #692999]
|
||||
* windowManager: Respect icon geometry when minimizing [Florian; #692997]
|
||||
* ScreenShield: Only show lock icon when actually locked [Giovanni; #693007]
|
||||
* general: Use & instead of 'and' for Settings panels [Jeremy; #689590]
|
||||
* network: Add support for new ModemManager1 interface [Aleksander; #687359]
|
||||
* network: Handle LTE-only modems as GSM ones [Aleksander; #688144]
|
||||
* mobile-providers: Port to libnm-gtk [Aleksander; #688943]
|
||||
* general: Consistently use Title Case in top bar [Jeremy; #689589]
|
||||
* panel: Add :overview pseudo class while in overview [Florian; #693218]
|
||||
* sessionMode: Add support for mode-specific styling [Florian; #693219]
|
||||
* loginManager: Make suspend a NOP in the ConsoleKit patch [Florian; #693162]
|
||||
* screenShield: Inhibit suspend until the screen is locked [Florian; #686482]
|
||||
* Misc bug fixes and cleanups [Jasper, Giovanni, Rui, Cosimo, Florian, Stefano,
|
||||
Adel, Yanko; #691745, #691731, #690171, #689091, #691976, #691963, #684279,
|
||||
#692052, #692091, #642831, #692454, #692715, #692678, #692723, #692677,
|
||||
#683986, #692693, #692749, #692948, #692995, #692996, #692994, #677215,
|
||||
#692586, #693067, #693031, #693049, #643111, #693161, #693220]
|
||||
|
||||
Contributors:
|
||||
Jeremy Bicha, Giovanni Campagna, Cosimo Cecchi, Tanner Doshier,
|
||||
Stefano Facchini, Adel Gadllah, Yanko Kaneti, Rui Matos, Aleksander Morgado,
|
||||
Florian Müllner, Hashem Nasarat, Jasper St. Pierre, Dan Winship
|
||||
|
||||
Translations:
|
||||
Duarte Loreto [pt], Daniel Mustieles [es], Kjartan Maraas [nb],
|
||||
Nilamdyuti Goswami [as], Мирослав Николић [sr,sr@latin],
|
||||
Tobias Endrigkeit [de], Fabio Tomat [fur], Matej Urbančič [sl], A S Alam [pa],
|
||||
Inaki Larranaga Murgoitio [eu], Piotr Drąg [pl], Wouter Bolsterlee [nl],
|
||||
Gheyret Kenji [ug], Yaron Shahrabani [he], Chao-Hsiung Liao [zh_HK,zh_TW],
|
||||
Milo Casagrande [it], Benjamin Steinwender [de]
|
||||
|
||||
3.7.4.1
|
||||
3.7.3.1
|
||||
=======
|
||||
* userMenu: Use show-full-name-in-top-bar setting [Bastien; #689561]
|
||||
* dateMenu: Add "Open Clocks" entry [Mathieu; #644390]
|
||||
* screenshot: Immediately show the flash spot [Jasper; #691875]
|
||||
* Misc. bug fixes [Rico, Jeremy]
|
||||
|
||||
Contributors:
|
||||
Jeremy Bicha, Mathieu Bridon, Bastien Nocera, Jasper St. Pierre,
|
||||
Rico Tzschichholz
|
||||
|
||||
Translations:
|
||||
Ihar Hrachyshka [be]
|
||||
|
||||
3.7.4
|
||||
=====
|
||||
* Make menu separators crisp [Giovanni, Allan; #641745]
|
||||
* power: Update for new D-Bus name [Bastien; #690506]
|
||||
* Add smooth scrolling support [Jasper; #687573]
|
||||
* Tweak notification layout [Allan; #688506]
|
||||
* Ping the active window when using the app menu [Giovanni; #684340]
|
||||
* Make password entries insensitive after submission [Jasper; #690594, #690895]
|
||||
* Honor lock-delay GSettings key [Giovanni, Matthias; #690766, #691170]
|
||||
* Use text/calendar preferred app as the calendar app [Giovanni; #690767]
|
||||
* lookingGlass: Move to an inspect() function [Jasper; #690726]
|
||||
* Make OSK animation quicker, snappier [Rui; #688642]
|
||||
* Allow to close chat notifications with Escape [Jasper; #690897]
|
||||
* Honor org.gnome.desktop.screensaver.user-switch-enabled [Giovanni; #691042]
|
||||
* Add a SelectArea() DBus method [Cosimo; #687954]
|
||||
* Support non-absolute paths when saving screenshots [Cosimo; #688004]
|
||||
* OSK: Fix extended keys popups [Rui; #674955]
|
||||
* Don't hide or show the keyboard immediately [Rui; #688646]
|
||||
* Improve padding in power menu [Giovanni; #689297]
|
||||
* Add per-window input source switching [Rui; #691414]
|
||||
* Misc bug fixes and cleanups [Rico, Jasper, Giovanni, Rui, Florian, Dan;
|
||||
#690608, #690589, #690539, #687081, #690667, #690665, #690666, #685856,
|
||||
#690858, #690895, #680414, #690965, #691019, #690590, #681376, #690180,
|
||||
#685513, #689263, #691553, #691720, #691743, #691750]
|
||||
|
||||
Contributors:
|
||||
Giovanni Campagna, Cosimo Cecchi, Matthias Clasen, Allan Day, Rui Matos,
|
||||
Florian Müllner, Bastien Nocera, Jasper St. Pierre, Rico Tzschichholz,
|
||||
Dan Winship
|
||||
|
||||
Translations:
|
||||
Matej Urbančič [sl], Kjartan Maraas [nb], Mattias Põldaru [et],
|
||||
Yaron Shahrabani [he], Aurimas Černius [lt], Khaled Hosny [ar],
|
||||
Fran Diéguez [gl], Daniel Mustieles [es], Piotr Drąg [pl], Balázs Úr [hu],
|
||||
Baurzhan Muftakhidinov [kk], Tobias Endrigkeit [de], Dušan Kazik [sk],
|
||||
Aron Xu [zh_CN], Gheyret Kenji [ug]
|
||||
* Revert 490206b to not depend on NMGTK-0.9.7, which hasn't been released yet
|
||||
|
||||
3.7.3
|
||||
=====
|
||||
|
118
configure.ac
118
configure.ac
@ -1,5 +1,5 @@
|
||||
AC_PREREQ(2.63)
|
||||
AC_INIT([gnome-shell],[3.7.90],[https://bugzilla.gnome.org/enter_bug.cgi?product=gnome-shell],[gnome-shell])
|
||||
AC_INIT([gnome-shell],[3.7.3.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,6 +16,8 @@ m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])])
|
||||
|
||||
# Checks for programs.
|
||||
AC_PROG_CC
|
||||
# Needed for per-target cflags, like in gnomeshell-taskpanel
|
||||
AM_PROG_CC_C_O
|
||||
|
||||
# Initialize libtool
|
||||
LT_PREREQ([2.2.6])
|
||||
@ -53,28 +55,29 @@ if $PKG_CONFIG --exists gstreamer-1.0 '>=' $GSTREAMER_MIN_VERSION ; then
|
||||
AC_MSG_RESULT(yes)
|
||||
build_recorder=true
|
||||
recorder_modules="gstreamer-1.0 gstreamer-base-1.0 x11 gtk+-3.0"
|
||||
PKG_CHECK_MODULES(TEST_SHELL_RECORDER, $recorder_modules clutter-1.0 xfixes)
|
||||
PKG_CHECK_MODULES(TEST_SHELL_RECORDER, $recorder_modules clutter-1.0 xfixes gl)
|
||||
else
|
||||
AC_MSG_RESULT(no)
|
||||
fi
|
||||
|
||||
AM_CONDITIONAL(BUILD_RECORDER, $build_recorder)
|
||||
|
||||
CLUTTER_MIN_VERSION=1.13.4
|
||||
CLUTTER_MIN_VERSION=1.11.11
|
||||
GOBJECT_INTROSPECTION_MIN_VERSION=0.10.1
|
||||
GJS_MIN_VERSION=1.35.4
|
||||
MUTTER_MIN_VERSION=3.7.90
|
||||
GTK_MIN_VERSION=3.7.9
|
||||
GJS_MIN_VERSION=1.33.2
|
||||
MUTTER_MIN_VERSION=3.7.3
|
||||
GTK_MIN_VERSION=3.3.9
|
||||
GIO_MIN_VERSION=2.35.0
|
||||
LIBECAL_MIN_VERSION=3.5.3
|
||||
LIBEDATASERVER_MIN_VERSION=3.5.3
|
||||
LIBEDATASERVERUI_MIN_VERSION=3.5.3
|
||||
TELEPATHY_GLIB_MIN_VERSION=0.17.5
|
||||
TELEPATHY_LOGGER_MIN_VERSION=0.2.4
|
||||
POLKIT_MIN_VERSION=0.100
|
||||
STARTUP_NOTIFICATION_MIN_VERSION=0.11
|
||||
GCR_MIN_VERSION=3.3.90
|
||||
GNOME_DESKTOP_REQUIRED_VERSION=3.7.90
|
||||
GNOME_DESKTOP_REQUIRED_VERSION=3.7.1
|
||||
GNOME_MENUS_REQUIRED_VERSION=3.5.3
|
||||
NETWORKMANAGER_MIN_VERSION=0.9.6
|
||||
PULSE_MIN_VERS=2.0
|
||||
|
||||
# Collect more than 20 libraries for a prize!
|
||||
@ -87,26 +90,42 @@ PKG_CHECK_MODULES(GNOME_SHELL, gio-unix-2.0 >= $GIO_MIN_VERSION
|
||||
libgnome-menu-3.0 >= $GNOME_MENUS_REQUIRED_VERSION
|
||||
$recorder_modules
|
||||
gdk-x11-3.0 libsoup-2.4
|
||||
gl
|
||||
clutter-x11-1.0 >= $CLUTTER_MIN_VERSION
|
||||
clutter-glx-1.0 >= $CLUTTER_MIN_VERSION
|
||||
libstartup-notification-1.0 >= $STARTUP_NOTIFICATION_MIN_VERSION
|
||||
gobject-introspection-1.0 >= $GOBJECT_INTROSPECTION_MIN_VERSION
|
||||
libcanberra libcanberra-gtk3
|
||||
libcanberra
|
||||
telepathy-glib >= $TELEPATHY_GLIB_MIN_VERSION
|
||||
telepathy-logger-0.2 >= $TELEPATHY_LOGGER_MIN_VERSION
|
||||
polkit-agent-1 >= $POLKIT_MIN_VERSION xfixes
|
||||
libnm-glib libnm-util >= $NETWORKMANAGER_MIN_VERSION
|
||||
libnm-gtk >= $NETWORKMANAGER_MIN_VERSION
|
||||
gnome-keyring-1 gcr-3 >= $GCR_MIN_VERSION)
|
||||
libnm-glib libnm-util gnome-keyring-1
|
||||
gcr-3 >= $GCR_MIN_VERSION)
|
||||
|
||||
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)
|
||||
|
||||
GNOME_KEYBINDINGS_KEYSDIR=`$PKG_CONFIG --variable keysdir gnome-keybindings`
|
||||
AC_SUBST([GNOME_KEYBINDINGS_KEYSDIR])
|
||||
|
||||
GOBJECT_INTROSPECTION_CHECK([$GOBJECT_INTROSPECTION_MIN_VERSION])
|
||||
|
||||
saved_CFLAGS=$CFLAGS
|
||||
saved_LIBS=$LIBS
|
||||
CFLAGS=$GNOME_SHELL_CFLAGS
|
||||
LIBS=$GNOME_SHELL_LIBS
|
||||
AC_CHECK_FUNCS(JS_NewGlobalObject XFixesCreatePointerBarrier)
|
||||
CFLAGS=$saved_CFLAGS
|
||||
LIBS=$saved_LIBS
|
||||
|
||||
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)
|
||||
PKG_CHECK_MODULES(DESKTOP_SCHEMAS, gsettings-desktop-schemas >= 3.7.2.2)
|
||||
|
||||
AC_MSG_CHECKING([for bluetooth support])
|
||||
PKG_CHECK_EXISTS([gnome-bluetooth-1.0 >= 3.1.0],
|
||||
@ -126,10 +145,32 @@ PKG_CHECK_MODULES(CALENDAR_SERVER, libecal-1.2 >= $LIBECAL_MIN_VERSION libedatas
|
||||
AC_SUBST(CALENDAR_SERVER_CFLAGS)
|
||||
AC_SUBST(CALENDAR_SERVER_LIBS)
|
||||
|
||||
GNOME_KEYBINDINGS_KEYSDIR=`$PKG_CONFIG --variable keysdir gnome-keybindings`
|
||||
AC_SUBST([GNOME_KEYBINDINGS_KEYSDIR])
|
||||
AC_ARG_WITH(systemd,
|
||||
AS_HELP_STRING([--with-systemd],
|
||||
[Add systemd support]),
|
||||
[with_systemd=$withval], [with_systemd=auto])
|
||||
|
||||
GOBJECT_INTROSPECTION_CHECK([$GOBJECT_INTROSPECTION_MIN_VERSION])
|
||||
PKG_CHECK_MODULES(SYSTEMD,
|
||||
[libsystemd-login libsystemd-daemon],
|
||||
[have_systemd=yes], [have_systemd=no])
|
||||
|
||||
if test "x$with_systemd" = "xauto" ; then
|
||||
if test x$have_systemd = xno ; then
|
||||
use_systemd=no
|
||||
else
|
||||
use_systemd=yes
|
||||
fi
|
||||
else
|
||||
use_systemd=$with_systemd
|
||||
fi
|
||||
|
||||
if test "x$use_systemd" = "xyes"; then
|
||||
if test "x$have_systemd" = "xno"; then
|
||||
AC_MSG_ERROR([Systemd support explicitly required, but systemd not found])
|
||||
fi
|
||||
|
||||
AC_DEFINE(WITH_SYSTEMD, 1, [systemd support])
|
||||
fi
|
||||
|
||||
MUTTER_GIR_DIR=`$PKG_CONFIG --variable=girdir libmutter`
|
||||
MUTTER_TYPELIB_DIR=`$PKG_CONFIG --variable=typelibdir libmutter`
|
||||
@ -156,6 +197,16 @@ fi
|
||||
|
||||
# Sets GLIB_GENMARSHAL and GLIB_MKENUMS
|
||||
AM_PATH_GLIB_2_0()
|
||||
G_IR_SCANNER=`$PKG_CONFIG --variable=g_ir_scanner gobject-introspection-1.0`
|
||||
AC_SUBST(G_IR_SCANNER)
|
||||
G_IR_COMPILER=`$PKG_CONFIG --variable=g_ir_compiler gobject-introspection-1.0`
|
||||
AC_SUBST(G_IR_COMPILER)
|
||||
G_IR_GENERATE=`$PKG_CONFIG --variable=g_ir_generate gobject-introspection-1.0`
|
||||
AC_SUBST(G_IR_GENERATE)
|
||||
GIRDIR=`$PKG_CONFIG --variable=girdir gobject-introspection-1.0`
|
||||
AC_SUBST(GIRDIR)
|
||||
TYPELIBDIR="$($PKG_CONFIG --variable=typelibdir gobject-introspection-1.0)"
|
||||
AC_SUBST(TYPELIBDIR)
|
||||
|
||||
GTK_DOC_CHECK([1.15], [--flavour no-tmpl])
|
||||
|
||||
@ -171,7 +222,32 @@ if test "$enable_man" != no; then
|
||||
fi
|
||||
AM_CONDITIONAL(ENABLE_MAN, test "$enable_man" != no)
|
||||
|
||||
GNOME_COMPILE_WARNINGS([error])
|
||||
# Stay command-line compatible with the gnome-common configure option. Here
|
||||
# minimum/yes/maximum are the same, however.
|
||||
AC_ARG_ENABLE(compile_warnings,
|
||||
AS_HELP_STRING([--enable-compile-warnings=@<:@no/minimum/yes/maximum/error@:>@],[Turn on compiler warnings]),,
|
||||
enable_compile_warnings=error)
|
||||
|
||||
changequote(,)dnl
|
||||
if test "$enable_compile_warnings" != no ; then
|
||||
if test "x$GCC" = "xyes"; then
|
||||
case " $CFLAGS " in
|
||||
*[\ \ ]-Wall[\ \ ]*) ;;
|
||||
*) CFLAGS="$CFLAGS -Wall" ;;
|
||||
esac
|
||||
case " $CFLAGS " in
|
||||
*[\ \ ]-Wmissing-prototypes[\ \ ]*) ;;
|
||||
*) CFLAGS="$CFLAGS -Wmissing-prototypes" ;;
|
||||
esac
|
||||
if test "$enable_compile_warnings" = error ; then
|
||||
case " $CFLAGS " in
|
||||
*[\ \ ]-Werror[\ \ ]*) ;;
|
||||
*) CFLAGS="$CFLAGS -Werror -Wno-error=deprecated-declarations" ;;
|
||||
esac
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
changequote([,])dnl
|
||||
|
||||
AC_ARG_ENABLE(jhbuild-wrapper-script,
|
||||
AS_HELP_STRING([--enable-jhbuild-wrapper-script],[Make "gnome-shell" script work for jhbuild]),,enable_jhbuild_wrapper_script=no)
|
||||
|
@ -12,7 +12,6 @@ desktop_DATA = gnome-shell.desktop gnome-shell-extension-prefs.desktop
|
||||
|
||||
introspectiondir = $(datadir)/dbus-1/interfaces
|
||||
introspection_DATA = \
|
||||
org.gnome.Shell.Screenshot.xml \
|
||||
org.gnome.ShellSearchProvider.xml \
|
||||
org.gnome.ShellSearchProvider2.xml
|
||||
|
||||
|
@ -1,128 +0,0 @@
|
||||
<!DOCTYPE node PUBLIC
|
||||
'-//freedesktop//DTD D-BUS Object Introspection 1.0//EN'
|
||||
'http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd'>
|
||||
<node>
|
||||
|
||||
<!--
|
||||
org.gnome.Shell.Screenshot:
|
||||
@short_description: Screenshot interface
|
||||
|
||||
The interface used to capture pictures of the screen contents.
|
||||
-->
|
||||
<interface name="org.gnome.Shell.Screenshot">
|
||||
|
||||
<!--
|
||||
Screenshot:
|
||||
@filename: The filename for the screenshot
|
||||
@include_cursor: Whether to include the cursor image or not
|
||||
@flash: Whether to flash the screen or not
|
||||
@success: whether the screenshot was captured
|
||||
@filename_used: the file where the screenshot was saved
|
||||
|
||||
Takes a screenshot of the whole screen and saves it
|
||||
in @filename as png image, it returns a boolean
|
||||
indicating whether the operation was successful or not.
|
||||
@filename can either be an absolute path or a basename, in
|
||||
which case the screenshot will be saved in the $XDG_PICTURES_DIR
|
||||
or the home directory if it doesn't exist. The filename used
|
||||
to save the screenshot will be returned in @filename_used.
|
||||
-->
|
||||
<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>
|
||||
|
||||
<!--
|
||||
ScreenshotWindow:
|
||||
@include_frame: Whether to include the frame or not
|
||||
@include_cursor: Whether to include the cursor image or not
|
||||
@flash: Whether to flash the window area or not
|
||||
@filename: The filename for the screenshot
|
||||
@success: whether the screenshot was captured
|
||||
@filename_used: the file where the screenshot was saved
|
||||
|
||||
Takes a screenshot of the focused window (optionally omitting the frame)
|
||||
and saves it in @filename as png image, it returns a boolean
|
||||
indicating whether the operation was successful or not.
|
||||
@filename can either be an absolute path or a basename, in
|
||||
which case the screenshot will be saved in the $XDG_PICTURES_DIR
|
||||
or the home directory if it doesn't exist. The filename used
|
||||
to save the screenshot will be returned in @filename_used.
|
||||
-->
|
||||
<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>
|
||||
|
||||
<!--
|
||||
ScreenshotArea:
|
||||
@x: the X coordinate of the area to capture
|
||||
@y: the Y coordinate of the area to capture
|
||||
@width: the width of the area to capture
|
||||
@height: the height of the area to capture
|
||||
@flash: whether to flash the area or not
|
||||
@filename: the filename for the screenshot
|
||||
@success: whether the screenshot was captured
|
||||
@filename_used: the file where the screenshot was saved
|
||||
|
||||
Takes a screenshot of the passed in area and saves it
|
||||
in @filename as png image, it returns a boolean
|
||||
indicating whether the operation was successful or not.
|
||||
@filename can either be an absolute path or a basename, in
|
||||
which case the screenshot will be saved in the $XDG_PICTURES_DIR
|
||||
or the home directory if it doesn't exist. The filename used
|
||||
to save the screenshot will be returned in @filename_used.
|
||||
-->
|
||||
<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>
|
||||
|
||||
<!--
|
||||
FlashArea:
|
||||
@x: the X coordinate of the area to flash
|
||||
@y: the Y coordinate of the area to flash
|
||||
@width: the width of the area to flash
|
||||
@height: the height of the area to flash
|
||||
|
||||
Renders a flash spot effect in the specified rectangle of the screen.
|
||||
-->
|
||||
<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>
|
||||
|
||||
<!--
|
||||
SelectArea:
|
||||
@x: the X coordinate of the selected area
|
||||
@y: the Y coordinate of the selected area
|
||||
@width: the width of the selected area
|
||||
@height: the height of the selected area
|
||||
|
||||
Interactively allows the user to select a rectangular area of
|
||||
the screen, and returns its coordinates.
|
||||
-->
|
||||
<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>
|
||||
|
||||
</interface>
|
||||
</node>
|
@ -46,7 +46,7 @@
|
||||
<!--
|
||||
GetResultMetas:
|
||||
@identifiers: An array of result identifiers as returned by GetInitialResultSet() or GetSubsearchResultSet()
|
||||
@metas: A dictionary describing the given search result, containing a human-readable 'name' (string), along with the result identifier this meta is for, 'id' (string). Optionally, either 'gicon' (a serialized GIcon) or 'icon-data' (raw image data as (iiibiiay) - width, height, rowstride, has-alpha, bits per sample, channels, data) can be specified if the result can be better served with a thumbnail of the content (such as with images). A 'description' field (string) may also be specified if more context would help the user find the desired result.
|
||||
@metas: A dictionary describing the given search result, containing 'id' and 'name' (both strings). Optionally, either 'gicon' (a serialized GIcon) or 'icon-data' (raw image data as (iiibiiay) - width, height, rowstride, has-alpha, bits per sample, channels, data) can be specified if the result can be better served with a thumbnail of the content (such as with images).
|
||||
|
||||
Return an array of meta data used to display each given result
|
||||
-->
|
||||
|
@ -46,7 +46,7 @@
|
||||
<!--
|
||||
GetResultMetas:
|
||||
@identifiers: An array of result identifiers as returned by GetInitialResultSet() or GetSubsearchResultSet()
|
||||
@metas: A dictionary describing the given search result, containing a human-readable 'name' (string), along with the result identifier this meta is for, 'id' (string). Optionally, either 'gicon' (a serialized GIcon) or 'icon-data' (raw image data as (iiibiiay) - width, height, rowstride, has-alpha, bits per sample, channels, data) can be specified if the result can be better served with a thumbnail of the content (such as with images). A 'description' field (string) may also be specified if more context would help the user find the desired result.
|
||||
@metas: A dictionary describing the given search result, containing 'id' and 'name' (both strings). Optionally, either 'gicon' (a serialized GIcon) or 'icon-data' (raw image data as (iiibiiay) - width, height, rowstride, has-alpha, bits per sample, channels, data) can be specified if the result can be better served with a thumbnail of the content (such as with images). A 'description' field (string) may also be specified if more context would help the user find the desired result.
|
||||
|
||||
Return an array of meta data used to display each given result
|
||||
-->
|
||||
|
@ -39,14 +39,6 @@
|
||||
will be displayed in the favorites area.
|
||||
</_description>
|
||||
</key>
|
||||
<key name="app-folder-categories" type="as">
|
||||
<default>[ 'Utilities', 'Sundry' ]</default>
|
||||
<_summary>List of categories that should be displayed as folders</_summary>
|
||||
<_description>
|
||||
Each category name in this list will be represented as folder in the
|
||||
application view, rather than being displayed inline in the main view.
|
||||
</_description>
|
||||
</key>
|
||||
<key name="command-history" type="as">
|
||||
<default>[]</default>
|
||||
<_summary>History for command (Alt-F2) dialog</_summary>
|
||||
@ -73,6 +65,11 @@ value here is from the GsmPresenceStatus enumeration.</_summary>
|
||||
menuitem in single-user, single-session situations.
|
||||
</_description>
|
||||
</key>
|
||||
<key name="show-full-name" type="b">
|
||||
<default>true</default>
|
||||
<_summary>Show full name in the user menu</_summary>
|
||||
<_description>Whether the users full name is shown in the user menu or not.</_description>
|
||||
</key>
|
||||
<key name="remember-mount-password" type="b">
|
||||
<default>false</default>
|
||||
<_summary>Whether to remember password for mounting encrypted or remote filesystems</_summary>
|
||||
|
@ -38,6 +38,7 @@ stage {
|
||||
|
||||
/* small */
|
||||
.app-well-menu,
|
||||
.contact-details-status,
|
||||
.run-dialog-error-label {
|
||||
font-size: 9pt;
|
||||
}
|
||||
@ -127,7 +128,7 @@ StScrollBar StButton#vhandle:active {
|
||||
|
||||
.popup-menu-boxpointer {
|
||||
-arrow-border-radius: 8px;
|
||||
-arrow-background-color: rgba(0,0,0,0.9);
|
||||
-arrow-background-color: black;
|
||||
-arrow-border-width: 2px;
|
||||
-arrow-border-color: #a5a5a5;
|
||||
-arrow-base: 24px;
|
||||
@ -205,12 +206,11 @@ StScrollBar StButton#vhandle:active {
|
||||
}
|
||||
|
||||
.popup-separator-menu-item {
|
||||
-gradient-height: 1px;
|
||||
-gradient-start: rgba(255,255,255,0.0);
|
||||
-gradient-end: rgba(255,255,255,0.3);
|
||||
-margin-horizontal: 24px;
|
||||
height: 1px;
|
||||
padding: 8px 0px;
|
||||
-gradient-height: 2px;
|
||||
-gradient-start: rgba(8,8,8,0);
|
||||
-gradient-end: #333333;
|
||||
-margin-horizontal: 1.5em;
|
||||
height: 1em;
|
||||
}
|
||||
|
||||
.popup-alternating-menu-item:alternate {
|
||||
@ -251,10 +251,6 @@ StScrollBar StButton#vhandle:active {
|
||||
icon-size: 1.09em;
|
||||
}
|
||||
|
||||
.popup-battery-percentage {
|
||||
padding-left: 24px;
|
||||
}
|
||||
|
||||
/* Switches */
|
||||
.toggle-switch {
|
||||
width: 65px;
|
||||
@ -285,24 +281,20 @@ StScrollBar StButton#vhandle:active {
|
||||
|
||||
/* Buttons */
|
||||
|
||||
.candidate-page-button,
|
||||
.dash-search-button,
|
||||
.notification-button,
|
||||
.notification-icon-button,
|
||||
.hotplug-notification-item,
|
||||
.hotplug-resident-eject-button,
|
||||
.modal-dialog-button,
|
||||
.app-view-control {
|
||||
.modal-dialog-button {
|
||||
font-weight: bold;
|
||||
border: 1px solid #8b8b8b;
|
||||
background-gradient-direction: vertical;
|
||||
background-gradient-start: rgba(255, 255, 255, 0.2);
|
||||
background-gradient-end: rgba(255, 255, 255, 0);
|
||||
}
|
||||
|
||||
.modal-dialog-button {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.candidate-page-button:hover,
|
||||
.dash-search-button:hover,
|
||||
.notification-button:hover,
|
||||
.notification-icon-button:hover,
|
||||
.hotplug-notification-item:hover,
|
||||
@ -312,6 +304,8 @@ StScrollBar StButton#vhandle:active {
|
||||
background-gradient-end: rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
|
||||
.dash-search-button:selected,
|
||||
.dash-search-button:focus,
|
||||
.notification-button:focus,
|
||||
.notification-icon-button:focus,
|
||||
.hotplug-notification-item:focus,
|
||||
@ -319,20 +313,18 @@ StScrollBar StButton#vhandle:active {
|
||||
border-width: 2px;
|
||||
}
|
||||
|
||||
.candidate-page-button:active,
|
||||
.candidate-page-button:pressed,
|
||||
.dash-search-button:active,
|
||||
.dash-search-button:pressed,
|
||||
.notification-button:active,
|
||||
.notification-icon-button:active,
|
||||
.hotplug-notification-item:active,
|
||||
.hotplug-resident-eject-button:active,
|
||||
.modal-dialog-button:active,
|
||||
.modal-dialog-button:pressed,
|
||||
.app-view-control:checked {
|
||||
.modal-dialog-button:pressed {
|
||||
background-gradient-start: rgba(255, 255, 255, 0);
|
||||
background-gradient-end: rgba(255, 255, 255, 0.2);
|
||||
}
|
||||
|
||||
.candidate-page-button:insensitive,
|
||||
.notification-button:insensitive,
|
||||
.notification-icon-button:insensitive,
|
||||
.modal-dialog-button:insensitive {
|
||||
@ -342,27 +334,6 @@ StScrollBar StButton#vhandle:active {
|
||||
background-color: rgba(102, 102, 102, 0.15);
|
||||
}
|
||||
|
||||
/* Common radii */
|
||||
|
||||
#searchEntry,
|
||||
.modal-dialog-button,
|
||||
.notification-button,
|
||||
.hotplug-notification-item,
|
||||
.app-view-controls {
|
||||
border-radius: 18px;
|
||||
}
|
||||
|
||||
.app-view-control:first-child:ltr,
|
||||
.app-view-control:last-child:rtl {
|
||||
border-radius: 18px 0px 0px 18px;
|
||||
border-right-width: 0px;
|
||||
}
|
||||
|
||||
.app-view-control:last-child:ltr,
|
||||
.app-view-control:first-child:rtl {
|
||||
border-radius: 0px 18px 18px 0px;
|
||||
}
|
||||
|
||||
/* Entries */
|
||||
|
||||
#searchEntry,
|
||||
@ -383,7 +354,7 @@ StScrollBar StButton#vhandle:active {
|
||||
background-gradient-start: rgba(5,5,6,0.1);
|
||||
background-gradient-end: rgba(254,254,254,0.1);
|
||||
background-gradient-direction: vertical;
|
||||
transition-duration: 300ms;
|
||||
transition-duration: 300;
|
||||
box-shadow: inset 0px 2px 4px rgba(0,0,0,0.6);
|
||||
}
|
||||
|
||||
@ -418,7 +389,7 @@ StScrollBar StButton#vhandle:active {
|
||||
color: rgb(64, 64, 64);
|
||||
caret-color: rgb(64, 64, 64);
|
||||
font-weight: bold;
|
||||
transition-duration: 0ms;
|
||||
transition-duration: 0;
|
||||
}
|
||||
|
||||
.notification StEntry,
|
||||
@ -449,14 +420,17 @@ StScrollBar StButton#vhandle:active {
|
||||
background-color: black;
|
||||
font-weight: bold;
|
||||
height: 1.86em;
|
||||
transition-duration: 250;
|
||||
}
|
||||
|
||||
#panel.lock-screen {
|
||||
height: 2em;
|
||||
background-color: rgba(0,0,0,0.3);
|
||||
}
|
||||
|
||||
#panel.unlock-screen,
|
||||
#panel.login-screen {
|
||||
height: 2em;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
@ -529,7 +503,7 @@ StScrollBar StButton#vhandle:active {
|
||||
-minimum-hpadding: 6px;
|
||||
font-weight: bold;
|
||||
color: #ccc;
|
||||
transition-duration: 100ms;
|
||||
transition-duration: 100;
|
||||
}
|
||||
|
||||
#panel.unlock-screen .panel-button,
|
||||
@ -577,7 +551,7 @@ StScrollBar StButton#vhandle:active {
|
||||
}
|
||||
|
||||
.panel-menu {
|
||||
-boxpointer-gap: 4px;
|
||||
-boxpointer-gap: 4px
|
||||
}
|
||||
|
||||
.panel-status-button-box {
|
||||
@ -646,8 +620,20 @@ StScrollBar StButton#vhandle:active {
|
||||
spacing: 24px;
|
||||
}
|
||||
|
||||
.overview-controls {
|
||||
padding-bottom: 32px;
|
||||
#overview-group {
|
||||
spacing: 32px;
|
||||
}
|
||||
|
||||
.workspaces-display {
|
||||
spacing: 32px; /* needs to be the same value as #overview-group */
|
||||
}
|
||||
|
||||
.window-caption {
|
||||
spacing: 25px;
|
||||
}
|
||||
|
||||
.workspace-controls {
|
||||
visible-width: 32px; /* Amount visible before hovering */
|
||||
}
|
||||
|
||||
.workspace-thumbnails-background {
|
||||
@ -667,7 +653,6 @@ StScrollBar StButton#vhandle:active {
|
||||
|
||||
.workspace-thumbnails {
|
||||
spacing: 11px;
|
||||
visible-width: 32px; /* Amount visible before hovering */
|
||||
}
|
||||
|
||||
.workspace-thumbnail-indicator {
|
||||
@ -677,7 +662,6 @@ StScrollBar StButton#vhandle:active {
|
||||
}
|
||||
|
||||
.window-caption {
|
||||
spacing: 25px;
|
||||
background: rgba(0,0,0,0.5);
|
||||
border-radius: 8px;
|
||||
padding: 4px 12px;
|
||||
@ -685,10 +669,6 @@ StScrollBar StButton#vhandle:active {
|
||||
border: 2px solid rgba(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
.window-caption:hover {
|
||||
border: 2px solid rgba(255, 255, 255, 0);
|
||||
}
|
||||
|
||||
.window-close, .notification-close {
|
||||
background-image: url("close-window.svg");
|
||||
background-size: 32px;
|
||||
@ -700,6 +680,10 @@ StScrollBar StButton#vhandle:active {
|
||||
-shell-close-overlap: 16px;
|
||||
}
|
||||
|
||||
.window-caption:hover {
|
||||
border: 2px solid rgba(255, 255, 255, 0);
|
||||
}
|
||||
|
||||
.window-clone-border {
|
||||
border: 4px solid rgba(255, 255, 255, 0.5);
|
||||
border-radius: 4px;
|
||||
@ -732,36 +716,6 @@ StScrollBar StButton#vhandle:active {
|
||||
.window-picker {
|
||||
-horizontal-spacing: 32px;
|
||||
-vertical-spacing: 32px;
|
||||
padding-left: 32px;
|
||||
padding-right: 32px;
|
||||
padding-bottom: 48px;
|
||||
}
|
||||
|
||||
.window-picker.external-monitor {
|
||||
padding: 32px;
|
||||
}
|
||||
|
||||
.messages-indicator {
|
||||
color: #999999;
|
||||
height: 32px;
|
||||
}
|
||||
|
||||
.messages-indicator-contents {
|
||||
spacing: 12px;
|
||||
padding-bottom: 12px;
|
||||
}
|
||||
|
||||
.messages-indicator-contents:hover {
|
||||
color: white;
|
||||
text-shadow: black 0px 2px 2px;
|
||||
}
|
||||
|
||||
.messages-indicator-highlight {
|
||||
background-gradient-start: transparent;
|
||||
background-gradient-end: #999999;
|
||||
background-gradient-direction: vertical;
|
||||
|
||||
height: 6px;
|
||||
}
|
||||
|
||||
/* Dash */
|
||||
@ -788,9 +742,14 @@ StScrollBar StButton#vhandle:active {
|
||||
height: 24px;
|
||||
}
|
||||
|
||||
#viewSelector {
|
||||
spacing: 1em;
|
||||
}
|
||||
|
||||
/* Search Box */
|
||||
|
||||
#searchEntry {
|
||||
border-radius: 17px;
|
||||
width: 320px;
|
||||
}
|
||||
|
||||
@ -807,20 +766,20 @@ StScrollBar StButton#vhandle:active {
|
||||
/* Search Results */
|
||||
|
||||
#searchResults {
|
||||
padding: 20px 10px 0px 10px;
|
||||
padding: 20px 10px 10px 10px;
|
||||
spacing: 18px;
|
||||
}
|
||||
|
||||
#searchResultsBin {
|
||||
max-width: 1000px;
|
||||
}
|
||||
|
||||
#searchResultsContent {
|
||||
padding-left: 20px;
|
||||
padding-right: 20px;
|
||||
spacing: 16px;
|
||||
}
|
||||
|
||||
#searchResultsContent:rtl {
|
||||
padding-right: 0px;
|
||||
padding-left: 20px;
|
||||
}
|
||||
|
||||
.search-section {
|
||||
/* This should be equal to #searchResultsContent spacing */
|
||||
spacing: 16px;
|
||||
@ -849,6 +808,24 @@ StScrollBar StButton#vhandle:active {
|
||||
spacing: 3px;
|
||||
}
|
||||
|
||||
/* Text labels are an odd number of pixels tall. The uneven top and bottom
|
||||
* padding compensates for this and ensures that the label is vertically
|
||||
* centered */
|
||||
.dash-search-button {
|
||||
border-radius: 16px;
|
||||
padding-top: 4px;
|
||||
padding-bottom: 5px;
|
||||
width: 300px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.dash-search-button:focus,
|
||||
.dash-search-button:selected {
|
||||
padding-top: 3px;
|
||||
padding-bottom: 4px;
|
||||
width: 298px;
|
||||
}
|
||||
|
||||
.dash-label {
|
||||
border-radius: 7px;
|
||||
padding: 4px 12px;
|
||||
@ -869,29 +846,40 @@ StScrollBar StButton#vhandle:active {
|
||||
icon-size: 96px;
|
||||
}
|
||||
|
||||
.app-display {
|
||||
padding: 8px;
|
||||
.all-app {
|
||||
padding: 16px 25px 16px 16px;
|
||||
spacing: 20px;
|
||||
}
|
||||
|
||||
.app-view-controls {
|
||||
width: 250px;
|
||||
padding-bottom: 32px;
|
||||
.all-app:rtl {
|
||||
padding-right: 16px;
|
||||
padding-left: 25px;
|
||||
}
|
||||
|
||||
.app-view-control {
|
||||
padding: 4px 16px;
|
||||
.app-filter {
|
||||
font-weight: bold;
|
||||
height: 2.85em;
|
||||
color: #aaa;
|
||||
width: 200px;
|
||||
}
|
||||
|
||||
.search-display > StBoxLayout,
|
||||
.all-apps > StBoxLayout,
|
||||
.frequent-apps > StBoxLayout {
|
||||
/* horizontal padding to make sure the scrollbar doesn't overlap content */
|
||||
padding: 0px 18px;
|
||||
.app-filter:hover {
|
||||
color: #eee;
|
||||
}
|
||||
|
||||
.app-folder-icon {
|
||||
padding: 5px;
|
||||
.app-filter:selected {
|
||||
color: #ffffff;
|
||||
background-image: url("filter-selected-ltr.svg");
|
||||
background-position: 190px 10px;
|
||||
}
|
||||
|
||||
.app-filter:selected:rtl {
|
||||
background-image: url("filter-selected-rtl.svg");
|
||||
background-position: 10px 10px;
|
||||
}
|
||||
|
||||
.app-filter:focus {
|
||||
outline: 1px solid #aaa;
|
||||
}
|
||||
|
||||
.dash-item-container > StButton {
|
||||
@ -910,6 +898,8 @@ StScrollBar StButton#vhandle:active {
|
||||
}
|
||||
|
||||
.list-search-result-description {
|
||||
font-weight: bold;
|
||||
font-size: 12pt;
|
||||
color: #eeeeec;
|
||||
}
|
||||
|
||||
@ -927,31 +917,16 @@ StScrollBar StButton#vhandle:active {
|
||||
border-radius: 4px;
|
||||
padding: 3px;
|
||||
border: 1px rgba(0,0,0,0);
|
||||
transition-duration: 100ms;
|
||||
transition-duration: 100;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.app-folder-popup {
|
||||
-arrow-border-radius: 8px;
|
||||
-arrow-background-color: black;
|
||||
-arrow-base: 24px;
|
||||
-arrow-rise: 11px;
|
||||
}
|
||||
|
||||
.app-folder-popup-bin {
|
||||
padding: 15px;
|
||||
}
|
||||
|
||||
.app-well-app.running > .overview-icon {
|
||||
text-shadow: black 0px 2px 2px;
|
||||
background-image: url("running-indicator.svg");
|
||||
background-size: contain;
|
||||
}
|
||||
|
||||
.app-well-app.app-folder > .overview-icon {
|
||||
background-color: rgba(0,0,0,0.5);
|
||||
}
|
||||
|
||||
.app-well-app:hover > .overview-icon,
|
||||
.show-apps:hover > .overview-icon,
|
||||
.search-provider-icon:hover,
|
||||
@ -959,14 +934,10 @@ StScrollBar StButton#vhandle:active {
|
||||
.grid-search-result:hover .overview-icon {
|
||||
background-color: rgba(255,255,255,0.1);
|
||||
text-shadow: black 0px 2px 2px;
|
||||
transition-duration: 100ms;
|
||||
transition-duration: 100;
|
||||
color:white;
|
||||
}
|
||||
|
||||
.list-search-result:hover .list-search-result-description {
|
||||
text-shadow: rgba(0,0,0,0.8) 0px 1px 2px;
|
||||
}
|
||||
|
||||
.show-apps {
|
||||
padding: 4px 0;
|
||||
}
|
||||
@ -979,22 +950,19 @@ StScrollBar StButton#vhandle:active {
|
||||
color: white;
|
||||
}
|
||||
|
||||
.app-well-app:checked > .overview-icon,
|
||||
.app-well-app:active > .overview-icon,
|
||||
.show-apps:checked > .overview-icon,
|
||||
.show-apps:active > .overview-icon {
|
||||
.show-apps:checked > .overview-icon {
|
||||
background-gradient-start: rgba(255, 255, 255, .05);
|
||||
background-gradient-end: rgba(255, 255, 255, .15);
|
||||
background-gradient-direction: vertical;
|
||||
border-radius: 4px;
|
||||
box-shadow: inset 0px 1px 2px 0px rgba(0, 0, 0, 1);
|
||||
transition-duration: 100ms;
|
||||
transition-duration: 100;
|
||||
}
|
||||
|
||||
.show-apps:checked .show-apps-icon,
|
||||
.show-apps:focus .show-apps-icon {
|
||||
color: white;
|
||||
transition-duration: 100ms;
|
||||
transition-duration: 100;
|
||||
}
|
||||
|
||||
.app-well-app:focus > .overview-icon,
|
||||
@ -1033,7 +1001,7 @@ StScrollBar StButton#vhandle:active {
|
||||
-minimum-hpadding: 6px;
|
||||
font-weight: bold;
|
||||
color: #ccc;
|
||||
transition-duration: 100ms;
|
||||
transition-duration: 100;
|
||||
padding-left: .3em;
|
||||
padding-right: .3em;
|
||||
}
|
||||
@ -1336,7 +1304,17 @@ StScrollBar StButton#vhandle:active {
|
||||
#message-tray {
|
||||
background: #2e3436 url(message-tray-background.png);
|
||||
background-repeat: repeat;
|
||||
height: 72px;
|
||||
transition-duration: 250;
|
||||
}
|
||||
|
||||
#message-tray:keyboard {
|
||||
/* Same as the OSK */
|
||||
background: rgba(0, 0, 0, 0.8);
|
||||
}
|
||||
|
||||
#message-tray:overview {
|
||||
background: rgba(0, 0, 0, 0.1);
|
||||
outline: 1px solid rgba(128, 128, 128, 0.3);
|
||||
}
|
||||
|
||||
.message-tray-summary {
|
||||
@ -1353,7 +1331,7 @@ StScrollBar StButton#vhandle:active {
|
||||
border-radius: 10px 10px 0px 0px;
|
||||
background: rgba(0,0,0,0.9);
|
||||
padding: 8px 8px 4px 8px;
|
||||
spacing-rows: 4px;
|
||||
spacing-rows: 10px;
|
||||
spacing-columns: 10px;
|
||||
}
|
||||
|
||||
@ -1433,11 +1411,11 @@ StScrollBar StButton#vhandle:active {
|
||||
}
|
||||
|
||||
.notification-actions {
|
||||
padding-top: 18px;
|
||||
spacing: 10px;
|
||||
}
|
||||
|
||||
.notification-button {
|
||||
border-radius: 18px;
|
||||
padding: 4px 42px 5px;
|
||||
}
|
||||
|
||||
@ -1470,6 +1448,7 @@ StScrollBar StButton#vhandle:active {
|
||||
|
||||
.hotplug-notification-item {
|
||||
padding: 2px 10px;
|
||||
border-radius: 18px;
|
||||
}
|
||||
|
||||
.hotplug-notification-item:focus {
|
||||
@ -1594,7 +1573,7 @@ StScrollBar StButton#vhandle:active {
|
||||
.summary-source {
|
||||
border-radius: 4px;
|
||||
padding: 0 6px 0 6px;
|
||||
transition-duration: 100ms;
|
||||
transition-duration: 100;
|
||||
}
|
||||
|
||||
.summary-source-counter {
|
||||
@ -1608,26 +1587,12 @@ StScrollBar StButton#vhandle:active {
|
||||
-shell-counter-overlap-y: 13px;
|
||||
}
|
||||
|
||||
/* OSD */
|
||||
.osd-window {
|
||||
text-align: center;
|
||||
font-weight: bold;
|
||||
spacing: 1em;
|
||||
}
|
||||
|
||||
.osd-window .level {
|
||||
height: 0.6em;
|
||||
border-radius: 0.3em;
|
||||
background-color: rgba(190,190,190,0.2);
|
||||
}
|
||||
|
||||
/* App Switcher */
|
||||
.switcher-popup {
|
||||
padding: 8px;
|
||||
spacing: 16px;
|
||||
}
|
||||
|
||||
.osd-window,
|
||||
.switcher-list {
|
||||
background: rgba(0,0,0,0.8);
|
||||
border: 1px solid rgba(128,128,128,0.40);
|
||||
@ -1779,6 +1744,8 @@ StScrollBar StButton#vhandle:active {
|
||||
}
|
||||
|
||||
.modal-dialog-button {
|
||||
border-radius: 18px;
|
||||
|
||||
margin-left: 10px;
|
||||
margin-right: 10px;
|
||||
padding: 4px 32px 5px;
|
||||
@ -2129,64 +2096,17 @@ StScrollBar StButton#vhandle:active {
|
||||
}
|
||||
|
||||
/* IBus Candidate Popup */
|
||||
.candidate-popup-boxpointer {
|
||||
-arrow-border-radius: 8px;
|
||||
-arrow-background-color: #707070;
|
||||
-arrow-border-width: 0px;
|
||||
-arrow-base: 24px;
|
||||
-arrow-rise: 11px;
|
||||
}
|
||||
|
||||
.candidate-popup-content {
|
||||
padding: 0.5em;
|
||||
spacing: 0.3em;
|
||||
}
|
||||
|
||||
.candidate-popup-text {
|
||||
font-size: 9pt;
|
||||
}
|
||||
|
||||
.candidate-index {
|
||||
padding: 0 0.5em 0 0;
|
||||
color: #cccccc;
|
||||
padding: 0.5em 0.5em 0.5em 0.5em;
|
||||
}
|
||||
|
||||
.candidate-box {
|
||||
padding: 0.3em 0.5em 0.3em 0.5em;
|
||||
.candidate-label {
|
||||
padding: 0.5em 0.5em 0.5em 0.5em;
|
||||
}
|
||||
|
||||
.candidate-box:selected {
|
||||
.candidate-label:selected {
|
||||
border-radius: 4px;
|
||||
background-color: rgba(255,255,255,0.2);
|
||||
}
|
||||
|
||||
.candidate-box:hover {
|
||||
border-radius: 4px;
|
||||
background-color: rgba(255,255,255,0.1);
|
||||
}
|
||||
.candidate-page-button-box {
|
||||
height: 2em;
|
||||
width: 80px;
|
||||
}
|
||||
|
||||
.vertical .candidate-page-button-box {
|
||||
padding-top: 0.5em;
|
||||
}
|
||||
|
||||
.horizontal .candidate-page-button-box {
|
||||
padding-left: 0.5em;
|
||||
}
|
||||
|
||||
.candidate-page-button-previous {
|
||||
border-radius: 4px 0px 0px 4px;
|
||||
}
|
||||
|
||||
.candidate-page-button-next {
|
||||
border-radius: 0px 4px 4px 0px;
|
||||
}
|
||||
|
||||
.candidate-page-button-icon {
|
||||
icon-size: 1em;
|
||||
background-color: rgba(255,255,255,0.33);
|
||||
}
|
||||
|
||||
/* Login Dialog */
|
||||
@ -2422,18 +2342,10 @@ StScrollBar StButton#vhandle:active {
|
||||
color: orange;
|
||||
}
|
||||
|
||||
.user-widget {
|
||||
.unlock-dialog-user-name-container {
|
||||
spacing: .4em;
|
||||
}
|
||||
|
||||
.user-widget-label {
|
||||
font-size: 16pt;
|
||||
font-weight: bold;
|
||||
text-align: left;
|
||||
padding-left: 15px;
|
||||
text-shadow: black 0px 4px 3px 0px;
|
||||
}
|
||||
|
||||
/* Screen shield */
|
||||
|
||||
.screen-shield-background {
|
||||
@ -2490,7 +2402,6 @@ StScrollBar StButton#vhandle:active {
|
||||
|
||||
.screen-shield-notifications-box {
|
||||
spacing: 18px;
|
||||
max-width: 34em;
|
||||
}
|
||||
|
||||
.screen-shield-notification-source {
|
||||
@ -2525,13 +2436,7 @@ StScrollBar StButton#vhandle:active {
|
||||
}
|
||||
|
||||
.input-source-switcher-symbol {
|
||||
font-size: 34pt;
|
||||
font-size: 42pt;
|
||||
width: 96px;
|
||||
height: 96px;
|
||||
}
|
||||
|
||||
/* Background menu */
|
||||
|
||||
.background-menu {
|
||||
-boxpointer-gap: 4px;
|
||||
}
|
||||
|
@ -88,18 +88,11 @@ doc-gen-org.gnome.Shell.SearchProvider2.xml: $(top_srcdir)/data/org.gnome.ShellS
|
||||
--generate-docbook doc-gen \
|
||||
$(top_srcdir)/data/org.gnome.ShellSearchProvider2.xml
|
||||
|
||||
doc-gen-org.gnome.Shell.Screenshot.xml: $(top_srcdir)/data/org.gnome.Shell.Screenshot.xml
|
||||
gdbus-codegen \
|
||||
--interface-prefix org.gnome.Shell.Screenshot. \
|
||||
--generate-docbook doc-gen \
|
||||
$(top_srcdir)/data/org.gnome.Shell.Screenshot.xml
|
||||
|
||||
# Extra SGML files that are included by $(DOC_MAIN_SGML_FILE).
|
||||
# e.g. content_files=running.sgml building.sgml changes-2.0.sgml
|
||||
content_files= \
|
||||
doc-gen-org.gnome.Shell.SearchProvider.xml \
|
||||
doc-gen-org.gnome.Shell.SearchProvider2.xml \
|
||||
doc-gen-org.gnome.Shell.Screenshot.xml
|
||||
doc-gen-org.gnome.Shell.SearchProvider2.xml
|
||||
|
||||
# SGML files where gtk-doc abbrevations (#GtkWidget) are expanded
|
||||
# These files must be listed here *and* in content_files
|
||||
|
@ -50,6 +50,7 @@
|
||||
<xi:include href="xml/shell-xfixes-cursor.xml"/>
|
||||
<xi:include href="xml/shell-util.xml"/>
|
||||
<xi:include href="xml/shell-mount-operation.xml"/>
|
||||
<xi:include href="xml/shell-mobile-providers.xml"/>
|
||||
<xi:include href="xml/shell-network-agent.xml"/>
|
||||
<xi:include href="xml/shell-polkit-authentication-agent.xml"/>
|
||||
<xi:include href="xml/shell-tp-client.xml"/>
|
||||
|
@ -66,11 +66,4 @@ its dependencies to build from tarballs.</description>
|
||||
<gnome:userid>fmuellner</gnome:userid>
|
||||
</foaf:Person>
|
||||
</maintainer>
|
||||
<maintainer>
|
||||
<foaf:Person>
|
||||
<foaf:name>Ray Strode</foaf:name>
|
||||
<foaf:mbox rdf:resource="mailto:halfline@gmail.com" />
|
||||
<gnome:userid>halfline</gnome:userid>
|
||||
</foaf:Person>
|
||||
</maintainer>
|
||||
</Project>
|
||||
|
@ -28,7 +28,6 @@ nobase_dist_js_DATA = \
|
||||
misc/extensionUtils.js \
|
||||
misc/fileUtils.js \
|
||||
misc/gnomeSession.js \
|
||||
misc/hash.js \
|
||||
misc/history.js \
|
||||
misc/jsParse.js \
|
||||
misc/loginManager.js \
|
||||
@ -39,8 +38,6 @@ nobase_dist_js_DATA = \
|
||||
ui/altTab.js \
|
||||
ui/appDisplay.js \
|
||||
ui/appFavorites.js \
|
||||
ui/backgroundMenu.js \
|
||||
ui/background.js \
|
||||
ui/boxpointer.js \
|
||||
ui/calendar.js \
|
||||
ui/checkBox.js \
|
||||
@ -52,6 +49,7 @@ nobase_dist_js_DATA = \
|
||||
ui/extensionSystem.js \
|
||||
ui/extensionDownloader.js \
|
||||
ui/environment.js \
|
||||
ui/flashspot.js \
|
||||
ui/ibusCandidatePopup.js\
|
||||
ui/grabHelper.js \
|
||||
ui/iconGrid.js \
|
||||
@ -69,16 +67,13 @@ nobase_dist_js_DATA = \
|
||||
ui/shellEntry.js \
|
||||
ui/shellMountOperation.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/runDialog.js \
|
||||
ui/screenshot.js \
|
||||
ui/screenShield.js \
|
||||
ui/scripting.js \
|
||||
ui/search.js \
|
||||
@ -95,7 +90,6 @@ nobase_dist_js_DATA = \
|
||||
ui/tweener.js \
|
||||
ui/unlockDialog.js \
|
||||
ui/userMenu.js \
|
||||
ui/userWidget.js \
|
||||
ui/viewSelector.js \
|
||||
ui/wanda.js \
|
||||
ui/windowAttentionHandler.js \
|
||||
|
@ -45,7 +45,6 @@ const Application = new Lang.Class({
|
||||
this._extensionPrefsModules = {};
|
||||
|
||||
this._extensionIters = {};
|
||||
this._startupUuid = null;
|
||||
},
|
||||
|
||||
_buildModel: function() {
|
||||
@ -204,7 +203,6 @@ 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();
|
||||
},
|
||||
|
||||
@ -214,11 +212,6 @@ const Application = new Lang.Class({
|
||||
this._extensionIters[extension.uuid] = iter;
|
||||
},
|
||||
|
||||
_extensionsLoaded: function() {
|
||||
if (this._startupUuid && this._extensionAvailable(this._startupUuid))
|
||||
this._selectExtension(this._startupUuid);
|
||||
this._startupUuid = null;
|
||||
},
|
||||
|
||||
_onActivate: function() {
|
||||
this._window.present();
|
||||
@ -239,10 +232,10 @@ const Application = new Lang.Class({
|
||||
// Strip off "extension:///" prefix which fakes a URI, if it exists
|
||||
uuid = stripPrefix(uuid, "extension:///");
|
||||
|
||||
if (this._extensionAvailable(uuid))
|
||||
if (!this._extensionAvailable(uuid))
|
||||
return 1;
|
||||
|
||||
this._selectExtension(uuid);
|
||||
else
|
||||
this._startupUuid = uuid;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -43,9 +43,8 @@ const Panel = imports.ui.panel;
|
||||
const PanelMenu = imports.ui.panelMenu;
|
||||
const Tweener = imports.ui.tweener;
|
||||
const UserMenu = imports.ui.userMenu;
|
||||
const UserWidget = imports.ui.userWidget;
|
||||
|
||||
const _FADE_ANIMATION_TIME = 0.25;
|
||||
const _RESIZE_ANIMATION_TIME = 0.25;
|
||||
const _SCROLL_ANIMATION_TIME = 0.5;
|
||||
const _TIMED_LOGIN_IDLE_THRESHOLD = 5.0;
|
||||
const _LOGO_ICON_HEIGHT = 16;
|
||||
@ -56,6 +55,39 @@ const WORK_SPINNER_ANIMATION_TIME = 0.3;
|
||||
|
||||
let _loginDialog = null;
|
||||
|
||||
function _smoothlyResizeActor(actor, width, height) {
|
||||
let finalWidth;
|
||||
let finalHeight;
|
||||
|
||||
if (width < 0)
|
||||
finalWidth = actor.width;
|
||||
else
|
||||
finalWidth = width;
|
||||
|
||||
if (height < 0)
|
||||
finalHeight = actor.height;
|
||||
else
|
||||
finalHeight = height;
|
||||
|
||||
actor.set_size(actor.width, actor.height);
|
||||
|
||||
if (actor.width == finalWidth && actor.height == finalHeight)
|
||||
return null;
|
||||
|
||||
let hold = new Batch.Hold();
|
||||
|
||||
Tweener.addTween(actor,
|
||||
{ width: finalWidth,
|
||||
height: finalHeight,
|
||||
time: _RESIZE_ANIMATION_TIME,
|
||||
transition: 'easeOutQuad',
|
||||
onComplete: Lang.bind(this, function() {
|
||||
hold.release();
|
||||
})
|
||||
});
|
||||
return hold;
|
||||
}
|
||||
|
||||
const LogoMenuButton = new Lang.Class({
|
||||
Name: 'LogoMenuButton',
|
||||
Extends: PanelMenu.Button,
|
||||
@ -96,7 +128,6 @@ const UserListItem = new Lang.Class({
|
||||
|
||||
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,
|
||||
child: layout,
|
||||
reactive: true,
|
||||
@ -214,23 +245,155 @@ const UserList = new Lang.Class({
|
||||
}
|
||||
},
|
||||
|
||||
_showItem: function(item) {
|
||||
let tasks = [function() {
|
||||
return GdmUtil.fadeInActor(item.actor);
|
||||
}];
|
||||
|
||||
let batch = new Batch.ConsecutiveBatch(this, tasks);
|
||||
return batch.run();
|
||||
},
|
||||
|
||||
_onItemActivated: function(activatedItem) {
|
||||
this.emit('activate', activatedItem);
|
||||
},
|
||||
|
||||
updateStyle: function(isExpanded) {
|
||||
giveUpWhitespace: function() {
|
||||
let container = this.actor.get_parent();
|
||||
|
||||
container.child_set(this.actor, { expand: false });
|
||||
},
|
||||
|
||||
takeOverWhitespace: function() {
|
||||
let container = this.actor.get_parent();
|
||||
|
||||
container.child_set(this.actor, { expand: true });
|
||||
},
|
||||
|
||||
pinInPlace: function() {
|
||||
this._box.set_size(this._box.width, this._box.height);
|
||||
},
|
||||
|
||||
shrinkToNaturalHeight: function() {
|
||||
let oldWidth = this._box.width;
|
||||
let oldHeight = this._box.height;
|
||||
this._box.set_size(-1, -1);
|
||||
let [minHeight, naturalHeight] = this._box.get_preferred_height(-1);
|
||||
this._box.set_size(oldWidth, oldHeight);
|
||||
|
||||
let batch = new Batch.ConsecutiveBatch(this,
|
||||
[function() {
|
||||
return _smoothlyResizeActor(this._box, -1, naturalHeight);
|
||||
},
|
||||
|
||||
function() {
|
||||
this._box.set_size(-1, -1);
|
||||
}
|
||||
]);
|
||||
|
||||
return batch.run();
|
||||
},
|
||||
|
||||
hideItemsExcept: function(exception) {
|
||||
let tasks = [];
|
||||
|
||||
if (isExpanded)
|
||||
this._box.add_style_pseudo_class('expanded');
|
||||
else
|
||||
for (let userName in this._items) {
|
||||
let item = this._items[userName];
|
||||
|
||||
item.actor.set_hover(false);
|
||||
item.actor.reactive = false;
|
||||
item.actor.can_focus = false;
|
||||
item.syncStyleClasses();
|
||||
item._timedLoginIndicator.scale_x = 0.;
|
||||
if (item != exception)
|
||||
tasks.push(function() {
|
||||
return GdmUtil.fadeOutActor(item.actor);
|
||||
});
|
||||
}
|
||||
|
||||
let batch = new Batch.ConsecutiveBatch(this,
|
||||
[function() {
|
||||
return GdmUtil.fadeOutActor(this.actor.vscroll);
|
||||
},
|
||||
|
||||
new Batch.ConcurrentBatch(this, tasks),
|
||||
|
||||
function() {
|
||||
this._box.remove_style_pseudo_class('expanded');
|
||||
}
|
||||
]);
|
||||
|
||||
return batch.run();
|
||||
},
|
||||
|
||||
hideItems: function() {
|
||||
return this.hideItemsExcept(null);
|
||||
},
|
||||
|
||||
_getExpandedHeight: function() {
|
||||
let hiddenActors = [];
|
||||
for (let userName in this._items) {
|
||||
let item = this._items[userName];
|
||||
if (!item.actor.visible) {
|
||||
item.actor.show();
|
||||
hiddenActors.push(item.actor);
|
||||
}
|
||||
}
|
||||
|
||||
if (!this._box.visible) {
|
||||
this._box.show();
|
||||
hiddenActors.push(this._box);
|
||||
}
|
||||
|
||||
this._box.set_size(-1, -1);
|
||||
let [minHeight, naturalHeight] = this._box.get_preferred_height(-1);
|
||||
|
||||
for (let i = 0; i < hiddenActors.length; i++) {
|
||||
let actor = hiddenActors[i];
|
||||
actor.hide();
|
||||
}
|
||||
|
||||
return naturalHeight;
|
||||
},
|
||||
|
||||
showItems: function() {
|
||||
let tasks = [];
|
||||
|
||||
for (let userName in this._items) {
|
||||
let item = this._items[userName];
|
||||
item.actor.sync_hover();
|
||||
item.actor.reactive = true;
|
||||
item.actor.can_focus = true;
|
||||
item.syncStyleClasses();
|
||||
tasks.push(function() {
|
||||
return this._showItem(item);
|
||||
});
|
||||
}
|
||||
|
||||
let batch = new Batch.ConsecutiveBatch(this,
|
||||
[function() {
|
||||
this.takeOverWhitespace();
|
||||
},
|
||||
|
||||
function() {
|
||||
let fullHeight = this._getExpandedHeight();
|
||||
return _smoothlyResizeActor(this._box, -1, fullHeight);
|
||||
},
|
||||
|
||||
function() {
|
||||
this._box.add_style_pseudo_class('expanded');
|
||||
},
|
||||
|
||||
new Batch.ConcurrentBatch(this, tasks),
|
||||
|
||||
function() {
|
||||
this.actor.set_size(-1, -1);
|
||||
},
|
||||
|
||||
function() {
|
||||
return GdmUtil.fadeInActor(this.actor.vscroll);
|
||||
}]);
|
||||
return batch.run();
|
||||
},
|
||||
|
||||
scrollToItem: function(item) {
|
||||
@ -329,7 +492,6 @@ const SessionListItem = new Lang.Class({
|
||||
this.id = id;
|
||||
|
||||
this.actor = new St.Button({ style_class: 'login-dialog-session-list-item',
|
||||
button_mask: St.ButtonMask.ONE | St.ButtonMask.THREE,
|
||||
can_focus: true,
|
||||
reactive: true,
|
||||
x_fill: true,
|
||||
@ -370,7 +532,6 @@ const SessionListItem = new Lang.Class({
|
||||
color.alpha / 255);
|
||||
cr.arc(width / 2, height / 2, width / 3, 0, 2 * Math.PI);
|
||||
cr.fill();
|
||||
cr.$dispose();
|
||||
},
|
||||
|
||||
_onClicked: function() {
|
||||
@ -390,7 +551,6 @@ const SessionList = new Lang.Class({
|
||||
this.actor.child = this._box;
|
||||
|
||||
this._button = new St.Button({ style_class: 'login-dialog-session-list-button',
|
||||
button_mask: St.ButtonMask.ONE | St.ButtonMask.THREE,
|
||||
can_focus: true,
|
||||
x_fill: true,
|
||||
y_fill: true });
|
||||
@ -402,7 +562,7 @@ const SessionList = new Lang.Class({
|
||||
box.add_actor(this._triangle);
|
||||
|
||||
let label = new St.Label({ style_class: 'login-dialog-session-list-label',
|
||||
text: _("Session…") });
|
||||
text: _("Session...") });
|
||||
box.add_actor(label);
|
||||
|
||||
this._button.connect('clicked',
|
||||
@ -513,7 +673,7 @@ const LoginDialog = new Lang.Class({
|
||||
this.parent({ shellReactive: true,
|
||||
styleClass: 'login-dialog',
|
||||
parentActor: parentActor,
|
||||
keybindingMode: Shell.KeyBindingMode.LOGIN_SCREEN,
|
||||
keybindingMode: Main.KeybindingMode.LOGIN_SCREEN,
|
||||
shouldFadeIn: false });
|
||||
this.connect('destroy',
|
||||
Lang.bind(this, this._onDestroy));
|
||||
@ -553,17 +713,21 @@ const LoginDialog = new Lang.Class({
|
||||
this._settings.connect('changed::' + GdmUtil.DISABLE_USER_LIST_KEY,
|
||||
Lang.bind(this, this._updateDisableUserList));
|
||||
|
||||
this._userSelectionBox = new St.BoxLayout({ style_class: 'login-dialog-user-selection-box',
|
||||
vertical: true });
|
||||
this.contentLayout.add(this._userSelectionBox);
|
||||
|
||||
this._bannerLabel = new St.Label({ style_class: 'login-dialog-banner',
|
||||
text: '' });
|
||||
this._userSelectionBox.add(this._bannerLabel);
|
||||
this.contentLayout.add(this._bannerLabel);
|
||||
this._updateBanner();
|
||||
|
||||
this._titleLabel = new St.Label({ style_class: 'login-dialog-title',
|
||||
text: C_("title", "Sign In"),
|
||||
visible: false });
|
||||
|
||||
this.contentLayout.add(this._titleLabel,
|
||||
{ y_fill: false,
|
||||
y_align: St.Align.START });
|
||||
|
||||
this._userList = new UserList();
|
||||
this._userSelectionBox.add(this._userList.actor,
|
||||
this.contentLayout.add(this._userList.actor,
|
||||
{ expand: true,
|
||||
x_fill: true,
|
||||
y_fill: true });
|
||||
@ -577,13 +741,6 @@ const LoginDialog = new Lang.Class({
|
||||
x_fill: true,
|
||||
y_fill: true,
|
||||
x_align: St.Align.START });
|
||||
this._promptUser = new St.Bin({ x_fill: true,
|
||||
x_align: St.Align.START });
|
||||
this._promptBox.add(this._promptUser,
|
||||
{ x_align: St.Align.START,
|
||||
x_fill: true,
|
||||
y_fill: true,
|
||||
expand: true });
|
||||
this._promptLabel = new St.Label({ style_class: 'login-dialog-prompt-label' });
|
||||
|
||||
this._promptBox.add(this._promptLabel,
|
||||
@ -629,7 +786,6 @@ const LoginDialog = new Lang.Class({
|
||||
let notListedLabel = new St.Label({ text: _("Not listed?"),
|
||||
style_class: 'login-dialog-not-listed-label' });
|
||||
this._notListedButton = new St.Button({ style_class: 'login-dialog-not-listed-button',
|
||||
button_mask: St.ButtonMask.ONE | St.ButtonMask.THREE,
|
||||
can_focus: true,
|
||||
child: notListedLabel,
|
||||
reactive: true,
|
||||
@ -638,7 +794,7 @@ const LoginDialog = new Lang.Class({
|
||||
|
||||
this._notListedButton.connect('clicked', Lang.bind(this, this._hideUserListAndLogIn));
|
||||
|
||||
this._userSelectionBox.add(this._notListedButton,
|
||||
this.contentLayout.add(this._notListedButton,
|
||||
{ expand: false,
|
||||
x_align: St.Align.START,
|
||||
x_fill: true });
|
||||
@ -683,9 +839,9 @@ const LoginDialog = new Lang.Class({
|
||||
|
||||
if (enabled && text) {
|
||||
this._bannerLabel.set_text(text);
|
||||
this._bannerLabel.show();
|
||||
this._fadeInBanner();
|
||||
} else {
|
||||
this._bannerLabel.hide();
|
||||
this._fadeOutBanner();
|
||||
}
|
||||
},
|
||||
|
||||
@ -716,50 +872,73 @@ const LoginDialog = new Lang.Class({
|
||||
if (message) {
|
||||
this._promptMessage.text = message;
|
||||
this._promptMessage.styleClass = styleClass;
|
||||
this._promptMessage.show();
|
||||
GdmUtil.fadeInActor(this._promptMessage);
|
||||
} else {
|
||||
this._promptMessage.hide();
|
||||
GdmUtil.fadeOutActor(this._promptMessage);
|
||||
}
|
||||
},
|
||||
|
||||
_showLoginHint: function(verifier, message) {
|
||||
this._promptLoginHint.set_text(message)
|
||||
this._promptLoginHint.show();
|
||||
this._promptLoginHint.opacity = 255;
|
||||
GdmUtil.fadeInActor(this._promptLoginHint);
|
||||
},
|
||||
|
||||
_hideLoginHint: function() {
|
||||
this._promptLoginHint.hide();
|
||||
GdmUtil.fadeOutActor(this._promptLoginHint);
|
||||
this._promptLoginHint.set_text('');
|
||||
},
|
||||
|
||||
cancel: function() {
|
||||
if (this._verifyingUser)
|
||||
this._userVerifier.cancel();
|
||||
else
|
||||
this._reset();
|
||||
},
|
||||
|
||||
_fadeInPrompt: function() {
|
||||
let tasks = [function() {
|
||||
return GdmUtil.fadeInActor(this._promptLabel);
|
||||
},
|
||||
|
||||
function() {
|
||||
return GdmUtil.fadeInActor(this._promptEntry);
|
||||
},
|
||||
|
||||
function() {
|
||||
// Show it with 0 opacity so we preallocate space for it
|
||||
// in the event we need to fade in the message
|
||||
this._promptLoginHint.opacity = 0;
|
||||
this._promptLoginHint.show();
|
||||
},
|
||||
|
||||
function() {
|
||||
return GdmUtil.fadeInActor(this._promptBox);
|
||||
},
|
||||
|
||||
function() {
|
||||
if (this._user && this._user.is_logged_in())
|
||||
return null;
|
||||
|
||||
if (!this._verifyingUser)
|
||||
return null;
|
||||
|
||||
return GdmUtil.fadeInActor(this._sessionList.actor);
|
||||
},
|
||||
|
||||
function() {
|
||||
this._promptEntry.grab_key_focus();
|
||||
}];
|
||||
|
||||
this._sessionList.actor.hide();
|
||||
let batch = new Batch.ConcurrentBatch(this, tasks);
|
||||
return batch.run();
|
||||
},
|
||||
|
||||
_showPrompt: function(forSecret) {
|
||||
this._sessionList.actor.hide();
|
||||
this._promptLabel.show();
|
||||
this._promptEntry.show();
|
||||
this._promptLoginHint.opacity = 0;
|
||||
this._promptLoginHint.show();
|
||||
this._promptBox.opacity = 0;
|
||||
this._promptBox.show();
|
||||
Tweener.addTween(this._promptBox,
|
||||
{ opacity: 255,
|
||||
time: _FADE_ANIMATION_TIME,
|
||||
transition: 'easeOutQuad' });
|
||||
|
||||
if ((this._user && !this._user.is_logged_in()) || this._verifyingUser)
|
||||
this._sessionList.actor.show();
|
||||
|
||||
this._promptEntry.grab_key_focus();
|
||||
|
||||
let hold = new Batch.Hold();
|
||||
|
||||
let tasks = [function() {
|
||||
return this._fadeInPrompt();
|
||||
},
|
||||
|
||||
function() {
|
||||
this._prepareDialog(forSecret, hold);
|
||||
},
|
||||
|
||||
@ -835,21 +1014,26 @@ const LoginDialog = new Lang.Class({
|
||||
this._promptEntryTextChangedId = 0;
|
||||
}
|
||||
|
||||
let tasks = [function() {
|
||||
this._setWorking(false);
|
||||
this._promptBox.hide();
|
||||
this._promptLoginHint.hide();
|
||||
|
||||
this._promptUser.set_child(null);
|
||||
return GdmUtil.fadeOutActor(this._promptBox);
|
||||
},
|
||||
|
||||
function() {
|
||||
this._promptLoginHint.hide();
|
||||
|
||||
this._updateSensitivity(true);
|
||||
this._promptEntry.set_text('');
|
||||
|
||||
this._sessionList.close();
|
||||
this._promptLoginHint.hide();
|
||||
|
||||
this.clearButtons();
|
||||
this._workSpinner = null;
|
||||
this._signInButton = null;
|
||||
}];
|
||||
|
||||
let batch = new Batch.ConsecutiveBatch(this, tasks);
|
||||
|
||||
return batch.run();
|
||||
},
|
||||
|
||||
_setWorking: function(working) {
|
||||
@ -871,7 +1055,6 @@ const LoginDialog = new Lang.Class({
|
||||
transition: 'linear',
|
||||
onCompleteScope: this,
|
||||
onComplete: function() {
|
||||
if (this._workSpinner)
|
||||
this._workSpinner.stop();
|
||||
}
|
||||
});
|
||||
@ -881,7 +1064,6 @@ const LoginDialog = new Lang.Class({
|
||||
_askQuestion: function(verifier, serviceName, question, passwordChar) {
|
||||
this._promptLabel.set_text(question);
|
||||
|
||||
this._updateSensitivity(true);
|
||||
this._promptEntry.set_text('');
|
||||
this._promptEntry.clutter_text.set_password_char(passwordChar);
|
||||
|
||||
@ -918,26 +1100,7 @@ const LoginDialog = new Lang.Class({
|
||||
},
|
||||
|
||||
_onSessionOpened: function(client, serviceName) {
|
||||
Tweener.addTween(this.dialogLayout,
|
||||
{ opacity: 0,
|
||||
time: _FADE_ANIMATION_TIME,
|
||||
transition: 'easeOutQuad',
|
||||
onUpdate: function() {
|
||||
let children = Main.layoutManager.uiGroup.get_children();
|
||||
|
||||
for (let i = 0; i < children.length; i++) {
|
||||
if (children[i] != Main.layoutManager.screenShieldGroup)
|
||||
children[i].opacity = this.dialogLayout.opacity;
|
||||
}
|
||||
},
|
||||
onUpdateScope: this,
|
||||
onComplete: function() {
|
||||
Mainloop.idle_add(Lang.bind(this, function() {
|
||||
this._greeter.call_start_session_when_ready_sync(serviceName, true, null);
|
||||
return false;
|
||||
}));
|
||||
},
|
||||
onCompleteScope: this });
|
||||
},
|
||||
|
||||
_waitForItemForUser: function(userName) {
|
||||
@ -1064,21 +1227,75 @@ const LoginDialog = new Lang.Class({
|
||||
}));
|
||||
},
|
||||
|
||||
_setUserListExpanded: function(expanded) {
|
||||
this._userList.updateStyle(expanded);
|
||||
this._userSelectionBox.visible = expanded;
|
||||
_hideUserListAndLogIn: function() {
|
||||
let tasks = [function() {
|
||||
return this._userList.hideItems();
|
||||
},
|
||||
|
||||
_hideUserListAndLogIn: function() {
|
||||
this._setUserListExpanded(false);
|
||||
GdmUtil.cloneAndFadeOutActor(this._userSelectionBox);
|
||||
this._askForUsernameAndLogIn();
|
||||
function() {
|
||||
return this._userList.giveUpWhitespace();
|
||||
},
|
||||
|
||||
function() {
|
||||
this._userList.actor.hide();
|
||||
},
|
||||
|
||||
new Batch.ConcurrentBatch(this, [this._fadeOutTitleLabel,
|
||||
this._fadeOutNotListedButton]),
|
||||
|
||||
function() {
|
||||
return this._askForUsernameAndLogIn();
|
||||
}];
|
||||
|
||||
let batch = new Batch.ConsecutiveBatch(this, tasks);
|
||||
batch.run();
|
||||
},
|
||||
|
||||
_showUserList: function() {
|
||||
this._hidePrompt();
|
||||
this._setUserListExpanded(true);
|
||||
let tasks = [this._hidePrompt,
|
||||
|
||||
new Batch.ConcurrentBatch(this, [this._fadeInTitleLabel,
|
||||
this._fadeInNotListedButton]),
|
||||
|
||||
function() {
|
||||
this._sessionList.close();
|
||||
this._promptLoginHint.hide();
|
||||
this._userList.actor.show();
|
||||
this._userList.actor.opacity = 255;
|
||||
return this._userList.showItems();
|
||||
},
|
||||
|
||||
function() {
|
||||
this._userList.actor.reactive = true;
|
||||
this._userList.actor.grab_key_focus();
|
||||
}];
|
||||
|
||||
let batch = new Batch.ConsecutiveBatch(this, tasks);
|
||||
batch.run();
|
||||
},
|
||||
|
||||
_fadeInBanner: function() {
|
||||
return GdmUtil.fadeInActor(this._bannerLabel);
|
||||
},
|
||||
|
||||
_fadeOutBanner: function() {
|
||||
return GdmUtil.fadeOutActor(this._bannerLabel);
|
||||
},
|
||||
|
||||
_fadeInTitleLabel: function() {
|
||||
return GdmUtil.fadeInActor(this._titleLabel);
|
||||
},
|
||||
|
||||
_fadeOutTitleLabel: function() {
|
||||
return GdmUtil.fadeOutActor(this._titleLabel);
|
||||
},
|
||||
|
||||
_fadeInNotListedButton: function() {
|
||||
return GdmUtil.fadeInActor(this._notListedButton);
|
||||
},
|
||||
|
||||
_fadeOutNotListedButton: function() {
|
||||
return GdmUtil.fadeOutActor(this._notListedButton);
|
||||
},
|
||||
|
||||
_beginVerificationForUser: function(userName) {
|
||||
@ -1089,30 +1306,38 @@ const LoginDialog = new Lang.Class({
|
||||
return hold;
|
||||
},
|
||||
|
||||
_beginVerificationForItem: function(item) {
|
||||
let userWidget = new UserWidget.UserWidget(item.user);
|
||||
this._promptUser.set_child(userWidget.actor);
|
||||
|
||||
let tasks = [function() {
|
||||
let userName = item.user.get_user_name();
|
||||
return this._beginVerificationForUser(userName);
|
||||
}];
|
||||
let batch = new Batch.ConsecutiveBatch(this, tasks);
|
||||
return batch.run();
|
||||
},
|
||||
|
||||
_onUserListActivated: function(activatedItem) {
|
||||
let userName;
|
||||
|
||||
let tasks = [function() {
|
||||
return GdmUtil.cloneAndFadeOutActor(this._userSelectionBox);
|
||||
this._userList.actor.reactive = false;
|
||||
return this._userList.pinInPlace();
|
||||
},
|
||||
|
||||
function() {
|
||||
this._setUserListExpanded(false);
|
||||
return this._userList.hideItemsExcept(activatedItem);
|
||||
},
|
||||
|
||||
function() {
|
||||
return this._userList.giveUpWhitespace();
|
||||
},
|
||||
|
||||
new Batch.ConcurrentBatch(this, [this._fadeOutTitleLabel,
|
||||
this._fadeOutNotListedButton]),
|
||||
|
||||
function() {
|
||||
return this._userList.shrinkToNaturalHeight();
|
||||
},
|
||||
|
||||
function() {
|
||||
userName = activatedItem.user.get_user_name();
|
||||
|
||||
return this._beginVerificationForUser(userName);
|
||||
}];
|
||||
|
||||
this._user = activatedItem.user;
|
||||
|
||||
let batch = new Batch.ConcurrentBatch(this, [new Batch.ConsecutiveBatch(this, tasks),
|
||||
this._beginVerificationForItem(activatedItem)]);
|
||||
let batch = new Batch.ConsecutiveBatch(this, tasks);
|
||||
batch.run();
|
||||
},
|
||||
|
||||
|
@ -1,6 +1,5 @@
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
|
||||
const Clutter = imports.gi.Clutter;
|
||||
const Gio = imports.gi.Gio;
|
||||
const Lang = imports.lang;
|
||||
const Mainloop = imports.mainloop;
|
||||
@ -16,7 +15,6 @@ const Tweener = imports.ui.tweener;
|
||||
const PASSWORD_SERVICE_NAME = 'gdm-password';
|
||||
const FINGERPRINT_SERVICE_NAME = 'gdm-fingerprint';
|
||||
const FADE_ANIMATION_TIME = 0.16;
|
||||
const CLONE_FADE_ANIMATION_TIME = 0.25;
|
||||
|
||||
const LOGIN_SCREEN_SCHEMA = 'org.gnome.login-screen';
|
||||
const FINGERPRINT_AUTHENTICATION_KEY = 'enable-fingerprint-authentication';
|
||||
@ -73,34 +71,6 @@ function fadeOutActor(actor) {
|
||||
return hold;
|
||||
}
|
||||
|
||||
function cloneAndFadeOutActor(actor) {
|
||||
// Immediately hide actor so its sibling can have its space
|
||||
// and position, but leave a non-reactive clone on-screen,
|
||||
// so from the user's point of view it smoothly fades away
|
||||
// and reveals its sibling.
|
||||
actor.hide();
|
||||
|
||||
let clone = new Clutter.Clone({ source: actor,
|
||||
reactive: false });
|
||||
|
||||
Main.uiGroup.add_child(clone);
|
||||
|
||||
let [x, y] = actor.get_transformed_position();
|
||||
clone.set_position(x, y);
|
||||
|
||||
let hold = new Batch.Hold();
|
||||
Tweener.addTween(clone,
|
||||
{ opacity: 0,
|
||||
time: CLONE_FADE_ANIMATION_TIME,
|
||||
transition: 'easeOutQuad',
|
||||
onComplete: function() {
|
||||
clone.destroy();
|
||||
hold.release();
|
||||
}
|
||||
});
|
||||
return hold;
|
||||
}
|
||||
|
||||
const ShellUserVerifier = new Lang.Class({
|
||||
Name: 'ShellUserVerifier',
|
||||
|
||||
|
@ -174,15 +174,10 @@ 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.collectFromDatadirsAsync('extensions',
|
||||
{ processFile: Lang.bind(this, this._loadExtension),
|
||||
loadedCallback: Lang.bind(this, this._extensionsLoaded),
|
||||
includeUserDir: true,
|
||||
data: perUserDir });
|
||||
}
|
||||
|
@ -58,7 +58,6 @@ const SessionManagerIface = <interface name="org.gnome.SessionManager">
|
||||
<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>
|
||||
|
141
js/misc/hash.js
141
js/misc/hash.js
@ -1,141 +0,0 @@
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
|
||||
const Lang = imports.lang;
|
||||
const System = imports.system;
|
||||
|
||||
const Params = imports.misc.params;
|
||||
|
||||
// This is an implementation of EcmaScript SameValue algorithm,
|
||||
// which returns true if two values are not observably distinguishable.
|
||||
// It was taken from http://wiki.ecmascript.org/doku.php?id=harmony:egal
|
||||
//
|
||||
// In the future, we may want to use the 'is' operator instead.
|
||||
function _sameValue(x, y) {
|
||||
if (x === y) {
|
||||
// 0 === -0, but they are not identical
|
||||
return x !== 0 || 1 / x === 1 / y;
|
||||
}
|
||||
|
||||
// NaN !== NaN, but they are identical.
|
||||
// NaNs are the only non-reflexive value, i.e., if x !== x,
|
||||
// then x is a NaN.
|
||||
// isNaN is broken: it converts its argument to number, so
|
||||
// isNaN("foo") => true
|
||||
return x !== x && y !== y;
|
||||
}
|
||||
|
||||
const _hashers = {
|
||||
object: function(o) { return o ? System.addressOf(o) : 'null'; },
|
||||
function: function(f) { return System.addressOf(f); },
|
||||
string: function(s) { return s; },
|
||||
number: function(n) { return String(n); },
|
||||
undefined: function() { return 'undefined'; },
|
||||
};
|
||||
|
||||
/* Map is meant to be similar in usage to ES6 Map, which is
|
||||
described at http://wiki.ecmascript.org/doku.php?id=harmony:simple_maps_and_sets,
|
||||
without requiring more than ES5 + Gjs extensions.
|
||||
|
||||
Known differences from other implementations:
|
||||
Polyfills around the web usually implement HashMaps for
|
||||
primitive values and reversed WeakMaps for object keys,
|
||||
but we want real maps with real O(1) semantics in all cases,
|
||||
and the easiest way is to have different hashers for different
|
||||
types.
|
||||
|
||||
Known differences from the ES6 specification:
|
||||
- Map is a Lang.Class, not a ES6 class, so inheritance,
|
||||
prototype, sealing, etc. work differently.
|
||||
- items(), keys() and values() don't return iterators,
|
||||
they return actual arrays, so they incur a full copy everytime
|
||||
they're called, and they don't see changes if you mutate
|
||||
the table while iterating
|
||||
(admittedly, the ES6 spec is a bit unclear on this, and
|
||||
the reference code would just blow up)
|
||||
*/
|
||||
const Map = new Lang.Class({
|
||||
Name: 'Map',
|
||||
|
||||
_init: function(iterable) {
|
||||
this._pool = { };
|
||||
|
||||
if (iterable) {
|
||||
for (let i = 0; i < iterable.length; i++) {
|
||||
let [key, value] = iterable[i];
|
||||
this.set(key, value);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
_hashKey: function(key) {
|
||||
let type = typeof(key);
|
||||
return type + ':' + _hashers[type](key);
|
||||
},
|
||||
|
||||
_internalGet: function(key) {
|
||||
let hash = this._hashKey(key);
|
||||
let node = this._pool[hash];
|
||||
|
||||
if (node && _sameValue(node.key, key))
|
||||
return [true, node.value];
|
||||
else
|
||||
return [false, null];
|
||||
},
|
||||
|
||||
get: function(key) {
|
||||
return this._internalGet(key)[1];
|
||||
},
|
||||
|
||||
has: function(key) {
|
||||
return this._internalGet(key)[0];
|
||||
},
|
||||
|
||||
set: function(key, value) {
|
||||
let hash = this._hashKey(key);
|
||||
let node = this._pool[hash];
|
||||
|
||||
if (node) {
|
||||
node.key = key;
|
||||
node.value = value;
|
||||
} else {
|
||||
this._pool[hash] = { key: key, value: value };
|
||||
}
|
||||
},
|
||||
|
||||
delete: function(key) {
|
||||
let hash = this._hashKey(key);
|
||||
let node = this._pool[hash];
|
||||
|
||||
if (node && _sameValue(node.key, key)) {
|
||||
delete this._pool[hash];
|
||||
return [node.key, node.value];
|
||||
} else {
|
||||
return [null, null];
|
||||
}
|
||||
},
|
||||
|
||||
keys: function() {
|
||||
let pool = this._pool;
|
||||
return Object.getOwnPropertyNames(pool).map(function(hash) {
|
||||
return pool[hash].key;
|
||||
});
|
||||
},
|
||||
|
||||
values: function() {
|
||||
let pool = this._pool;
|
||||
return Object.getOwnPropertyNames(pool).map(function(hash) {
|
||||
return pool[hash].value;
|
||||
});
|
||||
},
|
||||
|
||||
items: function() {
|
||||
let pool = this._pool;
|
||||
return Object.getOwnPropertyNames(pool).map(function(hash) {
|
||||
return [pool[hash].key, pool[hash].value];
|
||||
});
|
||||
},
|
||||
|
||||
size: function() {
|
||||
return Object.getOwnPropertyNames(this._pool).length;
|
||||
},
|
||||
});
|
@ -5,7 +5,7 @@ const Gio = imports.gi.Gio;
|
||||
const Lang = imports.lang;
|
||||
const Mainloop = imports.mainloop;
|
||||
const Shell = imports.gi.Shell;
|
||||
const Signals = imports.signals;
|
||||
const UPowerGlib = imports.gi.UPowerGlib;
|
||||
|
||||
const SystemdLoginManagerIface = <interface name='org.freedesktop.login1.Manager'>
|
||||
<method name='PowerOff'>
|
||||
@ -26,19 +26,6 @@ const SystemdLoginManagerIface = <interface name='org.freedesktop.login1.Manager
|
||||
<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='ListSessions'>
|
||||
<arg name='sessions' type='a(susso)' direction='out'/>
|
||||
</method>
|
||||
<signal name='PrepareForSleep'>
|
||||
<arg type='b' direction='out'/>
|
||||
</signal>
|
||||
</interface>;
|
||||
|
||||
const SystemdLoginSessionIface = <interface name='org.freedesktop.login1.Session'>
|
||||
@ -64,6 +51,12 @@ const ConsoleKitManagerIface = <interface name='org.freedesktop.ConsoleKit.Manag
|
||||
</interface>;
|
||||
|
||||
const ConsoleKitSessionIface = <interface name='org.freedesktop.ConsoleKit.Session'>
|
||||
<method name='IsActive'>
|
||||
<arg type='b' direction='out' />
|
||||
</method>
|
||||
<signal name='ActiveChanged'>
|
||||
<arg type='b' direction='out' />
|
||||
</signal>
|
||||
<signal name='Lock' />
|
||||
<signal name='Unlock' />
|
||||
</interface>;
|
||||
@ -100,8 +93,6 @@ const LoginManagerSystemd = new Lang.Class({
|
||||
this._proxy = new SystemdLoginManager(Gio.DBus.system,
|
||||
'org.freedesktop.login1',
|
||||
'/org/freedesktop/login1');
|
||||
this._proxy.connectSignal('PrepareForSleep',
|
||||
Lang.bind(this, this._prepareForSleep));
|
||||
},
|
||||
|
||||
// Having this function is a bit of a hack since the Systemd and ConsoleKit
|
||||
@ -118,6 +109,10 @@ const LoginManagerSystemd = new Lang.Class({
|
||||
return this._currentSession;
|
||||
},
|
||||
|
||||
get sessionActive() {
|
||||
return Shell.session_is_active_for_systemd();
|
||||
},
|
||||
|
||||
canPowerOff: function(asyncCallback) {
|
||||
this._proxy.CanPowerOffRemote(function(result, error) {
|
||||
if (error)
|
||||
@ -145,15 +140,6 @@ const LoginManagerSystemd = new Lang.Class({
|
||||
});
|
||||
},
|
||||
|
||||
listSessions: function(asyncCallback) {
|
||||
this._proxy.ListSessionsRemote(function(result, error) {
|
||||
if (error)
|
||||
asyncCallback([]);
|
||||
else
|
||||
asyncCallback(result[0]);
|
||||
});
|
||||
},
|
||||
|
||||
powerOff: function() {
|
||||
this._proxy.PowerOffRemote(true);
|
||||
},
|
||||
@ -164,33 +150,8 @@ const LoginManagerSystemd = new Lang.Class({
|
||||
|
||||
suspend: function() {
|
||||
this._proxy.SuspendRemote(true);
|
||||
},
|
||||
|
||||
inhibit: function(reason, callback) {
|
||||
let inVariant = GLib.Variant.new('(ssss)',
|
||||
['sleep',
|
||||
'GNOME Shell',
|
||||
reason,
|
||||
'delay']);
|
||||
this._proxy.call_with_unix_fd_list('Inhibit', inVariant, 0, -1, null, null,
|
||||
Lang.bind(this, function(proxy, result) {
|
||||
let fd = -1;
|
||||
try {
|
||||
let [outVariant, fdList] = proxy.call_with_unix_fd_list_finish(result);
|
||||
fd = fdList.steal_fds(outVariant.deep_unpack())[0];
|
||||
callback(new Gio.UnixInputStream({ fd: fd }));
|
||||
} catch(e) {
|
||||
logError(e, "Error getting systemd inhibitor");
|
||||
callback(null);
|
||||
}
|
||||
}));
|
||||
},
|
||||
|
||||
_prepareForSleep: function(proxy, sender, [aboutToSuspend]) {
|
||||
this.emit('prepare-for-sleep', aboutToSuspend);
|
||||
}
|
||||
});
|
||||
Signals.addSignalMethods(LoginManagerSystemd.prototype);
|
||||
|
||||
const LoginManagerConsoleKit = new Lang.Class({
|
||||
Name: 'LoginManagerConsoleKit',
|
||||
@ -199,6 +160,7 @@ const LoginManagerConsoleKit = new Lang.Class({
|
||||
this._proxy = new ConsoleKitManager(Gio.DBus.system,
|
||||
'org.freedesktop.ConsoleKit',
|
||||
'/org/freedesktop/ConsoleKit/Manager');
|
||||
this._upClient = new UPowerGlib.Client();
|
||||
},
|
||||
|
||||
// Having this function is a bit of a hack since the Systemd and ConsoleKit
|
||||
@ -215,6 +177,19 @@ const LoginManagerConsoleKit = new Lang.Class({
|
||||
return this._currentSession;
|
||||
},
|
||||
|
||||
get sessionActive() {
|
||||
if (this._sessionActive !== undefined)
|
||||
return this._sessionActive;
|
||||
|
||||
let session = this.getCurrentSessionProxy();
|
||||
session.connectSignal('ActiveChanged', Lang.bind(this, function(object, senderName, [isActive]) {
|
||||
this._sessionActive = isActive;
|
||||
}));
|
||||
[this._sessionActive] = session.IsActiveSync();
|
||||
|
||||
return this._sessionActive;
|
||||
},
|
||||
|
||||
canPowerOff: function(asyncCallback) {
|
||||
this._proxy.CanStopRemote(function(result, error) {
|
||||
if (error)
|
||||
@ -234,11 +209,10 @@ const LoginManagerConsoleKit = new Lang.Class({
|
||||
},
|
||||
|
||||
canSuspend: function(asyncCallback) {
|
||||
asyncCallback(false);
|
||||
},
|
||||
|
||||
listSessions: function(asyncCallback) {
|
||||
asyncCallback([]);
|
||||
Mainloop.idle_add(Lang.bind(this, function() {
|
||||
asyncCallback(this._upClient.get_can_suspend());
|
||||
return false;
|
||||
}));
|
||||
},
|
||||
|
||||
powerOff: function() {
|
||||
@ -250,12 +224,6 @@ const LoginManagerConsoleKit = new Lang.Class({
|
||||
},
|
||||
|
||||
suspend: function() {
|
||||
this.emit('prepare-for-sleep', true);
|
||||
this.emit('prepare-for-sleep', false);
|
||||
},
|
||||
|
||||
inhibit: function(reason, callback) {
|
||||
callback(null);
|
||||
this._upClient.suspend_sync(null);
|
||||
}
|
||||
});
|
||||
Signals.addSignalMethods(LoginManagerConsoleKit.prototype);
|
||||
|
@ -2,93 +2,9 @@
|
||||
|
||||
const Gio = imports.gi.Gio;
|
||||
const Lang = imports.lang;
|
||||
const NMGtk = imports.gi.NMGtk;
|
||||
const Shell = imports.gi.Shell;
|
||||
const Signals = imports.signals;
|
||||
|
||||
// _getMobileProvidersDatabase:
|
||||
//
|
||||
// Gets the database of mobile providers, with references between MCCMNC/SID and
|
||||
// operator name
|
||||
//
|
||||
let _mpd;
|
||||
function _getMobileProvidersDatabase() {
|
||||
if (_mpd == null) {
|
||||
try {
|
||||
_mpd = new NMGtk.MobileProvidersDatabase();
|
||||
_mpd.init(null);
|
||||
} catch (e) {
|
||||
log(e.message);
|
||||
_mpd = null;
|
||||
}
|
||||
}
|
||||
|
||||
return _mpd;
|
||||
}
|
||||
|
||||
// _findProviderForMccMnc:
|
||||
// @operator_name: operator name
|
||||
// @operator_code: operator code
|
||||
//
|
||||
// Given an operator name string (which may not be a real operator name) and an
|
||||
// operator code string, tries to find a proper operator name to display.
|
||||
//
|
||||
function _findProviderForMccMnc(operator_name, operator_code) {
|
||||
if (operator_name) {
|
||||
if (operator_name.length != 0 &&
|
||||
(operator_name.length > 6 || operator_name.length < 5)) {
|
||||
// this looks like a valid name, i.e. not an MCCMNC (that some
|
||||
// devices return when not yet connected
|
||||
return operator_name;
|
||||
}
|
||||
|
||||
if (isNaN(parseInt(operator_name))) {
|
||||
// name is definitely not a MCCMNC, so it may be a name
|
||||
// after all; return that
|
||||
return operator_name;
|
||||
}
|
||||
}
|
||||
|
||||
let needle;
|
||||
if ((!operator_name || operator_name.length == 0) && operator_code)
|
||||
needle = operator_code;
|
||||
else if (operator_name && (operator_name.length == 6 || operator_name.length == 5))
|
||||
needle = operator_name;
|
||||
else // nothing to search
|
||||
return null;
|
||||
|
||||
let mpd = _getMobileProvidersDatabase();
|
||||
if (mpd) {
|
||||
let provider = mpd.lookup_3gpp_mcc_mnc(needle);
|
||||
if (provider)
|
||||
return provider.get_name();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// _findProviderForSid:
|
||||
// @sid: System Identifier of the serving CDMA network
|
||||
//
|
||||
// Tries to find the operator name corresponding to the given SID
|
||||
//
|
||||
function _findProviderForSid(sid) {
|
||||
if (sid == 0)
|
||||
return null;
|
||||
|
||||
let mpd = _getMobileProvidersDatabase();
|
||||
if (mpd) {
|
||||
let provider = mpd.lookup_cdma_sid(sid);
|
||||
if (provider)
|
||||
return provider.get_name();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Support for the old ModemManager interface (MM < 0.7)
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
// The following are not the complete interfaces, just the methods we need
|
||||
// (or may need in the future)
|
||||
|
||||
@ -126,6 +42,76 @@ const ModemCdmaInterface = <interface name="org.freedesktop.ModemManager.Modem.C
|
||||
|
||||
const ModemCdmaProxy = Gio.DBusProxy.makeProxyWrapper(ModemCdmaInterface);
|
||||
|
||||
let _providersTable;
|
||||
function _getProvidersTable() {
|
||||
if (_providersTable)
|
||||
return _providersTable;
|
||||
return _providersTable = Shell.mobile_providers_parse(null,null);
|
||||
}
|
||||
|
||||
function findProviderForMCCMNC(table, needle) {
|
||||
let needlemcc = needle.substring(0, 3);
|
||||
let needlemnc = needle.substring(3, needle.length);
|
||||
|
||||
let name2, name3;
|
||||
for (let iter in table) {
|
||||
let country = table[iter];
|
||||
let providers = country.get_providers();
|
||||
|
||||
// Search through each country's providers
|
||||
for (let i = 0; i < providers.length; i++) {
|
||||
let provider = providers[i];
|
||||
|
||||
// Search through MCC/MNC list
|
||||
let list = provider.get_gsm_mcc_mnc();
|
||||
for (let j = 0; j < list.length; j++) {
|
||||
let mccmnc = list[j];
|
||||
|
||||
// Match both 2-digit and 3-digit MNC; prefer a
|
||||
// 3-digit match if found, otherwise a 2-digit one.
|
||||
if (mccmnc.mcc != needlemcc)
|
||||
continue; // MCC was wrong
|
||||
|
||||
if (!name3 && needle.length == 6 && needlemnc == mccmnc.mnc)
|
||||
name3 = provider.name;
|
||||
|
||||
if (!name2 && needlemnc.substring(0, 2) == mccmnc.mnc.substring(0, 2))
|
||||
name2 = provider.name;
|
||||
|
||||
if (name2 && name3)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return name3 || name2 || null;
|
||||
}
|
||||
|
||||
function findProviderForSid(table, sid) {
|
||||
if (sid == 0)
|
||||
return null;
|
||||
|
||||
// Search through each country
|
||||
for (let iter in table) {
|
||||
let country = table[iter];
|
||||
let providers = country.get_providers();
|
||||
|
||||
// Search through each country's providers
|
||||
for (let i = 0; i < providers.length; i++) {
|
||||
let provider = providers[i];
|
||||
let cdma_sid = provider.get_cdma_sid();
|
||||
|
||||
// Search through CDMA SID list
|
||||
for (let j = 0; j < cdma_sid.length; j++) {
|
||||
if (cdma_sid[j] == sid)
|
||||
return provider.name;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
const ModemGsm = new Lang.Class({
|
||||
Name: 'ModemGsm',
|
||||
|
||||
@ -141,7 +127,7 @@ const ModemGsm = new Lang.Class({
|
||||
this.emit('notify::signal-quality');
|
||||
}));
|
||||
this._proxy.connectSignal('RegistrationInfo', Lang.bind(this, function(proxy, sender, [status, code, name]) {
|
||||
this.operator_name = _findProviderForMccMnc(name, code);
|
||||
this.operator_name = this._findOperatorName(name, code);
|
||||
this.emit('notify::operator-name');
|
||||
}));
|
||||
this._proxy.GetRegistrationInfoRemote(Lang.bind(this, function([result], err) {
|
||||
@ -151,7 +137,7 @@ const ModemGsm = new Lang.Class({
|
||||
}
|
||||
|
||||
let [status, code, name] = result;
|
||||
this.operator_name = _findProviderForMccMnc(name, code);
|
||||
this.operator_name = this._findOperatorName(name, code);
|
||||
this.emit('notify::operator-name');
|
||||
}));
|
||||
this._proxy.GetSignalQualityRemote(Lang.bind(this, function(result, err) {
|
||||
@ -164,6 +150,32 @@ const ModemGsm = new Lang.Class({
|
||||
}
|
||||
this.emit('notify::signal-quality');
|
||||
}));
|
||||
},
|
||||
|
||||
_findOperatorName: function(name, opCode) {
|
||||
if (name) {
|
||||
if (name && name.length != 0 && (name.length > 6 || name.length < 5)) {
|
||||
// this looks like a valid name, i.e. not an MCCMNC (that some
|
||||
// devices return when not yet connected
|
||||
return name;
|
||||
}
|
||||
if (isNaN(parseInt(name))) {
|
||||
// name is definitely not a MCCMNC, so it may be a name
|
||||
// after all; return that
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
||||
let needle;
|
||||
if ((name == null || name.length == 0) && opCode)
|
||||
needle = opCode;
|
||||
else if (name.length == 6 || name.length == 5)
|
||||
needle = name;
|
||||
else // nothing to search
|
||||
return null;
|
||||
|
||||
let table = _getProvidersTable();
|
||||
return findProviderForMCCMNC(table, needle);
|
||||
}
|
||||
});
|
||||
Signals.addSignalMethods(ModemGsm.prototype);
|
||||
@ -203,99 +215,15 @@ const ModemCdma = new Lang.Class({
|
||||
// it will return an error if the device is not connected
|
||||
this.operator_name = null;
|
||||
} else {
|
||||
let [bandClass, band, sid] = result;
|
||||
|
||||
this.operator_name = _findProviderForSid(sid)
|
||||
let [bandClass, band, id] = result;
|
||||
if (name.length > 0) {
|
||||
let table = _getProvidersTable();
|
||||
this.operator_name = findProviderForSid(table, id);
|
||||
} else
|
||||
this.operator_name = null;
|
||||
}
|
||||
this.emit('notify::operator-name');
|
||||
}));
|
||||
}
|
||||
});
|
||||
Signals.addSignalMethods(ModemCdma.prototype);
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Support for the new ModemManager1 interface (MM >= 0.7)
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
const BroadbandModemInterface = <interface name="org.freedesktop.ModemManager1.Modem">
|
||||
<property name="SignalQuality" type="(ub)" access="read" />
|
||||
</interface>;
|
||||
const BroadbandModemProxy = Gio.DBusProxy.makeProxyWrapper(BroadbandModemInterface);
|
||||
|
||||
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 = <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({
|
||||
Name: 'BroadbandModem',
|
||||
|
||||
_init: function(path, capabilities) {
|
||||
this._proxy = new BroadbandModemProxy(Gio.DBus.system, 'org.freedesktop.ModemManager1', path);
|
||||
this._proxy_3gpp = new BroadbandModem3gppProxy(Gio.DBus.system, 'org.freedesktop.ModemManager1', path);
|
||||
this._proxy_cdma = new BroadbandModemCdmaProxy(Gio.DBus.system, 'org.freedesktop.ModemManager1', path);
|
||||
this._capabilities = capabilities;
|
||||
|
||||
this._proxy.connect('g-properties-changed', Lang.bind(this, function(proxy, properties) {
|
||||
if ('SignalQuality' in properties.deep_unpack())
|
||||
this._reloadSignalQuality();
|
||||
}));
|
||||
this._reloadSignalQuality();
|
||||
|
||||
this._proxy_3gpp.connect('g-properties-changed', Lang.bind(this, function(proxy, properties) {
|
||||
let unpacked = properties.deep_unpack();
|
||||
if ('OperatorName' in unpacked || 'OperatorCode' in unpacked)
|
||||
this._reload3gppOperatorName();
|
||||
}));
|
||||
this._reload3gppOperatorName();
|
||||
|
||||
this._proxy_cdma.connect('g-properties-changed', Lang.bind(this, function(proxy, properties) {
|
||||
let unpacked = properties.deep_unpack();
|
||||
if ('Nid' in unpacked || 'Sid' in unpacked)
|
||||
this._reloadCdmaOperatorName();
|
||||
}));
|
||||
this._reloadCdmaOperatorName();
|
||||
},
|
||||
|
||||
_reloadSignalQuality: function() {
|
||||
let [quality, recent] = this._proxy.SignalQuality;
|
||||
this.signal_quality = quality;
|
||||
this.emit('notify::signal-quality');
|
||||
},
|
||||
|
||||
_reloadOperatorName: function() {
|
||||
let new_name = "";
|
||||
if (this.operator_name_3gpp && this.operator_name_3gpp.length > 0)
|
||||
new_name += this.operator_name_3gpp;
|
||||
|
||||
if (this.operator_name_cdma && this.operator_name_cdma.length > 0) {
|
||||
if (new_name != "")
|
||||
new_name += ", ";
|
||||
new_name += this.operator_name_cdma;
|
||||
}
|
||||
|
||||
this.operator_name = new_name;
|
||||
this.emit('notify::operator-name');
|
||||
},
|
||||
|
||||
_reload3gppOperatorName: function() {
|
||||
let name = this._proxy_3gpp.OperatorName;
|
||||
let code = this._proxy_3gpp.OperatorCode;
|
||||
this.operator_name_3gpp = _findProviderForMccMnc(name, code);
|
||||
this._reloadOperatorName();
|
||||
},
|
||||
|
||||
_reloadCdmaOperatorName: function() {
|
||||
let sid = this._proxy_cdma.Sid;
|
||||
this.operator_name_cdma = _findProviderForSid(sid);
|
||||
this._reloadOperatorName();
|
||||
}
|
||||
});
|
||||
Signals.addSignalMethods(BroadbandModem.prototype);
|
||||
|
106
js/misc/util.js
106
js/misc/util.js
@ -1,8 +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 Main = imports.ui.main;
|
||||
|
||||
@ -161,6 +159,86 @@ function killall(processName) {
|
||||
}
|
||||
}
|
||||
|
||||
// This was ported from network-manager-applet
|
||||
// Copyright 2007 - 2011 Red Hat, Inc.
|
||||
// Author: Dan Williams <dcbw@redhat.com>
|
||||
|
||||
const _IGNORED_WORDS = [
|
||||
'Semiconductor',
|
||||
'Components',
|
||||
'Corporation',
|
||||
'Communications',
|
||||
'Company',
|
||||
'Corp.',
|
||||
'Corp',
|
||||
'Co.',
|
||||
'Inc.',
|
||||
'Inc',
|
||||
'Incorporated',
|
||||
'Ltd.',
|
||||
'Limited.',
|
||||
'Intel',
|
||||
'chipset',
|
||||
'adapter',
|
||||
'[hex]',
|
||||
'NDIS',
|
||||
'Module'
|
||||
];
|
||||
|
||||
const _IGNORED_PHRASES = [
|
||||
'Multiprotocol MAC/baseband processor',
|
||||
'Wireless LAN Controller',
|
||||
'Wireless LAN Adapter',
|
||||
'Wireless Adapter',
|
||||
'Network Connection',
|
||||
'Wireless Cardbus Adapter',
|
||||
'Wireless CardBus Adapter',
|
||||
'54 Mbps Wireless PC Card',
|
||||
'Wireless PC Card',
|
||||
'Wireless PC',
|
||||
'PC Card with XJACK(r) Antenna',
|
||||
'Wireless cardbus',
|
||||
'Wireless LAN PC Card',
|
||||
'Technology Group Ltd.',
|
||||
'Communication S.p.A.',
|
||||
'Business Mobile Networks BV',
|
||||
'Mobile Broadband Minicard Composite Device',
|
||||
'Mobile Communications AB',
|
||||
'(PC-Suite Mode)'
|
||||
];
|
||||
|
||||
function fixupPCIDescription(desc) {
|
||||
desc = desc.replace(/[_,]/, ' ');
|
||||
|
||||
/* Attempt to shorten ID by ignoring certain phrases */
|
||||
for (let i = 0; i < _IGNORED_PHRASES.length; i++) {
|
||||
let item = _IGNORED_PHRASES[i];
|
||||
let pos = desc.indexOf(item);
|
||||
if (pos != -1) {
|
||||
let before = desc.substring(0, pos);
|
||||
let after = desc.substring(pos + item.length, desc.length);
|
||||
desc = before + after;
|
||||
}
|
||||
}
|
||||
|
||||
/* Attmept to shorten ID by ignoring certain individual words */
|
||||
let words = desc.split(' ');
|
||||
let out = [ ];
|
||||
for (let i = 0; i < words.length; i++) {
|
||||
let item = words[i];
|
||||
|
||||
// skip empty items (that come out from consecutive spaces)
|
||||
if (item.length == 0)
|
||||
continue;
|
||||
|
||||
if (_IGNORED_WORDS.indexOf(item) == -1) {
|
||||
out.push(item);
|
||||
}
|
||||
}
|
||||
|
||||
return out.join(' ');
|
||||
}
|
||||
|
||||
// lowerBound:
|
||||
// @array: an array or array-like object, already sorted
|
||||
// according to @cmp
|
||||
@ -210,27 +288,3 @@ function insertSorted(array, val, cmp) {
|
||||
|
||||
return pos;
|
||||
}
|
||||
|
||||
function makeCloseButton() {
|
||||
let closeButton = new St.Button({ style_class: 'notification-close'});
|
||||
|
||||
// This is a bit tricky. St.Bin has its own x-align/y-align properties
|
||||
// that compete with Clutter's properties. This should be fixed for
|
||||
// Clutter 2.0. Since St.Bin doesn't define its own setters, the
|
||||
// setters are a workaround to get Clutter's version.
|
||||
closeButton.set_x_align(Clutter.ActorAlign.END);
|
||||
closeButton.set_y_align(Clutter.ActorAlign.START);
|
||||
|
||||
// XXX Clutter 2.0 workaround: ClutterBinLayout needs expand
|
||||
// to respect the alignments.
|
||||
closeButton.set_x_expand(true);
|
||||
closeButton.set_y_expand(true);
|
||||
|
||||
closeButton.connect('style-changed', function() {
|
||||
let themeNode = closeButton.get_theme_node();
|
||||
closeButton.translation_x = themeNode.get_length('-shell-close-overlap-x');
|
||||
closeButton.translation_y = themeNode.get_length('-shell-close-overlap-y');
|
||||
});
|
||||
|
||||
return closeButton;
|
||||
}
|
||||
|
100
js/ui/altTab.js
100
js/ui/altTab.js
@ -98,13 +98,43 @@ const AppSwitcherPopup = new Lang.Class({
|
||||
}
|
||||
},
|
||||
|
||||
_createSwitcher: function() {
|
||||
let apps = Shell.AppSystem.get_default().get_running ();
|
||||
_getAppLists: function() {
|
||||
let tracker = Shell.WindowTracker.get_default();
|
||||
let appSys = Shell.AppSystem.get_default();
|
||||
let allApps = appSys.get_running ();
|
||||
|
||||
if (apps.length == 0)
|
||||
let screen = global.screen;
|
||||
let display = screen.get_display();
|
||||
let windows = display.get_tab_list(Meta.TabList.NORMAL_ALL, screen,
|
||||
screen.get_active_workspace());
|
||||
|
||||
// windows is only the windows on the current workspace. For
|
||||
// each one, if it corresponds to an app we know, move that
|
||||
// app from allApps to apps.
|
||||
let apps = [];
|
||||
for (let i = 0; i < windows.length && allApps.length != 0; i++) {
|
||||
let app = tracker.get_window_app(windows[i]);
|
||||
let index = allApps.indexOf(app);
|
||||
if (index != -1) {
|
||||
apps.push(app);
|
||||
allApps.splice(index, 1);
|
||||
}
|
||||
}
|
||||
|
||||
// Now @apps is a list of apps on the current workspace, in
|
||||
// standard Alt+Tab order (MRU except for minimized windows),
|
||||
// and allApps is a list of apps that only appear on other
|
||||
// workspaces, sorted by user_time, which is good enough.
|
||||
return [apps, allApps];
|
||||
},
|
||||
|
||||
_createSwitcher: function() {
|
||||
let [localApps, otherApps] = this._getAppLists();
|
||||
|
||||
if (localApps.length == 0 && otherApps.length == 0)
|
||||
return false;
|
||||
|
||||
this._switcherList = new AppSwitcher(apps, this);
|
||||
this._switcherList = new AppSwitcher(localApps, otherApps, this);
|
||||
this._items = this._switcherList.icons;
|
||||
|
||||
return true;
|
||||
@ -235,8 +265,12 @@ const AppSwitcherPopup = new Lang.Class({
|
||||
this.parent();
|
||||
|
||||
let appIcon = this._items[this._selectedIndex];
|
||||
let window = this._currentWindow > 0 ? this._currentWindow : 0;
|
||||
appIcon.app.activate_window(appIcon.cachedWindows[window], timestamp);
|
||||
let window;
|
||||
if (this._currentWindow >= 0)
|
||||
window = appIcon.cachedWindows[this._currentWindow];
|
||||
else
|
||||
window = null;
|
||||
appIcon.app.activate_window(window, timestamp);
|
||||
},
|
||||
|
||||
_onDestroy : function() {
|
||||
@ -427,26 +461,34 @@ const AppSwitcher = new Lang.Class({
|
||||
Name: 'AppSwitcher',
|
||||
Extends: SwitcherPopup.SwitcherList,
|
||||
|
||||
_init : function(apps, altTabPopup) {
|
||||
_init : function(localApps, otherApps, altTabPopup) {
|
||||
this.parent(true);
|
||||
|
||||
// Construct the AppIcons, add to the popup
|
||||
let activeWorkspace = global.screen.get_active_workspace();
|
||||
let workspaceIcons = [];
|
||||
let otherIcons = [];
|
||||
for (let i = 0; i < localApps.length; i++) {
|
||||
let appIcon = new AppIcon(localApps[i]);
|
||||
// Cache the window list now; we don't handle dynamic changes here,
|
||||
// and we don't want to be continually retrieving it
|
||||
appIcon.cachedWindows = appIcon.app.get_windows();
|
||||
workspaceIcons.push(appIcon);
|
||||
}
|
||||
for (let i = 0; i < otherApps.length; i++) {
|
||||
let appIcon = new AppIcon(otherApps[i]);
|
||||
appIcon.cachedWindows = appIcon.app.get_windows();
|
||||
otherIcons.push(appIcon);
|
||||
}
|
||||
|
||||
this.icons = [];
|
||||
this._arrows = [];
|
||||
|
||||
let windowTracker = Shell.WindowTracker.get_default();
|
||||
let allWindows = global.display.get_tab_list(Meta.TabList.NORMAL,
|
||||
global.screen, null);
|
||||
|
||||
// Construct the AppIcons, add to the popup
|
||||
for (let i = 0; i < apps.length; i++) {
|
||||
let appIcon = new AppIcon(apps[i]);
|
||||
// Cache the window list now; we don't handle dynamic changes here,
|
||||
// and we don't want to be continually retrieving it
|
||||
appIcon.cachedWindows = allWindows.filter(function(w) {
|
||||
return windowTracker.get_window_app (w) == appIcon.app;
|
||||
});
|
||||
this._addIcon(appIcon);
|
||||
}
|
||||
for (let i = 0; i < workspaceIcons.length; i++)
|
||||
this._addIcon(workspaceIcons[i]);
|
||||
if (workspaceIcons.length > 0 && otherIcons.length > 0)
|
||||
this.addSeparator();
|
||||
for (let i = 0; i < otherIcons.length; i++)
|
||||
this._addIcon(otherIcons[i]);
|
||||
|
||||
this._curApp = -1;
|
||||
this._iconSize = 0;
|
||||
@ -472,6 +514,8 @@ const AppSwitcher = new Lang.Class({
|
||||
let [iconMinHeight, iconNaturalHeight] = this.icons[j].label.get_preferred_height(-1);
|
||||
let iconSpacing = iconNaturalHeight + iconPadding + iconBorder;
|
||||
let totalSpacing = this._list.spacing * (this._items.length - 1);
|
||||
if (this._separator)
|
||||
totalSpacing += this._separator.width + this._list.spacing;
|
||||
|
||||
// We just assume the whole screen here due to weirdness happing with the passed width
|
||||
let primary = Main.layoutManager.primaryMonitor;
|
||||
@ -594,12 +638,24 @@ const ThumbnailList = new Lang.Class({
|
||||
_init : function(windows) {
|
||||
this.parent(false);
|
||||
|
||||
let activeWorkspace = global.screen.get_active_workspace();
|
||||
|
||||
// We fake the value of 'separatorAdded' when the app has no window
|
||||
// on the current workspace, to avoid displaying a useless separator in
|
||||
// that case.
|
||||
let separatorAdded = windows.length == 0 || windows[0].get_workspace() != activeWorkspace;
|
||||
|
||||
this._labels = new Array();
|
||||
this._thumbnailBins = new Array();
|
||||
this._clones = new Array();
|
||||
this._windows = windows;
|
||||
|
||||
for (let i = 0; i < windows.length; i++) {
|
||||
if (!separatorAdded && windows[i].get_workspace() != activeWorkspace) {
|
||||
this.addSeparator();
|
||||
separatorAdded = true;
|
||||
}
|
||||
|
||||
let box = new St.BoxLayout({ style_class: 'thumbnail-box',
|
||||
vertical: true });
|
||||
|
||||
|
@ -3,7 +3,6 @@
|
||||
const Clutter = imports.gi.Clutter;
|
||||
const Gio = imports.gi.Gio;
|
||||
const GLib = imports.gi.GLib;
|
||||
const GObject = imports.gi.GObject;
|
||||
const Gtk = imports.gi.Gtk;
|
||||
const GMenu = imports.gi.GMenu;
|
||||
const Shell = imports.gi.Shell;
|
||||
@ -15,12 +14,10 @@ const Mainloop = imports.mainloop;
|
||||
const Atk = imports.gi.Atk;
|
||||
|
||||
const AppFavorites = imports.ui.appFavorites;
|
||||
const BoxPointer = imports.ui.boxpointer;
|
||||
const DND = imports.ui.dnd;
|
||||
const IconGrid = imports.ui.iconGrid;
|
||||
const Main = imports.ui.main;
|
||||
const Overview = imports.ui.overview;
|
||||
const OverviewControls = imports.ui.overviewControls;
|
||||
const PopupMenu = imports.ui.popupMenu;
|
||||
const Tweener = imports.ui.tweener;
|
||||
const Workspace = imports.ui.workspace;
|
||||
@ -30,232 +27,58 @@ const Util = imports.misc.util;
|
||||
const MAX_APPLICATION_WORK_MILLIS = 75;
|
||||
const MENU_POPUP_TIMEOUT = 600;
|
||||
const SCROLL_TIME = 0.1;
|
||||
const MAX_COLUMNS = 6;
|
||||
|
||||
const INACTIVE_GRID_OPACITY = 77;
|
||||
const FOLDER_SUBICON_FRACTION = .4;
|
||||
|
||||
|
||||
// Recursively load a GMenuTreeDirectory; we could put this in ShellAppSystem too
|
||||
function _loadCategory(dir, view) {
|
||||
let iter = dir.iter();
|
||||
let appSystem = Shell.AppSystem.get_default();
|
||||
let nextType;
|
||||
while ((nextType = iter.next()) != GMenu.TreeItemType.INVALID) {
|
||||
if (nextType == GMenu.TreeItemType.ENTRY) {
|
||||
let entry = iter.get_entry();
|
||||
let app = appSystem.lookup_app_by_tree_entry(entry);
|
||||
if (!entry.get_app_info().get_nodisplay())
|
||||
view.addApp(app);
|
||||
} else if (nextType == GMenu.TreeItemType.DIRECTORY) {
|
||||
let itemDir = iter.get_directory();
|
||||
if (!itemDir.get_is_nodisplay())
|
||||
_loadCategory(itemDir, view);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const AlphabeticalView = new Lang.Class({
|
||||
Name: 'AlphabeticalView',
|
||||
Abstract: true,
|
||||
|
||||
_init: function() {
|
||||
this._grid = new IconGrid.IconGrid({ xAlign: St.Align.MIDDLE,
|
||||
columnLimit: MAX_COLUMNS });
|
||||
this._grid = new IconGrid.IconGrid({ xAlign: St.Align.START });
|
||||
this._appSystem = Shell.AppSystem.get_default();
|
||||
|
||||
// Standard hack for ClutterBinLayout
|
||||
this._grid.actor.x_expand = true;
|
||||
|
||||
this._items = {};
|
||||
this._allItems = [];
|
||||
},
|
||||
|
||||
removeAll: function() {
|
||||
this._grid.removeAll();
|
||||
this._items = {};
|
||||
this._allItems = [];
|
||||
},
|
||||
|
||||
_getItemId: function(item) {
|
||||
throw new Error('Not implemented');
|
||||
},
|
||||
|
||||
_createItemIcon: function(item) {
|
||||
throw new Error('Not implemented');
|
||||
},
|
||||
|
||||
_compareItems: function(a, b) {
|
||||
throw new Error('Not implemented');
|
||||
},
|
||||
|
||||
_addItem: function(item) {
|
||||
let id = this._getItemId(item);
|
||||
if (this._items[id] !== undefined)
|
||||
return null;
|
||||
|
||||
let itemIcon = this._createItemIcon(item);
|
||||
this._allItems.push(item);
|
||||
this._items[id] = itemIcon;
|
||||
|
||||
return itemIcon;
|
||||
},
|
||||
|
||||
loadGrid: function() {
|
||||
this._allItems.sort(this._compareItems);
|
||||
|
||||
for (let i = 0; i < this._allItems.length; i++) {
|
||||
let id = this._getItemId(this._allItems[i]);
|
||||
if (!id)
|
||||
continue;
|
||||
this._grid.addItem(this._items[id].actor);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const FolderView = new Lang.Class({
|
||||
Name: 'FolderView',
|
||||
Extends: AlphabeticalView,
|
||||
|
||||
_init: function() {
|
||||
this.parent();
|
||||
this.actor = this._grid.actor;
|
||||
},
|
||||
|
||||
_getItemId: function(item) {
|
||||
return item.get_id();
|
||||
},
|
||||
|
||||
_createItemIcon: function(item) {
|
||||
return new AppIcon(item);
|
||||
},
|
||||
|
||||
_compareItems: function(a, b) {
|
||||
return a.compare_by_name(b);
|
||||
},
|
||||
|
||||
addApp: function(app) {
|
||||
this._addItem(app);
|
||||
},
|
||||
|
||||
createFolderIcon: function(size) {
|
||||
let icon = new St.Widget({ layout_manager: new Clutter.BinLayout(),
|
||||
style_class: 'app-folder-icon',
|
||||
width: size, height: size });
|
||||
let subSize = Math.floor(FOLDER_SUBICON_FRACTION * size);
|
||||
|
||||
let aligns = [ Clutter.ActorAlign.START, Clutter.ActorAlign.END ];
|
||||
for (let i = 0; i < Math.min(this._allItems.length, 4); i++) {
|
||||
let texture = this._allItems[i].create_icon_texture(subSize);
|
||||
let bin = new St.Bin({ child: texture,
|
||||
x_expand: true, y_expand: true });
|
||||
bin.set_x_align(aligns[i % 2]);
|
||||
bin.set_y_align(aligns[Math.floor(i / 2)]);
|
||||
icon.add_actor(bin);
|
||||
}
|
||||
|
||||
return icon;
|
||||
}
|
||||
});
|
||||
|
||||
const AllView = new Lang.Class({
|
||||
Name: 'AllView',
|
||||
Extends: AlphabeticalView,
|
||||
|
||||
_init: function() {
|
||||
this.parent();
|
||||
this._pendingAppLaterId = 0;
|
||||
this._appIcons = {}; // desktop file id
|
||||
this._allApps = [];
|
||||
|
||||
let box = new St.BoxLayout({ vertical: true });
|
||||
this._stack = new St.Widget({ layout_manager: new Clutter.BinLayout() });
|
||||
this._stack.add_actor(this._grid.actor);
|
||||
this._eventBlocker = new St.Widget({ x_expand: true, y_expand: true });
|
||||
this._stack.add_actor(this._eventBlocker);
|
||||
box.add(this._stack, { y_align: St.Align.START, expand: true });
|
||||
box.add(this._grid.actor, { y_align: St.Align.START, expand: true });
|
||||
|
||||
this.actor = new St.ScrollView({ x_fill: true,
|
||||
y_fill: false,
|
||||
y_align: St.Align.START,
|
||||
x_expand: true,
|
||||
y_expand: true,
|
||||
overlay_scrollbars: true,
|
||||
style_class: 'all-apps vfade' });
|
||||
style_class: 'vfade' });
|
||||
this.actor.add_actor(box);
|
||||
this.actor.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC);
|
||||
let action = new Clutter.PanAction({ interpolate: true });
|
||||
action.connect('pan', Lang.bind(this, this._onPan));
|
||||
this.actor.add_action(action);
|
||||
|
||||
this._clickAction = new Clutter.ClickAction();
|
||||
this._clickAction.connect('clicked', Lang.bind(this, function() {
|
||||
if (!this._currentPopup)
|
||||
return;
|
||||
|
||||
let [x, y] = this._clickAction.get_coords();
|
||||
let actor = global.stage.get_actor_at_pos(Clutter.PickMode.ALL, x, y);
|
||||
if (!this._currentPopup.actor.contains(actor))
|
||||
this._currentPopup.popdown();
|
||||
}));
|
||||
this._eventBlocker.add_action(this._clickAction);
|
||||
},
|
||||
|
||||
_onPan: function(action) {
|
||||
this._clickAction.release();
|
||||
|
||||
let [dist, dx, dy] = action.get_motion_delta(0);
|
||||
let adjustment = this.actor.vscroll.adjustment;
|
||||
adjustment.value -= (dy / this.actor.height) * adjustment.page_size;
|
||||
return false;
|
||||
},
|
||||
|
||||
_getItemId: function(item) {
|
||||
if (item instanceof Shell.App)
|
||||
return item.get_id();
|
||||
else if (item instanceof GMenu.TreeDirectory)
|
||||
return item.get_menu_id();
|
||||
else
|
||||
return null;
|
||||
},
|
||||
|
||||
_createItemIcon: function(item) {
|
||||
if (item instanceof Shell.App)
|
||||
return new AppIcon(item);
|
||||
else if (item instanceof GMenu.TreeDirectory)
|
||||
return new FolderIcon(item, this);
|
||||
else
|
||||
return null;
|
||||
},
|
||||
|
||||
_compareItems: function(itemA, itemB) {
|
||||
// bit of a hack: rely on both ShellApp and GMenuTreeDirectory
|
||||
// having a get_name() method
|
||||
let nameA = GLib.utf8_collate_key(itemA.get_name(), -1);
|
||||
let nameB = GLib.utf8_collate_key(itemB.get_name(), -1);
|
||||
return (nameA > nameB) ? 1 : (nameA < nameB ? -1 : 0);
|
||||
removeAll: function() {
|
||||
this._grid.removeAll();
|
||||
this._appIcons = {};
|
||||
this._allApps = [];
|
||||
},
|
||||
|
||||
addApp: function(app) {
|
||||
let appIcon = this._addItem(app);
|
||||
if (appIcon)
|
||||
appIcon.actor.connect('key-focus-in',
|
||||
Lang.bind(this, this._ensureIconVisible));
|
||||
},
|
||||
var id = app.get_id();
|
||||
if (this._appIcons[id] !== undefined)
|
||||
return;
|
||||
|
||||
addFolder: function(dir) {
|
||||
let folderIcon = this._addItem(dir);
|
||||
if (folderIcon)
|
||||
folderIcon.actor.connect('key-focus-in',
|
||||
Lang.bind(this, this._ensureIconVisible));
|
||||
},
|
||||
let appIcon = new AppWellIcon(app);
|
||||
let pos = Util.insertSorted(this._allApps, app, function(a, b) {
|
||||
return a.compare_by_name(b);
|
||||
});
|
||||
this._grid.addItem(appIcon.actor, pos);
|
||||
appIcon.actor.connect('key-focus-in', Lang.bind(this, this._ensureIconVisible));
|
||||
|
||||
addFolderPopup: function(popup) {
|
||||
this._stack.add_actor(popup.actor);
|
||||
popup.connect('open-state-changed', Lang.bind(this,
|
||||
function(popup, isOpen) {
|
||||
this._eventBlocker.reactive = isOpen;
|
||||
this._currentPopup = isOpen ? popup : null;
|
||||
this._updateIconOpacities(isOpen);
|
||||
if (isOpen)
|
||||
this._ensureIconVisible(popup.actor);
|
||||
}));
|
||||
this._appIcons[id] = appIcon;
|
||||
},
|
||||
|
||||
_ensureIconVisible: function(icon) {
|
||||
@ -263,9 +86,9 @@ const AllView = new Lang.Class({
|
||||
let [value, lower, upper, stepIncrement, pageIncrement, pageSize] = adjustment.get_values();
|
||||
|
||||
let offset = 0;
|
||||
let vfade = this.actor.get_effect("fade");
|
||||
let vfade = this.actor.get_effect("vfade");
|
||||
if (vfade)
|
||||
offset = vfade.vfade_offset;
|
||||
offset = vfade.fade_offset;
|
||||
|
||||
// If this gets called as part of a right-click, the actor
|
||||
// will be needs_allocation, and so "icon.y" would return 0
|
||||
@ -284,170 +107,174 @@ const AllView = new Lang.Class({
|
||||
transition: 'easeOutQuad' });
|
||||
},
|
||||
|
||||
_updateIconOpacities: function(folderOpen) {
|
||||
for (let id in this._items) {
|
||||
if (folderOpen && !this._items[id].actor.checked)
|
||||
this._items[id].actor.opacity = INACTIVE_GRID_OPACITY;
|
||||
else
|
||||
this._items[id].actor.opacity = 255;
|
||||
setVisibleApps: function(apps) {
|
||||
if (apps == null) { // null implies "all"
|
||||
for (var id in this._appIcons) {
|
||||
var icon = this._appIcons[id];
|
||||
icon.actor.visible = true;
|
||||
}
|
||||
} else {
|
||||
// Set everything to not-visible, then set to visible what we should see
|
||||
for (var id in this._appIcons) {
|
||||
var icon = this._appIcons[id];
|
||||
icon.actor.visible = false;
|
||||
}
|
||||
for (var i = 0; i < apps.length; i++) {
|
||||
var app = apps[i];
|
||||
var id = app.get_id();
|
||||
var icon = this._appIcons[id];
|
||||
icon.actor.visible = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const FrequentView = new Lang.Class({
|
||||
Name: 'FrequentView',
|
||||
|
||||
_init: function() {
|
||||
this._grid = new IconGrid.IconGrid({ xAlign: St.Align.MIDDLE,
|
||||
fillParent: true,
|
||||
columnLimit: MAX_COLUMNS });
|
||||
this.actor = new St.Widget({ style_class: 'frequent-apps',
|
||||
x_expand: true, y_expand: true });
|
||||
this.actor.add_actor(this._grid.actor);
|
||||
|
||||
this._usage = Shell.AppUsage.get_default();
|
||||
},
|
||||
|
||||
removeAll: function() {
|
||||
this._grid.removeAll();
|
||||
},
|
||||
|
||||
loadApps: function() {
|
||||
let mostUsed = this._usage.get_most_used ("");
|
||||
for (let i = 0; i < mostUsed.length; i++) {
|
||||
let appIcon = new AppIcon(mostUsed[i]);
|
||||
this._grid.addItem(appIcon.actor, -1);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const Views = {
|
||||
FREQUENT: 0,
|
||||
ALL: 1
|
||||
};
|
||||
|
||||
const AppDisplay = new Lang.Class({
|
||||
Name: 'AppDisplay',
|
||||
const ViewByCategories = new Lang.Class({
|
||||
Name: 'ViewByCategories',
|
||||
|
||||
_init: function() {
|
||||
this._appSystem = Shell.AppSystem.get_default();
|
||||
this._appSystem.connect('installed-changed', Lang.bind(this, function() {
|
||||
Main.queueDeferredWork(this._allAppsWorkId);
|
||||
this.actor = new St.BoxLayout({ style_class: 'all-app' });
|
||||
this.actor._delegate = this;
|
||||
|
||||
this._view = new AlphabeticalView();
|
||||
|
||||
// categories can be -1 (the All view) or 0...n-1, where n
|
||||
// is the number of sections
|
||||
// -2 is a flag to indicate that nothing is selected
|
||||
// (used only before the actor is mapped the first time)
|
||||
this._currentCategory = -2;
|
||||
this._categories = [];
|
||||
|
||||
this._categoryBox = new St.BoxLayout({ vertical: true,
|
||||
reactive: true,
|
||||
accessible_role: Atk.Role.LIST });
|
||||
this._categoryScroll = new St.ScrollView({ x_fill: false,
|
||||
y_fill: false,
|
||||
style_class: 'vfade' });
|
||||
this._categoryScroll.add_actor(this._categoryBox);
|
||||
this.actor.add(this._view.actor, { expand: true, x_fill: true, y_fill: true });
|
||||
this.actor.add(this._categoryScroll, { expand: false, y_fill: false, y_align: St.Align.START });
|
||||
|
||||
// Always select the "All" filter when switching to the app view
|
||||
this.actor.connect('notify::mapped', Lang.bind(this,
|
||||
function() {
|
||||
if (this.actor.mapped && this._allCategoryButton)
|
||||
this._selectCategory(-1);
|
||||
}));
|
||||
Main.overview.connect('showing', Lang.bind(this, function() {
|
||||
Main.queueDeferredWork(this._frequentAppsWorkId);
|
||||
}));
|
||||
global.settings.connect('changed::app-folder-categories', Lang.bind(this, function() {
|
||||
Main.queueDeferredWork(this._allAppsWorkId);
|
||||
}));
|
||||
|
||||
this._views = [];
|
||||
|
||||
let view, button;
|
||||
view = new FrequentView();
|
||||
button = new St.Button({ label: _("Frequent"),
|
||||
style_class: 'app-view-control',
|
||||
can_focus: true,
|
||||
x_expand: true });
|
||||
this._views[Views.FREQUENT] = { 'view': view, 'control': button };
|
||||
|
||||
view = new AllView();
|
||||
button = new St.Button({ label: _("All"),
|
||||
style_class: 'app-view-control',
|
||||
can_focus: true,
|
||||
x_expand: true });
|
||||
this._views[Views.ALL] = { 'view': view, 'control': button };
|
||||
|
||||
this.actor = new St.BoxLayout({ style_class: 'app-display',
|
||||
vertical: true,
|
||||
x_expand: true, y_expand: true });
|
||||
|
||||
this._viewStack = new St.Widget({ layout_manager: new Clutter.BinLayout(),
|
||||
x_expand: true, y_expand: true });
|
||||
this.actor.add(this._viewStack, { expand: true });
|
||||
|
||||
let layout = new Clutter.BoxLayout({ homogeneous: true });
|
||||
this._controls = new St.Widget({ style_class: 'app-view-controls',
|
||||
layout_manager: layout });
|
||||
this.actor.add(new St.Bin({ child: this._controls }));
|
||||
|
||||
|
||||
for (let i = 0; i < this._views.length; i++) {
|
||||
this._viewStack.add_actor(this._views[i].view.actor);
|
||||
this._controls.add_actor(this._views[i].control);
|
||||
|
||||
let viewIndex = i;
|
||||
this._views[i].control.connect('clicked', Lang.bind(this,
|
||||
function(actor) {
|
||||
this._showView(viewIndex);
|
||||
}));
|
||||
}
|
||||
this._showView(Views.FREQUENT);
|
||||
|
||||
// We need a dummy actor to catch the keyboard focus if the
|
||||
// user Ctrl-Alt-Tabs here before the deferred work creates
|
||||
// our real contents
|
||||
this._focusDummy = new St.Bin({ can_focus: true });
|
||||
this._viewStack.add_actor(this._focusDummy);
|
||||
|
||||
this._allAppsWorkId = Main.initializeDeferredWork(this.actor, Lang.bind(this, this._redisplayAllApps));
|
||||
this._frequentAppsWorkId = Main.initializeDeferredWork(this.actor, Lang.bind(this, this._redisplayFrequentApps));
|
||||
this.actor.add(this._focusDummy);
|
||||
},
|
||||
|
||||
_showView: function(activeIndex) {
|
||||
for (let i = 0; i < this._views.length; i++) {
|
||||
let actor = this._views[i].view.actor;
|
||||
let params = { time: OverviewControls.SIDE_CONTROLS_ANIMATION_TIME,
|
||||
opacity: (i == activeIndex) ? 255 : 0 };
|
||||
if (i == activeIndex)
|
||||
actor.visible = true;
|
||||
else
|
||||
params.onComplete = function() { actor.hide(); };
|
||||
Tweener.addTween(actor, params);
|
||||
_selectCategory: function(num) {
|
||||
if (this._currentCategory == num) // nothing to do
|
||||
return;
|
||||
|
||||
if (i == activeIndex)
|
||||
this._views[i].control.add_style_pseudo_class('checked');
|
||||
this._currentCategory = num;
|
||||
|
||||
if (num != -1) {
|
||||
var category = this._categories[num];
|
||||
this._allCategoryButton.remove_style_pseudo_class('selected');
|
||||
this._view.setVisibleApps(category.apps);
|
||||
} else {
|
||||
this._allCategoryButton.add_style_pseudo_class('selected');
|
||||
this._view.setVisibleApps(null);
|
||||
}
|
||||
|
||||
for (var i = 0; i < this._categories.length; i++) {
|
||||
if (i == num)
|
||||
this._categories[i].button.add_style_pseudo_class('selected');
|
||||
else
|
||||
this._views[i].control.remove_style_pseudo_class('checked');
|
||||
this._categories[i].button.remove_style_pseudo_class('selected');
|
||||
}
|
||||
},
|
||||
|
||||
_redisplay: function() {
|
||||
this._redisplayFrequentApps();
|
||||
this._redisplayAllApps();
|
||||
// Recursively load a GMenuTreeDirectory; we could put this in ShellAppSystem too
|
||||
_loadCategory: function(dir, appList) {
|
||||
var iter = dir.iter();
|
||||
var nextType;
|
||||
while ((nextType = iter.next()) != GMenu.TreeItemType.INVALID) {
|
||||
if (nextType == GMenu.TreeItemType.ENTRY) {
|
||||
var entry = iter.get_entry();
|
||||
var app = this._appSystem.lookup_app_by_tree_entry(entry);
|
||||
if (!entry.get_app_info().get_nodisplay()) {
|
||||
this._view.addApp(app);
|
||||
appList.push(app);
|
||||
}
|
||||
} else if (nextType == GMenu.TreeItemType.DIRECTORY) {
|
||||
var itemDir = iter.get_directory();
|
||||
if (!itemDir.get_is_nodisplay())
|
||||
this._loadCategory(itemDir, appList);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
_redisplayFrequentApps: function() {
|
||||
let view = this._views[Views.FREQUENT].view;
|
||||
_addCategory: function(name, index, dir) {
|
||||
let apps;
|
||||
|
||||
view.removeAll();
|
||||
view.loadApps();
|
||||
if (dir != null) {
|
||||
apps = [];
|
||||
this._loadCategory(dir, apps);
|
||||
|
||||
if (apps.length == 0)
|
||||
return false;
|
||||
}
|
||||
|
||||
let button = new St.Button({ label: GLib.markup_escape_text (name, -1),
|
||||
style_class: 'app-filter',
|
||||
x_align: St.Align.START,
|
||||
can_focus: true ,
|
||||
accessible_role: Atk.Role.LIST_ITEM });
|
||||
button.connect('clicked', Lang.bind(this, function() {
|
||||
this._selectCategory(index);
|
||||
}));
|
||||
|
||||
if (dir == null) {
|
||||
this._allCategoryButton = button;
|
||||
} else {
|
||||
this._categories.push({ apps: apps,
|
||||
name: name,
|
||||
button: button });
|
||||
}
|
||||
|
||||
this._categoryBox.add(button, { expand: true, x_fill: true, y_fill: false });
|
||||
return true;
|
||||
},
|
||||
|
||||
_redisplayAllApps: function() {
|
||||
let view = this._views[Views.ALL].view;
|
||||
_removeAll: function() {
|
||||
this._view.removeAll();
|
||||
this._categories = [];
|
||||
this._categoryBox.destroy_all_children();
|
||||
},
|
||||
|
||||
view.removeAll();
|
||||
refresh: function() {
|
||||
this._removeAll();
|
||||
|
||||
let tree = this._appSystem.get_tree();
|
||||
let root = tree.get_root_directory();
|
||||
/* Translators: Filter to display all applications */
|
||||
this._addCategory(_("All"), -1, null);
|
||||
|
||||
let iter = root.iter();
|
||||
let nextType;
|
||||
let folderCategories = global.settings.get_strv('app-folder-categories');
|
||||
var tree = this._appSystem.get_tree();
|
||||
var root = tree.get_root_directory();
|
||||
|
||||
var iter = root.iter();
|
||||
var nextType;
|
||||
var i = 0;
|
||||
while ((nextType = iter.next()) != GMenu.TreeItemType.INVALID) {
|
||||
if (nextType == GMenu.TreeItemType.DIRECTORY) {
|
||||
let dir = iter.get_directory();
|
||||
var dir = iter.get_directory();
|
||||
if (dir.get_is_nodisplay())
|
||||
continue;
|
||||
|
||||
if (folderCategories.indexOf(dir.get_menu_id()) != -1)
|
||||
view.addFolder(dir);
|
||||
else
|
||||
_loadCategory(dir, view);
|
||||
if (this._addCategory(dir.get_name(), i, dir))
|
||||
i++;
|
||||
}
|
||||
}
|
||||
view.loadGrid();
|
||||
|
||||
this._selectCategory(-1);
|
||||
|
||||
if (this._focusDummy) {
|
||||
let focused = this._focusDummy.has_key_focus();
|
||||
@ -459,6 +286,29 @@ const AppDisplay = new Lang.Class({
|
||||
}
|
||||
});
|
||||
|
||||
/* This class represents a display containing a collection of application items.
|
||||
* The applications are sorted based on their name.
|
||||
*/
|
||||
const AllAppDisplay = new Lang.Class({
|
||||
Name: 'AllAppDisplay',
|
||||
|
||||
_init: function() {
|
||||
this._appSystem = Shell.AppSystem.get_default();
|
||||
this._appSystem.connect('installed-changed', Lang.bind(this, function() {
|
||||
Main.queueDeferredWork(this._workId);
|
||||
}));
|
||||
|
||||
this._appView = new ViewByCategories();
|
||||
this.actor = new St.Bin({ child: this._appView.actor, x_fill: true, y_fill: true });
|
||||
|
||||
this._workId = Main.initializeDeferredWork(this.actor, Lang.bind(this, this._redisplay));
|
||||
},
|
||||
|
||||
_redisplay: function() {
|
||||
this._appView.refresh();
|
||||
}
|
||||
});
|
||||
|
||||
const AppSearchProvider = new Lang.Class({
|
||||
Name: 'AppSearchProvider',
|
||||
|
||||
@ -510,163 +360,70 @@ const AppSearchProvider = new Lang.Class({
|
||||
|
||||
createResultActor: function (resultMeta, terms) {
|
||||
let app = resultMeta['id'];
|
||||
let icon = new AppIcon(app);
|
||||
let icon = new AppWellIcon(app);
|
||||
return icon.actor;
|
||||
}
|
||||
});
|
||||
|
||||
const FolderIcon = new Lang.Class({
|
||||
Name: 'FolderIcon',
|
||||
const SettingsSearchProvider = new Lang.Class({
|
||||
Name: 'SettingsSearchProvider',
|
||||
|
||||
_init: function(dir, parentView) {
|
||||
this._dir = dir;
|
||||
this._parentView = parentView;
|
||||
|
||||
this.actor = new St.Button({ style_class: 'app-well-app app-folder',
|
||||
button_mask: St.ButtonMask.ONE,
|
||||
toggle_mode: true,
|
||||
can_focus: true,
|
||||
x_fill: true,
|
||||
y_fill: true });
|
||||
this.actor._delegate = this;
|
||||
|
||||
let label = this._dir.get_name();
|
||||
this.icon = new IconGrid.BaseIcon(label,
|
||||
{ createIcon: Lang.bind(this, this._createIcon) });
|
||||
this.actor.set_child(this.icon.actor);
|
||||
this.actor.label_actor = this.icon.label;
|
||||
|
||||
this.view = new FolderView();
|
||||
this.view.actor.reactive = false;
|
||||
_loadCategory(dir, this.view);
|
||||
this.view.loadGrid();
|
||||
|
||||
this.actor.connect('clicked', Lang.bind(this,
|
||||
function() {
|
||||
this._ensurePopup();
|
||||
this._popup.toggle();
|
||||
}));
|
||||
this.actor.connect('notify::mapped', Lang.bind(this,
|
||||
function() {
|
||||
if (!this.actor.mapped && this._popup)
|
||||
this._popup.popdown();
|
||||
}));
|
||||
_init: function() {
|
||||
this.appInfo = Gio.DesktopAppInfo.new('gnome-control-center.desktop');
|
||||
this._appSys = Shell.AppSystem.get_default();
|
||||
},
|
||||
|
||||
_createIcon: function(size) {
|
||||
return this.view.createFolderIcon(size);
|
||||
},
|
||||
|
||||
_ensurePopup: function() {
|
||||
if (this._popup)
|
||||
return;
|
||||
|
||||
let spaceTop = this.actor.y;
|
||||
let spaceBottom = this._parentView.actor.height - (this.actor.y + this.actor.height);
|
||||
let side = spaceTop > spaceBottom ? St.Side.BOTTOM : St.Side.TOP;
|
||||
|
||||
this._popup = new AppFolderPopup(this, side);
|
||||
this._parentView.addFolderPopup(this._popup);
|
||||
|
||||
// Position the popup above or below the source icon
|
||||
if (side == St.Side.BOTTOM) {
|
||||
this._popup.actor.show();
|
||||
this._popup.actor.y = this.actor.y - this._popup.actor.height;
|
||||
this._popup.actor.hide();
|
||||
} else {
|
||||
this._popup.actor.y = this.actor.y + this.actor.height;
|
||||
}
|
||||
|
||||
this._popup.connect('open-state-changed', Lang.bind(this,
|
||||
function(popup, isOpen) {
|
||||
if (!isOpen)
|
||||
this.actor.checked = false;
|
||||
}));
|
||||
},
|
||||
getResultMetas: function(prefs, callback) {
|
||||
let metas = [];
|
||||
for (let i = 0; i < prefs.length; i++) {
|
||||
let pref = prefs[i];
|
||||
metas.push({ 'id': pref,
|
||||
'name': pref.get_name(),
|
||||
'createIcon': function() { return null; }
|
||||
});
|
||||
|
||||
const AppFolderPopup = new Lang.Class({
|
||||
Name: 'AppFolderPopup',
|
||||
|
||||
_init: function(source, side) {
|
||||
this._source = source;
|
||||
this._view = source.view;
|
||||
this._arrowSide = side;
|
||||
|
||||
this._isOpen = false;
|
||||
|
||||
this.actor = new St.Widget({ layout_manager: new Clutter.BinLayout(),
|
||||
visible: false,
|
||||
// We don't want to expand really, but look
|
||||
// at the layout manager of our parent...
|
||||
//
|
||||
// DOUBLE HACK: if you set one, you automatically
|
||||
// get the effect for the other direction too, so
|
||||
// we need to set the y_align
|
||||
x_expand: true,
|
||||
y_expand: true,
|
||||
x_align: Clutter.ActorAlign.CENTER,
|
||||
y_align: Clutter.ActorAlign.START });
|
||||
this._boxPointer = new BoxPointer.BoxPointer(this._arrowSide,
|
||||
{ style_class: 'app-folder-popup-bin',
|
||||
x_fill: true,
|
||||
y_fill: true,
|
||||
x_align: St.Align.START });
|
||||
|
||||
this._boxPointer.actor.style_class = 'app-folder-popup';
|
||||
this.actor.add_actor(this._boxPointer.actor);
|
||||
this._boxPointer.bin.set_child(this._view.actor);
|
||||
|
||||
let closeButton = Util.makeCloseButton();
|
||||
closeButton.connect('clicked', Lang.bind(this, this.popdown));
|
||||
this.actor.add_actor(closeButton);
|
||||
|
||||
this._boxPointer.actor.bind_property('opacity', closeButton, 'opacity',
|
||||
GObject.BindingFlags.SYNC_CREATE);
|
||||
|
||||
source.actor.connect('destroy', Lang.bind(this,
|
||||
function() {
|
||||
this.actor.destroy();
|
||||
}));
|
||||
}
|
||||
callback(metas);
|
||||
},
|
||||
|
||||
toggle: function() {
|
||||
if (this._isOpen)
|
||||
this.popdown();
|
||||
else
|
||||
this.popup();
|
||||
getInitialResultSet: function(terms) {
|
||||
this.searchSystem.pushResults(this, this._appSys.search_settings(terms));
|
||||
},
|
||||
|
||||
popup: function() {
|
||||
if (this._isOpen)
|
||||
return;
|
||||
|
||||
this.actor.show();
|
||||
|
||||
this._boxPointer.setArrowActor(this._source.actor);
|
||||
this._boxPointer.show(BoxPointer.PopupAnimation.FADE |
|
||||
BoxPointer.PopupAnimation.SLIDE);
|
||||
|
||||
this._isOpen = true;
|
||||
this.emit('open-state-changed', true);
|
||||
getSubsearchResultSet: function(previousResults, terms) {
|
||||
this.searchSystem.pushResults(this, this._appSys.search_settings(terms));
|
||||
},
|
||||
|
||||
popdown: function() {
|
||||
if (!this._isOpen)
|
||||
return;
|
||||
activateResult: function(pref) {
|
||||
pref.activate();
|
||||
},
|
||||
|
||||
this._boxPointer.hide(BoxPointer.PopupAnimation.FADE |
|
||||
BoxPointer.PopupAnimation.SLIDE);
|
||||
this._isOpen = false;
|
||||
this.emit('open-state-changed', false);
|
||||
launchSearch: function(terms) {
|
||||
// FIXME: this should be a remote search provider
|
||||
this.appInfo.launch([], global.create_app_launch_context());
|
||||
}
|
||||
});
|
||||
Signals.addSignalMethods(AppFolderPopup.prototype);
|
||||
|
||||
const AppIcon = new Lang.Class({
|
||||
Name: 'AppIcon',
|
||||
Extends: IconGrid.BaseIcon,
|
||||
|
||||
_init : function(app, iconParams) {
|
||||
_init : function(app, params) {
|
||||
this.app = app;
|
||||
|
||||
let label = this.app.get_name();
|
||||
|
||||
this.parent(label, params);
|
||||
},
|
||||
|
||||
createIcon: function(iconSize) {
|
||||
return this.app.create_icon_texture(iconSize);
|
||||
}
|
||||
});
|
||||
|
||||
const AppWellIcon = new Lang.Class({
|
||||
Name: 'AppWellIcon',
|
||||
|
||||
_init : function(app, iconParams, onActivateOverride) {
|
||||
this.app = app;
|
||||
this.actor = new St.Button({ style_class: 'app-well-app',
|
||||
reactive: true,
|
||||
@ -676,15 +433,13 @@ const AppIcon = new Lang.Class({
|
||||
y_fill: true });
|
||||
this.actor._delegate = this;
|
||||
|
||||
if (!iconParams)
|
||||
iconParams = {};
|
||||
|
||||
iconParams['createIcon'] = Lang.bind(this, this._createIcon);
|
||||
this.icon = new IconGrid.BaseIcon(app.get_name(), iconParams);
|
||||
this.icon = new AppIcon(app, iconParams);
|
||||
this.actor.set_child(this.icon.actor);
|
||||
|
||||
this.actor.label_actor = this.icon.label;
|
||||
|
||||
// A function callback to override the default "app.activate()"; used by preferences
|
||||
this._onActivateOverride = onActivateOverride;
|
||||
this.actor.connect('button-press-event', Lang.bind(this, this._onButtonPress));
|
||||
this.actor.connect('clicked', Lang.bind(this, this._onClicked));
|
||||
this.actor.connect('popup-menu', Lang.bind(this, this._onKeyboardPopupMenu));
|
||||
@ -723,10 +478,6 @@ const AppIcon = new Lang.Class({
|
||||
this._removeMenuTimeout();
|
||||
},
|
||||
|
||||
_createIcon: function(iconSize) {
|
||||
return this.app.create_icon_texture(iconSize);
|
||||
},
|
||||
|
||||
_removeMenuTimeout: function() {
|
||||
if (this._menuTimeoutId > 0) {
|
||||
Mainloop.source_remove(this._menuTimeoutId);
|
||||
@ -784,7 +535,6 @@ const AppIcon = new Lang.Class({
|
||||
popupMenu: function() {
|
||||
this._removeMenuTimeout();
|
||||
this.actor.fake_release();
|
||||
this._draggable.fakeRelease();
|
||||
|
||||
if (!this._menu) {
|
||||
this._menu = new AppIconMenu(this);
|
||||
@ -826,13 +576,16 @@ const AppIcon = new Lang.Class({
|
||||
this.emit('launching');
|
||||
let modifiers = event.get_state();
|
||||
|
||||
if (this._onActivateOverride) {
|
||||
this._onActivateOverride(event);
|
||||
} else {
|
||||
if (modifiers & Clutter.ModifierType.CONTROL_MASK
|
||||
&& this.app.state == Shell.AppState.RUNNING) {
|
||||
this.app.open_new_window(-1);
|
||||
} else {
|
||||
this.app.activate();
|
||||
}
|
||||
|
||||
}
|
||||
Main.overview.hide();
|
||||
},
|
||||
|
||||
@ -853,7 +606,7 @@ const AppIcon = new Lang.Class({
|
||||
return this.icon.icon;
|
||||
}
|
||||
});
|
||||
Signals.addSignalMethods(AppIcon.prototype);
|
||||
Signals.addSignalMethods(AppWellIcon.prototype);
|
||||
|
||||
const AppIconMenu = new Lang.Class({
|
||||
Name: 'AppIconMenu',
|
||||
|
@ -1,724 +0,0 @@
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
|
||||
const Clutter = imports.gi.Clutter;
|
||||
const GDesktopEnums = imports.gi.GDesktopEnums;
|
||||
const Gio = imports.gi.Gio;
|
||||
const GLib = imports.gi.GLib;
|
||||
const GnomeDesktop = imports.gi.GnomeDesktop;
|
||||
const Lang = imports.lang;
|
||||
const Meta = imports.gi.Meta;
|
||||
const Signals = imports.signals;
|
||||
|
||||
const Main = imports.ui.main;
|
||||
const Params = imports.misc.params;
|
||||
const Tweener = imports.ui.tweener;
|
||||
|
||||
const BACKGROUND_SCHEMA = 'org.gnome.desktop.background';
|
||||
const PRIMARY_COLOR_KEY = 'primary-color';
|
||||
const SECONDARY_COLOR_KEY = 'secondary-color';
|
||||
const COLOR_SHADING_TYPE_KEY = 'color-shading-type';
|
||||
const BACKGROUND_STYLE_KEY = 'picture-options';
|
||||
const PICTURE_OPACITY_KEY = 'picture-opacity';
|
||||
const PICTURE_URI_KEY = 'picture-uri';
|
||||
|
||||
const FADE_ANIMATION_TIME = 1.0;
|
||||
|
||||
// These parameters affect how often we redraw.
|
||||
// The first is how different (percent crossfaded) the slide show
|
||||
// has to look before redrawing and the second is the minimum
|
||||
// frequency (in seconds) we're willing to wake up
|
||||
const ANIMATION_OPACITY_STEP_INCREMENT = 4.0;
|
||||
const ANIMATION_MIN_WAKEUP_INTERVAL = 1.0;
|
||||
|
||||
let _backgroundCache = null;
|
||||
|
||||
const BackgroundCache = new Lang.Class({
|
||||
Name: 'BackgroundCache',
|
||||
|
||||
_init: function() {
|
||||
this._patterns = [];
|
||||
this._images = [];
|
||||
this._fileMonitors = {};
|
||||
},
|
||||
|
||||
getPatternContent: function(params) {
|
||||
params = Params.parse(params, { monitorIndex: 0,
|
||||
color: null,
|
||||
secondColor: null,
|
||||
shadingType: null,
|
||||
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;
|
||||
|
||||
if (!params.color.equal(this._patterns[i].get_color()))
|
||||
continue;
|
||||
|
||||
if (params.shadingType != GDesktopEnums.BackgroundShading.SOLID &&
|
||||
!params.secondColor.equal(this._patterns[i].get_second_color()))
|
||||
continue;
|
||||
|
||||
candidateContent = this._patterns[i];
|
||||
|
||||
if (params.effects != this._patterns[i].effects)
|
||||
continue;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (candidateContent) {
|
||||
content = candidateContent.copy(params.monitorIndex, params.effects);
|
||||
} else {
|
||||
content = new Meta.Background({ meta_screen: global.screen,
|
||||
monitor: params.monitorIndex,
|
||||
effects: params.effects });
|
||||
|
||||
if (params.shadingType == GDesktopEnums.BackgroundShading.SOLID) {
|
||||
content.load_color(params.color);
|
||||
} else {
|
||||
content.load_gradient(params.shadingType, params.color, params.secondColor);
|
||||
}
|
||||
|
||||
this._patterns.push(content);
|
||||
}
|
||||
|
||||
return content;
|
||||
},
|
||||
|
||||
_monitorFile: function(filename) {
|
||||
if (this._fileMonitors[filename])
|
||||
return;
|
||||
|
||||
let file = Gio.File.new_for_path(filename);
|
||||
let monitor = file.monitor(Gio.FileMonitorFlags.NONE, null);
|
||||
|
||||
let signalId = monitor.connect('changed',
|
||||
Lang.bind(this, function() {
|
||||
for (let i = 0; i < this._images.length; i++) {
|
||||
if (this._images[i].get_filename() == filename)
|
||||
this._images.splice(i, 1);
|
||||
}
|
||||
|
||||
monitor.disconnect(signalId);
|
||||
|
||||
this.emit('file-changed', filename);
|
||||
}));
|
||||
|
||||
this._fileMonitors[filename] = monitor;
|
||||
},
|
||||
|
||||
_removeContent: function(contentList, content) {
|
||||
let index = contentList.indexOf(content);
|
||||
|
||||
if (index >= 0)
|
||||
contentList.splice(index, 1);
|
||||
},
|
||||
|
||||
removePatternContent: function(content) {
|
||||
this._removeContent(this._patterns, content);
|
||||
},
|
||||
|
||||
removeImageContent: function(content) {
|
||||
this._removeContent(this._images, content);
|
||||
},
|
||||
|
||||
getImageContent: function(params) {
|
||||
params = Params.parse(params, { monitorIndex: 0,
|
||||
style: null,
|
||||
filename: null,
|
||||
effects: Meta.BackgroundEffects.NONE,
|
||||
cancellable: null,
|
||||
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;
|
||||
|
||||
if (this._images[i].get_filename() != params.filename)
|
||||
continue;
|
||||
|
||||
if (params.style == GDesktopEnums.BackgroundStyle.SPANNED &&
|
||||
this._images[i].monitor_index != this._monitorIndex)
|
||||
continue;
|
||||
|
||||
candidateContent = this._images[i];
|
||||
|
||||
if (params.effects != this._images[i].effects)
|
||||
continue;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (candidateContent) {
|
||||
content = candidateContent.copy(params.monitorIndex, params.effects);
|
||||
|
||||
if (params.cancellable && params.cancellable.is_cancelled())
|
||||
content = null;
|
||||
|
||||
if (params.onFinished)
|
||||
params.onFinished(content);
|
||||
} else {
|
||||
content = new Meta.Background({ meta_screen: global.screen,
|
||||
monitor: params.monitorIndex,
|
||||
effects: params.effects });
|
||||
|
||||
content.load_file_async(params.filename,
|
||||
params.style,
|
||||
params.cancellable,
|
||||
Lang.bind(this,
|
||||
function(object, result) {
|
||||
try {
|
||||
content.load_file_finish(result);
|
||||
|
||||
this._monitorFile(params.filename);
|
||||
this._images.push(content);
|
||||
} catch(e) {
|
||||
content = null;
|
||||
}
|
||||
|
||||
if (params.onFinished)
|
||||
params.onFinished(content);
|
||||
}));
|
||||
}
|
||||
},
|
||||
|
||||
getAnimation: function(params) {
|
||||
params = Params.parse(params, { filename: null,
|
||||
onLoaded: null });
|
||||
|
||||
if (this._animationFilename == params.filename) {
|
||||
if (params.onLoaded) {
|
||||
GLib.idle_add(GLib.PRIORITY_DEFAULT, Lang.bind(this, function() {
|
||||
params.onLoaded(this._animation);
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
let animation = new Animation({ filename: params.filename });
|
||||
|
||||
animation.load(Lang.bind(this, function() {
|
||||
this._monitorFile(params.filename);
|
||||
this._animationFilename = params.filename;
|
||||
this._animation = animation;
|
||||
|
||||
if (params.onLoaded) {
|
||||
GLib.idle_add(GLib.PRIORITY_DEFAULT, Lang.bind(this, function() {
|
||||
params.onLoaded(this._animation);
|
||||
}));
|
||||
}
|
||||
}));
|
||||
}
|
||||
});
|
||||
Signals.addSignalMethods(BackgroundCache.prototype);
|
||||
|
||||
function getBackgroundCache() {
|
||||
if (!_backgroundCache)
|
||||
_backgroundCache = new BackgroundCache();
|
||||
return _backgroundCache;
|
||||
}
|
||||
|
||||
const Background = new Lang.Class({
|
||||
Name: 'Background',
|
||||
|
||||
_init: function(params) {
|
||||
params = Params.parse(params, { monitorIndex: 0,
|
||||
layoutManager: Main.layoutManager,
|
||||
effects: Meta.BackgroundEffects.NONE });
|
||||
this.actor = new Meta.BackgroundGroup();
|
||||
this.actor._delegate = this;
|
||||
|
||||
this._destroySignalId = this.actor.connect('destroy',
|
||||
Lang.bind(this, this._destroy));
|
||||
|
||||
this._settings = new Gio.Settings({ schema: BACKGROUND_SCHEMA });
|
||||
this._monitorIndex = params.monitorIndex;
|
||||
this._layoutManager = params.layoutManager;
|
||||
this._effects = params.effects;
|
||||
this._fileWatches = {};
|
||||
this._pattern = null;
|
||||
// contains a single image for static backgrounds and
|
||||
// two images (from and to) for slide shows
|
||||
this._images = {};
|
||||
|
||||
this._brightness = 1.0;
|
||||
this._vignetteSharpness = 0.2;
|
||||
this._saturation = 1.0;
|
||||
this._cancellable = new Gio.Cancellable();
|
||||
this.isLoaded = false;
|
||||
|
||||
this._settings.connect('changed', Lang.bind(this, function() {
|
||||
this.emit('changed');
|
||||
}));
|
||||
|
||||
this._load();
|
||||
},
|
||||
|
||||
_destroy: function() {
|
||||
this._cancellable.cancel();
|
||||
|
||||
if (this._animationUpdateTimeoutId) {
|
||||
GLib.source_remove (this._animationUpdateTimeoutId);
|
||||
this._animationUpdateTimeoutId = 0
|
||||
}
|
||||
|
||||
let i;
|
||||
let keys = Object.keys(this._fileWatches);
|
||||
for (i = 0; i < keys.length; i++) {
|
||||
this._cache.disconnect(this._fileWatches[keys[i]]);
|
||||
}
|
||||
this._fileWatches = null;
|
||||
|
||||
if (this._pattern) {
|
||||
if (this._pattern.content)
|
||||
this._cache.removePatternContent(this._pattern.content);
|
||||
|
||||
this._pattern.destroy();
|
||||
this._pattern = null;
|
||||
}
|
||||
|
||||
keys = Object.keys(this._images);
|
||||
for (i = 0; i < keys.length; i++) {
|
||||
let actor = this._images[keys[i]];
|
||||
|
||||
if (actor.content)
|
||||
this._cache.removeImageContent(actor.content);
|
||||
|
||||
actor.destroy();
|
||||
this._images[keys[i]] = null;
|
||||
}
|
||||
|
||||
this.actor.disconnect(this._destroySignalId);
|
||||
this._destroySignalId = 0;
|
||||
},
|
||||
|
||||
_setLoaded: function() {
|
||||
if (this.isLoaded)
|
||||
return;
|
||||
|
||||
this.isLoaded = true;
|
||||
|
||||
GLib.idle_add(GLib.PRIORITY_DEFAULT, Lang.bind(this, function() {
|
||||
this.emit('loaded');
|
||||
return false;
|
||||
}));
|
||||
},
|
||||
|
||||
_loadPattern: function() {
|
||||
let colorString, res, color, secondColor;
|
||||
|
||||
colorString = this._settings.get_string(PRIMARY_COLOR_KEY);
|
||||
[res, color] = Clutter.Color.from_string(colorString);
|
||||
colorString = this._settings.get_string(SECONDARY_COLOR_KEY);
|
||||
[res, secondColor] = Clutter.Color.from_string(colorString);
|
||||
|
||||
let shadingType = this._settings.get_enum(COLOR_SHADING_TYPE_KEY);
|
||||
|
||||
let content = this._cache.getPatternContent({ monitorIndex: this._monitorIndex,
|
||||
effects: this._effects,
|
||||
color: color,
|
||||
secondColor: secondColor,
|
||||
shadingType: shadingType });
|
||||
|
||||
this._pattern = new Meta.BackgroundActor();
|
||||
this.actor.add_child(this._pattern);
|
||||
|
||||
this._pattern.content = content;
|
||||
},
|
||||
|
||||
_watchCacheFile: function(filename) {
|
||||
if (this._fileWatches[filename])
|
||||
return;
|
||||
|
||||
let signalId = this._cache.connect('file-changed',
|
||||
Lang.bind(this, function(cache, changedFile) {
|
||||
if (changedFile == filename) {
|
||||
this.emit('changed');
|
||||
}
|
||||
}));
|
||||
this._fileWatches[filename] = signalId;
|
||||
},
|
||||
|
||||
_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;
|
||||
this.actor.add_child(actor);
|
||||
|
||||
this._images[index] = actor;
|
||||
this._watchCacheFile(filename);
|
||||
},
|
||||
|
||||
_updateImage: function(content, index, filename) {
|
||||
content.saturation = this._saturation;
|
||||
content.brightness = this._brightness;
|
||||
content.vignette_sharpness = this._vignetteSharpness;
|
||||
|
||||
this._images[index].content = content;
|
||||
this._watchCacheFile(filename);
|
||||
},
|
||||
|
||||
_updateAnimationProgress: function() {
|
||||
if (this._images[1]) {
|
||||
this._images[1].raise_top();
|
||||
this._images[1].opacity = this._animation.transitionProgress * 255;
|
||||
}
|
||||
|
||||
this._queueAnimationUpdate();
|
||||
},
|
||||
|
||||
_updateAnimation: function() {
|
||||
this._animationUpdateTimeoutId = 0;
|
||||
|
||||
let files = this._animation.getKeyFrameFiles(this._layoutManager.monitors[this._monitorIndex]);
|
||||
|
||||
if (!files) {
|
||||
this._setLoaded();
|
||||
this._queueAnimationUpdate();
|
||||
return;
|
||||
}
|
||||
|
||||
let numPendingImages = files.length;
|
||||
for (let i = 0; i < files.length; i++) {
|
||||
if (this._images[i] && this._images[i].content &&
|
||||
this._images[i].content.get_filename() == files[i]) {
|
||||
|
||||
numPendingImages--;
|
||||
if (numPendingImages == 0)
|
||||
this._updateAnimationProgress();
|
||||
continue;
|
||||
}
|
||||
this._cache.getImageContent({ monitorIndex: this._monitorIndex,
|
||||
effects: this._effects,
|
||||
style: this._style,
|
||||
filename: files[i],
|
||||
cancellable: this._cancellable,
|
||||
onFinished: Lang.bind(this, function(content) {
|
||||
numPendingImages--;
|
||||
|
||||
if (!content) {
|
||||
this._setLoaded();
|
||||
if (numPendingImages == 0)
|
||||
this._updateAnimationProgress();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this._images[i]) {
|
||||
this._addImage(content, i, files[i]);
|
||||
} else {
|
||||
this._updateImage(content, i, files[i]);
|
||||
}
|
||||
|
||||
if (numPendingImages == 0) {
|
||||
this._setLoaded();
|
||||
this._updateAnimationProgress();
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
_queueAnimationUpdate: function() {
|
||||
if (this._animationUpdateTimeoutId != 0)
|
||||
return;
|
||||
|
||||
if (!this._cancellable || this._cancellable.is_cancelled())
|
||||
return;
|
||||
|
||||
if (!this._animation.duration)
|
||||
return;
|
||||
|
||||
let interval = Math.max(ANIMATION_MIN_WAKEUP_INTERVAL * 1000,
|
||||
ANIMATION_OPACITY_STEP_INCREMENT / this._animation.duration);
|
||||
this._animationUpdateTimeoutId = GLib.timeout_add(GLib.PRIORITY_DEFAULT,
|
||||
interval,
|
||||
Lang.bind(this, function() {
|
||||
this._animationUpdateTimeoutId = 0;
|
||||
this._updateAnimation();
|
||||
return false;
|
||||
}));
|
||||
},
|
||||
|
||||
_loadAnimation: function(filename) {
|
||||
this._cache.getAnimation({ filename: filename,
|
||||
onLoaded: Lang.bind(this, function(animation) {
|
||||
this._animation = animation;
|
||||
|
||||
if (!this._animation || this._cancellable.is_cancelled()) {
|
||||
this._setLoaded();
|
||||
return;
|
||||
}
|
||||
|
||||
this._updateAnimation();
|
||||
this._watchCacheFile(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) {
|
||||
if (!this._cancellable.is_cancelled())
|
||||
this._loadAnimation(filename);
|
||||
return;
|
||||
}
|
||||
|
||||
this._addImage(content, 0, filename);
|
||||
this._setLoaded();
|
||||
})
|
||||
});
|
||||
|
||||
},
|
||||
|
||||
_load: function () {
|
||||
this._cache = getBackgroundCache();
|
||||
|
||||
this._loadPattern(this._cache);
|
||||
|
||||
this._style = this._settings.get_enum(BACKGROUND_STYLE_KEY);
|
||||
if (this._style == GDesktopEnums.BackgroundStyle.NONE) {
|
||||
this._setLoaded();
|
||||
return;
|
||||
}
|
||||
|
||||
let uri = this._settings.get_string(PICTURE_URI_KEY);
|
||||
let filename = Gio.File.new_for_uri(uri).get_path();
|
||||
|
||||
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;
|
||||
},
|
||||
|
||||
set brightness(factor) {
|
||||
this._brightness = factor;
|
||||
if (this._pattern && this._pattern.content)
|
||||
this._pattern.content.brightness = factor;
|
||||
|
||||
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.brightness = factor;
|
||||
}
|
||||
},
|
||||
|
||||
get vignetteSharpness() {
|
||||
return this._vignetteSharpness;
|
||||
},
|
||||
|
||||
set vignetteSharpness(sharpness) {
|
||||
this._vignetteSharpness = sharpness;
|
||||
if (this._pattern && this._pattern.content)
|
||||
this._pattern.content.vignette_sharpness = sharpness;
|
||||
|
||||
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.vignette_sharpness = sharpness;
|
||||
}
|
||||
}
|
||||
});
|
||||
Signals.addSignalMethods(Background.prototype);
|
||||
|
||||
const SystemBackground = new Lang.Class({
|
||||
Name: 'SystemBackground',
|
||||
|
||||
_init: function() {
|
||||
this._cache = getBackgroundCache();
|
||||
this.actor = new Meta.BackgroundActor();
|
||||
|
||||
this._cache.getImageContent({ style: GDesktopEnums.BackgroundStyle.WALLPAPER,
|
||||
filename: global.datadir + '/theme/noise-texture.png',
|
||||
effects: Meta.BackgroundEffects.NONE,
|
||||
onFinished: Lang.bind(this, function(content) {
|
||||
this.actor.content = content;
|
||||
this.emit('loaded');
|
||||
})
|
||||
});
|
||||
}
|
||||
});
|
||||
Signals.addSignalMethods(SystemBackground.prototype);
|
||||
|
||||
const Animation = new Lang.Class({
|
||||
Name: 'Animation',
|
||||
|
||||
_init: function(params) {
|
||||
params = Params.parse(params, { filename: null });
|
||||
|
||||
this.filename = params.filename;
|
||||
this._keyFrames = [];
|
||||
this.duration = 0.0;
|
||||
this.transitionProgress = 0.0;
|
||||
this.loaded = false;
|
||||
},
|
||||
|
||||
load: function(callback) {
|
||||
let file = Gio.File.new_for_path(this.filename);
|
||||
|
||||
this._show = new GnomeDesktop.BGSlideShow({ filename: this.filename });
|
||||
|
||||
this._show.load_async(null,
|
||||
Lang.bind(this,
|
||||
function(object, result) {
|
||||
this.duration = this._show.get_total_duration();
|
||||
this.loaded = true;
|
||||
if (callback)
|
||||
callback();
|
||||
}));
|
||||
},
|
||||
|
||||
getKeyFrameFiles: function(monitor) {
|
||||
if (!this._show)
|
||||
return null;
|
||||
|
||||
if (this._show.get_num_slides() < 1)
|
||||
return null;
|
||||
|
||||
let [progress, duration, isFixed, file1, file2] = this._show.get_current_slide(monitor.width, monitor.height);
|
||||
|
||||
this.transitionProgress = progress;
|
||||
|
||||
let files = [];
|
||||
|
||||
if (file1)
|
||||
files.push(file1);
|
||||
|
||||
if (file2)
|
||||
files.push(file2);
|
||||
|
||||
return files;
|
||||
},
|
||||
});
|
||||
Signals.addSignalMethods(Animation.prototype);
|
||||
|
||||
const BackgroundManager = new Lang.Class({
|
||||
Name: 'BackgroundManager',
|
||||
|
||||
_init: function(params) {
|
||||
params = Params.parse(params, { container: null,
|
||||
layoutManager: Main.layoutManager,
|
||||
monitorIndex: null,
|
||||
effects: Meta.BackgroundEffects.NONE,
|
||||
controlPosition: true });
|
||||
|
||||
this._container = params.container;
|
||||
this._layoutManager = params.layoutManager;
|
||||
this._effects = params.effects;
|
||||
this._monitorIndex = params.monitorIndex;
|
||||
this._controlPosition = params.controlPosition;
|
||||
|
||||
this.background = this._createBackground();
|
||||
this._newBackground = null;
|
||||
this._loadedSignalId = 0;
|
||||
this._changedSignalId = 0;
|
||||
},
|
||||
|
||||
destroy: function() {
|
||||
if (this._loadedSignalId)
|
||||
this._newBackground.disconnect(this._loadedSignalId);
|
||||
|
||||
if (this._changedSignalId)
|
||||
this.background.disconnect(this._changedSignalId);
|
||||
|
||||
if (this._newBackground) {
|
||||
this._newBackground.actor.destroy();
|
||||
this._newBackground = null;
|
||||
}
|
||||
|
||||
if (this.background) {
|
||||
this.background.actor.destroy();
|
||||
this.background = null;
|
||||
}
|
||||
},
|
||||
|
||||
_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;
|
||||
|
||||
let signalId = newBackground.connect('loaded',
|
||||
Lang.bind(this, function() {
|
||||
newBackground.disconnect(signalId);
|
||||
Tweener.addTween(background.actor,
|
||||
{ opacity: 0,
|
||||
time: FADE_ANIMATION_TIME,
|
||||
transition: 'easeOutQuad',
|
||||
onComplete: Lang.bind(this, function() {
|
||||
this.background = newBackground;
|
||||
this._newBackground = null;
|
||||
background.actor.destroy();
|
||||
this.emit('changed');
|
||||
})
|
||||
});
|
||||
}));
|
||||
this._loadedSignalId = signalId;
|
||||
|
||||
this._newBackground = newBackground;
|
||||
},
|
||||
|
||||
_createBackground: function() {
|
||||
let background = new Background({ monitorIndex: this._monitorIndex,
|
||||
layoutManager: this._layoutManager,
|
||||
effects: this._effects });
|
||||
this._container.add_child(background.actor);
|
||||
|
||||
let monitor = this._layoutManager.monitors[this._monitorIndex];
|
||||
|
||||
background.actor.set_size(monitor.width, monitor.height);
|
||||
if (this._controlPosition) {
|
||||
background.actor.set_position(monitor.x, monitor.y);
|
||||
background.actor.lower_bottom();
|
||||
}
|
||||
|
||||
let signalId = background.connect('changed', Lang.bind(this, function() {
|
||||
background.disconnect(signalId);
|
||||
this._updateBackground(background, this._monitorIndex);
|
||||
}));
|
||||
|
||||
this._changedSignalId = signalId;
|
||||
|
||||
return background;
|
||||
},
|
||||
});
|
||||
Signals.addSignalMethods(BackgroundManager.prototype);
|
@ -1,58 +0,0 @@
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
|
||||
const Clutter = imports.gi.Clutter;
|
||||
const Lang = imports.lang;
|
||||
const St = imports.gi.St;
|
||||
const Shell = imports.gi.Shell;
|
||||
|
||||
const BoxPointer = imports.ui.boxpointer;
|
||||
const Main = imports.ui.main;
|
||||
const PopupMenu = imports.ui.popupMenu;
|
||||
|
||||
const BackgroundMenu = new Lang.Class({
|
||||
Name: 'BackgroundMenu',
|
||||
Extends: PopupMenu.PopupMenu,
|
||||
|
||||
_init: function(source) {
|
||||
this.parent(source, 0, St.Side.TOP);
|
||||
|
||||
this.addSettingsAction(_("Settings"), 'gnome-control-center.desktop');
|
||||
this.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
|
||||
this.addSettingsAction(_("Change Background…"), 'gnome-background-panel.desktop');
|
||||
|
||||
this.actor.add_style_class_name('background-menu');
|
||||
|
||||
Main.uiGroup.add_actor(this.actor);
|
||||
this.actor.hide();
|
||||
}
|
||||
});
|
||||
|
||||
function addBackgroundMenu(actor) {
|
||||
let cursor = new St.Bin({ opacity: 0 });
|
||||
Main.uiGroup.add_actor(cursor);
|
||||
|
||||
actor.reactive = true;
|
||||
actor._backgroundMenu = new BackgroundMenu(cursor);
|
||||
actor._backgroundManager = new PopupMenu.PopupMenuManager({ actor: actor });
|
||||
actor._backgroundManager.addMenu(actor._backgroundMenu);
|
||||
|
||||
function openMenu() {
|
||||
let [x, y] = global.get_pointer();
|
||||
cursor.set_position(x, y);
|
||||
actor._backgroundMenu.open(BoxPointer.PopupAnimation.NONE);
|
||||
}
|
||||
|
||||
let clickAction = new Clutter.ClickAction();
|
||||
clickAction.connect('long-press', function(action, actor, state) {
|
||||
if (state == Clutter.LongPressState.QUERY)
|
||||
return action.get_button() == 1 && !actor._backgroundMenu.isOpen;
|
||||
if (state == Clutter.LongPressState.ACTIVATE)
|
||||
openMenu();
|
||||
return true;
|
||||
});
|
||||
clickAction.connect('clicked', function(action) {
|
||||
if (action.get_button() == 3)
|
||||
openMenu();
|
||||
});
|
||||
actor.add_action(clickAction);
|
||||
}
|
@ -38,7 +38,6 @@ const BoxPointer = new Lang.Class({
|
||||
this._arrowSide = arrowSide;
|
||||
this._userArrowSide = arrowSide;
|
||||
this._arrowOrigin = 0;
|
||||
this._arrowActor = null;
|
||||
this.actor = new St.Bin({ x_fill: true,
|
||||
y_fill: true });
|
||||
this._container = new Shell.GenericContainer();
|
||||
@ -221,27 +220,31 @@ const BoxPointer = new Lang.Class({
|
||||
this.bin.allocate(childBox, flags);
|
||||
|
||||
if (this._sourceActor && this._sourceActor.mapped) {
|
||||
this._reposition();
|
||||
this._updateFlip();
|
||||
this._reposition(this._sourceActor, this._arrowAlignment);
|
||||
|
||||
if (this._shouldFlip()) {
|
||||
switch (this._arrowSide) {
|
||||
case St.Side.TOP:
|
||||
this._arrowSide = St.Side.BOTTOM;
|
||||
break;
|
||||
case St.Side.BOTTOM:
|
||||
this._arrowSide = St.Side.TOP;
|
||||
break;
|
||||
case St.Side.LEFT:
|
||||
this._arrowSide = St.Side.RIGHT;
|
||||
break;
|
||||
case St.Side.RIGHT:
|
||||
this._arrowSide = St.Side.LEFT;
|
||||
break;
|
||||
}
|
||||
this._reposition(this._sourceActor, this._arrowAlignment);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
_drawBorder: function(area) {
|
||||
let themeNode = this.actor.get_theme_node();
|
||||
|
||||
if (this._arrowActor) {
|
||||
let [sourceX, sourceY] = this._arrowActor.get_transformed_position();
|
||||
let [sourceWidth, sourceHeight] = this._arrowActor.get_transformed_size();
|
||||
let [absX, absY] = this.actor.get_transformed_position();
|
||||
|
||||
if (this._arrowSide == St.Side.TOP ||
|
||||
this._arrowSide == St.Side.BOTTOM) {
|
||||
this._arrowOrigin = sourceX - absX + sourceWidth / 2;
|
||||
} else {
|
||||
this._arrowOrigin = sourceY - absY + sourceHeight / 2;
|
||||
}
|
||||
}
|
||||
|
||||
let borderWidth = themeNode.get_length('-arrow-border-width');
|
||||
let base = themeNode.get_length('-arrow-base');
|
||||
let rise = themeNode.get_length('-arrow-rise');
|
||||
@ -402,11 +405,11 @@ const BoxPointer = new Lang.Class({
|
||||
cr.setLineWidth(borderWidth);
|
||||
cr.stroke();
|
||||
}
|
||||
|
||||
cr.$dispose();
|
||||
},
|
||||
|
||||
setPosition: function(sourceActor, alignment) {
|
||||
this._arrowSide = this._userArrowSide;
|
||||
|
||||
// We need to show it now to force an allocation,
|
||||
// so that we can query the correct size.
|
||||
this.actor.show();
|
||||
@ -414,8 +417,7 @@ const BoxPointer = new Lang.Class({
|
||||
this._sourceActor = sourceActor;
|
||||
this._arrowAlignment = alignment;
|
||||
|
||||
this._reposition();
|
||||
this._updateFlip();
|
||||
this._reposition(sourceActor, alignment);
|
||||
},
|
||||
|
||||
setSourceAlignment: function(alignment) {
|
||||
@ -427,10 +429,7 @@ const BoxPointer = new Lang.Class({
|
||||
this.setPosition(this._sourceActor, this._arrowAlignment);
|
||||
},
|
||||
|
||||
_reposition: function() {
|
||||
let sourceActor = this._sourceActor;
|
||||
let alignment = this._arrowAlignment;
|
||||
|
||||
_reposition: function(sourceActor, alignment) {
|
||||
// Position correctly relative to the sourceActor
|
||||
let sourceNode = sourceActor.get_theme_node();
|
||||
let sourceContentBox = sourceNode.get_content_box(sourceActor.get_allocation_box());
|
||||
@ -551,20 +550,10 @@ const BoxPointer = new Lang.Class({
|
||||
}
|
||||
},
|
||||
|
||||
// @actor: an actor relative to which the arrow is positioned.
|
||||
// Differently from setPosition, this will not move the boxpointer itself,
|
||||
// on the arrow
|
||||
setArrowActor: function(actor) {
|
||||
if (this._arrowActor != actor) {
|
||||
this._arrowActor = actor;
|
||||
this._border.queue_repaint();
|
||||
}
|
||||
},
|
||||
|
||||
_shiftActor : function() {
|
||||
// Since the position of the BoxPointer depends on the allocated size
|
||||
// of the BoxPointer and the position of the source actor, trying
|
||||
// to position the BoxPointer via the x/y properties will result in
|
||||
// to position the BoxPoiner via the x/y properties will result in
|
||||
// allocation loops and warnings. Instead we do the positioning via
|
||||
// the anchor point, which is independent of allocation, and leave
|
||||
// x == y == 0.
|
||||
@ -572,47 +561,37 @@ const BoxPointer = new Lang.Class({
|
||||
-(this._yPosition + this._yOffset));
|
||||
},
|
||||
|
||||
_calculateArrowSide: function(arrowSide) {
|
||||
_shouldFlip: function() {
|
||||
let sourceAllocation = Shell.util_get_transformed_allocation(this._sourceActor);
|
||||
let [minWidth, minHeight, boxWidth, boxHeight] = this._container.get_preferred_size();
|
||||
let boxAllocation = Shell.util_get_transformed_allocation(this.actor);
|
||||
let boxWidth = boxAllocation.x2 - boxAllocation.x1;
|
||||
let boxHeight = boxAllocation.y2 - boxAllocation.y1;
|
||||
let monitor = Main.layoutManager.findMonitorForActor(this.actor);
|
||||
|
||||
switch (arrowSide) {
|
||||
switch (this._arrowSide) {
|
||||
case St.Side.TOP:
|
||||
if (sourceAllocation.y2 + boxHeight > monitor.y + monitor.height &&
|
||||
if (boxAllocation.y2 > monitor.y + monitor.height &&
|
||||
boxHeight < sourceAllocation.y1 - monitor.y)
|
||||
return St.Side.BOTTOM;
|
||||
return true;
|
||||
break;
|
||||
case St.Side.BOTTOM:
|
||||
if (sourceAllocation.y1 - boxHeight < monitor.y &&
|
||||
if (boxAllocation.y1 < monitor.y &&
|
||||
boxHeight < monitor.y + monitor.height - sourceAllocation.y2)
|
||||
return St.Side.TOP;
|
||||
return true;
|
||||
break;
|
||||
case St.Side.LEFT:
|
||||
if (sourceAllocation.y2 + boxWidth > monitor.x + monitor.width &&
|
||||
if (boxAllocation.x2 > monitor.x + monitor.width &&
|
||||
boxWidth < sourceAllocation.x1 - monitor.x)
|
||||
return St.Side.RIGHT;
|
||||
return true;
|
||||
break;
|
||||
case St.Side.RIGHT:
|
||||
if (sourceAllocation.y1 - boxWidth < monitor.x &&
|
||||
if (boxAllocation.x1 < monitor.x &&
|
||||
boxWidth < monitor.x + monitor.width - sourceAllocation.x2)
|
||||
return St.Side.LEFT;
|
||||
return true;
|
||||
break;
|
||||
}
|
||||
|
||||
return arrowSide;
|
||||
},
|
||||
|
||||
_updateFlip: function() {
|
||||
let arrowSide = this._calculateArrowSide(this._userArrowSide);
|
||||
if (this._arrowSide != arrowSide) {
|
||||
this._arrowSide = arrowSide;
|
||||
this._reposition();
|
||||
Meta.later_add(Meta.LaterType.BEFORE_REDRAW, Lang.bind(this, function() {
|
||||
this._container.queue_relayout();
|
||||
return false;
|
||||
}));
|
||||
}
|
||||
},
|
||||
|
||||
set xOffset(offset) {
|
||||
|
@ -2,7 +2,6 @@
|
||||
|
||||
const Clutter = imports.gi.Clutter;
|
||||
const Gio = imports.gi.Gio;
|
||||
const GLib = imports.gi.GLib;
|
||||
const Lang = imports.lang;
|
||||
const St = imports.gi.St;
|
||||
const Signals = imports.signals;
|
||||
@ -63,18 +62,15 @@ function _formatEventTime(event, clockFormat) {
|
||||
} else {
|
||||
switch (clockFormat) {
|
||||
case '24h':
|
||||
/* Translators: Shown in calendar event list, if 24h format,
|
||||
\u2236 is a ratio character, similar to : */
|
||||
ret = event.date.toLocaleFormat(C_("event list time", "%H\u2236%M"));
|
||||
/* Translators: Shown in calendar event list, if 24h format */
|
||||
ret = event.date.toLocaleFormat(C_("event list time", "%H:%M"));
|
||||
break;
|
||||
|
||||
default:
|
||||
/* explicit fall-through */
|
||||
case '12h':
|
||||
/* Transators: Shown in calendar event list, if 12h format,
|
||||
\u2236 is a ratio character, similar to : and \u2009 is
|
||||
a thin space */
|
||||
ret = event.date.toLocaleFormat(C_("event list time", "%l\u2236%M\u2009%p"));
|
||||
/* Transators: Shown in calendar event list, if 12h format */
|
||||
ret = event.date.toLocaleFormat(C_("event list time", "%l:%M %p"));
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -197,12 +193,15 @@ const CalendarServerIface = <interface name="org.gnome.Shell.CalendarServer">
|
||||
const CalendarServerInfo = Gio.DBusInterfaceInfo.new_for_xml(CalendarServerIface);
|
||||
|
||||
function CalendarServer() {
|
||||
return new Gio.DBusProxy({ g_connection: Gio.DBus.session,
|
||||
var self = new Gio.DBusProxy({ g_connection: Gio.DBus.session,
|
||||
g_interface_name: CalendarServerInfo.name,
|
||||
g_interface_info: CalendarServerInfo,
|
||||
g_name: 'org.gnome.Shell.CalendarServer',
|
||||
g_object_path: '/org/gnome/Shell/CalendarServer',
|
||||
g_flags: Gio.DBusProxyFlags.DO_NOT_LOAD_PROPERTIES });
|
||||
|
||||
self.init(null);
|
||||
return self;
|
||||
}
|
||||
|
||||
function _datesEqual(a, b) {
|
||||
@ -230,16 +229,7 @@ const DBusEventSource = new Lang.Class({
|
||||
_init: function() {
|
||||
this._resetCache();
|
||||
|
||||
this._initialized = false;
|
||||
this._dbusProxy = new CalendarServer();
|
||||
this._dbusProxy.init_async(GLib.PRIORITY_DEFAULT, null, Lang.bind(this, function(object, result) {
|
||||
try {
|
||||
this._dbusProxy.init_finish(result);
|
||||
} catch(e) {
|
||||
log('Error loading calendars: ' + e.message);
|
||||
return;
|
||||
}
|
||||
|
||||
this._dbusProxy.connectSignal('Changed', Lang.bind(this, this._onChanged));
|
||||
|
||||
this._dbusProxy.connect('notify::g-name-owner', Lang.bind(this, function() {
|
||||
@ -248,10 +238,6 @@ const DBusEventSource = new Lang.Class({
|
||||
else
|
||||
this._onNameVanished();
|
||||
}));
|
||||
|
||||
this._initialized = true;
|
||||
this._onNameAppeared();
|
||||
}));
|
||||
},
|
||||
|
||||
_resetCache: function() {
|
||||
@ -297,10 +283,6 @@ const DBusEventSource = new Lang.Class({
|
||||
},
|
||||
|
||||
_loadEvents: function(forceReload) {
|
||||
// Ignore while loading
|
||||
if (!this._initialized)
|
||||
return;
|
||||
|
||||
if (this._curRequestBegin && this._curRequestEnd){
|
||||
let callFlags = Gio.DBusCallFlags.NO_AUTO_START;
|
||||
if (forceReload)
|
||||
|
@ -8,6 +8,7 @@ const Params = imports.misc.params;
|
||||
const Shell = imports.gi.Shell;
|
||||
|
||||
const GnomeSession = imports.misc.gnomeSession;
|
||||
const LoginManager = imports.misc.loginManager;
|
||||
const Main = imports.ui.main;
|
||||
const ShellMountOperation = imports.ui.shellMountOperation;
|
||||
|
||||
@ -32,6 +33,7 @@ const AutomountManager = new Lang.Class({
|
||||
Lang.bind(this, this._InhibitorsChanged));
|
||||
this._inhibited = false;
|
||||
|
||||
this._loginManager = LoginManager.getLoginManager();
|
||||
this._volumeMonitor = Gio.VolumeMonitor.get();
|
||||
},
|
||||
|
||||
@ -83,29 +85,25 @@ const AutomountManager = new Lang.Class({
|
||||
_onDriveConnected: function() {
|
||||
// if we're not in the current ConsoleKit session,
|
||||
// or screensaver is active, don't play sounds
|
||||
if (!this._session.SessionIsActive)
|
||||
if (!this._loginManager.sessionActive)
|
||||
return;
|
||||
|
||||
global.play_theme_sound(0, 'device-added-media',
|
||||
_("External drive connected"),
|
||||
null);
|
||||
global.play_theme_sound(0, 'device-added-media');
|
||||
},
|
||||
|
||||
_onDriveDisconnected: function() {
|
||||
// if we're not in the current ConsoleKit session,
|
||||
// or screensaver is active, don't play sounds
|
||||
if (!this._session.SessionIsActive)
|
||||
if (!this._loginManager.sessionActive)
|
||||
return;
|
||||
|
||||
global.play_theme_sound(0, 'device-removed-media',
|
||||
_("External drive disconnected"),
|
||||
null);
|
||||
global.play_theme_sound(0, 'device-removed-media');
|
||||
},
|
||||
|
||||
_onDriveEjectButton: function(monitor, drive) {
|
||||
// TODO: this code path is not tested, as the GVfs volume monitor
|
||||
// doesn't emit this signal just yet.
|
||||
if (!this._session.SessionIsActive)
|
||||
if (!this._loginManager.sessionActive)
|
||||
return;
|
||||
|
||||
// we force stop/eject in this case, so we don't have to pass a
|
||||
@ -145,7 +143,7 @@ const AutomountManager = new Lang.Class({
|
||||
if (params.checkSession) {
|
||||
// if we're not in the current ConsoleKit session,
|
||||
// don't attempt automount
|
||||
if (!this._session.SessionIsActive)
|
||||
if (!this._loginManager.sessionActive)
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -4,7 +4,7 @@ const Lang = imports.lang;
|
||||
const Gio = imports.gi.Gio;
|
||||
const St = imports.gi.St;
|
||||
|
||||
const GnomeSession = imports.misc.gnomeSession;
|
||||
const LoginManager = imports.misc.loginManager;
|
||||
const Main = imports.ui.main;
|
||||
const MessageTray = imports.ui.messageTray;
|
||||
const ShellMountOperation = imports.ui.shellMountOperation;
|
||||
@ -162,7 +162,8 @@ const AutorunManager = new Lang.Class({
|
||||
Name: 'AutorunManager',
|
||||
|
||||
_init: function() {
|
||||
this._session = new GnomeSession.SessionManager();
|
||||
this._loginManager = LoginManager.getLoginManager();
|
||||
|
||||
this._volumeMonitor = Gio.VolumeMonitor.get();
|
||||
|
||||
this._transDispatcher = new AutorunTransientDispatcher(this);
|
||||
@ -214,7 +215,7 @@ const AutorunManager = new Lang.Class({
|
||||
_onMountAdded: function(monitor, mount) {
|
||||
// don't do anything if our session is not the currently
|
||||
// active one
|
||||
if (!this._session.SessionIsActive)
|
||||
if (!this._loginManager.sessionActive)
|
||||
return;
|
||||
|
||||
this._processMount(mount, true);
|
||||
@ -292,6 +293,7 @@ const AutorunResidentSource = new Lang.Class({
|
||||
|
||||
_init: function(manager) {
|
||||
this.parent(_("Removable Devices"), 'media-removable');
|
||||
this.showInLockScreen = false;
|
||||
|
||||
this._mounts = [];
|
||||
|
||||
@ -299,10 +301,6 @@ const AutorunResidentSource = new Lang.Class({
|
||||
this._notification = new AutorunResidentNotification(this._manager, this);
|
||||
},
|
||||
|
||||
_createPolicy: function() {
|
||||
return new MessageTray.NotificationPolicy({ showInLockScreen: false });
|
||||
},
|
||||
|
||||
buildRightClickMenu: function() {
|
||||
return null;
|
||||
},
|
||||
|
@ -60,14 +60,18 @@ const KeyringDialog = new Lang.Class({
|
||||
|
||||
this._controlTable = null;
|
||||
|
||||
|
||||
this._cancelButton = this.addButton({ label: '',
|
||||
let buttons = [{ label: '',
|
||||
action: Lang.bind(this, this._onCancelButton),
|
||||
key: Clutter.Escape });
|
||||
this._continueButton = this.addButton({ label: '',
|
||||
key: Clutter.Escape
|
||||
},
|
||||
{ label: '',
|
||||
action: Lang.bind(this, this._onContinueButton),
|
||||
default: true },
|
||||
{ expand: true, x_fill: false, x_align: St.Align.END });
|
||||
default: true
|
||||
}]
|
||||
|
||||
this.setButtons(buttons);
|
||||
this._cancelButton = buttons[0].button;
|
||||
this._continueButton = buttons[1].button;
|
||||
|
||||
this.prompt.bind_property('cancel-label', this._cancelButton, 'label', GObject.BindingFlags.SYNC_CREATE);
|
||||
this.prompt.bind_property('continue-label', this._continueButton, 'label', GObject.BindingFlags.SYNC_CREATE);
|
||||
@ -142,14 +146,6 @@ const KeyringDialog = new Lang.Class({
|
||||
this._messageBox.add(table, { x_fill: true, y_fill: true });
|
||||
},
|
||||
|
||||
_updateSensitivity: function(sensitive) {
|
||||
this._passwordEntry.reactive = sensitive;
|
||||
this._passwordEntry.clutter_text.editable = sensitive;
|
||||
|
||||
this._continueButton.can_focus = sensitive;
|
||||
this._continueButton.reactive = sensitive;
|
||||
},
|
||||
|
||||
_ensureOpen: function() {
|
||||
// NOTE: ModalDialog.open() is safe to call if the dialog is
|
||||
// already open - it just returns true without side-effects
|
||||
@ -171,14 +167,12 @@ const KeyringDialog = new Lang.Class({
|
||||
_onShowPassword: function(prompt) {
|
||||
this._buildControlTable();
|
||||
this._ensureOpen();
|
||||
this._updateSensitivity(true);
|
||||
this._passwordEntry.grab_key_focus();
|
||||
},
|
||||
|
||||
_onShowConfirm: function(prompt) {
|
||||
this._buildControlTable();
|
||||
this._ensureOpen();
|
||||
this._updateSensitivity(true);
|
||||
this._continueButton.grab_key_focus();
|
||||
},
|
||||
|
||||
@ -198,7 +192,6 @@ const KeyringDialog = new Lang.Class({
|
||||
},
|
||||
|
||||
_onContinueButton: function() {
|
||||
this._updateSensitivity(false);
|
||||
this.prompt.complete();
|
||||
},
|
||||
|
||||
|
@ -587,19 +587,18 @@ const NetworkAgent = new Lang.Class({
|
||||
Name: 'NetworkAgent',
|
||||
|
||||
_init: function() {
|
||||
this._native = new Shell.NetworkAgent({ identifier: 'org.gnome.Shell.NetworkAgent' });
|
||||
this._native = new Shell.NetworkAgent({ auto_register: false,
|
||||
identifier: 'org.gnome.Shell.NetworkAgent' });
|
||||
|
||||
this._dialogs = { };
|
||||
this._vpnRequests = { };
|
||||
|
||||
this._native.connect('new-request', Lang.bind(this, this._newRequest));
|
||||
this._native.connect('cancel-request', Lang.bind(this, this._cancelRequest));
|
||||
|
||||
this._enabled = false;
|
||||
},
|
||||
|
||||
enable: function() {
|
||||
this._enabled = true;
|
||||
this._native.auto_register = true;
|
||||
},
|
||||
|
||||
disable: function() {
|
||||
@ -613,15 +612,12 @@ const NetworkAgent = new Lang.Class({
|
||||
this._vpnRequests[requestId].cancel(true);
|
||||
this._vpnRequests = { };
|
||||
|
||||
this._enabled = false;
|
||||
this._native.auto_register = false;
|
||||
if (this._native.registered)
|
||||
this._native.unregister();
|
||||
},
|
||||
|
||||
_newRequest: function(agent, requestId, connection, settingName, hints, flags) {
|
||||
if (!this._enabled) {
|
||||
agent.respond(requestId, Shell.NetworkAgentResponse.USER_CANCELED);
|
||||
return;
|
||||
}
|
||||
|
||||
if (settingName == 'vpn') {
|
||||
this._vpnRequest(requestId, connection, hints, flags);
|
||||
return;
|
||||
|
@ -159,13 +159,14 @@ const AuthenticationDialog = new Lang.Class({
|
||||
messageBox.add(this._nullMessageLabel);
|
||||
this._nullMessageLabel.show();
|
||||
|
||||
this._cancelButton = this.addButton({ label: _("Cancel"),
|
||||
this.setButtons([{ label: _("Cancel"),
|
||||
action: Lang.bind(this, this.cancel),
|
||||
key: Clutter.Escape });
|
||||
this._okButton = this.addButton({ label: _("Authenticate"),
|
||||
key: Clutter.Escape
|
||||
},
|
||||
{ label: _("Authenticate"),
|
||||
action: Lang.bind(this, this._onAuthenticateButtonPressed),
|
||||
default: true },
|
||||
{ expand: true, x_fill: false, x_align: St.Align.END });
|
||||
default: true
|
||||
}]);
|
||||
|
||||
this._doneEmitted = false;
|
||||
|
||||
@ -213,17 +214,8 @@ const AuthenticationDialog = new Lang.Class({
|
||||
}
|
||||
},
|
||||
|
||||
_updateSensitivity: function(sensitive) {
|
||||
this._passwordEntry.reactive = sensitive;
|
||||
this._passwordEntry.clutter_text.editable = sensitive;
|
||||
|
||||
this._okButton.can_focus = sensitive;
|
||||
this._okButton.reactive = sensitive;
|
||||
},
|
||||
|
||||
_onEntryActivate: function() {
|
||||
let response = this._passwordEntry.get_text();
|
||||
this._updateSensitivity(false);
|
||||
this._session.response(response);
|
||||
// When the user responds, dismiss already shown info and
|
||||
// error texts (if any)
|
||||
@ -277,7 +269,6 @@ const AuthenticationDialog = new Lang.Class({
|
||||
this._passwordBox.show();
|
||||
this._passwordEntry.set_text('');
|
||||
this._passwordEntry.grab_key_focus();
|
||||
this._updateSensitivity(true);
|
||||
this._ensureOpen();
|
||||
},
|
||||
|
||||
@ -335,19 +326,11 @@ const AuthenticationAgent = new Lang.Class({
|
||||
},
|
||||
|
||||
enable: function() {
|
||||
try {
|
||||
this._native.register();
|
||||
} catch(e) {
|
||||
log('Failed to register AuthenticationAgent');
|
||||
}
|
||||
},
|
||||
|
||||
disable: function() {
|
||||
try {
|
||||
this._native.unregister();
|
||||
} catch(e) {
|
||||
log('Failed to unregister AuthenticationAgent');
|
||||
}
|
||||
},
|
||||
|
||||
_onInitiate: function(nativeAgent, actionId, message, iconName, cookie, userNames) {
|
||||
|
@ -20,8 +20,8 @@ const Recorder = new Lang.Class({
|
||||
Main.wm.addKeybinding('toggle-recording',
|
||||
this._bindingSettings,
|
||||
Meta.KeyBindingFlags.NONE,
|
||||
Shell.KeyBindingMode.NORMAL |
|
||||
Shell.KeyBindingMode.OVERVIEW,
|
||||
Main.KeybindingMode.NORMAL |
|
||||
Main.KeybindingMode.OVERVIEW,
|
||||
Lang.bind(this, this._toggleRecorder));
|
||||
},
|
||||
|
||||
|
@ -13,7 +13,6 @@ 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;
|
||||
|
||||
@ -416,8 +415,6 @@ const TelepathyClient = new Lang.Class({
|
||||
_ensureAppSource: function() {
|
||||
if (this._appSource == null) {
|
||||
this._appSource = new MessageTray.Source(_("Chat"), 'empathy');
|
||||
this._appSource.policy = new NotificationDaemon.NotificationApplicationPolicy('empathy');
|
||||
|
||||
Main.messageTray.add(this._appSource);
|
||||
this._appSource.connect('destroy', Lang.bind(this, function () {
|
||||
this._appSource = null;
|
||||
@ -487,10 +484,6 @@ const ChatSource = new Lang.Class({
|
||||
return rightClickMenu;
|
||||
},
|
||||
|
||||
_createPolicy: function() {
|
||||
return new NotificationDaemon.NotificationApplicationPolicy('empathy');
|
||||
},
|
||||
|
||||
_updateAlias: function() {
|
||||
let oldAlias = this.title;
|
||||
let newAlias = this._contact.get_alias();
|
||||
@ -640,10 +633,6 @@ const ChatSource = new Lang.Class({
|
||||
return this._pendingMessages.length;
|
||||
},
|
||||
|
||||
get indicatorCount() {
|
||||
return this.count;
|
||||
},
|
||||
|
||||
get unseenCount() {
|
||||
return this.count;
|
||||
},
|
||||
@ -1059,10 +1048,6 @@ const ApproverSource = new Lang.Class({
|
||||
}));
|
||||
},
|
||||
|
||||
_createPolicy: function() {
|
||||
return new NotificationDaemon.NotificationApplicationPolicy('empathy');
|
||||
},
|
||||
|
||||
destroy: function() {
|
||||
if (this._invalidId != 0) {
|
||||
this._dispatchOp.disconnect(this._invalidId);
|
||||
@ -1361,8 +1346,9 @@ const AccountNotification = new Lang.Class({
|
||||
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 cmd = '/usr/bin/empathy-accounts'
|
||||
+ ' --select-account=%s'
|
||||
.format(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;
|
||||
|
196
js/ui/dash.js
196
js/ui/dash.js
@ -22,8 +22,11 @@ const DASH_ITEM_LABEL_HIDE_TIME = 0.1;
|
||||
const DASH_ITEM_HOVER_TIMEOUT = 300;
|
||||
|
||||
function getAppFromSource(source) {
|
||||
if (source instanceof AppDisplay.AppIcon) {
|
||||
if (source instanceof AppDisplay.AppWellIcon) {
|
||||
return source.app;
|
||||
} else if (source.metaWindow) {
|
||||
let tracker = Shell.WindowTracker.get_default();
|
||||
return tracker.get_window_app(source.metaWindow);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
@ -33,26 +36,30 @@ function getAppFromSource(source) {
|
||||
// when requesting a size
|
||||
const DashItemContainer = new Lang.Class({
|
||||
Name: 'DashItemContainer',
|
||||
Extends: St.Widget,
|
||||
|
||||
_init: function() {
|
||||
this.parent({ style_class: 'dash-item-container' });
|
||||
this.actor = new Shell.GenericContainer({ style_class: 'dash-item-container' });
|
||||
this.actor.connect('get-preferred-width',
|
||||
Lang.bind(this, this._getPreferredWidth));
|
||||
this.actor.connect('get-preferred-height',
|
||||
Lang.bind(this, this._getPreferredHeight));
|
||||
this.actor.connect('allocate',
|
||||
Lang.bind(this, this._allocate));
|
||||
this.actor._delegate = this;
|
||||
|
||||
this._labelText = "";
|
||||
this.label = new St.Label({ style_class: 'dash-label'});
|
||||
this.label.hide();
|
||||
Main.layoutManager.addChrome(this.label);
|
||||
this.label_actor = this.label;
|
||||
this.actor.label_actor = this.label;
|
||||
|
||||
this.child = null;
|
||||
this._childScale = 0;
|
||||
this._childOpacity = 0;
|
||||
this._childScale = 1;
|
||||
this._childOpacity = 255;
|
||||
this.animatingOut = false;
|
||||
},
|
||||
|
||||
vfunc_allocate: function(box, flags) {
|
||||
this.set_allocation(box, flags);
|
||||
|
||||
_allocate: function(actor, box, flags) {
|
||||
if (this.child == null)
|
||||
return;
|
||||
|
||||
@ -74,28 +81,28 @@ const DashItemContainer = new Lang.Class({
|
||||
this.child.allocate(childBox, flags);
|
||||
},
|
||||
|
||||
vfunc_get_preferred_height: function(forWidth) {
|
||||
let themeNode = this.get_theme_node();
|
||||
_getPreferredHeight: function(actor, forWidth, alloc) {
|
||||
alloc.min_size = 0;
|
||||
alloc.natural_size = 0;
|
||||
|
||||
if (this.child == null)
|
||||
return [0, 0];
|
||||
return;
|
||||
|
||||
forWidth = themeNode.adjust_for_width(forWidth);
|
||||
let [minHeight, natHeight] = this.child.get_preferred_height(forWidth);
|
||||
return themeNode.adjust_preferred_height(minHeight * this.child.scale_y,
|
||||
natHeight * this.child.scale_y);
|
||||
alloc.min_size += minHeight * this.child.scale_y;
|
||||
alloc.natural_size += natHeight * this.child.scale_y;
|
||||
},
|
||||
|
||||
vfunc_get_preferred_width: function(forHeight) {
|
||||
let themeNode = this.get_theme_node();
|
||||
_getPreferredWidth: function(actor, forHeight, alloc) {
|
||||
alloc.min_size = 0;
|
||||
alloc.natural_size = 0;
|
||||
|
||||
if (this.child == null)
|
||||
return [0, 0];
|
||||
return;
|
||||
|
||||
forHeight = themeNode.adjust_for_height(forHeight);
|
||||
let [minWidth, natWidth] = this.child.get_preferred_width(forHeight);
|
||||
return themeNode.adjust_preferred_width(minWidth * this.child.scale_y,
|
||||
natWidth * this.child.scale_y);
|
||||
alloc.min_size = minWidth * this.child.scale_y;
|
||||
alloc.natural_size = natWidth * this.child.scale_y;
|
||||
},
|
||||
|
||||
showLabel: function() {
|
||||
@ -106,9 +113,9 @@ const DashItemContainer = new Lang.Class({
|
||||
this.label.opacity = 0;
|
||||
this.label.show();
|
||||
|
||||
let [stageX, stageY] = this.get_transformed_position();
|
||||
let [stageX, stageY] = this.actor.get_transformed_position();
|
||||
|
||||
let itemHeight = this.allocation.y2 - this.allocation.y1;
|
||||
let itemHeight = this.actor.allocation.y2 - this.actor.allocation.y1;
|
||||
|
||||
let labelHeight = this.label.get_height();
|
||||
let yOffset = Math.floor((itemHeight - labelHeight) / 2)
|
||||
@ -122,7 +129,7 @@ const DashItemContainer = new Lang.Class({
|
||||
if (Clutter.get_default_text_direction() == Clutter.TextDirection.RTL)
|
||||
x = stageX - this.label.get_width() - xOffset;
|
||||
else
|
||||
x = stageX + this.get_width() + xOffset;
|
||||
x = stageX + this.actor.get_width() + xOffset;
|
||||
|
||||
this.label.set_position(x, y);
|
||||
Tweener.addTween(this.label,
|
||||
@ -152,25 +159,22 @@ const DashItemContainer = new Lang.Class({
|
||||
if (this.child == actor)
|
||||
return;
|
||||
|
||||
this.destroy_all_children();
|
||||
this.actor.destroy_all_children();
|
||||
|
||||
this.child = actor;
|
||||
this.add_actor(this.child);
|
||||
|
||||
this.child.set_scale_with_gravity(this._childScale, this._childScale,
|
||||
Clutter.Gravity.CENTER);
|
||||
this.child.set_opacity(this._childOpacity);
|
||||
this.actor.add_actor(this.child);
|
||||
},
|
||||
|
||||
show: function(animate) {
|
||||
animateIn: function() {
|
||||
if (this.child == null)
|
||||
return;
|
||||
|
||||
let time = animate ? DASH_ANIMATION_TIME : 0;
|
||||
this.childScale = 0;
|
||||
this.childOpacity = 0;
|
||||
Tweener.addTween(this,
|
||||
{ childScale: 1.0,
|
||||
childOpacity: 255,
|
||||
time: time,
|
||||
time: DASH_ANIMATION_TIME,
|
||||
transition: 'easeOutQuad'
|
||||
});
|
||||
},
|
||||
@ -179,7 +183,7 @@ const DashItemContainer = new Lang.Class({
|
||||
if (this.label)
|
||||
this.label.destroy();
|
||||
|
||||
this.parent();
|
||||
this.actor.destroy();
|
||||
},
|
||||
|
||||
animateOutAndDestroy: function() {
|
||||
@ -187,18 +191,19 @@ const DashItemContainer = new Lang.Class({
|
||||
this.label.destroy();
|
||||
|
||||
if (this.child == null) {
|
||||
this.destroy();
|
||||
this.actor.destroy();
|
||||
return;
|
||||
}
|
||||
|
||||
this.animatingOut = true;
|
||||
this.childScale = 1.0;
|
||||
Tweener.addTween(this,
|
||||
{ childScale: 0.0,
|
||||
childOpacity: 0,
|
||||
time: DASH_ANIMATION_TIME,
|
||||
transition: 'easeOutQuad',
|
||||
onComplete: Lang.bind(this, function() {
|
||||
this.destroy();
|
||||
this.actor.destroy();
|
||||
})
|
||||
});
|
||||
},
|
||||
@ -211,7 +216,7 @@ const DashItemContainer = new Lang.Class({
|
||||
|
||||
this.child.set_scale_with_gravity(scale, scale,
|
||||
Clutter.Gravity.CENTER);
|
||||
this.queue_relayout();
|
||||
this.actor.queue_relayout();
|
||||
},
|
||||
|
||||
get childScale() {
|
||||
@ -225,7 +230,7 @@ const DashItemContainer = new Lang.Class({
|
||||
return;
|
||||
|
||||
this.child.set_opacity(opacity);
|
||||
this.queue_redraw();
|
||||
this.actor.queue_redraw();
|
||||
},
|
||||
|
||||
get childOpacity() {
|
||||
@ -356,23 +361,6 @@ const DashActor = new Lang.Class({
|
||||
childBox.y1 = contentBox.y2 - showAppsNatHeight;
|
||||
childBox.y2 = contentBox.y2;
|
||||
showAppsButton.allocate(childBox, flags);
|
||||
},
|
||||
|
||||
vfunc_get_preferred_height: function(forWidth) {
|
||||
// We want to request the natural height of all our children
|
||||
// as our natural height, so we chain up to StWidget (which
|
||||
// then calls BoxLayout), but we only request the showApps
|
||||
// button as the minimum size
|
||||
|
||||
let [, natHeight] = this.parent(forWidth);
|
||||
|
||||
let themeNode = this.get_theme_node();
|
||||
let adjustedForWidth = themeNode.adjust_for_width(forWidth);
|
||||
let [, showAppsButton] = this.get_children();
|
||||
let [minHeight, ] = showAppsButton.get_preferred_height(adjustedForWidth);
|
||||
[minHeight, ] = themeNode.adjust_preferred_height(minHeight, natHeight);
|
||||
|
||||
return [minHeight, natHeight];
|
||||
}
|
||||
});
|
||||
|
||||
@ -398,14 +386,12 @@ const Dash = new Lang.Class({
|
||||
this._container.add_actor(this._box);
|
||||
|
||||
this._showAppsIcon = new ShowAppsIcon();
|
||||
this._showAppsIcon.childScale = 1;
|
||||
this._showAppsIcon.childOpacity = 255;
|
||||
this._showAppsIcon.icon.setIconSize(this.iconSize);
|
||||
this._hookUpLabel(this._showAppsIcon);
|
||||
|
||||
this.showAppsButton = this._showAppsIcon.toggleButton;
|
||||
|
||||
this._container.add_actor(this._showAppsIcon);
|
||||
this._container.add_actor(this._showAppsIcon.actor);
|
||||
|
||||
this.actor = new St.Bin({ child: this._container });
|
||||
this.actor.connect('notify::height', Lang.bind(this,
|
||||
@ -429,10 +415,12 @@ const Dash = new Lang.Class({
|
||||
Lang.bind(this, this._onDragEnd));
|
||||
Main.overview.connect('item-drag-cancelled',
|
||||
Lang.bind(this, this._onDragCancelled));
|
||||
|
||||
// Translators: this is the name of the dock/favorites area on
|
||||
// the left of the overview
|
||||
Main.ctrlAltTabManager.addGroup(this.actor, _("Dash"), 'user-bookmarks-symbolic');
|
||||
Main.overview.connect('window-drag-begin',
|
||||
Lang.bind(this, this._onDragBegin));
|
||||
Main.overview.connect('window-drag-cancelled',
|
||||
Lang.bind(this, this._onDragCancelled));
|
||||
Main.overview.connect('window-drag-end',
|
||||
Lang.bind(this, this._onDragEnd));
|
||||
},
|
||||
|
||||
_onDragBegin: function() {
|
||||
@ -467,7 +455,7 @@ const Dash = new Lang.Class({
|
||||
return DND.DragMotionResult.CONTINUE;
|
||||
|
||||
let showAppsHovered =
|
||||
this._showAppsIcon.contains(dragEvent.targetActor);
|
||||
this._showAppsIcon.actor.contains(dragEvent.targetActor);
|
||||
|
||||
if (!this._box.contains(dragEvent.targetActor) || showAppsHovered)
|
||||
this._clearDragPlaceholder();
|
||||
@ -503,7 +491,7 @@ const Dash = new Lang.Class({
|
||||
},
|
||||
|
||||
_createAppItem: function(app) {
|
||||
let appIcon = new AppDisplay.AppIcon(app,
|
||||
let appIcon = new AppDisplay.AppWellIcon(app,
|
||||
{ setSizeManually: true,
|
||||
showLabel: false });
|
||||
appIcon._draggable.connect('drag-begin',
|
||||
@ -522,7 +510,7 @@ const Dash = new Lang.Class({
|
||||
let item = new DashItemContainer();
|
||||
item.setChild(appIcon.actor);
|
||||
|
||||
// Override default AppIcon label_actor, now the
|
||||
// Override default AppWellIcon label_actor, now the
|
||||
// accessible_name is set at DashItemContainer.setLabelText
|
||||
appIcon.actor.label_actor = null;
|
||||
item.setLabelText(app.get_name());
|
||||
@ -582,13 +570,13 @@ const Dash = new Lang.Class({
|
||||
// animating out (which means they will be destroyed at the end of
|
||||
// the animation)
|
||||
let iconChildren = this._box.get_children().filter(function(actor) {
|
||||
return actor.child &&
|
||||
actor.child._delegate &&
|
||||
actor.child._delegate.icon &&
|
||||
!actor.animatingOut;
|
||||
return actor._delegate.child &&
|
||||
actor._delegate.child._delegate &&
|
||||
actor._delegate.child._delegate.icon &&
|
||||
!actor._delegate.animatingOut;
|
||||
});
|
||||
|
||||
iconChildren.push(this._showAppsIcon);
|
||||
iconChildren.push(this._showAppsIcon.actor);
|
||||
|
||||
if (this._maxHeight == -1)
|
||||
return;
|
||||
@ -601,18 +589,23 @@ const Dash = new Lang.Class({
|
||||
let availHeight = maxContent.y2 - maxContent.y1;
|
||||
let spacing = themeNode.get_length('spacing');
|
||||
|
||||
let firstButton = iconChildren[0].child;
|
||||
let firstIcon = firstButton._delegate.icon;
|
||||
|
||||
let firstIcon = iconChildren[0]._delegate.child._delegate.icon;
|
||||
|
||||
let minHeight, natHeight;
|
||||
|
||||
// Enforce the current icon size during the size request
|
||||
// Enforce the current icon size during the size request if
|
||||
// the icon is animating
|
||||
if (firstIcon._animating) {
|
||||
let [currentWidth, currentHeight] = firstIcon.icon.get_size();
|
||||
|
||||
firstIcon.icon.set_size(this.iconSize, this.iconSize);
|
||||
[minHeight, natHeight] = firstButton.get_preferred_height(-1);
|
||||
[minHeight, natHeight] = iconChildren[0].get_preferred_height(-1);
|
||||
|
||||
firstIcon.icon.set_size(currentWidth, currentHeight);
|
||||
} else {
|
||||
[minHeight, natHeight] = iconChildren[0].get_preferred_height(-1);
|
||||
}
|
||||
|
||||
// Subtract icon padding and box spacing from the available height
|
||||
availHeight -= iconChildren.length * (natHeight - this.iconSize) +
|
||||
@ -637,7 +630,7 @@ const Dash = new Lang.Class({
|
||||
|
||||
let scale = oldIconSize / newIconSize;
|
||||
for (let i = 0; i < iconChildren.length; i++) {
|
||||
let icon = iconChildren[i].child._delegate.icon;
|
||||
let icon = iconChildren[i]._delegate.child._delegate.icon;
|
||||
|
||||
// Set the new size immediately, to keep the icons' sizes
|
||||
// in sync with this.iconSize
|
||||
@ -657,11 +650,15 @@ const Dash = new Lang.Class({
|
||||
icon.icon.set_size(icon.icon.width * scale,
|
||||
icon.icon.height * scale);
|
||||
|
||||
icon._animating = true;
|
||||
Tweener.addTween(icon.icon,
|
||||
{ width: targetWidth,
|
||||
height: targetHeight,
|
||||
time: DASH_ANIMATION_TIME,
|
||||
transition: 'easeOutQuad',
|
||||
onComplete: function() {
|
||||
icon._animating = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
@ -672,13 +669,13 @@ const Dash = new Lang.Class({
|
||||
let running = this._appSystem.get_running();
|
||||
|
||||
let children = this._box.get_children().filter(function(actor) {
|
||||
return actor.child &&
|
||||
actor.child._delegate &&
|
||||
actor.child._delegate.app;
|
||||
return actor._delegate.child &&
|
||||
actor._delegate.child._delegate &&
|
||||
actor._delegate.child._delegate.app;
|
||||
});
|
||||
// Apps currently in the dash
|
||||
let oldApps = children.map(function(actor) {
|
||||
return actor.child._delegate.app;
|
||||
return actor._delegate.child._delegate.app;
|
||||
});
|
||||
// Apps supposed to be in the dash
|
||||
let newApps = [];
|
||||
@ -744,7 +741,7 @@ const Dash = new Lang.Class({
|
||||
let insertHere = newApps[newIndex + 1] &&
|
||||
newApps[newIndex + 1] == oldApps[oldIndex];
|
||||
let alreadyRemoved = removedActors.reduce(function(result, actor) {
|
||||
let removedApp = actor.child._delegate.app;
|
||||
let removedApp = actor._delegate.child._delegate.app;
|
||||
return result || removedApp == newApps[newIndex];
|
||||
}, false);
|
||||
|
||||
@ -761,11 +758,11 @@ const Dash = new Lang.Class({
|
||||
}
|
||||
|
||||
for (let i = 0; i < addedItems.length; i++)
|
||||
this._box.insert_child_at_index(addedItems[i].item,
|
||||
this._box.insert_child_at_index(addedItems[i].item.actor,
|
||||
addedItems[i].pos);
|
||||
|
||||
for (let i = 0; i < removedActors.length; i++) {
|
||||
let item = removedActors[i];
|
||||
let item = removedActors[i]._delegate;
|
||||
|
||||
// Don't animate item removal when the overview is transitioning
|
||||
// or hidden
|
||||
@ -779,20 +776,18 @@ const Dash = new Lang.Class({
|
||||
|
||||
// Skip animations on first run when adding the initial set
|
||||
// of items, to avoid all items zooming in at once
|
||||
|
||||
let animate = this._shownInitially && Main.overview.visible &&
|
||||
!Main.overview.animationInProgress;
|
||||
|
||||
if (!this._shownInitially)
|
||||
if (!this._shownInitially) {
|
||||
this._shownInitially = true;
|
||||
|
||||
for (let i = 0; i < addedItems.length; i++) {
|
||||
addedItems[i].item.show(animate);
|
||||
return;
|
||||
}
|
||||
|
||||
// Workaround for https://bugzilla.gnome.org/show_bug.cgi?id=692744
|
||||
// Without it, StBoxLayout may use a stale size cache
|
||||
this._box.queue_relayout();
|
||||
// Don't animate item addition when the overview is transitioning
|
||||
// or hidden
|
||||
if (!Main.overview.visible || Main.overview.animationInProgress)
|
||||
return;
|
||||
|
||||
for (let i = 0; i < addedItems.length; i++)
|
||||
addedItems[i].item.animateIn();
|
||||
},
|
||||
|
||||
_clearDragPlaceholder: function() {
|
||||
@ -823,7 +818,7 @@ const Dash = new Lang.Class({
|
||||
// the remove target has the same size as "normal" items, we don't
|
||||
// need to do the same adjustment there.
|
||||
if (this._dragPlaceholder) {
|
||||
boxHeight -= this._dragPlaceholder.height;
|
||||
boxHeight -= this._dragPlaceholder.actor.height;
|
||||
numChildren--;
|
||||
}
|
||||
|
||||
@ -837,7 +832,7 @@ const Dash = new Lang.Class({
|
||||
if (this._dragPlaceholder) {
|
||||
this._dragPlaceholder.animateOutAndDestroy();
|
||||
this._animatingPlaceholdersCount++;
|
||||
this._dragPlaceholder.connect('destroy',
|
||||
this._dragPlaceholder.actor.connect('destroy',
|
||||
Lang.bind(this, function() {
|
||||
this._animatingPlaceholdersCount--;
|
||||
}));
|
||||
@ -852,7 +847,7 @@ const Dash = new Lang.Class({
|
||||
// an animation
|
||||
let fadeIn;
|
||||
if (this._dragPlaceholder) {
|
||||
this._dragPlaceholder.destroy();
|
||||
this._dragPlaceholder.actor.destroy();
|
||||
fadeIn = false;
|
||||
} else {
|
||||
fadeIn = true;
|
||||
@ -861,9 +856,10 @@ const Dash = new Lang.Class({
|
||||
this._dragPlaceholder = new DragPlaceholderItem();
|
||||
this._dragPlaceholder.child.set_width (this.iconSize);
|
||||
this._dragPlaceholder.child.set_height (this.iconSize / 2);
|
||||
this._box.insert_child_at_index(this._dragPlaceholder,
|
||||
this._box.insert_child_at_index(this._dragPlaceholder.actor,
|
||||
this._dragPlaceholderPos);
|
||||
this._dragPlaceholder.show(fadeIn);
|
||||
if (fadeIn)
|
||||
this._dragPlaceholder.animateIn();
|
||||
}
|
||||
|
||||
// Remove the drag placeholder if we are not in the
|
||||
@ -901,10 +897,10 @@ const Dash = new Lang.Class({
|
||||
let children = this._box.get_children();
|
||||
for (let i = 0; i < this._dragPlaceholderPos; i++) {
|
||||
if (this._dragPlaceholder &&
|
||||
children[i] == this._dragPlaceholder)
|
||||
children[i] == this._dragPlaceholder.actor)
|
||||
continue;
|
||||
|
||||
let childId = children[i].child._delegate.app.get_id();
|
||||
let childId = children[i]._delegate.child._delegate.app.get_id();
|
||||
if (childId == id)
|
||||
continue;
|
||||
if (childId in favorites)
|
||||
|
@ -32,7 +32,6 @@ function _onVertSepRepaint (area)
|
||||
cr.setDash([1, 3], 1); // Hard-code for now
|
||||
cr.setLineWidth(stippleWidth);
|
||||
cr.stroke();
|
||||
cr.$dispose();
|
||||
};
|
||||
|
||||
const DateMenuButton = new Lang.Class({
|
||||
@ -84,26 +83,12 @@ const DateMenuButton = new Lang.Class({
|
||||
}));
|
||||
vbox.add(this._calendar.actor);
|
||||
|
||||
item = this.menu.addSettingsAction(_("Date and Time Settings"), 'gnome-datetime-panel.desktop');
|
||||
if (item) {
|
||||
let separator = new PopupMenu.PopupSeparatorMenuItem();
|
||||
separator.setColumnWidths(1);
|
||||
vbox.add(separator.actor, {y_align: St.Align.END, expand: true, y_fill: false});
|
||||
|
||||
this._openCalendarItem = new PopupMenu.PopupMenuItem(_("Open Calendar"));
|
||||
this._openCalendarItem.connect('activate', Lang.bind(this, this._onOpenCalendarActivate));
|
||||
this._openCalendarItem.actor.can_focus = false;
|
||||
vbox.add(this._openCalendarItem.actor, {y_align: St.Align.END, expand: true, y_fill: false});
|
||||
|
||||
this._openClocksItem = new PopupMenu.PopupMenuItem(_("Open Clocks"));
|
||||
this._openClocksItem.connect('activate', Lang.bind(this, this._onOpenClocksActivate));
|
||||
this._openClocksItem.actor.can_focus = false;
|
||||
vbox.add(this._openClocksItem.actor, {y_align: St.Align.END, expand: true, y_fill: false});
|
||||
|
||||
Shell.AppSystem.get_default().connect('installed-changed',
|
||||
Lang.bind(this, this._appInstalledChanged));
|
||||
this._appInstalledChanged();
|
||||
|
||||
item = this.menu.addSettingsAction(_("Date & Time Settings"), 'gnome-datetime-panel.desktop');
|
||||
if (item) {
|
||||
item.actor.show_on_set_parent = false;
|
||||
item.actor.can_focus = false;
|
||||
item.actor.reparent(vbox);
|
||||
@ -123,6 +108,16 @@ const DateMenuButton = new Lang.Class({
|
||||
// Event list
|
||||
vbox.add(this._eventList.actor, { expand: true });
|
||||
|
||||
this._openCalendarItem = new PopupMenu.PopupMenuItem(_("Open Calendar"));
|
||||
this._openCalendarItem.connect('activate', Lang.bind(this, this._onOpenCalendarActivate));
|
||||
this._openCalendarItem.actor.can_focus = false;
|
||||
vbox.add(this._openCalendarItem.actor, {y_align: St.Align.END, expand: true, y_fill: false});
|
||||
|
||||
this._calendarSettings = new Gio.Settings({ schema: 'org.gnome.desktop.default-applications.office.calendar' });
|
||||
this._calendarSettings.connect('changed::exec',
|
||||
Lang.bind(this, this._calendarSettingsChanged));
|
||||
this._calendarSettingsChanged();
|
||||
|
||||
// Whenever the menu is opened, select today
|
||||
this.menu.connect('open-state-changed', Lang.bind(this, function(menu, isOpen) {
|
||||
if (isOpen) {
|
||||
@ -156,9 +151,10 @@ const DateMenuButton = new Lang.Class({
|
||||
this._sessionUpdated();
|
||||
},
|
||||
|
||||
_appInstalledChanged: function() {
|
||||
let app = Shell.AppSystem.get_default().lookup_app('gnome-clocks.desktop');
|
||||
this._openClocksItem.actor.visible = app !== null;
|
||||
_calendarSettingsChanged: function() {
|
||||
let exec = this._calendarSettings.get_string('exec');
|
||||
let fullExec = GLib.find_program_in_path(exec);
|
||||
this._openCalendarItem.actor.visible = fullExec != null;
|
||||
},
|
||||
|
||||
_setEventsVisibility: function(visible) {
|
||||
@ -209,14 +205,24 @@ const DateMenuButton = new Lang.Class({
|
||||
|
||||
_onOpenCalendarActivate: function() {
|
||||
this.menu.close();
|
||||
|
||||
let app = Gio.AppInfo.get_default_for_type('text/calendar', false);
|
||||
app.launch([], global.create_app_launch_context());
|
||||
},
|
||||
|
||||
_onOpenClocksActivate: function() {
|
||||
this.menu.close();
|
||||
let app = Shell.AppSystem.get_default().lookup_app('gnome-clocks.desktop');
|
||||
let tool = this._calendarSettings.get_string('exec');
|
||||
if (tool.length == 0 || tool.substr(0, 9) == 'evolution') {
|
||||
// TODO: pass the selected day
|
||||
let app = Shell.AppSystem.get_default().lookup_app('evolution-calendar.desktop');
|
||||
app.activate();
|
||||
} else {
|
||||
let needTerm = this._calendarSettings.get_boolean('needs-term');
|
||||
if (needTerm) {
|
||||
let terminalSettings = new Gio.Settings({ schema: 'org.gnome.desktop.default-applications.terminal' });
|
||||
let term = terminalSettings.get_string('exec');
|
||||
let arg = terminalSettings.get_string('exec-arg');
|
||||
if (arg != '')
|
||||
Util.spawn([term, arg, tool]);
|
||||
else
|
||||
Util.spawn([term, tool]);
|
||||
} else {
|
||||
Util.spawnCommandLine(tool)
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
16
js/ui/dnd.js
16
js/ui/dnd.js
@ -136,10 +136,9 @@ const _Draggable = new Lang.Class({
|
||||
},
|
||||
|
||||
_ungrabActor: function() {
|
||||
Clutter.ungrab_pointer();
|
||||
if (!this._onEventId)
|
||||
return;
|
||||
|
||||
Clutter.ungrab_pointer();
|
||||
this.actor.disconnect(this._onEventId);
|
||||
this._onEventId = null;
|
||||
},
|
||||
@ -204,19 +203,6 @@ const _Draggable = new Lang.Class({
|
||||
return false;
|
||||
},
|
||||
|
||||
/**
|
||||
* fakeRelease:
|
||||
*
|
||||
* Fake a release event.
|
||||
* Must be called if you want to intercept release events on draggable
|
||||
* actors for other purposes (for example if you're using
|
||||
* PopupMenu.ignoreRelease())
|
||||
*/
|
||||
fakeRelease: function() {
|
||||
this._buttonDown = false;
|
||||
this._ungrabActor();
|
||||
},
|
||||
|
||||
/**
|
||||
* startDrag:
|
||||
* @stageX: X coordinate of event
|
||||
|
@ -19,7 +19,6 @@
|
||||
*/
|
||||
|
||||
const Lang = imports.lang;
|
||||
const Mainloop = imports.mainloop;
|
||||
const Signals = imports.signals;
|
||||
|
||||
const AccountsService = imports.gi.AccountsService;
|
||||
@ -51,7 +50,6 @@ const EndSessionDialogIface = <interface name="org.gnome.SessionManager.EndSessi
|
||||
<arg type="u" direction="in" />
|
||||
<arg type="ao" direction="in" />
|
||||
</method>
|
||||
<method name="Close" />
|
||||
<signal name="ConfirmedLogout" />
|
||||
<signal name="ConfirmedReboot" />
|
||||
<signal name="ConfirmedShutdown" />
|
||||
@ -379,12 +377,7 @@ const EndSessionDialog = new Lang.Class({
|
||||
let signal = dialogContent.confirmButtons[i].signal;
|
||||
let label = dialogContent.confirmButtons[i].label;
|
||||
buttons.push({ action: Lang.bind(this, function() {
|
||||
this.close(true);
|
||||
let signalId = this.connect('closed',
|
||||
Lang.bind(this, function() {
|
||||
this.disconnect(signalId);
|
||||
this._confirm(signal);
|
||||
}));
|
||||
}),
|
||||
label: label });
|
||||
}
|
||||
@ -392,17 +385,15 @@ const EndSessionDialog = new Lang.Class({
|
||||
this.setButtons(buttons);
|
||||
},
|
||||
|
||||
close: function(skipSignal) {
|
||||
close: function() {
|
||||
this.parent();
|
||||
|
||||
if (!skipSignal)
|
||||
this._dbusImpl.emit_signal('Closed', null);
|
||||
},
|
||||
|
||||
cancel: function() {
|
||||
this._stopTimer();
|
||||
this._dbusImpl.emit_signal('Canceled', null);
|
||||
this.close();
|
||||
this.close(global.get_current_time());
|
||||
},
|
||||
|
||||
_confirm: function(signal) {
|
||||
@ -417,34 +408,22 @@ const EndSessionDialog = new Lang.Class({
|
||||
},
|
||||
|
||||
_startTimer: function() {
|
||||
let startTime = GLib.get_monotonic_time();
|
||||
this._secondsLeft = this._totalSecondsToStayOpen;
|
||||
|
||||
this._timerId = Mainloop.timeout_add_seconds(1, Lang.bind(this,
|
||||
function() {
|
||||
let currentTime = GLib.get_monotonic_time();
|
||||
let secondsElapsed = ((currentTime - startTime) / 1000000);
|
||||
|
||||
this._secondsLeft = this._totalSecondsToStayOpen - secondsElapsed;
|
||||
if (this._secondsLeft > 0) {
|
||||
this._updateDescription();
|
||||
return true;
|
||||
}
|
||||
|
||||
Tweener.addTween(this,
|
||||
{ _secondsLeft: 0,
|
||||
time: this._secondsLeft,
|
||||
transition: 'linear',
|
||||
onUpdate: Lang.bind(this, this._updateDescription),
|
||||
onComplete: Lang.bind(this, function() {
|
||||
let dialogContent = DialogContent[this._type];
|
||||
let button = dialogContent.confirmButtons[dialogContent.confirmButtons.length - 1];
|
||||
this._confirm(button.signal);
|
||||
|
||||
return false;
|
||||
}));
|
||||
}),
|
||||
});
|
||||
},
|
||||
|
||||
_stopTimer: function() {
|
||||
if (this._timerId != 0) {
|
||||
Mainloop.source_remove(this._timerId);
|
||||
this._timerId = 0;
|
||||
}
|
||||
|
||||
Tweener.removeTweens(this);
|
||||
this._secondsLeft = 0;
|
||||
},
|
||||
|
||||
@ -461,7 +440,7 @@ const EndSessionDialog = new Lang.Class({
|
||||
let item = new ListItem(app, reason);
|
||||
item.connect('activate',
|
||||
Lang.bind(this, function() {
|
||||
this.close();
|
||||
this.close(global.get_current_time());
|
||||
}));
|
||||
this._applicationList.add(item.actor, { x_fill: true });
|
||||
this._stopTimer();
|
||||
@ -509,9 +488,5 @@ const EndSessionDialog = new Lang.Class({
|
||||
invocation.return_value(null);
|
||||
this.disconnect(signalId);
|
||||
}));
|
||||
},
|
||||
|
||||
Close: function(parameters, invocation) {
|
||||
this.close();
|
||||
}
|
||||
});
|
||||
|
@ -215,7 +215,7 @@ const InstallExtensionDialog = new Lang.Class({
|
||||
},
|
||||
|
||||
_onCancelButtonPressed: function(button, event) {
|
||||
this.close();
|
||||
this.close(global.get_current_time());
|
||||
this._invocation.return_value(GLib.Variant.new('(s)', ['cancelled']));
|
||||
},
|
||||
|
||||
@ -257,7 +257,7 @@ const InstallExtensionDialog = new Lang.Class({
|
||||
gotExtensionZipFile(session, message, uuid, dir, callback, errback);
|
||||
}));
|
||||
|
||||
this.close();
|
||||
this.close(global.get_current_time());
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -106,15 +106,11 @@ function enableExtension(uuid) {
|
||||
|
||||
extensionOrder.push(uuid);
|
||||
|
||||
let stylesheetNames = [global.session_mode + '.css', 'stylesheet.css'];
|
||||
for (let i = 0; i < stylesheetNames.length; i++) {
|
||||
let stylesheetFile = extension.dir.get_child(stylesheetNames[i]);
|
||||
let stylesheetFile = extension.dir.get_child('stylesheet.css');
|
||||
if (stylesheetFile.query_exists(null)) {
|
||||
let theme = St.ThemeContext.get_for_stage(global.stage).get_theme();
|
||||
theme.load_stylesheet(stylesheetFile.get_path());
|
||||
extension.stylesheet = stylesheetFile;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
extension.stateObj.enable();
|
||||
|
45
js/ui/flashspot.js
Normal file
45
js/ui/flashspot.js
Normal file
@ -0,0 +1,45 @@
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
|
||||
const Lang = imports.lang;
|
||||
|
||||
const Lightbox = imports.ui.lightbox;
|
||||
const Main = imports.ui.main;
|
||||
const Tweener = imports.ui.tweener;
|
||||
|
||||
const FLASHSPOT_ANIMATION_TIME = 0.25; // seconds
|
||||
|
||||
const Flashspot = new Lang.Class({
|
||||
Name: 'Flashspot',
|
||||
Extends: Lightbox.Lightbox,
|
||||
|
||||
_init: function(area) {
|
||||
this.parent(Main.uiGroup, { inhibitEvents: true,
|
||||
width: area.width,
|
||||
height: area.height });
|
||||
|
||||
this.actor.style_class = 'flashspot';
|
||||
this.actor.set_position(area.x, area.y);
|
||||
},
|
||||
|
||||
fire: function() {
|
||||
this.actor.opacity = 0;
|
||||
Tweener.addTween(this.actor,
|
||||
{ opacity: 255,
|
||||
time: FLASHSPOT_ANIMATION_TIME,
|
||||
transition: 'linear',
|
||||
onComplete: Lang.bind(this, this._onFireShowComplete)
|
||||
});
|
||||
this.actor.show();
|
||||
},
|
||||
|
||||
_onFireShowComplete: function() {
|
||||
Tweener.addTween(this.actor,
|
||||
{ opacity: 0,
|
||||
time: FLASHSPOT_ANIMATION_TIME,
|
||||
transition: 'linear',
|
||||
onComplete: Lang.bind(this, function() {
|
||||
this.destroy();
|
||||
})
|
||||
});
|
||||
}
|
||||
});
|
@ -1,4 +1,4 @@
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
|
||||
|
||||
const Clutter = imports.gi.Clutter;
|
||||
const Gtk = imports.gi.Gtk;
|
||||
@ -10,6 +10,17 @@ const St = imports.gi.St;
|
||||
const Main = imports.ui.main;
|
||||
const Params = imports.misc.params;
|
||||
|
||||
function _navigateActor(actor) {
|
||||
if (!actor)
|
||||
return;
|
||||
|
||||
let needsGrab = true;
|
||||
if (actor instanceof St.Widget)
|
||||
needsGrab = !actor.navigate_focus(null, Gtk.DirectionType.TAB_FORWARD, false);
|
||||
if (needsGrab)
|
||||
actor.grab_key_focus();
|
||||
}
|
||||
|
||||
// GrabHelper:
|
||||
// @owner: the actor that owns the GrabHelper
|
||||
// @params: optional parameters to pass to Main.pushModal()
|
||||
@ -35,7 +46,6 @@ const GrabHelper = new Lang.Class({
|
||||
this._keyFocusNotifyId = 0;
|
||||
this._focusWindowChangedId = 0;
|
||||
this._ignoreRelease = false;
|
||||
this._isUngrabbingCount = 0;
|
||||
|
||||
this._modalCount = 0;
|
||||
this._grabFocusCount = 0;
|
||||
@ -168,18 +178,12 @@ const GrabHelper = new Lang.Class({
|
||||
if (params.grabFocus && !this._takeFocusGrab(hadFocus))
|
||||
return false;
|
||||
|
||||
this._grabStack.push(params);
|
||||
|
||||
if (params.focus) {
|
||||
if (params.focus)
|
||||
params.focus.grab_key_focus();
|
||||
} else if (newFocus && (hadFocus || params.grabFocus)) {
|
||||
if (!newFocus.navigate_focus(null, Gtk.DirectionType.TAB_FORWARD, false))
|
||||
newFocus.grab_key_focus();
|
||||
}
|
||||
|
||||
if ((params.grabFocus || params.modal) && !this._capturedEventId)
|
||||
this._capturedEventId = global.stage.connect('captured-event', Lang.bind(this, this._onCapturedEvent));
|
||||
else if (hadFocus || params.grabFocus)
|
||||
_navigateActor(newFocus);
|
||||
|
||||
this._grabStack.push(params);
|
||||
return true;
|
||||
},
|
||||
|
||||
@ -188,6 +192,8 @@ const GrabHelper = new Lang.Class({
|
||||
if (firstGrab) {
|
||||
if (!Main.pushModal(this._owner, this._modalParams))
|
||||
return false;
|
||||
|
||||
this._capturedEventId = global.stage.connect('captured-event', Lang.bind(this, this._onCapturedEvent));
|
||||
}
|
||||
|
||||
this._modalCount++;
|
||||
@ -199,6 +205,11 @@ const GrabHelper = new Lang.Class({
|
||||
if (this._modalCount > 0)
|
||||
return;
|
||||
|
||||
if (this._capturedEventId > 0) {
|
||||
global.stage.disconnect(this._capturedEventId);
|
||||
this._capturedEventId = 0;
|
||||
}
|
||||
|
||||
Main.popModal(this._owner);
|
||||
global.sync_pointer();
|
||||
},
|
||||
@ -234,7 +245,7 @@ const GrabHelper = new Lang.Class({
|
||||
this._keyFocusNotifyId = 0;
|
||||
}
|
||||
|
||||
if (this._focusWindowChangedId > 0) {
|
||||
if (!this._focusWindowChanged > 0) {
|
||||
let metaDisplay = global.screen.get_display();
|
||||
metaDisplay.disconnect(this._focusWindowChangedId);
|
||||
this._focusWindowChangedId = 0;
|
||||
@ -276,14 +287,6 @@ const GrabHelper = new Lang.Class({
|
||||
if (grabStackIndex < 0)
|
||||
return;
|
||||
|
||||
// We may get key focus changes when calling onUngrab, which
|
||||
// would cause an extra ungrab() on the next actor in the
|
||||
// stack, which is wrong. Ignore key focus changes during the
|
||||
// ungrab, and restore the saved key focus ourselves afterwards.
|
||||
// We use a count as ungrab() may be re-entrant, as onUngrab()
|
||||
// may ungrab additional actors.
|
||||
this._isUngrabbingCount++;
|
||||
|
||||
let focus = global.stage.key_focus;
|
||||
let hadFocus = focus && this._isWithinGrabbedActor(focus);
|
||||
|
||||
@ -305,29 +308,14 @@ const GrabHelper = new Lang.Class({
|
||||
this._releaseFocusGrab();
|
||||
}
|
||||
|
||||
if (!this.grabbed && this._capturedEventId > 0) {
|
||||
global.stage.disconnect(this._capturedEventId);
|
||||
this._capturedEventId = 0;
|
||||
}
|
||||
|
||||
if (hadFocus) {
|
||||
let poppedGrab = poppedGrabs[0];
|
||||
if (poppedGrab.savedFocus)
|
||||
poppedGrab.savedFocus.grab_key_focus();
|
||||
_navigateActor(poppedGrab.savedFocus);
|
||||
}
|
||||
|
||||
this._isUngrabbingCount--;
|
||||
},
|
||||
|
||||
_onCapturedEvent: function(actor, event) {
|
||||
let type = event.type();
|
||||
|
||||
if (type == Clutter.EventType.KEY_PRESS &&
|
||||
event.get_key_symbol() == Clutter.KEY_Escape) {
|
||||
this.ungrab({ isUser: true });
|
||||
return true;
|
||||
}
|
||||
|
||||
let press = type == Clutter.EventType.BUTTON_PRESS;
|
||||
let release = type == Clutter.EventType.BUTTON_RELEASE;
|
||||
let button = press || release;
|
||||
@ -340,6 +328,12 @@ const GrabHelper = new Lang.Class({
|
||||
if (!button && this._modalCount == 0)
|
||||
return false;
|
||||
|
||||
if (type == Clutter.EventType.KEY_PRESS &&
|
||||
event.get_key_symbol() == Clutter.KEY_Escape) {
|
||||
this.ungrab({ isUser: true });
|
||||
return true;
|
||||
}
|
||||
|
||||
if (this._isWithinGrabbedActor(event.get_source()))
|
||||
return false;
|
||||
|
||||
@ -359,9 +353,6 @@ const GrabHelper = new Lang.Class({
|
||||
},
|
||||
|
||||
_onKeyFocusChanged: function() {
|
||||
if (this._isUngrabbingCount > 0)
|
||||
return;
|
||||
|
||||
let focus = global.stage.key_focus;
|
||||
if (!focus || !this._isWithinGrabbedActor(focus))
|
||||
this.ungrab({ isUser: true });
|
||||
|
@ -3,149 +3,107 @@
|
||||
const Clutter = imports.gi.Clutter;
|
||||
const IBus = imports.gi.IBus;
|
||||
const Lang = imports.lang;
|
||||
const Signals = imports.signals;
|
||||
const St = imports.gi.St;
|
||||
|
||||
const BoxPointer = imports.ui.boxpointer;
|
||||
const Main = imports.ui.main;
|
||||
const PopupMenu = imports.ui.popupMenu;
|
||||
|
||||
const MAX_CANDIDATES_PER_PAGE = 16;
|
||||
|
||||
const CandidateArea = new Lang.Class({
|
||||
Name: 'CandidateArea',
|
||||
Extends: PopupMenu.PopupBaseMenuItem,
|
||||
|
||||
_init: function() {
|
||||
this.actor = new St.BoxLayout({ vertical: true,
|
||||
visible: false });
|
||||
this._candidateBoxes = [];
|
||||
this.parent({ reactive: false });
|
||||
|
||||
// St.Table exhibits some sizing problems so let's go with a
|
||||
// clutter layout manager for now.
|
||||
this._table = new Clutter.Actor();
|
||||
this.addActor(this._table);
|
||||
|
||||
this._tableLayout = new Clutter.TableLayout();
|
||||
this._table.set_layout_manager(this._tableLayout);
|
||||
|
||||
this._indexLabels = [];
|
||||
this._candidateLabels = [];
|
||||
for (let i = 0; i < MAX_CANDIDATES_PER_PAGE; ++i) {
|
||||
let box = new St.BoxLayout({ style_class: 'candidate-box',
|
||||
reactive: true,
|
||||
track_hover: true });
|
||||
box._indexLabel = new St.Label({ style_class: 'candidate-index' });
|
||||
box._candidateLabel = new St.Label({ style_class: 'candidate-label' });
|
||||
box.add(box._indexLabel, { y_fill: false });
|
||||
box.add(box._candidateLabel, { y_fill: false });
|
||||
this._candidateBoxes.push(box);
|
||||
this.actor.add(box);
|
||||
|
||||
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());
|
||||
}));
|
||||
this._indexLabels.push(new St.Label({ style_class: 'candidate-index' }));
|
||||
this._candidateLabels.push(new St.Label({ style_class: 'candidate-label' }));
|
||||
}
|
||||
|
||||
this._buttonBox = new St.BoxLayout({ style_class: 'candidate-page-button-box' });
|
||||
|
||||
this._previousButton = new St.Button({ style_class: 'candidate-page-button candidate-page-button-previous' });
|
||||
this._previousButton.child = new St.Icon({ style_class: 'candidate-page-button-icon' });
|
||||
this._buttonBox.add(this._previousButton, { expand: true });
|
||||
|
||||
this._nextButton = new St.Button({ style_class: 'candidate-page-button candidate-page-button-next' });
|
||||
this._nextButton.child = new St.Icon({ style_class: 'candidate-page-button-icon' });
|
||||
this._buttonBox.add(this._nextButton, { expand: true });
|
||||
|
||||
this.actor.add(this._buttonBox);
|
||||
|
||||
this._previousButton.connect('clicked', Lang.bind(this, function() {
|
||||
this.emit('previous-page');
|
||||
}));
|
||||
this._nextButton.connect('clicked', Lang.bind(this, function() {
|
||||
this.emit('next-page');
|
||||
}));
|
||||
|
||||
this._orientation = -1;
|
||||
this._cursorPosition = 0;
|
||||
},
|
||||
|
||||
setOrientation: function(orientation) {
|
||||
_setOrientation: function(orientation) {
|
||||
if (this._orientation == orientation)
|
||||
return;
|
||||
|
||||
this._orientation = orientation;
|
||||
|
||||
if (this._orientation == IBus.Orientation.HORIZONTAL) {
|
||||
this.actor.vertical = false;
|
||||
this.actor.remove_style_class_name('vertical');
|
||||
this.actor.add_style_class_name('horizontal');
|
||||
this._previousButton.child.icon_name = 'go-previous-symbolic';
|
||||
this._nextButton.child.icon_name = 'go-next-symbolic';
|
||||
} else { // VERTICAL || SYSTEM
|
||||
this.actor.vertical = true;
|
||||
this.actor.add_style_class_name('vertical');
|
||||
this.actor.remove_style_class_name('horizontal');
|
||||
this._previousButton.child.icon_name = 'go-up-symbolic';
|
||||
this._nextButton.child.icon_name = 'go-down-symbolic';
|
||||
this._table.remove_all_children();
|
||||
|
||||
if (this._orientation == IBus.Orientation.HORIZONTAL)
|
||||
for (let i = 0; i < MAX_CANDIDATES_PER_PAGE; ++i) {
|
||||
this._tableLayout.pack(this._indexLabels[i], i*2, 0);
|
||||
this._tableLayout.pack(this._candidateLabels[i], i*2 + 1, 0);
|
||||
}
|
||||
else // VERTICAL || SYSTEM
|
||||
for (let i = 0; i < MAX_CANDIDATES_PER_PAGE; ++i) {
|
||||
this._tableLayout.pack(this._indexLabels[i], 0, i);
|
||||
this._tableLayout.pack(this._candidateLabels[i], 1, i);
|
||||
}
|
||||
},
|
||||
|
||||
setCandidates: function(indexes, candidates, cursorPosition, cursorVisible) {
|
||||
setCandidates: function(indexes, candidates, orientation, cursorPosition, cursorVisible) {
|
||||
this._setOrientation(orientation);
|
||||
|
||||
for (let i = 0; i < MAX_CANDIDATES_PER_PAGE; ++i) {
|
||||
let visible = i < candidates.length;
|
||||
let box = this._candidateBoxes[i];
|
||||
box.visible = visible;
|
||||
this._indexLabels[i].visible = visible;
|
||||
this._candidateLabels[i].visible = visible;
|
||||
|
||||
if (!visible)
|
||||
continue;
|
||||
|
||||
box._indexLabel.text = ((indexes && indexes[i]) ? indexes[i] : '%x'.format(i + 1));
|
||||
box._candidateLabel.text = candidates[i];
|
||||
this._indexLabels[i].text = ((indexes && indexes[i]) ? indexes[i] : '%x.'.format(i + 1));
|
||||
this._candidateLabels[i].text = candidates[i];
|
||||
}
|
||||
|
||||
this._candidateBoxes[this._cursorPosition].remove_style_pseudo_class('selected');
|
||||
this._candidateLabels[this._cursorPosition].remove_style_pseudo_class('selected');
|
||||
this._cursorPosition = cursorPosition;
|
||||
if (cursorVisible)
|
||||
this._candidateBoxes[cursorPosition].add_style_pseudo_class('selected');
|
||||
},
|
||||
|
||||
updateButtons: function(wrapsAround, page, nPages) {
|
||||
if (nPages < 2) {
|
||||
this._buttonBox.hide();
|
||||
return;
|
||||
}
|
||||
this._buttonBox.show();
|
||||
this._previousButton.reactive = wrapsAround || page > 0;
|
||||
this._nextButton.reactive = wrapsAround || page < nPages - 1;
|
||||
this._candidateLabels[cursorPosition].add_style_pseudo_class('selected');
|
||||
},
|
||||
});
|
||||
Signals.addSignalMethods(CandidateArea.prototype);
|
||||
|
||||
const CandidatePopup = new Lang.Class({
|
||||
Name: 'CandidatePopup',
|
||||
Extends: PopupMenu.PopupMenu,
|
||||
|
||||
_init: function() {
|
||||
this._cursor = new St.Bin({ opacity: 0 });
|
||||
Main.uiGroup.add_actor(this._cursor);
|
||||
|
||||
this._boxPointer = new BoxPointer.BoxPointer(St.Side.TOP);
|
||||
this._boxPointer.actor.visible = false;
|
||||
this._boxPointer.actor.style_class = 'candidate-popup-boxpointer';
|
||||
Main.layoutManager.addChrome(this._boxPointer.actor);
|
||||
this.parent(this._cursor, 0, St.Side.TOP);
|
||||
this.actor.hide();
|
||||
Main.uiGroup.add_actor(this.actor);
|
||||
|
||||
let box = new St.BoxLayout({ style_class: 'candidate-popup-content',
|
||||
vertical: true });
|
||||
this._boxPointer.bin.set_child(box);
|
||||
this._preeditTextItem = new PopupMenu.PopupMenuItem('', { reactive: false });
|
||||
this._preeditTextItem.actor.hide();
|
||||
this.addMenuItem(this._preeditTextItem);
|
||||
|
||||
this._preeditText = new St.Label({ style_class: 'candidate-popup-text',
|
||||
visible: false });
|
||||
box.add(this._preeditText);
|
||||
this._auxTextItem = new PopupMenu.PopupMenuItem('', { reactive: false });
|
||||
this._auxTextItem.actor.hide();
|
||||
this.addMenuItem(this._auxTextItem);
|
||||
|
||||
this._auxText = new St.Label({ style_class: 'candidate-popup-text',
|
||||
visible: false });
|
||||
box.add(this._auxText);
|
||||
this.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
|
||||
|
||||
this._candidateArea = new CandidateArea();
|
||||
box.add(this._candidateArea.actor);
|
||||
|
||||
this._candidateArea.connect('previous-page', Lang.bind(this, function() {
|
||||
this._panelService.page_up();
|
||||
}));
|
||||
this._candidateArea.connect('next-page', Lang.bind(this, function() {
|
||||
this._panelService.page_down();
|
||||
}));
|
||||
this._candidateArea.connect('candidate-clicked', Lang.bind(this, function(ca, index, button, state) {
|
||||
this._panelService.candidate_clicked(index, button, state);
|
||||
}));
|
||||
this._lookupTableItem = new CandidateArea();
|
||||
this._lookupTableItem.actor.hide();
|
||||
this.addMenuItem(this._lookupTableItem);
|
||||
|
||||
this._panelService = null;
|
||||
},
|
||||
@ -159,61 +117,66 @@ const CandidatePopup = new Lang.Class({
|
||||
Lang.bind(this, function(ps, x, y, w, h) {
|
||||
this._cursor.set_position(x, y);
|
||||
this._cursor.set_size(w, h);
|
||||
if (this._boxPointer.actor.visible)
|
||||
this._boxPointer.setPosition(this._cursor, 0);
|
||||
}));
|
||||
panelService.connect('update-preedit-text',
|
||||
Lang.bind(this, function(ps, text, cursorPosition, visible) {
|
||||
this._preeditText.visible = visible;
|
||||
if (visible)
|
||||
this._preeditTextItem.actor.show();
|
||||
else
|
||||
this._preeditTextItem.actor.hide();
|
||||
this._updateVisibility();
|
||||
|
||||
this._preeditText.text = text.get_text();
|
||||
this._preeditTextItem.actor.label_actor.text = text.get_text();
|
||||
|
||||
let attrs = text.get_attributes();
|
||||
if (attrs)
|
||||
this._setTextAttributes(this._preeditText.clutter_text,
|
||||
this._setTextAttributes(this._preeditTextItem.actor.label_actor.clutter_text,
|
||||
attrs);
|
||||
}));
|
||||
panelService.connect('show-preedit-text',
|
||||
Lang.bind(this, function(ps) {
|
||||
this._preeditText.show();
|
||||
this._preeditTextItem.actor.show();
|
||||
this._updateVisibility();
|
||||
}));
|
||||
panelService.connect('hide-preedit-text',
|
||||
Lang.bind(this, function(ps) {
|
||||
this._preeditText.hide();
|
||||
this._preeditTextItem.actor.hide();
|
||||
this._updateVisibility();
|
||||
}));
|
||||
panelService.connect('update-auxiliary-text',
|
||||
Lang.bind(this, function(ps, text, visible) {
|
||||
this._auxText.visible = visible;
|
||||
if (visible)
|
||||
this._auxTextItem.actor.show();
|
||||
else
|
||||
this._auxTextItem.actor.hide();
|
||||
this._updateVisibility();
|
||||
|
||||
this._auxText.text = text.get_text();
|
||||
this._auxTextItem.actor.label_actor.text = text.get_text();
|
||||
}));
|
||||
panelService.connect('show-auxiliary-text',
|
||||
Lang.bind(this, function(ps) {
|
||||
this._auxText.show();
|
||||
this._auxTextItem.actor.show();
|
||||
this._updateVisibility();
|
||||
}));
|
||||
panelService.connect('hide-auxiliary-text',
|
||||
Lang.bind(this, function(ps) {
|
||||
this._auxText.hide();
|
||||
this._auxTextItem.actor.hide();
|
||||
this._updateVisibility();
|
||||
}));
|
||||
panelService.connect('update-lookup-table',
|
||||
Lang.bind(this, function(ps, lookupTable, visible) {
|
||||
this._candidateArea.actor.visible = visible;
|
||||
if (visible)
|
||||
this._lookupTableItem.actor.show();
|
||||
else
|
||||
this._lookupTableItem.actor.hide();
|
||||
this._updateVisibility();
|
||||
|
||||
let nCandidates = lookupTable.get_number_of_candidates();
|
||||
let cursorPos = lookupTable.get_cursor_pos();
|
||||
let pageSize = lookupTable.get_page_size();
|
||||
let nPages = Math.ceil(nCandidates / pageSize);
|
||||
let page = ((cursorPos == 0) ? 0 : Math.floor(cursorPos / pageSize));
|
||||
let startIndex = page * pageSize;
|
||||
let endIndex = Math.min((page + 1) * pageSize, nCandidates);
|
||||
|
||||
let endIndex = Math.min((page + 1) * pageSize,
|
||||
lookupTable.get_number_of_candidates());
|
||||
let indexes = [];
|
||||
let indexLabel;
|
||||
for (let i = 0; indexLabel = lookupTable.get_label(i); ++i)
|
||||
@ -223,41 +186,37 @@ const CandidatePopup = new Lang.Class({
|
||||
for (let i = startIndex; i < endIndex; ++i)
|
||||
candidates.push(lookupTable.get_candidate(i).get_text());
|
||||
|
||||
this._candidateArea.setCandidates(indexes,
|
||||
this._lookupTableItem.setCandidates(indexes,
|
||||
candidates,
|
||||
lookupTable.get_orientation(),
|
||||
cursorPos % pageSize,
|
||||
lookupTable.is_cursor_visible());
|
||||
this._candidateArea.setOrientation(lookupTable.get_orientation());
|
||||
this._candidateArea.updateButtons(lookupTable.is_round(), page, nPages);
|
||||
}));
|
||||
panelService.connect('show-lookup-table',
|
||||
Lang.bind(this, function(ps) {
|
||||
this._candidateArea.actor.show();
|
||||
this._lookupTableItem.actor.show();
|
||||
this._updateVisibility();
|
||||
}));
|
||||
panelService.connect('hide-lookup-table',
|
||||
Lang.bind(this, function(ps) {
|
||||
this._candidateArea.actor.hide();
|
||||
this._lookupTableItem.actor.hide();
|
||||
this._updateVisibility();
|
||||
}));
|
||||
panelService.connect('focus-out',
|
||||
Lang.bind(this, function(ps) {
|
||||
this._boxPointer.hide(BoxPointer.PopupAnimation.NONE);
|
||||
this.close(BoxPointer.PopupAnimation.NONE);
|
||||
}));
|
||||
},
|
||||
|
||||
_updateVisibility: function() {
|
||||
let isVisible = (this._preeditText.visible ||
|
||||
this._auxText.visible ||
|
||||
this._candidateArea.actor.visible);
|
||||
let isVisible = (this._preeditTextItem.actor.visible ||
|
||||
this._auxTextItem.actor.visible ||
|
||||
this._lookupTableItem.actor.visible);
|
||||
|
||||
if (isVisible) {
|
||||
this._boxPointer.setPosition(this._cursor, 0);
|
||||
this._boxPointer.show(BoxPointer.PopupAnimation.NONE);
|
||||
this._boxPointer.actor.raise_top();
|
||||
} else {
|
||||
this._boxPointer.hide(BoxPointer.PopupAnimation.NONE);
|
||||
}
|
||||
if (isVisible)
|
||||
this.open(BoxPointer.PopupAnimation.NONE);
|
||||
else
|
||||
this.close(BoxPointer.PopupAnimation.NONE);
|
||||
},
|
||||
|
||||
_setTextAttributes: function(clutterText, ibusAttrList) {
|
||||
|
@ -176,16 +176,13 @@ const IconGrid = new Lang.Class({
|
||||
_init: function(params) {
|
||||
params = Params.parse(params, { rowLimit: null,
|
||||
columnLimit: null,
|
||||
fillParent: false,
|
||||
xAlign: St.Align.MIDDLE });
|
||||
this._rowLimit = params.rowLimit;
|
||||
this._colLimit = params.columnLimit;
|
||||
this._xAlign = params.xAlign;
|
||||
this._fillParent = params.fillParent;
|
||||
|
||||
this.actor = new St.BoxLayout({ style_class: 'icon-grid',
|
||||
vertical: true });
|
||||
|
||||
// Pulled from CSS, but hardcode some defaults here
|
||||
this._spacing = 0;
|
||||
this._hItemSize = this._vItemSize = ICON_SIZE;
|
||||
@ -199,11 +196,6 @@ const IconGrid = new Lang.Class({
|
||||
},
|
||||
|
||||
_getPreferredWidth: function (grid, forHeight, alloc) {
|
||||
if (this._fillParent)
|
||||
// Ignore all size requests of children and request a size of 0;
|
||||
// later we'll allocate as many children as fit the parent
|
||||
return;
|
||||
|
||||
let children = this._grid.get_children();
|
||||
let nColumns = this._colLimit ? Math.min(this._colLimit,
|
||||
children.length)
|
||||
@ -225,20 +217,12 @@ const IconGrid = new Lang.Class({
|
||||
},
|
||||
|
||||
_getPreferredHeight: function (grid, forWidth, alloc) {
|
||||
if (this._fillParent)
|
||||
// Ignore all size requests of children and request a size of 0;
|
||||
// later we'll allocate as many children as fit the parent
|
||||
return;
|
||||
|
||||
let children = this._getVisibleChildren();
|
||||
let nColumns, spacing;
|
||||
if (forWidth < 0) {
|
||||
let nColumns;
|
||||
if (forWidth < 0)
|
||||
nColumns = children.length;
|
||||
spacing = this._spacing;
|
||||
} else {
|
||||
[nColumns, , spacing] = this._computeLayout(forWidth);
|
||||
}
|
||||
|
||||
else
|
||||
nColumns = this._computeLayout(forWidth)[0];
|
||||
let nRows;
|
||||
if (nColumns > 0)
|
||||
nRows = Math.ceil(children.length / nColumns);
|
||||
@ -246,25 +230,18 @@ const IconGrid = new Lang.Class({
|
||||
nRows = 0;
|
||||
if (this._rowLimit)
|
||||
nRows = Math.min(nRows, this._rowLimit);
|
||||
let totalSpacing = Math.max(0, nRows - 1) * spacing;
|
||||
let totalSpacing = Math.max(0, nRows - 1) * this._spacing;
|
||||
let height = nRows * this._vItemSize + totalSpacing;
|
||||
alloc.min_size = height;
|
||||
alloc.natural_size = height;
|
||||
},
|
||||
|
||||
_allocate: function (grid, box, flags) {
|
||||
if (this._fillParent) {
|
||||
// Reset the passed in box to fill the parent
|
||||
let parentBox = this.actor.get_parent().allocation;
|
||||
let gridBox = this.actor.get_theme_node().get_content_box(parentBox);
|
||||
box = this._grid.get_theme_node().get_content_box(gridBox);
|
||||
}
|
||||
|
||||
let children = this._getVisibleChildren();
|
||||
let availWidth = box.x2 - box.x1;
|
||||
let availHeight = box.y2 - box.y1;
|
||||
|
||||
let [nColumns, usedWidth, spacing] = this._computeLayout(availWidth);
|
||||
let [nColumns, usedWidth] = this._computeLayout(availWidth);
|
||||
|
||||
let leftPadding;
|
||||
switch(this._xAlign) {
|
||||
@ -303,8 +280,7 @@ const IconGrid = new Lang.Class({
|
||||
childBox.x2 = childBox.x1 + width;
|
||||
childBox.y2 = childBox.y1 + height;
|
||||
|
||||
if (this._rowLimit && rowIndex >= this._rowLimit ||
|
||||
this._fillParent && childBox.y2 > availHeight) {
|
||||
if (this._rowLimit && rowIndex >= this._rowLimit) {
|
||||
this._grid.set_skip_paint(children[i], true);
|
||||
} else {
|
||||
children[i].allocate(childBox, flags);
|
||||
@ -318,10 +294,10 @@ const IconGrid = new Lang.Class({
|
||||
}
|
||||
|
||||
if (columnIndex == 0) {
|
||||
y += this._vItemSize + spacing;
|
||||
y += this._vItemSize + this._spacing;
|
||||
x = box.x1 + leftPadding;
|
||||
} else {
|
||||
x += this._hItemSize + spacing;
|
||||
x += this._hItemSize + this._spacing;
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -337,25 +313,16 @@ const IconGrid = new Lang.Class({
|
||||
_computeLayout: function (forWidth) {
|
||||
let nColumns = 0;
|
||||
let usedWidth = 0;
|
||||
let spacing = this._spacing;
|
||||
|
||||
if (this._colLimit) {
|
||||
let itemWidth = this._hItemSize * this._colLimit;
|
||||
let emptyArea = forWidth - itemWidth;
|
||||
spacing = Math.max(this._spacing, emptyArea / (2 * this._colLimit));
|
||||
spacing = Math.round(spacing);
|
||||
}
|
||||
|
||||
while ((this._colLimit == null || nColumns < this._colLimit) &&
|
||||
(usedWidth + this._hItemSize <= forWidth)) {
|
||||
usedWidth += this._hItemSize + spacing;
|
||||
usedWidth += this._hItemSize + this._spacing;
|
||||
nColumns += 1;
|
||||
}
|
||||
|
||||
if (nColumns > 0)
|
||||
usedWidth -= spacing;
|
||||
usedWidth -= this._spacing;
|
||||
|
||||
return [nColumns, usedWidth, spacing];
|
||||
return [nColumns, usedWidth];
|
||||
},
|
||||
|
||||
_onStyleChanged: function() {
|
||||
|
@ -2,21 +2,18 @@
|
||||
|
||||
const Caribou = imports.gi.Caribou;
|
||||
const Clutter = imports.gi.Clutter;
|
||||
const DBus = imports.dbus;
|
||||
const Gdk = imports.gi.Gdk;
|
||||
const Gio = imports.gi.Gio;
|
||||
const GLib = imports.gi.GLib;
|
||||
const Lang = imports.lang;
|
||||
const Shell = imports.gi.Shell;
|
||||
const Signals = imports.signals;
|
||||
const St = imports.gi.St;
|
||||
|
||||
const BoxPointer = imports.ui.boxpointer;
|
||||
const Layout = imports.ui.layout;
|
||||
const Main = imports.ui.main;
|
||||
const MessageTray = imports.ui.messageTray;
|
||||
|
||||
const KEYBOARD_REST_TIME = Layout.KEYBOARD_ANIMATION_TIME * 2 * 1000;
|
||||
|
||||
const KEYBOARD_SCHEMA = 'org.gnome.shell.keyboard';
|
||||
const KEYBOARD_TYPE = 'keyboard-type';
|
||||
|
||||
@ -59,7 +56,14 @@ const Key = new Lang.Class({
|
||||
if (this._key.name == 'Control_L' || this._key.name == 'Alt_L')
|
||||
this._key.latch = true;
|
||||
|
||||
this._key.connect('key-pressed', Lang.bind(this, function ()
|
||||
{ this.actor.checked = true }));
|
||||
this._key.connect('key-released', Lang.bind(this, function ()
|
||||
{ this.actor.checked = false; }));
|
||||
|
||||
if (this._extended_keys.length > 0) {
|
||||
this._grabbed = false;
|
||||
this._eventCaptureId = 0;
|
||||
this._key.connect('notify::show-subkeys', Lang.bind(this, this._onShowSubkeysChanged));
|
||||
this._boxPointer = new BoxPointer.BoxPointer(St.Side.BOTTOM,
|
||||
{ x_fill: true,
|
||||
@ -111,23 +115,52 @@ const Key = new Lang.Class({
|
||||
this._boxPointer.bin.add_actor(this._extended_keyboard);
|
||||
},
|
||||
|
||||
get subkeys() {
|
||||
return this._boxPointer;
|
||||
_onEventCapture: function (actor, event) {
|
||||
let source = event.get_source();
|
||||
let type = event.type();
|
||||
|
||||
if ((type == Clutter.EventType.BUTTON_PRESS ||
|
||||
type == Clutter.EventType.BUTTON_RELEASE) &&
|
||||
this._extended_keyboard.contains(source)) {
|
||||
source.extended_key.press();
|
||||
source.extended_key.release();
|
||||
return false;
|
||||
}
|
||||
if (type == Clutter.EventType.BUTTON_PRESS) {
|
||||
this._boxPointer.actor.hide();
|
||||
this._ungrab();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
_ungrab: function () {
|
||||
global.stage.disconnect(this._eventCaptureId);
|
||||
this._eventCaptureId = 0;
|
||||
this._grabbed = false;
|
||||
Main.popModal(this.actor);
|
||||
},
|
||||
|
||||
_onShowSubkeysChanged: function () {
|
||||
if (this._key.show_subkeys) {
|
||||
this.actor.fake_release();
|
||||
this._boxPointer.actor.raise_top();
|
||||
this._boxPointer.setPosition(this.actor, 0.5);
|
||||
this.emit('show-subkeys');
|
||||
this.actor.fake_release();
|
||||
this._boxPointer.show(BoxPointer.PopupAnimation.FULL);
|
||||
this.actor.set_hover(false);
|
||||
if (!this._grabbed) {
|
||||
Main.pushModal(this.actor);
|
||||
this._eventCaptureId = global.stage.connect('captured-event', Lang.bind(this, this._onEventCapture));
|
||||
this._grabbed = true;
|
||||
}
|
||||
this._key.release();
|
||||
} else {
|
||||
this.emit('hide-subkeys');
|
||||
if (this._grabbed)
|
||||
this._ungrab();
|
||||
this._boxPointer.hide(BoxPointer.PopupAnimation.FULL);
|
||||
}
|
||||
}
|
||||
});
|
||||
Signals.addSignalMethods(Key.prototype);
|
||||
|
||||
const Keyboard = new Lang.Class({
|
||||
// HACK: we can't set Name, because it collides with Name dbus property
|
||||
@ -142,26 +175,16 @@ const Keyboard = new Lang.Class({
|
||||
this._focusInExtendedKeys = false;
|
||||
|
||||
this._timestamp = global.display.get_current_time_roundtrip();
|
||||
Main.layoutManager.connect('monitors-changed', Lang.bind(this, this._redraw));
|
||||
|
||||
this._keyboardSettings = new Gio.Settings({ schema: KEYBOARD_SCHEMA });
|
||||
this._keyboardSettings.connect('changed', Lang.bind(this, this._settingsChanged));
|
||||
this._a11yApplicationsSettings = new Gio.Settings({ schema: A11Y_APPLICATIONS_SCHEMA });
|
||||
this._a11yApplicationsSettings.connect('changed', Lang.bind(this, this._settingsChanged));
|
||||
this._settingsChanged();
|
||||
},
|
||||
|
||||
this._showIdleId = 0;
|
||||
this._subkeysBoxPointer = null;
|
||||
this._capturedEventId = 0;
|
||||
this._capturedPress = false;
|
||||
|
||||
this._keyboardVisible = false;
|
||||
Main.layoutManager.connect('keyboard-visible-changed', Lang.bind(this, function(o, visible) {
|
||||
this._keyboardVisible = visible;
|
||||
}));
|
||||
this._keyboardRequested = false;
|
||||
this._keyboardRestingId = 0;
|
||||
|
||||
Main.layoutManager.connect('monitors-changed', Lang.bind(this, this._redraw));
|
||||
init: function () {
|
||||
this._redraw();
|
||||
},
|
||||
|
||||
@ -176,19 +199,25 @@ const Keyboard = new Lang.Class({
|
||||
if (this._keyboard)
|
||||
this._destroyKeyboard();
|
||||
|
||||
if (this._enableKeyboard)
|
||||
this._setupKeyboard();
|
||||
else
|
||||
if (this._enableKeyboard) {
|
||||
// If we've been called because the setting actually just
|
||||
// changed to true (as opposed to being called from
|
||||
// this._init()), then we want to pop up the keyboard.
|
||||
let showKeyboard = (settings != null);
|
||||
|
||||
// However, caribou-gtk-module or this._onKeyFocusChanged
|
||||
// will probably immediately tell us to hide it, so we
|
||||
// have to fake things out so we'll ignore that request.
|
||||
if (showKeyboard)
|
||||
this._timestamp = global.display.get_current_time_roundtrip() + 1;
|
||||
this._setupKeyboard(showKeyboard);
|
||||
} else
|
||||
Main.layoutManager.hideKeyboard(true);
|
||||
},
|
||||
|
||||
_destroyKeyboard: function() {
|
||||
if (this._keyboardNotifyId)
|
||||
this._keyboard.disconnect(this._keyboardNotifyId);
|
||||
if (this._keyboardGroupAddedId)
|
||||
this._keyboard.disconnect(this._keyboardGroupAddedId);
|
||||
if (this._keyboardGroupRemovedId)
|
||||
this._keyboard.disconnect(this._keyboardGroupRemovedId);
|
||||
if (this._focusNotifyId)
|
||||
global.stage.disconnect(this._focusNotifyId);
|
||||
this._keyboard = null;
|
||||
@ -198,7 +227,7 @@ const Keyboard = new Lang.Class({
|
||||
this._destroySource();
|
||||
},
|
||||
|
||||
_setupKeyboard: function() {
|
||||
_setupKeyboard: function(show) {
|
||||
this.actor = new St.BoxLayout({ name: 'keyboard', vertical: true, reactive: true });
|
||||
Main.layoutManager.keyboardBox.add_actor(this.actor);
|
||||
Main.layoutManager.trackChrome(this.actor);
|
||||
@ -219,10 +248,11 @@ const Keyboard = new Lang.Class({
|
||||
this.actor.text_direction = Clutter.TextDirection.LTR;
|
||||
|
||||
this._keyboardNotifyId = this._keyboard.connect('notify::active-group', Lang.bind(this, this._onGroupChanged));
|
||||
this._keyboardGroupAddedId = this._keyboard.connect('group-added', Lang.bind(this, this._onGroupAdded));
|
||||
this._keyboardGroupRemovedId = this._keyboard.connect('group-removed', Lang.bind(this, this._onGroupRemoved));
|
||||
this._focusNotifyId = global.stage.connect('notify::key-focus', Lang.bind(this, this._onKeyFocusChanged));
|
||||
|
||||
if (show)
|
||||
this.show(Main.layoutManager.focusIndex);
|
||||
else
|
||||
this._createSource();
|
||||
},
|
||||
|
||||
@ -243,17 +273,16 @@ const Keyboard = new Lang.Class({
|
||||
return;
|
||||
|
||||
let time = global.get_current_time();
|
||||
if (!(focus instanceof Clutter.Text)) {
|
||||
if (focus instanceof Clutter.Text)
|
||||
this.Show(time);
|
||||
else
|
||||
this.Hide(time);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this._showIdleId)
|
||||
this._showIdleId = GLib.idle_add(GLib.PRIORITY_DEFAULT_IDLE,
|
||||
Lang.bind(this, function() { this.Show(time); }));
|
||||
},
|
||||
|
||||
_createLayersForGroup: function (gname) {
|
||||
_addKeys: function () {
|
||||
let groups = this._keyboard.get_groups();
|
||||
for (let i = 0; i < groups.length; ++i) {
|
||||
let gname = groups[i];
|
||||
let group = this._keyboard.get_group(gname);
|
||||
group.connect('notify::active-level', Lang.bind(this, this._onLevelChanged));
|
||||
let layers = {};
|
||||
@ -269,76 +298,63 @@ const Keyboard = new Lang.Class({
|
||||
|
||||
layout.hide();
|
||||
}
|
||||
return layers;
|
||||
},
|
||||
|
||||
_addKeys: function () {
|
||||
let groups = this._keyboard.get_groups();
|
||||
for (let i = 0; i < groups.length; ++i) {
|
||||
let gname = groups[i];
|
||||
this._groups[gname] = this._createLayersForGroup(gname);
|
||||
this._groups[gname] = layers;
|
||||
}
|
||||
|
||||
this._setActiveLayer();
|
||||
},
|
||||
|
||||
_onCapturedEvent: function(actor, event) {
|
||||
let type = event.type();
|
||||
let press = type == Clutter.EventType.BUTTON_PRESS;
|
||||
let release = type == Clutter.EventType.BUTTON_RELEASE;
|
||||
_getTrayIcon: function () {
|
||||
let trayButton = new St.Button ({ label: _("tray"),
|
||||
style_class: 'keyboard-key' });
|
||||
trayButton.key_width = 1;
|
||||
trayButton.connect('button-press-event', Lang.bind(this, function () {
|
||||
Main.messageTray.toggle();
|
||||
}));
|
||||
|
||||
if (press)
|
||||
this._capturedPress = true;
|
||||
else if (release && this._capturedPress)
|
||||
this._hideSubkeys();
|
||||
Main.overview.connect('showing', Lang.bind(this, function () {
|
||||
trayButton.reactive = false;
|
||||
trayButton.add_style_pseudo_class('grayed');
|
||||
}));
|
||||
Main.overview.connect('hiding', Lang.bind(this, function () {
|
||||
trayButton.reactive = true;
|
||||
trayButton.remove_style_pseudo_class('grayed');
|
||||
}));
|
||||
Main.sessionMode.connect('updated', Lang.bind(this, function() {
|
||||
trayButton.reactive = !Main.sessionMode.isLocked;
|
||||
if (Main.sessionMode.isLocked)
|
||||
trayButton.add_style_pseudo_class('grayed');
|
||||
else
|
||||
trayButton.remove_style_pseudo_class('grayed');
|
||||
}));
|
||||
|
||||
return true;
|
||||
return trayButton;
|
||||
},
|
||||
|
||||
_addRows : function (keys, layout) {
|
||||
let keyboard_row = new St.BoxLayout();
|
||||
for (let i = 0; i < keys.length; ++i) {
|
||||
let children = keys[i].get_children();
|
||||
let left_box = new St.BoxLayout({ style_class: 'keyboard-row' });
|
||||
let center_box = new St.BoxLayout({ style_class: 'keyboard-row' });
|
||||
let right_box = new St.BoxLayout({ style_class: 'keyboard-row' });
|
||||
let left_box = new St.BoxLayout({ style_class: 'keyboard-row' });
|
||||
for (let j = 0; j < children.length; ++j) {
|
||||
if (this._numOfHorizKeys == 0)
|
||||
this._numOfHorizKeys = children.length;
|
||||
let key = children[j];
|
||||
let button = new Key(key);
|
||||
|
||||
switch (key.align) {
|
||||
case 'right':
|
||||
if (key.align == 'right')
|
||||
right_box.add(button.actor);
|
||||
break;
|
||||
case 'center':
|
||||
center_box.add(button.actor);
|
||||
break;
|
||||
case 'left':
|
||||
default:
|
||||
else
|
||||
left_box.add(button.actor);
|
||||
break;
|
||||
}
|
||||
if (key.name == 'Caribou_Prefs') {
|
||||
key.connect('key-released', Lang.bind(this, this.hide));
|
||||
}
|
||||
|
||||
button.connect('show-subkeys', Lang.bind(this, function() {
|
||||
if (this._subkeysBoxPointer)
|
||||
this._subkeysBoxPointer.hide(BoxPointer.PopupAnimation.FULL);
|
||||
this._subkeysBoxPointer = button.subkeys;
|
||||
this._subkeysBoxPointer.show(BoxPointer.PopupAnimation.FULL);
|
||||
if (!this._capturedEventId)
|
||||
this._capturedEventId = this.actor.connect('captured-event',
|
||||
Lang.bind(this, this._onCapturedEvent));
|
||||
}));
|
||||
button.connect('hide-subkeys', Lang.bind(this, function() {
|
||||
this._hideSubkeys();
|
||||
}));
|
||||
// Add new key for hiding message tray
|
||||
right_box.add(this._getTrayIcon());
|
||||
}
|
||||
}
|
||||
keyboard_row.add(left_box, { expand: true, x_fill: false, x_align: St.Align.START });
|
||||
keyboard_row.add(center_box, { expand: true, x_fill: false, x_align: St.Align.MIDDLE });
|
||||
keyboard_row.add(right_box, { expand: true, x_fill: false, x_align: St.Align.END });
|
||||
}
|
||||
layout.add(keyboard_row);
|
||||
@ -411,14 +427,6 @@ const Keyboard = new Lang.Class({
|
||||
this._redraw();
|
||||
},
|
||||
|
||||
_onGroupAdded: function (keyboard, gname) {
|
||||
this._groups[gname] = this._createLayersForGroup(gname);
|
||||
},
|
||||
|
||||
_onGroupRemoved: function (keyboard, gname) {
|
||||
delete this._groups[gname];
|
||||
},
|
||||
|
||||
_setActiveLayer: function () {
|
||||
let active_group_name = this._keyboard.active_group;
|
||||
let active_group = this._keyboard.get_group(active_group_name);
|
||||
@ -454,37 +462,7 @@ const Keyboard = new Lang.Class({
|
||||
actor._extended_keys || actor.extended_key;
|
||||
},
|
||||
|
||||
_clearKeyboardRestTimer: function() {
|
||||
if (!this._keyboardRestingId)
|
||||
return;
|
||||
GLib.source_remove(this._keyboardRestingId);
|
||||
this._keyboardRestingId = 0;
|
||||
},
|
||||
|
||||
show: function (monitor) {
|
||||
this._keyboardRequested = true;
|
||||
|
||||
if (this._keyboardVisible) {
|
||||
if (monitor != Main.layoutManager.keyboardIndex) {
|
||||
Main.layoutManager.keyboardIndex = monitor;
|
||||
this._redraw();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
this._clearKeyboardRestTimer();
|
||||
this._keyboardRestingId = GLib.timeout_add(GLib.PRIORITY_DEFAULT,
|
||||
KEYBOARD_REST_TIME,
|
||||
Lang.bind(this, function() {
|
||||
this._clearKeyboardRestTimer();
|
||||
this._show(monitor);
|
||||
}));
|
||||
},
|
||||
|
||||
_show: function(monitor) {
|
||||
if (!this._keyboardRequested)
|
||||
return;
|
||||
|
||||
Main.layoutManager.keyboardIndex = monitor;
|
||||
this._redraw();
|
||||
Main.layoutManager.showKeyboard();
|
||||
@ -492,41 +470,10 @@ const Keyboard = new Lang.Class({
|
||||
},
|
||||
|
||||
hide: function () {
|
||||
this._keyboardRequested = false;
|
||||
|
||||
if (!this._keyboardVisible)
|
||||
return;
|
||||
|
||||
this._clearKeyboardRestTimer();
|
||||
this._keyboardRestingId = GLib.timeout_add(GLib.PRIORITY_DEFAULT,
|
||||
KEYBOARD_REST_TIME,
|
||||
Lang.bind(this, function() {
|
||||
this._clearKeyboardRestTimer();
|
||||
this._hide();
|
||||
}));
|
||||
},
|
||||
|
||||
_hide: function() {
|
||||
if (this._keyboardRequested)
|
||||
return;
|
||||
|
||||
this._hideSubkeys();
|
||||
Main.layoutManager.hideKeyboard();
|
||||
this._createSource();
|
||||
},
|
||||
|
||||
_hideSubkeys: function() {
|
||||
if (this._subkeysBoxPointer) {
|
||||
this._subkeysBoxPointer.hide(BoxPointer.PopupAnimation.FULL);
|
||||
this._subkeysBoxPointer = null;
|
||||
}
|
||||
if (this._capturedEventId) {
|
||||
this.actor.disconnect(this._capturedEventId);
|
||||
this._capturedEventId = 0;
|
||||
}
|
||||
this._capturedPress = false;
|
||||
},
|
||||
|
||||
_moveTemporarily: function () {
|
||||
let currentWindow = global.screen.get_display().focus_window;
|
||||
let rect = currentWindow.get_outer_rect();
|
||||
@ -555,13 +502,6 @@ const Keyboard = new Lang.Class({
|
||||
return one - two;
|
||||
},
|
||||
|
||||
_clearShowIdle: function() {
|
||||
if (!this._showIdleId)
|
||||
return;
|
||||
GLib.source_remove(this._showIdleId);
|
||||
this._showIdleId = 0;
|
||||
},
|
||||
|
||||
// D-Bus methods
|
||||
Show: function(timestamp) {
|
||||
if (!this._enableKeyboard)
|
||||
@ -570,8 +510,6 @@ const Keyboard = new Lang.Class({
|
||||
if (this._compareTimestamp(timestamp, this._timestamp) < 0)
|
||||
return;
|
||||
|
||||
this._clearShowIdle();
|
||||
|
||||
if (timestamp != Clutter.CURRENT_TIME)
|
||||
this._timestamp = timestamp;
|
||||
this.show(Main.layoutManager.focusIndex);
|
||||
@ -584,8 +522,6 @@ const Keyboard = new Lang.Class({
|
||||
if (this._compareTimestamp(timestamp, this._timestamp) < 0)
|
||||
return;
|
||||
|
||||
this._clearShowIdle();
|
||||
|
||||
if (timestamp != Clutter.CURRENT_TIME)
|
||||
this._timestamp = timestamp;
|
||||
this.hide();
|
||||
@ -620,7 +556,11 @@ const KeyboardSource = new Lang.Class({
|
||||
this.keepTrayOnSummaryClick = true;
|
||||
},
|
||||
|
||||
handleSummaryClick: function(button) {
|
||||
handleSummaryClick: function() {
|
||||
let event = Clutter.get_current_event();
|
||||
if (event.type() != Clutter.EventType.BUTTON_RELEASE)
|
||||
return false;
|
||||
|
||||
this.open();
|
||||
return true;
|
||||
},
|
||||
|
1276
js/ui/layout.js
1276
js/ui/layout.js
File diff suppressed because it is too large
Load Diff
@ -3,7 +3,6 @@
|
||||
const Clutter = imports.gi.Clutter;
|
||||
const Lang = imports.lang;
|
||||
const Meta = imports.gi.Meta;
|
||||
const Signals = imports.signals;
|
||||
const St = imports.gi.St;
|
||||
|
||||
const Params = imports.misc.params;
|
||||
@ -102,7 +101,6 @@ const Lightbox = new Lang.Class({
|
||||
},
|
||||
|
||||
show: function() {
|
||||
Tweener.removeTweens(this.actor);
|
||||
if (this._fadeInTime) {
|
||||
this.shown = false;
|
||||
this.actor.opacity = 0;
|
||||
@ -112,20 +110,17 @@ const Lightbox = new Lang.Class({
|
||||
transition: 'easeOutQuad',
|
||||
onComplete: Lang.bind(this, function() {
|
||||
this.shown = true;
|
||||
this.emit('shown');
|
||||
})
|
||||
});
|
||||
} else {
|
||||
this.actor.opacity = 255 * this._fadeFactor;
|
||||
this.shown = true;
|
||||
this.emit('shown');
|
||||
}
|
||||
this.actor.show();
|
||||
},
|
||||
|
||||
hide: function() {
|
||||
this.shown = false;
|
||||
Tweener.removeTweens(this.actor);
|
||||
if (this._fadeOutTime) {
|
||||
Tweener.addTween(this.actor,
|
||||
{ opacity: 0,
|
||||
@ -202,4 +197,3 @@ const Lightbox = new Lang.Class({
|
||||
this.highlight(null);
|
||||
}
|
||||
});
|
||||
Signals.addSignalMethods(Lightbox.prototype);
|
||||
|
@ -39,7 +39,6 @@ var commandHeader = 'const Clutter = imports.gi.Clutter; ' +
|
||||
* in the shell core code too. */
|
||||
'const stage = global.stage; ' +
|
||||
/* Special lookingGlass functions */
|
||||
'const inspect = Lang.bind(Main.lookingGlass, Main.lookingGlass.inspect); ' +
|
||||
'const it = Main.lookingGlass.getIt(); ' +
|
||||
'const r = Lang.bind(Main.lookingGlass, Main.lookingGlass.getResult); ';
|
||||
|
||||
@ -685,8 +684,7 @@ const Memory = new Lang.Class({
|
||||
const Extensions = new Lang.Class({
|
||||
Name: 'Extensions',
|
||||
|
||||
_init: function(lookingGlass) {
|
||||
this._lookingGlass = lookingGlass;
|
||||
_init: function() {
|
||||
this.actor = new St.BoxLayout({ vertical: true,
|
||||
name: 'lookingGlassExtensions' });
|
||||
this._noExtensions = new St.Label({ style_class: 'lg-extensions-none',
|
||||
@ -873,7 +871,8 @@ const LookingGlass = new Lang.Class({
|
||||
inspectIcon.connect('button-press-event', Lang.bind(this, function () {
|
||||
let inspector = new Inspector(this);
|
||||
inspector.connect('target', Lang.bind(this, function(i, target, stageX, stageY) {
|
||||
this._pushResult('inspect(' + Math.round(stageX) + ', ' + Math.round(stageY) + ')', target);
|
||||
this._pushResult('<inspect x:' + stageX + ' y:' + stageY + '>',
|
||||
target);
|
||||
}));
|
||||
inspector.connect('closed', Lang.bind(this, function() {
|
||||
this.actor.show();
|
||||
@ -913,7 +912,7 @@ const LookingGlass = new Lang.Class({
|
||||
this._memory = new Memory();
|
||||
notebook.appendPage('Memory', this._memory.actor);
|
||||
|
||||
this._extensions = new Extensions(this);
|
||||
this._extensions = new Extensions();
|
||||
notebook.appendPage('Extensions', this._extensions.actor);
|
||||
|
||||
this._entry.clutter_text.connect('activate', Lang.bind(this, function (o, e) {
|
||||
@ -951,7 +950,9 @@ const LookingGlass = new Lang.Class({
|
||||
|
||||
_updateFont: function() {
|
||||
let fontName = this._interfaceSettings.get_string('monospace-font-name');
|
||||
let fontDesc = Pango.FontDescription.from_string(fontName);
|
||||
// This is mishandled by the scanner - should by Pango.FontDescription_from_string(fontName);
|
||||
// https://bugzilla.gnome.org/show_bug.cgi?id=595889
|
||||
let fontDesc = Pango.font_description_from_string(fontName);
|
||||
// We ignore everything but size and style; you'd be crazy to set your system-wide
|
||||
// monospace font to be bold/oblique/etc. Could easily be added here.
|
||||
this.actor.style =
|
||||
@ -1056,10 +1057,6 @@ const LookingGlass = new Lang.Class({
|
||||
this._entry.text = '';
|
||||
},
|
||||
|
||||
inspect: function(x, y) {
|
||||
return global.stage.get_actor_at_pos(Clutter.PickMode.REACTIVE, x, y);
|
||||
},
|
||||
|
||||
getIt: function () {
|
||||
return this._it;
|
||||
},
|
||||
@ -1132,7 +1129,7 @@ const LookingGlass = new Lang.Class({
|
||||
if (this._open)
|
||||
return;
|
||||
|
||||
if (!Main.pushModal(this._entry, { keybindingMode: Shell.KeyBindingMode.LOOKING_GLASS }))
|
||||
if (!Main.pushModal(this._entry, { keybindingMode: Main.KeybindingMode.LOOKING_GLASS }))
|
||||
return;
|
||||
|
||||
this._notebook.selectIndex(0);
|
||||
|
175
js/ui/main.js
175
js/ui/main.js
@ -18,7 +18,6 @@ const ExtensionSystem = imports.ui.extensionSystem;
|
||||
const ExtensionDownloader = imports.ui.extensionDownloader;
|
||||
const Keyboard = imports.ui.keyboard;
|
||||
const MessageTray = imports.ui.messageTray;
|
||||
const OsdWindow = imports.ui.osdWindow;
|
||||
const Overview = imports.ui.overview;
|
||||
const Panel = imports.ui.panel;
|
||||
const Params = imports.misc.params;
|
||||
@ -41,6 +40,19 @@ const Util = imports.misc.util;
|
||||
const OVERRIDES_SCHEMA = 'org.gnome.shell.overrides';
|
||||
const DEFAULT_BACKGROUND_COLOR = Clutter.Color.from_pixel(0x2e3436ff);
|
||||
|
||||
const KeybindingMode = {
|
||||
NONE: 0, // block all keybindings
|
||||
NORMAL: 1 << 0, // window mode
|
||||
OVERVIEW: 1 << 1,
|
||||
LOCK_SCREEN: 1 << 2,
|
||||
UNLOCK_SCREEN: 1 << 3,
|
||||
LOGIN_SCREEN: 1 << 4,
|
||||
MESSAGE_TRAY: 1 << 5,
|
||||
SYSTEM_MODAL: 1 << 6,
|
||||
LOOKING_GLASS: 1 << 7,
|
||||
ALL: ~0,
|
||||
};
|
||||
|
||||
let componentManager = null;
|
||||
let panel = null;
|
||||
let overview = null;
|
||||
@ -52,13 +64,12 @@ let screenShield = null;
|
||||
let notificationDaemon = null;
|
||||
let windowAttentionHandler = null;
|
||||
let ctrlAltTabManager = null;
|
||||
let osdWindow = null;
|
||||
let sessionMode = null;
|
||||
let shellDBusService = null;
|
||||
let shellMountOpDBusService = null;
|
||||
let screenSaverDBus = null;
|
||||
let modalCount = 0;
|
||||
let keybindingMode = Shell.KeyBindingMode.NORMAL;
|
||||
let keybindingMode = KeybindingMode.NORMAL;
|
||||
let modalActorFocusStack = [];
|
||||
let uiGroup = null;
|
||||
let magnifier = null;
|
||||
@ -70,17 +81,19 @@ let _defaultCssStylesheet = null;
|
||||
let _cssStylesheet = null;
|
||||
let _overridesSettings = null;
|
||||
|
||||
let background = null;
|
||||
|
||||
function _sessionUpdated() {
|
||||
wm.setCustomKeybindingHandler('panel-main-menu',
|
||||
Shell.KeyBindingMode.NORMAL |
|
||||
Shell.KeyBindingMode.OVERVIEW,
|
||||
KeybindingMode.NORMAL |
|
||||
KeybindingMode.OVERVIEW,
|
||||
sessionMode.hasOverview ? Lang.bind(overview, overview.toggle) : null);
|
||||
wm.allowKeybinding('overlay-key', Shell.KeyBindingMode.NORMAL |
|
||||
Shell.KeyBindingMode.OVERVIEW);
|
||||
wm.allowKeybinding('overlay-key', KeybindingMode.NORMAL |
|
||||
KeybindingMode.OVERVIEW);
|
||||
|
||||
wm.setCustomKeybindingHandler('panel-run-dialog',
|
||||
Shell.KeyBindingMode.NORMAL |
|
||||
Shell.KeyBindingMode.OVERVIEW,
|
||||
KeybindingMode.NORMAL |
|
||||
KeybindingMode.OVERVIEW,
|
||||
sessionMode.hasRunDialog ? openRunDialog : null);
|
||||
if (sessionMode.isGreeter)
|
||||
screenShield.showDialog();
|
||||
@ -91,26 +104,12 @@ function start() {
|
||||
global.logError = window.log;
|
||||
global.log = window.log;
|
||||
|
||||
// Hide the stage until we're ready for it
|
||||
global.stage.hide();
|
||||
|
||||
// Chain up async errors reported from C
|
||||
global.connect('notify-error', function (global, msg, detail) { notifyError(msg, detail); });
|
||||
|
||||
Gio.DesktopAppInfo.set_desktop_env('GNOME');
|
||||
|
||||
sessionMode = new SessionMode.SessionMode();
|
||||
|
||||
// start session after we know what mode we're running in
|
||||
let signalId = sessionMode.connect('updated', function() {
|
||||
sessionMode.disconnect(signalId);
|
||||
startSession();
|
||||
});
|
||||
}
|
||||
|
||||
function startSession() {
|
||||
sessionMode.connect('updated', _loadDefaultStylesheet);
|
||||
|
||||
shellDBusService = new ShellDBus.GnomeShell();
|
||||
shellMountOpDBusService = new ShellMountOperation.GnomeShellMountOpHandler();
|
||||
|
||||
@ -127,19 +126,40 @@ function startSession() {
|
||||
|
||||
tracker.connect('startup-sequence-changed', _queueCheckWorkspaces);
|
||||
|
||||
_loadDefaultStylesheet();
|
||||
// The stage is always covered so Clutter doesn't need to clear it; however
|
||||
// the color is used as the default contents for the Mutter root background
|
||||
// actor so set it anyways.
|
||||
global.stage.color = DEFAULT_BACKGROUND_COLOR;
|
||||
global.stage.no_clear_hint = true;
|
||||
|
||||
_defaultCssStylesheet = global.datadir + '/theme/gnome-shell.css';
|
||||
loadTheme();
|
||||
|
||||
// Set up stage hierarchy to group all UI actors under one container.
|
||||
uiGroup = new Shell.GenericContainer({ name: 'uiGroup' });
|
||||
uiGroup.connect('allocate',
|
||||
function (actor, box, flags) {
|
||||
let children = uiGroup.get_children();
|
||||
for (let i = 0; i < children.length; i++)
|
||||
children[i].allocate_preferred_size(flags);
|
||||
});
|
||||
uiGroup.connect('get-preferred-width',
|
||||
function(actor, forHeight, alloc) {
|
||||
let width = global.stage.width;
|
||||
[alloc.min_size, alloc.natural_size] = [width, width];
|
||||
});
|
||||
uiGroup.connect('get-preferred-height',
|
||||
function(actor, forWidth, alloc) {
|
||||
let height = global.stage.height;
|
||||
[alloc.min_size, alloc.natural_size] = [height, height];
|
||||
});
|
||||
global.window_group.reparent(uiGroup);
|
||||
global.overlay_group.reparent(uiGroup);
|
||||
global.stage.add_actor(uiGroup);
|
||||
|
||||
// Setup the stage hierarchy early
|
||||
layoutManager = new Layout.LayoutManager();
|
||||
|
||||
// Various parts of the codebase still refers to Main.uiGroup
|
||||
// instead using the layoutManager. This keeps that code
|
||||
// working until it's updated.
|
||||
uiGroup = layoutManager.uiGroup;
|
||||
|
||||
xdndHandler = new XdndHandler.XdndHandler();
|
||||
ctrlAltTabManager = new CtrlAltTab.CtrlAltTabManager();
|
||||
osdWindow = new OsdWindow.OsdWindow();
|
||||
overview = new Overview.Overview();
|
||||
wm = new WindowManager.WindowManager();
|
||||
magnifier = new Magnifier.Magnifier();
|
||||
@ -147,9 +167,6 @@ function startSession() {
|
||||
screenShield = new ScreenShield.ScreenShield();
|
||||
else
|
||||
screenShield = new ScreenShield.ScreenShieldFallback();
|
||||
|
||||
// The message tray relies on being constructed
|
||||
// after the panel.
|
||||
panel = new Panel.Panel();
|
||||
messageTray = new MessageTray.MessageTray();
|
||||
keyboard = new Keyboard.Keyboard();
|
||||
@ -158,7 +175,7 @@ function startSession() {
|
||||
componentManager = new Components.ComponentManager();
|
||||
|
||||
layoutManager.init();
|
||||
layoutManager.prepareStartupAnimation();
|
||||
keyboard.init();
|
||||
overview.init();
|
||||
|
||||
global.screen.override_workspace_layout(Meta.ScreenCorner.TOPLEFT,
|
||||
@ -171,9 +188,6 @@ function startSession() {
|
||||
// initiate logouts.
|
||||
EndSessionDialog.init();
|
||||
|
||||
// We're ready for the session manager to move to the next phase
|
||||
Meta.register_with_session();
|
||||
|
||||
_startDate = new Date();
|
||||
|
||||
log('GNOME Shell started at ' + _startDate);
|
||||
@ -198,10 +212,6 @@ function startSession() {
|
||||
|
||||
ExtensionDownloader.init();
|
||||
ExtensionSystem.init();
|
||||
|
||||
layoutManager.connect('startup-prepared', function() {
|
||||
layoutManager.startupAnimation();
|
||||
});
|
||||
}
|
||||
|
||||
let _workspaces = [];
|
||||
@ -385,18 +395,6 @@ function _nWorkspacesChanged() {
|
||||
return false;
|
||||
}
|
||||
|
||||
function _loadDefaultStylesheet() {
|
||||
if (!sessionMode.isPrimary)
|
||||
return;
|
||||
|
||||
let stylesheet = global.datadir + '/theme/' + sessionMode.stylesheetName;
|
||||
if (_defaultCssStylesheet == stylesheet)
|
||||
return;
|
||||
|
||||
_defaultCssStylesheet = stylesheet;
|
||||
loadTheme();
|
||||
}
|
||||
|
||||
/**
|
||||
* getThemeStylesheet:
|
||||
*
|
||||
@ -477,6 +475,17 @@ function notifyError(msg, details) {
|
||||
notify(msg, details);
|
||||
}
|
||||
|
||||
function isWindowActorDisplayedOnWorkspace(win, workspaceIndex) {
|
||||
return win.get_workspace() == workspaceIndex ||
|
||||
(win.get_meta_window() && win.get_meta_window().is_on_all_workspaces());
|
||||
}
|
||||
|
||||
function getWindowActorsForWorkspace(workspaceIndex) {
|
||||
return global.get_window_actors().filter(function (win) {
|
||||
return isWindowActorDisplayedOnWorkspace(win, workspaceIndex);
|
||||
});
|
||||
}
|
||||
|
||||
function _findModal(actor) {
|
||||
for (let i = 0; i < modalActorFocusStack.length; i++) {
|
||||
if (modalActorFocusStack[i].actor == actor)
|
||||
@ -485,6 +494,10 @@ function _findModal(actor) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
function isInModalStack(actor) {
|
||||
return _findModal(actor) != -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* pushModal:
|
||||
* @actor: #ClutterActor which will be given keyboard focus
|
||||
@ -507,7 +520,7 @@ function _findModal(actor) {
|
||||
* - options: Meta.ModalOptions flags to indicate that the pointer is
|
||||
* already grabbed
|
||||
*
|
||||
* - keybindingMode: used to set the current Shell.KeyBindingMode to filter
|
||||
* - keybindingMode: used to set the current Main.KeybindingMode to filter
|
||||
* global keybindings; the default of NONE will filter
|
||||
* out all keybindings
|
||||
*
|
||||
@ -516,7 +529,7 @@ function _findModal(actor) {
|
||||
function pushModal(actor, params) {
|
||||
params = Params.parse(params, { timestamp: global.get_current_time(),
|
||||
options: 0,
|
||||
keybindingMode: Shell.KeyBindingMode.NONE });
|
||||
keybindingMode: KeybindingMode.NONE });
|
||||
|
||||
if (modalCount == 0) {
|
||||
if (!global.begin_modal(params.timestamp, params.options)) {
|
||||
@ -534,20 +547,19 @@ function pushModal(actor, params) {
|
||||
if (index >= 0)
|
||||
popModal(actor);
|
||||
});
|
||||
|
||||
let prevFocus = global.stage.get_key_focus();
|
||||
let prevFocusDestroyId;
|
||||
if (prevFocus != null) {
|
||||
prevFocusDestroyId = prevFocus.connect('destroy', function() {
|
||||
let curFocus = global.stage.get_key_focus();
|
||||
let curFocusDestroyId;
|
||||
if (curFocus != null) {
|
||||
curFocusDestroyId = curFocus.connect('destroy', function() {
|
||||
let index = _findModal(actor);
|
||||
if (index >= 0)
|
||||
modalActorFocusStack[index].prevFocus = null;
|
||||
modalActorFocusStack[index].actor = null;
|
||||
});
|
||||
}
|
||||
modalActorFocusStack.push({ actor: actor,
|
||||
focus: curFocus,
|
||||
destroyId: actorDestroyId,
|
||||
prevFocus: prevFocus,
|
||||
prevFocusDestroyId: prevFocusDestroyId,
|
||||
focusDestroyId: curFocusDestroyId,
|
||||
keybindingMode: keybindingMode });
|
||||
|
||||
keybindingMode = params.keybindingMode;
|
||||
@ -577,7 +589,7 @@ function popModal(actor, timestamp) {
|
||||
global.stage.set_key_focus(null);
|
||||
global.end_modal(timestamp);
|
||||
global.set_stage_input_mode(Shell.StageInputMode.NORMAL);
|
||||
keybindingMode = Shell.KeyBindingMode.NORMAL;
|
||||
keybindingMode = KeybindingMode.NORMAL;
|
||||
|
||||
throw new Error('incorrect pop');
|
||||
}
|
||||
@ -588,33 +600,18 @@ function popModal(actor, timestamp) {
|
||||
record.actor.disconnect(record.destroyId);
|
||||
|
||||
if (focusIndex == modalActorFocusStack.length - 1) {
|
||||
if (record.prevFocus)
|
||||
record.prevFocus.disconnect(record.prevFocusDestroyId);
|
||||
if (record.focus)
|
||||
record.focus.disconnect(record.focusDestroyId);
|
||||
keybindingMode = record.keybindingMode;
|
||||
global.stage.set_key_focus(record.prevFocus);
|
||||
global.stage.set_key_focus(record.focus);
|
||||
} else {
|
||||
// If we have:
|
||||
// global.stage.set_focus(a);
|
||||
// Main.pushModal(b);
|
||||
// Main.pushModal(c);
|
||||
// Main.pushModal(d);
|
||||
//
|
||||
// then we have the stack:
|
||||
// [{ prevFocus: a, actor: b },
|
||||
// { prevFocus: b, actor: c },
|
||||
// { prevFocus: c, actor: d }]
|
||||
//
|
||||
// When actor c is destroyed/popped, if we only simply remove the
|
||||
// record, then the focus stack will be [a, c], rather than the correct
|
||||
// [a, b]. Shift the focus stack up before removing the record to ensure
|
||||
// that we get the correct result.
|
||||
let t = modalActorFocusStack[modalActorFocusStack.length - 1];
|
||||
if (t.prevFocus)
|
||||
t.prevFocus.disconnect(t.prevFocusDestroyId);
|
||||
if (t.focus)
|
||||
t.focus.disconnect(t.focusDestroyId);
|
||||
// Remove from the middle, shift the focus chain up
|
||||
for (let i = modalActorFocusStack.length - 1; i > focusIndex; i--) {
|
||||
modalActorFocusStack[i].prevFocus = modalActorFocusStack[i - 1].prevFocus;
|
||||
modalActorFocusStack[i].prevFocusDestroyId = modalActorFocusStack[i - 1].prevFocusDestroyId;
|
||||
modalActorFocusStack[i].focus = modalActorFocusStack[i - 1].focus;
|
||||
modalActorFocusStack[i].focusDestroyId = modalActorFocusStack[i - 1].focusDestroyId;
|
||||
modalActorFocusStack[i].keybindingMode = modalActorFocusStack[i - 1].keybindingMode;
|
||||
}
|
||||
}
|
||||
@ -626,7 +623,7 @@ function popModal(actor, timestamp) {
|
||||
global.end_modal(timestamp);
|
||||
global.set_stage_input_mode(Shell.StageInputMode.NORMAL);
|
||||
Meta.enable_unredirect_for_screen(global.screen);
|
||||
keybindingMode = Shell.KeyBindingMode.NORMAL;
|
||||
keybindingMode = KeybindingMode.NORMAL;
|
||||
}
|
||||
|
||||
function createLookingGlass() {
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -37,7 +37,7 @@ const ModalDialog = new Lang.Class({
|
||||
params = Params.parse(params, { shellReactive: false,
|
||||
styleClass: null,
|
||||
parentActor: Main.uiGroup,
|
||||
keybindingMode: Shell.KeyBindingMode.SYSTEM_MODAL,
|
||||
keybindingMode: Main.KeybindingMode.SYSTEM_MODAL,
|
||||
shouldFadeIn: true });
|
||||
|
||||
this.state = State.CLOSED;
|
||||
@ -58,9 +58,7 @@ const ModalDialog = new Lang.Class({
|
||||
|
||||
this._group.connect('destroy', Lang.bind(this, this._onGroupDestroy));
|
||||
|
||||
this._pressedKey = null;
|
||||
this._buttonKeys = {};
|
||||
this._group.connect('key-press-event', Lang.bind(this, this._onKeyPressEvent));
|
||||
this._group.connect('key-release-event', Lang.bind(this, this._onKeyReleaseEvent));
|
||||
|
||||
this._backgroundBin = new St.Bin();
|
||||
@ -82,7 +80,7 @@ const ModalDialog = new Lang.Class({
|
||||
let stack = new Shell.Stack();
|
||||
this._backgroundBin.child = stack;
|
||||
|
||||
this._eventBlocker = new Clutter.Actor({ reactive: true });
|
||||
this._eventBlocker = new Clutter.Group({ reactive: true });
|
||||
stack.add_actor(this._eventBlocker);
|
||||
stack.add_actor(this.dialogLayout);
|
||||
} else {
|
||||
@ -98,6 +96,7 @@ const ModalDialog = new Lang.Class({
|
||||
y_align: St.Align.START });
|
||||
|
||||
this.buttonLayout = new St.BoxLayout({ style_class: 'modal-dialog-button-box',
|
||||
visible: false,
|
||||
vertical: false });
|
||||
this.dialogLayout.add(this.buttonLayout,
|
||||
{ expand: true,
|
||||
@ -121,6 +120,7 @@ const ModalDialog = new Lang.Class({
|
||||
|
||||
setButtons: function(buttons) {
|
||||
this.clearButtons();
|
||||
this.buttonLayout.visible = (buttons.length > 0);
|
||||
|
||||
for (let i = 0; i < buttons.length; i++) {
|
||||
let buttonInfo = buttons[i];
|
||||
@ -159,7 +159,6 @@ const ModalDialog = new Lang.Class({
|
||||
keys = [];
|
||||
|
||||
let button = new St.Button({ style_class: 'modal-dialog-button',
|
||||
button_mask: St.ButtonMask.ONE | St.ButtonMask.THREE,
|
||||
reactive: true,
|
||||
can_focus: true,
|
||||
label: label });
|
||||
@ -181,19 +180,10 @@ const ModalDialog = new Lang.Class({
|
||||
return button;
|
||||
},
|
||||
|
||||
_onKeyPressEvent: function(object, event) {
|
||||
this._pressedKey = event.get_key_symbol();
|
||||
},
|
||||
|
||||
_onKeyReleaseEvent: function(object, event) {
|
||||
let pressedKey = this._pressedKey;
|
||||
this._pressedKey = null;
|
||||
|
||||
let symbol = event.get_key_symbol();
|
||||
if (symbol != pressedKey)
|
||||
return false;
|
||||
|
||||
let buttonInfo = this._buttonKeys[symbol];
|
||||
|
||||
if (!buttonInfo)
|
||||
return false;
|
||||
|
||||
@ -276,7 +266,6 @@ const ModalDialog = new Lang.Class({
|
||||
function() {
|
||||
this.state = State.CLOSED;
|
||||
this._group.hide();
|
||||
this.emit('closed');
|
||||
})
|
||||
});
|
||||
},
|
||||
|
@ -103,126 +103,6 @@ const STANDARD_TRAY_ICON_IMPLEMENTATIONS = {
|
||||
'ibus-ui-gtk': 'keyboard'
|
||||
};
|
||||
|
||||
const NotificationGenericPolicy = new Lang.Class({
|
||||
Name: 'NotificationGenericPolicy',
|
||||
Extends: MessageTray.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: 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',
|
||||
|
||||
@ -247,19 +127,30 @@ const NotificationDaemon = new Lang.Class({
|
||||
this._trayManager.manage_stage(global.stage, Main.messageTray.actor);
|
||||
},
|
||||
|
||||
_imageForNotificationData: function(hints) {
|
||||
if (hints['image-data']) {
|
||||
_iconForNotificationData: function(icon, hints) {
|
||||
// If an icon is not specified, we use 'image-data' or 'image-path' hint for an icon
|
||||
// and don't show a large image. There are currently many applications that use
|
||||
// notify_notification_set_icon_from_pixbuf() from libnotify, which in turn sets
|
||||
// the 'image-data' hint. These applications don't typically pass in 'app_icon'
|
||||
// argument to Notify() and actually expect the pixbuf to be shown as an icon.
|
||||
// So the logic here does the right thing for this case. If both an icon and either
|
||||
// one of 'image-data' or 'image-path' are specified, we show both an icon and
|
||||
// a large image.
|
||||
if (icon) {
|
||||
if (icon.substr(0, 7) == 'file://')
|
||||
return new Gio.FileIcon({ file: Gio.File.new_for_uri(icon) });
|
||||
else if (icon[0] == '/') {
|
||||
return new Gio.FileIcon({ file: Gio.File.new_for_path(icon) });
|
||||
} else
|
||||
return new Gio.ThemedIcon({ name: icon });
|
||||
} else if (hints['image-data']) {
|
||||
let [width, height, rowStride, hasAlpha,
|
||||
bitsPerSample, nChannels, data] = hints['image-data'];
|
||||
return Shell.util_create_pixbuf_from_data(data, GdkPixbuf.Colorspace.RGB, hasAlpha,
|
||||
bitsPerSample, width, height, rowStride);
|
||||
} else if (hints['image-path']) {
|
||||
return new Gio.FileIcon({ file: Gio.File.new_for_path(hints['image-path']) });
|
||||
}
|
||||
return null;
|
||||
},
|
||||
|
||||
_fallbackIconForNotificationData: function(hints) {
|
||||
} else {
|
||||
let stockIcon;
|
||||
switch (hints.urgency) {
|
||||
case Urgency.LOW:
|
||||
@ -271,18 +162,7 @@ const NotificationDaemon = new Lang.Class({
|
||||
break;
|
||||
}
|
||||
return new Gio.ThemedIcon({ name: stockIcon });
|
||||
},
|
||||
|
||||
_iconForNotificationData: function(icon) {
|
||||
if (icon) {
|
||||
if (icon.substr(0, 7) == 'file://')
|
||||
return new Gio.FileIcon({ file: Gio.File.new_for_uri(icon) });
|
||||
else if (icon[0] == '/')
|
||||
return new Gio.FileIcon({ file: Gio.File.new_for_path(icon) });
|
||||
else
|
||||
return new Gio.ThemedIcon({ name: icon });
|
||||
}
|
||||
return null;
|
||||
},
|
||||
|
||||
_lookupSource: function(title, pid, trayIcon) {
|
||||
@ -333,7 +213,7 @@ const NotificationDaemon = new Lang.Class({
|
||||
}
|
||||
}
|
||||
|
||||
let source = new Source(title, pid, sender, trayIcon, ndata ? ndata.hints['desktop-entry'] : null);
|
||||
let source = new Source(title, pid, sender, trayIcon);
|
||||
source.setTransient(isForTransientNotification);
|
||||
|
||||
if (!isForTransientNotification) {
|
||||
@ -475,8 +355,12 @@ const NotificationDaemon = new Lang.Class({
|
||||
[ndata.id, ndata.icon, ndata.summary, ndata.body,
|
||||
ndata.actions, ndata.hints, ndata.notification];
|
||||
|
||||
let gicon = this._iconForNotificationData(icon, hints);
|
||||
|
||||
if (notification == null) {
|
||||
notification = new MessageTray.Notification(source);
|
||||
notification = new MessageTray.Notification(source, summary, body,
|
||||
{ gicon: gicon,
|
||||
bannerMarkup: true });
|
||||
ndata.notification = notification;
|
||||
notification.connect('destroy', Lang.bind(this,
|
||||
function(n, reason) {
|
||||
@ -499,38 +383,29 @@ const NotificationDaemon = new Lang.Class({
|
||||
function(n, actionId) {
|
||||
this._emitActionInvoked(ndata.id, actionId);
|
||||
}));
|
||||
}
|
||||
|
||||
// Mark music notifications so they can be shown in the screen shield
|
||||
notification.isMusic = (ndata.hints['category'] == 'x-gnome.music');
|
||||
|
||||
let gicon = this._iconForNotificationData(icon, hints);
|
||||
let gimage = this._imageForNotificationData(hints);
|
||||
|
||||
let image = null;
|
||||
|
||||
// If an icon is not specified, we use 'image-data' or 'image-path' hint for an icon
|
||||
// and don't show a large image. There are currently many applications that use
|
||||
// notify_notification_set_icon_from_pixbuf() from libnotify, which in turn sets
|
||||
// the 'image-data' hint. These applications don't typically pass in 'app_icon'
|
||||
// argument to Notify() and actually expect the pixbuf to be shown as an icon.
|
||||
// So the logic here does the right thing for this case. If both an icon and either
|
||||
// one of 'image-data' or 'image-path' are specified, we show both an icon and
|
||||
// a large image.
|
||||
if (gicon && gimage)
|
||||
image = new St.Icon({ gicon: gimage,
|
||||
icon_size: notification.IMAGE_SIZE });
|
||||
else if (!gicon && gimage)
|
||||
gicon = gimage;
|
||||
else if (!gicon)
|
||||
gicon = this._fallbackIconForNotificationData(hints);
|
||||
|
||||
} else {
|
||||
notification.update(summary, body, { gicon: gicon,
|
||||
bannerMarkup: true,
|
||||
clear: true,
|
||||
soundFile: hints['sound-file'],
|
||||
soundName: hints['sound-name'] });
|
||||
clear: true });
|
||||
}
|
||||
|
||||
// We only display a large image if an icon is also specified.
|
||||
if (icon && (hints['image-data'] || hints['image-path'])) {
|
||||
let image = null;
|
||||
if (hints['image-data']) {
|
||||
let [width, height, rowStride, hasAlpha,
|
||||
bitsPerSample, nChannels, data] = hints['image-data'];
|
||||
image = St.TextureCache.get_default().load_from_raw(data, hasAlpha,
|
||||
width, height, rowStride, notification.IMAGE_SIZE);
|
||||
} else if (hints['image-path']) {
|
||||
image = St.TextureCache.get_default().load_uri_async(GLib.filename_to_uri(hints['image-path'], null),
|
||||
notification.IMAGE_SIZE,
|
||||
notification.IMAGE_SIZE);
|
||||
}
|
||||
notification.setImage(image);
|
||||
} else {
|
||||
notification.unsetImage();
|
||||
}
|
||||
|
||||
if (actions.length) {
|
||||
notification.setUseActionIcons(hints['action-icons'] == true);
|
||||
@ -560,7 +435,7 @@ const NotificationDaemon = new Lang.Class({
|
||||
// of the 'transient' hint with hints['transient'] rather than hints.transient
|
||||
notification.setTransient(hints['transient'] == true);
|
||||
|
||||
let sourceGIcon = source.useNotificationIcon ? gicon : null;
|
||||
let sourceGIcon = source.useNotificationIcon ? this._iconForNotificationData(icon, hints) : null;
|
||||
source.processNotification(notification, sourceGIcon);
|
||||
},
|
||||
|
||||
@ -584,7 +459,7 @@ const NotificationDaemon = new Lang.Class({
|
||||
// 'icon-multi',
|
||||
'icon-static',
|
||||
'persistence',
|
||||
'sound',
|
||||
// 'sound',
|
||||
];
|
||||
},
|
||||
|
||||
@ -640,22 +515,12 @@ const Source = new Lang.Class({
|
||||
Name: 'NotificationDaemonSource',
|
||||
Extends: MessageTray.Source,
|
||||
|
||||
_init: function(title, pid, sender, trayIcon, appId) {
|
||||
// Need to set the app before chaining up, so
|
||||
// methods called from the parent constructor can find it
|
||||
this.trayIcon = trayIcon;
|
||||
this.pid = pid;
|
||||
this.app = this._getApp(appId);
|
||||
|
||||
_init: function(title, pid, sender, trayIcon) {
|
||||
this.parent(title);
|
||||
|
||||
this.initialTitle = title;
|
||||
|
||||
if (this.app)
|
||||
this.title = this.app.get_name();
|
||||
else
|
||||
this.useNotificationIcon = true;
|
||||
|
||||
this.pid = pid;
|
||||
if (sender)
|
||||
this._nameWatcherId = Gio.DBus.session.watch_name(sender,
|
||||
Gio.BusNameWatcherFlags.NONE,
|
||||
@ -664,22 +529,19 @@ const Source = new Lang.Class({
|
||||
else
|
||||
this._nameWatcherId = 0;
|
||||
|
||||
this._setApp();
|
||||
if (this.app)
|
||||
this.title = this.app.get_name();
|
||||
else
|
||||
this.useNotificationIcon = true;
|
||||
|
||||
this.trayIcon = trayIcon;
|
||||
if (this.trayIcon) {
|
||||
// Try again finding the app, using the WM_CLASS from the tray icon
|
||||
this._setSummaryIcon(this.trayIcon);
|
||||
this.useNotificationIcon = false;
|
||||
}
|
||||
},
|
||||
|
||||
_createPolicy: function() {
|
||||
if (this.app) {
|
||||
let id = this.app.get_id().replace(/\.desktop$/,'');
|
||||
return new NotificationApplicationPolicy(id);
|
||||
} else {
|
||||
return new NotificationGenericPolicy();
|
||||
}
|
||||
},
|
||||
|
||||
_onNameVanished: function() {
|
||||
// Destroy the notification source when its sender is removed from DBus.
|
||||
// Only do so if this.app is set to avoid removing "notify-send" sources, senders
|
||||
@ -703,17 +565,19 @@ const Source = new Lang.Class({
|
||||
this.notify(notification);
|
||||
},
|
||||
|
||||
handleSummaryClick: function(button) {
|
||||
handleSummaryClick: function() {
|
||||
if (!this.trayIcon)
|
||||
return false;
|
||||
|
||||
let event = Clutter.get_current_event();
|
||||
if (event.type() != Clutter.EventType.BUTTON_RELEASE)
|
||||
return false;
|
||||
|
||||
// Left clicks are passed through only where there aren't unacknowledged
|
||||
// notifications, so it possible to open them in summary mode; right
|
||||
// clicks are always forwarded, as the right click menu is not useful for
|
||||
// tray icons
|
||||
if (button == 1 &&
|
||||
if (event.get_button() == 1 &&
|
||||
this.notifications.length > 0)
|
||||
return false;
|
||||
|
||||
@ -726,7 +590,7 @@ const Source = new Lang.Class({
|
||||
return true;
|
||||
},
|
||||
|
||||
_getApp: function(appId) {
|
||||
_getApp: function() {
|
||||
let app;
|
||||
|
||||
app = Shell.WindowTracker.get_default().get_app_from_pid(this.pid);
|
||||
@ -734,13 +598,7 @@ const Source = new Lang.Class({
|
||||
return app;
|
||||
|
||||
if (this.trayIcon) {
|
||||
app = Shell.AppSystem.get_default().lookup_wmclass(this.trayIcon.wm_class);
|
||||
if (app != null)
|
||||
return app;
|
||||
}
|
||||
|
||||
if (appId) {
|
||||
app = Shell.AppSystem.get_default().lookup_app(appId + '.desktop');
|
||||
app = Shell.AppSystem.get_default().lookup_wmclass(this.trayIcon.wmclass);
|
||||
if (app != null)
|
||||
return app;
|
||||
}
|
||||
@ -748,11 +606,11 @@ const Source = new Lang.Class({
|
||||
return null;
|
||||
},
|
||||
|
||||
_setApp: function(appId) {
|
||||
_setApp: function() {
|
||||
if (this.app)
|
||||
return;
|
||||
|
||||
this.app = this._getApp(appId);
|
||||
this.app = this._getApp();
|
||||
if (!this.app)
|
||||
return;
|
||||
|
||||
|
@ -1,179 +0,0 @@
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
|
||||
const Clutter = imports.gi.Clutter;
|
||||
const St = imports.gi.St;
|
||||
|
||||
const Lang = imports.lang;
|
||||
const Layout = imports.ui.layout;
|
||||
const Main = imports.ui.main;
|
||||
const Mainloop = imports.mainloop;
|
||||
const Tweener = imports.ui.tweener;
|
||||
|
||||
const HIDE_TIMEOUT = 1500;
|
||||
const FADE_TIME = 0.1;
|
||||
const LEVEL_ANIMATION_TIME = 0.1;
|
||||
|
||||
const LevelBar = new Lang.Class({
|
||||
Name: 'LevelBar',
|
||||
|
||||
_init: function() {
|
||||
this._level = 0;
|
||||
|
||||
this.actor = new St.Bin({ style_class: 'level',
|
||||
x_fill: true, y_fill: true });
|
||||
this._bar = new St.DrawingArea();
|
||||
this._bar.connect('repaint', Lang.bind(this, this._repaint));
|
||||
|
||||
this.actor.set_child(this._bar);
|
||||
},
|
||||
|
||||
get level() {
|
||||
return this._level;
|
||||
},
|
||||
|
||||
set level(value) {
|
||||
let newValue = Math.max(0, Math.min(value, 100));
|
||||
if (newValue == this._level)
|
||||
return;
|
||||
this._level = newValue;
|
||||
this._bar.queue_repaint();
|
||||
},
|
||||
|
||||
_repaint: function() {
|
||||
let cr = this._bar.get_context();
|
||||
|
||||
let node = this.actor.get_theme_node();
|
||||
let radius = node.get_border_radius(0); // assume same radius for all corners
|
||||
Clutter.cairo_set_source_color(cr, node.get_foreground_color());
|
||||
|
||||
let [w, h] = this._bar.get_surface_size();
|
||||
w *= (this._level / 100.);
|
||||
|
||||
if (w == 0)
|
||||
return;
|
||||
|
||||
cr.moveTo(radius, 0);
|
||||
if (w >= radius)
|
||||
cr.arc(w - radius, radius, radius, 1.5 * Math.PI, 2. * Math.PI);
|
||||
else
|
||||
cr.lineTo(w, 0);
|
||||
if (w >= radius)
|
||||
cr.arc(w - radius, h - radius, radius, 0, 0.5 * Math.PI);
|
||||
else
|
||||
cr.lineTo(w, h);
|
||||
cr.arc(radius, h - radius, radius, 0.5 * Math.PI, Math.PI);
|
||||
cr.arc(radius, radius, radius, Math.PI, 1.5 * Math.PI);
|
||||
cr.fill();
|
||||
}
|
||||
});
|
||||
|
||||
const OsdWindow = new Lang.Class({
|
||||
Name: 'OsdWindow',
|
||||
|
||||
_init: function() {
|
||||
this.actor = new St.Widget({ x_expand: true,
|
||||
y_expand: true,
|
||||
x_align: Clutter.ActorAlign.CENTER,
|
||||
y_align: Clutter.ActorAlign.CENTER });
|
||||
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);
|
||||
|
||||
this._icon = new St.Icon();
|
||||
this._box.add(this._icon, { expand: true });
|
||||
|
||||
this._label = new St.Label();
|
||||
this._box.add(this._label);
|
||||
|
||||
this._level = new LevelBar();
|
||||
this._box.add(this._level.actor);
|
||||
|
||||
this._hideTimeoutId = 0;
|
||||
this._reset();
|
||||
|
||||
Main.layoutManager.connect('monitors-changed',
|
||||
Lang.bind(this, this._monitorsChanged));
|
||||
this._monitorsChanged();
|
||||
|
||||
Main.layoutManager.addChrome(this.actor, { affectsInputRegion: false });
|
||||
},
|
||||
|
||||
setIcon: function(icon) {
|
||||
this._icon.gicon = icon;
|
||||
},
|
||||
|
||||
setLabel: function(label) {
|
||||
this._label.visible = (label != undefined);
|
||||
if (label)
|
||||
this._label.text = label;
|
||||
},
|
||||
|
||||
setLevel: function(level) {
|
||||
this._level.actor.visible = (level != undefined);
|
||||
if (this.actor.visible)
|
||||
Tweener.addTween(this._level,
|
||||
{ level: level,
|
||||
time: LEVEL_ANIMATION_TIME,
|
||||
transition: 'easeOutQuad' });
|
||||
else
|
||||
this._level.level = level;
|
||||
},
|
||||
|
||||
show: function() {
|
||||
if (!this._icon.gicon)
|
||||
return;
|
||||
|
||||
if (!this.actor.visible) {
|
||||
this.actor.show();
|
||||
this.actor.opacity = 0;
|
||||
|
||||
Tweener.addTween(this.actor,
|
||||
{ opacity: 255,
|
||||
time: FADE_TIME,
|
||||
transition: 'easeOutQuad' });
|
||||
}
|
||||
|
||||
if (this._hideTimeoutId)
|
||||
Mainloop.source_remove(this._hideTimeoutId);
|
||||
this._hideTimeoutId = Mainloop.timeout_add(HIDE_TIMEOUT,
|
||||
Lang.bind(this, this._hide));
|
||||
},
|
||||
|
||||
cancel: function() {
|
||||
if (!this._hideTimeoutId)
|
||||
return;
|
||||
|
||||
Mainloop.source_remove(this._hideTimeoutId);
|
||||
this._hideTimeoutId = 0;
|
||||
this._hide();
|
||||
},
|
||||
|
||||
_hide: function() {
|
||||
Tweener.addTween(this.actor,
|
||||
{ opacity: 0,
|
||||
time: FADE_TIME,
|
||||
transition: 'easeOutQuad',
|
||||
onComplete: Lang.bind(this, this._reset) });
|
||||
},
|
||||
|
||||
_reset: function() {
|
||||
this.actor.hide();
|
||||
this.setLabel(null);
|
||||
this.setLevel(null);
|
||||
},
|
||||
|
||||
_monitorsChanged: function() {
|
||||
/* assume 130x130 on a 640x480 display and scale from there */
|
||||
let monitor = Main.layoutManager.primaryMonitor;
|
||||
let scalew = monitor.width / 640.0;
|
||||
let scaleh = monitor.height / 480.0;
|
||||
let scale = Math.min(scalew, scaleh);
|
||||
let size = 130 * Math.max(1, scale);
|
||||
|
||||
this._box.set_size(size, size);
|
||||
this._box.translation_y = monitor.height / 4;
|
||||
|
||||
this._icon.icon_size = size / 2;
|
||||
}
|
||||
});
|
@ -10,13 +10,10 @@ const St = imports.gi.St;
|
||||
const Shell = imports.gi.Shell;
|
||||
const Gdk = imports.gi.Gdk;
|
||||
|
||||
const Background = imports.ui.background;
|
||||
const Dash = imports.ui.dash;
|
||||
const DND = imports.ui.dnd;
|
||||
const LayoutManager = imports.ui.layout;
|
||||
const Main = imports.ui.main;
|
||||
const MessageTray = imports.ui.messageTray;
|
||||
const OverviewControls = imports.ui.overviewControls;
|
||||
const Panel = imports.ui.panel;
|
||||
const Params = imports.misc.params;
|
||||
const Tweener = imports.ui.tweener;
|
||||
@ -26,13 +23,26 @@ const WorkspaceThumbnail = imports.ui.workspaceThumbnail;
|
||||
// Time for initial animation going into Overview mode
|
||||
const ANIMATION_TIME = 0.25;
|
||||
|
||||
// Must be less than ANIMATION_TIME, since we switch to
|
||||
// or from the overview completely after ANIMATION_TIME,
|
||||
// and don't want the shading animation to get cut off
|
||||
const SHADE_ANIMATION_TIME = .20;
|
||||
|
||||
const DND_WINDOW_SWITCH_TIMEOUT = 1250;
|
||||
|
||||
const GLSL_DIM_EFFECT_DECLARATIONS = '';
|
||||
const GLSL_DIM_EFFECT_CODE = '\
|
||||
vec2 dist = cogl_tex_coord_in[0].xy - vec2(0.5, 0.5); \
|
||||
float elipse_radius = 0.5; \
|
||||
/* from https://bugzilla.gnome.org/show_bug.cgi?id=669798: \
|
||||
the alpha on the gradient goes from 250 at its darkest to 180 at its most transparent. */ \
|
||||
float y = 250.0 / 255.0; \
|
||||
float x = 180.0 / 255.0; \
|
||||
/* interpolate darkening value, based on distance from screen center */ \
|
||||
float val = min(length(dist), elipse_radius); \
|
||||
float a = mix(x, y, val / elipse_radius); \
|
||||
/* dim_factor varies from [1.0 -> 0.5] when overview is showing \
|
||||
We use it to smooth value, then we clamp it to valid color interval */ \
|
||||
a = clamp(a - cogl_color_in.r + 0.5, 0.0, 1.0); \
|
||||
/* We\'re blending between: color and black color (obviously omitted in the equation) */ \
|
||||
cogl_color_out.xyz = cogl_color_out.xyz * (1.0 - a); \
|
||||
cogl_color_out.a = 1.0;';
|
||||
|
||||
const ShellInfo = new Lang.Class({
|
||||
Name: 'ShellInfo',
|
||||
|
||||
@ -93,9 +103,7 @@ const Overview = new Lang.Class({
|
||||
_init: function() {
|
||||
this._overviewCreated = false;
|
||||
this._initCalled = false;
|
||||
this._controlPressed = false;
|
||||
|
||||
global.stage.connect('captured-event', Lang.bind(this, this._capturedEvent));
|
||||
Main.sessionMode.connect('updated', Lang.bind(this, this._sessionUpdated));
|
||||
this._sessionUpdated();
|
||||
},
|
||||
@ -109,49 +117,41 @@ const Overview = new Lang.Class({
|
||||
|
||||
this._overviewCreated = true;
|
||||
|
||||
// The main Background actors are inside global.window_group which are
|
||||
// The main BackgroundActor is inside global.window_group which is
|
||||
// hidden when displaying the overview, so we create a new
|
||||
// one. Instances of this class share a single CoglTexture behind the
|
||||
// scenes which allows us to show the background with different
|
||||
// rendering options without duplicating the texture data.
|
||||
let monitor = Main.layoutManager.primaryMonitor;
|
||||
this._background = Meta.BackgroundActor.new_for_screen(global.screen);
|
||||
this._background.add_glsl_snippet(Meta.SnippetHook.FRAGMENT,
|
||||
GLSL_DIM_EFFECT_DECLARATIONS,
|
||||
GLSL_DIM_EFFECT_CODE,
|
||||
false);
|
||||
this._background.hide();
|
||||
global.overlay_group.add_actor(this._background);
|
||||
|
||||
this._desktopFade = new St.Bin();
|
||||
global.overlay_group.add_actor(this._desktopFade);
|
||||
|
||||
let layout = new Clutter.BinLayout();
|
||||
this._stack = new Clutter.Actor({ layout_manager: layout });
|
||||
this._stack.add_constraint(new LayoutManager.MonitorConstraint({ primary: true }));
|
||||
|
||||
/* Translators: This is the main view to select
|
||||
activities. See also note for "Activities" string. */
|
||||
this._overview = new St.BoxLayout({ name: 'overview',
|
||||
accessible_name: _("Overview"),
|
||||
reactive: true,
|
||||
vertical: true,
|
||||
x_expand: true,
|
||||
y_expand: true });
|
||||
vertical: true });
|
||||
this._overview._delegate = this;
|
||||
|
||||
this._groupStack = new St.Widget({ layout_manager: new Clutter.BinLayout(),
|
||||
x_expand: true, y_expand: true,
|
||||
clip_to_allocation: true });
|
||||
this._group = new St.BoxLayout({ name: 'overview-group',
|
||||
reactive: true,
|
||||
x_expand: true, y_expand: true });
|
||||
this._groupStack.add_actor(this._group);
|
||||
this._group = new St.BoxLayout({ name: 'overview-group' });
|
||||
|
||||
this._backgroundGroup = new Meta.BackgroundGroup();
|
||||
global.overlay_group.add_child(this._backgroundGroup);
|
||||
this._backgroundGroup.hide();
|
||||
this._bgManagers = [];
|
||||
this._capturedEventId = 0;
|
||||
this._buttonPressId = 0;
|
||||
|
||||
this.visible = false; // animating to overview, in overview, animating out
|
||||
this._shown = false; // show() and not hide()
|
||||
this._shownTemporarily = false; // showTemporarily() and not hideTemporarily()
|
||||
this._modal = false; // have a modal grab
|
||||
this.animationInProgress = false;
|
||||
this.visibleTarget = false;
|
||||
this._hideInProgress = false;
|
||||
|
||||
// During transitions, we raise this to the top to avoid having the overview
|
||||
// area be reactive; it causes too many issues such as double clicks on
|
||||
@ -161,9 +161,8 @@ const Overview = new Lang.Class({
|
||||
this._overview.add_actor(this._coverPane);
|
||||
this._coverPane.connect('event', Lang.bind(this, function (actor, event) { return true; }));
|
||||
|
||||
this._stack.hide();
|
||||
this._stack.add_actor(this._overview);
|
||||
global.overlay_group.add_actor(this._stack);
|
||||
this._overview.hide();
|
||||
global.overlay_group.add_actor(this._overview);
|
||||
|
||||
this._coverPane.hide();
|
||||
|
||||
@ -176,7 +175,6 @@ const Overview = new Lang.Class({
|
||||
Main.xdndHandler.connect('drag-end', Lang.bind(this, this._onDragEnd));
|
||||
|
||||
global.screen.connect('restacked', Lang.bind(this, this._onRestacked));
|
||||
this._group.connect('scroll-event', Lang.bind(this, this._onScrollEvent));
|
||||
|
||||
this._windowSwitchTimeoutId = 0;
|
||||
this._windowSwitchTimestamp = 0;
|
||||
@ -188,70 +186,6 @@ const Overview = new Lang.Class({
|
||||
this.init();
|
||||
},
|
||||
|
||||
_updateBackgrounds: function() {
|
||||
for (let i = 0; i < this._bgManagers.length; i++)
|
||||
this._bgManagers[i].destroy();
|
||||
|
||||
this._bgManagers = [];
|
||||
|
||||
for (let i = 0; i < Main.layoutManager.monitors.length; i++) {
|
||||
let bgManager = new Background.BackgroundManager({ container: this._backgroundGroup,
|
||||
monitorIndex: i,
|
||||
effects: Meta.BackgroundEffects.VIGNETTE });
|
||||
this._bgManagers.push(bgManager);
|
||||
}
|
||||
},
|
||||
|
||||
_unshadeBackgrounds: function() {
|
||||
let backgrounds = this._backgroundGroup.get_children();
|
||||
for (let i = 0; i < backgrounds.length; i++) {
|
||||
let background = backgrounds[i]._delegate;
|
||||
|
||||
Tweener.addTween(background,
|
||||
{ brightness: 1.0,
|
||||
time: SHADE_ANIMATION_TIME,
|
||||
transition: 'easeOutQuad'
|
||||
});
|
||||
Tweener.addTween(background,
|
||||
{ vignetteSharpness: 0.0,
|
||||
time: SHADE_ANIMATION_TIME,
|
||||
transition: 'easeOutQuad'
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
_shadeBackgrounds: function() {
|
||||
let backgrounds = this._backgroundGroup.get_children();
|
||||
for (let i = 0; i < backgrounds.length; i++) {
|
||||
let background = backgrounds[i]._delegate;
|
||||
|
||||
Tweener.addTween(background,
|
||||
{ brightness: 0.8,
|
||||
time: SHADE_ANIMATION_TIME,
|
||||
transition: 'easeOutQuad'
|
||||
});
|
||||
Tweener.addTween(background,
|
||||
{ vignetteSharpness: 0.7,
|
||||
time: SHADE_ANIMATION_TIME,
|
||||
transition: 'easeOutQuad'
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
_capturedEvent: function(actor, event) {
|
||||
let type = event.type();
|
||||
if (type != Clutter.EventType.KEY_PRESS &&
|
||||
type != Clutter.EventType.KEY_RELEASE)
|
||||
return false;
|
||||
|
||||
let symbol = event.get_key_symbol();
|
||||
if (symbol == Clutter.KEY_Control_L ||
|
||||
symbol == Clutter.KEY_Control_R)
|
||||
this._controlPressed = type == Clutter.EventType.KEY_PRESS;
|
||||
|
||||
return false;
|
||||
},
|
||||
|
||||
_sessionUpdated: function() {
|
||||
this.isDummy = !Main.sessionMode.hasOverview;
|
||||
this._createOverview();
|
||||
@ -281,46 +215,43 @@ const Overview = new Lang.Class({
|
||||
in the search entry when no search is
|
||||
active; it should not exceed ~30
|
||||
characters. */
|
||||
hint_text: _("Type to search…"),
|
||||
hint_text: _("Type to search..."),
|
||||
track_hover: true,
|
||||
can_focus: true });
|
||||
this._searchEntryBin = new St.Bin({ child: this._searchEntry,
|
||||
x_align: St.Align.MIDDLE });
|
||||
this._overview.add_actor(this._searchEntryBin);
|
||||
|
||||
// Create controls
|
||||
this._dash = new Dash.Dash();
|
||||
this._viewSelector = new ViewSelector.ViewSelector(this._searchEntry,
|
||||
this._dash.showAppsButton);
|
||||
this._thumbnailsBox = new WorkspaceThumbnail.ThumbnailsBox();
|
||||
this._controls = new OverviewControls.ControlsManager(this._dash,
|
||||
this._thumbnailsBox,
|
||||
this._viewSelector);
|
||||
|
||||
this._controls.dashActor.x_align = Clutter.ActorAlign.START;
|
||||
this._controls.dashActor.y_expand = true;
|
||||
|
||||
// Put the dash in a separate layer to allow content to be centered
|
||||
this._groupStack.add_actor(this._controls.dashActor);
|
||||
|
||||
// Pack all the actors into the group
|
||||
this._group.add_actor(this._controls.dashSpacer);
|
||||
this._group.add(this._viewSelector.actor, { x_fill: true,
|
||||
expand: true });
|
||||
this._group.add_actor(this._controls.thumbnailsActor);
|
||||
|
||||
// Add our same-line elements after the search entry
|
||||
this._overview.add(this._groupStack, { y_fill: true, expand: true });
|
||||
|
||||
this._stack.add_actor(this._controls.indicatorActor);
|
||||
|
||||
// TODO - recalculate everything when desktop size changes
|
||||
this._dash = new Dash.Dash();
|
||||
this._group.add_actor(this._dash.actor);
|
||||
this.dashIconSize = this._dash.iconSize;
|
||||
this._dash.connect('icon-size-changed',
|
||||
Lang.bind(this, function() {
|
||||
this.dashIconSize = this._dash.iconSize;
|
||||
}));
|
||||
|
||||
// Translators: this is the name of the dock/favorites area on
|
||||
// the left of the overview
|
||||
Main.ctrlAltTabManager.addGroup(this._dash.actor, _("Dash"), 'user-bookmarks-symbolic');
|
||||
|
||||
this._viewSelector = new ViewSelector.ViewSelector(this._searchEntry,
|
||||
this._dash.showAppsButton);
|
||||
this._group.add(this._viewSelector.actor, { x_fill: true,
|
||||
expand: true });
|
||||
|
||||
// Add our same-line elements after the search entry
|
||||
this._overview.add(this._group, { y_fill: true,
|
||||
expand: true });
|
||||
|
||||
// Then account for message tray
|
||||
this._messageTrayGhost = new St.Bin({ style_class: 'message-tray-summary',
|
||||
reactive: false,
|
||||
opacity: 0,
|
||||
x_fill: true,
|
||||
y_fill: true });
|
||||
this._overview.add_actor(this._messageTrayGhost);
|
||||
|
||||
Main.layoutManager.connect('monitors-changed', Lang.bind(this, this._relayout));
|
||||
this._relayout();
|
||||
},
|
||||
@ -413,10 +344,6 @@ const Overview = new Lang.Class({
|
||||
return DND.DragMotionResult.CONTINUE;
|
||||
},
|
||||
|
||||
_onScrollEvent: function(actor, event) {
|
||||
this.emit('scroll-event', event);
|
||||
},
|
||||
|
||||
addAction: function(action) {
|
||||
if (this.isDummy)
|
||||
return;
|
||||
@ -446,12 +373,16 @@ const Overview = new Lang.Class({
|
||||
// when it is next shown.
|
||||
this.hide();
|
||||
|
||||
let workArea = Main.layoutManager.getWorkAreaForMonitor(Main.layoutManager.primaryIndex);
|
||||
let primary = Main.layoutManager.primaryMonitor;
|
||||
|
||||
this._coverPane.set_position(0, workArea.y);
|
||||
this._coverPane.set_size(workArea.width, workArea.height);
|
||||
let contentY = Main.panel.actor.height;
|
||||
let contentHeight = primary.height - contentY - Main.messageTray.actor.height;
|
||||
|
||||
this._updateBackgrounds();
|
||||
this._overview.set_position(primary.x, primary.y);
|
||||
this._overview.set_size(primary.width, primary.height);
|
||||
|
||||
this._coverPane.set_position(0, contentY);
|
||||
this._coverPane.set_size(primary.width, contentHeight);
|
||||
},
|
||||
|
||||
_onRestacked: function() {
|
||||
@ -535,7 +466,6 @@ const Overview = new Lang.Class({
|
||||
|
||||
this.visible = true;
|
||||
this.animationInProgress = true;
|
||||
this.visibleTarget = true;
|
||||
|
||||
// All the the actors in the window group are completely obscured,
|
||||
// hiding the group holding them while the Overview is displayed greatly
|
||||
@ -548,20 +478,24 @@ const Overview = new Lang.Class({
|
||||
// Disable unredirection while in the overview
|
||||
Meta.disable_unredirect_for_screen(global.screen);
|
||||
global.window_group.hide();
|
||||
global.top_window_group.hide();
|
||||
this._stack.show();
|
||||
this._backgroundGroup.show();
|
||||
this._overview.show();
|
||||
this._background.show();
|
||||
this._viewSelector.show();
|
||||
|
||||
this._stack.opacity = 0;
|
||||
Tweener.addTween(this._stack,
|
||||
this._overview.opacity = 0;
|
||||
Tweener.addTween(this._overview,
|
||||
{ opacity: 255,
|
||||
transition: 'easeOutQuad',
|
||||
time: ANIMATION_TIME,
|
||||
onComplete: this._showDone,
|
||||
onCompleteScope: this
|
||||
});
|
||||
this._shadeBackgrounds();
|
||||
|
||||
Tweener.addTween(this._background,
|
||||
{ dim_factor: 0.8,
|
||||
time: ANIMATION_TIME,
|
||||
transition: 'easeOutQuad'
|
||||
});
|
||||
|
||||
this._coverPane.raise_top();
|
||||
this._coverPane.show();
|
||||
@ -596,9 +530,6 @@ const Overview = new Lang.Class({
|
||||
if (!this._shown)
|
||||
return;
|
||||
|
||||
if (this._controlPressed)
|
||||
return;
|
||||
|
||||
if (!this._shownTemporarily)
|
||||
this._animateNotVisible();
|
||||
|
||||
@ -645,7 +576,7 @@ const Overview = new Lang.Class({
|
||||
if (this._shown) {
|
||||
if (!this._modal) {
|
||||
if (Main.pushModal(this._overview,
|
||||
{ keybindingMode: Shell.KeyBindingMode.OVERVIEW }))
|
||||
{ keybindingMode: Main.KeybindingMode.OVERVIEW }))
|
||||
this._modal = true;
|
||||
else
|
||||
this.hide();
|
||||
@ -671,19 +602,24 @@ const Overview = new Lang.Class({
|
||||
return;
|
||||
|
||||
this.animationInProgress = true;
|
||||
this.visibleTarget = false;
|
||||
this._hideInProgress = true;
|
||||
|
||||
this._viewSelector.zoomFromOverview();
|
||||
|
||||
// Make other elements fade out.
|
||||
Tweener.addTween(this._stack,
|
||||
Tweener.addTween(this._overview,
|
||||
{ opacity: 0,
|
||||
transition: 'easeOutQuad',
|
||||
time: ANIMATION_TIME,
|
||||
onComplete: this._hideDone,
|
||||
onCompleteScope: this
|
||||
});
|
||||
this._unshadeBackgrounds();
|
||||
|
||||
Tweener.addTween(this._background,
|
||||
{ dim_factor: 1.0,
|
||||
time: ANIMATION_TIME,
|
||||
transition: 'easeOutQuad'
|
||||
});
|
||||
|
||||
this._coverPane.raise_top();
|
||||
this._coverPane.show();
|
||||
@ -709,15 +645,15 @@ const Overview = new Lang.Class({
|
||||
Meta.enable_unredirect_for_screen(global.screen);
|
||||
|
||||
global.window_group.show();
|
||||
global.top_window_group.show();
|
||||
|
||||
this._viewSelector.hide();
|
||||
this._desktopFade.hide();
|
||||
this._backgroundGroup.hide();
|
||||
this._stack.hide();
|
||||
this._background.hide();
|
||||
this._overview.hide();
|
||||
|
||||
this.visible = false;
|
||||
this.animationInProgress = false;
|
||||
this._hideInProgress = false;
|
||||
|
||||
this._coverPane.hide();
|
||||
|
||||
|
@ -1,551 +0,0 @@
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
|
||||
const Clutter = imports.gi.Clutter;
|
||||
const Lang = imports.lang;
|
||||
const Meta = imports.gi.Meta;
|
||||
const St = imports.gi.St;
|
||||
const Shell = imports.gi.Shell;
|
||||
|
||||
const Main = imports.ui.main;
|
||||
const Params = imports.misc.params;
|
||||
const Tweener = imports.ui.tweener;
|
||||
const ViewSelector = imports.ui.viewSelector;
|
||||
|
||||
const SIDE_CONTROLS_ANIMATION_TIME = 0.16;
|
||||
|
||||
function getRtlSlideDirection(direction, actor) {
|
||||
let rtl = (actor.text_direction == Clutter.TextDirection.RTL);
|
||||
if (rtl)
|
||||
direction = (direction == SlideDirection.LEFT) ?
|
||||
SlideDirection.RIGHT : SlideDirection.LEFT;
|
||||
|
||||
return direction;
|
||||
};
|
||||
|
||||
const SlideDirection = {
|
||||
LEFT: 0,
|
||||
RIGHT: 1
|
||||
};
|
||||
|
||||
const SlideLayout = new Lang.Class({
|
||||
Name: 'SlideLayout',
|
||||
Extends: Clutter.FixedLayout,
|
||||
|
||||
_init: function(params) {
|
||||
this._slideX = 1;
|
||||
this._direction = SlideDirection.LEFT;
|
||||
|
||||
this.parent(params);
|
||||
},
|
||||
|
||||
vfunc_get_preferred_width: function(container, forHeight) {
|
||||
let child = container.get_first_child();
|
||||
|
||||
let [minWidth, natWidth] = child.get_preferred_width(forHeight);
|
||||
|
||||
minWidth *= this._slideX;
|
||||
natWidth *= this._slideX;
|
||||
|
||||
return [minWidth, natWidth];
|
||||
},
|
||||
|
||||
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 realDirection = getRtlSlideDirection(this._direction, child);
|
||||
let translationX = (realDirection == SlideDirection.LEFT) ?
|
||||
(availWidth - natWidth) : (natWidth - availWidth);
|
||||
|
||||
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);
|
||||
},
|
||||
|
||||
set slideX(value) {
|
||||
this._slideX = value;
|
||||
this.layout_changed();
|
||||
},
|
||||
|
||||
get slideX() {
|
||||
return this._slideX;
|
||||
},
|
||||
|
||||
set slideDirection(direction) {
|
||||
this._direction = direction;
|
||||
this.layout_changed();
|
||||
},
|
||||
|
||||
get slideDirection() {
|
||||
return this._direction;
|
||||
}
|
||||
});
|
||||
|
||||
const SlidingControl = new Lang.Class({
|
||||
Name: 'SlidingControl',
|
||||
|
||||
_init: function(params) {
|
||||
params = Params.parse(params, { slideDirection: SlideDirection.LEFT });
|
||||
|
||||
this.visible = true;
|
||||
this.inDrag = false;
|
||||
|
||||
this.layout = new SlideLayout();
|
||||
this.layout.slideDirection = params.slideDirection;
|
||||
this.actor = new St.Widget({ layout_manager: this.layout,
|
||||
style_class: 'overview-controls',
|
||||
clip_to_allocation: true });
|
||||
|
||||
Main.overview.connect('showing', Lang.bind(this, this._onOverviewShowing));
|
||||
|
||||
Main.overview.connect('item-drag-begin', Lang.bind(this, this._onDragBegin));
|
||||
Main.overview.connect('item-drag-end', Lang.bind(this, this._onDragEnd));
|
||||
Main.overview.connect('item-drag-cancelled', Lang.bind(this, this._onDragEnd));
|
||||
|
||||
Main.overview.connect('window-drag-begin', Lang.bind(this, this._onWindowDragBegin));
|
||||
Main.overview.connect('window-drag-cancelled', Lang.bind(this, this._onWindowDragEnd));
|
||||
Main.overview.connect('window-drag-end', Lang.bind(this, this._onWindowDragEnd));
|
||||
},
|
||||
|
||||
getSlide: function() {
|
||||
throw new Error('getSlide() must be overridden');
|
||||
},
|
||||
|
||||
updateSlide: function() {
|
||||
Tweener.addTween(this.layout, { slideX: this.getSlide(),
|
||||
time: SIDE_CONTROLS_ANIMATION_TIME,
|
||||
transition: 'easeOutQuad' });
|
||||
},
|
||||
|
||||
getVisibleWidth: function() {
|
||||
let child = this.actor.get_first_child();
|
||||
let [, , natWidth, ] = child.get_preferred_size();
|
||||
return natWidth;
|
||||
},
|
||||
|
||||
_getTranslation: function() {
|
||||
let child = this.actor.get_first_child();
|
||||
let direction = getRtlSlideDirection(this.layout.slideDirection, child);
|
||||
let visibleWidth = this.getVisibleWidth();
|
||||
|
||||
if (direction == SlideDirection.LEFT)
|
||||
return - visibleWidth;
|
||||
else
|
||||
return visibleWidth;
|
||||
},
|
||||
|
||||
_updateTranslation: function() {
|
||||
let translationStart = 0;
|
||||
let translationEnd = 0;
|
||||
let translation = this._getTranslation();
|
||||
|
||||
if (this.visible) {
|
||||
translationStart = translation;
|
||||
} else {
|
||||
translationEnd = translation;
|
||||
}
|
||||
|
||||
if (this.actor.translation_x == translationEnd)
|
||||
return;
|
||||
|
||||
this.actor.translation_x = translationStart;
|
||||
Tweener.addTween(this.actor, { translation_x: translationEnd,
|
||||
time: SIDE_CONTROLS_ANIMATION_TIME,
|
||||
transition: 'easeOutQuad'
|
||||
});
|
||||
},
|
||||
|
||||
_onOverviewShowing: function() {
|
||||
// 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() {
|
||||
this._onDragBegin();
|
||||
},
|
||||
|
||||
_onWindowDragEnd: function() {
|
||||
this._onDragEnd();
|
||||
},
|
||||
|
||||
_onDragBegin: function() {
|
||||
this.inDrag = true;
|
||||
this.actor.translation_x = 0;
|
||||
this.updateSlide();
|
||||
},
|
||||
|
||||
_onDragEnd: function() {
|
||||
this.inDrag = false;
|
||||
this.updateSlide();
|
||||
},
|
||||
|
||||
fadeIn: function() {
|
||||
Tweener.addTween(this.actor, { opacity: 255,
|
||||
time: SIDE_CONTROLS_ANIMATION_TIME / 2,
|
||||
transition: 'easeInQuad'
|
||||
});
|
||||
},
|
||||
|
||||
fadeHalf: function() {
|
||||
Tweener.addTween(this.actor, { opacity: 128,
|
||||
time: SIDE_CONTROLS_ANIMATION_TIME / 2,
|
||||
transition: 'easeOutQuad'
|
||||
});
|
||||
},
|
||||
|
||||
slideIn: function() {
|
||||
this.visible = true;
|
||||
// we will update slideX and the translation from pageEmpty
|
||||
},
|
||||
|
||||
slideOut: function() {
|
||||
this.visible = false;
|
||||
this._updateTranslation();
|
||||
// we will update slideX from pageEmpty
|
||||
},
|
||||
|
||||
pageEmpty: function() {
|
||||
// When pageEmpty is received, there's no visible view in the
|
||||
// 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._updateTranslation();
|
||||
}
|
||||
});
|
||||
|
||||
const ThumbnailsSlider = new Lang.Class({
|
||||
Name: 'ThumbnailsSlider',
|
||||
Extends: SlidingControl,
|
||||
|
||||
_init: function(thumbnailsBox) {
|
||||
this.parent({ slideDirection: SlideDirection.RIGHT });
|
||||
|
||||
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));
|
||||
},
|
||||
|
||||
_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;
|
||||
|
||||
if (!alwaysZoomOut) {
|
||||
let monitors = Main.layoutManager.monitors;
|
||||
let primary = Main.layoutManager.primaryMonitor;
|
||||
|
||||
/* Look for any monitor to the right of the primary, if there is
|
||||
* one, we always keep zoom out, otherwise its hard to reach
|
||||
* the thumbnail area without passing into the next monitor. */
|
||||
for (let i = 0; i < monitors.length; i++) {
|
||||
if (monitors[i].x >= primary.x + primary.width) {
|
||||
alwaysZoomOut = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return alwaysZoomOut;
|
||||
},
|
||||
|
||||
getSlide: function() {
|
||||
if (!this.visible)
|
||||
return 0;
|
||||
|
||||
let alwaysZoomOut = this._getAlwaysZoomOut();
|
||||
if (alwaysZoomOut)
|
||||
return 1;
|
||||
|
||||
let child = this.actor.get_first_child();
|
||||
let preferredHeight = child.get_preferred_height(-1)[1];
|
||||
let expandedWidth = child.get_preferred_width(preferredHeight)[1];
|
||||
let visibleWidth = child.get_theme_node().get_length('visible-width');
|
||||
|
||||
return visibleWidth / expandedWidth;
|
||||
},
|
||||
|
||||
getVisibleWidth: function() {
|
||||
let alwaysZoomOut = this._getAlwaysZoomOut();
|
||||
if (alwaysZoomOut)
|
||||
return this.parent();
|
||||
|
||||
let child = this.actor.get_first_child();
|
||||
return child.get_theme_node().get_length('visible-width');
|
||||
}
|
||||
});
|
||||
|
||||
const DashSlider = new Lang.Class({
|
||||
Name: 'DashSlider',
|
||||
Extends: SlidingControl,
|
||||
|
||||
_init: function(dash) {
|
||||
this.parent({ slideDirection: SlideDirection.LEFT });
|
||||
|
||||
this._dash = dash;
|
||||
|
||||
// SlideLayout reads the actor's expand flags to decide
|
||||
// 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.add_actor(this._dash.actor);
|
||||
|
||||
this._dash.connect('icon-size-changed', Lang.bind(this, this.updateSlide));
|
||||
},
|
||||
|
||||
getSlide: function() {
|
||||
if (this.visible || this.inDrag)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
},
|
||||
|
||||
_onWindowDragBegin: function() {
|
||||
this.fadeHalf();
|
||||
},
|
||||
|
||||
_onWindowDragEnd: function() {
|
||||
this.fadeIn();
|
||||
}
|
||||
});
|
||||
|
||||
const DashSpacer = new Lang.Class({
|
||||
Name: 'DashSpacer',
|
||||
Extends: St.Widget,
|
||||
|
||||
_init: function(params) {
|
||||
this.parent(params);
|
||||
|
||||
this._bindConstraint = null;
|
||||
},
|
||||
|
||||
setDashActor: function(dashActor) {
|
||||
if (this._bindConstraint) {
|
||||
this.remove_constraint(this._bindConstraint);
|
||||
this._bindConstraint = null;
|
||||
}
|
||||
|
||||
if (dashActor) {
|
||||
this._bindConstraint = new Clutter.BindConstraint({ source: dashActor,
|
||||
coordinate: Clutter.BindCoordinate.SIZE });
|
||||
this.add_constraint(this._bindConstraint);
|
||||
}
|
||||
},
|
||||
|
||||
vfunc_get_preferred_width: function(forHeight) {
|
||||
let box = this.get_allocation_box();
|
||||
let minWidth = this.parent(forHeight)[0];
|
||||
let natWidth = box.x2 - box.x1;
|
||||
return [minWidth, natWidth];
|
||||
},
|
||||
|
||||
vfunc_get_preferred_height: function(forWidth) {
|
||||
let box = this.get_allocation_box();
|
||||
let minHeight = this.parent(forWidth)[0];
|
||||
let natHeight = box.y2 - box.y1;
|
||||
return [minHeight, natHeight];
|
||||
}
|
||||
});
|
||||
|
||||
const MessagesIndicator = new Lang.Class({
|
||||
Name: 'MessagesIndicator',
|
||||
|
||||
_init: function(viewSelector) {
|
||||
this._count = 0;
|
||||
this._sources = [];
|
||||
this._viewSelector = viewSelector;
|
||||
|
||||
this._container = new St.BoxLayout({ style_class: 'messages-indicator-contents',
|
||||
reactive: true,
|
||||
track_hover: true,
|
||||
x_expand: true,
|
||||
y_expand: true,
|
||||
x_align: Clutter.ActorAlign.CENTER });
|
||||
|
||||
this._icon = new St.Icon({ icon_name: 'user-idle-symbolic',
|
||||
icon_size: 16 });
|
||||
this._container.add_actor(this._icon);
|
||||
|
||||
this._label = new St.Label();
|
||||
this._container.add_actor(this._label);
|
||||
|
||||
this._highlight = new St.Widget({ style_class: 'messages-indicator-highlight',
|
||||
x_expand: true,
|
||||
y_expand: true,
|
||||
y_align: Clutter.ActorAlign.END,
|
||||
visible: false });
|
||||
|
||||
this._container.connect('notify::hover', Lang.bind(this,
|
||||
function() {
|
||||
this._highlight.visible = this._container.hover;
|
||||
}));
|
||||
|
||||
let clickAction = new Clutter.ClickAction();
|
||||
this._container.add_action(clickAction);
|
||||
clickAction.connect('clicked', Lang.bind(this,
|
||||
function() {
|
||||
Main.messageTray.openTray();
|
||||
}));
|
||||
|
||||
Main.messageTray.connect('showing', Lang.bind(this,
|
||||
function() {
|
||||
this._highlight.visible = false;
|
||||
this._container.hover = false;
|
||||
}));
|
||||
|
||||
let layout = new Clutter.BinLayout();
|
||||
this.actor = new St.Widget({ layout_manager: layout,
|
||||
style_class: 'messages-indicator',
|
||||
y_expand: true,
|
||||
y_align: Clutter.ActorAlign.END,
|
||||
visible: false });
|
||||
this.actor.add_actor(this._container);
|
||||
this.actor.add_actor(this._highlight);
|
||||
|
||||
Main.messageTray.connect('source-added', Lang.bind(this, this._onSourceAdded));
|
||||
Main.messageTray.connect('source-removed', Lang.bind(this, this._onSourceRemoved));
|
||||
|
||||
let sources = Main.messageTray.getSources();
|
||||
sources.forEach(Lang.bind(this, function(source) { this._onSourceAdded(null, source); }));
|
||||
|
||||
this._viewSelector.connect('page-changed', Lang.bind(this, this._updateVisibility));
|
||||
Main.overview.connect('showing', Lang.bind(this, this._updateVisibility));
|
||||
},
|
||||
|
||||
_onSourceAdded: function(tray, source) {
|
||||
if (source.trayIcon)
|
||||
return;
|
||||
|
||||
if (source.isTransient)
|
||||
return;
|
||||
|
||||
source.connect('count-updated', Lang.bind(this, this._updateCount));
|
||||
this._sources.push(source);
|
||||
this._updateCount();
|
||||
},
|
||||
|
||||
_onSourceRemoved: function(tray, source) {
|
||||
this._sources.splice(this._sources.indexOf(source), 1);
|
||||
this._updateCount();
|
||||
},
|
||||
|
||||
_updateCount: function() {
|
||||
let count = 0;
|
||||
this._sources.forEach(Lang.bind(this,
|
||||
function(source) {
|
||||
count += source.indicatorCount;
|
||||
}));
|
||||
|
||||
this._count = count;
|
||||
this._label.text = ngettext("%d new message",
|
||||
"%d new messages",
|
||||
count).format(count);
|
||||
|
||||
this._updateVisibility();
|
||||
},
|
||||
|
||||
_updateVisibility: function() {
|
||||
let activePage = this._viewSelector.getActivePage();
|
||||
let visible = ((this._count > 0) && (activePage == ViewSelector.ViewPage.WINDOWS));
|
||||
|
||||
this.actor.visible = visible;
|
||||
}
|
||||
});
|
||||
|
||||
const ControlsManager = new Lang.Class({
|
||||
Name: 'ControlsManager',
|
||||
|
||||
_init: function(dash, thumbnails, viewSelector) {
|
||||
this._dashSlider = new DashSlider(dash);
|
||||
this.dashActor = this._dashSlider.actor;
|
||||
this.dashSpacer = new DashSpacer();
|
||||
this.dashSpacer.setDashActor(this.dashActor);
|
||||
|
||||
this._thumbnailsSlider = new ThumbnailsSlider(thumbnails);
|
||||
this.thumbnailsActor = this._thumbnailsSlider.actor;
|
||||
|
||||
this._indicator = new MessagesIndicator(viewSelector);
|
||||
this.indicatorActor = this._indicator.actor;
|
||||
|
||||
this._viewSelector = viewSelector;
|
||||
this._viewSelector.connect('page-changed', Lang.bind(this, this._setVisibility));
|
||||
this._viewSelector.connect('page-empty', Lang.bind(this, this._onPageEmpty));
|
||||
|
||||
Main.overview.connect('showing', Lang.bind(this, this._updateSpacerVisibility));
|
||||
Main.overview.connect('item-drag-begin', Lang.bind(this,
|
||||
function() {
|
||||
let activePage = this._viewSelector.getActivePage();
|
||||
if (activePage != ViewSelector.ViewPage.WINDOWS)
|
||||
this._viewSelector.fadeHalf();
|
||||
}));
|
||||
Main.overview.connect('item-drag-end', Lang.bind(this,
|
||||
function() {
|
||||
this._viewSelector.fadeIn();
|
||||
}));
|
||||
Main.overview.connect('item-drag-cancelled', Lang.bind(this,
|
||||
function() {
|
||||
this._viewSelector.fadeIn();
|
||||
}));
|
||||
},
|
||||
|
||||
_setVisibility: function() {
|
||||
// Ignore the case when we're leaving the overview, since
|
||||
// actors will be made visible again when entering the overview
|
||||
// next time, and animating them while doing so is just
|
||||
// unnecessary noise
|
||||
if (!Main.overview.visible ||
|
||||
(Main.overview.animationInProgress && !Main.overview.visibleTarget))
|
||||
return;
|
||||
|
||||
let activePage = this._viewSelector.getActivePage();
|
||||
let dashVisible = (activePage == ViewSelector.ViewPage.WINDOWS ||
|
||||
activePage == ViewSelector.ViewPage.APPS);
|
||||
let thumbnailsVisible = (activePage == ViewSelector.ViewPage.WINDOWS);
|
||||
|
||||
if (dashVisible)
|
||||
this._dashSlider.slideIn();
|
||||
else
|
||||
this._dashSlider.slideOut();
|
||||
|
||||
if (thumbnailsVisible)
|
||||
this._thumbnailsSlider.slideIn();
|
||||
else
|
||||
this._thumbnailsSlider.slideOut();
|
||||
},
|
||||
|
||||
_updateSpacerVisibility: function() {
|
||||
if (Main.overview.animationInProgress && !Main.overview.visibleTarget)
|
||||
return;
|
||||
|
||||
let activePage = this._viewSelector.getActivePage();
|
||||
this.dashSpacer.visible = (activePage == ViewSelector.ViewPage.WINDOWS);
|
||||
},
|
||||
|
||||
_onPageEmpty: function() {
|
||||
this._dashSlider.pageEmpty();
|
||||
this._thumbnailsSlider.pageEmpty();
|
||||
|
||||
this._updateSpacerVisibility();
|
||||
}
|
||||
});
|
@ -203,7 +203,7 @@ const TextShadower = new Lang.Class({
|
||||
let child = children[i];
|
||||
let childBox = new Clutter.ActorBox();
|
||||
// The order of the labels here is arbitrary, except
|
||||
// we know the "real" label is at the end because Clutter.Actor
|
||||
// we know the "real" label is at the end because Clutter.Group
|
||||
// sorts by Z order
|
||||
switch (i) {
|
||||
case 0: // top
|
||||
@ -315,7 +315,7 @@ const AppMenuButton = new Lang.Class({
|
||||
},
|
||||
|
||||
show: function() {
|
||||
if (this._visible)
|
||||
if (this._visible || Main.screenShield.locked)
|
||||
return;
|
||||
|
||||
this._visible = true;
|
||||
@ -598,11 +598,6 @@ const AppMenuButton = new Lang.Class({
|
||||
return;
|
||||
|
||||
menu = new PopupMenu.RemoteMenu(this.actor, this._targetApp.menu, this._targetApp.action_group);
|
||||
menu.connect('activate', Lang.bind(this, function() {
|
||||
let win = this._targetApp.get_windows()[0];
|
||||
win.check_alive(global.get_current_time());
|
||||
}));
|
||||
|
||||
} else {
|
||||
if (this.menu.isDummyQuitMenu)
|
||||
return;
|
||||
@ -644,7 +639,7 @@ const ActivitiesButton = new Lang.Class({
|
||||
|
||||
this.actor.label_actor = this._label;
|
||||
|
||||
this.hotCorner = new Layout.HotCorner(Main.layoutManager);
|
||||
this.hotCorner = new Layout.HotCorner();
|
||||
container.add_actor(this.hotCorner.actor);
|
||||
|
||||
this.actor.connect('captured-event', Lang.bind(this, this._onCapturedEvent));
|
||||
@ -739,6 +734,7 @@ const ActivitiesButton = new Lang.Class({
|
||||
if (pickedActor == this.actor) {
|
||||
if (!Main.overview.visible && !Main.overview.animationInProgress) {
|
||||
Main.overview.showTemporarily();
|
||||
Main.overview.beginItemDrag(actor);
|
||||
}
|
||||
}
|
||||
|
||||
@ -750,9 +746,12 @@ const ActivitiesButton = new Lang.Class({
|
||||
const PanelCorner = new Lang.Class({
|
||||
Name: 'PanelCorner',
|
||||
|
||||
_init: function(side) {
|
||||
_init: function(box, side) {
|
||||
this._side = side;
|
||||
|
||||
this._box = box;
|
||||
this._box.connect('style-changed', Lang.bind(this, this._boxStyleChanged));
|
||||
|
||||
this.actor = new St.DrawingArea({ style_class: 'panel-corner' });
|
||||
this.actor.connect('style-changed', Lang.bind(this, this._styleChanged));
|
||||
this.actor.connect('repaint', Lang.bind(this, this._repaint));
|
||||
@ -808,12 +807,12 @@ const PanelCorner = new Lang.Class({
|
||||
return children[index];
|
||||
},
|
||||
|
||||
setStyleParent: function(box) {
|
||||
_boxStyleChanged: function() {
|
||||
let side = this._side;
|
||||
|
||||
let rtlAwareContainer = box instanceof St.BoxLayout;
|
||||
let rtlAwareContainer = this._box instanceof St.BoxLayout;
|
||||
if (rtlAwareContainer &&
|
||||
box.get_text_direction() == Clutter.TextDirection.RTL) {
|
||||
this._box.get_text_direction() == Clutter.TextDirection.RTL) {
|
||||
if (this._side == St.Side.LEFT)
|
||||
side = St.Side.RIGHT;
|
||||
else if (this._side == St.Side.RIGHT)
|
||||
@ -822,9 +821,9 @@ const PanelCorner = new Lang.Class({
|
||||
|
||||
let button;
|
||||
if (side == St.Side.LEFT)
|
||||
button = this._findLeftmostButton(box);
|
||||
button = this._findLeftmostButton(this._box);
|
||||
else if (side == St.Side.RIGHT)
|
||||
button = this._findRightmostButton(box);
|
||||
button = this._findRightmostButton(this._box);
|
||||
|
||||
if (button) {
|
||||
if (this._button && this._buttonStyleChangedSignalId) {
|
||||
@ -851,7 +850,7 @@ const PanelCorner = new Lang.Class({
|
||||
|
||||
// The corner doesn't support theme transitions, so override
|
||||
// the .panel-button default
|
||||
button.style = 'transition-duration: 0ms';
|
||||
button.style = 'transition-duration: 0';
|
||||
}
|
||||
},
|
||||
|
||||
@ -864,8 +863,8 @@ const PanelCorner = new Lang.Class({
|
||||
let backgroundColor = node.get_color('-panel-corner-background-color');
|
||||
let borderColor = node.get_color('-panel-corner-border-color');
|
||||
|
||||
let overlap = borderColor.alpha != 0;
|
||||
let offsetY = overlap ? 0 : borderWidth;
|
||||
let noOverlap = borderColor.alpha == 0;
|
||||
let offsetY = noOverlap ? borderWidth : 0;
|
||||
|
||||
let cr = this.actor.get_context();
|
||||
cr.setOperator(Cairo.Operator.SOURCE);
|
||||
@ -889,7 +888,9 @@ const PanelCorner = new Lang.Class({
|
||||
Clutter.cairo_set_source_color(cr, over);
|
||||
cr.fill();
|
||||
|
||||
if (overlap) {
|
||||
if (noOverlap)
|
||||
return;
|
||||
|
||||
let offset = borderWidth;
|
||||
Clutter.cairo_set_source_color(cr, backgroundColor);
|
||||
|
||||
@ -898,9 +899,6 @@ const PanelCorner = new Lang.Class({
|
||||
cr.appendPath(savedPath);
|
||||
cr.fill();
|
||||
cr.restore();
|
||||
}
|
||||
|
||||
cr.$dispose();
|
||||
},
|
||||
|
||||
_styleChanged: function() {
|
||||
@ -919,7 +917,6 @@ const PANEL_ITEM_IMPLEMENTATIONS = {
|
||||
'appMenu': AppMenuButton,
|
||||
'dateMenu': imports.ui.dateMenu.DateMenuButton,
|
||||
'a11y': imports.ui.status.accessibility.ATIndicator,
|
||||
'a11yGreeter': imports.ui.status.accessibility.ATGreeterIndicator,
|
||||
'volume': imports.ui.status.volume.Indicator,
|
||||
'battery': imports.ui.status.power.Indicator,
|
||||
'lockScreen': imports.ui.status.lockScreenMenu.Indicator,
|
||||
@ -961,10 +958,17 @@ const Panel = new Lang.Class({
|
||||
this._rightBox = new St.BoxLayout({ name: 'panelRight' });
|
||||
this.actor.add_actor(this._rightBox);
|
||||
|
||||
this._leftCorner = new PanelCorner(St.Side.LEFT);
|
||||
if (this.actor.get_text_direction() == Clutter.TextDirection.RTL)
|
||||
this._leftCorner = new PanelCorner(this._rightBox, St.Side.LEFT);
|
||||
else
|
||||
this._leftCorner = new PanelCorner(this._leftBox, St.Side.LEFT);
|
||||
|
||||
this.actor.add_actor(this._leftCorner.actor);
|
||||
|
||||
this._rightCorner = new PanelCorner(St.Side.RIGHT);
|
||||
if (this.actor.get_text_direction() == Clutter.TextDirection.RTL)
|
||||
this._rightCorner = new PanelCorner(this._leftBox, St.Side.RIGHT);
|
||||
else
|
||||
this._rightCorner = new PanelCorner(this._rightBox, St.Side.RIGHT);
|
||||
this.actor.add_actor(this._rightCorner.actor);
|
||||
|
||||
this.actor.connect('get-preferred-width', Lang.bind(this, this._getPreferredWidth));
|
||||
@ -972,13 +976,6 @@ const Panel = new Lang.Class({
|
||||
this.actor.connect('allocate', Lang.bind(this, this._allocate));
|
||||
this.actor.connect('button-press-event', Lang.bind(this, this._onButtonPress));
|
||||
|
||||
Main.overview.connect('showing', Lang.bind(this, function () {
|
||||
this.actor.add_style_pseudo_class('overview');
|
||||
}));
|
||||
Main.overview.connect('hiding', Lang.bind(this, function () {
|
||||
this.actor.remove_style_pseudo_class('overview');
|
||||
}));
|
||||
|
||||
Main.layoutManager.panelBox.add(this.actor);
|
||||
Main.ctrlAltTabManager.addGroup(this.actor, _("Top Bar"), 'emblem-system-symbolic',
|
||||
{ sortGroup: CtrlAltTab.SortGroup.TOP });
|
||||
@ -1065,9 +1062,6 @@ const Panel = new Lang.Class({
|
||||
},
|
||||
|
||||
_onButtonPress: function(actor, event) {
|
||||
if (Main.modalCount > 0)
|
||||
return false;
|
||||
|
||||
if (event.get_source() != actor)
|
||||
return false;
|
||||
|
||||
@ -1147,13 +1141,17 @@ const Panel = new Lang.Class({
|
||||
this._sessionStyle = Main.sessionMode.panelStyle;
|
||||
if (this._sessionStyle)
|
||||
this._addStyleClassName(this._sessionStyle);
|
||||
},
|
||||
|
||||
if (this.actor.get_text_direction() == Clutter.TextDirection.RTL) {
|
||||
this._leftCorner.setStyleParent(this._rightBox);
|
||||
this._rightCorner.setStyleParent(this._leftBox);
|
||||
} else {
|
||||
this._leftCorner.setStyleParent(this._leftBox);
|
||||
this._rightCorner.setStyleParent(this._rightBox);
|
||||
_initBox: function(elements, box) {
|
||||
for (let i = 0; i < elements.length; i++) {
|
||||
let role = elements[i];
|
||||
let constructor = PANEL_ITEM_IMPLEMENTATIONS[role];
|
||||
if (!constructor) {
|
||||
// panel icon is not supported (can happen for
|
||||
// bluetooth or network)
|
||||
continue;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -205,8 +205,10 @@ const Button = new Lang.Class({
|
||||
// Setting the max-height won't do any good if the minimum height of the
|
||||
// menu is higher then the screen; it's useful if part of the menu is
|
||||
// scrollable so the minimum height is smaller than the natural height
|
||||
let workArea = Main.layoutManager.getWorkAreaForMonitor(Main.layoutManager.primaryIndex);
|
||||
this.menu.actor.style = ('max-height: ' + Math.round(workArea.height) + 'px;');
|
||||
let monitor = Main.layoutManager.primaryMonitor;
|
||||
this.menu.actor.style = ('max-height: ' +
|
||||
Math.round(monitor.height - Main.panel.actor.height) +
|
||||
'px;');
|
||||
},
|
||||
|
||||
destroy: function() {
|
||||
@ -242,21 +244,18 @@ const SystemStatusButton = new Lang.Class({
|
||||
this.setIcon(iconName);
|
||||
},
|
||||
|
||||
get icons() {
|
||||
return this._box.get_children();
|
||||
},
|
||||
|
||||
addIcon: function(gicon) {
|
||||
let icon = new St.Icon({ gicon: gicon,
|
||||
style_class: 'system-status-icon' });
|
||||
this._box.add_actor(icon);
|
||||
|
||||
this.emit('icons-changed');
|
||||
|
||||
return icon;
|
||||
},
|
||||
|
||||
setIcon: function(iconName) {
|
||||
// Need to first add a NULL GIcon and then set icon_name, to ensure
|
||||
// compatibility with -symbolic fallbacks
|
||||
|
||||
if (!this.mainIcon)
|
||||
this.mainIcon = this.addIcon(null);
|
||||
this.mainIcon.icon_name = iconName;
|
||||
|
@ -41,9 +41,10 @@ const PointerWatcher = new Lang.Class({
|
||||
Name: 'PointerWatcher',
|
||||
|
||||
_init: function() {
|
||||
this._idleMonitor = new GnomeDesktop.IdleMonitor();
|
||||
this._idleMonitor.add_idle_watch(IDLE_TIME, Lang.bind(this, this._onIdleMonitorBecameIdle));
|
||||
this._idle = this._idleMonitor.get_idletime() > IDLE_TIME;
|
||||
let idleMonitor = new GnomeDesktop.IdleMonitor();
|
||||
idleMonitor.connect('became-active', Lang.bind(this, this._onIdleMonitorBecameActive));
|
||||
idleMonitor.add_watch(IDLE_TIME, Lang.bind(this, this._onIdleMonitorBecameIdle));
|
||||
this._idle = idleMonitor.get_idletime() > IDLE_TIME;
|
||||
this._watches = [];
|
||||
this.pointerX = null;
|
||||
this.pointerY = null;
|
||||
@ -86,7 +87,6 @@ const PointerWatcher = new Lang.Class({
|
||||
|
||||
_onIdleMonitorBecameIdle: function(monitor) {
|
||||
this._idle = true;
|
||||
this._idleMonitor.add_user_active_watch(Lang.bind(this, this._onIdleMonitorBecameActive));
|
||||
this._updateTimeout();
|
||||
},
|
||||
|
||||
|
@ -207,7 +207,6 @@ const PopupBaseMenuItem = new Lang.Class({
|
||||
color.alpha / 255);
|
||||
cr.arc(width / 2, height / 2, width / 3, 0, 2 * Math.PI);
|
||||
cr.fill();
|
||||
cr.$dispose();
|
||||
},
|
||||
|
||||
// This returns column widths in logical order (i.e. from the dot
|
||||
@ -605,7 +604,6 @@ const PopupSliderMenuItem = new Lang.Class({
|
||||
color.alpha / 255);
|
||||
cr.arc(handleX, handleY, handleRadius, 0, 2 * Math.PI);
|
||||
cr.fill();
|
||||
cr.$dispose();
|
||||
},
|
||||
|
||||
_startDragging: function(actor, event) {
|
||||
@ -638,34 +636,20 @@ const PopupSliderMenuItem = new Lang.Class({
|
||||
return true;
|
||||
},
|
||||
|
||||
scroll: function(event) {
|
||||
_onScrollEvent: function (actor, event) {
|
||||
let direction = event.get_scroll_direction();
|
||||
let delta;
|
||||
|
||||
if (event.is_pointer_emulated())
|
||||
return;
|
||||
|
||||
if (direction == Clutter.ScrollDirection.DOWN) {
|
||||
delta = -SLIDER_SCROLL_STEP;
|
||||
} else if (direction == Clutter.ScrollDirection.UP) {
|
||||
delta = +SLIDER_SCROLL_STEP;
|
||||
} else if (direction == Clutter.ScrollDirection.SMOOTH) {
|
||||
let [dx, dy] = event.get_scroll_delta();
|
||||
// Even though the slider is horizontal, use dy to match
|
||||
// the UP/DOWN above.
|
||||
delta = -dy / 10;
|
||||
this._value = Math.max(0, this._value - SLIDER_SCROLL_STEP);
|
||||
}
|
||||
else if (direction == Clutter.ScrollDirection.UP) {
|
||||
this._value = Math.min(1, this._value + SLIDER_SCROLL_STEP);
|
||||
}
|
||||
|
||||
this._value = Math.min(Math.max(0, this._value + delta), 1);
|
||||
|
||||
this._slider.queue_repaint();
|
||||
this.emit('value-changed', this._value);
|
||||
},
|
||||
|
||||
_onScrollEvent: function(actor, event) {
|
||||
this.scroll(event);
|
||||
},
|
||||
|
||||
_motionEvent: function(actor, event) {
|
||||
let absX, absY;
|
||||
[absX, absY] = event.get_coords();
|
||||
@ -867,6 +851,7 @@ const PopupMenuBase = new Lang.Class({
|
||||
this.blockSourceEvents = false;
|
||||
|
||||
this._activeMenuItem = null;
|
||||
this._childMenus = [];
|
||||
this._settingsActions = { };
|
||||
|
||||
this._sessionUpdatedId = Main.sessionMode.connect('updated', Lang.bind(this, this._sessionUpdated));
|
||||
@ -888,7 +873,7 @@ const PopupMenuBase = new Lang.Class({
|
||||
|
||||
addSettingsAction: function(title, desktopFile) {
|
||||
let menuItem = this.addAction(title, function() {
|
||||
let app = Shell.AppSystem.get_default().lookup_app(desktopFile);
|
||||
let app = Shell.AppSystem.get_default().lookup_setting(desktopFile);
|
||||
|
||||
if (!app) {
|
||||
log('Settings panel for desktop file ' + desktopFile + ' could not be loaded!');
|
||||
@ -913,15 +898,29 @@ const PopupMenuBase = new Lang.Class({
|
||||
},
|
||||
|
||||
isEmpty: function() {
|
||||
let hasVisibleChildren = this.box.get_children().some(function(child) {
|
||||
return child.visible;
|
||||
});
|
||||
|
||||
return !hasVisibleChildren;
|
||||
return this.box.get_n_children() == 0;
|
||||
},
|
||||
|
||||
isChildMenu: function() {
|
||||
return false;
|
||||
isChildMenu: function(menu) {
|
||||
return this._childMenus.indexOf(menu) != -1;
|
||||
},
|
||||
|
||||
addChildMenu: function(menu) {
|
||||
if (this.isChildMenu(menu))
|
||||
return;
|
||||
|
||||
this._childMenus.push(menu);
|
||||
this.emit('child-menu-added', menu);
|
||||
},
|
||||
|
||||
removeChildMenu: function(menu) {
|
||||
let index = this._childMenus.indexOf(menu);
|
||||
|
||||
if (index == -1)
|
||||
return;
|
||||
|
||||
this._childMenus.splice(index, 1);
|
||||
this.emit('child-menu-removed', menu);
|
||||
},
|
||||
|
||||
/**
|
||||
@ -1196,8 +1195,6 @@ const PopupMenu = new Lang.Class({
|
||||
|
||||
global.focus_manager.add_group(this.actor);
|
||||
this.actor.reactive = true;
|
||||
|
||||
this._childMenus = [];
|
||||
},
|
||||
|
||||
_boxGetPreferredWidth: function (actor, forHeight, alloc) {
|
||||
@ -1224,28 +1221,6 @@ const PopupMenu = new Lang.Class({
|
||||
this._boxPointer.setSourceAlignment(alignment);
|
||||
},
|
||||
|
||||
isChildMenu: function(menu) {
|
||||
return this._childMenus.indexOf(menu) != -1;
|
||||
},
|
||||
|
||||
addChildMenu: function(menu) {
|
||||
if (this.isChildMenu(menu))
|
||||
return;
|
||||
|
||||
this._childMenus.push(menu);
|
||||
this.emit('child-menu-added', menu);
|
||||
},
|
||||
|
||||
removeChildMenu: function(menu) {
|
||||
let index = this._childMenus.indexOf(menu);
|
||||
|
||||
if (index == -1)
|
||||
return;
|
||||
|
||||
this._childMenus.splice(index, 1);
|
||||
this.emit('child-menu-removed', menu);
|
||||
},
|
||||
|
||||
open: function(animate) {
|
||||
if (this.isOpen)
|
||||
return;
|
||||
@ -1267,10 +1242,6 @@ const PopupMenu = new Lang.Class({
|
||||
if (this._activeMenuItem)
|
||||
this._activeMenuItem.setActive(false);
|
||||
|
||||
this._childMenus.forEach(function(childMenu) {
|
||||
childMenu.close();
|
||||
});
|
||||
|
||||
if (this._boxPointer.actor.visible)
|
||||
this._boxPointer.hide(animate);
|
||||
|
||||
@ -1691,7 +1662,9 @@ const PopupComboBoxMenuItem = new Lang.Class({
|
||||
_getTopMenu: function() {
|
||||
let actor = this.actor.get_parent();
|
||||
while (actor) {
|
||||
if (actor._delegate && actor._delegate instanceof PopupMenu)
|
||||
if (actor._delegate &&
|
||||
(actor._delegate instanceof PopupMenu ||
|
||||
actor._delegate instanceof PopupComboMenu))
|
||||
return actor._delegate;
|
||||
|
||||
actor = actor.get_parent();
|
||||
|
@ -1,11 +1,9 @@
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
|
||||
const GdkPixbuf = imports.gi.GdkPixbuf;
|
||||
const Gio = imports.gi.Gio;
|
||||
const GLib = imports.gi.GLib;
|
||||
const Lang = imports.lang;
|
||||
const St = imports.gi.St;
|
||||
const Shell = imports.gi.Shell;
|
||||
|
||||
const FileUtils = imports.misc.fileUtils;
|
||||
const Search = imports.ui.search;
|
||||
@ -123,10 +121,6 @@ function loadRemoteSearchProvider(file, info, data) {
|
||||
function remoteProvidersLoaded(loadState) {
|
||||
let searchSettings = new Gio.Settings({ schema: Search.SEARCH_PROVIDERS_SCHEMA });
|
||||
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');
|
||||
|
||||
let numSorted = sortOrder.length;
|
||||
|
||||
loadState.loadedProviders.sort(
|
||||
@ -141,12 +135,8 @@ function remoteProvidersLoaded(loadState) {
|
||||
idxB = sortOrder.indexOf(appIdB);
|
||||
|
||||
// if no provider is found in the order, use alphabetical order
|
||||
if ((idxA == -1) && (idxB == -1)) {
|
||||
let nameA = providerA.appInfo.get_name();
|
||||
let nameB = providerB.appInfo.get_name();
|
||||
|
||||
return GLib.utf8_collate(nameA, nameB);
|
||||
}
|
||||
if ((idxA == -1) && (idxB == -1))
|
||||
return GLib.utf8_collate(providerA.title, providerB.title);
|
||||
|
||||
if (numSorted > 1) {
|
||||
// if providerA is the last, it goes after everything
|
||||
@ -197,18 +187,18 @@ const RemoteSearchProvider = new Lang.Class({
|
||||
},
|
||||
|
||||
createIcon: function(size, meta) {
|
||||
let gicon;
|
||||
if (meta['gicon']) {
|
||||
gicon = Gio.icon_new_for_string(meta['gicon']);
|
||||
return new St.Icon({ gicon: Gio.icon_new_for_string(meta['gicon']),
|
||||
icon_size: size });
|
||||
} else if (meta['icon-data']) {
|
||||
let [width, height, rowStride, hasAlpha,
|
||||
bitsPerSample, nChannels, data] = meta['icon-data'];
|
||||
gicon = Shell.util_create_pixbuf_from_data(data, GdkPixbuf.Colorspace.RGB, hasAlpha,
|
||||
bitsPerSample, width, height, rowStride);
|
||||
let textureCache = St.TextureCache.get_default();
|
||||
return textureCache.load_from_raw(data, hasAlpha,
|
||||
width, height, rowStride, size);
|
||||
}
|
||||
|
||||
return new St.Icon({ gicon: gicon,
|
||||
icon_size: size });
|
||||
return null;
|
||||
},
|
||||
|
||||
_getResultsFinished: function(results, error) {
|
||||
@ -225,7 +215,7 @@ const RemoteSearchProvider = new Lang.Class({
|
||||
Lang.bind(this, this._getResultsFinished),
|
||||
this._cancellable);
|
||||
} catch(e) {
|
||||
log('Error calling GetInitialResultSet for provider %s: %s'.format(this.id, e.toString()));
|
||||
log('Error calling GetInitialResultSet for provider %s: %s'.format( this.title, e.toString()));
|
||||
this.searchSystem.pushResults(this, []);
|
||||
}
|
||||
},
|
||||
@ -238,7 +228,7 @@ const RemoteSearchProvider = new Lang.Class({
|
||||
Lang.bind(this, this._getResultsFinished),
|
||||
this._cancellable);
|
||||
} catch(e) {
|
||||
log('Error calling GetSubsearchResultSet for provider %s: %s'.format(this.id, e.toString()));
|
||||
log('Error calling GetSubsearchResultSet for provider %s: %s'.format(this.title, e.toString()));
|
||||
this.searchSystem.pushResults(this, []);
|
||||
}
|
||||
},
|
||||
@ -255,7 +245,6 @@ const RemoteSearchProvider = new Lang.Class({
|
||||
metas[i][prop] = metas[i][prop].deep_unpack();
|
||||
resultMetas.push({ id: metas[i]['id'],
|
||||
name: metas[i]['name'],
|
||||
description: metas[i]['description'],
|
||||
createIcon: Lang.bind(this,
|
||||
this.createIcon, metas[i]) });
|
||||
}
|
||||
@ -270,7 +259,7 @@ const RemoteSearchProvider = new Lang.Class({
|
||||
Lang.bind(this, this._getResultMetasFinished, callback),
|
||||
this._cancellable);
|
||||
} catch(e) {
|
||||
log('Error calling GetResultMetas for provider %s: %s'.format(this.id, e.toString()));
|
||||
log('Error calling GetResultMetas for provider %s: %s'.format(this.title, e.toString()));
|
||||
callback([]);
|
||||
}
|
||||
},
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,277 +0,0 @@
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
|
||||
const Clutter = imports.gi.Clutter;
|
||||
const Gdk = imports.gi.Gdk;
|
||||
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 Signals = imports.signals;
|
||||
const St = imports.gi.St;
|
||||
|
||||
const Lightbox = imports.ui.lightbox;
|
||||
const Main = imports.ui.main;
|
||||
const Tweener = imports.ui.tweener;
|
||||
|
||||
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',
|
||||
|
||||
_init: function() {
|
||||
this._dbusImpl = Gio.DBusExportedObject.wrapJSObject(ScreenshotIface, this);
|
||||
this._dbusImpl.export(Gio.DBus.session, '/org/gnome/Shell/Screenshot');
|
||||
|
||||
Gio.DBus.session.own_name('org.gnome.Shell.Screenshot', Gio.BusNameOwnerFlags.REPLACE, null, null);
|
||||
},
|
||||
|
||||
_onScreenshotComplete: function(obj, result, area, filenameUsed, flash, invocation) {
|
||||
if (flash && result) {
|
||||
let flashspot = new Flashspot(area);
|
||||
flashspot.fire();
|
||||
}
|
||||
|
||||
let retval = GLib.Variant.new('(bs)', [result, filenameUsed]);
|
||||
invocation.return_value(retval);
|
||||
},
|
||||
|
||||
ScreenshotAreaAsync : function (params, invocation) {
|
||||
let [x, y, width, height, flash, filename, callback] = params;
|
||||
if (height <= 0 || width <= 0) {
|
||||
invocation.return_error_literal(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED,
|
||||
"Invalid params");
|
||||
return;
|
||||
}
|
||||
let screenshot = new Shell.Screenshot();
|
||||
screenshot.screenshot_area (x, y, width, height, filename,
|
||||
Lang.bind(this, this._onScreenshotComplete,
|
||||
flash, invocation));
|
||||
},
|
||||
|
||||
ScreenshotWindowAsync : function (params, invocation) {
|
||||
let [include_frame, include_cursor, flash, filename] = params;
|
||||
let screenshot = new Shell.Screenshot();
|
||||
screenshot.screenshot_window (include_frame, include_cursor, filename,
|
||||
Lang.bind(this, this._onScreenshotComplete,
|
||||
flash, invocation));
|
||||
},
|
||||
|
||||
ScreenshotAsync : function (params, invocation) {
|
||||
let [include_cursor, flash, filename] = params;
|
||||
let screenshot = new Shell.Screenshot();
|
||||
screenshot.screenshot(include_cursor, filename,
|
||||
Lang.bind(this, this._onScreenshotComplete,
|
||||
flash, invocation));
|
||||
},
|
||||
|
||||
SelectAreaAsync: function (params, invocation) {
|
||||
let selectArea = new SelectArea();
|
||||
selectArea.show();
|
||||
selectArea.connect('finished', Lang.bind(this,
|
||||
function(selectArea, areaRectangle) {
|
||||
if (areaRectangle) {
|
||||
let retval = GLib.Variant.new('(iiii)',
|
||||
[areaRectangle.x, areaRectangle.y,
|
||||
areaRectangle.width, areaRectangle.height]);
|
||||
invocation.return_value(retval);
|
||||
} else {
|
||||
invocation.return_error_literal(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED,
|
||||
"Operation was cancelled");
|
||||
}
|
||||
}));
|
||||
},
|
||||
|
||||
FlashArea: function(x, y, width, height) {
|
||||
let flashspot = new Flashspot({ x : x, y : y, width: width, height: height});
|
||||
flashspot.fire();
|
||||
}
|
||||
});
|
||||
|
||||
const SelectArea = new Lang.Class({
|
||||
Name: 'SelectArea',
|
||||
|
||||
_init: function() {
|
||||
this._startX = -1;
|
||||
this._startY = -1;
|
||||
this._lastX = 0;
|
||||
this._lastY = 0;
|
||||
|
||||
this._initRubberbandColors();
|
||||
|
||||
this._group = new St.Widget({ visible: false,
|
||||
reactive: true,
|
||||
x: 0,
|
||||
y: 0 });
|
||||
Main.uiGroup.add_actor(this._group);
|
||||
|
||||
this._group.connect('button-press-event',
|
||||
Lang.bind(this, this._onButtonPress));
|
||||
this._group.connect('button-release-event',
|
||||
Lang.bind(this, this._onButtonRelease));
|
||||
this._group.connect('key-press-event',
|
||||
Lang.bind(this, this._onKeyPress));
|
||||
this._group.connect('motion-event',
|
||||
Lang.bind(this, this._onMotionEvent));
|
||||
|
||||
let constraint = new Clutter.BindConstraint({ source: global.stage,
|
||||
coordinate: Clutter.BindCoordinate.ALL });
|
||||
this._group.add_constraint(constraint);
|
||||
|
||||
this._rubberband = new Clutter.Rectangle({ color: this._background,
|
||||
has_border: true,
|
||||
border_width: 1,
|
||||
border_color: this._border });
|
||||
this._group.add_actor(this._rubberband);
|
||||
},
|
||||
|
||||
show: function() {
|
||||
if (!Main.pushModal(this._group) || this._group.visible)
|
||||
return;
|
||||
|
||||
global.set_cursor(Shell.Cursor.CROSSHAIR);
|
||||
this._group.visible = true;
|
||||
},
|
||||
|
||||
_initRubberbandColors: function() {
|
||||
function colorFromRGBA(rgba) {
|
||||
return new Clutter.Color({ red: rgba.red * 255,
|
||||
green: rgba.green * 255,
|
||||
blue: rgba.blue * 255,
|
||||
alpha: rgba.alpha * 255 });
|
||||
}
|
||||
|
||||
let path = new Gtk.WidgetPath();
|
||||
path.append_type(Gtk.IconView);
|
||||
|
||||
let context = new Gtk.StyleContext();
|
||||
context.set_path(path);
|
||||
context.add_class('rubberband');
|
||||
|
||||
this._background = colorFromRGBA(context.get_background_color(Gtk.StateFlags.NORMAL));
|
||||
this._border = colorFromRGBA(context.get_border_color(Gtk.StateFlags.NORMAL));
|
||||
},
|
||||
|
||||
_getGeometry: function() {
|
||||
return { x: Math.min(this._startX, this._lastX),
|
||||
y: Math.min(this._startY, this._lastY),
|
||||
width: Math.abs(this._startX - this._lastX),
|
||||
height: Math.abs(this._startY - this._lastY) };
|
||||
},
|
||||
|
||||
_onKeyPress: function(actor, event) {
|
||||
if (event.get_key_symbol() == Clutter.Escape)
|
||||
this._destroy(null, false);
|
||||
|
||||
return;
|
||||
},
|
||||
|
||||
_onMotionEvent: function(actor, event) {
|
||||
if (this._startX == -1 || this._startY == -1)
|
||||
return false;
|
||||
|
||||
[this._lastX, this._lastY] = event.get_coords();
|
||||
let geometry = this._getGeometry();
|
||||
|
||||
this._rubberband.set_position(geometry.x, geometry.y);
|
||||
this._rubberband.set_size(geometry.width, geometry.height);
|
||||
|
||||
return false;
|
||||
},
|
||||
|
||||
_onButtonPress: function(actor, event) {
|
||||
[this._startX, this._startY] = event.get_coords();
|
||||
this._rubberband.set_position(this._startX, this._startY);
|
||||
|
||||
return false;
|
||||
},
|
||||
|
||||
_onButtonRelease: function(actor, event) {
|
||||
this._destroy(this._getGeometry(), true);
|
||||
return false;
|
||||
},
|
||||
|
||||
_destroy: function(geometry, fade) {
|
||||
Tweener.addTween(this._group,
|
||||
{ opacity: 0,
|
||||
time: fade ? 0.2 : 0,
|
||||
transition: 'easeOutQuad',
|
||||
onComplete: Lang.bind(this,
|
||||
function() {
|
||||
Main.popModal(this._group);
|
||||
this._group.destroy();
|
||||
global.unset_cursor();
|
||||
|
||||
this.emit('finished', geometry);
|
||||
})
|
||||
});
|
||||
}
|
||||
});
|
||||
Signals.addSignalMethods(SelectArea.prototype);
|
||||
|
||||
const FLASHSPOT_ANIMATION_OUT_TIME = 0.5; // seconds
|
||||
|
||||
const Flashspot = new Lang.Class({
|
||||
Name: 'Flashspot',
|
||||
Extends: Lightbox.Lightbox,
|
||||
|
||||
_init: function(area) {
|
||||
this.parent(Main.uiGroup, { inhibitEvents: true,
|
||||
width: area.width,
|
||||
height: area.height });
|
||||
|
||||
this.actor.style_class = 'flashspot';
|
||||
this.actor.set_position(area.x, area.y);
|
||||
},
|
||||
|
||||
fire: function() {
|
||||
this.actor.show();
|
||||
this.actor.opacity = 255;
|
||||
Tweener.addTween(this.actor,
|
||||
{ opacity: 0,
|
||||
time: FLASHSPOT_ANIMATION_OUT_TIME,
|
||||
transition: 'easeOutQuad',
|
||||
onComplete: Lang.bind(this, function() {
|
||||
this.destroy();
|
||||
})
|
||||
});
|
||||
}
|
||||
});
|
@ -60,18 +60,28 @@ const SearchSystem = new Lang.Class({
|
||||
this.emit('search-updated', this._previousResults[i]);
|
||||
},
|
||||
|
||||
updateSearch: function(searchString) {
|
||||
searchString = searchString.replace(/^\s+/g, '').replace(/\s+$/g, '');
|
||||
if (searchString == '')
|
||||
return;
|
||||
|
||||
let terms = searchString.split(/\s+/);
|
||||
this.updateSearchResults(terms);
|
||||
},
|
||||
|
||||
updateSearchResults: function(terms) {
|
||||
if (!terms)
|
||||
return;
|
||||
|
||||
let searchString = terms.join(' ');
|
||||
let previousSearchString = this._previousTerms.join(' ');
|
||||
if (searchString == previousSearchString)
|
||||
return;
|
||||
|
||||
let isSubSearch = false;
|
||||
if (this._previousTerms.length > 0)
|
||||
isSubSearch = searchString.indexOf(previousSearchString) == 0;
|
||||
let isSubSearch = terms.length == this._previousTerms.length;
|
||||
if (isSubSearch) {
|
||||
for (let i = 0; i < terms.length; i++) {
|
||||
if (terms[i].indexOf(this._previousTerms[i]) != 0) {
|
||||
isSubSearch = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let previousResultsArr = this._previousResults;
|
||||
|
||||
@ -100,6 +110,6 @@ const SearchSystem = new Lang.Class({
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
Signals.addSignalMethods(SearchSystem.prototype);
|
||||
|
@ -17,26 +17,6 @@ const Search = imports.ui.search;
|
||||
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',
|
||||
|
||||
@ -103,9 +83,10 @@ const ListSearchResult = new Lang.Class({
|
||||
x_align: St.Align.START,
|
||||
y_align: St.Align.START });
|
||||
|
||||
// TODO: should highlight terms in the description here
|
||||
if (this.metaInfo['description']) {
|
||||
let description = new St.Label({ style_class: 'list-search-result-description' });
|
||||
description.clutter_text.set_markup(this.metaInfo['description']);
|
||||
let description = new St.Label({ style_class: 'list-search-result-description',
|
||||
text: '"' + this.metaInfo['description'] + '"' });
|
||||
details.add(description, { x_fill: false,
|
||||
y_fill: false,
|
||||
x_align: St.Align.START,
|
||||
@ -197,7 +178,7 @@ const ListSearchResults = new Lang.Class({
|
||||
|
||||
this._content = new St.BoxLayout({ style_class: 'list-search-results',
|
||||
vertical: true });
|
||||
this.actor.add(this._content, { expand: true });
|
||||
this.actor.add_actor(this._content);
|
||||
|
||||
this._notDisplayedResult = [];
|
||||
this._terms = [];
|
||||
@ -320,20 +301,12 @@ const SearchResults = new Lang.Class({
|
||||
|
||||
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' });
|
||||
style_class: 'vfade' });
|
||||
this._scrollView.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC);
|
||||
this._scrollView.add_actor(scrollChild);
|
||||
this._scrollView.add_actor(this._content);
|
||||
let action = new Clutter.PanAction({ interpolate: true });
|
||||
action.connect('pan', Lang.bind(this, this._onPan));
|
||||
this._scrollView.add_action(action);
|
||||
@ -423,15 +396,18 @@ const SearchResults = new Lang.Class({
|
||||
this._searchSystem.reset();
|
||||
this._statusBin.hide();
|
||||
this._clearDisplay();
|
||||
this._defaultResult = null;
|
||||
},
|
||||
|
||||
startingSearch: function() {
|
||||
this.reset();
|
||||
this._statusText.set_text(_("Searching…"));
|
||||
this._statusText.set_text(_("Searching..."));
|
||||
this._statusBin.show();
|
||||
},
|
||||
|
||||
doSearch: function (searchString) {
|
||||
this._searchSystem.updateSearch(searchString);
|
||||
},
|
||||
|
||||
_metaForProvider: function(provider) {
|
||||
return this._providerMeta[this._providers.indexOf(provider)];
|
||||
},
|
||||
|
@ -30,6 +30,5 @@ const HorizontalSeparator = new Lang.Class({
|
||||
cr.setSource(pattern);
|
||||
cr.rectangle(margin, gradientOffset, gradientWidth, gradientHeight);
|
||||
cr.fill();
|
||||
cr.$dispose();
|
||||
}
|
||||
});
|
||||
|
@ -15,7 +15,6 @@ const DEFAULT_MODE = 'restrictive';
|
||||
const _modes = {
|
||||
'restrictive': {
|
||||
parentMode: null,
|
||||
stylesheetName: 'gnome-shell.css',
|
||||
hasOverview: false,
|
||||
showCalendarEvents: false,
|
||||
allowSettings: false,
|
||||
@ -47,7 +46,7 @@ const _modes = {
|
||||
panel: {
|
||||
left: ['logo'],
|
||||
center: ['dateMenu'],
|
||||
right: ['a11yGreeter', 'display', 'keyboard',
|
||||
right: ['a11y', 'display', 'keyboard',
|
||||
'volume', 'battery', 'powerMenu']
|
||||
},
|
||||
panelStyle: 'login-screen'
|
||||
@ -84,7 +83,7 @@ const _modes = {
|
||||
panel: {
|
||||
left: [],
|
||||
center: ['dateMenu'],
|
||||
right: ['a11yGreeter', 'keyboard', 'volume']
|
||||
right: ['a11y', 'keyboard', 'volume']
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -1,18 +1,16 @@
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
|
||||
const Lang = imports.lang;
|
||||
const Gio = imports.gi.Gio;
|
||||
const GLib = imports.gi.GLib;
|
||||
const Lang = imports.lang;
|
||||
const Meta = imports.gi.Meta;
|
||||
const Shell = imports.gi.Shell;
|
||||
|
||||
const Config = imports.misc.config;
|
||||
const ExtensionSystem = imports.ui.extensionSystem;
|
||||
const ExtensionDownloader = imports.ui.extensionDownloader;
|
||||
const ExtensionUtils = imports.misc.extensionUtils;
|
||||
const Hash = imports.misc.hash;
|
||||
const Flashspot = imports.ui.flashspot;
|
||||
const Main = imports.ui.main;
|
||||
const Screenshot = imports.ui.screenshot;
|
||||
|
||||
const GnomeShellIface = <interface name="org.gnome.Shell">
|
||||
<method name="Eval">
|
||||
@ -20,26 +18,34 @@ const GnomeShellIface = <interface name="org.gnome.Shell">
|
||||
<arg type="b" direction="out" name="success" />
|
||||
<arg type="s" direction="out" name="result" />
|
||||
</method>
|
||||
<method name="ShowOSD">
|
||||
<arg type="a{sv}" direction="in" name="params"/>
|
||||
</method>
|
||||
<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"/>
|
||||
<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"/>
|
||||
</method>
|
||||
<signal name="AcceleratorActivated">
|
||||
<arg name="action" type="u" />
|
||||
<arg name="deviceid" type="u" />
|
||||
</signal>
|
||||
<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"/>
|
||||
</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"/>
|
||||
</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>
|
||||
<property name="Mode" type="s" access="read" />
|
||||
<property name="OverviewActive" type="b" access="readwrite" />
|
||||
<property name="ShellVersion" type="s" access="read" />
|
||||
@ -69,16 +75,7 @@ const GnomeShell = new Lang.Class({
|
||||
this._dbusImpl = Gio.DBusExportedObject.wrapJSObject(GnomeShellIface, this);
|
||||
this._dbusImpl.export(Gio.DBus.session, '/org/gnome/Shell');
|
||||
|
||||
this._extensionsService = new GnomeShellExtensions();
|
||||
this._screenshotService = new Screenshot.ScreenshotService();
|
||||
|
||||
this._grabbedAccelerators = new Hash.Map();
|
||||
this._grabbers = new Hash.Map();
|
||||
|
||||
global.display.connect('accelerator-activated', Lang.bind(this,
|
||||
function(display, action, deviceid) {
|
||||
this._emitAcceleratorActivated(action, deviceid);
|
||||
}));
|
||||
this._extensionsSerivce = new GnomeShellExtensions();
|
||||
},
|
||||
|
||||
/**
|
||||
@ -114,101 +111,81 @@ const GnomeShell = new Lang.Class({
|
||||
return [success, returnValue];
|
||||
},
|
||||
|
||||
ShowOSD: function(params) {
|
||||
for (let param in params)
|
||||
params[param] = params[param].deep_unpack();
|
||||
|
||||
let icon = null;
|
||||
if (params['icon'])
|
||||
icon = Gio.Icon.new_for_string(params['icon']);
|
||||
|
||||
Main.osdWindow.setIcon(icon);
|
||||
Main.osdWindow.setLabel(params['label']);
|
||||
Main.osdWindow.setLevel(params['level']);
|
||||
|
||||
Main.osdWindow.show();
|
||||
},
|
||||
|
||||
GrabAcceleratorAsync: function(params, invocation) {
|
||||
let [accel, flags] = params;
|
||||
let sender = invocation.get_sender();
|
||||
let bindingAction = this._grabAcceleratorForSender(accel, flags, sender);
|
||||
return invocation.return_value(GLib.Variant.new('(u)', [bindingAction]));
|
||||
},
|
||||
|
||||
GrabAcceleratorsAsync: function(params, invocation) {
|
||||
let [accels] = params;
|
||||
let sender = invocation.get_sender();
|
||||
let bindingActions = [];
|
||||
for (let i = 0; i < accels.length; i++) {
|
||||
let [accel, flags] = accels[i];
|
||||
bindingActions.push(this._grabAcceleratorForSender(accel, flags, sender));
|
||||
}
|
||||
return invocation.return_value(GLib.Variant.new('(au)', [bindingActions]));
|
||||
},
|
||||
|
||||
UngrabAcceleratorAsync: function(params, invocation) {
|
||||
let [action] = params;
|
||||
let grabbedBy = this._grabbedAccelerators.get(action);
|
||||
if (invocation.get_sender() != grabbedBy)
|
||||
return invocation.return_value(GLib.Variant.new('(b)', [false]));
|
||||
|
||||
let ungrabSucceeded = global.display.ungrab_accelerator(action);
|
||||
if (ungrabSucceeded)
|
||||
this._grabbedAccelerators.delete(action);
|
||||
return invocation.return_value(GLib.Variant.new('(b)', [ungrabSucceeded]));
|
||||
},
|
||||
|
||||
_emitAcceleratorActivated: function(action, deviceid) {
|
||||
let destination = this._grabbedAccelerators.get(action);
|
||||
if (!destination)
|
||||
return;
|
||||
|
||||
let connection = this._dbusImpl.get_connection();
|
||||
let info = this._dbusImpl.get_info();
|
||||
connection.emit_signal(destination,
|
||||
this._dbusImpl.get_object_path(),
|
||||
info ? info.name : null,
|
||||
'AcceleratorActivated',
|
||||
GLib.Variant.new('(uu)', [action, deviceid]));
|
||||
},
|
||||
|
||||
_grabAcceleratorForSender: function(accelerator, flags, sender) {
|
||||
let bindingAction = global.display.grab_accelerator(accelerator);
|
||||
if (bindingAction == Meta.KeyBindingAction.NONE)
|
||||
return Meta.KeyBindingAction.NONE;
|
||||
|
||||
let bindingName = Meta.external_binding_name_for_action(bindingAction);
|
||||
Main.wm.allowKeybinding(bindingName, flags);
|
||||
|
||||
this._grabbedAccelerators.set(bindingAction, sender);
|
||||
|
||||
if (!this._grabbers.has(sender)) {
|
||||
let id = Gio.bus_watch_name(Gio.BusType.SESSION, sender, 0, null,
|
||||
Lang.bind(this, this._onGrabberBusNameVanished));
|
||||
this._grabbers.set(sender, id);
|
||||
_onScreenshotComplete: function(obj, result, area, flash, invocation) {
|
||||
if (flash && result) {
|
||||
let flashspot = new Flashspot.Flashspot(area);
|
||||
flashspot.fire();
|
||||
}
|
||||
|
||||
return bindingAction;
|
||||
let retval = GLib.Variant.new('(b)', [result]);
|
||||
invocation.return_value(retval);
|
||||
},
|
||||
|
||||
_ungrabAccelerator: function(action) {
|
||||
let ungrabSucceeded = global.display.ungrab_accelerator(action);
|
||||
if (ungrabSucceeded)
|
||||
this._grabbedAccelerators.delete(action);
|
||||
/**
|
||||
* ScreenshotArea:
|
||||
* @x: The X coordinate of the area
|
||||
* @y: The Y coordinate of the area
|
||||
* @width: The width of the area
|
||||
* @height: The height of the area
|
||||
* @flash: Whether to flash the area or not
|
||||
* @filename: The filename for the screenshot
|
||||
*
|
||||
* Takes a screenshot of the passed in area and saves it
|
||||
* in @filename as png image, it returns a boolean
|
||||
* indicating whether the operation was successful or not.
|
||||
*
|
||||
*/
|
||||
ScreenshotAreaAsync : function (params, invocation) {
|
||||
let [x, y, width, height, flash, filename, callback] = params;
|
||||
let screenshot = new Shell.Screenshot();
|
||||
screenshot.screenshot_area (x, y, width, height, filename,
|
||||
Lang.bind(this, this._onScreenshotComplete,
|
||||
flash, invocation));
|
||||
},
|
||||
|
||||
_onGrabberBusNameVanished: function(connection, name) {
|
||||
let grabs = this._grabbedAccelerators.items();
|
||||
for (let i = 0; i < grabs.length; i++) {
|
||||
let [action, sender] = grabs[i];
|
||||
if (sender == name)
|
||||
this._ungrabAccelerator(action);
|
||||
}
|
||||
Gio.bus_unwatch_name(this._grabbers.get(name));
|
||||
this._grabbers.delete(name);
|
||||
/**
|
||||
* ScreenshotWindow:
|
||||
* @include_frame: Whether to include the frame or not
|
||||
* @include_cursor: Whether to include the cursor image or not
|
||||
* @flash: Whether to flash the window area or not
|
||||
* @filename: The filename for the screenshot
|
||||
*
|
||||
* Takes a screenshot of the focused window (optionally omitting the frame)
|
||||
* and saves it in @filename as png image, it returns a boolean
|
||||
* indicating whether the operation was successful or not.
|
||||
*
|
||||
*/
|
||||
ScreenshotWindowAsync : function (params, invocation) {
|
||||
let [include_frame, include_cursor, flash, filename] = params;
|
||||
let screenshot = new Shell.Screenshot();
|
||||
screenshot.screenshot_window (include_frame, include_cursor, filename,
|
||||
Lang.bind(this, this._onScreenshotComplete,
|
||||
flash, invocation));
|
||||
},
|
||||
|
||||
/**
|
||||
* Screenshot:
|
||||
* @filename: The filename for the screenshot
|
||||
* @include_cursor: Whether to include the cursor image or not
|
||||
* @flash: Whether to flash the screen or not
|
||||
*
|
||||
* Takes a screenshot of the whole screen and saves it
|
||||
* in @filename as png image, it returns a boolean
|
||||
* indicating whether the operation was successful or not.
|
||||
*
|
||||
*/
|
||||
ScreenshotAsync : function (params, invocation) {
|
||||
let [include_cursor, flash, filename] = params;
|
||||
let screenshot = new Shell.Screenshot();
|
||||
screenshot.screenshot(include_cursor, filename,
|
||||
Lang.bind(this, this._onScreenshotComplete,
|
||||
flash, invocation));
|
||||
},
|
||||
|
||||
FlashArea: function(x, y, width, height) {
|
||||
let flashspot = new Flashspot.Flashspot({ x : x, y : y, width: width, height: height});
|
||||
flashspot.fire();
|
||||
},
|
||||
|
||||
Mode: global.session_mode,
|
||||
|
||||
@ -373,8 +350,8 @@ const ScreenSaverDBus = new Lang.Class({
|
||||
this.parent();
|
||||
|
||||
this._screenShield = screenShield;
|
||||
screenShield.connect('active-changed', Lang.bind(this, function(shield) {
|
||||
this._dbusImpl.emit_signal('ActiveChanged', GLib.Variant.new('(b)', [shield.active]));
|
||||
screenShield.connect('lock-status-changed', Lang.bind(this, function(shield) {
|
||||
this._dbusImpl.emit_signal('ActiveChanged', GLib.Variant.new('(b)', [shield.locked]));
|
||||
}));
|
||||
|
||||
this._dbusImpl = Gio.DBusExportedObject.wrapJSObject(ScreenSaverIface, this);
|
||||
@ -395,13 +372,13 @@ const ScreenSaverDBus = new Lang.Class({
|
||||
|
||||
SetActive: function(active) {
|
||||
if (active)
|
||||
this._screenShield.activate(true);
|
||||
this._screenShield.lock(true);
|
||||
else
|
||||
this._screenShield.unlock(false);
|
||||
this._screenShield.unlock();
|
||||
},
|
||||
|
||||
GetActive: function() {
|
||||
return this._screenShield.active;
|
||||
return this._screenShield.locked;
|
||||
},
|
||||
|
||||
GetActiveTime: function() {
|
||||
|
@ -1,11 +1,8 @@
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
|
||||
const Clutter = imports.gi.Clutter;
|
||||
const Gtk = imports.gi.Gtk;
|
||||
const Lang = imports.lang;
|
||||
const St = imports.gi.St;
|
||||
|
||||
const BoxPointer = imports.ui.boxpointer;
|
||||
const Main = imports.ui.main;
|
||||
const Params = imports.misc.params;
|
||||
const PopupMenu = imports.ui.popupMenu;
|
||||
@ -68,33 +65,32 @@ const EntryMenu = new Lang.Class({
|
||||
}
|
||||
},
|
||||
|
||||
open: function(animate) {
|
||||
open: function() {
|
||||
this._updatePasteItem();
|
||||
this._updateCopyItem();
|
||||
if (this._passwordItem)
|
||||
this._updatePasswordItem();
|
||||
|
||||
this.parent(animate);
|
||||
this._entry.add_style_pseudo_class('focus');
|
||||
|
||||
let direction = Gtk.DirectionType.TAB_FORWARD;
|
||||
if (!this.actor.navigate_focus(null, direction, false))
|
||||
this.actor.grab_key_focus();
|
||||
|
||||
this.parent();
|
||||
this._entry.add_style_pseudo_class('focus');
|
||||
},
|
||||
|
||||
close: function(animate) {
|
||||
close: function() {
|
||||
this._entry.grab_key_focus();
|
||||
this.parent(animate);
|
||||
this.parent();
|
||||
},
|
||||
|
||||
_updateCopyItem: function() {
|
||||
let selection = this._entry.clutter_text.get_selection();
|
||||
this._copyItem.setSensitive(!this._entry.clutter_text.password_char &&
|
||||
selection && selection != '');
|
||||
this._copyItem.setSensitive(selection && selection != '');
|
||||
},
|
||||
|
||||
_updatePasteItem: function() {
|
||||
this._clipboard.get_text(St.ClipboardType.CLIPBOARD, Lang.bind(this,
|
||||
this._clipboard.get_text(Lang.bind(this,
|
||||
function(clipboard, text) {
|
||||
this._pasteItem.setSensitive(text && text != '');
|
||||
}));
|
||||
@ -110,11 +106,11 @@ const EntryMenu = new Lang.Class({
|
||||
|
||||
_onCopyActivated: function() {
|
||||
let selection = this._entry.clutter_text.get_selection();
|
||||
this._clipboard.set_text(St.ClipboardType.CLIPBOARD, selection);
|
||||
this._clipboard.set_text(selection);
|
||||
},
|
||||
|
||||
_onPasteActivated: function() {
|
||||
this._clipboard.get_text(St.ClipboardType.CLIPBOARD, Lang.bind(this,
|
||||
this._clipboard.get_text(Lang.bind(this,
|
||||
function(clipboard, text) {
|
||||
if (!text)
|
||||
return;
|
||||
@ -138,12 +134,12 @@ function _setMenuAlignment(entry, stageX) {
|
||||
|
||||
function _onButtonPressEvent(actor, event, entry) {
|
||||
if (entry.menu.isOpen) {
|
||||
entry.menu.close(BoxPointer.PopupAnimation.FULL);
|
||||
entry.menu.close();
|
||||
return true;
|
||||
} else if (event.get_button() == 3) {
|
||||
let [stageX, stageY] = event.get_coords();
|
||||
_setMenuAlignment(entry, stageX);
|
||||
entry.menu.open(BoxPointer.PopupAnimation.FULL);
|
||||
entry.menu.open();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@ -153,7 +149,7 @@ function _onPopup(actor, entry) {
|
||||
let [success, textX, textY, lineHeight] = entry.clutter_text.position_to_coords(-1);
|
||||
if (success)
|
||||
entry.menu.setSourceAlignment(textX / entry.width);
|
||||
entry.menu.open(BoxPointer.PopupAnimation.FULL);
|
||||
entry.menu.open();
|
||||
};
|
||||
|
||||
function addContextMenu(entry, params) {
|
||||
|
@ -2,7 +2,6 @@
|
||||
|
||||
const Gio = imports.gi.Gio;
|
||||
const Lang = imports.lang;
|
||||
const Mainloop = imports.mainloop;
|
||||
|
||||
const PanelMenu = imports.ui.panelMenu;
|
||||
const PopupMenu = imports.ui.popupMenu;
|
||||
@ -15,7 +14,12 @@ const KEY_MOUSE_KEYS_ENABLED = 'mousekeys-enable';
|
||||
|
||||
const APPLICATIONS_SCHEMA = 'org.gnome.desktop.a11y.applications';
|
||||
|
||||
const DPI_LOW_REASONABLE_VALUE = 50;
|
||||
const DPI_HIGH_REASONABLE_VALUE = 500;
|
||||
|
||||
const DPI_FACTOR_LARGE = 1.25;
|
||||
const DPI_FACTOR_LARGER = 1.5;
|
||||
const DPI_FACTOR_LARGEST = 2.0;
|
||||
|
||||
const WM_SCHEMA = 'org.gnome.desktop.wm.preferences';
|
||||
const KEY_VISUAL_BELL = 'visual-bell';
|
||||
@ -70,25 +74,6 @@ const ATIndicator = new Lang.Class({
|
||||
|
||||
this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
|
||||
this.menu.addSettingsAction(_("Universal Access Settings"), 'gnome-universal-access-panel.desktop');
|
||||
|
||||
this._syncMenuVisibility();
|
||||
},
|
||||
|
||||
_syncMenuVisibility: function() {
|
||||
this._syncMenuVisibilityIdle = 0;
|
||||
|
||||
let items = this.menu._getMenuItems();
|
||||
|
||||
this.actor.visible = items.some(function(f) { return !!f.state; });
|
||||
|
||||
return false;
|
||||
},
|
||||
|
||||
_queueSyncMenuVisibility: function() {
|
||||
if (this._syncMenuVisibilityIdle)
|
||||
return;
|
||||
|
||||
this._syncMenuVisbilityIdle = Mainloop.idle_add(Lang.bind(this, this._syncMenuVisibility));
|
||||
},
|
||||
|
||||
_buildItemExtended: function(string, initial_value, writable, on_set) {
|
||||
@ -110,11 +95,9 @@ const ATIndicator = new Lang.Class({
|
||||
function(enabled) {
|
||||
return settings.set_boolean(key, enabled);
|
||||
});
|
||||
settings.connect('changed::'+key, Lang.bind(this, function() {
|
||||
settings.connect('changed::'+key, function() {
|
||||
widget.setToggleState(settings.get_boolean(key));
|
||||
|
||||
this._queueSyncMenuVisibility();
|
||||
}));
|
||||
});
|
||||
return widget;
|
||||
},
|
||||
|
||||
@ -146,7 +129,7 @@ const ATIndicator = new Lang.Class({
|
||||
wmSettings.reset(KEY_WM_THEME);
|
||||
}
|
||||
});
|
||||
interfaceSettings.connect('changed::' + KEY_GTK_THEME, Lang.bind(this, function() {
|
||||
interfaceSettings.connect('changed::' + KEY_GTK_THEME, function() {
|
||||
let value = interfaceSettings.get_string(KEY_GTK_THEME);
|
||||
if (value == HIGH_CONTRAST_THEME) {
|
||||
highContrast.setToggleState(true);
|
||||
@ -154,9 +137,7 @@ const ATIndicator = new Lang.Class({
|
||||
highContrast.setToggleState(false);
|
||||
gtkTheme = value;
|
||||
}
|
||||
|
||||
this._queueSyncMenuVisibility();
|
||||
}));
|
||||
});
|
||||
interfaceSettings.connect('changed::' + KEY_ICON_THEME, function() {
|
||||
let value = interfaceSettings.get_string(KEY_ICON_THEME);
|
||||
if (value != HIGH_CONTRAST_THEME)
|
||||
@ -185,22 +166,11 @@ const ATIndicator = new Lang.Class({
|
||||
else
|
||||
settings.reset(KEY_TEXT_SCALING_FACTOR);
|
||||
});
|
||||
settings.connect('changed::' + KEY_TEXT_SCALING_FACTOR, Lang.bind(this, function() {
|
||||
settings.connect('changed::' + KEY_TEXT_SCALING_FACTOR, function() {
|
||||
let factor = settings.get_double(KEY_TEXT_SCALING_FACTOR);
|
||||
let active = (factor > 1.0);
|
||||
widget.setToggleState(active);
|
||||
|
||||
this._queueSyncMenuVisibility();
|
||||
}));
|
||||
});
|
||||
return widget;
|
||||
}
|
||||
});
|
||||
|
||||
const ATGreeterIndicator = new Lang.Class({
|
||||
Name: 'ATGreeterIndicator',
|
||||
Extends: ATIndicator,
|
||||
|
||||
// Override visibility handling to be always visible
|
||||
_syncMenuVisibility: function() { },
|
||||
_queueSyncMenuVisibility: function() { }
|
||||
});
|
||||
|
@ -9,7 +9,6 @@ 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;
|
||||
|
||||
@ -56,8 +55,8 @@ const Indicator = new Lang.Class({
|
||||
this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
|
||||
|
||||
this._fullMenuItems = [new PopupMenu.PopupSeparatorMenuItem(),
|
||||
new PopupMenu.PopupMenuItem(_("Send Files to Device…")),
|
||||
new PopupMenu.PopupMenuItem(_("Set Up a New Device…")),
|
||||
new PopupMenu.PopupMenuItem(_("Send Files to Device...")),
|
||||
new PopupMenu.PopupMenuItem(_("Set up a New Device...")),
|
||||
new PopupMenu.PopupSeparatorMenuItem()];
|
||||
this._hasDevices = false;
|
||||
|
||||
@ -236,7 +235,7 @@ const Indicator = new Lang.Class({
|
||||
}
|
||||
|
||||
if (device.capabilities & GnomeBluetoothApplet.Capabilities.OBEX_PUSH) {
|
||||
item.menu.addAction(_("Send Files…"), Lang.bind(this, function() {
|
||||
item.menu.addAction(_("Send Files..."), Lang.bind(this, function() {
|
||||
this._applet.send_to_address(device.bdaddr, device.alias);
|
||||
}));
|
||||
}
|
||||
@ -287,7 +286,6 @@ const Indicator = new Lang.Class({
|
||||
_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);
|
||||
}
|
||||
},
|
||||
@ -448,5 +446,10 @@ const PinNotification = new Lang.Class({
|
||||
return this._entry.clutter_text.text.length == 6;
|
||||
else
|
||||
return true;
|
||||
},
|
||||
|
||||
grabFocus: function(lockTray) {
|
||||
this.parent(lockTray);
|
||||
global.stage.set_key_focus(this._entry);
|
||||
}
|
||||
});
|
||||
|
@ -115,14 +115,9 @@ const IBusManager = new Lang.Class({
|
||||
this._panelService.connect('update-property', Lang.bind(this, this._updateProperty));
|
||||
// If an engine is already active we need to get its properties
|
||||
this._ibus.get_global_engine_async(-1, null, Lang.bind(this, function(i, result) {
|
||||
let engine;
|
||||
try {
|
||||
engine = this._ibus.get_global_engine_async_finish(result);
|
||||
let engine = this._ibus.get_global_engine_async_finish(result);
|
||||
if (!engine)
|
||||
return;
|
||||
} catch(e) {
|
||||
return;
|
||||
}
|
||||
this._engineChanged(this._ibus, engine.get_name());
|
||||
}));
|
||||
this._updateReadiness();
|
||||
@ -337,14 +332,14 @@ const InputSourceIndicator = new Lang.Class({
|
||||
Main.wm.addKeybinding('switch-input-source',
|
||||
new Gio.Settings({ schema: "org.gnome.desktop.wm.keybindings" }),
|
||||
Meta.KeyBindingFlags.REVERSES,
|
||||
Shell.KeyBindingMode.ALL,
|
||||
Main.KeybindingMode.ALL,
|
||||
Lang.bind(this, this._switchInputSource));
|
||||
this._keybindingActionBackward =
|
||||
Main.wm.addKeybinding('switch-input-source-backward',
|
||||
new Gio.Settings({ schema: "org.gnome.desktop.wm.keybindings" }),
|
||||
Meta.KeyBindingFlags.REVERSES |
|
||||
Meta.KeyBindingFlags.REVERSED,
|
||||
Shell.KeyBindingMode.ALL,
|
||||
Main.KeybindingMode.ALL,
|
||||
Lang.bind(this, this._switchInputSource));
|
||||
this._settings = new Gio.Settings({ schema: DESKTOP_INPUT_SOURCES_SCHEMA });
|
||||
this._settings.connect('changed::' + KEY_CURRENT_INPUT_SOURCE, Lang.bind(this, this._currentInputSourceChanged));
|
||||
@ -370,14 +365,7 @@ const InputSourceIndicator = new Lang.Class({
|
||||
Main.sessionMode.connect('updated', Lang.bind(this, this._sessionUpdated));
|
||||
this._sessionUpdated();
|
||||
|
||||
this.menu.addSettingsAction(_("Region & Language Settings"), 'gnome-region-panel.desktop');
|
||||
|
||||
this._sourcesPerWindow = false;
|
||||
this._focusWindowNotifyId = 0;
|
||||
this._overviewShowingId = 0;
|
||||
this._overviewHiddenId = 0;
|
||||
this._settings.connect('changed::per-window', Lang.bind(this, this._sourcesPerWindowChanged));
|
||||
this._sourcesPerWindowChanged();
|
||||
this.menu.addSettingsAction(_("Region and Language Settings"), 'gnome-region-panel.desktop');
|
||||
},
|
||||
|
||||
_sessionUpdated: function() {
|
||||
@ -398,9 +386,6 @@ const InputSourceIndicator = new Lang.Class({
|
||||
},
|
||||
|
||||
_switchInputSource: function(display, screen, window, binding) {
|
||||
if (this._mruSources.length < 2)
|
||||
return;
|
||||
|
||||
let popup = new InputSourcePopup(this._mruSources, this._keybindingAction, this._keybindingActionBackward);
|
||||
let modifiers = binding.get_modifiers();
|
||||
let backwards = modifiers & Meta.VirtualModifier.SHIFT_MASK;
|
||||
@ -413,9 +398,6 @@ const InputSourceIndicator = new Lang.Class({
|
||||
let newSourceIndex = this._settings.get_uint(KEY_CURRENT_INPUT_SOURCE);
|
||||
let newSource = this._inputSources[newSourceIndex];
|
||||
|
||||
let oldSource;
|
||||
[oldSource, this._currentSource] = [this._currentSource, newSource];
|
||||
|
||||
if (!newSource || (nVisibleSources < 2 && !newSource.properties)) {
|
||||
// This source index might be invalid if we weren't able
|
||||
// to build a menu item for it, so we hide ourselves since
|
||||
@ -430,13 +412,16 @@ const InputSourceIndicator = new Lang.Class({
|
||||
|
||||
this.actor.show();
|
||||
|
||||
let oldSource;
|
||||
[oldSource, this._currentSource] = [this._currentSource, newSource];
|
||||
|
||||
if (oldSource) {
|
||||
oldSource.menuItem.setShowDot(false);
|
||||
oldSource.indicatorLabel.hide();
|
||||
this._container.set_skip_paint(oldSource.indicatorLabel, true);
|
||||
}
|
||||
|
||||
newSource.menuItem.setShowDot(true);
|
||||
newSource.indicatorLabel.show();
|
||||
this._container.set_skip_paint(newSource.indicatorLabel, false);
|
||||
|
||||
this._buildPropSection(newSource.properties);
|
||||
|
||||
@ -446,8 +431,6 @@ const InputSourceIndicator = new Lang.Class({
|
||||
this._mruSources = currentSource.concat(this._mruSources);
|
||||
break;
|
||||
}
|
||||
|
||||
this._changePerWindowSource();
|
||||
},
|
||||
|
||||
_inputSourcesChanged: function() {
|
||||
@ -487,8 +470,6 @@ const InputSourceIndicator = new Lang.Class({
|
||||
let is = new InputSource(type, id, displayName, shortName, i);
|
||||
|
||||
is.connect('activate', Lang.bind(this, function() {
|
||||
if (this._currentSource.index == is.index)
|
||||
return;
|
||||
this._settings.set_value(KEY_CURRENT_INPUT_SOURCE,
|
||||
GLib.Variant.new_uint32(is.index));
|
||||
}));
|
||||
@ -513,8 +494,8 @@ const InputSourceIndicator = new Lang.Class({
|
||||
|
||||
this.menu.addMenuItem(is.menuItem, menuIndex++);
|
||||
|
||||
is.indicatorLabel.hide();
|
||||
this._container.add_actor(is.indicatorLabel);
|
||||
this._container.set_skip_paint(is.indicatorLabel, true);
|
||||
}
|
||||
|
||||
let sourcesList = [];
|
||||
@ -721,82 +702,6 @@ const InputSourceIndicator = new Lang.Class({
|
||||
}
|
||||
},
|
||||
|
||||
_getNewInputSource: function(current) {
|
||||
for (let i in this._inputSources) {
|
||||
let is = this._inputSources[i];
|
||||
if (is.type == current.type &&
|
||||
is.id == current.id)
|
||||
return is;
|
||||
}
|
||||
return this._currentSource;
|
||||
},
|
||||
|
||||
_getCurrentWindow: function() {
|
||||
if (Main.overview.visible)
|
||||
return Main.overview;
|
||||
else
|
||||
return global.display.focus_window;
|
||||
},
|
||||
|
||||
_setPerWindowInputSource: function() {
|
||||
let window = this._getCurrentWindow();
|
||||
if (!window)
|
||||
return;
|
||||
|
||||
if (!window._inputSources) {
|
||||
window._inputSources = this._inputSources;
|
||||
window._currentSource = this._currentSource;
|
||||
} else if (window._inputSources == this._inputSources) {
|
||||
window._currentSource.activate();
|
||||
} else {
|
||||
window._inputSources = this._inputSources;
|
||||
window._currentSource = this._getNewInputSource(window._currentSource);
|
||||
window._currentSource.activate();
|
||||
}
|
||||
},
|
||||
|
||||
_sourcesPerWindowChanged: function() {
|
||||
this._sourcesPerWindow = this._settings.get_boolean('per-window');
|
||||
|
||||
if (this._sourcesPerWindow && this._focusWindowNotifyId == 0) {
|
||||
this._focusWindowNotifyId = global.display.connect('notify::focus-window',
|
||||
Lang.bind(this, this._setPerWindowInputSource));
|
||||
this._overviewShowingId = Main.overview.connect('showing',
|
||||
Lang.bind(this, this._setPerWindowInputSource));
|
||||
this._overviewHiddenId = Main.overview.connect('hidden',
|
||||
Lang.bind(this, this._setPerWindowInputSource));
|
||||
} else if (!this._sourcesPerWindow && this._focusWindowNotifyId != 0) {
|
||||
global.display.disconnect(this._focusWindowNotifyId);
|
||||
this._focusWindowNotifyId = 0;
|
||||
Main.overview.disconnect(this._overviewShowingId);
|
||||
this._overviewShowingId = 0;
|
||||
Main.overview.disconnect(this._overviewHiddenId);
|
||||
this._overviewHiddenId = 0;
|
||||
|
||||
let windows = global.get_window_actors().map(function(w) {
|
||||
return w.meta_window;
|
||||
});
|
||||
for (let i = 0; i < windows.length; ++i) {
|
||||
delete windows[i]._inputSources;
|
||||
delete windows[i]._currentSource;
|
||||
}
|
||||
delete Main.overview._inputSources;
|
||||
delete Main.overview._currentSource;
|
||||
}
|
||||
},
|
||||
|
||||
_changePerWindowSource: function() {
|
||||
if (!this._sourcesPerWindow)
|
||||
return;
|
||||
|
||||
let window = this._getCurrentWindow();
|
||||
if (!window)
|
||||
return;
|
||||
|
||||
window._inputSources = this._inputSources;
|
||||
window._currentSource = this._currentSource;
|
||||
},
|
||||
|
||||
_containerGetPreferredWidth: function(container, for_height, alloc) {
|
||||
// Here, and in _containerGetPreferredHeight, we need to query
|
||||
// for the height of all children, but we ignore the results
|
||||
|
@ -10,31 +10,6 @@ const PanelMenu = imports.ui.panelMenu;
|
||||
const PopupMenu = imports.ui.popupMenu;
|
||||
const VolumeMenu = imports.ui.status.volume;
|
||||
|
||||
const FakeStatusIcon = new Lang.Class({
|
||||
Name: 'FakeStatusIcon',
|
||||
|
||||
_init: function(button) {
|
||||
this.actor = new St.BoxLayout({ style_class: 'panel-status-button-box' });
|
||||
this._button = button;
|
||||
this._button.connect('icons-updated', Lang.bind(this, this._reconstructIcons));
|
||||
this._button.actor.bind_property('visible', this.actor, 'visible',
|
||||
GObject.BindingFlags.SYNC_CREATE);
|
||||
this._reconstructIcons();
|
||||
},
|
||||
|
||||
_reconstructIcons: function() {
|
||||
this.actor.destroy_all_children();
|
||||
this._button.icons.forEach(Lang.bind(this, function(icon) {
|
||||
let newIcon = new St.Icon({ style_class: 'system-status-icon' });
|
||||
icon.bind_property('gicon', newIcon, 'gicon',
|
||||
GObject.BindingFlags.SYNC_CREATE);
|
||||
icon.bind_property('visible', newIcon, 'visible',
|
||||
GObject.BindingFlags.SYNC_CREATE);
|
||||
this.actor.add_actor(newIcon);
|
||||
}));
|
||||
}
|
||||
});
|
||||
|
||||
const Indicator = new Lang.Class({
|
||||
Name: 'LockScreenMenuIndicator',
|
||||
Extends: PanelMenu.SystemStatusButton,
|
||||
@ -43,20 +18,41 @@ const Indicator = new Lang.Class({
|
||||
this.parent(null, _("Volume, network, battery"));
|
||||
this._box.style_class = 'lock-screen-status-button-box';
|
||||
|
||||
this._volume = Main.panel.statusArea.volume;
|
||||
if (this._volume) {
|
||||
this._volumeIcon = this.addIcon(null);
|
||||
this._volume.mainIcon.bind_property('gicon', this._volumeIcon, 'gicon',
|
||||
GObject.BindingFlags.SYNC_CREATE);
|
||||
this._volume.mainIcon.bind_property('visible', this._volumeIcon, 'visible',
|
||||
GObject.BindingFlags.SYNC_CREATE);
|
||||
|
||||
this._volumeControl = VolumeMenu.getMixerControl();
|
||||
this._volumeMenu = new VolumeMenu.VolumeMenu(this._volumeControl);
|
||||
this.menu.addMenuItem(this._volumeMenu);
|
||||
|
||||
this._volume = new FakeStatusIcon(Main.panel.statusArea.volume);
|
||||
this._box.add_child(this._volume.actor);
|
||||
|
||||
// Network may not exist if the user doesn't have NetworkManager
|
||||
if (Main.panel.statusArea.network) {
|
||||
this._network = new FakeStatusIcon(Main.panel.statusArea.network);
|
||||
this._box.add_child(this._network.actor);
|
||||
}
|
||||
|
||||
this._battery = new FakeStatusIcon(Main.panel.statusArea.battery);
|
||||
this._box.add_child(this._battery.actor);
|
||||
this._network = Main.panel.statusArea.network;
|
||||
if (this._network) {
|
||||
this._networkIcon = this.addIcon(null);
|
||||
this._network.mainIcon.bind_property('gicon', this._networkIcon, 'gicon',
|
||||
GObject.BindingFlags.SYNC_CREATE);
|
||||
this._network.mainIcon.bind_property('visible', this._networkIcon, 'visible',
|
||||
GObject.BindingFlags.SYNC_CREATE);
|
||||
|
||||
this._networkSecondaryIcon = this.addIcon(null);
|
||||
this._network.secondaryIcon.bind_property('gicon', this._networkSecondaryIcon, 'gicon',
|
||||
GObject.BindingFlags.SYNC_CREATE);
|
||||
this._network.secondaryIcon.bind_property('visible', this._networkSecondaryIcon, 'visible',
|
||||
GObject.BindingFlags.SYNC_CREATE);
|
||||
}
|
||||
|
||||
this._battery = Main.panel.statusArea.battery;
|
||||
if (this._battery) {
|
||||
this._batteryIcon = this.addIcon(null);
|
||||
this._battery.mainIcon.bind_property('gicon', this._batteryIcon, 'gicon',
|
||||
GObject.BindingFlags.SYNC_CREATE);
|
||||
this._battery.mainIcon.bind_property('visible', this._batteryIcon, 'visible',
|
||||
GObject.BindingFlags.SYNC_CREATE);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -8,26 +8,16 @@ const NMClient = imports.gi.NMClient;
|
||||
const Signals = imports.signals;
|
||||
const St = imports.gi.St;
|
||||
|
||||
// Some of the new code depends on as-yet-unreleased NM
|
||||
var NMGtk;
|
||||
try {
|
||||
NMGtk = imports.gi.NMGtk;
|
||||
} catch(e) {
|
||||
NMGtk = null;
|
||||
}
|
||||
|
||||
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 ModemManager = imports.misc.modemManager;
|
||||
const Util = imports.misc.util;
|
||||
|
||||
const NMConnectionCategory = {
|
||||
INVALID: 'invalid',
|
||||
WIRED: 'wired',
|
||||
VIRTUAL: 'virtual',
|
||||
WIRELESS: 'wireless',
|
||||
WWAN: 'wwan',
|
||||
VPN: 'vpn'
|
||||
@ -49,7 +39,7 @@ const NM80211ApFlags = NetworkManager['80211ApFlags'];
|
||||
const NM80211ApSecurityFlags = NetworkManager['80211ApSecurityFlags'];
|
||||
|
||||
// number of wireless networks that should be visible
|
||||
// (the remaining are placed into More…)
|
||||
// (the remaining are placed into More...)
|
||||
const NUM_VISIBLE_NETWORKS = 5;
|
||||
|
||||
function macToArray(string) {
|
||||
@ -149,6 +139,46 @@ const NMNetworkMenuItem = new Lang.Class({
|
||||
}
|
||||
});
|
||||
|
||||
const NMWiredSectionTitleMenuItem = new Lang.Class({
|
||||
Name: 'NMWiredSectionTitleMenuItem',
|
||||
Extends: PopupMenu.PopupSwitchMenuItem,
|
||||
|
||||
_init: function(label, params) {
|
||||
params = params || { };
|
||||
params.style_class = 'popup-subtitle-menu-item';
|
||||
this.parent(label, false, params);
|
||||
},
|
||||
|
||||
updateForDevice: function(device) {
|
||||
if (device) {
|
||||
this._device = device;
|
||||
this.setStatus(device.getStatusLabel());
|
||||
this.setToggleState(device.connected);
|
||||
} else
|
||||
this.setStatus('');
|
||||
},
|
||||
|
||||
activate: function(event) {
|
||||
this.parent(event);
|
||||
|
||||
if (!this._device) {
|
||||
log('Section title activated when there is more than one device, should be non reactive');
|
||||
return;
|
||||
}
|
||||
|
||||
let newState = this._switch.state;
|
||||
|
||||
let ok;
|
||||
if (newState)
|
||||
ok = this._device.activate();
|
||||
else
|
||||
ok = this._device.deactivate();
|
||||
|
||||
if (!ok)
|
||||
this._switch.setToggleState(false);
|
||||
}
|
||||
});
|
||||
|
||||
const NMWirelessSectionTitleMenuItem = new Lang.Class({
|
||||
Name: 'NMWirelessSectionTitleMenuItem',
|
||||
Extends: PopupMenu.PopupSwitchMenuItem,
|
||||
@ -309,16 +339,19 @@ const NMDevice = new Lang.Class({
|
||||
Extends: NMConnectionBased,
|
||||
|
||||
_init: function(client, device, connections) {
|
||||
this._client = client;
|
||||
this._setDevice(device);
|
||||
this.parent(connections);
|
||||
this.device = device;
|
||||
this.device._delegate = this;
|
||||
this._stateChangedId = this.device.connect('state-changed', Lang.bind(this, this._deviceStateChanged));
|
||||
|
||||
// protected
|
||||
this._client = client;
|
||||
this.parent(connections);
|
||||
this._activeConnection = null;
|
||||
this._activeConnectionItem = null;
|
||||
this._autoConnectionItem = null;
|
||||
this._overflowItem = null;
|
||||
|
||||
this.statusItem = new PopupMenu.PopupSwitchMenuItem('', this.connected, { style_class: 'popup-subtitle-menu-item' });
|
||||
this.statusItem = new PopupMenu.PopupSwitchMenuItem(this._getDescription(), this.connected, { style_class: 'popup-subtitle-menu-item' });
|
||||
this._statusChanged = this.statusItem.connect('toggled', Lang.bind(this, function(item, state) {
|
||||
let ok;
|
||||
if (state)
|
||||
@ -337,26 +370,7 @@ const NMDevice = new Lang.Class({
|
||||
},
|
||||
|
||||
destroy: function() {
|
||||
this._setDevice(null);
|
||||
|
||||
if (this._deferredWorkId) {
|
||||
// Just clear out, the actual removal is handled when the
|
||||
// actor is destroyed
|
||||
this._deferredWorkId = 0;
|
||||
}
|
||||
|
||||
this._clearSection();
|
||||
if (this.statusItem)
|
||||
this.statusItem.destroy();
|
||||
this.section.destroy();
|
||||
},
|
||||
|
||||
_setDevice: function(device) {
|
||||
if (device) {
|
||||
this.device = device;
|
||||
this.device._delegate = this;
|
||||
this._stateChangedId = this.device.connect('state-changed', Lang.bind(this, this._deviceStateChanged));
|
||||
} else if (this.device) {
|
||||
if (this.device)
|
||||
this.device._delegate = null;
|
||||
|
||||
if (this._stateChangedId) {
|
||||
@ -366,6 +380,7 @@ const NMDevice = new Lang.Class({
|
||||
this._stateChangedId = 0;
|
||||
}
|
||||
if (this._carrierChangedId) {
|
||||
// see above for why this is needed
|
||||
GObject.Object.prototype.disconnect.call(this.device, this._carrierChangedId);
|
||||
this._carrierChangedId = 0;
|
||||
}
|
||||
@ -374,8 +389,10 @@ const NMDevice = new Lang.Class({
|
||||
this._firmwareChangedId = 0;
|
||||
}
|
||||
|
||||
this.device = null;
|
||||
}
|
||||
this._clearSection();
|
||||
if (this.statusItem)
|
||||
this.statusItem.destroy();
|
||||
this.section.destroy();
|
||||
},
|
||||
|
||||
deactivate: function() {
|
||||
@ -392,7 +409,7 @@ const NMDevice = new Lang.Class({
|
||||
// Otherwise, if no connection is currently configured,
|
||||
// try automatic configuration (or summon the config dialog)
|
||||
if (this._connections.length == 1) {
|
||||
this._client.activate_connection(this._connections[0].connection, this.device || null, null, null);
|
||||
this._client.activate_connection(this._connections[0].connection, this.device, null, null);
|
||||
return true;
|
||||
} else if (this._connections.length == 0) {
|
||||
return this._activateAutomaticConnection();
|
||||
@ -412,7 +429,7 @@ const NMDevice = new Lang.Class({
|
||||
},
|
||||
|
||||
get connected() {
|
||||
return this.device && this.device.state == NetworkManager.DeviceState.ACTIVATED;
|
||||
return this.device.state == NetworkManager.DeviceState.ACTIVATED;
|
||||
},
|
||||
|
||||
clearActiveConnection: function(activeConnection) {
|
||||
@ -432,6 +449,7 @@ const NMDevice = new Lang.Class({
|
||||
|
||||
this._activeConnection = activeConnection;
|
||||
|
||||
this._clearSection();
|
||||
this._queueCreateSection();
|
||||
},
|
||||
|
||||
@ -445,9 +463,6 @@ const NMDevice = new Lang.Class({
|
||||
},
|
||||
|
||||
getStatusLabel: function() {
|
||||
if (!this.device)
|
||||
return null;
|
||||
|
||||
switch(this.device.state) {
|
||||
case NetworkManager.DeviceState.DISCONNECTED:
|
||||
case NetworkManager.DeviceState.ACTIVATED:
|
||||
@ -497,21 +512,14 @@ const NMDevice = new Lang.Class({
|
||||
}
|
||||
},
|
||||
|
||||
syncDescription: function() {
|
||||
if (this.device && this.device._description)
|
||||
this.statusItem.label.text = this.device._description;
|
||||
},
|
||||
|
||||
// protected
|
||||
_createAutomaticConnection: function() {
|
||||
throw new TypeError('Invoking pure virtual function NMDevice.createAutomaticConnection');
|
||||
},
|
||||
|
||||
_queueCreateSection: function() {
|
||||
if (this._deferredWorkId) {
|
||||
this._clearSection();
|
||||
Main.queueDeferredWork(this._deferredWorkId);
|
||||
}
|
||||
},
|
||||
|
||||
_clearSection: function() {
|
||||
@ -549,7 +557,7 @@ const NMDevice = new Lang.Class({
|
||||
|
||||
if (j + activeOffset >= NUM_VISIBLE_NETWORKS) {
|
||||
if (!this._overflowItem) {
|
||||
this._overflowItem = new PopupMenu.PopupSubMenuMenuItem(_("More…"));
|
||||
this._overflowItem = new PopupMenu.PopupSubMenuMenuItem(_("More..."));
|
||||
this.section.addMenuItem(this._overflowItem);
|
||||
}
|
||||
this._overflowItem.menu.addMenuItem(obj.item);
|
||||
@ -611,6 +619,7 @@ const NMDevice = new Lang.Class({
|
||||
|
||||
this._updateStatusItem();
|
||||
|
||||
this._clearSection();
|
||||
this._queueCreateSection();
|
||||
this.emit('state-changed');
|
||||
},
|
||||
@ -634,6 +643,25 @@ const NMDevice = new Lang.Class({
|
||||
this.statusItem.setStatus(this.getStatusLabel());
|
||||
|
||||
this.emit('state-changed');
|
||||
},
|
||||
|
||||
_getDescription: function() {
|
||||
let dev_product = this.device.get_product();
|
||||
let dev_vendor = this.device.get_vendor();
|
||||
if (!dev_product || !dev_vendor)
|
||||
return '';
|
||||
|
||||
let product = Util.fixupPCIDescription(dev_product);
|
||||
let vendor = Util.fixupPCIDescription(dev_vendor);
|
||||
let out = '';
|
||||
|
||||
// Another quick hack; if all of the fixed up vendor string
|
||||
// is found in product, ignore the vendor.
|
||||
if (product.indexOf(vendor) == -1)
|
||||
out += vendor + ' ';
|
||||
out += product;
|
||||
|
||||
return out;
|
||||
}
|
||||
});
|
||||
|
||||
@ -664,7 +692,6 @@ const NMDeviceWired = new Lang.Class({
|
||||
Extends: NMDeviceSimple,
|
||||
|
||||
_init: function(client, device, connections) {
|
||||
device._description = _("Wired");
|
||||
this._autoConnectionName = _("Auto Ethernet");
|
||||
this.category = NMConnectionCategory.WIRED;
|
||||
|
||||
@ -692,24 +719,12 @@ const NMDeviceModem = new Lang.Class({
|
||||
_init: function(client, device, connections) {
|
||||
let is_wwan = false;
|
||||
|
||||
device._description = _("Mobile broadband");
|
||||
this._enabled = true;
|
||||
this.mobileDevice = null;
|
||||
this._connectionType = 'ppp';
|
||||
|
||||
this._capabilities = device.current_capabilities;
|
||||
// Support new ModemManager1 devices
|
||||
if (device.udi.indexOf('/org/freedesktop/ModemManager1/Modem') == 0) {
|
||||
is_wwan = true;
|
||||
this.mobileDevice = new ModemManager.BroadbandModem(device.udi, device.current_capabilities);
|
||||
if (this._capabilities & NetworkManager.DeviceModemCapabilities.GSM_UMTS) {
|
||||
this._connectionType = NetworkManager.SETTING_GSM_SETTING_NAME;
|
||||
} else if (this._capabilities & NetworkManager.DeviceModemCapabilities.LTE) {
|
||||
this._connectionType = NetworkManager.SETTING_GSM_SETTING_NAME;
|
||||
} else if (this._capabilities & NetworkManager.DeviceModemCapabilities.CDMA_EVDO) {
|
||||
this._connectionType = NetworkManager.SETTING_CDMA_SETTING_NAME;
|
||||
}
|
||||
} else if (this._capabilities & NetworkManager.DeviceModemCapabilities.GSM_UMTS) {
|
||||
is_wwan = true;
|
||||
this.mobileDevice = new ModemManager.ModemGsm(device.udi);
|
||||
this._connectionType = NetworkManager.SETTING_GSM_SETTING_NAME;
|
||||
@ -719,8 +734,7 @@ const NMDeviceModem = new Lang.Class({
|
||||
this._connectionType = NetworkManager.SETTING_CDMA_SETTING_NAME;
|
||||
} else if (this._capabilities & NetworkManager.DeviceModemCapabilities.LTE) {
|
||||
is_wwan = true;
|
||||
this.mobileDevice = new ModemManager.ModemGsm(device.udi);
|
||||
this._connectionType = NetworkManager.SETTING_GSM_SETTING_NAME;
|
||||
// FIXME: support signal quality
|
||||
}
|
||||
|
||||
if (is_wwan) {
|
||||
@ -823,7 +837,6 @@ const NMDeviceBluetooth = new Lang.Class({
|
||||
Extends: NMDevice,
|
||||
|
||||
_init: function(client, device, connections) {
|
||||
device._description = _("Bluetooth");
|
||||
this._autoConnectionName = this._makeConnectionName(device);
|
||||
device.connect('notify::name', Lang.bind(this, this._updateAutoConnectionName));
|
||||
|
||||
@ -866,8 +879,13 @@ const NMDeviceBluetooth = new Lang.Class({
|
||||
_updateAutoConnectionName: function() {
|
||||
this._autoConnectionName = this._makeConnectionName(this.device);
|
||||
|
||||
this._clearSection();
|
||||
this._queueCreateSection();
|
||||
this._updateStatusItem();
|
||||
},
|
||||
|
||||
_getDescription: function() {
|
||||
return this.device.name || _("Bluetooth");
|
||||
}
|
||||
});
|
||||
|
||||
@ -1127,8 +1145,10 @@ const NMDeviceWireless = new Lang.Class({
|
||||
this._networks.splice(res.network, 1);
|
||||
let newPos = Util.insertSorted(this._networks, network, Lang.bind(this, this._networkSortFunction));
|
||||
|
||||
if (newPos != res.network)
|
||||
if (newPos != res.network) {
|
||||
this._clearSection();
|
||||
this._queueCreateSection();
|
||||
}
|
||||
},
|
||||
|
||||
_accessPointAdded: function(device, accessPoint) {
|
||||
@ -1181,8 +1201,10 @@ const NMDeviceWireless = new Lang.Class({
|
||||
let newPos = Util.insertSorted(this._networks, apObj, this._networkSortFunction);
|
||||
|
||||
// Queue an update of the UI if we changed the order
|
||||
if (newPos != pos)
|
||||
if (newPos != pos) {
|
||||
this._clearSection();
|
||||
this._queueCreateSection();
|
||||
}
|
||||
},
|
||||
|
||||
_accessPointRemoved: function(device, accessPoint) {
|
||||
@ -1242,11 +1264,13 @@ const NMDeviceWireless = new Lang.Class({
|
||||
if (res.network < this._networks.length-1)
|
||||
okNext = this._networkSortFunction(this._networks[res.network + 1], apObj) <= 0;
|
||||
|
||||
if (!okPrev || !okNext)
|
||||
if (!okPrev || !okNext) {
|
||||
this._clearSection();
|
||||
this._queueCreateSection();
|
||||
else if (apObj.item)
|
||||
} else if (apObj.item) {
|
||||
apObj.item.updateBestAP(apObj.accessPoints[0]);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
_createAPItem: function(connection, accessPointObj, useConnectionName) {
|
||||
@ -1321,6 +1345,7 @@ const NMDeviceWireless = new Lang.Class({
|
||||
|
||||
if (forceupdate) {
|
||||
this._networks.sort(this._networkSortFunction);
|
||||
this._clearSection();
|
||||
this._queueCreateSection();
|
||||
}
|
||||
},
|
||||
@ -1353,6 +1378,7 @@ const NMDeviceWireless = new Lang.Class({
|
||||
|
||||
if (forceupdate) {
|
||||
this._networks.sort(this._networkSortFunction);
|
||||
this._clearSection();
|
||||
this._queueCreateSection();
|
||||
}
|
||||
},
|
||||
@ -1432,7 +1458,7 @@ const NMDeviceWireless = new Lang.Class({
|
||||
this.section.addMenuItem(apObj.item, position);
|
||||
} else {
|
||||
if (!this._overflowItem) {
|
||||
this._overflowItem = new PopupMenu.PopupSubMenuMenuItem(_("More…"));
|
||||
this._overflowItem = new PopupMenu.PopupSubMenuMenuItem(_("More..."));
|
||||
this.section.addMenuItem(this._overflowItem);
|
||||
}
|
||||
this._overflowItem.menu.addMenuItem(apObj.item, position - NUM_VISIBLE_NETWORKS);
|
||||
@ -1463,56 +1489,6 @@ const NMDeviceWireless = new Lang.Class({
|
||||
},
|
||||
});
|
||||
|
||||
const NMDeviceVirtual = new Lang.Class({
|
||||
Name: 'NMDeviceVirtual',
|
||||
Extends: NMDeviceSimple,
|
||||
|
||||
_init: function(client, iface, connections) {
|
||||
this.iface = iface;
|
||||
this.parent(client, null, connections);
|
||||
this.category = NMConnectionCategory.VIRTUAL;
|
||||
},
|
||||
|
||||
_shouldShowConnectionList: function() {
|
||||
return this.hasConnections();
|
||||
},
|
||||
|
||||
connectionValid: function(connection) {
|
||||
return connection.get_virtual_iface_name() == this.iface;
|
||||
},
|
||||
|
||||
addConnection: function(connection) {
|
||||
if (!this.device && !this.hasConnections())
|
||||
this.statusItem.label.text = NMGtk.utils_get_connection_device_name(connection);
|
||||
|
||||
this.parent(connection);
|
||||
},
|
||||
|
||||
adoptDevice: function(device) {
|
||||
if (device.get_iface() == this.iface) {
|
||||
this._setDevice(device);
|
||||
if (device._description)
|
||||
this.syncDescription();
|
||||
this._updateStatusItem();
|
||||
this.emit('state-changed');
|
||||
return true;
|
||||
} else
|
||||
return false;
|
||||
},
|
||||
|
||||
removeDevice: function(device) {
|
||||
if (device == this.device) {
|
||||
this._setDevice(null);
|
||||
this._updateStatusItem();
|
||||
this.emit('state-changed');
|
||||
}
|
||||
},
|
||||
|
||||
hasConnections: function() {
|
||||
return this._connections.length != 0;
|
||||
}
|
||||
});
|
||||
|
||||
const NMVPNSection = new Lang.Class({
|
||||
Name: 'NMVPNSection',
|
||||
Extends: NMConnectionBased,
|
||||
@ -1624,7 +1600,7 @@ const NMVPNSection = new Lang.Class({
|
||||
|
||||
if (j >= NUM_VISIBLE_NETWORKS) {
|
||||
if (!this._overflowItem) {
|
||||
this._overflowItem = new PopupMenu.PopupSubMenuMenuItem(_("More…"));
|
||||
this._overflowItem = new PopupMenu.PopupSubMenuMenuItem(_("More..."));
|
||||
this.section.addMenuItem(this._overflowItem);
|
||||
}
|
||||
this._overflowItem.menu.addMenuItem(obj.item);
|
||||
@ -1669,59 +1645,7 @@ const NMApplet = new Lang.Class({
|
||||
this.secondaryIcon = this.addIcon(new Gio.ThemedIcon({ name: 'network-vpn-symbolic' }));
|
||||
this.secondaryIcon.hide();
|
||||
|
||||
// Device types
|
||||
this._dtypes = { };
|
||||
this._dtypes[NetworkManager.DeviceType.ETHERNET] = NMDeviceWired;
|
||||
this._dtypes[NetworkManager.DeviceType.WIFI] = NMDeviceWireless;
|
||||
this._dtypes[NetworkManager.DeviceType.MODEM] = NMDeviceModem;
|
||||
this._dtypes[NetworkManager.DeviceType.BT] = NMDeviceBluetooth;
|
||||
this._dtypes[NetworkManager.DeviceType.INFINIBAND] = NMDeviceSimple;
|
||||
// TODO: WiMax support
|
||||
|
||||
// Virtual device types
|
||||
this._vtypes = { };
|
||||
if (NMGtk) {
|
||||
this._vtypes[NetworkManager.SETTING_VLAN_SETTING_NAME] = NMDeviceVirtual;
|
||||
this._vtypes[NetworkManager.SETTING_BOND_SETTING_NAME] = NMDeviceVirtual;
|
||||
this._vtypes[NetworkManager.SETTING_BRIDGE_SETTING_NAME] = NMDeviceVirtual;
|
||||
}
|
||||
|
||||
// Connection types
|
||||
this._ctypes = { };
|
||||
this._ctypes[NetworkManager.SETTING_WIRELESS_SETTING_NAME] = NMConnectionCategory.WIRELESS;
|
||||
this._ctypes[NetworkManager.SETTING_WIRED_SETTING_NAME] = NMConnectionCategory.WIRED;
|
||||
this._ctypes[NetworkManager.SETTING_PPPOE_SETTING_NAME] = NMConnectionCategory.WIRED;
|
||||
this._ctypes[NetworkManager.SETTING_PPP_SETTING_NAME] = NMConnectionCategory.WIRED;
|
||||
this._ctypes[NetworkManager.SETTING_BLUETOOTH_SETTING_NAME] = NMConnectionCategory.WWAN;
|
||||
this._ctypes[NetworkManager.SETTING_CDMA_SETTING_NAME] = NMConnectionCategory.WWAN;
|
||||
this._ctypes[NetworkManager.SETTING_GSM_SETTING_NAME] = NMConnectionCategory.WWAN;
|
||||
this._ctypes[NetworkManager.SETTING_INFINIBAND_SETTING_NAME] = NMConnectionCategory.WIRED;
|
||||
if (NMGtk) {
|
||||
this._ctypes[NetworkManager.SETTING_VLAN_SETTING_NAME] = NMConnectionCategory.VIRTUAL;
|
||||
this._ctypes[NetworkManager.SETTING_BOND_SETTING_NAME] = NMConnectionCategory.VIRTUAL;
|
||||
this._ctypes[NetworkManager.SETTING_BRIDGE_SETTING_NAME] = NMConnectionCategory.VIRTUAL;
|
||||
}
|
||||
this._ctypes[NetworkManager.SETTING_VPN_SETTING_NAME] = NMConnectionCategory.VPN;
|
||||
|
||||
NMClient.Client.new_async(null, Lang.bind(this, this._clientGot));
|
||||
NMClient.RemoteSettings.new_async(null, null, Lang.bind(this, this._remoteSettingsGot));
|
||||
},
|
||||
|
||||
_clientGot: function(obj, result) {
|
||||
this._client = NMClient.Client.new_finish(result);
|
||||
|
||||
this._tryLateInit();
|
||||
},
|
||||
|
||||
_remoteSettingsGot: function(obj, result) {
|
||||
this._settings = NMClient.RemoteSettings.new_finish(result);
|
||||
|
||||
this._tryLateInit();
|
||||
},
|
||||
|
||||
_tryLateInit: function() {
|
||||
if (!this._client || !this._settings)
|
||||
return;
|
||||
this._client = NMClient.Client.new();
|
||||
|
||||
this._statusSection = new PopupMenu.PopupMenuSection();
|
||||
this._statusItem = new PopupMenu.PopupMenuItem('', { reactive: false });
|
||||
@ -1743,32 +1667,23 @@ const NMApplet = new Lang.Class({
|
||||
this._mobileUpdateId = 0;
|
||||
this._mobileUpdateDevice = null;
|
||||
|
||||
this._nmDevices = [];
|
||||
this._devices = { };
|
||||
this._virtualDevices = [ ];
|
||||
|
||||
this._devices.wired = {
|
||||
section: new PopupMenu.PopupMenuSection(),
|
||||
devices: [ ],
|
||||
item: new NMWiredSectionTitleMenuItem(_("Wired"))
|
||||
};
|
||||
|
||||
this._devices.wired.section.addMenuItem(this._devices.wired.item);
|
||||
this._devices.wired.section.actor.hide();
|
||||
this.menu.addMenuItem(this._devices.wired.section);
|
||||
this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
|
||||
|
||||
this._devices.virtual = {
|
||||
section: new PopupMenu.PopupMenuSection(),
|
||||
devices: [ ],
|
||||
};
|
||||
|
||||
this._devices.virtual.section.actor.hide();
|
||||
this.menu.addMenuItem(this._devices.virtual.section);
|
||||
this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
|
||||
|
||||
this._devices.wireless = {
|
||||
section: new PopupMenu.PopupMenuSection(),
|
||||
devices: [ ],
|
||||
item: this._makeToggleItem('wireless', _("Wi-Fi"))
|
||||
item: this._makeToggleItem('wireless', _("Wireless"))
|
||||
};
|
||||
this._devices.wireless.section.addMenuItem(this._devices.wireless.item);
|
||||
this._devices.wireless.section.actor.hide();
|
||||
@ -1778,7 +1693,9 @@ const NMApplet = new Lang.Class({
|
||||
this._devices.wwan = {
|
||||
section: new PopupMenu.PopupMenuSection(),
|
||||
devices: [ ],
|
||||
item: this._makeToggleItem('wwan', _("Mobile broadband"))
|
||||
};
|
||||
this._devices.wwan.section.addMenuItem(this._devices.wwan.item);
|
||||
this._devices.wwan.section.actor.hide();
|
||||
this.menu.addMenuItem(this._devices.wwan.section);
|
||||
this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
|
||||
@ -1789,10 +1706,37 @@ const NMApplet = new Lang.Class({
|
||||
this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
|
||||
this.menu.addSettingsAction(_("Network Settings"), 'gnome-network-panel.desktop');
|
||||
|
||||
// Device types
|
||||
this._dtypes = { };
|
||||
this._dtypes[NetworkManager.DeviceType.ETHERNET] = NMDeviceWired;
|
||||
this._dtypes[NetworkManager.DeviceType.WIFI] = NMDeviceWireless;
|
||||
this._dtypes[NetworkManager.DeviceType.MODEM] = NMDeviceModem;
|
||||
this._dtypes[NetworkManager.DeviceType.BT] = NMDeviceBluetooth;
|
||||
this._dtypes[NetworkManager.DeviceType.INFINIBAND] = NMDeviceSimple;
|
||||
// TODO: WiMax support
|
||||
|
||||
// Connection types
|
||||
this._ctypes = { };
|
||||
this._ctypes[NetworkManager.SETTING_WIRELESS_SETTING_NAME] = NMConnectionCategory.WIRELESS;
|
||||
this._ctypes[NetworkManager.SETTING_WIRED_SETTING_NAME] = NMConnectionCategory.WIRED;
|
||||
this._ctypes[NetworkManager.SETTING_PPPOE_SETTING_NAME] = NMConnectionCategory.WIRED;
|
||||
this._ctypes[NetworkManager.SETTING_PPP_SETTING_NAME] = NMConnectionCategory.WIRED;
|
||||
this._ctypes[NetworkManager.SETTING_BLUETOOTH_SETTING_NAME] = NMConnectionCategory.WWAN;
|
||||
this._ctypes[NetworkManager.SETTING_CDMA_SETTING_NAME] = NMConnectionCategory.WWAN;
|
||||
this._ctypes[NetworkManager.SETTING_GSM_SETTING_NAME] = NMConnectionCategory.WWAN;
|
||||
this._ctypes[NetworkManager.SETTING_INFINIBAND_SETTING_NAME] = NMConnectionCategory.WIRED;
|
||||
this._ctypes[NetworkManager.SETTING_VPN_SETTING_NAME] = NMConnectionCategory.VPN;
|
||||
|
||||
this._settings = NMClient.RemoteSettings.new(null);
|
||||
this._connectionsReadId = this._settings.connect('connections-read', Lang.bind(this, function() {
|
||||
this._readConnections();
|
||||
this._readDevices();
|
||||
this._syncNMState();
|
||||
|
||||
// Connect to signals late so that early signals don't find in inconsistent state
|
||||
// and connect only once (this signal handler can be called again if NetworkManager goes up and down)
|
||||
if (!this._inited) {
|
||||
this._inited = true;
|
||||
this._client.connect('notify::manager-running', Lang.bind(this, this._syncNMState));
|
||||
this._client.connect('notify::networking-enabled', Lang.bind(this, this._syncNMState));
|
||||
this._client.connect('notify::state', Lang.bind(this, this._syncNMState));
|
||||
@ -1800,13 +1744,14 @@ const NMApplet = new Lang.Class({
|
||||
this._client.connect('device-added', Lang.bind(this, this._deviceAdded));
|
||||
this._client.connect('device-removed', Lang.bind(this, this._deviceRemoved));
|
||||
this._settings.connect('new-connection', Lang.bind(this, this._newConnection));
|
||||
}
|
||||
}));
|
||||
},
|
||||
|
||||
_ensureSource: function() {
|
||||
if (!this._source) {
|
||||
this._source = new MessageTray.Source(_("Network Manager"),
|
||||
'network-transmit-receive');
|
||||
this._source.policy = new NotificationDaemon.NotificationApplicationPolicy('gnome-network-panel');
|
||||
|
||||
this._source.connect('destroy', Lang.bind(this, function() {
|
||||
this._source = null;
|
||||
@ -1831,22 +1776,10 @@ const NMApplet = new Lang.Class({
|
||||
let devices = this._devices[category].devices;
|
||||
let item = this._devices[category].item;
|
||||
let section = this._devices[category].section;
|
||||
|
||||
let visible;
|
||||
if (category == NMConnectionCategory.VIRTUAL)
|
||||
visible = !section.isEmpty();
|
||||
else
|
||||
visible = devices.length > 0;
|
||||
|
||||
if (!visible)
|
||||
if (devices.length == 0)
|
||||
section.actor.hide();
|
||||
else {
|
||||
section.actor.show();
|
||||
|
||||
// Sync the relation between the section title
|
||||
// item (the one with the airplane mode switch)
|
||||
// and the individual device switches
|
||||
if (item) {
|
||||
if (devices.length == 1) {
|
||||
let dev = devices[0];
|
||||
dev.statusItem.actor.hide();
|
||||
@ -1855,20 +1788,17 @@ const NMApplet = new Lang.Class({
|
||||
devices.forEach(function(dev) {
|
||||
dev.statusItem.actor.show();
|
||||
});
|
||||
|
||||
// remove status text from the section title item
|
||||
item.updateForDevice(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
_readDevices: function() {
|
||||
let devices = this._client.get_devices() || [ ];
|
||||
for (let i = 0; i < devices.length; ++i) {
|
||||
this._deviceAdded(this._client, devices[i], true);
|
||||
this._deviceAdded(this._client, devices[i]);
|
||||
}
|
||||
this._syncDeviceNames();
|
||||
},
|
||||
|
||||
_notifyForDevice: function(device, iconName, title, text, urgency) {
|
||||
@ -1899,50 +1829,9 @@ const NMApplet = new Lang.Class({
|
||||
MessageTray.Urgency.HIGH);
|
||||
},
|
||||
|
||||
_syncDeviceNames: function() {
|
||||
if (NMGtk) {
|
||||
let names = NMGtk.utils_disambiguate_device_names(this._nmDevices);
|
||||
for (let i = 0; i < this._nmDevices.length; i++) {
|
||||
let device = this._nmDevices[i];
|
||||
device._description = names[i];
|
||||
if (device._delegate)
|
||||
device._delegate.syncDescription();
|
||||
}
|
||||
} else {
|
||||
for (let i = 0; i < this._nmDevices.length; i++) {
|
||||
let device = this._nmDevices[i];
|
||||
device._delegate.syncDescription();
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
_deviceAdded: function(client, device, skipSyncDeviceNames) {
|
||||
if (device._delegate) {
|
||||
// already seen, not adding again
|
||||
return;
|
||||
}
|
||||
|
||||
for (let i = 0; i < this._virtualDevices.length; i++) {
|
||||
if (this._virtualDevices[i].adoptDevice(device)) {
|
||||
this._nmDevices.push(device);
|
||||
if (!skipSyncDeviceNames)
|
||||
this._syncDeviceNames();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
let wrapperClass = this._dtypes[device.get_device_type()];
|
||||
if (wrapperClass) {
|
||||
_makeWrapperDevice: function(wrapperClass, device) {
|
||||
let wrapper = new wrapperClass(this._client, device, this._connections);
|
||||
this._addDeviceWrapper(wrapper);
|
||||
|
||||
this._nmDevices.push(device);
|
||||
if (!skipSyncDeviceNames)
|
||||
this._syncDeviceNames();
|
||||
}
|
||||
},
|
||||
|
||||
_addDeviceWrapper: function(wrapper) {
|
||||
wrapper._activationFailedId = wrapper.connect('activation-failed',
|
||||
Lang.bind(this, this._onActivationFailed));
|
||||
wrapper._deviceStateChangedId = wrapper.connect('state-changed', Lang.bind(this, function(dev) {
|
||||
@ -1954,36 +1843,35 @@ const NMApplet = new Lang.Class({
|
||||
wrapper.disconnect(wrapper._destroyId);
|
||||
});
|
||||
|
||||
let section = this._devices[wrapper.category].section;
|
||||
section.addMenuItem(wrapper.statusItem);
|
||||
section.addMenuItem(wrapper.section);
|
||||
return wrapper;
|
||||
},
|
||||
|
||||
_deviceAdded: function(client, device) {
|
||||
if (device._delegate) {
|
||||
// already seen, not adding again
|
||||
return;
|
||||
}
|
||||
let wrapperClass = this._dtypes[device.get_device_type()];
|
||||
if (wrapperClass) {
|
||||
let wrapper = this._makeWrapperDevice(wrapperClass, device);
|
||||
let section = this._devices[wrapper.category].section;
|
||||
let devices = this._devices[wrapper.category].devices;
|
||||
|
||||
section.addMenuItem(wrapper.section, 1);
|
||||
section.addMenuItem(wrapper.statusItem, 1);
|
||||
devices.push(wrapper);
|
||||
|
||||
this._syncSectionTitle(wrapper.category);
|
||||
}
|
||||
},
|
||||
|
||||
_deviceRemoved: function(client, device) {
|
||||
let pos = this._nmDevices.indexOf(device);
|
||||
if (pos != -1) {
|
||||
this._nmDevices.splice(pos, 1);
|
||||
this._syncDeviceNames();
|
||||
}
|
||||
|
||||
let wrapper = device._delegate;
|
||||
if (!wrapper) {
|
||||
if (!device._delegate) {
|
||||
log('Removing a network device that was not added');
|
||||
return;
|
||||
}
|
||||
|
||||
if (wrapper instanceof NMDeviceVirtual)
|
||||
wrapper.removeDevice(device);
|
||||
else
|
||||
this._removeDeviceWrapper(wrapper);
|
||||
},
|
||||
|
||||
_removeDeviceWrapper: function(wrapper) {
|
||||
let wrapper = device._delegate;
|
||||
wrapper.destroy();
|
||||
|
||||
let devices = this._devices[wrapper.category].devices;
|
||||
@ -2184,13 +2072,6 @@ const NMApplet = new Lang.Class({
|
||||
devices[i].removeConnection(connection);
|
||||
}
|
||||
|
||||
if (section == NMConnectionCategory.VIRTUAL) {
|
||||
let iface = connection.get_virtual_iface_name();
|
||||
let wrapper = this._findVirtualDevice(iface);
|
||||
if (wrapper && !wrapper.hasConnections())
|
||||
this._removeDeviceWrapper(wrapper);
|
||||
}
|
||||
|
||||
connection.disconnect(connection._removedId);
|
||||
connection.disconnect(connection._updatedId);
|
||||
connection._removedId = connection._updatedId = 0;
|
||||
@ -2204,27 +2085,6 @@ const NMApplet = new Lang.Class({
|
||||
|
||||
let section = connection._section;
|
||||
|
||||
if (section == NMConnectionCategory.VIRTUAL) {
|
||||
let wrapperClass = this._vtypes[connection._type];
|
||||
if (!wrapperClass)
|
||||
return;
|
||||
|
||||
let iface = connection.get_virtual_iface_name();
|
||||
let wrapper = this._findVirtualDevice(iface);
|
||||
if (!wrapper) {
|
||||
wrapper = new wrapperClass(this._client, iface, this._connections);
|
||||
this._addDeviceWrapper(wrapper);
|
||||
this._virtualDevices.push(wrapper);
|
||||
|
||||
// We might already have a device for this connection
|
||||
for (let i = 0; i < this._nmDevices.length; i++) {
|
||||
let device = this._nmDevices[i];
|
||||
if (wrapper.adoptDevice(device))
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (section == NMConnectionCategory.INVALID)
|
||||
return;
|
||||
if (section == NMConnectionCategory.VPN) {
|
||||
@ -2237,15 +2097,6 @@ const NMApplet = new Lang.Class({
|
||||
}
|
||||
},
|
||||
|
||||
_findVirtualDevice: function(iface) {
|
||||
for (let i = 0; i < this._virtualDevices.length; i++) {
|
||||
if (this._virtualDevices[i].iface == iface)
|
||||
return this._virtualDevices[i];
|
||||
}
|
||||
|
||||
return null;
|
||||
},
|
||||
|
||||
_hideDevices: function() {
|
||||
this._devicesHidden = true;
|
||||
|
||||
@ -2261,7 +2112,6 @@ const NMApplet = new Lang.Class({
|
||||
this._statusSection.actor.hide();
|
||||
|
||||
this._syncSectionTitle(NMConnectionCategory.WIRED);
|
||||
this._syncSectionTitle(NMConnectionCategory.VIRTUAL);
|
||||
this._syncSectionTitle(NMConnectionCategory.WIRELESS);
|
||||
this._syncSectionTitle(NMConnectionCategory.WWAN);
|
||||
},
|
||||
@ -2299,7 +2149,6 @@ const NMApplet = new Lang.Class({
|
||||
this.setIcon('network-wireless-acquiring-symbolic');
|
||||
break;
|
||||
case NMConnectionCategory.WIRED:
|
||||
case NMConnectionCategory.VIRTUAL:
|
||||
this.setIcon('network-wired-acquiring-symbolic');
|
||||
break;
|
||||
default:
|
||||
@ -2339,7 +2188,6 @@ const NMApplet = new Lang.Class({
|
||||
break;
|
||||
}
|
||||
case NMConnectionCategory.WIRED:
|
||||
case NMConnectionCategory.VIRTUAL:
|
||||
this.setIcon('network-wired-symbolic');
|
||||
break;
|
||||
case NMConnectionCategory.WWAN:
|
||||
|
@ -7,7 +7,7 @@ const St = imports.gi.St;
|
||||
const PanelMenu = imports.ui.panelMenu;
|
||||
const PopupMenu = imports.ui.popupMenu;
|
||||
|
||||
const BUS_NAME = 'org.gnome.SettingsDaemon.Power';
|
||||
const BUS_NAME = 'org.gnome.SettingsDaemon';
|
||||
const OBJECT_PATH = '/org/gnome/SettingsDaemon/Power';
|
||||
|
||||
const UPDeviceType = {
|
||||
@ -54,23 +54,14 @@ const Indicator = new Lang.Class({
|
||||
_init: function() {
|
||||
this.parent('battery-missing-symbolic', _("Battery"));
|
||||
|
||||
this._proxy = new PowerManagerProxy(Gio.DBus.session, BUS_NAME, OBJECT_PATH,
|
||||
Lang.bind(this, function(proxy, error) {
|
||||
if (error) {
|
||||
log(error.message);
|
||||
return;
|
||||
}
|
||||
this._proxy.connect('g-properties-changed',
|
||||
Lang.bind(this, this._devicesChanged));
|
||||
this._devicesChanged();
|
||||
}));
|
||||
this._proxy = new PowerManagerProxy(Gio.DBus.session, BUS_NAME, OBJECT_PATH);
|
||||
|
||||
this._deviceItems = [ ];
|
||||
this._hasPrimary = false;
|
||||
this._primaryDeviceId = null;
|
||||
|
||||
this._batteryItem = new PopupMenu.PopupMenuItem('', { reactive: false });
|
||||
this._primaryPercentage = new St.Label({ style_class: 'popup-battery-percentage' });
|
||||
this._primaryPercentage = new St.Label();
|
||||
this._batteryItem.addActor(this._primaryPercentage, { align: St.Align.END });
|
||||
this.menu.addMenuItem(this._batteryItem);
|
||||
|
||||
@ -79,6 +70,10 @@ const Indicator = new Lang.Class({
|
||||
|
||||
this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
|
||||
this.menu.addSettingsAction(_("Power Settings"), 'gnome-power-panel.desktop');
|
||||
|
||||
this._proxy.connect('g-properties-changed',
|
||||
Lang.bind(this, this._devicesChanged));
|
||||
this._devicesChanged();
|
||||
},
|
||||
|
||||
_readPrimaryDevice: function() {
|
||||
@ -96,7 +91,7 @@ const Indicator = new Lang.Class({
|
||||
if (time == 0) {
|
||||
// 0 is reported when UPower does not have enough data
|
||||
// to estimate battery life
|
||||
this._batteryItem.label.text = _("Estimating…");
|
||||
this._batteryItem.label.text = _("Estimating...");
|
||||
} else {
|
||||
let minutes = time % 60;
|
||||
let hours = Math.floor(time / 60);
|
||||
@ -188,8 +183,7 @@ const DeviceItem = new Lang.Class({
|
||||
this._box.add_actor(this._label);
|
||||
this.addActor(this._box);
|
||||
|
||||
let percentLabel = new St.Label({ text: C_("percent of battery remaining", "%d%%").format(Math.round(percentage)),
|
||||
style_class: 'popup-battery-percentage' });
|
||||
let percentLabel = new St.Label({ text: C_("percent of battery remaining", "%d%%").format(Math.round(percentage)) });
|
||||
this.addActor(percentLabel, { align: St.Align.END });
|
||||
//FIXME: ideally we would like to expose this._label and percentLabel
|
||||
this.actor.label_actor = percentLabel;
|
||||
@ -198,9 +192,9 @@ const DeviceItem = new Lang.Class({
|
||||
_deviceTypeToString: function(type) {
|
||||
switch (type) {
|
||||
case UPDeviceType.AC_POWER:
|
||||
return _("AC Adapter");
|
||||
return _("AC adapter");
|
||||
case UPDeviceType.BATTERY:
|
||||
return _("Laptop Battery");
|
||||
return _("Laptop battery");
|
||||
case UPDeviceType.UPS:
|
||||
return _("UPS");
|
||||
case UPDeviceType.MONITOR:
|
||||
@ -212,9 +206,9 @@ const DeviceItem = new Lang.Class({
|
||||
case UPDeviceType.PDA:
|
||||
return _("PDA");
|
||||
case UPDeviceType.PHONE:
|
||||
return _("Cell Phone");
|
||||
return _("Cell phone");
|
||||
case UPDeviceType.MEDIA_PLAYER:
|
||||
return _("Media Player");
|
||||
return _("Media player");
|
||||
case UPDeviceType.TABLET:
|
||||
return _("Tablet");
|
||||
case UPDeviceType.COMPUTER:
|
||||
|
@ -5,7 +5,6 @@ const Lang = imports.lang;
|
||||
const Gio = imports.gi.Gio;
|
||||
const Gvc = imports.gi.Gvc;
|
||||
const St = imports.gi.St;
|
||||
const Signals = imports.signals;
|
||||
|
||||
const PanelMenu = imports.ui.panelMenu;
|
||||
const PopupMenu = imports.ui.popupMenu;
|
||||
@ -27,210 +26,6 @@ function getMixerControl() {
|
||||
return _mixerControl;
|
||||
}
|
||||
|
||||
const StreamSlider = new Lang.Class({
|
||||
Name: 'StreamSlider',
|
||||
|
||||
_init: function(control, title) {
|
||||
this._control = control;
|
||||
|
||||
this.item = new PopupMenu.PopupMenuSection();
|
||||
|
||||
this._title = new PopupMenu.PopupMenuItem(title, { reactive: false });
|
||||
this._slider = new PopupMenu.PopupSliderMenuItem(0);
|
||||
this._slider.connect('value-changed', Lang.bind(this, this._sliderChanged));
|
||||
this._slider.connect('drag-end', Lang.bind(this, this._notifyVolumeChange));
|
||||
|
||||
this.item.addMenuItem(this._title);
|
||||
this.item.addMenuItem(this._slider);
|
||||
|
||||
this._stream = null;
|
||||
this._shouldShow = true;
|
||||
},
|
||||
|
||||
get stream() {
|
||||
return this._stream;
|
||||
},
|
||||
|
||||
set stream(stream) {
|
||||
if (this._stream) {
|
||||
this._disconnectStream(this._stream);
|
||||
}
|
||||
|
||||
this._stream = stream;
|
||||
|
||||
if (this._stream) {
|
||||
this._connectStream(this._stream);
|
||||
this._updateVolume();
|
||||
} else {
|
||||
this.emit('stream-updated');
|
||||
}
|
||||
|
||||
this._updateVisibility();
|
||||
},
|
||||
|
||||
_disconnectStream: function(stream) {
|
||||
stream.disconnect(this._mutedChangedId);
|
||||
this._mutedChangedId = 0;
|
||||
stream.disconnect(this._volumeChangedId);
|
||||
this._volumeChangedId = 0;
|
||||
},
|
||||
|
||||
_connectStream: function(stream) {
|
||||
this._mutedChangedId = stream.connect('notify::is-muted', Lang.bind(this, this._updateVolume));
|
||||
this._volumeChangedId = stream.connect('notify::volume', Lang.bind(this, this._updateVolume));
|
||||
},
|
||||
|
||||
_shouldBeVisible: function() {
|
||||
return this._stream != null;
|
||||
},
|
||||
|
||||
_updateVisibility: function() {
|
||||
let visible = this._shouldBeVisible();
|
||||
this._title.actor.visible = visible;
|
||||
this._slider.actor.visible = visible;
|
||||
},
|
||||
|
||||
scroll: function(event) {
|
||||
this._slider.scroll(event);
|
||||
},
|
||||
|
||||
setValue: function(value) {
|
||||
// piggy-back off of sliderChanged
|
||||
this._slider.setValue(value);
|
||||
},
|
||||
|
||||
_sliderChanged: function(slider, value, property) {
|
||||
if (!this._stream)
|
||||
return;
|
||||
|
||||
let volume = value * this._control.get_vol_max_norm();
|
||||
let prevMuted = this._stream.is_muted;
|
||||
if (volume < 1) {
|
||||
this._stream.volume = 0;
|
||||
if (!prevMuted)
|
||||
this._stream.change_is_muted(true);
|
||||
} else {
|
||||
this._stream.volume = volume;
|
||||
if (prevMuted)
|
||||
this._stream.change_is_muted(false);
|
||||
}
|
||||
this._stream.push_volume();
|
||||
},
|
||||
|
||||
_notifyVolumeChange: function() {
|
||||
global.cancel_theme_sound(VOLUME_NOTIFY_ID);
|
||||
global.play_theme_sound(VOLUME_NOTIFY_ID,
|
||||
'audio-volume-change',
|
||||
_("Volume changed"),
|
||||
Clutter.get_current_event ());
|
||||
},
|
||||
|
||||
_updateVolume: function() {
|
||||
let muted = this._stream.is_muted;
|
||||
this._slider.setValue(muted ? 0 : (this._stream.volume / this._control.get_vol_max_norm()));
|
||||
this.emit('stream-updated');
|
||||
},
|
||||
|
||||
getIcon: function() {
|
||||
if (!this._stream)
|
||||
return null;
|
||||
|
||||
let volume = this._stream.volume;
|
||||
if (this._stream.is_muted || volume <= 0) {
|
||||
return 'audio-volume-muted-symbolic';
|
||||
} else {
|
||||
let n = Math.floor(3 * volume / this._control.get_vol_max_norm()) + 1;
|
||||
if (n < 2)
|
||||
return 'audio-volume-low-symbolic';
|
||||
if (n >= 3)
|
||||
return 'audio-volume-high-symbolic';
|
||||
return 'audio-volume-medium-symbolic';
|
||||
}
|
||||
}
|
||||
});
|
||||
Signals.addSignalMethods(StreamSlider.prototype);
|
||||
|
||||
const OutputStreamSlider = new Lang.Class({
|
||||
Name: 'OutputStreamSlider',
|
||||
Extends: StreamSlider,
|
||||
|
||||
_connectStream: function(stream) {
|
||||
this.parent(stream);
|
||||
this._portChangedId = stream.connect('notify::port', Lang.bind(this, this._portChanged));
|
||||
this._portChanged();
|
||||
},
|
||||
|
||||
_findHeadphones: function(sink) {
|
||||
// This only works for external headphones (e.g. bluetooth)
|
||||
if (sink.get_form_factor() == 'headset' ||
|
||||
sink.get_form_factor() == 'headphone')
|
||||
return true;
|
||||
|
||||
// a bit hackish, but ALSA/PulseAudio have a number
|
||||
// of different identifiers for headphones, and I could
|
||||
// not find the complete list
|
||||
if (sink.get_ports().length > 0)
|
||||
return sink.get_port().port.indexOf('headphone') >= 0;
|
||||
|
||||
return false;
|
||||
},
|
||||
|
||||
_disconnectStream: function(stream) {
|
||||
this.parent(stream);
|
||||
stream.disconnect(this._portChangedId);
|
||||
this._portChangedId = 0;
|
||||
},
|
||||
|
||||
_portChanged: function() {
|
||||
let hasHeadphones = this._findHeadphones(this._stream);
|
||||
if (hasHeadphones != this._hasHeadphones) {
|
||||
this._hasHeadphones = hasHeadphones;
|
||||
this.emit('headphones-changed', this._hasHeadphones);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const InputStreamSlider = new Lang.Class({
|
||||
Name: 'InputStreamSlider',
|
||||
Extends: StreamSlider,
|
||||
|
||||
_init: function(control, title) {
|
||||
this.parent(control, title);
|
||||
this._control.connect('stream-added', Lang.bind(this, this._maybeShowInput));
|
||||
this._control.connect('stream-removed', Lang.bind(this, this._maybeShowInput));
|
||||
},
|
||||
|
||||
_connectStream: function(stream) {
|
||||
this.parent(stream);
|
||||
this._maybeShowInput();
|
||||
},
|
||||
|
||||
_maybeShowInput: function() {
|
||||
// only show input widgets if any application is recording audio
|
||||
let showInput = false;
|
||||
let recordingApps = this._control.get_source_outputs();
|
||||
if (this._stream && recordingApps) {
|
||||
for (let i = 0; i < recordingApps.length; i++) {
|
||||
let outputStream = recordingApps[i];
|
||||
let id = outputStream.get_application_id();
|
||||
// but skip gnome-volume-control and pavucontrol
|
||||
// (that appear as recording because they show the input level)
|
||||
if (!id || (id != 'org.gnome.VolumeControl' && id != 'org.PulseAudio.pavucontrol')) {
|
||||
showInput = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this._showInput = showInput;
|
||||
this._updateVisibility();
|
||||
},
|
||||
|
||||
_shouldBeVisible: function() {
|
||||
return this.parent() && this._showInput;
|
||||
}
|
||||
});
|
||||
|
||||
const VolumeMenu = new Lang.Class({
|
||||
Name: 'VolumeMenu',
|
||||
Extends: PopupMenu.PopupMenuSection,
|
||||
@ -244,48 +39,207 @@ const VolumeMenu = new Lang.Class({
|
||||
this._control.connect('state-changed', Lang.bind(this, this._onControlStateChanged));
|
||||
this._control.connect('default-sink-changed', Lang.bind(this, this._readOutput));
|
||||
this._control.connect('default-source-changed', Lang.bind(this, this._readInput));
|
||||
this._control.connect('stream-added', Lang.bind(this, this._maybeShowInput));
|
||||
this._control.connect('stream-removed', Lang.bind(this, this._maybeShowInput));
|
||||
this._volumeMax = this._control.get_vol_max_norm();
|
||||
|
||||
this._output = null;
|
||||
this._outputVolumeId = 0;
|
||||
this._outputMutedId = 0;
|
||||
/* Translators: This is the label for audio volume */
|
||||
this._output = new OutputStreamSlider(this._control, _("Volume"));
|
||||
this._output.connect('stream-updated', Lang.bind(this, function() {
|
||||
this.emit('icon-changed');
|
||||
}));
|
||||
this._output.connect('headphones-changed', Lang.bind(this, function(stream, value) {
|
||||
this.emit('headphones-changed', value);
|
||||
}));
|
||||
this.addMenuItem(this._output.item);
|
||||
|
||||
this._input = new InputStreamSlider(this._control, _("Microphone"));
|
||||
this.addMenuItem(this._input.item);
|
||||
this._outputTitle = new PopupMenu.PopupMenuItem(_("Volume"), { reactive: false });
|
||||
this._outputSlider = new PopupMenu.PopupSliderMenuItem(0);
|
||||
this._outputSlider.connect('value-changed', Lang.bind(this, this._sliderChanged, '_output'));
|
||||
this._outputSlider.connect('drag-end', Lang.bind(this, this._notifyVolumeChange));
|
||||
this.addMenuItem(this._outputTitle);
|
||||
this.addMenuItem(this._outputSlider);
|
||||
|
||||
this.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
|
||||
|
||||
this._input = null;
|
||||
this._inputVolumeId = 0;
|
||||
this._inputMutedId = 0;
|
||||
this._inputTitle = new PopupMenu.PopupMenuItem(_("Microphone"), { reactive: false });
|
||||
this._inputSlider = new PopupMenu.PopupSliderMenuItem(0);
|
||||
this._inputSlider.connect('value-changed', Lang.bind(this, this._sliderChanged, '_input'));
|
||||
this._inputSlider.connect('drag-end', Lang.bind(this, this._notifyVolumeChange));
|
||||
this.addMenuItem(this._inputTitle);
|
||||
this.addMenuItem(this._inputSlider);
|
||||
|
||||
this._onControlStateChanged();
|
||||
},
|
||||
|
||||
scroll: function(event) {
|
||||
this._output.scroll(event);
|
||||
scroll: function(direction) {
|
||||
let currentVolume = this._output.volume;
|
||||
|
||||
if (direction == Clutter.ScrollDirection.DOWN) {
|
||||
let prev_muted = this._output.is_muted;
|
||||
this._output.volume = Math.max(0, currentVolume - this._volumeMax * VOLUME_ADJUSTMENT_STEP);
|
||||
if (this._output.volume < 1) {
|
||||
this._output.volume = 0;
|
||||
if (!prev_muted)
|
||||
this._output.change_is_muted(true);
|
||||
}
|
||||
this._output.push_volume();
|
||||
}
|
||||
else if (direction == Clutter.ScrollDirection.UP) {
|
||||
this._output.volume = Math.min(this._volumeMax, currentVolume + this._volumeMax * VOLUME_ADJUSTMENT_STEP);
|
||||
this._output.change_is_muted(false);
|
||||
this._output.push_volume();
|
||||
}
|
||||
|
||||
this._notifyVolumeChange();
|
||||
},
|
||||
|
||||
_onControlStateChanged: function() {
|
||||
if (this._control.get_state() == Gvc.MixerControlState.READY) {
|
||||
this._readInput();
|
||||
this._readOutput();
|
||||
this._readInput();
|
||||
this._maybeShowInput();
|
||||
} else {
|
||||
this.emit('icon-changed');
|
||||
this.emit('icon-changed', null);
|
||||
}
|
||||
},
|
||||
|
||||
_findHeadphones: function(sink) {
|
||||
// This only works for external headphones (e.g. bluetooth)
|
||||
if (sink.get_form_factor() == 'headset' ||
|
||||
sink.get_form_factor() == 'headphone')
|
||||
return true;
|
||||
|
||||
// a bit hackish, but ALSA/PulseAudio have a number
|
||||
// of different identifiers for headphones, and I could
|
||||
// not find the complete list
|
||||
let port = sink.get_port();
|
||||
if (port)
|
||||
return port.port.indexOf('headphone') >= 0;
|
||||
|
||||
return false;
|
||||
},
|
||||
|
||||
_portChanged: function() {
|
||||
this.hasHeadphones = this._findHeadphones(this._output);
|
||||
this.emit('headphones-changed');
|
||||
},
|
||||
|
||||
_readOutput: function() {
|
||||
this._output.stream = this._control.get_default_sink();
|
||||
if (this._outputVolumeId) {
|
||||
this._output.disconnect(this._outputVolumeId);
|
||||
this._output.disconnect(this._outputMutedId);
|
||||
this._output.disconnect(this._outputPortId);
|
||||
this._outputVolumeId = 0;
|
||||
this._outputMutedId = 0;
|
||||
this._outputPortId = 0;
|
||||
}
|
||||
this._output = this._control.get_default_sink();
|
||||
if (this._output) {
|
||||
this._outputMutedId = this._output.connect('notify::is-muted', Lang.bind(this, this._mutedChanged, '_output'));
|
||||
this._outputVolumeId = this._output.connect('notify::volume', Lang.bind(this, this._volumeChanged, '_output'));
|
||||
this._outputPortId = this._output.connect('notify::port', Lang.bind(this, this._portChanged));
|
||||
|
||||
this._mutedChanged(null, null, '_output');
|
||||
this._volumeChanged(null, null, '_output');
|
||||
this._portChanged();
|
||||
} else {
|
||||
this.hasHeadphones = false;
|
||||
this._outputSlider.setValue(0);
|
||||
this.emit('icon-changed', 'audio-volume-muted-symbolic');
|
||||
}
|
||||
},
|
||||
|
||||
_readInput: function() {
|
||||
this._input.stream = this._control.get_default_source();
|
||||
if (this._inputVolumeId) {
|
||||
this._input.disconnect(this._inputVolumeId);
|
||||
this._input.disconnect(this._inputMutedId);
|
||||
this._inputVolumeId = 0;
|
||||
this._inputMutedId = 0;
|
||||
}
|
||||
this._input = this._control.get_default_source();
|
||||
if (this._input) {
|
||||
this._inputMutedId = this._input.connect('notify::is-muted', Lang.bind(this, this._mutedChanged, '_input'));
|
||||
this._inputVolumeId = this._input.connect('notify::volume', Lang.bind(this, this._volumeChanged, '_input'));
|
||||
this._mutedChanged (null, null, '_input');
|
||||
this._volumeChanged (null, null, '_input');
|
||||
} else {
|
||||
this._inputTitle.actor.hide();
|
||||
this._inputSlider.actor.hide();
|
||||
}
|
||||
},
|
||||
|
||||
getIcon: function() {
|
||||
return this._output.getIcon();
|
||||
_maybeShowInput: function() {
|
||||
// only show input widgets if any application is recording audio
|
||||
let showInput = false;
|
||||
let recordingApps = this._control.get_source_outputs();
|
||||
if (this._input && recordingApps) {
|
||||
for (let i = 0; i < recordingApps.length; i++) {
|
||||
let outputStream = recordingApps[i];
|
||||
let id = outputStream.get_application_id();
|
||||
// but skip gnome-volume-control and pavucontrol
|
||||
// (that appear as recording because they show the input level)
|
||||
if (!id || (id != 'org.gnome.VolumeControl' && id != 'org.PulseAudio.pavucontrol')) {
|
||||
showInput = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this._inputTitle.actor.visible = showInput;
|
||||
this._inputSlider.actor.visible = showInput;
|
||||
},
|
||||
|
||||
_volumeToIcon: function(volume) {
|
||||
if (volume <= 0) {
|
||||
return 'audio-volume-muted-symbolic';
|
||||
} else {
|
||||
let n = Math.floor(3 * volume / this._volumeMax) + 1;
|
||||
if (n < 2)
|
||||
return 'audio-volume-low-symbolic';
|
||||
if (n >= 3)
|
||||
return 'audio-volume-high-symbolic';
|
||||
return 'audio-volume-medium-symbolic';
|
||||
}
|
||||
},
|
||||
|
||||
_sliderChanged: function(slider, value, property) {
|
||||
if (this[property] == null) {
|
||||
log ('Volume slider changed for %s, but %s does not exist'.format(property, property));
|
||||
return;
|
||||
}
|
||||
let volume = value * this._volumeMax;
|
||||
let prev_muted = this[property].is_muted;
|
||||
if (volume < 1) {
|
||||
this[property].volume = 0;
|
||||
if (!prev_muted)
|
||||
this[property].change_is_muted(true);
|
||||
} else {
|
||||
this[property].volume = volume;
|
||||
if (prev_muted)
|
||||
this[property].change_is_muted(false);
|
||||
}
|
||||
this[property].push_volume();
|
||||
},
|
||||
|
||||
_notifyVolumeChange: function() {
|
||||
global.cancel_theme_sound(VOLUME_NOTIFY_ID);
|
||||
global.play_theme_sound(VOLUME_NOTIFY_ID, 'audio-volume-change');
|
||||
},
|
||||
|
||||
_mutedChanged: function(object, param_spec, property) {
|
||||
let muted = this[property].is_muted;
|
||||
let slider = this[property+'Slider'];
|
||||
slider.setValue(muted ? 0 : (this[property].volume / this._volumeMax));
|
||||
if (property == '_output') {
|
||||
if (muted)
|
||||
this.emit('icon-changed', 'audio-volume-muted-symbolic');
|
||||
else
|
||||
this.emit('icon-changed', this._volumeToIcon(this._output.volume));
|
||||
}
|
||||
},
|
||||
|
||||
_volumeChanged: function(object, param_spec, property) {
|
||||
this[property+'Slider'].setValue(this[property].volume / this._volumeMax);
|
||||
if (property == '_output' && !this._output.is_muted)
|
||||
this.emit('icon-changed', this._volumeToIcon(this._output.volume));
|
||||
}
|
||||
});
|
||||
|
||||
@ -298,13 +252,13 @@ const Indicator = new Lang.Class({
|
||||
|
||||
this._control = getMixerControl();
|
||||
this._volumeMenu = new VolumeMenu(this._control);
|
||||
this._volumeMenu.connect('icon-changed', Lang.bind(this, function(menu) {
|
||||
let icon = this._volumeMenu.getIcon();
|
||||
this.actor.visible = (icon != null);
|
||||
this._volumeMenu.connect('icon-changed', Lang.bind(this, function(menu, icon) {
|
||||
this._hasPulseAudio = (icon != null);
|
||||
this.setIcon(icon);
|
||||
this._syncVisibility();
|
||||
}));
|
||||
this._volumeMenu.connect('headphones-changed', Lang.bind(this, function(menu, value) {
|
||||
this._headphoneIcon.visible = value;
|
||||
this._volumeMenu.connect('headphones-changed', Lang.bind(this, function() {
|
||||
this._syncVisibility();
|
||||
}));
|
||||
|
||||
this._headphoneIcon = this.addIcon(new Gio.ThemedIcon({ name: 'headphones-symbolic' }));
|
||||
@ -318,7 +272,13 @@ const Indicator = new Lang.Class({
|
||||
this.actor.connect('scroll-event', Lang.bind(this, this._onScrollEvent));
|
||||
},
|
||||
|
||||
_syncVisibility: function() {
|
||||
this.actor.visible = this._hasPulseAudio;
|
||||
this.mainIcon.visible = this._hasPulseAudio;
|
||||
this._headphoneIcon.visible = this._hasPulseAudio && this._volumeMenu.hasHeadphones;
|
||||
},
|
||||
|
||||
_onScrollEvent: function(actor, event) {
|
||||
this._volumeMenu.scroll(event);
|
||||
this._volumeMenu.scroll(event.get_scroll_direction());
|
||||
}
|
||||
});
|
||||
|
@ -46,8 +46,7 @@ const SwitcherPopup = new Lang.Class({
|
||||
this._selectedIndex = 0;
|
||||
|
||||
this.actor = new Shell.GenericContainer({ style_class: 'switcher-popup',
|
||||
reactive: true,
|
||||
visible: false });
|
||||
reactive: true });
|
||||
this.actor.connect('get-preferred-width', Lang.bind(this, this._getPreferredWidth));
|
||||
this.actor.connect('get-preferred-height', Lang.bind(this, this._getPreferredHeight));
|
||||
this.actor.connect('allocate', Lang.bind(this, this._allocate));
|
||||
@ -160,7 +159,6 @@ const SwitcherPopup = new Lang.Class({
|
||||
// disturbed by the popup briefly flashing.
|
||||
this._initialDelayTimeoutId = Mainloop.timeout_add(POPUP_DELAY_TIMEOUT,
|
||||
Lang.bind(this, function () {
|
||||
Main.osdWindow.cancel();
|
||||
this.actor.opacity = 255;
|
||||
this._initialDelayTimeoutId = 0;
|
||||
}));
|
||||
@ -305,7 +303,7 @@ const SwitcherList = new Lang.Class({
|
||||
this.actor.connect('allocate', Lang.bind(this, this._allocateTop));
|
||||
|
||||
// Here we use a GenericContainer so that we can force all the
|
||||
// children to have the same width.
|
||||
// children except the separator to have the same width.
|
||||
this._list = new Shell.GenericContainer({ style_class: 'switcher-list-item-container' });
|
||||
this._list.spacing = 0;
|
||||
this._list.connect('style-changed', Lang.bind(this, function() {
|
||||
@ -340,6 +338,7 @@ const SwitcherList = new Lang.Class({
|
||||
|
||||
this._items = [];
|
||||
this._highlighted = -1;
|
||||
this._separator = null;
|
||||
this._squareItems = squareItems;
|
||||
this._minSize = 0;
|
||||
this._scrollableRight = true;
|
||||
@ -402,6 +401,12 @@ const SwitcherList = new Lang.Class({
|
||||
this._itemEntered(index);
|
||||
},
|
||||
|
||||
addSeparator: function () {
|
||||
let box = new St.Bin({ style_class: 'separator' });
|
||||
this._separator = box;
|
||||
this._list.add_actor(box);
|
||||
},
|
||||
|
||||
highlight: function(index, justOutline) {
|
||||
if (this._highlighted != -1) {
|
||||
this._items[this._highlighted].remove_style_pseudo_class('outlined');
|
||||
@ -509,8 +514,14 @@ const SwitcherList = new Lang.Class({
|
||||
_getPreferredWidth: function (actor, forHeight, alloc) {
|
||||
let [maxChildMin, maxChildNat] = this._maxChildWidth(forHeight);
|
||||
|
||||
let separatorWidth = 0;
|
||||
if (this._separator) {
|
||||
let [sepMin, sepNat] = this._separator.get_preferred_width(forHeight);
|
||||
separatorWidth = sepNat + this._list.spacing;
|
||||
}
|
||||
|
||||
let totalSpacing = this._list.spacing * (this._items.length - 1);
|
||||
alloc.min_size = this._items.length * maxChildMin + totalSpacing;
|
||||
alloc.min_size = this._items.length * maxChildMin + separatorWidth + totalSpacing;
|
||||
alloc.natural_size = alloc.min_size;
|
||||
this._minSize = alloc.min_size;
|
||||
},
|
||||
@ -541,7 +552,14 @@ const SwitcherList = new Lang.Class({
|
||||
let [maxChildMin, maxChildNat] = this._maxChildWidth(childHeight);
|
||||
let totalSpacing = this._list.spacing * (this._items.length - 1);
|
||||
|
||||
let childWidth = Math.floor(Math.max(0, box.x2 - box.x1 - totalSpacing) / this._items.length);
|
||||
let separatorWidth = 0;
|
||||
if (this._separator) {
|
||||
let [sepMin, sepNat] = this._separator.get_preferred_width(childHeight);
|
||||
separatorWidth = sepNat;
|
||||
totalSpacing += this._list.spacing;
|
||||
}
|
||||
|
||||
let childWidth = Math.floor(Math.max(0, box.x2 - box.x1 - totalSpacing - separatorWidth) / this._items.length);
|
||||
|
||||
let x = 0;
|
||||
let children = this._list.get_children();
|
||||
@ -561,6 +579,14 @@ const SwitcherList = new Lang.Class({
|
||||
children[i].allocate(childBox, flags);
|
||||
|
||||
x += this._list.spacing + childWidth;
|
||||
} else if (children[i] == this._separator) {
|
||||
// We want the separator to be more compact than the rest.
|
||||
childBox.x1 = x;
|
||||
childBox.y1 = 0;
|
||||
childBox.x2 = x + separatorWidth;
|
||||
childBox.y2 = childHeight;
|
||||
children[i].allocate(childBox, flags);
|
||||
x += this._list.spacing + separatorWidth;
|
||||
} else {
|
||||
// Something else, eg, AppSwitcher's arrows;
|
||||
// we don't allocate it.
|
||||
@ -611,6 +637,5 @@ function drawArrow(area, side) {
|
||||
|
||||
Clutter.cairo_set_source_color(cr, bodyColor);
|
||||
cr.fill();
|
||||
cr.$dispose();
|
||||
}
|
||||
|
||||
|
@ -2,7 +2,6 @@
|
||||
|
||||
const Clutter = imports.gi.Clutter;
|
||||
const GLib = imports.gi.GLib;
|
||||
const Gtk = imports.gi.Gtk;
|
||||
const Lang = imports.lang;
|
||||
const Mainloop = imports.mainloop;
|
||||
const Shell = imports.gi.Shell;
|
||||
@ -74,9 +73,6 @@ 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);
|
||||
}
|
||||
|
@ -18,7 +18,6 @@ const Panel = imports.ui.panel;
|
||||
const ShellEntry = imports.ui.shellEntry;
|
||||
const Tweener = imports.ui.tweener;
|
||||
const UserMenu = imports.ui.userMenu;
|
||||
const UserWidget = imports.ui.userWidget;
|
||||
|
||||
const Batch = imports.gdm.batch;
|
||||
const GdmUtil = imports.gdm.util;
|
||||
@ -56,6 +55,59 @@ function isSupported() {
|
||||
}
|
||||
}
|
||||
|
||||
// A widget showing the user avatar and name
|
||||
const UserWidget = new Lang.Class({
|
||||
Name: 'UserWidget',
|
||||
|
||||
_init: function(user) {
|
||||
this._user = user;
|
||||
|
||||
this.actor = new St.BoxLayout({ style_class: 'unlock-dialog-user-name-container',
|
||||
vertical: false });
|
||||
|
||||
this._avatar = new UserMenu.UserAvatarWidget(user);
|
||||
this.actor.add(this._avatar.actor,
|
||||
{ x_fill: true, y_fill: true });
|
||||
|
||||
this._label = new St.Label({ style_class: 'login-dialog-username' });
|
||||
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));
|
||||
if (this._user.is_loaded)
|
||||
this._updateUser();
|
||||
},
|
||||
|
||||
destroy: 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;
|
||||
}
|
||||
|
||||
this.actor.destroy();
|
||||
},
|
||||
|
||||
_updateUser: function() {
|
||||
if (this._user.is_loaded)
|
||||
this._label.text = this._user.get_real_name();
|
||||
else
|
||||
this._label.text = '';
|
||||
|
||||
this._avatar.update();
|
||||
}
|
||||
});
|
||||
|
||||
const UnlockDialog = new Lang.Class({
|
||||
Name: 'UnlockDialog',
|
||||
Extends: ModalDialog.ModalDialog,
|
||||
@ -63,7 +115,7 @@ const UnlockDialog = new Lang.Class({
|
||||
_init: function(parentActor) {
|
||||
this.parent({ shellReactive: true,
|
||||
styleClass: 'login-dialog',
|
||||
keybindingMode: Shell.KeyBindingMode.UNLOCK_SCREEN,
|
||||
keybindingMode: Main.KeybindingMode.UNLOCK_SCREEN,
|
||||
parentActor: parentActor
|
||||
});
|
||||
|
||||
@ -86,7 +138,7 @@ const UnlockDialog = new Lang.Class({
|
||||
this._userVerifier.connect('show-login-hint', Lang.bind(this, this._showLoginHint));
|
||||
this._userVerifier.connect('hide-login-hint', Lang.bind(this, this._hideLoginHint));
|
||||
|
||||
this._userWidget = new UserWidget.UserWidget(this._user);
|
||||
this._userWidget = new UserWidget(this._user);
|
||||
this.contentLayout.add_actor(this._userWidget.actor);
|
||||
|
||||
this._promptLayout = new St.BoxLayout({ style_class: 'login-dialog-prompt-layout',
|
||||
@ -146,8 +198,6 @@ const UnlockDialog = new Lang.Class({
|
||||
x_align: St.Align.END,
|
||||
y_align: St.Align.MIDDLE });
|
||||
|
||||
let screenSaverSettings = new Gio.Settings({ schema: 'org.gnome.desktop.screensaver' });
|
||||
if (screenSaverSettings.get_boolean('user-switch-enabled')) {
|
||||
let otherUserLabel = new St.Label({ text: _("Log in as another user"),
|
||||
style_class: 'login-dialog-not-listed-label' });
|
||||
this._otherUserButton = new St.Button({ style_class: 'login-dialog-not-listed-button',
|
||||
@ -160,9 +210,6 @@ const UnlockDialog = new Lang.Class({
|
||||
this.dialogLayout.add(this._otherUserButton,
|
||||
{ x_align: St.Align.START,
|
||||
x_fill: false });
|
||||
} else {
|
||||
this._otherUserButton = null;
|
||||
}
|
||||
|
||||
this._updateSensitivity(true);
|
||||
|
||||
@ -177,17 +224,15 @@ const UnlockDialog = new Lang.Class({
|
||||
Main.ctrlAltTabManager.addGroup(this.dialogLayout, _("Unlock Window"), 'dialog-password-symbolic');
|
||||
|
||||
this._idleMonitor = new GnomeDesktop.IdleMonitor();
|
||||
this._idleWatchId = this._idleMonitor.add_idle_watch(IDLE_TIMEOUT * 1000, Lang.bind(this, this._escape));
|
||||
this._idleWatchId = this._idleMonitor.add_watch(IDLE_TIMEOUT * 1000, Lang.bind(this, this._escape));
|
||||
},
|
||||
|
||||
_updateSensitivity: function(sensitive) {
|
||||
this._promptEntry.reactive = sensitive;
|
||||
this._promptEntry.clutter_text.editable = sensitive;
|
||||
this._updateOkButtonSensitivity(sensitive && this._promptEntry.text.length > 0);
|
||||
if (this._otherUserButton) {
|
||||
this._otherUserButton.reactive = sensitive;
|
||||
this._otherUserButton.can_focus = sensitive;
|
||||
}
|
||||
},
|
||||
|
||||
_updateOkButtonSensitivity: function(sensitive) {
|
||||
|
@ -4,20 +4,17 @@ const AccountsService = imports.gi.AccountsService;
|
||||
const Gdm = imports.gi.Gdm;
|
||||
const Gio = imports.gi.Gio;
|
||||
const GLib = imports.gi.GLib;
|
||||
const Gtk = imports.gi.Gtk;
|
||||
const Lang = imports.lang;
|
||||
const Pango = imports.gi.Pango;
|
||||
const Shell = imports.gi.Shell;
|
||||
const St = imports.gi.St;
|
||||
const Tp = imports.gi.TelepathyGLib;
|
||||
const Atk = imports.gi.Atk;
|
||||
const Clutter = imports.gi.Clutter;
|
||||
|
||||
const BoxPointer = imports.ui.boxpointer;
|
||||
const GnomeSession = imports.misc.gnomeSession;
|
||||
const LoginManager = imports.misc.loginManager;
|
||||
const Main = imports.ui.main;
|
||||
const ModalDialog = imports.ui.modalDialog;
|
||||
const PanelMenu = imports.ui.panelMenu;
|
||||
const PopupMenu = imports.ui.popupMenu;
|
||||
const Params = imports.misc.params;
|
||||
@ -25,17 +22,15 @@ const Util = imports.misc.util;
|
||||
|
||||
const LOCKDOWN_SCHEMA = 'org.gnome.desktop.lockdown';
|
||||
const SCREENSAVER_SCHEMA = 'org.gnome.desktop.screensaver';
|
||||
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 LOCK_ENABLED_KEY = 'lock-enabled';
|
||||
const ALWAYS_SHOW_LOG_OUT_KEY = 'always-show-log-out';
|
||||
const SHOW_FULL_NAME_IN_TOP_BAR_KEY = 'show-full-name-in-top-bar';
|
||||
const SHOW_FULL_NAME_KEY = 'show-full-name';
|
||||
|
||||
const DIALOG_ICON_SIZE = 64;
|
||||
|
||||
const MAX_USERS_IN_SESSION_DIALOG = 5;
|
||||
|
||||
const IMStatus = {
|
||||
AVAILABLE: 0,
|
||||
BUSY: 1,
|
||||
@ -46,17 +41,6 @@ const IMStatus = {
|
||||
LAST: 6
|
||||
};
|
||||
|
||||
|
||||
const SystemdLoginSessionIface = <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 SystemdLoginSession = Gio.DBusProxy.makeProxyWrapper(SystemdLoginSessionIface);
|
||||
|
||||
// Adapted from gdm/gui/user-switch-applet/applet.c
|
||||
//
|
||||
// Copyright (C) 2004-2005 James M. Cape <jcape@ignore-your.tv>.
|
||||
@ -84,7 +68,7 @@ const UserAvatarWidget = new Lang.Class({
|
||||
|
||||
update: function() {
|
||||
let iconFile = this._user.get_icon_file();
|
||||
if (iconFile && !GLib.file_test(iconFile, GLib.FileTest.EXISTS))
|
||||
if (!GLib.file_test(iconFile, GLib.FileTest.EXISTS))
|
||||
iconFile = null;
|
||||
|
||||
if (iconFile) {
|
||||
@ -493,7 +477,6 @@ const UserMenuButton = new Lang.Class({
|
||||
|
||||
this._screenSaverSettings = new Gio.Settings({ schema: SCREENSAVER_SCHEMA });
|
||||
this._lockdownSettings = new Gio.Settings({ schema: LOCKDOWN_SCHEMA });
|
||||
this._privacySettings = new Gio.Settings({ schema: PRIVACY_SCHEMA });
|
||||
|
||||
this._userManager = AccountsService.UserManager.get_default();
|
||||
|
||||
@ -570,11 +553,9 @@ const UserMenuButton = new Lang.Class({
|
||||
Lang.bind(this, this._updateLogout));
|
||||
this._lockdownSettings.connect('changed::' + DISABLE_LOCK_SCREEN_KEY,
|
||||
Lang.bind(this, this._updateLockScreen));
|
||||
global.settings.connect('changed::' + ALWAYS_SHOW_LOG_OUT_KEY,
|
||||
Lang.bind(this, this._updateLogout));
|
||||
this._screenSaverSettings.connect('changed::' + SHOW_FULL_NAME_IN_TOP_BAR_KEY,
|
||||
this._screenSaverSettings.connect('changed::' + SHOW_FULL_NAME_KEY,
|
||||
Lang.bind(this, this._updateUserName));
|
||||
this._privacySettings.connect('changed::' + SHOW_FULL_NAME_IN_TOP_BAR_KEY,
|
||||
global.settings.connect('changed::' + SHOW_FULL_NAME_KEY,
|
||||
Lang.bind(this, this._updateUserName));
|
||||
this._updateSwitchUser();
|
||||
this._updateLogout();
|
||||
@ -600,7 +581,6 @@ const UserMenuButton = new Lang.Class({
|
||||
Lang.bind(this, this._updateHaveShutdown));
|
||||
|
||||
Main.sessionMode.connect('updated', Lang.bind(this, this._sessionUpdated));
|
||||
Main.screenShield.connect('locked-changed', Lang.bind(this, this._updatePresenceIcon));
|
||||
this._sessionUpdated();
|
||||
},
|
||||
|
||||
@ -622,10 +602,10 @@ const UserMenuButton = new Lang.Class({
|
||||
},
|
||||
|
||||
_updateUserName: function() {
|
||||
let settings = this._privacySettings;
|
||||
let settings = global.settings;
|
||||
if (Main.sessionMode.isLocked)
|
||||
settings = this._screenSaverSettings;
|
||||
if (this._user.is_loaded && settings.get_boolean(SHOW_FULL_NAME_IN_TOP_BAR_KEY))
|
||||
if (this._user.is_loaded && settings.get_boolean(SHOW_FULL_NAME_KEY))
|
||||
this._name.set_text(this._user.get_real_name());
|
||||
else
|
||||
this._name.set_text("");
|
||||
@ -720,11 +700,6 @@ const UserMenuButton = new Lang.Class({
|
||||
this._iconBox.child = this._idleIcon;
|
||||
else
|
||||
this._iconBox.child = this._offlineIcon;
|
||||
|
||||
if (Main.sessionMode.isLocked)
|
||||
this._iconBox.visible = Main.screenShield.locked;
|
||||
else
|
||||
this._iconBox.visible = true;
|
||||
},
|
||||
|
||||
_setupAccounts: function() {
|
||||
@ -845,7 +820,7 @@ const UserMenuButton = new Lang.Class({
|
||||
|
||||
_onMyAccountActivate: function() {
|
||||
Main.overview.hide();
|
||||
let app = Shell.AppSystem.get_default().lookup_app('gnome-user-accounts-panel.desktop');
|
||||
let app = Shell.AppSystem.get_default().lookup_setting('gnome-user-accounts-panel.desktop');
|
||||
app.activate();
|
||||
},
|
||||
|
||||
@ -880,115 +855,25 @@ const UserMenuButton = new Lang.Class({
|
||||
this._session.RebootRemote();
|
||||
},
|
||||
|
||||
_openSessionWarnDialog: function(sessions) {
|
||||
let dialog = new ModalDialog.ModalDialog();
|
||||
let subjectLabel = new St.Label({ style_class: 'end-session-dialog-subject',
|
||||
text: _("Other users are logged in.") });
|
||||
dialog.contentLayout.add(subjectLabel, { y_fill: true,
|
||||
y_align: St.Align.START });
|
||||
|
||||
let descriptionLabel = new St.Label({ style_class: 'end-session-dialog-description'});
|
||||
descriptionLabel.set_text(_("Shutting down might cause them to lose unsaved work."));
|
||||
descriptionLabel.clutter_text.line_wrap = true;
|
||||
dialog.contentLayout.add(descriptionLabel, { x_fill: true,
|
||||
y_fill: true,
|
||||
y_align: St.Align.START });
|
||||
|
||||
let scrollView = new St.ScrollView({ style_class: 'end-session-dialog-app-list' });
|
||||
scrollView.add_style_class_name('vfade');
|
||||
scrollView.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC);
|
||||
dialog.contentLayout.add(scrollView, { x_fill: true, y_fill: true });
|
||||
|
||||
let userList = new St.BoxLayout({ vertical: true });
|
||||
scrollView.add_actor(userList);
|
||||
|
||||
for (let i = 0; i < sessions.length; i++) {
|
||||
let session = sessions[i];
|
||||
let userEntry = new St.BoxLayout({ style_class: 'login-dialog-user-list-item',
|
||||
vertical: false });
|
||||
let avatar = new UserAvatarWidget(session.user);
|
||||
avatar.update();
|
||||
userEntry.add(avatar.actor);
|
||||
|
||||
let userLabelText = "";;
|
||||
let userName = session.user.get_real_name() ?
|
||||
session.user.get_real_name() : session.username;
|
||||
|
||||
if (session.info.remote)
|
||||
userLabelText = _("%s (remote)").format(userName);
|
||||
else if (session.info.type == "tty")
|
||||
userLabelText = _("%s (console)").format(userName);
|
||||
else
|
||||
userLabelText = userName;
|
||||
|
||||
let textLayout = new St.BoxLayout({ style_class: 'login-dialog-user-list-item-text-box',
|
||||
vertical: true });
|
||||
textLayout.add(new St.Label({ text: userLabelText }),
|
||||
{ y_fill: false,
|
||||
y_align: St.Align.MIDDLE,
|
||||
expand: true });
|
||||
userEntry.add(textLayout, { expand: true });
|
||||
userList.add(userEntry, { x_fill: true });
|
||||
}
|
||||
|
||||
let cancelButton = { label: _("Cancel"),
|
||||
action: function() { dialog.close(); },
|
||||
key: Clutter.Escape };
|
||||
|
||||
let powerOffButton = { label: _("Power Off"), action: Lang.bind(this, function() {
|
||||
dialog.close();
|
||||
this._session.ShutdownRemote();
|
||||
}), default: true };
|
||||
|
||||
dialog.setButtons([cancelButton, powerOffButton]);
|
||||
|
||||
dialog.open();
|
||||
},
|
||||
|
||||
_onSuspendOrPowerOffActivate: function() {
|
||||
Main.overview.hide();
|
||||
|
||||
if (this._haveShutdown &&
|
||||
this._suspendOrPowerOffItem.state == PopupMenu.PopupAlternatingMenuItemState.DEFAULT) {
|
||||
this._loginManager.listSessions(Lang.bind(this,
|
||||
function(result) {
|
||||
let sessions = [];
|
||||
let n = 0;
|
||||
for (let i = 0; i < result.length; i++) {
|
||||
let[id, uid, userName, seat, sessionPath] = result[i];
|
||||
let proxy = new SystemdLoginSession(Gio.DBus.system,
|
||||
'org.freedesktop.login1',
|
||||
sessionPath);
|
||||
|
||||
if (proxy.Class != 'user')
|
||||
continue;
|
||||
|
||||
if (proxy.State == 'closing')
|
||||
continue;
|
||||
|
||||
if (proxy.Id == GLib.getenv('XDG_SESSION_ID'))
|
||||
continue;
|
||||
|
||||
sessions.push({ user: this._userManager.get_user(userName),
|
||||
username: userName,
|
||||
info: { type: proxy.Type,
|
||||
remote: proxy.Remote }
|
||||
});
|
||||
|
||||
// limit the number of entries
|
||||
n++;
|
||||
if (n == MAX_USERS_IN_SESSION_DIALOG)
|
||||
break;
|
||||
}
|
||||
|
||||
if (n != 0)
|
||||
this._openSessionWarnDialog(sessions);
|
||||
else
|
||||
this._session.ShutdownRemote();
|
||||
}));
|
||||
} else {
|
||||
if (this._screenSaverSettings.get_boolean(LOCK_ENABLED_KEY)) {
|
||||
let tmpId = Main.screenShield.connect('lock-screen-shown', Lang.bind(this, function() {
|
||||
Main.screenShield.disconnect(tmpId);
|
||||
|
||||
this._loginManager.suspend();
|
||||
}));
|
||||
|
||||
this.menu.close(BoxPointer.PopupAnimation.NONE);
|
||||
Main.screenShield.lock(true);
|
||||
} else {
|
||||
this._loginManager.suspend();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -1,61 +0,0 @@
|
||||
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
//
|
||||
// A widget showing the user avatar and name
|
||||
const AccountsService = imports.gi.AccountsService;
|
||||
const Lang = imports.lang;
|
||||
const St = imports.gi.St;
|
||||
|
||||
const UserMenu = imports.ui.userMenu;
|
||||
|
||||
const UserWidget = new Lang.Class({
|
||||
Name: 'UserWidget',
|
||||
|
||||
_init: function(user) {
|
||||
this._user = user;
|
||||
|
||||
this.actor = new St.BoxLayout({ style_class: 'user-widget',
|
||||
vertical: false });
|
||||
|
||||
this._avatar = new UserMenu.UserAvatarWidget(user);
|
||||
this.actor.add(this._avatar.actor,
|
||||
{ x_fill: true, y_fill: true });
|
||||
|
||||
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));
|
||||
if (this._user.is_loaded)
|
||||
this._updateUser();
|
||||
},
|
||||
|
||||
destroy: 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;
|
||||
}
|
||||
|
||||
this.actor.destroy();
|
||||
},
|
||||
|
||||
_updateUser: function() {
|
||||
if (this._user.is_loaded)
|
||||
this._label.text = this._user.get_real_name();
|
||||
else
|
||||
this._label.text = '';
|
||||
|
||||
this._avatar.update();
|
||||
}
|
||||
});
|
@ -12,8 +12,6 @@ const St = imports.gi.St;
|
||||
|
||||
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;
|
||||
@ -24,12 +22,6 @@ const WorkspacesView = imports.ui.workspacesView;
|
||||
|
||||
const SHELL_KEYBINDINGS_SCHEMA = 'org.gnome.shell.keybindings';
|
||||
|
||||
const ViewPage = {
|
||||
WINDOWS: 1,
|
||||
APPS: 2,
|
||||
SEARCH: 3
|
||||
};
|
||||
|
||||
const FocusTrap = new Lang.Class({
|
||||
Name: 'FocusTrap',
|
||||
Extends: St.Widget,
|
||||
@ -42,14 +34,6 @@ const FocusTrap = new Lang.Class({
|
||||
}
|
||||
});
|
||||
|
||||
function getTermsForSearchString(searchString) {
|
||||
searchString = searchString.replace(/^\s+/g, '').replace(/\s+$/g, '');
|
||||
if (searchString == '')
|
||||
return [];
|
||||
|
||||
let terms = searchString.split(/\s+/);
|
||||
return terms;
|
||||
}
|
||||
|
||||
const ViewSelector = new Lang.Class({
|
||||
Name: 'ViewSelector',
|
||||
@ -57,13 +41,13 @@ const ViewSelector = new Lang.Class({
|
||||
_init : function(searchEntry, showAppsButton) {
|
||||
this.actor = new Shell.Stack({ name: 'viewSelector' });
|
||||
|
||||
this._showAppsBlocked = false;
|
||||
this._showAppsButton = showAppsButton;
|
||||
this._showAppsButton.connect('notify::checked', Lang.bind(this, this._onShowAppsButtonToggled));
|
||||
|
||||
this._activePage = null;
|
||||
|
||||
this._searchActive = false;
|
||||
this.active = false;
|
||||
this._searchPending = false;
|
||||
this._searchTimeoutId = 0;
|
||||
|
||||
this._searchSystem = new Search.SearchSystem();
|
||||
@ -83,26 +67,26 @@ const ViewSelector = new Lang.Class({
|
||||
this._entry.connect('notify::mapped', Lang.bind(this, this._onMapped));
|
||||
global.stage.connect('notify::key-focus', Lang.bind(this, this._onStageKeyFocusChanged));
|
||||
|
||||
this._entry.set_primary_icon(new St.Icon({ style_class: 'search-entry-icon',
|
||||
icon_name: 'edit-find-symbolic' }));
|
||||
this._clearIcon = new St.Icon({ style_class: 'search-entry-icon',
|
||||
this._inactiveIcon = new St.Icon({ style_class: 'search-entry-icon',
|
||||
icon_name: 'edit-find-symbolic' });
|
||||
this._activeIcon = new St.Icon({ style_class: 'search-entry-icon',
|
||||
icon_name: 'edit-clear-symbolic' });
|
||||
this._entry.set_secondary_icon(this._inactiveIcon);
|
||||
|
||||
this._iconClickedId = 0;
|
||||
this._capturedEventId = 0;
|
||||
|
||||
this._workspacesDisplay = new WorkspacesView.WorkspacesDisplay();
|
||||
this._workspacesPage = this._addPage(this._workspacesDisplay.actor,
|
||||
this._workspacesPage = this._addPage(this._workspacesDisplay.actor, null,
|
||||
_("Windows"), 'emblem-documents-symbolic');
|
||||
|
||||
this._appDisplay = new AppDisplay.AppDisplay();
|
||||
this._appsPage = this._addPage(this._appDisplay.actor,
|
||||
this._appDisplay = new AppDisplay.AllAppDisplay();
|
||||
this._appsPage = this._addPage(this._appDisplay.actor, null,
|
||||
_("Applications"), 'view-grid-symbolic');
|
||||
|
||||
this._searchResults = new SearchDisplay.SearchResults(this._searchSystem);
|
||||
this._searchPage = this._addPage(this._searchResults.actor,
|
||||
_("Search"), 'edit-find-symbolic',
|
||||
{ a11yFocus: this._entry });
|
||||
this._searchPage = this._addPage(this._searchResults.actor, this._entry,
|
||||
_("Search"), 'edit-find-symbolic');
|
||||
|
||||
this._searchSettings = new Gio.Settings({ schema: Search.SEARCH_PROVIDERS_SCHEMA });
|
||||
this._searchSettings.connect('changed::disabled', Lang.bind(this, this._reloadRemoteProviders));
|
||||
@ -113,6 +97,7 @@ const ViewSelector = new Lang.Class({
|
||||
// Wanda comes obviously first
|
||||
this.addSearchProvider(new Wanda.WandaSearchProvider());
|
||||
this.addSearchProvider(new AppDisplay.AppSearchProvider());
|
||||
this.addSearchProvider(new AppDisplay.SettingsSearchProvider());
|
||||
|
||||
// Load remote search providers provided by applications
|
||||
RemoteSearch.loadRemoteSearchProviders(Lang.bind(this, this.addSearchProvider));
|
||||
@ -128,6 +113,9 @@ const ViewSelector = new Lang.Class({
|
||||
|
||||
global.focus_manager.add_group(this._searchResults.actor);
|
||||
|
||||
Main.overview.connect('item-drag-begin',
|
||||
Lang.bind(this, this._resetShowAppsButton));
|
||||
|
||||
this._stageKeyPressId = 0;
|
||||
Main.overview.connect('showing', Lang.bind(this,
|
||||
function () {
|
||||
@ -147,8 +135,8 @@ const ViewSelector = new Lang.Class({
|
||||
Main.wm.addKeybinding('toggle-application-view',
|
||||
new Gio.Settings({ schema: SHELL_KEYBINDINGS_SCHEMA }),
|
||||
Meta.KeyBindingFlags.NONE,
|
||||
Shell.KeyBindingMode.NORMAL |
|
||||
Shell.KeyBindingMode.OVERVIEW,
|
||||
Main.KeybindingMode.NORMAL |
|
||||
Main.KeybindingMode.OVERVIEW,
|
||||
Lang.bind(this, this._toggleAppsPage));
|
||||
},
|
||||
|
||||
@ -160,7 +148,6 @@ const ViewSelector = new Lang.Class({
|
||||
show: function() {
|
||||
this._activePage = this._workspacesPage;
|
||||
|
||||
this.reset();
|
||||
this._appsPage.hide();
|
||||
this._searchPage.hide();
|
||||
this._workspacesDisplay.show();
|
||||
@ -168,7 +155,7 @@ const ViewSelector = new Lang.Class({
|
||||
if (!this._workspacesDisplay.activeWorkspaceHasMaximizedWindows())
|
||||
Main.overview.fadeOutDesktop();
|
||||
|
||||
this._showPage(this._workspacesPage, true);
|
||||
this._showPage(this._workspacesPage);
|
||||
},
|
||||
|
||||
zoomFromOverview: function() {
|
||||
@ -182,16 +169,14 @@ const ViewSelector = new Lang.Class({
|
||||
this._workspacesDisplay.hide();
|
||||
},
|
||||
|
||||
_addPage: function(actor, name, a11yIcon, params) {
|
||||
params = Params.parse(params, { a11yFocus: null });
|
||||
|
||||
_addPage: function(actor, a11yFocus, name, a11yIcon) {
|
||||
let page = new St.Bin({ child: actor,
|
||||
x_align: St.Align.START,
|
||||
y_align: St.Align.START,
|
||||
x_fill: true,
|
||||
y_fill: true });
|
||||
if (params.a11yFocus)
|
||||
Main.ctrlAltTabManager.addGroup(params.a11yFocus, name, a11yIcon);
|
||||
if (a11yFocus)
|
||||
Main.ctrlAltTabManager.addGroup(a11yFocus, name, a11yIcon);
|
||||
else
|
||||
Main.ctrlAltTabManager.addGroup(actor, name, a11yIcon,
|
||||
{ proxy: this.actor,
|
||||
@ -204,40 +189,29 @@ const ViewSelector = new Lang.Class({
|
||||
return page;
|
||||
},
|
||||
|
||||
_fadePageIn: function(oldPage) {
|
||||
if (oldPage)
|
||||
oldPage.hide();
|
||||
|
||||
this.emit('page-empty');
|
||||
|
||||
this._activePage.show();
|
||||
Tweener.addTween(this._activePage,
|
||||
{ opacity: 255,
|
||||
time: OverviewControls.SIDE_CONTROLS_ANIMATION_TIME,
|
||||
transition: 'easeOutQuad'
|
||||
});
|
||||
},
|
||||
|
||||
_showPage: function(page, noFade) {
|
||||
_showPage: function(page) {
|
||||
if(page == this._activePage)
|
||||
return;
|
||||
|
||||
let oldPage = this._activePage;
|
||||
this._activePage = page;
|
||||
this.emit('page-changed');
|
||||
|
||||
if (oldPage && !noFade)
|
||||
Tweener.addTween(oldPage,
|
||||
if(this._activePage) {
|
||||
Tweener.addTween(this._activePage,
|
||||
{ opacity: 0,
|
||||
time: OverviewControls.SIDE_CONTROLS_ANIMATION_TIME,
|
||||
time: 0.1,
|
||||
transition: 'easeOutQuad',
|
||||
onComplete: Lang.bind(this,
|
||||
function() {
|
||||
this._fadePageIn(oldPage);
|
||||
this._activePage.hide();
|
||||
this._activePage = page;
|
||||
})
|
||||
});
|
||||
else
|
||||
this._fadePageIn(oldPage);
|
||||
}
|
||||
|
||||
page.show();
|
||||
Tweener.addTween(page,
|
||||
{ opacity: 255,
|
||||
time: 0.1,
|
||||
transition: 'easeOutQuad'
|
||||
});
|
||||
},
|
||||
|
||||
_a11yFocusPage: function(page) {
|
||||
@ -246,19 +220,15 @@ const ViewSelector = new Lang.Class({
|
||||
},
|
||||
|
||||
_onShowAppsButtonToggled: function() {
|
||||
if (this._showAppsBlocked)
|
||||
return;
|
||||
|
||||
this._showPage(this._showAppsButton.checked ?
|
||||
this._appsPage : this._workspacesPage);
|
||||
if (this.active)
|
||||
this.reset();
|
||||
else
|
||||
this._showPage(this._showAppsButton.checked ? this._appsPage
|
||||
: this._workspacesPage);
|
||||
},
|
||||
|
||||
_resetShowAppsButton: function() {
|
||||
this._showAppsBlocked = true;
|
||||
this._showAppsButton.checked = false;
|
||||
this._showAppsBlocked = false;
|
||||
|
||||
this._showPage(this._workspacesPage, true);
|
||||
},
|
||||
|
||||
_onStageKeyPress: function(actor, event) {
|
||||
@ -271,16 +241,17 @@ const ViewSelector = new Lang.Class({
|
||||
let symbol = event.get_key_symbol();
|
||||
|
||||
if (symbol == Clutter.Escape) {
|
||||
if (this._searchActive)
|
||||
if (this.active)
|
||||
this.reset();
|
||||
else if (this._showAppsButton.checked)
|
||||
this._showAppsButton.checked = false;
|
||||
this._resetShowAppsButton();
|
||||
else
|
||||
Main.overview.hide();
|
||||
return true;
|
||||
} else if (this._shouldTriggerSearch(symbol)) {
|
||||
} else if (Clutter.keysym_to_unicode(symbol) ||
|
||||
(symbol == Clutter.BackSpace && this.active)) {
|
||||
this.startSearch(event);
|
||||
} else if (!this._searchActive) {
|
||||
} else if (!this.active) {
|
||||
if (symbol == Clutter.Tab || symbol == Clutter.Down) {
|
||||
this._activePage.navigate_focus(null, Gtk.DirectionType.TAB_FORWARD, false);
|
||||
return true;
|
||||
@ -343,17 +314,6 @@ const ViewSelector = new Lang.Class({
|
||||
}
|
||||
},
|
||||
|
||||
_shouldTriggerSearch: function(symbol) {
|
||||
let unicode = Clutter.keysym_to_unicode(symbol);
|
||||
if (unicode == 0)
|
||||
return false;
|
||||
|
||||
if (getTermsForSearchString(String.fromCharCode(unicode)).length > 0)
|
||||
return true;
|
||||
|
||||
return symbol == Clutter.BackSpace && this._searchActive;
|
||||
},
|
||||
|
||||
startSearch: function(event) {
|
||||
global.stage.set_key_focus(this._text);
|
||||
this._text.event(event, true);
|
||||
@ -365,39 +325,39 @@ const ViewSelector = new Lang.Class({
|
||||
},
|
||||
|
||||
_onTextChanged: function (se, prop) {
|
||||
let terms = getTermsForSearchString(this._entry.get_text());
|
||||
|
||||
let searchPreviouslyActive = this._searchActive;
|
||||
this._searchActive = (terms.length > 0);
|
||||
|
||||
let startSearch = this._searchActive && !searchPreviouslyActive;
|
||||
if (startSearch)
|
||||
let searchPreviouslyActive = this.active;
|
||||
this.active = this._entry.get_text() != '';
|
||||
this._searchPending = this.active && !searchPreviouslyActive;
|
||||
if (this._searchPending) {
|
||||
this._searchResults.startingSearch();
|
||||
}
|
||||
if (this.active) {
|
||||
this._entry.set_secondary_icon(this._activeIcon);
|
||||
|
||||
if (this._searchActive) {
|
||||
this._entry.set_secondary_icon(this._clearIcon);
|
||||
|
||||
if (this._iconClickedId == 0)
|
||||
if (this._iconClickedId == 0) {
|
||||
this._iconClickedId = this._entry.connect('secondary-icon-clicked',
|
||||
Lang.bind(this, this.reset));
|
||||
|
||||
if (this._searchTimeoutId == 0)
|
||||
this._searchTimeoutId = Mainloop.timeout_add(150,
|
||||
Lang.bind(this, this._doSearch));
|
||||
Lang.bind(this, function() {
|
||||
this.reset();
|
||||
}));
|
||||
}
|
||||
} else {
|
||||
if (this._iconClickedId > 0) {
|
||||
if (this._iconClickedId > 0)
|
||||
this._entry.disconnect(this._iconClickedId);
|
||||
this._iconClickedId = 0;
|
||||
}
|
||||
|
||||
this._entry.set_secondary_icon(this._inactiveIcon);
|
||||
this._searchCancelled();
|
||||
}
|
||||
if (!this.active) {
|
||||
if (this._searchTimeoutId > 0) {
|
||||
Mainloop.source_remove(this._searchTimeoutId);
|
||||
this._searchTimeoutId = 0;
|
||||
}
|
||||
|
||||
this._entry.set_secondary_icon(null);
|
||||
this._searchCancelled();
|
||||
return;
|
||||
}
|
||||
if (this._searchTimeoutId > 0)
|
||||
return;
|
||||
this._searchTimeoutId = Mainloop.timeout_add(150, Lang.bind(this, this._doSearch));
|
||||
},
|
||||
|
||||
_onKeyPress: function(entry, event) {
|
||||
@ -407,7 +367,16 @@ const ViewSelector = new Lang.Class({
|
||||
this.reset();
|
||||
return true;
|
||||
}
|
||||
} else if (this._searchActive) {
|
||||
} 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.
|
||||
if (this._searchTimeoutId > 0) {
|
||||
Mainloop.source_remove(this._searchTimeoutId);
|
||||
this._doSearch();
|
||||
}
|
||||
this._searchResults.activateDefault();
|
||||
return true;
|
||||
} else if (this.active) {
|
||||
let arrowNext, nextDirection;
|
||||
if (entry.get_text_direction() == Clutter.TextDirection.RTL) {
|
||||
arrowNext = Clutter.Left;
|
||||
@ -431,15 +400,6 @@ const ViewSelector = new Lang.Class({
|
||||
} else if (symbol == arrowNext && this._text.position == -1) {
|
||||
this._searchResults.navigateFocus(nextDirection);
|
||||
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.
|
||||
if (this._searchTimeoutId > 0) {
|
||||
Mainloop.source_remove(this._searchTimeoutId);
|
||||
this._doSearch();
|
||||
}
|
||||
this._searchResults.activateDefault();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
@ -462,10 +422,9 @@ const ViewSelector = new Lang.Class({
|
||||
|
||||
_doSearch: function () {
|
||||
this._searchTimeoutId = 0;
|
||||
let text = this._text.get_text().replace(/^\s+/g, '').replace(/\s+$/g, '');
|
||||
this._searchResults.doSearch(text);
|
||||
|
||||
let terms = getTermsForSearchString(this._entry.get_text());
|
||||
|
||||
this._searchSystem.updateSearchResults(terms);
|
||||
this._showPage(this._searchPage);
|
||||
},
|
||||
|
||||
@ -502,31 +461,6 @@ const ViewSelector = new Lang.Class({
|
||||
removeSearchProvider: function(provider) {
|
||||
this._searchSystem.unregisterProvider(provider);
|
||||
this._searchResults.destroyProviderMeta(provider);
|
||||
},
|
||||
|
||||
getActivePage: function() {
|
||||
if (this._activePage == this._workspacesPage)
|
||||
return ViewPage.WINDOWS;
|
||||
else if (this._activePage == this._appsPage)
|
||||
return ViewPage.APPS;
|
||||
else
|
||||
return ViewPage.SEARCH;
|
||||
},
|
||||
|
||||
fadeIn: function() {
|
||||
let actor = this._activePage;
|
||||
Tweener.addTween(actor, { opacity: 255,
|
||||
time: OverviewControls.SIDE_CONTROLS_ANIMATION_TIME / 2,
|
||||
transition: 'easeInQuad'
|
||||
});
|
||||
},
|
||||
|
||||
fadeHalf: function() {
|
||||
let actor = this._activePage;
|
||||
Tweener.addTween(actor, { opacity: 128,
|
||||
time: OverviewControls.SIDE_CONTROLS_ANIMATION_TIME / 2,
|
||||
transition: 'easeOutQuad'
|
||||
});
|
||||
}
|
||||
});
|
||||
Signals.addSignalMethods(ViewSelector.prototype);
|
||||
|
@ -105,75 +105,84 @@ const WindowManager = new Lang.Class({
|
||||
|
||||
this._workspaceSwitcherPopup = null;
|
||||
this.setCustomKeybindingHandler('switch-to-workspace-left',
|
||||
Shell.KeyBindingMode.NORMAL |
|
||||
Shell.KeyBindingMode.OVERVIEW,
|
||||
Main.KeybindingMode.NORMAL |
|
||||
Main.KeybindingMode.OVERVIEW,
|
||||
Lang.bind(this, this._showWorkspaceSwitcher));
|
||||
this.setCustomKeybindingHandler('switch-to-workspace-right',
|
||||
Shell.KeyBindingMode.NORMAL |
|
||||
Shell.KeyBindingMode.OVERVIEW,
|
||||
Main.KeybindingMode.NORMAL |
|
||||
Main.KeybindingMode.OVERVIEW,
|
||||
Lang.bind(this, this._showWorkspaceSwitcher));
|
||||
this.setCustomKeybindingHandler('switch-to-workspace-up',
|
||||
Shell.KeyBindingMode.NORMAL |
|
||||
Shell.KeyBindingMode.OVERVIEW,
|
||||
Main.KeybindingMode.NORMAL |
|
||||
Main.KeybindingMode.OVERVIEW,
|
||||
Lang.bind(this, this._showWorkspaceSwitcher));
|
||||
this.setCustomKeybindingHandler('switch-to-workspace-down',
|
||||
Shell.KeyBindingMode.NORMAL |
|
||||
Shell.KeyBindingMode.OVERVIEW,
|
||||
Main.KeybindingMode.NORMAL |
|
||||
Main.KeybindingMode.OVERVIEW,
|
||||
Lang.bind(this, this._showWorkspaceSwitcher));
|
||||
this.setCustomKeybindingHandler('move-to-workspace-left',
|
||||
Shell.KeyBindingMode.NORMAL |
|
||||
Shell.KeyBindingMode.OVERVIEW,
|
||||
Main.KeybindingMode.NORMAL |
|
||||
Main.KeybindingMode.OVERVIEW,
|
||||
Lang.bind(this, this._showWorkspaceSwitcher));
|
||||
this.setCustomKeybindingHandler('move-to-workspace-right',
|
||||
Shell.KeyBindingMode.NORMAL |
|
||||
Shell.KeyBindingMode.OVERVIEW,
|
||||
Main.KeybindingMode.NORMAL |
|
||||
Main.KeybindingMode.OVERVIEW,
|
||||
Lang.bind(this, this._showWorkspaceSwitcher));
|
||||
this.setCustomKeybindingHandler('move-to-workspace-up',
|
||||
Shell.KeyBindingMode.NORMAL |
|
||||
Shell.KeyBindingMode.OVERVIEW,
|
||||
Main.KeybindingMode.NORMAL |
|
||||
Main.KeybindingMode.OVERVIEW,
|
||||
Lang.bind(this, this._showWorkspaceSwitcher));
|
||||
this.setCustomKeybindingHandler('move-to-workspace-down',
|
||||
Shell.KeyBindingMode.NORMAL |
|
||||
Shell.KeyBindingMode.OVERVIEW,
|
||||
Main.KeybindingMode.NORMAL |
|
||||
Main.KeybindingMode.OVERVIEW,
|
||||
Lang.bind(this, this._showWorkspaceSwitcher));
|
||||
this.setCustomKeybindingHandler('switch-applications',
|
||||
Shell.KeyBindingMode.NORMAL,
|
||||
Main.KeybindingMode.NORMAL,
|
||||
Lang.bind(this, this._startAppSwitcher));
|
||||
this.setCustomKeybindingHandler('switch-group',
|
||||
Shell.KeyBindingMode.NORMAL,
|
||||
Main.KeybindingMode.NORMAL,
|
||||
Lang.bind(this, this._startAppSwitcher));
|
||||
this.setCustomKeybindingHandler('switch-applications-backward',
|
||||
Shell.KeyBindingMode.NORMAL,
|
||||
Main.KeybindingMode.NORMAL,
|
||||
Lang.bind(this, this._startAppSwitcher));
|
||||
this.setCustomKeybindingHandler('switch-group-backward',
|
||||
Shell.KeyBindingMode.NORMAL,
|
||||
Main.KeybindingMode.NORMAL,
|
||||
Lang.bind(this, this._startAppSwitcher));
|
||||
this.setCustomKeybindingHandler('switch-windows',
|
||||
Shell.KeyBindingMode.NORMAL,
|
||||
Main.KeybindingMode.NORMAL,
|
||||
Lang.bind(this, this._startWindowSwitcher));
|
||||
this.setCustomKeybindingHandler('switch-windows-backward',
|
||||
Shell.KeyBindingMode.NORMAL,
|
||||
Main.KeybindingMode.NORMAL,
|
||||
Lang.bind(this, this._startWindowSwitcher));
|
||||
this.setCustomKeybindingHandler('switch-panels',
|
||||
Shell.KeyBindingMode.NORMAL |
|
||||
Shell.KeyBindingMode.OVERVIEW |
|
||||
Shell.KeyBindingMode.LOCK_SCREEN |
|
||||
Shell.KeyBindingMode.UNLOCK_SCREEN |
|
||||
Shell.KeyBindingMode.LOGIN_SCREEN,
|
||||
Main.KeybindingMode.NORMAL |
|
||||
Main.KeybindingMode.OVERVIEW |
|
||||
Main.KeybindingMode.LOCK_SCREEN |
|
||||
Main.KeybindingMode.UNLOCK_SCREEN |
|
||||
Main.KeybindingMode.LOGIN_SCREEN,
|
||||
Lang.bind(this, this._startA11ySwitcher));
|
||||
this.setCustomKeybindingHandler('switch-panels-backward',
|
||||
Shell.KeyBindingMode.NORMAL |
|
||||
Shell.KeyBindingMode.OVERVIEW |
|
||||
Shell.KeyBindingMode.LOCK_SCREEN |
|
||||
Shell.KeyBindingMode.UNLOCK_SCREEN |
|
||||
Shell.KeyBindingMode.LOGIN_SCREEN,
|
||||
Main.KeybindingMode.NORMAL |
|
||||
Main.KeybindingMode.OVERVIEW |
|
||||
Main.KeybindingMode.LOCK_SCREEN |
|
||||
Main.KeybindingMode.UNLOCK_SCREEN |
|
||||
Main.KeybindingMode.LOGIN_SCREEN,
|
||||
Lang.bind(this, this._startA11ySwitcher));
|
||||
|
||||
this.addKeybinding('open-application-menu',
|
||||
new Gio.Settings({ schema: SHELL_KEYBINDINGS_SCHEMA }),
|
||||
Meta.KeyBindingFlags.NONE,
|
||||
Shell.KeyBindingMode.NORMAL,
|
||||
Main.KeybindingMode.NORMAL,
|
||||
Lang.bind(this, this._openAppMenu));
|
||||
|
||||
Main.overview.connect('showing', Lang.bind(this, function() {
|
||||
for (let i = 0; i < this._dimmedWindows.length; i++)
|
||||
this._undimWindow(this._dimmedWindows[i]);
|
||||
}));
|
||||
Main.overview.connect('hiding', Lang.bind(this, function() {
|
||||
for (let i = 0; i < this._dimmedWindows.length; i++)
|
||||
this._dimWindow(this._dimmedWindows[i]);
|
||||
}));
|
||||
},
|
||||
|
||||
setCustomKeybindingHandler: function(name, modes, handler) {
|
||||
@ -190,7 +199,7 @@ const WindowManager = new Lang.Class({
|
||||
|
||||
removeKeybinding: function(name) {
|
||||
if (global.display.remove_keybinding(name))
|
||||
this.allowKeybinding(name, Shell.KeyBindingMode.NONE);
|
||||
this.allowKeybinding(name, Main.KeybindingMode.NONE);
|
||||
},
|
||||
|
||||
allowKeybinding: function(name, modes) {
|
||||
@ -233,42 +242,22 @@ const WindowManager = new Lang.Class({
|
||||
}
|
||||
|
||||
actor.set_scale(1.0, 1.0);
|
||||
actor.move_anchor_point_from_gravity(Clutter.Gravity.CENTER);
|
||||
|
||||
/* scale window down to 0x0.
|
||||
* maybe TODO: get icon geometry passed through and move the window towards it?
|
||||
*/
|
||||
this._minimizing.push(actor);
|
||||
|
||||
if (actor.meta_window.is_monitor_sized()) {
|
||||
Tweener.addTween(actor,
|
||||
{ opacity: 0,
|
||||
time: WINDOW_ANIMATION_TIME,
|
||||
transition: 'easeOutQuad',
|
||||
onComplete: this._minimizeWindowDone,
|
||||
onCompleteScope: this,
|
||||
onCompleteParams: [shellwm, actor],
|
||||
onOverwrite: this._minimizeWindowOverwritten,
|
||||
onOverwriteScope: this,
|
||||
onOverwriteParams: [shellwm, actor]
|
||||
});
|
||||
} else {
|
||||
let xDest, yDest, xScale, yScale;
|
||||
let [success, geom] = actor.meta_window.get_icon_geometry();
|
||||
if (success) {
|
||||
xDest = geom.x;
|
||||
yDest = geom.y;
|
||||
xScale = geom.width / actor.width;
|
||||
yScale = geom.height / actor.height;
|
||||
} else {
|
||||
let monitor = Main.layoutManager.monitors[actor.meta_window.get_monitor()];
|
||||
xDest = monitor.x;
|
||||
yDest = monitor.y;
|
||||
let monitor = Main.layoutManager.findMonitorForWindow(actor.meta_window);
|
||||
let xDest = monitor.x;
|
||||
let yDest = monitor.y;
|
||||
if (Clutter.get_default_text_direction() == Clutter.TextDirection.RTL)
|
||||
xDest += monitor.width;
|
||||
xScale = 0;
|
||||
yScale = 0;
|
||||
}
|
||||
|
||||
Tweener.addTween(actor,
|
||||
{ scale_x: xScale,
|
||||
scale_y: yScale,
|
||||
{ scale_x: 0.0,
|
||||
scale_y: 0.0,
|
||||
x: xDest,
|
||||
y: yDest,
|
||||
time: WINDOW_ANIMATION_TIME,
|
||||
@ -280,14 +269,12 @@ const WindowManager = new Lang.Class({
|
||||
onOverwriteScope: this,
|
||||
onOverwriteParams: [shellwm, actor]
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
_minimizeWindowDone : function(shellwm, actor) {
|
||||
if (this._removeEffect(this._minimizing, actor)) {
|
||||
Tweener.removeTweens(actor);
|
||||
actor.set_scale(1.0, 1.0);
|
||||
actor.set_opacity(255);
|
||||
actor.move_anchor_point_from_gravity(Clutter.Gravity.NORTH_WEST);
|
||||
|
||||
shellwm.completed_minimize(actor);
|
||||
@ -333,12 +320,14 @@ const WindowManager = new Lang.Class({
|
||||
if (shouldDim && !window._dimmed) {
|
||||
window._dimmed = true;
|
||||
this._dimmedWindows.push(window);
|
||||
if (!Main.overview.visible)
|
||||
this._dimWindow(window);
|
||||
} else if (!shouldDim && window._dimmed) {
|
||||
window._dimmed = false;
|
||||
this._dimmedWindows = this._dimmedWindows.filter(function(win) {
|
||||
return win != window;
|
||||
});
|
||||
if (!Main.overview.visible)
|
||||
this._undimWindow(window);
|
||||
}
|
||||
},
|
||||
@ -505,14 +494,14 @@ const WindowManager = new Lang.Class({
|
||||
},
|
||||
|
||||
_filterKeybinding: function(shellwm, binding) {
|
||||
if (Main.keybindingMode == Shell.KeyBindingMode.NONE)
|
||||
if (Main.keybindingMode == Main.KeybindingMode.NONE)
|
||||
return true;
|
||||
|
||||
// There's little sense in implementing a keybinding in mutter and
|
||||
// not having it work in NORMAL mode; handle this case generically
|
||||
// so we don't have to explicitly allow all builtin keybindings in
|
||||
// NORMAL mode.
|
||||
if (Main.keybindingMode == Shell.KeyBindingMode.NORMAL &&
|
||||
if (Main.keybindingMode == Main.KeybindingMode.NORMAL &&
|
||||
binding.is_builtin())
|
||||
return false;
|
||||
|
||||
@ -536,11 +525,11 @@ const WindowManager = new Lang.Class({
|
||||
if (direction == Meta.MotionDirection.UP ||
|
||||
direction == Meta.MotionDirection.UP_LEFT ||
|
||||
direction == Meta.MotionDirection.UP_RIGHT)
|
||||
yDest = global.screen_height - Main.panel.actor.height;
|
||||
yDest = global.screen_height;
|
||||
else if (direction == Meta.MotionDirection.DOWN ||
|
||||
direction == Meta.MotionDirection.DOWN_LEFT ||
|
||||
direction == Meta.MotionDirection.DOWN_RIGHT)
|
||||
yDest = -global.screen_height + Main.panel.actor.height;
|
||||
yDest = -global.screen_height;
|
||||
|
||||
if (direction == Meta.MotionDirection.LEFT ||
|
||||
direction == Meta.MotionDirection.UP_LEFT ||
|
||||
@ -553,9 +542,9 @@ const WindowManager = new Lang.Class({
|
||||
|
||||
let switchData = {};
|
||||
this._switchData = switchData;
|
||||
switchData.inGroup = new Clutter.Actor();
|
||||
switchData.outGroup = new Clutter.Actor();
|
||||
switchData.movingWindowBin = new Clutter.Actor();
|
||||
switchData.inGroup = new Clutter.Group();
|
||||
switchData.outGroup = new Clutter.Group();
|
||||
switchData.movingWindowBin = new Clutter.Group();
|
||||
switchData.windows = [];
|
||||
|
||||
let wgroup = global.window_group;
|
||||
@ -582,7 +571,7 @@ const WindowManager = new Lang.Class({
|
||||
switchData.windows.push({ window: window,
|
||||
parent: window.get_parent() });
|
||||
window.reparent(switchData.inGroup);
|
||||
window.show();
|
||||
window.show_all();
|
||||
}
|
||||
}
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -55,9 +55,10 @@ const WorkspaceSwitcherPopup = new Lang.Class({
|
||||
|
||||
_getPreferredHeight : function (actor, forWidth, alloc) {
|
||||
let children = this._list.get_children();
|
||||
let workArea = Main.layoutManager.getWorkAreaForMonitor(Main.layoutManager.primaryIndex);
|
||||
let primary = Main.layoutManager.primaryMonitor;
|
||||
|
||||
let availHeight = workArea.height;
|
||||
let availHeight = primary.height;
|
||||
availHeight -= Main.panel.actor.height;
|
||||
availHeight -= this.actor.get_theme_node().get_vertical_padding();
|
||||
availHeight -= this._container.get_theme_node().get_vertical_padding();
|
||||
availHeight -= this._list.get_theme_node().get_vertical_padding();
|
||||
@ -66,7 +67,7 @@ const WorkspaceSwitcherPopup = new Lang.Class({
|
||||
for (let i = 0; i < children.length; i++) {
|
||||
let [childMinHeight, childNaturalHeight] = children[i].get_preferred_height(-1);
|
||||
let [childMinWidth, childNaturalWidth] = children[i].get_preferred_width(childNaturalHeight);
|
||||
height += childNaturalHeight * workArea.width / workArea.height;
|
||||
height += childNaturalHeight * primary.width / primary.height;
|
||||
}
|
||||
|
||||
let spacing = this._itemSpacing * (global.screen.n_workspaces - 1);
|
||||
@ -80,8 +81,8 @@ const WorkspaceSwitcherPopup = new Lang.Class({
|
||||
},
|
||||
|
||||
_getPreferredWidth : function (actor, forHeight, alloc) {
|
||||
let workArea = Main.layoutManager.getWorkAreaForMonitor(Main.layoutManager.primaryIndex);
|
||||
this._childWidth = Math.round(this._childHeight * workArea.width / workArea.height);
|
||||
let primary = Main.layoutManager.primaryMonitor;
|
||||
this._childWidth = Math.round(this._childHeight * primary.width / primary.height);
|
||||
|
||||
alloc.min_size = this._childWidth;
|
||||
alloc.natural_size = this._childWidth;
|
||||
@ -121,11 +122,12 @@ const WorkspaceSwitcherPopup = new Lang.Class({
|
||||
|
||||
}
|
||||
|
||||
let workArea = Main.layoutManager.getWorkAreaForMonitor(Main.layoutManager.primaryIndex);
|
||||
let primary = Main.layoutManager.primaryMonitor;
|
||||
let [containerMinHeight, containerNatHeight] = this._container.get_preferred_height(global.screen_width);
|
||||
let [containerMinWidth, containerNatWidth] = this._container.get_preferred_width(containerNatHeight);
|
||||
this._container.x = workArea.x + Math.floor((workArea.width - containerNatWidth) / 2);
|
||||
this._container.y = workArea.y + Math.floor((workArea.height - containerNatHeight) / 2);
|
||||
this._container.x = primary.x + Math.floor((primary.width - containerNatWidth) / 2);
|
||||
this._container.y = primary.y + Main.panel.actor.height +
|
||||
Math.floor(((primary.height - Main.panel.actor.height) - containerNatHeight) / 2);
|
||||
},
|
||||
|
||||
_show : function() {
|
||||
|
@ -9,11 +9,9 @@ const Shell = imports.gi.Shell;
|
||||
const Signals = imports.signals;
|
||||
const St = imports.gi.St;
|
||||
|
||||
const Background = imports.ui.background;
|
||||
const DND = imports.ui.dnd;
|
||||
const Main = imports.ui.main;
|
||||
const Tweener = imports.ui.tweener;
|
||||
const WindowManager = imports.ui.windowManager;
|
||||
const Workspace = imports.ui.workspace;
|
||||
const WorkspacesView = imports.ui.workspacesView;
|
||||
|
||||
@ -32,49 +30,20 @@ const WORKSPACE_KEEP_ALIVE_TIME = 100;
|
||||
|
||||
const OVERRIDE_SCHEMA = 'org.gnome.shell.overrides';
|
||||
|
||||
/* A layout manager that requests size only for primary_actor, but then allocates
|
||||
all using a fixed layout */
|
||||
const PrimaryActorLayout = new Lang.Class({
|
||||
Name: 'PrimaryActorLayout',
|
||||
Extends: Clutter.FixedLayout,
|
||||
|
||||
_init: function(primaryActor) {
|
||||
this.parent();
|
||||
|
||||
this.primaryActor = primaryActor;
|
||||
},
|
||||
|
||||
vfunc_get_preferred_width: function(forHeight) {
|
||||
return this.primaryActor.get_preferred_width(forHeight);
|
||||
},
|
||||
|
||||
vfunc_get_preferred_height: function(forWidth) {
|
||||
return this.primaryActor.get_preferred_height(forWidth);
|
||||
},
|
||||
});
|
||||
|
||||
const WindowClone = new Lang.Class({
|
||||
Name: 'WindowClone',
|
||||
|
||||
_init : function(realWindow) {
|
||||
this.clone = new Clutter.Clone({ source: realWindow });
|
||||
|
||||
/* Can't use a Shell.GenericContainer because of DND and reparenting... */
|
||||
this.actor = new Clutter.Actor({ layout_manager: new PrimaryActorLayout(this.clone),
|
||||
this.actor = new Clutter.Clone({ source: realWindow.get_texture(),
|
||||
reactive: true });
|
||||
this.actor._delegate = this;
|
||||
this.actor.add_child(this.clone);
|
||||
this.realWindow = realWindow;
|
||||
this.metaWindow = realWindow.meta_window;
|
||||
|
||||
this.clone._updateId = this.realWindow.connect('position-changed',
|
||||
this._positionChangedId = this.realWindow.connect('position-changed',
|
||||
Lang.bind(this, this._onPositionChanged));
|
||||
this.clone._destroyId = this.realWindow.connect('destroy', Lang.bind(this, function() {
|
||||
// First destroy the clone and then destroy everything
|
||||
// This will ensure that we never see it in the _disconnectSignals loop
|
||||
this.clone.destroy();
|
||||
this.destroy();
|
||||
}));
|
||||
this._realWindowDestroyedId = this.realWindow.connect('destroy',
|
||||
Lang.bind(this, this._disconnectRealWindowSignals));
|
||||
this._onPositionChanged();
|
||||
|
||||
this.actor.connect('button-release-event',
|
||||
@ -90,24 +59,6 @@ const WindowClone = new Lang.Class({
|
||||
this._draggable.connect('drag-cancelled', Lang.bind(this, this._onDragCancelled));
|
||||
this._draggable.connect('drag-end', Lang.bind(this, this._onDragEnd));
|
||||
this.inDrag = false;
|
||||
|
||||
let iter = Lang.bind(this, function(win) {
|
||||
let actor = win.get_compositor_private();
|
||||
|
||||
if (!actor)
|
||||
return false;
|
||||
if (!win.is_attached_dialog())
|
||||
return false;
|
||||
|
||||
this._doAddAttachedDialog(win, actor);
|
||||
win.foreach_transient(iter);
|
||||
|
||||
return true;
|
||||
});
|
||||
this.metaWindow.foreach_transient(iter);
|
||||
|
||||
this._dimmer = new WindowManager.WindowDimmer(this.clone);
|
||||
this._updateDimmer();
|
||||
},
|
||||
|
||||
setStackAbove: function (actor) {
|
||||
@ -122,57 +73,25 @@ const WindowClone = new Lang.Class({
|
||||
this.actor.destroy();
|
||||
},
|
||||
|
||||
addAttachedDialog: function(win) {
|
||||
this._doAddAttachedDialog(win, win.get_compositor_private());
|
||||
this._updateDimmer();
|
||||
},
|
||||
|
||||
_doAddAttachedDialog: function(metaDialog, realDialog) {
|
||||
let clone = new Clutter.Clone({ source: realDialog });
|
||||
this._updateDialogPosition(realDialog, clone);
|
||||
|
||||
clone._updateId = realDialog.connect('position-changed',
|
||||
Lang.bind(this, this._updateDialogPosition, clone));
|
||||
clone._destroyId = realDialog.connect('destroy', Lang.bind(this, function() {
|
||||
clone.destroy();
|
||||
this._updateDimmer();
|
||||
}));
|
||||
this.actor.add_child(clone);
|
||||
},
|
||||
|
||||
_updateDimmer: function() {
|
||||
if (this.actor.get_n_children() > 1) {
|
||||
this._dimmer.setEnabled(true);
|
||||
this._dimmer.dimFactor = 1.0;
|
||||
} else {
|
||||
this._dimmer.setEnabled(false);
|
||||
}
|
||||
},
|
||||
|
||||
_updateDialogPosition: function(realDialog, cloneDialog) {
|
||||
let metaDialog = realDialog.meta_window;
|
||||
let dialogRect = metaDialog.get_outer_rect();
|
||||
let rect = this.metaWindow.get_outer_rect();
|
||||
|
||||
cloneDialog.set_position(dialogRect.x - rect.x, dialogRect.y - rect.y);
|
||||
},
|
||||
|
||||
_onPositionChanged: function() {
|
||||
let rect = this.metaWindow.get_outer_rect();
|
||||
this.actor.set_position(this.realWindow.x, this.realWindow.y);
|
||||
},
|
||||
|
||||
_disconnectSignals: function() {
|
||||
this.actor.get_children().forEach(function(child) {
|
||||
let realWindow = child.source;
|
||||
_disconnectRealWindowSignals: function() {
|
||||
if (this._positionChangedId != 0) {
|
||||
this.realWindow.disconnect(this._positionChangedId);
|
||||
this._positionChangedId = 0;
|
||||
}
|
||||
|
||||
realWindow.disconnect(child._updateId);
|
||||
realWindow.disconnect(child._destroyId);
|
||||
});
|
||||
if (this._realWindowDestroyedId != 0) {
|
||||
this.realWindow.disconnect(this._realWindowDestroyedId);
|
||||
this._realWindowDestroyedId = 0;
|
||||
}
|
||||
},
|
||||
|
||||
_onDestroy: function() {
|
||||
this._disconnectSignals();
|
||||
this._disconnectRealWindowSignals();
|
||||
|
||||
this.actor._delegate = null;
|
||||
|
||||
@ -246,20 +165,18 @@ const WorkspaceThumbnail = new Lang.Class({
|
||||
style_class: 'workspace-thumbnail' });
|
||||
this.actor._delegate = this;
|
||||
|
||||
this._contents = new Clutter.Actor();
|
||||
this.actor.add_child(this._contents);
|
||||
this._contents = new Clutter.Group();
|
||||
this.actor.add_actor(this._contents);
|
||||
|
||||
this.actor.connect('destroy', Lang.bind(this, this._onDestroy));
|
||||
|
||||
this._createBackground();
|
||||
this._background = Meta.BackgroundActor.new_for_screen(global.screen);
|
||||
this._contents.add_actor(this._background);
|
||||
|
||||
let monitor = Main.layoutManager.primaryMonitor;
|
||||
this.setPorthole(monitor.x, monitor.y, monitor.width, monitor.height);
|
||||
|
||||
let windows = global.get_window_actors().filter(Lang.bind(this, function(actor) {
|
||||
let win = actor.meta_window;
|
||||
return win.located_on_workspace(metaWorkspace);
|
||||
}));
|
||||
let windows = global.get_window_actors().filter(this._isWorkspaceWindow, this);
|
||||
|
||||
// Create clones for windows that should be visible in the Overview
|
||||
this._windows = [];
|
||||
@ -293,12 +210,6 @@ const WorkspaceThumbnail = new Lang.Class({
|
||||
this._collapseFraction = 0; // Not collapsed
|
||||
},
|
||||
|
||||
_createBackground: function() {
|
||||
this._bgManager = new Background.BackgroundManager({ monitorIndex: Main.layoutManager.primaryIndex,
|
||||
container: this._contents,
|
||||
effects: Meta.BackgroundEffects.NONE });
|
||||
},
|
||||
|
||||
setPorthole: function(x, y, width, height) {
|
||||
this._portholeX = x;
|
||||
this._portholeY = y;
|
||||
@ -322,7 +233,7 @@ const WorkspaceThumbnail = new Lang.Class({
|
||||
let clone = this._windows[i];
|
||||
let metaWindow = clone.metaWindow;
|
||||
if (i == 0) {
|
||||
clone.setStackAbove(this._bgManager.background.actor);
|
||||
clone.setStackAbove(this._background);
|
||||
} else {
|
||||
let previousClone = this._windows[i - 1];
|
||||
clone.setStackAbove(previousClone.actor);
|
||||
@ -400,26 +311,10 @@ const WorkspaceThumbnail = new Lang.Class({
|
||||
if (this._lookupIndex (metaWin) != -1)
|
||||
return;
|
||||
|
||||
if (!this._isMyWindow(win))
|
||||
if (!this._isMyWindow(win) || !this._isOverviewWindow(win))
|
||||
return;
|
||||
|
||||
if (this._isOverviewWindow(win)) {
|
||||
this._addWindowClone(win);
|
||||
} else if (metaWin.is_attached_dialog()) {
|
||||
let parent = metaWin.get_transient_for();
|
||||
while (parent.is_attached_dialog())
|
||||
parent = metaWin.get_transient_for();
|
||||
|
||||
let idx = this._lookupIndex (parent);
|
||||
if (idx < 0) {
|
||||
// parent was not created yet, it will take care
|
||||
// of the dialog when created
|
||||
return;
|
||||
}
|
||||
|
||||
let clone = this._windows[idx];
|
||||
clone.addAttachedDialog(metaWin);
|
||||
}
|
||||
let clone = this._addWindowClone(win);
|
||||
},
|
||||
|
||||
_windowAdded : function(metaWorkspace, metaWin) {
|
||||
@ -458,8 +353,6 @@ const WorkspaceThumbnail = new Lang.Class({
|
||||
|
||||
destroy : function() {
|
||||
this.actor.destroy();
|
||||
this._bgManager.destroy();
|
||||
this._bgManager = null;
|
||||
},
|
||||
|
||||
workspaceRemoved : function() {
|
||||
@ -484,11 +377,15 @@ const WorkspaceThumbnail = new Lang.Class({
|
||||
this.actor = null;
|
||||
},
|
||||
|
||||
// Tests if @actor belongs to this workspace and monitor
|
||||
_isMyWindow : function (actor) {
|
||||
let win = actor.meta_window;
|
||||
return win.located_on_workspace(this.metaWorkspace) &&
|
||||
(win.get_monitor() == this.monitorIndex);
|
||||
// Tests if @win belongs to this workspace
|
||||
_isWorkspaceWindow : function (win) {
|
||||
return Main.isWindowActorDisplayedOnWorkspace(win, this.metaWorkspace.index());
|
||||
},
|
||||
|
||||
// Tests if @win belongs to this workspace and monitor
|
||||
_isMyWindow : function (win) {
|
||||
return this._isWorkspaceWindow(win) &&
|
||||
(!win.get_meta_window() || win.get_meta_window().get_monitor() == this.monitorIndex);
|
||||
},
|
||||
|
||||
// Tests if @win should be shown in the Overview
|
||||
@ -521,7 +418,7 @@ const WorkspaceThumbnail = new Lang.Class({
|
||||
this._contents.add_actor(clone.actor);
|
||||
|
||||
if (this._windows.length == 0)
|
||||
clone.setStackAbove(this._bgManager.background.actor);
|
||||
clone.setStackAbove(this._background);
|
||||
else
|
||||
clone.setStackAbove(this._windows[this._windows.length - 1].actor);
|
||||
|
||||
@ -647,6 +544,7 @@ const ThumbnailsBox = new Lang.Class({
|
||||
|
||||
this.actor.connect('button-press-event', function() { return true; });
|
||||
this.actor.connect('button-release-event', Lang.bind(this, this._onButtonRelease));
|
||||
this.actor.connect('scroll-event', Lang.bind(this, this._onScrollEvent));
|
||||
|
||||
Main.overview.connect('showing',
|
||||
Lang.bind(this, this._createThumbnails));
|
||||
@ -685,7 +583,7 @@ const ThumbnailsBox = new Lang.Class({
|
||||
let thumbnail = this._thumbnails[i]
|
||||
let [w, h] = thumbnail.actor.get_transformed_size();
|
||||
if (y >= thumbnail.actor.y && y <= thumbnail.actor.y + h) {
|
||||
thumbnail.activate(event.get_time());
|
||||
thumbnail.activate(event.time);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -861,7 +759,14 @@ const ThumbnailsBox = new Lang.Class({
|
||||
this._stateCounts[ThumbnailState[key]] = 0;
|
||||
|
||||
// The "porthole" is the portion of the screen that we show in the workspaces
|
||||
this._porthole = Main.layoutManager.getWorkAreaForMonitor(Main.layoutManager.primaryIndex);
|
||||
let panelHeight = Main.panel.actor.height;
|
||||
let monitor = Main.layoutManager.primaryMonitor;
|
||||
this._porthole = {
|
||||
x: monitor.x,
|
||||
y: monitor.y + panelHeight,
|
||||
width: monitor.width,
|
||||
height: monitor.height - panelHeight
|
||||
};
|
||||
|
||||
this.addThumbnails(0, global.screen.n_workspaces);
|
||||
|
||||
@ -1095,6 +1000,8 @@ const ThumbnailsBox = new Lang.Class({
|
||||
// See comment about this._background in _init()
|
||||
let themeNode = this._background.get_theme_node();
|
||||
|
||||
forWidth = themeNode.adjust_for_width(forWidth);
|
||||
|
||||
// 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.
|
||||
@ -1310,5 +1217,16 @@ const ThumbnailsBox = new Lang.Class({
|
||||
},
|
||||
onCompleteScope: this
|
||||
});
|
||||
},
|
||||
|
||||
_onScrollEvent: function (actor, event) {
|
||||
switch (event.get_scroll_direction()) {
|
||||
case Clutter.ScrollDirection.UP:
|
||||
Main.wm.actionMoveWorkspace(Meta.MotionDirection.UP);
|
||||
break;
|
||||
case Clutter.ScrollDirection.DOWN:
|
||||
Main.wm.actionMoveWorkspace(Meta.MotionDirection.DOWN);
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -23,13 +23,14 @@ const MAX_WORKSPACES = 16;
|
||||
|
||||
const OVERRIDE_SCHEMA = 'org.gnome.shell.overrides';
|
||||
|
||||
const CONTROLS_POP_IN_TIME = 0.1;
|
||||
|
||||
|
||||
const WorkspacesView = new Lang.Class({
|
||||
Name: 'WorkspacesView',
|
||||
|
||||
_init: function(workspaces) {
|
||||
this.actor = new St.Widget({ style_class: 'workspaces-view',
|
||||
reactive: true });
|
||||
this.actor = new St.Widget({ style_class: 'workspaces-view' });
|
||||
|
||||
// The actor itself isn't a drop target, so we don't want to pick on its area
|
||||
this.actor.set_size(0, 0);
|
||||
@ -47,6 +48,10 @@ const WorkspacesView = new Lang.Class({
|
||||
this._height = 0;
|
||||
this._x = 0;
|
||||
this._y = 0;
|
||||
this._clipX = 0;
|
||||
this._clipY = 0;
|
||||
this._clipWidth = 0;
|
||||
this._clipHeight = 0;
|
||||
this._spacing = 0;
|
||||
this._animating = false; // tweening
|
||||
this._scrolling = false; // swipe-scrolling
|
||||
@ -85,8 +90,8 @@ const WorkspacesView = new Lang.Class({
|
||||
this._overviewShownId =
|
||||
Main.overview.connect('shown',
|
||||
Lang.bind(this, function() {
|
||||
this.actor.set_clip(this._x, this._y,
|
||||
this._width, this._height);
|
||||
this.actor.set_clip(this._clipX, this._clipY,
|
||||
this._clipWidth, this._clipHeight);
|
||||
}));
|
||||
|
||||
this.scrollAdjustment = new St.Adjustment({ value: activeWorkspaceIndex,
|
||||
@ -153,6 +158,13 @@ const WorkspacesView = new Lang.Class({
|
||||
this._workspaces[i].setGeometry(x, y, width, height);
|
||||
},
|
||||
|
||||
setClipRect: function(x, y, width, height) {
|
||||
this._clipX = x;
|
||||
this._clipY = y;
|
||||
this._clipWidth = width;
|
||||
this._clipHeight = height;
|
||||
},
|
||||
|
||||
_lookupWorkspaceForMetaWindow: function (metaWindow) {
|
||||
for (let i = 0; i < this._workspaces.length; i++) {
|
||||
if (this._workspaces[i].containsMetaWindow(metaWindow))
|
||||
@ -191,6 +203,11 @@ const WorkspacesView = new Lang.Class({
|
||||
this._extraWorkspaces[i].syncStacking(stackIndices);
|
||||
},
|
||||
|
||||
updateWindowPositions: function() {
|
||||
for (let w = 0; w < this._workspaces.length; w++)
|
||||
this._workspaces[w].positionWindows(Workspace.WindowPositionFlags.ANIMATE);
|
||||
},
|
||||
|
||||
_scrollToActive: function() {
|
||||
let active = global.screen.get_active_workspace_index();
|
||||
|
||||
@ -420,9 +437,23 @@ const WorkspacesDisplay = new Lang.Class({
|
||||
Name: 'WorkspacesDisplay',
|
||||
|
||||
_init: function() {
|
||||
this.actor = new St.Widget({ clip_to_allocation: true });
|
||||
this.actor.connect('notify::allocation', Lang.bind(this, this._updateWorkspacesGeometry));
|
||||
this.actor = new Shell.GenericContainer({ style_class: 'workspaces-display' });
|
||||
this.actor.connect('get-preferred-width', Lang.bind(this, this._getPreferredWidth));
|
||||
this.actor.connect('get-preferred-height', Lang.bind(this, this._getPreferredHeight));
|
||||
this.actor.connect('allocate', Lang.bind(this, this._allocate));
|
||||
this.actor.connect('parent-set', Lang.bind(this, this._parentSet));
|
||||
this.actor.set_clip_to_allocation(true);
|
||||
|
||||
this._spacing = 0;
|
||||
this.actor.connect('style-changed', Lang.bind(this,
|
||||
function() {
|
||||
let node = this.actor.get_theme_node();
|
||||
let spacing = node.get_length('spacing');
|
||||
if (spacing != this._spacing) {
|
||||
this._spacing = spacing;
|
||||
this._updateWorkspacesGeometry();
|
||||
}
|
||||
}));
|
||||
|
||||
let clickAction = new Clutter.ClickAction()
|
||||
clickAction.connect('clicked', Lang.bind(this, function(action) {
|
||||
@ -443,11 +474,6 @@ const WorkspacesDisplay = new Lang.Class({
|
||||
this._workspacesViews[i].startSwipeScroll();
|
||||
return true;
|
||||
}));
|
||||
panAction.connect('gesture-cancel', Lang.bind(this, function() {
|
||||
clickAction.release();
|
||||
for (let i = 0; i < this._workspacesViews.length; i++)
|
||||
this._workspacesViews[i].endSwipeScroll();
|
||||
}));
|
||||
panAction.connect('gesture-end', Lang.bind(this, function() {
|
||||
clickAction.release();
|
||||
for (let i = 0; i < this._workspacesViews.length; i++)
|
||||
@ -456,8 +482,23 @@ const WorkspacesDisplay = new Lang.Class({
|
||||
Main.overview.addAction(panAction);
|
||||
this.actor.bind_property('mapped', panAction, 'enabled', GObject.BindingFlags.SYNC_CREATE);
|
||||
|
||||
let controls = new St.Bin({ style_class: 'workspace-controls',
|
||||
request_mode: Clutter.RequestMode.WIDTH_FOR_HEIGHT,
|
||||
y_align: St.Align.START,
|
||||
y_fill: true });
|
||||
this._controls = controls;
|
||||
this.actor.add_actor(controls);
|
||||
|
||||
controls.reactive = true;
|
||||
controls.track_hover = true;
|
||||
controls.connect('notify::hover',
|
||||
Lang.bind(this, this._onControlsHoverChanged));
|
||||
|
||||
this._primaryIndex = Main.layoutManager.primaryIndex;
|
||||
|
||||
this._thumbnailsBox = new WorkspaceThumbnail.ThumbnailsBox();
|
||||
controls.add_actor(this._thumbnailsBox.actor);
|
||||
|
||||
this._workspacesViews = [];
|
||||
this._workspaces = [];
|
||||
this._primaryScrollAdjustment = null;
|
||||
@ -468,13 +509,43 @@ const WorkspacesDisplay = new Lang.Class({
|
||||
this._workspacesOnlyOnPrimaryChanged));
|
||||
this._workspacesOnlyOnPrimaryChanged();
|
||||
|
||||
this._inDrag = false;
|
||||
this._cancelledDrag = false;
|
||||
|
||||
this._controlsInitiallyHovered = false;
|
||||
this._alwaysZoomOut = false;
|
||||
this._zoomOut = false;
|
||||
this._zoomFraction = 0;
|
||||
|
||||
this._updateAlwaysZoom();
|
||||
|
||||
// If we stop hiding the overview on layout changes, we will need to
|
||||
// update the _workspacesViews here
|
||||
Main.layoutManager.connect('monitors-changed', Lang.bind(this, this._updateAlwaysZoom));
|
||||
|
||||
Main.xdndHandler.connect('drag-begin', Lang.bind(this, function(){
|
||||
this._alwaysZoomOut = true;
|
||||
}));
|
||||
|
||||
Main.xdndHandler.connect('drag-end', Lang.bind(this, function(){
|
||||
this._alwaysZoomOut = false;
|
||||
this._updateAlwaysZoom();
|
||||
}));
|
||||
|
||||
global.screen.connect('notify::n-workspaces',
|
||||
Lang.bind(this, this._workspacesChanged));
|
||||
|
||||
this._switchWorkspaceNotifyId = 0;
|
||||
|
||||
this._itemDragBeginId = 0;
|
||||
this._itemDragCancelledId = 0;
|
||||
this._itemDragEndId = 0;
|
||||
this._windowDragBeginId = 0;
|
||||
this._windowDragCancelledId = 0;
|
||||
this._windowDragEndId = 0;
|
||||
this._notifyOpacityId = 0;
|
||||
this._scrollEventId = 0;
|
||||
this._swipeScrollBeginId = 0;
|
||||
this._swipeScrollEndId = 0;
|
||||
},
|
||||
|
||||
_onPan: function(action) {
|
||||
@ -485,13 +556,49 @@ const WorkspacesDisplay = new Lang.Class({
|
||||
},
|
||||
|
||||
show: function() {
|
||||
if(!this._alwaysZoomOut) {
|
||||
let [mouseX, mouseY] = global.get_pointer();
|
||||
let [x, y] = this._controls.get_transformed_position();
|
||||
let [width, height] = this._controls.get_transformed_size();
|
||||
let visibleWidth = this._controls.get_theme_node().get_length('visible-width');
|
||||
let rtl = (Clutter.get_default_text_direction () == Clutter.TextDirection.RTL);
|
||||
if(rtl)
|
||||
x = x + width - visibleWidth;
|
||||
if(mouseX > x - 0.5 && mouseX < x + visibleWidth + 0.5 &&
|
||||
mouseY > y - 0.5 && mouseY < y + height + 0.5)
|
||||
this._controlsInitiallyHovered = true;
|
||||
}
|
||||
|
||||
this._zoomOut = this._alwaysZoomOut;
|
||||
this._zoomFraction = this._alwaysZoomOut ? 1 : 0;
|
||||
this._updateZoom();
|
||||
|
||||
this._controls.show();
|
||||
|
||||
this._updateWorkspacesViews();
|
||||
|
||||
this._restackedNotifyId =
|
||||
Main.overview.connect('windows-restacked',
|
||||
Lang.bind(this, this._onRestacked));
|
||||
if (this._scrollEventId == 0)
|
||||
this._scrollEventId = Main.overview.connect('scroll-event', Lang.bind(this, this._onScrollEvent));
|
||||
|
||||
if (this._itemDragBeginId == 0)
|
||||
this._itemDragBeginId = Main.overview.connect('item-drag-begin',
|
||||
Lang.bind(this, this._dragBegin));
|
||||
if (this._itemDragCancelledId == 0)
|
||||
this._itemDragCancelledId = Main.overview.connect('item-drag-cancelled',
|
||||
Lang.bind(this, this._dragCancelled));
|
||||
if (this._itemDragEndId == 0)
|
||||
this._itemDragEndId = Main.overview.connect('item-drag-end',
|
||||
Lang.bind(this, this._dragEnd));
|
||||
if (this._windowDragBeginId == 0)
|
||||
this._windowDragBeginId = Main.overview.connect('window-drag-begin',
|
||||
Lang.bind(this, this._dragBegin));
|
||||
if (this._windowDragCancelledId == 0)
|
||||
this._windowDragCancelledId = Main.overview.connect('window-drag-cancelled',
|
||||
Lang.bind(this, this._dragCancelled));
|
||||
if (this._windowDragEndId == 0)
|
||||
this._windowDragEndId = Main.overview.connect('window-drag-end',
|
||||
Lang.bind(this, this._dragEnd));
|
||||
},
|
||||
|
||||
zoomFromOverview: function() {
|
||||
@ -501,13 +608,38 @@ const WorkspacesDisplay = new Lang.Class({
|
||||
},
|
||||
|
||||
hide: function() {
|
||||
this._controls.hide();
|
||||
|
||||
if (!this._alwaysZoomOut)
|
||||
this.zoomFraction = 0;
|
||||
|
||||
if (this._restackedNotifyId > 0){
|
||||
Main.overview.disconnect(this._restackedNotifyId);
|
||||
this._restackedNotifyId = 0;
|
||||
}
|
||||
if (this._scrollEventId > 0) {
|
||||
Main.overview.disconnect(this._scrollEventId);
|
||||
this._scrollEventId = 0;
|
||||
if (this._itemDragBeginId > 0) {
|
||||
Main.overview.disconnect(this._itemDragBeginId);
|
||||
this._itemDragBeginId = 0;
|
||||
}
|
||||
if (this._itemDragCancelledId > 0) {
|
||||
Main.overview.disconnect(this._itemDragCancelledId);
|
||||
this._itemDragCancelledId = 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._windowDragCancelledId > 0) {
|
||||
Main.overview.disconnect(this._windowDragCancelledId);
|
||||
this._windowDragCancelledId = 0;
|
||||
}
|
||||
if (this._windowDragEndId > 0) {
|
||||
Main.overview.disconnect(this._windowDragEndId);
|
||||
this._windowDragEndId = 0;
|
||||
}
|
||||
|
||||
for (let i = 0; i < this._workspacesViews.length; i++)
|
||||
@ -554,7 +686,6 @@ const WorkspacesDisplay = new Lang.Class({
|
||||
this._workspaces.push(monitorWorkspaces);
|
||||
|
||||
let view = new WorkspacesView(monitorWorkspaces);
|
||||
view.actor.connect('scroll-event', Lang.bind(this, this._onScrollEvent));
|
||||
if (this._workspacesOnlyOnPrimary || i == this._primaryIndex) {
|
||||
this._scrollAdjustment = view.scrollAdjustment;
|
||||
this._scrollAdjustment.connect('notify::value',
|
||||
@ -597,6 +728,76 @@ const WorkspacesDisplay = new Lang.Class({
|
||||
return this._getPrimaryView().getActiveWorkspace().hasMaximizedWindows();
|
||||
},
|
||||
|
||||
// zoomFraction property allows us to tween the controls sliding in and out
|
||||
set zoomFraction(fraction) {
|
||||
this._zoomFraction = fraction;
|
||||
this.actor.queue_relayout();
|
||||
},
|
||||
|
||||
get zoomFraction() {
|
||||
return this._zoomFraction;
|
||||
},
|
||||
|
||||
_updateAlwaysZoom: function() {
|
||||
// Always show the pager if workspaces are actually used,
|
||||
// e.g. there are windows on more than one
|
||||
this._alwaysZoomOut = global.screen.n_workspaces > 2;
|
||||
|
||||
if (this._alwaysZoomOut)
|
||||
return;
|
||||
|
||||
let monitors = Main.layoutManager.monitors;
|
||||
let primary = Main.layoutManager.primaryMonitor;
|
||||
|
||||
/* Look for any monitor to the right of the primary, if there is
|
||||
* one, we always keep zoom out, otherwise its hard to reach
|
||||
* the thumbnail area without passing into the next monitor. */
|
||||
for (let i = 0; i < monitors.length; i++) {
|
||||
if (monitors[i].x >= primary.x + primary.width) {
|
||||
this._alwaysZoomOut = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
_getPreferredWidth: function (actor, forHeight, alloc) {
|
||||
// pass through the call in case the child needs it, but report 0x0
|
||||
this._controls.get_preferred_width(forHeight);
|
||||
},
|
||||
|
||||
_getPreferredHeight: function (actor, forWidth, alloc) {
|
||||
// pass through the call in case the child needs it, but report 0x0
|
||||
this._controls.get_preferred_height(forWidth);
|
||||
},
|
||||
|
||||
_allocate: function (actor, box, flags) {
|
||||
let childBox = new Clutter.ActorBox();
|
||||
|
||||
let totalWidth = box.x2 - box.x1;
|
||||
|
||||
// width of the controls
|
||||
let [controlsMin, controlsNatural] = this._controls.get_preferred_width(box.y2 - box.y1);
|
||||
|
||||
// Amount of space on the screen we reserve for the visible control
|
||||
let controlsVisible = this._controls.get_theme_node().get_length('visible-width');
|
||||
let controlsReserved = controlsVisible * (1 - this._zoomFraction) + controlsNatural * this._zoomFraction;
|
||||
|
||||
let rtl = (Clutter.get_default_text_direction () == Clutter.TextDirection.RTL);
|
||||
if (rtl) {
|
||||
childBox.x2 = controlsReserved;
|
||||
childBox.x1 = childBox.x2 - controlsNatural;
|
||||
} else {
|
||||
childBox.x1 = totalWidth - controlsReserved;
|
||||
childBox.x2 = childBox.x1 + controlsNatural;
|
||||
}
|
||||
|
||||
childBox.y1 = 0;
|
||||
childBox.y2 = box.y2- box.y1;
|
||||
this._controls.allocate(childBox, flags);
|
||||
|
||||
this._updateWorkspacesGeometry();
|
||||
},
|
||||
|
||||
_parentSet: function(actor, oldParent) {
|
||||
if (oldParent && this._notifyOpacityId)
|
||||
oldParent.disconnect(this._notifyOpacityId);
|
||||
@ -633,17 +834,37 @@ const WorkspacesDisplay = new Lang.Class({
|
||||
let width = fullWidth;
|
||||
let height = fullHeight;
|
||||
|
||||
let [controlsMin, controlsNatural] = this._controls.get_preferred_width(height);
|
||||
let controlsVisible = this._controls.get_theme_node().get_length('visible-width');
|
||||
|
||||
let [x, y] = this.actor.get_transformed_position();
|
||||
|
||||
let rtl = (Clutter.get_default_text_direction () == Clutter.TextDirection.RTL);
|
||||
|
||||
let clipWidth = width - controlsVisible;
|
||||
let clipHeight = fullHeight;
|
||||
let clipX = rtl ? x + controlsVisible : x;
|
||||
let clipY = y + (fullHeight - clipHeight) / 2;
|
||||
|
||||
let widthAdjust = this._zoomOut ? controlsNatural : controlsVisible;
|
||||
widthAdjust += this._spacing;
|
||||
width -= widthAdjust;
|
||||
if (rtl)
|
||||
x += widthAdjust;
|
||||
|
||||
let monitors = Main.layoutManager.monitors;
|
||||
let m = 0;
|
||||
for (let i = 0; i < monitors.length; i++) {
|
||||
if (i == this._primaryIndex) {
|
||||
this._workspacesViews[m].setClipRect(clipX, clipY,
|
||||
clipWidth, clipHeight);
|
||||
this._workspacesViews[m].setGeometry(x, y, width, height);
|
||||
m++;
|
||||
} else if (!this._workspacesOnlyOnPrimary) {
|
||||
this._workspacesViews[m].setClipRect(monitors[i].x,
|
||||
monitors[i].y,
|
||||
monitors[i].width,
|
||||
monitors[i].height);
|
||||
this._workspacesViews[m].setGeometry(monitors[i].x,
|
||||
monitors[i].y,
|
||||
monitors[i].width,
|
||||
@ -659,6 +880,9 @@ const WorkspacesDisplay = new Lang.Class({
|
||||
},
|
||||
|
||||
_workspacesChanged: function() {
|
||||
this._updateAlwaysZoom();
|
||||
this._updateZoom();
|
||||
|
||||
if (!this._workspacesViews.length)
|
||||
return;
|
||||
|
||||
@ -712,18 +936,66 @@ const WorkspacesDisplay = new Lang.Class({
|
||||
newNumWorkspaces);
|
||||
},
|
||||
|
||||
_onScrollEvent: function(actor, event) {
|
||||
if (!this.actor.mapped)
|
||||
return false;
|
||||
switch (event.get_scroll_direction()) {
|
||||
case Clutter.ScrollDirection.UP:
|
||||
Main.wm.actionMoveWorkspace(Meta.MotionDirection.UP);
|
||||
return true;
|
||||
case Clutter.ScrollDirection.DOWN:
|
||||
Main.wm.actionMoveWorkspace(Meta.MotionDirection.DOWN);
|
||||
return true;
|
||||
_updateZoom : function() {
|
||||
if (Main.overview.animationInProgress)
|
||||
return;
|
||||
|
||||
let shouldZoom = this._alwaysZoomOut || this._controls.hover;
|
||||
if (shouldZoom != this._zoomOut) {
|
||||
this._zoomOut = shouldZoom;
|
||||
this._updateWorkspacesGeometry();
|
||||
|
||||
if (!this._workspacesViews.length)
|
||||
return;
|
||||
|
||||
Tweener.addTween(this,
|
||||
{ zoomFraction: this._zoomOut ? 1 : 0,
|
||||
time: WORKSPACE_SWITCH_TIME,
|
||||
transition: 'easeOutQuad' });
|
||||
|
||||
for (let i = 0; i < this._workspacesViews.length; i++)
|
||||
this._workspacesViews[i].updateWindowPositions();
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
_onControlsHoverChanged: function() {
|
||||
if(!this._controls.hover)
|
||||
this._controlsInitiallyHovered = false;
|
||||
if(!this._controlsInitiallyHovered)
|
||||
this._updateZoom();
|
||||
},
|
||||
|
||||
_dragBegin: function() {
|
||||
this._inDrag = true;
|
||||
this._cancelledDrag = false;
|
||||
this._dragMonitor = {
|
||||
dragMotion: Lang.bind(this, this._onDragMotion)
|
||||
};
|
||||
DND.addDragMonitor(this._dragMonitor);
|
||||
},
|
||||
|
||||
_dragCancelled: function() {
|
||||
this._cancelledDrag = true;
|
||||
DND.removeDragMonitor(this._dragMonitor);
|
||||
},
|
||||
|
||||
_onDragMotion: function(dragEvent) {
|
||||
let controlsHovered = this._controls.contains(dragEvent.targetActor);
|
||||
this._controls.set_hover(controlsHovered);
|
||||
|
||||
return DND.DragMotionResult.CONTINUE;
|
||||
},
|
||||
|
||||
_dragEnd: function() {
|
||||
this._inDrag = false;
|
||||
|
||||
// We do this deferred because drag-end is emitted before dnd.js emits
|
||||
// event/leave events that were suppressed during the drag. If we didn't
|
||||
// defer this, we'd zoom out then immediately zoom in because of the
|
||||
// enter event we received. That would normally be invisible but we
|
||||
// might as well avoid it.
|
||||
Meta.later_add(Meta.LaterType.BEFORE_REDRAW,
|
||||
Lang.bind(this, this._updateZoom));
|
||||
}
|
||||
});
|
||||
Signals.addSignalMethods(WorkspacesDisplay.prototype);
|
||||
|
@ -2,7 +2,6 @@
|
||||
|
||||
const Clutter = imports.gi.Clutter;
|
||||
const Lang = imports.lang;
|
||||
const Main = imports.ui.main;
|
||||
const Shell = imports.gi.Shell;
|
||||
const Signals = imports.signals;
|
||||
const DND = imports.ui.dnd;
|
||||
@ -17,11 +16,18 @@ const XdndHandler = new Lang.Class({
|
||||
|
||||
// Used as a drag actor in case we don't have a cursor window clone
|
||||
this._dummy = new Clutter.Rectangle({ width: 1, height: 1, opacity: 0 });
|
||||
Main.uiGroup.add_actor(this._dummy);
|
||||
global.stage.add_actor(this._dummy);
|
||||
Shell.util_set_hidden_from_pick(this._dummy, true);
|
||||
this._dummy.hide();
|
||||
|
||||
// Mutter delays the creation of the output window as long
|
||||
// as possible to avoid flicker. In case a plugin wants to
|
||||
// access it directly it has to connect to the stage's show
|
||||
// signal. (see comment in compositor.c:meta_compositor_manage_screen)
|
||||
global.stage.connect('show', function () {
|
||||
global.init_xdnd();
|
||||
return false;
|
||||
});
|
||||
|
||||
global.connect('xdnd-enter', Lang.bind(this, this._onEnter));
|
||||
global.connect('xdnd-position-changed', Lang.bind(this, this._onPositionChanged));
|
||||
@ -68,7 +74,7 @@ const XdndHandler = new Lang.Class({
|
||||
source: cursorWindow});
|
||||
|
||||
this._cursorWindowClone = new Clutter.Clone({ source: cursorWindow });
|
||||
Main.uiGroup.add_actor(this._cursorWindowClone);
|
||||
global.overlay_group.add_actor(this._cursorWindowClone);
|
||||
Shell.util_set_hidden_from_pick(this._cursorWindowClone, true);
|
||||
|
||||
// Make sure that the clone has the same position as the source
|
||||
@ -82,7 +88,7 @@ const XdndHandler = new Lang.Class({
|
||||
},
|
||||
|
||||
_onPositionChanged: function(obj, x, y) {
|
||||
let pickedActor = global.stage.get_actor_at_pos(Clutter.PickMode.REACTIVE, x, y);
|
||||
let pickedActor = global.stage.get_actor_at_pos(Clutter.PickMode.ALL, x, y);
|
||||
|
||||
// Make sure that the cursor window is on top
|
||||
if (this._cursorWindowClone)
|
||||
|
@ -21,7 +21,6 @@ eu
|
||||
fa
|
||||
fi
|
||||
fr
|
||||
fur
|
||||
ga
|
||||
gl
|
||||
gu
|
||||
|
@ -1,6 +1,3 @@
|
||||
# List of source files containing translatable strings.
|
||||
# Please keep this file sorted alphabetically.
|
||||
[encoding: UTF-8]
|
||||
data/50-gnome-shell-screenshot.xml.in
|
||||
data/50-gnome-shell-system.xml.in
|
||||
data/gnome-shell.desktop.in.in
|
||||
@ -13,9 +10,7 @@ js/gdm/util.js
|
||||
js/misc/util.js
|
||||
js/ui/appDisplay.js
|
||||
js/ui/appFavorites.js
|
||||
js/ui/backgroundMenu.js
|
||||
js/ui/calendar.js
|
||||
js/ui/components/automountManager.js
|
||||
js/ui/components/autorunManager.js
|
||||
js/ui/components/keyring.js
|
||||
js/ui/components/networkAgent.js
|
||||
@ -33,7 +28,6 @@ js/ui/lookingGlass.js
|
||||
js/ui/main.js
|
||||
js/ui/messageTray.js
|
||||
js/ui/notificationDaemon.js
|
||||
js/ui/overviewControls.js
|
||||
js/ui/overview.js
|
||||
js/ui/panel.js
|
||||
js/ui/popupMenu.js
|
||||
@ -61,5 +55,6 @@ src/shell-app.c
|
||||
src/shell-app-system.c
|
||||
src/shell-global.c
|
||||
src/shell-keyring-prompt.c
|
||||
src/shell-mobile-providers.c
|
||||
src/shell-polkit-authentication-agent.c
|
||||
src/shell-util.c
|
||||
|
237
po/ar.po
237
po/ar.po
@ -8,7 +8,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: HEAD\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2012-12-23 18:34+0200\n"
|
||||
"POT-Creation-Date: 2012-12-09 04:45+0200\n"
|
||||
"PO-Revision-Date: 2012-12-09 04:52+0200\n"
|
||||
"Last-Translator: Khaled Hosny <khaledhosny@eglug.org>\n"
|
||||
"Language-Team: Arabic <doc@arabeyes.org>\n"
|
||||
@ -365,8 +365,8 @@ msgstr "نافذة الولوج"
|
||||
msgid "Power"
|
||||
msgstr "الطاقة"
|
||||
|
||||
#: ../js/gdm/powerMenu.js:93 ../js/ui/userMenu.js:675 ../js/ui/userMenu.js:679
|
||||
#: ../js/ui/userMenu.js:790
|
||||
#: ../js/gdm/powerMenu.js:93 ../js/ui/userMenu.js:674 ../js/ui/userMenu.js:678
|
||||
#: ../js/ui/userMenu.js:789
|
||||
msgid "Suspend"
|
||||
msgstr "علّق"
|
||||
|
||||
@ -374,8 +374,8 @@ msgstr "علّق"
|
||||
msgid "Restart"
|
||||
msgstr "أعِد التشغيل"
|
||||
|
||||
#: ../js/gdm/powerMenu.js:103 ../js/ui/userMenu.js:677
|
||||
#: ../js/ui/userMenu.js:679 ../js/ui/userMenu.js:789
|
||||
#: ../js/gdm/powerMenu.js:103 ../js/ui/userMenu.js:676
|
||||
#: ../js/ui/userMenu.js:678 ../js/ui/userMenu.js:788
|
||||
msgid "Power Off"
|
||||
msgstr "أطفئ الحاسوب"
|
||||
|
||||
@ -410,19 +410,27 @@ msgid "Execution of '%s' failed:"
|
||||
msgstr "فشل تنفيذ '%s':"
|
||||
|
||||
#. Translators: Filter to display all applications
|
||||
#: ../js/ui/appDisplay.js:258
|
||||
#: ../js/ui/appDisplay.js:259
|
||||
msgid "All"
|
||||
msgstr "الكل"
|
||||
|
||||
#: ../js/ui/appDisplay.js:666
|
||||
#: ../js/ui/appDisplay.js:318
|
||||
msgid "APPLICATIONS"
|
||||
msgstr "التطبيقات"
|
||||
|
||||
#: ../js/ui/appDisplay.js:375
|
||||
msgid "SETTINGS"
|
||||
msgstr "الإعدادات"
|
||||
|
||||
#: ../js/ui/appDisplay.js:679
|
||||
msgid "New Window"
|
||||
msgstr "نافذة جديدة"
|
||||
|
||||
#: ../js/ui/appDisplay.js:669 ../js/ui/dash.js:289
|
||||
#: ../js/ui/appDisplay.js:682 ../js/ui/dash.js:289
|
||||
msgid "Remove from Favorites"
|
||||
msgstr "أزِل من المفضّلة"
|
||||
|
||||
#: ../js/ui/appDisplay.js:670
|
||||
#: ../js/ui/appDisplay.js:683
|
||||
msgid "Add to Favorites"
|
||||
msgstr "أضِف إلى المفضّلة"
|
||||
|
||||
@ -439,19 +447,19 @@ msgstr "أُزيل %s من مفضّلتك."
|
||||
#. Translators: Shown in calendar event list for all day events
|
||||
#. * Keep it short, best if you can use less then 10 characters
|
||||
#.
|
||||
#: ../js/ui/calendar.js:61
|
||||
#: ../js/ui/calendar.js:62
|
||||
msgctxt "event list time"
|
||||
msgid "All Day"
|
||||
msgstr "طوال اليوم"
|
||||
|
||||
#. Translators: Shown in calendar event list, if 24h format
|
||||
#: ../js/ui/calendar.js:66
|
||||
#: ../js/ui/calendar.js:67
|
||||
msgctxt "event list time"
|
||||
msgid "%H:%M"
|
||||
msgstr "%H:%M"
|
||||
|
||||
#. Transators: Shown in calendar event list, if 12h format
|
||||
#: ../js/ui/calendar.js:73
|
||||
#: ../js/ui/calendar.js:74
|
||||
msgctxt "event list time"
|
||||
msgid "%l:%M %p"
|
||||
msgstr "%l:%M %p"
|
||||
@ -461,43 +469,43 @@ msgstr "%l:%M %p"
|
||||
#. * NOTE: These grid abbreviations are always shown together
|
||||
#. * and in order, e.g. "S M T W T F S".
|
||||
#.
|
||||
#: ../js/ui/calendar.js:104
|
||||
#: ../js/ui/calendar.js:114
|
||||
msgctxt "grid sunday"
|
||||
msgid "S"
|
||||
msgstr "ح"
|
||||
|
||||
#. Translators: Calendar grid abbreviation for Monday
|
||||
#: ../js/ui/calendar.js:106
|
||||
#: ../js/ui/calendar.js:116
|
||||
msgctxt "grid monday"
|
||||
msgid "M"
|
||||
msgstr "ن"
|
||||
|
||||
#. Translators: Calendar grid abbreviation for Tuesday
|
||||
#: ../js/ui/calendar.js:108
|
||||
#: ../js/ui/calendar.js:118
|
||||
msgctxt "grid tuesday"
|
||||
msgid "T"
|
||||
msgstr "ث"
|
||||
|
||||
#. Translators: Calendar grid abbreviation for Wednesday
|
||||
#: ../js/ui/calendar.js:110
|
||||
#: ../js/ui/calendar.js:120
|
||||
msgctxt "grid wednesday"
|
||||
msgid "W"
|
||||
msgstr "ر"
|
||||
|
||||
#. Translators: Calendar grid abbreviation for Thursday
|
||||
#: ../js/ui/calendar.js:112
|
||||
#: ../js/ui/calendar.js:122
|
||||
msgctxt "grid thursday"
|
||||
msgid "T"
|
||||
msgstr "خ"
|
||||
|
||||
#. Translators: Calendar grid abbreviation for Friday
|
||||
#: ../js/ui/calendar.js:114
|
||||
#: ../js/ui/calendar.js:124
|
||||
msgctxt "grid friday"
|
||||
msgid "F"
|
||||
msgstr "ج"
|
||||
|
||||
#. Translators: Calendar grid abbreviation for Saturday
|
||||
#: ../js/ui/calendar.js:116
|
||||
#: ../js/ui/calendar.js:126
|
||||
msgctxt "grid saturday"
|
||||
msgid "S"
|
||||
msgstr "س"
|
||||
@ -508,77 +516,77 @@ msgstr "س"
|
||||
#. * so they need to be unique (e.g. Tuesday and Thursday cannot
|
||||
#. * both be 'T').
|
||||
#.
|
||||
#: ../js/ui/calendar.js:129
|
||||
#: ../js/ui/calendar.js:139
|
||||
msgctxt "list sunday"
|
||||
msgid "Su"
|
||||
msgstr "الأحد"
|
||||
|
||||
#. Translators: Event list abbreviation for Monday
|
||||
#: ../js/ui/calendar.js:131
|
||||
#: ../js/ui/calendar.js:141
|
||||
msgctxt "list monday"
|
||||
msgid "M"
|
||||
msgstr "الاثنين"
|
||||
|
||||
#. Translators: Event list abbreviation for Tuesday
|
||||
#: ../js/ui/calendar.js:133
|
||||
#: ../js/ui/calendar.js:143
|
||||
msgctxt "list tuesday"
|
||||
msgid "T"
|
||||
msgstr "الثلاثاء"
|
||||
|
||||
#. Translators: Event list abbreviation for Wednesday
|
||||
#: ../js/ui/calendar.js:135
|
||||
#: ../js/ui/calendar.js:145
|
||||
msgctxt "list wednesday"
|
||||
msgid "W"
|
||||
msgstr "الأربعاء"
|
||||
|
||||
#. Translators: Event list abbreviation for Thursday
|
||||
#: ../js/ui/calendar.js:137
|
||||
#: ../js/ui/calendar.js:147
|
||||
msgctxt "list thursday"
|
||||
msgid "Th"
|
||||
msgstr "الخميس"
|
||||
|
||||
#. Translators: Event list abbreviation for Friday
|
||||
#: ../js/ui/calendar.js:139
|
||||
#: ../js/ui/calendar.js:149
|
||||
msgctxt "list friday"
|
||||
msgid "F"
|
||||
msgstr "الجمعة"
|
||||
|
||||
#. Translators: Event list abbreviation for Saturday
|
||||
#: ../js/ui/calendar.js:141
|
||||
#: ../js/ui/calendar.js:151
|
||||
msgctxt "list saturday"
|
||||
msgid "S"
|
||||
msgstr "السبت"
|
||||
|
||||
#. Translators: Text to show if there are no events
|
||||
#: ../js/ui/calendar.js:674
|
||||
#: ../js/ui/calendar.js:700
|
||||
msgid "Nothing Scheduled"
|
||||
msgstr "الجدول خال"
|
||||
|
||||
#. Translators: Shown on calendar heading when selected day occurs on current year
|
||||
#: ../js/ui/calendar.js:690
|
||||
#: ../js/ui/calendar.js:716
|
||||
msgctxt "calendar heading"
|
||||
msgid "%A, %B %d"
|
||||
msgstr "%A %d %B"
|
||||
|
||||
#. Translators: Shown on calendar heading when selected day occurs on different year
|
||||
#: ../js/ui/calendar.js:693
|
||||
#: ../js/ui/calendar.js:719
|
||||
msgctxt "calendar heading"
|
||||
msgid "%A, %B %d, %Y"
|
||||
msgstr "%A %d %B %Y"
|
||||
|
||||
#: ../js/ui/calendar.js:703
|
||||
#: ../js/ui/calendar.js:729
|
||||
msgid "Today"
|
||||
msgstr "اليوم"
|
||||
|
||||
#: ../js/ui/calendar.js:707
|
||||
#: ../js/ui/calendar.js:733
|
||||
msgid "Tomorrow"
|
||||
msgstr "غدا"
|
||||
|
||||
#: ../js/ui/calendar.js:718
|
||||
#: ../js/ui/calendar.js:744
|
||||
msgid "This week"
|
||||
msgstr "هذا الأسبوع"
|
||||
|
||||
#: ../js/ui/calendar.js:726
|
||||
#: ../js/ui/calendar.js:752
|
||||
msgid "Next week"
|
||||
msgstr "الأسبوع القادم"
|
||||
|
||||
@ -940,7 +948,7 @@ msgstr "أظهر الحساب"
|
||||
msgid "Unknown reason"
|
||||
msgstr "السبب غير معروف"
|
||||
|
||||
#: ../js/ui/ctrlAltTab.js:29 ../js/ui/viewSelector.js:81
|
||||
#: ../js/ui/ctrlAltTab.js:29 ../js/ui/viewSelector.js:87
|
||||
msgid "Windows"
|
||||
msgstr "النوافذ"
|
||||
|
||||
@ -1080,7 +1088,7 @@ msgstr "هل تريد تنزيل وتثبيت '%s' من extensions.gnome.org؟"
|
||||
msgid "tray"
|
||||
msgstr "لوحة النظام"
|
||||
|
||||
#: ../js/ui/keyboard.js:555 ../js/ui/status/keyboard.js:309
|
||||
#: ../js/ui/keyboard.js:555 ../js/ui/status/keyboard.js:195
|
||||
#: ../js/ui/status/power.js:205
|
||||
msgid "Keyboard"
|
||||
msgstr "لوحة المفاتيح"
|
||||
@ -1107,9 +1115,7 @@ msgstr "اظهر الأخطاء"
|
||||
msgid "Enabled"
|
||||
msgstr "مفعّل"
|
||||
|
||||
#. translators:
|
||||
#. * The device has been disabled
|
||||
#: ../js/ui/lookingGlass.js:767 ../src/gvc/gvc-mixer-control.c:1830
|
||||
#: ../js/ui/lookingGlass.js:767
|
||||
msgid "Disabled"
|
||||
msgstr "معطّل"
|
||||
|
||||
@ -1141,15 +1147,15 @@ msgstr "افتح"
|
||||
msgid "Remove"
|
||||
msgstr "أزِل"
|
||||
|
||||
#: ../js/ui/messageTray.js:1552
|
||||
#: ../js/ui/messageTray.js:1551
|
||||
msgid "No Messages"
|
||||
msgstr "لا رسائل"
|
||||
|
||||
#: ../js/ui/messageTray.js:1570
|
||||
#: ../js/ui/messageTray.js:1568
|
||||
msgid "Message Tray"
|
||||
msgstr "لوحة الرسائل"
|
||||
|
||||
#: ../js/ui/messageTray.js:2639
|
||||
#: ../js/ui/messageTray.js:2635
|
||||
msgid "System Information"
|
||||
msgstr "معلومات النظام"
|
||||
|
||||
@ -1158,11 +1164,11 @@ msgctxt "program"
|
||||
msgid "Unknown"
|
||||
msgstr "غير معروف"
|
||||
|
||||
#: ../js/ui/overview.js:92
|
||||
#: ../js/ui/overview.js:95
|
||||
msgid "Undo"
|
||||
msgstr "تراجع"
|
||||
|
||||
#: ../js/ui/overview.js:139
|
||||
#: ../js/ui/overview.js:144
|
||||
msgid "Overview"
|
||||
msgstr "نظرة عامة"
|
||||
|
||||
@ -1170,13 +1176,13 @@ msgstr "نظرة عامة"
|
||||
#. in the search entry when no search is
|
||||
#. active; it should not exceed ~30
|
||||
#. characters.
|
||||
#: ../js/ui/overview.js:218
|
||||
#: ../js/ui/overview.js:221
|
||||
msgid "Type to search..."
|
||||
msgstr "اكتب نصا للبحث عنه..."
|
||||
|
||||
#. Translators: this is the name of the dock/favorites area on
|
||||
#. the left of the overview
|
||||
#: ../js/ui/overview.js:236
|
||||
#: ../js/ui/overview.js:242
|
||||
msgid "Dash"
|
||||
msgstr "الشريط"
|
||||
|
||||
@ -1199,7 +1205,7 @@ msgstr "الشريط العلوي"
|
||||
#. "ON" and "OFF") or "toggle-switch-intl" (for toggle
|
||||
#. switches containing "◯" and "|"). Other values will
|
||||
#. simply result in invisible toggle switches.
|
||||
#: ../js/ui/popupMenu.js:725
|
||||
#: ../js/ui/popupMenu.js:732
|
||||
msgid "toggle-switch-us"
|
||||
msgstr "toggle-switch-intl"
|
||||
|
||||
@ -1239,15 +1245,15 @@ msgstr[3] "%d تنبيهات جديدة"
|
||||
msgstr[4] "%d تنبيها جديدا"
|
||||
msgstr[5] "%d تنبيه جديد"
|
||||
|
||||
#: ../js/ui/screenShield.js:402 ../js/ui/userMenu.js:781
|
||||
#: ../js/ui/screenShield.js:402 ../js/ui/userMenu.js:780
|
||||
msgid "Lock"
|
||||
msgstr "أوصِد"
|
||||
|
||||
#: ../js/ui/searchDisplay.js:403
|
||||
#: ../js/ui/searchDisplay.js:277
|
||||
msgid "Searching..."
|
||||
msgstr "يبحث..."
|
||||
|
||||
#: ../js/ui/searchDisplay.js:451
|
||||
#: ../js/ui/searchDisplay.js:325
|
||||
msgid "No results."
|
||||
msgstr "لا نتائج."
|
||||
|
||||
@ -1363,7 +1369,7 @@ msgid "disconnecting..."
|
||||
msgstr "يقطع الاتّصال..."
|
||||
|
||||
#: ../js/ui/status/bluetooth.js:220 ../js/ui/status/network.js:442
|
||||
#: ../js/ui/status/network.js:1464
|
||||
#: ../js/ui/status/network.js:1453
|
||||
msgid "connecting..."
|
||||
msgstr "يتّصل..."
|
||||
|
||||
@ -1379,7 +1385,7 @@ msgstr "إعدادات لوحة المفاتيح"
|
||||
msgid "Mouse Settings"
|
||||
msgstr "إعدادات الفأرة"
|
||||
|
||||
#: ../js/ui/status/bluetooth.js:253 ../js/ui/status/volume.js:314
|
||||
#: ../js/ui/status/bluetooth.js:253 ../js/ui/status/volume.js:270
|
||||
msgid "Sound Settings"
|
||||
msgstr "إعدادات الصوت"
|
||||
|
||||
@ -1443,15 +1449,15 @@ msgstr "من فضلك أدخل الرقم المذكور على الجهاز."
|
||||
msgid "OK"
|
||||
msgstr "حسنا"
|
||||
|
||||
#: ../js/ui/status/keyboard.js:363
|
||||
#: ../js/ui/status/keyboard.js:228
|
||||
msgid "Show Keyboard Layout"
|
||||
msgstr "أظهر تخطيط لوحة المفاتيح"
|
||||
|
||||
#: ../js/ui/status/keyboard.js:368
|
||||
#: ../js/ui/status/keyboard.js:233
|
||||
msgid "Region and Language Settings"
|
||||
msgstr "إعدادات الإقليم واللغة"
|
||||
|
||||
#: ../js/ui/status/lockScreenMenu.js:43
|
||||
#: ../js/ui/status/lockScreenMenu.js:18
|
||||
msgid "Volume, network, battery"
|
||||
msgstr "الصوت، الشبكة، البطارية"
|
||||
|
||||
@ -1471,7 +1477,7 @@ msgid "unmanaged"
|
||||
msgstr "غير مُدار"
|
||||
|
||||
#. Translators: this is for network connections that require some kind of key or password
|
||||
#: ../js/ui/status/network.js:445 ../js/ui/status/network.js:1467
|
||||
#: ../js/ui/status/network.js:445 ../js/ui/status/network.js:1456
|
||||
msgid "authentication required"
|
||||
msgstr "الاستيثاق مطلوب"
|
||||
|
||||
@ -1492,72 +1498,72 @@ msgstr "الكبل مفصول"
|
||||
msgid "unavailable"
|
||||
msgstr "غير متاح"
|
||||
|
||||
#: ../js/ui/status/network.js:469 ../js/ui/status/network.js:1469
|
||||
#: ../js/ui/status/network.js:469 ../js/ui/status/network.js:1458
|
||||
msgid "connection failed"
|
||||
msgstr "فشل الاتصال"
|
||||
|
||||
#: ../js/ui/status/network.js:525 ../js/ui/status/network.js:1403
|
||||
#: ../js/ui/status/network.js:1545
|
||||
#: ../js/ui/status/network.js:525 ../js/ui/status/network.js:1392
|
||||
#: ../js/ui/status/network.js:1534
|
||||
msgid "More..."
|
||||
msgstr "المزيد..."
|
||||
|
||||
#. TRANSLATORS: this is the indication that a connection for another logged in user is active,
|
||||
#. and we cannot access its settings (including the name)
|
||||
#: ../js/ui/status/network.js:561 ../js/ui/status/network.js:1333
|
||||
#: ../js/ui/status/network.js:561 ../js/ui/status/network.js:1322
|
||||
msgid "Connected (private)"
|
||||
msgstr "متّصل (شخصي)"
|
||||
|
||||
#: ../js/ui/status/network.js:641
|
||||
#: ../js/ui/status/network.js:619
|
||||
msgid "Auto Ethernet"
|
||||
msgstr "إيثرنت تلقائي"
|
||||
|
||||
#: ../js/ui/status/network.js:688
|
||||
#: ../js/ui/status/network.js:677
|
||||
msgid "Auto broadband"
|
||||
msgstr "شبكة هاتف محمول تلقائية"
|
||||
|
||||
#: ../js/ui/status/network.js:691
|
||||
#: ../js/ui/status/network.js:680
|
||||
msgid "Auto dial-up"
|
||||
msgstr "اتصال هاتفي تلقائي"
|
||||
|
||||
#. TRANSLATORS: this the automatic wireless connection name (including the network name)
|
||||
#: ../js/ui/status/network.js:820 ../js/ui/status/network.js:1350
|
||||
#: ../js/ui/status/network.js:809 ../js/ui/status/network.js:1339
|
||||
#, c-format
|
||||
msgid "Auto %s"
|
||||
msgstr "%s تلقائي"
|
||||
|
||||
#: ../js/ui/status/network.js:822
|
||||
#: ../js/ui/status/network.js:811
|
||||
msgid "Auto bluetooth"
|
||||
msgstr "بلوتوث تلقائي"
|
||||
|
||||
#: ../js/ui/status/network.js:1352
|
||||
#: ../js/ui/status/network.js:1341
|
||||
msgid "Auto wireless"
|
||||
msgstr "لاسلكي تلقائي"
|
||||
|
||||
#: ../js/ui/status/network.js:1595
|
||||
#: ../js/ui/status/network.js:1584
|
||||
msgid "Enable networking"
|
||||
msgstr "فعّل الشبكات"
|
||||
|
||||
#: ../js/ui/status/network.js:1627
|
||||
#: ../js/ui/status/network.js:1616
|
||||
msgid "Wi-Fi"
|
||||
msgstr "واي فاي"
|
||||
|
||||
#: ../js/ui/status/network.js:1646
|
||||
#: ../js/ui/status/network.js:1635
|
||||
msgid "Network Settings"
|
||||
msgstr "إعدادات الشّبكة"
|
||||
|
||||
#: ../js/ui/status/network.js:1692
|
||||
#: ../js/ui/status/network.js:1679
|
||||
msgid "Network Manager"
|
||||
msgstr "مدير الشبكة"
|
||||
|
||||
#: ../js/ui/status/network.js:1774
|
||||
#: ../js/ui/status/network.js:1761
|
||||
msgid "Connection failed"
|
||||
msgstr "فشل الاتصال"
|
||||
|
||||
#: ../js/ui/status/network.js:1775
|
||||
#: ../js/ui/status/network.js:1762
|
||||
msgid "Activation of network connection failed"
|
||||
msgstr "فشل تفعيل اتصال الشبكة"
|
||||
|
||||
#: ../js/ui/status/network.js:2092
|
||||
#: ../js/ui/status/network.js:2079
|
||||
msgid "Networking is disabled"
|
||||
msgstr "عُطّلت الشبكات"
|
||||
|
||||
@ -1675,11 +1681,11 @@ msgid "Unknown"
|
||||
msgstr "غير معروف"
|
||||
|
||||
#. Translators: This is the label for audio volume
|
||||
#: ../js/ui/status/volume.js:247 ../js/ui/status/volume.js:295
|
||||
#: ../js/ui/status/volume.js:50 ../js/ui/status/volume.js:251
|
||||
msgid "Volume"
|
||||
msgstr "شدة الصوت"
|
||||
|
||||
#: ../js/ui/status/volume.js:256
|
||||
#: ../js/ui/status/volume.js:62
|
||||
msgid "Microphone"
|
||||
msgstr "ميكروفون"
|
||||
|
||||
@ -1715,31 +1721,31 @@ msgstr "ساكن"
|
||||
msgid "Offline"
|
||||
msgstr "غير متصل"
|
||||
|
||||
#: ../js/ui/userMenu.js:755
|
||||
#: ../js/ui/userMenu.js:754
|
||||
msgid "Notifications"
|
||||
msgstr "التنبيهات"
|
||||
|
||||
#: ../js/ui/userMenu.js:763
|
||||
#: ../js/ui/userMenu.js:762
|
||||
msgid "Settings"
|
||||
msgstr "الإعدادات"
|
||||
|
||||
#: ../js/ui/userMenu.js:771
|
||||
#: ../js/ui/userMenu.js:770
|
||||
msgid "Switch User"
|
||||
msgstr "بدّل المستخدم"
|
||||
|
||||
#: ../js/ui/userMenu.js:776
|
||||
#: ../js/ui/userMenu.js:775
|
||||
msgid "Log Out"
|
||||
msgstr "اخرج"
|
||||
|
||||
#: ../js/ui/userMenu.js:796
|
||||
#: ../js/ui/userMenu.js:795
|
||||
msgid "Install Updates & Restart"
|
||||
msgstr "ثبّت التحديثات وأعد التشغيل"
|
||||
|
||||
#: ../js/ui/userMenu.js:814
|
||||
#: ../js/ui/userMenu.js:813
|
||||
msgid "Your chat status will be set to busy"
|
||||
msgstr "ستُجعل حالة اتصالك ”مشغول“"
|
||||
|
||||
#: ../js/ui/userMenu.js:815
|
||||
#: ../js/ui/userMenu.js:814
|
||||
msgid ""
|
||||
"Notifications are now disabled, including chat messages. Your online status "
|
||||
"has been adjusted to let others know that you might not see their messages."
|
||||
@ -1747,15 +1753,15 @@ msgstr ""
|
||||
"التنبيهات معطلة الآن، بما فيها رسائل المحادثة. حالة اتصالك تغيرت حتى يعلم "
|
||||
"الآخرون أنك قد لا ترى رسائلهم."
|
||||
|
||||
#: ../js/ui/viewSelector.js:85
|
||||
#: ../js/ui/viewSelector.js:91
|
||||
msgid "Applications"
|
||||
msgstr "التطبيقات"
|
||||
|
||||
#: ../js/ui/viewSelector.js:89
|
||||
#: ../js/ui/viewSelector.js:95
|
||||
msgid "Search"
|
||||
msgstr "ابحث"
|
||||
|
||||
#: ../js/ui/wanda.js:92
|
||||
#: ../js/ui/wanda.js:94
|
||||
#, c-format
|
||||
msgid ""
|
||||
"Sorry, no wisdom for you today:\n"
|
||||
@ -1764,11 +1770,15 @@ msgstr ""
|
||||
"عذرًا, لا حكمة لك اليوم:\n"
|
||||
"%s"
|
||||
|
||||
#: ../js/ui/wanda.js:96
|
||||
#: ../js/ui/wanda.js:98
|
||||
#, c-format
|
||||
msgid "%s the Oracle says"
|
||||
msgstr "يقول الحكيم %s"
|
||||
|
||||
#: ../js/ui/wanda.js:139
|
||||
msgid "Your favorite Easter Egg"
|
||||
msgstr ""
|
||||
|
||||
#: ../js/ui/windowAttentionHandler.js:19
|
||||
#, c-format
|
||||
msgid "'%s' is ready"
|
||||
@ -1778,36 +1788,6 @@ msgstr "'%s' جاهز"
|
||||
msgid "Evolution Calendar"
|
||||
msgstr "تقويم إيفُليوشِن"
|
||||
|
||||
#. translators:
|
||||
#. * The number of sound outputs on a particular device
|
||||
#: ../src/gvc/gvc-mixer-control.c:1837
|
||||
#, c-format
|
||||
msgid "%u Output"
|
||||
msgid_plural "%u Outputs"
|
||||
msgstr[0] "لا مخرَج"
|
||||
msgstr[1] "مخرَج واحد"
|
||||
msgstr[2] "مخرَجين"
|
||||
msgstr[3] "%u مخارج"
|
||||
msgstr[4] "%u مخرجا"
|
||||
msgstr[5] "%u مخرج"
|
||||
|
||||
#. translators:
|
||||
#. * The number of sound inputs on a particular device
|
||||
#: ../src/gvc/gvc-mixer-control.c:1847
|
||||
#, c-format
|
||||
msgid "%u Input"
|
||||
msgid_plural "%u Inputs"
|
||||
msgstr[0] "لا مدخل"
|
||||
msgstr[1] "مدخل واحد"
|
||||
msgstr[2] "مدخلين"
|
||||
msgstr[3] "%u مداخل"
|
||||
msgstr[4] "%u مدخلا"
|
||||
msgstr[5] "%u مدخل"
|
||||
|
||||
#: ../src/gvc/gvc-mixer-control.c:2371
|
||||
msgid "System Sounds"
|
||||
msgstr "أصوات النظام"
|
||||
|
||||
#: ../src/main.c:332
|
||||
msgid "Print version"
|
||||
msgstr "اطبع الإصدارة"
|
||||
@ -1849,12 +1829,6 @@ msgstr "المبدئي"
|
||||
msgid "Authentication dialog was dismissed by the user"
|
||||
msgstr "أغلق المستخدم مربع الاستيثاق الحِواري"
|
||||
|
||||
#~ msgid "APPLICATIONS"
|
||||
#~ msgstr "التطبيقات"
|
||||
|
||||
#~ msgid "SETTINGS"
|
||||
#~ msgstr "الإعدادات"
|
||||
|
||||
#~ msgid "Subscription request"
|
||||
#~ msgstr "طلب اشتراك"
|
||||
|
||||
@ -1903,6 +1877,27 @@ msgstr "أغلق المستخدم مربع الاستيثاق الحِواري"
|
||||
#~ msgid "System Settings"
|
||||
#~ msgstr "إعدادات النظام"
|
||||
|
||||
#~ msgid "%u Output"
|
||||
#~ msgid_plural "%u Outputs"
|
||||
#~ msgstr[0] "لا مخرَج"
|
||||
#~ msgstr[1] "مخرَج واحد"
|
||||
#~ msgstr[2] "مخرَجين"
|
||||
#~ msgstr[3] "%u مخارج"
|
||||
#~ msgstr[4] "%u مخرجا"
|
||||
#~ msgstr[5] "%u مخرج"
|
||||
|
||||
#~ msgid "%u Input"
|
||||
#~ msgid_plural "%u Inputs"
|
||||
#~ msgstr[0] "لا مدخل"
|
||||
#~ msgstr[1] "مدخل واحد"
|
||||
#~ msgstr[2] "مدخلين"
|
||||
#~ msgstr[3] "%u مداخل"
|
||||
#~ msgstr[4] "%u مدخلا"
|
||||
#~ msgstr[5] "%u مدخل"
|
||||
|
||||
#~ msgid "System Sounds"
|
||||
#~ msgstr "أصوات النظام"
|
||||
|
||||
#~ msgid "Failed to unmount '%s'"
|
||||
#~ msgstr "فشل فصْل '%s'"
|
||||
|
||||
|
1071
po/ca@valencia.po
1071
po/ca@valencia.po
File diff suppressed because it is too large
Load Diff
12
po/et.po
12
po/et.po
@ -14,7 +14,7 @@ msgstr ""
|
||||
"Report-Msgid-Bugs-To: http://bugzilla.gnome.org/enter_bug.cgi?product=gnome-"
|
||||
"shell&keywords=I18N+L10N&component=general\n"
|
||||
"POT-Creation-Date: 2012-12-09 13:03+0000\n"
|
||||
"PO-Revision-Date: 2012-12-19 16:47+0300\n"
|
||||
"PO-Revision-Date: 2012-12-18 17:13+0300\n"
|
||||
"Last-Translator: Mattias Põldaru <mahfiaz@gmail.com>\n"
|
||||
"Language-Team: Estonian <>\n"
|
||||
"Language: et\n"
|
||||
@ -153,8 +153,8 @@ msgid ""
|
||||
"state of the checkbox."
|
||||
msgstr ""
|
||||
"Shell küsib parooli, kui haagitakse krüpteeritud seade või kaugfailisüsteem. "
|
||||
"Kui parooli on võimalik salvestada edaspidiseks kasutuseks, näidatakse "
|
||||
"'Salvesta parool' märkeruutu. See võti määrab selle märkeruudu vaikimisi "
|
||||
"Kui parooli on võimalik salvestada järgmise kasutuse jaoks, näidatakse "
|
||||
"\"Jäta parool meelde\" märkeruutu. See võti määrab märkeruudu vaikimisi "
|
||||
"oleku."
|
||||
|
||||
msgid "Show the week date in the calendar"
|
||||
@ -257,9 +257,9 @@ msgid ""
|
||||
"are 'thumbnail-only' (shows a thumbnail of the window), 'app-icon-"
|
||||
"only' (shows only the application icon) or 'both'."
|
||||
msgstr ""
|
||||
"Seadistab, kuidas aknaid aknavahetajas kuvatakse. Sobivad väärtused on "
|
||||
"'thumbnail-only' (näidatakse ainult pisipilti aknast), 'app-icon-"
|
||||
"only' (näidatakse ainult akna ikooni) või 'both' (mõlemad)."
|
||||
"Seadistab, kuidas aknaid akendevahetajas kuvatakse. Sobivad väärtused on "
|
||||
"'thumbnail-only' (näidatakse ainult pisipilti), 'app-icon-only' (näidatakse "
|
||||
"ainult rakenduse ikooni) või 'both' (näidatakse mõlemaid)."
|
||||
|
||||
msgid "Attach modal dialog to the parent window"
|
||||
msgstr "Modaaldialoog kuulub vanemakna juurde"
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user