Compare commits

...

252 Commits

Author SHA1 Message Date
8f2a6f8387 Bump version to 3.6.0
Update NEWS
2012-09-25 12:59:31 +02:00
908bf3b117 volume: Fix initial visibility of input
Currently the visibility of input volume is only updated when a stream
is added/removed - apparently no one noticed until now, as in the normal
user session we get away with this as long as we have some startup sound,
but this is not the case in the lock screen, so we may end up showing
input volume incorrectly.

https://bugzilla.gnome.org/show_bug.cgi?id=684611
2012-09-25 12:02:06 +02:00
6a739afd25 gdm: Make SessionList accessible
https://bugzilla.gnome.org/show_bug.cgi?id=684748
2012-09-25 12:02:06 +02:00
506490e32d Updated Hebrew translation. 2012-09-25 11:31:42 +02:00
846771f2a1 Updated Hebrew translation. 2012-09-25 11:31:36 +02:00
759b7584e0 hindi update 2012-09-25 14:39:53 +05:30
e5cb224598 Updated Arabic translation 2012-09-25 11:06:42 +02:00
e32df1b405 Updated Galician translations 2012-09-25 10:48:11 +02:00
db9f91b687 Updated Spanish translation 2012-09-25 10:27:16 +02:00
0941357068 Updated Greek translation 2012-09-25 11:22:01 +03:00
d8993c52d0 Updated Latvian translation 2012-09-25 10:45:06 +03:00
6424b2dd03 Assamese translation updated 2012-09-25 12:29:55 +05:30
2a4eb3ed1a Updated Slovenian translation 2012-09-25 08:58:03 +02:00
c9fa00cce1 Updated Portuguese translation 2012-09-25 07:59:40 +01:00
18eedbc02d keyboard: Disable "tray" button in lock/login screen
It is not possible to summon the tray via shortcut or dwelling
while the screen is locked, so it is odd to allow it from the
on-screen-keyboard.

https://bugzilla.gnome.org/show_bug.cgi?id=683546
2012-09-25 08:25:26 +02:00
ef9f63fe59 keyboard: Ignore focus changes from extended keys
The keyboard is shown/hidden automatically when (un)focusing a
ClutterText actor. This behavior is unwanted when opening the
extended keys popup, so focus changes to the popup are ignored.
However, we also want to ignore focus changes from the popup
to avoid the keyboard hiding itself after pressing an extended
key.

https://bugzilla.gnome.org/show_bug.cgi?id=683546
2012-09-25 08:25:26 +02:00
f8ce788425 keyboard: Fix check for extended keys
The existing check tested for non-existent properties.

https://bugzilla.gnome.org/show_bug.cgi?id=683546
2012-09-25 08:25:25 +02:00
6c1bd95643 keyboard: Ignore focus changes caused by tray showing/hiding
The keyboard is shown/hidden automatically when (un)focusing a
ClutterText actor. This behavior breaks with the message tray now
grabbing/releasing key focus when toggled. Fix this by ignoring
all focus changes to or from the message tray.

https://bugzilla.gnome.org/show_bug.cgi?id=683546
2012-09-25 08:25:25 +02:00
2ed7ee8f71 keyboard: Keep tray after clicking summary item
Currently if a summary item signals that it has handled a click
itself, the tray hides itself. This behavior is wrong for the
On-Screen-Keyboard, which appears as a unit with the tray, so add
a property to opt-out of the default behavior.

https://bugzilla.gnome.org/show_bug.cgi?id=683546
2012-09-25 08:25:25 +02:00
2e63709450 grabHelper: Ignore events from On-Screen-Keyboard
GrabHelper automatically releases grabs when the user clicks outside
the grabbed actors. However at least for the message-tray (which is
the only user of grabHelper at the moment), we must ignore any events
from the On-Screen-Keyboard, to prevent the tray from hiding at every
key press.

https://bugzilla.gnome.org/show_bug.cgi?id=683546
2012-09-25 08:25:24 +02:00
6611d639a8 messageTray: Only update keyboardVisible as necessary
This fixes a case of _updateState() being called recursively,
resulting in stray grab()/ungrab() calls the leave the entire
desktop in a stuck focus state.

https://bugzilla.gnome.org/show_bug.cgi?id=683546
2012-09-25 08:25:24 +02:00
fe124e6ab3 Keyboard: update for the message tray changes
The message tray is now modal and pushes the view up, but the keyboard
is shown below it. Solve this by applying a special styling to the
keyboard and message tray combination, and by not pushing the windows
up when the keyboard is shown.

https://bugzilla.gnome.org/show_bug.cgi?id=683546
2012-09-25 08:25:24 +02:00
fee0a8527d Updated Marathi Translations 2012-09-25 09:03:28 +05:30
2f6b00403f Updated Indonesian translation 2012-09-25 09:55:32 +07:00
dbe2c117e3 update Punjabi Translation 2012-09-25 06:46:18 +05:30
c4b1ccb6d6 Updated Brazilian Portuguese Translation 2012-09-24 21:58:42 -03:00
2c70ee7e43 [l10n] Update Japanese translation 2012-09-25 09:35:23 +09:00
f7826616b8 gdm: Make UserList accessible
https://bugzilla.gnome.org/show_bug.cgi?id=684728
2012-09-25 02:06:02 +02:00
9f476a12dd gdm: Provide an accessible name for powerMenu
https://bugzilla.gnome.org/show_bug.cgi?id=684727
2012-09-25 02:06:02 +02:00
6f3cf0ae50 userMenu: Force reload of background-image on icon changes
When changing the user's avatar image, AccountsService will
overwrite the old image with the new one, so the location
returned by get_icon_file() is always the same.
In order to pick up the change, we need to make sure to clear the
previous image from both StTextureCache and StThemeNode's paint
cache.

https://bugzilla.gnome.org/show_bug.cgi?id=679268
2012-09-24 22:03:06 +02:00
cd024e21f0 st-widget: Add method to clear background-image
For performance reasons, resources required to paint a widget are
aggressively cached; we know of at least one case where our caching
prevents updating the used background-image correctly, so add explicit
API to clear all associated cache data.

https://bugzilla.gnome.org/show_bug.cgi?id=679268
2012-09-24 22:03:05 +02:00
c4c470c1f3 st-theme-node: Add method to invalidate drawing state
StThemeNode caches its resources aggressively to keep the required
work on paint to a minimum - right now, resources are only recreated
on allocation changes.
In order to update the background-image property correctly when the
underlying file changes, resources need to be recreated without a
size change, so add an explicit method for that.

https://bugzilla.gnome.org/show_bug.cgi?id=679268
2012-09-24 22:03:05 +02:00
dc9ad8df80 st-texture-cache: Add API to remove cache data
The current API assumes that image data loaded from files remains
valid during the life time of the shell. This assumption is mostly
valid for image files we provide ourselves (with the exception being
designers working on those files), but not necessarily for "external"
files - provide API to explicitly remove cached data associated with
a URI for those cases.

https://bugzilla.gnome.org/show_bug.cgi?id=679268
2012-09-24 22:03:04 +02:00
74d6225993 Update Czech translation 2012-09-24 18:31:14 +02:00
e1e0c5035d Updated Traditional Chinese translation(Hong Kong and Taiwan) 2012-09-24 22:58:55 +08:00
adf6d0eb82 Update Czech translation by Adam Matousek 2012-09-24 15:43:00 +02:00
90df435345 Added Kyrgyz translation 2012-09-24 14:34:08 +06:00
83d57211db Added 'ky' to LINGUAS 2012-09-24 14:33:12 +06:00
0a8eeb2827 [l10n] Updated Estonian translation 2012-09-24 10:42:16 +03:00
0c324c42f4 [l10n] Update Japanese translation 2012-09-24 11:45:40 +09:00
3adf54a952 Updated Latvian translation 2012-09-23 20:23:09 +03:00
8076c66a4c Updated Russian translation 2012-09-23 20:32:14 +04:00
f9c583a636 Updated Russian translation 2012-09-23 19:50:31 +04:00
30d536b19c hindi update 2012-09-23 20:46:41 +05:30
1957899146 [l10n] Updated German translation 2012-09-23 12:31:15 +02:00
b52c83d88a [l10n]Updated Catalan (Valencian) translation 2012-09-23 00:21:06 +02:00
27ff388413 [l10n] Updated Catalan translation 2012-09-23 00:21:00 +02:00
d4306f7768 update Simplified Chinese (zh_CN) translation 2012-09-23 04:35:44 +08:00
5d0a57c97d Finnish translation update by Jiri Grönroos 2012-09-22 21:54:22 +03:00
a87ba467ae messageTray: Don't open the tray from a dwell if we're in a modal grab
If we're in an alt-tab popup or modal dialog, we shouldn't pop up the tray
at all.

https://bugzilla.gnome.org/show_bug.cgi?id=684458
2012-09-22 15:39:22 -03:00
7df7cd01eb messageTray: Clean up commented code a bit
Since we changed the grabHelper.grab call to be in a conditional,
it's been a little clear what the comment has been referring to.

https://bugzilla.gnome.org/show_bug.cgi?id=684458
2012-09-22 15:39:22 -03:00
098d805a8b [l10n] Updated Italian translation. 2012-09-22 16:54:29 +02:00
4a21034a00 Updated Hebrew translation. 2012-09-22 15:06:30 +03:00
7904e359f2 Updated Hebrew translation. 2012-09-22 15:06:07 +03:00
0c8a94beb8 screenShield: Fix unlock animation
When unlocking succeeds, the transition back to the user session is
animated. However, commit 8cf9baa1 broke the transition by hiding the
actor before starting the animation.

https://bugzilla.gnome.org/show_bug.cgi?id=684591
2012-09-22 13:50:25 +02:00
c13a573792 Updated Danish translation 2012-09-22 12:27:49 +02:00
f9b42e12ae Updated British English translation 2012-09-22 11:18:23 +01:00
5c2031b768 Updated Bulgarian translation 2012-09-22 12:52:52 +03:00
49643882d4 Updated Korean translation 2012-09-22 18:50:34 +09:00
175ddaa3a1 searchDisplay: Fix alignment of section headers in RTL locales
https://bugzilla.gnome.org/show_bug.cgi?id=684379
2012-09-21 21:03:52 +02:00
cc1d6e97b8 Updated Brazilian Portuguese Translation 2012-09-21 15:26:12 -03:00
79b96ab301 Updated Lithuanian translation 2012-09-21 20:53:34 +03:00
44d9316023 Updated Belarusian translation. 2012-09-21 20:02:55 +03:00
5b0c9a74fb Updated Spanish translation 2012-09-21 17:52:32 +02:00
3429fc3e4c userMenu: Close menu immediately on user/session switch
The same reasoning as for commit 1f30670c1d also applies to
VT switches.

https://bugzilla.gnome.org/show_bug.cgi?id=684459
2012-09-21 16:07:38 +02:00
d11d8d5353 Updated translation for Odia. 2012-09-21 17:34:09 +05:30
1742bd6ded Updated Galician translations 2012-09-21 13:18:37 +02:00
9f6e118ea0 Updated Portuguese translation 2012-09-20 22:19:24 +01:00
717bbd3bb5 Updated Serbian translation 2012-09-20 20:23:24 +02:00
e8ebe4de14 popupMenu: Set initial visibility of settings items
With the recent session mode changes, the visibility of settings
items is now only set on sessionMode::updated - while the signal
is emitted when the session mode is initialized, settings items
that are added after that are visible regardless of the allowSettings
setting until the next sessionMode::updated signal is received.
Fix this by explicitly setting the initial visibility of settings
items.

https://bugzilla.gnome.org/show_bug.cgi?id=684473
2012-09-20 20:04:05 +02:00
0ff614ccd4 Don't show network dialogs in the lock screen
Remove the network agent component from the lock screen and unlock
dialog session modes.

https://bugzilla.gnome.org/show_bug.cgi?id=684384
2012-09-20 20:03:23 +02:00
d0a77b7e0c keyboard: Make input source items accessible
https://bugzilla.gnome.org/show_bug.cgi?id=684462
2012-09-20 19:59:27 +02:00
2815889090 Updated Malayalam file 2012-09-20 22:57:20 +05:30
1317956663 Updated Malayalam file 2012-09-20 21:40:54 +05:30
a2303d8895 Updated Malayalam file 2012-09-20 21:39:01 +05:30
2161c793dc Updated Hungarian translation 2012-09-20 14:56:16 +02:00
a2f943db8f Updated Galician translations 2012-09-20 13:20:04 +02:00
23a31b9c00 Update French translation 2012-09-20 12:25:57 +02:00
2591d1b94b Updated Thai translation 2012-09-20 16:23:00 +07:00
300f97f102 Updated Greek translation 2012-09-20 11:10:59 +03:00
7e3f6c3066 Updated Marathi Translations 2012-09-20 12:34:06 +05:30
601d232064 Updated Arabic translation 2012-09-20 06:55:05 +02:00
8854ac84ad Updated Arabic translation 2012-09-20 06:45:35 +02:00
0302c3fbd4 Updated HINDI translation 2012-09-20 09:53:23 +05:30
6b6fdc6cfe Assamese translation updated 2012-09-20 00:14:33 +05:30
7126ce86ec Updated Bulgarian translation 2012-09-19 20:42:24 +03:00
760bf52f75 update Punjabi Translation 2012-09-19 21:27:02 +05:30
6d791d31de Updated Polish translation 2012-09-19 16:42:35 +02:00
21adc98d70 updated Tamil translation 2012-09-19 19:46:23 +05:30
6fd7a56568 Updated Slovenian translation 2012-09-19 13:47:04 +02:00
fba427fcaf Bump version to 3.5.92
Update NEWS
2012-09-19 13:12:02 +02:00
7753361ffb shell-docs: Remove left-over includes
Clean out a couple of references to code that was removed or
marked private.
2012-09-19 13:12:02 +02:00
c1590d9ed7 Revert "messageTray: Fix summary position in RTL locales"
This reverts commit e6ba7c6e40.
The original issue is fixed by Clutter commit 64c7973c7429c.
2012-09-19 13:12:02 +02:00
23c1138a58 screenShield: Fix regression from 114f6f577f 2012-09-19 13:12:01 +02:00
2acb097662 grabHelper: Fix regression for dwelling with mouse down
b203a95a78 introduced a regression
where we forgot to bail out if the pushModal didn't succeed properly.

https://bugzilla.gnome.org/show_bug.cgi?id=684344
2012-09-19 08:10:12 -03:00
449d116af2 Fix 10884ef7f5
Bad rebase and code left in that had no effect.
2012-09-19 13:01:56 +02:00
110240981d Updated Telugu Translation 2012-09-19 16:22:35 +05:30
ac5c6de929 Updated Indonesian translation 2012-09-19 17:33:45 +07:00
51bdc44352 gdm: Fix property typo
Introduced by cc6744055f
2012-09-19 12:11:25 +02:00
bafe34696d build: Install keybinding files for control-center
As some keybindings are now provided by gnome-shell rather than
mutter, it makes sense to expose those in System Settings.

https://bugzilla.gnome.org/show_bug.cgi?id=671010
2012-09-19 11:50:57 +02:00
114f6f577f screenShield: Delay destruction of unlock dialog
While the unlock dialog is created early so that it appears below
the shield while the curtain slides up, it is destroyed immediately
when the shield slides back in.
Keep it around until the shield is down instead.

https://bugzilla.gnome.org/show_bug.cgi?id=684342
2012-09-19 11:50:57 +02:00
1f30670c1d userMenu: Close menu immediately when activating Lock
When locking the screen, the user menu is moved to the opposite
side. Unless we close the menu immediately without animation, the
menu will jump to the other side and fade out while the screen
shield slides down.

https://bugzilla.gnome.org/show_bug.cgi?id=684343
2012-09-19 11:50:57 +02:00
10884ef7f5 ShellUserVerifier: catch DBus errors and report them to the user
Instead of leaving the login or unlock dialogs in an inconsistent state,
catch DBus errors and show an Authentication Error message. The error
details are logged in the session logs.

https://bugzilla.gnome.org/show_bug.cgi?id=683060
2012-09-19 11:50:57 +02:00
5e12e5f42a layout: Add a fake root pixmap actor at startup, and fade it out
This provides us with a smooth transition between plymouth and gdm.

https://bugzilla.gnome.org/show_bug.cgi?id=682428
2012-09-19 11:45:24 +02:00
e7a2e1f268 Updated Thai translation 2012-09-19 12:21:44 +07:00
cc6744055f gdm: Don't fade in the log in dialog
Instead, directly show it.

https://bugzilla.gnome.org/show_bug.cgi?id=682428
2012-09-19 01:41:17 -03:00
e6ba7c6e40 messageTray: Fix summary position in RTL locales
https://bugzilla.gnome.org/show_bug.cgi?id=684214
2012-09-19 03:44:49 +02:00
ea4855e908 Updated Galician translations 2012-09-19 02:47:41 +02:00
5c7da4b0e6 status/keyboard: Fix hidden separator when menu changes while open
Due to the way the IBus API works we might get property changes while
the menu is already open. In that case the separator visibility logic
doesn't work since it only applies on menu open/close. This works
around that issue.

https://bugzilla.gnome.org/show_bug.cgi?id=682314
2012-09-18 21:32:37 +02:00
9659d934ac status/keyboard: Add menu items for IBus Anthy's InputMode, TypingMode
IBus has a properties API which are basically generic knobs into the
engine which are serialized and presented in a way that allows us to
easily build actionable UI elements with them.

Instead of implementing the whole generic system and accepting
everything coming out of the engines, for now, this patch just adds
support for a couple of important IBus Anthy properties.

https://bugzilla.gnome.org/show_bug.cgi?id=682314
2012-09-18 21:32:37 +02:00
de93677271 Allow the shell to run without the screenshield
The screenshield requires gdm 3.5, which can be problematic in
jhbuild configurations, or distributions that don't use GDM as the display
manager. Allow transparent fallback to gnome-screensaver in that case.

https://bugzilla.gnome.org/show_bug.cgi?id=683060
2012-09-18 20:25:09 +02:00
6ef3c628e6 messageTray: Move focus ourselves when entering by keybinding
When the tray is triggered by keybinding rather than dwelling, the
first summary item should be given key focus. Currently this is
achieved by grabbing the focus before toggling the tray, so that
the grabHelper will move the focus for us. However this interferes
with the grabHelper's focus save/restore mechanism - for instance,
after using the keybinding once, the tray will always come up with
the first item focused.

https://bugzilla.gnome.org/show_bug.cgi?id=682243
2012-09-18 18:45:42 +02:00
f2af0be9ac messageTray: Allow to start keynav with Tab
Currently it is only possible to use keynav inside the tray if it
has been triggered with the keyboard shortcut. Make it possible to
initiate keynav by hitting Tab in other cases as well.

https://bugzilla.gnome.org/show_bug.cgi?id=682243
2012-09-18 18:45:41 +02:00
ef7b74a104 grabHelper: Remove support for untracked grabs
https://bugzilla.gnome.org/show_bug.cgi?id=682243
2012-09-18 18:45:41 +02:00
906368d916 messageTray: Add shortcuts to summary boxpointer
Currently opening the summary boxpointer acts as a stop gap for
keynav - the only shortcut still working is "Escape" to hide the
tray altogether.
Change the handling of Escape to only close the summary boxpointer
and allow to use the down arrow as alternative (unless the boxpointer
already processes the key press itself of course, like the chat
entry does). Also add a Delete shortcut to dismiss the open summary
item.

https://bugzilla.gnome.org/show_bug.cgi?id=682243
2012-09-18 18:45:41 +02:00
809cbf58c6 grabHelper: Ungrab the entire stack on "outside clicks"
Currently clicks outside the grabbed actors are handled the same as
the user pressing Escape - a single actor is popped from the grab stack.
However according to the design, outside clicks should release all grabs.

https://bugzilla.gnome.org/show_bug.cgi?id=682243
2012-09-18 18:45:41 +02:00
a5d60050a2 messageTray: Allow to open summary item with up arrow
When using keynav in the top bar, menus may be opened using the
down arrow; in a similar fashion, allow to open the summary
boxpointer with the up arrow.

https://bugzilla.gnome.org/show_bug.cgi?id=682243
2012-09-18 18:45:40 +02:00
2c130c8668 history: Allow events to bubble up when arrowing past the first/last item
Currently the HistoryManager consumes all arrow up/down key presses
unconditionally. Change this to only consume the event if the entry
text was actually changed, e.g. not when trying to move past the
first/last item.

https://bugzilla.gnome.org/show_bug.cgi?id=682243
2012-09-18 16:44:08 +02:00
c0ff02d9c7 Updated Spanish translation 2012-09-18 16:36:42 +02:00
cb627db392 Updated Greek translation 2012-09-18 15:59:15 +03:00
33bd6bc75b Updated gujarati file 2012-09-18 17:00:22 +05:30
ea5bf109cb hindi update 2012-09-18 16:06:01 +05:30
b150a2842e hindi update 2012-09-18 15:59:55 +05:30
2a46c39019 hindi update 2012-09-18 15:17:39 +05:30
5ca5f026c5 Assamese translation updated 2012-09-18 14:56:39 +05:30
15f22add79 Updated Portuguese translation 2012-09-18 07:58:05 +01:00
131fa6a359 Updated Indonesian translation 2012-09-18 11:20:04 +07:00
2d184e1842 Updated Polish translation 2012-09-18 00:04:08 +02:00
95a55a2c1c Updated Hungarian translation 2012-09-17 23:21:16 +02:00
8eecbb5c17 Updated Lithuanian translation 2012-09-17 23:28:55 +03:00
abfdcaa1b5 Updated Russian translation 2012-09-18 00:06:46 +04:00
8ee74e5661 st-theme: Fix extension ordering with !important
Extensions need to have priority over !important styles too.

https://bugzilla.gnome.org/show_bug.cgi?id=684163
2012-09-17 17:03:59 -03:00
ff31ccdd30 grabHelper: Remove unused parameters
Some left-overs from commit b203a95a7 ...

https://bugzilla.gnome.org/show_bug.cgi?id=683546
2012-09-17 21:53:53 +02:00
f6645a41d2 grabHelper: Set _grabbedFromKeynav
This one got lost in commit b203a95a7.

https://bugzilla.gnome.org/show_bug.cgi?id=683546
2012-09-17 21:53:53 +02:00
daceb8105f Updated Slovenian translation 2012-09-17 21:37:35 +02:00
4beba796d7 Wanda: remove unnecessary destroy signal connection
'destroy' is emitted before the actor is unmapped during destruction, so
notify::mapped would emit an exception. Since unmapping is guaranteed,
the 'destroy' signal is unnecessary.

https://bugzilla.gnome.org/show_bug.cgi?id=684154
2012-09-17 19:49:58 +02:00
70c34baafb Wanda: don't recreate the texture if the icon size doesn't change
Wanda flickers if the animation is recreated, but we don't need to if
the size doesn't change (as we're not affected by icon theme changes).

https://bugzilla.gnome.org/show_bug.cgi?id=684154
2012-09-17 19:49:57 +02:00
e71c016477 recorder: Port to new gstreamer vp8enc api
The speed and quality properties have been removed in favor of properties
closer to the upstream library.

Removing the properies from the pipeline would result into a huge
slowdown so we have to map the old values to the new ones.

According to the source code of the old vp8enc element quality maps to
(int)(63 - quality * 6.2) for min_quantizer and max_quantizer, while
speed maps to cpu-used = speed == 0 ? 0 : (speed - 1).

So set min_quantizer and min_quantizer to 13, and cpu-used to 5 based on
the above formulas.

https://bugzilla.gnome.org/show_bug.cgi?id=684206
2012-09-17 19:49:04 +02:00
633bbd8a9e Fix regression from 38f943ef81
In gdm mode there is no activities button, and accessing it causes an
exception.

https://bugzilla.gnome.org/show_bug.cgi?id=684162
2012-09-17 15:31:04 +02:00
4c82df56e9 Updated POTFILES.in 2012-09-16 22:45:07 +02:00
0d62ec5b03 lookingGlass: Fix object inspector for multi-monitor scenarios
Otherwise the object inspector appears off-screen.

https://bugzilla.gnome.org/show_bug.cgi?id=683982
2012-09-16 17:38:18 -03:00
38f943ef81 messageTray: Do not block hot corner when open
https://bugzilla.gnome.org/show_bug.cgi?id=682255
2012-09-16 19:53:49 +02:00
e421953fcd panel: Make activities button's hot corner public
https://bugzilla.gnome.org/show_bug.cgi?id=682255
2012-09-16 19:53:49 +02:00
f39098a4f2 ViewSelector: remove the places & devices search provider
Remove the PlacesManager, its search provider and all associated code.
Places search is now provided by nautilus using the external search
provider API.

https://bugzilla.gnome.org/show_bug.cgi?id=683506
2012-09-16 19:02:22 +02:00
b203a95a78 grabHelper: Rework grabbing code to properly handle stacking
When Dan Winship wrote the GrabHelper code originally, it didn't
handle a grab stack. I wrote the grab stack code hastily when landed
the message tray, not understanding all of the code that was involved
here.

Fix it so that we properly do the operations for each type of grab
when we first need to, and not sometimes when the first grab is taken.

https://bugzilla.gnome.org/show_bug.cgi?id=683546
2012-09-15 10:32:31 -03:00
2bb1a6792a update Simplified Chinese (zh_CN) translation 2012-09-15 17:00:59 +08:00
e30d45a2b0 Updated Bulgarian translation 2012-09-15 08:27:48 +03:00
afcd90ae27 messageTray: Fix _hideTray() being called recursively
_hideTray() is called by _updateState() when the tray is visible
but should be hidden; however, _updateState() may be called again
from within _hideTray() when releasing the GrabHelper grab, so
unless we update the _trayState variable before that, _hideTray()
will be called a second time.

https://bugzilla.gnome.org/show_bug.cgi?id=682243
2012-09-15 00:17:44 +02:00
94c1d5a18c focus-manager: Make groups "refcounted"
Rather than unconditionally removing a focus root in remove_group(),
decrement a counter that add_group() increments, and only actually
remove a focus root when the counter drops to 0.

https://bugzilla.gnome.org/show_bug.cgi?id=682243
2012-09-15 00:17:44 +02:00
4254fa3d38 ScreenShield: Make Return key dismiss screenshield
A couple of people have walked up to me and asked how to get to the
unlock screen from the screen shield. This was partly addressed by
bug 682285, but all three people who asked me about this said they
tried the return key and were surprised when it didn't work.

It sort of makes sense, since the user is "enter"ing the computer or
"return"ing to it.

This commit makes enter work in addition to the existing escape key.

https://bugzilla.gnome.org/show_bug.cgi?id=683889
2012-09-14 16:28:13 -04:00
3b293e91e3 viewSelector: Make the start search event available to input methods
Since we now use the capture phase to feed events into the input
method, we must set the capture flag for the event that starts
searches so that IMs can get at it.

https://bugzilla.gnome.org/show_bug.cgi?id=684040
2012-09-14 21:50:38 +02:00
3d6320295e UnlockDialog: allow typing before the first question from PAM
If the user starts typing right away, assume that the entry is
for a password and don't clear it when the secret request actually
comes. Then, if the user completes typing, we also stash the answer
and send it to GDM right away on the first PAM prompt.

https://bugzilla.gnome.org/show_bug.cgi?id=681576
2012-09-14 18:40:19 +02:00
7654f1ca3e MessageTray: remove bad fast path in hideSummaryBoxPointer
The onUngrab callback already checks if all notifications are destroyed and
hides immediately if so. Previous code instead would leave state handling
in an inconsistent state, by not removing the grab, not setting
summaryBoxPointerState to HIDDEN and not disconnecting various signals.

https://bugzilla.gnome.org/show_bug.cgi?id=684036
2012-09-14 18:29:47 +02:00
e62c66b153 TelepathyClient: fix regression from 6f5b700833
https://bugzilla.gnome.org/show_bug.cgi?id=684035
2012-09-14 18:29:47 +02:00
638507caff fingerprint: autostart fprintd when necessary
commit e333263fd6 changed fingerprint.js
to not throw an exception when fprintd is uninstalled, by adding the
flags DO_NOT_LOAD_PROPERTIES and DO_NOT_AUTO_START

DO_NOT_LOAD_PROPERTIES is correct.  Loading the properties is what makes
it fail at initialization time when not installed.  DO_NOT_AUTO_START is
not correct though. It means fprintd will never get activated implicitly
when we need it.

This commit removes DO_NOT_AUTO_START thus making fprintd start when we
need it, but not fail at initialization time when not around.

https://bugzilla.gnome.org/show_bug.cgi?id=683131
2012-09-14 12:12:46 -04:00
107f5de58e ScreenShield: animate going from the unlock dialog to the lock screen
If the user presses esc in the dialog, tween the lock screen from
the top instead of showing it immediately.

https://bugzilla.gnome.org/show_bug.cgi?id=681143
2012-09-14 17:11:57 +02:00
b1451523ca messageTray: Disable the tray dwell when the user is interacting
Look at the focus window's interaction timestamp to catch the case
where the user is typing and knocks the pointer into the tray or
mouses down to the bottom of the screen and clicks on something.
If the focus window's interaction time differs at the start and
end of the tray dwell then we don't activate the tray.

https://bugzilla.gnome.org/show_bug.cgi?id=683811
2012-09-14 10:42:40 -04:00
f7a95b5edc Update French translation 2012-09-14 11:07:42 +02:00
be290fafe7 ScreenShield: wait for stage mapping before taking a grab
In gdm, we would attempt to become modal during the synchronous initialization,
and this would fail, as X prevents grabs on unmapped windows. Instead,
wait for the stage to be visible before becoming modal.

https://bugzilla.gnome.org/show_bug.cgi?id=683357
2012-09-14 00:54:50 +02:00
b7ae74edb9 Revert showing notifications in the locked screen
As PAM messages are now shown below the password entry, there is no
need for this complexity, and we can just hide all notifications.
Also, this avoids the ambiguity between notification.showWhenLocked and
source.showInLockScreen, which have very different effects.

https://bugzilla.gnome.org/show_bug.cgi?id=683369
2012-09-14 00:06:30 +02:00
b3041ae9fc TelepathyClient: fix includes
The chat menu requires the PopupMenu module.

https://bugzilla.gnome.org/show_bug.cgi?id=683989
2012-09-13 23:59:55 +02:00
7499b04638 Fix insensitive styling for popup menu items
The selector for insensitive popup menu items was wrong (a PopupMenuItem is
a ShellGenericContainer, not a StButton). Fixing it showed that previous
:insensitive tracking was manual for a reason: we have many items that are
not reactive, but don't want the insensitive styling (for example those in
the battery menu).
Fix it by adding a new style-class, popup-inactive-menu-item, that is added
to all new PopupMenuItems that are not activatable.

https://bugzilla.gnome.org/show_bug.cgi?id=683988
2012-09-13 23:48:17 +02:00
bf2d2071fc Keyboard: fix timestamp handling to account for CURRENT_TIME
CLUTTER_CURRENT_TIME (like GDK_CURRENT_TIME and libX11 CurrentTime) is 0,
and thus compares lower than all valid timestamps, meaning that
focus changes without an X11 event in the stack are ignored by
the on screen keyboard.

https://bugzilla.gnome.org/show_bug.cgi?id=664309
2012-09-13 23:48:17 +02:00
488820daec TelepathyClient: don't emit an error if an unknown message is acknowledged
pending-messages-removed is emitted for sent messages too, but we don't
include those in the _pendingMessages list. Avoid useless spew in the session
logs in that case.

https://bugzilla.gnome.org/show_bug.cgi?id=683449
2012-09-13 22:41:17 +02:00
77c15b76b5 Fix extension styling
St.Theme.load_stylesheet() does not queue a theme context change, so
any styling of widgets created before will not be updated. To fix this,
load the stylesheet before the extension builds its own UI in enable()

https://bugzilla.gnome.org/show_bug.cgi?id=682128
2012-09-13 22:41:17 +02:00
e71129aa68 autorunManager: Don't show a right-click menu
Activating the source shouldn't be possible, and neither should
removing it.

https://bugzilla.gnome.org/show_bug.cgi?id=683438
2012-09-13 15:45:07 -03:00
6f5b700833 messageTray: Split out the building of the right menu to a separate method
Besides code cleanliness, this allows us to stub out a right-click menu
for resident sources.

https://bugzilla.gnome.org/show_bug.cgi?id=683438
2012-09-13 15:45:07 -03:00
9627864ca8 status/network: Fix another StIconType regression 2012-09-13 20:32:11 +02:00
2a8625ffae screenShield: Add box-shadow to the shield
According to the mockups, the screen shield should cast a shadow
when lifted.
2012-09-13 19:15:37 +02:00
ed82c3763c recorder: Fix more fallout from session-mode changes 2012-09-13 14:29:59 +02:00
22266899dc shellEntry: Make the entry have a fake focus state when a context menu is open
This means that right-clicking on an entry shouldn't visibly change the theme,
which is unexpected. Make sure that closing the menu refocused the entry, too.

