Compare commits

...

751 Commits

Author SHA1 Message Date
ccb6b93b65 Bump version to 3.13.92
Update NEWS.
2014-09-17 06:36:54 +02:00
5623f3b4b5 messageTray: Add focusTrap
The summary container will trap the focus if any sources are present,
making the message tray menu unreachable by keynav. Apply the same
hack as in searchDisplay and add a focusTrap to move the focus manually
as necessary.

https://bugzilla.gnome.org/show_bug.cgi?id=707799
2014-09-17 06:19:08 +02:00
a227d595f5 Updated Swedish translation 2014-09-16 20:15:14 +00:00
012955e341 Updated Danish translation 2014-09-16 20:54:42 +02:00
a41cd7d3cc appFavorites: Add gnome-boxes to the rename list 2014-09-16 17:14:36 +02:00
11d947f1e5 l10n: Update Japanese translation 2014-09-16 22:14:02 +09:00
2bb717b0b7 Updated Turkish translation 2014-09-16 09:04:55 +00:00
770f8c6538 Updated Malay translation 2014-09-16 06:49:52 +00:00
e76e0042a8 Updated Marathi Translations 2014-09-16 10:08:16 +05:30
91e266113c appFavorites: Add games to the rename list
Can't wait to double the size of this list when these start using D-Bus
activation.

These were actually renamed in GNOME 3.12, but we couldn't do anything
about it before, and now we can.
2014-09-15 17:05:06 -05:00
ed2956a2ea Updated Bulgarian translation 2014-09-15 20:21:14 +03:00
aa6f352cb0 st-box-layout: Don't report a paint volume when we have no allocation 2014-09-15 17:35:17 +02:00
5a42a91ee0 Updated Assamese translation 2014-09-15 09:30:21 +00:00
4d682c7861 [l10n] Updated Catalan (Valencian) translation 2014-09-14 23:34:57 +02:00
20fec42496 [l10n] Update Catalan translation 2014-09-14 23:34:55 +02:00
437df2f0bd Updated Slovak translation 2014-09-14 19:33:52 +00:00
445aa54622 Finnish translation update by Jiri Grönroos 2014-09-14 19:56:41 +03:00
7fa9ca0a9c Updated Hungarian translation 2014-09-14 13:23:25 +00:00
0fe7ae1810 Updated Russian translation 2014-09-14 15:25:43 +04:00
9c251d85cf Updated Hebrew translation 2014-09-13 23:32:50 +03:00
959b5fe5cf Added Nepali translation 2014-09-13 19:07:46 +00:00
75a8bf626a Updated Slovenian translation 2014-09-13 21:04:13 +02:00
eb514f335c Updated Korean translation 2014-09-14 01:13:56 +09:00
ad77b4ddfc Updated Tamil translation 2014-09-13 16:10:22 +00:00
534bf2b000 Updated Tamil translation 2014-09-13 16:02:03 +00:00
3821fd04a4 Updated Indonesian translation 2014-09-13 08:39:25 +00:00
b55b9cc7a9 Updated Brazilian Portuguese translation 2014-09-13 01:50:33 +00:00
ac6462c7c6 Update Arabic translation 2014-09-13 03:11:12 +03:00
aa7b0a285b search: Do not use deprecated GSettings:schema 2014-09-12 23:56:56 +02:00
0a63de8c8d Updated Polish translation 2014-09-12 23:50:15 +02:00
0992bd41ed background.js: fix updating a BackgroundSource on monitor changes
It was assumed that BackgroundSource objects were always destroyed
on monitor changes because the BackgroundManager objects that hold
references were destroyed, but sequencing of updating of different
BackgroundManager objects meant that was not the case.

Properly update any cached Background objects held by the
BackgroundSource on a change to the monitor layout; in particular this
means updating animations in case they are multi-resolution.
2014-09-12 17:10:04 -04:00
ed52a5a58b Updated Lithuanian translation 2014-09-12 22:29:16 +03:00
79bf770783 Updated French translation 2014-09-12 17:09:58 +00:00
c7e3b68dcd location: Add link to corresponding Settings
All other submenus link to the corresponding settings, so we should
do the same for location - the privacy panel in this case, which now
sports a "Location Services" switch ...

https://bugzilla.gnome.org/show_bug.cgi?id=736542
2014-09-12 18:59:36 +02:00
1b9318c82f keyring: Fix dialog layout in RTL locales
Another case of "StTable used to handle this for us" ...
2014-09-12 13:25:35 +02:00
6a142c4260 Remove some apps from the default favourite apps list
Remove Empathy, LibreOffice Writer and Documents.

https://bugzilla.gnome.org/show_bug.cgi?id=735682
2014-09-12 12:49:20 +03:00
c49f2e1384 search: Only queue an immediate search if we don't have one queued 2014-09-11 18:01:23 -06:00
9208473e59 search: Be a bit more careful in _doSearch about timeouts 2014-09-11 17:51:12 -06:00
08ece4c186 search: Fix timeout ordering 2014-09-11 17:50:56 -06:00
99c29366ee search: Make sure to clear the timeout 2014-09-11 17:40:00 -06:00
7a11964dfb search: Fix indentation 2014-09-11 17:14:54 -06:00
c4922f6624 search: Move the timeout for searching into setTerms
This lets us considerably clean up the event flow here and change how
things are structured. It also makes sure that we never show "No
Results" -- search.js not being aware of the timeout means that it might
not think that any work was being done when we show the page.
2014-09-11 17:10:26 -06:00
4f2070a7c6 search: Track search status more accurately
Keep a flag depending on whether a provider is in-flight, and use that
to determine what status label to show.

This ensures that we only show "No Results" when we're done searching
and we're sure that all providers have returned results back to us.
2014-09-11 17:10:26 -06:00
03177dc474 search: Merge SearchSystem with SearchResults
The complexities of tracking these two things separately, with the
display on one half, and the searching on the other half, is difficult
to manage. Squash it all together.
2014-09-11 17:10:26 -06:00
b9b4886a6f search: Don't bother clearing the result display twice
It's just extra work, and breaks our hide/show hack to prevent the
flashing on search results.
2014-09-11 17:10:25 -06:00
33e35f269f overview: Use a MetaWindow argument in window-drag-* signals/API
It is quite weird to have those calls/signals using WindowClone as an
argument, it is neater to pass MetaWindows around, and have each user
deal with their own representations of these.

https://bugzilla.gnome.org/show_bug.cgi?id=735972
2014-09-12 00:57:40 +02:00
b886656f61 workspace: Take a MetaWindow as argument to setReservedSlot()
And use it to lookup the local WindowClone that applies. Otherwise,
WorkspaceThumbnail.WindowClone objects may be mistakenly set, which
are not usable interchangeably with Workspace.WindowClone ones. This
may lead to several misbehaviors as fields available in the second
object but not in the first one are accessed, some those undefined
values get used in math ops, which result in NaNs over the place.

Likewise, the similar functions in WorkspacesViewBase subclasses take
now MetaWindow arguments too.

https://bugzilla.gnome.org/show_bug.cgi?id=735972
2014-09-12 00:57:40 +02:00
8589bfb62e Implement input source switching
Instead of calling out to gnome-settings-daemon we'll just implement
the switching logic ourselves and use mutter APIs that allow this
functionality to work both in X sessions and when we're a Wayland
compositor.

Switching IBus engines is done transparently as well just like g-s-d
used to do.

https://bugzilla.gnome.org/show_bug.cgi?id=736435
2014-09-11 19:14:46 +02:00
6a36a68f32 ibusManager: Spawn ibus-daemon
gnome-settings-daemon doesn't this for us anymore. Note that
ibus-daemon isn't DBus activatable but just spawning it is fine
because it does its own single instance management. The library
notifies us when it shows up and goes away through the connected and
disconnected signals.

https://bugzilla.gnome.org/show_bug.cgi?id=736435
2014-09-11 19:14:46 +02:00
a0a701757e status/keyboard: Move all UI elements to the indicator class
This will allow us to have multiple indicator instances, e.g. show a
indicator next to text entries in modal shell dialogs.

https://bugzilla.gnome.org/show_bug.cgi?id=736435
2014-09-11 19:14:46 +02:00
effe6fab3a status/keyboard: Factor out an InputSourceManager class
https://bugzilla.gnome.org/show_bug.cgi?id=736435
2014-09-11 19:14:46 +02:00
8e560f98d1 status/keyboard: Factor out a KeyboardManager class
This code will grow in a forthcoming patch so let's move it out.

https://bugzilla.gnome.org/show_bug.cgi?id=736435
2014-09-11 19:14:46 +02:00
58aabfcf5b status/keyboard: Move IBusManager into its own file
This also makes it a singleton for easier access from multiple places.

https://bugzilla.gnome.org/show_bug.cgi?id=736435
2014-09-11 19:14:45 +02:00
19e3f794f8 status/keyboard: Remove unused variable
https://bugzilla.gnome.org/show_bug.cgi?id=735976
2014-09-11 19:12:17 +02:00
2b1077aaa1 switcherPopup: Factor the initial selection into the base class
Only the application switcher needs to keep its own implementation
since it has two modes of operation depending on the binding.

https://bugzilla.gnome.org/show_bug.cgi?id=735976
2014-09-11 19:12:17 +02:00
547cdf86cc switcherPopup: Move _createSwitcher implementations into constructors
We don't really need this step as a separate method since all
implementations are supposed to be created and shown immediately. This
also ensures that we have items to show in all subclasses.

https://bugzilla.gnome.org/show_bug.cgi?id=735976
2014-09-11 19:12:17 +02:00
7653175c6f location: Translate accuracy level for geoclue
The enums values of geoclue have gaps in them (so more levels could be
added in future) but enum values of settings don't have such gaps so we
gotta translate between them.

Since desrt says that enums as integers in gsettings are bad, we now
treat accuracy level settings as string.

This fixes the recent regression of geoclue only allowing geiop level
accuracy to apps.

https://bugzilla.gnome.org/show_bug.cgi?id=736479
2014-09-11 17:43:46 +01:00
a4c1b55111 endSessionDialog: Fix DialogContent const
Fallout from commit 0258c7a518 ...
2014-09-11 17:05:48 +01:00
93205eefb9 global: Filter out destroyed actors from get_window_actors()
All current code assumes that the list of window actors corresponds to the
list of windows; however as the list returned by meta_get_window_actors()
now includes actors during the destroy animation, that assumption breaks.

Eventually we should make everyone move to a more appropriate API, but
for now make it work again by returning a filtered list of "good"
window actors.

https://bugzilla.gnome.org/show_bug.cgi?id=735927
2014-09-11 16:51:31 +01:00
ec3f8d4b85 endSessionDialog: Port offline updates to PackageKit's dbus interface
https://bugzilla.gnome.org/show_bug.cgi?id=736337
2014-09-11 16:13:42 +02:00
0258c7a518 endSessionDialog: Use DialogType constants instead of magic numbers 2014-09-11 15:04:46 +01:00
ebfdb8ec3c Updated German translation 2014-09-10 17:51:53 +00:00
6823bad2d8 popupMenu: Adjust submenu arrows to RTL icon changes
Since commit e04e507659, we will already get the right icon for the
submenu arrow, so we must not mirror it again. However we do need to
take the text direction into account for the rotation now (but that's
not actually too bad - the resulting code gets quite a bit easier).

https://bugzilla.gnome.org/show_bug.cgi?id=736343
2014-09-09 19:48:41 +02:00
491100c7ee appDisplay: Only allow ctrl-click for apps that can open new windows
Trust the heuristics in shell_app_can_open_new_window() to get it right
more often than not, and add an appropriate check in activate(). This
makes the behavior consistent with the dash, e.g. we will try to open
a new window (and show the corresponding animation) for apps that don't
have a "New window" item in their dash context menu.

https://bugzilla.gnome.org/show_bug.cgi?id=736329
2014-09-09 15:57:15 +02:00
762e770c84 update Punjabi Translation - back for 3.14 2014-09-08 19:29:30 -05:00
c214e3b07a Updated Czech translation 2014-09-08 12:37:49 +02:00
b656b1c22f Updated gujarati translations 2014-09-08 14:21:58 +05:30
d211680534 build: Bump GTK+ requirement
... for GTK_ICON_LOOKUP_DIR_{RTL,LTR}
2014-09-07 22:37:06 +02:00
d44c3d0cd3 iconGrid: Make actors reactive on animating out as well
Commit 9e5704b introduced a regression due to a sloppy mistake not
making actors reactive on animation out.
Fix that making actors reactive when animating out as well.
2014-09-07 13:03:24 +02:00
6cb1692841 Finnish translation update by Jiri Grönroos 2014-09-07 13:40:56 +03:00
593acb954d extensionPrefs: Improve handling of OutOfDate extensions
Our current UI is horrible in dealing with outdated extensions - we
don't give users any indication at all that something is not working as
expected (unless hiding the prefs button as we did until the last commit
counts).
To fix this, make the enable switch insensitive to indicate OutOfDate
extensions.

https://bugzilla.gnome.org/show_bug.cgi?id=736185
2014-09-06 22:06:23 +02:00
d209bc69b6 extensionPrefs: Remove version check from extensionAvailable()
It is confusing to treat outdated extensions as if they didn't exist
in some places, but like any other extensions elsewhere. In particular
gnome-tweak-tool still allows to launch prefs for them while making
it clear to users that the extension will not work - opening the
list of installed extensions in that case is unexpected and confusing.
Just remove the version check for now, we will soon follow tweak-tool
and use it to disable the extension switch instead.

https://bugzilla.gnome.org/show_bug.cgi?id=736185
2014-09-06 22:06:23 +02:00
4d64bbcf7d extensionSystem: Fix reloading on version-validation changes
The current code only works for enabled extensions, which means
that extensions that were marked OUT_OF_DATE cannot be enabled
without a restart when disabling the version check.
Fix this by reloading all extensions while making sure to only
enable any extensions when we're supposed to.

https://bugzilla.gnome.org/show_bug.cgi?id=736185
2014-09-06 22:06:07 +02:00
5bd4329b11 iconGrid: Fix latest commit
Wrong copy/paste, the "out" direction should use max distance between
source actor and original actor animating as latest item.
2014-09-06 14:07:22 +02:00
02870e5363 iconGrid: Remove unuseful comment 2014-09-06 13:54:09 +02:00
2a59478b37 iconGrid: Fix last item check on spring animation
Currently we consider the last item animating being the last actor of
the list, but that's wrong since the last item animating depends on the
distance between the source actor and the original position of the
animated actor.

Take that into account to check the last item of the animation.
2014-09-06 13:54:01 +02:00
04030f22a6 Updated Slovak translation 2014-09-06 12:17:09 +02:00
2cc4558018 l10n: Update Japanese translation 2014-09-06 13:27:39 +09:00
215eb5c65f windowManager: limit the "switch app" gesture to !overview.visible
This gesture only makes sense to be triggered outside the overview, when
dealing with application windows themselves.

https://bugzilla.gnome.org/show_bug.cgi?id=736110
2014-09-06 00:50:00 +02:00
5faef316b8 Revert "wobbly"
This reverts commit 6751ca4c18.

As fun as it is, I don't think we want this by default.
2014-09-05 14:51:01 -07:00
6751ca4c18 wobbly 2014-09-05 14:37:18 -07:00
84e0a20701 shellEntry: Remove unused style class 2014-09-05 14:37:18 -07:00
e04e507659 texture-cache: Use LTR/RTL icon lookup flags 2014-09-05 10:25:19 -07:00
6a48dee037 Updated Russian translation 2014-09-05 17:56:05 +04:00
ea3fd0cf65 main: Fix code indentation
This has been bothering me for a while.
2014-09-04 17:55:40 -07:00
9c614057be Updated Korean translation 2014-09-05 07:09:38 +09:00
8096e71c53 Fix problem when background settings change multiple times in rapid succession
The code that cleaned up when a background actor was destroyed tried to access
the Background as backgroundActor.background._delegate but when the destroy
signal is emitted, the MetaBackgroundActor was already disposed and
backgroundActor.background NULL.
2014-09-04 10:07:24 -04:00
73977795a6 Revert accidental commit "Test stuff"
This reverts commit 3b3445146d.
2014-09-03 13:47:18 -04:00
3b3445146d Test stuff 2014-09-03 13:45:01 -04:00
650dea017b Adapt to Mutter background changes
The rewrite of Mutter's background code (see bug 735637) requires
corresponding changes here - we no longer need to layer multiple
MetaBackgroundActors together.

The general strategy is that a BackgroundSource object is created
per GSettings schema, and keeps either one Background/MetaBackground pair,
or, for animation, a Background/Metabackground pair for each monitor.

https://bugzilla.gnome.org/show_bug.cgi?id=735638
2014-09-03 13:45:01 -04:00
70099872ab a11y: initialize clutter accessibility always.
In order to ensure that is clutter AtkUtil implementation the current one.

https://bugzilla.gnome.org/show_bug.cgi?id=735908
2014-09-03 18:45:32 +02:00
dc5618558f popupMenu: Force submenu arrow rotation angles to multiples of 90
When you open or close a PopupSubMenu the arrow icon rotates, but
the code previously assumed that the starting angle was a multiple
of 90.  If you click the submenu fast enough the rotation could overlap
with the previous rotation and you'd get something that wasn't a multiple
of 90.
Now we ensure that the ending arrowRotation angle is always a multiple
of 90 regardless of what the starting angle is.

https://bugzilla.gnome.org/show_bug.cgi?id=728927
2014-09-03 17:50:03 +02:00
62481f4b7c Updated Polish translation 2014-09-03 16:21:24 +02:00
d3418f6381 Bump version to 3.13.91
Update NEWS.
2014-09-03 14:22:32 +02:00
57dd862e35 keyboard: Update for new code
_cursorChanged was folded into _sync at some point.
2014-09-02 14:47:48 -07:00
db76fb8ff9 iconGrid: Fix a typo
It was making icons of the spring animation going/returning to the wrong
position of the dash icon.
2014-09-02 23:24:19 +02:00
9e5704b498 iconGrid: Make actors non reactive while animating
Although the actor are with opacity 0, they were reactive, so the if the
user quickly make a click on the grid while animating it can launch an
app accidentally.
To avoid that make the actors non reactive while animating.
2014-09-02 22:53:14 +02:00
3deaeb4a90 keyboard: Monitor the ShowOSK property of g-s-d
Show the on-screen keyboard if gnome-settings-daemon requests that it
should be shown, such as when using a touchscreen input device. Do this
in addition to monitoring the accessibility setting for the OSK.

https://bugzilla.gnome.org/show_bug.cgi?id=702015
2014-09-02 22:42:33 +02:00
afb7f08e6b Updated Indonesian translation 2014-09-02 12:20:41 +00:00
38c70e73b9 overviewControls: Use correct translation in dragBegin
Commit 12845f0eef reset translationX to 0 to fix the slide-in
animation of the dash when dragging a search result, but 0 is the
wrong value for the thumbnail slider - the next time it will be
shown, it will just pop up instead of sliding in due to translationX
already being at its target value.
Fix this by making _updateTranslation take the actual visibility into
account and call that to set the correct translation in dragBegin.
2014-09-02 00:19:37 +02:00
e60bf44c2e overviewControls: Fix initial slide-in animation
Controls are slided in by animating translationX from the actor's
width to 0; however as _updateTranslation() will skip the animation
when the property is already at its target value and 0 happens to be
the initial value of translationX, the initial animation is skipped.
Fix this by initializing translationX to undefined, which will always
differ from a valid target value.
2014-09-02 00:19:37 +02:00
746a8692ac overviewControls: Don't update translation on slideIn()
The comment is right, updating the translation should be deferred
to pageEmpty, or else overview controls will just pop up instead
of sliding in. So revert that part of commit 6a7fa52879.
2014-09-02 00:19:37 +02:00
a00762ddd9 overviewControls: Fix typos in comment 2014-09-02 00:19:23 +02:00
3981b27d8f search: Remove DND code from GridSearchResult
Providers that need drag-and-drop behavior can implement this via the
createResultObject() hook (as the app search provider already does), no
need to duplicate that code in the generic result objects
(ListSearchResult already does not implement DND).

https://bugzilla.gnome.org/show_bug.cgi?id=734726
2014-09-02 00:07:32 +02:00
62786c09a8 appDisplay: Animate appIcon for new window of apps
Following design mockups, animate the icons on AllView, FrequentView,
Dash and Search to zoom out when opening a new window of the app or when
the app is not running and the user execute it.

https://bugzilla.gnome.org/show_bug.cgi?id=734726
2014-09-02 00:07:32 +02:00
67c216a6fe search: Allow providers to return the complete result object
This makes the existing createResultObject() match its name better
 and avoids oddities like nested StButtons in app search results.

https://bugzilla.gnome.org/show_bug.cgi?id=734726
2014-09-02 00:07:32 +02:00
e933302ae4 shell-glsl-quad: Provide a paint volume
To prevent from falling back to the slow path of doing a full-stage
repaint every time.
2014-09-01 14:06:08 -07:00
75d5e84a4b appDisplay: Animate indicators out
Given that we animate indicator in, it makes sense to animate them out
as well.
Also make possible animating indicators between view changes as well.

https://bugzilla.gnome.org/show_bug.cgi?id=734726
2014-09-01 22:34:51 +02:00
f160dda187 appDisplay: Animate AllView and FrequentView
Following design decision, we want to animate AllView and FrequentView
when opening and closing with a swarm spring form.

This involves a few changes needed to allow that, since from some time
now, we are animating page changes in viewSelector, using only a fade
transition. However now we want to let appDisplay and iconGrid apply its
own animation.

For that we special case the change to and from apps page on
viewSelector to let appDisplay to animate its own items, using and API
on appDisplay which at the same time uses an API on iconGrid.

Thanks Florian Müllner for the debugging work

https://bugzilla.gnome.org/show_bug.cgi?id=734726
2014-09-01 22:34:51 +02:00
9c474a635a appDisplay: Animate folder view items
Add a new animation  to folder view based on designers mockups that
emulates pulsating icons.
The code on iconGrid is though to work well for the upcoming patches to
animate AllView and FrequentView.

https://bugzilla.gnome.org/show_bug.cgi?id=734726
2014-09-01 22:33:42 +02:00
d445bd17eb screenShield: Accept scrolls / swipes either way
If you turn on natural scrolling, instead of swiping up, you need to
swipe down, which is bizarre. Just accept any type of scroll and have
them contribute to the delta.

https://bugzilla.gnome.org/show_bug.cgi?id=734874
2014-09-01 13:15:49 -07:00
584f8c8381 Makefile: Use $(NULL) in one more place 2014-09-01 13:06:51 -07:00
032a688a72 Revert "keyboard: Handle touch events"
This reverts commit a84fb99c0a.

This commit didn't make the OSK fully operational yet on Wayland, and
caused the double emission of key events on X11 due to the OSK keys
receiving first touch events from the passive touch grab, and then
emulated pointer events from event selection after the touch sequence
was rejected in the grab.

When we make a better effort at handling touch events just once on X11,
this commit can be reapplied and remaining wayland OSK support resumed
from there. In the mean time, this patch is better reverted.

https://bugzilla.gnome.org/show_bug.cgi?id=735681
2014-09-01 21:33:04 +02:00
285a7467d0 messageTray: Add bottom drag gesture to popup the message tray
https://bugzilla.gnome.org/show_bug.cgi?id=735625
2014-08-30 14:01:44 +02:00
3289105ac4 viewSelector: Take edge drag gesture into a separate file
This may not be solely used by this code, so take the gesture action
code to its own separate file.

https://bugzilla.gnome.org/show_bug.cgi?id=735625
2014-08-30 14:01:44 +02:00
51861b1e6b appFavorites: Add two more desktop files to the rename list 2014-08-29 13:21:58 +02:00
d85f97c744 grabHelper: Adjust to property name change
Commit bbfa616f27 renamed _ignoreRelease to _ignoreUntilRelease
in some places, but not others, which broke GrabHelper.ignoreRelease().
Complete the name change to fix the fallout (e.g. app launcher menus
closing on button release).
2014-08-28 19:49:51 +02:00
98847f2279 popupMenu: Use an appropriate key to move focus into the menu
The code from PanelMenu.Button assumed menus would open below their
source actor, making KEY_Down a good choice; however with the new
generic code, we should base the key used on the actual menu position.

https://bugzilla.gnome.org/show_bug.cgi?id=735614
2014-08-28 19:12:48 +02:00
1d58ea25ab popupMenu: Handle key-press events on sourceActor
The behavior of opening/closing/navigating a menu from its source
actor is generic enough to not limit it to PanelMenu.Buttons, so
move the code into PopupMenu itself.

https://bugzilla.gnome.org/show_bug.cgi?id=735614
2014-08-28 19:12:48 +02:00
9de05994db Update Persian Translation 2014-08-28 21:02:26 +04:30
c9f3afc38f workspace: Always remove removed windows
Since mutter commit 527c53a2a0582eba, MetaWorkspace::window-removed
is emitted *before* MetaWindow:workspace is updated, so the test
whether the removed window should still be on the workspace in
question will always return true.
Assume the test is no longer necessary nowadays to fix this very
obvious regression.

https://bugzilla.gnome.org/show_bug.cgi?id=735608
2014-08-28 16:57:29 +02:00
3526bc0f0a Updated Telugu Translation 2014-08-27 10:47:14 +05:30
079809af1d workspace: Remove tweens of overlay.title before animate again
Currently we are removing tweens of the button and border, but not from
the title. That causes the title to be in wrong positions sometimes when
dragging windows on the overview, given that the slider is moving and
therefore the windows + overlay are moving too.
To avoid that, remove tweens of the title as well.
2014-08-26 19:35:25 +02:00
26719b02e4 Updated French translation 2014-08-26 11:25:46 +00:00
3a45ddcaad Updated Oriya translation 2014-08-26 10:58:12 +00:00
f839100bc2 committed file 2014-08-26 16:19:41 +05:30
c93767768c perf: fix wallpaper style for overridden background
The code that loads SHELL_BACKGROUND_IMAGE, which is used to load the
performance background was loading it in WALLPAPER mode, not ZOOM
mode. Zoom mode is what we use for the actual GNOME defaultiwallpaper
and what we want to test: the background will be scaled except when
the resolution matches the 2560x1440 default backgrounds.

https://bugzilla.gnome.org/show_bug.cgi?id=735385
2014-08-25 20:28:57 -04:00
0011755b41 Updated Galician translations 2014-08-25 23:08:17 +02:00
ec932b2306 screenShield: Fix typo in comment
And remove outdated reference to gnome-screensaver

https://bugzilla.gnome.org/show_bug.cgi?id=735190
2014-08-21 22:49:58 +02:00
1c0c38574d search: Remove unused function 2014-08-20 18:41:18 +02:00
78b81650f5 Bump version to 3.13.90
Update NEWS.
2014-08-20 02:17:04 +02:00
62bfde45aa search: Fix default drag actor source
Another unnoticed fallout from commit 792b963bda ...
2014-08-19 20:34:08 +02:00
5b624a34b8 location: Only show menu when geolocation is in use
Users can now toggle geolocation off/on from privacy panel of
gnome-control-center so we don't need to clutter the menu with a
settings that most users won't touch most of the time.

https://bugzilla.gnome.org/show_bug.cgi?id=731122
2014-08-19 19:20:47 +01:00
9c008ab998 iconGrid: Move code around a bit
The scale passed to _updateChildrenScale is exclusively computed from
properties, so it can be moved into the function itself - as the scale
now becomes a mere detail, rename to a more appropriate _updateIconSizes
at the same time.
2014-08-19 19:46:45 +02:00
6edcd82103 tweener: Also consider delay when disabling animations
'time' is not the only timing parameter for tweens, in order to
really disable animations, we need to override 'delay' as well.
2014-08-19 19:46:44 +02:00
d5aa276c41 search: Fix custom drag actor source
The existing code broke when commit 792b963bda changed the custom
result actor hook to return an object instead of an actor - stop
trying to go through a _delegate to make it work again.
2014-08-19 19:12:02 +02:00
d54efe0838 runDialog: catch the case where no completion is available
Just return null, instead of failing with an exception later trying to
call substr() on null.

https://bugzilla.gnome.org/show_bug.cgi?id=735062
2014-08-19 09:39:51 -07:00
d0fe1211f2 search: Fix visibility of "more" icon
Since commit 19749bb37f, the icon is always visible - ooops.
2014-08-19 18:13:40 +02:00
3e20843d9c dateMenu: Try to use the default calendar application
Commit 14ceb10555 changed the "Open Calendar" item to open the
"recommended" calendar application rather than the default one to
avoid problems with MIME subclassing (namely falling back to the
default text editor when no calendar app is installed).
With this change however, the application launched does no longer
necessarily match the one configured in Settings, which is unexpected.
To avoid both problems, use the default calendar application again,
but only if it is in the list of recommended applications.

https://bugzilla.gnome.org/show_bug.cgi?id=722333
2014-08-19 18:13:40 +02:00
7c9d90b0aa TelepathyClient: fix history trimming
We need to put the actual actors in the history, not just the labels,
otherwise all emptyLine (which are not messages but are not empty
either) and all lines with a timestamp will get stuck in the scrollback.

https://bugzilla.gnome.org/show_bug.cgi?id=733899
2014-08-19 16:48:13 +02:00
b6e6e097b7 PortalHelper: fix portals that don't redirect properly
We assumed that either a portal would give us a target URI, or we
would eventually reach the URI of our choice (which is http://www.gnome.org)

This is not always the case: even after a successful login we may
stay in a confirmation page, so make sure that every time we see a
redirect we trigger a connectivity check (or queue one for when
the user closes the window)

https://bugzilla.gnome.org/show_bug.cgi?id=733848
2014-08-19 15:29:22 +02:00
3842981c35 SearchEntry: replace the ID with a style class
This way extension authors can create entries that look and feel
like the overview search entry.

https://bugzilla.gnome.org/show_bug.cgi?id=733813
2014-08-19 15:29:22 +02:00
926177785d search: add support for default disabled search providers
Search providers that should be disabled by default come with
a DefaultDisabled=true key in their keyfile, and are enabled
with the "enabled" whitelist, not with the "disabled" blacklist.

https://bugzilla.gnome.org/show_bug.cgi?id=734110
2014-08-19 15:29:22 +02:00
7d80647170 popupMenu: Remove unused function 2014-08-19 15:23:00 +02:00
c2a21bb885 Updated Traditional Chinese translation(Hong Kong and Taiwan) 2014-08-19 19:17:46 +08:00
eaff1e9290 perf-tool: Remove dead code 2014-08-18 22:58:30 +02:00
93c5e6d97e altTab: Fix WindowSwitcherPopup
The "backwards" parameter needs to be dropped here as well.
2014-08-18 13:34:32 -04:00
20fc9735fa Add a special background to use for performance testing
Performance testing was producing inconsistent values at different
times in the day since the GNOME default background is animated and
sometimes has a single layer, and sometimes two blended layers.

So we have consistent numbers, install a simple animated background
with GNOME Shell that has 40-year long transition ending in 2030,a
and set an environment variable in gnome-shell-perf-tool so that the
background is override with that background. (The background depends
on files installed by gnome-backgrounds; we assume that the person
running performance tests is doing so within the scope of a full
GNOME install.)

https://bugzilla.gnome.org/show_bug.cgi?id=734610
2014-08-18 10:54:42 -04:00
d450b74e10 Remove 'backwards' argument from SwitcherPopup:_keyPressHandler
All derived classes are already checking explicitly for action names
(FOO and FOO_BACKWARDS). mutter used to have a META_KEY_BINDING_REVERSES
flag for keybindings which required special handling of "shift"+FOO as
FOO_BACKWARDS, but this has been removed now, so this special handling
is no longer necessary.

https://bugzilla.gnome.org/show_bug.cgi?id=732296
2014-08-17 19:33:22 +02:00
e8fa2b6417 Stop using Meta.KeyBindingFlags.REVERSES for IM switch keybinding
When this flag is set on a MetaKeyBinding, mutter will know that
the keybinding has an associated reverse keybinding triggered with
the shift modifier. However, an undesirable side-effect is that
gnome-control-center keyboard panel does not know that this 'shift'
is reserved for these reverse keybindings and cannot detect
conflicting bindings in this case.
This 'reverse' logic can now be handled at a higher level (in gcc keyboard
panel) so this commit removes it from gnome-shell so that they do not
conflict.

https://bugzilla.gnome.org/show_bug.cgi?id=732296
2014-08-17 19:33:22 +02:00
c459ef6888 Use new meta_key_binding_is_reversed() method
Now that mutter gives a way to check if a MetaKeyBinding was marked as
'reversed' or not, gnome-shell does not have to hardcode that a
MetaKeyBinding using a shift modifier is reversed, it can directly check
if the appropriate flag is set.

https://bugzilla.gnome.org/show_bug.cgi?id=732296
2014-08-17 19:33:22 +02:00
d1a3a000af appDisplay: sync page when changing adjustment
We were setting the value of adjustment on size changes, but we weren't
changing the page value, so adjustment and page value was not in sync.

To fix it, make sure adjustment of the view is in sync with the page
value.

https://bugzilla.gnome.org/show_bug.cgi?id=734680
2014-08-15 23:07:25 +02:00
5ce8980db3 shell-global: Remove grab notifier
With the window menus gone, it is no longer possible to have a GTK+ grab
in-process, so remove our code that was tracking GTK+ grabs.
2014-08-14 10:59:43 -04:00
8c32cff6fc Updated Friulian translation 2014-08-14 06:06:24 +02:00
bc99db9fd3 Updated Assamese translation 2014-08-13 15:40:14 +00:00
a5eae8e3d8 Updated Assamese translation 2014-08-13 12:04:42 +00:00
82a764ee93 Updated Dutch translation 2014-08-12 23:17:25 +02:00
ce2c90a534 location: Move settings to gsettings-desktop-schemas
Since these settings are now going to be accessed by
gnome-control-center as well, its more appropriate for them to live in
gsettings-desktop-schemas.

https://bugzilla.gnome.org/show_bug.cgi?id=734483
2014-08-10 17:56:52 +01:00
28cc0da151 hwtest.js: Fix median computation
By default Array.prototype.sort() sorts all values by converting
them to strings, even numbers!
2014-08-10 09:25:10 +02:00
f1957dccb7 location: Separate setting for enabling/disabling
Having the on/off setting be backed by a boolean in dconf makes sense
anyway but this is mainly to be able to remember the max accuracy set
before user disabled geolocation so that when they enable it next time,
we have the max accuracy level on same value as before.

There hasn't been a real need for this but now we are about to add
geolocation settings in control center and it'll be easiser for
control-center to simply toggle a boolean property rather than to have
to know about and deal with accuracy levels.

Later we might also want to add accuracy level settings to privacy panel
so keeping the accuracy level setting around still. However we no longer
support 'off' accuracy level as the new boolean property covers that.

This also implies that we no longer track available accuracy level,
which made the code a bit hard to follow/maintain.

https://bugzilla.gnome.org/show_bug.cgi?id=734483
2014-08-09 15:59:41 +01:00
0af4dc0b4c Remove explicit ENABLE_EXPERIMENTAL_API switches
Those are already defined globally via the Makefile, and newer
compiler versions complain about redefining those symbols.
2014-08-08 17:58:37 +02:00
687e1ebf69 workspace: Fade in instead of zoom to return desktop
The zooming animation of the windows looks nice when animating
from the workspace display page, but looks weird from other pages
like apps page or search page since the windows come from nowhere
with an initial position not known to the user.

Instead of that just fade the desktop with the windows in its
original position.

https://bugzilla.gnome.org/show_bug.cgi?id=732901
2014-08-08 16:40:41 +02:00
805b686576 overviewControls: don't override explicit calls to slideIn
Currently we are overriding the explicit calls to slideIn
given that it's called also with the signal of showing overview.

It was necessary because of the bug that previous patch fixed,
so now we can just delete that.

https://bugzilla.gnome.org/show_bug.cgi?id=732901
2014-08-08 16:40:41 +02:00
101daf6791 workspaceThumbnails: allow requesting size at any time
The slide of thumbnailWorkspace is shown when entering overview,
connecting to the same signal that creates the thumbnails, the showing
signal of overview, but, to make the slide animation we need to know how
much width the slider has.  To do that we ask the thumbnailsWorkspace
about its width, but given that it connects to the same signal it could
ask the width without having created the thumbnails yet, so reporting a
width of 0 and confusing the slide animation.

Currently it works because gjs calls the callbacks following the order
of the clients connecting that signal, and the thumbnailsWorskpace is
connected before the slide ones.

To avoid that we allow to request the preferred size of the
thumbnailsBox at any time with any number of thumbnails. The only thing
required is to make sure the porthole is accessible when requesting the
preferred size.

https://bugzilla.gnome.org/show_bug.cgi?id=732901
2014-08-08 16:40:41 +02:00
5d12ab415c viewSelector: Remove duplicate call to showPage
We were calling twice showPage() with the correct page, here and in
show() / zoomFromOverview given that _resetShowAppsbutton was called
from the signal 'showing' of overview.  Given that the call to
_resetShowAppsbutton is only actually used when hiding the overview we
can actually put the checked state of the button to false when animating
from overview so it shows the workspace page, causing the same behavior
of _resetShowAppsbutton without all the shenanigans of resetting when
the hiding overview signal is triggered.

https://bugzilla.gnome.org/show_bug.cgi?id=732901
2014-08-08 16:40:41 +02:00
0810ab62db Port to cogl_texture_2d_new_from_data 2014-08-07 14:49:55 -04:00
6f00d81abf texture-cache: Port to modern Cogl 2014-08-07 14:49:55 -04:00
4184edc7f8 texture-cache: Remove FBO path for padding icons
GtkIconTheme now pads icons when it loads them to make sure that they
are square, so this code is effectively dead.
2014-08-07 14:49:55 -04:00
05f9f991d8 st: Adapt the mutter implementation for create_texture_material
This is the new API that uses set_null_texture instead of a dummy texture.
2014-08-07 14:49:54 -04:00
3df7ef6ce6 shell: Define COGL_ENABLE_EXPERIMENTAL_API and related defines globally
This allows us to use new Cogl APIs without having to define things in
every .c/.h file manually.
2014-08-07 14:49:54 -04:00
d836194e31 appDisplay: Remove pointless return value
StButton::clicked does not have a return type, so don't return anything.
2014-08-07 18:41:28 +02:00
8ed3e2117f Add Software to the end of the dash
https://bugzilla.gnome.org/show_bug.cgi?id=734406
2014-08-07 14:19:55 +02:00
62fcda5d91 Updated Basque language 2014-08-07 12:36:21 +02:00
0a780376f3 Updated Basque language 2014-08-07 12:31:50 +02:00
efb9f167bd messageTray: Fix RTL handling in notifications
Commit 234b90ac86 replaced a member variable with a "local"
one, except that it wasn't that local after all ...
2014-08-06 16:10:27 +02:00
eb69f3aa76 networkAgent: Use Clutter.GridLayout
Clutter.TableLayout has been deprecated, so move to the recommended
replacement.
2014-08-06 15:23:21 +02:00
c15a885418 keyring: Use Clutter.GridLayout
Clutter.TableLayout has been deprecated, so move to the recommended
replacement.
2014-08-06 15:23:21 +02:00
fe60db64e0 appDisplay: Use Clutter.GridLayout
Clutter.TableLayout has been deprecated, so move to the recommended
replacement.
2014-08-06 15:23:21 +02:00
b90cc5ff26 calendar: Port events to Clutter.GridLayout
Clutter.TableLayout has been deprecated, so move to the recommended
replacement.
2014-08-06 15:23:21 +02:00
e9f95ca605 calendar: Use Clutter.GridLayout
Clutter.TableLayout has been deprecated, so move to the recommended
replacement.
2014-08-06 15:23:21 +02:00
017c2468ee popupMenu: Remove unused imports 2014-08-06 15:23:21 +02:00
8c6a2874ff workspace: Fix style 2014-08-06 15:23:21 +02:00
557130d2f2 workspace: Remove unused parameter 2014-08-06 15:23:20 +02:00
84cbbafaae appDisplay: Don't grow indicators more than the parent
Currently the indicators are a BoxLayout inside a BinLayout in AllView.
BinLayout doesn't have any size constraint, so if the indicators request
a bigger size than AllView the entire overview is grown, causing the
overview to go crazy.

To avoid that, create an actor for the page indicators that request as
minimum size 0, and as a natural size, the sum of all indicators natural
sizes. Then we clip_to_allocation, so it doesn't grow more than the
parent.

https://bugzilla.gnome.org/show_bug.cgi?id=723496
2014-08-06 09:41:29 +02:00
72a663f554 windowManager: Fix destroy animation
Guess who didn't test his destroy animation that he pushed without any
review!!! It wasn't me!
2014-08-03 15:30:06 -04:00
7c762ef9df Updated Greek translation 2014-08-02 09:33:20 +00:00
3182aba744 AppDisplay: don't show a "New Window" menu item if not possible
If the application reports itself as single window (through
an explicit indication in the desktop file or some heuristics),
not show a "New window" item that doesn't actually open a new window.

https://bugzilla.gnome.org/show_bug.cgi?id=722554
2014-08-01 11:45:18 +02:00
e6339fbb45 doap: add <programming-language> 2014-07-31 17:48:46 +02:00
a6d8c25494 panel: Avoid _onEvent() to be called twice
Both Panel.ActivitiesButton and its parent class Panel.MenuButton would
attempt to connect their own _onEvent() function to Clutter::event,
which counterintuitively was connecting the child class' _onEvent()
function twice.

So, actually chain up on the signal handler, and don't connect twice
to the signal. Both methods were calling this.menu.close(), so only
do that on the parent class handler, since we're chaining up and doing
the right thing now.

https://bugzilla.gnome.org/show_bug.cgi?id=733840
2014-07-31 17:43:09 +02:00
cd4eda8bef ScreenShield: remove obsolete comment and hack
We don't need to wait to until the stage window is mapped to take
the modal grab, because that code now runs in a startup-prepared
signal handler, which in turn runs some time after the mainloop
has started and well after the stage window is mapped.

https://bugzilla.gnome.org/show_bug.cgi?id=711682
2014-07-31 16:54:47 +02:00
a0bd4a02e4 Fix accidental gvc downgrade 2014-07-31 16:54:34 +02:00
42b54aaa21 grabHelper: handle touch events during grab modality
The "pointer emulating" touch sequence will be handled in order to dismiss
the grab, while the others are just propagated.

https://bugzilla.gnome.org/show_bug.cgi?id=733633
2014-07-31 10:55:25 +02:00
bbfa616f27 grabHelper: consume the press/motion/release sequence if a press dismisses the grab
The grab would previously just consume the button release, while propagating
motion events, possibly down to clients in wayland. This would produce
inconsistent streams there.

On pointer events, the inconsistency would just be having clients receiving
events with the button 1 set in the mask, with no implicit grab. When touch
events are handled, this would be more hindering as the client would receive
touch_motion events with no prior touch_down nor later touch_up, something
never supposed to happen.

https://bugzilla.gnome.org/show_bug.cgi?id=733633
2014-07-31 10:55:11 +02:00
7e31015ba2 doap category core 2014-07-30 16:31:48 +02:00
aa2fc3c858 WindowManager: update animation timings after designer review
Lapo, Jakub and Allan all agree with this.

https://bugzilla.gnome.org/show_bug.cgi?id=732857
2014-07-29 14:55:51 +02:00
d4f0b5bdf3 WindowManager: improve destroy window animation
The animation is the same for modal dialogs, but it is now
run for non modal dialogs too (matching the new behavior on
show).
In addition, we run a destroy animation for normal windows,
if they use CSD (there are technical limitations that prevent
running animations after destroy on server decorated windows)

https://bugzilla.gnome.org/show_bug.cgi?id=732857
2014-07-29 14:55:48 +02:00
eda27d5194 WindowManager: improve minimize/map animations
Using the parameters from Elementary's Gala, which is generally
considered a DE that cares about eye-candy.

https://bugzilla.gnome.org/show_bug.cgi?id=732857
2014-07-29 14:53:28 +02:00
589e6c29f3 loginDialog: Push a modal for LOCK_SCREEN
So that we're in the correct keybinding mode.
2014-07-27 08:18:51 -04:00
4b46533ce8 loginDialog: Fix the removal from the ctrlAltTabManager
When we ported away from ModalDialog, we forgot to change this one
reference to the dialog layout. Change it now.
2014-07-27 08:12:27 -04:00
6687b9b739 layout: re-allocate keyboard box when monitor config changes
For example, because we are changing orientation.

https://bugzilla.gnome.org/show_bug.cgi?id=733790
2014-07-26 17:45:55 +02:00
91c4408d23 shell-recorder: Don't use XI2 in the recorder to query the pointer
Just use the normal MetaCursorTracker, which works under Wayland.
2014-07-26 10:51:48 -04:00
83adb2a864 clutter.paintCompletedTimestamp: cogl_flush() before glFinish()
Calling glFinish() doesn't give us a reliable timestamp unless we
flush Cogl rendering to GL first.
2014-07-26 16:46:45 +02:00
5918faddf7 Updated Lithuanian translation 2014-07-25 22:54:13 +03:00
916c02a2f5 hwtest: Handle rename of gedit desktop file
It's now org.gnome.gedit.desktop not gedit.desktop.
2014-07-25 10:40:45 +02:00
a84fb99c0a keyboard: Handle touch events
Handle touch events, so that an interacted button locks to a single sequence,
but multiple sequences are free to interact with multiple key buttons.

https://bugzilla.gnome.org/show_bug.cgi?id=733633
2014-07-24 18:44:14 +02:00
69d5cef3b2 keyboard: Use common code to create regular and extension key buttons
The code is almost the same, so pull this out to a generic _makeKey(), and
use it from both places.

https://bugzilla.gnome.org/show_bug.cgi?id=733633
2014-07-24 18:26:56 +02:00
38d05a8285 panel: Make the "Activities" button react to touch events
https://bugzilla.gnome.org/show_bug.cgi?id=733633
2014-07-24 18:23:17 +02:00
f8899cf274 appDisplay: Allow clicks/long presses through touch events
The long press code has been refactored so it can be used on both pointer and
touch events, and the click gesture has been made to account for button=0.

https://bugzilla.gnome.org/show_bug.cgi?id=733633
2014-07-24 18:15:02 +02:00
dbbf4097a5 slider: React to touch events
The slider locks to the first interacting sequence, and ignores events from
any other.

https://bugzilla.gnome.org/show_bug.cgi?id=733633
2014-07-24 18:15:02 +02:00
acb1497f4f backgroundMenu: Allow for long presses on touch devices
These don't have a button set. Also, popup the menu relative to gesture
reported coordinates, and not relative to the pointer position everytime.

https://bugzilla.gnome.org/show_bug.cgi?id=733633
2014-07-24 18:15:02 +02:00
e545ec59b9 panelMenu: Interact to touch events
No sequence checks are done, these UI elements promptly trigger a grab that
will cancel ongoing touches and redirect later ones somewhere else, so that
works as a barrier to multi-toggling.

https://bugzilla.gnome.org/show_bug.cgi?id=733633
2014-07-24 18:15:02 +02:00
da26a9daf8 popupMenu: dismiss the menu on touch events
No sequence checks are done, just any touch outside will dismiss the popup.

https://bugzilla.gnome.org/show_bug.cgi?id=733633
2014-07-24 18:15:02 +02:00
a2f263dcbb st-button: Handle touch events
On touch events, StButton becomes locked to a single sequence, so no multiple
touches can trigger it simultaneously.

https://bugzilla.gnome.org/show_bug.cgi?id=733633
2014-07-24 18:15:02 +02:00
ce5cd3bf30 st-scroll-view-fade: Refuse to work without GLSL
Disable the effect when GLSL is not available otherwise we will
crash later.

https://bugzilla.gnome.org/show_bug.cgi?id=733623
2014-07-24 16:51:03 +02:00
9a05aea76f lightbox: Do not assume GLSL is available
Some hardware does not support it causing crashes in cogl during paint.

https://bugzilla.gnome.org/show_bug.cgi?id=733623
2014-07-24 16:51:02 +02:00
c9f6d5e2a1 Bump version to 3.13.4
Update NEWS.
2014-07-23 13:02:10 +02:00
eba2b999ed popupMenu: Fix PopupImageMenuItem
https://bugzilla.gnome.org/show_bug.cgi?id=733540
2014-07-23 10:24:18 +02:00
cceac0d8fb appFavorites: Automatically update desktop file names in user settings
This adds a table with mappings for GNOME apps that have recently
renamed their desktop files, and uses that to update the desktop names
saved in user settings with the new values.

https://bugzilla.gnome.org/show_bug.cgi?id=729429
2014-07-22 14:18:06 +02:00
14eedf8651 Updated Spanish translation 2014-07-22 12:31:23 +02:00
9c6180afa2 system: Fix orientation lock never appearing
Typos meant that the orientation service was never detected as running
and that the orientation lock menu item didn't appear.

https://bugzilla.gnome.org/show_bug.cgi?id=733498
2014-07-21 14:35:27 +02:00
f1b1dbcb00 Updated Norwegian bokmål translation from Åka Sikrom. 2014-07-21 13:50:39 +02:00
ee23b8dbe0 Updated Norwegian bokmål translation from Åka Sikrom. 2014-07-21 13:48:46 +02:00
c9e00bee08 plugin: Use the clutter xdisplay for has_swap_events
The filter now runs on the backend connection.
2014-07-19 18:51:56 +02:00
9970671bb1 Search: Don't use IconGrid width for maxDisplayedResults
Currently to know how many results we could show for GridResults
we use the width of the bin containing those results. Since it's
expanding it shouldn't be a problem. But it becomes a problem when
no results are displayed, thus the container becomes hidden and
it losts its allocation.
In the next introduction of terms in search we call again
maxDisplayedResults but it doesn't have allocation yet, and therefore no
results are displayed (currently a bug on IconGrid makes the min size =
one icon, so actually we show one and only one icon in this case).

To solve that use the parent container which contains the search results
of all providers or the text label with not displayed results, so it
always have the real available width to calculate maxDisplayedResults.

Thanks Alban Browaeys for the debugging footwork.

https://bugzilla.gnome.org/show_bug.cgi?id=732416
2014-07-19 18:12:43 +02:00
bb4502dca8 Updated Brazilian Portuguese translation 2014-07-18 16:25:29 +00:00
d77c7a407c extensionPrefs: Respect 'disable-extension-version-validation' setting 2014-07-18 10:47:02 +02:00
554001c0ed appDisplay: Move focus to popup only when necessary
Unlike for the main app view, where we only move the key focus once the
users starts navigating, the key focus is moved immediately when opening
a folder popup. This is unexpected, so make app folders consistent with
the main view.
As arrow keys will not work while the container itself has key focus, we
handle those explicitly by translating them to TAB_FORWARD and
TAB_BACKWARD respectively.

https://bugzilla.gnome.org/show_bug.cgi?id=731477
2014-07-17 20:41:24 +02:00
4d153bc96f Updated Hebrew translation 2014-07-17 09:49:16 +03:00
476394809a Mark a string to be translatable
And replace three points ('...') with the
unicode character '…'.
2014-07-17 09:48:26 +03:00
b6f3e15037 Add support for meta_restart() and MetaDisplay::restart
Support was added to Mutter to allow it to trigger a restart
to allow for restarts when switching in or out of stereo mode.

Hook up to the new signals on MetaDisplay to show the restart
message and reexec. Meta.is_restart() is used to suppress
the startup animation.

This also allows us to do 'Alt-F2 r' restarts more cleanly
without a visual flash and animation.

https://bugzilla.gnome.org/show_bug.cgi?id=733026
2014-07-16 18:04:19 -04:00
46c86e093c hwtest.js: Don't parse JSON with regexps
Use JSON.parse() to parse systemd log records, rather than using
regexps.

https://bugzilla.gnome.org/show_bug.cgi?id=732350
2014-07-16 13:22:13 -04:00
c6350aa557 Add --hwtest option to gnome-shell-perf-helper
Add a --hwtest option to gnome-shell-perf-helper which runs the
tests in perf/hwtest.js with the appropriate environment, and then
logs the results using the 'gnome-hwtest-log' utility which is
available in the hardware testing environent.

(For development of hwtest.js in a normal environment, run the tests
as: gnome-shell-perf-tool --perf=hwtest --extra-filter=Gedit)

https://bugzilla.gnome.org/show_bug.cgi?id=732350
2014-07-16 10:37:48 -04:00
4e56af39da Add a new hwtest script
Add a performance test script that is used by the GNOME Hardware Testing
Project to measure metrics to be reported to perf.gnome.org.

https://bugzilla.gnome.org/show_bug.cgi?id=732350
2014-07-16 10:37:48 -04:00
9fff972946 perf: add a ShellGlobal property to call glFinish and log the time
It's useful to know how long frames are taking to render on the GPU.
This is impossible to measure in the normal case because frames may
parallelize with previous frames, but by calling glFinish() at the
end of the frame, we can create a (somewhat artificial, but useful)
environment where we have a meaningful timestamp for the frame
finishing drawing.

https://bugzilla.gnome.org/show_bug.cgi?id=732350
2014-07-16 10:37:48 -04:00
e30925995f Make frame-timestamp logging optional
Instead of always logging frame timestamps for every frame - which
was using >26 bytes of memory per frame, or 5MB per hour of continuous
redrawing - make frame timestamps something that defaults off and is
turned turned on using a new ShellGlobal::frame-timestamps property by
the perf scripts.

https://bugzilla.gnome.org/show_bug.cgi?id=732350
2014-07-16 10:33:59 -04:00
f0d4260c81 ShellPerfLog: Use monotonic timestamps for logging
Use g_get_monotonic_time() (that is, CLOCK_MONOTONIC) timestamps,
rather than gettimeofday() values.

https://bugzilla.gnome.org/show_bug.cgi?id=732350
2014-07-16 10:33:59 -04:00
a7f82745c6 shell-perf-helper: Add an option for continual redraws
Add an option for windows created with Scripting.createTestWindow()
to continually redraw themselves; this is for testing performance
of application updates.

https://bugzilla.gnome.org/show_bug.cgi?id=732350
2014-07-16 10:33:59 -04:00
a6fa6519d5 Updated Greek translation 2014-07-16 10:54:09 +00:00
a944dca60e overview: Remove wrong comment 2014-07-14 22:05:51 +02:00
fdc443aebe viewSelector: Going to the apps grid is a swipe from the left, not right 2014-07-14 14:02:46 -04:00
7e08e1e0e7 Updated Brazilian Portuguese translation 2014-07-14 16:24:06 +00:00
bd7938e02f Updated German translation 2014-07-09 22:28:21 +00:00
a583f45cc6 viewSelector: Synthesize a new event with correct source for search
We currently replay events that should start a search to the search
entry, which is fairly dodgy. Synthesize a new event with the correct
source actor instead, which is a bit less evil.
2014-07-09 12:23:30 +02:00
1071ac5d25 notificationDaemon: Group tray icon stuff together 2014-07-08 15:39:46 -04:00
45793d0e47 panel: Fix style 2014-07-08 15:38:35 -04:00
ea3866a07a main: Fix code style 2014-07-08 14:29:50 -04:00
e41879a5c4 windowManager: Switch the focused application on 3-finger hold + tap
The gesture action only cycles through the applications in the current
workspace.
2014-07-08 12:06:14 -04:00
24dc926660 windowManager: Switch workspaces on 4-finger drag
The workspace to switch is obtained from the direction received
by the WorkspaceSwitchAction gesture.
2014-07-08 12:06:14 -04:00
932b895127 viewSelector: Show the overview on 3-finger pinch gestures 2014-07-08 12:06:14 -04:00
9c4ffc4bf3 viewSelector: Add left edge drag gesture to show the app picker 2014-07-08 12:06:12 -04:00
1ea2e2bcab backgroundMenu: Release the click gesture if a grab operation begun
If an active grab on pointer events happens during multi-touch operations,
all non-pointer-emulating touches will be muted. This may leave the
Clutter.ClickAction incomplete if triggered by one of those sequences,
just to have a gesture take over and trigger a compositor grab, which would
leave the capture-event handler stuck eating events.

So listen for grab-op-begin from the display, and ensure the action is
released if such grab begins.
and the capture event handler stuck.
2014-07-08 12:01:43 -04:00
a8b15dd2cf gitignore: Add portal helper generated files 2014-07-08 16:15:19 +02:00
b1b8147ab8 Updated Russian translation 2014-07-08 17:18:44 +04:00
39c210abed ibusCandidatePopup: Fix default candidate index labels
The first 10 candidates are supposed to be shortcutted with the
keyboard keys 1 through 0 so the 10th index should be '0', not 'a'.

https://bugzilla.gnome.org/show_bug.cgi?id=702944
2014-07-08 11:31:15 +02:00
4bb2a364d3 overview: Avoid repositioning windows while returning to desktop
When returning to the desktop from overview we always show the
workspaceDisplay, given that is which have the windows clones to allow
animations.
The problem becomes when previous that we were at some other
page, like Search or AppDisplay. The problem is that when showing the
workspaceDisplay the windows are repositioned. That's wanted except
when returning from overview, since that causes unwanted animations
of the windows.
To avoid that just not reposition the windows if leaving the overview.
2014-07-07 17:37:24 +02:00
6d3ebdcb5e update Punjabi Translation - back for 3.14 2014-07-05 23:23:36 -05:00
e865db57e0 extension-tool: Fix multi-monitor handling in example extension 2014-07-05 11:22:46 +02:00
19ba9a98b8 Updated Chinese (Taiwan) translation 2014-07-04 12:24:13 +00:00
4a39af7f98 overview: Reorder functions for better context 2014-07-03 16:15:25 +02:00
c326aad9d7 overview: Delete false comment 2014-07-03 16:15:04 +02:00
dc94f7b9f5 notificationdaemon: fix gtk protocol for newer glib
The new protocol uses a "priority" string instead of the "urgent"
boolean.
2014-07-01 21:57:29 +02:00
e5be41b667 Updated Galician translations 2014-07-01 17:56:24 +02:00
775bd961b6 hidpi: Scale fonts on wayland
On X11 we don't need to scale up fonts because font scaling is already handled
by clutter based xft-dpi. On wayland we need to set the resolution by ourselves
so do that when the scale factor changes.

https://bugzilla.gnome.org/show_bug.cgi?id=732537
2014-07-01 12:02:19 +02:00
3c67d012e7 Updated Spanish translation 2014-06-30 13:50:32 +02:00
2fbd8f063e Scripting: catch errors from shell-perf-helper
When calling remote D-Bus methods, handle exceptions, log them
and exit, rather than just proceeding as if nothing happened.

https://bugzilla.gnome.org/show_bug.cgi?id=732349
2014-06-29 18:27:54 -04:00
f285f2c69f Scripting.createTestWindow(): take params
Take a parameter object rather than a long parameter list containing
multiple booleans.

https://bugzilla.gnome.org/show_bug.cgi?id=732349
2014-06-29 18:27:54 -04:00
e375e1a857 perf: fix bug in code to print out metrics
We don't normally hit the code in scripting.js to print metrics
because shell-perf-tool bypasses it, but there was a left-over
in the code that no longer works. Also add in the units to the
output.

https://bugzilla.gnome.org/show_bug.cgi?id=732349
2014-06-29 18:27:54 -04:00
910c95fa9b Scripting: exit if the perf script throws an error during collection
If an exception occurs while collecting parameters, exit rather than
just leaving the shell running in the main loop.

https://bugzilla.gnome.org/show_bug.cgi?id=732349
2014-06-29 18:27:54 -04:00
b95c0682b0 js/Makefile.am: Fix dependency generation with srcdir != builddir
If reusing an existing separate builddir, the generation of dependencies
for the JS resource file would fail because it couldn't find misc/config.js,
resulting in the resource file not being regenerated.

https://bugzilla.gnome.org/show_bug.cgi?id=732348
2014-06-29 18:27:53 -04:00
9f460a36f6 recorder: Fix typo
Both stage width and height are meant to be tracked.
2014-06-28 00:47:53 +02:00
41a3f10938 layout: Make the dummy cursor invisible
This means that moving it around won't attempt to cause a full redraw of
the stage. Yikes.
2014-06-27 11:59:10 -04:00
d850c8599e windowManager: Don't use ClutterActor.scale-gravity
It's deprecated as well.
2014-06-27 10:54:11 -04:00
ec288d0e68 layout: Use ClutterActor.background-color instead of ClutterStage.color
The latter is deprecated.
2014-06-27 10:54:10 -04:00
0b92cd0772 Updated POTFILES.in 2014-06-27 01:21:25 +02:00
c7f5f172dd Use the new RTL icons from adwaita
Use the suffix -rtl and -ltr.

https://bugzilla.gnome.org/show_bug.cgi?id=732301
2014-06-27 01:25:22 +03:00
84bc445593 st-icon: Undeprecate icon-name
Don't cause a bunch of warnings when the icon-name property is still a
really convenient internal shorthand.
2014-06-26 18:16:50 -04:00
365bfcae12 portalHelper: fix typo
Not even an hour, and already the first bug...
2014-06-26 20:10:18 +02:00
47c9243271 NetworkManager: show portal logins when required
Listen to changes in connectivity, and ask our helper to authenticate
when needed.
We don't have a URL to connect to yet (we will have when
the new NM API lands), so we use the default of trying
www.gnome.org (which is also more reliable because we can
recognize when the login is done)

https://bugzilla.gnome.org/show_bug.cgi?id=704416
2014-06-26 19:55:02 +02:00
8c67a70db0 Add a helper to handle captive portal logins
Add a small DBus-activated GtkApplication that embeds a WebKitWebView
and implements some minimal logic to see if the login succeeds.
It will try to connect to a custom NM-provided url (the portal login
page), if one exists, or to www.gnome.org in the normal case of
a portal doing redirect.

https://bugzilla.gnome.org/show_bug.cgi?id=704416
2014-06-26 19:54:58 +02:00
5f4591e24c NetworkMenu: make sure menu icons are updated at the end of connectivity checks
Icons inside the menu are updated only for device state change,
but for the main device they also depend on connectivity (which
is a global property).
Add a public method to force an update of the icon, and call it
when connectivity changes.

https://bugzilla.gnome.org/show_bug.cgi?id=726401
2014-06-26 19:23:57 +02:00
37ef0e4bed WorkspacesView: don't access the allocation 4 times
Access it once, and save 3 GObject property accesses and related
copies.

https://bugzilla.gnome.org/show_bug.cgi?id=729823
2014-06-26 19:20:17 +02:00
7d7b92419f Workspace: ignore actual geometry changes while unmapped
If unmapped, ignore geometry changes. This avoids doing useless
layout work on invisible workspaces during the slider control
animations.

https://bugzilla.gnome.org/show_bug.cgi?id=729823
2014-06-26 19:20:17 +02:00
309d40a92b WorkspacesView: separate setting the full and the actual geometry
They are different properties, they deserve different syncs.
Especially because a full allocation cycle sets both anyway, so
we should save some cycles this way.

https://bugzilla.gnome.org/show_bug.cgi?id=729823
2014-06-26 19:20:17 +02:00
02718357da workspace: avoid GObject overhead while computing the clone layout
We already have the width and height information cached in JS,
let's avoid going through gjs-gobject-clutter to retrieve them
again. As a plus, with normal properties the optimizer should
be able to generate better code.

https://bugzilla.gnome.org/show_bug.cgi?id=729823
2014-06-26 19:20:17 +02:00
cfef107114 background: fix early destroy of SystemBackground
If the SystemBackground is destroyed before loading, we call
removeImageContent() with null, which crashes.
2014-06-26 19:20:17 +02:00
b742b1eed2 background: fix typo updating images for animated background
We must remove the old image from the cache, not the new one.

This was causing a leak of old (and expensive) background
images, and was causing errors at the end of animations, trying
to destroy the animated background.
2014-06-26 19:20:17 +02:00
d58be565a1 Updated Russian translation 2014-06-25 22:59:18 +04:00
522ed3c21d theme: whitespace typo 2014-06-25 17:00:10 +02:00
2fb8781f30 Bump version to 3.13.3
Update NEWS.
2014-06-24 23:54:06 +02:00
2bda6db30f appDisplay: Fix folder icons for RTL locales
Unlike StTable, ClutterTableLayout does not take the actor's text
direction into account, so mirror columns ourselves now.

https://bugzilla.gnome.org/show_bug.cgi?id=731923
2014-06-24 23:37:35 +02:00
8abd18363c networkAgent: Fix layout for RTL locales
Unlike StTable, ClutterTableLayout does not take the actor's text
direction into account, so mirror columns ourselves now.

https://bugzilla.gnome.org/show_bug.cgi?id=731923
2014-06-24 23:37:35 +02:00
256bb532a2 calendar: Fix events for RTL locales
Unlike StTable, ClutterTableLayout does not take the actor's text
direction into account, so mirror columns ourselves now.

https://bugzilla.gnome.org/show_bug.cgi?id=731923
2014-06-24 23:37:34 +02:00
6077e28f95 calendar: Fix for RTL locales
Unlike StTable, ClutterTableLayout does not take the actor's text
direction into account, so mirror columns ourselves now.

https://bugzilla.gnome.org/show_bug.cgi?id=731923
2014-06-24 23:37:34 +02:00
83cb26d70e js: Adapt to GSettings API change
The 'schema' property has been deprecated for a long time. Even though
this will likely be reverted in glib, let's stop using it.
2014-06-24 15:17:09 -04:00
6d66afc14e popupMenu: Fix last commit
A missing git commit --amend meant we weren't showing the right icon.
2014-06-24 14:37:08 -04:00
88faee4c79 popupMenu: Use the standard arrow icons popup menu arrows
Rather than our own theme asset.
2014-06-24 14:25:14 -04:00
66f5e4b44d Revert "plugin: Don't query for swap_events support directly"
This reverts commit e23c2ffecc.

The patch was intended as a cleanup but accidently removed the setting of the
event base, breaking the swap event handling.

With the event base setting removing the other code isn't much of a cleanup so
just revert it.
2014-06-24 17:37:23 +02:00
772d8692e7 DBus: Remove flash argument
There is no flash argument implemented.
2014-06-23 17:17:12 +02:00
17f481f6fe shell-recorder: send EOS to the pipeline
Send EOS to the complete pipeline instead of only to our own source.

When there are multiple sources in the pipeline (for example when we also
record audio), the pipeline will send the EOS to all sources in order to
shut down the complete pipeline.
2014-06-23 17:16:55 +02:00
b057e786a4 shell-recorder: depth and bpp are no more in 1.0
Remove 0.10 style bpp and depth, they are not needed anymore, the
format specifies the layout completely.
2014-06-23 17:15:44 +02:00
8b9904b6d0 shell-recorder-src: allow sending EOS to our source
When we send EOS to our source, make it queue the special item to cause
EOS after all buffers are pushed.
2014-06-23 17:15:44 +02:00
43ae3b8140 shell-recorder-src: use timestamping from basesrc
Use the do-timestamp feature of basesrc to place the correct timestamp
on each outgoing buffer.
2014-06-23 17:15:44 +02:00
f76dd4d6b2 shell-recorder-src: only negotiate once
Set the format of the basesrc to the configured caps only once
during negotiation instead of before pushing each buffer.
2014-06-23 17:15:44 +02:00
079cc39166 Updated Lithuanian translation 2014-06-22 15:56:38 +03:00
bf0c7f731d a11y: initialize atspi on demand
Only call atspi.init if needed. This is also more
coherent with the listener registration, that is
only done when needed.

https://bugzilla.gnome.org/show_bug.cgi?id=730118
2014-06-20 14:32:55 +02:00
5a8a293614 location: Update available accuracy on max accuracy changing
We translate 'On' to available accuracy level but if available accuracy
level later changes, we don't update available accuracy level accordingly
and hence limit the accuracy of apps.

E.g if available accuracy level is 'city' and geolocation is enabled,
the max accuracy level would be 'city' and apps can't get higher than
that. Now if user plugs in GPS, the available accuracy level will change
to 'exact' but without this patch max accuracy level will remain to be
'city' and apps will not be able to use the GPS.

https://bugzilla.gnome.org/show_bug.cgi?id=731882
2014-06-20 12:26:27 +01:00
c768ee6175 Updated Swedish translation 2014-06-19 18:03:57 +00:00
75c2a723d9 IconGrid: calculate icon size only once 2014-06-18 00:04:34 +02:00
32240df141 IconGrid: Don't check twice for min icon size 2014-06-17 22:33:51 +02:00
c532e3f1a5 Updated Turkish translation 2014-06-17 19:37:41 +00:00
b04c79643d screenshot: Scale and unscale the area for HiDpi displays
https://bugzilla.gnome.org/show_bug.cgi?id=731738
2014-06-17 21:22:35 +02:00
4eca992db8 Updated Spanish translation 2014-06-17 19:21:30 +02:00
c36ca625e6 workspace: Adapt to mutter API change 2014-06-17 11:12:15 -04:00
238466b3d6 Updated Slovenian translation 2014-06-16 22:11:02 +02:00
4f28840a59 dateMenu: Fix style 2014-06-16 15:10:36 -04:00
d98c1ba522 Fix Meta.KeyBindingFlags.IS_REVERSED typo
The code currently tries to use Meta.KeyBindingFlags.REVERSED. Since
this constant is |'ed with Meta.KeyBindingFlags.REVERSES, gjs silently
ignores the unknown flag.

https://bugzilla.gnome.org/show_bug.cgi?id=731619
2014-06-16 12:57:10 +02:00
9bbb3e9c85 appDisplay: Fix app folder "modal-ness"
Commit 5d00c1a5ee moved app folder popups to GrabHelper - for some
reason, the line that ensures the current behavior of only considering
events inside the app picker to dismiss popups got lost ...
2014-06-16 10:28:59 +02:00
2710c56827 Updated Hebrew translation 2014-06-14 22:11:29 +03:00
e22ff0e42d Mark all gsettings schema entries as translatable
Some entries have untranslatable descriptions/summaries. This means that
when running dconf-editor, some entries will get a translated descriptions,
and a few will not.

https://bugzilla.gnome.org/show_bug.cgi?id=728170
2014-06-13 13:14:50 +02:00
8c74a4fee0 messageTray: Remove an unused variable 2014-06-12 13:58:13 -04:00
234b90ac86 messageTray: Don't use a member variable when we can use a local
Tiny cleanup.
2014-06-12 13:31:39 -04:00
ce46b06f36 Updated Spanish translation 2014-06-12 17:52:25 +02:00
585930123d layout: Do not expand struts to screen edges
set_builtin_struts() in mutter now handles this for us, so we can kill
off the extra code here.

https://bugzilla.gnome.org/show_bug.cgi?id=730527
2014-06-12 15:36:40 +02:00
5d00c1a5ee appDisplay: Use GrabHelper for folder popups
As clicks outside the app picker should still be handled normally
while clicks inside should dismiss the popup, we cannot make full
use of GrabHelper. However using it at least for focus handling
fixes some minor details we are getting wrong, for instance not
restoring the previous focus after dismissing a folder popup.
2014-06-11 23:24:30 +02:00
f288c43e6e viewSelector: Use clutter constant instead of true 2014-06-10 21:22:51 +02:00
b981a591c7 main: Actually use the correct schema for overrides
Fix commit ae2751a68b to not only pick up the keys from the
correct schema, but also use the correct schema-id for the overrides.
2014-06-10 13:00:57 +02:00
3b7756b610 data: Do not convert 'button-layout' setting
It has been removed from our overrides schema ...
2014-06-10 12:32:28 +02:00
292f87caf7 sessionMode: Don't set overridesSchema
Unused since commit ae2751a68b.
2014-06-09 22:39:15 +02:00
ae2751a68b main: Move pref overrides back into C
Commit 6c2f3d1d17 moved pref overrides into JS to implement
session mode specific overrides in a clean and generic way.
However that approach comes with a cost - doing the overrides only
after having handled over control to JS means that the core will
be initialized with the non-overridden settings before changing
to the correct values. In the best case this is unnecessary work,
but it can in fact have a worse effect: when initializing workspaces,
we will restore the previous number of workspaces when using
dynamic-workspaces and reset to the configured number otherwise.
As the non-overridden default for dynamic-workspaces is FALSE, we
can easily end up moving the user's windows to the "wrong" workspace.

Now GSettings is expected to grow support for session specific defaults,
which will render our entire override system obsolete (yay!). Given
that, it seems acceptable to use a less generic (and uglier) approach
in the meanwhile, in order to fix aforementioned problems. So move
overrides back before core initialization and just hardcode the
session-mode => override-schema relation.

https://bugzilla.gnome.org/show_bug.cgi?id=695487
2014-06-09 21:52:03 +02:00
589becbc79 panelMenu: Clean up code a bit 2014-06-08 22:25:27 +02:00
4c7fcf272c Updated Turkish translation 2014-06-05 23:34:50 +00:00
e51aecee03 Updated Hungarian translation 2014-06-05 11:23:27 +00:00
d98e7dbd4a screenshot: Also validate parameters to FlashArea()
Apply the same parameter validation to FlashArea() we already use
for ScreenshotArea().

https://bugzilla.gnome.org/show_bug.cgi?id=731220
2014-06-04 18:12:31 +02:00
1b97778925 Updated Norwegian bokmål translation from Åka Sikrom. 2014-06-03 19:55:46 +02:00
829e7623df css: Clean up slightly
Remove the networking stuff from the message tray section.
2014-06-03 12:32:56 -04:00
89675c9061 Updated Brazilian Portuguese translation 2014-06-03 13:29:01 +00:00
f9df83802d ui: Adapt to display.get_tab_list API change 2014-06-03 14:52:18 +02:00
e51eb723fc windowMenu: Do a better job with faking the source actor
The 0x0 dummyCursor works well when the menu pops up directly underneath
the pointer (e.g. when triggered by right-clicking the titlebar) or by
keyboard, but not when triggered by the menu button - the menu does not
point to the center of the button's bottom edge, and unless the user
keeps holding the mouse button while moving into the menu, the menu will
be dismissed immediately on button release.
Address these issues by using the button geometry to overlay the window
button with an appropriately sized actor that acts as a proper sourceActor,
to make the window menu behavior consistent with other shell menus.

https://bugzilla.gnome.org/show_bug.cgi?id=731058
2014-06-02 23:48:53 +02:00
5b61f2d642 windowMenu: Implement new show_menu_for_rect() hook
Having the full geometry of the menu's source button (if any) will
allow us to address several misbehaviors of window menus, so use
that instead of show_menu().

https://bugzilla.gnome.org/show_bug.cgi?id=731058
2014-06-02 23:48:53 +02:00
094669baee messageTray: Clear the pointer left timeout when showing a notification
When the pointer leaves the notification area, we queue a timeout to
hide the notification after a little while. If the user is hovering over
a notification and clicks the X button to close the notification, we will
destroy the notification, which causes a "pointer left" event on the
notification area. This queues a timeout which erroneously fires after
the next notification in the queue shows up.

The code and state machine are too complex to properly make sure this
timeout doesn't fire when there is no notification up next, so instead
just clear it when showing a notification to make sure that any
previously queued timeout doesn't apply to us.

https://bugzilla.gnome.org/show_bug.cgi?id=731118
2014-06-02 17:39:52 -04:00
f6b5385495 messageTray: Squash together some duplicated code
https://bugzilla.gnome.org/show_bug.cgi?id=731118
2014-06-02 17:39:51 -04:00
524e2df708 messageTray: Don't exit out early if we have a left timeout
Otherwise, we won't mark the pointer as hovering on the notification.

https://bugzilla.gnome.org/show_bug.cgi?id=731118
2014-06-02 17:39:51 -04:00
9f887d9a28 Updated Lithuanian translation 2014-06-02 23:35:53 +03:00
214a41793f build: Remove GMenu include
The actual GMenu dependency was removed a while ago, so stop adding
it to the GIR includes.
2014-06-02 17:56:38 +02:00
2e40ffc558 Updated Italian translation 2014-05-31 12:55:41 +00:00
3584887938 openbsd: fix shell_global_reexec_self()
Rework the way we re-exec the shell on OpenBSD so that it does not only
work the first time it is re-exec'd.
Plug a small leak in the __linux__ case while here.

https://bugzilla.gnome.org/show_bug.cgi?id=727763
2014-05-30 11:26:39 +02:00
0d6c002b8e calendar: Port EventsList to ClutterTableLayout
We don't make use of any functionality StTable provides over
ClutterTableLayout, so port all users to the Clutter layout
in order to remove our own copy of the code.

https://bugzilla.gnome.org/show_bug.cgi?id=703833
2014-05-28 22:11:38 +02:00
ec714864f2 calendar: Port calendar to ClutterTableLayout
We don't make use of any functionality StTable provides over
ClutterTableLayout, so port all users to the Clutter layout
in order to remove our own copy of the code.

https://bugzilla.gnome.org/show_bug.cgi?id=703833
2014-05-28 22:11:38 +02:00
1b77149ec9 build: Remove ShellNetworkAgent documentation
It is only an internal implementation detail, and it also causes build problem
when NetworkManager is disabled.

https://bugzilla.gnome.org/show_bug.cgi?id=726460
2014-05-28 22:07:19 +02:00
93c9e031e3 Update (allow-none) annotations
The annotation has been deprecated in favor of (nullable) and/or
(optional).
2014-05-28 22:01:55 +02:00
3ff4277f86 workspace: Don't allow closing windows with attached modals
Modal dialogs prevent the parent from being closed in "normal mode",
so it makes sense to not allow it in the overview either.

https://bugzilla.gnome.org/show_bug.cgi?id=729886
2014-05-28 22:01:54 +02:00
2a63267be0 loginDialog: Remove unused variable 2014-05-28 22:01:54 +02:00
2b365627ed windowManager: Remove (un)blockAnimations()
They are no longer used, kill them.
2014-05-28 22:01:53 +02:00
b8f0d0f0dc telepathyClient: Only use 12-hour format when supported by the locale
It is a bit odd to request AM/PM format when the locale selected
by LC_TIME lacks the concept. We ignore the format setting in that
case elsewhere and assume 24-hour format, let's do the same for
chat timestamps for consistency.

https://bugzilla.gnome.org/show_bug.cgi?id=728271
2014-05-28 22:01:53 +02:00
df1bed941d telepathyClient: Remove unused variable 2014-05-28 13:09:43 -04:00
604085fdb9 Update British English translation 2014-05-27 21:44:13 +01:00
2d3c81390b Bump version to 3.13.2
Update NEWS.
2014-05-27 21:35:37 +02:00
516b8f6bf8 screenshot: Don't use meta_window_get_rect
It's going to be removed soon.
2014-05-27 15:14:33 -04:00
75fdca0b47 data: Drop button-layout from overrides schema
The default in gsettings-desktop-schemas now matches what we want,
so no need to keep overriding it.
2014-05-27 19:54:31 +02:00
9f366118f0 windowMenu: Only add workspace actions when enabled by session mode
When workspaces are disabled by the session mode, all workspace
related actions don't make sense. Worse, the "Move to Workspace ..."
actions allow sending windows into a nirvana with no means to
get them back.

https://bugzilla.gnome.org/show_bug.cgi?id=730653
2014-05-27 19:49:06 +02:00
c228a9a89a viewSelector: Don't re-navigate into the active page
Starting keynav into the active page is handled from a key-press
handler on the stage, however we should not "start" keynav when
we are already navigating elsewhere - the latter can happen when
keynav fails (for instance because the focus is trapped inside an
open app folder or at the end of the dash), and the event bubbles
up to the stage. So make sure to only handle the event to actually
start keynav, to not interfere with the normal navigation handling.

Thanks to Carlos Soriano <carlos.soriano89@gmail.com> for the
debugging footwork.

https://bugzilla.gnome.org/show_bug.cgi?id=726760
2014-05-27 19:49:06 +02:00
e747fcb16f windowMenu: Ping window when activating any menu action
We do this for actions in the regular app menu, it makes sense to
do the same for window menu and fallback app menu.
2014-05-27 19:49:05 +02:00
a72a24ebff theme: Bring fallback app-menu style closer to GTK+
The fallback app-menu in GTK+'s client side decorations obviously
uses the GTK+ theme rather than the shell one; update the style
of our own fallback app-menu to resemble that style.

https://bugzilla.gnome.org/show_bug.cgi?id=730752
2014-05-27 19:49:05 +02:00
8811ba2ec0 Support (fallback) app menu in SSD
We now allow "appmenu" in the button layout to make synchronizing it
with GTK+'s client-side decorations easier, but as some people tweak
their settings to get in-window app menus even when using the shell,
actually pop up the app menu when the button is activated.

https://bugzilla.gnome.org/show_bug.cgi?id=730752
2014-05-27 19:49:05 +02:00
38d8e465b3 popupMenu: Hide separator label when not in use
The optional label support introduced in commit af063dc2f2 broke
the centering of separators, as the label still adds additional
spacing even when empty.
Properly hide the label actor in that case to fix the alignment.

https://bugzilla.gnome.org/show_bug.cgi?id=730753
2014-05-27 19:49:04 +02:00
5b3fb024be extensionPrefs: Skip main window when launched with a UUID
The extension-prefs tool is used by gnome-tweak-tool and the
extensions web site to display preferences. However as those
already implement their own extension lists, the main window
is not useful in that context (to not say it is rather silly).

Just skip the main window and only show the specified extension's
preference dialog in those cases.

https://bugzilla.gnome.org/show_bug.cgi?id=730829
2014-05-27 18:02:25 +02:00
521f5f2b6b extensionPrefs: Add switches to enable/disable extensions
Bring the extension-prefs tool in line with the mockup by adding
switches to enable/disable extensions, similar to the extension
page in gnome-tweak-tool.

https://bugzilla.gnome.org/show_bug.cgi?id=730829
2014-05-27 18:02:25 +02:00
e1b30b2924 extension-prefs: Give the UI a bit of GNOME 3 treatment
The extension-prefs UI has never been great, but as the GNOME 3
design patterns are evolving, it is starting to look seriously
outdated. Modernize the UI a bit to have it fit in a bit better.

https://bugzilla.gnome.org/show_bug.cgi?id=730829
2014-05-27 18:02:25 +02:00
dd85670f8b switcherPopup: Add a return value to _keyPressHandler
This allows us to handle keybindings that use Escape instead of just
dismissing the popup unconditionally when we see an Escape press.

https://bugzilla.gnome.org/show_bug.cgi?id=730739
2014-05-26 15:55:37 +02:00
625f3a5113 tools/build: Update to 3.14 2014-05-25 23:22:18 +02:00
58c4a6c847 Updated Hebrew translation 2014-05-22 23:46:51 +03:00
752aca811c windowManager: Support coords 2014-05-22 10:51:49 -04:00
a4cf0501ee Updated Indonesian translation 2014-05-22 09:22:25 +00:00
4c7b992c36 windowMenu: Fix typo
Closing windows is done with delete(), not close() ...
2014-05-21 19:57:17 +02:00
264a51de3f gnome-shell-wayland.desktop: Drop mutter-launch from Exec line
mutter-launch has been replaced with logind's Session and Seat APIs.
2014-05-21 11:11:27 +02:00
625280bcd6 Updated Brazilian Portuguese translation 2014-05-20 19:36:14 +00:00
4f8265f82e Updated Spanish translation 2014-05-20 20:05:06 +02:00
ff07d3a46a Renable compiler warnings and fix a few that show up
The switch to GNOME_COMPILE_WARNINGS() caused -Wall and other
warnings to not actually be used since GNOME_COMPILE_WARNINGS()
just sets WARN_CFLAGS. Add WARN_CFLAGS to AM_CFLAGS so that
it takes effect.

Add  -Wno-error=deprecated-declarations so that when -Werror is
enabled, we don't fail on all the deprecated cogl and clutter
symbols.

https://bugzilla.gnome.org/show_bug.cgi?id=730408
2014-05-19 20:51:12 -04:00
5d11941638 Support resource:/// URL's in GNOME_SHELL_JS envvar
It can be useful to augment the shell's search path by doing

 GNOME_SHELL_JS=resource:///org/gnome/shell:<mypath>

But this doesn't work because resource: is split off. Special
case path elements that are just 'resource' and recombine
them with the next element.

https://bugzilla.gnome.org/show_bug.cgi?id=730409
2014-05-19 20:47:05 -04:00
f1f659571b Updated Turkish translation 2014-05-19 11:46:28 +00:00
c60d13b33e Updated Lithuanian translation 2014-05-18 22:25:40 +03:00
33060d382b Updated Czech translation 2014-05-18 15:40:01 +02:00
4b1e412ac3 Updated Hebrew translation 2014-05-18 02:48:02 +03:00
659730ab09 Mark string as translatable 2014-05-18 01:08:49 +02:00
7c3a99b7ed Updated POTFILES.in 2014-05-18 01:02:36 +02:00
e7af257814 Implement window menus in gnome-shell
https://bugzilla.gnome.org/show_bug.cgi?id=726352
2014-05-17 15:17:29 -04:00
c9190294bc gnome-shell-build-setup.sh: work around removal of gpk-install-package-name
gpk-install-package-name was removed in 3.12. Call the D-Bus interface
using gdbus instead.
2014-05-17 15:10:04 -04:00
e070e3c44a Updated Czech translation 2014-05-16 14:37:15 +02:00
fe87de7cec Updated Hebrew translation 2014-05-16 04:20:15 +03:00
2519e4f08d Updated Brazilian Portuguese translation 2014-05-15 18:28:01 +00:00
fe304d3c94 Updated Lithuanian translation 2014-05-11 23:43:13 +03:00
1f4e6872ab Updated Spanish translation 2014-05-10 19:48:56 +02:00
5ade2e7418 main: emit systemd message for any session except gdm and initial-setup 2014-05-09 23:35:57 +02:00
3e7d325e77 [l10n] Updated Catalan (Valencian) translation 2014-05-09 00:02:51 +02:00
ef04a9d1ed osdWindow: Check monitor validity before updating
When a monitor is removed, the OsdWindow for that monitor may process
the monitors-changed signal before OsdWindowManager does (which will
remove the OSD). If that happens, we will currently try to access
an invalid monitor; check for this to avoid a couple of warning.
2014-05-08 11:14:23 +02:00
011fef4b2b system: Keep key focus when switching between alternatives
When switching between alternatives in AltSwitcher, the currently
visible child is replaced with the alternative. If the original
child has the key focus when it is removed from the stage, the
focus is lost. Detect this case and manually move the focus to
the new child.

https://bugzilla.gnome.org/show_bug.cgi?id=727259
2014-05-06 14:25:39 +02:00
caf6389f79 Fix Italian translation
- "Aereo" is the thing that flies, "Aero" is the Windows 7 theme.
- "Abilita", not "Abilitato", for the Enable action.
2014-05-04 15:22:55 +02:00
c7306449ae workspaceThumbnails: Move to primary monitor first when creating workspace
When dragging a window preview from a non-primary monitor onto a
workspace thumbnail, the window is moved to the primery monitor
first before changing its workspace. However when dragging the window
between thumbnails to create a new workspace, it is kept on its current
monitor instead. This is not only inconsistent, but outright confusing
with the default 'workspaces-only-on-primary' setting, as the newly
created workspace is immediately removed again.

https://bugzilla.gnome.org/show_bug.cgi?id=683819
2014-05-03 23:50:25 +02:00
8c45e6fa43 main: Don't depend on GSystem unconditionally
We only need GSystem when running under systemd. As libgsystem itself
has a hard dependency on systemd, only import it when actually needed
to keep working on systems where systemd is not available.

https://bugzilla.gnome.org/show_bug.cgi?id=728449
2014-05-03 23:50:25 +02:00
9504d21297 Updated Belarusian translation.
(cherry picked from commit 6d679148b6)
2014-05-03 14:46:57 +02:00
0832ca544a Update the default favourite apps list for renamed desktop files
Nautilus and gnome-documents have changed their desktop file names to
support DBus activation.

https://bugzilla.gnome.org/show_bug.cgi?id=729429
2014-05-03 00:01:56 +02:00
a000a1f76e rfkill: make the Airplane mode menu insensitive in the lock screen
Like we do for the bluetooth and wifi menus

https://bugzilla.gnome.org/show_bug.cgi?id=729224
2014-04-30 21:52:56 +02:00
ea8b02ff7f Bump version to 3.13.1
Update NEWS.
2014-04-30 19:15:12 +02:00
3cc7112283 Add a 'Show Details' menuitem in the app picker
Add a menu item that shows the details of the application
in gnome-software.

https://bugzilla.gnome.org/show_bug.cgi?id=643043
2014-04-30 19:15:06 +02:00
50f0fc4e23 overviewControls: Adjust heuristic for hiding workspace switcher
The workspace switcher should be expanded when workspaces are in use.
Our current implementation assumes that workspaces are used when there
are windows on at least two workspaces. However workspaces are already
used when moving from a non-empty workspace to an empty one (presumably
with the intention to launch something on that workspace), so tweak the
heuristic accordingly.

https://bugzilla.gnome.org/show_bug.cgi?id=662457
2014-04-30 18:06:52 +02:00
0a4ad01d8a Updated Galician translations 2014-04-30 15:34:42 +02:00
19afabe2a1 dateMenu: Don't make dateMenuButton reactive on current day
Having the ability to go to the current date if the user is already
on the current date can be confusing. So don't make the button reactive
until the selected date changes.

https://bugzilla.gnome.org/show_bug.cgi?id=726724
2014-04-29 01:02:27 +02:00
103027a446 St: remove hover state if reactive disabled
The hover state of a widget can become persistent if
the widget becomes reactive while a pointer grab.
To avoid that, remove hover state if the reactive property
is disabled.

https://bugzilla.gnome.org/show_bug.cgi?id=728343
2014-04-29 01:02:27 +02:00
28c1f81f4a appDisplay: Make page panning smoother on touch
Currently, our logic for page panning isn't great. If the user starts a
pan upwards and hesitates over a new page, we'll go to the *next* page
on release, since the difference is greater, but the velocity wound down
to 0.

Instead of trying to treat it like page down or scrolls, simply do the
math to find the page where the user scrolled to.

This is unfortunately broken for fast swipes, since the user doesn't get
far enough into the new page to make a difference. I'm getting the
impression we'll need a gesture recognizer for this, though, however
crude. Simple hacks I tried, like a velocity multiplier, didn't work
properly.

https://bugzilla.gnome.org/show_bug.cgi?id=729064
2014-04-28 13:30:09 -04:00
82ec6c08b8 appDisplay: Fix pages getting "stuck" under touch
We often call goToPage like:

  this.goToPage(this._currentPage - 1);

(or + 1). During panning, these are based on the velocity values
of the gesture action. If we're already on the first or last page
and the panning ends, it's possible to get goToPage that's either
-1 or greater than the last page.

During normal usage, this isn't a problem, since the Y values will
be correct, always. But when panning, the Y values stick to the
finger, and thus if we return early, we won't snap to the exact page,
making it seem like things get "stuck".

Fix this the simple way by clamping to the correctly-ranged values
of pageNumber

https://bugzilla.gnome.org/show_bug.cgi?id=729064
2014-04-28 13:30:09 -04:00
551e57406d appDisplay: Remove redundant checks for pageNumber
We already do these at the beginning of the function.

https://bugzilla.gnome.org/show_bug.cgi?id=729064
2014-04-28 13:30:08 -04:00
1c8036b863 If systemd is enabled send a message with MESSAGE_ID after gnome-shell has started in user mode
Also adds a new dependency - libgsystem
https://bugzilla.gnome.org/show_bug.cgi?id=728449
2014-04-28 18:49:44 +02:00
f8bac5c197 util: Don't pass too many arguments to child_watch_add 2014-04-28 10:22:51 -04:00
6ece67b654 calendar: Don't mark translations from GTK+ for translation
The order in which month and year are displayed is controlled by
a "special" translated string in GTK+. We pick up the translation
from there, so make sure that it doesn't get translated again
in gnome-shell.

https://bugzilla.gnome.org/show_bug.cgi?id=715042
2014-04-27 02:06:27 +02:00
96411dfed5 Updated Brazilian Portuguese translation 2014-04-26 22:14:01 +00:00
24897169a9 st-entry: Handle <shift>insert
GTK+ supports this as alternative to <ctrl>v, so let's do the same
for consistency.

https://bugzilla.gnome.org/show_bug.cgi?id=648318
2014-04-26 21:19:59 +02:00
05ddece9a0 workspaceThumbnails: Fix removal of multiple workspaces
When workspaces have been removed, we need to remove the corresponding
thumbnails as well; the number of thumbnails that need removing is
the difference between the old number of workspaces and the new one.
Currently we assume that the old number of workspaces corresponds to
the number of existing thumbnails, but that may actually be wrong:
A thumbnail will still be animated out after its workspace has been
removed. As a result, we end up removing too many thumbnails when a
workspace is removed while a thumbnail of a previously removed workspace
is still animating out. Fix this by basing the old number of workspaces
only on thumbnails that have not been removed previously.

https://bugzilla.gnome.org/show_bug.cgi?id=728820
2014-04-26 17:50:38 +02:00
df08ae7996 screenshot: Port to GrabHelper
Taking an area screenshot doesn't work currently when in "grab mode",
for instance when the message tray or top bar menus are open. Fix
this by using GrabHelper for selecting the area, so grabs are properly
stacked for us.

https://bugzilla.gnome.org/show_bug.cgi?id=709126
2014-04-26 16:19:21 +02:00
a244c1e987 loginManager: Kill ConsoleKit support
The code path is completely unmaintained and untested (and probably
unused as well, considering that nobody has complained about accessing
the session object's Active property which does not exist in the
ConsoleKit case).
Most of our ConsoleKit code is already a dummy anyway, just do the
same for the remaining functionality.

https://bugzilla.gnome.org/show_bug.cgi?id=686626
2014-04-25 15:53:45 +02:00
bc182f78b1 style: Clean out unused selectors 2014-04-25 15:51:43 +02:00
2d18b06b3f osdWindow: Fix setting a zero-level in osdWindow
Commit 7101cc3170 caused a small
regression insomuch that it checks for a valid "level" but simply using
"if (level)" which will be false if level is undefined and if
level == 0.

Check for not undefined instead.

https://bugzilla.gnome.org/show_bug.cgi?id=727384
2014-04-25 15:20:18 +02:00
61852df9a1 Tajik translation updated 2014-04-25 17:16:49 +05:00
3969be38bd environment: Be more careful when hooking up style properties
Sometimes it is more appropriate to set layout properties that are
hooked up to CSS properties in code. However this is currently not
possible, as we end up setting properties to 0 when not found in CSS;
be a bit more careful when hooking up CSS properties to support this.

https://bugzilla.gnome.org/show_bug.cgi?id=728897
2014-04-24 19:31:55 +02:00
92f9aff784 tests/gapplication: Don't pass too many args to gtk_init 2014-04-23 16:49:44 -04:00
815cfe6c20 Updated Romanian Translation 2014-04-23 21:46:14 +02:00
052b5176d2 Updated Czech translation 2014-04-23 17:05:29 +02:00
bccbcd8e4a networkAgent: Handle empty vpn 'keyfiles'
Passing back no data is valid in case both secrets (group and user passwords)
are stored.

Just confirm the request in that case.

https://bugzilla.gnome.org/show_bug.cgi?id=728681
2014-04-23 13:09:34 +02:00
90589fabee texture-cache: Fix compile warning 2014-04-22 18:35:56 -04:00
5947111f14 Updated Ukrainian translation 2014-04-22 23:07:18 +03:00
c8c56a5443 Updated Khmer translation 2014-04-22 08:46:49 +00:00
a83b9ed6d7 search: Make sure to destroy old provider displays when we unregister
When we unregistered providers, like when we refreshed the list of
active remote providers, we would forget to destroy the old provider
display after the fact. This left an empty "skeleton" provider display
still in the search results that would never be filled in. Make sure
to destroy it properly.

https://bugzilla.gnome.org/show_bug.cgi?id=728597
2014-04-21 23:36:52 -04:00
f9c83bccb6 status: use consistent messages for network connections
https://bugzilla.gnome.org/show_bug.cgi?id=727163
2014-04-21 22:03:22 +02:00
2f720e22fc rfkill: fix turning off airplane mode from the menu
The menu does not have a proxy anymore, it needs to go through
the manager.

https://bugzilla.gnome.org/show_bug.cgi?id=728512
2014-04-21 19:10:54 +02:00
329028d3b9 Updated Dutch translation 2014-04-18 20:16:51 +02:00
5c3f9f6999 osdWindow: Show on all monitors
We had one osdWindow that we displayed either on the primary monitor or on
whatever monitor index got passed over dbus.

Change that to show the osd on all monitors when no explicit monitor is
requested. A monitor should be requested in cases like display brightness where it makes sense to only show the osd on the affected monitor.

https://bugzilla.gnome.org/show_bug.cgi?id=722684
2014-04-17 15:15:14 +02:00
4a6b89d44c windowManager: add switch-to-workspace-last keybinding
When using dynamic workspace, the number of the last workspace may vary,
and it would be nice to have a keybinding to jump directly to it.

https://bugzilla.gnome.org/show_bug.cgi?id=659288
2014-04-16 21:45:14 +02:00
7fa1834ab6 extension-prefs: Remove extra whitespace 2014-04-15 17:54:51 -04:00
c7bc9f8925 extension-prefs: Kill warning
We need to include shell-js.h
2014-04-15 17:54:51 -04:00
70d75ca311 loginManager: Don't pass too many args to steal_fds 2014-04-15 17:53:37 -04:00
9830b3b8f7 appDisplay: Don't pass too many args to add_actor 2014-04-15 17:53:34 -04:00
525c8780fd Fix typo 2014-04-15 23:35:06 +02:00
76c4ec8ee4 layout: Don't always extend struts to the screen edge
NetWM struts are defined in terms of screen edges (rather than monitor
edges), which works poorly with vertical monitor layouts (as it renders
entire monitors unusable). Don't extend struts in those cases.

https://bugzilla.gnome.org/show_bug.cgi?id=663690
2014-04-15 23:35:06 +02:00
b4a48a7644 extension-prefs: Force linking with libgnome-shell-js
Use the same hack we use for the main executable to fool the linker
when using --as-needed.

https://bugzilla.gnome.org/show_bug.cgi?id=727948
2014-04-15 23:35:05 +02:00
5087f0930c l10n: Update Japanese translation 2014-04-15 00:36:54 +09:00
398cc5af85 Updated Danish translation 2014-04-13 21:53:58 +02:00
f073945d31 Updated Hungarian translation 2014-04-13 15:42:18 +02:00
c36abcb905 Updated Latvian translation 2014-04-12 12:35:33 +03:00
e2ccbe5528 layout: Change setDummyCursorPosition to also set the size
If we are being used to follow a text entry cursor we also need to set
the size so that the popup menu avoids covering it.

https://bugzilla.gnome.org/show_bug.cgi?id=727579
2014-04-11 16:54:01 +02:00
68b2d5fcf0 LookingGlass: Correct timeout usage
Calling Mainloop.source_remove() on the timeout ID will not reset it,
and we're already removing the timeout by returning GLib.SOURCE_REMOVE
in the callback.
2014-04-10 21:08:49 +02:00
cd2bd7685a js: Name all the timeouts and idles
With very uninventive names. Names now, good names later.

https://bugzilla.gnome.org/show_bug.cgi?id=727983
2014-04-10 21:08:16 +02:00
85f811f147 src: Name all the timeouts and idles
https://bugzilla.gnome.org/show_bug.cgi?id=727983
2014-04-10 19:38:04 +02:00
e8fd8b58d0 Added Khmer translation 2014-04-10 07:30:29 +00:00
2aa12e8f4b Updated Indonesian translation 2014-04-10 05:48:25 +00:00
ee0c76c2b9 Link to libmutter always
Wayland support was merged into mutter master.
2014-04-09 15:24:09 -07:00
6ce6e77d2a Tajik translation updated 2014-04-09 11:38:37 +05:00
0117fcb0e7 location: Don't hide location menu
If geoclue reports that we can't aquire location, we hide the menu. This
will typically happen when user is offline (and doesn't have a 3G
modem). This is likely not what we want since this like a temporary
situation and user would want the ability to toggle geolocation still
even if its currently not possible any applications to query the
location.

https://bugzilla.gnome.org/show_bug.cgi?id=727398
2014-04-08 14:11:28 +01:00
79bebe849d Updated Portuguese translation 2014-04-07 21:34:08 +00:00
25eadc5559 Updated Italian translation 2014-04-06 12:17:24 +00:00
a5784484e0 doap: update URLs 2014-04-04 19:32:09 +02:00
a701b006c5 Updated Italian translation 2014-04-03 07:08:23 +00:00
2d68bbf94e theme: Fix bad antialising on panel menu buttons
https://bugzilla.gnome.org/show_bug.cgi?id=727336
2014-04-01 19:47:28 +02:00
df305314c1 a11y: setting accessible role and label for windows at the overview
https://bugzilla.gnome.org/show_bug.cgi?id=726670
2014-04-01 13:56:53 +02:00
d03239c009 [l10n] Update Catalan translation 2014-03-31 23:53:35 +02:00
71ccad4399 Updated Galician translations 2014-03-31 23:35:41 +02:00
c916d43688 Updated Slovenian translation 2014-03-31 20:51:33 +02:00
3e6d0bc252 Updated French translation 2014-03-31 16:26:37 +00:00
79d0a848a4 Updated Russian translation 2014-03-31 15:48:54 +00:00
a6af33d450 Updated Lithuanian translation 2014-03-30 23:02:54 +03:00
c6664adcce Updated Swedish translation 2014-03-30 19:05:44 +00:00
4e8a9470d1 Updated Basque language 2014-03-30 12:56:28 +02:00
1b88df9439 update zh_CN translation 2014-03-30 16:57:39 +08:00
ec42278654 Updated German translation 2014-03-29 08:36:27 +01:00
f435f249d0 Updated Korean translation 2014-03-29 16:13:54 +09:00
9c88fec4fc texture-cache: use scale factor for load_uri_async()
https://bugzilla.gnome.org/show_bug.cgi?id=726907
2014-03-28 10:53:01 -07:00
9ecf466ce1 texture-cache: use scale factor to load background and borders
https://bugzilla.gnome.org/show_bug.cgi?id=726907
2014-03-28 10:53:01 -07:00
a22fdea0e3 border-image: add support for scale factor
In a later commit we'll add support for rendering borders and
backgrounds with scale factor.

https://bugzilla.gnome.org/show_bug.cgi?id=726907
2014-03-28 10:53:01 -07:00
90e52d7266 texture-cache: always call gdk_pixbuf_loader_set_size
Just use the regular image size if we don't want to scale it. This is a
refactor in preparation for the next commit.

https://bugzilla.gnome.org/show_bug.cgi?id=726907
2014-03-28 10:53:01 -07:00
74d9b6c2bf texture-cache: use scale factor to load sliced image
We need to use a GdkPixbufLoader instead of the straightforward
gdk_pixbuf_new_from_file(), since we want to load the image already
scaled if possible - e.g. if it's an SVG file.

https://bugzilla.gnome.org/show_bug.cgi?id=726907
2014-03-28 10:53:01 -07:00
b1e9873de5 Updated Spanish translation 2014-03-28 13:44:52 +01:00
6fdc52a64a Updated Indonesian translation 2014-03-28 11:58:53 +00:00
b7d6792de9 Updated Greek translation 2014-03-28 09:34:14 +02:00
c78dc55e65 Updated Czech translation 2014-03-27 22:17:34 +01:00
af74bded14 Updated Brazilian Portuguese translation 2014-03-27 20:53:59 +00:00
e3c9a9c3e4 Updated Hebrew translation 2014-03-27 20:25:06 +02:00
c68eecaf1c Updated Polish translation 2014-03-27 19:23:43 +01:00
b0bdf7f6c3 location: Improved language
* 'Turn On' -> 'Enable'
* 'Turn Off' -> 'Disable'
* 'Off' -> 'Disabled'
* 'On' ->  'In Use' or 'Enabled' depending on whether or not service is
  in use.

https://bugzilla.gnome.org/show_bug.cgi?id=726498
2014-03-27 17:42:11 +00:00
d0f69a72dc appDisplay: Ensure the currently focused icon is viewable
We either scroll or paginate to the correct place when an icon gets
key focus.

https://bugzilla.gnome.org/show_bug.cgi?id=726759
2014-03-26 11:42:34 +01:00
8d8c75d32d iconGrid: Add a key-focus-in signal
This fires whenever a grid's child emits its own key-focus-in signal.

https://bugzilla.gnome.org/show_bug.cgi?id=726759
2014-03-26 11:42:33 +01:00
e339e2658d search: Ensure that the default result is visible in the scroll view
The default result is set to selected when key focus enters the search
entry. We must also scroll the view if needed.

https://bugzilla.gnome.org/show_bug.cgi?id=726759
2014-03-26 11:42:32 +01:00
bc4a75a732 Update Arabic translation 2014-03-26 01:41:24 +02:00
e09e1bc3f5 Specifically ask for Telepathy 0.x
Telepathy 1.0 will not be compatible, and will probably require
source changes. telepathy-glib 0.12 and telepathy-logger 0.2 are
the 0.x ABIs (they were the first stable-branches to have g-i).

Bug: https://bugzilla.gnome.org/show_bug.cgi?id=721704
Reviewed-by: Giovanni Campagna
2014-03-25 17:19:28 +00:00
87c50eb495 Bump version to 3.12.0
Update NEWS.
2014-03-25 16:24:42 +01:00
be291ee4f9 loginScreen: reset greeter when coming back to login screen
When a user logs in to a wayland session, we keep the login screen
running on the X server with the login screen running in a deactivated mode.

This commit makes sure it get reactivated when the user comes back to
the VT (from user switching, logout or just ctrl-alt-f1).

https://bugzilla.gnome.org/show_bug.cgi?id=726989
2014-03-25 10:41:12 -04:00
e634b49859 Updated slovak translation 2014-03-24 23:40:30 +01:00
4dddaefa41 Updated Japanese translation 2014-03-23 23:22:30 +00:00
cda60455f0 Update Danish translation 2014-03-23 23:52:56 +01:00
a42b8870b0 Update Danish translation 2014-03-23 23:36:42 +01:00
daa66a6de6 Updated Danish translation 2014-03-23 23:29:51 +01:00
6c6aed84bc Updated Danish translation 2014-03-23 23:09:56 +01:00
c59314acc1 Updated Serbian translation 2014-03-23 11:12:07 +01:00
dd3cc78be5 French translation change for "Location" 2014-03-22 15:35:49 +01:00
54b0b6eec5 Updated Traditional Chinese translation(Hong Kong and Taiwan) 2014-03-22 20:04:22 +08:00
41654b22b3 Updated Slovenian translation 2014-03-22 10:03:14 +01:00
07cc60d65a Updated Slovenian translation 2014-03-21 21:44:00 +01:00
a7f9dc5114 Updated Telugu translation 2014-03-21 22:04:33 +05:30
b5ae23d544 Updated Arabic translation 2014-03-21 11:07:50 +01:00
75347cb4f7 Updated Arabic translation 2014-03-21 10:53:17 +01:00
03a44b6ec2 Updated Basque language 2014-03-20 22:56:30 +01:00
17d2349c49 Updated Russian translation 2014-03-20 23:00:58 +04:00
4e98c44052 Update Aragonese translation 2014-03-20 19:39:33 +01:00
0bef281d66 Bump version to 3.11.92
Update NEWS.
2014-03-19 22:07:59 +01:00
54af25ec24 Updated Danish translation 2014-03-19 22:04:16 +01:00
86ab02f400 Updated Hungarian translation 2014-03-19 09:47:15 +00:00
ae01cd143f Updated Norwegian bokmål translation. 2014-03-18 22:52:17 +01:00
2974b29f15 layout: Create a group for modal dialogs
This way we can ensure that they're always stacked under the OSK.

https://bugzilla.gnome.org/show_bug.cgi?id=719451
2014-03-18 17:03:39 +01:00
1b78dd662b modalDialog: Remove unused parentActor param
No ModalDialog users set this so let's hardcode it.

https://bugzilla.gnome.org/show_bug.cgi?id=719451
2014-03-18 17:03:38 +01:00
c22264a0ca BluetoothMenu: fix visibility
In addition to BluetoothAirplaneMode, we need to check also
BluetoothHasAirplaneMode, which is indicative of bluetooth rfkill
devices (and by extension bluetooth adapters).
This prevents showing the menu if there is no adapter present.

https://bugzilla.gnome.org/show_bug.cgi?id=725057
2014-03-17 16:45:30 +01:00
48c3e3f534 Tajik translation updated 2014-03-17 12:26:07 +05:00
6ccc134ba6 Updated Greek translation 2014-03-16 22:22:29 +02:00
9aa36d7851 Finnish translation update by Jiri Grönroos 2014-03-16 20:35:48 +02:00
3278f77739 Updated Hebrew translation. 2014-03-16 16:15:10 +02:00
5d24f48e3b Updated Ukrainian translation 2014-03-16 15:57:12 +02:00
573c1c86cc focus-manager: Make C ANSI-compliant 2014-03-15 15:44:40 -04:00
374c5967ba Updated French translation 2014-03-15 15:58:04 +00:00
66b71a36ce app-system: Filter out stale apps from cache
Since rebasing our AppSystem on GLib's facilities, we only ever
append to the id-to-app cache. So if an application is uninstalled,
shell_app_system_lookup_app() will still happily return it if it
was cached previously. For instance if a favorite app is uninstalled,
it keeps lurking in the dash until a restart.
To fix, filter out removed apps from the cache when handling
GAppInfoMonitor::installed-changed.

https://bugzilla.gnome.org/show_bug.cgi?id=726414
2014-03-15 15:56:30 +01:00
e70fd5a57a location: Make insensitive when locked
Most system menu entries are disabled on the lock/login screen,
there is no good reason for the location entry to be an exception.

https://bugzilla.gnome.org/show_bug.cgi?id=726319
2014-03-15 14:19:02 +01:00
4589ce4d78 bluetooth: Make insensitive when locked
Most system menu entries are disabled on the lock/login screen;
there is no good reason why users should be allowed to turn bluetooth
on/off (but not e.g. Wifi), so disable the entry as well.

https://bugzilla.gnome.org/show_bug.cgi?id=726319
2014-03-15 14:19:01 +01:00
d6197b0904 background: Destroy redundant backgrounds right after loading
When reacting to background settings changes, we may end up queuing
more than one load. The redundant backgrounds are expected to be
destroyed when the previous background has faded out; however since
commit 933f38390b, the tweened actor is the same for all
consecutive load operations and we end up with a single onComplete
handler, ergo a single destroyed actor.
As new backgrounds are always added to the bottom, we are not only
piling up additional background actors, but break changing backgrounds
more than once, as the correct background ends up being covered by
previously added redundant actors.
Fix this by destroying redundant actors right after loading rather
than waiting for the fade animation to complete.

https://bugzilla.gnome.org/show_bug.cgi?id=726120
2014-03-15 00:43:15 +01:00
30fb2b0d99 appDisplay: Improve icons of folders with few apps
Folders use a 2x2 grid of the first 4 app icons as icon - if a folder
contains less apps, we currently skip the corresponding grid positions.
As a result, the overall size request may be smaller than the one for
other icons, making the folder icon look out of place.
Fix this by always using a full grid as folder icon, using dummy actors
as necessary.

https://bugzilla.gnome.org/show_bug.cgi?id=726322
2014-03-15 00:23:50 +01:00
5cdefc324d ScreenShield: wake up the screen when resuming from suspend
At some point ScreenShield had code to do this, I don't know when
it was lost, but it makes sense and avoids having to move the mouse
just to see the shield.

https://bugzilla.gnome.org/show_bug.cgi?id=726378
2014-03-14 23:27:20 +01:00
b222d0fe44 appDisplay: Add some spacing in folder icons
With the switch to a table layout in commit f959cafb36, setting
alignments to place the individual icons at the outer edge of the grid
stopped working. Remove that code and add some explicit spacing instead.

https://bugzilla.gnome.org/show_bug.cgi?id=726323
2014-03-14 17:21:57 +01:00
fe4fddf0d5 gnome-shell-wayland.desktop: Add --display-server
This is now required by mutter to run as a native wayland compositor.
2014-03-14 16:53:59 +01:00
c675c93733 messageTray: Set the state to SHOWN when the notification is updated
If the notification is updated while SHOWING, we'll overwrite the
tween updating it to the new 'y' position, but forget to update the
state to SHOWN at the end of our transition. Make sure to always set
the state to SHOWN at the end.

https://bugzilla.gnome.org/show_bug.cgi?id=704844
2014-03-14 11:13:17 -04:00
29485ff24b layout: really queue region update before redraw
This code may have worked when written in 2009, but later gjs commit
b5e467d89aea43a8e32a1138d232c8a32e6b0785 removed the priority
parameter from idle_add.

Now, when running a constantly-updating client (es2gears) on an
embedded platform, _updateRegions() does not get called and I see
unresponsive window decorations.

Update the code to use meta_later_add() like other parts of the
shell, which is actually slightly better in this case anyway.
Solves the unresponsiveness problem.

https://bugzilla.gnome.org/show_bug.cgi?id=585500
2014-03-14 06:16:42 -06:00
f6ed3d9f88 authPrompt: Don't ever ask for a username if smartcard service is in foreground
The smartcard service is put in the foreground in two cases:

1) If password service is disabled by admin configuratoin
2) if a smartcard is inserted

In either case we don't want to ask the user to pick a user from the
userlist.  We currently only avoid asking in case 2.

This commit fixes case 1.

https://bugzilla.gnome.org/show_bug.cgi?id=726263
2014-03-13 15:08:00 -04:00
39a36cb510 Updated German translation 2014-03-13 20:01:15 +01:00
ff5550c82b util: fix "login card" smartcard detection on unlock screen
We only want to react to the card the user logged in with, at
the unlock screen.  We check "at the unlock screen" by checking
the "reauthenticating" state variable.  That variable is the
wrong one, though. It gets set too late, and in some cases, gets
set at the login screen, too.  We should be checking this._reauthOnly
instead.

This commit fixes that.

https://bugzilla.gnome.org/show_bug.cgi?id=726262
2014-03-13 14:01:02 -04:00
7d5ce1a159 screenShield: fix lifting when inserting smartcard
If a user inserts the smartcard they logged in with into the system,
it's supposed to lift the shield and prompt for pin.  That doesn't
happen because the parameter list of the smartcard-inserted signal
handler is wrong.

This commit fixes that.

https://bugzilla.gnome.org/show_bug.cgi?id=726262
2014-03-13 14:01:01 -04:00
c492415386 hidpi: Make sure gdk and clutter scaling stays disabled when the scale factor changes
Not doing that could led to messy situations when the user changes the scale factor
at runtime.

https://bugzilla.gnome.org/show_bug.cgi?id=726238
2014-03-13 14:16:11 +01:00
5616bbd45b hidpi: Listen for gtk-xft-dpi instead of monitors-changed
Currently we update the scale factor on startup and when we get a
monitors-changed signal, which is not the only cases where the setting changes. We cannot listen for gdk-window-scaling-factor changes because it is not
exported to gdk.

So use gtk-xft-dpi which also indicates a scale factor change.

When someone changes gtk-xft-dpi directly without changing the scale factor
we will just re-read the gdk-window-scaling-factor so no harm is done.

https://bugzilla.gnome.org/show_bug.cgi?id=726238
2014-03-13 14:16:11 +01:00
e117aa5297 Calendar: force-rebuild the calendar when the events change
Don't overoptimize and skip the rebuild when the month is the same,
as the calendar depends on the events too.

https://bugzilla.gnome.org/show_bug.cgi?id=726119
2014-03-13 14:12:38 +01:00
17ac1382df Updated Portuguese translation 2014-03-12 22:47:49 +00:00
057a026ea4 MessageTray: don't destroy notifications when the user presses ESC
Doing so is inconsistent with the behavior in the summary, and
is quite annoying when dealing with chats (because there is no way
to unfocus a chat notification with the keyboard only)

https://bugzilla.gnome.org/show_bug.cgi?id=724178
2014-03-12 19:33:35 +01:00
6ce6e86318 TelepathyClient: destroy an existing account notification when the user goes offline
We already filter new notifications caused by the explicit
user action, but we don't do so for changes to existing
notifications.

https://bugzilla.gnome.org/show_bug.cgi?id=723976
2014-03-12 19:26:42 +01:00
492558a2d2 search: survive the provider reporting the wrong number of metas
If a provider crashes during GetResultMetas, or returns the wrong
number of metas, report it as failing but don't cause a JS exception.

https://bugzilla.gnome.org/show_bug.cgi?id=725020
2014-03-12 19:26:41 +01:00
b78e00f372 search: destroy result actors before forgetting about them
We can't let live (ie, never destroyed) actors undergo GC, because
they will emit :destroy signals during finalization and assert/crash
libmozjs. Properly destroy all actors before letting the GC
free them.

https://bugzilla.gnome.org/show_bug.cgi?id=724798
2014-03-12 19:26:41 +01:00
c2cc504837 NetworkMenu: destroy the wifi dialog when the associate device disappears
When the device is removed by NetworkManager, we can't use it
to connect, so the dialog is useless and should be destroyed.

https://bugzilla.gnome.org/show_bug.cgi?id=723935
2014-03-12 19:26:41 +01:00
ac76940530 StTextureCache: don't crash if we fail to allocate a framebuffer
It's possible that FBO creation fails due to hw limits or the
driver not exposing the EXT_framebuffer_object extension.
In that case, just give up on creating square icons.

https://bugzilla.gnome.org/show_bug.cgi?id=724977
2014-03-12 19:26:41 +01:00
55d1c7e2ab background: fix cancellable issue
If we have the following sequence:

    cache.getImageContent({ filename: "foo", cancellable: cancellable1 });
    cache.getImageContent({ filename: "foo", cancellable: cancellable2 });
    cancellable1.cancel();

Then the second load will complete with "null" as its content, even though
it was never cancelled, and we'll see a blank image. Meanwhile, since the
second load simply appends to the list of callers for the second load,
cancellable2 does absolutely nothing: cancelling it won't stop the load,
and it will still receive onFinished handling.

To prevent this from happening, give the actual load operation its own
Gio.Cancellable, which is "ref-counted" -- only cancel it when all the other
possible callers cancel.

Based on work from Jasper St. Pierre <jstpierre@macheye.net>

https://bugzilla.gnome.org/show_bug.cgi?id=722149
2014-03-12 12:15:43 -04:00
fdf264ff64 background: get rid of nested loop when finishing file loading
At the moment when a file is loaded, we iterate through the list of
pending file loads and ignore any unrelated to the file, then iterate
all the callers of the related file loads and finish them.

In fact, there can only ever be one pending file load related to the
file, and we already know it, so we can avoid the ugly nested loops.

https://bugzilla.gnome.org/show_bug.cgi?id=722149
2014-03-12 12:15:42 -04:00
e917b7ce0f background: refactor file loading
This commit moves the code around a bit such that the
caller gets allocated up front and then a file load is either
found or created to attach the caller to.

Functionally, the code is the same, it's just now factored in a way
that will make it easier to fix a bug with cancellation later.

https://bugzilla.gnome.org/show_bug.cgi?id=722149
2014-03-12 12:12:47 -04:00
ec6facb9e7 background: always copy background content when loading into cache
Copying is actually a lightweight operation, so trying to avoid it just adds
code complexity for little gain.

Based on work from Jasper St. Pierre <jstpierre@macheye.net>

https://bugzilla.gnome.org/show_bug.cgi?id=722149
2014-03-12 12:12:47 -04:00
60f3c09f90 Updated Czech translation 2014-03-12 15:53:48 +01:00
afdfd6cebc Updated Russian translation 2014-03-11 22:30:13 +04:00
edd66c40d9 ScreenShield: send a signal to GSD to wake up the screen
Instead of poking through IDLETIME, which confuses the state tracking
and can prevent automatic suspend, send a special signal to GSD
when the screen is to be waken up for a notification.

Someday we'll bring over all the state tracking and avoid this
ping-pong between gnome-shell and gnome-settings-daemon, but
that day's not today.

https://bugzilla.gnome.org/show_bug.cgi?id=712706
2014-03-11 18:10:05 +01:00
fc4bc5277a Lightbox: complete radial effect for modal dialogs
Rework the radial effect to use similar code to MetaBackground,
and adjust parameters to make it more noticeable.

https://bugzilla.gnome.org/show_bug.cgi?id=725830
2014-03-11 17:14:07 +01:00
821768a414 network: Don't show network-offline-symbolic in the top bar
This is against the designs.

https://bugzilla.gnome.org/show_bug.cgi?id=725340

https://bugzilla.gnome.org/show_bug.cgi?id=721459
2014-03-11 10:01:07 -04:00
522f3bf171 NMConnectionSection: don't remove connections that were never added
NMApplet will call removeConnection() unconditionally on all sections,
including those that had nothing to do with the connection in the first
place.

Fixes:

Gjs-WARNING **: JS ERROR: TypeError: this._connectionItems.get(...) is undefined
NMConnectionSection<.removeConnection@resource:///org/gnome/shell/ui/status/network.js:323
wrapper@resource:///org/gnome/gjs/modules/lang.js:169
NMApplet<._connectionRemoved@resource:///org/gnome/shell/ui/status/network.js:1885
wrapper@resource:///org/gnome/gjs/modules/lang.js:169

https://bugzilla.gnome.org/show_bug.cgi?id=725958
2014-03-10 17:49:43 +01:00
fb7400ab85 Updated Chinese (Taiwan) translation 2014-03-09 04:26:03 +00:00
210128f22b Updated Lithuanian translation 2014-03-08 21:49:25 +02:00
78ae233823 Updated Chinese (China) translation 2014-03-08 14:04:28 +00:00
8f25da7cea Updated Latvian translation 2014-03-08 11:48:25 +02:00
7f52fdb435 update Punjabi Translation for gnome-shell: Alam 2014-03-07 19:31:38 -06:00
0ba05b29b9 loginDialog: Defer loading user list until needed
Loading the user list can be expensive, for instance when there is
a large number of users and/or their avatars have to be fetched over
the network. In case the user list is disabled anyway, there is no
point in doing that work just to hide it, so stop doing that.

https://bugzilla.gnome.org/show_bug.cgi?id=725905
2014-03-08 00:29:11 +01:00
ef8123e3a2 loginDialog: Add missing return value
_loadUserList() may be used as idle handler, so we should explicitly
return a boolean.

https://bugzilla.gnome.org/show_bug.cgi?id=725905
2014-03-08 00:29:10 +01:00
257e1f3096 calendar: Grab key focus when user changes day
When the user changes the active day by mouse click or keyboard focus
plus key press on a day in the grid, always move the keyboard focus to
the newly activated day.

This basically restores functionality that was introduced in commit
31478e9fb4 but got lost again in the re-factoring in commit
cc4659f5c6.

https://bugzilla.gnome.org/show_bug.cgi?id=725606
2014-03-07 19:18:32 +01:00
6441ae77d9 Updated Indonesian translation 2014-03-07 06:48:50 +00:00
3f0938072f Updated Kazakh translation 2014-03-07 02:35:31 +00:00
2fe06a28aa Updated Czech translation 2014-03-06 18:18:06 +01:00
38750ba798 LookingGlass: add GObject and Gio to the ns available inline
Having to go through import.gi is awfully inconvenient when one
is using the looking glass as a quick gjs console, and we're
already importing all sorts of stuff there.

https://bugzilla.gnome.org/show_bug.cgi?id=725832
2014-03-06 16:57:41 +01:00
b4c01f8905 Updated Galician translations 2014-03-06 12:27:41 +01:00
104d70c88e Updated Friulian translation 2014-03-06 11:11:35 +01:00
133a350f2f Updated Brazilian Portuguese translation 2014-03-06 08:38:30 +00:00
496ab55357 Updated Friulian translation 2014-03-06 04:59:38 +01:00
a391758e31 Updated Friulian translation 2014-03-06 04:23:40 +01:00
eaf8ad4949 Updated Friulian translation 2014-03-06 03:59:10 +01:00
2f583bdcf3 Updated Friulian translation 2014-03-06 03:45:24 +01:00
db19012a41 Bump version to 3.11.91
Update NEWS.
2014-03-06 00:23:41 +01:00
62be46884e calendar: Don't forget to rebuild the calendar
Don't forget to rebuild the calendar when changing the setting
'org.gnome.shell.calendar show-weekdate'. This wasn't happening anymore
and changing the setting resulted in a calendar without the days
grid.

https://bugzilla.gnome.org/show_bug.cgi?id=725533
2014-03-05 20:14:56 +01:00
3f2e6a48a9 Updated Hebrew translation 2014-03-05 18:58:56 +02:00
ff124e5f74 Updated Spanish translation 2014-03-05 16:58:35 +01:00
c07421c195 Calendar: make current date label clickable
Once you start navigating between months, you can't return to the
current day.  However, the current day is always displayed above the
calendar grid.  Fix this by making the current date clickable; when
clicked, the calendar grid jumps back to that day.

https://bugzilla.gnome.org/show_bug.cgi?id=641366
2014-03-05 16:40:56 +01:00
de8348d3b9 Updated Spanish translation 2014-03-05 16:39:11 +01:00
184df8a853 Updated Korean translation 2014-03-05 19:55:27 +09:00
12768a147c Updated Norwegian bokmål translation 2014-03-05 06:47:35 +01:00
94161cea37 Updated Polish translation 2014-03-04 18:18:35 +01:00
52a4ef7cf7 Updated Hebrew translation 2014-03-04 18:30:55 +02:00
3432f71500 NetworkMenu: use Connected instead of profile name for wired and wwan
The profile name is most often not useful (because it's an
autogenerated string like "Wired Connection 1"), and even when it
is, it's already available in the submenu.

https://bugzilla.gnome.org/show_bug.cgi?id=725586
2014-03-04 16:08:02 +01:00
8282aa6c24 Updated Galician translations 2014-03-03 17:34:02 +01:00
59f9eaa1c9 NetworkAgent: fix initial secrets requests after 17726abb
While the named commit was correct for VPN connections, it didn't
work correctly for the initial secrets requests like when connecting
to a new access point.  In that case, secrets *should* be requested
when none are found, but only if interaction is enabled.  The
bits of 17726abb which removed checking secrets against the hints
*were* correct, but 17726abb removed too much.

Also, to ensure passwords don't get inadvertently cleared when
simply reading them from the keyring, don't save passwords
unless something might have changed.

https://bugzilla.gnome.org/show_bug.cgi?id=724779
2014-03-03 15:17:43 +01:00
4433b735c4 Updated Lithuanian translation 2014-03-02 19:57:10 +02:00
9cd30fa6b5 Updated Polish translation 2014-03-02 17:24:18 +01:00
2c7bbfb500 Fix a typo 2014-03-02 17:21:34 +01:00
51a1d23bf9 Finnish translation update by Jiri Grönroos 2014-03-01 20:15:45 +02:00
c02e6e82bc Update Arabic translation 2014-02-28 23:09:15 +02:00
e37a3fa7e6 perf: Restore shell after runs
Currently running the perf tool results into no wm running
afterwards making it hard for the user to get the results from a terminal
and generally does not make it easy for users to run it to gather numbers.

So restore the shell after the test has completed.

https://bugzilla.gnome.org/show_bug.cgi?id=724870
2014-02-28 21:40:31 +01:00
e23c2ffecc plugin: Don't query for swap_events support directly
There is no need for the duplication, clutter already exports
this information.

https://bugzilla.gnome.org/show_bug.cgi?id=724870
2014-02-28 21:40:31 +01:00
744f11d045 Updated Spanish translation 2014-02-28 14:13:08 +01:00
b7eb1f3e8b Don't use get_core_device
clutter_device_manager_get_core_device calls XIGetClientPointer, which
requires a round-trip to the server. Since we do this on StWidget
creation, this means a full round-trip for every created StWidget.
Replace this with get_device with the ID of the VCP/VCK, since mutter
doesn't support MPX, and we know this is what the device is.
2014-02-27 14:55:29 -05:00
3f28091e52 Tajik translation updated 2014-02-27 12:13:18 +05:00
b4ee86955d messageTray: Make sure that the source actor is square
Commit b7e1539699 removed the size to support hidpi but that caused the
actor to no longer be square. Fix that by going back to setting a size
but apply the scale factor before doing so.
2014-02-26 18:15:38 +01:00
8b866efe92 location: Adapt to new Geoclue agent interface
To be able to correctly setup dbus policy, I had to change the expected
agent D-Bus API a bit: Now object path is fixed and not different for
each user.

https://bugzilla.gnome.org/show_bug.cgi?id=725082
2014-02-25 12:45:32 +00:00
fb61ab8df7 Updated Spanish translation 2014-02-24 17:28:11 +01:00
990956ece7 Updated Galician translations 2014-02-24 15:22:12 +01:00
414b592d53 Updated Hebrew translation 2014-02-24 15:25:37 +02:00
751154d9da shell-util: Fix warning in shell_util_cursor_tracker_to_clutter
If the sprite is NULL, like if a Wayland app wanted to hide the cursor,
then we need to hide the ClutterTexture on our side, as ClutterTexture
has no easy way to tell it to paint nothing.
2014-02-23 10:54:32 -05:00
29addc499c shell-global: Only set the scale factor if get_setting succeeded
If gdk_screen_get_setting fails, like if it's running without XSettings,
then the GValue will have a value of 0. A lot of code tries to divide by
the scale factor. This produces NaN, and combined with the fact that NaN
is "leaky", we very quickly end up spinning out of control.
2014-02-23 10:54:32 -05:00
caa98de581 Updated Hebrew translation 2014-02-23 14:16:30 +02:00
1fd1ec4312 Updated Chinese (China) translation 2014-02-23 09:57:11 +00:00
f4607626e4 workspaceThumbnails: Really fix DND creating new workspaces
The same problem spotted in commit 89a2dc71fc is present in
some more places, fix those as well.

https://bugzilla.gnome.org/show_bug.cgi?id=724686
2014-02-23 00:29:29 +01:00
b494c15e4b shell-js: Kill some compile warnings
jsapi.h has some bad warnings with gcc. gjs-module.h already includes
jsapi.h and uses a complicated set of GCC pragmas to mask them out, so
just kill our include.
2014-02-22 17:42:03 -05:00
3c0defa125 Updated Belarusian translation. 2014-02-22 11:27:32 +01:00
f2df4d95de Updated Czech translation 2014-02-22 08:51:14 +01:00
fabcf20e06 Updated Kazakh translation 2014-02-21 17:25:04 +00:00
b9510b9ab7 Updated Spanish translation 2014-02-21 13:10:31 +01:00
52a2ebad04 Updated Brazilian Portuguese translation 2014-02-21 12:02:52 +00:00
89a2dc71fc workspaceThumbnails: Fix creating new workspace via DND
Commit 61a58ff3c9 replaced the (removed in commit 254afc50223a7)
MetaWindowActor.get_workspace() method by MetaWindow.get_workspace(),
but did not take into account that the return values differ - the
former returns the workspace index, the latter the workspace object.

https://bugzilla.gnome.org/show_bug.cgi?id=724686
2014-02-21 11:48:55 +01:00
adb0de43d8 Updated Indonesian translation 2014-02-21 06:46:22 +00:00
e2a811a720 Updated Greek translation 2014-02-20 23:20:56 +02:00
5bcafc5c17 Updated Lithuanian translation 2014-02-20 22:42:10 +02:00
2d24536caf shellDBus: Fix LaunchExtensionPreferences()
Commit 5dedc5d8ba removed "unused" functionality which was
still used by that method. Launch it via GAppInfo instead, which
still supports passing URIs.

https://bugzilla.gnome.org/show_bug.cgi?id=724813
2014-02-20 20:27:02 +01:00
b088c4086b Tajik translation updated 2014-02-20 17:00:40 +05:00
3c58f4abd3 Bump version to 3.11.90
Update NEWS.
2014-02-20 00:31:55 +01:00
e2a9b27b2b Revert "viewSelector: Give the active page key focus when it is shown"
This broke keyboard navigation in the app picker, which is not an
acceptable regression for the release.

This reverts commit ec2bb039ae.
2014-02-20 00:29:14 +01:00
fcd5f06c09 windowManager: Animate tile previews
With tile previews being implemented as Clutter actors in the shell, we
can now easily add fancy animations when showing/hiding the preview.
Besides looking more polished, the animations also help understanding
what will happen to the window when the drag is finished.

https://bugzilla.gnome.org/show_bug.cgi?id=665758
2014-02-20 00:29:14 +01:00
6d93c8b3fd windowManager: Implement tile previews
Mutter now delegates tile previews to compositor plugins, so
add a simple implementation based on the UI previously provided
by mutter.

https://bugzilla.gnome.org/show_bug.cgi?id=665758
2014-02-20 00:29:14 +01:00
2663e1be5d window-tracker: Be more cautious when setting focus app
Since we started tracking non-interesting windows, we can no longer
assume that if we manage to find an app associated with the focus window,
it should appear focused - we now can find apps for docks, the DESKTOP
window etc.
To restore the old behavior, make sure that the focus window or one of
its parents is "interesting".

https://bugzilla.gnome.org/show_bug.cgi?id=722928
2014-02-20 00:29:14 +01:00
0fa6be4614 endSessionDialog: Add extra strings for translation
Add two extra, currently unused strings in order to make the life easier
for translators and avoid breaking the upcoming string freezes.

https://bugzilla.gnome.org/show_bug.cgi?id=722898
2014-02-20 00:27:35 +01:00
46163a6607 endSessionDialog: Warn when trying to install updates on battery power
Interrupting update installation can mess up the package database quite
a bit and could lead to totally destroying the distro installtion. To
avoid running out of juice during an upgrade, warn when someone tries to
install updates on battery power.

https://bugzilla.gnome.org/show_bug.cgi?id=722898
2014-02-20 00:27:35 +01:00
645ef093f7 endSessionDialog: Offer offline updates in the shutdown dialog
This adds a checkbox for installing software updates to the shut down
dialog. The implementation relies on an already prepared offline update
and uses PackageKit's pk-trigger-offline-update helper to trigger the
installation.

https://bugzilla.gnome.org/show_bug.cgi?id=722898
2014-02-20 00:27:35 +01:00
7551e134da endSessionDialog: Fix the "Restart & Install" button
This moves the dialog type overriding that gnome-software uses to bring
up restartInstallDialogContent from _sync() to OpenAsync(), in order to
ensure the type is overridden early enough to show the correct buttons.

While at this, make sure the & symbol in the button's label is escaped
to avoid runtime warnings, now that the label actually gets used.

https://bugzilla.gnome.org/show_bug.cgi?id=722898
2014-02-20 00:27:35 +01:00
5bec5fb6cb endSessionDialog: Simplify CSS padding handling
... so that we add more items to messageLayout without having to
hardcode the same padding in each of the children.

https://bugzilla.gnome.org/show_bug.cgi?id=722898
2014-02-20 00:27:35 +01:00
c176af4da5 endSessionDialog: Use a 48px icon as per mockups
https://bugzilla.gnome.org/show_bug.cgi?id=722898
2014-02-20 00:27:35 +01:00
2631f03108 windowManager: Don't remove the active workspace
Currently workspaces (except for the last one) are removed when
they become empty. While we do have special treatment for the
case where the currently active workspace is removed, we just
move directly without animations to the last workspace to avoid
ending up on a "random" workspace. However this behavior is still
a bit confusing, so keep the workspace around instead until the
user decides to move to another one.

https://bugzilla.gnome.org/show_bug.cgi?id=709064
2014-02-19 21:52:52 +01:00
525c71658b Updated Norwegian bokmål translation 2014-02-19 19:45:45 +01:00
10e5778deb Updated Brazilian Portuguese translation 2014-02-19 18:04:26 +00:00
6512a5fd6b browser_plugin: Expose version validation boolean
Expose the version validation boolean through the public JS
API so that e.g.o can make use of it.

https://bugzilla.gnome.org/show_bug.cgi?id=724683
2014-02-19 17:07:38 +01:00
1af40b1345 extensionSystem: Add a gsettings key to disable version validation
Add a key 'disable-extension-version-validation' key that disables
the validation of extension's claimed to be supported shell version
with the shell version and just load all extensions unconditionally.

https://bugzilla.gnome.org/show_bug.cgi?id=724683
2014-02-19 17:07:38 +01:00
0418b68051 popupMenu: Use an image for arrows
Until now the arrows were the associated arrow
character of the font. This cause some problems like
different arrows for different fonts, and size can be
altered because of the font size.
To solve that, use an image for the arrows.

https://bugzilla.gnome.org/show_bug.cgi?id=720206
2014-02-19 13:44:27 +01:00
a7283864e8 popupMenu: Use relative rotation for arrows
Currently the animation of the arrows doesn't take
into account previous rotation.
Since in a incoming patch we will use one arrow
and rotate it to generate the four directions, we
need that the animation use relative rotation.

https://bugzilla.gnome.org/show_bug.cgi?id=720206
2014-02-19 13:44:26 +01:00
4950bad2a7 popupMenu: Rename _arrow_rotation to follow JS covention 2014-02-19 13:44:26 +01:00
470ac0eae3 shell_global: Use correct agruments for in update_scale_factor
Otherwise we crash ...

https://bugzilla.gnome.org/show_bug.cgi?id=705410
2014-02-18 23:40:34 +01:00
87abbf9b20 hdpi: Revert hacks
Revert the hacks that where added in response to a bug caused by
commit ba459f4d20

https://bugzilla.gnome.org/show_bug.cgi?id=705410
2014-02-18 23:40:34 +01:00
3e7e88cd5f popupMenu: Make destroy() a bit more robust
Currently destroying a menu's actor and calling its destroy() method
are subtly different - the latter will also result in the menu being
removed from the corresponding menu manager.
There is no good justification for that behavior, so make both actions
behave the same.

https://bugzilla.gnome.org/show_bug.cgi?id=724690
2014-02-18 21:27:24 +01:00
b7e1539699 messageTray: don't force a size on SourceActor's iconBin
Supports hidpi icons this way.

https://bugzilla.gnome.org/show_bug.cgi?id=724607
2014-02-18 07:46:54 -08:00
8492f2ba24 osdWindow: scale by scaleFactor
Since we calculate this dimensions from the size of the monitor, the
result was too large. Scale it by scaleFactor instead.

https://bugzilla.gnome.org/show_bug.cgi?id=724607
2014-02-18 07:46:07 -08:00
737f4eb1c1 dateMenu: Update gnome-clocks' desktop file
https://bugzilla.gnome.org/show_bug.cgi?id=724282
2014-02-18 14:52:48 +01:00
58191ea66b telepathyClient: Use locale format for timestamps
Until now the timestamps were using 24h format.
Check gsetting clock-format to know when
the user is using 12h format or 24h format and
make the timestamp acordingly.

https://bugzilla.gnome.org/show_bug.cgi?id=715158
2014-02-18 11:27:34 +01:00
1f786df462 NetworkMenu: add VPN settings menu item
Add a menu item that launches the VPN page of the network panel,
or the network panel generically if multiple VPNs are configured.

https://bugzilla.gnome.org/show_bug.cgi?id=709167
2014-02-18 00:17:11 +01:00
fa4c481aed telepathyClient: Use ratio char for timestamps 2014-02-17 20:52:51 +01:00
d555fd7883 ShellApp: remove impossible check
The action muxer is created and destroyed with the running state,
it can never be NULL.

https://bugzilla.gnome.org/show_bug.cgi?id=722554
2014-02-17 20:44:58 +01:00
fe7ece1f5a NetworkMenu: use radio items instead of switches for multiple profiles
Multiple connections for the same device are mutually exclusive, so
a switch is not the appropriate UI metaphor. Use a radio item instead,
and provide a separate "Turn off" item to disconnect.
Behavior when there is only one connection is not changed, there
is a single Connect/Turn off item.

https://bugzilla.gnome.org/show_bug.cgi?id=723570
2014-02-17 20:44:58 +01:00
2bb3aed729 NetworkMenu: sort connections by name only
We don't watch for timestamp changes, and sorting by name keeps
the order consistent and predictable. In practice, there should
be at most 3 or 4 elements, so the user will always read all them
at once and sorting is irrelevant.

https://bugzilla.gnome.org/show_bug.cgi?id=723570
2014-02-17 20:44:57 +01:00
488a42696c NetworkMenu: fix connection name update
If the connection name is changed, the UUID doesn't necessarily,
so checkConnection would take the early return path. Make sure
we update the existing menu item too.

https://bugzilla.gnome.org/show_bug.cgi?id=723570
2014-02-17 20:44:57 +01:00
f43ff45683 NetworkMenu: update for latest designs
Distinguish reaching the full internet from being in a non-routed
LAN, and show a different icon when being an hotspot master.

https://bugzilla.gnome.org/show_bug.cgi?id=723570
2014-02-17 20:44:57 +01:00
bde1451896 NMDeviceWired: don't unconditionally access device.active_connection
The active_connection might be null, but the NMApplet code might
still belive the device wrapper is the primary connection (because
dbus signals are emitted one after the other).
(Also, remove an old and wrong comment about bluetooth in wwan code)

Fixes:

(gnome-shell:22511): Gjs-WARNING **: JS ERROR: Exception in callback for signal: icon-changed: TypeError: this._device.active_connection is null
NMDeviceWired<.getIndicatorIcon@resource:///org/gnome/shell/ui/status/network.js:475
wrapper@resource:///org/gnome/gjs/modules/lang.js:169
NMApplet<._updateIcon@resource:///org/gnome/shell/ui/status/network.js:1790
wrapper@resource:///org/gnome/gjs/modules/lang.js:169
_emit@resource:///org/gnome/gjs/modules/signals.js:124
NMConnectionSection<._addConnection/<@resource:///org/gnome/shell/ui/status/network.js:265
_emit@resource:///org/gnome/gjs/modules/signals.js:124
NMConnectionItem<._sync@resource:///org/gnome/shell/ui/status/network.js:137
wrapper@resource:///org/gnome/gjs/modules/lang.js:169
NMConnectionItem<.setActiveConnection@resource:///org/gnome/shell/ui/status/network.js:169
wrapper@resource:///org/gnome/gjs/modules/lang.js:169
NMConnectionDevice<._activeConnectionChanged@resource:///org/gnome/shell/ui/status/network.js:327
wrapper@resource:///org/gnome/gjs/modules/lang.js:169

https://bugzilla.gnome.org/show_bug.cgi?id=723570
2014-02-17 20:44:57 +01:00
fff2ca6f26 telephatyIdle: Time stamps next conversation line
To give more context to the chat notification bubble, put the
time stamp next to the last conversation line instead of
a new line.

https://bugzilla.gnome.org/show_bug.cgi?id=708031
2014-02-17 20:00:00 +01:00
bec57a6cee Revert "location: Allow user to disable GPS"
This reverts commit 5d05b66902.

Had a long discussion with Bastien Nocera and Allan Day on IRC about
this and in the end we decided to go with the simple on/off controls for
now.

Conflicts:
	js/ui/status/location.js

https://bugzilla.gnome.org/show_bug.cgi?id=723684
2014-02-17 15:49:34 +00:00
a012ca4fac layout: Don't query the monitor size twice 2014-02-17 13:42:20 +01:00
3ba49b0a50 layout: Protect against broken monitor size reports
VNC / XRDP reports nonsensial (i.e 0) monitor dimensions causing us to
end up with a dpi of "Infinity" and thus scale even though we shouldn't.

https://bugzilla.redhat.com/show_bug.cgi?id=1065788
2014-02-17 13:38:55 +01:00
314aa024b5 appDisplay: Add time to view switch animation
Add more time to the fade in/out animation when switching
views so they don't switch abruptly and add a delay
between view switch animations to avoid morphing.

https://bugzilla.gnome.org/show_bug.cgi?id=722331
2014-02-17 13:31:52 +01:00
598f750859 messageTray: Add source actor without count label
Split the current implementation of SourceActor into
SourceActor and SourceActorWithLabel.
In this manner we can use source actors withouth count labels,
required in the screenShield to not clash with the count
text label.

https://bugzilla.gnome.org/show_bug.cgi?id=709275
2014-02-17 13:22:39 +01:00
8057848458 location: Rename _onoffAction to _onOffAction
It was just a typo that this patch now corrects.

https://bugzilla.gnome.org/show_bug.cgi?id=723684
2014-02-17 12:08:40 +00:00
e80c28a530 location: Mark 2 user-visible strings for translation
https://bugzilla.gnome.org/show_bug.cgi?id=723684
2014-02-17 12:08:40 +00:00
5d05b66902 location: Allow user to disable GPS
When exact accuracy (i-e GPS) is available, allow user to disable that.
When users don't want application to get their precise location, they
can now opt for network-based geolocation only, which can be
street-level at best.

https://bugzilla.gnome.org/show_bug.cgi?id=723684
2014-02-17 12:08:40 +00:00
59634b2cf5 location: Rename _updateMenuVisibility to _updateMenu
We'll soon be doing more than just toggling the accuracy of menu itself
in this function. Hence the renaming.

https://bugzilla.gnome.org/show_bug.cgi?id=723684
2014-02-17 12:08:40 +00:00
7c3892f5a2 location: disconnect from 'g-properties-changed' signal
https://bugzilla.gnome.org/show_bug.cgi?id=723684
2014-02-17 12:08:40 +00:00
19406a238b location: 'MaxAccuracyLevel' property is now read-only
https://bugzilla.gnome.org/show_bug.cgi?id=723684
2014-02-17 12:08:40 +00:00
d6146197dd location,schema: Keep max accuracy in gsetting
Instead of relying on geoclue to store this user configuration, lets
keep it in gsettings. Geoclue is a system service and therefore is not
the appropriate entity to keep this info.

https://bugzilla.gnome.org/show_bug.cgi?id=723684
2014-02-17 12:08:39 +00:00
38f241479c location: Coding style fixes
No space between identifier and '('.

https://bugzilla.gnome.org/show_bug.cgi?id=723684
2014-02-17 12:08:39 +00:00
aa45999824 location: Rename _setAccuracy to setMaxAccuracyLevel
More descriptive name to avoid any confusion.

https://bugzilla.gnome.org/show_bug.cgi?id=723684
2014-02-17 12:08:39 +00:00
3b7593ed7f altTab: Scale thumbnails by the scale factor
Fixes their size on high dpi.

https://bugzilla.gnome.org/show_bug.cgi?id=705410
2014-02-16 16:55:55 +01:00
f959cafb36 appDisplay: don't force size on folder icon actor
Use a table layout instead.

https://bugzilla.gnome.org/show_bug.cgi?id=705410
2014-02-16 07:49:25 -08:00
e92d204d42 dash: account for scale factor to determine icon size
https://bugzilla.gnome.org/show_bug.cgi?id=705410
2014-02-16 07:49:25 -08:00
f543161234 st-icon: remove custom size request/allocate
Use a layout manager instead. This has the effect of not enforcing a
priv->icon_size size request, since that value is unscaled.

https://bugzilla.gnome.org/show_bug.cgi?id=705410
2014-02-16 07:49:25 -08:00
9cc1017912 iconGrid: don't force icon size to the BaseIcon
Since we might get a scaled up version for HiDpi.

https://bugzilla.gnome.org/show_bug.cgi?id=705410
2014-02-16 07:49:25 -08:00
fc719c19f9 altTab: account for scale factor when computing icon size
https://bugzilla.gnome.org/show_bug.cgi?id=705410
2014-02-16 07:49:24 -08:00
ad97fc6855 altTab: don't override icon size request
Instead of overriding the actor's request with the icon size, just set
the new icon size on the actors, and let the default handler take the
preferred size of children.

https://bugzilla.gnome.org/show_bug.cgi?id=705410
2014-02-16 07:49:24 -08:00
407dc74502 shell-app: finish support for loading with scale
https://bugzilla.gnome.org/show_bug.cgi?id=705410
2014-02-16 07:49:24 -08:00
e5e764b402 texture-cache: require icon scale to load gicon
To support HiDpi.

https://bugzilla.gnome.org/show_bug.cgi?id=705410
2014-02-16 07:49:24 -08:00
65ad65fe52 Updated Brazilian Portuguese translation 2014-02-16 06:23:41 +00:00
8d09d20510 Updated Hebrew translation 2014-02-15 20:16:43 +02:00
5a5b04b2b0 Updated POTFILES.in 2014-02-15 20:13:20 +02:00
3113bac8e6 location: React to changes in available accuracy level
GPS could be plugged in and out, network can go up and down and
therefore available accuracy level can also change.

https://bugzilla.gnome.org/show_bug.cgi?id=723684
2014-02-15 17:41:26 +00:00
9217f2c916 location: Don't show menu if geoclue is totally incapable
If geoclue can't provide location at all (no GPS or network), don't
bother to show controls that don't serve any purpose.

https://bugzilla.gnome.org/show_bug.cgi?id=723684
2014-02-15 17:41:26 +00:00
32a49b7846 location: Provide a way to disable geolocation
Now that we are indicating 'geolocation in use' to user, we better also
provide at least a way to disable geolocation. Once this is in place, we
can provide slightly better controls rather than simply on/off switch.

https://bugzilla.gnome.org/show_bug.cgi?id=723684
2014-02-15 17:41:26 +00:00
12ef034b7b location: Make _connectToGeoclue() reentrent
https://bugzilla.gnome.org/show_bug.cgi?id=723684
2014-02-15 17:41:26 +00:00
e70e4a21f2 location: Rename _onGeoclueAppeared to _connectToGeoclue
Rename _onGeoclueAppeared to _connectToGeoclue as in the following patch
we'll call it from other contexts then geoclue appearing.

https://bugzilla.gnome.org/show_bug.cgi?id=723684
2014-02-15 17:41:26 +00:00
7826fb4f04 location: Create Geoclue proxy asynchronously
https://bugzilla.gnome.org/show_bug.cgi?id=723684
2014-02-15 17:41:26 +00:00
8f1b8909dc Fix position/size changed disconnects
Commit 3f7a989d38 changed the signals to match mutter api changes,
but did not update disconnects, so do that.
2014-02-15 13:07:14 +01:00
3f7a989d38 Update to changes for MetaWindow size-changed / position-changed signals
These have changed upstream to be on the MetaWindow, rather than
the MetaWindowActor. Follow suit.
2014-02-14 23:49:54 -05:00
4d3fd7598d appDisplay: Re-add _getCategories
It was introduced by one of the commits reverted by 812a61939e,
but is now used for app folders as well; add it back.
2014-02-14 14:02:31 +01:00
620e3cef20 appDisplay: Open new window on middle-click
The current middle-click action of opening a new window on a new
workspace is a bit peculiar; it is also not overly hard to achieve
the same result by moving a new window to the desired workspace or
selecting a workspace before opening a new window. Just opening
a new window is also a more common action, so having a shortcut
available that doesn't require a modifier is a good idea as well;
change the middle-click behavior accordingly.

https://bugzilla.gnome.org/show_bug.cgi?id=695010
2014-02-14 12:01:48 +01:00
812a61939e Revert "appDisplay: Special case terminal launching"
Having terminal launchers behave differently than any other launchers
is non-obvious and confusing. Remove the special-casing to restore
consistency, we will make the new window action more accessible
instead.
This reverts commit 68faba6bde, 4ed0f3e5f0
and 887a21afb9.

https://bugzilla.gnome.org/show_bug.cgi?id=695010
2014-02-14 12:01:48 +01:00
793c6c2f7b Magnifier: clip the UI group clone to the allocation
Without clipping, we show parts of the message tray and workspace
thumbnails that are normally clipped by the screen.

https://bugzilla.gnome.org/show_bug.cgi?id=724305
2014-02-13 19:43:44 +01:00
f8f4d0f646 Magnifier: use the system noise texture for the dead area
The design says that the noise texture is the implicit bottom
layer, and so it's appropriate to use it togheter with the default
color to cover the dead area outside the screen which becomes
visibile when scrolling.

https://bugzilla.gnome.org/show_bug.cgi?id=724305
2014-02-13 19:43:44 +01:00
3a92aa751f Magnifier: don't listen for focus/tracker events if the magnifier is not active
In addition to checking the current settings, check also if the
zoom region is active before registering the event listener.
This way, we avoid DBus traffic for events we're not interested in.

Also, make FocusCaretTracker resilient to multiple register/deregister
calls (which can now happen).

https://bugzilla.gnome.org/show_bug.cgi?id=724305
2014-02-13 19:43:41 +01:00
6882273aa0 Magnifier: demote exceptions reading focus/caret position
It's possible that the DBus call goes in timeout (which is bad,
but unavoidable, given that atspi is synchronous) or fails
because the component has been removed (race condition). Those
errors are not dependent on gnome-shell, but on faulty applications
(mostly).
If they happen, log a debug message and continue.

https://bugzilla.gnome.org/show_bug.cgi?id=724305
2014-02-13 19:31:00 +01:00
3b0197620f Magnifier: fix a warning when calling setActive() with the same value
We must not call enable/disable_unredirect if we didn't change the
active value, otherwise mutter gets confused and emits warnings.

https://bugzilla.gnome.org/show_bug.cgi?id=724293
2014-02-13 19:31:00 +01:00
f6240e114c Don't send all debug messages to Telepathy
The log handler can be invoked at bad times, and in particular
it can be invoked from gsignal with the signal lock taken.
At that time, calling into arbitrary high-level APIs can
cause a dead-lock.
Instead, only send to telepathy the tp-glib debug messages.
Everything else is in the journal anyway.

https://bugzilla.gnome.org/show_bug.cgi?id=724256
2014-02-13 13:03:37 +01:00
0f3c129b95 layout: Set high dpi scaling factor
Set the scaling factor when the dpi is above the hidpi threshold.

https://bugzilla.gnome.org/show_bug.cgi?id=705410
2014-02-12 22:53:37 +01:00
6f87b01c47 Revert "shell-global: Set high dpi scaling factor"
This reverts commit ba459f4d20.

This breaks gdm.
2014-02-12 22:53:11 +01:00
32110a9866 layout: Remove stray reference to parentSetId
This was removed in a4dea25d76.
2014-02-12 14:13:08 -05:00
ba459f4d20 shell-global: Set high dpi scaling factor
Set the scaling factor based on the xsetting.

https://bugzilla.gnome.org/show_bug.cgi?id=705410
2014-02-12 19:45:53 +01:00
d868e6bfaf st: Add high dpi support
Add a scale_factor property to StThemeContext that can
be used to enable (integer) scaling of pixel values.

https://bugzilla.gnome.org/show_bug.cgi?id=705410
2014-02-12 19:45:47 +01:00
9f3499a7c3 make NetworkManager optional
NetworkManager is only available on Linux.

https://bugzilla.gnome.org/show_bug.cgi?id=669495
2014-02-11 18:04:44 -05:00
ccec7732a7 calendar server: fix _LDFLAGS vs _LDADD mixup
_LDFLAGS is for flags.  _LDADD is for LIBS.

https://bugzilla.gnome.org/show_bug.cgi?id=724184
2014-02-11 17:46:44 -05:00
3b980a173f Updated Assamese translation 2014-02-11 13:07:53 +00:00
246139f90b Updated Ukranian 2014-02-09 23:08:26 +02:00
4e85fb7d8d Updated German translation 2014-02-09 20:17:24 +00:00
ab32411b0c Updated Norwegian bokmål translation 2014-02-09 19:46:37 +01:00
477f28a6bd LayoutManager: untrack actors that are destroyed
If an actor is destroyed, calling get_transformed_size()/position()
can return bogus values and trigger JS exceptions.
This can happen if a tracked actor comes from an extension
(such as classic mode's window-list) and that extension is
deactivated.

https://bugzilla.gnome.org/show_bug.cgi?id=723661
2014-02-09 19:30:02 +01:00
96ef0a178d autogen.sh: use #!/bin/sh instead of #!/bin/bash
We don't have any bashisms in this file, so we may as well use sh.

https://bugzilla.gnome.org/show_bug.cgi?id=722342
2014-02-09 11:00:04 -05:00
ab603e7ef7 Updated Aragonese translation 2014-02-09 13:25:09 +01:00
d52104a62a Updated Kazakh translation 2014-02-09 04:11:08 +00:00
8d8d1cfdd6 Magnifier: Restore crosshairs
This patch is to restore broken crosshairs so they may be used
once more

https://bugzilla.gnome.org/show_bug.cgi?id=723709
	magnifier.js
2014-02-08 23:47:40 +00:00
5451751513 Updated Czech translation 2014-02-08 11:22:36 +01:00
92ae26bb9f Fix username shadows in Lock/Loginscreen
https://bugzilla.gnome.org/show_bug.cgi?id=723833
2014-02-07 16:20:14 +00:00
3c8ee0c8cb Updated Spanish translation 2014-02-07 14:47:46 +01:00
20f76b8118 Tajik translation updated 2014-02-07 09:59:45 +05:00
d8eeeead18 Updated Galician translations 2014-02-07 00:59:18 +01:00
5452162bc3 Updated Brazilian Portuguese translation 2014-02-06 18:53:18 +00:00
a4adcba405 Revert "network: Use NMDevice.get_available_connections(); for NMWirelessDialog"
This reverts commit a36bfced47.

get_available_connections() returns the connections that are
available right now, ie, with the currently visible APs, but
that might change while the dialog is open, so we can't use it.

https://bugzilla.gnome.org/show_bug.cgi?id=709128
2014-02-06 19:45:24 +01:00
66da594382 Updated Hebrew translation 2014-02-06 20:30:25 +02:00
aa426842f2 BluetoothMenu: show the submenu when active but not connected
Following the updated designs for system status, show the submenu
but not the indicator when bluetooth radio is on but no device
is connected.

https://bugzilla.gnome.org/show_bug.cgi?id=709353
2014-02-06 19:07:48 +01:00
ed53a45228 NetworkMenu: show the device name instead of Bluetooth
To distinguish the bluetooth network menu from the bluetooth
menu proper, use the device name as the label.
Also, replace Connect with "Use as Internet connection"

https://bugzilla.gnome.org/show_bug.cgi?id=709353
2014-02-06 19:07:47 +01:00
2ddbcb2369 Updated Brazilian Portuguese translation 2014-02-06 17:35:33 +00:00
61a58ff3c9 Fix regression after mutter commit 254afc50223a707c3afa7c9f638681199f41809e
The "old and unused API" was not so unused after all :)
2014-02-06 18:15:36 +01:00
638aee65c0 Update Arabic translation 2014-02-06 15:32:37 +02:00
f21c49f8da Slider: put imports in order
Bug https://bugzilla.gnome.org/show_bug.cgi?id=712649
2014-02-05 19:36:50 +00:00
583d2cb4e4 Magnifier: take x,y from center of focused widget
bug https://bugzilla.gnome.org/show_bug.cgi?id=720951
2014-02-05 18:21:42 +00:00
aa70dcfc8f Updated Spanish translation 2014-02-05 13:48:04 +01:00
ffb61c425b Tajik translation updated 2014-02-05 10:59:16 +05:00
858cf5e0c9 Bump version to 3.11.5
Update NEWS.
2014-02-05 00:17:32 +01:00
881dd4666e Updated Hebrew translation
Signed-off-by: Yosef Or Boczko <yoseforb@src.gnome.org>
2014-02-05 00:32:33 +02:00
c4aeaf7fe8 NetworkMenu: use the carrier state to the decide if wired should be shown
The design says "when a network cable is connected", not
"When a network cable is connected and the link is up and we
have an IP etc. etc." (which is what ACTIVATED would imply).

https://bugzilla.gnome.org/show_bug.cgi?id=723570
2014-02-04 22:25:11 +01:00
ea1f5a8fc6 NMWirelessDialog: show an informative message when airplane mode is on
Rather than just showing "No networks", inform the user if airplane
mode is on or if wifi is off, and allow the user to change that
from the dialog (if possible).

https://bugzilla.gnome.org/show_bug.cgi?id=709128
2014-02-04 22:25:06 +01:00
7f1e420a0a NMWirelessDialog: request a scan when there are no visible access points
Ideally, we should keep scanning while the dialog is open, and
stop (or reduce the frequency) when it's closed. Forcing a new
scan when the dialog is opened empty is a close approximation
and increases the probability that the user will find the AP
he needs.

https://bugzilla.gnome.org/show_bug.cgi?id=709128
2014-02-04 22:24:01 +01:00
1272eaf07f NMWirelessDialog: fix removing access points
We must destroy the actor, not the item, because the latter doesn't
have a destroy() method.

https://bugzilla.gnome.org/show_bug.cgi?id=709128
2014-02-04 22:24:00 +01:00
2fe760cc4b rfkill: split out the dbus handling parts from the indicator
status.network wants to watch for airplane mode too, we can
share the code with a manager singleton.

https://bugzilla.gnome.org/show_bug.cgi?id=709128
2014-02-04 22:24:00 +01:00
df3a50bae8 AirplaneMode: don't show a "Turn off" item if HW enabled
If airplane mode is enabled with an HW switch, we can't turn it
off from the menu, so make the menu item insensitive and
replace it with a helpful tip.

https://bugzilla.gnome.org/show_bug.cgi?id=709685
2014-02-04 22:24:00 +01:00
0db3605f33 Magnifier: Disable unredirect when active
The unredirect feature does not apply to the magnifier and it
prevents users from gaming whilst it is on so disable when magnifier
is active and allow magnifier users to game!

Bug https://bugzilla.gnome.org/show_bug.cgi?id=708985
2014-02-04 16:58:25 +01:00
173fa92116 Updated Indonesian translation 2014-02-04 14:16:26 +00:00
02ca58c1eb Updated Hebrew translation. 2014-02-03 16:30:03 +02:00
4a22fe58bf updated kn.po 2014-02-03 16:51:29 +05:30
3fc478a14b overview: don't add a null desktop clone
If there is no desktop window, getDesktopClone() returns null.
In that case, we know that no animation is needed.

Fixes a regression from b97f3a9ecf

https://bugzilla.gnome.org/show_bug.cgi?id=723523
2014-02-03 11:55:50 +01:00
203bc674fe Updated Traditional Chinese translation(Hong Kong and Taiwan) 2014-02-02 20:36:23 +08:00
a4a9f0a04c Updated Kazakh translation 2014-02-01 15:12:11 +00:00
918e7fffeb Updated Tajik translation 2014-02-01 12:55:49 +00:00
e1648de661 Updated Brazilian Portuguese translation 2014-02-01 10:05:14 +00:00
f7c94e6343 Updated Greek translation 2014-02-01 08:16:19 +02:00
220 changed files with 53872 additions and 34049 deletions

7
.gitignore vendored
View File

@ -24,10 +24,13 @@ data/gnome-shell-wayland.desktop.in
data/gnome-shell-extension-prefs.desktop
data/gnome-shell-extension-prefs.desktop.in
data/gschemas.compiled
data/perf-background.xml
data/org.gnome.shell.gschema.xml
data/org.gnome.shell.gschema.valid
data/org.gnome.shell.evolution.calendar.gschema.xml
data/org.gnome.shell.evolution.calendar.gschema.valid
data/org.gnome.Shell.PortalHelper.desktop
data/org.gnome.Shell.PortalHelper.service
docs/reference/*/*.args
docs/reference/*/*.bak
docs/reference/*/*.hierarchy
@ -78,11 +81,9 @@ src/gnome-shell-calendar-server
src/gnome-shell-extension-prefs
src/gnome-shell-extension-tool
src/gnome-shell-hotplug-sniffer
src/gnome-shell-jhbuild
src/gnome-shell-perf-helper
src/gnome-shell-perf-tool
src/gnome-shell-real
src/gnome-shell-wayland
src/gnome-shell-portal-helper
src/hotplug-sniffer/org.gnome.Shell.HotplugSniffer.service
src/run-js-test
src/test-recorder

333
NEWS
View File

@ -1,3 +1,336 @@
3.13.92
=======
* Fix submenu arrow animations [Hashem; #728927]
* Always initialize clutter accessibility [Alejandro; #735908]
* Adapt to mutter background changes [Owen; #735638]
* Improve handling of outOfDate extensions in prefs [Florian; #736185]
* Port offline updates to PackageKit's DBus interface [Kalev; #736337]
* location: Translate accuracy levels for geoclue [Zeeshan; #736479]
* Implement input source switching [Rui; #736435]
* Fix crash when dragging window from workspace switcher [Carlos G.; #735972]
* Clean out list of default favorites [Elad; #735682]
* Add settings link to location submenu [Florian; #736542]
* Fix keynav of message tray menu button [Florian; #707799]
* Misc. bug fixes [Carlos G., Florian, Rui; #736110, #736329, #736343,
#735927, #735976]
Contributors:
Elad Alfassa, Zeeshan Ali (Khattak), Michael Catanzaro, Adel Gadllah,
Carlos Garnacho, Kalev Lember, Rui Matos, Florian Müllner, Hashem Nasarat,
Alejandro Piñeiro, Carlos Soriano, Jasper St. Pierre, Owen W. Taylor
Translations:
Piotr Drąg [pl], Changwoo Ryu [ko], Yuri Myasoedov [ru], Zhou Fang [ja],
Peter Mráz [sk], Ville-Pekka Vainio [fi], Sweta Kothari [gu],
Marek Černocký [cs], A S Alam [pa], Christian Kirbach [de],
Alexandre Franke [fr], Aurimas Černius [lt], Khaled Hosny [ar],
Enrico Nicoletto [pt_BR], Andika Triwidada [id], Shantha kumar [ta],
Matej Urbančič [sl], Pawan Chitrakar [ne], Yosef Or Boczko [he],
Balázs Úr [hu], Dušan Kazik [sk], Gil Forcada [ca],
Carles Ferrando [ca@valencia], Nilamdyuti Goswami [as], Ivaylo Valkov [bg],
Sandeep Sheshrao Shedmake [mr], Umarzuki Bin Mochlis Moktar [ms],
Muhammet Kara [tr], Jiro Matsuzawa [ja], Kris Thomsen [da],
Mattias Eriksson [sv]
3.13.91
=======
* Fix keynav into session menu on login screen [Florian; #735614]
* Add gesture to summon message tray [Carlos G.; #735625]
* Accept scrolls/swipes either way on the screen shield [Jasper; #734874]
* Animate opening the app picker and improve app folder animations
[Carlos S.; #734726]
* Animate app icons on launching a new window [Carlos S., Florian; #734726]
* Show the on-screen keyboard when touch input is being used [David; #702015]
* Misc. bug fixes [Bastien, Owen, Florian, Carlos G.; #735190, #735385,
#735608, #735681]
Contributors:
Carlos Garnacho, David King, Kalev Lember, Florian Müllner, Bastien Nocera,
Carlos Soriano, Jasper St. Pierre, Owen W. Taylor
Translations:
Fran Diéguez [gl], Sweta Kothari [gu], Manoj Kumar Giri [or],
Alain Lojewski [fr], Praveen Illa [te], Arash Mousavi [fa],
Andika Triwidada [id]
3.13.90
=======
* Make use of GLSL optional [Adel; #733623]
* Update on-screen-keyboard position on monitor changes [Cosimo; #733790]
* Improve window manager animations [Giovanni; #732857]
* Handle touch events [Carlos G.; #733633]
* Try to not show "New Window" action for single-window apps
[Giovanni; #722554]
* Fix overview exceeding screen size with many apps installed
[Carlos S.; #723496]
* Add Software to default favorites [Mathieu; #734406]
* Improve app picker <-> desktop transition [Carlos S.; #732901]
* Remove <shift>-magic for switcher popups [Christophe; #732296]
* Add a special background to use for performance testing [Owen; #734610]
* Add support for default disabled search providers [Giovanni; #734110]
* Fix portals that don't redirect properly [Giovanni; #733848]
* Fix history trimming in chat notifications [Giovanni; #733899]
* Try to use default calendar application [Florian; #722333]
* Only show location menu when geolocation is in use [Zeeshan; #731122]
* Misc. bug fixes and cleanups [Giovanni, Carlos G., Zeeshan, Carlos S.,
Cosimo; #711682, #733840, #734483, #734680, #733813, #735062]
Contributors:
Zeeshan Ali (Khattak), Mathieu Bridon, Giovanni Campagna, Cosimo Cecchi,
Piotr Drąg, Christophe Fergeau, Adel Gadllah, Carlos Garnacho,
Florian Müllner, Carlos Soriano, Jasper St. Pierre, Olav Vitters,
Owen W. Taylor
Translations:
Aurimas Černius [lt], MarMav [el], Inaki Larranaga Murgoitio [eu],
Reinout van Schouwen [nl], ngoswami [as], Fabio Tomat [fur],
Chao-Hsiung Liao [zh_HK, zh_TW]
3.13.4
======
* Handle portal login requests [Giovanni; #704416]
* Scale fonts on wayland on hiDPI devices [Adel; #732537]
* Fix default ibus candidate index labels [Rui; #702944]
* Add gestures for various system actions [Carlos G.]
* Add performance test script for the perf.gnome.org [Owen; #732350]
* Use new restart framework to improve restart visuals [Owen; #733026]
* Improve keynav in app folder popups [Carlos S.; #731477]
* Fix truncation of app search results [Carlos S.; #732416]
* Automatically update renamed desktop files in favorites [Kalev; #729429]
* Misc. bug fixes and cleanups [Giovanni, Yosef, Owen, Bastien, Javier;
#729823, #726401, #732301, #732348, #732349, #733498, #733540]
Contributors:
Giovanni Campagna, Adel Gadllah, Carlos Garnacho, Javier Hernández,
Kalev Lember, Rui Matos, Florian Müllner, Bastien Nocera, Yosef Or Boczko,
Carlos Soriano, Jasper St. Pierre, Owen W. Taylor
Translations:
Yuri Myasoedov [ru], Daniel Mustieles [es], Fran Diéguez [gl],
Cheng-Chia Tseng [zh_TW], A S Alam [pa], Benjamin Steinwender [de],
Enrico Nicoletto [pt_BR], MarMav [el], Yosef Or Boczko [he],
Kjartan Maraas [nb]
3.13.3
======
* Don't allow closing windows with attached modals [Florian; #729886]
* Fix self-restarting on OpenBSD [Antoine; #727763]
* Improve behavior of window buttons with compositor menus [Florian; #731058]
* Work around atspi-related performance regression [Alejandro; #730118]
* Misc bug fixes and cleanups [Florian, Lan, Jasper, Christophe, Debarshi,
Zeeshan; #728271, #726460, #703833, #731118, #731220, #695487, #730527,
#728170, #731619, #731738, #731882, #731923]
Contributors:
Zeeshan Ali (Khattak), Christophe Fergeau, Adel Gadllah, Antoine Jacoutot,
Ting-Wei Lan, Florian Müllner, Alejandro Piñeiro, Debarshi Ray,
Carlos Soriano, Jasper St. Pierre, Wim Taymans, Rico Tzschichholz
Translations:
Philip Withnall [en_GB], Milo Casagrande [it], Aurimas Černius [lt],
Enrico Nicoletto [pt_BR], Kjartan Maraas [nb], Balázs Meskó [hu],
Muhammet Kara [tr], Daniel Mustieles [es], Yosef Or Boczko [he],
Matej Urbančič [sl], Mattias Eriksson [sv]
3.13.2
======
* Make airplane mode menu insensitive in lock screen [Giovanni; #729224]
* Don't always extend struts to the screen edge [Florian; #683819]
* Fix keynav for alternatives in AltSwitcher [Florian; #727259]
* Implement window menus in the shell [Jasper; #726352]
* Support resource:/// URLs in GNOME_SHELL_JS envvar [Owen; #730409]
* Fix switcher popups with keybindings containing Escape [Rui; #730739]
* Update extension-prefs UI to follow GNOME 3 patterns [Florian; #730829]
* Add support for fallback app menu in window decorations [Florian; #730752]
* Fix keynav escaping open app folders [Florian; #726760]
* Misc. bug fixes [Kalev, Florian, Owen; #729429, #728449, #730408, #730753,
#730653]
Contributors:
Giovanni Campagna, Piotr Drąg, Kalev Lember, Rui Matos, Florian Müllner,
Vadim Rutkovsky, Carlos Soriano, Jasper St. Pierre, Owen W. Taylor
Translations:
Ihar Hrachyshka [be], Giovanni Campagna [it], Carles Ferrando [ca@valencia],
Daniel Mustieles [es], Aurimas Černius [lt], Enrico Nicoletto [pt_BR],
Yosef Or Boczko [he], Marek Černocký [cs], Muhammet Kara [tr],
Georges Neto [pt_BR], Andika Triwidada [id]
3.13.1
======
* Ensure the currently focused app icon is viewable [Rui; #726759]
* Improve language in location menu [Zeeshan; #726498]
* Improve HiDpi support [Cosimo; #726907]
* Set accessible role for window previews [Alejandro; #726670]
* Fix bad antialiasing on panel menu buttons [Carlos; #727336]
* Don't hide location menu [Zeeshan; #727398]
* Fix IM candidate window obscuring current text [Rui; #727579]
* Don't always extend struts to the screen edge [Florian; #663690]
* Add shortcuts for switching to the last workspace [Elad; #659288]
* Show OSD window on all monitors [Adel; #722684]
* Improve consistency of labels in network menu [Paul; #727163]
* Fix zombie search providers showing up [Jasper; #728597]
* Remove ConsoleKit support [Florian; #686626]
* Fix region screenshots with open shell menus [Florian; #709126]
* Support <shift>insert in text entries [Florian; #648318]
* Improve app picker scrolling on touch [Jasper; #729064]
* Don't make date button clickable when on current date [Carlos; #726724]
* Tweak heuristic for hiding workspace switcher [Florian; #662457]
* Add option to show in Software to app context menu [Matthias; #643043]
* Misc. bug fixes and cleanups [Bastien, Florian, Giovanni, Adel, Vadim,
Carlos; #727983, #727948, #728512, #728681, #728897, #727384, #728820,
#715042, #728449, #728343]
Contributors:
Elad Alfassa, Zeeshan Ali (Khattak), Giovanni Campagna, Cosimo Cecchi,
Matthias Clasen, Piotr Drąg, Adel Gadllah, Paul Lange, Rui Matos,
Simon McVittie, Florian Müllner, Bastien Nocera, Alejandro Piñeiro,
Vadim Rutkovsky, Carlos Soriano, Jasper St. Pierre
Translations:
Khaled Hosny [ar], Piotr Drąg [pl], Yosef Or Boczko [he],
Antonio Fernandes C. Neto [pt_BR], Marek Černocký [cs], maria thukididu [el],
Andika Triwidada [id], Daniel Mustieles [es], Changwoo Ryu [ko],
Benjamin Steinwender [de], Sphinx Jiang [zh_CN],
Inaki Larranaga Murgoitio [eu], Marcus Lundblad [sv], Aurimas Černius [lt],
Stas Solovey [ru], Alexandre Franke [fr], Matej Urbančič [sl],
Fran Diéguez [gl], Pau Iranzo [ca], Luca Ferretti [it], Milo Casagrande [it],
Tiago S [pt], Victor Ibragimov [tg], Dirgita [id], Khoem Sokhem [km],
Rūdolfs Mazurs [lv], Balázs Úr [hu], Ask H. Larsen [da], Ikuya Awashiro [ja],
Wouter Bolsterlee [nl], Daniel Korostil [uk], Daniel Șerbănescu [ro],
Enrico Nicoletto [pt_BR]
3.12.0
======
* gdm: Reset greeter when coming back to login screen [Jasper; #726989]
Contributors:
Jasper St. Pierre
Translations:
Daniel Martinez [an], Yuri Myasoedov [ru], Inaki Larranaga Murgoitio [eu],
Abderrahim Kitouni [ar], Praveen Illa [te], Matej Urbančič [sl],
Chao-Hsiung Liao [zh_HK, zh_TW], Frédéric Péters [fr],
Мирослав Николић [sr, sr@latin], Ask H. Larsen [da], Kenneth Nielsen [da],
Jiro Matsuzawa [ja], Dušan Kazik [sk]
3.11.92
=======
* calendar: Grab key focus after changing day [Volker; #725606]
* gdm: Don't load user list if disabled [Florian; #725905]
* Don't show network-offline in the top bar [Jasper; #725340]
* Improve radial shade effect of modal dialogs [Giovanni; #725830]
* Fix broken suspend-on-idle functionality [Giovanni; #712706]
* Close wifi selection dialog when device disappears [Giovanni; #723935]
* Don't close chats when pressing Escape [Giovanni; #724178]
* Improve smartcard support in login/lock screen [Ray; #726262, #726263]
* Wake up screen when resuming from suspend [Giovanni; #726378]
* Make bluetooth and location items insensitive when locked [Florian; #726319]
* Don't show bluetooth icon when there is no adapter [Giovanni; #725057]
* Make sure to keep the OSK on top of modal dialogs [Rui; #719451]
* Misc. bug fixes and cleanups [Giovanni, Ray, Adel, Daniel, Jasper, Florian;
#725832, #725958, #722149, #724977, #724798, #725020, #723976, #726119,
#726238, #585500, #704844, #726323, #726322, #726120, #726414]
Contributors:
Giovanni Campagna, Daniel Drake, Adel Gadllah, Rui Matos, Florian Müllner,
Volker Sobek, Jasper St. Pierre, Ray Strode
Translations:
Fabio Tomat [fur], Rafael Ferreira [pt_BR], Fran Diéguez [gl],
Marek Černocký [cs], Baurzhan Muftakhidinov [kk], Andika Triwidada [id],
A S Alam [pa], Rūdolfs Mazurs [lv], Wylmer Wang [zh_CN],
Aurimas Černius [lt], Cheng-Chia Tseng [zh_TW], Stas Solovey [ru],
Tiagosdot [pt], Benjamin Steinwender [de], Frédéric Peters [fr],
Daniel Korostil [uk], Yaron Shahrabani [he], Ville-Pekka Vainio [fi],
maria thukididu [el], Victor Ibragimov [tg], Kjartan Maraas [nb],
Gábor Kelemen [hu], Ask H. Larsen [da]
3.11.91
=======
* Don't use network profile name in menu [Giovanni; #725586]
* calendar: Make date label clickable to return to current date [Vit; #641366]
* Misc. bug fixes [Florian, Zeeshan, Adel, Jasper, Dan, Volker; #724813,
#724686, #725082, #724870, #724779, #725533]
Contributors:
Zeeshan Ali (Khattak), Giovanni Campagna, Piotr Drąg, Adel Gadllah,
Florian Müllner, Volker Sobek, Vit Stanislav, Jasper St. Pierre, Dan Williams
Translations:
Victor Ibragimov [tg], Aurimas Černius [lt], Dimitris Spingos [el],
Andika Triwidada [id], Rafael Ferreira [pt_BR], Daniel Mustieles [es],
Baurzhan Muftakhidinov [kk], Marek Černocký [cs], Ihar Hrachyshka [be],
eternalhui [zh_CN], Yosef Or Boczko [he], Fran Diéguez [gl],
Khaled Hosny [ar], Ville-Pekka Vainio [fi], Piotr Drąg [pl],
Kjartan Maraas [nb], Changwoo Ryu [ko]
3.11.90
=======
* Stop showing two bluetooth entries [Giovanni; #709353]
* Improve styling of login/lock screen [Reda; #723833]
* Fix magnifier crosshairs [Magdalen; #723709]
* Make NetworkManager support optional [Michael; #669495]
* Make middle-click open a new instance [Florian; #695010]
* Scale the UI on high resolution displays [Cosimo, Adel; #705410, #724607]
* Remove notification counter on screen shield [Carlos; #709275]
* Improve app picker transition [Carlos; #722331]
* Add geolocation indicator to status menu [Zeeshan; #723684]
* Improve timestamps in chat notifications [Carlos; #708031, #715158]
* Improve network menus [Giovanni; #723570]
* Add "VPN Setting" item to VPN submenu [Giovanni; #709167]
* Improve appearance of disclosure arrows [Carlos; #720206]
* Add GSetting key to disable version validation of extensions [Adel; #724683]
* Delay auto-removing empty workspaces [Florian; #709064]
* Offer offline updates in the shutdown dialog [Kalev; #722898]
* Animate tile previews [Florian; #665758]
* Misc. bug fixes and cleanups [Giovanni, Ryan, Debarshi, Florian; #709128,
#722342, #723661, #724184, #724256, #724293, #724305, #722554, #724282,
#724690, #722928]
Contributors:
Zeeshan Ali (Khattak), Magdalen Berns, Michael Biebl, Giovanni Campagna,
Cosimo Cecchi, Adel Gadllah, Reda Lazri, Kalev Lember, Ryan Lortie,
Florian Müllner, Debarshi Ray, Carlos Soriano, Jasper St. Pierre,
Colin Walters
Translations:
Victor Ibragimov [tg], Daniel Mustieles [es], Khaled Hosny [ar],
Enrico Nicoletto [pt_BR], Yosef Or Boczko [he], Fran Diéguez [gl],
Marek Černocký [cs], Baurzhan Muftakhidinov [kk], Jorge Pérez Pérez [an],
Kjartan Maraas [nb], David Lüder [de], Daniel Korostil [uk], ngoswami [as],
Rafael Ferreira [pt_BR]
3.11.5
======
* Fix extension preference tool [Florian; #722334]
* Fix keyboard activation of legacy tray icons [Giovanni; #721267]
* Add radial background shade for modal dialogs [Giovanni; #669798]
* Show attached modal windows in the overview [Giovanni; #650843]
* Add support for desktop actions [Giovanni; #669603]
* Indicate in system status when location service is used [Zeeshan; #709372]
* Add support for extended app folder schema [Jasper; #723179]
* Show status icon for wired network connections [Jasper; #708966]
* Indicate airplane mode in network selection dialog [Giovanni; #709128]
* Misc bug fixes and cleanups [Florian, Sebastian, Giovanni, Tim, Matt, Jasper;
#722417, #722494, #722547, #722593, #722434, #722787, #722690, #722840,
#722660, #722812, #723197, #722927, #723306, #723308, #723523, #709685,
#723570]
Contributors:
Zeeshan Ali (Khattak), Magdalen Berns, Giovanni Campagna, William Jon McCann,
Sebastian Keller, Tim Lunn, Florian Müllner, Carlos Soriano,
Jasper St. Pierre, Rico Tzschichholz, Matt Watson
Translations:
Marek Černocký [cs], Mattias Põldaru [et], Tong Hui [zh_CN],
Victor Ibragimov [tg], Enrico Nicoletto [pt_BR], Daniel Mustieles [es],
Fran Diéguez [gl], Kjartan Maraas [nb], Nilamdyuti Goswami [as],
Aurimas Černius [lt], Stas Solovey [ru], Yosef Or Boczko [he],
Jorge Pérez Pérez [an], Dimitris Spingos [el], Baurzhan Muftakhidinov [kk],
Chao-Hsiung Liao [zh_HK, zh_TW], Shankar Prasad [kn], Yaron Shahrabani [he],
Andika Triwidada [id]
3.11.4
======
* Fix removal of workspacaes that are not at the end [Giovanni; #721417]

2
README
View File

@ -8,7 +8,7 @@ For more information about GNOME Shell, including instructions on how
to build GNOME Shell from source and how to get involved with the project,
see:
http://live.gnome.org/GnomeShell
https://wiki.gnome.org/Projects/GnomeShell
Bugs should be reported at http://bugzilla.gnome.org against the 'gnome-shell'
product.

View File

@ -1,4 +1,4 @@
#!/bin/bash
#!/bin/sh
# Run this to generate all the initial makefiles, etc.
srcdir=`dirname $0`

View File

@ -41,6 +41,8 @@
#define PLUGIN_API_VERSION 5
#define EXTENSION_DISABLE_VERSION_CHECK_KEY "disable-extension-version-validation"
typedef struct {
GDBusProxy *proxy;
} PluginData;
@ -831,6 +833,16 @@ plugin_get_shell_version (PluginObject *obj,
return ret;
}
static gboolean
plugin_get_version_validation_enabled (PluginObject *obj,
NPVariant *result)
{
gboolean is_enabled = !g_settings_get_boolean (obj->settings, EXTENSION_DISABLE_VERSION_CHECK_KEY);
BOOLEAN_TO_NPVARIANT(is_enabled, *result);
return TRUE;
}
#define METHODS \
METHOD (list_extensions) \
METHOD (get_info) \
@ -850,6 +862,8 @@ static NPIdentifier api_version_id;
static NPIdentifier shell_version_id;
static NPIdentifier onextension_changed_id;
static NPIdentifier onrestart_id;
static NPIdentifier version_validation_enabled_id;
static bool
plugin_object_has_method (NPObject *npobj,
@ -892,7 +906,8 @@ plugin_object_has_property (NPObject *npobj,
return (name == onextension_changed_id ||
name == onrestart_id ||
name == api_version_id ||
name == shell_version_id);
name == shell_version_id ||
name == version_validation_enabled_id);
}
static bool
@ -910,6 +925,8 @@ plugin_object_get_property (NPObject *npobj,
return plugin_get_api_version (obj, result);
else if (name == shell_version_id)
return plugin_get_shell_version (obj, result);
else if (name == version_validation_enabled_id)
return plugin_get_version_validation_enabled (obj, result);
else if (name == onextension_changed_id)
{
if (obj->listener)
@ -988,6 +1005,7 @@ init_methods_and_properties (void)
/* this is the JS public API; it is manipulated through NPIdentifiers for speed */
api_version_id = funcs.getstringidentifier ("apiVersion");
shell_version_id = funcs.getstringidentifier ("shellVersion");
version_validation_enabled_id = funcs.getstringidentifier ("versionValidationEnabled");
get_info_id = funcs.getstringidentifier ("getExtensionInfo");
list_extensions_id = funcs.getstringidentifier ("listExtensions");

View File

@ -1,5 +1,5 @@
AC_PREREQ(2.63)
AC_INIT([gnome-shell],[3.11.4],[https://bugzilla.gnome.org/enter_bug.cgi?product=gnome-shell],[gnome-shell])
AC_INIT([gnome-shell],[3.13.92],[https://bugzilla.gnome.org/enter_bug.cgi?product=gnome-shell],[gnome-shell])
AC_CONFIG_HEADERS([config.h])
AC_CONFIG_SRCDIR([src/shell-global.c])
@ -76,8 +76,8 @@ AC_MSG_RESULT($enable_systemd)
CLUTTER_MIN_VERSION=1.15.90
GOBJECT_INTROSPECTION_MIN_VERSION=0.10.1
GJS_MIN_VERSION=1.39.0
MUTTER_MIN_VERSION=3.11.1
GTK_MIN_VERSION=3.7.9
MUTTER_MIN_VERSION=3.13.92
GTK_MIN_VERSION=3.13.2
GIO_MIN_VERSION=2.37.0
LIBECAL_MIN_VERSION=3.5.3
LIBEDATASERVER_MIN_VERSION=3.5.3
@ -105,22 +105,13 @@ SHARED_PCS="gio-unix-2.0 >= $GIO_MIN_VERSION
libcanberra libcanberra-gtk3
telepathy-glib >= $TELEPATHY_GLIB_MIN_VERSION
polkit-agent-1 >= $POLKIT_MIN_VERSION
libnm-glib libnm-util >= $NETWORKMANAGER_MIN_VERSION
libnm-gtk >= $NETWORKMANAGER_MIN_VERSION
libsecret-unstable gcr-base-3 >= $GCR_MIN_VERSION"
gcr-base-3 >= $GCR_MIN_VERSION"
if test x$have_systemd = xyes; then
SHARED_PCS="${SHARED_PCS} libsystemd-journal"
fi
PKG_CHECK_MODULES(GNOME_SHELL, $SHARED_PCS)
PKG_CHECK_MODULES(MUTTER, libmutter >= $MUTTER_MIN_VERSION)
PKG_CHECK_MODULES(MUTTER_WAYLAND, [libmutter-wayland >= $MUTTER_MIN_VERSION],
[MUTTER_WAYLAND_TYPELIB_DIR=`$PKG_CONFIG --variable=typelibdir libmutter-wayland`
AC_SUBST(MUTTER_WAYLAND_TYPELIB_DIR)
have_mutter_wayland=yes],
[have_mutter_wayland=no])
AM_CONDITIONAL(HAVE_MUTTER_WAYLAND, test $have_mutter_wayland != no)
PKG_CHECK_MODULES(GNOME_SHELL_JS, gio-2.0 gjs-internals-1.0 >= $GJS_MIN_VERSION)
PKG_CHECK_MODULES(ST, clutter-1.0 gtk+-3.0 libcroco-0.6 >= 0.6.8 x11)
@ -182,6 +173,38 @@ if test "$langinfo_ok" = "yes"; then
[Define if _NL_TIME_FIRST_WEEKDAY is available])
fi
AC_ARG_ENABLE(networkmanager,
AS_HELP_STRING([--disable-networkmanager],
[disable NetworkManager support @<:@default=auto@:>@]),,
[enable_networkmanager=auto])
if test "x$enable_networkmanager" != "xno"; then
PKG_CHECK_MODULES(NETWORKMANAGER,
[libnm-glib
libnm-util >= $NETWORKMANAGER_MIN_VERSION
libnm-gtk >= $NETWORKMANAGER_MIN_VERSION
libsecret-unstable],
[have_networkmanager=yes],
[have_networkmanager=no])
GNOME_SHELL_CFLAGS="$GNOME_SHELL_CFLAGS $NETWORKMANAGER_CFLAGS"
GNOME_SHELL_LIBS="$GNOME_SHELL_LIBS $NETWORKMANAGER_LIBS"
else
have_networkmanager="no (disabled)"
fi
if test "x$have_networkmanager" = "xyes"; then
AC_DEFINE(HAVE_NETWORKMANAGER, [1], [Define if we have NetworkManager])
AC_SUBST([HAVE_NETWORKMANAGER], [1])
else
if test "x$enable_networkmanager" = "xyes"; then
AC_MSG_ERROR([Couldn't find NetworkManager.])
fi
AC_SUBST([HAVE_NETWORKMANAGER], [0])
fi
AM_CONDITIONAL(HAVE_NETWORKMANAGER, test "$have_networkmanager" = "yes")
# Sets GLIB_GENMARSHAL and GLIB_MKENUMS
AM_PATH_GLIB_2_0()
@ -200,6 +223,14 @@ fi
AM_CONDITIONAL(ENABLE_MAN, test "$enable_man" != no)
GNOME_COMPILE_WARNINGS([error])
case "$WARN_CFLAGS" in
*-Werror*)
WARN_CFLAGS="$WARN_CFLAGS -Wno-error=deprecated-declarations"
;;
esac
AM_CFLAGS="$AM_CFLAGS $WARN_CFLAGS"
AC_SUBST(AM_CFLAGS)
BROWSER_PLUGIN_DIR="${BROWSER_PLUGIN_DIR:-"\${libdir}/mozilla/plugins"}"
AC_ARG_VAR([BROWSER_PLUGIN_DIR],[Where to install the plugin to])
@ -223,3 +254,15 @@ AC_CONFIG_FILES([
man/Makefile
])
AC_OUTPUT
echo "
Build configuration:
Prefix: ${prefix}
Source code location: ${srcdir}
Compiler: ${CC}
Compiler Warnings: $enable_compile_warnings
Support for NetworkManager: $have_networkmanager
Support for GStreamer recording: $build_recorder
"

View File

@ -1,9 +1,23 @@
desktopdir=$(datadir)/applications
desktop_DATA = gnome-shell.desktop gnome-shell-extension-prefs.desktop
if HAVE_MUTTER_WAYLAND
desktop_DATA += gnome-shell-wayland.desktop
endif HAVE_MUTTER_WAYLAND
CLEANFILES =
desktopdir=$(datadir)/applications
desktop_DATA = gnome-shell.desktop gnome-shell-wayland.desktop gnome-shell-extension-prefs.desktop
if HAVE_NETWORKMANAGER
desktop_DATA += org.gnome.Shell.PortalHelper.desktop
servicedir = $(datadir)/dbus-1/services
service_DATA = org.gnome.Shell.PortalHelper.service
CLEANFILES += \
org.gnome.Shell.PortalHelper.service \
org.gnome.Shell.PortalHelper.desktop
endif
%.service: %.service.in
$(AM_V_GEN) sed -e "s|@libexecdir[@]|$(libexecdir)|" \
$< > $@ || rm $@
# We substitute in bindir so it works as an autostart
# file when built in a non-system prefix
@ -60,6 +74,13 @@ dist_theme_DATA = \
theme/ws-switch-arrow-up.png \
theme/ws-switch-arrow-down.png
backgrounddir = $(pkgdatadir)
background_DATA = perf-background.xml
perf-background.xml: perf-background.xml.in
$(AM_V_GEN) sed -e "s|@datadir[@]|$(datadir)|" \
$< > $@ || rm $@
keysdir = @GNOME_KEYBINDINGS_KEYSDIR@
keys_in_files = 50-gnome-shell-system.xml.in
keys_DATA = $(keys_in_files:.xml.in=.xml)
@ -92,15 +113,19 @@ EXTRA_DIST = \
$(menu_DATA) \
$(convert_DATA) \
$(keys_in_files) \
perf-background.xml.in \
org.gnome.Shell.PortalHelper.desktop.in \
org.gnome.Shell.PortalHelper.service.in \
org.gnome.shell.gschema.xml.in.in
CLEANFILES = \
CLEANFILES += \
gnome-shell.desktop.in \
gnome-shell-wayland.desktop.in \
gnome-shell-extension-prefs.in \
$(desktop_DATA) \
$(keys_DATA) \
$(gsettings_SCHEMAS) \
perf-background.xml \
gschemas.compiled \
org.gnome.shell.gschema.valid \
org.gnome.shell.gschema.xml.in

View File

@ -1,5 +1,4 @@
[org.gnome.shell.overrides]
attach-modal-dialogs = /desktop/gnome/shell/windows/attach_modal_dialogs
button-layout = /desktop/gnome/shell/windows/button_layout
edge-tiling = /desktop/gnome/shell/windows/edge_tiling
workspaces-only-on-primary = /desktop/gnome/shell/windows/workspaces_only_on_primary

View File

@ -2,7 +2,7 @@
Type=Application
_Name=GNOME Shell (wayland compositor)
_Comment=Window management and application launching
Exec=@bindir@/mutter-launch -- gnome-shell-wayland --wayland
Exec=@bindir@/gnome-shell --wayland --display-server
X-GNOME-Bugzilla-Bugzilla=GNOME
X-GNOME-Bugzilla-Product=gnome-shell
X-GNOME-Bugzilla-Component=general

View File

@ -0,0 +1,9 @@
[Desktop Entry]
_Name=Captive Portal
Type=Application
Exec=gapplication launch org.gnome.Shell.PortalHelper
DBusActivatable=true
NoDisplay=true
Icon=network-workgroup
StartupNotify=true
OnlyShowIn=GNOME;

View File

@ -0,0 +1,3 @@
[D-BUS Service]
Name=org.gnome.Shell.PortalHelper
Exec=@libexecdir@/gnome-shell-portal-helper

View File

@ -38,7 +38,6 @@
<method name="Screencast">
<arg type="s" direction="in" name="file_template"/>
<arg type="a{sv}" direction="in" name="options"/>
<arg type="b" direction="in" name="flash"/>
<arg type="b" direction="out" name="success"/>
<arg type="s" direction="out" name="filename_used"/>
</method>

View File

@ -21,8 +21,17 @@
EnableExtension and DisableExtension D-Bus methods on org.gnome.Shell.
</_description>
</key>
<key name="disable-extension-version-validation" type="b">
<default>false</default>
<_summary>Disables the validation of extension version compatibility</_summary>
<_description>
GNOME Shell will only load extensions that claim to support the current
running version. Enabling this option will disable this check and try to
load all extensions regardless of the versions they claim to support.
</_description>
</key>
<key name="favorite-apps" type="as">
<default>[ 'epiphany.desktop', 'evolution.desktop', 'empathy.desktop', 'rhythmbox.desktop', 'shotwell.desktop', 'libreoffice-writer.desktop', 'nautilus.desktop', 'gnome-documents.desktop' ]</default>
<default>[ 'epiphany.desktop', 'evolution.desktop', 'rhythmbox.desktop', 'shotwell.desktop', 'org.gnome.Nautilus.desktop', 'org.gnome.Software.desktop' ]</default>
<_summary>List of desktop file IDs for favorite applications</_summary>
<_description>
The applications corresponding to these identifiers
@ -31,10 +40,10 @@
</key>
<key name="app-picker-view" type="u">
<default>0</default>
<summary>App Picker View</summary>
<description>
<_summary>App Picker View</_summary>
<_description>
Index of the currently selected view in the application picker.
</description>
</_description>
</key>
<key name="command-history" type="as">
<default>[]</default>
@ -118,8 +127,8 @@
</key>
<key name="pause-resume-tweens" type="as">
<default>[]</default>
<summary>Keybinding that pauses and resumes all running tweens, for debugging purposes</summary>
<description></description>
<_summary>Keybinding that pauses and resumes all running tweens, for debugging purposes</_summary>
<_description></_description>
</key>
</schema>
@ -139,11 +148,11 @@
gettext-domain="@GETTEXT_PACKAGE@">
<key type="b" name="current-workspace-only">
<default>false</default>
<summary>Limit switcher to current workspace.</summary>
<description>
<_summary>Limit switcher to current workspace.</_summary>
<_description>
If true, only applications that have windows on the current workspace are shown in the switcher.
Otherwise, all applications are included.
</description>
</_description>
</key>
</schema>
@ -166,11 +175,11 @@
</key>
<key type="b" name="current-workspace-only">
<default>true</default>
<summary>Limit switcher to current workspace.</summary>
<description>
<_summary>Limit switcher to current workspace.</_summary>
<_description>
If true, only windows from the current workspace are shown in the switcher.
Otherwise, all windows are included.
</description>
</_description>
</key>
</schema>
@ -185,15 +194,6 @@
</_description>
</key>
<key name="button-layout" type="s">
<default>":close"</default>
<_summary>Arrangement of buttons on the titlebar</_summary>
<_description>
This key overrides the key in org.gnome.desktop.wm.preferences when
running GNOME Shell.
</_description>
</key>
<key name="edge-tiling" type="b">
<default>true</default>
<_summary>Enable edge tiling when dropping windows on screen edges</_summary>

View File

@ -0,0 +1,31 @@
<!-- With an animated background, performance will differ depending on whether
one layer or two layers are being blended together. This messes up our
benchmarks. We could just benchmark a single image, but since blended
images are present for much of the day with the GNOME default background,
we want to make sure that also performs well; for that reason we ship
an "animated" background that animates super-slowly to use during
performance tests; it will be in the blended state until 2030. -->
<background>
<starttime>
<year>1990</year>
<month>1</month>
<day>1</day>
<hour>0</hour>
<minute>00</minute>
<second>00</second>
</starttime>
<!-- One transition that takes 40 years -->
<transition type="overlay">
<duration>1261440000.0</duration>
<from>@datadir@/backgrounds/gnome/adwaita-morning.jpg</from>
<to>@datadir@/backgrounds/gnome/adwaita-day.jpg</to>
</transition>
<!-- A single slide doesn't work, so another slide for 1 minute after 40 years -->
<static>
<duration>60</duration>
<file>/usr/share/backgrounds/gnome/Sandstone.jpg</file>
</static>
</background>

View File

@ -45,7 +45,7 @@ stage {
/* small bold */
.dash-label,
.window-caption,
.switcher-list,
.switcher-list,
.app-well-app > .overview-icon,
.show-apps > .overview-icon,
.grid-search-result .overview-icon {
@ -153,18 +153,43 @@ StScrollBar StButton#vhandle:active {
-arrow-rise: 11px;
}
.popup-menu-boxpointer.fallback-app-menu {
-arrow-border-radius: 4px;
-arrow-background-color: #ededed;
-arrow-border-width: 1px;
-arrow-border-color: #a6a6a6;
-arrow-base: 24px;
-arrow-rise: 11px;
}
.popup-menu-boxpointer.fallback-app-menu.dark {
-arrow-background-color: #3f4747;
-arrow-border-color: #282b2b;
}
.popup-menu {
min-width: 200px;
}
.unicode-arrow {
font-size: 120%;
.popup-menu-arrow {
width: 16px;
height: 16px;
}
.popup-submenu-menu-item:open {
background-color: #333333;
}
.fallback-app-menu .popup-submenu-menu-item:open {
background-color: #888888;
color: white;
}
.fallback-app-menu.dark .popup-submenu-menu-item:open {
background-color: #333333;
}
.popup-sub-menu {
background-gradient-start: rgba(80,80,80,0.3);
background-gradient-end: rgba(80,80,80,0.4);
@ -172,6 +197,20 @@ StScrollBar StButton#vhandle:active {
box-shadow: inset 0px 2px 4px rgba(0,0,0,0.9);
}
.fallback-app-menu .popup-sub-menu {
background-gradient-start: #dddddd;
background-gradient-end: #dfdfdf;
background-gradient-direction: vertical;
box-shadow: inset 0px 2px 4px rgba(0,0,0,0.4);
}
.fallback-app-menu.dark .popup-sub-menu {
background-gradient-start: #474747;
background-gradient-end: #4b4b4b;
background-gradient-direction: vertical;
box-shadow: inset 0px 2px 4px rgba(0,0,0,0.9);
}
.popup-sub-menu:scrolled .popup-menu-item:ltr {
padding-right: 0em;
}
@ -220,7 +259,29 @@ StScrollBar StButton#vhandle:active {
color: #9f9f9f;
}
.popup-image-menu-item {
.fallback-app-menu .popup-menu-item {
color: #43484a;
}
.fallback-app-menu .popup-menu-item:active {
color: white;
background-color: #4689cd;
}
.fallback-app-menu .popup-menu-item:insensitive {
color: gray;
}
.fallback-app-menu.dark .popup-menu-item {
color: white;
}
.fallback-app-menu.dark .popup-menu-item:active {
background-color: #445f7d;
}
.fallback-app-menu.dark .popup-menu-item:insensitive {
color: #9f9f9f;
}
.popup-separator-menu-item {
@ -232,8 +293,15 @@ StScrollBar StButton#vhandle:active {
padding: 8px 0px;
}
.popup-alternating-menu-item:alternate {
font-weight: bold;
.fallback-app-menu .popup-separator-menu-item {
-gradient-start: #a0a2a3;
-gradient-end: #a0a2a3;
-margin-horizontal: 0;
}
.fallback-app-menu.dark .popup-separator-menu-item {
-gradient-start: #818584;
-gradient-end: #818584;
}
.popup-status-menu-item {
@ -289,6 +357,20 @@ StScrollBar StButton#vhandle:active {
spacing: 10px;
}
.nm-dialog-airplane-box {
spacing: 12px;
}
.nm-dialog-airplane-headline {
font-size: 1.1em;
font-weight: bold;
text-align: center;
}
.nm-dialog-airplane-text {
color: #999999;
}
.nm-dialog-header-icon {
icon-size: 32px;
}
@ -321,6 +403,14 @@ StScrollBar StButton#vhandle:active {
icon-size: 16px;
}
.no-networks-label {
color: #999999;
}
.no-networks-box {
spacing: 12px;
}
/* Buttons */
.candidate-page-button,
@ -388,7 +478,7 @@ StScrollBar StButton#vhandle:active {
/* Common radii */
#searchEntry,
.search-entry,
.modal-dialog-button,
.notification-button,
.hotplug-notification-item,
@ -410,7 +500,7 @@ StScrollBar StButton#vhandle:active {
/* Entries */
#searchEntry,
.search-entry,
.login-dialog StEntry,
.notification StEntry,
.modal-dialog StEntry {
@ -422,7 +512,7 @@ StScrollBar StButton#vhandle:active {
padding: 4px 12px;
}
#searchEntry,
.search-entry,
.login-dialog StEntry,
.run-dialog-entry,
.notification StEntry {
@ -434,8 +524,8 @@ StScrollBar StButton#vhandle:active {
box-shadow: inset 0px 2px 4px rgba(0,0,0,0.6);
}
#searchEntry:focus,
#searchEntry:hover,
.search-entry:focus,
.search-entry:hover,
.login-dialog StEntry:focus,
.notification StEntry:focus,
.modal-dialog StEntry {
@ -452,18 +542,18 @@ StScrollBar StButton#vhandle:active {
border: 2px solid #3465a4;
}
#searchEntry {
.search-entry {
border-color: rgba(245,245,245,0.3);
color: rgb(192, 192, 192);
caret-color: rgb(192, 192, 192);
}
#searchEntry:hover {
.search-entry:hover {
color: rgb(128, 128, 128);
caret-color: rgb(128, 128, 128);
}
#searchEntry:focus {
.search-entry:focus {
color: rgb(64, 64, 64);
caret-color: rgb(64, 64, 64);
font-weight: bold;
@ -567,11 +657,6 @@ StScrollBar StButton#vhandle:active {
app-icon-bottom-clip: 2px;
}
.app-menu-icon {
width: 24px;
height: 24px;
}
.panel-button {
-natural-hpadding: 12px;
-minimum-hpadding: 6px;
@ -655,7 +740,7 @@ StScrollBar StButton#vhandle:active {
color: #e6e6e6;
border-radius: 32px; /* wish we could do 50% */
padding: 13px;
border: 1px solid #5f5f5f; /* using rgba() is flaky unfortunately */
border: 2px solid #5f5f5f; /* using rgba() is flaky unfortunately */
}
.system-menu-action:hover,
@ -663,7 +748,7 @@ StScrollBar StButton#vhandle:active {
color: white;
background-color: #4c4c4c;
border: none;
padding: 14px;
padding: 15px;
}
.system-menu-action:active {
@ -832,7 +917,7 @@ StScrollBar StButton#vhandle:active {
/* Search Box */
#searchEntry {
.search-entry {
width: 320px;
}
@ -841,8 +926,8 @@ StScrollBar StButton#vhandle:active {
color: #c0c0c0;
}
#searchEntry:hover .search-entry-icon,
#searchEntry:focus .search-entry-icon {
.search-entry:hover .search-entry-icon,
.search-entry:focus .search-entry-icon {
color: #8d8f8a;
}
@ -964,6 +1049,8 @@ StScrollBar StButton#vhandle:active {
.app-folder-icon {
padding: 5px;
spacing-rows: 5px;
spacing-columns: 5px;
}
.dash-item-container > StButton {
@ -1072,6 +1159,7 @@ StScrollBar StButton#vhandle:active {
.show-apps:checked > .overview-icon,
.show-apps:active > .overview-icon,
.search-provider-icon:active,
.grid-search-result:active .overview-icon,
.list-search-result:active {
background-gradient-start: rgba(255, 255, 255, .05);
background-gradient-end: rgba(255, 255, 255, .15);
@ -1140,11 +1228,6 @@ StScrollBar StButton#vhandle:active {
text-shadow: black 0px 2px 2px;
}
#LookingGlassDialog .lg-inspector-title {
font-weight: bold;
padding-bottom: 8px;
}
.lg-dialog StEntry {
selection-background-color: #bbbbbb;
selected-color: #333333;
@ -1224,14 +1307,8 @@ StScrollBar StButton#vhandle:active {
width: 0.3em;
}
#calendarPopup .calendar {
padding: 10px;
}
.calendar {
padding: .4em 1.75em .8em 1.75em;
spacing-rows: 0px;
spacing-columns: 0px;
}
.calendar-month-label {
@ -1289,12 +1366,18 @@ StScrollBar StButton#vhandle:active {
font-weight: bold;
text-align: center;
color: #eeeeec;
border-radius: 4px;
}
.datemenu-date-label:hover,
.datemenu-date-label:focus {
background-color: #999999;
}
.datemenu-date-label:active {
background-color: #aaaaaa;
}
.calendar-day-base {
font-size: 9pt;
text-align: center;
@ -1421,11 +1504,8 @@ StScrollBar StButton#vhandle:active {
padding-right: 8pt;
}
.url-highlighter {
link-color: #ccccff;
}
/* Message Tray */
#message-tray {
background: #2e3436 url(message-tray-background.png);
background-repeat: repeat;
@ -1448,8 +1528,11 @@ StScrollBar StButton#vhandle:active {
color: #eeeeee;
}
.no-messages-label,
.no-networks-label {
.url-highlighter {
link-color: #ccccff;
}
.no-messages-label {
color: #999999;
}
@ -1630,8 +1713,8 @@ StScrollBar StButton#vhandle:active {
color: #888888;
}
.chat-group-sent, .chat-group-meta {
padding: 8px 0;
.chat-empty-line {
font-size: 4px;
}
.chat-received {
@ -1656,6 +1739,7 @@ StScrollBar StButton#vhandle:active {
.chat-meta-message {
padding-left: 4px;
font-size: 9pt;
font-weight: bold;
color: #bbbbbb;
}
@ -1745,26 +1829,6 @@ StScrollBar StButton#vhandle:active {
spacing: 8px;
}
.thumbnail-scroll-gradient-left {
background-gradient-direction: horizontal;
background-gradient-start: rgba(51, 51, 51, 1.0);
background-gradient-end: rgba(51, 51, 51, 0);
border-radius: 24px;
border-radius-topright: 0px;
border-radius-bottomright: 0px;
width: 60px;
}
.thumbnail-scroll-gradient-right {
background-gradient-direction: horizontal;
background-gradient-start: rgba(51, 51, 51, 0);
background-gradient-end: rgba(51, 51, 51, 1.0);
border-radius: 24px;
border-radius-topleft: 0px;
border-radius-bottomleft: 0px;
width: 60px;
}
.switcher-list .item-box {
padding: 8px;
border-radius: 8px;
@ -1857,6 +1921,27 @@ StScrollBar StButton#vhandle:active {
border-radius: 8px;
}
/* Tile previews */
.tile-preview {
background-color: rgba(74, 144, 217, 0.35);
border: 1px solid #4a90d9; /* Adwaita selected bg color */
}
.tile-preview-left.on-primary {
/* keep in sync with -panel-corner-radius */
border-radius: 6px 0 0 0;
}
.tile-preview-right.on-primary {
/* keep in sync with -panel-corner-radius */
border-radius: 0 6px 0 0;
}
.tile-preview-left.tile-preview-right.on-primary {
/* keep in sync with -panel-corner-radius */
border-radius: 6px 6px 0 0;
}
/* Modal Dialogs */
/* Dialog Subject Text Style */
@ -1927,45 +2012,57 @@ StScrollBar StButton#vhandle:active {
padding-top: 20px;
}
.end-session-dialog-subject {
.end-session-dialog-layout {
padding-left: 17px;
padding-bottom: 20px;
}
.end-session-dialog-subject:rtl {
padding-left: 0px;
.end-session-dialog-layout:rtl {
padding-right: 17px;
}
.end-session-dialog-description {
padding-left: 17px;
width: 28em;
padding-bottom: 10px;
}
.end-session-dialog-description:rtl {
padding-right: 17px;
width: 28em;
padding-bottom: 10px;
text-align: right;
}
.end-session-dialog-warning {
width: 28em;
color: #f57900;
padding-top: 6px;
}
.end-session-dialog-warning:rtl {
width: 28em;
color: #f57900;
padding-top: 6px;
text-align: right;
}
.end-session-dialog-logout-icon {
border: 2px solid #8b8b8b;
border-radius: 5px;
width: 32px;
height: 32px;
width: 48px;
height: 48px;
background-size: contain;
}
.end-session-dialog-shutdown-icon {
color: #bebebe;
width: 32px;
height: 32px;
width: 48px;
height: 48px;
}
.end-session-dialog-inhibitor-layout {
spacing: 16px;
max-height: 200px;
padding-right: 50px;
padding-left: 50px;
padding-right: 65px;
padding-left: 65px;
}
.end-session-dialog-session-list,
@ -1996,15 +2093,16 @@ StScrollBar StButton#vhandle:active {
font-size: 10pt;
}
/* Restart message */
.restart-message {
font-size: 14pt;
}
/* ShellMountOperation Dialogs */
.shell-mount-operation-icon {
icon-size: 48px;
}
.mount-password-reask {
color: red;
}
.show-processes-dialog,
.mount-question-dialog {
spacing: 24px;
@ -2300,13 +2398,6 @@ StScrollBar StButton#vhandle:active {
padding-bottom: 1em;
}
.login-dialog-title {
font-size: 14pt;
font-weight: bold;
color: #666666;
padding-bottom: 2em;
}
.login-dialog {
/* Reset border and background */
border: none;
@ -2355,10 +2446,6 @@ StScrollBar StButton#vhandle:active {
background-size: contain;
}
.login-dialog-user-list-item-text-box {
padding: 0 0.5em;
}
.login-dialog-user-list-item .login-dialog-timed-login-indicator {
background-color: rgba(0,0,0,0.0);
height: 2px;
@ -2388,12 +2475,13 @@ StScrollBar StButton#vhandle:active {
color: #E8E8E8;
}
.login-dialog-username {
.login-dialog-username,
.user-widget-label {
font-size: 16pt;
font-weight: bold;
text-align: left;
padding-left: 15px;
text-shadow: black 0px 4px 3px 0px;
text-shadow: rgba(0, 0, 0, 0.5) 0px 2px 1px 0px;
}
.login-dialog-prompt-layout {
@ -2485,11 +2573,6 @@ StScrollBar StButton#vhandle:active {
}
.user-widget-label {
font-size: 20px;
font-weight: bold;
text-align: left;
color:white;
text-shadow: black 0px 4px 3px 0px;
}
.user-widget-label:ltr {

View File

@ -66,6 +66,7 @@ IGNORE_HFILES= \
gactionmuxer.h \
gactionobservable.h \
gactionobserver.h \
shell-network-agent.h \
shell-recorder-src.h
if !BUILD_RECORDER

View File

@ -50,7 +50,6 @@
<xi:include href="xml/shell-wm.xml"/>
<xi:include href="xml/shell-util.xml"/>
<xi:include href="xml/shell-mount-operation.xml"/>
<xi:include href="xml/shell-network-agent.xml"/>
<xi:include href="xml/shell-polkit-authentication-agent.xml"/>
<xi:include href="xml/shell-tp-client.xml"/>
</chapter>

View File

@ -17,19 +17,19 @@ packages. If you are interested in building GNOME Shell from source,
we would recommend building from version control using the build
script described at:
http://live.gnome.org/GnomeShell
https://wiki.gnome.org/Projects/GnomeShell
Not only will that give you the very latest version of this rapidly
changing project, it will be much easier than get GNOME Shell and
its dependencies to build from tarballs.</description>
<!--
<homepage rdf:resource="http://live.gnome.org/GnomeShell" />
-->
<homepage rdf:resource="https://wiki.gnome.org/Projects/GnomeShell" />
<mailing-list rdf:resource="http://mail.gnome.org/mailman/listinfo/gnome-shell-list" />
<download-page rdf:resource="http://download.gnome.org/sources/gnome-shell/" />
<bug-database rdf:resource="http://bugzilla.gnome.org/browse.cgi?product=gnome-shell" />
<bug-database rdf:resource="https://bugzilla.gnome.org/browse.cgi?product=gnome-shell" />
<category rdf:resource="http://api.gnome.org/doap-extensions#desktop" />
<category rdf:resource="http://api.gnome.org/doap-extensions#core" />
<programming-language>JavaScript</programming-language>
<programming-language>C</programming-language>
<maintainer>
<foaf:Person>

View File

@ -6,13 +6,14 @@ misc/config.js: misc/config.js.in Makefile
sed -e "s|[@]PACKAGE_NAME@|$(PACKAGE_NAME)|g" \
-e "s|[@]PACKAGE_VERSION@|$(PACKAGE_VERSION)|g" \
-e "s|[@]HAVE_BLUETOOTH@|$(HAVE_BLUETOOTH)|g" \
-e "s|[@]HAVE_NETWORKMANAGER@|$(HAVE_NETWORKMANAGER)|g" \
-e "s|[@]GETTEXT_PACKAGE@|$(GETTEXT_PACKAGE)|g" \
-e "s|[@]datadir@|$(datadir)|g" \
-e "s|[@]libexecdir@|$(libexecdir)|g" \
-e "s|[@]sysconfdir@|$(sysconfdir)|g" \
$< > $@
js_resource_files = $(shell $(GLIB_COMPILE_RESOURCES) --sourcedir=$(srcdir) --generate-dependencies $(srcdir)/js-resources.gresource.xml)
js_resource_files = $(shell $(GLIB_COMPILE_RESOURCES) --sourcedir=$(srcdir) --sourcedir=$(builddir) --generate-dependencies $(srcdir)/js-resources.gresource.xml)
js-resources.h: js-resources.gresource.xml $(js_resource_files) misc/config.js
$(AM_V_GEN) $(GLIB_COMPILE_RESOURCES) --target=$@ --sourcedir=$(srcdir) --sourcedir=$(builddir) --generate --c-name shell_js_resources $<
js-resources.c: js-resources.gresource.xml $(js_resource_files) misc/config.js

View File

@ -23,6 +23,11 @@ const GnomeShellIface = '<node> \
</interface> \
</node>';
const customCss = '.prefs-button { \
padding: 8px; \
border-radius: 20px; \
}';
const GnomeShellProxy = Gio.DBusProxy.makeProxyWrapper(GnomeShellIface);
function stripPrefix(string, prefix) {
@ -46,13 +51,10 @@ const Application = new Lang.Class({
this._extensionPrefsModules = {};
this._extensionIters = {};
this._startupUuid = null;
},
_buildModel: function() {
this._model = new Gtk.ListStore();
this._model.set_column_types([GObject.TYPE_STRING, GObject.TYPE_STRING]);
this._loaded = false;
this._skipMainWindow = false;
this._settings = new Gio.Settings({ schema_id: 'org.gnome.shell' });
},
_extensionAvailable: function(uuid) {
@ -61,20 +63,12 @@ const Application = new Lang.Class({
if (!extension)
return false;
if (ExtensionUtils.isOutOfDate(extension))
return false;
if (!extension.dir.get_child('prefs.js').query_exists(null))
return false;
return true;
},
_setExtensionInsensitive: function(layout, cell, model, iter, data) {
let uuid = model.get_value(iter, 0);
cell.set_sensitive(this._extensionAvailable(uuid));
},
_getExtensionPrefsModule: function(extension) {
let uuid = extension.metadata.uuid;
@ -104,21 +98,23 @@ const Application = new Lang.Class({
widget = this._buildErrorUI(extension, e);
}
// Destroy the current prefs widget, if it exists
if (this._extensionPrefsBin.get_child())
this._extensionPrefsBin.get_child().destroy();
let dialog = new Gtk.Dialog({ use_header_bar: true,
modal: true,
title: extension.metadata.name });
this._extensionPrefsBin.add(widget);
this._extensionSelector.set_active_iter(this._extensionIters[uuid]);
},
if (this._skipMainWindow) {
this.application.add_window(dialog);
if (this._window)
this._window.destroy();
this._window = dialog;
this._window.window_position = Gtk.WindowPosition.CENTER;
} else {
dialog.transient_for = this._window;
}
_extensionSelected: function() {
let [success, iter] = this._extensionSelector.get_active_iter();
if (!success)
return;
let uuid = this._model.get_value(iter, 0);
this._selectExtension(uuid);
dialog.set_default_size(600, 400);
dialog.get_content_area().add(widget);
dialog.show();
},
_buildErrorUI: function(extension, exc) {
@ -151,48 +147,26 @@ const Application = new Lang.Class({
_buildUI: function(app) {
this._window = new Gtk.ApplicationWindow({ application: app,
window_position: Gtk.WindowPosition.CENTER,
title: _("GNOME Shell Extension Preferences") });
window_position: Gtk.WindowPosition.CENTER });
this._window.set_size_request(600, 400);
this._window.set_size_request(800, 500);
let vbox = new Gtk.Box({ orientation: Gtk.Orientation.VERTICAL });
this._window.add(vbox);
this._titlebar = new Gtk.HeaderBar({ show_close_button: true,
title: _("GNOME Shell Extensions") });
this._window.set_titlebar(this._titlebar);
let toolbar = new Gtk.Toolbar();
toolbar.get_style_context().add_class(Gtk.STYLE_CLASS_PRIMARY_TOOLBAR);
vbox.add(toolbar);
let toolitem;
let scroll = new Gtk.ScrolledWindow({ hscrollbar_policy: Gtk.PolicyType.NEVER,
shadow_type: Gtk.ShadowType.IN,
halign: Gtk.Align.CENTER,
margin: 18 });
this._window.add(scroll);
let label = new Gtk.Label({ label: '<b>' + _("Extension") + '</b>',
use_markup: true });
toolitem = new Gtk.ToolItem({ child: label });
toolbar.add(toolitem);
this._extensionSelector = new Gtk.ListBox({ selection_mode: Gtk.SelectionMode.NONE });
this._extensionSelector.set_sort_func(Lang.bind(this, this._sortList));
this._extensionSelector.set_header_func(Lang.bind(this, this._updateHeader));
this._extensionSelector = new Gtk.ComboBox({ model: this._model,
margin_left: 8,
hexpand: true });
this._extensionSelector.get_style_context().add_class(Gtk.STYLE_CLASS_RAISED);
scroll.add(this._extensionSelector);
let renderer = new Gtk.CellRendererText();
this._extensionSelector.pack_start(renderer, true);
this._extensionSelector.add_attribute(renderer, 'text', 1);
this._extensionSelector.set_cell_data_func(renderer, Lang.bind(this, this._setExtensionInsensitive));
this._extensionSelector.connect('changed', Lang.bind(this, this._extensionSelected));
toolitem = new Gtk.ToolItem({ child: this._extensionSelector });
toolitem.set_expand(true);
toolbar.add(toolitem);
this._extensionPrefsBin = new Gtk.Frame();
vbox.add(this._extensionPrefsBin);
let label = new Gtk.Label({
label: _("Select an extension to configure using the combobox above."),
vexpand: true
});
this._extensionPrefsBin.add(label);
this._shellProxy = new GnomeShellProxy(Gio.DBus.session, 'org.gnome.Shell', '/org/gnome/Shell');
this._shellProxy.connectSignal('ExtensionStatusChanged', Lang.bind(this, function(proxy, senderName, [uuid, state, error]) {
@ -203,6 +177,35 @@ const Application = new Lang.Class({
this._window.show_all();
},
_addCustomStyle: function() {
let provider = new Gtk.CssProvider();
try {
provider.load_from_data(customCss, -1);
} catch(e) {
log('Failed to add application style');
return;
}
let screen = this._window.window.get_screen();
let priority = Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION;
Gtk.StyleContext.add_provider_for_screen(screen, provider, priority);
},
_sortList: function(row1, row2) {
let name1 = ExtensionUtils.extensions[row1.uuid].metadata.name;
let name2 = ExtensionUtils.extensions[row2.uuid].metadata.name;
return name1.localeCompare(name2);
},
_updateHeader: function(row, before) {
if (!before || row.get_header())
return;
let sep = new Gtk.Separator({ orientation: Gtk.Orientation.HORIZONTAL });
row.set_header(sep);
},
_scanExtensions: function() {
let finder = new ExtensionUtils.ExtensionFinder();
finder.connect('extension-found', Lang.bind(this, this._extensionFound));
@ -211,15 +214,24 @@ const Application = new Lang.Class({
},
_extensionFound: function(finder, extension) {
let iter = this._model.append();
this._model.set(iter, [0, 1], [extension.uuid, extension.metadata.name]);
this._extensionIters[extension.uuid] = iter;
let row = new ExtensionRow(extension.uuid);
row.prefsButton.visible = this._extensionAvailable(row.uuid);
row.prefsButton.connect('clicked', Lang.bind(this,
function() {
this._selectExtension(row.uuid);
}));
row.show_all();
this._extensionSelector.add(row);
},
_extensionsLoaded: function() {
if (this._startupUuid && this._extensionAvailable(this._startupUuid))
this._selectExtension(this._startupUuid);
this._startupUuid = null;
this._skipMainWindow = false;
this._loaded = true;
},
_onActivate: function() {
@ -227,29 +239,137 @@ const Application = new Lang.Class({
},
_onStartup: function(app) {
this._buildModel();
this._buildUI(app);
this._addCustomStyle();
this._scanExtensions();
},
_onCommandLine: function(app, commandLine) {
app.activate();
let args = commandLine.get_arguments();
if (args.length) {
let uuid = args[0];
this._skipMainWindow = true;
// Strip off "extension:///" prefix which fakes a URI, if it exists
uuid = stripPrefix(uuid, "extension:///");
if (this._extensionAvailable(uuid))
this._selectExtension(uuid);
else
else if (!this._loaded)
this._startupUuid = uuid;
else
this._skipMainWindow = false;
}
return 0;
}
});
const ExtensionRow = new Lang.Class({
Name: 'ExtensionRow',
Extends: Gtk.ListBoxRow,
_init: function(uuid) {
this.parent();
this.uuid = uuid;
this._settings = new Gio.Settings({ schema_id: 'org.gnome.shell' });
this._settings.connect('changed::enabled-extensions', Lang.bind(this,
function() {
this._switch.state = this._isEnabled();
}));
this._settings.connect('changed::disable-extension-version-validation',
Lang.bind(this, function() {
this._switch.sensitive = this._canEnable();
}));
this._buildUI();
},
_buildUI: function() {
let extension = ExtensionUtils.extensions[this.uuid];
let hbox = new Gtk.Box({ orientation: Gtk.Orientation.HORIZONTAL,
hexpand: true, margin: 12, spacing: 6 });
this.add(hbox);
let vbox = new Gtk.Box({ orientation: Gtk.Orientation.VERTICAL,
spacing: 6, hexpand: true });
hbox.add(vbox);
let name = GLib.markup_escape_text(extension.metadata.name, -1);
let label = new Gtk.Label({ label: '<b>' + name + '</b>',
use_markup: true,
halign: Gtk.Align.START });
vbox.add(label);
let desc = extension.metadata.description.split('\n')[0];
label = new Gtk.Label({ label: desc,
ellipsize: Pango.EllipsizeMode.END,
halign: Gtk.Align.START });
vbox.add(label);
let button = new Gtk.Button({ valign: Gtk.Align.CENTER,
no_show_all: true });
button.add(new Gtk.Image({ icon_name: 'emblem-system-symbolic',
icon_size: Gtk.IconSize.BUTTON,
visible: true }));
button.get_style_context().add_class('prefs-button');
hbox.add(button);
this.prefsButton = button;
this._switch = new Gtk.Switch({ valign: Gtk.Align.CENTER,
sensitive: this._canEnable(),
state: this._isEnabled() });
this._switch.connect('notify::active', Lang.bind(this,
function() {
if (this._switch.active)
this._enable();
else
this._disable();
}));
this._switch.connect('state-set', function() { return true; });
hbox.add(this._switch);
},
_canEnable: function() {
let extension = ExtensionUtils.extensions[this.uuid];
let checkVersion = !this._settings.get_boolean('disable-extension-version-validation');
return !(checkVersion && ExtensionUtils.isOutOfDate(extension));
},
_isEnabled: function() {
let extensions = this._settings.get_strv('enabled-extensions');
return extensions.indexOf(this.uuid) != -1;
},
_enable: function() {
let extensions = this._settings.get_strv('enabled-extensions');
if (extensions.indexOf(this.uuid) != -1)
return;
extensions.push(this.uuid);
this._settings.set_strv('enabled-extensions', extensions);
},
_disable: function() {
let extensions = this._settings.get_strv('enabled-extensions');
let pos = extensions.indexOf(this.uuid);
if (pos == -1)
return;
do {
extensions.splice(pos, 1);
pos = extensions.indexOf(this.uuid);
} while (pos != -1);
this._settings.set_strv('enabled-extensions', extensions);
}
});
function initEnvironment() {
// Monkey-patch in a "global" object that fakes some Shell utilities
// that ExtensionUtils depends on.

View File

@ -450,8 +450,7 @@ const AuthPrompt = new Lang.Class({
// respond to the request with the username
beginRequestType = BeginRequestType.PROVIDE_USERNAME;
} else if (this._userVerifier.serviceIsForeground(GdmUtil.OVIRT_SERVICE_NAME) ||
(this.smartcardDetected &&
this._userVerifier.serviceIsForeground(GdmUtil.SMARTCARD_SERVICE_NAME))) {
this._userVerifier.serviceIsForeground(GdmUtil.SMARTCARD_SERVICE_NAME)) {
// We don't need to know the username if the user preempted the login screen
// with a smartcard or with preauthenticated oVirt credentials
beginRequestType = BeginRequestType.DONT_PROVIDE_USERNAME;

View File

@ -36,6 +36,7 @@ const BoxPointer = imports.ui.boxpointer;
const CtrlAltTab = imports.ui.ctrlAltTab;
const GdmUtil = imports.gdm.util;
const Layout = imports.ui.layout;
const LoginManager = imports.misc.loginManager;
const Main = imports.ui.main;
const PopupMenu = imports.ui.popupMenu;
const Realmd = imports.gdm.realmd;
@ -47,8 +48,6 @@ const _SCROLL_ANIMATION_TIME = 0.5;
const _TIMED_LOGIN_IDLE_THRESHOLD = 5.0;
const _LOGO_ICON_HEIGHT = 48;
let _loginDialog = null;
const UserListItem = new Lang.Class({
Name: 'UserListItem',
@ -383,7 +382,7 @@ const LoginDialog = new Lang.Class({
Lang.bind(this, this._onTimedLoginRequested));
}
this._settings = new Gio.Settings({ schema: GdmUtil.LOGIN_SCREEN_SCHEMA });
this._settings = new Gio.Settings({ schema_id: GdmUtil.LOGIN_SCREEN_SCHEMA });
this._settings.connect('changed::' + GdmUtil.BANNER_MESSAGE_KEY,
Lang.bind(this, this._updateBanner));
@ -469,7 +468,20 @@ const LoginDialog = new Lang.Class({
this._sessionMenuButton.actor.show();
this._authPrompt.addActorToDefaultButtonWell(this._sessionMenuButton.actor);
if (!this._userManager.is_loaded)
this._disableUserList = undefined;
this._userListLoaded = false;
LoginManager.getLoginManager().getCurrentSessionProxy(Lang.bind(this, this._gotGreeterSessionProxy));
// If the user list is enabled, it should take key focus; make sure the
// screen shield is initialized first to prevent it from stealing the
// focus later
Main.layoutManager.connect('startup-complete',
Lang.bind(this, this._updateDisableUserList));
},
_ensureUserListLoaded: function() {
if (!this._userManager.is_loaded) {
this._userManagerLoadedId = this._userManager.connect('notify::is-loaded',
Lang.bind(this, function() {
if (this._userManager.is_loaded) {
@ -478,10 +490,11 @@ const LoginDialog = new Lang.Class({
this._userManagerLoadedId = 0;
}
}));
else
GLib.idle_add(GLib.PRIORITY_DEFAULT, Lang.bind(this, this._loadUserList));
},
} else {
let id = GLib.idle_add(GLib.PRIORITY_DEFAULT, Lang.bind(this, this._loadUserList));
GLib.Source.set_name_by_id(id, '[gnome-shell] _loadUserList');
}
},
_updateDisableUserList: function() {
let disableUserList = this._settings.get_boolean(GdmUtil.DISABLE_USER_LIST_KEY);
@ -524,9 +537,12 @@ const LoginDialog = new Lang.Class({
return;
this._logoBin.destroy_all_children();
if (this._logoFileUri)
if (this._logoFileUri) {
let scaleFactor = St.ThemeContext.get_for_stage(global.stage).scale_factor;
this._logoBin.add_child(this._textureCache.load_uri_async(this._logoFileUri,
-1, _LOGO_ICON_HEIGHT));
-1, _LOGO_ICON_HEIGHT,
scaleFactor));
}
},
_updateLogo: function() {
@ -625,6 +641,36 @@ const LoginDialog = new Lang.Class({
this._showPrompt();
},
_loginScreenSessionActivated: function() {
if (this._authPrompt.verificationStatus != AuthPrompt.AuthPromptStatus.VERIFICATION_SUCCEEDED)
return;
Tweener.addTween(this.actor,
{ opacity: 255,
time: _FADE_ANIMATION_TIME,
transition: 'easeOutQuad',
onUpdate: function() {
let children = Main.layoutManager.uiGroup.get_children();
for (let i = 0; i < children.length; i++) {
if (children[i] != Main.layoutManager.screenShieldGroup)
children[i].opacity = this.actor.opacity;
}
},
onUpdateScope: this,
onComplete: function() {
this._authPrompt.reset();
},
onCompleteScope: this });
},
_gotGreeterSessionProxy: function(proxy) {
proxy.connect('g-properties-changed', Lang.bind(this, function() {
if (proxy.Active)
this._loginScreenSessionActivated();
}));
},
_startSession: function(serviceName) {
Tweener.addTween(this.actor,
{ opacity: 0,
@ -640,10 +686,11 @@ const LoginDialog = new Lang.Class({
},
onUpdateScope: this,
onComplete: function() {
Mainloop.idle_add(Lang.bind(this, function() {
let id = Mainloop.idle_add(Lang.bind(this, function() {
this._greeter.call_start_session_when_ready_sync(serviceName, true, null);
return GLib.SOURCE_REMOVE;
}));
GLib.Source.set_name_by_id(id, '[gnome-shell] this._greeter.call_start_session_when_ready_sync');
},
onCompleteScope: this });
},
@ -699,6 +746,7 @@ const LoginDialog = new Lang.Class({
hold.release();
return GLib.SOURCE_REMOVE;
});
GLib.Source.set_name_by_id(this._timedLoginIdleTimeOutId, '[gnome-shell] this._timedLoginAnimationTime');
return hold;
},
@ -801,6 +849,7 @@ const LoginDialog = new Lang.Class({
},
_showUserList: function() {
this._ensureUserListLoaded();
this._authPrompt.hide();
this._sessionMenuButton.close();
this._setUserListExpanded(true);
@ -844,14 +893,17 @@ const LoginDialog = new Lang.Class({
},
_loadUserList: function() {
if (this._userListLoaded)
return GLib.SOURCE_REMOVE;
this._userListLoaded = true;
let users = this._userManager.list_users();
for (let i = 0; i < users.length; i++) {
this._userList.addUser(users[i]);
}
this._updateDisableUserList();
this._userManager.connect('user-added',
Lang.bind(this, function(userManager, user) {
this._userList.addUser(user);
@ -861,6 +913,8 @@ const LoginDialog = new Lang.Class({
Lang.bind(this, function(userManager, user) {
this._userList.removeUser(user);
}));
return GLib.SOURCE_REMOVE;
},
open: function() {
@ -872,6 +926,8 @@ const LoginDialog = new Lang.Class({
this.actor.show();
this.actor.opacity = 0;
Main.pushModal(this.actor, { keybindingMode: Shell.KeyBindingMode.LOGIN_SCREEN });
Tweener.addTween(this.actor,
{ opacity: 255,
time: 1,
@ -881,7 +937,8 @@ const LoginDialog = new Lang.Class({
},
close: function() {
Main.ctrlAltTabManager.removeGroup(this.dialogLayout);
Main.popModal(this.actor);
Main.ctrlAltTabManager.removeGroup(this.actor);
},
cancel: function() {

View File

@ -128,7 +128,7 @@ const ShellUserVerifier = new Lang.Class({
this._client = client;
this._settings = new Gio.Settings({ schema: LOGIN_SCREEN_SCHEMA });
this._settings = new Gio.Settings({ schema_id: LOGIN_SCREEN_SCHEMA });
this._settings.connect('changed',
Lang.bind(this, this._updateDefaultService));
this._updateDefaultService();
@ -252,6 +252,7 @@ const ShellUserVerifier = new Lang.Class({
this._queueMessageTimeout();
return GLib.SOURCE_REMOVE;
}));
GLib.Source.set_name_by_id(this._messageQueueTimeoutId, '[gnome-shell] this._queueMessageTimeout');
},
_queueMessage: function(message, messageType) {
@ -298,7 +299,7 @@ const ShellUserVerifier = new Lang.Class({
if (!this._settings.get_boolean(SMARTCARD_AUTHENTICATION_KEY))
smartcardDetected = false;
else if (this.reauthenticating)
else if (this._reauthOnly)
smartcardDetected = this._smartcardManager.hasInsertedLoginToken();
else
smartcardDetected = this._smartcardManager.hasInsertedTokens();

View File

@ -16,7 +16,9 @@
<file>misc/fileUtils.js</file>
<file>misc/gnomeSession.js</file>
<file>misc/history.js</file>
<file>misc/ibusManager.js</file>
<file>misc/jsParse.js</file>
<file>misc/keyboardManager.js</file>
<file>misc/loginManager.js</file>
<file>misc/modemManager.js</file>
<file>misc/objectManager.js</file>
@ -25,6 +27,9 @@
<file>misc/util.js</file>
<file>perf/core.js</file>
<file>perf/hwtest.js</file>
<file>portalHelper/main.js</file>
<file>ui/altTab.js</file>
<file>ui/animation.js</file>
@ -39,6 +44,7 @@
<file>ui/dash.js</file>
<file>ui/dateMenu.js</file>
<file>ui/dnd.js</file>
<file>ui/edgeDragAction.js</file>
<file>ui/endSessionDialog.js</file>
<file>ui/environment.js</file>
<file>ui/extensionDownloader.js</file>
@ -84,6 +90,7 @@
<file>ui/userWidget.js</file>
<file>ui/viewSelector.js</file>
<file>ui/windowAttentionHandler.js</file>
<file>ui/windowMenu.js</file>
<file>ui/windowManager.js</file>
<file>ui/workspace.js</file>
<file>ui/workspaceSwitcherPopup.js</file>

View File

@ -6,6 +6,8 @@ const PACKAGE_NAME = '@PACKAGE_NAME@';
const PACKAGE_VERSION = '@PACKAGE_VERSION@';
/* 1 if gnome-bluetooth is available, 0 otherwise */
const HAVE_BLUETOOTH = @HAVE_BLUETOOTH@;
/* 1 if networkmanager is available, 0 otherwise */
const HAVE_NETWORKMANAGER = @HAVE_NETWORKMANAGER@;
/* gettext package */
const GETTEXT_PACKAGE = '@GETTEXT_PACKAGE@';
/* locale dir */

180
js/misc/ibusManager.js Normal file
View File

@ -0,0 +1,180 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
const Gio = imports.gi.Gio;
const Lang = imports.lang;
const Signals = imports.signals;
try {
var IBus = imports.gi.IBus;
if (!('new_async' in IBus.Bus))
throw "IBus version is too old";
const IBusCandidatePopup = imports.ui.ibusCandidatePopup;
} catch (e) {
var IBus = null;
log(e);
}
let _ibusManager = null;
function getIBusManager() {
if (_ibusManager == null)
_ibusManager = new IBusManager();
return _ibusManager;
}
const IBusManager = new Lang.Class({
Name: 'IBusManager',
// This is the longest we'll keep the keyboard frozen until an input
// source is active.
_MAX_INPUT_SOURCE_ACTIVATION_TIME: 4000, // ms
_init: function() {
if (!IBus)
return;
IBus.init();
this._candidatePopup = new IBusCandidatePopup.CandidatePopup();
this._panelService = null;
this._engines = {};
this._ready = false;
this._registerPropertiesId = 0;
this._currentEngineName = null;
this._ibus = IBus.Bus.new_async();
this._ibus.connect('connected', Lang.bind(this, this._onConnected));
this._ibus.connect('disconnected', Lang.bind(this, this._clear));
// Need to set this to get 'global-engine-changed' emitions
this._ibus.set_watch_ibus_signal(true);
this._ibus.connect('global-engine-changed', Lang.bind(this, this._engineChanged));
this._spawn();
},
_spawn: function() {
try {
Gio.Subprocess.new(['ibus-daemon', '--xim', '--panel', 'disable'],
Gio.SubprocessFlags.NONE);
} catch(e) {
log('Failed to launch ibus-daemon: ' + e.message);
}
},
_clear: function() {
if (this._panelService)
this._panelService.destroy();
this._panelService = null;
this._candidatePopup.setPanelService(null);
this._engines = {};
this._ready = false;
this._registerPropertiesId = 0;
this._currentEngineName = null;
this.emit('ready', false);
this._spawn();
},
_onConnected: function() {
this._ibus.list_engines_async(-1, null, Lang.bind(this, this._initEngines));
this._ibus.request_name_async(IBus.SERVICE_PANEL,
IBus.BusNameFlag.REPLACE_EXISTING,
-1, null,
Lang.bind(this, this._initPanelService));
},
_initEngines: function(ibus, result) {
let enginesList = this._ibus.list_engines_async_finish(result);
if (enginesList) {
for (let i = 0; i < enginesList.length; ++i) {
let name = enginesList[i].get_name();
this._engines[name] = enginesList[i];
}
this._updateReadiness();
} else {
this._clear();
}
},
_initPanelService: function(ibus, result) {
let success = this._ibus.request_name_async_finish(result);
if (success) {
this._panelService = new IBus.PanelService({ connection: this._ibus.get_connection(),
object_path: IBus.PATH_PANEL });
this._candidatePopup.setPanelService(this._panelService);
this._panelService.connect('update-property', Lang.bind(this, this._updateProperty));
// If an engine is already active we need to get its properties
this._ibus.get_global_engine_async(-1, null, Lang.bind(this, function(i, result) {
let engine;
try {
engine = this._ibus.get_global_engine_async_finish(result);
if (!engine)
return;
} catch(e) {
return;
}
this._engineChanged(this._ibus, engine.get_name());
}));
this._updateReadiness();
} else {
this._clear();
}
},
_updateReadiness: function() {
this._ready = (Object.keys(this._engines).length > 0 &&
this._panelService != null);
this.emit('ready', this._ready);
},
_engineChanged: function(bus, engineName) {
if (!this._ready)
return;
this._currentEngineName = engineName;
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', this._currentEngineName, props);
}));
},
_updateProperty: function(panel, prop) {
this.emit('property-updated', this._currentEngineName, prop);
},
activateProperty: function(key, state) {
this._panelService.property_activate(key, state);
},
getEngineDesc: function(id) {
if (!IBus || !this._ready)
return null;
return this._engines[id];
},
setEngine: function(id, callback) {
if (!IBus || !this._ready || id == this._currentEngineName) {
if (callback)
callback();
return;
}
this._ibus.set_global_engine_async(id, this._MAX_INPUT_SOURCE_ACTIVATION_TIME,
null, callback);
},
});
Signals.addSignalMethods(IBusManager.prototype);

153
js/misc/keyboardManager.js Normal file
View File

@ -0,0 +1,153 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
const GLib = imports.gi.GLib;
const GnomeDesktop = imports.gi.GnomeDesktop;
const Lang = imports.lang;
const Meta = imports.gi.Meta;
const Main = imports.ui.main;
const DEFAULT_LOCALE = 'en_US';
const DEFAULT_LAYOUT = 'us';
const DEFAULT_VARIANT = '';
let _xkbInfo = null;
function getXkbInfo() {
if (_xkbInfo == null)
_xkbInfo = new GnomeDesktop.XkbInfo();
return _xkbInfo;
}
let _keyboardManager = null;
function getKeyboardManager() {
if (_keyboardManager == null)
_keyboardManager = new KeyboardManager();
return _keyboardManager;
}
function releaseKeyboard() {
if (Main.modalCount > 0)
global.display.unfreeze_keyboard(global.get_current_time());
else
global.display.ungrab_keyboard(global.get_current_time());
}
function holdKeyboard() {
global.freeze_keyboard(global.get_current_time());
}
const KeyboardManager = new Lang.Class({
Name: 'KeyboardManager',
// The XKB protocol doesn't allow for more that 4 layouts in a
// keymap. Wayland doesn't impose this limit and libxkbcommon can
// handle up to 32 layouts but since we need to support X clients
// even as a Wayland compositor, we can't bump this.
MAX_LAYOUTS_PER_GROUP: 4,
_init: function() {
this._xkbInfo = getXkbInfo();
this._current = null;
this._localeLayoutInfo = this._getLocaleLayout();
this._layoutInfos = {};
},
_applyLayoutGroup: function(group) {
let options = this._buildOptionsString();
let [layouts, variants] = this._buildGroupStrings(group);
Meta.get_backend().set_keymap(layouts, variants, options);
},
_applyLayoutGroupIndex: function(idx) {
Meta.get_backend().lock_layout_group(idx);
},
apply: function(id) {
let info = this._layoutInfos[id];
if (!info)
return;
if (this._current && this._current.group == info.group) {
if (this._current.groupIndex != info.groupIndex)
this._applyLayoutGroupIndex(info.groupIndex);
} else {
this._applyLayoutGroup(info.group);
this._applyLayoutGroupIndex(info.groupIndex);
}
this._current = info;
},
reapply: function() {
if (!this._current)
return;
this._applyLayoutGroup(this._current.group);
this._applyLayoutGroupIndex(this._current.groupIndex);
},
setUserLayouts: function(ids) {
this._current = null;
this._layoutInfos = {};
for (let i = 0; i < ids.length; ++i) {
let [found, , , _layout, _variant] = this._xkbInfo.get_layout_info(ids[i]);
if (found)
this._layoutInfos[ids[i]] = { id: ids[i], layout: _layout, variant: _variant };
}
let i = 0;
let group = [];
for (let id in this._layoutInfos) {
// We need to leave one slot on each group free so that we
// can add a layout containing the symbols for the
// language used in UI strings to ensure that toolkits can
// handle mnemonics like Alt+Ф even if the user is
// actually typing in a different layout.
let groupIndex = i % (this.MAX_LAYOUTS_PER_GROUP - 1);
if (groupIndex == 0)
group = [];
let info = this._layoutInfos[id];
group[groupIndex] = info;
info.group = group;
info.groupIndex = groupIndex;
i += 1;
}
},
_getLocaleLayout: function() {
let locale = GLib.get_language_names()[0];
if (locale.indexOf('_') == -1)
locale = DEFAULT_LOCALE;
let [found, , id] = GnomeDesktop.get_input_source_from_locale(locale);
if (!found)
[, , id] = GnomeDesktop.get_input_source_from_locale(DEFAULT_LOCALE);
let [found, , , _layout, _variant] = this._xkbInfo.get_layout_info(id);
if (found)
return { layout: _layout, variant: _variant };
else
return { layout: DEFAULT_LAYOUT, variant: DEFAULT_VARIANT };
},
_buildGroupStrings: function(_group) {
let group = _group.concat(this._localeLayoutInfo);
let layouts = group.map(function(g) { return g.layout; }).join(',');
let variants = group.map(function(g) { return g.variant; }).join(',');
return [layouts, variants];
},
setKeyboardOptions: function(options) {
this._xkbOptions = options;
},
_buildOptionsString: function() {
let options = this._xkbOptions.join(',');
return options;
}
});

View File

@ -39,38 +39,13 @@ const SystemdLoginSessionIface = '<node> \
<interface name="org.freedesktop.login1.Session"> \
<signal name="Lock" /> \
<signal name="Unlock" /> \
<property name="Active" type="b" access="read" /> \
</interface> \
</node>';
const SystemdLoginManager = Gio.DBusProxy.makeProxyWrapper(SystemdLoginManagerIface);
const SystemdLoginSession = Gio.DBusProxy.makeProxyWrapper(SystemdLoginSessionIface);
const ConsoleKitManagerIface = '<node> \
<interface name="org.freedesktop.ConsoleKit.Manager"> \
<method name="CanRestart"> \
<arg type="b" direction="out"/> \
</method> \
<method name="CanStop"> \
<arg type="b" direction="out"/> \
</method> \
<method name="Restart" /> \
<method name="Stop" /> \
<method name="GetCurrentSession"> \
<arg type="o" direction="out" /> \
</method> \
</interface> \
</node>';
const ConsoleKitSessionIface = '<node> \
<interface name="org.freedesktop.ConsoleKit.Session"> \
<signal name="Lock" /> \
<signal name="Unlock" /> \
</interface> \
</node>';
const ConsoleKitSession = Gio.DBusProxy.makeProxyWrapper(ConsoleKitSessionIface);
const ConsoleKitManager = Gio.DBusProxy.makeProxyWrapper(ConsoleKitManagerIface);
function haveSystemd() {
return GLib.access("/run/systemd/seats", 0) >= 0;
}
@ -100,7 +75,7 @@ function canLock() {
-1, null);
let version = result.deep_unpack()[0].deep_unpack();
return versionCompare('3.5.91', version);
return haveSystemd() && versionCompare('3.5.91', version);
} catch(e) {
return false;
}
@ -118,7 +93,7 @@ function getLoginManager() {
if (haveSystemd())
_loginManager = new LoginManagerSystemd();
else
_loginManager = new LoginManagerConsoleKit();
_loginManager = new LoginManagerDummy();
}
return _loginManager;
@ -135,9 +110,6 @@ const LoginManagerSystemd = new Lang.Class({
Lang.bind(this, this._prepareForSleep));
},
// Having this function is a bit of a hack since the Systemd and ConsoleKit
// session objects have different interfaces - but in both cases there are
// Lock/Unlock signals, and that's all we count upon at the moment.
getCurrentSessionProxy: function(callback) {
if (this._currentSession) {
callback (this._currentSession);
@ -190,7 +162,7 @@ const LoginManagerSystemd = new Lang.Class({
let fd = -1;
try {
let [outVariant, fdList] = proxy.call_with_unix_fd_list_finish(result);
fd = fdList.steal_fds(outVariant.deep_unpack())[0];
fd = fdList.steal_fds()[0];
callback(new Gio.UnixInputStream({ fd: fd }));
} catch(e) {
logError(e, "Error getting systemd inhibitor");
@ -205,35 +177,13 @@ const LoginManagerSystemd = new Lang.Class({
});
Signals.addSignalMethods(LoginManagerSystemd.prototype);
const LoginManagerConsoleKit = new Lang.Class({
Name: 'LoginManagerConsoleKit',
const LoginManagerDummy = new Lang.Class({
Name: 'LoginManagerDummy',
_init: function() {
this._proxy = new ConsoleKitManager(Gio.DBus.system,
'org.freedesktop.ConsoleKit',
'/org/freedesktop/ConsoleKit/Manager');
},
// Having this function is a bit of a hack since the Systemd and ConsoleKit
// session objects have different interfaces - but in both cases there are
// Lock/Unlock signals, and that's all we count upon at the moment.
getCurrentSessionProxy: function(callback) {
if (this._currentSession) {
callback (this._currentSession);
return;
}
this._proxy.GetCurrentSessionRemote(Lang.bind(this,
function(result, error) {
if (error) {
logError(error, 'Could not get a proxy for the current session');
} else {
this._currentSession = new ConsoleKitSession(Gio.DBus.system,
'org.freedesktop.ConsoleKit',
result[0]);
callback(this._currentSession);
}
}));
// we could return a DummySession object that fakes whatever callers
// expect (at the time of writing: connect() and connectSignal()
// methods), but just never calling the callback should be safer
},
canSuspend: function(asyncCallback) {
@ -253,4 +203,4 @@ const LoginManagerConsoleKit = new Lang.Class({
callback(null);
}
});
Signals.addSignalMethods(LoginManagerConsoleKit.prototype);
Signals.addSignalMethods(LoginManagerDummy.prototype);

View File

@ -129,7 +129,7 @@ function trySpawn(argv)
// Dummy child watch; we don't want to double-fork internally
// because then we lose the parent-child relationship, which
// can break polkit. See https://bugzilla.redhat.com//show_bug.cgi?id=819275
GLib.child_watch_add(GLib.PRIORITY_DEFAULT, pid, function () {}, null);
GLib.child_watch_add(GLib.PRIORITY_DEFAULT, pid, function () {});
}
// trySpawnCommandLine:

View File

@ -72,6 +72,9 @@ function run() {
Scripting.defineScriptEvent("applicationsShowStart", "Starting to switch to applications view");
Scripting.defineScriptEvent("applicationsShowDone", "Done switching to applications view");
// Enable recording of timestamps for different points in the frame cycle
global.frame_timestamps = true;
Main.overview.connect('shown', function() {
Scripting.scriptEvent('overviewShowDone');
});
@ -87,7 +90,10 @@ function run() {
yield Scripting.destroyTestWindows();
for (let k = 0; k < config.count; k++)
yield Scripting.createTestWindow(config.width, config.height, config.alpha, config.maximized);
yield Scripting.createTestWindow({ width: config.width,
height: config.height,
alpha: config.alpha,
maximized: config.maximized });
yield Scripting.waitTestWindows();
yield Scripting.sleep(1000);

308
js/perf/hwtest.js Normal file
View File

@ -0,0 +1,308 @@
const Clutter = imports.gi.Clutter;
const Gio = imports.gi.Gio;
const Gtk = imports.gi.Gtk;
const Meta = imports.gi.Meta;
const Main = imports.ui.main;
const Scripting = imports.ui.scripting;
const Shell = imports.gi.Shell;
let METRICS = {
timeToDesktop:
{ description: "Time from starting graphical.target to desktop showing",
units: "us" },
overviewShowTime:
{ description: "Time to switch to overview view, first time",
units: "us" },
applicationsShowTime:
{ description: "Time to switch to applications view, first time",
units: "us" },
mainViewRedrawTime:
{ description: "Time to redraw the main view, full screen",
units: "us" },
overviewRedrawTime:
{ description: "Time to redraw the overview, full screen, 5 windows",
units: "us" },
applicationRedrawTime:
{ description: "Time to redraw frame with a maximized application update",
units: "us" },
geditStartTime:
{ description: "Time from gedit launch to window drawn",
units: "us" },
}
function waitAndDraw(milliseconds) {
let cb;
let timeline = new Clutter.Timeline({ duration: milliseconds });
timeline.start();
timeline.connect('new-frame',
function(timeline, frame) {
global.stage.queue_redraw();
});
timeline.connect('completed',
function() {
timeline.stop();
if (cb)
cb();
});
return function(callback) {
cb = callback;
};
}
function waitSignal(object, signal) {
let cb;
let id = object.connect(signal, function() {
object.disconnect(id);
if (cb)
cb();
});
return function(callback) {
cb = callback;
};
}
function extractBootTimestamp() {
let sp = Gio.Subprocess.new(['journalctl', '-b',
'MESSAGE_ID=7d4958e842da4a758f6c1cdc7b36dcc5',
'UNIT=graphical.target',
'-o',
'json'],
Gio.SubprocessFlags.STDOUT_PIPE);
let result = null;
let datastream = Gio.DataInputStream.new(sp.get_stdout_pipe());
while (true) {
let [line, length] = datastream.read_line_utf8(null);
if (line === null)
break;
let fields = JSON.parse(line);
result = Number(fields['__MONOTONIC_TIMESTAMP']);
}
datastream.close(null);
return result;
}
function run() {
Scripting.defineScriptEvent("desktopShown", "Finished initial animation");
Scripting.defineScriptEvent("overviewShowStart", "Starting to show the overview");
Scripting.defineScriptEvent("overviewShowDone", "Overview finished showing");
Scripting.defineScriptEvent("applicationsShowStart", "Starting to switch to applications view");
Scripting.defineScriptEvent("applicationsShowDone", "Done switching to applications view");
Scripting.defineScriptEvent("mainViewDrawStart", "Drawing main view");
Scripting.defineScriptEvent("mainViewDrawDone", "Ending timing main view drawing");
Scripting.defineScriptEvent("overviewDrawStart", "Drawing overview");
Scripting.defineScriptEvent("overviewDrawDone", "Ending timing overview drawing");
Scripting.defineScriptEvent("redrawTestStart", "Drawing application window");
Scripting.defineScriptEvent("redrawTestDone", "Ending timing application window drawing");
Scripting.defineScriptEvent("collectTimings", "Accumulate frame timings from redraw tests");
Scripting.defineScriptEvent("geditLaunch", "gedit application launch");
Scripting.defineScriptEvent("geditFirstFrame", "first frame of gedit window drawn");
yield Scripting.waitLeisure();
Scripting.scriptEvent('desktopShown');
Gtk.Settings.get_default().gtk_enable_animations = false;
Scripting.scriptEvent('overviewShowStart');
Main.overview.show();
yield Scripting.waitLeisure();
Scripting.scriptEvent('overviewShowDone');
yield Scripting.sleep(1000);
Scripting.scriptEvent('applicationsShowStart');
Main.overview._dash.showAppsButton.checked = true;
yield Scripting.waitLeisure();
Scripting.scriptEvent('applicationsShowDone');
yield Scripting.sleep(1000);
Main.overview.hide();
yield Scripting.waitLeisure();
////////////////////////////////////////
// Tests of redraw speed
////////////////////////////////////////
global.frame_timestamps = true;
global.frame_finish_timestamp = true;
for (let k = 0; k < 5; k++)
yield Scripting.createTestWindow(640, 480,
{ maximized: true });
yield Scripting.waitTestWindows();
yield Scripting.sleep(1000);
Scripting.scriptEvent('mainViewDrawStart');
yield waitAndDraw(1000);
Scripting.scriptEvent('mainViewDrawDone');
Main.overview.show();
Scripting.waitLeisure();
yield Scripting.sleep(1500);
Scripting.scriptEvent('overviewDrawStart');
yield waitAndDraw(1000);
Scripting.scriptEvent('overviewDrawDone');
yield Scripting.destroyTestWindows();
Main.overview.hide();
yield Scripting.createTestWindow(640, 480,
{ maximized: true,
redraws: true});
yield Scripting.waitTestWindows();
yield Scripting.sleep(1000);
Scripting.scriptEvent('redrawTestStart');
yield Scripting.sleep(1000);
Scripting.scriptEvent('redrawTestDone');
yield Scripting.sleep(1000);
Scripting.scriptEvent('collectTimings');
yield Scripting.destroyTestWindows();
global.frame_timestamps = false;
global.frame_finish_timestamp = false;
yield Scripting.sleep(1000);
////////////////////////////////////////
let appSys = Shell.AppSystem.get_default();
let app = appSys.lookup_app('org.gnome.gedit.desktop');
Scripting.scriptEvent('geditLaunch');
app.activate();
let windows = app.get_windows();
if (windows.length > 0)
throw new Error('gedit was already running');
while (windows.length == 0) {
yield waitSignal(global.display, 'window-created');
windows = app.get_windows();
}
let actor = windows[0].get_compositor_private();
yield waitSignal(actor, 'first-frame');
Scripting.scriptEvent('geditFirstFrame');
yield Scripting.sleep(1000);
windows[0].delete(global.get_current_time());
yield Scripting.sleep(1000);
Gtk.Settings.get_default().gtk_enable_animations = true;
}
let overviewShowStart;
let applicationsShowStart;
let stagePaintStart;
let redrawTiming;
let redrawTimes = {};
let geditLaunchTime;
function script_desktopShown(time) {
let bootTimestamp = extractBootTimestamp();
METRICS.timeToDesktop.value = time - bootTimestamp;
}
function script_overviewShowStart(time) {
overviewShowStart = time;
}
function script_overviewShowDone(time) {
METRICS.overviewShowTime.value = time - overviewShowStart;
}
function script_applicationsShowStart(time) {
applicationsShowStart = time;
}
function script_applicationsShowDone(time) {
METRICS.applicationsShowTime.value = time - applicationsShowStart;
}
function script_mainViewDrawStart(time) {
redrawTiming = 'mainView';
}
function script_mainViewDrawDone(time) {
redrawTiming = null;
}
function script_overviewDrawStart(time) {
redrawTiming = 'overview';
}
function script_overviewDrawDone(time) {
redrawTiming = null;
}
function script_redrawTestStart(time) {
redrawTiming = 'application';
}
function script_redrawTestDone(time) {
redrawTiming = null;
}
function script_collectTimings(time) {
for (let timing in redrawTimes) {
let times = redrawTimes[timing];
times.sort(function(a, b) { return a - b });
let len = times.length;
let median;
if (len == 0)
median = -1;
else if (len % 2 == 1)
median = times[(len - 1)/ 2];
else
median = Math.round((times[len / 2 - 1] + times[len / 2]) / 2);
METRICS[timing + 'RedrawTime'].value = median;
}
}
function script_geditLaunch(time) {
geditLaunchTime = time;
}
function script_geditFirstFrame(time) {
METRICS.geditStartTime.value = time - geditLaunchTime;
}
function clutter_stagePaintStart(time) {
stagePaintStart = time;
}
function clutter_paintCompletedTimestamp(time) {
if (redrawTiming != null && stagePaintStart != null) {
if (!(redrawTiming in redrawTimes))
redrawTimes[redrawTiming] = [];
redrawTimes[redrawTiming].push(time - stagePaintStart);
}
stagePaintStart = null;
}

247
js/portalHelper/main.js Normal file
View File

@ -0,0 +1,247 @@
const Format = imports.format;
const Gettext = imports.gettext;
const GLib = imports.gi.GLib;
const GObject = imports.gi.GObject;
const Gio = imports.gi.Gio;
const Gtk = imports.gi.Gtk;
const Lang = imports.lang;
const Pango = imports.gi.Pango;
const Soup = imports.gi.Soup;
const WebKit = imports.gi.WebKit2;
const _ = Gettext.gettext;
const Config = imports.misc.config;
const PortalHelperResult = {
CANCELLED: 0,
COMPLETED: 1,
RECHECK: 2
};
const INACTIVITY_TIMEOUT = 30000; //ms
const CONNECTIVITY_RECHECK_RATELIMIT_TIMEOUT = 30 * GLib.USEC_PER_SEC;
const HelperDBusInterface = '<node> \
<interface name="org.gnome.Shell.PortalHelper"> \
<method name="Authenticate"> \
<arg type="o" direction="in" name="connection" /> \
<arg type="s" direction="in" name="url" /> \
<arg type="u" direction="in" name="timestamp" /> \
</method> \
<method name="Close"> \
<arg type="o" direction="in" name="connection" /> \
</method> \
<method name="Refresh"> \
<arg type="o" direction="in" name="connection" /> \
</method> \
<signal name="Done"> \
<arg type="o" name="connection" /> \
<arg type="u" name="result" /> \
</signal> \
</interface> \
</node>';
const PortalWindow = new Lang.Class({
Name: 'PortalWindow',
Extends: Gtk.ApplicationWindow,
_init: function(application, url, timestamp, doneCallback) {
this.parent({ application: application });
if (!url) {
url = 'http://www.gnome.org';
this._originalUrlWasGnome = true;
} else {
this._originalUrlWasGnome = false;
}
this._uri = new Soup.URI(url);
this._everSeenRedirect = false;
this._originalUrl = url;
this._doneCallback = doneCallback;
this._lastRecheck = 0;
this._recheckAtExit = false;
this._webView = new WebKit.WebView();
this._webView.connect('decide-policy', Lang.bind(this, this._onDecidePolicy));
this._webView.load_uri(url);
this._webView.connect('notify::title', Lang.bind(this, this._syncTitle));
this._syncTitle();
this.add(this._webView);
this._webView.show();
this.maximize();
this.present_with_time(timestamp);
},
_syncTitle: function() {
let title = this._webView.title;
if (title) {
this.title = title;
} else {
// TRANSLATORS: this is the title of the wifi captive portal login
// window, until we know the title of the actual login page
this.title = _("Web Authentication Redirect");
}
},
refresh: function() {
this._everSeenRedirect = false;
this._webView.load_uri(this._originalUrl);
},
vfunc_delete_event: function(event) {
if (this._recheckAtExit)
this._doneCallback(PortalHelperResult.RECHECK);
else
this._doneCallback(PortalHelperResult.CANCELLED);
return false;
},
_onDecidePolicy: function(view, decision, type) {
if (type == WebKit.PolicyDecisionType.NEW_WINDOW_ACTION) {
decision.ignore();
return true;
}
if (type != WebKit.PolicyDecisionType.NAVIGATION_ACTION)
return false;
let request = decision.get_request();
let uri = new Soup.URI(request.get_uri());
if (!uri.host_equal(this._uri) && this._originalUrlWasGnome) {
if (uri.get_host() == 'www.gnome.org' && this._everSeenRedirect) {
// Yay, we got to gnome!
decision.ignore();
this._doneCallback(PortalHelperResult.COMPLETED);
return true;
} else if (uri.get_host() != 'www.gnome.org') {
this._everSeenRedirect = true;
}
}
// We *may* have finished here, but we don't know for
// sure. Tell gnome-shell to run another connectivity check
// (but ratelimit the checks, we don't want to spam
// nmcheck.gnome.org for portals that have 10 or more internal
// redirects - and unfortunately they exist)
// If we hit the rate limit, we also queue a recheck
// when the window is closed, just in case we miss the
// final check and don't realize we're connected
// This should not be a problem in the cancelled logic,
// because if the user doesn't want to start the login,
// we should not see any redirect at all, outside this._uri
let now = GLib.get_monotonic_time();
let shouldRecheck = (now - this._lastRecheck) >
CONNECTIVITY_RECHECK_RATELIMIT_TIMEOUT;
if (shouldRecheck) {
this._lastRecheck = now;
this._recheckAtExit = false;
this._doneCallback(PortalHelperResult.RECHECK);
} else {
this._recheckAtExit = true;
}
// Update the URI, in case of chained redirects, so we still
// think we're doing the login until gnome-shell kills us
this._uri = uri;
decision.use();
return true;
},
});
const WebPortalHelper = new Lang.Class({
Name: 'WebPortalHelper',
Extends: Gtk.Application,
_init: function() {
this.parent({ application_id: 'org.gnome.Shell.PortalHelper',
flags: Gio.ApplicationFlags.IS_SERVICE,
inactivity_timeout: 30000 });
this._dbusImpl = Gio.DBusExportedObject.wrapJSObject(HelperDBusInterface, this);
this._queue = [];
},
vfunc_dbus_register: function(connection, path) {
this._dbusImpl.export(connection, path);
this.parent(connection, path);
return true;
},
vfunc_dbus_unregister: function(connection, path) {
this._dbusImpl.unexport_from_connection(connection);
this.parent(connection, path);
},
vfunc_activate: function() {
// If launched manually (for example for testing), force a dummy authentication
// session with the default url
this.Authenticate('/org/gnome/dummy', '', 0);
},
Authenticate: function(connection, url, timestamp) {
this._queue.push({ connection: connection, url: url, timestamp: timestamp });
this._processQueue();
},
Close: function(connection) {
for (let i = 0; i < this._queue.length; i++) {
let obj = this._queue[i];
if (obj.connection == connection) {
if (obj.window)
obj.window.destroy();
this._queue.splice(i, 1);
break;
}
}
this._processQueue();
},
Refresh: function(connection) {
for (let i = 0; i < this._queue.length; i++) {
let obj = this._queue[i];
if (obj.connection == connection) {
if (obj.window)
obj.window.refresh();
break;
}
}
},
_processQueue: function() {
if (this._queue.length == 0)
return;
let top = this._queue[0];
if (top.window != null)
return;
top.window = new PortalWindow(this, top.uri, top.timestamp, Lang.bind(this, function(result) {
this._dbusImpl.emit_signal('Done', new GLib.Variant('(ou)', [top.connection, result]));
}));
},
});
function initEnvironment() {
String.prototype.format = Format.format;
}
function main(argv) {
initEnvironment();
Gettext.bindtextdomain(Config.GETTEXT_PACKAGE, Config.LOCALEDIR);
Gettext.textdomain(Config.GETTEXT_PACKAGE);
let app = new WebPortalHelper();
return app.run(argv);
}

View File

@ -24,7 +24,7 @@ const WINDOW_PREVIEW_SIZE = 128;
const APP_ICON_SIZE = 96;
const APP_ICON_SIZE_SMALL = 48;
const iconSizes = [96, 64, 48, 32, 22];
const baseIconSizes = [96, 64, 48, 32, 22];
const AppIconMode = {
THUMBNAIL_ONLY: 1,
@ -58,6 +58,14 @@ const AppSwitcherPopup = new Lang.Class({
this._currentWindow = -1;
this.thumbnailsVisible = false;
let apps = Shell.AppSystem.get_default().get_running ();
if (apps.length == 0)
return;
this._switcherList = new AppSwitcher(apps, this);
this._items = this._switcherList.icons;
},
_allocate: function (actor, box, flags) {
@ -99,20 +107,6 @@ const AppSwitcherPopup = new Lang.Class({
}
},
_createSwitcher: function() {
let apps = Shell.AppSystem.get_default().get_running ();
if (apps.length == 0)
return false;
this._switcherList = new AppSwitcher(apps, this);
this._items = this._switcherList.icons;
if (this._items.length == 0)
return false;
return true;
},
_initialSelection: function(backward, binding) {
if (binding == 'switch-group') {
if (backward) {
@ -151,13 +145,13 @@ const AppSwitcherPopup = new Lang.Class({
this._items[this._selectedIndex].cachedWindows.length);
},
_keyPressHandler: function(keysym, backwards, action) {
_keyPressHandler: function(keysym, action) {
if (action == Meta.KeyBindingAction.SWITCH_GROUP) {
this._select(this._selectedIndex, backwards ? this._previousWindow() : this._nextWindow());
this._select(this._selectedIndex, this._nextWindow());
} else if (action == Meta.KeyBindingAction.SWITCH_GROUP_BACKWARD) {
this._select(this._selectedIndex, this._previousWindow());
} else if (action == Meta.KeyBindingAction.SWITCH_APPLICATIONS) {
this._select(backwards ? this._previous() : this._next());
this._select(this._next());
} else if (action == Meta.KeyBindingAction.SWITCH_APPLICATIONS_BACKWARD) {
this._select(this._previous());
} else if (this._thumbnailsFocused) {
@ -167,6 +161,8 @@ const AppSwitcherPopup = new Lang.Class({
this._select(this._selectedIndex, this._nextWindow());
else if (keysym == Clutter.Up)
this._select(this._selectedIndex, null, true);
else
return Clutter.EVENT_PROPAGATE;
} else {
if (keysym == Clutter.Left)
this._select(this._previous());
@ -174,7 +170,11 @@ const AppSwitcherPopup = new Lang.Class({
this._select(this._next());
else if (keysym == Clutter.Down)
this._select(this._selectedIndex, 0);
else
return Clutter.EVENT_PROPAGATE;
}
return Clutter.EVENT_STOP;
},
_scrollHandler: function(direction) {
@ -305,6 +305,7 @@ const AppSwitcherPopup = new Lang.Class({
this._thumbnailTimeoutId = Mainloop.timeout_add (
THUMBNAIL_POPUP_TIME,
Lang.bind(this, this._timeoutPopupThumbnails));
GLib.Source.set_name_by_id(this._thumbnailTimeoutId, '[gnome-shell] this._timeoutPopupThumbnails');
}
},
@ -358,44 +359,28 @@ const WindowSwitcherPopup = new Lang.Class({
Name: 'WindowSwitcherPopup',
Extends: SwitcherPopup.SwitcherPopup,
_init: function(items) {
this.parent(items);
this._settings = new Gio.Settings({ schema: 'org.gnome.shell.window-switcher' });
},
_init: function() {
this.parent();
this._settings = new Gio.Settings({ schema_id: 'org.gnome.shell.window-switcher' });
_getWindowList: function() {
let workspace = this._settings.get_boolean('current-workspace-only') ? global.screen.get_active_workspace() : null;
return global.display.get_tab_list(Meta.TabList.NORMAL, global.screen, workspace);
},
_createSwitcher: function() {
let windows = this._getWindowList();
if (windows.length == 0)
return false;
return;
let mode = this._settings.get_enum('app-icon-mode');
this._switcherList = new WindowList(windows, mode);
this._items = this._switcherList.icons;
if (this._items.length == 0)
return false;
return true;
},
_initialSelection: function(backward, binding) {
if (binding == 'switch-windows-backward' || backward)
this._select(this._items.length - 1);
else if (this._items.length == 1)
this._select(0);
else
this._select(1);
_getWindowList: function() {
let workspace = this._settings.get_boolean('current-workspace-only') ? global.screen.get_active_workspace() : null;
return global.display.get_tab_list(Meta.TabList.NORMAL, workspace);
},
_keyPressHandler: function(keysym, backwards, action) {
_keyPressHandler: function(keysym, action) {
if (action == Meta.KeyBindingAction.SWITCH_WINDOWS) {
this._select(backwards ? this._previous() : this._next());
this._select(this._next());
} else if (action == Meta.KeyBindingAction.SWITCH_WINDOWS_BACKWARD) {
this._select(this._previous());
} else {
@ -403,7 +388,11 @@ const WindowSwitcherPopup = new Lang.Class({
this._select(this._previous());
else if (keysym == Clutter.Right)
this._select(this._next());
else
return Clutter.EVENT_PROPAGATE;
}
return Clutter.EVENT_STOP;
},
_finish: function() {
@ -430,7 +419,6 @@ const AppIcon = new Lang.Class({
set_size: function(size) {
this.icon = this.app.create_icon_texture(size);
this._iconBin.set_size(size, size);
this._iconBin.child = this.icon;
}
});
@ -446,11 +434,10 @@ const AppSwitcher = new Lang.Class({
this._arrows = [];
let windowTracker = Shell.WindowTracker.get_default();
let settings = new Gio.Settings({ schema: 'org.gnome.shell.app-switcher' });
let settings = new Gio.Settings({ schema_id: 'org.gnome.shell.app-switcher' });
let workspace = settings.get_boolean('current-workspace-only') ? global.screen.get_active_workspace()
: null;
let allWindows = global.display.get_tab_list(Meta.TabList.NORMAL,
global.screen, workspace);
let allWindows = global.display.get_tab_list(Meta.TabList.NORMAL, workspace);
// Construct the AppIcons, add to the popup
for (let i = 0; i < apps.length; i++) {
@ -479,12 +466,13 @@ const AppSwitcher = new Lang.Class({
Mainloop.source_remove(this._mouseTimeOutId);
},
_getPreferredHeight: function (actor, forWidth, alloc) {
_setIconSize: function() {
let j = 0;
while(this._items.length > 1 && this._items[j].style_class != 'item-box') {
j++;
}
let themeNode = this._items[j].get_theme_node();
let iconPadding = themeNode.get_horizontal_padding();
let iconBorder = themeNode.get_border_width(St.Side.LEFT) + themeNode.get_border_width(St.Side.RIGHT);
let [iconMinHeight, iconNaturalHeight] = this.icons[j].label.get_preferred_height(-1);
@ -495,19 +483,22 @@ const AppSwitcher = new Lang.Class({
let primary = Main.layoutManager.primaryMonitor;
let parentPadding = this.actor.get_parent().get_theme_node().get_horizontal_padding();
let availWidth = primary.width - parentPadding - this.actor.get_theme_node().get_horizontal_padding();
let height = 0;
for(let i = 0; i < iconSizes.length; i++) {
this._iconSize = iconSizes[i];
height = iconSizes[i] + iconSpacing;
let w = height * this._items.length + totalSpacing;
if (w <= availWidth)
break;
}
let scaleFactor = St.ThemeContext.get_for_stage(global.stage).scale_factor;
let iconSizes = baseIconSizes.map(function(s) {
return s * scaleFactor;
});
if (this._items.length == 1) {
this._iconSize = iconSizes[0];
height = iconSizes[0] + iconSpacing;
this._iconSize = baseIconSizes[0];
} else {
for(let i = 0; i < baseIconSizes.length; i++) {
this._iconSize = baseIconSizes[i];
let height = iconSizes[i] + iconSpacing;
let w = height * this._items.length + totalSpacing;
if (w <= availWidth)
break;
}
}
for(let i = 0; i < this.icons.length; i++) {
@ -515,9 +506,11 @@ const AppSwitcher = new Lang.Class({
break;
this.icons[i].set_size(this._iconSize);
}
},
alloc.min_size = height;
alloc.natural_size = height;
_getPreferredHeight: function (actor, forWidth, alloc) {
this._setIconSize();
this.parent(actor, forWidth, alloc);
},
_allocate: function (actor, box, flags) {
@ -551,6 +544,7 @@ const AppSwitcher = new Lang.Class({
this._mouseTimeOutId = 0;
return GLib.SOURCE_REMOVE;
}));
GLib.Source.set_name_by_id(this._mouseTimeOutId, '[gnome-shell] this._enterItem');
} else
this._itemEntered(index);
},
@ -650,17 +644,19 @@ const ThumbnailList = new Lang.Class({
totalPadding += this.actor.get_theme_node().get_horizontal_padding() + this.actor.get_theme_node().get_vertical_padding();
let [labelMinHeight, labelNaturalHeight] = this._labels[0].get_preferred_height(-1);
let spacing = this._items[0].child.get_theme_node().get_length('spacing');
let scaleFactor = St.ThemeContext.get_for_stage(global.stage).scale_factor;
let thumbnailSize = THUMBNAIL_DEFAULT_SIZE * scaleFactor;
availHeight = Math.min(availHeight - labelNaturalHeight - totalPadding - spacing, THUMBNAIL_DEFAULT_SIZE);
availHeight = Math.min(availHeight - labelNaturalHeight - totalPadding - spacing, thumbnailSize);
let binHeight = availHeight + this._items[0].get_theme_node().get_vertical_padding() + this.actor.get_theme_node().get_vertical_padding() - spacing;
binHeight = Math.min(THUMBNAIL_DEFAULT_SIZE, binHeight);
binHeight = Math.min(thumbnailSize, binHeight);
for (let i = 0; i < this._thumbnailBins.length; i++) {
let mutterWindow = this._windows[i].get_compositor_private();
if (!mutterWindow)
continue;
let clone = _createWindowClone(mutterWindow, THUMBNAIL_DEFAULT_SIZE);
let clone = _createWindowClone(mutterWindow, thumbnailSize);
this._thumbnailBins[i].set_height(binHeight);
this._thumbnailBins[i].add_actor(clone);
this._clones.push(clone);

View File

@ -21,7 +21,9 @@ const Animation = new Lang.Class({
this._isPlaying = false;
this._timeoutId = 0;
this._frame = 0;
this._animations = St.TextureCache.get_default().load_sliced_image (filename, width, height,
let scaleFactor = St.ThemeContext.get_for_stage(global.stage).scale_factor;
this._animations = St.TextureCache.get_default().load_sliced_image (filename, width, height, scaleFactor,
Lang.bind(this, this._animationsLoaded));
this.actor.set_child(this._animations);
},
@ -32,6 +34,7 @@ const Animation = new Lang.Class({
this._showFrame(0);
this._timeoutId = Mainloop.timeout_add(this._speed, Lang.bind(this, this._update));
GLib.Source.set_name_by_id(this._timeoutId, '[gnome-shell] this._update');
}
this._isPlaying = true;

View File

@ -16,6 +16,7 @@ const Atk = imports.gi.Atk;
const AppFavorites = imports.ui.appFavorites;
const BoxPointer = imports.ui.boxpointer;
const DND = imports.ui.dnd;
const GrabHelper = imports.ui.grabHelper;
const IconGrid = imports.ui.iconGrid;
const Main = imports.ui.main;
const Overview = imports.ui.overview;
@ -33,7 +34,9 @@ const MIN_COLUMNS = 4;
const MIN_ROWS = 4;
const INACTIVE_GRID_OPACITY = 77;
const INACTIVE_GRID_OPACITY_ANIMATION_TIME = 0.40;
// This time needs to be less than IconGrid.EXTRA_SPACE_ANIMATION_TIME
// to not clash with other animations
const INACTIVE_GRID_OPACITY_ANIMATION_TIME = 0.24;
const FOLDER_SUBICON_FRACTION = .4;
const MIN_FREQUENT_APPS_COUNT = 3;
@ -41,11 +44,22 @@ const MIN_FREQUENT_APPS_COUNT = 3;
const INDICATORS_BASE_TIME = 0.25;
const INDICATORS_ANIMATION_DELAY = 0.125;
const INDICATORS_ANIMATION_MAX_TIME = 0.75;
// Fraction of page height the finger or mouse must reach
// to change page
const PAGE_SWITCH_TRESHOLD = 0.2;
// Follow iconGrid animations approach and divide by 2 to animate out to
// not annoy the user when the user wants to quit appDisplay.
// Also, make sure we don't exceed iconGrid animation total time or
// views switch time.
const INDICATORS_BASE_TIME_OUT = 0.125;
const INDICATORS_ANIMATION_DELAY_OUT = 0.0625;
const INDICATORS_ANIMATION_MAX_TIME_OUT =
Math.min (VIEWS_SWITCH_TIME,
IconGrid.ANIMATION_TIME_OUT + IconGrid.ANIMATION_MAX_DELAY_OUT_FOR_ITEM);
const PAGE_SWITCH_TIME = 0.3;
const VIEWS_SWITCH_TIME = 0.4;
const VIEWS_SWITCH_ANIMATION_DELAY = 0.1;
function _getCategories(info) {
let categoriesStr = info.get_categories();
if (!categoriesStr)
@ -53,14 +67,6 @@ function _getCategories(info) {
return categoriesStr.split(';');
}
function _isTerminal(app) {
let info = app.get_app_info();
if (!info)
return false;
let categories = _getCategories(info);
return categories.indexOf('TerminalEmulator') > -1;
}
function _listsIntersect(a, b) {
for (let itemA of a)
if (b.indexOf(itemA) >= 0)
@ -86,6 +92,10 @@ function _getFolderName(folder) {
return name;
}
function clamp(value, min, max) {
return Math.max(min, Math.min(max, value));
}
const BaseAppView = new Lang.Class({
Name: 'BaseAppView',
Abstract: true,
@ -104,6 +114,9 @@ const BaseAppView = new Lang.Class({
else
this._grid = new IconGrid.IconGrid(gridParams);
this._grid.connect('key-focus-in', Lang.bind(this, function(grid, actor) {
this._keyFocusIn(actor);
}));
// Standard hack for ClutterBinLayout
this._grid.actor.x_expand = true;
@ -111,6 +124,10 @@ const BaseAppView = new Lang.Class({
this._allItems = [];
},
_keyFocusIn: function(actor) {
// Nothing by default
},
removeAll: function() {
this._grid.destroyAll();
this._items = {};
@ -172,26 +189,98 @@ const BaseAppView = new Lang.Class({
this.selectApp(id);
}));
}
},
_doSpringAnimation: function(animationDirection) {
this._grid.actor.opacity = 255;
this._grid.animateSpring(animationDirection,
Main.overview.getShowAppsButton());
},
animate: function(animationDirection, onComplete) {
if (animationDirection == IconGrid.AnimationDirection.IN) {
let toAnimate = this._grid.actor.connect('notify::allocation', Lang.bind(this,
function() {
this._grid.actor.disconnect(toAnimate);
// We need to hide the grid temporary to not flash it
// for a frame
this._grid.actor.opacity = 0;
Meta.later_add(Meta.LaterType.BEFORE_REDRAW,
Lang.bind(this, function() {
this._doSpringAnimation(animationDirection)
}));
}));
} else {
this._doSpringAnimation(animationDirection);
}
if (onComplete) {
let animationDoneId = this._grid.connect('animation-done', Lang.bind(this,
function () {
this._grid.disconnect(animationDoneId);
onComplete();
}));
}
},
animateSwitch: function(animationDirection) {
Tweener.removeTweens(this.actor);
Tweener.removeTweens(this._grid.actor);
let params = { time: VIEWS_SWITCH_TIME,
transition: 'easeOutQuad' };
if (animationDirection == IconGrid.AnimationDirection.IN) {
this.actor.show();
params.opacity = 255;
params.delay = VIEWS_SWITCH_ANIMATION_DELAY;
} else {
params.opacity = 0;
params.delay = 0;
params.onComplete = Lang.bind(this, function() { this.actor.hide() });
}
Tweener.addTween(this._grid.actor, params);
}
});
Signals.addSignalMethods(BaseAppView.prototype);
const PageIndicatorsActor = new Lang.Class({
Name:'PageIndicatorsActor',
Extends: St.BoxLayout,
_init: function() {
this.parent({ style_class: 'page-indicators',
vertical: true,
x_expand: true, y_expand: true,
x_align: Clutter.ActorAlign.END,
y_align: Clutter.ActorAlign.CENTER,
reactive: true,
clip_to_allocation: true });
},
vfunc_get_preferred_height: function(forWidth) {
// We want to request the natural height of all our children as our
// natural height, so we chain up to St.BoxLayout, but we only request 0
// as minimum height, since it's not that important if some indicators
// are not shown
let [, natHeight] = this.parent(forWidth);
return [0, natHeight];
}
});
const PageIndicators = new Lang.Class({
Name:'PageIndicators',
_init: function() {
this.actor = new St.BoxLayout({ style_class: 'page-indicators',
vertical: true,
x_expand: true, y_expand: true,
x_align: Clutter.ActorAlign.END,
y_align: Clutter.ActorAlign.CENTER,
reactive: true });
this.actor = new PageIndicatorsActor();
this._nPages = 0;
this._currentPage = undefined;
this.actor.connect('notify::mapped',
Lang.bind(this, this._animateIndicators));
Lang.bind(this, function() {
this.animateIndicators(IconGrid.AnimationDirection.IN);
})
);
},
setNPages: function(nPages) {
@ -232,7 +321,7 @@ const PageIndicators = new Lang.Class({
children[i].set_checked(i == this._currentPage);
},
_animateIndicators: function() {
animateIndicators: function(animationDirection) {
if (!this.actor.mapped)
return;
@ -240,23 +329,32 @@ const PageIndicators = new Lang.Class({
if (children.length == 0)
return;
for (let i = 0; i < this._nPages; i++)
Tweener.removeTweens(children[i]);
let offset;
if (this.actor.get_text_direction() == Clutter.TextDirection.RTL)
offset = -children[0].width;
else
offset = children[0].width;
let delay = INDICATORS_ANIMATION_DELAY;
let totalAnimationTime = INDICATORS_BASE_TIME + INDICATORS_ANIMATION_DELAY * this._nPages;
if (totalAnimationTime > INDICATORS_ANIMATION_MAX_TIME)
delay -= (totalAnimationTime - INDICATORS_ANIMATION_MAX_TIME) / this._nPages;
let isAnimationIn = animationDirection == IconGrid.AnimationDirection.IN;
let delay = isAnimationIn ? INDICATORS_ANIMATION_DELAY :
INDICATORS_ANIMATION_DELAY_OUT;
let baseTime = isAnimationIn ? INDICATORS_BASE_TIME : INDICATORS_BASE_TIME_OUT;
let totalAnimationTime = baseTime + delay * this._nPages;
let maxTime = isAnimationIn ? INDICATORS_ANIMATION_MAX_TIME :
INDICATORS_ANIMATION_MAX_TIME_OUT;
if (totalAnimationTime > maxTime)
delay -= (totalAnimationTime - maxTime) / this._nPages;
for (let i = 0; i < this._nPages; i++) {
children[i].translation_x = offset;
children[i].translation_x = isAnimationIn ? offset : 0;
Tweener.addTween(children[i],
{ translation_x: 0,
time: INDICATORS_BASE_TIME + delay * i,
transition: 'easeInOutQuad'
{ translation_x: isAnimationIn ? 0 : offset,
time: baseTime + delay * i,
transition: 'easeInOutQuad',
delay: isAnimationIn ? VIEWS_SWITCH_ANIMATION_DELAY : 0
});
}
}
@ -299,7 +397,7 @@ const AllView = new Lang.Class({
this._stack = new St.Widget({ layout_manager: new Clutter.BinLayout() });
let box = new St.BoxLayout({ vertical: true });
this._currentPage = 0;
this._grid.currentPage = 0;
this._stack.add_actor(this._grid.actor);
this._eventBlocker = new St.Widget({ x_expand: true, y_expand: true });
this._stack.add_actor(this._eventBlocker);
@ -365,7 +463,7 @@ const AllView = new Lang.Class({
Shell.AppSystem.get_default().connect('installed-changed', Lang.bind(this, function() {
Main.queueDeferredWork(this._redisplayWorkId);
}));
this._folderSettings = new Gio.Settings({ schema: 'org.gnome.desktop.app-folders' });
this._folderSettings = new Gio.Settings({ schema_id: 'org.gnome.desktop.app-folders' });
this._folderSettings.connect('changed::folder-children', Lang.bind(this, function() {
Main.queueDeferredWork(this._redisplayWorkId);
}));
@ -431,14 +529,52 @@ const AllView = new Lang.Class({
this._refilterApps();
},
// Overriden from BaseAppView
animate: function (animationDirection, onComplete) {
if (animationDirection == IconGrid.AnimationDirection.OUT &&
this._displayingPopup && this._currentPopup) {
this._currentPopup.popdown();
let spaceClosedId = this._grid.connect('space-closed', Lang.bind(this,
function() {
this._grid.disconnect(spaceClosedId);
// Given that we can't call this.parent() inside the
// signal handler, call again animate which will
// call the parent given that popup is already
// closed.
this.animate(animationDirection, onComplete);
}));
} else {
this.parent(animationDirection, onComplete);
if (animationDirection == IconGrid.AnimationDirection.OUT)
this._pageIndicators.animateIndicators(animationDirection);
}
},
animateSwitch: function(animationDirection) {
this.parent(animationDirection);
if (this._currentPopup && this._displayingPopup &&
animationDirection == IconGrid.AnimationDirection.OUT)
Tweener.addTween(this._currentPopup.actor,
{ time: VIEWS_SWITCH_TIME,
transition: 'easeOutQuad',
opacity: 0,
onComplete: function() {
this.opacity = 255;
} });
if (animationDirection == IconGrid.AnimationDirection.OUT)
this._pageIndicators.animateIndicators(animationDirection);
},
getCurrentPageY: function() {
return this._grid.getPageY(this._currentPage);
return this._grid.getPageY(this._grid.currentPage);
},
goToPage: function(pageNumber) {
if(pageNumber < 0 || pageNumber > this._grid.nPages() - 1)
return;
if (this._currentPage == pageNumber && this._displayingPopup && this._currentPopup)
pageNumber = clamp(pageNumber, 0, this._grid.nPages() - 1);
if (this._grid.currentPage == pageNumber && this._displayingPopup && this._currentPopup)
return;
if (this._displayingPopup && this._currentPopup)
this._currentPopup.popdown();
@ -458,7 +594,7 @@ const AllView = new Lang.Class({
let time;
// Only take the velocity into account on page changes, otherwise
// return smoothly to the current page using the default velocity
if (this._currentPage != pageNumber) {
if (this._grid.currentPage != pageNumber) {
let minVelocity = totalHeight / (PAGE_SWITCH_TIME * 1000);
velocity = Math.max(minVelocity, velocity);
time = (diffToPage / velocity) / 1000;
@ -469,14 +605,12 @@ const AllView = new Lang.Class({
// longer than PAGE_SWITCH_TIME
time = Math.min(time, PAGE_SWITCH_TIME);
if (pageNumber < this._grid.nPages() && pageNumber >= 0) {
this._currentPage = pageNumber;
Tweener.addTween(this._adjustment,
{ value: this._grid.getPageY(this._currentPage),
time: time,
transition: 'easeOutQuad' });
this._pageIndicators.setCurrentPage(pageNumber);
}
this._grid.currentPage = pageNumber;
Tweener.addTween(this._adjustment,
{ value: this._grid.getPageY(this._grid.currentPage),
time: time,
transition: 'easeOutQuad' });
this._pageIndicators.setCurrentPage(pageNumber);
},
_diffToPage: function (pageNumber) {
@ -502,9 +636,9 @@ const AllView = new Lang.Class({
let direction = event.get_scroll_direction();
if (direction == Clutter.ScrollDirection.UP)
this.goToPage(this._currentPage - 1);
this.goToPage(this._grid.currentPage - 1);
else if (direction == Clutter.ScrollDirection.DOWN)
this.goToPage(this._currentPage + 1);
this.goToPage(this._grid.currentPage + 1);
return Clutter.EVENT_STOP;
},
@ -523,15 +657,19 @@ const AllView = new Lang.Class({
_onPanEnd: function(action) {
if (this._displayingPopup)
return;
let diffCurrentPage = this._diffToPage(this._currentPage);
if (diffCurrentPage > this._scrollView.height * PAGE_SWITCH_TRESHOLD) {
if (action.get_velocity(0)[2] > 0)
this.goToPage(this._currentPage - 1);
else
this.goToPage(this._currentPage + 1);
} else {
this.goToPage(this._currentPage);
}
let pageHeight = this._grid.getPageHeight();
// Calculate the scroll value we'd be at, which is our current
// scroll plus any velocity the user had when they released
// their finger.
let velocity = -action.get_velocity(0)[2];
let endPanValue = this._adjustment.value + velocity;
let closestPage = Math.round(endPanValue / pageHeight);
this.goToPage(closestPage);
this._panning = false;
},
@ -540,10 +678,10 @@ const AllView = new Lang.Class({
return Clutter.EVENT_STOP;
if (event.get_key_symbol() == Clutter.Page_Up) {
this.goToPage(this._currentPage - 1);
this.goToPage(this._grid.currentPage - 1);
return Clutter.EVENT_STOP;
} else if (event.get_key_symbol() == Clutter.Page_Down) {
this.goToPage(this._currentPage + 1);
this.goToPage(this._grid.currentPage + 1);
return Clutter.EVENT_STOP;
}
@ -562,7 +700,7 @@ const AllView = new Lang.Class({
}));
},
_ensureIconVisible: function(icon) {
_keyFocusIn: function(icon) {
let itemPage = this._grid.getItemPage(icon);
this.goToPage(itemPage);
},
@ -604,6 +742,7 @@ const AllView = new Lang.Class({
if (this._availWidth != availWidth || this._availHeight != availHeight || oldNPages != this._grid.nPages()) {
this._adjustment.value = 0;
this._grid.currentPage = 0;
Meta.later_add(Meta.LaterType.BEFORE_REDRAW, Lang.bind(this,
function() {
this._pageIndicators.setNPages(this._grid.nPages());
@ -733,7 +872,7 @@ const AppDisplay = new Lang.Class({
Name: 'AppDisplay',
_init: function() {
this._privacySettings = new Gio.Settings({ schema: 'org.gnome.desktop.privacy' });
this._privacySettings = new Gio.Settings({ schema_id: 'org.gnome.desktop.privacy' });
this._privacySettings.connect('changed::remember-app-usage',
Lang.bind(this, this._updateFrequentVisibility));
@ -761,10 +900,23 @@ const AppDisplay = new Lang.Class({
this._viewStack = new St.Widget({ x_expand: true, y_expand: true,
layout_manager: this._viewStackLayout });
this._viewStackLayout.connect('allocated-size-changed', Lang.bind(this, this._onAllocatedSizeChanged));
this.actor.add_actor(this._viewStack, { expand: true });
this.actor.add_actor(this._viewStack);
let layout = new ControlsBoxLayout({ homogeneous: true });
this._controls = new St.Widget({ style_class: 'app-view-controls',
layout_manager: layout });
this._controls.connect('notify::mapped', Lang.bind(this,
function() {
// controls are faded either with their parent or
// explicitly in animate(); we can't know how they'll be
// shown next, so make sure to restore their opacity
// when they are hidden
if (this._controls.mapped)
return;
Tweener.removeTweens(this._controls);
this._controls.opacity = 255;
}));
layout.hookup_style(this._controls);
this.actor.add_actor(new St.Bin({ child: this._controls }));
@ -788,21 +940,39 @@ const AppDisplay = new Lang.Class({
this._updateFrequentVisibility();
},
animate: function(animationDirection, onComplete) {
let currentView = this._views[global.settings.get_uint('app-picker-view')].view;
// Animate controls opacity using iconGrid animation time, since
// it will be the time the AllView or FrequentView takes to show
// it entirely.
let finalOpacity;
if (animationDirection == IconGrid.AnimationDirection.IN) {
this._controls.opacity = 0;
finalOpacity = 255;
} else {
finalOpacity = 0
}
Tweener.addTween(this._controls,
{ time: IconGrid.ANIMATION_TIME_IN,
transition: 'easeInOutQuad',
opacity: finalOpacity,
});
currentView.animate(animationDirection, onComplete);
},
_showView: function(activeIndex) {
for (let i = 0; i < this._views.length; i++) {
let actor = this._views[i].view.actor;
let params = { time: OverviewControls.SIDE_CONTROLS_ANIMATION_TIME,
opacity: (i == activeIndex) ? 255 : 0 };
if (i == activeIndex)
actor.visible = true;
else
params.onComplete = function() { actor.hide(); };
Tweener.addTween(actor, params);
if (i == activeIndex)
this._views[i].control.add_style_pseudo_class('checked');
else
this._views[i].control.remove_style_pseudo_class('checked');
let animationDirection = i == activeIndex ? IconGrid.AnimationDirection.IN :
IconGrid.AnimationDirection.OUT;
this._views[i].view.animateSwitch(animationDirection);
}
},
@ -884,26 +1054,6 @@ const AppSearchProvider = new Lang.Class({
this.getInitialResultSet(terms, callback, cancellable);
},
activateResult: function(result) {
let app = this._appSys.lookup_app(result);
let event = Clutter.get_current_event();
let modifiers = event ? event.get_state() : 0;
let openNewWindow = (modifiers & Clutter.ModifierType.CONTROL_MASK) || _isTerminal(app);
if (openNewWindow)
app.open_new_window(-1);
else
app.activate();
},
dragActivateResult: function(id, params) {
params = Params.parse(params, { workspace: -1,
timestamp: 0 });
let app = this._appSys.lookup_app(id);
app.open_new_window(workspace);
},
createResultObject: function (resultMeta) {
let app = this._appSys.lookup_app(resultMeta['id']);
return new AppIcon(app);
@ -931,20 +1081,33 @@ const FolderView = new Lang.Class({
this.actor.add_action(action);
},
_keyFocusIn: function(actor) {
Util.ensureActorVisibleInScrollView(this.actor, actor);
},
// Overriden from BaseAppView
animate: function(animationDirection) {
this._grid.animatePulse(animationDirection);
},
createFolderIcon: function(size) {
let icon = new St.Widget({ layout_manager: new Clutter.BinLayout(),
style_class: 'app-folder-icon',
width: size, height: size });
let layout = new Clutter.GridLayout();
let icon = new St.Widget({ layout_manager: layout,
style_class: 'app-folder-icon' });
layout.hookup_style(icon);
let subSize = Math.floor(FOLDER_SUBICON_FRACTION * size);
let aligns = [ Clutter.ActorAlign.START, Clutter.ActorAlign.END ];
for (let i = 0; i < Math.min(this._allItems.length, 4); i++) {
let texture = this._allItems[i].app.create_icon_texture(subSize);
let bin = new St.Bin({ child: texture,
x_expand: true, y_expand: true });
bin.set_x_align(aligns[i % 2]);
bin.set_y_align(aligns[Math.floor(i / 2)]);
icon.add_actor(bin);
let numItems = this._allItems.length;
let rtl = icon.get_text_direction() == Clutter.TextDirection.RTL;
for (let i = 0; i < 4; i++) {
let bin;
if (i < numItems) {
let texture = this._allItems[i].app.create_icon_texture(subSize);
bin = new St.Bin({ child: texture });
} else {
bin = new St.Bin({ width: subSize, height: subSize });
}
layout.attach(bin, rtl ? (i + 1) % 2 : i % 2, Math.floor(i / 2), 1, 1);
}
return icon;
@ -1233,18 +1396,53 @@ const AppFolderPopup = new Lang.Class({
function() {
this.actor.destroy();
}));
this._grabHelper = new GrabHelper.GrabHelper(this.actor);
this._grabHelper.addActor(Main.layoutManager.overviewGroup);
this.actor.connect('key-press-event', Lang.bind(this, this._onKeyPress));
},
_onKeyPress: function(actor, event) {
if (!this._isOpen)
if (global.stage.get_key_focus() != actor)
return Clutter.EVENT_PROPAGATE;
if (event.get_key_symbol() != Clutter.KEY_Escape)
return Clutter.EVENT_PROPAGATE;
// Since we need to only grab focus on one item child when the user
// actually press a key we don't use navigate_focus when opening
// the popup.
// Instead of that, grab the focus on the AppFolderPopup actor
// and actually moves the focus to a child only when the user
// actually press a key.
// It should work with just grab_key_focus on the AppFolderPopup
// actor, but since the arrow keys are not wrapping_around the focus
// is not grabbed by a child when the widget that has the current focus
// is the same that is requesting focus, so to make it works with arrow
// keys we need to connect to the key-press-event and navigate_focus
// when that happens using TAB_FORWARD or TAB_BACKWARD instead of arrow
// keys
this.popdown();
return Clutter.EVENT_STOP;
// Use TAB_FORWARD for down key and right key
// and TAB_BACKWARD for up key and left key on ltr
// languages
let direction;
let isLtr = Clutter.get_default_text_direction() == Clutter.TextDirection.LTR;
switch (event.get_key_symbol()) {
case Clutter.Down:
direction = Gtk.DirectionType.TAB_FORWARD;
break;
case Clutter.Right:
direction = isLtr ? Gtk.DirectionType.TAB_FORWARD :
Gtk.DirectionType.TAB_BACKWARD;
break;
case Clutter.Up:
direction = Gtk.DirectionType.TAB_BACKWARD;
break;
case Clutter.Left:
direction = isLtr ? Gtk.DirectionType.TAB_BACKWARD :
Gtk.DirectionType.TAB_FORWARD;
break;
default:
return Clutter.EVENT_PROPAGATE;
}
return actor.navigate_focus(null, direction, false);
},
toggle: function() {
@ -1258,15 +1456,27 @@ const AppFolderPopup = new Lang.Class({
if (this._isOpen)
return;
this._isOpen = this._grabHelper.grab({ actor: this.actor,
onUngrab: Lang.bind(this, this.popdown) });
if (!this._isOpen)
return;
this.actor.show();
this._boxPointer.setArrowActor(this._source.actor);
// We need to hide the icons of the view until the boxpointer animation
// is completed so we can animate the icons after as we like without
// showing them while boxpointer is animating.
this._view.actor.opacity = 0;
this._boxPointer.show(BoxPointer.PopupAnimation.FADE |
BoxPointer.PopupAnimation.SLIDE);
BoxPointer.PopupAnimation.SLIDE,
Lang.bind(this,
function() {
this._view.actor.opacity = 255;
this._view.animate(IconGrid.AnimationDirection.IN);
}));
this.actor.navigate_focus(null, Gtk.DirectionType.TAB_FORWARD, false);
this._isOpen = true;
this.emit('open-state-changed', true);
},
@ -1274,6 +1484,8 @@ const AppFolderPopup = new Lang.Class({
if (!this._isOpen)
return;
this._grabHelper.ungrab({ actor: this.actor });
this._boxPointer.hide(BoxPointer.PopupAnimation.FADE |
BoxPointer.PopupAnimation.SLIDE);
this._isOpen = false;
@ -1324,7 +1536,9 @@ const AppIcon = new Lang.Class({
this.actor.label_actor = this.icon.label;
this.actor.connect('leave-event', Lang.bind(this, this._onLeaveEvent));
this.actor.connect('button-press-event', Lang.bind(this, this._onButtonPress));
this.actor.connect('touch-event', Lang.bind(this, this._onTouchEvent));
this.actor.connect('clicked', Lang.bind(this, this._onClicked));
this.actor.connect('popup-menu', Lang.bind(this, this._onKeyboardPopupMenu));
@ -1380,16 +1594,26 @@ const AppIcon = new Lang.Class({
this.actor.remove_style_class_name('running');
},
_setPopupTimeout: function() {
this._removeMenuTimeout();
this._menuTimeoutId = Mainloop.timeout_add(MENU_POPUP_TIMEOUT,
Lang.bind(this, function() {
this._menuTimeoutId = 0;
this.popupMenu();
return GLib.SOURCE_REMOVE;
}));
GLib.Source.set_name_by_id(this._menuTimeoutId, '[gnome-shell] this.popupMenu');
},
_onLeaveEvent: function(actor, event) {
this.actor.fake_release();
this._removeMenuTimeout();
},
_onButtonPress: function(actor, event) {
let button = event.get_button();
if (button == 1) {
this._removeMenuTimeout();
this._menuTimeoutId = Mainloop.timeout_add(MENU_POPUP_TIMEOUT,
Lang.bind(this, function() {
this._menuTimeoutId = 0;
this.popupMenu();
return GLib.SOURCE_REMOVE;
}));
this._setPopupTimeout();
} else if (button == 3) {
this.popupMenu();
return Clutter.EVENT_STOP;
@ -1397,19 +1621,16 @@ const AppIcon = new Lang.Class({
return Clutter.EVENT_PROPAGATE;
},
_onTouchEvent: function (actor, event) {
if (event.type() == Clutter.EventType.TOUCH_BEGIN)
this._setPopupTimeout();
return Clutter.EVENT_PROPAGATE;
},
_onClicked: function(actor, button) {
this._removeMenuTimeout();
if (button == 1) {
this._onActivate(Clutter.get_current_event());
} else if (button == 2) {
// Last workspace is always empty
let launchWorkspace = global.screen.get_workspace_by_index(global.screen.n_workspaces - 1);
launchWorkspace.activate(global.get_current_time());
this.app.open_new_window(-1);
Main.overview.hide();
}
return false;
this.activate(button);
},
_onKeyboardPopupMenu: function() {
@ -1463,20 +1684,29 @@ const AppIcon = new Lang.Class({
this.emit('menu-state-changed', false);
},
_onActivate: function (event) {
let modifiers = event.get_state();
activate: function (button) {
let event = Clutter.get_current_event();
let modifiers = event ? event.get_state() : 0;
let openNewWindow = this.app.can_open_new_window () &&
modifiers & Clutter.ModifierType.CONTROL_MASK &&
this.app.state == Shell.AppState.RUNNING ||
button && button == 2;
if ((modifiers & Clutter.ModifierType.CONTROL_MASK
&& this.app.state == Shell.AppState.RUNNING)
|| _isTerminal(this.app)) {
if (this.app.state == Shell.AppState.STOPPED || openNewWindow)
this.animateLaunch();
if (openNewWindow)
this.app.open_new_window(-1);
} else {
else
this.app.activate();
}
Main.overview.hide();
},
animateLaunch: function() {
this.icon.animateZoomOut();
},
shellWorkspaceLaunch : function(params) {
params = Params.parse(params, { workspace: -1,
timestamp: 0 });
@ -1555,12 +1785,17 @@ const AppIconMenu = new Lang.Class({
if (!this._source.app.is_window_backed()) {
this._appendSeparator();
this._newWindowMenuItem = this._appendMenuItem(_("New Window"));
this._newWindowMenuItem.connect('activate', Lang.bind(this, function() {
this._source.app.open_new_window(-1);
this.emit('activate-window', null);
}));
this._appendSeparator();
if (this._source.app.can_open_new_window()) {
this._newWindowMenuItem = this._appendMenuItem(_("New Window"));
this._newWindowMenuItem.connect('activate', Lang.bind(this, function() {
if (this._source.app.state == Shell.AppState.STOPPED)
this._source.animateLaunch();
this._source.app.open_new_window(-1);
this.emit('activate-window', null);
}));
this._appendSeparator();
}
let appInfo = this._source.app.get_app_info();
let actions = appInfo.list_actions();
@ -1589,6 +1824,26 @@ const AppIconMenu = new Lang.Class({
favs.addFavorite(this._source.app.get_id());
}));
}
if (Shell.AppSystem.get_default().lookup_app('org.gnome.Software.desktop')) {
this._appendSeparator();
let item = this._appendMenuItem(_("Show Details"));
item.connect('activate', Lang.bind(this, function() {
let id = this._source.app.get_id();
let args = GLib.Variant.new('(ss)', [id, '']);
Gio.DBus.get(Gio.BusType.SESSION, null,
function(o, res) {
let bus = Gio.DBus.get_finish(res);
bus.call('org.gnome.Software',
'/org/gnome/Software',
'org.gtk.Actions', 'Activate',
GLib.Variant.new('(sava{sv})',
['details', [args], null]),
null, 0, -1, null, null);
Main.overview.hide();
});
}));
}
}
},

View File

@ -6,6 +6,36 @@ const Signals = imports.signals;
const Main = imports.ui.main;
const RENAMED_DESKTOP_IDS = {
'baobab.desktop': 'org.gnome.baobab.desktop',
'cheese.desktop': 'org.gnome.Cheese.desktop',
'dconf-editor.desktop': 'ca.desrt.dconf-editor.desktop',
'file-roller.desktop': 'org.gnome.FileRoller.desktop',
'gcalctool.desktop': 'gnome-calculator.desktop',
'gedit.desktop': 'org.gnome.gedit.desktop',
'glchess.desktop': 'gnome-chess.desktop',
'glines.desktop': 'five-or-more.desktop',
'gnect.desktop': 'four-in-a-row.desktop',
'gnibbles.desktop': 'gnome-nibbles.desktop',
'gnobots2.desktop': 'gnome-robots.desktop',
'gnome-boxes.desktop': 'org.gnome.Boxes.desktop',
'gnome-clocks.desktop': 'org.gnome.clocks.desktop',
'gnome-contacts.desktop': 'org.gnome.Contacts.desktop',
'gnome-documents.desktop': 'org.gnome.Documents.desktop',
'gnome-font-viewer.desktop': 'org.gnome.font-viewer.desktop',
'gnome-photos.desktop': 'org.gnome.Photos.desktop',
'gnome-screenshot.desktop': 'org.gnome.Screenshot.desktop',
'gnome-software.desktop': 'org.gnome.Software.desktop',
'gnome-weather.desktop': 'org.gnome.Weather.Application.desktop',
'gnomine.desktop': 'gnome-mines.desktop',
'gnotravex.desktop': 'gnome-tetravex.desktop',
'gnotski.desktop': 'gnome-klotski.desktop',
'gtali.desktop': 'tali.desktop',
'nautilus.desktop': 'org.gnome.Nautilus.desktop',
'polari.desktop': 'org.gnome.Polari.desktop',
'totem.desktop': 'org.gnome.Totem.desktop',
};
const AppFavorites = new Lang.Class({
Name: 'AppFavorites',
@ -24,6 +54,21 @@ const AppFavorites = new Lang.Class({
reload: function() {
let ids = global.settings.get_strv(this.FAVORITE_APPS_KEY);
// Map old desktop file names to the current ones
let updated = false;
ids = ids.map(function (id) {
let newId = RENAMED_DESKTOP_IDS[id];
if (newId !== undefined) {
updated = true;
return newId;
}
return id;
});
// ... and write back the updated desktop file names
if (updated)
global.settings.set_strv(this.FAVORITE_APPS_KEY, ids);
let appSys = Shell.AppSystem.get_default();
let apps = ids.map(function (id) {
return appSys.lookup_app(id);

File diff suppressed because it is too large Load Diff

View File

@ -33,31 +33,40 @@ function addBackgroundMenu(actor, layoutManager) {
actor._backgroundManager = new PopupMenu.PopupMenuManager({ actor: actor });
actor._backgroundManager.addMenu(actor._backgroundMenu);
function openMenu() {
let [x, y] = global.get_pointer();
Main.layoutManager.setDummyCursorPosition(x, y);
function openMenu(x, y) {
Main.layoutManager.setDummyCursorGeometry(x, y, 0, 0);
actor._backgroundMenu.open(BoxPointer.PopupAnimation.NONE);
}
let clickAction = new Clutter.ClickAction();
clickAction.connect('long-press', function(action, actor, state) {
if (state == Clutter.LongPressState.QUERY)
return action.get_button() == 1 && !actor._backgroundMenu.isOpen;
return ((action.get_button() == 0 ||
action.get_button() == 1) &&
!actor._backgroundMenu.isOpen);
if (state == Clutter.LongPressState.ACTIVATE) {
openMenu();
let [x, y] = action.get_coords();
openMenu(x, y);
actor._backgroundManager.ignoreRelease();
}
return true;
});
clickAction.connect('clicked', function(action) {
if (action.get_button() == 3)
openMenu();
if (action.get_button() == 3) {
let [x, y] = action.get_coords();
openMenu(x, y);
}
});
actor.add_action(clickAction);
let grabOpBeginId = global.display.connect('grab-op-begin', function () {
clickAction.release();
});
actor.connect('destroy', function() {
actor._backgroundMenu.destroy();
actor._backgroundMenu = null;
actor._backgroundManager = null;
global.display.disconnect(grabOpBeginId);
});
}

View File

@ -14,6 +14,9 @@ const Shell = imports.gi.Shell;
const MSECS_IN_DAY = 24 * 60 * 60 * 1000;
const SHOW_WEEKDATE_KEY = 'show-weekdate';
// alias to prevent xgettext from picking up strings translated in GTK+
const gtk30_ = Gettext_gtk30.gettext;
// in org.gnome.desktop.interface
const CLOCK_FORMAT_KEY = 'clock-format';
@ -380,14 +383,14 @@ const Calendar = new Lang.Class({
_init: function() {
this._weekStart = Shell.util_get_week_start();
this._settings = new Gio.Settings({ schema: 'org.gnome.shell.calendar' });
this._settings = new Gio.Settings({ schema_id: 'org.gnome.shell.calendar' });
this._settings.connect('changed::' + SHOW_WEEKDATE_KEY, Lang.bind(this, this._onSettingsChange));
this._useWeekdate = this._settings.get_boolean(SHOW_WEEKDATE_KEY);
// Find the ordering for month/year in the calendar heading
this._headerFormatWithoutYear = '%B';
switch (Gettext_gtk30.gettext('calendar:MY')) {
switch (gtk30_('calendar:MY')) {
case 'calendar:MY':
this._headerFormat = '%B %Y';
break;
@ -403,9 +406,11 @@ const Calendar = new Lang.Class({
// Start off with the current date
this._selectedDate = new Date();
this.actor = new St.Table({ homogeneous: false,
style_class: 'calendar',
reactive: true });
this._shouldDateGrabFocus = false;
this.actor = new St.Widget({ style_class: 'calendar',
layout_manager: new Clutter.GridLayout(),
reactive: true });
this.actor.connect('scroll-event',
Lang.bind(this, this._onScroll));
@ -418,8 +423,10 @@ const Calendar = new Lang.Class({
setEventSource: function(eventSource) {
this._eventSource = eventSource;
this._eventSource.connect('changed', Lang.bind(this, function() {
this._rebuildCalendar();
this._update();
}));
this._rebuildCalendar();
this._update();
},
@ -434,13 +441,13 @@ const Calendar = new Lang.Class({
},
_buildHeader: function() {
let layout = this.actor.layout_manager;
let offsetCols = this._useWeekdate ? 1 : 0;
this.actor.destroy_all_children();
// Top line of the calendar '<| September 2009 |>'
this._topBox = new St.BoxLayout();
this.actor.add(this._topBox,
{ row: 0, col: 0, col_span: offsetCols + 7 });
layout.attach(this._topBox, 0, 0, offsetCols + 7, 1);
this._backButton = new St.Button({ style_class: 'calendar-change-month-back',
accessible_name: _("Previous month"),
@ -472,10 +479,12 @@ const Calendar = new Lang.Class({
let customDayAbbrev = _getCalendarDayAbbreviation(iter.getDay());
let label = new St.Label({ style_class: 'calendar-day-base calendar-day-heading',
text: customDayAbbrev });
this.actor.add(label,
{ row: 1,
col: offsetCols + (7 + iter.getDay() - this._weekStart) % 7,
x_fill: false, x_align: St.Align.MIDDLE });
let col;
if (this.actor.get_text_direction() == Clutter.TextDirection.RTL)
col = 6 - (7 + iter.getDay() - this._weekStart) % 7;
else
col = offsetCols + (7 + iter.getDay() - this._weekStart) % 7;
layout.attach(label, col, 1, 1, 1);
iter.setTime(iter.getTime() + MSECS_IN_DAY);
}
@ -548,6 +557,7 @@ const Calendar = new Lang.Class({
_onSettingsChange: function() {
this._useWeekdate = this._settings.get_boolean(SHOW_WEEKDATE_KEY);
this._buildHeader();
this._rebuildCalendar();
this._update();
},
@ -593,6 +603,7 @@ const Calendar = new Lang.Class({
beginDate.setTime(beginDate.getTime() - (weekPadding + daysToWeekStart) * MSECS_IN_DAY);
let layout = this.actor.layout_manager;
let iter = new Date(beginDate);
let row = 2;
// nRows here means 6 weeks + one header + one navbar
@ -607,7 +618,9 @@ const Calendar = new Lang.Class({
button._date = new Date(iter);
button.connect('clicked', Lang.bind(this, function() {
this._shouldDateGrabFocus = true;
this.setDate(button._date);
this._shouldDateGrabFocus = false;
}));
let hasEvents = this._eventSource.hasEvents(iter);
@ -638,16 +651,19 @@ const Calendar = new Lang.Class({
button.style_class = styleClass;
let offsetCols = this._useWeekdate ? 1 : 0;
this.actor.add(button,
{ row: row, col: offsetCols + (7 + iter.getDay() - this._weekStart) % 7 });
let col;
if (rtl)
col = 6 - (7 + iter.getDay() - this._weekStart) % 7;
else
col = offsetCols + (7 + iter.getDay() - this._weekStart) % 7;
layout.attach(button, col, row, 1, 1);
this._buttons.push(button);
if (this._useWeekdate && iter.getDay() == 4) {
let label = new St.Label({ text: _getCalendarWeekForDate(iter).toString(),
style_class: 'calendar-day-base calendar-week-number'});
this.actor.add(label,
{ row: row, col: 0, y_align: St.Align.MIDDLE });
layout.attach(label, rtl ? 7 : 0, row, 1, 1);
}
iter.setTime(iter.getTime() + MSECS_IN_DAY);
@ -673,8 +689,11 @@ const Calendar = new Lang.Class({
this._rebuildCalendar();
this._buttons.forEach(Lang.bind(this, function(button) {
if (_sameDay(button._date, this._selectedDate))
if (_sameDay(button._date, this._selectedDate)) {
button.add_style_pseudo_class('active');
if (this._shouldDateGrabFocus)
button.grab_key_focus();
}
else
button.remove_style_pseudo_class('active');
}));
@ -687,9 +706,12 @@ const EventsList = new Lang.Class({
Name: 'EventsList',
_init: function() {
this.actor = new St.Table({ style_class: 'events-table' });
let layout = new Clutter.GridLayout({ orientation: Clutter.Orientation.VERTICAL });
this.actor = new St.Widget({ style_class: 'events-table',
layout_manager: layout });
layout.hookup_style(this.actor);
this._date = new Date();
this._desktopSettings = new Gio.Settings({ schema: 'org.gnome.desktop.interface' });
this._desktopSettings = new Gio.Settings({ schema_id: 'org.gnome.desktop.interface' });
this._desktopSettings.connect('changed', Lang.bind(this, this._update));
this._weekStart = Shell.util_get_week_start();
},
@ -707,33 +729,34 @@ const EventsList = new Lang.Class({
dayString = '';
let dayLabel = new St.Label({ style_class: 'events-day-dayname',
text: dayString });
text: dayString,
x_align: Clutter.ActorAlign.END,
y_align: Clutter.ActorAlign.START });
dayLabel.clutter_text.line_wrap = false;
dayLabel.clutter_text.ellipsize = false;
this.actor.add(dayLabel, { row: index, col: 0,
x_expand: false, x_align: St.Align.END,
y_fill: false, y_align: St.Align.START });
let rtl = this.actor.get_text_direction() == Clutter.TextDirection.RTL;
let layout = this.actor.layout_manager;
layout.attach(dayLabel, rtl ? 2 : 0, index, 1, 1);
let clockFormat = this._desktopSettings.get_string(CLOCK_FORMAT_KEY);
let timeString = _formatEventTime(event, clockFormat);
let timeLabel = new St.Label({ style_class: 'events-day-time',
text: timeString });
text: timeString,
y_align: Clutter.ActorAlign.START });
timeLabel.clutter_text.line_wrap = false;
timeLabel.clutter_text.ellipsize = false;
this.actor.add(timeLabel, { row: index, col: 1,
x_expand: false, x_align: St.Align.MIDDLE,
y_fill: false, y_align: St.Align.START });
layout.attach(timeLabel, 1, index, 1, 1);
let titleLabel = new St.Label({ style_class: 'events-day-task',
text: event.summary });
text: event.summary,
x_expand: true });
titleLabel.clutter_text.line_wrap = true;
titleLabel.clutter_text.ellipsize = false;
this.actor.add(titleLabel, { row: index, col: 2,
x_expand: true, x_align: St.Align.START,
y_fill: false, y_align: St.Align.START });
layout.attach(titleLabel, rtl ? 0 : 2, index, 1, 1);
},
_addPeriod: function(header, index, begin, end, includeDayName, showNothingScheduled) {
@ -742,13 +765,9 @@ const EventsList = new Lang.Class({
if (events.length == 0 && !showNothingScheduled)
return index;
this.actor.add(new St.Label({ style_class: 'events-day-header', text: header }),
{ row: index, col: 0, col_span: 3,
// In theory, x_expand should be true here, but x_expand
// is a property of the column for StTable, ie all day cells
// get it too
x_expand: false, x_align: St.Align.START,
y_fill: false, y_align: St.Align.START });
let label = new St.Label({ style_class: 'events-day-header', text: header });
let layout = this.actor.layout_manager;
layout.attach(label, 0, index, 3, 1);
index++;
for (let n = 0; n < events.length; n++) {

View File

@ -23,7 +23,7 @@ const AutomountManager = new Lang.Class({
Name: 'AutomountManager',
_init: function() {
this._settings = new Gio.Settings({ schema: SETTINGS_SCHEMA });
this._settings = new Gio.Settings({ schema_id: SETTINGS_SCHEMA });
this._volumeQueue = [];
this._session = new GnomeSession.SessionManager();
this._session.connectSignal('InhibitorAdded',
@ -43,6 +43,7 @@ const AutomountManager = new Lang.Class({
this._driveEjectButtonId = this._volumeMonitor.connect('drive-eject-button', Lang.bind(this, this._onDriveEjectButton));
this._mountAllId = Mainloop.idle_add(Lang.bind(this, this._startupMountAll));
GLib.Source.set_name_by_id(this._mountAllId, '[gnome-shell] this._startupMountAll');
},
disable: function() {
@ -234,10 +235,11 @@ const AutomountManager = new Lang.Class({
},
_allowAutorunExpire: function(volume) {
Mainloop.timeout_add_seconds(AUTORUN_EXPIRE_TIMEOUT_SECS, function() {
let id = Mainloop.timeout_add_seconds(AUTORUN_EXPIRE_TIMEOUT_SECS, function() {
volume.allowAutorun = false;
return GLib.SOURCE_REMOVE;
});
GLib.Source.set_name_by_id(id, '[gnome-shell] volume.allowAutorun');
}
});
const Component = AutomountManager;

View File

@ -96,7 +96,7 @@ const ContentTypeDiscoverer = new Lang.Class({
_init: function(callback) {
this._callback = callback;
this._settings = new Gio.Settings({ schema: SETTINGS_SCHEMA });
this._settings = new Gio.Settings({ schema_id: SETTINGS_SCHEMA });
},
guessContentTypes: function(mount) {
@ -441,7 +441,7 @@ const AutorunTransientDispatcher = new Lang.Class({
_init: function(manager) {
this._manager = manager;
this._sources = [];
this._settings = new Gio.Settings({ schema: SETTINGS_SCHEMA });
this._settings = new Gio.Settings({ schema_id: SETTINGS_SCHEMA });
},
_getAutorunSettingForType: function(contentType) {

View File

@ -80,44 +80,58 @@ const KeyringDialog = new Lang.Class({
},
_buildControlTable: function() {
let layout = new Clutter.TableLayout();
let layout = new Clutter.GridLayout({ orientation: Clutter.Orientation.VERTICAL });
let table = new St.Widget({ style_class: 'keyring-dialog-control-table',
layout_manager: layout });
layout.hookup_style(table);
let rtl = table.get_text_direction() == Clutter.TextDirection.RTL;
let row = 0;
if (this.prompt.password_visible) {
let label = new St.Label({ style_class: 'prompt-dialog-password-label' });
let label = new St.Label({ style_class: 'prompt-dialog-password-label',
x_align: Clutter.ActorAlign.START,
y_align: Clutter.ActorAlign.CENTER });
label.set_text(_("Password:"));
label.clutter_text.ellipsize = Pango.EllipsizeMode.NONE;
layout.pack(label, 0, row);
layout.child_set(label, { x_expand: false, y_fill: false,
x_align: Clutter.TableAlignment.START });
this._passwordEntry = new St.Entry({ style_class: 'prompt-dialog-password-entry',
text: '',
can_focus: true });
can_focus: true,
x_expand: true });
this._passwordEntry.clutter_text.set_password_char('\u25cf'); // ● U+25CF BLACK CIRCLE
ShellEntry.addContextMenu(this._passwordEntry, { isPassword: true });
this._passwordEntry.clutter_text.connect('activate', Lang.bind(this, this._onPasswordActivate));
layout.pack(this._passwordEntry, 1, row);
if (rtl) {
layout.attach(this._passwordEntry, 0, row, 1, 1);
layout.attach(label, 1, row, 1, 1);
} else {
layout.attach(label, 0, row, 1, 1);
layout.attach(this._passwordEntry, 1, row, 1, 1);
}
row++;
} else {
this._passwordEntry = null;
}
if (this.prompt.confirm_visible) {
var label = new St.Label(({ style_class: 'prompt-dialog-password-label' }));
var label = new St.Label(({ style_class: 'prompt-dialog-password-label',
x_align: Clutter.ActorAlign.START,
y_align: Clutter.ActorAlign.CENTER }));
label.set_text(_("Type again:"));
layout.pack(label, 0, row);
layout.child_set(label, { x_expand: false, y_fill: false,
x_align: Clutter.TableAlignment.START });
this._confirmEntry = new St.Entry({ style_class: 'prompt-dialog-password-entry',
text: '',
can_focus: true });
can_focus: true,
x_expand: true });
this._confirmEntry.clutter_text.set_password_char('\u25cf'); // ● U+25CF BLACK CIRCLE
ShellEntry.addContextMenu(this._confirmEntry, { isPassword: true });
this._confirmEntry.clutter_text.connect('activate', Lang.bind(this, this._onConfirmActivate));
layout.pack(this._confirmEntry, 1, row);
if (rtl) {
layout.attach(this._confirmEntry, 0, row, 1, 1);
layout.attach(label, 1, row, 1, 1);
} else {
layout.attach(label, 0, row, 1, 1);
layout.attach(this._confirmEntry, 1, row, 1, 1);
}
row++;
} else {
this._confirmEntry = null;
@ -130,15 +144,15 @@ const KeyringDialog = new Lang.Class({
let choice = new CheckBox.CheckBox();
this.prompt.bind_property('choice-label', choice.getLabelActor(), 'text', GObject.BindingFlags.SYNC_CREATE);
this.prompt.bind_property('choice-chosen', choice.actor, 'checked', GObject.BindingFlags.SYNC_CREATE | GObject.BindingFlags.BIDIRECTIONAL);
layout.pack(choice.actor, 1, row);
layout.attach(choice.actor, rtl ? 0 : 1, row, 1, 1);
row++;
}
let warning = new St.Label({ style_class: 'prompt-dialog-error-label' });
let warning = new St.Label({ style_class: 'prompt-dialog-error-label',
x_align: Clutter.ActorAlign.START });
warning.clutter_text.ellipsize = Pango.EllipsizeMode.NONE;
warning.clutter_text.line_wrap = true;
layout.pack(warning, 1, row);
layout.child_set(warning, { x_fill: false, x_align: Clutter.TableAlignment.START });
layout.attach(warning, rtl ? 0 : 1, row, 1, 1);
this.prompt.bind_property('warning-visible', warning, 'visible', GObject.BindingFlags.SYNC_CREATE);
this.prompt.bind_property('warning', warning, 'text', GObject.BindingFlags.SYNC_CREATE);

View File

@ -72,24 +72,28 @@ const NetworkSecretDialog = new Lang.Class({
expand: true });
}
let layout = new Clutter.TableLayout();
let layout = new Clutter.GridLayout({ orientation: Clutter.Orientation.VERTICAL });
let secretTable = new St.Widget({ style_class: 'network-dialog-secret-table',
layout_manager: layout });
layout.hookup_style(secretTable);
let rtl = secretTable.get_text_direction() == Clutter.TextDirection.RTL;
let initialFocusSet = false;
let pos = 0;
for (let i = 0; i < this._content.secrets.length; i++) {
let secret = this._content.secrets[i];
let label = new St.Label({ style_class: 'prompt-dialog-password-label',
text: secret.label });
text: secret.label,
x_align: Clutter.ActorAlign.START,
y_align: Clutter.ActorAlign.CENTER });
label.clutter_text.ellipsize = Pango.EllipsizeMode.NONE;
let reactive = secret.key != null;
secret.entry = new St.Entry({ style_class: 'prompt-dialog-password-entry',
text: secret.value, can_focus: reactive,
reactive: reactive });
reactive: reactive,
x_expand: true });
ShellEntry.addContextMenu(secret.entry,
{ isPassword: secret.password });
@ -116,10 +120,13 @@ const NetworkSecretDialog = new Lang.Class({
} else
secret.valid = true;
layout.pack(label, 0, pos);
layout.child_set(label, { x_expand: false, y_fill: false,
x_align: Clutter.TableAlignment.START });
layout.pack(secret.entry, 1, pos);
if (rtl) {
layout.attach(secret.entry, 0, pos, 1, 1);
layout.attach(label, 1, pos, 1, 1);
} else {
layout.attach(label, 0, pos, 1, 1);
layout.attach(secret.entry, 1, pos, 1, 1);
}
pos++;
if (secret.password)
@ -510,10 +517,12 @@ const VPNRequestHandler = new Lang.Class({
_showNewStyleDialog: function() {
let keyfile = new GLib.KeyFile();
let data;
let contentOverride;
try {
let data = this._dataStdout.peek_buffer();
data = this._dataStdout.peek_buffer();
keyfile.load_from_data(data.toString(), data.length,
GLib.KeyFileFlags.NONE);
@ -546,13 +555,16 @@ const VPNRequestHandler = new Lang.Class({
}
}
} catch(e) {
logError(e, 'error while reading VPN plugin output keyfile');
// No output is a valid case it means "both secrets are stored"
if (data.length > 0) {
logError(e, 'error while reading VPN plugin output keyfile');
this._agent.respond(this._requestId, Shell.NetworkAgentResponse.INTERNAL_ERROR);
return;
this._agent.respond(this._requestId, Shell.NetworkAgentResponse.INTERNAL_ERROR);
return;
}
}
if (contentOverride.secrets.length) {
if (contentOverride && contentOverride.secrets.length) {
// Only show the dialog if we actually have something to ask
this._shellDialog = new NetworkSecretDialog(this._agent, this._requestId, this._connection, 'vpn', [], contentOverride);
this._shellDialog.open(global.get_current_time());

View File

@ -1,5 +1,6 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
const Clutter = imports.gi.Clutter;
const Gio = imports.gi.Gio;
const GLib = imports.gi.GLib;
const Lang = imports.lang;
@ -28,6 +29,8 @@ const SCROLLBACK_HISTORY_LINES = 10;
// See Notification._onEntryChanged
const COMPOSING_STOP_TIMEOUT = 5;
const CLOCK_FORMAT_KEY = 'clock-format';
const NotificationDirection = {
SENT: 'chat-sent',
RECEIVED: 'chat-received'
@ -678,6 +681,7 @@ const ChatSource = new Lang.Class({
Mainloop.source_remove(this._notifyTimeoutId);
this._notifyTimeoutId = Mainloop.timeout_add(500,
Lang.bind(this, this._notifyTimeout));
GLib.Source.set_name_by_id(this._notifyTimeoutId, '[gnome-shell] this._notifyTimeout');
},
_notifyTimeout: function() {
@ -779,7 +783,6 @@ const ChatNotification = new Lang.Class({
this._createScrollArea();
this._lastGroup = null;
this._lastGroupActor = null;
// Keep track of the bottom position for the current adjustment and
// force a scroll to the bottom if things change while we were at the
@ -860,13 +863,6 @@ const ChatNotification = new Lang.Class({
for (let i = 0; i < expired.length; i++)
expired[i].actor.destroy();
}
let groups = this._contentArea.get_children();
for (let i = 0; i < groups.length; i++) {
let group = groups[i];
if (group.get_n_children() == 0)
group.destroy();
}
},
/**
@ -905,30 +901,35 @@ const ChatNotification = new Lang.Class({
let group = props.group;
if (group != this._lastGroup) {
let style = 'chat-group-' + group;
this._lastGroup = group;
this._lastGroupActor = new St.BoxLayout({ style_class: style,
vertical: true });
this.addActor(this._lastGroupActor);
let emptyLine = new St.Label({ style_class: 'chat-empty-line' });
this.addActor(emptyLine);
this._history.unshift({ actor: emptyLine, time: timestamp,
realMessage: false });
}
this._lastGroupActor.add(body, props.childProps);
let lineBox = new St.BoxLayout({ vertical: false });
lineBox.add(body, props.childProps);
this.addActor(lineBox);
this._lastMessageBox = lineBox;
this.updated();
let timestamp = props.timestamp;
this._history.unshift({ actor: body, time: timestamp,
this._history.unshift({ actor: lineBox, time: timestamp,
realMessage: group != 'meta' });
if (!props.noTimestamp) {
if (timestamp < currentTime - SCROLLBACK_IMMEDIATE_TIME)
if (timestamp < currentTime - SCROLLBACK_IMMEDIATE_TIME) {
this.appendTimestamp();
else
} else {
// Schedule a new timestamp in SCROLLBACK_IMMEDIATE_TIME
// from the timestamp of the message.
this._timestampTimeoutId = Mainloop.timeout_add_seconds(
SCROLLBACK_IMMEDIATE_TIME - (currentTime - timestamp),
Lang.bind(this, this.appendTimestamp));
GLib.Source.set_name_by_id(this._timestampTimeoutId, '[gnome-shell] this.appendTimestamp');
}
}
this._filterMessages();
@ -941,32 +942,77 @@ const ChatNotification = new Lang.Class({
let format;
// Show only the hour if date is on today
if(daysAgo < 1){
format = "<b>%H:%M</b>";
}
// Show the word "Yesterday" and time if date is on yesterday
else if(daysAgo <2){
/* Translators: this is the word "Yesterday" followed by a time string. i.e. "Yesterday, 14:30"*/
// xgettext:no-c-format
format = _("<b>Yesterday</b>, <b>%H:%M</b>");
}
// Show a week day and time if date is in the last week
else if (daysAgo < 7) {
/* Translators: this is the week day name followed by a time string. i.e. "Monday, 14:30*/
// xgettext:no-c-format
format = _("<b>%A</b>, <b>%H:%M</b>");
let desktopSettings = new Gio.Settings({ schema_id: 'org.gnome.desktop.interface' });
let clockFormat = desktopSettings.get_string(CLOCK_FORMAT_KEY);
let hasAmPm = date.toLocaleFormat('%p') != '';
} else if (date.getYear() == now.getYear()) {
/* Translators: this is the month name and day number followed by a time string. i.e. "May 25, 14:30"*/
// xgettext:no-c-format
format = _("<b>%B</b> <b>%d</b>, <b>%H:%M</b>");
if (clockFormat == '24h' || !hasAmPm) {
// Show only the time if date is on today
if(daysAgo < 1){
/* Translators: Time in 24h format */
format = _("%H\u2236%M");
}
// Show the word "Yesterday" and time if date is on yesterday
else if(daysAgo <2){
/* Translators: this is the word "Yesterday" followed by a
time string in 24h format. i.e. "Yesterday, 14:30" */
// xgettext:no-c-format
format = _("Yesterday, %H\u2236%M");
}
// Show a week day and time if date is in the last week
else if (daysAgo < 7) {
/* Translators: this is the week day name followed by a time
string in 24h format. i.e. "Monday, 14:30" */
// xgettext:no-c-format
format = _("%A, %H\u2236%M");
} else if (date.getYear() == now.getYear()) {
/* Translators: this is the month name and day number
followed by a time string in 24h format.
i.e. "May 25, 14:30" */
// xgettext:no-c-format
format = _("%B %d, %H\u2236%M");
} else {
/* Translators: this is the month name, day number, year
number followed by a time string in 24h format.
i.e. "May 25 2012, 14:30" */
// xgettext:no-c-format
format = _("%B %d %Y, %H\u2236%M");
}
} else {
/* Translators: this is the month name, day number, year number followed by a time string. i.e. "May 25 2012, 14:30"*/
// xgettext:no-c-format
format = _("<b>%B</b> <b>%d</b> <b>%Y</b>, <b>%H:%M</b> ");
}
// Show only the time if date is on today
if(daysAgo < 1){
/* Translators: Time in 24h format */
format = _("%l\u2236%M %p");
}
// Show the word "Yesterday" and time if date is on yesterday
else if(daysAgo <2){
/* Translators: this is the word "Yesterday" followed by a
time string in 12h format. i.e. "Yesterday, 2:30 pm" */
// xgettext:no-c-format
format = _("Yesterday, %l\u2236%M %p");
}
// Show a week day and time if date is in the last week
else if (daysAgo < 7) {
/* Translators: this is the week day name followed by a time
string in 12h format. i.e. "Monday, 2:30 pm" */
// xgettext:no-c-format
format = _("%A, %l\u2236%M %p");
} else if (date.getYear() == now.getYear()) {
/* Translators: this is the month name and day number
followed by a time string in 12h format.
i.e. "May 25, 2:30 pm" */
// xgettext:no-c-format
format = _("%B %d, %l\u2236%M %p");
} else {
/* Translators: this is the month name, day number, year
number followed by a time string in 12h format.
i.e. "May 25 2012, 2:30 pm"*/
// xgettext:no-c-format
format = _("%B %d %Y, %l\u2236%M %p");
}
}
return date.toLocaleFormat(format);
},
@ -976,13 +1022,14 @@ const ChatNotification = new Lang.Class({
let lastMessageTime = this._history[0].time;
let lastMessageDate = new Date(lastMessageTime * 1000);
let timeLabel = this._append({ body: this._formatTimestamp(lastMessageDate),
group: 'meta',
styles: ['chat-meta-message'],
childProps: { expand: true, x_fill: false,
x_align: St.Align.END },
noTimestamp: true,
timestamp: lastMessageTime });
let timeLabel = new St.Label({ text: this._formatTimestamp(lastMessageDate),
style_class: 'chat-meta-message',
x_expand: true,
y_expand: true,
x_align: Clutter.ActorAlign.END,
y_align: Clutter.ActorAlign.END });
this._lastMessageBox.add_actor(timeLabel);
this._filterMessages();
@ -1047,6 +1094,7 @@ const ChatNotification = new Lang.Class({
this._composingTimeoutId = Mainloop.timeout_add_seconds(
COMPOSING_STOP_TIMEOUT,
Lang.bind(this, this._composingStopTimeout));
GLib.Source.set_name_by_id(this._composingTimeoutId, '[gnome-shell] this._composingStopTimeout');
} else {
this.source.setChatState(Tp.ChannelChatState.ACTIVE);
}
@ -1217,7 +1265,8 @@ const SubscriptionRequestNotification = new Lang.Class({
if (file) {
let uri = file.get_uri();
iconBox.child = textureCache.load_uri_async(uri, iconBox._size, iconBox._size);
let scaleFactor = St.ThemeContext.get_for_stage(global.stage).scale_factor;
iconBox.child = textureCache.load_uri_async(uri, iconBox._size, iconBox._size, scaleFactor);
}
else {
iconBox.child = new St.Icon({ icon_name: 'avatar-default',
@ -1368,7 +1417,12 @@ const AccountNotification = new Lang.Class({
if (status == Tp.ConnectionStatus.CONNECTED) {
this.destroy();
} else if (status == Tp.ConnectionStatus.DISCONNECTED) {
this.update(this.title, this._getMessage(account.connection_error));
let connectionError = account.connection_error;
if (connectionError == Tp.error_get_dbus_name(Tp.Error.CANCELLED))
this.destroy();
else
this.update(this.title, this._getMessage(connectionError));
}
}));
},

View File

@ -87,7 +87,7 @@ const CtrlAltTabManager = new Lang.Class({
if (Main.sessionMode.hasWindows && !Main.overview.visible) {
let screen = global.screen;
let display = screen.get_display();
let windows = display.get_tab_list(Meta.TabList.DOCKS, screen, screen.get_active_workspace ());
let windows = display.get_tab_list(Meta.TabList.DOCKS, screen.get_active_workspace ());
let windowTracker = Shell.WindowTracker.get_default();
let textureCache = St.TextureCache.get_default();
for (let i = 0; i < windows.length; i++) {
@ -140,31 +140,25 @@ const CtrlAltTabPopup = new Lang.Class({
Name: 'CtrlAltTabPopup',
Extends: SwitcherPopup.SwitcherPopup,
_createSwitcher: function() {
_init: function(items) {
this.parent(items);
this._switcherList = new CtrlAltTabSwitcher(this._items);
return true;
},
_initialSelection: function(backward, binding) {
if (binding == 'switch-panels') {
if (backward)
this._selectedIndex = this._items.length - 1;
} else if (binding == 'switch-panels-backward') {
if (!backward)
this._selectedIndex = this._items.length - 1;
}
this._select(this._selectedIndex);
},
_keyPressHandler: function(keysym, backwards, action) {
_keyPressHandler: function(keysym, action) {
if (action == Meta.KeyBindingAction.SWITCH_PANELS)
this._select(backwards ? this._previous() : this._next());
this._select(this._next());
else if (action == Meta.KeyBindingAction.SWITCH_PANELS_BACKWARD)
this._select(backwards ? this._next() : this._previous());
this._select(this._previous());
else if (keysym == Clutter.Left)
this._select(this._previous());
else if (keysym == Clutter.Right)
this._select(this._next());
else
return Clutter.EVENT_PROPAGATE;
return Clutter.EVENT_STOP;
},
_finish : function(time) {

View File

@ -381,6 +381,8 @@ const DashActor = new Lang.Class({
}
});
const baseIconSizes = [ 16, 22, 24, 32, 48, 64 ];
const Dash = new Lang.Class({
Name: 'Dash',
@ -580,6 +582,7 @@ const Dash = new Lang.Class({
this._showLabelTimeoutId = 0;
return GLib.SOURCE_REMOVE;
}));
GLib.Source.set_name_by_id(this._showLabelTimeoutId, '[gnome-shell] item.showLabel');
if (this._resetHoverTimeoutId > 0) {
Mainloop.source_remove(this._resetHoverTimeoutId);
this._resetHoverTimeoutId = 0;
@ -597,6 +600,7 @@ const Dash = new Lang.Class({
this._resetHoverTimeoutId = 0;
return GLib.SOURCE_REMOVE;
}));
GLib.Source.set_name_by_id(this._resetHoverTimeoutId, '[gnome-shell] this._labelShowing');
}
}
},
@ -632,25 +636,24 @@ const Dash = new Lang.Class({
let minHeight, natHeight;
// Enforce the current icon size during the size request
let [currentWidth, currentHeight] = firstIcon.icon.get_size();
firstIcon.icon.set_size(this.iconSize, this.iconSize);
firstIcon.setIconSize(this.iconSize);
[minHeight, natHeight] = firstButton.get_preferred_height(-1);
firstIcon.icon.set_size(currentWidth, currentHeight);
let scaleFactor = St.ThemeContext.get_for_stage(global.stage).scale_factor;
let iconSizes = baseIconSizes.map(function(s) {
return s * scaleFactor;
});
// Subtract icon padding and box spacing from the available height
availHeight -= iconChildren.length * (natHeight - this.iconSize) +
availHeight -= iconChildren.length * (natHeight - this.iconSize * scaleFactor) +
(iconChildren.length - 1) * spacing;
let availSize = availHeight / iconChildren.length;
let iconSizes = [ 16, 22, 24, 32, 48, 64 ];
let newIconSize = 16;
let newIconSize = baseIconSizes[0];
for (let i = 0; i < iconSizes.length; i++) {
if (iconSizes[i] < availSize)
newIconSize = iconSizes[i];
newIconSize = baseIconSizes[i];
}
if (newIconSize == this.iconSize)

View File

@ -18,8 +18,7 @@ const PanelMenu = imports.ui.panelMenu;
const PopupMenu = imports.ui.popupMenu;
const Calendar = imports.ui.calendar;
function _onVertSepRepaint (area)
{
function _onVertSepRepaint(area) {
let cr = area.get_context();
let themeNode = area.get_theme_node();
let [width, height] = area.get_surface_size();
@ -33,7 +32,7 @@ function _onVertSepRepaint (area)
cr.setLineWidth(stippleWidth);
cr.stroke();
cr.$dispose();
};
}
const DateMenuButton = new Lang.Class({
Name: 'DateMenuButton',
@ -63,9 +62,17 @@ const DateMenuButton = new Lang.Class({
hbox.add(vbox);
// Date
this._date = new St.Label({ style_class: 'datemenu-date-label',
can_focus: true });
vbox.add(this._date);
// Having the ability to go to the current date if the user is already
// on the current date can be confusing. So don't make the button reactive
// until the selected date changes.
this._date = new St.Button({ style_class: 'datemenu-date-label',
reactive: false
});
this._date.connect('clicked',
Lang.bind(this, function() {
this._calendar.setDate(new Date(), false);
}));
vbox.add(this._date, { x_fill: false });
this._eventList = new Calendar.EventsList();
this._calendar = new Calendar.Calendar();
@ -77,6 +84,9 @@ const DateMenuButton = new Lang.Class({
// and the calender makes those dates unclickable when instantiated with
// a null event source
this._eventList.setDate(date);
// Make the button reactive only if the selected date is not the current date.
this._date.can_focus = this._date.reactive = !this._isToday(date)
}));
vbox.add(this._calendar.actor);
@ -127,6 +137,13 @@ const DateMenuButton = new Lang.Class({
this._sessionUpdated();
},
_isToday: function(date) {
let now = new Date();
return now.getYear() == date.getYear() &&
now.getMonth() == date.getMonth() &&
now.getDay() == date.getDay();
},
_appInstalledChanged: function() {
this._calendarApp = undefined;
this._updateEventsVisibility();
@ -186,7 +203,7 @@ const DateMenuButton = new Lang.Class({
*/
let dateFormat = _("%A %B %e, %Y");
let displayDate = new Date();
this._date.set_text(displayDate.toLocaleFormat(dateFormat));
this._date.set_label(displayDate.toLocaleFormat(dateFormat));
},
_getCalendarApp: function() {
@ -194,15 +211,18 @@ const DateMenuButton = new Lang.Class({
return this._calendarApp;
let apps = Gio.AppInfo.get_recommended_for_type('text/calendar');
if (apps && (apps.length > 0))
this._calendarApp = apps[0];
else
if (apps && (apps.length > 0)) {
let app = Gio.AppInfo.get_default_for_type('text/calendar', false);
let defaultInRecommended = apps.some(function(a) { return a.equal(app); });
this._calendarApp = defaultInRecommended ? app : apps[0];
} else {
this._calendarApp = null;
}
return this._calendarApp;
},
_getClockApp: function() {
return Shell.AppSystem.get_default().lookup_app('gnome-clocks.desktop');
return Shell.AppSystem.get_default().lookup_app('org.gnome.clocks.desktop');
},
_onOpenCalendarActivate: function() {

View File

@ -395,6 +395,7 @@ const _Draggable = new Lang.Class({
this._updateHoverId = GLib.idle_add(GLib.PRIORITY_DEFAULT,
Lang.bind(this, this._updateDragHover));
GLib.Source.set_name_by_id(this._updateHoverId, '[gnome-shell] this._updateDragHover');
},
_updateDragPosition : function (event) {

78
js/ui/edgeDragAction.js Normal file
View File

@ -0,0 +1,78 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
const Lang = imports.lang;
const Signals = imports.signals;
const Meta = imports.gi.Meta;
const Clutter = imports.gi.Clutter;
const St = imports.gi.St;
const EDGE_THRESHOLD = 20;
const DRAG_DISTANCE = 80;
const EdgeDragAction = new Lang.Class({
Name: 'EdgeDragAction',
Extends: Clutter.GestureAction,
_init : function(side) {
this.parent();
this._side = side;
this.set_n_touch_points(1);
global.display.connect('grab-op-begin', Lang.bind(this, function() {
this.cancel();
}));
},
_getMonitorRect : function (x, y) {
let rect = new Meta.Rectangle({ x: x - 1, y: y - 1, width: 1, height: 1 });
let monitorIndex = global.screen.get_monitor_index_for_rect(rect);
return global.screen.get_monitor_geometry(monitorIndex);
},
vfunc_gesture_prepare : function(action, actor) {
if (this.get_n_current_points() == 0)
return false;
let [x, y] = this.get_press_coords(0);
let monitorRect = this._getMonitorRect(x, y);
return ((this._side == St.Side.LEFT && x < monitorRect.x + EDGE_THRESHOLD) ||
(this._side == St.Side.RIGHT && x > monitorRect.x + monitorRect.width - EDGE_THRESHOLD) ||
(this._side == St.Side.TOP && y < monitorRect.y + EDGE_THRESHOLD) ||
(this._side == St.Side.BOTTOM && y > monitorRect.y + monitorRect.height - EDGE_THRESHOLD));
},
vfunc_gesture_progress : function (action, actor) {
let [startX, startY] = this.get_press_coords(0);
let [x, y] = this.get_motion_coords(0);
let offsetX = Math.abs (x - startX);
let offsetY = Math.abs (y - startY);
if (offsetX < EDGE_THRESHOLD && offsetY < EDGE_THRESHOLD)
return true;
if ((offsetX > offsetY &&
(this._side == St.Side.TOP || this._side == St.Side.BOTTOM)) ||
(offsetY > offsetX &&
(this._side == St.Side.LEFT || this._side == St.Side.RIGHT))) {
this.cancel();
return false;
}
return true;
},
vfunc_gesture_end : function (action, actor) {
let [startX, startY] = this.get_press_coords(0);
let [x, y] = this.get_motion_coords(0);
let monitorRect = this._getMonitorRect(startX, startY);
if ((this._side == St.Side.TOP && y > monitorRect.y + DRAG_DISTANCE) ||
(this._side == St.Side.BOTTOM && y < monitorRect.y + monitorRect.height - DRAG_DISTANCE) ||
(this._side == St.Side.LEFT && x > monitorRect.x + DRAG_DISTANCE) ||
(this._side == St.Side.RIGHT && x < monitorRect.x + monitorRect.width - DRAG_DISTANCE))
this.emit('activated');
}
});
Signals.addSignalMethods(EdgeDragAction.prototype);

View File

@ -25,9 +25,11 @@ const Gio = imports.gi.Gio;
const GLib = imports.gi.GLib;
const Gtk = imports.gi.Gtk;
const Pango = imports.gi.Pango;
const Polkit = imports.gi.Polkit;
const St = imports.gi.St;
const Shell = imports.gi.Shell;
const CheckBox = imports.ui.checkBox;
const GnomeSession = imports.misc.gnomeSession;
const LoginManager = imports.misc.loginManager;
const ModalDialog = imports.ui.modalDialog;
@ -37,7 +39,7 @@ const UserWidget = imports.ui.userWidget;
let _endSessionDialog = null;
const _ITEM_ICON_SIZE = 48;
const _DIALOG_ICON_SIZE = 32;
const _DIALOG_ICON_SIZE = 48;
const GSM_SESSION_MANAGER_LOGOUT_FORCE = 2;
@ -71,6 +73,7 @@ const logoutDialogContent = {
"You will be logged out automatically in %d seconds.",
seconds).format(seconds);
},
showBatteryWarning: false,
confirmButtons: [{ signal: 'ConfirmedLogout',
label: C_("button", "Log Out") }],
iconStyleClass: 'end-session-dialog-logout-icon',
@ -79,11 +82,14 @@ const logoutDialogContent = {
const shutdownDialogContent = {
subject: C_("title", "Power Off"),
subjectWithUpdates: C_("title", "Install Updates & Power Off"),
description: function(seconds) {
return ngettext("The system will power off automatically in %d second.",
"The system will power off automatically in %d seconds.",
seconds).format(seconds);
},
checkBoxText: C_("checkbox", "Install pending software updates"),
showBatteryWarning: true,
confirmButtons: [{ signal: 'ConfirmedReboot',
label: C_("button", "Restart") },
{ signal: 'ConfirmedShutdown',
@ -100,6 +106,7 @@ const restartDialogContent = {
"The system will restart automatically in %d seconds.",
seconds).format(seconds);
},
showBatteryWarning: false,
confirmButtons: [{ signal: 'ConfirmedReboot',
label: C_("button", "Restart") }],
iconName: 'view-refresh-symbolic',
@ -115,18 +122,28 @@ const restartInstallDialogContent = {
"The system will automatically restart and install updates in %d seconds.",
seconds).format(seconds);
},
showBatteryWarning: true,
confirmButtons: [{ signal: 'ConfirmedReboot',
label: C_("button", "Restart & Install") }],
label: C_("button", "Restart &amp; Install") }],
unusedFutureButtonForTranslation: C_("button", "Install &amp; Power Off"),
unusedFutureCheckBoxForTranslation: C_("checkbox", "Power off after updates are installed"),
iconName: 'view-refresh-symbolic',
iconStyleClass: 'end-session-dialog-shutdown-icon',
showOtherSessions: true,
};
const DialogType = {
LOGOUT: 0 /* GSM_SHELL_END_SESSION_DIALOG_TYPE_LOGOUT */,
SHUTDOWN: 1 /* GSM_SHELL_END_SESSION_DIALOG_TYPE_SHUTDOWN */,
RESTART: 2 /* GSM_SHELL_END_SESSION_DIALOG_TYPE_RESTART */,
UPDATE_RESTART: 3
};
const DialogContent = {
0 /* GSM_SHELL_END_SESSION_DIALOG_TYPE_LOGOUT */: logoutDialogContent,
1 /* GSM_SHELL_END_SESSION_DIALOG_TYPE_SHUTDOWN */: shutdownDialogContent,
2 /* GSM_SHELL_END_SESSION_DIALOG_TYPE_RESTART */: restartDialogContent,
3: restartInstallDialogContent
0 /* DialogType.LOGOUT */: logoutDialogContent,
1 /* DialogType.SHUTDOWN */: shutdownDialogContent,
2 /* DialogType.RESTART */: restartDialogContent,
3 /* DialogType.UPDATE_RESTART */: restartInstallDialogContent
};
const MAX_USERS_IN_SESSION_DIALOG = 5;
@ -143,6 +160,27 @@ const LogindSessionIface = '<node> \
const LogindSession = Gio.DBusProxy.makeProxyWrapper(LogindSessionIface);
const PkOfflineIface = '<node> \
<interface name="org.freedesktop.PackageKit.Offline"> \
<property name="UpdatePrepared" type="b" access="read"/> \
<property name="TriggerAction" type="s" access="read"/> \
<method name="Trigger"> \
<arg type="s" name="action" direction="in"/> \
</method> \
<method name="Cancel"/> \
</interface> \
</node>';
const PkOfflineProxy = Gio.DBusProxy.makeProxyWrapper(PkOfflineIface);
const UPowerIface = '<node> \
<interface name="org.freedesktop.UPower"> \
<property name="OnBattery" type="b" access="read"/> \
</interface> \
</node>';
const UPowerProxy = Gio.DBusProxy.makeProxyWrapper(UPowerIface);
function findAppFromInhibitor(inhibitor) {
let desktopFile;
try {
@ -195,6 +233,18 @@ function _setLabelText(label, text) {
}
}
function _setCheckBoxLabel(checkBox, text) {
let label = checkBox.getLabelActor();
if (text) {
label.set_text(text);
checkBox.actor.show();
} else {
label.set_text('');
checkBox.actor.hide();
}
}
function init() {
// This always returns the same singleton object
// By instantiating it initially, we register the
@ -213,7 +263,26 @@ const EndSessionDialog = new Lang.Class({
this._loginManager = LoginManager.getLoginManager();
this._userManager = AccountsService.UserManager.get_default();
this._user = this._userManager.get_user(GLib.get_user_name());
this._updatesFile = Gio.File.new_for_path('/system-update');
this._pkOfflineProxy = new PkOfflineProxy(Gio.DBus.system,
'org.freedesktop.PackageKit',
'/org/freedesktop/PackageKit',
Lang.bind(this, function(proxy, error) {
if (error)
log(error.message);
}));
this._powerProxy = new UPowerProxy(Gio.DBus.system,
'org.freedesktop.UPower',
'/org/freedesktop/UPower',
Lang.bind(this, function(proxy, error) {
if (error) {
log(error.message);
return;
}
this._powerProxy.connect('g-properties-changed',
Lang.bind(this, this._sync));
this._sync();
}));
this._secondsLeft = 0;
this._totalSecondsToStayOpen = 0;
@ -240,7 +309,8 @@ const EndSessionDialog = new Lang.Class({
x_align: St.Align.END,
y_align: St.Align.START });
let messageLayout = new St.BoxLayout({ vertical: true });
let messageLayout = new St.BoxLayout({ vertical: true,
style_class: 'end-session-dialog-layout' });
mainContentLayout.add(messageLayout,
{ y_align: St.Align.START });
@ -260,6 +330,16 @@ const EndSessionDialog = new Lang.Class({
{ y_fill: true,
y_align: St.Align.START });
this._checkBox = new CheckBox.CheckBox();
this._checkBox.actor.connect('clicked', Lang.bind(this, this._sync));
messageLayout.add(this._checkBox.actor);
this._batteryWarning = new St.Label({ style_class: 'end-session-dialog-warning',
text: _("Running on battery power: please plug in before installing updates.") });
this._batteryWarning.clutter_text.ellipsize = Pango.EllipsizeMode.NONE;
this._batteryWarning.clutter_text.line_wrap = true;
messageLayout.add(this._batteryWarning);
this._scrollView = new St.ScrollView({ style_class: 'end-session-dialog-list' });
this._scrollView.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC);
this.contentLayout.add(this._scrollView,
@ -285,6 +365,12 @@ const EndSessionDialog = new Lang.Class({
this._inhibitorSection.add_actor(this._sessionHeader);
this._inhibitorSection.add_actor(this._sessionList);
try {
this._updatesPermission = Polkit.Permission.new_sync("org.freedesktop.packagekit.trigger-offline-update", null, null);
} catch(e) {
log('No permission to trigger offline updates: %s'.format(e.toString()));
}
this._dbusImpl = Gio.DBusExportedObject.wrapJSObject(EndSessionDialogIface, this);
this._dbusImpl.export(Gio.DBus.session, '/org/gnome/SessionManager/EndSessionDialog');
},
@ -299,13 +385,22 @@ const EndSessionDialog = new Lang.Class({
if (!open)
return;
if (this._type == 2 && this._updatesFile.query_exists(null))
this._type = 3;
let dialogContent = DialogContent[this._type];
let subject = dialogContent.subject;
// Use different title when we are installing updates
if (dialogContent.subjectWithUpdates && this._checkBox.actor.checked)
subject = dialogContent.subjectWithUpdates;
if (dialogContent.showBatteryWarning) {
// Warn when running on battery power
if (this._powerProxy.OnBattery && this._checkBox.actor.checked)
this._batteryWarning.opacity = 255;
else
this._batteryWarning.opacity = 0;
}
let description;
let displayTime = _roundSecondsToInterval(this._totalSecondsToStayOpen,
this._secondsLeft,
@ -388,15 +483,73 @@ const EndSessionDialog = new Lang.Class({
},
_confirm: function(signal) {
this._fadeOutDialog();
this._stopTimer();
this._dbusImpl.emit_signal(signal, null);
let callback = Lang.bind(this, function() {
this._fadeOutDialog();
this._stopTimer();
this._dbusImpl.emit_signal(signal, null);
});
// Offline update not available; just emit the signal
if (!this._checkBox.actor.visible) {
callback();
return;
}
// Trigger the offline update as requested
if (this._checkBox.actor.checked) {
switch (signal) {
case "ConfirmedReboot":
this._triggerOfflineUpdateReboot(callback);
break;
case "ConfirmedShutdown":
// To actually trigger the offline update, we need to
// reboot to do the upgrade. When the upgrade is complete,
// the computer will shut down automatically.
signal = "ConfirmedReboot";
this._triggerOfflineUpdateShutdown(callback);
break;
default:
callback();
break;
}
} else {
this._triggerOfflineUpdateCancel(callback);
}
},
_onOpened: function() {
this._sync();
},
_triggerOfflineUpdateReboot: function(callback) {
this._pkOfflineProxy.TriggerRemote('reboot',
function (result, error) {
if (error)
log(error.message);
callback();
});
},
_triggerOfflineUpdateShutdown: function(callback) {
this._pkOfflineProxy.TriggerRemote('power-off',
function (result, error) {
if (error)
log(error.message);
callback();
});
},
_triggerOfflineUpdateCancel: function(callback) {
this._pkOfflineProxy.CancelRemote(function (result, error) {
if (error)
log(error.message);
callback();
});
},
_startTimer: function() {
let startTime = GLib.get_monotonic_time();
this._secondsLeft = this._totalSecondsToStayOpen;
@ -419,6 +572,7 @@ const EndSessionDialog = new Lang.Class({
return GLib.SOURCE_REMOVE;
}));
GLib.Source.set_name_by_id(this._timerId, '[gnome-shell] this._confirm');
},
_stopTimer: function() {
@ -544,6 +698,10 @@ const EndSessionDialog = new Lang.Class({
this._totalSecondsToStayOpen = totalSecondsToStayOpen;
this._type = type;
if (this._type == DialogType.RESTART &&
this._pkOfflineProxy.TriggerAction == 'reboot')
this._type = DialogType.UPDATE_RESTART;
this._applications = [];
this._applicationList.destroy_all_children();
@ -556,6 +714,8 @@ const EndSessionDialog = new Lang.Class({
return;
}
let dialogContent = DialogContent[this._type];
for (let i = 0; i < inhibitorObjectPaths.length; i++) {
let inhibitor = new GnomeSession.Inhibitor(inhibitorObjectPaths[i], Lang.bind(this, function(proxy, error) {
this._onInhibitorLoaded(proxy);
@ -564,9 +724,23 @@ const EndSessionDialog = new Lang.Class({
this._applications.push(inhibitor);
}
if (DialogContent[type].showOtherSessions)
if (dialogContent.showOtherSessions)
this._loadSessions();
let updateAlreadyTriggered = this._pkOfflineProxy.TriggerAction == 'power-off' || this._pkOfflineProxy.TriggerAction == 'reboot';
let updatePrepared = this._pkOfflineProxy.UpdatePrepared;
let updatesAllowed = this._updatesPermission && this._updatesPermission.allowed;
_setCheckBoxLabel(this._checkBox, dialogContent.checkBoxText);
this._checkBox.actor.visible = (dialogContent.checkBoxText && updatePrepared && updatesAllowed);
this._checkBox.actor.checked = (updatePrepared && updateAlreadyTriggered);
// We show the warning either together with the checkbox, or when
// updates have already been triggered, but the user doesn't have
// enough permissions to cancel them.
this._batteryWarning.visible = (dialogContent.showBatteryWarning &&
(this._checkBox.actor.visible || updatePrepared && updateAlreadyTriggered && !updatesAllowed));
this._updateButtons();
if (!this.open(timestamp)) {

View File

@ -5,6 +5,8 @@ imports.gi.versions.Gio = '2.0';
imports.gi.versions.Gdk = '3.0';
imports.gi.versions.GdkPixbuf = '2.0';
imports.gi.versions.Gtk = '3.0';
imports.gi.versions.TelepathyGLib = '0.12';
imports.gi.versions.TelepathyLogger = '0.2';
const Clutter = imports.gi.Clutter;;
const Gettext = imports.gettext;
@ -45,8 +47,11 @@ function _patchLayoutClass(layoutClass, styleProps) {
layoutClass.prototype.hookup_style = function(container) {
container.connect('style-changed', Lang.bind(this, function() {
let node = container.get_theme_node();
for (let prop in styleProps)
this[prop] = node.get_length(styleProps[prop]);
for (let prop in styleProps) {
let [found, length] = node.lookup_length(styleProps[prop], false);
if (found)
this[prop] = length;
}
}));
};
layoutClass.prototype.child_set = function(actor, props) {

View File

@ -38,6 +38,7 @@ const connect = Lang.bind(_signals, _signals.connect);
const disconnect = Lang.bind(_signals, _signals.disconnect);
const ENABLED_EXTENSIONS_KEY = 'enabled-extensions';
const EXTENSION_DISABLE_VERSION_CHECK_KEY = 'disable-extension-version-validation';
var initted = false;
var enabled;
@ -156,7 +157,9 @@ function loadExtension(extension) {
// Default to error, we set success as the last step
extension.state = ExtensionState.ERROR;
if (ExtensionUtils.isOutOfDate(extension)) {
let checkVersion = !global.settings.get_boolean(EXTENSION_DISABLE_VERSION_CHECK_KEY);
if (checkVersion && ExtensionUtils.isOutOfDate(extension)) {
extension.state = ExtensionState.OUT_OF_DATE;
} else {
let enabled = enabledExtensions.indexOf(extension.uuid) != -1;
@ -267,8 +270,26 @@ function onEnabledExtensionsChanged() {
enabledExtensions = newEnabledExtensions;
}
function _onVersionValidationChanged() {
// we want to reload all extensions, but only enable
// extensions when allowed by the sessionMode, so
// temporarily disable them all
enabledExtensions = [];
for (let uuid in ExtensionUtils.extensions)
reloadExtension(ExtensionUtils.extensions[uuid]);
enabledExtensions = getEnabledExtensions();
if (Main.sessionMode.allowExtensions) {
enabledExtensions.forEach(function(uuid) {
enableExtension(uuid);
});
}
}
function _loadExtensions() {
global.settings.connect('changed::' + ENABLED_EXTENSIONS_KEY, onEnabledExtensionsChanged);
global.settings.connect('changed::' + EXTENSION_DISABLE_VERSION_CHECK_KEY, _onVersionValidationChanged);
enabledExtensions = getEnabledExtensions();
let finder = new ExtensionUtils.ExtensionFinder();

View File

@ -32,9 +32,11 @@ const FocusCaretTracker = new Lang.Class({
Name: 'FocusCaretTracker',
_init: function() {
Atspi.init();
Atspi.set_timeout(250, 250);
this._atspiListener = Atspi.EventListener.new(Lang.bind(this, this._onChanged));
this._atspiInited = false;
this._focusListenerRegistered = false;
this._caretListenerRegistered = false;
},
_onChanged: function(event) {
@ -44,22 +46,50 @@ const FocusCaretTracker = new Lang.Class({
this.emit('caret-moved', event);
},
_initAtspi: function() {
if (!this._atspiInited) {
Atspi.init();
Atspi.set_timeout(250, 250);
this._atspiInited = true;
}
},
registerFocusListener: function() {
return this._atspiListener.register(STATECHANGED + ':focused') &&
this._atspiListener.register(STATECHANGED + ':selected');
if (this._focusListenerRegistered)
return;
this._initAtspi();
this._atspiListener.register(STATECHANGED + ':focused');
this._atspiListener.register(STATECHANGED + ':selected');
this._focusListenerRegistered = true;
},
registerCaretListener: function() {
return this._atspiListener.register(CARETMOVED);
if (this._caretListenerRegistered)
return;
this._initAtspi();
this._atspiListener.register(CARETMOVED);
this._caretListenerRegistered = true;
},
deregisterFocusListener: function() {
return this._atspiListener.deregister(STATECHANGED + ':focused') &&
this._atspiListener.deregister(STATECHANGED + ':selected');
if (!this._focusListenerRegistered)
return;
this._atspiListener.deregister(STATECHANGED + ':focused');
this._atspiListener.deregister(STATECHANGED + ':selected');
this._focusListenerRegistered = false;
},
deregisterCaretListener: function() {
return this._atspiListener.deregister(CARETMOVED);
if (!this._caretListenerRegistered)
return;
this._atspiListener.deregister(CARETMOVED);
this._caretListenerRegistered = false;
}
});
Signals.addSignalMethods(FocusCaretTracker.prototype);

View File

@ -56,7 +56,7 @@ const GrabHelper = new Lang.Class({
this._grabStack = [];
this._actors = [];
this._ignoreRelease = false;
this._ignoreUntilRelease = false;
this._modalCount = 0;
},
@ -215,7 +215,7 @@ const GrabHelper = new Lang.Class({
_popGrabHelper(this);
this._ignoreRelease = false;
this._ignoreUntilRelease = false;
Main.popModal(this._owner);
global.sync_pointer();
@ -228,7 +228,7 @@ const GrabHelper = new Lang.Class({
// like the ComboBoxMenu that go away on press, but need to eat
// the next release event.
ignoreRelease: function() {
this._ignoreRelease = true;
this._ignoreUntilRelease = true;
},
// ungrab:
@ -283,12 +283,22 @@ const GrabHelper = new Lang.Class({
return Clutter.EVENT_STOP;
}
let motion = type == Clutter.EventType.MOTION;
let press = type == Clutter.EventType.BUTTON_PRESS;
let release = type == Clutter.EventType.BUTTON_RELEASE;
let button = press || release;
if (release && this._ignoreRelease) {
this._ignoreRelease = false;
let touchUpdate = type == Clutter.EventType.TOUCH_UPDATE;
let touchBegin = type == Clutter.EventType.TOUCH_BEGIN;
let touchEnd = type == Clutter.EventType.TOUCH_END;
let touch = touchUpdate || touchBegin || touchEnd;
if (touch && !global.display.is_pointer_emulating_sequence (event.get_event_sequence()))
return Clutter.EVENT_PROPAGATE;
if (this._ignoreUntilRelease && (motion || release || touch)) {
if (release || touchEnd)
this._ignoreUntilRelease = false;
return Clutter.EVENT_STOP;
}
@ -298,11 +308,12 @@ const GrabHelper = new Lang.Class({
if (Main.keyboard.shouldTakeEvent(event))
return Clutter.EVENT_PROPAGATE;
if (button) {
// If we have a press event, ignore the next event,
// which should be a release event.
if (press)
this._ignoreRelease = true;
if (button || touchBegin) {
// If we have a press event, ignore the next
// motion/release events.
if (press || touchBegin)
this._ignoreUntilRelease = true;
let i = this._actorInGrabStack(event.get_source()) + 1;
this.ungrab({ actor: this._grabStack[i].actor, isUser: true });
return Clutter.EVENT_STOP;

View File

@ -11,6 +11,9 @@ const Main = imports.ui.main;
const MAX_CANDIDATES_PER_PAGE = 16;
const DEFAULT_INDEX_LABELS = [ '1', '2', '3', '4', '5', '6', '7', '8',
'9', '0', 'a', 'b', 'c', 'd', 'e', 'f' ];
const CandidateArea = new Lang.Class({
Name: 'CandidateArea',
@ -89,7 +92,7 @@ const CandidateArea = new Lang.Class({
if (!visible)
continue;
box._indexLabel.text = ((indexes && indexes[i]) ? indexes[i] : '%x'.format(i + 1));
box._indexLabel.text = ((indexes && indexes[i]) ? indexes[i] : DEFAULT_INDEX_LABELS[i]);
box._candidateLabel.text = candidates[i];
}
@ -155,7 +158,7 @@ const CandidatePopup = new Lang.Class({
panelService.connect('set-cursor-location',
Lang.bind(this, function(ps, x, y, w, h) {
Main.layoutManager.setDummyCursorPosition(x, y);
Main.layoutManager.setDummyCursorGeometry(x, y, w, h);
if (this._boxPointer.actor.visible)
this._boxPointer.setPosition(Main.layoutManager.dummyCursor, 0);
}));

View File

@ -10,12 +10,29 @@ const St = imports.gi.St;
const Lang = imports.lang;
const Params = imports.misc.params;
const Tweener = imports.ui.tweener;
const Main = imports.ui.main;
const ICON_SIZE = 96;
const MIN_ICON_SIZE = 16;
const EXTRA_SPACE_ANIMATION_TIME = 0.25;
const ANIMATION_TIME_IN = 0.350;
const ANIMATION_TIME_OUT = 1/2 * ANIMATION_TIME_IN;
const ANIMATION_MAX_DELAY_FOR_ITEM = 2/3 * ANIMATION_TIME_IN;
const ANIMATION_MAX_DELAY_OUT_FOR_ITEM = 2/3 * ANIMATION_TIME_OUT;
const ANIMATION_FADE_IN_TIME_FOR_ITEM = 1/4 * ANIMATION_TIME_IN;
const ANIMATION_BOUNCE_ICON_SCALE = 1.1;
const AnimationDirection = {
IN: 0,
OUT: 1
};
const APPICON_ANIMATION_OUT_SCALE = 3;
const APPICON_ANIMATION_OUT_TIME = 0.25;
const BaseIcon = new Lang.Class({
Name: 'BaseIcon',
@ -143,11 +160,6 @@ const BaseIcon = new Lang.Class({
this.icon = this.createIcon(this.iconSize);
this._iconBin.child = this.icon;
// The icon returned by createIcon() might actually be smaller than
// the requested icon size (for instance StTextureCache does this
// for fallback icons), so set the size explicitly.
this._iconBin.set_size(this.iconSize, this.iconSize);
},
_onStyleChanged: function() {
@ -178,9 +190,55 @@ const BaseIcon = new Lang.Class({
_onIconThemeChanged: function() {
this._createIconTexture(this.iconSize);
},
animateZoomOut: function() {
// Animate only the child instead of the entire actor, so the
// styles like hover and running are not applied while
// animating.
zoomOutActor(this.actor.child);
}
});
function clamp(value, min, max) {
return Math.max(Math.min(value, max), min);
};
function zoomOutActor(actor) {
let actorClone = new Clutter.Clone({ source: actor,
reactive: false });
let [width, height] = actor.get_transformed_size();
let [x, y] = actor.get_transformed_position();
actorClone.set_size(width, height);
actorClone.set_position(x, y);
actorClone.opacity = 255;
actorClone.set_pivot_point(0.5, 0.5);
Main.uiGroup.add_actor(actorClone);
// Avoid monitor edges to not zoom outside the current monitor
let monitor = Main.layoutManager.findMonitorForActor(actor);
let scaledWidth = width * APPICON_ANIMATION_OUT_SCALE;
let scaledHeight = height * APPICON_ANIMATION_OUT_SCALE;
let scaledX = x - (scaledWidth - width) / 2;
let scaledY = y - (scaledHeight - height) / 2;
let containedX = clamp(scaledX, monitor.x, monitor.x + monitor.width - scaledWidth);
let containedY = clamp(scaledY, monitor.y, monitor.y + monitor.height - scaledHeight);
Tweener.addTween(actorClone,
{ time: APPICON_ANIMATION_OUT_TIME,
scale_x: APPICON_ANIMATION_OUT_SCALE,
scale_y: APPICON_ANIMATION_OUT_SCALE,
translation_x: containedX - scaledX,
translation_y: containedY - scaledY,
opacity: 0,
transition: 'easeOutQuad',
onComplete: function() {
actorClone.destroy();
}
});
}
const IconGrid = new Lang.Class({
Name: 'IconGrid',
@ -219,6 +277,20 @@ const IconGrid = new Lang.Class({
this._grid.connect('get-preferred-width', Lang.bind(this, this._getPreferredWidth));
this._grid.connect('get-preferred-height', Lang.bind(this, this._getPreferredHeight));
this._grid.connect('allocate', Lang.bind(this, this._allocate));
this._grid.connect('actor-added', Lang.bind(this, this._childAdded));
this._grid.connect('actor-removed', Lang.bind(this, this._childRemoved));
},
_keyFocusIn: function(actor) {
this.emit('key-focus-in', actor);
},
_childAdded: function(grid, child) {
child._iconGridKeyFocusInId = child.connect('key-focus-in', Lang.bind(this, this._keyFocusIn));
},
_childRemoved: function(grid, child) {
child.disconnect(child._iconGridKeyFocusInId);
},
_getPreferredWidth: function (grid, forHeight, alloc) {
@ -329,15 +401,208 @@ const IconGrid = new Lang.Class({
}
},
_calculateChildBox: function(child, x, y, box) {
let [childMinWidth, childMinHeight, childNaturalWidth, childNaturalHeight] =
child.get_preferred_size();
/**
* Intended to be override by subclasses if they need a different
* set of items to be animated.
*/
_getChildrenToAnimate: function() {
return this._getVisibleChildren();
},
_animationDone: function() {
this._animating = false;
this.emit('animation-done');
},
animatePulse: function(animationDirection) {
if (animationDirection != AnimationDirection.IN)
throw new Error("Pulse animation only implements 'in' animation direction");
if (this._animating)
return;
this._animating = true;
let actors = this._getChildrenToAnimate();
if (actors.length == 0) {
this._animationDone();
return;
}
for (let index = 0; index < actors.length; index++) {
let actor = actors[index];
actor.opacity = 0;
actor.reactive = false;
let delay = index / actors.length * ANIMATION_MAX_DELAY_FOR_ITEM;
let [originalX, originalY] = actor.get_transformed_position();
let [originalWidth, originalHeight,,] = this._getAllocatedChildSizeAndSpacing(actor);
let actorClone = new Clutter.Clone({ source: actor });
Main.uiGroup.add_actor(actorClone);
actorClone.set_position(originalX, originalY);
actorClone.set_scale(0, 0);
actorClone.set_pivot_point(0.5, 0.5);
actorClone.set_size(originalWidth, originalHeight);
let bounceUpTime = ANIMATION_TIME_IN / 4;
let isLastItem = index == actors.length - 1;
Tweener.addTween(actorClone,
{ time: bounceUpTime,
transition: 'easeInOutQuad',
delay: delay,
scale_x: ANIMATION_BOUNCE_ICON_SCALE,
scale_y: ANIMATION_BOUNCE_ICON_SCALE,
onComplete: Lang.bind(this, function() {
Tweener.addTween(actorClone,
{ time: ANIMATION_TIME_IN - bounceUpTime,
transition: 'easeInOutQuad',
scale_x: 1,
scale_y: 1,
onComplete: Lang.bind(this, function() {
if (isLastItem)
this._animationDone();
actor.opacity = 255;
actor.reactive = true;
actorClone.destroy();
})
});
})
});
}
},
animateSpring: function(animationDirection, sourceActor) {
if (this._animating)
return;
this._animating = true;
let actors = this._getChildrenToAnimate();
if (actors.length == 0) {
this._animationDone();
return;
}
let [sourceX, sourceY] = sourceActor.get_transformed_position();
let [sourceWidth, sourceHeight] = sourceActor.get_size();
// Get the center
let [sourceCenterX, sourceCenterY] = [sourceX + sourceWidth / 2, sourceY + sourceHeight / 2];
// Design decision, 1/2 of the source actor size.
let [sourceScaledWidth, sourceScaledHeight] = [sourceWidth / 2, sourceHeight / 2];
actors.forEach(function(actor) {
let [actorX, actorY] = actor._transformedPosition = actor.get_transformed_position();
let [x, y] = [actorX - sourceX, actorY - sourceY];
actor._distance = Math.sqrt(x * x + y * y);
});
let maxDist = actors.reduce(function(prev, cur) {
return Math.max(prev, cur._distance);
}, 0);
let minDist = actors.reduce(function(prev, cur) {
return Math.min(prev, cur._distance);
}, Infinity);
let normalization = maxDist - minDist;
for (let index = 0; index < actors.length; index++) {
let actor = actors[index];
actor.opacity = 0;
actor.reactive = false;
let actorClone = new Clutter.Clone({ source: actor });
Main.uiGroup.add_actor(actorClone);
let [width, height,,] = this._getAllocatedChildSizeAndSpacing(actor);
actorClone.set_size(width, height);
let scaleX = sourceScaledWidth / width;
let scaleY = sourceScaledHeight / height;
let [adjustedSourcePositionX, adjustedSourcePositionY] = [sourceCenterX - sourceScaledWidth / 2, sourceCenterY - sourceScaledHeight / 2];
let movementParams, fadeParams;
if (animationDirection == AnimationDirection.IN) {
let isLastItem = actor._distance == minDist;
actorClone.opacity = 0;
actorClone.set_scale(scaleX, scaleY);
actorClone.set_position(adjustedSourcePositionX, adjustedSourcePositionY);
let delay = (1 - (actor._distance - minDist) / normalization) * ANIMATION_MAX_DELAY_FOR_ITEM;
let [finalX, finalY] = actor._transformedPosition;
movementParams = { time: ANIMATION_TIME_IN,
transition: 'easeInOutQuad',
delay: delay,
x: finalX,
y: finalY,
scale_x: 1,
scale_y: 1,
onComplete: Lang.bind(this, function() {
if (isLastItem)
this._animationDone();
actor.opacity = 255;
actor.reactive = true;
actorClone.destroy();
})};
fadeParams = { time: ANIMATION_FADE_IN_TIME_FOR_ITEM,
transition: 'easeInOutQuad',
delay: delay,
opacity: 255 };
} else {
let isLastItem = actor._distance == maxDist;
let [startX, startY] = actor._transformedPosition;
actorClone.set_position(startX, startY);
let delay = (actor._distance - minDist) / normalization * ANIMATION_MAX_DELAY_OUT_FOR_ITEM;
movementParams = { time: ANIMATION_TIME_OUT,
transition: 'easeInOutQuad',
delay: delay,
x: adjustedSourcePositionX,
y: adjustedSourcePositionY,
scale_x: scaleX,
scale_y: scaleY,
onComplete: Lang.bind(this, function() {
if (isLastItem) {
this._animationDone();
this._restoreItemsOpacity();
}
actor.reactive = true;
actorClone.destroy();
})};
fadeParams = { time: ANIMATION_FADE_IN_TIME_FOR_ITEM,
transition: 'easeInOutQuad',
delay: ANIMATION_TIME_OUT + delay - ANIMATION_FADE_IN_TIME_FOR_ITEM,
opacity: 0 };
}
Tweener.addTween(actorClone, movementParams);
Tweener.addTween(actorClone, fadeParams);
}
},
_restoreItemsOpacity: function() {
for (let index = 0; index < this._items.length; index++) {
this._items[index].actor.opacity = 255;
}
},
_getAllocatedChildSizeAndSpacing: function(child) {
let [,, natWidth, natHeight] = child.get_preferred_size();
let width = Math.min(this._getHItemSize(), natWidth);
let xSpacing = Math.max(0, width - natWidth) / 2;
let height = Math.min(this._getVItemSize(), natHeight);
let ySpacing = Math.max(0, height - natHeight) / 2;
return [width, height, xSpacing, ySpacing];
},
_calculateChildBox: function(child, x, y, box) {
/* Center the item in its allocation horizontally */
let width = Math.min(this._getHItemSize(), childNaturalWidth);
let childXSpacing = Math.max(0, width - childNaturalWidth) / 2;
let height = Math.min(this._getVItemSize(), childNaturalHeight);
let childYSpacing = Math.max(0, height - childNaturalHeight) / 2;
let [width, height, childXSpacing, childYSpacing] =
this._getAllocatedChildSizeAndSpacing(child);
let childBox = new Clutter.ActorBox();
if (Clutter.get_default_text_direction() == Clutter.TextDirection.RTL) {
@ -513,25 +778,22 @@ const IconGrid = new Lang.Class({
this._fixedHItemSize = Math.max(this._hItemSize - neededSpacePerItem, MIN_ICON_SIZE);
this._fixedVItemSize = Math.max(this._vItemSize - neededSpacePerItem, MIN_ICON_SIZE);
if (this._fixedHItemSize < MIN_ICON_SIZE)
this._fixedHItemSize = MIN_ICON_SIZE;
if (this._fixedVItemSize < MIN_ICON_SIZE)
this._fixedVItemSize = MIN_ICON_SIZE;
this._updateSpacingForSize(availWidth, availHeight);
}
let scale = Math.min(this._fixedHItemSize, this._fixedVItemSize) / Math.max(this._hItemSize, this._vItemSize);
Meta.later_add(Meta.LaterType.BEFORE_REDRAW, Lang.bind(this, function() { this._updateChildrenScale(scale); }));
Meta.later_add(Meta.LaterType.BEFORE_REDRAW,
Lang.bind(this, this._updateIconSizes));
},
// Note that this is ICON_SIZE as used by BaseIcon, not elsewhere in IconGrid; it's a bit messed up
_updateChildrenScale: function(scale) {
_updateIconSizes: function() {
let scale = Math.min(this._fixedHItemSize, this._fixedVItemSize) / Math.max(this._hItemSize, this._vItemSize);
let newIconSize = Math.floor(ICON_SIZE * scale);
for (let i in this._items) {
let newIconSize = Math.floor(ICON_SIZE * scale);
this._items[i].icon.setIconSize(newIconSize);
}
}
});
Signals.addSignalMethods(IconGrid.prototype);
const PaginatedIconGrid = new Lang.Class({
Name: 'PaginatedIconGrid',
@ -540,6 +802,7 @@ const PaginatedIconGrid = new Lang.Class({
_init: function(params) {
this.parent(params);
this._nPages = 0;
this.currentPage = 0;
this._rowsPerPage = 0;
this._spaceBetweenPages = 0;
this._childrenPerPage = 0;
@ -603,6 +866,15 @@ const PaginatedIconGrid = new Lang.Class({
}
},
// Overriden from IconGrid
_getChildrenToAnimate: function() {
let children = this._getVisibleChildren();
let firstIndex = this._childrenPerPage * this.currentPage;
let lastIndex = firstIndex + this._childrenPerPage;
return children.slice(firstIndex, lastIndex);
},
_computePages: function (availWidthPerPage, availHeightPerPage) {
let [nColumns, usedWidth] = this._computeLayout(availWidthPerPage);
let nRows;
@ -635,6 +907,10 @@ const PaginatedIconGrid = new Lang.Class({
return this._nPages;
},
getPageHeight: function() {
return this._availableHeightPerPageForItems();
},
getPageY: function(pageNumber) {
if (!this._nPages)
return 0;

View File

@ -23,6 +23,12 @@ const KEYBOARD_TYPE = 'keyboard-type';
const A11Y_APPLICATIONS_SCHEMA = 'org.gnome.desktop.a11y.applications';
const SHOW_KEYBOARD = 'screen-keyboard-enabled';
const CURSOR_BUS_NAME = 'org.gnome.SettingsDaemon.Cursor';
const CURSOR_OBJECT_PATH = '/org/gnome/SettingsDaemon/Cursor';
const CARIBOU_BUS_NAME = 'org.gnome.Caribou.Daemon';
const CARIBOU_OBJECT_PATH = '/org/gnome/Caribou/Daemon';
const CaribouKeyboardIface = '<node> \
<interface name="org.gnome.Caribou.Keyboard"> \
<method name="Show"> \
@ -47,13 +53,28 @@ const CaribouKeyboardIface = '<node> \
</interface> \
</node>';
const CaribouDaemonIface = '<node> \
<interface name="org.gnome.Caribou.Daemon"> \
<method name="Run" /> \
<method name="Quit" /> \
</interface> \
</node>';
const CursorManagerIface = '<node> \
<interface name="org.gnome.SettingsDaemon.Cursor"> \
<property name="ShowOSK" type="b" access="read" /> \
</interface> \
</node>';
const CaribouDaemonProxy = Gio.DBusProxy.makeProxyWrapper(CaribouDaemonIface);
const CursorManagerProxy = Gio.DBusProxy.makeProxyWrapper(CursorManagerIface);
const Key = new Lang.Class({
Name: 'Key',
_init : function(key) {
this._key = key;
this.actor = this._makeKey();
this.actor = this._makeKey(key, GLib.markup_escape_text(key.label, -1));
this._extended_keys = this._key.get_extended_keys();
this._extended_keyboard = null;
@ -76,20 +97,19 @@ const Key = new Lang.Class({
}
},
_makeKey: function () {
let label = GLib.markup_escape_text(this._key.label, -1);
_makeKey: function (key, label) {
let button = new St.Button ({ label: label,
style_class: 'keyboard-key' });
button.key_width = this._key.width;
button.connect('button-press-event', Lang.bind(this,
function () {
this._key.press();
key.press();
return Clutter.EVENT_PROPAGATE;
}));
button.connect('button-release-event', Lang.bind(this,
function () {
this._key.release();
key.release();
return Clutter.EVENT_PROPAGATE;
}));
@ -112,18 +132,9 @@ const Key = new Lang.Class({
for (let i = 0; i < this._extended_keys.length; ++i) {
let extended_key = this._extended_keys[i];
let label = this._getUnichar(extended_key);
let key = new St.Button({ label: label, style_class: 'keyboard-key' });
let key = this._makeKey(extended_key, label);
key.extended_key = extended_key;
key.connect('button-press-event', Lang.bind(this,
function () {
extended_key.press();
return Clutter.EVENT_PROPAGATE;
}));
key.connect('button-release-event', Lang.bind(this,
function () {
extended_key.release();
return Clutter.EVENT_PROPAGATE;
}));
this._extended_keyboard.add(key);
}
this._boxPointer.bin.add_actor(this._extended_keyboard);
@ -161,11 +172,33 @@ const Keyboard = new Lang.Class({
this._timestamp = global.display.get_current_time_roundtrip();
this._keyboardSettings = new Gio.Settings({ schema: KEYBOARD_SCHEMA });
this._keyboardSettings.connect('changed', Lang.bind(this, this._settingsChanged));
this._a11yApplicationsSettings = new Gio.Settings({ schema: A11Y_APPLICATIONS_SCHEMA });
this._a11yApplicationsSettings.connect('changed', Lang.bind(this, this._settingsChanged));
this._settingsChanged();
this._keyboardSettings = new Gio.Settings({ schema_id: KEYBOARD_SCHEMA });
this._keyboardSettings.connect('changed', Lang.bind(this, this._sync));
this._a11yApplicationsSettings = new Gio.Settings({ schema_id: A11Y_APPLICATIONS_SCHEMA });
this._a11yApplicationsSettings.connect('changed', Lang.bind(this, this._sync));
this._watchNameId = Gio.bus_watch_name(Gio.BusType.SESSION, CURSOR_BUS_NAME, 0,
Lang.bind(this, this._sync),
Lang.bind(this, this._sync));
this._daemonProxy = new CaribouDaemonProxy(Gio.DBus.session, CARIBOU_BUS_NAME,
CARIBOU_OBJECT_PATH,
Lang.bind(this, function(proxy, error) {
if (error) {
log(error.message);
return;
}
}));
this._cursorProxy = new CursorManagerProxy(Gio.DBus.session, CURSOR_BUS_NAME,
CURSOR_OBJECT_PATH,
Lang.bind(this, function(proxy, error) {
if (error) {
log(error.message);
return;
}
this._cursorProxy.connect('g-properties-changed',
Lang.bind(this, this._sync));
this._sync();
}));
this._sync();
this._showIdleId = 0;
this._subkeysBoxPointer = null;
@ -183,8 +216,9 @@ const Keyboard = new Lang.Class({
this._redraw();
},
_settingsChanged: function (settings, key) {
this._enableKeyboard = this._a11yApplicationsSettings.get_boolean(SHOW_KEYBOARD);
_sync: function () {
this._enableKeyboard = this._a11yApplicationsSettings.get_boolean(SHOW_KEYBOARD) ||
this._cursorProxy.ShowOSK;
if (!this._enableKeyboard && !this._keyboard)
return;
if (this._enableKeyboard && this._keyboard &&
@ -214,9 +248,22 @@ const Keyboard = new Lang.Class({
this.actor = null;
this._destroySource();
this._daemonProxy.QuitRemote(function (result, error) {
if (error) {
log(error.message);
return;
}
});
},
_setupKeyboard: function() {
this._daemonProxy.RunRemote(function (result, error) {
if (error) {
log(error.message);
return;
}
});
this.actor = new St.BoxLayout({ name: 'keyboard', vertical: true, reactive: true });
Main.layoutManager.keyboardBox.add_actor(this.actor);
Main.layoutManager.trackChrome(this.actor);
@ -266,12 +313,14 @@ const Keyboard = new Lang.Class({
return;
}
if (!this._showIdleId)
this._showIdleId = GLib.idle_add(GLib.PRIORITY_DEFAULT_IDLE,
Lang.bind(this, function() {
this.Show(time);
return GLib.SOURCE_REMOVE;
}));
if (!this._showIdleId) {
this._showIdleId = GLib.idle_add(GLib.PRIORITY_DEFAULT_IDLE,
Lang.bind(this, function() {
this.Show(time);
return GLib.SOURCE_REMOVE;
}));
GLib.Source.set_name_by_id(this._showIdleId, '[gnome-shell] this.Show');
}
},
_createLayersForGroup: function (gname) {
@ -500,6 +549,7 @@ const Keyboard = new Lang.Class({
this._show(monitor);
return GLib.SOURCE_REMOVE;
}));
GLib.Source.set_name_by_id(this._keyboardRestingId, '[gnome-shell] this._clearKeyboardRestTimer');
},
_show: function(monitor) {
@ -526,6 +576,7 @@ const Keyboard = new Lang.Class({
this._hide();
return GLib.SOURCE_REMOVE;
}));
GLib.Source.set_name_by_id(this._keyboardRestingId, '[gnome-shell] this._clearKeyboardRestTimer');
},
_hide: function() {

View File

@ -4,7 +4,6 @@ const Clutter = imports.gi.Clutter;
const GLib = imports.gi.GLib;
const GObject = imports.gi.GObject;
const Lang = imports.lang;
const Mainloop = imports.mainloop;
const Meta = imports.gi.Meta;
const Shell = imports.gi.Shell;
const Signals = imports.signals;
@ -164,7 +163,7 @@ const LayoutManager = new Lang.Class({
// Normally, the stage is always covered so Clutter doesn't need to clear
// it; however it becomes visible during the startup animation
// See the comment below for a longer explanation
global.stage.color = DEFAULT_BACKGROUND_COLOR;
global.stage.background_color = DEFAULT_BACKGROUND_COLOR;
// Set up stage hierarchy to group all UI actors under one container.
this.uiGroup = new Shell.GenericContainer({ name: 'uiGroup' });
@ -213,6 +212,10 @@ const LayoutManager = new Lang.Class({
this.addChrome(this.trayBox);
this._setupTrayPressure();
this.modalDialogGroup = new St.Widget({ name: 'modalDialogGroup',
layout_manager: new Clutter.BinLayout() });
this.uiGroup.add_actor(this.modalDialogGroup);
this.keyboardBox = new St.BoxLayout({ name: 'keyboardBox',
reactive: true,
track_hover: true });
@ -220,8 +223,8 @@ const LayoutManager = new Lang.Class({
this._keyboardHeightNotifyId = 0;
// A dummy actor that tracks the mouse or text cursor, based on the
// position set in setDummyCursorPosition.
this.dummyCursor = new St.Widget({ width: 0, height: 0 });
// position and size set in setDummyCursorGeometry.
this.dummyCursor = new St.Widget({ width: 0, height: 0, visible: false });
this.uiGroup.add_actor(this.dummyCursor);
global.stage.remove_actor(global.top_window_group);
@ -358,7 +361,7 @@ const LayoutManager = new Lang.Class({
},
_addBackgroundMenu: function(bgManager) {
BackgroundMenu.addBackgroundMenu(bgManager.background.actor, this);
BackgroundMenu.addBackgroundMenu(bgManager.backgroundActor, this);
},
_createBackgroundManager: function(monitorIndex) {
@ -375,10 +378,10 @@ const LayoutManager = new Lang.Class({
_showSecondaryBackgrounds: function() {
for (let i = 0; i < this.monitors.length; i++) {
if (i != this.primaryIndex) {
let background = this._bgManagers[i].background;
background.actor.show();
background.actor.opacity = 0;
Tweener.addTween(background.actor,
let backgroundActor = this._bgManagers[i].backgroundActor;
backgroundActor.show();
backgroundActor.opacity = 0;
Tweener.addTween(backgroundActor,
{ opacity: 255,
time: BACKGROUND_FADE_ANIMATION_TIME,
transition: 'easeOutQuad' });
@ -401,10 +404,16 @@ const LayoutManager = new Lang.Class({
this._bgManagers.push(bgManager);
if (i != this.primaryIndex && this._startingUp)
bgManager.background.actor.hide();
bgManager.backgroundActor.hide();
}
},
_updateKeyboardBox: function() {
this.keyboardBox.set_position(this.keyboardMonitor.x,
this.keyboardMonitor.y + this.keyboardMonitor.height);
this.keyboardBox.set_size(this.keyboardMonitor.width, -1);
},
_updateBoxes: function() {
this.screenShieldGroup.set_position(0, 0);
this.screenShieldGroup.set_size(global.screen_width, global.screen_height);
@ -414,6 +423,8 @@ const LayoutManager = new Lang.Class({
if (this.keyboardIndex < 0)
this.keyboardIndex = this.primaryIndex;
else
this._updateKeyboardBox();
this.trayBox.set_position(this.bottomMonitor.x,
this.bottomMonitor.y + this.bottomMonitor.height);
@ -538,9 +549,7 @@ const LayoutManager = new Lang.Class({
set keyboardIndex(v) {
this._keyboardIndex = v;
this.keyboardBox.set_position(this.keyboardMonitor.x,
this.keyboardMonitor.y + this.keyboardMonitor.height);
this.keyboardBox.set_size(this.keyboardMonitor.width, -1);
this._updateKeyboardBox();
},
get keyboardIndex() {
@ -594,13 +603,15 @@ const LayoutManager = new Lang.Class({
reactive: true });
this.addChrome(this._coverPane);
if (Main.sessionMode.isGreeter) {
if (Meta.is_restart()) {
// On restart, we don't do an animation
} else if (Main.sessionMode.isGreeter) {
this.panelBox.translation_y = -this.panelBox.height;
} else {
this._updateBackgrounds();
// We need to force an update of the regions now before we scale
// the UI group to get the coorect allocation for the struts.
// the UI group to get the correct allocation for the struts.
this._updateRegions();
this.trayBox.hide();
@ -625,14 +636,17 @@ const LayoutManager = new Lang.Class({
// until the event loop is uncontended and idle.
// This helps to prevent us from running the animation
// when the system is bogged down
GLib.idle_add(GLib.PRIORITY_LOW, Lang.bind(this, function() {
let id = GLib.idle_add(GLib.PRIORITY_LOW, Lang.bind(this, function() {
this._startupAnimation();
return GLib.SOURCE_REMOVE;
}));
GLib.Source.set_name_by_id(id, '[gnome-shell] this._startupAnimation');
},
_startupAnimation: function() {
if (Main.sessionMode.isGreeter)
if (Meta.is_restart())
this._startupAnimationComplete();
else if (Main.sessionMode.isGreeter)
this._startupAnimationGreeter();
else
this._startupAnimationSession();
@ -725,7 +739,7 @@ const LayoutManager = new Lang.Class({
this._updateRegions();
},
// setDummyCursorPosition:
// setDummyCursorGeometry:
//
// The cursor dummy is a standard widget commonly used for popup
// menus and box pointers to track, as the box pointer API only
@ -734,9 +748,10 @@ const LayoutManager = new Lang.Class({
// is what you should use. Given that the menu should not track
// the actual mouse pointer as it moves, you need to call this
// function before you show the menu to ensure it is at the right
// position.
setDummyCursorPosition: function(x, y) {
// position and has the right size.
setDummyCursorGeometry: function(x, y, w, h) {
this.dummyCursor.set_position(Math.round(x), Math.round(y));
this.dummyCursor.set_size(Math.round(w), Math.round(h));
},
// addChrome:
@ -834,6 +849,8 @@ const LayoutManager = new Lang.Class({
Lang.bind(this, this._queueUpdateRegions));
actorData.allocationId = actor.connect('notify::allocation',
Lang.bind(this, this._queueUpdateRegions));
actorData.destroyId = actor.connect('destroy',
Lang.bind(this, this._untrackActor));
// Note that destroying actor will unset its parent, so we don't
// need to connect to 'destroy' too.
@ -851,7 +868,7 @@ const LayoutManager = new Lang.Class({
this._trackedActors.splice(i, 1);
actor.disconnect(actorData.visibleId);
actor.disconnect(actorData.allocationId);
actor.disconnect(actorData.parentSetId);
actor.disconnect(actorData.destroyId);
this._queueUpdateRegions();
},
@ -905,8 +922,8 @@ const LayoutManager = new Lang.Class({
return;
if (!this._updateRegionIdle)
this._updateRegionIdle = Mainloop.idle_add(Lang.bind(this, this._updateRegions),
Meta.PRIORITY_BEFORE_REDRAW);
this._updateRegionIdle = Meta.later_add(Meta.LaterType.BEFORE_REDRAW,
Lang.bind(this, this._updateRegions));
},
_getWindowActorsForWorkspace: function(workspace) {
@ -937,7 +954,7 @@ const LayoutManager = new Lang.Class({
let rects = [], struts = [], i;
if (this._updateRegionIdle) {
Mainloop.source_remove(this._updateRegionIdle);
Meta.later_remove(this._updateRegionIdle);
delete this._updateRegionIdle;
}
@ -1010,23 +1027,6 @@ const LayoutManager = new Lang.Class({
else
continue;
// Ensure that the strut rects goes all the way to the screen edge,
// as this really what mutter expects.
switch (side) {
case Meta.Side.TOP:
y1 = 0;
break;
case Meta.Side.BOTTOM:
y2 = global.screen_height;
break;
case Meta.Side.LEFT:
x1 = 0;
break;
case Meta.Side.RIGHT:
x2 = global.screen_width;
break;
}
let strutRect = new Meta.Rectangle({ x: x1, y: y1, width: x2 - x1, height: y2 - y1});
let strut = new Meta.Strut({ rect: strutRect, side: side });
struts.push(strut);

View File

@ -11,30 +11,60 @@ const Params = imports.misc.params;
const Tweener = imports.ui.tweener;
const DEFAULT_FADE_FACTOR = 0.4;
const VIGNETTE_BRIGHTNESS = 0.8;
const VIGNETTE_SHARPNESS = 0.7;
const GLSL_DIM_EFFECT_DECLARATIONS = '\
float compute_dim_factor (const vec2 coords) {\
vec2 dist = coords - vec2(0.5, 0.5); \
float elipse_radius = 0.5; \
/* interpolate darkening value, based on distance from screen center */ \
float val = min(length(dist), elipse_radius); \
return mix(0.3, 1.0, val / elipse_radius) * 0.4; \
}';
const GLSL_DIM_EFFECT_CODE = '\
float a = compute_dim_factor (cogl_tex_coord0_in.xy);\
cogl_color_out = vec4(0, 0, 0, cogl_color_in.a * a);'
;
const VIGNETTE_DECLARATIONS = '\
uniform float brightness;\n\
uniform float vignette_sharpness;\n';
const VIGNETTE_CODE = '\
cogl_color_out.a = cogl_color_in.a;\n\
cogl_color_out.rgb = vec3(0.0, 0.0, 0.0);\n\
vec2 position = cogl_tex_coord_in[0].xy - 0.5;\n\
float t = length(2.0 * position);\n\
t = clamp(t, 0.0, 1.0);\n\
float pixel_brightness = mix(1.0, 1.0 - vignette_sharpness, t);\n\
cogl_color_out.a = cogl_color_out.a * (1 - pixel_brightness * brightness);';
const RadialShaderQuad = new Lang.Class({
Name: 'RadialShaderQuad',
Extends: Shell.GLSLQuad,
_init: function(params) {
this.parent(params);
this._brightnessLocation = this.get_uniform_location('brightness');
this._sharpnessLocation = this.get_uniform_location('vignette_sharpness');
this.brightness = 1.0;
this.vignetteSharpness = 0.0;
},
vfunc_build_pipeline: function() {
this.add_glsl_snippet(Shell.SnippetHook.FRAGMENT,
GLSL_DIM_EFFECT_DECLARATIONS,
GLSL_DIM_EFFECT_CODE,
true);
VIGNETTE_DECLARATIONS, VIGNETTE_CODE, true);
},
get brightness() {
return this._brightness;
},
set brightness(v) {
this._brightness = v;
this.set_uniform_float(this._brightnessLocation,
1, [this._brightness]);
},
get vignetteSharpness() {
return this._sharpness;
},
set vignetteSharpness(v) {
this._sharpness = v;
this.set_uniform_float(this._sharpnessLocation,
1, [this._sharpness]);
}
});
/**
@ -75,13 +105,15 @@ const Lightbox = new Lang.Class({
this._container = container;
this._children = container.get_children();
this._fadeFactor = params.fadeFactor;
if (params.radialEffect)
this._radialEffect = Clutter.feature_available(Clutter.FeatureFlags.SHADERS_GLSL) && params.radialEffect;
if (this._radialEffect)
this.actor = new RadialShaderQuad({ x: 0,
y: 0,
reactive: params.inhibitEvents });
else
this.actor = new St.Bin({ x: 0,
y: 0,
opacity: 0,
style_class: 'lightbox',
reactive: params.inhibitEvents });
@ -133,9 +165,18 @@ const Lightbox = new Lang.Class({
fadeInTime = fadeInTime || 0;
Tweener.removeTweens(this.actor);
if (fadeInTime != 0) {
this.shown = false;
this.actor.opacity = 0;
if (this._radialEffect) {
Tweener.addTween(this.actor,
{ brightness: VIGNETTE_BRIGHTNESS,
vignetteSharpness: VIGNETTE_SHARPNESS,
time: fadeInTime,
transition: 'easeOutQuad',
onComplete: Lang.bind(this, function() {
this.shown = true;
this.emit('shown');
})
});
} else {
Tweener.addTween(this.actor,
{ opacity: 255 * this._fadeFactor,
time: fadeInTime,
@ -145,11 +186,8 @@ const Lightbox = new Lang.Class({
this.emit('shown');
})
});
} else {
this.actor.opacity = 255 * this._fadeFactor;
this.shown = true;
this.emit('shown');
}
this.actor.show();
},
@ -158,7 +196,18 @@ const Lightbox = new Lang.Class({
this.shown = false;
Tweener.removeTweens(this.actor);
if (fadeOutTime != 0) {
if (this._radialEffect) {
Tweener.addTween(this.actor,
{ brightness: 1.0,
vignetteSharpness: 0.0,
opacity: 0,
time: fadeOutTime,
transition: 'easeOutQuad',
onComplete: Lang.bind(this, function() {
this.actor.hide();
})
});
} else {
Tweener.addTween(this.actor,
{ opacity: 0,
time: fadeOutTime,
@ -167,8 +216,6 @@ const Lightbox = new Lang.Class({
this.actor.hide();
})
});
} else {
this.actor.hide();
}
},

View File

@ -27,6 +27,8 @@ const CHEVRON = '>>> ';
/* Imports...feel free to add here as needed */
var commandHeader = 'const Clutter = imports.gi.Clutter; ' +
'const GLib = imports.gi.GLib; ' +
'const GObject = imports.gi.GObject; ' +
'const Gio = imports.gi.Gio; ' +
'const Gtk = imports.gi.Gtk; ' +
'const Mainloop = imports.mainloop; ' +
'const Meta = imports.gi.Meta; ' +
@ -795,7 +797,7 @@ const LookingGlass = new Lang.Class({
reactive: true });
this.actor.connect('key-press-event', Lang.bind(this, this._globalKeyPressEvent));
this._interfaceSettings = new Gio.Settings({ schema: 'org.gnome.desktop.interface' });
this._interfaceSettings = new Gio.Settings({ schema_id: 'org.gnome.desktop.interface' });
this._interfaceSettings.connect('changed::monospace-font-name',
Lang.bind(this, this._updateFont));
this._updateFont();
@ -841,9 +843,10 @@ const LookingGlass = new Lang.Class({
System.gc();
this._timeoutId = Mainloop.timeout_add(500, Lang.bind(this, function () {
gcIcon.icon_name = 'gnome-fs-trash-full';
Mainloop.source_remove(this._timeoutId);
this._timeoutId = 0;
return GLib.SOURCE_REMOVE;
}));
GLib.Source.set_name_by_id(this._timeoutId, '[gnome-shell] gcIcon.icon_name = \'gnome-fs-trash-full\'');
return Clutter.EVENT_PROPAGATE;
}));

View File

@ -11,6 +11,7 @@ const Mainloop = imports.mainloop;
const Meta = imports.gi.Meta;
const Signals = imports.signals;
const Background = imports.ui.background;
const FocusCaretTracker = imports.ui.focusCaretTracker;
const Main = imports.ui.main;
const MagnifierDBus = imports.ui.magnifierDBus;
@ -57,20 +58,6 @@ const Magnifier = new Lang.Class({
// Magnifier is a manager of ZoomRegions.
this._zoomRegions = [];
// Export to dbus.
magDBusService = new MagnifierDBus.ShellMagnifier();
let showAtLaunch = this._settingsInit();
this.setActive(showAtLaunch);
},
_initialize: function() {
if (this._initialized)
return;
this._initialized = true;
this._settingsInitLate();
// Create small clutter tree for the magnified mouse.
let cursorTracker = Meta.CursorTracker.get_for_screen(global.screen);
this._mouseSprite = new Clutter.Texture();
@ -86,11 +73,15 @@ const Magnifier = new Lang.Class({
let aZoomRegion = new ZoomRegion(this, this._cursorRoot);
this._zoomRegions.push(aZoomRegion);
this._settingsInitRegion(aZoomRegion);
let showAtLaunch = this._settingsInit(aZoomRegion);
aZoomRegion.scrollContentsTo(this.xMouse, this.yMouse);
cursorTracker.connect('cursor-changed', Lang.bind(this, this._updateMouseSprite));
this._cursorTracker = cursorTracker;
// Export to dbus.
magDBusService = new MagnifierDBus.ShellMagnifier();
this.setActive(showAtLaunch);
},
/**
@ -115,20 +106,21 @@ const Magnifier = new Lang.Class({
* @activate: Boolean to activate or de-activate the magnifier.
*/
setActive: function(activate) {
if (activate == this.isActive())
return;
if (activate)
this._initialize();
let isActive = this.isActive();
this._zoomRegions.forEach (function(zoomRegion, index, array) {
zoomRegion.setActive(activate);
});
if (activate)
this.startTrackingMouse();
else
this.stopTrackingMouse();
if (isActive != activate) {
if (activate) {
Meta.disable_unredirect_for_screen(global.screen);
this.startTrackingMouse();
} else {
Meta.enable_unredirect_for_screen(global.screen);
this.stopTrackingMouse();
}
}
// Make sure system mouse pointer is shown when all zoom regions are
// invisible.
@ -448,68 +440,64 @@ const Magnifier = new Lang.Class({
this._mouseSprite.set_anchor_point(xHot, yHot);
},
_settingsInitRegion: function(zoomRegion) {
// Mag factor is accurate to two decimal places.
let aPref = parseFloat(this._settings.get_double(MAG_FACTOR_KEY).toFixed(2));
if (aPref != 0.0)
zoomRegion.setMagFactor(aPref, aPref);
_settingsInit: function(zoomRegion) {
this._appSettings = new Gio.Settings({ schema_id: APPLICATIONS_SCHEMA });
this._settings = new Gio.Settings({ schema_id: MAGNIFIER_SCHEMA });
aPref = this._settings.get_enum(SCREEN_POSITION_KEY);
if (aPref)
zoomRegion.setScreenPosition(aPref);
if (zoomRegion) {
// Mag factor is accurate to two decimal places.
let aPref = parseFloat(this._settings.get_double(MAG_FACTOR_KEY).toFixed(2));
if (aPref != 0.0)
zoomRegion.setMagFactor(aPref, aPref);
zoomRegion.setLensMode(this._settings.get_boolean(LENS_MODE_KEY));
zoomRegion.setClampScrollingAtEdges(!this._settings.get_boolean(CLAMP_MODE_KEY));
aPref = this._settings.get_enum(SCREEN_POSITION_KEY);
if (aPref)
zoomRegion.setScreenPosition(aPref);
aPref = this._settings.get_enum(MOUSE_TRACKING_KEY);
if (aPref)
zoomRegion.setMouseTrackingMode(aPref);
zoomRegion.setLensMode(this._settings.get_boolean(LENS_MODE_KEY));
zoomRegion.setClampScrollingAtEdges(!this._settings.get_boolean(CLAMP_MODE_KEY));
aPref = this._settings.get_enum(FOCUS_TRACKING_KEY);
if (aPref)
zoomRegion.setFocusTrackingMode(aPref);
aPref = this._settings.get_enum(MOUSE_TRACKING_KEY);
if (aPref)
zoomRegion.setMouseTrackingMode(aPref);
aPref = this._settings.get_enum(CARET_TRACKING_KEY);
if (aPref)
zoomRegion.setCaretTrackingMode(aPref);
aPref = this._settings.get_enum(FOCUS_TRACKING_KEY);
if (aPref)
zoomRegion.setFocusTrackingMode(aPref);
aPref = this._settings.get_boolean(INVERT_LIGHTNESS_KEY);
if (aPref)
zoomRegion.setInvertLightness(aPref);
aPref = this._settings.get_enum(CARET_TRACKING_KEY);
if (aPref)
zoomRegion.setCaretTrackingMode(aPref);
aPref = this._settings.get_double(COLOR_SATURATION_KEY);
if (aPref)
zoomRegion.setColorSaturation(aPref);
aPref = this._settings.get_boolean(INVERT_LIGHTNESS_KEY);
if (aPref)
zoomRegion.setInvertLightness(aPref);
let bc = {};
bc.r = this._settings.get_double(BRIGHT_RED_KEY);
bc.g = this._settings.get_double(BRIGHT_GREEN_KEY);
bc.b = this._settings.get_double(BRIGHT_BLUE_KEY);
zoomRegion.setBrightness(bc);
aPref = this._settings.get_double(COLOR_SATURATION_KEY);
if (aPref)
zoomRegion.setColorSaturation(aPref);
bc.r = this._settings.get_double(CONTRAST_RED_KEY);
bc.g = this._settings.get_double(CONTRAST_GREEN_KEY);
bc.b = this._settings.get_double(CONTRAST_BLUE_KEY);
zoomRegion.setContrast(bc);
},
let bc = {};
bc.r = this._settings.get_double(BRIGHT_RED_KEY);
bc.g = this._settings.get_double(BRIGHT_GREEN_KEY);
bc.b = this._settings.get_double(BRIGHT_BLUE_KEY);
zoomRegion.setBrightness(bc);
_settingsInit: function() {
this._appSettings = new Gio.Settings({ schema: APPLICATIONS_SCHEMA });
this._settings = new Gio.Settings({ schema: MAGNIFIER_SCHEMA });
bc.r = this._settings.get_double(CONTRAST_RED_KEY);
bc.g = this._settings.get_double(CONTRAST_GREEN_KEY);
bc.b = this._settings.get_double(CONTRAST_BLUE_KEY);
zoomRegion.setContrast(bc);
}
this._appSettings.connect('changed::' + SHOW_KEY, Lang.bind(this, function() {
let active = this._appSettings.get_boolean(SHOW_KEY);
this.setActive(active);
}));
return this._appSettings.get_boolean(SHOW_KEY);
},
_settingsInitLate: function() {
let showCrosshairs = this._settings.get_boolean(SHOW_CROSS_HAIRS_KEY);
this.addCrosshairs();
this.setCrosshairsVisible(showCrosshairs);
this._appSettings.connect('changed::' + SHOW_KEY,
Lang.bind(this, function() {
this.setActive(this._appSettings.get_boolean(SHOW_KEY));
}));
this._settings.connect('changed::' + SCREEN_POSITION_KEY,
Lang.bind(this, this._updateScreenPosition));
this._settings.connect('changed::' + MAG_FACTOR_KEY,
@ -573,6 +561,7 @@ const Magnifier = new Lang.Class({
Lang.bind(this, function() {
this.setCrosshairsClip(this._settings.get_boolean(CROSS_HAIRS_CLIP_KEY));
}));
return this._appSettings.get_boolean(SHOW_KEY);
},
_updateScreenPosition: function() {
@ -731,8 +720,16 @@ const ZoomRegion = new Lang.Class({
let component = event.source.get_component_iface();
if (!component || event.detail1 != 1)
return;
let extents = component.get_extents(Atspi.CoordType.SCREEN);
[this._xFocus, this._yFocus] = [extents.x, extents.y]
let extents;
try {
extents = component.get_extents(Atspi.CoordType.SCREEN);
} catch(e) {
log('Failed to read extents of focused component: ' + e.message);
return;
}
[this._xFocus, this._yFocus] = [extents.x + (extents.width / 2),
extents.y + (extents.height / 2)];
this._centerFromFocusPosition();
},
@ -740,7 +737,14 @@ const ZoomRegion = new Lang.Class({
let text = event.source.get_text_iface();
if (!text)
return;
let extents = text.get_character_extents(text.get_caret_offset(), 0);
let extents;
try {
extents = text.get_character_extents(text.get_caret_offset(), 0);
} catch(e) {
log('Failed to read extents of text caret: ' + e.message);
return;
}
[this._xCaret, this._yCaret] = [extents.x, extents.y];
this._centerFromCaretPosition();
},
@ -763,6 +767,9 @@ const ZoomRegion = new Lang.Class({
} else {
this._destroyActors();
}
this._syncCaretTracking();
this._syncFocusTracking();
},
/**
@ -822,10 +829,7 @@ const ZoomRegion = new Lang.Class({
*/
setFocusTrackingMode: function(mode) {
this._focusTrackingMode = mode;
if (this._focusTrackingMode == GDesktopEnums.MagnifierFocusTrackingMode.NONE)
this._focusCaretTracker.deregisterFocusListener();
else
this._focusCaretTracker.registerFocusListener();
this._syncFocusTracking();
},
/**
@ -834,10 +838,27 @@ const ZoomRegion = new Lang.Class({
*/
setCaretTrackingMode: function(mode) {
this._caretTrackingMode = mode;
if (this._caretTrackingMode == GDesktopEnums.MagnifierCaretTrackingMode.NONE)
this._focusCaretTracker.deregisterCaretListener();
this._syncCaretTracking();
},
_syncFocusTracking: function() {
let enabled = this._focusTrackingMode != GDesktopEnums.MagnifierFocusTrackingMode.NONE &&
this.isActive();
if (enabled)
this._focusCaretTracker.registerFocusListener();
else
this._focusCaretTracker.deregisterFocusListener();
},
_syncCaretTracking: function() {
let enabled = this._caretTrackingMode != GDesktopEnums.MagnifierCaretTrackingMode.NONE &&
this.isActive();
if (enabled)
this._focusCaretTracker.registerCaretListener();
else
this._focusCaretTracker.deregisterCaretListener();
},
/**
@ -1178,13 +1199,17 @@ const ZoomRegion = new Lang.Class({
// Add a background for when the magnified uiGroup is scrolled
// out of view (don't want to see desktop showing through).
this._background = new Clutter.Actor({ background_color: Main.DEFAULT_BACKGROUND_COLOR,
layout_manager: new Clutter.BinLayout(),
width: global.screen_width,
height: global.screen_height });
let noiseTexture = (new Background.SystemBackground()).actor;
this._background.add_actor(noiseTexture);
mainGroup.add_actor(this._background);
// Clone the group that contains all of UI on the screen. This is the
// chrome, the windows, etc.
this._uiGroupClone = new Clutter.Clone({ source: Main.uiGroup });
this._uiGroupClone = new Clutter.Clone({ source: Main.uiGroup,
clip_to_allocation: true });
mainGroup.add_actor(this._uiGroupClone);
// Add either the given mouseSourceActor to the ZoomRegion, or a clone of

View File

@ -18,6 +18,7 @@ const ExtensionSystem = imports.ui.extensionSystem;
const ExtensionDownloader = imports.ui.extensionDownloader;
const Keyboard = imports.ui.keyboard;
const MessageTray = imports.ui.messageTray;
const ModalDialog = imports.ui.modalDialog;
const OsdWindow = imports.ui.osdWindow;
const Overview = imports.ui.overview;
const Panel = imports.ui.panel;
@ -43,6 +44,7 @@ const DEFAULT_BACKGROUND_COLOR = Clutter.Color.from_pixel(0x2e3436ff);
const A11Y_SCHEMA = 'org.gnome.desktop.a11y.keyboard';
const STICKY_KEYS_ENABLE = 'stickykeys-enable';
const GNOMESHELL_STARTED_MESSAGE_ID = 'f3ea493c22934e26811cd62abe8e203a';
let componentManager = null;
let panel = null;
@ -55,7 +57,7 @@ let screenShield = null;
let notificationDaemon = null;
let windowAttentionHandler = null;
let ctrlAltTabManager = null;
let osdWindow = null;
let osdWindowManager = null;
let sessionMode = null;
let shellDBusService = null;
let shellMountOpDBusService = null;
@ -73,7 +75,6 @@ let _startDate;
let _defaultCssStylesheet = null;
let _cssStylesheet = null;
let _a11ySettings = null;
let dynamicWorkspacesSchema = null;
function _sessionUpdated() {
_loadDefaultStylesheet();
@ -103,9 +104,6 @@ function start() {
global.logError = window.log;
global.log = window.log;
if (!Meta.is_wayland_compositor)
Meta.is_wayland_compositor = function () { return false; };
// Chain up async errors reported from C
global.connect('notify-error', function (global, msg, detail) { notifyError(msg, detail); });
@ -113,7 +111,6 @@ function start() {
sessionMode = new SessionMode.SessionMode();
sessionMode.connect('updated', _sessionUpdated);
_initializePrefs();
_initializeUI();
shellDBusService = new ShellDBus.GnomeShell();
@ -122,17 +119,6 @@ function start() {
_sessionUpdated();
}
function _initializePrefs() {
let keys = new Gio.Settings({ schema: sessionMode.overridesSchema }).list_keys();
for (let i = 0; i < keys.length; i++)
Meta.prefs_override_preference_schema(keys[i], sessionMode.overridesSchema);
if (keys.indexOf('dynamic-workspaces') > -1)
dynamicWorkspacesSchema = sessionMode.overridesSchema;
else
dynamicWorkspacesSchema = 'org.gnome.mutter';
}
function _initializeUI() {
// Ensure ShellWindowTracker and ShellAppUsage are initialized; this will
// also initialize ShellAppSystem first. ShellAppSystem
@ -158,7 +144,7 @@ function _initializeUI() {
screencastService = new Screencast.ScreencastService();
xdndHandler = new XdndHandler.XdndHandler();
ctrlAltTabManager = new CtrlAltTab.CtrlAltTabManager();
osdWindow = new OsdWindow.OsdWindow();
osdWindowManager = new OsdWindow.OsdWindowManager();
overview = new Overview.Overview();
wm = new WindowManager.WindowManager();
magnifier = new Magnifier.Magnifier();
@ -175,13 +161,23 @@ function _initializeUI() {
layoutManager.init();
overview.init();
_a11ySettings = new Gio.Settings({ schema: A11Y_SCHEMA });
_a11ySettings = new Gio.Settings({ schema_id: A11Y_SCHEMA });
global.display.connect('overlay-key', Lang.bind(overview, function () {
if (!_a11ySettings.get_boolean (STICKY_KEYS_ENABLE))
overview.toggle();
}));
global.display.connect('show-restart-message', function(display, message) {
showRestartMessage(message);
return true;
});
global.display.connect('restart', function() {
global.reexec_self();
return true;
});
// Provide the bus object for gnome-session to
// initiate logouts.
EndSessionDialog.init();
@ -191,8 +187,6 @@ function _initializeUI() {
_startDate = new Date();
log('GNOME Shell started at ' + _startDate);
let perfModuleName = GLib.getenv("SHELL_PERF_MODULE");
if (perfModuleName) {
let perfOutput = GLib.getenv("SHELL_PERF_OUTPUT");
@ -210,13 +204,24 @@ function _initializeUI() {
}
layoutManager.connect('startup-complete', function() {
if (keybindingMode == Shell.KeyBindingMode.NONE) {
keybindingMode = Shell.KeyBindingMode.NORMAL;
}
if (screenShield) {
screenShield.lockIfWasLocked();
}
});
if (keybindingMode == Shell.KeyBindingMode.NONE) {
keybindingMode = Shell.KeyBindingMode.NORMAL;
}
if (screenShield) {
screenShield.lockIfWasLocked();
}
if (LoginManager.haveSystemd() &&
sessionMode.currentMode != 'gdm' &&
sessionMode.currentMode != 'initial-setup') {
// Do not import globally to not depend
// on systemd on non-systemd systems.
let GSystem = imports.gi.GSystem;
GSystem.log_structured_print('GNOME Shell started at ' + _startDate,
['MESSAGE_ID=' + GNOMESHELL_STARTED_MESSAGE_ID]);
} else {
log('GNOME Shell started at ' + _startDate);
}
});
}
function _loadDefaultStylesheet() {
@ -239,8 +244,7 @@ function _loadDefaultStylesheet() {
* Returns: A file path that contains the theme CSS,
* null if using the default
*/
function getThemeStylesheet()
{
function getThemeStylesheet() {
return _cssStylesheet;
}
@ -251,8 +255,7 @@ function getThemeStylesheet()
*
* Set the theme CSS file that the shell will load
*/
function setThemeStylesheet(cssStylesheet)
{
function setThemeStylesheet(cssStylesheet) {
_cssStylesheet = cssStylesheet;
}
@ -611,5 +614,31 @@ function queueDeferredWork(workId) {
_deferredTimeoutId = 0;
return GLib.SOURCE_REMOVE;
});
GLib.Source.set_name_by_id(_deferredTimeoutId, '[gnome-shell] _runAllDeferredWork');
}
}
const RestartMessage = new Lang.Class({
Name: 'RestartMessage',
Extends: ModalDialog.ModalDialog,
_init : function(message) {
this.parent({ shellReactive: true,
styleClass: 'restart-message',
shouldFadeIn: false,
destroyOnClose: true });
let label = new St.Label({ text: message });
this.contentLayout.add(label, { x_fill: false,
y_fill: false,
x_align: St.Align.MIDDLE,
y_align: St.Align.MIDDLE });
this.buttonLayout.hide();
}
});
function showRestartMessage(message) {
let restartMessage = new RestartMessage(message);
restartMessage.open();
}

View File

@ -15,6 +15,7 @@ const Signals = imports.signals;
const St = imports.gi.St;
const Tp = imports.gi.TelepathyGLib;
const EdgeDragAction = imports.ui.edgeDragAction;
const BoxPointer = imports.ui.boxpointer;
const CtrlAltTab = imports.ui.ctrlAltTab;
const GnomeSession = imports.misc.gnomeSession;
@ -26,6 +27,7 @@ const PopupMenu = imports.ui.popupMenu;
const Params = imports.misc.params;
const Tweener = imports.ui.tweener;
const Util = imports.misc.util;
const ViewSelector = imports.ui.viewSelector;
const SHELL_KEYBINDINGS_SCHEMA = 'org.gnome.shell.keybindings';
@ -111,7 +113,6 @@ const FocusGrabber = new Lang.Class({
if (this._focused)
return;
this._prevFocusedWindow = global.display.focus_window;
this._prevKeyFocusActor = global.stage.get_key_focus();
this._focusActorChangedId = global.stage.connect('notify::key-focus', Lang.bind(this, this._focusActorChanged));
@ -316,7 +317,7 @@ const NotificationGenericPolicy = new Lang.Class({
this.id = 'generic';
this._masterSettings = new Gio.Settings({ schema: 'org.gnome.desktop.notifications' });
this._masterSettings = new Gio.Settings({ schema_id: 'org.gnome.desktop.notifications' });
this._masterSettings.connect('changed', Lang.bind(this, this._changed));
},
@ -366,8 +367,8 @@ const NotificationApplicationPolicy = new Lang.Class({
this.id = id;
this._canonicalId = this._canonicalizeId(id);
this._masterSettings = new Gio.Settings({ schema: 'org.gnome.desktop.notifications' });
this._settings = new Gio.Settings({ schema: 'org.gnome.desktop.notifications.application',
this._masterSettings = new Gio.Settings({ schema_id: 'org.gnome.desktop.notifications' });
this._settings = new Gio.Settings({ schema_id: 'org.gnome.desktop.notifications.application',
path: '/org/gnome/desktop/notifications/application/' + this._canonicalId + '/' });
this._masterSettings.connect('changed', Lang.bind(this, this._changed));
@ -504,7 +505,6 @@ const Notification = new Lang.Class({
this.bannerBodyMarkup = false;
this._bannerBodyAdded = false;
this._titleFitsInBannerMode = true;
this._titleDirection = Clutter.TextDirection.DEFAULT;
this._spacing = 0;
this._scrollPolicy = Gtk.PolicyType.AUTOMATIC;
this._imageBin = null;
@ -643,10 +643,11 @@ const Notification = new Lang.Class({
title = title ? _fixMarkup(title.replace(/\n/g, ' '), false) : '';
this._titleLabel.clutter_text.set_markup('<b>' + title + '</b>');
let titleDirection;
if (Pango.find_base_dir(title, -1) == Pango.Direction.RTL)
this._titleDirection = Clutter.TextDirection.RTL;
titleDirection = Clutter.TextDirection.RTL;
else
this._titleDirection = Clutter.TextDirection.LTR;
titleDirection = Clutter.TextDirection.LTR;
// Let the title's text direction control the overall direction
// of the notification - in case where different scripts are used
@ -654,7 +655,7 @@ const Notification = new Lang.Class({
// arguably for action buttons as well. Labels other than the title
// will be allocated at the available width, so that their alignment
// is done correctly automatically.
this._table.set_text_direction(this._titleDirection);
this._table.set_text_direction(titleDirection);
// Unless the notification has custom content, we save this.bannerBodyText
// to add it to the content of the notification if the notification is
@ -923,7 +924,7 @@ const Notification = new Lang.Class({
let [titleMinH, titleNatH] = this._titleLabel.get_preferred_height(availWidth);
let [bannerMinW, bannerNatW] = this._bannerLabel.get_preferred_width(availWidth);
let rtl = (this._titleDirection == Clutter.TextDirection.RTL);
let rtl = (this._table.text_direction == Clutter.TextDirection.RTL);
let x = rtl ? availWidth : 0;
if (this._secondaryIcon) {
@ -1162,32 +1163,12 @@ const SourceActor = new Lang.Class({
}));
this._actorDestroyed = false;
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,
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,
y_fill: true });
let scale_factor = St.ThemeContext.get_for_stage(global.stage).scale_factor;
this._iconBin = new St.Bin({ x_fill: true,
height: size * scale_factor,
width: size * scale_factor });
this.actor.add_actor(this._iconBin);
this.actor.add_actor(this._counterBin);
this._source.connect('count-updated', Lang.bind(this, this._updateCount));
this._updateCount();
this._source.connect('icon-updated', Lang.bind(this, this._updateIcon));
this._updateIcon();
@ -1211,6 +1192,48 @@ const SourceActor = new Lang.Class({
_allocate: function(actor, box, flags) {
// the iconBin should fill our entire box
this._iconBin.allocate(box, flags);
},
_updateIcon: function() {
if (this._actorDestroyed)
return;
if (!this._iconSet)
this._iconBin.child = this._source.createIcon(this._size);
}
});
const SourceActorWithLabel = new Lang.Class({
Name: 'SourceActorWithLabel',
Extends: SourceActor,
_init: function(source, size) {
this.parent(source, size);
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,
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.actor.add_actor(this._counterBin);
this._source.connect('count-updated', Lang.bind(this, this._updateCount));
this._updateCount();
},
_allocate: function(actor, box, flags) {
this.parent(actor, box, flags);
let childBox = new Clutter.ActorBox();
@ -1233,14 +1256,6 @@ const SourceActor = new Lang.Class({
this._counterBin.allocate(childBox, flags);
},
_updateIcon: function() {
if (this._actorDestroyed)
return;
if (!this._iconSet)
this._iconBin.child = this._source.createIcon(this._size);
},
_updateCount: function() {
if (this._actorDestroyed)
return;
@ -1353,7 +1368,7 @@ const Source = new Lang.Class({
if (this._mainIcon)
return;
this._mainIcon = new SourceActor(this, this.SOURCE_ICON_SIZE);
this._mainIcon = new SourceActorWithLabel(this, this.SOURCE_ICON_SIZE);
},
// Unlike createIcon, this always returns the same actor;
@ -1797,6 +1812,13 @@ const MessageTray = new Lang.Class({
y_expand: true });
this.actor.add_actor(this._summary);
this._focusTrap = new ViewSelector.FocusTrap({ can_focus: true });
this._focusTrap.connect('key-focus-in', Lang.bind(this,
function() {
this._messageTrayMenuButton.actor.grab_key_focus();
}));
this._summary.add_actor(this._focusTrap);
this._summaryMotionId = 0;
this._summaryBoxPointer = new BoxPointer.BoxPointer(St.Side.BOTTOM,
@ -1887,14 +1909,14 @@ const MessageTray = new Lang.Class({
Main.sessionMode.connect('updated', Lang.bind(this, this._sessionUpdated));
Main.wm.addKeybinding('toggle-message-tray',
new Gio.Settings({ schema: SHELL_KEYBINDINGS_SCHEMA }),
new Gio.Settings({ schema_id: SHELL_KEYBINDINGS_SCHEMA }),
Meta.KeyBindingFlags.NONE,
Shell.KeyBindingMode.NORMAL |
Shell.KeyBindingMode.MESSAGE_TRAY |
Shell.KeyBindingMode.OVERVIEW,
Lang.bind(this, this.toggleAndNavigate));
Main.wm.addKeybinding('focus-active-notification',
new Gio.Settings({ schema: SHELL_KEYBINDINGS_SCHEMA }),
new Gio.Settings({ schema_id: SHELL_KEYBINDINGS_SCHEMA }),
Meta.KeyBindingFlags.NONE,
Shell.KeyBindingMode.NORMAL |
Shell.KeyBindingMode.MESSAGE_TRAY |
@ -1920,6 +1942,13 @@ const MessageTray = new Lang.Class({
this._messageTrayMenuButton = new MessageTrayMenuButton(this);
this.actor.add_actor(this._messageTrayMenuButton.actor);
this._messageTrayMenuButton.actor.connect('key-press-event',
Lang.bind(this, this._onTrayButtonKeyPress));
let gesture = new EdgeDragAction.EdgeDragAction(St.Side.BOTTOM);
gesture.connect('activated', Lang.bind(this, this.toggle));
global.stage.add_action(gesture);
},
close: function() {
@ -1973,6 +2002,7 @@ const MessageTray = new Lang.Class({
this._trayDwellTimeoutId = Mainloop.timeout_add(TRAY_DWELL_TIME,
Lang.bind(this, this._trayDwellTimeout));
GLib.Source.set_name_by_id(this._trayDwellTimeoutId, '[gnome-shell] this._trayDwellTimeout');
}
this._trayDwelling = true;
} else {
@ -2011,15 +2041,30 @@ const MessageTray = new Lang.Class({
return GLib.SOURCE_REMOVE;
},
_onTrayButtonKeyPress: function(actor, event) {
if (event.get_key_symbol() == Clutter.ISO_Left_Tab) {
this._focusTrap.can_focus = false;
this._summary.navigate_focus(null, Gtk.DirectionType.TAB_BACKWARD, false);
this._focusTrap.can_focus = true;
return Clutter.EVENT_STOP;
}
return Clutter.EVENT_PROPAGATE;
},
_onNotificationKeyRelease: function(actor, event) {
if (event.get_key_symbol() == Clutter.KEY_Escape && event.get_state() == 0) {
this._closeNotification();
this._expireNotification();
return Clutter.EVENT_STOP;
}
return Clutter.EVENT_PROPAGATE;
},
_expireNotification: function() {
this._notificationExpired = true;
this._updateState();
},
_closeNotification: function() {
if (this._notificationState == State.SHOWN) {
this._closeButton.hide();
@ -2248,6 +2293,16 @@ const MessageTray = new Lang.Class({
this._grabHelper.addActor(corner.actor);
},
_resetNotificationLeftTimeout: function() {
this._useLongerNotificationLeftTimeout = false;
if (this._notificationLeftTimeoutId) {
Mainloop.source_remove(this._notificationLeftTimeoutId);
this._notificationLeftTimeoutId = 0;
this._notificationLeftMouseX = -1;
this._notificationLeftMouseY = -1;
}
},
_onNotificationHoverChanged: function() {
if (this._notificationWidget.hover == this._notificationHovered)
return;
@ -2257,14 +2312,7 @@ const MessageTray = new Lang.Class({
// No dwell inside notifications at the bottom of the screen
this._cancelTrayDwell();
this._useLongerNotificationLeftTimeout = false;
if (this._notificationLeftTimeoutId) {
Mainloop.source_remove(this._notificationLeftTimeoutId);
this._notificationLeftTimeoutId = 0;
this._notificationLeftMouseX = -1;
this._notificationLeftMouseY = -1;
return;
}
this._resetNotificationLeftTimeout();
if (this._showNotificationMouseX >= 0) {
let actorAtShowNotificationPosition =
@ -2281,6 +2329,7 @@ const MessageTray = new Lang.Class({
return;
}
}
this._pointerInNotification = true;
this._updateState();
} else {
@ -2297,6 +2346,7 @@ const MessageTray = new Lang.Class({
// That gives the user more time to mouse away from the notification and mouse back in in order to expand it.
let timeout = this._useLongerNotificationLeftTimeout ? LONGER_HIDE_TIMEOUT * 1000 : HIDE_TIMEOUT * 1000;
this._notificationLeftTimeoutId = Mainloop.timeout_add(timeout, Lang.bind(this, this._onNotificationLeftTimeout));
GLib.Source.set_name_by_id(this._notificationLeftTimeoutId, '[gnome-shell] this._onNotificationLeftTimeout');
}
},
@ -2332,6 +2382,7 @@ const MessageTray = new Lang.Class({
this._notificationLeftMouseX = -1;
this._notificationLeftTimeoutId = Mainloop.timeout_add(LONGER_HIDE_TIMEOUT * 1000,
Lang.bind(this, this._onNotificationLeftTimeout));
GLib.Source.set_name_by_id(this._notificationLeftTimeoutId, '[gnome-shell] this._onNotificationLeftTimeout');
} else {
this._notificationLeftTimeoutId = 0;
this._useLongerNotificationLeftTimeout = false;
@ -2384,7 +2435,7 @@ const MessageTray = new Lang.Class({
this._notificationTimeoutId == 0 &&
this._notification.urgency != Urgency.CRITICAL &&
!this._notification.focused &&
!this._pointerInNotification);
!this._pointerInNotification) || this._notificationExpired;
let mustClose = (this._notificationRemoved || !hasNotifications || expired || this._traySummoned);
if (mustClose) {
@ -2445,6 +2496,10 @@ const MessageTray = new Lang.Class({
this._hideDesktopClone();
this._updatingState = false;
// Clean transient variables that are used to communicate actions
// to updateState()
this._notificationExpired = false;
},
_tween: function(actor, statevar, value, params) {
@ -2601,6 +2656,8 @@ const MessageTray = new Lang.Class({
// the mouse is moving towards it or within it.
this._lastSeenMouseX = x;
this._lastSeenMouseY = y;
this._resetNotificationLeftTimeout();
},
_updateShowingNotification: function() {
@ -2645,10 +2702,12 @@ const MessageTray = new Lang.Class({
Mainloop.source_remove(this._notificationTimeoutId);
this._notificationTimeoutId = 0;
}
if (timeout > 0)
if (timeout > 0) {
this._notificationTimeoutId =
Mainloop.timeout_add(timeout,
Lang.bind(this, this._notificationTimeout));
GLib.Source.set_name_by_id(this._notificationTimeoutId, '[gnome-shell] this._notificationTimeout');
}
},
_notificationTimeout: function() {
@ -2691,13 +2750,7 @@ const MessageTray = new Lang.Class({
this._notificationUnfocusedId = 0;
}
this._useLongerNotificationLeftTimeout = false;
if (this._notificationLeftTimeoutId) {
Mainloop.source_remove(this._notificationLeftTimeoutId);
this._notificationLeftTimeoutId = 0;
this._notificationLeftMouseX = -1;
this._notificationLeftMouseY = -1;
}
this._resetNotificationLeftTimeout();
if (animate) {
this._tween(this._notificationWidget, '_notificationState', State.HIDDEN,
@ -2767,7 +2820,12 @@ const MessageTray = new Lang.Class({
{ y: expandedY,
opacity: 255,
time: ANIMATION_TIME,
transition: 'easeOutQuad'
transition: 'easeOutQuad',
// HACK: Drive the state machine here better,
// instead of overwriting tweens
onComplete: Lang.bind(this, function() {
this._notificationState = State.SHOWN;
}),
});
}
},

View File

@ -41,9 +41,9 @@ const ModalDialog = new Lang.Class({
_init: function(params) {
params = Params.parse(params, { shellReactive: false,
styleClass: null,
parentActor: Main.uiGroup,
keybindingMode: Shell.KeyBindingMode.SYSTEM_MODAL,
shouldFadeIn: true,
shouldFadeOut: true,
destroyOnClose: true });
this.state = State.CLOSED;
@ -51,13 +51,14 @@ const ModalDialog = new Lang.Class({
this._keybindingMode = params.keybindingMode;
this._shellReactive = params.shellReactive;
this._shouldFadeIn = params.shouldFadeIn;
this._shouldFadeOut = params.shouldFadeOut;
this._destroyOnClose = params.destroyOnClose;
this._group = new St.Widget({ visible: false,
x: 0,
y: 0,
accessible_role: Atk.Role.DIALOG });
params.parentActor.add_actor(this._group);
Main.layoutManager.modalDialogGroup.add_actor(this._group);
let constraint = new Clutter.BindConstraint({ source: global.stage,
coordinate: Clutter.BindCoordinate.ALL });
@ -308,6 +309,15 @@ const ModalDialog = new Lang.Class({
return true;
},
_closeComplete: function() {
this.state = State.CLOSED;
this._group.hide();
this.emit('closed');
if (this._destroyOnClose)
this.destroy();
},
close: function(timestamp) {
if (this.state == State.CLOSED || this.state == State.CLOSING)
return;
@ -316,20 +326,16 @@ const ModalDialog = new Lang.Class({
this.popModal(timestamp);
this._savedKeyFocus = null;
Tweener.addTween(this._group,
{ opacity: 0,
time: OPEN_AND_CLOSE_TIME,
transition: 'easeOutQuad',
onComplete: Lang.bind(this,
function() {
this.state = State.CLOSED;
this._group.hide();
this.emit('closed');
if (this._destroyOnClose)
this.destroy();
})
});
if (this._shouldFadeOut)
Tweener.addTween(this._group,
{ opacity: 0,
time: OPEN_AND_CLOSE_TIME,
transition: 'easeOutQuad',
onComplete: Lang.bind(this,
this._closeComplete)
})
else
this._closeComplete();
},
// Drop modal status without closing the dialog; this makes the

View File

@ -120,15 +120,12 @@ const FdoNotificationDaemon = new Lang.Class({
this._nextNotificationId = 1;
Shell.WindowTracker.get_default().connect('notify::focus-app', Lang.bind(this, this._onFocusAppChanged));
Main.overview.connect('hidden', Lang.bind(this, this._onFocusAppChanged));
this._trayManager = new Shell.TrayManager();
this._trayIconAddedId = this._trayManager.connect('tray-icon-added', Lang.bind(this, this._onTrayIconAdded));
this._trayIconRemovedId = this._trayManager.connect('tray-icon-removed', Lang.bind(this, this._onTrayIconRemoved));
Shell.WindowTracker.get_default().connect('notify::focus-app',
Lang.bind(this, this._onFocusAppChanged));
Main.overview.connect('hidden',
Lang.bind(this, this._onFocusAppChanged));
this._trayManager.manage_screen(global.screen, Main.messageTray.actor);
},
@ -244,11 +241,12 @@ const FdoNotificationDaemon = new Lang.Class({
// Ignore replacesId since we already sent back a
// NotificationClosed for that id.
id = this._nextNotificationId++;
Mainloop.idle_add(Lang.bind(this,
function () {
this._emitNotificationClosed(id, NotificationClosedReason.DISMISSED);
return GLib.SOURCE_REMOVE;
}));
let idle_id = Mainloop.idle_add(Lang.bind(this,
function () {
this._emitNotificationClosed(id, NotificationClosedReason.DISMISSED);
return GLib.SOURCE_REMOVE;
}));
GLib.Source.set_name_by_id(idle_id, '[gnome-shell] this._emitNotificationClosed');
return invocation.return_value(GLib.Variant.new('(u)', [id]));
}
@ -691,6 +689,12 @@ const FdoNotificationDaemonSource = new Lang.Class({
}
});
const PRIORITY_URGENCY_MAP = {
low: MessageTray.Urgency.LOW,
normal: MessageTray.Urgency.NORMAL,
high: MessageTray.Urgency.HIGH,
urgent: MessageTray.Urgency.CRITICAL
};
const GtkNotificationDaemonNotification = new Lang.Class({
Name: 'GtkNotificationDaemonNotification',
@ -704,12 +708,20 @@ const GtkNotificationDaemonNotification = new Lang.Class({
"body": body,
"icon": gicon,
"urgent": urgent,
"priority": priority,
"buttons": buttons,
"default-action": defaultAction,
"default-action-target": defaultActionTarget } = notification;
this.setUrgency(urgent.unpack() ? MessageTray.Urgency.CRITICAL
: MessageTray.Urgency.NORMAL);
if (priority) {
let urgency = PRIORITY_URGENCY_MAP[priority.unpack()];
this.setUrgency(urgency != undefined ? urgency : MessageTray.Urgency.NORMAL);
} else if (urgent) {
this.setUrgency(urgent.unpack() ? MessageTray.Urgency.CRITICAL
: MessageTray.Urgency.NORMAL);
} else {
this.setUrgency(MessageTray.Urgency.NORMAL);
}
if (buttons) {
buttons.deep_unpack().forEach(Lang.bind(this, function(button) {

View File

@ -73,14 +73,17 @@ const LevelBar = new Lang.Class({
const OsdWindow = new Lang.Class({
Name: 'OsdWindow',
_init: function() {
_init: function(monitorIndex) {
this._popupSize = 0;
this.actor = new St.Widget({ x_expand: true,
y_expand: true,
x_align: Clutter.ActorAlign.CENTER,
y_align: Clutter.ActorAlign.CENTER });
this._currentMonitor = undefined;
this.setMonitor (-1);
this._monitorIndex = monitorIndex;
let constraint = new Layout.MonitorConstraint({ index: monitorIndex });
this.actor.add_constraint(constraint);
this._box = new St.BoxLayout({ style_class: 'osd-window',
vertical: true });
this.actor.add_actor(this._box);
@ -109,7 +112,6 @@ const OsdWindow = new Lang.Class({
Main.layoutManager.connect('monitors-changed',
Lang.bind(this, this._monitorsChanged));
this._monitorsChanged();
Main.uiGroup.add_child(this.actor);
},
@ -125,7 +127,7 @@ const OsdWindow = new Lang.Class({
setLevel: function(level) {
this._level.actor.visible = (level != undefined);
if (level) {
if (level != undefined) {
if (this.actor.visible)
Tweener.addTween(this._level,
{ level: level,
@ -156,6 +158,7 @@ const OsdWindow = new Lang.Class({
Mainloop.source_remove(this._hideTimeoutId);
this._hideTimeoutId = Mainloop.timeout_add(HIDE_TIMEOUT,
Lang.bind(this, this._hide));
GLib.Source.set_name_by_id(this._hideTimeoutId, '[gnome-shell] this._hide');
},
cancel: function() {
@ -188,20 +191,18 @@ const OsdWindow = new Lang.Class({
_monitorsChanged: function() {
/* assume 110x110 on a 640x480 display and scale from there */
let monitor;
if (this._currentMonitor >= 0)
monitor = Main.layoutManager.monitors[this._currentMonitor];
else
monitor = Main.layoutManager.primaryMonitor;
let monitor = Main.layoutManager.monitors[this._monitorIndex];
if (!monitor)
return; // we are about to be removed
let scalew = monitor.width / 640.0;
let scaleh = monitor.height / 480.0;
let scale = Math.min(scalew, scaleh);
this._popupSize = 110 * Math.max(1, scale);
let scaleFactor = St.ThemeContext.get_for_stage(global.stage).scale_factor;
this._icon.icon_size = this._popupSize / (2 * scaleFactor);
this._box.translation_y = monitor.height / 4;
this._icon.icon_size = this._popupSize / 2;
this._box.style_changed();
},
@ -217,24 +218,60 @@ const OsdWindow = new Lang.Class({
let minWidth = this._popupSize - verticalPadding - leftBorder - rightBorder;
let minHeight = this._popupSize - horizontalPadding - topBorder - bottomBorder;
this._box.style = 'min-height: %dpx;'.format(Math.max(minWidth, minHeight));
},
setMonitor: function(index) {
let constraint;
if (index < 0)
index = -1;
if (this._currentMonitor == index)
return;
if (index < 0)
constraint = new Layout.MonitorConstraint({ primary: true });
else
constraint = new Layout.MonitorConstraint({ index: index });
this.actor.clear_constraints();
this.actor.add_constraint(constraint);
this._currentMonitor = index;
// minWidth/minHeight here are in real pixels,
// but the theme takes measures in unscaled dimensions
let scaleFactor = St.ThemeContext.get_for_stage(global.stage).scale_factor;
this._box.style = 'min-height: %dpx;'.format(Math.max(minWidth, minHeight) / scaleFactor);
}
});
const OsdWindowManager = new Lang.Class({
Name: 'OsdWindowManager',
_init: function() {
this._osdWindows = [];
Main.layoutManager.connect('monitors-changed',
Lang.bind(this, this._monitorsChanged));
this._monitorsChanged();
},
_monitorsChanged: function() {
for (let i = 0; i < Main.layoutManager.monitors.length; i++) {
if (this._osdWindows[i] == undefined)
this._osdWindows[i] = new OsdWindow(i);
}
for (let i = Main.layoutManager.monitors.length; i < this._osdWindows.length; i++) {
this._osdWindows[i].actor.destroy();
this._osdWindows[i] = null;
}
this._osdWindows.length = Main.layoutManager.monitors.length;
},
_showOsdWindow: function(monitorIndex, icon, label, level) {
this._osdWindows[monitorIndex].setIcon(icon);
this._osdWindows[monitorIndex].setLabel(label);
this._osdWindows[monitorIndex].setLevel(level);
this._osdWindows[monitorIndex].show();
},
show: function(monitorIndex, icon, label, level) {
if (monitorIndex != -1) {
for (let i = 0; i < this._osdWindows.length; i++) {
if (i == monitorIndex)
this._showOsdWindow(i, icon, label, level);
else
this._osdWindows[i].cancel();
}
} else {
for (let i = 0; i < this._osdWindows.length; i++)
this._showOsdWindow(i, icon, label, level);
}
},
hideAll: function() {
for (let i = 0; i < this._osdWindows.length; i++)
this._osdWindows[i].cancel();
}
});

View File

@ -14,6 +14,7 @@ const Gdk = imports.gi.Gdk;
const Background = imports.ui.background;
const DND = imports.ui.dnd;
const LayoutManager = imports.ui.layout;
const Lightbox = imports.ui.lightbox;
const Main = imports.ui.main;
const MessageTray = imports.ui.messageTray;
const OverviewControls = imports.ui.overviewControls;
@ -184,7 +185,7 @@ const Overview = new Lang.Class({
for (let i = 0; i < Main.layoutManager.monitors.length; i++) {
let bgManager = new Background.BackgroundManager({ container: this._backgroundGroup,
monitorIndex: i,
effects: Meta.BackgroundEffects.VIGNETTE });
vignette: true });
this._bgManagers.push(bgManager);
}
},
@ -192,15 +193,9 @@ const Overview = new Lang.Class({
_unshadeBackgrounds: function() {
let backgrounds = this._backgroundGroup.get_children();
for (let i = 0; i < backgrounds.length; i++) {
let background = backgrounds[i]._delegate;
Tweener.addTween(background,
Tweener.addTween(backgrounds[i],
{ brightness: 1.0,
time: SHADE_ANIMATION_TIME,
transition: 'easeOutQuad'
});
Tweener.addTween(background,
{ vignetteSharpness: 0.0,
vignette_sharpness: 0.0,
time: SHADE_ANIMATION_TIME,
transition: 'easeOutQuad'
});
@ -210,15 +205,9 @@ const Overview = new Lang.Class({
_shadeBackgrounds: function() {
let backgrounds = this._backgroundGroup.get_children();
for (let i = 0; i < backgrounds.length; i++) {
let background = backgrounds[i]._delegate;
Tweener.addTween(background,
{ brightness: 0.8,
time: SHADE_ANIMATION_TIME,
transition: 'easeOutQuad'
});
Tweener.addTween(background,
{ vignetteSharpness: 0.7,
Tweener.addTween(backgrounds[i],
{ brightness: Lightbox.VIGNETTE_BRIGHTNESS,
vignette_sharpness: Lightbox.VIGNETTE_SHARPNESS,
time: SHADE_ANIMATION_TIME,
transition: 'easeOutQuad'
});
@ -249,7 +238,7 @@ const Overview = new Lang.Class({
opacity: 0 });
this._overview.add_actor(this._panelGhost);
this._searchEntry = new St.Entry({ name: 'searchEntry',
this._searchEntry = new St.Entry({ style_class: 'search-entry',
/* Translators: this is the text displayed
in the search entry when no search is
active; it should not exceed ~30
@ -372,6 +361,7 @@ const Overview = new Lang.Class({
this._lastHoveredWindow = null;
return GLib.SOURCE_REMOVE;
}));
GLib.Source.set_name_by_id(this._windowSwitchTimeoutId, '[gnome-shell] Main.activateWindow');
}
return DND.DragMotionResult.CONTINUE;
@ -431,8 +421,6 @@ const Overview = new Lang.Class({
this.emit('windows-restacked', stackIndices);
},
//// Public methods ////
beginItemDrag: function(source) {
this.emit('item-drag-begin');
this._inDrag = true;
@ -447,37 +435,20 @@ const Overview = new Lang.Class({
this._inDrag = false;
},
beginWindowDrag: function(clone) {
this.emit('window-drag-begin', clone);
beginWindowDrag: function(window) {
this.emit('window-drag-begin', window);
this._inDrag = true;
},
cancelledWindowDrag: function(clone) {
this.emit('window-drag-cancelled', clone);
cancelledWindowDrag: function(window) {
this.emit('window-drag-cancelled', window);
},
endWindowDrag: function(clone) {
this.emit('window-drag-end', clone);
endWindowDrag: function(window) {
this.emit('window-drag-end', window);
this._inDrag = false;
},
// show:
//
// Animates the overview visible and grabs mouse and keyboard input
show: function() {
if (this.isDummy)
return;
if (this._shown)
return;
this._shown = true;
if (!this._syncGrab())
return;
Main.layoutManager.showOverview();
this._animateVisible();
},
focusSearch: function() {
this.show();
this._searchEntry.grab_key_focus();
@ -493,8 +464,13 @@ const Overview = new Lang.Class({
},
fadeOutDesktop: function() {
if (!this._desktopFade.get_n_children())
this._desktopFade.add_child(this._getDesktopClone());
if (!this._desktopFade.get_n_children()) {
let clone = this._getDesktopClone();
if (!clone)
return;
this._desktopFade.add_child(clone);
}
this._desktopFade.opacity = 255;
this._desktopFade.show();
@ -505,69 +481,6 @@ const Overview = new Lang.Class({
});
},
_animateVisible: function() {
if (this.visible || this.animationInProgress)
return;
this.visible = true;
this.animationInProgress = true;
this.visibleTarget = true;
this._activationTime = Date.now() / 1000;
Meta.disable_unredirect_for_screen(global.screen);
this.viewSelector.show();
this._stack.opacity = 0;
Tweener.addTween(this._stack,
{ opacity: 255,
transition: 'easeOutQuad',
time: ANIMATION_TIME,
onComplete: this._showDone,
onCompleteScope: this
});
this._shadeBackgrounds();
this._coverPane.raise_top();
this._coverPane.show();
this.emit('showing');
},
// hide:
//
// Reverses the effect of show()
hide: function() {
if (this.isDummy)
return;
if (!this._shown)
return;
let event = Clutter.get_current_event();
if (event) {
let type = event.type();
let button = (type == Clutter.EventType.BUTTON_PRESS ||
type == Clutter.EventType.BUTTON_RELEASE);
let ctrl = (event.get_state() & Clutter.ModifierType.CONTROL_MASK) != 0;
if (button && ctrl)
return;
}
this._animateNotVisible();
this._shown = false;
this._syncGrab();
},
toggle: function() {
if (this.isDummy)
return;
if (this.visible)
this.hide();
else
this.show();
},
// Checks if the Activities button is currently sensitive to
// clicks. The first call to this function within the
// OVERVIEW_ACTIVATION_TIMEOUT time of the hot corner being
@ -584,8 +497,6 @@ const Overview = new Lang.Class({
return false;
},
//// Private methods ////
_syncGrab: function() {
// We delay grab changes during animation so that when removing the
// overview we don't have a problem with the release of a press/release
@ -615,28 +526,49 @@ const Overview = new Lang.Class({
return true;
},
_animateNotVisible: function() {
if (!this.visible || this.animationInProgress)
// show:
//
// Animates the overview visible and grabs mouse and keyboard input
show: function() {
if (this.isDummy)
return;
if (this._shown)
return;
this._shown = true;
if (!this._syncGrab())
return;
Main.layoutManager.showOverview();
this._animateVisible();
},
_animateVisible: function() {
if (this.visible || this.animationInProgress)
return;
this.visible = true;
this.animationInProgress = true;
this.visibleTarget = false;
this.visibleTarget = true;
this._activationTime = Date.now() / 1000;
this.viewSelector.zoomFromOverview();
Meta.disable_unredirect_for_screen(global.screen);
this.viewSelector.show();
// Make other elements fade out.
this._stack.opacity = 0;
Tweener.addTween(this._stack,
{ opacity: 0,
{ opacity: 255,
transition: 'easeOutQuad',
time: ANIMATION_TIME,
onComplete: this._hideDone,
onComplete: this._showDone,
onCompleteScope: this
});
this._unshadeBackgrounds();
this._shadeBackgrounds();
this._coverPane.raise_top();
this._coverPane.show();
this.emit('hiding');
this.emit('showing');
},
_showDone: function() {
@ -653,6 +585,57 @@ const Overview = new Lang.Class({
global.sync_pointer();
},
// hide:
//
// Reverses the effect of show()
hide: function() {
if (this.isDummy)
return;
if (!this._shown)
return;
let event = Clutter.get_current_event();
if (event) {
let type = event.type();
let button = (type == Clutter.EventType.BUTTON_PRESS ||
type == Clutter.EventType.BUTTON_RELEASE);
let ctrl = (event.get_state() & Clutter.ModifierType.CONTROL_MASK) != 0;
if (button && ctrl)
return;
}
this._animateNotVisible();
this._shown = false;
this._syncGrab();
},
_animateNotVisible: function() {
if (!this.visible || this.animationInProgress)
return;
this.animationInProgress = true;
this.visibleTarget = false;
this.viewSelector.animateFromOverview();
// Make other elements fade out.
Tweener.addTween(this._stack,
{ opacity: 0,
transition: 'easeOutQuad',
time: ANIMATION_TIME,
onComplete: this._hideDone,
onCompleteScope: this
});
this._unshadeBackgrounds();
this._coverPane.raise_top();
this._coverPane.show();
this.emit('hiding');
},
_hideDone: function() {
// Re-enable unredirection
Meta.enable_unredirect_for_screen(global.screen);
@ -678,6 +661,20 @@ const Overview = new Lang.Class({
this._fakePointerEvent();
this._needsFakePointerEvent = false;
}
},
toggle: function() {
if (this.isDummy)
return;
if (this.visible)
this.hide();
else
this.show();
},
getShowAppsButton: function() {
return this._dash.showAppsButton;
}
});
Signals.addSignalMethods(Overview.prototype);

View File

@ -36,7 +36,7 @@ const SlideLayout = new Lang.Class({
_init: function(params) {
this._slideX = 1;
this._translationX = 0;
this._translationX = undefined;
this._direction = SlideDirection.LEFT;
this.parent(params);
@ -118,7 +118,6 @@ const SlidingControl = new Lang.Class({
style_class: 'overview-controls',
clip_to_allocation: true });
Main.overview.connect('showing', Lang.bind(this, this._onOverviewShowing));
Main.overview.connect('hiding', Lang.bind(this, this._onOverviewHiding));
Main.overview.connect('item-drag-begin', Lang.bind(this, this._onDragBegin));
@ -162,7 +161,8 @@ const SlidingControl = new Lang.Class({
let translationEnd = 0;
let translation = this._getTranslation();
if (this._visible) {
let shouldShow = (this._getSlide() > 0);
if (shouldShow) {
translationStart = translation;
} else {
translationEnd = translation;
@ -177,14 +177,9 @@ const SlidingControl = new Lang.Class({
transition: 'easeOutQuad' });
},
_onOverviewShowing: function() {
this._visible = true;
this.layout.slideX = this._getSlide();
this.layout.translationX = this._getTranslation();
this.slideIn();
},
_onOverviewHiding: function() {
// We need to explicitly slideOut since showing pages
// doesn't imply sliding out, instead, hiding the overview does.
this.slideOut();
},
@ -198,7 +193,7 @@ const SlidingControl = new Lang.Class({
_onDragBegin: function() {
this._inDrag = true;
this.layout.translationX = 0;
this._updateTranslation();
this._updateSlide();
},
@ -223,7 +218,6 @@ const SlidingControl = new Lang.Class({
slideIn: function() {
this._visible = true;
this._updateTranslation();
// we will update slideX and the translation from pageEmpty
},
@ -259,13 +253,18 @@ const ThumbnailsSlider = new Lang.Class({
Main.layoutManager.connect('monitors-changed', Lang.bind(this, this._updateSlide));
this.actor.connect('notify::hover', Lang.bind(this, this._updateSlide));
global.window_manager.connect('switch-workspace', Lang.bind(this, this._updateSlide));
this._thumbnailsBox.actor.bind_property('visible', this.actor, 'visible', GObject.BindingFlags.SYNC_CREATE);
},
_getAlwaysZoomOut: function() {
// Always show the pager when hover, during a drag, or if workspaces are
// actually used, e.g. there are windows on more than one
let alwaysZoomOut = this.actor.hover || this._inDrag || !Meta.prefs_get_dynamic_workspaces() || global.screen.n_workspaces > 2;
// actually used, e.g. there are windows on any non-active workspace
let alwaysZoomOut = this.actor.hover ||
this._inDrag ||
!Meta.prefs_get_dynamic_workspaces() ||
global.screen.n_workspaces > 2 ||
global.screen.get_active_workspace_index() != 0;
if (!alwaysZoomOut) {
let monitors = Main.layoutManager.monitors;

View File

@ -14,7 +14,6 @@ const St = imports.gi.St;
const Signals = imports.signals;
const Atk = imports.gi.Atk;
const Animation = imports.ui.animation;
const Config = imports.misc.config;
const CtrlAltTab = imports.ui.ctrlAltTab;
@ -213,7 +212,7 @@ const AppMenuButton = new Lang.Class({
this._label = new TextShadower();
this._label.actor.y_align = Clutter.ActorAlign.CENTER;
this._hbox.add_actor(this._label.actor);
this._arrow = PopupMenu.unicodeArrow(St.Side.BOTTOM);
this._arrow = PopupMenu.arrowIcon(St.Side.BOTTOM);
this._hbox.add_actor(this._arrow);
this._iconBottomClip = 0;
@ -572,7 +571,6 @@ const ActivitiesButton = new Lang.Class({
this.actor.label_actor = this._label;
this.actor.connect('captured-event', Lang.bind(this, this._onCapturedEvent));
this.actor.connect_after('button-release-event', Lang.bind(this, this._onButtonRelease));
this.actor.connect_after('key-release-event', Lang.bind(this, this._onKeyRelease));
Main.overview.connect('showing', Lang.bind(this, function() {
@ -595,21 +593,27 @@ const ActivitiesButton = new Lang.Class({
Mainloop.source_remove(this._xdndTimeOut);
this._xdndTimeOut = Mainloop.timeout_add(BUTTON_DND_ACTIVATION_TIMEOUT,
Lang.bind(this, this._xdndToggleOverview, actor));
GLib.Source.set_name_by_id(this._xdndTimeOut, '[gnome-shell] this._xdndToggleOverview');
return DND.DragMotionResult.CONTINUE;
},
_onCapturedEvent: function(actor, event) {
if (event.type() == Clutter.EventType.BUTTON_PRESS) {
if (event.type() == Clutter.EventType.BUTTON_PRESS ||
event.type() == Clutter.EventType.TOUCH_BEGIN) {
if (!Main.overview.shouldToggleByCornerOrButton())
return Clutter.EVENT_STOP;
}
return Clutter.EVENT_PROPAGATE;
},
_onButtonRelease: function() {
Main.overview.toggle();
this.menu.close();
_onEvent: function(actor, event) {
this.parent(actor, event);
if (event.type() == Clutter.EventType.TOUCH_END ||
event.type() == Clutter.EventType.BUTTON_RELEASE)
Main.overview.toggle();
return Clutter.EVENT_PROPAGATE;
},
@ -812,7 +816,11 @@ const AggregateMenu = new Lang.Class({
this._indicators = new St.BoxLayout({ style_class: 'panel-status-indicators-box' });
this.actor.add_child(this._indicators);
this._network = new imports.ui.status.network.NMApplet();
if (Config.HAVE_NETWORKMANAGER) {
this._network = new imports.ui.status.network.NMApplet();
} else {
this._network = null;
}
if (Config.HAVE_BLUETOOTH) {
this._bluetooth = new imports.ui.status.bluetooth.Indicator();
} else {
@ -829,22 +837,27 @@ const AggregateMenu = new Lang.Class({
this._indicators.add_child(this._screencast.indicators);
this._indicators.add_child(this._location.indicators);
this._indicators.add_child(this._network.indicators);
if (this._network) {
this._indicators.add_child(this._network.indicators);
}
if (this._bluetooth) {
this._indicators.add_child(this._bluetooth.indicators);
}
this._indicators.add_child(this._rfkill.indicators);
this._indicators.add_child(this._volume.indicators);
this._indicators.add_child(this._power.indicators);
this._indicators.add_child(PopupMenu.unicodeArrow(St.Side.BOTTOM));
this._indicators.add_child(PopupMenu.arrowIcon(St.Side.BOTTOM));
this.menu.addMenuItem(this._volume.menu);
this.menu.addMenuItem(this._brightness.menu);
this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
this.menu.addMenuItem(this._network.menu);
if (this._network) {
this.menu.addMenuItem(this._network.menu);
}
if (this._bluetooth) {
this.menu.addMenuItem(this._bluetooth.menu);
}
this.menu.addMenuItem(this._location.menu);
this.menu.addMenuItem(this._rfkill.menu);
this.menu.addMenuItem(this._power.menu);
this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());

View File

@ -41,8 +41,7 @@ const ButtonBox = new Lang.Class({
},
_getPreferredWidth: function(actor, forHeight, alloc) {
let children = actor.get_children();
let child = children.length > 0 ? children[0] : null;
let child = actor.get_first_child();
if (child) {
[alloc.min_size, alloc.natural_size] = child.get_preferred_width(-1);
@ -55,8 +54,7 @@ const ButtonBox = new Lang.Class({
},
_getPreferredHeight: function(actor, forWidth, alloc) {
let children = actor.get_children();
let child = children.length > 0 ? children[0] : null;
let child = actor.get_first_child();
if (child) {
[alloc.min_size, alloc.natural_size] = child.get_preferred_height(-1);
@ -66,13 +64,11 @@ const ButtonBox = new Lang.Class({
},
_allocate: function(actor, box, flags) {
let children = actor.get_children();
if (children.length == 0)
let child = actor.get_first_child();
if (!child)
return;
let child = children[0];
let [minWidth, natWidth] = child.get_preferred_width(-1);
let [minHeight, natHeight] = child.get_preferred_height(-1);
let availWidth = box.x2 - box.x1;
let availHeight = box.y2 - box.y1;
@ -104,8 +100,7 @@ const Button = new Lang.Class({
accessible_name: nameText ? nameText : "",
accessible_role: Atk.Role.MENU });
this.actor.connect('button-press-event', Lang.bind(this, this._onButtonPress));
this.actor.connect('key-press-event', Lang.bind(this, this._onSourceKeyPress));
this.actor.connect('event', Lang.bind(this, this._onEvent));
this.actor.connect('notify::visible', Lang.bind(this, this._onVisibilityChanged));
if (dontCreateMenu)
@ -135,32 +130,13 @@ const Button = new Lang.Class({
}
},
_onButtonPress: function(actor, event) {
if (!this.menu)
return Clutter.EVENT_PROPAGATE;
this.menu.toggle();
return Clutter.EVENT_PROPAGATE;
},
_onSourceKeyPress: function(actor, event) {
if (!this.menu)
return Clutter.EVENT_PROPAGATE;
let symbol = event.get_key_symbol();
if (symbol == Clutter.KEY_space || symbol == Clutter.KEY_Return) {
_onEvent: function(actor, event) {
if (this.menu &&
(event.type() == Clutter.EventType.TOUCH_BEGIN ||
event.type() == Clutter.EventType.BUTTON_PRESS))
this.menu.toggle();
return Clutter.EVENT_STOP;
} else if (symbol == Clutter.KEY_Escape && this.menu.isOpen) {
this.menu.close();
return Clutter.EVENT_STOP;
} else if (symbol == Clutter.KEY_Down) {
if (!this.menu.isOpen)
this.menu.toggle();
this.menu.actor.navigate_focus(this.actor, Gtk.DirectionType.DOWN, false);
return Clutter.EVENT_STOP;
} else
return Clutter.EVENT_PROPAGATE;
return Clutter.EVENT_PROPAGATE;
},
_onVisibilityChanged: function() {

View File

@ -107,6 +107,7 @@ const PointerWatcher = new Lang.Class({
this._timeoutId = Mainloop.timeout_add(minInterval,
Lang.bind(this, this._onTimeout));
GLib.Source.set_name_by_id(this._timeoutId, '[gnome-shell] this._onTimeout');
},
_onTimeout: function() {

View File

@ -1,9 +1,7 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
const Clutter = imports.gi.Clutter;
const GLib = imports.gi.GLib;
const Gtk = imports.gi.Gtk;
const Gio = imports.gi.Gio;
const Lang = imports.lang;
const Shell = imports.gi.Shell;
const Signals = imports.signals;
@ -15,7 +13,6 @@ const GrabHelper = imports.ui.grabHelper;
const Main = imports.ui.main;
const Params = imports.misc.params;
const Separator = imports.ui.separator;
const Slider = imports.ui.slider;
const Tweener = imports.ui.tweener;
const Ornament = {
@ -24,17 +21,6 @@ const Ornament = {
CHECK: 2,
};
function _ensureStyle(actor) {
if (actor.get_children) {
let children = actor.get_children();
for (let i = 0; i < children.length; i++)
_ensureStyle(children[i]);
}
if (actor instanceof St.Widget)
actor.ensure_style();
}
function isPopupMenuItemVisible(child) {
if (child._delegate instanceof PopupMenuSection)
if (child._delegate.isEmpty())
@ -45,28 +31,30 @@ function isPopupMenuItemVisible(child) {
/**
* @side Side to which the arrow points.
*/
function unicodeArrow(side) {
let arrowChar;
function arrowIcon(side) {
let iconName;
switch (side) {
case St.Side.TOP:
arrowChar = '\u25B4';
iconName = 'pan-up-symbolic';
break;
case St.Side.RIGHT:
arrowChar = '\u25B8';
iconName = 'pan-end-symbolic';
break;
case St.Side.BOTTOM:
arrowChar = '\u25BE';
iconName = 'pan-down-symbolic';
break;
case St.Side.LEFT:
arrowChar = '\u25C2';
iconName = 'pan-start-symbolic';
break;
}
return new St.Label({ text: arrowChar,
style_class: 'unicode-arrow',
accessible_role: Atk.Role.ARROW,
y_expand: true,
y_align: Clutter.ActorAlign.CENTER });
let arrow = new St.Icon({ style_class: 'popup-menu-arrow',
icon_name: iconName,
accessible_role: Atk.Role.ARROW,
y_expand: true,
y_align: Clutter.ActorAlign.CENTER });
return arrow;
}
const PopupBaseMenuItem = new Lang.Class({
@ -104,6 +92,7 @@ const PopupBaseMenuItem = new Lang.Class({
if (this._activatable) {
this.actor.connect('button-release-event', Lang.bind(this, this._onButtonReleaseEvent));
this.actor.connect('touch-event', Lang.bind(this, this._onTouchEvent));
this.actor.connect('key-press-event', Lang.bind(this, this._onKeyPressEvent));
}
if (params.reactive && params.hover)
@ -111,6 +100,7 @@ const PopupBaseMenuItem = new Lang.Class({
this.actor.connect('key-focus-in', Lang.bind(this, this._onKeyFocusIn));
this.actor.connect('key-focus-out', Lang.bind(this, this._onKeyFocusOut));
this.actor.connect('destroy', Lang.bind(this, this._onDestroy));
},
_getTopMenu: function() {
@ -129,6 +119,14 @@ const PopupBaseMenuItem = new Lang.Class({
return Clutter.EVENT_STOP;
},
_onTouchEvent: function (actor, event) {
if (event.type() == Clutter.EventType.TOUCH_END) {
this.activate(event);
return Clutter.EVENT_STOP;
}
return Clutter.EVENT_PROPAGATE;
},
_onKeyPressEvent: function (actor, event) {
let symbol = event.get_key_symbol();
@ -192,6 +190,9 @@ const PopupBaseMenuItem = new Lang.Class({
destroy: function() {
this.actor.destroy();
},
_onDestroy: function() {
this.emit('destroy');
},
@ -240,8 +241,16 @@ const PopupSeparatorMenuItem = new Lang.Class({
this.actor.add(this.label);
this.actor.label_actor = this.label;
this.label.connect('notify::text',
Lang.bind(this, this._syncVisibility));
this._syncVisibility();
this._separator = new Separator.HorizontalSeparator({ style_class: 'popup-separator-menu-item' });
this.actor.add(this._separator.actor, { expand: true });
},
_syncVisibility: function() {
this.label.visible = this.label.text != '';
}
});
@ -364,9 +373,9 @@ const PopupImageMenuItem = new Lang.Class({
this.parent(params);
this.label = new St.Label({ text: text });
this.addActor(this.label);
this.actor.add_child(this.label);
this._icon = new St.Icon({ style_class: 'popup-menu-icon' });
this.addActor(this._icon, { align: St.Align.END });
this.actor.add_child(this._icon, { align: St.Align.END });
this.setIcon(iconName);
},
@ -722,6 +731,10 @@ const PopupMenu = new Lang.Class({
global.focus_manager.add_group(this.actor);
this.actor.reactive = true;
if (this.sourceActor)
this._keyPressId = this.sourceActor.connect('key-press-event',
Lang.bind(this, this._onKeyPress));
this._openedSubMenu = null;
},
@ -732,6 +745,40 @@ const PopupMenu = new Lang.Class({
this._openedSubMenu = submenu;
},
_onKeyPress: function(actor, event) {
let navKey;
switch (this._boxPointer.arrowSide) {
case St.Side.TOP:
navKey = Clutter.KEY_Down;
break;
case St.Side.BOTTOM:
navKey = Clutter.KEY_Up;
break;
case St.Side.LEFT:
navKey = Clutter.KEY_Right;
break;
case St.Side.RIGHT:
navKey = Clutter.KEY_Left;
break;
}
let symbol = event.get_key_symbol();
if (symbol == Clutter.KEY_space || symbol == Clutter.KEY_Return) {
this.toggle();
return Clutter.EVENT_STOP;
} else if (symbol == Clutter.KEY_Escape && this.isOpen) {
this.close();
return Clutter.EVENT_STOP;
} else if (symbol == navKey) {
if (!this.isOpen)
this.toggle();
this.actor.navigate_focus(null, Gtk.DirectionType.TAB_FORWARD, false);
return Clutter.EVENT_STOP;
} else
return Clutter.EVENT_PROPAGATE;
},
setArrowOrigin: function(origin) {
this._boxPointer.setArrowOrigin(origin);
},
@ -772,6 +819,12 @@ const PopupMenu = new Lang.Class({
this.isOpen = false;
this.emit('open-state-changed', false);
},
destroy: function() {
if (this._keyPressId)
this.sourceActor.disconnect(this._keyPressId);
this.parent();
}
});
@ -865,17 +918,19 @@ const PopupSubMenu = new Lang.Class({
if (animate && needsScrollbar)
animate = false;
let targetAngle = this.actor.text_direction == Clutter.TextDirection.RTL ? -90 : 90;
if (animate) {
let [minHeight, naturalHeight] = this.actor.get_preferred_height(-1);
this.actor.height = 0;
this.actor._arrow_rotation = this._arrow.rotation_angle_z;
this.actor._arrowRotation = this._arrow.rotation_angle_z;
Tweener.addTween(this.actor,
{ _arrow_rotation: 90,
{ _arrowRotation: targetAngle,
height: naturalHeight,
time: 0.25,
onUpdateScope: this,
onUpdate: function() {
this._arrow.rotation_angle_z = this.actor._arrow_rotation;
this._arrow.rotation_angle_z = this.actor._arrowRotation;
},
onCompleteScope: this,
onComplete: function() {
@ -883,7 +938,7 @@ const PopupSubMenu = new Lang.Class({
}
});
} else {
this._arrow.rotation_angle_z = 90;
this._arrow.rotation_angle_z = targetAngle;
}
},
@ -901,14 +956,14 @@ const PopupSubMenu = new Lang.Class({
animate = false;
if (animate) {
this.actor._arrow_rotation = this._arrow.rotation_angle_z;
this.actor._arrowRotation = this._arrow.rotation_angle_z;
Tweener.addTween(this.actor,
{ _arrow_rotation: 0,
{ _arrowRotation: 0,
height: 0,
time: 0.25,
onUpdateScope: this,
onUpdate: function() {
this._arrow.rotation_angle_z = this.actor._arrow_rotation;
this._arrow.rotation_angle_z = this.actor._arrowRotation;
},
onCompleteScope: this,
onComplete: function() {
@ -989,14 +1044,12 @@ const PopupSubMenuMenuItem = new Lang.Class({
y_align: Clutter.ActorAlign.CENTER });
this.actor.add_child(this.status);
this._triangle = unicodeArrow(St.Side.RIGHT);
this._triangle = arrowIcon(St.Side.RIGHT);
this._triangle.pivot_point = new Clutter.Point({ x: 0.5, y: 0.6 });
this._triangleBin = new St.Widget({ y_expand: true,
y_align: Clutter.ActorAlign.CENTER });
this._triangleBin.add_child(this._triangle);
if (this._triangleBin.get_text_direction() == Clutter.TextDirection.RTL)
this._triangleBin.set_scale(-1.0, 1.0);
this.actor.add_child(this._triangleBin);
this.actor.add_accessible_state (Atk.StateType.EXPANDABLE);

View File

@ -110,6 +110,13 @@ function loadRemoteSearchProviders(callback) {
else
remoteProvider = new RemoteSearchProvider(appInfo, busName, objectPath);
remoteProvider.defaultEnabled = true;
try {
remoteProvider.defaultEnabled = !keyfile.get_boolean(group, 'DefaultDisabled');
} catch(e) {
// ignore error
}
objectPaths[objectPath] = remoteProvider;
loadedProviders.push(remoteProvider);
} catch(e) {
@ -117,7 +124,7 @@ function loadRemoteSearchProviders(callback) {
}
}
let searchSettings = new Gio.Settings({ schema: Search.SEARCH_PROVIDERS_SCHEMA });
let searchSettings = new Gio.Settings({ schema_id: Search.SEARCH_PROVIDERS_SCHEMA });
if (searchSettings.get_boolean('disable-external')) {
callback([]);
return;
@ -132,8 +139,14 @@ function loadRemoteSearchProviders(callback) {
loadedProviders = loadedProviders.filter(function(provider) {
let appId = provider.appInfo.get_id();
let disabled = searchSettings.get_strv('disabled');
return disabled.indexOf(appId) == -1;
if (provider.defaultEnabled) {
let disabled = searchSettings.get_strv('disabled');
return disabled.indexOf(appId) == -1;
} else {
let enabled = searchSettings.get_strv('enabled');
return enabled.indexOf(appId) != -1;
}
});
loadedProviders.sort(function(providerA, providerB) {

View File

@ -38,8 +38,8 @@ const RunDialog = new Lang.Class({
this.parent({ styleClass: 'run-dialog',
destroyOnClose: false });
this._lockdownSettings = new Gio.Settings({ schema: LOCKDOWN_SCHEMA });
this._terminalSettings = new Gio.Settings({ schema: TERMINAL_SCHEMA });
this._lockdownSettings = new Gio.Settings({ schema_id: LOCKDOWN_SCHEMA });
this._terminalSettings = new Gio.Settings({ schema_id: TERMINAL_SCHEMA });
global.settings.connect('changed::development-tools', Lang.bind(this, function () {
this._enableInternalCommands = global.settings.get_boolean('development-tools');
}));
@ -50,14 +50,10 @@ const RunDialog = new Lang.Class({
Main.createLookingGlass().open();
}),
'r': Lang.bind(this, function() {
global.reexec_self();
}),
'r': Lang.bind(this, this._restart),
// Developer brain backwards compatibility
'restart': Lang.bind(this, function() {
global.reexec_self();
}),
'restart': Lang.bind(this, this._restart),
'debugexit': Lang.bind(this, function() {
Meta.quit(Meta.ExitCode.ERROR);
@ -186,6 +182,10 @@ const RunDialog = new Lang.Class({
let results = someResults.reduce(function(a, b) {
return a.concat(b);
}, []);
if (!results.length)
return null;
let common = results.reduce(_getCommon, null);
return common.substr(text.length);
},
@ -271,6 +271,12 @@ const RunDialog = new Lang.Class({
}
},
_restart: function() {
this._shouldFadeOut = false;
this.close();
Meta.restart(_("Restarting…"));
},
open: function() {
this._history.lastItem();
this._errorBox.hide();

View File

@ -301,7 +301,7 @@ const NotificationsBox = new Lang.Class({
});
this._updateVisibility();
Shell.util_wake_up_screen();
this.emit('wake-up-screen');
}
},
@ -327,7 +327,7 @@ const NotificationsBox = new Lang.Class({
this._updateVisibility();
if (obj.sourceBox.visible)
Shell.util_wake_up_screen();
this.emit('wake-up-screen');
},
_visibleChanged: function(source, obj) {
@ -342,7 +342,7 @@ const NotificationsBox = new Lang.Class({
this._updateVisibility();
if (obj.sourceBox.visible)
Shell.util_wake_up_screen();
this.emit('wake-up-screen');
},
_detailedChanged: function(source, obj) {
@ -380,6 +380,7 @@ const NotificationsBox = new Lang.Class({
this._sources.delete(source);
},
});
Signals.addSignalMethods(NotificationsBox.prototype);
const Arrow = new Lang.Class({
Name: 'Arrow',
@ -443,14 +444,12 @@ function clamp(value, min, max) {
}
/**
* To test screen shield, make sure to kill gnome-screensaver.
*
* If you are setting org.gnome.desktop.session.idle-delay directly in dconf,
* rather than through System Settings, you also need to set
* org.gnome.settings-daemon.plugins.power.sleep-display-ac and
* org.gnome.settings-daemon.plugins.power.sleep-display-battery to the same value.
* This will ensure that the screen blanks at the right time when it fades out.
* https://bugzilla.gnome.org/show_bug.cgi?id=668703 explains the dependance.
* https://bugzilla.gnome.org/show_bug.cgi?id=668703 explains the dependency.
*/
const ScreenShield = new Lang.Class({
Name: 'ScreenShield',
@ -536,7 +535,7 @@ const ScreenShield = new Lang.Class({
this._smartcardManager = SmartcardManager.getSmartcardManager();
this._smartcardManager.connect('smartcard-inserted',
Lang.bind(this, function(token) {
Lang.bind(this, function(manager, token) {
if (this._isLocked && token.UsedToLogin)
this._liftShield(true, 0);
}));
@ -562,7 +561,7 @@ const ScreenShield = new Lang.Class({
this._loginSession.connectSignal('Unlock', Lang.bind(this, function() { this.deactivate(false); }));
}));
this._settings = new Gio.Settings({ schema: SCREENSAVER_SCHEMA });
this._settings = new Gio.Settings({ schema_id: SCREENSAVER_SCHEMA });
this._isModal = false;
this._hasLockScreen = false;
@ -688,10 +687,10 @@ const ScreenShield = new Lang.Class({
return Clutter.EVENT_PROPAGATE;
let delta = 0;
if (event.get_scroll_direction() == Clutter.ScrollDirection.UP)
if (event.get_scroll_direction() == Clutter.ScrollDirection.SMOOTH)
delta = Math.abs(event.get_scroll_delta()[0]);
else
delta = 5;
else if (event.get_scroll_direction() == Clutter.ScrollDirection.SMOOTH)
delta = Math.max(0, event.get_scroll_delta()[0]);
this._lockScreenScrollCounter += delta;
@ -728,7 +727,7 @@ const ScreenShield = new Lang.Class({
} else {
this._inhibitSuspend();
this._onUserBecameActive();
this._wakeUpScreen();
}
},
@ -849,6 +848,7 @@ const ScreenShield = new Lang.Class({
this.lock(false);
return GLib.SOURCE_REMOVE;
}));
GLib.Source.set_name_by_id(this._lockTimeoutId, '[gnome-shell] this.lock');
}
this._activateFade(this._longLightbox, STANDARD_FADE_TIME);
@ -900,17 +900,11 @@ const ScreenShield = new Lang.Class({
},
showDialog: function() {
// 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._becomeModal()) {
// In the login screen, this is a hard error. Fail-whale
log('Could not acquire modal grab for the login screen. Aborting login process.');
Meta.quit(Meta.ExitCode.ERROR);
}
return false;
}));
if (!this._becomeModal()) {
// In the login screen, this is a hard error. Fail-whale
log('Could not acquire modal grab for the login screen. Aborting login process.');
Meta.quit(Meta.ExitCode.ERROR);
}
this.actor.show();
this._isGreeter = Main.sessionMode.isGreeter;
@ -1040,6 +1034,7 @@ const ScreenShield = new Lang.Class({
if (!this._arrowAnimationId) {
this._arrowAnimationId = Mainloop.timeout_add(6000, Lang.bind(this, this._animateArrows));
GLib.Source.set_name_by_id(this._arrowAnimationId, '[gnome-shell] this._animateArrows');
this._animateArrows();
}
@ -1107,10 +1102,11 @@ const ScreenShield = new Lang.Class({
if (params.fadeToBlack && params.animateFade) {
// Take a beat
Mainloop.timeout_add(1000 * MANUAL_FADE_TIME, Lang.bind(this, function() {
let id = Mainloop.timeout_add(1000 * MANUAL_FADE_TIME, Lang.bind(this, function() {
this._activateFade(this._shortLightbox, MANUAL_FADE_TIME);
return GLib.SOURCE_REMOVE;
}));
GLib.Source.set_name_by_id(id, '[gnome-shell] this._activateFade');
} else {
if (params.fadeToBlack)
this._activateFade(this._shortLightbox, 0);
@ -1151,6 +1147,7 @@ const ScreenShield = new Lang.Class({
this._lockScreenContents.add_actor(this._lockScreenContentsBox);
this._notificationsBox = new NotificationsBox();
this._wakeUpScreenId = this._notificationsBox.connect('wake-up-screen', Lang.bind(this, this._wakeUpScreen));
this._lockScreenContentsBox.add(this._notificationsBox.actor, { x_fill: true,
y_fill: true,
expand: true });
@ -1158,11 +1155,17 @@ const ScreenShield = new Lang.Class({
this._hasLockScreen = true;
},
_wakeUpScreen: function() {
this._onUserBecameActive();
this.emit('wake-up-screen');
},
_clearLockScreen: function() {
this._clock.destroy();
this._clock = null;
if (this._notificationsBox) {
this._notificationsBox.disconnect(this._wakeUpScreenId);
this._notificationsBox.destroy();
this._notificationsBox = null;
}

View File

@ -11,6 +11,7 @@ const Shell = imports.gi.Shell;
const Signals = imports.signals;
const St = imports.gi.St;
const GrabHelper = imports.ui.grabHelper;
const Lightbox = imports.ui.lightbox;
const Main = imports.ui.main;
const Tweener = imports.ui.tweener;
@ -67,6 +68,13 @@ const ScreenshotService = new Lang.Class({
Gio.DBus.session.own_name('org.gnome.Shell.Screenshot', Gio.BusNameOwnerFlags.REPLACE, null, null);
},
_checkArea: function(x, y, width, height) {
return x >= 0 && y >= 0 &&
width > 0 && height > 0 &&
x + width <= global.screen_width &&
y + height <= global.screen_height;
},
_onScreenshotComplete: function(obj, result, area, filenameUsed, flash, invocation) {
if (flash && result) {
let flashspot = new Flashspot(area);
@ -77,13 +85,31 @@ const ScreenshotService = new Lang.Class({
invocation.return_value(retval);
},
_scaleArea: function(x, y, width, height) {
let scaleFactor = St.ThemeContext.get_for_stage(global.stage).scale_factor;
x *= scaleFactor;
y *= scaleFactor;
width *= scaleFactor;
height *= scaleFactor;
return [x, y, width, height];
},
_unscaleArea: function(x, y, width, height) {
let scaleFactor = St.ThemeContext.get_for_stage(global.stage).scale_factor;
x /= scaleFactor;
y /= scaleFactor;
width /= scaleFactor;
height /= scaleFactor;
return [x, y, width, height];
},
ScreenshotAreaAsync : function (params, invocation) {
let [x, y, width, height, flash, filename, callback] = params;
if (x < 0 || y < 0 ||
width <= 0 || height <= 0 ||
x + width > global.screen_width || y + height > global.screen_height) {
invocation.return_error_literal(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED,
"Invalid params");
[x, y, width, height] = this._scaleArea(x, y, width, height);
if (!this._checkArea(x, y, width, height)) {
invocation.return_error_literal(Gio.IOErrorEnum,
Gio.IOErrorEnum.CANCELLED,
"Invalid params");
return;
}
let screenshot = new Shell.Screenshot();
@ -114,9 +140,9 @@ const ScreenshotService = new Lang.Class({
selectArea.connect('finished', Lang.bind(this,
function(selectArea, areaRectangle) {
if (areaRectangle) {
let retval = GLib.Variant.new('(iiii)',
[areaRectangle.x, areaRectangle.y,
areaRectangle.width, areaRectangle.height]);
let retRectangle = this._unscaleArea(areaRectangle.x, areaRectangle.y,
areaRectangle.width, areaRectangle.height);
let retval = GLib.Variant.new('(iiii)', retRectangle);
invocation.return_value(retval);
} else {
invocation.return_error_literal(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED,
@ -125,9 +151,18 @@ const ScreenshotService = new Lang.Class({
}));
},
FlashArea: function(x, y, width, height) {
FlashAreaAsync: function(params, invocation) {
let [x, y, width, height] = params;
[x, y, width, height] = this._scaleArea(x, y, width, height);
if (!this._checkArea(x, y, width, height)) {
invocation.return_error_literal(Gio.IOErrorEnum,
Gio.IOErrorEnum.CANCELLED,
"Invalid params");
return;
}
let flashspot = new Flashspot({ x : x, y : y, width: width, height: height});
flashspot.fire();
invocation.return_value(null);
}
});
@ -139,6 +174,7 @@ const SelectArea = new Lang.Class({
this._startY = -1;
this._lastX = 0;
this._lastY = 0;
this._result = null;
this._initRubberbandColors();
@ -148,12 +184,12 @@ const SelectArea = new Lang.Class({
y: 0 });
Main.uiGroup.add_actor(this._group);
this._grabHelper = new GrabHelper.GrabHelper(this._group);
this._group.connect('button-press-event',
Lang.bind(this, this._onButtonPress));
this._group.connect('button-release-event',
Lang.bind(this, this._onButtonRelease));
this._group.connect('key-press-event',
Lang.bind(this, this._onKeyPress));
this._group.connect('motion-event',
Lang.bind(this, this._onMotionEvent));
@ -169,10 +205,12 @@ const SelectArea = new Lang.Class({
},
show: function() {
if (!Main.pushModal(this._group) || this._group.visible)
if (!this._grabHelper.grab({ actor: this._group,
onUngrab: Lang.bind(this, this._onUngrab) }))
return;
global.screen.set_cursor(Meta.Cursor.CROSSHAIR);
Main.uiGroup.set_child_above_sibling(this._group, null);
this._group.visible = true;
},
@ -202,13 +240,6 @@ const SelectArea = new Lang.Class({
height: Math.abs(this._startY - this._lastY) };
},
_onKeyPress: function(actor, event) {
if (event.get_key_symbol() == Clutter.Escape)
this._destroy(null, false);
return Clutter.EVENT_PROPAGATE;
},
_onMotionEvent: function(actor, event) {
if (this._startX == -1 || this._startY == -1)
return Clutter.EVENT_PROPAGATE;
@ -230,24 +261,28 @@ const SelectArea = new Lang.Class({
},
_onButtonRelease: function(actor, event) {
this._destroy(this._getGeometry(), true);
return Clutter.EVENT_PROPAGATE;
},
_destroy: function(geometry, fade) {
this._result = this._getGeometry();
Tweener.addTween(this._group,
{ opacity: 0,
time: fade ? 0.2 : 0,
time: 0.2,
transition: 'easeOutQuad',
onComplete: Lang.bind(this,
function() {
Main.popModal(this._group);
this._group.destroy();
global.screen.set_cursor(Meta.Cursor.DEFAULT);
this.emit('finished', geometry);
this._grabHelper.ungrab();
})
});
return Clutter.EVENT_PROPAGATE;
},
_onUngrab: function() {
global.screen.set_cursor(Meta.Cursor.DEFAULT);
this.emit('finished', this._result);
GLib.idle_add(GLib.PRIORITY_DEFAULT, Lang.bind(this,
function() {
this._group.destroy();
return GLib.SOURCE_REMOVE;
}));
}
});
Signals.addSignalMethods(SelectArea.prototype);

View File

@ -7,6 +7,7 @@ const Meta = imports.gi.Meta;
const Shell = imports.gi.Shell;
const Main = imports.ui.main;
const Params = imports.misc.params;
// This module provides functionality for driving the shell user interface
// in an automated fashion. The primary current use case for this is
@ -39,11 +40,12 @@ const Main = imports.ui.main;
function sleep(milliseconds) {
let cb;
Mainloop.timeout_add(milliseconds, function() {
let id = Mainloop.timeout_add(milliseconds, function() {
if (cb)
cb();
return GLib.SOURCE_REMOVE;
});
GLib.Source.set_name_by_id(id, '[gnome-shell] sleep');
return function(callback) {
cb = callback;
@ -77,6 +79,7 @@ const PerfHelperIface = '<node> \
<arg type="i" direction="in" /> \
<arg type="b" direction="in" /> \
<arg type="b" direction="in" /> \
<arg type="b" direction="in" /> \
</method> \
<method name="WaitWindows" /> \
<method name="DestroyWindows" /> \
@ -96,11 +99,36 @@ function _getPerfHelper() {
return _perfHelper;
}
function _callRemote(obj, method, ...args) {
let cb;
let errcb;
args.push(function(result, excp) {
if (excp) {
if (errcb)
errcb(excp);
} else {
if (cb)
cb();
}
});
method.apply(obj, args);
return function(callback, error_callback) {
cb = callback;
errcb = error_callback;
};
}
/**
* createTestWindow:
* @width: width of window, in pixels
* @height: height of window, in pixels
* @alpha: whether the window should be alpha transparent
* @params: options for window creation.
* width - width of window, in pixels (default 640)
* height - height of window, in pixels (default 480)
* alpha - whether the window should have an alpha channel (default false)
* maximized - whether the window should be created maximized (default false)
* redraws - whether the window should continually redraw itself (default false)
* @maximized: whethe the window should be created maximized
*
* Creates a window using gnome-shell-perf-helper for testing purposes.
@ -109,19 +137,17 @@ function _getPerfHelper() {
* because of the normal X asynchronous mapping process, to actually wait
* until the window has been mapped and exposed, use waitTestWindows().
*/
function createTestWindow(width, height, alpha, maximized) {
let cb;
function createTestWindow(width, height, params) {
params = Params.parse(params, { width: 640,
height: 480,
alpha: false,
maximized: false,
redraws: false });
let perfHelper = _getPerfHelper();
perfHelper.CreateWindowRemote(width, height, alpha, maximized,
function(result, excp) {
if (cb)
cb();
});
return function(callback) {
cb = callback;
};
return _callRemote(perfHelper, perfHelper.CreateWindowRemote,
params.width, params.height,
params.alpha, params.maximized, params.redraws);
}
/**
@ -131,17 +157,8 @@ function createTestWindow(width, height, alpha, maximized) {
* created with createTestWindow have been mapped and exposed.
*/
function waitTestWindows() {
let cb;
let perfHelper = _getPerfHelper();
perfHelper.WaitWindowsRemote(function(result, excp) {
if (cb)
cb();
});
return function(callback) {
cb = callback;
};
return _callRemote(perfHelper, perfHelper.WaitWindowsRemote);
}
/**
@ -154,17 +171,8 @@ function waitTestWindows() {
* process because of normal X asynchronicity.
*/
function destroyTestWindows() {
let cb;
let perfHelper = _getPerfHelper();
perfHelper.DestroyWindowsRemote(function(result, excp) {
if (cb)
cb();
});
return function(callback) {
cb = callback;
};
return _callRemote(perfHelper, perfHelper.DestroyWindowsRemote);
}
/**
@ -207,6 +215,10 @@ function _step(g, finish, onError) {
let waitFunction = g.next();
waitFunction(function() {
_step(g, finish, onError);
},
function(err) {
if (onError)
onError(err);
});
} catch (err if err instanceof StopIteration) {
if (finish)
@ -305,8 +317,8 @@ function _collect(scriptModule, outputFile) {
print ('------------------------------------------------------------');
for (let i = 0; i < metrics.length; i++) {
let metric = metrics[i];
print ('# ' + scriptModule.METRIC_DESCRIPTIONS[metric]);
print (metric + ': ' + scriptModule.METRICS[metric]);
print ('# ' + scriptModule.METRICS[metric].description);
print (metric + ': ' + scriptModule.METRICS[metric].value + scriptModule.METRICS[metric].units);
}
print ('------------------------------------------------------------');
}
@ -359,7 +371,12 @@ function runPerfScript(scriptModule, outputFile) {
_step(g,
function() {
_collect(scriptModule, outputFile);
try {
_collect(scriptModule, outputFile);
} catch (err) {
log("Script failed: " + err + "\n" + err.stack);
Meta.exit(Meta.ExitCode.ERROR);
}
Meta.exit(Meta.ExitCode.SUCCESS);
},
function(err) {

View File

@ -2,10 +2,12 @@
const Clutter = imports.gi.Clutter;
const Lang = imports.lang;
const GLib = imports.gi.GLib;
const Gio = imports.gi.Gio;
const Gtk = imports.gi.Gtk;
const Meta = imports.gi.Meta;
const Signals = imports.signals;
const Shell = imports.gi.Shell;
const St = imports.gi.St;
const Atk = imports.gi.Atk;
@ -23,104 +25,6 @@ const SEARCH_PROVIDERS_SCHEMA = 'org.gnome.desktop.search-providers';
const MAX_LIST_SEARCH_RESULTS_ROWS = 3;
const MAX_GRID_SEARCH_RESULTS_ROWS = 1;
const SearchSystem = new Lang.Class({
Name: 'SearchSystem',
_init: function() {
this._providers = [];
this._registerProvider(new AppDisplay.AppSearchProvider());
this._searchSettings = new Gio.Settings({ schema: SEARCH_PROVIDERS_SCHEMA });
this._searchSettings.connect('changed::disabled', Lang.bind(this, this._reloadRemoteProviders));
this._searchSettings.connect('changed::disable-external', Lang.bind(this, this._reloadRemoteProviders));
this._searchSettings.connect('changed::sort-order', Lang.bind(this, this._reloadRemoteProviders));
this._reloadRemoteProviders();
this._cancellable = new Gio.Cancellable();
},
addProvider: function(provider) {
this._providers.push(provider);
this.emit('providers-changed');
},
_reloadRemoteProviders: function() {
let remoteProviders = this._providers.filter(function(provider) {
return provider.isRemoteProvider;
});
remoteProviders.forEach(Lang.bind(this, function(provider) {
this._unregisterProvider(provider);
}));
RemoteSearch.loadRemoteSearchProviders(Lang.bind(this, function(providers) {
providers.forEach(Lang.bind(this, this._registerProvider));
}));
this.emit('providers-changed');
},
_registerProvider: function (provider) {
this._providers.push(provider);
},
_unregisterProvider: function (provider) {
let index = this._providers.indexOf(provider);
this._providers.splice(index, 1);
},
getProviders: function() {
return this._providers;
},
getTerms: function() {
return this._terms;
},
reset: function() {
this._terms = [];
this._results = {};
},
_gotResults: function(results, provider) {
this._results[provider.id] = results;
this.emit('search-updated', provider, results);
},
setTerms: function(terms) {
this._cancellable.cancel();
this._cancellable.reset();
let previousResults = this._results;
let previousTerms = this._terms;
this.reset();
if (!terms)
return;
let searchString = terms.join(' ');
let previousSearchString = previousTerms.join(' ');
if (searchString == previousSearchString)
return;
let isSubSearch = false;
if (previousTerms.length > 0)
isSubSearch = searchString.indexOf(previousSearchString) == 0;
this._terms = terms;
this._providers.forEach(Lang.bind(this, function(provider) {
let previousProviderResults = previousResults[provider.id];
if (isSubSearch && previousProviderResults)
provider.getSubsearchResultSet(previousProviderResults, terms, Lang.bind(this, this._gotResults, provider), this._cancellable);
else
provider.getInitialResultSet(terms, Lang.bind(this, this._gotResults, provider), this._cancellable);
}));
}
});
Signals.addSignalMethods(SearchSystem.prototype);
const MaxWidthBin = new Lang.Class({
Name: 'MaxWidthBin',
Extends: St.Bin,
@ -160,13 +64,6 @@ const SearchResult = new Lang.Class({
activate: function() {
this.emit('activate', this.metaInfo.id);
},
setSelected: function(selected) {
if (selected)
this.actor.add_style_pseudo_class('selected');
else
this.actor.remove_style_pseudo_class('selected');
}
});
Signals.addSignalMethods(SearchResult.prototype);
@ -227,59 +124,11 @@ const GridSearchResult = new Lang.Class({
this.actor.style_class = 'grid-search-result';
let content = provider.createResultObject(metaInfo);
let dragSource = null;
if (content == null) {
let actor = new St.Bin();
let icon = new IconGrid.BaseIcon(this.metaInfo['name'],
{ createIcon: this.metaInfo['createIcon'] });
actor.set_child(icon.actor);
actor.label_actor = icon.label;
dragSource = icon.icon;
content = { actor: actor, icon: icon };
} else {
if (content._delegate && content._delegate.getDragActorSource)
dragSource = content._delegate.getDragActorSource();
}
this.actor.set_child(content.actor);
this.actor.label_actor = content.actor.label_actor;
this.icon = content.icon;
let draggable = DND.makeDraggable(this.actor);
draggable.connect('drag-begin',
Lang.bind(this, function() {
Main.overview.beginItemDrag(this);
}));
draggable.connect('drag-cancelled',
Lang.bind(this, function() {
Main.overview.cancelledItemDrag(this);
}));
draggable.connect('drag-end',
Lang.bind(this, function() {
Main.overview.endItemDrag(this);
}));
if (!dragSource)
// not exactly right, but alignment problems are hard to notice
dragSource = content;
this._dragActorSource = dragSource;
},
getDragActorSource: function() {
return this._dragActorSource;
},
getDragActor: function() {
return this.metaInfo['createIcon'](Main.overview.dashIconSize);
},
shellWorkspaceLaunch: function(params) {
if (this.provider.dragActivateResult)
this.provider.dragActivateResult(this.metaInfo.id, params);
else
this.provider.activateResult(this.metaInfo.id, this.terms);
this.icon = new IconGrid.BaseIcon(this.metaInfo['name'],
{ createIcon: this.metaInfo['createIcon'] });
let content = new St.Bin({ child: this.icon.actor });
this.actor.set_child(content);
this.actor.label_actor = this.icon.label;
}
});
@ -311,10 +160,16 @@ const SearchResultsBase = new Lang.Class({
this._terms = [];
},
_clearResultDisplay: function() {
_createResultDisplay: function(meta) {
if (this.provider.createResultObject)
return this.provider.createResultObject(meta);
return null;
},
clear: function() {
for (let resultId in this._resultDisplays)
this._resultDisplays[resultId].actor.destroy();
this._resultDisplays = {};
this._clearResultDisplay();
this.actor.hide();
@ -338,12 +193,22 @@ const SearchResultsBase = new Lang.Class({
}));
if (metasNeeded.length === 0) {
callback();
callback(true);
} else {
this._cancellable.cancel();
this._cancellable.reset();
this.provider.getResultMetas(metasNeeded, Lang.bind(this, function(metas) {
if (metas.length == 0) {
callback(false);
return;
}
if (metas.length != metasNeeded.length) {
log('Wrong number of result metas returned by search provider');
callback(false);
return;
}
metasNeeded.forEach(Lang.bind(this, function(resultId, i) {
let meta = metas[i];
let display = this._createResultDisplay(meta);
@ -351,7 +216,7 @@ const SearchResultsBase = new Lang.Class({
display.actor.connect('key-focus-in', Lang.bind(this, this._keyFocusIn));
this._resultDisplays[resultId] = display;
}));
callback();
callback(true);
}), this._cancellable);
}
},
@ -368,8 +233,11 @@ const SearchResultsBase = new Lang.Class({
let results = this.provider.filterResults(providerResults, maxResults);
let hasMoreResults = results.length < providerResults.length;
this._ensureResultActors(results, Lang.bind(this, function() {
this._clearResultDisplay();
this._ensureResultActors(results, Lang.bind(this, function(successful) {
if (!successful) {
this._clearResultDisplay();
return;
}
// To avoid CSS transitions causing flickering when
// the first search result stays the same, we hide the
@ -399,6 +267,7 @@ const ListSearchResults = new Lang.Class({
this.providerIcon.connect('key-focus-in', Lang.bind(this, this._keyFocusIn));
this.providerIcon.connect('clicked', Lang.bind(this,
function() {
this.providerIcon.animateLaunch();
provider.launchSearch(this._terms);
Main.overview.toggle();
}));
@ -416,7 +285,7 @@ const ListSearchResults = new Lang.Class({
},
_setMoreIconVisible: function(visible) {
this.providerIcon.moreIcon.visible = true;
this.providerIcon.moreIcon.visible = visible;
},
_getMaxDisplayedResults: function() {
@ -428,7 +297,7 @@ const ListSearchResults = new Lang.Class({
},
_createResultDisplay: function(meta) {
return new ListSearchResult(this.provider, meta);
return this.parent(meta) || new ListSearchResult(this.provider, meta);
},
_addItem: function(display) {
@ -448,8 +317,14 @@ const GridSearchResults = new Lang.Class({
Name: 'GridSearchResults',
Extends: SearchResultsBase,
_init: function(provider) {
_init: function(provider, parentContainer) {
this.parent(provider);
// We need to use the parent container to know how much results we can show.
// None of the actors in this class can be used for that, since the main actor
// goes hidden when no results are displayed, and then it lost its allocation.
// Then on the next use of _getMaxDisplayedResults allocation is 0, en therefore
// it doesn't show any result although we have some.
this._parentContainer = parentContainer;
this._grid = new IconGrid.IconGrid({ rowLimit: MAX_GRID_SEARCH_RESULTS_ROWS,
xAlign: St.Align.START });
@ -460,16 +335,9 @@ const GridSearchResults = new Lang.Class({
},
_getMaxDisplayedResults: function() {
return this._grid.columnsForWidth(this._bin.width) * this._grid.getRowLimit();
},
_renderResults: function(metas) {
for (let i = 0; i < metas.length; i++) {
let display = new GridSearchResult(this.provider, metas[i]);
display.connect('activate', Lang.bind(this, this._activateResult));
display.actor.connect('key-focus-in', Lang.bind(this, this._keyFocusIn));
this._grid.addItem(display);
}
let parentThemeNode = this._parentContainer.get_theme_node();
let availableWidth = parentThemeNode.adjust_for_width(this._parentContainer.width);
return this._grid.columnsForWidth(availableWidth) * this._grid.getRowLimit();
},
_clearResultDisplay: function () {
@ -477,7 +345,7 @@ const GridSearchResults = new Lang.Class({
},
_createResultDisplay: function(meta) {
return new GridSearchResult(this.provider, meta);
return this.parent(meta) || new GridSearchResult(this.provider, meta);
},
_addItem: function(display) {
@ -529,16 +397,120 @@ const SearchResults = new Lang.Class({
this._statusText = new St.Label({ style_class: 'search-statustext' });
this._statusBin = new St.Bin({ x_align: St.Align.MIDDLE,
y_align: St.Align.MIDDLE });
this._content.add(this._statusBin, { expand: true });
this.actor.add(this._statusBin, { expand: true });
this._statusBin.add_actor(this._statusText);
this._highlightDefault = false;
this._defaultResult = null;
this._startingSearch = false;
this._searchSystem = new SearchSystem();
this._searchSystem.connect('search-updated', Lang.bind(this, this._updateResults));
this._searchSystem.connect('providers-changed', Lang.bind(this, this._updateProviderDisplays));
this._updateProviderDisplays();
this._terms = [];
this._results = {};
this._providers = [];
this._searchSettings = new Gio.Settings({ schema_id: SEARCH_PROVIDERS_SCHEMA });
this._searchSettings.connect('changed::disabled', Lang.bind(this, this._reloadRemoteProviders));
this._searchSettings.connect('changed::disable-external', Lang.bind(this, this._reloadRemoteProviders));
this._searchSettings.connect('changed::sort-order', Lang.bind(this, this._reloadRemoteProviders));
this._searchTimeoutId = 0;
this._cancellable = new Gio.Cancellable();
this._registerProvider(new AppDisplay.AppSearchProvider());
this._reloadRemoteProviders();
},
_reloadRemoteProviders: function() {
let remoteProviders = this._providers.filter(function(provider) {
return provider.isRemoteProvider;
});
remoteProviders.forEach(Lang.bind(this, function(provider) {
this._unregisterProvider(provider);
}));
RemoteSearch.loadRemoteSearchProviders(Lang.bind(this, function(providers) {
providers.forEach(Lang.bind(this, this._registerProvider));
}));
},
_registerProvider: function (provider) {
this._providers.push(provider);
this._ensureProviderDisplay(provider);
},
_unregisterProvider: function (provider) {
let index = this._providers.indexOf(provider);
this._providers.splice(index, 1);
if (provider.display)
provider.display.destroy();
},
_gotResults: function(results, provider) {
this._results[provider.id] = results;
this._updateResults(provider, results);
},
_doSearch: function() {
this._startingSearch = false;
let previousResults = this._results;
this._results = {};
this._providers.forEach(Lang.bind(this, function(provider) {
provider.searchInProgress = true;
let previousProviderResults = previousResults[provider.id];
if (this._isSubSearch && previousProviderResults)
provider.getSubsearchResultSet(previousProviderResults, this._terms, Lang.bind(this, this._gotResults, provider), this._cancellable);
else
provider.getInitialResultSet(this._terms, Lang.bind(this, this._gotResults, provider), this._cancellable);
}));
this._updateSearchProgress();
if (this._searchTimeoutId > 0) {
GLib.source_remove(this._searchTimeoutId);
this._searchTimeoutId = 0;
}
},
_onSearchTimeout: function() {
this._searchTimeoutId = 0;
this._doSearch();
return GLib.SOURCE_REMOVE;
},
setTerms: function(terms) {
this._startingSearch = true;
this._cancellable.cancel();
this._cancellable.reset();
if (!terms) {
if (this._searchTimeoutId > 0) {
GLib.source_remove(this._searchTimeoutId);
this._searchTimeoutId = 0;
}
return;
}
let searchString = terms.join(' ');
let previousSearchString = this._terms.join(' ');
if (searchString == previousSearchString)
return;
let isSubSearch = false;
if (this._terms.length > 0)
isSubSearch = searchString.indexOf(previousSearchString) == 0;
this._terms = terms;
this._isSubSearch = isSubSearch;
this._updateSearchProgress();
if (this._searchTimeoutId == 0)
this._searchTimeoutId = GLib.timeout_add(GLib.PRIORITY_DEFAULT, 150, Lang.bind(this, this._onSearchTimeout));
},
_onPan: function(action) {
@ -560,44 +532,23 @@ const SearchResults = new Lang.Class({
if (provider.appInfo)
providerDisplay = new ListSearchResults(provider);
else
providerDisplay = new GridSearchResults(provider);
providerDisplay = new GridSearchResults(provider, this.actor);
providerDisplay.connect('key-focus-in', Lang.bind(this, this._keyFocusIn));
this._content.add(providerDisplay.actor);
provider.display = providerDisplay;
},
_updateProviderDisplays: function() {
this._searchSystem.getProviders().forEach(Lang.bind(this, this._ensureProviderDisplay));
},
_clearDisplay: function() {
this._searchSystem.getProviders().forEach(function(provider) {
this._providers.forEach(function(provider) {
provider.display.clear();
});
},
reset: function() {
this._searchSystem.reset();
this._statusBin.hide();
this._clearDisplay();
this._defaultResult = null;
},
startingSearch: function() {
this.reset();
this._statusText.set_text(_("Searching…"));
this._statusBin.show();
},
setTerms: function(terms) {
this._searchSystem.setTerms(terms);
},
_maybeSetInitialSelection: function() {
let newDefaultResult = null;
let providers = this._searchSystem.getProviders();
let providers = this._providers;
for (let i = 0; i < providers.length; i++) {
let provider = providers[i];
let display = provider.display;
@ -613,48 +564,64 @@ const SearchResults = new Lang.Class({
}
if (newDefaultResult != this._defaultResult) {
if (this._defaultResult)
this._defaultResult.setSelected(false);
if (newDefaultResult)
newDefaultResult.setSelected(this._highlightDefault);
this._setSelected(this._defaultResult, false);
this._setSelected(newDefaultResult, this._highlightDefault);
this._defaultResult = newDefaultResult;
}
},
_updateStatusText: function () {
let haveResults = this._searchSystem.getProviders().some(function(provider) {
get searchInProgress() {
if (this._startingSearch)
return true;
return this._providers.some(function(provider) {
return provider.searchInProgress;
});
},
_updateSearchProgress: function () {
let haveResults = this._providers.some(function(provider) {
let display = provider.display;
return (display.getFirstResult() != null);
});
this._scrollView.visible = haveResults;
this._statusBin.visible = !haveResults;
if (!haveResults) {
this._statusText.set_text(_("No results."));
this._statusBin.show();
} else {
this._statusBin.hide();
if (this.searchInProgress) {
this._statusText.set_text(_("Searching…"));
} else {
this._statusText.set_text(_("No results."));
}
}
},
_updateResults: function(searchSystem, provider, results) {
let terms = searchSystem.getTerms();
_updateResults: function(provider, results) {
let terms = this._terms;
let display = provider.display;
display.updateSearch(results, terms, Lang.bind(this, function() {
provider.searchInProgress = false;
this._maybeSetInitialSelection();
this._updateStatusText();
this._updateSearchProgress();
}));
},
activateDefault: function() {
// If we have a search queued up, force the search now.
if (this._searchTimeoutId > 0)
this._doSearch();
if (this._defaultResult)
this._defaultResult.activate();
},
highlightDefault: function(highlight) {
this._highlightDefault = highlight;
if (this._defaultResult)
this._defaultResult.setSelected(highlight);
this._setSelected(this._defaultResult, highlight);
},
navigateFocus: function(direction) {
@ -669,6 +636,18 @@ const SearchResults = new Lang.Class({
let from = this._defaultResult ? this._defaultResult.actor : null;
this.actor.navigate_focus(from, direction, false);
},
_setSelected: function(result, selected) {
if (!result)
return;
if (selected) {
result.actor.add_style_pseudo_class('selected');
Util.ensureActorVisibleInScrollView(this._scrollView, result.actor);
} else {
result.actor.remove_style_pseudo_class('selected');
}
}
});
@ -702,5 +681,12 @@ const ProviderIcon = new Lang.Class({
gicon: provider.appInfo.get_icon() });
this._content.add_actor(icon);
this._content.add_actor(this.moreIcon);
},
animateLaunch: function() {
let appSys = Shell.AppSystem.get_default();
let app = appSys.lookup_app(this.provider.appInfo.get_id());
if (app.state == Shell.AppState.STOPPED)
IconGrid.zoomOutActor(this._content);
}
});

View File

@ -10,13 +10,14 @@ const FileUtils = imports.misc.fileUtils;
const Main = imports.ui.main;
const Params = imports.misc.params;
const Config = imports.misc.config;
const DEFAULT_MODE = 'restrictive';
const _modes = {
'restrictive': {
parentMode: null,
stylesheetName: 'gnome-shell.css',
overridesSchema: 'org.gnome.shell.overrides',
hasOverview: false,
showCalendarEvents: false,
allowSettings: false,
@ -92,8 +93,12 @@ const _modes = {
isLocked: false,
isPrimary: true,
unlockDialog: imports.ui.unlockDialog.UnlockDialog,
components: ['networkAgent', 'polkitAgent', 'telepathyClient',
components: Config.HAVE_NETWORKMANAGER ?
['networkAgent', 'polkitAgent', 'telepathyClient',
'keyring', 'autorunManager', 'automountManager'] :
['polkitAgent', 'telepathyClient',
'keyring', 'autorunManager', 'automountManager'],
panel: {
left: ['activities', 'appMenu'],
center: ['dateMenu'],
@ -134,13 +139,14 @@ function _loadModes() {
function listModes() {
_loadModes();
Mainloop.idle_add(function() {
let id = Mainloop.idle_add(function() {
let names = Object.getOwnPropertyNames(_modes);
for (let i = 0; i < names.length; i++)
if (_modes[names[i]].isPrimary)
print(names[i]);
Mainloop.quit('listModes');
});
GLib.Source.set_name_by_id(id, '[gnome-shell] listModes');
Mainloop.run('listModes');
}

View File

@ -69,6 +69,7 @@ const ScreenSaverIface = '<node> \
<signal name="ActiveChanged"> \
<arg name="new_value" type="b" /> \
</signal> \
<signal name="WakeUpScreen" /> \
</interface> \
</node>';
@ -140,12 +141,7 @@ const GnomeShell = new Lang.Class({
if (params['icon'])
icon = Gio.Icon.new_for_string(params['icon']);
Main.osdWindow.setIcon(icon);
Main.osdWindow.setMonitor (monitorIndex);
Main.osdWindow.setLabel(params['label']);
Main.osdWindow.setLevel(params['level']);
Main.osdWindow.show();
Main.osdWindowManager.show(monitorIndex, icon, params['label'], params['level']);
},
FocusApp: function(id) {
@ -371,8 +367,10 @@ const GnomeShellExtensions = new Lang.Class({
LaunchExtensionPrefs: function(uuid) {
let appSys = Shell.AppSystem.get_default();
let app = appSys.lookup_app('gnome-shell-extension-prefs.desktop');
app.launch(global.display.get_current_time_roundtrip(),
['extension:///' + uuid], -1, null);
let info = app.get_app_info();
let timestamp = global.display.get_current_time_roundtrip();
info.launch_uris(['extension:///' + uuid],
global.create_app_launch_context(timestamp, -1));
},
ReloadExtension: function(uuid) {
@ -405,6 +403,9 @@ const ScreenSaverDBus = new Lang.Class({
screenShield.connect('active-changed', Lang.bind(this, function(shield) {
this._dbusImpl.emit_signal('ActiveChanged', GLib.Variant.new('(b)', [shield.active]));
}));
screenShield.connect('wake-up-screen', Lang.bind(this, function(shield) {
this._dbusImpl.emit_signal('WakeUpScreen', null);
}));
this._dbusImpl = Gio.DBusExportedObject.wrapJSObject(ScreenSaverIface, this);
this._dbusImpl.export(Gio.DBus.session, '/org/gnome/ScreenSaver');

View File

@ -17,8 +17,6 @@ const EntryMenu = new Lang.Class({
_init: function(entry) {
this.parent(entry, 0, St.Side.TOP);
this.actor.add_style_class_name('entry-context-menu');
this._entry = entry;
this._clipboard = St.Clipboard.get_default();

View File

@ -1,11 +1,11 @@
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
const Atk = imports.gi.Atk;
const Cairo = imports.cairo;
const Clutter = imports.gi.Clutter;
const Lang = imports.lang;
const St = imports.gi.St;
const Signals = imports.signals;
const Atk = imports.gi.Atk;
const SLIDER_SCROLL_STEP = 0.05; /* Slider scrolling step in % */
@ -24,6 +24,7 @@ const Slider = new Lang.Class({
accessible_role: Atk.Role.SLIDER });
this.actor.connect('repaint', Lang.bind(this, this._sliderRepaint));
this.actor.connect('button-press-event', Lang.bind(this, this._startDragging));
this.actor.connect('touch-event', Lang.bind(this, this._touchDragging));
this.actor.connect('scroll-event', Lang.bind(this, this._onScrollEvent));
this.actor.connect('key-press-event', Lang.bind(this, this.onKeyPressEvent));
@ -121,11 +122,21 @@ const Slider = new Lang.Class({
this._dragging = true;
let device = event.get_device();
device.grab(this.actor);
this._grabbedDevice = device;
let sequence = event.get_event_sequence();
if (sequence != null)
device.sequence_grab(sequence, this.actor);
else
device.grab(this.actor);
this._grabbedDevice = device;
this._grabbedSequence = sequence;
if (sequence == null) {
this._releaseId = this.actor.connect('button-release-event', Lang.bind(this, this._endDragging));
this._motionId = this.actor.connect('motion-event', Lang.bind(this, this._motionEvent));
}
this._releaseId = this.actor.connect('button-release-event', Lang.bind(this, this._endDragging));
this._motionId = this.actor.connect('motion-event', Lang.bind(this, this._motionEvent));
let absX, absY;
[absX, absY] = event.get_coords();
this._moveHandle(absX, absY);
@ -134,10 +145,17 @@ const Slider = new Lang.Class({
_endDragging: function() {
if (this._dragging) {
this.actor.disconnect(this._releaseId);
this.actor.disconnect(this._motionId);
if (this._releaseId)
this.actor.disconnect(this._releaseId);
if (this._motionId)
this.actor.disconnect(this._motionId);
this._grabbedDevice.ungrab();
if (this._grabbedSequence != null)
this._grabbedDevice.sequence_ungrab(this._grabbedSequence);
else
this._grabbedDevice.ungrab();
this._grabbedSequence = null;
this._grabbedDevice = null;
this._dragging = false;
@ -146,6 +164,24 @@ const Slider = new Lang.Class({
return Clutter.EVENT_STOP;
},
_touchDragging: function(actor, event) {
let device = event.get_device();
let sequence = event.get_event_sequence();
if (!this._dragging &&
event.type() == Clutter.EventType.TOUCH_BEGIN) {
this.startDragging(event);
return Clutter.EVENT_STOP;
} else if (device.sequence_get_grabbed_actor(sequence) == actor) {
if (event.type() == Clutter.EventType.TOUCH_UPDATE)
return this._motionEvent(actor, event);
else if (event.type() == Clutter.EventType.TOUCH_END)
return this._endDragging();
}
return Clutter.EVENT_PROPAGATE;
},
scroll: function(event) {
let direction = event.get_scroll_direction();
let delta;

View File

@ -44,11 +44,11 @@ const ATIndicator = new Lang.Class({
this._hbox = new St.BoxLayout({ style_class: 'panel-status-menu-box' });
this._hbox.add_child(new St.Icon({ style_class: 'system-status-icon',
icon_name: 'preferences-desktop-accessibility-symbolic' }));
this._hbox.add_child(PopupMenu.unicodeArrow(St.Side.BOTTOM));
this._hbox.add_child(PopupMenu.arrowIcon(St.Side.BOTTOM));
this.actor.add_child(this._hbox);
this._a11ySettings = new Gio.Settings({ schema: A11Y_SCHEMA });
this._a11ySettings = new Gio.Settings({ schema_id: A11Y_SCHEMA });
this._a11ySettings.connect('changed::' + KEY_ALWAYS_SHOW, Lang.bind(this, this._queueSyncMenuVisibility));
let highContrast = this._buildHCItem();
@ -103,6 +103,7 @@ const ATIndicator = new Lang.Class({
return;
this._syncMenuVisbilityIdle = Mainloop.idle_add(Lang.bind(this, this._syncMenuVisibility));
GLib.Source.set_name_by_id(this._syncMenuVisbilityIdle, '[gnome-shell] this._syncMenuVisibility');
},
_buildItemExtended: function(string, initial_value, writable, on_set) {
@ -117,7 +118,7 @@ const ATIndicator = new Lang.Class({
},
_buildItem: function(string, schema, key) {
let settings = new Gio.Settings({ schema: schema });
let settings = new Gio.Settings({ schema_id: schema });
let widget = this._buildItemExtended(string,
settings.get_boolean(key),
settings.is_writable(key),
@ -133,8 +134,8 @@ const ATIndicator = new Lang.Class({
},
_buildHCItem: function() {
let interfaceSettings = new Gio.Settings({ schema: DESKTOP_INTERFACE_SCHEMA });
let wmSettings = new Gio.Settings({ schema: WM_SCHEMA });
let interfaceSettings = new Gio.Settings({ schema_id: DESKTOP_INTERFACE_SCHEMA });
let wmSettings = new Gio.Settings({ schema_id: WM_SCHEMA });
let gtkTheme = interfaceSettings.get_string(KEY_GTK_THEME);
let iconTheme = interfaceSettings.get_string(KEY_ICON_THEME);
let wmTheme = wmSettings.get_string(KEY_WM_THEME);
@ -185,7 +186,7 @@ const ATIndicator = new Lang.Class({
},
_buildFontItem: function() {
let settings = new Gio.Settings({ schema: DESKTOP_INTERFACE_SCHEMA });
let settings = new Gio.Settings({ schema_id: DESKTOP_INTERFACE_SCHEMA });
let factor = settings.get_double(KEY_TEXT_SCALING_FACTOR);
let initial_setting = (factor > 1.0);

View File

@ -17,6 +17,7 @@ const OBJECT_PATH = '/org/gnome/SettingsDaemon/Rfkill';
const RfkillManagerInterface = '<node> \
<interface name="org.gnome.SettingsDaemon.Rfkill"> \
<property name="BluetoothAirplaneMode" type="b" access="readwrite" /> \
<property name="BluetoothHasAirplaneMode" type="b" access="read" /> \
</interface> \
</node>';
@ -38,7 +39,10 @@ const Indicator = new Lang.Class({
log(error.message);
return;
}
this._sync();
}));
this._proxy.connect('g-properties-changed', Lang.bind(this, this._sync));
// The Bluetooth menu only appears when Bluetooth is in use,
// so just statically build it with a "Turn Off" menu item.
@ -55,6 +59,7 @@ const Indicator = new Lang.Class({
this._model.connect('row-changed', Lang.bind(this, this._sync));
this._model.connect('row-deleted', Lang.bind(this, this._sync));
this._model.connect('row-inserted', Lang.bind(this, this._sync));
Main.sessionMode.connect('updated', Lang.bind(this, this._sync));
this._sync();
},
@ -89,12 +94,15 @@ const Indicator = new Lang.Class({
_sync: function() {
let nDevices = this._getNConnectedDevices();
let sensitive = !Main.sessionMode.isLocked && !Main.sessionMode.isGreeter;
let on = nDevices > 0;
this._indicator.visible = on;
this._item.actor.visible = on;
this.menu.setSensitive(sensitive);
this._indicator.visible = nDevices > 0;
this._item.actor.visible = this._proxy.BluetoothHasAirplaneMode && !this._proxy.BluetoothAirplaneMode;
if (on)
if (nDevices > 0)
this._item.status.text = ngettext("%d Connected Device", "%d Connected Devices", nDevices).format(nDevices);
else
this._item.status.text = _("Not Connected");
},
});

File diff suppressed because it is too large Load Diff

View File

@ -1,18 +1,51 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
const GLib = imports.gi.GLib;
const Gio = imports.gi.Gio;
const Lang = imports.lang;
const Main = imports.ui.main;
const PanelMenu = imports.ui.panelMenu;
const PopupMenu = imports.ui.popupMenu;
const Shell = imports.gi.Shell;
const LOCATION_SCHEMA = 'org.gnome.system.location';
const MAX_ACCURACY_LEVEL = 'max-accuracy-level';
const ENABLED = 'enabled';
const GeoclueAccuracyLevel = {
NONE: 0,
COUNTRY: 1,
CITY: 4,
NEIGHBORHOOD: 5,
STREET: 6,
EXACT: 8
};
var GeoclueIface = '<node> \
<interface name="org.freedesktop.GeoClue2.Manager"> \
<property name="InUse" type="b" access="read"/> \
<property name="AvailableAccuracyLevel" type="u" access="read"/> \
<method name="AddAgent"> \
<arg name="id" type="s" direction="in"/> \
</method> \
</interface> \
</node>';
const GeoclueManager = Gio.DBusProxy.makeProxyWrapper(GeoclueIface);
var AgentIface = '<node> \
<interface name="org.freedesktop.GeoClue2.Agent"> \
<property name="MaxAccuracyLevel" type="u" access="read"/> \
<method name="AuthorizeApp"> \
<arg name="desktop_id" type="s" direction="in"/> \
<arg name="req_accuracy_level" type="u" direction="in"/> \
<arg name="authorized" type="b" direction="out"/> \
<arg name="allowed_accuracy_level" type="u" direction="out"/> \
</method> \
</interface> \
</node>';
const Indicator = new Lang.Class({
Name: 'LocationIndicator',
Extends: PanelMenu.SystemIndicator,
@ -20,39 +53,166 @@ const Indicator = new Lang.Class({
_init: function() {
this.parent();
this._settings = new Gio.Settings({ schema_id: LOCATION_SCHEMA });
this._settings.connect('changed::' + ENABLED,
Lang.bind(this, this._onMaxAccuracyLevelChanged));
this._settings.connect('changed::' + MAX_ACCURACY_LEVEL,
Lang.bind(this, this._onMaxAccuracyLevelChanged));
this._indicator = this._addIndicator();
this._indicator.icon_name = 'find-location-symbolic';
this._sync();
this._item = new PopupMenu.PopupSubMenuMenuItem(_("Location"), true);
this._item.icon.icon_name = 'find-location-symbolic';
this._agent = Gio.DBusExportedObject.wrapJSObject(AgentIface, this);
this._agent.export(Gio.DBus.system, '/org/freedesktop/GeoClue2/Agent');
this._item.status.text = _("Enabled");
this._onOffAction = this._item.menu.addAction(_("Disable"), Lang.bind(this, this._onOnOffAction));
this._item.menu.addSettingsAction(_("Privacy Settings"), 'gnome-privacy-panel.desktop');
this.menu.addMenuItem(this._item);
this._watchId = Gio.bus_watch_name(Gio.BusType.SYSTEM,
'org.freedesktop.GeoClue2',
0,
Lang.bind(this, this._onGeoclueAppeared),
Lang.bind(this, this._connectToGeoclue),
Lang.bind(this, this._onGeoclueVanished));
Main.sessionMode.connect('updated', Lang.bind(this, this._onSessionUpdated));
this._onSessionUpdated();
this._onMaxAccuracyLevelChanged();
this._connectToGeoclue();
},
_sync: function() {
get MaxAccuracyLevel() {
return this._getMaxAccuracyLevel();
},
// We (and geoclue) have currently no way to reliably identifying apps so
// for now, lets just authorize all apps as long as they provide a valid
// desktop ID. We also ensure they don't get more accuracy than global max.
AuthorizeApp: function(desktop_id, reqAccuracyLevel) {
var appSystem = Shell.AppSystem.get_default();
var app = appSystem.lookup_app(desktop_id + ".desktop");
if (app == null) {
return [false, 0];
}
let allowedAccuracyLevel = clamp(reqAccuracyLevel, 0, this._getMaxAccuracyLevel());
return [true, allowedAccuracyLevel];
},
_syncIndicator: function() {
if (this._proxy == null) {
this._indicator.visible = false;
this._item.actor.visible = false;
return;
}
this._indicator.visible = this._proxy.InUse;
this._item.actor.visible = this._indicator.visible;
this._updateMenuLabels();
},
_onGeoclueAppeared: function() {
// FIXME: This should be done async
this._proxy = new GeoclueManager(Gio.DBus.system,
'org.freedesktop.GeoClue2',
'/org/freedesktop/GeoClue2/Manager');
this._proxy.connect('g-properties-changed', Lang.bind(this, this._sync));
_connectToGeoclue: function() {
if (this._proxy != null || this._connecting)
return false;
this._sync();
this._connecting = true;
new GeoclueManager(Gio.DBus.system,
'org.freedesktop.GeoClue2',
'/org/freedesktop/GeoClue2/Manager',
Lang.bind(this, this._onProxyReady));
return true;
},
_onProxyReady: function(proxy, error) {
if (error != null) {
log(error.message);
this._connecting = false;
return;
}
this._proxy = proxy;
this._propertiesChangedId = this._proxy.connect('g-properties-changed',
Lang.bind(this, this._onGeocluePropsChanged));
this._syncIndicator();
this._proxy.AddAgentRemote('gnome-shell', Lang.bind(this, this._onAgentRegistered));
},
_onAgentRegistered: function(result, error) {
this._connecting = false;
this._notifyMaxAccuracyLevel();
if (error != null)
log(error.message);
},
_onGeoclueVanished: function() {
if (this._propertiesChangedId) {
this._proxy.disconnect(this._propertiesChangedId);
this._propertiesChangedId = 0;
}
this._proxy = null;
this._sync();
this._syncIndicator();
},
_onOnOffAction: function() {
let enabled = this._settings.get_boolean(ENABLED);
this._settings.set_boolean(ENABLED, !enabled);
},
_onSessionUpdated: function() {
let sensitive = !Main.sessionMode.isLocked && !Main.sessionMode.isGreeter;
this.menu.setSensitive(sensitive);
},
_updateMenuLabels: function() {
if (this._settings.get_boolean(ENABLED)) {
this._item.status.text = this._indicator.visible ? _("In Use") : _("Enabled");
this._onOffAction.label.text = _("Disable");
} else {
this._item.status.text = _("Disabled");
this._onOffAction.label.text = _("Enable");
}
},
_onMaxAccuracyLevelChanged: function() {
this._updateMenuLabels();
// Gotta ensure geoclue is up and we are registered as agent to it
// before we emit the notify for this property change.
if (!this._connectToGeoclue())
this._notifyMaxAccuracyLevel();
},
_getMaxAccuracyLevel: function() {
if (this._settings.get_boolean(ENABLED)) {
let level = this._settings.get_string(MAX_ACCURACY_LEVEL);
return GeoclueAccuracyLevel[level.toUpperCase()] ||
GeoclueAccuracyLevel.NONE;
} else {
return GeoclueAccuracyLevel.NONE;
}
},
_notifyMaxAccuracyLevel: function() {
let variant = new GLib.Variant('u', this._getMaxAccuracyLevel());
this._agent.emit_property_changed('MaxAccuracyLevel', variant);
},
_onGeocluePropsChanged: function(proxy, properties) {
let unpacked = properties.deep_unpack();
if ("InUse" in unpacked)
this._syncIndicator();
}
});
function clamp(value, min, max) {
return Math.max(min, Math.min(max, value));
}

View File

@ -9,14 +9,17 @@ const NetworkManager = imports.gi.NetworkManager;
const NMClient = imports.gi.NMClient;
const NMGtk = imports.gi.NMGtk;
const Signals = imports.signals;
const Shell = imports.gi.Shell;
const St = imports.gi.St;
const Animation = imports.ui.animation;
const Main = imports.ui.main;
const PanelMenu = imports.ui.panelMenu;
const PopupMenu = imports.ui.popupMenu;
const MessageTray = imports.ui.messageTray;
const ModalDialog = imports.ui.modalDialog;
const ModemManager = imports.misc.modemManager;
const Rfkill = imports.ui.status.rfkill;
const Util = imports.misc.util;
const NMConnectionCategory = {
@ -41,6 +44,33 @@ const NM80211Mode = NetworkManager['80211Mode'];
const NM80211ApFlags = NetworkManager['80211ApFlags'];
const NM80211ApSecurityFlags = NetworkManager['80211ApSecurityFlags'];
const PortalHelperResult = {
CANCELLED: 0,
COMPLETED: 1,
RECHECK: 2
};
const PortalHelperIface = '<node> \
<interface name="org.gnome.Shell.PortalHelper"> \
<method name="Authenticate"> \
<arg type="o" direction="in" name="connection" /> \
<arg type="s" direction="in" name="url" /> \
<arg type="u" direction="in" name="timestamp" /> \
</method> \
<method name="Close"> \
<arg type="o" direction="in" name="connection" /> \
</method> \
<method name="Refresh"> \
<arg type="o" direction="in" name="connection" /> \
</method> \
<signal name="Done"> \
<arg type="o" name="connection" /> \
<arg type="u" name="result" /> \
</signal> \
</interface> \
</node>';
const PortalHelperProxy = Gio.DBusProxy.makeProxyWrapper(PortalHelperIface);
function ssidCompare(one, two) {
if (!one || !two)
return false;
@ -102,18 +132,34 @@ const NMConnectionItem = new Lang.Class({
this._activeConnection = null;
this._activeConnectionChangedId = 0;
this._buildUI();
this._sync();
},
_buildUI: function() {
this.labelItem = new PopupMenu.PopupMenuItem('');
this.labelItem.connect('activate', Lang.bind(this, this._toggle));
this.switchItem = new PopupMenu.PopupSwitchMenuItem(connection.get_id(), false);
this.switchItem.connect('toggled', Lang.bind(this, this._toggle));
this._sync();
this.radioItem = new PopupMenu.PopupMenuItem(this._connection.get_id(), false);
this.radioItem.connect('activate', Lang.bind(this, this._activate));
},
destroy: function() {
this.labelItem.destroy();
this.switchItem.destroy();
this.radioItem.destroy();
},
updateForConnection: function(connection) {
// connection should always be the same object
// (and object path) as this._connection, but
// this can be false if NetworkManager was restarted
// and picked up connections in a different order
// Just to be safe, we set it here again
this._connection = connection;
this.radioItem.label.text = connection.get_id();
this._sync();
this.emit('name-changed');
},
getName: function() {
@ -129,9 +175,8 @@ const NMConnectionItem = new Lang.Class({
_sync: function() {
let isActive = this.isActive();
this.labelItem.label.text = isActive ? _("Turn Off") : _("Connect");
this.switchItem.setToggleState(isActive);
this.switchItem.setStatus(this._getStatus());
this.labelItem.label.text = isActive ? _("Turn Off") : this._section.getConnectLabel();
this.radioItem.setOrnament(isActive ? PopupMenu.Ornament.DOT : PopupMenu.Ornament.NONE);
this.emit('icon-changed');
},
@ -144,8 +189,11 @@ const NMConnectionItem = new Lang.Class({
this._sync();
},
_getStatus: function() {
return null;
_activate: function() {
if (this._activeConnection == null)
this._section.activateConnection(this._connection);
this._sync();
},
_connectionStateChanged: function(ac, newstate, reason) {
@ -180,23 +228,33 @@ const NMConnectionSection = new Lang.Class({
this._connections = [];
this._labelSection = new PopupMenu.PopupMenuSection();
this._switchSection = new PopupMenu.PopupMenuSection();
this._radioSection = new PopupMenu.PopupMenuSection();
this.item = new PopupMenu.PopupSubMenuMenuItem('', true);
this.item.menu.addMenuItem(this._labelSection);
this.item.menu.addMenuItem(this._switchSection);
this.item.menu.addMenuItem(this._radioSection);
this.connect('icon-changed', Lang.bind(this, this._sync));
this._notifyConnectivityId = this._client.connect('notify::connectivity', Lang.bind(this, this._iconChanged));
},
destroy: function() {
if (this._notifyConnectivityId != 0) {
this._client.disconnect(this._notifyConnectivityId);
this._notifyConnectivityId = 0;
}
this.item.destroy();
},
_iconChanged: function() {
this._sync();
this.emit('icon-changed');
},
_sync: function() {
let nItems = this._connectionItems.size;
this._switchSection.actor.visible = (nItems > 1);
this._radioSection.actor.visible = (nItems > 1);
this._labelSection.actor.visible = (nItems == 1);
this.item.status.text = this._getStatus();
@ -211,18 +269,12 @@ const NMConnectionSection = new Lang.Class({
this.item.label.text = '';
},
_getStatus: function() {
let values = this._connectionItems.values();
for (let item of values) {
if (item.isActive())
return item.getName();
}
return _("Off");
_getMenuIcon: function() {
return this.getIndicatorIcon();
},
_hasConnection: function(connection) {
return this._connectionItems.has(connection.get_uuid());
getConnectLabel: function() {
return _("Connect");
},
_connectionValid: function(connection) {
@ -230,10 +282,7 @@ const NMConnectionSection = new Lang.Class({
},
_connectionSortFunction: function(one, two) {
if (one._timestamp == two._timestamp)
return GLib.utf8_collate(one.get_id(), two.get_id());
return two._timestamp - one._timestamp;
return GLib.utf8_collate(one.get_id(), two.get_id());
},
_makeConnectionItem: function(connection) {
@ -244,10 +293,20 @@ const NMConnectionSection = new Lang.Class({
if (!this._connectionValid(connection))
return;
if (this._hasConnection(connection))
return;
// This function is called everytime connection is added or updated
// In the usual case, we already added this connection and UUID
// didn't change. So we need to check if we already have an item,
// and update it for properties in the connection that changed
// (the only one we care about is the name)
// But it's also possible we didn't know about this connection
// (eg, during coldplug, or because it was updated and suddenly
// it's valid for this device), in which case we add a new item
this._addConnection(connection);
let item = this._connectionItems.get(connection.get_uuid());
if (item)
item.updateForConnection(connection);
else
this._addConnection(connection);
},
_addConnection: function(connection) {
@ -256,22 +315,28 @@ const NMConnectionSection = new Lang.Class({
return;
item.connect('icon-changed', Lang.bind(this, function() {
this.emit('icon-changed');
this._iconChanged();
}));
item.connect('activation-failed', Lang.bind(this, function(item, reason) {
this.emit('activation-failed', reason);
}));
item.connect('name-changed', Lang.bind(this, this._sync));
let pos = Util.insertSorted(this._connections, connection, Lang.bind(this, this._connectionSortFunction));
this._labelSection.addMenuItem(item.labelItem, pos);
this._switchSection.addMenuItem(item.switchItem, pos);
this._radioSection.addMenuItem(item.radioItem, pos);
this._connectionItems.set(connection.get_uuid(), item);
this._sync();
},
removeConnection: function(connection) {
this._connectionItems.get(connection.get_uuid()).destroy();
this._connectionItems.delete(connection.get_uuid());
let uuid = connection.get_uuid();
let item = this._connectionItems.get(uuid);
if (item == undefined)
return;
item.destroy();
this._connectionItems.delete(uuid);
let pos = this._connections.indexOf(connection);
this._connections.splice(pos, 1);
@ -292,11 +357,19 @@ const NMConnectionDevice = new Lang.Class({
this._settings = settings;
this._autoConnectItem = this.item.menu.addAction(_("Connect"), Lang.bind(this, this._autoConnect));
this._deactivateItem = this._radioSection.addAction(_("Turn Off"), Lang.bind(this, this.deactivateConnection));
this._stateChangedId = this._device.connect('state-changed', Lang.bind(this, this._deviceStateChanged));
this._activeConnectionChangedId = this._device.connect('notify::active-connection', Lang.bind(this, this._activeConnectionChanged));
},
_canReachInternet: function() {
if (this._client.primary_connection != this._device.active_connection)
return true;
return this._client.connectivity == NetworkManager.ConnectivityState.FULL;
},
_autoConnect: function() {
let connection = new NetworkManager.Connection();
this._client.add_and_activate_connection(connection, this._device, null, null);
@ -371,6 +444,7 @@ const NMConnectionDevice = new Lang.Class({
_sync: function() {
let nItems = this._connectionItems.size;
this._autoConnectItem.actor.visible = (nItems == 0);
this._deactivateItem.actor.visible = this._device.state > NetworkManager.DeviceState.DISCONNECTED;
this.parent();
},
@ -382,22 +456,22 @@ const NMConnectionDevice = new Lang.Class({
case NetworkManager.DeviceState.DISCONNECTED:
return _("Off");
case NetworkManager.DeviceState.ACTIVATED:
return this.parent();
return _("Connected");
case NetworkManager.DeviceState.UNMANAGED:
/* Translators: this is for network devices that are physically present but are not
under NetworkManager's control (and thus cannot be used in the menu) */
return _("unmanaged");
return _("Unmanaged");
case NetworkManager.DeviceState.DEACTIVATING:
return _("disconnecting...");
return _("Disconnecting");
case NetworkManager.DeviceState.PREPARE:
case NetworkManager.DeviceState.CONFIG:
case NetworkManager.DeviceState.IP_CONFIG:
case NetworkManager.DeviceState.IP_CHECK:
case NetworkManager.DeviceState.SECONDARIES:
return _("connecting...");
return _("Connecting");
case NetworkManager.DeviceState.NEED_AUTH:
/* Translators: this is for network connections that require some kind of key or password */
return _("authentication required");
return _("Authentication required");
case NetworkManager.DeviceState.UNAVAILABLE:
// This state is actually a compound of various states (generically unavailable,
// firmware missing), that are exposed by different properties (whose state may
@ -405,13 +479,13 @@ const NMConnectionDevice = new Lang.Class({
if (this._device.firmware_missing) {
/* Translators: this is for devices that require some kind of firmware or kernel
module, which is missing */
return _("firmware missing");
return _("Firmware missing");
}
/* Translators: this is for a network device that cannot be activated (for example it
is disabled by rfkill, or it has no coverage */
return _("unavailable");
return _("Unavailable");
case NetworkManager.DeviceState.FAILED:
return _("connection failed");
return _("Connection failed");
default:
log('Device state invalid, is %d'.format(this._device.state));
return 'invalid';
@ -430,33 +504,33 @@ const NMDeviceWired = new Lang.Class({
this.item.menu.addMenuItem(createSettingsAction(_("Wired Settings"), device));
},
_isConnected: function() {
if (!this._device.active_connection)
return false;
let state = this._device.active_connection.state;
return state >= NetworkManager.ActiveConnectionState.ACTIVATING;
_hasCarrier: function() {
if (this._device instanceof NMClient.DeviceEthernet)
return this._device.carrier;
else
return true;
},
_sync: function() {
this.item.actor.visible = this._isConnected();
this.item.actor.visible = this._hasCarrier();
this.parent();
},
_getMenuIcon: function() {
if (this._device.active_connection)
return this.getIndicatorIcon();
else
return 'network-wired-disconnected-symbolic';
},
getIndicatorIcon: function() {
let state = this._device.active_connection.state;
if (state == NetworkManager.ActiveConnectionState.ACTIVATING)
return 'network-wired-acquiring-symbolic';
else if (state == NetworkManager.ActiveConnectionState.ACTIVATED)
return 'network-wired-symbolic';
else
if (this._device.active_connection) {
let state = this._device.active_connection.state;
if (state == NetworkManager.ActiveConnectionState.ACTIVATING) {
return 'network-wired-acquiring-symbolic';
} else if (state == NetworkManager.ActiveConnectionState.ACTIVATED) {
if (this._canReachInternet())
return 'network-wired-symbolic';
else
return 'network-wired-no-route-symbolic';
} else {
return 'network-wired-disconnected-symbolic';
}
} else
return 'network-wired-disconnected-symbolic';
}
});
@ -486,7 +560,7 @@ const NMDeviceModem = new Lang.Class({
if (this._mobileDevice) {
this._operatorNameId = this._mobileDevice.connect('notify::operator-name', Lang.bind(this, this._sync));
this._signalQualityId = this._mobileDevice.connect('notify::signal-quality', Lang.bind(this, function() {
this.emit('icon-changed');
this._iconChanged();
}));
}
},
@ -523,28 +597,20 @@ const NMDeviceModem = new Lang.Class({
return this.parent();
},
_getMenuIcon: function() {
if (this._device.active_connection)
return this.getIndicatorIcon();
else
getIndicatorIcon: function() {
if (this._device.active_connection) {
if (this._device.active_connection.state == NetworkManager.ActiveConnectionState.ACTIVATING)
return 'network-cellular-acquiring-symbolic';
return this._getSignalIcon();
} else {
return 'network-cellular-signal-none-symbolic';
}
},
_getSignalIcon: function() {
return 'network-cellular-signal-' + signalToIcon(this._mobileDevice.signal_quality) + '-symbolic';
},
getIndicatorIcon: function() {
if (this._device.active_connection.state == NetworkManager.ActiveConnectionState.ACTIVATING)
return 'network-cellular-acquiring-symbolic';
if (!this._mobileDevice) {
// this can happen for bluetooth in PAN mode
return 'network-cellular-connected-symbolic';
}
return this._getSignalIcon();
}
});
const NMDeviceBluetooth = new Lang.Class({
@ -558,21 +624,26 @@ const NMDeviceBluetooth = new Lang.Class({
this.item.menu.addMenuItem(createSettingsAction(_("Mobile Broadband Settings"), device));
},
_getMenuIcon: function() {
if (this._device.active_connection)
return this.getIndicatorIcon();
else
return 'network-cellular-signal-none-symbolic';
_getDescription: function() {
return this._device.name;
},
getConnectLabel: function() {
return _("Use as Internet connection");
},
getIndicatorIcon: function() {
let state = this._device.active_connection.state;
if (state == NetworkManager.ActiveConnectionState.ACTIVATING)
return 'network-cellular-acquiring-symbolic';
else if (state == NetworkManager.ActiveConnectionState.ACTIVATED)
return 'network-cellular-connected-symbolic';
else
if (this._device.active_connection) {
let state = this._device.active_connection.state;
if (state == NetworkManager.ActiveConnectionState.ACTIVATING)
return 'network-cellular-acquiring-symbolic';
else if (state == NetworkManager.ActiveConnectionState.ACTIVATED)
return 'network-cellular-connected-symbolic';
else
return 'network-cellular-signal-none-symbolic';
} else {
return 'network-cellular-signal-none-symbolic';
}
}
});
@ -645,16 +716,26 @@ const NMWirelessDialog = new Lang.Class({
Name: 'NMWirelessDialog',
Extends: ModalDialog.ModalDialog,
_init: function(client, device) {
_init: function(client, device, settings) {
this.parent({ styleClass: 'nm-dialog' });
this._client = client;
this._device = device;
this._wirelessEnabledChangedId = this._client.connect('notify::wireless-enabled',
Lang.bind(this, this._syncView));
this._rfkill = Rfkill.getRfkillManager();
this._airplaneModeChangedId = this._rfkill.connect('airplane-mode-changed',
Lang.bind(this, this._syncView));
this._networks = [];
this._buildLayout();
this._connections = device.get_available_connections();
let connections = settings.list_connections();
this._connections = connections.filter(Lang.bind(this, function(connection) {
return device.connection_valid(connection);
}));
this._apAddedId = device.connect('access-point-added', Lang.bind(this, this._accessPointAdded));
this._apRemovedId = device.connect('access-point-removed', Lang.bind(this, this._accessPointRemoved));
@ -669,6 +750,12 @@ const NMWirelessDialog = new Lang.Class({
this._selectedNetwork = null;
this._activeApChanged();
this._updateSensitivity();
this._syncView();
if (accessPoints.length == 0) {
/* If there are no visible access points, request a scan */
this._device.request_scan_simple(null);
}
},
destroy: function() {
@ -684,6 +771,14 @@ const NMWirelessDialog = new Lang.Class({
GObject.Object.prototype.disconnect.call(this._device, this._activeApChangedId);
this._activeApChangedId = 0;
}
if (this._wirelessEnabledChangedId) {
this._client.disconnect(this._wirelessEnabledChangedId);
this._wirelessEnabledChangedId = 0;
}
if (this._airplaneModeChangedId) {
this._rfkill.disconnect(this._airplaneModeChangedId);
this._airplaneModeChangedId = 0;
}
this.parent();
},
@ -705,13 +800,44 @@ const NMWirelessDialog = new Lang.Class({
},
_updateSensitivity: function() {
let connectSensitive = this._selectedNetwork && (this._selectedNetwork != this._activeNetwork);
let connectSensitive = this._client.wireless_enabled && this._selectedNetwork && (this._selectedNetwork != this._activeNetwork);
this._connectButton.reactive = connectSensitive;
this._connectButton.can_focus = connectSensitive;
},
_updateVisibility: function() {
this._noNetworksLabel.visible = (this._networks.length == 0);
_syncView: function() {
if (this._rfkill.airplaneMode) {
this._airplaneBox.show();
this._airplaneIcon.icon_name = 'airplane-mode-symbolic';
this._airplaneHeadline.text = _("Airplane Mode is On");
this._airplaneText.text = _("Wi-Fi is disabled when airplane mode is on.");
this._airplaneButton.label = _("Turn Off Airplane Mode");
this._airplaneButton.visible = !this._rfkill.hwAirplaneMode;
this._airplaneInactive.visible = this._rfkill.hwAirplaneMode;
this._noNetworksBox.hide();
} else if (!this._client.wireless_enabled) {
this._airplaneBox.show();
this._airplaneIcon.icon_name = 'dialog-information-symbolic';
this._airplaneHeadline.text = _("Wi-Fi is Off");
this._airplaneText.text = _("Wi-Fi needs to be turned on in order to connect to a network.");
this._airplaneButton.label = _("Turn On Wi-Fi");
this._airplaneButton.show();
this._airplaneInactive.hide();
this._noNetworksBox.hide();
} else {
this._airplaneBox.hide();
this._noNetworksBox.visible = (this._networks.length == 0);
}
if (this._noNetworksBox.visible)
this._noNetworksSpinner.play();
else
this._noNetworksSpinner.stop();
},
_buildLayout: function() {
@ -745,11 +871,43 @@ const NMWirelessDialog = new Lang.Class({
this._scrollView.add_actor(this._itemBox);
this._stack.add_child(this._scrollView);
this._noNetworksLabel = new St.Label({ style_class: 'no-networks-label',
this._noNetworksBox = new St.BoxLayout({ vertical: true,
style_class: 'no-networks-box',
x_align: Clutter.ActorAlign.CENTER,
y_align: Clutter.ActorAlign.CENTER });
this._noNetworksSpinner = new Animation.AnimatedIcon(global.datadir + '/theme/process-working.svg', 24, 24);
this._noNetworksBox.add_actor(this._noNetworksSpinner.actor);
this._noNetworksBox.add_actor(new St.Label({ style_class: 'no-networks-label',
text: _("No Networks") }));
this._stack.add_child(this._noNetworksBox);
this._airplaneBox = new St.BoxLayout({ vertical: true,
style_class: 'nm-dialog-airplane-box',
x_align: Clutter.ActorAlign.CENTER,
y_align: Clutter.ActorAlign.CENTER,
text: _("No Networks") });
this._stack.add_child(this._noNetworksLabel);
y_align: Clutter.ActorAlign.CENTER });
this._airplaneIcon = new St.Icon({ icon_size: 48 });
this._airplaneHeadline = new St.Label({ style_class: 'nm-dialog-airplane-headline' });
this._airplaneText = new St.Label({ style_class: 'nm-dialog-airplane-text' });
let airplaneSubStack = new St.Widget({ layout_manager: new Clutter.BinLayout });
this._airplaneButton = new St.Button({ style_class: 'modal-dialog-button' });
this._airplaneButton.connect('clicked', Lang.bind(this, function() {
if (this._rfkill.airplaneMode)
this._rfkill.airplaneMode = false;
else
this._client.wireless_enabled = true;
}));
airplaneSubStack.add_actor(this._airplaneButton);
this._airplaneInactive = new St.Label({ style_class: 'nm-dialog-airplane-text',
text: _("Use hardware switch to turn off") });
airplaneSubStack.add_actor(this._airplaneInactive);
this._airplaneBox.add(this._airplaneIcon, { x_align: St.Align.MIDDLE });
this._airplaneBox.add(this._airplaneHeadline, { x_align: St.Align.MIDDLE });
this._airplaneBox.add(this._airplaneText, { x_align: St.Align.MIDDLE });
this._airplaneBox.add(airplaneSubStack, { x_align: St.Align.MIDDLE });
this._stack.add_child(this._airplaneBox);
this.contentLayout.add(this._stack, { expand: true });
@ -942,7 +1100,7 @@ const NMWirelessDialog = new Lang.Class({
this._itemBox.insert_child_at_index(network.item.actor, newPos);
}
this._updateVisibility();
this._syncView();
},
_accessPointRemoved: function(device, accessPoint) {
@ -957,14 +1115,14 @@ const NMWirelessDialog = new Lang.Class({
network.accessPoints.splice(res.ap, 1);
if (network.accessPoints.length == 0) {
network.item.destroy();
network.item.actor.destroy();
this._networks.splice(res.network, 1);
} else {
network.item.updateBestAP(network.accessPoints[0]);
this._resortItems();
}
this._updateVisibility();
this._syncView();
},
_resortItems: function() {
@ -1004,9 +1162,10 @@ const NMDeviceWireless = new Lang.Class({
Name: 'NMDeviceWireless',
category: NMConnectionCategory.WIRELESS,
_init: function(client, device) {
_init: function(client, device, settings) {
this._client = client;
this._device = device;
this._settings = settings;
this._description = '';
@ -1023,10 +1182,16 @@ const NMDeviceWireless = new Lang.Class({
this._wirelessHwEnabledChangedId = this._client.connect('notify::wireless-hardware-enabled', Lang.bind(this, this._sync));
this._activeApChangedId = this._device.connect('notify::active-access-point', Lang.bind(this, this._activeApChanged));
this._stateChangedId = this._device.connect('state-changed', Lang.bind(this, this._deviceStateChanged));
this._notifyConnectivityId = this._client.connect('notify::connectivity', Lang.bind(this, this._iconChanged));
this._sync();
},
_iconChanged: function() {
this._sync();
this.emit('icon-changed');
},
destroy: function() {
if (this._activeApChangedId) {
GObject.Object.prototype.disconnect.call(this._device, this._activeApChangedId);
@ -1048,6 +1213,14 @@ const NMDeviceWireless = new Lang.Class({
this._client.disconnect(this._wirelessHwEnabledChangedId);
this._wirelessHwEnabledChangedId = 0;
}
if (this._dialog) {
this._dialog.destroy();
this._dialog = null;
}
if (this._notifyConnectivityId) {
this._client.disconnect(this._notifyConnectivityId);
this._notifyConnectivityId = 0;
}
this.item.destroy();
},
@ -1074,7 +1247,7 @@ const NMDeviceWireless = new Lang.Class({
},
_showDialog: function() {
this._dialog = new NMWirelessDialog(this._client, this._device);
this._dialog = new NMWirelessDialog(this._client, this._device, this._settings);
this._dialog.connect('closed', Lang.bind(this, this._dialogClosed));
this._dialog.open();
},
@ -1085,7 +1258,7 @@ const NMDeviceWireless = new Lang.Class({
},
_strengthChanged: function() {
this.emit('icon-changed');
this._iconChanged();
},
_activeApChanged: function() {
@ -1121,7 +1294,12 @@ const NMDeviceWireless = new Lang.Class({
_getStatus: function() {
let ap = this._device.active_access_point;
if (ap)
if (this._isHotSpotMaster())
return _("Hotspot Active");
else if (this._device.state >= NetworkManager.DeviceState.PREPARE &&
this._device.state < NetworkManager.DeviceState.ACTIVATED)
return _("Connecting");
else if (ap)
return ssidToLabel(ap.get_ssid());
else if (!this._client.wireless_hardware_enabled)
return _("Hardware Disabled");
@ -1140,20 +1318,52 @@ const NMDeviceWireless = new Lang.Class({
return 'network-wireless-signal-none-symbolic';
},
_canReachInternet: function() {
if (this._client.primary_connection != this._device.active_connection)
return true;
return this._client.connectivity == NetworkManager.ConnectivityState.FULL;
},
_isHotSpotMaster: function() {
if (!this._device.active_connection)
return false;
let connection = this._settings.get_connection_by_path(this._device.active_connection.connection);
if (!connection)
return false;
let ip4config = connection.get_setting_ip4_config();
if (!ip4config)
return false;
return ip4config.get_method() == NetworkManager.SETTING_IP4_CONFIG_METHOD_SHARED;
},
getIndicatorIcon: function() {
if (this._device.state >= NetworkManager.DeviceState.PREPARE &&
this._device.state < NetworkManager.DeviceState.ACTIVATED)
if (this._device.state < NetworkManager.DeviceState.PREPARE)
return 'network-wireless-disconnected-symbolic';
if (this._device.state < NetworkManager.DeviceState.ACTIVATED)
return 'network-wireless-acquiring-symbolic';
if (this._isHotSpotMaster())
return 'network-wireless-hotspot-symbolic';
let ap = this._device.active_access_point;
if (!ap) {
if (this._device.mode != NM80211Mode.ADHOC)
log('An active wireless connection, in infrastructure mode, involves no access point?');
return 'network-wireless-connected-symbolic';
if (this._canReachInternet())
return 'network-wireless-connected-symbolic';
else
return 'network-wireless-no-route-symbolic';
}
return 'network-wireless-signal-' + signalToIcon(ap.strength) + '-symbolic';
if (this._canReachInternet())
return 'network-wireless-signal-' + signalToIcon(ap.strength) + '-symbolic';
else
return 'network-wireless-no-route-symbolic';
},
});
Signals.addSignalMethods(NMDeviceWireless.prototype);
@ -1169,6 +1379,22 @@ const NMVPNConnectionItem = new Lang.Class({
return this._activeConnection.vpn_state != NetworkManager.VPNConnectionState.DISCONNECTED;
},
_buildUI: function() {
this.labelItem = new PopupMenu.PopupMenuItem('');
this.labelItem.connect('activate', Lang.bind(this, this._toggle));
this.radioItem = new PopupMenu.PopupSwitchMenuItem(this._connection.get_id(), false);
this.radioItem.connect('toggled', Lang.bind(this, this._toggle));
},
_sync: function() {
let isActive = this.isActive();
this.labelItem.label.text = isActive ? _("Turn Off") : this._section.getConnectLabel();
this.radioItem.setToggleState(isActive);
this.radioItem.setStatus(this._getStatus());
this.emit('icon-changed');
},
_getStatus: function() {
if (this._activeConnection == null)
return null;
@ -1238,19 +1464,53 @@ const NMVPNSection = new Lang.Class({
_init: function(client) {
this.parent(client);
this._vpnSettings = new PopupMenu.PopupMenuItem('');
this.item.menu.addMenuItem(this._vpnSettings);
this._vpnSettings.connect('activate', Lang.bind(this, this._onSettingsActivate));
this._sync();
},
_sync: function() {
let nItems = this._connectionItems.size;
this.item.actor.visible = (nItems > 0);
if (nItems > 1)
this._vpnSettings.label.text = _("Network Settings");
else
this._vpnSettings.label.text = _("VPN Settings");
this.parent();
},
_onSettingsActivate: function() {
let nItems = this._connectionItems.size;
if (nItems > 1) {
let appSys = Shell.AppSystem.get_default();
let app = appSys.lookup_app('gnome-network-panel.desktop');
app.launch(0, -1);
} else {
let connection = this._connections[0];
Util.spawnApp(['gnome-control-center', 'network', 'show-device',
connection.get_path()]);
}
},
_getDescription: function() {
return _("VPN");
},
_getStatus: function() {
let values = this._connectionItems.values();
for (let item of values) {
if (item.isActive())
return item.getName();
}
return _("Off");
},
_getMenuIcon: function() {
return this.getIndicatorIcon() || 'network-vpn-symbolic';
},
@ -1348,6 +1608,7 @@ const NMApplet = new Lang.Class({
this._activeConnections = [ ];
this._connections = [ ];
this._connectivityQueue = [ ];
this._mainConnection = null;
this._mainConnectionIconChangedId = 0;
@ -1376,6 +1637,7 @@ const NMApplet = new Lang.Class({
this._client.connect('notify::primary-connection', Lang.bind(this, this._syncMainConnection));
this._client.connect('notify::activating-connection', Lang.bind(this, this._syncMainConnection));
this._client.connect('notify::active-connections', Lang.bind(this, this._syncVPNConnections));
this._client.connect('notify::connectivity', Lang.bind(this, this._syncConnectivity));
this._client.connect('device-added', Lang.bind(this, this._deviceAdded));
this._client.connect('device-removed', Lang.bind(this, this._deviceRemoved));
this._settings.connect('new-connection', Lang.bind(this, this._newConnection));
@ -1544,6 +1806,7 @@ const NMApplet = new Lang.Class({
}
this._updateIcon();
this._syncConnectivity();
},
_syncVPNConnections: function() {
@ -1629,7 +1892,6 @@ const NMApplet = new Lang.Class({
let connectionSettings = connection.get_setting_by_name(NetworkManager.SETTING_CONNECTION_SETTING_NAME);
connection._type = connectionSettings.type;
connection._section = this._ctypes[connection._type] || NMConnectionCategory.INVALID;
connection._timestamp = connectionSettings.timestamp;
let section = connection._section;
@ -1650,12 +1912,102 @@ const NMApplet = new Lang.Class({
_syncNMState: function() {
this.indicators.visible = this._client.manager_running;
this.menu.actor.visible = this._client.networking_enabled;
this._syncConnectivity();
},
_flushConnectivityQueue: function() {
if (this._portalHelperProxy) {
for (let item of this._connectivityQueue)
this._portalHelperProxy.CloseRemote(item);
}
this._connectivityQueue = [];
},
_closeConnectivityCheck: function(path) {
let index = this._connectivityQueue.indexOf(path);
if (index >= 0) {
if (this._portalHelperProxy)
this._portalHelperProxy.CloseRemote(path);
this._connectivityQueue.splice(index, 1);
}
},
_portalHelperDone: function(proxy, emitter, parameters) {
let [path, result] = parameters;
if (result == PortalHelperResult.CANCELLED) {
// Keep the connection in the queue, so the user is not
// spammed with more logins until we next flush the queue,
// which will happen once he chooses a better connection
// or we get to full connectivity through other means
} else if (result == PortalHelperResult.COMPLETED) {
this._closeConnectivityCheck(path);
return;
} else if (result == PortalHelperResult.RECHECK) {
this._client.check_connectivity_async(null, Lang.bind(this, function(client, result) {
try {
let state = client.check_connectivity_finish(result);
if (state >= NetworkManager.ConnectivityState.FULL)
this._closeConnectivityCheck(path);
} catch(e) { }
}));
} else {
log('Invalid result from portal helper: ' + result);
}
},
_syncConnectivity: function() {
if (this._mainConnection == null ||
this._mainConnection.state != NetworkManager.ActiveConnectionState.ACTIVATED) {
this._flushConnectivityQueue();
return;
}
let isPortal = this._client.connectivity == NetworkManager.ConnectivityState.PORTAL;
// For testing, allow interpreting any value != FULL as PORTAL, because
// LIMITED (no upstream route after the default gateway) is easy to obtain
// with a tethered phone
// NONE is also possible, with a connection configured to force no default route
// (but in general we should only prompt a portal if we know there is a portal)
if (GLib.getenv('GNOME_SHELL_CONNECTIVITY_TEST') != null)
isPortal = isPortal || this._client.connectivity < NetworkManager.ConnectivityState.FULL;
if (!isPortal)
return;
let path = this._mainConnection.get_path();
for (let item of this._connectivityQueue) {
if (item == path)
return;
}
let timestamp = global.get_current_time();
if (this._portalHelperProxy) {
this._portalHelperProxy.AuthenticateRemote(path, '', timestamp);
} else {
new PortalHelperProxy(Gio.DBus.session, 'org.gnome.Shell.PortalHelper',
'/org/gnome/Shell/PortalHelper', Lang.bind(this, function (proxy, error) {
if (error) {
log('Error launching the portal helper: ' + error);
return;
}
this._portalHelperProxy = proxy;
proxy.connectSignal('Done', Lang.bind(this, this._portalHelperDone));
proxy.AuthenticateRemote(path, '', timestamp);
}));
}
this._connectivityQueue.push(path);
},
_updateIcon: function() {
if (!this._client.networking_enabled || !this._mainConnection) {
this._primaryIndicator.icon_name = 'network-offline-symbolic';
this._primaryIndicator.visible = true;
this._primaryIndicator.visible = false;
} else {
let dev = this._mainConnection._primaryDevice;
this._primaryIndicator.visible = (dev != null);

View File

@ -2,7 +2,9 @@
const Gio = imports.gi.Gio;
const Lang = imports.lang;
const Signals = imports.signals;
const Main = imports.ui.main;
const PanelMenu = imports.ui.panelMenu;
const PopupMenu = imports.ui.popupMenu;
@ -12,11 +14,55 @@ const OBJECT_PATH = '/org/gnome/SettingsDaemon/Rfkill';
const RfkillManagerInterface = '<node> \
<interface name="org.gnome.SettingsDaemon.Rfkill"> \
<property name="AirplaneMode" type="b" access="readwrite" /> \
<property name="HardwareAirplaneMode" type="b" access="read" /> \
</interface> \
</node>';
const RfkillManagerProxy = Gio.DBusProxy.makeProxyWrapper(RfkillManagerInterface);
const RfkillManager = new Lang.Class({
Name: 'RfkillManager',
_init: function() {
this._proxy = new RfkillManagerProxy(Gio.DBus.session, BUS_NAME, OBJECT_PATH,
Lang.bind(this, function(proxy, error) {
if (error) {
log(error.message);
return;
}
this._proxy.connect('g-properties-changed',
Lang.bind(this, this._changed));
this._changed();
}));
},
get airplaneMode() {
return this._proxy.AirplaneMode;
},
set airplaneMode(v) {
this._proxy.AirplaneMode = v;
},
get hwAirplaneMode() {
return this._proxy.HardwareAirplaneMode;
},
_changed: function() {
this.emit('airplane-mode-changed');
}
});
Signals.addSignalMethods(RfkillManager.prototype);
var _manager;
function getRfkillManager() {
if (_manager != null)
return _manager;
_manager = new RfkillManager();
return _manager;
}
const Indicator = new Lang.Class({
Name: 'RfkillIndicator',
Extends: PanelMenu.SystemIndicator,
@ -24,16 +70,8 @@ const Indicator = new Lang.Class({
_init: function() {
this.parent();
this._proxy = new RfkillManagerProxy(Gio.DBus.session, BUS_NAME, OBJECT_PATH,
Lang.bind(this, function(proxy, error) {
if (error) {
log(error.message);
return;
}
this._proxy.connect('g-properties-changed',
Lang.bind(this, this._sync));
this._sync();
}));
this._manager = getRfkillManager();
this._manager.connect('airplane-mode-changed', Lang.bind(this, this._sync));
this._indicator = this._addIndicator();
this._indicator.icon_name = 'airplane-mode-symbolic';
@ -45,16 +83,34 @@ const Indicator = new Lang.Class({
this._item = new PopupMenu.PopupSubMenuMenuItem(_("Airplane Mode"), true);
this._item.icon.icon_name = 'airplane-mode-symbolic';
this._item.status.text = _("On");
this._item.menu.addAction(_("Turn Off"), Lang.bind(this, function() {
this._proxy.AirplaneMode = false;
this._offItem = this._item.menu.addAction(_("Turn Off"), Lang.bind(this, function() {
this._manager.airplaneMode = false;
}));
this._item.menu.addSettingsAction(_("Network Settings"), 'gnome-network-panel.desktop');
this.menu.addMenuItem(this._item);
Main.sessionMode.connect('updated', Lang.bind(this, this._sessionUpdated));
this._sessionUpdated();
},
_sessionUpdated: function() {
let sensitive = !Main.sessionMode.isLocked && !Main.sessionMode.isGreeter;
this.menu.setSensitive(sensitive);
},
_sync: function() {
let airplaneMode = this._proxy.AirplaneMode;
let airplaneMode = this._manager.airplaneMode;
let hwAirplaneMode = this._manager.hwAirplaneMode;
let changed = (airplaneMode != this._indicator.visible) ||
(hwAirplaneMode != this._offItem.actor.visible);
this._indicator.visible = airplaneMode;
this._item.actor.visible = airplaneMode;
this._offItem.setSensitive(!hwAirplaneMode);
if (hwAirplaneMode)
this._offItem.label.text = _("Use hardware switch to turn off");
else
this._offItem.label.text = _("Turn Off");
},
});

View File

@ -56,7 +56,10 @@ const AltSwitcher = new Lang.Class({
}
if (this.actor.get_child() != childToShow) {
let hasFocus = this.actor.contains(global.stage.get_key_focus());
this.actor.set_child(childToShow);
if (hasFocus)
childToShow.grab_key_focus();
// The actors might respond to hover, so
// sync the pointer to make sure they update.
@ -92,11 +95,11 @@ const Indicator = new Lang.Class({
_init: function() {
this.parent();
this._screenSaverSettings = new Gio.Settings({ schema: SCREENSAVER_SCHEMA });
this._loginScreenSettings = new Gio.Settings({ schema: LOGIN_SCREEN_SCHEMA });
this._lockdownSettings = new Gio.Settings({ schema: LOCKDOWN_SCHEMA });
this._privacySettings = new Gio.Settings({ schema: PRIVACY_SCHEMA });
this._orientationSettings = new Gio.Settings({ schema: 'org.gnome.settings-daemon.peripherals.touchscreen' });
this._screenSaverSettings = new Gio.Settings({ schema_id: SCREENSAVER_SCHEMA });
this._loginScreenSettings = new Gio.Settings({ schema_id: LOGIN_SCREEN_SCHEMA });
this._lockdownSettings = new Gio.Settings({ schema_id: LOCKDOWN_SCHEMA });
this._privacySettings = new Gio.Settings({ schema_id: PRIVACY_SCHEMA });
this._orientationSettings = new Gio.Settings({ schema_id: 'org.gnome.settings-daemon.peripherals.touchscreen' });
this._session = new GnomeSession.SessionManager();
this._loginManager = LoginManager.getLoginManager();
@ -148,11 +151,11 @@ const Indicator = new Lang.Class({
Gio.DBus.session.watch_name('org.gnome.SettingsDaemon.Orientation',
Gio.BusNameWatcherFlags.NONE,
Lang.bind(this, function() {
this._orentationExists = true;
this._orientationExists = true;
this._updateOrientationLock();
}),
Lang.bind(this, function() {
this._orentationExists = false;
this._orientationExists = false;
this._updateOrientationLock();
}));
this._updateOrientationLock();

View File

@ -102,16 +102,17 @@ const SwitcherPopup = new Lang.Class({
this._switcherList.actor.allocate(childBox, flags);
},
_createSwitcher: function() {
throw new Error('Not implemented');
},
_initialSelection: function(backward, binding) {
throw new Error('Not implemented');
if (backward)
this._select(this._items.length - 1);
else if (this._items.length == 1)
this._select(0);
else
this._select(1);
},
show: function(backward, binding, mask) {
if (!this._createSwitcher())
if (this._items.length == 0)
return false;
if (!Main.pushModal(this.actor)) {
@ -139,11 +140,6 @@ const SwitcherPopup = new Lang.Class({
this.actor.show();
this.actor.get_allocation_box();
if (this._items.length > 1)
this._selectedIndex = 1;
else
this._selectedIndex = 0;
this._initialSelection(backward, binding);
// There's a race condition; if the user released Alt before
@ -161,11 +157,12 @@ const SwitcherPopup = new Lang.Class({
// disturbed by the popup briefly flashing.
this._initialDelayTimeoutId = Mainloop.timeout_add(POPUP_DELAY_TIMEOUT,
Lang.bind(this, function () {
Main.osdWindow.cancel();
Main.osdWindowManager.hideAll();
this.actor.opacity = 255;
this._initialDelayTimeoutId = 0;
return GLib.SOURCE_REMOVE;
}));
GLib.Source.set_name_by_id(this._initialDelayTimeoutId, '[gnome-shell] Main.osdWindow.cancel');
return true;
},
@ -177,22 +174,21 @@ const SwitcherPopup = new Lang.Class({
return mod(this._selectedIndex - 1, this._items.length);
},
_keyPressHandler: function(keysym, backwards, action) {
_keyPressHandler: function(keysym, action) {
throw new Error('Not implemented');
},
_keyPressEvent: function(actor, event) {
let keysym = event.get_key_symbol();
let event_state = event.get_state();
let backwards = event_state & Clutter.ModifierType.SHIFT_MASK;
let action = global.display.get_keybinding_action(event.get_key_code(), event_state);
let action = global.display.get_keybinding_action(event.get_key_code(), event.get_state());
this._disableHover();
if (this._keyPressHandler(keysym, action) != Clutter.EVENT_PROPAGATE)
return Clutter.EVENT_STOP;
if (keysym == Clutter.Escape)
this.destroy();
else
this._keyPressHandler(keysym, backwards, action);
return Clutter.EVENT_STOP;
},
@ -250,6 +246,7 @@ const SwitcherPopup = new Lang.Class({
Mainloop.source_remove(this._motionTimeoutId);
this._motionTimeoutId = Mainloop.timeout_add(DISABLE_HOVER_TIMEOUT, Lang.bind(this, this._mouseTimedOut));
GLib.Source.set_name_by_id(this._motionTimeoutId, '[gnome-shell] this._mouseTimedOut');
},
_mouseTimedOut: function() {

View File

@ -53,8 +53,10 @@ function _wrapTweening(target, tweeningParameters) {
}
}
if (!Gtk.Settings.get_default().gtk_enable_animations)
if (!Gtk.Settings.get_default().gtk_enable_animations) {
tweeningParameters['time'] = 0.000001;
tweeningParameters['delay'] = 0.000001;
}
_addHandler(target, tweeningParameters, 'onComplete', _tweenCompleted);
}

View File

@ -62,7 +62,7 @@ const UnlockDialog = new Lang.Class({
this.allowCancel = false;
let screenSaverSettings = new Gio.Settings({ schema: 'org.gnome.desktop.screensaver' });
let screenSaverSettings = new Gio.Settings({ schema_id: 'org.gnome.desktop.screensaver' });
if (screenSaverSettings.get_boolean('user-switch-enabled')) {
let otherUserLabel = new St.Label({ text: _("Log in as another user"),
style_class: 'login-dialog-not-listed-label' });

View File

@ -19,6 +19,8 @@ const Search = imports.ui.search;
const ShellEntry = imports.ui.shellEntry;
const Tweener = imports.ui.tweener;
const WorkspacesView = imports.ui.workspacesView;
const EdgeDragAction = imports.ui.edgeDragAction;
const IconGrid = imports.ui.iconGrid;
const SHELL_KEYBINDINGS_SCHEMA = 'org.gnome.shell.keybindings';
@ -49,20 +51,80 @@ function getTermsForSearchString(searchString) {
return terms;
}
const ShowOverviewAction = new Lang.Class({
Name: 'ShowOverviewAction',
Extends: Clutter.GestureAction,
_init : function() {
this.parent();
this.set_n_touch_points(3);
global.display.connect('grab-op-begin', Lang.bind(this, function() {
this.cancel();
}));
},
vfunc_gesture_prepare : function(action, actor) {
return this.get_n_current_points() == this.get_n_touch_points();
},
_getBoundingRect : function(motion) {
let minX, minY, maxX, maxY;
for (let i = 0; i < this.get_n_current_points(); i++) {
let x, y;
if (motion == true) {
[x, y] = this.get_motion_coords(i);
} else {
[x, y] = this.get_press_coords(i);
}
if (i == 0) {
minX = maxX = x;
minY = maxY = y;
} else {
minX = Math.min(minX, x);
minY = Math.min(minY, y);
maxX = Math.max(maxX, x);
maxY = Math.max(maxY, y);
}
}
return new Meta.Rectangle({ x: minX,
y: minY,
width: maxX - minX,
height: maxY - minY });
},
vfunc_gesture_begin : function(action, actor) {
this._initialRect = this._getBoundingRect(false);
return true;
},
vfunc_gesture_end : function(action, actor) {
let rect = this._getBoundingRect(true);
let oldArea = this._initialRect.width * this._initialRect.height;
let newArea = rect.width * rect.height;
let areaDiff = newArea / oldArea;
this.emit('activated', areaDiff);
}
});
Signals.addSignalMethods(ShowOverviewAction.prototype);
const ViewSelector = new Lang.Class({
Name: 'ViewSelector',
_init : function(searchEntry, showAppsButton) {
this.actor = new Shell.Stack({ name: 'viewSelector' });
this._showAppsBlocked = false;
this._showAppsButton = showAppsButton;
this._showAppsButton.connect('notify::checked', Lang.bind(this, this._onShowAppsButtonToggled));
this._activePage = null;
this._searchActive = false;
this._searchTimeoutId = 0;
this._entry = searchEntry;
ShellEntry.addContextMenu(this._entry);
@ -81,12 +143,8 @@ const ViewSelector = new Lang.Class({
this._entry.set_primary_icon(new St.Icon({ style_class: 'search-entry-icon',
icon_name: 'edit-find-symbolic' }));
if (this._entry.get_text_direction() == Clutter.TextDirection.RTL)
this._clearIcon = new St.Icon({ style_class: 'search-entry-icon',
icon_name: 'edit-clear-rtl-symbolic' });
else
this._clearIcon = new St.Icon({ style_class: 'search-entry-icon',
icon_name: 'edit-clear-symbolic' });
this._clearIcon = new St.Icon({ style_class: 'search-entry-icon',
icon_name: 'edit-clear-symbolic' });
this._iconClickedId = 0;
this._capturedEventId = 0;
@ -118,58 +176,91 @@ const ViewSelector = new Lang.Class({
this._stageKeyPressId = 0;
Main.overview.connect('showing', Lang.bind(this,
function () {
this._resetShowAppsButton();
this._stageKeyPressId = global.stage.connect('key-press-event',
Lang.bind(this, this._onStageKeyPress));
}));
Main.overview.connect('hiding', Lang.bind(this,
function () {
this._resetShowAppsButton();
if (this._stageKeyPressId != 0) {
global.stage.disconnect(this._stageKeyPressId);
this._stageKeyPressId = 0;
}
}));
Main.overview.connect('shown', Lang.bind(this,
function() {
// If we were animating from the desktop view to the
// apps page the workspace page was visible, allowing
// the windows to animate, but now we no longer want to
// show it given that we are now on the apps page or
// search page.
if (this._activePage != this._workspacesPage)
this._workspacesPage.opacity = 0;
}));
Main.wm.addKeybinding('toggle-application-view',
new Gio.Settings({ schema: SHELL_KEYBINDINGS_SCHEMA }),
new Gio.Settings({ schema_id: SHELL_KEYBINDINGS_SCHEMA }),
Meta.KeyBindingFlags.NONE,
Shell.KeyBindingMode.NORMAL |
Shell.KeyBindingMode.OVERVIEW,
Lang.bind(this, this._toggleAppsPage));
Main.wm.addKeybinding('toggle-overview',
new Gio.Settings({ schema: SHELL_KEYBINDINGS_SCHEMA }),
new Gio.Settings({ schema_id: SHELL_KEYBINDINGS_SCHEMA }),
Meta.KeyBindingFlags.NONE,
Shell.KeyBindingMode.NORMAL |
Shell.KeyBindingMode.OVERVIEW,
Lang.bind(Main.overview, Main.overview.toggle));
let gesture;
gesture = new EdgeDragAction.EdgeDragAction(St.Side.LEFT);
gesture.connect('activated', Lang.bind(this, function() {
if (Main.overview.visible)
Main.overview.hide();
else
this.showApps();
}));
global.stage.add_action(gesture);
gesture = new ShowOverviewAction();
gesture.connect('activated', Lang.bind(this, function(action, areaDiff) {
if (areaDiff < 0.7)
Main.overview.show();
}));
global.stage.add_action(gesture);
},
_toggleAppsPage: function() {
Main.overview.show();
this._showAppsButton.checked = !this._showAppsButton.checked;
Main.overview.show();
},
showApps: function() {
Main.overview.show();
this._showAppsButton.checked = true;
Main.overview.show();
},
show: function() {
this.reset();
this._workspacesDisplay.show();
this._workspacesDisplay.show(this._showAppsButton.checked);
this._activePage = null;
this._showPage(this._workspacesPage);
if (this._showAppsButton.checked)
this._showPage(this._appsPage);
else
this._showPage(this._workspacesPage);
if (!this._workspacesDisplay.activeWorkspaceHasMaximizedWindows())
Main.overview.fadeOutDesktop();
},
zoomFromOverview: function() {
this._workspacesDisplay.zoomFromOverview();
animateFromOverview: function() {
// Make sure workspace page is fully visible to allow
// workspace.js do the animation of the windows
this._workspacesPage.opacity = 255;
this._workspacesDisplay.animateFromOverview(this._activePage != this._workspacesPage);
this._showAppsButton.checked = false;
if (!this._workspacesDisplay.activeWorkspaceHasMaximizedWindows())
Main.overview.fadeInDesktop();
@ -187,7 +278,6 @@ const ViewSelector = new Lang.Class({
params = Params.parse(params, { a11yFocus: null });
let page = new St.Bin({ child: actor,
visible: false,
x_align: St.Align.START,
y_align: St.Align.START,
x_fill: true,
@ -207,21 +297,61 @@ const ViewSelector = new Lang.Class({
return page;
},
_fadePageIn: function(oldPage) {
_fadePageIn: function() {
Tweener.addTween(this._activePage,
{ opacity: 255,
time: OverviewControls.SIDE_CONTROLS_ANIMATION_TIME,
transition: 'easeOutQuad'
});
},
_fadePageOut: function(page) {
let oldPage = page;
Tweener.addTween(page,
{ opacity: 0,
time: OverviewControls.SIDE_CONTROLS_ANIMATION_TIME,
transition: 'easeOutQuad',
onComplete: Lang.bind(this, function() {
this._animateIn(oldPage);
})
});
},
_animateIn: function(oldPage) {
if (oldPage)
oldPage.hide();
this.emit('page-empty');
this._activePage.navigate_focus(null, Gtk.DirectionType.TAB_FORWARD, false);
this._activePage.show();
Tweener.addTween(this._activePage,
{ opacity: 255,
time: OverviewControls.SIDE_CONTROLS_ANIMATION_TIME,
transition: 'easeOutQuad'
});
if (this._activePage == this._appsPage && oldPage == this._workspacesPage) {
// Restore opacity, in case we animated via _fadePageOut
this._activePage.opacity = 255;
this.appDisplay.animate(IconGrid.AnimationDirection.IN);
} else {
this._fadePageIn();
}
},
_showPage: function(page, noFade) {
_animateOut: function(page) {
let oldPage = page;
if (page == this._appsPage &&
this._activePage == this._workspacesPage &&
!Main.overview.animationInProgress) {
this.appDisplay.animate(IconGrid.AnimationDirection.OUT, Lang.bind(this,
function() {
this._animateIn(oldPage)
}));
} else {
this._fadePageOut(page);
}
},
_showPage: function(page) {
if (!Main.overview.visible)
return;
if (page == this._activePage)
return;
@ -229,18 +359,10 @@ const ViewSelector = new Lang.Class({
this._activePage = page;
this.emit('page-changed');
if (oldPage && !noFade)
Tweener.addTween(oldPage,
{ opacity: 0,
time: OverviewControls.SIDE_CONTROLS_ANIMATION_TIME,
transition: 'easeOutQuad',
onComplete: Lang.bind(this,
function() {
this._fadePageIn(oldPage);
})
});
if (oldPage)
this._animateOut(oldPage)
else
this._fadePageIn(oldPage);
this._animateIn();
},
_a11yFocusPage: function(page) {
@ -249,21 +371,10 @@ const ViewSelector = new Lang.Class({
},
_onShowAppsButtonToggled: function() {
if (this._showAppsBlocked)
return;
this._showPage(this._showAppsButton.checked ?
this._appsPage : this._workspacesPage);
},
_resetShowAppsButton: function() {
this._showAppsBlocked = true;
this._showAppsButton.checked = false;
this._showAppsBlocked = false;
this._showPage(this._workspacesPage, true);
},
_onStageKeyPress: function(actor, event) {
// Ignore events while anything but the overview has
// pushed a modal (system modals, looking glass, ...)
@ -283,6 +394,14 @@ const ViewSelector = new Lang.Class({
return Clutter.EVENT_STOP;
} else if (this._shouldTriggerSearch(symbol)) {
this.startSearch(event);
} else if (!this._searchActive && !global.stage.key_focus) {
if (symbol == Clutter.Tab || symbol == Clutter.Down) {
this._activePage.navigate_focus(null, Gtk.DirectionType.TAB_FORWARD, false);
return Clutter.EVENT_STOP;
} else if (symbol == Clutter.ISO_Left_Tab) {
this._activePage.navigate_focus(null, Gtk.DirectionType.TAB_BACKWARD, false);
return Clutter.EVENT_STOP;
}
}
return Clutter.EVENT_PROPAGATE;
},
@ -351,7 +470,10 @@ const ViewSelector = new Lang.Class({
startSearch: function(event) {
global.stage.set_key_focus(this._text);
this._text.event(event, true);
let synthEvent = event.copy();
synthEvent.set_source(this._text);
this._text.event(synthEvent, true);
},
// the entry does not show the hint
@ -362,34 +484,23 @@ const ViewSelector = new Lang.Class({
_onTextChanged: function (se, prop) {
let terms = getTermsForSearchString(this._entry.get_text());
let searchPreviouslyActive = this._searchActive;
this._searchActive = (terms.length > 0);
let startSearch = this._searchActive && !searchPreviouslyActive;
if (startSearch)
this._searchResults.startingSearch();
this._searchResults.setTerms(terms);
if (this._searchActive) {
this._showPage(this._searchPage);
this._entry.set_secondary_icon(this._clearIcon);
if (this._iconClickedId == 0)
this._iconClickedId = this._entry.connect('secondary-icon-clicked',
Lang.bind(this, this.reset));
if (this._searchTimeoutId == 0)
this._searchTimeoutId = Mainloop.timeout_add(150,
Lang.bind(this, this._doSearch));
} else {
if (this._iconClickedId > 0) {
this._entry.disconnect(this._iconClickedId);
this._iconClickedId = 0;
}
if (this._searchTimeoutId > 0) {
Mainloop.source_remove(this._searchTimeoutId);
this._searchTimeoutId = 0;
}
this._entry.set_secondary_icon(null);
this._searchCancelled();
}
@ -427,12 +538,6 @@ const ViewSelector = new Lang.Class({
this._searchResults.navigateFocus(nextDirection);
return Clutter.EVENT_STOP;
} else if (symbol == Clutter.Return || symbol == Clutter.KP_Enter) {
// We can't connect to 'activate' here because search providers
// might want to do something with the modifiers in activateDefault.
if (this._searchTimeoutId > 0) {
Mainloop.source_remove(this._searchTimeoutId);
this._doSearch();
}
this._searchResults.activateDefault();
return Clutter.EVENT_STOP;
}
@ -455,17 +560,6 @@ const ViewSelector = new Lang.Class({
return Clutter.EVENT_PROPAGATE;
},
_doSearch: function () {
this._searchTimeoutId = 0;
let terms = getTermsForSearchString(this._entry.get_text());
this._searchResults.setTerms(terms);
this._showPage(this._searchPage);
return GLib.SOURCE_REMOVE;
},
getActivePage: function() {
if (this._activePage == this._workspacesPage)
return ViewPage.WINDOWS;

View File

@ -9,14 +9,23 @@ const Meta = imports.gi.Meta;
const Pango = imports.gi.Pango;
const St = imports.gi.St;
const Shell = imports.gi.Shell;
const Signals = imports.signals;
const AltTab = imports.ui.altTab;
const WorkspaceSwitcherPopup = imports.ui.workspaceSwitcherPopup;
const Main = imports.ui.main;
const ModalDialog = imports.ui.modalDialog;
const Tweener = imports.ui.tweener;
const WindowMenu = imports.ui.windowMenu;
const SHELL_KEYBINDINGS_SCHEMA = 'org.gnome.shell.keybindings';
const MAXIMIZE_WINDOW_ANIMATION_TIME = 0.15;
const UNMAXIMIZE_WINDOW_ANIMATION_TIME = 0.15;
const MINIMIZE_WINDOW_ANIMATION_TIME = 0.2;
const SHOW_WINDOW_ANIMATION_TIME = 0.15;
const DIALOG_SHOW_WINDOW_ANIMATION_TIME = 0.1;
const DESTROY_WINDOW_ANIMATION_TIME = 0.15;
const DIALOG_DESTROY_WINDOW_ANIMATION_TIME = 0.1;
const WINDOW_ANIMATION_TIME = 0.25;
const DIM_BRIGHTNESS = -0.3;
const DIM_TIME = 0.500;
@ -82,6 +91,7 @@ const DisplayChangeDialog = new Lang.Class({
{ expand: false, x_fill: false, x_align: St.Align.END });
this._timeoutId = Mainloop.timeout_add(ONE_SECOND, Lang.bind(this, this._tick));
GLib.Source.set_name_by_id(this._timeoutId, '[gnome-shell] this._tick');
},
close: function(timestamp) {
@ -191,17 +201,25 @@ const WorkspaceTracker = new Lang.Class({
tracker.connect('startup-sequence-changed', Lang.bind(this, this._queueCheckWorkspaces));
global.screen.connect('notify::n-workspaces', Lang.bind(this, this._nWorkspacesChanged));
global.window_manager.connect('switch-workspace', Lang.bind(this, this._queueCheckWorkspaces));
global.screen.connect('window-entered-monitor', Lang.bind(this, this._windowEnteredMonitor));
global.screen.connect('window-left-monitor', Lang.bind(this, this._windowLeftMonitor));
global.screen.connect('restacked', Lang.bind(this, this._windowsRestacked));
this._workspaceSettings = new Gio.Settings({ schema: Main.dynamicWorkspacesSchema });
this._workspaceSettings = this._getWorkspaceSettings();
this._workspaceSettings.connect('changed::dynamic-workspaces', Lang.bind(this, this._queueCheckWorkspaces));
this._nWorkspacesChanged();
},
_getWorkspaceSettings: function() {
let settings = global.get_overrides_settings();
if (settings.list_keys().indexOf('dynamic-workspaces') > -1)
return settings;
return new Gio.Settings({ schema_id: 'org.gnome.mutter' });
},
_checkWorkspaces: function() {
let i;
let emptyWorkspaces = [];
@ -249,13 +267,7 @@ const WorkspaceTracker = new Lang.Class({
}
let activeWorkspaceIndex = global.screen.get_active_workspace_index();
let removingCurrentWorkspace = (emptyWorkspaces[activeWorkspaceIndex] &&
activeWorkspaceIndex < emptyWorkspaces.length - 1);
if (removingCurrentWorkspace) {
// "Merge" the empty workspace we are removing with the one at the end
this._wm.blockAnimations();
}
emptyWorkspaces[activeWorkspaceIndex] = false;
// Delete other empty workspaces; do it from the end to avoid index changes
for (i = emptyWorkspaces.length - 2; i >= 0; i--) {
@ -263,11 +275,6 @@ const WorkspaceTracker = new Lang.Class({
global.screen.remove_workspace(this._workspaces[i], global.get_current_time());
}
if (removingCurrentWorkspace) {
global.screen.get_workspace_by_index(global.screen.n_workspaces - 1).activate(global.get_current_time());
this._wm.unblockAnimations();
}
this._checkWorkspacesId = 0;
return false;
},
@ -281,18 +288,20 @@ const WorkspaceTracker = new Lang.Class({
this._queueCheckWorkspaces();
return GLib.SOURCE_REMOVE;
}));
GLib.Source.set_name_by_id(workspace._keepAliveId, '[gnome-shell] this._queueCheckWorkspaces');
},
_windowRemoved: function(workspace, window) {
workspace._lastRemovedWindow = window;
this._queueCheckWorkspaces();
Mainloop.timeout_add(LAST_WINDOW_GRACE_TIME, Lang.bind(this, function() {
let id = Mainloop.timeout_add(LAST_WINDOW_GRACE_TIME, Lang.bind(this, function() {
if (workspace._lastRemovedWindow == window) {
workspace._lastRemovedWindow = null;
this._queueCheckWorkspaces();
}
return GLib.SOURCE_REMOVE;
}));
GLib.Source.set_name_by_id(id, '[gnome-shell] this._queueCheckWorkspaces');
},
_windowLeftMonitor: function(metaScreen, monitorIndex, metaWin) {
@ -368,6 +377,207 @@ const WorkspaceTracker = new Lang.Class({
}
});
const TilePreview = new Lang.Class({
Name: 'TilePreview',
_init: function() {
this.actor = new St.Widget();
global.window_group.add_actor(this.actor);
this._reset();
this._showing = false;
},
show: function(window, tileRect, monitorIndex) {
let windowActor = window.get_compositor_private();
if (!windowActor)
return;
global.window_group.set_child_below_sibling(this.actor, windowActor);
if (this._rect && this._rect.equal(tileRect))
return;
let changeMonitor = (this._monitorIndex == -1 ||
this._monitorIndex != monitorIndex);
this._monitorIndex = monitorIndex;
this._rect = tileRect;
let monitor = Main.layoutManager.monitors[monitorIndex];
this._updateStyle(monitor);
if (!this._showing || changeMonitor) {
let monitorRect = new Meta.Rectangle({ x: monitor.x,
y: monitor.y,
width: monitor.width,
height: monitor.height });
let [, rect] = window.get_outer_rect().intersect(monitorRect);
this.actor.set_size(rect.width, rect.height);
this.actor.set_position(rect.x, rect.y);
this.actor.opacity = 0;
}
this._showing = true;
this.actor.show();
Tweener.addTween(this.actor,
{ x: tileRect.x,
y: tileRect.y,
width: tileRect.width,
height: tileRect.height,
opacity: 255,
time: WINDOW_ANIMATION_TIME,
transition: 'easeOutQuad'
});
},
hide: function() {
if (!this._showing)
return;
this._showing = false;
Tweener.addTween(this.actor,
{ opacity: 0,
time: WINDOW_ANIMATION_TIME,
transition: 'easeOutQuad',
onComplete: Lang.bind(this, this._reset)
});
},
_reset: function() {
this.actor.hide();
this._rect = null;
this._monitorIndex = -1;
},
_updateStyle: function(monitor) {
let styles = ['tile-preview'];
if (this._monitorIndex == Main.layoutManager.primaryIndex)
styles.push('on-primary');
if (this._rect.x == monitor.x)
styles.push('tile-preview-left');
if (this._rect.x + this._rect.width == monitor.x + monitor.width)
styles.push('tile-preview-right');
this.actor.style_class = styles.join(' ');
}
});
const WorkspaceSwitchAction = new Lang.Class({
Name: 'WorkspaceSwitchAction',
Extends: Clutter.GestureAction,
_init : function() {
this.parent();
this.set_n_touch_points(4);
global.display.connect('grab-op-begin', Lang.bind(this, function() {
this.cancel();
}));
},
vfunc_gesture_prepare : function(action, actor) {
return this.get_n_current_points() == this.get_n_touch_points();
},
vfunc_gesture_end : function(action, actor) {
const MOTION_THRESHOLD = 50;
// Just check one touchpoint here
let [startX, startY] = this.get_press_coords(0);
let [x, y] = this.get_motion_coords(0);
let offsetX = x - startX;
let offsetY = y - startY;
let direction;
if (Math.abs(offsetX) < MOTION_THRESHOLD &&
Math.abs(offsetY) < MOTION_THRESHOLD)
return;
if (Math.abs(offsetY) > Math.abs(offsetX)) {
if (offsetY > 0)
direction = Meta.MotionDirection.UP;
else
direction = Meta.MotionDirection.DOWN;
} else {
if (offsetX > 0)
direction = Meta.MotionDirection.LEFT;
else
direction = Meta.MotionDirection.RIGHT;
}
this.emit('activated', direction);
}
});
Signals.addSignalMethods(WorkspaceSwitchAction.prototype);
const AppSwitchAction = new Lang.Class({
Name: 'AppSwitchAction',
Extends: Clutter.GestureAction,
_init : function() {
this.parent();
this.set_n_touch_points(3);
global.display.connect('grab-op-begin', Lang.bind(this, function() {
this.cancel();
}));
},
vfunc_gesture_prepare : function(action, actor) {
if (Main.overview.visible) {
this.cancel();
return false;
}
return this.get_n_current_points() <= 4;
},
vfunc_gesture_begin : function(action, actor) {
// in milliseconds
const LONG_PRESS_TIMEOUT = 250;
let nPoints = this.get_n_current_points();
let event = this.get_last_event (nPoints - 1);
if (nPoints == 3)
this._longPressStartTime = event.get_time();
else if (nPoints == 4) {
// Check whether the 4th finger press happens after a 3-finger long press,
// this only needs to be checked on the first 4th finger press
if (this._longPressStartTime != null &&
event.get_time() < this._longPressStartTime + LONG_PRESS_TIMEOUT)
this.cancel();
else {
this._longPressStartTime = null;
this.emit('activated');
}
}
return this.get_n_current_points() <= 4;
},
vfunc_gesture_progress : function(action, actor) {
const MOTION_THRESHOLD = 30;
if (this.get_n_current_points() == 3) {
for (let i = 0; i < this.get_n_current_points(); i++) {
[startX, startY] = this.get_press_coords(i);
[x, y] = this.get_motion_coords(i);
if (Math.abs(x - startX) > MOTION_THRESHOLD ||
Math.abs(y - startY) > MOTION_THRESHOLD)
return false;
}
}
return true;
}
});
Signals.addSignalMethods(AppSwitchAction.prototype);
const WindowManager = new Lang.Class({
Name: 'WindowManager',
@ -383,8 +593,6 @@ const WindowManager = new Lang.Class({
this._dimmedWindows = [];
this._animationBlockCount = 0;
this._allowedKeybindings = {};
this._switchData = null;
@ -398,6 +606,9 @@ const WindowManager = new Lang.Class({
}));
this._shellwm.connect('switch-workspace', Lang.bind(this, this._switchWorkspace));
this._shellwm.connect('show-tile-preview', Lang.bind(this, this._showTilePreview));
this._shellwm.connect('hide-tile-preview', Lang.bind(this, this._hideTilePreview));
this._shellwm.connect('show-window-menu', Lang.bind(this, this._showWindowMenu));
this._shellwm.connect('minimize', Lang.bind(this, this._minimizeWindow));
this._shellwm.connect('maximize', Lang.bind(this, this._maximizeWindow));
this._shellwm.connect('unmaximize', Lang.bind(this, this._unmaximizeWindow));
@ -407,6 +618,8 @@ const WindowManager = new Lang.Class({
this._shellwm.connect('confirm-display-change', Lang.bind(this, this._confirmDisplayChange));
this._workspaceSwitcherPopup = null;
this._tilePreview = null;
this.setCustomKeybindingHandler('switch-to-workspace-left',
Shell.KeyBindingMode.NORMAL |
Shell.KeyBindingMode.OVERVIEW,
@ -423,6 +636,10 @@ const WindowManager = new Lang.Class({
Shell.KeyBindingMode.NORMAL |
Shell.KeyBindingMode.OVERVIEW,
Lang.bind(this, this._showWorkspaceSwitcher));
this.setCustomKeybindingHandler('switch-to-workspace-last',
Shell.KeyBindingMode.NORMAL |
Shell.KeyBindingMode.OVERVIEW,
Lang.bind(this, this._showWorkspaceSwitcher));
this.setCustomKeybindingHandler('move-to-workspace-left',
Shell.KeyBindingMode.NORMAL |
Shell.KeyBindingMode.OVERVIEW,
@ -523,6 +740,9 @@ const WindowManager = new Lang.Class({
this.setCustomKeybindingHandler('move-to-workspace-12',
Shell.KeyBindingMode.NORMAL,
Lang.bind(this, this._showWorkspaceSwitcher));
this.setCustomKeybindingHandler('move-to-workspace-last',
Shell.KeyBindingMode.NORMAL,
Lang.bind(this, this._showWorkspaceSwitcher));
this.setCustomKeybindingHandler('switch-applications',
Shell.KeyBindingMode.NORMAL,
Lang.bind(this, this._startAppSwitcher));
@ -557,13 +777,13 @@ const WindowManager = new Lang.Class({
Lang.bind(this, this._startA11ySwitcher));
this.addKeybinding('pause-resume-tweens',
new Gio.Settings({ schema: SHELL_KEYBINDINGS_SCHEMA }),
new Gio.Settings({ schema_id: SHELL_KEYBINDINGS_SCHEMA }),
Meta.KeyBindingFlags.NONE,
Shell.KeyBindingMode.ALL,
Lang.bind(this, this._toggleTweens));
this.addKeybinding('open-application-menu',
new Gio.Settings({ schema: SHELL_KEYBINDINGS_SCHEMA }),
new Gio.Settings({ schema_id: SHELL_KEYBINDINGS_SCHEMA }),
Meta.KeyBindingFlags.NONE,
Shell.KeyBindingMode.NORMAL |
Shell.KeyBindingMode.TOPBAR_POPUP,
@ -578,11 +798,60 @@ const WindowManager = new Lang.Class({
this._dimWindow(this._dimmedWindows[i]);
}));
this._windowMenuManager = new WindowMenu.WindowMenuManager();
if (Main.sessionMode.hasWorkspaces)
this._workspaceTracker = new WorkspaceTracker(this);
global.screen.override_workspace_layout(Meta.ScreenCorner.TOPLEFT,
false, -1, 1);
let gesture = new WorkspaceSwitchAction();
gesture.connect('activated', Lang.bind(this, function(action, direction) {
let newWs = global.screen.get_active_workspace().get_neighbor(direction);
this.actionMoveWorkspace(newWs);
}));
global.stage.add_action(gesture);
gesture = new AppSwitchAction();
gesture.connect('activated', Lang.bind(this, this._switchApp));
global.stage.add_action(gesture);
},
_lookupIndex: function (windows, metaWindow) {
for (let i = 0; i < windows.length; i++) {
if (windows[i].metaWindow == metaWindow) {
return i;
}
}
return -1;
},
_switchApp : function () {
let windows = global.get_window_actors().filter(Lang.bind(this, function(actor) {
let win = actor.metaWindow;
return (!win.is_override_redirect() &&
win.located_on_workspace(global.screen.get_active_workspace()));
}));
if (windows.length == 0)
return;
let focusWindow = global.display.focus_window;
let nextWindow;
if (focusWindow == null)
nextWindow = windows[0].metaWindow;
else {
let index = this._lookupIndex (windows, focusWindow) + 1;
if (index >= windows.length)
index = 0;
nextWindow = windows[index].metaWindow;
}
Main.activateWindow(nextWindow);
},
keepWorkspaceAlive: function(workspace, duration) {
@ -613,24 +882,16 @@ const WindowManager = new Lang.Class({
this._allowedKeybindings[name] = modes;
},
blockAnimations: function() {
this._animationBlockCount++;
},
unblockAnimations: function() {
this._animationBlockCount = Math.max(0, this._animationBlockCount - 1);
},
_shouldAnimate: function() {
return !(Main.overview.visible || this._animationBlockCount > 0);
return !Main.overview.visible;
},
_shouldAnimateActor: function(actor) {
_shouldAnimateActor: function(actor, types) {
if (!this._shouldAnimate())
return false;
let windowType = actor.meta_window.get_window_type();
return windowType == Meta.WindowType.NORMAL ||
windowType == Meta.WindowType.MODAL_DIALOG;
let type = actor.meta_window.get_window_type();
return types.indexOf(type) >= 0;
},
_removeEffect : function(list, actor) {
@ -643,7 +904,10 @@ const WindowManager = new Lang.Class({
},
_minimizeWindow : function(shellwm, actor) {
if (!this._shouldAnimateActor(actor)) {
let types = [Meta.WindowType.NORMAL,
Meta.WindowType.MODAL_DIALOG,
Meta.WindowType.DIALOG];
if (!this._shouldAnimateActor(actor, types)) {
shellwm.completed_minimize(actor);
return;
}
@ -655,7 +919,7 @@ const WindowManager = new Lang.Class({
if (actor.meta_window.is_monitor_sized()) {
Tweener.addTween(actor,
{ opacity: 0,
time: WINDOW_ANIMATION_TIME,
time: MINIMIZE_WINDOW_ANIMATION_TIME,
transition: 'easeOutQuad',
onComplete: this._minimizeWindowDone,
onCompleteScope: this,
@ -687,8 +951,8 @@ const WindowManager = new Lang.Class({
scale_y: yScale,
x: xDest,
y: yDest,
time: WINDOW_ANIMATION_TIME,
transition: 'easeOutQuad',
time: MINIMIZE_WINDOW_ANIMATION_TIME,
transition: 'easeInExpo',
onComplete: this._minimizeWindowDone,
onCompleteScope: this,
onCompleteParams: [shellwm, actor],
@ -704,7 +968,7 @@ const WindowManager = new Lang.Class({
Tweener.removeTweens(actor);
actor.set_scale(1.0, 1.0);
actor.set_opacity(255);
actor.move_anchor_point_from_gravity(Clutter.Gravity.NORTH_WEST);
actor.set_pivot_point(0, 0);
shellwm.completed_minimize(actor);
}
@ -802,7 +1066,10 @@ const WindowManager = new Lang.Class({
actor._windowType = type;
}));
if (!this._shouldAnimateActor(actor)) {
let types = [Meta.WindowType.NORMAL,
Meta.WindowType.DIALOG,
Meta.WindowType.MODAL_DIALOG];
if (!this._shouldAnimateActor(actor, types)) {
shellwm.completed_map(actor);
return;
}
@ -810,15 +1077,23 @@ const WindowManager = new Lang.Class({
if (actor.meta_window.is_attached_dialog()) {
/* Scale the window from the center of the parent */
this._checkDimming(actor.get_meta_window().get_transient_for());
actor.set_scale(1.0, 0.0);
actor.scale_gravity = Clutter.Gravity.CENTER;
}
switch (actor._windowType) {
case Meta.WindowType.NORMAL:
actor.set_pivot_point(0.5, 1.0);
actor.scale_x = 0.01;
actor.scale_y = 0.05;
actor.opacity = 0;
actor.show();
this._mapping.push(actor);
Tweener.addTween(actor,
{ scale_y: 1,
time: WINDOW_ANIMATION_TIME,
transition: "easeOutQuad",
{ opacity: 255,
scale_x: 1,
scale_y: 1,
time: SHOW_WINDOW_ANIMATION_TIME,
transition: 'easeOutExpo',
onComplete: this._mapWindowDone,
onCompleteScope: this,
onCompleteParams: [shellwm, actor],
@ -826,15 +1101,20 @@ const WindowManager = new Lang.Class({
onOverwriteScope: this,
onOverwriteParams: [shellwm, actor]
});
} else {
/* Fade window in */
break;
case Meta.WindowType.MODAL_DIALOG:
case Meta.WindowType.DIALOG:
actor.set_pivot_point(0.5, 0.5);
actor.scale_y = 0;
actor.opacity = 0;
actor.show();
this._mapping.push(actor);
Tweener.addTween(actor,
{ opacity: 255,
time: WINDOW_ANIMATION_TIME,
scale_x: 1,
scale_y: 1,
time: DIALOG_SHOW_WINDOW_ANIMATION_TIME,
transition: 'easeOutQuad',
onComplete: this._mapWindowDone,
onCompleteScope: this,
@ -843,6 +1123,10 @@ const WindowManager = new Lang.Class({
onOverwriteScope: this,
onOverwriteParams: [shellwm, actor]
});
break;
default:
shellwm.completed_map(actor);
return;
}
},
@ -850,7 +1134,11 @@ const WindowManager = new Lang.Class({
if (this._removeEffect(this._mapping, actor)) {
Tweener.removeTweens(actor);
actor.opacity = 255;
actor.set_pivot_point(0, 0);
actor.scale_y = 1;
actor.scale_x = 1;
actor.translation_y = 0;
actor.translation_x = 0;
shellwm.completed_map(actor);
}
},
@ -873,30 +1161,25 @@ const WindowManager = new Lang.Class({
});
}
if (!this._shouldAnimateActor(actor)) {
let types = [Meta.WindowType.NORMAL,
Meta.WindowType.DIALOG,
Meta.WindowType.MODAL_DIALOG];
if (!this._shouldAnimateActor(actor, types)) {
shellwm.completed_destroy(actor);
return;
}
this._destroying.push(actor);
if (window.is_attached_dialog()) {
let parent = window.get_transient_for();
this._checkDimming(parent, window);
actor.set_scale(1.0, 1.0);
actor.scale_gravity = Clutter.Gravity.CENTER;
actor.show();
actor._parentDestroyId = parent.connect('unmanaged', Lang.bind(this, function () {
Tweener.removeTweens(actor);
this._destroyWindowDone(shellwm, actor);
}));
switch (actor._windowType) {
case Meta.WindowType.NORMAL:
actor.set_pivot_point(0.5, 0.5);
this._destroying.push(actor);
Tweener.addTween(actor,
{ scale_y: 0,
time: WINDOW_ANIMATION_TIME,
transition: "easeOutQuad",
{ opacity: 0,
scale_x: 0.8,
scale_y: 0.8,
time: DESTROY_WINDOW_ANIMATION_TIME,
transition: 'easeOutQuad',
onComplete: this._destroyWindowDone,
onCompleteScope: this,
onCompleteParams: [shellwm, actor],
@ -904,9 +1187,37 @@ const WindowManager = new Lang.Class({
onOverwriteScope: this,
onOverwriteParams: [shellwm, actor]
});
break;
case Meta.WindowType.MODAL_DIALOG:
case Meta.WindowType.DIALOG:
actor.set_pivot_point(0.5, 0.5);
this._destroying.push(actor);
if (window.is_attached_dialog()) {
let parent = window.get_transient_for();
this._checkDimming(parent, window);
actor._parentDestroyId = parent.connect('unmanaged', Lang.bind(this, function () {
Tweener.removeTweens(actor);
this._destroyWindowDone(shellwm, actor);
}));
}
Tweener.addTween(actor,
{ scale_y: 0,
time: DIALOG_DESTROY_WINDOW_ANIMATION_TIME,
transition: 'easeOutQuad',
onComplete: this._destroyWindowDone,
onCompleteScope: this,
onCompleteParams: [shellwm, actor],
onOverwrite: this._destroyWindowDone,
onOverwriteScope: this,
onOverwriteParams: [shellwm, actor]
});
break;
default:
shellwm.completed_destroy(actor);
return;
}
shellwm.completed_destroy(actor);
},
_destroyWindowDone : function(shellwm, actor) {
@ -1056,6 +1367,22 @@ const WindowManager = new Lang.Class({
shellwm.completed_switch_workspace();
},
_showTilePreview: function(shellwm, window, tileRect, monitorIndex) {
if (!this._tilePreview)
this._tilePreview = new TilePreview();
this._tilePreview.show(window, tileRect, monitorIndex);
},
_hideTilePreview: function(shellwm) {
if (!this._tilePreview)
return;
this._tilePreview.hide();
},
_showWindowMenu: function(shellwm, window, menu, rect) {
this._windowMenuManager.showWindowMenuForWindow(window, menu, rect);
},
_startAppSwitcher : function(display, screen, window, binding) {
/* prevent a corner case where both popups show up at once */
if (this._workspaceSwitcherPopup != null)
@ -1063,9 +1390,7 @@ const WindowManager = new Lang.Class({
let tabPopup = new AltTab.AppSwitcherPopup();
let modifiers = binding.get_modifiers();
let backwards = modifiers & Meta.VirtualModifier.SHIFT_MASK;
if (!tabPopup.show(backwards, binding.get_name(), binding.get_mask()))
if (!tabPopup.show(binding.is_reversed(), binding.get_name(), binding.get_mask()))
tabPopup.destroy();
},
@ -1076,16 +1401,12 @@ const WindowManager = new Lang.Class({
let tabPopup = new AltTab.WindowSwitcherPopup();
let modifiers = binding.get_modifiers();
let backwards = modifiers & Meta.VirtualModifier.SHIFT_MASK;
if (!tabPopup.show(backwards, binding.get_name(), binding.get_mask()))
if (!tabPopup.show(binding.is_reversed(), binding.get_name(), binding.get_mask()))
tabPopup.destroy();
},
_startA11ySwitcher : function(display, screen, window, binding) {
let modifiers = binding.get_modifiers();
let backwards = modifiers & Meta.VirtualModifier.SHIFT_MASK;
Main.ctrlAltTabManager.popup(backwards, binding.get_name(), binding.get_mask());
Main.ctrlAltTabManager.popup(binding.is_reversed(), binding.get_name(), binding.get_mask());
},
_toggleAppMenu : function(display, screen, window, event, binding) {
@ -1112,7 +1433,10 @@ const WindowManager = new Lang.Class({
let newWs;
let direction;
if (isNaN(target)) {
if (target == 'last') {
direction = Meta.MotionDirection.DOWN;
newWs = screen.get_workspace_by_index(screen.n_workspaces - 1);
} else if (isNaN(target)) {
direction = Meta.MotionDirection[target.toUpperCase()];
newWs = screen.get_active_workspace().get_neighbor(direction);
} else if (target > 0) {

185
js/ui/windowMenu.js Normal file
View File

@ -0,0 +1,185 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*
const Gtk = imports.gi.Gtk;
const Lang = imports.lang;
const Meta = imports.gi.Meta;
const St = imports.gi.St;
const Shell = imports.gi.Shell;
const BoxPointer = imports.ui.boxpointer;
const Main = imports.ui.main;
const PopupMenu = imports.ui.popupMenu;
const RemoteMenu = imports.ui.remoteMenu;
const WindowMenu = new Lang.Class({
Name: 'WindowMenu',
Extends: PopupMenu.PopupMenu,
_init: function(window, sourceActor) {
this.parent(sourceActor, 0, St.Side.TOP);
this.actor.add_style_class_name('window-menu');
Main.layoutManager.uiGroup.add_actor(this.actor);
this.actor.hide();
this._buildMenu(window);
},
_buildMenu: function(window) {
let type = window.get_window_type();
let item;
item = this.addAction(_("Minimize"), Lang.bind(this, function(event) {
window.minimize();
}));
if (!window.can_minimize())
item.setSensitive(false);
if (window.get_maximized()) {
item = this.addAction(_("Unmaximize"), Lang.bind(this, function() {
window.unmaximize(Meta.MaximizeFlags.BOTH);
}));
} else {
item = this.addAction(_("Maximize"), Lang.bind(this, function() {
window.maximize(Meta.MaximizeFlags.BOTH);
}));
}
if (!window.can_maximize())
item.setSensitive(false);
item = this.addAction(_("Move"), Lang.bind(this, function(event) {
window.begin_grab_op(Meta.GrabOp.KEYBOARD_MOVING, true, event.get_time());
}));
if (!window.allows_move())
item.setSensitive(false);
item = this.addAction(_("Resize"), Lang.bind(this, function(event) {
window.begin_grab_op(Meta.GrabOp.KEYBOARD_RESIZING_UNKNOWN, true, event.get_time());
}));
if (!window.allows_resize())
item.setSensitive(false);
if (!window.titlebar_is_onscreen() && type != Meta.WindowType.DOCK && type != Meta.WindowType.DESKTOP) {
this.addAction(_("Move Titlebar Onscreen"), Lang.bind(this, function(event) {
window.shove_titlebar_onscreen();
}));
}
item = this.addAction(_("Always on Top"), Lang.bind(this, function() {
if (window.is_above())
window.unmake_above();
else
window.make_above();
}));
if (window.is_above())
item.setOrnament(PopupMenu.Ornament.DOT);
if (window.get_maximized() ||
type == Meta.WindowType.DOCK ||
type == Meta.WindowType.DESKTOP ||
type == Meta.WindowType.SPLASHSCREEN)
item.setSensitive(false);
if (Main.sessionMode.hasWorkspaces &&
(!Meta.prefs_get_workspaces_only_on_primary() ||
window.is_on_primary_monitor())) {
let isSticky = window.is_on_all_workspaces();
item = this.addAction(_("Always on Visible Workspace"), Lang.bind(this, function() {
if (isSticky)
window.unstick();
else
window.stick();
}));
if (isSticky)
item.setOrnament(PopupMenu.Ornament.DOT);
if (window.is_always_on_all_workspaces())
item.setSensitive(false);
let nWorkspaces = global.screen.n_workspaces;
if (!isSticky) {
let workspace = window.get_workspace();
let idx = workspace.index();
if (idx > 0) {
this.addAction(_("Move to Workspace Up"), Lang.bind(this, function(event) {
window.change_workspace(workspace.get_neighbor(Meta.MotionDirection.UP));
}));
}
if (idx < nWorkspaces) {
this.addAction(_("Move to Workspace Down"), Lang.bind(this, function(event) {
window.change_workspace(workspace.get_neighbor(Meta.MotionDirection.DOWN));
}));
}
}
}
this.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
item = this.addAction(_("Close"), Lang.bind(this, function(event) {
window.delete(event.get_time());
}));
if (!window.can_close())
item.setSensitive(false);
}
});
const AppMenu = new Lang.Class({
Name: 'AppMenu',
Extends: RemoteMenu.RemoteMenu,
_init: function(window, sourceActor) {
let app = Shell.WindowTracker.get_default().get_window_app(window);
this.parent(sourceActor, app.menu, app.action_group);
this.actor.add_style_class_name('fallback-app-menu');
let variant = window.get_gtk_theme_variant();
if (variant)
this.actor.add_style_class_name(variant);
Main.layoutManager.uiGroup.add_actor(this.actor);
this.actor.hide();
}
});
const WindowMenuManager = new Lang.Class({
Name: 'WindowMenuManager',
_init: function() {
this._manager = new PopupMenu.PopupMenuManager({ actor: Main.layoutManager.dummyCursor });
this._sourceActor = new St.Widget({ reactive: true, visible: false });
this._sourceActor.connect('button-press-event', Lang.bind(this,
function() {
this._manager.activeMenu.toggle();
}));
Main.uiGroup.add_actor(this._sourceActor);
},
showWindowMenuForWindow: function(window, type, rect) {
let menuType = (type == Meta.WindowMenuType.WM) ? WindowMenu : AppMenu;
let menu = new menuType(window, this._sourceActor);
this._manager.addMenu(menu);
menu.connect('activate', function() {
window.check_alive(global.get_current_time());
});
this._sourceActor.set_size(rect.width, rect.height);
this._sourceActor.set_position(rect.x, rect.y);
this._sourceActor.show();
menu.open(BoxPointer.PopupAnimation.NONE);
menu.actor.navigate_focus(null, Gtk.DirectionType.TAB_FORWARD, false);
menu.connect('open-state-changed', Lang.bind(this, function(menu_, isOpen) {
if (isOpen)
return;
this._sourceActor.hide();
menu.destroy();
}));
}
});

View File

@ -8,6 +8,8 @@ const Meta = imports.gi.Meta;
const Pango = imports.gi.Pango;
const Shell = imports.gi.Shell;
const St = imports.gi.St;
const Atk = imports.gi.Atk;
const Signals = imports.signals;
const DND = imports.ui.dnd;
@ -32,6 +34,8 @@ const DRAGGING_WINDOW_OPACITY = 100;
const LAYOUT_SCALE_WEIGHT = 1;
const LAYOUT_SPACE_WEIGHT = 0.1;
const WINDOW_ANIMATION_MAX_NUMBER_BLENDING = 3;
function _interpolate(start, end, step) {
return start + (end - start) * step;
}
@ -65,7 +69,7 @@ const WindowCloneLayout = new Lang.Class({
// paradoxically is the smaller rectangle, containing the positions
// of the visible frame. The input rect contains everything,
// including the invisible border padding.
let inputRect = window.get_input_rect();
let inputRect = window.get_buffer_rect();
let box = new Clutter.ActorBox();
@ -85,7 +89,7 @@ const WindowCloneLayout = new Lang.Class({
},
vfunc_allocate: function(container, box, flags) {
let clone = container.get_children().forEach(function (child) {
container.get_children().forEach(Lang.bind(this, function (child) {
let realWindow;
if (child == container._delegate._windowClone)
realWindow = container._delegate.realWindow;
@ -94,8 +98,8 @@ const WindowCloneLayout = new Lang.Class({
child.allocate(this._makeBoxForWindow(realWindow.meta_window),
flags);
}, this);
},
}));
}
});
const WindowClone = new Lang.Class({
@ -121,6 +125,7 @@ const WindowClone = new Lang.Class({
// the hierarchy that is sized to only the visible portion.
this.actor = new St.Widget({ reactive: true,
can_focus: true,
accessible_role: Atk.Role.PUSH_BUTTON,
layout_manager: new WindowCloneLayout() });
this.actor.add_child(this._windowClone);
@ -131,7 +136,7 @@ const WindowClone = new Lang.Class({
this._dragSlot = [0, 0, 0, 0];
this._stackAbove = null;
this._windowClone._updateId = this.realWindow.connect('size-changed',
this._windowClone._updateId = this.metaWindow.connect('size-changed',
Lang.bind(this, this._onRealWindowSizeChanged));
this._windowClone._destroyId = this.realWindow.connect('destroy', Lang.bind(this, function() {
// First destroy the clone and then destroy everything
@ -197,9 +202,13 @@ const WindowClone = new Lang.Class({
this.emit('size-changed');
},
hasAttachedDialogs: function() {
return this.actor.get_n_children() > 1;
},
_doAddAttachedDialog: function(metaWin, realWin) {
let clone = new Clutter.Clone({ source: realWin });
clone._updateId = realWin.connect('size-changed', Lang.bind(this, function() {
clone._updateId = metaWin.connect('size-changed', Lang.bind(this, function() {
this._computeBoundingBox();
this.emit('size-changed');
}));
@ -232,6 +241,14 @@ const WindowClone = new Lang.Class({
return this._boundingBox;
},
get width() {
return this._boundingBox.width;
},
get height() {
return this._boundingBox.height;
},
getOriginalPosition: function() {
return [this._boundingBox.x, this._boundingBox.y];
},
@ -250,7 +267,8 @@ const WindowClone = new Lang.Class({
rect = rect.union(metaWindow.get_outer_rect());
}, this);
this._boundingBox = rect;
// Convert from a MetaRectangle to a native JS object
this._boundingBox = { x: rect.x, y: rect.y, width: rect.width, height: rect.height };
this.actor.layout_manager.boundingBox = rect;
},
@ -295,7 +313,7 @@ const WindowClone = new Lang.Class({
else
realWindow = child.source;
realWindow.disconnect(child._updateId);
realWindow.meta_window.disconnect(child._updateId);
realWindow.disconnect(child._destroyId);
}));
},
@ -424,6 +442,7 @@ const WindowOverlay = new Lang.Class({
text: metaWindow.title });
title.clutter_text.ellipsize = Pango.EllipsizeMode.END;
title._spacing = 0;
windowClone.actor.label_actor = title;
this._updateCaptionId = metaWindow.connect('notify::title',
Lang.bind(this, function(w) {
@ -500,6 +519,7 @@ const WindowOverlay = new Lang.Class({
Tweener.removeTweens(button);
Tweener.removeTweens(border);
Tweener.removeTweens(title);
let [cloneX, cloneY, cloneWidth, cloneHeight] = this._windowClone.slot;
@ -578,7 +598,8 @@ const WindowOverlay = new Lang.Class({
},
_windowCanClose: function() {
return this._windowClone.metaWindow.can_close();
return this._windowClone.metaWindow.can_close() &&
!this._windowClone.hasAttachedDialogs();
},
_onWindowAdded: function(workspace, win) {
@ -590,11 +611,12 @@ const WindowOverlay = new Lang.Class({
// use an idle handler to avoid mapping problems -
// see comment in Workspace._windowAdded
Mainloop.idle_add(Lang.bind(this,
function() {
this._windowClone.emit('selected');
return GLib.SOURCE_REMOVE;
}));
let id = Mainloop.idle_add(Lang.bind(this,
function() {
this._windowClone.emit('selected');
return GLib.SOURCE_REMOVE;
}));
GLib.Source.set_name_by_id(id, '[gnome-shell] this._windowClone.emit');
}
},
@ -665,8 +687,10 @@ const WindowOverlay = new Lang.Class({
},
_onLeave: function() {
if (this._idleToggleCloseId == 0)
if (this._idleToggleCloseId == 0) {
this._idleToggleCloseId = Mainloop.timeout_add(750, Lang.bind(this, this._idleToggleCloseButton));
GLib.Source.set_name_by_id(this._idleToggleCloseId, '[gnome-shell] this._idleToggleCloseButton');
}
return Clutter.EVENT_PROPAGATE;
},
@ -820,7 +844,7 @@ const LayoutStrategy = new Lang.Class({
// thumbnails is much more important to preserve than the width of
// them, so two windows with equal height, but maybe differering
// widths line up.
let ratio = window.actor.height / this._monitor.height;
let ratio = window.height / this._monitor.height;
// The purpose of this manipulation here is to prevent windows
// from getting too small. For something like a calculator window,
@ -922,11 +946,11 @@ const LayoutStrategy = new Lang.Class({
let window = row.windows[j];
let s = scale * this._computeWindowScale(window) * row.additionalScale;
let cellWidth = window.actor.width * s;
let cellHeight = window.actor.height * s;
let cellWidth = window.width * s;
let cellHeight = window.height * s;
s = Math.min(s, WINDOW_CLONE_MAXIMUM_SCALE);
let cloneWidth = window.actor.width * s;
let cloneWidth = window.width * s;
let cloneX = x + (cellWidth - cloneWidth) / 2;
let cloneY = row.y + row.height - cellHeight;
@ -980,7 +1004,7 @@ const UnalignedLayoutStrategy = new Lang.Class({
for (let i = 0; i < windows.length; i++) {
let window = windows[i];
let s = this._computeWindowScale(window);
totalWidth += window.actor.width * s;
totalWidth += window.width * s;
}
let idealRowWidth = totalWidth / numRows;
@ -993,8 +1017,8 @@ const UnalignedLayoutStrategy = new Lang.Class({
for (; windowIdx < windows.length; windowIdx++) {
let window = windows[windowIdx];
let s = this._computeWindowScale(window);
let width = window.actor.width * s;
let height = window.actor.height * s;
let width = window.width * s;
let height = window.height * s;
row.fullHeight = Math.max(row.fullHeight, height);
// either new width is < idealWidth or new width is nearer from idealWidth then oldWidth
@ -1119,6 +1143,11 @@ const Workspace = new Lang.Class({
this._positionWindowsFlags = 0;
this._positionWindowsId = 0;
this.actor.connect('notify::mapped', Lang.bind(this, function() {
if (this.actor.mapped)
this._syncActualGeometry();
}));
},
setFullGeometry: function(geom) {
@ -1126,7 +1155,9 @@ const Workspace = new Lang.Class({
return;
this._fullGeometry = geom;
this._recalculateWindowPositions(WindowPositionFlags.NONE);
if (this.actor.mapped)
this._recalculateWindowPositions(WindowPositionFlags.NONE);
},
setActualGeometry: function(geom) {
@ -1134,18 +1165,29 @@ const Workspace = new Lang.Class({
return;
this._actualGeometry = geom;
this._actualGeometryDirty = true;
if (this._actualGeometryLater)
if (this.actor.mapped)
this._syncActualGeometry();
},
_syncActualGeometry: function() {
if (this._actualGeometryLater || !this._actualGeometryDirty)
return;
if (!this._actualGeometry)
return;
this._actualGeometryLater = Meta.later_add(Meta.LaterType.BEFORE_REDRAW, Lang.bind(this, function() {
this._actualGeometryLater = 0;
if (!this.actor.mapped)
return false;
let geom = this._actualGeometry;
this._dropRect.set_position(geom.x, geom.y);
this._dropRect.set_size(geom.width, geom.height);
this._updateWindowPositions(Main.overview.animationInProgress ? WindowPositionFlags.ANIMATE : WindowPositionFlags.NONE);
this._actualGeometryLater = 0;
return false;
}));
},
@ -1167,14 +1209,18 @@ const Workspace = new Lang.Class({
return this._windows.length == 0;
},
setReservedSlot: function(clone) {
if (this._reservedSlot == clone)
setReservedSlot: function(metaWindow) {
if (this._reservedSlotWindow == metaWindow)
return;
if (clone && this.containsMetaWindow(clone.metaWindow))
clone = null;
if (!metaWindow || this.containsMetaWindow(metaWindow)) {
this._reservedSlotWindow = null;
this._reservedSlot = null;
} else {
this._reservedSlotWindow = metaWindow;
this._reservedSlot = this._windows[this._lookupIndex(metaWindow)];
}
this._reservedSlot = clone;
this._recalculateWindowPositions(WindowPositionFlags.ANIMATE);
},
@ -1219,6 +1265,13 @@ const Workspace = new Lang.Class({
return;
}
// We will reposition windows anyway when enter again overview or when ending the windows
// animations whith fade animation.
// In this way we avoid unwanted animations of windows repositioning while
// animating overview.
if (this.leavingOverview || this._animatingWindowsFade)
return;
let initialPositioning = flags & WindowPositionFlags.INITIAL;
let animate = flags & WindowPositionFlags.ANIMATE;
@ -1281,7 +1334,7 @@ const Workspace = new Lang.Class({
});
}
this._animateClone(clone, overlay, x, y, scale, initialPositioning);
this._animateClone(clone, overlay, x, y, scale);
} else {
// cancel any active tweens (otherwise they might override our changes)
Tweener.removeTweens(clone.actor);
@ -1310,7 +1363,7 @@ const Workspace = new Lang.Class({
}
},
_animateClone: function(clone, overlay, x, y, scale, initialPositioning) {
_animateClone: function(clone, overlay, x, y, scale) {
Tweener.addTween(clone.actor,
{ x: x,
y: y,
@ -1368,10 +1421,6 @@ const Workspace = new Lang.Class({
if (index == -1)
return;
// Check if window still should be here
if (win && this._isMyWindow(win))
return;
let clone = this._windows[index];
this._windows.splice(index, 1);
@ -1414,6 +1463,7 @@ const Workspace = new Lang.Class({
this._currentLayout = null;
this._repositionWindowsId = Mainloop.timeout_add(750,
Lang.bind(this, this._delayedWindowRepositioning));
GLib.Source.set_name_by_id(this._repositionWindowsId, '[gnome-shell] this._delayedWindowRepositioning');
},
_doAddWindow : function(metaWin) {
@ -1425,14 +1475,15 @@ const Workspace = new Lang.Class({
if (!win) {
// Newly-created windows are added to a workspace before
// the compositor finds out about them...
Mainloop.idle_add(Lang.bind(this,
function () {
if (this.actor &&
metaWin.get_compositor_private() &&
metaWin.get_workspace() == this.metaWorkspace)
this._doAddWindow(metaWin);
return GLib.SOURCE_REMOVE;
}));
let id = Mainloop.idle_add(Lang.bind(this,
function () {
if (this.actor &&
metaWin.get_compositor_private() &&
metaWin.get_workspace() == this.metaWorkspace)
this._doAddWindow(metaWin);
return GLib.SOURCE_REMOVE;
}));
GLib.Source.set_name_by_id(id, '[gnome-shell] this._doAddWindow');
return;
}
@ -1515,14 +1566,141 @@ const Workspace = new Lang.Class({
return false;
},
// Animate the full-screen to Overview transition.
zoomToOverview : function() {
fadeToOverview: function() {
// We don't want to reposition windows while animating in this way.
this._animatingWindowsFade = true;
this._overviewShownId = Main.overview.connect('shown', Lang.bind(this,
this._doneShowingOverview));
if (this._windows.length == 0)
return;
if (this.metaWorkspace != null && this.metaWorkspace != global.screen.get_active_workspace())
return;
// Special case maximized windows, since it doesn't make sense
// to animate windows below in the stack
let topMaximizedWindow;
// It is ok to treat the case where there is no maximized
// window as if the bottom-most window was maximized given that
// it won't affect the result of the animation
for (topMaximizedWindow = this._windows.length - 1; topMaximizedWindow > 0; topMaximizedWindow--) {
let metaWindow = this._windows[topMaximizedWindow].metaWindow;
if (metaWindow.maximized_horizontally && metaWindow.maximized_vertically)
break;
}
let nTimeSlots = Math.min(WINDOW_ANIMATION_MAX_NUMBER_BLENDING + 1, this._windows.length - topMaximizedWindow);
let windowBaseTime = Overview.ANIMATION_TIME / nTimeSlots;
let topIndex = this._windows.length - 1;
for (let i = 0; i < this._windows.length; i++) {
if (i < topMaximizedWindow) {
// below top-most maximized window, don't animate
let overlay = this._windowOverlays[i];
if (overlay)
overlay.hide();
this._windows[i].actor.opacity = 0;
} else {
let fromTop = topIndex - i;
let time;
if (fromTop < nTimeSlots) // animate top-most windows gradually
time = windowBaseTime * (nTimeSlots - fromTop);
else
time = windowBaseTime;
this._windows[i].actor.opacity = 255;
this._fadeWindow(i, time, 0);
}
}
},
fadeFromOverview: function() {
this.leavingOverview = true;
this._overviewHiddenId = Main.overview.connect('hidden', Lang.bind(this,
this._doneLeavingOverview));
if (this._windows.length == 0)
return;
for (let i = 0; i < this._windows.length; i++) {
let clone = this._windows[i];
Tweener.removeTweens(clone.actor);
}
if (this._repositionWindowsId > 0) {
Mainloop.source_remove(this._repositionWindowsId);
this._repositionWindowsId = 0;
}
if (this.metaWorkspace != null && this.metaWorkspace != global.screen.get_active_workspace())
return;
// Special case maximized windows, since it doesn't make sense
// to animate windows below in the stack
let topMaximizedWindow;
// It is ok to treat the case where there is no maximized
// window as if the bottom-most window was maximized given that
// it won't affect the result of the animation
for (topMaximizedWindow = this._windows.length - 1; topMaximizedWindow > 0; topMaximizedWindow--) {
let metaWindow = this._windows[topMaximizedWindow].metaWindow;
if (metaWindow.maximized_horizontally && metaWindow.maximized_vertically)
break;
}
let nTimeSlots = Math.min(WINDOW_ANIMATION_MAX_NUMBER_BLENDING + 1, this._windows.length - topMaximizedWindow);
let windowBaseTime = Overview.ANIMATION_TIME / nTimeSlots;
let topIndex = this._windows.length - 1;
for (let i = 0; i < this._windows.length; i++) {
if (i < topMaximizedWindow) {
// below top-most maximized window, don't animate
let overlay = this._windowOverlays[i];
if (overlay)
overlay.hide();
this._windows[i].actor.opacity = 0;
} else {
let fromTop = topIndex - i;
let time;
if (fromTop < nTimeSlots) // animate top-most windows gradually
time = windowBaseTime * (fromTop + 1);
else
time = windowBaseTime * nTimeSlots;
this._windows[i].actor.opacity = 0;
this._fadeWindow(i, time, 255);
}
}
},
_fadeWindow: function(index, time, opacity) {
let clone = this._windows[index];
let overlay = this._windowOverlays[index];
if (overlay)
overlay.hide();
if (clone.metaWindow.showing_on_its_workspace()) {
let [origX, origY] = clone.getOriginalPosition();
clone.actor.scale_x = 1;
clone.actor.scale_y = 1;
clone.actor.x = origX;
clone.actor.y = origY;
Tweener.addTween(clone.actor,
{ time: time,
opacity: opacity,
transition: 'easeOutQuad'
});
} else {
// The window is hidden
clone.actor.opacity = 0;
}
},
zoomToOverview: function() {
// Position and scale the windows.
this._recalculateWindowPositions(WindowPositionFlags.ANIMATE | WindowPositionFlags.INITIAL);
},
// Animates the return from Overview mode
zoomFromOverview : function() {
zoomFromOverview: function() {
let currentWorkspace = global.screen.get_active_workspace();
this.leavingOverview = true;
@ -1543,35 +1721,37 @@ const Workspace = new Lang.Class({
return;
// Position and scale the windows.
for (let i = 0; i < this._windows.length; i++) {
let clone = this._windows[i];
let overlay = this._windowOverlays[i];
for (let i = 0; i < this._windows.length; i++)
this._zoomWindowFromOverview(i);
},
if (overlay)
overlay.hide();
_zoomWindowFromOverview: function(index) {
let clone = this._windows[index];
let overlay = this._windowOverlays[index];
if (clone.metaWindow.showing_on_its_workspace()) {
let [origX, origY] = clone.getOriginalPosition();
if (overlay)
overlay.hide();
Tweener.addTween(clone.actor,
{ x: origX,
y: origY,
scale_x: 1.0,
scale_y: 1.0,
time: Overview.ANIMATION_TIME,
opacity: 255,
transition: 'easeOutQuad'
});
} else {
// The window is hidden, make it shrink and fade it out
Tweener.addTween(clone.actor,
{ scale_x: 0,
scale_y: 0,
opacity: 0,
time: Overview.ANIMATION_TIME,
transition: 'easeOutQuad'
});
}
if (clone.metaWindow.showing_on_its_workspace()) {
let [origX, origY] = clone.getOriginalPosition();
Tweener.addTween(clone.actor,
{ x: origX,
y: origY,
scale_x: 1.0,
scale_y: 1.0,
time: Overview.ANIMATION_TIME,
opacity: 255,
transition: 'easeOutQuad'
});
} else {
// The window is hidden, make it shrink and fade it out
Tweener.addTween(clone.actor,
{ scale_x: 0,
scale_y: 0,
opacity: 0,
time: Overview.ANIMATION_TIME,
transition: 'easeOutQuad'
});
}
},
@ -1610,6 +1790,11 @@ const Workspace = new Lang.Class({
this.leavingOverview = false;
},
_doneShowingOverview: function() {
this._animatingWindowsFade = false;
this._recalculateWindowPositions(WindowPositionFlags.INITIAL);
},
// Tests if @actor belongs to this workspaces and monitor
_isMyWindow : function (actor) {
let win = actor.meta_window;
@ -1633,16 +1818,16 @@ const Workspace = new Lang.Class({
Lang.bind(this, this._onCloneSelected));
clone.connect('drag-begin',
Lang.bind(this, function() {
Main.overview.beginWindowDrag(clone);
Main.overview.beginWindowDrag(clone.metaWindow);
overlay.hide();
}));
clone.connect('drag-cancelled',
Lang.bind(this, function() {
Main.overview.cancelledWindowDrag(clone);
Main.overview.cancelledWindowDrag(clone.metaWindow);
}));
clone.connect('drag-end',
Lang.bind(this, function() {
Main.overview.endWindowDrag(clone);
Main.overview.endWindowDrag(clone.metaWindow);
overlay.show();
}));
clone.connect('size-changed',

View File

@ -52,6 +52,7 @@ const WorkspaceSwitcherPopup = new Lang.Class({
this._globalSignals.push(global.screen.connect('workspace-removed', Lang.bind(this, this._redisplay)));
this._timeoutId = Mainloop.timeout_add(DISPLAY_TIMEOUT, Lang.bind(this, this._onTimeout));
GLib.Source.set_name_by_id(this._timeoutId, '[gnome-shell] this._onTimeout');
},
_getPreferredHeight : function (actor, forWidth, alloc) {
@ -145,6 +146,7 @@ const WorkspaceSwitcherPopup = new Lang.Class({
if (this._timeoutId != 0)
Mainloop.source_remove(this._timeoutId);
this._timeoutId = Mainloop.timeout_add(DISPLAY_TIMEOUT, Lang.bind(this, this._onTimeout));
GLib.Source.set_name_by_id(this._timeoutId, '[gnome-shell] this._onTimeout');
this._show();
},

View File

@ -68,7 +68,7 @@ const WindowClone = new Lang.Class({
this.realWindow = realWindow;
this.metaWindow = realWindow.meta_window;
this.clone._updateId = this.realWindow.connect('position-changed',
this.clone._updateId = this.metaWindow.connect('position-changed',
Lang.bind(this, this._onPositionChanged));
this.clone._destroyId = this.realWindow.connect('destroy', Lang.bind(this, function() {
// First destroy the clone and then destroy everything
@ -151,7 +151,7 @@ const WindowClone = new Lang.Class({
let clone = new Clutter.Clone({ source: realDialog });
this._updateDialogPosition(realDialog, clone);
clone._updateId = realDialog.connect('position-changed',
clone._updateId = metaDialog.connect('position-changed',
Lang.bind(this, this._updateDialogPosition, clone));
clone._destroyId = realDialog.connect('destroy', Lang.bind(this, function() {
clone.destroy();
@ -176,7 +176,7 @@ const WindowClone = new Lang.Class({
this.actor.get_children().forEach(function(child) {
let realWindow = child.source;
realWindow.disconnect(child._updateId);
realWindow.meta_window.disconnect(child._updateId);
realWindow.disconnect(child._destroyId);
});
},
@ -306,7 +306,7 @@ const WorkspaceThumbnail = new Lang.Class({
_createBackground: function() {
this._bgManager = new Background.BackgroundManager({ monitorIndex: Main.layoutManager.primaryIndex,
container: this._contents,
effects: Meta.BackgroundEffects.NONE });
vignette: false });
},
setPorthole: function(x, y, width, height) {
@ -332,7 +332,7 @@ const WorkspaceThumbnail = new Lang.Class({
let clone = this._windows[i];
let metaWindow = clone.metaWindow;
if (i == 0) {
clone.setStackAbove(this._bgManager.background.actor);
clone.setStackAbove(this._bgManager.backgroundActor);
} else {
let previousClone = this._windows[i - 1];
clone.setStackAbove(previousClone.actor);
@ -367,10 +367,6 @@ const WorkspaceThumbnail = new Lang.Class({
if (index == -1)
return;
// Check if window still should be here
if (win && this._isMyWindow(win) && this._isOverviewWindow(win))
return;
let clone = this._windows[index];
this._windows.splice(index, 1);
@ -386,14 +382,15 @@ const WorkspaceThumbnail = new Lang.Class({
if (!win) {
// Newly-created windows are added to a workspace before
// the compositor finds out about them...
Mainloop.idle_add(Lang.bind(this,
function () {
let id = Mainloop.idle_add(Lang.bind(this,
function () {
if (!this._removed &&
metaWin.get_compositor_private() &&
metaWin.get_workspace() == this.metaWorkspace)
this._doAddWindow(metaWin);
return GLib.SOURCE_REMOVE;
}));
GLib.Source.set_name_by_id(id, '[gnome-shell] this._doAddWindow');
return;
}
@ -521,20 +518,20 @@ const WorkspaceThumbnail = new Lang.Class({
}));
clone.connect('drag-begin',
Lang.bind(this, function() {
Main.overview.beginWindowDrag(clone);
Main.overview.beginWindowDrag(clone.metaWindow);
}));
clone.connect('drag-cancelled',
Lang.bind(this, function() {
Main.overview.cancelledWindowDrag(clone);
Main.overview.cancelledWindowDrag(clone.metaWindow);
}));
clone.connect('drag-end',
Lang.bind(this, function() {
Main.overview.endWindowDrag(clone);
Main.overview.endWindowDrag(clone.metaWindow);
}));
this._contents.add_actor(clone.actor);
if (this._windows.length == 0)
clone.setStackAbove(this._bgManager.background.actor);
clone.setStackAbove(this._bgManager.backgroundActor);
else
clone.setStackAbove(this._windows[this._windows.length - 1].actor);
@ -664,7 +661,7 @@ const ThumbnailsBox = new Lang.Class({
Main.overview.connect('window-drag-cancelled',
Lang.bind(this, this._onDragCancelled));
this._settings = new Gio.Settings({ schema: OVERRIDE_SCHEMA });
this._settings = new Gio.Settings({ schema_id: OVERRIDE_SCHEMA });
this._settings.connect('changed::dynamic-workspaces',
Lang.bind(this, this._updateSwitcherVisibility));
},
@ -804,28 +801,35 @@ const ThumbnailsBox = new Lang.Class({
[newWorkspaceIndex, this._dropPlaceholderPos] = [this._dropPlaceholderPos, -1];
// Nab all the windows below us.
let windows = global.get_window_actors().filter(function(win) {
let windows = global.get_window_actors().filter(function(winActor) {
// If the window is attached to an ancestor, we don't need/want to move it
if (!!win.meta_window.get_transient_for())
let window = winActor.meta_window;
if (window.get_transient_for() != null)
return false;
if (isWindow)
return win.get_workspace() >= newWorkspaceIndex && win != source;
return window.get_workspace().index() >= newWorkspaceIndex && winActor != source;
else
return win.get_workspace() >= newWorkspaceIndex;
return window.get_workspace().index() >= newWorkspaceIndex;
});
this._spliceIndex = newWorkspaceIndex;
// ... move them down one.
windows.forEach(function(win) {
win.meta_window.change_workspace_by_index(win.get_workspace() + 1, true);
windows.forEach(function(winActor) {
let window = winActor.meta_window;
window.change_workspace_by_index(window.get_workspace().index() + 1, true);
});
if (isWindow)
if (isWindow) {
// ... and bam, a workspace, good as new.
// Move the window to our monitor first if necessary.
let thumbMonitor = this._thumbnails[newWorkspaceIndex].monitorIndex;
if (source.metaWindow.get_monitor() != thumbMonitor)
source.metaWindow.move_to_monitor(thumbMonitor);
source.metaWindow.change_workspace_by_index(newWorkspaceIndex, true);
else if (source.shellWorkspaceLaunch) {
} else if (source.shellWorkspaceLaunch) {
source.shellWorkspaceLaunch({ workspace: newWorkspaceIndex,
timestamp: time });
// This new workspace will be automatically removed if the application fails
@ -870,9 +874,6 @@ const ThumbnailsBox = new Lang.Class({
for (let key in ThumbnailState)
this._stateCounts[ThumbnailState[key]] = 0;
// The "porthole" is the portion of the screen that we show in the workspaces
this._porthole = Main.layoutManager.getWorkAreaForMonitor(Main.layoutManager.primaryIndex);
this.addThumbnails(0, global.screen.n_workspaces);
this._updateSwitcherVisibility();
@ -896,10 +897,14 @@ const ThumbnailsBox = new Lang.Class({
for (let w = 0; w < this._thumbnails.length; w++)
this._thumbnails[w].destroy();
this._thumbnails = [];
this._porthole = null;
},
_workspacesChanged: function() {
let oldNumWorkspaces = this._thumbnails.length;
let validThumbnails = this._thumbnails.filter(function(t) {
return t.state <= ThumbnailState.NORMAL;
});
let oldNumWorkspaces = validThumbnails.length;
let newNumWorkspaces = global.screen.n_workspaces;
let active = global.screen.get_active_workspace_index();
@ -923,6 +928,7 @@ const ThumbnailsBox = new Lang.Class({
},
addThumbnails: function(start, count) {
this._ensurePorthole();
for (let k = start; k < start + count; k++) {
let metaWorkspace = global.screen.get_workspace_by_index(k);
let thumbnail = new WorkspaceThumbnail(metaWorkspace);
@ -1110,9 +1116,7 @@ const ThumbnailsBox = new Lang.Class({
// the size request to our children because we know how big they are and know
// that the actors aren't depending on the virtual functions being called.
if (this._thumbnails.length == 0)
return;
this._ensurePorthole();
let themeNode = this.actor.get_theme_node();
let spacing = themeNode.get_length('spacing');
@ -1124,8 +1128,7 @@ const ThumbnailsBox = new Lang.Class({
},
_getPreferredWidth: function(actor, forHeight, alloc) {
if (this._thumbnails.length == 0)
return;
this._ensurePorthole();
let themeNode = this.actor.get_theme_node();
@ -1143,6 +1146,13 @@ const ThumbnailsBox = new Lang.Class({
alloc.natural_size = width;
},
// The "porthole" is the portion of the screen that we show in the
// workspaces
_ensurePorthole: function() {
if (!this._porthole)
this._porthole = Main.layoutManager.getWorkAreaForMonitor(Main.layoutManager.primaryIndex);
},
_allocate: function(actor, box, flags) {
let rtl = (Clutter.get_default_text_direction () == Clutter.TextDirection.RTL);

View File

@ -21,6 +21,11 @@ const WORKSPACE_SWITCH_TIME = 0.25;
// Note that mutter has a compile-time limit of 36
const MAX_WORKSPACES = 16;
const AnimationType = {
ZOOM: 0,
FADE: 1
};
const OVERRIDE_SCHEMA = 'org.gnome.shell.overrides';
const WorkspacesViewBase = new Lang.Class({
@ -58,9 +63,9 @@ const WorkspacesViewBase = new Lang.Class({
}
},
_dragBegin: function(overview, clone) {
_dragBegin: function(overview, window) {
this._inDrag = true;
this._setReservedSlot(clone);
this._setReservedSlot(window);
},
_dragEnd: function() {
@ -74,12 +79,12 @@ const WorkspacesViewBase = new Lang.Class({
setFullGeometry: function(geom) {
this._fullGeometry = geom;
this._syncGeometry();
this._syncFullGeometry();
},
setActualGeometry: function(geom) {
this._actualGeometry = geom;
this._syncGeometry();
this._syncActualGeometry();
},
});
@ -94,7 +99,7 @@ const WorkspacesView = new Lang.Class({
this._scrolling = false; // swipe-scrolling
this._animatingScroll = false; // programatically updating the adjustment
this._settings = new Gio.Settings({ schema: OVERRIDE_SCHEMA });
this._settings = new Gio.Settings({ schema_id: OVERRIDE_SCHEMA });
let activeWorkspaceIndex = global.screen.get_active_workspace_index();
this.scrollAdjustment = new St.Adjustment({ value: activeWorkspaceIndex,
@ -122,14 +127,17 @@ const WorkspacesView = new Lang.Class({
Lang.bind(this, this._activeWorkspaceChanged));
},
_setReservedSlot: function(clone) {
_setReservedSlot: function(window) {
for (let i = 0; i < this._workspaces.length; i++)
this._workspaces[i].setReservedSlot(clone);
this._workspaces[i].setReservedSlot(window);
},
_syncGeometry: function() {
_syncFullGeometry: function() {
for (let i = 0; i < this._workspaces.length; i++)
this._workspaces[i].setFullGeometry(this._fullGeometry);
},
_syncActualGeometry: function() {
for (let i = 0; i < this._workspaces.length; i++)
this._workspaces[i].setActualGeometry(this._actualGeometry);
},
@ -139,17 +147,25 @@ const WorkspacesView = new Lang.Class({
return this._workspaces[active];
},
zoomToOverview: function() {
for (let w = 0; w < this._workspaces.length; w++)
this._workspaces[w].zoomToOverview();
animateToOverview: function(animationType) {
for (let w = 0; w < this._workspaces.length; w++) {
if (animationType == AnimationType.ZOOM)
this._workspaces[w].zoomToOverview();
else
this._workspaces[w].fadeToOverview();
}
this._updateWorkspaceActors(false);
},
zoomFromOverview: function() {
animateFromOverview: function(animationType) {
this.actor.remove_clip();
for (let w = 0; w < this._workspaces.length; w++)
this._workspaces[w].zoomFromOverview();
for (let w = 0; w < this._workspaces.length; w++) {
if (animationType == AnimationType.ZOOM)
this._workspaces[w].zoomFromOverview();
else
this._workspaces[w].fadeFromOverview();
}
},
syncStacking: function(stackIndices) {
@ -260,10 +276,12 @@ const WorkspacesView = new Lang.Class({
}
}
if (this._fullGeometry)
if (this._fullGeometry) {
this._updateWorkspaceActors(false);
this._syncGeometry();
this._syncFullGeometry();
}
if (this._actualGeometry)
this._syncActualGeometry();
},
_activeWorkspaceChanged: function(wm, from, to, direction) {
@ -348,21 +366,30 @@ const ExtraWorkspaceView = new Lang.Class({
this.actor.add_actor(this._workspace.actor);
},
_setReservedSlot: function(clone) {
this._workspace.setReservedSlot(clone);
_setReservedSlot: function(window) {
this._workspace.setReservedSlot(window);
},
_syncGeometry: function() {
_syncFullGeometry: function() {
this._workspace.setFullGeometry(this._fullGeometry);
},
_syncActualGeometry: function() {
this._workspace.setActualGeometry(this._actualGeometry);
},
zoomToOverview: function() {
this._workspace.zoomToOverview();
animateToOverview: function(animationType) {
if (animationType == AnimationType.ZOOM)
this._workspace.zoomToOverview();
else
this._workspace.fadeToOverview();
},
zoomFromOverview: function() {
this._workspace.zoomFromOverview();
animateFromOverview: function(animationType) {
if (animationType == AnimationType.ZOOM)
this._workspace.zoomFromOverview();
else
this._workspace.fadeFromOverview();
},
syncStacking: function(stackIndices) {
@ -429,7 +456,7 @@ const WorkspacesDisplay = new Lang.Class({
this._workspacesViews = [];
this._primaryScrollAdjustment = null;
this._settings = new Gio.Settings({ schema: OVERRIDE_SCHEMA });
this._settings = new Gio.Settings({ schema_id: OVERRIDE_SCHEMA });
this._settings.connect('changed::workspaces-only-on-primary',
Lang.bind(this,
this._workspacesOnlyOnPrimaryChanged));
@ -454,10 +481,16 @@ const WorkspacesDisplay = new Lang.Class({
return this._getPrimaryView().actor.navigate_focus(from, direction, false);
},
show: function() {
show: function(fadeOnPrimary) {
this._updateWorkspacesViews();
for (let i = 0; i < this._workspacesViews.length; i++)
this._workspacesViews[i].zoomToOverview();
for (let i = 0; i < this._workspacesViews.length; i++) {
let animationType;
if (fadeOnPrimary && i == this._primaryIndex)
animationType = AnimationType.FADE;
else
animationType = AnimationType.ZOOM;
this._workspacesViews[i].animateToOverview(animationType);
}
this._restackedNotifyId =
Main.overview.connect('windows-restacked',
@ -466,9 +499,15 @@ const WorkspacesDisplay = new Lang.Class({
this._scrollEventId = Main.overview.connect('scroll-event', Lang.bind(this, this._onScrollEvent));
},
zoomFromOverview: function() {
for (let i = 0; i < this._workspacesViews.length; i++)
this._workspacesViews[i].zoomFromOverview();
animateFromOverview: function(fadeOnPrimary) {
for (let i = 0; i < this._workspacesViews.length; i++) {
let animationType;
if (fadeOnPrimary && i == this._primaryIndex)
animationType = AnimationType.FADE;
else
animationType = AnimationType.ZOOM;
this._workspacesViews[i].animateFromOverview(animationType);
}
},
hide: function() {
@ -598,8 +637,9 @@ const WorkspacesDisplay = new Lang.Class({
return;
let [x, y] = this.actor.get_transformed_position();
let width = this.actor.allocation.x2 - this.actor.allocation.x1;
let height = this.actor.allocation.y2 - this.actor.allocation.y1;
let allocation = this.actor.allocation;
let width = allocation.x2 - allocation.x1;
let height = allocation.y2 - allocation.y1;
let primaryGeometry = { x: x, y: y, width: width, height: height };
let monitors = Main.layoutManager.monitors;

View File

@ -33,6 +33,7 @@ id
it
ja
kk
km
kn
ko
ku
@ -44,6 +45,7 @@ mk
mr
ms
nb
ne
nl
nn
or

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