Compare commits

..

15 Commits

Author SHA1 Message Date
Ray Strode
d985477a9d loginDialog: handle really long messages better
Right now if a long message comes in, the whole dialog grows. This
commit fixes that by making the label a label of the entire screen,
instead of a child of the prompt box. To ensure there's still height
allocated for it, this commit introduces a dummy placeholder actor.
2013-06-19 15:52:36 -04:00
Ray Strode
b188d57609 loginDialog: make entry a little wider by default
With recent changes the dialog is somewhat taller now that it was
before.

This comment makes the prompt entry longer to help square things
out.
2013-06-19 13:37:25 -04:00
Ray Strode
412af26e4e loginDialog: drop separate login hint label
There isn't really room for a login hint label and an auth message label
at the same time.  They shouldn't really be showing messages at the same
time anyway, so consolidate them.
2013-06-19 13:37:25 -04:00
Ray Strode
7b440f3864 loginDialog: pre-allocate prompt message height
Right now things jump around if a message comes in.
This commit makes sure there's room for a message to start.
2013-06-19 13:36:33 -04:00
Ray Strode
2d98903c90 loginDialog: drop padding between buttons and entry
Now that the closed session list preallocates space for its
open self, there is a lot of padding between the entry and
buttons.

This commit helps alleviate the padding problem by getting rid
of the large top padding set above the login buttons.
2013-06-19 13:35:26 -04:00
Ray Strode
9a0d0d2fd3 sessionList: always allocate full height
This helps to prevent stuff from jumping around on the login dialog
when the session list opens.
2013-06-19 13:35:26 -04:00
Ray Strode
9451c04a09 loginDialog: start to move login dialog away from modal dialog 2013-06-19 13:35:26 -04:00
Ray Strode
ca9099997c loginDialog: move user list to its own file
The userList code has no dependencies on anything else in
loginDialog.js so move it to its own file.

This is part of the greater reorganization effort to clean up
the login dialog / unlock dialog situation.
2013-06-18 08:01:27 -04:00
Ray Strode
4de18f2d4b loginDialog: move session list to its own file
The sessionList code has no dependencies on anything else in
loginDialog.js so move it to its own file.

This is part of the greater reorganization effort to clean up
the login dialog / unlock dialog situation.
2013-06-18 08:01:27 -04:00
Ray Strode
73d8f6c993 gdm: move all login/unlock code to auth/ directory
Right now the GDM and unlock code use a mish-mash of files
from ui/ and from gdm/.

This commit consolidates all the files into ui/auth as a
first step toward cleaning up the duplication of code between
the two features.
2013-06-18 08:01:27 -04:00
Ray Strode
2141138a6f gdm: move batch.js to misc/
batch.js has nothing to do with GDM, other than it's used by the login
dialog.

We eventually want to get rid of it entirely, but in the mean time move
it to misc/ for clarity.
2013-06-18 08:01:27 -04:00
Ray Strode
4f135be89a ui: move userAvatar to own file
There are a few places in the code that use the UserAvatar widget
without using the user menu.

Since the avatar is used outside of the user menu, move it from
userMenu.js to its own file.
2013-06-18 08:01:27 -04:00
Ray Strode
026ec2d4c2 ui: move AnimatedIcon out of panel.js
The class is generally useful, so it only makes sense in panel.js
for historical reasons. Because other parts of the code are
using it, though, problems are cropping up that require a
workaround like:

placeSpinner: function(...) {
    /* This is here because of recursive imports */
    const Panel = imports.ui.panel;
    Panel.AnimatedIcon(spinnerIcon, WORK_SPINNER_ICON_SIZE);
    ...
}

This commit moves AnimatedIcon to its own file so we can drop that
workaround.
2013-06-18 08:01:24 -04:00
Ray Strode
a82fae3a2f unlockDialog: clean up unused imports 2013-06-14 08:40:20 -04:00
Ray Strode
892d224cd7 loginDialog: clean up unused imports 2013-06-14 08:16:49 -04:00
101 changed files with 11075 additions and 9460 deletions

89
NEWS
View File

@@ -1,92 +1,3 @@
3.9.5
=====
* Fix width changes of the calendar popup [Florian; #704200]
* Work towards aggregate status menu [Jasper; #702539, #704336, #704368,
#704670]
* Update design of lock screen notifications [Allan; #702305]
* Don't show empty backgroundMenu [Michael; #703868]
* Add option to limit app switcher to current workspace [Adel; #703538]
* Consolidate design of login screen and unlock dialog [Ray; #702308, #704795]
* Respect hasWorkspace property of session mode [Jasper; #698593]
* Fix fade of app menu icon in RTL locales [Jasper; #704583]
* Destroy notifications when the close button is clicked [Adel; #687016]
* Fix clicks on legacy tray icons in the message tray [Florian; #704095]
* authPrompt: Fade out message if users start to type [Ray; #704817]
* Export timestamps of global shortcuts on DBus [Bastien; #704859]
* Fix duplicate search provider results [Jasper; #700283]
* Misc bug fixes and cleanups [Lionel, Florian, Emilio, Ray, Jasper; #703859,
#703540, #704077, #703997, #704318, #704347, #704265, #704411, #704430,
#704347, #704453, #704471, #704542, #704707, #703905, #705037]
Contributors:
Allan Day, Adel Gadllah, Lionel Landwerlin, Florian Müllner, Bastien Nocera,
Emilio Pozuelo Monfort, Jasper St. Pierre, Ray Strode, Colin Walters,
Michael Wood
Translations:
eternalhui [zh_CN], Victor Ibragimov [tg], Dušan Kazik [sk],
Jiro Matsuzawa [ja], Kjartan Maraas [nb], Milo Casagrande [it],
Marek Černocký [cs], Daniel Mustieles [es], Benjamin Steinwender [de]
3.9.4
=====
* Fix chat entries not being focused when expanded [Jasper; #698778]
* Fix alignment of "Not Listed?" label [Mathieu; #702307]
* Fix alignment of time stamps in chat notifications [Carlos; #687809]
* Round the ends of slider trough [Jasper; #702825]
* Add support for "box-shadow: none" [Cosimo; #702782]
* Keep chrome below popup windows [Florian; #702338]
* Move the session list to a popup menu [Ray; #702818]
* Fix autorun notifications for "non-native" volumes [Matthias; #703418]
* dnd: Speed up by not picking on each motion event [Jasper; #703443]
* Fix management of asynchronous background loading [Lionel; #703001]
* Rework focus handling [Jasper; #700735]
* Optimize box-shadow rendering [Lionel; #689858]
* Remove support for fixed positioning in BoxLayouts [Florian; #703808]
* Misc bug fixes and cleanups [Adel, Jasper, Florian, Ray, Lionel, Emilio;
#702849, #610279, #703132, #703105, #703160, #703126, #703304, #703403,
#698593, #703442, #703565, #700901, #703874, #703807, #703893, #703909]
Contributors:
Mathieu Bridon, Giovanni Campagna, Cosimo Cecchi, Matthias Clasen,
Fran Diéguez, Adel Gadllah, Lionel Landwerlin, Florian Müllner,
Emilio Pozuelo Monfort, Carlos Soriano, Jasper St. Pierre, Ray Strode
Translations:
Baurzhan Muftakhidinov [kk], Marek Černocký [cs], Daniel Mustieles [es],
Fran Diéguez [gl], Kjartan Maraas [nb], Andika Triwidada [id],
Benjamin Steinwender [de], Nguyễn Thái Ngọc Duy [vi], Trần Ngọc Quân [vi]
3.9.3
=====
* Don't push window thumbs when workspace switcher is hidden [Jasper; #701167]
* Tweak timeout for activating windows during XDND [Adel; #700150]
* Fix ellipsization in control buttons in app picker [Carlos; #696307]
* Fix DND to empty dash [Florian; #684618]
* Fix OSD window appearing below system modal dialogs [Rui; #701269]
* Clear clipboard on screen lock to prevent information leak [Florian; #698922]
* Allow session mode specific overrides schema [Florian; #701717]
* window-switcher: Only show windows from current workspace by default
[Florian; #701214]
* logout dialog: Show the correct text right away [Matthias; #702056]
* bluetooth: Port to bluez 5 [Emilio; #700891]
* dateMenu: Allow events to span multiple lines [Giovanni; #701231]
* gdm: Clear message queue when no more messages are pending [Jonh; #702458]
* Misc bug fixes and cleanups [Jasper, Florian, Adel, Giovanni; #693836,
#700972, #701386, #700877, #701755, #698918, #701224, #702125, #701954,
#701849, #702121]
Contributors:
Giovanni Campagna, Matthias Clasen, Fran Diéguez, Adel Gadllah, Rui Matos,
Florian Müllner, Emilio Pozuelo Monfort, Carlos Soriano, Jasper St. Pierre,
Jonh Wendell
Translations:
Marek Černocký [cs], Victor Ibragimov [tg], Fran Diéguez [gl],
Benjamin Steinwender [de], Cheng-Chia Tseng [zh_HK, zh_TW],
eternalhui [zh_CN], Ivaylo Valkov [bg], Kjartan Maraas [nb],
Daniel Mustieles [es]
3.9.2
=====
* Use a symbolic icon for DESKTOP windows [Matthias; #697914]

View File

@@ -1,5 +1,5 @@
AC_PREREQ(2.63)
AC_INIT([gnome-shell],[3.9.5],[https://bugzilla.gnome.org/enter_bug.cgi?product=gnome-shell],[gnome-shell])
AC_INIT([gnome-shell],[3.9.2],[https://bugzilla.gnome.org/enter_bug.cgi?product=gnome-shell],[gnome-shell])
AC_CONFIG_HEADERS([config.h])
AC_CONFIG_SRCDIR([src/shell-global.c])
@@ -63,7 +63,7 @@ AM_CONDITIONAL(BUILD_RECORDER, $build_recorder)
CLUTTER_MIN_VERSION=1.13.4
GOBJECT_INTROSPECTION_MIN_VERSION=0.10.1
GJS_MIN_VERSION=1.35.4
MUTTER_MIN_VERSION=3.9.5
MUTTER_MIN_VERSION=3.9.2
GTK_MIN_VERSION=3.7.9
GIO_MIN_VERSION=2.37.0
LIBECAL_MIN_VERSION=3.5.3
@@ -71,7 +71,7 @@ LIBEDATASERVER_MIN_VERSION=3.5.3
TELEPATHY_GLIB_MIN_VERSION=0.17.5
POLKIT_MIN_VERSION=0.100
STARTUP_NOTIFICATION_MIN_VERSION=0.11
GCR_MIN_VERSION=3.7.5
GCR_MIN_VERSION=3.3.90
GNOME_DESKTOP_REQUIRED_VERSION=3.7.90
GNOME_MENUS_REQUIRED_VERSION=3.5.3
NETWORKMANAGER_MIN_VERSION=0.9.8
@@ -109,7 +109,7 @@ PKG_CHECK_MODULES(DESKTOP_SCHEMAS, gsettings-desktop-schemas >= 3.7.4)
PKG_CHECK_MODULES(CARIBOU, caribou-1.0 >= 0.4.8)
AC_MSG_CHECKING([for bluetooth support])
PKG_CHECK_EXISTS([gnome-bluetooth-1.0 >= 3.9.0],
PKG_CHECK_EXISTS([gnome-bluetooth-1.0 >= 3.1.0],
[BLUETOOTH_DIR=`$PKG_CONFIG --variable=applet_libdir gnome-bluetooth-1.0`
BLUETOOTH_LIBS=`$PKG_CONFIG --variable=applet_libs gnome-bluetooth-1.0`
AC_SUBST([BLUETOOTH_LIBS],["$BLUETOOTH_LIBS"])

View File

@@ -186,19 +186,6 @@ value here is from the GsmPresenceStatus enumeration.</_summary>
</key>
</schema>
<schema id="org.gnome.shell.app-switcher"
path="/org/gnome/shell/app-switcher/"
gettext-domain="@GETTEXT_PACKAGE@">
<key type="b" name="current-workspace-only">
<default>false</default>
<summary>Limit switcher to current workspace.</summary>
<description>
If true, only applications that have windows on the current workspace are shown in the switcher.
Otherwise, all applications are included.
</description>
</key>
</schema>
<enum id="org.gnome.shell.window-switcher.AppIconMode">
<value value="1" nick="thumbnail-only"/>
<value value="2" nick="app-icon-only"/>
@@ -217,7 +204,7 @@ value here is from the GsmPresenceStatus enumeration.</_summary>
</_description>
</key>
<key type="b" name="current-workspace-only">
<default>true</default>
<default>false</default>
<summary>Limit switcher to current workspace.</summary>
<description>
If true, only windows from the current workspace are shown in the switcher.

View File

@@ -123,20 +123,6 @@ StScrollBar StButton#vhandle:active {
background-image: url("checkbox-focused.svg");
}
/* Slider */
.slider {
height: 1em;
min-width: 15em;
-slider-height: 0.3em;
-slider-background-color: #333333;
-slider-border-color: #5f5f5f;
-slider-active-background-color: #76b0ec;
-slider-active-border-color: #1f6dbc;
-slider-border-width: 1px;
-slider-handle-radius: 0.5em;
}
/* PopupMenu */
.popup-menu-ornament {
@@ -189,6 +175,13 @@ StScrollBar StButton#vhandle:active {
border-width: 0px;
}
.popup-combo-menu {
background-color: rgba(0,0,0,0.9);
padding: 1em 0em;
border: 1px solid #5f5f5f;
border-radius: 9px;
}
/* The remaining popup-menu sizing is all done in ems, so that if you
* override .popup-menu.font-size, everything else will scale with it.
*/
@@ -212,6 +205,10 @@ StScrollBar StButton#vhandle:active {
.popup-image-menu-item {
}
.popup-combobox-item {
spacing: 1em;
}
.popup-separator-menu-item {
-gradient-height: 1px;
-gradient-start: rgba(255,255,255,0.0);
@@ -225,6 +222,22 @@ StScrollBar StButton#vhandle:active {
font-weight: bold;
}
.popup-slider-menu-item {
height: 1em;
min-width: 15em;
-slider-height: 0.3em;
-slider-background-color: #333333;
-slider-border-color: #5f5f5f;
-slider-active-background-color: #76b0ec;
-slider-active-border-color: #1f6dbc;
-slider-border-width: 1px;
-slider-handle-radius: 0.5em;
}
.popup-device-menu-item {
spacing: .5em;
}
.popup-status-menu-item {
font-weight: normal;
color: #999;
@@ -234,10 +247,19 @@ StScrollBar StButton#vhandle:active {
color: white;
}
.popup-subtitle-menu-item, .popup-subtitle-menu-item:insensitive {
font-weight: bold;
color: white;
}
.popup-menu-icon {
icon-size: 1.09em;
}
.popup-battery-percentage {
padding-left: 24px;
}
/* Switches */
.toggle-switch {
width: 65px;
@@ -262,51 +284,10 @@ StScrollBar StButton#vhandle:active {
background-size: contain;
}
/* Network */
.nm-dialog {
max-height: 400px;
}
.nm-dialog-content {
spacing: 8px;
}
.nm-dialog-header-hbox {
spacing: 4px;
}
.nm-dialog-header-icon {
icon-size: 32px;
}
.nm-dialog-scroll-view {
border: 2px solid #666;
border-radius: 6px;
}
.nm-dialog-header {
font-weight: bold;
}
.nm-dialog-item {
font-size: 12pt;
border-bottom: 1px solid #666;
padding: 12px;
}
.nm-dialog-item:checked {
background-color: #333;
}
.nm-dialog-icons {
.nm-menu-item-icons {
spacing: .5em;
}
.nm-dialog-icon {
icon-size: 16px;
}
/* Buttons */
.candidate-page-button,
@@ -344,6 +325,10 @@ StScrollBar StButton#vhandle:active {
border-width: 2px;
}
.app-view-control:focus {
padding: 3px;
}
.app-view-control:first-child:ltr:focus,
.app-view-control:last-child:rtl:focus {
border-right-width: 1px;
@@ -378,8 +363,7 @@ StScrollBar StButton#vhandle:active {
.modal-dialog-button,
.notification-button,
.hotplug-notification-item,
.app-view-controls,
#screenShieldNotifications {
.app-view-controls {
border-radius: 18px;
}
@@ -488,6 +472,10 @@ StScrollBar StButton#vhandle:active {
height: 1.86em;
}
#panel.lock-screen {
background-color: rgba(0,0,0,0.3);
}
#panel.unlock-screen,
#panel.login-screen {
background-color: transparent;
@@ -622,30 +610,58 @@ StScrollBar StButton#vhandle:active {
spacing: 8px;
}
/* User Menu */
#panelUserMenu {
spacing: 4px;
}
.status-chooser {
spacing: .4em;
}
.status-chooser .popup-menu-item,
.status-chooser-combo .popup-menu-item {
padding: .4em;
}
.status-chooser-user-icon {
border: 2px solid #8b8b8b;
border-radius: 5px;
width: 48pt;
height: 48pt;
background-size: contain;
}
.status-chooser-user-icon:hover {
border: 2px solid #bbbbbb;
}
.status-chooser-user-name {
font-weight: bold;
font-size: 1.3em;
min-width: 120pt;
}
.status-chooser-combo {
border: 1px solid transparent;
}
.status-chooser-combo.popup-combo-menu {
padding: .4em 0em;
border-radius: 4px;
border: 1px solid #5f5f5f;
}
.status-chooser-status-item,
.status-chooser-combo .popup-combobox-item {
spacing: .4em;
}
.system-status-icon {
icon-size: 1.09em;
}
.system-switch-user-submenu-icon {
icon-size: 24px;
border: 1px solid #8b8b8b;
}
.system-menu-action {
color: #e6e6e6;
border-radius: 4px;
padding: 6px;
}
.system-menu-action:hover {
color: white;
background-color: rgba(255,255,255,0.1);
}
.system-menu-action > StIcon {
icon-size: 32px;
}
/* Overview */
#overview {
@@ -794,11 +810,6 @@ StScrollBar StButton#vhandle:active {
height: 24px;
}
.empty-dash-drop-target {
width: 24px;
height: 24px;
}
/* Search Box */
#searchEntry {
@@ -886,18 +897,14 @@ StScrollBar StButton#vhandle:active {
}
.app-view-controls {
width: 250px;
padding-bottom: 32px;
}
.app-view-control {
padding: 4px 32px;
padding: 4px 16px;
}
.app-view-control:focus {
padding: 3px 31px;
}
.search-display > StBoxLayout,
.all-apps > StBoxLayout,
.frequent-apps > StBoxLayout {
@@ -1119,7 +1126,7 @@ StScrollBar StButton#vhandle:active {
padding: 4px;
}
.lg-extensions-list {
.lg-extension-list {
padding: 4px;
spacing: 6px;
}
@@ -1147,6 +1154,11 @@ StScrollBar StButton#vhandle:active {
/* Calendar popup */
#calendarEventsArea {
/* this is the width of the second column of the popup */
min-width: 320px;
}
.calendar-vertical-separator {
-stipple-width: 1px;
-stipple-color: #505050;
@@ -1283,40 +1295,32 @@ StScrollBar StButton#vhandle:active {
color: #333333;
}
.events-table {
width: 320px;
spacing-columns: 6pt;
padding: 0 1.4em;
.events-header-vbox {
spacing: 6pt;
padding-right: .5em;
}
.events-table:ltr {
padding-right: 1.9em;
.events-header-vbox:rtl {
padding-left: .5em;
}
.events-table:rtl {
padding-left: 1.9em;
.events-header-hbox {
padding: 0.3em 1.4em;
}
.events-day-header {
font-weight: bold;
color: #999999;
padding-left: 0.4em;
padding-top: 1.2em;
}
.events-day-header:first-child {
padding-top: 0;
padding: 0.4em 1.4em 0em 1.4em;
}
.events-day-header:rtl {
padding-left: 0;
padding-right: 0.4em;
padding: 0em 1.4em 0.4em 1.4em;
}
.events-day-dayname {
color: rgba(153, 153, 153, 1.0);
text-align: left;
min-width: 20px;
}
.events-day-dayname:rtl {
@@ -1334,12 +1338,23 @@ StScrollBar StButton#vhandle:active {
.events-day-task {
color: rgba(153, 153, 153, 1.0);
padding-left: 8pt;
}
.events-day-task:rtl {
padding-left: 0px;
padding-right: 8pt;
.events-day-name-box {
min-width: 15pt;
}
.events-time-box {
min-width: 48pt;
padding-right: 12pt;
}
.events-time-box:rtl {
padding-right: 0px;
padding-left: 12pt;
}
.events-event-box {
}
.url-highlighter {
@@ -2196,18 +2211,6 @@ StScrollBar StButton#vhandle:active {
/* Login Dialog */
.framed-user-icon {
border: 2px solid #8b8b8b;
border-radius: 5px;
width: 48pt;
height: 48pt;
background-size: contain;
}
.framed-user-icon:hover {
border: 2px solid #bbbbbb;
}
.login-dialog-banner {
font-size: 10pt;
font-weight: bold;
@@ -2238,11 +2241,12 @@ StScrollBar StButton#vhandle:active {
}
.login-dialog-button-box {
spacing: 5px;
spacing: 21px;
}
.login-dialog-prompt-login-hint-message {
font-size: 10.5pt;
min-width: 480px;
}
.login-dialog-user-list-view {
@@ -2324,10 +2328,6 @@ StScrollBar StButton#vhandle:active {
padding-top: 1em;
}
.login-dialog-user-selection-box .login-dialog-not-listed-label {
padding-left: 2px;
}
.login-dialog-not-listed-button:focus .login-dialog-not-listed-label,
.login-dialog-not-listed-button:hover .login-dialog-not-listed-label {
color: #E8E8E8;
@@ -2345,7 +2345,6 @@ StScrollBar StButton#vhandle:active {
padding-top: 24px;
padding-bottom: 12px;
spacing: 8px;
width: 23em;
}
.login-dialog-prompt-label {
@@ -2353,17 +2352,47 @@ StScrollBar StButton#vhandle:active {
font-size: 14px;
}
.login-dialog-session-list-button StIcon {
icon-size: 1.25em;
.login-dialog-prompt-entry {
width: 480px;
}
.login-dialog-session-list,
.login-dialog-session-list-item {
color: #babdb6;
}
.login-dialog-session-list-button:focus,
.login-dialog-session-list-button:active,
.login-dialog-session-list-button:hover,
.login-dialog-session-list-item:focus,
.login-dialog-session-list-item:hover {
color: white;
}
.login-dialog-session-list-button {
color: #8b8b8b;
padding: 4px;
}
.login-dialog-session-list-button:hover,
.login-dialog-session-list-button:active {
color: white;
.login-dialog-session-list-scroll-view {
padding: 6px;
}
.login-dialog-session-list-item {
padding-bottom: 6px;
}
.login-dialog-session-list-triangle {
padding-right: 6px;
}
.login-dialog-session-list-item-box {
padding-left: 6px;
spacing: 6px;
}
.login-dialog-session-list-item-dot {
width: 10px;
height: 10px;
}
.login-dialog-logo-bin {
@@ -2430,11 +2459,6 @@ StScrollBar StButton#vhandle:active {
/* Screen shield */
#panel.lock-screen,
#screenShieldNotifications {
background-color: rgba(0,0,0,0.3);
}
.screen-shield-background {
background: black;
box-shadow: 0px 4px 8px rgba(0,0,0,0.9);
@@ -2479,27 +2503,33 @@ StScrollBar StButton#vhandle:active {
}
#screenShieldNotifications {
border-radius: 8px;
background-color: rgba(0.0, 0.0, 0.0, 0.9);
border: 2px solid #868686;
max-height: 500px;
padding: 12px;
padding: 18px 0;
box-shadow: .5em .5em 20px rgba(0, 0, 0, 0.5);
}
.screen-shield-notifications-box {
spacing: 12px;
width: 30em;
spacing: 18px;
max-width: 34em;
}
.screen-shield-notification-source {
padding: 3px 6px;
padding: 13px 24px;
spacing: 5px;
}
.screen-shield-notification-label {
font-size: 1.2em;
font-weight: bold;
padding: 0px 0px 0px 12px;
padding: 0px 18px;
color: #babdb6;
}
.screen-shield-notification-count-text {
padding: 0px 0px 0px 12px;
padding: 0px 18px;
}
/* Remove background from notifications, otherwise
@@ -2517,31 +2547,6 @@ StScrollBar StButton#vhandle:active {
padding-bottom: 0px;
}
#screenShieldNotifications .notification-button,
#screenShieldNotifications .notification-icon-button {
border: 1px rgba(255,255,255,0.5);
}
#screenShieldNotifications StScrollBar StBin#trough {
background-color: rgba(0,0,0,0.2);
}
#screenShieldNotifications StScrollBar StButton#vhandle,
#screenShieldNotifications StScrollBar StButton#hhandle {
background-color: rgba(0,0,0,0.3);
border: none;
}
#screenShieldNotifications StScrollBar StButton#vhandle:hover,
#screenShieldNotifications StScrollBar StButton#hhandle {
background-color: rgba(0,0,0,0.6);
}
#screenShieldNotifications StScrollBar StButton#vhandle:active,
#screenShieldNotifications StScrollBar StButton#hhandle {
background-color: rgba(0,0,0,0.8);
}
.input-source-switcher-symbol {
font-size: 34pt;
width: 96px;

View File

@@ -17,14 +17,8 @@ misc/config.js: misc/config.js.in Makefile
jsdir = $(pkgdatadir)/js
nobase_dist_js_DATA = \
gdm/authPrompt.js \
gdm/batch.js \
gdm/fingerprint.js \
gdm/loginDialog.js \
gdm/powerMenu.js \
gdm/realmd.js \
gdm/util.js \
extensionPrefs/main.js \
misc/batch.js \
misc/config.js \
misc/extensionUtils.js \
misc/fileUtils.js \
@@ -70,7 +64,6 @@ nobase_dist_js_DATA = \
ui/sessionMode.js \
ui/shellEntry.js \
ui/shellMountOperation.js \
ui/slider.js \
ui/notificationDaemon.js \
ui/osdWindow.js \
ui/overview.js \
@@ -96,10 +89,10 @@ nobase_dist_js_DATA = \
ui/status/power.js \
ui/status/volume.js \
ui/status/bluetooth.js \
ui/status/system.js \
ui/switcherPopup.js \
ui/tweener.js \
ui/unlockDialog.js \
ui/userAvatar.js \
ui/userMenu.js \
ui/userWidget.js \
ui/viewSelector.js \
ui/wanda.js \
@@ -110,6 +103,14 @@ nobase_dist_js_DATA = \
ui/workspacesView.js \
ui/workspaceSwitcherPopup.js \
ui/xdndHandler.js \
ui/auth/fingerprint.js \
ui/auth/loginDialog.js \
ui/auth/powerMenu.js \
ui/auth/realmd.js \
ui/auth/sessionList.js \
ui/auth/unlockDialog.js \
ui/auth/userList.js \
ui/auth/util.js \
ui/components/__init__.js \
ui/components/autorunManager.js \
ui/components/automountManager.js \

View File

@@ -1,458 +0,0 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
const Clutter = imports.gi.Clutter;
const Lang = imports.lang;
const Signals = imports.signals;
const St = imports.gi.St;
const Animation = imports.ui.animation;
const Batch = imports.gdm.batch;
const GdmUtil = imports.gdm.util;
const Params = imports.misc.params;
const ShellEntry = imports.ui.shellEntry;
const Tweener = imports.ui.tweener;
const UserWidget = imports.ui.userWidget;
const DEFAULT_BUTTON_WELL_ICON_SIZE = 24;
const DEFAULT_BUTTON_WELL_ANIMATION_DELAY = 1.0;
const DEFAULT_BUTTON_WELL_ANIMATION_TIME = 0.3;
const MESSAGE_FADE_OUT_ANIMATION_TIME = 0.5;
const AuthPromptMode = {
UNLOCK_ONLY: 0,
UNLOCK_OR_LOG_IN: 1
};
const AuthPrompt = new Lang.Class({
Name: 'AuthPrompt',
_init: function(gdmClient, mode) {
this.verifyingUser = false;
this._gdmClient = gdmClient;
this._mode = mode;
let reauthenticationOnly;
if (this._mode == AuthPromptMode.UNLOCK_ONLY)
reauthenticationOnly = true;
else if (this._mode == AuthPromptMode.UNLOCK_OR_LOG_IN)
reauthenticationOnly = false;
this._userVerifier = new GdmUtil.ShellUserVerifier(this._gdmClient, { reauthenticationOnly: reauthenticationOnly });
this._userVerifier.connect('ask-question', Lang.bind(this, this._onAskQuestion));
this._userVerifier.connect('show-message', Lang.bind(this, this._onShowMessage));
this._userVerifier.connect('verification-failed', Lang.bind(this, this._onVerificationFailed));
this._userVerifier.connect('verification-complete', Lang.bind(this, this._onVerificationComplete));
this._userVerifier.connect('reset', Lang.bind(this, this._onReset));
this._userVerifier.connect('show-login-hint', Lang.bind(this, this._onShowLoginHint));
this._userVerifier.connect('hide-login-hint', Lang.bind(this, this._onHideLoginHint));
this.connect('next', Lang.bind(this, function() {
this.updateSensitivity(false);
this.startSpinning();
if (this._queryingService) {
this._userVerifier.answerQuery(this._queryingService, this._entry.text);
} else {
this._preemptiveAnswer = this._entry.text;
}
}));
this.actor = new St.BoxLayout({ style_class: 'login-dialog-prompt-layout',
vertical: true });
this.actor.connect('destroy', Lang.bind(this, this._onDestroy));
this.actor.connect('key-press-event',
Lang.bind(this, function(actor, event) {
if (event.get_key_symbol() == Clutter.KEY_Escape) {
this.cancel();
}
}));
this._userWell = new St.Bin({ x_fill: true,
x_align: St.Align.START });
this.actor.add(this._userWell,
{ x_align: St.Align.START,
x_fill: true,
y_fill: true,
expand: true });
this._label = new St.Label({ style_class: 'login-dialog-prompt-label' });
this.actor.add(this._label,
{ expand: true,
x_fill: true,
y_fill: true,
x_align: St.Align.START });
this._entry = new St.Entry({ style_class: 'login-dialog-prompt-entry',
can_focus: true });
ShellEntry.addContextMenu(this._entry, { isPassword: true });
this.actor.add(this._entry,
{ expand: true,
x_fill: true,
y_fill: false,
x_align: St.Align.START });
this._entry.grab_key_focus();
this._message = new St.Label({ opacity: 0 });
this._message.clutter_text.line_wrap = true;
this.actor.add(this._message, { x_fill: true });
this._loginHint = new St.Label({ style_class: 'login-dialog-prompt-login-hint-message' });
this.actor.add(this._loginHint);
this._buttonBox = new St.BoxLayout({ style_class: 'login-dialog-button-box',
vertical: false });
this.actor.add(this._buttonBox,
{ expand: true,
x_align: St.Align.MIDDLE,
y_align: St.Align.END });
this._defaultButtonWell = new St.Widget();
this._defaultButtonWellActor = null;
this._initButtons();
let spinnerIcon = global.datadir + '/theme/process-working.svg';
this._spinner = new Animation.AnimatedIcon(spinnerIcon, DEFAULT_BUTTON_WELL_ICON_SIZE);
this._spinner.actor.opacity = 0;
this._spinner.actor.show();
this._defaultButtonWell.add_child(this._spinner.actor);
},
_onDestroy: function() {
this._userVerifier.clear();
},
_initButtons: function() {
this.cancelButton = new St.Button({ style_class: 'modal-dialog-button',
button_mask: St.ButtonMask.ONE | St.ButtonMask.THREE,
reactive: true,
can_focus: true,
label: _("Cancel") });
this.cancelButton.connect('clicked',
Lang.bind(this, function() {
this.cancel();
}));
this._buttonBox.add(this.cancelButton,
{ expand: false,
x_fill: false,
y_fill: false,
x_align: St.Align.START,
y_align: St.Align.END });
this._buttonBox.add(this._defaultButtonWell,
{ expand: true,
x_fill: false,
y_fill: false,
x_align: St.Align.END,
y_align: St.Align.MIDDLE });
this.nextButton = new St.Button({ style_class: 'modal-dialog-button',
button_mask: St.ButtonMask.ONE | St.ButtonMask.THREE,
reactive: true,
can_focus: true,
label: _("Next") });
this.nextButton.connect('clicked',
Lang.bind(this, function() {
this.emit('next');
}));
this.nextButton.add_style_pseudo_class('default');
this._buttonBox.add(this.nextButton,
{ expand: false,
x_fill: false,
y_fill: false,
x_align: St.Align.END,
y_align: St.Align.END });
this._updateNextButtonSensitivity(this._entry.text.length > 0);
this._entry.clutter_text.connect('text-changed',
Lang.bind(this, function() {
if (!this._userVerifier.hasPendingMessages)
this._fadeOutMessage();
this._updateNextButtonSensitivity(this._entry.text.length > 0);
}));
this._entry.clutter_text.connect('activate', Lang.bind(this, function() {
this.emit('next');
}));
},
_onAskQuestion: function(verifier, serviceName, question, passwordChar) {
if (this._preemptiveAnswer) {
this._userVerifier.answerQuery(this._queryingService, this._preemptiveAnswer);
this._preemptiveAnswer = null;
return;
}
if (this._queryingService)
this.clear();
this._queryingService = serviceName;
this.setPasswordChar(passwordChar);
this.setQuestion(question);
if (this.verifyingUser)
this.cancelButton.show();
else
this.cancelButton.hide();
if (passwordChar) {
if (this._userVerifier.reauthenticating)
this.nextButton.label = _("Unlock");
else
this.nextButton.label = C_("button", "Sign In");
} else {
this.nextButton.label = _("Next");
}
this.updateSensitivity(true);
this.emit('prompted');
},
_onShowMessage: function(userVerifier, message, styleClass) {
this.setMessage(message, styleClass);
},
_onVerificationFailed: function() {
this.clear();
this.updateSensitivity(true);
this.setActorInDefaultButtonWell(null);
this.userVerified = false;
},
_onVerificationComplete: function() {
this.userVerified = true;
},
_onReset: function() {
if (!this.userVerified)
this.reset();
},
_onShowLoginHint: function(verifier, message) {
this.setHint(message);
},
_onHideLoginHint: function() {
this.setHint(null);
},
addActorToDefaultButtonWell: function(actor) {
this._defaultButtonWell.add_child(actor);
actor.add_constraint(new Clutter.AlignConstraint({ source: this._spinner.actor,
align_axis: Clutter.AlignAxis.BOTH,
factor: 0.5 }));
},
setActorInDefaultButtonWell: function(actor, animate) {
if (!this._defaultButtonWellActor &&
!actor)
return;
let oldActor = this._defaultButtonWellActor;
if (oldActor)
Tweener.removeTweens(oldActor);
let isSpinner;
if (actor == this._spinner.actor)
isSpinner = true;
else
isSpinner = false;
if (this._defaultButtonWellActor != actor && oldActor) {
if (!animate) {
oldActor.opacity = 0;
} else {
Tweener.addTween(oldActor,
{ opacity: 0,
time: DEFAULT_BUTTON_WELL_ANIMATION_TIME,
delay: DEFAULT_BUTTON_WELL_ANIMATION_DELAY,
transition: 'linear',
onCompleteScope: this,
onComplete: function() {
if (isSpinner) {
if (this._spinner)
this._spinner.stop();
}
}
});
}
}
if (actor) {
if (isSpinner)
this._spinner.play();
if (!animate)
actor.opacity = 255;
else
Tweener.addTween(actor,
{ opacity: 255,
time: DEFAULT_BUTTON_WELL_ANIMATION_TIME,
delay: DEFAULT_BUTTON_WELL_ANIMATION_DELAY,
transition: 'linear' });
}
this._defaultButtonWellActor = actor;
},
startSpinning: function() {
this.setActorInDefaultButtonWell(this._spinner.actor, true);
},
stopSpinning: function() {
this.setActorInDefaultButtonWell(null, false);
},
clear: function() {
this._entry.text = '';
this.stopSpinning();
},
setPasswordChar: function(passwordChar) {
this._entry.clutter_text.set_password_char(passwordChar);
this._entry.menu.isPassword = passwordChar != '';
},
setQuestion: function(question) {
this._label.set_text(question);
this._label.show();
this._entry.show();
this._loginHint.opacity = 0;
this._loginHint.show();
this._entry.grab_key_focus();
},
getAnswer: function() {
let text = this._entry.get_text();
return text;
},
_fadeOutMessage: function() {
if (this._message.opacity == 0)
return;
Tweener.removeTweens(this._message);
Tweener.addTween(this._message,
{ opacity: 0,
time: MESSAGE_FADE_OUT_ANIMATION_TIME,
transition: 'easeOutQuad'
});
},
setMessage: function(message, styleClass) {
if (message) {
Tweener.removeTweens(this._message);
this._message.text = message;
this._message.styleClass = styleClass;
this._message.opacity = 255;
} else {
this._message.opacity = 0;
}
},
_updateNextButtonSensitivity: function(sensitive) {
this.nextButton.reactive = sensitive;
this.nextButton.can_focus = sensitive;
},
updateSensitivity: function(sensitive) {
this._updateNextButtonSensitivity(sensitive);
this._entry.reactive = sensitive;
this._entry.clutter_text.editable = sensitive;
},
hide: function() {
this.setActorInDefaultButtonWell(null, true);
this.actor.hide();
this._loginHint.opacity = 0;
this.setUser(null);
this.updateSensitivity(true);
this._entry.set_text('');
},
setUser: function(user) {
if (user) {
let userWidget = new UserWidget.UserWidget(user);
this._userWell.set_child(userWidget.actor);
} else {
this._userWell.set_child(null);
}
},
setHint: function(message) {
if (message) {
this._loginHint.set_text(message)
this._loginHint.opacity = 255;
} else {
this._loginHint.opacity = 0;
this._loginHint.set_text('');
}
},
reset: function() {
this.verifyingUser = false;
this.userVerified = false;
this._queryingService = null;
this.clear();
this._message.opacity = 0;
this.setUser(null);
this.stopSpinning();
this.setHint(null);
this.emit('reset');
},
addCharacter: function(unichar) {
if (!this._entry.visible)
return;
this._entry.grab_key_focus();
this._entry.clutter_text.insert_unichar(unichar);
},
begin: function(params) {
params = Params.parse(params, { userName: null,
hold: null });
this.updateSensitivity(false);
let hold = params.hold;
if (!hold)
hold = new Batch.Hold();
this._userVerifier.begin(params.userName, hold);
this.verifyingUser = true;
},
finish: function(onComplete) {
if (!this._userVerifier.hasPendingMessages) {
onComplete();
return;
}
let signalId = this._userVerifier.connect('no-more-messages',
Lang.bind(this, function() {
this._userVerifier.disconnect(signalId);
onComplete();
}));
},
cancel: function() {
if (this.verifyingUser)
this._userVerifier.cancel();
this.reset();
}
});
Signals.addSignalMethods(AuthPrompt.prototype);

View File

@@ -436,11 +436,8 @@ const AppSwitcher = new Lang.Class({
this._arrows = [];
let windowTracker = Shell.WindowTracker.get_default();
let settings = new Gio.Settings({ schema: 'org.gnome.shell.app-switcher' });
let workspace = settings.get_boolean('current-workspace-only') ? global.screen.get_active_workspace()
: null;
let allWindows = global.display.get_tab_list(Meta.TabList.NORMAL,
global.screen, workspace);
global.screen, null);
// Construct the AppIcons, add to the popup
for (let i = 0; i < apps.length; i++) {
@@ -450,9 +447,7 @@ const AppSwitcher = new Lang.Class({
appIcon.cachedWindows = allWindows.filter(function(w) {
return windowTracker.get_window_app (w) == appIcon.app;
});
if (workspace == null || appIcon.cachedWindows.length > 0) {
this._addIcon(appIcon);
}
this._addIcon(appIcon);
}
this._curApp = -1;

View File

@@ -336,31 +336,6 @@ const Views = {
ALL: 1
};
const ControlsBoxLayout = Lang.Class({
Name: 'ControlsBoxLayout',
Extends: Clutter.BoxLayout,
/**
* Override the BoxLayout behavior to use the maximum preferred width of all
* buttons for each child
*/
vfunc_get_preferred_width: function(container, forHeight) {
let maxMinWidth = 0;
let maxNaturalWidth = 0;
for (let child = container.get_first_child();
child;
child = child.get_next_sibling()) {
let [minWidth, natWidth] = child.get_preferred_width(forHeight);
maxMinWidth = Math.max(maxMinWidth, minWidth);
maxNaturalWidth = Math.max(maxNaturalWidth, natWidth);
}
let childrenCount = container.get_n_children();
let totalSpacing = this.spacing * (childrenCount - 1);
return [maxMinWidth * childrenCount + totalSpacing,
maxNaturalWidth * childrenCount + totalSpacing];
}
});
const AppDisplay = new Lang.Class({
Name: 'AppDisplay',
@@ -404,10 +379,9 @@ const AppDisplay = new Lang.Class({
x_expand: true, y_expand: true });
this.actor.add(this._viewStack, { expand: true });
let layout = new ControlsBoxLayout({ homogeneous: true });
let layout = new Clutter.BoxLayout({ homogeneous: true });
this._controls = new St.Widget({ style_class: 'app-view-controls',
layout_manager: layout });
layout.hookup_style(this._controls);
this.actor.add(new St.Bin({ child: this._controls }));

File diff suppressed because it is too large Load Diff

View File

@@ -23,7 +23,7 @@ const Lang = imports.lang;
const LoginManager = imports.misc.loginManager;
const GdmUtil = imports.gdm.util;
const AuthUtil = imports.ui.auth.util;
const PanelMenu = imports.ui.panelMenu;
const PopupMenu = imports.ui.popupMenu;
@@ -37,7 +37,7 @@ const PowerMenuButton = new Lang.Class({
this._loginManager = LoginManager.getLoginManager();
this._settings = new Gio.Settings({ schema: GdmUtil.LOGIN_SCREEN_SCHEMA });
this._settings = new Gio.Settings({ schema: AuthUtil.LOGIN_SCREEN_SCHEMA });
this._settings.connect('changed::disable-restart-buttons',
Lang.bind(this, this._updateVisibility));

230
js/ui/auth/sessionList.js Normal file
View File

@@ -0,0 +1,230 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
/*
* Copyright 2011 Red Hat, Inc
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*/
const Gtk = imports.gi.Gtk;
const Lang = imports.lang;
const Signals = imports.signals;
const St = imports.gi.St;
const Gdm = imports.gi.Gdm;
const SessionListItem = new Lang.Class({
Name: 'SessionListItem',
_init: function(id, name) {
this.id = id;
this.actor = new St.Button({ style_class: 'login-dialog-session-list-item',
button_mask: St.ButtonMask.ONE | St.ButtonMask.THREE,
can_focus: true,
reactive: true,
x_fill: true,
x_align: St.Align.START });
this._box = new St.BoxLayout({ style_class: 'login-dialog-session-list-item-box' });
this.actor.add_actor(this._box);
this.actor.connect('clicked', Lang.bind(this, this._onClicked));
this._dot = new St.DrawingArea({ style_class: 'login-dialog-session-list-item-dot' });
this._dot.connect('repaint', Lang.bind(this, this._onRepaintDot));
this._box.add_actor(this._dot);
this.setShowDot(false);
let label = new St.Label({ style_class: 'login-dialog-session-list-item-label',
text: name });
this.actor.label_actor = label;
this._box.add_actor(label);
},
setShowDot: function(show) {
if (show)
this._dot.opacity = 255;
else
this._dot.opacity = 0;
},
_onRepaintDot: function(area) {
let cr = area.get_context();
let [width, height] = area.get_surface_size();
let color = area.get_theme_node().get_foreground_color();
cr.setSourceRGBA (color.red / 255,
color.green / 255,
color.blue / 255,
color.alpha / 255);
cr.arc(width / 2, height / 2, width / 3, 0, 2 * Math.PI);
cr.fill();
cr.$dispose();
},
_onClicked: function() {
this.emit('activate');
}
});
Signals.addSignalMethods(SessionListItem.prototype);
const SessionList = new Lang.Class({
Name: 'SessionList',
_init: function() {
this.actor = new St.Bin();
this._box = new St.BoxLayout({ style_class: 'login-dialog-session-list',
vertical: true});
this.actor.child = this._box;
this._button = new St.Button({ style_class: 'login-dialog-session-list-button',
button_mask: St.ButtonMask.ONE | St.ButtonMask.THREE,
can_focus: true,
x_fill: true,
y_fill: true });
let box = new St.BoxLayout();
this._button.add_actor(box);
this._triangle = new St.Label({ style_class: 'login-dialog-session-list-triangle',
text: '\u25B8' });
box.add_actor(this._triangle);
let label = new St.Label({ style_class: 'login-dialog-session-list-label',
text: _("Session…") });
box.add_actor(label);
this._button.connect('clicked',
Lang.bind(this, this._onClicked));
this._box.add_actor(this._button);
this._scrollView = new St.ScrollView({ style_class: 'login-dialog-session-list-scroll-view'});
this._scrollView.set_policy(Gtk.PolicyType.NEVER,
Gtk.PolicyType.AUTOMATIC);
this._box.add_actor(this._scrollView);
this._itemList = new St.BoxLayout({ style_class: 'login-dialog-session-item-list',
vertical: true });
this._scrollView.add_actor(this._itemList);
this._hideSessions();
this.isOpen = false;
this._populate();
},
_hideSessions: function() {
this._itemList.can_focus = false;
this._itemList.reactive = false;
this._scrollView.opacity = 0;
},
_showSessions: function() {
this._scrollView.opacity = 255;
this._itemList.reactive = true;
this._itemList.can_focus = true;
},
open: function() {
if (this.isOpen)
return;
this._button.add_style_pseudo_class('open');
this._showSessions();
this._triangle.set_text('\u25BE');
this.isOpen = true;
},
close: function() {
if (!this.isOpen)
return;
this._button.remove_style_pseudo_class('open');
this._hideSessions();
this._triangle.set_text('\u25B8');
this.isOpen = false;
},
_onClicked: function() {
if (!this.isOpen)
this.open();
else
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;
if (this._activeSessionId)
this._items[this._activeSessionId].setShowDot(false);
this._items[sessionId].setShowDot(true);
this._activeSessionId = sessionId;
this.emit('session-activated', this._activeSessionId);
},
_populate: function() {
this._itemList.destroy_all_children();
this._activeSessionId = null;
this._items = {};
let ids = Gdm.get_session_ids();
ids.sort();
if (ids.length <= 1) {
this._box.hide();
this._button.hide();
} else {
this._button.show();
this._box.show();
}
for (let i = 0; i < ids.length; i++) {
let [sessionName, sessionDescription] = Gdm.get_session_name_and_description(ids[i]);
let item = new SessionListItem(ids[i], sessionName);
this._itemList.add_actor(item.actor);
this._items[ids[i]] = item;
if (!this._activeSessionId)
this.setActiveSession(ids[i]);
item.connect('activate',
Lang.bind(this, function() {
this.setActiveSession(item.id);
}));
item.actor.can_focus = this._itemList.can_focus;
let signalId = this._itemList.connect('notify::can-focus',
Lang.bind(this, function() {
item.actor.can_focus = this._itemList.can_focus;
}));
item.actor.connect('destroy',
Lang.bind(this, function() {
this._itemList.disconnect(signalId);
}));
}
}
});
Signals.addSignalMethods(SessionList.prototype);

293
js/ui/auth/unlockDialog.js Normal file
View File

@@ -0,0 +1,293 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
const AccountsService = imports.gi.AccountsService;
const Clutter = imports.gi.Clutter;
const Gdm = imports.gi.Gdm;
const Gio = imports.gi.Gio;
const GLib = imports.gi.GLib;
const GnomeDesktop = imports.gi.GnomeDesktop;
const Lang = imports.lang;
const Shell = imports.gi.Shell;
const St = imports.gi.St;
const Main = imports.ui.main;
const ModalDialog = imports.ui.modalDialog;
const ShellEntry = imports.ui.shellEntry;
const UserWidget = imports.ui.userWidget;
const AuthUtil = imports.ui.auth.util;
const Batch = imports.misc.batch;
// The timeout before going back automatically to the lock screen (in seconds)
const IDLE_TIMEOUT = 2 * 60;
const UnlockDialog = new Lang.Class({
Name: 'UnlockDialog',
Extends: ModalDialog.ModalDialog,
_init: function(parentActor) {
this.parent({ shellReactive: true,
styleClass: 'login-dialog',
keybindingMode: Shell.KeyBindingMode.UNLOCK_SCREEN,
parentActor: parentActor
});
this._userManager = AccountsService.UserManager.get_default();
this._userName = GLib.get_user_name();
this._user = this._userManager.get_user(this._userName);
this._failCounter = 0;
this._firstQuestion = true;
this._greeterClient = new Gdm.Client();
this._userVerifier = new AuthUtil.ShellUserVerifier(this._greeterClient, { reauthenticationOnly: true });
this._userVerified = false;
this._userVerifier.connect('ask-question', Lang.bind(this, this._onAskQuestion));
this._userVerifier.connect('show-message', Lang.bind(this, this._showMessage));
this._userVerifier.connect('verification-complete', Lang.bind(this, this._onVerificationComplete));
this._userVerifier.connect('verification-failed', Lang.bind(this, this._onVerificationFailed));
this._userVerifier.connect('reset', Lang.bind(this, this._onReset));
this._userVerifier.connect('show-login-hint', Lang.bind(this, this._showLoginHint));
this._userVerifier.connect('hide-login-hint', Lang.bind(this, this._hideLoginHint));
this._userWidget = new UserWidget.UserWidget(this._user);
this.contentLayout.add_actor(this._userWidget.actor);
this._promptLayout = new St.BoxLayout({ style_class: 'login-dialog-prompt-layout',
vertical: true });
this._promptLabel = new St.Label({ style_class: 'login-dialog-prompt-label' });
this._promptLayout.add(this._promptLabel,
{ x_align: St.Align.START });
this._promptEntry = new St.Entry({ style_class: 'login-dialog-prompt-entry',
can_focus: true });
this._promptEntry.clutter_text.connect('activate', Lang.bind(this, this._doUnlock));
this._promptEntry.clutter_text.set_password_char('\u25cf');
ShellEntry.addContextMenu(this._promptEntry, { isPassword: true });
this.setInitialKeyFocus(this._promptEntry);
this._promptEntry.clutter_text.connect('text-changed', Lang.bind(this, function() {
this._updateOkButtonSensitivity(this._promptEntry.text.length > 0);
}));
this._promptLayout.add(this._promptEntry,
{ expand: true,
x_fill: true });
this.contentLayout.add_actor(this._promptLayout);
this._promptMessage = new St.Label({ visible: false });
this.contentLayout.add(this._promptMessage, { x_fill: true });
this._promptLoginHint = new St.Label({ style_class: 'login-dialog-prompt-login-hint' });
this._promptLoginHint.hide();
this.contentLayout.add_actor(this._promptLoginHint);
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.placeSpinner({ 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;
}
this._updateSensitivity(true);
let batch = new Batch.Hold();
this._userVerifier.begin(this._userName, batch);
Main.ctrlAltTabManager.addGroup(this.dialogLayout, _("Unlock Window"), 'dialog-password-symbolic');
this._idleMonitor = new GnomeDesktop.IdleMonitor();
this._idleWatchId = this._idleMonitor.add_idle_watch(IDLE_TIMEOUT * 1000, Lang.bind(this, this._escape));
},
_updateSensitivity: function(sensitive) {
this._promptEntry.reactive = sensitive;
this._promptEntry.clutter_text.editable = sensitive;
this._updateOkButtonSensitivity(sensitive && this._promptEntry.text.length > 0);
if (this._otherUserButton) {
this._otherUserButton.reactive = sensitive;
this._otherUserButton.can_focus = sensitive;
}
},
_updateOkButtonSensitivity: function(sensitive) {
this._okButton.reactive = sensitive;
this._okButton.can_focus = sensitive;
},
_showMessage: function(userVerifier, message, styleClass) {
if (message) {
this._promptMessage.text = message;
this._promptMessage.styleClass = styleClass;
AuthUtil.fadeInActor(this._promptMessage);
} else {
AuthUtil.fadeOutActor(this._promptMessage);
}
},
_onAskQuestion: function(verifier, serviceName, question, passwordChar) {
if (this._firstQuestion && this._firstQuestionAnswer) {
this._userVerifier.answerQuery(serviceName, this._firstQuestionAnswer);
this._firstQuestionAnswer = null;
this._firstQuestion = false;
return;
}
this._promptLabel.text = question;
if (!this._firstQuestion)
this._promptEntry.text = '';
else
this._firstQuestion = false;
this._promptEntry.clutter_text.set_password_char(passwordChar);
this._promptEntry.menu.isPassword = passwordChar != '';
this._currentQuery = serviceName;
this._updateSensitivity(true);
this.setWorking(false);
},
_showLoginHint: function(verifier, message) {
this._promptLoginHint.set_text(message)
AuthUtil.fadeInActor(this._promptLoginHint);
},
_hideLoginHint: function() {
AuthUtil.fadeOutActor(this._promptLoginHint);
},
_doUnlock: function() {
if (this._firstQuestion) {
// we haven't received a query yet, so stash the answer
// and make ourself non-reactive
// the actual reply to GDM will be sent as soon as asked
this._firstQuestionAnswer = this._promptEntry.text;
this._updateSensitivity(false);
this.setWorking(true);
return;
}
if (!this._currentQuery)
return;
let query = this._currentQuery;
this._currentQuery = null;
this._updateSensitivity(false);
this.setWorking(true);
this._userVerifier.answerQuery(query, this._promptEntry.text);
},
_finishUnlock: function() {
this._userVerifier.clear();
this.emit('unlocked');
},
_onVerificationComplete: function() {
this._userVerified = true;
if (!this._userVerifier.hasPendingMessages) {
this._finishUnlock();
} else {
let signalId = this._userVerifier.connect('no-more-messages',
Lang.bind(this, function() {
this._userVerifier.disconnect(signalId);
this._finishUnlock();
}));
}
},
_onReset: function() {
if (!this._userVerified) {
this._userVerifier.clear();
this.emit('failed');
}
},
_onVerificationFailed: function() {
this._currentQuery = null;
this._firstQuestion = true;
this._userVerified = false;
this._promptEntry.text = '';
this._promptEntry.clutter_text.set_password_char('\u25cf');
this._promptEntry.menu.isPassword = true;
this._updateSensitivity(false);
this.setWorking(false);
},
_escape: function() {
if (this.allowCancel) {
this._userVerifier.cancel();
this.emit('failed');
}
},
_otherUserClicked: function(button, event) {
Gdm.goto_login_session_sync(null);
this._userVerifier.cancel();
this.emit('failed');
},
destroy: function() {
this._userVerifier.clear();
if (this._idleWatchId) {
this._idleMonitor.remove_watch(this._idleWatchId);
this._idleWatchId = 0;
}
this.parent();
},
cancel: function() {
this._userVerifier.cancel(null);
this.destroy();
},
addCharacter: function(unichar) {
this._promptEntry.clutter_text.insert_unichar(unichar);
},
});

251
js/ui/auth/userList.js Normal file
View File

@@ -0,0 +1,251 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
const AccountsService = imports.gi.AccountsService;
const Gtk = imports.gi.Gtk;
const Meta = imports.gi.Meta;
const Lang = imports.lang;
const Signals = imports.signals;
const St = imports.gi.St;
const Gdm = imports.gi.Gdm;
const Batch = imports.misc.batch;
const Tweener = imports.ui.tweener;
const UserAvatar = imports.ui.userAvatar;
const _SCROLL_ANIMATION_TIME = 0.5;
const UserListItem = new Lang.Class({
Name: 'UserListItem',
_init: function(user) {
this.user = user;
this._userChangedId = this.user.connect('changed',
Lang.bind(this, this._onUserChanged));
let layout = new St.BoxLayout({ vertical: false });
this.actor = new St.Button({ style_class: 'login-dialog-user-list-item',
button_mask: St.ButtonMask.ONE | St.ButtonMask.THREE,
can_focus: true,
child: layout,
reactive: true,
x_align: St.Align.START,
x_fill: true });
this._userAvatar = new UserAvatar.UserAvatar(this.user,
{ styleClass: 'login-dialog-user-list-item-icon' });
layout.add(this._userAvatar.actor);
let textLayout = new St.BoxLayout({ style_class: 'login-dialog-user-list-item-text-box',
vertical: true });
layout.add(textLayout, { expand: true });
this._nameLabel = new St.Label({ style_class: 'login-dialog-user-list-item-name' });
this.actor.label_actor = this._nameLabel;
textLayout.add(this._nameLabel,
{ y_fill: false,
y_align: St.Align.MIDDLE,
expand: true });
this._timedLoginIndicator = new St.Bin({ style_class: 'login-dialog-timed-login-indicator',
scale_x: 0 });
textLayout.add(this._timedLoginIndicator,
{ x_fill: true,
x_align: St.Align.MIDDLE,
y_fill: false,
y_align: St.Align.END });
this.actor.connect('clicked', Lang.bind(this, this._onClicked));
this._onUserChanged();
},
_onUserChanged: function() {
this._nameLabel.set_text(this.user.get_real_name());
this._userAvatar.update();
this._updateLoggedIn();
},
syncStyleClasses: function() {
this._updateLoggedIn();
if (global.stage.get_key_focus() == this.actor)
this.actor.add_style_pseudo_class('focus');
else
this.actor.remove_style_pseudo_class('focus');
},
_updateLoggedIn: function() {
if (this.user.is_logged_in())
this.actor.add_style_pseudo_class('logged-in');
else
this.actor.remove_style_pseudo_class('logged-in');
},
_onClicked: function() {
this.emit('activate');
},
showTimedLoginIndicator: function(time) {
let hold = new Batch.Hold();
this.hideTimedLoginIndicator();
Tweener.addTween(this._timedLoginIndicator,
{ scale_x: 1.,
time: time,
transition: 'linear',
onComplete: function() {
hold.release();
},
onCompleteScope: this
});
return hold;
},
hideTimedLoginIndicator: function() {
Tweener.removeTweens(this._timedLoginIndicator);
this._timedLoginIndicator.scale_x = 0.;
}
});
Signals.addSignalMethods(UserListItem.prototype);
const UserList = new Lang.Class({
Name: 'UserList',
_init: function() {
this.actor = new St.ScrollView({ style_class: 'login-dialog-user-list-view'});
this.actor.set_policy(Gtk.PolicyType.NEVER,
Gtk.PolicyType.AUTOMATIC);
this._box = new St.BoxLayout({ vertical: true,
style_class: 'login-dialog-user-list',
pseudo_class: 'expanded' });
this.actor.add_actor(this._box);
this._items = {};
this.actor.connect('key-focus-in', Lang.bind(this, this._moveFocusToItems));
},
_moveFocusToItems: function() {
let hasItems = Object.keys(this._items).length > 0;
if (!hasItems)
return;
if (global.stage.get_key_focus() != this.actor)
return;
let focusSet = this.actor.navigate_focus(null, Gtk.DirectionType.TAB_FORWARD, false);
if (!focusSet) {
Meta.later_add(Meta.LaterType.BEFORE_REDRAW, Lang.bind(this, function() {
this._moveFocusToItems();
return false;
}));
}
},
_onItemActivated: function(activatedItem) {
this.emit('activate', activatedItem);
},
updateStyle: function(isExpanded) {
let tasks = [];
if (isExpanded)
this._box.add_style_pseudo_class('expanded');
else
this._box.remove_style_pseudo_class('expanded');
for (let userName in this._items) {
let item = this._items[userName];
item.actor.sync_hover();
item.syncStyleClasses();
}
},
scrollToItem: function(item) {
let box = item.actor.get_allocation_box();
let adjustment = this.actor.get_vscroll_bar().get_adjustment();
let value = (box.y1 + adjustment.step_increment / 2.0) - (adjustment.page_size / 2.0);
Tweener.removeTweens(adjustment);
Tweener.addTween (adjustment,
{ value: value,
time: _SCROLL_ANIMATION_TIME,
transition: 'easeOutQuad' });
},
jumpToItem: function(item) {
let box = item.actor.get_allocation_box();
let adjustment = this.actor.get_vscroll_bar().get_adjustment();
let value = (box.y1 + adjustment.step_increment / 2.0) - (adjustment.page_size / 2.0);
adjustment.set_value(value);
},
getItemFromUserName: function(userName) {
let item = this._items[userName];
if (!item)
return null;
return item;
},
addUser: function(user) {
if (!user.is_loaded)
return;
if (user.is_system_account())
return;
if (user.locked)
return;
let userName = user.get_user_name();
if (!userName)
return;
this.removeUser(user);
let item = new UserListItem(user);
this._box.add(item.actor, { x_fill: true });
this._items[userName] = item;
item.connect('activate',
Lang.bind(this, this._onItemActivated));
// Try to keep the focused item front-and-center
item.actor.connect('key-focus-in',
Lang.bind(this,
function() {
this.scrollToItem(item);
}));
this._moveFocusToItems();
this.emit('item-added', item);
},
removeUser: function(user) {
if (!user.is_loaded)
return;
let userName = user.get_user_name();
if (!userName)
return;
let item = this._items[userName];
if (!item)
return;
item.actor.destroy();
delete this._items[userName];
}
});
Signals.addSignalMethods(UserList.prototype);

View File

@@ -6,13 +6,11 @@ const GLib = imports.gi.GLib;
const Lang = imports.lang;
const Mainloop = imports.mainloop;
const Signals = imports.signals;
const St = imports.gi.St;
const Batch = imports.gdm.batch;
const Fprint = imports.gdm.fingerprint;
const Batch = imports.misc.batch;
const Fprint = imports.ui.auth.fingerprint;
const Main = imports.ui.main;
const Params = imports.misc.params;
const ShellEntry = imports.ui.shellEntry;
const Tweener = imports.ui.tweener;
const PASSWORD_SERVICE_NAME = 'gdm-password';
@@ -121,7 +119,6 @@ const ShellUserVerifier = new Lang.Class({
this._messageQueue = [];
this._messageQueueTimeoutId = 0;
this.hasPendingMessages = false;
this.reauthenticating = false;
this._failCounter = 0;
},
@@ -130,7 +127,6 @@ const ShellUserVerifier = new Lang.Class({
this._cancellable = new Gio.Cancellable();
this._hold = hold;
this._userName = userName;
this.reauthenticating = false;
this._checkForFingerprintReader();
@@ -167,14 +163,14 @@ const ShellUserVerifier = new Lang.Class({
},
answerQuery: function(serviceName, answer) {
if (!this.hasPendingMessages) {
if (!this._userVerifier.hasPendingMessages) {
this._userVerifier.call_answer_query(serviceName, answer, this._cancellable, null);
} else {
let signalId = this.connect('no-more-messages',
Lang.bind(this, function() {
this.disconnect(signalId);
this._userVerifier.call_answer_query(serviceName, answer, this._cancellable, null);
}));
let signalId = this._userVerifier.connect('no-more-messages',
Lang.bind(this, function() {
this._userVerifier.disconnect(signalId);
this._userVerifier.call_answer_query(serviceName, answer, this._cancellable, null);
}));
}
},
@@ -269,7 +265,6 @@ const ShellUserVerifier = new Lang.Class({
return;
}
this.reauthenticating = true;
this._connectSignals();
this._beginVerification();
this._hold.release();
@@ -427,24 +422,24 @@ const ShellUserVerifier = new Lang.Class({
this._failCounter < this._settings.get_int(ALLOWED_FAILURES_KEY);
if (canRetry) {
if (!this.hasPendingMessages) {
if (!this._userVerifier.hasPendingMessages) {
this._retry();
} else {
let signalId = this.connect('no-more-messages',
Lang.bind(this, function() {
this.disconnect(signalId);
this._retry();
}));
let signalId = this._userVerifier.connect('no-more-messages',
Lang.bind(this, function() {
this._userVerifier.disconnect(signalId);
this._retry();
}));
}
} else {
if (!this.hasPendingMessages) {
if (!this._userVerifier.hasPendingMessages) {
this._cancelAndReset();
} else {
let signalId = this.connect('no-more-messages',
Lang.bind(this, function() {
this.disconnect(signalId);
this._cancelAndReset();
}));
let signalId = this._userVerifier.connect('no-more-messages',
Lang.bind(this, function() {
this._userVerifier.disconnect(signalId);
this._cancelAndReset();
}));
}
}

View File

@@ -142,40 +142,33 @@ const BackgroundCache = new Lang.Class({
cancellable: null,
onFinished: null });
let fileLoad = { filename: params.filename,
style: params.style,
shouldCopy: false,
monitorIndex: params.monitorIndex,
effects: params.effects,
onFinished: params.onFinished,
cancellable: new Gio.Cancellable(), };
this._pendingFileLoads.push(fileLoad);
if (params.cancellable) {
params.cancellable.connect(Lang.bind(this, function(c) {
fileLoad.cancellable.cancel();
}));
for (let i = 0; i < this._pendingFileLoads.length; i++) {
if (this._pendingFileLoads[i].filename == params.filename &&
this._pendingFileLoads[i].style == params.style) {
this._pendingFileLoads[i].callers.push({ shouldCopy: true,
monitorIndex: params.monitorIndex,
effects: params.effects,
onFinished: params.onFinished });
return;
}
}
this._pendingFileLoads.push({ filename: params.filename,
style: params.style,
callers: [{ shouldCopy: false,
monitorIndex: params.monitorIndex,
effects: params.effects,
onFinished: params.onFinished }] });
let content = new Meta.Background({ meta_screen: global.screen,
monitor: params.monitorIndex,
effects: params.effects });
content.load_file_async(params.filename,
params.style,
fileLoad.cancellable,
params.cancellable,
Lang.bind(this,
function(object, result) {
if (fileLoad.cancellable.is_cancelled()) {
if (params.cancellable && params.cancellable.is_cancelled()) {
if (params.onFinished)
params.onFinished(null);
this._removePendingFileLoad(fileLoad);
return;
}
return;
}
try {
content.load_file_finish(result);
@@ -185,25 +178,22 @@ const BackgroundCache = new Lang.Class({
content = null;
}
let needsCopy = false;
for (let i = 0; i < this._pendingFileLoads.length; i++) {
let pendingLoad = this._pendingFileLoads[i];
if (pendingLoad.filename != params.filename ||
pendingLoad.style != params.style)
continue;
if (pendingLoad.cancellable.is_cancelled())
continue;
for (let j = 0; j < pendingLoad.callers.length; j++) {
if (pendingLoad.callers[j].onFinished) {
if (content && pendingLoad.callers[j].shouldCopy) {
content = object.copy(pendingLoad.callers[j].monitorIndex,
pendingLoad.callers[j].effects);
pendingLoad.cancellable.cancel();
if (pendingLoad.onFinished) {
if (content && needsCopy) {
content = object.copy(pendingLoad.monitorIndex,
pendingLoad.effects);
}
pendingLoad.callers[j].onFinished(content);
}
needsCopy = true;
pendingLoad.onFinished(content);
}
this._pendingFileLoads.splice(i, 1);
@@ -211,15 +201,6 @@ const BackgroundCache = new Lang.Class({
}));
},
_removePendingFileLoad: function(fileLoad) {
for (let i = 0; i < this._pendingFileLoads.length; i++) {
if (this._pendingFileLoads[i].cancellable == fileLoad.cancellable) {
this._pendingFileLoads.splice(i, 1);
break;
}
}
},
getImageContent: function(params) {
params = Params.parse(params, { monitorIndex: 0,
style: null,
@@ -590,16 +571,7 @@ const Background = new Lang.Class({
}
let uri = this._settings.get_string(PICTURE_URI_KEY);
let filename;
if (GLib.uri_parse_scheme(uri) != null)
filename = Gio.File.new_for_uri(uri).get_path();
else
filename = uri;
if (!filename) {
this._setLoaded();
return;
}
let filename = Gio.File.new_for_uri(uri).get_path();
this._loadFile(filename);
},

View File

@@ -589,12 +589,12 @@ const BoxPointer = new Lang.Class({
return St.Side.TOP;
break;
case St.Side.LEFT:
if (sourceAllocation.x2 + boxWidth > monitor.x + monitor.width &&
if (sourceAllocation.y2 + boxWidth > monitor.x + monitor.width &&
boxWidth < sourceAllocation.x1 - monitor.x)
return St.Side.RIGHT;
break;
case St.Side.RIGHT:
if (sourceAllocation.x1 - boxWidth < monitor.x &&
if (sourceAllocation.y1 - boxWidth < monitor.x &&
boxWidth < monitor.x + monitor.width - sourceAllocation.x2)
return St.Side.LEFT;
break;

View File

@@ -675,7 +675,7 @@ const EventsList = new Lang.Class({
Name: 'EventsList',
_init: function() {
this.actor = new St.Table({ style_class: 'events-table' });
this.actor = new St.BoxLayout({ vertical: true, style_class: 'events-header-vbox'});
this._date = new Date();
this._desktopSettings = new Gio.Settings({ schema: 'org.gnome.desktop.interface' });
this._desktopSettings.connect('changed', Lang.bind(this, this._update));
@@ -687,72 +687,55 @@ const EventsList = new Lang.Class({
this._eventSource.connect('changed', Lang.bind(this, this._update));
},
_addEvent: function(event, index, includeDayName) {
let dayString;
if (includeDayName)
dayString = _getEventDayAbbreviation(event.date.getDay());
else
dayString = '';
let dayLabel = new St.Label({ style_class: 'events-day-dayname',
text: dayString });
dayLabel.clutter_text.line_wrap = false;
dayLabel.clutter_text.ellipsize = false;
this.actor.add(dayLabel, { row: index, col: 0,
x_expand: false, x_align: St.Align.END,
y_fill: false, y_align: St.Align.START });
let clockFormat = this._desktopSettings.get_string(CLOCK_FORMAT_KEY);
let timeString = _formatEventTime(event, clockFormat);
let timeLabel = new St.Label({ style_class: 'events-day-time',
text: timeString });
timeLabel.clutter_text.line_wrap = false;
timeLabel.clutter_text.ellipsize = false;
this.actor.add(timeLabel, { row: index, col: 1,
x_expand: false, x_align: St.Align.MIDDLE,
y_fill: false, y_align: St.Align.START });
let titleLabel = new St.Label({ style_class: 'events-day-task',
text: event.summary });
titleLabel.clutter_text.line_wrap = true;
titleLabel.clutter_text.ellipsize = false;
this.actor.add(titleLabel, { row: index, col: 2,
x_expand: true, x_align: St.Align.START,
y_fill: false, y_align: St.Align.START });
_addEvent: function(dayNameBox, timeBox, eventTitleBox, includeDayName, day, time, desc) {
if (includeDayName) {
dayNameBox.add(new St.Label( { style_class: 'events-day-dayname',
text: day } ),
{ x_fill: true } );
}
timeBox.add(new St.Label( { style_class: 'events-day-time',
text: time} ),
{ x_fill: true } );
eventTitleBox.add(new St.Label( { style_class: 'events-day-task',
text: desc} ));
},
_addPeriod: function(header, index, begin, end, includeDayName, showNothingScheduled) {
_addPeriod: function(header, begin, end, includeDayName, showNothingScheduled) {
let events = this._eventSource.getEvents(begin, end);
if (events.length == 0 && !showNothingScheduled)
return index;
let clockFormat = this._desktopSettings.get_string(CLOCK_FORMAT_KEY);;
this.actor.add(new St.Label({ style_class: 'events-day-header', text: header }),
{ row: index, col: 0, col_span: 3,
// In theory, x_expand should be true here, but x_expand
// is a property of the column for StTable, ie all day cells
// get it too
x_expand: false, x_align: St.Align.START,
y_fill: false, y_align: St.Align.START });
index++;
if (events.length == 0 && !showNothingScheduled)
return;
let vbox = new St.BoxLayout( {vertical: true} );
this.actor.add(vbox);
vbox.add(new St.Label({ style_class: 'events-day-header', text: header }));
let box = new St.BoxLayout({style_class: 'events-header-hbox'});
let dayNameBox = new St.BoxLayout({ vertical: true, style_class: 'events-day-name-box' });
let timeBox = new St.BoxLayout({ vertical: true, style_class: 'events-time-box' });
let eventTitleBox = new St.BoxLayout({ vertical: true, style_class: 'events-event-box' });
box.add(dayNameBox, {x_fill: false});
box.add(timeBox, {x_fill: false});
box.add(eventTitleBox, {expand: true});
vbox.add(box);
for (let n = 0; n < events.length; n++) {
this._addEvent(events[n], index, includeDayName);
index++;
let event = events[n];
let dayString = _getEventDayAbbreviation(event.date.getDay());
let timeString = _formatEventTime(event, clockFormat);
let summaryString = event.summary;
this._addEvent(dayNameBox, timeBox, eventTitleBox, includeDayName, dayString, timeString, summaryString);
}
if (events.length == 0 && showNothingScheduled) {
let now = new Date();
/* Translators: Text to show if there are no events */
let nothingEvent = new CalendarEvent(now, now, _("Nothing Scheduled"), true);
this._addEvent(nothingEvent, index, false);
index++;
let timeString = _formatEventTime(nothingEvent, clockFormat);
this._addEvent(dayNameBox, timeBox, eventTitleBox, false, "", timeString, nothingEvent.summary);
}
return index;
},
_showOtherDay: function(day) {
@@ -769,21 +752,20 @@ const EventsList = new Lang.Class({
else
/* Translators: Shown on calendar heading when selected day occurs on different year */
dayString = day.toLocaleFormat(C_("calendar heading", "%A, %B %d, %Y"));
this._addPeriod(dayString, 0, dayBegin, dayEnd, false, true);
this._addPeriod(dayString, dayBegin, dayEnd, false, true);
},
_showToday: function() {
this.actor.destroy_all_children();
let index = 0;
let now = new Date();
let dayBegin = _getBeginningOfDay(now);
let dayEnd = _getEndOfDay(now);
index = this._addPeriod(_("Today"), index, dayBegin, dayEnd, false, true);
this._addPeriod(_("Today"), dayBegin, dayEnd, false, true);
let tomorrowBegin = new Date(dayBegin.getTime() + 86400 * 1000);
let tomorrowEnd = new Date(dayEnd.getTime() + 86400 * 1000);
index = this._addPeriod(_("Tomorrow"), index, tomorrowBegin, tomorrowEnd, false, true);
this._addPeriod(_("Tomorrow"), tomorrowBegin, tomorrowEnd, false, true);
let dayInWeek = (dayEnd.getDay() - this._weekStart + 7) % 7;
@@ -794,7 +776,7 @@ const EventsList = new Lang.Class({
*/
let thisWeekBegin = new Date(dayBegin.getTime() + 2 * 86400 * 1000);
let thisWeekEnd = new Date(dayEnd.getTime() + (6 - dayInWeek) * 86400 * 1000);
index = this._addPeriod(_("This week"), index, thisWeekBegin, thisWeekEnd, true, false);
this._addPeriod(_("This week"), thisWeekBegin, thisWeekEnd, true, false);
} else {
/* otherwise it's one of the two last days of the week ... show
* "Next week" and include events up until and including *next*
@@ -802,7 +784,7 @@ const EventsList = new Lang.Class({
*/
let nextWeekBegin = new Date(dayBegin.getTime() + 2 * 86400 * 1000);
let nextWeekEnd = new Date(dayEnd.getTime() + (13 - dayInWeek) * 86400 * 1000);
index = this._addPeriod(_("Next week"), index, nextWeekBegin, nextWeekEnd, true, false);
this._addPeriod(_("Next week"), nextWeekBegin, nextWeekEnd, true, false);
}
},

View File

@@ -31,7 +31,7 @@ function shouldAutorunMount(mount, forTransient) {
if (!volume || (!volume.allowAutorun && forTransient))
return false;
if (root.is_native() && isMountRootHidden(root))
if (!root.is_native() || isMountRootHidden(root))
return false;
return true;

View File

@@ -16,7 +16,7 @@ const PolkitAgent = imports.gi.PolkitAgent;
const Components = imports.ui.components;
const ModalDialog = imports.ui.modalDialog;
const ShellEntry = imports.ui.shellEntry;
const UserWidget = imports.ui.userWidget;
const UserAvatar = imports.ui.userAvatar;
const DIALOG_ICON_SIZE = 48;
@@ -100,9 +100,9 @@ const AuthenticationDialog = new Lang.Class({
let userBox = new St.BoxLayout({ style_class: 'polkit-dialog-user-layout',
vertical: false });
messageBox.add(userBox);
this._userAvatar = new UserWidget.Avatar(this._user,
{ iconSize: DIALOG_ICON_SIZE,
styleClass: 'polkit-dialog-user-icon' });
this._userAvatar = new UserAvatar.UserAvatar(this._user,
{ iconSize: DIALOG_ICON_SIZE,
styleClass: 'polkit-dialog-user-icon' });
this._userAvatar.actor.hide();
userBox.add(this._userAvatar.actor,
{ x_fill: true,

View File

@@ -18,7 +18,7 @@ const Params = imports.misc.params;
const PopupMenu = imports.ui.popupMenu;
// See Notification.appendMessage
const SCROLLBACK_IMMEDIATE_TIME = 3 * 60; // 3 minutes
const SCROLLBACK_IMMEDIATE_TIME = 60; // 1 minute
const SCROLLBACK_RECENT_TIME = 15 * 60; // 15 minutes
const SCROLLBACK_RECENT_LENGTH = 20;
const SCROLLBACK_IDLE_LENGTH = 5;
@@ -967,8 +967,7 @@ const ChatNotification = new Lang.Class({
let timeLabel = this._append({ body: this._formatTimestamp(lastMessageDate),
group: 'meta',
styles: ['chat-meta-message'],
childProps: { expand: true, x_fill: false,
x_align: St.Align.END },
childProps: { expand: true, x_fill: false },
noTimestamp: true,
timestamp: lastMessageTime });

View File

@@ -58,10 +58,14 @@ const CtrlAltTabManager = new Lang.Class({
},
focusGroup: function(item, timestamp) {
if (item.focusCallback)
if (item.focusCallback) {
item.focusCallback(timestamp);
else
} else {
if (global.stage_input_mode == Shell.StageInputMode.NORMAL)
global.set_stage_input_mode(Shell.StageInputMode.FOCUSED);
item.root.navigate_focus(null, Gtk.DirectionType.TAB_FORWARD, false);
}
},
// Sort the items into a consistent order; panel first, tray last,
@@ -132,6 +136,8 @@ const CtrlAltTabManager = new Lang.Class({
},
_focusWindows: function(timestamp) {
global.set_stage_input_mode(Shell.StageInputMode.NORMAL);
global.stage.key_focus = null;
global.screen.focus_default_window(timestamp);
}
});

View File

@@ -287,7 +287,13 @@ const ShowAppsIcon = new Lang.Class({
},
handleDragOver: function(source, actor, x, y, time) {
if (!this._canRemoveApp(getAppFromSource(source)))
let app = getAppFromSource(source);
if (app == null)
return DND.DragMotionResult.NO_DROP;
let id = app.get_id();
let isFavorite = AppFavorites.getAppFavorites().isFavorite(id);
if (!isFavorite)
return DND.DragMotionResult.NO_DROP;
return DND.DragMotionResult.MOVE_DROP;
@@ -295,7 +301,7 @@ const ShowAppsIcon = new Lang.Class({
acceptDrop: function(source, actor, x, y, time) {
let app = getAppFromSource(source);
if (!this._canRemoveApp(app))
if (app == null)
return false;
let id = app.get_id();
@@ -320,16 +326,6 @@ const DragPlaceholderItem = new Lang.Class({
}
});
const EmptyDropTargetItem = new Lang.Class({
Name: 'EmptyDropTargetItem',
Extends: DashItemContainer,
_init: function() {
this.parent();
this.setChild(new St.Bin({ style_class: 'empty-dash-drop-target' }));
}
});
const DashActor = new Lang.Class({
Name: 'DashActor',
Extends: St.Widget,
@@ -445,12 +441,6 @@ const Dash = new Lang.Class({
dragMotion: Lang.bind(this, this._onDragMotion)
};
DND.addDragMonitor(this._dragMonitor);
if (this._box.get_n_children() == 0) {
this._emptyDropTarget = new EmptyDropTargetItem();
this._box.insert_child_at_index(this._emptyDropTarget, 0);
this._emptyDropTarget.show(true);
}
},
_onDragCancelled: function() {
@@ -467,7 +457,6 @@ const Dash = new Lang.Class({
_endDrag: function() {
this._clearDragPlaceholder();
this._clearEmptyDropTarget();
this._showAppsIcon.setDragApp(null);
DND.removeDragMonitor(this._dragMonitor);
},
@@ -808,21 +797,9 @@ const Dash = new Lang.Class({
_clearDragPlaceholder: function() {
if (this._dragPlaceholder) {
this._animatingPlaceholdersCount++;
this._dragPlaceholder.animateOutAndDestroy();
this._dragPlaceholder.connect('destroy',
Lang.bind(this, function() {
this._animatingPlaceholdersCount--;
}));
this._dragPlaceholder = null;
}
this._dragPlaceholderPos = -1;
},
_clearEmptyDropTarget: function() {
if (this._emptyDropTarget) {
this._emptyDropTarget.animateOutAndDestroy();
this._emptyDropTarget = null;
this._dragPlaceholderPos = -1;
}
},
@@ -850,18 +827,23 @@ const Dash = new Lang.Class({
numChildren--;
}
let pos;
if (!this._emptyDropTarget)
pos = Math.floor(y * numChildren / boxHeight);
else
pos = 0; // always insert at the top when dash is empty
let pos = Math.floor(y * numChildren / boxHeight);
if (pos != this._dragPlaceholderPos && pos <= numFavorites && this._animatingPlaceholdersCount == 0) {
this._dragPlaceholderPos = pos;
// Don't allow positioning before or after self
if (favPos != -1 && (pos == favPos || pos == favPos + 1)) {
this._clearDragPlaceholder();
if (this._dragPlaceholder) {
this._dragPlaceholder.animateOutAndDestroy();
this._animatingPlaceholdersCount++;
this._dragPlaceholder.connect('destroy',
Lang.bind(this, function() {
this._animatingPlaceholdersCount--;
}));
}
this._dragPlaceholder = null;
return DND.DragMotionResult.CONTINUE;
}
@@ -886,9 +868,9 @@ const Dash = new Lang.Class({
// Remove the drag placeholder if we are not in the
// "favorites zone"
if (pos > numFavorites)
if (pos > numFavorites && this._dragPlaceholder) {
this._clearDragPlaceholder();
}
if (!this._dragPlaceholder)
return DND.DragMotionResult.NO_DROP;

View File

@@ -80,7 +80,8 @@ const DateMenuButton = new Lang.Class({
vbox.add(this._calendar.actor);
let separator = new PopupMenu.PopupSeparatorMenuItem();
vbox.add(separator.actor, { y_align: St.Align.END, expand: true, y_fill: false });
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));
@@ -106,7 +107,12 @@ const DateMenuButton = new Lang.Class({
hbox.add(this._separator);
// Fill up the second column
hbox.add(this._eventList.actor, { expand: true, y_fill: false, y_align: St.Align.START });
vbox = new St.BoxLayout({ name: 'calendarEventsArea',
vertical: true });
hbox.add(vbox, { expand: true });
// Event list
vbox.add(this._eventList.actor, { expand: true });
// Whenever the menu is opened, select today
this.menu.connect('open-state-changed', Lang.bind(this, function(menu, isOpen) {
@@ -153,14 +159,15 @@ const DateMenuButton = new Lang.Class({
this._openClocksItem.actor.visible = visible &&
(this._getClockApp() != null);
this._separator.visible = visible;
this._eventList.actor.visible = visible;
if (visible) {
let alignment = 0.25;
if (Clutter.get_default_text_direction() == Clutter.TextDirection.RTL)
alignment = 1.0 - alignment;
this.menu._arrowAlignment = alignment;
let alignment = 0.25;
if (Clutter.get_default_text_direction() == Clutter.TextDirection.RTL)
alignment = 1.0 - alignment;
this.menu._arrowAlignment = alignment;
this._eventList.actor.get_parent().show();
} else {
this.menu._arrowAlignment = 0.5;
this.menu._arrowAlignment = 0.5;
this._eventList.actor.get_parent().hide();
}
},

View File

@@ -1,7 +1,6 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
const Clutter = imports.gi.Clutter;
const GLib = imports.gi.GLib;
const Gtk = imports.gi.Gtk;
const St = imports.gi.St;
const Lang = imports.lang;
@@ -148,16 +147,16 @@ const _Draggable = new Lang.Class({
_grabEvents: function() {
if (!this._eventsGrabbed) {
this._eventsGrabbed = Main.pushModal(_getEventHandlerActor());
if (this._eventsGrabbed)
Clutter.grab_pointer(_getEventHandlerActor());
Clutter.grab_pointer(_getEventHandlerActor());
Clutter.grab_keyboard(_getEventHandlerActor());
this._eventsGrabbed = true;
}
},
_ungrabEvents: function() {
if (this._eventsGrabbed) {
Clutter.ungrab_pointer();
Main.popModal(_getEventHandlerActor());
Clutter.ungrab_keyboard();
this._eventsGrabbed = false;
}
},
@@ -359,65 +358,60 @@ const _Draggable = new Lang.Class({
return true;
},
_updateDragHover : function () {
let target = this._dragActor.get_stage().get_actor_at_pos(Clutter.PickMode.ALL,
this._dragX, this._dragY);
let dragEvent = {
x: this._dragX,
y: this._dragY,
dragActor: this._dragActor,
source: this.actor._delegate,
targetActor: target
};
for (let i = 0; i < dragMonitors.length; i++) {
let motionFunc = dragMonitors[i].dragMotion;
if (motionFunc) {
let result = motionFunc(dragEvent);
if (result != DragMotionResult.CONTINUE) {
global.set_cursor(DRAG_CURSOR_MAP[result]);
return false;
}
}
}
while (target) {
if (target._delegate && target._delegate.handleDragOver) {
let [r, targX, targY] = target.transform_stage_point(this._dragX, this._dragY);
// We currently loop through all parents on drag-over even if one of the children has handled it.
// We can check the return value of the function and break the loop if it's true if we don't want
// to continue checking the parents.
let result = target._delegate.handleDragOver(this.actor._delegate,
this._dragActor,
targX,
targY,
0);
if (result != DragMotionResult.CONTINUE) {
global.set_cursor(DRAG_CURSOR_MAP[result]);
return false;
}
}
target = target.get_parent();
}
global.set_cursor(Shell.Cursor.DND_IN_DRAG);
return false;
},
_queueUpdateDragHover: function() {
if (this._updateHoverId)
GLib.source_remove(this._updateHoverId);
this._updateHoverId = GLib.idle_add(GLib.PRIORITY_DEFAULT,
Lang.bind(this, this._updateDragHover));
},
_updateDragPosition : function (event) {
let [stageX, stageY] = event.get_coords();
this._dragX = stageX;
this._dragY = stageY;
this._dragActor.set_position(stageX + this._dragOffsetX,
stageY + this._dragOffsetY);
this._queueUpdateDragHover();
// If we are dragging, update the position
if (this._dragActor) {
this._dragActor.set_position(stageX + this._dragOffsetX,
stageY + this._dragOffsetY);
let target = this._dragActor.get_stage().get_actor_at_pos(Clutter.PickMode.ALL,
stageX, stageY);
// We call observers only once per motion with the innermost
// target actor. If necessary, the observer can walk the
// parent itself.
let dragEvent = {
x: stageX,
y: stageY,
dragActor: this._dragActor,
source: this.actor._delegate,
targetActor: target
};
for (let i = 0; i < dragMonitors.length; i++) {
let motionFunc = dragMonitors[i].dragMotion;
if (motionFunc) {
let result = motionFunc(dragEvent);
if (result != DragMotionResult.CONTINUE) {
global.set_cursor(DRAG_CURSOR_MAP[result]);
return true;
}
}
}
while (target) {
if (target._delegate && target._delegate.handleDragOver) {
let [r, targX, targY] = target.transform_stage_point(stageX, stageY);
// We currently loop through all parents on drag-over even if one of the children has handled it.
// We can check the return value of the function and break the loop if it's true if we don't want
// to continue checking the parents.
let result = target._delegate.handleDragOver(this.actor._delegate,
this._dragActor,
targX,
targY,
event.get_time());
if (result != DragMotionResult.CONTINUE) {
global.set_cursor(DRAG_CURSOR_MAP[result]);
return true;
}
}
target = target.get_parent();
}
global.set_cursor(Shell.Cursor.DND_IN_DRAG);
}
return true;
},
@@ -517,11 +511,6 @@ const _Draggable = new Lang.Class({
},
_cancelDrag: function(eventTime) {
if (this._updateHoverId) {
GLib.source_remove(this._updateHoverId);
this._updateHoverId = 0;
}
this.emit('drag-cancelled', eventTime);
this._dragInProgress = false;
let [snapBackX, snapBackY, snapBackScale] = this._getRestoreLocation();

View File

@@ -35,7 +35,7 @@ const GnomeSession = imports.misc.gnomeSession;
const Main = imports.ui.main;
const ModalDialog = imports.ui.modalDialog;
const Tweener = imports.ui.tweener;
const UserWidget = imports.ui.userWidget;
const UserAvatar = imports.ui.userAvatar;
let _endSessionDialog = null;
@@ -360,9 +360,9 @@ const EndSessionDialog = new Lang.Class({
icon_size: _DIALOG_ICON_SIZE,
style_class: dialogContent.iconStyleClass });
} else {
let avatarWidget = new UserWidget.Avatar(this._user,
{ iconSize: _DIALOG_ICON_SIZE,
styleClass: dialogContent.iconStyleClass });
let avatarWidget = new UserAvatar.UserAvatar(this._user,
{ iconSize: _DIALOG_ICON_SIZE,
styleClass: dialogContent.iconStyleClass });
this._iconBin.child = avatarWidget.actor;
avatarWidget.update();
}
@@ -420,7 +420,6 @@ const EndSessionDialog = new Lang.Class({
_startTimer: function() {
let startTime = GLib.get_monotonic_time();
this._secondsLeft = this._totalSecondsToStayOpen;
this._updateDescription();
this._timerId = Mainloop.timeout_add_seconds(1, Lang.bind(this,
function() {

View File

@@ -10,7 +10,6 @@ const Clutter = imports.gi.Clutter;;
const Gettext = imports.gettext;
const GLib = imports.gi.GLib;
const Gtk = imports.gi.Gtk;
const Lang = imports.lang;
const Shell = imports.gi.Shell;
const St = imports.gi.St;
@@ -40,22 +39,6 @@ function _patchContainerClass(containerClass) {
};
}
function _patchLayoutClass(layoutClass, styleProps) {
if (styleProps)
layoutClass.prototype.hookup_style = function(container) {
container.connect('style-changed', Lang.bind(this, function() {
let node = container.get_theme_node();
for (let prop in styleProps)
this[prop] = node.get_length(styleProps[prop]);
}));
};
layoutClass.prototype.child_set = function(actor, props) {
let meta = this.get_child_meta(actor.get_parent(), actor);
for (let prop in props)
meta[prop] = props[prop];
};
}
function _makeLoggingFunc(func) {
return function() {
return func([].join.call(arguments, ', '));
@@ -77,12 +60,6 @@ function init() {
_patchContainerClass(St.BoxLayout);
_patchContainerClass(St.Table);
_patchLayoutClass(Clutter.TableLayout, { row_spacing: 'spacing-rows',
column_spacing: 'spacing-columns' });
_patchLayoutClass(Clutter.GridLayout, { row_spacing: 'spacing-rows',
column_spacing: 'spacing-columns' });
_patchLayoutClass(Clutter.BoxLayout, { spacing: 'spacing' });
Clutter.Actor.prototype.toString = function() {
return St.describe_actor(this);
};

View File

@@ -32,9 +32,13 @@ const GrabHelper = new Lang.Class({
this._actors = [];
this._capturedEventId = 0;
this._keyFocusNotifyId = 0;
this._focusWindowChangedId = 0;
this._ignoreRelease = false;
this._isUngrabbingCount = 0;
this._modalCount = 0;
this._grabFocusCount = 0;
},
// addActor:
@@ -114,36 +118,38 @@ const GrabHelper = new Lang.Class({
// grab:
// @params: A bunch of parameters, see below
//
// The general effect of a "grab" is to ensure that the passed in actor
// and all actors inside the grab get exclusive control of the mouse and
// keyboard, with the grab automatically being dropped if the user tries
// to dismiss it. The actor is passed in through @params.actor.
// Grabs the mouse and keyboard, according to the GrabHelper's
// parameters. If @newFocus is not %null, then the keyboard focus
// is moved to the first #StWidget:can-focus widget inside it.
//
// grab() can be called multiple times, with the scope of the grab being
// changed to a different actor every time. A nested grab does not have
// to have its grabbed actor inside the parent grab actors.
// The grab will automatically be dropped if:
// - The user clicks outside the grabbed actors
// - The user types Escape
// - The keyboard focus is moved outside the grabbed actors
// - A window is focused
//
// Grabs can be automatically dropped if the user tries to dismiss it
// in one of two ways: the user clicking outside the currently grabbed
// actor, or the user typing the Escape key.
// If @params.actor is not null, then it will be focused as the
// new actor. If you attempt to grab an already focused actor, the
// request to be focused will be ignored. The actor will not be
// added to the grab stack, so do not call a paired ungrab().
//
// If the user clicks outside the grabbed actors, and the clicked on
// actor is part of a previous grab in the stack, grabs will be popped
// until that grab is active. However, the click event will not be
// replayed to the actor.
// If @params contains { modal: true }, then grab() will push a modal
// on the owner of the GrabHelper. As long as there is at least one
// { modal: true } actor on the grab stack, the grab will be kept.
// When the last { modal: true } actor is ungrabbed, then the modal
// will be dropped. A modal grab can fail if there is already a grab
// in effect from aother application; in this case the function returns
// false and nothing happens. Non-modal grabs can never fail.
//
// If the user types the Escape key, one grab from the grab stack will
// be popped.
//
// When a grab is popped by user interacting as described above, if you
// pass a callback as @params.onUngrab, it will be called with %true.
//
// If @params.focus is not null, we'll set the key focus directly
// to that actor instead of navigating in @params.actor. This is for
// use cases like menus, where we want to grab the menu actor, but keep
// focus on the clicked on menu item.
// If @params contains { grabFocus: true }, then if you call grab()
// while the shell is outside the overview, it will set the stage
// input mode to %Shell.StageInputMode.FOCUSED, and ungrab() will
// revert it back, and re-focus the previously-focused window (if
// another window hasn't been explicitly focused before then).
grab: function(params) {
params = Params.parse(params, { actor: null,
modal: false,
grabFocus: false,
focus: null,
onUngrab: null });
@@ -156,18 +162,24 @@ const GrabHelper = new Lang.Class({
params.savedFocus = focus;
if (!this._takeModalGrab())
if (params.modal && !this._takeModalGrab())
return false;
if (params.grabFocus && !this._takeFocusGrab(hadFocus))
return false;
this._grabStack.push(params);
if (params.focus) {
params.focus.grab_key_focus();
} else if (newFocus && hadFocus) {
} else if (newFocus && (hadFocus || params.grabFocus)) {
if (!newFocus.navigate_focus(null, Gtk.DirectionType.TAB_FORWARD, false))
newFocus.grab_key_focus();
}
if ((params.grabFocus || params.modal) && !this._capturedEventId)
this._capturedEventId = global.stage.connect('captured-event', Lang.bind(this, this._onCapturedEvent));
return true;
},
@@ -176,8 +188,6 @@ const GrabHelper = new Lang.Class({
if (firstGrab) {
if (!Main.pushModal(this._owner, this._modalParams))
return false;
this._capturedEventId = global.stage.connect('captured-event', Lang.bind(this, this._onCapturedEvent));
}
this._modalCount++;
@@ -189,15 +199,56 @@ const GrabHelper = new Lang.Class({
if (this._modalCount > 0)
return;
global.stage.disconnect(this._capturedEventId);
this._capturedEventId = 0;
this._ignoreRelease = false;
Main.popModal(this._owner);
global.sync_pointer();
},
_takeFocusGrab: function(hadFocus) {
let firstGrab = (this._grabFocusCount == 0);
if (firstGrab) {
let metaDisplay = global.screen.get_display();
this._grabbedFromKeynav = hadFocus;
this._preGrabInputMode = global.stage_input_mode;
if (this._preGrabInputMode == Shell.StageInputMode.NORMAL)
global.set_stage_input_mode(Shell.StageInputMode.FOCUSED);
this._keyFocusNotifyId = global.stage.connect('notify::key-focus', Lang.bind(this, this._onKeyFocusChanged));
this._focusWindowChangedId = metaDisplay.connect('notify::focus-window', Lang.bind(this, this._focusWindowChanged));
}
this._grabFocusCount++;
return true;
},
_releaseFocusGrab: function() {
this._grabFocusCount--;
if (this._grabFocusCount > 0)
return;
if (this._keyFocusNotifyId > 0) {
global.stage.disconnect(this._keyFocusNotifyId);
this._keyFocusNotifyId = 0;
}
if (this._focusWindowChangedId > 0) {
let metaDisplay = global.screen.get_display();
metaDisplay.disconnect(this._focusWindowChangedId);
this._focusWindowChangedId = 0;
}
let prePopInputMode = global.stage_input_mode;
if (this._grabbedFromKeynav) {
if (this._preGrabInputMode == Shell.StageInputMode.FOCUSED &&
prePopInputMode != Shell.StageInputMode.FULLSCREEN)
global.set_stage_input_mode(Shell.StageInputMode.FOCUSED);
}
global.screen.focus_default_window(global.display.get_current_time_roundtrip());
},
// ignoreRelease:
//
// Make sure that the next button release event evaluated by the
@@ -211,14 +262,10 @@ const GrabHelper = new Lang.Class({
// ungrab:
// @params: The parameters for the grab; see below.
//
// Pops @params.actor from the grab stack, potentially dropping
// the grab. If the actor is not on the grab stack, this call is
// ignored with no ill effects.
// Pops an actor from the grab stack, potentially dropping the grab.
//
// If the actor is not at the top of the grab stack, grabs are
// popped until the grabbed actor is at the top of the grab stack.
// The onUngrab callback for every grab is called for every popped
// grab with the parameter %false.
// 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 });
@@ -227,6 +274,14 @@ const GrabHelper = new Lang.Class({
if (grabStackIndex < 0)
return;
// We may get key focus changes when calling onUngrab, which
// would cause an extra ungrab() on the next actor in the
// stack, which is wrong. Ignore key focus changes during the
// ungrab, and restore the saved key focus ourselves afterwards.
// We use a count as ungrab() may be re-entrant, as onUngrab()
// may ungrab additional actors.
this._isUngrabbingCount++;
let focus = global.stage.key_focus;
let hadFocus = focus && this._isWithinGrabbedActor(focus);
@@ -241,7 +296,18 @@ const GrabHelper = new Lang.Class({
if (poppedGrab.onUngrab)
poppedGrab.onUngrab(params.isUser);
this._releaseModalGrab();
if (poppedGrab.modal)
this._releaseModalGrab();
if (poppedGrab.grabFocus)
this._releaseFocusGrab();
}
if (!this.grabbed && this._capturedEventId > 0) {
global.stage.disconnect(this._capturedEventId);
this._capturedEventId = 0;
this._ignoreRelease = false;
}
if (hadFocus) {
@@ -249,6 +315,8 @@ const GrabHelper = new Lang.Class({
if (poppedGrab.savedFocus)
poppedGrab.savedFocus.grab_key_focus();
}
this._isUngrabbingCount--;
},
_onCapturedEvent: function(actor, event) {
@@ -269,6 +337,9 @@ const GrabHelper = new Lang.Class({
return true;
}
if (!button && this._modalCount == 0)
return false;
if (this._isWithinGrabbedActor(event.get_source()))
return false;
@@ -285,6 +356,21 @@ const GrabHelper = new Lang.Class({
return true;
}
return true;
return this._modalCount > 0;
},
_onKeyFocusChanged: function() {
if (this._isUngrabbingCount > 0)
return;
let focus = global.stage.key_focus;
if (!focus || !this._isWithinGrabbedActor(focus))
this.ungrab({ isUser: true });
},
_focusWindowChanged: function() {
let metaDisplay = global.screen.get_display();
if (metaDisplay.focus_window != null)
this.ungrab({ isUser: true });
}
});

View File

@@ -528,10 +528,17 @@ const LayoutManager = new Lang.Class({
get focusIndex() {
let i = Main.layoutManager.primaryIndex;
if (global.stage.key_focus != null)
i = this.findIndexForActor(global.stage.key_focus);
else if (global.display.focus_window != null)
i = global.display.focus_window.get_monitor();
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.findIndexForActor(focusActor);
} else {
let focusWindow = global.display.focus_window;
if (focusWindow)
i = focusWindow.get_monitor();
}
return i;
},
@@ -589,13 +596,9 @@ const LayoutManager = new Lang.Class({
// screen. So, we set no_clear_hint at the end of the animation.
_prepareStartupAnimation: function() {
// During the initial transition, add a simple actor to block all events,
// so they don't get delivered to X11 windows that have been transformed.
this._coverPane = new Clutter.Actor({ opacity: 0,
width: global.screen_width,
height: global.screen_height,
reactive: true });
this.addChrome(this._coverPane);
// Set ourselves to FULLSCREEN input mode while the animation is running
// so events don't get delivered to X11 windows (which are distorted by the animation)
global.stage_input_mode = Shell.StageInputMode.FULLSCREEN;
if (Main.sessionMode.isGreeter) {
this.panelBox.translation_y = -this.panelBox.height;
@@ -665,8 +668,7 @@ const LayoutManager = new Lang.Class({
// we no longer need to clear the stage
global.stage.no_clear_hint = true;
this._coverPane.destroy();
this._coverPane = null;
global.stage_input_mode = Shell.StageInputMode.NORMAL;
this._systemBackground.actor.destroy();
this._systemBackground = null;
@@ -747,8 +749,6 @@ const LayoutManager = new Lang.Class({
// and shown otherwise)
addChrome: function(actor, params) {
this.uiGroup.add_actor(actor);
if (this.uiGroup.contains(global.top_window_group))
this.uiGroup.set_child_below_sibling(actor, global.top_window_group);
this._trackActor(actor, params);
},

View File

@@ -849,9 +849,8 @@ const LookingGlass = new Lang.Class({
this._updateFont();
// We want it to appear to slide out from underneath the panel
Main.uiGroup.add_actor(this.actor);
Main.uiGroup.set_child_below_sibling(this.actor,
Main.layoutManager.panelBox);
Main.layoutManager.panelBox.add_actor(this.actor);
this.actor.lower_bottom();
Main.layoutManager.panelBox.connect('allocation-changed',
Lang.bind(this, this._queueResize));
Main.layoutManager.keyboardBox.connect('allocation-changed',
@@ -1073,7 +1072,7 @@ const LookingGlass = new Lang.Class({
let availableHeight = primary.height - Main.layoutManager.keyboardBox.height;
let myHeight = Math.min(primary.height * 0.7, availableHeight * 0.9);
this.actor.x = (primary.width - myWidth) / 2;
this._hiddenY = Main.layoutManager.panelBox.height - myHeight - 4; // -4 to hide the top corners
this._hiddenY = this.actor.get_parent().height - myHeight - 4; // -4 to hide the top corners
this._targetY = this._hiddenY + myHeight;
this.actor.y = this._hiddenY;
this.actor.width = myWidth;

View File

@@ -71,7 +71,6 @@ let _startDate;
let _defaultCssStylesheet = null;
let _cssStylesheet = null;
let _a11ySettings = null;
let dynamicWorkspacesSchema = null;
function _sessionUpdated() {
_loadDefaultStylesheet();
@@ -109,7 +108,6 @@ function start() {
function _sessionsLoaded() {
sessionMode.connect('updated', _sessionUpdated);
_initializePrefs();
_initializeUI();
shellDBusService = new ShellDBus.GnomeShell();
@@ -118,17 +116,6 @@ function _sessionsLoaded() {
_sessionUpdated();
}
function _initializePrefs() {
let keys = new Gio.Settings({ schema: sessionMode.overridesSchema }).list_keys();
for (let i = 0; i < keys.length; i++)
Meta.prefs_override_preference_schema(keys[i], sessionMode.overridesSchema);
if (keys.indexOf('dynamic-workspaces') > -1)
dynamicWorkspacesSchema = sessionMode.overridesSchema;
else
dynamicWorkspacesSchema = 'org.gnome.mutter';
}
function _initializeUI() {
// Ensure ShellWindowTracker and ShellAppUsage are initialized; this will
// also initialize ShellAppSystem first. ShellAppSystem
@@ -356,6 +343,8 @@ function pushModal(actor, params) {
Meta.disable_unredirect_for_screen(global.screen);
}
global.set_stage_input_mode(Shell.StageInputMode.FULLSCREEN);
modalCount += 1;
let actorDestroyId = actor.connect('destroy', function() {
let index = _findModal(actor);
@@ -404,6 +393,7 @@ function popModal(actor, timestamp) {
if (focusIndex < 0) {
global.stage.set_key_focus(null);
global.end_modal(timestamp);
global.set_stage_input_mode(Shell.StageInputMode.NORMAL);
keybindingMode = Shell.KeyBindingMode.NORMAL;
throw new Error('incorrect pop');
@@ -451,6 +441,7 @@ function popModal(actor, timestamp) {
return;
global.end_modal(timestamp);
global.set_stage_input_mode(Shell.StageInputMode.NORMAL);
Meta.enable_unredirect_for_screen(global.screen);
keybindingMode = Shell.KeyBindingMode.NORMAL;
}

View File

@@ -97,65 +97,6 @@ function _fixMarkup(text, allowMarkup) {
return GLib.markup_escape_text(text, -1);
}
const FocusGrabber = new Lang.Class({
Name: 'FocusGrabber',
_init: function(actor) {
this._actor = actor;
this._prevKeyFocusActor = null;
this._focusActorChangedId = 0;
this._focused = false;
},
grabFocus: function() {
if (this._focused)
return;
this._prevFocusedWindow = global.display.focus_window;
this._prevKeyFocusActor = global.stage.get_key_focus();
this._focusActorChangedId = global.stage.connect('notify::key-focus', Lang.bind(this, this._focusActorChanged));
if (!this._actor.navigate_focus(null, Gtk.DirectionType.TAB_FORWARD, false))
this._actor.grab_key_focus();
this._focused = true;
},
_focusUngrabbed: function() {
if (!this._focused)
return false;
if (this._focusActorChangedId > 0) {
global.stage.disconnect(this._focusActorChangedId);
this._focusActorChangedId = 0;
}
this._focused = false;
return true;
},
_focusActorChanged: function() {
let focusedActor = global.stage.get_key_focus();
if (!focusedActor || !this._actor.contains(focusedActor))
this._focusUngrabbed();
},
ungrabFocus: function() {
if (!this._focusUngrabbed())
return;
if (this._prevKeyFocusActor) {
global.stage.set_key_focus(this._prevKeyFocusActor);
this._prevKeyFocusActor = null;
} else {
let focusedActor = global.stage.get_key_focus();
if (focusedActor && this._actor.contains(focusedActor))
global.stage.set_key_focus(null);
}
}
});
const URLHighlighter = new Lang.Class({
Name: 'URLHighlighter',
@@ -1424,10 +1365,6 @@ const SummaryItem = new Lang.Class({
this.notificationStackWidget.add_actor(this.notificationStackView);
this.closeButton = Util.makeCloseButton();
this.closeButton.connect('clicked', Lang.bind(this, function() {
source.destroy();
source.emit('done-displaying-content');
}));
this.notificationStackWidget.add_actor(this.closeButton);
this._stackedNotifications = [];
@@ -1637,7 +1574,6 @@ const MessageTray = new Lang.Class({
this._notificationBin.set_y_align(Clutter.ActorAlign.START);
this._notificationWidget.add_actor(this._notificationBin);
this._notificationWidget.hide();
this._notificationFocusGrabber = new FocusGrabber(this._notificationWidget);
this._notificationQueue = [];
this._notification = null;
this._notificationClickedId = 0;
@@ -1687,6 +1623,7 @@ const MessageTray = new Lang.Class({
{ keybindingMode: Shell.KeyBindingMode.MESSAGE_TRAY });
this._grabHelper.addActor(this._summaryBoxPointer.actor);
this._grabHelper.addActor(this.actor);
this._grabHelper.addActor(this._notificationWidget);
Main.layoutManager.connect('keyboard-visible-changed', Lang.bind(this, this._onKeyboardVisibleChanged));
@@ -1812,6 +1749,7 @@ const MessageTray = new Lang.Class({
let [x, y, mask] = global.get_pointer();
this._contextMenu.setPosition(Math.round(x), Math.round(y));
this._grabHelper.grab({ actor: this._contextMenu.actor,
modal: true,
onUngrab: Lang.bind(this, function () {
this._contextMenu.close(BoxPointer.PopupAnimation.FULL);
})
@@ -1919,8 +1857,9 @@ const MessageTray = new Lang.Class({
_closeNotification: function() {
if (this._notificationState == State.SHOWN) {
this._closeButton.hide();
this._notification.emit('done-displaying');
this._notification.destroy();
this._notificationClosed = true;
this._updateState();
this._notificationClosed = false;
}
},
@@ -2377,6 +2316,7 @@ const MessageTray = new Lang.Class({
_showTray: function() {
if (!this._grabHelper.grab({ actor: this.actor,
modal: true,
onUngrab: Lang.bind(this, this._escapeTray) })) {
this._traySummoned = false;
return false;
@@ -2580,7 +2520,19 @@ const MessageTray = new Lang.Class({
},
_hideNotification: function() {
this._notificationFocusGrabber.ungrabFocus();
// 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._notificationExpandedId) {
this._notification.disconnect(this._notificationExpandedId);
@@ -2645,16 +2597,16 @@ const MessageTray = new Lang.Class({
},
_expandNotification: function(autoExpanding) {
// Don't focus notifications that are auto-expanding.
if (!autoExpanding)
this._ensureNotificationFocused();
if (!this._notificationExpandedId)
this._notificationExpandedId =
this._notification.connect('expanded',
Lang.bind(this, this._onNotificationExpanded));
// Don't animate changes in notifications that are auto-expanding.
this._notification.expand(!autoExpanding);
// Don't focus notifications that are auto-expanding.
if (!autoExpanding)
this._ensureNotificationFocused();
},
_onNotificationExpanded: function() {
@@ -2678,7 +2630,8 @@ const MessageTray = new Lang.Class({
},
_ensureNotificationFocused: function() {
this._notificationFocusGrabber.grabFocus();
this._grabHelper.grab({ actor: this._notification.actor,
grabFocus: true });
},
_onSourceDoneDisplayingContent: function(source, closeTray) {
@@ -2701,9 +2654,11 @@ const MessageTray = new Lang.Class({
let closeButton = summaryItem.closeButton;
closeButton.show();
this._summaryBoxPointerCloseClickedId = closeButton.connect('clicked', Lang.bind(this, this._hideSummaryBoxPointer));
summaryItem.prepareNotificationStackForShowing();
} else if (this._clickedSummaryItemMouseButton == 3) {
child = summaryItem.rightClickMenu;
this._summaryBoxPointerCloseClickedId = 0;
}
// If the user clicked the middle mouse button, or the item
@@ -2719,6 +2674,7 @@ const MessageTray = new Lang.Class({
this._summaryBoxPointer.bin.child = child;
this._grabHelper.grab({ actor: this._summaryBoxPointer.bin.child,
modal: true,
onUngrab: Lang.bind(this, this._onSummaryBoxPointerUngrabbed) });
this._summaryBoxPointer.actor.opacity = 0;
@@ -2797,7 +2753,10 @@ const MessageTray = new Lang.Class({
this._summaryBoxPointerItem.disconnect(this._summaryBoxPointerContentUpdatedId);
this._summaryBoxPointerContentUpdatedId = 0;
}
if (this._summaryBoxPointerCloseClickedId != 0) {
this._summaryBoxPointerItem.closeButton.disconnect(this._summaryBoxPointerCloseClickedId);
this._summaryBoxPointerCloseClickedId = 0;
}
if (this._sourceDoneDisplayingId) {
this._summaryBoxPointerItem.source.disconnect(this._sourceDoneDisplayingId);
this._sourceDoneDisplayingId = 0;

View File

@@ -79,8 +79,9 @@ const ModalDialog = new Lang.Class({
this.dialogLayout = new St.BoxLayout({ style_class: 'modal-dialog',
vertical: true });
if (params.styleClass != null)
if (params.styleClass != null) {
this.dialogLayout.add_style_class_name(params.styleClass);
}
if (!this._shellReactive) {
this._lightbox = new Lightbox.Lightbox(this._group,
@@ -356,9 +357,8 @@ const ModalDialog = new Lang.Class({
if (this._savedKeyFocus) {
this._savedKeyFocus.grab_key_focus();
this._savedKeyFocus = null;
} else {
} else
this._initialKeyFocus.grab_key_focus();
}
if (!this._shellReactive)
this._eventBlocker.lower_bottom();

View File

@@ -717,8 +717,8 @@ const Source = new Lang.Class({
this.notifications.length > 0)
return false;
let id = global.stage.connect('deactivate', Lang.bind(this, function () {
global.stage.disconnect(id);
let id = global.connect('notify::stage-input-mode', Lang.bind(this, function () {
global.disconnect(id);
this.trayIcon.click(event);
}));

View File

@@ -136,10 +136,8 @@ const OsdWindow = new Lang.Class({
return;
if (!this.actor.visible) {
Meta.disable_unredirect_for_screen(global.screen);
this.actor.show();
this.actor.opacity = 0;
this.actor.get_parent().set_child_above_sibling(this.actor, null);
Tweener.addTween(this.actor,
{ opacity: 255,
@@ -158,20 +156,16 @@ const OsdWindow = new Lang.Class({
return;
Mainloop.source_remove(this._hideTimeoutId);
this._hideTimeoutId = 0;
this._hide();
},
_hide: function() {
this._hideTimeoutId = 0;
Tweener.addTween(this.actor,
{ opacity: 0,
time: FADE_TIME,
transition: 'easeOutQuad',
onComplete: Lang.bind(this, function() {
this._reset();
Meta.enable_unredirect_for_screen(global.screen);
})
});
onComplete: Lang.bind(this, this._reset) });
},
_reset: function() {

View File

@@ -148,7 +148,7 @@ const Overview = new Lang.Class({
// Dash elements, or mouseover handlers in the workspaces.
this._coverPane = new Clutter.Actor({ opacity: 0,
reactive: true });
this._stack.add_actor(this._coverPane);
this._overview.add_actor(this._coverPane);
this._coverPane.connect('event', Lang.bind(this, function (actor, event) { return true; }));
this._stack.add_actor(this._overview);

View File

@@ -297,16 +297,13 @@ const AppMenuButton = new Lang.Class({
this._updateIconBoxClip();
},
_syncIcon: function() {
let icon = this._targetApp.get_faded_icon(2 * PANEL_ICON_SIZE, this._iconBox.text_direction);
this._iconBox.set_child(icon);
},
_onIconThemeChanged: function() {
if (this._iconBox.child == null)
return;
this._syncIcon();
this._iconBox.child.destroy();
let icon = this._targetApp.get_faded_icon(2 * PANEL_ICON_SIZE);
this._iconBox.set_child(icon);
},
_updateIconBoxClip: function() {
@@ -452,7 +449,7 @@ const AppMenuButton = new Lang.Class({
// If the app has just lost focus to the panel, pretend
// nothing happened; otherwise you can't keynav to the
// app menu.
if (global.stage.key_focus != null)
if (global.stage_input_mode == Shell.StageInputMode.FOCUSED)
return;
}
this._sync();
@@ -529,10 +526,12 @@ const AppMenuButton = new Lang.Class({
}
this._targetApp = targetApp;
let icon = targetApp.get_faded_icon(2 * PANEL_ICON_SIZE);
this._label.setText(targetApp.get_name());
this.setName(targetApp.get_name());
this._syncIcon();
this._iconBox.set_child(icon);
this._iconBox.show();
if (targetApp.get_state() == Shell.AppState.STARTING ||
@@ -857,8 +856,8 @@ const PANEL_ITEM_IMPLEMENTATIONS = {
'battery': imports.ui.status.power.Indicator,
'lockScreen': imports.ui.status.lockScreenMenu.Indicator,
'keyboard': imports.ui.status.keyboard.InputSourceIndicator,
'powerMenu': imports.gdm.powerMenu.PowerMenuButton,
'system': imports.ui.status.system.Indicator,
'powerMenu': imports.ui.auth.powerMenu.PowerMenuButton,
'userMenu': imports.ui.userMenu.UserMenuButton
};
if (Config.HAVE_BLUETOOTH)

View File

@@ -110,7 +110,6 @@ const Button = new Lang.Class({
this.actor.connect('button-press-event', Lang.bind(this, this._onButtonPress));
this.actor.connect('key-press-event', Lang.bind(this, this._onSourceKeyPress));
this.actor.connect('notify::visible', Lang.bind(this, this._onVisibilityChanged));
if (dontCreateMenu)
this.menu = new PopupMenu.PopupDummyMenu(this.actor);
@@ -184,14 +183,6 @@ const Button = new Lang.Class({
return false;
},
_onVisibilityChanged: function() {
if (!this.menu)
return;
if (!this.actor.visible)
this.menu.close();
},
_onMenuKeyPress: function(actor, event) {
if (global.focus_manager.navigate_from_event(event))
return true;

File diff suppressed because it is too large Load Diff

View File

@@ -7,6 +7,7 @@ const Lang = imports.lang;
const St = imports.gi.St;
const Shell = imports.gi.Shell;
const FileUtils = imports.misc.fileUtils;
const Search = imports.ui.search;
const KEY_FILE_GROUP = 'Shell Search Provider';
@@ -59,114 +60,108 @@ var SearchProviderProxy = Gio.DBusProxy.makeProxyWrapper(SearchProviderIface);
var SearchProvider2Proxy = Gio.DBusProxy.makeProxyWrapper(SearchProvider2Iface);
function loadRemoteSearchProviders(addProviderCallback) {
let objectPaths = {};
let loadedProviders = [];
let data = { loadedProviders: [],
objectPaths: {},
addProviderCallback: addProviderCallback };
FileUtils.collectFromDatadirsAsync('search-providers',
{ loadedCallback: remoteProvidersLoaded,
processFile: loadRemoteSearchProvider,
data: data
});
}
function loadRemoteSearchProvider(file) {
let keyfile = new GLib.KeyFile();
let path = file.get_path();
function loadRemoteSearchProvider(file, info, data) {
let keyfile = new GLib.KeyFile();
let path = file.get_path();
try {
keyfile.load_from_file(path, 0);
} catch(e) {
return;
}
if (!keyfile.has_group(KEY_FILE_GROUP))
return;
let remoteProvider;
try {
let group = KEY_FILE_GROUP;
let busName = keyfile.get_string(group, 'BusName');
let objectPath = keyfile.get_string(group, 'ObjectPath');
if (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);
objectPaths[objectPath] = remoteProvider;
loadedProviders.push(remoteProvider);
} catch(e) {
log('Failed to add search provider %s: %s'.format(path, e.toString()));
}
try {
keyfile.load_from_file(path, 0);
} catch(e) {
return;
}
let dataDirs = GLib.get_system_data_dirs();
dataDirs.forEach(function(dataDir) {
let path = GLib.build_filenamev([dataDir, 'gnome-shell', 'search-providers']);
let dir = Gio.File.new_for_path(path);
let fileEnum;
try {
fileEnum = dir.enumerate_children('standard::name,standard::type',
Gio.FileQueryInfoFlags.NONE, null);
} catch (e) {
fileEnum = null;
}
if (fileEnum != null) {
let info;
while ((info = fileEnum.next_file(null)))
loadRemoteSearchProvider(fileEnum.get_child(info));
}
});
if (!keyfile.has_group(KEY_FILE_GROUP))
return;
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');
// Special case gnome-control-center to be always active and always first
sortOrder.unshift('gnome-control-center.desktop');
loadedProviders.sort(function(providerA, providerB) {
let idxA, idxB;
let appIdA, appIdB;
loadState.loadedProviders.sort(
function(providerA, providerB) {
let idxA, idxB;
let appIdA, appIdB;
appIdA = providerA.appInfo.get_id();
appIdB = providerB.appInfo.get_id();
appIdA = providerA.appInfo.get_id();
appIdB = providerB.appInfo.get_id();
idxA = sortOrder.indexOf(appIdA);
idxB = sortOrder.indexOf(appIdB);
idxA = sortOrder.indexOf(appIdA);
idxB = sortOrder.indexOf(appIdB);
// if no provider is found in the order, use alphabetical order
if ((idxA == -1) && (idxB == -1)) {
let nameA = providerA.appInfo.get_name();
let nameB = providerB.appInfo.get_name();
// if no provider is found in the order, use alphabetical order
if ((idxA == -1) && (idxB == -1)) {
let nameA = providerA.appInfo.get_name();
let nameB = providerB.appInfo.get_name();
return GLib.utf8_collate(nameA, nameB);
}
return GLib.utf8_collate(nameA, nameB);
}
// if providerA isn't found, it's sorted after providerB
if (idxA == -1)
return 1;
// if providerA isn't found, it's sorted after providerB
if (idxA == -1)
return 1;
// if providerB isn't found, it's sorted after providerA
if (idxB == -1)
return -1;
// if providerB isn't found, it's sorted after providerA
if (idxB == -1)
return -1;
// finally, if both providers are found, return their order in the list
return (idxA - idxB);
});
// finally, if both providers are found, return their order in the list
return (idxA - idxB);
});
loadedProviders.forEach(addProviderCallback);
loadState.loadedProviders.forEach(
function(provider) {
loadState.addProviderCallback(provider);
});
}
const RemoteSearchProvider = new Lang.Class({

View File

@@ -720,8 +720,6 @@ const ScreenShield = new Lang.Class({
},
_onDragEnd: function(action, actor, eventX, eventY, modifiers) {
if (this._lockScreenState != MessageTray.State.HIDING)
return;
if (this._lockScreenGroup.y < -(ARROW_DRAG_THRESHOLD * global.stage.height)) {
// Complete motion automatically
let [velocity, velocityX, velocityY] = this._dragAction.get_velocity(0);
@@ -764,19 +762,6 @@ const ScreenShield = new Lang.Class({
}
}
if (this._lightbox.actor.visible ||
this._isActive) {
// We're either shown and active, or in the process of
// showing.
// The latter is a very unlikely condition (it requires
// idle-delay < 20), but in any case we have nothing
// to do at this point: either isActive is true, or
// it will soon be.
// isActive can also be true if the lightbox is hidden,
// in case the shield is down and the user hasn't unlocked yet
return;
}
if (!this._becomeModal()) {
// We could not become modal, so we can't activate the
// screenshield. The user is probably very upset at this
@@ -790,6 +775,19 @@ const ScreenShield = new Lang.Class({
return;
}
if (this._lightbox.actor.visible ||
this._isActive) {
// We're either shown and active, or in the process of
// showing.
// The latter is a very unlikely condition (it requires
// idle-delay < 20), but in any case we have nothing
// to do at this point: either isActive is true, or
// it will soon be.
// isActive can also be true if the lightbox is hidden,
// in case the shield is down and the user hasn't unlocked yet
return;
}
this._lightbox.show();
if (this._activationTime == 0)
@@ -927,6 +925,7 @@ 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;
@@ -936,6 +935,10 @@ const ScreenShield = new Lang.Class({
this._resetLockScreen(true, false);
},
_onUnlockSucceded: function() {
this.deactivate(true);
},
_resetLockScreen: function(animateLockScreen, animateLockDialog) {
// Don't reset the lock screen unless it is completely hidden
// This prevents the shield going down if the lock-delay timeout
@@ -1121,12 +1124,6 @@ const ScreenShield = new Lang.Class({
},
deactivate: function(animate) {
this._dialog.finish(Lang.bind(this, function() {
this._finishDeactivate(animate);
}));
},
_finishDeactivate: function(animate) {
this._hideLockScreen(animate, 0);
if (this._hasLockScreen)
@@ -1218,12 +1215,6 @@ const ScreenShield = new Lang.Class({
return;
}
// Clear the clipboard - otherwise, its contents may be leaked
// to unauthorized parties by pasting into the unlock dialog's
// password entry and unmasking the entry
St.Clipboard.get_default().set_text(St.ClipboardType.CLIPBOARD, '');
St.Clipboard.get_default().set_text(St.ClipboardType.PRIMARY, '');
this._isLocked = true;
this.activate(animate);

View File

@@ -31,7 +31,7 @@ const SearchSystem = new Lang.Class({
let remoteIndex = this._remoteProviders.indexOf(provider);
if (remoteIndex != -1)
this._remoteProviders.splice(remoteIndex, 1);
this._remoteProviders.splice(index, 1);
},
getProviders: function() {

View File

@@ -16,7 +16,6 @@ const _modes = {
'restrictive': {
parentMode: null,
stylesheetName: 'gnome-shell.css',
overridesSchema: 'org.gnome.shell.overrides',
hasOverview: false,
showCalendarEvents: false,
allowSettings: false,
@@ -43,7 +42,7 @@ const _modes = {
hasNotifications: true,
isGreeter: true,
isPrimary: true,
unlockDialog: imports.gdm.loginDialog.LoginDialog,
unlockDialog: imports.ui.auth.loginDialog.LoginDialog,
components: ['polkitAgent'],
panel: {
left: [],
@@ -60,7 +59,7 @@ const _modes = {
unlockDialog: undefined,
components: ['polkitAgent', 'telepathyClient'],
panel: {
left: [],
left: ['userMenu'],
center: [],
right: ['lockScreen']
},
@@ -72,7 +71,7 @@ const _modes = {
unlockDialog: undefined,
components: ['polkitAgent', 'telepathyClient'],
panel: {
left: [],
left: ['userMenu'],
center: [],
right: ['a11y', 'keyboard', 'lockScreen']
},
@@ -90,14 +89,14 @@ const _modes = {
hasNotifications: true,
isLocked: false,
isPrimary: true,
unlockDialog: imports.ui.unlockDialog.UnlockDialog,
unlockDialog: imports.ui.auth.unlockDialog.UnlockDialog,
components: ['networkAgent', 'polkitAgent', 'telepathyClient',
'keyring', 'recorder', 'autorunManager', 'automountManager'],
panel: {
left: ['activities', 'appMenu'],
center: ['dateMenu'],
right: ['a11y', 'keyboard', 'volume', 'bluetooth',
'network', 'battery', 'system']
'network', 'battery', 'userMenu']
}
}
};

View File

@@ -41,7 +41,6 @@ const GnomeShellIface = <interface name="org.gnome.Shell">
<signal name="AcceleratorActivated">
<arg name="action" type="u" />
<arg name="deviceid" type="u" />
<arg name="timestamp" type="u" />
</signal>
<property name="Mode" type="s" access="read" />
<property name="OverviewActive" type="b" access="readwrite" />
@@ -80,8 +79,8 @@ const GnomeShell = new Lang.Class({
this._grabbers = new Hash.Map();
global.display.connect('accelerator-activated', Lang.bind(this,
function(display, action, deviceid, timestamp) {
this._emitAcceleratorActivated(action, deviceid, timestamp);
function(display, action, deviceid) {
this._emitAcceleratorActivated(action, deviceid);
}));
},
@@ -167,7 +166,7 @@ const GnomeShell = new Lang.Class({
return invocation.return_value(GLib.Variant.new('(b)', [ungrabSucceeded]));
},
_emitAcceleratorActivated: function(action, deviceid, timestamp) {
_emitAcceleratorActivated: function(action, deviceid) {
let destination = this._grabbedAccelerators.get(action);
if (!destination)
return;
@@ -178,7 +177,7 @@ const GnomeShell = new Lang.Class({
this._dbusImpl.get_object_path(),
info ? info.name : null,
'AcceleratorActivated',
GLib.Variant.new('(uuu)', [action, deviceid, timestamp]));
GLib.Variant.new('(uu)', [action, deviceid]));
},
_grabAcceleratorForSender: function(accelerator, flags, sender) {

View File

@@ -1,210 +0,0 @@
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
const Cairo = imports.cairo;
const Clutter = imports.gi.Clutter;
const Lang = imports.lang;
const St = imports.gi.St;
const Signals = imports.signals;
const SLIDER_SCROLL_STEP = 0.05; /* Slider scrolling step in % */
const Slider = new Lang.Class({
Name: "Slider",
_init: function(value) {
if (isNaN(value))
// Avoid spreading NaNs around
throw TypeError('The slider value must be a number');
this._value = Math.max(Math.min(value, 1), 0);
this.actor = new St.DrawingArea({ style_class: 'slider',
can_focus: true,
reactive: true });
this.actor.connect('repaint', Lang.bind(this, this._sliderRepaint));
this.actor.connect('button-press-event', Lang.bind(this, this._startDragging));
this.actor.connect('scroll-event', Lang.bind(this, this._onScrollEvent));
this.actor.connect('key-press-event', Lang.bind(this, this._onKeyPressEvent));
this._releaseId = this._motionId = 0;
this._dragging = false;
},
setValue: function(value) {
if (isNaN(value))
throw TypeError('The slider value must be a number');
this._value = Math.max(Math.min(value, 1), 0);
this.actor.queue_repaint();
},
_sliderRepaint: function(area) {
let cr = area.get_context();
let themeNode = area.get_theme_node();
let [width, height] = area.get_surface_size();
let handleRadius = themeNode.get_length('-slider-handle-radius');
let handleBorderWidth = themeNode.get_length('-slider-handle-border-width');
let [hasHandleColor, handleBorderColor] =
themeNode.lookup_color('-slider-handle-border-color', false);
let sliderHeight = themeNode.get_length('-slider-height');
let sliderBorderWidth = themeNode.get_length('-slider-border-width');
let sliderBorderRadius = Math.min(width, sliderHeight) / 2;
let sliderBorderColor = themeNode.get_color('-slider-border-color');
let sliderColor = themeNode.get_color('-slider-background-color');
let sliderActiveBorderColor = themeNode.get_color('-slider-active-border-color');
let sliderActiveColor = themeNode.get_color('-slider-active-background-color');
const TAU = Math.PI * 2;
let handleX = handleRadius + (width - 2 * handleRadius) * this._value;
cr.arc(sliderBorderRadius + sliderBorderWidth, height / 2, sliderBorderRadius, TAU * 1/4, TAU * 3/4);
cr.lineTo(handleX, (height - sliderHeight) / 2);
cr.lineTo(handleX, (height + sliderHeight) / 2);
cr.lineTo(sliderBorderRadius + sliderBorderWidth, (height + sliderHeight) / 2);
Clutter.cairo_set_source_color(cr, sliderActiveColor);
cr.fillPreserve();
Clutter.cairo_set_source_color(cr, sliderActiveBorderColor);
cr.setLineWidth(sliderBorderWidth);
cr.stroke();
cr.arc(width - sliderBorderRadius - sliderBorderWidth, height / 2, sliderBorderRadius, TAU * 3/4, TAU * 1/4);
cr.lineTo(handleX, (height + sliderHeight) / 2);
cr.lineTo(handleX, (height - sliderHeight) / 2);
cr.lineTo(width - sliderBorderRadius - sliderBorderWidth, (height - sliderHeight) / 2);
Clutter.cairo_set_source_color(cr, sliderColor);
cr.fillPreserve();
Clutter.cairo_set_source_color(cr, sliderBorderColor);
cr.setLineWidth(sliderBorderWidth);
cr.stroke();
let handleY = height / 2;
let color = themeNode.get_foreground_color();
Clutter.cairo_set_source_color(cr, color);
cr.arc(handleX, handleY, handleRadius, 0, 2 * Math.PI);
cr.fillPreserve();
if (hasHandleColor && handleBorderWidth) {
Clutter.cairo_set_source_color(cr, handleBorderColor);
cr.setLineWidth(handleBorderWidth);
cr.stroke();
}
cr.$dispose();
},
_startDragging: function(actor, event) {
this.startDragging(event);
},
startDragging: function(event) {
if (this._dragging)
return false;
this._dragging = true;
let device = event.get_device();
device.grab(this.actor);
this._grabbedDevice = device;
this._releaseId = this.actor.connect('button-release-event', Lang.bind(this, this._endDragging));
this._motionId = this.actor.connect('motion-event', Lang.bind(this, this._motionEvent));
let absX, absY;
[absX, absY] = event.get_coords();
this._moveHandle(absX, absY);
return true;
},
_endDragging: function() {
if (this._dragging) {
this.actor.disconnect(this._releaseId);
this.actor.disconnect(this._motionId);
this._grabbedDevice.ungrab();
this._grabbedDevice = null;
this._dragging = false;
this.emit('drag-end');
}
return true;
},
scroll: function(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.min(Math.max(0, this._value + delta), 1);
this.actor.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();
this._moveHandle(absX, absY);
return true;
},
_onKeyPressEvent: function (actor, event) {
let key = event.get_key_symbol();
if (key == Clutter.KEY_Right || key == Clutter.KEY_Left) {
let delta = key == Clutter.KEY_Right ? 0.1 : -0.1;
this._value = Math.max(0, Math.min(this._value + delta, 1));
this._slider.queue_repaint();
this.emit('value-changed', this._value);
this.emit('drag-end');
return true;
}
return false;
},
_moveHandle: function(absX, absY) {
let relX, relY, sliderX, sliderY;
[sliderX, sliderY] = this.actor.get_transformed_position();
relX = absX - sliderX;
relY = absY - sliderY;
let width = this.actor.width;
let handleRadius = this.actor.get_theme_node().get_length('-slider-handle-radius');
let newvalue;
if (relX < handleRadius)
newvalue = 0;
else if (relX > width - handleRadius)
newvalue = 1;
else
newvalue = (relX - handleRadius) / (width - 2 * handleRadius);
this._value = newvalue;
this.actor.queue_repaint();
this.emit('value-changed', this._value);
},
get value() {
return this._value;
}
});
Signals.addSignalMethods(Slider.prototype);

View File

@@ -68,6 +68,9 @@ const ATIndicator = new Lang.Class({
let mouseKeys = this._buildItem(_("Mouse Keys"), A11Y_SCHEMA, KEY_MOUSE_KEYS_ENABLED);
this.menu.addMenuItem(mouseKeys);
this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
this.menu.addSettingsAction(_("Universal Access Settings"), 'gnome-universal-access-panel.desktop');
this._syncMenuVisibility();
},

View File

@@ -13,6 +13,13 @@ const NotificationDaemon = imports.ui.notificationDaemon;
const PanelMenu = imports.ui.panelMenu;
const PopupMenu = imports.ui.popupMenu;
const ConnectionState = {
DISCONNECTED: 0,
CONNECTED: 1,
DISCONNECTING: 2,
CONNECTING: 3
}
const Indicator = new Lang.Class({
Name: 'BTIndicator',
Extends: PanelMenu.SystemStatusButton,
@@ -20,38 +27,261 @@ const Indicator = new Lang.Class({
_init: function() {
this.parent('bluetooth-disabled-symbolic', _("Bluetooth"));
// The Bluetooth menu only appears when Bluetooth is in use,
// so just statically build it with a "Turn Off" menu item.
this._item = new PopupMenu.PopupSubMenuMenuItem(_("Bluetooth"), true);
this._item.icon.icon_name = 'bluetooth-active-symbolic';
this._item.menu.addAction(_("Turn Off"), Lang.bind(this, function() {
this._applet.killswitch_state = GnomeBluetooth.KillswitchState.SOFT_BLOCKED;
}));
this._item.menu.addSettingsAction(_("Bluetooth Settings"), 'gnome-bluetooth-panel.desktop');
this._applet = new GnomeBluetoothApplet.Applet();
this._applet.connect('devices-changed', Lang.bind(this, this._sync));
this._sync();
this._killswitch = new PopupMenu.PopupSwitchMenuItem(_("Bluetooth"), false);
this._applet.connect('notify::killswitch-state', Lang.bind(this, this._updateKillswitch));
this._killswitch.connect('toggled', Lang.bind(this, function() {
let current_state = this._applet.killswitch_state;
if (current_state != GnomeBluetooth.KillswitchState.HARD_BLOCKED &&
current_state != GnomeBluetooth.KillswitchState.NO_ADAPTER) {
this._applet.killswitch_state = this._killswitch.state ?
GnomeBluetooth.KillswitchState.UNBLOCKED:
GnomeBluetooth.KillswitchState.SOFT_BLOCKED;
} else
this._killswitch.setToggleState(false);
}));
this._discoverable = new PopupMenu.PopupSwitchMenuItem(_("Visibility"), this._applet.discoverable);
this._applet.connect('notify::discoverable', Lang.bind(this, function() {
this._discoverable.setToggleState(this._applet.discoverable);
}));
this._discoverable.connect('toggled', Lang.bind(this, function() {
this._applet.discoverable = this._discoverable.state;
}));
this._updateKillswitch();
this.menu.addMenuItem(this._killswitch);
this.menu.addMenuItem(this._discoverable);
this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
this._fullMenuItems = [new PopupMenu.PopupSeparatorMenuItem(),
new PopupMenu.PopupMenuItem(_("Send Files to Device…")),
new PopupMenu.PopupMenuItem(_("Set Up a New Device…")),
new PopupMenu.PopupSeparatorMenuItem()];
this._hasDevices = false;
this._fullMenuItems[1].connect('activate', function() {
GLib.spawn_command_line_async('bluetooth-sendto');
});
this._fullMenuItems[2].connect('activate', function() {
GLib.spawn_command_line_async('bluetooth-wizard');
});
for (let i = 0; i < this._fullMenuItems.length; i++) {
let item = this._fullMenuItems[i];
this.menu.addMenuItem(item);
}
this._deviceItemPosition = 3;
this._deviceItems = [];
this._applet.connect('devices-changed', Lang.bind(this, this._updateDevices));
this._updateDevices();
this._applet.connect('notify::show-full-menu', Lang.bind(this, this._updateFullMenu));
this._updateFullMenu();
this.menu.addSettingsAction(_("Bluetooth Settings"), 'gnome-bluetooth-panel.desktop');
this._applet.connect('pincode-request', Lang.bind(this, this._pinRequest));
this._applet.connect('confirm-request', Lang.bind(this, this._confirmRequest));
this._applet.connect('auth-request', Lang.bind(this, this._authRequest));
this._applet.connect('auth-service-request', Lang.bind(this, this._authServiceRequest));
this._applet.connect('cancel-request', Lang.bind(this, this._cancelRequest));
},
_sync: function() {
let connectedDevices = this._applet.get_devices().filter(function(device) {
return device.connected;
});
let nDevices = connectedDevices.length;
_updateKillswitch: function() {
let current_state = this._applet.killswitch_state;
let on = current_state == GnomeBluetooth.KillswitchState.UNBLOCKED;
let has_adapter = current_state != GnomeBluetooth.KillswitchState.NO_ADAPTER;
let can_toggle = current_state != GnomeBluetooth.KillswitchState.NO_ADAPTER &&
current_state != GnomeBluetooth.KillswitchState.HARD_BLOCKED;
let on = nDevices > 0;
this.mainIcon.visible = on;
this.actor.visible = on;
this._killswitch.setToggleState(on);
if (can_toggle)
this._killswitch.setStatus(null);
else
/* TRANSLATORS: this means that bluetooth was disabled by hardware rfkill */
this._killswitch.setStatus(_("hardware disabled"));
if (on)
this._item.status.text = ngettext("%d Connected Device", "%d Connected Devices").format(nDevices);
this.actor.visible = has_adapter;
if (on) {
this._discoverable.actor.show();
this.setIcon('bluetooth-active-symbolic');
} else {
this._discoverable.actor.hide();
this.setIcon('bluetooth-disabled-symbolic');
}
},
_updateDevices: function() {
let devices = this._applet.get_devices();
let newlist = [ ];
for (let i = 0; i < this._deviceItems.length; i++) {
let item = this._deviceItems[i];
let destroy = true;
for (let j = 0; j < devices.length; j++) {
if (item._device.device_path == devices[j].device_path) {
this._updateDeviceItem(item, devices[j]);
destroy = false;
break;
}
}
if (destroy)
item.destroy();
else
newlist.push(item);
}
this._deviceItems = newlist;
this._hasDevices = newlist.length > 0;
for (let i = 0; i < devices.length; i++) {
let d = devices[i];
if (d._item)
continue;
let item = this._createDeviceItem(d);
if (item) {
this.menu.addMenuItem(item, this._deviceItemPosition + this._deviceItems.length);
this._deviceItems.push(item);
this._hasDevices = true;
}
}
},
_updateDeviceItem: function(item, device) {
if (!device.can_connect && device.capabilities == GnomeBluetoothApplet.Capabilities.NONE) {
item.destroy();
return;
}
let prevDevice = item._device;
let prevCapabilities = prevDevice.capabilities;
let prevCanConnect = prevDevice.can_connect;
// adopt the new device object
item._device = device;
device._item = item;
// update properties
item.label.text = device.alias;
if (prevCapabilities != device.capabilities ||
prevCanConnect != device.can_connect) {
// need to rebuild the submenu
item.menu.removeAll();
this._buildDeviceSubMenu(item, device);
}
// update connected property
if (device.can_connect)
item._connectedMenuItem.setToggleState(device.connected);
},
_createDeviceItem: function(device) {
if (!device.can_connect && device.capabilities == GnomeBluetoothApplet.Capabilities.NONE)
return null;
let item = new PopupMenu.PopupSubMenuMenuItem(device.alias);
// adopt the device object, and add a back link
item._device = device;
device._item = item;
this._buildDeviceSubMenu(item, device);
return item;
},
_buildDeviceSubMenu: function(item, device) {
if (device.can_connect) {
let menuitem = new PopupMenu.PopupSwitchMenuItem(_("Connection"), device.connected);
item._connected = device.connected;
item._connectedMenuItem = menuitem;
menuitem.connect('toggled', Lang.bind(this, function() {
if (item._connected > ConnectionState.CONNECTED) {
// operation already in progress, revert
// (should not happen anyway)
menuitem.setToggleState(menuitem.state);
}
if (item._connected) {
item._connected = ConnectionState.DISCONNECTING;
menuitem.setStatus(_("disconnecting..."));
this._applet.disconnect_device(item._device.device_path, function(applet, success) {
if (success) { // apply
item._connected = ConnectionState.DISCONNECTED;
menuitem.setToggleState(false);
} else { // revert
item._connected = ConnectionState.CONNECTED;
menuitem.setToggleState(true);
}
menuitem.setStatus(null);
});
} else {
item._connected = ConnectionState.CONNECTING;
menuitem.setStatus(_("connecting..."));
this._applet.connect_device(item._device.device_path, function(applet, success) {
if (success) { // apply
item._connected = ConnectionState.CONNECTED;
menuitem.setToggleState(true);
} else { // revert
item._connected = ConnectionState.DISCONNECTED;
menuitem.setToggleState(false);
}
menuitem.setStatus(null);
});
}
}));
item.menu.addMenuItem(menuitem);
}
if (device.capabilities & GnomeBluetoothApplet.Capabilities.OBEX_PUSH) {
item.menu.addAction(_("Send Files…"), Lang.bind(this, function() {
this._applet.send_to_address(device.bdaddr, device.alias);
}));
}
switch (device.type) {
case GnomeBluetoothApplet.Type.KEYBOARD:
item.menu.addSettingsAction(_("Keyboard Settings"), 'gnome-keyboard-panel.desktop');
break;
case GnomeBluetoothApplet.Type.MOUSE:
item.menu.addSettingsAction(_("Mouse Settings"), 'gnome-mouse-panel.desktop');
break;
case GnomeBluetoothApplet.Type.HEADSET:
case GnomeBluetoothApplet.Type.HEADPHONES:
case GnomeBluetoothApplet.Type.OTHER_AUDIO:
item.menu.addSettingsAction(_("Sound Settings"), 'gnome-sound-panel.desktop');
break;
default:
break;
}
},
_updateFullMenu: function() {
if (this._applet.show_full_menu) {
this._showAll(this._fullMenuItems);
if (this._hasDevices)
this._showAll(this._deviceItems);
} else {
this._hideAll(this._fullMenuItems);
this._hideAll(this._deviceItems);
}
},
_showAll: function(items) {
for (let i = 0; i < items.length; i++)
items[i].actor.show();
},
_hideAll: function(items) {
for (let i = 0; i < items.length; i++)
items[i].actor.hide();
},
_destroyAll: function(items) {
for (let i = 0; i < items.length; i++)
items[i].destroy();
},
_ensureSource: function() {
@@ -62,14 +292,9 @@ const Indicator = new Lang.Class({
}
},
_authRequest: function(applet, device_path, name, long_name) {
_authRequest: function(applet, device_path, name, long_name, uuid) {
this._ensureSource();
this._source.notify(new AuthNotification(this._source, this._applet, device_path, name, long_name));
},
_authServiceRequest: function(applet, device_path, name, long_name, uuid) {
this._ensureSource();
this._source.notify(new AuthServiceNotification(this._source, this._applet, device_path, name, long_name, uuid));
this._source.notify(new AuthNotification(this._source, this._applet, device_path, name, long_name, uuid));
},
_confirmRequest: function(applet, device_path, name, long_name, pin) {
@@ -91,34 +316,6 @@ const AuthNotification = new Lang.Class({
Name: 'AuthNotification',
Extends: MessageTray.Notification,
_init: function(source, applet, device_path, name, long_name) {
this.parent(source,
_("Bluetooth"),
_("Authorization request from %s").format(name),
{ customContent: true });
this.setResident(true);
this._applet = applet;
this._devicePath = device_path;
this.addBody(_("Device %s wants to pair with this computer").format(long_name));
this.addButton('allow', _("Allow"));
this.addButton('deny', _("Deny"));
this.connect('action-invoked', Lang.bind(this, function(self, action) {
if (action == 'allow')
this._applet.agent_reply_confirm(this._devicePath, true);
else
this._applet.agent_reply_confirm(this._devicePath, false);
this.destroy();
}));
}
});
const AuthServiceNotification = new Lang.Class({
Name: 'AuthServiceNotification',
Extends: MessageTray.Notification,
_init: function(source, applet, device_path, name, long_name, uuid) {
this.parent(source,
_("Bluetooth"),
@@ -137,14 +334,14 @@ const AuthServiceNotification = new Lang.Class({
this.connect('action-invoked', Lang.bind(this, function(self, action) {
switch (action) {
case 'always-grant':
this._applet.agent_reply_auth_service(this._devicePath, true, true);
this._applet.agent_reply_auth(this._devicePath, true, true);
break;
case 'grant':
this._applet.agent_reply_auth_service(this._devicePath, true, false);
this._applet.agent_reply_auth(this._devicePath, true, false);
break;
case 'reject':
default:
this._applet.agent_reply_auth_service(this._devicePath, false, false);
this._applet.agent_reply_auth(this._devicePath, false, false);
}
this.destroy();
}));

View File

@@ -398,6 +398,8 @@ const InputSourceIndicator = new Lang.Class({
Main.sessionMode.connect('updated', Lang.bind(this, this._sessionUpdated));
this._sessionUpdated();
this.menu.addSettingsAction(_("Region & Language Settings"), 'gnome-region-panel.desktop');
this._sourcesPerWindow = false;
this._focusWindowNotifyId = 0;
this._overviewShowingId = 0;

File diff suppressed because it is too large Load Diff

View File

@@ -2,15 +2,39 @@
const Gio = imports.gi.Gio;
const Lang = imports.lang;
const UPower = imports.gi.UPowerGlib;
const St = imports.gi.St;
const Main = imports.ui.main;
const PanelMenu = imports.ui.panelMenu;
const PopupMenu = imports.ui.popupMenu;
const BUS_NAME = 'org.gnome.SettingsDaemon.Power';
const OBJECT_PATH = '/org/gnome/SettingsDaemon/Power';
const UPDeviceType = {
UNKNOWN: 0,
AC_POWER: 1,
BATTERY: 2,
UPS: 3,
MONITOR: 4,
MOUSE: 5,
KEYBOARD: 6,
PDA: 7,
PHONE: 8,
MEDIA_PLAYER: 9,
TABLET: 10,
COMPUTER: 11
};
const UPDeviceState = {
UNKNOWN: 0,
CHARGING: 1,
DISCHARGING: 2,
EMPTY: 3,
FULLY_CHARGED: 4,
PENDING_CHARGE: 5,
PENDING_DISCHARGE: 6
};
const PowerManagerInterface = <interface name="org.gnome.SettingsDaemon.Power">
<method name="GetDevices">
<arg type="a(susdut)" direction="out" />
@@ -31,73 +55,96 @@ const Indicator = new Lang.Class({
this.parent('battery-missing-symbolic', _("Battery"));
this._proxy = new PowerManagerProxy(Gio.DBus.session, BUS_NAME, OBJECT_PATH,
Lang.bind(this, function(proxy, error) {
if (error) {
log(error.message);
return;
}
this._proxy.connect('g-properties-changed',
Lang.bind(this, this._sync));
this._sync();
}));
Lang.bind(this, function(proxy, error) {
if (error) {
log(error.message);
return;
}
this._proxy.connect('g-properties-changed',
Lang.bind(this, this._devicesChanged));
this._devicesChanged();
}));
this._item = new PopupMenu.PopupSubMenuMenuItem(_("Battery"), true);
this._item.menu.addSettingsAction(_("Power Settings"), 'gnome-power-panel.desktop');
this.menu.addMenuItem(this._item);
this._deviceItems = [ ];
this._hasPrimary = false;
this._primaryDeviceId = null;
Main.sessionMode.connect('updated', Lang.bind(this, this._sessionUpdated));
this._sessionUpdated();
this._batteryItem = new PopupMenu.PopupMenuItem('', { reactive: false });
this._primaryPercentage = new St.Label({ style_class: 'popup-battery-percentage' });
this._batteryItem.addActor(this._primaryPercentage, { align: St.Align.END });
this.menu.addMenuItem(this._batteryItem);
this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
this._otherDevicePosition = 2;
this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
this.menu.addSettingsAction(_("Power Settings"), 'gnome-power-panel.desktop');
},
_sessionUpdated: function() {
let sensitive = !Main.sessionMode.isLocked && !Main.sessionMode.isGreeter;
this.menu.setSensitive(sensitive);
},
_statusForDevice: function(device) {
let [device_id, device_type, icon, percentage, state, seconds] = device;
if (state == UPower.DeviceState.FULLY_CHARGED)
return _("Fully Charged");
let time = Math.round(seconds / 60);
if (time == 0) {
// 0 is reported when UPower does not have enough data
// to estimate battery life
return _("Estimating…");
}
let minutes = time % 60;
let hours = Math.floor(time / 60);
if (state == UPower.DeviceState.DISCHARGING) {
// Translators: this is <hours>:<minutes> Remaining (<percentage>)
return _("%d\u2236%d Remaining (%d%%)".format(hours, minutes, percentage));
}
if (state == UPower.DeviceState.CHARGING) {
// Translators: this is <hours>:<minutes> Until Full (<percentage>)
return _("%d\u2236%d Until Full (%d%%)".format(hours, minutes, percentage));
}
// state is one of PENDING_CHARGING, PENDING_DISCHARGING
return _("Estimating…");
},
_syncStatusLabel: function() {
_readPrimaryDevice: function() {
this._proxy.GetPrimaryDeviceRemote(Lang.bind(this, function(result, error) {
if (error) {
this._item.actor.hide();
this._hasPrimary = false;
this._primaryDeviceId = null;
this._batteryItem.actor.hide();
return;
}
let [[device_id, device_type, icon, percentage, state, seconds]] = result;
if (device_type == UPDeviceType.BATTERY) {
this._hasPrimary = true;
let time = Math.round(seconds / 60);
if (time == 0) {
// 0 is reported when UPower does not have enough data
// to estimate battery life
this._batteryItem.label.text = _("Estimating…");
} else {
let minutes = time % 60;
let hours = Math.floor(time / 60);
let timestring;
if (time >= 60) {
if (minutes == 0) {
timestring = ngettext("%d hour remaining", "%d hours remaining", hours).format(hours);
} else {
/* TRANSLATORS: this is a time string, as in "%d hours %d minutes remaining" */
let template = _("%d %s %d %s remaining");
timestring = template.format (hours, ngettext("hour", "hours", hours), minutes, ngettext("minute", "minutes", minutes));
}
} else
timestring = ngettext("%d minute remaining", "%d minutes remaining", minutes).format(minutes);
this._batteryItem.label.text = timestring;
}
this._primaryPercentage.text = C_("percent of battery remaining", "%d%%").format(Math.round(percentage));
this._batteryItem.actor.show();
} else {
this._hasPrimary = false;
this._batteryItem.actor.hide();
}
this._primaryDeviceId = device_id;
}));
},
_readOtherDevices: function() {
this._proxy.GetDevicesRemote(Lang.bind(this, function(result, error) {
this._deviceItems.forEach(function(i) { i.destroy(); });
this._deviceItems = [];
if (error) {
return;
}
let [device] = result;
let [device_id, device_type] = device;
if (device_type == UPower.DeviceKind.BATTERY) {
this._item.status.text = this._statusForDevice(device);
this._item.actor.show();
} else {
this._item.actor.hide();
let position = 0;
let [devices] = result;
for (let i = 0; i < devices.length; i++) {
let [device_id, device_type] = devices[i];
if (device_type == UPDeviceType.AC_POWER || device_id == this._primaryDeviceId)
continue;
let item = new DeviceItem (devices[i]);
this._deviceItems.push(item);
this.menu.addMenuItem(item, this._otherDevicePosition + position);
position++;
}
}));
},
@@ -109,15 +156,71 @@ const Indicator = new Lang.Class({
if (icon) {
let gicon = Gio.icon_new_for_string(icon);
this.setGIcon(gicon);
this._item.icon.gicon = gicon;
hasIcon = true;
}
this.mainIcon.visible = hasIcon;
this.actor.visible = hasIcon;
},
_sync: function() {
_devicesChanged: function() {
this._syncIcon();
this._syncStatusLabel();
this._readPrimaryDevice();
this._readOtherDevices();
}
});
const DeviceItem = new Lang.Class({
Name: 'DeviceItem',
Extends: PopupMenu.PopupBaseMenuItem,
_init: function(device) {
this.parent({ reactive: false });
let [device_id, device_type, icon, percentage, state, time] = device;
this._box = new St.BoxLayout({ style_class: 'popup-device-menu-item' });
this._label = new St.Label({ text: this._deviceTypeToString(device_type) });
this._icon = new St.Icon({ gicon: Gio.icon_new_for_string(icon),
style_class: 'popup-menu-icon' });
this._box.add_actor(this._icon);
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' });
this.addActor(percentLabel, { align: St.Align.END });
//FIXME: ideally we would like to expose this._label and percentLabel
this.actor.label_actor = percentLabel;
},
_deviceTypeToString: function(type) {
switch (type) {
case UPDeviceType.AC_POWER:
return _("AC Adapter");
case UPDeviceType.BATTERY:
return _("Laptop Battery");
case UPDeviceType.UPS:
return _("UPS");
case UPDeviceType.MONITOR:
return _("Monitor");
case UPDeviceType.MOUSE:
return _("Mouse");
case UPDeviceType.KEYBOARD:
return _("Keyboard");
case UPDeviceType.PDA:
return _("PDA");
case UPDeviceType.PHONE:
return _("Cell Phone");
case UPDeviceType.MEDIA_PLAYER:
return _("Media Player");
case UPDeviceType.TABLET:
return _("Tablet");
case UPDeviceType.COMPUTER:
return _("Computer");
default:
return C_("device", "Unknown");
}
}
});

View File

@@ -1,358 +0,0 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
const AccountsService = imports.gi.AccountsService;
const Gdm = imports.gi.Gdm;
const Gio = imports.gi.Gio;
const GLib = imports.gi.GLib;
const Gtk = imports.gi.Gtk;
const Lang = imports.lang;
const Shell = imports.gi.Shell;
const St = imports.gi.St;
const Clutter = imports.gi.Clutter;
const BoxPointer = imports.ui.boxpointer;
const GnomeSession = imports.misc.gnomeSession;
const LoginManager = imports.misc.loginManager;
const Main = imports.ui.main;
const ModalDialog = imports.ui.modalDialog;
const PanelMenu = imports.ui.panelMenu;
const PopupMenu = imports.ui.popupMenu;
const Util = imports.misc.util;
const UserWidget = imports.ui.userWidget;
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 ALWAYS_SHOW_LOG_OUT_KEY = 'always-show-log-out';
const MAX_USERS_IN_SESSION_DIALOG = 5;
const SystemdLoginSessionIface = <interface name='org.freedesktop.login1.Session'>
<property name="Id" type="s" access="read"/>
<property name="Remote" type="b" access="read"/>
<property name="Class" type="s" access="read"/>
<property name="Type" type="s" access="read"/>
<property name="State" type="s" access="read"/>
</interface>;
const SystemdLoginSession = Gio.DBusProxy.makeProxyWrapper(SystemdLoginSessionIface);
const Indicator = new Lang.Class({
Name: 'SystemIndicator',
Extends: PanelMenu.SystemStatusButton,
_init: function() {
this.parent('system-shutdown-symbolic', _("System"));
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._session = new GnomeSession.SessionManager();
this._haveShutdown = true;
this._loginManager = LoginManager.getLoginManager();
this._userManager = AccountsService.UserManager.get_default();
this._user = this._userManager.get_user(GLib.get_user_name());
this._createSubMenu();
this._userManager.connect('notify::is-loaded',
Lang.bind(this, this._updateMultiUser));
this._userManager.connect('notify::has-multiple-users',
Lang.bind(this, this._updateMultiUser));
this._userManager.connect('user-added',
Lang.bind(this, this._updateMultiUser));
this._userManager.connect('user-removed',
Lang.bind(this, this._updateMultiUser));
this._lockdownSettings.connect('changed::' + DISABLE_USER_SWITCH_KEY,
Lang.bind(this, this._updateMultiUser));
this._lockdownSettings.connect('changed::' + DISABLE_LOG_OUT_KEY,
Lang.bind(this, this._updateMultiUser));
this._lockdownSettings.connect('changed::' + DISABLE_LOCK_SCREEN_KEY,
Lang.bind(this, this._updateLockScreen));
global.settings.connect('changed::' + ALWAYS_SHOW_LOG_OUT_KEY,
Lang.bind(this, this._updateMultiUser));
this._updateSwitchUser();
this._updateMultiUser();
// Whether shutdown is available or not depends on both lockdown
// settings (disable-log-out) and Polkit policy - the latter doesn't
// notify, so we update the menu item each time the menu opens or
// the lockdown setting changes, which should be close enough.
this.menu.connect('open-state-changed', Lang.bind(this,
function(menu, open) {
if (!open)
return;
this._updateHaveShutdown();
}));
this._lockdownSettings.connect('changed::' + DISABLE_LOG_OUT_KEY,
Lang.bind(this, this._updateHaveShutdown));
Main.sessionMode.connect('updated', Lang.bind(this, this._sessionUpdated));
this._sessionUpdated();
},
_sessionUpdated: function() {
this._updateLockScreen();
this._updatePowerOff();
this._settingsAction.visible = Main.sessionMode.allowSettings;
},
_updateMultiUser: function() {
let shouldShowInMode = !Main.sessionMode.isLocked && !Main.sessionMode.isGreeter;
let hasSwitchUser = this._updateSwitchUser();
let hasLogout = this._updateLogout();
this._switchUserSubMenu.actor.visible = shouldShowInMode && (hasSwitchUser || hasLogout);
},
_updateSwitchUser: function() {
let allowSwitch = !this._lockdownSettings.get_boolean(DISABLE_USER_SWITCH_KEY);
let multiUser = this._userManager.can_switch() && this._userManager.has_multiple_users;
let visible = allowSwitch && multiUser;
this._loginScreenItem.actor.visible = visible;
return visible;
},
_updateLogout: function() {
let allowLogout = !this._lockdownSettings.get_boolean(DISABLE_LOG_OUT_KEY);
let alwaysShow = global.settings.get_boolean(ALWAYS_SHOW_LOG_OUT_KEY);
let systemAccount = this._user.system_account;
let localAccount = this._user.local_account;
let multiUser = this._userManager.has_multiple_users;
let multiSession = Gdm.get_session_ids().length > 1;
let visible = allowLogout && (alwaysShow || multiUser || multiSession || systemAccount || !localAccount);
this._logoutItem.actor.visible = visible;
return visible;
},
_updateSwitchUserSubMenu: function() {
this._switchUserSubMenu.label.text = this._user.get_real_name();
let iconFile = this._user.get_icon_file();
if (iconFile && !GLib.file_test(iconFile, GLib.FileTest.EXISTS))
iconFile = null;
if (iconFile) {
let file = Gio.File.new_for_path(iconFile);
let gicon = new Gio.FileIcon({ file: file });
this._switchUserSubMenu.icon.gicon = gicon;
} else {
this._switchUserSubMenu.icon_name = 'avatar-default-symbolic';
}
},
_updateLockScreen: function() {
let showLock = !Main.sessionMode.isLocked && !Main.sessionMode.isGreeter;
let allowLockScreen = !this._lockdownSettings.get_boolean(DISABLE_LOCK_SCREEN_KEY);
this._lockScreenAction.visible = showLock && allowLockScreen && LoginManager.canLock();
},
_updateHaveShutdown: function() {
this._session.CanShutdownRemote(Lang.bind(this,
function(result, error) {
if (!error) {
this._haveShutdown = result[0];
this._updatePowerOff();
}
}));
},
_updatePowerOff: function() {
this._powerOffAction.visible = this._haveShutdown && !Main.sessionMode.isLocked;
},
_createActionButton: function(iconName, accessibleName) {
let icon = new St.Button({ reactive: true,
can_focus: true,
track_hover: true,
accessible_name: accessibleName,
style_class: 'system-menu-action' });
icon.child = new St.Icon({ icon_name: iconName });
return icon;
},
_createSubMenu: function() {
let item;
this._switchUserSubMenu = new PopupMenu.PopupSubMenuMenuItem('', true);
this._switchUserSubMenu.icon.style_class = 'system-switch-user-submenu-icon';
item = new PopupMenu.PopupMenuItem(_("Switch User"));
item.connect('activate', Lang.bind(this, this._onLoginScreenActivate));
this._switchUserSubMenu.menu.addMenuItem(item);
this._loginScreenItem = item;
item = new PopupMenu.PopupMenuItem(_("Log Out"));
item.connect('activate', Lang.bind(this, this._onQuitSessionActivate));
this._switchUserSubMenu.menu.addMenuItem(item);
this._logoutItem = item;
this._user.connect('notify::is-loaded', Lang.bind(this, this._updateSwitchUserSubMenu));
this._user.connect('changed', Lang.bind(this, this._updateSwitchUserSubMenu));
this.menu.addMenuItem(this._switchUserSubMenu);
this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
let hbox = new St.BoxLayout({ style_class: 'system-menu-actions-box' });
this._settingsAction = this._createActionButton('preferences-system-symbolic', _("Settings"));
this._settingsAction.connect('clicked', Lang.bind(this, this._onSettingsClicked));
hbox.add(this._settingsAction, { expand: true, x_fill: false });
this._lockScreenAction = this._createActionButton('changes-prevent-symbolic', _("Lock"));
this._lockScreenAction.connect('clicked', Lang.bind(this, this._onLockScreenClicked));
hbox.add(this._lockScreenAction, { expand: true, x_fill: false });
this._powerOffAction = this._createActionButton('system-shutdown-symbolic', _("Power Off"));
this._powerOffAction.connect('clicked', Lang.bind(this, this._onPowerOffClicked));
hbox.add(this._powerOffAction, { expand: true, x_fill: false });
item = new PopupMenu.PopupBaseMenuItem({ reactive: false,
can_focus: false });
item.addActor(hbox, { expand: true });
this.menu.addMenuItem(item);
},
_onSettingsClicked: function() {
this.menu.itemActivated();
let app = Shell.AppSystem.get_default().lookup_app('gnome-control-center.desktop');
Main.overview.hide();
app.activate();
},
_onLockScreenClicked: function() {
this.menu.itemActivated(BoxPointer.PopupAnimation.NONE);
Main.overview.hide();
Main.screenShield.lock(true);
},
_onLoginScreenActivate: function() {
this.menu.itemActivated(BoxPointer.PopupAnimation.NONE);
Main.overview.hide();
if (Main.screenShield)
Main.screenShield.lock(false);
Gdm.goto_login_session_sync(null);
},
_onQuitSessionActivate: function() {
Main.overview.hide();
this._session.LogoutRemote(0);
},
_openSessionWarnDialog: function(sessions) {
let dialog = new ModalDialog.ModalDialog();
let subjectLabel = new St.Label({ style_class: 'end-session-dialog-subject',
text: _("Other users are logged in.") });
dialog.contentLayout.add(subjectLabel, { y_fill: true,
y_align: St.Align.START });
let descriptionLabel = new St.Label({ style_class: 'end-session-dialog-description'});
descriptionLabel.set_text(_("Shutting down might cause them to lose unsaved work."));
descriptionLabel.clutter_text.line_wrap = true;
dialog.contentLayout.add(descriptionLabel, { x_fill: true,
y_fill: true,
y_align: St.Align.START });
let scrollView = new St.ScrollView({ style_class: 'end-session-dialog-app-list' });
scrollView.add_style_class_name('vfade');
scrollView.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC);
dialog.contentLayout.add(scrollView, { x_fill: true, y_fill: true });
let userList = new St.BoxLayout({ vertical: true });
scrollView.add_actor(userList);
for (let i = 0; i < sessions.length; i++) {
let session = sessions[i];
let userEntry = new St.BoxLayout({ style_class: 'login-dialog-user-list-item',
vertical: false });
let avatar = new UserWidget.Avatar(session.user);
avatar.update();
userEntry.add(avatar.actor);
let userLabelText = "";;
let userName = session.user.get_real_name() ?
session.user.get_real_name() : session.username;
if (session.info.remote)
/* Translators: Remote here refers to a remote session, like a ssh login */
userLabelText = _("%s (remote)").format(userName);
else if (session.info.type == "tty")
/* Translators: Console here refers to a tty like a VT console */
userLabelText = _("%s (console)").format(userName);
else
userLabelText = userName;
let textLayout = new St.BoxLayout({ style_class: 'login-dialog-user-list-item-text-box',
vertical: true });
textLayout.add(new St.Label({ text: userLabelText }),
{ y_fill: false,
y_align: St.Align.MIDDLE,
expand: true });
userEntry.add(textLayout, { expand: true });
userList.add(userEntry, { x_fill: true });
}
let cancelButton = { label: _("Cancel"),
action: function() { dialog.close(); },
key: Clutter.Escape };
let powerOffButton = { label: _("Power Off"), action: Lang.bind(this, function() {
dialog.close();
this._session.ShutdownRemote();
}), default: true };
dialog.setButtons([cancelButton, powerOffButton]);
dialog.open();
},
_onPowerOffClicked: function() {
this.menu.itemActivated();
Main.overview.hide();
this._loginManager.listSessions(Lang.bind(this, function(result) {
let sessions = [];
let n = 0;
for (let i = 0; i < result.length; i++) {
let[id, uid, userName, seat, sessionPath] = result[i];
let proxy = new SystemdLoginSession(Gio.DBus.system,
'org.freedesktop.login1',
sessionPath);
if (proxy.Class != 'user')
continue;
if (proxy.State == 'closing')
continue;
if (proxy.Id == GLib.getenv('XDG_SESSION_ID'))
continue;
sessions.push({ user: this._userManager.get_user(userName),
username: userName,
info: { type: proxy.Type,
remote: proxy.Remote }
});
// limit the number of entries
n++;
if (n == MAX_USERS_IN_SESSION_DIALOG)
break;
}
if (n != 0)
this._openSessionWarnDialog(sessions);
else
this._session.ShutdownRemote();
}));
}
});

View File

@@ -9,7 +9,8 @@ const Signals = imports.signals;
const PanelMenu = imports.ui.panelMenu;
const PopupMenu = imports.ui.popupMenu;
const Slider = imports.ui.slider;
const VOLUME_ADJUSTMENT_STEP = 0.05; /* Volume adjustment step in % */
const VOLUME_NOTIFY_ID = 1;
@@ -29,25 +30,21 @@ function getMixerControl() {
const StreamSlider = new Lang.Class({
Name: 'StreamSlider',
_init: function(control) {
_init: function(control, title) {
this._control = control;
this.item = new PopupMenu.PopupBaseMenuItem({ activate: false });
this.item = new PopupMenu.PopupMenuSection();
this._slider = new Slider.Slider(0);
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._icon = new St.Icon({ style_class: 'popup-menu-icon' });
this.item.addActor(this._icon, { align: St.Align.MIDDLE });
this.item.addActor(this._slider.actor, { expand: true });
this.item.actor.connect('button-press-event', Lang.bind(this, function(actor, event) {
this._slider.startDragging(event);
}));
this.item.addMenuItem(this._title);
this.item.addMenuItem(this._slider);
this._stream = null;
this._shouldShow = true;
},
get stream() {
@@ -89,7 +86,8 @@ const StreamSlider = new Lang.Class({
_updateVisibility: function() {
let visible = this._shouldBeVisible();
this.item.actor.visible = visible;
this._title.actor.visible = visible;
this._slider.actor.visible = visible;
},
scroll: function(event) {
@@ -183,17 +181,11 @@ const OutputStreamSlider = new Lang.Class({
this._portChangedId = 0;
},
_updateSliderIcon: function() {
this._icon.icon_name = (this._hasHeadphones ?
'audio-headphones-symbolic' :
'audio-speakers-symbolic');
},
_portChanged: function() {
let hasHeadphones = this._findHeadphones(this._stream);
if (hasHeadphones != this._hasHeadphones) {
this._hasHeadphones = hasHeadphones;
this._updateSliderIcon();
this.emit('headphones-changed', this._hasHeadphones);
}
}
});
@@ -202,11 +194,10 @@ const InputStreamSlider = new Lang.Class({
Name: 'InputStreamSlider',
Extends: StreamSlider,
_init: function(control) {
this.parent(control);
_init: function(control, title) {
this.parent(control, title);
this._control.connect('stream-added', Lang.bind(this, this._maybeShowInput));
this._control.connect('stream-removed', Lang.bind(this, this._maybeShowInput));
this._icon.icon_name = 'audio-input-microphone-symbolic';
},
_connectStream: function(stream) {
@@ -254,13 +245,17 @@ const VolumeMenu = new Lang.Class({
this._control.connect('default-sink-changed', Lang.bind(this, this._readOutput));
this._control.connect('default-source-changed', Lang.bind(this, this._readInput));
this._output = new OutputStreamSlider(this._control);
/* 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);
this._input = new InputStreamSlider(this._control, _("Microphone"));
this.addMenuItem(this._input.item);
this.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
@@ -308,9 +303,18 @@ const Indicator = new Lang.Class({
this.actor.visible = (icon != null);
this.setIcon(icon);
}));
this._volumeMenu.connect('headphones-changed', Lang.bind(this, function(menu, value) {
this._headphoneIcon.visible = value;
}));
this._headphoneIcon = this.addIcon(new Gio.ThemedIcon({ name: 'audio-headphones-symbolic' }));
this._headphoneIcon.visible = false;
this.menu.addMenuItem(this._volumeMenu);
this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
this.menu.addSettingsAction(_("Sound Settings"), 'gnome-sound-panel.desktop');
this.actor.connect('scroll-event', Lang.bind(this, this._onScrollEvent));
},

View File

@@ -1,158 +0,0 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
const AccountsService = imports.gi.AccountsService;
const Atk = imports.gi.Atk;
const Clutter = imports.gi.Clutter;
const Gdm = imports.gi.Gdm;
const Gio = imports.gi.Gio;
const GLib = imports.gi.GLib;
const GnomeDesktop = imports.gi.GnomeDesktop;
const Gtk = imports.gi.Gtk;
const Lang = imports.lang;
const Signals = imports.signals;
const Shell = imports.gi.Shell;
const St = imports.gi.St;
const Layout = imports.ui.layout;
const Main = imports.ui.main;
const Panel = imports.ui.panel;
const Tweener = imports.ui.tweener;
const UserWidget = imports.ui.userWidget;
const AuthPrompt = imports.gdm.authPrompt;
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;
const UnlockDialog = new Lang.Class({
Name: 'UnlockDialog',
_init: function(parentActor) {
this.actor = new St.Widget({ accessible_role: Atk.Role.WINDOW,
style_class: 'login-dialog',
visible: false });
this.actor.add_constraint(new Layout.MonitorConstraint({ primary: true }));
parentActor.add_child(this.actor);
this._userManager = AccountsService.UserManager.get_default();
this._userName = GLib.get_user_name();
this._user = this._userManager.get_user(this._userName);
this._promptBox = new St.BoxLayout({ vertical: true });
this.actor.add_child(this._promptBox);
this._promptBox.add_constraint(new Clutter.AlignConstraint({ source: this.actor,
align_axis: Clutter.AlignAxis.BOTH,
factor: 0.5 }));
this._authPrompt = new AuthPrompt.AuthPrompt(new Gdm.Client(), AuthPrompt.AuthPromptMode.UNLOCK_ONLY);
this._authPrompt.connect('reset', Lang.bind(this, this._onReset));
this._authPrompt.setUser(this._user);
this._authPrompt.setPasswordChar('\u25cf');
this._authPrompt.nextButton.label = _("Unlock");
this._promptBox.add_child(this._authPrompt.actor);
this.allowCancel = false;
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._promptBox.add_child(this._otherUserButton);
} else {
this._otherUserButton = null;
}
this._authPrompt.begin({ userName: this._userName });
this._updateSensitivity(true);
Main.ctrlAltTabManager.addGroup(this.actor, _("Unlock Window"), 'dialog-password-symbolic');
this._idleMonitor = new GnomeDesktop.IdleMonitor();
this._idleWatchId = this._idleMonitor.add_idle_watch(IDLE_TIMEOUT * 1000, Lang.bind(this, this._escape));
},
_updateSensitivity: function(sensitive) {
this._authPrompt.updateSensitivity(sensitive);
if (this._otherUserButton) {
this._otherUserButton.reactive = sensitive;
this._otherUserButton.can_focus = sensitive;
}
},
_onReset: function() {
this.emit('failed');
},
_escape: function() {
if (this.allowCancel) {
this._authPrompt.cancel();
this.emit('failed');
}
},
_otherUserClicked: function(button, event) {
Gdm.goto_login_session_sync(null);
this._authPrompt.cancel();
},
destroy: function() {
this.popModal();
this.actor.destroy();
if (this._idleWatchId) {
this._idleMonitor.remove_watch(this._idleWatchId);
this._idleWatchId = 0;
}
},
cancel: function() {
this._authPrompt.cancel();
this.destroy();
},
addCharacter: function(unichar) {
this._authPrompt.addCharacter(unichar);
},
finish: function(onComplete) {
this._authPrompt.finish(onComplete);
},
open: function(timestamp) {
this.actor.show();
if (this._isModal)
return true;
if (!Main.pushModal(this.actor, { timestamp: timestamp,
keybindingMode: Shell.KeyBindingMode.UNLOCK_SCREEN }))
return false;
this._isModal = true;
return true;
},
popModal: function(timestamp) {
if (this._isModal) {
Main.popModal(this.actor, timestamp);
this._isModal = false;
}
}
});
Signals.addSignalMethods(UnlockDialog.prototype);

52
js/ui/userAvatar.js Normal file
View File

@@ -0,0 +1,52 @@
// -*- 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 St = imports.gi.St;
const Params = imports.misc.params;
const DIALOG_ICON_SIZE = 64;
// Adapted from gdm/gui/user-switch-applet/applet.c
//
// Copyright (C) 2004-2005 James M. Cape <jcape@ignore-your.tv>.
// Copyright (C) 2008,2009 Red Hat, Inc.
const UserAvatar = new Lang.Class({
Name: 'UserAvatar',
_init: function(user, params) {
this._user = user;
params = Params.parse(params, { reactive: false,
iconSize: DIALOG_ICON_SIZE,
styleClass: 'status-chooser-user-icon' });
this._iconSize = params.iconSize;
this.actor = new St.Bin({ style_class: params.styleClass,
track_hover: params.reactive,
reactive: params.reactive });
},
setSensitive: function(sensitive) {
this.actor.can_focus = sensitive;
this.actor.reactive = sensitive;
},
update: function() {
let iconFile = this._user.get_icon_file();
if (iconFile && !GLib.file_test(iconFile, GLib.FileTest.EXISTS))
iconFile = null;
if (iconFile) {
let file = Gio.File.new_for_path(iconFile);
this.actor.child = null;
this.actor.style = 'background-image: url("%s");'.format(iconFile);
} else {
this.actor.style = null;
this.actor.child = new St.Icon({ icon_name: 'avatar-default-symbolic',
icon_size: this._iconSize });
}
}
});

957
js/ui/userMenu.js Normal file
View File

@@ -0,0 +1,957 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
const AccountsService = imports.gi.AccountsService;
const Gdm = imports.gi.Gdm;
const Gio = imports.gi.Gio;
const GLib = imports.gi.GLib;
const Gtk = imports.gi.Gtk;
const Lang = imports.lang;
const Pango = imports.gi.Pango;
const Shell = imports.gi.Shell;
const St = imports.gi.St;
const Tp = imports.gi.TelepathyGLib;
const Atk = imports.gi.Atk;
const Clutter = imports.gi.Clutter;
const BoxPointer = imports.ui.boxpointer;
const GnomeSession = imports.misc.gnomeSession;
const LoginManager = imports.misc.loginManager;
const Main = imports.ui.main;
const ModalDialog = imports.ui.modalDialog;
const PanelMenu = imports.ui.panelMenu;
const PopupMenu = imports.ui.popupMenu;
const Params = imports.misc.params;
const UserAvatar = imports.ui.userAvatar;
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 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;
const MAX_USERS_IN_SESSION_DIALOG = 5;
const IMStatus = {
AVAILABLE: 0,
BUSY: 1,
HIDDEN: 2,
AWAY: 3,
IDLE: 4,
OFFLINE: 5,
LAST: 6
};
const SystemdLoginSessionIface = <interface name='org.freedesktop.login1.Session'>
<property name="Id" type="s" access="read"/>
<property name="Remote" type="b" access="read"/>
<property name="Class" type="s" access="read"/>
<property name="Type" type="s" access="read"/>
<property name="State" type="s" access="read"/>
</interface>;
const SystemdLoginSession = Gio.DBusProxy.makeProxyWrapper(SystemdLoginSessionIface);
const IMStatusItem = new Lang.Class({
Name: 'IMStatusItem',
Extends: PopupMenu.PopupBaseMenuItem,
_init: function(label, iconName) {
this.parent();
this.actor.add_style_class_name('status-chooser-status-item');
this._icon = new St.Icon({ style_class: 'popup-menu-icon' });
this.addActor(this._icon);
if (iconName)
this._icon.icon_name = iconName;
this.label = new St.Label({ text: label });
this.actor.label_actor = this.label;
this.addActor(this.label);
}
});
const IMUserNameItem = new Lang.Class({
Name: 'IMUserNameItem',
Extends: PopupMenu.PopupBaseMenuItem,
_init: function() {
this.parent({ reactive: false,
can_focus: false,
style_class: 'status-chooser-user-name' });
this._wrapper = new Shell.GenericContainer();
this._wrapper.connect('get-preferred-width',
Lang.bind(this, this._wrapperGetPreferredWidth));
this._wrapper.connect('get-preferred-height',
Lang.bind(this, this._wrapperGetPreferredHeight));
this._wrapper.connect('allocate',
Lang.bind(this, this._wrapperAllocate));
this.addActor(this._wrapper, { expand: true, span: -1 });
this.label = new St.Label();
this.label.clutter_text.set_line_wrap(true);
this.label.clutter_text.set_ellipsize(Pango.EllipsizeMode.NONE);
this._wrapper.add_actor(this.label);
},
_wrapperGetPreferredWidth: function(actor, forHeight, alloc) {
alloc.min_size = 1;
alloc.natural_size = 1;
},
_wrapperGetPreferredHeight: function(actor, forWidth, alloc) {
[alloc.min_size, alloc.natural_size] = this.label.get_preferred_height(forWidth);
},
_wrapperAllocate: function(actor, box, flags) {
this.label.allocate(box, flags);
}
});
const IMStatusChooserItem = new Lang.Class({
Name: 'IMStatusChooserItem',
Extends: PopupMenu.PopupBaseMenuItem,
_init: function() {
this.parent({ reactive: false,
can_focus: false,
style_class: 'status-chooser' });
this._userManager = AccountsService.UserManager.get_default();
this._user = this._userManager.get_user(GLib.get_user_name());
this._avatar = new UserAvatar.UserAvatar(this._user, { reactive: true });
this._iconBin = new St.Button({ child: this._avatar.actor });
this.addActor(this._iconBin);
this._iconBin.connect('clicked', Lang.bind(this,
function() {
this.activate();
}));
this._section = new PopupMenu.PopupMenuSection();
this.addActor(this._section.actor);
this._name = new IMUserNameItem();
this._section.addMenuItem(this._name);
this._combo = new PopupMenu.PopupComboBoxMenuItem({ style_class: 'status-chooser-combo' });
this._section.addMenuItem(this._combo);
let item;
item = new IMStatusItem(_("Available"), 'user-available-symbolic');
this._combo.addMenuItem(item, IMStatus.AVAILABLE);
item = new IMStatusItem(_("Busy"), 'user-busy-symbolic');
this._combo.addMenuItem(item, IMStatus.BUSY);
item = new IMStatusItem(_("Invisible"), 'user-invisible-symbolic');
this._combo.addMenuItem(item, IMStatus.HIDDEN);
item = new IMStatusItem(_("Away"), 'user-away-symbolic');
this._combo.addMenuItem(item, IMStatus.AWAY);
item = new IMStatusItem(_("Idle"), 'user-idle-symbolic');
this._combo.addMenuItem(item, IMStatus.IDLE);
item = new IMStatusItem(_("Offline"), 'user-offline-symbolic');
this._combo.addMenuItem(item, IMStatus.OFFLINE);
this._combo.connect('active-item-changed',
Lang.bind(this, this._changeIMStatus));
this._presence = new GnomeSession.Presence();
this._presence.connectSignal('StatusChanged', Lang.bind(this, function(proxy, senderName, [status]) {
this._sessionStatusChanged(status);
}));
this._sessionPresenceRestored = false;
this._imPresenceRestored = false;
this._currentPresence = undefined;
this._accountMgr = Tp.AccountManager.dup();
this._accountMgr.connect('most-available-presence-changed',
Lang.bind(this, this._IMStatusChanged));
this._accountMgr.connect('account-enabled',
Lang.bind(this, this._IMAccountsChanged));
this._accountMgr.connect('account-disabled',
Lang.bind(this, this._IMAccountsChanged));
this._accountMgr.connect('account-removed',
Lang.bind(this, this._IMAccountsChanged));
this._accountMgr.connect('account-validity-changed',
Lang.bind(this, this._IMAccountsChanged));
this._accountMgr.prepare_async(null, Lang.bind(this,
function(mgr) {
this._IMAccountsChanged(mgr);
if (this._networkMonitor.network_available)
this._restorePresence();
else
this._setComboboxPresence(Tp.ConnectionPresenceType.OFFLINE);
}));
this._networkMonitor = Gio.NetworkMonitor.get_default();
this._networkMonitor.connect('network-changed',
Lang.bind(this, function(monitor, available) {
this._IMAccountsChanged(this._accountMgr);
if (available && !this._imPresenceRestored)
this._restorePresence();
}));
this._userLoadedId = this._user.connect('notify::is-loaded',
Lang.bind(this,
this._updateUser));
this._userChangedId = this._user.connect('changed',
Lang.bind(this,
this._updateUser));
this.actor.connect('notify::mapped', Lang.bind(this, function() {
if (this.actor.mapped)
this._updateUser();
}));
this.connect('sensitive-changed', function(sensitive) {
this._avatar.setSensitive(sensitive);
});
},
_restorePresence: function() {
let [presence, status, msg] = this._accountMgr.get_most_available_presence();
let savedPresence = global.settings.get_int('saved-im-presence');
if (savedPresence == presence) {
this._IMStatusChanged(this._accountMgr, presence, status, msg);
} else {
this._setComboboxPresence(savedPresence);
status = this._statusForPresence(savedPresence);
msg = msg ? msg : '';
this._accountMgr.set_all_requested_presences(savedPresence, status, msg);
}
},
destroy: function() {
// clean up signal handlers
if (this._userLoadedId != 0) {
this._user.disconnect(this._userLoadedId);
this._userLoadedId = 0;
}
if (this._userChangedId != 0) {
this._user.disconnect(this._userChangedId);
this._userChangedId = 0;
}
this.parent();
},
// Override getColumnWidths()/setColumnWidths() to make the item
// independent from the overall column layout of the menu
getColumnWidths: function() {
return [];
},
setColumnWidths: function(widths) {
},
_updateUser: function() {
if (this._user.is_loaded)
this._name.label.set_text(this._user.get_real_name());
else
this._name.label.set_text("");
this._avatar.update();
},
_statusForPresence: function(presence) {
switch(presence) {
case Tp.ConnectionPresenceType.AVAILABLE:
return 'available';
case Tp.ConnectionPresenceType.BUSY:
return 'busy';
case Tp.ConnectionPresenceType.OFFLINE:
return 'offline';
case Tp.ConnectionPresenceType.HIDDEN:
return 'hidden';
case Tp.ConnectionPresenceType.AWAY:
return 'away';
case Tp.ConnectionPresenceType.EXTENDED_AWAY:
return 'xa';
default:
return 'unknown';
}
},
_IMAccountsChanged: function(mgr) {
let accounts = mgr.get_valid_accounts().filter(function(account) {
return account.enabled;
});
let sensitive = accounts.length > 0 && this._networkMonitor.network_available;
this._combo.setSensitive(sensitive);
},
_IMStatusChanged: function(accountMgr, presence, status, message) {
if (!this._imPresenceRestored)
this._imPresenceRestored = true;
if (presence == this._currentPresence)
return;
this._currentPresence = presence;
this._setComboboxPresence(presence);
if (!this._sessionPresenceRestored) {
this._sessionStatusChanged(this._presence.status);
return;
}
if (presence == Tp.ConnectionPresenceType.AVAILABLE)
this._presence.status = GnomeSession.PresenceStatus.AVAILABLE;
// We ignore the actual value of _expectedPresence and never safe
// the first presence change after an "automatic" change, assuming
// that it is the response to our request; this is to account for
// mission control falling back to "similar" presences if an account
// type does not implement the requested presence.
if (!this._expectedPresence)
global.settings.set_int('saved-im-presence', presence);
else
this._expectedPresence = undefined;
},
_setComboboxPresence: function(presence) {
let activatedItem;
if (presence == Tp.ConnectionPresenceType.AVAILABLE)
activatedItem = IMStatus.AVAILABLE;
else if (presence == Tp.ConnectionPresenceType.BUSY)
activatedItem = IMStatus.BUSY;
else if (presence == Tp.ConnectionPresenceType.HIDDEN)
activatedItem = IMStatus.HIDDEN;
else if (presence == Tp.ConnectionPresenceType.AWAY)
activatedItem = IMStatus.AWAY;
else if (presence == Tp.ConnectionPresenceType.EXTENDED_AWAY)
activatedItem = IMStatus.IDLE;
else
activatedItem = IMStatus.OFFLINE;
this._combo.setActiveItem(activatedItem);
for (let i = 0; i < IMStatus.LAST; i++) {
if (i == IMStatus.AVAILABLE || i == IMStatus.OFFLINE)
continue; // always visible
this._combo.setItemVisible(i, i == activatedItem);
}
},
_changeIMStatus: function(menuItem, id) {
let [presence, s, msg] = this._accountMgr.get_most_available_presence();
let newPresence, status;
if (id == IMStatus.AVAILABLE) {
newPresence = Tp.ConnectionPresenceType.AVAILABLE;
} else if (id == IMStatus.OFFLINE) {
newPresence = Tp.ConnectionPresenceType.OFFLINE;
} else
return;
status = this._statusForPresence(newPresence);
msg = msg ? msg : '';
this._accountMgr.set_all_requested_presences(newPresence, status, msg);
},
getIMPresenceForSessionStatus: function(sessionStatus) {
// Restore the last user-set presence when coming back from
// BUSY/IDLE (otherwise the last user-set presence matches
// the current one)
if (sessionStatus == GnomeSession.PresenceStatus.AVAILABLE)
return global.settings.get_int('saved-im-presence');
if (sessionStatus == GnomeSession.PresenceStatus.BUSY) {
// Only change presence if the current one is "more present" than
// busy, or if coming back from idle
if (this._currentPresence == Tp.ConnectionPresenceType.AVAILABLE ||
this._currentPresence == Tp.ConnectionPresenceType.EXTENDED_AWAY)
return Tp.ConnectionPresenceType.BUSY;
}
if (sessionStatus == GnomeSession.PresenceStatus.IDLE) {
// Only change presence if the current one is "more present" than
// idle
if (this._currentPresence != Tp.ConnectionPresenceType.OFFLINE &&
this._currentPresence != Tp.ConnectionPresenceType.HIDDEN)
return Tp.ConnectionPresenceType.EXTENDED_AWAY;
}
return this._currentPresence;
},
_sessionStatusChanged: function(sessionStatus) {
if (!this._imPresenceRestored)
return;
let savedStatus = global.settings.get_int('saved-session-presence');
if (!this._sessionPresenceRestored) {
// We should never save/restore a status other than AVAILABLE
// or BUSY
if (savedStatus != GnomeSession.PresenceStatus.AVAILABLE &&
savedStatus != GnomeSession.PresenceStatus.BUSY)
savedStatus = GnomeSession.PresenceStatus.AVAILABLE;
if (sessionStatus != savedStatus) {
this._presence.status = savedStatus;
return;
}
this._sessionPresenceRestored = true;
}
if ((sessionStatus == GnomeSession.PresenceStatus.AVAILABLE ||
sessionStatus == GnomeSession.PresenceStatus.BUSY) &&
savedStatus != sessionStatus)
global.settings.set_int('saved-session-presence', sessionStatus);
let [presence, s, msg] = this._accountMgr.get_most_available_presence();
let newPresence, status;
let newPresence = this.getIMPresenceForSessionStatus(sessionStatus);
if (!newPresence || newPresence == presence)
return;
status = this._statusForPresence(newPresence);
msg = msg ? msg : '';
this._expectedPresence = newPresence;
this._accountMgr.set_all_requested_presences(newPresence, status, msg);
}
});
const UserMenuButton = new Lang.Class({
Name: 'UserMenuButton',
Extends: PanelMenu.Button,
_init: function() {
this.parent(0.0);
this.actor.accessible_role = Atk.Role.MENU;
let box = new St.BoxLayout({ name: 'panelUserMenu' });
this.actor.add_actor(box);
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();
this._user = this._userManager.get_user(GLib.get_user_name());
this._presence = new GnomeSession.Presence();
this._session = new GnomeSession.SessionManager();
this._haveShutdown = true;
this._haveSuspend = true;
this._accountMgr = Tp.AccountManager.dup();
this._loginManager = LoginManager.getLoginManager();
this.actor.connect('destroy', Lang.bind(this, this._onDestroy));
this._iconBox = new St.Bin();
box.add(this._iconBox, { y_align: St.Align.MIDDLE, y_fill: false });
let textureCache = St.TextureCache.get_default();
this._offlineIcon = new St.Icon({ icon_name: 'user-offline-symbolic',
style_class: 'popup-menu-icon' });
this._availableIcon = new St.Icon({ icon_name: 'user-available-symbolic',
style_class: 'popup-menu-icon' });
this._busyIcon = new St.Icon({ icon_name: 'user-busy-symbolic',
style_class: 'popup-menu-icon' });
this._invisibleIcon = new St.Icon({ icon_name: 'user-invisible-symbolic',
style_class: 'popup-menu-icon' });
this._awayIcon = new St.Icon({ icon_name: 'user-away-symbolic',
style_class: 'popup-menu-icon' });
this._idleIcon = new St.Icon({ icon_name: 'user-idle-symbolic',
style_class: 'popup-menu-icon' });
this._pendingIcon = new St.Icon({ icon_name: 'user-status-pending-symbolic',
style_class: 'popup-menu-icon' });
this._lockedIcon = new St.Icon({ icon_name: 'changes-prevent-symbolic',
style_class: 'popup-menu-icon' });
this._accountMgr.connect('most-available-presence-changed',
Lang.bind(this, this._updatePresenceIcon));
this._accountMgr.connect('account-enabled',
Lang.bind(this, this._onAccountEnabled));
this._accountMgr.connect('account-removed',
Lang.bind(this, this._onAccountRemoved));
this._accountMgr.prepare_async(null, Lang.bind(this,
function(mgr) {
let [presence, s, msg] = mgr.get_most_available_presence();
this._updatePresenceIcon(mgr, presence, s, msg);
this._setupAccounts();
}));
this._name = new St.Label();
this.actor.label_actor = this._name;
box.add(this._name, { y_align: St.Align.MIDDLE, y_fill: false });
this._userLoadedId = this._user.connect('notify::is-loaded', Lang.bind(this, this._updateUserName));
this._userChangedId = this._user.connect('changed', Lang.bind(this, this._updateUserName));
this._updateUserName();
this._createSubMenu();
this._updateSwitch(this._presence.status);
this._presence.connectSignal('StatusChanged', Lang.bind(this, function (proxy, senderName, [status]) {
this._updateSwitch(status);
}));
this._userManager.connect('notify::is-loaded',
Lang.bind(this, this._updateMultiUser));
this._userManager.connect('notify::has-multiple-users',
Lang.bind(this, this._updateMultiUser));
this._userManager.connect('user-added',
Lang.bind(this, this._updateMultiUser));
this._userManager.connect('user-removed',
Lang.bind(this, this._updateMultiUser));
this._lockdownSettings.connect('changed::' + DISABLE_USER_SWITCH_KEY,
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));
global.settings.connect('changed::' + ALWAYS_SHOW_LOG_OUT_KEY,
Lang.bind(this, this._updateLogout));
this._screenSaverSettings.connect('changed::' + SHOW_FULL_NAME_IN_TOP_BAR_KEY,
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();
this._updatesFile = Gio.File.new_for_path('/var/lib/PackageKit/prepared-update');
this._updatesMonitor = this._updatesFile.monitor(Gio.FileMonitorFlags.NONE, null);
this._updatesMonitor.connect('changed', Lang.bind(this, this._updateInstallUpdates));
// Whether shutdown is available or not depends on both lockdown
// settings (disable-log-out) and Polkit policy - the latter doesn't
// notify, so we update the menu item each time the menu opens or
// the lockdown setting changes, which should be close enough.
this.menu.connect('open-state-changed', Lang.bind(this,
function(menu, open) {
if (!open)
return;
this._updateHaveShutdown();
this._updateHaveSuspend();
}));
this._lockdownSettings.connect('changed::' + DISABLE_LOG_OUT_KEY,
Lang.bind(this, this._updateHaveShutdown));
Main.sessionMode.connect('updated', Lang.bind(this, this._sessionUpdated));
if (Main.screenShield)
Main.screenShield.connect('locked-changed', Lang.bind(this, this._updatePresenceIcon));
this._sessionUpdated();
},
_sessionUpdated: function() {
this.actor.visible = !Main.sessionMode.isGreeter;
let allowSettings = Main.sessionMode.allowSettings;
this._statusChooser.setSensitive(allowSettings);
this._systemSettings.visible = allowSettings;
this.setSensitive(!Main.sessionMode.isLocked);
this._updatePresenceIcon();
this._updateUserName();
},
_onDestroy: function() {
this._user.disconnect(this._userLoadedId);
this._user.disconnect(this._userChangedId);
},
_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))
this._name.set_text(this._user.get_real_name());
else
this._name.set_text("");
},
_updateMultiUser: function() {
this._updateSwitchUser();
this._updateLogout();
},
_updateSwitchUser: function() {
let allowSwitch = !this._lockdownSettings.get_boolean(DISABLE_USER_SWITCH_KEY);
let multiUser = this._userManager.can_switch() && this._userManager.has_multiple_users;
this._loginScreenItem.actor.visible = allowSwitch && multiUser;
},
_updateLogout: function() {
let allowLogout = !this._lockdownSettings.get_boolean(DISABLE_LOG_OUT_KEY);
let alwaysShow = global.settings.get_boolean(ALWAYS_SHOW_LOG_OUT_KEY);
let systemAccount = this._user.system_account;
let localAccount = this._user.local_account;
let multiUser = this._userManager.has_multiple_users;
let multiSession = Gdm.get_session_ids().length > 1;
this._logoutItem.actor.visible = allowLogout && (alwaysShow || multiUser || multiSession || systemAccount || !localAccount);
},
_updateLockScreen: function() {
let allowLockScreen = !this._lockdownSettings.get_boolean(DISABLE_LOCK_SCREEN_KEY);
this._lockScreenItem.actor.visible = allowLockScreen && LoginManager.canLock();
},
_updateInstallUpdates: function() {
let haveUpdates = this._updatesFile.query_exists(null);
this._installUpdatesItem.actor.visible = haveUpdates && this._haveShutdown;
},
_updateHaveShutdown: function() {
this._session.CanShutdownRemote(Lang.bind(this,
function(result, error) {
if (!error) {
this._haveShutdown = result[0];
this._updateInstallUpdates();
this._updateSuspendOrPowerOff();
}
}));
},
_updateHaveSuspend: function() {
this._loginManager.canSuspend(Lang.bind(this,
function(result) {
this._haveSuspend = result;
this._updateSuspendOrPowerOff();
}));
},
_updateSuspendOrPowerOff: function() {
if (!this._suspendOrPowerOffItem)
return;
this._suspendOrPowerOffItem.actor.visible = this._haveShutdown || this._haveSuspend;
// If we can't power off show Suspend instead
// and disable the alt key
if (!this._haveShutdown) {
this._suspendOrPowerOffItem.updateText(_("Suspend"), null);
} else if (!this._haveSuspend) {
this._suspendOrPowerOffItem.updateText(_("Power Off"), null);
} else {
this._suspendOrPowerOffItem.updateText(_("Power Off"), _("Suspend"));
}
},
_updateSwitch: function(status) {
let active = status == GnomeSession.PresenceStatus.AVAILABLE;
this._notificationsSwitch.setToggleState(active);
},
_updatePresenceIcon: function(accountMgr, presence, status, message) {
if (Main.sessionMode.isLocked)
this._iconBox.child = this._lockedIcon;
else if (presence == Tp.ConnectionPresenceType.AVAILABLE)
this._iconBox.child = this._availableIcon;
else if (presence == Tp.ConnectionPresenceType.BUSY)
this._iconBox.child = this._busyIcon;
else if (presence == Tp.ConnectionPresenceType.HIDDEN)
this._iconBox.child = this._invisibleIcon;
else if (presence == Tp.ConnectionPresenceType.AWAY)
this._iconBox.child = this._awayIcon;
else if (presence == Tp.ConnectionPresenceType.EXTENDED_AWAY)
this._iconBox.child = this._idleIcon;
else
this._iconBox.child = this._offlineIcon;
if (Main.sessionMode.isLocked)
this._iconBox.visible = Main.screenShield.locked;
else
this._iconBox.visible = true;
},
_setupAccounts: function() {
let accounts = this._accountMgr.get_valid_accounts();
for (let i = 0; i < accounts.length; i++) {
accounts[i]._changingId = accounts[i].connect('notify::connection-status',
Lang.bind(this, this._updateChangingPresence));
}
this._updateChangingPresence();
},
_onAccountEnabled: function(accountMgr, account) {
if (!account._changingId)
account._changingId = account.connect('notify::connection-status',
Lang.bind(this, this._updateChangingPresence));
this._updateChangingPresence();
},
_onAccountRemoved: function(accountMgr, account) {
if (account._changingId) {
account.disconnect(account._changingId);
account._changingId = 0;
}
this._updateChangingPresence();
},
_updateChangingPresence: function() {
let accounts = this._accountMgr.get_valid_accounts();
let changing = false;
for (let i = 0; i < accounts.length; i++) {
if (accounts[i].connection_status == Tp.ConnectionStatus.CONNECTING) {
changing = true;
break;
}
}
if (changing) {
this._iconBox.child = this._pendingIcon;
} else {
let [presence, s, msg] = this._accountMgr.get_most_available_presence();
this._updatePresenceIcon(this._accountMgr, presence, s, msg);
}
},
_createSubMenu: function() {
let item;
item = new IMStatusChooserItem();
item.connect('activate', Lang.bind(this, this._onMyAccountActivate));
this.menu.addMenuItem(item);
this._statusChooser = item;
item = new PopupMenu.PopupSwitchMenuItem(_("Notifications"));
item.connect('toggled', Lang.bind(this, this._updatePresenceStatus));
this.menu.addMenuItem(item);
this._notificationsSwitch = item;
item = new PopupMenu.PopupSeparatorMenuItem();
this.menu.addMenuItem(item);
item = new PopupMenu.PopupMenuItem(_("Settings"));
item.connect('activate', Lang.bind(this, this._onPreferencesActivate));
this.menu.addMenuItem(item);
this._systemSettings = item;
item = new PopupMenu.PopupSeparatorMenuItem();
this.menu.addMenuItem(item);
item = new PopupMenu.PopupMenuItem(_("Switch User"));
item.connect('activate', Lang.bind(this, this._onLoginScreenActivate));
this.menu.addMenuItem(item);
this._loginScreenItem = item;
item = new PopupMenu.PopupMenuItem(_("Log Out"));
item.connect('activate', Lang.bind(this, this._onQuitSessionActivate));
this.menu.addMenuItem(item);
this._logoutItem = item;
item = new PopupMenu.PopupMenuItem(_("Lock"));
item.connect('activate', Lang.bind(this, this._onLockScreenActivate));
this.menu.addMenuItem(item);
this._lockScreenItem = item;
item = new PopupMenu.PopupSeparatorMenuItem();
this.menu.addMenuItem(item);
item = new PopupMenu.PopupAlternatingMenuItem(_("Power Off"),
_("Suspend"));
this.menu.addMenuItem(item);
item.connect('activate', Lang.bind(this, this._onSuspendOrPowerOffActivate));
this._suspendOrPowerOffItem = item;
this._updateSuspendOrPowerOff();
item = new PopupMenu.PopupMenuItem(_("Install Updates & Restart"));
item.connect('activate', Lang.bind(this, this._onInstallUpdatesActivate));
this.menu.addMenuItem(item);
this._installUpdatesItem = item;
},
_updatePresenceStatus: function(item, event) {
let status;
if (item.state) {
status = GnomeSession.PresenceStatus.AVAILABLE;
} else {
status = GnomeSession.PresenceStatus.BUSY;
let [presence, s, msg] = this._accountMgr.get_most_available_presence();
let newPresence = this._statusChooser.getIMPresenceForSessionStatus(status);
if (newPresence != presence &&
newPresence == Tp.ConnectionPresenceType.BUSY)
Main.notify(_("Your chat status will be set to busy"),
_("Notifications are now disabled, including chat messages. Your online status has been adjusted to let others know that you might not see their messages."));
}
this._presence.status = status;
},
_onMyAccountActivate: function() {
Main.overview.hide();
let app = Shell.AppSystem.get_default().lookup_app('gnome-user-accounts-panel.desktop');
app.activate();
},
_onPreferencesActivate: function() {
Main.overview.hide();
let app = Shell.AppSystem.get_default().lookup_app('gnome-control-center.desktop');
app.activate();
},
_onLockScreenActivate: function() {
this.menu.close(BoxPointer.PopupAnimation.NONE);
Main.overview.hide();
Main.screenShield.lock(true);
},
_onLoginScreenActivate: function() {
this.menu.close(BoxPointer.PopupAnimation.NONE);
Main.overview.hide();
if (Main.screenShield)
Main.screenShield.lock(false);
Gdm.goto_login_session_sync(null);
},
_onQuitSessionActivate: function() {
Main.overview.hide();
this._session.LogoutRemote(0);
},
_onInstallUpdatesActivate: function() {
Main.overview.hide();
Util.spawn(['pkexec', '/usr/libexec/pk-trigger-offline-update']);
this._session.RebootRemote();
},
_openSessionWarnDialog: function(sessions) {
let dialog = new ModalDialog.ModalDialog();
let subjectLabel = new St.Label({ style_class: 'end-session-dialog-subject',
text: _("Other users are logged in.") });
dialog.contentLayout.add(subjectLabel, { y_fill: true,
y_align: St.Align.START });
let descriptionLabel = new St.Label({ style_class: 'end-session-dialog-description'});
descriptionLabel.set_text(_("Shutting down might cause them to lose unsaved work."));
descriptionLabel.clutter_text.line_wrap = true;
dialog.contentLayout.add(descriptionLabel, { x_fill: true,
y_fill: true,
y_align: St.Align.START });
let scrollView = new St.ScrollView({ style_class: 'end-session-dialog-app-list' });
scrollView.add_style_class_name('vfade');
scrollView.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC);
dialog.contentLayout.add(scrollView, { x_fill: true, y_fill: true });
let userList = new St.BoxLayout({ vertical: true });
scrollView.add_actor(userList);
for (let i = 0; i < sessions.length; i++) {
let session = sessions[i];
let userEntry = new St.BoxLayout({ style_class: 'login-dialog-user-list-item',
vertical: false });
let avatar = new UserAvatar.UserAvatar(session.user);
avatar.update();
userEntry.add(avatar.actor);
let userLabelText = "";;
let userName = session.user.get_real_name() ?
session.user.get_real_name() : session.username;
if (session.info.remote)
/* Translators: Remote here refers to a remote session, like a ssh login */
userLabelText = _("%s (remote)").format(userName);
else if (session.info.type == "tty")
/* Translators: Console here refers to a tty like a VT console */
userLabelText = _("%s (console)").format(userName);
else
userLabelText = userName;
let textLayout = new St.BoxLayout({ style_class: 'login-dialog-user-list-item-text-box',
vertical: true });
textLayout.add(new St.Label({ text: userLabelText }),
{ y_fill: false,
y_align: St.Align.MIDDLE,
expand: true });
userEntry.add(textLayout, { expand: true });
userList.add(userEntry, { x_fill: true });
}
let cancelButton = { label: _("Cancel"),
action: function() { dialog.close(); },
key: Clutter.Escape };
let powerOffButton = { label: _("Power Off"), action: Lang.bind(this, function() {
dialog.close();
this._session.ShutdownRemote();
}), default: true };
dialog.setButtons([cancelButton, powerOffButton]);
dialog.open();
},
_onSuspendOrPowerOffActivate: function() {
Main.overview.hide();
if (this._haveShutdown &&
this._suspendOrPowerOffItem.state == PopupMenu.PopupAlternatingMenuItemState.DEFAULT) {
this._loginManager.listSessions(Lang.bind(this,
function(result) {
let sessions = [];
let n = 0;
for (let i = 0; i < result.length; i++) {
let[id, uid, userName, seat, sessionPath] = result[i];
let proxy = new SystemdLoginSession(Gio.DBus.system,
'org.freedesktop.login1',
sessionPath);
if (proxy.Class != 'user')
continue;
if (proxy.State == 'closing')
continue;
if (proxy.Id == GLib.getenv('XDG_SESSION_ID'))
continue;
sessions.push({ user: this._userManager.get_user(userName),
username: userName,
info: { type: proxy.Type,
remote: proxy.Remote }
});
// limit the number of entries
n++;
if (n == MAX_USERS_IN_SESSION_DIALOG)
break;
}
if (n != 0)
this._openSessionWarnDialog(sessions);
else
this._session.ShutdownRemote();
}));
} else {
this.menu.close(BoxPointer.PopupAnimation.NONE);
this._loginManager.suspend();
}
}
});

View File

@@ -3,56 +3,10 @@
//
// A widget showing the user avatar and name
const AccountsService = imports.gi.AccountsService;
const GLib = imports.gi.GLib;
const Gio = imports.gi.Gio;
const Lang = imports.lang;
const St = imports.gi.St;
const Params = imports.misc.params;
const AVATAR_ICON_SIZE = 64;
// Adapted from gdm/gui/user-switch-applet/applet.c
//
// Copyright (C) 2004-2005 James M. Cape <jcape@ignore-your.tv>.
// Copyright (C) 2008,2009 Red Hat, Inc.
const Avatar = new Lang.Class({
Name: 'Avatar',
_init: function(user, params) {
this._user = user;
params = Params.parse(params, { reactive: false,
iconSize: AVATAR_ICON_SIZE,
styleClass: 'framed-user-icon' });
this._iconSize = params.iconSize;
this.actor = new St.Bin({ style_class: params.styleClass,
track_hover: params.reactive,
reactive: params.reactive });
},
setSensitive: function(sensitive) {
this.actor.can_focus = sensitive;
this.actor.reactive = sensitive;
},
update: function() {
let iconFile = this._user.get_icon_file();
if (iconFile && !GLib.file_test(iconFile, GLib.FileTest.EXISTS))
iconFile = null;
if (iconFile) {
let file = Gio.File.new_for_path(iconFile);
this.actor.child = null;
this.actor.style = 'background-image: url("%s");'.format(iconFile);
} else {
this.actor.style = null;
this.actor.child = new St.Icon({ icon_name: 'avatar-default-symbolic',
icon_size: this._iconSize });
}
}
});
const UserAvatar = imports.ui.userAvatar;
const UserWidget = new Lang.Class({
Name: 'UserWidget',
@@ -64,7 +18,7 @@ const UserWidget = new Lang.Class({
vertical: false });
this.actor.connect('destroy', Lang.bind(this, this._onDestroy));
this._avatar = new Avatar(user);
this._avatar = new UserAvatar.UserAvatar(user);
this.actor.add(this._avatar.actor,
{ x_fill: true, y_fill: true });

View File

@@ -93,8 +93,8 @@ const WorkspaceTracker = new Lang.Class({
global.screen.connect('window-left-monitor', Lang.bind(this, this._windowLeftMonitor));
global.screen.connect('restacked', Lang.bind(this, this._windowsRestacked));
this._workspaceSettings = new Gio.Settings({ schema: Main.dynamicWorkspacesSchema });
this._workspaceSettings.connect('changed::dynamic-workspaces', Lang.bind(this, this._queueCheckWorkspaces));
this._overrideSettings = new Gio.Settings({ schema: 'org.gnome.shell.overrides' });
this._overrideSettings.connect('changed::dynamic-workspaces', Lang.bind(this, this._queueCheckWorkspaces));
this._nWorkspacesChanged();
},
@@ -473,20 +473,12 @@ const WindowManager = new Lang.Class({
this._dimWindow(this._dimmedWindows[i]);
}));
if (Main.sessionMode.hasWorkspaces)
this._workspaceTracker = new WorkspaceTracker(this);
this._workspaceTracker = new WorkspaceTracker(this);
global.screen.override_workspace_layout(Meta.ScreenCorner.TOPLEFT,
false, -1, 1);
},
keepWorkspaceAlive: function(workspace, duration) {
if (!this._workspaceTracker)
return;
this._workspaceTracker.keepWorkspaceAlive(workspace, duration);
},
setCustomKeybindingHandler: function(name, modes, handler) {
if (Meta.keybindings_set_custom_handler(name, handler))
this.allowKeybinding(name, modes);
@@ -833,7 +825,7 @@ const WindowManager = new Lang.Class({
},
_switchWorkspace : function(shellwm, from, to, direction) {
if (!Main.sessionMode.hasWorkspaces || !this._shouldAnimate()) {
if (!this._shouldAnimate()) {
shellwm.completed_switch_workspace();
return;
}
@@ -986,9 +978,6 @@ const WindowManager = new Lang.Class({
},
_showWorkspaceSwitcher : function(display, screen, window, binding) {
if (!Main.sessionMode.hasWorkspaces)
return;
if (screen.n_workspaces == 1)
return;
@@ -1030,19 +1019,14 @@ const WindowManager = new Lang.Class({
},
actionMoveWorkspace: function(workspace) {
if (!Main.sessionMode.hasWorkspaces)
return;
let activeWorkspace = global.screen.get_active_workspace();
if (activeWorkspace != workspace)
workspace.activate(global.get_current_time());
},
actionMoveWindow: function(window, workspace) {
if (!Main.sessionMode.hasWorkspaces)
return;
let activeWorkspace = global.screen.get_active_workspace();
if (activeWorkspace != workspace) {
@@ -1055,5 +1039,6 @@ const WindowManager = new Lang.Class({
global.display.clear_mouse_mode();
workspace.activate_with_focus (window, global.get_current_time());
}
},
});

View File

@@ -127,7 +127,7 @@ const WindowClone = new Lang.Class({
if (this._stackAbove == null)
return null;
if (this.inDrag) {
if (this.inDrag || this._zooming) {
if (this._stackAbove._delegate)
return this._stackAbove._delegate.getActualStackAbove();
else
@@ -997,7 +997,7 @@ const Workspace = new Lang.Class({
this._dropRect.set_position(geom.x, geom.y);
this._dropRect.set_size(geom.width, geom.height);
this._updateWindowPositions(Main.overview.animationInProgress ? WindowPositionFlags.ANIMATE : WindowPositionFlags.NONE);
this._updateWindowPositions(WindowPositionFlags.NONE);
this._actualGeometryLater = 0;
return false;

View File

@@ -764,8 +764,8 @@ const ThumbnailsBox = new Lang.Class({
// to open its first window within some time, as tracked by Shell.WindowTracker.
// Here, we only add a very brief timeout to avoid the _immediate_ removal of the
// workspace while we wait for the startup sequence to load.
Main.wm.keepWorkspaceAlive(global.screen.get_workspace_by_index(newWorkspaceIndex),
WORKSPACE_KEEP_ALIVE_TIME);
Main.keepWorkspaceAlive(global.screen.get_workspace_by_index(newWorkspaceIndex),
WORKSPACE_KEEP_ALIVE_TIME);
}
// Start the animation on the workspace (which is actually

View File

@@ -7,7 +7,6 @@ data/gnome-shell.desktop.in.in
data/gnome-shell-extension-prefs.desktop.in.in
data/org.gnome.shell.gschema.xml.in.in
js/extensionPrefs/main.js
js/gdm/authPrompt.js
js/gdm/loginDialog.js
js/gdm/powerMenu.js
js/gdm/util.js
@@ -49,9 +48,9 @@ js/ui/status/keyboard.js
js/ui/status/lockScreenMenu.js
js/ui/status/network.js
js/ui/status/power.js
js/ui/status/system.js
js/ui/status/volume.js
js/ui/unlockDialog.js
js/ui/userMenu.js
js/ui/viewSelector.js
js/ui/wanda.js
js/ui/windowAttentionHandler.js

777
po/bg.po

File diff suppressed because it is too large Load Diff

691
po/cs.po

File diff suppressed because it is too large Load Diff

926
po/de.po

File diff suppressed because it is too large Load Diff

674
po/es.po

File diff suppressed because it is too large Load Diff

572
po/gl.po

File diff suppressed because it is too large Load Diff

588
po/id.po

File diff suppressed because it is too large Load Diff

615
po/it.po

File diff suppressed because it is too large Load Diff

573
po/ja.po

File diff suppressed because it is too large Load Diff

554
po/kk.po

File diff suppressed because it is too large Load Diff

353
po/nb.po
View File

@@ -8,8 +8,8 @@ msgid ""
msgstr ""
"Project-Id-Version: gnome-shell 3.9.x\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2013-07-18 15:29+0200\n"
"PO-Revision-Date: 2013-07-04 11:09+0200\n"
"POT-Creation-Date: 2013-05-28 09:43+0200\n"
"PO-Revision-Date: 2013-05-28 09:44+0200\n"
"Last-Translator: Kjartan Maraas <kmaraas@gnome.org>\n"
"Language-Team: Norwegian bokmål <i18n-nb@lister.ping.uio.no>\n"
"Language: \n"
@@ -331,41 +331,37 @@ msgstr "Utvidelse"
msgid "Select an extension to configure using the combobox above."
msgstr "Velg en utvidelse som skal konfigureres med komboboksen over."
#: ../js/gdm/loginDialog.js:308
msgid "Choose Session"
msgstr "Velg økt"
#: ../js/gdm/loginDialog.js:326
msgid "Session"
msgstr "Økt"
#: ../js/gdm/loginDialog.js:371
msgid "Session"
msgstr "Økt …"
#. 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:533
#: ../js/gdm/loginDialog.js:601
msgid "Not listed?"
msgstr "Ikke listet?"
#: ../js/gdm/loginDialog.js:810 ../js/ui/components/networkAgent.js:137
#: ../js/gdm/loginDialog.js:776 ../js/ui/components/networkAgent.js:137
#: ../js/ui/components/polkitAgent.js:161 ../js/ui/endSessionDialog.js:376
#: ../js/ui/extensionDownloader.js:195 ../js/ui/shellMountOperation.js:399
#: ../js/ui/status/bluetooth.js:449 ../js/ui/unlockDialog.js:95
#: ../js/ui/userMenu.js:884
#: ../js/ui/status/bluetooth.js:415 ../js/ui/unlockDialog.js:96
#: ../js/ui/userMenu.js:938
msgid "Cancel"
msgstr "Avbryt"
#: ../js/gdm/loginDialog.js:833
#: ../js/gdm/loginDialog.js:791
msgctxt "button"
msgid "Sign In"
msgstr "Logg inn"
#: ../js/gdm/loginDialog.js:833
#: ../js/gdm/loginDialog.js:791
msgid "Next"
msgstr "Neste"
#. Translators: this message is shown below the username entry field
#. to clue the user in on how to login to the local network realm
#: ../js/gdm/loginDialog.js:934
#: ../js/gdm/loginDialog.js:888
#, c-format
msgid "(e.g., user or %s)"
msgstr "(f.eks. bruker eller %s)"
@@ -373,12 +369,12 @@ msgstr "(f.eks. bruker eller %s)"
#. 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:938 ../js/ui/components/networkAgent.js:260
#: ../js/gdm/loginDialog.js:892 ../js/ui/components/networkAgent.js:260
#: ../js/ui/components/networkAgent.js:278
msgid "Username: "
msgstr "Brukernavn: "
#: ../js/gdm/loginDialog.js:1205
#: ../js/gdm/loginDialog.js:1158
msgid "Login Window"
msgstr "Innloggingsvindu"
@@ -387,8 +383,8 @@ msgstr "Innloggingsvindu"
msgid "Power"
msgstr "Strøm"
#: ../js/gdm/powerMenu.js:93 ../js/ui/userMenu.js:651 ../js/ui/userMenu.js:655
#: ../js/ui/userMenu.js:768
#: ../js/gdm/powerMenu.js:93 ../js/ui/userMenu.js:696 ../js/ui/userMenu.js:700
#: ../js/ui/userMenu.js:816
msgid "Suspend"
msgstr "Hvilemodus"
@@ -396,8 +392,8 @@ msgstr "Hvilemodus"
msgid "Restart"
msgstr "Start på nytt"
#: ../js/gdm/powerMenu.js:103 ../js/ui/userMenu.js:653
#: ../js/ui/userMenu.js:655 ../js/ui/userMenu.js:767 ../js/ui/userMenu.js:888
#: ../js/gdm/powerMenu.js:103 ../js/ui/userMenu.js:698
#: ../js/ui/userMenu.js:700 ../js/ui/userMenu.js:815 ../js/ui/userMenu.js:942
msgid "Power Off"
msgstr "Slå av"
@@ -426,23 +422,23 @@ msgstr "Klarte ikke å lese kommando:"
msgid "Execution of '%s' failed:"
msgstr "Kjøring av «%s» feilet:"
#: ../js/ui/appDisplay.js:397
#: ../js/ui/appDisplay.js:361
msgid "Frequent"
msgstr "Ofte"
#: ../js/ui/appDisplay.js:404
#: ../js/ui/appDisplay.js:368
msgid "All"
msgstr "Alle"
#: ../js/ui/appDisplay.js:996
#: ../js/ui/appDisplay.js:960
msgid "New Window"
msgstr "Nytt vindu"
#: ../js/ui/appDisplay.js:999 ../js/ui/dash.js:284
#: ../js/ui/appDisplay.js:963 ../js/ui/dash.js:284
msgid "Remove from Favorites"
msgstr "Fjern fra favoritter"
#: ../js/ui/appDisplay.js:1000
#: ../js/ui/appDisplay.js:964
msgid "Add to Favorites"
msgstr "Legg til i favoritter"
@@ -456,7 +452,7 @@ msgstr "%s ble lagt til i dine favoritter."
msgid "%s has been removed from your favorites."
msgstr "%s ble fjernet fra dine favoritter."
#: ../js/ui/backgroundMenu.js:19 ../js/ui/userMenu.js:744
#: ../js/ui/backgroundMenu.js:19 ../js/ui/userMenu.js:789
msgid "Settings"
msgstr "Innstillinger"
@@ -581,35 +577,35 @@ msgid "S"
msgstr "Lø"
#. Translators: Text to show if there are no events
#: ../js/ui/calendar.js:750
#: ../js/ui/calendar.js:735
msgid "Nothing Scheduled"
msgstr "Ingenting planlagt"
#. Translators: Shown on calendar heading when selected day occurs on current year
#: ../js/ui/calendar.js:768
#: ../js/ui/calendar.js:751
msgctxt "calendar heading"
msgid "%A, %B %d"
msgstr "%A %B %d"
#. Translators: Shown on calendar heading when selected day occurs on different year
#: ../js/ui/calendar.js:771
#: ../js/ui/calendar.js:754
msgctxt "calendar heading"
msgid "%A, %B %d, %Y"
msgstr "%A %B %d, %Y"
#: ../js/ui/calendar.js:782
#: ../js/ui/calendar.js:764
msgid "Today"
msgstr "I dag"
#: ../js/ui/calendar.js:786
#: ../js/ui/calendar.js:768
msgid "Tomorrow"
msgstr "I morgen"
#: ../js/ui/calendar.js:797
#: ../js/ui/calendar.js:779
msgid "This week"
msgstr "Denne uken"
#: ../js/ui/calendar.js:805
#: ../js/ui/calendar.js:787
msgid "Next week"
msgstr "Neste uke"
@@ -798,14 +794,14 @@ msgstr "<b>%d</b> <b>%B</b> <b>%Y</b>, <b>%H.%M</b> "
#. Translators: this is the other person changing their old IM name to their new
#. IM name.
#: ../js/ui/components/telepathyClient.js:986
#: ../js/ui/components/telepathyClient.js:985
#, c-format
msgid "%s is now known as %s"
msgstr "%s er nå kjent som %s"
#. translators: argument is a room name like
#. * room@jabber.org for example.
#: ../js/ui/components/telepathyClient.js:1089
#: ../js/ui/components/telepathyClient.js:1088
#, c-format
msgid "Invitation to %s"
msgstr "Invitasjon til %s"
@@ -813,38 +809,38 @@ msgstr "Invitasjon til %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:1097
#: ../js/ui/components/telepathyClient.js:1096
#, c-format
msgid "%s is inviting you to join %s"
msgstr "%s inviterer deg til å bli med i %s"
#: ../js/ui/components/telepathyClient.js:1099
#: ../js/ui/components/telepathyClient.js:1138
#: ../js/ui/components/telepathyClient.js:1178
#: ../js/ui/components/telepathyClient.js:1241
#: ../js/ui/components/telepathyClient.js:1098
#: ../js/ui/components/telepathyClient.js:1137
#: ../js/ui/components/telepathyClient.js:1177
#: ../js/ui/components/telepathyClient.js:1240
msgid "Decline"
msgstr "Avslå"
#: ../js/ui/components/telepathyClient.js:1100
#: ../js/ui/components/telepathyClient.js:1179
#: ../js/ui/components/telepathyClient.js:1242
#: ../js/ui/components/telepathyClient.js:1099
#: ../js/ui/components/telepathyClient.js:1178
#: ../js/ui/components/telepathyClient.js:1241
msgid "Accept"
msgstr "Godta"
#. translators: argument is a contact name like Alice for example.
#: ../js/ui/components/telepathyClient.js:1130
#: ../js/ui/components/telepathyClient.js:1129
#, c-format
msgid "Video call from %s"
msgstr "Videosamtale fra %s"
#. translators: argument is a contact name like Alice for example.
#: ../js/ui/components/telepathyClient.js:1133
#: ../js/ui/components/telepathyClient.js:1132
#, c-format
msgid "Call from %s"
msgstr "Samtale fra %s"
#. translators: this is a button label (verb), not a noun
#: ../js/ui/components/telepathyClient.js:1140
#: ../js/ui/components/telepathyClient.js:1139
msgid "Answer"
msgstr "Svar"
@@ -853,110 +849,110 @@ msgstr "Svar"
#. * file name. The string will be something
#. * like: "Alice is sending you test.ogg"
#.
#: ../js/ui/components/telepathyClient.js:1172
#: ../js/ui/components/telepathyClient.js:1171
#, c-format
msgid "%s is sending you %s"
msgstr "%s sender deg %s"
#. To translators: The parameter is the contact's alias
#: ../js/ui/components/telepathyClient.js:1207
#: ../js/ui/components/telepathyClient.js:1206
#, c-format
msgid "%s would like permission to see when you are online"
msgstr "%s vil ha rettigheter til å se når du er tilkoblet"
#: ../js/ui/components/telepathyClient.js:1299
#: ../js/ui/components/telepathyClient.js:1298
msgid "Network error"
msgstr "Nettverksfeil"
#: ../js/ui/components/telepathyClient.js:1301
#: ../js/ui/components/telepathyClient.js:1300
msgid "Authentication failed"
msgstr "Autentisering feilet"
#: ../js/ui/components/telepathyClient.js:1303
#: ../js/ui/components/telepathyClient.js:1302
msgid "Encryption error"
msgstr "Feil ved kryptering"
#: ../js/ui/components/telepathyClient.js:1305
#: ../js/ui/components/telepathyClient.js:1304
msgid "Certificate not provided"
msgstr "Sertifikat ikke oppgitt"
#: ../js/ui/components/telepathyClient.js:1307
#: ../js/ui/components/telepathyClient.js:1306
msgid "Certificate untrusted"
msgstr "Stoler ikke på sertifikatet"
#: ../js/ui/components/telepathyClient.js:1309
#: ../js/ui/components/telepathyClient.js:1308
msgid "Certificate expired"
msgstr "Sertifikatet er utløpt"
#: ../js/ui/components/telepathyClient.js:1311
#: ../js/ui/components/telepathyClient.js:1310
msgid "Certificate not activated"
msgstr "Sertifikatet er ikke aktivert"
#: ../js/ui/components/telepathyClient.js:1313
#: ../js/ui/components/telepathyClient.js:1312
msgid "Certificate hostname mismatch"
msgstr "Feil vertsnavn for sertifikat"
#: ../js/ui/components/telepathyClient.js:1315
#: ../js/ui/components/telepathyClient.js:1314
msgid "Certificate fingerprint mismatch"
msgstr "Feil fingeravtrykk for sertifikat"
#: ../js/ui/components/telepathyClient.js:1317
#: ../js/ui/components/telepathyClient.js:1316
msgid "Certificate self-signed"
msgstr "Sertifikatet er selvsignert"
#: ../js/ui/components/telepathyClient.js:1319
#: ../js/ui/components/telepathyClient.js:1318
msgid "Status is set to offline"
msgstr "Status er satt til frakoblet"
#: ../js/ui/components/telepathyClient.js:1321
#: ../js/ui/components/telepathyClient.js:1320
msgid "Encryption is not available"
msgstr "Kryptering er ikke tilgjengelig"
#: ../js/ui/components/telepathyClient.js:1323
#: ../js/ui/components/telepathyClient.js:1322
msgid "Certificate is invalid"
msgstr "Sertifikatet er ugyldig"
#: ../js/ui/components/telepathyClient.js:1325
#: ../js/ui/components/telepathyClient.js:1324
msgid "Connection has been refused"
msgstr "Tilkobling ble nektet"
#: ../js/ui/components/telepathyClient.js:1327
#: ../js/ui/components/telepathyClient.js:1326
msgid "Connection can't be established"
msgstr "Tilkobling kan ikke etableres"
#: ../js/ui/components/telepathyClient.js:1329
#: ../js/ui/components/telepathyClient.js:1328
msgid "Connection has been lost"
msgstr "Tilkobling tapt"
#: ../js/ui/components/telepathyClient.js:1331
#: ../js/ui/components/telepathyClient.js:1330
msgid "This account is already connected to the server"
msgstr "Denne kontoen er allerede koblet til tjeneren"
#: ../js/ui/components/telepathyClient.js:1333
#: ../js/ui/components/telepathyClient.js:1332
msgid ""
"Connection has been replaced by a new connection using the same resource"
msgstr ""
"Tilkoblingen har blitt erstattet av en ny tilkobling som bruker samme ressurs"
#: ../js/ui/components/telepathyClient.js:1335
#: ../js/ui/components/telepathyClient.js:1334
msgid "The account already exists on the server"
msgstr "Kontoen eksisterer allerede på tjeneren"
#: ../js/ui/components/telepathyClient.js:1337
#: ../js/ui/components/telepathyClient.js:1336
msgid "Server is currently too busy to handle the connection"
msgstr "Tjener er for opptatt til å håndtere tilkoblingen"
#: ../js/ui/components/telepathyClient.js:1339
#: ../js/ui/components/telepathyClient.js:1338
msgid "Certificate has been revoked"
msgstr "Sertifikatet er tilbaketrukket"
#: ../js/ui/components/telepathyClient.js:1341
#: ../js/ui/components/telepathyClient.js:1340
msgid ""
"Certificate uses an insecure cipher algorithm or is cryptographically weak"
msgstr ""
"Sertifikatet bruker en usikker sifferalgoritme eller er krytografisk svakt"
#: ../js/ui/components/telepathyClient.js:1343
#: ../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"
@@ -964,22 +960,22 @@ msgstr ""
"Lengden eller dybden på tjenersertifikatet oversteg grensen som er satt i "
"kryptografibiblioteket"
#: ../js/ui/components/telepathyClient.js:1345
#: ../js/ui/components/telepathyClient.js:1344
msgid "Internal error"
msgstr "Intern feil"
#. translators: argument is the account name, like
#. * name@jabber.org for example.
#: ../js/ui/components/telepathyClient.js:1355
#: ../js/ui/components/telepathyClient.js:1354
#, c-format
msgid "Unable to connect to %s"
msgstr "Kan ikke koble til %s"
#: ../js/ui/components/telepathyClient.js:1360
#: ../js/ui/components/telepathyClient.js:1359
msgid "View account"
msgstr "Vis konto"
#: ../js/ui/components/telepathyClient.js:1399
#: ../js/ui/components/telepathyClient.js:1398
msgid "Unknown reason"
msgstr "Ukjent årsak"
@@ -993,26 +989,26 @@ msgstr "Vis programmer"
#. Translators: this is the name of the dock/favorites area on
#. the left of the overview
#: ../js/ui/dash.js:439
#: ../js/ui/dash.js:435
msgid "Dash"
msgstr "Favoritter"
#: ../js/ui/dateMenu.js:85
#: ../js/ui/dateMenu.js:86
msgid "Open Calendar"
msgstr "Åpne kalender"
#: ../js/ui/dateMenu.js:89
#: ../js/ui/dateMenu.js:90
msgid "Open Clocks"
msgstr "Åpne Klokker"
#: ../js/ui/dateMenu.js:96
#: ../js/ui/dateMenu.js:97
msgid "Date & Time Settings"
msgstr "Innstillinger for dato og klokkeslett"
#. 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:208
msgid "%A %B %e, %Y"
msgstr "%a %e %B, %Y"
@@ -1170,31 +1166,31 @@ msgstr "Vis kildekode"
msgid "Web Page"
msgstr "Nettside"
#: ../js/ui/messageTray.js:1241
#: ../js/ui/messageTray.js:1182
msgid "Open"
msgstr "Åpne"
#: ../js/ui/messageTray.js:1248
#: ../js/ui/messageTray.js:1189
msgid "Remove"
msgstr "Fjern"
#: ../js/ui/messageTray.js:1560
#: ../js/ui/messageTray.js:1501
msgid "Clear Messages"
msgstr "Tøm meldinger"
#: ../js/ui/messageTray.js:1587
#: ../js/ui/messageTray.js:1528
msgid "Notification Settings"
msgstr "Innstillinger for varsling"
#: ../js/ui/messageTray.js:1770
#: ../js/ui/messageTray.js:1707
msgid "No Messages"
msgstr "Ingen meldinger"
#: ../js/ui/messageTray.js:1842
#: ../js/ui/messageTray.js:1780
msgid "Message Tray"
msgstr "Meldingstrau"
#: ../js/ui/messageTray.js:2854
#: ../js/ui/messageTray.js:2805
msgid "System Information"
msgstr "Systeminformasjon"
@@ -1203,7 +1199,7 @@ msgctxt "program"
msgid "Unknown"
msgstr "Ukjent"
#: ../js/ui/overviewControls.js:474 ../js/ui/screenShield.js:150
#: ../js/ui/overviewControls.js:472 ../js/ui/screenShield.js:150
#, c-format
msgid "%d new message"
msgid_plural "%d new messages"
@@ -1226,17 +1222,17 @@ msgstr "Oversikt"
msgid "Type to search…"
msgstr "Skriv for å søke …"
#: ../js/ui/panel.js:567
#: ../js/ui/panel.js:642
msgid "Quit"
msgstr "Avslutt"
#. Translators: If there is no suitable word for "Activities"
#. in your language, you can use the word for "Overview".
#: ../js/ui/panel.js:618
#: ../js/ui/panel.js:693
msgid "Activities"
msgstr "Aktiviteter"
#: ../js/ui/panel.js:914
#: ../js/ui/panel.js:989
msgid "Top Bar"
msgstr "Topp-panel"
@@ -1245,7 +1241,7 @@ msgstr "Topp-panel"
#. "ON" and "OFF") or "toggle-switch-intl" (for toggle
#. switches containing "◯" and "|"). Other values will
#. simply result in invisible toggle switches.
#: ../js/ui/popupMenu.js:517
#: ../js/ui/popupMenu.js:738
msgid "toggle-switch-us"
msgstr "toggle-switch-intl"
@@ -1270,7 +1266,7 @@ msgid_plural "%d new notifications"
msgstr[0] "%d ny varsling"
msgstr[1] "%d nye varslinger"
#: ../js/ui/screenShield.js:449 ../js/ui/userMenu.js:759
#: ../js/ui/screenShield.js:449 ../js/ui/userMenu.js:807
msgid "Lock"
msgstr "Lås"
@@ -1285,19 +1281,19 @@ msgstr "GNOME må låse skjermen"
#.
#. XXX: another option is to kick the user into the gdm login
#. screen, where we're not affected by grabs
#: ../js/ui/screenShield.js:788 ../js/ui/screenShield.js:1216
#: ../js/ui/screenShield.js:773 ../js/ui/screenShield.js:1213
msgid "Unable to lock"
msgstr "Kan ikke låse"
#: ../js/ui/screenShield.js:789 ../js/ui/screenShield.js:1217
#: ../js/ui/screenShield.js:774 ../js/ui/screenShield.js:1214
msgid "Lock was blocked by an application"
msgstr "Låsing ble stoppet av et program"
#: ../js/ui/searchDisplay.js:445
#: ../js/ui/searchDisplay.js:453
msgid "Searching…"
msgstr "Søker …"
#: ../js/ui/searchDisplay.js:489
#: ../js/ui/searchDisplay.js:497
msgid "No results."
msgstr "Ingen resultater."
@@ -1325,7 +1321,7 @@ msgstr "Passord"
msgid "Remember Password"
msgstr "Husk passord"
#: ../js/ui/shellMountOperation.js:403 ../js/ui/unlockDialog.js:108
#: ../js/ui/shellMountOperation.js:403 ../js/ui/unlockDialog.js:109
msgid "Unlock"
msgstr "Lås opp"
@@ -1378,9 +1374,9 @@ msgid "Large Text"
msgstr "Stor tekst"
#: ../js/ui/status/bluetooth.js:28 ../js/ui/status/bluetooth.js:32
#: ../js/ui/status/bluetooth.js:290 ../js/ui/status/bluetooth.js:327
#: ../js/ui/status/bluetooth.js:355 ../js/ui/status/bluetooth.js:391
#: ../js/ui/status/bluetooth.js:422 ../js/ui/status/network.js:713
#: ../js/ui/status/bluetooth.js:289 ../js/ui/status/bluetooth.js:321
#: ../js/ui/status/bluetooth.js:357 ../js/ui/status/bluetooth.js:388
#: ../js/ui/status/network.js:739
msgid "Bluetooth"
msgstr "Bluetooth"
@@ -1401,106 +1397,97 @@ msgid "Bluetooth Settings"
msgstr "Innstillinger for Bluetooth"
#. TRANSLATORS: this means that bluetooth was disabled by hardware rfkill
#: ../js/ui/status/bluetooth.js:105 ../js/ui/status/network.js:140
#: ../js/ui/status/bluetooth.js:104 ../js/ui/status/network.js:142
msgid "hardware disabled"
msgstr "maskinvare slått av"
#: ../js/ui/status/bluetooth.js:198
#: ../js/ui/status/bluetooth.js:197
msgid "Connection"
msgstr "Tilkobling"
#: ../js/ui/status/bluetooth.js:209 ../js/ui/status/network.js:399
#: ../js/ui/status/bluetooth.js:208 ../js/ui/status/network.js:404
msgid "disconnecting..."
msgstr "kobler fra …"
#: ../js/ui/status/bluetooth.js:222 ../js/ui/status/network.js:405
#: ../js/ui/status/network.js:1298
#: ../js/ui/status/bluetooth.js:221 ../js/ui/status/network.js:410
#: ../js/ui/status/network.js:1343
msgid "connecting..."
msgstr "kobler til …"
#: ../js/ui/status/bluetooth.js:240
#: ../js/ui/status/bluetooth.js:239
msgid "Send Files…"
msgstr "Send filer …"
#: ../js/ui/status/bluetooth.js:247
#: ../js/ui/status/bluetooth.js:246
msgid "Keyboard Settings"
msgstr "Innstillinger for tastatur"
#: ../js/ui/status/bluetooth.js:250
#: ../js/ui/status/bluetooth.js:249
msgid "Mouse Settings"
msgstr "Innstillinger for mus"
#: ../js/ui/status/bluetooth.js:255 ../js/ui/status/volume.js:313
#: ../js/ui/status/bluetooth.js:254 ../js/ui/status/volume.js:316
msgid "Sound Settings"
msgstr "Innstillinger for lyd"
#: ../js/ui/status/bluetooth.js:328 ../js/ui/status/bluetooth.js:356
#: ../js/ui/status/bluetooth.js:322
#, c-format
msgid "Authorization request from %s"
msgstr "Forespørsel om autorisering fra %s"
#: ../js/ui/status/bluetooth.js:334 ../js/ui/status/bluetooth.js:399
#: ../js/ui/status/bluetooth.js:430
#, c-format
msgid "Device %s wants to pair with this computer"
msgstr "Enhet %s vil koble seg sammen med denne datamaskinen"
#: ../js/ui/status/bluetooth.js:336
msgid "Allow"
msgstr "Tillat"
#: ../js/ui/status/bluetooth.js:337
msgid "Deny"
msgstr "Nekt"
#: ../js/ui/status/bluetooth.js:362
#: ../js/ui/status/bluetooth.js:328
#, c-format
msgid "Device %s wants access to the service '%s'"
msgstr "Enhet %s vil ha tilgang til tjenesten «%s»"
#: ../js/ui/status/bluetooth.js:364
#: ../js/ui/status/bluetooth.js:330
msgid "Always grant access"
msgstr "Alltid gi tilgang"
#: ../js/ui/status/bluetooth.js:365
#: ../js/ui/status/bluetooth.js:331
msgid "Grant this time only"
msgstr "Gi tilgang kun denne ene gangen"
#: ../js/ui/status/bluetooth.js:366
#: ../js/ui/status/bluetooth.js:332
msgid "Reject"
msgstr "Avvis"
#. Translators: argument is the device short name
#: ../js/ui/status/bluetooth.js:393
#: ../js/ui/status/bluetooth.js:359
#, c-format
msgid "Pairing confirmation for %s"
msgstr "Bekreftelse for tilkobling for %s"
#: ../js/ui/status/bluetooth.js:400
#: ../js/ui/status/bluetooth.js:365 ../js/ui/status/bluetooth.js:396
#, c-format
msgid "Device %s wants to pair with this computer"
msgstr "Enhet %s vil koble seg sammen med denne datamaskinen"
#: ../js/ui/status/bluetooth.js:366
#, c-format
msgid ""
"Please confirm whether the Passkey '%06d' matches the one on the device."
msgstr "Vennligst bekreft om passord «%06d» er lik den som brukes på enheten."
#. Translators: this is the verb, not the noun
#: ../js/ui/status/bluetooth.js:403
#: ../js/ui/status/bluetooth.js:369
msgid "Matches"
msgstr "Stemmer overens"
#: ../js/ui/status/bluetooth.js:404
#: ../js/ui/status/bluetooth.js:370
msgid "Does not match"
msgstr "Stemmer ikke overens"
#: ../js/ui/status/bluetooth.js:423
#: ../js/ui/status/bluetooth.js:389
#, c-format
msgid "Pairing request for %s"
msgstr "Forespørsel om tilkobling for %s"
#: ../js/ui/status/bluetooth.js:431
#: ../js/ui/status/bluetooth.js:397
msgid "Please enter the PIN mentioned on the device."
msgstr "Vennligst oppgi PIN som oppgitt på enheten."
#: ../js/ui/status/bluetooth.js:448
#: ../js/ui/status/bluetooth.js:414
msgid "OK"
msgstr "OK"
@@ -1520,81 +1507,87 @@ msgstr "Volum, nettverk, batteri"
msgid "<unknown>"
msgstr "<ukjent>"
#: ../js/ui/status/network.js:125
#: ../js/ui/status/network.js:127
msgid "Wi-Fi"
msgstr "Wi-Fi"
#. Translators: this indicates that wireless or wwan is disabled by hardware killswitch
#: ../js/ui/status/network.js:162
#: ../js/ui/status/network.js:164
msgid "disabled"
msgstr "slått av"
#. Translators: this is for network devices that are physically present but are not
#. under NetworkManager's control (and thus cannot be used in the menu)
#: ../js/ui/status/network.js:397
#: ../js/ui/status/network.js:402
msgid "unmanaged"
msgstr "ikke håndtert"
#. Translators: this is for network connections that require some kind of key or password
#: ../js/ui/status/network.js:408 ../js/ui/status/network.js:1301
#: ../js/ui/status/network.js:413 ../js/ui/status/network.js:1346
msgid "authentication required"
msgstr "autentisering kreves"
#. Translators: this is for devices that require some kind of firmware or kernel
#. module, which is missing
#: ../js/ui/status/network.js:419
#: ../js/ui/status/network.js:423
msgid "firmware missing"
msgstr "fastvare mangler"
#. Translators: this is for wired network devices that are physically disconnected
#: ../js/ui/status/network.js:430
msgid "cable unplugged"
msgstr "kabel koblet fra"
#. Translators: this is for a network device that cannot be activated (for example it
#. is disabled by rfkill, or it has no coverage
#: ../js/ui/status/network.js:423
#: ../js/ui/status/network.js:435
msgid "unavailable"
msgstr "ikke tilgjengelig"
#: ../js/ui/status/network.js:425 ../js/ui/status/network.js:1303
#: ../js/ui/status/network.js:437 ../js/ui/status/network.js:1348
msgid "connection failed"
msgstr "tilkobling feilet"
#: ../js/ui/status/network.js:478 ../js/ui/status/network.js:1190
#: ../js/ui/status/network.js:490 ../js/ui/status/network.js:1236
#: ../js/ui/status/network.js:1424
msgid "More…"
msgstr "Mer …"
#. 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:506 ../js/ui/status/network.js:1142
#: ../js/ui/status/network.js:518 ../js/ui/status/network.js:1191
msgid "Connected (private)"
msgstr "Tilkoblet (privat)"
#: ../js/ui/status/network.js:572
#: ../js/ui/status/network.js:597
msgid "Wired"
msgstr "Kablet"
#: ../js/ui/status/network.js:592
#: ../js/ui/status/network.js:611
msgid "Mobile broadband"
msgstr "Mobilt bredbånd"
#: ../js/ui/status/network.js:1474
#: ../js/ui/status/network.js:1522
msgid "Enable networking"
msgstr "Slå på nettverk"
#: ../js/ui/status/network.js:1522
#: ../js/ui/status/network.js:1583
msgid "Network Settings"
msgstr "Innstillinger for nettverk"
#: ../js/ui/status/network.js:1539
#: ../js/ui/status/network.js:1600
msgid "Network Manager"
msgstr "Nettverkshåndtering"
#: ../js/ui/status/network.js:1623
#: ../js/ui/status/network.js:1690
msgid "Connection failed"
msgstr "Tilkobling feilet"
#: ../js/ui/status/network.js:1624
#: ../js/ui/status/network.js:1691
msgid "Activation of network connection failed"
msgstr "Aktivering av nettverkstilkobling feilet"
#: ../js/ui/status/network.js:1938
#: ../js/ui/status/network.js:2047
msgid "Networking is disabled"
msgstr "Nettverk er slått av"
@@ -1695,72 +1688,72 @@ msgctxt "device"
msgid "Unknown"
msgstr "Ukjent"
#: ../js/ui/status/volume.js:121
#: ../js/ui/status/volume.js:124
msgid "Volume changed"
msgstr "Volum endret"
#. Translators: This is the label for audio volume
#: ../js/ui/status/volume.js:246 ../js/ui/status/volume.js:294
#: ../js/ui/status/volume.js:249 ../js/ui/status/volume.js:297
msgid "Volume"
msgstr "Volum"
#: ../js/ui/status/volume.js:255
#: ../js/ui/status/volume.js:258
msgid "Microphone"
msgstr "Mikrofon"
#: ../js/ui/unlockDialog.js:119
#: ../js/ui/unlockDialog.js:120
msgid "Log in as another user"
msgstr "Logg inn som en annen bruker"
#: ../js/ui/unlockDialog.js:140
#: ../js/ui/unlockDialog.js:141
msgid "Unlock Window"
msgstr "Lås opp vindu"
#: ../js/ui/userMenu.js:149
#: ../js/ui/userMenu.js:193
msgid "Available"
msgstr "Tilgjengelig"
#: ../js/ui/userMenu.js:152
#: ../js/ui/userMenu.js:196
msgid "Busy"
msgstr "Opptatt"
#: ../js/ui/userMenu.js:155
#: ../js/ui/userMenu.js:199
msgid "Invisible"
msgstr "Usynlig"
#: ../js/ui/userMenu.js:158
#: ../js/ui/userMenu.js:202
msgid "Away"
msgstr "Borte"
#: ../js/ui/userMenu.js:161
#: ../js/ui/userMenu.js:205
msgid "Idle"
msgstr "Ledig"
#: ../js/ui/userMenu.js:164
#: ../js/ui/userMenu.js:208
msgid "Offline"
msgstr "Frakoblet"
#: ../js/ui/userMenu.js:736
#: ../js/ui/userMenu.js:781
msgid "Notifications"
msgstr "Varslinger"
#: ../js/ui/userMenu.js:749
#: ../js/ui/userMenu.js:797
msgid "Switch User"
msgstr "Bytt bruker"
#: ../js/ui/userMenu.js:754
#: ../js/ui/userMenu.js:802
msgid "Log Out"
msgstr "Logg ut"
#: ../js/ui/userMenu.js:774
#: ../js/ui/userMenu.js:822
msgid "Install Updates & Restart"
msgstr "Installer oppdateringer og start på nytt"
#: ../js/ui/userMenu.js:792
#: ../js/ui/userMenu.js:840
msgid "Your chat status will be set to busy"
msgstr "Din pratestatus vil bli satt til opptatt"
#: ../js/ui/userMenu.js:793
#: ../js/ui/userMenu.js:841
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."
@@ -1769,24 +1762,24 @@ msgstr ""
"tilkoblingsstatus er justert for å la andre vite at du kanskje ikke ser "
"deres meldinger."
#: ../js/ui/userMenu.js:834
#: ../js/ui/userMenu.js:888
msgid "Other users are logged in."
msgstr "Andre brukere er logget inn."
#: ../js/ui/userMenu.js:839
#: ../js/ui/userMenu.js:893
msgid "Shutting down might cause them to lose unsaved work."
msgstr ""
"Hvis du slår av vil dette kunne medføre at de mister arbeid som ikke er "
"lagret."
#. Translators: Remote here refers to a remote session, like a ssh login
#: ../js/ui/userMenu.js:867
#: ../js/ui/userMenu.js:921
#, c-format
msgid "%s (remote)"
msgstr "%s (ekstern)"
#. Translators: Console here refers to a tty like a VT console
#: ../js/ui/userMenu.js:870
#: ../js/ui/userMenu.js:924
#, c-format
msgid "%s (console)"
msgstr "%s (konsoll)"
@@ -1844,19 +1837,19 @@ msgstr[1] "%u innganger"
msgid "System Sounds"
msgstr "Systemlyder"
#: ../src/main.c:353
#: ../src/main.c:372
msgid "Print version"
msgstr "Skriv ut versjon"
#: ../src/main.c:359
#: ../src/main.c:378
msgid "Mode used by GDM for login screen"
msgstr "Modus som brukes av GDM for innloggingsskjermen"
#: ../src/main.c:365
#: ../src/main.c:384
msgid "Use a specific mode, e.g. \"gdm\" for login screen"
msgstr "Bruk spesifikt modus, f.eks «gdm» for innloggingsskjerm"
#: ../src/main.c:371
#: ../src/main.c:390
msgid "List possible modes"
msgstr "Vis mulige modi"

369
po/sk.po
View File

@@ -10,8 +10,8 @@ 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"
"POT-Creation-Date: 2013-07-13 07:31+0000\n"
"PO-Revision-Date: 2013-07-13 20:32+0200\n"
"POT-Creation-Date: 2013-05-24 21:21+0000\n"
"PO-Revision-Date: 2013-05-24 23:24+0100\n"
"Last-Translator: Dušan Kazik <prescott66@gmail.com>\n"
"Language-Team: Slovak <gnome-sk-list@gnome.org>\n"
"Language: sk\n"
@@ -384,43 +384,38 @@ msgstr "Rozšírenie"
msgid "Select an extension to configure using the combobox above."
msgstr "Použitím ponuky vyberte rozšírenie na nastavenie"
# button
#: ../js/gdm/loginDialog.js:308
msgid "Choose Session"
msgstr "Vybrať reláciu"
#: ../js/gdm/loginDialog.js:326
msgid "Session"
msgstr "Relácia"
#: ../js/gdm/loginDialog.js:371
msgid "Session…"
msgstr "Relácia…"
# https://bugzilla.gnome.org/show_bug.cgi?id=659972
#. 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:533
#: ../js/gdm/loginDialog.js:601
msgid "Not listed?"
msgstr "Nie ste v zozname?"
#: ../js/gdm/loginDialog.js:810 ../js/ui/components/networkAgent.js:137
#: ../js/gdm/loginDialog.js:776 ../js/ui/components/networkAgent.js:137
#: ../js/ui/components/polkitAgent.js:161 ../js/ui/endSessionDialog.js:376
#: ../js/ui/extensionDownloader.js:195 ../js/ui/shellMountOperation.js:399
#: ../js/ui/status/bluetooth.js:449 ../js/ui/unlockDialog.js:95
#: ../js/ui/userMenu.js:884
#: ../js/ui/status/bluetooth.js:415 ../js/ui/unlockDialog.js:96
#: ../js/ui/userMenu.js:938
msgid "Cancel"
msgstr "Zrušiť"
#: ../js/gdm/loginDialog.js:833
#: ../js/gdm/loginDialog.js:791
msgctxt "button"
msgid "Sign In"
msgstr "Prihlásiť sa"
#: ../js/gdm/loginDialog.js:833
#: ../js/gdm/loginDialog.js:791
msgid "Next"
msgstr "Ďalej"
#. Translators: this message is shown below the username entry field
#. to clue the user in on how to login to the local network realm
#: ../js/gdm/loginDialog.js:934
#: ../js/gdm/loginDialog.js:888
#, c-format
msgid "(e.g., user or %s)"
msgstr "(napr., používateľ alebo %s)"
@@ -428,12 +423,12 @@ msgstr "(napr., používateľ alebo %s)"
#. 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:938 ../js/ui/components/networkAgent.js:260
#: ../js/gdm/loginDialog.js:892 ../js/ui/components/networkAgent.js:260
#: ../js/ui/components/networkAgent.js:278
msgid "Username: "
msgstr "Používateľské meno: "
#: ../js/gdm/loginDialog.js:1205
#: ../js/gdm/loginDialog.js:1158
msgid "Login Window"
msgstr "Prihlasovacie okno"
@@ -442,8 +437,8 @@ msgstr "Prihlasovacie okno"
msgid "Power"
msgstr "Napájanie"
#: ../js/gdm/powerMenu.js:93 ../js/ui/userMenu.js:651 ../js/ui/userMenu.js:655
#: ../js/ui/userMenu.js:768
#: ../js/gdm/powerMenu.js:93 ../js/ui/userMenu.js:696 ../js/ui/userMenu.js:700
#: ../js/ui/userMenu.js:816
msgid "Suspend"
msgstr "Uspať"
@@ -451,18 +446,18 @@ msgstr "Uspať"
msgid "Restart"
msgstr "Reštartovať"
#: ../js/gdm/powerMenu.js:103 ../js/ui/userMenu.js:653
#: ../js/ui/userMenu.js:655 ../js/ui/userMenu.js:767 ../js/ui/userMenu.js:888
#: ../js/gdm/powerMenu.js:103 ../js/ui/userMenu.js:698
#: ../js/ui/userMenu.js:700 ../js/ui/userMenu.js:815 ../js/ui/userMenu.js:942
msgid "Power Off"
msgstr "Vypnúť"
#: ../js/gdm/util.js:248
#: ../js/gdm/util.js:247
msgid "Authentication error"
msgstr "Chyba pri overovaní totožnosti"
#. Translators: this message is shown below the password entry field
#. to indicate the user can swipe their finger instead
#: ../js/gdm/util.js:365
#: ../js/gdm/util.js:364
msgid "(or swipe finger)"
msgstr "(alebo prejdite prstom)"
@@ -481,23 +476,23 @@ msgstr "Nepodarilo sa analyzovať príkaz:"
msgid "Execution of '%s' failed:"
msgstr "Spustenie „%s“ zlyhalo:"
#: ../js/ui/appDisplay.js:397
#: ../js/ui/appDisplay.js:361
msgid "Frequent"
msgstr "Často používané"
#: ../js/ui/appDisplay.js:404
#: ../js/ui/appDisplay.js:368
msgid "All"
msgstr "Všetky"
#: ../js/ui/appDisplay.js:996
#: ../js/ui/appDisplay.js:960
msgid "New Window"
msgstr "Nové okno"
#: ../js/ui/appDisplay.js:999 ../js/ui/dash.js:284
#: ../js/ui/appDisplay.js:963 ../js/ui/dash.js:284
msgid "Remove from Favorites"
msgstr "Odstrániť z obľúbených"
#: ../js/ui/appDisplay.js:1000
#: ../js/ui/appDisplay.js:964
msgid "Add to Favorites"
msgstr "Pridať do obľúbených"
@@ -511,7 +506,7 @@ msgstr "Program %s bol pridaný medzi obľúbené."
msgid "%s has been removed from your favorites."
msgstr "Program %s bol odstránený z obľúbených."
#: ../js/ui/backgroundMenu.js:19 ../js/ui/userMenu.js:744
#: ../js/ui/backgroundMenu.js:19 ../js/ui/userMenu.js:789
msgid "Settings"
msgstr "Nastavenia"
@@ -636,35 +631,35 @@ msgid "S"
msgstr "So"
#. Translators: Text to show if there are no events
#: ../js/ui/calendar.js:750
#: ../js/ui/calendar.js:735
msgid "Nothing Scheduled"
msgstr "Žiadne naplánované udalosti"
#. Translators: Shown on calendar heading when selected day occurs on current year
#: ../js/ui/calendar.js:768
#: ../js/ui/calendar.js:751
msgctxt "calendar heading"
msgid "%A, %B %d"
msgstr "%A, %e. %B"
#. Translators: Shown on calendar heading when selected day occurs on different year
#: ../js/ui/calendar.js:771
#: ../js/ui/calendar.js:754
msgctxt "calendar heading"
msgid "%A, %B %d, %Y"
msgstr "%A, %e. %B %Y"
#: ../js/ui/calendar.js:782
#: ../js/ui/calendar.js:764
msgid "Today"
msgstr "Dnes"
#: ../js/ui/calendar.js:786
#: ../js/ui/calendar.js:768
msgid "Tomorrow"
msgstr "Zajtra"
#: ../js/ui/calendar.js:797
#: ../js/ui/calendar.js:779
msgid "This week"
msgstr "Tento týždeň"
#: ../js/ui/calendar.js:805
#: ../js/ui/calendar.js:787
msgid "Next week"
msgstr "Ďalší týždeň"
@@ -856,14 +851,14 @@ msgstr "<b>%e.</b> <b>%B</b> <b>%Y</b> o <b>%H:%M</b>"
#. Translators: this is the other person changing their old IM name to their new
#. IM name.
#: ../js/ui/components/telepathyClient.js:986
#: ../js/ui/components/telepathyClient.js:985
#, c-format
msgid "%s is now known as %s"
msgstr "Kontakt %s odteraz vystupuje ako %s"
#. translators: argument is a room name like
#. * room@jabber.org for example.
#: ../js/ui/components/telepathyClient.js:1089
#: ../js/ui/components/telepathyClient.js:1088
#, c-format
msgid "Invitation to %s"
msgstr "Pozvánka do %s"
@@ -871,38 +866,38 @@ msgstr "Pozvánka do %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:1097
#: ../js/ui/components/telepathyClient.js:1096
#, c-format
msgid "%s is inviting you to join %s"
msgstr "Kontakt %s vás pozýva aby ste sa pridali do %s"
#: ../js/ui/components/telepathyClient.js:1099
#: ../js/ui/components/telepathyClient.js:1138
#: ../js/ui/components/telepathyClient.js:1178
#: ../js/ui/components/telepathyClient.js:1241
#: ../js/ui/components/telepathyClient.js:1098
#: ../js/ui/components/telepathyClient.js:1137
#: ../js/ui/components/telepathyClient.js:1177
#: ../js/ui/components/telepathyClient.js:1240
msgid "Decline"
msgstr "Odmietnuť"
#: ../js/ui/components/telepathyClient.js:1100
#: ../js/ui/components/telepathyClient.js:1179
#: ../js/ui/components/telepathyClient.js:1242
#: ../js/ui/components/telepathyClient.js:1099
#: ../js/ui/components/telepathyClient.js:1178
#: ../js/ui/components/telepathyClient.js:1241
msgid "Accept"
msgstr "Prijať"
#. translators: argument is a contact name like Alice for example.
#: ../js/ui/components/telepathyClient.js:1130
#: ../js/ui/components/telepathyClient.js:1129
#, c-format
msgid "Video call from %s"
msgstr "Videohovor od kontaktu %s"
#. translators: argument is a contact name like Alice for example.
#: ../js/ui/components/telepathyClient.js:1133
#: ../js/ui/components/telepathyClient.js:1132
#, c-format
msgid "Call from %s"
msgstr "Hovor od kontaktu %s"
#. translators: this is a button label (verb), not a noun
#: ../js/ui/components/telepathyClient.js:1140
#: ../js/ui/components/telepathyClient.js:1139
msgid "Answer"
msgstr "Prijať hovor"
@@ -911,110 +906,110 @@ msgstr "Prijať hovor"
#. * file name. The string will be something
#. * like: "Alice is sending you test.ogg"
#.
#: ../js/ui/components/telepathyClient.js:1172
#: ../js/ui/components/telepathyClient.js:1171
#, c-format
msgid "%s is sending you %s"
msgstr "Kontakt %s vám posiela %s"
#. To translators: The parameter is the contact's alias
#: ../js/ui/components/telepathyClient.js:1207
#: ../js/ui/components/telepathyClient.js:1206
#, c-format
msgid "%s would like permission to see when you are online"
msgstr "Kontakt %s by chcel získať oprávnenie vidieť, kedy ste pripojený"
#: ../js/ui/components/telepathyClient.js:1299
#: ../js/ui/components/telepathyClient.js:1298
msgid "Network error"
msgstr "Chyba siete"
#: ../js/ui/components/telepathyClient.js:1301
#: ../js/ui/components/telepathyClient.js:1300
msgid "Authentication failed"
msgstr "Overenie totožnosti zlyhalo"
#: ../js/ui/components/telepathyClient.js:1303
#: ../js/ui/components/telepathyClient.js:1302
msgid "Encryption error"
msgstr "Chyba šifrovania"
#: ../js/ui/components/telepathyClient.js:1305
#: ../js/ui/components/telepathyClient.js:1304
msgid "Certificate not provided"
msgstr "Neposkytnutý certifikát"
#: ../js/ui/components/telepathyClient.js:1307
#: ../js/ui/components/telepathyClient.js:1306
msgid "Certificate untrusted"
msgstr "Nedôveryhodný certifikát"
#: ../js/ui/components/telepathyClient.js:1309
#: ../js/ui/components/telepathyClient.js:1308
msgid "Certificate expired"
msgstr "Certifikát s ukončenou platnosťou"
#: ../js/ui/components/telepathyClient.js:1311
#: ../js/ui/components/telepathyClient.js:1310
msgid "Certificate not activated"
msgstr "Neaktivovaný certifikát"
#: ../js/ui/components/telepathyClient.js:1313
#: ../js/ui/components/telepathyClient.js:1312
msgid "Certificate hostname mismatch"
msgstr "Certifikát s nesúhlasným názvom hostiteľa"
#: ../js/ui/components/telepathyClient.js:1315
#: ../js/ui/components/telepathyClient.js:1314
msgid "Certificate fingerprint mismatch"
msgstr "Certifikát s nesúhlasným odtlačkom"
#: ../js/ui/components/telepathyClient.js:1317
#: ../js/ui/components/telepathyClient.js:1316
msgid "Certificate self-signed"
msgstr "Sebou podpísaný certifikát"
#: ../js/ui/components/telepathyClient.js:1319
#: ../js/ui/components/telepathyClient.js:1318
msgid "Status is set to offline"
msgstr "Stav je nastavený na odhlásený"
#: ../js/ui/components/telepathyClient.js:1321
#: ../js/ui/components/telepathyClient.js:1320
msgid "Encryption is not available"
msgstr "Šifrovanie nie je dostupné"
#: ../js/ui/components/telepathyClient.js:1323
#: ../js/ui/components/telepathyClient.js:1322
msgid "Certificate is invalid"
msgstr "Certifikát je neplatný"
#: ../js/ui/components/telepathyClient.js:1325
#: ../js/ui/components/telepathyClient.js:1324
msgid "Connection has been refused"
msgstr "Pripojenie bolo odmietnuté"
#: ../js/ui/components/telepathyClient.js:1327
#: ../js/ui/components/telepathyClient.js:1326
msgid "Connection can't be established"
msgstr "Nedá sa nadviazať spojenie"
#: ../js/ui/components/telepathyClient.js:1329
#: ../js/ui/components/telepathyClient.js:1328
msgid "Connection has been lost"
msgstr "Spojenie sa stratilo"
#: ../js/ui/components/telepathyClient.js:1331
#: ../js/ui/components/telepathyClient.js:1330
msgid "This account is already connected to the server"
msgstr "Tento účet je už pripojený k serveru"
#: ../js/ui/components/telepathyClient.js:1333
#: ../js/ui/components/telepathyClient.js:1332
msgid ""
"Connection has been replaced by a new connection using the same resource"
msgstr "Pripojenie bolo nahradené novým, ktoré používa rovnaký zdroj"
#: ../js/ui/components/telepathyClient.js:1335
#: ../js/ui/components/telepathyClient.js:1334
msgid "The account already exists on the server"
msgstr "Účet na serveri už existuje"
#: ../js/ui/components/telepathyClient.js:1337
#: ../js/ui/components/telepathyClient.js:1336
msgid "Server is currently too busy to handle the connection"
msgstr "Server je momentálne príliš zaneprázdnený na zvládnutie pripojenia"
#: ../js/ui/components/telepathyClient.js:1339
#: ../js/ui/components/telepathyClient.js:1338
msgid "Certificate has been revoked"
msgstr "Certifikát bol zrušený"
#: ../js/ui/components/telepathyClient.js:1341
#: ../js/ui/components/telepathyClient.js:1340
msgid ""
"Certificate uses an insecure cipher algorithm or is cryptographically weak"
msgstr ""
"Šifrovací algoritmus používaný certifikátom nie je bezpečný alebo je "
"kryptograficky slabý"
#: ../js/ui/components/telepathyClient.js:1343
#: ../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"
@@ -1022,22 +1017,22 @@ msgstr ""
"Dĺžka certifikátu servera, alebo hĺbka reťazca certifikátu servera presahuje "
"limit stanovený kryptografickou knižnicou."
#: ../js/ui/components/telepathyClient.js:1345
#: ../js/ui/components/telepathyClient.js:1344
msgid "Internal error"
msgstr "Vnútorná chyba"
#. translators: argument is the account name, like
#. * name@jabber.org for example.
#: ../js/ui/components/telepathyClient.js:1355
#: ../js/ui/components/telepathyClient.js:1354
#, c-format
msgid "Unable to connect to %s"
msgstr "Nepodarilo sa pripojiť účet %s"
#: ../js/ui/components/telepathyClient.js:1360
#: ../js/ui/components/telepathyClient.js:1359
msgid "View account"
msgstr "Zobraziť účet"
#: ../js/ui/components/telepathyClient.js:1399
#: ../js/ui/components/telepathyClient.js:1398
msgid "Unknown reason"
msgstr "Neznámy dôvod"
@@ -1052,26 +1047,26 @@ msgstr "Zobrazí aplikácie"
#. Translators: this is the name of the dock/favorites area on
#. the left of the overview
#: ../js/ui/dash.js:439
#: ../js/ui/dash.js:435
msgid "Dash"
msgstr "Dok"
#: ../js/ui/dateMenu.js:85
#: ../js/ui/dateMenu.js:86
msgid "Open Calendar"
msgstr "Otvoriť kalendár"
#: ../js/ui/dateMenu.js:89
#: ../js/ui/dateMenu.js:90
msgid "Open Clocks"
msgstr "Otvoriť hodiny"
#: ../js/ui/dateMenu.js:96
#: ../js/ui/dateMenu.js:97
msgid "Date & Time Settings"
msgstr "Nastavenia dátumu a času"
#. 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:208
msgid "%A %B %e, %Y"
msgstr "%A, %e. %B %Y"
@@ -1180,7 +1175,7 @@ msgstr "Inštalovať"
msgid "Download and install '%s' from extensions.gnome.org?"
msgstr "Stiahnuť a nainštalovať „%s“ z extensions.gnome.org?"
#: ../js/ui/keyboard.js:619 ../js/ui/status/keyboard.js:333
#: ../js/ui/keyboard.js:619 ../js/ui/status/keyboard.js:314
#: ../js/ui/status/power.js:211
msgid "Keyboard"
msgstr "Klávesnica"
@@ -1234,33 +1229,33 @@ msgstr "Zobraziť zdroj"
msgid "Web Page"
msgstr "Webová stránka"
#: ../js/ui/messageTray.js:1241
#: ../js/ui/messageTray.js:1182
msgid "Open"
msgstr "Otvoriť"
#: ../js/ui/messageTray.js:1248
#: ../js/ui/messageTray.js:1189
msgid "Remove"
msgstr "Odstrániť"
#: ../js/ui/messageTray.js:1560
#: ../js/ui/messageTray.js:1501
msgid "Clear Messages"
msgstr "Vymazať správy"
#: ../js/ui/messageTray.js:1587
#: ../js/ui/messageTray.js:1528
msgid "Notification Settings"
msgstr "Nastavenia oznámení"
#: ../js/ui/messageTray.js:1770
#: ../js/ui/messageTray.js:1707
msgid "No Messages"
msgstr "Žiadne správy"
# DK: zvazoval som pouzit "Panel správ"
# neviem co bude vhodnejsie ako preklad "tray"
#: ../js/ui/messageTray.js:1842
#: ../js/ui/messageTray.js:1780
msgid "Message Tray"
msgstr "Lišta správ"
#: ../js/ui/messageTray.js:2854
#: ../js/ui/messageTray.js:2800
msgid "System Information"
msgstr "Informácie o systéme"
@@ -1269,7 +1264,7 @@ msgctxt "program"
msgid "Unknown"
msgstr "Neznámy"
#: ../js/ui/overviewControls.js:474 ../js/ui/screenShield.js:150
#: ../js/ui/overviewControls.js:472 ../js/ui/screenShield.js:150
#, c-format
msgid "%d new message"
msgid_plural "%d new messages"
@@ -1294,17 +1289,17 @@ msgstr "Prehľad"
msgid "Type to search…"
msgstr "Zadajte text na vyhľadanie…"
#: ../js/ui/panel.js:567
#: ../js/ui/panel.js:642
msgid "Quit"
msgstr "Ukončiť"
#. Translators: If there is no suitable word for "Activities"
#. in your language, you can use the word for "Overview".
#: ../js/ui/panel.js:618
#: ../js/ui/panel.js:693
msgid "Activities"
msgstr "Aktivity"
#: ../js/ui/panel.js:914
#: ../js/ui/panel.js:989
msgid "Top Bar"
msgstr "Horná lišta"
@@ -1313,7 +1308,7 @@ msgstr "Horná lišta"
#. "ON" and "OFF") or "toggle-switch-intl" (for toggle
#. switches containing "◯" and "|"). Other values will
#. simply result in invisible toggle switches.
#: ../js/ui/popupMenu.js:549
#: ../js/ui/popupMenu.js:738
msgid "toggle-switch-us"
msgstr "toggle-switch-intl"
@@ -1342,7 +1337,7 @@ msgstr[0] "%d nových oznámení"
msgstr[1] "%d nové oznámenie"
msgstr[2] "%d nové oznámenia"
#: ../js/ui/screenShield.js:449 ../js/ui/userMenu.js:759
#: ../js/ui/screenShield.js:449 ../js/ui/userMenu.js:807
msgid "Lock"
msgstr "Uzamknúť"
@@ -1357,19 +1352,19 @@ msgstr "Prostredie GNOME vyžaduje uzamknutie obrazovky"
#.
#. XXX: another option is to kick the user into the gdm login
#. screen, where we're not affected by grabs
#: ../js/ui/screenShield.js:788 ../js/ui/screenShield.js:1215
#: ../js/ui/screenShield.js:773 ../js/ui/screenShield.js:1213
msgid "Unable to lock"
msgstr "Nepodarilo sa uzamknúť obrazovku"
#: ../js/ui/screenShield.js:789 ../js/ui/screenShield.js:1216
#: ../js/ui/screenShield.js:774 ../js/ui/screenShield.js:1214
msgid "Lock was blocked by an application"
msgstr "Uzamknutie bolo zablokované aplikáciou"
#: ../js/ui/searchDisplay.js:445
#: ../js/ui/searchDisplay.js:453
msgid "Searching…"
msgstr "Hľadá sa…"
#: ../js/ui/searchDisplay.js:489
#: ../js/ui/searchDisplay.js:497
msgid "No results."
msgstr "Žiadne výsledky."
@@ -1397,7 +1392,7 @@ msgstr "Heslo"
msgid "Remember Password"
msgstr "Zapamätať heslo"
#: ../js/ui/shellMountOperation.js:403 ../js/ui/unlockDialog.js:108
#: ../js/ui/shellMountOperation.js:403 ../js/ui/unlockDialog.js:109
msgid "Unlock"
msgstr "Odblokovať"
@@ -1453,9 +1448,9 @@ msgid "Large Text"
msgstr "Veľký text"
#: ../js/ui/status/bluetooth.js:28 ../js/ui/status/bluetooth.js:32
#: ../js/ui/status/bluetooth.js:290 ../js/ui/status/bluetooth.js:327
#: ../js/ui/status/bluetooth.js:355 ../js/ui/status/bluetooth.js:391
#: ../js/ui/status/bluetooth.js:422 ../js/ui/status/network.js:713
#: ../js/ui/status/bluetooth.js:289 ../js/ui/status/bluetooth.js:321
#: ../js/ui/status/bluetooth.js:357 ../js/ui/status/bluetooth.js:388
#: ../js/ui/status/network.js:739
msgid "Bluetooth"
msgstr "Bluetooth"
@@ -1476,117 +1471,106 @@ msgid "Bluetooth Settings"
msgstr "Nastavenia Bluetooth"
#. TRANSLATORS: this means that bluetooth was disabled by hardware rfkill
#: ../js/ui/status/bluetooth.js:105 ../js/ui/status/network.js:140
#: ../js/ui/status/bluetooth.js:104 ../js/ui/status/network.js:142
msgid "hardware disabled"
msgstr "hardvér zakázaný"
#: ../js/ui/status/bluetooth.js:198
#: ../js/ui/status/bluetooth.js:197
msgid "Connection"
msgstr "Pripojenie"
#: ../js/ui/status/bluetooth.js:209 ../js/ui/status/network.js:399
#: ../js/ui/status/bluetooth.js:208 ../js/ui/status/network.js:404
msgid "disconnecting..."
msgstr "odpája sa…"
#: ../js/ui/status/bluetooth.js:222 ../js/ui/status/network.js:405
#: ../js/ui/status/network.js:1298
#: ../js/ui/status/bluetooth.js:221 ../js/ui/status/network.js:410
#: ../js/ui/status/network.js:1343
msgid "connecting..."
msgstr "pripája sa…"
# menu item
#: ../js/ui/status/bluetooth.js:240
#: ../js/ui/status/bluetooth.js:239
msgid "Send Files…"
msgstr "Odoslať súbory…"
#: ../js/ui/status/bluetooth.js:247
#: ../js/ui/status/bluetooth.js:246
msgid "Keyboard Settings"
msgstr "Nastavenia klávesnice"
#: ../js/ui/status/bluetooth.js:250
#: ../js/ui/status/bluetooth.js:249
msgid "Mouse Settings"
msgstr "Nastavenia myši"
#: ../js/ui/status/bluetooth.js:255 ../js/ui/status/volume.js:313
#: ../js/ui/status/bluetooth.js:254 ../js/ui/status/volume.js:316
msgid "Sound Settings"
msgstr "Nastavenia zvuku"
#: ../js/ui/status/bluetooth.js:328 ../js/ui/status/bluetooth.js:356
#: ../js/ui/status/bluetooth.js:322
#, c-format
msgid "Authorization request from %s"
msgstr "Žiadosť o potvrdenie prístupu od %s"
#: ../js/ui/status/bluetooth.js:334 ../js/ui/status/bluetooth.js:399
#: ../js/ui/status/bluetooth.js:430
#, c-format
msgid "Device %s wants to pair with this computer"
msgstr "Zariadenie %s sa chce spárovať s týmto počítačom"
# button
#: ../js/ui/status/bluetooth.js:336
msgid "Allow"
msgstr "Povoliť"
# button
#: ../js/ui/status/bluetooth.js:337
msgid "Deny"
msgstr "Zakázať"
#: ../js/ui/status/bluetooth.js:362
#: ../js/ui/status/bluetooth.js:328
#, c-format
msgid "Device %s wants access to the service '%s'"
msgstr "Zariadenie %s chce pristupovať k službe „%s“"
#: ../js/ui/status/bluetooth.js:364
#: ../js/ui/status/bluetooth.js:330
msgid "Always grant access"
msgstr "Vždy povoliť prístup"
#: ../js/ui/status/bluetooth.js:365
#: ../js/ui/status/bluetooth.js:331
msgid "Grant this time only"
msgstr "Povoliť iba teraz"
#: ../js/ui/status/bluetooth.js:366
#: ../js/ui/status/bluetooth.js:332
msgid "Reject"
msgstr "Odmietnuť"
#. Translators: argument is the device short name
#: ../js/ui/status/bluetooth.js:393
#: ../js/ui/status/bluetooth.js:359
#, c-format
msgid "Pairing confirmation for %s"
msgstr "Potvrdenie spárovania pre %s"
#: ../js/ui/status/bluetooth.js:400
#: ../js/ui/status/bluetooth.js:365 ../js/ui/status/bluetooth.js:396
#, c-format
msgid "Device %s wants to pair with this computer"
msgstr "Zariadenie %s sa chce spárovať s týmto počítačom"
#: ../js/ui/status/bluetooth.js:366
#, c-format
msgid ""
"Please confirm whether the Passkey '%06d' matches the one on the device."
msgstr "Prosím, potvrďte, či sa heslo „%06d“ zhoduje s tým na zariadení."
#. Translators: this is the verb, not the noun
#: ../js/ui/status/bluetooth.js:403
#: ../js/ui/status/bluetooth.js:369
msgid "Matches"
msgstr "Zhoduje sa"
#: ../js/ui/status/bluetooth.js:404
#: ../js/ui/status/bluetooth.js:370
msgid "Does not match"
msgstr "Nezhoduje sa"
#: ../js/ui/status/bluetooth.js:423
#: ../js/ui/status/bluetooth.js:389
#, c-format
msgid "Pairing request for %s"
msgstr "Požiadavka na spárovanie pre %s"
#: ../js/ui/status/bluetooth.js:431
#: ../js/ui/status/bluetooth.js:397
msgid "Please enter the PIN mentioned on the device."
msgstr "Zadajte PIN, ktoré je uvedené na zariadení."
#: ../js/ui/status/bluetooth.js:448
#: ../js/ui/status/bluetooth.js:414
msgid "OK"
msgstr "Ok"
#: ../js/ui/status/keyboard.js:396
#: ../js/ui/status/keyboard.js:368
msgid "Show Keyboard Layout"
msgstr "Zobraziť rozloženie klávesnice"
#: ../js/ui/status/keyboard.js:401
#: ../js/ui/status/keyboard.js:373
msgid "Region & Language Settings"
msgstr "Miestne a jazykové nastavenia"
@@ -1599,81 +1583,87 @@ msgstr "Hlasitosť, sieť, batéria"
msgid "<unknown>"
msgstr "<neznáme>"
#: ../js/ui/status/network.js:125
#: ../js/ui/status/network.js:127
msgid "Wi-Fi"
msgstr "Wi-Fi"
#. Translators: this indicates that wireless or wwan is disabled by hardware killswitch
#: ../js/ui/status/network.js:162
#: ../js/ui/status/network.js:164
msgid "disabled"
msgstr "zakázané"
#. Translators: this is for network devices that are physically present but are not
#. under NetworkManager's control (and thus cannot be used in the menu)
#: ../js/ui/status/network.js:397
#: ../js/ui/status/network.js:402
msgid "unmanaged"
msgstr "nespravované"
#. Translators: this is for network connections that require some kind of key or password
#: ../js/ui/status/network.js:408 ../js/ui/status/network.js:1301
#: ../js/ui/status/network.js:413 ../js/ui/status/network.js:1346
msgid "authentication required"
msgstr "požaduje sa overenie totožnosti"
#. Translators: this is for devices that require some kind of firmware or kernel
#. module, which is missing
#: ../js/ui/status/network.js:419
#: ../js/ui/status/network.js:423
msgid "firmware missing"
msgstr "chýba firmvér"
#. Translators: this is for wired network devices that are physically disconnected
#: ../js/ui/status/network.js:430
msgid "cable unplugged"
msgstr "kábel odpojený"
#. Translators: this is for a network device that cannot be activated (for example it
#. is disabled by rfkill, or it has no coverage
#: ../js/ui/status/network.js:423
#: ../js/ui/status/network.js:435
msgid "unavailable"
msgstr "nedostupné"
#: ../js/ui/status/network.js:425 ../js/ui/status/network.js:1303
#: ../js/ui/status/network.js:437 ../js/ui/status/network.js:1348
msgid "connection failed"
msgstr "pripojenie zlyhalo"
#: ../js/ui/status/network.js:478 ../js/ui/status/network.js:1190
#: ../js/ui/status/network.js:490 ../js/ui/status/network.js:1236
#: ../js/ui/status/network.js:1424
msgid "More…"
msgstr "Viac…"
#. 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:506 ../js/ui/status/network.js:1142
#: ../js/ui/status/network.js:518 ../js/ui/status/network.js:1191
msgid "Connected (private)"
msgstr "Pripojené (súkromne)"
#: ../js/ui/status/network.js:572
#: ../js/ui/status/network.js:597
msgid "Wired"
msgstr "Drôtové pripojenie"
#: ../js/ui/status/network.js:592
#: ../js/ui/status/network.js:611
msgid "Mobile broadband"
msgstr "Širokopásmové pripojenie"
#: ../js/ui/status/network.js:1474
#: ../js/ui/status/network.js:1522
msgid "Enable networking"
msgstr "Povoliť sieť"
#: ../js/ui/status/network.js:1522
#: ../js/ui/status/network.js:1583
msgid "Network Settings"
msgstr "Nastavenia siete"
#: ../js/ui/status/network.js:1539
#: ../js/ui/status/network.js:1600
msgid "Network Manager"
msgstr "Správca siete"
#: ../js/ui/status/network.js:1623
#: ../js/ui/status/network.js:1690
msgid "Connection failed"
msgstr "Pripojenie zlyhalo"
#: ../js/ui/status/network.js:1624
#: ../js/ui/status/network.js:1691
msgid "Activation of network connection failed"
msgstr "Aktivácia pripojenia k sieti zlyhala"
#: ../js/ui/status/network.js:1938
#: ../js/ui/status/network.js:2047
msgid "Networking is disabled"
msgstr "Sieť je zakázaná"
@@ -1778,72 +1768,72 @@ msgctxt "device"
msgid "Unknown"
msgstr "Neznáme"
#: ../js/ui/status/volume.js:121
#: ../js/ui/status/volume.js:124
msgid "Volume changed"
msgstr "Hlasitosť bola zmenená"
#. Translators: This is the label for audio volume
#: ../js/ui/status/volume.js:246 ../js/ui/status/volume.js:294
#: ../js/ui/status/volume.js:249 ../js/ui/status/volume.js:297
msgid "Volume"
msgstr "Hlasitosť"
#: ../js/ui/status/volume.js:255
#: ../js/ui/status/volume.js:258
msgid "Microphone"
msgstr "Mikrofón"
#: ../js/ui/unlockDialog.js:119
#: ../js/ui/unlockDialog.js:120
msgid "Log in as another user"
msgstr "Prihlásiť ako iný používateľ"
#: ../js/ui/unlockDialog.js:140
#: ../js/ui/unlockDialog.js:141
msgid "Unlock Window"
msgstr "Odomykacie okno"
#: ../js/ui/userMenu.js:149
#: ../js/ui/userMenu.js:193
msgid "Available"
msgstr "Prítomný"
#: ../js/ui/userMenu.js:152
#: ../js/ui/userMenu.js:196
msgid "Busy"
msgstr "Zaneprázdnený"
#: ../js/ui/userMenu.js:155
#: ../js/ui/userMenu.js:199
msgid "Invisible"
msgstr "Neviditeľný"
#: ../js/ui/userMenu.js:158
#: ../js/ui/userMenu.js:202
msgid "Away"
msgstr "Neprítomný"
#: ../js/ui/userMenu.js:161
#: ../js/ui/userMenu.js:205
msgid "Idle"
msgstr "Nečinný"
#: ../js/ui/userMenu.js:164
#: ../js/ui/userMenu.js:208
msgid "Offline"
msgstr "Odhlásený"
#: ../js/ui/userMenu.js:736
#: ../js/ui/userMenu.js:781
msgid "Notifications"
msgstr "Upozornenia"
#: ../js/ui/userMenu.js:749
#: ../js/ui/userMenu.js:797
msgid "Switch User"
msgstr "Prepnúť používateľa"
#: ../js/ui/userMenu.js:754
#: ../js/ui/userMenu.js:802
msgid "Log Out"
msgstr "Odhlásiť sa"
#: ../js/ui/userMenu.js:774
#: ../js/ui/userMenu.js:822
msgid "Install Updates & Restart"
msgstr "Nainštalovať aktualizácie a reštartovať"
#: ../js/ui/userMenu.js:792
#: ../js/ui/userMenu.js:840
msgid "Your chat status will be set to busy"
msgstr "Váš stav bude nastavený na zaneprázdnený"
#: ../js/ui/userMenu.js:793
#: ../js/ui/userMenu.js:841
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."
@@ -1851,22 +1841,22 @@ msgstr ""
"Oznámenia, vrátane správ rozhovoru, sú teraz zakázané. Váš stav online bol "
"nastavený tak, aby ostatní vedeli, že nemusíte vidieť ich správy."
#: ../js/ui/userMenu.js:834
#: ../js/ui/userMenu.js:888
msgid "Other users are logged in."
msgstr "Sú prihlásení iní používatelia."
#: ../js/ui/userMenu.js:839
#: ../js/ui/userMenu.js:893
msgid "Shutting down might cause them to lose unsaved work."
msgstr "Vypnutie môže spôsobiť stratu neuloženej práce."
#. Translators: Remote here refers to a remote session, like a ssh login
#: ../js/ui/userMenu.js:867
#: ../js/ui/userMenu.js:921
#, c-format
msgid "%s (remote)"
msgstr "%s (vzdialená relácia)"
#. Translators: Console here refers to a tty like a VT console
#: ../js/ui/userMenu.js:870
#: ../js/ui/userMenu.js:924
#, c-format
msgid "%s (console)"
msgstr "%s (konzola)"
@@ -1928,19 +1918,19 @@ msgstr[2] "%u vstupy"
msgid "System Sounds"
msgstr "Systémové zvuky"
#: ../src/main.c:353
#: ../src/main.c:372
msgid "Print version"
msgstr "Verzia pre tlač"
#: ../src/main.c:359
#: ../src/main.c:378
msgid "Mode used by GDM for login screen"
msgstr "Režim používaný GDM pre prihlasovaciu obrazovku"
#: ../src/main.c:365
#: ../src/main.c:384
msgid "Use a specific mode, e.g. \"gdm\" for login screen"
msgstr "Použitie zvláštneho režimu, napr. „gdm“ pre prihlasovaciu obrazovku"
#: ../src/main.c:371
#: ../src/main.c:390
msgid "List possible modes"
msgstr "Zoznam možných režimov"
@@ -1962,9 +1952,6 @@ msgstr "Heslo nemôže byť prázdne"
msgid "Authentication dialog was dismissed by the user"
msgstr "Dialógové okno overenia totožnosti bolo zatvorené používateľom"
#~ msgid "cable unplugged"
#~ msgstr "kábel odpojený"
#~ msgid "Whether to collect stats about applications usage"
#~ msgstr "Či sa majú zhromažďovať štatistické údaje o používaní aplikácií"

808
po/tg.po

File diff suppressed because it is too large Load Diff

694
po/vi.po

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -36,6 +36,8 @@ extern GType gnome_shell_plugin_get_type (void);
#define SHELL_DBUS_SERVICE "org.gnome.Shell"
#define MAGNIFIER_DBUS_SERVICE "org.gnome.Magnifier"
#define OVERRIDES_SCHEMA "org.gnome.shell.overrides"
#define WM_NAME "GNOME Shell"
#define GNOME_WM_KEYBINDINGS "Mutter,GNOME Shell"
@@ -169,6 +171,23 @@ shell_dbus_init (gboolean replace)
g_object_unref (session);
}
static void
shell_prefs_init (void)
{
meta_prefs_override_preference_schema ("attach-modal-dialogs",
OVERRIDES_SCHEMA);
meta_prefs_override_preference_schema ("dynamic-workspaces",
OVERRIDES_SCHEMA);
meta_prefs_override_preference_schema ("workspaces-only-on-primary",
OVERRIDES_SCHEMA);
meta_prefs_override_preference_schema ("button-layout",
OVERRIDES_SCHEMA);
meta_prefs_override_preference_schema ("edge-tiling",
OVERRIDES_SCHEMA);
meta_prefs_override_preference_schema ("focus-change-on-pointer-rest",
OVERRIDES_SCHEMA);
}
static void
shell_introspection_init (void)
{
@@ -417,6 +436,7 @@ main (int argc, char **argv)
shell_dbus_init (meta_get_replace_current_wm ());
shell_a11y_init ();
shell_perf_log_init ();
shell_prefs_init ();
shell_introspection_init ();
shell_fonts_init ();

View File

@@ -214,7 +214,6 @@ shell_app_create_icon_texture (ShellApp *app,
typedef struct {
ShellApp *app;
int size;
ClutterTextDirection direction;
} CreateFadedIconData;
static CoglHandle
@@ -232,7 +231,7 @@ shell_app_create_faded_icon_cpu (StTextureCache *cache,
guint8 n_channels;
gboolean have_alpha;
gint fade_start;
gint fade_end;
gint fade_range;
guint i, j;
guint pixbuf_byte_size;
guint8 *orig_pixels;
@@ -284,26 +283,14 @@ shell_app_create_faded_icon_cpu (StTextureCache *cache,
pixels = g_malloc0 (rowstride * height);
memcpy (pixels, orig_pixels, pixbuf_byte_size);
/* fade on the right side for LTR, left side for RTL */
if (data->direction == CLUTTER_TEXT_DIRECTION_LTR)
{
fade_start = width / 2;
fade_end = width;
}
else
{
fade_start = 0;
fade_end = width / 2;
}
for (i = fade_start; i < fade_end; i++)
fade_start = width / 2;
fade_range = width - fade_start;
for (i = fade_start; i < width; i++)
{
for (j = 0; j < height; j++)
{
guchar *pixel = &pixels[j * rowstride + i * n_channels];
float fade = ((float) i - fade_start) / (fade_end - fade_start);
if (data->direction == CLUTTER_TEXT_DIRECTION_LTR)
fade = 1.0 - fade;
float fade = 1.0 - ((float) i - fade_start) / fade_range;
pixel[0] = 0.5 + pixel[0] * fade;
pixel[1] = 0.5 + pixel[1] * fade;
pixel[2] = 0.5 + pixel[2] * fade;
@@ -329,14 +316,13 @@ shell_app_create_faded_icon_cpu (StTextureCache *cache,
* shell_app_get_faded_icon:
* @app: A #ShellApp
* @size: Size in pixels
* @direction: Whether to fade on the left or right
*
* Return an actor with a horizontally faded look.
*
* Return value: (transfer none): A floating #ClutterActor, or %NULL if no icon
*/
ClutterActor *
shell_app_get_faded_icon (ShellApp *app, int size, ClutterTextDirection direction)
shell_app_get_faded_icon (ShellApp *app, int size)
{
CoglHandle texture;
ClutterActor *result;
@@ -352,13 +338,9 @@ shell_app_get_faded_icon (ShellApp *app, int size, ClutterTextDirection directio
/* Use icon: prefix so that we get evicted from the cache on
* icon theme changes. */
cache_key = g_strdup_printf ("icon:%s,size=%d,faded-%s",
shell_app_get_id (app),
size,
direction == CLUTTER_TEXT_DIRECTION_RTL ? "rtl" : "ltr");
cache_key = g_strdup_printf ("icon:%s,size=%d,faded", shell_app_get_id (app), size);
data.app = app;
data.size = size;
data.direction = direction;
texture = st_texture_cache_load (st_texture_cache_get_default (),
cache_key,
ST_TEXTURE_CACHE_POLICY_FOREVER,

View File

@@ -43,7 +43,7 @@ GMenuTreeEntry *shell_app_get_tree_entry (ShellApp *app);
GDesktopAppInfo *shell_app_get_app_info (ShellApp *app);
ClutterActor *shell_app_create_icon_texture (ShellApp *app, int size);
ClutterActor *shell_app_get_faded_icon (ShellApp *app, int size, ClutterTextDirection direction);
ClutterActor *shell_app_get_faded_icon (ShellApp *app, int size);
const char *shell_app_get_name (ShellApp *app);
const char *shell_app_get_description (ShellApp *app);
gboolean shell_app_is_window_backed (ShellApp *app);

View File

@@ -70,6 +70,7 @@ struct _ShellGlobal {
GtkWindow *grab_notifier;
gboolean gtk_grab_active;
ShellStageInputMode input_mode;
XserverRegion input_region;
GjsContext *js_context;
@@ -93,8 +94,6 @@ struct _ShellGlobal {
guint32 xdnd_timestamp;
gint64 last_gc_end_time;
gboolean has_modal;
};
enum {
@@ -107,6 +106,7 @@ enum {
PROP_SCREEN_WIDTH,
PROP_SCREEN_HEIGHT,
PROP_STAGE,
PROP_STAGE_INPUT_MODE,
PROP_WINDOW_GROUP,
PROP_TOP_WINDOW_GROUP,
PROP_WINDOW_MANAGER,
@@ -141,6 +141,9 @@ shell_global_set_property(GObject *object,
switch (prop_id)
{
case PROP_STAGE_INPUT_MODE:
shell_global_set_stage_input_mode (global, g_value_get_enum (value));
break;
case PROP_SESSION_MODE:
g_clear_pointer (&global->session_mode, g_free);
global->session_mode = g_ascii_strdown (g_value_get_string (value), -1);
@@ -192,6 +195,9 @@ shell_global_get_property(GObject *object,
case PROP_STAGE:
g_value_set_object (value, global->stage);
break;
case PROP_STAGE_INPUT_MODE:
g_value_set_enum (value, global->input_mode);
break;
case PROP_WINDOW_GROUP:
g_value_set_object (value, meta_get_window_group_for_screen (global->meta_screen));
break;
@@ -272,6 +278,8 @@ shell_global_init (ShellGlobal *global)
g_signal_connect (global->grab_notifier, "grab-notify", G_CALLBACK (grab_notify), global);
global->gtk_grab_active = FALSE;
global->input_mode = SHELL_STAGE_INPUT_MODE_NORMAL;
global->sound_context = ca_gtk_context_get ();
ca_context_change_props (global->sound_context,
CA_PROP_APPLICATION_NAME, "GNOME Shell",
@@ -409,6 +417,14 @@ shell_global_class_init (ShellGlobalClass *klass)
"Stage holding the desktop scene graph",
CLUTTER_TYPE_ACTOR,
G_PARAM_READABLE));
g_object_class_install_property (gobject_class,
PROP_STAGE_INPUT_MODE,
g_param_spec_enum ("stage-input-mode",
"Stage input mode",
"The stage input mode",
SHELL_TYPE_STAGE_INPUT_MODE,
SHELL_STAGE_INPUT_MODE_NORMAL,
G_PARAM_READWRITE));
g_object_class_install_property (gobject_class,
PROP_WINDOW_GROUP,
g_param_spec_object ("window-group",
@@ -513,18 +529,6 @@ shell_global_get (void)
return the_object;
}
static guint32
get_current_time_maybe_roundtrip (ShellGlobal *global)
{
guint32 time;
time = shell_global_get_current_time (global);
if (time != CurrentTime)
return time;
return meta_display_get_current_time_roundtrip (global->meta_display);
}
static void
focus_window_changed (MetaDisplay *display,
GParamSpec *param,
@@ -532,71 +536,58 @@ focus_window_changed (MetaDisplay *display,
{
ShellGlobal *global = user_data;
if (global->has_modal)
return;
/* If the stage window became unfocused, drop the key focus
* on Clutter's side. */
if (!meta_stage_is_focused (global->meta_screen))
clutter_stage_set_key_focus (global->stage, NULL);
if (global->input_mode == SHELL_STAGE_INPUT_MODE_FOCUSED &&
meta_display_get_focus_window (display) != NULL)
shell_global_set_stage_input_mode (global, SHELL_STAGE_INPUT_MODE_NORMAL);
}
static ClutterActor *
get_key_focused_actor (ShellGlobal *global)
/**
* shell_global_set_stage_input_mode:
* @global: the #ShellGlobal
* @mode: the stage input mode
*
* Sets the input mode of the stage; when @mode is
* %SHELL_STAGE_INPUT_MODE_NORMAL, then the stage accepts clicks in
* the region defined by shell_global_set_stage_input_region() but
* passes through clicks outside that region. When it is
* %SHELL_STAGE_INPUT_MODE_FULLSCREEN, the stage absorbs all input.
*
* When the input mode is %SHELL_STAGE_INPUT_MODE_FOCUSED, the pointer
* is handled as with %SHELL_STAGE_INPUT_MODE_NORMAL, but additionally
* the stage window has the keyboard focus. If the stage loses the
* focus (eg, because the user clicked into a window) the input mode
* will revert to %SHELL_STAGE_INPUT_MODE_NORMAL.
*
* Note that whenever a mutter-internal Gtk widget has a pointer grab,
* the shell goes unresponsive and passes things to the underlying GTK+
* widget to ensure that the widget gets any clicks it is expecting.
*/
void
shell_global_set_stage_input_mode (ShellGlobal *global,
ShellStageInputMode mode)
{
ClutterActor *actor;
MetaScreen *screen;
actor = clutter_stage_get_key_focus (global->stage);
g_return_if_fail (SHELL_IS_GLOBAL (global));
/* If there's no explicit key focus, clutter_stage_get_key_focus()
* returns the stage. This is a terrible API. */
if (actor == CLUTTER_ACTOR (global->stage))
actor = NULL;
return actor;
}
static void
sync_stage_window_focus (ShellGlobal *global)
{
ClutterActor *actor;
if (global->has_modal)
return;
actor = get_key_focused_actor (global);
/* An actor got key focus and the stage needs to be focused. */
if (actor != NULL && !meta_stage_is_focused (global->meta_screen))
meta_focus_stage_window (global->meta_screen,
get_current_time_maybe_roundtrip (global));
/* An actor dropped key focus. Focus the default window. */
else if (actor == NULL && meta_stage_is_focused (global->meta_screen))
meta_screen_focus_default_window (global->meta_screen,
get_current_time_maybe_roundtrip (global));
}
static void
focus_actor_changed (ClutterStage *stage,
GParamSpec *param,
gpointer user_data)
{
ShellGlobal *global = user_data;
sync_stage_window_focus (global);
}
static void
sync_input_region (ShellGlobal *global)
{
MetaScreen *screen = global->meta_screen;
screen = meta_plugin_get_screen (global->plugin);
if (global->gtk_grab_active)
meta_empty_stage_input_region (screen);
else if (global->has_modal)
else if (mode == SHELL_STAGE_INPUT_MODE_FULLSCREEN || !global->input_region)
meta_set_stage_input_region (screen, None);
else
meta_set_stage_input_region (screen, global->input_region);
if (mode == SHELL_STAGE_INPUT_MODE_FOCUSED)
meta_focus_stage_window (global->meta_screen,
shell_global_get_current_time (global));
if (mode != global->input_mode)
{
global->input_mode = mode;
g_object_notify (G_OBJECT (global), "stage-input-mode");
}
}
/**
@@ -691,7 +682,8 @@ shell_global_unset_cursor (ShellGlobal *global)
* describing the input region.
*
* Sets the area of the stage that is responsive to mouse clicks when
* we don't have a modal or grab.
* the stage mode is %SHELL_STAGE_INPUT_MODE_NORMAL (but does not change the
* current stage mode).
*/
void
shell_global_set_stage_input_region (ShellGlobal *global,
@@ -721,7 +713,10 @@ shell_global_set_stage_input_region (ShellGlobal *global,
global->input_region = XFixesCreateRegion (global->xdisplay, rects, nrects);
g_free (rects);
sync_input_region (global);
/* set_stage_input_mode() will figure out whether or not we
* should actually change the input region right now.
*/
shell_global_set_stage_input_mode (global, global->input_mode);
}
/**
@@ -961,8 +956,6 @@ _shell_global_set_plugin (ShellGlobal *global,
"End of stage page repaint",
"");
g_signal_connect (global->stage, "notify::key-focus",
G_CALLBACK (focus_actor_changed), global);
g_signal_connect (global->meta_display, "notify::focus-window",
G_CALLBACK (focus_window_changed), global);
@@ -998,14 +991,7 @@ shell_global_begin_modal (ShellGlobal *global,
guint32 timestamp,
MetaModalOptions options)
{
/* Make it an error to call begin_modal while we already
* have a modal active. */
if (global->has_modal)
return FALSE;
global->has_modal = meta_plugin_begin_modal (global->plugin, global->stage_xwindow, None, options, timestamp);
sync_input_region (global);
return global->has_modal;
return meta_plugin_begin_modal (global->plugin, global->stage_xwindow, None, options, timestamp);
}
/**
@@ -1018,25 +1004,7 @@ void
shell_global_end_modal (ShellGlobal *global,
guint32 timestamp)
{
ClutterActor *actor;
if (!global->has_modal)
return;
meta_plugin_end_modal (global->plugin, timestamp);
global->has_modal = FALSE;
/* If the stage window is unfocused, ensure that there's no
* actor focused on Clutter's side. */
if (!meta_stage_is_focused (global->meta_screen))
clutter_stage_set_key_focus (global->stage, NULL);
/* An actor dropped key focus. Focus the default window. */
else if (get_key_focused_actor (global) && meta_stage_is_focused (global->meta_screen))
meta_screen_focus_default_window (global->meta_screen,
get_current_time_maybe_roundtrip (global));
sync_input_region (global);
}
void
@@ -1254,7 +1222,7 @@ grab_notify (GtkWidget *widget, gboolean was_grabbed, gpointer user_data)
global->gtk_grab_active = !was_grabbed;
/* Update for the new setting of gtk_grab_active */
sync_input_region (global);
shell_global_set_stage_input_mode (global, global->input_mode);
}
/**
@@ -1346,6 +1314,10 @@ shell_global_sync_pointer (ShellGlobal *global)
event.type = CLUTTER_MOTION;
event.time = shell_global_get_current_time (global);
event.flags = 0;
/* This is wrong: we should be setting event.stage to NULL if the
* pointer is not inside the bounds of the stage given the current
* stage_input_mode. For our current purposes however, this works.
*/
event.stage = global->stage;
event.x = x;
event.y = y;

View File

@@ -47,6 +47,14 @@ void shell_global_end_modal (ShellGlobal *global,
void shell_global_freeze_keyboard (ShellGlobal *global,
guint32 timestamp);
typedef enum {
SHELL_STAGE_INPUT_MODE_NORMAL,
SHELL_STAGE_INPUT_MODE_FOCUSED,
SHELL_STAGE_INPUT_MODE_FULLSCREEN
} ShellStageInputMode;
void shell_global_set_stage_input_mode (ShellGlobal *global,
ShellStageInputMode mode);
void shell_global_set_stage_input_region (ShellGlobal *global,
GSList *rectangles);

View File

@@ -43,6 +43,8 @@ struct _ShellNetworkAgentClass
/* used by SHELL_TYPE_NETWORK_AGENT */
GType shell_network_agent_get_type (void);
ShellNetworkAgent *shell_network_agent_new (void);
void shell_network_agent_set_password (ShellNetworkAgent *self,
gchar *request_id,
gchar *setting_key,

View File

@@ -104,8 +104,8 @@ shell_slicer_paint_child (ShellSlicer *self)
return;
st_bin_get_alignment (ST_BIN (self), &x_align, &y_align);
st_get_align_factors (x_align, y_align,
&x_align_factor, &y_align_factor);
_st_get_align_factors (x_align, y_align,
&x_align_factor, &y_align_factor);
clutter_actor_get_allocation_box (CLUTTER_ACTOR (self), &self_box);
clutter_actor_get_allocation_box (child, &child_box);

View File

@@ -108,8 +108,8 @@ st_bin_allocate (ClutterActor *self,
gdouble x_align_f, y_align_f;
st_theme_node_get_content_box (theme_node, box, &childbox);
st_get_align_factors (priv->x_align, priv->y_align,
&x_align_f, &y_align_f);
_st_get_align_factors (priv->x_align, priv->y_align,
&x_align_f, &y_align_f);
clutter_actor_allocate_align_fill (priv->child, &childbox,
x_align_f, y_align_f,
priv->x_fill, priv->y_fill,

View File

@@ -285,6 +285,7 @@ get_content_preferred_width (StBoxLayout *self,
{
StBoxLayoutPrivate *priv = self->priv;
gint n_children = 0;
gint n_fixed = 0;
gfloat min_width, natural_width;
ClutterActor *child;
@@ -303,6 +304,12 @@ get_content_preferred_width (StBoxLayout *self,
n_children++;
if (clutter_actor_get_fixed_position_set (child))
{
n_fixed++;
continue;
}
if (priv->is_vertical)
{
_st_actor_get_preferred_width (child, -1, FALSE,
@@ -322,10 +329,10 @@ get_content_preferred_width (StBoxLayout *self,
}
}
if (!priv->is_vertical && n_children > 1)
if (!priv->is_vertical && (n_children - n_fixed) > 1)
{
min_width += priv->spacing * (n_children - 1);
natural_width += priv->spacing * (n_children - 1);
min_width += priv->spacing * (n_children - n_fixed - 1);
natural_width += priv->spacing * (n_children - n_fixed - 1);
}
if (min_width_p)
@@ -360,6 +367,7 @@ get_content_preferred_height (StBoxLayout *self,
{
StBoxLayoutPrivate *priv = self->priv;
gint n_children = 0;
gint n_fixed = 0;
gfloat min_height, natural_height;
ClutterActor *child;
@@ -378,6 +386,12 @@ get_content_preferred_height (StBoxLayout *self,
n_children++;
if (clutter_actor_get_fixed_position_set (child))
{
n_fixed++;
continue;
}
if (priv->is_vertical)
{
clutter_container_child_get ((ClutterContainer*) self, child,
@@ -402,10 +416,10 @@ get_content_preferred_height (StBoxLayout *self,
}
}
if (priv->is_vertical && n_children > 1)
if (priv->is_vertical && (n_children - n_fixed) > 1)
{
min_height += priv->spacing * (n_children - 1);
natural_height += priv->spacing * (n_children - 1);
min_height += priv->spacing * (n_children - n_fixed - 1);
natural_height += priv->spacing * (n_children - n_fixed - 1);
}
if (min_height_p)
@@ -497,9 +511,12 @@ compute_shrinks (StBoxLayout *self,
{
gfloat child_min, child_nat;
gboolean child_fill;
gboolean fixed;
fixed = clutter_actor_get_fixed_position_set (child);
shrinks[i].child_index = i;
if (CLUTTER_ACTOR_IS_VISIBLE (child))
if (CLUTTER_ACTOR_IS_VISIBLE (child) && !fixed)
{
if (priv->is_vertical)
{
@@ -721,13 +738,20 @@ st_box_layout_allocate (ClutterActor *actor,
{
ClutterActorBox child_box;
gfloat child_min, child_nat, child_allocated;
gboolean xfill, yfill, expand;
gboolean xfill, yfill, expand, fixed;
StAlign xalign, yalign;
gdouble xalign_f, yalign_f;
if (!CLUTTER_ACTOR_IS_VISIBLE (child))
goto next_child;
fixed = clutter_actor_get_fixed_position_set (child);
if (fixed)
{
clutter_actor_allocate_preferred_size (child, flags);
goto next_child;
}
clutter_container_child_get ((ClutterContainer*) actor, child,
"x-fill", &xfill,
"y-fill", &yfill,
@@ -736,7 +760,7 @@ st_box_layout_allocate (ClutterActor *actor,
"expand", &expand,
NULL);
st_get_align_factors (xalign, yalign, &xalign_f, &yalign_f);
_st_get_align_factors (xalign, yalign, &xalign_f, &yalign_f);
if (priv->is_vertical)
{

View File

@@ -98,6 +98,66 @@ _st_actor_get_preferred_height (ClutterActor *actor,
clutter_actor_get_preferred_height (actor, for_width, min_height_p, natural_height_p);
}
/**
* _st_get_align_factors:
* @x_align: an #StAlign
* @y_align: an #StAlign
* @x_align_out: (out) (allow-none): @x_align as a #gdouble
* @y_align_out: (out) (allow-none): @y_align as a #gdouble
*
* Converts @x_align and @y_align to #gdouble values.
*/
void
_st_get_align_factors (StAlign x_align,
StAlign y_align,
gdouble *x_align_out,
gdouble *y_align_out)
{
if (x_align_out)
{
switch (x_align)
{
case ST_ALIGN_START:
*x_align_out = 0.0;
break;
case ST_ALIGN_MIDDLE:
*x_align_out = 0.5;
break;
case ST_ALIGN_END:
*x_align_out = 1.0;
break;
default:
g_warn_if_reached ();
break;
}
}
if (y_align_out)
{
switch (y_align)
{
case ST_ALIGN_START:
*y_align_out = 0.0;
break;
case ST_ALIGN_MIDDLE:
*y_align_out = 0.5;
break;
case ST_ALIGN_END:
*y_align_out = 1.0;
break;
default:
g_warn_if_reached ();
break;
}
}
}
/**
* _st_set_text_from_style:
* @text: Target #ClutterText

View File

@@ -45,6 +45,11 @@ G_END_DECLS
ClutterActor *_st_widget_get_dnd_clone (StWidget *widget);
void _st_get_align_factors (StAlign x_align,
StAlign y_align,
gdouble *x_align_out,
gdouble *y_align_out);
void _st_actor_get_preferred_width (ClutterActor *actor,
gfloat for_height,
gboolean y_fill,

View File

@@ -598,7 +598,7 @@ st_scroll_view_allocate (ClutterActor *actor,
*/
/* Vertical scrollbar */
if (vscrollbar_visible)
if (CLUTTER_ACTOR_IS_VISIBLE (priv->vscroll))
{
if (clutter_actor_get_text_direction (actor) == CLUTTER_TEXT_DIRECTION_RTL)
{
@@ -617,7 +617,7 @@ st_scroll_view_allocate (ClutterActor *actor,
}
/* Horizontal scrollbar */
if (hscrollbar_visible)
if (CLUTTER_ACTOR_IS_VISIBLE (priv->hscroll))
{
if (clutter_actor_get_text_direction (actor) == CLUTTER_TEXT_DIRECTION_RTL)
{

View File

@@ -257,8 +257,8 @@ st_table_homogeneous_allocate (ClutterActor *self,
row_span = meta->row_span;
col_span = meta->col_span;
st_get_align_factors (meta->x_align, meta->y_align,
&x_align_f, &y_align_f);
_st_get_align_factors (meta->x_align, meta->y_align,
&x_align_f, &y_align_f);
if (ltr)
{
@@ -609,8 +609,8 @@ st_table_preferred_allocate (ClutterActor *self,
row_span = meta->row_span;
col_span = meta->col_span;
st_get_align_factors (meta->x_align, meta->y_align,
&x_align_f, &y_align_f);
_st_get_align_factors (meta->x_align, meta->y_align,
&x_align_f, &y_align_f);
/* initialise the width and height */
col_width = col_widths[col];

View File

@@ -1268,7 +1268,8 @@ st_theme_node_prerender_background (StThemeNode *node,
return texture;
}
static void st_theme_node_paint_borders (StThemeNodePaintState *state,
static void st_theme_node_paint_borders (StThemeNode *node,
StThemeNodePaintState *state,
const ClutterActorBox *box,
guint8 paint_opacity);
@@ -1369,11 +1370,9 @@ st_theme_node_load_background_image (StThemeNode *node)
return node->background_texture != COGL_INVALID_HANDLE;
}
static void st_theme_node_prerender_shadow (StThemeNodePaintState *state);
static void
st_theme_node_render_resources (StThemeNodePaintState *state,
StThemeNode *node,
st_theme_node_render_resources (StThemeNode *node,
StThemeNodePaintState *state,
float width,
float height)
{
@@ -1391,7 +1390,6 @@ st_theme_node_render_resources (StThemeNodePaintState *state,
*/
st_theme_node_paint_state_free (state);
st_theme_node_paint_state_set_node (state, node);
state->alloc_width = width;
state->alloc_height = height;
@@ -1476,82 +1474,40 @@ st_theme_node_render_resources (StThemeNodePaintState *state,
state->box_shadow_material = _st_create_shadow_material (box_shadow_spec,
state->prerendered_texture);
else if (node->background_color.alpha > 0 || has_border)
st_theme_node_prerender_shadow (state);
}
/* If we don't have cached textures yet, check whether we can cache
them. */
if (!node->cached_textures)
{
if (state->prerendered_material == COGL_INVALID_HANDLE &&
width >= node->box_shadow_min_width &&
height >= node->box_shadow_min_height)
{
st_theme_node_paint_state_copy (&node->cached_state, state);
node->cached_textures = TRUE;
CoglHandle buffer, offscreen;
int texture_width = ceil (width);
int texture_height = ceil (height);
buffer = cogl_texture_new_with_size (texture_width,
texture_height,
COGL_TEXTURE_NO_SLICING,
COGL_PIXEL_FORMAT_ANY);
offscreen = cogl_offscreen_new_to_texture (buffer);
if (offscreen != COGL_INVALID_HANDLE)
{
ClutterActorBox box = { 0, 0, width, height };
CoglColor clear_color;
cogl_push_framebuffer (offscreen);
cogl_ortho (0, width, height, 0, 0, 1.0);
cogl_color_set_from_4ub (&clear_color, 0, 0, 0, 0);
cogl_clear (&clear_color, COGL_BUFFER_BIT_COLOR);
st_theme_node_paint_borders (node, state, &box, 0xFF);
cogl_pop_framebuffer ();
cogl_handle_unref (offscreen);
state->box_shadow_material = _st_create_shadow_material (box_shadow_spec,
buffer);
}
cogl_handle_unref (buffer);
}
}
}
static void
st_theme_node_update_resources (StThemeNodePaintState *state,
StThemeNode *node,
float width,
float height)
{
gboolean had_prerendered_texture = FALSE;
gboolean had_box_shadow = FALSE;
StShadow *box_shadow_spec;
g_return_if_fail (width > 0 && height > 0);
/* Free handles we can't reuse */
if (state->prerendered_texture != COGL_INVALID_HANDLE)
{
cogl_handle_unref (state->prerendered_texture);
state->prerendered_texture = COGL_INVALID_HANDLE;
had_prerendered_texture = TRUE;
}
if (state->prerendered_material != COGL_INVALID_HANDLE)
{
cogl_handle_unref (state->prerendered_material);
state->prerendered_material = COGL_INVALID_HANDLE;
if (node->border_slices_texture == COGL_INVALID_HANDLE &&
state->box_shadow_material != COGL_INVALID_HANDLE)
{
cogl_handle_unref (state->box_shadow_material);
state->box_shadow_material = COGL_INVALID_HANDLE;
had_box_shadow = TRUE;
}
}
st_theme_node_paint_state_set_node (state, node);
state->alloc_width = width;
state->alloc_height = height;
box_shadow_spec = st_theme_node_get_box_shadow (node);
if (had_prerendered_texture)
{
state->prerendered_texture = st_theme_node_prerender_background (node, width, height);
state->prerendered_material = _st_create_texture_material (state->prerendered_texture);
}
else
{
int corner_id;
for (corner_id = 0; corner_id < 4; corner_id++)
if (state->corner_material[corner_id] == COGL_INVALID_HANDLE)
state->corner_material[corner_id] =
st_theme_node_lookup_corner (node, width, height, corner_id);
}
if (had_box_shadow)
state->box_shadow_material = _st_create_shadow_material (box_shadow_spec,
state->prerendered_texture);
}
static void
paint_material_with_opacity (CoglHandle material,
ClutterActorBox *box,
@@ -1571,11 +1527,11 @@ paint_material_with_opacity (CoglHandle material,
}
static void
st_theme_node_paint_borders (StThemeNodePaintState *state,
st_theme_node_paint_borders (StThemeNode *node,
StThemeNodePaintState *state,
const ClutterActorBox *box,
guint8 paint_opacity)
{
StThemeNode *node = state->node;
float width, height;
int border_width[4];
guint border_radius[4];
@@ -1836,353 +1792,6 @@ st_theme_node_paint_borders (StThemeNodePaintState *state,
}
}
static void
st_theme_node_paint_sliced_shadow (StThemeNodePaintState *state,
const ClutterActorBox *box,
guint8 paint_opacity)
{
StThemeNode *node = state->node;
guint border_radius[4];
CoglColor color;
StShadow *box_shadow_spec;
gfloat xoffset, yoffset;
gfloat width, height;
gfloat shadow_width, shadow_height;
gfloat xend, yend, top, bottom, left, right;
gfloat s_top, s_bottom, s_left, s_right;
gfloat shadow_blur_radius, x_spread_factor, y_spread_factor;
float rectangles[8 * 9];
gint idx;
if (paint_opacity == 0)
return;
st_theme_node_reduce_border_radius (node, box->x2 - box->x1, box->y2 - box->y1, border_radius);
box_shadow_spec = st_theme_node_get_box_shadow (node);
/* Compute input & output areas :
*
* yoffset ----------------------------
* | | | |
* | | | |
* | | | |
* top ----------------------------
* | | | |
* | | | |
* | | | |
* bottom ----------------------------
* | | | |
* | | | |
* | | | |
* yend ----------------------------
* xoffset left right xend
*
* s_top = top in offscreen's coordinates (0.0 - 1.0)
* s_bottom = bottom in offscreen's coordinates (0.0 - 1.0)
* s_left = left in offscreen's coordinates (0.0 - 1.0)
* s_right = right in offscreen's coordinates (0.0 - 1.0)
*/
if (box_shadow_spec->blur == 0)
shadow_blur_radius = 0;
else
shadow_blur_radius = (5 * (box_shadow_spec->blur / 2.0)) / 2;
shadow_width = state->box_shadow_width + 2 * shadow_blur_radius;
shadow_height = state->box_shadow_height + 2 * shadow_blur_radius;
/* Compute input regions parameters */
s_top = shadow_blur_radius + box_shadow_spec->blur +
MAX (node->border_radius[ST_CORNER_TOPLEFT],
node->border_radius[ST_CORNER_TOPRIGHT]);
s_bottom = shadow_blur_radius + box_shadow_spec->blur +
MAX (node->border_radius[ST_CORNER_BOTTOMLEFT],
node->border_radius[ST_CORNER_BOTTOMRIGHT]);
s_left = shadow_blur_radius + box_shadow_spec->blur +
MAX (node->border_radius[ST_CORNER_TOPLEFT],
node->border_radius[ST_CORNER_BOTTOMLEFT]);
s_right = shadow_blur_radius + box_shadow_spec->blur +
MAX (node->border_radius[ST_CORNER_TOPRIGHT],
node->border_radius[ST_CORNER_BOTTOMRIGHT]);
/* Compute output regions parameters */
xoffset = box->x1 + box_shadow_spec->xoffset - shadow_blur_radius - box_shadow_spec->spread;
yoffset = box->y1 + box_shadow_spec->yoffset - shadow_blur_radius - box_shadow_spec->spread;
width = box->x2 - box->x1 + 2 * shadow_blur_radius;
height = box->y2 - box->y1 + 2 * shadow_blur_radius;
x_spread_factor = (width + 2 * box_shadow_spec->spread) / width;
y_spread_factor = (height + 2 * box_shadow_spec->spread) / height;
width += 2 * box_shadow_spec->spread;
height += 2 * box_shadow_spec->spread;
xend = xoffset + width;
yend = yoffset + height;
top = s_top * y_spread_factor;
bottom = s_bottom * y_spread_factor;
left = s_left * x_spread_factor;
right = s_right * x_spread_factor;
bottom = height - bottom;
right = width - right;
/* Final adjustments */
s_top /= shadow_height;
s_bottom /= shadow_height;
s_left /= shadow_width;
s_right /= shadow_width;
s_bottom = 1.0 - s_bottom;
s_right = 1.0 - s_right;
top += yoffset;
bottom += yoffset;
left += xoffset;
right += xoffset;
/* Setup pipeline */
cogl_color_set_from_4ub (&color,
box_shadow_spec->color.red * paint_opacity / 255,
box_shadow_spec->color.green * paint_opacity / 255,
box_shadow_spec->color.blue * paint_opacity / 255,
box_shadow_spec->color.alpha * paint_opacity / 255);
cogl_color_premultiply (&color);
cogl_material_set_layer_combine_constant (state->box_shadow_material, 0, &color);
cogl_set_source (state->box_shadow_material);
idx = 0;
if (top > 0)
{
if (left > 0)
{
/* Top left corner */
rectangles[idx++] = xoffset;
rectangles[idx++] = yoffset;
rectangles[idx++] = left;
rectangles[idx++] = top;
rectangles[idx++] = 0;
rectangles[idx++] = 0;
rectangles[idx++] = s_left;
rectangles[idx++] = s_top;
}
/* Top middle */
rectangles[idx++] = left;
rectangles[idx++] = yoffset;
rectangles[idx++] = right;
rectangles[idx++] = top;
rectangles[idx++] = s_left;
rectangles[idx++] = 0;
rectangles[idx++] = s_right;
rectangles[idx++] = s_top;
if (right > 0)
{
/* Top right corner */
rectangles[idx++] = right;
rectangles[idx++] = yoffset;
rectangles[idx++] = xend;
rectangles[idx++] = top;
rectangles[idx++] = s_right;
rectangles[idx++] = 0;
rectangles[idx++] = 1;
rectangles[idx++] = s_top;
}
}
if (left > 0)
{
/* Left middle */
rectangles[idx++] = xoffset;
rectangles[idx++] = top;
rectangles[idx++] = left;
rectangles[idx++] = bottom;
rectangles[idx++] = 0;
rectangles[idx++] = s_top;
rectangles[idx++] = s_left;
rectangles[idx++] = s_bottom;
}
/* Center middle */
rectangles[idx++] = left;
rectangles[idx++] = top;
rectangles[idx++] = right;
rectangles[idx++] = bottom;
rectangles[idx++] = s_left;
rectangles[idx++] = s_top;
rectangles[idx++] = s_right;
rectangles[idx++] = s_bottom;
if (right > 0)
{
/* Right middle */
rectangles[idx++] = right;
rectangles[idx++] = top;
rectangles[idx++] = xend;
rectangles[idx++] = bottom;
rectangles[idx++] = s_right;
rectangles[idx++] = s_top;
rectangles[idx++] = 1;
rectangles[idx++] = s_bottom;
}
if (bottom > 0)
{
if (left > 0)
{
/* Bottom left corner */
rectangles[idx++] = xoffset;
rectangles[idx++] = bottom;
rectangles[idx++] = left;
rectangles[idx++] = yend;
rectangles[idx++] = 0;
rectangles[idx++] = s_bottom;
rectangles[idx++] = s_left;
rectangles[idx++] = 1;
}
/* Bottom middle */
rectangles[idx++] = left;
rectangles[idx++] = bottom;
rectangles[idx++] = right;
rectangles[idx++] = yend;
rectangles[idx++] = s_left;
rectangles[idx++] = s_bottom;
rectangles[idx++] = s_right;
rectangles[idx++] = 1;
if (right > 0)
{
/* Bottom right corner */
rectangles[idx++] = right;
rectangles[idx++] = bottom;
rectangles[idx++] = xend;
rectangles[idx++] = yend;
rectangles[idx++] = s_right;
rectangles[idx++] = s_bottom;
rectangles[idx++] = 1;
rectangles[idx++] = 1;
}
}
cogl_rectangles_with_texture_coords (rectangles, idx / 8);
#if 0
/* Visual feedback on shadow's 9-slice and orignal offscreen buffer,
for debug purposes */
cogl_rectangle (xend, yoffset, xend + shadow_width, yoffset + shadow_height);
cogl_set_source_color4ub (0xff, 0x0, 0x0, 0xff);
cogl_rectangle (xoffset, top, xend, top + 1);
cogl_rectangle (xoffset, bottom, xend, bottom + 1);
cogl_rectangle (left, yoffset, left + 1, yend);
cogl_rectangle (right, yoffset, right + 1, yend);
cogl_rectangle (xend, yoffset, xend + shadow_width, yoffset + 1);
cogl_rectangle (xend, yoffset + shadow_height, xend + shadow_width, yoffset + shadow_height + 1);
cogl_rectangle (xend, yoffset, xend + 1, yoffset + shadow_height);
cogl_rectangle (xend + shadow_width, yoffset, xend + shadow_width + 1, yoffset + shadow_height);
s_top *= shadow_height;
s_bottom *= shadow_height;
s_left *= shadow_width;
s_right *= shadow_width;
cogl_rectangle (xend, yoffset + s_top, xend + shadow_width, yoffset + s_top + 1);
cogl_rectangle (xend, yoffset + s_bottom, xend + shadow_width, yoffset + s_bottom + 1);
cogl_rectangle (xend + s_left, yoffset, xend + s_left + 1, yoffset + shadow_height);
cogl_rectangle (xend + s_right, yoffset, xend + s_right + 1, yoffset + shadow_height);
#endif
}
static void
st_theme_node_prerender_shadow (StThemeNodePaintState *state)
{
StThemeNode *node = state->node;
guint border_radius[4];
int max_borders[4];
int center_radius, corner_id;
CoglHandle buffer, offscreen;
/* Get infos from the node */
if (state->alloc_width < node->box_shadow_min_width ||
state->alloc_height < node->box_shadow_min_height)
st_theme_node_reduce_border_radius (node, state->alloc_width, state->alloc_height, border_radius);
else
for (corner_id = 0; corner_id < 4; corner_id++)
border_radius[corner_id] = node->border_radius[corner_id];
/* Compute maximum borders sizes */
max_borders[ST_SIDE_TOP] = MAX (node->border_radius[ST_CORNER_TOPLEFT],
node->border_radius[ST_CORNER_TOPRIGHT]);
max_borders[ST_SIDE_BOTTOM] = MAX (node->border_radius[ST_CORNER_BOTTOMLEFT],
node->border_radius[ST_CORNER_BOTTOMRIGHT]);
max_borders[ST_SIDE_LEFT] = MAX (node->border_radius[ST_CORNER_TOPLEFT],
node->border_radius[ST_CORNER_BOTTOMLEFT]);
max_borders[ST_SIDE_RIGHT] = MAX (node->border_radius[ST_CORNER_TOPRIGHT],
node->border_radius[ST_CORNER_BOTTOMRIGHT]);
center_radius = (node->box_shadow->blur > 0) ? (2 * node->box_shadow->blur + 1) : 1;
node->box_shadow_min_width = max_borders[ST_SIDE_LEFT] + max_borders[ST_SIDE_RIGHT] + center_radius;
node->box_shadow_min_height = max_borders[ST_SIDE_TOP] + max_borders[ST_SIDE_BOTTOM] + center_radius;
if (state->alloc_width < node->box_shadow_min_width ||
state->alloc_height < node->box_shadow_min_height)
{
state->box_shadow_width = state->alloc_width;
state->box_shadow_height = state->alloc_height;
}
else
{
state->box_shadow_width = node->box_shadow_min_width;
state->box_shadow_height = node->box_shadow_min_height;
}
/* Render offscreen */
buffer = cogl_texture_new_with_size (state->box_shadow_width,
state->box_shadow_height,
COGL_TEXTURE_NO_SLICING,
COGL_PIXEL_FORMAT_ANY);
offscreen = cogl_offscreen_new_to_texture (buffer);
if (offscreen != COGL_INVALID_HANDLE)
{
ClutterActorBox box = { 0, 0, state->box_shadow_width, state->box_shadow_height};
CoglColor clear_color;
cogl_push_framebuffer (offscreen);
cogl_ortho (0, state->box_shadow_width, state->box_shadow_height, 0, 0, 1.0);
cogl_color_set_from_4ub (&clear_color, 0, 0, 0, 0);
cogl_clear (&clear_color, COGL_BUFFER_BIT_COLOR);
st_theme_node_paint_borders (state, &box, 0xFF);
cogl_pop_framebuffer ();
cogl_handle_unref (offscreen);
state->box_shadow_material = _st_create_shadow_material (st_theme_node_get_box_shadow (node),
buffer);
}
cogl_handle_unref (buffer);
}
static void
st_theme_node_paint_sliced_border_image (StThemeNode *node,
float width,
@@ -2336,43 +1945,6 @@ st_theme_node_paint_outline (StThemeNode *node,
cogl_rectangles (rects, 4);
}
static gboolean
st_theme_node_needs_new_box_shadow_for_size (StThemeNodePaintState *state,
StThemeNode *node,
float width,
float height)
{
if (!node->rendered_once)
return TRUE;
/* The allocation hasn't changed, no need to recompute a new
box-shadow. */
if (state->alloc_width == width &&
state->alloc_height == height)
return FALSE;
/* If there is no shadow, no need to recompute a new box-shadow. */
if (node->box_shadow_min_width == 0 ||
node->box_shadow_min_height == 0)
return FALSE;
/* If the new size is inferior to the box-shadow minimum size (we
already know the size has changed), we need to recompute the
box-shadow. */
if (width < node->box_shadow_min_width ||
height < node->box_shadow_min_height)
return TRUE;
/* Now checking whether the size of the node has crossed the minimum
box-shadow size boundary, from below to above the minimum size .
If that's the case, we need to recompute the box-shadow */
if (state->alloc_width < node->box_shadow_min_width ||
state->alloc_height < node->box_shadow_min_height)
return TRUE;
return FALSE;
}
void
st_theme_node_paint (StThemeNode *node,
StThemeNodePaintState *state,
@@ -2392,28 +1964,11 @@ st_theme_node_paint (StThemeNode *node,
if (width <= 0 || height <= 0)
return;
/* Check whether we need to recreate the textures of the paint
* state, either because :
* 1) the theme node associated to the paint state has changed
* 2) the allocation size change requires recreating textures
*/
if (state->node != node ||
st_theme_node_needs_new_box_shadow_for_size (state, node, width, height))
if (state->alloc_width != width || state->alloc_height != height)
{
/* If we had the ability to cache textures on the node, then we
can just copy them over to the paint state and avoid all
rendering. We end up sharing textures a cross different
widgets. */
if (node->rendered_once && node->cached_textures &&
width >= node->box_shadow_min_width && height >= node->box_shadow_min_height)
st_theme_node_paint_state_copy (state, &node->cached_state);
else
st_theme_node_render_resources (state, node, width, height);
node->rendered_once = TRUE;
state->node = node;
st_theme_node_render_resources (node, state, width, height);
}
else if (state->alloc_width != width || state->alloc_height != height)
st_theme_node_update_resources (state, node, width, height);
/* Rough notes about the relationship of borders and backgrounds in CSS3;
* see http://www.w3.org/TR/css3-background/ for more accurate details.
@@ -2442,18 +1997,10 @@ st_theme_node_paint (StThemeNode *node,
*/
if (state->box_shadow_material)
{
if (state->alloc_width < node->box_shadow_min_width ||
state->alloc_height < node->box_shadow_min_height)
_st_paint_shadow_with_opacity (node->box_shadow,
state->box_shadow_material,
&allocation,
paint_opacity);
else
st_theme_node_paint_sliced_shadow (state,
&allocation,
paint_opacity);
}
_st_paint_shadow_with_opacity (node->box_shadow,
state->box_shadow_material,
&allocation,
paint_opacity);
if (state->prerendered_material != COGL_INVALID_HANDLE ||
st_theme_node_load_border_image (node))
@@ -2477,7 +2024,7 @@ st_theme_node_paint (StThemeNode *node,
}
else
{
st_theme_node_paint_borders (state, box, paint_opacity);
st_theme_node_paint_borders (node, state, box, paint_opacity);
}
st_theme_node_paint_outline (node, box, paint_opacity);
@@ -2529,9 +2076,8 @@ st_theme_node_paint (StThemeNode *node,
}
}
static void
st_theme_node_paint_state_node_free_internal (StThemeNodePaintState *state,
gboolean unref_node)
void
st_theme_node_paint_state_free (StThemeNodePaintState *state)
{
int corner_id;
@@ -2546,46 +2092,14 @@ st_theme_node_paint_state_node_free_internal (StThemeNodePaintState *state,
if (state->corner_material[corner_id] != COGL_INVALID_HANDLE)
cogl_handle_unref (state->corner_material[corner_id]);
if (unref_node)
st_theme_node_paint_state_set_node (state, NULL);
st_theme_node_paint_state_init (state);
}
static void
st_theme_node_paint_state_node_freed (StThemeNodePaintState *state)
{
st_theme_node_paint_state_node_free_internal (state, FALSE);
}
void
st_theme_node_paint_state_set_node (StThemeNodePaintState *state, StThemeNode *node)
{
if (state->node)
g_object_weak_unref (G_OBJECT (state->node),
(GWeakNotify) st_theme_node_paint_state_node_freed,
state);
state->node = node;
if (state->node)
g_object_weak_ref (G_OBJECT (state->node),
(GWeakNotify) st_theme_node_paint_state_node_freed,
state);
}
void
st_theme_node_paint_state_free (StThemeNodePaintState *state)
{
st_theme_node_paint_state_node_free_internal (state, TRUE);
}
void
st_theme_node_paint_state_init (StThemeNodePaintState *state)
{
int corner_id;
state->alloc_width = 0;
state->alloc_height = 0;
state->node = NULL;
state->box_shadow_material = COGL_INVALID_HANDLE;
state->prerendered_texture = COGL_INVALID_HANDLE;
@@ -2606,12 +2120,10 @@ st_theme_node_paint_state_copy (StThemeNodePaintState *state,
st_theme_node_paint_state_free (state);
st_theme_node_paint_state_set_node (state, other->node);
state->node = other->node;
state->alloc_width = other->alloc_width;
state->alloc_height = other->alloc_height;
state->box_shadow_width = other->box_shadow_width;
state->box_shadow_height = other->box_shadow_height;
if (other->box_shadow_material)
state->box_shadow_material = cogl_handle_ref (other->box_shadow_material);

View File

@@ -99,19 +99,12 @@ struct _StThemeNode {
guint background_image_shadow_computed : 1;
guint text_shadow_computed : 1;
guint link_type : 2;
guint rendered_once : 1;
guint cached_textures : 1;
int box_shadow_min_width;
int box_shadow_min_height;
CoglHandle border_slices_texture;
CoglHandle border_slices_material;
CoglHandle background_texture;
CoglHandle background_material;
CoglHandle background_shadow_material;
StThemeNodePaintState cached_state;
};
struct _StThemeNodeClass {

View File

@@ -148,13 +148,9 @@ st_theme_node_transition_update (StThemeNodeTransition *transition,
if (st_theme_node_equal (new_node, old_node))
{
{
StThemeNodePaintState tmp;
st_theme_node_paint_state_init (&tmp);
st_theme_node_paint_state_copy (&tmp, &priv->old_paint_state);
st_theme_node_paint_state_copy (&priv->old_paint_state, &priv->new_paint_state);
st_theme_node_paint_state_copy (&priv->new_paint_state, &tmp);
st_theme_node_paint_state_free (&tmp);
StThemeNodePaintState tmp = priv->old_paint_state;
priv->old_paint_state = priv->new_paint_state;
priv->new_paint_state = tmp;
}
if (clutter_timeline_get_elapsed_time (priv->timeline) > 0)

View File

@@ -54,8 +54,6 @@ st_theme_node_init (StThemeNode *node)
node->background_shadow_material = COGL_INVALID_HANDLE;
node->border_slices_texture = COGL_INVALID_HANDLE;
node->border_slices_material = COGL_INVALID_HANDLE;
st_theme_node_paint_state_init (&node->cached_state);
}
static void
@@ -103,8 +101,6 @@ st_theme_node_dispose (GObject *gobject)
g_signal_handlers_disconnect_by_func (node->theme,
on_custom_stylesheets_changed, node);
st_theme_node_paint_state_free (&node->cached_state);
g_clear_object (&node->theme);
G_OBJECT_CLASS (st_theme_node_parent_class)->dispose (gobject);
@@ -3060,10 +3056,6 @@ parse_shadow_property (StThemeNode *node,
*/
for (term = decl->value; term; term = term->next)
{
/* if we found "none", we're all set with the default values */
if (term_is_none (term))
return VALUE_FOUND;
if (term->type == TERM_NUMBER)
{
gdouble value;

View File

@@ -102,9 +102,6 @@ struct _StThemeNodePaintState {
float alloc_width;
float alloc_height;
float box_shadow_width;
float box_shadow_height;
CoglHandle box_shadow_material;
CoglHandle prerendered_texture;
CoglHandle prerendered_material;
@@ -281,8 +278,6 @@ void st_theme_node_paint_state_free (StThemeNodePaintState *state);
void st_theme_node_paint_state_copy (StThemeNodePaintState *state,
StThemeNodePaintState *other);
void st_theme_node_paint_state_invalidate (StThemeNodePaintState *state);
void st_theme_node_paint_state_set_node (StThemeNodePaintState *state,
StThemeNode *node);
G_END_DECLS

View File

@@ -67,8 +67,6 @@ struct _StWidgetPrivate
gboolean hover : 1;
gboolean can_focus : 1;
gulong texture_file_changed_id;
AtkObject *accessible;
AtkRole accessible_role;
AtkStateSet *local_state_set;
@@ -364,11 +362,9 @@ st_widget_dispose (GObject *gobject)
priv->label_actor = NULL;
}
if (priv->texture_file_changed_id != 0)
{
g_signal_handler_disconnect (st_texture_cache_get_default (), priv->texture_file_changed_id);
priv->texture_file_changed_id = 0;
}
g_signal_handlers_disconnect_by_func (st_texture_cache_get_default (),
st_widget_texture_cache_changed,
actor);
g_clear_object (&priv->prev_first_child);
g_clear_object (&priv->prev_last_child);
@@ -389,7 +385,7 @@ st_widget_finalize (GObject *gobject)
g_free (priv->inline_style);
for (i = 0; i < G_N_ELEMENTS (priv->paint_states); i++)
st_theme_node_paint_state_free (&priv->paint_states[i]);
st_theme_node_paint_state_init (&priv->paint_states[i]);
G_OBJECT_CLASS (st_widget_parent_class)->finalize (gobject);
}
@@ -647,9 +643,8 @@ st_widget_get_theme_node (StWidget *widget)
if (stage == NULL)
{
g_critical ("st_widget_get_theme_node called on the widget %s which is not in the stage.",
st_describe_actor (CLUTTER_ACTOR (widget)));
return g_object_new (ST_TYPE_THEME_NODE, NULL);
g_error ("st_widget_get_theme_node called on the widget %s which is not in the stage.",
st_describe_actor (CLUTTER_ACTOR (widget)));
}
if (parent_node == NULL)
@@ -1556,8 +1551,8 @@ st_widget_init (StWidget *actor)
g_signal_connect (actor, "notify::first-child", G_CALLBACK (st_widget_first_child_notify), NULL);
g_signal_connect (actor, "notify::last-child", G_CALLBACK (st_widget_last_child_notify), NULL);
priv->texture_file_changed_id = g_signal_connect (st_texture_cache_get_default (), "texture-file-changed",
G_CALLBACK (st_widget_texture_cache_changed), actor);
g_signal_connect (st_texture_cache_get_default (), "texture-file-changed",
G_CALLBACK (st_widget_texture_cache_changed), actor);
for (i = 0; i < G_N_ELEMENTS (priv->paint_states); i++)
st_theme_node_paint_state_init (&priv->paint_states[i]);
@@ -2885,63 +2880,3 @@ st_widget_get_focus_chain (StWidget *widget)
{
return ST_WIDGET_GET_CLASS (widget)->get_focus_chain (widget);
}
/**
* st_get_align_factors:
* @x_align: an #StAlign
* @y_align: an #StAlign
* @x_align_out: (out) (allow-none): @x_align as a #gdouble
* @y_align_out: (out) (allow-none): @y_align as a #gdouble
*
* Converts @x_align and @y_align to #gdouble values.
*/
void
st_get_align_factors (StAlign x_align,
StAlign y_align,
gdouble *x_align_out,
gdouble *y_align_out)
{
if (x_align_out)
{
switch (x_align)
{
case ST_ALIGN_START:
*x_align_out = 0.0;
break;
case ST_ALIGN_MIDDLE:
*x_align_out = 0.5;
break;
case ST_ALIGN_END:
*x_align_out = 1.0;
break;
default:
g_warn_if_reached ();
break;
}
}
if (y_align_out)
{
switch (y_align)
{
case ST_ALIGN_START:
*y_align_out = 0.0;
break;
case ST_ALIGN_MIDDLE:
*y_align_out = 0.5;
break;
case ST_ALIGN_END:
*y_align_out = 1.0;
break;
default:
g_warn_if_reached ();
break;
}
}
}

View File

@@ -151,6 +151,7 @@ StThemeNode * st_widget_peek_theme_node (StWidget *widg
GList * st_widget_get_focus_chain (StWidget *widget);
void st_widget_paint_background (StWidget *widget);
/* debug methods */
char *st_describe_actor (ClutterActor *actor);
void st_set_slow_down_factor (gfloat factor);
@@ -168,12 +169,6 @@ void st_widget_set_accessible_name (StWidget *widget,
const gchar *name);
const gchar * st_widget_get_accessible_name (StWidget *widget);
/* utility methods */
void st_get_align_factors (StAlign x_align,
StAlign y_align,
gdouble *x_align_out,
gdouble *y_align_out);
G_END_DECLS
#endif /* __ST_WIDGET_H__ */

View File

@@ -8,7 +8,6 @@ TEST_JS = \
interactive/border-radius.js \
interactive/border-width.js \
interactive/box-layout.js \
interactive/box-shadow-animated.js \
interactive/box-shadows.js \
interactive/calendar.js \
interactive/css-fonts.js \

View File

@@ -45,6 +45,12 @@ function test() {
style: 'border: 1px solid #aaaaaa; '
+ 'background: #cceeff' }));
b2.add(new St.Label({ x: 50,
y: 50,
text: "Fixed",
style: 'border: 1px solid #aaaaaa;'
+ 'background: #ffffcc' }));
////////////////////////////////////////////////////////////////////////////////
function createCollapsableBox(width) {

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