https://bugzilla.gnome.org/show_bug.cgi?id=683509
2012-09-12 14:15:18 -03:00
9dfd1bfa41 shellEntry: Don't use a ClutterClickAction to pop up a menu
This removes support for long press, but fixes the brokenness of
other types of event handling.

https://bugzilla.gnome.org/show_bug.cgi?id=683509
2012-09-12 14:15:17 -03:00
409af28cb7 status/keyboard: Handle IBus engines which don't specify a symbol
In this case, fall back to the 2 or 3 letter language code or, failing
that, to a keyboard symbol.

https://bugzilla.gnome.org/show_bug.cgi?id=683613
2012-09-12 18:54:51 +02:00
4fe604bfe8 status/keyboard: Make IBus display strings consistent with g-c-c
Instead of entries like "Anthy" we want "Japanese (Anthy)".

https://bugzilla.gnome.org/show_bug.cgi?id=683124
2012-09-12 18:54:50 +02:00
49df72ceda st-im-text: Replace key-* handler with captured-event
When using an input method like IBus, the IM is expected to process
key events before anything else. Currently this doesn't always work
as expected, as the event filtering is done in the default handlers
of the key-press and key-release events, e.g. only after other
handlers have been run.
To allow the IM to filter events earlier, move the code to a
captured-event handler instead.

https://bugzilla.gnome.org/show_bug.cgi?id=658325
2012-09-12 18:50:26 +02:00
2db029bcdb dash: Don't underallocate show-apps button
When the dash contains more icons than fit at the minimum icon size,
icons are cut off at the end. This means that the show-apps button
will be the first to disappear, which is problematic given it's the
sole access point for other applications (for those that refuse to
use search at least).
Fix by using a dedicated widget for the dash actor, so that in case
of underallocation only icons above the show-apps button end up being
cut off.

https://bugzilla.gnome.org/show_bug.cgi?id=683340
2012-09-12 16:32:52 +02:00
7fd128eabc Updated Marathi Translations 2012-09-12 16:25:12 +05:30
5e3d8dd3eb Assamese translation updated 2012-09-11 21:01:34 +05:30
785be2f327 Hide the user menu in the GDM greeter lock screen
https://bugzilla.gnome.org/show_bug.cgi?id=683705
2012-09-10 21:23:25 +02:00
8cf9baa132 ScreenShield: move lock status handling to use session mode
Have distinct session modes for the lock screen and the unlock dialog,
and rework the logic in ScreenShield to have the lock-screen mode stack
onto the unlock-dialog mode (where applicable)

https://bugzilla.gnome.org/show_bug.cgi?id=682542
2012-09-10 21:23:25 +02:00
09e3aed770 St: don't focus hidden actors
If an actors is not mapped (visible and all parents visible), then don't
allow navigating focus to it.
This fixes a regression in the keyboard navigation of the panel with
invisibile items.

https://bugzilla.gnome.org/show_bug.cgi?id=683529
2012-09-10 21:23:25 +02:00
452ac297ab PolkitAgent: don't crash if there is no avatar
If we're asking for root's password, we don't show an avatar. Don't
emit an exception in that case.

https://bugzilla.gnome.org/show_bug.cgi?id=683707
2012-09-10 18:40:05 +02:00
7ebb5c6a10 NotificationDaemon: don't fail if a tray icon has no WM_CLASS
If there is no WM_CLASS for a tray icon, it returns null, not the empty
string. Detect that case without an exception.

https://bugzilla.gnome.org/show_bug.cgi?id=683724
2012-09-10 18:40:05 +02:00
00e0d24a6a Updated Thai translation. 2012-09-10 23:19:00 +07:00
8a269041fb messageTray: Restyle the summary counters
They are bigger and show an ellipsis if the count goes over 99. They
now have a blurred background and a drop shadow based on
data/theme/close-window.svg.

https://bugzilla.gnome.org/show_bug.cgi?id=682891
2012-09-10 17:41:30 +02:00
9f48adcff9 MessageTray: fix unexpanded height when receiving multiple telepathy messages
ClutterBinLayout is so amazingly broken: it uses the y_expand property to
find out if the children needs to honor alignment/fill, but that property is
"bubbled up" from the grand-children, so the notificationWidget would notice
the y_expand on the notificationBin (necessary to make the layout manager on
notificationWidget honor the alignment property for the bin), and would
receive the full height of the MessageTray actor from the parent's layout manager,
resulting in a notificationWidget shifting up, with the notification detached
from the screen.

https://bugzilla.gnome.org/show_bug.cgi?id=683628
2012-09-10 10:41:37 +02:00
48e7d732b9 Updated Portuguese translation 2012-09-09 12:38:56 +01:00
30048b74d1 Updated Korean translation 2012-09-09 07:25:27 +09:00
c866b0dbfd Clean up vestiges of the OpenSearch system
https://bugzilla.gnome.org/show_bug.cgi?id=683583
2012-09-07 20:49:35 +02:00
1c79f18b13 stage: Change background color to grey
The stage's background color can visible on screencasts when multiple monitors
with different resolutions are in use.

Change it to from blue to grey to look better as requested by the designers.

https://bugzilla.gnome.org/show_bug.cgi?id=683514
2012-09-07 18:29:20 +02:00
6d704be88b Updated Belarusian translation. 2012-09-07 18:58:44 +03:00
5af389c087 Updated Hebrew translation. 2012-09-07 16:13:59 +03:00
475dde4193 Updated German translation 2012-09-07 09:47:48 +02:00
8c534163e1 Panel: don't animate session mode switches
It causes problems with extensions, and it's excessively distracting.

https://bugzilla.gnome.org/show_bug.cgi?id=683526
2012-09-06 21:38:18 +02:00
657887b241 Revert "userMenu: Don't update the presence icon immediately"
This reverts commit f1ca96bbf0.
We're moving towards atomic panel upgrade, so we don't need this.

https://bugzilla.gnome.org/show_bug.cgi?id=683526
2012-09-06 21:38:17 +02:00
10da35cbef boxpointer: Clean up
https://bugzilla.gnome.org/show_bug.cgi?id=680077
2012-09-06 20:59:58 +02:00
00f15c1075 boxpointer: Avoid malformed boxpointer arrow
If the arrow's origin is so close to the edge that the arrow will not
be isosceles, we try to compensate as follows:
  - We skip the rounded corner and settle for a right angled arrow as
    as shown below.
    |\_____
    |
    |
  - If the arrow was going to be acute angled, we move the position of
    the box to maintain the arrow's accuracy.

https://bugzilla.gnome.org/show_bug.cgi?id=680077
2012-09-06 20:56:04 +02:00
19f92df8ab Updated Slovenian translation 2012-09-06 19:57:27 +02:00
8639cf8060 l10n: Updated Persian translation 2012-09-06 20:44:44 +04:30
2501d29e9d Updated Brazilian Portuguese translation. 2012-09-06 11:32:17 -04:00
8109dd684e sessionMode: Introduce the concept of "primary" modes
With the recent session mode changes, there is now a mix of modes
that are meant to apply to the entire session (specified as parameter
to the --mode command line switch) and temporary modes like the lock
screen; introduce a property to make the difference explicit, and only
allow "primary" modes to be specified on the command line.

https://bugzilla.gnome.org/show_bug.cgi?id=683488
2012-09-06 17:02:51 +02:00
5a259dd6b0 GrabHelper: always navigate focus when grabbing
Users of GrabHelper.grab() espect that the actor parameter (or one of its
children) will receive focus, irrespective of the previous focus location.
This fixes the key focus on the chat entry when expanding the notification.

https://bugzilla.gnome.org/show_bug.cgi?id=683449
2012-09-06 15:20:14 +02:00
2ed28211ed popupMenu: Don't always ignore SubMenu children in width requests
Hidden children are currently ignored in width requests; in the
case of submenu items, this results in abrupt width changes of
open menus when the corresponding SubMenuMenuItem is toggled.
To fix, only ignore SubMenu children when the corresponding
SubMenuMenuItem is hidden as well.

https://bugzilla.gnome.org/show_bug.cgi?id=683485
2012-09-06 13:56:44 +02:00
9d0eaa216f layout: Fix hiding panel for fullscreen apps
Yet another fallout from the sessionMode changes ...

https://bugzilla.gnome.org/show_bug.cgi?id=683487
2012-09-06 13:56:44 +02:00
58477282fe popupSubMenu: Only remove padding when scrollbar is shown
The special padding rules for submenu items currently ensure that
content aligns properly when the scrollbar is shown. While they
work nicely for the network menu, it looks odd for non-scrolled
submenus, so make this case explicit by introducing a :scrolled
pseudo class and adjust the style rules to use it.

https://bugzilla.gnome.org/show_bug.cgi?id=683009
2012-09-06 13:56:44 +02:00
6b016c2528 st-texture-cache: Fix stretched textures
st_texture_cache_load_from_raw() enforces a square ClutterTexture,
resulting in the texture being stretched if the passed in image
data has a different width:height ratio.
Add padding in those cases as we already do when loading from pixbufs.

https://bugzilla.gnome.org/show_bug.cgi?id=683483
2012-09-06 13:56:43 +02:00
b98c5f94ee shellSearchProvider: Fix GetResultMetas definition
The searchProvider interface originally used a GetResultMeta method to
return meta data of a single id; when it was changed to GetResultMetas,
the return value was not updated accordingly.

https://bugzilla.gnome.org/show_bug.cgi?id=683482
2012-09-06 13:56:43 +02:00
ad8bdb929a ShellDBus: fully show the lock screen before returning for Lock
Otherwise, gnome-settings-daemon proceeds with suspension too early,
and we may end up with visible windows on resume.

https://bugzilla.gnome.org/show_bug.cgi?id=683448
2012-09-06 13:15:27 +02:00
5030d59fcc messageTray: Focusing the text entry should force chats to stay open
https://bugzilla.gnome.org/show_bug.cgi?id=682236
2012-09-06 12:05:54 +02:00
ec52928736 messageTray: A variable to indicate that the close button was clicked
Otherwise critical resident notifications can not be closed by
clicking the close button.

https://bugzilla.gnome.org/show_bug.cgi?id=683472
2012-09-06 12:04:11 +02:00
7f479e18e6 Finnish translation update by Jiri Grönroos 2012-09-06 08:59:38 +03:00
7999e9020d Updated Greek translation 2012-09-06 02:40:59 +03:00
43ba93a817 screenShield: Animate the raising of the lock screen with the scroll wheel
A sudden transition to the lock screen is a bit jarring.
2012-09-05 14:51:30 -03:00
b37e02c90a screenShield: Fix typo
We aren't French, no matter how much we may want to be.

https://bugzilla.gnome.org/show_bug.cgi?id=683305
2012-09-05 14:28:57 -03:00
be5df17a4a grabHelper: Clean up the code a bit
I don't remember why I added needsGrab in the first place.
2012-09-05 14:28:45 -03:00
ffbc1fd190 unlockDialog: Fix centering of label in screen shield
The code here was trying to center the label, but that didn't
happen because we allocated the entire space to the label, which
still plonks it at the top.
2012-09-05 14:26:01 -03:00
457fb604dd autorunManager: Fix another regression
We may not have a resident source to destroy if no mounts are found.
2012-09-05 13:47:01 -03:00
09c81f79f6 AutorunManager: fix regression from the components rewrite
Message tray sources cannot be reused after destruction, so connect
to 'destroy' signal and clear out the previous one.
Also, fix some code paths that used the autorun manager incorrectly.

https://bugzilla.gnome.org/show_bug.cgi?id=683377
2012-09-05 16:22:11 +02:00
0725a7d836 SessionMode: add polkit to gdm session
It's needed to shutdown when other users are logged in or inhibitors are
active.

https://bugzilla.gnome.org/show_bug.cgi?id=683400
2012-09-05 16:14:02 +02:00
f957ae71c3 Don't start new components when activating the screen-shield in gdm
Previous code was activating the networkAgent and telepathyClient
in the lock-screen, irrespective of the previous mode.
Now it checks if the session mode is locked down, and if so it refuses
to start new components.

https://bugzilla.gnome.org/show_bug.cgi?id=683400
2012-09-05 16:14:02 +02:00
011c9d1beb Updated Indonesian translation 2012-09-05 21:07:28 +07:00
aed589a98d Updated British English translation 2012-09-05 13:58:08 +01:00
3830e90642 Updated Traditional Chinese translation(Hong Kong and Taiwan) 2012-09-05 20:08:12 +08:00
3710b88ab9 Bluetooth: don't restrict the length of non numeric PINs
The protocol restriction is only for numeric PINs (passkeys, in bluez
jargon). For passwords, any length is allowed.

https://bugzilla.gnome.org/show_bug.cgi?id=683356
2012-09-05 13:15:33 +02:00
5c990f103e Rewrite the layout code of the message tray
Previous code had a mixture of fixed positioning and ClutterBinLayout,
and this was broken badly for autorun notifications.
Rewrite to use ClutterBinLayout and Clutter properties exclusively.

https://bugzilla.gnome.org/show_bug.cgi?id=683378
2012-09-05 12:42:11 +02:00
2890fc9d7d Updated Serbian translation 2012-09-05 10:37:18 +02:00
0223507a2e Updated Arabic translation 2012-09-05 07:08:55 +02:00
59412a9405 Components/Keyring: unregister the system prompter when disabling
Otherwise, we get a critical when enabling again
2012-09-05 01:13:36 +02:00
110d58bbc3 Reintroduce run dialog
Fix regression from 92d8d65543, bad rebase.
2012-09-05 01:10:44 +02:00
eda17defb2 messageTray: Move close button above notification widget stack
This allows us to click on the entire close button, not just the part
of it that's unobscured.
2012-09-04 19:21:31 -03:00
f563fb124e shell-gtk-embed: Fix NULL pointer dereference
Clutter will try to unmap during a dispose if we have a parent, so if we
set our own actor to NULL before the chain up, we're going to attempt to
unmap our own NULL actor. Fix that by swapping the order in which we
chain up.

https://bugzilla.gnome.org/show_bug.cgi?id=672790
2012-09-04 19:21:30 -03:00
14d0a96999 shell-recorder: Fix warning message about unknown escapes
We were showing the percent character here.

https://bugzilla.gnome.org/show_bug.cgi?id=677434
2012-09-04 19:21:30 -03:00
f0474ffccc shell-recorder: Remove the ability to pause the timeline
https://bugzilla.gnome.org/show_bug.cgi?id=677434
2012-09-04 19:21:30 -03:00
11ce6845f2 shell-recorder: Remove count and unique filename settigs
These aren't used anymore.

https://bugzilla.gnome.org/show_bug.cgi?id=677434
2012-09-04 19:21:30 -03:00
70d610b5e4 shell-recorder: Fix accidental fallthrough
Don't append a unique identifier when we asked for a timestamp.

https://bugzilla.gnome.org/show_bug.cgi?id=677434
2012-09-04 19:21:29 -03:00
f5ca649977 shell-recorder: Don't use a default filename
The default filename isn't localized and isn't the same one that
the shell sets. Just remove the fallback mechanism, and abort
recording if somebody didn't set the filename

https://bugzilla.gnome.org/show_bug.cgi?id=677434
2012-09-04 19:21:29 -03:00
8954d33019 Updated Polish translation 2012-09-05 00:20:30 +02:00
2e6205bc05 Updated POTFILES.in 2012-09-05 00:06:19 +02:00
e0dea63079 Updated POTFILES.in 2012-09-04 23:59:30 +02:00
7c244b01c6 Panel: move the _panelContainer down to PanelMenu
Panel already forces each item to be a PanelMenu.Button, so it's better
to have the latter handle the bin container too, instead of attaching
a private property that might collide with internal usage by the indicator.

https://bugzilla.gnome.org/show_bug.cgi?id=683156
2012-09-04 23:52:41 +02:00
3f5edf7c3e VolumeMenu: read output and input if PulseAudio is already ready when constructing
Previously we would only read the default sink and default source when
the connection to PulseAudio succeded. This worked because all VolumeMenu
users where initialized synchronously during shell load.
With the recent session mode changes though, the lock screen menu is
created on demand, and when it loads PA is already connected, so
it doesn't update the sliders.

https://bugzilla.gnome.org/show_bug.cgi?id=683156
2012-09-04 23:52:41 +02:00
92d8d65543 ScreenShield: use session mode to handle the GDM login dialog
Have main.js call .showDialog() when going back from the lock-screen, instead
of using the return value of createUnlockDialog to know if the dialog
was persistent.
_keepDialog is still used as LoginDialog cannot really be destroyed,
and cancelling it does not destroy it.

https://bugzilla.gnome.org/show_bug.cgi?id=683156
2012-09-04 23:52:41 +02:00
cebd8e14e9 screenShield: Zoom out on login
The sudden transition from the lock screen to the user session
may be a bit sudden and overwhelming. Make ourselves more shell-like
by resizing out the screen shield according to mockups.

https://bugzilla.gnome.org/show_bug.cgi?id=683170
2012-09-04 18:42:46 -03:00
16e92a7ca3 sessionMode: Inherit from a more restrictive session mode by default
It makes more sense to define session modes in terms of what you're
adding to the bare shell, not in terms of what you're taking away
from the user session.

https://bugzilla.gnome.org/show_bug.cgi?id=683156
2012-09-04 18:42:45 -03:00
59e2710137 sessionMode: Reindent
This puts all the parameters at the same indent level, which makes the
file much easier to read.

https://bugzilla.gnome.org/show_bug.cgi?id=683156
2012-09-04 18:42:45 -03:00
f1ca96bbf0 userMenu: Don't update the presence icon immediately
If we don't freeze the presence icon, we can end up in a place where
we'll be updating the icon before we fade out the panel indicators when
coming back from the lock screen.

https://bugzilla.gnome.org/show_bug.cgi?id=683156
2012-09-04 18:42:45 -03:00
ec01f5d5ee userMenu: Make the user menu insensitive in the lock screen
And show a lock icon as well.

https://bugzilla.gnome.org/show_bug.cgi?id=683156
2012-09-04 18:42:44 -03:00
2a800e4ce0 Rearchitect the Shell to have a components system
Components are pieces of the shell code that can be added/removed
at runtime, like extension, but are tied more directly to a session
mode. The session polkit agent, the network agent, autorun/automount,
are all components, keyring, recorder and telepathy client are all
now copmonents.

https://bugzilla.gnome.org/show_bug.cgi?id=683156
2012-09-04 18:42:44 -03:00
ca2e09fe8b sessionMode: Allow changing the session mode at runtime
Since we eventually want to add a system for changing the top panel
contents depending on the current state of the shell, let's use the
"session mode" feature for this, and add a mechanism for updating the
session mode at runtime. Add support for every key besides the two
functional keys, and make all the components update automatically when the
session mode is changed. Add a new lock-screen mode, and make the lock
screen change to this when locked.

https://bugzilla.gnome.org/show_bug.cgi?id=683156
2012-09-04 18:42:44 -03:00
7e343f11f2 st-bin: Make sure not to allocate hidden children 2012-09-04 18:42:44 -03:00
db20a54861 Login/UnlockDialog: don't reset immediately if auth fails
Instead of showing a notification, add a small message immediately
below the entry, and give the user two more attempts to login,
before going back to the welcome or lock screen.

https://bugzilla.gnome.org/show_bug.cgi?id=682544
2012-09-04 23:38:46 +02:00
ec4f6b7f91 Updated Hungarian translation 2012-09-04 15:54:39 +02:00
127 changed files with 38451 additions and 33744 deletions

1
.gitignore vendored
View File

@ -16,6 +16,7 @@ config.log
config.status
config
configure
data/50-gnome-shell-*.xml
data/gnome-shell.desktop
data/gnome-shell.desktop.in
data/gnome-shell-extension-prefs.desktop

101
NEWS
View File

