Compare commits

...

385 Commits

Author SHA1 Message Date
71daa39349 Bump version to 3.14.4
Update NEWS.
2015-03-23 19:36:31 +01:00
92e0cc1008 build: Work around distcheck issue 2015-03-23 19:36:31 +01:00
d19e78af24 Refresh all background instances after suspend if needed
NVIDIA drivers don't preserve FBO contents across suspend / resume
cycles which results in broken backgrounds. We can work around that by
forcing a refresh when coming out of suspend.

https://bugzilla.gnome.org/show_bug.cgi?id=739178
2015-03-20 10:23:47 +01:00
4b0cbafdcd viewSelector: Mirror open-app-view edge drag gesture for RTL
It makes sense for the gesture to reflect the position of the
activities button / dash. In RTL locales, those are located on
the right rather than the left, so make the gesture apply to
the opposite edge in that case.

https://bugzilla.gnome.org/show_bug.cgi?id=737502
2015-03-17 10:27:16 +01:00
c01ec075ab Added Bosnian translation 2015-03-14 16:58:33 +00:00
c4b2968f9f loginDialog: Pass-through UserWidget's label-actor
https://bugzilla.gnome.org/show_bug.cgi?id=729603
2015-03-06 17:25:44 +01:00
eab8ea9a1e appDisplay: Fix leaking signal connections
The overview has a longer life-time than dash items, so we are leaking a
signal connection each time an item is destroyed.

https://bugzilla.gnome.org/show_bug.cgi?id=745570
2015-03-04 12:57:43 +01:00
6ecaf0e0fc Revert "workspace: Grab the key focus when hovering over a window"
Turns out this makes interaction with the OSK or candidate popups
using a mouse basically impossible since they get dismissed when the
key focus is captured by a window in the overview.

This reverts commit aeb9f5775f.

https://bugzilla.gnome.org/show_bug.cgi?id=745245
2015-03-02 15:56:32 +01:00
840482c750 WorkspacesDisplay: update the primary monitor index too
The primary monitor index might change so we need to update it too.

https://bugzilla.gnome.org/show_bug.cgi?id=743993
2015-03-02 15:49:49 +01:00
681e1b2075 dash: Fix leaking signal connections
The overview has a longer life-time than dash items, so we are
leaking a signal connection each time an item is destroyed.
Spotted by Michele (<micxgx@gmail.com>)

https://bugzilla.gnome.org/show_bug.cgi?id=744575
2015-02-27 14:46:39 +01:00
bff6f71488 screenShield: Do not wake up screen after adding hidden source
The screen should be woken up when a new notification is shown on
the lock screen, but not when a notification arrives while disabled.
Add a missing condition to fix.

https://bugzilla.gnome.org/show_bug.cgi?id=744114
2015-02-27 14:45:53 +01:00
0adf3b84a7 system: Fix visibility of suspend button
It depends on the availability of suspend, not shutdown ...
2015-02-04 12:24:08 +01:00
fd635ba933 calendar: update current day highlight on day change
https://bugzilla.gnome.org/show_bug.cgi?id=742492
2015-01-11 17:41:13 +01:00
fd4f2f405f slider: Don't hardcode scroll interval for smooth scrolling
Use the SLIDER_SCROLL_STEP constant instead for consistency.

https://bugzilla.gnome.org/show_bug.cgi?id=742648
2015-01-11 17:40:56 +01:00
1a30f1b2f0 Updated Slovenian translation 2014-12-25 19:21:52 +01:00
412d40f844 calendar: Stop computing week number ourselves
Correctly computing the ISO week number is tricky and we already
have code in the platform to do it, so just refer its computation
to GDateTime rather than doing it ourselves.

https://bugzilla.gnome.org/show_bug.cgi?id=736722
2014-12-19 17:25:11 +01:00
3dff544396 Bump version to 3.14.3
Update NEWS.
2014-12-19 12:07:06 +01:00
7e7eab2bea gestures: Restrict actions based on keybindingMode
Just like keybindings and the message tray pointer barrier, gestures
don't always make sense - for instance, swiping up the screen shield
should not trigger the message tray just as the SelectArea action around
the left edge should not open the overview.
To avoid this, restrict gestures based on the current keybinding mode.

https://bugzilla.gnome.org/show_bug.cgi?id=740237
2014-12-19 11:48:27 +01:00
c568b44997 Calendar: ignore timeouts starting the calendar-server
In certain cases the timeout for starting the calendar helper can
be reached but the calendar helper still loads fine. If so, just
ignore the timeout and wait until we get a notification from
dbus of the successful start.

https://bugzilla.gnome.org/show_bug.cgi?id=735308
2014-12-14 17:19:12 -08:00
ce818c0ae5 calendar-server: activate evolution-source-registry manually at startup
g_dbus_proxy_new() (and library calls that wrap it) has an hardcoded
timeout of 25 seconds, which is insufficient for starting up e-s-r
in certain setups. Avoid a timeout error by starting the service
manually with a longer timeout before hand.
Also demote the error to a warning + exit failure instead of
a crash, to avoid triggering abrt reports.

https://bugzilla.gnome.org/show_bug.cgi?id=735308
2014-12-14 17:19:12 -08:00
ef2e301c08 Add ScrollView to calendar events
Added single ScrollView to make the calendar events scrollable

The calendar height will not go beyond the screen height
Calendar events for all periods will be enclosed in a single ScrollView

Moved the separator to top of the buttons while expanding

https://bugzilla.gnome.org/show_bug.cgi?id=705115
2014-12-11 18:48:22 +01:00
ba274f42b2 build: Workaround quoting issues in configure script
Default value of BROWSER_PLUGIN_DIR variable contains special symbols.
Thus quoting and inlining it in parameter expansion is not portable.
In particular it does not work in dash. Replace ${a:-b} parameter
expansion with conditional statement.

https://bugzilla.gnome.org/show_bug.cgi?id=739241
2014-11-29 16:37:54 +00:00
2ceaa05a5a gdm: fix sensitivity of auth prompt when cancelling early and user list is disabled
If the user list is disabled and the user clicks cancel quickly enough
after typing their username, they can get in a state where the
auth prompt gets stuck in the insensitive state.

This is because the login dialog code makes the prompt insensitive
while while pam is processing the provided username, but the prompt
only makes itself sensitive again when it is hidden.

This commit makes it sensitive right before asking for a username again.

https://bugzilla.gnome.org/show_bug.cgi?id=740141
2014-11-26 19:04:43 -06:00
047e454a7c gdm: disallow cancel after verification succeeds
Once verification has succeeded, the train's already
left the building and we shouldn't allow canceling.

This commit renders the cancel button non-reactive
and makes the cancel function be a noop after
verification succeeds.

https://bugzilla.gnome.org/show_bug.cgi?id=740141
2014-11-26 19:04:29 -06:00
86618ce1f9 network: properly remove connections from list
Due to a typo we were always removing the first (index 0) connection
from the global list of connections instead of the correct one.

This resulted in some connections remaining in the shell's connection
list long after they were removed.  In particular, this resulted in
multiple copies of a bluetooth connection appearing after suspend/resume
(when the device was readded and the cached connection list was
rescanned).

https://bugzilla.gnome.org/show_bug.cgi?id=740227
2014-11-26 16:08:17 -05:00
59724c5dd5 Bump version to 3.14.2
Update NEWS.
2014-11-12 19:30:14 +01:00
3bb500fed4 viewSelector: Hide workspace page after animating to app picker
WorkspacesDisplay relies on being hidden to disable workspace switches
by scrolling or panning. Usually viewSelector will hide the previous
page on page switch, but we currently miss the case when opening the
overview at the app picker, where the workspaces page is still shown
for the transition, but never hidden.
Fix this by calling hide() in addition to setting the opacity to 0 at
the end of the overview animation.

https://bugzilla.gnome.org/show_bug.cgi?id=737534
2014-11-12 19:19:31 +01:00
dcd3945bb7 Move style updates in AppIcon._onStateChanged out
There is currently no simple way to inject into AppIcon's state change,
so an extension that wants to do this has to destroy/remove/update all
icons in the Shell (i.e. in the Dash, AllView, FrequentView) on enable()
and disable() after updating AppIcon.prototype._onStateChange, or the
extension must require a restart of the Shell.

To solve this issue, we rename _onStateChanged to _updateRunningStyle,
and connect the notify::state signal with an anonymous function that
calls _updateRunningStyle.
This extra function call should allow extensions to just extend the
updateRunningStyle function in the prototype.

https://bugzilla.gnome.org/show_bug.cgi?id=739497
2014-11-06 21:31:47 +01:00
f414f616c4 dateMenu: Fix typo in _isToday()
getDay() is the day of week, what we want there is getDate().

https://bugzilla.gnome.org/show_bug.cgi?id=738725
2014-11-03 15:05:59 +01:00
e21e90c5e6 networkAgent: Support NM versions without :capabilities
Commit 926de53c0c bumped the requirement for NetworkManager,
which is problematic on a stable branch; optionally fall back to
the previous code.

https://bugzilla.gnome.org/show_bug.cgi?id=738485
2014-10-31 12:41:23 +00:00
1e7b2ef51f Bump version to 3.14.1.5
Update NEWS
2014-10-30 11:22:27 +00:00
c291de7479 Calendar: Inline _ellipsizeEventTime into caller
This patch inlines the function _ellipsizeEventTime into its only caller
_addEvent. This also removes the need for the global const
EventEllipses and is thus removed by this commit as well.

https://bugzilla.gnome.org/show_bug.cgi?id=727302
2014-10-27 19:33:25 -05:00
aee1a18270 Calendar: sort multi-day events by ending day/time
With commit dc6a60dde, the calendar displays the ending day and time of
a continuing multi-day event on its ending day. This results in the list
not appearing to be sorted. This patch sorts the list according to the
displayed day/time.

With the two appointments
Thursday 0800-1000 Foo, and Wednesday 0900-Friday 1200 Bar and today
being Monday, the rest of the week list currently displays:
F ...1200 Bar
T    0800 Foo
With this patch, the displaying order is switched because Friday comes
after Thursday.

https://bugzilla.gnome.org/show_bug.cgi?id=727302
2014-10-27 19:33:25 -05:00
6c67f26e7d Calendar: Show multi-day event continuation
Currently, multi-day events are shown as individual appointments on each
day.  This patch ellipsizes multi-day events to indicate continuation on
the prior or following day (or other time-period.)

The time label spot is now replaced by a box layout that contains the
prefix ellipsis label, the time label and the postfix ellipsis label.
In order to keep the alignment, ellipses are merely invisible (zero
opacity) when hidden.

The ellipses are styled using the events-day-time-ellipses class which,
by default, take the color of the event text.

When RTL is used, the box contents are adjusted accordingly (clutter
does that for us).

An event spanning three days now displays "...All Day..." in the
calendar on the second day.

https://bugzilla.gnome.org/show_bug.cgi?id=727302
2014-10-27 19:33:25 -05:00
deb651acbf BackgroundCache: plug an Animation object leak
We need to return early in case the animation file is the same,
otherwise we'll create a new Animation object and leak the previous
one.

https://bugzilla.gnome.org/show_bug.cgi?id=739252
2014-10-27 18:28:39 +01:00
d2011f6d7f messageTray: Summarize notifications when messages queue up
It is really annoying for the user to acknowledge multiple notifications
when they queue up. So, to prevent a notification flood that has to be
handled by the user one-by-one, a summarized-notification feature is
added which leaves a single summarized-notification for the user,
replacing multiple notifications if the number exceeds 1, which they may
or may not acknowledge. When this summarized-notification is acknowledged,
the message-tray is opened where they can view the notifications that were
summarized. This helps the user concentrate on his primary task
simultaneously informing them about the new notifications.

https://bugzilla.gnome.org/show_bug.cgi?id=702460
2014-10-27 18:22:36 +01:00
416adec904 Fix handling of SystemBackground
Since the background rework, SystemBackground is no longer a transparent
actor that you have to stack on top of a solid background, it is an
opaque actor. Fix the color of the background actor, and remove places
where we were setting the background color underneath the system background
and expecting blending - in particular, we can always set no_clear_hint
on the stage.

https://bugzilla.gnome.org/show_bug.cgi?id=738652
2014-10-16 17:17:33 -04:00
a72dca3610 Bump version to 3.14.1
Update NEWS.
2014-10-14 21:04:00 +02:00
5e5035a0f7 StWidget: carefully clear ->accessible pointer to avoid resurrection
The pointer to ->accessible was cleared too early in dispose, which
resulted in another accessible object being created when the actor
was removed from its parent in clutter_actor_dispose(). Use a
weak reference instead to clear the ->accessible pointer.

https://bugzilla.gnome.org/show_bug.cgi?id=738147
2014-10-13 12:46:35 -04:00
ffdb85e003 messageTray: add some missing signal disconnections
Disconnect some signal connections that weren't disconnected on actor destroy
(not the result of comprehensive review.)

https://bugzilla.gnome.org/show_bug.cgi?id=738256
2014-10-13 11:50:12 -04:00
6a969b934f gdm: fix missing braces
Incorrect braces meant that if the ShellUserVerifier was destroyed before
the call to fprintManager.GetDefaultDeviceRemote(), the reply would result in
an error.

https://bugzilla.gnome.org/show_bug.cgi?id=738256
2014-10-13 11:50:12 -04:00
8d3ff56846 gdm: disconnect signals
Many signal connections on global objects and on non-widgets were not
disconnected when the unlock screen was destroyed, causing leaks.

https://bugzilla.gnome.org/show_bug.cgi?id=738256
2014-10-13 11:50:11 -04:00
d8d046f2b3 AuthPrompt: properly remove user widgets
When replacing a user widget, we need to destroy the child, not just
unparent it, or it will leak.

https://bugzilla.gnome.org/show_bug.cgi?id=738256
2014-10-13 11:50:11 -04:00
0bec76b6ee app-well: Set menu width
Currently the app well menu has unrestricted with which can cause it to grow
with long window titles and can even go offscreen that way.

So set a max size, long titles will now be properly elipised.

https://bugzilla.gnome.org/show_bug.cgi?id=738054
2014-10-13 15:39:31 +02:00
aa3aea7520 window-tracker: Also listen for changes in the gtk-application-id
Wayland applications don't tend to have very useful WM Class properties,
as GTK+ isn't very good at picking an appropriate application ID. While
we should likely fix GTK+ to pick a better app ID, we do have the
existing gtk_shell for more accurate information. The only problem is
that the gtk_surface is set after the MetaWindow is constructed, and
we're not listening for changes on the GTK+ application ID.

Listen to changes on the GTK+ application ID to fix app tracking for
most GTK+ applications under Wayland.
2014-10-12 17:20:22 -07:00
49fcc93a4b window-tracker: Fix minor style issue 2014-10-12 17:20:12 -07:00
eaec459ee9 st: Bail out on clipboard requests if there is no text.
If a selection request happens through foreign means, the selected
text is NULL, and a crash happens.

https://bugzilla.gnome.org/show_bug.cgi?id=738314
2014-10-10 19:37:40 +02:00
72c6f0025d status/keyboard: Ensure we always have at least one input source
Most of the code handles the sources setting being empty and
InputSourceManager.currentSource being null because previously the
"model" (i.e. the sources list) was kept in gnome-settings-daemon.

But this is fragile and since we're now the canonical place where the
list lives we can force it to never be empty even if the gsetting is
empty or contains only invalid entries.  Adding the default keyboard
layout in that case is the safest thing to do.

