Compare commits

..

3 Commits

Author SHA1 Message Date
60d87ef4ba Handle global keybindings in the shell
Handling global keybindings, such as volume and brightness keys
but also custom keybindings, directly in the compositor is the only way
to deal with grabs and modal operations that could be active (primarily
the overview, for which special policy was introduced in the last
commit)

https://bugzilla.gnome.org/show_bug.cgi?id=613543
2012-11-10 17:04:48 +01:00
d886dc17e1 Prefix keybinding names with 'internal-keybinding-'
This is what mutter does internally now, to disambiguate them with
custom keybindings introduced with display.add_keybinding().

https://bugzilla.gnome.org/show_bug.cgi?id=613543
2012-11-10 17:04:48 +01:00
9dd2a467ba Main: filter keybindings when the shell is modal
Mutter now handles some keybindings even when the compositor is
grabbed, so we need to filter the invocation at the handler level.
This allows to finally get rid of a old hack.

https://bugzilla.gnome.org/show_bug.cgi?id=613543
2012-11-10 16:22:03 +01:00
172 changed files with 21080 additions and 19354 deletions

3
.gitignore vendored
View File

@ -38,7 +38,6 @@ docs/reference/*/*.txt
docs/reference/*/*.types
docs/reference/*/html/
docs/reference/*/xml/
docs/reference/shell/doc-gen-*
gtk-doc.make
js/misc/config.js
intltool-extract.in
@ -86,8 +85,6 @@ src/test-theme
src/st.h
src/stamp-st.h
src/stamp-st.h.tmp
src/st-scroll-view-fade-generated.c
src/stamp-st-scroll-view-fade-generated.c
stamp-h1
tests/run-test.sh
xmldocs.make

3
.gitmodules vendored
View File

@ -1,3 +0,0 @@
[submodule "src/gvc"]
path = src/gvc
url = git://git.gnome.org/libgnome-volume-control

View File

@ -16,7 +16,6 @@ EXTRA_DIST = \
# These are files checked into Git that we don't want to distribute
DIST_EXCLUDE = \
.gitignore \
.gitmodules \
gnome-shell.doap \
HACKING \
MAINTAINERS \

171
NEWS
View File

@ -1,174 +1,3 @@
3.7.4.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]
3.7.3
=====
* Add 'No Messages' label when message tray is empty [Victoria; #686738]
* Use better icons in Ctrl-Alt-Tab popup [Stéphane; #641303]
* Show the OSK on the monitor where the focused window lives [Giovanni; #685856]
* Highlight window clone and caption when hovered [Giovanni, Marc; #665310]
* Improve login process indication [Stéphane; #687113]
* Omit empty categories in apps view [Stéphane; #687970]
* Style panel differently according to mode [Florian; #684573]
* Make it possible to hide the user name [Matthias; #688577]
* Consolidate and improve chat connection notifications [Giovanni; #687213]
* Improve notification scrollbar appearance [Carlos; #688393]
* Fade scroll view fade near scrolling edges [Jasper; #689249]
* Add a read-only org.gnome.Shell.Mode property [Debarshi; #689300]
* Don't close message tray after using context menus [Giovanni; #689296]
* Port swipe-scrolling to ClutterPanAction [Jasper, Florian; #689062, #689552]
* Remember state of 'Remember Password' checkbox [Ron; #688039]
* Improve timestamp format in chat notifications [Carlos; #680989]
* Improve style of missed-messages counter [Carlos; #686472]
* Omit connection failure notifications if cancelled by user [Giovanni; #684823]
* Add window-based Alt-Tab popup [Florian; #688913]
* Support external session mode definitions [Florian; #689304]
* Support session-mode-specific extensions [Florian; #689305]
* Support 'parentMode' property in session modes [Florian; #689308]
* Support a new org.gnome.ShellSearchProvider2 DBus interface
[Cosimo; #689735, #690009]
* Add "windows" to Ctrl-Alt-Tab popup [Jasper; #689653]
* Port PopupMenu to GrabHelper [Jasper; #689109, #689954]
* Show headphone icon when headphones are plugged in [Giovanni; #675902]
* Display (non-app) search results as list [Tanner, Cosimo; #681797]
* Skip diacritical marks in search terms [Aleksander; #648587]
* Expose all engine options in input sources [Giovanni, Rui; #682318]
* Add input source switcher popup [Rui; #682315]
* Add minimal support for InfiniBand in network menu [Dan; #677150]
* Misc bug fixes and cleanups [Sebastian, Aleksander, Giovanni, Tim, Cosimo,
Florian, Matthias, Rui, Lionel, Colin, Piotr, Guillaume, Bastien, Tanner,
Carlos, Stéphane, Jakub; #688422, #688379, #688750, #688771, #686800,
#688133, #688895, #688966, #683986, #688004, #689108, #689029, #683449,
#688196, #689304, #689243, #689295, #689325, #689400, #679168, #689568,
#689537, #689528, #689749, #689789, #689353, #689820, #689868, #689778,
#689959, #688589, #688589, #689955, #687250, #689965, #690046, #690049,
#689884, #682286, #690173, #690174, #672941, #689876, #687881, #690171,
#690241, #690312, #690175, #687955, #650843, #688234, #690427
Contributors:
Giovanni Campagna, Cosimo Cecchi, Matthias Clasen, Stéphane Démurget,
Guillaume Desmottes, Tanner Doshier, Piotr Drąg, Sebastian Keller,
Lionel Landwerlin, Tim Lunn, Victoria Martínez de la Cruz, Aleksander Morgado,
Florian Müllner, Bastien Nocera, Marc Plano-Lesay, Carlos Soriano Sánchez,
Jakub Steiner, Jasper St. Pierre, Colin Walters, Dan Winship, Ron Yorston
Translations:
Yuri Myasoedov [ru], Wouter Bolsterlee [nl], Yaron Shahrabani [he],
Nilamdyuti Goswami [as], Ani Peter [ml], Kjartan Maraas [nb],
Dr.T.Vasudevan [ta], A S Alam [pa], Shankar Prasad [kn], Khaled Hosny [ar],
Daniel Mustieles [es], Dušan Kazik [sk]
3.7.2
=====
* Enforce RTL in he for messages that might end up as LTR [Florian; #686630]
* gdm: Move logo into the panel [Florian; #685852]
* Hide notifications when closed button is clicked [Jasper, Florian; #682237]
* Tweak screenShield animations [Rui; #686745]
* Restore Fittsability of summary items in message tray [Florian; #686474]
* Save screencasts as recent item [Ray; #680647]
* overview: Resize window captions on content change [Giovanni, Alex; #620874]
* App search: Match GenericName too [Matthias; #687121]
* runDialog: Better match style of other modal dialogs [Florian, Allan; #687127]
* Improve the button insensitive style [Stéphane; #687110]
* network: Don't use a global switch for all VPN connections [Giovanni; #682929]
* appMenu: Update on icon theme changes [Florian; #687224]
* Show 'Log out' in more situations [Matthias; #686736]
* Add a setting to force the 'Log out' menuitem [Matthias; #686057]
* overview: Improve styling of search box [Stéphane; #686479]
* Implement 'disable-user-list' in login screen [Ray; #660660]
* Fix auto-scroll to bottom in chat notifications [Sjoerd; #686571]
* Show feedback notifications when user is busy [Stéphane; #662900]
* Disable login button when there is no input [Stéphane; #687112]
* Use non-linear overview shade for background [Giovanni, Pierre-Eric; #669798]
* Reduce blocking in compositor thread [Simon, Jasper; #687465]
* network: new country-specific type to gather providers [Aleksander; #687356]
* Update man page [Matthias; #680601]
* st-entry: Change the pointer cursor on enter/leave events [Thomas; #687130]
* screenShield: Blur and desaturate the background [Giovanni, Cosimo; #682536]
* Change height of chat notifications to have more context [Carlos; #665255]
* screenShield: Account for motion velocity when hiding [Giovanni; #682537]
* screenShield: hide the cursor while the lock screen is on [Giovanni; #682535]
* Support remote search provider settings [Cosimo; #687491]
* unlockDialog: Improve label of confirmation button [Stéphane; #687656]
* userMenu: Rename "System Settings" item to "Settings" [Elad; #687738]
* messageTray: Add keybinding to focus current notification [Stéphane; #652082]
* Remove shell-screen-grabber [Neil; #685915]
* main: Stop using Metacity's keybinding files [Florian; #687672]
* Bluetooth: Remove ObexFTP functionality [Bastien; #688160]
* a11y: Also set WM theme when HighContrast is switched on [Cosimo; #688256]
* network: Rework multiple NIC support [Giovanni; #677142]
* Rework keybindings to allow selective blocking/processing [Florian; #688202]
* recorder: Show indicator on primary monitor [Adel; #688470]
* recorder: Set frame duration to fix broken video headers [Adel; #688487]
* Misc. bugfixes and cleanups [Florian, Jasper, Giovanni, Matthew, Stéphane,
Allan, Daiki, Owen, Alejandro, Jean-François, Cosimo, Sebastian, Adel, Alban;
#686484, #686728, #686805, #686574, #686763, #682428, #687132, #685239,
#687189, #687226, #658091, #670687, #687457, #687242, #687287, #687020,
#686583, #661194, #687491, #657315, #687958, #683986, #688089, #687708,
#686530, #684810, #688181, #688475, #688557, #688507, #638351]
Contributors:
Elad Alfassa, Matthew Barnes, Alban Browaeys, Giovanni Campagna,
Cosimo Cecchi, Matthias Clasen, Allan Day, Stéphane Démurget,
Jean-François Fortin Tam, Adel Gadllah, Alex Hultman, Sebastian Keller,
Rui Matos, Simon McVittie, Aleksander Morgado, Florian Müllner,
Bastien Nocera, Pierre-Eric Pelloux-Prayer, Alejandro Piñeiro, Neil Roberts,
Sjoerd Simons, Carlos Soriano Sánchez, Jasper St. Pierre, Ray Strode,
Owen Taylor, Daiki Ueno, Thomas Wood
Translations:
Dušan Kazik [sk], Pavol Klačanský [sk], Piotr Drąg [pl], Yuri Myasoedov [ru],
Marek Černocký [cs], Kjartan Maraas [nb], Wolfgang Stöggl [de],
Yaron Shahrabani [he], Fran Diéguez [gl], Mattias Põldaru [et]
3.7.1
=====
* Add shortcut to open application view directly [Jeremy; #685738]

View File

@ -13,14 +13,6 @@ PKG_NAME="gnome-shell"
exit 1
}
# Fetch submodules if needed
if test ! -f src/gvc/Makefile.am;
then
echo "+ Setting up submodules"
git submodule init
fi
git submodule update
which gnome-autogen.sh || {
echo "You need to install gnome-common from GNOME Git (or from"
echo "your OS vendor's package manager)."

View File

@ -1,5 +1,5 @@
AC_PREREQ(2.63)
AC_INIT([gnome-shell],[3.7.4.1],[https://bugzilla.gnome.org/enter_bug.cgi?product=gnome-shell],[gnome-shell])
AC_INIT([gnome-shell],[3.7.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])
@ -64,12 +64,13 @@ AM_CONDITIONAL(BUILD_RECORDER, $build_recorder)
CLUTTER_MIN_VERSION=1.11.11
GOBJECT_INTROSPECTION_MIN_VERSION=0.10.1
GJS_MIN_VERSION=1.35.4
MUTTER_MIN_VERSION=3.7.4
GJS_MIN_VERSION=1.33.2
MUTTER_MIN_VERSION=3.7.1
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
@ -77,8 +78,6 @@ STARTUP_NOTIFICATION_MIN_VERSION=0.11
GCR_MIN_VERSION=3.3.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!
PKG_CHECK_MODULES(GNOME_SHELL, gio-unix-2.0 >= $GIO_MIN_VERSION
@ -99,9 +98,8 @@ PKG_CHECK_MODULES(GNOME_SHELL, gio-unix-2.0 >= $GIO_MIN_VERSION
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)
@ -125,8 +123,8 @@ 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(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(GVC, libpulse libpulse-mainloop-glib gobject-2.0)
PKG_CHECK_MODULES(DESKTOP_SCHEMAS, gsettings-desktop-schemas >= 3.5.4)
AC_MSG_CHECKING([for bluetooth support])
PKG_CHECK_EXISTS([gnome-bluetooth-1.0 >= 3.1.0],
@ -269,7 +267,6 @@ AC_CONFIG_FILES([
js/Makefile
src/calendar-server/evolution-calendar.desktop.in
src/Makefile
src/gvc/Makefile
browser-plugin/Makefile
tests/Makefile
po/Makefile.in

View File

@ -11,10 +11,7 @@ desktop_DATA = gnome-shell.desktop gnome-shell-extension-prefs.desktop
@INTLTOOL_DESKTOP_RULE@
introspectiondir = $(datadir)/dbus-1/interfaces
introspection_DATA = \
org.gnome.Shell.Screenshot.xml \
org.gnome.ShellSearchProvider.xml \
org.gnome.ShellSearchProvider2.xml
introspection_DATA = org.gnome.ShellSearchProvider.xml
themedir = $(pkgdatadir)/theme
dist_theme_DATA = \
@ -35,7 +32,6 @@ dist_theme_DATA = \
theme/gnome-shell.css \
theme/logged-in-indicator.svg \
theme/message-tray-background.png \
theme/more-results.svg \
theme/noise-texture.png \
theme/panel-button-border.svg \
theme/panel-button-highlight-narrow.svg \

View File

@ -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>

View File

@ -2,72 +2,146 @@
'-//freedesktop//DTD D-BUS Object Introspection 1.0//EN'
'http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd'>
<node>
<!--
org.gnome.Shell.SearchProvider:
@short_description: Search provider interface
The interface used for integrating into GNOME Shell's search
interface. This interface is deprecated, and org.gnome.Shell.SearchProvider2 should be used instead.
-->
<interface name="org.gnome.Shell.SearchProvider">
<doc:doc>
<doc:description>
<doc:para>
The interface used for integrating into GNOME Shell's search
interface.
</doc:para>
</doc:description>
</doc:doc>
<!--
GetInitialResultSet:
@terms: Array of search terms, which the provider should treat as logical AND.
@results: An array of result identifier strings representing items which match the given search terms. Identifiers must be unique within the provider's domain, but other than that may be chosen freely by the provider.
Called when the user first begins a search.
-->
<method name="GetInitialResultSet">
<arg type="as" name="terms" direction="in" />
<arg type="as" name="results" direction="out" />
<doc:doc>
<doc:description>
<doc:para>
Called when the user first begins a search.
</doc:para>
</doc:description>
</doc:doc>
<arg type="as" direction="in">
<doc:doc>
<doc:summary>
<doc:para>
Array of search terms, which the provider should treat as
logical AND.
</doc:para>
</doc:summary>
</doc:doc>
</arg>
<arg type="as" direction="out">
<doc:doc>
<doc:summary>
<doc:para>
An array of result identifier strings representing items which
match the given search terms. Identifiers must be unique within
the provider's domain, but other than that may be chosen freely
by the provider.
</doc:para>
</doc:summary>
</doc:doc>
</arg>
</method>
<!--
GetSubsearchResultSet:
@previous_results: Array of results previously returned by GetInitialResultSet().
@terms: Array of updated search terms, which the provider should treat as logical AND.
@results: An array of result identifier strings representing items which match the given search terms. Identifiers must be unique within the provider's domain, but other than that may be chosen freely by the provider.
Called when a search is performed which is a "subsearch" of
the previous search, e.g. the method may return less results, but
not more or different results.
This allows search providers to only search through the previous
result set, rather than possibly performing a full re-query.
-->
<method name="GetSubsearchResultSet">
<arg type="as" name="previous_results" direction="in" />
<arg type="as" name="terms" direction="in" />
<arg type="as" name="results" direction="out" />
<doc:doc>
<doc:description>
<doc:para>
Called when a search is performed which is a "subsearch" of
the previous search, e.g. the method may return less results, but
not more or different results.
This allows search providers to only search through the previous
result set, rather than possibly performing a full re-query.
</doc:para>
</doc:description>
</doc:doc>
<arg type="as" direction="in">
<doc:doc>
<doc:summary>
<doc:para>
Array of item identifiers
</doc:para>
</doc:summary>
</doc:doc>
</arg>
<arg type="as" direction="in">
<doc:doc>
<doc:summary>
<doc:para>
Array of updated search terms, which the provider should treat as
logical AND.
</doc:para>
</doc:summary>
</doc:doc>
</arg>
<arg type="as" direction="out">
<doc:doc>
<doc:summary>
<doc:para>
An array of result identifier strings representing items which
match the given search terms. Identifiers must be unique within
the provider's domain, but other than that may be chosen freely
by the provider.
</doc:para>
</doc:summary>
</doc:doc>
</arg>
</method>
<!--
GetResultMetas:
@identifiers: An array of result identifiers as returned by GetInitialResultSet() or GetSubsearchResultSet()
@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
-->
<method name="GetResultMetas">
<arg type="as" name="identifiers" direction="in" />
<arg type="aa{sv}" name="metas" direction="out" />
<doc:doc>
<doc:description>
<doc:para>
Return an array of meta data used to display each given result
</doc:para>
</doc:description>
</doc:doc>
<arg type="as" direction="in">
<doc:doc>
<doc:summary>
<doc:para>
An array of result identifiers as returned by
GetInitialResultSet() or GetSubsearchResultSet()
</doc:para>
</doc:summary>
</doc:doc>
</arg>
<arg type="aa{sv}" direction="out">
<doc:doc>
<doc:summary>
<doc:para>
A dictionary describing the given search result, containing
'id', 'name' (both strings) and either 'icon' (a serialized
GIcon) or 'icon-data' (raw image data as (iiibiiay) - width,
height, rowstride, has-alpha, bits per sample, channels, data)
</doc:para>
</doc:summary>
</doc:doc>
</arg>
</method>
<!--
ActivateResult:
@identifier: A result identifier as returned by GetInitialResultSet() or GetSubsearchResultSet()
Called when the users chooses a given result. The result should
be displayed in the application associated with the corresponding
provider.
This method is deprecated, and providers should implement ActivateResult2()
instead.
-->
<method name="ActivateResult">
<arg type="s" name="identifier" direction="in" />
<doc:doc>
<doc:description>
<doc:para>
Called when the users chooses a given result. The result should
be displayed in the application associated with the corresponding
provider.
</doc:para>
</doc:description>
</doc:doc>
<arg type="s" direction="in">
<doc:doc>
<doc:summary>
<doc:para>
A result identifier as returned by GetInitialResultSet() or
GetSubsearchResultSet()
</doc:para>
</doc:summary>
</doc:doc>
</arg>
</method>
</interface>
</node>

View File

@ -1,87 +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.SearchProvider2:
@short_description: Search provider interface
The interface used for integrating into GNOME Shell's search
interface (version 2).
-->
<interface name="org.gnome.Shell.SearchProvider2">
<!--
GetInitialResultSet:
@terms: Array of search terms, which the provider should treat as logical AND.
@results: An array of result identifier strings representing items which match the given search terms. Identifiers must be unique within the provider's domain, but other than that may be chosen freely by the provider.
Called when the user first begins a search.
-->
<method name="GetInitialResultSet">
<arg type="as" name="terms" direction="in" />
<arg type="as" name="results" direction="out" />
</method>
<!--
GetSubsearchResultSet:
@previous_results: Array of results previously returned by GetInitialResultSet().
@terms: Array of updated search terms, which the provider should treat as logical AND.
@results: An array of result identifier strings representing items which match the given search terms. Identifiers must be unique within the provider's domain, but other than that may be chosen freely by the provider.
Called when a search is performed which is a "subsearch" of
the previous search, e.g. the method may return less results, but
not more or different results.
This allows search providers to only search through the previous
result set, rather than possibly performing a full re-query.
-->
<method name="GetSubsearchResultSet">
<arg type="as" name="previous_results" direction="in" />
<arg type="as" name="terms" direction="in" />
<arg type="as" name="results" direction="out" />
</method>
<!--
GetResultMetas:
@identifiers: An array of result identifiers as returned by GetInitialResultSet() or GetSubsearchResultSet()
@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
-->
<method name="GetResultMetas">
<arg type="as" name="identifiers" direction="in" />
<arg type="aa{sv}" name="metas" direction="out" />
</method>
<!--
ActivateResult:
@identifier: A result identifier as returned by GetInitialResultSet() or GetSubsearchResultSet()
@terms: Array of search terms, which the provider should treat as logical AND.
@timestamp: A timestamp of the user interaction that triggered this call
Called when the users chooses a given result. The result should
be displayed in the application associated with the corresponding
provider. The provided search terms can be used to allow launching a full search in
the application.
-->
<method name="ActivateResult">
<arg type="s" name="identifier" direction="in" />
<arg type="as" name="terms" direction="in" />
<arg type="u" name="timestamp" direction="in" />
</method>
<!--
LaunchSearch:
@terms: Array of search terms, which the provider should treat as logical AND.
@timestamp: A timestamp of the user interaction that triggered this call
Asks the search provider to launch a full search in the application for the provided terms.
-->
<method name="LaunchSearch">
<arg type="as" name="terms" direction="in" />
<arg type="u" name="timestamp" direction="in" />
</method>
</interface>
</node>

View File

@ -65,16 +65,6 @@ value here is from the GsmPresenceStatus enumeration.</_summary>
menuitem in single-user, single-session situations.
</_description>
</key>
<key name="remember-mount-password" type="b">
<default>false</default>
<_summary>Whether to remember password for mounting encrypted or remote filesystems</_summary>
<_description>
The shell will request a password when an encrypted device or a
remote filesystem is mounted. If the password can be saved for
future use a 'Remember Password' checkbox will be present.
This key sets the default state of the checkbox.
</_description>
</key>
<child name="calendar" schema="org.gnome.shell.calendar"/>
<child name="recorder" schema="org.gnome.shell.recorder"/>
<child name="keybindings" schema="org.gnome.shell.keybindings"/>
@ -181,33 +171,6 @@ value here is from the GsmPresenceStatus enumeration.</_summary>
</key>
</schema>
<enum id="org.gnome.shell.window-switcher.AppIconMode">
<value value="1" nick="thumbnail-only"/>
<value value="2" nick="app-icon-only"/>
<value value="3" nick="both"/>
</enum>
<schema id="org.gnome.shell.window-switcher"
path="/org/gnome/shell/window-switcher/"
gettext-domain="@GETTEXT_PACKAGE@">
<key name="app-icon-mode" enum="org.gnome.shell.window-switcher.AppIconMode">
<default>'both'</default>
<_summary>The application icon mode.</_summary>
<_description>
Configures how the windows are shown in the switcher. Valid possibilities
are 'thumbnail-only' (shows a thumbnail of the window), 'app-icon-only'
(shows only the application icon) or 'both'.
</_description>
</key>
<key type="b" name="current-workspace-only">
<default>false</default>
<summary>Limit switcher to current workspace.</summary>
<description>
If true, only windows from the current workspace are shown in the switcher.
Otherwise, all windows are included.
</description>
</key>
</schema>
<schema id="org.gnome.shell.overrides" path="/org/gnome/shell/overrides/"
gettext-domain="@GETTEXT_PACKAGE@">
<key name="attach-modal-dialogs" type="b">

View File

@ -49,7 +49,7 @@ stage {
.switcher-list,
.app-well-app > .overview-icon,
.show-apps > .overview-icon,
.grid-search-result .overview-icon {
.search-result-content > .overview-icon {
font-size: 9pt;
font-weight: bold;
}
@ -206,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 {
@ -252,10 +251,6 @@ StScrollBar StButton#vhandle:active {
icon-size: 1.09em;
}
.popup-battery-percentage {
padding-left: 24px;
}
/* Switches */
.toggle-switch {
width: 65px;
@ -292,17 +287,13 @@ StScrollBar StButton#vhandle:active {
.hotplug-notification-item,
.hotplug-resident-eject-button,
.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);
}
.dash-search-button,
.modal-dialog-button {
font-weight: bold;
}
.dash-search-button:hover,
.notification-button:hover,
.notification-icon-button:hover,
@ -363,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);
}
@ -398,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,
@ -414,13 +405,11 @@ StScrollBar StButton#vhandle:active {
padding: 0 4px;
}
.modal-dialog StEntry:insensitive {
border-color: #666666;
color: #9f9f9f;
border: 2px solid #9f9f9f;
background-gradient-direction: none;
background-color: rgba(102, 102, 102, 0.15);
box-shadow: inset 0 0 rgba(0,0,0,1.0);
.login-dialog-prompt-entry:insensitive {
color: rgba(0,0,0,0.7);
border: 2px solid #565656;
background-gradient-start: rgb(200,200,200);
background-gradient-end: rgb(210,210,210);
}
/* Panel */
@ -429,18 +418,6 @@ StScrollBar StButton#vhandle:active {
background-color: black;
font-weight: bold;
height: 1.86em;
transition-duration: 250ms;
}
#panel.lock-screen {
height: 2em;
background-color: rgba(0,0,0,0.3);
}
#panel.unlock-screen,
#panel.login-screen {
height: 2em;
background-color: transparent;
}
#panelLeft, #panelCenter {
@ -476,13 +453,6 @@ StScrollBar StButton#vhandle:active {
-panel-corner-border-color: rgba(255,255,255,0.8);
}
.panel-corner.lock-screen,
.panel-corner.unlock-screen,
.panel-corner.login-screen {
-panel-corner-background-color: transparent;
-panel-corner-border-color: transparent;
}
#appMenu {
spacing: 4px;
}
@ -512,25 +482,7 @@ StScrollBar StButton#vhandle:active {
-minimum-hpadding: 6px;
font-weight: bold;
color: #ccc;
transition-duration: 100ms;
}
#panel.unlock-screen .panel-button,
#panel.lock-screen .panel-button,
#panel.login-screen .panel-button {
color: #e6e6e6;
}
#panel.unlock-screen .panel-button:hover,
#panel.lock-screen .panel-button:hover,
#panel.login-screen .panel-button:hover,
#panel.unlock-screen .panel-button:active,
#panel.lock-screen .panel-button:active,
#panel.login-screen .panel-button:active,
#panel.unlock-screen .panel-button:focus,
#panel.lock-screen .panel-button:focus,
#panel.login-screen .panel-button:focus {
color: white;
transition-duration: 100;
}
.panel-button:hover {
@ -567,10 +519,6 @@ StScrollBar StButton#vhandle:active {
spacing: 4px;
}
.lock-screen-status-button-box {
spacing: 8px;
}
/* User Menu */
#panelUserMenu {
@ -626,15 +574,7 @@ StScrollBar StButton#vhandle:active {
/* Overview */
#overview {
spacing: 24px;
}
#overview-group {
spacing: 32px;
}
.workspaces-display {
spacing: 32px; /* needs to be the same value as #overview-group */
spacing: 40px;
}
.window-caption {
@ -675,7 +615,6 @@ StScrollBar StButton#vhandle:active {
border-radius: 8px;
padding: 4px 12px;
-shell-caption-spacing: 12px;
border: 2px solid rgba(0, 0, 0, 0);
}
.window-close, .notification-close {
@ -686,16 +625,7 @@ StScrollBar StButton#vhandle:active {
}
.window-close {
-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;
-shell-close-overlap: 20px;
}
.notification-close {
@ -723,8 +653,8 @@ StScrollBar StButton#vhandle:active {
}
.window-picker {
-horizontal-spacing: 32px;
-vertical-spacing: 32px;
-horizontal-spacing: 40px;
-vertical-spacing: 40px;
}
/* Dash */
@ -781,7 +711,7 @@ StScrollBar StButton#vhandle:active {
#searchResultsContent {
padding-right: 20px;
spacing: 16px;
spacing: 36px;
}
#searchResultsContent:rtl {
@ -789,22 +719,11 @@ StScrollBar StButton#vhandle:active {
padding-left: 20px;
}
.search-section {
/* This should be equal to #searchResultsContent spacing */
spacing: 16px;
}
.search-section-separator {
-gradient-height: 1px;
-gradient-start: rgba(255,255,255,0);
-gradient-end: rgba(255,255,255,0.5);
-margin-horizontal: 1.5em;
height: 1px;
}
.search-section-content {
/* This is the space between the provider icon and the results container */
spacing: 32px;
.search-section-header {
padding: 4px 12px;
spacing: 4px;
color: #6f6f6f;
font-size: .8em;
}
.search-statustext {
@ -813,8 +732,16 @@ StScrollBar StButton#vhandle:active {
font-weight: bold;
}
.list-search-results {
spacing: 3px;
.search-section-results {
padding: 6px;
}
.search-section-list-results {
spacing: 4px;
}
.results-container {
spacing: 4px;
}
/* Text labels are an odd number of pixels tall. The uneven top and bottom
@ -843,7 +770,7 @@ StScrollBar StButton#vhandle:active {
-x-offset: 8px;
}
/* Application Launchers, Grid and List results */
/* Application Launchers and Grid */
.icon-grid {
spacing: 36px;
@ -895,38 +822,13 @@ StScrollBar StButton#vhandle:active {
padding: 4px 8px;
}
.list-search-result-content {
spacing: 12px;
padding: 12px;
}
.list-search-result-title {
font-weight: bold;
font-size: 14pt;
color: white;
}
.list-search-result-description {
font-weight: bold;
font-size: 12pt;
color: #eeeeec;
}
.search-provider-icon-more {
width: 16px;
height: 16px;
background-image: url("more-results.svg");
}
.app-well-app > .overview-icon,
.show-apps > .overview-icon,
.search-provider-icon,
.list-search-result,
.grid-search-result .overview-icon {
.search-result-content > .overview-icon {
border-radius: 4px;
padding: 3px;
border: 1px rgba(0,0,0,0);
transition-duration: 100ms;
transition-duration: 100;
text-align: center;
}
@ -938,12 +840,10 @@ StScrollBar StButton#vhandle:active {
.app-well-app:hover > .overview-icon,
.show-apps:hover > .overview-icon,
.search-provider-icon:hover,
.list-search-result:hover,
.grid-search-result:hover .overview-icon {
.search-result-content: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;
}
@ -965,24 +865,20 @@ StScrollBar StButton#vhandle:active {
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,
.grid-search-result:focus .overview-icon,
.search-result-content:focus > .overview-icon,
.show-apps:focus > .overview-icon,
.search-provider-icon:focus,
.list-search-result:focus,
.app-well-app:selected > .overview-icon,
.grid-search-result:selected .overview-icon,
.search-provider-icon:selected,
.list-search-result:selected {
.search-result-content:selected > .overview-icon {
background-color: rgba(255,255,255,0.33);
}
@ -1010,7 +906,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;
}
@ -1313,8 +1209,7 @@ StScrollBar StButton#vhandle:active {
#message-tray {
background: #2e3436 url(message-tray-background.png);
background-repeat: repeat;
transition-duration: 250ms;
height: 72px;
transition-duration: 250;
}
#message-tray:keyboard {
@ -1327,21 +1222,11 @@ StScrollBar StButton#vhandle:active {
outline: 1px solid rgba(128, 128, 128, 0.3);
}
.message-tray-summary {
height: 72px;
}
.no-messages-label {
font-family: cantarell, sans-serif;
font-size: 11pt;
color: #999999;
}
.notification {
border-radius: 10px 10px 0px 0px;
background: rgba(0,0,0,0.9);
background: rgba(0,0,0,0.8);
padding: 8px 8px 4px 8px;
spacing-rows: 4px;
spacing-rows: 10px;
spacing-columns: 10px;
}
@ -1370,8 +1255,8 @@ StScrollBar StButton#vhandle:active {
}
.summary-boxpointer {
-arrow-border-radius: 15px;
-arrow-background-color: rgba(0,0,0,0.9);
-arrow-border-radius: 8px;
-arrow-background-color: rgba(0,0,0,0.8);
-arrow-base: 36px;
-arrow-rise: 18px;
color: white;
@ -1391,8 +1276,8 @@ StScrollBar StButton#vhandle:active {
.summary-notification-stack-scrollview {
max-height: 18em;
padding-top: 8px;
padding-bottom: 8px;
padding-top: 6px;
padding-bottom: 6px;
}
.summary-notification-stack-scrollview:ltr {
@ -1421,7 +1306,6 @@ StScrollBar StButton#vhandle:active {
}
.notification-actions {
padding-top: 18px;
spacing: 10px;
}
@ -1560,6 +1444,10 @@ StScrollBar StButton#vhandle:active {
border-radius: 4px;
}
#summary-mode {
height: 72px;
}
.summary-source-button {
padding: 6px 3px 6px 3px;
}
@ -1584,22 +1472,22 @@ StScrollBar StButton#vhandle:active {
.summary-source {
border-radius: 4px;
padding: 0 6px 0 6px;
transition-duration: 100ms;
transition-duration: 100;
}
.summary-source-counter {
background-image: url("summary-counter.svg");
background-size: 2.4em;
background-size: 2.5em;
font-size: 10pt;
font-weight: bold;
height: 2.4em;
width: 2.4em;
-shell-counter-overlap-x: 13px;
-shell-counter-overlap-y: 13px;
height: 2.5em;
width: 2.5em;
-shell-counter-overlap-x: 4px;
-shell-counter-overlap-y: 4px;
}
/* App Switcher */
.switcher-popup {
#altTabPopup {
padding: 8px;
spacing: 16px;
}
@ -2241,7 +2129,7 @@ StScrollBar StButton#vhandle:active {
font-weight: bold;
text-align: left;
padding-left: 15px;
text-shadow: black 0px 4px 3px 0px;
text-shadow: black 4px 4px 3px 0px;
}
.login-dialog-prompt-layout {
@ -2307,10 +2195,6 @@ StScrollBar StButton#vhandle:active {
height: .75em;
}
.login-dialog .modal-dialog-button-box {
spacing: 3px;
}
.login-dialog .modal-dialog-button {
border-radius: 5px;
padding: 3px 18px;
@ -2416,21 +2300,16 @@ StScrollBar StButton#vhandle:active {
}
.screen-shield-notification-source {
padding: 13px 24px;
padding: 0 24px;
spacing: 5px;
}
.screen-shield-notification-label {
font-size: 1.2em;
font-weight: bold;
padding: 0px 18px;
color: #babdb6;
}
.screen-shield-notification-count-text {
padding: 0px 18px;
}
/* Remove background from notifications, otherwise
opacity is doubled and they look darker
*/
@ -2446,8 +2325,17 @@ StScrollBar StButton#vhandle:active {
padding-bottom: 0px;
}
.input-source-switcher-symbol {
font-size: 42pt;
width: 96px;
height: 96px;
.osd-window {
color: #ededed;
background-color: rgba(33, 37, 38, 0.80);
border-radius: 15px;
text-shadow: 0 1px rgba(0, 0, 0, 0.75);
padding: 40px;
spacing: 5px;
}
.osd-progress-bar {
height: 0.8em;
border: 1px solid;
}

View File

@ -1,109 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="16"
height="16"
id="svg12430"
version="1.1"
inkscape:version="0.48.3.1 r9886"
sodipodi:docname="more-results.svg">
<defs
id="defs12432" />
<sodipodi:namedview
id="base"
pagecolor="#7a7a7a"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="1"
inkscape:pageshadow="2"
inkscape:zoom="1"
inkscape:cx="8.3155237"
inkscape:cy="0.89548874"
inkscape:document-units="px"
inkscape:current-layer="g14642-3-0"
showgrid="false"
borderlayer="true"
inkscape:showpageshadow="false"
inkscape:window-width="2560"
inkscape:window-height="1376"
inkscape:window-x="1200"
inkscape:window-y="187"
inkscape:window-maximized="1">
<inkscape:grid
type="xygrid"
id="grid13002" />
</sodipodi:namedview>
<metadata
id="metadata12435">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(0,-1036.3622)">
<g
style="display:inline"
transform="translate(-141.99984,638.37113)"
inkscape:label="zoom-in"
id="g14642-3-0">
<path
sodipodi:type="inkscape:offset"
inkscape:radius="0"
inkscape:original="M 145.1875 400 C 144.5248 400 144 400.54899 144 401.21875 L 144 410.78125 C 144 411.45101 144.5248 412 145.1875 412 L 154.8125 412 C 155.4752 412 156 411.45101 156 410.78125 L 156 401.21875 C 156 400.54899 155.4752 400 154.8125 400 L 145.1875 400 z M 149 403 L 151 403 L 151 405 L 153 405 L 153 407 L 151 407 L 151 409 L 149 409 L 149 407 L 147 407 L 147 405 L 149 405 L 149 403 z "
xlink:href="#rect11749-5-0-1-8"
style="color:#bebebe;fill:#000000;fill-opacity:1;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;opacity:0.8"
id="path13004"
inkscape:href="#rect11749-5-0-1-8"
d="M 145.1875,400 C 144.5248,400 144,400.54899 144,401.21875 l 0,9.5625 c 0,0.66976 0.5248,1.21875 1.1875,1.21875 l 9.625,0 c 0.6627,0 1.1875,-0.54899 1.1875,-1.21875 l 0,-9.5625 C 156,400.54899 155.4752,400 154.8125,400 L 145.1875,400 z m 3.8125,3 2,0 0,2 2,0 0,2 -2,0 0,2 -2,0 0,-2 -2,0 0,-2 2,0 L 149,403 Z"
transform="translate(0,1)" />
<use
x="0"
y="0"
xlink:href="#path13004"
id="use11960"
transform="translate(1,-1)"
width="16"
height="16" />
<use
x="0"
y="0"
xlink:href="#use11960"
id="use11962"
transform="translate(-2,0)"
width="16"
height="16" />
<path
inkscape:connector-curvature="0"
style="color:#bebebe;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible"
d="M 145.1875,400 C 144.5248,400 144,400.54899 144,401.21875 l 0,9.5625 c 0,0.66976 0.5248,1.21875 1.1875,1.21875 l 9.625,0 c 0.6627,0 1.1875,-0.54899 1.1875,-1.21875 l 0,-9.5625 C 156,400.54899 155.4752,400 154.8125,400 L 145.1875,400 z m 3.8125,3 2,0 0,2 2,0 0,2 -2,0 0,2 -2,0 0,-2 -2,0 0,-2 2,0 L 149,403 Z"
id="rect11749-5-0-1-8" />
<rect
style="fill:none;stroke:none"
id="rect3620-5-4"
width="15.981825"
height="16"
x="142"
y="398"
rx="0"
ry="0" />
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 4.1 KiB

View File

@ -76,30 +76,9 @@ endif
# e.g. HTML_IMAGES=$(top_srcdir)/gtk/stock-icons/stock_about_24.png
HTML_IMAGES=
doc-gen-org.gnome.Shell.SearchProvider.xml: $(top_srcdir)/data/org.gnome.ShellSearchProvider.xml
gdbus-codegen \
--interface-prefix org.gnome.ShellSearchProvider. \
--generate-docbook doc-gen \
$(top_srcdir)/data/org.gnome.ShellSearchProvider.xml
doc-gen-org.gnome.Shell.SearchProvider2.xml: $(top_srcdir)/data/org.gnome.ShellSearchProvider2.xml
gdbus-codegen \
--interface-prefix org.gnome.ShellSearchProvider2. \
--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
content_files=
# SGML files where gtk-doc abbrevations (#GtkWidget) are expanded
# These files must be listed here *and* in content_files

View File

@ -43,8 +43,6 @@
</chapter>
<chapter>
<title>Integration helpers and utilities</title>
<xi:include href="doc-gen-org.gnome.Shell.SearchProvider.xml"/>
<xi:include href="doc-gen-org.gnome.Shell.SearchProvider2.xml"/>
<xi:include href="xml/shell-global.xml"/>
<xi:include href="xml/shell-wm.xml"/>
<xi:include href="xml/shell-xfixes-cursor.xml"/>

View File

@ -52,6 +52,13 @@ its dependencies to build from tarballs.</description>
<gnome:userid>walters</gnome:userid>
</foaf:Person>
</maintainer>
<maintainer>
<foaf:Person>
<foaf:name>Dan Winship</foaf:name>
<foaf:mbox rdf:resource="mailto:danw@gnome.org" />
<gnome:userid>danw</gnome:userid>
</foaf:Person>
</maintainer>
<maintainer>
<foaf:Person>
<foaf:name>Marina Zhurakhinskaya</foaf:name>

View File

@ -49,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 \
@ -61,7 +62,6 @@ nobase_dist_js_DATA = \
ui/main.js \
ui/messageTray.js \
ui/modalDialog.js \
ui/separator.js \
ui/sessionMode.js \
ui/shellEntry.js \
ui/shellMountOperation.js \
@ -73,7 +73,6 @@ nobase_dist_js_DATA = \
ui/popupMenu.js \
ui/remoteSearch.js \
ui/runDialog.js \
ui/screenshot.js \
ui/screenShield.js \
ui/scripting.js \
ui/search.js \
@ -86,7 +85,6 @@ nobase_dist_js_DATA = \
ui/status/power.js \
ui/status/volume.js \
ui/status/bluetooth.js \
ui/switcherPopup.js \
ui/tweener.js \
ui/unlockDialog.js \
ui/userMenu.js \
@ -102,6 +100,7 @@ nobase_dist_js_DATA = \
ui/components/__init__.js \
ui/components/autorunManager.js \
ui/components/automountManager.js \
ui/components/mediaKeysManager.js \
ui/components/networkAgent.js \
ui/components/polkitAgent.js \
ui/components/recorder.js \

View File

@ -39,7 +39,6 @@ const GdmUtil = imports.gdm.util;
const Lightbox = imports.ui.lightbox;
const Main = imports.ui.main;
const ModalDialog = imports.ui.modalDialog;
const Panel = imports.ui.panel;
const PanelMenu = imports.ui.panelMenu;
const Tweener = imports.ui.tweener;
const UserMenu = imports.ui.userMenu;
@ -49,10 +48,6 @@ const _SCROLL_ANIMATION_TIME = 0.5;
const _TIMED_LOGIN_IDLE_THRESHOLD = 5.0;
const _LOGO_ICON_HEIGHT = 16;
const WORK_SPINNER_ICON_SIZE = 24;
const WORK_SPINNER_ANIMATION_DELAY = 1.0;
const WORK_SPINNER_ANIMATION_TIME = 0.3;
let _loginDialog = null;
function _smoothlyResizeActor(actor, width, height) {
@ -532,7 +527,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() {
@ -610,14 +604,6 @@ const SessionList = new Lang.Class({
this.close();
},
updateSensitivity: function(sensitive) {
this._button.reactive = sensitive;
this._button.can_focus = sensitive;
for (let id in this._items)
this._items[id].actor.reactive = sensitive;
},
setActiveSession: function(sessionId) {
if (sessionId == this._activeSessionId)
return;
@ -674,7 +660,6 @@ const LoginDialog = new Lang.Class({
this.parent({ shellReactive: true,
styleClass: 'login-dialog',
parentActor: parentActor,
keybindingMode: Main.KeybindingMode.LOGIN_SCREEN,
shouldFadeIn: false });
this.connect('destroy',
Lang.bind(this, this._onDestroy));
@ -699,7 +684,6 @@ const LoginDialog = new Lang.Class({
this._userVerifier = new GdmUtil.ShellUserVerifier(this._greeterClient);
this._userVerifier.connect('ask-question', Lang.bind(this, this._askQuestion));
this._userVerifier.connect('show-message', Lang.bind(this, this._showMessage));
this._userVerifier.connect('verification-failed', Lang.bind(this, this._verificationFailed));
this._userVerifier.connect('reset', Lang.bind(this, this._reset));
this._userVerifier.connect('show-login-hint', Lang.bind(this, this._showLoginHint));
this._userVerifier.connect('hide-login-hint', Lang.bind(this, this._hideLoginHint));
@ -765,9 +749,6 @@ const LoginDialog = new Lang.Class({
this._promptLoginHint.hide();
this._promptBox.add(this._promptLoginHint);
this._signInButton = null;
this._workSpinner = null;
this._sessionList = new SessionList();
this._sessionList.connect('session-activated',
Lang.bind(this, function(list, sessionId) {
@ -847,7 +828,6 @@ const LoginDialog = new Lang.Class({
},
_reset: function() {
this._updateSensitivity(true);
this._promptMessage.hide();
this._user = null;
this._verifyingUser = false;
@ -858,13 +838,6 @@ const LoginDialog = new Lang.Class({
this._showUserList();
},
_verificationFailed: function() {
this._promptEntry.text = '';
this._updateSensitivity(true);
this._setWorking(false);
},
_onDefaultSessionChanged: function(client, sessionId) {
this._sessionList.setActiveSession(sessionId);
},
@ -935,12 +908,35 @@ const LoginDialog = new Lang.Class({
_showPrompt: function(forSecret) {
let hold = new Batch.Hold();
let cancelButtonInfo = { action: Lang.bind(this, this.cancel),
label: _("Cancel"),
key: Clutter.Escape };
let okButtonInfo = { action: Lang.bind(this, function() {
hold.release();
}),
label: forSecret ? C_("button", "Sign In") : _("Next"),
default: true };
let buttons = [];
if (!this._disableUserList || this._verifyingUser)
buttons.push(cancelButtonInfo);
buttons.push(okButtonInfo);
let tasks = [function() {
return this._fadeInPrompt();
},
function() {
this._prepareDialog(forSecret, hold);
this.setButtons(buttons);
let updateOkButtonEnabled = Lang.bind(this, function() {
let sensitive = this._promptEntry.text.length > 0;
okButtonInfo.button.reactive = sensitive;
okButtonInfo.button.can_focus = sensitive;
});
updateOkButtonEnabled();
this._promptEntryTextChangedId = this._promptEntry.clutter_text.connect('text-changed', updateOkButtonEnabled);
},
hold];
@ -950,63 +946,6 @@ const LoginDialog = new Lang.Class({
return batch.run();
},
_prepareDialog: function(forSecret, hold) {
this._workSpinner = new Panel.AnimatedIcon('process-working.svg', WORK_SPINNER_ICON_SIZE);
this._workSpinner.actor.opacity = 0;
this._workSpinner.actor.show();
this.buttonLayout.visible = true;
this.clearButtons();
if (!this._disableUserList || this._verifyingUser)
this.addButton({ action: Lang.bind(this, this.cancel),
label: _("Cancel"),
key: Clutter.Escape },
{ expand: true,
x_fill: false,
y_fill: false,
x_align: St.Align.START,
y_align: St.Align.MIDDLE });
this.buttonLayout.add(this._workSpinner.actor,
{ expand: false,
x_fill: false,
y_fill: false,
x_align: St.Align.END,
y_align: St.Align.MIDDLE });
this._signInButton = this.addButton({ action: Lang.bind(this, function() {
hold.release();
}),
label: forSecret ? C_("button", "Sign In") : _("Next"),
default: true },
{ expand: false,
x_fill: false,
y_fill: false,
x_align: St.Align.END,
y_align: St.Align.MIDDLE });
this._updateSignInButtonSensitivity(this._promptEntry.text.length > 0);
this._promptEntryTextChangedId =
this._promptEntry.clutter_text.connect('text-changed',
Lang.bind(this, function() {
this._updateSignInButtonSensitivity(this._promptEntry.text.length > 0);
}));
},
_updateSensitivity: function(sensitive) {
this._promptEntry.reactive = sensitive;
this._promptEntry.clutter_text.editable = sensitive;
this._sessionList.updateSensitivity(sensitive);
this._updateSignInButtonSensitivity(sensitive);
},
_updateSignInButtonSensitivity: function(sensitive) {
if (this._signInButton) {
this._signInButton.reactive = sensitive;
this._signInButton.can_focus = sensitive;
}
},
_hidePrompt: function() {
this.setButtons([]);
@ -1016,20 +955,13 @@ const LoginDialog = new Lang.Class({
}
let tasks = [function() {
this._setWorking(false);
return GdmUtil.fadeOutActor(this._promptBox);
},
function() {
this._promptLoginHint.hide();
this._updateSensitivity(true);
this._promptEntry.reactive = true;
this._promptEntry.set_text('');
this.clearButtons();
this._workSpinner = null;
this._signInButton = null;
}];
let batch = new Batch.ConsecutiveBatch(this, tasks);
@ -1037,31 +969,6 @@ const LoginDialog = new Lang.Class({
return batch.run();
},
_setWorking: function(working) {
if (!this._workSpinner)
return;
if (working) {
this._workSpinner.play();
Tweener.addTween(this._workSpinner.actor,
{ opacity: 255,
delay: WORK_SPINNER_ANIMATION_DELAY,
time: WORK_SPINNER_ANIMATION_TIME,
transition: 'linear'
});
} else {
Tweener.addTween(this._workSpinner.actor,
{ opacity: 0,
time: WORK_SPINNER_ANIMATION_TIME,
transition: 'linear',
onCompleteScope: this,
onComplete: function() {
this._workSpinner.stop();
}
});
}
},
_askQuestion: function(verifier, serviceName, question, passwordChar) {
this._promptLabel.set_text(question);
@ -1073,10 +980,9 @@ const LoginDialog = new Lang.Class({
},
function() {
let text = this._promptEntry.get_text();
this._updateSensitivity(false);
this._setWorking(true);
this._userVerifier.answerQuery(serviceName, text);
let _text = this._promptEntry.get_text();
this._promptEntry.reactive = false;
this._userVerifier.answerQuery(serviceName, _text);
}];
let batch = new Batch.ConsecutiveBatch(this, tasks);
@ -1381,7 +1287,7 @@ const LoginDialog = new Lang.Class({
_onOpened: function() {
Main.ctrlAltTabManager.addGroup(this.dialogLayout,
_("Login Window"),
'dialog-password-symbolic',
'dialog-password',
{ sortGroup: CtrlAltTab.SortGroup.MIDDLE });
},
@ -1389,6 +1295,6 @@ const LoginDialog = new Lang.Class({
close: function() {
this.parent();
Main.ctrlAltTabManager.removeGroup(this.dialogLayout);
Main.ctrlAltTabManager.removeGroup(this._group);
}
});

View File

@ -11,7 +11,6 @@ const Gio = imports.gi.Gio;
const ShellJS = imports.gi.ShellJS;
const Config = imports.misc.config;
const FileUtils = imports.misc.fileUtils;
const ExtensionType = {
SYSTEM: 1,
@ -151,35 +150,53 @@ function installImporter(extension) {
const ExtensionFinder = new Lang.Class({
Name: 'ExtensionFinder',
_loadExtension: function(extensionDir, info, perUserDir) {
let fileType = info.get_file_type();
if (fileType != Gio.FileType.DIRECTORY)
return;
let uuid = info.get_name();
let existing = extensions[uuid];
if (existing) {
log('Extension %s already installed in %s. %s will not be loaded'.format(uuid, existing.path, extensionDir.get_path()));
_scanExtensionsInDirectory: function(dir, type) {
let fileEnum;
let file, info;
try {
fileEnum = dir.enumerate_children('standard::*', Gio.FileQueryInfoFlags.NONE, null);
} catch(e) {
if (e.domain != Gio.io_error_quark() || e.code != Gio.IOErrorEnum.NOT_FOUND)
logError(e, 'Could not enumerate extensions directory');
return;
}
let extension;
let type = extensionDir.has_prefix(perUserDir) ? ExtensionType.PER_USER
: ExtensionType.SYSTEM;
try {
extension = createExtensionObject(uuid, extensionDir, type);
} catch(e) {
logError(e, 'Could not load extension %s'.format(uuid));
return;
while ((info = fileEnum.next_file(null)) != null) {
let fileType = info.get_file_type();
if (fileType != Gio.FileType.DIRECTORY)
continue;
let uuid = info.get_name();
let extensionDir = dir.get_child(uuid);
let existing = extensions[uuid];
if (existing) {
log('Extension %s already installed in %s. %s will not be loaded'.format(uuid, existing.path, extensionDir.get_path()));
continue;
}
let extension;
try {
extension = createExtensionObject(uuid, extensionDir, type);
} catch(e) {
logError(e, 'Could not load extension %s'.format(uuid));
continue;
}
this.emit('extension-found', extension);
}
this.emit('extension-found', extension);
fileEnum.close(null);
},
scanExtensions: function() {
let perUserDir = Gio.File.new_for_path(global.userdatadir);
FileUtils.collectFromDatadirsAsync('extensions',
{ processFile: Lang.bind(this, this._loadExtension),
includeUserDir: true,
data: perUserDir });
let userExtensionsDir = Gio.File.new_for_path(GLib.build_filenamev([global.userdatadir, 'extensions']));
this._scanExtensionsInDirectory(userExtensionsDir, ExtensionType.PER_USER);
let systemDataDirs = GLib.get_system_data_dirs();
for (let i = 0; i < systemDataDirs.length; i++) {
let dirPath = GLib.build_filenamev([systemDataDirs[i], 'gnome-shell', 'extensions']);
let dir = Gio.file_new_for_path(dirPath);
if (dir.query_exists(null))
this._scanExtensionsInDirectory(dir, ExtensionType.SYSTEM);
}
}
});
Signals.addSignalMethods(ExtensionFinder.prototype);

View File

@ -2,12 +2,10 @@
const Gio = imports.gi.Gio;
const GLib = imports.gi.GLib;
const Lang = imports.lang;
const Params = imports.misc.params;
function listDirAsync(file, callback) {
let allFiles = [];
file.enumerate_children_async('standard::name,standard::type',
file.enumerate_children_async(Gio.FILE_ATTRIBUTE_STANDARD_NAME,
Gio.FileQueryInfoFlags.NONE,
GLib.PRIORITY_LOW, null, function (obj, res) {
let enumerator = obj.enumerate_children_finish(res);
@ -25,63 +23,6 @@ function listDirAsync(file, callback) {
});
}
function _collectFromDirectoryAsync(dir, loadState) {
function done() {
loadState.numLoading--;
if (loadState.loadedCallback &&
loadState.numLoading == 0)
loadState.loadedCallback(loadState.data);
}
dir.query_info_async('standard::type', Gio.FileQueryInfoFlags.NONE,
GLib.PRIORITY_DEFAULT, null, function(object, res) {
try {
object.query_info_finish(res);
} catch (e) {
if (!e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.NOT_FOUND))
log(e.message);
done();
return;
}
listDirAsync(dir, Lang.bind(this, function(infos) {
for (let i = 0; i < infos.length; i++)
loadState.processFile(dir.get_child(infos[i].get_name()),
infos[i], loadState.data);
done();
}));
});
}
function collectFromDatadirsAsync(subdir, params) {
params = Params.parse(params, { includeUserDir: false,
processFile: null,
loadedCallback: null,
data: null });
let loadState = { data: params.data,
numLoading: 0,
loadedCallback: params.loadedCallback,
processFile: params.processFile };
if (params.processFile == null) {
if (params.loadedCallback)
params.loadedCallback(params.data);
return;
}
let dataDirs = GLib.get_system_data_dirs();
if (params.includeUserDir)
dataDirs.unshift(GLib.get_user_data_dir());
loadState.numLoading = dataDirs.length;
for (let i = 0; i < dataDirs.length; i++) {
let path = GLib.build_filenamev([dataDirs[i], 'gnome-shell', subdir]);
let dir = Gio.File.new_for_path(path);
_collectFromDirectoryAsync(dir, loadState);
}
}
function deleteGFile(file) {
// Work around 'delete' being a keyword in JS.
return file['delete'](null);

View File

@ -17,6 +17,9 @@ const SystemdLoginManagerIface = <interface name='org.freedesktop.login1.Manager
<method name='Suspend'>
<arg type='b' direction='in'/>
</method>
<method name='Hibernate'>
<arg type='b' direction='in'/>
</method>
<method name='CanPowerOff'>
<arg type='s' direction='out'/>
</method>
@ -26,6 +29,9 @@ const SystemdLoginManagerIface = <interface name='org.freedesktop.login1.Manager
<method name='CanSuspend'>
<arg type='s' direction='out'/>
</method>
<method name='CanHibernate'>
<arg type='s' direction='out'/>
</method>
</interface>;
const SystemdLoginSessionIface = <interface name='org.freedesktop.login1.Session'>
@ -140,6 +146,15 @@ const LoginManagerSystemd = new Lang.Class({
});
},
canHibernate: function(asyncCallback) {
this._proxy.CanSuspendRemote(function(result, error) {
if (error)
asyncCallback(false);
else
asyncCallback(result[0] != 'no');
});
},
powerOff: function() {
this._proxy.PowerOffRemote(true);
},
@ -150,6 +165,10 @@ const LoginManagerSystemd = new Lang.Class({
suspend: function() {
this._proxy.SuspendRemote(true);
},
hibernate: function() {
this._proxy.HibernateRemote(true);
}
});
@ -215,6 +234,13 @@ const LoginManagerConsoleKit = new Lang.Class({
}));
},
canHibernate: function(asyncCallback) {
Mainloop.idle_add(Lang.bind(this, function() {
asyncCallback(this._upClient.get_can_hibernate());
return false;
}));
},
powerOff: function() {
this._proxy.StopRemote();
},
@ -225,5 +251,9 @@ const LoginManagerConsoleKit = new Lang.Class({
suspend: function() {
this._upClient.suspend_sync(null);
},
hibernate: function() {
this._upClient.hibernate_sync(null);
}
});

View File

@ -159,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
@ -208,3 +288,31 @@ function insertSorted(array, val, cmp) {
return pos;
}
/**
* wrapKeybinding:
*
* Wrap a keybinding handler so that
* it ignores an invocation if the shell is modal, but
* not when the overview is active, or when global
* keybindings are allowed by session mode.
* This function is only useful for keybindings installed
* with Meta.KeybindingFlags.HANDLE_WHEN_GRABBED
*/
function wrapKeybinding(handler, onlyInOverview) {
return function() {
let handle;
if (onlyInOverview) {
handle = Main.sessionMode.allowKeybindingsWhenModal ||
Main.modalCount == (Main.overview.visible ? 1 : 0);
} else {
handle = true;
}
if (handle)
return handler.apply(this, arguments);
else
return false;
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,6 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
const Clutter = imports.gi.Clutter;
const Gio = imports.gi.Gio;
const GLib = imports.gi.GLib;
const Gtk = imports.gi.Gtk;
const GMenu = imports.gi.GMenu;
@ -19,6 +18,7 @@ const IconGrid = imports.ui.iconGrid;
const Main = imports.ui.main;
const Overview = imports.ui.overview;
const PopupMenu = imports.ui.popupMenu;
const Search = imports.ui.search;
const Tweener = imports.ui.tweener;
const Workspace = imports.ui.workspace;
const Params = imports.misc.params;
@ -48,16 +48,18 @@ const AlphabeticalView = new Lang.Class({
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.actor.connect('notify::mapped', Lang.bind(this,
function() {
if (!this.actor.mapped)
return;
_onPan: function(action) {
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;
let adjustment = this.actor.vscroll.adjustment;
let direction = Overview.SwipeScrollDirection.VERTICAL;
Main.overview.setScrollAdjustment(adjustment, direction);
// Reset scroll on mapping
adjustment.value = 0;
}));
},
removeAll: function() {
@ -214,16 +216,6 @@ const ViewByCategories = new Lang.Class({
},
_addCategory: function(name, index, dir) {
let apps;
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,
@ -233,16 +225,18 @@ const ViewByCategories = new Lang.Class({
this._selectCategory(index);
}));
var apps;
if (dir == null) {
this._allCategoryButton = button;
} else {
apps = [];
this._loadCategory(dir, apps);
this._categories.push({ apps: apps,
name: name,
button: button });
}
this._categoryBox.add(button, { expand: true, x_fill: true, y_fill: false });
return true;
},
_removeAll: function() {
@ -268,9 +262,8 @@ const ViewByCategories = new Lang.Class({
var dir = iter.get_directory();
if (dir.get_is_nodisplay())
continue;
if (this._addCategory(dir.get_name(), i, dir))
i++;
this._addCategory(dir.get_name(), i, dir);
i++;
}
}
@ -311,10 +304,11 @@ const AllAppDisplay = new Lang.Class({
const AppSearchProvider = new Lang.Class({
Name: 'AppSearchProvider',
Extends: Search.SearchProvider,
_init: function() {
this.parent(_("APPLICATIONS"));
this._appSys = Shell.AppSystem.get_default();
this.id = 'applications';
},
getResultMetas: function(apps, callback) {
@ -339,15 +333,18 @@ const AppSearchProvider = new Lang.Class({
this.searchSystem.pushResults(this, this._appSys.subsearch(previousResults, terms));
},
activateResult: function(app) {
activateResult: function(app, params) {
params = Params.parse(params, { workspace: -1,
timestamp: 0 });
let event = Clutter.get_current_event();
let modifiers = event ? event.get_state() : 0;
let openNewWindow = modifiers & Clutter.ModifierType.CONTROL_MASK;
if (openNewWindow)
app.open_new_window(-1);
app.open_new_window(params.workspace);
else
app.activate();
app.activate_full(params.workspace, params.timestamp);
},
dragActivateResult: function(id, params) {
@ -367,10 +364,13 @@ const AppSearchProvider = new Lang.Class({
const SettingsSearchProvider = new Lang.Class({
Name: 'SettingsSearchProvider',
Extends: Search.SearchProvider,
_init: function() {
this.appInfo = Gio.DesktopAppInfo.new('gnome-control-center.desktop');
this.parent(_("SETTINGS"));
this._appSys = Shell.AppSystem.get_default();
this._gnomecc = this._appSys.lookup_app('gnome-control-center.desktop');
},
getResultMetas: function(prefs, callback) {
@ -379,7 +379,9 @@ const SettingsSearchProvider = new Lang.Class({
let pref = prefs[i];
metas.push({ 'id': pref,
'name': pref.get_name(),
'createIcon': function() { return null; }
'createIcon': function(size) {
return pref.create_icon_texture(size);
}
});
}
callback(metas);
@ -393,13 +395,21 @@ const SettingsSearchProvider = new Lang.Class({
this.searchSystem.pushResults(this, this._appSys.search_settings(terms));
},
activateResult: function(pref) {
pref.activate();
activateResult: function(pref, params) {
params = Params.parse(params, { workspace: -1,
timestamp: 0 });
pref.activate_full(params.workspace, params.timestamp);
},
launchSearch: function(terms) {
// FIXME: this should be a remote search provider
this.appInfo.launch([], global.create_app_launch_context());
dragActivateResult: function(pref, params) {
this.activateResult(pref, params);
},
createResultActor: function (resultMeta, terms) {
let app = resultMeta['id'];
let icon = new AppWellIcon(app);
return icon.actor;
}
});
@ -554,7 +564,6 @@ const AppWellIcon = new Lang.Class({
this.actor.set_hover(true);
this._menu.popup();
this._menuManager.ignoreRelease();
return false;
},

View File

@ -220,8 +220,25 @@ 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);
}
}
},
@ -388,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();
@ -400,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) {
@ -413,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());
@ -540,7 +553,7 @@ const BoxPointer = new Lang.Class({
_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.
@ -548,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;
}));
}
return false;
},
set xOffset(offset) {

View File

@ -11,6 +11,7 @@ const Mainloop = imports.mainloop;
const Shell = imports.gi.Shell;
const MSECS_IN_DAY = 24 * 60 * 60 * 1000;
const WEEKDATE_HEADER_WIDTH_DIGITS = 3;
const SHOW_WEEKDATE_KEY = 'show-weekdate';
// in org.gnome.desktop.interface
@ -94,6 +95,15 @@ function _getCalendarWeekForDate(date) {
return weekNumber;
}
function _getDigitWidth(actor){
let context = actor.get_pango_context();
let themeNode = actor.get_theme_node();
let font = themeNode.get_font();
let metrics = context.get_metrics(font, context.get_language());
let width = metrics.get_approximate_digit_width();
return width;
}
function _getCalendarDayAbbreviation(dayNumber) {
let abbreviations = [
/* Translators: Calendar grid abbreviation for Sunday.
@ -335,6 +345,8 @@ const Calendar = new Lang.Class({
_init: function() {
this._weekStart = Shell.util_get_week_start();
this._weekdate = NaN;
this._digitWidth = NaN;
this._settings = new Gio.Settings({ schema: 'org.gnome.shell.calendar' });
this._settings.connect('changed::' + SHOW_WEEKDATE_KEY, Lang.bind(this, this._onSettingsChange));
@ -407,6 +419,8 @@ const Calendar = new Lang.Class({
this.actor.add(this._topBox,
{ row: 0, col: 0, col_span: offsetCols + 7 });
this.actor.connect('style-changed', Lang.bind(this, this._onStyleChange));
let back = new St.Button({ style_class: 'calendar-change-month-back' });
this._topBox.add(back);
back.connect('clicked', Lang.bind(this, this._onPrevMonthButtonClicked));
@ -443,6 +457,18 @@ const Calendar = new Lang.Class({
this._firstDayIndex = this.actor.get_n_children();
},
_onStyleChange: function(actor, event) {
// width of a digit in pango units
this._digitWidth = _getDigitWidth(this.actor) / Pango.SCALE;
this._setWeekdateHeaderWidth();
},
_setWeekdateHeaderWidth: function() {
if (this.digitWidth != NaN && this._useWeekdate && this._weekdateHeader) {
this._weekdateHeader.set_width (this._digitWidth * WEEKDATE_HEADER_WIDTH_DIGITS);
}
},
_onScroll : function(actor, event) {
switch (event.get_scroll_direction()) {
case Clutter.ScrollDirection.UP:

View File

@ -60,14 +60,18 @@ const KeyringDialog = new Lang.Class({
this._controlTable = null;
let buttons = [{ label: '',
action: Lang.bind(this, this._onCancelButton),
key: Clutter.Escape
},
{ label: '',
action: Lang.bind(this, this._onContinueButton),
default: true
}]
this._cancelButton = this.addButton({ label: '',
action: Lang.bind(this, this._onCancelButton),
key: Clutter.Escape });
this._continueButton = this.addButton({ label: '',
action: Lang.bind(this, this._onContinueButton),
default: true },
{ expand: true, x_fill: false, x_align: St.Align.END });
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();
},

View File

@ -0,0 +1,647 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
const Clutter = imports.gi.Clutter;
const Gdk = imports.gi.Gdk;
const GLib = imports.gi.GLib;
const Gio = imports.gi.Gio;
const Lang = imports.lang;
const Meta = imports.gi.Meta;
const Shell = imports.gi.Shell;
const St = imports.gi.St;
const Main = imports.ui.main;
const MessageTray = imports.ui.messageTray;
const ShellMountOperation = imports.ui.shellMountOperation;
const Tweener = imports.ui.tweener;
const Util = imports.misc.util;
const INTERFACE_SETTINGS = 'org.gnome.desktop.interface';
const POWER_SETTINGS = 'org.gnome.settings-daemon.plugins.power';
const XSETTINGS_SETTINGS = 'org.gnome.settings-daemon.plugins.xsettings';
const TOUCHPAD_SETTINGS = 'org.gnome.settings-daemon.peripherals.touchpad';
const KEYBINDING_SETTINGS = 'org.gnome.settings-daemon.plugins.media-keys';
const CUSTOM_KEYBINDING_SETTINGS = 'org.gnome.settings-daemon.plugins.media-keys.custom-keybinding';
const A11Y_SETTINGS = 'org.gnome.desktop.a11y.applications';
const MAGNIFIER_SETTINGS = 'org.gnome.desktop.a11y.magnifier';
const INPUT_SOURCE_SETTINGS = 'org.gnome.desktop.input-sources';
const MediaKeysInterface = <interface name='org.gnome.SettingsDaemon.MediaKeys'>
<method name='GrabMediaPlayerKeys'>
<arg name='application' direction='in' type='s'/>
<arg name='time' direction='in' type='u'/>
</method>
<method name='ReleaseMediaPlayerKeys'>
<arg name='application' direction='in' type='s'/>
</method>
<signal name='MediaPlayerKeyPressed'>
<arg name='application' type='s'/>
<arg name='key' type='s'/>
</signal>
</interface>;
/* [ actionName, setting, hardcodedKeysym, overviewOnly, args ] */
/* (overviewOnly means that the keybinding is handled when the shell is not
modal, or when the overview is active, but not when other modal operations
are active; otherwise the keybinding is always handled) */
const DEFAULT_KEYBINDINGS = [
[ 'doTouchpadToggle', null, 'XF86TouchpadToggle', false ],
[ 'doTouchpadSet', null, 'XF86TouchpadOn', false, [ true ] ],
[ 'doTouchpadSet', null, 'XF86TouchpadOff', false, [ false ] ],
[ 'doMute', 'volume-mute', null, false, [ false ] ],
[ 'doVolumeAdjust', 'volume-down', null, false, [ Clutter.ScrollDirection.DOWN, false ] ],
[ 'doVolumeAdjust', 'volume-up', null, false, [ Clutter.ScrollDirection.UP, false ] ],
[ 'doMute', null, '<Alt>XF86AudioMute', false, [ true ] ],
[ 'doVolumeAdjust', null, '<Alt>XF86AudioLowerVolume', false, [ Clutter.ScrollDirection.DOWN, true ] ],
[ 'doVolumeAdjust', null, '<Alt>XF86AudioRaiseVolume', false, [ Clutter.ScrollDirection.UP, true ] ],
[ 'doLogout', 'logout', null, true ],
[ 'doEject', 'eject', null, false ],
[ 'doHome', 'home', null, true ],
[ 'doLaunchMimeHandler', 'media', null, true, [ 'application/x-vorbis+ogg' ] ],
[ 'doLaunchApp', 'calculator', null, true, [ 'gcalcltool.desktop' ] ],
[ 'doLaunchApp', 'search', null, true, [ 'tracker-needle.desktop' ] ],
[ 'doLaunchMimeHandler', 'email', null, true, [ 'x-scheme-handler/mailto' ] ],
[ 'doScreensaver', 'screensaver', null, true ],
[ 'doScreensaver', null, 'XF86ScreenSaver', true ],
[ 'doLaunchApp', 'help', null, true, [ 'yelp.desktop' ] ],
[ 'doSpawn', 'screenshot', null, true, [ ['gnome-screenshot'] ] ],
[ 'doSpawn', 'window-screenshot', null, true, [ ['gnome-screenshot', '--window'] ] ],
[ 'doSpawn', 'area-screenshot', null, true, [ ['gnome-screenshot', '--area'] ] ],
[ 'doSpawn', 'screenshot-clip', null, true, [ ['gnome-screenshot', '--clipboard'] ] ],
[ 'doSpawn', 'window-screenshot-clip', null, true, [ ['gnome-screenshot', '--window', '--clipboard'] ] ],
[ 'doSpawn', 'area-screenshot-clip', null, true, [ ['gnome-screenshot', '--area', '--clipboard'] ] ],
[ 'doLaunchMimeHandler', 'www', null, true, [ 'x-scheme-handler/http' ] ],
[ 'doMediaKey', 'play', null, true, [ 'Play' ] ],
[ 'doMediaKey', 'pause', null, true, [ 'Pause' ] ],
[ 'doMediaKey', 'stop', null, true, [ 'Stop' ] ],
[ 'doMediaKey', 'previous', null, true, [ 'Previous' ] ],
[ 'doMediaKey', 'next', null, true, [ 'Next' ] ],
[ 'doMediaKey', null, 'XF86AudioRewind', true, [ 'Rewind' ] ],
[ 'doMediaKey', null, 'XF86AudioForward', true, [ 'FastForward' ] ],
[ 'doMediaKey', null, 'XF86AudioRepeat', true, [ 'Repeat' ] ],
[ 'doMediaKey', null, 'XF86AudioRandomPlay', true, [ 'Shuffle' ] ],
[ 'doXRandRAction', null, '<Super>p', false, [ 'VideoModeSwitch' ] ],
/* Key code of the XF86Display key (Fn-F7 on Thinkpads, Fn-F4 on HP machines, etc.) */
[ 'doXRandRAction', null, 'XF86Display', false, [ 'VideoModeSwitch' ] ],
/* Key code of the XF86RotateWindows key (present on some tablets) */
[ 'doXRandRAction', null, 'XF86RotateWindows', false, [ 'Rotate' ] ],
[ 'doA11yAction', 'magnifier', null, true, [ 'screen-magnifier-enabled' ] ],
[ 'doA11yAction', 'screenreader', null, true, [ 'screen-reader-enabled' ] ],
[ 'doA11yAction', 'on-screen-keyboard', null, true, [ 'screen-keyboard-enabled' ] ],
[ 'doTextSize', 'increase-text-size', null, true, [ 1 ] ],
[ 'doTextSize', 'decrease-text-size', null, true, [ -1 ] ],
[ 'doToggleContrast', 'toggle-contrast', null, true ],
[ 'doMagnifierZoom', 'magnifier-zoom-in', null, true, [ 1 ] ],
[ 'doMagnifierZoom', 'magnifier-zoom-out', null, true, [ -1 ] ],
[ 'doPowerAction', null, 'XF86PowerOff', true, [ 'button-power' ] ],
/* the kernel / Xorg names really are like this... */
[ 'doPowerAction', null, 'XF86Suspend', false, [ 'button-sleep' ] ],
[ 'doPowerAction', null, 'XF86Sleep', false, [ 'button-suspend' ] ],
[ 'doPowerAction', null, 'XF86Hibernate', false, [ 'button-hibernate' ] ],
[ 'doBrightness', null, 'XF86MonBrightnessUp', false, [ 'Screen', 'StepUp' ] ],
[ 'doBrightness', null, 'XF86MonBrightnessDown', false, [ 'Screen', 'StepDown' ] ],
[ 'doBrightness', null, 'XF86KbdBrightnessUp', false, [ 'Keyboard', 'StepUp' ] ],
[ 'doBrightness', null, 'XF86KbdBrightnessDown', false, [ 'Keyboard', 'StepDown' ] ],
[ 'doBrightnessToggle', null, 'XF86KbdLightOnOff', false, ],
[ 'doInputSource', 'switch-input-source', null, false, [ +1 ] ],
[ 'doInputSource', 'switch-input-source-backward', null, false, [ -1 ] ],
[ 'doLaunchApp', null, 'XF86Battery', true, [ 'gnome-power-statistics.desktop' ] ]
];
var osdWin;
const OSDWindow = new Lang.Class({
Name: 'OSDWindow',
FADE_TIMEOUT: 1500,
FADE_DURATION: 100,
_init: function(iconName, value) {
/* 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.actor = new St.BoxLayout({ style_class: 'osd-window',
vertical: true,
reactive: false,
visible: false,
width: size,
height: size,
});
this._icon = new St.Icon({ icon_name: iconName,
icon_size: size / 2,
});
this.actor.add(this._icon, { expand: true,
x_align: St.Align.MIDDLE,
y_align: St.Align.MIDDLE });
this._value = value;
this._progressBar = new St.DrawingArea({ style_class: 'osd-progress-bar' });
this._progressBar.connect('repaint', Lang.bind(this, this._drawProgress));
this.actor.add(this._progressBar, { expand: true, x_fill: true, y_fill: false });
this._progressBar.visible = value !== undefined;
Main.layoutManager.addChrome(this.actor);
/* Position in the middle of primary monitor */
let [width, height] = this.actor.get_size();
this.actor.x = ((monitor.width - width) / 2) + monitor.x;
this.actor.y = monitor.y + (monitor.height / 2) + (monitor.height / 2 - height) / 2;
},
show: function() {
this.actor.show();
Tweener.addTween(this.actor,
{ opacity: 255,
time: this.FADE_DURATION / 1000,
transition: 'easeInQuad' });
if (this._timeoutId)
GLib.source_remove(this._timeoutId);
this._timeoutId = GLib.timeout_add(GLib.PRIORITY_DEFAULT, this.FADE_TIMEOUT, Lang.bind(this, this.hide));
},
hide: function() {
Tweener.addTween(this.actor,
{ opacity: 0,
time: this.FADE_DURATION / 1000,
transition: 'easeOutQuad',
onComplete: function() {
this.actor.destroy();
this.actor = null;
osdWin = null;
},
onCompleteScope: this });
return false;
},
setIcon: function(name) {
this._icon.icon_name = name;
},
setValue: function(value) {
if (value == this._value)
return;
this._value = value;
this._progressBar.visible = value !== undefined;
this._progressBar.queue_repaint();
},
_drawProgress: function(area) {
let cr = area.get_context();
let themeNode = this.actor.get_theme_node();
let color = themeNode.get_foreground_color();
Clutter.cairo_set_source_color(cr, color);
let [width, height] = area.get_surface_size();
width = width * this._value;
cr.moveTo(0,0);
cr.lineTo(width, 0);
cr.lineTo(width, height);
cr.lineTo(0, height);
cr.fill();
}
});
function showOSD(icon, value) {
if (osdWin) {
osdWin.setIcon(icon);
osdWin.setValue(value);
} else {
osdWin = new OSDWindow(icon, value);
}
osdWin.show();
}
const MediaKeysGrabber = new Lang.Class({
Name: 'MediaKeysGrabber',
_init: function() {
this._dbusImpl = Gio.DBusExportedObject.wrapJSObject(MediaKeysInterface, this);
this._apps = [];
},
enable: function() {
this._dbusImpl.export(Gio.DBus.session, '/org/gnome/SettingsDaemon/MediaKeys');
},
disable: function() {
this._dbusImpl.unexport();
},
GrabMediaPlayerKeysAsync: function(parameters, invocation) {
let [appName, time] = parameters;
/* I'm not sure of this code, but it is in gnome-settings-daemon
(letting alone that the introspection is wrong in glib...)
*/
if (time == Gdk.CURRENT_TIME) {
let tv = new GLib.TimeVal;
GLib.get_current_time(tv);
time = tv.tv_sec * 1000 + tv.tv_usec / 1000;
}
let pos = -1;
for (let i = 0; i < this._apps.length; i++) {
if (this._apps[i].appName == appName) {
pos = i;
break;
}
}
if (pos != -1)
this._freeMediaPlayer(pos);
let app = {
appName: appName,
name: invocation.get_sender(),
time: time,
watchId: Gio.DBus.session.watch_name(invocation.get_sender(),
Gio.BusNameWatcherFlags.NONE,
null,
Lang.bind(this, this._onNameVanished)),
};
Util.insertSorted(this._apps, app, function(a, b) {
return b.time-a.time;
});
invocation.return_value(GLib.Variant.new('()', []));
},
ReleaseMediaPlayerAsync: function(parameters, invocation) {
let name = invocation.get_sender();
let [appName] = parameters;
let pos = -1;
for (let i = 0; i < this._apps.length; i++) {
if (this._apps[i].appName == appName) {
pos = i;
break;
}
}
if (pos == -1) {
for (let i = 0; i < this._apps.length; i++) {
if (this._apps[i].name == name) {
pos = i;
break;
}
}
}
if (pos != -1)
this._freeMediaPlayer(pos);
invocation.return_value(GLib.Variant.new('()', []));
},
_freeMediaPlayer: function(pos) {
let app = this._apps[pos];
Gio.bus_unwatch_name(app.watchId)
this._apps.splice(pos, 1);
},
mediaKeyPressed: function(key) {
if (this._apps.length == 0) {
showOSD('action-unavailable-symbolic');
return;
}
let app = this._apps[0];
Gio.DBus.session.emit_signal(app.name,
'/org/gnome/SettingsDaemon/MediaKeys',
'org.gnome.SettingsDaemon.MediaKeys',
'MediaPlayerKeyPressed',
GLib.Variant.new('(ss)', [app.appName || '',
key]));
},
});
const MediaKeysManager = new Lang.Class({
Name: 'MediaKeysManager',
_init: function() {
this._a11yControl = Main.panel.statusArea.a11y;
this._volumeControl = Main.panel.statusArea.volume;
this._userMenu = Main.panel.statusArea.userMenu;
this._mediaPlayerKeys = new MediaKeysGrabber();
this._keybindingSettings = new Gio.Settings({ schema: KEYBINDING_SETTINGS });
},
enable: function() {
for (let i = 0; i < DEFAULT_KEYBINDINGS.length; i++) {
let [action, setting, keyval, overviewOnly, args] = DEFAULT_KEYBINDINGS[i];
let func = this[action];
if (!func) {
log('Keybinding action %s is missing'.format(action));
continue;
}
let name = setting ? setting : 'media-keys-keybindings-%d'.format(i);
let ok;
func = Util.wrapKeybinding(Lang.bind.apply(null, [this, func].concat(args)), overviewOnly);
if (setting)
ok = global.display.add_keybinding(setting, this._keybindingSettings,
Meta.KeyBindingFlags.BUILTIN |
Meta.KeyBindingFlags.IS_SINGLE |
Meta.KeyBindingFlags.HANDLE_WHEN_GRABBED, func);
else
ok = global.display.add_grabbed_key(name, keyval,
Meta.KeyBindingFlags.HANDLE_WHEN_GRABBED, func);
if (!ok)
log('Installing keybinding %s failed'.format(name));
}
this._customKeybindings = [];
this._changedId = this._keybindingSettings.connect('changed::custom-keybindings',
Lang.bind(this, this._reloadCustomKeybindings));
this._reloadCustomKeybindings();
this._mediaPlayerKeys.enable();
},
disable: function() {
for (let i = 0; i < DEFAULT_KEYBINDINGS.length; i++) {
let [action, setting, keyval, overviewOnly, args] = DEFAULT_KEYBINDINGS[i];
let name = setting ? setting : 'media-keys-keybindings-%d'.format(i);
if (setting)
global.display.remove_keybinding(setting, this._keybindingSettings);
else
global.display.remove_grabbed_key(name);
}
this._clearCustomKeybindings();
this._keybindingSettings.disconnect(this._changedId);
this._mediaPlayerKeys.disable();
},
_clearCustomKeybindings: function() {
for (let i = 0; i < this._customKeybindings.length; i++)
global.display.remove_keybinding('binding', this._customKeybindings[i]);
this._customKeybindings = [];
},
_reloadCustomKeybindings: function() {
this._clearCustomKeybindings();
let paths = this._keybindingSettings.get_strv('custom-keybindings');
for (let i = 0; i < paths.length; i++) {
let setting = new Gio.Settings({ schema: CUSTOM_KEYBINDING_SETTINGS,
path: paths[i] });
let func = Util.wrapKeybinding(Lang.bind(this, this.doCustom, setting), true);
global.display.add_keybinding('binding', setting,
Meta.KeyBindingFlags.IS_SINGLE |
Meta.KeyBindingFlags.HANDLE_WHEN_GRABBED, func);
this._customKeybindings.push(setting);
}
},
doCustom: function(display, screen, window, binding, settings) {
let command = settings.get_string('command');
Util.spawnCommandLine(command);
},
doTouchpadToggle: function(display, screen, window, binding) {
let settings = new Gio.Settings({ schema: TOUCHPAD_SETTINGS });
let enabled = settings.get_boolean('touchpad-enabled');
this.doTouchpadSet(display, screen, window, binding, !enabled);
settings.set_boolean(!enabled);
return true;
},
doTouchpadSet: function(display, screen, window, binding, enabled) {
showOSD(enabled ? 'input-touchpad-symbolic' : 'touchpad-disabled-symbolic');
return true;
},
doMute: function(display, screen, window, binding, quiet) {
let [icon, value] = this._volumeControl.volumeMenu.toggleMute(quiet);
showOSD(icon, value);
return true;
},
doVolumeAdjust: function(display, screen, window, binding, direction, quiet) {
let [icon, value] = this._volumeControl.volumeMenu.scroll(direction, quiet);
showOSD(icon, value);
return true;
},
doLogout: function(display, screen, window, binding) {
this._userMenu.logOut();
return true;
},
doEject: function(display, screen, window, binding) {
let volumeMonitor = Gio.VolumeMonitor.get();
let drives = volumeMonitor.get_connected_drives();
let score = 0, drive;
for (let i = 0; i < drives.length; i++) {
if (!drives[i].can_eject())
continue;
if (!drives[i].is_media_removable())
continue;
if (score < 1) {
drive = drives[i];
score = 1;
}
if (!drives[i].has_media())
continue;
if (score < 2) {
drive = drives[i];
score = 2;
break;
}
}
showOSD('media-eject-custom-symbolic');
if (!drive)
return true;
let mountOp = new ShellMountOperation.ShellMountOperation(drive);
drive.eject_with_operation(Gio.MountUnmountFlags.FORCE,
mountOp.mountOp, null, null);
return true;
},
doHome: function() {
let homeFile = Gio.file_new_for_path (GLib.get_home_dir());
let homeUri = homeFile.get_uri();
Gio.app_info_launch_default_for_uri(homeUri, null);
return true;
},
doLaunchMimeHandler: function(display, screen, window, binding, mimeType) {
let gioApp = Gio.AppInfo.get_default_for_type(mimeType, false);
if (gioApp != null) {
let app = Shell.AppSystem.get_default().lookup_app(gioApp.get_id());
app.open_new_window(-1);
} else {
log('Could not find default application for \'%s\' mime-type'.format(mimeType));
}
return true;
},
doLaunchApp: function(display, screen, window, binding, appId) {
let app = Shell.AppSystem.get_default().lookup_app(appId);
app.open_new_window(-1);
return true;
},
doScreensaver: function() {
// FIXME: handled in house, to the screenshield!
return true;
},
doSpawn: function(display, screen, window, binding, argv) {
Util.spawn(argv);
return true;
},
doMediaKey: function(display, screen, window, binding, key) {
this._mediaPlayerKeys.mediaKeyPressed(key);
},
_onXRandRFinished: function(connection, result) {
connection.call_finish(result);
this._XRandRCancellable = null;
},
doXRandRAction: function(display, screen, window, binding, action) {
if (this._XRandRCancellable)
this._XRandRCancellable.cancel();
this._XRandRCancellable = new Gio.Cancellable();
Gio.DBus.session.call('org.gnome.SettingsDaemon',
'/org/gnome/SettingsDaemon/XRANDR',
'org.gnome.SettingsDaemon.XRANDR_2',
action,
GLib.Variant.new('(x)', [global.get_current_time()]),
null, /* reply type */
Gio.DBusCallFlags.NONE,
-1,
this._XRandRCancellable,
Lang.bind(this, this._onXRandRFinished));
},
doA11yAction: function(display, screen, window, binding, key) {
let settings = new Gio.Settings({ schema: A11Y_SETTINGS });
let enabled = settings.get_boolean(key);
settings.set_boolean(key, !enabled);
},
doTextSize: function(display, screen, window, binding, multiplier) {
// Same values used in the Seeing tab of the Universal Access panel
const FACTORS = [ 0.75, 1.0, 1.25, 1.5 ];
// Figure out the current DPI scaling factor
let settings = new Gio.Settings({ schema: INTERFACE_SETTINGS });
let factor = settings.get_double('text-scaling-factor');
factor += multiplier * 0.25;
/* Try to find a matching value */
let distance = 1e6;
let best = 1.0;
for (let i = 0; i < FACTORS.length; i++) {
let d = Math.abs(factor - FACTORS[i]);
if (d < distance) {
best = factors[i];
distance = d;
}
}
if (best == 1.0)
settings.reset('text-scaling-factor');
else
settings.set_double('text-scaling-factor', best);
},
doToggleContrast: function(display, screen, window, binding) {
this._a11yControl.toggleHighContrast();
},
doMagnifierZoom: function(display, screen, window, binding, offset) {
let settings = new Gio.Settings({ schema: MAGNIFIER_SETTINGS });
let value = settings.get_value('mag-factor');
value = Math.round(value + offset);
settings.set_value('mag-factor', value);
},
doPowerAction: function(display, screen, window, binding, action) {
let settings = new Gio.Settings({ schema: POWER_SETTINGS });
switch (settings.get_string(action)) {
case 'suspend':
this._userMenu.suspend();
break;
case 'interactive':
case 'shutdown':
this._userMenu.shutdown();
break;
case 'hibernate':
this._userMenu.hibernate();
break;
case 'blank':
case 'default':
default:
break;
}
},
_onBrightnessFinished: function(connection, result, kind) {
let [percentage] = connection.call_finish(result).deep_unpack();
let icon = kind == 'Keyboard' ? 'keyboard-brightness-symbolic' : 'display-brightness-symbolic';
showOSD(icon, percentage / 100);
},
doBrightness: function(display, screen, window, binding, kind, action) {
let iface = 'org.gnome.SettingsDaemon.Power.' + kind;
let objectPath = '/org/gnome/SettingsDaemon/Power';
Gio.DBus.session.call('org.gnome.SettingsDaemon',
objectPath, iface, action,
null, null, /* parameters, reply type */
Gio.DBusCallFlags.NONE, -1, null,
Lang.bind(this, this._onBrightnessFinished, kind));
},
doInputSource: function(display, screen, window, binding, offset) {
let settings = new Gio.Settings({ schema: INPUT_SOURCE_SETTINGS });
let current = settings.get_uint('current');
let max = settings.get_strv('sources').length - 1;
current += offset;
if (current < 0)
current = 0;
else if (current > max)
current = max;
settings.set_uint('current', current);
},
});
const Component = MediaKeysManager;

View File

@ -598,7 +598,7 @@ const NetworkAgent = new Lang.Class({
},
enable: function() {
this._native.auto_register = true;
this._native.register();
},
disable: function() {
@ -612,9 +612,7 @@ const NetworkAgent = new Lang.Class({
this._vpnRequests[requestId].cancel(true);
this._vpnRequests = { };
this._native.auto_register = false;
if (this._native.registered)
this._native.unregister();
this._native.unregister();
},
_newRequest: function(agent, requestId, connection, settingName, hints, flags) {

View File

@ -49,7 +49,7 @@ const AuthenticationDialog = new Lang.Class({
let messageBox = new St.BoxLayout({ style_class: 'prompt-dialog-message-layout',
vertical: true });
mainContentBox.add(messageBox,
{ expand: true, y_align: St.Align.START });
{ y_align: St.Align.START });
this._subjectLabel = new St.Label({ style_class: 'prompt-dialog-headline',
text: _("Authentication Required") });
@ -159,13 +159,14 @@ const AuthenticationDialog = new Lang.Class({
messageBox.add(this._nullMessageLabel);
this._nullMessageLabel.show();
this._cancelButton = this.addButton({ label: _("Cancel"),
action: Lang.bind(this, this.cancel),
key: Clutter.Escape });
this._okButton = this.addButton({ label: _("Authenticate"),
action: Lang.bind(this, this._onAuthenticateButtonPressed),
default: true },
{ expand: true, x_fill: false, x_align: St.Align.END });
this.setButtons([{ label: _("Cancel"),
action: Lang.bind(this, this.cancel),
key: Clutter.Escape
},
{ label: _("Authenticate"),
action: Lang.bind(this, this._onAuthenticateButtonPressed),
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();
},

View File

@ -1,6 +1,5 @@
const Lang = imports.lang;
const Main = imports.ui.main;
const Gio = imports.gi.Gio;
const Meta = imports.gi.Meta;
@ -17,16 +16,13 @@ const Recorder = new Lang.Class({
},
enable: function() {
Main.wm.addKeybinding('toggle-recording',
this._bindingSettings,
Meta.KeyBindingFlags.NONE,
Main.KeybindingMode.NORMAL |
Main.KeybindingMode.OVERVIEW,
Lang.bind(this, this._toggleRecorder));
global.display.add_keybinding('toggle-recording',
this._bindingSettings,
Meta.KeyBindingFlags.NONE, Lang.bind(this, this._toggleRecorder));
},
disable: function() {
Main.wm.removeKeybinding('toggle-recording');
global.display.remove_keybinding('toggle-recording');
},
_ensureRecorder: function() {
@ -56,6 +52,8 @@ const Recorder = new Lang.Class({
Meta.disable_unredirect_for_screen(global.screen);
recorder.record();
}
return true;
}
});

View File

@ -383,12 +383,25 @@ const TelepathyClient = new Lang.Class({
}
/* Display notification to ask user to accept/reject request */
let source = this._ensureAppSource();
let source = this._ensureSubscriptionSource();
let notif = new SubscriptionRequestNotification(source, contact);
source.notify(notif);
},
_ensureSubscriptionSource: function() {
if (this._subscriptionSource == null) {
this._subscriptionSource = new MessageTray.Source(_("Subscription request"),
'gtk-dialog-question');
Main.messageTray.add(this._subscriptionSource);
this._subscriptionSource.connect('destroy', Lang.bind(this, function () {
this._subscriptionSource = null;
}));
}
return this._subscriptionSource;
},
_accountConnectionStatusNotifyCb: function(account) {
let connectionError = account.connection_error;
@ -402,7 +415,7 @@ const TelepathyClient = new Lang.Class({
return;
/* Display notification that account failed to connect */
let source = this._ensureAppSource();
let source = this._ensureAccountSource();
notif = new AccountNotification(source, account, connectionError);
this._accountNotifications[account.get_object_path()] = notif;
@ -412,16 +425,17 @@ const TelepathyClient = new Lang.Class({
source.notify(notif);
},
_ensureAppSource: function() {
if (this._appSource == null) {
this._appSource = new MessageTray.Source(_("Chat"), 'empathy');
Main.messageTray.add(this._appSource);
this._appSource.connect('destroy', Lang.bind(this, function () {
this._appSource = null;
_ensureAccountSource: function() {
if (this._accountSource == null) {
this._accountSource = new MessageTray.Source(_("Connection error"),
'gtk-dialog-error');
Main.messageTray.add(this._accountSource);
this._accountSource.connect('destroy', Lang.bind(this, function () {
this._accountSource = null;
}));
}
return this._appSource;
return this._accountSource;
}
});
@ -478,7 +492,7 @@ const ChatSource = new Lang.Class({
}));
item.connect('activate', Lang.bind(this, function() {
this.setMuted(!this.isMuted);
this.emit('done-displaying-content', false);
this.emit('done-displaying-content');
}));
rightClickMenu.add(item.actor);
return rightClickMenu;
@ -730,7 +744,8 @@ const ChatSource = new Lang.Class({
_ackMessages: function() {
// Don't clear our messages here, tp-glib will send a
// 'pending-message-removed' for each one.
this._channel.ack_all_pending_messages_async(null);
this._channel.ack_all_pending_messages_async(Lang.bind(this, function(src, result) {
this._channel.ack_all_pending_messages_finish(result);}));
}
});
@ -926,24 +941,26 @@ const ChatNotification = new Lang.Class({
}
// Show the word "Yesterday" and time if date is on yesterday
else if(daysAgo <2){
/* Translators: this is the word "Yesterday" followed by a time string. i.e. "Yesterday, 14:30"*/
/* Translators: this is a time format string followed by the word "Yesterday". i.e. "14:30 on Yesterday"*/
// xgettext:no-c-format
format = _("<b>Yesterday</b>, <b>%H:%M</b>");
format = _("<b>%H:%M</b> on Yesterday");
}
// Show a week day and time if date is in the last week
else if (daysAgo < 7) {
/* Translators: this is the week day name followed by a time string. i.e. "Monday, 14:30*/
/* Translators: this is a time format string followed by a week day name. i.e. "14:30 on Monday*/
// xgettext:no-c-format
format = _("<b>%A</b>, <b>%H:%M</b>");
format = _("<b>%H:%M</b> on <b>%A</b>");
} else if (date.getYear() == now.getYear()) {
/* Translators: this is the month name and day number followed by a time string. i.e. "May 25, 14:30"*/
/* Translators: this is a time format in the style of "14:30 on Wednesday, May 25",
shown when you get a chat message in the same year */
// xgettext:no-c-format
format = _("<b>%B</b> <b>%d</b>, <b>%H:%M</b>");
format = _("<b>%H:%M</b> on <b>%A</b>, <b>%B</b> <b>%d</b>");
} else {
/* Translators: this is the month name, day number, year number followed by a time string. i.e. "May 25 2012, 14:30"*/
/* Translators: this is a time format in the style of "14:30 on Wednesday, May 25, 2012",
shown when you get a chat message in a different year */
// xgettext:no-c-format
format = _("<b>%B</b> <b>%d</b> <b>%Y</b>, <b>%H:%M</b> ");
format = _("<b>%H:%M</b> on <b>%A</b>, <b>%B</b> <b>%d</b>, %Y");
}
return date.toLocaleFormat(format);
@ -1336,18 +1353,29 @@ const AccountNotification = new Lang.Class({
this.parent(source,
/* translators: argument is the account name, like
* name@jabber.org for example. */
_("Unable to connect to %s").format(account.get_display_name()),
this._getMessage(connectionError));
_("Connection to %s failed").format(account.get_display_name()),
null, { customContent: true });
this._label = new St.Label();
this.addActor(this._label);
this._updateMessage(connectionError);
this._account = account;
this.addButton('view', _("View account"));
this.addButton('reconnect', _("Reconnect"));
this.addButton('edit', _("Edit account"));
this.connect('action-invoked', Lang.bind(this, function(self, action) {
switch (action) {
case 'view':
let cmd = 'empathy-accounts --select-account=' +
account.get_path_suffix();
case 'reconnect':
// If it fails again, a new notification should pop up with the
// new error.
account.reconnect_async(null);
break;
case 'edit':
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;
@ -1370,19 +1398,19 @@ const AccountNotification = new Lang.Class({
if (status == Tp.ConnectionStatus.CONNECTED) {
this.destroy();
} else if (status == Tp.ConnectionStatus.DISCONNECTED) {
this.update(this.title, this._getMessage(account.connection_error));
this._updateMessage(account.connection_error);
}
}));
},
_getMessage: function(connectionError) {
_updateMessage: function(connectionError) {
let message;
if (connectionError in _connectionErrorMessages) {
message = _connectionErrorMessages[connectionError];
} else {
message = _("Unknown reason");
}
return message;
this._label.set_text(message);
},
destroy: function() {

View File

@ -1,14 +1,15 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
const Clutter = imports.gi.Clutter;
const Gdk = imports.gi.Gdk;
const Gtk = imports.gi.Gtk;
const Lang = imports.lang;
const Meta = imports.gi.Meta;
const Shell = imports.gi.Shell;
const St = imports.gi.St;
const AltTab = imports.ui.altTab;
const Main = imports.ui.main;
const SwitcherPopup = imports.ui.switcherPopup;
const Params = imports.misc.params;
const Tweener = imports.ui.tweener;
@ -26,9 +27,6 @@ const CtrlAltTabManager = new Lang.Class({
_init: function() {
this._items = [];
this.addGroup(global.window_group, _("Windows"),
'emblem-documents-symbolic', { sortGroup: SortGroup.TOP,
focusCallback: Lang.bind(this, this._focusWindows) });
},
addGroup: function(root, name, icon, params) {
@ -42,13 +40,11 @@ const CtrlAltTabManager = new Lang.Class({
this._items.push(item);
root.connect('destroy', Lang.bind(this, function() { this.removeGroup(root); }));
if (root instanceof St.Widget)
global.focus_manager.add_group(root);
global.focus_manager.add_group(root);
},
removeGroup: function(root) {
if (root instanceof St.Widget)
global.focus_manager.remove_group(root);
global.focus_manager.remove_group(root);
for (let i = 0; i < this._items.length; i++) {
if (this._items[i].root == root) {
this._items.splice(i, 1);
@ -57,9 +53,11 @@ const CtrlAltTabManager = new Lang.Class({
}
},
focusGroup: function(item, timestamp) {
if (item.focusCallback) {
item.focusCallback(timestamp);
focusGroup: function(item) {
if (item.window) {
Main.activateWindow(item.window);
} else if (item.focusCallback) {
item.focusCallback();
} else {
if (global.stage_input_mode == Shell.StageInputMode.NONREACTIVE ||
global.stage_input_mode == Shell.StageInputMode.NORMAL)
@ -77,14 +75,24 @@ const CtrlAltTabManager = new Lang.Class({
if (a.sortGroup != b.sortGroup)
return a.sortGroup - b.sortGroup;
let ax, bx, y;
[ax, y] = a.proxy.get_transformed_position();
[bx, y] = b.proxy.get_transformed_position();
let y;
if (a.x == undefined) {
if (a.window)
a.x = a.window.get_compositor_private().x;
else
[a.x, y] = a.proxy.get_transformed_position();
}
if (b.x == undefined) {
if (b.window)
b.x = b.window.get_compositor_private().x;
else
[b.x, y] = b.proxy.get_transformed_position();
}
return ax - bx;
return a.x - b.x;
},
popup: function(backward, binding, mask) {
popup: function(backwards, mask) {
// Start with the set of focus groups that are currently mapped
let items = this._items.filter(function (item) { return item.proxy.mapped; });
@ -102,7 +110,8 @@ const CtrlAltTabManager = new Lang.Class({
icon = app.create_icon_texture(POPUP_APPICON_SIZE);
else
icon = textureCache.bind_pixbuf_property(windows[i], 'icon');
items.push({ name: windows[i].title,
items.push({ window: windows[i],
name: windows[i].title,
iconActor: icon,
sortGroup: SortGroup.MIDDLE });
}
@ -114,63 +123,187 @@ const CtrlAltTabManager = new Lang.Class({
items.sort(Lang.bind(this, this._sortItems));
if (!this._popup) {
this._popup = new CtrlAltTabPopup(items);
this._popup.show(backward, binding, mask);
this._popup = new CtrlAltTabPopup();
this._popup.show(items, backwards, mask);
this._popup.actor.connect('destroy',
Lang.bind(this, function() {
this._popup = null;
}));
}
},
_focusWindows: function(timestamp) {
global.set_stage_input_mode(Shell.StageInputMode.NORMAL);
global.stage.key_focus = null;
global.screen.focus_default_window(timestamp);
}
});
function mod(a, b) {
return (a + b) % b;
}
const CtrlAltTabPopup = new Lang.Class({
Name: 'CtrlAltTabPopup',
Extends: SwitcherPopup.SwitcherPopup,
_createSwitcher: function() {
this._switcherList = new CtrlAltTabSwitcher(this._items);
_init : function() {
this.actor = new Shell.GenericContainer({ name: 'ctrlAltTabPopup',
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));
this.actor.connect('destroy', Lang.bind(this, this._onDestroy));
this._haveModal = false;
this._modifierMask = 0;
this._selection = 0;
Main.uiGroup.add_actor(this.actor);
},
_getPreferredWidth: function (actor, forHeight, alloc) {
let primary = Main.layoutManager.primaryMonitor;
alloc.min_size = primary.width;
alloc.natural_size = primary.width;
},
_getPreferredHeight: function (actor, forWidth, alloc) {
let primary = Main.layoutManager.primaryMonitor;
alloc.min_size = primary.height;
alloc.natural_size = primary.height;
},
_allocate: function (actor, box, flags) {
let childBox = new Clutter.ActorBox();
let primary = Main.layoutManager.primaryMonitor;
let leftPadding = this.actor.get_theme_node().get_padding(St.Side.LEFT);
let vPadding = this.actor.get_theme_node().get_vertical_padding();
let hPadding = this.actor.get_theme_node().get_horizontal_padding();
let [childMinHeight, childNaturalHeight] = this._switcher.actor.get_preferred_height(primary.width - hPadding);
let [childMinWidth, childNaturalWidth] = this._switcher.actor.get_preferred_width(childNaturalHeight);
childBox.x1 = Math.max(primary.x + leftPadding, primary.x + Math.floor((primary.width - childNaturalWidth) / 2));
childBox.x2 = Math.min(primary.x + primary.width - hPadding, childBox.x1 + childNaturalWidth);
childBox.y1 = primary.y + Math.floor((primary.height - childNaturalHeight) / 2);
childBox.y2 = childBox.y1 + childNaturalHeight;
this._switcher.actor.allocate(childBox, flags);
},
show : function(items, startBackwards, mask) {
if (!Main.pushModal(this.actor))
return false;
this._haveModal = true;
this._modifierMask = AltTab.primaryModifier(mask);
this._keyPressEventId = this.actor.connect('key-press-event', Lang.bind(this, this._keyPressEvent));
this._keyReleaseEventId = this.actor.connect('key-release-event', Lang.bind(this, this._keyReleaseEvent));
this._items = items;
this._switcher = new CtrlAltTabSwitcher(items);
this.actor.add_actor(this._switcher.actor);
if (startBackwards)
this._selection = this._items.length - 1;
this._select(this._selection);
let [x, y, mods] = global.get_pointer();
if (!(mods & this._modifierMask)) {
this._finish();
return false;
}
this.actor.opacity = 0;
this.actor.show();
Tweener.addTween(this.actor,
{ opacity: 255,
time: POPUP_FADE_TIME,
transition: 'easeOutQuad'
});
return true;
},
_initialSelection: function(backward, binding) {
if (binding == 'switch-panels') {
if (backward)
this._selectedIndex = this._items.length - 1;
} else if (binding == 'switch-panels-backward') {
if (!backward)
this._selectedIndex = this._items.length - 1;
}
this._select(this._selectedIndex);
_next : function() {
return mod(this._selection + 1, this._items.length);
},
_keyPressHandler: function(keysym, backwards, action) {
if (action == Meta.KeyBindingAction.SWITCH_PANELS)
this._select(backwards ? this._previous() : this._next());
else if (action == Meta.KeyBindingAction.SWITCH_PANELS_BACKWARD)
this._select(backwards ? this._next() : this._previous());
else if (keysym == Clutter.Left)
this._select(this._previous());
else if (keysym == Clutter.Right)
_previous : function() {
return mod(this._selection - 1, this._items.length);
},
_keyPressEvent : function(actor, event) {
let keysym = event.get_key_symbol();
let shift = (event.get_state() & Clutter.ModifierType.SHIFT_MASK);
if (shift && keysym == Clutter.KEY_Tab)
keysym = Clutter.ISO_Left_Tab;
if (keysym == Clutter.KEY_Escape)
this.destroy();
else if (keysym == Clutter.KEY_Tab)
this._select(this._next());
else if (keysym == Clutter.KEY_ISO_Left_Tab)
this._select(this._previous());
else if (keysym == Clutter.KEY_Left)
this._select(this._previous());
else if (keysym == Clutter.KEY_Right)
this._select(this._next());
return true;
},
_finish : function(time) {
this.parent(time);
Main.ctrlAltTabManager.focusGroup(this._items[this._selectedIndex], time);
_keyReleaseEvent : function(actor, event) {
let [x, y, mods] = global.get_pointer();
let state = mods & this._modifierMask;
if (state == 0)
this._finish();
return true;
},
_finish : function() {
this.destroy();
Main.ctrlAltTabManager.focusGroup(this._items[this._selection]);
},
_popModal: function() {
if (this._haveModal) {
Main.popModal(this.actor);
this._haveModal = false;
}
},
destroy : function() {
this._popModal();
Tweener.addTween(this.actor,
{ opacity: 0,
time: POPUP_FADE_TIME,
transition: 'easeOutQuad',
onComplete: Lang.bind(this,
function() {
this.actor.destroy();
})
});
},
_onDestroy : function() {
this._popModal();
if (this._keyPressEventId)
this.actor.disconnect(this._keyPressEventId);
if (this._keyReleaseEventId)
this.actor.disconnect(this._keyReleaseEventId);
},
_select : function(num) {
this._selection = num;
this._switcher.highlight(num);
}
});
const CtrlAltTabSwitcher = new Lang.Class({
Name: 'CtrlAltTabSwitcher',
Extends: SwitcherPopup.SwitcherList,
Extends: AltTab.SwitcherList,
_init : function(items) {
this.parent(true);

View File

@ -637,10 +637,8 @@ const Dash = new Lang.Class({
icon.setIconSize(this.iconSize);
// Don't animate the icon size change when the overview
// is transitioning, not visible or when initially filling
// the dash
if (!Main.overview.visible || Main.overview.animationInProgress ||
!this._shownInitially)
// is not visible or when initially filling the dash
if (!Main.overview.visible || !this._shownInitially)
continue;
let [targetWidth, targetHeight] = icon.icon.get_size();
@ -764,9 +762,8 @@ const Dash = new Lang.Class({
for (let i = 0; i < removedActors.length; i++) {
let item = removedActors[i]._delegate;
// Don't animate item removal when the overview is transitioning
// or hidden
if (Main.overview.visible && !Main.overview.animationInProgress)
// Don't animate item removal when the overview is hidden
if (Main.overview.visible)
item.animateOutAndDestroy();
else
item.destroy();
@ -781,9 +778,8 @@ const Dash = new Lang.Class({
return;
}
// Don't animate item addition when the overview is transitioning
// or hidden
if (!Main.overview.visible || Main.overview.animationInProgress)
// Don't animate item addition when the overview is hidden
if (!Main.overview.visible)
return;
for (let i = 0; i < addedItems.length; i++)

View File

@ -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);
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 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});
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');
app.activate();
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)
}
}
}
});

View File

@ -234,7 +234,7 @@ const _Draggable = new Lang.Class({
this._dragY = this._dragStartY = stageY;
if (this.actor._delegate && this.actor._delegate.getDragActor) {
this._dragActor = this.actor._delegate.getDragActor();
this._dragActor = this.actor._delegate.getDragActor(this._dragStartX, this._dragStartY);
this._dragActor.reparent(Main.uiGroup);
this._dragActor.raise_top();
Shell.util_set_hidden_from_pick(this._dragActor, true);

View File

@ -126,10 +126,13 @@ function logExtensionError(uuid, error) {
let message = '' + error;
extension.state = ExtensionState.ERROR;
if (error.state)
extension.state = error.state;
else
extension.state = ExtensionState.ERROR;
if (!extension.errors)
extension.errors = [];
extension.errors.push(message);
log('Extension "%s" had error: %s'.format(uuid, message));
_signals.emit('extension-state-changed', { uuid: uuid,
@ -142,16 +145,18 @@ function loadExtension(extension) {
extension.state = ExtensionState.ERROR;
if (ExtensionUtils.isOutOfDate(extension)) {
extension.state = ExtensionState.OUT_OF_DATE;
let error = new Error('extension is not compatible with current GNOME Shell and/or GJS version');
error.state = ExtensionState.OUT_OF_DATE;
throw error;
}
let enabled = enabledExtensions.indexOf(extension.uuid) != -1;
if (enabled) {
initExtension(extension.uuid);
if (extension.state == ExtensionState.DISABLED)
enableExtension(extension.uuid);
} else {
let enabled = enabledExtensions.indexOf(extension.uuid) != -1;
if (enabled) {
initExtension(extension.uuid);
if (extension.state == ExtensionState.DISABLED)
enableExtension(extension.uuid);
} else {
extension.state = ExtensionState.INITIALIZED;
}
extension.state = ExtensionState.INITIALIZED;
}
_signals.emit('extension-state-changed', extension);
@ -212,16 +217,8 @@ function initExtension(uuid) {
_signals.emit('extension-loaded', uuid);
}
function getEnabledExtensions() {
let extensions = global.settings.get_strv(ENABLED_EXTENSIONS_KEY);
if (!Array.isArray(Main.sessionMode.enabledExtensions))
return extensions;
return Main.sessionMode.enabledExtensions.concat(extensions);
}
function onEnabledExtensionsChanged() {
let newEnabledExtensions = getEnabledExtensions();
let newEnabledExtensions = global.settings.get_strv(ENABLED_EXTENSIONS_KEY);
if (!enabled)
return;
@ -255,7 +252,7 @@ function onEnabledExtensionsChanged() {
function _loadExtensions() {
global.settings.connect('changed::' + ENABLED_EXTENSIONS_KEY, onEnabledExtensionsChanged);
enabledExtensions = getEnabledExtensions();
enabledExtensions = global.settings.get_strv(ENABLED_EXTENSIONS_KEY);
let finder = new ExtensionUtils.ExtensionFinder();
finder.connect('extension-found', function(signals, extension) {
@ -297,17 +294,10 @@ function disableAllExtensions() {
}
function _sessionUpdated() {
// For now sessionMode.allowExtensions controls extensions from both the
// 'enabled-extensions' preference and the sessionMode.enabledExtensions
// property; it might make sense to make enabledExtensions independent
// from allowExtensions in the future
if (Main.sessionMode.allowExtensions) {
if (initted)
onEnabledExtensionsChanged();
if (Main.sessionMode.allowExtensions)
enableAllExtensions();
} else {
else
disableAllExtensions();
}
}
function init() {

45
js/ui/flashspot.js Normal file
View 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();
})
});
}
});

View File

@ -23,7 +23,6 @@ function _navigateActor(actor) {
// GrabHelper:
// @owner: the actor that owns the GrabHelper
// @params: optional parameters to pass to Main.pushModal()
//
// Creates a new GrabHelper object, for dealing with keyboard and pointer grabs
// associated with a set of actors.
@ -35,14 +34,14 @@ function _navigateActor(actor) {
const GrabHelper = new Lang.Class({
Name: 'GrabHelper',
_init: function(owner, params) {
_init: function(owner) {
this._owner = owner;
this._modalParams = params;
this._grabStack = [];
this._actors = [];
this._capturedEventId = 0;
this._eventId = 0;
this._keyFocusNotifyId = 0;
this._focusWindowChangedId = 0;
this._ignoreRelease = false;
@ -77,12 +76,9 @@ const GrabHelper = new Lang.Class({
},
_isWithinGrabbedActor: function(actor) {
let currentActor = this.currentGrab.actor;
while (actor) {
if (this._actors.indexOf(actor) != -1)
return true;
if (actor == currentActor)
return true;
actor = actor.get_parent();
}
return false;
@ -92,14 +88,6 @@ const GrabHelper = new Lang.Class({
return this._grabStack[this._grabStack.length - 1] || {};
},
get grabbed() {
return this._grabStack.length > 0;
},
get grabStack() {
return this._grabStack;
},
_findStackIndex: function(actor) {
if (!actor)
return -1;
@ -111,16 +99,6 @@ const GrabHelper = new Lang.Class({
return -1;
},
_actorInGrabStack: function(actor) {
while (actor) {
let idx = this._findStackIndex(actor);
if (idx >= 0)
return idx;
actor = actor.get_parent();
}
return -1;
},
isActorGrabbed: function(actor) {
return this._findStackIndex(actor) >= 0;
},
@ -160,7 +138,6 @@ const GrabHelper = new Lang.Class({
params = Params.parse(params, { actor: null,
modal: false,
grabFocus: false,
focus: null,
onUngrab: null });
let focus = global.stage.key_focus;
@ -178,14 +155,9 @@ const GrabHelper = new Lang.Class({
if (params.grabFocus && !this._takeFocusGrab(hadFocus))
return false;
if (params.focus)
params.focus.grab_key_focus();
else if (hadFocus || params.grabFocus)
if (hadFocus || params.grabFocus)
_navigateActor(newFocus);
if ((params.grabFocus || params.modal) && !this._capturedEventId)
this._capturedEventId = global.stage.connect('captured-event', Lang.bind(this, this._onCapturedEvent));
this._grabStack.push(params);
return true;
},
@ -193,8 +165,11 @@ const GrabHelper = new Lang.Class({
_takeModalGrab: function() {
let firstGrab = (this._modalCount == 0);
if (firstGrab) {
if (!Main.pushModal(this._owner, this._modalParams))
if (!Main.pushModal(this._owner))
return false;
this._capturedEventId = global.stage.connect('captured-event', Lang.bind(this, this._onCapturedEvent));
this._eventId = global.stage.connect('event', Lang.bind(this, this._onEvent));
}
this._modalCount++;
@ -206,6 +181,16 @@ const GrabHelper = new Lang.Class({
if (this._modalCount > 0)
return;
if (this._capturedEventId > 0) {
global.stage.disconnect(this._capturedEventId);
this._capturedEventId = 0;
}
if (this._eventId > 0) {
global.stage.disconnect(this._eventId);
this._eventId = 0;
}
Main.popModal(this._owner);
global.sync_pointer();
},
@ -217,6 +202,7 @@ const GrabHelper = new Lang.Class({
this._grabbedFromKeynav = hadFocus;
this._preGrabInputMode = global.stage_input_mode;
this._prevFocusedWindow = metaDisplay.focus_window;
if (this._preGrabInputMode == Shell.StageInputMode.NONREACTIVE ||
this._preGrabInputMode == Shell.StageInputMode.NORMAL) {
@ -255,7 +241,13 @@ const GrabHelper = new Lang.Class({
global.set_stage_input_mode(Shell.StageInputMode.FOCUSED);
}
global.screen.focus_default_window(global.get_current_time());
if (this._prevFocusedWindow) {
let metaDisplay = global.screen.get_display();
if (!metaDisplay.focus_window) {
metaDisplay.set_input_focus_window(this._prevFocusedWindow,
false, global.get_current_time());
}
}
},
// ignoreRelease:
@ -276,8 +268,7 @@ const GrabHelper = new Lang.Class({
// If the actor that was popped from the grab stack was not the actor
// That was passed in, this call is ignored.
ungrab: function(params) {
params = Params.parse(params, { actor: this.currentGrab.actor,
isUser: false });
params = Params.parse(params, { actor: this.currentGrab.actor });
let grabStackIndex = this._findStackIndex(params.actor);
if (grabStackIndex < 0)
@ -295,7 +286,7 @@ const GrabHelper = new Lang.Class({
let poppedGrab = poppedGrabs[i];
if (poppedGrab.onUngrab)
poppedGrab.onUngrab(params.isUser);
poppedGrab.onUngrab();
if (poppedGrab.modal)
this._releaseModalGrab();
@ -304,11 +295,6 @@ 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];
_navigateActor(poppedGrab.savedFocus);
@ -317,20 +303,13 @@ const GrabHelper = new Lang.Class({
_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;
if (release && this._ignoreRelease) {
this._ignoreRelease = false;
return true;
return false;
}
if (!button && this._modalCount == 0)
@ -347,22 +326,33 @@ const GrabHelper = new Lang.Class({
// which should be a release event.
if (press)
this._ignoreRelease = true;
let i = this._actorInGrabStack(event.get_source()) + 1;
this.ungrab({ actor: this._grabStack[i].actor, isUser: true });
this.ungrab({ actor: this._grabStack[0].actor });
}
return this._modalCount > 0;
},
// We catch 'event' rather than 'key-press-event' so that we get
// a chance to run before the overview's own Escape check
_onEvent: function(actor, event) {
if (event.type() == Clutter.EventType.KEY_PRESS &&
event.get_key_symbol() == Clutter.KEY_Escape) {
this.ungrab();
return true;
}
return false;
},
_onKeyFocusChanged: function() {
let focus = global.stage.key_focus;
if (!focus || !this._isWithinGrabbedActor(focus))
this.ungrab({ isUser: true });
this.ungrab();
},
_focusWindowChanged: function() {
let metaDisplay = global.screen.get_display();
if (metaDisplay.focus_window != null)
this.ungrab({ isUser: true });
this.ungrab();
}
});

View File

@ -23,8 +23,6 @@ const BaseIcon = new Lang.Class({
this.actor._delegate = this;
this.actor.connect('style-changed',
Lang.bind(this, this._onStyleChanged));
this.actor.connect('destroy',
Lang.bind(this, this._onDestroy));
this._spacing = 0;
@ -54,9 +52,6 @@ const BaseIcon = new Lang.Class({
this._setSizeManually = params.setSizeManually;
this.icon = null;
let cache = St.TextureCache.get_default();
this._iconThemeChangedId = cache.connect('icon-theme-changed', Lang.bind(this, this._onIconThemeChanged));
},
_allocate: function(actor, box, flags) {
@ -151,22 +146,7 @@ const BaseIcon = new Lang.Class({
size = found ? len : ICON_SIZE;
}
if (this.iconSize == size && this._iconBin.child)
return;
this._createIconTexture(size);
},
_onDestroy: function() {
if (this._iconThemeChangedId > 0) {
let cache = St.TextureCache.get_default();
cache.disconnect(this._iconThemeChangedId);
this._iconThemeChangedId = 0;
}
},
_onIconThemeChanged: function() {
this._createIconTexture(this.iconSize);
}
});
@ -218,11 +198,7 @@ const IconGrid = new Lang.Class({
_getPreferredHeight: function (grid, forWidth, alloc) {
let children = this._getVisibleChildren();
let nColumns;
if (forWidth < 0)
nColumns = children.length;
else
nColumns = this._computeLayout(forWidth)[0];
let [nColumns, usedWidth] = this._computeLayout(forWidth);
let nRows;
if (nColumns > 0)
nRows = Math.ceil(children.length / nColumns);

View File

@ -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
@ -149,18 +182,6 @@ const Keyboard = new Lang.Class({
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;
},
init: function () {
@ -230,7 +251,7 @@ const Keyboard = new Lang.Class({
this._focusNotifyId = global.stage.connect('notify::key-focus', Lang.bind(this, this._onKeyFocusChanged));
if (show)
this.show(Main.layoutManager.focusIndex);
this.show();
else
this._createSource();
},
@ -252,14 +273,10 @@ 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); }));
},
_addKeys: function () {
@ -314,19 +331,6 @@ const Keyboard = new Lang.Class({
return trayButton;
},
_onCapturedEvent: function(actor, event) {
let type = event.type();
let press = type == Clutter.EventType.BUTTON_PRESS;
let release = type == Clutter.EventType.BUTTON_RELEASE;
if (press)
this._capturedPress = true;
else if (release && this._capturedPress)
this._hideSubkeys();
return true;
},
_addRows : function (keys, layout) {
let keyboard_row = new St.BoxLayout();
for (let i = 0; i < keys.length; ++i) {
@ -349,19 +353,6 @@ const Keyboard = new Lang.Class({
// Add new key for hiding message tray
right_box.add(this._getTrayIcon());
}
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();
}));
}
keyboard_row.add(left_box, { expand: true, x_fill: false, x_align: St.Align.START });
keyboard_row.add(right_box, { expand: true, x_fill: false, x_align: St.Align.END });
@ -384,7 +375,7 @@ const Keyboard = new Lang.Class({
if (!this._enableKeyboard)
return;
let monitor = Main.layoutManager.keyboardMonitor;
let monitor = Main.layoutManager.bottomMonitor;
let maxHeight = monitor.height / 3;
this.actor.width = monitor.width;
@ -471,79 +462,18 @@ 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;
show: function () {
this._redraw();
Main.layoutManager.showKeyboard();
this._destroySource();
},
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();
@ -572,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)
@ -587,11 +510,9 @@ 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);
this.show();
},
Hide: function(timestamp) {
@ -601,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();
@ -647,7 +566,6 @@ const KeyboardSource = new Lang.Class({
},
open: function() {
// Show the OSK below the message tray
this._keyboard.show(Main.layoutManager.bottomIndex);
this._keyboard.show();
}
});

View File

@ -16,7 +16,7 @@ const Tweener = imports.ui.tweener;
const HOT_CORNER_ACTIVATION_TIMEOUT = 0.5;
const STARTUP_ANIMATION_TIME = 0.2;
const KEYBOARD_ANIMATION_TIME = 0.15;
const KEYBOARD_ANIMATION_TIME = 0.5;
const PLYMOUTH_TRANSITION_TIME = 1;
const MonitorConstraint = new Lang.Class({
@ -103,7 +103,6 @@ const LayoutManager = new Lang.Class({
this.monitors = [];
this.primaryMonitor = null;
this.primaryIndex = -1;
this._keyboardIndex = -1;
this._hotCorners = [];
this._background = null;
this._leftPanelBarrier = 0;
@ -124,7 +123,7 @@ const LayoutManager = new Lang.Class({
this.addChrome(this.panelBox, { affectsStruts: true,
trackFullscreen: true });
this.panelBox.connect('allocation-changed',
Lang.bind(this, this._panelBoxChanged));
Lang.bind(this, this._updatePanelBarriers));
this.trayBox = new St.Widget({ name: 'trayBox',
layout_manager: new Clutter.BinLayout() });
@ -241,8 +240,9 @@ const LayoutManager = new Lang.Class({
this.panelBox.set_position(this.primaryMonitor.x, this.primaryMonitor.y);
this.panelBox.set_size(this.primaryMonitor.width, -1);
if (this.keyboardIndex < 0)
this.keyboardIndex = this.primaryIndex;
this.keyboardBox.set_position(this.bottomMonitor.x,
this.bottomMonitor.y + this.bottomMonitor.height);
this.keyboardBox.set_size(this.bottomMonitor.width, -1);
this.trayBox.set_position(this.bottomMonitor.x,
this.bottomMonitor.y + this.bottomMonitor.height);
@ -256,11 +256,6 @@ const LayoutManager = new Lang.Class({
this.bottomMonitor.width, this.bottomMonitor.height);
},
_panelBoxChanged: function() {
this.emit('panel-box-changed');
this._updatePanelBarriers();
},
_updatePanelBarriers: function() {
if (this._leftPanelBarrier)
global.destroy_pointer_barrier(this._leftPanelBarrier);
@ -310,44 +305,8 @@ const LayoutManager = new Lang.Class({
return this.monitors[index];
},
get keyboardMonitor() {
return this.monitors[this.keyboardIndex];
},
get focusIndex() {
let i = Main.layoutManager.primaryIndex;
if (global.stage_input_mode == Shell.StageInputMode.FOCUSED ||
global.stage_input_mode == Shell.StageInputMode.FULLSCREEN) {
let focusActor = global.stage.key_focus;
if (focusActor)
i = this._chrome.findIndexForActor(focusActor);
} else {
let focusWindow = global.display.focus_window;
if (focusWindow)
i = this._chrome.findIndexForWindow(focusWindow);
}
return i;
},
get focusMonitor() {
return this.monitors[this.focusIndex];
},
set keyboardIndex(v) {
this._keyboardIndex = v;
this.keyboardBox.set_position(this.keyboardMonitor.x,
this.keyboardMonitor.y + this.keyboardMonitor.height);
this.keyboardBox.set_size(this.keyboardMonitor.width, -1);
},
get keyboardIndex() {
return this._keyboardIndex;
},
_startupAnimation: function() {
this.panelBox.translation_y = -this.panelBox.height;
this.panelBox.anchor_y = this.panelBox.height;
let plymouthTransitionRunning = false;
@ -383,7 +342,7 @@ const LayoutManager = new Lang.Class({
}
Tweener.addTween(this.panelBox,
{ translation_y: 0,
{ anchor_y: 0,
time: STARTUP_ANIMATION_TIME,
transition: 'easeOutQuad',
onComplete: this._startupAnimationComplete,
@ -392,7 +351,6 @@ const LayoutManager = new Lang.Class({
},
_startupAnimationComplete: function() {
this.emit('panel-box-changed');
this._chrome.thawUpdateRegions();
},
@ -405,14 +363,11 @@ const LayoutManager = new Lang.Class({
onComplete: this._showKeyboardComplete,
onCompleteScope: this
});
if (this.keyboardIndex == this.bottomIndex) {
Tweener.addTween(this.trayBox,
{ anchor_y: this.keyboardBox.height,
time: KEYBOARD_ANIMATION_TIME,
transition: 'easeOutQuad'
});
}
Tweener.addTween(this.trayBox,
{ anchor_y: this.keyboardBox.height,
time: KEYBOARD_ANIMATION_TIME,
transition: 'easeOutQuad'
});
this.emit('keyboard-visible-changed', true);
},
@ -424,8 +379,7 @@ const LayoutManager = new Lang.Class({
this._keyboardHeightNotifyId = this.keyboardBox.connect('notify::height', Lang.bind(this, function () {
this.keyboardBox.anchor_y = this.keyboardBox.height;
if (this.keyboardIndex == this.bottomIndex)
this.trayBox.anchor_y = this.keyboardBox.height;
this.trayBox.anchor_y = this.keyboardBox.height;
}));
},
@ -437,18 +391,15 @@ const LayoutManager = new Lang.Class({
Tweener.addTween(this.keyboardBox,
{ anchor_y: 0,
time: immediate ? 0 : KEYBOARD_ANIMATION_TIME,
transition: 'easeInQuad',
transition: 'easeOutQuad',
onComplete: this._hideKeyboardComplete,
onCompleteScope: this
});
if (this.keyboardIndex == this.bottomIndex) {
Tweener.addTween(this.trayBox,
{ anchor_y: 0,
time: immediate ? 0 : KEYBOARD_ANIMATION_TIME,
transition: 'easeOutQuad'
});
}
Tweener.addTween(this.trayBox,
{ anchor_y: 0,
time: immediate ? 0 : KEYBOARD_ANIMATION_TIME,
transition: 'easeOutQuad'
});
this.emit('keyboard-visible-changed', false);
},
@ -512,12 +463,8 @@ const LayoutManager = new Lang.Class({
},
findMonitorForActor: function(actor) {
return this.monitors[this._chrome.findIndexForActor(actor)];
},
findMonitorForWindow: function(window) {
return this.monitors[this._chrome.findIndexForWindow(window)];
},
return this._chrome.findMonitorForActor(actor);
}
});
Signals.addSignalMethods(LayoutManager.prototype);
@ -865,7 +812,6 @@ const Chrome = new Lang.Class({
_relayout: function() {
this._monitors = this._layoutManager.monitors;
this._primaryIndex = this._layoutManager.primaryIndex;
this._primaryMonitor = this._layoutManager.primaryMonitor;
this._updateFullscreen();
@ -881,49 +827,32 @@ const Chrome = new Lang.Class({
let monitor = this._monitors[i];
if (cx >= monitor.x && cx < monitor.x + monitor.width &&
cy >= monitor.y && cy < monitor.y + monitor.height)
return i;
return monitor;
}
// If the center is not on a monitor, return the first overlapping monitor
for (let i = 0; i < this._monitors.length; i++) {
let monitor = this._monitors[i];
if (x + w > monitor.x && x < monitor.x + monitor.width &&
y + h > monitor.y && y < monitor.y + monitor.height)
return i;
return monitor;
}
// otherwise on no monitor
return -1;
return null;
},
findIndexForWindow: function(window) {
let rect = window.get_input_rect();
let i = this._findMonitorForRect(rect.x, rect.y, rect.width, rect.height);
if (i >= 0)
return i;
return this._primaryIndex; // Not on any monitor, pretend its on the primary
_findMonitorForWindow: function(window) {
return this._findMonitorForRect(window.x, window.y, window.width, window.height);
},
// This call guarantees that we return some monitor to simplify usage of it
// In practice all tracked actors should be visible on some monitor anyway
findIndexForActor: function(actor) {
findMonitorForActor: function(actor) {
let [x, y] = actor.get_transformed_position();
let [w, h] = actor.get_transformed_size();
let i = this._findMonitorForRect(x, y, w, h);
if (i >= 0)
return i;
return this._primaryIndex; // Not on any monitor, pretend its on the primary
},
findMonitorForWindow: function(window) {
let rect = window.get_input_rect();
let i = this._findMonitorForRect(rect.x, rect.y, rect.width, rect.height);
if (i >= 0)
return this._monitors[i];
else
return null;
},
findMonitorForActor: function(actor) {
return this._monitors[this.findIndexForActor(actor)];
let monitor = this._findMonitorForRect(x, y, w, h);
if (monitor)
return monitor;
return this._primaryMonitor; // Not on any monitor, pretend its on the primary
},
_queueUpdateRegions: function() {
@ -964,15 +893,14 @@ const Chrome = new Lang.Class({
for (let i = windows.length - 1; i > -1; i--) {
let window = windows[i];
let metaWindow = window.meta_window;
let layer = metaWindow.get_layer();
let layer = window.get_meta_window().get_layer();
// Skip minimized windows
if (!window.showing_on_its_workspace())
continue;
if (layer == Meta.StackLayer.FULLSCREEN) {
let monitor = this.findMonitorForWindow(metaWindow);
let monitor = this._findMonitorForWindow(window);
if (monitor)
monitor.inFullscreen = true;
}
@ -989,7 +917,7 @@ const Chrome = new Lang.Class({
}
// Or whether it is monitor sized
let monitor = this.findMonitorForWindow(metaWindow);
let monitor = this._findMonitorForWindow(window);
if (monitor &&
window.x <= monitor.x &&
window.x + window.width >= monitor.x + monitor.width &&
@ -1092,7 +1020,7 @@ const Chrome = new Lang.Class({
} else if (y1 <= primary.y && y2 >= primary.y + primary.height) {
if (x1 <= 0)
side = Meta.Side.LEFT;
else if (x2 >= primary.x + primary.width)
else if (x2 >= global.screen_width)
side = Meta.Side.RIGHT;
else
continue;

View File

@ -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); ';
@ -872,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();
@ -1057,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;
},
@ -1133,7 +1129,7 @@ const LookingGlass = new Lang.Class({
if (this._open)
return;
if (!Main.pushModal(this._entry, { keybindingMode: Main.KeybindingMode.LOOKING_GLASS }))
if (!Main.pushModal(this._entry))
return;
this._notebook.selectIndex(0);

View File

@ -20,7 +20,6 @@ const Keyboard = imports.ui.keyboard;
const MessageTray = imports.ui.messageTray;
const Overview = imports.ui.overview;
const Panel = imports.ui.panel;
const Params = imports.misc.params;
const RunDialog = imports.ui.runDialog;
const Layout = imports.ui.layout;
const LookingGlass = imports.ui.lookingGlass;
@ -40,19 +39,6 @@ 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;
@ -69,7 +55,6 @@ let shellDBusService = null;
let shellMountOpDBusService = null;
let screenSaverDBus = null;
let modalCount = 0;
let keybindingMode = KeybindingMode.NORMAL;
let modalActorFocusStack = [];
let uiGroup = null;
let magnifier = null;
@ -81,18 +66,10 @@ let _defaultCssStylesheet = null;
let _cssStylesheet = null;
let _overridesSettings = null;
function _sessionUpdated() {
wm.setCustomKeybindingHandler('panel-main-menu',
KeybindingMode.NORMAL |
KeybindingMode.OVERVIEW,
sessionMode.hasOverview ? Lang.bind(overview, overview.toggle) : null);
wm.allowKeybinding('overlay-key', KeybindingMode.NORMAL |
KeybindingMode.OVERVIEW);
let background = null;
wm.setCustomKeybindingHandler('panel-run-dialog',
KeybindingMode.NORMAL |
KeybindingMode.OVERVIEW,
sessionMode.hasRunDialog ? openRunDialog : null);
function _sessionUpdated() {
Meta.keybindings_set_custom_handler('internal-keybinding-panel-run-dialog', sessionMode.hasRunDialog ? Util.wrapKeybinding(openRunDialog, true) : null);
if (sessionMode.isGreeter)
screenShield.showDialog();
}
@ -159,13 +136,13 @@ function start() {
xdndHandler = new XdndHandler.XdndHandler();
ctrlAltTabManager = new CtrlAltTab.CtrlAltTabManager();
overview = new Overview.Overview();
wm = new WindowManager.WindowManager();
magnifier = new Magnifier.Magnifier();
if (UnlockDialog.isSupported())
screenShield = new ScreenShield.ScreenShield();
else
screenShield = new ScreenShield.ScreenShieldFallback();
panel = new Panel.Panel();
wm = new WindowManager.WindowManager();
messageTray = new MessageTray.MessageTray();
keyboard = new Keyboard.Keyboard();
notificationDaemon = new NotificationDaemon.NotificationDaemon();
@ -178,8 +155,16 @@ function start() {
global.screen.override_workspace_layout(Meta.ScreenCorner.TOPLEFT,
false, -1, 1);
global.display.connect('overlay-key', Lang.bind(overview, overview.toggle));
sessionMode.connect('updated', _sessionUpdated);
Meta.keybindings_set_custom_handler('internal-keybinding-panel-main-menu', Util.wrapKeybinding(Lang.bind(overview, function() {
this.toggle();
return true;
}), true));
global.display.connect('overlay-key', Util.wrapKeybinding(Lang.bind(overview, function() {
this.toggle();
return true;
}), true));
sessionMode.connect('update', _sessionUpdated);
_sessionUpdated();
// Provide the bus object for gnome-session to
@ -499,7 +484,7 @@ function isInModalStack(actor) {
/**
* pushModal:
* @actor: #ClutterActor which will be given keyboard focus
* @params: optional parameters
* @timestamp: optional timestamp
*
* Ensure we are in a mode where all keyboard and mouse input goes to
* the stage, and focus @actor. Multiple calls to this function act in
@ -510,27 +495,21 @@ function isInModalStack(actor) {
* modal stack returns to this actor, reset the focus to the actor
* which was focused at the time pushModal() was invoked.
*
* @params may be used to provide the following parameters:
* - timestamp: used to associate the call with a specific user initiated
* event. If not provided then the value of
* global.get_current_time() is assumed.
* @timestamp is optionally used to associate the call with a specific user
* initiated event. If not provided then the value of
* global.get_current_time() is assumed.
*
* - options: Meta.ModalOptions flags to indicate that the pointer is
* already grabbed
*
* - keybindingMode: used to set the current Main.KeybindingMode to filter
* global keybindings; the default of NONE will filter
* out all keybindings
* @options: optional Meta.ModalOptions flags to indicate that the
* pointer is alrady grabbed
*
* Returns: true iff we successfully acquired a grab or already had one
*/
function pushModal(actor, params) {
params = Params.parse(params, { timestamp: global.get_current_time(),
options: 0,
keybindingMode: KeybindingMode.NONE });
function pushModal(actor, timestamp, options) {
if (timestamp == undefined)
timestamp = global.get_current_time();
if (modalCount == 0) {
if (!global.begin_modal(params.timestamp, params.options)) {
if (!global.begin_modal(timestamp, options ? options : 0)) {
log('pushModal: invocation of begin_modal failed');
return false;
}
@ -545,23 +524,20 @@ 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,
keybindingMode: keybindingMode });
focusDestroyId: curFocusDestroyId });
keybindingMode = params.keybindingMode;
global.stage.set_key_focus(actor);
return true;
}
@ -588,7 +564,6 @@ function popModal(actor, timestamp) {
global.stage.set_key_focus(null);
global.end_modal(timestamp);
global.set_stage_input_mode(Shell.StageInputMode.NORMAL);
keybindingMode = KeybindingMode.NORMAL;
throw new Error('incorrect pop');
}
@ -599,34 +574,17 @@ function popModal(actor, timestamp) {
record.actor.disconnect(record.destroyId);
if (focusIndex == modalActorFocusStack.length - 1) {
if (record.prevFocus)
record.prevFocus.disconnect(record.prevFocusDestroyId);
keybindingMode = record.keybindingMode;
global.stage.set_key_focus(record.prevFocus);
if (record.focus)
record.focus.disconnect(record.focusDestroyId);
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].keybindingMode = modalActorFocusStack[i - 1].keybindingMode;
modalActorFocusStack[i].focus = modalActorFocusStack[i - 1].focus;
modalActorFocusStack[i].focusDestroyId = modalActorFocusStack[i - 1].focusDestroyId;
}
}
modalActorFocusStack.splice(focusIndex, 1);
@ -637,7 +595,6 @@ function popModal(actor, timestamp) {
global.end_modal(timestamp);
global.set_stage_input_mode(Shell.StageInputMode.NORMAL);
Meta.enable_unredirect_for_screen(global.screen);
keybindingMode = KeybindingMode.NORMAL;
}
function createLookingGlass() {
@ -652,6 +609,8 @@ function openRunDialog() {
runDialog = new RunDialog.RunDialog();
}
runDialog.open();
return true;
}
/**

View File

@ -611,8 +611,6 @@ const Notification = new Lang.Class({
setImage: function(image) {
if (this._imageBin)
this.unsetImage();
if (!image)
return;
this._imageBin = new St.Bin();
this._imageBin.child = image;
this._imageBin.opacity = 230;
@ -1090,14 +1088,14 @@ const Source = new Lang.Class({
item = new PopupMenu.PopupMenuItem(_("Open"));
item.connect('activate', Lang.bind(this, function() {
this.open();
this.emit('done-displaying-content', true);
this.emit('done-displaying-content');
}));
rightClickMenu.add(item.actor);
item = new PopupMenu.PopupMenuItem(_("Remove"));
item.connect('activate', Lang.bind(this, function() {
this.destroy();
this.emit('done-displaying-content', false);
this.emit('done-displaying-content');
}));
rightClickMenu.add(item.actor);
return rightClickMenu;
@ -1343,7 +1341,7 @@ const SummaryItem = new Lang.Class({
},
_notificationDoneDisplaying: function() {
this.source.emit('done-displaying-content', true);
this.source.emit('done-displaying-content');
},
_notificationDestroyed: function(notification) {
@ -1414,7 +1412,7 @@ const MessageTray = new Lang.Class({
actor.grab_key_focus();
}));
global.focus_manager.add_group(this.actor);
this._summary = new St.BoxLayout({ style_class: 'message-tray-summary',
this._summary = new St.BoxLayout({ name: 'summary-mode',
reactive: true,
track_hover: true,
x_align: Clutter.ActorAlign.END,
@ -1443,6 +1441,7 @@ const MessageTray = new Lang.Class({
this._clickedSummaryItem = null;
this._clickedSummaryItemMouseButton = -1;
this._clickedSummaryItemAllocationChangedId = 0;
this._pointerBarrier = 0;
this._closeButton = makeCloseButton();
this._closeButton.hide();
@ -1454,8 +1453,7 @@ const MessageTray = new Lang.Class({
this.idleMonitor = new GnomeDesktop.IdleMonitor();
this._grabHelper = new GrabHelper.GrabHelper(this.actor,
{ keybindingMode: Main.KeybindingMode.MESSAGE_TRAY });
this._grabHelper = new GrabHelper.GrabHelper(this.actor);
this._grabHelper.addActor(this._summaryBoxPointer.actor);
this._grabHelper.addActor(this.actor);
if (Main.panel.statusArea.activities)
@ -1472,7 +1470,6 @@ const MessageTray = new Lang.Class({
this._pointerInTray = false;
this._pointerInKeyboard = false;
this._keyboardVisible = false;
this._keyboardUnderMessageTray = false;
this._summaryState = State.HIDDEN;
this._pointerInSummary = false;
this._notificationClosed = false;
@ -1487,7 +1484,6 @@ const MessageTray = new Lang.Class({
this._reNotifyAfterHideNotification = null;
this._inFullscreen = false;
this._desktopClone = null;
this._inCtrlAltTab = false;
this._lightbox = new Lightbox.Lightbox(global.window_group,
{ inhibitEvents: true,
@ -1521,20 +1517,14 @@ const MessageTray = new Lang.Class({
Main.sessionMode.connect('updated', Lang.bind(this, this._sessionUpdated));
Main.wm.addKeybinding('toggle-message-tray',
new Gio.Settings({ schema: SHELL_KEYBINDINGS_SCHEMA }),
Meta.KeyBindingFlags.NONE,
Main.KeybindingMode.NORMAL |
Main.KeybindingMode.MESSAGE_TRAY |
Main.KeybindingMode.OVERVIEW,
Lang.bind(this, this.toggleAndNavigate));
Main.wm.addKeybinding('focus-active-notification',
new Gio.Settings({ schema: SHELL_KEYBINDINGS_SCHEMA }),
Meta.KeyBindingFlags.NONE,
Main.KeybindingMode.NORMAL |
Main.KeybindingMode.MESSAGE_TRAY |
Main.KeybindingMode.OVERVIEW,
Lang.bind(this, this._expandActiveNotification));
global.display.add_keybinding('toggle-message-tray',
new Gio.Settings({ schema: SHELL_KEYBINDINGS_SCHEMA }),
Meta.KeyBindingFlags.NONE,
Lang.bind(this, this.toggleAndNavigate));
global.display.add_keybinding('focus-active-notification',
new Gio.Settings({ schema: SHELL_KEYBINDINGS_SCHEMA }),
Meta.KeyBindingFlags.NONE,
Lang.bind(this, this._expandActiveNotification));
this._summaryItems = [];
this._chatSummaryItemsCount = 0;
@ -1546,34 +1536,15 @@ const MessageTray = new Lang.Class({
this._trayDwellUserTime = 0;
this._sessionUpdated();
this._updateNoMessagesLabel();
},
_updateNoMessagesLabel: function() {
if (this._summaryItems.length == 0 && !this._noMessages) {
this._noMessages = new St.Label({ text: _("No Messages"),
style_class: 'no-messages-label',
x_align: Clutter.ActorAlign.CENTER,
x_expand: true,
y_align: Clutter.ActorAlign.CENTER,
y_expand: true });
this.actor.add_actor(this._noMessages);
} else if (this._summaryItems.length > 0 && this._noMessages) {
this._noMessages.destroy();
this._noMessages = null;
}
},
_sessionUpdated: function() {
if ((Main.sessionMode.isLocked || Main.sessionMode.isGreeter) && this._inCtrlAltTab) {
if (Main.sessionMode.isLocked || Main.sessionMode.isGreeter)
Main.ctrlAltTabManager.removeGroup(this._summary);
this._inCtrlAltTab = false;
} else if (!this._inCtrlAltTab) {
Main.ctrlAltTabManager.addGroup(this._summary, _("Message Tray"), 'user-available-symbolic',
else
Main.ctrlAltTabManager.addGroup(this._summary, _("Message Tray"), 'start-here-symbolic',
{ focusCallback: Lang.bind(this, this.toggleAndNavigate),
sortGroup: CtrlAltTab.SortGroup.BOTTOM });
this._inCtrlAltTab = true;
}
this._updateState();
},
@ -1611,8 +1582,6 @@ const MessageTray = new Lang.Class({
},
_trayDwellTimeout: function() {
this._trayDwellTimeoutId = 0;
if (Main.modalCount > 0)
return false;
@ -1623,6 +1592,8 @@ const MessageTray = new Lang.Class({
if (currentUserTime != this._trayDwellUserTime)
return false;
this._trayDwellTimeoutId = 0;
this._traySummoned = true;
this._updateState();
@ -1709,8 +1680,6 @@ const MessageTray = new Lang.Class({
Meta.later_add(Meta.LaterType.BEFORE_REDRAW, Lang.bind(this, function() { this._updateState(); return false; }));
this.emit('summary-item-added', summaryItem);
this._updateNoMessagesLabel();
},
getSummaryItems: function() {
@ -1743,8 +1712,6 @@ const MessageTray = new Lang.Class({
summaryItemToRemove.actor.destroy();
this._updateNoMessagesLabel();
if (needUpdate)
this._updateState();
},
@ -1930,15 +1897,12 @@ const MessageTray = new Lang.Class({
},
_onKeyboardVisibleChanged: function(layoutManager, keyboardVisible) {
let keyboardUnderMessageTray = layoutManager.keyboardIndex == layoutManager.bottomIndex;
if (this._keyboardVisible == keyboardVisible &&
this._keyboardUnderMesssageTray == keyboardUnderMessageTray)
if (this._keyboardVisible == keyboardVisible)
return;
this._keyboardVisible = keyboardVisible;
this._keyboardUnderMessageTray = keyboardUnderMessageTray;
if (keyboardVisible && keyboardUnderMessageTray)
if (keyboardVisible)
this.actor.add_style_pseudo_class('keyboard');
else
this.actor.remove_style_pseudo_class('keyboard');
@ -2042,7 +2006,8 @@ const MessageTray = new Lang.Class({
let summaryPinned = this._pointerInTray || summarySummoned || this._locked;
let summaryHovered = this._pointerInTray || this._pointerInSummary;
let notificationsVisible = this._notificationState != State.HIDDEN;
let notificationsVisible = (this._notificationState == State.SHOWING ||
this._notificationState == State.SHOWN);
let notificationsDone = !notificationsVisible && !notificationsPending;
let summaryOptionalInOverview = this._overviewVisible && !this._locked && !summaryHovered;
@ -2095,12 +2060,12 @@ const MessageTray = new Lang.Class({
this._desktopCloneState == State.SHOWN);
let desktopCloneShouldBeVisible = (trayShouldBeVisible &&
!this._overviewVisible &&
(!this._keyboardVisible || !this._keyboardUnderMessageTray));
!this._keyboardVisible);
if (!desktopCloneIsVisible && desktopCloneShouldBeVisible) {
this._showDesktopClone();
} else if (desktopCloneIsVisible && !desktopCloneShouldBeVisible) {
this._hideDesktopClone (this._keyboardVisible && this._keyboardUnderMessageTray);
this._hideDesktopClone (this._keyboardVisible);
}
},
@ -2113,8 +2078,6 @@ const MessageTray = new Lang.Class({
params.onCompleteScope = this;
params.onCompleteParams = [statevar, value, onComplete, onCompleteScope, onCompleteParams];
// Remove other tweens that could mess with the state machine
Tweener.removeTweens(actor);
Tweener.addTween(actor, params);
let valuing = (value == State.SHOWN) ? State.SHOWING : State.HIDING;
@ -2268,28 +2231,40 @@ const MessageTray = new Lang.Class({
_updateShowingNotification: function() {
this._notification.acknowledged = true;
Tweener.removeTweens(this._notificationWidget);
// We auto-expand notifications with CRITICAL urgency.
if (this._notification.urgency == Urgency.CRITICAL)
// We use Tweener.removeTweens() to remove a tween that was hiding the notification we are
// updating, in case that notification was in the process of being hidden. However,
// Tweener.removeTweens() would also remove a tween that was updating the position of the
// notification we are updating, in case that notification was already expanded and its height
// changed. Therefore we need to call this._expandNotification() for expanded notifications
// to make sure their position is updated.
if (this._notification.urgency == Urgency.CRITICAL || this._notification.expanded)
this._expandNotification(true);
// We tween all notifications to full opacity. This ensures that both new notifications and
// notifications that might have been in the process of hiding get full opacity.
//
// We tween any notification showing in the banner mode to the appropriate height
// (which is banner height or expanded height, depending on the notification state)
// We tween any notification showing in the banner mode to banner height
// (this._notificationWidget.y = -this._notificationWidget.height).
// This ensures that both new notifications and notifications in the banner mode that might
// have been in the process of hiding are shown with the correct height.
// have been in the process of hiding are shown with the banner height.
//
// We use this._showNotificationCompleted() onComplete callback to extend the time the updated
// notification is being shown.
//
// We don't set the y parameter for the tween for expanded notifications because
// this._expandNotification() will result in getting this._notificationWidget.y set to the appropriate
// fully expanded value.
let tweenParams = { opacity: 255,
y: -this._notificationWidget.height,
time: ANIMATION_TIME,
transition: 'easeOutQuad',
onComplete: this._showNotificationCompleted,
onCompleteScope: this
};
if (!this._notification.expanded)
tweenParams.y = -this._notificationWidget.height;
this._tween(this._notificationWidget, '_notificationState', State.SHOWN, tweenParams);
},
@ -2335,18 +2310,6 @@ const MessageTray = new Lang.Class({
},
_hideNotification: function() {
// HACK!
// There seems to be a reentrancy issue in calling .ungrab() here,
// which causes _updateState to be called before _notificationState
// becomes HIDING. That hides the notification again, nullifying the
// object but not setting _notificationState (and that's the weird part)
// As then _notificationState is stuck into SHOWN but _notification
// is null, every new _updateState fails and the message tray is
// lost forever.
//
// See more at https://bugzilla.gnome.org/show_bug.cgi?id=683986
this._notificationState = State.HIDING;
this._grabHelper.ungrab({ actor: this._notification.actor });
if (this._idleMonitorBecameActiveId) {
@ -2360,7 +2323,6 @@ const MessageTray = new Lang.Class({
}
if (this._notificationRemoved) {
Tweener.removeTweens(this._notificationWidget);
this._notificationWidget.y = this.actor.height;
this._notificationWidget.opacity = 0;
this._notificationState = State.HIDDEN;
@ -2424,11 +2386,8 @@ const MessageTray = new Lang.Class({
if (this._notificationWidget.y < expandedY) {
this._notificationWidget.y = expandedY;
} else if (this._notification.y != expandedY) {
// Tween also opacity here, to override a possible tween that's
// currently hiding the notification.
this._tween(this._notificationWidget, '_notificationState', State.SHOWN,
{ y: expandedY,
opacity: 255,
time: ANIMATION_TIME,
transition: 'easeOutQuad'
});
@ -2459,21 +2418,12 @@ const MessageTray = new Lang.Class({
});
},
_onSourceDoneDisplayingContent: function(source, closeTray) {
if (closeTray) {
this._escapeTray();
} else {
this._setClickedSummaryItem(null);
this._updateState();
}
},
_showSummaryBoxPointer: function() {
this._summaryBoxPointerItem = this._clickedSummaryItem;
this._summaryBoxPointerContentUpdatedId = this._summaryBoxPointerItem.connect('content-updated',
Lang.bind(this, this._onSummaryBoxPointerContentUpdated));
this._sourceDoneDisplayingId = this._summaryBoxPointerItem.source.connect('done-displaying-content',
Lang.bind(this, this._onSourceDoneDisplayingContent));
Lang.bind(this, this._escapeTray));
let hasRightClickMenu = this._summaryBoxPointerItem.rightClickMenu != null;
if (this._clickedSummaryItemMouseButton == 1 || !hasRightClickMenu) {
@ -2496,7 +2446,6 @@ const MessageTray = new Lang.Class({
this._summaryBoxPointerItem.prepareNotificationStackForShowing();
} else if (this._clickedSummaryItemMouseButton == 3) {
this._summaryBoxPointer.bin.child = this._clickedSummaryItem.rightClickMenu;
this._summaryBoxPointerCloseClickedId = 0;
}
this._grabHelper.grab({ actor: this._summaryBoxPointer.bin.child,
@ -2603,10 +2552,8 @@ const MessageTray = new Lang.Class({
this._summaryBoxPointer.bin.child = null;
this._summaryBoxPointerItem.disconnect(this._summaryBoxPointerContentUpdatedId);
this._summaryBoxPointerContentUpdatedId = 0;
if (this._summaryBoxPointerCloseClickedId != 0) {
this._summaryBoxPointerItem.closeButton.disconnect(this._summaryBoxPointerCloseClickedId);
this._summaryBoxPointerCloseClickedId = 0;
}
this._summaryBoxPointerItem.closeButton.disconnect(this._summaryBoxPointerCloseClickedId);
this._summaryBoxPointerCloseClickedId = 0;
this._summaryBoxPointerItem.source.disconnect(this._sourceDoneDisplayingId);
this._summaryBoxPointerDoneDisplayingId = 0;

View File

@ -37,12 +37,10 @@ const ModalDialog = new Lang.Class({
params = Params.parse(params, { shellReactive: false,
styleClass: null,
parentActor: Main.uiGroup,
keybindingMode: Main.KeybindingMode.SYSTEM_MODAL,
shouldFadeIn: true });
this.state = State.CLOSED;
this._hasModal = false;
this._keybindingMode = params.keybindingMode;
this._shellReactive = params.shellReactive;
this._shouldFadeIn = params.shouldFadeIn;
@ -58,7 +56,7 @@ const ModalDialog = new Lang.Class({
this._group.connect('destroy', Lang.bind(this, this._onGroupDestroy));
this._buttonKeys = {};
this._actionKeys = {};
this._group.connect('key-release-event', Lang.bind(this, this._onKeyReleaseEvent));
this._backgroundBin = new St.Bin();
@ -95,9 +93,10 @@ const ModalDialog = new Lang.Class({
x_align: St.Align.MIDDLE,
y_align: St.Align.START });
this.buttonLayout = new St.BoxLayout({ style_class: 'modal-dialog-button-box',
vertical: false });
this.dialogLayout.add(this.buttonLayout,
this._buttonLayout = new St.BoxLayout({ style_class: 'modal-dialog-button-box',
visible: false,
vertical: false });
this.dialogLayout.add(this._buttonLayout,
{ expand: true,
x_align: St.Align.MIDDLE,
y_align: St.Align.END });
@ -112,16 +111,35 @@ const ModalDialog = new Lang.Class({
this._group.destroy();
},
clearButtons: function() {
this.buttonLayout.destroy_all_children();
this._buttonKeys = {};
setActionKey: function(key, action) {
this._actionKeys[key] = action;
},
setButtons: function(buttons) {
this.clearButtons();
this._buttonLayout.destroy_all_children();
this._actionKeys = {};
this._buttonLayout.visible = (buttons.length > 0);
for (let i = 0; i < buttons.length; i++) {
let buttonInfo = buttons[i];
let label = buttonInfo['label'];
let action = buttonInfo['action'];
let key = buttonInfo['key'];
let isDefault = buttonInfo['default'];
if (isDefault && !key) {
this._actionKeys[Clutter.KEY_KP_Enter] = action;
this._actionKeys[Clutter.KEY_ISO_Enter] = action;
key = Clutter.KEY_Return;
}
buttonInfo.button = new St.Button({ style_class: 'modal-dialog-button',
reactive: true,
can_focus: true,
label: label });
if (isDefault)
buttonInfo.button.add_style_pseudo_class('default');
let x_alignment;
if (buttons.length == 1)
@ -133,62 +151,29 @@ const ModalDialog = new Lang.Class({
else
x_alignment = St.Align.MIDDLE;
this.addButton(buttonInfo, { expand: true,
x_fill: false,
y_fill: false,
x_align: x_alignment,
y_align: St.Align.MIDDLE });
if (!this._initialKeyFocusDestroyId)
this._initialKeyFocus = buttonInfo.button;
this._buttonLayout.add(buttonInfo.button,
{ expand: true,
x_fill: false,
y_fill: false,
x_align: x_alignment,
y_align: St.Align.MIDDLE });
buttonInfo.button.connect('clicked', action);
if (key)
this._actionKeys[key] = action;
}
},
addButton: function(buttonInfo, layoutInfo) {
let label = buttonInfo['label'];
let action = buttonInfo['action'];
let key = buttonInfo['key'];
let isDefault = buttonInfo['default'];
let keys;
if (key)
keys = [key];
else if (isDefault)
keys = [Clutter.KEY_Return, Clutter.KEY_KP_Enter, Clutter.KEY_ISO_Enter];
else
keys = [];
let button = new St.Button({ style_class: 'modal-dialog-button',
reactive: true,
can_focus: true,
label: label });
button.connect('clicked', action);
buttonInfo['button'] = button;
if (isDefault)
button.add_style_pseudo_class('default');
if (!this._initialKeyFocusDestroyId)
this._initialKeyFocus = button;
for (let i in keys)
this._buttonKeys[keys[i]] = buttonInfo;
this.buttonLayout.add(button, layoutInfo);
return button;
this.emit('buttons-set');
},
_onKeyReleaseEvent: function(object, event) {
let symbol = event.get_key_symbol();
let buttonInfo = this._buttonKeys[symbol];
let action = this._actionKeys[symbol];
if (!buttonInfo)
return false;
let button = buttonInfo['button'];
let action = buttonInfo['action'];
if (action && button.reactive) {
if (action) {
action();
return true;
}
@ -241,7 +226,7 @@ const ModalDialog = new Lang.Class({
if (this.state == State.OPENED || this.state == State.OPENING)
return true;
if (!this.pushModal({ timestamp: timestamp }))
if (!this.pushModal(timestamp))
return false;
this._fadeOpen(onPrimary);
@ -291,8 +276,7 @@ const ModalDialog = new Lang.Class({
pushModal: function (timestamp) {
if (this._hasModal)
return true;
if (!Main.pushModal(this._group, { timestamp: timestamp,
keybindingMode: this._keybindingMode }))
if (!Main.pushModal(this._group, timestamp))
return false;
this._hasModal = true;

View File

@ -127,42 +127,42 @@ 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']) });
} else {
let stockIcon;
switch (hints.urgency) {
case Urgency.LOW:
case Urgency.NORMAL:
stockIcon = 'gtk-dialog-info';
break;
case Urgency.CRITICAL:
stockIcon = 'gtk-dialog-error';
break;
}
return new Gio.ThemedIcon({ name: stockIcon });
}
return null;
},
_fallbackIconForNotificationData: function(hints) {
let stockIcon;
switch (hints.urgency) {
case Urgency.LOW:
case Urgency.NORMAL:
stockIcon = 'gtk-dialog-info';
break;
case Urgency.CRITICAL:
stockIcon = 'gtk-dialog-error';
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) {
@ -355,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) {
@ -379,33 +383,29 @@ const NotificationDaemon = new Lang.Class({
function(n, actionId) {
this._emitActionInvoked(ndata.id, actionId);
}));
} else {
notification.update(summary, body, { gicon: gicon,
bannerMarkup: true,
clear: true });
}
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 });
else if (!gicon && gimage)
gicon = gimage;
else if (!gicon)
gicon = this._fallbackIconForNotificationData(hints);
notification.setImage(image);
notification.update(summary, body, { gicon: gicon,
bannerMarkup: true,
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);
@ -435,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);
},

View File

@ -23,6 +23,9 @@ const WorkspaceThumbnail = imports.ui.workspaceThumbnail;
// Time for initial animation going into Overview mode
const ANIMATION_TIME = 0.25;
// XXX -- grab this automatically. Hard to do.
const DASH_MAX_WIDTH = 96;
const DND_WINDOW_SWITCH_TIMEOUT = 1250;
const GLSL_DIM_EFFECT_DECLARATIONS = '';
@ -30,9 +33,9 @@ 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; \
the alpha on the gradient goes from 165 at its darkest to 98 at its most transparent. */ \
float y = 165.0 / 255.0; \
float x = 98.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); \
@ -43,6 +46,18 @@ const GLSL_DIM_EFFECT_CODE = '\
cogl_color_out.xyz = cogl_color_out.xyz * (1.0 - a); \
cogl_color_out.a = 1.0;';
const SwipeScrollDirection = {
NONE: 0,
HORIZONTAL: 1,
VERTICAL: 2
};
const SwipeScrollResult = {
CANCEL: 0,
SWIPE: 1,
CLICK: 2
};
const ShellInfo = new Lang.Class({
Name: 'ShellInfo',
@ -102,7 +117,6 @@ const Overview = new Lang.Class({
_init: function() {
this._overviewCreated = false;
this._initCalled = false;
Main.sessionMode.connect('updated', Lang.bind(this, this._sessionUpdated));
this._sessionUpdated();
@ -133,16 +147,26 @@ const Overview = new Lang.Class({
this._desktopFade = new St.Bin();
global.overlay_group.add_actor(this._desktopFade);
this._spacing = 0;
/* 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 });
this._overview._delegate = this;
this._group = new St.BoxLayout({ name: 'overview-group' });
this._group = new St.Widget({ name: 'overview',
accessible_name: _("Overview"),
reactive: true });
this._group._delegate = this;
this._group.connect('style-changed',
Lang.bind(this, function() {
let node = this._group.get_theme_node();
let spacing = node.get_length('spacing');
if (spacing != this._spacing) {
this._spacing = spacing;
this._relayout();
}
}));
this._scrollDirection = SwipeScrollDirection.NONE;
this._scrollAdjustment = null;
this._capturedEventId = 0;
this._buttonPressId = 0;
@ -158,11 +182,12 @@ const Overview = new Lang.Class({
// Dash elements, or mouseover handlers in the workspaces.
this._coverPane = new Clutter.Rectangle({ opacity: 0,
reactive: true });
this._overview.add_actor(this._coverPane);
this._group.add_actor(this._coverPane);
this._coverPane.connect('event', Lang.bind(this, function (actor, event) { return true; }));
this._overview.hide();
global.overlay_group.add_actor(this._overview);
this._group.hide();
global.overlay_group.add_actor(this._group);
this._coverPane.hide();
@ -174,16 +199,11 @@ const Overview = new Lang.Class({
Main.xdndHandler.connect('drag-begin', Lang.bind(this, this._onDragBegin));
Main.xdndHandler.connect('drag-end', Lang.bind(this, this._onDragEnd));
global.screen.connect('restacked', Lang.bind(this, this._onRestacked));
this._windowSwitchTimeoutId = 0;
this._windowSwitchTimestamp = 0;
this._lastActiveWorkspaceIndex = -1;
this._lastHoveredWindow = null;
this._needsFakePointerEvent = false;
if (this._initCalled)
this.init();
},
_sessionUpdated: function() {
@ -196,20 +216,11 @@ const Overview = new Lang.Class({
// signal handlers and so forth. So we create them after
// construction in this init() method.
init: function() {
this._initCalled = true;
if (this.isDummy)
return;
this._shellInfo = new ShellInfo();
// Add a clone of the panel to the overview so spacing and such is
// automatic
this._panelGhost = new St.Bin({ child: new Clutter.Clone({ source: Main.panel.actor }),
reactive: false,
opacity: 0 });
this._overview.add_actor(this._panelGhost);
this._searchEntry = new St.Entry({ name: 'searchEntry',
/* Translators: this is the text displayed
in the search entry when no search is
@ -218,13 +229,16 @@ const Overview = new Lang.Class({
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);
this._group.add_actor(this._searchEntry);
this._dash = new Dash.Dash();
this._viewSelector = new ViewSelector.ViewSelector(this._searchEntry,
this._dash.showAppsButton);
this._group.add_actor(this._viewSelector.actor);
this._group.add_actor(this._dash.actor);
// TODO - recalculate everything when desktop size changes
this._dash = new Dash.Dash();
this._group.add_actor(this._dash.actor);
this._dash.actor.add_constraint(this._viewSelector.constrainHeight);
this.dashIconSize = this._dash.iconSize;
this._dash.connect('icon-size-changed',
Lang.bind(this, function() {
@ -235,23 +249,6 @@ const Overview = new Lang.Class({
// 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();
},
@ -344,11 +341,159 @@ const Overview = new Lang.Class({
return DND.DragMotionResult.CONTINUE;
},
addAction: function(action) {
setScrollAdjustment: function(adjustment, direction) {
if (this.isDummy)
return;
this._overview.add_action(action);
this._scrollAdjustment = adjustment;
if (this._scrollAdjustment == null)
this._scrollDirection = SwipeScrollDirection.NONE;
else
this._scrollDirection = direction;
},
_onButtonPress: function(actor, event) {
if (this._scrollDirection == SwipeScrollDirection.NONE
|| event.get_button() != 1)
return;
let [stageX, stageY] = event.get_coords();
this._dragStartX = this._dragX = stageX;
this._dragStartY = this._dragY = stageY;
this._dragStartValue = this._scrollAdjustment.value;
this._lastMotionTime = -1; // used to track "stopping" while swipe-scrolling
this._capturedEventId = global.stage.connect('captured-event',
Lang.bind(this, this._onCapturedEvent));
this.emit('swipe-scroll-begin');
},
_onCapturedEvent: function(actor, event) {
let stageX, stageY;
let threshold = Gtk.Settings.get_default().gtk_dnd_drag_threshold;
switch(event.type()) {
case Clutter.EventType.BUTTON_RELEASE:
[stageX, stageY] = event.get_coords();
// default to snapping back to the original value
let newValue = this._dragStartValue;
let minValue = this._scrollAdjustment.lower;
let maxValue = this._scrollAdjustment.upper - this._scrollAdjustment.page_size;
let direction;
if (this._scrollDirection == SwipeScrollDirection.HORIZONTAL) {
direction = stageX > this._dragStartX ? -1 : 1;
if (Clutter.get_default_text_direction() == Clutter.TextDirection.RTL)
direction *= -1;
} else {
direction = stageY > this._dragStartY ? -1 : 1;
}
// We default to scroll a full page size; both the first
// and the last page may be smaller though, so we need to
// adjust difference in those cases.
let difference = direction * this._scrollAdjustment.page_size;
if (this._dragStartValue + difference > maxValue)
difference = maxValue - this._dragStartValue;
else if (this._dragStartValue + difference < minValue)
difference = minValue - this._dragStartValue;
// If the user has moved more than half the scroll
// difference, we want to "settle" to the new value
// even if the user stops dragging rather "throws" by
// releasing during the drag.
let distance = this._dragStartValue - this._scrollAdjustment.value;
let noStop = Math.abs(distance / difference) > 0.5;
// We detect if the user is stopped by comparing the
// timestamp of the button release with the timestamp of
// the last motion. Experimentally, a difference of 0 or 1
// millisecond indicates that the mouse is in motion, a
// larger difference indicates that the mouse is stopped.
if ((this._lastMotionTime > 0 &&
this._lastMotionTime > event.get_time() - 2) ||
noStop) {
if (this._dragStartValue + difference >= minValue &&
this._dragStartValue + difference <= maxValue)
newValue += difference;
}
let result;
// See if the user has moved the mouse enough to trigger
// a drag
if (Math.abs(stageX - this._dragStartX) < threshold &&
Math.abs(stageY - this._dragStartY) < threshold) {
// no motion? It's a click!
result = SwipeScrollResult.CLICK;
this.emit('swipe-scroll-end', result);
} else {
if (newValue == this._dragStartValue)
result = SwipeScrollResult.CANCEL;
else
result = SwipeScrollResult.SWIPE;
// The event capture handler is disconnected
// while scrolling to the final position, so
// to avoid undesired prelights we raise
// the cover pane.
this._coverPane.raise_top();
this._coverPane.show();
Tweener.addTween(this._scrollAdjustment,
{ value: newValue,
time: ANIMATION_TIME,
transition: 'easeOutQuad',
onCompleteScope: this,
onComplete: function() {
this._coverPane.hide();
this.emit('swipe-scroll-end',
result);
}
});
}
global.stage.disconnect(this._capturedEventId);
this._capturedEventId = 0;
return result != SwipeScrollResult.CLICK;
case Clutter.EventType.MOTION:
[stageX, stageY] = event.get_coords();
let dx = this._dragX - stageX;
let dy = this._dragY - stageY;
let primary = Main.layoutManager.primaryMonitor;
this._dragX = stageX;
this._dragY = stageY;
this._lastMotionTime = event.get_time();
// See if the user has moved the mouse enough to trigger
// a drag
if (Math.abs(stageX - this._dragStartX) < threshold &&
Math.abs(stageY - this._dragStartY) < threshold)
return true;
if (this._scrollDirection == SwipeScrollDirection.HORIZONTAL) {
if (Clutter.get_default_text_direction() == Clutter.TextDirection.RTL)
this._scrollAdjustment.value -= (dx / primary.width) * this._scrollAdjustment.page_size;
else
this._scrollAdjustment.value += (dx / primary.width) * this._scrollAdjustment.page_size;
} else {
this._scrollAdjustment.value += (dy / primary.height) * this._scrollAdjustment.page_size;
}
return true;
// Block enter/leave events to avoid prelights
// during swipe-scroll
case Clutter.EventType.ENTER:
case Clutter.EventType.LEAVE:
return true;
}
return false;
},
_getDesktopClone: function() {
@ -374,27 +519,41 @@ const Overview = new Lang.Class({
this.hide();
let primary = Main.layoutManager.primaryMonitor;
let rtl = (Clutter.get_default_text_direction() == Clutter.TextDirection.RTL);
let contentY = Main.panel.actor.height;
let contentHeight = primary.height - contentY - Main.messageTray.actor.height;
this._overview.set_position(primary.x, primary.y);
this._overview.set_size(primary.width, primary.height);
this._group.set_position(primary.x, primary.y);
this._group.set_size(primary.width, primary.height);
this._coverPane.set_position(0, contentY);
this._coverPane.set_size(primary.width, contentHeight);
},
_onRestacked: function() {
let stack = global.get_window_actors();
let stackIndices = {};
let searchWidth = this._searchEntry.get_width();
let searchHeight = this._searchEntry.get_height();
let searchX = (primary.width - searchWidth) / 2;
let searchY = contentY + this._spacing;
for (let i = 0; i < stack.length; i++) {
// Use the stable sequence for an integer to use as a hash key
stackIndices[stack[i].get_meta_window().get_stable_sequence()] = i;
let dashWidth = DASH_MAX_WIDTH;
let dashY = searchY + searchHeight + this._spacing;
let dashX;
if (rtl) {
this._dash.actor.set_anchor_point_from_gravity(Clutter.Gravity.NORTH_EAST);
dashX = primary.width;
} else {
dashX = 0;
}
this.emit('windows-restacked', stackIndices);
let viewX = rtl ? 0 : dashWidth + this._spacing;
let viewY = searchY + searchHeight + this._spacing;
let viewWidth = primary.width - dashWidth - this._spacing;
let viewHeight = contentHeight - this._spacing - viewY;
this._searchEntry.set_position(searchX, searchY);
this._dash.actor.set_position(dashX, dashY);
this._viewSelector.actor.set_position(viewX, viewY);
this._viewSelector.actor.set_size(viewWidth, viewHeight);
},
//// Public methods ////
@ -431,11 +590,15 @@ const Overview = new Lang.Class({
return;
if (this._shown)
return;
this._shown = true;
this._syncInputMode();
if (!this._modal)
// Do this manually instead of using _syncInputMode, to handle failure
if (!Main.pushModal(this._group))
return;
this._modal = true;
this._animateVisible();
this._shown = true;
this._buttonPressId = this._group.connect('button-press-event',
Lang.bind(this, this._onButtonPress));
},
fadeInDesktop: function() {
@ -478,12 +641,12 @@ const Overview = new Lang.Class({
// Disable unredirection while in the overview
Meta.disable_unredirect_for_screen(global.screen);
global.window_group.hide();
this._overview.show();
this._group.show();
this._background.show();
this._viewSelector.show();
this._overview.opacity = 0;
Tweener.addTween(this._overview,
this._group.opacity = 0;
Tweener.addTween(this._group,
{ opacity: 255,
transition: 'easeOutQuad',
time: ANIMATION_TIME,
@ -535,6 +698,10 @@ const Overview = new Lang.Class({
this._shown = false;
this._syncInputMode();
if (this._buttonPressId > 0)
this._group.disconnect(this._buttonPressId);
this._buttonPressId = 0;
},
// hideTemporarily:
@ -558,7 +725,7 @@ const Overview = new Lang.Class({
if (this.isDummy)
return;
if (this.visible)
if (this._shown)
this.hide();
else
this.show();
@ -575,21 +742,20 @@ const Overview = new Lang.Class({
if (this._shown) {
if (!this._modal) {
if (Main.pushModal(this._overview,
{ keybindingMode: Main.KeybindingMode.OVERVIEW }))
if (Main.pushModal(this._group))
this._modal = true;
else
this.hide();
}
} else if (this._shownTemporarily) {
if (this._modal) {
Main.popModal(this._overview);
Main.popModal(this._group);
this._modal = false;
}
global.stage_input_mode = Shell.StageInputMode.FULLSCREEN;
} else {
if (this._modal) {
Main.popModal(this._overview);
Main.popModal(this._group);
this._modal = false;
}
else if (global.stage_input_mode == Shell.StageInputMode.FULLSCREEN)
@ -607,7 +773,7 @@ const Overview = new Lang.Class({
this._viewSelector.zoomFromOverview();
// Make other elements fade out.
Tweener.addTween(this._overview,
Tweener.addTween(this._group,
{ opacity: 0,
transition: 'easeOutQuad',
time: ANIMATION_TIME,
@ -649,7 +815,7 @@ const Overview = new Lang.Class({
this._viewSelector.hide();
this._desktopFade.hide();
this._background.hide();
this._overview.hide();
this._group.hide();
this.visible = false;
this.animationInProgress = false;

View File

@ -75,41 +75,33 @@ function _unpremultiply(color) {
blue: blue, alpha: color.alpha });
};
const Animation = new Lang.Class({
Name: 'Animation',
_init: function(filename, width, height, speed) {
this.actor = new St.Bin();
const AnimatedIcon = new Lang.Class({
Name: 'AnimatedIcon',
_init: function(name, size) {
this.actor = new St.Bin({ visible: false });
this.actor.connect('destroy', Lang.bind(this, this._onDestroy));
this._speed = speed;
this.actor.connect('notify::visible', Lang.bind(this, this._onVisibleNotify));
this._isLoaded = false;
this._isPlaying = false;
this._timeoutId = 0;
this._frame = 0;
this._animations = St.TextureCache.get_default().load_sliced_image (filename, width, height,
Lang.bind(this, this._animationsLoaded));
this._animations = St.TextureCache.get_default().load_sliced_image (global.datadir + '/theme/' + name, size, size);
this.actor.set_child(this._animations);
},
play: function() {
if (this._isLoaded && this._timeoutId == 0) {
if (this._frame == 0)
this._showFrame(0);
this._timeoutId = Mainloop.timeout_add(this._speed, Lang.bind(this, this._update));
}
this._isPlaying = true;
},
stop: function() {
_disconnectTimeout: function() {
if (this._timeoutId > 0) {
Mainloop.source_remove(this._timeoutId);
this._timeoutId = 0;
}
},
this._isPlaying = false;
_onVisibleNotify: function() {
if (this.actor.visible)
this._timeoutId = Mainloop.timeout_add(ANIMATED_ICON_UPDATE_TIMEOUT, Lang.bind(this, this._update));
else
this._disconnectTimeout();
},
_showFrame: function(frame) {
@ -129,24 +121,8 @@ const Animation = new Lang.Class({
return true;
},
_animationsLoaded: function() {
this._isLoaded = true;
if (this._isPlaying)
this.play();
},
_onDestroy: function() {
this.stop();
}
});
const AnimatedIcon = new Lang.Class({
Name: 'AnimatedIcon',
Extends: Animation,
_init: function(name, size) {
this.parent(global.datadir + '/theme/' + name, size, size, ANIMATED_ICON_UPDATE_TIMEOUT);
this._disconnectTimeout();
}
});
@ -301,7 +277,6 @@ const AppMenuButton = new Lang.Class({
this._spinner = new AnimatedIcon('process-working.svg',
PANEL_ICON_SIZE);
this._container.add_actor(this._spinner.actor);
this._spinner.actor.hide();
this._spinner.actor.lower_bottom();
let tracker = Shell.WindowTracker.get_default();
@ -392,7 +367,6 @@ const AppMenuButton = new Lang.Class({
transition: "easeOutQuad",
onCompleteScope: this,
onComplete: function() {
this._spinner.stop();
this._spinner.actor.opacity = 255;
this._spinner.actor.hide();
}
@ -402,7 +376,6 @@ const AppMenuButton = new Lang.Class({
startAnimation: function() {
this._stop = false;
this.actor.reactive = false;
this._spinner.play();
this._spinner.actor.show();
},
@ -598,18 +571,12 @@ 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)
if (this.menu && !(this.menu instanceof PopupMenu.RemoteMenu))
return;
// fallback to older menu
menu = new PopupMenu.PopupMenu(this.actor, 0.0, St.Side.TOP, 0);
menu.isDummyQuitMenu = true;
menu.addAction(_("Quit"), Lang.bind(this, function() {
this._targetApp.request_quit();
}));
@ -622,12 +589,15 @@ const AppMenuButton = new Lang.Class({
Signals.addSignalMethods(AppMenuButton.prototype);
// Activities button. Because everything else in the top bar is a
// PanelMenu.Button, it simplifies some things to make this be one too.
// We just hack it up to not actually have a menu attached to it.
const ActivitiesButton = new Lang.Class({
Name: 'ActivitiesButton',
Extends: PanelMenu.Button,
_init: function() {
this.parent(0.0, null, true);
this.parent(0.0);
this.actor.accessible_role = Atk.Role.TOGGLE_BUTTON;
let container = new Shell.GenericContainer();
@ -647,27 +617,27 @@ const ActivitiesButton = new Lang.Class({
this.hotCorner = new Layout.HotCorner();
container.add_actor(this.hotCorner.actor);
// Hack up our menu...
this.menu.open = Lang.bind(this, this._onMenuOpenRequest);
this.menu.close = Lang.bind(this, this._onMenuCloseRequest);
this.menu.toggle = Lang.bind(this, this._onMenuToggleRequest);
this.actor.connect('captured-event', Lang.bind(this, this._onCapturedEvent));
this.actor.connect_after('button-release-event', Lang.bind(this, this._onButtonRelease));
this.actor.connect_after('key-release-event', Lang.bind(this, this._onKeyRelease));
Main.overview.connect('showing', Lang.bind(this, function() {
this.actor.add_style_pseudo_class('overview');
this._escapeMenuGrab();
this.actor.add_accessible_state (Atk.StateType.CHECKED);
}));
Main.overview.connect('hiding', Lang.bind(this, function() {
this.actor.remove_style_pseudo_class('overview');
this._escapeMenuGrab();
this.actor.remove_accessible_state (Atk.StateType.CHECKED);
}));
this._xdndTimeOut = 0;
// Since the hot corner uses stage coordinates, Clutter won't
// queue relayouts for us when the panel moves. Queue a relayout
// when that happens.
Main.layoutManager.connect('panel-box-changed', Lang.bind(this, function() {
container.queue_relayout();
}));
},
_containerGetPreferredWidth: function(actor, forHeight, alloc) {
@ -713,6 +683,11 @@ const ActivitiesButton = new Lang.Class({
return DND.DragMotionResult.CONTINUE;
},
_escapeMenuGrab: function() {
if (this.menu.isOpen)
this.menu.close();
},
_onCapturedEvent: function(actor, event) {
if (event.type() == Clutter.EventType.BUTTON_PRESS) {
if (!this.hotCorner.shouldToggleOverviewOnClick())
@ -721,13 +696,33 @@ const ActivitiesButton = new Lang.Class({
return false;
},
_onMenuOpenRequest: function() {
this.menu.isOpen = true;
this.menu.emit('open-state-changed', true);
},
_onMenuCloseRequest: function() {
this.menu.isOpen = false;
this.menu.emit('open-state-changed', false);
},
_onMenuToggleRequest: function() {
this.menu.isOpen = !this.menu.isOpen;
this.menu.emit('open-state-changed', this.menu.isOpen);
},
_onButtonRelease: function() {
Main.overview.toggle();
if (this.menu.isOpen) {
this.menu.close();
Main.overview.toggle();
}
},
_onKeyRelease: function(actor, event) {
let symbol = event.get_key_symbol();
if (symbol == Clutter.KEY_Return || symbol == Clutter.KEY_space) {
if (this.menu.isOpen)
this.menu.close();
Main.overview.toggle();
}
},
@ -751,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));
@ -809,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)
@ -823,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) {
@ -852,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';
}
},
@ -865,13 +863,10 @@ 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 cr = this.actor.get_context();
cr.setOperator(Cairo.Operator.SOURCE);
cr.moveTo(0, offsetY);
cr.moveTo(0, 0);
if (this._side == St.Side.LEFT)
cr.arc(cornerRadius,
borderWidth + cornerRadius,
@ -880,7 +875,7 @@ const PanelCorner = new Lang.Class({
cr.arc(0,
borderWidth + cornerRadius,
cornerRadius, 3 * Math.PI / 2, 2 * Math.PI);
cr.lineTo(cornerRadius, offsetY);
cr.lineTo(cornerRadius, 0);
cr.closePath();
let savedPath = cr.copyPath();
@ -890,18 +885,14 @@ const PanelCorner = new Lang.Class({
Clutter.cairo_set_source_color(cr, over);
cr.fill();
if (overlap) {
let offset = borderWidth;
Clutter.cairo_set_source_color(cr, backgroundColor);
let offset = borderWidth;
Clutter.cairo_set_source_color(cr, backgroundColor);
cr.save();
cr.translate(xOffsetDirection * offset, - offset);
cr.appendPath(savedPath);
cr.fill();
cr.restore();
}
cr.$dispose();
cr.save();
cr.translate(xOffsetDirection * offset, - offset);
cr.appendPath(savedPath);
cr.fill();
cr.restore();
},
_styleChanged: function() {
@ -948,10 +939,15 @@ const Panel = new Lang.Class({
reactive: true });
this.actor._delegate = this;
this._sessionStyle = null;
this.statusArea = {};
Main.overview.connect('shown', Lang.bind(this, function () {
this.actor.add_style_class_name('in-overview');
}));
Main.overview.connect('hiding', Lang.bind(this, function () {
this.actor.remove_style_class_name('in-overview');
}));
this.menuManager = new PopupMenu.PopupMenuManager(this);
this._leftBox = new St.BoxLayout({ name: 'panelLeft' });
@ -961,10 +957,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));
@ -973,7 +976,7 @@ const Panel = new Lang.Class({
this.actor.connect('button-press-event', Lang.bind(this, this._onButtonPress));
Main.layoutManager.panelBox.add(this.actor);
Main.ctrlAltTabManager.addGroup(this.actor, _("Top Bar"), 'emblem-system-symbolic',
Main.ctrlAltTabManager.addGroup(this.actor, _("Top Bar"), 'start-here-symbolic',
{ sortGroup: CtrlAltTab.SortGroup.TOP });
Main.sessionMode.connect('updated', Lang.bind(this, this._updatePanel));
@ -1130,20 +1133,17 @@ const Panel = new Lang.Class({
this._updateBox(panel.left, this._leftBox);
this._updateBox(panel.center, this._centerBox);
this._updateBox(panel.right, this._rightBox);
},
if (this._sessionStyle)
this._removeStyleClassName(this._sessionStyle);
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;
}
}
},
@ -1221,17 +1221,5 @@ const Panel = new Lang.Class({
this.statusArea[role] = indicator;
this._addToPanelBox(role, indicator, position, boxContainer);
return indicator;
},
_addStyleClassName: function(className) {
this.actor.add_style_class_name(className);
this._rightCorner.actor.add_style_class_name(className);
this._leftCorner.actor.add_style_class_name(className);
},
_removeStyleClassName: function(className) {
this.actor.remove_style_class_name(className);
this._rightCorner.actor.remove_style_class_name(className);
this._leftCorner.actor.remove_style_class_name(className);
}
});

View File

@ -112,7 +112,7 @@ const Button = new Lang.Class({
this.actor.connect('key-press-event', Lang.bind(this, this._onSourceKeyPress));
if (dontCreateMenu)
this.menu = new PopupMenu.PopupDummyMenu(this.actor);
this.menu = null;
else
this.setMenu(new PopupMenu.PopupMenu(this.actor, menuAlignment, St.Side.TOP, 0));
@ -244,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;

View File

@ -1,5 +1,6 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
const Cairo = imports.cairo;
const Clutter = imports.gi.Clutter;
const GLib = imports.gi.GLib;
const Gtk = imports.gi.Gtk;
@ -11,10 +12,8 @@ const St = imports.gi.St;
const Atk = imports.gi.Atk;
const BoxPointer = imports.ui.boxpointer;
const GrabHelper = imports.ui.grabHelper;
const Main = imports.ui.main;
const Params = imports.misc.params;
const Separator = imports.ui.separator;
const Tweener = imports.ui.tweener;
const SLIDER_SCROLL_STEP = 0.05; /* Slider scrolling step in % */
@ -207,7 +206,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
@ -406,8 +404,29 @@ const PopupSeparatorMenuItem = new Lang.Class({
this.parent({ reactive: false,
can_focus: false});
this._separator = new Separator.HorizontalSeparator({ style_class: 'popup-separator-menu-item' });
this.addActor(this._separator.actor, { span: -1, expand: true });
this._drawingArea = new St.DrawingArea({ style_class: 'popup-separator-menu-item' });
this.addActor(this._drawingArea, { span: -1, expand: true });
this._drawingArea.connect('repaint', Lang.bind(this, this._onRepaint));
},
_onRepaint: function(area) {
let cr = area.get_context();
let themeNode = area.get_theme_node();
let [width, height] = area.get_surface_size();
let margin = themeNode.get_length('-margin-horizontal');
let gradientHeight = themeNode.get_length('-gradient-height');
let startColor = themeNode.get_color('-gradient-start');
let endColor = themeNode.get_color('-gradient-end');
let gradientWidth = (width - margin * 2);
let gradientOffset = (height - gradientHeight) / 2;
let pattern = new Cairo.LinearGradient(margin, gradientOffset, width - margin, gradientOffset + gradientHeight);
pattern.addColorStopRGBA(0, startColor.red / 255, startColor.green / 255, startColor.blue / 255, startColor.alpha / 255);
pattern.addColorStopRGBA(0.5, endColor.red / 255, endColor.green / 255, endColor.blue / 255, endColor.alpha / 255);
pattern.addColorStopRGBA(1, startColor.red / 255, startColor.green / 255, startColor.blue / 255, startColor.alpha / 255);
cr.setSource(pattern);
cr.rectangle(margin, gradientOffset, gradientWidth, gradientHeight);
cr.fill();
}
});
@ -605,7 +624,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 +656,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();
@ -1200,6 +1204,7 @@ const PopupMenu = new Lang.Class({
this.actor = this._boxPointer.actor;
this.actor._delegate = this;
this.actor.style_class = 'popup-menu-boxpointer';
this.actor.connect('key-press-event', Lang.bind(this, this._onKeyPressEvent));
this._boxWrapper = new Shell.GenericContainer();
this._boxWrapper.connect('get-preferred-width', Lang.bind(this, this._boxGetPreferredWidth));
@ -1229,6 +1234,15 @@ const PopupMenu = new Lang.Class({
this.box.allocate(box, flags);
},
_onKeyPressEvent: function(actor, event) {
if (event.get_key_symbol() == Clutter.Escape) {
this.close(BoxPointer.PopupAnimation.FULL);
return true;
}
return false;
},
setArrowOrigin: function(origin) {
this._boxPointer.setArrowOrigin(origin);
},
@ -1269,28 +1283,6 @@ const PopupMenu = new Lang.Class({
}
});
const PopupDummyMenu = new Lang.Class({
Name: 'PopupDummyMenu',
_init: function(sourceActor) {
this.sourceActor = sourceActor;
this.actor = sourceActor;
this.actor._delegate = this;
},
isChildMenu: function() {
return false;
},
open: function() { this.emit('open-state-changed', true); },
close: function() { this.emit('open-state-changed', false); },
toggle: function() {},
destroy: function() {
this.emit('destroy');
},
});
Signals.addSignalMethods(PopupDummyMenu.prototype);
const PopupSubMenu = new Lang.Class({
Name: 'PopupSubMenu',
Extends: PopupMenuBase,
@ -1545,6 +1537,7 @@ const PopupComboMenu = new Lang.Class({
this.actor = this.box;
this.actor._delegate = this;
this.actor.connect('key-press-event', Lang.bind(this, this._onKeyPressEvent));
this.actor.connect('key-focus-in', Lang.bind(this, this._onKeyFocusIn));
sourceActor.connect('style-changed',
Lang.bind(this, this._onSourceActorStyleChanged));
@ -1552,6 +1545,15 @@ const PopupComboMenu = new Lang.Class({
global.focus_manager.add_group(this.actor);
},
_onKeyPressEvent: function(actor, event) {
if (event.get_key_symbol() == Clutter.Escape) {
this.close(BoxPointer.PopupAnimation.FULL);
return true;
}
return false;
},
_onKeyFocusIn: function(actor) {
let items = this._getMenuItems();
let activeItem = items[this._activeItemPos];
@ -2042,8 +2044,17 @@ const PopupMenuManager = new Lang.Class({
_init: function(owner) {
this._owner = owner;
this._grabHelper = new GrabHelper.GrabHelper(owner.actor);
this.grabbed = false;
this._eventCaptureId = 0;
this._enterEventId = 0;
this._leaveEventId = 0;
this._keyFocusNotifyId = 0;
this._activeMenu = null;
this._menus = [];
this._menuStack = [];
this._preGrabInputMode = null;
this._grabbedFromKeynav = false;
},
addMenu: function(menu, position) {
@ -2062,8 +2073,6 @@ const PopupMenuManager = new Lang.Class({
let source = menu.sourceActor;
if (source) {
if (!menu.blockSourceEvents)
this._grabHelper.addActor(source);
menudata.enterId = source.connect('enter-event', Lang.bind(this, function() { this._onMenuSourceEnter(menu); }));
menudata.focusInId = source.connect('key-focus-in', Lang.bind(this, function() { this._onMenuSourceEnter(menu); }));
}
@ -2076,7 +2085,7 @@ const PopupMenuManager = new Lang.Class({
removeMenu: function(menu) {
if (menu == this._activeMenu)
this._closeMenu(menu);
this._closeMenu();
let position = this._findMenu(menu);
if (position == -1) // not a menu we manage
@ -2093,29 +2102,79 @@ const PopupMenuManager = new Lang.Class({
if (menudata.focusInId)
menu.sourceActor.disconnect(menudata.focusInId);
if (menu.sourceActor)
this._grabHelper.removeActor(menu.sourceActor);
this._menus.splice(position, 1);
},
get activeMenu() {
let actor = this._grabHelper.currentGrab.actor;
if (actor)
return actor._delegate;
else
return null;
_grab: function() {
Main.pushModal(this._owner.actor);
this._eventCaptureId = global.stage.connect('captured-event', Lang.bind(this, this._onEventCapture));
// captured-event doesn't see enter/leave events
this._enterEventId = global.stage.connect('enter-event', Lang.bind(this, this._onEventCapture));
this._leaveEventId = global.stage.connect('leave-event', Lang.bind(this, this._onEventCapture));
this._keyFocusNotifyId = global.stage.connect('notify::key-focus', Lang.bind(this, this._onKeyFocusChanged));
this.grabbed = true;
},
ignoreRelease: function() {
return this._grabHelper.ignoreRelease();
_ungrab: function() {
global.stage.disconnect(this._eventCaptureId);
this._eventCaptureId = 0;
global.stage.disconnect(this._enterEventId);
this._enterEventId = 0;
global.stage.disconnect(this._leaveEventId);
this._leaveEventId = 0;
global.stage.disconnect(this._keyFocusNotifyId);
this._keyFocusNotifyId = 0;
this.grabbed = false;
Main.popModal(this._owner.actor);
},
_onMenuOpenState: function(menu, open) {
if (open) {
this._grabHelper.grab({ actor: menu.actor, modal: true, focus: menu.sourceActor,
onUngrab: Lang.bind(this, this._closeMenu, menu) });
if (this._activeMenu && this._activeMenu.isChildMenu(menu)) {
this._menuStack.push(this._activeMenu);
menu.actor.grab_key_focus();
}
this._activeMenu = menu;
} else {
this._grabHelper.ungrab({ actor: menu.actor });
if (this._menuStack.length > 0) {
this._activeMenu = this._menuStack.pop();
if (menu.sourceActor)
menu.sourceActor.grab_key_focus();
this._didPop = true;
}
}
// Check what the focus was before calling pushModal/popModal
let focus = global.stage.key_focus;
let hadFocus = focus && this._activeMenuContains(focus);
if (open) {
if (!this.grabbed) {
this._preGrabInputMode = global.stage_input_mode;
this._grabbedFromKeynav = hadFocus;
this._grab();
}
if (hadFocus)
focus.grab_key_focus();
else
menu.actor.grab_key_focus();
} else if (menu == this._activeMenu) {
if (this.grabbed)
this._ungrab();
this._activeMenu = null;
if (this._grabbedFromKeynav) {
if (this._preGrabInputMode == Shell.StageInputMode.FOCUSED)
global.stage_input_mode = Shell.StageInputMode.FOCUSED;
if (hadFocus && menu.sourceActor)
menu.sourceActor.grab_key_focus();
else if (focus)
focus.grab_key_focus();
}
}
},
@ -2127,38 +2186,87 @@ const PopupMenuManager = new Lang.Class({
this.removeMenu(childMenu);
},
// change the currently-open menu without dropping grab
_changeMenu: function(newMenu) {
let oldMenu = this.activeMenu;
if (oldMenu) {
if (this._activeMenu) {
// _onOpenMenuState will drop the grab if it sees
// this._activeMenu being closed; so clear _activeMenu
// before closing it to keep that from happening
let oldMenu = this._activeMenu;
this._activeMenu = null;
for (let i = this._menuStack.length - 1; i >= 0; i--)
this._menuStack[i].close(BoxPointer.PopupAnimation.FADE);
oldMenu.close(BoxPointer.PopupAnimation.FADE);
newMenu.open(BoxPointer.PopupAnimation.FADE);
} else {
} else
newMenu.open(BoxPointer.PopupAnimation.FULL);
}
},
_onMenuSourceEnter: function(menu) {
if (!this._grabHelper.grabbed)
if (!this.grabbed || menu == this._activeMenu)
return false;
if (this._grabHelper.isActorGrabbed(menu.actor))
if (this._activeMenu && this._activeMenu.isChildMenu(menu))
return false;
let isChildMenu = this._grabHelper.grabStack.some(function(grab) {
let existingMenu = grab.actor._delegate;
return existingMenu.isChildMenu(menu);
});
if (isChildMenu)
if (this._menuStack.indexOf(menu) != -1)
return false;
if (this._menuStack.length > 0 && this._menuStack[0].isChildMenu(menu))
return false;
this._changeMenu(menu);
return false;
},
_onKeyFocusChanged: function() {
if (!this.grabbed || !this._activeMenu)
return;
let focus = global.stage.key_focus;
if (focus) {
if (this._activeMenuContains(focus))
return;
if (this._menuStack.length > 0)
return;
if (focus._delegate && focus._delegate.menu &&
this._findMenu(focus._delegate.menu) != -1)
return;
}
this._closeMenu();
},
_onMenuDestroy: function(menu) {
this.removeMenu(menu);
},
_activeMenuContains: function(actor) {
return this._activeMenu != null
&& (this._activeMenu.actor.contains(actor) ||
(this._activeMenu.sourceActor && this._activeMenu.sourceActor.contains(actor)));
},
_eventIsOnActiveMenu: function(event) {
return this._activeMenuContains(event.get_source());
},
_shouldBlockEvent: function(event) {
let src = event.get_source();
if (this._activeMenu != null && this._activeMenu.actor.contains(src))
return false;
for (let i = 0; i < this._menus.length; i++) {
let menu = this._menus[i].menu;
if (menu.sourceActor && !menu.blockSourceEvents && menu.sourceActor.contains(src)) {
return false;
}
}
return true;
},
_findMenu: function(item) {
for (let i = 0; i < this._menus.length; i++) {
let menudata = this._menus[i];
@ -2168,11 +2276,41 @@ const PopupMenuManager = new Lang.Class({
return -1;
},
_closeMenu: function(isUser, menu) {
// If this isn't a user action, we called close()
// on the BoxPointer ourselves, so we shouldn't
// reanimate.
if (isUser)
menu.close(BoxPointer.PopupAnimation.FULL);
_onEventCapture: function(actor, event) {
if (!this.grabbed)
return false;
if (this._owner.menuEventFilter &&
this._owner.menuEventFilter(event))
return true;
if (this._didPop) {
this._didPop = false;
return true;
}
let activeMenuContains = this._eventIsOnActiveMenu(event);
let eventType = event.type();
if (eventType == Clutter.EventType.BUTTON_RELEASE) {
if (activeMenuContains) {
return false;
} else {
this._closeMenu();
return true;
}
} else if (eventType == Clutter.EventType.BUTTON_PRESS && !activeMenuContains) {
this._closeMenu();
return true;
} else if (!this._shouldBlockEvent(event)) {
return false;
}
return true;
},
_closeMenu: function() {
if (this._activeMenu != null)
this._activeMenu.close(BoxPointer.PopupAnimation.FULL);
}
});

View File

@ -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;
@ -31,156 +29,93 @@ const SearchProviderIface = <interface name="org.gnome.Shell.SearchProvider">
</method>
</interface>;
const SearchProvider2Iface = <interface name="org.gnome.Shell.SearchProvider2">
<method name="GetInitialResultSet">
<arg type="as" direction="in" />
<arg type="as" direction="out" />
</method>
<method name="GetSubsearchResultSet">
<arg type="as" direction="in" />
<arg type="as" direction="in" />
<arg type="as" direction="out" />
</method>
<method name="GetResultMetas">
<arg type="as" direction="in" />
<arg type="aa{sv}" direction="out" />
</method>
<method name="ActivateResult">
<arg type="s" direction="in" />
<arg type="as" direction="in" />
<arg type="u" direction="in" />
</method>
<method name="LaunchSearch">
<arg type="as" direction="in" />
<arg type="u" direction="in" />
</method>
</interface>;
var SearchProviderProxy = Gio.DBusProxy.makeProxyWrapper(SearchProviderIface);
var SearchProvider2Proxy = Gio.DBusProxy.makeProxyWrapper(SearchProvider2Iface);
function loadRemoteSearchProviders(addProviderCallback) {
let data = { loadedProviders: [],
objectPaths: {},
addProviderCallback: addProviderCallback };
FileUtils.collectFromDatadirsAsync('search-providers',
{ loadedCallback: remoteProvidersLoaded,
processFile: loadRemoteSearchProvider,
data: data
});
}
let dataDirs = GLib.get_system_data_dirs();
let loadedProviders = {};
for (let i = 0; i < dataDirs.length; i++) {
let path = GLib.build_filenamev([dataDirs[i], 'gnome-shell', 'search-providers']);
let dir = Gio.file_new_for_path(path);
function loadRemoteSearchProvider(file, info, data) {
let keyfile = new GLib.KeyFile();
let path = file.get_path();
dir.query_info_async('standard:type', Gio.FileQueryInfoFlags.NONE,
GLib.PRIORITY_DEFAULT, null,
function(object, res) {
let exists = false;
try {
object.query_info_finish(res);
exists = true;
} catch (e) {
}
try {
keyfile.load_from_file(path, 0);
} catch(e) {
return;
if (!exists)
return;
loadRemoteSearchProvidersFromDir(dir, loadedProviders, addProviderCallback);
});
}
};
if (!keyfile.has_group(KEY_FILE_GROUP))
return;
function loadRemoteSearchProvidersFromDir(dir, loadedProviders, addProviderCallback) {
let dirPath = dir.get_path();
FileUtils.listDirAsync(dir, Lang.bind(this, function(files) {
for (let i = 0; i < files.length; i++) {
let keyfile = new GLib.KeyFile();
let path = GLib.build_filenamev([dirPath, files[i].get_name()]);
let remoteProvider;
try {
let group = KEY_FILE_GROUP;
let busName = keyfile.get_string(group, 'BusName');
let objectPath = keyfile.get_string(group, 'ObjectPath');
if (data.objectPaths[objectPath])
return;
let appInfo = null;
try {
let desktopId = keyfile.get_string(group, 'DesktopId');
appInfo = Gio.DesktopAppInfo.new(desktopId);
} catch (e) {
log('Ignoring search provider ' + path + ': missing DesktopId');
return;
}
let version = '1';
try {
version = keyfile.get_string(group, 'Version');
} catch (e) {
// ignore error
}
if (version >= 2)
remoteProvider = new RemoteSearchProvider2(appInfo, busName, objectPath);
else
remoteProvider = new RemoteSearchProvider(appInfo, busName, objectPath);
data.objectPaths[objectPath] = remoteProvider;
data.loadedProviders.push(remoteProvider);
} catch(e) {
log('Failed to add search provider %s: %s'.format(path, e.toString()));
}
}
function remoteProvidersLoaded(loadState) {
let searchSettings = new Gio.Settings({ schema: Search.SEARCH_PROVIDERS_SCHEMA });
let sortOrder = searchSettings.get_strv('sort-order');
let numSorted = sortOrder.length;
loadState.loadedProviders.sort(
function(providerA, providerB) {
let idxA, idxB;
let appIdA, appIdB;
appIdA = providerA.appInfo.get_id();
appIdB = providerB.appInfo.get_id();
idxA = sortOrder.indexOf(appIdA);
idxB = sortOrder.indexOf(appIdB);
// if no provider is found in the order, use alphabetical order
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
if ((idxA + 1) == numSorted)
return 1;
// if providerB is the last, it goes after everything
else if ((idxB + 1) == numSorted)
return -1;
try {
keyfile.load_from_file(path, 0);
} catch(e) {
continue;
}
// if providerA isn't found, it's sorted after providerB
if (idxA == -1)
return 1;
if (!keyfile.has_group(KEY_FILE_GROUP))
continue;
// if providerB isn't found, it's sorted after providerA
if (idxB == -1)
return -1;
let remoteProvider;
try {
let group = KEY_FILE_GROUP;
let busName = keyfile.get_string(group, 'BusName');
let objectPath = keyfile.get_string(group, 'ObjectPath');
// finally, if both providers are found, return their order in the list
return (idxA - idxB);
});
if (loadedProviders[objectPath])
continue;
loadState.loadedProviders.forEach(
function(provider) {
loadState.addProviderCallback(provider);
});
}
let appInfo = null;
try {
let desktopId = keyfile.get_string(group, 'DesktopId');
appInfo = Gio.DesktopAppInfo.new(desktopId);
} catch (e) {
log('Ignoring search provider ' + path + ': missing DesktopId');
continue;
}
remoteProvider = new RemoteSearchProvider(appInfo.get_name(),
appInfo.get_icon(),
busName,
objectPath);
loadedProviders[objectPath] = remoteProvider;
} catch(e) {
log('Failed to add search provider %s: %s'.format(path, e.toString()));
continue;
}
addProviderCallback(remoteProvider);
}
}));
};
const RemoteSearchProvider = new Lang.Class({
Name: 'RemoteSearchProvider',
Extends: Search.SearchProvider,
_init: function(appInfo, dbusName, dbusPath, proxyType) {
if (!proxyType)
proxyType = SearchProviderProxy;
this.proxy = new proxyType(Gio.DBus.session,
dbusName, dbusPath, Lang.bind(this, this._onProxyConstructed));
this.appInfo = appInfo;
this.id = appInfo.get_id();
this.isRemoteProvider = true;
_init: function(title, icon, dbusName, dbusPath) {
this._proxy = new SearchProviderProxy(Gio.DBus.session,
dbusName, dbusPath, Lang.bind(this, this._onProxyConstructed));
this.parent(title.toUpperCase());
this._cancellable = new Gio.Cancellable();
},
@ -189,17 +124,19 @@ 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,
// Ugh, but we want to fall back to something ...
return new St.Icon({ icon_name: 'text-x-generic',
icon_size: size });
},
@ -213,9 +150,9 @@ const RemoteSearchProvider = new Lang.Class({
this._cancellable.cancel();
this._cancellable.reset();
try {
this.proxy.GetInitialResultSetRemote(terms,
Lang.bind(this, this._getResultsFinished),
this._cancellable);
this._proxy.GetInitialResultSetRemote(terms,
Lang.bind(this, this._getResultsFinished),
this._cancellable);
} catch(e) {
log('Error calling GetInitialResultSet for provider %s: %s'.format( this.title, e.toString()));
this.searchSystem.pushResults(this, []);
@ -226,9 +163,9 @@ const RemoteSearchProvider = new Lang.Class({
this._cancellable.cancel();
this._cancellable.reset();
try {
this.proxy.GetSubsearchResultSetRemote(previousResults, newTerms,
Lang.bind(this, this._getResultsFinished),
this._cancellable);
this._proxy.GetSubsearchResultSetRemote(previousResults, newTerms,
Lang.bind(this, this._getResultsFinished),
this._cancellable);
} catch(e) {
log('Error calling GetSubsearchResultSet for provider %s: %s'.format(this.title, e.toString()));
this.searchSystem.pushResults(this, []);
@ -257,9 +194,9 @@ const RemoteSearchProvider = new Lang.Class({
this._cancellable.cancel();
this._cancellable.reset();
try {
this.proxy.GetResultMetasRemote(ids,
Lang.bind(this, this._getResultMetasFinished, callback),
this._cancellable);
this._proxy.GetResultMetasRemote(ids,
Lang.bind(this, this._getResultMetasFinished, callback),
this._cancellable);
} catch(e) {
log('Error calling GetResultMetas for provider %s: %s'.format(this.title, e.toString()));
callback([]);
@ -267,32 +204,8 @@ const RemoteSearchProvider = new Lang.Class({
},
activateResult: function(id) {
this.proxy.ActivateResultRemote(id);
},
launchSearch: function(terms) {
// the provider is not compatible with the new version of the interface, launch
// the app itself but warn so we can catch the error in logs
log('Search provider ' + this.appInfo.get_id() + ' does not implement LaunchSearch');
this.appInfo.launch([], global.create_app_launch_context());
this._proxy.ActivateResultRemote(id);
}
});
const RemoteSearchProvider2 = new Lang.Class({
Name: 'RemoteSearchProvider2',
Extends: RemoteSearchProvider,
_init: function(appInfo, dbusName, dbusPath) {
this.parent(appInfo, dbusName, dbusPath, SearchProvider2Proxy);
this.canLaunchSearch = true;
},
activateResult: function(id, terms) {
this.proxy.ActivateResultRemote(id, terms, global.get_current_time());
},
launchSearch: function(terms) {
this.proxy.LaunchSearchRemote(terms, global.get_current_time());
}
});

View File

@ -25,7 +25,6 @@ const Util = imports.misc.util;
const SCREENSAVER_SCHEMA = 'org.gnome.desktop.screensaver';
const LOCK_ENABLED_KEY = 'lock-enabled';
const LOCK_DELAY_KEY = 'lock-delay';
const CURTAIN_SLIDE_TIME = 0.3;
// fraction of screen height the arrow must reach before completing
@ -52,11 +51,10 @@ const SHORT_FADE_TIME = 0.3;
function sample(offx, offy) {
return 'texel += texture2D (sampler, tex_coord.st + pixel_step * ' +
'vec2 (' + offx + ',' + offy + '));\n'
'vec2 (' + offx + ',' + offy + ') * 2.0);\n'
}
const GLSL_BLUR_EFFECT_DECLARATIONS = ' \
uniform vec2 pixel_step;\n \
uniform float desaturation;\n \
vec4 apply_blur(in sampler2D sampler, in vec2 tex_coord) {\n \
vec4 texel;\n \
texel = texture2D (sampler, tex_coord.st);\n'
@ -64,6 +62,7 @@ vec4 apply_blur(in sampler2D sampler, in vec2 tex_coord) {\n \
+ sample( 0.0, -1.0)
+ sample(+1.0, -1.0)
+ sample(-1.0, 0.0)
+ sample( 0.0, 0.0)
+ sample(+1.0, 0.0)
+ sample(-1.0, +1.0)
+ sample( 0.0, +1.0)
@ -71,7 +70,7 @@ vec4 apply_blur(in sampler2D sampler, in vec2 tex_coord) {\n \
texel /= 9.0;\n \
return texel;\n \
}\n \
vec3 desaturate (const vec3 color)\n \
vec3 desaturate (const vec3 color, const float desaturation)\n \
{\n \
const vec3 gray_conv = vec3 (0.299, 0.587, 0.114);\n \
vec3 gray = vec3 (dot (gray_conv, color));\n \
@ -79,7 +78,7 @@ vec3 desaturate (const vec3 color)\n \
}';
const GLSL_BLUR_EFFECT_CODE = ' \
cogl_texel = apply_blur(cogl_sampler, cogl_tex_coord.st);\n \
cogl_texel.rgb = desaturate(cogl_texel.rgb);\n';
cogl_texel.rgb = desaturate(cogl_texel.rgb, 0.6);\n';
const Clock = new Lang.Class({
@ -309,7 +308,6 @@ const NotificationsBox = new Lang.Class({
obj.item.disconnect(obj.contentUpdatedId);
obj.source.disconnect(obj.sourceDestroyId);
obj.source.disconnect(obj.sourceCountChangedId);
obj.source.disconnect(obj.sourceTitleChangedId);
},
});
@ -400,7 +398,6 @@ const ScreenShield = new Lang.Class({
Lang.bind(this, this._onLockScreenKeyRelease));
this._lockScreenGroup.connect('scroll-event',
Lang.bind(this, this._onLockScreenScroll));
Main.ctrlAltTabManager.addGroup(this._lockScreenGroup, _("Lock"), 'changes-prevent-symbolic');
this._lockScreenContents = new St.Widget({ layout_manager: new Clutter.BinLayout(),
name: 'lockScreenContents' });
@ -411,12 +408,6 @@ const ScreenShield = new Lang.Class({
GLSL_BLUR_EFFECT_DECLARATIONS,
GLSL_BLUR_EFFECT_CODE,
true);
backgroundActor.set_uniform_float('desaturation',
1, 1, [0.6]);
backgroundActor.connect('notify::size', function(actor) {
actor.set_uniform_float('pixel_step', 2, 1, [1/actor.width, 1/actor.height]);
});
this._background = new St.Bin({ style_class: 'screen-shield-background',
child: backgroundActor });
this._lockScreenGroup.add_actor(this._background);
@ -504,7 +495,7 @@ const ScreenShield = new Lang.Class({
if (symbol == Clutter.KEY_Escape ||
symbol == Clutter.KEY_Return ||
symbol == Clutter.KEY_KP_Enter) {
this._ensureUnlockDialog(true, true);
this._ensureUnlockDialog(true);
this._hideLockScreen(true, 0);
return true;
}
@ -527,7 +518,7 @@ const ScreenShield = new Lang.Class({
// 7 standard scrolls to lift up
if (this._lockScreenScrollCounter > 35) {
this._ensureUnlockDialog(false, true);
this._ensureUnlockDialog(false);
this._hideLockScreen(true, 0);
}
@ -559,7 +550,7 @@ const ScreenShield = new Lang.Class({
_onDragBegin: function() {
Tweener.removeTweens(this._lockScreenGroup);
this._lockScreenState = MessageTray.State.HIDING;
this._ensureUnlockDialog(false, false);
this._ensureUnlockDialog(false);
return true;
},
@ -581,7 +572,6 @@ const ScreenShield = new Lang.Class({
// Complete motion automatically
let [velocity, velocityX, velocityY] = this._dragAction.get_velocity(0);
this._hideLockScreen(true, -velocityY);
this._ensureUnlockDialog(false, true);
} else {
// restore the lock screen to its original place
// try to use the same speed as the normal animation
@ -621,7 +611,7 @@ const ScreenShield = new Lang.Class({
}
if (!this._isModal) {
Main.pushModal(this.actor, { keybindingMode: Main.KeybindingMode.LOCK_SCREEN });
Main.pushModal(this.actor);
this._isModal = true;
}
@ -637,11 +627,7 @@ const ScreenShield = new Lang.Class({
let lightboxWasShown = this._lightbox.shown;
this._lightbox.hide();
// GLib.get_monotonic_time() returns microseconds, convert to seconds
let elapsedTime = (GLib.get_monotonic_time() - this._activationTime) / 1000000;
let shouldLock = lightboxWasShown &&
this._settings.get_boolean(LOCK_ENABLED_KEY) &&
(elapsedTime >= this._settings.get_uint(LOCK_DELAY_KEY));
let shouldLock = lightboxWasShown && this._settings.get_boolean(LOCK_ENABLED_KEY);
if (shouldLock || this._isLocked) {
this.lock(false);
} else if (this._isActive) {
@ -668,7 +654,7 @@ const ScreenShield = new Lang.Class({
this.actor.show();
this._isGreeter = Main.sessionMode.isGreeter;
this._ensureUnlockDialog(true, true);
this._ensureUnlockDialog(true);
this._hideLockScreen(false, 0);
},
@ -724,18 +710,16 @@ const ScreenShield = new Lang.Class({
Main.sessionMode.popMode('lock-screen');
},
_ensureUnlockDialog: function(onPrimary, allowCancel) {
_ensureUnlockDialog: function(onPrimary) {
if (!this._dialog) {
let constructor = Main.sessionMode.unlockDialog;
if (!constructor) {
this._dialog = new constructor(this._lockDialogGroup);
if (!this._dialog) {
// This session mode has no locking capabilities
this.unlock();
return;
}
this._dialog = new constructor(this._lockDialogGroup);
let time = global.get_current_time();
this._dialog.connect('loaded', Lang.bind(this, function() {
if (!this._dialog.open(time, onPrimary)) {
@ -747,8 +731,6 @@ const ScreenShield = new Lang.Class({
this._dialog.connect('failed', Lang.bind(this, this._onUnlockFailed));
this._dialog.connect('unlocked', Lang.bind(this, this._onUnlockSucceded));
}
this._dialog.allowCancel = allowCancel;
},
_onUnlockFailed: function() {
@ -760,10 +742,6 @@ const ScreenShield = new Lang.Class({
},
_resetLockScreen: function(animateLockScreen, animateLockDialog) {
if (this._lockScreenState == MessageTray.State.SHOWING ||
this._lockScreenState == MessageTray.State.SHOWN)
return;
this._ensureLockScreen();
this._lockDialogGroup.scale_x = 1;
this._lockDialogGroup.scale_y = 1;
@ -940,7 +918,7 @@ const ScreenShield = new Lang.Class({
lock: function(animate) {
if (!this._isModal) {
Main.pushModal(this.actor, { keybindingMode: Main.KeybindingMode.LOCK_SCREEN });
Main.pushModal(this.actor);
this._isModal = true;
}

View File

@ -1,272 +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;
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();
})
});
}
});

View File

@ -1,25 +1,183 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
const Gio = imports.gi.Gio;
const GLib = imports.gi.GLib;
const Lang = imports.lang;
const Signals = imports.signals;
const Shell = imports.gi.Shell;
const Util = imports.misc.util;
const SEARCH_PROVIDERS_SCHEMA = 'org.gnome.desktop.search-providers';
const FileUtils = imports.misc.fileUtils;
const Main = imports.ui.main;
// Not currently referenced by the search API, but
// this enumeration can be useful for provider
// implementations.
const MatchType = {
NONE: 0,
SUBSTRING: 1,
PREFIX: 2
};
const SearchResultDisplay = new Lang.Class({
Name: 'SearchResultDisplay',
_init: function(provider) {
this.provider = provider;
this.actor = null;
},
/**
* renderResults:
* @results: List of identifier strings
* @terms: List of search term strings
*
* Display the given search matches which resulted
* from the given terms. It's expected that not
* all results will fit in the space for the container
* actor; in this case, show as many as makes sense
* for your result type.
*
* The terms are useful for search match highlighting.
*/
renderResults: function(results, terms) {
throw new Error('Not implemented');
},
/**
* clear:
* Remove all results from this display.
*/
clear: function() {
this.actor.destroy_all_children();
},
/**
* getVisibleResultCount:
*
* Returns: The number of actors visible.
*/
getVisibleResultCount: function() {
throw new Error('Not implemented');
},
});
/**
* SearchProvider:
*
* Subclass this object to add a new result type
* to the search system, then call registerProvider()
* in SearchSystem with an instance.
* Search is asynchronous and uses the
* getInitialResultSet()/getSubsearchResultSet() methods.
*/
const SearchProvider = new Lang.Class({
Name: 'SearchProvider',
_init: function(title) {
this.title = title;
this.searchSystem = null;
},
/**
* getInitialResultSet:
* @terms: Array of search terms, treated as logical AND
*
* Called when the user first begins a search (most likely
* therefore a single term of length one or two), or when
* a new term is added.
*
* Should "return" an array of result identifier strings representing
* items which match the given search terms. This
* is expected to be a substring match on the metadata for a given
* item. Ordering of returned results is up to the discretion of the provider,
* but you should follow these heruistics:
*
* * Put items where the term matches multiple criteria (e.g. name and
* description) before single matches
* * Put items which match on a prefix before non-prefix substring matches
*
* We say "return" above, but in order to make the query asynchronous, use
* this.searchSystem.pushResults();. The return value should be ignored.
*
* This function should be fast; do not perform unindexed full-text searches
* or network queries.
*/
getInitialResultSet: function(terms) {
throw new Error('Not implemented');
},
/**
* getSubsearchResultSet:
* @previousResults: Array of item identifiers
* @newTerms: Updated search terms
*
* Called when a search is performed which is a "subsearch" of
* the previous search; i.e. when every search term has exactly
* one corresponding term in the previous search which is a prefix
* of the new term.
*
* This allows search providers to only search through the previous
* result set, rather than possibly performing a full re-query.
*
* Similar to getInitialResultSet, the return value for this will
* be ignored; use this.searchSystem.pushResults();.
*/
getSubsearchResultSet: function(previousResults, newTerms) {
throw new Error('Not implemented');
},
/**
* getResultMetas:
* @ids: Result identifier strings
*
* Call callback with array of objects with 'id', 'name', (both strings) and
* 'createIcon' (function(size) returning a Clutter.Texture) properties
* with the same number of members as @ids
*/
getResultMetas: function(ids, callback) {
throw new Error('Not implemented');
},
/**
* createResultActor:
* @resultMeta: Object with result metadata
* @terms: Array of search terms, should be used for highlighting
*
* Search providers may optionally override this to render a
* particular serch result in a custom fashion. The default
* implementation will show the icon next to the name.
*
* The actor should be an instance of St.Widget, with the style class
* 'search-result-content'.
*/
createResultActor: function(resultMeta, terms) {
return null;
},
/**
* activateResult:
* @id: Result identifier string
*
* Called when the user chooses a given result.
*/
activateResult: function(id) {
throw new Error('Not implemented');
}
});
Signals.addSignalMethods(SearchProvider.prototype);
const SearchSystem = new Lang.Class({
Name: 'SearchSystem',
_init: function() {
this._providers = [];
this._remoteProviders = [];
this.reset();
},
registerProvider: function (provider) {
provider.searchSystem = this;
this._providers.push(provider);
if (provider.isRemoteProvider)
this._remoteProviders.push(provider);
},
unregisterProvider: function (provider) {
@ -28,20 +186,12 @@ const SearchSystem = new Lang.Class({
return;
provider.searchSystem = null;
this._providers.splice(index, 1);
let remoteIndex = this._remoteProviders.indexOf(provider);
if (remoteIndex != -1)
this._remoteProviders.splice(index, 1);
},
getProviders: function() {
return this._providers;
},
getRemoteProviders: function() {
return this._remoteProviders;
},
getTerms: function() {
return this._previousTerms;
},
@ -96,7 +246,7 @@ const SearchSystem = new Lang.Class({
results.push([provider, []]);
provider.getSubsearchResultSet(previousResults, terms);
} catch (error) {
log('A ' + error.name + ' has occured in ' + provider.id + ': ' + error.message);
log('A ' + error.name + ' has occured in ' + provider.title + ': ' + error.message);
}
}
} else {
@ -106,7 +256,7 @@ const SearchSystem = new Lang.Class({
results.push([provider, []]);
provider.getInitialResultSet(terms);
} catch (error) {
log('A ' + error.name + ' has occured in ' + provider.id + ': ' + error.message);
log('A ' + error.name + ' has occured in ' + provider.title + ': ' + error.message);
}
}
}

View File

@ -11,11 +11,10 @@ const DND = imports.ui.dnd;
const IconGrid = imports.ui.iconGrid;
const Main = imports.ui.main;
const Overview = imports.ui.overview;
const Separator = imports.ui.separator;
const Search = imports.ui.search;
const MAX_LIST_SEARCH_RESULTS_ROWS = 3;
const MAX_GRID_SEARCH_RESULTS_ROWS = 1;
const MAX_SEARCH_RESULTS_ROWS = 1;
const SearchResult = new Lang.Class({
Name: 'SearchResult',
@ -23,104 +22,34 @@ const SearchResult = new Lang.Class({
_init: function(provider, metaInfo, terms) {
this.provider = provider;
this.metaInfo = metaInfo;
this.terms = terms;
this.actor = new St.Button({ reactive: true,
can_focus: true,
track_hover: true,
this.actor = new St.Button({ style_class: 'search-result',
reactive: true,
x_align: St.Align.START,
y_fill: true });
this.actor._delegate = this;
this.actor.connect('clicked', Lang.bind(this, this.activate));
},
activate: function() {
this.provider.activateResult(this.metaInfo.id, this.terms);
Main.overview.toggle();
},
setSelected: function(selected) {
if (selected)
this.actor.add_style_pseudo_class('selected');
else
this.actor.remove_style_pseudo_class('selected');
}
});
const ListSearchResult = new Lang.Class({
Name: 'ListSearchResult',
Extends: SearchResult,
ICON_SIZE: 64,
_init: function(provider, metaInfo, terms) {
this.parent(provider, metaInfo, terms);
this.actor.style_class = 'list-search-result';
this.actor.x_fill = true;
let content = new St.BoxLayout({ style_class: 'list-search-result-content',
vertical: false });
this.actor.set_child(content);
// An icon for, or thumbnail of, content
let icon = this.metaInfo['createIcon'](this.ICON_SIZE);
if (icon) {
content.add(icon);
}
let details = new St.BoxLayout({ vertical: true });
content.add(details, { x_fill: true,
y_fill: false,
x_align: St.Align.START,
y_align: St.Align.MIDDLE });
let title = new St.Label({ style_class: 'list-search-result-title',
text: this.metaInfo['name'] })
details.add(title, { x_fill: false,
y_fill: false,
x_align: St.Align.START,
y_align: St.Align.START });
// TODO: should highlight terms in the description here
if (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,
y_align: St.Align.END });
}
}
});
const GridSearchResult = new Lang.Class({
Name: 'GridSearchResult',
Extends: SearchResult,
_init: function(provider, metaInfo, terms) {
this.parent(provider, metaInfo, terms);
this.actor.style_class = 'grid-search-result';
this._dragActorSource = null;
let content = provider.createResultActor(metaInfo, terms);
let dragSource = null;
if (content == null) {
content = new St.Bin();
content = new St.Bin({ style_class: 'search-result-content',
reactive: true,
can_focus: true,
track_hover: true,
accessible_role: Atk.Role.PUSH_BUTTON });
let icon = new IconGrid.BaseIcon(this.metaInfo['name'],
{ createIcon: this.metaInfo['createIcon'] });
content.set_child(icon.actor);
this._dragActorSource = icon.icon;
content.label_actor = icon.label;
dragSource = icon.icon;
} else {
if (content._delegate && content._delegate.getDragActorSource)
dragSource = content._delegate.getDragActorSource();
this._dragActorSource = content._delegate.getDragActorSource();
}
this._content = content;
this.actor.set_child(content);
this.actor.connect('clicked', Lang.bind(this, this._onResultClicked));
let draggable = DND.makeDraggable(this.actor);
draggable.connect('drag-begin',
Lang.bind(this, function() {
@ -134,18 +63,32 @@ const GridSearchResult = new Lang.Class({
Lang.bind(this, function() {
Main.overview.endItemDrag(this);
}));
},
if (!dragSource)
// not exactly right, but alignment problems are hard to notice
dragSource = content;
this._dragActorSource = dragSource;
setSelected: function(selected) {
if (selected)
this._content.add_style_pseudo_class('selected');
else
this._content.remove_style_pseudo_class('selected');
},
activate: function() {
this.provider.activateResult(this.metaInfo.id);
Main.overview.toggle();
},
_onResultClicked: function(actor) {
this.activate();
},
getDragActorSource: function() {
return this._dragActorSource;
if (this._dragActorSource)
return this._dragActorSource;
// not exactly right, but alignment problems are hard to notice
return this._content;
},
getDragActor: function() {
getDragActor: function(stageX, stageY) {
return this.metaInfo['createIcon'](Main.overview.dashIconSize);
},
@ -153,93 +96,34 @@ const GridSearchResult = new Lang.Class({
if (this.provider.dragActivateResult)
this.provider.dragActivateResult(this.metaInfo.id, params);
else
this.provider.activateResult(this.metaInfo.id, this.terms);
this.provider.activateResult(this.metaInfo.id, params);
}
});
const ListSearchResults = new Lang.Class({
Name: 'ListSearchResults',
_init: function(provider) {
this.provider = provider;
this.actor = new St.BoxLayout({ style_class: 'search-section-content' });
this.providerIcon = new ProviderIcon(provider);
this.providerIcon.connect('clicked', Lang.bind(this,
function() {
provider.launchSearch(this._terms);
Main.overview.toggle();
}));
this.actor.add(this.providerIcon, { x_fill: false,
y_fill: false,
x_align: St.Align.START,
y_align: St.Align.START });
this._content = new St.BoxLayout({ style_class: 'list-search-results',
vertical: true });
this.actor.add_actor(this._content);
this._notDisplayedResult = [];
this._terms = [];
this._pendingClear = false;
},
getResultsForDisplay: function() {
let alreadyVisible = this._pendingClear ? 0 : this.getVisibleResultCount();
let canDisplay = MAX_LIST_SEARCH_RESULTS_ROWS - alreadyVisible;
let newResults = this._notDisplayedResult.splice(0, canDisplay);
return newResults;
},
getVisibleResultCount: function() {
return this._content.get_n_children();
},
hasMoreResults: function() {
return this._notDisplayedResult.length > 0;
},
setResults: function(results, terms) {
// copy the lists
this._notDisplayedResult = results.slice(0);
this._terms = terms.slice(0);
this._pendingClear = true;
},
renderResults: function(metas) {
for (let i = 0; i < metas.length; i++) {
let display = new ListSearchResult(this.provider, metas[i], this._terms);
this._content.add_actor(display.actor);
}
},
clear: function () {
this._content.destroy_all_children();
this._pendingClear = false;
},
getFirstResult: function() {
if (this.getVisibleResultCount() > 0)
return this._content.get_child_at_index(0)._delegate;
else
return null;
}
});
const GridSearchResults = new Lang.Class({
Name: 'GridSearchResults',
Extends: Search.SearchResultDisplay,
_init: function(provider) {
this.provider = provider;
_init: function(provider, grid) {
this.parent(provider);
this._grid = new IconGrid.IconGrid({ rowLimit: MAX_GRID_SEARCH_RESULTS_ROWS,
xAlign: St.Align.START });
this.actor = new St.Bin({ x_align: St.Align.MIDDLE });
this._grid = grid || new IconGrid.IconGrid({ rowLimit: MAX_SEARCH_RESULTS_ROWS,
xAlign: St.Align.START });
this.actor = new St.Bin({ x_align: St.Align.START });
this.actor.set_child(this._grid.actor);
this._width = 0;
this.actor.connect('notify::width', Lang.bind(this, function() {
this._width = this.actor.width;
Meta.later_add(Meta.LaterType.BEFORE_REDRAW, Lang.bind(this, function() {
let results = this.getResultsForDisplay();
if (results.length == 0)
return;
provider.getResultMetas(results, Lang.bind(this, this.renderResults));
}));
}));
this._notDisplayedResult = [];
this._terms = [];
this._pendingClear = false;
@ -247,21 +131,18 @@ const GridSearchResults = new Lang.Class({
getResultsForDisplay: function() {
let alreadyVisible = this._pendingClear ? 0 : this._grid.visibleItemsCount();
let canDisplay = this._grid.childrenInRow(this.actor.width) * this._grid.getRowLimit()
let canDisplay = this._grid.childrenInRow(this._width) * this._grid.getRowLimit()
- alreadyVisible;
let newResults = this._notDisplayedResult.splice(0, canDisplay);
return newResults;
let numResults = Math.min(this._notDisplayedResult.length, canDisplay);
return this._notDisplayedResult.splice(0, numResults);
},
getVisibleResultCount: function() {
return this._grid.visibleItemsCount();
},
hasMoreResults: function() {
return this._notDisplayedResult.length > 0;
},
setResults: function(results, terms) {
// copy the lists
this._notDisplayedResult = results.slice(0);
@ -271,7 +152,7 @@ const GridSearchResults = new Lang.Class({
renderResults: function(metas) {
for (let i = 0; i < metas.length; i++) {
let display = new GridSearchResult(this.provider, metas[i], this._terms);
let display = new SearchResult(this.provider, metas[i], this._terms);
this._grid.addItem(display.actor);
}
},
@ -302,20 +183,26 @@ const SearchResults = new Lang.Class({
this._content = new St.BoxLayout({ name: 'searchResultsContent',
vertical: true });
this._scrollView = new St.ScrollView({ x_fill: true,
y_fill: false,
style_class: 'vfade' });
this._scrollView.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC);
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);
let scrollView = new St.ScrollView({ x_fill: true,
y_fill: false,
style_class: 'vfade' });
scrollView.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC);
scrollView.add_actor(this._content);
this.actor.add(this._scrollView, { x_fill: true,
y_fill: true,
expand: true,
x_align: St.Align.START,
y_align: St.Align.START });
this.actor.add(scrollView, { x_fill: true,
y_fill: true,
expand: true,
x_align: St.Align.START,
y_align: St.Align.START });
this.actor.connect('notify::mapped', Lang.bind(this,
function() {
if (!this.actor.mapped)
return;
let adjustment = scrollView.vscroll.adjustment;
let direction = Overview.SwipeScrollDirection.VERTICAL;
Main.overview.setScrollAdjustment(adjustment, direction);
}));
this._statusText = new St.Label({ style_class: 'search-statustext' });
this._statusBin = new St.Bin({ x_align: St.Align.MIDDLE,
@ -332,37 +219,22 @@ const SearchResults = new Lang.Class({
this._defaultResult = null;
},
_onPan: function(action) {
let [dist, dx, dy] = action.get_motion_delta(0);
let adjustment = this._scrollView.vscroll.adjustment;
adjustment.value -= (dy / this.actor.height) * adjustment.page_size;
return false;
},
createProviderMeta: function(provider) {
let providerBox = new St.BoxLayout({ style_class: 'search-section',
vertical: true });
let providerIcon = null;
let resultDisplay = null;
let title = new St.Label({ style_class: 'search-section-header',
text: provider.title });
providerBox.add(title, { x_fill: false, x_align: St.Align.START });
if (provider.appInfo) {
resultDisplay = new ListSearchResults(provider);
providerIcon = resultDisplay.providerIcon;
} else {
resultDisplay = new GridSearchResults(provider);
}
let resultDisplayBin = new St.Bin({ child: resultDisplay.actor,
let resultDisplayBin = new St.Bin({ style_class: 'search-section-results',
x_fill: true,
y_fill: true });
providerBox.add(resultDisplayBin, { expand: true });
let separator = new Separator.HorizontalSeparator({ style_class: 'search-section-separator' });
providerBox.add(separator.actor);
let resultDisplay = new GridSearchResults(provider);
resultDisplayBin.set_child(resultDisplay.actor);
this._providerMeta.push({ provider: provider,
actor: providerBox,
icon: providerIcon,
resultDisplay: resultDisplay });
this._content.add(providerBox);
},
@ -469,11 +341,6 @@ const SearchResults = new Lang.Class({
meta.resultDisplay.setResults(providerResults, terms);
let results = meta.resultDisplay.getResultsForDisplay();
if (meta.icon)
meta.icon.moreIcon.visible =
meta.resultDisplay.hasMoreResults() &&
provider.canLaunchSearch;
provider.getResultMetas(results, Lang.bind(this, function(metas) {
this._clearDisplayForProvider(provider);
meta.actor.show();
@ -519,37 +386,10 @@ const SearchResults = new Lang.Class({
let from = this._defaultResult ? this._defaultResult.actor : null;
this.actor.navigate_focus(from, direction, false);
}
});
const ProviderIcon = new Lang.Class({
Name: 'ProviderIcon',
Extends: St.Button,
PROVIDER_ICON_SIZE: 48,
_init: function(provider) {
this.provider = provider;
this.parent({ style_class: 'search-provider-icon',
reactive: true,
can_focus: true,
track_hover: true });
this._content = new St.Widget({ layout_manager: new Clutter.BinLayout() });
this.set_child(this._content);
let rtl = (this.get_text_direction() == Clutter.TextDirection.RTL);
this.moreIcon = new St.Widget({ style_class: 'search-provider-icon-more',
visible: false,
x_align: rtl ? Clutter.ActorAlign.START : Clutter.ActorAlign.END,
y_align: Clutter.ActorAlign.END,
x_expand: true,
y_expand: true });
let icon = new St.Icon({ icon_size: this.PROVIDER_ICON_SIZE,
gicon: provider.appInfo.get_icon() });
this._content.add_actor(icon);
this._content.add_actor(this.moreIcon);
if (this._defaultResult) {
// The default result appears focused, so navigate directly to the
// next result.
this.actor.navigate_focus(global.stage.key_focus, direction, false);
}
}
});

View File

@ -1,35 +0,0 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
const Cairo = imports.cairo;
const Lang = imports.lang;
const St = imports.gi.St;
const HorizontalSeparator = new Lang.Class({
Name: 'HorizontalSeparator',
_init: function (params) {
this.actor = new St.DrawingArea(params);
this.actor.connect('repaint', Lang.bind(this, this._onRepaint));
},
_onRepaint: function(area) {
let cr = area.get_context();
let themeNode = area.get_theme_node();
let [width, height] = area.get_surface_size();
let margin = themeNode.get_length('-margin-horizontal');
let gradientHeight = themeNode.get_length('-gradient-height');
let startColor = themeNode.get_color('-gradient-start');
let endColor = themeNode.get_color('-gradient-end');
let gradientWidth = (width - margin * 2);
let gradientOffset = (height - gradientHeight) / 2;
let pattern = new Cairo.LinearGradient(margin, gradientOffset, width - margin, gradientOffset + gradientHeight);
pattern.addColorStopRGBA(0, startColor.red / 255, startColor.green / 255, startColor.blue / 255, startColor.alpha / 255);
pattern.addColorStopRGBA(0.5, endColor.red / 255, endColor.green / 255, endColor.blue / 255, endColor.alpha / 255);
pattern.addColorStopRGBA(1, startColor.red / 255, startColor.green / 255, startColor.blue / 255, startColor.alpha / 255);
cr.setSource(pattern);
cr.rectangle(margin, gradientOffset, gradientWidth, gradientHeight);
cr.fill();
cr.$dispose();
}
});

View File

@ -1,12 +1,8 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
const Gio = imports.gi.Gio;
const GLib = imports.gi.GLib;
const Lang = imports.lang;
const Mainloop = imports.mainloop;
const Signals = imports.signals;
const FileUtils = imports.misc.fileUtils;
const Main = imports.ui.main;
const Params = imports.misc.params;
@ -14,12 +10,11 @@ const DEFAULT_MODE = 'restrictive';
const _modes = {
'restrictive': {
parentMode: null,
hasOverview: false,
showCalendarEvents: false,
allowSettings: false,
allowExtensions: false,
enabledExtensions: [],
allowKeybindingsWhenModal: false,
hasRunDialog: false,
hasWorkspaces: false,
hasWindows: false,
@ -34,52 +29,49 @@ const _modes = {
center: [],
right: []
},
panelStyle: null
},
'gdm': {
allowKeybindingsWhenModal: true,
hasNotifications: true,
isGreeter: true,
isPrimary: true,
unlockDialog: imports.gdm.loginDialog.LoginDialog,
components: ['polkitAgent'],
components: ['polkitAgent', 'mediaKeysManager'],
panel: {
left: ['logo'],
center: ['dateMenu'],
right: ['a11y', 'display', 'keyboard',
'volume', 'battery', 'powerMenu']
},
panelStyle: 'login-screen'
}
},
'lock-screen': {
isLocked: true,
isGreeter: undefined,
unlockDialog: undefined,
components: ['polkitAgent', 'telepathyClient'],
components: ['polkitAgent', 'telepathyClient', 'mediaKeysManager'],
panel: {
left: ['userMenu'],
center: [],
right: ['lockScreen']
},
panelStyle: 'lock-screen'
},
'unlock-dialog': {
isLocked: true,
unlockDialog: undefined,
components: ['polkitAgent', 'telepathyClient'],
components: ['polkitAgent', 'telepathyClient', 'mediaKeysManager'],
panel: {
left: ['userMenu'],
center: [],
right: ['a11y', 'keyboard', 'lockScreen']
},
panelStyle: 'unlock-screen'
},
'initial-setup': {
isPrimary: true,
components: ['keyring'],
components: ['keyring', 'mediaKeysManager'],
panel: {
left: [],
center: ['dateMenu'],
@ -99,8 +91,9 @@ const _modes = {
isLocked: false,
isPrimary: true,
unlockDialog: imports.ui.unlockDialog.UnlockDialog,
components: ['networkAgent', 'polkitAgent', 'telepathyClient',
'keyring', 'recorder', 'autorunManager', 'automountManager'],
components: ['networkAgent', 'polkitAgent', 'telepathyClient', 'keyring',
'recorder', 'autorunManager', 'automountManager',
'mediaKeysManager'],
panel: {
left: ['activities', 'appMenu'],
center: ['dateMenu'],
@ -110,48 +103,11 @@ const _modes = {
}
};
function _getModes(modesLoadedCallback) {
FileUtils.collectFromDatadirsAsync('modes',
{ processFile: _loadMode,
loadedCallback: modesLoadedCallback,
data: _modes });
}
function _loadMode(file, info, loadedData) {
let name = info.get_name();
let suffix = name.indexOf('.json');
let modeName = suffix == -1 ? name : name.slice(name, suffix);
if (loadedData.hasOwnProperty(modeName))
return;
let fileContent, success, tag, newMode;
try {
[success, fileContent, tag] = file.load_contents(null);
newMode = JSON.parse(fileContent);
} catch(e) {
return;
}
loadedData[modeName] = {};
let propBlacklist = ['unlockDialog'];
for (let prop in loadedData[DEFAULT_MODE]) {
if (newMode[prop] !== undefined &&
propBlacklist.indexOf(prop) == -1)
loadedData[modeName][prop]= newMode[prop];
}
loadedData[modeName]['isPrimary'] = true;
}
function listModes() {
_getModes(function(modes) {
let names = Object.getOwnPropertyNames(modes);
for (let i = 0; i < names.length; i++)
if (_modes[names[i]].isPrimary)
print(names[i]);
Mainloop.quit('listModes');
});
Mainloop.run('listModes');
let modes = Object.getOwnPropertyNames(_modes);
for (let i = 0; i < modes.length; i++)
if (_modes[modes[i]].isPrimary)
print(modes[i]);
}
const SessionMode = new Lang.Class({
@ -159,18 +115,10 @@ const SessionMode = new Lang.Class({
_init: function() {
global.connect('notify::session-mode', Lang.bind(this, this._sync));
this._modes = _modes;
this._modeStack = [DEFAULT_MODE];
let mode = _modes[global.session_mode].isPrimary ? global.session_mode
: 'user';
this._modeStack = [mode];
this._sync();
_getModes(Lang.bind(this, function(modes) {
this._modes = modes;
let primary = modes[global.session_mode] &&
modes[global.session_mode].isPrimary;
let mode = primary ? global.session_mode : 'user';
this._modeStack = [mode];
this._sync();
}));
},
pushMode: function(mode) {
@ -197,14 +145,8 @@ const SessionMode = new Lang.Class({
},
_sync: function() {
let params = this._modes[this.currentMode];
let defaults;
if (params.parentMode)
defaults = Params.parse(this._modes[params.parentMode],
this._modes[DEFAULT_MODE]);
else
defaults = this._modes[DEFAULT_MODE];
params = Params.parse(params, defaults);
let params = _modes[this.currentMode];
params = Params.parse(params, _modes[DEFAULT_MODE]);
// A simplified version of Lang.copyProperties, handles
// undefined as a special case for "no change / inherit from previous mode"

View File

@ -9,8 +9,8 @@ const Config = imports.misc.config;
const ExtensionSystem = imports.ui.extensionSystem;
const ExtensionDownloader = imports.ui.extensionDownloader;
const ExtensionUtils = imports.misc.extensionUtils;
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">
@ -18,7 +18,34 @@ const GnomeShellIface = <interface name="org.gnome.Shell">
<arg type="b" direction="out" name="success" />
<arg type="s" direction="out" name="result" />
</method>
<property name="Mode" type="s" access="read" />
<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>
<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="OverviewActive" type="b" access="readwrite" />
<property name="ShellVersion" type="s" access="read" />
</interface>;
@ -48,7 +75,6 @@ const GnomeShell = new Lang.Class({
this._dbusImpl.export(Gio.DBus.session, '/org/gnome/Shell');
this._extensionsSerivce = new GnomeShellExtensions();
this._screenshotService = new Screenshot.ScreenshotService();
},
/**
@ -84,7 +110,81 @@ const GnomeShell = new Lang.Class({
return [success, returnValue];
},
Mode: global.session_mode,
_onScreenshotComplete: function(obj, result, area, flash, invocation) {
if (flash) {
let flashspot = new Flashspot.Flashspot(area);
flashspot.fire();
}
let retval = GLib.Variant.new('(b)', [result]);
invocation.return_value(retval);
},
/**
* 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));
},
/**
* 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();
},
get OverviewActive() {
return Main.overview.visible;

View File

@ -19,8 +19,6 @@ const ShellEntry = imports.ui.shellEntry;
const LIST_ITEM_ICON_SIZE = 48;
const REMEMBER_MOUNT_PASSWORD_KEY = 'remember-mount-password';
/* ------ Common Utils ------- */
function _setLabelText(label, text) {
if (text) {
@ -389,8 +387,7 @@ const ShellMountPasswordDialog = new Lang.Class({
if (flags & Gio.AskPasswordFlags.SAVING_SUPPORTED) {
this._rememberChoice = new CheckBox.CheckBox();
this._rememberChoice.getLabelActor().text = _("Remember Password");
this._rememberChoice.actor.checked =
global.settings.get_boolean(REMEMBER_MOUNT_PASSWORD_KEY);
this._rememberChoice.actor.checked = true;
this._messageBox.add(this._rememberChoice.actor);
} else {
this._rememberChoice = null;
@ -422,8 +419,6 @@ const ShellMountPasswordDialog = new Lang.Class({
},
_onEntryActivate: function() {
global.settings.set_boolean(REMEMBER_MOUNT_PASSWORD_KEY,
this._rememberChoice && this._rememberChoice.actor.checked);
this.emit('response', 1,
this._passwordEntry.get_text(),
this._rememberChoice &&

View File

@ -27,7 +27,6 @@ const KEY_VISUAL_BELL = 'visual-bell';
const DESKTOP_INTERFACE_SCHEMA = 'org.gnome.desktop.interface';
const KEY_GTK_THEME = 'gtk-theme';
const KEY_ICON_THEME = 'icon-theme';
const KEY_WM_THEME = 'theme';
const KEY_TEXT_SCALING_FACTOR = 'text-scaling-factor';
const HIGH_CONTRAST_THEME = 'HighContrast';
@ -39,8 +38,8 @@ const ATIndicator = new Lang.Class({
_init: function() {
this.parent('preferences-desktop-accessibility-symbolic', _("Accessibility"));
let highContrast = this._buildHCItem();
this.menu.addMenuItem(highContrast);
this._highContrast = this._buildHCItem();
this.menu.addMenuItem(this._highContrast);
let magnifier = this._buildItem(_("Zoom"), APPLICATIONS_SCHEMA,
'screen-magnifier-enabled');
@ -102,35 +101,28 @@ const ATIndicator = new Lang.Class({
},
_buildHCItem: function() {
let interfaceSettings = new Gio.Settings({ schema: DESKTOP_INTERFACE_SCHEMA });
let wmSettings = new Gio.Settings({ schema: WM_SCHEMA });
let gtkTheme = interfaceSettings.get_string(KEY_GTK_THEME);
let iconTheme = interfaceSettings.get_string(KEY_ICON_THEME);
let wmTheme = wmSettings.get_string(KEY_WM_THEME);
let settings = new Gio.Settings({ schema: DESKTOP_INTERFACE_SCHEMA });
let gtkTheme = settings.get_string(KEY_GTK_THEME);
let iconTheme = settings.get_string(KEY_ICON_THEME);
let hasHC = (gtkTheme == HIGH_CONTRAST_THEME);
let highContrast = this._buildItemExtended(
_("High Contrast"),
hasHC,
interfaceSettings.is_writable(KEY_GTK_THEME) &&
interfaceSettings.is_writable(KEY_ICON_THEME) &&
wmSettings.is_writable(KEY_WM_THEME),
settings.is_writable(KEY_GTK_THEME) && settings.is_writable(KEY_ICON_THEME),
function (enabled) {
if (enabled) {
interfaceSettings.set_string(KEY_GTK_THEME, HIGH_CONTRAST_THEME);
interfaceSettings.set_string(KEY_ICON_THEME, HIGH_CONTRAST_THEME);
wmSettings.set_string(KEY_WM_THEME, HIGH_CONTRAST_THEME);
settings.set_string(KEY_GTK_THEME, HIGH_CONTRAST_THEME);
settings.set_string(KEY_ICON_THEME, HIGH_CONTRAST_THEME);
} else if(!hasHC) {
interfaceSettings.set_string(KEY_GTK_THEME, gtkTheme);
interfaceSettings.set_string(KEY_ICON_THEME, iconTheme);
wmSettings.set_string(KEY_WM_THEME, wmTheme);
settings.set_string(KEY_GTK_THEME, gtkTheme);
settings.set_string(KEY_ICON_THEME, iconTheme);
} else {
interfaceSettings.reset(KEY_GTK_THEME);
interfaceSettings.reset(KEY_ICON_THEME);
wmSettings.reset(KEY_WM_THEME);
settings.reset(KEY_GTK_THEME);
settings.reset(KEY_ICON_THEME);
}
});
interfaceSettings.connect('changed::' + KEY_GTK_THEME, function() {
let value = interfaceSettings.get_string(KEY_GTK_THEME);
settings.connect('changed::' + KEY_GTK_THEME, function() {
let value = settings.get_string(KEY_GTK_THEME);
if (value == HIGH_CONTRAST_THEME) {
highContrast.setToggleState(true);
} else {
@ -138,16 +130,11 @@ const ATIndicator = new Lang.Class({
gtkTheme = value;
}
});
interfaceSettings.connect('changed::' + KEY_ICON_THEME, function() {
let value = interfaceSettings.get_string(KEY_ICON_THEME);
settings.connect('changed::' + KEY_ICON_THEME, function() {
let value = settings.get_string(KEY_ICON_THEME);
if (value != HIGH_CONTRAST_THEME)
iconTheme = value;
});
wmSettings.connect('changed::' + KEY_WM_THEME, function() {
let value = wmSettings.get_string(KEY_WM_THEME);
if (value != HIGH_CONTRAST_THEME)
wmTheme = value;
});
return highContrast;
},
@ -172,5 +159,9 @@ const ATIndicator = new Lang.Class({
widget.setToggleState(active);
});
return widget;
}
},
toggleHighContrast: function() {
this._highContrast.toggle();
},
});

View File

@ -80,7 +80,7 @@ const Indicator = new Lang.Class({
this._applet.connect('notify::show-full-menu', Lang.bind(this, this._updateFullMenu));
this._updateFullMenu();
this.menu.addSettingsAction(_("Bluetooth Settings"), 'gnome-bluetooth-panel.desktop');
this.menu.addSettingsAction(_("Bluetooth Settings"), 'bluetooth-properties.desktop');
this._applet.connect('pincode-request', Lang.bind(this, this._pinRequest));
this._applet.connect('confirm-request', Lang.bind(this, this._confirmRequest));
@ -239,6 +239,22 @@ const Indicator = new Lang.Class({
this._applet.send_to_address(device.bdaddr, device.alias);
}));
}
if (device.capabilities & GnomeBluetoothApplet.Capabilities.OBEX_FILE_TRANSFER) {
item.menu.addAction(_("Browse Files..."), Lang.bind(this, function(event) {
this._applet.browse_address(device.bdaddr, event.get_time(),
Lang.bind(this, function(applet, result) {
try {
applet.browse_address_finish(result);
} catch (e) {
this._ensureSource();
this._source.notify(new MessageTray.Notification(this._source,
_("Bluetooth"),
_("Error browsing device"),
{ body: _("The requested device cannot be browsed, error is '%s'").format(e) }));
}
}));
}));
}
switch (device.type) {
case GnomeBluetoothApplet.Type.KEYBOARD:
@ -353,7 +369,6 @@ const ConfirmNotification = new Lang.Class({
_init: function(source, applet, device_path, name, long_name, pin) {
this.parent(source,
_("Bluetooth"),
/* Translators: argument is the device short name */
_("Pairing confirmation for %s").format(name),
{ customContent: true });
this.setResident(true);
@ -363,7 +378,6 @@ const ConfirmNotification = new Lang.Class({
this.addBody(_("Device %s wants to pair with this computer").format(long_name));
this.addBody(_("Please confirm whether the PIN '%06d' matches the one on the device.").format(pin));
/* Translators: this is the verb, not the noun */
this.addButton('matches', _("Matches"));
this.addButton('does-not-match', _("Does not match"));
@ -446,5 +460,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);
}
});

View File

@ -1,11 +1,9 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
const Clutter = imports.gi.Clutter;
const Gio = imports.gi.Gio;
const GLib = imports.gi.GLib;
const GnomeDesktop = imports.gi.GnomeDesktop;
const Lang = imports.lang;
const Meta = imports.gi.Meta;
const Shell = imports.gi.Shell;
const Signals = imports.signals;
const St = imports.gi.St;
@ -23,7 +21,6 @@ try {
const Main = imports.ui.main;
const PopupMenu = imports.ui.popupMenu;
const PanelMenu = imports.ui.panelMenu;
const SwitcherPopup = imports.ui.switcherPopup;
const Util = imports.misc.util;
const DESKTOP_INPUT_SOURCES_SCHEMA = 'org.gnome.desktop.input-sources';
@ -50,7 +47,6 @@ const IBusManager = new Lang.Class({
this._engines = {};
this._ready = false;
this._registerPropertiesId = 0;
this._currentEngineName = null;
this._nameWatcherId = Gio.DBus.session.watch_name(IBus.SERVICE_IBUS,
Gio.BusNameWatcherFlags.NONE,
@ -70,10 +66,6 @@ const IBusManager = new Lang.Class({
this._engines = {};
this._ready = false;
this._registerPropertiesId = 0;
this._currentEngineName = null;
if (this._readyCallback)
this._readyCallback(false);
},
_onNameAppeared: function() {
@ -97,10 +89,12 @@ const IBusManager = new Lang.Class({
let name = enginesList[i].get_name();
this._engines[name] = enginesList[i];
}
this._updateReadiness();
} else {
this._clear();
return;
}
this._updateReadiness();
},
_initPanelService: function(ibus, result) {
@ -111,31 +105,27 @@ const IBusManager = new Lang.Class({
this._candidatePopup.setPanelService(this._panelService);
// Need to set this to get 'global-engine-changed' emitions
this._ibus.set_watch_ibus_signal(true);
this._ibus.connect('global-engine-changed', Lang.bind(this, this._engineChanged));
this._ibus.connect('global-engine-changed', Lang.bind(this, this._resetProperties));
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 = this._ibus.get_global_engine_async_finish(result);
if (!engine)
return;
this._engineChanged(this._ibus, engine.get_name());
}));
this._updateReadiness();
this._resetProperties();
} else {
this._clear();
return;
}
this._updateReadiness();
},
_updateReadiness: function() {
this._ready = (Object.keys(this._engines).length > 0 &&
this._panelService != null);
if (this._readyCallback)
this._readyCallback(this._ready);
if (this._ready && this._readyCallback)
this._readyCallback();
},
_engineChanged: function(bus, engineName) {
this._currentEngineName = engineName;
_resetProperties: function() {
this.emit('properties-registered', null);
if (this._registerPropertiesId != 0)
return;
@ -148,18 +138,25 @@ const IBusManager = new Lang.Class({
this._panelService.disconnect(this._registerPropertiesId);
this._registerPropertiesId = 0;
this.emit('properties-registered', this._currentEngineName, props);
this.emit('properties-registered', props);
}));
},
_updateProperty: function(panel, prop) {
this.emit('property-updated', this._currentEngineName, prop);
this.emit('property-updated', prop);
},
activateProperty: function(key, state) {
this._panelService.property_activate(key, state);
},
hasProperties: function(id) {
if (id == 'anthy')
return true;
return false;
},
getEngineDesc: function(id) {
if (!IBus || !this._ready)
return null;
@ -184,127 +181,16 @@ const LayoutMenuItem = new Lang.Class({
}
});
const InputSource = new Lang.Class({
Name: 'InputSource',
_init: function(type, id, displayName, shortName, index) {
this.type = type;
this.id = id;
this.displayName = displayName;
this._shortName = shortName;
this.index = index;
this._menuItem = new LayoutMenuItem(this.displayName, this._shortName);
this._menuItem.connect('activate', Lang.bind(this, this.activate));
this._indicatorLabel = new St.Label({ text: this._shortName });
this.properties = null;
},
destroy: function() {
this._menuItem.destroy();
this._indicatorLabel.destroy();
},
get shortName() {
return this._shortName;
},
set shortName(v) {
this._shortName = v;
this._menuItem.indicator.set_text(v);
this._indicatorLabel.set_text(v);
},
get menuItem() {
return this._menuItem;
},
get indicatorLabel() {
return this._indicatorLabel;
},
activate: function() {
this.emit('activate');
},
});
Signals.addSignalMethods(InputSource.prototype);
const InputSourcePopup = new Lang.Class({
Name: 'InputSourcePopup',
Extends: SwitcherPopup.SwitcherPopup,
_init: function(items, action, actionBackward) {
this.parent(items);
this._action = action;
this._actionBackward = actionBackward;
},
_createSwitcher: function() {
this._switcherList = new InputSourceSwitcher(this._items);
return true;
},
_initialSelection: function(backward, binding) {
if (binding == 'switch-input-source') {
if (backward)
this._selectedIndex = this._items.length - 1;
} else if (binding == 'switch-input-source-backward') {
if (!backward)
this._selectedIndex = this._items.length - 1;
}
this._select(this._selectedIndex);
},
_keyPressHandler: function(keysym, backwards, action) {
if (action == this._action)
this._select(backwards ? this._previous() : this._next());
else if (action == this._actionBackward)
this._select(backwards ? this._next() : this._previous());
else if (keysym == Clutter.Left)
this._select(this._previous());
else if (keysym == Clutter.Right)
this._select(this._next());
},
_finish : function() {
this.parent();
this._items[this._selectedIndex].activate();
},
});
const InputSourceSwitcher = new Lang.Class({
Name: 'InputSourceSwitcher',
Extends: SwitcherPopup.SwitcherList,
_init: function(items) {
this.parent(true);
for (let i = 0; i < items.length; i++)
this._addIcon(items[i]);
},
_addIcon: function(item) {
let box = new St.BoxLayout({ vertical: true });
let bin = new St.Bin({ style_class: 'input-source-switcher-symbol' });
let symbol = new St.Label({ text: item.shortName });
bin.set_child(symbol);
box.add(bin, { x_fill: false, y_fill: false } );
let text = new St.Label({ text: item.displayName });
box.add(text, { x_fill: false });
this.addItem(box, text);
}
});
const InputSourceIndicator = new Lang.Class({
Name: 'InputSourceIndicator',
Extends: PanelMenu.Button,
_propertiesWhitelist: [
'InputMode',
'TypingMode',
'DictMode'
],
_init: function() {
this.parent(0.0, _("Keyboard"));
@ -315,36 +201,14 @@ const InputSourceIndicator = new Lang.Class({
this.actor.add_actor(this._container);
this.actor.add_style_class_name('panel-status-button');
// All valid input sources currently in the gsettings
// KEY_INPUT_SOURCES list indexed by their index there
this._inputSources = {};
// All valid input sources currently in the gsettings
// KEY_INPUT_SOURCES list of type INPUT_SOURCE_TYPE_IBUS
// indexed by the IBus ID
this._ibusSources = {};
this._labelActors = {};
this._layoutItems = {};
this._currentSource = null;
// All valid input sources currently in the gsettings
// KEY_INPUT_SOURCES list ordered by most recently used
this._mruSources = [];
this._keybindingAction =
Main.wm.addKeybinding('switch-input-source',
new Gio.Settings({ schema: "org.gnome.desktop.wm.keybindings" }),
Meta.KeyBindingFlags.REVERSES,
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,
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));
this._settings.connect('changed::' + KEY_INPUT_SOURCES, Lang.bind(this, this._inputSourcesChanged));
this._currentSourceIndex = this._settings.get_uint(KEY_CURRENT_INPUT_SOURCE);
this._xkbInfo = new GnomeDesktop.XkbInfo();
this._propSeparator = new PopupMenu.PopupSeparatorMenuItem();
@ -353,8 +217,9 @@ const InputSourceIndicator = new Lang.Class({
this.menu.addMenuItem(this._propSection);
this._propSection.actor.hide();
this._ibusReady = false;
this._ibusManager = new IBusManager(Lang.bind(this, this._ibusReadyCallback));
this._properties = null;
this._ibusManager = new IBusManager(Lang.bind(this, this._inputSourcesChanged));
this._ibusManager.connect('properties-registered', Lang.bind(this, this._ibusPropertiesRegistered));
this._ibusManager.connect('property-updated', Lang.bind(this, this._ibusPropertyUpdated));
this._inputSourcesChanged();
@ -366,13 +231,6 @@ const InputSourceIndicator = new Lang.Class({
this._sessionUpdated();
this.menu.addSettingsAction(_("Region and 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();
},
_sessionUpdated: function() {
@ -383,29 +241,18 @@ const InputSourceIndicator = new Lang.Class({
this._showLayoutItem.actor.visible = Main.sessionMode.allowSettings;
},
_ibusReadyCallback: function(ready) {
if (this._ibusReady == ready)
return;
this._ibusReady = ready;
this._mruSources = [];
this._inputSourcesChanged();
},
_switchInputSource: function(display, screen, window, binding) {
let popup = new InputSourcePopup(this._mruSources, this._keybindingAction, this._keybindingActionBackward);
let modifiers = binding.get_modifiers();
let backwards = modifiers & Meta.VirtualModifier.SHIFT_MASK;
if (!popup.show(backwards, binding.get_name(), binding.get_mask()))
popup.destroy();
},
_currentInputSourceChanged: function() {
let nVisibleSources = Object.keys(this._inputSources).length;
let newSourceIndex = this._settings.get_uint(KEY_CURRENT_INPUT_SOURCE);
let newSource = this._inputSources[newSourceIndex];
let nVisibleSources = Object.keys(this._layoutItems).length;
let newCurrentSourceIndex = this._settings.get_uint(KEY_CURRENT_INPUT_SOURCE);
let newLayoutItem = this._layoutItems[newCurrentSourceIndex];
let hasProperties;
if (!newSource || (nVisibleSources < 2 && !newSource.properties)) {
if (newLayoutItem)
hasProperties = this._ibusManager.hasProperties(newLayoutItem.ibusEngineId);
else
hasProperties = false;
if (!newLayoutItem || (nVisibleSources < 2 && !hasProperties)) {
// This source index might be invalid if we weren't able
// to build a menu item for it, so we hide ourselves since
// we can't fix it here. *shrug*
@ -419,125 +266,106 @@ const InputSourceIndicator = new Lang.Class({
this.actor.show();
let oldSource;
[oldSource, this._currentSource] = [this._currentSource, newSource];
if (oldSource) {
oldSource.menuItem.setShowDot(false);
this._container.set_skip_paint(oldSource.indicatorLabel, true);
if (this._layoutItems[this._currentSourceIndex]) {
this._layoutItems[this._currentSourceIndex].setShowDot(false);
this._container.set_skip_paint(this._labelActors[this._currentSourceIndex], true);
}
newSource.menuItem.setShowDot(true);
this._container.set_skip_paint(newSource.indicatorLabel, false);
newLayoutItem.setShowDot(true);
this._buildPropSection(newSource.properties);
let newLabelActor = this._labelActors[newCurrentSourceIndex];
this._container.set_skip_paint(newLabelActor, false);
for (let i = 1; i < this._mruSources.length; ++i)
if (this._mruSources[i] == newSource) {
let currentSource = this._mruSources.splice(i, 1);
this._mruSources = currentSource.concat(this._mruSources);
break;
}
if (hasProperties)
newLabelActor.set_text(newLayoutItem.indicator.get_text());
this._changePerWindowSource();
this._currentSourceIndex = newCurrentSourceIndex;
},
_inputSourcesChanged: function() {
let sources = this._settings.get_value(KEY_INPUT_SOURCES);
let nSources = sources.n_children();
for (let i in this._inputSources)
this._inputSources[i].destroy();
for (let i in this._layoutItems)
this._layoutItems[i].destroy();
this._inputSources = {};
this._ibusSources = {};
for (let i in this._labelActors)
this._labelActors[i].destroy();
let inputSourcesByShortName = {};
this._layoutItems = {};
this._labelActors = {};
let infos = [];
let infosByShortName = {};
for (let i = 0; i < nSources; i++) {
let displayName;
let shortName;
let info = { exists: false };
let [type, id] = sources.get_child_value(i).deep_unpack();
let exists = false;
if (type == INPUT_SOURCE_TYPE_XKB) {
[exists, displayName, shortName, , ] =
[info.exists, info.displayName, info.shortName, , ] =
this._xkbInfo.get_layout_info(id);
} else if (type == INPUT_SOURCE_TYPE_IBUS) {
let engineDesc = this._ibusManager.getEngineDesc(id);
if (engineDesc) {
let language = IBus.get_language_name(engineDesc.get_language());
exists = true;
displayName = language + ' (' + engineDesc.get_longname() + ')';
shortName = this._makeEngineShortName(engineDesc);
info.exists = true;
info.displayName = language + ' (' + engineDesc.get_longname() + ')';
info.shortName = this._makeEngineShortName(engineDesc);
info.ibusEngineId = id;
}
}
if (!exists)
if (!info.exists)
continue;
let is = new InputSource(type, id, displayName, shortName, i);
info.sourceIndex = 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));
}));
if (!(is.shortName in inputSourcesByShortName))
inputSourcesByShortName[is.shortName] = [];
inputSourcesByShortName[is.shortName].push(is);
this._inputSources[is.index] = is;
if (is.type == INPUT_SOURCE_TYPE_IBUS)
this._ibusSources[is.id] = is;
if (!(info.shortName in infosByShortName))
infosByShortName[info.shortName] = [];
infosByShortName[info.shortName].push(info);
infos.push(info);
}
let menuIndex = 0;
for (let i in this._inputSources) {
let is = this._inputSources[i];
if (inputSourcesByShortName[is.shortName].length > 1) {
let sub = inputSourcesByShortName[is.shortName].indexOf(is) + 1;
is.shortName += String.fromCharCode(0x2080 + sub);
for (let i = 0; i < infos.length; i++) {
let info = infos[i];
if (infosByShortName[info.shortName].length > 1) {
let sub = infosByShortName[info.shortName].indexOf(info) + 1;
info.shortName += String.fromCharCode(0x2080 + sub);
}
this.menu.addMenuItem(is.menuItem, menuIndex++);
let item = new LayoutMenuItem(info.displayName, info.shortName);
item.ibusEngineId = info.ibusEngineId;
this._layoutItems[info.sourceIndex] = item;
this.menu.addMenuItem(item, i);
item.connect('activate', Lang.bind(this, function() {
this._settings.set_value(KEY_CURRENT_INPUT_SOURCE,
GLib.Variant.new_uint32(info.sourceIndex));
}));
this._container.add_actor(is.indicatorLabel);
this._container.set_skip_paint(is.indicatorLabel, true);
let shortLabel = new St.Label({ text: info.shortName });
this._labelActors[info.sourceIndex] = shortLabel;
this._container.add_actor(shortLabel);
this._container.set_skip_paint(shortLabel, true);
}
let sourcesList = [];
for (let i in this._inputSources)
sourcesList.push(this._inputSources[i]);
let mruSources = [];
for (let i = 0; i < this._mruSources.length; i++) {
for (let j = 0; j < sourcesList.length; j++)
if (this._mruSources[i].type == sourcesList[j].type &&
this._mruSources[i].id == sourcesList[j].id) {
mruSources = mruSources.concat(sourcesList.splice(j, 1));
break;
}
}
this._mruSources = mruSources.concat(sourcesList);
this._currentInputSourceChanged();
},
_showLayout: function() {
Main.overview.hide();
let source = this._currentSource;
let sources = this._settings.get_value(KEY_INPUT_SOURCES);
let current = this._settings.get_uint(KEY_CURRENT_INPUT_SOURCE);
let [type, id] = sources.get_child_value(current).deep_unpack();
let xkbLayout = '';
let xkbVariant = '';
if (source.type == INPUT_SOURCE_TYPE_XKB) {
[, , , xkbLayout, xkbVariant] = this._xkbInfo.get_layout_info(source.id);
} else if (source.type == INPUT_SOURCE_TYPE_IBUS) {
let engineDesc = this._ibusManager.getEngineDesc(source.id);
if (type == INPUT_SOURCE_TYPE_XKB) {
[, , , xkbLayout, xkbVariant] = this._xkbInfo.get_layout_info(id);
} else if (type == INPUT_SOURCE_TYPE_IBUS) {
let engineDesc = this._ibusManager.getEngineDesc(id);
if (engineDesc) {
xkbLayout = engineDesc.get_layout();
xkbVariant = '';
@ -566,25 +394,26 @@ const InputSourceIndicator = new Lang.Class({
return String.fromCharCode(0x2328); // keyboard glyph
},
_ibusPropertiesRegistered: function(im, engineName, props) {
let source = this._ibusSources[engineName];
if (!source)
return;
source.properties = props;
if (source == this._currentSource)
this._currentInputSourceChanged();
_propertyWhitelisted: function(prop) {
for (let i = 0; i < this._propertiesWhitelist.length; ++i) {
let key = prop.get_key();
if (key.substr(0, this._propertiesWhitelist[i].length) == this._propertiesWhitelist[i])
return true;
}
return false;
},
_ibusPropertyUpdated: function(im, engineName, prop) {
let source = this._ibusSources[engineName];
if (!source)
_ibusPropertiesRegistered: function(im, props) {
this._properties = props;
this._buildPropSection();
},
_ibusPropertyUpdated: function(im, prop) {
if (!this._propertyWhitelisted(prop))
return;
if (this._updateSubProperty(source.properties, prop) &&
source == this._currentSource)
this._currentInputSourceChanged();
if (this._updateSubProperty(this._properties, prop))
this._buildPropSection();
},
_updateSubProperty: function(props, prop) {
@ -604,12 +433,25 @@ const InputSourceIndicator = new Lang.Class({
return false;
},
_buildPropSection: function(properties) {
_updateIndicatorLabel: function(text) {
let layoutItem = this._layoutItems[this._currentSourceIndex];
let hasProperties;
if (layoutItem)
hasProperties = this._ibusManager.hasProperties(layoutItem.ibusEngineId);
else
hasProperties = false;
if (hasProperties)
this._labelActors[this._currentSourceIndex].set_text(text);
},
_buildPropSection: function() {
this._propSeparator.actor.hide();
this._propSection.actor.hide();
this._propSection.removeAll();
this._buildPropSubMenu(this._propSection, properties);
this._buildPropSubMenu(this._propSection, this._properties);
if (!this._propSection.isEmpty()) {
this._propSection.actor.show();
@ -626,7 +468,8 @@ const InputSourceIndicator = new Lang.Class({
for (let i = 0; (p = props.get(i)) != null; ++i) {
let prop = p;
if (!prop.get_visible())
if (!this._propertyWhitelisted(prop) ||
!prop.get_visible())
continue;
if (prop.get_key() == 'InputMode') {
@ -637,17 +480,15 @@ const InputSourceIndicator = new Lang.Class({
text = prop.get_label().get_text();
if (text && text.length > 0 && text.length < 3)
this._currentSource.indicatorLabel.set_text(text);
this._updateIndicatorLabel(text);
}
let item;
switch (prop.get_prop_type()) {
case IBus.PropType.MENU:
let type = prop.get_prop_type();
if (type == IBus.PropType.MENU) {
item = new PopupMenu.PopupSubMenuMenuItem(prop.get_label().get_text());
this._buildPropSubMenu(item.menu, prop.get_sub_props());
break;
case IBus.PropType.RADIO:
} else if (type == IBus.PropType.RADIO) {
item = new PopupMenu.PopupMenuItem(prop.get_label().get_text());
item.prop = prop;
radioGroup.push(item);
@ -672,39 +513,7 @@ const InputSourceIndicator = new Lang.Class({
}
}
}));
break;
case IBus.PropType.TOGGLE:
item = new PopupMenu.PopupSwitchMenuItem(prop.get_label().get_text(), prop.get_state() == IBus.PropState.CHECKED);
item.prop = prop;
item.connect('toggled', Lang.bind(this, function() {
if (item.state) {
item.prop.set_state(IBus.PropState.CHECKED);
this._ibusManager.activateProperty(item.prop.get_key(),
IBus.PropState.CHECKED);
} else {
item.prop.set_state(IBus.PropState.UNCHECKED);
this._ibusManager.activateProperty(item.prop.get_key(),
IBus.PropState.UNCHECKED);
}
}));
break;
case IBus.PropType.NORMAL:
item = new PopupMenu.PopupMenuItem(prop.get_label().get_text());
item.prop = prop;
item.connect('activate', Lang.bind(this, function() {
this._ibusManager.activateProperty(item.prop.get_key(),
IBus.PropState.CHECKED);
}));
break;
case IBus.PropType.SEPARATOR:
item = new PopupMenu.PopupSeparatorMenuItem();
break;
default:
log ('IBus property %s has invalid type %d'.format(prop.get_key(), type));
} else {
continue;
}
@ -713,91 +522,14 @@ 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
// for those we don't actually display.
let max_min_width = 0, max_natural_width = 0;
for (let i in this._inputSources) {
let is = this._inputSources[i];
let [min_width, natural_width] = is.indicatorLabel.get_preferred_width(for_height);
for (let i in this._labelActors) {
let [min_width, natural_width] = this._labelActors[i].get_preferred_width(for_height);
max_min_width = Math.max(max_min_width, min_width);
max_natural_width = Math.max(max_natural_width, natural_width);
}
@ -809,9 +541,8 @@ const InputSourceIndicator = new Lang.Class({
_containerGetPreferredHeight: function(container, for_width, alloc) {
let max_min_height = 0, max_natural_height = 0;
for (let i in this._inputSources) {
let is = this._inputSources[i];
let [min_height, natural_height] = is.indicatorLabel.get_preferred_height(for_width);
for (let i in this._labelActors) {
let [min_height, natural_height] = this._labelActors[i].get_preferred_height(for_width);
max_min_height = Math.max(max_min_height, min_height);
max_natural_height = Math.max(max_natural_height, natural_height);
}
@ -827,9 +558,7 @@ const InputSourceIndicator = new Lang.Class({
box.y2 -= box.y1;
box.y1 = 0;
for (let i in this._inputSources) {
let is = this._inputSources[i];
is.indicatorLabel.allocate_align_fill(box, 0.5, 0, false, false, flags);
}
for (let i in this._labelActors)
this._labelActors[i].allocate_align_fill(box, 0.5, 0, false, false, flags);
}
});

View File

@ -10,53 +10,48 @@ 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,
_init: function() {
this.parent(null, _("Volume, network, battery"));
this._box.style_class = 'lock-screen-status-button-box';
this._volumeControl = VolumeMenu.getMixerControl();
this._volumeMenu = new VolumeMenu.VolumeMenu(this._volumeControl);
this.menu.addMenuItem(this._volumeMenu);
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._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._volumeControl = VolumeMenu.getMixerControl();
this._volumeMenu = new VolumeMenu.VolumeMenu(this._volumeControl);
this.menu.addMenuItem(this._volumeMenu);
}
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);
}
}
});

View File

@ -8,14 +8,6 @@ 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;
@ -147,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,
@ -319,7 +351,7 @@ const NMDevice = new Lang.Class({
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)
@ -480,11 +512,6 @@ const NMDevice = new Lang.Class({
}
},
syncDescription: function() {
if (this.device._description)
this.statusItem.label.text = this.device._description;
},
// protected
_createAutomaticConnection: function() {
throw new TypeError('Invoking pure virtual function NMDevice.createAutomaticConnection');
@ -582,11 +609,7 @@ const NMDevice = new Lang.Class({
this.emit('network-lost');
}
/* Emit a notification if activation fails, but don't do it
if the reason is no secrets, as that indicates the user
cancelled the agent dialog */
if (newstate == NetworkManager.DeviceState.FAILED &&
reason != NetworkManager.DeviceStateReason.NO_SECRETS) {
if (newstate == NetworkManager.DeviceState.FAILED) {
this.emit('activation-failed', reason);
}
@ -616,14 +639,34 @@ 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;
}
});
const NMDeviceSimple = new Lang.Class({
Name: 'NMDeviceSimple',
const NMDeviceWired = new Lang.Class({
Name: 'NMDeviceWired',
Extends: NMDevice,
_init: function(client, device, connections) {
this._autoConnectionName = _("Auto Ethernet");
this.category = NMConnectionCategory.WIRED;
this.parent(client, device, connections);
@ -638,19 +681,6 @@ const NMDeviceSimple = new Lang.Class({
// we can do it here because addConnection and removeConnection
// both call _createSection at some point
this.section.actor.visible = this._connections.length > 1;
}
});
const NMDeviceWired = new Lang.Class({
Name: 'NMDeviceWired',
Extends: NMDeviceSimple,
_init: function(client, device, connections) {
device._description = _("Wired");
this._autoConnectionName = _("Auto Ethernet");
this.category = NMConnectionCategory.WIRED;
this.parent(client, device, connections);
},
_createAutomaticConnection: function() {
@ -674,7 +704,6 @@ 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';
@ -793,7 +822,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));
@ -839,6 +867,10 @@ const NMDeviceBluetooth = new Lang.Class({
this._clearSection();
this._queueCreateSection();
this._updateStatusItem();
},
_getDescription: function() {
return this.device.name || _("Bluetooth");
}
});
@ -1566,8 +1598,7 @@ const NMVPNSection = new Lang.Class({
},
_connectionStateChanged: function(vpnConnection, newstate, reason) {
if (newstate == NetworkManager.VPNConnectionState.FAILED &&
reason != NetworkManager.VPNConnectionStateReason.NO_SECRETS) {
if (newstate == NetworkManager.VPNConnectionState.FAILED) {
// FIXME: if we ever want to show something based on reason,
// we need to convert from NetworkManager.VPNConnectionStateReason
// to NetworkManager.DeviceStateReason
@ -1620,14 +1651,15 @@ const NMApplet = new Lang.Class({
this._mobileUpdateId = 0;
this._mobileUpdateDevice = null;
this._nmDevices = [];
this._devices = { };
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());
@ -1635,7 +1667,7 @@ const NMApplet = new Lang.Class({
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();
@ -1645,7 +1677,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());
@ -1662,7 +1696,6 @@ const NMApplet = new Lang.Class({
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
@ -1674,7 +1707,6 @@ const NMApplet = new Lang.Class({
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);
@ -1730,23 +1762,16 @@ const NMApplet = new Lang.Class({
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();
item.updateForDevice(dev);
} else {
devices.forEach(function(dev) {
dev.statusItem.actor.show();
});
// remove status text from the section title item
item.updateForDevice(null);
}
if (devices.length == 1) {
let dev = devices[0];
dev.statusItem.actor.hide();
item.updateForDevice(dev);
} else {
devices.forEach(function(dev) {
dev.statusItem.actor.show();
});
// remove status text from the section title item
item.updateForDevice(null);
}
}
},
@ -1754,9 +1779,8 @@ const NMApplet = new Lang.Class({
_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) {
@ -1804,23 +1828,7 @@ const NMApplet = new Lang.Class({
return wrapper;
},
_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];
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) {
_deviceAdded: function(client, device) {
if (device._delegate) {
// already seen, not adding again
return;
@ -1831,14 +1839,10 @@ const NMApplet = new Lang.Class({
let section = this._devices[wrapper.category].section;
let devices = this._devices[wrapper.category].devices;
section.addMenuItem(wrapper.statusItem);
section.addMenuItem(wrapper.section);
section.addMenuItem(wrapper.section, 1);
section.addMenuItem(wrapper.statusItem, 1);
devices.push(wrapper);
this._nmDevices.push(device);
if (!skipSyncDeviceNames)
this._syncDeviceNames();
this._syncSectionTitle(wrapper.category);
}
},
@ -1856,10 +1860,6 @@ const NMApplet = new Lang.Class({
let pos = devices.indexOf(wrapper);
devices.splice(pos, 1);
pos = this._nmDevices.indexOf(device);
this._nmDevices.splice(pos, 1);
this._syncDeviceNames();
this._syncSectionTitle(wrapper.category)
},

View File

@ -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 = {
@ -61,7 +61,7 @@ const Indicator = new Lang.Class({
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);
@ -183,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;

View File

@ -2,10 +2,8 @@
const Clutter = imports.gi.Clutter;
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,187 +25,143 @@ function getMixerControl() {
return _mixerControl;
}
const StreamSlider = new Lang.Class({
Name: 'StreamSlider',
const VolumeMenu = new Lang.Class({
Name: 'VolumeMenu',
Extends: PopupMenu.PopupMenuSection,
_init: function(control) {
this.parent();
_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');
},
_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
let port = sink.get_port();
if (port)
return 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('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._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();
},
_connectStream: function(stream) {
this.parent(stream);
this._maybeShowInput();
toggleMute: function(quiet) {
let muted = this._output.is_muted;
this._output.change_is_muted(!muted);
if (muted && !quiet)
this._notifyVolumeChange();
if (!muted)
return ['audio-volume-muted-symbolic', 0];
else
return [this._volumeToIcon(this._output.volume),
this._output.volume / this._volumeMax];
},
scroll: function(direction, quiet) {
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();
}
if (!quiet)
this._notifyVolumeChange();
if (this._output.is_muted)
return ['audio-volume-muted-symbolic', 0];
else
return [this._volumeToIcon(this._output.volume),
this._output.volume / this._volumeMax];
},
_onControlStateChanged: function() {
if (this._control.get_state() == Gvc.MixerControlState.READY) {
this._readOutput();
this._readInput();
this._maybeShowInput();
} else {
this.emit('icon-changed', null);
}
},
_readOutput: function() {
if (this._outputVolumeId) {
this._output.disconnect(this._outputVolumeId);
this._output.disconnect(this._outputMutedId);
this._outputVolumeId = 0;
this._outputMutedId = 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._mutedChanged (null, null, '_output');
this._volumeChanged (null, null, '_output');
} else {
this._outputSlider.setValue(0);
this.emit('icon-changed', 'audio-volume-muted-symbolic');
}
},
_readInput: function() {
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();
}
},
_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) {
if (this._input && recordingApps) {
for (let i = 0; i < recordingApps.length; i++) {
let outputStream = recordingApps[i];
let id = outputStream.get_application_id();
@ -220,70 +174,63 @@ const InputStreamSlider = new Lang.Class({
}
}
this._showInput = showInput;
this._updateVisibility();
this._inputTitle.actor.visible = showInput;
this._inputSlider.actor.visible = showInput;
},
_shouldBeVisible: function() {
return this.parent() && this._showInput;
}
});
const VolumeMenu = new Lang.Class({
Name: 'VolumeMenu',
Extends: PopupMenu.PopupMenuSection,
_init: function(control) {
this.parent();
this.hasHeadphones = false;
this._control = control;
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));
/* 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.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
this._onControlStateChanged();
},
scroll: function(event) {
this._output.scroll(event);
},
_onControlStateChanged: function() {
if (this._control.get_state() == Gvc.MixerControlState.READY) {
this._readInput();
this._readOutput();
_volumeToIcon: function(volume) {
if (volume <= 0) {
return 'audio-volume-muted-symbolic';
} else {
this.emit('icon-changed');
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';
}
},
_readOutput: function() {
this._output.stream = this._control.get_default_sink();
_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();
},
_readInput: function() {
this._input.stream = this._control.get_default_source();
_notifyVolumeChange: function() {
global.cancel_theme_sound(VOLUME_NOTIFY_ID);
global.play_theme_sound(VOLUME_NOTIFY_ID, 'audio-volume-change');
},
getIcon: function() {
return this._output.getIcon();
_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));
}
});
@ -295,20 +242,14 @@ const Indicator = new Lang.Class({
this.parent('audio-volume-muted-symbolic', _("Volume"));
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 = new VolumeMenu(this._control);
this.volumeMenu.connect('icon-changed', Lang.bind(this, function(menu, icon) {
this._hasPulseAudio = (icon != null);
this.setIcon(icon);
}));
this._volumeMenu.connect('headphones-changed', Lang.bind(this, function(menu, value) {
this._headphoneIcon.visible = value;
this._syncVisibility();
}));
this._headphoneIcon = this.addIcon(new Gio.ThemedIcon({ name: 'headphones-symbolic' }));
this._headphoneIcon.visible = false;
this.menu.addMenuItem(this._volumeMenu);
this.menu.addMenuItem(this.volumeMenu);
this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
this.menu.addSettingsAction(_("Sound Settings"), 'gnome-sound-panel.desktop');
@ -316,7 +257,12 @@ 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;
},
_onScrollEvent: function(actor, event) {
this._volumeMenu.scroll(event);
}
this.volumeMenu.scroll(event.get_scroll_direction(), false);
},
});

View File

@ -1,642 +0,0 @@
// -*- 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 Mainloop = imports.mainloop;
const Meta = imports.gi.Meta;
const Shell = imports.gi.Shell;
const Signals = imports.signals;
const St = imports.gi.St;
const Main = imports.ui.main;
const Tweener = imports.ui.tweener;
const POPUP_DELAY_TIMEOUT = 150; // milliseconds
const POPUP_SCROLL_TIME = 0.10; // seconds
const POPUP_FADE_OUT_TIME = 0.1; // seconds
const DISABLE_HOVER_TIMEOUT = 500; // milliseconds
function mod(a, b) {
return (a + b) % b;
}
function primaryModifier(mask) {
if (mask == 0)
return 0;
let primary = 1;
while (mask > 1) {
mask >>= 1;
primary <<= 1;
}
return primary;
}
const SwitcherPopup = new Lang.Class({
Name: 'SwitcherPopup',
Abstract: true,
_init: function(items) {
this._switcherList = null;
this._items = items || [];
this._selectedIndex = 0;
this.actor = new Shell.GenericContainer({ style_class: 'switcher-popup',
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));
this.actor.connect('destroy', Lang.bind(this, this._onDestroy));
Main.uiGroup.add_actor(this.actor);
this._haveModal = false;
this._modifierMask = 0;
this._motionTimeoutId = 0;
this._initialDelayTimeoutId = 0;
// Initially disable hover so we ignore the enter-event if
// the switcher appears underneath the current pointer location
this._disableHover();
},
_getPreferredWidth: function(actor, forHeight, alloc) {
let primary = Main.layoutManager.primaryMonitor;
alloc.min_size = primary.width;
alloc.natural_size = primary.width;
},
_getPreferredHeight: function(actor, forWidth, alloc) {
let primary = Main.layoutManager.primaryMonitor;
alloc.min_size = primary.height;
alloc.natural_size = primary.height;
},
_allocate: function(actor, box, flags) {
let childBox = new Clutter.ActorBox();
let primary = Main.layoutManager.primaryMonitor;
let leftPadding = this.actor.get_theme_node().get_padding(St.Side.LEFT);
let rightPadding = this.actor.get_theme_node().get_padding(St.Side.RIGHT);
let bottomPadding = this.actor.get_theme_node().get_padding(St.Side.BOTTOM);
let vPadding = this.actor.get_theme_node().get_vertical_padding();
let hPadding = leftPadding + rightPadding;
// Allocate the switcherList
// We select a size based on an icon size that does not overflow the screen
let [childMinHeight, childNaturalHeight] = this._switcherList.actor.get_preferred_height(primary.width - hPadding);
let [childMinWidth, childNaturalWidth] = this._switcherList.actor.get_preferred_width(childNaturalHeight);
childBox.x1 = Math.max(primary.x + leftPadding, primary.x + Math.floor((primary.width - childNaturalWidth) / 2));
childBox.x2 = Math.min(primary.x + primary.width - rightPadding, childBox.x1 + childNaturalWidth);
childBox.y1 = primary.y + Math.floor((primary.height - childNaturalHeight) / 2);
childBox.y2 = childBox.y1 + childNaturalHeight;
this._switcherList.actor.allocate(childBox, flags);
},
_createSwitcher: function() {
throw new Error('Not implemented');
},
_initialSelection: function(backward, binding) {
throw new Error('Not implemented');
},
show: function(backward, binding, mask) {
if (!this._createSwitcher())
return false;
if (!Main.pushModal(this.actor)) {
// Probably someone else has a pointer grab, try again with keyboard only
if (!Main.pushModal(this.actor, { options: Meta.ModalOptions.POINTER_ALREADY_GRABBED })) {
return false;
}
}
this._haveModal = true;
this._modifierMask = primaryModifier(mask);
this.actor.connect('key-press-event', Lang.bind(this, this._keyPressEvent));
this.actor.connect('key-release-event', Lang.bind(this, this._keyReleaseEvent));
this.actor.connect('button-press-event', Lang.bind(this, this._clickedOutside));
this.actor.connect('scroll-event', Lang.bind(this, this._scrollEvent));
this.actor.add_actor(this._switcherList.actor);
this._switcherList.connect('item-activated', Lang.bind(this, this._itemActivated));
this._switcherList.connect('item-entered', Lang.bind(this, this._itemEntered));
// Need to force an allocation so we can figure out whether we
// need to scroll when selecting
this.actor.opacity = 0;
this.actor.show();
this.actor.get_allocation_box();
if (this._items.length > 1)
this._selectedIndex = 1;
else
this._selectedIndex = 0;
this._initialSelection(backward, binding);
// There's a race condition; if the user released Alt before
// we got the grab, then we won't be notified. (See
// https://bugzilla.gnome.org/show_bug.cgi?id=596695 for
// details.) So we check now. (Have to do this after updating
// selection.)
let [x, y, mods] = global.get_pointer();
if (!(mods & this._modifierMask)) {
this._finish(global.get_current_time());
return false;
}
// We delay showing the popup so that fast Alt+Tab users aren't
// disturbed by the popup briefly flashing.
this._initialDelayTimeoutId = Mainloop.timeout_add(POPUP_DELAY_TIMEOUT,
Lang.bind(this, function () {
this.actor.opacity = 255;
this._initialDelayTimeoutId = 0;
}));
return true;
},
_next: function() {
return mod(this._selectedIndex + 1, this._items.length);
},
_previous: function() {
return mod(this._selectedIndex - 1, this._items.length);
},
_keyPressHandler: function(keysym, backwards, action) {
throw new Error('Not implemented');
},
_keyPressEvent: function(actor, event) {
let keysym = event.get_key_symbol();
let event_state = event.get_state();
let backwards = event_state & Clutter.ModifierType.SHIFT_MASK;
let action = global.display.get_keybinding_action(event.get_key_code(), event_state);
this._disableHover();
if (keysym == Clutter.Escape)
this.destroy();
else
this._keyPressHandler(keysym, backwards, action);
return true;
},
_keyReleaseEvent: function(actor, event) {
let [x, y, mods] = global.get_pointer();
let state = mods & this._modifierMask;
if (state == 0)
this._finish(event.get_time());
return true;
},
_clickedOutside: function(actor, event) {
this.destroy();
},
_scrollHandler: function(direction) {
if (direction == Clutter.ScrollDirection.UP)
this._select(this._previous());
else if (direction == Clutter.ScrollDirection.DOWN)
this._select(this._next());
},
_scrollEvent: function(actor, event) {
this._scrollHandler(event.get_scroll_direction());
},
_itemActivatedHandler: function(n) {
this._select(n);
},
_itemActivated: function(switcher, n) {
this._itemActivatedHandler(n);
this._finish(global.get_current_time());
},
_itemEnteredHandler: function(n) {
this._select(n);
},
_itemEntered: function(switcher, n) {
if (!this.mouseActive)
return;
this._itemEnteredHandler(n);
},
_disableHover: function() {
this.mouseActive = false;
if (this._motionTimeoutId != 0)
Mainloop.source_remove(this._motionTimeoutId);
this._motionTimeoutId = Mainloop.timeout_add(DISABLE_HOVER_TIMEOUT, Lang.bind(this, this._mouseTimedOut));
},
_mouseTimedOut: function() {
this._motionTimeoutId = 0;
this.mouseActive = true;
},
_popModal: function() {
if (this._haveModal) {
Main.popModal(this.actor);
this._haveModal = false;
}
},
destroy: function() {
this._popModal();
if (this.actor.visible) {
Tweener.addTween(this.actor,
{ opacity: 0,
time: POPUP_FADE_OUT_TIME,
transition: 'easeOutQuad',
onComplete: Lang.bind(this,
function() {
this.actor.destroy();
})
});
} else
this.actor.destroy();
},
_finish: function(timestamp) {
this.destroy();
},
_onDestroy: function() {
this._popModal();
if (this._motionTimeoutId != 0)
Mainloop.source_remove(this._motionTimeoutId);
if (this._initialDelayTimeoutId != 0)
Mainloop.source_remove(this._initialDelayTimeoutId);
},
_select: function(num) {
this._selectedIndex = num;
this._switcherList.highlight(num);
}
});
const SwitcherList = new Lang.Class({
Name: 'SwitcherList',
_init : function(squareItems) {
this.actor = new Shell.GenericContainer({ style_class: 'switcher-list' });
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._allocateTop));
// Here we use a GenericContainer so that we can force all the
// 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() {
this._list.spacing = this._list.get_theme_node().get_length('spacing');
}));
this._list.connect('get-preferred-width', Lang.bind(this, this._getPreferredWidth));
this._list.connect('get-preferred-height', Lang.bind(this, this._getPreferredHeight));
this._list.connect('allocate', Lang.bind(this, this._allocate));
this._scrollView = new St.ScrollView({ style_class: 'hfade',
enable_mouse_scrolling: false });
this._scrollView.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.NEVER);
let scrollBox = new St.BoxLayout();
scrollBox.add_actor(this._list);
this._scrollView.add_actor(scrollBox);
this.actor.add_actor(this._scrollView);
// Those arrows indicate whether scrolling in one direction is possible
this._leftArrow = new St.DrawingArea({ style_class: 'switcher-arrow',
pseudo_class: 'highlighted' });
this._leftArrow.connect('repaint', Lang.bind(this,
function() { drawArrow(this._leftArrow, St.Side.LEFT); }));
this._rightArrow = new St.DrawingArea({ style_class: 'switcher-arrow',
pseudo_class: 'highlighted' });
this._rightArrow.connect('repaint', Lang.bind(this,
function() { drawArrow(this._rightArrow, St.Side.RIGHT); }));
this.actor.add_actor(this._leftArrow);
this.actor.add_actor(this._rightArrow);
this._items = [];
this._highlighted = -1;
this._separator = null;
this._squareItems = squareItems;
this._minSize = 0;
this._scrollableRight = true;
this._scrollableLeft = false;
},
_allocateTop: function(actor, box, flags) {
let leftPadding = this.actor.get_theme_node().get_padding(St.Side.LEFT);
let rightPadding = this.actor.get_theme_node().get_padding(St.Side.RIGHT);
let childBox = new Clutter.ActorBox();
let scrollable = this._minSize > box.x2 - box.x1;
box.y1 -= this.actor.get_theme_node().get_padding(St.Side.TOP);
box.y2 += this.actor.get_theme_node().get_padding(St.Side.BOTTOM);
this._scrollView.allocate(box, flags);
let arrowWidth = Math.floor(leftPadding / 3);
let arrowHeight = arrowWidth * 2;
childBox.x1 = leftPadding / 2;
childBox.y1 = this.actor.height / 2 - arrowWidth;
childBox.x2 = childBox.x1 + arrowWidth;
childBox.y2 = childBox.y1 + arrowHeight;
this._leftArrow.allocate(childBox, flags);
this._leftArrow.opacity = (this._scrollableLeft && scrollable) ? 255 : 0;
arrowWidth = Math.floor(rightPadding / 3);
arrowHeight = arrowWidth * 2;
childBox.x1 = this.actor.width - arrowWidth - rightPadding / 2;
childBox.y1 = this.actor.height / 2 - arrowWidth;
childBox.x2 = childBox.x1 + arrowWidth;
childBox.y2 = childBox.y1 + arrowHeight;
this._rightArrow.allocate(childBox, flags);
this._rightArrow.opacity = (this._scrollableRight && scrollable) ? 255 : 0;
},
addItem : function(item, label) {
let bbox = new St.Button({ style_class: 'item-box',
reactive: true });
bbox.set_child(item);
this._list.add_actor(bbox);
let n = this._items.length;
bbox.connect('clicked', Lang.bind(this, function() { this._onItemClicked(n); }));
bbox.connect('enter-event', Lang.bind(this, function() { this._onItemEnter(n); }));
bbox.label_actor = label;
this._items.push(bbox);
return bbox;
},
_onItemClicked: function (index) {
this._itemActivated(index);
},
_onItemEnter: function (index) {
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');
this._items[this._highlighted].remove_style_pseudo_class('selected');
}
this._highlighted = index;
if (this._highlighted != -1) {
if (justOutline)
this._items[this._highlighted].add_style_pseudo_class('outlined');
else
this._items[this._highlighted].add_style_pseudo_class('selected');
}
let adjustment = this._scrollView.hscroll.adjustment;
let [value, lower, upper, stepIncrement, pageIncrement, pageSize] = adjustment.get_values();
let [absItemX, absItemY] = this._items[index].get_transformed_position();
let [result, posX, posY] = this.actor.transform_stage_point(absItemX, 0);
let [containerWidth, containerHeight] = this.actor.get_transformed_size();
if (posX + this._items[index].get_width() > containerWidth)
this._scrollToRight();
else if (this._items[index].allocation.x1 - value < 0)
this._scrollToLeft();
},
_scrollToLeft : function() {
let adjustment = this._scrollView.hscroll.adjustment;
let [value, lower, upper, stepIncrement, pageIncrement, pageSize] = adjustment.get_values();
let item = this._items[this._highlighted];
if (item.allocation.x1 < value)
value = Math.min(0, item.allocation.x1);
else if (item.allocation.x2 > value + pageSize)
value = Math.max(upper, item.allocation.x2 - pageSize);
this._scrollableRight = true;
Tweener.addTween(adjustment,
{ value: value,
time: POPUP_SCROLL_TIME,
transition: 'easeOutQuad',
onComplete: Lang.bind(this, function () {
if (this._highlighted == 0) {
this._scrollableLeft = false;
this.actor.queue_relayout();
}
})
});
},
_scrollToRight : function() {
let adjustment = this._scrollView.hscroll.adjustment;
let [value, lower, upper, stepIncrement, pageIncrement, pageSize] = adjustment.get_values();
let item = this._items[this._highlighted];
if (item.allocation.x1 < value)
value = Math.max(0, item.allocation.x1);
else if (item.allocation.x2 > value + pageSize)
value = Math.min(upper, item.allocation.x2 - pageSize);
this._scrollableLeft = true;
Tweener.addTween(adjustment,
{ value: value,
time: POPUP_SCROLL_TIME,
transition: 'easeOutQuad',
onComplete: Lang.bind(this, function () {
if (this._highlighted == this._items.length - 1) {
this._scrollableRight = false;
this.actor.queue_relayout();
}
})
});
},
_itemActivated: function(n) {
this.emit('item-activated', n);
},
_itemEntered: function(n) {
this.emit('item-entered', n);
},
_maxChildWidth: function (forHeight) {
let maxChildMin = 0;
let maxChildNat = 0;
for (let i = 0; i < this._items.length; i++) {
let [childMin, childNat] = this._items[i].get_preferred_width(forHeight);
maxChildMin = Math.max(childMin, maxChildMin);
maxChildNat = Math.max(childNat, maxChildNat);
if (this._squareItems) {
let [childMin, childNat] = this._items[i].get_preferred_height(-1);
maxChildMin = Math.max(childMin, maxChildMin);
maxChildNat = Math.max(childNat, maxChildNat);
}
}
return [maxChildMin, maxChildNat];
},
_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 + separatorWidth + totalSpacing;
alloc.natural_size = alloc.min_size;
this._minSize = alloc.min_size;
},
_getPreferredHeight: function (actor, forWidth, alloc) {
let maxChildMin = 0;
let maxChildNat = 0;
for (let i = 0; i < this._items.length; i++) {
let [childMin, childNat] = this._items[i].get_preferred_height(-1);
maxChildMin = Math.max(childMin, maxChildMin);
maxChildNat = Math.max(childNat, maxChildNat);
}
if (this._squareItems) {
let [childMin, childNat] = this._maxChildWidth(-1);
maxChildMin = Math.max(childMin, maxChildMin);
maxChildNat = maxChildMin;
}
alloc.min_size = maxChildMin;
alloc.natural_size = maxChildNat;
},
_allocate: function (actor, box, flags) {
let childHeight = box.y2 - box.y1;
let [maxChildMin, maxChildNat] = this._maxChildWidth(childHeight);
let totalSpacing = this._list.spacing * (this._items.length - 1);
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();
let childBox = new Clutter.ActorBox();
let primary = Main.layoutManager.primaryMonitor;
let parentRightPadding = this.actor.get_parent().get_theme_node().get_padding(St.Side.RIGHT);
for (let i = 0; i < children.length; i++) {
if (this._items.indexOf(children[i]) != -1) {
let [childMin, childNat] = children[i].get_preferred_height(childWidth);
let vSpacing = (childHeight - childNat) / 2;
childBox.x1 = x;
childBox.y1 = vSpacing;
childBox.x2 = x + childWidth;
childBox.y2 = childBox.y1 + childNat;
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.
}
}
}
});
Signals.addSignalMethods(SwitcherList.prototype);
function drawArrow(area, side) {
let themeNode = area.get_theme_node();
let borderColor = themeNode.get_border_color(side);
let bodyColor = themeNode.get_foreground_color();
let [width, height] = area.get_surface_size ();
let cr = area.get_context();
cr.setLineWidth(1.0);
Clutter.cairo_set_source_color(cr, borderColor);
switch (side) {
case St.Side.TOP:
cr.moveTo(0, height);
cr.lineTo(Math.floor(width * 0.5), 0);
cr.lineTo(width, height);
break;
case St.Side.BOTTOM:
cr.moveTo(width, 0);
cr.lineTo(Math.floor(width * 0.5), height);
cr.lineTo(0, 0);
break;
case St.Side.LEFT:
cr.moveTo(width, height);
cr.lineTo(0, Math.floor(height * 0.5));
cr.lineTo(width, 0);
break;
case St.Side.RIGHT:
cr.moveTo(0, 0);
cr.lineTo(width, Math.floor(height * 0.5));
cr.lineTo(0, height);
break;
}
cr.strokePreserve();
Clutter.cairo_set_source_color(cr, bodyColor);
cr.fill();
cr.$dispose();
}

View File

@ -14,14 +14,12 @@ const St = imports.gi.St;
const Main = imports.ui.main;
const ModalDialog = imports.ui.modalDialog;
const Panel = imports.ui.panel;
const ShellEntry = imports.ui.shellEntry;
const Tweener = imports.ui.tweener;
const UserMenu = imports.ui.userMenu;
const Batch = imports.gdm.batch;
const GdmUtil = imports.gdm.util;
const LoginDialog = imports.gdm.loginDialog;
// The timeout before going back automatically to the lock screen (in seconds)
const IDLE_TIMEOUT = 2 * 60;
@ -115,7 +113,6 @@ const UnlockDialog = new Lang.Class({
_init: function(parentActor) {
this.parent({ shellReactive: true,
styleClass: 'login-dialog',
keybindingMode: Main.KeybindingMode.UNLOCK_SCREEN,
parentActor: parentActor
});
@ -153,6 +150,7 @@ const UnlockDialog = new Lang.Class({
this._promptEntry.clutter_text.set_password_char('\u25cf');
ShellEntry.addContextMenu(this._promptEntry, { isPassword: true });
this.setInitialKeyFocus(this._promptEntry);
this._promptEntry.clutter_text.connect('activate', Lang.bind(this, this._doUnlock));
this._promptEntry.clutter_text.connect('text-changed', Lang.bind(this, function() {
this._updateOkButtonSensitivity(this._promptEntry.text.length > 0);
}));
@ -170,54 +168,29 @@ const UnlockDialog = new Lang.Class({
this._promptLoginHint.hide();
this.contentLayout.add_actor(this._promptLoginHint);
this._workSpinner = new Panel.AnimatedIcon('process-working.svg', LoginDialog.WORK_SPINNER_ICON_SIZE);
this._workSpinner.actor.opacity = 0;
this.allowCancel = false;
this.buttonLayout.visible = true;
this.addButton({ label: _("Cancel"),
action: Lang.bind(this, this._escape),
key: Clutter.KEY_Escape },
{ expand: true,
x_fill: false,
y_fill: false,
x_align: St.Align.START,
y_align: St.Align.MIDDLE });
this.buttonLayout.add(this._workSpinner.actor,
{ expand: false,
x_fill: false,
y_fill: false,
x_align: St.Align.END,
y_align: St.Align.MIDDLE });
this._okButton = this.addButton({ label: _("Unlock"),
action: Lang.bind(this, this._doUnlock),
default: true },
{ expand: false,
x_fill: false,
y_fill: false,
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',
can_focus: true,
child: otherUserLabel,
reactive: true,
x_align: St.Align.START,
x_fill: true });
this._otherUserButton.connect('clicked', Lang.bind(this, this._otherUserClicked));
this.dialogLayout.add(this._otherUserButton,
{ x_align: St.Align.START,
x_fill: false });
} else {
this._otherUserButton = null;
}
let cancelButton = { label: _("Cancel"),
action: Lang.bind(this, this._escape),
key: Clutter.KEY_Escape };
this._okButton = { label: _("Unlock"),
action: Lang.bind(this, this._doUnlock),
default: true };
this.setButtons([cancelButton, this._okButton]);
this._updateSensitivity(true);
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',
can_focus: true,
child: otherUserLabel,
reactive: true,
x_align: St.Align.START,
x_fill: true });
this._otherUserButton.connect('clicked', Lang.bind(this, this._otherUserClicked));
this.dialogLayout.add(this._otherUserButton,
{ x_align: St.Align.START,
x_fill: false });
let batch = new Batch.Hold();
this._userVerifier.begin(this._userName, batch);
@ -226,8 +199,6 @@ const UnlockDialog = new Lang.Class({
return false;
}));
Main.ctrlAltTabManager.addGroup(this.dialogLayout, _("Unlock Window"), 'dialog-password-symbolic');
this._idleMonitor = new GnomeDesktop.IdleMonitor();
this._idleWatchId = this._idleMonitor.add_watch(IDLE_TIMEOUT * 1000, Lang.bind(this, this._escape));
},
@ -236,37 +207,11 @@ const UnlockDialog = new Lang.Class({
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) {
this._okButton.reactive = sensitive;
this._okButton.can_focus = sensitive;
},
_setWorking: function(working) {
if (working) {
this._workSpinner.play();
Tweener.addTween(this._workSpinner.actor,
{ opacity: 255,
delay: LoginDialog.WORK_SPINNER_ANIMATION_DELAY,
time: LoginDialog.WORK_SPINNER_ANIMATION_TIME,
transition: 'linear'
});
} else {
Tweener.addTween(this._workSpinner.actor,
{ opacity: 0,
time: LoginDialog.WORK_SPINNER_ANIMATION_TIME,
transition: 'linear',
onCompleteScope: this,
onComplete: function() {
this._workSpinner.stop();
}
});
}
this._okButton.button.reactive = sensitive;
this._okButton.button.can_focus = sensitive;
},
_showMessage: function(userVerifier, message, styleClass) {
@ -299,7 +244,6 @@ const UnlockDialog = new Lang.Class({
this._currentQuery = serviceName;
this._updateSensitivity(true);
this._setWorking(false);
},
_showLoginHint: function(verifier, message) {
@ -318,7 +262,6 @@ const UnlockDialog = new Lang.Class({
// the actual reply to GDM will be sent as soon as asked
this._firstQuestionAnswer = this._promptEntry.text;
this._updateSensitivity(false);
this._setWorking(true);
return;
}
@ -329,7 +272,6 @@ const UnlockDialog = new Lang.Class({
this._currentQuery = null;
this._updateSensitivity(false);
this._setWorking(true);
this._userVerifier.answerQuery(query, this._promptEntry.text);
},
@ -352,14 +294,11 @@ const UnlockDialog = new Lang.Class({
this._promptEntry.menu.isPassword = true;
this._updateSensitivity(false);
this._setWorking(false);
},
_escape: function() {
if (this.allowCancel) {
this._userVerifier.cancel();
this.emit('failed');
}
this._userVerifier.cancel();
this.emit('failed');
},
_otherUserClicked: function(button, event) {

View File

@ -22,13 +22,11 @@ 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 DIALOG_ICON_SIZE = 64;
@ -478,7 +476,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();
@ -553,12 +550,9 @@ const UserMenuButton = new Lang.Class({
Lang.bind(this, this._updateSwitchUser));
this._lockdownSettings.connect('changed::' + DISABLE_LOG_OUT_KEY,
Lang.bind(this, this._updateLogout));
this._lockdownSettings.connect('changed::' + DISABLE_LOCK_SCREEN_KEY,
Lang.bind(this, this._updateLockScreen));
this._screenSaverSettings.connect('changed::' + SHOW_FULL_NAME_IN_TOP_BAR_KEY,
Lang.bind(this, this._updateUserName));
this._privacySettings.connect('changed::' + SHOW_FULL_NAME_IN_TOP_BAR_KEY,
Lang.bind(this, this._updateUserName));
this._updateSwitchUser();
this._updateLogout();
this._updateLockScreen();
@ -578,6 +572,7 @@ const UserMenuButton = new Lang.Class({
this._updateHaveShutdown();
this._updateHaveSuspend();
this._updateHaveHibernate();
}));
this._lockdownSettings.connect('changed::' + DISABLE_LOG_OUT_KEY,
Lang.bind(this, this._updateHaveShutdown));
@ -595,7 +590,6 @@ const UserMenuButton = new Lang.Class({
this.setSensitive(!Main.sessionMode.isLocked);
this._updatePresenceIcon();
this._updateUserName();
},
_onDestroy: function() {
@ -604,10 +598,7 @@ const UserMenuButton = new Lang.Class({
},
_updateUserName: function() {
let settings = this._privacySettings;
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)
this._name.set_text(this._user.get_real_name());
else
this._name.set_text("");
@ -665,6 +656,13 @@ const UserMenuButton = new Lang.Class({
}));
},
_updateHaveHibernate: function() {
this._loginManager.canHibernate(Lang.bind(this,
function(result) {
this._haveHibernate = result;
}));
},
_updateSuspendOrPowerOff: function() {
if (!this._suspendOrPowerOffItem)
return;
@ -776,7 +774,7 @@ const UserMenuButton = new Lang.Class({
this._loginScreenItem = item;
item = new PopupMenu.PopupMenuItem(_("Log Out"));
item.connect('activate', Lang.bind(this, this._onQuitSessionActivate));
item.connect('activate', Lang.bind(this, this.logOut));
this.menu.addMenuItem(item);
this._logoutItem = item;
@ -845,7 +843,7 @@ const UserMenuButton = new Lang.Class({
Gdm.goto_login_session_sync(null);
},
_onQuitSessionActivate: function() {
logOut: function() {
Main.overview.hide();
this._session.LogoutRemote(0);
},
@ -857,25 +855,60 @@ const UserMenuButton = new Lang.Class({
this._session.RebootRemote();
},
shutdown: function() {
this._session.ShutdownRemote();
},
suspend: function() {
if (!this._haveSuspend)
return false;
// Ensure we only suspend after locking the screen
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();
}
return true;
},
hibernate: function() {
if (!this._haveHibernate)
return false;
// Ensure we only suspend after locking the screen
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.hibernate();
}));
this.menu.close(BoxPointer.PopupAnimation.NONE);
Main.screenShield.lock(true);
} else {
this._loginManager.hibernate();
}
return true;
},
_onSuspendOrPowerOffActivate: function() {
Main.overview.hide();
if (this._haveShutdown &&
this._suspendOrPowerOffItem.state == PopupMenu.PopupAlternatingMenuItemState.DEFAULT) {
this._session.ShutdownRemote();
this.shutdown();
} 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();
}
this.suspend();
}
}
});

View File

@ -39,11 +39,17 @@ const ViewSelector = new Lang.Class({
Name: 'ViewSelector',
_init : function(searchEntry, showAppsButton) {
this.actor = new Shell.Stack({ name: 'viewSelector' });
this.actor = new St.BoxLayout({ name: 'viewSelector',
vertical: true });
this._showAppsButton = showAppsButton;
this._showAppsButton.connect('notify::checked', Lang.bind(this, this._onShowAppsButtonToggled));
this._pageArea = new Shell.Stack();
this.actor.add(this._pageArea, { x_fill: true,
y_fill: true,
expand: true });
this._activePage = null;
this.active = false;
@ -78,21 +84,16 @@ const ViewSelector = new Lang.Class({
this._workspacesDisplay = new WorkspacesView.WorkspacesDisplay();
this._workspacesPage = this._addPage(this._workspacesDisplay.actor, null,
_("Windows"), 'emblem-documents-symbolic');
_("Windows"), 'text-x-generic-symbolic');
this._appDisplay = new AppDisplay.AllAppDisplay();
this._appsPage = this._addPage(this._appDisplay.actor, null,
_("Applications"), 'view-grid-symbolic');
_("Applications"), 'system-run-symbolic');
this._searchResults = new SearchDisplay.SearchResults(this._searchSystem);
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));
this._searchSettings.connect('changed::disable-external', Lang.bind(this, this._reloadRemoteProviders));
this._searchSettings.connect('changed::sort-order', Lang.bind(this, this._reloadRemoteProviders));
// Default search providers
// Wanda comes obviously first
this.addSearchProvider(new Wanda.WandaSearchProvider());
@ -132,17 +133,26 @@ const ViewSelector = new Lang.Class({
}
}));
Main.wm.addKeybinding('toggle-application-view',
new Gio.Settings({ schema: SHELL_KEYBINDINGS_SCHEMA }),
Meta.KeyBindingFlags.NONE,
Main.KeybindingMode.NORMAL |
Main.KeybindingMode.OVERVIEW,
Lang.bind(this, this._toggleAppsPage));
// Public constraints which may be used to tie actors' height or
// vertical position to the current tab's content; as the content's
// height and position depend on the view selector's style properties
// (e.g. font size, padding, spacing, ...) it would be extremely hard
// and ugly to get these from the outside. While it would be possible
// to use position and height properties directly, outside code would
// need to ensure that the content is properly allocated before
// accessing the properties.
this.constrainHeight = new Clutter.BindConstraint({ source: this._pageArea,
coordinate: Clutter.BindCoordinate.HEIGHT });
global.display.add_keybinding('toggle-application-view',
new Gio.Settings({ schema: SHELL_KEYBINDINGS_SCHEMA }),
Meta.KeyBindingFlags.NONE,
Lang.bind(this, this._showWithAppsPage));
},
_toggleAppsPage: function() {
_showWithAppsPage: function() {
Main.overview.show();
this._showAppsButton.checked = !this._showAppsButton.checked;
this._showAppsButton.set_checked(true);
},
show: function() {
@ -185,7 +195,7 @@ const ViewSelector = new Lang.Class({
this._a11yFocusPage(page);
})
});;
this.actor.add_actor(page);
this._pageArea.add_actor(page);
return page;
},
@ -232,11 +242,6 @@ const ViewSelector = new Lang.Class({
},
_onStageKeyPress: function(actor, event) {
// Ignore events while anything but the overview has
// pushed a modal (system modals, looking glass, ...)
if (Main.modalCount > 1)
return false;
let modifiers = event.get_state();
let symbol = event.get_key_symbol();
@ -428,32 +433,7 @@ const ViewSelector = new Lang.Class({
this._showPage(this._searchPage);
},
_shouldUseSearchProvider: function(provider) {
// the disable-external GSetting only affects remote providers
if (!provider.isRemoteProvider)
return true;
if (this._searchSettings.get_boolean('disable-external'))
return false;
let appId = provider.appInfo.get_id();
let disable = this._searchSettings.get_strv('disabled');
return disable.indexOf(appId) == -1;
},
_reloadRemoteProviders: function() {
// removeSearchProvider() modifies the provider list we iterate on,
// so make a copy first
let remoteProviders = this._searchSystem.getRemoteProviders().slice(0);
remoteProviders.forEach(Lang.bind(this, this.removeSearchProvider));
RemoteSearch.loadRemoteSearchProviders(Lang.bind(this, this.addSearchProvider));
},
addSearchProvider: function(provider) {
if (!this._shouldUseSearchProvider(provider))
return;
this._searchSystem.registerProvider(provider);
this._searchResults.createProviderMeta(provider);
},

View File

@ -9,7 +9,7 @@ const St = imports.gi.St;
const IconGrid = imports.ui.iconGrid;
const Layout = imports.ui.layout;
const Main = imports.ui.main;
const Panel = imports.ui.panel;
const Search = imports.ui.search;
// we could make these gsettings
const FISH_NAME = 'wanda';
@ -53,9 +53,20 @@ const WandaIcon = new Lang.Class({
icon_size: iconSize });
}
this._animations = new Panel.Animation(this._imageFile, this._imgWidth, this._imgHeight, FISH_SPEED);
this._animations.play();
return this._animations.actor;
this._animations = St.TextureCache.get_default().load_sliced_image(this._imageFile, this._imgWidth, this._imgHeight);
this._animations.connect('notify::mapped', Lang.bind(this, function() {
if (this._animations.mapped && !this._timeoutId) {
this._timeoutId = GLib.timeout_add(GLib.PRIORITY_DEFAULT, FISH_SPEED, Lang.bind(this, this._update));
this._i = 0;
this._update();
} else if (!this._animations.mapped && this._timeoutId) {
GLib.source_remove(this._timeoutId);
this._timeoutId = 0;
}
}));
return this._animations;
},
_createIconTexture: function(size) {
@ -63,14 +74,28 @@ const WandaIcon = new Lang.Class({
return;
this.parent(size);
}
},
_update: function() {
let n = this._animations.get_n_children();
if (n == 0) {
return true;
}
this._animations.get_child_at_index(this._i).hide();
this._i = (this._i + 1) % n;
this._animations.get_child_at_index(this._i).show();
return true;
},
});
const WandaIconBin = new Lang.Class({
Name: 'WandaIconBin',
_init: function(fish, label, params) {
this.actor = new St.Bin({ reactive: true,
this.actor = new St.Bin({ style_class: 'search-result-content',
reactive: true,
track_hover: true });
this.icon = new WandaIcon(fish, label, params);
@ -131,9 +156,10 @@ function capitalize(str) {
const WandaSearchProvider = new Lang.Class({
Name: 'WandaSearchProvider',
Extends: Search.SearchProvider,
_init: function() {
this.id = 'wanda';
this.parent(_("Your favorite Easter Egg"));
},
getResultMetas: function(fish, callback) {
@ -159,7 +185,7 @@ const WandaSearchProvider = new Lang.Class({
this.getInitialResultSet(terms);
},
activateResult: function(fish) {
activateResult: function(fish, params) {
if (this._dialog)
this._dialog.destroy();
this._dialog = new FortuneDialog(capitalize(fish), FISH_COMMAND);

View File

@ -12,6 +12,7 @@ const AltTab = imports.ui.altTab;
const WorkspaceSwitcherPopup = imports.ui.workspaceSwitcherPopup;
const Main = imports.ui.main;
const Tweener = imports.ui.tweener;
const Util = imports.misc.util;
const SHELL_KEYBINDINGS_SCHEMA = 'org.gnome.shell.keybindings';
const WINDOW_ANIMATION_TIME = 0.25;
@ -83,8 +84,6 @@ const WindowManager = new Lang.Class({
this._animationBlockCount = 0;
this._allowedKeybindings = {};
this._switchData = null;
this._shellwm.connect('kill-switch-workspace', Lang.bind(this, this._switchWorkspaceDone));
this._shellwm.connect('kill-window-effects', Lang.bind(this, function (shellwm, actor) {
@ -101,79 +100,38 @@ const WindowManager = new Lang.Class({
this._shellwm.connect('unmaximize', Lang.bind(this, this._unmaximizeWindow));
this._shellwm.connect('map', Lang.bind(this, this._mapWindow));
this._shellwm.connect('destroy', Lang.bind(this, this._destroyWindow));
this._shellwm.connect('filter-keybinding', Lang.bind(this, this._filterKeybinding));
this._workspaceSwitcherPopup = null;
this.setCustomKeybindingHandler('switch-to-workspace-left',
Main.KeybindingMode.NORMAL |
Main.KeybindingMode.OVERVIEW,
Lang.bind(this, this._showWorkspaceSwitcher));
this.setCustomKeybindingHandler('switch-to-workspace-right',
Main.KeybindingMode.NORMAL |
Main.KeybindingMode.OVERVIEW,
Lang.bind(this, this._showWorkspaceSwitcher));
this.setCustomKeybindingHandler('switch-to-workspace-up',
Main.KeybindingMode.NORMAL |
Main.KeybindingMode.OVERVIEW,
Lang.bind(this, this._showWorkspaceSwitcher));
this.setCustomKeybindingHandler('switch-to-workspace-down',
Main.KeybindingMode.NORMAL |
Main.KeybindingMode.OVERVIEW,
Lang.bind(this, this._showWorkspaceSwitcher));
this.setCustomKeybindingHandler('move-to-workspace-left',
Main.KeybindingMode.NORMAL |
Main.KeybindingMode.OVERVIEW,
Lang.bind(this, this._showWorkspaceSwitcher));
this.setCustomKeybindingHandler('move-to-workspace-right',
Main.KeybindingMode.NORMAL |
Main.KeybindingMode.OVERVIEW,
Lang.bind(this, this._showWorkspaceSwitcher));
this.setCustomKeybindingHandler('move-to-workspace-up',
Main.KeybindingMode.NORMAL |
Main.KeybindingMode.OVERVIEW,
Lang.bind(this, this._showWorkspaceSwitcher));
this.setCustomKeybindingHandler('move-to-workspace-down',
Main.KeybindingMode.NORMAL |
Main.KeybindingMode.OVERVIEW,
Lang.bind(this, this._showWorkspaceSwitcher));
this.setCustomKeybindingHandler('switch-applications',
Main.KeybindingMode.NORMAL,
Lang.bind(this, this._startAppSwitcher));
this.setCustomKeybindingHandler('switch-group',
Main.KeybindingMode.NORMAL,
Lang.bind(this, this._startAppSwitcher));
this.setCustomKeybindingHandler('switch-applications-backward',
Main.KeybindingMode.NORMAL,
Lang.bind(this, this._startAppSwitcher));
this.setCustomKeybindingHandler('switch-group-backward',
Main.KeybindingMode.NORMAL,
Lang.bind(this, this._startAppSwitcher));
this.setCustomKeybindingHandler('switch-windows',
Main.KeybindingMode.NORMAL,
Lang.bind(this, this._startWindowSwitcher));
this.setCustomKeybindingHandler('switch-windows-backward',
Main.KeybindingMode.NORMAL,
Lang.bind(this, this._startWindowSwitcher));
this.setCustomKeybindingHandler('switch-panels',
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',
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,
Main.KeybindingMode.NORMAL,
Lang.bind(this, this._openAppMenu));
Meta.keybindings_set_custom_handler('internal-keybinding-switch-to-workspace-left',
Util.wrapKeybinding(Lang.bind(this, this._showWorkspaceSwitcher), true));
Meta.keybindings_set_custom_handler('internal-keybinding-switch-to-workspace-right',
Util.wrapKeybinding(Lang.bind(this, this._showWorkspaceSwitcher), true));
Meta.keybindings_set_custom_handler('internal-keybinding-switch-to-workspace-up',
Util.wrapKeybinding(Lang.bind(this, this._showWorkspaceSwitcher), true));
Meta.keybindings_set_custom_handler('internal-keybinding-switch-to-workspace-down',
Util.wrapKeybinding(Lang.bind(this, this._showWorkspaceSwitcher), true));
Meta.keybindings_set_custom_handler('internal-keybinding-move-to-workspace-left',
Lang.bind(this, this._showWorkspaceSwitcher));
Meta.keybindings_set_custom_handler('internal-keybinding-move-to-workspace-right',
Lang.bind(this, this._showWorkspaceSwitcher));
Meta.keybindings_set_custom_handler('internal-keybinding-move-to-workspace-up',
Lang.bind(this, this._showWorkspaceSwitcher));
Meta.keybindings_set_custom_handler('internal-keybinding-move-to-workspace-down',
Lang.bind(this, this._showWorkspaceSwitcher));
Meta.keybindings_set_custom_handler('internal-keybinding-switch-windows',
Lang.bind(this, this._startAppSwitcher));
Meta.keybindings_set_custom_handler('internal-keybinding-switch-group',
Lang.bind(this, this._startAppSwitcher));
Meta.keybindings_set_custom_handler('internal-keybinding-switch-windows-backward',
Lang.bind(this, this._startAppSwitcher));
Meta.keybindings_set_custom_handler('internal-keybinding-switch-group-backward',
Lang.bind(this, this._startAppSwitcher));
Meta.keybindings_set_custom_handler('internal-keybinding-switch-panels',
Util.wrapKeybinding(Lang.bind(this, this._startA11ySwitcher), true));
global.display.add_keybinding('open-application-menu',
new Gio.Settings({ schema: SHELL_KEYBINDINGS_SCHEMA }),
Meta.KeyBindingFlags.NONE,
Lang.bind(this, this._openAppMenu));
Main.overview.connect('showing', Lang.bind(this, function() {
for (let i = 0; i < this._dimmedWindows.length; i++)
@ -185,27 +143,6 @@ const WindowManager = new Lang.Class({
}));
},
setCustomKeybindingHandler: function(name, modes, handler) {
if (Meta.keybindings_set_custom_handler(name, handler))
this.allowKeybinding(name, modes);
},
addKeybinding: function(name, settings, flags, modes, handler) {
let action = global.display.add_keybinding(name, settings, flags, handler);
if (action != Meta.KeyBindingAction.NONE)
this.allowKeybinding(name, modes);
return action;
},
removeKeybinding: function(name) {
if (global.display.remove_keybinding(name))
this.allowKeybinding(name, Main.KeybindingMode.NONE);
},
allowKeybinding: function(name, modes) {
this._allowedKeybindings[name] = modes;
},
blockAnimations: function() {
this._animationBlockCount++;
},
@ -221,9 +158,7 @@ const WindowManager = new Lang.Class({
_shouldAnimateActor: function(actor) {
if (!this._shouldAnimate())
return false;
let windowType = actor.meta_window.get_window_type();
return windowType == Meta.WindowType.NORMAL ||
windowType == Meta.WindowType.MODAL_DIALOG;
return actor.meta_window.get_window_type() == Meta.WindowType.NORMAL;
},
_removeEffect : function(list, actor) {
@ -249,17 +184,16 @@ const WindowManager = new Lang.Class({
*/
this._minimizing.push(actor);
let monitor = Main.layoutManager.findMonitorForWindow(actor.meta_window);
let xDest = monitor.x;
let yDest = monitor.y;
let primary = Main.layoutManager.primaryMonitor;
let xDest = primary.x;
if (Clutter.get_default_text_direction() == Clutter.TextDirection.RTL)
xDest += monitor.width;
xDest += primary.width;
Tweener.addTween(actor,
{ scale_x: 0.0,
scale_y: 0.0,
x: xDest,
y: yDest,
y: 0,
time: WINDOW_ANIMATION_TIME,
transition: 'easeOutQuad',
onComplete: this._minimizeWindowDone,
@ -374,56 +308,57 @@ const WindowManager = new Lang.Class({
actor._windowType = type;
}));
if (actor.meta_window.is_attached_dialog()) {
this._checkDimming(actor.get_meta_window().get_transient_for());
if (this._shouldAnimate()) {
actor.set_scale(1.0, 0.0);
actor.scale_gravity = Clutter.Gravity.CENTER;
actor.show();
this._mapping.push(actor);
Tweener.addTween(actor,
{ scale_y: 1,
time: WINDOW_ANIMATION_TIME,
transition: "easeOutQuad",
onComplete: this._mapWindowDone,
onCompleteScope: this,
onCompleteParams: [shellwm, actor],
onOverwrite: this._mapWindowOverwrite,
onOverwriteScope: this,
onOverwriteParams: [shellwm, actor]
});
return;
}
shellwm.completed_map(actor);
return;
}
if (!this._shouldAnimateActor(actor)) {
shellwm.completed_map(actor);
return;
}
if (actor.meta_window.is_attached_dialog()) {
/* Scale the window from the center of the parent */
this._checkDimming(actor.get_meta_window().get_transient_for());
actor.set_scale(1.0, 0.0);
actor.scale_gravity = Clutter.Gravity.CENTER;
actor.show();
this._mapping.push(actor);
actor.opacity = 0;
actor.show();
Tweener.addTween(actor,
{ scale_y: 1,
time: WINDOW_ANIMATION_TIME,
transition: "easeOutQuad",
onComplete: this._mapWindowDone,
onCompleteScope: this,
onCompleteParams: [shellwm, actor],
onOverwrite: this._mapWindowOverwrite,
onOverwriteScope: this,
onOverwriteParams: [shellwm, actor]
});
} else {
/* Fade window in */
actor.opacity = 0;
actor.show();
this._mapping.push(actor);
Tweener.addTween(actor,
{ opacity: 255,
time: WINDOW_ANIMATION_TIME,
transition: 'easeOutQuad',
onComplete: this._mapWindowDone,
onCompleteScope: this,
onCompleteParams: [shellwm, actor],
onOverwrite: this._mapWindowOverwrite,
onOverwriteScope: this,
onOverwriteParams: [shellwm, actor]
});
}
/* Fade window in */
this._mapping.push(actor);
Tweener.addTween(actor,
{ opacity: 255,
time: WINDOW_ANIMATION_TIME,
transition: 'easeOutQuad',
onComplete: this._mapWindowDone,
onCompleteScope: this,
onCompleteParams: [shellwm, actor],
onOverwrite: this._mapWindowOverwrite,
onOverwriteScope: this,
onOverwriteParams: [shellwm, actor]
});
},
_mapWindowDone : function(shellwm, actor) {
if (this._removeEffect(this._mapping, actor)) {
Tweener.removeTweens(actor);
actor.opacity = 255;
actor.scale_y = 1;
shellwm.completed_map(actor);
}
},
@ -445,21 +380,18 @@ const WindowManager = new Lang.Class({
return win != window;
});
}
if (!this._shouldAnimateActor(actor)) {
shellwm.completed_destroy(actor);
return;
}
this._destroying.push(actor);
if (window.is_attached_dialog()) {
let parent = window.get_transient_for();
this._checkDimming(parent, window);
if (!this._shouldAnimate()) {
shellwm.completed_destroy(actor);
return;
}
actor.set_scale(1.0, 1.0);
actor.scale_gravity = Clutter.Gravity.CENTER;
actor.show();
this._destroying.push(actor);
actor._parentDestroyId = parent.connect('unmanaged', Lang.bind(this, function () {
Tweener.removeTweens(actor);
@ -493,21 +425,6 @@ const WindowManager = new Lang.Class({
}
},
_filterKeybinding: function(shellwm, binding) {
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 == Main.KeybindingMode.NORMAL &&
binding.is_builtin())
return false;
return !(this._allowedKeybindings[binding.get_name()] & Main.keybindingMode);
},
_switchWorkspace : function(shellwm, from, to, direction) {
if (!this._shouldAnimate()) {
shellwm.completed_switch_workspace();
@ -630,49 +547,38 @@ const WindowManager = new Lang.Class({
if (this._workspaceSwitcherPopup != null)
this._workspaceSwitcherPopup.destroy();
let tabPopup = new AltTab.AppSwitcherPopup();
let modifiers = binding.get_modifiers();
let backwards = modifiers & Meta.VirtualModifier.SHIFT_MASK;
if (!tabPopup.show(backwards, binding.get_name(), binding.get_mask()))
tabPopup.destroy();
},
_startWindowSwitcher : function(display, screen, window, binding) {
/* prevent a corner case where both popups show up at once */
if (this._workspaceSwitcherPopup != null)
this._workspaceSwitcherPopup.destroy();
let tabPopup = new AltTab.WindowSwitcherPopup();
let tabPopup = new AltTab.AltTabPopup();
let modifiers = binding.get_modifiers();
let backwards = modifiers & Meta.VirtualModifier.SHIFT_MASK;
if (!tabPopup.show(backwards, binding.get_name(), binding.get_mask()))
tabPopup.destroy();
return true;
},
_startA11ySwitcher : function(display, screen, window, binding) {
let modifiers = binding.get_modifiers();
let backwards = modifiers & Meta.VirtualModifier.SHIFT_MASK;
Main.ctrlAltTabManager.popup(backwards, binding.get_name(), binding.get_mask());
Main.ctrlAltTabManager.popup(backwards, binding.get_mask());
return true;
},
_openAppMenu : function(display, screen, window, event, binding) {
Main.panel.openAppMenu();
return true;
},
_showWorkspaceSwitcher : function(display, screen, window, binding) {
if (screen.n_workspaces == 1)
return;
return false;
let [action,,,direction] = binding.get_name().split('-');
let [,,action,,,direction] = binding.get_name().split('-');
let direction = Meta.MotionDirection[direction.toUpperCase()];
let newWs;
if (direction != Meta.MotionDirection.UP &&
direction != Meta.MotionDirection.DOWN)
return;
return false;
if (action == 'switch')
newWs = this.actionMoveWorkspace(direction);
@ -688,6 +594,8 @@ const WindowManager = new Lang.Class({
}
this._workspaceSwitcherPopup.display(direction, newWs.index());
}
return true;
},
actionMoveWorkspace: function(direction) {

View File

@ -1,6 +1,7 @@
// -*- 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;
const Meta = imports.gi.Meta;
@ -29,6 +30,9 @@ const CLOSE_BUTTON_FADE_TIME = 0.1;
const DRAGGING_WINDOW_OPACITY = 100;
const BUTTON_LAYOUT_SCHEMA = 'org.gnome.shell.overrides';
const BUTTON_LAYOUT_KEY = 'button-layout';
// When calculating a layout, we calculate the scale of windows and the percent
// of the available area the new layout uses. If the values for the new layout,
// when weighted with the values as below, are worse than the previous layout's,
@ -120,8 +124,6 @@ const WindowClone = new Lang.Class({
this.actor._delegate = this;
this._slot = [0, 0, 0, 0];
this._dragSlot = [0, 0, 0, 0];
this._stackAbove = null;
this._sizeChangedId = this.realWindow.connect('size-changed',
@ -157,15 +159,22 @@ const WindowClone = new Lang.Class({
this._selected = false;
},
set slot(slot) {
this._slot = slot;
},
get slot() {
if (this.inDrag)
return this._dragSlot;
else
return this._slot;
let x, y, w, h;
if (this.inDrag) {
x = this.dragOrigX;
y = this.dragOrigY;
w = this.actor.width * this.dragOrigScale;
h = this.actor.height * this.dragOrigScale;
} else {
x = this.actor.x;
y = this.actor.y;
w = this.actor.width * this.actor.scale_x;
h = this.actor.height * this.actor.scale_y;
}
return [x, y, w, h];
},
setStackAbove: function (actor) {
@ -256,37 +265,23 @@ const WindowClone = new Lang.Class({
_onScroll : function (actor, event) {
let direction = event.get_scroll_direction();
let delta;
if (event.is_pointer_emulated())
return;
if (direction == Clutter.ScrollDirection.DOWN) {
delta = -SCROLL_SCALE_AMOUNT;
} else if (direction == Clutter.ScrollDirection.UP) {
delta = +SCROLL_SCALE_AMOUNT;
} else if (direction == Clutter.ScrollDirection.SMOOTH) {
let [dx, dy] = event.get_scroll_delta();
delta = -dy * 10;
}
if (delta > 0) {
if (direction == Clutter.ScrollDirection.UP) {
if (this._zoomStep == undefined)
this._zoomStart();
if (this._zoomStep < 100) {
this._zoomStep += delta;
this._zoomStep = Math.min(100, this._zoomStep);
this._zoomStep += SCROLL_SCALE_AMOUNT;
this._zoomUpdate();
}
} else if (delta < 0) {
} else if (direction == Clutter.ScrollDirection.DOWN) {
if (this._zoomStep > 0) {
this._zoomStep += delta;
this._zoomStep -= SCROLL_SCALE_AMOUNT;
this._zoomStep = Math.max(0, this._zoomStep);
this._zoomUpdate();
}
if (this._zoomStep <= 0.0)
this._zoomEnd();
}
},
_zoomUpdate : function () {
@ -397,7 +392,6 @@ const WindowClone = new Lang.Class({
if (this._zooming)
this._zoomEnd();
this._dragSlot = this._slot;
[this.dragOrigX, this.dragOrigY] = this.actor.get_position();
this.dragOrigScale = this.actor.scale_x;
this.inDrag = true;
@ -451,9 +445,6 @@ const WindowOverlay = new Lang.Class({
this._parentActor = parentActor;
this._hidden = false;
this.borderSize = 0;
this.border = new St.Bin({ style_class: 'window-clone-border' });
let title = new St.Label({ style_class: 'window-caption',
text: metaWindow.title });
title.clutter_text.ellipsize = Pango.EllipsizeMode.END;
@ -462,7 +453,11 @@ const WindowOverlay = new Lang.Class({
this._updateCaptionId = metaWindow.connect('notify::title',
Lang.bind(this, function(w) {
this.title.text = w.title;
this.relayout(false);
// we need this for the next call to get_preferred_width
// to return useful results
this.title.set_size(-1, -1);
this._repositionSelf();
}));
let button = new St.Button({ style_class: 'window-close' });
@ -487,13 +482,11 @@ const WindowOverlay = new Lang.Class({
this.closeButton = button;
parentActor.add_actor(this.title);
parentActor.add_actor(this.border);
parentActor.add_actor(this.closeButton);
title.connect('style-changed',
Lang.bind(this, this._onStyleChanged));
button.connect('style-changed',
Lang.bind(this, this._onStyleChanged));
this.border.connect('style-changed', Lang.bind(this, this._onStyleChanged));
// force a style change if we are already on a stage - otherwise
// the signal will be emitted normally when we are added
if (parentActor.get_stage())
@ -502,17 +495,15 @@ const WindowOverlay = new Lang.Class({
hide: function() {
this._hidden = true;
this.closeButton.hide();
this.title.hide();
this.hideCloseButton();
},
show: function() {
this._hidden = false;
this.title.show();
if (this._windowClone.actor.has_pointer)
this._animateVisible();
this.closeButton.show();
this.title.show();
},
fadeIn: function() {
@ -529,22 +520,39 @@ const WindowOverlay = new Lang.Class({
},
chromeHeights: function () {
return [Math.max(this.borderSize, this.closeButton.height - this.closeButton._overlap),
return [this.closeButton.height - this.closeButton._overlap,
this.title.height + this.title._spacing];
},
chromeWidths: function () {
return [this.borderSize, this.borderSize];
_repositionSelf: function() {
let [cloneX, cloneY, cloneWidth, cloneHeight] = this._windowClone.slot;
this.updatePositions(cloneX, cloneY, cloneWidth, cloneHeight, false);
},
relayout: function(animate) {
let [cloneX, cloneY, cloneWidth, cloneHeight] = this._windowClone.slot;
/**
* @cloneX: x position of windowClone
* @cloneY: y position of windowClone
* @cloneWidth: width of windowClone
* @cloneHeight height of windowClone
*/
// These parameters are not the values retrieved with
// get_transformed_position() and get_transformed_size(),
// as windowClone might be moving.
// See Workspace._showWindowOverlay
updatePositions: function(cloneX, cloneY, cloneWidth, cloneHeight, animate) {
let button = this.closeButton;
let title = this.title;
let layout = Meta.prefs_get_button_layout();
let side = layout.left_buttons.indexOf(Meta.ButtonFunction.CLOSE) > -1 ? St.Side.LEFT : St.Side.RIGHT;
let settings = new Gio.Settings({ schema: BUTTON_LAYOUT_SCHEMA });
let layout = settings.get_string(BUTTON_LAYOUT_KEY);
let rtl = Clutter.get_default_text_direction() == Clutter.TextDirection.RTL;
let split = layout.split(":");
let side;
if (split[0].indexOf("close") > -1)
side = rtl ? St.Side.RIGHT : St.Side.LEFT;
else
side = rtl ? St.Side.LEFT : St.Side.RIGHT;
let buttonX;
let buttonY = cloneY - (button.height - button._overlap);
@ -558,16 +566,8 @@ const WindowOverlay = new Lang.Class({
else
button.set_position(Math.floor(buttonX), Math.floor(buttonY));
// Clutter.Actor.get_preferred_width() will return the fixed width if one
// is set, so we need to reset the width by calling set_width(-1), to forward
// the call down to StLabel.
// We also need to save and restore the current width, otherwise the animation
// starts from the wrong point.
let prevTitleWidth = title.width;
title.set_width(-1);
let [titleMinWidth, titleNatWidth] = title.get_preferred_width(-1);
let titleWidth = Math.max(titleMinWidth, Math.min(titleNatWidth, cloneWidth));
title.width = prevTitleWidth;
let titleX = cloneX + (cloneWidth - titleWidth) / 2;
let titleY = cloneY + cloneHeight + title._spacing;
@ -578,32 +578,16 @@ const WindowOverlay = new Lang.Class({
title.width = titleWidth;
title.set_position(Math.floor(titleX), Math.floor(titleY));
}
let borderX = cloneX - this.borderSize;
let borderY = cloneY - this.borderSize;
let borderWidth = cloneWidth + 2 * this.borderSize;
let borderHeight = cloneHeight + 2 * this.borderSize;
if (animate) {
this._animateOverlayActor(this.border, borderX, borderY,
borderWidth, borderHeight);
} else {
this.border.set_position(borderX, borderY);
this.border.set_size(borderWidth, borderHeight);
}
},
_animateOverlayActor: function(actor, x, y, width, height) {
let params = { x: x,
y: y,
width: width,
time: Overview.ANIMATION_TIME,
transition: 'easeOutQuad' };
if (height !== undefined)
params.height = height;
Tweener.addTween(actor, params);
_animateOverlayActor: function(actor, x, y, width) {
Tweener.addTween(actor,
{ x: x,
y: y,
width: width,
time: Overview.ANIMATION_TIME,
transition: 'easeOutQuad'
});
},
_closeWindow: function(actor) {
@ -646,43 +630,6 @@ const WindowOverlay = new Lang.Class({
this._windowClone.metaWindow.disconnect(this._updateCaptionId);
this.title.destroy();
this.closeButton.destroy();
this.border.destroy();
},
_animateVisible: function() {
this._parentActor.raise_top();
this.closeButton.show();
this.closeButton.opacity = 0;
Tweener.addTween(this.closeButton,
{ opacity: 255,
time: CLOSE_BUTTON_FADE_TIME,
transition: 'easeOutQuad' });
this.border.show();
this.border.opacity = 0;
Tweener.addTween(this.border,
{ opacity: 255,
time: CLOSE_BUTTON_FADE_TIME,
transition: 'easeOutQuad' });
this.title.add_style_pseudo_class('hover');
},
_animateInvisible: function() {
this.closeButton.opacity = 255;
Tweener.addTween(this.closeButton,
{ opacity: 0,
time: CLOSE_BUTTON_FADE_TIME,
transition: 'easeInQuad' });
this.border.opacity = 255;
Tweener.addTween(this.border,
{ opacity: 0,
time: CLOSE_BUTTON_FADE_TIME,
transition: 'easeInQuad' });
this.title.remove_style_pseudo_class('hover');
},
_onEnter: function() {
@ -692,8 +639,8 @@ const WindowOverlay = new Lang.Class({
// are shown again
if (this._hidden)
return;
this._animateVisible();
this._parentActor.raise_top();
this.closeButton.show();
this.emit('show-close-button');
},
@ -704,10 +651,9 @@ const WindowOverlay = new Lang.Class({
_idleToggleCloseButton: function() {
this._idleToggleCloseId = 0;
if (!this._windowClone.actor.has_pointer &&
!this.closeButton.has_pointer)
this._animateInvisible();
this.closeButton.hide();
return false;
},
@ -718,8 +664,6 @@ const WindowOverlay = new Lang.Class({
this._idleToggleCloseId = 0;
}
this.closeButton.hide();
this.border.hide();
this.title.remove_style_pseudo_class('hover');
},
_onStyleChanged: function() {
@ -729,9 +673,6 @@ const WindowOverlay = new Lang.Class({
let closeNode = this.closeButton.get_theme_node();
this.closeButton._overlap = closeNode.get_length('-shell-close-overlap');
let borderNode = this.border.get_theme_node();
this.borderSize = borderNode.get_border_width(St.Side.TOP);
this._parentActor.queue_relayout();
}
});
@ -1173,8 +1114,8 @@ const Workspace = new Lang.Class({
let slot = slots[i];
let clone = clones[i];
let metaWindow = clone.metaWindow;
let overlay = clone.overlay;
clone.slotId = i;
let mainIndex = this._lookupIndex(metaWindow);
let overlay = this._windowOverlays[mainIndex];
// Positioning a window currently being dragged must be avoided;
// we'll just leave a blank spot in the layout for it.
@ -1182,7 +1123,6 @@ const Workspace = new Lang.Class({
continue;
let [x, y, scale] = slot;
clone.slot = [x, y, clone.actor.width * scale, clone.actor.height * scale];
if (overlay && initialPositioning)
overlay.hide();
@ -1214,7 +1154,7 @@ const Workspace = new Lang.Class({
Tweener.removeTweens(clone.actor);
clone.actor.set_position(x, y);
clone.actor.set_scale(scale, scale);
clone.overlay.relayout(false);
this._updateWindowOverlayPositions(clone, overlay, x, y, scale, false);
this._showWindowOverlay(clone, overlay, isOnCurrentWorkspace);
}
}
@ -1249,7 +1189,15 @@ const Workspace = new Lang.Class({
})
});
clone.overlay.relayout(true);
this._updateWindowOverlayPositions(clone, overlay, x, y, scale, true);
},
_updateWindowOverlayPositions: function(clone, overlay, x, y, scale, animate) {
if (!overlay)
return;
let [cloneWidth, cloneHeight] = clone.actor.get_size();
overlay.updatePositions(x, y, cloneWidth * scale, cloneHeight * scale, animate);
},
_showWindowOverlay: function(clone, overlay, fade) {
@ -1384,10 +1332,9 @@ const Workspace = new Lang.Class({
let scale = win._overviewHint.scale;
delete win._overviewHint;
clone.slot = [x, y, clone.actor.width * scale, clone.actor.height * scale];
clone.actor.set_position (x, y);
clone.actor.set_scale (scale, scale);
clone.overlay.relayout(false);
this._updateWindowOverlayPositions(clone, overlay, x, y, scale, false);
} else {
// Position new windows at the top corner of the workspace rather
// than where they were placed for real to avoid the window
@ -1552,7 +1499,6 @@ const Workspace = new Lang.Class({
_addWindowClone : function(win) {
let clone = new WindowClone(win, this);
let overlay = new WindowOverlay(clone, this._windowOverlaysGroup);
clone.overlay = overlay;
clone.connect('selected',
Lang.bind(this, this._onCloneSelected));
@ -1677,25 +1623,20 @@ const Workspace = new Lang.Class({
return [];
let closeButtonHeight, captionHeight;
let leftBorder, rightBorder;
if (this._windowOverlays.length) {
// All of the overlays have the same chrome sizes,
// so just pick the first one.
let overlay = this._windowOverlays[0];
[closeButtonHeight, captionHeight] = overlay.chromeHeights();
[leftBorder, rightBorder] = overlay.chromeWidths();
} else {
[closeButtonHeight, captionHeight] = [0, 0];
}
rowSpacing += captionHeight;
columnSpacing += rightBorder;
let area = { x: this._x, y: this._y, width: this._width, height: this._height };
area.y += closeButtonHeight;
area.height -= closeButtonHeight;
area.x += leftBorder;
area.width -= leftBorder;
if (!this._currentLayout)
this._currentLayout = this._computeLayout(windows, area, rowSpacing, columnSpacing, captionHeight);

View File

@ -1,7 +1,6 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
const Clutter = imports.gi.Clutter;
const Gio = imports.gi.Gio;
const Lang = imports.lang;
const Mainloop = imports.mainloop;
const Meta = imports.gi.Meta;
@ -28,8 +27,6 @@ const WORKSPACE_CUT_SIZE = 10;
const WORKSPACE_KEEP_ALIVE_TIME = 100;
const OVERRIDE_SCHEMA = 'org.gnome.shell.overrides';
const WindowClone = new Lang.Class({
Name: 'WindowClone',
@ -544,12 +541,6 @@ 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));
Main.overview.connect('hidden',
Lang.bind(this, this._destroyThumbnails));
Main.overview.connect('item-drag-begin',
Lang.bind(this, this._onDragBegin));
@ -563,16 +554,6 @@ const ThumbnailsBox = new Lang.Class({
Lang.bind(this, this._onDragEnd));
Main.overview.connect('window-drag-cancelled',
Lang.bind(this, this._onDragCancelled));
this._settings = new Gio.Settings({ schema: OVERRIDE_SCHEMA });
this._settings.connect('changed::dynamic-workspaces',
Lang.bind(this, this._updateSwitcherVisibility));
},
_updateSwitcherVisibility: function() {
this.actor.visible =
this._settings.get_boolean('dynamic-workspaces') ||
global.screen.n_workspaces > 1;
},
_onButtonRelease: function(actor, event) {
@ -738,16 +719,10 @@ const ThumbnailsBox = new Lang.Class({
}
},
_createThumbnails: function() {
show: function() {
this._switchWorkspaceNotifyId =
global.window_manager.connect('switch-workspace',
Lang.bind(this, this._activeWorkspaceChanged));
this._nWorkspacesNotifyId =
global.screen.connect('notify::n-workspaces',
Lang.bind(this, this._workspacesChanged));
this._syncStackingId =
Main.overview.connect('windows-restacked',
Lang.bind(this, this._syncStacking));
this._targetScale = 0;
this._scale = 0;
@ -769,54 +744,19 @@ const ThumbnailsBox = new Lang.Class({
};
this.addThumbnails(0, global.screen.n_workspaces);
this._updateSwitcherVisibility();
},
_destroyThumbnails: function() {
hide: function() {
if (this._switchWorkspaceNotifyId > 0) {
global.window_manager.disconnect(this._switchWorkspaceNotifyId);
this._switchWorkspaceNotifyId = 0;
}
if (this._nWorkspacesNotifyId > 0) {
global.screen.disconnect(this._nWorkspacesNotifyId);
this._nWorkspacesNotifyId = 0;
}
if (this._syncStackingId > 0) {
Main.overview.disconnect(this._syncStackingId);
this._syncStackingId = 0;
}
for (let w = 0; w < this._thumbnails.length; w++)
this._thumbnails[w].destroy();
this._thumbnails = [];
},
_workspacesChanged: function() {
let oldNumWorkspaces = this._thumbnails.length;
let newNumWorkspaces = global.screen.n_workspaces;
let active = global.screen.get_active_workspace_index();
if (newNumWorkspaces > oldNumWorkspaces) {
this.addThumbnails(oldNumWorkspaces, newNumWorkspaces - oldNumWorkspaces);
} else {
let removedIndex;
let removedNum = oldNumWorkspaces - newNumWorkspaces;
for (let w = 0; w < oldNumWorkspaces; w++) {
let metaWorkspace = global.screen.get_workspace_by_index(w);
if (this._thumbnails[w].metaWorkspace != metaWorkspace) {
removedIndex = w;
break;
}
}
this.removeThumbnails(removedIndex, removedNum);
}
this._updateSwitcherVisibility();
},
addThumbnails: function(start, count) {
for (let k = start; k < start + count; k++) {
let metaWorkspace = global.screen.get_workspace_by_index(k);
@ -862,7 +802,7 @@ const ThumbnailsBox = new Lang.Class({
this._queueUpdateStates();
},
_syncStacking: function(overview, stackIndices) {
syncStacking: function(stackIndices) {
for (let i = 0; i < this._thumbnails.length; i++)
this._thumbnails[i].syncStacking(stackIndices);
},
@ -1217,16 +1157,5 @@ 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;
}
}
});

View File

@ -2,7 +2,6 @@
const Clutter = imports.gi.Clutter;
const Gio = imports.gi.Gio;
const GObject = imports.gi.GObject;
const Lang = imports.lang;
const Mainloop = imports.mainloop;
const Meta = imports.gi.Meta;
@ -69,7 +68,7 @@ const WorkspacesView = new Lang.Class({
// Add workspace actors
for (let w = 0; w < global.screen.n_workspaces; w++)
this.actor.add_actor(this._workspaces[w].actor);
this._workspaces[w].actor.reparent(this.actor);
this._workspaces[activeWorkspaceIndex].actor.raise_top();
this._extraWorkspaces = [];
@ -129,10 +128,8 @@ const WorkspacesView = new Lang.Class({
continue;
let ws = new Workspace.Workspace(null, i);
ws.setGeometry(monitors[i].x,
monitors[i].y,
monitors[i].width,
monitors[i].height);
ws.setGeometry(monitors[i].x, monitors[i].y,
monitors[i].width, monitors[i].height);
global.overlay_group.add_actor(ws.actor);
this._extraWorkspaces.push(ws);
}
@ -208,11 +205,11 @@ const WorkspacesView = new Lang.Class({
this._workspaces[w].positionWindows(Workspace.WindowPositionFlags.ANIMATE);
},
_scrollToActive: function() {
_scrollToActive: function(showAnimation) {
let active = global.screen.get_active_workspace_index();
this._updateWorkspaceActors(true);
this._updateScrollAdjustment(active);
this._updateWorkspaceActors(showAnimation);
this._updateScrollAdjustment(active, showAnimation);
},
// Update workspace actors parameters
@ -270,21 +267,26 @@ const WorkspacesView = new Lang.Class({
}
},
_updateScrollAdjustment: function(index) {
_updateScrollAdjustment: function(index, showAnimation) {
if (this._scrolling)
return;
this._animatingScroll = true;
Tweener.addTween(this.scrollAdjustment, {
value: index,
time: WORKSPACE_SWITCH_TIME,
transition: 'easeOutQuad',
onComplete: Lang.bind(this,
function() {
this._animatingScroll = false;
})
});
if (showAnimation) {
Tweener.addTween(this.scrollAdjustment, {
value: index,
time: WORKSPACE_SWITCH_TIME,
transition: 'easeOutQuad',
onComplete: Lang.bind(this,
function() {
this._animatingScroll = false;
})
});
} else {
this.scrollAdjustment.value = index;
this._animatingScroll = false;
}
},
updateWorkspaces: function(oldNumWorkspaces, newNumWorkspaces) {
@ -311,7 +313,7 @@ const WorkspacesView = new Lang.Class({
if (this._scrolling)
return;
this._scrollToActive();
this._scrollToActive(true);
},
_onDestroy: function() {
@ -385,11 +387,24 @@ const WorkspacesView = new Lang.Class({
this._scrolling = true;
},
endSwipeScroll: function() {
endSwipeScroll: function(result) {
this._scrolling = false;
if (result == Overview.SwipeScrollResult.CLICK) {
let [x, y, mod] = global.get_pointer();
let actor = global.stage.get_actor_at_pos(Clutter.PickMode.ALL,
x, y);
// Only switch to the workspace when there's no application
// windows open. The problem is that it's too easy to miss
// an app window and get the wrong one focused.
let active = global.screen.get_active_workspace_index();
if (this._workspaces[active].isEmpty() &&
this.actor.contains(actor))
Main.overview.hide();
}
// Make sure title captions etc are shown as necessary
this._scrollToActive();
this._updateVisibility();
},
@ -437,51 +452,14 @@ const WorkspacesDisplay = new Lang.Class({
Name: 'WorkspacesDisplay',
_init: function() {
this.actor = new Shell.GenericContainer({ style_class: 'workspaces-display' });
this.actor = new Shell.GenericContainer();
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('notify::mapped', Lang.bind(this, this._setupSwipeScrolling));
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) {
// Only switch to the workspace when there's no application
// windows open. The problem is that it's too easy to miss
// an app window and get the wrong one focused.
if (action.get_button() == 1 &&
this._getPrimaryView().getActiveWorkspace().isEmpty())
Main.overview.hide();
}));
Main.overview.addAction(clickAction);
this.actor.bind_property('mapped', clickAction, 'enabled', GObject.BindingFlags.SYNC_CREATE);
let panAction = new Clutter.PanAction();
panAction.connect('pan', Lang.bind(this, this._onPan));
panAction.connect('gesture-begin', Lang.bind(this, function() {
for (let i = 0; i < this._workspacesViews.length; i++)
this._workspacesViews[i].startSwipeScroll();
return true;
}));
panAction.connect('gesture-end', Lang.bind(this, function() {
clickAction.release();
for (let i = 0; i < this._workspacesViews.length; i++)
this._workspacesViews[i].endSwipeScroll();
}));
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,
@ -493,14 +471,15 @@ const WorkspacesDisplay = new Lang.Class({
controls.track_hover = true;
controls.connect('notify::hover',
Lang.bind(this, this._onControlsHoverChanged));
controls.connect('scroll-event',
Lang.bind(this, this._onScrollEvent));
this._primaryIndex = Main.layoutManager.primaryIndex;
this._thumbnailsBox = new WorkspaceThumbnail.ThumbnailsBox();
controls.add_actor(this._thumbnailsBox.actor);
this._workspacesViews = [];
this._workspaces = [];
this._workspacesViews = null;
this._primaryScrollAdjustment = null;
this._settings = new Gio.Settings({ schema: OVERRIDE_SCHEMA });
@ -546,13 +525,16 @@ const WorkspacesDisplay = new Lang.Class({
this._notifyOpacityId = 0;
this._swipeScrollBeginId = 0;
this._swipeScrollEndId = 0;
this._settings = new Gio.Settings({ schema: OVERRIDE_SCHEMA });
this._settings.connect('changed::dynamic-workspaces',
Lang.bind(this, this._updateSwitcherVisibility));
},
_onPan: function(action) {
let [dist, dx, dy] = action.get_motion_delta(0);
let adjustment = this._scrollAdjustment;
adjustment.value -= (dy / this.actor.height) * adjustment.page_size;
return false;
_updateSwitcherVisibility: function() {
this._thumbnailsBox.actor.visible =
this._settings.get_boolean('dynamic-workspaces') ||
global.screen.n_workspaces > 1;
},
show: function() {
@ -574,11 +556,13 @@ const WorkspacesDisplay = new Lang.Class({
this._updateZoom();
this._controls.show();
this._thumbnailsBox.show();
this._updateSwitcherVisibility();
this._updateWorkspacesViews();
this._restackedNotifyId =
Main.overview.connect('windows-restacked',
global.screen.connect('restacked',
Lang.bind(this, this._onRestacked));
if (this._itemDragBeginId == 0)
@ -599,6 +583,8 @@ const WorkspacesDisplay = new Lang.Class({
if (this._windowDragEndId == 0)
this._windowDragEndId = Main.overview.connect('window-drag-end',
Lang.bind(this, this._dragEnd));
this._onRestacked();
},
zoomFromOverview: function() {
@ -609,12 +595,13 @@ const WorkspacesDisplay = new Lang.Class({
hide: function() {
this._controls.hide();
this._thumbnailsBox.hide();
if (!this._alwaysZoomOut)
this.zoomFraction = 0;
if (this._restackedNotifyId > 0){
Main.overview.disconnect(this._restackedNotifyId);
global.screen.disconnect(this._restackedNotifyId);
this._restackedNotifyId = 0;
}
if (this._itemDragBeginId > 0) {
@ -644,7 +631,7 @@ const WorkspacesDisplay = new Lang.Class({
for (let i = 0; i < this._workspacesViews.length; i++)
this._workspacesViews[i].destroy();
this._workspacesViews = [];
this._workspacesViews = null;
for (let i = 0; i < this._workspaces.length; i++)
for (let w = 0; w < this._workspaces[i].length; w++) {
@ -653,6 +640,33 @@ const WorkspacesDisplay = new Lang.Class({
}
},
_setupSwipeScrolling: function() {
if (this._swipeScrollBeginId)
Main.overview.disconnect(this._swipeScrollBeginId);
this._swipeScrollBeginId = 0;
if (this._swipeScrollEndId)
Main.overview.disconnect(this._swipeScrollEndId);
this._swipeScrollEndId = 0;
if (!this.actor.mapped)
return;
let direction = Overview.SwipeScrollDirection.VERTICAL;
Main.overview.setScrollAdjustment(this._scrollAdjustment,
direction);
this._swipeScrollBeginId = Main.overview.connect('swipe-scroll-begin',
Lang.bind(this, function() {
for (let i = 0; i < this._workspacesViews.length; i++)
this._workspacesViews[i].startSwipeScroll();
}));
this._swipeScrollEndId = Main.overview.connect('swipe-scroll-end',
Lang.bind(this, function(overview, result) {
for (let i = 0; i < this._workspacesViews.length; i++)
this._workspacesViews[i].endSwipeScroll(result);
}));
},
_workspacesOnlyOnPrimaryChanged: function() {
this._workspacesOnlyOnPrimary = this._settings.get_boolean('workspaces-only-on-primary');
@ -663,12 +677,14 @@ const WorkspacesDisplay = new Lang.Class({
},
_updateWorkspacesViews: function() {
for (let i = 0; i < this._workspacesViews.length; i++)
this._workspacesViews[i].destroy();
if (this._workspacesViews)
for (let i = 0; i < this._workspacesViews.length; i++)
this._workspacesViews[i].destroy();
for (let i = 0; i < this._workspaces.length; i++)
for (let w = 0; w < this._workspaces[i].length; w++)
this._workspaces[i][w].destroy();
if (this._workspaces)
for (let i = 0; i < this._workspaces.length; i++)
for (let w = 0; w < this._workspaces[i].length; w++)
this._workspaces[i][w].destroy();
this._workspacesViews = [];
this._workspaces = [];
@ -690,6 +706,7 @@ const WorkspacesDisplay = new Lang.Class({
this._scrollAdjustment = view.scrollAdjustment;
this._scrollAdjustment.connect('notify::value',
Lang.bind(this, this._scrollValueChanged));
this._setupSwipeScrolling();
}
this._workspacesViews.push(view);
}
@ -716,7 +733,7 @@ const WorkspacesDisplay = new Lang.Class({
},
_getPrimaryView: function() {
if (!this._workspacesViews.length)
if (!this._workspacesViews)
return null;
if (this._workspacesOnlyOnPrimary)
return this._workspacesViews[0];
@ -825,7 +842,7 @@ const WorkspacesDisplay = new Lang.Class({
},
_updateWorkspacesGeometry: function() {
if (!this._workspacesViews.length)
if (!this._workspacesViews)
return;
let fullWidth = this.actor.allocation.x2 - this.actor.allocation.x1;
@ -847,7 +864,7 @@ const WorkspacesDisplay = new Lang.Class({
let clipY = y + (fullHeight - clipHeight) / 2;
let widthAdjust = this._zoomOut ? controlsNatural : controlsVisible;
widthAdjust += this._spacing;
widthAdjust += Main.overview._spacing;
width -= widthAdjust;
if (rtl)
x += widthAdjust;
@ -874,16 +891,26 @@ const WorkspacesDisplay = new Lang.Class({
}
},
_onRestacked: function(overview, stackIndices) {
_onRestacked: function() {
let stack = global.get_window_actors();
let stackIndices = {};
for (let i = 0; i < stack.length; i++) {
// Use the stable sequence for an integer to use as a hash key
stackIndices[stack[i].get_meta_window().get_stable_sequence()] = i;
}
for (let i = 0; i < this._workspacesViews.length; i++)
this._workspacesViews[i].syncStacking(stackIndices);
this._thumbnailsBox.syncStacking(stackIndices);
},
_workspacesChanged: function() {
this._updateAlwaysZoom();
this._updateZoom();
if (!this._workspacesViews.length)
if (this._workspacesViews == null)
return;
let oldNumWorkspaces = this._workspaces[0].length;
@ -907,6 +934,8 @@ const WorkspacesDisplay = new Lang.Class({
}
m++;
}
this._thumbnailsBox.addThumbnails(oldNumWorkspaces, newNumWorkspaces - oldNumWorkspaces);
} else {
// Assume workspaces are only removed sequentially
// (e.g. 2,3,4 - not 2,4,7)
@ -929,11 +958,14 @@ const WorkspacesDisplay = new Lang.Class({
lostWorkspaces[l].destroy();
}
}
this._thumbnailsBox.removeThumbnails(removedIndex, removedNum);
}
for (let i = 0; i < this._workspacesViews.length; i++)
this._workspacesViews[i].updateWorkspaces(oldNumWorkspaces,
newNumWorkspaces);
this._updateSwitcherVisibility();
},
_updateZoom : function() {
@ -945,7 +977,7 @@ const WorkspacesDisplay = new Lang.Class({
this._zoomOut = shouldZoom;
this._updateWorkspacesGeometry();
if (!this._workspacesViews.length)
if (!this._workspacesViews)
return;
Tweener.addTween(this,
@ -996,6 +1028,17 @@ const WorkspacesDisplay = new Lang.Class({
// might as well avoid it.
Meta.later_add(Meta.LaterType.BEFORE_REDRAW,
Lang.bind(this, this._updateZoom));
},
_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;
}
}
});
Signals.addSignalMethods(WorkspacesDisplay.prototype);

View File

@ -17,7 +17,6 @@ js/ui/components/networkAgent.js
js/ui/components/polkitAgent.js
js/ui/components/recorder.js
js/ui/components/telepathyClient.js
js/ui/ctrlAltTab.js
js/ui/dash.js
js/ui/dateMenu.js
js/ui/endSessionDialog.js

797
po/ar.po

File diff suppressed because it is too large Load Diff

860
po/as.po

File diff suppressed because it is too large Load Diff

727
po/be.po

File diff suppressed because it is too large Load Diff

820
po/de.po

File diff suppressed because it is too large Load Diff

814
po/es.po

File diff suppressed because it is too large Load Diff

301
po/et.po
View File

@ -13,8 +13,8 @@ msgstr ""
"Project-Id-Version: gnome-shell MASTER\n"
"Report-Msgid-Bugs-To: http://bugzilla.gnome.org/enter_bug.cgi?product=gnome-"
"shell&keywords=I18N+L10N&component=general\n"
"POT-Creation-Date: 2012-12-09 13:03+0000\n"
"PO-Revision-Date: 2012-12-19 16:47+0300\n"
"POT-Creation-Date: 2012-09-22 22:24+0000\n"
"PO-Revision-Date: 2012-09-23 08:48+0300\n"
"Last-Translator: Mattias Põldaru <mahfiaz@gmail.com>\n"
"Language-Team: Estonian <>\n"
"Language: et\n"
@ -37,15 +37,6 @@ msgstr "Arvuti"
msgid "Show the message tray"
msgstr "Teateala näitamine"
msgid "Focus the active notification"
msgstr "Aktiivse märguande fokuseerimine"
msgid "Show all applications"
msgstr "Kõigi rakenduste kuvamine"
msgid "Open the application menu"
msgstr "Rakenduste menüü avamine"
msgid "GNOME Shell"
msgstr "GNOME Shell"
@ -125,38 +116,6 @@ msgstr ""
"Kasutatakse kasutaja poolt viimati vahetult määratud kiirsuhtluse oleku "
"salvestamiseks. See väärtus pärineb GsmPresenceStatus nummerdusest."
msgid "Always show the 'Log out' menuitem in the user menu."
msgstr "Kasutajamenüüs näidatakse alati 'Logi välja' menüükirjet."
msgid ""
"This key overrides the automatic hiding of the 'Log out' menuitem in single-"
"user, single-session situations."
msgstr ""
"See võti keelab automaatse 'Logi välja' menüükirje peitmise, kui arvutis on "
"üks kasutaja ning avatud üks seanss."
msgid "Show full name in the user menu"
msgstr "Kasutajamenüüs näidatakse kasutaja tervet nime"
msgid "Whether the users full name is shown in the user menu or not."
msgstr "Kas kasutajamenüüs näidatakse kasutaja kogu nime või mitte."
msgid ""
"Whether to remember password for mounting encrypted or remote filesystems"
msgstr ""
"Kas pidada meeles krüpteeritud või kaugfailisüsteemide haakimise paroole."
msgid ""
"The shell will request a password when an encrypted device or a remote "
"filesystem is mounted. If the password can be saved for future use a "
"'Remember Password' checkbox will be present. This key sets the default "
"state of the checkbox."
msgstr ""
"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 "
"oleku."
msgid "Show the week date in the calendar"
msgstr "Kalendris näidatakse kuupäeva nädalavormingus"
@ -169,25 +128,12 @@ msgstr "Rakenduste menüü avamise kiirklahv"
msgid "Keybinding to open the application menu."
msgstr "Kiirklahv rakenduste menüü avamiseks."
msgid "Keybinding to open the \"Show Applications\" view"
msgstr "\"Rakenduste vaate\" avamise kiirklahv"
msgid ""
"Keybinding to open the \"Show Applications\" view of the Activities Overview."
msgstr "\"Rakenduste vaate\" avamise kiirklahv tegevuste ülevaates."
msgid "Keybinding to toggle the visibility of the message tray"
msgstr "Teateala nähtavuse muutmise kiirklahv"
msgid "Keybinding to toggle the visibility of the message tray."
msgstr "Kiirklahv teateala nähtavuse muutmiseks."
msgid "Keybinding to focus the active notification"
msgstr "Aktiivse teate fokuseerimise kiirklahv"
msgid "Keybinding to focus the active notification."
msgstr "Aktiivse teate fokuseerimise kiirklahv."
msgid "Keybinding to toggle the screen recorder"
msgstr "Erkaanilindistaja lülitamise kiirklahv"
@ -249,46 +195,6 @@ msgstr ""
"konteinervormingusse salvestades tuleks ka sellele vormingule vastav laiend "
"määrata."
msgid "The application icon mode."
msgstr "Rakenduste ikooni režiim."
msgid ""
"Configures how the windows are shown in the switcher. Valid possibilities "
"are 'thumbnail-only' (shows a thumbnail of the window), 'app-icon-"
"only' (shows only the application icon) or 'both'."
msgstr ""
"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)."
msgid "Attach modal dialog to the parent window"
msgstr "Modaaldialoog kuulub vanemakna juurde"
msgid ""
"This key overrides the key in org.gnome.mutter when running GNOME Shell."
msgstr ""
"See võti on ülimuslik võtme org.gnome.mutter suhtes, kui kasutatakse GNOME "
"Shelli."
msgid "Arrangement of buttons on the titlebar"
msgstr "Nuppude järjekord tiitliribal"
msgid ""
"This key overrides the key in org.gnome.desktop.wm.preferences when running "
"GNOME Shell."
msgstr ""
"See võti on ülimuslik võtme org.gnome.desktop.wm.preferences suhtes, kui "
"kasutatakse GNOME Shelli."
msgid "Enable edge tiling when dropping windows on screen edges"
msgstr "Akende lohistamisel ekraani serva lubatakse serva paigutamine"
msgid "Workspaces are managed dynamically"
msgstr "Tööalasid hallatakse dünaamiliselt"
msgid "Workspaces only on primary monitor"
msgstr "Tööalad peamisel monitoril"
#, c-format
msgid "There was an error loading the preferences dialog for %s:"
msgstr "%s jaoks eelistuste dialoogi laadimisel esines viga:"
@ -319,22 +225,9 @@ msgctxt "button"
msgid "Sign In"
msgstr "Logi sisse"
msgid "Next"
msgstr "Järgmine"
#. TTLS and PEAP are actually much more complicated, but this complication
#. is not visible here since we only care about phase2 authentication
#. (and don't even care of which one)
msgid "Username: "
msgstr "Kasutajanimi: "
msgid "Login Window"
msgstr "Sisselogimisaken"
#. Translators: accessible name of the power menu in the login screen
msgid "Power"
msgstr "Vool"
msgid "Suspend"
msgstr "Uinak"
@ -544,6 +437,12 @@ msgstr "Parool: "
msgid "Key: "
msgstr "Võti: "
#. TTLS and PEAP are actually much more complicated, but this complication
#. is not visible here since we only care about phase2 authentication
#. (and don't even care of which one)
msgid "Username: "
msgstr "Kasutajanimi: "
msgid "Identity: "
msgstr "Identiteet: "
@ -622,8 +521,11 @@ msgstr "Helista"
msgid "File Transfer"
msgstr "Failiülekanne"
msgid "Chat"
msgstr "Vestlus"
msgid "Subscription request"
msgstr "Tellimuse päring"
msgid "Connection error"
msgstr "Ühenduse viga"
msgid "Unmute"
msgstr "Heli peale"
@ -631,25 +533,24 @@ msgstr "Heli peale"
msgid "Mute"
msgstr "Heli maha"
#. Translators: this is the word "Yesterday" followed by a time string. i.e. "Yesterday, 14:30"
#. Translators: this is a time format string followed by a date.
#. If applicable, replace %X with a strftime format valid for your
#. locale, without seconds.
#, no-c-format
msgid "<b>Yesterday</b>, <b>%H:%M</b>"
msgstr "<b>Eile</b> <b>%H:%M</b>"
msgid "Sent at <b>%X</b> on <b>%A</b>"
msgstr "Saadetud: <b>%A</b>, <b>%X</b>"
#. Translators: this is the week day name followed by a time string. i.e. "Monday, 14:30
#. Translators: this is a time format in the style of "Wednesday, May 25",
#. shown when you get a chat message in the same year.
#, no-c-format
msgid "<b>%A</b>, <b>%H:%M</b>"
msgstr "<b>%A</b>, <b>%H:%M</b>"
msgid "Sent on <b>%A</b>, <b>%B %d</b>"
msgstr "Saadeti <b>%A</b>, <b>%B %d</b>"
#. Translators: this is the month name and day number followed by a time string. i.e. "May 25, 14:30"
#. Translators: this is a time format in the style of "Wednesday, May 25, 2012",
#. shown when you get a chat message in a different year.
#, no-c-format
msgid "<b>%B</b> <b>%d</b>, <b>%H:%M</b>"
msgstr "<b>%d. %B</b>, <b>%H:%M</b>"
#. Translators: this is the month name, day number, year number followed by a time string. i.e. "May 25 2012, 14:30"
#, no-c-format
msgid "<b>%B</b> <b>%d</b> <b>%Y</b>, <b>%H:%M</b> "
msgstr "<b>%d. %B %Y</b>, <b>%H:%M</b>"
msgid "Sent on <b>%A</b>, <b>%B %d</b>, %Y"
msgstr "Saadeti <b>%A</b>, <b>%B %d</b>, %Y"
#. Translators: this is the other person changing their old IM name to their new
#. IM name.
@ -686,6 +587,9 @@ msgstr "%s tahab alustada videokõnet"
msgid "Call from %s"
msgstr "%s helistab"
msgid "Reject"
msgstr "Lükka tagasi"
#. translators: this is a button label (verb), not a noun
msgid "Answer"
msgstr "Vasta"
@ -786,18 +690,18 @@ msgstr "Sisemine viga"
#. translators: argument is the account name, like
#. * name@jabber.org for example.
#, c-format
msgid "Unable to connect to %s"
msgstr "Pole võimalik ühenduda võrguga %s"
msgid "Connection to %s failed"
msgstr "Ühendus %s nurjus"
msgid "View account"
msgstr "Konto kuvamine"
msgid "Reconnect"
msgstr "Ühendu uuesti"
msgid "Edit account"
msgstr "Konto muutmine"
msgid "Unknown reason"
msgstr "Põhjus teadmata"
msgid "Windows"
msgstr "Aknad"
msgid "Show Applications"
msgstr "Rakenduste kuvamine"
@ -920,6 +824,8 @@ msgstr "Näita vigu"
msgid "Enabled"
msgstr "Lubatud"
#. translators:
#. * The device has been disabled
msgid "Disabled"
msgstr "Keelatud"
@ -944,9 +850,6 @@ msgstr "Ava"
msgid "Remove"
msgstr "Eemalda"
msgid "No Messages"
msgstr "Teateid pole"
msgid "Message Tray"
msgstr "Teateala"
@ -994,11 +897,8 @@ msgstr "Ülemine riba"
msgid "toggle-switch-us"
msgstr "toggle-switch-intl"
msgid "Enter a Command"
msgstr "Palun sisesta käsk"
msgid "Close"
msgstr "Sulge"
msgid "Please enter a command:"
msgstr "Palun sisesta käsk:"
#. Translators: This is a time format for a date in
#. long format
@ -1017,9 +917,6 @@ msgid_plural "%d new notifications"
msgstr[0] "%d uus märguanne"
msgstr[1] "%d uut märguannet"
msgid "Lock"
msgstr "Lukusta"
msgid "Searching..."
msgstr "Otsimine..."
@ -1114,6 +1011,16 @@ msgstr "ühendumine..."
msgid "Send Files..."
msgstr "Failide saatmine..."
msgid "Browse Files..."
msgstr "Failide sirvimine..."
msgid "Error browsing device"
msgstr "Viga seadme sirvimisel"
#, c-format
msgid "The requested device cannot be browsed, error is '%s'"
msgstr "Küsitud seadet pole võimalik sirvida, viga on '%s'"
msgid "Keyboard Settings"
msgstr "Klaviatuurisätted"
@ -1137,10 +1044,6 @@ msgstr "Luba alati"
msgid "Grant this time only"
msgstr "Luba ainult seekord"
msgid "Reject"
msgstr "Lükka tagasi"
#. Translators: argument is the device short name
#, c-format
msgid "Pairing confirmation for %s"
msgstr "Paardumise kinnitus seadmele %s"
@ -1153,7 +1056,6 @@ msgstr "Seade '%s' tahab selle arvutiga paarduda"
msgid "Please confirm whether the PIN '%06d' matches the one on the device."
msgstr "Palun kontrolli, kas PIN-kood '%06d' kattub seadme parooliga."
#. Translators: this is the verb, not the noun
msgid "Matches"
msgstr "Kattub"
@ -1243,8 +1145,17 @@ msgstr "Automaatne juhtmeta ühendus"
msgid "Enable networking"
msgstr "Luba võrguühendused"
msgid "Wi-Fi"
msgstr "Wi-Fi"
msgid "Wired"
msgstr "Juhtmega"
msgid "Wireless"
msgstr "Juhtmeta"
msgid "Mobile broadband"
msgstr "Mobiiliühendus"
msgid "VPN Connections"
msgstr "VPN-ühendused"
msgid "Network Settings"
msgstr "Võrgusätted"
@ -1348,9 +1259,6 @@ msgstr "Mikrofon"
msgid "Log in as another user"
msgstr "Logi sisse teise kasutajana"
msgid "Unlock Window"
msgstr "Võta aken lukust lahti"
msgid "Available"
msgstr "Saadaval"
@ -1366,21 +1274,27 @@ msgstr "Eemal"
msgid "Idle"
msgstr "Jõude"
msgid "Offline"
msgstr "Ühendamata"
msgid "Notifications"
msgstr "Märguanded"
msgid "Settings"
msgstr "Sätted"
msgid "Unavailable"
msgstr "Pole saadaval"
msgid "Switch User"
msgstr "Vaheta kasutajat"
msgid "Switch Session"
msgstr "Vaheta seanssi"
msgid "Notifications"
msgstr "Märguanded"
msgid "System Settings"
msgstr "Süsteemi sätted"
msgid "Log Out"
msgstr "Logi välja"
msgid "Lock"
msgstr "Lukusta"
msgid "Install Updates & Restart"
msgstr "Paigalda uuendused ja taaskäivita"
@ -1394,6 +1308,9 @@ msgstr ""
"Märguanded on nüüd keelatud, sealhulgas vestlusteated. Sinu netiolekut "
"muudeti, et teised teaksid, et sa ei pruugi nende teateid näha."
msgid "Windows"
msgstr "Aknad"
msgid "Applications"
msgstr "Rakendused"
@ -1422,6 +1339,25 @@ msgstr "'%s' on valmis"
msgid "Evolution Calendar"
msgstr "Evolutioni kalender"
#. translators:
#. * The number of sound outputs on a particular device
#, c-format
msgid "%u Output"
msgid_plural "%u Outputs"
msgstr[0] "%u väljund"
msgstr[1] "%u väljundit"
#. translators:
#. * The number of sound inputs on a particular device
#, c-format
msgid "%u Input"
msgid_plural "%u Inputs"
msgstr[0] "%u sisend"
msgstr[1] "%u sisendit"
msgid "System Sounds"
msgstr "Süsteemi helid"
msgid "Print version"
msgstr "Printimise versioon"
@ -1453,46 +1389,6 @@ msgstr "Vaikimisi"
msgid "Authentication dialog was dismissed by the user"
msgstr "Kasutaja katkestas autentimisdialoogi"
#~ msgid "Subscription request"
#~ msgstr "Tellimuse päring"
#~ msgid "Connection error"
#~ msgstr "Ühenduse viga"
#~ msgid "<b>%H:%M</b> on Yesterday"
#~ msgstr "Eile <b>%H:%M</b>"
#~ msgid "<b>%H:%M</b> on <b>%A</b>, <b>%B</b> <b>%d</b>, %Y"
#~ msgstr "<b>%H:%M</b>, <b>%A</b>, <b>%d. %B</b> %Y"
#~ msgid "Connection to %s failed"
#~ msgstr "Ühendus %s nurjus"
#~ msgid "Reconnect"
#~ msgstr "Ühendu uuesti"
#~ msgid "Wired"
#~ msgstr "Juhtmega"
#~ msgid "Wireless"
#~ msgstr "Juhtmeta"
#~ msgid "Mobile broadband"
#~ msgstr "Mobiiliühendus"
#~ msgid "%u Output"
#~ msgid_plural "%u Outputs"
#~ msgstr[0] "%u väljund"
#~ msgstr[1] "%u väljundit"
#~ msgid "%u Input"
#~ msgid_plural "%u Inputs"
#~ msgstr[0] "%u sisend"
#~ msgstr[1] "%u sisendit"
#~ msgid "System Sounds"
#~ msgstr "Süsteemi helid"
#~ msgid "disabled OpenSearch providers"
#~ msgstr "keelatud OpenSearch pakkujad"
@ -1508,6 +1404,9 @@ msgstr "Kasutaja katkestas autentimisdialoogi"
#~ msgid "If true, display date in the clock, in addition to time."
#~ msgstr "Kui määratud, siis kuvatakse kellaaja kõrval ka kuupäeva."
#~ msgid "Offline"
#~ msgstr "Ühendamata"
#~ msgid "CONTACTS"
#~ msgstr "KONTAKTID"

821
po/gl.po

File diff suppressed because it is too large Load Diff

698
po/he.po

File diff suppressed because it is too large Load Diff

873
po/hu.po

File diff suppressed because it is too large Load Diff

1832
po/kk.po

File diff suppressed because it is too large Load Diff

418
po/kn.po
View File

@ -8,8 +8,8 @@ msgstr ""
"Project-Id-Version: gnome-shell master\n"
"Report-Msgid-Bugs-To: http://bugzilla.gnome.org/enter_bug.cgi?product=gnome-"
"shell&keywords=I18N+L10N&component=general\n"
"POT-Creation-Date: 2012-12-07 10:16+0000\n"
"PO-Revision-Date: 2012-12-07 16:12+0530\n"
"POT-Creation-Date: 2012-09-19 11:02+0000\n"
"PO-Revision-Date: 2012-09-26 16:05+0530\n"
"Last-Translator: Shankar Prasad <svenkate@redhat.com>\n"
"Language-Team: Kannada <kn@li.org>\n"
"Language: kn\n"
@ -17,7 +17,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n!=1);\n"
"X-Generator: Lokalize 1.5\n"
"X-Generator: Lokalize 1.2\n"
#: ../data/50-gnome-shell-screenshot.xml.in.h:1
msgid "Screenshots"
@ -25,15 +25,16 @@ msgstr "ತೆರೆಚಿತ್ರಗಳು"
#: ../data/50-gnome-shell-screenshot.xml.in.h:2
msgid "Record a screencast"
msgstr "ಒಂದು ಸ್ಕ್ರೀನ್‌ಕ್ಯಾಸ್ಟನ್ನು ರೆಕಾರ್ಡು ಮಾಡಿ"
msgstr ""
#: ../data/50-gnome-shell-system.xml.in.h:1
#| msgid "File System"
msgid "System"
msgstr "ವ್ಯವಸ್ಥೆ"
#: ../data/50-gnome-shell-system.xml.in.h:2
msgid "Show the message tray"
msgstr "ಸಂದೇಶ ಟ್ರೇ ಅನ್ನು ತೋರಿಸು"
msgstr ""
#: ../data/gnome-shell.desktop.in.in.h:1
msgid "GNOME Shell"
@ -78,12 +79,6 @@ msgid ""
"list. You can also manipulate this list with the EnableExtension and "
"DisableExtension DBus methods on org.gnome.Shell."
msgstr ""
"GNOME ಶೆಲ್ ವಿಸ್ತರಣೆಗಳು ಒಂದು uuid ಗುಣವನ್ನು ಹೊಂದಿವೆ; ಈ ಕೀಲಿ ಪಟ್ಟಿಯು ಲೋಡ್ "
"ಮಾಡಬೇಕಿರುವ "
"ವಿಸ್ತರಣೆಗಳ ಪಟ್ಟಿಯನ್ನು ತೋರಿಸುತ್ತದೆ. ಯಾವುದೆ ವಿಸ್ತರಣೆಗಳನ್ನು ಲೋಡ್‌ ಮಾಡಬೇಕಿದ್ದಲ್ಲಿ "
"ಅದು ಈ "
"ಪಟ್ಟಿಯಲ್ಲಿ ಇರುವುದು ಅತ್ಯಗತ್ಯ. org.gnome.Shell ನಲ್ಲಿ EnableExtension ಮತ್ತು "
"DisableExtension DBus ವಿಧಾನಗಳನ್ನು ಬಳಸಿಕೊಂಡೂ ಸಹ ಈ ಪಟ್ಟಿಯನ್ನು ನಿರ್ವಹಿಸಬಹುದು."
#: ../data/org.gnome.shell.gschema.xml.in.in.h:5
msgid "Whether to collect stats about applications usage"
@ -96,11 +91,6 @@ msgid ""
"want to disable this for privacy reasons. Please note that doing so won't "
"remove already saved data."
msgstr ""
"ಶೆಲ್‌ ಸಾಮಾನ್ಯವಾಗಿ ಹೆಚ್ಚಾಗಿ ಬಳಸಲಾದ (ಉದಾ. ಆರಂಭಕಗಳಲ್ಲಿ) ಅನ್ವಯಗಳನ್ನು ತೋರಿಸಲು "
"ಸಕ್ರಿಯವಾದವುಗಳನ್ನು ಮೇಲ್ವಿಚಾರಣೆ ನಡೆಸುತ್ತದೆ. ಈ ದತ್ತಾಂಶವನ್ನು ಗೌಪ್ಯವಾಗಿ "
"ಇರಿಸಲಾಗುತ್ತದೆ, "
"ಹಾಗೂ ಗೌಪ್ಯತಾ ಕಾರಣಗಳಿದ್ದಲ್ಲಿ ನೀವು ಅದನ್ನು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಬಹುದು. ಹಾಗೆ ಮಾಡುವುದರಿಂದ "
"ಉಳಿಸಲಾದ ಯಾವದೆ ದತ್ತಾಂಶವು ತೆಗೆದುಹಾಕಲ್ಪಡುವುದಿಲ್ಲ ಎನ್ನುವುದನ್ನು ನೆನಪಿಡಿ."
#: ../data/org.gnome.shell.gschema.xml.in.in.h:7
msgid "List of desktop file IDs for favorite applications"
@ -126,75 +116,64 @@ msgid ""
"Internally used to store the last IM presence explicitly set by the user. "
"The value here is from the TpConnectionPresenceType enumeration."
msgstr ""
"ಆಂತರಿಕವಾಗಿ ಬಳಕೆದಾರರಿಂದ ಸ್ಪಷ್ಟವಾಗಿ ಹೊಂದಿಸಲಾದ ಕೊನೆಯ IM ಅನ್ನು ಶೇಖರಿಸಿಡಸಲು "
"ಬಳಸಲಾಗುತ್ತದೆ. ಇಲ್ಲಿರುವ ಮೌಲ್ಯವು TpConnectionPresenceType ಎನ್ಯೂಮರೇಶನ್‌ನಿಂದ "
"ಬಂದಿರುತ್ತದೆ."
#: ../data/org.gnome.shell.gschema.xml.in.in.h:12
msgid ""
"Internally used to store the last session presence status for the user. The "
"value here is from the GsmPresenceStatus enumeration."
msgstr ""
"ಆಂತರಿಕವಾಗಿ ಬಳಕೆದಾರರಿಂದ ಸ್ಪಷ್ಟವಾಗಿ ಹೊಂದಿಸಲಾದ ಕೊನೆಯ ಅಧಿವೇಶನವನ್ನು ಶೇಖರಿಸಿಡಸಲು "
"ಬಳಸಲಾಗುತ್ತದೆ. ಇಲ್ಲಿರುವ ಮೌಲ್ಯವು GsmPresenceStatus ಎನ್ಯೂಮರೇಶನ್‌ನಿಂದ ಬಂದಿರುತ್ತದೆ."
#: ../data/org.gnome.shell.gschema.xml.in.in.h:13
msgid "Always show the 'Log out' menuitem in the user menu."
msgstr "ಯಾವಾಗಲೂ 'ನಿರ್ಗಮಿಸು' ಪರಿವಿಡಿಅಂಶವನ್ನು ಬಳಕೆದಾರ ಪರಿವಿಡಿಯಲ್ಲಿ ತೋರಿಸು."
#: ../data/org.gnome.shell.gschema.xml.in.in.h:14
msgid ""
"This key overrides the automatic hiding of the 'Log out' menuitem in single-"
"user, single-session situations."
msgstr ""
"ಈ ಕೀಲಿಯು ಏಕ-ಬಳಕೆದಾರ, ಏಕ-ಅಧಿವೇಶನ ಸಂದರ್ಭಗಳಲ್ಲಿ 'ನಿರ್ಗಮಿಸು' ಪರಿವಿಡಿಅಂಶವನ್ನು "
"ಸ್ವಯಂಚಾಲಿತವಾಗಿ ಅಡಗಿಸುವ ಆಯ್ಕೆಯನ್ನು ಅತಿಕ್ರಮಿಸುತ್ತದೆ."
#: ../data/org.gnome.shell.gschema.xml.in.in.h:15
msgid "Show the week date in the calendar"
msgstr "ಕ್ಯಾಲೆಂಡರಿನಲ್ಲಿ ವಾರದ ದಿನವನ್ನು ತೋರಿಸು"
#: ../data/org.gnome.shell.gschema.xml.in.in.h:16
#: ../data/org.gnome.shell.gschema.xml.in.in.h:14
msgid "If true, display the ISO week date in the calendar."
msgstr "true ಆದಲ್ಲಿ, ಕ್ಯಾಲೆಂಡರಿನಲ್ಲಿ ISO ವಾರದ ದಿನವನ್ನು ತೋರಿಸುತ್ತದೆ."
#: ../data/org.gnome.shell.gschema.xml.in.in.h:17
#: ../data/org.gnome.shell.gschema.xml.in.in.h:15
msgid "Keybinding to open the application menu"
msgstr "ಅನ್ವಯಗಳ ಮೆನುವನ್ನು ತೆರೆಯಬೇಕಿರುವ ಕೀಲಿಬೈಂಡಿಂಗ್"
#: ../data/org.gnome.shell.gschema.xml.in.in.h:18
#: ../data/org.gnome.shell.gschema.xml.in.in.h:16
msgid "Keybinding to open the application menu."
msgstr "ಅನ್ವಯಗಳ ಮೆನುವನ್ನು ತೆರೆಯಬೇಕಿರುವ ಕೀಲಿಬೈಂಡಿಂಗ್."
#: ../data/org.gnome.shell.gschema.xml.in.in.h:19
#: ../data/org.gnome.shell.gschema.xml.in.in.h:17
msgid "Keybinding to toggle the visibility of the message tray"
msgstr "ಸಂದೇಶ ಟ್ರೇಯ ಗೋಚರಿಕೆಯನ್ನು ಹೊರಳಿಸಲು ಕೀಬೈಂಡಿಂಗ್"
msgstr ""
#: ../data/org.gnome.shell.gschema.xml.in.in.h:18
#, fuzzy
#| msgid "Keybinding to open the application menu."
msgid "Keybinding to toggle the visibility of the message tray."
msgstr "ಅನ್ವಯಗಳ ಮೆನುವನ್ನು ತೆರೆಯಬೇಕಿರುವ ಕೀಲಿಬೈಂಡಿಂಗ್."
#: ../data/org.gnome.shell.gschema.xml.in.in.h:19
#, fuzzy
#| msgid "Keybinding to open the application menu"
msgid "Keybinding to toggle the screen recorder"
msgstr "ಅನ್ವಯಗಳ ಮೆನುವನ್ನು ತೆರೆಯಬೇಕಿರುವ ಕೀಲಿಬೈಂಡಿಂಗ್"
#: ../data/org.gnome.shell.gschema.xml.in.in.h:20
msgid "Keybinding to toggle the visibility of the message tray."
msgstr "ಸಂದೇಶ ಟ್ರೇಯ ಗೋಚರಿಕೆಯನ್ನು ಹೊರಳಿಸಲು ಕೀಬೈಂಡಿಂಗ್."
#, fuzzy
#| msgid "Keybinding to open the application menu."
msgid "Keybinding to start/stop the builtin screen recorder."
msgstr "ಅನ್ವಯಗಳ ಮೆನುವನ್ನು ತೆರೆಯಬೇಕಿರುವ ಕೀಲಿಬೈಂಡಿಂಗ್."
#: ../data/org.gnome.shell.gschema.xml.in.in.h:21
msgid "Keybinding to toggle the screen recorder"
msgstr "ತೆರೆ ರೆಕಾರ್ಡರ್ ಅನ್ನು ಹೊರಳಿಸಲು ಕೀಬೈಂಡಿಂಗ್"
#: ../data/org.gnome.shell.gschema.xml.in.in.h:22
msgid "Keybinding to start/stop the builtin screen recorder."
msgstr "ಒಳನಿರ್ಮಿತ ತೆರೆ ರೆಕಾರ್ಡರ್ ಅನ್ನು ಆರಂಭಿಸಲು/ನಿಲ್ಲಿಸಲು ಕೀಬೈಂಡಿಂಗ್."
#: ../data/org.gnome.shell.gschema.xml.in.in.h:23
msgid "Which keyboard to use"
msgstr "ಯಾವ ಕೀಲಿಮಣೆಯನ್ನು ಬಳಸಬೇಕಿದೆ"
#: ../data/org.gnome.shell.gschema.xml.in.in.h:24
#: ../data/org.gnome.shell.gschema.xml.in.in.h:22
msgid "The type of keyboard to use."
msgstr "ಬಳಸಬೇಕಿರುವ ಕೀಲಿಮಣೆಯ ಬಗೆ."
#: ../data/org.gnome.shell.gschema.xml.in.in.h:25
#: ../data/org.gnome.shell.gschema.xml.in.in.h:23
msgid "Framerate used for recording screencasts."
msgstr "ಸ್ಕ್ರೀನ್‌ಕ್ಯಾಸ್ಟುಗಳನ್ನು ರೆಕಾರ್ಡು ಮಾಡಲು ಬಳಸಲಾಗುವ ಫ್ರೇಮ್‌ದರಗಳು."
#: ../data/org.gnome.shell.gschema.xml.in.in.h:26
#: ../data/org.gnome.shell.gschema.xml.in.in.h:24
msgid ""
"The framerate of the resulting screencast recordered by GNOME Shell's "
"screencast recorder in frames-per-second."
@ -203,11 +182,11 @@ msgstr ""
"ರೆಕಾರ್ಡು ಮಾಡಲಾದ "
"ಸ್ಕ್ರೀನ್‌ಕ್ಯಾಸ್ಟಿನ ಫ್ರೇಮ್‌ದರ. "
#: ../data/org.gnome.shell.gschema.xml.in.in.h:27
#: ../data/org.gnome.shell.gschema.xml.in.in.h:25
msgid "The gstreamer pipeline used to encode the screencast"
msgstr "ಸ್ಕ್ರೀನ್‌ಕ್ಯಾಸ್ಟ್‍ ಅನ್ನು ಎನ್ಕೋಡ್ ಮಾಡಲು ಬಳಸಲಾಗುವ gstreamer ಪೈಪ್‌ಲೈನ್"
#: ../data/org.gnome.shell.gschema.xml.in.in.h:29
#: ../data/org.gnome.shell.gschema.xml.in.in.h:27
#, no-c-format
msgid ""
"Sets the GStreamer pipeline used to encode recordings. It follows the syntax "
@ -221,31 +200,12 @@ msgid ""
"threads=%T ! queue ! webmmux' and records to WEBM using the VP8 codec. %T is "
"used as a placeholder for a guess at the optimal thread count on the system."
msgstr ""
"ರೆಕಾರ್ಡಿಂಗ್‌ಗಳನ್ನು ಎನ್ಕೋಡ್ ಮಾಡಲು ಬಳಸಲಾದ GStreamer ಪೈಪ್‌ಲೈನ್‌ ಅನ್ನು "
"ಹೊಂದಿಸುತ್ತದೆ. ಇದು gst-"
"launch ನಲ್ಲಿ ಬಳಸಲಾದ ಸಿಂಟ್ಯಾಕ್ಸನ್ನು ಅನುಸರಿಸುತ್ತದೆ. ಪೈಪ್‌ಲೈನ್ ವಿಡಿಯೊವನ್ನು "
"ರೆಕಾರ್ಡು ಮಾಡಲು "
"ಒಂದು ನಿಯೋಜಿಸದೇ ಇರುವ ಸಿಂಕ್‌ಪ್ಯಾಡ್‌ಗೆ ಸಂಪರ್ಕಿತಗೊಂಡಿರಬೇಕು. ಇದು ಸಾಮಾನ್ಯವಾಗಿ "
"ಸಂಪರ್ಕಿತಗೊಂಡಿರದೆ ಇರುವ ಪೈಪ್‌ಲೈನ್ ಅನ್ನು ಹೊಂದಿರುತ್ತದೆ; ಆ ಪ್ಯಾಡ್‌ನಿಂದ ಔಟ್‌ಪುಟ್ "
"ಅನ್ನು ಔಟ್‌ಪುಟ್ "
"ಕಡತಕ್ಕೆ ಬರೆಯಲಾಗುತ್ತದೆ. ಆದರೆ ಪೈಪ್‌ಲೈನ್ ತನ್ನದೆ ಆದ ಔಟ್‌ಪುಟ್ ಅನ್ನು "
"ನೋಡಿಕೊಳ್ಳಬಲ್ಲದು - "
"shout2send ಅಥವ ಅದೇ ರೀತಿಯದರ ಮೂಲಕ icecast ಪೂರೈಕೆಗಣಕಕ್ಕೆ ಔಟ್‌ಪುಟ್ ಅನ್ನು ಕಳುಹಿಸಲು "
"ಇದನ್ನು ಬಳಸಬಹುದಾಗಿರುತ್ತದೆ. ಇದರ ಹೊಂದಿಕೆಯನ್ನು ರದ್ದುಗೊಳಿಸಿದಲ್ಲಿ ಅಥವ ಒಂದು ಖಾಲಿ "
"ಮೌಲ್ಯಕ್ಕೆ "
"ಹೊಂದಿಸಿದಲ್ಲಿ, ಪೂರ್ವನಿಯೋಜಿತ ಪೈಪ್‌ಲೈನ್ ಅನ್ನು ಬಳಸಲಾಗುತ್ತದೆ. ಇದು ಪ್ರಸ್ತುತ 'vp8enc "
"min_quantizer=13 max_quantizer=13 cpu-used=5 deadline=1000000 threads=%T ! "
"queue ! webmmux' ಆಗಿರುತ್ತದೆ ಮತ್ತು VP8 ಕೋಡೆಕ್ ಅನ್ನು ಬಳಸಿಕೊಂಡು WEBM ಅನ್ನು "
"ರೆಕಾರ್ಡು "
"ಮಾಡುತ್ತದೆ. %T ಎನ್ನು ವ್ಯವಸ್ತೆಯಲ್ಲಿನ ಸೂಕ್ತವಾದ ಎಳೆಯ ಎಣಿಕೆಯನ್ನು ಊಹಿಸಲು ಒಂದು "
"ಪ್ಲೇಸ್‌ಹೋಲ್ಡರ್ "
"ಆಗಿ ಬಳಸಲಾಗುತ್ತದೆ."
#: ../data/org.gnome.shell.gschema.xml.in.in.h:30
#: ../data/org.gnome.shell.gschema.xml.in.in.h:28
msgid "File extension used for storing the screencast"
msgstr "ಸ್ಕ್ರೀನ್‌ಕ್ಯಾಸ್ಟುಗಳನ್ನು ಶೇಖರಿಸಿಡಲು ಬಳಸಲಾಗುವ ಕಡತ ವಿಸ್ತರಣೆಗಳು"
#: ../data/org.gnome.shell.gschema.xml.in.in.h:31
#: ../data/org.gnome.shell.gschema.xml.in.in.h:29
msgid ""
"The filename for recorded screencasts will be a unique filename based on the "
"current date, and use this extension. It should be changed when recording to "
@ -262,6 +222,7 @@ msgid "There was an error loading the preferences dialog for %s:"
msgstr "%s ಗಾಗಿ ಆದ್ಯತೆಗಳ ಸಂವಾದವನ್ನು ಲೋಡ್ ಮಾಡುವಲ್ಲಿ ದೋಷ ಉಂಟಾಗಿದೆ:"
#: ../js/extensionPrefs/main.js:164
#| msgid "<b>Extension</b>"
msgid "Extension"
msgstr "ವಿಸ್ತರಣೆ"
@ -270,11 +231,11 @@ msgid "Select an extension to configure using the combobox above."
msgstr ""
"ಮೇಲಿನ ಸಂಯೋಜನಾಚೌಕವನ್ನು ಬಳಸಿಕೊಂಡು ಸಂರಚಿಸಬೇಕಿರುವ ಒಂದು ವಿಸ್ತರಣೆಯನ್ನು ಆರಿಸಿ."
#: ../js/gdm/loginDialog.js:529
#: ../js/gdm/loginDialog.js:526
msgid "Session..."
msgstr "ಅಧಿವೇಶನ..."
#: ../js/gdm/loginDialog.js:680
#: ../js/gdm/loginDialog.js:674
msgctxt "title"
msgid "Sign In"
msgstr "ಒಳ ಪ್ರವೇಶಿಸಿ"
@ -282,68 +243,55 @@ msgstr "ಒಳ ಪ್ರವೇಶಿಸಿ"
#. translators: this message is shown below the user list on the
#. login screen. It can be activated to reveal an entry for
#. manually entering the username.
#: ../js/gdm/loginDialog.js:740
#: ../js/gdm/loginDialog.js:741
msgid "Not listed?"
msgstr "ಪಟ್ಟಿಯಲ್ಲಿಲ್ಲವೆ?"
#: ../js/gdm/loginDialog.js:898 ../js/ui/components/networkAgent.js:137
#: ../js/gdm/loginDialog.js:894 ../js/ui/components/networkAgent.js:137
#: ../js/ui/components/polkitAgent.js:162 ../js/ui/endSessionDialog.js:373
#: ../js/ui/extensionDownloader.js:195 ../js/ui/shellMountOperation.js:396
#: ../js/ui/status/bluetooth.js:427 ../js/ui/unlockDialog.js:168
#: ../js/ui/status/bluetooth.js:427 ../js/ui/unlockDialog.js:166
msgid "Cancel"
msgstr "ರದ್ದು ಮಾಡು"
#: ../js/gdm/loginDialog.js:903
#: ../js/gdm/loginDialog.js:899
msgctxt "button"
msgid "Sign In"
msgstr "ಒಳಗೆ ಪ್ರವೇಶಿಸು"
#. TTLS and PEAP are actually much more complicated, but this complication
#. is not visible here since we only care about phase2 authentication
#. (and don't even care of which one)
#: ../js/gdm/loginDialog.js:962 ../js/ui/components/networkAgent.js:260
#: ../js/ui/components/networkAgent.js:278
msgid "Username: "
msgstr "ಬಳಕೆದಾರ ಹೆಸರು: "
#: ../js/gdm/loginDialog.js:1269
#: ../js/gdm/loginDialog.js:1238
msgid "Login Window"
msgstr "ಪ್ರವೇಶದ ಕಿಟಕಿ"
#. Translators: accessible name of the power menu in the login screen
#: ../js/gdm/powerMenu.js:35
#| msgid "Power Off"
msgid "Power"
msgstr "ವಿದ್ಯುಚ್ಛಕ್ತಿ"
#: ../js/gdm/powerMenu.js:89 ../js/ui/userMenu.js:664 ../js/ui/userMenu.js:668
#: ../js/ui/userMenu.js:779
#: ../js/gdm/powerMenu.js:88 ../js/ui/userMenu.js:658 ../js/ui/userMenu.js:662
#: ../js/ui/userMenu.js:773
msgid "Suspend"
msgstr "ಅಮಾನತ್ತಿನಲ್ಲಿಡು"
#: ../js/gdm/powerMenu.js:94
#: ../js/gdm/powerMenu.js:93
msgid "Restart"
msgstr "ಮರಳಿ ಆರಂಭಿಸು"
#: ../js/gdm/powerMenu.js:99 ../js/ui/userMenu.js:666 ../js/ui/userMenu.js:668
#: ../js/ui/userMenu.js:778
#: ../js/gdm/powerMenu.js:98 ../js/ui/userMenu.js:660 ../js/ui/userMenu.js:662
#: ../js/ui/userMenu.js:772
msgid "Power Off"
msgstr "ಸ್ಥಗಿತಗೊಳಿಸು"
#: ../js/gdm/util.js:152
#: ../js/gdm/util.js:148
#| msgid "Authentication Required"
msgid "Authentication error"
msgstr "ದೃಢೀಕರಣ ದೋಷ"
#. Translators: this message is shown below the password entry field
#. to indicate the user can swipe their finger instead
#: ../js/gdm/util.js:269
#: ../js/gdm/util.js:265
msgid "(or swipe finger)"
msgstr "(ಅಥವ ನಿಮ್ಮ ಬೆರಳನ್ನು ಉಜ್ಜಿ)"
#: ../js/gdm/util.js:294
#: ../js/gdm/util.js:290
#, c-format
msgid "(e.g., user or %s)"
msgstr "(ಉದಾ., ಬಳಕೆದಾರ ಅಥವ %s)"
msgstr ""
#: ../js/misc/util.js:92
msgid "Command not found"
@ -377,7 +325,7 @@ msgstr "SETTINGS"
msgid "New Window"
msgstr "ಹೊಸ ವಿಂಡೊ"
#: ../js/ui/appDisplay.js:678 ../js/ui/dash.js:290
#: ../js/ui/appDisplay.js:678 ../js/ui/dash.js:271
msgid "Remove from Favorites"
msgstr "ಎಲ್ಲಾ ಅಚ್ಚುಮೆಚ್ಚಿನವುಗಳನ್ನು ತೆಗೆದುಹಾಕು"
@ -541,16 +489,16 @@ msgstr "ಈ ವಾರ"
msgid "Next week"
msgstr "ಮುಂದಿನ ವಾರ"
#: ../js/ui/components/autorunManager.js:297
#: ../js/ui/components/autorunManager.js:278
msgid "Removable Devices"
msgstr "ತೆಗೆದುಹಾಕಬಹುದಾದ ಸಾಧನಗಳು"
#: ../js/ui/components/autorunManager.js:594
#: ../js/ui/components/autorunManager.js:575
#, c-format
msgid "Open with %s"
msgstr "%s ನೊಂದಿಗೆ ತೆರೆ"
#: ../js/ui/components/autorunManager.js:620
#: ../js/ui/components/autorunManager.js:601
msgid "Eject"
msgstr "ಹೊರತಳ್ಳು"
@ -580,6 +528,14 @@ msgstr "ದಾಟುಪದ: "
msgid "Key: "
msgstr "ಕೀಲಿ: "
#. TTLS and PEAP are actually much more complicated, but this complication
#. is not visible here since we only care about phase2 authentication
#. (and don't even care of which one)
#: ../js/ui/components/networkAgent.js:260
#: ../js/ui/components/networkAgent.js:278
msgid "Username: "
msgstr "ಬಳಕೆದಾರ ಹೆಸರು: "
#: ../js/ui/components/networkAgent.js:266
msgid "Identity: "
msgstr "ಗುರುತು: "
@ -690,7 +646,7 @@ msgstr "ಸಂಪರ್ಕ ದೋಷ"
#: ../js/ui/components/telepathyClient.js:491
msgid "Unmute"
msgstr "ಮಾತುಬರಿಸು"
msgstr ""
#: ../js/ui/components/telepathyClient.js:491
msgid "Mute"
@ -699,35 +655,35 @@ msgstr "ಮೂಕಗೊಳಿಸು"
#. Translators: this is a time format string followed by a date.
#. If applicable, replace %X with a strftime format valid for your
#. locale, without seconds.
#: ../js/ui/components/telepathyClient.js:952
#: ../js/ui/components/telepathyClient.js:948
#, no-c-format
msgid "Sent at <b>%X</b> on <b>%A</b>"
msgstr "<b>%A</b> ರಂದು <b>%X</b> ಗೆ ಕಳುಹಿಸಲಾಗಿದೆ"
#. Translators: this is a time format in the style of "Wednesday, May 25",
#. shown when you get a chat message in the same year.
#: ../js/ui/components/telepathyClient.js:958
#: ../js/ui/components/telepathyClient.js:954
#, no-c-format
msgid "Sent on <b>%A</b>, <b>%B %d</b>"
msgstr "<b>%A</b>, <b>%B %d</b> ರಂದು ಕಳುಹಿಸಲಾಗಿದೆ"
#. Translators: this is a time format in the style of "Wednesday, May 25, 2012",
#. shown when you get a chat message in a different year.
#: ../js/ui/components/telepathyClient.js:963
#: ../js/ui/components/telepathyClient.js:959
#, no-c-format
msgid "Sent on <b>%A</b>, <b>%B %d</b>, %Y"
msgstr "%A</b>, <b>%B %d</b>, %Y ರಂದು ಕಳುಹಿಸಲಾಗಿದೆ"
#. Translators: this is the other person changing their old IM name to their new
#. IM name.
#: ../js/ui/components/telepathyClient.js:992
#: ../js/ui/components/telepathyClient.js:988
#, c-format
msgid "%s is now known as %s"
msgstr "%s ಈಗ %s ಆಗಿದ್ದಾರೆ"
#. translators: argument is a room name like
#. * room@jabber.org for example.
#: ../js/ui/components/telepathyClient.js:1092
#: ../js/ui/components/telepathyClient.js:1088
#, c-format
msgid "Invitation to %s"
msgstr "%s ಗಾಗಿನ ಆಹ್ವಾನ"
@ -735,42 +691,42 @@ msgstr "%s ಗಾಗಿನ ಆಹ್ವಾನ"
#. translators: first argument is the name of a contact and the second
#. * one the name of a room. "Alice is inviting you to join room@jabber.org
#. * for example.
#: ../js/ui/components/telepathyClient.js:1100
#: ../js/ui/components/telepathyClient.js:1096
#, c-format
msgid "%s is inviting you to join %s"
msgstr "%s ನಿಮ್ಮನ್ನು %s ಗೆ ಸೇರುವಂತೆ ಆಹ್ವಾನಿಸುತ್ತಿದ್ದಾರೆ"
#: ../js/ui/components/telepathyClient.js:1102
#: ../js/ui/components/telepathyClient.js:1181
#: ../js/ui/components/telepathyClient.js:1244
#: ../js/ui/components/telepathyClient.js:1098
#: ../js/ui/components/telepathyClient.js:1177
#: ../js/ui/components/telepathyClient.js:1240
msgid "Decline"
msgstr "ತಿರಸ್ಕರಿಸು"
#: ../js/ui/components/telepathyClient.js:1103
#: ../js/ui/components/telepathyClient.js:1182
#: ../js/ui/components/telepathyClient.js:1245
#: ../js/ui/components/telepathyClient.js:1099
#: ../js/ui/components/telepathyClient.js:1178
#: ../js/ui/components/telepathyClient.js:1241
msgid "Accept"
msgstr "ಅಂಗೀಕರಿಸು"
#. translators: argument is a contact name like Alice for example.
#: ../js/ui/components/telepathyClient.js:1133
#: ../js/ui/components/telepathyClient.js:1129
#, c-format
msgid "Video call from %s"
msgstr "%s ಇಂದ ವೀಡಿಯೊ ಕರೆ ಬಂದಿದೆ"
#. translators: argument is a contact name like Alice for example.
#: ../js/ui/components/telepathyClient.js:1136
#: ../js/ui/components/telepathyClient.js:1132
#, c-format
msgid "Call from %s"
msgstr "%s ಇಂದ ಕರೆ ಬಂದಿದೆ"
#: ../js/ui/components/telepathyClient.js:1141
#: ../js/ui/components/telepathyClient.js:1137
#: ../js/ui/status/bluetooth.js:346
msgid "Reject"
msgstr "ತಿರಸ್ಕರಿಸು"
#. translators: this is a button label (verb), not a noun
#: ../js/ui/components/telepathyClient.js:1143
#: ../js/ui/components/telepathyClient.js:1139
msgid "Answer"
msgstr "ಉತ್ತರ"
@ -779,106 +735,106 @@ msgstr "ಉತ್ತರ"
#. * file name. The string will be something
#. * like: "Alice is sending you test.ogg"
#.
#: ../js/ui/components/telepathyClient.js:1175
#: ../js/ui/components/telepathyClient.js:1171
#, c-format
msgid "%s is sending you %s"
msgstr "%s ರವರು ನಿಮಗೆ %s ಅನ್ನು ಕಳುಹಿಸುತ್ತಿದ್ದಾರೆ"
#. To translators: The parameter is the contact's alias
#: ../js/ui/components/telepathyClient.js:1210
#: ../js/ui/components/telepathyClient.js:1206
#, c-format
msgid "%s would like permission to see when you are online"
msgstr ""
"ನೀವು ಯಾವಾಗ ಆನ್‌ಲೈನ್‌ನಲ್ಲಿ ಇರುತ್ತೀರಿ ಎಂದು ತಿಳಿಯಲು %s ರವರು ನಿಮ್ಮ ಅನುಮತಿಯನ್ನು "
"ಕೋರಿದ್ದಾರೆ"
#: ../js/ui/components/telepathyClient.js:1302
#: ../js/ui/components/telepathyClient.js:1298
msgid "Network error"
msgstr "ಜಾಲಬಂಧದ ದೋಷ"
#: ../js/ui/components/telepathyClient.js:1304
#: ../js/ui/components/telepathyClient.js:1300
msgid "Authentication failed"
msgstr "ದೃಢೀಕರಣವು ವಿಫಲಗೊಂಡಿದೆ"
#: ../js/ui/components/telepathyClient.js:1306
#: ../js/ui/components/telepathyClient.js:1302
msgid "Encryption error"
msgstr "ಗೂಢಲಿಪೀಕರಣ ದೋಷ"
#: ../js/ui/components/telepathyClient.js:1308
#: ../js/ui/components/telepathyClient.js:1304
msgid "Certificate not provided"
msgstr "ಪ್ರಮಾಣಪತ್ರವನ್ನು ಒದಗಿಸಲಾಗಿಲ್ಲ"
#: ../js/ui/components/telepathyClient.js:1310
#: ../js/ui/components/telepathyClient.js:1306
msgid "Certificate untrusted"
msgstr "ಪ್ರಮಾಣಪತ್ರವನ್ನು ನಂಬಲಾಗಿಲ್ಲ"
#: ../js/ui/components/telepathyClient.js:1312
#: ../js/ui/components/telepathyClient.js:1308
msgid "Certificate expired"
msgstr "ಪ್ರಮಾಣಪತ್ರದ ಕಾಲಾವಧಿ ತೀರಿದೆ"
#: ../js/ui/components/telepathyClient.js:1314
#: ../js/ui/components/telepathyClient.js:1310
msgid "Certificate not activated"
msgstr "ಪ್ರಮಾಣಪತ್ರವು ಸಕ್ರಿಯಗೊಂಡಿಲ್ಲ"
#: ../js/ui/components/telepathyClient.js:1316
#: ../js/ui/components/telepathyClient.js:1312
msgid "Certificate hostname mismatch"
msgstr "ಪ್ರಮಾಣಪತ್ರದ ಅತಿಥೇಯದ ಹೆಸರು ತಾಳೆಯಾಗುತ್ತಿಲ್ಲ"
#: ../js/ui/components/telepathyClient.js:1318
#: ../js/ui/components/telepathyClient.js:1314
msgid "Certificate fingerprint mismatch"
msgstr "ಪ್ರಮಾಣಪತ್ರದ ಫಿಂಗರ್‌ಪ್ರಿಂಟ್ ತಾಳೆಯಾಗುತ್ತಿಲ್ಲ"
#: ../js/ui/components/telepathyClient.js:1320
#: ../js/ui/components/telepathyClient.js:1316
msgid "Certificate self-signed"
msgstr "ಪ್ರಮಾಣಪತ್ರವು ಸ್ವತಃ ಸೈನ್ ಮಾಡಲ್ಪಟ್ಟಿದೆ"
#: ../js/ui/components/telepathyClient.js:1322
#: ../js/ui/components/telepathyClient.js:1318
msgid "Status is set to offline"
msgstr "ಸ್ಥಿತಿಯನ್ನು ಆಫ್‌ಲೈನ್‌ ಎಂದು ಸೂಚಿಸಿದ್ದಾರೆ."
#: ../js/ui/components/telepathyClient.js:1324
#: ../js/ui/components/telepathyClient.js:1320
msgid "Encryption is not available"
msgstr "ಗೂಢಲಿಪೀಕರಣ ಲಭ್ಯವಿಲ್ಲ"
#: ../js/ui/components/telepathyClient.js:1326
#: ../js/ui/components/telepathyClient.js:1322
msgid "Certificate is invalid"
msgstr "ಪ್ರಮಾಣಪತ್ರವು ಅಮಾನ್ಯವಾಗಿದೆ"
#: ../js/ui/components/telepathyClient.js:1328
#: ../js/ui/components/telepathyClient.js:1324
msgid "Connection has been refused"
msgstr "ಸಂಪರ್ಕವನ್ನು ನಿರಾಕರಿಸಲಾಗಿದೆ"
#: ../js/ui/components/telepathyClient.js:1330
#: ../js/ui/components/telepathyClient.js:1326
msgid "Connection can't be established"
msgstr "ಸಂಪರ್ಕವನ್ನು ಸಾಧಿಸಲಾಗಿಲ್ಲ"
#: ../js/ui/components/telepathyClient.js:1332
#: ../js/ui/components/telepathyClient.js:1328
msgid "Connection has been lost"
msgstr "ಸಂಪರ್ಕವು ಕಡಿದು ಹೋಗಿದೆ"
#: ../js/ui/components/telepathyClient.js:1334
#: ../js/ui/components/telepathyClient.js:1330
msgid "This account is already connected to the server"
msgstr "ಈ ಖಾತೆಯು ಈಗಾಗಲೆ ಪರಿಚಾರಕದೊಂದಿಗೆ ಸಂಪರ್ಕ ಜೋಡಿಸಲಾಗಿದೆ"
#: ../js/ui/components/telepathyClient.js:1336
#: ../js/ui/components/telepathyClient.js:1332
msgid ""
"Connection has been replaced by a new connection using the same resource"
msgstr ""
"ಒಂದು ಹೊಸ ಸಂಪರ್ಕದಿಂದ ಈ ಸಂಪರ್ಕವನ್ನು ಇದೇ ಸಂಪನ್ಮೂಲವನ್ನು ಬಳಸಿಕೊಂಡು ಬದಲಾಯಿಸಲಾಗಿದೆ"
#: ../js/ui/components/telepathyClient.js:1338
#: ../js/ui/components/telepathyClient.js:1334
msgid "The account already exists on the server"
msgstr "ಖಾತೆಯು ಈಗಾಗಲೆ ಪರಿಚಾರಕದಲ್ಲಿ ಅಸ್ತಿತ್ವದಲ್ಲಿದೆ"
#: ../js/ui/components/telepathyClient.js:1340
#: ../js/ui/components/telepathyClient.js:1336
msgid "Server is currently too busy to handle the connection"
msgstr "ಪರಿಚಾರಕಕ್ಕೆ ಬಿಡುವಿಲ್ಲದ ಕಾರಣ ಸಂಪರ್ಕವನ್ನು ನಿಭಾಯಿಸಲಾಗುತ್ತಿಲ್ಲ"
#: ../js/ui/components/telepathyClient.js:1342
#: ../js/ui/components/telepathyClient.js:1338
msgid "Certificate has been revoked"
msgstr "ಪ್ರಮಾಣಪತ್ರವನ್ನು ಹಿಂದಕ್ಕೆ ತೆಗೆದುಕೊಳ್ಳಲಾಗಿದೆ"
#: ../js/ui/components/telepathyClient.js:1344
#: ../js/ui/components/telepathyClient.js:1340
msgid ""
"Certificate uses an insecure cipher algorithm or is cryptographically weak"
msgstr ""
@ -886,7 +842,7 @@ msgstr ""
"ಗೂಢಲಿಪೀಕರಣವನ್ನು "
"ಹೊಂದಿದೆ"
#: ../js/ui/components/telepathyClient.js:1346
#: ../js/ui/components/telepathyClient.js:1342
msgid ""
"The length of the server certificate, or the depth of the server certificate "
"chain, exceed the limits imposed by the cryptography library"
@ -895,30 +851,31 @@ msgstr ""
"ಲೈಬ್ರರಿಯಿಂದ "
"ನಿಗದಿ ಪಡಿಸಲಾದ ಮಿತಿಗಳನ್ನು ಮೀರಿದೆ."
#: ../js/ui/components/telepathyClient.js:1348
#: ../js/ui/components/telepathyClient.js:1344
msgid "Internal error"
msgstr "ಆಂತರಿಕ ತಪ್ಪು"
#. translators: argument is the account name, like
#. * name@jabber.org for example.
#: ../js/ui/components/telepathyClient.js:1358
#: ../js/ui/components/telepathyClient.js:1354
#, c-format
msgid "Connection to %s failed"
msgstr "%s ಗಾಗಿನ ಸಂಪರ್ಕವು ವಿಫಲಗೊಂಡಿದೆ"
#: ../js/ui/components/telepathyClient.js:1367
#: ../js/ui/components/telepathyClient.js:1363
msgid "Reconnect"
msgstr "ಮರಳಿ ಸಂಪರ್ಕ ಜೋಡಿಸು"
#: ../js/ui/components/telepathyClient.js:1368
#: ../js/ui/components/telepathyClient.js:1364
msgid "Edit account"
msgstr "ಖಾತೆಯನ್ನು ಸಂಪಾದಿಸು"
#: ../js/ui/components/telepathyClient.js:1413
#: ../js/ui/components/telepathyClient.js:1409
msgid "Unknown reason"
msgstr "ಅಜ್ಞಾತ ಕಾರಣ"
#: ../js/ui/dash.js:254 ../js/ui/dash.js:292
#: ../js/ui/dash.js:245 ../js/ui/dash.js:273
#| msgid "Applications"
msgid "Show Applications"
msgstr "ಅನ್ವಯಗಳನ್ನು ತೋರಿಸು"
@ -926,14 +883,14 @@ msgstr "ಅನ್ವಯಗಳನ್ನು ತೋರಿಸು"
msgid "Date and Time Settings"
msgstr "ದಿನಾಂಕ ಹಾಗು ಸಮಯದ ಸಿದ್ಧತೆಗಳು"
#: ../js/ui/dateMenu.js:111
#: ../js/ui/dateMenu.js:109
msgid "Open Calendar"
msgstr "ಕ್ಯಾಲೆಂಡರನ್ನು ತೆರೆ"
#. Translators: This is the date format to use when the calendar popup is
#. * shown - it is shown just below the time in the shell (e.g. "Tue 9:29 AM").
#.
#: ../js/ui/dateMenu.js:201
#: ../js/ui/dateMenu.js:175
msgid "%A %B %e, %Y"
msgstr "%A %B %e, %Y"
@ -1038,11 +995,11 @@ msgid "Download and install '%s' from extensions.gnome.org?"
msgstr ""
"'%s' ಅನ್ನು extensions.gnome.org ಇಂದ ಡೌನ್‌ಲೋಡ್ ಮಾಡಿಕೊಂಡು ಅನುಸ್ಥಾಪಿಸಬೇಕೆ?"
#: ../js/ui/keyboard.js:337
#: ../js/ui/keyboard.js:327
msgid "tray"
msgstr "ಟ್ರೇ"
#: ../js/ui/keyboard.js:584 ../js/ui/status/keyboard.js:195
#: ../js/ui/keyboard.js:561 ../js/ui/status/keyboard.js:194
#: ../js/ui/status/power.js:205
msgid "Keyboard"
msgstr "ಕೀಲಿಮಣೆ"
@ -1095,23 +1052,24 @@ msgstr "ಆಕರವನ್ನು ನೋಡಿ"
msgid "Web Page"
msgstr "ಜಾಲ ಪುಟ"
#: ../js/ui/messageTray.js:1084
#: ../js/ui/messageTray.js:1080
msgid "Open"
msgstr "ತೆರೆ"
#: ../js/ui/messageTray.js:1091
#: ../js/ui/messageTray.js:1087
msgid "Remove"
msgstr "ತೆಗೆದು ಹಾಕು"
#: ../js/ui/messageTray.js:1531
#: ../js/ui/messageTray.js:2052
msgid "Message Tray"
msgstr "ಸಂದೇಶ ಟ್ರೇ"
msgstr ""
#: ../js/ui/messageTray.js:2543
#: ../js/ui/messageTray.js:2508
msgid "System Information"
msgstr "ವ್ಯವಸ್ಥೆಯ ಮಾಹಿತಿ"
#: ../js/ui/notificationDaemon.js:506 ../src/shell-app.c:374
#: ../js/ui/notificationDaemon.js:506 ../src/shell-app.c:373
#| msgid "Unknown"
msgctxt "program"
msgid "Unknown"
msgstr "ಗೊತ್ತಿಲ್ಲದ"
@ -1167,29 +1125,33 @@ msgstr "ದಯವಿಟ್ಟು ಒಂದು ಆಜ್ಞೆಯನ್ನು ನ
#. Translators: This is a time format for a date in
#. long format
#: ../js/ui/screenShield.js:81
#: ../js/ui/screenShield.js:79
#| msgctxt "calendar heading"
#| msgid "%A, %B %d"
msgid "%A, %B %d"
msgstr "%A, %B %d"
#: ../js/ui/screenShield.js:145
#: ../js/ui/screenShield.js:144
#, c-format
msgid "%d new message"
msgid_plural "%d new messages"
msgstr[0] "%d ಹೊಸ ಸಂದೇಶ"
msgstr[1] "%d ಹೊಸ ಸಂದೇಶಗಳು"
msgstr[0] ""
msgstr[1] ""
#: ../js/ui/screenShield.js:147
#, c-format
#: ../js/ui/screenShield.js:146
#, fuzzy, c-format
#| msgid "Notifications"
msgid "%d new notification"
msgid_plural "%d new notifications"
msgstr[0] "%d ಹೊಸ ಸೂಚನೆ"
msgstr[1] "%d ಹೊಸ ಸೂಚನೆಗಳು"
msgstr[0] "ಸೂಚನೆಗಳು"
msgstr[1] "ಸೂಚನೆಗಳು"
#: ../js/ui/searchDisplay.js:275
msgid "Searching..."
msgstr "ಹುಡುಕಲಾಗುತ್ತಿದೆ..."
#: ../js/ui/searchDisplay.js:323
#| msgid "No matching results."
msgid "No results."
msgstr "ಯಾವುದೆ ಫಲಿತಾಂಶಗಳಿಲ್ಲ."
@ -1210,16 +1172,18 @@ msgid "Hide Text"
msgstr "ಪಠ್ಯವನ್ನು ಅಡಗಿಸು"
#: ../js/ui/shellMountOperation.js:368
#| msgid "Password:"
msgid "Password"
msgstr "ಗುಪ್ತಪದ"
#: ../js/ui/shellMountOperation.js:389
#| msgid "Password:"
msgid "Remember Password"
msgstr "ಈ ಗುಪ್ತಪದವನ್ನು ನೆನಪಿನಲ್ಲಿಡು"
#: ../js/ui/shellMountOperation.js:400 ../js/ui/unlockDialog.js:171
#: ../js/ui/shellMountOperation.js:400 ../js/ui/unlockDialog.js:169
msgid "Unlock"
msgstr "ಅನ್‌ಲಾಕ್ ಮಾಡು"
msgstr ""
#: ../js/ui/status/accessibility.js:39
msgid "Accessibility"
@ -1335,7 +1299,7 @@ msgstr "ಕೀಲಿಮಣೆ ಸಿದ್ಧತೆಗಳು"
msgid "Mouse Settings"
msgstr "ಮೌಸ್‌ನ ಸಿದ್ಧತೆಗಳು"
#: ../js/ui/status/bluetooth.js:269 ../js/ui/status/volume.js:234
#: ../js/ui/status/bluetooth.js:269 ../js/ui/status/volume.js:236
msgid "Sound Settings"
msgstr "ಧ್ವನಿಯ ಸಿದ್ಧತೆಗಳು"
@ -1368,10 +1332,10 @@ msgid "Device %s wants to pair with this computer"
msgstr "%s ಎನ್ನುವ ಸಾಧನದೊಂದಿಗೆ ಸಂಪರ್ಕ ಜೋಡಿಸಲು ಬಯಸುತ್ತಿದೆ"
#: ../js/ui/status/bluetooth.js:379
#, c-format
#, fuzzy, c-format
#| msgid "Please confirm whether the PIN '%s' matches the one on the device."
msgid "Please confirm whether the PIN '%06d' matches the one on the device."
msgstr ""
"'%06d' ಎಂಬ PIN ಸಾಧನದಲ್ಲಿರುವುದಕ್ಕೆ ತಾಳೆಯಾಗುತ್ತದೆಯೆ ಎಂದು ದಯವಿಟ್ಟು ಖಚಿತಪಡಿಸಿ."
msgstr "'%s' ಎನ್ನುವ PIN ಸಾಧನದಲ್ಲಿರುವುದಕ್ಕೆ ತಾಳೆಯಾಗುತ್ತದೆಯೆ ಎಂದು ಖಚಿತಪಡಿಸಿ."
#: ../js/ui/status/bluetooth.js:381
msgid "Matches"
@ -1394,17 +1358,17 @@ msgstr "ದಯವಿಟ್ಟು ಸಾಧನದಲ್ಲಿ ಸೂಚಿಸಿ
msgid "OK"
msgstr "ಸರಿ"
#: ../js/ui/status/keyboard.js:228
#: ../js/ui/status/keyboard.js:227
msgid "Show Keyboard Layout"
msgstr "ಕೀಲಿಮಣೆ ವಿನ್ಯಾಸವನ್ನು ತೋರಿಸು"
#: ../js/ui/status/keyboard.js:233
#: ../js/ui/status/keyboard.js:232
msgid "Region and Language Settings"
msgstr "ಪ್ರದೇಶ ಮತ್ತು ಭಾಷೆ ಸಿದ್ಧತೆಗಳು"
#: ../js/ui/status/lockScreenMenu.js:18
msgid "Volume, network, battery"
msgstr "ಧ್ವನಿಪ್ರಮಾಣ, ಜಾಲಬಂಧ, ಬ್ಯಾಟರಿ"
msgstr ""
#: ../js/ui/status/network.js:94
msgid "<unknown>"
@ -1616,12 +1580,13 @@ msgid "Computer"
msgstr "ಗಣಕ"
#: ../js/ui/status/power.js:217
#| msgid "Unknown"
msgctxt "device"
msgid "Unknown"
msgstr "ಗೊತ್ತಿಲ್ಲದ"
#. Translators: This is the label for audio volume
#: ../js/ui/status/volume.js:47 ../js/ui/status/volume.js:221
#: ../js/ui/status/volume.js:47 ../js/ui/status/volume.js:223
msgid "Volume"
msgstr "ಧ್ವನಿ ಪ್ರಮಾಣ"
@ -1629,71 +1594,75 @@ msgstr "ಧ್ವನಿ ಪ್ರಮಾಣ"
msgid "Microphone"
msgstr "ಮೈಕ್ರೊಫೋನ್"
#: ../js/ui/unlockDialog.js:178
#: ../js/ui/unlockDialog.js:176
msgid "Log in as another user"
msgstr "ಇನ್ನೊಬ್ಬ ಬಳಕೆದಾರನಾಗಿ ಪ್ರವೇಶಿಸಿ"
msgstr ""
#: ../js/ui/userMenu.js:181
#: ../js/ui/userMenu.js:175
msgid "Available"
msgstr "ಲಭ್ಯ"
#: ../js/ui/userMenu.js:184
#: ../js/ui/userMenu.js:178
msgid "Busy"
msgstr "ಕಾರ್ಯನಿರತ"
#: ../js/ui/userMenu.js:187
#: ../js/ui/userMenu.js:181
msgid "Invisible"
msgstr "ಅಗೋಚರ"
#: ../js/ui/userMenu.js:190
#: ../js/ui/userMenu.js:184
msgid "Away"
msgstr "ಹೊರಗೆ ಹೋಗಿದ್ದೇನೆ"
#: ../js/ui/userMenu.js:193
#: ../js/ui/userMenu.js:187
msgid "Idle"
msgstr "ಜಡ"
#: ../js/ui/userMenu.js:196
#: ../js/ui/userMenu.js:190
msgid "Unavailable"
msgstr "ಅಲಭ್ಯ"
#: ../js/ui/userMenu.js:744
msgid "Notifications"
msgstr "ಸೂಚನೆಗಳು"
#: ../js/ui/userMenu.js:752
msgid "System Settings"
msgstr "ವ್ಯವಸ್ಥೆಯ ಸಿದ್ಧತೆಗಳು"
#: ../js/ui/userMenu.js:760
#: ../js/ui/userMenu.js:613 ../js/ui/userMenu.js:754
msgid "Switch User"
msgstr "ಬಳಕೆದಾರನನ್ನು ಬದಲಿಸು"
#: ../js/ui/userMenu.js:765
#: ../js/ui/userMenu.js:614
#, fuzzy
#| msgid "Switch User"
msgid "Switch Session"
msgstr "ಬಳಕೆದಾರನನ್ನು ಬದಲಿಸು"
#: ../js/ui/userMenu.js:738
msgid "Notifications"
msgstr "ಸೂಚನೆಗಳು"
#: ../js/ui/userMenu.js:746
msgid "System Settings"
msgstr "ವ್ಯವಸ್ಥೆಯ ಸಿದ್ಧತೆಗಳು"
#: ../js/ui/userMenu.js:759
#| msgctxt "title"
#| msgid "Log Out"
msgid "Log Out"
msgstr "ನಿರ್ಗಮಿಸು"
#: ../js/ui/userMenu.js:770
#: ../js/ui/userMenu.js:764
msgid "Lock"
msgstr "ಲಾಕ್ ಮಾಡು"
msgstr ""
#: ../js/ui/userMenu.js:785
#: ../js/ui/userMenu.js:779
msgid "Install Updates & Restart"
msgstr "ಅಪ್‌ಡೇಟ್‌ಗಳನ್ನು ಅನುಸ್ಥಾಪಿಸು ಮತ್ತು ಮರಳಿಸ್ಥಾಪಿಸು"
msgstr ""
#: ../js/ui/userMenu.js:803
#: ../js/ui/userMenu.js:797
msgid "Your chat status will be set to busy"
msgstr "ನಿಮ್ಮ ಹರಟೆಯ ಸ್ಥಿತಿಯನ್ನು ಕಾರ್ಯನಿರತರಾಗಿದ್ದಾರೆ ಎಂದು ಬದಲಾಯಿಸಲಾಗಿದೆ."
#: ../js/ui/userMenu.js:804
#: ../js/ui/userMenu.js:798
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."
msgstr ""
"ಸಂಭಾಷಣೆಯ ಸಂದೇಶಗಳೂ ಸಹ ಸೇರಿದಂತೆ ಸೂಚನೆಗಳನ್ನು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲಾಗಿರುತ್ತದೆ. ನೀವು "
"ಬೇರೆಯವರಿಂದ ಬಂದ ಸಂದೇಶಗಳನ್ನು ನೀವು ನೋಡಿಲ್ಲ ಎಂದು ಅವರಿಗೆ ಗೊತ್ತಾಗುವಂತೆ ನಿಮ್ಮ "
"ಆನ್‌ಲೈನ್ "
"ಸ್ಥಿತಿಯನ್ನು ಹೊಂದಿಸಲಾಗಿರುತ್ತದೆ."
#: ../js/ui/viewSelector.js:85
msgid "Windows"
@ -1707,7 +1676,7 @@ msgstr "ಅನ್ವಯಗಳು"
msgid "Search"
msgstr "ಹುಡುಕು"
#: ../js/ui/wanda.js:117
#: ../js/ui/wanda.js:119
#, c-format
msgid ""
"Sorry, no wisdom for you today:\n"
@ -1716,12 +1685,12 @@ msgstr ""
"ಕ್ಷಮಿಸಿ, ನಿಮಗಾಗಿ ಯಾವುದೆ ವಿವೇಕವಾಣಿ ಇಲ್ಲ :\n"
"%s"
#: ../js/ui/wanda.js:121
#: ../js/ui/wanda.js:123
#, c-format
msgid "%s the Oracle says"
msgstr "%s Oracle ಹೇಳುವಂತೆ"
#: ../js/ui/wanda.js:162
#: ../js/ui/wanda.js:164
msgid "Your favorite Easter Egg"
msgstr "ನಿಮ್ಮ ಮೆಚ್ಚಿನ ಈಸ್ಟರ್ ಮೊಟ್ಟೆ"
@ -1731,6 +1700,7 @@ msgid "'%s' is ready"
msgstr "'%s' ಸಿದ್ಧಗೊಂಡಿದೆ"
#: ../src/calendar-server/evolution-calendar.desktop.in.in.h:1
#| msgid "Open Calendar"
msgid "Evolution Calendar"
msgstr "Evolution ಕ್ಯಾಲೆಂಡರ್"
@ -1756,23 +1726,23 @@ msgstr[1] "%u ಇನ್‌ಪುಟ್‌ಗಳು"
msgid "System Sounds"
msgstr "ವ್ಯವಸ್ಥೆಯ ಧ್ವನಿಗಳು"
#: ../src/main.c:332
#: ../src/main.c:330
msgid "Print version"
msgstr "ಮುದ್ರಿಸಬಹುದಾದ ಆವೃತ್ತಿ"
#: ../src/main.c:338
#: ../src/main.c:336
msgid "Mode used by GDM for login screen"
msgstr "ಪ್ರವೇಶದ ತೆರೆಗಾಗಿ GDM ಬಳಸಿದ ಪ್ರಕಾರ"
#: ../src/main.c:344
#: ../src/main.c:342
msgid "Use a specific mode, e.g. \"gdm\" for login screen"
msgstr "ನಿಶ್ಚಿತ ಸ್ಥಿತಿಯನ್ನು ಬಳಸು, ಉದಾ. ಪ್ರವೇಶ ತೆರೆಗಾಗಿ \"gdm\""
msgstr ""
#: ../src/main.c:350
#: ../src/main.c:348
msgid "List possible modes"
msgstr "ಸಾಧ್ಯವಿರುವ ಸ್ಥಿತಿಗಳನ್ನು ಪಟ್ಟಿ ಮಾಡು"
msgstr ""
#: ../src/shell-app.c:622
#: ../src/shell-app.c:621
#, c-format
msgid "Failed to launch '%s'"
msgstr "'%s' ಅನ್ನು ಆರಂಭಿಸುವಲ್ಲಿ ವಿಫಲಗೊಂಡಿದೆ"
@ -1797,10 +1767,6 @@ msgstr "ಪೂರ್ವನಿಯೋಜಿತ"
msgid "Authentication dialog was dismissed by the user"
msgstr "ದೃಢೀಕರಣದ ಸಂವಾದವನ್ನು ಬಳಕೆದಾರರಿಂದ ತಿರಸ್ಕರಿಸಲಾಗಿದೆ"
#~| msgid "Switch User"
#~ msgid "Switch Session"
#~ msgstr "ಅಧಿವೇಶನವನ್ನು ಬದಲಿಸು"
#~ msgid "disabled OpenSearch providers"
#~ msgstr "ಅಶಕ್ತಗೊಳಿಸಲಾದ OpenSearch ಒದಗಿಸುವವರು"

962
po/lt.po

File diff suppressed because it is too large Load Diff

111
po/ml.po
View File

@ -11,15 +11,15 @@ 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-09-20 16:11+0000\n"
"PO-Revision-Date: 2012-11-26 15:02+0530\n"
"Last-Translator: Ani Peter <peter.ani@gmail.com>\n"
"PO-Revision-Date: 2012-09-20 22:56+0000\n"
"Last-Translator: Ani Peter <apeter@redhat.com>\n"
"Language-Team: Malayalam <discuss@lists.smc.org.in>\n"
"Language: ml\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
"X-Generator: Lokalize 1.5\n"
"X-Generator: Lokalize 1.0\n"
"X-DamnedLies-Scope: partial\n"
#: ../data/50-gnome-shell-screenshot.xml.in.h:1
@ -61,8 +61,7 @@ msgstr "ഗ്നോം ഷെല്‍ എക്സ്റ്റെന്‍ഷ
#: ../data/org.gnome.shell.gschema.xml.in.in.h:1
msgid "Enable internal tools useful for developers and testers from Alt-F2"
msgstr ""
"Alt-F2-ല്‍ ഡവലപ്പര്‍മാര്‍ക്കും ടെസ്റ്റേര്‍സിനും പ്രയോജനകരമായ ആന്തരിക "
"പ്രയോഗങ്ങള്‍ പ്രവര്‍ത്തന "
"Alt-F2-ല്‍ ഡവലപ്പര്‍മാര്‍ക്കും ടെസ്റ്റേര്‍സിനും പ്രയോജനകരമായ ആന്തരിക പ്രയോഗങ്ങള്‍ പ്രവര്‍ത്തന "
"സജ്ജമാക്കുന്നു"
#: ../data/org.gnome.shell.gschema.xml.in.in.h:2
@ -70,8 +69,7 @@ msgid ""
"Allows access to internal debugging and monitoring tools using the Alt-F2 "
"dialog."
msgstr ""
"Alt-F2 ഡയലോഗ് ഉപയോഗിച്ചു് ആന്തരിക ഡീബഗ്ഗിലേക്കും നീരീക്ഷണ പ്രയോഗങ്ങളിലേക്കും "
"പ്രവേശനം "
"Alt-F2 ഡയലോഗ് ഉപയോഗിച്ചു് ആന്തരിക ഡീബഗ്ഗിലേക്കും നീരീക്ഷണ പ്രയോഗങ്ങളിലേക്കും പ്രവേശനം "
"അനുവദിയ്ക്കുക."
#: ../data/org.gnome.shell.gschema.xml.in.in.h:3
@ -85,19 +83,14 @@ msgid ""
"list. You can also manipulate this list with the EnableExtension and "
"DisableExtension DBus methods on org.gnome.Shell."
msgstr ""
"ഗ്നോം ഷെല്‍ എക്സ്റ്റെന്‍ഷനുകള്‍ക്കു് ഒരു യുയുഐഡി വിശേഷതയുണ്ടു്; ലഭ്യമാക്കേണ്ട "
"എക്സ്റ്റെന്‍ഷനുകള്‍ ഈ കീ പട്ടിക "
"ലഭ്യമാക്കുന്നു. ലഭ്യമാക്കേണ്ട ഏതു് എക്സ്റ്റെന്‍ഷനും ഈ പട്ടികയിലുണ്ടാവണം. "
"org.gnome.Shell-ല്‍ "
"നിങ്ങള്‍ക്കു് EnableExtension, DisableExtension എന്നീ ഡീബസ് രീതികളിലൂടെ ഈ "
"പട്ടിക "
"ഗ്നോം ഷെല്‍ എക്സ്റ്റെന്‍ഷനുകള്‍ക്കു് ഒരു യുയുഐഡി വിശേഷതയുണ്ടു്; ലഭ്യമാക്കേണ്ട എക്സ്റ്റെന്‍ഷനുകള്‍ ഈ കീ പട്ടിക "
"ലഭ്യമാക്കുന്നു. ലഭ്യമാക്കേണ്ട ഏതു് എക്സ്റ്റെന്‍ഷനും ഈ പട്ടികയിലുണ്ടാവണം. org.gnome.Shell-ല്‍ "
"നിങ്ങള്‍ക്കു് EnableExtension, DisableExtension എന്നീ ഡീബസ് രീതികളിലൂടെ ഈ പട്ടിക "
"കൈകാര്യം ചെയ്യുവാനും സാധിയ്ക്കുന്നു."
#: ../data/org.gnome.shell.gschema.xml.in.in.h:5
msgid "Whether to collect stats about applications usage"
msgstr ""
"പ്രയോഗങ്ങളുടെ ഉപയോഗത്തെപ്പറ്റിയുള്ള സ്ഥിതിവിവരക്കണക്കുകള്‍ ശേഖരിയ്ക്കണമോ "
"എന്നു്"
msgstr "പ്രയോഗങ്ങളുടെ ഉപയോഗത്തെപ്പറ്റിയുള്ള സ്ഥിതിവിവരക്കണക്കുകള്‍ ശേഖരിയ്ക്കണമോ എന്നു്"
#: ../data/org.gnome.shell.gschema.xml.in.in.h:6
msgid ""
@ -106,12 +99,9 @@ msgid ""
"want to disable this for privacy reasons. Please note that doing so won't "
"remove already saved data."
msgstr ""
"ഏറ്റവും കൂടുതല്‍ തവണ ഉപയോഗിയ്ക്കുന്ന പ്രയോഗങ്ങള്‍ ലഭ്യമാക്കുന്നതിനായി ഷെല്‍ "
"സാധാരണയായി സജീവമായ "
"പ്രയോഗങ്ങളെ നിരീക്ഷിയ്ക്കുന്നു. (ഉദാഹരണത്തിനു്, ലോഞ്ചേര്‍സ്). ഈ ഡേറ്റാ "
"സ്വകാര്യമായി "
"സൂക്ഷിയ്ക്കുന്നെങ്കിലും, ചില കാരണങ്ങളാല്‍ ഇതു് പ്രവര്‍ത്തന "
"രഹിതമാക്കേണ്ടതുണ്ടു്. ഇങ്ങനെ ചെയ്യുന്നതു് "
"ഏറ്റവും കൂടുതല്‍ തവണ ഉപയോഗിയ്ക്കുന്ന പ്രയോഗങ്ങള്‍ ലഭ്യമാക്കുന്നതിനായി ഷെല്‍ സാധാരണയായി സജീവമായ "
"പ്രയോഗങ്ങളെ നിരീക്ഷിയ്ക്കുന്നു. (ഉദാഹരണത്തിനു്, ലോഞ്ചേര്‍സ്). ഈ ഡേറ്റാ സ്വകാര്യമായി "
"സൂക്ഷിയ്ക്കുന്നെങ്കിലും, ചില കാരണങ്ങളാല്‍ ഇതു് പ്രവര്‍ത്തന രഹിതമാക്കേണ്ടതുണ്ടു്. ഇങ്ങനെ ചെയ്യുന്നതു് "
"നിങ്ങള്‍ സൂക്ഷിച്ച ഡേറ്റയെ ബാധിയ്ക്കുന്നതല്ല."
#: ../data/org.gnome.shell.gschema.xml.in.in.h:7
@ -122,8 +112,7 @@ msgstr "ഇഷ്ടമുള്ള പ്രയോഗങ്ങള്‍ക്
msgid ""
"The applications corresponding to these identifiers will be displayed in the "
"favorites area."
msgstr ""
"ഈ ഐഡന്റിഫയറുകള്‍ക്കുള്ള പ്രയോഗങ്ങള്‍ ഉചിതമായ സ്ഥലങ്ങളില്‍ കാണിയ്ക്കുന്നു."
msgstr "ഈ ഐഡന്റിഫയറുകള്‍ക്കുള്ള പ്രയോഗങ്ങള്‍ ഉചിതമായ സ്ഥലങ്ങളില്‍ കാണിയ്ക്കുന്നു."
#: ../data/org.gnome.shell.gschema.xml.in.in.h:9
msgid "History for command (Alt-F2) dialog"
@ -138,8 +127,7 @@ msgid ""
"Internally used to store the last IM presence explicitly set by the user. "
"The value here is from the TpConnectionPresenceType enumeration."
msgstr ""
"ഉപയോക്താവു് സജ്ജമാക്കിയ അവസാന ഐഎം ആന്തരികമായി സൂക്ഷിയ്ക്കുന്നതിനു് "
"ഉപയോഗിയ്ക്കുന്നു. മൂല്യം "
"ഉപയോക്താവു് സജ്ജമാക്കിയ അവസാന ഐഎം ആന്തരികമായി സൂക്ഷിയ്ക്കുന്നതിനു് ഉപയോഗിയ്ക്കുന്നു. മൂല്യം "
"TpConnectionPresenceType തരത്തിലുള്ളതാകുന്നു."
#: ../data/org.gnome.shell.gschema.xml.in.in.h:12
@ -147,8 +135,7 @@ msgid ""
"Internally used to store the last session presence status for the user. The "
"value here is from the GsmPresenceStatus enumeration."
msgstr ""
"ഉപയോക്താവിനുള്ള അവസാന സെഷന്‍ അവസ്ഥ ആന്തരികമായി സൂക്ഷിയ്ക്കുന്നതിനു് "
"ഉപയോഗിയ്ക്കുന്നു. മൂല്യം "
"ഉപയോക്താവിനുള്ള അവസാന സെഷന്‍ അവസ്ഥ ആന്തരികമായി സൂക്ഷിയ്ക്കുന്നതിനു് ഉപയോഗിയ്ക്കുന്നു. മൂല്യം "
"GsmPresenceStatus തരത്തിലുള്ളതാകുന്നു."
#: ../data/org.gnome.shell.gschema.xml.in.in.h:13
@ -181,9 +168,7 @@ msgstr "സ്ക്രീന്‍ റിക്കോര്‍ഡര്‍ ട
#: ../data/org.gnome.shell.gschema.xml.in.in.h:20
msgid "Keybinding to start/stop the builtin screen recorder."
msgstr ""
"ബിള്‍ട്ടിന്‍ സ്ക്രീന്‍ റിക്കോര്‍ഡര്‍ തുടങ്ങുവാന്‍/നിര്‍ത്തുന്നതിനുള്ള "
"കീക്കൂട്ടം."
msgstr "ബിള്‍ട്ടിന്‍ സ്ക്രീന്‍ റിക്കോര്‍ഡര്‍ തുടങ്ങുവാന്‍/നിര്‍ത്തുന്നതിനുള്ള കീക്കൂട്ടം."
#: ../data/org.gnome.shell.gschema.xml.in.in.h:21
msgid "Which keyboard to use"
@ -202,8 +187,7 @@ msgid ""
"The framerate of the resulting screencast recordered by GNOME Shell's "
"screencast recorder in frames-per-second."
msgstr ""
"ഗ്നോം ഷെല്ലിന്റെ സ്ക്രീന്‍കാസ്റ്റ് റിക്കോര്‍ഡര്‍ റീക്കോര്‍ഡ് ചെയ്തിട്ടുള്ള "
"സ്ക്രീന്‍കാസ്റ്റിന്റെ "
"ഗ്നോം ഷെല്ലിന്റെ സ്ക്രീന്‍കാസ്റ്റ് റിക്കോര്‍ഡര്‍ റീക്കോര്‍ഡ് ചെയ്തിട്ടുള്ള സ്ക്രീന്‍കാസ്റ്റിന്റെ "
"ഫ്രെയിംറേറ്റ്, ഒരു സെക്കന്‍ഡില്‍ ഒരു ഫ്രെയിം."
#: ../data/org.gnome.shell.gschema.xml.in.in.h:25
@ -235,12 +219,9 @@ msgid ""
"threads=%T ! queue ! webmmux' and records to WEBM using the VP8 codec. %T is "
"used as a placeholder for a guess at the optimal thread count on the system."
msgstr ""
"റിക്കോര്‍ഡിങുകള്‍ എന്‍കോഡ് ചെയ്യുന്നതിനായി GStreamer പൈപ്പ് ലൈന്‍ "
"ഉപയോഗിയ്ക്കുന്നു. "
"gst-launch-നുള്ള സിന്റാക്സ് ഉപയോഗിയ്ക്കുന്നു. കാലിയായി സജ്ജമാക്കുമ്പോള്‍ "
"കാലിയാകുന്നു."
"ഇതു് നിലവില്‍ 'vp8enc min_quantizer=13 max_quantizer=13 cpu-used=5 "
"deadline=1000000 "
"റിക്കോര്‍ഡിങുകള്‍ എന്‍കോഡ് ചെയ്യുന്നതിനായി GStreamer പൈപ്പ് ലൈന്‍ ഉപയോഗിയ്ക്കുന്നു. "
"gst-launch-നുള്ള സിന്റാക്സ് ഉപയോഗിയ്ക്കുന്നു. കാലിയായി സജ്ജമാക്കുമ്പോള്‍ കാലിയാകുന്നു."
"ഇതു് നിലവില്‍ 'vp8enc min_quantizer=13 max_quantizer=13 cpu-used=5 deadline=1000000 "
"threads=%T ! queue ! webmmux' ആകുന്നുസ WEBM VP8 കോഡ് ഉപയോഗിച്ചു് റിക്കോര്‍ഡ് "
"ചെയ്യുന്നു."
@ -254,10 +235,8 @@ msgid ""
"current date, and use this extension. It should be changed when recording to "
"a different container format."
msgstr ""
"റിക്കോര്‍ഡ് ചെയ്ത സ്ക്രീന്‍കാസ്റ്റുകള്‍ക്കുള്ള ഫയല്‍നാമം നിലവിലുള്ള തീയതി, "
"എക്സ്റ്റെന്‍ഷന്‍ എന്നിവ "
"അനുസരിച്ചാകുന്നു. മറ്റൊരു ശൈലിയിലേക്കു് റിക്കോര്‍ഡ് ചെയ്യുമ്പോള്‍ ഇതു് "
"മാറ്റണം."
"റിക്കോര്‍ഡ് ചെയ്ത സ്ക്രീന്‍കാസ്റ്റുകള്‍ക്കുള്ള ഫയല്‍നാമം നിലവിലുള്ള തീയതി, എക്സ്റ്റെന്‍ഷന്‍ എന്നിവ "
"അനുസരിച്ചാകുന്നു. മറ്റൊരു ശൈലിയിലേക്കു് റിക്കോര്‍ഡ് ചെയ്യുമ്പോള്‍ ഇതു് മാറ്റണം."
#: ../js/extensionPrefs/main.js:124
#, c-format
@ -270,9 +249,7 @@ msgstr "എക്സ്റ്റെന്‍ഷന്‍"
#: ../js/extensionPrefs/main.js:188
msgid "Select an extension to configure using the combobox above."
msgstr ""
"മുകളിലുള്ള കോമ്പോ ബോക്സ് ഉപയോഗിച്ചു് ക്രമീകരിയ്ക്കുന്നതിനുള്ളൊരു "
"എക്സ്റ്റെന്‍ഷന്‍ തെര‍ഞ്ഞെടുക്കുക."
msgstr "മുകളിലുള്ള കോമ്പോ ബോക്സ് ഉപയോഗിച്ചു് ക്രമീകരിയ്ക്കുന്നതിനുള്ളൊരു എക്സ്റ്റെന്‍ഷന്‍ തെര‍ഞ്ഞെടുക്കുക."
#: ../js/gdm/loginDialog.js:526
msgid "Session..."
@ -601,8 +578,7 @@ msgid ""
"Passwords or encryption keys are required to access the wireless network "
"'%s'."
msgstr ""
"വയര്‍ലെസ് നെറ്റ്‌വര്‍ക്ക് '%s'-ലേക്ക് പ്രവേശിക്കുന്നതിനായി രഹസ്യവാക്കുകള്‍ "
"അല്ലെങ്കില്‍ എന്‍ക്രിപ്ഷന്‍ കീകള്‍ "
"വയര്‍ലെസ് നെറ്റ്‌വര്‍ക്ക് '%s'-ലേക്ക് പ്രവേശിക്കുന്നതിനായി രഹസ്യവാക്കുകള്‍ അല്ലെങ്കില്‍ എന്‍ക്രിപ്ഷന്‍ കീകള്‍ "
"ആവശ്യമുണ്ടു്."
#: ../js/ui/components/networkAgent.js:314
@ -788,8 +764,7 @@ msgstr "%s നിങ്ങള്‍ക്കു് %s അയച്ചിരി
#: ../js/ui/components/telepathyClient.js:1206
#, c-format
msgid "%s would like permission to see when you are online"
msgstr ""
"നിങ്ങള്‍ ഓണ്‍ലൈന്‍ ആകുമ്പോള്‍ കാണുന്നതിനുള്ള അനുമതി %s-നു് ആവശ്യമുണ്ടു്"
msgstr "നിങ്ങള്‍ ഓണ്‍ലൈന്‍ ആകുമ്പോള്‍ കാണുന്നതിനുള്ള അനുമതി %s-നു് ആവശ്യമുണ്ടു്"
#: ../js/ui/components/telepathyClient.js:1298
msgid "Network error"
@ -860,11 +835,8 @@ msgid "This account is already connected to the server"
msgstr "ഈ അക്കൌണ്ട് നിലവില്‍ സര്‍വറിലേക്കു് കണക്ട് ചെയ്തിരിയ്ക്കുന്നു"
#: ../js/ui/components/telepathyClient.js:1332
msgid ""
"Connection has been replaced by a new connection using the same resource"
msgstr ""
"അതേ ശ്രോതസ്സ് ഉപയോഗിച്ചു് ഒരു പുതിയ കണക്ഷന്‍ ഉപയോഗിച്ചു് ഈ കണക്ഷന്‍ "
"മാറ്റിസ്ഥാപിയ്ക്കുന്നു"
msgid "Connection has been replaced by a new connection using the same resource"
msgstr "അതേ ശ്രോതസ്സ് ഉപയോഗിച്ചു് ഒരു പുതിയ കണക്ഷന്‍ ഉപയോഗിച്ചു് ഈ കണക്ഷന്‍ മാറ്റിസ്ഥാപിയ്ക്കുന്നു"
#: ../js/ui/components/telepathyClient.js:1334
msgid "The account already exists on the server"
@ -879,19 +851,15 @@ msgid "Certificate has been revoked"
msgstr "സമ്മതപത്രം വീണ്ടും ആവശ്യപ്പെട്ടിരിയ്ക്കുന്നു"
#: ../js/ui/components/telepathyClient.js:1340
msgid ""
"Certificate uses an insecure cipher algorithm or is cryptographically weak"
msgstr ""
"സമ്മതപത്രം സുരക്ഷിതമല്ലാത്തൊരു സിഫര്‍ ആല്‍ഗോരിഥം ഉപയോഗിയ്ക്കുന്നു "
"അല്ലെങ്കില്‍ ഉചിതമല്ല"
msgid "Certificate uses an insecure cipher algorithm or is cryptographically weak"
msgstr "സമ്മതപത്രം സുരക്ഷിതമല്ലാത്തൊരു സിഫര്‍ ആല്‍ഗോരിഥം ഉപയോഗിയ്ക്കുന്നു അല്ലെങ്കില്‍ ഉചിതമല്ല"
#: ../js/ui/components/telepathyClient.js:1342
msgid ""
"The length of the server certificate, or the depth of the server certificate "
"chain, exceed the limits imposed by the cryptography library"
msgstr ""
"സര്‍വറിന്റെ സമ്മതപത്രത്തിന്റെ വ്യാപ്തി, അല്ലെങ്കില്‍ സര്‍വര്‍ സമ്മതപത്ര "
"ചെയിന്റെ വ്യാപ്തി, എന്നിവ "
"സര്‍വറിന്റെ സമ്മതപത്രത്തിന്റെ വ്യാപ്തി, അല്ലെങ്കില്‍ സര്‍വര്‍ സമ്മതപത്ര ചെയിന്റെ വ്യാപ്തി, എന്നിവ "
"പരിധിയില്‍ കൂടുന്നു"
#: ../js/ui/components/telepathyClient.js:1344
@ -950,8 +918,7 @@ msgstr "പുറത്ത് കടക്കുക"
#: ../js/ui/endSessionDialog.js:63
msgid "Click Log Out to quit these applications and log out of the system."
msgstr ""
"ഈ പ്രയോഗങ്ങളില്‍ നിന്നും പുറത്തു് കടക്കുന്നതിനായി പുറത്തു കടക്കുക ക്ലിക്ക് "
"ചെയ്തു് സിസ്റ്റത്തില്‍ നിന്നും "
"ഈ പ്രയോഗങ്ങളില്‍ നിന്നും പുറത്തു് കടക്കുന്നതിനായി പുറത്തു കടക്കുക ക്ലിക്ക് ചെയ്തു് സിസ്റ്റത്തില്‍ നിന്നും "
"പുറത്തു് കടക്കുക."
#: ../js/ui/endSessionDialog.js:65
@ -985,8 +952,7 @@ msgstr "നിര്‍ത്തുക"
#: ../js/ui/endSessionDialog.js:82
msgid "Click Power Off to quit these applications and power off the system."
msgstr ""
"ഈ പ്രയോഗങ്ങളില്‍ നിന്നും പുറത്തു് കടക്കുന്നതിനായി പവര്‍ ഓഫ് ചെയ്യുക ക്ലിക്ക് "
"ചെയ്തു സിസ്റ്റിന്റെ പവര്‍ "
"ഈ പ്രയോഗങ്ങളില്‍ നിന്നും പുറത്തു് കടക്കുന്നതിനായി പവര്‍ ഓഫ് ചെയ്യുക ക്ലിക്ക് ചെയ്തു സിസ്റ്റിന്റെ പവര്‍ "
"ഓഫ് ചെയ്യുക."
#: ../js/ui/endSessionDialog.js:84
@ -1017,8 +983,7 @@ msgstr "പുനരാരംഭിക്കുക"
#: ../js/ui/endSessionDialog.js:99
msgid "Click Restart to quit these applications and restart the system."
msgstr ""
"ഈ പ്രയോഗങ്ങള്‍ നിറുത്തി സിസ്റ്റം പുനരാരംഭിക്കുവാന്‍ പുനരാരംഭിക്കൂ അമര്‍ത്തുക"
msgstr "ഈ പ്രയോഗങ്ങള്‍ നിറുത്തി സിസ്റ്റം പുനരാരംഭിക്കുവാന്‍ പുനരാരംഭിക്കൂ അമര്‍ത്തുക"
#: ../js/ui/endSessionDialog.js:101
#, c-format
@ -1038,9 +1003,7 @@ msgstr "ഇന്‍സ്റ്റോള്‍"
#: ../js/ui/extensionDownloader.js:204
#, c-format
msgid "Download and install '%s' from extensions.gnome.org?"
msgstr ""
"extensions.gnome.org ഇല്‍ നിന്നും '%s' ഡൗണ്‍ലോട് ചെയ്ത് ഇന്‍സ്റ്റോള്‍ "
"ചെയ്യേണമോ?"
msgstr "extensions.gnome.org ഇല്‍ നിന്നും '%s' ഡൗണ്‍ലോട് ചെയ്ത് ഇന്‍സ്റ്റോള്‍ ചെയ്യേണമോ?"
#: ../js/ui/keyboard.js:327
msgid "tray"
@ -1697,10 +1660,8 @@ 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."
msgstr ""
"ചാറ്റ് സന്ദേശങ്ങള്‍ എന്ന പോലെ അറിയിപ്പുകള്‍ പ്രവര്‍ത്തന രഹിതമാക്കുന്നു. "
"മറ്റുള്ളവരുടെ ചാറ്റ് സന്ദേശങ്ങള്‍ "
"നിങ്ങള്‍ക്കു് കാണുവാന്‍ സാധ്യമല്ല എന്നു് നിങ്ങളുടെ ഓണ്‍ലൈന്‍ അവസ്ഥയില്‍ "
"വ്യക്തമാക്കുന്നു."
"ചാറ്റ് സന്ദേശങ്ങള്‍ എന്ന പോലെ അറിയിപ്പുകള്‍ പ്രവര്‍ത്തന രഹിതമാക്കുന്നു. മറ്റുള്ളവരുടെ ചാറ്റ് സന്ദേശങ്ങള്‍ "
"നിങ്ങള്‍ക്കു് കാണുവാന്‍ സാധ്യമല്ല എന്നു് നിങ്ങളുടെ ഓണ്‍ലൈന്‍ അവസ്ഥയില്‍ വ്യക്തമാക്കുന്നു."
#: ../js/ui/viewSelector.js:85
msgid "Windows"

717
po/nb.po

File diff suppressed because it is too large Load Diff

1975
po/nl.po

File diff suppressed because it is too large Load Diff

732
po/pa.po

File diff suppressed because it is too large Load Diff

724
po/pl.po

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

281
po/ru.po
View File

@ -13,16 +13,18 @@
msgid ""
msgstr ""
"Project-Id-Version: gnome-shell\n"
"Report-Msgid-Bugs-To: http://bugzilla.gnome.org/enter_bug.cgi?product=gnome-shell&keywords=I18N+L10N&component=general\n"
"Report-Msgid-Bugs-To: http://bugzilla.gnome.org/enter_bug.cgi?product=gnome-"
"shell&keywords=I18N+L10N&component=general\n"
"POT-Creation-Date: 2012-10-31 16:48+0000\n"
"PO-Revision-Date: 2012-11-20 11:46+0300\n"
"PO-Revision-Date: 2012-11-04 20:48+0400\n"
"Last-Translator: Yuri Myasoedov <omerta13@yandex.ru>\n"
"Language-Team: русский <gnome-cyr@gnome.org>\n"
"Language: ru\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2)\n"
"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n"
"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2)\n"
"X-Generator: Lokalize 1.2\n"
#: ../data/50-gnome-shell-screenshot.xml.in.h:1
@ -63,32 +65,55 @@ msgid "Enable internal tools useful for developers and testers from Alt-F2"
msgstr "Включить внутренние инструменты из Alt-F2 для разработчиков и тестеров"
#: ../data/org.gnome.shell.gschema.xml.in.in.h:2
msgid "Allows access to internal debugging and monitoring tools using the Alt-F2 dialog."
msgstr "Разрешает доступ к внутренней отладке и инструментам наблюдения, используя диалог Alt-F2."
msgid ""
"Allows access to internal debugging and monitoring tools using the Alt-F2 "
"dialog."
msgstr ""
"Разрешает доступ к внутренней отладке и инструментам наблюдения, используя "
"диалог Alt-F2."
#: ../data/org.gnome.shell.gschema.xml.in.in.h:3
msgid "Uuids of extensions to enable"
msgstr "Uuid включенных расширений"
#: ../data/org.gnome.shell.gschema.xml.in.in.h:4
msgid "GNOME Shell extensions have a uuid property; this key lists extensions which should be loaded. Any extension that wants to be loaded needs to be in this list. You can also manipulate this list with the EnableExtension and DisableExtension DBus methods on org.gnome.Shell."
msgstr "У расширений GNOME Shell есть свойство uuid; в этом ключе перечислены расширения, которые должны быть загружены. Этим список также можно управлять через методы DBus EnableExtension и DisableExtension сервиса org.gnome.Shell."
msgid ""
"GNOME Shell extensions have a uuid property; this key lists extensions which "
"should be loaded. Any extension that wants to be loaded needs to be in this "
"list. You can also manipulate this list with the EnableExtension and "
"DisableExtension DBus methods on org.gnome.Shell."
msgstr ""
"У расширений GNOME Shell есть свойство uuid; в этом ключе перечислены "
"расширения, которые должны быть загружены. Этим список также можно управлять "
"через методы DBus EnableExtension и DisableExtension сервиса org.gnome.Shell."
#: ../data/org.gnome.shell.gschema.xml.in.in.h:5
msgid "Whether to collect stats about applications usage"
msgstr "Собирать ли статистику об использовании приложений"
#: ../data/org.gnome.shell.gschema.xml.in.in.h:6
msgid "The shell normally monitors active applications in order to present the most used ones (e.g. in launchers). While this data will be kept private, you may want to disable this for privacy reasons. Please note that doing so won't remove already saved data."
msgstr "Обычно, оболочка отслеживает активные приложения, чтобы определить наиболее используемые приложения. Хотя эти данные хранятся как личные, возможно вы захотите отключить эту возможность из соображений безопасности. Это не приведёт к удалению уже сохранённых данных."
msgid ""
"The shell normally monitors active applications in order to present the most "
"used ones (e.g. in launchers). While this data will be kept private, you may "
"want to disable this for privacy reasons. Please note that doing so won't "
"remove already saved data."
msgstr ""
"Обычно, оболочка отслеживает активные приложения, чтобы определить наиболее "
"используемые приложения. Хотя эти данные хранятся как личные, возможно вы "
"захотите отключить эту возможность из соображений безопасности. Это не "
"приведёт к удалению уже сохранённых данных."
#: ../data/org.gnome.shell.gschema.xml.in.in.h:7
msgid "List of desktop file IDs for favorite applications"
msgstr "Список идентификаторов desktop-файлов для избранных приложений"
#: ../data/org.gnome.shell.gschema.xml.in.in.h:8
msgid "The applications corresponding to these identifiers will be displayed in the favorites area."
msgstr "Приложения, соответствующие этих идентификаторам, будут показаны в области избранных приложений."
msgid ""
"The applications corresponding to these identifiers will be displayed in the "
"favorites area."
msgstr ""
"Приложения, соответствующие этих идентификаторам, будут показаны в области "
"избранных приложений."
#: ../data/org.gnome.shell.gschema.xml.in.in.h:9
msgid "History for command (Alt-F2) dialog"
@ -99,20 +124,33 @@ msgid "History for the looking glass dialog"
msgstr "История просмотра прозрачного диалога"
#: ../data/org.gnome.shell.gschema.xml.in.in.h:11
msgid "Internally used to store the last IM presence explicitly set by the user. The value here is from the TpConnectionPresenceType enumeration."
msgstr "Используется для хранения статуса о присутствии, установленного пользователем. Данное значение берётся из перечисления TpConnectionPresenceType."
msgid ""
"Internally used to store the last IM presence explicitly set by the user. "
"The value here is from the TpConnectionPresenceType enumeration."
msgstr ""
"Используется для хранения статуса о присутствии, установленного "
"пользователем. Данное значение берётся из перечисления "
"TpConnectionPresenceType."
#: ../data/org.gnome.shell.gschema.xml.in.in.h:12
msgid "Internally used to store the last session presence status for the user. The value here is from the GsmPresenceStatus enumeration."
msgstr "Используется для хранения статуса о присутствии для последнего сеанса. Данное значение берётся из перечисления GsmPresenceStatus."
msgid ""
"Internally used to store the last session presence status for the user. The "
"value here is from the GsmPresenceStatus enumeration."
msgstr ""
"Используется для хранения статуса о присутствии для последнего сеанса. "
"Данное значение берётся из перечисления GsmPresenceStatus."
#: ../data/org.gnome.shell.gschema.xml.in.in.h:13
msgid "Always show the 'Log out' menuitem in the user menu."
msgstr "Всегда показывать в меню пункт «Завершить сеанс»."
#: ../data/org.gnome.shell.gschema.xml.in.in.h:14
msgid "This key overrides the automatic hiding of the 'Log out' menuitem in single-user, single-session situations."
msgstr "Этот ключ переопределяет автоматическое скрытие пункта «Завершить сеанс» при использовании одиночного сеанса."
msgid ""
"This key overrides the automatic hiding of the 'Log out' menuitem in single-"
"user, single-session situations."
msgstr ""
"Этот ключ переопределяет автоматическое скрытие пункта «Завершить сеанс» при "
"использовании одиночного сеанса."
#: ../data/org.gnome.shell.gschema.xml.in.in.h:15
msgid "Show the week date in the calendar"
@ -144,7 +182,8 @@ msgstr "Комбинация клавиш для переключения зап
#: ../data/org.gnome.shell.gschema.xml.in.in.h:22
msgid "Keybinding to start/stop the builtin screen recorder."
msgstr "Комбинация клавиш для запуска/остановки встроенного средства записи экрана."
msgstr ""
"Комбинация клавиш для запуска/остановки встроенного средства записи экрана."
#: ../data/org.gnome.shell.gschema.xml.in.in.h:23
msgid "Which keyboard to use"
@ -159,8 +198,12 @@ msgid "Framerate used for recording screencasts."
msgstr "Частота смены кадров для записи скринкастов."
#: ../data/org.gnome.shell.gschema.xml.in.in.h:26
msgid "The framerate of the resulting screencast recordered by GNOME Shell's screencast recorder in frames-per-second."
msgstr "Частота смены кадров в скринкасте, записанном с помощью GNOME Shell (кадров/сек)."
msgid ""
"The framerate of the resulting screencast recordered by GNOME Shell's "
"screencast recorder in frames-per-second."
msgstr ""
"Частота смены кадров в скринкасте, записанном с помощью GNOME Shell (кадров/"
"сек)."
#: ../data/org.gnome.shell.gschema.xml.in.in.h:27
msgid "The gstreamer pipeline used to encode the screencast"
@ -168,16 +211,44 @@ msgstr "Конвейер gstreamer, используемый для кодиро
#: ../data/org.gnome.shell.gschema.xml.in.in.h:29
#, no-c-format
msgid "Sets the GStreamer pipeline used to encode recordings. It follows the syntax used for gst-launch. The pipeline should have an unconnected sink pad where the recorded video is recorded. It will normally have a unconnected source pad; output from that pad will be written into the output file. However the pipeline can also take care of its own output - this might be used to send the output to an icecast server via shout2send or similar. When unset or set to an empty value, the default pipeline will be used. This is currently 'vp8enc min_quantizer=13 max_quantizer=13 cpu-used=5 deadline=1000000 threads=%T ! queue ! webmmux' and records to WEBM using the VP8 codec. %T is used as a placeholder for a guess at the optimal thread count on the system."
msgstr "Устанавливает конвейер GStreamer для кодирования записей. Соответствует синтаксису, используемому для gst-launch. Конвейер должен иметь неподключенный входной коннектор, где происходит запись видео. Выход коннектора обычно отключён, выход с этого коннектора записывается в файл вывода. Однако конвейер также может позаботиться о своём выводе, что можно использовать для отправки вывода на сервер icecast через shout2send или нечто подобное. При сбросе или установке пустого значения будет использоваться конвейер по умолчанию. В данный момент это «vp8enc min_quantizer=13 max_quantizer=13 cpu-used=5 deadline=1000000 threads=%T ! queue ! webmmux»; запись выполняется в WEBM с помощью кодека VP8. %T используется как заполнитель для определения оптимального количества потоков в системе."
msgid ""
"Sets the GStreamer pipeline used to encode recordings. It follows the syntax "
"used for gst-launch. The pipeline should have an unconnected sink pad where "
"the recorded video is recorded. It will normally have a unconnected source "
"pad; output from that pad will be written into the output file. However the "
"pipeline can also take care of its own output - this might be used to send "
"the output to an icecast server via shout2send or similar. When unset or set "
"to an empty value, the default pipeline will be used. This is currently "
"'vp8enc min_quantizer=13 max_quantizer=13 cpu-used=5 deadline=1000000 "
"threads=%T ! queue ! webmmux' and records to WEBM using the VP8 codec. %T is "
"used as a placeholder for a guess at the optimal thread count on the system."
msgstr ""
"Устанавливает конвейер GStreamer для кодирования записей. Соответствует "
"синтаксису, используемому для gst-launch. Конвейер должен иметь "
"неподключенный входной коннектор, где происходит запись видео. Выход "
"коннектора обычно отключён, выход с этого коннектора записывается в файл "
"вывода. Однако конвейер также может позаботиться о своём выводе, что можно "
"использовать для отправки вывода на сервер icecast через shout2send или "
"нечто подобное. При сбросе или установке пустого значения будет "
"использоваться конвейер по умолчанию. В данный момент это «vp8enc "
"min_quantizer=13 max_quantizer=13 cpu-used=5 deadline=1000000 threads=%T ! "
"queue ! webmmux»; запись выполняется в WEBM с помощью кодека VP8. %T "
"используется как заполнитель для определения оптимального количества потоков "
"в системе."
#: ../data/org.gnome.shell.gschema.xml.in.in.h:30
msgid "File extension used for storing the screencast"
msgstr "Расширение файла, использующееся для хранения скринкастов"
#: ../data/org.gnome.shell.gschema.xml.in.in.h:31
msgid "The filename for recorded screencasts will be a unique filename based on the current date, and use this extension. It should be changed when recording to a different container format."
msgstr "Имя файла записанного скринкаста будет уникальным именем, основанным на текущей дате, и использует это расширение. Оно должно быть изменено, если запись выполняется в другой контейнерный формат."
msgid ""
"The filename for recorded screencasts will be a unique filename based on the "
"current date, and use this extension. It should be changed when recording to "
"a different container format."
msgstr ""
"Имя файла записанного скринкаста будет уникальным именем, основанным на "
"текущей дате, и использует это расширение. Оно должно быть изменено, если "
"запись выполняется в другой контейнерный формат."
#: ../js/extensionPrefs/main.js:124
#, c-format
@ -208,14 +279,10 @@ msgstr "Вход в систему"
msgid "Not listed?"
msgstr "Нет в списке?"
#: ../js/gdm/loginDialog.js:889
#: ../js/ui/components/networkAgent.js:137
#: ../js/ui/components/polkitAgent.js:162
#: ../js/ui/endSessionDialog.js:373
#: ../js/ui/extensionDownloader.js:195
#: ../js/ui/shellMountOperation.js:396
#: ../js/ui/status/bluetooth.js:427
#: ../js/ui/unlockDialog.js:167
#: ../js/gdm/loginDialog.js:889 ../js/ui/components/networkAgent.js:137
#: ../js/ui/components/polkitAgent.js:162 ../js/ui/endSessionDialog.js:373
#: ../js/ui/extensionDownloader.js:195 ../js/ui/shellMountOperation.js:396
#: ../js/ui/status/bluetooth.js:427 ../js/ui/unlockDialog.js:167
msgid "Cancel"
msgstr "Отмена"
@ -233,9 +300,7 @@ msgstr "Окно входа в систему"
msgid "Power"
msgstr "Питание"
#: ../js/gdm/powerMenu.js:89
#: ../js/ui/userMenu.js:664
#: ../js/ui/userMenu.js:668
#: ../js/gdm/powerMenu.js:89 ../js/ui/userMenu.js:664 ../js/ui/userMenu.js:668
#: ../js/ui/userMenu.js:779
msgid "Suspend"
msgstr "Ждущий режим"
@ -244,9 +309,7 @@ msgstr "Ждущий режим"
msgid "Restart"
msgstr "Перезапустить"
#: ../js/gdm/powerMenu.js:99
#: ../js/ui/userMenu.js:666
#: ../js/ui/userMenu.js:668
#: ../js/gdm/powerMenu.js:99 ../js/ui/userMenu.js:666 ../js/ui/userMenu.js:668
#: ../js/ui/userMenu.js:778
msgid "Power Off"
msgstr "Выключить"
@ -292,14 +355,13 @@ msgstr "ПРИЛОЖЕНИЯ"
#: ../js/ui/appDisplay.js:370
msgid "SETTINGS"
msgstr "ПАРАМЕТРЫ"
msgstr "НАСТРОЙКИ"
#: ../js/ui/appDisplay.js:675
msgid "New Window"
msgstr "Новое окно"
#: ../js/ui/appDisplay.js:678
#: ../js/ui/dash.js:290
#: ../js/ui/appDisplay.js:678 ../js/ui/dash.js:290
msgid "Remove from Favorites"
msgstr "Удалить из избранного"
@ -476,8 +538,7 @@ msgstr "Открыть с помощью %s"
msgid "Eject"
msgstr "Извлечь"
#: ../js/ui/components/keyring.js:86
#: ../js/ui/components/polkitAgent.js:260
#: ../js/ui/components/keyring.js:86 ../js/ui/components/polkitAgent.js:260
msgid "Password:"
msgstr "Пароль:"
@ -529,8 +590,11 @@ msgstr "Беспроводная сеть требует подтвержден
#: ../js/ui/components/networkAgent.js:310
#, c-format
msgid "Passwords or encryption keys are required to access the wireless network '%s'."
msgstr "Для доступа к беспроводной сети «%s» требуются пароли или ключи шифрования."
msgid ""
"Passwords or encryption keys are required to access the wireless network "
"'%s'."
msgstr ""
"Для доступа к беспроводной сети «%s» требуются пароли или ключи шифрования."
#: ../js/ui/components/networkAgent.js:314
msgid "Wired 802.1X authentication"
@ -581,8 +645,7 @@ msgstr "Подтвердить"
#. * requested authentication was not gained; this can happen
#. * because of an authentication error (like invalid password),
#. * for instance.
#: ../js/ui/components/polkitAgent.js:248
#: ../js/ui/shellMountOperation.js:381
#: ../js/ui/components/polkitAgent.js:248 ../js/ui/shellMountOperation.js:381
msgid "Sorry, that didn't work. Please try again."
msgstr "Извините, это не сработало. Попробуйте снова."
@ -787,7 +850,8 @@ msgid "This account is already connected to the server"
msgstr "Эта учётная запись уже подключена к серверу"
#: ../js/ui/components/telepathyClient.js:1334
msgid "Connection has been replaced by a new connection using the same resource"
msgid ""
"Connection has been replaced by a new connection using the same resource"
msgstr "Соединение было заменено новым, используя тот же источник"
#: ../js/ui/components/telepathyClient.js:1336
@ -796,19 +860,27 @@ msgstr "Учётная запись уже существует на серве
#: ../js/ui/components/telepathyClient.js:1338
msgid "Server is currently too busy to handle the connection"
msgstr "Сервер в настоящее время сильно перегружен, чтобы обработать соединение"
msgstr ""
"Сервер в настоящее время сильно перегружен, чтобы обработать соединение"
#: ../js/ui/components/telepathyClient.js:1340
msgid "Certificate has been revoked"
msgstr "Сертификат аннулирован"
#: ../js/ui/components/telepathyClient.js:1342
msgid "Certificate uses an insecure cipher algorithm or is cryptographically weak"
msgstr "Сертификат использует небезопасный алгоритм шифрования или он криптографически нестоек"
msgid ""
"Certificate uses an insecure cipher algorithm or is cryptographically weak"
msgstr ""
"Сертификат использует небезопасный алгоритм шифрования или он "
"криптографически нестоек"
#: ../js/ui/components/telepathyClient.js:1344
msgid "The length of the server certificate, or the depth of the server certificate chain, exceed the limits imposed by the cryptography library"
msgstr "Длина сертификата сервера, или глубина цепочки сертификатов сервера, превышает пределы, установленные библиотекой криптографии"
msgid ""
"The length of the server certificate, or the depth of the server certificate "
"chain, exceed the limits imposed by the cryptography library"
msgstr ""
"Длина сертификата сервера, или глубина цепочки сертификатов сервера, "
"превышает пределы, установленные библиотекой криптографии"
#: ../js/ui/components/telepathyClient.js:1346
msgid "Internal error"
@ -833,8 +905,7 @@ msgstr "Изменить учётную запись"
msgid "Unknown reason"
msgstr "Неизвестная причина"
#: ../js/ui/dash.js:253
#: ../js/ui/dash.js:292
#: ../js/ui/dash.js:253 ../js/ui/dash.js:292
msgid "Show Applications"
msgstr "Показать приложения"
@ -866,14 +937,17 @@ msgstr "Выйти из системы"
#: ../js/ui/endSessionDialog.js:63
msgid "Click Log Out to quit these applications and log out of the system."
msgstr "Нажмите «Выйти из системы», чтобы закрыть эти приложения и выйти из системы."
msgstr ""
"Нажмите «Выйти из системы», чтобы закрыть эти приложения и выйти из системы."
#: ../js/ui/endSessionDialog.js:65
#, c-format
msgid "%s will be logged out automatically in %d second."
msgid_plural "%s will be logged out automatically in %d seconds."
msgstr[0] "Сеанс пользователя %s будет автоматически завершён через %d секунду."
msgstr[1] "Сеанс пользователя %s будет автоматически завершён через %d секунды."
msgstr[0] ""
"Сеанс пользователя %s будет автоматически завершён через %d секунду."
msgstr[1] ""
"Сеанс пользователя %s будет автоматически завершён через %d секунды."
msgstr[2] "Сеанс пользователя %s будет автоматически завершён через %d секунд."
#: ../js/ui/endSessionDialog.js:70
@ -914,8 +988,7 @@ msgstr[2] "Система будет автоматически выключен
msgid "Powering off the system."
msgstr "Выключение системы."
#: ../js/ui/endSessionDialog.js:90
#: ../js/ui/endSessionDialog.js:107
#: ../js/ui/endSessionDialog.js:90 ../js/ui/endSessionDialog.js:107
msgctxt "button"
msgid "Restart"
msgstr "Перезапустить"
@ -932,7 +1005,9 @@ msgstr "Перезапустить"
#: ../js/ui/endSessionDialog.js:99
msgid "Click Restart to quit these applications and restart the system."
msgstr "Нажмите «Перезапустить», чтобы закрыть эти приложения и перезапустить систему."
msgstr ""
"Нажмите «Перезапустить», чтобы закрыть эти приложения и перезапустить "
"систему."
#: ../js/ui/endSessionDialog.js:101
#, c-format
@ -959,8 +1034,7 @@ msgstr "Загрузить и установить расширение «%s»
msgid "tray"
msgstr "лоток"
#: ../js/ui/keyboard.js:584
#: ../js/ui/status/keyboard.js:195
#: ../js/ui/keyboard.js:584 ../js/ui/status/keyboard.js:195
#: ../js/ui/status/power.js:205
msgid "Keyboard"
msgstr "Клавиатура"
@ -979,8 +1053,7 @@ msgstr "%s не сообщал о каких-либо ошибках."
msgid "Hide Errors"
msgstr "Скрыть ошибки"
#: ../js/ui/lookingGlass.js:755
#: ../js/ui/lookingGlass.js:815
#: ../js/ui/lookingGlass.js:755 ../js/ui/lookingGlass.js:815
msgid "Show Errors"
msgstr "Показать ошибки"
@ -990,8 +1063,7 @@ msgstr "Включено"
#. translators:
#. * The device has been disabled
#: ../js/ui/lookingGlass.js:767
#: ../src/gvc/gvc-mixer-control.c:1082
#: ../js/ui/lookingGlass.js:767 ../src/gvc/gvc-mixer-control.c:1082
msgid "Disabled"
msgstr "Выключено"
@ -1031,8 +1103,7 @@ msgstr "Панель сообщений"
msgid "System Information"
msgstr "Системная информация"
#: ../js/ui/notificationDaemon.js:506
#: ../src/shell-app.c:374
#: ../js/ui/notificationDaemon.js:506 ../src/shell-app.c:374
msgctxt "program"
msgid "Unknown"
msgstr "Неизвестно"
@ -1140,8 +1211,7 @@ msgstr "Пароль"
msgid "Remember Password"
msgstr "Запомнить пароль"
#: ../js/ui/shellMountOperation.js:400
#: ../js/ui/unlockDialog.js:170
#: ../js/ui/shellMountOperation.js:400 ../js/ui/unlockDialog.js:170
msgid "Unlock"
msgstr "Разблокировать"
@ -1193,14 +1263,10 @@ msgstr "Высокая контрастность"
msgid "Large Text"
msgstr "Крупный текст"
#: ../js/ui/status/bluetooth.js:27
#: ../js/ui/status/bluetooth.js:31
#: ../js/ui/status/bluetooth.js:251
#: ../js/ui/status/bluetooth.js:304
#: ../js/ui/status/bluetooth.js:335
#: ../js/ui/status/bluetooth.js:371
#: ../js/ui/status/bluetooth.js:400
#: ../js/ui/status/network.js:867
#: ../js/ui/status/bluetooth.js:27 ../js/ui/status/bluetooth.js:31
#: ../js/ui/status/bluetooth.js:251 ../js/ui/status/bluetooth.js:304
#: ../js/ui/status/bluetooth.js:335 ../js/ui/status/bluetooth.js:371
#: ../js/ui/status/bluetooth.js:400 ../js/ui/status/network.js:867
msgid "Bluetooth"
msgstr "Bluetooth"
@ -1221,8 +1287,7 @@ msgid "Bluetooth Settings"
msgstr "Настроить Bluetooth"
#. TRANSLATORS: this means that bluetooth was disabled by hardware rfkill
#: ../js/ui/status/bluetooth.js:103
#: ../js/ui/status/network.js:208
#: ../js/ui/status/bluetooth.js:103 ../js/ui/status/network.js:208
msgid "hardware disabled"
msgstr "устройство выключено"
@ -1230,13 +1295,11 @@ msgstr "устройство выключено"
msgid "Connection"
msgstr "Соединение"
#: ../js/ui/status/bluetooth.js:207
#: ../js/ui/status/network.js:458
#: ../js/ui/status/bluetooth.js:207 ../js/ui/status/network.js:458
msgid "disconnecting..."
msgstr "отключение…"
#: ../js/ui/status/bluetooth.js:220
#: ../js/ui/status/network.js:464
#: ../js/ui/status/bluetooth.js:220 ../js/ui/status/network.js:464
#: ../js/ui/status/network.js:934
msgid "connecting..."
msgstr "подключение…"
@ -1266,8 +1329,7 @@ msgstr "Настроить клавиатуру"
msgid "Mouse Settings"
msgstr "Настроить мышь"
#: ../js/ui/status/bluetooth.js:269
#: ../js/ui/status/volume.js:234
#: ../js/ui/status/bluetooth.js:269 ../js/ui/status/volume.js:234
msgid "Sound Settings"
msgstr "Настроить звук"
@ -1294,8 +1356,7 @@ msgstr "Предоставить единовременно"
msgid "Pairing confirmation for %s"
msgstr "Подтверждение на сопряжение с %s"
#: ../js/ui/status/bluetooth.js:378
#: ../js/ui/status/bluetooth.js:408
#: ../js/ui/status/bluetooth.js:378 ../js/ui/status/bluetooth.js:408
#, c-format
msgid "Device %s wants to pair with this computer"
msgstr "Устройство %s пытается выполнить сопряжение с этим компьютером"
@ -1328,11 +1389,11 @@ msgstr "OK"
#: ../js/ui/status/keyboard.js:228
msgid "Show Keyboard Layout"
msgstr "Показать раскладку клавиатуры"
msgstr "Показывать раскладку клавиатуры"
#: ../js/ui/status/keyboard.js:233
msgid "Region and Language Settings"
msgstr "Региональные и языковые параметры"
msgstr "Региональные и языковые настройки"
#: ../js/ui/status/lockScreenMenu.js:18
msgid "Volume, network, battery"
@ -1354,8 +1415,7 @@ msgid "unmanaged"
msgstr "не управляется"
#. Translators: this is for network connections that require some kind of key or password
#: ../js/ui/status/network.js:467
#: ../js/ui/status/network.js:937
#: ../js/ui/status/network.js:467 ../js/ui/status/network.js:937
msgid "authentication required"
msgstr "требуется подтверждение подлинности"
@ -1376,20 +1436,17 @@ msgstr "кабель не подключен"
msgid "unavailable"
msgstr "недоступное"
#: ../js/ui/status/network.js:491
#: ../js/ui/status/network.js:939
#: ../js/ui/status/network.js:491 ../js/ui/status/network.js:939
msgid "connection failed"
msgstr "сбой подключения"
#: ../js/ui/status/network.js:552
#: ../js/ui/status/network.js:1529
#: ../js/ui/status/network.js:552 ../js/ui/status/network.js:1529
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:588
#: ../js/ui/status/network.js:1459
#: ../js/ui/status/network.js:588 ../js/ui/status/network.js:1459
msgid "Connected (private)"
msgstr "Подключено (частное)"
@ -1406,8 +1463,7 @@ msgid "Auto dial-up"
msgstr "Автоматическое коммутируемое"
#. TRANSLATORS: this the automatic wireless connection name (including the network name)
#: ../js/ui/status/network.js:853
#: ../js/ui/status/network.js:1476
#: ../js/ui/status/network.js:853 ../js/ui/status/network.js:1476
#, c-format
msgid "Auto %s"
msgstr "Автоматическое %s"
@ -1510,8 +1566,7 @@ msgstr[0] "Осталась %d минута"
msgstr[1] "Осталось %d минуты"
msgstr[2] "Осталось %d минут"
#: ../js/ui/status/power.js:112
#: ../js/ui/status/power.js:186
#: ../js/ui/status/power.js:112 ../js/ui/status/power.js:186
#, c-format
msgctxt "percent of battery remaining"
msgid "%d%%"
@ -1563,8 +1618,7 @@ msgid "Unknown"
msgstr "Неизвестно"
#. Translators: This is the label for audio volume
#: ../js/ui/status/volume.js:47
#: ../js/ui/status/volume.js:221
#: ../js/ui/status/volume.js:47 ../js/ui/status/volume.js:221
msgid "Volume"
msgstr "Громкость"
@ -1629,8 +1683,12 @@ msgid "Your chat status will be set to busy"
msgstr "Будет установлен статус «не беспокоить»"
#: ../js/ui/userMenu.js:804
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."
msgstr "Уведомления отключены, включая сообщения в чате. Ваш статус доступности изменён, чтобы другие знали, что вы возможно не видите их сообщения."
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."
msgstr ""
"Уведомления отключены, включая сообщения в чате. Ваш статус доступности "
"изменён, чтобы другие знали, что вы возможно не видите их сообщения."
#: ../js/ui/viewSelector.js:85
msgid "Windows"
@ -1677,9 +1735,9 @@ msgstr "Календарь Evolution"
#, c-format
msgid "%u Output"
msgid_plural "%u Outputs"
msgstr[0] "%u выход"
msgstr[1] "%u выхода"
msgstr[2] "%u выходов"
msgstr[0] "%u вывод"
msgstr[1] "%u вывода"
msgstr[2] "%u выводов"
#. translators:
#. * The number of sound inputs on a particular device
@ -1705,7 +1763,8 @@ msgstr "Режим, используемый GDM для окна входа в
#: ../src/main.c:344
msgid "Use a specific mode, e.g. \"gdm\" for login screen"
msgstr "Использовать для экрана входа в систему определённый режим, например «gdm»"
msgstr ""
"Использовать для экрана входа в систему определённый режим, например «gdm»"
#: ../src/main.c:350
msgid "List possible modes"

815
po/sk.po

File diff suppressed because it is too large Load Diff

1081
po/sl.po

File diff suppressed because it is too large Load Diff

946
po/ta.po

File diff suppressed because it is too large Load Diff

3571
po/ug.po

File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More