@ -1,3 +1,104 @@
3.6.0
=====
* keyboard: Make input source items accessible [Florian; #684462]
* Don't show network dialogs in the lock screen [Giovanni; #684384]
* popupMenu: Fix initial visibility of settings items [Florian; #684473]
* userMenu: Close menu immediately on user/session switch [Florian; #684459]
* Fix alignment of search section headers in RTL locales [Florian; #684379]
* screenShield: Fix unlock animation [Florian; #684591]
* Don't open the tray from a dwell while in a modal grab [Jasper; #684458]
* userMenu: Fix texture updates on icon changes [Florian; #679268]
* Fix a11y support in the login screen [Florian, Ray; #684727, #684728, #684748]
* Make On-Screen-Keyboard usable with new message tray [Giovanni, Florian;
#683546]
* Fix initial visibility of input volume in lock-screen [Florian; #684611]
Contributors:
Giovanni Campagna, Florian Müllner, Jasper St. Pierre, Ray Strode
Translations:
Matej Urbančič [sl], Dr.T.Vasudevan [ta], Piotr Drąg [pl], A S Alam [pa],
Alexander Shopov [bg], Nilamdyuti Goswami [as], Chandan Kumar [hi],
Khaled Hosny [ar], Ibrahim Saed [ar], Sandeep Sheshrao Shedmake [mr],
Tom Tryfonidis [el], Theppitak Karoonboonyanan [th], Alexandre Franke [fr],
Fran Diéguez [gl], Gabor Kelemen [hu], Ani Peter [ml], Daniel Mustieles [es],
Мирослав Николић [sr, sr@latin], Duarte Loreto [pt], ManojKumar Giri [or],
Ihar Hrachyshka [be], Aurimas Černius [lt], Djavan Fagundes [pt_BR],
Changwoo Ryu [ko], Bruce Cowan [en_GB], Kris Thomsen [da], Gil Forcada [ca],
Yaron Shahrabani [he], Milo Casagrande [it], Ville-Pekka Vainio [fi],
YunQiang Su [zh_CN], Carles Ferrando [ca@valencia], Mario Blättermann [de],
Rajesh Ranjan [hi], Yuri Myasoedov [ru], Rūdolfs Mazurs [lv],
Jiro Matsuzawa [ja], Mattias Põldaru [et], Timur Zhamakeev [ky],
Petr Kovar [cs], Chao-Hsiung Liao [zh_HK,zh_TW], Andika Triwidada [id]
3.5.92
======
* Login/UnlockDialog: Don't reset immediately if auth fails [Giovanni; #682544]
* Allow changing session mode at runtime [Jasper, Giovanni; #683156]
* Add zoom out animation on login [Jasper; #683170]
* Bluetooth: don't restrict the length of non numeric PINs [Giovanni; #683356]
* Force chat notification to stay open when focusing entry [Debarshi; #682236]
* Make sure the screen is fully locked before suspending [Giovanni; #683448]
* st-texture-cache: Fix a case of distorted textures [Florian; #683483]
* popupSubMenu: Fix padding for non-scrolled submenus [Florian; #683009]
* popupMenu: Fix width changes on submenu open/close [Florian; #683485]
* boxpointer: Avoid malformed boxpointer arrow [Debarshi; #680077]
* Change stage background color to grey [Adel; #683514]
* messageTray: Update style of summary counters [Debarshi; #682891]
* Don't fail if a legacy tray icon has no WM_CLASS [Giovanni; #683724]
* PolkitAgent: Fix a crash if there is no avatar [Giovanni; #683707]
* Hide the a11y menu in the lock screen, but show it in the login screen
[Giovanni; #682542]
* Fix show-apps button dropping off the dash [Florian; #683340]
* Fix committing strings to shell entries from input method [Florian; #658325]
* Make IBus display strings consistent with control-center [Rui; #683124]
* Fix missing short codes for some input sources [Rui; #683613]
* Remove support for long-press from entry context menus [Jasper; #683509]
* screenShield: Add box-shadow to the shield [Florian]
* Don't show a right-click menu for the hotplug source [Jasper; #683438]
* Fix extension styling [Giovanni; #682128]
* Fix on-screen keyboard not working with system-modal dialogs
[Giovanni; #664309]
* Fix insensitive styling for popup menu items [Giovanni; #683988]
* Disable the message tray dwell when the user is interacting [Owen; #683811]
* Animate going from the unlock dialog to the lock screen [Giovanni; #681143]
* Autostart fprintd when necessary [Ray; #683131]
* UnlockDialog: Allow typing before the first PAM question [Giovanni; #681576]
* Make Return key dismiss screenshield [Ray; #683889]
* Fix keyboard navigation in the message tray [Florian; #682243]
* Remove the places & devices search provider [Giovanni; #683506]
* Enable hot corner while the message tray is up [Florian; #682255]
* Port screen recorder to new GStreamer vp8enc API [Adel; #684206]
* Fix fish flickering [Giovanni; #684154]
* Fix extension ordering with !important [Jasper; #684163]
* Allow the shell to run without the screenshield [Giovanni; #683060]
* Add menu items for IBus Anthy's InputMode, TypingMode [Rui; #682314]
* Improve transition to the login dialog [Jasper; #682428]
* Keep unlock dialog around until shield animation ends [Florian; #684342]
* Expose shell keybindings in System Settings [Florian; #671010]
* Misc. bugfixes and cleanups [Debarshi, Florian, Giovanni, Jasper, Rico, Rui;
#672790, #677434, #683305, #683357, #683369, #683377, #683378, #683400,
#683449, #683472, #683482, #683487, #683488, #683526, #683529, #683546,
#683583, #683628, #683705, #683982, #683989, #684035, #684036, #684040,
#684162, #684214, #684343]
Contributors:
Giovanni Campagna, Adel Gadllah, Rui Matos, Florian Müllner, Debarshi Ray,
Jasper St. Pierre, Ray Strode, Owen Taylor, Rico Tzschichholz
Translations:
Gabor Kelemen [hu], Piotr Drąg [pl], Khaled Hosny [ar],
Мирослав Николић [sr, sr@latin], Chao-Hsiung Liao [zh_HK, zh_TW],
Bruce Cowan [en_GB], Dirgita [id], Tom Tryfonidis [el], Timo Jyrinki [fi],
Adorilson Bezerra [pt_BR], Arash Mousavi [fa], Matej Urbančič [sl],
Christian Kirbach [de], Yaron Shahrabani [he], Ihar Hrachyshka [be],
Changwoo Ryu [ko], Duarte Loreto [pt], Theppitak Karoonboonyanan [th],
Nilamdyuti Goswami [as], Sandeep Sheshrao Shedmake [mr],
Alexandre Franke [fr], Ivaylo Valkov [bg], tuhaihe [zh_CN],
Yuri Myasoedov [ru], Aurimas Černius [lt], Andika Triwidada [id],
Rajesh Ranjan [hi], Sweta Kothari [gu], Daniel Mustieles [es],
Fran Diéguez [gl], Praveen Illa [te]
3.5.91
======
* Improve modal dialog styling of network secret prompts [Jasper; #682412]

View File

@ -1,5 +1,5 @@
AC_PREREQ(2.63)
AC_INIT([gnome-shell],[3.5.91],[https://bugzilla.gnome.org/enter_bug.cgi?product=gnome-shell],[gnome-shell])
AC_INIT([gnome-shell],[3.6.0],[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.11.11
GOBJECT_INTROSPECTION_MIN_VERSION=0.10.1
GJS_MIN_VERSION=1.33.2
MUTTER_MIN_VERSION=3.5.91
MUTTER_MIN_VERSION=3.6.0
GTK_MIN_VERSION=3.3.9
GIO_MIN_VERSION=2.31.6
LIBECAL_MIN_VERSION=3.5.3
@ -106,6 +106,9 @@ PKG_CHECK_MODULES(SHELL_HOTPLUG_SNIFFER, gio-2.0 gdk-pixbuf-2.0)
PKG_CHECK_MODULES(BROWSER_PLUGIN, gio-2.0 >= $GIO_MIN_VERSION json-glib-1.0 >= 0.13.2)
GNOME_KEYBINDINGS_KEYSDIR=`$PKG_CONFIG --variable keysdir gnome-keybindings`
AC_SUBST([GNOME_KEYBINDINGS_KEYSDIR])
GOBJECT_INTROSPECTION_CHECK([$GOBJECT_INTROSPECTION_MIN_VERSION])
saved_CFLAGS=$CFLAGS

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8" ?>
<KeyListEntries schema="org.gnome.shell.keybindings"
group="system"
_name="Screenshots"
wm_name="GNOME Shell"
package="gnome-shell">
<KeyListEntry name="toggle-recording"
_description="Record a screencast"/>
</KeyListEntries>

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8" ?>
<KeyListEntries schema="org.gnome.shell.keybindings"
group="system"
_name="System"
wm_name="GNOME Shell"
package="gnome-shell">
<KeyListEntry name="toggle-message-tray"
_description="Show the message tray"/>
</KeyListEntries>

View File

@ -39,6 +39,7 @@ dist_theme_DATA = \
theme/process-working.svg \
theme/running-indicator.svg \
theme/source-button-border.svg \
theme/summary-counter.svg \
theme/toggle-off-us.svg \
theme/toggle-off-intl.svg \
theme/toggle-on-us.svg \
@ -46,6 +47,13 @@ dist_theme_DATA = \
theme/ws-switch-arrow-up.png \
theme/ws-switch-arrow-down.png
keysdir = @GNOME_KEYBINDINGS_KEYSDIR@
keys_in_files = \
50-gnome-shell-screenshot.xml.in \
50-gnome-shell-system.xml.in \
$(NULL)
keys_DATA = $(keys_in_files:.xml.in=.xml)
gsettings_SCHEMAS = org.gnome.shell.gschema.xml
@INTLTOOL_XML_NOMERGE_RULE@
@ -72,12 +80,14 @@ EXTRA_DIST = \
$(introspection_DATA) \
$(menu_DATA) \
$(convert_DATA) \
$(keys_in_files) \
org.gnome.shell.gschema.xml.in.in
CLEANFILES = \
gnome-shell.desktop.in \
gnome-shell-extension-prefs.in \
$(desktop_DATA) \
$(keys_DATA) \
$(gsettings_SCHEMAS) \
gschemas.compiled \
org.gnome.shell.gschema.valid \

View File

@ -108,7 +108,7 @@
</doc:summary>
</doc:doc>
</arg>
<arg type="a{sv}" direction="out">
<arg type="aa{sv}" direction="out">
<doc:doc>
<doc:summary>
<doc:para>

View File

@ -39,10 +39,6 @@
will be displayed in the favorites area.
</_description>
</key>
<key name="disabled-open-search-providers" type="as">
<default>[]</default>
<_summary>disabled OpenSearch providers</_summary>
</key>
<key name="command-history" type="as">
<default>[]</default>
<_summary>History for command (Alt-F2) dialog</_summary>
@ -136,7 +132,7 @@ value here is from the GsmPresenceStatus enumeration.</_summary>
take care of its own output - this might be used to send the output
to an icecast server via shout2send or similar. When unset or set
to an empty value, the default pipeline will be used. This is currently
'vp8enc quality=8 speed=6 threads=%T ! queue ! webmmux'
'vp8enc min_quantizer=13 max_quantizer=13 cpu-used=5 deadline=1000000 threads=%T ! queue ! webmmux'
and records to WEBM using the VP8 codec. %T is used as a placeholder
for a guess at the optimal thread count on the system.
</_description>

View File

@ -151,11 +151,11 @@ StScrollBar StButton#vhandle:active {
box-shadow: inset 0px 2px 4px rgba(0,0,0,0.9);
}
.popup-sub-menu .popup-menu-item:ltr {
.popup-sub-menu:scrolled .popup-menu-item:ltr {
padding-right: 0em;
}
.popup-sub-menu .popup-menu-item:rtl {
.popup-sub-menu:scrolled .popup-menu-item:rtl {
padding-left: 0em;
}
@ -195,7 +195,7 @@ StScrollBar StButton#vhandle:active {
background-color: #4c4c4c;
}
StButton.popup-menu-item:insensitive {
.popup-menu-item:insensitive {
color: #9f9f9f;
}
@ -234,13 +234,18 @@ StButton.popup-menu-item:insensitive {
spacing: .5em;
}
.popup-inactive-menu-item {
.popup-status-menu-item {
font-weight: normal;
color: #999;
}
.popup-subtitle-menu-item {
.popup-inactive-menu-item, .popup-inactive-menu-item:insensitive {
color: white;
}
.popup-subtitle-menu-item, .popup-subtitle-menu-item:insensitive {
font-weight: bold;
color: white;
}
.popup-menu-icon {
@ -720,10 +725,6 @@ StButton.popup-menu-item:insensitive {
spacing: 4px;
}
.search-providers-box {
spacing: 12px;
}
/* Text labels are an odd number of pixels tall. The uneven top and bottom
* padding compensates for this and ensures that the label is vertically
* centered */
@ -1193,6 +1194,11 @@ StButton.popup-menu-item:insensitive {
height: 72px;
}
#message-tray:keyboard {
/* Same as the OSK */
background: rgba(0, 0, 0, 0.8);
}
#message-tray:overview {
background: rgba(0, 0, 0, 0.1);
border-top: 1px solid rgba(128, 128, 128, 0.3);
@ -1442,13 +1448,14 @@ StButton.popup-menu-item:insensitive {
}
.summary-source-counter {
color: white;
background-color: #3465A4;
text-shadow: black 1px 1px 0;
font-size: 9pt;
border-radius: 1em;
min-height: 1em;
min-width: 1em;
background-image: url("summary-counter.svg");
background-size: 2.5em;
font-size: 10pt;
font-weight: bold;
height: 2.5em;
width: 2.5em;
-shell-counter-overlap-x: 4px;
-shell-counter-overlap-y: 4px;
}
/* App Switcher */
@ -2189,12 +2196,21 @@ StButton.popup-menu-item:insensitive {
background-gradient-end: #74a0d0;
}
.login-dialog-message-warning {
color: orange;
}
.unlock-dialog-user-name-container {
spacing: .4em;
}
/* Screen shield */
.screen-shield-background {
background: black;
box-shadow: 0px 4px 8px rgba(0,0,0,0.9);
}
#lockDialogGroup {
background: #2e3436 url(noise-texture.png);
background-repeat: repeat;

View File

@ -0,0 +1,120 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Generator: Adobe Illustrator 13.0.2, SVG Export Plug-In . SVG Version: 6.00 Build 14948) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
version="1.0"
id="Foreground"
x="0px"
y="0px"
width="32"
height="32"
viewBox="0 0 23.272727 23.272727"
enable-background="new 0 0 16 16"
xml:space="preserve"
sodipodi:version="0.32"
inkscape:version="0.48.2 r9819"
sodipodi:docname="summary-counter.svg"
inkscape:output_extension="org.inkscape.output.svg.inkscape"><metadata
id="metadata2399"><rdf:RDF><cc:Work
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title /></cc:Work></rdf:RDF></metadata><defs
id="defs2397"><linearGradient
id="linearGradient3173"><stop
style="stop-color:#c4c4c4;stop-opacity:1;"
offset="0"
id="stop3175" /><stop
style="stop-color:#ffffff;stop-opacity:1;"
offset="1"
id="stop3177" /></linearGradient><inkscape:perspective
sodipodi:type="inkscape:persp3d"
inkscape:vp_x="0 : 8 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_z="16 : 8 : 1"
inkscape:persp3d-origin="8 : 5.3333333 : 1"
id="perspective2401" /><filter
color-interpolation-filters="sRGB"
inkscape:collect="always"
id="filter16494-4"
x="-0.20989846"
width="1.4197969"
y="-0.20903821"
height="1.4180764"><feGaussianBlur
inkscape:collect="always"
stdDeviation="1.3282637"
id="feGaussianBlur16496-8" /></filter><radialGradient
inkscape:collect="always"
xlink:href="#linearGradient16498-6"
id="radialGradient16504-1"
cx="7.6582627"
cy="5.8191104"
fx="7.6582627"
fy="5.8191104"
r="8.6928644"
gradientTransform="matrix(1.0474339,0,0,1.0517402,-0.3632615,-0.42032492)"
gradientUnits="userSpaceOnUse" /><linearGradient
inkscape:collect="always"
id="linearGradient16498-6"><stop
style="stop-color:#9FD0FF;stop-opacity:1"
offset="0"
id="stop16500-8" /><stop
style="stop-color:#3465A4;stop-opacity:1"
offset="1"
id="stop16502-0" /></linearGradient></defs><sodipodi:namedview
inkscape:window-height="709"
inkscape:window-width="1366"
inkscape:pageshadow="2"
inkscape:pageopacity="0"
guidetolerance="10.0"
gridtolerance="10.0"
objecttolerance="10.0"
borderopacity="1.0"
bordercolor="#666666"
pagecolor="#000000"
id="base"
showgrid="false"
inkscape:zoom="11.313708"
inkscape:cx="15.386407"
inkscape:cy="13.739577"
inkscape:window-x="0"
inkscape:window-y="1179"
inkscape:current-layer="g16402-8"
showguides="true"
inkscape:guide-bbox="true"
borderlayer="true"
inkscape:showpageshadow="false"
inkscape:window-maximized="1"><inkscape:grid
type="xygrid"
id="grid11246"
empspacing="5"
visible="true"
enabled="true"
snapvisiblegridlinesonly="true" /></sodipodi:namedview><g
style="display:inline"
id="g16402-8"
transform="translate(4.7533483,2.8238929)"><g
id="g3175-4"
transform="translate(-0.89995416,0.94028614)"><path
sodipodi:type="inkscape:offset"
inkscape:radius="0"
inkscape:original="M 7.65625 0.125 C 3.2589349 0.125 -0.3125 3.7070002 -0.3125 8.125 C -0.3125 12.543001 3.2589349 16.125 7.65625 16.125 C 12.053566 16.125 15.625 12.543001 15.625 8.125 C 15.625 3.7070002 12.053566 0.125 7.65625 0.125 z "
xlink:href="#path2394-32"
style="opacity:0.52994014;color:#000000;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:2.18181825;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;filter:url(#filter16494-4);enable-background:accumulate"
id="path16480-5"
inkscape:href="#path2394-32"
d="m 7.65625,0.125 c -4.3973151,0 -7.96875,3.5820002 -7.96875,8 0,4.418001 3.5714349,8 7.96875,8 4.397316,0 7.96875,-3.581999 7.96875,-8 0,-4.4179998 -3.571434,-8 -7.96875,-8 z"
transform="translate(0,1.028519)" /><path
clip-rule="evenodd"
d="m -0.30428257,8.1237596 c 0,-4.4179998 3.56522987,-7.9999996 7.96254497,-7.9999996 4.3973156,0 7.9625456,3.5819998 7.9625456,7.9999996 0,4.4180014 -3.56523,8.0000004 -7.9625456,8.0000004 -4.3973151,0 -7.96254497,-3.581999 -7.96254497,-8.0000004 z"
id="path2394-32"
style="color:#000000;fill:url(#radialGradient16504-1);fill-opacity:1;fill-rule:nonzero;stroke:#eeeeec;stroke-width:1.4545455;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
sodipodi:nodetypes="csssc"
inkscape:connector-curvature="0" /><g
id="g3172-6" /></g></g></svg>

After

Width:  |  Height:  |  Size: 5.4 KiB

View File

@ -29,8 +29,6 @@
<chapter>
<title>Search</title>
<xi:include href="xml/shell-app-system.xml"/>
<xi:include href="xml/shell-contact-system.xml"/>
<xi:include href="xml/shell-doc-system.xml"/>
</chapter>
<chapter>
<title>Tray Icons</title>
@ -42,7 +40,6 @@
<chapter>
<title>Recorder</title>
<xi:include href="xml/shell-recorder.xml"/>
<xi:include href="xml/shell-recorder-src.xml"/>
</chapter>
<chapter>
<title>Integration helpers and utilities</title>

View File

@ -1,3 +1,4 @@
NULL =
EXTRA_DIST = misc/config.js.in
CLEANFILES = misc/config.js
@ -37,8 +38,6 @@ nobase_dist_js_DATA = \
ui/altTab.js \
ui/appDisplay.js \
ui/appFavorites.js \
ui/automountManager.js \
ui/autorunManager.js \
ui/boxpointer.js \
ui/calendar.js \
ui/checkBox.js \
@ -47,15 +46,14 @@ nobase_dist_js_DATA = \
ui/dateMenu.js \
ui/dnd.js \
ui/endSessionDialog.js \
ui/environment.js \
ui/extensionSystem.js \
ui/extensionDownloader.js \
ui/environment.js \
ui/flashspot.js \
ui/ibusCandidatePopup.js\
ui/grabHelper.js \
ui/iconGrid.js \
ui/keyboard.js \
ui/keyringPrompt.js \
ui/layout.js \
ui/lightbox.js \
ui/lookingGlass.js \
@ -64,7 +62,6 @@ nobase_dist_js_DATA = \
ui/main.js \
ui/messageTray.js \
ui/modalDialog.js \
ui/networkAgent.js \
ui/sessionMode.js \
ui/shellEntry.js \
ui/shellMountOperation.js \
@ -72,9 +69,7 @@ nobase_dist_js_DATA = \
ui/overview.js \
ui/panel.js \
ui/panelMenu.js \
ui/placeDisplay.js \
ui/pointerWatcher.js \
ui/polkitAuthenticationAgent.js \
ui/popupMenu.js \
ui/remoteSearch.js \
ui/runDialog.js \
@ -90,7 +85,6 @@ nobase_dist_js_DATA = \
ui/status/power.js \
ui/status/volume.js \
ui/status/bluetooth.js \
ui/telepathyClient.js \
ui/tweener.js \
ui/unlockDialog.js \
ui/userMenu.js \
@ -102,4 +96,13 @@ nobase_dist_js_DATA = \
ui/workspaceThumbnail.js \
ui/workspacesView.js \
ui/workspaceSwitcherPopup.js \
ui/xdndHandler.js
ui/xdndHandler.js \
ui/components/__init__.js \
ui/components/autorunManager.js \
ui/components/automountManager.js \
ui/components/networkAgent.js \
ui/components/polkitAgent.js \
ui/components/recorder.js \
ui/components/telepathyClient.js \
ui/components/keyring.js \
$(NULL)

View File

@ -19,8 +19,7 @@ function FprintManager() {
g_interface_info: FprintManagerInfo,
g_name: 'net.reactivated.Fprint',
g_object_path: '/net/reactivated/Fprint/Manager',
g_flags: (Gio.DBusProxyFlags.DO_NOT_AUTO_START |
Gio.DBusProxyFlags.DO_NOT_LOAD_PROPERTIES) });
g_flags: (Gio.DBusProxyFlags.DO_NOT_LOAD_PROPERTIES) });
self.init(null);
return self;

View File

@ -105,6 +105,7 @@ const UserListItem = new Lang.Class({
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,
@ -471,6 +472,7 @@ const SessionListItem = new Lang.Class({
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);
},
@ -625,8 +627,8 @@ const LoginDialog = new Lang.Class({
_init: function(parentActor) {
this.parent({ shellReactive: true,
styleClass: 'login-dialog',
parentActor: parentActor
});
parentActor: parentActor,
shouldFadeIn: false });
this.connect('destroy',
Lang.bind(this, this._onDestroy));
this.connect('opened',
@ -647,9 +649,8 @@ const LoginDialog = new Lang.Class({
this._userVerifier = new GdmUtil.ShellUserVerifier(this._greeterClient);
this._userVerifier.connect('ask-question', Lang.bind(this, this._askQuestion));
this._userVerifier.connect('verification-failed', Lang.bind(this, this._onVerificationFailed));
this._userVerifier.connect('show-message', Lang.bind(this, this._showMessage));
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));
@ -715,6 +716,10 @@ const LoginDialog = new Lang.Class({
x_fill: true,
y_fill: false,
x_align: St.Align.START });
this._promptMessage = new St.Label({ visible: false });
this._promptBox.add(this._promptMessage, { x_fill: true });
this._promptLoginHint = new St.Label({ style_class: 'login-dialog-prompt-login-hint-message' });
this._promptLoginHint.hide();
this._promptBox.add(this._promptLoginHint);
@ -797,6 +802,8 @@ const LoginDialog = new Lang.Class({
},
_onReset: function(client, serviceName) {
this._promptMessage.hide();
let tasks = [this._hidePrompt,
new Batch.ConcurrentBatch(this, [this._fadeInTitleLabel,
@ -826,6 +833,12 @@ const LoginDialog = new Lang.Class({
this._sessionList.setActiveSession(sessionId);
},
_showMessage: function(userVerifier, message, styleClass) {
this._promptMessage.text = message;
this._promptMessage.styleClass = styleClass;
GdmUtil.fadeInActor(this._promptMessage);
},
_showLoginHint: function(verifier, message) {
this._promptLoginHint.set_text(message)
GdmUtil.fadeInActor(this._promptLoginHint);
@ -1081,10 +1094,6 @@ const LoginDialog = new Lang.Class({
}));
},
_onVerificationFailed: function() {
this._userVerifier.cancel();
},
_onNotListedClicked: function(user) {
let tasks = [function() {
return this._userList.hideItems();

View File

@ -31,7 +31,8 @@ const PowerMenuButton = new Lang.Class({
Extends: PanelMenu.SystemStatusButton,
_init: function() {
this.parent('system-shutdown-symbolic', null);
/* Translators: accessible name of the power menu in the login screen */
this.parent('system-shutdown-symbolic', _("Power"));
this._upClient = new UPowerGlib.Client();
this._loginManager = LoginManager.getLoginManager();

View File

@ -2,6 +2,7 @@
const Gio = imports.gi.Gio;
const Lang = imports.lang;
const Mainloop = imports.mainloop;
const Signals = imports.signals;
const Batch = imports.gdm.batch;
@ -19,6 +20,7 @@ const LOGIN_SCREEN_SCHEMA = 'org.gnome.login-screen';
const FINGERPRINT_AUTHENTICATION_KEY = 'enable-fingerprint-authentication';
const BANNER_MESSAGE_KEY = 'banner-message-enable';
const BANNER_MESSAGE_TEXT_KEY = 'banner-message-text';
const ALLOWED_FAILURES_KEY = 'allowed-failures';
const LOGO_KEY = 'logo';
@ -81,6 +83,8 @@ const ShellUserVerifier = new Lang.Class({
this._fprintManager = new Fprint.FprintManager();
this._realmManager = new Realmd.Manager();
this._failCounter = 0;
},
begin: function(userName, hold) {
@ -137,34 +141,43 @@ const ShellUserVerifier = new Lang.Class({
}));
},
_reportInitError: function(where, error) {
logError(error, where);
this._hold.relase();
this.emit('show-message', _("Authentication error"), 'login-dialog-message-warning');
this._verificationFailed(false);
},
_reauthenticationChannelOpened: function(client, result) {
try {
this._userVerifier = client.open_reauthentication_channel_finish(result);
this._connectSignals();
this._beginVerification();
this._hold.release();
} catch (e) {
if (this._reauthOnly) {
if (e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED))
return;
logError(e, 'Failed to open reauthentication channel');
this.emit('verification-failed');
this._hold.release();
return;
}
// If there's no session running, or it otherwise fails, then fall back
// to performing verification from this login session
} catch(e if e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) {
return;
} catch(e if e.matches(Gio.DBusError, Gio.DBusError.ACCESS_DENIED) &&
!this._reauthOnly) {
// Gdm emits org.freedesktop.DBus.Error.AccessDenied when there is
// no session to reauthenticate. Fall back to performing verification
// from this login session
client.get_user_verifier(this._cancellable, Lang.bind(this, this._userVerifierGot));
return;
} catch(e) {
this._reportInitError('Failed to open reauthentication channel', e);
return;
}
this._connectSignals();
this._beginVerification();
this._hold.release();
},
_userVerifierGot: function(client, result) {
try {
this._userVerifier = client.get_user_verifier_finish(result);
} catch(e if e.matches(Gio.IOErrorEnum, Gio.ErrorEnum.CANCELLED)) {
} catch(e if e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) {
return;
} catch(e) {
this._reportInitError('Failed to obtain user verifier', e);
return;
}
@ -195,6 +208,9 @@ const ShellUserVerifier = new Lang.Class({
obj.call_begin_verification_for_user_finish(result);
} catch(e if e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) {
return;
} catch(e) {
this._reportInitError('Failed to start verification for user', e);
return;
}
this._hold.release();
@ -211,6 +227,9 @@ const ShellUserVerifier = new Lang.Class({
obj.call_begin_verification_for_user_finish(result);
} catch(e if e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) {
return;
} catch(e) {
this._reportInitError('Failed to start fingerprint verification for user', e);
return;
}
this._hold.release();
@ -224,6 +243,9 @@ const ShellUserVerifier = new Lang.Class({
obj.call_begin_verification_finish(result);
} catch(e if e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) {
return;
} catch(e) {
this._reportInitError('Failed to start verification', e);
return;
}
this._hold.release();
@ -242,7 +264,7 @@ const ShellUserVerifier = new Lang.Class({
// to indicate the user can swipe their finger instead
this.emit('show-login-hint', _("(or swipe finger)"));
} else if (serviceName == PASSWORD_SERVICE_NAME) {
Main.notifyError(info);
this.emit('show-message', info, 'login-dialog-message-info');
}
},
@ -251,7 +273,7 @@ const ShellUserVerifier = new Lang.Class({
// users who haven't enrolled their fingerprint.
if (serviceName != PASSWORD_SERVICE_NAME)
return;
Main.notifyError(problem);
this.emit('show-message', problem, 'login-dialog-message-warning');
},
_showRealmLoginHint: function() {
@ -290,8 +312,10 @@ const ShellUserVerifier = new Lang.Class({
},
_onReset: function() {
this._userVerifier.run_dispose();
this._userVerifier = null;
this.clear();
// Clear previous attempts to authenticate
this._failCounter = 0;
this.emit('reset');
},
@ -300,12 +324,38 @@ const ShellUserVerifier = new Lang.Class({
this.emit('verification-complete');
},
_verificationFailed: function(retry) {
// For Not Listed / enterprise logins, immediately reset
// the dialog
// Otherwise, we allow ALLOWED_FAILURES attempts. After that, we
// go back to the welcome screen.
let canRetry = retry && this._userName &&
this._failCounter < this._settings.get_int(ALLOWED_FAILURES_KEY);
if (canRetry) {
this._failCounter++;
this.clear();
this.begin(this._userName, new Batch.Hold());
} else {
// Allow some time to see the message, then reset everything
Mainloop.timeout_add(3000, Lang.bind(this, function() {
this.cancel();
this._onReset();
}));
}
this.emit('verification-failed');
},
_onConversationStopped: function(client, serviceName) {
// if the password service fails, then cancel everything.
// But if, e.g., fingerprint fails, still give
// password authentication a chance to succeed
if (serviceName == PASSWORD_SERVICE_NAME) {
this.emit('verification-failed');
this._verificationFailed(true);
}
this.emit('hide-login-hint');

View File

@ -41,24 +41,26 @@ const HistoryManager = new Lang.Class({
this._historyIndex = this._history.length;
},
prevItem: function(text) {
_setPrevItem: function(text) {
if (this._historyIndex <= 0)
return text;
return false;
if (text)
this._history[this._historyIndex] = text;
this._historyIndex--;
return this._indexChanged();
this._indexChanged();
return true;
},
nextItem: function(text) {
_setNextItem: function(text) {
if (this._historyIndex >= this._history.length)
return text;
return false;
if (text)
this._history[this._historyIndex] = text;
this._historyIndex++;
return this._indexChanged();
this._indexChanged();
return true;
},
lastItem: function() {
@ -83,11 +85,9 @@ const HistoryManager = new Lang.Class({
_onEntryKeyPress: function(entry, event) {
let symbol = event.get_key_symbol();
if (symbol == Clutter.KEY_Up) {
this.prevItem(entry.get_text());
return true;
return this._setPrevItem(entry.get_text());
} else if (symbol == Clutter.KEY_Down) {
this.nextItem(entry.get_text());
return true;
return this._setNextItem(entry.get_text());
}
return false;
},
@ -98,8 +98,6 @@ const HistoryManager = new Lang.Class({
if (this._entry)
this._entry.set_text(current);
return current;
},
_save: function() {

View File

@ -274,14 +274,51 @@ const BoxPointer = new Lang.Class({
let [x1, y1] = [halfBorder, halfBorder];
let [x2, y2] = [boxWidth - halfBorder, boxHeight - halfBorder];
let skipTopLeft = false;
let skipTopRight = false;
let skipBottomLeft = false;
let skipBottomRight = false;
switch (this._arrowSide) {
case St.Side.TOP:
if (this._arrowOrigin == x1)
skipTopLeft = true;
else if (this._arrowOrigin == x2)
skipTopRight = true;
break;
case St.Side.RIGHT:
if (this._arrowOrigin == y1)
skipTopRight = true;
else if (this._arrowOrigin == y2)
skipBottomRight = true;
break;
case St.Side.BOTTOM:
if (this._arrowOrigin == x1)
skipBottomLeft = true;
else if (this._arrowOrigin == x2)
skipBottomRight = true;
break;
case St.Side.LEFT:
if (this._arrowOrigin == y1)
skipTopLeft = true;
else if (this._arrowOrigin == y2)
skipBottomLeft = true;
break;
}
cr.moveTo(x1 + borderRadius, y1);
if (this._arrowSide == St.Side.TOP) {
if (this._arrowOrigin < (x1 + (borderRadius + halfBase))) {
cr.lineTo(this._arrowOrigin, y1 - rise);
cr.lineTo(Math.max(x1 + borderRadius, this._arrowOrigin) + halfBase, y1);
} else if (this._arrowOrigin > (x2 - (borderRadius + halfBase))) {
cr.lineTo(Math.min(x2 - borderRadius, this._arrowOrigin) - halfBase, y1);
cr.lineTo(this._arrowOrigin, y1 - rise);
if (skipTopLeft) {
cr.moveTo(x1, y2 - borderRadius);
cr.lineTo(x1, y1 - rise);
cr.lineTo(x1 + halfBase, y1);
} else if (skipTopRight) {
cr.lineTo(x2 - halfBase, y1);
cr.lineTo(x2, y1 - rise);
cr.lineTo(x2, y1 + borderRadius);
} else {
cr.lineTo(this._arrowOrigin - halfBase, y1);
cr.lineTo(this._arrowOrigin, y1 - rise);
@ -289,19 +326,20 @@ const BoxPointer = new Lang.Class({
}
}
cr.lineTo(x2 - borderRadius, y1);
// top-right corner
cr.arc(x2 - borderRadius, y1 + borderRadius, borderRadius,
3*Math.PI/2, Math.PI*2);
if (!skipTopRight) {
cr.lineTo(x2 - borderRadius, y1);
cr.arc(x2 - borderRadius, y1 + borderRadius, borderRadius,
3*Math.PI/2, Math.PI*2);
}
if (this._arrowSide == St.Side.RIGHT) {
if (this._arrowOrigin < (y1 + (borderRadius + halfBase))) {
cr.lineTo(x2 + rise, this._arrowOrigin);
cr.lineTo(x2, Math.max(y1 + borderRadius, this._arrowOrigin) + halfBase);
} else if (this._arrowOrigin > (y2 - (borderRadius + halfBase))) {
cr.lineTo(x2, Math.min(y2 - borderRadius, this._arrowOrigin) - halfBase);
cr.lineTo(x2 + rise, this._arrowOrigin);
if (skipTopRight) {
cr.lineTo(x2 + rise, y1);
cr.lineTo(x2 + rise, y1 + halfBase);
} else if (skipBottomRight) {
cr.lineTo(x2, y2 - halfBase);
cr.lineTo(x2 + rise, y2);
cr.lineTo(x2 - borderRadius, y2);
} else {
cr.lineTo(x2, this._arrowOrigin - halfBase);
cr.lineTo(x2 + rise, this._arrowOrigin);
@ -309,19 +347,20 @@ const BoxPointer = new Lang.Class({
}
}
cr.lineTo(x2, y2 - borderRadius);
// bottom-right corner
cr.arc(x2 - borderRadius, y2 - borderRadius, borderRadius,
0, Math.PI/2);
if (!skipBottomRight) {
cr.lineTo(x2, y2 - borderRadius);
cr.arc(x2 - borderRadius, y2 - borderRadius, borderRadius,
0, Math.PI/2);
}
if (this._arrowSide == St.Side.BOTTOM) {
if (this._arrowOrigin < (x1 + (borderRadius + halfBase))) {
cr.lineTo(Math.max(x1 + borderRadius, this._arrowOrigin) + halfBase, y2);
cr.lineTo(this._arrowOrigin, y2 + rise);
} else if (this._arrowOrigin > (x2 - (borderRadius + halfBase))) {
cr.lineTo(this._arrowOrigin, y2 + rise);
cr.lineTo(Math.min(x2 - borderRadius, this._arrowOrigin) - halfBase, y2);
if (skipBottomLeft) {
cr.lineTo(x1 + halfBase, y2);
cr.lineTo(x1, y2 + rise);
cr.lineTo(x1, y2 - borderRadius);
} else if (skipBottomRight) {
cr.lineTo(x2, y2 + rise);
cr.lineTo(x2 - halfBase, y2);
} else {
cr.lineTo(this._arrowOrigin + halfBase, y2);
cr.lineTo(this._arrowOrigin, y2 + rise);
@ -329,19 +368,20 @@ const BoxPointer = new Lang.Class({
}
}
cr.lineTo(x1 + borderRadius, y2);
// bottom-left corner
cr.arc(x1 + borderRadius, y2 - borderRadius, borderRadius,
Math.PI/2, Math.PI);
if (!skipBottomLeft) {
cr.lineTo(x1 + borderRadius, y2);
cr.arc(x1 + borderRadius, y2 - borderRadius, borderRadius,
Math.PI/2, Math.PI);
}
if (this._arrowSide == St.Side.LEFT) {
if (this._arrowOrigin < (y1 + (borderRadius + halfBase))) {
cr.lineTo(x1, Math.max(y1 + borderRadius, this._arrowOrigin) + halfBase);
cr.lineTo(x1 - rise, this._arrowOrigin);
} else if (this._arrowOrigin > (y2 - (borderRadius + halfBase))) {
cr.lineTo(x1 - rise, this._arrowOrigin);
cr.lineTo(x1, Math.min(y2 - borderRadius, this._arrowOrigin) - halfBase);
if (skipTopLeft) {
cr.lineTo(x1, y1 + halfBase);
cr.lineTo(x1 - rise, y1);
cr.lineTo(x1 + borderRadius, y1);
} else if (skipBottomLeft) {
cr.lineTo(x1 - rise, y2)
cr.lineTo(x1 - rise, y2 - halfBase);
} else {
cr.lineTo(x1, this._arrowOrigin + halfBase);
cr.lineTo(x1 - rise, this._arrowOrigin);
@ -349,11 +389,11 @@ const BoxPointer = new Lang.Class({
}
}
cr.lineTo(x1, y1 + borderRadius);
// top-left corner
cr.arc(x1 + borderRadius, y1 + borderRadius, borderRadius,
Math.PI, 3*Math.PI/2);
if (!skipTopLeft) {
cr.lineTo(x1, y1 + borderRadius);
cr.arc(x1 + borderRadius, y1 + borderRadius, borderRadius,
Math.PI, 3*Math.PI/2);
}
Clutter.cairo_set_source_color(cr, backgroundColor);
cr.fillPreserve();
@ -406,9 +446,7 @@ const BoxPointer = new Lang.Class({
let arrowBase = themeNode.get_length('-arrow-base');
let borderRadius = themeNode.get_length('-arrow-border-radius');
let margin = (4 * borderRadius + borderWidth + arrowBase);
let halfMargin = margin / 2;
let themeNode = this.actor.get_theme_node();
let gap = themeNode.get_length('-boxpointer-gap');
let padding = themeNode.get_length('-arrow-rise');
@ -429,8 +467,24 @@ const BoxPointer = new Lang.Class({
break;
}
// Now align and position the pointing axis, making sure
// it fits on screen
// Now align and position the pointing axis, making sure it fits on
// screen. If the arrowOrigin is so close to the edge that the arrow
// will not be isosceles, we try to compensate as follows:
// - We skip the rounded corner and settle for a right angled arrow
// as shown below. See _drawBorder for further details.
// |\_____
// |
// |
// - If the arrow was going to be acute angled, we move the position
// of the box to maintain the arrow's accuracy.
let arrowOrigin;
let halfBase = Math.floor(arrowBase/2);
let halfBorder = borderWidth / 2;
let halfMargin = margin / 2;
let [x1, y1] = [halfBorder, halfBorder];
let [x2, y2] = [natWidth - halfBorder, natHeight - halfBorder];
switch (this._arrowSide) {
case St.Side.TOP:
case St.Side.BOTTOM:
@ -438,7 +492,17 @@ const BoxPointer = new Lang.Class({
resX = Math.max(resX, monitor.x + padding);
resX = Math.min(resX, monitor.x + monitor.width - (padding + natWidth));
this.setArrowOrigin(sourceCenterX - resX);
arrowOrigin = sourceCenterX - resX;
if (arrowOrigin <= (x1 + (borderRadius + halfBase))) {
if (arrowOrigin > x1)
resX += (arrowOrigin - x1);
arrowOrigin = x1;
} else if (arrowOrigin >= (x2 - (borderRadius + halfBase))) {
if (arrowOrigin < x2)
resX -= (x2 - arrowOrigin);
arrowOrigin = x2;
}
break;
case St.Side.LEFT:
@ -448,10 +512,21 @@ const BoxPointer = new Lang.Class({
resY = Math.max(resY, monitor.y + padding);
resY = Math.min(resY, monitor.y + monitor.height - (padding + natHeight));
this.setArrowOrigin(sourceCenterY - resY);
arrowOrigin = sourceCenterY - resY;
if (arrowOrigin <= (y1 + (borderRadius + halfBase))) {
if (arrowOrigin > y1)
resY += (arrowOrigin - y1);
arrowOrigin = y1;
} else if (arrowOrigin >= (y2 - (borderRadius + halfBase))) {
if (arrowOrigin < y2)
resX -= (y2 - arrowOrigin);
arrowOrigin = y2;
}
break;
}
this.setArrowOrigin(arrowOrigin);
let parent = this.actor.get_parent();
let success, x, y;
while (!success) {

View File

@ -339,22 +339,10 @@ const DBusEventSource = new Lang.Class({
});
Signals.addSignalMethods(DBusEventSource.prototype);
// Calendar:
// @eventSource: is an object implementing the EventSource API, e.g. the
// requestRange(), getEvents(), hasEvents() methods and the ::changed signal.
const Calendar = new Lang.Class({
Name: 'Calendar',
_init: function(eventSource) {
if (eventSource) {
this._eventSource = eventSource;
this._eventSource.connect('changed', Lang.bind(this,
function() {
this._update(false);
}));
}
_init: function() {
this._weekStart = Shell.util_get_week_start();
this._weekdate = NaN;
this._digitWidth = NaN;
@ -391,6 +379,24 @@ const Calendar = new Lang.Class({
this._buildHeader ();
},
// @eventSource: is an object implementing the EventSource API, e.g. the
// requestRange(), getEvents(), hasEvents() methods and the ::changed signal.
setEventSource: function(eventSource) {
if (this._eventSource) {
this._eventSource.disconnect(this._eventSourceChangedId);
this._eventSource = null;
}
this._eventSource = eventSource;
if (this._eventSource) {
this._eventSourceChangedId = this._eventSource.connect('changed', Lang.bind(this, function() {
this._update(false);
}));
this._update(true);
}
},
// Sets the calendar to show a specific date
setDate: function(date, forceReload) {
if (!_sameDay(date, this._selectedDate)) {
@ -621,16 +627,25 @@ Signals.addSignalMethods(Calendar.prototype);
const EventsList = new Lang.Class({
Name: 'EventsList',
_init: function(eventSource) {
_init: function() {
this.actor = new St.BoxLayout({ vertical: true, style_class: 'events-header-vbox'});
this._date = new Date();
this._eventSource = eventSource;
this._eventSource.connect('changed', Lang.bind(this, this._update));
this._desktopSettings = new Gio.Settings({ schema: 'org.gnome.desktop.interface' });
this._desktopSettings.connect('changed', Lang.bind(this, this._update));
this._weekStart = Shell.util_get_week_start();
},
this._update();
setEventSource: function(eventSource) {
if (this._eventSource) {
this._eventSource.disconnect(this._eventSourceChangedId);
this._eventSource = null;
}
this._eventSource = eventSource;
if (this._eventSource) {
this._eventSourceChangedId = this._eventSource.connect('changed', Lang.bind(this, this._update));
}
},
_addEvent: function(dayNameBox, timeBox, eventTitleBox, includeDayName, day, time, desc) {

View File

@ -0,0 +1,65 @@
const Lang = imports.lang;
const Main = imports.ui.main;
const ComponentManager = new Lang.Class({
Name: 'ComponentManager',
_init: function() {
this._allComponents = {};
this._enabledComponents = [];
Main.sessionMode.connect('updated', Lang.bind(this, this._sessionUpdated));
this._sessionUpdated();
},
_sessionUpdated: function() {
let newEnabledComponents = Main.sessionMode.components;
newEnabledComponents.filter(Lang.bind(this, function(name) {
return this._enabledComponents.indexOf(name) == -1;
})).forEach(Lang.bind(this, function(name) {
this._enableComponent(name);
}));
this._enabledComponents.filter(Lang.bind(this, function(name) {
return newEnabledComponents.indexOf(name) == -1;
})).forEach(Lang.bind(this, function(name) {
this._disableComponent(name);
}));
this._enabledComponents = newEnabledComponents;
},
_importComponent: function(name) {
let module = imports.ui.components[name];
return module.Component;
},
_ensureComponent: function(name) {
let component = this._allComponents[name];
if (component)
return component;
if (Main.sessionMode.isLocked)
return null;
let constructor = this._importComponent(name);
component = new constructor();
this._allComponents[name] = component;
return component;
},
_enableComponent: function(name) {
let component = this._ensureComponent(name);
if (component)
component.enable();
},
_disableComponent: function(name) {
let component = this._allComponents[name];
if (component == null)
return;
component.disable();
}
});

View File

@ -34,28 +34,30 @@ const AutomountManager = new Lang.Class({
this._inhibited = false;
this._loginManager = LoginManager.getLoginManager();
Main.screenShield.connect('lock-status-changed', Lang.bind(this, this._lockStatusChanged));
this._volumeMonitor = Gio.VolumeMonitor.get();
},
this._volumeMonitor.connect('volume-added',
Lang.bind(this,
this._onVolumeAdded));
this._volumeMonitor.connect('volume-removed',
Lang.bind(this,
this._onVolumeRemoved));
this._volumeMonitor.connect('drive-connected',
Lang.bind(this,
this._onDriveConnected));
this._volumeMonitor.connect('drive-disconnected',
Lang.bind(this,
this._onDriveDisconnected));
this._volumeMonitor.connect('drive-eject-button',
Lang.bind(this,
this._onDriveEjectButton));
enable: function() {
this._volumeAddedId = this._volumeMonitor.connect('volume-added', Lang.bind(this, this._onVolumeAdded));
this._volumeRemovedId = this._volumeMonitor.connect('volume-removed', Lang.bind(this, this._onVolumeRemoved));
this._driveConnectedId = this._volumeMonitor.connect('drive-connected', Lang.bind(this, this._onDriveConnected));
this._driveDisconnectedId = this._volumeMonitor.connect('drive-disconnected', Lang.bind(this, this._onDriveDisconnected));
this._driveEjectButtonId = this._volumeMonitor.connect('drive-eject-button', Lang.bind(this, this._onDriveEjectButton));
Mainloop.idle_add(Lang.bind(this, this._startupMountAll));
this._mountAllId = Mainloop.idle_add(Lang.bind(this, this._startupMountAll));
},
disable: function() {
this._volumeMonitor.disconnect(this._volumeAddedId);
this._volumeMonitor.disconnect(this._volumeRemovedId);
this._volumeMonitor.disconnect(this._driveConnectedId);
this._volumeMonitor.disconnect(this._driveDisconnectedId);
this._volumeMonitor.disconnect(this._driveEjectButtonId);
if (this._mountAllId > 0) {
Mainloop.source_remove(this._mountAllId);
this._mountAllId = 0;
}
},
_InhibitorsChanged: function(object, senderName, [inhibtor]) {
@ -68,17 +70,6 @@ const AutomountManager = new Lang.Class({
}));
},
_lockStatusChanged: function(shield, locked) {
if (!locked) {
this._volumeQueue.forEach(Lang.bind(this, function(volume) {
this._checkAndMountVolume(volume);
}));
}
// clear the queue anyway
this._volumeQueue = [];
},
_startupMountAll: function() {
let volumes = this._volumeMonitor.get_volumes();
volumes.forEach(Lang.bind(this, function(volume) {
@ -87,6 +78,7 @@ const AutomountManager = new Lang.Class({
allowAutorun: false });
}));
this._mountAllId = 0;
return false;
},
@ -96,9 +88,6 @@ const AutomountManager = new Lang.Class({
if (!this._loginManager.sessionActive)
return;
if (Main.screenShield.locked)
return;
global.play_theme_sound(0, 'device-added-media');
},
@ -108,9 +97,6 @@ const AutomountManager = new Lang.Class({
if (!this._loginManager.sessionActive)
return;
if (Main.screenShield.locked)
return;
global.play_theme_sound(0, 'device-removed-media');
},
@ -159,13 +145,6 @@ const AutomountManager = new Lang.Class({
// don't attempt automount
if (!this._loginManager.sessionActive)
return;
if (Main.screenShield.locked) {
if (this._volumeQueue.indexOf(volume) == -1)
this._volumeQueue.push(volume);
return;
}
}
if (this._inhibited)
@ -259,3 +238,4 @@ const AutomountManager = new Lang.Class({
});
}
});
const Component = AutomountManager;

View File

@ -147,21 +147,40 @@ const AutorunManager = new Lang.Class({
this._volumeMonitor = Gio.VolumeMonitor.get();
this._volumeMonitor.connect('mount-added',
Lang.bind(this,
this._onMountAdded));
this._volumeMonitor.connect('mount-removed',
Lang.bind(this,
this._onMountRemoved));
this._transDispatcher = new AutorunTransientDispatcher(this);
},
this._transDispatcher = new AutorunTransientDispatcher();
this._createResidentSource();
_ensureResidentSource: function() {
if (this._residentSource)
return;
this._residentSource = new AutorunResidentSource(this);
let destroyId = this._residentSource.connect('destroy', Lang.bind(this, function() {
this._residentSource.disconnect(destroyId);
this._residentSource = null;
}));
},
enable: function() {
this._scanMounts();
this._mountAddedId = this._volumeMonitor.connect('mount-added', Lang.bind(this, this._onMountAdded));
this._mountRemovedId = this._volumeMonitor.connect('mount-removed', Lang.bind(this, this._onMountRemoved));
},
disable: function() {
if (this._residentSource)
this._residentSource.destroy();
this._volumeMonitor.disconnect(this._mountAddedId);
this._volumeMonitor.disconnect(this._mountRemovedId);
},
_scanMounts: function() {
let mounts = this._volumeMonitor.get_mounts();
mounts.forEach(Lang.bind(this, function (mount) {
let discoverer = new ContentTypeDiscoverer(Lang.bind (this,
function (mount, apps) {
this._ensureResidentSource();
this._residentSource.addMount(mount, apps);
}));
@ -169,13 +188,6 @@ const AutorunManager = new Lang.Class({
}));
},
_createResidentSource: function() {
this._residentSource = new AutorunResidentSource();
this._residentSource.connect('destroy',
Lang.bind(this,
this._createResidentSource));
},
_onMountAdded: function(monitor, mount) {
// don't do anything if our session is not the currently
// active one
@ -185,6 +197,7 @@ const AutorunManager = new Lang.Class({
let discoverer = new ContentTypeDiscoverer(Lang.bind (this,
function (mount, apps, contentTypes) {
this._transDispatcher.addMount(mount, apps, contentTypes);
this._ensureResidentSource();
this._residentSource.addMount(mount, apps);
}));
@ -193,7 +206,8 @@ const AutorunManager = new Lang.Class({
_onMountRemoved: function(monitor, mount) {
this._transDispatcher.removeMount(mount);
this._residentSource.removeMount(mount);
if (this._residentSource)
this._residentSource.removeMount(mount);
},
ejectMount: function(mount) {
@ -260,13 +274,18 @@ const AutorunResidentSource = new Lang.Class({
Name: 'AutorunResidentSource',
Extends: MessageTray.Source,
_init: function() {
_init: function(manager) {
this.parent(_("Removable Devices"), 'media-removable');
this.showInLockScreen = false;
this._mounts = [];
this._notification = new AutorunResidentNotification(this);
this._manager = manager;
this._notification = new AutorunResidentNotification(this._manager, this);
},
buildRightClickMenu: function() {
return null;
},
addMount: function(mount, apps) {
@ -316,7 +335,7 @@ const AutorunResidentNotification = new Lang.Class({
Name: 'AutorunResidentNotification',
Extends: MessageTray.Notification,
_init: function(source) {
_init: function(manager, source) {
this.parent(source, source.title, null, { customContent: true });
// set the notification as resident
@ -324,6 +343,7 @@ const AutorunResidentNotification = new Lang.Class({
this._layout = new St.BoxLayout ({ style_class: 'hotplug-resident-box',
vertical: true });
this._manager = manager;
this.addActor(this._layout,
{ x_expand: true,
@ -386,7 +406,7 @@ const AutorunResidentNotification = new Lang.Class({
}));
ejectButton.connect('clicked', Lang.bind(this, function() {
Main.autorunManager.ejectMount(mount);
this._manager.ejectMount(mount);
}));
return item;
@ -396,7 +416,8 @@ const AutorunResidentNotification = new Lang.Class({
const AutorunTransientDispatcher = new Lang.Class({
Name: 'AutorunTransientDispatcher',
_init: function() {
_init: function(manager) {
this._manager = manager;
this._sources = [];
this._settings = new Gio.Settings({ schema: SETTINGS_SCHEMA });
},
@ -439,7 +460,7 @@ const AutorunTransientDispatcher = new Lang.Class({
return;
// add a new source
this._sources.push(new AutorunTransientSource(mount, apps));
this._sources.push(new AutorunTransientSource(this._manager, mount, apps));
},
addMount: function(mount, apps, contentTypes) {
@ -492,13 +513,14 @@ const AutorunTransientSource = new Lang.Class({
Name: 'AutorunTransientSource',
Extends: MessageTray.Source,
_init: function(mount, apps) {
_init: function(manager, mount, apps) {
this._manager = manager;
this.mount = mount;
this.apps = apps;
this.parent(mount.get_name());
this._notification = new AutorunTransientNotification(this);
this._notification = new AutorunTransientNotification(this._manager, this);
// add ourselves as a source, and popup the notification
Main.messageTray.add(this);
@ -515,9 +537,10 @@ const AutorunTransientNotification = new Lang.Class({
Name: 'AutorunTransientNotification',
Extends: MessageTray.Notification,
_init: function(source) {
_init: function(manager, source) {
this.parent(source, source.title, null, { customContent: true });
this._manager = manager;
this._box = new St.BoxLayout({ style_class: 'hotplug-transient-box',
vertical: true });
this.addActor(this._box);
@ -586,10 +609,11 @@ const AutorunTransientNotification = new Lang.Class({
style_class: 'hotplug-notification-item' });
button.connect('clicked', Lang.bind(this, function() {
Main.autorunManager.ejectMount(this._mount);
this._manager.ejectMount(this._mount);
}));
return button;
}
});
const Component = AutorunManager;

View File

@ -192,23 +192,36 @@ const KeyringDialog = new Lang.Class({
},
_onContinueButton: function() {
this.prompt.complete()
this.prompt.complete();
},
_onCancelButton: function() {
this.prompt.cancel()
this.prompt.cancel();
},
});
function init() {
prompter = new Gcr.SystemPrompter();
prompter.connect('new-prompt', function(prompter) {
let dialog = new KeyringDialog();
return dialog.prompt;
});
const KeyringPrompter = new Lang.Class({
Name: 'KeyringPrompter',
let connection = Gio.DBus.session;
prompter.register(connection);
Gio.bus_own_name_on_connection (connection, 'org.gnome.keyring.SystemPrompter',
Gio.BusNameOwnerFlags.REPLACE, null, null);
}
_init: function() {
this._prompter = new Gcr.SystemPrompter();
this._prompter.connect('new-prompt', function(prompter) {
let dialog = new KeyringDialog();
return dialog.prompt;
});
this._dbusId = null;
},
enable: function() {
this._prompter.register(Gio.DBus.session);
this._dbusId = Gio.DBus.session.own_name('org.gnome.keyring.SystemPrompter',
Gio.BusNameOwnerFlags.REPLACE, null, null);
},
disable: function() {
this._prompter.unregister(false);
Gio.DBus.session.unown_name(this._dbusId);
}
});
const Component = KeyringPrompter;

View File

@ -1,23 +1,4 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
/*
* Copyright 2011 Giovanni Campagna <scampa.giovanni@gmail.com>
*
* 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 Clutter = imports.gi.Clutter;
const Gio = imports.gi.Gio;
@ -603,7 +584,7 @@ const NetworkAgent = new Lang.Class({
Name: 'NetworkAgent',
_init: function() {
this._native = new Shell.NetworkAgent({ auto_register: true,
this._native = new Shell.NetworkAgent({ auto_register: false,
identifier: 'org.gnome.Shell.NetworkAgent' });
this._dialogs = { };
@ -613,6 +594,14 @@ const NetworkAgent = new Lang.Class({
this._native.connect('cancel-request', Lang.bind(this, this._cancelRequest));
},
enable: function() {
this._native.register();
},
disable: function() {
this._native.unregister();
},
_newRequest: function(agent, requestId, connection, settingName, hints, flags) {
if (settingName == 'vpn') {
this._vpnRequest(requestId, connection, hints, flags);
@ -702,3 +691,4 @@ const NetworkAgent = new Lang.Class({
}
}
});
const Component = NetworkAgent;

View File

@ -1,24 +1,4 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
/*
* Copyright 2010 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.
*
* Author: David Zeuthen <davidz@redhat.com>
*/
const Lang = imports.lang;
const Signals = imports.signals;
@ -33,6 +13,7 @@ const Mainloop = imports.mainloop;
const Polkit = imports.gi.Polkit;
const PolkitAgent = imports.gi.PolkitAgent;
const Components = imports.ui.components;
const ModalDialog = imports.ui.modalDialog;
const ShellEntry = imports.ui.shellEntry;
const UserMenu = imports.ui.userMenu;
@ -318,7 +299,7 @@ const AuthenticationDialog = new Lang.Class({
},
_onUserChanged: function() {
if (this._user.is_loaded) {
if (this._user.is_loaded && this._userAvatar) {
this._userAvatar.update();
this._userAvatar.actor.show();
}
@ -336,11 +317,20 @@ const AuthenticationAgent = new Lang.Class({
Name: 'AuthenticationAgent',
_init: function() {
this._currentDialog = null;
this._isCompleting = false;
this._handle = null;
this._native = new Shell.PolkitAuthenticationAgent();
this._native.connect('initiate', Lang.bind(this, this._onInitiate));
this._native.connect('cancel', Lang.bind(this, this._onCancel));
this._currentDialog = null;
this._isCompleting = false;
},
enable: function() {
this._native.register();
},
disable: function() {
this._native.unregister();
},
_onInitiate: function(nativeAgent, actionId, message, iconName, cookie, userNames) {
@ -398,6 +388,4 @@ const AuthenticationAgent = new Lang.Class({
}
});
function init() {
let agent = new AuthenticationAgent();
}
const Component = AuthenticationAgent;

View File

@ -0,0 +1,58 @@
const Lang = imports.lang;
const Gio = imports.gi.Gio;
const Meta = imports.gi.Meta;
const Shell = imports.gi.Shell;
const Recorder = new Lang.Class({
Name: 'Recorder',
_init: function() {
this._recorderSettings = new Gio.Settings({ schema: 'org.gnome.shell.recorder' });
this._desktopLockdownSettings = new Gio.Settings({ schema: 'org.gnome.desktop.lockdown' });
this._bindingSettings = new Gio.Settings({ schema: 'org.gnome.shell.keybindings' });
this._recorder = null;
},
enable: function() {
global.display.add_keybinding('toggle-recording',
this._bindingSettings,
Meta.KeyBindingFlags.NONE, Lang.bind(this, this._toggleRecorder));
},
disable: function() {
global.display.remove_keybinding('toggle-recording');
},
_ensureRecorder: function() {
if (this._recorder == null)
this._recorder = new Shell.Recorder({ stage: global.stage });
return this._recorder;
},
_toggleRecorder: function() {
let recorder = this._ensureRecorder();
if (recorder.is_recording()) {
recorder.close();
Meta.enable_unredirect_for_screen(global.screen);
} else if (!this._desktopLockdownSettings.get_boolean('disable-save-to-disk')) {
// read the parameters from GSettings always in case they have changed
recorder.set_framerate(this._recorderSettings.get_int('framerate'));
/* Translators: this is a filename used for screencast recording */
// xgettext:no-c-format
recorder.set_filename(_("Screencast from %d %t") + '.' + this._recorderSettings.get_string('file-extension'));
let pipeline = this._recorderSettings.get_string('pipeline');
if (!pipeline.match(/^\s*$/))
recorder.set_pipeline(pipeline);
else
recorder.set_pipeline(null);
Meta.disable_unredirect_for_screen(global.screen);
recorder.record();
}
}
});
const Component = Recorder;

View File

@ -11,10 +11,10 @@ const Tpl = imports.gi.TelepathyLogger;
const Tp = imports.gi.TelepathyGLib;
const History = imports.misc.history;
const Params = imports.misc.params;
const Main = imports.ui.main;
const MessageTray = imports.ui.messageTray;
const Params = imports.misc.params;
const PopupMenu = imports.ui.popupMenu;
// See Notification.appendMessage
const SCROLLBACK_IMMEDIATE_TIME = 60; // 1 minute
@ -63,10 +63,10 @@ function makeMessageFromTplEvent(event) {
};
}
const Client = new Lang.Class({
Name: 'Client',
const TelepathyClient = new Lang.Class({
Name: 'TelepathyClient',
_init : function() {
_init: function() {
// channel path -> ChatSource
this._chatSources = {};
this._chatState = Tp.ChannelChatState.ACTIVE;
@ -89,9 +89,9 @@ const Client = new Lang.Class({
// channel matching its filters is detected.
// The second argument, recover, means _observeChannels will be run
// for any existing channel as well.
this._tpClient = new Shell.TpClient({ 'account-manager': this._accountManager,
'name': 'GnomeShell',
'uniquify-name': true })
this._tpClient = new Shell.TpClient({ name: 'GnomeShell',
account_manager: this._accountManager,
uniquify_name: true });
this._tpClient.set_observe_channels_func(
Lang.bind(this, this._observeChannels));
this._tpClient.set_approve_channels_func(
@ -99,6 +99,10 @@ const Client = new Lang.Class({
this._tpClient.set_handle_channels_func(
Lang.bind(this, this._handleChannels));
// Watch subscription requests and connection errors
this._subscriptionSource = null;
this._accountSource = null;
// Workaround for gjs not supporting GPtrArray in signals.
// See BGO bug #653941 for context.
this._tpClient.set_contact_list_changed_func(
@ -108,21 +112,26 @@ const Client = new Lang.Class({
// needed
this._tpClient.set_delegated_channels_callback(
Lang.bind(this, this._delegatedChannelsCb));
},
enable: function() {
try {
this._tpClient.register();
} catch (e) {
throw new Error('Couldn\'t register Telepathy client. Error: \n' + e);
}
// Watch subscription requests and connection errors
this._subscriptionSource = null;
this._accountSource = null;
this._accountManagerValidityChangedId = this._accountManager.connect('account-validity-changed',
Lang.bind(this, this._accountValidityChanged));
this._accountManager.connect('account-validity-changed',
Lang.bind(this, this._accountValidityChanged));
if (!this._accountManager.is_prepared(Tp.AccountManager.get_feature_quark_core()))
this._accountManager.prepare_async(null, Lang.bind(this, this._accountManagerPrepared));
},
this._accountManager.prepare_async(null, Lang.bind(this, this._accountManagerPrepared));
disable: function() {
this._tpClient.unregister();
this._accountManager.disconnect(this._accountManagerValidityChangedId);
this._accountManagerValidityChangedId = 0;
},
_observeChannels: function(observer, account, conn, channels,
@ -473,6 +482,22 @@ const ChatSource = new Lang.Class({
this._getLogMessages();
},
buildRightClickMenu: function() {
let item;
let rightClickMenu = this.parent();
item = new PopupMenu.PopupMenuItem('');
item.actor.connect('notify::mapped', Lang.bind(this, function() {
item.label.set_text(this.isMuted ? _("Unmute") : _("Mute"));
}));
item.connect('activate', Lang.bind(this, function() {
this.setMuted(!this.isMuted);
this.emit('done-displaying-content');
}));
rightClickMenu.add(item.actor);
return rightClickMenu;
},
_updateAlias: function() {
let oldAlias = this.title;
let newAlias = this._contact.get_alias();
@ -721,8 +746,6 @@ const ChatSource = new Lang.Class({
this._pendingMessages.splice(idx, 1);
this.countUpdated();
}
else
throw new Error('Message not in our pending list: ' + message);
},
_ackMessages: function() {
@ -747,6 +770,14 @@ const ChatNotification = new Lang.Class({
this._responseEntry.clutter_text.connect('text-changed', Lang.bind(this, this._onEntryChanged));
this.setActionArea(this._responseEntry);
this._responseEntry.clutter_text.connect('key-focus-in', Lang.bind(this, function() {
this.focused = true;
}));
this._responseEntry.clutter_text.connect('key-focus-out', Lang.bind(this, function() {
this.focused = false;
this.emit('unfocused');
}));
this._oldMaxScrollAdjustment = 0;
this._createScrollArea();
this._lastGroup = null;
@ -1399,3 +1430,4 @@ const AccountNotification = new Lang.Class({
this.parent();
}
});
const Component = TelepathyClient;

View File

@ -310,6 +310,40 @@ const DragPlaceholderItem = new Lang.Class({
}
});
const DashActor = new Lang.Class({
Name: 'DashActor',
Extends: St.Widget,
_init: function() {
let layout = new Clutter.BoxLayout({ orientation: Clutter.Orientation.VERTICAL });
this.parent({ name: 'dash',
layout_manager: layout,
clip_to_allocation: true });
},
vfunc_allocate: function(box, flags) {
let contentBox = this.get_theme_node().get_content_box(box);
let availWidth = contentBox.x2 - contentBox.x1;
let availHeight = contentBox.y2 - contentBox.y1;
this.set_allocation(box, flags);
let [appIcons, showAppsButton] = this.get_children();
let [minHeight, natHeight] = showAppsButton.get_preferred_height(availWidth);
let childBox = new Clutter.ActorBox();
childBox.x1 = 0;
childBox.x2 = availWidth;
childBox.y1 = 0;
childBox.y2 = availHeight - natHeight;
appIcons.allocate(childBox, flags);
childBox.y1 = availHeight - natHeight;
childBox.y2 = availHeight;
showAppsButton.allocate(childBox, flags);
}
});
const Dash = new Lang.Class({
Name: 'Dash',
@ -325,14 +359,11 @@ const Dash = new Lang.Class({
this._resetHoverTimeoutId = 0;
this._labelShowing = false;
this._container = new St.BoxLayout({ name: 'dash',
vertical: true,
clip_to_allocation: true });
this._container = new DashActor();
this._box = new St.BoxLayout({ vertical: true,
clip_to_allocation: true });
this._box._delegate = this;
this._container.add(this._box);
this._container.add_actor(this._box);
this._showAppsIcon = new ShowAppsIcon();
this._showAppsIcon.icon.setIconSize(this.iconSize);
@ -340,7 +371,7 @@ const Dash = new Lang.Class({
this.showAppsButton = this._showAppsIcon.toggleButton;
this._container.add(this._showAppsIcon.actor);
this._container.add_actor(this._showAppsIcon.actor);
this.actor = new St.Bin({ child: this._container });
this.actor.connect('notify::height', Lang.bind(this,

View File

@ -70,16 +70,8 @@ const DateMenuButton = new Lang.Class({
this._date.style_class = 'datemenu-date-label';
vbox.add(this._date);
if (Main.sessionMode.showCalendarEvents) {
this._eventSource = new Calendar.DBusEventSource();
this._eventList = new Calendar.EventsList(this._eventSource);
} else {
this._eventSource = null;
this._eventList = null;
}
// Calendar
this._calendar = new Calendar.Calendar(this._eventSource);
this._eventList = new Calendar.EventsList();
this._calendar = new Calendar.Calendar();
this._calendar.connect('selected-date-changed',
Lang.bind(this, function(calendar, date) {
@ -101,27 +93,23 @@ const DateMenuButton = new Lang.Class({
item.actor.reparent(vbox);
}
if (Main.sessionMode.showCalendarEvents) {
// Add vertical separator
this._separator = new St.DrawingArea({ style_class: 'calendar-vertical-separator',
pseudo_class: 'highlighted' });
this._separator.connect('repaint', Lang.bind(this, _onVertSepRepaint));
hbox.add(this._separator);
item = new St.DrawingArea({ style_class: 'calendar-vertical-separator',
pseudo_class: 'highlighted' });
item.connect('repaint', Lang.bind(this, _onVertSepRepaint));
hbox.add(item);
// Fill up the second column
vbox = new St.BoxLayout({ name: 'calendarEventsArea',
vertical: true });
hbox.add(vbox, { expand: true });
// Fill up the second column
vbox = new St.BoxLayout({name: 'calendarEventsArea',
vertical: true});
hbox.add(vbox, { expand: true });
// Event list
vbox.add(this._eventList.actor, { expand: true });
// Event list
vbox.add(this._eventList.actor, { expand: true });
item = new PopupMenu.PopupMenuItem(_("Open Calendar"));
item.connect('activate', Lang.bind(this, this._onOpenCalendarActivate));
item.actor.can_focus = false;
vbox.add(item.actor, {y_align: St.Align.END, expand: true, y_fill: false});
}
this._openCalendarItem = new PopupMenu.PopupMenuItem(_("Open Calendar"));
this._openCalendarItem.connect('activate', Lang.bind(this, this._onOpenCalendarActivate));
this._openCalendarItem.actor.can_focus = false;
vbox.add(this._openCalendarItem.actor, {y_align: St.Align.END, expand: true, y_fill: false});
// Whenever the menu is opened, select today
this.menu.connect('open-state-changed', Lang.bind(this, function(menu, isOpen) {
@ -151,6 +139,32 @@ const DateMenuButton = new Lang.Class({
this._clock = new GnomeDesktop.WallClock();
this._clock.connect('notify::clock', Lang.bind(this, this._updateClockAndDate));
this._updateClockAndDate();
Main.sessionMode.connect('updated', Lang.bind(this, this._sessionUpdated));
this._sessionUpdated();
},
_setEventsVisibility: function(visible) {
this._separator.visible = visible;
this._eventList.visible = visible;
this._openCalendarItem.visible = visible;
},
_setEventSource: function(eventSource) {
this._calendar.setEventSource(eventSource);
this._eventList.setEventSource(eventSource);
},
_sessionUpdated: function() {
let eventSource;
let showEvents = Main.sessionMode.showCalendarEvents;
if (showEvents) {
eventSource = new Calendar.DBusEventSource();
} else {
eventSource = null;
}
this._setEventSource(eventSource);
this._setEventsVisibility(showEvents);
},
_updateClockAndDate: function() {

View File

@ -8,6 +8,7 @@ const Gio = imports.gi.Gio;
const St = imports.gi.St;
const ExtensionUtils = imports.misc.extensionUtils;
const Main = imports.ui.main;
const ExtensionState = {
ENABLED: 1,
@ -38,6 +39,9 @@ const disconnect = Lang.bind(_signals, _signals.disconnect);
const ENABLED_EXTENSIONS_KEY = 'enabled-extensions';
var initted = false;
var enabled;
function disableExtension(uuid) {
let extension = ExtensionUtils.extensions[uuid];
if (!extension)
@ -102,8 +106,6 @@ function enableExtension(uuid) {
extensionOrder.push(uuid);
extension.stateObj.enable();
let stylesheetFile = extension.dir.get_child('stylesheet.css');
if (stylesheetFile.query_exists(null)) {
let theme = St.ThemeContext.get_for_stage(global.stage).get_theme();
@ -111,6 +113,8 @@ function enableExtension(uuid) {
extension.stylesheet = stylesheetFile;
}
extension.stateObj.enable();
extension.state = ExtensionState.ENABLED;
_signals.emit('extension-state-changed', extension);
}
@ -216,6 +220,9 @@ function initExtension(uuid) {
function onEnabledExtensionsChanged() {
let newEnabledExtensions = global.settings.get_strv(ENABLED_EXTENSIONS_KEY);
if (!enabled)
return;
// Find and enable all the newly enabled extensions: UUIDs found in the
// new setting, but not in the old one.
newEnabledExtensions.filter(function(uuid) {
@ -243,7 +250,7 @@ function onEnabledExtensionsChanged() {
enabledExtensions = newEnabledExtensions;
}
function loadExtensions() {
function _loadExtensions() {
global.settings.connect('changed::' + ENABLED_EXTENSIONS_KEY, onEnabledExtensionsChanged);
enabledExtensions = global.settings.get_strv(ENABLED_EXTENSIONS_KEY);
@ -257,3 +264,43 @@ function loadExtensions() {
});
finder.scanExtensions();
}
function enableAllExtensions() {
if (enabled)
return;
if (!initted) {
_loadExtensions();
initted = true;
} else {
enabledExtensions.forEach(function(uuid) {
enableExtension(uuid);
});
}
enabled = true;
}
function disableAllExtensions() {
if (!enabled)
return;
if (initted) {
enabledExtensions.forEach(function(uuid) {
disableExtension(uuid);
});
}
enabled = false;
}
function _sessionUpdated() {
if (Main.sessionMode.allowExtensions)
enableAllExtensions();
else
disableAllExtensions();
}
function init() {
Main.sessionMode.connect('updated', _sessionUpdated);
_sessionUpdated();
}

View File

@ -10,11 +10,12 @@ const St = imports.gi.St;
const Main = imports.ui.main;
const Params = imports.misc.params;
function _navigateActor(actor, needsGrab) {
function _navigateActor(actor) {
if (!actor)
return;
if (needsGrab && actor instanceof St.Widget)
let needsGrab = true;
if (actor instanceof St.Widget)
needsGrab = !actor.navigate_focus(null, Gtk.DirectionType.TAB_FORWARD, false);
if (needsGrab)
actor.grab_key_focus();
@ -84,11 +85,7 @@ const GrabHelper = new Lang.Class({
},
get currentGrab() {
let idx = this._grabStack.length - 1;
while (idx >= 0 && this._grabStack[idx].untracked)
idx--;
return this._grabStack[idx] || {};
return this._grabStack[this._grabStack.length - 1] || {};
},
_findStackIndex: function(actor) {
@ -137,14 +134,9 @@ const GrabHelper = new Lang.Class({
// 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).
//
// If @params contains { untracked: true }, then it will be skipped
// when the grab helper ungrabs for you, or when calculating
// currentGrab.
grab: function(params) {
params = Params.parse(params, { actor: null,
modal: false,
untracked: false,
grabFocus: false,
onUngrab: null });
@ -155,55 +147,109 @@ const GrabHelper = new Lang.Class({
if (this.isActorGrabbed(params.actor))
return true;
if (this._grabFocusCount == 0 && this._modalCount == 0) {
if (!this._fullGrab(hadFocus, params.modal, params.grabFocus))
return false;
}
params.savedFocus = focus;
if (params.modal && !this._takeModalGrab())
return false;
if (params.grabFocus && !this._takeFocusGrab(hadFocus))
return false;
if (hadFocus || params.grabFocus)
_navigateActor(newFocus);
this._grabStack.push(params);
if (params.modal)
this._modalCount++;
if (params.grabFocus)
this._grabFocusCount++;
_navigateActor(newFocus, hadFocus);
return true;
},
_fullGrab: function(hadFocus, modal, grabFocus) {
let metaDisplay = global.screen.get_display();
if (modal) {
_takeModalGrab: function() {
let firstGrab = (this._modalCount == 0);
if (firstGrab) {
if (!Main.pushModal(this._owner))
return false;
this._capturedEventId = global.stage.connect('captured-event', Lang.bind(this, this._onCapturedEvent));
this._eventId = global.stage.connect('event', Lang.bind(this, this._onEvent));
}
this._grabbedFromKeynav = hadFocus;
this._preGrabInputMode = global.stage_input_mode;
this._prevFocusedWindow = null;
this._modalCount++;
return true;
},
if (grabFocus) {
_releaseModalGrab: function() {
this._modalCount--;
if (this._modalCount > 0)
return;
if (this._capturedEventId > 0) {
global.stage.disconnect(this._capturedEventId);
this._capturedEventId = 0;
}
if (this._eventId > 0) {
global.stage.disconnect(this._eventId);
this._eventId = 0;
}
Main.popModal(this._owner);
global.sync_pointer();
},
_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;
this._prevFocusedWindow = metaDisplay.focus_window;
if (this._preGrabInputMode == Shell.StageInputMode.NONREACTIVE ||
this._preGrabInputMode == Shell.StageInputMode.NORMAL) {
global.set_stage_input_mode(Shell.StageInputMode.FOCUSED);
}
}
if (modal || grabFocus) {
this._capturedEventId = global.stage.connect('captured-event', Lang.bind(this, this._onCapturedEvent));
this._eventId = global.stage.connect('event', Lang.bind(this, this._onEvent));
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._focusWindowChanged > 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);
}
if (this._prevFocusedWindow) {
let metaDisplay = global.screen.get_display();
if (!metaDisplay.focus_window) {
metaDisplay.set_input_focus_window(this._prevFocusedWindow,
false, global.get_current_time());
}
}
},
// ignoreRelease:
//
// Make sure that the next button release event evaluated by the
@ -228,12 +274,14 @@ const GrabHelper = new Lang.Class({
if (grabStackIndex < 0)
return;
let focus = global.stage.key_focus;
let hadFocus = focus && this._isWithinGrabbedActor(focus);
let poppedGrabs = this._grabStack.slice(grabStackIndex);
// "Pop" all newly ungrabbed actors off the grab stack
// by truncating the array.
this._grabStack.length = grabStackIndex;
let wasModal = this._modalCount > 0;
for (let i = poppedGrabs.length - 1; i >= 0; i--) {
let poppedGrab = poppedGrabs[i];
@ -241,63 +289,15 @@ const GrabHelper = new Lang.Class({
poppedGrab.onUngrab();
if (poppedGrab.modal)
this._modalCount--;
this._releaseModalGrab();
if (poppedGrab.grabFocus)
this._grabFocusCount--;
this._releaseFocusGrab();
}
let focus = global.stage.key_focus;
let hadFocus = focus && this._isWithinGrabbedActor(focus);
if (this._grabFocusCount == 0 && this._modalCount == 0)
this._fullUngrab(wasModal);
let poppedGrab = poppedGrabs[0];
_navigateActor(poppedGrab.savedFocus, hadFocus);
},
_fullUngrab: function(wasModal) {
if (this._capturedEventId > 0) {
global.stage.disconnect(this._capturedEventId);
this._capturedEventId = 0;
}
if (this._eventId > 0) {
global.stage.disconnect(this._eventId);
this._eventId = 0;
}
if (this._keyFocusNotifyId > 0) {
global.stage.disconnect(this._keyFocusNotifyId);
this._keyFocusNotifyId = 0;
}
if (!this._focusWindowChanged > 0) {
let metaDisplay = global.screen.get_display();
metaDisplay.disconnect(this._focusWindowChangedId);
this._focusWindowChangedId = 0;
}
let prePopInputMode = global.stage_input_mode;
if (wasModal) {
Main.popModal(this._owner);
global.sync_pointer();
}
if (this._grabbedFromKeynav) {
if (this._preGrabInputMode == Shell.StageInputMode.FOCUSED &&
prePopInputMode != Shell.StageInputMode.FULLSCREEN)
global.set_stage_input_mode(Shell.StageInputMode.FOCUSED);
}
if (this._prevFocusedWindow) {
let metaDisplay = global.screen.get_display();
if (!metaDisplay.focus_window) {
metaDisplay.set_input_focus_window(this._prevFocusedWindow,
false, global.get_current_time());
}
if (hadFocus) {
let poppedGrab = poppedGrabs[0];
_navigateActor(poppedGrab.savedFocus);
}
},
@ -318,12 +318,15 @@ const GrabHelper = new Lang.Class({
if (this._isWithinGrabbedActor(event.get_source()))
return false;
if (Main.keyboard.shouldTakeEvent(event))
return false;
if (button) {
// If we have a press event, ignore the next event,
// which should be a release event.
if (press)
this._ignoreRelease = true;
this.ungrab();
this.ungrab({ actor: this._grabStack[0].actor });
}
return this._modalCount > 0;

View File

@ -200,8 +200,10 @@ const Keyboard = new Lang.Class({
this._impl.export(Gio.DBus.session, '/org/gnome/Caribou/Keyboard');
this.actor = null;
this._focusInTray = false;
this._focusInExtendedKeys = false;
this._timestamp = global.get_current_time();
this._timestamp = global.display.get_current_time_roundtrip();
Main.layoutManager.connect('monitors-changed', Lang.bind(this, this._redraw));
this._keyboardSettings = new Gio.Settings({ schema: KEYBOARD_SCHEMA });
@ -288,7 +290,15 @@ const Keyboard = new Lang.Class({
// Showing an extended key popup and clicking a key from the extended keys
// will grab focus, but ignore that
if (focus && (focus._extended_keys || (focus._key && focus._key.extended_key)))
let extendedKeysWereFocused = this._focusInExtendedKeys;
this._focusInExtendedKeys = focus && (focus._extended_keys || focus.extended_key);
if (this._focusInExtendedKeys || extendedKeysWereFocused)
return;
// Ignore focus changes caused by message tray showing/hiding
let trayWasFocused = this._focusInTray;
this._focusInTray = (focus && Main.messageTray.actor.contains(focus));
if (this._focusInTray || trayWasFocused)
return;
let time = global.get_current_time();
@ -339,6 +349,13 @@ const Keyboard = new Lang.Class({
trayButton.reactive = true;
trayButton.remove_style_pseudo_class('grayed');
}));
Main.sessionMode.connect('updated', Lang.bind(this, function() {
trayButton.reactive = !Main.sessionMode.isLocked;
if (Main.sessionMode.isLocked)
trayButton.add_style_pseudo_class('grayed');
else
trayButton.remove_style_pseudo_class('grayed');
}));
return trayButton;
},
@ -468,6 +485,12 @@ const Keyboard = new Lang.Class({
}
},
shouldTakeEvent: function(event) {
let actor = event.get_source();
return Main.layoutManager.keyboardBox.contains(actor) ||
actor._extended_keys || actor.extended_key;
},
show: function () {
this._redraw();
@ -494,15 +517,30 @@ const Keyboard = new Lang.Class({
this._moveTemporarily();
},
// _compareTimestamp:
//
// Compare two timestamps taking into account
// CURRENT_TIME (0)
_compareTimestamp: function(one, two) {
if (one == two)
return 0;
if (one == Clutter.CURRENT_TIME)
return 1;
if (two == Clutter.CURRENT_TIME)
return -1;
return one - two;
},
// D-Bus methods
Show: function(timestamp) {
if (!this._enableKeyboard)
return;
if (timestamp - this._timestamp < 0)
if (this._compareTimestamp(timestamp, this._timestamp) < 0)
return;
this._timestamp = timestamp;
if (timestamp != Clutter.CURRENT_TIME)
this._timestamp = timestamp;
this.show();
},
@ -510,10 +548,11 @@ const Keyboard = new Lang.Class({
if (!this._enableKeyboard)
return;
if (timestamp - this._timestamp < 0)
if (this._compareTimestamp(timestamp, this._timestamp) < 0)
return;
this._timestamp = timestamp;
if (timestamp != Clutter.CURRENT_TIME)
this._timestamp = timestamp;
this.hide();
},
@ -543,6 +582,7 @@ const KeyboardSource = new Lang.Class({
_init: function(keyboard) {
this._keyboard = keyboard;
this.parent(_("Keyboard"), 'input-keyboard-symbolic');
this.keepTrayOnSummaryClick = true;
},
handleSummaryClick: function() {

View File

@ -17,6 +17,7 @@ const Tweener = imports.ui.tweener;
const HOT_CORNER_ACTIVATION_TIMEOUT = 0.5;
const STARTUP_ANIMATION_TIME = 0.2;
const KEYBOARD_ANIMATION_TIME = 0.5;
const PLYMOUTH_TRANSITION_TIME = 1;
const MonitorConstraint = new Lang.Class({
Name: 'MonitorConstraint',
@ -100,6 +101,7 @@ const LayoutManager = new Lang.Class({
this.primaryMonitor = null;
this.primaryIndex = -1;
this._hotCorners = [];
this._rootPixmap = null;
this._leftPanelBarrier = 0;
this._rightPanelBarrier = 0;
this._trayBarrier = 0;
@ -120,7 +122,8 @@ const LayoutManager = new Lang.Class({
this.panelBox.connect('allocation-changed',
Lang.bind(this, this._updatePanelBarriers));
this.trayBox = new St.BoxLayout({ name: 'trayBox' });
this.trayBox = new St.Widget({ name: 'trayBox',
layout_manager: new Clutter.BinLayout() });
this.addChrome(this.trayBox);
this.trayBox.connect('allocation-changed',
Lang.bind(this, this._updateTrayBarrier));
@ -318,10 +321,41 @@ const LayoutManager = new Lang.Class({
},
_startupAnimation: function() {
this.panelBox.anchor_y = this.panelBox.height;
let plymouthTransitionRunning = false;
// If we're the greeter, put up the xrootpmap actor
// and fade it out to have a nice transition from plymouth
// to the greeter. Otherwise, we'll just animate the panel,
// as usual.
if (Main.sessionMode.isGreeter) {
this._rootPixmap = global.create_xrootpmap_texture();
if (this._rootPixmap != null) {
Main.uiGroup.add_actor(this._rootPixmap);
Tweener.addTween(this._rootPixmap,
{ opacity: 0,
time: PLYMOUTH_TRANSITION_TIME,
transition: 'linear',
onComplete: this._fadeRootpmapComplete,
onCompleteScope: this });
plymouthTransitionRunning = true;
}
}
if (!plymouthTransitionRunning)
this._fadeRootpmapComplete();
},
_fadeRootpmapComplete: function() {
// Don't animate the strut
this._chrome.freezeUpdateRegions();
this.panelBox.anchor_y = this.panelBox.height;
if (this._rootPixmap != null) {
this._rootPixmap.destroy();
this._rootPixmap = null;
}
Tweener.addTween(this.panelBox,
{ anchor_y: 0,
time: STARTUP_ANIMATION_TIME,
@ -336,7 +370,6 @@ const LayoutManager = new Lang.Class({
},
showKeyboard: function () {
Main.messageTray.hide();
this.keyboardBox.raise_top();
Tweener.addTween(this.keyboardBox,
{ anchor_y: this.keyboardBox.height,
@ -350,6 +383,8 @@ const LayoutManager = new Lang.Class({
time: KEYBOARD_ANIMATION_TIME,
transition: 'easeOutQuad'
});
this.emit('keyboard-visible-changed', true);
},
_showKeyboardComplete: function() {
@ -364,7 +399,6 @@ const LayoutManager = new Lang.Class({
},
hideKeyboard: function (immediate) {
Main.messageTray.hide();
if (this._keyboardHeightNotifyId) {
this.keyboardBox.disconnect(this._keyboardHeightNotifyId);
this._keyboardHeightNotifyId = 0;
@ -381,6 +415,8 @@ const LayoutManager = new Lang.Class({
time: immediate ? 0 : KEYBOARD_ANIMATION_TIME,
transition: 'easeOutQuad'
});
this.emit('keyboard-visible-changed', false);
},
_hideKeyboardComplete: function() {
@ -639,7 +675,6 @@ const Chrome = new Lang.Class({
this._monitors = [];
this._inOverview = false;
this._isLocked = false;
this._updateRegionIdle = 0;
this._freezeUpdateCount = 0;
@ -658,12 +693,9 @@ const Chrome = new Lang.Class({
},
init: function() {
Main.overview.connect('showing',
Lang.bind(this, this._overviewShowing));
Main.overview.connect('hidden',
Lang.bind(this, this._overviewHidden));
Main.screenShield.connect('lock-status-changed',
Lang.bind(this, this._lockStatusChanged));
Main.overview.connect('showing', Lang.bind(this, this._overviewShowing));
Main.overview.connect('hidden', Lang.bind(this, this._overviewHidden));
Main.sessionMode.connect('updated', Lang.bind(this, this._sessionUpdated));
},
addActor: function(actor, params) {
@ -763,7 +795,7 @@ const Chrome = new Lang.Class({
if (!actorData.isToplevel)
continue;
if (this._inOverview || this._isLocked)
if (this._inOverview || !Main.sessionMode.hasWindows)
visible = true;
else if (this.findMonitorForActor(actorData.actor).inFullscreen)
visible = false;
@ -785,8 +817,7 @@ const Chrome = new Lang.Class({
this._queueUpdateRegions();
},
_lockStatusChanged: function(shield, locked) {
this._isLocked = locked;
_sessionUpdated: function() {
this._updateVisibility();
this._queueUpdateRegions();
},

View File

@ -371,7 +371,8 @@ const ObjInspector = new Lang.Class({
this._parentList = [];
this.actor = new St.ScrollView({ x_fill: true, y_fill: true });
this.actor = new St.ScrollView({ pivot_point: new Clutter.Point({ x: 0.5, y: 0.5 }),
x_fill: true, y_fill: true });
this.actor.get_hscroll_bar().hide();
this._container = new St.BoxLayout({ name: 'LookingGlassPropertyInspector',
style_class: 'lg-dialog',
@ -443,10 +444,6 @@ const ObjInspector = new Lang.Class({
this.actor.show();
if (sourceActor) {
this.actor.set_scale(0, 0);
let [sourceX, sourceY] = sourceActor.get_transformed_position();
let [sourceWidth, sourceHeight] = sourceActor.get_transformed_size();
this.actor.move_anchor_point(Math.floor(sourceX + sourceWidth / 2),
Math.floor(sourceY + sourceHeight / 2));
Tweener.addTween(this.actor, { scale_x: 1, scale_y: 1,
transition: 'easeOutQuad',
time: 0.2 });
@ -1092,8 +1089,8 @@ const LookingGlass = new Lang.Class({
this.actor.width = myWidth;
this.actor.height = myHeight;
this._objInspector.actor.set_size(Math.floor(myWidth * 0.8), Math.floor(myHeight * 0.8));
this._objInspector.actor.set_position(this.actor.x + Math.floor(myWidth * 0.1),
this._targetY + Math.floor(myHeight * 0.1));
this._objInspector.actor.set_position(primary.x + this.actor.x + Math.floor(myWidth * 0.1),
primary.y + this._targetY + Math.floor(myHeight * 0.1));
},
insertObject: function(obj) {

View File

@ -10,12 +10,9 @@ const Meta = imports.gi.Meta;
const Shell = imports.gi.Shell;
const St = imports.gi.St;
const AutomountManager = imports.ui.automountManager;
const AutorunManager = imports.ui.autorunManager;
const Components = imports.ui.components;
const CtrlAltTab = imports.ui.ctrlAltTab;
const EndSessionDialog = imports.ui.endSessionDialog;
const PolkitAuthenticationAgent = imports.ui.polkitAuthenticationAgent;
const KeyringPrompt = imports.ui.keyringPrompt;
const Environment = imports.ui.environment;
const ExtensionSystem = imports.ui.extensionSystem;
const ExtensionDownloader = imports.ui.extensionDownloader;
@ -23,11 +20,9 @@ const Keyboard = imports.ui.keyboard;
const MessageTray = imports.ui.messageTray;
const Overview = imports.ui.overview;
const Panel = imports.ui.panel;
const PlaceDisplay = imports.ui.placeDisplay;
const RunDialog = imports.ui.runDialog;
const Layout = imports.ui.layout;
const LookingGlass = imports.ui.lookingGlass;
const NetworkAgent = imports.ui.networkAgent;
const NotificationDaemon = imports.ui.notificationDaemon;
const WindowAttentionHandler = imports.ui.windowAttentionHandler;
const ScreenShield = imports.ui.screenShield;
@ -35,7 +30,6 @@ const Scripting = imports.ui.scripting;
const SessionMode = imports.ui.sessionMode;
const ShellDBus = imports.ui.shellDBus;
const ShellMountOperation = imports.ui.shellMountOperation;
const TelepathyClient = imports.ui.telepathyClient;
const UnlockDialog = imports.ui.unlockDialog;
const WindowManager = imports.ui.windowManager;
const Magnifier = imports.ui.magnifier;
@ -43,10 +37,9 @@ const XdndHandler = imports.ui.xdndHandler;
const Util = imports.misc.util;
const OVERRIDES_SCHEMA = 'org.gnome.shell.overrides';
const DEFAULT_BACKGROUND_COLOR = Clutter.Color.from_pixel(0x2266bbff);
const DEFAULT_BACKGROUND_COLOR = Clutter.Color.from_pixel(0x2e3436ff);
let automountManager = null;
let autorunManager = null;
let componentManager = null;
let panel = null;
let overview = null;
let runDialog = null;
@ -56,9 +49,7 @@ let messageTray = null;
let screenShield = null;
let notificationDaemon = null;
let windowAttentionHandler = null;
let telepathyClient = null;
let ctrlAltTabManager = null;
let recorder = null;
let sessionMode = null;
let shellDBusService = null;
let shellMountOpDBusService = null;
@ -70,7 +61,6 @@ let magnifier = null;
let xdndHandler = null;
let keyboard = null;
let layoutManager = null;
let networkAgent = null;
let _startDate;
let _defaultCssStylesheet = null;
let _cssStylesheet = null;
@ -78,69 +68,10 @@ let _overridesSettings = null;
let background = null;
function createUserSession() {
telepathyClient = new TelepathyClient.Client();
automountManager = new AutomountManager.AutomountManager();
autorunManager = new AutorunManager.AutorunManager();
networkAgent = new NetworkAgent.NetworkAgent();
_initRecorder();
}
function createGDMSession() {
screenShield.showDialog();
}
function createGDMLoginDialog(parentActor) {
// We do this this here instead of at the top to prevent GDM
// related code from getting loaded in normal user sessions
const LoginDialog = imports.gdm.loginDialog;
let loginDialog = new LoginDialog.LoginDialog(parentActor);
return [loginDialog, true];
}
function createSessionUnlockDialog(parentActor) {
let dialog = new UnlockDialog.UnlockDialog(parentActor);
return [dialog, false];
}
function createInitialSetupSession() {
networkAgent = new NetworkAgent.NetworkAgent();
}
function _initRecorder() {
let recorderSettings = new Gio.Settings({ schema: 'org.gnome.shell.recorder' });
let desktopLockdownSettings = new Gio.Settings({ schema: 'org.gnome.desktop.lockdown' });
let bindingSettings = new Gio.Settings({ schema: 'org.gnome.shell.keybindings' });
global.display.add_keybinding('toggle-recording',
bindingSettings,
Meta.KeyBindingFlags.NONE, function() {
if (recorder == null) {
recorder = new Shell.Recorder({ stage: global.stage });
}
if (recorder.is_recording()) {
recorder.close();
Meta.enable_unredirect_for_screen(global.screen);
} else if (!desktopLockdownSettings.get_boolean('disable-save-to-disk')) {
// read the parameters from GSettings always in case they have changed
recorder.set_framerate(recorderSettings.get_int('framerate'));
/* Translators: this is a filename used for screencast recording */
// xgettext:no-c-format
recorder.set_filename(_("Screencast from %d %t") + '.' + recorderSettings.get_string('file-extension'));
let pipeline = recorderSettings.get_string('pipeline');
if (!pipeline.match(/^\s*$/))
recorder.set_pipeline(pipeline);
else
recorder.set_pipeline(null);
Meta.disable_unredirect_for_screen(global.screen);
recorder.record();
}
});
function _sessionUpdated() {
Meta.keybindings_set_custom_handler('panel-run-dialog', sessionMode.hasRunDialog ? openRunDialog : null);
if (sessionMode.isGreeter)
screenShield.showDialog();
}
function start() {
@ -206,51 +137,34 @@ function start() {
ctrlAltTabManager = new CtrlAltTab.CtrlAltTabManager();
overview = new Overview.Overview();
magnifier = new Magnifier.Magnifier();
screenShield = new ScreenShield.ScreenShield();
screenSaverDBus = new ShellDBus.ScreenSaverDBus();
if (UnlockDialog.isSupported())
screenShield = new ScreenShield.ScreenShield();
else
screenShield = new ScreenShield.ScreenShieldFallback();
panel = new Panel.Panel();
wm = new WindowManager.WindowManager();
messageTray = new MessageTray.MessageTray();
keyboard = new Keyboard.Keyboard();
notificationDaemon = new NotificationDaemon.NotificationDaemon();
windowAttentionHandler = new WindowAttentionHandler.WindowAttentionHandler();
componentManager = new Components.ComponentManager();
sessionMode.createSession();
panel.init();
layoutManager.init();
keyboard.init();
overview.init();
if (sessionMode.hasWorkspaces)
global.screen.override_workspace_layout(Meta.ScreenCorner.TOPLEFT,
false, -1, 1);
global.screen.override_workspace_layout(Meta.ScreenCorner.TOPLEFT,
false, -1, 1);
Meta.keybindings_set_custom_handler('panel-main-menu', Lang.bind(overview, overview.toggle));
global.display.connect('overlay-key', Lang.bind(overview, overview.toggle));
if (sessionMode.hasRunDialog) {
Meta.keybindings_set_custom_handler('panel-run-dialog', function() {
getRunDialog().open();
});
}
if (sessionMode.hasOverview) {
Meta.keybindings_set_custom_handler('panel-main-menu', function () {
overview.toggle();
});
global.display.connect('overlay-key',
Lang.bind(overview, overview.toggle));
}
sessionMode.connect('update', _sessionUpdated);
_sessionUpdated();
// Provide the bus object for gnome-session to
// initiate logouts.
EndSessionDialog.init();
// Attempt to become a PolicyKit authentication agent
PolkitAuthenticationAgent.init()
// Become a prompter for gnome keyring
KeyringPrompt.init();
_startDate = new Date();
global.stage.connect('captured-event', _globalKeyPressHandler);
@ -275,10 +189,8 @@ function start() {
_nWorkspacesChanged();
if (sessionMode.allowExtensions) {
ExtensionDownloader.init();
ExtensionSystem.loadExtensions();
}
ExtensionDownloader.init();
ExtensionSystem.init();
}
let _workspaces = [];
@ -522,7 +434,6 @@ function notify(msg, details) {
messageTray.add(source);
let notification = new MessageTray.Notification(source, msg, details);
notification.setTransient(true);
notification.setShowWhenLocked(true);
source.notify(notification);
}
@ -617,7 +528,7 @@ function _globalKeyPressHandler(actor, event) {
if (!sessionMode.hasRunDialog)
return false;
getRunDialog().open();
openRunDialog();
return true;
case Meta.KeyBindingAction.PANEL_MAIN_MENU:
case Meta.KeyBindingAction.OVERLAY_KEY:
@ -763,11 +674,11 @@ function createLookingGlass() {
return lookingGlass;
}
function getRunDialog() {
function openRunDialog() {
if (runDialog == null) {
runDialog = new RunDialog.RunDialog();
}
return runDialog;
runDialog.open();
}
/**

View File

@ -318,7 +318,7 @@ const Notification = new Lang.Class({
// 'transient' is a reserved keyword in JS, so we have to use an alternate variable name
this.isTransient = false;
this.expanded = false;
this.showWhenLocked = false;
this.focused = false;
this.acknowledged = false;
this._destroyed = false;
this._useActionIcons = false;
@ -711,14 +711,6 @@ const Notification = new Lang.Class({
this.isTransient = isTransient;
},
setShowWhenLocked: function(show) {
if (show && !this.isTransient) {
throw new Error('ShowWhenLocked can only be set on a transient notification');
}
this.showWhenLocked = show;
},
setUseActionIcons: function(useIcons) {
this._useActionIcons = useIcons;
},
@ -952,11 +944,22 @@ const SourceActor = new Lang.Class({
}));
this._actorDestroyed = false;
this._counterLabel = new St.Label();
this._counterLabel = new St.Label( {x_align: Clutter.ActorAlign.CENTER,
x_expand: true,
y_align: Clutter.ActorAlign.CENTER,
y_expand: true });
this._counterBin = new St.Bin({ style_class: 'summary-source-counter',
child: this._counterLabel });
child: this._counterLabel,
layout_manager: new Clutter.BinLayout() });
this._counterBin.hide();
this._counterBin.connect('style-changed', Lang.bind(this, function() {
let themeNode = this._counterBin.get_theme_node();
this._counterBin.translation_x = themeNode.get_length('-shell-counter-overlap-x');
this._counterBin.translation_y = themeNode.get_length('-shell-counter-overlap-y');
}));
this._iconBin = new St.Bin({ width: size,
height: size,
x_fill: true,
@ -1025,7 +1028,14 @@ const SourceActor = new Lang.Class({
return;
this._counterBin.visible = this._source.countVisible;
this._counterLabel.set_text(this._source.count.toString());
let text;
if (this._source.count < 100)
text = this._source.count.toString();
else
text = String.fromCharCode(0x22EF); // midline horizontal ellipsis
this._counterLabel.set_text(text);
}
});
@ -1042,6 +1052,7 @@ const Source = new Lang.Class({
this.isChat = false;
this.isMuted = false;
this.showInLockScreen = true;
this.keepTrayOnSummaryClick = false;
this.notifications = [];
},
@ -1062,6 +1073,27 @@ const Source = new Lang.Class({
this.emit('count-updated');
},
buildRightClickMenu: function() {
let item;
let rightClickMenu = new St.BoxLayout({ name: 'summary-right-click-menu',
vertical: true });
item = new PopupMenu.PopupMenuItem(_("Open"));
item.connect('activate', Lang.bind(this, function() {
this.open();
this.emit('done-displaying-content');
}));
rightClickMenu.add(item.actor);
item = new PopupMenu.PopupMenuItem(_("Remove"));
item.connect('activate', Lang.bind(this, function() {
this.destroy();
this.emit('done-displaying-content');
}));
rightClickMenu.add(item.actor);
return rightClickMenu;
},
setTransient: function(isTransient) {
this.isTransient = isTransient;
},
@ -1190,6 +1222,7 @@ const SummaryItem = new Lang.Class({
can_focus: true,
track_hover: true });
this.actor.label_actor = new St.Label({ text: source.title });
this.actor.connect('key-press-event', Lang.bind(this, this._onKeyPress));
this._sourceBox = new St.BoxLayout({ style_class: 'summary-source' });
this._sourceIcon = source.getSummaryIcon();
@ -1201,10 +1234,9 @@ const SummaryItem = new Lang.Class({
this._closeButton = makeCloseButton();
this._closeButton.connect('clicked', Lang.bind(this, function() {
source.destroy();
this.emit('done-displaying-content');
source.emit('done-displaying-content');
}));
this.notificationStackWidget.add_actor(this._closeButton);
this.notificationStackView = new St.ScrollView({ style_class: source.isChat ? '' : 'summary-notification-stack-scrollview',
vscrollbar_policy: source.isChat ? Gtk.PolicyType.NEVER : Gtk.PolicyType.AUTOMATIC,
hscrollbar_policy: Gtk.PolicyType.NEVER });
@ -1213,6 +1245,7 @@ const SummaryItem = new Lang.Class({
vertical: true });
this.notificationStackView.add_actor(this.notificationStack);
this.notificationStackWidget.add_actor(this.notificationStackView);
this.notificationStackWidget.add_actor(this._closeButton);
this._stackedNotifications = [];
this._oldMaxScrollAdjustment = 0;
@ -1224,38 +1257,9 @@ const SummaryItem = new Lang.Class({
this._oldMaxScrollAdjustment = adjustment.upper;
}));
this.rightClickMenu = new St.BoxLayout({ name: 'summary-right-click-menu',
vertical: true });
let item;
item = new PopupMenu.PopupMenuItem(_("Open"));
item.connect('activate', Lang.bind(this, function() {
source.open();
this.emit('done-displaying-content');
}));
this.rightClickMenu.add(item.actor);
item = new PopupMenu.PopupMenuItem(_("Remove"));
item.connect('activate', Lang.bind(this, function() {
source.destroy();
this.emit('done-displaying-content');
}));
this.rightClickMenu.add(item.actor);
if (source.isChat) {
item = new PopupMenu.PopupMenuItem('');
item.actor.connect('notify::mapped', Lang.bind(this, function() {
item.label.set_text(source.isMuted ? _("Unmute") : _("Mute"));
}));
item.connect('activate', Lang.bind(this, function() {
source.setMuted(!source.isMuted);
this.emit('done-displaying-content');
}));
this.rightClickMenu.add(item.actor);
}
global.focus_manager.add_group(this.rightClickMenu);
this.rightClickMenu = source.buildRightClickMenu();
if (this.rightClickMenu)
global.focus_manager.add_group(this.rightClickMenu);
},
get closeButtonVisible() {
@ -1266,6 +1270,14 @@ const SummaryItem = new Lang.Class({
this._closeButton.visible = v;
},
_onKeyPress: function(actor, event) {
if (event.get_key_symbol() == Clutter.KEY_Up) {
actor.emit('clicked', 1);
return true;
}
return false;
},
prepareNotificationStackForShowing: function() {
if (this.notificationStack.get_n_children() > 0)
return;
@ -1330,7 +1342,7 @@ const SummaryItem = new Lang.Class({
},
_notificationDoneDisplaying: function() {
this.emit('done-displaying-content');
this.source.emit('done-displaying-content');
},
_notificationDestroyed: function(notification) {
@ -1368,39 +1380,47 @@ const MessageTray = new Lang.Class({
}));
this.actor = new St.Widget({ name: 'message-tray',
layout_manager: new Clutter.BinLayout(),
reactive: true,
track_hover: true });
this.actor.connect('style-changed', Lang.bind(this, this._onStyleChanged));
track_hover: true,
layout_manager: new Clutter.BinLayout(),
x_expand: true,
y_expand: true,
y_align: Clutter.ActorAlign.START,
});
this.actor.connect('notify::hover', Lang.bind(this, this._onTrayHoverChanged));
this._notificationWidget = new St.Widget({ name: 'notification-container',
y_align: Clutter.ActorAlign.START,
x_align: Clutter.ActorAlign.CENTER,
y_expand: true,
x_expand: true,
layout_manager: new Clutter.BinLayout() });
this.actor.add_actor(this._notificationWidget);
this._notificationBin = new St.Bin();
this._notificationBin = new St.Bin({ y_expand: true });
this._notificationBin.set_y_align(Clutter.ActorAlign.START);
this._notificationWidget.add_actor(this._notificationBin);
this._notificationWidget.hide();
this._notificationQueue = [];
this._notification = null;
this._notificationClickedId = 0;
this._summaryBin = new St.Bin({ x_align: St.Align.END,
y_expand: true, // this is the Clutter property
reactive: true });
this._summaryBin.connect('button-release-event', Lang.bind(this, function(actor, event) {
this.actor.connect('button-release-event', Lang.bind(this, function(actor, event) {
this._setClickedSummaryItem(null);
this._updateState();
actor.grab_key_focus();
}));
this.actor.add_actor(this._summaryBin);
global.focus_manager.add_group(this.actor);
this._summary = new St.BoxLayout({ name: 'summary-mode',
reactive: true,
track_hover: true });
global.focus_manager.add_group(this._summary);
track_hover: true,
x_align: Clutter.ActorAlign.END,
x_expand: true,
y_align: Clutter.ActorAlign.CENTER,
y_expand: true });
this._summary.connect('notify::hover', Lang.bind(this, this._onSummaryHoverChanged));
this._summaryBin.child = this._summary;
this._summaryBin.opacity = 0;
this.actor.add_actor(this._summary);
this._summary.opacity = 0;
this._summaryMotionId = 0;
this._trayMotionId = 0;
@ -1408,6 +1428,8 @@ const MessageTray = new Lang.Class({
this._summaryBoxPointer = new BoxPointer.BoxPointer(St.Side.BOTTOM,
{ reactive: true,
track_hover: true });
this._summaryBoxPointer.actor.connect('key-press-event',
Lang.bind(this, this._onSummaryBoxPointerKeyPress));
this._summaryBoxPointer.actor.style_class = 'summary-boxpointer';
this._summaryBoxPointer.actor.hide();
Main.layoutManager.addChrome(this._summaryBoxPointer.actor);
@ -1433,8 +1455,11 @@ const MessageTray = new Lang.Class({
this._grabHelper = new GrabHelper.GrabHelper(this.actor);
this._grabHelper.addActor(this._summaryBoxPointer.actor);
this._grabHelper.addActor(this.actor);
if (Main.panel.statusArea.activities)
this._grabHelper.addActor(Main.panel.statusArea.activities.hotCorner.actor);
Main.layoutManager.keyboardBox.connect('notify::hover', Lang.bind(this, this._onKeyboardHoverChanged));
Main.layoutManager.connect('keyboard-visible-changed', Lang.bind(this, this._onKeyboardVisibleChanged));
this._trayState = State.HIDDEN;
this._locked = false;
@ -1443,18 +1468,22 @@ const MessageTray = new Lang.Class({
this._trayLeftTimeoutId = 0;
this._pointerInTray = false;
this._pointerInKeyboard = false;
this._keyboardVisible = false;
this._summaryState = State.HIDDEN;
this._pointerInSummary = false;
this._notificationClosed = false;
this._notificationState = State.HIDDEN;
this._notificationTimeoutId = 0;
this._notificationExpandedId = 0;
this._summaryBoxPointerState = State.HIDDEN;
this._summaryBoxPointerTimeoutId = 0;
this._desktopCloneState = State.HIDDEN;
this._overviewVisible = Main.overview.visible;
this._notificationRemoved = false;
this._reNotifyAfterHideNotification = null;
this._inFullscreen = false;
this._desktopClone = null;
this._inCtrlAltTab = false;
this._lightbox = new Lightbox.Lightbox(global.window_group,
{ inhibitEvents: true,
@ -1469,14 +1498,12 @@ const MessageTray = new Lang.Class({
Main.layoutManager.trackChrome(this._notificationWidget);
Main.layoutManager.trackChrome(this._closeButton);
Main.layoutManager.connect('monitors-changed', Lang.bind(this, function() {
this.actor.style_changed();
}));
Main.layoutManager.connect('primary-fullscreen-changed', Lang.bind(this, this._onFullscreenChanged));
Main.overview.connect('showing', Lang.bind(this,
function() {
this._overviewVisible = true;
this._grabHelper.ungrab(); // drop modal grab if necessary
this.actor.add_style_pseudo_class('overview');
this._updateState();
}));
@ -1488,8 +1515,7 @@ const MessageTray = new Lang.Class({
this._updateState();
}));
this._isScreenLocked = false;
Main.screenShield.connect('lock-status-changed', Lang.bind(this, this._onScreenLockStatusChanged));
Main.sessionMode.connect('updated', Lang.bind(this, this._updateState));
global.display.add_keybinding('toggle-message-tray',
new Gio.Settings({ schema: SHELL_KEYBINDINGS_SCHEMA }),
@ -1503,6 +1529,7 @@ const MessageTray = new Lang.Class({
pointerWatcher.addWatch(TRAY_DWELL_CHECK_INTERVAL, Lang.bind(this, this._checkTrayDwell));
this._trayDwellTimeoutId = 0;
this._trayDwelling = false;
this._trayDwellUserTime = 0;
},
_checkTrayDwell: function(x, y) {
@ -1516,9 +1543,14 @@ const MessageTray = new Lang.Class({
// of the monitor. The _trayDwelling variable is used so that we only try to
// fire off one tray dwell - if it fails (because, say, the user has the mouse down),
// we don't try again until the user moves the mouse up and down again.
if (!this._trayDwelling && !this.actor.hover && this._trayDwellTimeoutId == 0)
if (!this._trayDwelling && !this.actor.hover && this._trayDwellTimeoutId == 0) {
// Save the interaction timestamp so we can detect user input
let focusWindow = global.display.focus_window;
this._trayDwellUserTime = focusWindow ? focusWindow.user_time : 0;
this._trayDwellTimeoutId = Mainloop.timeout_add(TRAY_DWELL_TIME,
Lang.bind(this, this._trayDwellTimeout));
}
this._trayDwelling = true;
} else {
this._cancelTrayDwell();
@ -1534,6 +1566,16 @@ const MessageTray = new Lang.Class({
},
_trayDwellTimeout: function() {
if (Main.modalCount > 0)
return false;
// If the user interacted with the focus window since we started the tray
// dwell (by clicking or typing), don't activate the message tray
let focusWindow = global.display.focus_window;
let currentUserTime = focusWindow ? focusWindow.user_time : 0;
if (currentUserTime != this._trayDwellUserTime)
return false;
this._trayDwellTimeoutId = 0;
this._traySummoned = true;
@ -1544,21 +1586,16 @@ const MessageTray = new Lang.Class({
_onCloseClicked: function() {
if (this._notificationState == State.SHOWN) {
this._notificationClosed = true;
this._notification.emit('done-displaying');
if (!this._notification.resident)
this._notification.destroy();
this._notificationClosed = false;
}
},
_onStyleChanged: function() {
let monitor = Main.layoutManager.bottomMonitor;
let width = this._notificationWidget.get_width();
this._notificationWidget.x = Math.floor((monitor.width - width) / 2);
this._summaryBin.x = 0;
this._summaryBin.width = monitor.width;
},
contains: function(source) {
return this._getIndexOfSummaryItemForSource(source) >= 0;
},
@ -1668,11 +1705,6 @@ const MessageTray = new Lang.Class({
this._notificationQueue.splice(index, 1);
},
_onScreenLockStatusChanged: function(screenShield, locked) {
this._isScreenLocked = locked;
this._updateState();
},
_lock: function() {
this._locked = true;
},
@ -1691,10 +1723,8 @@ const MessageTray = new Lang.Class({
},
toggleAndNavigate: function() {
// Grab the key focus so that GrabHelper knows
// that we have the key grab.
this._summary.grab_key_focus();
this.toggle();
this._summary.navigate_focus(null, Gtk.DirectionType.TAB_FORWARD, false);
},
hide: function() {
@ -1747,7 +1777,10 @@ const MessageTray = new Lang.Class({
_onSummaryItemClicked: function(summaryItem, button) {
if (summaryItem.source.handleSummaryClick()) {
this._escapeTray();
if (summaryItem.source.keepTrayOnSummaryClick)
this._setClickedSummaryItem(null);
else
this._escapeTray();
} else {
if (!this._setClickedSummaryItem(summaryItem, button))
this._setClickedSummaryItem(null);
@ -1838,6 +1871,20 @@ const MessageTray = new Lang.Class({
this._updateState();
},
_onKeyboardVisibleChanged: function(layoutManager, keyboardVisible) {
if (this._keyboardVisible == keyboardVisible)
return;
this._keyboardVisible = keyboardVisible;
if (keyboardVisible)
this.actor.add_style_pseudo_class('keyboard');
else
this.actor.remove_style_pseudo_class('keyboard');
this._updateState();
},
_onFullscreenChanged: function(obj, state) {
this._inFullscreen = state;
this._updateState();
@ -1898,34 +1945,26 @@ const MessageTray = new Lang.Class({
// at the present time.
_updateState: function() {
// Notifications
let notificationQueue = this._notificationQueue.filter(Lang.bind(this, function(notification) {
if (this._isScreenLocked)
return notification.showWhenLocked;
else
return true;
}));
let notificationQueue = this._notificationQueue;
let notificationUrgent = notificationQueue.length > 0 && notificationQueue[0].urgency == Urgency.CRITICAL;
// notificationsLimited is false when the screen is locked, because they go through
// different filtering, and we want to show non urgent messages at times
let notificationsLimited = (this._busy || this._inFullscreen) && !this._isScreenLocked;
let notificationsPending = notificationQueue.length > 0 && (!notificationsLimited || notificationUrgent);
let notificationsLimited = this._busy || this._inFullscreen;
let notificationsPending = notificationQueue.length > 0 && (!notificationsLimited || notificationUrgent) && Main.sessionMode.hasNotifications;
let nextNotification = notificationQueue.length > 0 ? notificationQueue[0] : null;
let notificationPinned = this._pointerInTray && !this._pointerInSummary && !this._notificationRemoved;
let notificationExpanded = this._notification && this._notification.expanded;
let notificationExpired = this._notificationTimeoutId == 0 &&
!(this._notification && this._notification.urgency == Urgency.CRITICAL) &&
!(this._notification && this._notification.focused) &&
!this._pointerInTray &&
!this._locked &&
!(this._pointerInKeyboard && notificationExpanded);
let notificationLockedOut = this._isScreenLocked && (this._notification && !this._notification.showWhenLocked);
// TODO: how to deal with locked out notiifcations if want to keep showing notifications?!
let notificationMustClose = this._notificationRemoved || notificationLockedOut || (notificationExpired && this._userActiveWhileNotificationShown);
let notificationLockedOut = !Main.sessionMode.hasNotifications && this._notification;
let notificationMustClose = this._notificationRemoved || notificationLockedOut || (notificationExpired && this._userActiveWhileNotificationShown) || this._notificationClosed;
let canShowNotification = notificationsPending && this._summaryState == State.HIDDEN;
if (this._notificationState == State.HIDDEN) {
if (canShowNotification) {
this._showNotification(nextNotification);
this._notificationQueue.splice(this._notificationQueue.indexOf(nextNotification), 1);
this._showNotification();
}
} else if (this._notificationState == State.SHOWN) {
if (notificationMustClose)
@ -1947,7 +1986,7 @@ const MessageTray = new Lang.Class({
let summaryOptionalInOverview = this._overviewVisible && !this._locked && !summaryHovered;
let mustHideSummary = (notificationsPending && (notificationUrgent || summaryOptionalInOverview))
|| notificationsVisible || this._isScreenLocked;
|| notificationsVisible || !Main.sessionMode.hasNotifications;
if (this._summaryState == State.HIDDEN && !mustHideSummary && summarySummoned)
this._showSummary();
@ -1989,6 +2028,19 @@ const MessageTray = new Lang.Class({
this._showTray();
else if (trayIsVisible && !trayShouldBeVisible)
this._hideTray();
// Desktop clone
let desktopCloneIsVisible = (this._desktopCloneState == State.SHOWING ||
this._desktopCloneState == State.SHOWN);
let desktopCloneShouldBeVisible = (trayShouldBeVisible &&
!this._overviewVisible &&
!this._keyboardVisible);
if (!desktopCloneIsVisible && desktopCloneShouldBeVisible) {
this._showDesktopClone();
} else if (desktopCloneIsVisible && !desktopCloneShouldBeVisible) {
this._hideDesktopClone (this._keyboardVisible);
}
},
_tween: function(actor, statevar, value, params) {
@ -2017,8 +2069,10 @@ const MessageTray = new Lang.Class({
// Don't actually take a modal grab in the overview.
// Just add something to the grab stack that we can
// pop later.
let modal = !this._overviewVisible;
if (!this._grabHelper.grab({ actor: this.actor,
modal: !this._overviewVisible,
modal: modal,
onUngrab: Lang.bind(this, this._escapeTray) })) {
this._traySummoned = false;
return;
@ -2030,84 +2084,89 @@ const MessageTray = new Lang.Class({
transition: 'easeOutQuad'
});
// Don't move the windows up if we are in the overview,
// but show the tray in the ctrl+alt+tab list.
if (this._overviewVisible) {
Main.ctrlAltTabManager.addGroup(this._summary, _("Message Tray"), 'start-here-symbolic',
{ sortGroup: CtrlAltTab.SortGroup.BOTTOM });
return;
this._inCtrlAltTab = true;
} else {
this._lightbox.show();
}
},
_showDesktopClone: function() {
let bottomMonitor = Main.layoutManager.bottomMonitor;
let geometry = new Clutter.Geometry({ x: bottomMonitor.x,
y: bottomMonitor.y,
width: bottomMonitor.width,
height: bottomMonitor.height
});
if (this._desktopClone)
this._desktopClone.destroy();
this._desktopClone = new Clutter.Clone({ source: global.window_group, clip: geometry });
Main.uiGroup.insert_child_above(this._desktopClone, global.window_group);
this._desktopClone.x = 0;
this._desktopClone.y = 0;
this._desktopClone.show();
this._lightbox.show();
this._desktopClone._progress = 0;
Tweener.addTween(this._desktopClone,
{ _progress: this.actor.height,
time: ANIMATION_TIME,
transition: 'easeOutQuad',
onUpdate: Lang.bind(this, function() {
let progress = Math.round(this._desktopClone._progress);
this._desktopClone.y = - progress;
this._desktopClone.set_clip(geometry.x,
geometry.y + progress,
geometry.width,
geometry.height - progress);
})
});
this._tween(this._desktopClone, '_desktopCloneState', State.SHOWN,
{ y: -this.actor.height,
time: ANIMATION_TIME,
transition: 'easeOutQuad',
onUpdate: function() {
let progress = Math.round(-this.y);
this.set_clip(geometry.x,
geometry.y + progress,
geometry.width,
geometry.height - progress);
}
});
},
_hideTray: function() {
// Note that we might have entered here without a grab,
// which would happen if GrabHelper ungrabbed for us.
// This is a no-op in that case.
this._grabHelper.ungrab({ actor: this.actor });
this._tween(this.actor, '_trayState', State.HIDDEN,
{ y: 0,
time: ANIMATION_TIME,
transition: 'easeOutQuad'
});
// If we are coming back from the overview, there are no windows
// to be moved. Just remove the tray from the ctrl+alt+tab list.
if (!this._desktopClone) {
// Note that we might have entered here without a grab,
// which would happen if GrabHelper ungrabbed for us.
// This is a no-op in that case.
this._grabHelper.ungrab({ actor: this.actor });
if (this._inCtrlAltTab) {
Main.ctrlAltTabManager.removeGroup(this._summary);
this._inCtrlAltTab = false;
} else {
this._lightbox.hide();
}
},
_hideDesktopClone: function(now) {
if (now) {
this._desktopClone.destroy();
this._desktopClone = null;
this._desktopCloneState = State.HIDDEN;
return;
}
let geometry = this._desktopClone.clip;
this._desktopClone._progress = 0;
Tweener.addTween(this._desktopClone,
{ _progress: this.actor.height,
time: ANIMATION_TIME,
transition: 'easeOutQuad',
onComplete: Lang.bind(this, function() {
this._desktopClone.destroy();
this._desktopClone = null;
}),
onUpdate: Lang.bind(this, function() {
let progress = Math.round(this._desktopClone._progress);
this._desktopClone.y = progress - this.actor.height;
this._desktopClone.set_clip(geometry.x,
geometry.y - progress,
geometry.width,
geometry.height + progress);
})
});
this._lightbox.hide();
this._tween(this._desktopClone, '_desktopCloneState', State.HIDDEN,
{ y: 0,
time: ANIMATION_TIME,
transition: 'easeOutQuad',
onComplete: Lang.bind(this, function() {
this._desktopClone.destroy();
this._desktopClone = null;
}),
onUpdate: function() {
let progress = Math.round(-this.y);
this.set_clip(geometry.x,
geometry.y - progress,
geometry.width,
geometry.height + progress);
}
});
},
_onIdleMonitorWatch: function(monitor, id, userBecameIdle) {
@ -2119,13 +2178,16 @@ const MessageTray = new Lang.Class({
this._updateState();
},
_showNotification: function(notification) {
this._notification = notification;
_showNotification: function() {
this._notification = this._notificationQueue.shift();
this._userActiveWhileNotificationShown = this.idleMonitor.get_idletime() <= IDLE_TIME;
this._idleMonitorWatchId = this.idleMonitor.add_watch(IDLE_TIME,
Lang.bind(this, this._onIdleMonitorWatch));
this._notificationClickedId = this._notification.connect('done-displaying',
Lang.bind(this, this._escapeTray));
this._notification.connect('unfocused', Lang.bind(this, function() {
this._updateState();
}));
this._notificationBin.child = this._notification.actor;
this._notificationWidget.opacity = 0;
@ -2311,18 +2373,16 @@ const MessageTray = new Lang.Class({
},
_showSummary: function() {
this._summaryBin.opacity = 0;
this._summaryBin.y = this.actor.height;
this._tween(this._summaryBin, '_summaryState', State.SHOWN,
{ y: 0,
opacity: 255,
this._summary.opacity = 0;
this._tween(this._summary, '_summaryState', State.SHOWN,
{ opacity: 255,
time: ANIMATION_TIME,
transition: 'easeOutQuad',
});
},
_hideSummary: function() {
this._tween(this._summaryBin, '_summaryState', State.HIDDEN,
this._tween(this._summary, '_summaryState', State.HIDDEN,
{ opacity: 0,
time: ANIMATION_TIME,
transition: 'easeOutQuad',
@ -2333,9 +2393,11 @@ const MessageTray = new Lang.Class({
this._summaryBoxPointerItem = this._clickedSummaryItem;
this._summaryBoxPointerContentUpdatedId = this._summaryBoxPointerItem.connect('content-updated',
Lang.bind(this, this._onSummaryBoxPointerContentUpdated));
this._summaryBoxPointerDoneDisplayingId = this._summaryBoxPointerItem.connect('done-displaying-content',
Lang.bind(this, this._escapeTray));
if (this._clickedSummaryItemMouseButton == 1) {
this._sourceDoneDisplayingId = this._summaryBoxPointerItem.source.connect('done-displaying-content',
Lang.bind(this, this._escapeTray));
let hasRightClickMenu = this._summaryBoxPointerItem.rightClickMenu != null;
if (this._clickedSummaryItemMouseButton == 1 || !hasRightClickMenu) {
let newQueue = [];
for (let i = 0; i < this._notificationQueue.length; i++) {
let notification = this._notificationQueue[i];
@ -2355,7 +2417,6 @@ const MessageTray = new Lang.Class({
}
this._grabHelper.grab({ actor: this._summaryBoxPointer.bin.child,
untracked: true,
grabFocus: true,
onUngrab: Lang.bind(this, this._onSummaryBoxPointerUngrabbed) });
this._lock();
@ -2418,6 +2479,21 @@ const MessageTray = new Lang.Class({
return true;
},
_onSummaryBoxPointerKeyPress: function(actor, event) {
switch (event.get_key_symbol()) {
case Clutter.KEY_Down:
case Clutter.KEY_Escape:
this._setClickedSummaryItem(null);
this._updateState();
return true;
case Clutter.KEY_Delete:
this._clickedSummaryItem.source.destroy();
this._escapeTray();
return true;
}
return false;
},
_onSummaryBoxPointerUngrabbed: function() {
this._summaryBoxPointerState = State.HIDING;
this._unlock();
@ -2431,14 +2507,6 @@ const MessageTray = new Lang.Class({
},
_hideSummaryBoxPointer: function() {
// We should be sure to hide the box pointer if all notifications in it are destroyed while
// it is hiding, so that we don't show an animation of an empty blob being hidden.
if (this._summaryBoxPointerState == State.HIDING &&
this._summaryBoxPointerItem.notificationStack.get_n_children() == 0) {
this._summaryBoxPointer.actor.hide();
return;
}
this._grabHelper.ungrab({ actor: this._summaryBoxPointer.bin.child });
},
@ -2449,7 +2517,7 @@ const MessageTray = new Lang.Class({
this._summaryBoxPointer.bin.child = null;
this._summaryBoxPointerItem.disconnect(this._summaryBoxPointerContentUpdatedId);
this._summaryBoxPointerContentUpdatedId = 0;
this._summaryBoxPointerItem.disconnect(this._summaryBoxPointerDoneDisplayingId);
this._summaryBoxPointerItem.source.disconnect(this._sourceDoneDisplayingId);
this._summaryBoxPointerDoneDisplayingId = 0;
let sourceNotificationStackDoneShowing = null;

View File

@ -37,12 +37,13 @@ const ModalDialog = new Lang.Class({
_init: function(params) {
params = Params.parse(params, { shellReactive: false,
styleClass: null,
parentActor: Main.uiGroup
});
parentActor: Main.uiGroup,
shouldFadeIn: true });
this.state = State.CLOSED;
this._hasModal = false;
this._shellReactive = params.shellReactive;
this._shouldFadeIn = params.shouldFadeIn;
this._group = new St.Widget({ visible: false,
x: 0,
@ -210,7 +211,7 @@ const ModalDialog = new Lang.Class({
this._group.show();
Tweener.addTween(this._group,
{ opacity: 255,
time: OPEN_AND_CLOSE_TIME,
time: this._shouldFadeIn ? OPEN_AND_CLOSE_TIME : 0,
transition: 'easeOutQuad',
onComplete: Lang.bind(this,
function() {

View File

@ -499,7 +499,7 @@ const NotificationDaemon = new Lang.Class({
},
_onTrayIconAdded: function(o, icon) {
let wmClass = icon.wm_class.toLowerCase();
let wmClass = icon.wm_class ? icon.wm_class.toLowerCase() : '';
if (STANDARD_TRAY_ICON_IMPLEMENTATIONS[wmClass] !== undefined)
return;

View File

@ -71,7 +71,6 @@ const ShellInfo = new Lang.Class({
if (this._source.notifications.length == 0) {
notification = new MessageTray.Notification(this._source, text, null);
notification.setTransient(true);
notification.setShowWhenLocked(true);
} else {
notification = this._source.notifications[0];
notification.update(text, null, { clear: true });
@ -92,16 +91,21 @@ const ShellInfo = new Lang.Class({
const Overview = new Lang.Class({
Name: 'Overview',
_init : function() {
this.isDummy = !Main.sessionMode.hasOverview;
_init: function() {
this._overviewCreated = false;
// We only have an overview in user sessions, so
// create a dummy overview in other cases
if (this.isDummy) {
this.animationInProgress = false;
this.visible = false;
Main.sessionMode.connect('updated', Lang.bind(this, this._sessionUpdated));
this._sessionUpdated();
},
_createOverview: function() {
if (this._overviewCreated)
return;
}
if (this.isDummy)
return;
this._overviewCreated = true;
// The main BackgroundActor is inside global.window_group which is
// hidden when displaying the overview, so we create a new
@ -174,6 +178,11 @@ const Overview = new Lang.Class({
this._needsFakePointerEvent = false;
},
_sessionUpdated: function() {
this.isDummy = !Main.sessionMode.hasOverview;
this._createOverview();
},
// The members we construct that are implemented in JS might
// want to access the overview as Main.overview to connect
// signal handlers and so forth. So we create them after

View File

@ -468,15 +468,6 @@ const AppMenuButton = new Lang.Class({
this._sync();
},
setLockedState: function(locked) {
if (locked) {
this.hide();
} else {
this.show();
this._sync();
}
},
_sync: function() {
let tracker = Shell.WindowTracker.get_default();
let focusedApp = tracker.focus_app;
@ -610,8 +601,8 @@ const ActivitiesButton = new Lang.Class({
this.actor.label_actor = this._label;
this._hotCorner = new Layout.HotCorner();
container.add_actor(this._hotCorner.actor);
this.hotCorner = new Layout.HotCorner();
container.add_actor(this.hotCorner.actor);
// Hack up our menu...
this.menu.open = Lang.bind(this, this._onMenuOpenRequest);
@ -661,10 +652,10 @@ const ActivitiesButton = new Lang.Class({
}
hotBox.x1 = Math.round(x);
hotBox.x2 = hotBox.x1 + this._hotCorner.actor.width;
hotBox.x2 = hotBox.x1 + this.hotCorner.actor.width;
hotBox.y1 = Math.round(y);
hotBox.y2 = hotBox.y1 + this._hotCorner.actor.height;
this._hotCorner.actor.allocate(hotBox, flags);
hotBox.y2 = hotBox.y1 + this.hotCorner.actor.height;
this.hotCorner.actor.allocate(hotBox, flags);
},
handleDragOver: function(source, actor, x, y, time) {
@ -686,7 +677,7 @@ const ActivitiesButton = new Lang.Class({
_onCapturedEvent: function(actor, event) {
if (event.type() == Clutter.EventType.BUTTON_PRESS) {
if (!this._hotCorner.shouldToggleOverviewOnClick())
if (!this.hotCorner.shouldToggleOverviewOnClick())
return true;
}
return false;
@ -943,8 +934,6 @@ const Panel = new Lang.Class({
this.actor.remove_style_class_name('in-overview');
}));
Main.screenShield.connect('lock-status-changed', Lang.bind(this, this._onLockStateChanged));
this.menuManager = new PopupMenu.PopupMenuManager(this);
this._leftBox = new St.BoxLayout({ name: 'panelLeft' });
@ -975,6 +964,9 @@ const Panel = new Lang.Class({
Main.layoutManager.panelBox.add(this.actor);
Main.ctrlAltTabManager.addGroup(this.actor, _("Top Bar"), 'start-here-symbolic',
{ sortGroup: CtrlAltTab.SortGroup.TOP });
Main.sessionMode.connect('updated', Lang.bind(this, this._updatePanel));
this._updatePanel();
},
_getPreferredWidth: function(actor, forHeight, alloc) {
@ -1103,11 +1095,27 @@ const Panel = new Lang.Class({
menu.actor.navigate_focus(null, Gtk.DirectionType.TAB_FORWARD, false);
},
init: function() {
set boxOpacity(value) {
let isReactive = value > 0;
this._leftBox.opacity = value;
this._leftBox.reactive = isReactive;
this._centerBox.opacity = value;
this._centerBox.reactive = isReactive;
this._rightBox.opacity = value;
this._rightBox.reactive = isReactive;
},
get boxOpacity() {
return this._leftBox.opacity;
},
_updatePanel: function() {
let panel = Main.sessionMode.panel;
this._initBox(panel.left, this._leftBox);
this._initBox(panel.center, this._centerBox);
this._initBox(panel.right, this._rightBox);
this._hideIndicators();
this._updateBox(panel.left, this._leftBox);
this._updateBox(panel.center, this._centerBox);
this._updateBox(panel.right, this._rightBox);
},
_initBox: function(elements, box) {
@ -1119,20 +1127,63 @@ const Panel = new Lang.Class({
// bluetooth or network)
continue;
}
}
},
let indicator = new constructor(this);
this._addToPanelBox(role, indicator, i, box);
_hideIndicators: function() {
for (let role in PANEL_ITEM_IMPLEMENTATIONS) {
let indicator = this.statusArea[role];
if (!indicator)
continue;
if (indicator.menu)
indicator.menu.close();
indicator.container.hide();
}
},
_ensureIndicator: function(role) {
let indicator = this.statusArea[role];
if (!indicator) {
let constructor = PANEL_ITEM_IMPLEMENTATIONS[role];
if (!constructor) {
// This icon is not implemented (this is a bug)
return null;
}
indicator = new constructor(this);
this.statusArea[role] = indicator;
}
return indicator;
},
_updateBox: function(elements, box) {
let nChildren = box.get_n_children();
for (let i = 0; i < elements.length; i++) {
let role = elements[i];
let indicator = this._ensureIndicator(role);
if (indicator == null)
continue;
this._addToPanelBox(role, indicator, i + nChildren, box);
}
},
_addToPanelBox: function(role, indicator, position, box) {
box.insert_child_at_index(indicator.actor, position);
let container = indicator.container;
container.show();
let parent = container.get_parent();
if (parent)
parent.remove_actor(container);
box.insert_child_at_index(container, position);
if (indicator.menu)
this.menuManager.addMenu(indicator.menu);
this.statusArea[role] = indicator;
let destroyId = indicator.connect('destroy', Lang.bind(this, function(emitter) {
delete this.statusArea[role];
emitter.disconnect(destroyId);
container.destroy();
}));
},
@ -1150,12 +1201,8 @@ const Panel = new Lang.Class({
right: this._rightBox
};
let boxContainer = boxes[box] || this._rightBox;
this.statusArea[role] = indicator;
this._addToPanelBox(role, indicator, position, boxContainer);
return indicator;
},
_onLockStateChanged: function(shield, locked) {
for (let id in this.statusArea)
this.statusArea[id].setLockedState(locked);
},
}
});

View File

@ -21,6 +21,10 @@ const ButtonBox = new Lang.Class({
this.actor = new Shell.GenericContainer(params);
this.actor._delegate = this;
this.container = new St.Bin({ y_fill: true,
x_fill: true,
child: this.actor });
this.actor.connect('get-preferred-width', Lang.bind(this, this._getPreferredWidth));
this.actor.connect('get-preferred-height', Lang.bind(this, this._getPreferredHeight));
this.actor.connect('allocate', Lang.bind(this, this._allocate));
@ -115,6 +119,12 @@ const Button = new Lang.Class({
this.setName(nameText);
},
setSensitive: function(sensitive) {
this.actor.reactive = sensitive;
this.actor.can_focus = sensitive;
this.actor.track_hover = sensitive;
},
setName: function(text) {
if (text != null) {
// This is the easiest way to provide a accessible name to
@ -146,13 +156,6 @@ const Button = new Lang.Class({
}
},
setLockedState: function(locked) {
// default behaviour is to hide completely
if (locked)
this.menu.close();
this.actor.visible = !locked;
},
_onButtonPress: function(actor, event) {
if (!this.menu)
return;

View File

@ -1,412 +0,0 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
const GLib = imports.gi.GLib;
const Gio = imports.gi.Gio;
const Shell = imports.gi.Shell;
const Lang = imports.lang;
const Mainloop = imports.mainloop;
const Signals = imports.signals;
const St = imports.gi.St;
const DND = imports.ui.dnd;
const Main = imports.ui.main;
const Params = imports.misc.params;
const Search = imports.ui.search;
const Util = imports.misc.util;
/**
* Represents a place object, which is most normally a bookmark entry,
* a mount/volume, or a special place like the Home Folder, Computer, and Network.
*
* @name: String title
* @iconFactory: A JavaScript callback which will create an icon texture given a size parameter
* @launch: A JavaScript callback to launch the entry
*/
const PlaceInfo = new Lang.Class({
Name: 'PlaceInfo',
_init: function(id, name, iconFactory, launch) {
this.id = id;
this.name = name;
this._lowerName = name.toLowerCase();
this.iconFactory = iconFactory;
this.launch = launch;
},
matchTerms: function(terms) {
let mtype = Search.MatchType.NONE;
for (let i = 0; i < terms.length; i++) {
let term = terms[i];
let idx = this._lowerName.indexOf(term);
if (idx == 0) {
mtype = Search.MatchType.PREFIX;
} else if (idx > 0) {
if (mtype == Search.MatchType.NONE)
mtype = Search.MatchType.SUBSTRING;
} else {
return Search.MatchType.NONE;
}
}
return mtype;
},
isRemovable: function() {
return false;
}
});
// Helper function to translate launch parameters into a GAppLaunchContext
function _makeLaunchContext(params)
{
params = Params.parse(params, { workspace: -1,
timestamp: 0 });
let launchContext = global.create_app_launch_context();
if (params.workspace != -1)
launchContext.set_desktop(params.workspace);
if (params.timestamp != 0)
launchContext.set_timestamp(params.timestamp);
return launchContext;
}
const PlaceDeviceInfo = new Lang.Class({
Name: 'PlaceDeviceInfo',
Extends: PlaceInfo,
_init: function(mount) {
this._mount = mount;
this.name = mount.get_name();
this._lowerName = this.name.toLowerCase();
this.id = 'mount:' + mount.get_root().get_uri();
},
iconFactory: function(size) {
let icon = this._mount.get_icon();
return St.TextureCache.get_default().load_gicon(null, icon, size);
},
launch: function(params) {
Gio.app_info_launch_default_for_uri(this._mount.get_root().get_uri(),
_makeLaunchContext(params));
},
isRemovable: function() {
return this._mount.can_unmount();
},
remove: function() {
if (!this.isRemovable())
return;
if (this._mount.can_eject())
this._mount.eject(0, null, Lang.bind(this, this._removeFinish));
else
this._mount.unmount(0, null, Lang.bind(this, this._removeFinish));
},
_removeFinish: function(o, res, data) {
try {
if (this._mount.can_eject())
this._mount.eject_finish(res);
else
this._mount.unmount_finish(res);
} catch (e) {
let message = _("Failed to unmount '%s'").format(o.get_name());
Main.overview.setMessage(message,
Lang.bind(this, this.remove),
_("Retry"));
}
}
});
const PlacesManager = new Lang.Class({
Name: 'PlacesManager',
_init: function() {
this._defaultPlaces = [];
this._mounts = [];
this._bookmarks = [];
let homeFile = Gio.file_new_for_path (GLib.get_home_dir());
let homeUri = homeFile.get_uri();
let homeLabel = Shell.util_get_label_for_uri (homeUri);
let homeIcon = Shell.util_get_icon_for_uri (homeUri);
this._home = new PlaceInfo('special:home', homeLabel,
function(size) {
return St.TextureCache.get_default().load_gicon(null, homeIcon, size);
},
function(params) {
Gio.app_info_launch_default_for_uri(homeUri, _makeLaunchContext(params));
});
let desktopPath = GLib.get_user_special_dir(GLib.UserDirectory.DIRECTORY_DESKTOP);
let desktopFile = Gio.file_new_for_path (desktopPath);
let desktopUri = desktopFile.get_uri();
let desktopLabel = Shell.util_get_label_for_uri (desktopUri);
let desktopIcon = Shell.util_get_icon_for_uri (desktopUri);
this._desktopMenu = new PlaceInfo('special:desktop', desktopLabel,
function(size) {
return St.TextureCache.get_default().load_gicon(null, desktopIcon, size);
},
function(params) {
Gio.app_info_launch_default_for_uri(desktopUri, _makeLaunchContext(params));
});
this._defaultPlaces.push(this._home);
this._defaultPlaces.push(this._desktopMenu);
/*
* Show devices, code more or less ported from nautilus-places-sidebar.c
*/
this._volumeMonitor = Gio.VolumeMonitor.get();
this._volumeMonitor.connect('volume-added', Lang.bind(this, this._updateDevices));
this._volumeMonitor.connect('volume-removed',Lang.bind(this, this._updateDevices));
this._volumeMonitor.connect('volume-changed', Lang.bind(this, this._updateDevices));
this._volumeMonitor.connect('mount-added', Lang.bind(this, this._updateDevices));
this._volumeMonitor.connect('mount-removed', Lang.bind(this, this._updateDevices));
this._volumeMonitor.connect('mount-changed', Lang.bind(this, this._updateDevices));
this._volumeMonitor.connect('drive-connected', Lang.bind(this, this._updateDevices));
this._volumeMonitor.connect('drive-disconnected', Lang.bind(this, this._updateDevices));
this._volumeMonitor.connect('drive-changed', Lang.bind(this, this._updateDevices));
this._updateDevices();
this._bookmarksPath = GLib.build_filenamev([GLib.get_user_config_dir(), 'gtk-3.0', 'bookmarks']);
this._bookmarksFile = Gio.file_new_for_path(this._bookmarksPath);
this._monitor = this._bookmarksFile.monitor_file(Gio.FileMonitorFlags.NONE, null);
this._bookmarkTimeoutId = 0;
this._monitor.connect('changed', Lang.bind(this, function () {
if (this._bookmarkTimeoutId > 0)
return;
/* Defensive event compression */
this._bookmarkTimeoutId = Mainloop.timeout_add(100, Lang.bind(this, function () {
this._bookmarkTimeoutId = 0;
this._reloadBookmarks();
return false;
}));
}));
this._reloadBookmarks();
},
_updateDevices: function() {
this._mounts = [];
/* first go through all connected drives */
let drives = this._volumeMonitor.get_connected_drives();
for (let i = 0; i < drives.length; i++) {
let volumes = drives[i].get_volumes();
for(let j = 0; j < volumes.length; j++) {
let mount = volumes[j].get_mount();
if(mount != null) {
this._addMount(mount);
}
}
}
/* add all volumes that is not associated with a drive */
let volumes = this._volumeMonitor.get_volumes();
for(let i = 0; i < volumes.length; i++) {
if(volumes[i].get_drive() != null)
continue;
let mount = volumes[i].get_mount();
if(mount != null) {
this._addMount(mount);
}
}
/* add mounts that have no volume (/etc/mtab mounts, ftp, sftp,...) */
let mounts = this._volumeMonitor.get_mounts();
for(let i = 0; i < mounts.length; i++) {
if(mounts[i].is_shadowed())
continue;
if(mounts[i].get_volume())
continue;
this._addMount(mounts[i]);
}
/* We emit two signals, one for a generic 'all places' update
* and the other for one specific to mounts. We do this because
* clients like PlaceDisplay may only care about places in general
* being updated while clients like DashPlaceDisplay care which
* specific type of place got updated.
*/
this.emit('mounts-updated');
this.emit('places-updated');
},
_reloadBookmarks: function() {
this._bookmarks = [];
if (!GLib.file_test(this._bookmarksPath, GLib.FileTest.EXISTS))
return;
let bookmarksContent = Shell.get_file_contents_utf8_sync(this._bookmarksPath);
let bookmarks = bookmarksContent.split('\n');
let bookmarksToLabel = {};
let bookmarksOrder = [];
for (let i = 0; i < bookmarks.length; i++) {
let bookmarkLine = bookmarks[i];
let components = bookmarkLine.split(' ');
let bookmark = components[0];
if (bookmark in bookmarksToLabel)
continue;
let label = null;
if (components.length > 1)
label = components.slice(1).join(' ');
bookmarksToLabel[bookmark] = label;
bookmarksOrder.push(bookmark);
}
for (let i = 0; i < bookmarksOrder.length; i++) {
let bookmark = bookmarksOrder[i];
let label = bookmarksToLabel[bookmark];
let file = Gio.file_new_for_uri(bookmark);
if (!file.query_exists(null))
continue;
if (label == null)
label = Shell.util_get_label_for_uri(bookmark);
if (label == null)
continue;
let icon = Shell.util_get_icon_for_uri(bookmark);
let item = new PlaceInfo('bookmark:' + bookmark, label,
function(size) {
return St.TextureCache.get_default().load_gicon(null, icon, size);
},
function(params) {
Gio.app_info_launch_default_for_uri(bookmark, _makeLaunchContext(params));
});
this._bookmarks.push(item);
}
/* See comment in _updateDevices for explanation why there are two signals. */
this.emit('bookmarks-updated');
this.emit('places-updated');
},
_addMount: function(mount) {
let devItem = new PlaceDeviceInfo(mount);
this._mounts.push(devItem);
},
getAllPlaces: function () {
return this.getDefaultPlaces().concat(this.getBookmarks(), this.getMounts());
},
getDefaultPlaces: function () {
return this._defaultPlaces;
},
getBookmarks: function () {
return this._bookmarks;
},
getMounts: function () {
return this._mounts;
},
_lookupIndexById: function(sourceArray, id) {
for (let i = 0; i < sourceArray.length; i++) {
let place = sourceArray[i];
if (place.id == id)
return i;
}
return -1;
},
lookupPlaceById: function(id) {
let colonIdx = id.indexOf(':');
let type = id.substring(0, colonIdx);
let sourceArray = null;
if (type == 'special')
sourceArray = this._defaultPlaces;
else if (type == 'mount')
sourceArray = this._mounts;
else if (type == 'bookmark')
sourceArray = this._bookmarks;
return sourceArray[this._lookupIndexById(sourceArray, id)];
},
_removeById: function(sourceArray, id) {
sourceArray.splice(this._lookupIndexById(sourceArray, id), 1);
}
});
Signals.addSignalMethods(PlacesManager.prototype);
const PlaceSearchProvider = new Lang.Class({
Name: 'PlaceSearchProvider',
Extends: Search.SearchProvider,
_init: function() {
this.parent(_("PLACES & DEVICES"));
this.placesManager = new PlacesManager();
},
getResultMetas: function(resultIds, callback) {
let metas = [];
for (let i = 0; i < resultIds.length; i++) {
let placeInfo = this.placesManager.lookupPlaceById(resultIds[i]);
if (!placeInfo)
metas.push(null);
else
metas.push({ 'id': resultIds[i],
'name': placeInfo.name,
'createIcon': function(size) {
return placeInfo.iconFactory(size);
}
});
}
callback(metas);
},
activateResult: function(id, params) {
let placeInfo = this.placesManager.lookupPlaceById(id);
placeInfo.launch(params);
},
_compareResultMeta: function (idA, idB) {
let infoA = this.placesManager.lookupPlaceById(idA);
let infoB = this.placesManager.lookupPlaceById(idB);
return infoA.name.localeCompare(infoB.name);
},
_searchPlaces: function(places, terms) {
let prefixResults = [];
let substringResults = [];
terms = terms.map(String.toLowerCase);
for (let i = 0; i < places.length; i++) {
let place = places[i];
let mtype = place.matchTerms(terms);
if (mtype == Search.MatchType.PREFIX)
prefixResults.push(place.id);
else if (mtype == Search.MatchType.SUBSTRING)
substringResults.push(place.id);
}
prefixResults.sort(Lang.bind(this, this._compareResultMeta));
substringResults.sort(Lang.bind(this, this._compareResultMeta));
this.searchSystem.pushResults(this, prefixResults.concat(substringResults));
},
getInitialResultSet: function(terms) {
let places = this.placesManager.getAllPlaces();
this._searchPlaces(places, terms);
},
getSubsearchResultSet: function(previousResults, terms) {
let places = previousResults.map(Lang.bind(this, function(id) {
return this.placesManager.lookupPlaceById(id);
}));
this._searchPlaces(places, terms);
}
});

View File

@ -61,6 +61,9 @@ const PopupBaseMenuItem = new Lang.Class({
this.setSensitive(this.sensitive);
if (!this._activatable)
this.actor.add_style_class_name('popup-inactive-menu-item');
if (params.style_class)
this.actor.add_style_class_name(params.style_class);
@ -763,7 +766,7 @@ const PopupSwitchMenuItem = new Lang.Class({
{ expand: true, span: -1, align: St.Align.END });
this._statusLabel = new St.Label({ text: '',
style_class: 'popup-inactive-menu-item'
style_class: 'popup-status-menu-item'
});
this._statusBin.child = this._switch.actor;
},
@ -870,6 +873,12 @@ const PopupMenuBase = new Lang.Class({
this._activeMenuItem = null;
this._childMenus = [];
this._settingsActions = { };
this._sessionUpdatedId = Main.sessionMode.connect('updated', Lang.bind(this, this._sessionUpdated));
},
_sessionUpdated: function() {
this._setSettingsVisibility(Main.sessionMode.allowSettings);
},
addAction: function(title, callback) {
@ -883,9 +892,6 @@ const PopupMenuBase = new Lang.Class({
},
addSettingsAction: function(title, desktopFile) {
if (!Main.sessionMode.allowSettings)
return null;
let menuItem = this.addAction(title, function() {
let app = Shell.AppSystem.get_default().lookup_setting(desktopFile);
@ -898,12 +904,13 @@ const PopupMenuBase = new Lang.Class({
app.activate();
});
menuItem.actor.visible = Main.sessionMode.allowSettings;
this._settingsActions[desktopFile] = menuItem;
return menuItem;
},
setSettingsVisibility: function(visible) {
_setSettingsVisibility: function(visible) {
for (let id in this._settingsActions) {
let item = this._settingsActions[id];
item.actor.visible = visible;
@ -1097,7 +1104,8 @@ const PopupMenuBase = new Lang.Class({
let columnWidths = [];
let items = this.box.get_children();
for (let i = 0; i < items.length; i++) {
if (!items[i].visible)
if (!items[i].visible &&
!(items[i]._delegate instanceof PopupSubMenu && items[i-1].visible))
continue;
if (items[i]._delegate instanceof PopupBaseMenuItem || items[i]._delegate instanceof PopupMenuBase) {
let itemColumnWidths = items[i]._delegate.getColumnWidths();
@ -1172,6 +1180,9 @@ const PopupMenuBase = new Lang.Class({
this.actor.destroy();
this.emit('destroy');
Main.sessionMode.disconnect(this._sessionUpdatedId);
this._sessionUpdatedId = 0;
}
});
Signals.addSignalMethods(PopupMenuBase.prototype);
@ -1337,6 +1348,11 @@ const PopupSubMenu = new Lang.Class({
this.actor.vscrollbar_policy =
needsScrollbar ? Gtk.PolicyType.AUTOMATIC : Gtk.PolicyType.NEVER;
if (needsScrollbar)
this.actor.add_style_pseudo_class('scrolled');
else
this.actor.remove_style_pseudo_class('scrolled');
// It looks funny if we animate with a scrollbar (at what point is
// the scrollbar added?) so just skip that case
if (animate && needsScrollbar)
@ -2041,6 +2057,9 @@ const PopupMenuManager = new Lang.Class({
},
addMenu: function(menu, position) {
if (this._findMenu(menu) > -1)
return;
let menudata = {
menu: menu,
openStateChangeId: menu.connect('open-state-changed', Lang.bind(this, this._onMenuOpenState)),

View File

@ -17,7 +17,9 @@ const Layout = imports.ui.layout;
const LoginManager = imports.misc.loginManager;
const Lightbox = imports.ui.lightbox;
const Main = imports.ui.main;
const Overview = imports.ui.overview;
const MessageTray = imports.ui.messageTray;
const ShellDBus = imports.ui.shellDBus;
const Tweener = imports.ui.tweener;
const SCREENSAVER_SCHEMA = 'org.gnome.desktop.screensaver';
@ -26,7 +28,7 @@ const LOCK_ENABLED_KEY = 'lock-enabled';
const CURTAIN_SLIDE_TIME = 0.5;
// fraction of screen height the arrow must reach before completing
// the slide up automatically
const ARROW_DRAG_TRESHOLD = 0.1;
const ARROW_DRAG_THRESHOLD = 0.1;
// Parameters for the arrow animation
const N_ARROWS = 3;
@ -365,7 +367,8 @@ const ScreenShield = new Lang.Class({
name: 'lockScreenContents' });
this._lockScreenContents.add_constraint(new Layout.MonitorConstraint({ primary: true }));
this._background = Meta.BackgroundActor.new_for_screen(global.screen);
this._background = new St.Bin({ style_class: 'screen-shield-background',
child: Meta.BackgroundActor.new_for_screen(global.screen) });
this._lockScreenGroup.add_actor(this._background);
this._lockScreenGroup.add_actor(this._lockScreenContents);
@ -395,6 +398,7 @@ const ScreenShield = new Lang.Class({
this._lockDialogGroup = new St.Widget({ x_expand: true,
y_expand: true,
pivot_point: new Clutter.Point({ x: 0.5, y: 0.5 }),
name: 'lockDialogGroup' });
this.actor.add_actor(this._lockDialogGroup);
@ -412,6 +416,8 @@ const ScreenShield = new Lang.Class({
this._onStatusChanged(status);
}));
this._screenSaverDBus = new ShellDBus.ScreenSaverDBus(this);
this._loginManager = LoginManager.getLoginManager();
this._loginSession = this._loginManager.getCurrentSessionProxy();
this._loginSession.connectSignal('Lock', Lang.bind(this, function() { this.lock(false); }));
@ -420,8 +426,10 @@ const ScreenShield = new Lang.Class({
this._settings = new Gio.Settings({ schema: SCREENSAVER_SCHEMA });
this._isModal = false;
this._isLocked = false;
this._hasLockScreen = false;
this._isGreeter = false;
this._isActive = false;
this._inUnlockAnimation = false;
this._lightbox = new Lightbox.Lightbox(Main.uiGroup,
{ inhibitEvents: true,
@ -430,7 +438,11 @@ const ScreenShield = new Lang.Class({
},
_onLockScreenKeyRelease: function(actor, event) {
if (event.get_key_symbol() == Clutter.KEY_Escape) {
let symbol = event.get_key_symbol();
if (symbol == Clutter.KEY_Escape ||
symbol == Clutter.KEY_Return ||
symbol == Clutter.KEY_KP_Enter) {
this._ensureUnlockDialog();
this._hideLockScreen(true);
return true;
@ -459,7 +471,7 @@ const ScreenShield = new Lang.Class({
// 7 standard scrolls to lift up
if (this._lockScreenScrollCounter > 35) {
this._ensureUnlockDialog();
this._hideLockScreen(0);
this._hideLockScreen(true);
}
return true;
@ -494,7 +506,7 @@ const ScreenShield = new Lang.Class({
},
_onDragEnd: function(action, actor, eventX, eventY, modifiers) {
if (this._lockScreenGroup.y < -(ARROW_DRAG_TRESHOLD * global.stage.height)) {
if (this._lockScreenGroup.y < -(ARROW_DRAG_THRESHOLD * global.stage.height)) {
// Complete motion automatically
this._hideLockScreen(true);
} else {
@ -517,7 +529,7 @@ const ScreenShield = new Lang.Class({
// If we have a unlock dialog, cancel it
if (this._dialog) {
this._dialog.cancel();
if (!this._keepDialog) {
if (!this._isGreeter) {
this._dialog = null;
}
}
@ -528,7 +540,7 @@ const ScreenShield = new Lang.Class({
if (status == GnomeSession.PresenceStatus.IDLE) {
if (this._dialog) {
this._dialog.cancel();
if (!this._keepDialog) {
if (!this._isGreeter) {
this._dialog = null;
}
}
@ -538,14 +550,14 @@ const ScreenShield = new Lang.Class({
this._isModal = true;
}
if (!this._isLocked)
if (!this._isActive)
this._lightbox.show();
} else {
let lightboxWasShown = this._lightbox.shown;
this._lightbox.hide();
let shouldLock = lightboxWasShown && this._settings.get_boolean(LOCK_ENABLED_KEY);
if (shouldLock || this._isLocked) {
if (shouldLock || this._isActive) {
this.lock(false);
} else if (this._isModal) {
this.unlock();
@ -554,7 +566,19 @@ const ScreenShield = new Lang.Class({
},
showDialog: function() {
this.lock(true);
// Ensure that the stage window is mapped, before taking a grab
// otherwise X errors out
Meta.later_add(Meta.LaterType.BEFORE_REDRAW, Lang.bind(this, function() {
if (!this._isModal) {
Main.pushModal(this.actor);
this._isModal = true;
}
return false;
}));
this.actor.show();
this._isGreeter = Main.sessionMode.isGreeter;
this._ensureUnlockDialog();
this._hideLockScreen(false);
},
@ -588,23 +612,24 @@ const ScreenShield = new Lang.Class({
time: time,
transition: 'linear',
onComplete: function() {
this._lockScreenHidden();
this._lockScreenState = MessageTray.State.HIDDEN;
this._lockScreenGroup.hide();
},
onCompleteScope: this,
});
} else {
this._lockScreenHidden();
this._lockScreenState = MessageTray.State.HIDDEN;
this._lockScreenGroup.hide();
}
},
_lockScreenHidden: function() {
this._lockScreenState = MessageTray.State.HIDDEN;
this._lockScreenGroup.hide();
if (Main.sessionMode.currentMode == 'lock-screen')
Main.sessionMode.popMode('lock-screen');
},
_ensureUnlockDialog: function() {
if (!this._dialog) {
[this._dialog, this._keepDialog] = Main.sessionMode.createUnlockDialog(this._lockDialogGroup);
let constructor = Main.sessionMode.unlockDialog;
this._dialog = new constructor(this._lockDialogGroup);
if (!this._dialog) {
// This session mode has no locking capabilities
this.unlock();
@ -621,33 +646,25 @@ const ScreenShield = new Lang.Class({
this._dialog.connect('failed', Lang.bind(this, this._onUnlockFailed));
this._dialog.connect('unlocked', Lang.bind(this, this._onUnlockSucceded));
}
if (this._keepDialog) {
// Notify the other components that even though we are showing the
// screenshield, we're not in a locked state
// (this happens for the gdm greeter)
this._isLocked = false;
this.emit('lock-status-changed', false);
}
},
_onUnlockFailed: function() {
this._dialog.destroy();
this._dialog = null;
this._resetLockScreen(false);
this._resetLockScreen(true, false);
},
_onUnlockSucceded: function() {
this.unlock();
this._tweenUnlocked();
},
_resetLockScreen: function(animate) {
_resetLockScreen: function(animateLockScreen, animateLockDialog) {
this._ensureLockScreen();
this._lockDialogGroup.scale_x = 1;
this._lockDialogGroup.scale_y = 1;
this._lockScreenGroup.show();
this._lockScreenState = MessageTray.State.SHOWING;
if (animate) {
if (animateLockScreen) {
this._lockScreenGroup.y = -global.screen_height;
Tweener.removeTweens(this._lockScreenGroup);
Tweener.addTween(this._lockScreenGroup,
@ -659,7 +676,12 @@ const ScreenShield = new Lang.Class({
},
onCompleteScope: this
});
} else {
this._lockScreenGroup.fixed_position_set = false;
this._lockScreenShown();
}
if (animateLockDialog) {
this._lockDialogGroup.opacity = 0;
Tweener.removeTweens(this._lockDialogGroup);
Tweener.addTween(this._lockDialogGroup,
@ -668,13 +690,20 @@ const ScreenShield = new Lang.Class({
transition: 'easeOutQuad' });
} else {
this._lockDialogGroup.opacity = 255;
this._lockScreenShown();
}
this._lockScreenGroup.grab_key_focus();
if (Main.sessionMode.currentMode != 'lock-screen')
Main.sessionMode.pushMode('lock-screen');
},
_lockScreenShown: function() {
if (this._dialog && !this._isGreeter) {
this._dialog.destroy();
this._dialog = null;
}
if (this._arrowAnimationId)
Mainloop.source_remove(this._arrowAnimationId);
this._arrowAnimationId = Mainloop.timeout_add(6000, Lang.bind(this, this._animateArrows));
@ -689,7 +718,10 @@ const ScreenShield = new Lang.Class({
// Some of the actors in the lock screen are heavy in
// resources, so we only create them when needed
_prepareLockScreen: function() {
_ensureLockScreen: function() {
if (this._hasLockScreen)
return;
this._lockScreenContentsBox = new St.BoxLayout({ x_align: Clutter.ActorAlign.CENTER,
y_align: Clutter.ActorAlign.CENTER,
x_expand: true,
@ -731,22 +763,34 @@ const ScreenShield = new Lang.Class({
},
get locked() {
return this._isLocked;
return this._isActive;
},
_tweenUnlocked: function() {
this._inUnlockAnimation = true;
this.unlock();
Tweener.addTween(this._lockDialogGroup, {
scale_x: 0,
scale_y: 0,
time: Overview.ANIMATION_TIME,
transition: 'easeOutQuad',
onComplete: function() {
if (this._dialog) {
this._dialog.destroy();
this._dialog = null;
}
this.actor.hide();
this._inUnlockAnimation = false;
},
onCompleteScope: this
});
},
unlock: function() {
if (this._hasLockScreen)
this._clearLockScreen();
if (this._keepDialog) {
// The dialog must be kept alive,
// so immediately go back to it
// This will also reset _isLocked
this._ensureUnlockDialog();
return;
}
if (this._dialog) {
if (this._dialog && !this._isGreeter) {
this._dialog.destroy();
this._dialog = null;
}
@ -758,26 +802,94 @@ const ScreenShield = new Lang.Class({
this._isModal = false;
}
this._isLocked = false;
this.actor.hide();
if (!this._inUnlockAnimation)
this.actor.hide();
this.emit('lock-status-changed', false);
if (Main.sessionMode.currentMode == 'lock-screen')
Main.sessionMode.popMode('lock-screen');
if (Main.sessionMode.currentMode == 'unlock-dialog')
Main.sessionMode.popMode('unlock-dialog');
this._isActive = false;
this.emit('lock-status-changed');
},
lock: function(animate) {
if (!this._hasLockScreen)
this._prepareLockScreen();
if (!this._isModal) {
Main.pushModal(this.actor);
this._isModal = true;
}
this._isLocked = true;
this.actor.show();
this._resetLockScreen(animate);
this.emit('lock-status-changed', true);
if (Main.sessionMode.currentMode != 'unlock-dialog' &&
Main.sessionMode.currentMode != 'lock-screen') {
this._isGreeter = Main.sessionMode.isGreeter;
if (!this._isGreeter)
Main.sessionMode.pushMode('unlock-dialog');
}
this._resetLockScreen(animate, animate);
this._isActive = true;
this.emit('lock-status-changed');
},
});
Signals.addSignalMethods(ScreenShield.prototype);
/* Fallback code to handle session locking using gnome-screensaver,
in case the required GDM dependency is not there
*/
const ScreenShieldFallback = new Lang.Class({
Name: 'ScreenShieldFallback',
_init: function() {
this._proxy = new Gio.DBusProxy({ g_connection: Gio.DBus.session,
g_name: 'org.gnome.ScreenSaver',
g_object_path: '/org/gnome/ScreenSaver',
g_interface_name: 'org.gnome.ScreenSaver',
g_flags: (Gio.DBusProxyFlags.DO_NOT_AUTO_START |
Gio.DBusProxyFlags.DO_NOT_LOAD_PROPERTIES),
});
this._proxy.init(null);
this._proxy.connect('g-signal', Lang.bind(this, this._onSignal));
this._proxy.connect('notify::g-name-owner', Lang.bind(this, this._onNameOwnerChanged));
},
_onNameOwnerChanged: function(object, pspec) {
if (this._proxy.g_name_owner)
[this._locked] = this._proxy.call_sync('GetActive', null,
Gio.DBusCallFlags.NONE, -1, null).deep_unpack();
else
this._locked = false;
this.emit('lock-status-changed', this._locked);
},
_onSignal: function(proxy, senderName, signalName, params) {
if (signalName == 'ActiveChanged') {
[this._locked] = params.deep_unpack();
this.emit('lock-status-changed', this._locked);
}
},
get locked() {
return this._locked;
},
lock: function() {
this._proxy.call('Lock', null, Gio.DBusCallFlags.NONE, -1, null,
Lang.bind(this, function(proxy, result) {
proxy.call_finish(result);
this.emit('lock-screen-shown');
}));
},
unlock: function() {
this._proxy.call('SetActive', GLib.Variant.new('(b)', false),
Gio.DBusCallFlags.NONE, -1, null, null);
},
});
Signals.addSignalMethods(ScreenShieldFallback.prototype);

View File

@ -214,8 +214,6 @@ const SearchResults = new Lang.Class({
for (let i = 0; i < this._providers.length; i++) {
this.createProviderMeta(this._providers[i]);
}
this._searchProvidersBox = new St.BoxLayout({ style_class: 'search-providers-box' });
this.actor.add(this._searchProvidersBox);
this._highlightDefault = false;
this._defaultResult = null;
@ -226,7 +224,7 @@ const SearchResults = new Lang.Class({
vertical: true });
let title = new St.Label({ style_class: 'search-section-header',
text: provider.title });
providerBox.add(title);
providerBox.add(title, { x_fill: false, x_align: St.Align.START });
let resultDisplayBin = new St.Bin({ style_class: 'search-section-results',
x_fill: true,
@ -302,9 +300,6 @@ const SearchResults = new Lang.Class({
}
}
if (!newDefaultResult)
newDefaultResult = this._searchProvidersBox.get_first_child();
if (newDefaultResult != this._defaultResult) {
if (this._defaultResult)
this._defaultResult.setSelected(false);

View File

@ -1,94 +1,160 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
const Lang = imports.lang;
const Signals = imports.signals;
const Main = imports.ui.main;
const Params = imports.misc.params;
const DEFAULT_MODE = 'user';
const DEFAULT_MODE = 'restrictive';
const _modes = {
'gdm': { hasOverview: false,
showCalendarEvents: false,
allowSettings: false,
allowExtensions: false,
allowKeybindingsWhenModal: true,
hasRunDialog: false,
hasWorkspaces: false,
createSession: Main.createGDMSession,
createUnlockDialog: Main.createGDMLoginDialog,
panel: {
left: [],
center: ['dateMenu'],
right: ['a11y', 'display', 'keyboard',
'volume', 'battery', 'lockScreen', 'powerMenu']
}
},
'restrictive': {
hasOverview: false,
showCalendarEvents: false,
allowSettings: false,
allowExtensions: false,
allowKeybindingsWhenModal: false,
hasRunDialog: false,
hasWorkspaces: false,
hasWindows: false,
hasNotifications: false,
isLocked: false,
isGreeter: false,
isPrimary: false,
unlockDialog: null,
components: [],
panel: {
left: [],
center: [],
right: []
},
},
'initial-setup': { hasOverview: false,
showCalendarEvents: false,
allowSettings: false,
allowExtensions: false,
allowKeybindingsWhenModal: false,
hasRunDialog: false,
hasWorkspaces: false,
createSession: Main.createInitialSetupSession,
panel: {
left: [],
center: ['dateMenu'],
right: ['a11y', 'keyboard', 'volume', 'lockScreen']
}
},
'gdm': {
allowKeybindingsWhenModal: true,
hasNotifications: true,
isGreeter: true,
isPrimary: true,
unlockDialog: imports.gdm.loginDialog.LoginDialog,
components: ['polkitAgent'],
panel: {
left: [],
center: ['dateMenu'],
right: ['a11y', 'display', 'keyboard',
'volume', 'battery', 'powerMenu']
}
},
'user': { hasOverview: true,
showCalendarEvents: true,
allowSettings: true,
allowExtensions: true,
allowKeybindingsWhenModal: false,
hasRunDialog: true,
hasWorkspaces: true,
createSession: Main.createUserSession,
createUnlockDialog: Main.createSessionUnlockDialog,
panel: {
left: ['activities', 'appMenu'],
center: ['dateMenu'],
right: ['a11y', 'keyboard', 'volume', 'bluetooth',
'network', 'battery', 'lockScreen', 'userMenu']
}
}
'lock-screen': {
isLocked: true,
isGreeter: undefined,
unlockDialog: undefined,
components: ['polkitAgent', 'telepathyClient'],
panel: {
left: ['userMenu'],
center: [],
right: ['lockScreen']
},
},
'unlock-dialog': {
isLocked: true,
unlockDialog: undefined,
components: ['polkitAgent', 'telepathyClient'],
panel: {
left: ['userMenu'],
center: [],
right: ['a11y', 'keyboard', 'lockScreen']
},
},
'initial-setup': {
isPrimary: true,
components: ['keyring'],
panel: {
left: [],
center: ['dateMenu'],
right: ['a11y', 'keyboard', 'volume']
}
},
'user': {
hasOverview: true,
showCalendarEvents: true,
allowSettings: true,
allowExtensions: true,
hasRunDialog: true,
hasWorkspaces: true,
hasWindows: true,
hasNotifications: true,
isLocked: false,
isPrimary: true,
unlockDialog: imports.ui.unlockDialog.UnlockDialog,
components: ['networkAgent', 'polkitAgent', 'telepathyClient',
'keyring', 'recorder', 'autorunManager', 'automountManager'],
panel: {
left: ['activities', 'appMenu'],
center: ['dateMenu'],
right: ['a11y', 'keyboard', 'volume', 'bluetooth',
'network', 'battery', 'userMenu']
}
}
};
function listModes() {
let modes = Object.getOwnPropertyNames(_modes);
for (let i = 0; i < modes.length; i++)
print(modes[i]);
if (_modes[modes[i]].isPrimary)
print(modes[i]);
}
const SessionMode = new Lang.Class({
Name: 'SessionMode',
_init: function() {
let params = _modes[global.session_mode];
global.connect('notify::session-mode', Lang.bind(this, this._sync));
let mode = _modes[global.session_mode].isPrimary ? global.session_mode
: 'user';
this._modeStack = [mode];
this._sync();
},
pushMode: function(mode) {
this._modeStack.push(mode);
this._sync();
},
popMode: function(mode) {
if (this.currentMode != mode || this._modeStack.length === 1)
throw new Error("Invalid SessionMode.popMode");
this._modeStack.pop();
this._sync();
},
switchMode: function(to) {
if (this.currentMode == to)
return;
this._modeStack[this._modeStack.length - 1] = to;
this._sync();
},
get currentMode() {
return this._modeStack[this._modeStack.length - 1];
},
_sync: function() {
let params = _modes[this.currentMode];
params = Params.parse(params, _modes[DEFAULT_MODE]);
this._createSession = params.createSession;
delete params.createSession;
this._createUnlockDialog = params.createUnlockDialog;
delete params.createUnlockDialog;
// A simplified version of Lang.copyProperties, handles
// undefined as a special case for "no change / inherit from previous mode"
for (let prop in params) {
if (params[prop] !== undefined)
this[prop] = params[prop];
}
Lang.copyProperties(params, this);
},
createSession: function() {
if (this._createSession)
this._createSession();
},
createUnlockDialog: function() {
if (this._createUnlockDialog)
return this._createUnlockDialog.apply(this, arguments);
else
return null;
},
this.emit('updated');
}
});
Signals.addSignalMethods(SessionMode.prototype);

View File

@ -340,29 +340,38 @@ const GnomeShellExtensions = new Lang.Class({
const ScreenSaverDBus = new Lang.Class({
Name: 'ScreenSaverDBus',
_init: function() {
_init: function(screenShield) {
this.parent();
Main.screenShield.connect('lock-status-changed', Lang.bind(this, function(shield, locked) {
this._dbusImpl.emit_signal('ActiveChanged', GLib.Variant.new('(b)', [locked]));
this._screenShield = screenShield;
screenShield.connect('lock-status-changed', Lang.bind(this, function(shield) {
this._dbusImpl.emit_signal('ActiveChanged', GLib.Variant.new('(b)', [shield.locked]));
}));
this._dbusImpl = Gio.DBusExportedObject.wrapJSObject(ScreenSaverIface, this);
this._dbusImpl.export(Gio.DBus.session, '/org/gnome/ScreenSaver');
Gio.DBus.session.own_name('org.gnome.ScreenSaver', Gio.BusNameOwnerFlags.REPLACE, null, null);
},
Lock: function() {
Main.screenShield.lock(true);
LockAsync: function(parameters, invocation) {
let tmpId = this._screenShield.connect('lock-screen-shown', Lang.bind(this, function() {
this._screenShield.disconnect(tmpId);
invocation.return_value(null);
}));
this._screenShield.lock(true);
},
SetActive: function(active) {
if (active)
Main.screenShield.lock(true);
this._screenShield.lock(true);
else
Main.screenShield.unlock();
this._screenShield.unlock();
},
GetActive: function() {
return Main.screenShield.locked;
return this._screenShield.locked;
}
});

View File

@ -76,6 +76,12 @@ const EntryMenu = new Lang.Class({
this.actor.grab_key_focus();
this.parent();
this._entry.add_style_pseudo_class('focus');
},
close: function() {
this._entry.grab_key_focus();
this.parent();
},
_updateCopyItem: function() {
@ -126,34 +132,20 @@ function _setMenuAlignment(entry, stageX) {
entry.menu.setSourceAlignment(entryX / entry.width);
};
function _onClicked(action, actor) {
let entry = actor.menu ? actor : actor.get_parent();
function _onButtonPressEvent(actor, event, entry) {
if (entry.menu.isOpen) {
entry.menu.close();
} else if (action.get_button() == 3) {
let [stageX, stageY] = action.get_coords();
_setMenuAlignment(entry, stageX);
entry.menu.open();
}
};
function _onLongPress(action, actor, state) {
let entry = actor.menu ? actor : actor.get_parent();
if (state == Clutter.LongPressState.QUERY)
return action.get_button() == 1 && !entry.menu.isOpen;
if (state == Clutter.LongPressState.ACTIVATE) {
let [stageX, stageY] = action.get_coords();
return true;
} else if (event.get_button() == 3) {
let [stageX, stageY] = event.get_coords();
_setMenuAlignment(entry, stageX);
entry.menu.open();
return true;
}
return false;
};
function _onPopup(actor) {
let entry = actor.menu ? actor : actor.get_parent();
function _onPopup(actor, entry) {
let [success, textX, textY, lineHeight] = entry.clutter_text.position_to_coords(-1);
if (success)
entry.menu.setSourceAlignment(textX / entry.width);
@ -168,20 +160,11 @@ function addContextMenu(entry, params) {
entry._menuManager = new PopupMenu.PopupMenuManager({ actor: entry });
entry._menuManager.addMenu(entry.menu);
let clickAction;
// Add a click action to both the entry and its clutter_text; the former
// Add an event handler to both the entry and its clutter_text; the former
// so padding is included in the clickable area, the latter because the
// event processing of ClutterText prevents event-bubbling.
clickAction = new Clutter.ClickAction();
clickAction.connect('clicked', _onClicked);
clickAction.connect('long-press', _onLongPress);
entry.clutter_text.add_action(clickAction);
entry.clutter_text.connect('button-press-event', Lang.bind(null, _onButtonPressEvent, entry));
entry.connect('button-press-event', Lang.bind(null, _onButtonPressEvent, entry));
clickAction = new Clutter.ClickAction();
clickAction.connect('clicked', _onClicked);
clickAction.connect('long-press', _onLongPress);
entry.add_action(clickAction);
entry.connect('popup-menu', _onPopup);
entry.connect('popup-menu', Lang.bind(null, _onPopup, entry));
}

View File

@ -75,10 +75,6 @@ const ATIndicator = new Lang.Class({
this.menu.addSettingsAction(_("Universal Access Settings"), 'gnome-universal-access-panel.desktop');
},
setLockedState: function(locked) {
this.actor.visible = !locked;
},
_buildItemExtended: function(string, initial_value, writable, on_set) {
let widget = new PopupMenu.PopupSwitchMenuItem(string, initial_value);
if (!writable)

View File

@ -88,11 +88,6 @@ const Indicator = new Lang.Class({
this._applet.connect('cancel-request', Lang.bind(this, this._cancelRequest));
},
setLockedState: function(locked) {
this._isLocked = locked;
this._updateKillswitch();
},
_updateKillswitch: function() {
let current_state = this._applet.killswitch_state;
let on = current_state == GnomeBluetooth.KillswitchState.UNBLOCKED;
@ -107,7 +102,7 @@ const Indicator = new Lang.Class({
/* TRANSLATORS: this means that bluetooth was disabled by hardware rfkill */
this._killswitch.setStatus(_("hardware disabled"));
this.actor.visible = !this._isLocked && has_adapter;
this.actor.visible = has_adapter;
if (on) {
this._discoverable.actor.show();
@ -461,7 +456,10 @@ const PinNotification = new Lang.Class({
_canActivateOkButton: function() {
// PINs have a fixed length of 6
return this._entry.clutter_text.text.length == 6;
if (this._numeric)
return this._entry.clutter_text.text.length == 6;
else
return true;
},
grabFocus: function(lockTray) {

View File

@ -5,6 +5,7 @@ const GLib = imports.gi.GLib;
const GnomeDesktop = imports.gi.GnomeDesktop;
const Lang = imports.lang;
const Shell = imports.gi.Shell;
const Signals = imports.signals;
const St = imports.gi.St;
try {
@ -45,6 +46,7 @@ const IBusManager = new Lang.Class({
this._panelService = null;
this._engines = {};
this._ready = false;
this._registerPropertiesId = 0;
this._nameWatcherId = Gio.DBus.session.watch_name(IBus.SERVICE_IBUS,
Gio.BusNameWatcherFlags.NONE,
@ -63,6 +65,7 @@ const IBusManager = new Lang.Class({
this._candidatePopup.setPanelService(null);
this._engines = {};
this._ready = false;
this._registerPropertiesId = 0;
},
_onNameAppeared: function() {
@ -100,6 +103,11 @@ const IBusManager = new Lang.Class({
this._panelService = new IBus.PanelService({ connection: this._ibus.get_connection(),
object_path: IBus.PATH_PANEL });
this._candidatePopup.setPanelService(this._panelService);
// Need to set this to get 'global-engine-changed' emitions
this._ibus.set_watch_ibus_signal(true);
this._ibus.connect('global-engine-changed', Lang.bind(this, this._resetProperties));
this._panelService.connect('update-property', Lang.bind(this, this._updateProperty));
this._resetProperties();
} else {
this._clear();
return;
@ -116,6 +124,39 @@ const IBusManager = new Lang.Class({
this._readyCallback();
},
_resetProperties: function() {
this.emit('properties-registered', null);
if (this._registerPropertiesId != 0)
return;
this._registerPropertiesId =
this._panelService.connect('register-properties', Lang.bind(this, function(p, props) {
if (!props.get(0))
return;
this._panelService.disconnect(this._registerPropertiesId);
this._registerPropertiesId = 0;
this.emit('properties-registered', props);
}));
},
_updateProperty: function(panel, prop) {
this.emit('property-updated', prop);
},
activateProperty: function(key, state) {
this._panelService.property_activate(key, state);
},
hasProperties: function(id) {
if (id == 'anthy')
return true;
return false;
},
getEngineDesc: function(id) {
if (!IBus || !this._ready)
return null;
@ -123,6 +164,7 @@ const IBusManager = new Lang.Class({
return this._engines[id];
}
});
Signals.addSignalMethods(IBusManager.prototype);
const LayoutMenuItem = new Lang.Class({
Name: 'LayoutMenuItem',
@ -135,6 +177,7 @@ const LayoutMenuItem = new Lang.Class({
this.indicator = new St.Label({ text: shortName });
this.addActor(this.label);
this.addActor(this.indicator);
this.actor.label_actor = this.label;
}
});
@ -142,6 +185,12 @@ const InputSourceIndicator = new Lang.Class({
Name: 'InputSourceIndicator',
Extends: PanelMenu.Button,
_propertiesWhitelist: [
'InputMode',
'TypingMode',
'DictMode'
],
_init: function() {
this.parent(0.0, _("Keyboard"));
@ -162,56 +211,73 @@ const InputSourceIndicator = new Lang.Class({
this._currentSourceIndex = this._settings.get_uint(KEY_CURRENT_INPUT_SOURCE);
this._xkbInfo = new GnomeDesktop.XkbInfo();
this._ibusManager = new IBusManager(Lang.bind(this, this._inputSourcesChanged));
this._propSeparator = new PopupMenu.PopupSeparatorMenuItem();
this.menu.addMenuItem(this._propSeparator);
this._propSection = new PopupMenu.PopupMenuSection();
this.menu.addMenuItem(this._propSection);
this._propSection.actor.hide();
this._properties = null;
this._ibusManager = new IBusManager(Lang.bind(this, this._inputSourcesChanged));
this._ibusManager.connect('properties-registered', Lang.bind(this, this._ibusPropertiesRegistered));
this._ibusManager.connect('property-updated', Lang.bind(this, this._ibusPropertyUpdated));
this._inputSourcesChanged();
this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
this._showLayoutItem = this.menu.addAction(_("Show Keyboard Layout"), Lang.bind(this, this._showLayout));
Main.sessionMode.connect('updated', Lang.bind(this, this._sessionUpdated));
this._sessionUpdated();
this.menu.addSettingsAction(_("Region and Language Settings"), 'gnome-region-panel.desktop');
},
_sessionUpdated: function() {
// re-using "allowSettings" for the keyboard layout is a bit shady,
// but at least for now it is used as "allow popping up windows
// from shell menus"; we can always add a separate sessionMode
// option if need arises.
if (Main.sessionMode.allowSettings) {
this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
this._showLayoutItem = this.menu.addAction(_("Show Keyboard Layout"), Lang.bind(this, this._showLayout));
}
this.menu.addSettingsAction(_("Region and Language Settings"), 'gnome-region-panel.desktop');
},
setLockedState: function(locked) {
if (Main.sessionMode.allowSettings) {
this._showLayoutItem.actor.visible = !locked;
}
this.menu.setSettingsVisibility(!locked);
this._showLayoutItem.visible = Main.sessionMode.allowSettings;
},
_currentInputSourceChanged: function() {
let nVisibleSources = Object.keys(this._layoutItems).length;
if (nVisibleSources < 2)
return;
let nSources = this._settings.get_value(KEY_INPUT_SOURCES).n_children();
let newCurrentSourceIndex = this._settings.get_uint(KEY_CURRENT_INPUT_SOURCE);
if (newCurrentSourceIndex >= nSources)
return;
let newLayoutItem = this._layoutItems[newCurrentSourceIndex];
let hasProperties;
if (!this._layoutItems[newCurrentSourceIndex]) {
// This source index is invalid as we weren't able to
// build a menu item for it, so we hide ourselves since we
// can't fix it here. *shrug*
if (newLayoutItem)
hasProperties = this._ibusManager.hasProperties(newLayoutItem.ibusEngineId);
else
hasProperties = false;
if (!newLayoutItem || (nVisibleSources < 2 && !hasProperties)) {
// This source index might be invalid if we weren't able
// to build a menu item for it, so we hide ourselves since
// we can't fix it here. *shrug*
// We also hide if we have only one visible source unless
// it's an IBus source with properties.
this.menu.close();
this.actor.hide();
return;
} else {
this.actor.show();
}
this.actor.show();
if (this._layoutItems[this._currentSourceIndex]) {
this._layoutItems[this._currentSourceIndex].setShowDot(false);
this._container.set_skip_paint(this._labelActors[this._currentSourceIndex], true);
}
this._layoutItems[newCurrentSourceIndex].setShowDot(true);
this._container.set_skip_paint(this._labelActors[newCurrentSourceIndex], false);
newLayoutItem.setShowDot(true);
let newLabelActor = this._labelActors[newCurrentSourceIndex];
this._container.set_skip_paint(newLabelActor, false);
if (hasProperties)
newLabelActor.set_text(newLayoutItem.indicator.get_text());
this._currentSourceIndex = newCurrentSourceIndex;
},
@ -242,9 +308,12 @@ const InputSourceIndicator = new Lang.Class({
} else if (type == INPUT_SOURCE_TYPE_IBUS) {
let engineDesc = this._ibusManager.getEngineDesc(id);
if (engineDesc) {
let language = IBus.get_language_name(engineDesc.get_language());
info.exists = true;
info.displayName = engineDesc.get_longname();
info.shortName = engineDesc.get_symbol();
info.displayName = language + ' (' + engineDesc.get_longname() + ')';
info.shortName = this._makeEngineShortName(engineDesc);
info.ibusEngineId = id;
}
}
@ -259,13 +328,6 @@ const InputSourceIndicator = new Lang.Class({
infos.push(info);
}
if (infos.length > 1) {
this.actor.show();
} else {
this.menu.close();
this.actor.hide();
}
for (let i = 0; i < infos.length; i++) {
let info = infos[i];
if (infosByShortName[info.shortName].length > 1) {
@ -274,6 +336,7 @@ const InputSourceIndicator = new Lang.Class({
}
let item = new LayoutMenuItem(info.displayName, info.shortName);
item.ibusEngineId = info.ibusEngineId;
this._layoutItems[info.sourceIndex] = item;
this.menu.addMenuItem(item, i);
item.connect('activate', Lang.bind(this, function() {
@ -319,6 +382,146 @@ const InputSourceIndicator = new Lang.Class({
Util.spawn(['gkbd-keyboard-display', '-l', description]);
},
_makeEngineShortName: function(engineDesc) {
let symbol = engineDesc.get_symbol();
if (symbol && symbol[0])
return symbol;
let langCode = engineDesc.get_language().split('_', 1)[0];
if (langCode.length == 2 || langCode.length == 3)
return langCode.toLowerCase();
return String.fromCharCode(0x2328); // keyboard glyph
},
_propertyWhitelisted: function(prop) {
for (let i = 0; i < this._propertiesWhitelist.length; ++i) {
let key = prop.get_key();
if (key.substr(0, this._propertiesWhitelist[i].length) == this._propertiesWhitelist[i])
return true;
}
return false;
},
_ibusPropertiesRegistered: function(im, props) {
this._properties = props;
this._buildPropSection();
},
_ibusPropertyUpdated: function(im, prop) {
if (!this._propertyWhitelisted(prop))
return;
if (this._updateSubProperty(this._properties, prop))
this._buildPropSection();
},
_updateSubProperty: function(props, prop) {
if (!props)
return false;
let p;
for (let i = 0; (p = props.get(i)) != null; ++i) {
if (p.get_key() == prop.get_key() && p.get_prop_type() == prop.get_prop_type()) {
p.update(prop);
return true;
} else if (p.get_prop_type() == IBus.PropType.MENU) {
if (this._updateSubProperty(p.get_sub_props(), prop))
return true;
}
}
return false;
},
_updateIndicatorLabel: function(text) {
let layoutItem = this._layoutItems[this._currentSourceIndex];
let hasProperties;
if (layoutItem)
hasProperties = this._ibusManager.hasProperties(layoutItem.ibusEngineId);
else
hasProperties = false;
if (hasProperties)
this._labelActors[this._currentSourceIndex].set_text(text);
},
_buildPropSection: function() {
this._propSeparator.actor.hide();
this._propSection.actor.hide();
this._propSection.removeAll();
this._buildPropSubMenu(this._propSection, this._properties);
if (!this._propSection.isEmpty()) {
this._propSection.actor.show();
this._propSeparator.actor.show();
}
},
_buildPropSubMenu: function(menu, props) {
if (!props)
return;
let radioGroup = [];
let p;
for (let i = 0; (p = props.get(i)) != null; ++i) {
let prop = p;
if (!this._propertyWhitelisted(prop) ||
!prop.get_visible())
continue;
if (prop.get_key() == 'InputMode') {
let text;
if (prop.get_symbol)
text = prop.get_symbol().get_text();
else
text = prop.get_label().get_text();
if (text && text.length > 0 && text.length < 3)
this._updateIndicatorLabel(text);
}
let item;
let type = prop.get_prop_type();
if (type == IBus.PropType.MENU) {
item = new PopupMenu.PopupSubMenuMenuItem(prop.get_label().get_text());
this._buildPropSubMenu(item.menu, prop.get_sub_props());
} else if (type == IBus.PropType.RADIO) {
item = new PopupMenu.PopupMenuItem(prop.get_label().get_text());
item.prop = prop;
radioGroup.push(item);
item.radioGroup = radioGroup;
item.setShowDot(prop.get_state() == IBus.PropState.CHECKED);
item.connect('activate', Lang.bind(this, function() {
if (item.prop.get_state() == IBus.PropState.CHECKED)
return;
let group = item.radioGroup;
for (let i = 0; i < group.length; ++i) {
if (group[i] == item) {
item.setShowDot(true);
item.prop.set_state(IBus.PropState.CHECKED);
this._ibusManager.activateProperty(item.prop.get_key(),
IBus.PropState.CHECKED);
} else {
group[i].setShowDot(false);
group[i].prop.set_state(IBus.PropState.UNCHECKED);
this._ibusManager.activateProperty(group[i].prop.get_key(),
IBus.PropState.UNCHECKED);
}
}
}));
} else {
continue;
}
item.setSensitive(prop.get_sensitive());
menu.addMenuItem(item);
}
},
_containerGetPreferredWidth: function(container, for_height, alloc) {
// Here, and in _containerGetPreferredHeight, we need to query
// for the height of all children, but we ignore the results

View File

@ -16,7 +16,6 @@ const Indicator = new Lang.Class({
_init: function() {
this.parent(null, _("Volume, network, battery"));
this.actor.hide();
this._volume = Main.panel.statusArea.volume;
if (this._volume) {
@ -54,9 +53,5 @@ const Indicator = new Lang.Class({
this._battery.mainIcon.bind_property('visible', this._batteryIcon, 'visible',
GObject.BindingFlags.SYNC_CREATE);
}
},
setLockedState: function(locked) {
this.actor.visible = locked;
}
});

View File

@ -1562,16 +1562,15 @@ const NMApplet = new Lang.Class({
Extends: PanelMenu.SystemStatusButton,
_init: function() {
this.parent('network-offline', _('Network'));
this.parent('network-offline-symbolic', _('Network'));
this.secondaryIcon = this.addIcon(new Gio.ThemedIcon({ name: 'network-vpn-symbolic' }));
this.secondaryIcon.hide();
this._isLocked = false;
this._client = NMClient.Client.new();
this._statusSection = new PopupMenu.PopupMenuSection();
this._statusItem = new PopupMenu.PopupMenuItem('', { style_class: 'popup-inactive-menu-item', reactive: false });
this._statusItem = new PopupMenu.PopupMenuItem('', { reactive: false });
this._statusSection.addMenuItem(this._statusItem);
this._statusSection.addAction(_("Enable networking"), Lang.bind(this, function() {
this._client.networking_enabled = true;
@ -1675,11 +1674,6 @@ const NMApplet = new Lang.Class({
}));
},
setLockedState: function(locked) {
this._isLocked = locked;
this._syncNMState();
},
_ensureSource: function() {
if (!this._source) {
this._source = new MessageTray.Source(_("Network Manager"),
@ -2063,7 +2057,7 @@ const NMApplet = new Lang.Class({
_syncNMState: function() {
this.mainIcon.visible = this._client.manager_running;
this.actor.visible = this.mainIcon.visible && !this._isLocked;
this.actor.visible = this.mainIcon.visible;
if (!this._client.networking_enabled) {
this.setIcon('network-offline-symbolic');

View File

@ -56,7 +56,6 @@ const Indicator = new Lang.Class({
this._proxy = new PowerManagerProxy(Gio.DBus.session, BUS_NAME, OBJECT_PATH);
this._isLocked = false;
this._deviceItems = [ ];
this._hasPrimary = false;
this._primaryDeviceId = null;
@ -77,11 +76,6 @@ const Indicator = new Lang.Class({
this._devicesChanged();
},
setLockedState: function(locked) {
this._isLocked = locked;
this._syncIcon();
},
_readPrimaryDevice: function() {
this._proxy.GetPrimaryDeviceRemote(Lang.bind(this, function(result, error) {
if (error) {
@ -160,7 +154,7 @@ const Indicator = new Lang.Class({
hasIcon = true;
}
this.mainIcon.visible = hasIcon;
this.actor.visible = hasIcon && !this._isLocked;
this.actor.visible = hasIcon;
},
_devicesChanged: function() {

View File

@ -62,6 +62,8 @@ const VolumeMenu = new Lang.Class({
this._inputSlider.connect('drag-end', Lang.bind(this, this._notifyVolumeChange));
this.addMenuItem(this._inputTitle);
this.addMenuItem(this._inputSlider);
this._onControlStateChanged();
},
scroll: function(direction) {
@ -90,6 +92,7 @@ const VolumeMenu = new Lang.Class({
if (this._control.get_state() == Gvc.MixerControlState.READY) {
this._readOutput();
this._readInput();
this._maybeShowInput();
} else {
this.emit('icon-changed', null);
}
@ -217,8 +220,6 @@ const Indicator = new Lang.Class({
_init: function() {
this.parent('audio-volume-muted-symbolic', _("Volume"));
this._isLocked = false;
this._control = getMixerControl();
this._volumeMenu = new VolumeMenu(this._control);
this._volumeMenu.connect('icon-changed', Lang.bind(this, function(menu, icon) {
@ -235,13 +236,8 @@ const Indicator = new Lang.Class({
this.actor.connect('scroll-event', Lang.bind(this, this._onScrollEvent));
},
setLockedState: function(locked) {
this._isLocked = locked;
this._syncVisibility();
},
_syncVisibility: function() {
this.actor.visible = this._hasPulseAudio && !this._isLocked;
this.actor.visible = this._hasPulseAudio;
this.mainIcon.visible = this._hasPulseAudio;
},

View File

@ -2,7 +2,7 @@
const AccountsService = imports.gi.AccountsService;
const Clutter = imports.gi.Clutter;
const Gdm = imports.gi.Gdm;
const Gdm = imports.gi.Gdm;
const Gio = imports.gi.Gio;
const GLib = imports.gi.GLib;
const Gtk = imports.gi.Gtk;
@ -23,6 +23,35 @@ const GdmUtil = imports.gdm.util;
// The timeout before going back automatically to the lock screen (in seconds)
const IDLE_TIMEOUT = 2 * 60;
function versionCompare(required, reference) {
required = required.split('.');
reference = reference.split('.');
for (let i = 0; i < required.length; i++) {
if (required[i] != reference[i])
return required[i] < reference[i];
}
return true;
}
function isSupported() {
try {
let params = GLib.Variant.new('(ss)', ['org.gnome.DisplayManager.Manager', 'Version']);
let result = Gio.DBus.system.call_sync('org.gnome.DisplayManager',
'/org/gnome/DisplayManager/Manager',
'org.freedesktop.DBus.Properties',
'Get', params, null,
Gio.DBusCallFlags.NONE,
-1, null);
let version = result.deep_unpack()[0].deep_unpack();
return versionCompare('3.5.91', version);
} catch(e) {
return false;
}
}
// A widget showing the user avatar and name
const UserWidget = new Lang.Class({
Name: 'UserWidget',
@ -41,6 +70,7 @@ const UserWidget = new Lang.Class({
this.actor.add(this._label,
{ expand: true,
x_fill: true,
y_fill: false,
y_align: St.Align.MIDDLE });
this._userLoadedId = this._user.connect('notify::is-loaded',
@ -89,13 +119,16 @@ const UnlockDialog = new Lang.Class({
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 GdmUtil.ShellUserVerifier(this._greeterClient, { reauthenticationOnly: true });
this._userVerifier.connect('reset', Lang.bind(this, this._reset));
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));
@ -112,7 +145,8 @@ const UnlockDialog = new Lang.Class({
this._promptEntry = new St.Entry({ style_class: 'login-dialog-prompt-entry',
can_focus: true });
ShellEntry.addContextMenu(this._promptEntry);
this._promptEntry.clutter_text.set_password_char('\u25cf');
ShellEntry.addContextMenu(this._promptEntry, { isPassword: true });
this.setInitialKeyFocus(this._promptEntry);
this._promptEntry.clutter_text.connect('activate', Lang.bind(this, this._doUnlock));
@ -122,6 +156,9 @@ const UnlockDialog = new Lang.Class({
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);
@ -134,8 +171,7 @@ const UnlockDialog = new Lang.Class({
default: true };
this.setButtons([cancelButton, this._okButton]);
this._updateOkButton(false);
this._reset();
this._updateOkButton(true);
let otherUserLabel = new St.Label({ text: _("Log in as another user"),
style_class: 'login-dialog-not-listed-label' });
@ -150,6 +186,9 @@ const UnlockDialog = new Lang.Class({
{ x_align: St.Align.START,
x_fill: false });
let batch = new Batch.Hold();
this._userVerifier.begin(this._userName, batch);
GLib.idle_add(GLib.PRIORITY_DEFAULT, Lang.bind(this, function() {
this.emit('loaded');
return false;
@ -163,17 +202,30 @@ const UnlockDialog = new Lang.Class({
_updateOkButton: function(sensitive) {
this._okButton.button.reactive = sensitive;
this._okButton.button.can_focus = sensitive;
},
_reset: function() {
this._userVerifier.clear();
this._userVerifier.begin(this._userName, new Batch.Hold());
_showMessage: function(userVerifier, message, styleClass) {
this._promptMessage.text = message;
this._promptMessage.styleClass = styleClass;
GdmUtil.fadeInActor(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;
this._promptEntry.text = '';
if (!this._firstQuestion)
this._promptEntry.text = '';
else
this._firstQuestion = false;
this._promptEntry.clutter_text.set_password_char(passwordChar);
this._promptEntry.menu.isPassword = passwordChar != '';
@ -191,6 +243,15 @@ const UnlockDialog = new Lang.Class({
},
_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._updateOkButton(false);
return;
}
if (!this._currentQuery)
return;
@ -207,13 +268,13 @@ const UnlockDialog = new Lang.Class({
this.emit('unlocked');
},
_onVerificationFailed: function() {
this._userVerifier.cancel();
_onReset: function() {
this.emit('failed');
},
_escape: function() {
this._onVerificationFailed();
this._userVerifier.cancel();
this.emit('failed');
},
_otherUserClicked: function(button, event) {

View File

@ -12,6 +12,7 @@ const Tp = imports.gi.TelepathyGLib;
const UPowerGlib = imports.gi.UPowerGlib;
const Atk = imports.gi.Atk;
const BoxPointer = imports.ui.boxpointer;
const GnomeSession = imports.misc.gnomeSession;
const Main = imports.ui.main;
const PanelMenu = imports.ui.panelMenu;
@ -58,6 +59,11 @@ const UserAvatarWidget = new Lang.Class({
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 (!GLib.file_test(iconFile, GLib.FileTest.EXISTS))
@ -67,6 +73,11 @@ const UserAvatarWidget = new Lang.Class({
let file = Gio.File.new_for_path(iconFile);
this.actor.child = null;
this.actor.style = 'background-image: url("%s");'.format(iconFile);
// AccountsService uses a fixed location for avatar images, so
// we need to clear out all cached data to pick up image changes,
// see https://bugzilla.gnome.org/show_bug.cgi?id=679268
this.actor.clear_background_image();
} else {
this.actor.style = null;
this.actor.child = new St.Icon({ icon_name: 'avatar-default-symbolic',
@ -236,6 +247,10 @@ const IMStatusChooserItem = new Lang.Class({
if (this.actor.mapped)
this._updateUser();
}));
this.connect('sensitive-changed', function(sensitive) {
this._avatar.setSensitive(sensitive);
});
},
_restorePresence: function() {
@ -496,6 +511,8 @@ const UserMenuButton = new Lang.Class({
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));
@ -560,10 +577,20 @@ const UserMenuButton = new Lang.Class({
Lang.bind(this, this._updateHaveShutdown));
this._upClient.connect('notify::can-suspend', Lang.bind(this, this._updateSuspendOrPowerOff));
Main.sessionMode.connect('updated', Lang.bind(this, this._sessionUpdated));
this._sessionUpdated();
},
setLockedState: function(locked) {
this.actor.visible = !locked;
_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();
},
_onDestroy: function() {
@ -647,7 +674,9 @@ const UserMenuButton = new Lang.Class({
},
_updatePresenceIcon: function(accountMgr, presence, status, message) {
if (presence == Tp.ConnectionPresenceType.AVAILABLE)
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;
@ -707,8 +736,7 @@ const UserMenuButton = new Lang.Class({
let item;
item = new IMStatusChooserItem();
if (Main.sessionMode.allowSettings)
item.connect('activate', Lang.bind(this, this._onMyAccountActivate));
item.connect('activate', Lang.bind(this, this._onMyAccountActivate));
this.menu.addMenuItem(item);
this._statusChooser = item;
@ -720,11 +748,10 @@ const UserMenuButton = new Lang.Class({
item = new PopupMenu.PopupSeparatorMenuItem();
this.menu.addMenuItem(item);
if (Main.sessionMode.allowSettings) {
item = new PopupMenu.PopupMenuItem(_("System Settings"));
item.connect('activate', Lang.bind(this, this._onPreferencesActivate));
this.menu.addMenuItem(item);
}
item = new PopupMenu.PopupMenuItem(_("System Settings"));
item.connect('activate', Lang.bind(this, this._onPreferencesActivate));
this.menu.addMenuItem(item);
this._systemSettings = item;
item = new PopupMenu.PopupSeparatorMenuItem();
this.menu.addMenuItem(item);
@ -792,11 +819,13 @@ const UserMenuButton = new Lang.Class({
},
_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 (this._screenSaverSettings.get_boolean(LOCK_ENABLED_KEY))
Main.screenShield.lock(false);

View File

@ -11,7 +11,6 @@ const St = imports.gi.St;
const AppDisplay = imports.ui.appDisplay;
const Main = imports.ui.main;
const PlaceDisplay = imports.ui.placeDisplay;
const RemoteSearch = imports.ui.remoteSearch;
const Search = imports.ui.search;
const SearchDisplay = imports.ui.searchDisplay;
@ -98,7 +97,6 @@ const ViewSelector = new Lang.Class({
this.addSearchProvider(new Wanda.WandaSearchProvider());
this.addSearchProvider(new AppDisplay.AppSearchProvider());
this.addSearchProvider(new AppDisplay.SettingsSearchProvider());
this.addSearchProvider(new PlaceDisplay.PlaceSearchProvider());
// Load remote search providers provided by applications
RemoteSearch.loadRemoteSearchProviders(Lang.bind(this, this.addSearchProvider));
@ -311,7 +309,7 @@ const ViewSelector = new Lang.Class({
startSearch: function(event) {
global.stage.set_key_focus(this._text);
this._text.event(event, false);
this._text.event(event, true);
},
// the entry does not show the hint

View File

@ -50,21 +50,12 @@ const WandaIcon = new Lang.Class({
},
createIcon: function(iconSize) {
if (this._animations)
this._animations.destroy();
if (!this._imageFile) {
return new St.Icon({ icon_name: 'face-smile',
icon_size: iconSize });
}
this._animations = St.TextureCache.get_default().load_sliced_image(this._imageFile, this._imgWidth, this._imgHeight);
this._animations.connect('destroy', Lang.bind(this, function() {
if (this._timeoutId)
GLib.source_remove(this._timeoutId);
this._timeoutId = 0;
this._animations = null;
}));
this._animations.connect('notify::mapped', Lang.bind(this, function() {
if (this._animations.mapped && !this._timeoutId) {
this._timeoutId = GLib.timeout_add(GLib.PRIORITY_DEFAULT, FISH_SPEED, Lang.bind(this, this._update));
@ -77,11 +68,16 @@ const WandaIcon = new Lang.Class({
}
}));
this._i = 0;
return this._animations;
},
_createIconTexture: function(size) {
if (size == this.iconSize)
return;
this.parent(size);
},
_update: function() {
let n = this._animations.get_n_children();
if (n == 0) {

View File

@ -34,6 +34,7 @@ kk
kn
ko
ku
ky
lt
lv
ml

View File

@ -1,3 +1,5 @@
data/50-gnome-shell-screenshot.xml.in
data/50-gnome-shell-system.xml.in
data/gnome-shell.desktop.in.in
data/gnome-shell-extension-prefs.desktop.in.in
data/org.gnome.shell.gschema.xml.in.in
@ -8,24 +10,25 @@ js/gdm/util.js
js/misc/util.js
js/ui/appDisplay.js
js/ui/appFavorites.js
js/ui/autorunManager.js
js/ui/calendar.js
js/ui/components/autorunManager.js
js/ui/components/keyring.js
js/ui/components/networkAgent.js
js/ui/components/polkitAgent.js
js/ui/components/recorder.js
js/ui/components/telepathyClient.js
js/ui/dash.js
js/ui/dateMenu.js
js/ui/endSessionDialog.js
js/ui/extensionDownloader.js
js/ui/extensionSystem.js
js/ui/keyboard.js
js/ui/keyringPrompt.js
js/ui/lookingGlass.js
js/ui/main.js
js/ui/messageTray.js
js/ui/networkAgent.js
js/ui/notificationDaemon.js
js/ui/overview.js
js/ui/panel.js
js/ui/placeDisplay.js
js/ui/polkitAuthenticationAgent.js
js/ui/popupMenu.js
js/ui/runDialog.js
js/ui/screenShield.js
@ -39,7 +42,6 @@ js/ui/status/lockScreenMenu.js
js/ui/status/network.js
js/ui/status/power.js
js/ui/status/volume.js
js/ui/telepathyClient.js
js/ui/unlockDialog.js
js/ui/userMenu.js
js/ui/viewSelector.js

1244
po/ar.po

File diff suppressed because it is too large Load Diff

1295
po/as.po

File diff suppressed because it is too large Load Diff

1552
po/be.po

File diff suppressed because it is too large Load Diff

1553
po/bg.po

File diff suppressed because it is too large Load Diff

1649
po/ca.po

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

1598
po/cs.po

File diff suppressed because it is too large Load Diff

1641
po/da.po

File diff suppressed because it is too large Load Diff

1340
po/de.po

File diff suppressed because it is too large Load Diff

1328
po/el.po

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

1247
po/es.po

File diff suppressed because it is too large Load Diff

1431
po/et.po

File diff suppressed because it is too large Load Diff

1432
po/fa.po

File diff suppressed because it is too large Load Diff

1640
po/fi.po

File diff suppressed because it is too large Load Diff

1568
po/fr.po

File diff suppressed because it is too large Load Diff

1190
po/gl.po

File diff suppressed because it is too large Load Diff

1282
po/gu.po

File diff suppressed because it is too large Load Diff

1397
po/he.po

File diff suppressed because it is too large Load Diff

2228
po/hi.po

File diff suppressed because it is too large Load Diff

1433
po/hu.po

File diff suppressed because it is too large Load Diff

1523
po/id.po

File diff suppressed because it is too large Load Diff

1367
po/it.po

File diff suppressed because it is too large Load Diff

1254
po/ja.po

File diff suppressed because it is too large Load Diff

1556
po/ko.po

File diff suppressed because it is too large Load Diff

1753
po/ky.po Normal file

File diff suppressed because it is too large Load Diff

1253
po/lt.po

File diff suppressed because it is too large Load Diff

1745
po/lv.po

File diff suppressed because it is too large Load Diff

2023
po/ml.po

File diff suppressed because it is too large Load Diff

1317
po/mr.po

File diff suppressed because it is too large Load Diff

2289
po/or.po

File diff suppressed because it is too large Load Diff

1253
po/pa.po

File diff suppressed because it is too large Load Diff

1190
po/pl.po

File diff suppressed because it is too large Load Diff

1656
po/pt.po

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

1281
po/ru.po

File diff suppressed because it is too large Load Diff

1338
po/sl.po

File diff suppressed because it is too large Load Diff

1348
po/sr.po

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

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