https://bugzilla.gnome.org/show_bug.cgi?id=738303
2014-10-10 18:45:45 +02:00
aa3caff714 overviewControls: Really fix x align
Commit a4475465f1 fixed the wrong alignment for the fully visible
control, but regressed the partially slid-out one; take the slideX
factor into account to get the right offset for both cases.
2014-10-10 11:16:35 +02:00
522ccaba3f Updated Italian translation 2014-10-10 08:02:28 +00:00
3d00864599 Updates Persian Translations 2014-10-10 10:53:08 +03:30
bd3dfb8f6a Fix wrong comment 2014-10-09 14:55:13 +02:00
1b3c89f32b shell-recorder: Disable unredirection while recording
This is required to be able to record windows that would
otherwise be unredirected.

https://bugzilla.gnome.org/show_bug.cgi?id=738226
2014-10-09 14:52:25 +02:00
a4475465f1 overviewControls: Fix thinko in SlideLayout
Controls that slide left are located on the left, so the offset to
align them with the corresponding edge is always 0. It's controls
on the right that need a different offset when the available width
exceeds the child's width.

https://bugzilla.gnome.org/show_bug.cgi?id=728899
2014-10-09 14:21:23 +02:00
84f14cb61c Updated Kazakh translation 2014-10-09 10:54:59 +00:00
d0de411a59 iconGrid: Fix slowness on pulse animation for few items
Currently we use the same amount of total delay divided by all items,
but that makes the items animate slow if the amount of items is small.
To avoid that, use a smaller total amount delay for an amount of items
smaller than four.

https://bugzilla.gnome.org/show_bug.cgi?id=737017
2014-10-09 12:47:16 +02:00
2b9645b268 Use MetaWindow.get_frame_rect()
get_outer_rect() has been deprecated for a while, use the new
function instead.
2014-10-09 12:17:15 +02:00
4f08bebbf0 Updated Italian translation 2014-10-09 07:37:11 +00:00
4e8c476153 screenShield: fix trace back when unlocking session from another vt
commit 1d374ac8bd introduced a bug that
prevents unlock from working when initiated from another VT
(user switching).

This commit fixes the exception raised.

https://bugzilla.gnome.org/show_bug.cgi?id=708105
2014-10-08 09:43:33 -04:00
1d374ac8bd screenShield: focus login screen after lifting shield
This commit ensures the login screen gets focused after
the screen shield is raised.

The code affects the unlock screen as well, but it's
less important since the unlock screen gets destroyed
and recreated each time the curtain moves, so it
has an opportunity to take focus on its own.

https://bugzilla.gnome.org/show_bug.cgi?id=708105
2014-10-07 10:54:48 -04:00
83f0f4ea36 layout: Add the feedback group to the uiGroup
This makes DND under Wayland visible under the magnifier.
2014-10-06 17:08:20 -07:00
18f569280c userWidget: Respect the scale factor in the bin size we set
Otherwise, the widget will be too small on hi-DPI devices.

Based on a patch by: Darcy Beurle <darcy@beurle.id.au>

https://bugzilla.gnome.org/show_bug.cgi?id=735419
2014-10-06 17:02:04 -07:00
fc0c98805f Updated Spanish translation 2014-10-06 13:01:23 +02:00
6722b69b8a Updated Portuguese translation 2014-10-05 21:08:06 +00:00
f9d909f985 screenshot: Respect lockdown settings
We allow users/admins to lock down disk writes, respect that when
taking screenshots.

https://bugzilla.gnome.org/show_bug.cgi?id=737846
2014-10-03 17:08:56 +02:00
dd42cfa853 screencast: Re-add lockdown support
Commit 81bb7009ea removed support for the disable-disk-writes
lockdown feature for screencasts, add it back.

https://bugzilla.gnome.org/show_bug.cgi?id=737846
2014-10-03 17:08:56 +02:00
4ed4bb330e screencast: Don't leak recorders on failure
ShellRecorder.record() may fail, remove the recorder from the map
in that case.

https://bugzilla.gnome.org/show_bug.cgi?id=737846
2014-10-03 17:08:56 +02:00
f02b007337 shell-screenshot: Only allow one screenshot request at a time per sender
We currently allow infinite number of screenshot requests to be active at
the same time, which can "dos" the system and cause OOM.

So fail subsequent requests for the same sender when a screenshot operation
is already running.

https://bugzilla.gnome.org/show_bug.cgi?id=737456
2014-10-03 16:22:36 +02:00
0035de4ab7 screencast: Properly stop all recordings on session mode changes
We currently just clear out the map of recorders (which results
in the top bar indicator to be hidden), but don't stop the actual
recordings.
Spotted by Adel Gadllah on IRC.
2014-10-03 16:19:41 +02:00
28552d4b38 Updated Chinese (Taiwan) translation 2014-10-02 12:04:11 +00:00
42066a7c46 dateMenu: Don't generate JS garbage every clock tick
Instead of waking up the JS every second to set the clock and update a
date label the user will rarely see, simply use property binding to
bypass JS string handling, and update the date in the menu when the menu
is opened.
2014-10-01 15:42:49 -06:00
45847470d1 Updated German translation 2014-10-01 20:18:07 +00:00
72b0a3d78f search: Change order of duplicate search check
Checks for a duplicate search before setting the current search
to true and before cancelling the current search. This ensures that
if a duplicate search occurs while the previous search is still active,
the duplicate search will not incorrectly cancel or change the state
of the previous search.
2014-10-01 07:32:06 -06:00
fc3ad390b7 Updated gujarati translations 2014-10-01 15:52:13 +05:30
926de53c0c networkAgent: pass VPN hints to auth dialogs
Indicate to NetworkManager that the Shell's agent supports VPN
hints, and pass those hints to VPN auth dialogs that also indicate
that they support hints.

VPN plugins can request new secrets, for example if the previous
ones are incorrect (eg, user mis-typed the password) or some other
reason (next token code required to re-sync a hardware token).
The specific secret that the VPN wants, and a VPN-specific message,
are passed in hints from the plugin, to NetworkManager, to the
agent (GNOME Shell) and then to the auth dialog.

https://bugzilla.gnome.org/show_bug.cgi?id=737592
2014-09-30 09:34:44 -05:00
e6cd112379 search: Reset the search display when there's no search terms
Destroy the previous search view when there's no search terms, to make
sure old search items don't show up.
2014-09-30 00:55:01 -06:00
2cefc8be27 search: Match an empty array, not a null one
When the terms are missing, we pass an empty array, not a null one.
2014-09-30 00:55:01 -06:00
991179835e search: Factor out a function 2014-09-30 00:55:01 -06:00
0ca2fee54f layout: Don't update the input region while we have a modal
If we have a modal, the stage's input region doesn't really matter --
all events go to us anyway. To avoid doing extra work doing animations
when we have a modal, like menus, the overview, and the message tray,
just fizzle out all updates.

To make sure we catch updates, update the input region whenever we end a
modal.

https://bugzilla.gnome.org/show_bug.cgi?id=737001
2014-09-30 00:23:48 -06:00
778ef365d9 search: hide provider actors when they're created
When the overview is created, search is populated with one actor for
each provider. As they're not hidden though, they will contribute to the
overall size request of the search page, which will shift upwards the
overview grid.

Reviewed-By: Jasper St. Pierre <jstpierre@mecheye.net>
2014-09-29 22:42:25 -07:00
45937ed85d Updated Latvian translation 2014-09-28 16:38:01 +03:00
65a9c09c9c Updated Norwegian bokmål translation. 2014-09-27 15:33:54 +02:00
67b14d5fe5 st-entry: Implement Ctrl-u / Ctrl-k keybindings
These keybindings are well-established on the CLI (e.g. "kill-line"
and "unix-line-discard" in readline(3)), and adding support for them
is cheap ...

https://bugzilla.gnome.org/show_bug.cgi?id=737346
2014-09-26 22:03:31 +02:00
f976e46c46 Updated Norwegian bokmål translation. 2014-09-26 17:26:52 +02:00
7026209eae status/keyboard: obtain keyboard variant from IBus
This will fix unable to show keyboard variant from IBus through menu.

https://bugzilla.gnome.org/show_bug.cgi?id=735066
2014-09-26 17:08:25 +02:00
1e82d6edc2 windowMenu: Only disable "Always on Top" for fully maximized
Since (mutter) commit 49400657caae27 we disable the "Always on Top"
action for maximized windows, however when commit e7af257814
moved the window menu into the shell, this behavior was accidentally
extended to partially maximized (including tiled) windows.
As it can be desirable in this case to keep the window visible while
interacting with a different one, restore the previous behavior.

https://bugzilla.gnome.org/show_bug.cgi?id=737382
2014-09-25 23:10:03 +02:00
50ac1dd197 background: when a file changes, remove it from the image cache
MetaBackgroundCache doesn't itself use file watches, so when a image
that we are monitoring changes we need to purge it from the cache,
so that when we load it again we get the new image.

https://bugzilla.gnome.org/show_bug.cgi?id=710756
2014-09-24 23:06:07 -04:00
9d933356e1 keyboard: Make sure to destroy the key's BoxPointer
When the keyboard is destroyed, we destroy the keyboard actor, but the
keyboard's menu isn't part of the key itself, so it's never tracked.

The menus are actually tracked actors, so they slow down the layout
manager's code to rebuild regions and other things. Keeping this list
small is a good idea.

To prevent leaking menus, destroy the menu when the key is destroyed.

https://bugzilla.gnome.org/show_bug.cgi?id=736999
2014-09-23 15:58:08 -06:00
c2a5c00111 Updated Telugu translation 2014-09-23 14:19:29 +00:00
edb561a6ff update zh_CN translation 2014-09-23 19:43:00 +08:00
14c2460fe4 Updated translation for Afrikaans (af), with contributions by Dawid Loubser 2014-09-23 12:41:31 +02:00
598362448a Updated Hindi translation 2014-09-23 10:08:41 +00:00
845273d4c0 Updated Bengali (India) translation 2014-09-23 05:53:57 +00:00
3aebfdc319 Updated Czech translation 2014-09-23 07:07:12 +02:00
f423c371c8 Updated Galician translations 2014-09-23 01:51:11 +02:00
6fe1ad62ba Updated Serbian translation 2014-09-22 23:06:40 +02:00
63efe1db11 iconGrid: Don't use clones for pulse animation
The spring animation has to use clones to escape any clip set on the
parent, as it mainly occurs outside the parent. The same does not apply
to the pulse animation, which is very much in place - in fact, if the
parent is clipped (for instance a scrolled app folder), not having the
clip applied to the animated icons is indeed wrong.
Just animate the original grid actors instead, which gives the expected
result.

https://bugzilla.gnome.org/show_bug.cgi?id=736885
2014-09-22 20:46:41 +02:00
002ae0e7f1 Bump version to 3.14.0
Update NEWS.
2014-09-22 20:46:41 +02:00
4f5e5e1999 Update Czech translation 2014-09-22 15:16:22 +02:00
f4feb409ff Updated Kannada translation 2014-09-22 06:45:32 +00:00
05a035e6fd Updated Greek translation 2014-09-21 13:34:47 +00:00
7c2a3cc233 update Punjabi Translation - back for 3.14 2014-09-21 07:48:14 -05:00
7f660fd4d7 Updated Korean translation 2014-09-21 11:25:12 +09:00
c0730b610e Updated Ukrainian translation 2014-09-20 23:19:20 +03:00
b0cfcc4842 Updated Spanish translation 2014-09-20 19:05:06 +02:00
1afc9fefcc Updated Danish translation 2014-09-20 09:40:24 +02:00
90bea5785e Updated Kannada translation 2014-09-19 18:51:44 +00:00
61dacf3d91 Updated Hindi translation 2014-09-19 16:08:04 +00:00
3ae45bddad appDisplay: Hide empty app folders
Trying to open an empty folder currently leaves the parent view in a
rather confused state. While we should look into fixing this in the
future, empty folders are not useful at all to begin with, so hide them.

https://bugzilla.gnome.org/show_bug.cgi?id=736910
2014-09-19 15:12:03 +02:00
9ad4070d58 Updated German translation 2014-09-18 21:37:54 +00:00
1981b21ea8 Updated Spanish translation 2014-09-18 19:22:41 +02:00
9896135c97 a11y: set again NO_AT_BRIDGE=1 before calling meta_init()
It was removed on commit
70099872ab
because it was thought to not be needed anymore.

https://bugzilla.gnome.org/show_bug.cgi?id=736821
2014-09-18 15:37:10 +02:00
0d340099da Updated Oriya translation 2014-09-18 12:13:47 +00:00
cacc780111 Updated Nepali translation 2014-09-17 19:47:06 +00:00
a9a6da08a1 Updated Russian translation 2014-09-17 20:45:46 +04:00
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
159 changed files with 40630 additions and 27870 deletions

4
.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
@ -80,6 +83,7 @@ src/gnome-shell-extension-tool
src/gnome-shell-hotplug-sniffer
src/gnome-shell-perf-helper
src/gnome-shell-perf-tool
src/gnome-shell-portal-helper
src/hotplug-sniffer/org.gnome.Shell.HotplugSniffer.service
src/run-js-test
src/test-recorder

210
NEWS
View File

@ -1,3 +1,213 @@
3.14.4
======
* Fix erroneous week numbers in calendar [Florian; #736722]
* Make slider scrolling smoother [Adel; #742648]
* Fix current day highlight on day change [Sebastian; #742492]
* Do not wake up the screen for disabled notifications [Florian; #744114]
* gdm: Fix user list accessibility [Florian; #729603]
* Work around background corruption with NVIDIA driver [Rui; #739178]
* Misc. bug fixes [Florian, Rui, Michele; #744575, #743993, #745245, #745570,
#737502]
Contributors:
Michele, Adel Gadllah, Sebastian Keller, Rui Matos, Florian Müllner
Translations:
Matej Urbančič [sl], Samir Ribic [bs]
3.14.3
======
* Properly remove network connections from list [Ryan; #740227]
* Fix handling of cancel button on login screen [Ray; #740141]
* Fix build when using dash as default shell [Alexander; #739241]
* Make event list in calendar scrollable [Stalin; #705115]
* Fix calendar-server crash on DBus timeout [Giovanni; #735308]
* Fix gestures triggering erroneously [Florian; #740237]
Contributors:
Giovanni Campagna, Ryan Lortie, Florian Müllner, Stalin Pereira, Ray Strode,
Alexander Tsoy
3.14.2
======
* Do not hard-depend on latest NetworkManager [Florian; #738485]
* Fix check for isToday in calendar [Darcy; #738725]
* Fix workspace changes from app picker [Yuki; #737534]
* Misc. bug fixes [Yuki; #739497]
Contributors:
Darcy, Florian Müllner, Yuki
3.14.1.5
========
* Fix handing of SystemBackground [Owen; #738652]
* Summarize queued up notifications [Devyani; #702460]
* Plug an animation object leak [Rui; #739252]
* Improve handling of multi-day events [Andreas; #727302]
Contributors:
Andreas Brauchli, Devyani Kota, Rui Matos, Owen W. Taylor
3.14.1
======
* Fix pulse animation for scrolled app folders [Florian; #736885]
* Fix updating background on file changes [Owen; #710756]
* Obtain keyboard variant from IBus [Jinkyu; #735066]
* Implement Ctrl-u / Ctrl-k keybindings in entries [Florian; #737346]
* Pass VPN hints to auth dialog [Dan; #737592]
* Only allow one screenshot request at a time [Adel; #737456]
* Respect disable-save-to-disc lockdown setting [Florian; #737846]
* Respect scaling-factor for profile pictures [Darcy; #735419]
* Focus login screen after lifting the lock screen shield [Ray; #708105]
* Speed up pulse animation for few items [Carlos S.; #737017]
* Fix gap between workspace switcher and screen edge [Florian; #728899]
* Disable unredirection during recordings [Adel; #738226]
* Ensure there's always at least one input source [Rui; #738303]
* Restrict width of dash icons' context menus [Adel; #738054]
* Misc. bug fixes [Jasper, Florian, Carlos G., Owen; #736999, #737382, #737001,
#738314, #738256, #738147]
Contributors:
Darcy Beurle, Cosimo Cecchi, Adel Gadllah, Carlos Garnacho, Rui Matos,
Florian Müllner, Carlos Soriano, Jasper St. Pierre, Ray Strode, Patrick Ward,
Dan Williams, Owen W. Taylor, Jinkyu Yi
Translations:
Мирослав Николић po/sr, sr@latin.po, Fran Diéguez [gl], Marek Černocký [cs],
Saibal Ray [bn_IN], Rajesh Ranjan [hi], Friedel Wolff [af],
Zhou Fang [zh_CN], Krishnababu Krothapalli [te], Kjartan Maraas [nb],
Rūdolfs Mazurs [lv], Sweta Kothari [gu], Christian Kirbach [de],
Cheng-Chia Tseng [zh_TW], Pedro Albuquerque [pt], Daniel Mustieles [es],
Luca Ferretti [it], Baurzhan Muftakhidinov [kk], Arash Mousavi [fa],
Milo Casagrande [it]
3.14.0
======
* Fix exposure of the accessible tree [Alejandro; #736821]
* Hide empty app folders in app picker [Florian; #736910]
Contributors:
Florian Müllner, Alejandro Piñeiro
Translations:
Yuri Myasoedov [ru], Pawan Chitrakar [ne], Manoj Kumar Giri [or],
Daniel Mustieles [es], GNOME Translation Robot [de], Rajesh Ranjan [hi],
Shankar Prasad [kn], Kenneth Nielsen [da], Daniel Korostil [uk],
Changwoo Ryu [ko], A S Alam [pa], Tom Tryfonidis [el], Petr Kovar [cs]
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]

View File

@ -1,5 +1,5 @@
AC_PREREQ(2.63)
AC_INIT([gnome-shell],[3.13.3],[https://bugzilla.gnome.org/enter_bug.cgi?product=gnome-shell],[gnome-shell])
AC_INIT([gnome-shell],[3.14.4],[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.13.3
GTK_MIN_VERSION=3.7.9
MUTTER_MIN_VERSION=3.14.4
GTK_MIN_VERSION=3.13.2
GIO_MIN_VERSION=2.37.0
LIBECAL_MIN_VERSION=3.5.3
LIBEDATASERVER_MIN_VERSION=3.5.3
@ -232,7 +232,9 @@ esac
AM_CFLAGS="$AM_CFLAGS $WARN_CFLAGS"
AC_SUBST(AM_CFLAGS)
BROWSER_PLUGIN_DIR="${BROWSER_PLUGIN_DIR:-"\${libdir}/mozilla/plugins"}"
if test -z "${BROWSER_PLUGIN_DIR}"; then
BROWSER_PLUGIN_DIR="\${libdir}/mozilla/plugins"
fi
AC_ARG_VAR([BROWSER_PLUGIN_DIR],[Where to install the plugin to])
AC_CONFIG_FILES([

View File

@ -74,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)
@ -106,6 +113,7 @@ 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
@ -117,6 +125,7 @@ CLEANFILES += \
$(desktop_DATA) \
$(keys_DATA) \
$(gsettings_SCHEMAS) \
perf-background.xml \
gschemas.compiled \
org.gnome.shell.gschema.valid \
org.gnome.shell.gschema.xml.in

View File

@ -31,7 +31,7 @@
</_description>
</key>
<key name="favorite-apps" type="as">
<default>[ 'epiphany.desktop', 'evolution.desktop', 'empathy.desktop', 'rhythmbox.desktop', 'shotwell.desktop', 'libreoffice-writer.desktop', 'org.gnome.Nautilus.desktop', 'org.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
@ -74,7 +74,6 @@
<child name="calendar" schema="org.gnome.shell.calendar"/>
<child name="keybindings" schema="org.gnome.shell.keybindings"/>
<child name="keyboard" schema="org.gnome.shell.keyboard"/>
<child name="location" schema="org.gnome.shell.location"/>
</schema>
<schema id="org.gnome.shell.calendar" path="/org/gnome/shell/calendar/"
@ -144,32 +143,6 @@
</key>
</schema>
<enum id="org.gnome.shell.geoclue.AccuracyLevel">
<value value="0" nick="off"/>
<value value="1" nick="country"/>
<value value="4" nick="city"/>
<value value="5" nick="neighborhood"/>
<value value="6" nick="street"/>
<value value="8" nick="exact"/>
</enum>
<schema id="org.gnome.shell.location"
path="/org/gnome/shell/location/"
gettext-domain="@GETTEXT_PACKAGE@">
<key name="max-accuracy-level" enum="org.gnome.shell.geoclue.AccuracyLevel">
<default>'exact'</default>
<_summary>The maximum accuracy level of location.</_summary>
<_description>
Configures the maximum level of location accuracy applications are
allowed to see. Valid options are 'off' (disable location tracking),
'country', 'city', 'neighborhood', 'street', and 'exact' (typically
requires GPS receiver). Please keep in mind that this only controls
what GeoClue will allow applications to see and they can find user's
location on their own using network resources (albeit with street-level
accuracy at best).
</_description>
</key>
</schema>
<schema id="org.gnome.shell.app-switcher"
path="/org/gnome/shell/app-switcher/"
gettext-domain="@GETTEXT_PACKAGE@">

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

@ -232,6 +232,10 @@ StScrollBar StButton#vhandle:active {
border-width: 0px;
}
.app-well-menu {
max-width: 400px;
}
/* The remaining popup-menu sizing is all done in ems, so that if you
* override .popup-menu.font-size, everything else will scale with it.
*/
@ -478,7 +482,7 @@ StScrollBar StButton#vhandle:active {
/* Common radii */
#searchEntry,
.search-entry,
.modal-dialog-button,
.notification-button,
.hotplug-notification-item,
@ -500,7 +504,7 @@ StScrollBar StButton#vhandle:active {
/* Entries */
#searchEntry,
.search-entry,
.login-dialog StEntry,
.notification StEntry,
.modal-dialog StEntry {
@ -512,7 +516,7 @@ StScrollBar StButton#vhandle:active {
padding: 4px 12px;
}
#searchEntry,
.search-entry,
.login-dialog StEntry,
.run-dialog-entry,
.notification StEntry {
@ -524,8 +528,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 {
@ -542,18 +546,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;
@ -917,7 +921,7 @@ StScrollBar StButton#vhandle:active {
/* Search Box */
#searchEntry {
.search-entry {
width: 320px;
}
@ -926,8 +930,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;
}
@ -1159,6 +1163,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);
@ -1489,6 +1494,10 @@ StScrollBar StButton#vhandle:active {
text-align: right;
}
.events-day-time-ellipses {
color: rgba(153, 153, 153, 1.0);
}
.events-day-time:rtl {
text-align: left;
}
@ -2092,6 +2101,11 @@ StScrollBar StButton#vhandle:active {
font-size: 10pt;
}
/* Restart message */
.restart-message {
font-size: 14pt;
}
/* ShellMountOperation Dialogs */
.shell-mount-operation-icon {
icon-size: 48px;

View File

@ -27,7 +27,9 @@ its dependencies to build from tarballs.</description>
<download-page rdf:resource="http://download.gnome.org/sources/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

@ -13,7 +13,7 @@ misc/config.js: misc/config.js.in Makefile
-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

@ -54,6 +54,7 @@ const Application = new Lang.Class({
this._startupUuid = null;
this._loaded = false;
this._skipMainWindow = false;
this._settings = new Gio.Settings({ schema_id: 'org.gnome.shell' });
},
_extensionAvailable: function(uuid) {
@ -62,9 +63,6 @@ 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;
@ -283,6 +281,10 @@ const ExtensionRow = new Lang.Class({
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();
},
@ -321,6 +323,7 @@ const ExtensionRow = new Lang.Class({
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() {
@ -333,6 +336,13 @@ const ExtensionRow = new Lang.Class({
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;

View File

@ -134,8 +134,7 @@ const AuthPrompt = new Lang.Class({
},
_onDestroy: function() {
this._userVerifier.clear();
this._userVerifier.disconnectAll();
this._userVerifier.destroy();
this._userVerifier = null;
},
@ -261,6 +260,7 @@ const AuthPrompt = new Lang.Class({
_onVerificationComplete: function() {
this.verificationStatus = AuthPromptStatus.VERIFICATION_SUCCEEDED;
this.cancelButton.reactive = false;
},
_onReset: function() {
@ -419,17 +419,20 @@ const AuthPrompt = new Lang.Class({
},
setUser: function(user) {
let oldChild = this._userWell.get_child();
if (oldChild)
oldChild.destroy();
if (user) {
let userWidget = new UserWidget.UserWidget(user);
this._userWell.set_child(userWidget.actor);
} else {
this._userWell.set_child(null);
}
},
reset: function() {
let oldStatus = this.verificationStatus;
this.verificationStatus = AuthPromptStatus.NOT_VERIFYING;
this.cancelButton.reactive = true;
if (oldStatus == AuthPromptStatus.VERIFYING)
this._userVerifier.cancel();
@ -498,6 +501,9 @@ const AuthPrompt = new Lang.Class({
},
cancel: function() {
if (this.verificationStatus == AuthPromptStatus.NOT_VERIFYING || this.verificationStatus == AuthPromptStatus.VERIFICATION_SUCCEEDED) {
return;
}
this.reset();
this.emit('cancelled');
}

View File

@ -22,6 +22,7 @@ const Clutter = imports.gi.Clutter;
const Gdm = imports.gi.Gdm;
const Gio = imports.gi.Gio;
const GLib = imports.gi.GLib;
const GObject = imports.gi.GObject;
const Gtk = imports.gi.Gtk;
const Lang = imports.lang;
const Mainloop = imports.mainloop;
@ -64,10 +65,15 @@ const UserListItem = new Lang.Class({
reactive: true,
x_align: St.Align.START,
x_fill: true });
this.actor.connect('destroy',
Lang.bind(this, this._onDestroy));
this._userWidget = new UserWidget.UserWidget(this.user);
layout.add(this._userWidget.actor);
this._userWidget.actor.bind_property('label-actor', this.actor, 'label-actor',
GObject.BindingFlags.SYNC_CREATE);
this._timedLoginIndicator = new St.Bin({ style_class: 'login-dialog-timed-login-indicator',
scale_x: 0 });
layout.add(this._timedLoginIndicator);
@ -87,6 +93,10 @@ const UserListItem = new Lang.Class({
this.actor.remove_style_pseudo_class('logged-in');
},
_onDestroy: function() {
this._user.disconnect(this._userChangedId);
},
_onClicked: function() {
this.emit('activate');
},
@ -373,13 +383,12 @@ const LoginDialog = new Lang.Class({
if (GLib.getenv('GDM_GREETER_TEST') != '1') {
this._greeter = gdmClient.get_greeter_sync(null);
this._greeter.connect('default-session-name-changed',
Lang.bind(this, this._onDefaultSessionChanged));
this._greeter.connect('session-opened',
Lang.bind(this, this._onSessionOpened));
this._greeter.connect('timed-login-requested',
Lang.bind(this, this._onTimedLoginRequested));
this._defaultSessionChangedId = this._greeter.connect('default-session-name-changed',
Lang.bind(this, this._onDefaultSessionChanged));
this._sessionOpenedId = this._greeter.connect('session-opened',
Lang.bind(this, this._onSessionOpened));
this._timedLoginRequestedId = this._greeter.connect('timed-login-requested',
Lang.bind(this, this._onTimedLoginRequested));
}
this._settings = new Gio.Settings({ schema_id: GdmUtil.LOGIN_SCREEN_SCHEMA });
@ -394,8 +403,8 @@ const LoginDialog = new Lang.Class({
Lang.bind(this, this._updateLogo));
this._textureCache = St.TextureCache.get_default();
this._textureCache.connect('texture-file-changed',
Lang.bind(this, this._updateLogoTexture));
this._updateLogoTextureId = this._textureCache.connect('texture-file-changed',
Lang.bind(this, this._updateLogoTexture));
this._userSelectionBox = new St.BoxLayout({ style_class: 'login-dialog-user-selection-box',
x_align: Clutter.ActorAlign.CENTER,
@ -476,8 +485,8 @@ const LoginDialog = new Lang.Class({
// 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));
this._startupCompleteId = Main.layoutManager.connect('startup-complete',
Lang.bind(this, this._updateDisableUserList));
},
_ensureUserListLoaded: function() {
@ -638,6 +647,8 @@ const LoginDialog = new Lang.Class({
realmManager.release();
}));
this._updateCancelButton();
this._authPrompt.updateSensitivity(true);
this._showPrompt();
},
@ -665,10 +676,12 @@ const LoginDialog = new Lang.Class({
},
_gotGreeterSessionProxy: function(proxy) {
proxy.connect('g-properties-changed', Lang.bind(this, function() {
if (proxy.Active)
this._loginScreenSessionActivated();
}));
this._greeterSessionProxy = proxy;
this._greeterSessionProxyChangedId =
proxy.connect('g-properties-changed', Lang.bind(this, function() {
if (proxy.Active)
this._loginScreenSessionActivated();
}));
},
_startSession: function(serviceName) {
@ -890,6 +903,30 @@ const LoginDialog = new Lang.Class({
this._userManager.disconnect(this._userManagerLoadedId);
this._userManagerLoadedId = 0;
}
if (this._userAddedId) {
this._userManager.disconnect(this._userAddedId);
this._userAddedId = 0;
}
if (this._userRemovedId) {
this._userManager.disconnect(this._userRemovedId);
this._userRemovedId = 0;
}
this._textureCache.disconnect(this._updateLogoTextureId);
Main.layoutManager.disconnect(this._startupCompleteId);
if (this._settings) {
this._settings.run_dispose();
this._settings = null;
}
if (this._greeter) {
this._greeter.disconnect(this._defaultSessionChangedId);
this._greeter.disconnect(this._sessionOpenedId);
this._greeter.disconnect(this._timedLoginRequestedId);
this._greeter = null;
}
if (this._greeterSessionProxy) {
this._greeterSessionProxy.disconnect(this._greeterSessionProxyChangedId);
this._greeterSessionProxy = null;
}
},
_loadUserList: function() {
@ -904,15 +941,15 @@ const LoginDialog = new Lang.Class({
this._userList.addUser(users[i]);
}
this._userManager.connect('user-added',
Lang.bind(this, function(userManager, user) {
this._userList.addUser(user);
}));
this._userAddedId = this._userManager.connect('user-added',
Lang.bind(this, function(userManager, user) {
this._userList.addUser(user);
}));
this._userManager.connect('user-removed',
Lang.bind(this, function(userManager, user) {
this._userList.removeUser(user);
}));
this._userRemovedId = this._userManager.connect('user-removed',
Lang.bind(this, function(userManager, user) {
this._userList.removeUser(user);
}));
return GLib.SOURCE_REMOVE;
},
@ -926,6 +963,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,
@ -935,7 +974,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

@ -142,10 +142,10 @@ const ShellUserVerifier = new Lang.Class({
// after a user has been picked.
this._checkForSmartcard();
this._smartcardManager.connect('smartcard-inserted',
Lang.bind(this, this._checkForSmartcard));
this._smartcardManager.connect('smartcard-removed',
Lang.bind(this, this._checkForSmartcard));
this._smartcardInsertedId = this._smartcardManager.connect('smartcard-inserted',
Lang.bind(this, this._checkForSmartcard));
this._smartcardRemovedId = this._smartcardManager.connect('smartcard-removed',
Lang.bind(this, this._checkForSmartcard));
this._messageQueue = [];
this._messageQueueTimeoutId = 0;
@ -159,8 +159,8 @@ const ShellUserVerifier = new Lang.Class({
if (this._oVirtCredentialsManager.hasToken())
this._oVirtUserAuthenticated(this._oVirtCredentialsManager.getToken());
this._oVirtCredentialsManager.connect('user-authenticated',
Lang.bind(this, this._oVirtUserAuthenticated));
this._oVirtUserAuthenticatedId = this._oVirtCredentialsManager.connect('user-authenticated',
Lang.bind(this, this._oVirtUserAuthenticated));
},
begin: function(userName, hold) {
@ -191,20 +191,37 @@ const ShellUserVerifier = new Lang.Class({
}
},
_clearUserVerifier: function() {
if (this._userVerifier) {
this._userVerifier.run_dispose();
this._userVerifier = null;
}
},
clear: function() {
if (this._cancellable) {
this._cancellable.cancel();
this._cancellable = null;
}
if (this._userVerifier) {
this._userVerifier.run_dispose();
this._userVerifier = null;
}
this._clearUserVerifier();
this._clearMessageQueue();
},
destroy: function() {
this.clear();
this._settings.run_dispose();
this._settings = null;
this._smartcardManager.disconnect(this._smartcardInsertedId);
this._smartcardManager.disconnect(this._smartcardRemovedId);
this._smartcardManager = null;
this._oVirtCredentialsManager.disconnect(this._oVirtUserAuthenticatedId);
this._oVirtCredentialsManager = null;
},
answerQuery: function(serviceName, answer) {
if (!this.hasPendingMessages) {
this._userVerifier.call_answer_query(serviceName, answer, this._cancellable, null);
@ -283,9 +300,10 @@ const ShellUserVerifier = new Lang.Class({
this._fprintManager.GetDefaultDeviceRemote(Gio.DBusCallFlags.NONE, this._cancellable, Lang.bind(this,
function(device, error) {
if (!error && device)
if (!error && device) {
this._haveFingerprintReader = true;
this._updateDefaultService();
}
}));
},
@ -326,6 +344,7 @@ const ShellUserVerifier = new Lang.Class({
_reauthenticationChannelOpened: function(client, result) {
try {
this._clearUserVerifier();
this._userVerifier = client.open_reauthentication_channel_finish(result);
} catch(e if e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) {
return;
@ -349,6 +368,7 @@ const ShellUserVerifier = new Lang.Class({
_userVerifierGot: function(client, result) {
try {
this._clearUserVerifier();
this._userVerifier = client.get_user_verifier_finish(result);
} catch(e if e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) {
return;

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,7 @@
<file>misc/util.js</file>
<file>perf/core.js</file>
<file>perf/hwtest.js</file>
<file>portalHelper/main.js</file>
@ -41,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>

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

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

View File

@ -49,13 +49,14 @@ const PortalWindow = new Lang.Class({
_init: function(application, url, timestamp, doneCallback) {
this.parent({ application: application });
if (url) {
this._uri = new Soup.URI(uri);
} else {
if (!url) {
url = 'http://www.gnome.org';
this._uri = null;
this._everSeenRedirect = false;
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;
@ -110,37 +111,7 @@ const PortalWindow = new Lang.Class({
let request = decision.get_request();
let uri = new Soup.URI(request.get_uri());
if (this._uri != null) {
if (!uri.host_equal(uri, this._uri)) {
// 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
// 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;
} else {
if (!uri.host_equal(this._uri) && this._originalUrlWasGnome) {
if (uri.get_host() == 'www.gnome.org' && this._everSeenRedirect) {
// Yay, we got to gnome!
decision.ignore();
@ -151,6 +122,34 @@ const PortalWindow = new Lang.Class({
}
}
// 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;
},

View File

@ -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) {
@ -365,9 +359,18 @@ const WindowSwitcherPopup = new Lang.Class({
Name: 'WindowSwitcherPopup',
Extends: SwitcherPopup.SwitcherPopup,
_init: function(items) {
this.parent(items);
_init: function() {
this.parent();
this._settings = new Gio.Settings({ schema_id: 'org.gnome.shell.window-switcher' });
let windows = this._getWindowList();
if (windows.length == 0)
return;
let mode = this._settings.get_enum('app-icon-mode');
this._switcherList = new WindowList(windows, mode);
this._items = this._switcherList.icons;
},
_getWindowList: function() {
@ -375,34 +378,9 @@ const WindowSwitcherPopup = new Lang.Class({
return global.display.get_tab_list(Meta.TabList.NORMAL, workspace);
},
_createSwitcher: function() {
let windows = this._getWindowList();
if (windows.length == 0)
return false;
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);
},
_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 {

View File

@ -34,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;
@ -43,6 +45,16 @@ const INDICATORS_BASE_TIME = 0.25;
const INDICATORS_ANIMATION_DELAY = 0.125;
const INDICATORS_ANIMATION_MAX_TIME = 0.75;
// 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;
@ -177,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) {
@ -237,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;
@ -245,24 +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,
{ translation_x: isAnimationIn ? 0 : offset,
time: baseTime + delay * i,
transition: 'easeInOutQuad',
delay: VIEWS_SWITCH_ANIMATION_DELAY
delay: isAnimationIn ? VIEWS_SWITCH_ANIMATION_DELAY : 0
});
}
}
@ -305,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);
@ -437,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) {
pageNumber = clamp(pageNumber, 0, this._grid.nPages() - 1);
if (this._currentPage == pageNumber && this._displayingPopup && this._currentPopup)
if (this._grid.currentPage == pageNumber && this._displayingPopup && this._currentPopup)
return;
if (this._displayingPopup && this._currentPopup)
this._currentPopup.popdown();
@ -464,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;
@ -475,9 +605,9 @@ const AllView = new Lang.Class({
// longer than PAGE_SWITCH_TIME
time = Math.min(time, PAGE_SWITCH_TIME);
this._currentPage = pageNumber;
this._grid.currentPage = pageNumber;
Tweener.addTween(this._adjustment,
{ value: this._grid.getPageY(this._currentPage),
{ value: this._grid.getPageY(this._grid.currentPage),
time: time,
transition: 'easeOutQuad' });
this._pageIndicators.setCurrentPage(pageNumber);
@ -506,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;
},
@ -548,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;
}
@ -612,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());
@ -773,6 +904,19 @@ const AppDisplay = new Lang.Class({
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 }));
@ -796,23 +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: VIEWS_SWITCH_TIME,
opacity: (i == activeIndex) ? 255 : 0,
delay: (i == activeIndex) ? VIEWS_SWITCH_ANIMATION_DELAY : 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);
}
},
@ -894,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;
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);
@ -945,8 +1085,13 @@ const FolderView = new Lang.Class({
Util.ensureActorVisibleInScrollView(this.actor, actor);
},
// Overriden from BaseAppView
animate: function(animationDirection) {
this._grid.animatePulse(animationDirection);
},
createFolderIcon: function(size) {
let layout = new Clutter.TableLayout();
let layout = new Clutter.GridLayout();
let icon = new St.Widget({ layout_manager: layout,
style_class: 'app-folder-icon' });
layout.hookup_style(icon);
@ -962,7 +1107,7 @@ const FolderView = new Lang.Class({
} else {
bin = new St.Bin({ width: subSize, height: subSize });
}
layout.pack(bin, rtl ? (i + 1) % 2 : i % 2, Math.floor(i / 2));
layout.attach(bin, rtl ? (i + 1) % 2 : i % 2, Math.floor(i / 2), 1, 1);
}
return icon;
@ -1122,6 +1267,7 @@ const FolderIcon = new Lang.Class({
addAppId(appInfo.get_id());
});
this.actor.visible = this.view.getAllItems().length > 0;
this.view.loadGrid();
this.emit('apps-changed');
},
@ -1253,6 +1399,51 @@ const AppFolderPopup = new Lang.Class({
}));
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 (global.stage.get_key_focus() != actor)
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
// 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() {
@ -1275,10 +1466,17 @@ const AppFolderPopup = new Lang.Class({
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);
this.actor.navigate_focus(null, Gtk.DirectionType.TAB_FORWARD, false);
BoxPointer.PopupAnimation.SLIDE,
Lang.bind(this,
function() {
this._view.actor.opacity = 255;
this._view.animate(IconGrid.AnimationDirection.IN);
}));
this.emit('open-state-changed', true);
},
@ -1339,7 +1537,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));
@ -1364,10 +1564,11 @@ const AppIcon = new Lang.Class({
this.actor.connect('destroy', Lang.bind(this, this._onDestroy));
this._menuTimeoutId = 0;
this._stateChangedId = this.app.connect('notify::state',
Lang.bind(this,
this._onStateChanged));
this._onStateChanged();
this._stateChangedId = this.app.connect('notify::state', Lang.bind(this,
function () {
this._updateRunningStyle();
}));
this._updateRunningStyle();
},
_onDestroy: function() {
@ -1388,24 +1589,33 @@ const AppIcon = new Lang.Class({
}
},
_onStateChanged: function() {
_updateRunningStyle: function() {
if (this.app.state != Shell.AppState.STOPPED)
this.actor.add_style_class_name('running');
else
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;
}));
GLib.Source.set_name_by_id(this._menuTimeoutId, '[gnome-shell] this.popupMenu');
this._setPopupTimeout();
} else if (button == 3) {
this.popupMenu();
return Clutter.EVENT_STOP;
@ -1413,16 +1623,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) {
this.app.open_new_window(-1);
Main.overview.hide();
}
return false;
this.activate(button);
},
_onKeyboardPopupMenu: function() {
@ -1448,7 +1658,10 @@ const AppIcon = new Lang.Class({
if (!isPoppedUp)
this._onMenuPoppedDown();
}));
Main.overview.connect('hiding', Lang.bind(this, function () { this._menu.close(); }));
let id = Main.overview.connect('hiding', Lang.bind(this, function () { this._menu.close(); }));
this.actor.connect('destroy', function() {
Main.overview.disconnect(id);
});
this._menuManager.addMenu(this._menu);
}
@ -1476,19 +1689,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) {
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 });
@ -1567,12 +1790,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();

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,8 +33,7 @@ function addBackgroundMenu(actor, layoutManager) {
actor._backgroundManager = new PopupMenu.PopupMenuManager({ actor: actor });
actor._backgroundManager.addMenu(actor._backgroundMenu);
function openMenu() {
let [x, y] = global.get_pointer();
function openMenu(x, y) {
Main.layoutManager.setDummyCursorGeometry(x, y, 0, 0);
actor._backgroundMenu.open(BoxPointer.PopupAnimation.NONE);
}
@ -42,22 +41,32 @@ function addBackgroundMenu(actor, layoutManager) {
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

@ -2,6 +2,7 @@
const Clutter = imports.gi.Clutter;
const Gio = imports.gi.Gio;
const Gtk = imports.gi.Gtk;
const GLib = imports.gi.GLib;
const Lang = imports.lang;
const St = imports.gi.St;
@ -13,6 +14,7 @@ const Shell = imports.gi.Shell;
const MSECS_IN_DAY = 24 * 60 * 60 * 1000;
const SHOW_WEEKDATE_KEY = 'show-weekdate';
const ELLIPSIS_CHAR = '\u2026';
// alias to prevent xgettext from picking up strings translated in GTK+
const gtk30_ = Gettext_gtk30.gettext;
@ -58,19 +60,21 @@ function _getEndOfDay(date) {
return ret;
}
function _formatEventTime(event, clockFormat) {
function _formatEventTime(event, clockFormat, periodBegin, periodEnd) {
let ret;
if (event.allDay) {
let allDay = (event.allDay || (event.date <= periodBegin && event.end >= periodEnd));
if (allDay) {
/* Translators: Shown in calendar event list for all day events
* Keep it short, best if you can use less then 10 characters
*/
ret = C_("event list time", "All Day");
} else {
let date = event.date >= periodBegin ? event.date : event.end;
switch (clockFormat) {
case '24h':
/* Translators: Shown in calendar event list, if 24h format,
\u2236 is a ratio character, similar to : */
ret = event.date.toLocaleFormat(C_("event list time", "%H\u2236%M"));
ret = date.toLocaleFormat(C_("event list time", "%H\u2236%M"));
break;
default:
@ -79,30 +83,13 @@ function _formatEventTime(event, clockFormat) {
/* Translators: Shown in calendar event list, if 12h format,
\u2236 is a ratio character, similar to : and \u2009 is
a thin space */
ret = event.date.toLocaleFormat(C_("event list time", "%l\u2236%M\u2009%p"));
ret = date.toLocaleFormat(C_("event list time", "%l\u2236%M\u2009%p"));
break;
}
}
return ret;
}
function _getCalendarWeekForDate(date) {
// Based on the algorithms found here:
// http://en.wikipedia.org/wiki/Talk:ISO_week_date
let midnightDate = new Date(date.getFullYear(), date.getMonth(), date.getDate());
// Need to get Monday to be 1 ... Sunday to be 7
let dayOfWeek = 1 + ((midnightDate.getDay() + 6) % 7);
let nearestThursday = new Date(midnightDate.getFullYear(), midnightDate.getMonth(),
midnightDate.getDate() + (4 - dayOfWeek));
let jan1st = new Date(nearestThursday.getFullYear(), 0, 1);
let diffDate = nearestThursday - jan1st;
let dayNumber = Math.floor(Math.abs(diffDate) / MSECS_IN_DAY);
let weekNumber = Math.floor(dayNumber / 7) + 1;
return weekNumber;
}
function _getCalendarDayAbbreviation(dayNumber) {
let abbreviations = [
/* Translators: Calendar grid abbreviation for Sunday.
@ -248,11 +235,24 @@ const DBusEventSource = new Lang.Class({
this._initialized = false;
this._dbusProxy = new CalendarServer();
this._dbusProxy.init_async(GLib.PRIORITY_DEFAULT, null, Lang.bind(this, function(object, result) {
let loaded = false;
try {
this._dbusProxy.init_finish(result);
loaded = true;
} catch(e) {
log('Error loading calendars: ' + e.message);
return;
if (e.matches(Gio.DBusError, Gio.DBusError.TIMED_OUT)) {
// Ignore timeouts and install signals as normal, because with high
// probability the service will appear later on, and we will get a
// NameOwnerChanged which will finish loading
//
// (But still _initialized to false, because the proxy does not know
// about the HasCalendars property and would cause an exception trying
// to read it)
} else {
log('Error loading calendars: ' + e.message);
return;
}
}
this._dbusProxy.connectSignal('Changed', Lang.bind(this, this._onChanged));
@ -268,9 +268,11 @@ const DBusEventSource = new Lang.Class({
this.emit('notify::has-calendars');
}));
this._initialized = true;
this.emit('notify::has-calendars');
this._onNameAppeared();
this._initialized = loaded;
if (loaded) {
this.emit('notify::has-calendars');
this._onNameAppeared();
}
}));
},
@ -292,6 +294,7 @@ const DBusEventSource = new Lang.Class({
},
_onNameAppeared: function(owner) {
this._initialized = true;
this._resetCache();
this._loadEvents(true);
},
@ -361,6 +364,12 @@ const DBusEventSource = new Lang.Class({
result.push(event);
}
}
result.sort(function(event1, event2) {
// sort events by end time on ending day
let d1 = event1.date < begin && event1.end <= end ? event1.end : event1.date;
let d2 = event2.date < begin && event2.end <= end ? event2.end : event2.date;
return d1.getTime() - d2.getTime();
});
return result;
},
@ -409,7 +418,7 @@ const Calendar = new Lang.Class({
this._shouldDateGrabFocus = false;
this.actor = new St.Widget({ style_class: 'calendar',
layout_manager: new Clutter.TableLayout(),
layout_manager: new Clutter.GridLayout(),
reactive: true });
this.actor.connect('scroll-event',
@ -447,8 +456,7 @@ const Calendar = new Lang.Class({
// Top line of the calendar '<| September 2009 |>'
this._topBox = new St.BoxLayout();
layout.pack(this._topBox, 0, 0);
layout.set_span(this._topBox, offsetCols + 7, 1);
layout.attach(this._topBox, 0, 0, offsetCols + 7, 1);
this._backButton = new St.Button({ style_class: 'calendar-change-month-back',
accessible_name: _("Previous month"),
@ -485,7 +493,7 @@ const Calendar = new Lang.Class({
col = 6 - (7 + iter.getDay() - this._weekStart) % 7;
else
col = offsetCols + (7 + iter.getDay() - this._weekStart) % 7;
layout.pack(label, col, 1);
layout.attach(label, col, 1, 1, 1);
iter.setTime(iter.getTime() + MSECS_IN_DAY);
}
@ -595,6 +603,7 @@ const Calendar = new Lang.Class({
beginDate.setHours(12);
this._calendarBegin = new Date(beginDate);
this._markedAsToday = now;
let year = beginDate.getYear();
@ -657,14 +666,14 @@ const Calendar = new Lang.Class({
col = 6 - (7 + iter.getDay() - this._weekStart) % 7;
else
col = offsetCols + (7 + iter.getDay() - this._weekStart) % 7;
layout.pack(button, col, row);
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(),
let label = new St.Label({ text: iter.toLocaleFormat('%V'),
style_class: 'calendar-day-base calendar-week-number'});
layout.pack(label, rtl ? 7 : 0, row);
layout.attach(label, rtl ? 7 : 0, row, 1, 1);
}
iter.setTime(iter.getTime() + MSECS_IN_DAY);
@ -686,7 +695,7 @@ const Calendar = new Lang.Class({
else
this._monthLabel.text = this._selectedDate.toLocaleFormat(this._headerFormat);
if (!this._calendarBegin || !_sameMonth(this._selectedDate, this._calendarBegin))
if (!this._calendarBegin || !_sameMonth(this._selectedDate, this._calendarBegin) || !_sameDay(now, this._markedAsToday))
this._rebuildCalendar();
this._buttons.forEach(Lang.bind(this, function(button) {
@ -707,7 +716,7 @@ const EventsList = new Lang.Class({
Name: 'EventsList',
_init: function() {
let layout = new Clutter.TableLayout();
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);
@ -722,68 +731,85 @@ const EventsList = new Lang.Class({
this._eventSource.connect('changed', Lang.bind(this, this._update));
},
_addEvent: function(event, index, includeDayName) {
_addEvent: function(event, index, includeDayName, periodBegin, periodEnd) {
let eventBox = new St.BoxLayout();
eventBox.set_vertical(false);
let dayString;
if (includeDayName)
dayString = _getEventDayAbbreviation(event.date.getDay());
else
if (includeDayName) {
if (event.date >= periodBegin)
dayString = _getEventDayAbbreviation(event.date.getDay());
else /* show event end day if it began earlier */
dayString = _getEventDayAbbreviation(event.end.getDay());
} else {
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;
let rtl = this.actor.get_text_direction() == Clutter.TextDirection.RTL;
let layout = this.actor.layout_manager;
layout.pack(dayLabel, rtl ? 2 : 0, index);
layout.child_set(dayLabel, { x_expand: false,
x_align: Clutter.TableAlignment.END,
y_align: Clutter.TableAlignment.START });
eventBox.add_actor(dayLabel);
let clockFormat = this._desktopSettings.get_string(CLOCK_FORMAT_KEY);
let timeString = _formatEventTime(event, clockFormat);
let timeString = _formatEventTime(event, clockFormat, periodBegin, periodEnd);
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;
layout.pack(timeLabel, 1, index);
layout.child_set(timeLabel, { x_expand: false,
y_align: Clutter.TableAlignment.START });
let preEllipsisLabel = new St.Label({ style_class: 'events-day-time-ellipses',
text: ELLIPSIS_CHAR,
y_align: Clutter.ActorAlign.START });
let postEllipsisLabel = new St.Label({ style_class: 'events-day-time-ellipses',
text: ELLIPSIS_CHAR,
y_align: Clutter.ActorAlign.START });
if (event.allDay || event.date >= periodBegin)
preEllipsisLabel.opacity = 0;
if (event.allDay || event.end <= periodEnd)
postEllipsisLabel.opacity = 0;
let timeLabelBoxLayout = new St.BoxLayout({ x_align: Clutter.ActorAlign.START });
timeLabelBoxLayout.add(preEllipsisLabel);
timeLabelBoxLayout.add(timeLabel);
timeLabelBoxLayout.add(postEllipsisLabel);
timeLabelBoxLayout.set_size(50, 1);
eventBox.add_actor(timeLabelBoxLayout);
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;
layout.pack(titleLabel, rtl ? 0 : 2, index);
layout.child_set(titleLabel, { x_expand: true });
eventBox.add_actor(titleLabel);
this._eventListBox.add_actor(eventBox);
},
_addPeriod: function(header, index, begin, end, includeDayName, showNothingScheduled) {
let events = this._eventSource.getEvents(begin, end);
_addPeriod: function(header, index, periodBegin, periodEnd, includeDayName, showNothingScheduled) {
let events = this._eventSource.getEvents(periodBegin, periodEnd);
if (events.length == 0 && !showNothingScheduled)
return index;
let label = new St.Label({ style_class: 'events-day-header', text: header });
let layout = this.actor.layout_manager;
layout.pack(label, 0, index);
layout.child_set(label, { column_span: 3, x_expand: false });
this._eventListBox.add_actor(label);
index++;
for (let n = 0; n < events.length; n++) {
this._addEvent(events[n], index, includeDayName);
this._addEvent(events[n], index, includeDayName, periodBegin, periodEnd);
index++;
}
if (events.length == 0 && showNothingScheduled) {
let now = new Date();
/* Translators: Text to show if there are no events */
let nothingEvent = new CalendarEvent(now, now, _("Nothing Scheduled"), true);
this._addEvent(nothingEvent, index, false);
let nothingEvent = new CalendarEvent(periodBegin, periodBegin, _("Nothing Scheduled"), true);
this._addEvent(nothingEvent, index, false, periodBegin, periodEnd);
index++;
}
@ -791,8 +817,6 @@ const EventsList = new Lang.Class({
},
_showOtherDay: function(day) {
this.actor.destroy_all_children();
let dayBegin = _getBeginningOfDay(day);
let dayEnd = _getEndOfDay(day);
@ -808,7 +832,6 @@ const EventsList = new Lang.Class({
},
_showToday: function() {
this.actor.destroy_all_children();
let index = 0;
let now = new Date();
@ -853,6 +876,24 @@ const EventsList = new Lang.Class({
if (this._eventSource.isLoading)
return;
this.actor.destroy_all_children();
let layout = this.actor.layout_manager;
this._eventListContainer = new St.BoxLayout({ x_expand: true, y_expand: true });
this._eventListContainer.set_vertical(true);
this._eventListBox = new St.BoxLayout();
this._eventListBox.set_vertical(true);
let eventScrollView = new St.ScrollView({style_class: 'vfade',
hscrollbar_policy: Gtk.PolicyType.NEVER,
vscrollbar_policy: Gtk.PolicyType.AUTOMATIC});
eventScrollView.add_actor(this._eventListBox);
this._eventListContainer.add_actor(eventScrollView);
layout.attach(this._eventListContainer, 0, 0, 1, 1);
let today = new Date();
if (_sameDay (this._date, today)) {
this._showToday();

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,7 +72,7 @@ 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);
@ -83,14 +83,17 @@ const NetworkSecretDialog = new Lang.Class({
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 });
@ -118,14 +121,12 @@ const NetworkSecretDialog = new Lang.Class({
secret.valid = true;
if (rtl) {
layout.pack(secret.entry, 0, pos);
layout.pack(label, 1, pos);
layout.attach(secret.entry, 0, pos, 1, 1);
layout.attach(label, 1, pos, 1, 1);
} else {
layout.pack(label, 0, pos);
layout.pack(secret.entry, 1, pos);
layout.attach(label, 0, pos, 1, 1);
layout.attach(secret.entry, 1, pos, 1, 1);
}
layout.child_set(label, { x_expand: false, y_fill: false,
x_align: Clutter.TableAlignment.START });
pos++;
if (secret.password)
@ -379,6 +380,12 @@ const VPNRequestHandler = new Lang.Class({
argv.push('-i');
if (flags & NMClient.SecretAgentGetSecretsFlags.REQUEST_NEW)
argv.push('-r');
if (authHelper.supportsHints) {
for (let i = 0; i < hints.length; i++) {
argv.push('-t');
argv.push(hints[i]);
}
}
this._newStylePlugin = authHelper.externalUIMode;
@ -597,7 +604,15 @@ const NetworkAgent = new Lang.Class({
Name: 'NetworkAgent',
_init: function() {
this._native = new Shell.NetworkAgent({ identifier: 'org.gnome.Shell.NetworkAgent' });
try {
this._native = new Shell.NetworkAgent({ identifier: 'org.gnome.Shell.NetworkAgent',
capabilities: NMClient.SecretAgentCapabilities.VPN_HINTS
});
} catch(e) {
// Support older versions without NetworkAgent:capabilities
this._native = new Shell.NetworkAgent({ identifier: 'org.gnome.Shell.NetworkAgent'
});
}
this._dialogs = { };
this._vpnRequests = { };
@ -697,16 +712,23 @@ const NetworkAgent = new Lang.Class({
let service = keyfile.get_string('VPN Connection', 'service');
let binary = keyfile.get_string('GNOME', 'auth-dialog');
let externalUIMode = false;
let hints = false;
try {
externalUIMode = keyfile.get_boolean('GNOME', 'supports-external-ui-mode');
} catch(e) { } // ignore errors if key does not exist
try {
hints = keyfile.get_boolean('GNOME', 'supports-hints');
} catch(e) { } // ignore errors if key does not exist
let path = binary;
if (!GLib.path_is_absolute(path)) {
path = GLib.build_filenamev([Config.LIBEXECDIR, path]);
}
if (GLib.file_test(path, GLib.FileTest.IS_EXECUTABLE))
this._vpnBinaries[service] = { fileName: path, externalUIMode: externalUIMode };
this._vpnBinaries[service] = { fileName: path, externalUIMode: externalUIMode, supportsHints: hints };
else
throw new Error('VPN plugin at %s is not executable'.format(path));
} catch(e) {

View File

@ -863,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();
}
},
/**
@ -911,16 +904,19 @@ const ChatNotification = new Lang.Class({
this._lastGroup = group;
let emptyLine = new St.Label({ style_class: 'chat-empty-line' });
this.addActor(emptyLine);
this._history.unshift({ actor: emptyLine, time: timestamp,
realMessage: false });
}
this._lastMessageBox = new St.BoxLayout({ vertical: false });
this._lastMessageBox.add(body, props.childProps);
this.addActor(this._lastMessageBox);
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) {

View File

@ -140,27 +140,17 @@ 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)

View File

@ -513,10 +513,13 @@ const Dash = new Lang.Class({
this._syncLabel(item, appIcon);
}));
Main.overview.connect('hiding', Lang.bind(this, function() {
let id = Main.overview.connect('hiding', Lang.bind(this, function() {
this._labelShowing = false;
item.hideLabel();
}));
item.child.connect('destroy', function() {
Main.overview.disconnect(id);
});
if (appIcon) {
appIcon.connect('sync-tooltip', Lang.bind(this, function() {

View File

@ -3,6 +3,7 @@
const GLib = imports.gi.GLib;
const Gio = imports.gi.Gio;
const GnomeDesktop = imports.gi.GnomeDesktop;
const GObject = imports.gi.GObject;
const Lang = imports.lang;
const Mainloop = imports.mainloop;
const Cairo = imports.cairo;
@ -58,7 +59,7 @@ const DateMenuButton = new Lang.Class({
// Fill up the first column
vbox = new St.BoxLayout({vertical: true});
vbox = new St.BoxLayout({vertical: true, x_expand: true, y_expand: true });
hbox.add(vbox);
// Date
@ -95,11 +96,11 @@ const DateMenuButton = new Lang.Class({
this._openCalendarItem = new PopupMenu.PopupMenuItem(_("Open Calendar"));
this._openCalendarItem.connect('activate', Lang.bind(this, this._onOpenCalendarActivate));
vbox.add(this._openCalendarItem.actor, {y_align: St.Align.END, expand: true, y_fill: false});
vbox.add(this._openCalendarItem.actor, {y_align: St.Align.END, expand: false, y_fill: false});
this._openClocksItem = new PopupMenu.PopupMenuItem(_("Open Clocks"));
this._openClocksItem.connect('activate', Lang.bind(this, this._onOpenClocksActivate));
vbox.add(this._openClocksItem.actor, {y_align: St.Align.END, expand: true, y_fill: false});
vbox.add(this._openClocksItem.actor, {y_align: St.Align.END, expand: false, y_fill: false});
Shell.AppSystem.get_default().connect('installed-changed',
Lang.bind(this, this._appInstalledChanged));
@ -124,14 +125,19 @@ const DateMenuButton = new Lang.Class({
if (isOpen) {
let now = new Date();
this._calendar.setDate(now);
/* Translators: This is the date format to use when the calendar popup is
* shown - it is shown just below the time in the shell (e.g. "Tue 9:29 AM").
*/
let dateFormat = _("%A %B %e, %Y");
this._date.set_label(now.toLocaleFormat(dateFormat));
}
}));
// Done with hbox for calendar and event list
this._clock = new GnomeDesktop.WallClock();
this._clock.connect('notify::clock', Lang.bind(this, this._updateClockAndDate));
this._updateClockAndDate();
this._clock.bind_property('clock', this._clockDisplay, 'text', GObject.BindingFlags.SYNC_CREATE);
Main.sessionMode.connect('updated', Lang.bind(this, this._sessionUpdated));
this._sessionUpdated();
@ -141,7 +147,7 @@ const DateMenuButton = new Lang.Class({
let now = new Date();
return now.getYear() == date.getYear() &&
now.getMonth() == date.getMonth() &&
now.getDay() == date.getDay();
now.getDate() == date.getDate();
},
_appInstalledChanged: function() {
@ -196,25 +202,18 @@ const DateMenuButton = new Lang.Class({
this._dateAndTimeSeparator.actor.visible = Main.sessionMode.allowSettings;
},
_updateClockAndDate: function() {
this._clockDisplay.set_text(this._clock.clock);
/* Translators: This is the date format to use when the calendar popup is
* shown - it is shown just below the time in the shell (e.g. "Tue 9:29 AM").
*/
let dateFormat = _("%A %B %e, %Y");
let displayDate = new Date();
this._date.set_label(displayDate.toLocaleFormat(dateFormat));
},
_getCalendarApp: function() {
if (this._calendarApp !== undefined)
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;
},

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

@ -0,0 +1,84 @@
// -*- 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 Main = imports.ui.main;
const EDGE_THRESHOLD = 20;
const DRAG_DISTANCE = 80;
const EdgeDragAction = new Lang.Class({
Name: 'EdgeDragAction',
Extends: Clutter.GestureAction,
_init : function(side, allowedModes) {
this.parent();
this._side = side;
this._allowedModes = allowedModes;
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;
if (!(this._allowedModes & Main.keybindingMode))
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

@ -38,8 +38,6 @@ const UserWidget = imports.ui.userWidget;
let _endSessionDialog = null;
const TRIGGER_OFFLINE_UPDATE = '/usr/libexec/pk-trigger-offline-update';
const _ITEM_ICON_SIZE = 48;
const _DIALOG_ICON_SIZE = 48;
@ -134,11 +132,18 @@ const restartInstallDialogContent = {
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;
@ -155,6 +160,19 @@ 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"/> \
@ -245,9 +263,14 @@ 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._preparedUpdateFile = Gio.File.new_for_path('/var/lib/PackageKit/prepared-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',
@ -499,31 +522,29 @@ const EndSessionDialog = new Lang.Class({
},
_triggerOfflineUpdateReboot: function(callback) {
this._pkexecSpawn([TRIGGER_OFFLINE_UPDATE, 'reboot'], callback);
this._pkOfflineProxy.TriggerRemote('reboot',
function (result, error) {
if (error)
log(error.message);
callback();
});
},
_triggerOfflineUpdateShutdown: function(callback) {
this._pkexecSpawn([TRIGGER_OFFLINE_UPDATE, 'power-off'], callback);
this._pkOfflineProxy.TriggerRemote('power-off',
function (result, error) {
if (error)
log(error.message);
callback();
});
},
_triggerOfflineUpdateCancel: function(callback) {
this._pkexecSpawn([TRIGGER_OFFLINE_UPDATE, '--cancel'], callback);
},
_pkexecSpawn: function(argv, callback) {
let ret, pid;
try {
[ret, pid] = GLib.spawn_async(null, ['pkexec'].concat(argv), null,
GLib.SpawnFlags.DO_NOT_REAP_CHILD | GLib.SpawnFlags.SEARCH_PATH,
null);
} catch (e) {
log('Error spawning "pkexec %s": %s'.format(argv.join(' '), e.toString()));
callback();
return;
}
GLib.child_watch_add(GLib.PRIORITY_DEFAULT, pid, function(pid, status) {
GLib.spawn_close_pid(pid);
this._pkOfflineProxy.CancelRemote(function (result, error) {
if (error)
log(error.message);
callback();
});
@ -677,8 +698,9 @@ const EndSessionDialog = new Lang.Class({
this._totalSecondsToStayOpen = totalSecondsToStayOpen;
this._type = type;
if (this._type == 2 && this._updatesFile.query_exists(null))
this._type = 3;
if (this._type == DialogType.RESTART &&
this._pkOfflineProxy.TriggerAction == 'reboot')
this._type = DialogType.UPDATE_RESTART;
this._applications = [];
this._applicationList.destroy_all_children();
@ -705,19 +727,19 @@ const EndSessionDialog = new Lang.Class({
if (dialogContent.showOtherSessions)
this._loadSessions();
let preparedUpdate = this._preparedUpdateFile.query_exists(null);
let updateAlreadyTriggered = this._updatesFile.query_exists(null);
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 && preparedUpdate && updatesAllowed);
this._checkBox.actor.checked = (preparedUpdate && updateAlreadyTriggered);
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 || preparedUpdate && updateAlreadyTriggered && !updatesAllowed));
(this._checkBox.actor.visible || updatePrepared && updateAlreadyTriggered && !updatesAllowed));
this._updateButtons();

View File

@ -271,10 +271,17 @@ function onEnabledExtensionsChanged() {
}
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) {
if (ExtensionUtils.extensions[uuid])
reloadExtension(ExtensionUtils.extensions[uuid]);
enableExtension(uuid);
});
}
}

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];
}

View File

@ -10,12 +10,30 @@ 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_BASE_DELAY_FOR_ITEM = 1/4 * ANIMATION_MAX_DELAY_FOR_ITEM;
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',
@ -173,9 +191,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',
@ -338,15 +402,202 @@ 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 few items the animation can be slow, so use a smaller
// delay when there are less than 4 items
// (ANIMATION_BASE_DELAY_FOR_ITEM = 1/4 *
// ANIMATION_MAX_DELAY_FOR_ITEM)
let maxDelay = Math.min(ANIMATION_BASE_DELAY_FOR_ITEM * actors.length,
ANIMATION_MAX_DELAY_FOR_ITEM);
for (let index = 0; index < actors.length; index++) {
let actor = actors[index];
actor.reactive = false;
actor.set_scale(0, 0);
actor.set_pivot_point(0.5, 0.5);
let delay = index / actors.length * maxDelay;
let bounceUpTime = ANIMATION_TIME_IN / 4;
let isLastItem = index == actors.length - 1;
Tweener.addTween(actor,
{ 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(actor,
{ time: ANIMATION_TIME_IN - bounceUpTime,
transition: 'easeInOutQuad',
scale_x: 1,
scale_y: 1,
onComplete: Lang.bind(this, function() {
if (isLastItem)
this._animationDone();
actor.reactive = true;
})
});
})
});
}
},
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) {
@ -524,12 +775,13 @@ const IconGrid = new Lang.Class({
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) {
this._items[i].icon.setIconSize(newIconSize);
@ -545,6 +797,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;
@ -608,6 +861,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;

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,29 @@ 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.actor.connect('destroy', Lang.bind(this, this._onDestroy));
this._extended_keys = this._key.get_extended_keys();
this._extended_keyboard = null;
@ -76,20 +98,26 @@ const Key = new Lang.Class({
}
},
_makeKey: function () {
let label = GLib.markup_escape_text(this._key.label, -1);
_onDestroy: function() {
if (this._boxPointer) {
this._boxPointer.actor.destroy();
this._boxPointer = null;
}
},
_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 +140,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);
@ -162,10 +181,32 @@ const Keyboard = new Lang.Class({
this._timestamp = global.display.get_current_time_roundtrip();
this._keyboardSettings = new Gio.Settings({ schema_id: KEYBOARD_SCHEMA });
this._keyboardSettings.connect('changed', Lang.bind(this, this._settingsChanged));
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._settingsChanged));
this._settingsChanged();
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 +224,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 +256,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);
@ -555,7 +610,7 @@ const Keyboard = new Lang.Class({
_moveTemporarily: function () {
let currentWindow = global.screen.get_display().focus_window;
let rect = currentWindow.get_outer_rect();
let rect = currentWindow.get_frame_rect();
let newX = rect.x;
let newY = 3 * this.actor.height / 2;

View File

@ -11,6 +11,7 @@ const St = imports.gi.St;
const Background = imports.ui.background;
const BackgroundMenu = imports.ui.backgroundMenu;
const LoginManager = imports.misc.loginManager;
const DND = imports.ui.dnd;
const Main = imports.ui.main;
@ -20,7 +21,6 @@ const Tweener = imports.ui.tweener;
const STARTUP_ANIMATION_TIME = 0.5;
const KEYBOARD_ANIMATION_TIME = 0.15;
const BACKGROUND_FADE_ANIMATION_TIME = 1.0;
const DEFAULT_BACKGROUND_COLOR = Clutter.Color.from_pixel(0x2e3436ff);
// The message tray takes this much pressure
// in the pressure barrier at once to release it.
@ -160,10 +160,10 @@ const LayoutManager = new Lang.Class({
this._isPopupWindowVisible = false;
this._startingUp = true;
// 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.background_color = DEFAULT_BACKGROUND_COLOR;
// We don't want to paint the stage background color because either
// the SystemBackground we create or the MetaBackgroundActor inside
// global.window_group covers the entirety of the screen.
global.stage.no_clear_hint = true;
// Set up stage hierarchy to group all UI actors under one container.
this.uiGroup = new Shell.GenericContainer({ name: 'uiGroup' });
@ -230,6 +230,10 @@ const LayoutManager = new Lang.Class({
global.stage.remove_actor(global.top_window_group);
this.uiGroup.add_actor(global.top_window_group);
let feedbackGroup = Meta.get_feedback_group_for_screen(global.screen);
global.stage.remove_actor(feedbackGroup);
this.uiGroup.add_actor(feedbackGroup);
this._backgroundGroup = new Meta.BackgroundGroup();
global.window_group.add_child(this._backgroundGroup);
this._backgroundGroup.lower_bottom();
@ -245,6 +249,18 @@ const LayoutManager = new Lang.Class({
global.screen.connect('in-fullscreen-changed',
Lang.bind(this, this._updateFullscreen));
this._monitorsChanged();
// NVIDIA drivers don't preserve FBO contents across
// suspend/resume, see
// https://bugzilla.gnome.org/show_bug.cgi?id=739178
if (Shell.util_need_background_refresh()) {
LoginManager.getLoginManager().connect('prepare-for-sleep',
function(lm, suspending) {
if (suspending)
return;
Meta.Background.refresh_all();
});
}
},
// This is called by Main after everything else is constructed
@ -259,7 +275,6 @@ const LayoutManager = new Lang.Class({
this._inOverview = true;
this._updateVisibility();
this._updateRegions();
},
hideOverview: function() {
@ -267,7 +282,6 @@ const LayoutManager = new Lang.Class({
this._inOverview = false;
this._updateVisibility();
this._queueUpdateRegions();
},
_sessionUpdated: function() {
@ -361,7 +375,7 @@ const LayoutManager = new Lang.Class({
},
_addBackgroundMenu: function(bgManager) {
BackgroundMenu.addBackgroundMenu(bgManager.background.actor, this);
BackgroundMenu.addBackgroundMenu(bgManager.backgroundActor, this);
},
_createBackgroundManager: function(monitorIndex) {
@ -378,10 +392,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' });
@ -404,10 +418,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);
@ -417,6 +437,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);
@ -541,9 +563,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() {
@ -583,10 +603,6 @@ const LayoutManager = new Lang.Class({
//
// When starting a normal user session, we want to grow it out of the middle
// of the screen.
//
// Usually, we don't want to paint the stage background color because the
// MetaBackgroundActor inside global.window_group covers the entirety of the
// screen. So, we set no_clear_hint at the end of the animation.
_prepareStartupAnimation: function() {
// During the initial transition, add a simple actor to block all events,
@ -597,7 +613,9 @@ 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();
@ -636,7 +654,9 @@ const LayoutManager = new Lang.Class({
},
_startupAnimation: function() {
if (Main.sessionMode.isGreeter)
if (Meta.is_restart())
this._startupAnimationComplete();
else if (Main.sessionMode.isGreeter)
this._startupAnimationGreeter();
else
this._startupAnimationSession();
@ -663,10 +683,6 @@ const LayoutManager = new Lang.Class({
},
_startupAnimationComplete: function() {
// At this point, the UI group is covering everything, so
// we no longer need to clear the stage
global.stage.no_clear_hint = true;
this._coverPane.destroy();
this._coverPane = null;
@ -905,9 +921,6 @@ const LayoutManager = new Lang.Class({
},
_queueUpdateRegions: function() {
if (Main.sessionMode.isGreeter)
return;
if (this._startingUp)
return;
@ -941,13 +954,16 @@ const LayoutManager = new Lang.Class({
},
_updateRegions: function() {
let rects = [], struts = [], i;
if (this._updateRegionIdle) {
Meta.later_remove(this._updateRegionIdle);
delete this._updateRegionIdle;
}
// No need to update when we have a modal.
if (Main.modalCount > 0)
return GLib.SOURCE_REMOVE;
let rects = [], struts = [], i;
let isPopupMenuVisible = global.top_window_group.get_children().some(isPopupMetaWindow);
let wantsInputRegion = !isPopupMenuVisible;
@ -1033,7 +1049,13 @@ const LayoutManager = new Lang.Class({
}
return GLib.SOURCE_REMOVE;
}
},
modalEnded: function() {
// We don't update the stage input region while in a modal,
// so queue an update now.
this._queueUpdateRegions();
},
});
Signals.addSignalMethods(LayoutManager.prototype);

View File

@ -105,8 +105,8 @@ const Lightbox = new Lang.Class({
this._container = container;
this._children = container.get_children();
this._fadeFactor = params.fadeFactor;
this._radialEffect = params.radialEffect;
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 });

View File

@ -1198,12 +1198,7 @@ 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);
this._background = (new Background.SystemBackground()).actor;
mainGroup.add_actor(this._background);
// Clone the group that contains all of UI on the screen. This is the

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;
@ -39,8 +40,6 @@ const Magnifier = imports.ui.magnifier;
const XdndHandler = imports.ui.xdndHandler;
const Util = imports.misc.util;
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';
@ -167,6 +166,16 @@ function _initializeUI() {
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();
@ -193,24 +202,24 @@ function _initializeUI() {
}
layoutManager.connect('startup-complete', function() {
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);
}
});
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() {
@ -233,8 +242,7 @@ function _loadDefaultStylesheet() {
* Returns: A file path that contains the theme CSS,
* null if using the default
*/
function getThemeStylesheet()
{
function getThemeStylesheet() {
return _cssStylesheet;
}
@ -245,8 +253,7 @@ function getThemeStylesheet()
*
* Set the theme CSS file that the shell will load
*/
function setThemeStylesheet(cssStylesheet)
{
function setThemeStylesheet(cssStylesheet) {
_cssStylesheet = cssStylesheet;
}
@ -445,6 +452,7 @@ function popModal(actor, timestamp) {
if (modalCount > 0)
return;
layoutManager.modalEnded();
global.end_modal(timestamp);
Meta.enable_unredirect_for_screen(global.screen);
keybindingMode = Shell.KeyBindingMode.NORMAL;
@ -608,3 +616,28 @@ function queueDeferredWork(workId) {
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';
@ -922,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) {
@ -1157,6 +1159,7 @@ const SourceActor = new Lang.Class({
this.actor.connect('get-preferred-height', Lang.bind(this, this._getPreferredHeight));
this.actor.connect('allocate', Lang.bind(this, this._allocate));
this.actor.connect('destroy', Lang.bind(this, function() {
this._source.disconnect(this._iconUpdatedId);
this._actorDestroyed = true;
}));
this._actorDestroyed = false;
@ -1168,7 +1171,7 @@ const SourceActor = new Lang.Class({
this.actor.add_actor(this._iconBin);
this._source.connect('icon-updated', Lang.bind(this, this._updateIcon));
this._iconUpdatedId = this._source.connect('icon-updated', Lang.bind(this, this._updateIcon));
this._updateIcon();
},
@ -1226,8 +1229,12 @@ const SourceActorWithLabel = new Lang.Class({
this.actor.add_actor(this._counterBin);
this._source.connect('count-updated', Lang.bind(this, this._updateCount));
this._countUpdatedId = this._source.connect('count-updated', Lang.bind(this, this._updateCount));
this._updateCount();
this.actor.connect('destroy', function() {
this._source.disconnect(this._countUpdatedId);
});
},
_allocate: function(actor, box, flags) {
@ -1810,6 +1817,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,
@ -1933,6 +1947,15 @@ 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,
Shell.KeyBindingMode.NORMAL |
Shell.KeyBindingMode.OVERVIEW);
gesture.connect('activated', Lang.bind(this, this.toggle));
global.stage.add_action(gesture);
},
close: function() {
@ -2025,6 +2048,16 @@ 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._expireNotification();
@ -2401,8 +2434,22 @@ const MessageTray = new Lang.Class({
if (shouldShowNotification && nextNotification) {
let limited = this._busy || Main.layoutManager.bottomMonitor.inFullscreen;
let showNextNotification = (!limited || nextNotification.forFeedback || nextNotification.urgency == Urgency.CRITICAL);
if (showNextNotification)
this._showNotification();
if (showNextNotification) {
let len = this._notificationQueue.length;
if (len > 1) {
this._notificationQueue.length = 0;
let source = new SystemNotificationSource();
this.add(source);
let notification = new Notification(source, ngettext("%d new message", "%d new messages", len).format(len));
notification.setTransient(true);
notification.connect('clicked', Lang.bind(this, function() {
this.openTray();
}));
source.notify(notification);
} else {
this._showNotification();
}
}
}
} else if (this._notificationState == State.SHOWN) {
let expired = (this._userActiveWhileNotificationShown &&

View File

@ -43,6 +43,7 @@ const ModalDialog = new Lang.Class({
styleClass: null,
keybindingMode: Shell.KeyBindingMode.SYSTEM_MODAL,
shouldFadeIn: true,
shouldFadeOut: true,
destroyOnClose: true });
this.state = State.CLOSED;
@ -50,6 +51,7 @@ 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,
@ -307,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;
@ -315,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);
},
@ -692,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',
@ -705,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

@ -185,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);
}
},
@ -193,11 +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,
vignetteSharpness: 0.0,
vignette_sharpness: 0.0,
time: SHADE_ANIMATION_TIME,
transition: 'easeOutQuad'
});
@ -207,11 +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,
Tweener.addTween(backgrounds[i],
{ brightness: Lightbox.VIGNETTE_BRIGHTNESS,
vignetteSharpness: Lightbox.VIGNETTE_SHARPNESS,
vignette_sharpness: Lightbox.VIGNETTE_SHARPNESS,
time: SHADE_ANIMATION_TIME,
transition: 'easeOutQuad'
});
@ -242,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
@ -425,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;
@ -441,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();
@ -504,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
@ -583,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
@ -614,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() {
@ -652,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);
@ -677,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);
@ -64,7 +64,8 @@ const SlideLayout = new Lang.Class({
// flags only determine what to do if the allocated box is bigger
// than the actor's box.
let realDirection = getRtlSlideDirection(this._direction, child);
let alignX = (realDirection == SlideDirection.LEFT) ? (availWidth - natWidth) : 0;
let alignX = (realDirection == SlideDirection.LEFT) ? (availWidth - natWidth)
: (availWidth - natWidth * this._slideX);
let actorBox = new Clutter.ActorBox();
actorBox.x1 = box.x1 + alignX + this._translationX;
@ -118,7 +119,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 +162,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 +178,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 +194,7 @@ const SlidingControl = new Lang.Class({
_onDragBegin: function() {
this._inDrag = true;
this.layout.translationX = 0;
this._updateTranslation();
this._updateSlide();
},
@ -223,7 +219,6 @@ const SlidingControl = new Lang.Class({
slideIn: function() {
this._visible = true;
this._updateTranslation();
// we will update slideX and the translation from pageEmpty
},

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;
@ -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() {
@ -601,16 +599,21 @@ const ActivitiesButton = new Lang.Class({
},
_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;
},
@ -1016,7 +1019,7 @@ const Panel = new Lang.Class({
if (!dragWindow)
return Clutter.EVENT_PROPAGATE;
let rect = dragWindow.get_outer_rect();
let rect = dragWindow.get_frame_rect();
let [stageX, stageY] = event.get_coords();
let allowDrag = dragWindow.maximized_vertically &&

View File

@ -100,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)
@ -131,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

@ -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())
@ -106,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)
@ -132,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();
@ -378,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);
},
@ -736,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;
},
@ -746,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);
},
@ -786,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();
}
});
@ -879,12 +918,14 @@ 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._arrowRotation = this._arrow.rotation_angle_z;
Tweener.addTween(this.actor,
{ _arrowRotation: this.actor._arrowRotation + 90,
{ _arrowRotation: targetAngle,
height: naturalHeight,
time: 0.25,
onUpdateScope: this,
@ -897,7 +938,7 @@ const PopupSubMenu = new Lang.Class({
}
});
} else {
this._arrow.rotation_angle_z = this.actor._arrowRotation + 90;
this._arrow.rotation_angle_z = targetAngle;
}
},
@ -917,7 +958,7 @@ const PopupSubMenu = new Lang.Class({
if (animate) {
this.actor._arrowRotation = this._arrow.rotation_angle_z;
Tweener.addTween(this.actor,
{ _arrowRotation: this.actor._arrowRotation - 90,
{ _arrowRotation: 0,
height: 0,
time: 0.25,
onUpdateScope: this,
@ -931,7 +972,7 @@ const PopupSubMenu = new Lang.Class({
},
});
} else {
this._arrow.rotation_angle_z = this.actor._arrowRotation - 90;
this._arrow.rotation_angle_z = 0;
this.actor.hide();
}
},
@ -1009,8 +1050,6 @@ const PopupSubMenuMenuItem = new Lang.Class({
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) {
@ -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

@ -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,8 @@ const NotificationsBox = new Lang.Class({
});
this._updateVisibility();
this.emit('wake-up-screen');
if (obj.sourceBox.visible)
this.emit('wake-up-screen');
}
},
@ -444,14 +445,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',
@ -689,10 +688,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;
@ -902,17 +901,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;
@ -927,6 +920,11 @@ const ScreenShield = new Lang.Class({
this._lockScreenState = MessageTray.State.HIDDEN;
this._lockScreenGroup.hide();
if (this._dialog) {
this._dialog.actor.grab_key_focus();
this._dialog.actor.navigate_focus(null, Gtk.DirectionType.TAB_FORWARD, false);
}
},
_hideLockScreen: function(animate, velocity) {

View File

@ -43,6 +43,8 @@ const ScreencastService = new Lang.Class({
this._recorders = new Map();
this._lockdownSettings = new Gio.Settings({ schema_id: 'org.gnome.desktop.lockdown' });
Main.sessionMode.connect('updated', Lang.bind(this, this._sessionUpdated));
},
@ -68,8 +70,8 @@ const ScreencastService = new Lang.Class({
if (Main.sessionMode.allowScreencast)
return;
this._recorders.clear();
this.emit('updated');
for (let sender of this._recorders.keys())
this._stopRecordingForSender(sender);
},
_onNameVanished: function(connection, name) {
@ -103,7 +105,8 @@ const ScreencastService = new Lang.Class({
ScreencastAsync: function(params, invocation) {
let returnValue = [false, ''];
if (!Main.sessionMode.allowScreencast) {
if (!Main.sessionMode.allowScreencast ||
this._lockdownSettings.get_boolean('disable-save-to-disk')) {
invocation.return_value(GLib.Variant.new('(bs)', returnValue));
return;
}
@ -117,6 +120,8 @@ const ScreencastService = new Lang.Class({
this._applyOptionalParameters(recorder, options);
let [success, fileName] = recorder.record();
returnValue = [success, fileName ? fileName : ''];
if (!success)
this._stopRecordingForSender(sender);
}
invocation.return_value(GLib.Variant.new('(bs)', returnValue));
@ -124,7 +129,8 @@ const ScreencastService = new Lang.Class({
ScreencastAreaAsync: function(params, invocation) {
let returnValue = [false, ''];
if (!Main.sessionMode.allowScreencast) {
if (!Main.sessionMode.allowScreencast ||
this._lockdownSettings.get_boolean('disable-save-to-disk')) {
invocation.return_value(GLib.Variant.new('(bs)', returnValue));
return;
}
@ -150,6 +156,8 @@ const ScreencastService = new Lang.Class({
this._applyOptionalParameters(recorder, options);
let [success, fileName] = recorder.record();
returnValue = [success, fileName ? fileName : ''];
if (!success)
this._stopRecordingForSender(sender);
}
invocation.return_value(GLib.Variant.new('(bs)', returnValue));

View File

@ -65,9 +65,44 @@ const ScreenshotService = new Lang.Class({
this._dbusImpl = Gio.DBusExportedObject.wrapJSObject(ScreenshotIface, this);
this._dbusImpl.export(Gio.DBus.session, '/org/gnome/Shell/Screenshot');
this._screenShooter = new Map();
this._lockdownSettings = new Gio.Settings({ schema_id: 'org.gnome.desktop.lockdown' });
Gio.DBus.session.own_name('org.gnome.Shell.Screenshot', Gio.BusNameOwnerFlags.REPLACE, null, null);
},
_createScreenshot: function(invocation) {
let sender = invocation.get_sender();
if (this._screenShooter.has(sender) ||
this._lockdownSettings.get_boolean('disable-save-to-disk')) {
invocation.return_value(GLib.Variant.new('(bs)', [false, '']));
return null;
}
let shooter = new Shell.Screenshot();
shooter._watchNameId =
Gio.bus_watch_name(Gio.BusType.SESSION, sender, 0, null,
Lang.bind(this, this._onNameVanished));
this._screenShooter.set(sender, shooter);
return shooter;
},
_onNameVanished: function(connection, name) {
this._removeShooterForSender(name);
},
_removeShooterForSender: function(sender) {
let shooter = this._screenShooter.get(sender);
if (!shooter)
return;
Gio.bus_unwatch_name(shooter._watchNameId);
this._screenShooter.delete(sender);
},
_checkArea: function(x, y, width, height) {
return x >= 0 && y >= 0 &&
width > 0 && height > 0 &&
@ -76,9 +111,15 @@ const ScreenshotService = new Lang.Class({
},
_onScreenshotComplete: function(obj, result, area, filenameUsed, flash, invocation) {
if (flash && result) {
let flashspot = new Flashspot(area);
flashspot.fire();
if (result) {
if (flash) {
let flashspot = new Flashspot(area);
flashspot.fire(Lang.bind(this, function() {
this._removeShooterForSender(invocation.get_sender());
}));
}
else
this._removeShooterForSender(invocation.get_sender());
}
let retval = GLib.Variant.new('(bs)', [result, filenameUsed]);
@ -112,7 +153,9 @@ const ScreenshotService = new Lang.Class({
"Invalid params");
return;
}
let screenshot = new Shell.Screenshot();
let screenshot = this._createScreenshot(invocation);
if (!screenshot)
return;
screenshot.screenshot_area (x, y, width, height, filename,
Lang.bind(this, this._onScreenshotComplete,
flash, invocation));
@ -120,7 +163,9 @@ const ScreenshotService = new Lang.Class({
ScreenshotWindowAsync : function (params, invocation) {
let [include_frame, include_cursor, flash, filename] = params;
let screenshot = new Shell.Screenshot();
let screenshot = this._createScreenshot(invocation);
if (!screenshot)
return;
screenshot.screenshot_window (include_frame, include_cursor, filename,
Lang.bind(this, this._onScreenshotComplete,
flash, invocation));
@ -128,7 +173,9 @@ const ScreenshotService = new Lang.Class({
ScreenshotAsync : function (params, invocation) {
let [include_cursor, flash, filename] = params;
let screenshot = new Shell.Screenshot();
let screenshot = this._createScreenshot(invocation);
if (!screenshot)
return;
screenshot.screenshot(include_cursor, filename,
Lang.bind(this, this._onScreenshotComplete,
flash, invocation));
@ -302,7 +349,7 @@ const Flashspot = new Lang.Class({
this.actor.set_position(area.x, area.y);
},
fire: function() {
fire: function(doneCallback) {
this.actor.show();
this.actor.opacity = 255;
Tweener.addTween(this.actor,
@ -310,6 +357,8 @@ const Flashspot = new Lang.Class({
time: FLASHSPOT_ANIMATION_OUT_TIME,
transition: 'easeOutQuad',
onComplete: Lang.bind(this, function() {
if (doneCallback)
doneCallback();
this.destroy();
})
});

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
@ -78,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" /> \
@ -97,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.
@ -110,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);
}
/**
@ -132,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);
}
/**
@ -155,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);
}
/**
@ -208,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)
@ -306,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 ('------------------------------------------------------------');
}
@ -360,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,107 +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_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._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);
if (provider.display)
provider.display.destroy();
},
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,
@ -163,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);
@ -230,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;
}
});
@ -314,7 +160,11 @@ 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() {
@ -384,9 +234,10 @@ const SearchResultsBase = new Lang.Class({
let hasMoreResults = results.length < providerResults.length;
this._ensureResultActors(results, Lang.bind(this, function(successful) {
this._clearResultDisplay();
if (!successful)
if (!successful) {
this._clearResultDisplay();
return;
}
// To avoid CSS transitions causing flickering when
// the first search result stays the same, we hide the
@ -416,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();
}));
@ -433,7 +285,7 @@ const ListSearchResults = new Lang.Class({
},
_setMoreIconVisible: function(visible) {
this.providerIcon.moreIcon.visible = true;
this.providerIcon.moreIcon.visible = visible;
},
_getMaxDisplayedResults: function() {
@ -445,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) {
@ -465,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 });
@ -477,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 () {
@ -494,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) {
@ -546,16 +397,136 @@ 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);
},
_clearSearchTimeout: function() {
if (this._searchTimeoutId > 0) {
GLib.source_remove(this._searchTimeoutId);
this._searchTimeoutId = 0;
}
},
_reset: function() {
this._terms = [];
this._results = {};
this._clearDisplay();
this._clearSearchTimeout();
this._defaultResult = null;
this._startingSearch = false;
this._updateSearchProgress();
},
_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();
this._clearSearchTimeout();
},
_onSearchTimeout: function() {
this._searchTimeoutId = 0;
this._doSearch();
return GLib.SOURCE_REMOVE;
},
setTerms: function(terms) {
// Check for the case of making a duplicate previous search before
// setting state of the current search or cancelling the search.
// This will prevent incorrect state being as a result of a duplicate
// search while the previous search is still active.
let searchString = terms.join(' ');
let previousSearchString = this._terms.join(' ');
if (searchString == previousSearchString)
return;
this._startingSearch = true;
this._cancellable.cancel();
this._cancellable.reset();
if (terms.length == 0) {
this._reset();
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) {
@ -577,44 +548,24 @@ 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));
providerDisplay.actor.hide();
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;
@ -630,54 +581,64 @@ const SearchResults = new Lang.Class({
}
if (newDefaultResult != this._defaultResult) {
if (this._defaultResult)
this._defaultResult.setSelected(false);
if (newDefaultResult) {
newDefaultResult.setSelected(this._highlightDefault);
if (this._highlightDefault)
Util.ensureActorVisibleInScrollView(this._scrollView, newDefaultResult.actor);
}
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);
if (highlight)
Util.ensureActorVisibleInScrollView(this._scrollView, this._defaultResult.actor);
}
this._setSelected(this._defaultResult, highlight);
},
navigateFocus: function(direction) {
@ -692,6 +653,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');
}
}
});
@ -725,5 +698,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

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

@ -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;
@ -161,7 +197,7 @@ const Slider = new Lang.Class({
let [dx, dy] = event.get_scroll_delta();
// Even though the slider is horizontal, use dy to match
// the UP/DOWN above.
delta = -dy / 10;
delta = -dy * SLIDER_SCROLL_STEP;
}
this._value = Math.min(Math.max(0, this._value + delta), 1);

File diff suppressed because it is too large Load Diff

View File

@ -9,8 +9,18 @@ const PanelMenu = imports.ui.panelMenu;
const PopupMenu = imports.ui.popupMenu;
const Shell = imports.gi.Shell;
const LOCATION_SCHEMA = 'org.gnome.shell.location';
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"> \
@ -44,6 +54,8 @@ const Indicator = new Lang.Class({
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));
@ -58,6 +70,7 @@ const Indicator = new Lang.Class({
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);
@ -93,10 +106,12 @@ const Indicator = new Lang.Class({
_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();
},
@ -123,7 +138,6 @@ const Indicator = new Lang.Class({
this._propertiesChangedId = this._proxy.connect('g-properties-changed',
Lang.bind(this, this._onGeocluePropsChanged));
this._availableAccuracyLevel = this._proxy.AvailableAccuracyLevel;
this._syncIndicator();
this._proxy.AddAgentRemote('gnome-shell', Lang.bind(this, this._onAgentRegistered));
@ -148,10 +162,8 @@ const Indicator = new Lang.Class({
},
_onOnOffAction: function() {
if (this._getMaxAccuracyLevel() == 0)
this._settings.set_enum(MAX_ACCURACY_LEVEL, this._availableAccuracyLevel);
else
this._settings.set_enum(MAX_ACCURACY_LEVEL, 0);
let enabled = this._settings.get_boolean(ENABLED);
this._settings.set_boolean(ENABLED, !enabled);
},
_onSessionUpdated: function() {
@ -160,12 +172,12 @@ const Indicator = new Lang.Class({
},
_updateMenuLabels: function() {
if (this._getMaxAccuracyLevel() == 0) {
this._item.status.text = _("Disabled");
this._onOffAction.label.text = _("Enable");
} else {
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");
}
},
@ -179,7 +191,14 @@ const Indicator = new Lang.Class({
},
_getMaxAccuracyLevel: function() {
return this._settings.get_enum(MAX_ACCURACY_LEVEL);
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() {
@ -191,12 +210,6 @@ const Indicator = new Lang.Class({
let unpacked = properties.deep_unpack();
if ("InUse" in unpacked)
this._syncIndicator();
if ("AvailableAccuracyLevel" in unpacked) {
this._availableAccuracyLevel = this._proxy.AvailableAccuracyLevel;
if (this._getMaxAccuracyLevel() != 0)
this._settings.set_enum(MAX_ACCURACY_LEVEL, this._availableAccuracyLevel);
}
}
});

View File

@ -1866,7 +1866,7 @@ const NMApplet = new Lang.Class({
_connectionRemoved: function(connection) {
let pos = this._connections.indexOf(connection);
if (pos != -1)
this._connections.splice(connection, 1);
this._connections.splice(pos, 1);
let section = connection._section;

View File

@ -151,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();
@ -285,7 +285,7 @@ const Indicator = new Lang.Class({
let disabled = Main.sessionMode.isLocked ||
(Main.sessionMode.isGreeter &&
this._loginScreenSettings.get_boolean(DISABLE_RESTART_KEY));
this._suspendAction.visible = this._haveShutdown && !disabled;
this._suspendAction.visible = this._haveSuspend && !disabled;
this._updateActionsVisibility();
},

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
@ -178,19 +174,17 @@ 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, backwards, action) != Clutter.EVENT_PROPAGATE)
if (this._keyPressHandler(keysym, action) != Clutter.EVENT_PROPAGATE)
return Clutter.EVENT_STOP;
if (keysym == Clutter.Escape)

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

@ -6,6 +6,7 @@ const Clutter = imports.gi.Clutter;
const AccountsService = imports.gi.AccountsService;
const GLib = imports.gi.GLib;
const Gio = imports.gi.Gio;
const GObject = imports.gi.GObject;
const Lang = imports.lang;
const St = imports.gi.St;
@ -28,11 +29,12 @@ const Avatar = new Lang.Class({
styleClass: 'framed-user-icon' });
this._iconSize = params.iconSize;
let scaleFactor = St.ThemeContext.get_for_stage(global.stage).scale_factor;
this.actor = new St.Bin({ style_class: params.styleClass,
track_hover: params.reactive,
reactive: params.reactive,
width: this._iconSize,
height: this._iconSize });
width: this._iconSize * scaleFactor,
height: this._iconSize * scaleFactor });
},
setSensitive: function(sensitive) {
@ -116,6 +118,7 @@ const UserWidgetLabel = new Lang.Class({
this._currentLabel = this._realNameLabel;
else
this._currentLabel = this._userNameLabel;
this.label_actor = this._currentLabel;
let childBox = new Clutter.ActorBox();
childBox.x1 = 0;
@ -157,6 +160,9 @@ const UserWidget = new Lang.Class({
this._label = new UserWidgetLabel(user);
this.actor.add_child(this._label);
this._label.bind_property('label-actor', this.actor, 'label-actor',
GObject.BindingFlags.SYNC_CREATE);
this._userLoadedId = this._user.connect('notify::is-loaded', Lang.bind(this, this._updateUser));
this._userChangedId = this._user.connect('changed', Lang.bind(this, this._updateUser));
this._updateUser();

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,81 @@ 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 Main.keybindingMode == Shell.KeyBindingMode.NORMAL &&
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 +144,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-symbolic-rtl' });
else
this._clearIcon = new St.Icon({ style_class: 'search-entry-icon',
icon_name: 'edit-clear-symbolic-ltr' });
this._clearIcon = new St.Icon({ style_class: 'search-entry-icon',
icon_name: 'edit-clear-symbolic' });
this._iconClickedId = 0;
this._capturedEventId = 0;
@ -118,18 +177,28 @@ 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;
this._workspacesPage.hide();
}
}));
Main.wm.addKeybinding('toggle-application-view',
new Gio.Settings({ schema_id: SHELL_KEYBINDINGS_SCHEMA }),
@ -145,31 +214,60 @@ const ViewSelector = new Lang.Class({
Shell.KeyBindingMode.OVERVIEW,
Lang.bind(Main.overview, Main.overview.toggle));
let side;
if (Clutter.get_default_text_direction() == Clutter.TextDirection.RTL)
side = St.Side.RIGHT;
else
side = St.Side.LEFT;
let gesture = new EdgeDragAction.EdgeDragAction(side,
Shell.KeyBindingMode.NORMAL);
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();
@ -206,21 +304,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.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;
@ -228,18 +366,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) {
@ -248,21 +378,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, ...)
@ -358,7 +477,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
@ -369,36 +491,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));
GLib.Source.set_name_by_id(this._searchTimeoutId, '[gnome-shell] 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();
}
@ -436,12 +545,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;
}
@ -464,17 +567,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,6 +9,7 @@ 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;
@ -18,6 +19,13 @@ 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;
@ -405,7 +413,7 @@ const TilePreview = new Lang.Class({
y: monitor.y,
width: monitor.width,
height: monitor.height });
let [, rect] = window.get_outer_rect().intersect(monitorRect);
let [, rect] = window.get_frame_rect().intersect(monitorRect);
this.actor.set_size(rect.width, rect.height);
this.actor.set_position(rect.x, rect.y);
this.actor.opacity = 0;
@ -456,6 +464,122 @@ const TilePreview = new Lang.Class({
}
});
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) {
let allowedModes = Shell.KeyBindingMode.NORMAL | Shell.KeyBindingMode.OVERVIEW;
return this.get_n_current_points() == this.get_n_touch_points() &&
(allowedModes & Main.keybindingMode);
},
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.keybindingMode != Shell.KeyBindingMode.NORMAL) {
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',
@ -683,6 +807,53 @@ const WindowManager = new Lang.Class({
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) {
@ -717,12 +888,12 @@ const WindowManager = new Lang.Class({
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) {
@ -735,7 +906,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;
}
@ -747,7 +921,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,
@ -779,8 +953,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],
@ -796,7 +970,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);
}
@ -894,7 +1068,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;
}
@ -902,15 +1079,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.set_pivot_point(0.5, 0.5);
}
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],
@ -918,15 +1103,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,
@ -935,6 +1125,10 @@ const WindowManager = new Lang.Class({
onOverwriteScope: this,
onOverwriteParams: [shellwm, actor]
});
break;
default:
shellwm.completed_map(actor);
return;
}
},
@ -942,7 +1136,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);
}
},
@ -965,30 +1163,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);
switch (actor._windowType) {
case Meta.WindowType.NORMAL:
actor.set_pivot_point(0.5, 0.5);
actor.show();
actor._parentDestroyId = parent.connect('unmanaged', Lang.bind(this, function () {
Tweener.removeTweens(actor);
this._destroyWindowDone(shellwm, actor);
}));
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],
@ -996,9 +1189,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) {
@ -1171,9 +1392,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();
},
@ -1184,16 +1403,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) {

View File

@ -75,7 +75,7 @@ const WindowMenu = new Lang.Class({
}));
if (window.is_above())
item.setOrnament(PopupMenu.Ornament.DOT);
if (window.get_maximized() ||
if (window.get_maximized() == Meta.MaximizeFlags.BOTH ||
type == Meta.WindowType.DOCK ||
type == Meta.WindowType.DESKTOP ||
type == Meta.WindowType.SPLASHSCREEN)

View File

@ -34,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;
}
@ -87,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;
@ -96,8 +98,8 @@ const WindowCloneLayout = new Lang.Class({
child.allocate(this._makeBoxForWindow(realWindow.meta_window),
flags);
}, this);
},
}));
}
});
const WindowClone = new Lang.Class({
@ -154,7 +156,6 @@ const WindowClone = new Lang.Class({
this.actor.add_action(clickAction);
this.actor.connect('destroy', Lang.bind(this, this._onDestroy));
this.actor.connect('key-press-event', Lang.bind(this, this._onKeyPress));
this.actor.connect('enter-event', Lang.bind(this, this._onEnter));
this._draggable = DND.makeDraggable(this.actor,
{ restoreOnSuccess: true,
@ -252,7 +253,7 @@ const WindowClone = new Lang.Class({
},
_computeBoundingBox: function() {
let rect = this.metaWindow.get_outer_rect();
let rect = this.metaWindow.get_frame_rect();
this.actor.get_children().forEach(function (child) {
let realWindow;
@ -262,7 +263,7 @@ const WindowClone = new Lang.Class({
realWindow = child.source;
let metaWindow = realWindow.meta_window;
rect = rect.union(metaWindow.get_outer_rect());
rect = rect.union(metaWindow.get_frame_rect());
}, this);
// Convert from a MetaRectangle to a native JS object
@ -351,10 +352,6 @@ const WindowClone = new Lang.Class({
return false;
},
_onEnter: function() {
this.actor.grab_key_focus();
},
_onClicked: function(action, actor) {
this._activate();
},
@ -517,6 +514,7 @@ const WindowOverlay = new Lang.Class({
Tweener.removeTweens(button);
Tweener.removeTweens(border);
Tweener.removeTweens(title);
let [cloneX, cloneY, cloneWidth, cloneHeight] = this._windowClone.slot;
@ -1206,14 +1204,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);
},
@ -1258,6 +1260,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;
@ -1320,7 +1329,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);
@ -1349,7 +1358,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,
@ -1407,10 +1416,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);
@ -1556,14 +1561,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;
@ -1584,35 +1716,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'
});
}
},
@ -1651,6 +1785,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;
@ -1674,16 +1813,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

@ -161,14 +161,14 @@ const WindowClone = new Lang.Class({
_updateDialogPosition: function(realDialog, cloneDialog) {
let metaDialog = realDialog.meta_window;
let dialogRect = metaDialog.get_outer_rect();
let rect = this.metaWindow.get_outer_rect();
let dialogRect = metaDialog.get_frame_rect();
let rect = this.metaWindow.get_frame_rect();
cloneDialog.set_position(dialogRect.x - rect.x, dialogRect.y - rect.y);
},
_onPositionChanged: function() {
let rect = this.metaWindow.get_outer_rect();
let rect = this.metaWindow.get_frame_rect();
this.actor.set_position(this.realWindow.x, this.realWindow.y);
},
@ -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);
@ -522,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);
@ -878,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();
@ -904,6 +897,7 @@ 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() {
@ -934,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);
@ -1121,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');
@ -1135,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();
@ -1154,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() {
@ -122,9 +127,9 @@ 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);
},
_syncFullGeometry: function() {
@ -142,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) {
@ -353,8 +366,8 @@ 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);
},
_syncFullGeometry: function() {
@ -365,12 +378,18 @@ const ExtraWorkspaceView = new Lang.Class({
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) {
@ -462,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',
@ -474,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() {
@ -507,6 +538,7 @@ const WorkspacesDisplay = new Lang.Class({
for (let i = 0; i < this._workspacesViews.length; i++)
this._workspacesViews[i].destroy();
this._primaryIndex = Main.layoutManager.primaryIndex;
this._workspacesViews = [];
let monitors = Main.layoutManager.monitors;
for (let i = 0; i < monitors.length; i++) {

View File

@ -7,6 +7,7 @@ be
bg
bn
bn_IN
bs
ca
ca@valencia
cs
@ -45,6 +46,7 @@ mk
mr
ms
nb
ne
nl
nn
or

View File

@ -1,2 +1,4 @@
data/org.gnome.shell.evolution.calendar.gschema.xml.in
src/calendar-server/evolution-calendar.desktop.in
# Meh, autofools :-(
sub/src/calendar-server/evolution-calendar.desktop.in

1768
po/af.po

File diff suppressed because it is too large Load Diff

1047
po/ar.po

File diff suppressed because it is too large Load Diff

1105
po/as.po

File diff suppressed because it is too large Load Diff

1761
po/bg.po

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

1804
po/bs.po Normal file

File diff suppressed because it is too large Load Diff

926
po/ca.po

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

652
po/cs.po

File diff suppressed because it is too large Load Diff

1220
po/da.po

File diff suppressed because it is too large Load Diff

845
po/de.po

File diff suppressed because it is too large Load Diff

959
po/el.po

File diff suppressed because it is too large Load Diff

525
po/es.po

File diff suppressed because it is too large Load Diff

796
po/eu.po

File diff suppressed because it is too large Load Diff

1265
po/fa.po

File diff suppressed because it is too large Load Diff

921
po/fi.po

File diff suppressed because it is too large Load Diff

915
po/fr.po

File diff suppressed because it is too large Load Diff

882
po/fur.po

File diff suppressed because it is too large Load Diff

846
po/gl.po

File diff suppressed because it is too large Load Diff

2213
po/gu.po

File diff suppressed because it is too large Load Diff

715
po/he.po

File diff suppressed because it is too large Load Diff

2257
po/hi.po

File diff suppressed because it is too large Load Diff

589
po/hu.po

File diff suppressed because it is too large Load Diff

595
po/id.po

File diff suppressed because it is too large Load Diff

778
po/it.po

File diff suppressed because it is too large Load Diff

834
po/ja.po

File diff suppressed because it is too large Load Diff

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