Compare commits

...

209 Commits

Author SHA1 Message Date
1afb04d1e4 overview: new transition 2014-01-31 17:57:57 -05:00
51e63233ce viewSelector: Move to a sync() model for deciding which page to show
https://bugzilla.gnome.org/show_bug.cgi?id=722196
2014-01-31 17:57:57 -05:00
a7d7f94892 screenShield: Don't hide windows until we've fully locked the shield
Revert the commit that ties hasWindows to the session mode, as we
need to do the "transition" manually. Instead, show/hide the
sessionGroup ourselves.

For optimization purposes, we also need to hide the window groups
when in the overview. Ideally, these would be culled out by Clutter,
but they are not from experimentation.
2014-01-31 17:57:57 -05:00
427f516d45 layout: Replace SystemBackground with CSS on the systemGroup
This merges the implementation of the noise texture on the lockScreenDialog
and the startup animation -- they now just use the systemGroup.
2014-01-31 17:57:57 -05:00
cbb88ffdbb layout: Add sessionGroup / systemGroup to better-define layers
In order to build a better transition animation from the lock screen, we
need to split the world into layers, as per this reference:

https://raw.github.com/gnome-design-team/gnome-mockups/master/system-lock-login-boot/system-layers2.png

Everything that pertains to the user's session is in the "session group",
which includes the window group, overview, message tray (for now),
keyboard, OSDs, menus, etc.

For implementation sake, we did not match this mockup exactly. The new layers
look like this, from top to bottom:

 * Stage
   * Magnifier (clones the uiGroup)
   * uiGroup
     * overlayGroup
       * menuGroup
     * panelGroup
     * screenShieldGroup
     * sessionGroup
       * top_window_group
       * other boxes (trayBox, keyboardBox, etc.)
       * other groups (osdGroup, switcherPopupGroup, etc.)
       * overviewGroup
       * window_group
     * systemGroup

The "session startup" animation now only zooms in the sessionGroup.

The panel is now outside the session, as it needs to sit above the screen
shield. This also means that it's not zoomed in as part of startup. I think
this is OK.

This also means that the lightboxes that the screen shield uses to fade out
the screen have to go in a new group, above the panel. This is known as the
overlayGroup, which has no relation to the old mutter group of the same name.

We also change the screen shield to put the lockDialogGroup in the system
group, and put the lockScreenGroup in the screenShieldGroup, which means
that the layer stacking is correct. Note that we don't hide the session
group in the lock screen yet, which is something I want to do.

Since not a lot of items need to be in the uiGroup anymore, we've removed
the Main.uiGroup fallback; others should use sessionGroup instead, when
appropriate.
2014-01-31 17:57:57 -05:00
71670bad3b layout: Add different groups in the LayoutManager for discrete UI components
This helps take cruft out of the uiGroup, and ensures that components remain
stacked properly on top of each other. In the future, we'll use this group
to ensure that grabs are ordered properly, as well.
2014-01-31 17:57:57 -05:00
a2e4153fa0 background: Fix cancellable issues
If we have the following sequence:

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

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

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

Additionally, clean up the large nested loops by splitting out duplicated
code and other stuff.

https://bugzilla.gnome.org/show_bug.cgi?id=722149
2014-01-31 17:57:57 -05:00
2fba8e29e0 shell-app: Rename internal function as suggested in review
Ooops, this was meant to be squashed with commit d44f40d105.
2014-01-31 13:59:30 +01:00
de1bb4e203 window-tracker: Remove is_window_interesting()
It is now unused, so kill it.

https://bugzilla.gnome.org/show_bug.cgi?id=723308
2014-01-31 13:49:07 +01:00
b4680a5c25 Use meta_window_is_skip_taskbar() directly
Rather than going through ShellWindowTracker, we can just clean up
the code to use the underlying MetaWindow property directly.

https://bugzilla.gnome.org/show_bug.cgi?id=723308
2014-01-31 13:49:07 +01:00
d44f40d105 shell-app: Track changes to MetaWindow:skip-taskbar
So far we have assumed that whether or not a window is interesting
is static. In general this is the case, but as it is legal for the
underlying properties to change at any time, there are of course
offenders that actually do this (flash I'm looking at ya).
While we used the property to determine whether a window should be
tracked or not, the worst case was showing windows that should be
hidden or missing windows that should be shown.
However as we nowadays base an app's running state on the number of
interesting windows, we need to be more careful in order to avoid
ending up with running apps with no windows.

https://bugzilla.gnome.org/show_bug.cgi?id=723308
2014-01-31 13:49:07 +01:00
8d5771e302 window-tracker: Use MetaWindow:skip-taskbar
The code from shell_window_tracker_is_window_interesting() is equivalent
of MetaWindow's skip-taskbar property, so use it to avoid code duplication.

https://bugzilla.gnome.org/show_bug.cgi?id=723308
2014-01-31 13:49:06 +01:00
fb31f99aed Updated Aragonese translation 2014-01-31 12:45:29 +01:00
b97f3a9ecf overview: Fix DESKTOP clone position
The DESKTOP window might not be located at (0,0), in particular
on multi-monitor setups. While we already consider this by setting
the clone's position, we then stuff the clone into a container which
ignores it - meh ...

https://bugzilla.gnome.org/show_bug.cgi?id=723306
2014-01-31 00:00:07 +01:00
ac22172a6e window-tracker: Fix memory leak
shell_window_tracker_get_window_app() returns a new reference
which we need to drop once we're done.

https://bugzilla.gnome.org/show_bug.cgi?id=722927
2014-01-30 23:55:13 +01:00
57367380f5 Updated Hebrew translation 2014-01-29 22:39:47 +02:00
7101cc3170 osdWindow: Don't tween to undefined
Check that we got a valid level before setting the level bar to it, to
prevent a Tweener warning.
2014-01-29 15:08:03 -05:00
7051411be7 network: Add a Wired device
This isn't quite like the design, as we don't show icons for other
devices when wired is in an error state.

https://bugzilla.gnome.org/show_bug.cgi?id=708966
2014-01-29 15:02:52 -05:00
bb8397b9b1 appDisplay: Support the 'excluded-apps' key for app folders
https://bugzilla.gnome.org/show_bug.cgi?id=723179
2014-01-29 14:02:27 -05:00
bb8fa61cb4 appDisplay: Support the 'categories' key for app folders
https://bugzilla.gnome.org/show_bug.cgi?id=723179
2014-01-29 14:02:27 -05:00
10147ee331 appDisplay: Make refiltering folders more efficient
Rather than queueing a full redisplay, simply filter the apps inside
folders by toggling the icon's visibility.

https://bugzilla.gnome.org/show_bug.cgi?id=723179
2014-01-29 14:02:27 -05:00
3779ac2c8a appDisplay: Make AllView handle the display of the all apps view
Rather than having the central component handle it. Just a code tidying-up.

https://bugzilla.gnome.org/show_bug.cgi?id=723179
2014-01-29 14:02:27 -05:00
bdad4db9ec appDisplay: Only reload frequently used data when mapping the frequent view
If the user mostly uses the All Apps view and uses it as his default view,
we shouldn't reload frequent data after a timeout. Simply do it when the
view is mapped.

https://bugzilla.gnome.org/show_bug.cgi?id=723179
2014-01-29 14:02:26 -05:00
36c69124f7 shell-app: Don't crash when trying to dispose
If we dispose a ShellApp that has windows left, then we'll crash
when we remove the last window, as that frees and NULLs out
app->running_state.

https://bugzilla.gnome.org/show_bug.cgi?id=723197
2014-01-29 14:02:26 -05:00
7c8c811134 Dispose cairo contexts in osdWindow and screenShield
Need to manually dispose of cairo contexts used in gjs with $dispose(),
or the context object will leak. These classes used cairo for drawing but
were missing the dispose call.

https://bugzilla.gnome.org/show_bug.cgi?id=722812
2014-01-28 16:46:10 -08:00
ccfc9f3ab0 TelepathyClient: disconnect signals from destroyed ChatSources
Otherwise they keep firing if the source is destroyed by the user
and they trigger Clutter warnings from touching invalid actors.

https://bugzilla.gnome.org/show_bug.cgi?id=722660
2014-01-28 21:50:07 +01:00
d163b92e0b Add indicator for location service being used
If an application is accessing location through geoclue, show an
indicator in the panel for that so that user knows.

https://bugzilla.gnome.org/show_bug.cgi?id=709372
2014-01-28 18:39:12 +00:00
887a21afb9 appDisplay: Properly check for TerminalEmulator in the Categories key
get_categories() returns an unparsed string, not a list of categories.
We need to parse the list by splitting on ';' to deterine whether the
actual 'TerminalEmulator' category is in the list, rather than something
like 'X-GNOME-TerminalEmulator'. It's an edge case, but I need to split
the list properly for the new folders, so I might as well fix this.

https://bugzilla.gnome.org/show_bug.cgi?id=723179
2014-01-28 13:32:36 -05:00
634adc9f71 Fixed Russian translation 2014-01-28 22:18:22 +04:00
974f01cef7 appDisplay: Remove unused method 2014-01-28 11:17:34 -05:00
ef9ade3548 shell-global: Remove unused declaration 2014-01-28 11:17:34 -05:00
24fdb73b44 Updated Lithuanian translation 2014-01-25 22:17:09 +02:00
ba06a87ba8 window-tracker: Fix typo 2014-01-24 12:38:27 -05:00
e6be483755 network: Fix copy-paste typo 2014-01-23 16:11:11 -05:00
a36bfced47 network: Use NMDevice.get_available_connections(); for NMWirelessDialog
It's a lot simpler and doesn't require us routing the NMRemoteSettings
all the way through. It's still a bit complicated to do this for the
usual connections, so let's drop it for now.
2014-01-23 16:02:19 -05:00
4faf421d5a network: Let NetworkManager figure out the best AP for the connection
According to dcbw, this can be handled by NetworkManager now.
2014-01-23 14:38:40 -05:00
a739455414 gnome-shell-extension-prefs: Fix warnings 2014-01-23 14:38:31 -05:00
73f6e75d8d shell-app: Unref running state when window count drops to zero
With the lastest ShellApp changes, an app is considered stopped
when the last "interesting" window is closed. However the app
may still track non-interesting windows, so if we unref the
running state on the state transition, we hit an assertion later-on
when trying to remove the non-interesting window.
Fix this by keeping the running state around until the last window
is closed.

https://bugzilla.gnome.org/show_bug.cgi?id=722840
2014-01-23 12:45:23 -05:00
17e7f8057a Assamese translation updated 2014-01-23 19:06:34 +05:30
b62c157680 shell-app: Base running state on "interesting" windows
An app should be considered running if it has at least one "interesting"
window, however the code considers an app running if it has at least
one tracked window. This was fine while we were only tracking interesting
windows, but since commit d21aa0d85f this is no longer the case.
So keep track of the number of interesting windows as well and use that
to determine the running state.

https://bugzilla.gnome.org/show_bug.cgi?id=722690
2014-01-22 22:16:03 +01:00
816f5162f9 BackgroundManager: don't destroy the newly created actor
Because we were setting this.background before calling .destroy(),
the call that was meant to destroy the old background was actually
destroying the new one!

https://bugzilla.gnome.org/show_bug.cgi?id=722787
2014-01-22 20:35:02 +01:00
9d8f8277aa altTab: Always filter out items with no windows
When restricting the switcher popup to the current workspace, we
filter out running apps with an empty window list (namely: no open
windows on the current workspace). However we may end up with an
empty window list even when not restricting items to the current
workspace when all windows of a running app are associated with a
different application via the transient_for hint.
To fix this, just filter out items with an empty window list
unconditionally.

https://bugzilla.gnome.org/show_bug.cgi?id=722434
2014-01-22 13:52:49 -05:00
cca14053a4 window-tracker: Always enable transient_for redirection
It is possible to associate an application's window with a different
application using the transient_for hint. However we currently only
consider the hint in get_window_app() and not when making the original
association, which opens the door to some confusing inconsistencies;
for instance, get_window_app() will not necessarily return the same
value for all windows retrieved via shell_app_get_windows().
Fix this by looking at the transient_for hint when making the original
association, not just in get_window_app().

https://bugzilla.gnome.org/show_bug.cgi?id=722434
2014-01-22 13:52:49 -05:00
427790f005 switcherPopup: Fix spacing calculation for empty lists
Without special-casing, our current spacing calculation results in
negative size requests for empty lists, which will trigger a Clutter
assert later.
While the list is never supposed to be empty, bugs happen; crashing
users' systems is the least graceful way of handling this, so don't
do it.

https://bugzilla.gnome.org/show_bug.cgi?id=722434
2014-01-22 13:52:49 -05:00
17845bf71e Updated Norwegian bokmål translation 2014-01-21 20:03:49 +01:00
452f5ab3ba Updated Galician translations 2014-01-20 23:10:20 +01:00
335744e78a build: bump clutter requirement to 1.15.90
PopupMenus don't render properly with clutter older than this.

https://bugzilla.gnome.org/show_bug.cgi?id=722593
2014-01-21 08:03:29 +11:00
c9e24439b2 Updated Spanish translation 2014-01-20 16:39:10 +01:00
61c697b6db Updated Brazilian Portuguese translation 2014-01-19 21:12:15 -02:00
3227d4f3ed ShellApp+ShellGlobal: unify app launch context code
Extend shell_global_create_app_launch_context() with the required
parameters and use that for shell_app_launch() too.

https://bugzilla.gnome.org/show_bug.cgi?id=669603
2014-01-19 18:51:48 +01:00
7e27afb645 Introduce support for desktop actions in the dash
Using the new list_actions() API in Gio, add entries for static
actions specified in .desktop files in the right-click app menus,
in the dash, app well and search.

https://bugzilla.gnome.org/show_bug.cgi?id=669603
2014-01-19 18:47:29 +01:00
9ba4790b4d AppDisplay: clean up handling of right click popup menu
Instead of connecting a global activate handler on the menu,
have one on each menu item, individually doing the right thing.

https://bugzilla.gnome.org/show_bug.cgi?id=669603
2014-01-19 18:46:31 +01:00
3a26f7f4d5 WindowManager: WORKAROUND: disable dimming in the overview
Clones and effects don't mix, due to a bug in Clutter we don't
know how to fix, and sometimes the clone is clipped completely.
As a workaround, undim windows with dialogs in the overview.

Clutter bug: https://bugzilla.gnome.org/show_bug.cgi?id=659523

https://bugzilla.gnome.org/show_bug.cgi?id=650843
2014-01-19 16:38:19 +01:00
8b99617513 WorkspaceThumbnails: show attached modal dialogs togheter with their parents
The window clones in the central part of the overview are showing modal
dialogs now, and this creates an inconsistency if the thumbnail doesn't too.
Code is intentionally similar in the two places.

https://bugzilla.gnome.org/show_bug.cgi?id=650843
2014-01-19 16:37:17 +01:00
587655f063 Workspace: show attached modal dialog
Windows in the overview should be like they appear in the workspace,
including modal dialogs that are attached above them.
In addition, hiding the dialogs in the overview causes a flash as
dialog appears at the end of the transition.

Based on a patch by Maxim Ermilov <zaspire@rambler.ru>

https://bugzilla.gnome.org/show_bug.cgi?id=650843
2014-01-19 16:37:17 +01:00
7e9ecf4eb2 Add a radial background shade for modal dialogs
Use a new ShellGLSLQuad actor class to build a RadialEffect that can be
enabled on Lightboxes to achieve a radial effect similar to the overview
one. Then enable it for modal dialogs.

https://bugzilla.gnome.org/show_bug.cgi?id=669798
2014-01-19 16:02:46 +01:00
5413010c60 Notification: don't expand the content on a destroyed notification
If the notification is destroyed between an allocate and the redraw,
the meta_later is invoked on a destroyed object, and fails because
the clutter calls are invalid at that point.

https://bugzilla.gnome.org/show_bug.cgi?id=722547
2014-01-19 15:59:18 +01:00
7d13cf1587 ShellTrayIcon: forward key presses too
StWidget::popup-menu is emitted when Menu/<Shift>F10 is pressed,
not released (for consistency with Gtk+), so we need to forward
that. Note that for key press we don't emit the matching key
release, because the app will take a grab and get the event directly
from X when the key is physicall released.

https://bugzilla.gnome.org/show_bug.cgi?id=721267
2014-01-19 15:42:54 +01:00
24cd13935a build: Don't dist generated gresources files
In addition to 2dd7db4808
2014-01-19 10:15:15 +01:00
1ae7dbec67 build: Fix linker failure for gnome-shell-extension-prefs
In addition to 2dd7db4808
2014-01-19 10:08:42 +01:00
2b0a2ab3bc build tools: Update to 3.12 2014-01-18 19:33:49 +01:00
4ed0f3e5f0 AppDisplay: fix isTerminal() check for apps without .desktop files
If the app has no .desktop file get_app_info() returns null.
This breaks window switching using the dash for those apps.

https://bugzilla.gnome.org/show_bug.cgi?id=722494
2014-01-18 11:36:10 -05:00
9cacc703dd Tajik translation updated 2014-01-18 16:48:41 +05:00
9ae70c6519 Updated Czech translation 2014-01-18 12:23:10 +01:00
02b38fed49 Update Chinese simplified translation 2014-01-18 16:48:13 +08:00
b2a65f809f Use recommended quotes
See https://wiki.gnome.org/Design/OS/Typography
2014-01-17 16:34:44 -05:00
2931869522 [l10n] Updated Estonian translation 2014-01-17 17:44:49 +02:00
11d8640ba6 workspacesView: Fix activating empty workspaces
By default, gesture actions no longer wait for the dnd threshold to
be reached before triggering, which breaks our mixing of click- and
pan actions. Fix this by only panning after reaching the threshold
and letting the click action go through if the pan is cancelled.

https://bugzilla.gnome.org/show_bug.cgi?id=722417
2014-01-17 09:30:59 -05:00
65ff947b5e Updated Czech translation 2014-01-17 14:21:41 +01:00
2dd7db4808 Make gnome-shell-extension-prefs a binary executable
Since commit 1ebb162a00 moved JS sources into resources,
the extension-prefs tool was broken. To fix it, we would either
need to generate an external GResource in addition to the generated
C code and teach gjs-console about loading it before evaluating
the script, or turn gnome-shell-extension-prefs into a binary with
the JS resources compiled in.

https://bugzilla.gnome.org/show_bug.cgi?id=722334
2014-01-16 09:33:01 -05:00
1d7354696e Bump version to 3.11.4
Update NEWS.
2014-01-16 01:52:54 +01:00
cbceac4c8a boxpointer: Add condition checks for -arrow-rise:0px
This is done for properly drawing popup menu when arrow rise is 0 (in
case of background menu).

Normally, the menu with arrow rise set to 0 is drawn properly having
all four corners rounded. But when the source(click/arrowOrigin) is
near screen's edges, one of the corners (depending on source's position
and arrow alignment) is drawn right angled.

This happens because the rounded corners are skipped and right angled
arrow is drawn when arrow origin is close to the edges.(That's why when
arrow-rise is 0, it forms right angled corner).

So, a few condition checks are made to ensure that right angled corner
is not drawn.

https://bugzilla.gnome.org/show_bug.cgi?id=699608
2014-01-15 18:28:31 +01:00
297877fbe2 theme: Set -arrow-rise property of backgroundMenu to 0
Background menu shown on right clicking desktop background has an arrow
pointer which points to nothing. This patch sets its height (rise) to 0
so that no arrow is formed.

https://bugzilla.gnome.org/show_bug.cgi?id=699608
2014-01-15 18:28:31 +01:00
0d92451c49 shell-global: Remove unused gc-notifications support
This is going to be removed upstream.
2014-01-15 09:18:53 -05:00
c8a58dcb69 layout: Add a standard dummy cursor
Right now we have three "dummy cursor" widgets between the background
menu, the message tray menu, and the IBus candidate popup. Consolidate
these into one "dummy cursor" widget which is tracked in the layout
manager.
2014-01-14 18:56:45 -05:00
a4dea25d76 layout: Don't require fullscreen-tracked actors to be toplevel
I don't know why this was ever here; We only have one
fullscreen-tracked actor.
2014-01-14 18:56:45 -05:00
bfb0235fc6 Remove our custom hashmap implementation
gjs uses Spidermonkey 24, which implements Map from the ES6
specification, so we can use that instead.

https://bugzilla.gnome.org/show_bug.cgi?id=722210
2014-01-15 00:55:00 +01:00
6dcc3d637f windowManager: Fix the name of the keybinding 2014-01-14 17:58:51 -05:00
9bb4d17e31 Add a debug keybinding to pause/resume all tweens
So we can inspect a mid-tween scene easier.
2014-01-14 17:25:14 -05:00
9df09db5fe appDisplay: Use the new org.gnome.desktop.app-folders schema for grouping
Rather than GMenu / app-folder-categories. This removes our last use of
gnome-menus in the stock gnome-shell, which is exciting, but also means
that app folders in Software start working.

Ideally, we'd have a button to launch our Software app as well from the
overview.

https://bugzilla.gnome.org/show_bug.cgi?id=722117
2014-01-14 11:25:08 -05:00
d8e28ec274 viewSelector: Remove unused setActivePage 2014-01-14 09:10:12 -05:00
d3905734c1 background: Remove unused argument 2014-01-13 20:17:57 -05:00
8fe7f923ec appDisplay: Move from instanceof-testing to polymorphic duck typing
Instead of having _compareItems, _getItemId, etc. on the view to
pull out info about items, use the AppIcon / FolderIcon items we
create as a place to track this additional info. We now require
that these items have a '.id' property for deduplication, and a
'.name' property to sort by.

https://bugzilla.gnome.org/show_bug.cgi?id=722117
2014-01-13 17:28:32 -05:00
933f38390b background: Don't require passing in a background to _updateBackground()
To make debugging background issues easier.
2014-01-13 17:14:58 -05:00
a4e019442f AppDisplay: fix isTerminal() check for apps without categories
If there is no Categories line in the .desktop file, get_categories()
returns null, not an empty array.
2014-01-13 23:13:28 +01:00
d1c4e60636 switcherPopup: Always show the arrows if the popup is scrollable
Currently we only show/hide the left and right arrows when
we reach the initial/end position. This patch changes this
behaviour by showing the arrows whenever is a scroll is possible.

https://bugzilla.gnome.org/show_bug.cgi?id=711467
2014-01-13 16:02:35 -02:00
765d0228c0 loginDialog: move user list loading after actors are constructed
Right now we queue populating the user list in the middle of setting
up the dialog actors. Of course, the actual population happens some time
later after going back to the main loop.

It's more logical to structure the code so the the actors are
instantiated first in one block and then other things after that.

This commit moves the user list population enqueuing operation to the
bottom of the constuctor.

https://bugzilla.gnome.org/show_bug.cgi?id=721868
2014-01-13 12:42:39 -05:00
2d2020a20d loginDialog: defer loading user list until idle
In some cases we load the user list after going back
to main loop and in other cases we load the user list
right away (depending on if accounts service is ready).

In the case we load the user list right away we cause a
traceback because loading the user list forces a reset,
which then tries to reset actors which aren't instantiated
yet.

This commit ensures the user list is loaded after the constructor
finishes and the event loop runs irregardless of the accountsservice
state.

https://bugzilla.gnome.org/show_bug.cgi?id=721868
2014-01-13 12:42:33 -05:00
03ab282f67 appDisplay: Fix style 2014-01-13 11:39:30 -05:00
7f94cb1cad Updated Galician translations 2014-01-13 01:46:07 +01:00
a2a303bd72 Updated Greek translation 2014-01-12 19:53:24 +02:00
d34bf9a14d app-system: Remove unnecessary debugging statement
It's just spam.
2014-01-10 15:19:07 -05:00
68faba6bde appDisplay: Special case terminal launching
One of the most frequent complaints about our launching behaviour is
how we handle terminals. Among all MDI applications, the terminal is
the one that is most likely to have lots of semi-independent windows
opened at the same time, and spawning new windows is much more common.
More so, if it does not support tabs.

Therefore, we special case terminal launchers to always create a new
window. It is an application that most non-technical users will not
use, so chances of them being confused by any special behaviour is
expected to be low.

https://bugzilla.gnome.org/show_bug.cgi?id=695010
2014-01-10 12:08:14 +01:00
5c5b9cfd96 Also update gtkaction*
Forgot about this.
2014-01-09 14:59:31 -05:00
9d683f4767 gtkmenutracker: Update from GTK+ 2014-01-09 14:47:11 -05:00
f2912bad95 fileUtils: Remove listDirAsync()
It's unused since commit da4238ec68, just kill it.

https://bugzilla.gnome.org/show_bug.cgi?id=721629
2014-01-09 13:23:26 -05:00
c8adfe0131 Updated Hebrew translation 2014-01-08 17:32:29 +02:00
8b7e637e74 Updated Spanish translation 2014-01-08 12:43:32 +01:00
43cffd7c4a main: allow session mode to be specified in the environment
Specifying the session mode on the command-line doesn't play
well with session management (since the saved session desktop
file well either drop the specified session mode, or force it
always, even if the user picked a different mode at the login
screen)

This commit adds support for specifying the session mode via an
enviroment variable. For now, keep the old command line interface
for backward compatibility

https://bugzilla.gnome.org/show_bug.cgi?id=720894
2014-01-07 16:36:26 -05:00
f3dad3765e Changed obsolete FSF postal address.
https://bugzilla.gnome.org/show_bug.cgi?id=721507
2014-01-08 04:35:14 +07:00
70c25141fc Tajik translation updated 2014-01-07 23:32:30 +05:00
b1b81a2672 Improve some strings in gschema file 2014-01-07 18:55:25 +01:00
46197bf262 Tajik translation updated 2014-01-07 13:49:47 +05:00
58ec409e7f [l10n] Updated Italian translation. 2014-01-06 09:42:06 +01:00
c2d68599de Update Kazakh translation 2014-01-05 20:31:42 +06:00
65f00f3af2 ShellWindowTracker: remove gtk-doc marks from private functions
static internal functions should be documented with /*, not /**

https://bugzilla.gnome.org/show_bug.cgi?id=721439
2014-01-04 17:34:29 +01:00
6544326ffd ShellWindowTracker: fix reference counting of ShellApp
All get_app_from_*() helpers are transfer full, but
get_app_from_gapplication_id() was directly returning the result
of lookup_app(), which is transfer none.

https://bugzilla.gnome.org/show_bug.cgi?id=721439
2014-01-04 17:34:10 +01:00
a23c206ccb Updated Indonesian translation 2014-01-04 10:25:11 +07:00
1b152e6bd0 WorkspacesView: fix removal of workspaces that are not at the end
Workspaces can removed from any index, and in particular they
will be removed by the WorkspaceTracker if they stop containing
windows at some point. Make sure WorkspacesView is not confused
and destroyes the right Workspace objects.

https://bugzilla.gnome.org/show_bug.cgi?id=721417
2014-01-03 22:46:45 +01:00
d9624d9882 Updated Lithuanian translation 2014-01-03 23:13:04 +02:00
178b8471cc shell-global: Remove an explicit js-version set
gjs's default js-version is already 1.8, and we're planning on removing
this API in the future, in accordance with upstream.
2014-01-02 13:41:14 -05:00
719d2092a7 Updated German translation 2014-01-02 14:43:18 +01:00
2f3a4675da Updated Brazilian Portuguese translation 2014-01-02 04:16:35 -02:00
9513be664b Updated Slovenian translation 2014-01-01 20:06:54 +01:00
64d8b7853a Update Chinese simplified translation 2014-01-01 17:02:30 +08:00
4174e57c13 Updated Spanish translation 2013-12-30 11:55:56 +01:00
88b395599a Updated Czech translation 2013-12-30 00:10:17 +01:00
b6d682c92c Updated Czech translation 2013-12-29 23:55:23 +01:00
3b02894341 Updated Brazilian Portuguese translation 2013-12-26 23:45:28 -02:00
f3feb13dfe ShellAppSystem: own the memory for the startup wm class and app id
The hash table must keep a copy of the IDs, because the GAppInfos
are unreferenced (and thus freed) at the end of the function.
This was possibly not a problem if the GAppInfos were referencing
the memory-mapped cache, but it becomes one for regularly parsed
desktop files in ~/.local.

https://bugzilla.gnome.org/show_bug.cgi?id=721039
2013-12-26 23:44:54 +01:00
114d8d0aba [l10n] Updated Italian translation. 2013-12-24 10:27:16 +01:00
503a843bb3 Updated Norwegian bokmål translation 2013-12-23 10:25:28 +01:00
c4d91aff40 Updated Aragonese translation 2013-12-22 21:16:13 +01:00
2ffe5faf6e Updated Slovenian translation 2013-12-22 19:24:13 +01:00
5d2a03aa82 Updated German translation 2013-12-22 18:59:27 +01:00
f4c83d1221 Update Chinese simplified translation 2013-12-22 22:54:09 +08:00
100e91714b Updated slovak translation 2013-12-22 13:14:30 +01:00
dafb7b5259 Bump version to 3.11.3
Update NEWS.
2013-12-19 21:54:37 +01:00
92906e217c Updated Spanish translation 2013-12-19 14:36:46 +01:00
5c7b721879 Tajik translation updated 2013-12-19 14:13:33 +05:00
c27dcb0414 Updated Galician translations 2013-12-19 01:53:09 +01:00
7fcae1e974 Remove use of superfluous MetaWindowActor APIs 2013-12-16 12:48:53 -05:00
cc4659f5c6 calendar: Don't rebuild the entire calendar widget when choosing a date
It's inefficient and wasteful. Combined with the JS GC not being great,
it leaks around 100 actors waiting to be GC'd. Yikes.

https://bugzilla.gnome.org/show_bug.cgi?id=720298
2013-12-16 12:44:23 -05:00
9fce12d6b4 calendar: Don't ever force reload
https://bugzilla.gnome.org/show_bug.cgi?id=720298
2013-12-16 12:44:22 -05:00
deb2f30b37 js: Use EVENT_PROPAGATE/EVENT_STOP constants in event handlers
Just as SOURCE_CONTINUE/SOURCE_REMOVE in source functions, these
constants increase code clarity over plain true/false.

https://bugzilla.gnome.org/show_bug.cgi?id=719567
2013-12-16 18:27:19 +01:00
751a3f0e94 js: Use SOURCE_CONTINUE/SOURCE_REMOVE constants in source functions
With support for boolean constants in g-i, we can finally use the
more readable constants instead of true/false.

https://bugzilla.gnome.org/show_bug.cgi?id=719567
2013-12-16 18:27:19 +01:00
fee2a07e08 runDialog: Explicitly set horizontal alignment
When set to fill, the label will always end up left-aligned, which
is only correct in LTR locales. Set the alignment explicitly to
work in both RTL and LTR locales.

https://bugzilla.gnome.org/show_bug.cgi?id=712579
2013-12-16 18:27:19 +01:00
17726abb0a NetworkAgent: handle empty hints and VPN secrets correctly
get_secrets_keyring_cb() contained an optimization (copied over from
nm-applet) that avoided a D-Bus round-trip when NetworkManager sent
secrets hints that were not satisified by the user.  This code did
not properly handle empty hints though, and proceeded to always
request new secrets whenever empty hints were sent.  Remove this
code entirely since the complexity is not worth it (per Jasper).

Second, get_secrets_keyring_cb() was mishandling VPN secrets which
were marked as "always ask".  Because the VPN secrets are not GObject
properties because they cannot be pre-defined, they are passed in
a hash table that is a GObject property marked 'secret'.  Unfortunately,
that means that the shell agent cannot determine their secret flags.
But since the VPN plugin auth dialogs have much better information
about what's required than the shell agent does, always ask the VPN
auth dialogs to handle the secrets requests after grabbing any that
already exist from the keyring.  This is also what nm-applet does.

https://bugzilla.gnome.org/show_bug.cgi?id=719815
2013-12-13 16:23:24 -06:00
01f740ce69 background: Don't prematurely remove file monitors
We need to only remove file monitors when there's no other users
of the content...
2013-12-13 11:50:17 -05:00
b168ccb605 st-scroll-view: Fix style 2013-12-11 20:36:44 -05:00
04a31a52ae calendar: Fix style 2013-12-11 20:36:44 -05:00
6a236fb91e keyring: Align more a srtings to the right side in RTL
It is missed in the previous patch.

Signed-off-by: Yosef Or Boczko <yoseforb@gmail.com>
2013-12-11 23:23:23 +02:00
619fa1bff8 polkitAgent: Align more a string to the right side in RTL
Signed-off-by: Yosef Or Boczko <yoseforb@gmail.com>
2013-12-11 23:14:08 +02:00
53b37e8d0c endSessionDialog: Align some strings to the right in RTL
https://bugzilla.gnome.org/show_bug.cgi?id=712600
2013-12-11 22:42:01 +02:00
f8eb8adfbe keyring: Align some srtings to right in RTL
https://bugzilla.gnome.org/show_bug.cgi?id=712594
2013-12-11 22:40:18 +02:00
3c2aecb81f polkitAgent: Explicitly set horizontal alignment
When set to fill, the label will always end up left-aligned, which
is only correct in LTR locales. Set the alignment explicitly to
work in both RTL and LTR locales.

https://bugzilla.gnome.org/show_bug.cgi?id=712596
2013-12-11 22:38:58 +02:00
efca9e11d6 unlockDialog: Explicitly set horizontal alignment
When set to fill, the label will always end up left-aligned, which
is only correct in LTR locales. Set the alignment explicitly to
work in both RTL and LTR locales.

https://bugzilla.gnome.org/show_bug.cgi?id=712638
2013-12-11 22:36:49 +02:00
49189e0e43 authPrompt: Explicitly set horizontal alignment
When set to fill, the label will always end up left-aligned, which
is only correct in LTR locales. Set the alignment explicitly to
work in both RTL and LTR locales.

https://bugzilla.gnome.org/show_bug.cgi?id=712638
2013-12-11 22:36:15 +02:00
ea86c9bafb userWidget: Fix the padding in RTL
https://bugzilla.gnome.org/show_bug.cgi?id=712638
2013-12-11 22:35:44 +02:00
c361b6a85c Update Arabic translation 2013-12-11 06:53:36 +02:00
c7ff45045c remoteSearch: Let remote search providers not provide an icon
The documentation indicates that they are optional, so let us make the
code behave accordingly.

https://bugzilla.gnome.org/show_bug.cgi?id=719965
2013-12-10 17:01:42 +01:00
090af35ea1 Finnish translation update 2013-12-09 08:08:10 +02:00
8e668ca633 sessionMode: Add back external session modes
Since commit da4238ec68, external session modes are no longer
loaded during start-up; bring them back.

https://bugzilla.gnome.org/show_bug.cgi?id=720017
2013-12-07 10:10:06 +01:00
4d9a16f33b sessionMode: Fix listModes()
Commit da4238ec68 just broke that function completely by
calling array methods on objects and other funny stuff. Fix it.

https://bugzilla.gnome.org/show_bug.cgi?id=720017
2013-12-07 10:10:06 +01:00
c9f2a0f694 sessionMode: Rename _getModes()
Since commit da4238ec68, the function doesn't return anything,
so rename it to _loadModes() to reflect this.

https://bugzilla.gnome.org/show_bug.cgi?id=720017
2013-12-07 10:10:06 +01:00
46bac3069e sessionMode: Fix left-over variable in _loadMode()
Commit da4238ec68 dropped a variable, but didn't replace all
consumers.

https://bugzilla.gnome.org/show_bug.cgi?id=720017
2013-12-07 10:10:06 +01:00
d21aa0d85f shell-app: Track all application windows
Filtering out "non-interesting" windows beforehand as we currently do
means that we may get properties that should be based on all windows,
like the last time the application was used, wrong.
Just track all windows and filter out non-interesting windows manually
in the one place we actually care about the difference.

https://bugzilla.gnome.org/show_bug.cgi?id=719824
2013-12-07 10:10:06 +01:00
3e87d699eb [l10n]Updated Turkish translation 2013-12-07 08:20:27 +02:00
23aa216908 [l10n] Updated Estonian translation 2013-12-05 12:45:57 +02:00
e34e681157 messageTray: Fix style 2013-12-05 01:32:28 -05:00
acd543fe4b messageTray: Fix style
We're missing a semi here
2013-12-04 20:51:10 -05:00
c2df5939d6 Sort js-resources.gresource.xml 2013-12-04 20:44:22 -05:00
b52e74b615 messageTray: Remove transient sources
As far as I can tell, the only behavior change of a transient source
is that they auto-destroy after viewing their summary box pointer.
Since all transient sources are only associated with transient
notifications, it seems that we can never get to their summary box
pointer in the first place! Remove support for this.

https://bugzilla.gnome.org/show_bug.cgi?id=710115
2013-12-04 20:25:28 -05:00
ec2bb039ae viewSelector: Give the active page key focus when it is shown
Rather than implement special focus policies like only allowing keynav
when pressing down, simply give the active page key focus when entering
the overview.

This may break stuff, as it's somewhat of a tricky patch to get right.
Testing this one would be super appreciated.

https://bugzilla.gnome.org/show_bug.cgi?id=644306
2013-12-04 11:22:55 -05:00
aeb9f5775f workspace: Grab the key focus when hovering over a window
This is simply an experiment. I'm not sure I like the result, but it was
worth trying out regardless.

https://bugzilla.gnome.org/show_bug.cgi?id=644306
2013-12-04 11:22:55 -05:00
47a20756b9 workspace: Implement key navigation on the workspaces page
Simply use St's existing key navigation system by making all the window
clones StWidgets, and making the WorkspacesView a focus group.

Since the workspace view is effectively "fake", we need to add a focus
delegator so that when key focus is assigned to the fake workspaces page,
we can keynav inside it properly.

https://bugzilla.gnome.org/show_bug.cgi?id=644306
2013-12-04 11:22:55 -05:00
a7aba1d585 st-widget: Sort actors by distance from the focused actor
Sorting actors by the distance in the axis of movement first and against
the axis otherwise means that if we have a situation like:

  A      F
   B

where "F" is the focused actor, and it slightly overlaps with B vertically,
then we'll choose "B" to go left, rather than "A", which is most likely
what the user intended.

This is especially apparent in the overview where slight window size
differences mean we might not get an exact grid shape.

https://bugzilla.gnome.org/show_bug.cgi?id=644306
2013-12-04 11:22:55 -05:00
c89af0cea4 messageTray: Only attempt to grab the summary box pointer after showing it
For mysterious reasons I'm not sure of myself, navigate_focus will only focus
mapped actors. So, make sure the widget is showing before navigating to it.

https://bugzilla.gnome.org/show_bug.cgi?id=709853
2013-12-04 11:22:55 -05:00
9d3a109946 messageTray: Reword a boolean condition
Just so it's a bit easier to understand...
2013-12-04 11:22:55 -05:00
079f1e6fff messageTray: Fix style 2013-12-04 11:22:55 -05:00
7249b11899 background: Don't silently fizzle out when removing bad content from the cache
If the background is already removed, or we're trying to remove bad content,
this is probably a bug in content accounting, so let us crash so we can fix
the bugs.

https://bugzilla.gnome.org/show_bug.cgi?id=719803
2013-12-03 19:13:12 -05:00
4cfb000812 background: Add copied content from pending image loads to the cache
https://bugzilla.gnome.org/show_bug.cgi?id=719803
2013-12-03 19:13:12 -05:00
5262a41619 background: Clarify the intent of the code
Stomping on local variables and trying to keep loop state isn't
too fun. Just use a new variable here so we aren't too confused
with what we're doing.

https://bugzilla.gnome.org/show_bug.cgi?id=719803
2013-12-03 19:13:12 -05:00
887590730d background: Simplify animation code
https://bugzilla.gnome.org/show_bug.cgi?id=719803
2013-12-03 19:13:12 -05:00
adb49bdf0b background: Remove unused variable
https://bugzilla.gnome.org/show_bug.cgi?id=719803
2013-12-03 19:13:12 -05:00
7f3aadc157 background: Remove the system noise content when not in use
https://bugzilla.gnome.org/show_bug.cgi?id=719803
2013-12-03 19:13:12 -05:00
eb1c85f3f5 background: Don't wait for gdk-pixbuf to fail before loading animations
We don't have any better way of determining whether something is a slideshow
animation, so discriminate on the .xml filename instead of waiting for
gdk-pixbuf to determine whether it can load a file or not.

https://bugzilla.gnome.org/show_bug.cgi?id=719803
2013-12-03 19:13:12 -05:00
dbdc884c96 background: Remove more bogus checks
The content in these arrays can never be null...

https://bugzilla.gnome.org/show_bug.cgi?id=719803
2013-12-03 19:13:12 -05:00
5166354e34 networkAgent: add support for EAP-FAST password requests
EAP-FAST is a top-level EAP method like TTLS, PEAP, etc.

https://bugzilla.gnome.org/show_bug.cgi?id=719813
2013-12-03 18:03:52 -06:00
04ea95049a background: Fix the check for spanning backgrounds
this._monitorIndex does not exist, and neither does
MetaBackground.monitor_index...

https://bugzilla.gnome.org/show_bug.cgi?id=719803
2013-12-03 18:36:46 -05:00
ec62e49001 bluetooth: Remove unused import 2013-12-03 18:36:46 -05:00
6fb21850d8 Updated Brazilian Portuguese translation 2013-12-02 23:17:13 -02:00
98b50fd942 UserWidget: replace vfunc_destroy override with a signal connection
The destroy vfunc might be called during object finalization, and
we can't call any JS from a GC finalizer, so we use a signal
connection instead, as that is removed by GObject the first time
the object is disposed.

https://bugzilla.gnome.org/show_bug.cgi?id=719730
2013-12-02 23:59:50 +01:00
729c962b7c loginDialog: Implement cancel()
The screen shield expects a cancel() method on the unlockDialog
implementation, but LoginDialog does not provide it currently.

https://bugzilla.gnome.org/show_bug.cgi?id=719378
2013-11-27 14:30:24 +01:00
ebc15e60a8 bluetooth: Remove GnomeBluetoothApplet hacks
https://bugzilla.gnome.org/show_bug.cgi?id=719341
2013-11-26 18:53:18 +01:00
85f2d94253 bluetooth: Use BluetoothClient to detect connected devices
Instead of the GnomeBluetoothApplet helper.

https://bugzilla.gnome.org/show_bug.cgi?id=719341
2013-11-26 18:53:18 +01:00
981a536cb5 bluetooth: Use g-s-d to turn off Bluetooth
https://bugzilla.gnome.org/show_bug.cgi?id=719341
2013-11-26 18:53:18 +01:00
abf7c333b1 bluetooth: Remove pairing agent
We'll only have it in the Bluetooth settings panel.

https://bugzilla.gnome.org/show_bug.cgi?id=719341
2013-11-26 18:53:18 +01:00
b2f547e934 authPrompt: propagate gdm "reset" signal after user switching
After a user types in their password at the login screen, one
of two things can happen

1) a new session is started
2) an existing session is switched to

In the latter case, GDM sends a reset signal to the login screen,
so it knows to go back to the user list and wait to be summoned
again.

Unfortunately, all reset signals are ignored after verification
success.  The reason is because the reset handler was copied from
the unlock dialog as part of a deduplication effort in commit
7e7295f259 and the unlock dialog
handler at the time also emitted a "failed" signal on reset
(which wouldn't make sense to emit after success).

These days "failed" is handled in a different way.

This commit changes the code to let reset signals through after
successful verification.

https://bugzilla.gnome.org/show_bug.cgi?id=710456
2013-11-25 22:38:44 -05:00
0870a25e2f Typo fixed in Dutch translation 2013-11-22 22:44:13 +01:00
1091e577a5 Updated Dutch translation by Erwin Poeze 2013-11-22 22:41:18 +01:00
151ad16fe6 Updated Norwegian bokmål translation 2013-11-21 21:24:50 +01:00
e325258091 build: require gjs 1.39.0
This is required for the gresources loader
2013-11-22 06:58:33 +11:00
1139a02b40 viewSelector: Don't show pages until they need to be visible
AppDisplay queues a deferred work to load frequently used apps when the
apps page is loaded. Unfortunately, when the overview is first opened,
all the pages start out visible and then immediately get hidden, so the
deferred work runs immediately after the first overview opening, whether
the user was going to view their frequent apps or not.

Start all pages off as hidden, and rearrange the code so that pages are
only shown when they really need to be.

https://bugzilla.gnome.org/show_bug.cgi?id=712753
2013-11-21 12:50:03 -05:00
4b90953226 osdWindow: add setMonitor() to allow changing the monitor
This is also exposed in the ShowOSD DBus method, the "monitor"
parameter may contain an integer to indicate the monitor number.
If the value is not provided or <0 is used, the monitor is shown
on the primary monitor as usually.

This way, the OSD can be used to notify upon events that solely
apply to one monitor, like tablet mapping as discussed in
https://bugzilla.gnome.org/show_bug.cgi?id=710373.

https://bugzilla.gnome.org/show_bug.cgi?id=712664
2013-11-20 18:03:32 +01:00
d77fc01580 boxpointer: Don't hide when we're already hidden
You would think we would already do something like this, but apparently
lots of code was calling hide() without checking if the box pointer was
already visible, causing it to queue a full tween. The biggest win was
with ibusCandidatePopup.js, which called hide() on every DBus message.

This increases the performance for me to enter the overview by a tiny
bit. The remaining time is spent updating the frequent apps / all apps
display.

https://bugzilla.gnome.org/show_bug.cgi?id=712727
2013-11-19 23:23:25 -05:00
216d84faeb layout: Adjust the opening animation to be less intense
https://bugzilla.gnome.org/show_bug.cgi?id=712362
2013-11-19 22:09:34 -05:00
0c9d95f183 userWidget: Chain up in destroy() 2013-11-19 18:11:43 -05:00
913739d732 shell-app: Remove unused method 2013-11-19 18:11:43 -05:00
7ecb5af587 appDisplay: Remove unused signal
The signal was last used in the pre-3.0 days, so we can stop dragging
it along and just remove it.
2013-11-18 16:24:13 +01:00
87f0e79749 messageTray: Prevent reentrancy issues in _updateState
The methods we call in _updateState may not be reentrant, so make
sure that we never get into a situation where _updateState, through
some crazy chain of events, calls itself.

https://bugzilla.gnome.org/show_bug.cgi?id=711694
2013-11-17 12:06:38 -05:00
c85145d73c entry: Make sure we chain up in enter/leave handlers
To ensure that the focus tracking executes correctly.

https://bugzilla.gnome.org/show_bug.cgi?id=706749
2013-11-15 12:51:19 -05:00
eea689841b highlight session menu button on key focus
https://bugzilla.gnome.org/show_bug.cgi?id=710539
2013-11-15 11:29:21 -05:00
e50a59361d entry: Remove old documentation about the hover style class 2013-11-15 11:14:36 -05:00
9862185bda theme: Clean up
Remove some unused CSS
2013-11-15 11:14:35 -05:00
fe05d35bbb messageTray: Fix style 2013-11-15 10:39:30 -05:00
ba602c17d4 appDisplay: Use the desktop file index for app searching
Rather than scanning all apps for searching, use Ryan's new desktop
file index and the glib support APIs for app searching instead of our
own system.

https://bugzilla.gnome.org/show_bug.cgi?id=711631
2013-11-14 14:28:52 -05:00
831bd07b0d layout: Fix several issues with the background management code
If monitor-changed fires at startup, it will destroy all of the
backgrounds, but since this._isStartup is true, won't recreate any
of them. Additionally, since _bgManagers is indexed by monitor index,
if the primary index is not 0, it could become a sparse array (e.g.
[undefined, undefined, primaryBackground]), and our for loop will
crash trying to access properties of undefined.

Fix both of these issues by always creating background managers for
every monitor, hiding them on startup but only showing them after
the startup animation is complete.

One thing we need to watch out for is that while LayoutManager is
constructing, Main.uiGroup / Main.layoutManager will be undefined,
so addBackgroundMenu will fail. Fix this by passing down the uiGroup
to the background menu code.

https://bugzilla.gnome.org/show_bug.cgi?id=709313
2013-11-14 14:28:51 -05:00
175c5d9fc3 overview: Fix stacking of background and desktop icons
If desktop icons are enabled and not covered by maximized windows,
we will fade them in/out during overview transitions. However when
moving background handling into mutter/gnome-shell, we ended up with
the overview background on top of the DESKTOP window clone, hiding
the fade transition.
Fix the stack order to bring the effect back.

https://bugzilla.gnome.org/show_bug.cgi?id=707671
2013-11-14 15:49:28 +00:00
158 changed files with 12154 additions and 13189 deletions

41
COPYING
View File

@ -1,12 +1,12 @@
GNU GENERAL PUBLIC LICENSE GNU GENERAL PUBLIC LICENSE
Version 2, June 1991 Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc. Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed. of this license document, but changing it is not allowed.
Preamble Preamble
The licenses for most software are designed to take away your The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public freedom to share and change it. By contrast, the GNU General Public
@ -15,7 +15,7 @@ software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by using it. (Some other Free Software Foundation software is covered by
the GNU Library General Public License instead.) You can apply it to the GNU Lesser General Public License instead.) You can apply it to
your programs, too. your programs, too.
When we speak of free software, we are referring to freedom, not When we speak of free software, we are referring to freedom, not
@ -55,8 +55,8 @@ patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and The precise terms and conditions for copying, distribution and
modification follow. modification follow.
GNU GENERAL PUBLIC LICENSE GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains 0. This License applies to any program or other work which contains
@ -110,7 +110,7 @@ above, provided that you also meet all of these conditions:
License. (Exception: if the Program itself is interactive but License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on does not normally print such an announcement, your work based on
the Program is not required to print an announcement.) the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program, identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in and can be reasonably considered independent and separate works in
@ -168,7 +168,7 @@ access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not distribution of the source code, even though third parties are not
compelled to copy the source along with the object code. compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program 4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is otherwise to copy, modify, sublicense or distribute the Program is
@ -225,7 +225,7 @@ impose that choice.
This section is intended to make thoroughly clear what is believed to This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License. be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in 8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License original copyright holder who places the Program under this License
@ -255,7 +255,7 @@ make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally. of promoting the sharing and reuse of software generally.
NO WARRANTY NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
@ -277,9 +277,9 @@ YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES. POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it possible use to the public, the best way to achieve this is to make it
@ -303,17 +303,16 @@ the "copyright" line and a pointer to where the full notice is found.
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License along
along with this program; if not, write to the Free Software with this program; if not, write to the Free Software Foundation, Inc.,
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Also add information on how to contact you by electronic and paper mail. Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this If the program is interactive, make it output a short notice like this
when it starts in an interactive mode: when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details. under certain conditions; type `show c' for details.
@ -336,5 +335,5 @@ necessary. Here is a sample; alter the names:
This General Public License does not permit incorporating your program into This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Library General library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License. Public License instead of this License.

58
NEWS
View File

@ -1,3 +1,61 @@
3.11.4
======
* Fix removal of workspacaes that are not at the end [Giovanni; #721417]
* Allow session mode to be specified in the environment [Ray; #720894]
* Special-case launching of terminals [Debarshi; #695010]
* Always show arrow if app switcher is scrollable [Jonh; #711467]
* Implement new app folders system [Jasper; #722117]
* Remove arrow from background menu [Tarun; #699608]
* Misc bug fixes and cleanups [Giovanni, Andika, Florian, Ray; #721039,
#721439, #721507, #721629, #721868, #722210]
Contributors:
Giovanni Campagna, Piotr Drąg, Tarun Kumar Joshi, Florian Müllner,
Debarshi Ray, Jasper St. Pierre, Ray Strode, Andika Triwidada, Jonh Wendell
Translations:
Dušan Kazik [sk], Tong Hui [zh_CN], Benjamin Steinwender [de],
Matej Urbančič [sl], Jorge Pérez Pérez [an], Kjartan Maraas [nb],
Milo Casagrande [it], Rafael Ferreira [pt_BR], Marek Černocký [cs],
Daniel Mustieles [es], Adorilson Bezerra [pt_BR], Christian Kirbach [de],
Aurimas Černius [lt], Andika Triwidada [id], Baurzhan Muftakhidinov [kk],
Victor Ibragimov [tg], Yosef Or Boczko [he], Dimitris Spingos [el],
Fran Diéguez [gl]
3.11.3
======
* Fix fade effect of desktop icons [Florian; #707671]
* Fix issues with background management code [Jasper; #709313]
* Use new Glib facilities for application search [Jasper; #711631]
* Add focus indication to session menu button [Sebastien; #710539]
* Fix hover tracking for StEntries [Jasper; #706749]
* Fix reentrancy issue in message tray [Jasper; #711694]
* Tone down zoom animation on login/unlock [Jasper; #712362]
* Allow specifying monitor for OSD [Carlos; #712664]
* Fix resetting prompt on user switch [Ray; #710456]
* Stop using gnome-bluetooth-applet [Bastien; #719341]
* Add support for EAP-FAST password requests [Dan; #719813]
* Fix entry focus of chat notifications [Jasper; #709853]
* Make window previews keyboard navigatable [Jasper; #644306]
* Fix app switcher order with dialog windows [Florian; #719824]
* Allow remote search providers without icons [Debarshi; #719965]
* Fix various alignment issues in RTL locales [Yosef; #712638, #712596,
#712594, #712600, #712579]
* Misc. bug fixes and cleanups [Jasper, Florian, Giovanni, Dan; #712727,
#712753, #719378, #719730, #719803, #710115, #720017, #719815, #719567,
#720298]
Contributors:
Giovanni Campagna, Carlos Garnacho, Sebastien Lafargue, Tim Lunn,
Florian Müllner, Bastien Nocera, Yosef Or Boczko, Debarshi Ray,
Jasper St. Pierre, Ray Strode, Dan Williams
Translations:
Kjartan Maraas [nb], Reinout van Schouwen [nl], Rafael Ferreira [pt_BR],
Mattias Põldaru [et], Emin Tufan Çetin [tr], Jiri Grönroos [fi],
Khaled Hosny [ar], Fran Diéguez [gl], Victor Ibragimov [tg],
Daniel Mustieles [es]
3.11.2 3.11.2
====== ======
* Cache search result display actors [Jasper; #704912] * Cache search result display actors [Jasper; #704912]

View File

@ -13,9 +13,7 @@
* General Public License for more details. * General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software * along with this program; if not, see <http://www.gnu.org/licenses/>.
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
* *
* Authors: * Authors:
* Jasper St. Pierre <jstpierre@mecheye.net> * Jasper St. Pierre <jstpierre@mecheye.net>

View File

@ -1,5 +1,5 @@
AC_PREREQ(2.63) AC_PREREQ(2.63)
AC_INIT([gnome-shell],[3.11.2],[https://bugzilla.gnome.org/enter_bug.cgi?product=gnome-shell],[gnome-shell]) AC_INIT([gnome-shell],[3.11.4],[https://bugzilla.gnome.org/enter_bug.cgi?product=gnome-shell],[gnome-shell])
AC_CONFIG_HEADERS([config.h]) AC_CONFIG_HEADERS([config.h])
AC_CONFIG_SRCDIR([src/shell-global.c]) AC_CONFIG_SRCDIR([src/shell-global.c])
@ -73,9 +73,9 @@ AS_IF([test x$enable_systemd != xno], [
AC_MSG_RESULT($enable_systemd) AC_MSG_RESULT($enable_systemd)
CLUTTER_MIN_VERSION=1.13.4 CLUTTER_MIN_VERSION=1.15.90
GOBJECT_INTROSPECTION_MIN_VERSION=0.10.1 GOBJECT_INTROSPECTION_MIN_VERSION=0.10.1
GJS_MIN_VERSION=1.38.1 GJS_MIN_VERSION=1.39.0
MUTTER_MIN_VERSION=3.11.1 MUTTER_MIN_VERSION=3.11.1
GTK_MIN_VERSION=3.7.9 GTK_MIN_VERSION=3.7.9
GIO_MIN_VERSION=2.37.0 GIO_MIN_VERSION=2.37.0
@ -140,19 +140,11 @@ AS_IF([test x$enable_browser_plugin = xyes], [
]) ])
AM_CONDITIONAL(BUILD_BROWSER_PLUGIN, test x$enable_browser_plugin = xyes) AM_CONDITIONAL(BUILD_BROWSER_PLUGIN, test x$enable_browser_plugin = xyes)
AC_MSG_CHECKING([for bluetooth support]) PKG_CHECK_MODULES(BLUETOOTH, gnome-bluetooth-1.0 >= 3.9.0,
PKG_CHECK_EXISTS([gnome-bluetooth-1.0 >= 3.9.0], [AC_DEFINE([HAVE_BLUETOOTH],[1],[Define if you have libgnome-bluetooth-applet])
[BLUETOOTH_DIR=`$PKG_CONFIG --variable=applet_libdir gnome-bluetooth-1.0` AC_SUBST([HAVE_BLUETOOTH],[1])],
BLUETOOTH_LIBS=`$PKG_CONFIG --variable=applet_libs gnome-bluetooth-1.0`
AC_SUBST([BLUETOOTH_LIBS],["$BLUETOOTH_LIBS"])
AC_SUBST([BLUETOOTH_DIR],["$BLUETOOTH_DIR"])
AC_DEFINE_UNQUOTED([BLUETOOTH_DIR],["$BLUETOOTH_DIR"],[Path to installed GnomeBluetooth typelib and library])
AC_DEFINE([HAVE_BLUETOOTH],[1],[Define if you have libgnome-bluetooth-applet])
AC_SUBST([HAVE_BLUETOOTH],[1])
AC_MSG_RESULT([yes])],
[AC_DEFINE([HAVE_BLUETOOTH],[0]) [AC_DEFINE([HAVE_BLUETOOTH],[0])
AC_SUBST([HAVE_BLUETOOTH],[0]) AC_SUBST([HAVE_BLUETOOTH],[0])])
AC_MSG_RESULT([no])])
PKG_CHECK_MODULES(CALENDAR_SERVER, libecal-1.2 >= $LIBECAL_MIN_VERSION libedataserver-1.2 >= $LIBEDATASERVER_MIN_VERSION gio-2.0) PKG_CHECK_MODULES(CALENDAR_SERVER, libecal-1.2 >= $LIBECAL_MIN_VERSION libedataserver-1.2 >= $LIBEDATASERVER_MIN_VERSION gio-2.0)
AC_SUBST(CALENDAR_SERVER_CFLAGS) AC_SUBST(CALENDAR_SERVER_CFLAGS)

View File

@ -13,12 +13,12 @@
</key> </key>
<key name="enabled-extensions" type="as"> <key name="enabled-extensions" type="as">
<default>[]</default> <default>[]</default>
<_summary>Uuids of extensions to enable</_summary> <_summary>UUIDs of extensions to enable</_summary>
<_description> <_description>
GNOME Shell extensions have a uuid property; this key lists extensions GNOME Shell extensions have a UUID property; this key lists extensions
which should be loaded. Any extension that wants to be loaded needs which should be loaded. Any extension that wants to be loaded needs
to be in this list. You can also manipulate this list with the to be in this list. You can also manipulate this list with the
EnableExtension and DisableExtension DBus methods on org.gnome.Shell. EnableExtension and DisableExtension D-Bus methods on org.gnome.Shell.
</_description> </_description>
</key> </key>
<key name="favorite-apps" type="as"> <key name="favorite-apps" type="as">
@ -29,14 +29,6 @@
will be displayed in the favorites area. will be displayed in the favorites area.
</_description> </_description>
</key> </key>
<key name="app-folder-categories" type="as">
<default>[ 'Utilities', 'Sundry' ]</default>
<_summary>List of categories that should be displayed as folders</_summary>
<_description>
Each category name in this list will be represented as folder in the
application view, rather than being displayed inline in the main view.
</_description>
</key>
<key name="app-picker-view" type="u"> <key name="app-picker-view" type="u">
<default>0</default> <default>0</default>
<summary>App Picker View</summary> <summary>App Picker View</summary>
@ -54,10 +46,10 @@
</key> </key>
<key name="always-show-log-out" type="b"> <key name="always-show-log-out" type="b">
<default>false</default> <default>false</default>
<_summary>Always show the 'Log out' menuitem in the user menu.</_summary> <_summary>Always show the 'Log out' menu item in the user menu.</_summary>
<_description> <_description>
This key overrides the automatic hiding of the 'Log out' This key overrides the automatic hiding of the 'Log out'
menuitem in single-user, single-session situations. menu item in single-user, single-session situations.
</_description> </_description>
</key> </key>
<key name="remember-mount-password" type="b"> <key name="remember-mount-password" type="b">
@ -124,6 +116,11 @@
Keybinding to focus the active notification. Keybinding to focus the active notification.
</_description> </_description>
</key> </key>
<key name="pause-resume-tweens" type="as">
<default>[]</default>
<summary>Keybinding that pauses and resumes all running tweens, for debugging purposes</summary>
<description></description>
</key>
</schema> </schema>
<schema id="org.gnome.shell.keyboard" path="/org/gnome/shell/keyboard/" <schema id="org.gnome.shell.keyboard" path="/org/gnome/shell/keyboard/"

View File

@ -1944,6 +1944,7 @@ StScrollBar StButton#vhandle:active {
.end-session-dialog-description:rtl { .end-session-dialog-description:rtl {
padding-right: 17px; padding-right: 17px;
text-align: right;
} }
.end-session-dialog-logout-icon { .end-session-dialog-logout-icon {
@ -1976,6 +1977,10 @@ StScrollBar StButton#vhandle:active {
font-weight: bold; font-weight: bold;
} }
.end-session-dialog-list-header:rtl {
text-align: right;
}
.end-session-dialog-app-list-item, .end-session-dialog-app-list-item,
.end-session-dialog-session-list-item { .end-session-dialog-session-list-item {
spacing: 1em; spacing: 1em;
@ -2095,6 +2100,10 @@ StScrollBar StButton#vhandle:active {
color: #666666; color: #666666;
} }
.prompt-dialog-description:rtl {
text-align: right;
}
.prompt-dialog-password-box { .prompt-dialog-password-box {
spacing: 1em; spacing: 1em;
padding-bottom: 1em; padding-bottom: 1em;
@ -2321,6 +2330,8 @@ StScrollBar StButton#vhandle:active {
.login-dialog-user-list-item { .login-dialog-user-list-item {
border-radius: 5px; border-radius: 5px;
padding: .2em; padding: .2em;
color: #bfbfbf;
text-shadow: black 0px 2px 2px;
} }
.login-dialog-user-list-item:ltr { .login-dialog-user-list-item:ltr {
@ -2331,24 +2342,6 @@ StScrollBar StButton#vhandle:active {
padding-left: 1em; padding-left: 1em;
} }
.login-dialog-user-list-item .login-dialog-user-list-item-name {
font-size: 20px;
padding-left: 18px;
font-weight: bold;
}
.login-dialog-user-list:expanded .login-dialog-user-list-item {
color: #bfbfbf;
}
.login-dialog-user-list-item,
.login-dialog-user-list-item:hover .login-dialog-user-list-item-name,
.login-dialog-user-list:expanded .login-dialog-user-list-item:focus .login-dialog-user-list-item-name,
.login-dialog-user-list:expanded .login-dialog-user-list-item:logged-in {
color: #bfbfbf;
text-shadow: black 0px 2px 2px;
}
.login-dialog-user-list-item:hover { .login-dialog-user-list-item:hover {
background-color: rgba(255,255,255,0.1); background-color: rgba(255,255,255,0.1);
} }
@ -2375,13 +2368,6 @@ StScrollBar StButton#vhandle:active {
background-color: #8b8b8b; background-color: #8b8b8b;
} }
.login-dialog-user-list-item-icon {
border: 2px solid #8b8b8b;
border-radius: 3px;
width: 64px;
height: 64px;
}
.login-dialog-not-listed-label { .login-dialog-not-listed-label {
font-size: 10.5pt; font-size: 10.5pt;
font-weight: bold; font-weight: bold;
@ -2432,6 +2418,7 @@ StScrollBar StButton#vhandle:active {
} }
.login-dialog-session-list-button:hover, .login-dialog-session-list-button:hover,
.login-dialog-session-list-button:focus,
.login-dialog-session-list-button:active { .login-dialog-session-list-button:active {
color: white; color: white;
} }
@ -2501,11 +2488,18 @@ StScrollBar StButton#vhandle:active {
font-size: 20px; font-size: 20px;
font-weight: bold; font-weight: bold;
text-align: left; text-align: left;
padding-left: 18px;
color:white; color:white;
text-shadow: black 0px 4px 3px 0px; text-shadow: black 0px 4px 3px 0px;
} }
.user-widget-label:ltr {
padding-left: 18px;
}
.user-widget-label:rtl {
padding-right: 18px;
}
/* Screen shield */ /* Screen shield */
#panel.lock-screen, #panel.lock-screen,
@ -2518,7 +2512,7 @@ StScrollBar StButton#vhandle:active {
box-shadow: 0px 4px 8px rgba(0,0,0,0.9); box-shadow: 0px 4px 8px rgba(0,0,0,0.9);
} }
#lockDialogGroup { #systemGroup {
background: #2e3436 url(noise-texture.png); background: #2e3436 url(noise-texture.png);
background-repeat: repeat; background-repeat: repeat;
} }
@ -2630,4 +2624,5 @@ StScrollBar StButton#vhandle:active {
.background-menu { .background-menu {
-boxpointer-gap: 4px; -boxpointer-gap: 4px;
-arrow-rise: 0px;
} }

View File

@ -112,7 +112,7 @@ expand_content_files=
# e.g. GTKDOC_CFLAGS=-I$(top_srcdir) -I$(top_builddir) $(GTK_DEBUG_FLAGS) # e.g. GTKDOC_CFLAGS=-I$(top_srcdir) -I$(top_builddir) $(GTK_DEBUG_FLAGS)
# e.g. GTKDOC_LIBS=$(top_builddir)/gtk/$(gtktargetlib) # e.g. GTKDOC_LIBS=$(top_builddir)/gtk/$(gtktargetlib)
GTKDOC_CFLAGS=$(GNOME_SHELL_CFLAGS) GTKDOC_CFLAGS=$(GNOME_SHELL_CFLAGS)
GTKDOC_LIBS=$(GNOME_SHELL_LIBS) $(BLUETOOTH_LIBS) $(top_builddir)/src/libgnome-shell-menu.la $(top_builddir)/src/libgnome-shell-base.la $(top_builddir)/src/libgnome-shell.la GTKDOC_LIBS=$(GNOME_SHELL_LIBS) $(top_builddir)/src/libgnome-shell-menu.la $(top_builddir)/src/libgnome-shell-base.la $(top_builddir)/src/libgnome-shell.la
# This includes the standard gtk-doc make rules, copied by gtkdocize. # This includes the standard gtk-doc make rules, copied by gtkdocize.
include $(top_srcdir)/gtk-doc.make include $(top_srcdir)/gtk-doc.make

View File

@ -80,6 +80,7 @@ const AuthPrompt = new Lang.Class({
if (event.get_key_symbol() == Clutter.KEY_Escape) { if (event.get_key_symbol() == Clutter.KEY_Escape) {
this.cancel(); this.cancel();
} }
return Clutter.EVENT_PROPAGATE;
})); }));
this._userWell = new St.Bin({ x_fill: true, this._userWell = new St.Bin({ x_fill: true,
@ -93,7 +94,7 @@ const AuthPrompt = new Lang.Class({
this.actor.add(this._label, this.actor.add(this._label,
{ expand: true, { expand: true,
x_fill: true, x_fill: false,
y_fill: true, y_fill: true,
x_align: St.Align.START }); x_align: St.Align.START });
this._entry = new St.Entry({ style_class: 'login-dialog-prompt-entry', this._entry = new St.Entry({ style_class: 'login-dialog-prompt-entry',
@ -111,7 +112,7 @@ const AuthPrompt = new Lang.Class({
this._message = new St.Label({ opacity: 0, this._message = new St.Label({ opacity: 0,
styleClass: 'login-dialog-message' }); styleClass: 'login-dialog-message' });
this._message.clutter_text.line_wrap = true; this._message.clutter_text.line_wrap = true;
this.actor.add(this._message, { x_fill: true, y_align: St.Align.START }); this.actor.add(this._message, { x_fill: false, x_align: St.Align.START, y_align: St.Align.START });
this._buttonBox = new St.BoxLayout({ style_class: 'login-dialog-button-box', this._buttonBox = new St.BoxLayout({ style_class: 'login-dialog-button-box',
vertical: false }); vertical: false });
@ -263,10 +264,8 @@ const AuthPrompt = new Lang.Class({
}, },
_onReset: function() { _onReset: function() {
if (this.verificationStatus != AuthPromptStatus.VERIFICATION_SUCCEEDED) { this.verificationStatus = AuthPromptStatus.NOT_VERIFYING;
this.verificationStatus = AuthPromptStatus.NOT_VERIFYING; this.reset();
this.reset();
}
}, },
addActorToDefaultButtonWell: function(actor) { addActorToDefaultButtonWell: function(actor) {

View File

@ -13,9 +13,7 @@
* GNU General Public License for more details. * GNU General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software * along with this program; if not, see <http://www.gnu.org/licenses/>.
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*/ */
const Lang = imports.lang; const Lang = imports.lang;

View File

@ -13,9 +13,7 @@
* GNU General Public License for more details. * GNU General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software * along with this program; if not, see <http://www.gnu.org/licenses/>.
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*/ */
const AccountsService = imports.gi.AccountsService; const AccountsService = imports.gi.AccountsService;
@ -276,7 +274,7 @@ const SessionMenuButton = new Lang.Class({
this.actor = new St.Bin({ child: this._button }); this.actor = new St.Bin({ child: this._button });
this._menu = new PopupMenu.PopupMenu(this._button, 0, St.Side.TOP); this._menu = new PopupMenu.PopupMenu(this._button, 0, St.Side.TOP);
Main.uiGroup.add_actor(this._menu.actor); Main.layoutManager.menuGroup.add_actor(this._menu.actor);
this._menu.actor.hide(); this._menu.actor.hide();
this._menu.connect('open-state-changed', this._menu.connect('open-state-changed',
@ -456,18 +454,6 @@ const LoginDialog = new Lang.Class({
this.actor.add_child(this._logoBin); this.actor.add_child(this._logoBin);
this._updateLogo(); this._updateLogo();
if (!this._userManager.is_loaded)
this._userManagerLoadedId = this._userManager.connect('notify::is-loaded',
Lang.bind(this, function() {
if (this._userManager.is_loaded) {
this._loadUserList();
this._userManager.disconnect(this._userManagerLoadedId);
this._userManagerLoadedId = 0;
}
}));
else
this._loadUserList();
this._userList.connect('activate', this._userList.connect('activate',
Lang.bind(this, function(userList, item) { Lang.bind(this, function(userList, item) {
this._onUserListActivated(item); this._onUserListActivated(item);
@ -483,6 +469,18 @@ const LoginDialog = new Lang.Class({
this._sessionMenuButton.actor.show(); this._sessionMenuButton.actor.show();
this._authPrompt.addActorToDefaultButtonWell(this._sessionMenuButton.actor); this._authPrompt.addActorToDefaultButtonWell(this._sessionMenuButton.actor);
if (!this._userManager.is_loaded)
this._userManagerLoadedId = this._userManager.connect('notify::is-loaded',
Lang.bind(this, function() {
if (this._userManager.is_loaded) {
this._loadUserList();
this._userManager.disconnect(this._userManagerLoadedId);
this._userManagerLoadedId = 0;
}
}));
else
GLib.idle_add(GLib.PRIORITY_DEFAULT, Lang.bind(this, this._loadUserList));
}, },
_updateDisableUserList: function() { _updateDisableUserList: function() {
@ -644,7 +642,7 @@ const LoginDialog = new Lang.Class({
onComplete: function() { onComplete: function() {
Mainloop.idle_add(Lang.bind(this, function() { Mainloop.idle_add(Lang.bind(this, function() {
this._greeter.call_start_session_when_ready_sync(serviceName, true, null); this._greeter.call_start_session_when_ready_sync(serviceName, true, null);
return false; return GLib.SOURCE_REMOVE;
})); }));
}, },
onCompleteScope: this }); onCompleteScope: this });
@ -699,6 +697,7 @@ const LoginDialog = new Lang.Class({
function() { function() {
this._timedLoginAnimationTime -= _TIMED_LOGIN_IDLE_THRESHOLD; this._timedLoginAnimationTime -= _TIMED_LOGIN_IDLE_THRESHOLD;
hold.release(); hold.release();
return GLib.SOURCE_REMOVE;
}); });
return hold; return hold;
}, },
@ -763,7 +762,7 @@ const LoginDialog = new Lang.Class({
global.stage.connect('captured-event', global.stage.connect('captured-event',
Lang.bind(this, function(actor, event) { Lang.bind(this, function(actor, event) {
if (this._timedLoginDelay == undefined) if (this._timedLoginDelay == undefined)
return false; return Clutter.EVENT_PROPAGATE;
if (event.type() == Clutter.EventType.KEY_PRESS || if (event.type() == Clutter.EventType.KEY_PRESS ||
event.type() == Clutter.EventType.BUTTON_PRESS) { event.type() == Clutter.EventType.BUTTON_PRESS) {
@ -776,7 +775,7 @@ const LoginDialog = new Lang.Class({
this._resetTimedLogin(); this._resetTimedLogin();
} }
return false; return Clutter.EVENT_PROPAGATE;
})); }));
}, },
@ -885,6 +884,10 @@ const LoginDialog = new Lang.Class({
Main.ctrlAltTabManager.removeGroup(this.dialogLayout); Main.ctrlAltTabManager.removeGroup(this.dialogLayout);
}, },
cancel: function() {
this._authPrompt.cancel();
},
addCharacter: function(unichar) { addCharacter: function(unichar) {
this._authPrompt.addCharacter(unichar); this._authPrompt.addCharacter(unichar);
}, },

View File

@ -250,6 +250,7 @@ const ShellUserVerifier = new Lang.Class({
Lang.bind(this, function() { Lang.bind(this, function() {
this._messageQueueTimeoutId = 0; this._messageQueueTimeoutId = 0;
this._queueMessageTimeout(); this._queueMessageTimeout();
return GLib.SOURCE_REMOVE;
})); }));
}, },

View File

@ -8,12 +8,13 @@
<file>gdm/oVirt.js</file> <file>gdm/oVirt.js</file>
<file>gdm/realmd.js</file> <file>gdm/realmd.js</file>
<file>gdm/util.js</file> <file>gdm/util.js</file>
<file>extensionPrefs/main.js</file> <file>extensionPrefs/main.js</file>
<file>misc/config.js</file> <file>misc/config.js</file>
<file>misc/extensionUtils.js</file> <file>misc/extensionUtils.js</file>
<file>misc/fileUtils.js</file> <file>misc/fileUtils.js</file>
<file>misc/gnomeSession.js</file> <file>misc/gnomeSession.js</file>
<file>misc/hash.js</file>
<file>misc/history.js</file> <file>misc/history.js</file>
<file>misc/jsParse.js</file> <file>misc/jsParse.js</file>
<file>misc/loginManager.js</file> <file>misc/loginManager.js</file>
@ -22,7 +23,9 @@
<file>misc/params.js</file> <file>misc/params.js</file>
<file>misc/smartcardManager.js</file> <file>misc/smartcardManager.js</file>
<file>misc/util.js</file> <file>misc/util.js</file>
<file>perf/core.js</file> <file>perf/core.js</file>
<file>ui/altTab.js</file> <file>ui/altTab.js</file>
<file>ui/animation.js</file> <file>ui/animation.js</file>
<file>ui/appDisplay.js</file> <file>ui/appDisplay.js</file>
@ -37,12 +40,12 @@
<file>ui/dateMenu.js</file> <file>ui/dateMenu.js</file>
<file>ui/dnd.js</file> <file>ui/dnd.js</file>
<file>ui/endSessionDialog.js</file> <file>ui/endSessionDialog.js</file>
<file>ui/extensionSystem.js</file>
<file>ui/extensionDownloader.js</file>
<file>ui/environment.js</file> <file>ui/environment.js</file>
<file>ui/extensionDownloader.js</file>
<file>ui/extensionSystem.js</file>
<file>ui/focusCaretTracker.js</file> <file>ui/focusCaretTracker.js</file>
<file>ui/ibusCandidatePopup.js</file>
<file>ui/grabHelper.js</file> <file>ui/grabHelper.js</file>
<file>ui/ibusCandidatePopup.js</file>
<file>ui/iconGrid.js</file> <file>ui/iconGrid.js</file>
<file>ui/keyboard.js</file> <file>ui/keyboard.js</file>
<file>ui/layout.js</file> <file>ui/layout.js</file>
@ -53,11 +56,6 @@
<file>ui/main.js</file> <file>ui/main.js</file>
<file>ui/messageTray.js</file> <file>ui/messageTray.js</file>
<file>ui/modalDialog.js</file> <file>ui/modalDialog.js</file>
<file>ui/separator.js</file>
<file>ui/sessionMode.js</file>
<file>ui/shellEntry.js</file>
<file>ui/shellMountOperation.js</file>
<file>ui/slider.js</file>
<file>ui/notificationDaemon.js</file> <file>ui/notificationDaemon.js</file>
<file>ui/osdWindow.js</file> <file>ui/osdWindow.js</file>
<file>ui/overview.js</file> <file>ui/overview.js</file>
@ -66,25 +64,20 @@
<file>ui/panelMenu.js</file> <file>ui/panelMenu.js</file>
<file>ui/pointerWatcher.js</file> <file>ui/pointerWatcher.js</file>
<file>ui/popupMenu.js</file> <file>ui/popupMenu.js</file>
<file>ui/remoteSearch.js</file>
<file>ui/remoteMenu.js</file> <file>ui/remoteMenu.js</file>
<file>ui/remoteSearch.js</file>
<file>ui/runDialog.js</file> <file>ui/runDialog.js</file>
<file>ui/screenShield.js</file>
<file>ui/screencast.js</file> <file>ui/screencast.js</file>
<file>ui/screenshot.js</file> <file>ui/screenshot.js</file>
<file>ui/screenShield.js</file>
<file>ui/scripting.js</file> <file>ui/scripting.js</file>
<file>ui/search.js</file> <file>ui/search.js</file>
<file>ui/separator.js</file>
<file>ui/sessionMode.js</file>
<file>ui/shellDBus.js</file> <file>ui/shellDBus.js</file>
<file>ui/status/accessibility.js</file> <file>ui/shellEntry.js</file>
<file>ui/status/brightness.js</file> <file>ui/shellMountOperation.js</file>
<file>ui/status/keyboard.js</file> <file>ui/slider.js</file>
<file>ui/status/network.js</file>
<file>ui/status/power.js</file>
<file>ui/status/rfkill.js</file>
<file>ui/status/volume.js</file>
<file>ui/status/bluetooth.js</file>
<file>ui/status/screencast.js</file>
<file>ui/status/system.js</file>
<file>ui/switcherPopup.js</file> <file>ui/switcherPopup.js</file>
<file>ui/tweener.js</file> <file>ui/tweener.js</file>
<file>ui/unlockDialog.js</file> <file>ui/unlockDialog.js</file>
@ -93,10 +86,11 @@
<file>ui/windowAttentionHandler.js</file> <file>ui/windowAttentionHandler.js</file>
<file>ui/windowManager.js</file> <file>ui/windowManager.js</file>
<file>ui/workspace.js</file> <file>ui/workspace.js</file>
<file>ui/workspaceSwitcherPopup.js</file>
<file>ui/workspaceThumbnail.js</file> <file>ui/workspaceThumbnail.js</file>
<file>ui/workspacesView.js</file> <file>ui/workspacesView.js</file>
<file>ui/workspaceSwitcherPopup.js</file>
<file>ui/xdndHandler.js</file> <file>ui/xdndHandler.js</file>
<file>ui/components/__init__.js</file> <file>ui/components/__init__.js</file>
<file>ui/components/autorunManager.js</file> <file>ui/components/autorunManager.js</file>
<file>ui/components/automountManager.js</file> <file>ui/components/automountManager.js</file>
@ -104,5 +98,17 @@
<file>ui/components/polkitAgent.js</file> <file>ui/components/polkitAgent.js</file>
<file>ui/components/telepathyClient.js</file> <file>ui/components/telepathyClient.js</file>
<file>ui/components/keyring.js</file> <file>ui/components/keyring.js</file>
<file>ui/status/accessibility.js</file>
<file>ui/status/brightness.js</file>
<file>ui/status/location.js</file>
<file>ui/status/keyboard.js</file>
<file>ui/status/network.js</file>
<file>ui/status/power.js</file>
<file>ui/status/rfkill.js</file>
<file>ui/status/volume.js</file>
<file>ui/status/bluetooth.js</file>
<file>ui/status/screencast.js</file>
<file>ui/status/system.js</file>
</gresource> </gresource>
</gresources> </gresources>

View File

@ -5,26 +5,6 @@ const GLib = imports.gi.GLib;
const Lang = imports.lang; const Lang = imports.lang;
const Params = imports.misc.params; const Params = imports.misc.params;
function listDirAsync(file, callback) {
let allFiles = [];
file.enumerate_children_async('standard::name,standard::type',
Gio.FileQueryInfoFlags.NONE,
GLib.PRIORITY_LOW, null, function (obj, res) {
let enumerator = obj.enumerate_children_finish(res);
function onNextFileComplete(obj, res) {
let files = obj.next_files_finish(res);
if (files.length) {
allFiles = allFiles.concat(files);
enumerator.next_files_async(100, GLib.PRIORITY_LOW, null, onNextFileComplete);
} else {
enumerator.close(null);
callback(allFiles);
}
}
enumerator.next_files_async(100, GLib.PRIORITY_LOW, null, onNextFileComplete);
});
}
function collectFromDatadirs(subdir, includeUserDir, processFile) { function collectFromDatadirs(subdir, includeUserDir, processFile) {
let dataDirs = GLib.get_system_data_dirs(); let dataDirs = GLib.get_system_data_dirs();
if (includeUserDir) if (includeUserDir)

View File

@ -1,144 +0,0 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
const Lang = imports.lang;
const System = imports.system;
const Params = imports.misc.params;
// This is an implementation of EcmaScript SameValue algorithm,
// which returns true if two values are not observably distinguishable.
// It was taken from http://wiki.ecmascript.org/doku.php?id=harmony:egal
//
// In the future, we may want to use the 'is' operator instead.
function _sameValue(x, y) {
if (x === y) {
// 0 === -0, but they are not identical
return x !== 0 || 1 / x === 1 / y;
}
// NaN !== NaN, but they are identical.
// NaNs are the only non-reflexive value, i.e., if x !== x,
// then x is a NaN.
// isNaN is broken: it converts its argument to number, so
// isNaN("foo") => true
return x !== x && y !== y;
}
const _hashers = {
object: function(o) { return o ? System.addressOf(o) : 'null'; },
function: function(f) { return System.addressOf(f); },
string: function(s) { return s; },
number: function(n) { return String(n); },
undefined: function() { return 'undefined'; },
};
/* Map is meant to be similar in usage to ES6 Map, which is
described at http://wiki.ecmascript.org/doku.php?id=harmony:simple_maps_and_sets,
without requiring more than ES5 + Gjs extensions.
Known differences from other implementations:
Polyfills around the web usually implement HashMaps for
primitive values and reversed WeakMaps for object keys,
but we want real maps with real O(1) semantics in all cases,
and the easiest way is to have different hashers for different
types.
Known differences from the ES6 specification:
- Map is a Lang.Class, not a ES6 class, so inheritance,
prototype, sealing, etc. work differently.
- items(), keys() and values() don't return iterators,
they return actual arrays, so they incur a full copy everytime
they're called, and they don't see changes if you mutate
the table while iterating
(admittedly, the ES6 spec is a bit unclear on this, and
the reference code would just blow up)
*/
const Map = new Lang.Class({
Name: 'Map',
_init: function(iterable) {
this._pool = { };
this._size = 0;
if (iterable) {
for (let i = 0; i < iterable.length; i++) {
let [key, value] = iterable[i];
this.set(key, value);
}
}
},
_hashKey: function(key) {
let type = typeof(key);
return type + ':' + _hashers[type](key);
},
_internalGet: function(key) {
let hash = this._hashKey(key);
let node = this._pool[hash];
if (node && _sameValue(node.key, key))
return [true, node.value];
else
return [false, null];
},
get: function(key) {
return this._internalGet(key)[1];
},
has: function(key) {
return this._internalGet(key)[0];
},
set: function(key, value) {
let hash = this._hashKey(key);
let node = this._pool[hash];
if (node) {
node.key = key;
node.value = value;
} else {
this._pool[hash] = { key: key, value: value };
this._size++;
}
},
delete: function(key) {
let hash = this._hashKey(key);
let node = this._pool[hash];
if (node && _sameValue(node.key, key)) {
delete this._pool[hash];
this._size--;
return [node.key, node.value];
} else {
return [null, null];
}
},
keys: function() {
let pool = this._pool;
return Object.getOwnPropertyNames(pool).map(function(hash) {
return pool[hash].key;
});
},
values: function() {
let pool = this._pool;
return Object.getOwnPropertyNames(pool).map(function(hash) {
return pool[hash].value;
});
},
items: function() {
let pool = this._pool;
return Object.getOwnPropertyNames(pool).map(function(hash) {
return [pool[hash].key, pool[hash].value];
});
},
size: function() {
return this._size;
},
});

View File

@ -89,7 +89,7 @@ const HistoryManager = new Lang.Class({
} else if (symbol == Clutter.KEY_Down) { } else if (symbol == Clutter.KEY_Down) {
return this._setNextItem(entry.get_text()); return this._setNextItem(entry.get_text());
} }
return false; return Clutter.EVENT_PROPAGATE;
}, },
_indexChanged: function() { _indexChanged: function() {

View File

@ -89,7 +89,7 @@ function spawnApp(argv) {
let app = Gio.AppInfo.create_from_commandline(argv.join(' '), null, let app = Gio.AppInfo.create_from_commandline(argv.join(' '), null,
Gio.AppInfoCreateFlags.SUPPORTS_STARTUP_NOTIFICATION); Gio.AppInfoCreateFlags.SUPPORTS_STARTUP_NOTIFICATION);
let context = global.create_app_launch_context(); let context = global.create_app_launch_context(0, -1);
app.launch([], context); app.launch([], context);
} catch(err) { } catch(err) {
_handleSpawnError(argv[0], err); _handleSpawnError(argv[0], err);
@ -153,7 +153,7 @@ function trySpawnCommandLine(command_line) {
} }
function _handleSpawnError(command, err) { function _handleSpawnError(command, err) {
let title = _("Execution of '%s' failed:").format(command); let title = _("Execution of %s failed:").format(command);
Main.notifyError(title, err.message); Main.notifyError(title, err.message);
} }

View File

@ -2,6 +2,7 @@
const Clutter = imports.gi.Clutter; const Clutter = imports.gi.Clutter;
const Gio = imports.gi.Gio; const Gio = imports.gi.Gio;
const GLib = imports.gi.GLib;
const Lang = imports.lang; const Lang = imports.lang;
const Mainloop = imports.mainloop; const Mainloop = imports.mainloop;
const Meta = imports.gi.Meta; const Meta = imports.gi.Meta;
@ -312,7 +313,7 @@ const AppSwitcherPopup = new Lang.Class({
this._createThumbnails(); this._createThumbnails();
this._thumbnailTimeoutId = 0; this._thumbnailTimeoutId = 0;
this._thumbnailsFocused = false; this._thumbnailsFocused = false;
return false; return GLib.SOURCE_REMOVE;
}, },
_destroyThumbnails : function() { _destroyThumbnails : function() {
@ -459,9 +460,10 @@ const AppSwitcher = new Lang.Class({
appIcon.cachedWindows = allWindows.filter(function(w) { appIcon.cachedWindows = allWindows.filter(function(w) {
return windowTracker.get_window_app (w) == appIcon.app; return windowTracker.get_window_app (w) == appIcon.app;
}); });
if (workspace == null || appIcon.cachedWindows.length > 0) { if (appIcon.cachedWindows.length > 0)
this._addIcon(appIcon); this._addIcon(appIcon);
} else if (workspace == null)
throw new Error('%s appears to be running, but doesn\'t have any windows'.format(appIcon.app.get_name()));
} }
this._curApp = -1; this._curApp = -1;
@ -547,7 +549,7 @@ const AppSwitcher = new Lang.Class({
Lang.bind(this, function () { Lang.bind(this, function () {
this._enterItem(index); this._enterItem(index);
this._mouseTimeOutId = 0; this._mouseTimeOutId = 0;
return false; return GLib.SOURCE_REMOVE;
})); }));
} else } else
this._itemEntered(index); this._itemEntered(index);

View File

@ -1,5 +1,6 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
const GLib = imports.gi.GLib;
const Lang = imports.lang; const Lang = imports.lang;
const Mainloop = imports.mainloop; const Mainloop = imports.mainloop;
const St = imports.gi.St; const St = imports.gi.St;
@ -59,7 +60,7 @@ const Animation = new Lang.Class({
_update: function() { _update: function() {
this._showFrame(this._frame + 1); this._showFrame(this._frame + 1);
return true; return GLib.SOURCE_CONTINUE;
}, },
_animationsLoaded: function() { _animationsLoaded: function() {

View File

@ -5,7 +5,6 @@ const Gio = imports.gi.Gio;
const GLib = imports.gi.GLib; const GLib = imports.gi.GLib;
const GObject = imports.gi.GObject; const GObject = imports.gi.GObject;
const Gtk = imports.gi.Gtk; const Gtk = imports.gi.Gtk;
const GMenu = imports.gi.GMenu;
const Shell = imports.gi.Shell; const Shell = imports.gi.Shell;
const Lang = imports.lang; const Lang = imports.lang;
const Signals = imports.signals; const Signals = imports.signals;
@ -47,24 +46,45 @@ const INDICATORS_ANIMATION_MAX_TIME = 0.75;
const PAGE_SWITCH_TRESHOLD = 0.2; const PAGE_SWITCH_TRESHOLD = 0.2;
const PAGE_SWITCH_TIME = 0.3; const PAGE_SWITCH_TIME = 0.3;
// Recursively load a GMenuTreeDirectory; we could put this in ShellAppSystem too function _getCategories(info) {
function _loadCategory(dir, view) { let categoriesStr = info.get_categories();
let iter = dir.iter(); if (!categoriesStr)
let appSystem = Shell.AppSystem.get_default(); return [];
let nextType; return categoriesStr.split(';');
while ((nextType = iter.next()) != GMenu.TreeItemType.INVALID) { }
if (nextType == GMenu.TreeItemType.ENTRY) {
let entry = iter.get_entry(); function _isTerminal(app) {
let appInfo = entry.get_app_info(); let info = app.get_app_info();
let app = appSystem.lookup_app(entry.get_desktop_file_id()); if (!info)
if (appInfo.should_show()) return false;
view.addApp(app); let categories = _getCategories(info);
} else if (nextType == GMenu.TreeItemType.DIRECTORY) { return categories.indexOf('TerminalEmulator') > -1;
let itemDir = iter.get_directory(); }
_loadCategory(itemDir, view);
function _listsIntersect(a, b) {
for (let itemA of a)
if (b.indexOf(itemA) >= 0)
return true;
return false;
}
function _getFolderName(folder) {
let name = folder.get_string('name');
if (folder.get_boolean('translate')) {
let keyfile = new GLib.KeyFile();
let path = 'desktop-directories/' + name;
try {
keyfile.load_from_data_dirs(path, GLib.KeyFileFlags.NONE);
name = keyfile.get_locale_string('Desktop Entry', 'Name', null);
} catch(e) {
return name;
} }
} }
};
return name;
}
const BaseAppView = new Lang.Class({ const BaseAppView = new Lang.Class({
Name: 'BaseAppView', Name: 'BaseAppView',
@ -97,40 +117,33 @@ const BaseAppView = new Lang.Class({
this._allItems = []; this._allItems = [];
}, },
_getItemId: function(item) { _redisplay: function() {
throw new Error('Not implemented'); this.removeAll();
this._loadApps();
}, },
_createItemIcon: function(item) { getAllItems: function() {
throw new Error('Not implemented'); return this._allItems;
},
addItem: function(icon) {
let id = icon.id;
if (this._items[id] !== undefined)
return;
this._allItems.push(icon);
this._items[id] = icon;
}, },
_compareItems: function(a, b) { _compareItems: function(a, b) {
throw new Error('Not implemented'); return a.name.localeCompare(b.name);
},
_addItem: function(item) {
let id = this._getItemId(item);
if (this._items[id] !== undefined)
return null;
let itemIcon = this._createItemIcon(item);
this._allItems.push(item);
this._items[id] = itemIcon;
return itemIcon;
}, },
loadGrid: function() { loadGrid: function() {
this._allItems.sort(Lang.bind(this, this._compareItems)); this._allItems.sort(this._compareItems);
this._allItems.forEach(Lang.bind(this, function(item) {
for (let i = 0; i < this._allItems.length; i++) { this._grid.addItem(item);
let id = this._getItemId(this._allItems[i]); }));
if (!id)
continue;
this._grid.addItem(this._items[id]);
}
this.emit('view-loaded'); this.emit('view-loaded');
}, },
@ -281,7 +294,7 @@ const AllView = new Lang.Class({
this._pageIndicators.actor.connect('scroll-event', Lang.bind(this, this._onScroll)); this._pageIndicators.actor.connect('scroll-event', Lang.bind(this, this._onScroll));
this.actor.add_actor(this._pageIndicators.actor); this.actor.add_actor(this._pageIndicators.actor);
this._folderIcons = []; this.folderIcons = [];
this._stack = new St.Widget({ layout_manager: new Clutter.BinLayout() }); this._stack = new St.Widget({ layout_manager: new Clutter.BinLayout() });
let box = new St.BoxLayout({ vertical: true }); let box = new St.BoxLayout({ vertical: true });
@ -346,6 +359,76 @@ const AllView = new Lang.Class({
this._keyPressEventId = 0; this._keyPressEventId = 0;
} }
})); }));
this._redisplayWorkId = Main.initializeDeferredWork(this.actor, Lang.bind(this, this._redisplay));
Shell.AppSystem.get_default().connect('installed-changed', Lang.bind(this, function() {
Main.queueDeferredWork(this._redisplayWorkId);
}));
this._folderSettings = new Gio.Settings({ schema: 'org.gnome.desktop.app-folders' });
this._folderSettings.connect('changed::folder-children', Lang.bind(this, function() {
Main.queueDeferredWork(this._redisplayWorkId);
}));
},
removeAll: function() {
this.folderIcons = [];
this.parent();
},
_itemNameChanged: function(item) {
// If an item's name changed, we can pluck it out of where it's
// supposed to be and reinsert it where it's sorted.
let oldIdx = this._allItems.indexOf(item);
this._allItems.splice(oldIdx, 1);
let newIdx = Util.insertSorted(this._allItems, item, this._compareItems);
this._grid.removeItem(item);
this._grid.addItem(item, newIdx);
},
_refilterApps: function() {
this._allItems.forEach(function(icon) {
if (icon instanceof AppIcon)
icon.actor.visible = true;
});
this.folderIcons.forEach(Lang.bind(this, function(folder) {
let folderApps = folder.getAppIds();
folderApps.forEach(Lang.bind(this, function(appId) {
let appIcon = this._items[appId];
appIcon.actor.visible = false;
}));
}));
},
_loadApps: function() {
let apps = Gio.AppInfo.get_all().filter(function(appInfo) {
return appInfo.should_show();
}).map(function(app) {
return app.get_id();
});
let appSys = Shell.AppSystem.get_default();
let folders = this._folderSettings.get_strv('folder-children');
folders.forEach(Lang.bind(this, function(id) {
let path = this._folderSettings.path + 'folders/' + id + '/';
let icon = new FolderIcon(id, path, this);
icon.connect('name-changed', Lang.bind(this, this._itemNameChanged));
icon.connect('apps-changed', Lang.bind(this, this._refilterApps));
this.addItem(icon);
this.folderIcons.push(icon);
}));
apps.forEach(Lang.bind(this, function(appId) {
let app = appSys.lookup_app(appId);
let icon = new AppIcon(app);
this.addItem(icon);
}));
this.loadGrid();
this._refilterApps();
}, },
getCurrentPageY: function() { getCurrentPageY: function() {
@ -415,7 +498,7 @@ const AllView = new Lang.Class({
_onScroll: function(actor, event) { _onScroll: function(actor, event) {
if (this._displayingPopup) if (this._displayingPopup)
return true; return Clutter.EVENT_STOP;
let direction = event.get_scroll_direction(); let direction = event.get_scroll_direction();
if (direction == Clutter.ScrollDirection.UP) if (direction == Clutter.ScrollDirection.UP)
@ -423,7 +506,7 @@ const AllView = new Lang.Class({
else if (direction == Clutter.ScrollDirection.DOWN) else if (direction == Clutter.ScrollDirection.DOWN)
this.goToPage(this._currentPage + 1); this.goToPage(this._currentPage + 1);
return true; return Clutter.EVENT_STOP;
}, },
_onPan: function(action) { _onPan: function(action) {
@ -454,63 +537,17 @@ const AllView = new Lang.Class({
_onKeyPressEvent: function(actor, event) { _onKeyPressEvent: function(actor, event) {
if (this._displayingPopup) if (this._displayingPopup)
return true; return Clutter.EVENT_STOP;
if (event.get_key_symbol() == Clutter.Page_Up) { if (event.get_key_symbol() == Clutter.Page_Up) {
this.goToPage(this._currentPage - 1); this.goToPage(this._currentPage - 1);
return true; return Clutter.EVENT_STOP;
} else if (event.get_key_symbol() == Clutter.Page_Down) { } else if (event.get_key_symbol() == Clutter.Page_Down) {
this.goToPage(this._currentPage + 1); this.goToPage(this._currentPage + 1);
return true; return Clutter.EVENT_STOP;
} }
return false; return Clutter.EVENT_PROPAGATE;
},
_getItemId: function(item) {
if (item instanceof Shell.App)
return item.get_id();
else if (item instanceof GMenu.TreeDirectory)
return item.get_menu_id();
else
return null;
},
_createItemIcon: function(item) {
if (item instanceof Shell.App)
return new AppIcon(item);
else if (item instanceof GMenu.TreeDirectory)
return new FolderIcon(item, this);
else
return null;
},
_compareItems: function(itemA, itemB) {
// bit of a hack: rely on both ShellApp and GMenuTreeDirectory
// having a get_name() method
let nameA = GLib.utf8_collate_key(itemA.get_name(), -1);
let nameB = GLib.utf8_collate_key(itemB.get_name(), -1);
return (nameA > nameB) ? 1 : (nameA < nameB ? -1 : 0);
},
removeAll: function() {
this._folderIcons = [];
this.parent();
},
addApp: function(app) {
let appIcon = this._addItem(app);
if (appIcon)
appIcon.actor.connect('key-focus-in',
Lang.bind(this, this._ensureIconVisible));
},
addFolder: function(dir) {
let folderIcon = this._addItem(dir);
this._folderIcons.push(folderIcon);
if (folderIcon)
folderIcon.actor.connect('key-focus-in',
Lang.bind(this, this._ensureIconVisible));
}, },
addFolderPopup: function(popup) { addFolderPopup: function(popup) {
@ -577,8 +614,8 @@ const AllView = new Lang.Class({
this._availWidth = availWidth; this._availWidth = availWidth;
this._availHeight = availHeight; this._availHeight = availHeight;
// Update folder views // Update folder views
for (let i = 0; i < this._folderIcons.length; i++) for (let i = 0; i < this.folderIcons.length; i++)
this._folderIcons[i].adaptToSize(availWidth, availHeight); this.folderIcons[i].adaptToSize(availWidth, availHeight);
} }
}); });
Signals.addSignalMethods(AllView.prototype); Signals.addSignalMethods(AllView.prototype);
@ -607,17 +644,18 @@ const FrequentView = new Lang.Class({
this._noFrequentAppsLabel.hide(); this._noFrequentAppsLabel.hide();
this._usage = Shell.AppUsage.get_default(); this._usage = Shell.AppUsage.get_default();
this.actor.connect('notify::mapped', Lang.bind(this, function() {
if (this.actor.mapped)
this._redisplay();
}));
}, },
hasUsefulData: function() { hasUsefulData: function() {
return this._usage.get_most_used("").length >= MIN_FREQUENT_APPS_COUNT; return this._usage.get_most_used("").length >= MIN_FREQUENT_APPS_COUNT;
}, },
removeAll: function() { _loadApps: function() {
this._grid.destroyAll();
},
loadApps: function() {
let mostUsed = this._usage.get_most_used (""); let mostUsed = this._usage.get_most_used ("");
let hasUsefulData = this.hasUsefulData(); let hasUsefulData = this.hasUsefulData();
this._noFrequentAppsLabel.visible = !hasUsefulData; this._noFrequentAppsLabel.visible = !hasUsefulData;
@ -695,15 +733,6 @@ const AppDisplay = new Lang.Class({
Name: 'AppDisplay', Name: 'AppDisplay',
_init: function() { _init: function() {
Shell.AppSystem.get_default().connect('installed-changed', Lang.bind(this, function() {
Main.queueDeferredWork(this._allAppsWorkId);
}));
Main.overview.connect('showing', Lang.bind(this, function() {
Main.queueDeferredWork(this._frequentAppsWorkId);
}));
global.settings.connect('changed::app-folder-categories', Lang.bind(this, function() {
Main.queueDeferredWork(this._allAppsWorkId);
}));
this._privacySettings = new Gio.Settings({ schema: 'org.gnome.desktop.privacy' }); this._privacySettings = new Gio.Settings({ schema: 'org.gnome.desktop.privacy' });
this._privacySettings.connect('changed::remember-app-usage', this._privacySettings.connect('changed::remember-app-usage',
Lang.bind(this, this._updateFrequentVisibility)); Lang.bind(this, this._updateFrequentVisibility));
@ -757,15 +786,6 @@ const AppDisplay = new Lang.Class({
initialView = Views.ALL; initialView = Views.ALL;
this._showView(initialView); this._showView(initialView);
this._updateFrequentVisibility(); this._updateFrequentVisibility();
// We need a dummy actor to catch the keyboard focus if the
// user Ctrl-Alt-Tabs here before the deferred work creates
// our real contents
this._focusDummy = new St.Bin({ can_focus: true });
this._viewStack.add_actor(this._focusDummy);
this._allAppsWorkId = Main.initializeDeferredWork(this.actor, Lang.bind(this, this._redisplayAllApps));
this._frequentAppsWorkId = Main.initializeDeferredWork(this.actor, Lang.bind(this, this._redisplayFrequentApps));
}, },
_showView: function(activeIndex) { _showView: function(activeIndex) {
@ -799,51 +819,6 @@ const AppDisplay = new Lang.Class({
this._showView(Views.ALL); this._showView(Views.ALL);
}, },
_redisplay: function() {
this._redisplayFrequentApps();
this._redisplayAllApps();
},
_redisplayFrequentApps: function() {
let view = this._views[Views.FREQUENT].view;
view.removeAll();
view.loadApps();
},
_redisplayAllApps: function() {
let view = this._views[Views.ALL].view;
view.removeAll();
let tree = new GMenu.Tree({ menu_basename: "applications.menu" });
tree.load_sync();
let root = tree.get_root_directory();
let iter = root.iter();
let nextType;
let folderCategories = global.settings.get_strv('app-folder-categories');
while ((nextType = iter.next()) != GMenu.TreeItemType.INVALID) {
if (nextType == GMenu.TreeItemType.DIRECTORY) {
let dir = iter.get_directory();
if (folderCategories.indexOf(dir.get_menu_id()) != -1)
view.addFolder(dir);
else
_loadCategory(dir, view);
}
}
view.loadGrid();
if (this._focusDummy) {
let focused = this._focusDummy.has_key_focus();
this._focusDummy.destroy();
this._focusDummy = null;
if (focused)
this.actor.navigate_focus(null, Gtk.DirectionType.TAB_FORWARD, false);
}
},
selectApp: function(id) { selectApp: function(id) {
this._showView(Views.ALL); this._showView(Views.ALL);
this._views[Views.ALL].view.selectApp(id); this._views[Views.ALL].view.selectApp(id);
@ -889,18 +864,31 @@ const AppSearchProvider = new Lang.Class({
}, },
getInitialResultSet: function(terms, callback, cancellable) { getInitialResultSet: function(terms, callback, cancellable) {
callback(this._appSys.initial_search(terms)); let query = terms.join(' ');
let groups = Gio.DesktopAppInfo.search(query);
let usage = Shell.AppUsage.get_default();
let results = [];
groups.forEach(function(group) {
group = group.filter(function(appID) {
let app = Gio.DesktopAppInfo.new(appID);
return app && app.should_show();
});
results = results.concat(group.sort(function(a, b) {
return usage.compare('', a, b);
}));
});
callback(results);
}, },
getSubsearchResultSet: function(previousResults, terms, callback, cancellable) { getSubsearchResultSet: function(previousResults, terms, callback, cancellable) {
callback(this._appSys.subsearch(previousResults, terms)); this.getInitialResultSet(terms, callback, cancellable);
}, },
activateResult: function(result) { activateResult: function(result) {
let app = this._appSys.lookup_app(result); let app = this._appSys.lookup_app(result);
let event = Clutter.get_current_event(); let event = Clutter.get_current_event();
let modifiers = event ? event.get_state() : 0; let modifiers = event ? event.get_state() : 0;
let openNewWindow = modifiers & Clutter.ModifierType.CONTROL_MASK; let openNewWindow = (modifiers & Clutter.ModifierType.CONTROL_MASK) || _isTerminal(app);
if (openNewWindow) if (openNewWindow)
app.open_new_window(-1); app.open_new_window(-1);
@ -943,22 +931,6 @@ const FolderView = new Lang.Class({
this.actor.add_action(action); this.actor.add_action(action);
}, },
_getItemId: function(item) {
return item.get_id();
},
_createItemIcon: function(item) {
return new AppIcon(item);
},
_compareItems: function(a, b) {
return a.compare_by_name(b);
},
addApp: function(app) {
this._addItem(app);
},
createFolderIcon: function(size) { createFolderIcon: function(size) {
let icon = new St.Widget({ layout_manager: new Clutter.BinLayout(), let icon = new St.Widget({ layout_manager: new Clutter.BinLayout(),
style_class: 'app-folder-icon', style_class: 'app-folder-icon',
@ -967,7 +939,7 @@ const FolderView = new Lang.Class({
let aligns = [ Clutter.ActorAlign.START, Clutter.ActorAlign.END ]; let aligns = [ Clutter.ActorAlign.START, Clutter.ActorAlign.END ];
for (let i = 0; i < Math.min(this._allItems.length, 4); i++) { for (let i = 0; i < Math.min(this._allItems.length, 4); i++) {
let texture = this._allItems[i].create_icon_texture(subSize); let texture = this._allItems[i].app.create_icon_texture(subSize);
let bin = new St.Bin({ child: texture, let bin = new St.Bin({ child: texture,
x_expand: true, y_expand: true }); x_expand: true, y_expand: true });
bin.set_x_align(aligns[i % 2]); bin.set_x_align(aligns[i % 2]);
@ -1044,10 +1016,12 @@ const FolderView = new Lang.Class({
const FolderIcon = new Lang.Class({ const FolderIcon = new Lang.Class({
Name: 'FolderIcon', Name: 'FolderIcon',
_init: function(dir, parentView) { _init: function(id, path, parentView) {
this._dir = dir; this.id = id;
this._parentView = parentView; this._parentView = parentView;
this._folder = new Gio.Settings({ schema_id: 'org.gnome.desktop.app-folders.folder',
path: path });
this.actor = new St.Button({ style_class: 'app-well-app app-folder', this.actor = new St.Button({ style_class: 'app-well-app app-folder',
button_mask: St.ButtonMask.ONE, button_mask: St.ButtonMask.ONE,
toggle_mode: true, toggle_mode: true,
@ -1058,15 +1032,11 @@ const FolderIcon = new Lang.Class({
// whether we need to update arrow side, position etc. // whether we need to update arrow side, position etc.
this._popupInvalidated = false; this._popupInvalidated = false;
let label = this._dir.get_name(); this.icon = new IconGrid.BaseIcon('', { createIcon: Lang.bind(this, this._createIcon), setSizeManually: true });
this.icon = new IconGrid.BaseIcon(label,
{ createIcon: Lang.bind(this, this._createIcon), setSizeManually: true });
this.actor.set_child(this.icon.actor); this.actor.set_child(this.icon.actor);
this.actor.label_actor = this.icon.label; this.actor.label_actor = this.icon.label;
this.view = new FolderView(); this.view = new FolderView();
_loadCategory(dir, this.view);
this.view.loadGrid();
this.actor.connect('clicked', Lang.bind(this, this.actor.connect('clicked', Lang.bind(this,
function() { function() {
@ -1079,6 +1049,63 @@ const FolderIcon = new Lang.Class({
if (!this.actor.mapped && this._popup) if (!this.actor.mapped && this._popup)
this._popup.popdown(); this._popup.popdown();
})); }));
this._folder.connect('changed', Lang.bind(this, this._redisplay));
this._redisplay();
},
getAppIds: function() {
return this.view.getAllItems().map(function(item) {
return item.id;
});
},
_updateName: function() {
let name = _getFolderName(this._folder);
if (this.name == name)
return;
this.name = name;
this.icon.label.text = this.name;
this.emit('name-changed');
},
_redisplay: function() {
this._updateName();
this.view.removeAll();
let excludedApps = this._folder.get_strv('excluded-apps');
let appSys = Shell.AppSystem.get_default();
let addAppId = (function addAppId(appId) {
if (excludedApps.indexOf(appId) >= 0)
return;
let app = appSys.lookup_app(appId);
if (!app)
return;
if (!app.get_app_info().should_show())
return;
let icon = new AppIcon(app);
this.view.addItem(icon);
}).bind(this);
let folderApps = this._folder.get_strv('apps');
folderApps.forEach(addAppId);
let folderCategories = this._folder.get_strv('categories');
Gio.AppInfo.get_all().forEach(function(appInfo) {
let appCategories = _getCategories(appInfo);
if (!_listsIntersect(folderCategories, appCategories))
return;
addAppId(appInfo.get_id());
});
this.view.loadGrid();
this.emit('apps-changed');
}, },
_createIcon: function(iconSize) { _createIcon: function(iconSize) {
@ -1157,6 +1184,7 @@ const FolderIcon = new Lang.Class({
this._popupInvalidated = true; this._popupInvalidated = true;
}, },
}); });
Signals.addSignalMethods(FolderIcon.prototype);
const AppFolderPopup = new Lang.Class({ const AppFolderPopup = new Lang.Class({
Name: 'AppFolderPopup', Name: 'AppFolderPopup',
@ -1210,13 +1238,13 @@ const AppFolderPopup = new Lang.Class({
_onKeyPress: function(actor, event) { _onKeyPress: function(actor, event) {
if (!this._isOpen) if (!this._isOpen)
return false; return Clutter.EVENT_PROPAGATE;
if (event.get_key_symbol() != Clutter.KEY_Escape) if (event.get_key_symbol() != Clutter.KEY_Escape)
return false; return Clutter.EVENT_PROPAGATE;
this.popdown(); this.popdown();
return true; return Clutter.EVENT_STOP;
}, },
toggle: function() { toggle: function() {
@ -1275,6 +1303,9 @@ const AppIcon = new Lang.Class({
_init : function(app, iconParams) { _init : function(app, iconParams) {
this.app = app; this.app = app;
this.id = app.get_id();
this.name = app.get_name();
this.actor = new St.Button({ style_class: 'app-well-app', this.actor = new St.Button({ style_class: 'app-well-app',
reactive: true, reactive: true,
button_mask: St.ButtonMask.ONE | St.ButtonMask.TWO, button_mask: St.ButtonMask.ONE | St.ButtonMask.TWO,
@ -1357,13 +1388,13 @@ const AppIcon = new Lang.Class({
Lang.bind(this, function() { Lang.bind(this, function() {
this._menuTimeoutId = 0; this._menuTimeoutId = 0;
this.popupMenu(); this.popupMenu();
return false; return GLib.SOURCE_REMOVE;
})); }));
} else if (button == 3) { } else if (button == 3) {
this.popupMenu(); this.popupMenu();
return true; return Clutter.EVENT_STOP;
} }
return false; return Clutter.EVENT_PROPAGATE;
}, },
_onClicked: function(actor, button) { _onClicked: function(actor, button) {
@ -1375,7 +1406,6 @@ const AppIcon = new Lang.Class({
// Last workspace is always empty // Last workspace is always empty
let launchWorkspace = global.screen.get_workspace_by_index(global.screen.n_workspaces - 1); let launchWorkspace = global.screen.get_workspace_by_index(global.screen.n_workspaces - 1);
launchWorkspace.activate(global.get_current_time()); launchWorkspace.activate(global.get_current_time());
this.emit('launching');
this.app.open_new_window(-1); this.app.open_new_window(-1);
Main.overview.hide(); Main.overview.hide();
} }
@ -1434,11 +1464,11 @@ const AppIcon = new Lang.Class({
}, },
_onActivate: function (event) { _onActivate: function (event) {
this.emit('launching');
let modifiers = event.get_state(); let modifiers = event.get_state();
if (modifiers & Clutter.ModifierType.CONTROL_MASK if ((modifiers & Clutter.ModifierType.CONTROL_MASK
&& this.app.state == Shell.AppState.RUNNING) { && this.app.state == Shell.AppState.RUNNING)
|| _isTerminal(this.app)) {
this.app.open_new_window(-1); this.app.open_new_window(-1);
} else { } else {
this.app.activate(); this.app.activate();
@ -1486,8 +1516,6 @@ const AppIconMenu = new Lang.Class({
this._source = source; this._source = source;
this.connect('activate', Lang.bind(this, this._onActivate));
this.actor.add_style_class_name('app-well-menu'); this.actor.add_style_class_name('app-well-menu');
// Chain our visibility and lifecycle to that of the source // Chain our visibility and lifecycle to that of the source
@ -1497,13 +1525,15 @@ const AppIconMenu = new Lang.Class({
})); }));
source.actor.connect('destroy', Lang.bind(this, function () { this.actor.destroy(); })); source.actor.connect('destroy', Lang.bind(this, function () { this.actor.destroy(); }));
Main.uiGroup.add_actor(this.actor); Main.layoutManager.menuGroup.add_actor(this.actor);
}, },
_redisplay: function() { _redisplay: function() {
this.removeAll(); this.removeAll();
let windows = this._source.app.get_windows(); let windows = this._source.app.get_windows().filter(function(w) {
return !w.skip_taskbar;
});
// Display the app windows menu items and the separator between windows // Display the app windows menu items and the separator between windows
// of the current desktop and other windows. // of the current desktop and other windows.
@ -1511,25 +1541,54 @@ const AppIconMenu = new Lang.Class({
let separatorShown = windows.length > 0 && windows[0].get_workspace() != activeWorkspace; let separatorShown = windows.length > 0 && windows[0].get_workspace() != activeWorkspace;
for (let i = 0; i < windows.length; i++) { for (let i = 0; i < windows.length; i++) {
if (!separatorShown && windows[i].get_workspace() != activeWorkspace) { let window = windows[i];
if (!separatorShown && window.get_workspace() != activeWorkspace) {
this._appendSeparator(); this._appendSeparator();
separatorShown = true; separatorShown = true;
} }
let item = this._appendMenuItem(windows[i].title); let item = this._appendMenuItem(window.title);
item._window = windows[i]; item.connect('activate', Lang.bind(this, function() {
this.emit('activate-window', window);
}));
} }
if (!this._source.app.is_window_backed()) { if (!this._source.app.is_window_backed()) {
if (windows.length > 0) this._appendSeparator();
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();
let appInfo = this._source.app.get_app_info();
let actions = appInfo.list_actions();
for (let i = 0; i < actions.length; i++) {
let action = actions[i];
let item = this._appendMenuItem(appInfo.get_action_name(action));
item.connect('activate', Lang.bind(this, function(emitter, event) {
this._source.app.launch_action(action, event.get_time(), -1);
this.emit('activate-window', null);
}));
}
this._appendSeparator();
let isFavorite = AppFavorites.getAppFavorites().isFavorite(this._source.app.get_id()); let isFavorite = AppFavorites.getAppFavorites().isFavorite(this._source.app.get_id());
this._newWindowMenuItem = this._appendMenuItem(_("New Window")); if (isFavorite) {
this._appendSeparator(); let item = this._appendMenuItem(_("Remove from Favorites"));
item.connect('activate', Lang.bind(this, function() {
this._toggleFavoriteMenuItem = this._appendMenuItem(isFavorite ? _("Remove from Favorites") let favs = AppFavorites.getAppFavorites();
: _("Add to Favorites")); favs.removeFavorite(this._source.app.get_id());
}));
} else {
let item = this._appendMenuItem(_("Add to Favorites"));
item.connect('activate', Lang.bind(this, function() {
let favs = AppFavorites.getAppFavorites();
favs.addFavorite(this._source.app.get_id());
}));
}
} }
}, },
@ -1548,24 +1607,6 @@ const AppIconMenu = new Lang.Class({
popup: function(activatingButton) { popup: function(activatingButton) {
this._redisplay(); this._redisplay();
this.open(); this.open();
},
_onActivate: function (actor, child) {
if (child._window) {
let metaWindow = child._window;
this.emit('activate-window', metaWindow);
} else if (child == this._newWindowMenuItem) {
this._source.app.open_new_window(-1);
this.emit('activate-window', null);
} else if (child == this._toggleFavoriteMenuItem) {
let favs = AppFavorites.getAppFavorites();
let isFavorite = favs.isFavorite(this._source.app.get_id());
if (isFavorite)
favs.removeFavorite(this._source.app.get_id());
else
favs.addFavorite(this._source.app.get_id());
}
this.close();
} }
}); });
Signals.addSignalMethods(AppIconMenu.prototype); Signals.addSignalMethods(AppIconMenu.prototype);

View File

@ -50,11 +50,9 @@ const BackgroundCache = new Lang.Class({
effects: Meta.BackgroundEffects.NONE }); effects: Meta.BackgroundEffects.NONE });
let content = null; let content = null;
let candidateContent = null; let candidateContent = null;
for (let i = 0; i < this._patterns.length; i++) { for (let i = 0; i < this._patterns.length; i++) {
if (!this._patterns[i])
continue;
if (this._patterns[i].get_shading() != params.shadingType) if (this._patterns[i].get_shading() != params.shadingType)
continue; continue;
@ -88,7 +86,6 @@ const BackgroundCache = new Lang.Class({
} }
this._patterns.push(content); this._patterns.push(content);
return content; return content;
}, },
@ -116,9 +113,9 @@ const BackgroundCache = new Lang.Class({
_removeContent: function(contentList, content) { _removeContent: function(contentList, content) {
let index = contentList.indexOf(content); let index = contentList.indexOf(content);
if (index < 0)
if (index >= 0) throw new Error("Trying to remove invalid content: " + content);
contentList.splice(index, 1); contentList.splice(index, 1);
}, },
removePatternContent: function(content) { removePatternContent: function(content) {
@ -128,12 +125,53 @@ const BackgroundCache = new Lang.Class({
removeImageContent: function(content) { removeImageContent: function(content) {
let filename = content.get_filename(); let filename = content.get_filename();
if (filename && this._fileMonitors[filename]) let hasOtherUsers = this._images.some(function(content) { return filename == content.get_filename(); });
if (!hasOtherUsers)
delete this._fileMonitors[filename]; delete this._fileMonitors[filename];
this._removeContent(this._images, content); this._removeContent(this._images, content);
}, },
_loadImageContentInternal: function(filename, style) {
let cancellable = new Gio.Cancellable();
let content = new Meta.Background({ meta_screen: global.screen });
let info = { filename: filename,
style: style,
cancellable: cancellable,
callers: [] };
content.load_file_async(filename, style, cancellable, Lang.bind(this, function(object, result) {
if (cancellable.is_cancelled())
return;
try {
content.load_file_finish(result);
} catch(e) {
content = null;
}
if (content) {
this._monitorFile(filename);
info.callers.forEach(Lang.bind(this, function(caller) {
let newContent = content.copy(caller.monitorIndex, caller.effects);
this._images.push(newContent);
caller.onFinished(newContent);
}));
} else {
info.callers.forEach(Lang.bind(this, function(caller) {
caller.onFinished(null);
}));
}
let idx = this._pendingFileLoads.indexOf(info);
this._pendingFileLoads.splice(idx, 1);
}));
this._pendingFileLoads.push(info);
return info;
},
_loadImageContent: function(params) { _loadImageContent: function(params) {
params = Params.parse(params, { monitorIndex: 0, params = Params.parse(params, { monitorIndex: 0,
style: null, style: null,
@ -142,63 +180,38 @@ const BackgroundCache = new Lang.Class({
cancellable: null, cancellable: null,
onFinished: null }); onFinished: null });
let caller = { monitorIndex: params.monitorIndex,
effects: params.effects,
cancellable: params.cancellable,
onFinished: params.onFinished };
let info = null;
for (let i = 0; i < this._pendingFileLoads.length; i++) { for (let i = 0; i < this._pendingFileLoads.length; i++) {
if (this._pendingFileLoads[i].filename == params.filename && let pendingLoad = this._pendingFileLoads[i];
this._pendingFileLoads[i].style == params.style) { if (pendingLoad.filename == params.filename && pendingLoad.style == params.style) {
this._pendingFileLoads[i].callers.push({ shouldCopy: true, info = pendingLoad;
monitorIndex: params.monitorIndex, break;
effects: params.effects,
onFinished: params.onFinished });
return;
} }
} }
this._pendingFileLoads.push({ filename: params.filename, if (!info)
style: params.style, info = this._loadImageContentInternal(params.filename, params.style);
callers: [{ shouldCopy: false,
monitorIndex: params.monitorIndex,
effects: params.effects,
onFinished: params.onFinished }] });
let content = new Meta.Background({ meta_screen: global.screen, info.callers.push(caller);
monitor: params.monitorIndex,
effects: params.effects });
content.load_file_async(params.filename, if (caller.cancellable) {
params.style, caller.cancellable.connect(Lang.bind(this, function() {
params.cancellable, let idx = info.callers.indexOf(caller);
Lang.bind(this, info.callers.splice(idx, 1);
function(object, result) {
try {
content.load_file_finish(result);
this._monitorFile(params.filename); if (info.callers.length == 0) {
this._images.push(content); info.cancellable.cancel();
} catch(e) {
content = null;
}
for (let i = 0; i < this._pendingFileLoads.length; i++) { let idx = this._pendingFileLoads.indexOf(info);
let pendingLoad = this._pendingFileLoads[i]; this._pendingFileLoads.splice(idx, 1);
if (pendingLoad.filename != params.filename || }
pendingLoad.style != params.style) }));
continue; }
for (let j = 0; j < pendingLoad.callers.length; j++) {
if (pendingLoad.callers[j].onFinished) {
if (content && pendingLoad.callers[j].shouldCopy) {
content = object.copy(pendingLoad.callers[j].monitorIndex,
pendingLoad.callers[j].effects);
}
pendingLoad.callers[j].onFinished(content);
}
}
this._pendingFileLoads.splice(i, 1);
}
}));
}, },
getImageContent: function(params) { getImageContent: function(params) {
@ -210,11 +223,9 @@ const BackgroundCache = new Lang.Class({
onFinished: null }); onFinished: null });
let content = null; let content = null;
let candidateContent = null; let candidateContent = null;
for (let i = 0; i < this._images.length; i++) { for (let i = 0; i < this._images.length; i++) {
if (!this._images[i])
continue;
if (this._images[i].get_style() != params.style) if (this._images[i].get_style() != params.style)
continue; continue;
@ -222,7 +233,7 @@ const BackgroundCache = new Lang.Class({
continue; continue;
if (params.style == GDesktopEnums.BackgroundStyle.SPANNED && if (params.style == GDesktopEnums.BackgroundStyle.SPANNED &&
this._images[i].monitor_index != this._monitorIndex) this._images[i].monitor != params.monitorIndex)
continue; continue;
candidateContent = this._images[i]; candidateContent = this._images[i];
@ -250,7 +261,6 @@ const BackgroundCache = new Lang.Class({
monitorIndex: params.monitorIndex, monitorIndex: params.monitorIndex,
cancellable: params.cancellable, cancellable: params.cancellable,
onFinished: params.onFinished }); onFinished: params.onFinished });
} }
}, },
@ -262,6 +272,7 @@ const BackgroundCache = new Lang.Class({
if (params.onLoaded) { if (params.onLoaded) {
GLib.idle_add(GLib.PRIORITY_DEFAULT, Lang.bind(this, function() { GLib.idle_add(GLib.PRIORITY_DEFAULT, Lang.bind(this, function() {
params.onLoaded(this._animation); params.onLoaded(this._animation);
return GLib.SOURCE_REMOVE;
})); }));
} }
} }
@ -276,6 +287,7 @@ const BackgroundCache = new Lang.Class({
if (params.onLoaded) { if (params.onLoaded) {
GLib.idle_add(GLib.PRIORITY_DEFAULT, Lang.bind(this, function() { GLib.idle_add(GLib.PRIORITY_DEFAULT, Lang.bind(this, function() {
params.onLoaded(this._animation); params.onLoaded(this._animation);
return GLib.SOURCE_REMOVE;
})); }));
} }
})); }));
@ -375,7 +387,7 @@ const Background = new Lang.Class({
GLib.idle_add(GLib.PRIORITY_DEFAULT, Lang.bind(this, function() { GLib.idle_add(GLib.PRIORITY_DEFAULT, Lang.bind(this, function() {
this.emit('loaded'); this.emit('loaded');
return false; return GLib.SOURCE_REMOVE;
})); }));
}, },
@ -414,27 +426,26 @@ const Background = new Lang.Class({
this._fileWatches[filename] = signalId; this._fileWatches[filename] = signalId;
}, },
_addImage: function(content, index, filename) { _ensureImage: function(index) {
content.brightness = this._brightness; if (this._images[index])
content.vignette_sharpness = this._vignetteSharpness; return;
let actor = new Meta.BackgroundActor(); let actor = new Meta.BackgroundActor();
actor.content = content;
// The background pattern is the first actor in // The background pattern is the first actor in
// the group, and all images should be above that. // the group, and all images should be above that.
this.actor.insert_child_at_index(actor, index + 1); this.actor.insert_child_at_index(actor, index + 1);
this._images[index] = actor; this._images[index] = actor;
this._watchCacheFile(filename);
}, },
_updateImage: function(content, index, filename) { _updateImage: function(index, content, filename) {
content.brightness = this._brightness; content.brightness = this._brightness;
content.vignette_sharpness = this._vignetteSharpness; content.vignette_sharpness = this._vignetteSharpness;
this._cache.removeImageContent(this._images[index].content); let image = this._images[index];
this._images[index].content = content; if (image.content)
this._cache.removeImageContent(content);
image.content = content;
this._watchCacheFile(filename); this._watchCacheFile(filename);
}, },
@ -482,11 +493,8 @@ const Background = new Lang.Class({
return; return;
} }
if (!this._images[i]) { this._ensureImage(i);
this._addImage(content, i, files[i]); this._updateImage(i, content, files[i]);
} else {
this._updateImage(content, i, files[i]);
}
if (numPendingImages == 0) { if (numPendingImages == 0) {
this._setLoaded(); this._setLoaded();
@ -521,7 +529,7 @@ const Background = new Lang.Class({
Lang.bind(this, function() { Lang.bind(this, function() {
this._updateAnimationTimeoutId = 0; this._updateAnimationTimeoutId = 0;
this._updateAnimation(); this._updateAnimation();
return false; return GLib.SOURCE_REMOVE;
})); }));
}, },
@ -541,30 +549,33 @@ const Background = new Lang.Class({
}); });
}, },
_loadFile: function(filename) { _loadImage: function(filename) {
this._cache.getImageContent({ monitorIndex: this._monitorIndex, this._cache.getImageContent({ monitorIndex: this._monitorIndex,
effects: this._effects, effects: this._effects,
style: this._style, style: this._style,
filename: filename, filename: filename,
cancellable: this._cancellable, cancellable: this._cancellable,
onFinished: Lang.bind(this, function(content) { onFinished: Lang.bind(this, function(content) {
if (!content) { if (content) {
if (!this._cancellable.is_cancelled()) this._ensureImage(0);
this._loadAnimation(filename); this._updateImage(0, content, filename);
return;
} }
this._addImage(content, 0, filename);
this._setLoaded(); this._setLoaded();
}) })
}); });
},
_loadFile: function(filename) {
if (filename.endsWith('.xml'))
this._loadAnimation(filename);
else
this._loadImage(filename);
}, },
_load: function () { _load: function () {
this._cache = getBackgroundCache(); this._cache = getBackgroundCache();
this._loadPattern(this._cache); this._loadPattern();
this._style = this._settings.get_enum(BACKGROUND_STYLE_KEY); this._style = this._settings.get_enum(BACKGROUND_STYLE_KEY);
if (this._style == GDesktopEnums.BackgroundStyle.NONE) { if (this._style == GDesktopEnums.BackgroundStyle.NONE) {
@ -623,25 +634,6 @@ const Background = new Lang.Class({
}); });
Signals.addSignalMethods(Background.prototype); Signals.addSignalMethods(Background.prototype);
const SystemBackground = new Lang.Class({
Name: 'SystemBackground',
_init: function() {
this._cache = getBackgroundCache();
this.actor = new Meta.BackgroundActor();
this._cache.getImageContent({ style: GDesktopEnums.BackgroundStyle.WALLPAPER,
filename: global.datadir + '/theme/noise-texture.png',
effects: Meta.BackgroundEffects.NONE,
onFinished: Lang.bind(this, function(content) {
this.actor.content = content;
this.emit('loaded');
})
});
}
});
Signals.addSignalMethods(SystemBackground.prototype);
const Animation = new Lang.Class({ const Animation = new Lang.Class({
Name: 'Animation', Name: 'Animation',
@ -726,29 +718,30 @@ const BackgroundManager = new Lang.Class({
} }
}, },
_updateBackground: function(background, monitorIndex) { _updateBackground: function() {
let newBackground = this._createBackground(monitorIndex); let newBackground = this._createBackground();
newBackground.vignetteSharpness = background.vignetteSharpness; newBackground.vignetteSharpness = this.background.vignetteSharpness;
newBackground.brightness = background.brightness; newBackground.brightness = this.background.brightness;
newBackground.visible = background.visible; newBackground.visible = this.background.visible;
newBackground.loadedSignalId = newBackground.connect('loaded', newBackground.loadedSignalId = newBackground.connect('loaded',
Lang.bind(this, function() { Lang.bind(this, function() {
newBackground.disconnect(newBackground.loadedSignalId); newBackground.disconnect(newBackground.loadedSignalId);
newBackground.loadedSignalId = 0; newBackground.loadedSignalId = 0;
Tweener.addTween(background.actor, Tweener.addTween(this.background.actor,
{ opacity: 0, { opacity: 0,
time: FADE_ANIMATION_TIME, time: FADE_ANIMATION_TIME,
transition: 'easeOutQuad', transition: 'easeOutQuad',
onComplete: Lang.bind(this, function() { onComplete: Lang.bind(this, function() {
if (this._newBackground == newBackground) { if (this._newBackground != newBackground) {
this.background = newBackground; /* Not interesting, we queued another load */
this._newBackground = null;
} else {
newBackground.actor.destroy(); newBackground.actor.destroy();
return;
} }
background.actor.destroy(); this.background.actor.destroy();
this.background = newBackground;
this._newBackground = null;
this.emit('changed'); this.emit('changed');
}) })
@ -776,7 +769,7 @@ const BackgroundManager = new Lang.Class({
background.changeSignalId = background.connect('changed', Lang.bind(this, function() { background.changeSignalId = background.connect('changed', Lang.bind(this, function() {
background.disconnect(background.changeSignalId); background.disconnect(background.changeSignalId);
background.changeSignalId = 0; background.changeSignalId = 0;
this._updateBackground(background, this._monitorIndex); this._updateBackground();
})); }));
background.actor.connect('destroy', Lang.bind(this, function() { background.actor.connect('destroy', Lang.bind(this, function() {

View File

@ -13,8 +13,8 @@ const BackgroundMenu = new Lang.Class({
Name: 'BackgroundMenu', Name: 'BackgroundMenu',
Extends: PopupMenu.PopupMenu, Extends: PopupMenu.PopupMenu,
_init: function(source) { _init: function(layoutManager) {
this.parent(source, 0, St.Side.TOP); this.parent(layoutManager.dummyCursor, 0, St.Side.TOP);
this.addSettingsAction(_("Settings"), 'gnome-control-center.desktop'); this.addSettingsAction(_("Settings"), 'gnome-control-center.desktop');
this.addMenuItem(new PopupMenu.PopupSeparatorMenuItem()); this.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
@ -22,23 +22,20 @@ const BackgroundMenu = new Lang.Class({
this.actor.add_style_class_name('background-menu'); this.actor.add_style_class_name('background-menu');
Main.uiGroup.add_actor(this.actor); layoutManager.menuGroup.add_actor(this.actor);
this.actor.hide(); this.actor.hide();
} }
}); });
function addBackgroundMenu(actor) { function addBackgroundMenu(actor, layoutManager) {
let cursor = new St.Bin({ opacity: 0 });
Main.uiGroup.add_actor(cursor);
actor.reactive = true; actor.reactive = true;
actor._backgroundMenu = new BackgroundMenu(cursor); actor._backgroundMenu = new BackgroundMenu(layoutManager);
actor._backgroundManager = new PopupMenu.PopupMenuManager({ actor: actor }); actor._backgroundManager = new PopupMenu.PopupMenuManager({ actor: actor });
actor._backgroundManager.addMenu(actor._backgroundMenu); actor._backgroundManager.addMenu(actor._backgroundMenu);
function openMenu() { function openMenu() {
let [x, y] = global.get_pointer(); let [x, y] = global.get_pointer();
cursor.set_position(x, y); Main.layoutManager.setDummyCursorPosition(x, y);
actor._backgroundMenu.open(BoxPointer.PopupAnimation.NONE); actor._backgroundMenu.open(BoxPointer.PopupAnimation.NONE);
} }
@ -59,10 +56,8 @@ function addBackgroundMenu(actor) {
actor.add_action(clickAction); actor.add_action(clickAction);
actor.connect('destroy', function() { actor.connect('destroy', function() {
actor._backgroundMenu.destroy(); actor._backgroundMenu.destroy();
actor._backgroundMenu = null; actor._backgroundMenu = null;
actor._backgroundManager = null; actor._backgroundManager = null;
});
cursor.destroy();
});
} }

View File

@ -69,7 +69,7 @@ const BoxPointer = new Lang.Class({
_muteInput: function() { _muteInput: function() {
if (this._capturedEventId == 0) if (this._capturedEventId == 0)
this._capturedEventId = this.actor.connect('captured-event', this._capturedEventId = this.actor.connect('captured-event',
function() { return true; }); function() { return Clutter.EVENT_STOP; });
}, },
_unmuteInput: function() { _unmuteInput: function() {
@ -121,6 +121,9 @@ const BoxPointer = new Lang.Class({
}, },
hide: function(animate, onComplete) { hide: function(animate, onComplete) {
if (!this.actor.visible)
return;
let xOffset = 0; let xOffset = 0;
let yOffset = 0; let yOffset = 0;
let themeNode = this.actor.get_theme_node(); let themeNode = this.actor.get_theme_node();
@ -284,38 +287,40 @@ const BoxPointer = new Lang.Class({
let skipBottomLeft = false; let skipBottomLeft = false;
let skipBottomRight = false; let skipBottomRight = false;
switch (this._arrowSide) { if (rise) {
case St.Side.TOP: switch (this._arrowSide) {
if (this._arrowOrigin == x1) case St.Side.TOP:
skipTopLeft = true; if (this._arrowOrigin == x1)
else if (this._arrowOrigin == x2) skipTopLeft = true;
skipTopRight = true; else if (this._arrowOrigin == x2)
break; skipTopRight = true;
break;
case St.Side.RIGHT: case St.Side.RIGHT:
if (this._arrowOrigin == y1) if (this._arrowOrigin == y1)
skipTopRight = true; skipTopRight = true;
else if (this._arrowOrigin == y2) else if (this._arrowOrigin == y2)
skipBottomRight = true; skipBottomRight = true;
break; break;
case St.Side.BOTTOM: case St.Side.BOTTOM:
if (this._arrowOrigin == x1) if (this._arrowOrigin == x1)
skipBottomLeft = true; skipBottomLeft = true;
else if (this._arrowOrigin == x2) else if (this._arrowOrigin == x2)
skipBottomRight = true; skipBottomRight = true;
break; break;
case St.Side.LEFT: case St.Side.LEFT:
if (this._arrowOrigin == y1) if (this._arrowOrigin == y1)
skipTopLeft = true; skipTopLeft = true;
else if (this._arrowOrigin == y2) else if (this._arrowOrigin == y2)
skipBottomLeft = true; skipBottomLeft = true;
break; break;
}
} }
cr.moveTo(x1 + borderRadius, y1); cr.moveTo(x1 + borderRadius, y1);
if (this._arrowSide == St.Side.TOP) { if (this._arrowSide == St.Side.TOP && rise) {
if (skipTopLeft) { if (skipTopLeft) {
cr.moveTo(x1, y2 - borderRadius); cr.moveTo(x1, y2 - borderRadius);
cr.lineTo(x1, y1 - rise); cr.lineTo(x1, y1 - rise);
@ -337,7 +342,7 @@ const BoxPointer = new Lang.Class({
3*Math.PI/2, Math.PI*2); 3*Math.PI/2, Math.PI*2);
} }
if (this._arrowSide == St.Side.RIGHT) { if (this._arrowSide == St.Side.RIGHT && rise) {
if (skipTopRight) { if (skipTopRight) {
cr.lineTo(x2 + rise, y1); cr.lineTo(x2 + rise, y1);
cr.lineTo(x2 + rise, y1 + halfBase); cr.lineTo(x2 + rise, y1 + halfBase);
@ -358,7 +363,7 @@ const BoxPointer = new Lang.Class({
0, Math.PI/2); 0, Math.PI/2);
} }
if (this._arrowSide == St.Side.BOTTOM) { if (this._arrowSide == St.Side.BOTTOM && rise) {
if (skipBottomLeft) { if (skipBottomLeft) {
cr.lineTo(x1 + halfBase, y2); cr.lineTo(x1 + halfBase, y2);
cr.lineTo(x1, y2 + rise); cr.lineTo(x1, y2 + rise);
@ -379,7 +384,7 @@ const BoxPointer = new Lang.Class({
Math.PI/2, Math.PI); Math.PI/2, Math.PI);
} }
if (this._arrowSide == St.Side.LEFT) { if (this._arrowSide == St.Side.LEFT && rise) {
if (skipTopLeft) { if (skipTopLeft) {
cr.lineTo(x1, y1 + halfBase); cr.lineTo(x1, y1 + halfBase);
cr.lineTo(x1 - rise, y1); cr.lineTo(x1 - rise, y1);

View File

@ -17,16 +17,18 @@ const SHOW_WEEKDATE_KEY = 'show-weekdate';
// in org.gnome.desktop.interface // in org.gnome.desktop.interface
const CLOCK_FORMAT_KEY = 'clock-format'; const CLOCK_FORMAT_KEY = 'clock-format';
function _sameDay(dateA, dateB) {
return (dateA.getDate() == dateB.getDate() &&
dateA.getMonth() == dateB.getMonth() &&
dateA.getYear() == dateB.getYear());
}
function _sameYear(dateA, dateB) { function _sameYear(dateA, dateB) {
return (dateA.getYear() == dateB.getYear()); return (dateA.getYear() == dateB.getYear());
} }
function _sameMonth(dateA, dateB) {
return _sameYear(dateA, dateB) && (dateA.getMonth() == dateB.getMonth());
}
function _sameDay(dateA, dateB) {
return _sameMonth(dateA, dateB) && (dateA.getDate() == dateB.getDate());
}
/* TODO: maybe needs config - right now we assume that Saturday and /* TODO: maybe needs config - right now we assume that Saturday and
* Sunday are non-work days (not true in e.g. Israel, it's Sunday and * Sunday are non-work days (not true in e.g. Israel, it's Sunday and
* Monday there) * Monday there)
@ -329,25 +331,22 @@ const DBusEventSource = new Lang.Class({
return; return;
if (this._curRequestBegin && this._curRequestEnd){ if (this._curRequestBegin && this._curRequestEnd){
let callFlags = Gio.DBusCallFlags.NO_AUTO_START;
if (forceReload)
callFlags = Gio.DBusCallFlags.NONE;
this._dbusProxy.GetEventsRemote(this._curRequestBegin.getTime() / 1000, this._dbusProxy.GetEventsRemote(this._curRequestBegin.getTime() / 1000,
this._curRequestEnd.getTime() / 1000, this._curRequestEnd.getTime() / 1000,
forceReload, forceReload,
Lang.bind(this, this._onEventsReceived), Lang.bind(this, this._onEventsReceived),
callFlags); Gio.DBusCallFlags.NONE);
} }
}, },
requestRange: function(begin, end, forceReload) { requestRange: function(begin, end) {
if (forceReload || !(_datesEqual(begin, this._lastRequestBegin) && _datesEqual(end, this._lastRequestEnd))) { if (!(_datesEqual(begin, this._lastRequestBegin) && _datesEqual(end, this._lastRequestEnd))) {
this.isLoading = true; this.isLoading = true;
this._lastRequestBegin = begin; this._lastRequestBegin = begin;
this._lastRequestEnd = end; this._lastRequestEnd = end;
this._curRequestBegin = begin; this._curRequestBegin = begin;
this._curRequestEnd = end; this._curRequestEnd = end;
this._loadEvents(forceReload); this._loadEvents(false);
} }
}, },
@ -419,21 +418,19 @@ const Calendar = new Lang.Class({
setEventSource: function(eventSource) { setEventSource: function(eventSource) {
this._eventSource = eventSource; this._eventSource = eventSource;
this._eventSource.connect('changed', Lang.bind(this, function() { this._eventSource.connect('changed', Lang.bind(this, function() {
this._update(false); this._update();
})); }));
this._update(true); this._update();
}, },
// Sets the calendar to show a specific date // Sets the calendar to show a specific date
setDate: function(date, forceReload) { setDate: function(date) {
if (!_sameDay(date, this._selectedDate)) { if (_sameDay(date, this._selectedDate))
this._selectedDate = date; return;
this._update(forceReload);
this.emit('selected-date-changed', new Date(this._selectedDate)); this._selectedDate = date;
} else { this._update();
if (forceReload) this.emit('selected-date-changed', new Date(this._selectedDate));
this._update(forceReload);
}
}, },
_buildHeader: function() { _buildHeader: function() {
@ -497,6 +494,7 @@ const Calendar = new Lang.Class({
this._onNextMonthButtonClicked(); this._onNextMonthButtonClicked();
break; break;
} }
return Clutter.EVENT_PROPAGATE;
}, },
_onPrevMonthButtonClicked: function() { _onPrevMonthButtonClicked: function() {
@ -520,7 +518,7 @@ const Calendar = new Lang.Class({
this._backButton.grab_key_focus(); this._backButton.grab_key_focus();
this.setDate(newDate, false); this.setDate(newDate);
}, },
_onNextMonthButtonClicked: function() { _onNextMonthButtonClicked: function() {
@ -544,28 +542,25 @@ const Calendar = new Lang.Class({
this._forwardButton.grab_key_focus(); this._forwardButton.grab_key_focus();
this.setDate(newDate, false); this.setDate(newDate);
}, },
_onSettingsChange: function() { _onSettingsChange: function() {
this._useWeekdate = this._settings.get_boolean(SHOW_WEEKDATE_KEY); this._useWeekdate = this._settings.get_boolean(SHOW_WEEKDATE_KEY);
this._buildHeader(); this._buildHeader();
this._update(false); this._update();
}, },
_update: function(forceReload) { _rebuildCalendar: function() {
let now = new Date(); let now = new Date();
if (_sameYear(this._selectedDate, now))
this._monthLabel.text = this._selectedDate.toLocaleFormat(this._headerFormatWithoutYear);
else
this._monthLabel.text = this._selectedDate.toLocaleFormat(this._headerFormat);
// Remove everything but the topBox and the weekday labels // Remove everything but the topBox and the weekday labels
let children = this.actor.get_children(); let children = this.actor.get_children();
for (let i = this._firstDayIndex; i < children.length; i++) for (let i = this._firstDayIndex; i < children.length; i++)
children[i].destroy(); children[i].destroy();
this._buttons = [];
// Start at the beginning of the week before the start of the month // Start at the beginning of the week before the start of the month
// //
// We want to show always 6 weeks (to keep the calendar menu at the same // We want to show always 6 weeks (to keep the calendar menu at the same
@ -583,11 +578,13 @@ const Calendar = new Lang.Class({
// Actually computing the number of weeks is complex, but we know that the // Actually computing the number of weeks is complex, but we know that the
// problematic categories (2 and 4) always start on week start, and that // problematic categories (2 and 4) always start on week start, and that
// all months at the end have 6 weeks. // all months at the end have 6 weeks.
let beginDate = new Date(this._selectedDate); let beginDate = new Date(this._selectedDate);
beginDate.setDate(1); beginDate.setDate(1);
beginDate.setSeconds(0); beginDate.setSeconds(0);
beginDate.setHours(12); beginDate.setHours(12);
this._calendarBegin = new Date(beginDate);
let year = beginDate.getYear(); let year = beginDate.getYear();
let daysToWeekStart = (7 + beginDate.getDay() - this._weekStart) % 7; let daysToWeekStart = (7 + beginDate.getDay() - this._weekStart) % 7;
@ -608,23 +605,18 @@ const Calendar = new Lang.Class({
if (this._eventSource.isDummy) if (this._eventSource.isDummy)
button.reactive = false; button.reactive = false;
let iterStr = iter.toUTCString(); button._date = new Date(iter);
button.connect('clicked', Lang.bind(this, function() { button.connect('clicked', Lang.bind(this, function() {
this._shouldDateGrabFocus = true; this.setDate(button._date);
let newlySelectedDate = new Date(iterStr);
this.setDate(newlySelectedDate, false);
this._shouldDateGrabFocus = false;
})); }));
let hasEvents = this._eventSource.hasEvents(iter); let hasEvents = this._eventSource.hasEvents(iter);
let styleClass = 'calendar-day-base calendar-day'; let styleClass = 'calendar-day-base calendar-day';
if (_isWorkDay(iter)) if (_isWorkDay(iter))
styleClass += ' calendar-work-day' styleClass += ' calendar-work-day';
else else
styleClass += ' calendar-nonwork-day' styleClass += ' calendar-nonwork-day';
// Hack used in lieu of border-collapse - see gnome-shell.css // Hack used in lieu of border-collapse - see gnome-shell.css
if (row == 2) if (row == 2)
@ -641,7 +633,7 @@ const Calendar = new Lang.Class({
styleClass += ' calendar-other-month-day'; styleClass += ' calendar-other-month-day';
if (hasEvents) if (hasEvents)
styleClass += ' calendar-day-with-events' styleClass += ' calendar-day-with-events';
button.style_class = styleClass; button.style_class = styleClass;
@ -649,12 +641,7 @@ const Calendar = new Lang.Class({
this.actor.add(button, this.actor.add(button,
{ row: row, col: offsetCols + (7 + iter.getDay() - this._weekStart) % 7 }); { row: row, col: offsetCols + (7 + iter.getDay() - this._weekStart) % 7 });
if (_sameDay(this._selectedDate, iter)) { this._buttons.push(button);
button.add_style_pseudo_class('active');
if (this._shouldDateGrabFocus)
button.grab_key_focus();
}
if (this._useWeekdate && iter.getDay() == 4) { if (this._useWeekdate && iter.getDay() == 4) {
let label = new St.Label({ text: _getCalendarWeekForDate(iter).toString(), let label = new St.Label({ text: _getCalendarWeekForDate(iter).toString(),
@ -668,9 +655,29 @@ const Calendar = new Lang.Class({
if (iter.getDay() == this._weekStart) if (iter.getDay() == this._weekStart)
row++; row++;
} }
// Signal to the event source that we are interested in events // Signal to the event source that we are interested in events
// only from this date range // only from this date range
this._eventSource.requestRange(beginDate, iter, forceReload); this._eventSource.requestRange(beginDate, iter);
},
_update: function() {
let now = new Date();
if (_sameYear(this._selectedDate, now))
this._monthLabel.text = this._selectedDate.toLocaleFormat(this._headerFormatWithoutYear);
else
this._monthLabel.text = this._selectedDate.toLocaleFormat(this._headerFormat);
if (!this._calendarBegin || !_sameMonth(this._selectedDate, this._calendarBegin))
this._rebuildCalendar();
this._buttons.forEach(Lang.bind(this, function(button) {
if (_sameDay(button._date, this._selectedDate))
button.add_style_pseudo_class('active');
else
button.remove_style_pseudo_class('active');
}));
} }
}); });

View File

@ -77,7 +77,7 @@ const AutomountManager = new Lang.Class({
})); }));
this._mountAllId = 0; this._mountAllId = 0;
return false; return GLib.SOURCE_REMOVE;
}, },
_onDriveConnected: function() { _onDriveConnected: function() {
@ -236,7 +236,7 @@ const AutomountManager = new Lang.Class({
_allowAutorunExpire: function(volume) { _allowAutorunExpire: function(volume) {
Mainloop.timeout_add_seconds(AUTORUN_EXPIRE_TIMEOUT_SECS, function() { Mainloop.timeout_add_seconds(AUTORUN_EXPIRE_TIMEOUT_SECS, function() {
volume.allowAutorun = false; volume.allowAutorun = false;
return false; return GLib.SOURCE_REMOVE;
}); });
} }
}); });

View File

@ -64,7 +64,7 @@ function startAppForMount(app, mount) {
try { try {
retval = app.launch(files, retval = app.launch(files,
global.create_app_launch_context()) global.create_app_launch_context(0, -1))
} catch (e) { } catch (e) {
log('Unable to launch the application ' + app.get_name() log('Unable to launch the application ' + app.get_name()
+ ': ' + e.toString()); + ': ' + e.toString());

View File

@ -45,7 +45,9 @@ const KeyringDialog = new Lang.Class({
this.prompt.bind_property('message', subject, 'text', GObject.BindingFlags.SYNC_CREATE); this.prompt.bind_property('message', subject, 'text', GObject.BindingFlags.SYNC_CREATE);
this._messageBox.add(subject, this._messageBox.add(subject,
{ y_fill: false, { x_fill: false,
y_fill: false,
x_align: St.Align.START,
y_align: St.Align.START }); y_align: St.Align.START });
let description = new St.Label({ style_class: 'prompt-dialog-description' }); let description = new St.Label({ style_class: 'prompt-dialog-description' });
@ -136,6 +138,7 @@ const KeyringDialog = new Lang.Class({
warning.clutter_text.ellipsize = Pango.EllipsizeMode.NONE; warning.clutter_text.ellipsize = Pango.EllipsizeMode.NONE;
warning.clutter_text.line_wrap = true; warning.clutter_text.line_wrap = true;
layout.pack(warning, 1, row); layout.pack(warning, 1, row);
layout.child_set(warning, { x_fill: false, x_align: Clutter.TableAlignment.START });
this.prompt.bind_property('warning-visible', warning, 'visible', GObject.BindingFlags.SYNC_CREATE); this.prompt.bind_property('warning-visible', warning, 'visible', GObject.BindingFlags.SYNC_CREATE);
this.prompt.bind_property('warning', warning, 'text', GObject.BindingFlags.SYNC_CREATE); this.prompt.bind_property('warning', warning, 'text', GObject.BindingFlags.SYNC_CREATE);

View File

@ -255,6 +255,7 @@ const NetworkSecretDialog = new Lang.Class({
case 'leap': case 'leap':
case 'ttls': case 'ttls':
case 'peap': case 'peap':
case 'fast':
// TTLS and PEAP are actually much more complicated, but this complication // TTLS and PEAP are actually much more complicated, but this complication
// is not visible here since we only care about phase2 authentication // is not visible here since we only care about phase2 authentication
// (and don't even care of which one) // (and don't even care of which one)
@ -308,7 +309,7 @@ const NetworkSecretDialog = new Lang.Class({
wirelessSetting = this._connection.get_setting_wireless(); wirelessSetting = this._connection.get_setting_wireless();
ssid = NetworkManager.utils_ssid_to_utf8(wirelessSetting.get_ssid()); ssid = NetworkManager.utils_ssid_to_utf8(wirelessSetting.get_ssid());
content.title = _("Authentication required by wireless network"); content.title = _("Authentication required by wireless network");
content.message = _("Passwords or encryption keys are required to access the wireless network '%s'.").format(ssid); content.message = _("Passwords or encryption keys are required to access the wireless network %s.").format(ssid);
this._getWirelessSecrets(content.secrets, wirelessSetting); this._getWirelessSecrets(content.secrets, wirelessSetting);
break; break;
case '802-3-ethernet': case '802-3-ethernet':
@ -335,7 +336,7 @@ const NetworkSecretDialog = new Lang.Class({
case 'cdma': case 'cdma':
case 'bluetooth': case 'bluetooth':
content.title = _("Mobile broadband network password"); content.title = _("Mobile broadband network password");
content.message = _("A password is required to connect to '%s'.").format(connectionSetting.get_id()); content.message = _("A password is required to connect to %s.").format(connectionSetting.get_id());
this._getMobileSecrets(content.secrets, connectionType); this._getMobileSecrets(content.secrets, connectionType);
break; break;
default: default:

View File

@ -54,7 +54,9 @@ const AuthenticationDialog = new Lang.Class({
text: _("Authentication Required") }); text: _("Authentication Required") });
messageBox.add(this._subjectLabel, messageBox.add(this._subjectLabel,
{ y_fill: false, { x_fill: false,
y_fill: false,
x_align: St.Align.START,
y_align: St.Align.START }); y_align: St.Align.START });
this._descriptionLabel = new St.Label({ style_class: 'prompt-dialog-description', this._descriptionLabel = new St.Label({ style_class: 'prompt-dialog-description',
@ -63,7 +65,9 @@ const AuthenticationDialog = new Lang.Class({
this._descriptionLabel.clutter_text.line_wrap = true; this._descriptionLabel.clutter_text.line_wrap = true;
messageBox.add(this._descriptionLabel, messageBox.add(this._descriptionLabel,
{ y_fill: true, { x_fill: false,
y_fill: true,
x_align: St.Align.START,
y_align: St.Align.START }); y_align: St.Align.START });
if (userNames.length > 1) { if (userNames.length > 1) {
@ -95,7 +99,8 @@ const AuthenticationDialog = new Lang.Class({
if (userIsRoot) { if (userIsRoot) {
let userLabel = new St.Label(({ style_class: 'polkit-dialog-user-root-label', let userLabel = new St.Label(({ style_class: 'polkit-dialog-user-root-label',
text: userRealName })); text: userRealName }));
messageBox.add(userLabel); messageBox.add(userLabel, { x_fill: false,
x_align: St.Align.START });
} else { } else {
let userBox = new St.BoxLayout({ style_class: 'polkit-dialog-user-layout', let userBox = new St.BoxLayout({ style_class: 'polkit-dialog-user-layout',
vertical: false }); vertical: false });
@ -137,7 +142,7 @@ const AuthenticationDialog = new Lang.Class({
this._errorMessageLabel = new St.Label({ style_class: 'prompt-dialog-error-label' }); this._errorMessageLabel = new St.Label({ style_class: 'prompt-dialog-error-label' });
this._errorMessageLabel.clutter_text.ellipsize = Pango.EllipsizeMode.NONE; this._errorMessageLabel.clutter_text.ellipsize = Pango.EllipsizeMode.NONE;
this._errorMessageLabel.clutter_text.line_wrap = true; this._errorMessageLabel.clutter_text.line_wrap = true;
messageBox.add(this._errorMessageLabel); messageBox.add(this._errorMessageLabel, { x_fill: false, x_align: St.Align.START });
this._errorMessageLabel.hide(); this._errorMessageLabel.hide();
this._infoMessageLabel = new St.Label({ style_class: 'prompt-dialog-info-label' }); this._infoMessageLabel = new St.Label({ style_class: 'prompt-dialog-info-label' });

View File

@ -621,7 +621,11 @@ const ChatSource = new Lang.Class({
this.notify(); this.notify();
}, },
_channelClosed: function() { destroy: function(reason) {
if (this._destroyed)
return;
this._destroyed = true;
this._channel.disconnect(this._closedId); this._channel.disconnect(this._closedId);
this._channel.disconnect(this._receivedId); this._channel.disconnect(this._receivedId);
this._channel.disconnect(this._pendingId); this._channel.disconnect(this._pendingId);
@ -631,7 +635,14 @@ const ChatSource = new Lang.Class({
this._contact.disconnect(this._notifyAvatarId); this._contact.disconnect(this._notifyAvatarId);
this._contact.disconnect(this._presenceChangedId); this._contact.disconnect(this._presenceChangedId);
this.destroy(); if (this._timestampTimeoutId)
Mainloop.source_remove(this._timestampTimeoutId);
this.parent(reason);
},
_channelClosed: function() {
this.destroy(MessageTray.NotificationDestroyedReason.SOURCE_CLOSED);
}, },
/* All messages are new messages for Telepathy sources */ /* All messages are new messages for Telepathy sources */
@ -675,7 +686,7 @@ const ChatSource = new Lang.Class({
this._notifyTimeoutId = 0; this._notifyTimeoutId = 0;
return false; return GLib.SOURCE_REMOVE;
}, },
// This is called for both messages we send from // This is called for both messages we send from
@ -975,7 +986,7 @@ const ChatNotification = new Lang.Class({
this._filterMessages(); this._filterMessages();
return false; return GLib.SOURCE_REMOVE;
}, },
appendAliasChange: function(oldAlias, newAlias) { appendAliasChange: function(oldAlias, newAlias) {
@ -1013,7 +1024,7 @@ const ChatNotification = new Lang.Class({
this.source.setChatState(Tp.ChannelChatState.PAUSED); this.source.setChatState(Tp.ChannelChatState.PAUSED);
return false; return GLib.SOURCE_REMOVE;
}, },
_onEntryChanged: function() { _onEntryChanged: function() {
@ -1339,7 +1350,7 @@ const AccountNotification = new Lang.Class({
let cmd = 'empathy-accounts --select-account=' + let cmd = 'empathy-accounts --select-account=' +
account.get_path_suffix(); account.get_path_suffix();
let app_info = Gio.app_info_create_from_commandline(cmd, null, 0); let app_info = Gio.app_info_create_from_commandline(cmd, null, 0);
app_info.launch([], global.create_app_launch_context()); app_info.launch([], global.create_app_launch_context(0, -1));
})); }));
this._enabledId = account.connect('notify::enabled', this._enabledId = account.connect('notify::enabled',

View File

@ -1,6 +1,7 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
const Clutter = imports.gi.Clutter; const Clutter = imports.gi.Clutter;
const GLib = imports.gi.GLib;
const Signals = imports.signals; const Signals = imports.signals;
const Lang = imports.lang; const Lang = imports.lang;
const Meta = imports.gi.Meta; const Meta = imports.gi.Meta;
@ -577,7 +578,7 @@ const Dash = new Lang.Class({
this._labelShowing = true; this._labelShowing = true;
item.showLabel(); item.showLabel();
this._showLabelTimeoutId = 0; this._showLabelTimeoutId = 0;
return false; return GLib.SOURCE_REMOVE;
})); }));
if (this._resetHoverTimeoutId > 0) { if (this._resetHoverTimeoutId > 0) {
Mainloop.source_remove(this._resetHoverTimeoutId); Mainloop.source_remove(this._resetHoverTimeoutId);
@ -594,7 +595,7 @@ const Dash = new Lang.Class({
Lang.bind(this, function() { Lang.bind(this, function() {
this._labelShowing = false; this._labelShowing = false;
this._resetHoverTimeoutId = 0; this._resetHoverTimeoutId = 0;
return false; return GLib.SOURCE_REMOVE;
})); }));
} }
} }

View File

@ -113,22 +113,7 @@ const DateMenuButton = new Lang.Class({
this.menu.connect('open-state-changed', Lang.bind(this, function(menu, isOpen) { this.menu.connect('open-state-changed', Lang.bind(this, function(menu, isOpen) {
if (isOpen) { if (isOpen) {
let now = new Date(); let now = new Date();
/* Passing true to setDate() forces events to be reloaded. We this._calendar.setDate(now);
* want this behavior, because
*
* o It will cause activation of the calendar server which is
* useful if it has crashed
*
* o It will cause the calendar server to reload events which
* is useful if dynamic updates are not supported or not
* properly working
*
* Since this only happens when the menu is opened, the cost
* isn't very big.
*/
this._calendar.setDate(now, true);
// No need to update this._eventList as ::selected-date-changed
// signal will fire
} }
})); }));
@ -226,7 +211,7 @@ const DateMenuButton = new Lang.Class({
let app = this._getCalendarApp(); let app = this._getCalendarApp();
if (app.get_id() == 'evolution.desktop') if (app.get_id() == 'evolution.desktop')
app = Gio.DesktopAppInfo.new('evolution-calendar.desktop'); app = Gio.DesktopAppInfo.new('evolution-calendar.desktop');
app.launch([], global.create_app_launch_context()); app.launch([], global.create_app_launch_context(0, -1));
}, },
_onOpenClocksActivate: function() { _onOpenClocksActivate: function() {

View File

@ -46,7 +46,7 @@ let dragMonitors = [];
function _getEventHandlerActor() { function _getEventHandlerActor() {
if (!eventHandlerActor) { if (!eventHandlerActor) {
eventHandlerActor = new Clutter.Actor({ width: 0, height: 0 }); eventHandlerActor = new Clutter.Actor({ width: 0, height: 0 });
Main.uiGroup.add_actor(eventHandlerActor); Main.layoutManager.sessionGroup.add_actor(eventHandlerActor);
// We connect to 'event' rather than 'captured-event' because the capturing phase doesn't happen // We connect to 'event' rather than 'captured-event' because the capturing phase doesn't happen
// when you've grabbed the pointer. // when you've grabbed the pointer.
eventHandlerActor.connect('event', eventHandlerActor.connect('event',
@ -106,10 +106,10 @@ const _Draggable = new Lang.Class({
_onButtonPress : function (actor, event) { _onButtonPress : function (actor, event) {
if (event.get_button() != 1) if (event.get_button() != 1)
return false; return Clutter.EVENT_PROPAGATE;
if (Tweener.getTweenCount(actor)) if (Tweener.getTweenCount(actor))
return false; return Clutter.EVENT_PROPAGATE;
this._buttonDown = true; this._buttonDown = true;
this._grabActor(); this._grabActor();
@ -118,7 +118,7 @@ const _Draggable = new Lang.Class({
this._dragStartX = stageX; this._dragStartX = stageX;
this._dragStartY = stageY; this._dragStartY = stageY;
return false; return Clutter.EVENT_PROPAGATE;
}, },
_grabActor: function() { _grabActor: function() {
@ -164,11 +164,11 @@ const _Draggable = new Lang.Class({
} else if (this._dragActor != null && !this._animationInProgress) { } else if (this._dragActor != null && !this._animationInProgress) {
// Drag must have been cancelled with Esc. // Drag must have been cancelled with Esc.
this._dragComplete(); this._dragComplete();
return true; return Clutter.EVENT_STOP;
} else { } else {
// Drag has never started. // Drag has never started.
this._ungrabActor(); this._ungrabActor();
return false; return Clutter.EVENT_PROPAGATE;
} }
// We intercept MOTION event to figure out if the drag has started and to draw // We intercept MOTION event to figure out if the drag has started and to draw
// this._dragActor under the pointer when dragging is in progress // this._dragActor under the pointer when dragging is in progress
@ -184,11 +184,11 @@ const _Draggable = new Lang.Class({
let symbol = event.get_key_symbol(); let symbol = event.get_key_symbol();
if (symbol == Clutter.Escape) { if (symbol == Clutter.Escape) {
this._cancelDrag(event.get_time()); this._cancelDrag(event.get_time());
return true; return Clutter.EVENT_STOP;
} }
} }
return false; return Clutter.EVENT_PROPAGATE;
}, },
/** /**
@ -236,7 +236,7 @@ const _Draggable = new Lang.Class({
if (this.actor._delegate && this.actor._delegate.getDragActor) { if (this.actor._delegate && this.actor._delegate.getDragActor) {
this._dragActor = this.actor._delegate.getDragActor(); this._dragActor = this.actor._delegate.getDragActor();
Main.uiGroup.add_child(this._dragActor); Main.layoutManager.sessionGroup.add_child(this._dragActor);
this._dragActor.raise_top(); this._dragActor.raise_top();
Shell.util_set_hidden_from_pick(this._dragActor, true); Shell.util_set_hidden_from_pick(this._dragActor, true);
@ -276,7 +276,7 @@ const _Draggable = new Lang.Class({
this._dragOrigScale = this._dragActor.scale_x; this._dragOrigScale = this._dragActor.scale_x;
// Set the actor's scale such that it will keep the same // Set the actor's scale such that it will keep the same
// transformed size when it's reparented to the uiGroup // transformed size when it's reparented to the sessionGroup
let [scaledWidth, scaledHeight] = this.actor.get_transformed_size(); let [scaledWidth, scaledHeight] = this.actor.get_transformed_size();
this._dragActor.set_scale(scaledWidth / this.actor.width, this._dragActor.set_scale(scaledWidth / this.actor.width,
scaledHeight / this.actor.height); scaledHeight / this.actor.height);
@ -286,7 +286,7 @@ const _Draggable = new Lang.Class({
this._dragOffsetY = actorStageY - this._dragStartY; this._dragOffsetY = actorStageY - this._dragStartY;
this._dragOrigParent.remove_actor(this._dragActor); this._dragOrigParent.remove_actor(this._dragActor);
Main.uiGroup.add_child(this._dragActor); Main.layoutManager.sessionGroup.add_child(this._dragActor);
this._dragActor.raise_top(); this._dragActor.raise_top();
Shell.util_set_hidden_from_pick(this._dragActor, true); Shell.util_set_hidden_from_pick(this._dragActor, true);
} }
@ -362,7 +362,7 @@ const _Draggable = new Lang.Class({
let result = motionFunc(dragEvent); let result = motionFunc(dragEvent);
if (result != DragMotionResult.CONTINUE) { if (result != DragMotionResult.CONTINUE) {
global.screen.set_cursor(DRAG_CURSOR_MAP[result]); global.screen.set_cursor(DRAG_CURSOR_MAP[result]);
return false; return GLib.SOURCE_REMOVE;
} }
} }
} }
@ -380,13 +380,13 @@ const _Draggable = new Lang.Class({
0); 0);
if (result != DragMotionResult.CONTINUE) { if (result != DragMotionResult.CONTINUE) {
global.screen.set_cursor(DRAG_CURSOR_MAP[result]); global.screen.set_cursor(DRAG_CURSOR_MAP[result]);
return false; return GLib.SOURCE_REMOVE;
} }
} }
target = target.get_parent(); target = target.get_parent();
} }
global.screen.set_cursor(Meta.Cursor.DND_IN_DRAG); global.screen.set_cursor(Meta.Cursor.DND_IN_DRAG);
return false; return GLib.SOURCE_REMOVE;
}, },
_queueUpdateDragHover: function() { _queueUpdateDragHover: function() {
@ -448,7 +448,7 @@ const _Draggable = new Lang.Class({
event.get_time())) { event.get_time())) {
// If it accepted the drop without taking the actor, // If it accepted the drop without taking the actor,
// handle it ourselves. // handle it ourselves.
if (this._dragActor.get_parent() == Main.uiGroup) { if (this._dragActor.get_parent() == Main.layoutManager.sessionGroup) {
if (this._restoreOnSuccess) { if (this._restoreOnSuccess) {
this._restoreDragActor(event.get_time()); this._restoreDragActor(event.get_time());
return true; return true;
@ -557,7 +557,7 @@ const _Draggable = new Lang.Class({
_onAnimationComplete : function (dragActor, eventTime) { _onAnimationComplete : function (dragActor, eventTime) {
if (this._dragOrigParent) { if (this._dragOrigParent) {
Main.uiGroup.remove_child(this._dragActor); Main.layoutManager.sessionGroup.remove_child(this._dragActor);
this._dragOrigParent.add_actor(this._dragActor); this._dragOrigParent.add_actor(this._dragActor);
dragActor.set_scale(this._dragOrigScale, this._dragOrigScale); dragActor.set_scale(this._dragOrigScale, this._dragOrigScale);
dragActor.set_position(this._dragOrigX, this._dragOrigY); dragActor.set_position(this._dragOrigX, this._dragOrigY);

View File

@ -13,9 +13,7 @@
* GNU General Public License for more details. * GNU General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software * along with this program; if not, see <http://www.gnu.org/licenses/>.
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*/ */
const Lang = imports.lang; const Lang = imports.lang;
@ -249,7 +247,9 @@ const EndSessionDialog = new Lang.Class({
this._subjectLabel = new St.Label({ style_class: 'end-session-dialog-subject' }); this._subjectLabel = new St.Label({ style_class: 'end-session-dialog-subject' });
messageLayout.add(this._subjectLabel, messageLayout.add(this._subjectLabel,
{ y_fill: false, { x_fill: false,
y_fill: false,
x_align: St.Align.START,
y_align: St.Align.START }); y_align: St.Align.START });
this._descriptionLabel = new St.Label({ style_class: 'end-session-dialog-description' }); this._descriptionLabel = new St.Label({ style_class: 'end-session-dialog-description' });
@ -409,7 +409,7 @@ const EndSessionDialog = new Lang.Class({
this._secondsLeft = this._totalSecondsToStayOpen - secondsElapsed; this._secondsLeft = this._totalSecondsToStayOpen - secondsElapsed;
if (this._secondsLeft > 0) { if (this._secondsLeft > 0) {
this._sync(); this._sync();
return true; return GLib.SOURCE_CONTINUE;
} }
let dialogContent = DialogContent[this._type]; let dialogContent = DialogContent[this._type];
@ -417,7 +417,7 @@ const EndSessionDialog = new Lang.Class({
this._confirm(button.signal); this._confirm(button.signal);
this._timerId = 0; this._timerId = 0;
return false; return GLib.SOURCE_REMOVE;
})); }));
}, },

View File

@ -201,7 +201,7 @@ const InstallExtensionDialog = new Lang.Class({
default: true default: true
}]); }]);
let message = _("Download and install '%s' from extensions.gnome.org?").format(info.name); let message = _("Download and install %s from extensions.gnome.org?").format(info.name);
let box = new St.BoxLayout(); let box = new St.BoxLayout();
this.contentLayout.add(box); this.contentLayout.add(box);

View File

@ -280,7 +280,7 @@ const GrabHelper = new Lang.Class({
if (type == Clutter.EventType.KEY_PRESS && if (type == Clutter.EventType.KEY_PRESS &&
event.get_key_symbol() == Clutter.KEY_Escape) { event.get_key_symbol() == Clutter.KEY_Escape) {
this.ungrab({ isUser: true }); this.ungrab({ isUser: true });
return true; return Clutter.EVENT_STOP;
} }
let press = type == Clutter.EventType.BUTTON_PRESS; let press = type == Clutter.EventType.BUTTON_PRESS;
@ -289,14 +289,14 @@ const GrabHelper = new Lang.Class({
if (release && this._ignoreRelease) { if (release && this._ignoreRelease) {
this._ignoreRelease = false; this._ignoreRelease = false;
return true; return Clutter.EVENT_STOP;
} }
if (this._isWithinGrabbedActor(event.get_source())) if (this._isWithinGrabbedActor(event.get_source()))
return false; return Clutter.EVENT_PROPAGATE;
if (Main.keyboard.shouldTakeEvent(event)) if (Main.keyboard.shouldTakeEvent(event))
return false; return Clutter.EVENT_PROPAGATE;
if (button) { if (button) {
// If we have a press event, ignore the next event, // If we have a press event, ignore the next event,
@ -305,9 +305,9 @@ const GrabHelper = new Lang.Class({
this._ignoreRelease = true; this._ignoreRelease = true;
let i = this._actorInGrabStack(event.get_source()) + 1; let i = this._actorInGrabStack(event.get_source()) + 1;
this.ungrab({ actor: this._grabStack[i].actor, isUser: true }); this.ungrab({ actor: this._grabStack[i].actor, isUser: true });
return true; return Clutter.EVENT_STOP;
} }
return true; return Clutter.EVENT_STOP;
}, },
}); });

View File

@ -32,6 +32,7 @@ const CandidateArea = new Lang.Class({
let j = i; let j = i;
box.connect('button-release-event', Lang.bind(this, function(actor, event) { box.connect('button-release-event', Lang.bind(this, function(actor, event) {
this.emit('candidate-clicked', j, event.get_button(), event.get_state()); this.emit('candidate-clicked', j, event.get_button(), event.get_state());
return Clutter.EVENT_PROPAGATE;
})); }));
} }
@ -114,9 +115,6 @@ const CandidatePopup = new Lang.Class({
Name: 'CandidatePopup', Name: 'CandidatePopup',
_init: function() { _init: function() {
this._cursor = new St.Bin({ opacity: 0 });
Main.uiGroup.add_actor(this._cursor);
this._boxPointer = new BoxPointer.BoxPointer(St.Side.TOP); this._boxPointer = new BoxPointer.BoxPointer(St.Side.TOP);
this._boxPointer.actor.visible = false; this._boxPointer.actor.visible = false;
this._boxPointer.actor.style_class = 'candidate-popup-boxpointer'; this._boxPointer.actor.style_class = 'candidate-popup-boxpointer';
@ -157,10 +155,9 @@ const CandidatePopup = new Lang.Class({
panelService.connect('set-cursor-location', panelService.connect('set-cursor-location',
Lang.bind(this, function(ps, x, y, w, h) { Lang.bind(this, function(ps, x, y, w, h) {
this._cursor.set_position(x, y); Main.layoutManager.setDummyCursorPosition(x, y);
this._cursor.set_size(w, h);
if (this._boxPointer.actor.visible) if (this._boxPointer.actor.visible)
this._boxPointer.setPosition(this._cursor, 0); this._boxPointer.setPosition(Main.layoutManager.dummyCursor, 0);
})); }));
panelService.connect('update-preedit-text', panelService.connect('update-preedit-text',
Lang.bind(this, function(ps, text, cursorPosition, visible) { Lang.bind(this, function(ps, text, cursorPosition, visible) {
@ -252,7 +249,7 @@ const CandidatePopup = new Lang.Class({
this._candidateArea.actor.visible); this._candidateArea.actor.visible);
if (isVisible) { if (isVisible) {
this._boxPointer.setPosition(this._cursor, 0); this._boxPointer.setPosition(Main.layoutManager.dummyCursor, 0);
this._boxPointer.show(BoxPointer.PopupAnimation.NONE); this._boxPointer.show(BoxPointer.PopupAnimation.NONE);
this._boxPointer.actor.raise_top(); this._boxPointer.actor.raise_top();
} else { } else {

View File

@ -433,6 +433,10 @@ const IconGrid = new Lang.Class({
this._grid.add_actor(item.actor); this._grid.add_actor(item.actor);
}, },
removeItem: function(item) {
this._grid.remove_child(item.actor);
},
getItemAtIndex: function(index) { getItemAtIndex: function(index) {
return this._grid.get_child_at_index(index); return this._grid.get_child_at_index(index);
}, },

View File

@ -82,8 +82,16 @@ const Key = new Lang.Class({
style_class: 'keyboard-key' }); style_class: 'keyboard-key' });
button.key_width = this._key.width; button.key_width = this._key.width;
button.connect('button-press-event', Lang.bind(this, function () { this._key.press(); })); button.connect('button-press-event', Lang.bind(this,
button.connect('button-release-event', Lang.bind(this, function () { this._key.release(); })); function () {
this._key.press();
return Clutter.EVENT_PROPAGATE;
}));
button.connect('button-release-event', Lang.bind(this,
function () {
this._key.release();
return Clutter.EVENT_PROPAGATE;
}));
return button; return button;
}, },
@ -106,8 +114,16 @@ const Key = new Lang.Class({
let label = this._getUnichar(extended_key); let label = this._getUnichar(extended_key);
let key = new St.Button({ label: label, style_class: 'keyboard-key' }); let key = new St.Button({ label: label, style_class: 'keyboard-key' });
key.extended_key = extended_key; key.extended_key = extended_key;
key.connect('button-press-event', Lang.bind(this, function () { extended_key.press(); })); key.connect('button-press-event', Lang.bind(this,
key.connect('button-release-event', Lang.bind(this, function () { extended_key.release(); })); 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._extended_keyboard.add(key);
} }
this._boxPointer.bin.add_actor(this._extended_keyboard); this._boxPointer.bin.add_actor(this._extended_keyboard);
@ -252,7 +268,10 @@ const Keyboard = new Lang.Class({
if (!this._showIdleId) if (!this._showIdleId)
this._showIdleId = GLib.idle_add(GLib.PRIORITY_DEFAULT_IDLE, this._showIdleId = GLib.idle_add(GLib.PRIORITY_DEFAULT_IDLE,
Lang.bind(this, function() { this.Show(time); })); Lang.bind(this, function() {
this.Show(time);
return GLib.SOURCE_REMOVE;
}));
}, },
_createLayersForGroup: function (gname) { _createLayersForGroup: function (gname) {
@ -294,7 +313,7 @@ const Keyboard = new Lang.Class({
else if (release && this._capturedPress) else if (release && this._capturedPress)
this._hideSubkeys(); this._hideSubkeys();
return true; return Clutter.EVENT_STOP;
}, },
_addRows : function (keys, layout) { _addRows : function (keys, layout) {
@ -438,7 +457,6 @@ const Keyboard = new Lang.Class({
_createSource: function () { _createSource: function () {
if (this._source == null) { if (this._source == null) {
this._source = new KeyboardSource(this); this._source = new KeyboardSource(this);
this._source.setTransient(true);
Main.messageTray.add(this._source); Main.messageTray.add(this._source);
} }
}, },
@ -480,6 +498,7 @@ const Keyboard = new Lang.Class({
Lang.bind(this, function() { Lang.bind(this, function() {
this._clearKeyboardRestTimer(); this._clearKeyboardRestTimer();
this._show(monitor); this._show(monitor);
return GLib.SOURCE_REMOVE;
})); }));
}, },
@ -505,6 +524,7 @@ const Keyboard = new Lang.Class({
Lang.bind(this, function() { Lang.bind(this, function() {
this._clearKeyboardRestTimer(); this._clearKeyboardRestTimer();
this._hide(); this._hide();
return GLib.SOURCE_REMOVE;
})); }));
}, },

View File

@ -162,9 +162,9 @@ const LayoutManager = new Lang.Class({
this._startingUp = true; this._startingUp = true;
// Normally, the stage is always covered so Clutter doesn't need to clear // Normally, the stage is always covered so Clutter doesn't need to clear
// it; however it becomes visible during the startup animation // it; however it becomes visible when using the magnifier.
// See the comment below for a longer explanation
global.stage.color = DEFAULT_BACKGROUND_COLOR; global.stage.color = DEFAULT_BACKGROUND_COLOR;
global.stage.no_clear_hint = true;
// Set up stage hierarchy to group all UI actors under one container. // Set up stage hierarchy to group all UI actors under one container.
this.uiGroup = new Shell.GenericContainer({ name: 'uiGroup' }); this.uiGroup = new Shell.GenericContainer({ name: 'uiGroup' });
@ -184,29 +184,27 @@ const LayoutManager = new Lang.Class({
let height = global.stage.height; let height = global.stage.height;
[alloc.min_size, alloc.natural_size] = [height, height]; [alloc.min_size, alloc.natural_size] = [height, height];
}); });
global.stage.add_child(this.uiGroup);
this.systemGroup = new St.Widget({ name: 'systemGroup',
layout_manager: new Clutter.BinLayout() });
this.uiGroup.add_actor(this.systemGroup);
this.sessionGroup = new St.Widget({ name: 'sessionGroup' });
this.uiGroup.add_child(this.sessionGroup);
global.stage.remove_actor(global.window_group); global.stage.remove_actor(global.window_group);
this.uiGroup.add_actor(global.window_group); this.sessionGroup.add_actor(global.window_group);
global.stage.add_child(this.uiGroup);
this.overviewGroup = new St.Widget({ name: 'overviewGroup', this.overviewGroup = new St.Widget({ name: 'overviewGroup',
visible: false }); visible: false });
this.addChrome(this.overviewGroup); this.addChrome(this.overviewGroup);
this.screenShieldGroup = new St.Widget({ name: 'screenShieldGroup', this.screenShieldGroup = new St.Widget({ name: 'screenShieldGroup',
visible: false,
clip_to_allocation: true, clip_to_allocation: true,
layout_manager: new Clutter.BinLayout(), layout_manager: new Clutter.BinLayout(),
}); });
this.addChrome(this.screenShieldGroup); this.uiGroup.add_child(this.screenShieldGroup);
this.panelBox = new St.BoxLayout({ name: 'panelBox',
vertical: true });
this.addChrome(this.panelBox, { affectsStruts: true,
trackFullscreen: true });
this.panelBox.connect('allocation-changed',
Lang.bind(this, this._panelBoxChanged));
this.trayBox = new St.Widget({ name: 'trayBox', this.trayBox = new St.Widget({ name: 'trayBox',
layout_manager: new Clutter.BinLayout() }); layout_manager: new Clutter.BinLayout() });
@ -219,8 +217,39 @@ const LayoutManager = new Lang.Class({
this.addChrome(this.keyboardBox); this.addChrome(this.keyboardBox);
this._keyboardHeightNotifyId = 0; this._keyboardHeightNotifyId = 0;
global.stage.remove_actor(global.top_window_group); this.osdGroup = new St.Widget();
this.uiGroup.add_actor(global.top_window_group); this.sessionGroup.add_child(this.osdGroup);
this.switcherPopupGroup = new St.Widget();
this.sessionGroup.add_child(this.switcherPopupGroup);
this.dialogGroup = new St.Widget();
this.sessionGroup.add_child(this.dialogGroup);
// A dummy actor that tracks the mouse or text cursor, based on the
// position set in setDummyCursorPosition.
this.dummyCursor = new St.Widget({ width: 0, height: 0 });
this.uiGroup.add_child(this.dummyCursor);
// The panel group isn't in the session, as it needs to go above the screen
// shield, and it isn't animated in the login animation.
this.panelGroup = new St.Widget({ name: 'panelGroup' });
this.uiGroup.add_child(this.panelGroup);
this._trackActor(this.panelGroup, { affectsStruts: true,
trackFullscreen: true });
this.panelGroup.connect('allocation-changed',
Lang.bind(this, this._panelGroupChanged));
this.overlayGroup = new St.Widget({ name: 'overlayGroup' });
this.uiGroup.add_child(this.overlayGroup);
this.menuGroup = new St.Widget();
this.overlayGroup.add_child(this.menuGroup);
this._topSessionGroup = new St.Widget();
this.overlayGroup.add_child(this._topSessionGroup);
global.stage.remove_child(global.top_window_group);
this._topSessionGroup.add_child(global.top_window_group);
this._backgroundGroup = new Meta.BackgroundGroup(); this._backgroundGroup = new Meta.BackgroundGroup();
global.window_group.add_child(this._backgroundGroup); global.window_group.add_child(this._backgroundGroup);
@ -242,8 +271,7 @@ const LayoutManager = new Lang.Class({
// This is called by Main after everything else is constructed // This is called by Main after everything else is constructed
init: function() { init: function() {
Main.sessionMode.connect('updated', Lang.bind(this, this._sessionUpdated)); Main.sessionMode.connect('updated', Lang.bind(this, this._sessionUpdated));
this._prepareStartupAnimation();
this._loadBackground();
}, },
showOverview: function() { showOverview: function() {
@ -252,6 +280,9 @@ const LayoutManager = new Lang.Class({
this._inOverview = true; this._inOverview = true;
this._updateVisibility(); this._updateVisibility();
this._updateRegions(); this._updateRegions();
global.window_group.hide();
global.top_window_group.hide();
}, },
hideOverview: function() { hideOverview: function() {
@ -260,6 +291,9 @@ const LayoutManager = new Lang.Class({
this._inOverview = false; this._inOverview = false;
this._updateVisibility(); this._updateVisibility();
this._queueUpdateRegions(); this._queueUpdateRegions();
global.window_group.show();
global.top_window_group.show();
}, },
_sessionUpdated: function() { _sessionUpdated: function() {
@ -301,7 +335,7 @@ const LayoutManager = new Lang.Class({
}); });
this.hotCorners = []; this.hotCorners = [];
let size = this.panelBox.height; let size = this.panelGroup.height;
// build new hot corners // build new hot corners
for (let i = 0; i < this.monitors.length; i++) { for (let i = 0; i < this.monitors.length; i++) {
@ -352,26 +386,26 @@ const LayoutManager = new Lang.Class({
this.emit('hot-corners-changed'); this.emit('hot-corners-changed');
}, },
_createBackground: function(monitorIndex) { _addBackgroundMenu: function(bgManager) {
BackgroundMenu.addBackgroundMenu(bgManager.background.actor, this);
},
_createBackgroundManager: function(monitorIndex) {
let bgManager = new Background.BackgroundManager({ container: this._backgroundGroup, let bgManager = new Background.BackgroundManager({ container: this._backgroundGroup,
layoutManager: this, layoutManager: this,
monitorIndex: monitorIndex }); monitorIndex: monitorIndex });
BackgroundMenu.addBackgroundMenu(bgManager.background.actor);
bgManager.connect('changed', Lang.bind(this, function() { bgManager.connect('changed', Lang.bind(this, this._addBackgroundMenu));
BackgroundMenu.addBackgroundMenu(bgManager.background.actor); this._addBackgroundMenu(bgManager);
}));
this._bgManagers[monitorIndex] = bgManager; return bgManager;
return bgManager.background;
}, },
_createSecondaryBackgrounds: function() { _showSecondaryBackgrounds: function() {
for (let i = 0; i < this.monitors.length; i++) { for (let i = 0; i < this.monitors.length; i++) {
if (i != this.primaryIndex) { if (i != this.primaryIndex) {
let background = this._createBackground(i); let background = this._bgManagers[i].background;
background.actor.show();
background.actor.opacity = 0; background.actor.opacity = 0;
Tweener.addTween(background.actor, Tweener.addTween(background.actor,
{ opacity: 255, { opacity: 255,
@ -381,10 +415,6 @@ const LayoutManager = new Lang.Class({
} }
}, },
_createPrimaryBackground: function() {
this._createBackground(this.primaryIndex);
},
_updateBackgrounds: function() { _updateBackgrounds: function() {
let i; let i;
for (i = 0; i < this._bgManagers.length; i++) for (i = 0; i < this._bgManagers.length; i++)
@ -395,20 +425,21 @@ const LayoutManager = new Lang.Class({
if (Main.sessionMode.isGreeter) if (Main.sessionMode.isGreeter)
return; return;
if (this._startingUp)
return;
for (let i = 0; i < this.monitors.length; i++) { for (let i = 0; i < this.monitors.length; i++) {
this._createBackground(i); let bgManager = this._createBackgroundManager(i);
this._bgManagers.push(bgManager);
if (i != this.primaryIndex && this._startingUp)
bgManager.background.actor.hide();
} }
}, },
_updateBoxes: function() { _updateBoxes: function() {
this.screenShieldGroup.set_position(0, 0); this.systemGroup.set_position(0, 0);
this.screenShieldGroup.set_size(global.screen_width, global.screen_height); this.systemGroup.set_size(global.screen_width, global.screen_height);
this.panelBox.set_position(this.primaryMonitor.x, this.primaryMonitor.y); this.panelGroup.set_position(this.primaryMonitor.x, this.primaryMonitor.y);
this.panelBox.set_size(this.primaryMonitor.width, -1); this.panelGroup.set_size(this.primaryMonitor.width, -1);
if (this.keyboardIndex < 0) if (this.keyboardIndex < 0)
this.keyboardIndex = this.primaryIndex; this.keyboardIndex = this.primaryIndex;
@ -418,10 +449,10 @@ const LayoutManager = new Lang.Class({
this.trayBox.set_size(this.bottomMonitor.width, -1); this.trayBox.set_size(this.bottomMonitor.width, -1);
}, },
_panelBoxChanged: function() { _panelGroupChanged: function() {
this._updatePanelBarrier(); this._updatePanelBarrier();
let size = this.panelBox.height; let size = this.panelGroup.height;
this.hotCorners.forEach(function(corner) { this.hotCorners.forEach(function(corner) {
if (corner) if (corner)
corner.setBarrierSize(size); corner.setBarrierSize(size);
@ -434,12 +465,12 @@ const LayoutManager = new Lang.Class({
this._rightPanelBarrier = null; this._rightPanelBarrier = null;
} }
if (this.panelBox.height) { if (this.panelGroup.height) {
let primary = this.primaryMonitor; let primary = this.primaryMonitor;
this._rightPanelBarrier = new Meta.Barrier({ display: global.display, this._rightPanelBarrier = new Meta.Barrier({ display: global.display,
x1: primary.x + primary.width, y1: primary.y, x1: primary.x + primary.width, y1: primary.y,
x2: primary.x + primary.width, y2: primary.y + this.panelBox.height, x2: primary.x + primary.width, y2: primary.y + this.panelGroup.height,
directions: Meta.BarrierDirection.NEGATIVE_X }); directions: Meta.BarrierDirection.NEGATIVE_X });
} }
}, },
@ -545,25 +576,6 @@ const LayoutManager = new Lang.Class({
return this._keyboardIndex; return this._keyboardIndex;
}, },
_loadBackground: function() {
this._systemBackground = new Background.SystemBackground();
this._systemBackground.actor.hide();
global.stage.insert_child_below(this._systemBackground.actor, null);
let constraint = new Clutter.BindConstraint({ source: global.stage,
coordinate: Clutter.BindCoordinate.ALL });
this._systemBackground.actor.add_constraint(constraint);
let signalId = this._systemBackground.connect('loaded', Lang.bind(this, function() {
this._systemBackground.disconnect(signalId);
this._systemBackground.actor.show();
global.stage.show();
this._prepareStartupAnimation();
}));
},
// Startup Animations // Startup Animations
// //
// We have two different animations, depending on whether we're a greeter // We have two different animations, depending on whether we're a greeter
@ -584,6 +596,8 @@ const LayoutManager = new Lang.Class({
// screen. So, we set no_clear_hint at the end of the animation. // screen. So, we set no_clear_hint at the end of the animation.
_prepareStartupAnimation: function() { _prepareStartupAnimation: function() {
global.stage.show();
// During the initial transition, add a simple actor to block all events, // During the initial transition, add a simple actor to block all events,
// so they don't get delivered to X11 windows that have been transformed. // so they don't get delivered to X11 windows that have been transformed.
this._coverPane = new Clutter.Actor({ opacity: 0, this._coverPane = new Clutter.Actor({ opacity: 0,
@ -593,9 +607,9 @@ const LayoutManager = new Lang.Class({
this.addChrome(this._coverPane); this.addChrome(this._coverPane);
if (Main.sessionMode.isGreeter) { if (Main.sessionMode.isGreeter) {
this.panelBox.translation_y = -this.panelBox.height; this.panelGroup.translation_y = -this.panelGroup.height;
} else { } else {
this._createPrimaryBackground(); this._updateBackgrounds();
// We need to force an update of the regions now before we scale // We need to force an update of the regions now before we scale
// the UI group to get the coorect allocation for the struts. // the UI group to get the coorect allocation for the struts.
@ -608,10 +622,10 @@ const LayoutManager = new Lang.Class({
let x = monitor.x + monitor.width / 2.0; let x = monitor.x + monitor.width / 2.0;
let y = monitor.y + monitor.height / 2.0; let y = monitor.y + monitor.height / 2.0;
this.uiGroup.set_pivot_point(x / global.screen_width, this.sessionGroup.set_pivot_point(x / global.screen_width,
y / global.screen_height); y / global.screen_height);
this.uiGroup.scale_x = this.uiGroup.scale_y = 0.5; this.sessionGroup.scale_x = this.sessionGroup.scale_y = 0.75;
this.uiGroup.opacity = 0; this.sessionGroup.opacity = 0;
global.window_group.set_clip(monitor.x, monitor.y, monitor.width, monitor.height); global.window_group.set_clip(monitor.x, monitor.y, monitor.width, monitor.height);
} }
@ -625,7 +639,7 @@ const LayoutManager = new Lang.Class({
// when the system is bogged down // when the system is bogged down
GLib.idle_add(GLib.PRIORITY_LOW, Lang.bind(this, function() { GLib.idle_add(GLib.PRIORITY_LOW, Lang.bind(this, function() {
this._startupAnimation(); this._startupAnimation();
return false; return GLib.SOURCE_REMOVE;
})); }));
}, },
@ -637,7 +651,7 @@ const LayoutManager = new Lang.Class({
}, },
_startupAnimationGreeter: function() { _startupAnimationGreeter: function() {
Tweener.addTween(this.panelBox, Tweener.addTween(this.panelGroup,
{ translation_y: 0, { translation_y: 0,
time: STARTUP_ANIMATION_TIME, time: STARTUP_ANIMATION_TIME,
transition: 'easeOutQuad', transition: 'easeOutQuad',
@ -646,7 +660,7 @@ const LayoutManager = new Lang.Class({
}, },
_startupAnimationSession: function() { _startupAnimationSession: function() {
Tweener.addTween(this.uiGroup, Tweener.addTween(this.sessionGroup,
{ scale_x: 1, { scale_x: 1,
scale_y: 1, scale_y: 1,
opacity: 255, opacity: 255,
@ -657,23 +671,16 @@ const LayoutManager = new Lang.Class({
}, },
_startupAnimationComplete: function() { _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.destroy();
this._coverPane = null; this._coverPane = null;
this._systemBackground.actor.destroy();
this._systemBackground = null;
this._startingUp = false; this._startingUp = false;
this.trayBox.show(); this.trayBox.show();
this.keyboardBox.show(); this.keyboardBox.show();
if (!Main.sessionMode.isGreeter) { if (!Main.sessionMode.isGreeter) {
this._createSecondaryBackgrounds(); this._showSecondaryBackgrounds();
global.window_group.remove_clip(); global.window_group.remove_clip();
} }
@ -723,6 +730,20 @@ const LayoutManager = new Lang.Class({
this._updateRegions(); this._updateRegions();
}, },
// setDummyCursorPosition:
//
// The cursor dummy is a standard widget commonly used for popup
// menus and box pointers to track, as the box pointer API only
// tracks actors. If you want to pop up a menu based on where the
// user clicked, or where the text cursor is, the cursor dummy
// is what you should use. Given that the menu should not track
// the actual mouse pointer as it moves, you need to call this
// function before you show the menu to ensure it is at the right
// position.
setDummyCursorPosition: function(x, y) {
this.dummyCursor.set_position(Math.round(x), Math.round(y));
},
// addChrome: // addChrome:
// @actor: an actor to add to the chrome // @actor: an actor to add to the chrome
// @params: (optional) additional params // @params: (optional) additional params
@ -742,9 +763,9 @@ const LayoutManager = new Lang.Class({
// monitor (it will be hidden whenever a fullscreen window is visible, // monitor (it will be hidden whenever a fullscreen window is visible,
// and shown otherwise) // and shown otherwise)
addChrome: function(actor, params) { addChrome: function(actor, params) {
this.uiGroup.add_actor(actor); this.sessionGroup.add_actor(actor);
if (this.uiGroup.contains(global.top_window_group)) if (this.sessionGroup.contains(global.top_window_group))
this.uiGroup.set_child_below_sibling(actor, global.top_window_group); this.sessionGroup.set_child_below_sibling(actor, global.top_window_group);
this._trackActor(actor, params); this._trackActor(actor, params);
}, },
@ -795,7 +816,7 @@ const LayoutManager = new Lang.Class({
// //
// Removes @actor from the chrome // Removes @actor from the chrome
removeChrome: function(actor) { removeChrome: function(actor) {
this.uiGroup.remove_actor(actor); this.sessionGroup.remove_actor(actor);
this._untrackActor(actor); this._untrackActor(actor);
}, },
@ -814,13 +835,10 @@ const LayoutManager = new Lang.Class({
let actorData = Params.parse(params, defaultParams); let actorData = Params.parse(params, defaultParams);
actorData.actor = actor; actorData.actor = actor;
actorData.isToplevel = actor.get_parent() == this.uiGroup;
actorData.visibleId = actor.connect('notify::visible', actorData.visibleId = actor.connect('notify::visible',
Lang.bind(this, this._queueUpdateRegions)); Lang.bind(this, this._queueUpdateRegions));
actorData.allocationId = actor.connect('notify::allocation', actorData.allocationId = actor.connect('notify::allocation',
Lang.bind(this, this._queueUpdateRegions)); Lang.bind(this, this._queueUpdateRegions));
actorData.parentSetId = actor.connect('parent-set',
Lang.bind(this, this._actorReparented));
// Note that destroying actor will unset its parent, so we don't // Note that destroying actor will unset its parent, so we don't
// need to connect to 'destroy' too. // need to connect to 'destroy' too.
@ -843,29 +861,13 @@ const LayoutManager = new Lang.Class({
this._queueUpdateRegions(); this._queueUpdateRegions();
}, },
_actorReparented: function(actor, oldParent) {
let newParent = actor.get_parent();
if (!newParent) {
this._untrackActor(actor);
} else {
let i = this._findActor(actor);
let actorData = this._trackedActors[i];
actorData.isToplevel = (newParent == this.uiGroup);
}
},
_updateVisibility: function() { _updateVisibility: function() {
let windowsVisible = Main.sessionMode.hasWindows && !this._inOverview; let windowsVisible = Main.sessionMode.hasWindows && !this._inOverview;
global.window_group.visible = windowsVisible;
global.top_window_group.visible = windowsVisible;
for (let i = 0; i < this._trackedActors.length; i++) { for (let i = 0; i < this._trackedActors.length; i++) {
let actorData = this._trackedActors[i], visible; let actorData = this._trackedActors[i], visible;
if (!actorData.trackFullscreen) if (!actorData.trackFullscreen)
continue; continue;
if (!actorData.isToplevel)
continue;
if (!windowsVisible) if (!windowsVisible)
visible = true; visible = true;
@ -1042,7 +1044,7 @@ const LayoutManager = new Lang.Class({
workspace.set_builtin_struts(struts); workspace.set_builtin_struts(struts);
} }
return false; return GLib.SOURCE_REMOVE;
} }
}); });
Signals.addSignalMethods(LayoutManager.prototype); Signals.addSignalMethods(LayoutManager.prototype);
@ -1080,9 +1082,9 @@ const HotCorner = new Lang.Class({
this._ripple2 = new St.BoxLayout({ style_class: 'ripple-box', opacity: 0, visible: false }); this._ripple2 = new St.BoxLayout({ style_class: 'ripple-box', opacity: 0, visible: false });
this._ripple3 = new St.BoxLayout({ style_class: 'ripple-box', opacity: 0, visible: false }); this._ripple3 = new St.BoxLayout({ style_class: 'ripple-box', opacity: 0, visible: false });
layoutManager.uiGroup.add_actor(this._ripple1); layoutManager.sessionGroup.add_actor(this._ripple1);
layoutManager.uiGroup.add_actor(this._ripple2); layoutManager.sessionGroup.add_actor(this._ripple2);
layoutManager.uiGroup.add_actor(this._ripple3); layoutManager.sessionGroup.add_actor(this._ripple3);
}, },
setBarrierSize: function(size) { setBarrierSize: function(size) {
@ -1229,20 +1231,20 @@ const HotCorner = new Lang.Class({
this._entered = true; this._entered = true;
this._toggleOverview(); this._toggleOverview();
} }
return false; return Clutter.EVENT_PROPAGATE;
}, },
_onCornerLeft : function(actor, event) { _onCornerLeft : function(actor, event) {
if (event.get_related() != this.actor) if (event.get_related() != this.actor)
this._entered = false; this._entered = false;
// Consume event, otherwise this will confuse onEnvironsLeft // Consume event, otherwise this will confuse onEnvironsLeft
return true; return Clutter.EVENT_STOP;
}, },
_onEnvironsLeft : function(actor, event) { _onEnvironsLeft : function(actor, event) {
if (event.get_related() != this._corner) if (event.get_related() != this._corner)
this._entered = false; this._entered = false;
return false; return Clutter.EVENT_PROPAGATE;
} }
}); });

View File

@ -5,12 +5,38 @@ const Lang = imports.lang;
const Meta = imports.gi.Meta; const Meta = imports.gi.Meta;
const Signals = imports.signals; const Signals = imports.signals;
const St = imports.gi.St; const St = imports.gi.St;
const Shell = imports.gi.Shell;
const Params = imports.misc.params; const Params = imports.misc.params;
const Tweener = imports.ui.tweener; const Tweener = imports.ui.tweener;
const DEFAULT_FADE_FACTOR = 0.4; const DEFAULT_FADE_FACTOR = 0.4;
const GLSL_DIM_EFFECT_DECLARATIONS = '\
float compute_dim_factor (const vec2 coords) {\
vec2 dist = coords - vec2(0.5, 0.5); \
float elipse_radius = 0.5; \
/* interpolate darkening value, based on distance from screen center */ \
float val = min(length(dist), elipse_radius); \
return mix(0.3, 1.0, val / elipse_radius) * 0.4; \
}';
const GLSL_DIM_EFFECT_CODE = '\
float a = compute_dim_factor (cogl_tex_coord0_in.xy);\
cogl_color_out = vec4(0, 0, 0, cogl_color_in.a * a);'
;
const RadialShaderQuad = new Lang.Class({
Name: 'RadialShaderQuad',
Extends: Shell.GLSLQuad,
vfunc_build_pipeline: function() {
this.add_glsl_snippet(Shell.SnippetHook.FRAGMENT,
GLSL_DIM_EFFECT_DECLARATIONS,
GLSL_DIM_EFFECT_CODE,
true);
},
});
/** /**
* Lightbox: * Lightbox:
* @container: parent Clutter.Container * @container: parent Clutter.Container
@ -43,15 +69,21 @@ const Lightbox = new Lang.Class({
width: null, width: null,
height: null, height: null,
fadeFactor: DEFAULT_FADE_FACTOR, fadeFactor: DEFAULT_FADE_FACTOR,
radialEffect: false,
}); });
this._container = container; this._container = container;
this._children = container.get_children(); this._children = container.get_children();
this._fadeFactor = params.fadeFactor; this._fadeFactor = params.fadeFactor;
this.actor = new St.Bin({ x: 0, if (params.radialEffect)
y: 0, this.actor = new RadialShaderQuad({ x: 0,
style_class: 'lightbox', y: 0,
reactive: params.inhibitEvents }); reactive: params.inhibitEvents });
else
this.actor = new St.Bin({ x: 0,
y: 0,
style_class: 'lightbox',
reactive: params.inhibitEvents });
container.add_actor(this.actor); container.add_actor(this.actor);
this.actor.raise_top(); this.actor.raise_top();

View File

@ -109,6 +109,7 @@ const AutoComplete = new Lang.Class({
} }
this._lastTabTime = currTime; this._lastTabTime = currTime;
} }
return Clutter.EVENT_PROPAGATE;
}, },
// Insert characters of text not already included in head at cursor position. i.e., if text="abc" and head="a", // Insert characters of text not already included in head at cursor position. i.e., if text="abc" and head="a",
@ -502,7 +503,7 @@ const Inspector = new Lang.Class({
let container = new Shell.GenericContainer({ width: 0, let container = new Shell.GenericContainer({ width: 0,
height: 0 }); height: 0 });
container.connect('allocate', Lang.bind(this, this._allocate)); container.connect('allocate', Lang.bind(this, this._allocate));
Main.uiGroup.add_actor(container); Main.layoutManager.sessionGroup.add_actor(container);
let eventHandler = new St.BoxLayout({ name: 'LookingGlassDialog', let eventHandler = new St.BoxLayout({ name: 'LookingGlassDialog',
vertical: false, vertical: false,
@ -558,7 +559,7 @@ const Inspector = new Lang.Class({
_onKeyPressEvent: function (actor, event) { _onKeyPressEvent: function (actor, event) {
if (event.get_key_symbol() == Clutter.Escape) if (event.get_key_symbol() == Clutter.Escape)
this._close(); this._close();
return true; return Clutter.EVENT_STOP;
}, },
_onButtonPressEvent: function (actor, event) { _onButtonPressEvent: function (actor, event) {
@ -567,7 +568,7 @@ const Inspector = new Lang.Class({
this.emit('target', this._target, stageX, stageY); this.emit('target', this._target, stageX, stageY);
} }
this._close(); this._close();
return true; return Clutter.EVENT_STOP;
}, },
_onScrollEvent: function (actor, event) { _onScrollEvent: function (actor, event) {
@ -601,12 +602,12 @@ const Inspector = new Lang.Class({
default: default:
break; break;
} }
return true; return Clutter.EVENT_STOP;
}, },
_onMotionEvent: function (actor, event) { _onMotionEvent: function (actor, event) {
this._update(event); this._update(event);
return true; return Clutter.EVENT_STOP;
}, },
_update: function(event) { _update: function(event) {
@ -669,13 +670,13 @@ const Extensions = new Lang.Class({
_onViewSource: function (actor) { _onViewSource: function (actor) {
let extension = actor._extension; let extension = actor._extension;
let uri = extension.dir.get_uri(); let uri = extension.dir.get_uri();
Gio.app_info_launch_default_for_uri(uri, global.create_app_launch_context()); Gio.app_info_launch_default_for_uri(uri, global.create_app_launch_context(0, -1));
this._lookingGlass.close(); this._lookingGlass.close();
}, },
_onWebPage: function (actor) { _onWebPage: function (actor) {
let extension = actor._extension; let extension = actor._extension;
Gio.app_info_launch_default_for_uri(extension.metadata.url, global.create_app_launch_context()); Gio.app_info_launch_default_for_uri(extension.metadata.url, global.create_app_launch_context(0, -1));
this._lookingGlass.close(); this._lookingGlass.close();
}, },
@ -800,16 +801,14 @@ const LookingGlass = new Lang.Class({
this._updateFont(); this._updateFont();
// We want it to appear to slide out from underneath the panel // We want it to appear to slide out from underneath the panel
Main.uiGroup.add_actor(this.actor); Main.layoutManager.sessionGroup.add_actor(this.actor);
Main.uiGroup.set_child_below_sibling(this.actor, Main.layoutManager.panelGroup.connect('allocation-changed',
Main.layoutManager.panelBox); Lang.bind(this, this._queueResize));
Main.layoutManager.panelBox.connect('allocation-changed',
Lang.bind(this, this._queueResize));
Main.layoutManager.keyboardBox.connect('allocation-changed', Main.layoutManager.keyboardBox.connect('allocation-changed',
Lang.bind(this, this._queueResize)); Lang.bind(this, this._queueResize));
this._objInspector = new ObjInspector(this); this._objInspector = new ObjInspector(this);
Main.uiGroup.add_actor(this._objInspector.actor); Main.layoutManager.sessionGroup.add_actor(this._objInspector.actor);
this._objInspector.actor.hide(); this._objInspector.actor.hide();
let toolbar = new St.BoxLayout({ name: 'Toolbar' }); let toolbar = new St.BoxLayout({ name: 'Toolbar' });
@ -828,7 +827,7 @@ const LookingGlass = new Lang.Class({
global.stage.set_key_focus(this._entry); global.stage.set_key_focus(this._entry);
})); }));
this.actor.hide(); this.actor.hide();
return true; return Clutter.EVENT_STOP;
})); }));
let gcIcon = new St.Icon({ icon_name: 'gnome-fs-trash-full', let gcIcon = new St.Icon({ icon_name: 'gnome-fs-trash-full',
@ -841,7 +840,9 @@ const LookingGlass = new Lang.Class({
this._timeoutId = Mainloop.timeout_add(500, Lang.bind(this, function () { this._timeoutId = Mainloop.timeout_add(500, Lang.bind(this, function () {
gcIcon.icon_name = 'gnome-fs-trash-full'; gcIcon.icon_name = 'gnome-fs-trash-full';
Mainloop.source_remove(this._timeoutId); Mainloop.source_remove(this._timeoutId);
return GLib.SOURCE_REMOVE;
})); }));
return Clutter.EVENT_PROPAGATE;
})); }));
let notebook = new Notebook(); let notebook = new Notebook();
@ -1034,7 +1035,7 @@ const LookingGlass = new Lang.Class({
let availableHeight = primary.height - Main.layoutManager.keyboardBox.height; let availableHeight = primary.height - Main.layoutManager.keyboardBox.height;
let myHeight = Math.min(primary.height * 0.7, availableHeight * 0.9); let myHeight = Math.min(primary.height * 0.7, availableHeight * 0.9);
this.actor.x = primary.x + (primary.width - myWidth) / 2; this.actor.x = primary.x + (primary.width - myWidth) / 2;
this._hiddenY = primary.y + Main.layoutManager.panelBox.height - myHeight - 4; // -4 to hide the top corners this._hiddenY = primary.y + Main.layoutManager.panelGroup.height - myHeight - 4; // -4 to hide the top corners
this._targetY = this._hiddenY + myHeight; this._targetY = this._hiddenY + myHeight;
this.actor.y = this._hiddenY; this.actor.y = this._hiddenY;
this.actor.width = myWidth; this.actor.width = myWidth;
@ -1063,7 +1064,7 @@ const LookingGlass = new Lang.Class({
} else { } else {
this.close(); this.close();
} }
return true; return Clutter.EVENT_STOP;
} }
// Ctrl+PgUp and Ctrl+PgDown switches tabs in the notebook view // Ctrl+PgUp and Ctrl+PgDown switches tabs in the notebook view
if (modifierState & Clutter.ModifierType.CONTROL_MASK) { if (modifierState & Clutter.ModifierType.CONTROL_MASK) {
@ -1073,7 +1074,7 @@ const LookingGlass = new Lang.Class({
this._notebook.nextTab(); this._notebook.nextTab();
} }
} }
return false; return Clutter.EVENT_PROPAGATE;
}, },
open : function() { open : function() {

View File

@ -1184,7 +1184,7 @@ const ZoomRegion = new Lang.Class({
// Clone the group that contains all of UI on the screen. This is the // Clone the group that contains all of UI on the screen. This is the
// chrome, the windows, etc. // chrome, the windows, etc.
this._uiGroupClone = new Clutter.Clone({ source: Main.uiGroup }); this._uiGroupClone = new Clutter.Clone({ source: Main.layoutManager.uiGroup });
mainGroup.add_actor(this._uiGroupClone); mainGroup.add_actor(this._uiGroupClone);
// Add either the given mouseSourceActor to the ZoomRegion, or a clone of // Add either the given mouseSourceActor to the ZoomRegion, or a clone of

View File

@ -64,7 +64,6 @@ let screencastService = null;
let modalCount = 0; let modalCount = 0;
let keybindingMode = Shell.KeyBindingMode.NONE; let keybindingMode = Shell.KeyBindingMode.NONE;
let modalActorFocusStack = []; let modalActorFocusStack = [];
let uiGroup = null;
let magnifier = null; let magnifier = null;
let xdndHandler = null; let xdndHandler = null;
let keyboard = null; let keyboard = null;
@ -150,11 +149,6 @@ function _initializeUI() {
// Setup the stage hierarchy early // Setup the stage hierarchy early
layoutManager = new Layout.LayoutManager(); layoutManager = new Layout.LayoutManager();
// Various parts of the codebase still refers to Main.uiGroup
// instead using the layoutManager. This keeps that code
// working until it's updated.
uiGroup = layoutManager.uiGroup;
screencastService = new Screencast.ScreencastService(); screencastService = new Screencast.ScreencastService();
xdndHandler = new XdndHandler.XdndHandler(); xdndHandler = new XdndHandler.XdndHandler();
ctrlAltTabManager = new CtrlAltTab.CtrlAltTabManager(); ctrlAltTabManager = new CtrlAltTab.CtrlAltTabManager();
@ -172,6 +166,19 @@ function _initializeUI() {
windowAttentionHandler = new WindowAttentionHandler.WindowAttentionHandler(); windowAttentionHandler = new WindowAttentionHandler.WindowAttentionHandler();
componentManager = new Components.ComponentManager(); componentManager = new Components.ComponentManager();
if (sessionMode.isGreeter && screenShield) {
layoutManager.connect('startup-prepared', function() {
screenShield.showDialog();
});
}
layoutManager.connect('startup-complete', function() {
if (keybindingMode == Shell.KeyBindingMode.NONE)
keybindingMode = Shell.KeyBindingMode.NORMAL;
if (screenShield)
screenShield.lockIfWasLocked();
});
layoutManager.init(); layoutManager.init();
overview.init(); overview.init();
@ -202,21 +209,6 @@ function _initializeUI() {
ExtensionDownloader.init(); ExtensionDownloader.init();
ExtensionSystem.init(); ExtensionSystem.init();
if (sessionMode.isGreeter && screenShield) {
layoutManager.connect('startup-prepared', function() {
screenShield.showDialog();
});
}
layoutManager.connect('startup-complete', function() {
if (keybindingMode == Shell.KeyBindingMode.NONE) {
keybindingMode = Shell.KeyBindingMode.NORMAL;
}
if (screenShield) {
screenShield.lockIfWasLocked();
}
});
} }
function _loadDefaultStylesheet() { function _loadDefaultStylesheet() {
@ -609,7 +601,7 @@ function queueDeferredWork(workId) {
_deferredTimeoutId = Mainloop.timeout_add_seconds(DEFERRED_TIMEOUT_SECONDS, function () { _deferredTimeoutId = Mainloop.timeout_add_seconds(DEFERRED_TIMEOUT_SECONDS, function () {
_runAllDeferredWork(); _runAllDeferredWork();
_deferredTimeoutId = 0; _deferredTimeoutId = 0;
return false; return GLib.SOURCE_REMOVE;
}); });
} }
} }

View File

@ -19,7 +19,6 @@ const BoxPointer = imports.ui.boxpointer;
const CtrlAltTab = imports.ui.ctrlAltTab; const CtrlAltTab = imports.ui.ctrlAltTab;
const GnomeSession = imports.misc.gnomeSession; const GnomeSession = imports.misc.gnomeSession;
const GrabHelper = imports.ui.grabHelper; const GrabHelper = imports.ui.grabHelper;
const Hash = imports.misc.hash;
const Lightbox = imports.ui.lightbox; const Lightbox = imports.ui.lightbox;
const Main = imports.ui.main; const Main = imports.ui.main;
const PointerWatcher = imports.ui.pointerWatcher; const PointerWatcher = imports.ui.pointerWatcher;
@ -76,7 +75,7 @@ const Urgency = {
NORMAL: 1, NORMAL: 1,
HIGH: 2, HIGH: 2,
CRITICAL: 3 CRITICAL: 3
} };
function _fixMarkup(text, allowMarkup) { function _fixMarkup(text, allowMarkup) {
if (allowMarkup) { if (allowMarkup) {
@ -187,7 +186,7 @@ const URLHighlighter = new Lang.Class({
// The MessageTray doesn't actually hide us, so // The MessageTray doesn't actually hide us, so
// we need to check for paint opacities as well. // we need to check for paint opacities as well.
if (!actor.visible || actor.get_paint_opacity() == 0) if (!actor.visible || actor.get_paint_opacity() == 0)
return false; return Clutter.EVENT_PROPAGATE;
// Keep Notification.actor from seeing this and taking // Keep Notification.actor from seeing this and taking
// a pointer grab, which would block our button-release-event // a pointer grab, which would block our button-release-event
@ -196,7 +195,7 @@ const URLHighlighter = new Lang.Class({
})); }));
this.actor.connect('button-release-event', Lang.bind(this, function (actor, event) { this.actor.connect('button-release-event', Lang.bind(this, function (actor, event) {
if (!actor.visible || actor.get_paint_opacity() == 0) if (!actor.visible || actor.get_paint_opacity() == 0)
return false; return Clutter.EVENT_PROPAGATE;
let urlId = this._findUrlAtPos(event); let urlId = this._findUrlAtPos(event);
if (urlId != -1) { if (urlId != -1) {
@ -204,14 +203,14 @@ const URLHighlighter = new Lang.Class({
if (url.indexOf(':') == -1) if (url.indexOf(':') == -1)
url = 'http://' + url; url = 'http://' + url;
Gio.app_info_launch_default_for_uri(url, global.create_app_launch_context()); Gio.app_info_launch_default_for_uri(url, global.create_app_launch_context(0, -1));
return true; return Clutter.EVENT_STOP;
} }
return false; return Clutter.EVENT_PROPAGATE;
})); }));
this.actor.connect('motion-event', Lang.bind(this, function(actor, event) { this.actor.connect('motion-event', Lang.bind(this, function(actor, event) {
if (!actor.visible || actor.get_paint_opacity() == 0) if (!actor.visible || actor.get_paint_opacity() == 0)
return false; return Clutter.EVENT_PROPAGATE;
let urlId = this._findUrlAtPos(event); let urlId = this._findUrlAtPos(event);
if (urlId != -1 && !this._cursorChanged) { if (urlId != -1 && !this._cursorChanged) {
@ -221,16 +220,17 @@ const URLHighlighter = new Lang.Class({
global.screen.set_cursor(Meta.Cursor.DEFAULT); global.screen.set_cursor(Meta.Cursor.DEFAULT);
this._cursorChanged = false; this._cursorChanged = false;
} }
return false; return Clutter.EVENT_PROPAGATE;
})); }));
this.actor.connect('leave-event', Lang.bind(this, function() { this.actor.connect('leave-event', Lang.bind(this, function() {
if (!this.actor.visible || this.actor.get_paint_opacity() == 0) if (!this.actor.visible || this.actor.get_paint_opacity() == 0)
return; return Clutter.EVENT_PROPAGATE;
if (this._cursorChanged) { if (this._cursorChanged) {
this._cursorChanged = false; this._cursorChanged = false;
global.screen.set_cursor(Meta.Cursor.DEFAULT); global.screen.set_cursor(Meta.Cursor.DEFAULT);
} }
return Clutter.EVENT_PROPAGATE;
})); }));
}, },
@ -1001,6 +1001,9 @@ const Notification = new Lang.Class({
Meta.later_add(Meta.LaterType.BEFORE_REDRAW, Meta.later_add(Meta.LaterType.BEFORE_REDRAW,
Lang.bind(this, Lang.bind(this,
function() { function() {
if (this._destroyed)
return false;
if (this._canExpandContent()) { if (this._canExpandContent()) {
this._addBannerBody(); this._addBannerBody();
this._table.add_style_class_name('multi-line-notification'); this._table.add_style_class_name('multi-line-notification');
@ -1159,7 +1162,7 @@ const SourceActor = new Lang.Class({
})); }));
this._actorDestroyed = false; this._actorDestroyed = false;
this._counterLabel = new St.Label( {x_align: Clutter.ActorAlign.CENTER, this._counterLabel = new St.Label({ x_align: Clutter.ActorAlign.CENTER,
x_expand: true, x_expand: true,
y_align: Clutter.ActorAlign.CENTER, y_align: Clutter.ActorAlign.CENTER,
y_expand: true }); y_expand: true });
@ -1263,7 +1266,6 @@ const Source = new Lang.Class({
this.title = title; this.title = title;
this.iconName = iconName; this.iconName = iconName;
this.isTransient = false;
this.isChat = false; this.isChat = false;
this.isMuted = false; this.isMuted = false;
this.keepTrayOnSummaryClick = false; this.keepTrayOnSummaryClick = false;
@ -1323,10 +1325,6 @@ const Source = new Lang.Class({
return rightClickMenu; return rightClickMenu;
}, },
setTransient: function(isTransient) {
this.isTransient = isTransient;
},
setTitle: function(newTitle) { setTitle: function(newTitle) {
this.title = newTitle; this.title = newTitle;
this.emit('title-changed'); this.emit('title-changed');
@ -1528,9 +1526,9 @@ const SummaryItem = new Lang.Class({
_onKeyPress: function(actor, event) { _onKeyPress: function(actor, event) {
if (event.get_key_symbol() == Clutter.KEY_Up) { if (event.get_key_symbol() == Clutter.KEY_Up) {
actor.emit('clicked', 1); actor.emit('clicked', 1);
return true; return Clutter.EVENT_STOP;
} }
return false; return Clutter.EVENT_PROPAGATE;
}, },
prepareNotificationStackForShowing: function() { prepareNotificationStackForShowing: function() {
@ -1613,7 +1611,7 @@ const MessageTrayMenu = new Lang.Class({
this._accountManager.prepare_async(null, Lang.bind(this, this._onIMPresenceChanged)); this._accountManager.prepare_async(null, Lang.bind(this, this._onIMPresenceChanged));
this.actor.hide(); this.actor.hide();
Main.layoutManager.addChrome(this.actor); Main.layoutManager.menuGroup.add_child(this.actor);
this._busyItem = new PopupMenu.PopupSwitchMenuItem(_("Notifications")); this._busyItem = new PopupMenu.PopupSwitchMenuItem(_("Notifications"));
this._busyItem.connect('toggled', Lang.bind(this, this._updatePresence)); this._busyItem.connect('toggled', Lang.bind(this, this._updatePresence));
@ -1625,7 +1623,7 @@ const MessageTrayMenu = new Lang.Class({
this._clearItem = this.addAction(_("Clear Messages"), function() { this._clearItem = this.addAction(_("Clear Messages"), function() {
let toDestroy = tray.getSources().filter(function(source) { let toDestroy = tray.getSources().filter(function(source) {
return source.isClearable; return source.isClearable;
}) });
toDestroy.forEach(function(source) { toDestroy.forEach(function(source) {
source.destroy(); source.destroy();
@ -1788,6 +1786,7 @@ const MessageTray = new Lang.Class({
this._setClickedSummaryItem(null); this._setClickedSummaryItem(null);
this._updateState(); this._updateState();
actor.grab_key_focus(); actor.grab_key_focus();
return Clutter.EVENT_PROPAGATE;
})); }));
global.focus_manager.add_group(this.actor); global.focus_manager.add_group(this.actor);
this._summary = new St.BoxLayout({ style_class: 'message-tray-summary', this._summary = new St.BoxLayout({ style_class: 'message-tray-summary',
@ -1902,7 +1901,7 @@ const MessageTray = new Lang.Class({
Shell.KeyBindingMode.OVERVIEW, Shell.KeyBindingMode.OVERVIEW,
Lang.bind(this, this._expandActiveNotification)); Lang.bind(this, this._expandActiveNotification));
this._sources = new Hash.Map(); this._sources = new Map();
this._chatSummaryItemsCount = 0; this._chatSummaryItemsCount = 0;
this._trayDwellTimeoutId = 0; this._trayDwellTimeoutId = 0;
@ -1939,7 +1938,7 @@ const MessageTray = new Lang.Class({
}, },
_updateNoMessagesLabel: function() { _updateNoMessagesLabel: function() {
this._noMessages.visible = this._sources.size() == 0; this._noMessages.visible = this._sources.size == 0;
}, },
_sessionUpdated: function() { _sessionUpdated: function() {
@ -1993,32 +1992,32 @@ const MessageTray = new Lang.Class({
this._trayDwellTimeoutId = 0; this._trayDwellTimeoutId = 0;
if (Main.layoutManager.bottomMonitor.inFullscreen) if (Main.layoutManager.bottomMonitor.inFullscreen)
return false; return GLib.SOURCE_REMOVE;
// We don't want to open the tray when a modal dialog // We don't want to open the tray when a modal dialog
// is up, so we check the modal count for that. When we are in the // is up, so we check the modal count for that. When we are in the
// overview we have to take the overview's modal push into account // overview we have to take the overview's modal push into account
if (Main.modalCount > (Main.overview.visible ? 1 : 0)) if (Main.modalCount > (Main.overview.visible ? 1 : 0))
return false; return GLib.SOURCE_REMOVE;
// If the user interacted with the focus window since we started the tray // If the user interacted with the focus window since we started the tray
// dwell (by clicking or typing), don't activate the message tray // dwell (by clicking or typing), don't activate the message tray
let focusWindow = global.display.focus_window; let focusWindow = global.display.focus_window;
let currentUserTime = focusWindow ? focusWindow.user_time : 0; let currentUserTime = focusWindow ? focusWindow.user_time : 0;
if (currentUserTime != this._trayDwellUserTime) if (currentUserTime != this._trayDwellUserTime)
return false; return GLib.SOURCE_REMOVE;
this.openTray(); this.openTray();
return false; return GLib.SOURCE_REMOVE;
}, },
_onNotificationKeyRelease: function(actor, event) { _onNotificationKeyRelease: function(actor, event) {
if (event.get_key_symbol() == Clutter.KEY_Escape && event.get_state() == 0) { if (event.get_key_symbol() == Clutter.KEY_Escape && event.get_state() == 0) {
this._closeNotification(); this._closeNotification();
return true; return Clutter.EVENT_STOP;
} }
return false; return Clutter.EVENT_PROPAGATE;
}, },
_closeNotification: function() { _closeNotification: function() {
@ -2102,7 +2101,8 @@ const MessageTray = new Lang.Class({
}, },
_removeSource: function(source) { _removeSource: function(source) {
let [, obj] = this._sources.delete(source); let obj = this._sources.get(source);
this._sources.delete(source);
let summaryItem = obj.summaryItem; let summaryItem = obj.summaryItem;
if (source.isChat) if (source.isChat)
@ -2123,7 +2123,7 @@ const MessageTray = new Lang.Class({
}, },
getSources: function() { getSources: function() {
return this._sources.keys(); return [k for (k of this._sources.keys())];
}, },
_onSourceEnableChanged: function(policy, source) { _onSourceEnableChanged: function(policy, source) {
@ -2339,7 +2339,7 @@ const MessageTray = new Lang.Class({
this._updateNotificationTimeout(0); this._updateNotificationTimeout(0);
this._updateState(); this._updateState();
} }
return false; return GLib.SOURCE_REMOVE;
}, },
_escapeTray: function() { _escapeTray: function() {
@ -2356,6 +2356,13 @@ const MessageTray = new Lang.Class({
// _updateState() figures out what (if anything) needs to be done // _updateState() figures out what (if anything) needs to be done
// at the present time. // at the present time.
_updateState: function() { _updateState: function() {
// If our state changes caused _updateState to be called,
// just exit now to prevent reentrancy issues.
if (this._updatingState)
return;
this._updatingState = true;
// Filter out acknowledged notifications. // Filter out acknowledged notifications.
this._notificationQueue = this._notificationQueue.filter(function(n) { this._notificationQueue = this._notificationQueue.filter(function(n) {
return !n.acknowledged; return !n.acknowledged;
@ -2375,7 +2382,7 @@ const MessageTray = new Lang.Class({
} else if (this._notificationState == State.SHOWN) { } else if (this._notificationState == State.SHOWN) {
let expired = (this._userActiveWhileNotificationShown && let expired = (this._userActiveWhileNotificationShown &&
this._notificationTimeoutId == 0 && this._notificationTimeoutId == 0 &&
!(this._notification.urgency == Urgency.CRITICAL) && this._notification.urgency != Urgency.CRITICAL &&
!this._notification.focused && !this._notification.focused &&
!this._pointerInNotification); !this._pointerInNotification);
let mustClose = (this._notificationRemoved || !hasNotifications || expired || this._traySummoned); let mustClose = (this._notificationRemoved || !hasNotifications || expired || this._traySummoned);
@ -2432,11 +2439,12 @@ const MessageTray = new Lang.Class({
this._desktopCloneState == State.SHOWN); this._desktopCloneState == State.SHOWN);
let desktopCloneShouldBeVisible = (trayShouldBeVisible); let desktopCloneShouldBeVisible = (trayShouldBeVisible);
if (!desktopCloneIsVisible && desktopCloneShouldBeVisible) { if (!desktopCloneIsVisible && desktopCloneShouldBeVisible)
this._showDesktopClone(); this._showDesktopClone();
} else if (desktopCloneIsVisible && !desktopCloneShouldBeVisible) { else if (desktopCloneIsVisible && !desktopCloneShouldBeVisible)
this._hideDesktopClone(); this._hideDesktopClone();
}
this._updatingState = false;
}, },
_tween: function(actor, statevar, value, params) { _tween: function(actor, statevar, value, params) {
@ -2504,7 +2512,7 @@ const MessageTray = new Lang.Class({
let cloneSource = Main.overview.visible ? Main.layoutManager.overviewGroup : global.window_group; let cloneSource = Main.overview.visible ? Main.layoutManager.overviewGroup : global.window_group;
this._desktopClone = new Clutter.Clone({ source: cloneSource, this._desktopClone = new Clutter.Clone({ source: cloneSource,
clip: new Clutter.Geometry(this._bottomMonitorGeometry) }); clip: new Clutter.Geometry(this._bottomMonitorGeometry) });
Main.uiGroup.insert_child_above(this._desktopClone, cloneSource); Main.layoutManager.sessionGroup.insert_child_above(this._desktopClone, cloneSource);
this._desktopClone.x = 0; this._desktopClone.x = 0;
this._desktopClone.y = 0; this._desktopClone.y = 0;
this._desktopClone.show(); this._desktopClone.show();
@ -2664,7 +2672,7 @@ const MessageTray = new Lang.Class({
this._lastSeenMouseX = x; this._lastSeenMouseX = x;
this._lastSeenMouseY = y; this._lastSeenMouseY = y;
return false; return GLib.SOURCE_REMOVE;
}, },
_hideNotification: function(animate) { _hideNotification: function(animate) {
@ -2801,13 +2809,13 @@ const MessageTray = new Lang.Class({
Lang.bind(this, this._onSourceDoneDisplayingContent)); Lang.bind(this, this._onSourceDoneDisplayingContent));
this._summaryBoxPointer.bin.child = child; this._summaryBoxPointer.bin.child = child;
this._grabHelper.grab({ actor: this._summaryBoxPointer.bin.child,
onUngrab: Lang.bind(this, this._onSummaryBoxPointerUngrabbed) });
this._summaryBoxPointer.actor.opacity = 0; this._summaryBoxPointer.actor.opacity = 0;
this._summaryBoxPointer.actor.show(); this._summaryBoxPointer.actor.show();
this._adjustSummaryBoxPointerPosition(); this._adjustSummaryBoxPointerPosition();
this._grabHelper.grab({ actor: this._summaryBoxPointer.bin.child,
onUngrab: Lang.bind(this, this._onSummaryBoxPointerUngrabbed) });
this._summaryBoxPointerState = State.SHOWING; this._summaryBoxPointerState = State.SHOWING;
this._summaryBoxPointer.show(BoxPointer.PopupAnimation.FULL, Lang.bind(this, function() { this._summaryBoxPointer.show(BoxPointer.PopupAnimation.FULL, Lang.bind(this, function() {
this._summaryBoxPointerState = State.SHOWN; this._summaryBoxPointerState = State.SHOWN;
@ -2862,13 +2870,13 @@ const MessageTray = new Lang.Class({
case Clutter.KEY_Escape: case Clutter.KEY_Escape:
this._setClickedSummaryItem(null); this._setClickedSummaryItem(null);
this._updateState(); this._updateState();
return true; return Clutter.EVENT_STOP;
case Clutter.KEY_Delete: case Clutter.KEY_Delete:
this._clickedSummaryItem.source.destroy(); this._clickedSummaryItem.source.destroy();
this._escapeTray(); this._escapeTray();
return true; return Clutter.EVENT_STOP;
} }
return false; return Clutter.EVENT_PROPAGATE;
}, },
_onSummaryBoxPointerUngrabbed: function() { _onSummaryBoxPointerUngrabbed: function() {
@ -2906,8 +2914,6 @@ const MessageTray = new Lang.Class({
this._summaryBoxPointerItem.doneShowingNotificationStack(); this._summaryBoxPointerItem.doneShowingNotificationStack();
this._summaryBoxPointerItem = null; this._summaryBoxPointerItem = null;
if (source.isTransient && !this._reNotifyAfterHideNotification)
source.destroy(NotificationDestroyedReason.EXPIRED);
if (this._reNotifyAfterHideNotification) { if (this._reNotifyAfterHideNotification) {
this._onNotify(this._reNotifyAfterHideNotification.source, this._reNotifyAfterHideNotification); this._onNotify(this._reNotifyAfterHideNotification.source, this._reNotifyAfterHideNotification);
this._reNotifyAfterHideNotification = null; this._reNotifyAfterHideNotification = null;
@ -2926,7 +2932,6 @@ const SystemNotificationSource = new Lang.Class({
_init: function() { _init: function() {
this.parent(_("System Information"), 'dialog-information-symbolic'); this.parent(_("System Information"), 'dialog-information-symbolic');
this.setTransient(true);
}, },
open: function() { open: function() {

View File

@ -41,7 +41,7 @@ const ModalDialog = new Lang.Class({
_init: function(params) { _init: function(params) {
params = Params.parse(params, { shellReactive: false, params = Params.parse(params, { shellReactive: false,
styleClass: null, styleClass: null,
parentActor: Main.uiGroup, parentActor: Main.layoutManager.dialogGroup,
keybindingMode: Shell.KeyBindingMode.SYSTEM_MODAL, keybindingMode: Shell.KeyBindingMode.SYSTEM_MODAL,
shouldFadeIn: true, shouldFadeIn: true,
destroyOnClose: true }); destroyOnClose: true });
@ -89,7 +89,8 @@ const ModalDialog = new Lang.Class({
if (!this._shellReactive) { if (!this._shellReactive) {
this._lightbox = new Lightbox.Lightbox(this._group, this._lightbox = new Lightbox.Lightbox(this._group,
{ inhibitEvents: true }); { inhibitEvents: true,
radialEffect: true });
this._lightbox.highlight(this._backgroundBin); this._lightbox.highlight(this._backgroundBin);
this._eventBlocker = new Clutter.Actor({ reactive: true }); this._eventBlocker = new Clutter.Actor({ reactive: true });
@ -229,6 +230,7 @@ const ModalDialog = new Lang.Class({
_onKeyPressEvent: function(object, event) { _onKeyPressEvent: function(object, event) {
this._pressedKey = event.get_key_symbol(); this._pressedKey = event.get_key_symbol();
return Clutter.EVENT_PROPAGATE;
}, },
_onKeyReleaseEvent: function(object, event) { _onKeyReleaseEvent: function(object, event) {
@ -237,21 +239,21 @@ const ModalDialog = new Lang.Class({
let symbol = event.get_key_symbol(); let symbol = event.get_key_symbol();
if (symbol != pressedKey) if (symbol != pressedKey)
return false; return Clutter.EVENT_PROPAGATE;
let buttonInfo = this._buttonKeys[symbol]; let buttonInfo = this._buttonKeys[symbol];
if (!buttonInfo) if (!buttonInfo)
return false; return Clutter.EVENT_PROPAGATE;
let button = buttonInfo['button']; let button = buttonInfo['button'];
let action = buttonInfo['action']; let action = buttonInfo['action'];
if (action && button.reactive) { if (action && button.reactive) {
action(); action();
return true; return Clutter.EVENT_STOP;
} }
return false; return Clutter.EVENT_PROPAGATE;
}, },
_onGroupDestroy: function() { _onGroupDestroy: function() {

View File

@ -181,12 +181,10 @@ const FdoNotificationDaemon = new Lang.Class({
}, },
// Returns the source associated with ndata.notification if it is set. // Returns the source associated with ndata.notification if it is set.
// Otherwise, returns the source associated with the title and pid if // If the existing or requested source is associated with a tray icon
// such source is stored in this._sources and the notification is not // and passed in pid matches a pid of an existing source, the title
// transient. If the existing or requested source is associated with // match is ignored to enable representing a tray icon and notifications
// a tray icon and passed in pid matches a pid of an existing source, // from the same application with a single source.
// the title match is ignored to enable representing a tray icon and
// notifications from the same application with a single source.
// //
// If no existing source is found, a new source is created as long as // If no existing source is found, a new source is created as long as
// pid is provided. // pid is provided.
@ -204,32 +202,20 @@ const FdoNotificationDaemon = new Lang.Class({
if (ndata && ndata.notification) if (ndata && ndata.notification)
return ndata.notification.source; return ndata.notification.source;
let isForTransientNotification = (ndata && ndata.hints['transient'] == true); let source = this._lookupSource(title, pid, trayIcon);
if (source) {
// We don't want to override a persistent notification source.setTitle(title);
// with a transient one from the same sender, so we return source;
// always create a new source object for new transient notifications
// and never add it to this._sources .
if (!isForTransientNotification) {
let source = this._lookupSource(title, pid, trayIcon);
if (source) {
source.setTitle(title);
return source;
}
} }
let source = new FdoNotificationDaemonSource(title, pid, sender, trayIcon, ndata ? ndata.hints['desktop-entry'] : null); let source = new FdoNotificationDaemonSource(title, pid, sender, trayIcon, ndata ? ndata.hints['desktop-entry'] : null);
source.setTransient(isForTransientNotification);
if (!isForTransientNotification) { this._sources.push(source);
this._sources.push(source); source.connect('destroy', Lang.bind(this, function() {
source.connect('destroy', Lang.bind(this, let index = this._sources.indexOf(source);
function() { if (index >= 0)
let index = this._sources.indexOf(source); this._sources.splice(index, 1);
if (index >= 0) }));
this._sources.splice(index, 1);
}));
}
Main.messageTray.add(source); Main.messageTray.add(source);
return source; return source;
@ -261,7 +247,7 @@ const FdoNotificationDaemon = new Lang.Class({
Mainloop.idle_add(Lang.bind(this, Mainloop.idle_add(Lang.bind(this,
function () { function () {
this._emitNotificationClosed(id, NotificationClosedReason.DISMISSED); this._emitNotificationClosed(id, NotificationClosedReason.DISMISSED);
return false; return GLib.SOURCE_REMOVE;
})); }));
return invocation.return_value(GLib.Variant.new('(u)', [id])); return invocation.return_value(GLib.Variant.new('(u)', [id]));
} }
@ -336,20 +322,10 @@ const FdoNotificationDaemon = new Lang.Class({
let [pid] = result; let [pid] = result;
source = this._getSource(appName, pid, ndata, sender, null); source = this._getSource(appName, pid, ndata, sender, null);
// We only store sender-pid entries for persistent sources. this._senderToPid[sender] = pid;
// Removing the entries once the source is destroyed source.connect('destroy', Lang.bind(this, function() {
// would result in the entries associated with transient delete this._senderToPid[sender];
// sources removed once the notification is shown anyway. }));
// However, keeping these pairs would mean that we would
// possibly remove an entry associated with a persistent
// source when a transient source for the same sender is
// distroyed.
if (!source.isTransient) {
this._senderToPid[sender] = pid;
source.connect('destroy', Lang.bind(this, function() {
delete this._senderToPid[sender];
}));
}
this._notifyForSource(source, ndata); this._notifyForSource(source, ndata);
})); }));

View File

@ -1,6 +1,7 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
const Clutter = imports.gi.Clutter; const Clutter = imports.gi.Clutter;
const GLib = imports.gi.GLib;
const St = imports.gi.St; const St = imports.gi.St;
const Lang = imports.lang; const Lang = imports.lang;
@ -65,6 +66,7 @@ const LevelBar = new Lang.Class({
cr.arc(radius, h - radius, radius, 0.5 * Math.PI, Math.PI); cr.arc(radius, h - radius, radius, 0.5 * Math.PI, Math.PI);
cr.arc(radius, radius, radius, Math.PI, 1.5 * Math.PI); cr.arc(radius, radius, radius, Math.PI, 1.5 * Math.PI);
cr.fill(); cr.fill();
cr.$dispose();
} }
}); });
@ -77,7 +79,8 @@ const OsdWindow = new Lang.Class({
y_expand: true, y_expand: true,
x_align: Clutter.ActorAlign.CENTER, x_align: Clutter.ActorAlign.CENTER,
y_align: Clutter.ActorAlign.CENTER }); y_align: Clutter.ActorAlign.CENTER });
this.actor.add_constraint(new Layout.MonitorConstraint({ primary: true })); this._currentMonitor = undefined;
this.setMonitor (-1);
this._box = new St.BoxLayout({ style_class: 'osd-window', this._box = new St.BoxLayout({ style_class: 'osd-window',
vertical: true }); vertical: true });
this.actor.add_actor(this._box); this.actor.add_actor(this._box);
@ -107,7 +110,7 @@ const OsdWindow = new Lang.Class({
Lang.bind(this, this._monitorsChanged)); Lang.bind(this, this._monitorsChanged));
this._monitorsChanged(); this._monitorsChanged();
Main.uiGroup.add_child(this.actor); Main.layoutManager.osdGroup.add_child(this.actor);
}, },
setIcon: function(icon) { setIcon: function(icon) {
@ -122,13 +125,15 @@ const OsdWindow = new Lang.Class({
setLevel: function(level) { setLevel: function(level) {
this._level.actor.visible = (level != undefined); this._level.actor.visible = (level != undefined);
if (this.actor.visible) if (level) {
Tweener.addTween(this._level, if (this.actor.visible)
{ level: level, Tweener.addTween(this._level,
time: LEVEL_ANIMATION_TIME, { level: level,
transition: 'easeOutQuad' }); time: LEVEL_ANIMATION_TIME,
else transition: 'easeOutQuad' });
this._level.level = level; else
this._level.level = level;
}
}, },
show: function() { show: function() {
@ -172,6 +177,7 @@ const OsdWindow = new Lang.Class({
Meta.enable_unredirect_for_screen(global.screen); Meta.enable_unredirect_for_screen(global.screen);
}) })
}); });
return GLib.SOURCE_REMOVE;
}, },
_reset: function() { _reset: function() {
@ -182,7 +188,13 @@ const OsdWindow = new Lang.Class({
_monitorsChanged: function() { _monitorsChanged: function() {
/* assume 110x110 on a 640x480 display and scale from there */ /* assume 110x110 on a 640x480 display and scale from there */
let monitor = Main.layoutManager.primaryMonitor; let monitor;
if (this._currentMonitor >= 0)
monitor = Main.layoutManager.monitors[this._currentMonitor];
else
monitor = Main.layoutManager.primaryMonitor;
let scalew = monitor.width / 640.0; let scalew = monitor.width / 640.0;
let scaleh = monitor.height / 480.0; let scaleh = monitor.height / 480.0;
let scale = Math.min(scalew, scaleh); let scale = Math.min(scalew, scaleh);
@ -206,5 +218,23 @@ const OsdWindow = new Lang.Class({
let minHeight = this._popupSize - horizontalPadding - topBorder - bottomBorder; let minHeight = this._popupSize - horizontalPadding - topBorder - bottomBorder;
this._box.style = 'min-height: %dpx;'.format(Math.max(minWidth, minHeight)); this._box.style = 'min-height: %dpx;'.format(Math.max(minWidth, minHeight));
},
setMonitor: function(index) {
let constraint;
if (index < 0)
index = -1;
if (this._currentMonitor == index)
return;
if (index < 0)
constraint = new Layout.MonitorConstraint({ primary: true });
else
constraint = new Layout.MonitorConstraint({ index: index });
this.actor.clear_constraints();
this.actor.add_constraint(constraint);
this._currentMonitor = index;
} }
}); });

View File

@ -1,6 +1,7 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
const Clutter = imports.gi.Clutter; const Clutter = imports.gi.Clutter;
const GLib = imports.gi.GLib;
const Gtk = imports.gi.Gtk; const Gtk = imports.gi.Gtk;
const Meta = imports.gi.Meta; const Meta = imports.gi.Meta;
const Mainloop = imports.mainloop; const Mainloop = imports.mainloop;
@ -112,9 +113,6 @@ const Overview = new Lang.Class({
// rendering options without duplicating the texture data. // rendering options without duplicating the texture data.
let monitor = Main.layoutManager.primaryMonitor; let monitor = Main.layoutManager.primaryMonitor;
this._desktopFade = new St.Bin();
Main.layoutManager.overviewGroup.add_child(this._desktopFade);
let layout = new Clutter.BinLayout(); let layout = new Clutter.BinLayout();
this._stack = new Clutter.Actor({ layout_manager: layout }); this._stack = new Clutter.Actor({ layout_manager: layout });
this._stack.add_constraint(new LayoutManager.MonitorConstraint({ primary: true })); this._stack.add_constraint(new LayoutManager.MonitorConstraint({ primary: true }));
@ -133,6 +131,9 @@ const Overview = new Lang.Class({
Main.layoutManager.overviewGroup.add_child(this._backgroundGroup); Main.layoutManager.overviewGroup.add_child(this._backgroundGroup);
this._bgManagers = []; this._bgManagers = [];
this._desktopFade = new St.Widget();
Main.layoutManager.overviewGroup.add_child(this._desktopFade);
this._activationTime = 0; this._activationTime = 0;
this.visible = false; // animating to overview, in overview, animating out this.visible = false; // animating to overview, in overview, animating out
@ -147,7 +148,7 @@ const Overview = new Lang.Class({
this._coverPane = new Clutter.Actor({ opacity: 0, this._coverPane = new Clutter.Actor({ opacity: 0,
reactive: true }); reactive: true });
Main.layoutManager.overviewGroup.add_child(this._coverPane); Main.layoutManager.overviewGroup.add_child(this._coverPane);
this._coverPane.connect('event', Lang.bind(this, function (actor, event) { return true; })); this._coverPane.connect('event', Lang.bind(this, function (actor, event) { return Clutter.EVENT_STOP; }));
this._stack.add_actor(this._overview); this._stack.add_actor(this._overview);
Main.layoutManager.overviewGroup.add_child(this._stack); Main.layoutManager.overviewGroup.add_child(this._stack);
@ -369,7 +370,7 @@ const Overview = new Lang.Class({
this._windowSwitchTimestamp); this._windowSwitchTimestamp);
this.hide(); this.hide();
this._lastHoveredWindow = null; this._lastHoveredWindow = null;
return false; return GLib.SOURCE_REMOVE;
})); }));
} }
@ -378,6 +379,7 @@ const Overview = new Lang.Class({
_onScrollEvent: function(actor, event) { _onScrollEvent: function(actor, event) {
this.emit('scroll-event', event); this.emit('scroll-event', event);
return Clutter.EVENT_PROPAGATE;
}, },
addAction: function(action) { addAction: function(action) {
@ -491,8 +493,8 @@ const Overview = new Lang.Class({
}, },
fadeOutDesktop: function() { fadeOutDesktop: function() {
if (!this._desktopFade.child) if (!this._desktopFade.get_n_children())
this._desktopFade.child = this._getDesktopClone(); this._desktopFade.add_child(this._getDesktopClone());
this._desktopFade.opacity = 255; this._desktopFade.opacity = 255;
this._desktopFade.show(); this._desktopFade.show();
@ -620,7 +622,7 @@ const Overview = new Lang.Class({
this.animationInProgress = true; this.animationInProgress = true;
this.visibleTarget = false; this.visibleTarget = false;
this.viewSelector.zoomFromOverview(); this.viewSelector.leaveOverview();
// Make other elements fade out. // Make other elements fade out.
Tweener.addTween(this._stack, Tweener.addTween(this._stack,

View File

@ -460,9 +460,6 @@ const MessagesIndicator = new Lang.Class({
if (source.trayIcon) if (source.trayIcon)
return; return;
if (source.isTransient)
return;
source.connect('count-updated', Lang.bind(this, this._updateCount)); source.connect('count-updated', Lang.bind(this, this._updateCount));
this._sources.push(source); this._sources.push(source);
this._updateCount(); this._updateCount();

View File

@ -602,14 +602,15 @@ const ActivitiesButton = new Lang.Class({
_onCapturedEvent: function(actor, event) { _onCapturedEvent: function(actor, event) {
if (event.type() == Clutter.EventType.BUTTON_PRESS) { if (event.type() == Clutter.EventType.BUTTON_PRESS) {
if (!Main.overview.shouldToggleByCornerOrButton()) if (!Main.overview.shouldToggleByCornerOrButton())
return true; return Clutter.EVENT_STOP;
} }
return false; return Clutter.EVENT_PROPAGATE;
}, },
_onButtonRelease: function() { _onButtonRelease: function() {
Main.overview.toggle(); Main.overview.toggle();
this.menu.close(); this.menu.close();
return Clutter.EVENT_PROPAGATE;
}, },
_onKeyRelease: function(actor, event) { _onKeyRelease: function(actor, event) {
@ -617,6 +618,7 @@ const ActivitiesButton = new Lang.Class({
if (symbol == Clutter.KEY_Return || symbol == Clutter.KEY_space) { if (symbol == Clutter.KEY_Return || symbol == Clutter.KEY_space) {
Main.overview.toggle(); Main.overview.toggle();
} }
return Clutter.EVENT_PROPAGATE;
}, },
_xdndToggleOverview: function(actor) { _xdndToggleOverview: function(actor) {
@ -628,6 +630,7 @@ const ActivitiesButton = new Lang.Class({
Mainloop.source_remove(this._xdndTimeOut); Mainloop.source_remove(this._xdndTimeOut);
this._xdndTimeOut = 0; this._xdndTimeOut = 0;
return GLib.SOURCE_REMOVE;
} }
}); });
@ -822,8 +825,10 @@ const AggregateMenu = new Lang.Class({
this._brightness = new imports.ui.status.brightness.Indicator(); this._brightness = new imports.ui.status.brightness.Indicator();
this._system = new imports.ui.status.system.Indicator(); this._system = new imports.ui.status.system.Indicator();
this._screencast = new imports.ui.status.screencast.Indicator(); this._screencast = new imports.ui.status.screencast.Indicator();
this._location = new imports.ui.status.location.Indicator();
this._indicators.add_child(this._screencast.indicators); this._indicators.add_child(this._screencast.indicators);
this._indicators.add_child(this._location.indicators);
this._indicators.add_child(this._network.indicators); this._indicators.add_child(this._network.indicators);
if (this._bluetooth) { if (this._bluetooth) {
this._indicators.add_child(this._bluetooth.indicators); this._indicators.add_child(this._bluetooth.indicators);
@ -896,7 +901,7 @@ const Panel = new Lang.Class({
this.actor.remove_style_pseudo_class('overview'); this.actor.remove_style_pseudo_class('overview');
})); }));
Main.layoutManager.panelBox.add(this.actor); Main.layoutManager.panelGroup.add_child(this.actor);
Main.ctrlAltTabManager.addGroup(this.actor, _("Top Bar"), 'emblem-system-symbolic', Main.ctrlAltTabManager.addGroup(this.actor, _("Top Bar"), 'emblem-system-symbolic',
{ sortGroup: CtrlAltTab.SortGroup.TOP }); { sortGroup: CtrlAltTab.SortGroup.TOP });
@ -983,23 +988,23 @@ const Panel = new Lang.Class({
_onButtonPress: function(actor, event) { _onButtonPress: function(actor, event) {
if (Main.modalCount > 0) if (Main.modalCount > 0)
return false; return Clutter.EVENT_PROPAGATE;
if (event.get_source() != actor) if (event.get_source() != actor)
return false; return Clutter.EVENT_PROPAGATE;
let button = event.get_button(); let button = event.get_button();
if (button != 1) if (button != 1)
return false; return Clutter.EVENT_PROPAGATE;
let focusWindow = global.display.focus_window; let focusWindow = global.display.focus_window;
if (!focusWindow) if (!focusWindow)
return false; return Clutter.EVENT_PROPAGATE;
let dragWindow = focusWindow.is_attached_dialog() ? focusWindow.get_transient_for() let dragWindow = focusWindow.is_attached_dialog() ? focusWindow.get_transient_for()
: focusWindow; : focusWindow;
if (!dragWindow) if (!dragWindow)
return false; return Clutter.EVENT_PROPAGATE;
let rect = dragWindow.get_outer_rect(); let rect = dragWindow.get_outer_rect();
let [stageX, stageY] = event.get_coords(); let [stageX, stageY] = event.get_coords();
@ -1008,7 +1013,7 @@ const Panel = new Lang.Class({
stageX > rect.x && stageX < rect.x + rect.width; stageX > rect.x && stageX < rect.x + rect.width;
if (!allowDrag) if (!allowDrag)
return false; return Clutter.EVENT_PROPAGATE;
global.display.begin_grab_op(global.screen, global.display.begin_grab_op(global.screen,
dragWindow, dragWindow,
@ -1020,7 +1025,7 @@ const Panel = new Lang.Class({
event.get_time(), event.get_time(),
stageX, stageY); stageX, stageY);
return true; return Clutter.EVENT_STOP;
}, },
toggleAppMenu: function() { toggleAppMenu: function() {

View File

@ -130,36 +130,37 @@ const Button = new Lang.Class({
this.menu.connect('open-state-changed', Lang.bind(this, this._onOpenStateChanged)); this.menu.connect('open-state-changed', Lang.bind(this, this._onOpenStateChanged));
this.menu.actor.connect('key-press-event', Lang.bind(this, this._onMenuKeyPress)); this.menu.actor.connect('key-press-event', Lang.bind(this, this._onMenuKeyPress));
Main.uiGroup.add_actor(this.menu.actor); Main.layoutManager.menuGroup.add_child(this.menu.actor);
this.menu.actor.hide(); this.menu.actor.hide();
} }
}, },
_onButtonPress: function(actor, event) { _onButtonPress: function(actor, event) {
if (!this.menu) if (!this.menu)
return; return Clutter.EVENT_PROPAGATE;
this.menu.toggle(); this.menu.toggle();
return Clutter.EVENT_PROPAGATE;
}, },
_onSourceKeyPress: function(actor, event) { _onSourceKeyPress: function(actor, event) {
if (!this.menu) if (!this.menu)
return false; return Clutter.EVENT_PROPAGATE;
let symbol = event.get_key_symbol(); let symbol = event.get_key_symbol();
if (symbol == Clutter.KEY_space || symbol == Clutter.KEY_Return) { if (symbol == Clutter.KEY_space || symbol == Clutter.KEY_Return) {
this.menu.toggle(); this.menu.toggle();
return true; return Clutter.EVENT_STOP;
} else if (symbol == Clutter.KEY_Escape && this.menu.isOpen) { } else if (symbol == Clutter.KEY_Escape && this.menu.isOpen) {
this.menu.close(); this.menu.close();
return true; return Clutter.EVENT_STOP;
} else if (symbol == Clutter.KEY_Down) { } else if (symbol == Clutter.KEY_Down) {
if (!this.menu.isOpen) if (!this.menu.isOpen)
this.menu.toggle(); this.menu.toggle();
this.menu.actor.navigate_focus(this.actor, Gtk.DirectionType.DOWN, false); this.menu.actor.navigate_focus(this.actor, Gtk.DirectionType.DOWN, false);
return true; return Clutter.EVENT_STOP;
} else } else
return false; return Clutter.EVENT_PROPAGATE;
}, },
_onVisibilityChanged: function() { _onVisibilityChanged: function() {
@ -172,7 +173,7 @@ const Button = new Lang.Class({
_onMenuKeyPress: function(actor, event) { _onMenuKeyPress: function(actor, event) {
if (global.focus_manager.navigate_from_event(event)) if (global.focus_manager.navigate_from_event(event))
return true; return Clutter.EVENT_STOP;
let symbol = event.get_key_symbol(); let symbol = event.get_key_symbol();
if (symbol == Clutter.KEY_Left || symbol == Clutter.KEY_Right) { if (symbol == Clutter.KEY_Left || symbol == Clutter.KEY_Right) {
@ -180,10 +181,10 @@ const Button = new Lang.Class({
if (group) { if (group) {
let direction = (symbol == Clutter.KEY_Left) ? Gtk.DirectionType.LEFT : Gtk.DirectionType.RIGHT; let direction = (symbol == Clutter.KEY_Left) ? Gtk.DirectionType.LEFT : Gtk.DirectionType.RIGHT;
group.navigate_focus(this.actor, direction, false); group.navigate_focus(this.actor, direction, false);
return true; return Clutter.EVENT_STOP;
} }
} }
return false; return Clutter.EVENT_PROPAGATE;
}, },
_onOpenStateChanged: function(menu, open) { _onOpenStateChanged: function(menu, open) {

View File

@ -1,5 +1,6 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
const GLib = imports.gi.GLib;
const Lang = imports.lang; const Lang = imports.lang;
const Mainloop = imports.mainloop; const Mainloop = imports.mainloop;
const Meta = imports.gi.Meta; const Meta = imports.gi.Meta;
@ -110,7 +111,7 @@ const PointerWatcher = new Lang.Class({
_onTimeout: function() { _onTimeout: function() {
this._updatePointer(); this._updatePointer();
return true; return GLib.SOURCE_CONTINUE;
}, },
_updatePointer: function() { _updatePointer: function() {

View File

@ -126,7 +126,7 @@ const PopupBaseMenuItem = new Lang.Class({
_onButtonReleaseEvent: function (actor, event) { _onButtonReleaseEvent: function (actor, event) {
this.activate(event); this.activate(event);
return true; return Clutter.EVENT_STOP;
}, },
_onKeyPressEvent: function (actor, event) { _onKeyPressEvent: function (actor, event) {
@ -134,9 +134,9 @@ const PopupBaseMenuItem = new Lang.Class({
if (symbol == Clutter.KEY_space || symbol == Clutter.KEY_Return) { if (symbol == Clutter.KEY_space || symbol == Clutter.KEY_Return) {
this.activate(event); this.activate(event);
return true; return Clutter.EVENT_STOP;
} }
return false; return Clutter.EVENT_PROPAGATE;
}, },
_onKeyFocusIn: function (actor) { _onKeyFocusIn: function (actor) {
@ -928,10 +928,10 @@ const PopupSubMenu = new Lang.Class({
if (this.isOpen && event.get_key_symbol() == Clutter.KEY_Left) { if (this.isOpen && event.get_key_symbol() == Clutter.KEY_Left) {
this.close(BoxPointer.PopupAnimation.FULL); this.close(BoxPointer.PopupAnimation.FULL);
this.sourceActor._delegate.setActive(true); this.sourceActor._delegate.setActive(true);
return true; return Clutter.EVENT_STOP;
} }
return false; return Clutter.EVENT_PROPAGATE;
} }
}); });
@ -1056,10 +1056,10 @@ const PopupSubMenuMenuItem = new Lang.Class({
if (symbol == Clutter.KEY_Right) { if (symbol == Clutter.KEY_Right) {
this._setOpenState(true); this._setOpenState(true);
this.menu.actor.navigate_focus(null, Gtk.DirectionType.DOWN, false); this.menu.actor.navigate_focus(null, Gtk.DirectionType.DOWN, false);
return true; return Clutter.EVENT_STOP;
} else if (symbol == Clutter.KEY_Left && this._getOpenState()) { } else if (symbol == Clutter.KEY_Left && this._getOpenState()) {
this._setOpenState(false); this._setOpenState(false);
return true; return Clutter.EVENT_STOP;
} }
return this.parent(actor, event); return this.parent(actor, event);
@ -1071,6 +1071,7 @@ const PopupSubMenuMenuItem = new Lang.Class({
_onButtonReleaseEvent: function(actor) { _onButtonReleaseEvent: function(actor) {
this._setOpenState(!this._getOpenState()); this._setOpenState(!this._getOpenState());
return Clutter.EVENT_PROPAGATE;
} }
}); });
@ -1102,7 +1103,7 @@ const PopupMenuManager = new Lang.Class({
if (source) { if (source) {
if (!menu.blockSourceEvents) if (!menu.blockSourceEvents)
this._grabHelper.addActor(source); this._grabHelper.addActor(source);
menudata.enterId = source.connect('enter-event', Lang.bind(this, function() { this._onMenuSourceEnter(menu); })); menudata.enterId = source.connect('enter-event', Lang.bind(this, function() { return this._onMenuSourceEnter(menu); }));
menudata.focusInId = source.connect('key-focus-in', Lang.bind(this, function() { this._onMenuSourceEnter(menu); })); menudata.focusInId = source.connect('key-focus-in', Lang.bind(this, function() { this._onMenuSourceEnter(menu); }));
} }
@ -1164,13 +1165,13 @@ const PopupMenuManager = new Lang.Class({
_onMenuSourceEnter: function(menu) { _onMenuSourceEnter: function(menu) {
if (!this._grabHelper.grabbed) if (!this._grabHelper.grabbed)
return false; return Clutter.EVENT_PROPAGATE;
if (this._grabHelper.isActorGrabbed(menu.actor)) if (this._grabHelper.isActorGrabbed(menu.actor))
return false; return Clutter.EVENT_PROPAGATE;
this._changeMenu(menu); this._changeMenu(menu);
return false; return Clutter.EVENT_PROPAGATE;
}, },
_onMenuDestroy: function(menu) { _onMenuDestroy: function(menu) {

View File

@ -191,7 +191,9 @@ const RemoteSearchProvider = new Lang.Class({
}, },
createIcon: function(size, meta) { createIcon: function(size, meta) {
let gicon; let gicon = null;
let icon = null;
if (meta['icon']) { if (meta['icon']) {
gicon = Gio.icon_deserialize(meta['icon']); gicon = Gio.icon_deserialize(meta['icon']);
} else if (meta['gicon']) { } else if (meta['gicon']) {
@ -203,8 +205,10 @@ const RemoteSearchProvider = new Lang.Class({
bitsPerSample, width, height, rowStride); bitsPerSample, width, height, rowStride);
} }
return new St.Icon({ gicon: gicon, if (gicon)
icon_size: size }); icon = new St.Icon({ gicon: gicon,
icon_size: size });
return icon;
}, },
filterResults: function(results, maxNumber) { filterResults: function(results, maxNumber) {
@ -279,7 +283,7 @@ const RemoteSearchProvider = new Lang.Class({
// the provider is not compatible with the new version of the interface, launch // the provider is not compatible with the new version of the interface, launch
// the app itself but warn so we can catch the error in logs // the app itself but warn so we can catch the error in logs
log('Search provider ' + this.appInfo.get_id() + ' does not implement LaunchSearch'); log('Search provider ' + this.appInfo.get_id() + ' does not implement LaunchSearch');
this.appInfo.launch([], global.create_app_launch_context()); this.appInfo.launch([], global.create_app_launch_context(0, -1));
} }
}); });

View File

@ -73,7 +73,9 @@ const RunDialog = new Lang.Class({
let label = new St.Label({ style_class: 'run-dialog-label', let label = new St.Label({ style_class: 'run-dialog-label',
text: _("Enter a Command") }); text: _("Enter a Command") });
this.contentLayout.add(label, { y_align: St.Align.START }); this.contentLayout.add(label, { x_fill: false,
x_align: St.Align.START,
y_align: St.Align.START });
let entry = new St.Entry({ style_class: 'run-dialog-entry', let entry = new St.Entry({ style_class: 'run-dialog-entry',
can_focus: true }); can_focus: true });
@ -101,6 +103,8 @@ const RunDialog = new Lang.Class({
this._errorMessage.clutter_text.line_wrap = true; this._errorMessage.clutter_text.line_wrap = true;
this._errorBox.add(this._errorMessage, { expand: true, this._errorBox.add(this._errorMessage, { expand: true,
x_align: St.Align.START,
x_fill: false,
y_align: St.Align.MIDDLE, y_align: St.Align.MIDDLE,
y_fill: false }); y_fill: false });
@ -124,7 +128,7 @@ const RunDialog = new Lang.Class({
!this.pushModal()) !this.pushModal())
this.close(); this.close();
return true; return Clutter.EVENT_STOP;
} }
if (symbol == Clutter.Tab) { if (symbol == Clutter.Tab) {
let text = o.get_text(); let text = o.get_text();
@ -138,9 +142,9 @@ const RunDialog = new Lang.Class({
o.insert_text(postfix, -1); o.insert_text(postfix, -1);
o.set_cursor_position(text.length + postfix.length); o.set_cursor_position(text.length + postfix.length);
} }
return true; return Clutter.EVENT_STOP;
} }
return false; return Clutter.EVENT_PROPAGATE;
})); }));
}, },
@ -229,7 +233,7 @@ const RunDialog = new Lang.Class({
let file = Gio.file_new_for_path(path); let file = Gio.file_new_for_path(path);
try { try {
Gio.app_info_launch_default_for_uri(file.get_uri(), Gio.app_info_launch_default_for_uri(file.get_uri(),
global.create_app_launch_context()); global.create_app_launch_context(0, -1));
} catch (e) { } catch (e) {
// The exception from gjs contains an error string like: // The exception from gjs contains an error string like:
// Error invoking Gio.app_info_launch_default_for_uri: No application // Error invoking Gio.app_info_launch_default_for_uri: No application

View File

@ -17,7 +17,6 @@ const TweenerEquations = imports.tweener.equations;
const Background = imports.ui.background; const Background = imports.ui.background;
const GnomeSession = imports.misc.gnomeSession; const GnomeSession = imports.misc.gnomeSession;
const Hash = imports.misc.hash;
const Layout = imports.ui.layout; const Layout = imports.ui.layout;
const OVirt = imports.gdm.oVirt; const OVirt = imports.gdm.oVirt;
const LoginManager = imports.misc.loginManager; const LoginManager = imports.misc.loginManager;
@ -115,7 +114,7 @@ const NotificationsBox = new Lang.Class({
this.actor.add(this._musicBin); this.actor.add(this._musicBin);
this.actor.add(this._scrollView, { x_fill: true, x_align: St.Align.START }); this.actor.add(this._scrollView, { x_fill: true, x_align: St.Align.START });
this._sources = new Hash.Map(); this._sources = new Map();
Main.messageTray.getSources().forEach(Lang.bind(this, function(source) { Main.messageTray.getSources().forEach(Lang.bind(this, function(source) {
this._sourceAdded(Main.messageTray, source, true); this._sourceAdded(Main.messageTray, source, true);
})); }));
@ -130,9 +129,8 @@ const NotificationsBox = new Lang.Class({
this._sourceAddedId = 0; this._sourceAddedId = 0;
} }
let items = this._sources.items(); let items = this._sources.entries();
for (let i = 0; i < items.length; i++) { for (let [source, obj] of items) {
let [source, obj] = items[i];
this._removeSource(source, obj); this._removeSource(source, obj);
} }
@ -240,10 +238,6 @@ const NotificationsBox = new Lang.Class({
}, },
_sourceAdded: function(tray, source, initial) { _sourceAdded: function(tray, source, initial) {
// Ignore transient sources
if (source.isTransient)
return;
let obj = { let obj = {
visible: source.policy.showInLockScreen, visible: source.policy.showInLockScreen,
detailed: source.policy.detailsInLockScreen, detailed: source.policy.detailsInLockScreen,
@ -419,6 +413,7 @@ const Arrow = new Lang.Class({
cr.lineTo(w/2, thickness); cr.lineTo(w/2, thickness);
cr.lineTo(w - thickness / 2, h - thickness / 2); cr.lineTo(w - thickness / 2, h - thickness / 2);
cr.stroke(); cr.stroke();
cr.$dispose();
}, },
vfunc_style_changed: function() { vfunc_style_changed: function() {
@ -461,8 +456,6 @@ const ScreenShield = new Lang.Class({
Name: 'ScreenShield', Name: 'ScreenShield',
_init: function() { _init: function() {
this.actor = Main.layoutManager.screenShieldGroup;
this._lockScreenState = MessageTray.State.HIDDEN; this._lockScreenState = MessageTray.State.HIDDEN;
this._lockScreenGroup = new St.Widget({ x_expand: true, this._lockScreenGroup = new St.Widget({ x_expand: true,
y_expand: true, y_expand: true,
@ -471,6 +464,7 @@ const ScreenShield = new Lang.Class({
name: 'lockScreenGroup', name: 'lockScreenGroup',
visible: false, visible: false,
}); });
this._lockScreenGroup.connect('key-press-event', this._lockScreenGroup.connect('key-press-event',
Lang.bind(this, this._onLockScreenKeyPress)); Lang.bind(this, this._onLockScreenKeyPress));
this._lockScreenGroup.connect('scroll-event', this._lockScreenGroup.connect('scroll-event',
@ -521,10 +515,9 @@ const ScreenShield = new Lang.Class({
reactive: true, reactive: true,
pivot_point: new Clutter.Point({ x: 0.5, y: 0.5 }), pivot_point: new Clutter.Point({ x: 0.5, y: 0.5 }),
name: 'lockDialogGroup' }); name: 'lockDialogGroup' });
Main.layoutManager.systemGroup.add_child(this._lockDialogGroup);
this.actor.add_actor(this._lockDialogGroup); Main.layoutManager.screenShieldGroup.add_child(this._lockScreenGroup);
this.actor.add_actor(this._lockScreenGroup);
this._presence = new GnomeSession.Presence(Lang.bind(this, function(proxy, error) { this._presence = new GnomeSession.Presence(Lang.bind(this, function(proxy, error) {
if (error) { if (error) {
logError(error, 'Error while reading gnome-session presence'); logError(error, 'Error while reading gnome-session presence');
@ -582,19 +575,27 @@ const ScreenShield = new Lang.Class({
// The "long" lightbox is used for the longer (20 seconds) fade from session // The "long" lightbox is used for the longer (20 seconds) fade from session
// to idle status, the "short" is used for quickly fading to black when locking // to idle status, the "short" is used for quickly fading to black when locking
// manually // manually
this._longLightbox = new Lightbox.Lightbox(Main.uiGroup, this._longLightbox = new Lightbox.Lightbox(Main.layoutManager.overlayGroup,
{ inhibitEvents: true, { inhibitEvents: true,
fadeFactor: 1 }); fadeFactor: 1 });
this._longLightbox.connect('shown', Lang.bind(this, this._onLongLightboxShown)); this._longLightbox.connect('shown', Lang.bind(this, this._onLongLightboxShown));
this._shortLightbox = new Lightbox.Lightbox(Main.uiGroup, this._shortLightbox = new Lightbox.Lightbox(Main.layoutManager.overlayGroup,
{ inhibitEvents: true, { inhibitEvents: true,
fadeFactor: 1 }); fadeFactor: 1 });
this._shortLightbox.connect('shown', Lang.bind(this, this._onShortLightboxShown)); this._shortLightbox.connect('shown', Lang.bind(this, this._onShortLightboxShown));
Main.layoutManager.connect('monitors-changed', Lang.bind(this, this._monitorsChanged));
this._monitorsChanged();
this.idleMonitor = Meta.IdleMonitor.get_core(); this.idleMonitor = Meta.IdleMonitor.get_core();
this._cursorTracker = Meta.CursorTracker.get_for_screen(global.screen); this._cursorTracker = Meta.CursorTracker.get_for_screen(global.screen);
}, },
_monitorsChanged: function() {
this._longLightbox.actor.set_size(global.screen_width, global.screen_height);
this._shortLightbox.actor.set_size(global.screen_width, global.screen_height);
},
_createBackground: function(monitorIndex) { _createBackground: function(monitorIndex) {
let monitor = Main.layoutManager.monitors[monitorIndex]; let monitor = Main.layoutManager.monitors[monitorIndex];
let widget = new St.Widget({ style_class: 'screen-shield-background', let widget = new St.Widget({ style_class: 'screen-shield-background',
@ -652,14 +653,14 @@ const ScreenShield = new Lang.Class({
if (this._isModal) if (this._isModal)
return true; return true;
this._isModal = Main.pushModal(this.actor, { keybindingMode: Shell.KeyBindingMode.LOCK_SCREEN }); this._isModal = Main.pushModal(this._lockDialogGroup, { keybindingMode: Shell.KeyBindingMode.LOCK_SCREEN });
if (this._isModal) if (this._isModal)
return true; return true;
// We failed to get a pointer grab, it means that // We failed to get a pointer grab, it means that
// something else has it. Try with a keyboard grab only // something else has it. Try with a keyboard grab only
this._isModal = Main.pushModal(this.actor, { options: Meta.ModalOptions.POINTER_ALREADY_GRABBED, this._isModal = Main.pushModal(this._lockDialogGroup, { options: Meta.ModalOptions.POINTER_ALREADY_GRABBED,
keybindingMode: Shell.KeyBindingMode.LOCK_SCREEN }); keybindingMode: Shell.KeyBindingMode.LOCK_SCREEN });
return this._isModal; return this._isModal;
}, },
@ -673,11 +674,11 @@ const ScreenShield = new Lang.Class({
// down after cancel. // down after cancel.
if (this._lockScreenState != MessageTray.State.SHOWN) if (this._lockScreenState != MessageTray.State.SHOWN)
return false; return Clutter.EVENT_PROPAGATE;
let isEnter = (symbol == Clutter.KEY_Return || symbol == Clutter.KEY_KP_Enter); let isEnter = (symbol == Clutter.KEY_Return || symbol == Clutter.KEY_KP_Enter);
if (!isEnter && !(GLib.unichar_isprint(unichar) || symbol == Clutter.KEY_Escape)) if (!isEnter && !(GLib.unichar_isprint(unichar) || symbol == Clutter.KEY_Escape))
return false; return Clutter.EVENT_PROPAGATE;
if (this._isLocked && if (this._isLocked &&
this._ensureUnlockDialog(true, true) && this._ensureUnlockDialog(true, true) &&
@ -685,12 +686,12 @@ const ScreenShield = new Lang.Class({
this._dialog.addCharacter(unichar); this._dialog.addCharacter(unichar);
this._liftShield(true, 0); this._liftShield(true, 0);
return true; return Clutter.EVENT_STOP;
}, },
_onLockScreenScroll: function(actor, event) { _onLockScreenScroll: function(actor, event) {
if (this._lockScreenState != MessageTray.State.SHOWN) if (this._lockScreenState != MessageTray.State.SHOWN)
return false; return Clutter.EVENT_PROPAGATE;
let delta = 0; let delta = 0;
if (event.get_scroll_direction() == Clutter.ScrollDirection.UP) if (event.get_scroll_direction() == Clutter.ScrollDirection.UP)
@ -705,7 +706,7 @@ const ScreenShield = new Lang.Class({
this._liftShield(true, 0); this._liftShield(true, 0);
} }
return true; return Clutter.EVENT_STOP;
}, },
_inhibitSuspend: function() { _inhibitSuspend: function() {
@ -756,7 +757,7 @@ const ScreenShield = new Lang.Class({
}); });
} }
return true; return GLib.SOURCE_CONTINUE;
}, },
_onDragBegin: function() { _onDragBegin: function() {
@ -852,7 +853,7 @@ const ScreenShield = new Lang.Class({
Lang.bind(this, function() { Lang.bind(this, function() {
this._lockTimeoutId = 0; this._lockTimeoutId = 0;
this.lock(false); this.lock(false);
return false; return GLib.SOURCE_REMOVE;
})); }));
} }
@ -917,7 +918,7 @@ const ScreenShield = new Lang.Class({
return false; return false;
})); }));
this.actor.show(); this._lockDialogGroup.show();
this._isGreeter = Main.sessionMode.isGreeter; this._isGreeter = Main.sessionMode.isGreeter;
this._isLocked = true; this._isLocked = true;
if (this._ensureUnlockDialog(true, true)) if (this._ensureUnlockDialog(true, true))
@ -1007,6 +1008,7 @@ const ScreenShield = new Lang.Class({
return; return;
this._ensureLockScreen(); this._ensureLockScreen();
this._lockDialogGroup.hide();
this._lockDialogGroup.scale_x = 1; this._lockDialogGroup.scale_x = 1;
this._lockDialogGroup.scale_y = 1; this._lockDialogGroup.scale_y = 1;
@ -1101,12 +1103,14 @@ const ScreenShield = new Lang.Class({
global.stage.disconnect(motionId); global.stage.disconnect(motionId);
} }
return false; return Clutter.EVENT_PROPAGATE;
})); }));
this._cursorTracker.set_pointer_visible(false); this._cursorTracker.set_pointer_visible(false);
this._lockScreenState = MessageTray.State.SHOWN; this._lockDialogGroup.show();
this._lockScreenGroup.fixed_position_set = false; this._lockScreenGroup.fixed_position_set = false;
this._lockScreenState = MessageTray.State.SHOWN;
Main.layoutManager.sessionGroup.hide();
this._lockScreenScrollCounter = 0; this._lockScreenScrollCounter = 0;
if (params.fadeToBlack && params.animateFade) { if (params.fadeToBlack && params.animateFade) {
@ -1114,6 +1118,7 @@ const ScreenShield = new Lang.Class({
Mainloop.timeout_add(1000 * MANUAL_FADE_TIME, Lang.bind(this, function() { Mainloop.timeout_add(1000 * MANUAL_FADE_TIME, Lang.bind(this, function() {
this._activateFade(this._shortLightbox, MANUAL_FADE_TIME); this._activateFade(this._shortLightbox, MANUAL_FADE_TIME);
return GLib.SOURCE_REMOVE;
})); }));
} else { } else {
if (params.fadeToBlack) if (params.fadeToBlack)
@ -1228,10 +1233,11 @@ const ScreenShield = new Lang.Class({
this._dialog.popModal(); this._dialog.popModal();
if (this._isModal) { if (this._isModal) {
Main.popModal(this.actor); Main.popModal(this._lockDialogGroup);
this._isModal = false; this._isModal = false;
} }
Main.layoutManager.sessionGroup.show();
Tweener.addTween(this._lockDialogGroup, { Tweener.addTween(this._lockDialogGroup, {
scale_x: 0, scale_x: 0,
scale_y: 0, scale_y: 0,
@ -1250,7 +1256,7 @@ const ScreenShield = new Lang.Class({
this._longLightbox.hide(); this._longLightbox.hide();
this._shortLightbox.hide(); this._shortLightbox.hide();
this.actor.hide(); this._lockScreenGroup.hide();
if (this._becameActiveId != 0) { if (this._becameActiveId != 0) {
this.idleMonitor.remove_watch(this._becameActiveId); this.idleMonitor.remove_watch(this._becameActiveId);
@ -1274,7 +1280,7 @@ const ScreenShield = new Lang.Class({
if (this._activationTime == 0) if (this._activationTime == 0)
this._activationTime = GLib.get_monotonic_time(); this._activationTime = GLib.get_monotonic_time();
this.actor.show(); this._lockScreenGroup.show();
if (Main.sessionMode.currentMode != 'unlock-dialog' && if (Main.sessionMode.currentMode != 'unlock-dialog' &&
Main.sessionMode.currentMode != 'lock-screen') { Main.sessionMode.currentMode != 'lock-screen') {

View File

@ -6,7 +6,6 @@ const Lang = imports.lang;
const Shell = imports.gi.Shell; const Shell = imports.gi.Shell;
const Signals = imports.signals; const Signals = imports.signals;
const Hash = imports.misc.hash;
const Main = imports.ui.main; const Main = imports.ui.main;
const ScreencastIface = '<node> \ const ScreencastIface = '<node> \
@ -42,13 +41,13 @@ const ScreencastService = new Lang.Class({
Gio.DBus.session.own_name('org.gnome.Shell.Screencast', Gio.BusNameOwnerFlags.REPLACE, null, null); Gio.DBus.session.own_name('org.gnome.Shell.Screencast', Gio.BusNameOwnerFlags.REPLACE, null, null);
this._recorders = new Hash.Map(); this._recorders = new Map();
Main.sessionMode.connect('updated', Lang.bind(this, this._sessionUpdated)); Main.sessionMode.connect('updated', Lang.bind(this, this._sessionUpdated));
}, },
get isRecording() { get isRecording() {
return this._recorders.size() > 0; return this._recorders.size > 0;
}, },
_ensureRecorderForSender: function(sender) { _ensureRecorderForSender: function(sender) {
@ -69,8 +68,7 @@ const ScreencastService = new Lang.Class({
if (Main.sessionMode.allowScreencast) if (Main.sessionMode.allowScreencast)
return; return;
for (let sender in this._recorders.keys()) this._recorders.clear();
this._recorders.delete(sender);
this.emit('updated'); this.emit('updated');
}, },

View File

@ -146,7 +146,7 @@ const SelectArea = new Lang.Class({
reactive: true, reactive: true,
x: 0, x: 0,
y: 0 }); y: 0 });
Main.uiGroup.add_actor(this._group); Main.layoutManager.osdGroup.add_actor(this._group);
this._group.connect('button-press-event', this._group.connect('button-press-event',
Lang.bind(this, this._onButtonPress)); Lang.bind(this, this._onButtonPress));
@ -206,12 +206,12 @@ const SelectArea = new Lang.Class({
if (event.get_key_symbol() == Clutter.Escape) if (event.get_key_symbol() == Clutter.Escape)
this._destroy(null, false); this._destroy(null, false);
return; return Clutter.EVENT_PROPAGATE;
}, },
_onMotionEvent: function(actor, event) { _onMotionEvent: function(actor, event) {
if (this._startX == -1 || this._startY == -1) if (this._startX == -1 || this._startY == -1)
return false; return Clutter.EVENT_PROPAGATE;
[this._lastX, this._lastY] = event.get_coords(); [this._lastX, this._lastY] = event.get_coords();
let geometry = this._getGeometry(); let geometry = this._getGeometry();
@ -219,19 +219,19 @@ const SelectArea = new Lang.Class({
this._rubberband.set_position(geometry.x, geometry.y); this._rubberband.set_position(geometry.x, geometry.y);
this._rubberband.set_size(geometry.width, geometry.height); this._rubberband.set_size(geometry.width, geometry.height);
return false; return Clutter.EVENT_PROPAGATE;
}, },
_onButtonPress: function(actor, event) { _onButtonPress: function(actor, event) {
[this._startX, this._startY] = event.get_coords(); [this._startX, this._startY] = event.get_coords();
this._rubberband.set_position(this._startX, this._startY); this._rubberband.set_position(this._startX, this._startY);
return false; return Clutter.EVENT_PROPAGATE;
}, },
_onButtonRelease: function(actor, event) { _onButtonRelease: function(actor, event) {
this._destroy(this._getGeometry(), true); this._destroy(this._getGeometry(), true);
return false; return Clutter.EVENT_PROPAGATE;
}, },
_destroy: function(geometry, fade) { _destroy: function(geometry, fade) {
@ -259,9 +259,9 @@ const Flashspot = new Lang.Class({
Extends: Lightbox.Lightbox, Extends: Lightbox.Lightbox,
_init: function(area) { _init: function(area) {
this.parent(Main.uiGroup, { inhibitEvents: true, this.parent(Main.layoutManager.osdGroup, { inhibitEvents: true,
width: area.width, width: area.width,
height: area.height }); height: area.height });
this.actor.style_class = 'flashspot'; this.actor.style_class = 'flashspot';
this.actor.set_position(area.x, area.y); this.actor.set_position(area.x, area.y);

View File

@ -1,6 +1,7 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
const Gio = imports.gi.Gio; const Gio = imports.gi.Gio;
const GLib = imports.gi.GLib;
const Mainloop = imports.mainloop; const Mainloop = imports.mainloop;
const Meta = imports.gi.Meta; const Meta = imports.gi.Meta;
const Shell = imports.gi.Shell; const Shell = imports.gi.Shell;
@ -41,7 +42,7 @@ function sleep(milliseconds) {
Mainloop.timeout_add(milliseconds, function() { Mainloop.timeout_add(milliseconds, function() {
if (cb) if (cb)
cb(); cb();
return false; return GLib.SOURCE_REMOVE;
}); });
return function(callback) { return function(callback) {

View File

@ -120,22 +120,22 @@ function _loadMode(file, info) {
_modes[modeName] = {}; _modes[modeName] = {};
let propBlacklist = ['unlockDialog']; let propBlacklist = ['unlockDialog'];
for (let prop in loadedData[DEFAULT_MODE]) { for (let prop in _modes[DEFAULT_MODE]) {
if (newMode[prop] !== undefined && if (newMode[prop] !== undefined &&
propBlacklist.indexOf(prop) == -1) propBlacklist.indexOf(prop) == -1)
loadedData[modeName][prop] = newMode[prop]; _modes[modeName][prop] = newMode[prop];
} }
_modes[modeName]['isPrimary'] = true; _modes[modeName]['isPrimary'] = true;
} }
function _getModes() { function _loadModes() {
FileUtils.collectFromDatadirs('modes', false, _loadMode); FileUtils.collectFromDatadirs('modes', false, _loadMode);
} }
function listModes() { function listModes() {
let modes = _getModes(); _loadModes();
modes.forEach(function() { Mainloop.idle_add(function() {
let names = Object.getOwnPropertyNames(modes); let names = Object.getOwnPropertyNames(_modes);
for (let i = 0; i < names.length; i++) for (let i = 0; i < names.length; i++)
if (_modes[names[i]].isPrimary) if (_modes[names[i]].isPrimary)
print(names[i]); print(names[i]);
@ -148,6 +148,7 @@ const SessionMode = new Lang.Class({
Name: 'SessionMode', Name: 'SessionMode',
_init: function() { _init: function() {
_loadModes();
let isPrimary = (_modes[global.session_mode] && let isPrimary = (_modes[global.session_mode] &&
_modes[global.session_mode].isPrimary); _modes[global.session_mode].isPrimary);
let mode = isPrimary ? global.session_mode : 'user'; let mode = isPrimary ? global.session_mode : 'user';

View File

@ -10,7 +10,6 @@ const Config = imports.misc.config;
const ExtensionSystem = imports.ui.extensionSystem; const ExtensionSystem = imports.ui.extensionSystem;
const ExtensionDownloader = imports.ui.extensionDownloader; const ExtensionDownloader = imports.ui.extensionDownloader;
const ExtensionUtils = imports.misc.extensionUtils; const ExtensionUtils = imports.misc.extensionUtils;
const Hash = imports.misc.hash;
const Main = imports.ui.main; const Main = imports.ui.main;
const Screenshot = imports.ui.screenshot; const Screenshot = imports.ui.screenshot;
const ViewSelector = imports.ui.viewSelector; const ViewSelector = imports.ui.viewSelector;
@ -83,8 +82,8 @@ const GnomeShell = new Lang.Class({
this._extensionsService = new GnomeShellExtensions(); this._extensionsService = new GnomeShellExtensions();
this._screenshotService = new Screenshot.ScreenshotService(); this._screenshotService = new Screenshot.ScreenshotService();
this._grabbedAccelerators = new Hash.Map(); this._grabbedAccelerators = new Map();
this._grabbers = new Hash.Map(); this._grabbers = new Map();
global.display.connect('accelerator-activated', Lang.bind(this, global.display.connect('accelerator-activated', Lang.bind(this,
function(display, action, deviceid, timestamp) { function(display, action, deviceid, timestamp) {
@ -133,11 +132,16 @@ const GnomeShell = new Lang.Class({
for (let param in params) for (let param in params)
params[param] = params[param].deep_unpack(); params[param] = params[param].deep_unpack();
let monitorIndex = -1;
if (params['monitor'])
monitorIndex = params['monitor'];
let icon = null; let icon = null;
if (params['icon']) if (params['icon'])
icon = Gio.Icon.new_for_string(params['icon']); icon = Gio.Icon.new_for_string(params['icon']);
Main.osdWindow.setIcon(icon); Main.osdWindow.setIcon(icon);
Main.osdWindow.setMonitor (monitorIndex);
Main.osdWindow.setLabel(params['label']); Main.osdWindow.setLabel(params['label']);
Main.osdWindow.setLevel(params['level']); Main.osdWindow.setLevel(params['level']);
@ -223,9 +227,8 @@ const GnomeShell = new Lang.Class({
}, },
_onGrabberBusNameVanished: function(connection, name) { _onGrabberBusNameVanished: function(connection, name) {
let grabs = this._grabbedAccelerators.items(); let grabs = this._grabbedAccelerators.entries();
for (let i = 0; i < grabs.length; i++) { for (let [action, sender] of grabs) {
let [action, sender] = grabs[i];
if (sender == name) if (sender == name)
this._ungrabAccelerator(action); this._ungrabAccelerator(action);
} }

View File

@ -36,7 +36,7 @@ const EntryMenu = new Lang.Class({
this._passwordItem = null; this._passwordItem = null;
Main.uiGroup.add_actor(this.actor); Main.layoutManager.menuGroup.add_actor(this.actor);
this.actor.hide(); this.actor.hide();
}, },
@ -132,14 +132,14 @@ function _setMenuAlignment(entry, stageX) {
function _onButtonPressEvent(actor, event, entry) { function _onButtonPressEvent(actor, event, entry) {
if (entry.menu.isOpen) { if (entry.menu.isOpen) {
entry.menu.close(BoxPointer.PopupAnimation.FULL); entry.menu.close(BoxPointer.PopupAnimation.FULL);
return true; return Clutter.EVENT_STOP;
} else if (event.get_button() == 3) { } else if (event.get_button() == 3) {
let [stageX, stageY] = event.get_coords(); let [stageX, stageY] = event.get_coords();
_setMenuAlignment(entry, stageX); _setMenuAlignment(entry, stageX);
entry.menu.open(BoxPointer.PopupAnimation.FULL); entry.menu.open(BoxPointer.PopupAnimation.FULL);
return true; return Clutter.EVENT_STOP;
} }
return false; return Clutter.EVENT_PROPAGATE;
}; };
function _onPopup(actor, entry) { function _onPopup(actor, entry) {

View File

@ -111,12 +111,12 @@ const Slider = new Lang.Class({
}, },
_startDragging: function(actor, event) { _startDragging: function(actor, event) {
this.startDragging(event); return this.startDragging(event);
}, },
startDragging: function(event) { startDragging: function(event) {
if (this._dragging) if (this._dragging)
return false; return Clutter.EVENT_PROPAGATE;
this._dragging = true; this._dragging = true;
@ -129,7 +129,7 @@ const Slider = new Lang.Class({
let absX, absY; let absX, absY;
[absX, absY] = event.get_coords(); [absX, absY] = event.get_coords();
this._moveHandle(absX, absY); this._moveHandle(absX, absY);
return true; return Clutter.EVENT_STOP;
}, },
_endDragging: function() { _endDragging: function() {
@ -143,7 +143,7 @@ const Slider = new Lang.Class({
this.emit('drag-end'); this.emit('drag-end');
} }
return true; return Clutter.EVENT_STOP;
}, },
scroll: function(event) { scroll: function(event) {
@ -151,7 +151,7 @@ const Slider = new Lang.Class({
let delta; let delta;
if (event.is_pointer_emulated()) if (event.is_pointer_emulated())
return; return Clutter.EVENT_PROPAGATE;
if (direction == Clutter.ScrollDirection.DOWN) { if (direction == Clutter.ScrollDirection.DOWN) {
delta = -SLIDER_SCROLL_STEP; delta = -SLIDER_SCROLL_STEP;
@ -168,17 +168,18 @@ const Slider = new Lang.Class({
this.actor.queue_repaint(); this.actor.queue_repaint();
this.emit('value-changed', this._value); this.emit('value-changed', this._value);
return Clutter.EVENT_STOP;
}, },
_onScrollEvent: function(actor, event) { _onScrollEvent: function(actor, event) {
this.scroll(event); return this.scroll(event);
}, },
_motionEvent: function(actor, event) { _motionEvent: function(actor, event) {
let absX, absY; let absX, absY;
[absX, absY] = event.get_coords(); [absX, absY] = event.get_coords();
this._moveHandle(absX, absY); this._moveHandle(absX, absY);
return true; return Clutter.EVENT_STOP;
}, },
onKeyPressEvent: function (actor, event) { onKeyPressEvent: function (actor, event) {
@ -189,9 +190,9 @@ const Slider = new Lang.Class({
this.actor.queue_repaint(); this.actor.queue_repaint();
this.emit('value-changed', this._value); this.emit('value-changed', this._value);
this.emit('drag-end'); this.emit('drag-end');
return true; return Clutter.EVENT_STOP;
} }
return false; return Clutter.EVENT_PROPAGATE;
}, },
_moveHandle: function(absX, absY) { _moveHandle: function(absX, absY) {

View File

@ -2,6 +2,7 @@
const Clutter = imports.gi.Clutter; const Clutter = imports.gi.Clutter;
const Gio = imports.gi.Gio; const Gio = imports.gi.Gio;
const GLib = imports.gi.GLib;
const Lang = imports.lang; const Lang = imports.lang;
const Mainloop = imports.mainloop; const Mainloop = imports.mainloop;
const St = imports.gi.St; const St = imports.gi.St;
@ -94,7 +95,7 @@ const ATIndicator = new Lang.Class({
this.actor.visible = alwaysShow || items.some(function(f) { return !!f.state; }); this.actor.visible = alwaysShow || items.some(function(f) { return !!f.state; });
return false; return GLib.SOURCE_REMOVE;
}, },
_queueSyncMenuVisibility: function() { _queueSyncMenuVisibility: function() {

View File

@ -2,16 +2,26 @@
const Clutter = imports.gi.Clutter; const Clutter = imports.gi.Clutter;
const GLib = imports.gi.GLib; const GLib = imports.gi.GLib;
const GnomeBluetoothApplet = imports.gi.GnomeBluetoothApplet; const Gio = imports.gi.Gio;
const GnomeBluetooth = imports.gi.GnomeBluetooth; const GnomeBluetooth = imports.gi.GnomeBluetooth;
const Lang = imports.lang; const Lang = imports.lang;
const St = imports.gi.St; const St = imports.gi.St;
const Main = imports.ui.main; const Main = imports.ui.main;
const MessageTray = imports.ui.messageTray;
const PanelMenu = imports.ui.panelMenu; const PanelMenu = imports.ui.panelMenu;
const PopupMenu = imports.ui.popupMenu; const PopupMenu = imports.ui.popupMenu;
const BUS_NAME = 'org.gnome.SettingsDaemon.Rfkill';
const OBJECT_PATH = '/org/gnome/SettingsDaemon/Rfkill';
const RfkillManagerInterface = '<node> \
<interface name="org.gnome.SettingsDaemon.Rfkill"> \
<property name="BluetoothAirplaneMode" type="b" access="readwrite" /> \
</interface> \
</node>';
const RfkillManagerProxy = Gio.DBusProxy.makeProxyWrapper(RfkillManagerInterface);
const Indicator = new Lang.Class({ const Indicator = new Lang.Class({
Name: 'BTIndicator', Name: 'BTIndicator',
Extends: PanelMenu.SystemIndicator, Extends: PanelMenu.SystemIndicator,
@ -22,32 +32,63 @@ const Indicator = new Lang.Class({
this._indicator = this._addIndicator(); this._indicator = this._addIndicator();
this._indicator.icon_name = 'bluetooth-active-symbolic'; this._indicator.icon_name = 'bluetooth-active-symbolic';
this._proxy = new RfkillManagerProxy(Gio.DBus.session, BUS_NAME, OBJECT_PATH,
Lang.bind(this, function(proxy, error) {
if (error) {
log(error.message);
return;
}
}));
// The Bluetooth menu only appears when Bluetooth is in use, // The Bluetooth menu only appears when Bluetooth is in use,
// so just statically build it with a "Turn Off" menu item. // so just statically build it with a "Turn Off" menu item.
this._item = new PopupMenu.PopupSubMenuMenuItem(_("Bluetooth"), true); this._item = new PopupMenu.PopupSubMenuMenuItem(_("Bluetooth"), true);
this._item.icon.icon_name = 'bluetooth-active-symbolic'; this._item.icon.icon_name = 'bluetooth-active-symbolic';
this._item.menu.addAction(_("Turn Off"), Lang.bind(this, function() { this._item.menu.addAction(_("Turn Off"), Lang.bind(this, function() {
this._applet.killswitch_state = GnomeBluetooth.KillswitchState.SOFT_BLOCKED; this._proxy.BluetoothAirplaneMode = true;
})); }));
this._item.menu.addSettingsAction(_("Bluetooth Settings"), 'gnome-bluetooth-panel.desktop'); this._item.menu.addSettingsAction(_("Bluetooth Settings"), 'gnome-bluetooth-panel.desktop');
this.menu.addMenuItem(this._item); this.menu.addMenuItem(this._item);
this._applet = new GnomeBluetoothApplet.Applet(); this._client = new GnomeBluetooth.Client();
this._applet.connect('devices-changed', Lang.bind(this, this._sync)); this._model = this._client.get_model();
this._model.connect('row-changed', Lang.bind(this, this._sync));
this._model.connect('row-deleted', Lang.bind(this, this._sync));
this._model.connect('row-inserted', Lang.bind(this, this._sync));
this._sync(); this._sync();
},
this._applet.connect('pincode-request', Lang.bind(this, this._pinRequest)); _getDefaultAdapter: function() {
this._applet.connect('confirm-request', Lang.bind(this, this._confirmRequest)); let [ret, iter] = this._model.get_iter_first();
this._applet.connect('auth-request', Lang.bind(this, this._authRequest)); while (ret) {
this._applet.connect('auth-service-request', Lang.bind(this, this._authServiceRequest)); let isDefault = this._model.get_value(iter,
this._applet.connect('cancel-request', Lang.bind(this, this._cancelRequest)); GnomeBluetooth.Column.DEFAULT);
if (isDefault)
return iter;
ret = this._model.iter_next(iter);
}
return null;
},
_getNConnectedDevices: function() {
let adapter = this._getDefaultAdapter();
if (!adapter)
return 0;
let nDevices = 0;
let [ret, iter] = this._model.iter_children(adapter);
while (ret) {
let isConnected = this._model.get_value(iter,
GnomeBluetooth.Column.CONNECTED);
if (isConnected)
nDevices++;
ret = this._model.iter_next(iter);
}
return nDevices;
}, },
_sync: function() { _sync: function() {
let connectedDevices = this._applet.get_devices().filter(function(device) { let nDevices = this._getNConnectedDevices();
return device.connected;
});
let nDevices = connectedDevices.length;
let on = nDevices > 0; let on = nDevices > 0;
this._indicator.visible = on; this._indicator.visible = on;
@ -56,204 +97,4 @@ const Indicator = new Lang.Class({
if (on) if (on)
this._item.status.text = ngettext("%d Connected Device", "%d Connected Devices", nDevices).format(nDevices); this._item.status.text = ngettext("%d Connected Device", "%d Connected Devices", nDevices).format(nDevices);
}, },
_ensureSource: function() {
if (!this._source) {
this._source = new MessageTray.Source(_("Bluetooth"), 'bluetooth-active');
this._source.policy = new MessageTray.NotificationApplicationPolicy('gnome-bluetooth-panel');
Main.messageTray.add(this._source);
}
},
_authRequest: function(applet, device_path, name, long_name) {
this._ensureSource();
this._source.notify(new AuthNotification(this._source, this._applet, device_path, name, long_name));
},
_authServiceRequest: function(applet, device_path, name, long_name, uuid) {
this._ensureSource();
this._source.notify(new AuthServiceNotification(this._source, this._applet, device_path, name, long_name, uuid));
},
_confirmRequest: function(applet, device_path, name, long_name, pin) {
this._ensureSource();
this._source.notify(new ConfirmNotification(this._source, this._applet, device_path, name, long_name, pin));
},
_pinRequest: function(applet, device_path, name, long_name, numeric) {
this._ensureSource();
this._source.notify(new PinNotification(this._source, this._applet, device_path, name, long_name, numeric));
},
_cancelRequest: function() {
this._source.destroy();
}
});
const AuthNotification = new Lang.Class({
Name: 'AuthNotification',
Extends: MessageTray.Notification,
_init: function(source, applet, device_path, name, long_name) {
this.parent(source,
_("Bluetooth"),
_("Authorization request from %s").format(name),
{ customContent: true });
this.setResident(true);
this._applet = applet;
this._devicePath = device_path;
this.addBody(_("Device %s wants to pair with this computer").format(long_name));
this.addAction('allow', _("Allow"));
this.addAction('deny', _("Deny"));
this.connect('action-invoked', Lang.bind(this, function(self, action) {
if (action == 'allow')
this._applet.agent_reply_confirm(this._devicePath, true);
else
this._applet.agent_reply_confirm(this._devicePath, false);
this.destroy();
}));
}
});
const AuthServiceNotification = new Lang.Class({
Name: 'AuthServiceNotification',
Extends: MessageTray.Notification,
_init: function(source, applet, device_path, name, long_name, uuid) {
this.parent(source,
_("Bluetooth"),
_("Authorization request from %s").format(name),
{ customContent: true });
this.setResident(true);
this._applet = applet;
this._devicePath = device_path;
this.addBody(_("Device %s wants access to the service '%s'").format(long_name, uuid));
this.addAction('always-grant', _("Always grant access"));
this.addAction('grant', _("Grant this time only"));
this.addAction('reject', _("Reject"));
this.connect('action-invoked', Lang.bind(this, function(self, action) {
switch (action) {
case 'always-grant':
this._applet.agent_reply_auth_service(this._devicePath, true, true);
break;
case 'grant':
this._applet.agent_reply_auth_service(this._devicePath, true, false);
break;
case 'reject':
default:
this._applet.agent_reply_auth_service(this._devicePath, false, false);
}
this.destroy();
}));
}
});
const ConfirmNotification = new Lang.Class({
Name: 'ConfirmNotification',
Extends: MessageTray.Notification,
_init: function(source, applet, device_path, name, long_name, pin) {
this.parent(source,
_("Bluetooth"),
/* Translators: argument is the device short name */
_("Pairing confirmation for %s").format(name),
{ customContent: true });
this.setResident(true);
this._applet = applet;
this._devicePath = device_path;
this.addBody(_("Device %s wants to pair with this computer").format(long_name));
this.addBody(_("Please confirm whether the Passkey '%06d' matches the one on the device.").format(pin));
/* Translators: this is the verb, not the noun */
this.addAction('matches', _("Matches"));
this.addAction('does-not-match', _("Does not match"));
this.connect('action-invoked', Lang.bind(this, function(self, action) {
if (action == 'matches')
this._applet.agent_reply_confirm(this._devicePath, true);
else
this._applet.agent_reply_confirm(this._devicePath, false);
this.destroy();
}));
}
});
const PinNotification = new Lang.Class({
Name: 'PinNotification',
Extends: MessageTray.Notification,
_init: function(source, applet, device_path, name, long_name, numeric) {
this.parent(source,
_("Bluetooth"),
_("Pairing request for %s").format(name),
{ customContent: true });
this.setResident(true);
this._applet = applet;
this._devicePath = device_path;
this._numeric = numeric;
this.addBody(_("Device %s wants to pair with this computer").format(long_name));
this.addBody(_("Please enter the PIN mentioned on the device."));
this._entry = new St.Entry();
this._entry.connect('key-release-event', Lang.bind(this, function(entry, event) {
let key = event.get_key_symbol();
if (key == Clutter.KEY_Return) {
if (this._canActivateOkButton())
this._ok();
return true;
} else if (key == Clutter.KEY_Escape) {
this._cancel();
return true;
}
return false;
}));
this.addActor(this._entry);
let okButton = this.addAction(_("OK"), Lang.bind(this, this._ok));
this.addAction(_("Cancel"), Lang.bind(this, this._cancel));
okButton.reactive = this._canActivateOkButton();
this._entry.clutter_text.connect('text-changed', Lang.bind(this, function() {
okButton.reactive = this._canActivateOkButton();
}));
},
_ok: function() {
if (this._numeric) {
let num = parseInt(this._entry.text, 10);
if (isNaN(num)) {
// user reply was empty, or was invalid
// cancel the operation
num = -1;
}
this._applet.agent_reply_passkey(this._devicePath, num);
} else {
this._applet.agent_reply_pincode(this._devicePath, this._entry.text);
}
this.destroy();
},
_cancel: function() {
if (this._numeric)
this._applet.agent_reply_passkey(this._devicePath, -1);
else
this._applet.agent_reply_pincode(this._devicePath, null);
this.destroy();
},
_canActivateOkButton: function() {
// PINs have a fixed length of 6
if (this._numeric)
return this._entry.clutter_text.text.length == 6;
else
return true;
}
}); });

View File

@ -48,7 +48,7 @@ const Indicator = new Lang.Class({
this._item.actor.add(icon); this._item.actor.add(icon);
this._item.actor.add(this._slider.actor, { expand: true }); this._item.actor.add(this._slider.actor, { expand: true });
this._item.actor.connect('button-press-event', Lang.bind(this, function(actor, event) { this._item.actor.connect('button-press-event', Lang.bind(this, function(actor, event) {
this._slider.startDragging(event); return this._slider.startDragging(event);
})); }));
this._item.actor.connect('key-press-event', Lang.bind(this, function(actor, event) { this._item.actor.connect('key-press-event', Lang.bind(this, function(actor, event) {
return this._slider.onKeyPressEvent(actor, event); return this._slider.onKeyPressEvent(actor, event);

58
js/ui/status/location.js Normal file
View File

@ -0,0 +1,58 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
const Gio = imports.gi.Gio;
const Lang = imports.lang;
const PanelMenu = imports.ui.panelMenu;
var GeoclueIface = '<node> \
<interface name="org.freedesktop.GeoClue2.Manager"> \
<property name="InUse" type="b" access="read"/> \
</interface> \
</node>';
const GeoclueManager = Gio.DBusProxy.makeProxyWrapper(GeoclueIface);
const Indicator = new Lang.Class({
Name: 'LocationIndicator',
Extends: PanelMenu.SystemIndicator,
_init: function() {
this.parent();
this._indicator = this._addIndicator();
this._indicator.icon_name = 'find-location-symbolic';
this._sync();
this._watchId = Gio.bus_watch_name(Gio.BusType.SYSTEM,
'org.freedesktop.GeoClue2',
0,
Lang.bind(this, this._onGeoclueAppeared),
Lang.bind(this, this._onGeoclueVanished));
},
_sync: function() {
if (this._proxy == null) {
this._indicator.visible = false;
return;
}
this._indicator.visible = this._proxy.InUse;
},
_onGeoclueAppeared: function() {
// FIXME: This should be done async
this._proxy = new GeoclueManager(Gio.DBus.system,
'org.freedesktop.GeoClue2',
'/org/freedesktop/GeoClue2/Manager');
this._proxy.connect('g-properties-changed', Lang.bind(this, this._sync));
this._sync();
},
_onGeoclueVanished: function() {
this._proxy = null;
this._sync();
}
});

View File

@ -11,7 +11,6 @@ const NMGtk = imports.gi.NMGtk;
const Signals = imports.signals; const Signals = imports.signals;
const St = imports.gi.St; const St = imports.gi.St;
const Hash = imports.misc.hash;
const Main = imports.ui.main; const Main = imports.ui.main;
const PanelMenu = imports.ui.panelMenu; const PanelMenu = imports.ui.panelMenu;
const PopupMenu = imports.ui.popupMenu; const PopupMenu = imports.ui.popupMenu;
@ -22,6 +21,7 @@ const Util = imports.misc.util;
const NMConnectionCategory = { const NMConnectionCategory = {
INVALID: 'invalid', INVALID: 'invalid',
WIRED: 'wired',
WIRELESS: 'wireless', WIRELESS: 'wireless',
WWAN: 'wwan', WWAN: 'wwan',
VPN: 'vpn' VPN: 'vpn'
@ -176,7 +176,7 @@ const NMConnectionSection = new Lang.Class({
_init: function(client) { _init: function(client) {
this._client = client; this._client = client;
this._connectionItems = new Hash.Map(); this._connectionItems = new Map();
this._connections = []; this._connections = [];
this._labelSection = new PopupMenu.PopupMenuSection(); this._labelSection = new PopupMenu.PopupMenuSection();
@ -194,7 +194,7 @@ const NMConnectionSection = new Lang.Class({
}, },
_sync: function() { _sync: function() {
let nItems = this._connectionItems.size(); let nItems = this._connectionItems.size;
this._switchSection.actor.visible = (nItems > 1); this._switchSection.actor.visible = (nItems > 1);
this._labelSection.actor.visible = (nItems == 1); this._labelSection.actor.visible = (nItems == 1);
@ -213,8 +213,7 @@ const NMConnectionSection = new Lang.Class({
_getStatus: function() { _getStatus: function() {
let values = this._connectionItems.values(); let values = this._connectionItems.values();
for (let i = 0; i < values.length; i++) { for (let item of values) {
let item = values[i];
if (item.isActive()) if (item.isActive())
return item.getName(); return item.getName();
} }
@ -298,6 +297,11 @@ const NMConnectionDevice = new Lang.Class({
this._activeConnectionChangedId = this._device.connect('notify::active-connection', Lang.bind(this, this._activeConnectionChanged)); this._activeConnectionChangedId = this._device.connect('notify::active-connection', Lang.bind(this, this._activeConnectionChanged));
}, },
_autoConnect: function() {
let connection = new NetworkManager.Connection();
this._client.add_and_activate_connection(connection, this._device, null, null);
},
destroy: function() { destroy: function() {
if (this._stateChangedId) { if (this._stateChangedId) {
GObject.Object.prototype.disconnect.call(this._device, this._stateChangedId); GObject.Object.prototype.disconnect.call(this._device, this._stateChangedId);
@ -305,7 +309,7 @@ const NMConnectionDevice = new Lang.Class({
} }
if (this._activeConnectionChangedId) { if (this._activeConnectionChangedId) {
GObject.Object.prototype.disconnect.call(this._device, this._activeConnectionChangedId); GObject.Object.prototype.disconnect.call(this._device, this._activeConnectionChangedId);
this._stateChangedId = 0; this._activeConnectionChangedId = 0;
} }
this.parent(); this.parent();
@ -365,7 +369,7 @@ const NMConnectionDevice = new Lang.Class({
}, },
_sync: function() { _sync: function() {
let nItems = this._connectionItems.size(); let nItems = this._connectionItems.size;
this._autoConnectItem.actor.visible = (nItems == 0); this._autoConnectItem.actor.visible = (nItems == 0);
this.parent(); this.parent();
}, },
@ -415,6 +419,48 @@ const NMConnectionDevice = new Lang.Class({
}, },
}); });
const NMDeviceWired = new Lang.Class({
Name: 'NMDeviceWired',
Extends: NMConnectionDevice,
category: NMConnectionCategory.WIRED,
_init: function(client, device, settings) {
this.parent(client, device, settings);
this.item.menu.addMenuItem(createSettingsAction(_("Wired Settings"), device));
},
_isConnected: function() {
if (!this._device.active_connection)
return false;
let state = this._device.active_connection.state;
return state >= NetworkManager.ActiveConnectionState.ACTIVATING;
},
_sync: function() {
this.item.actor.visible = this._isConnected();
this.parent();
},
_getMenuIcon: function() {
if (this._device.active_connection)
return this.getIndicatorIcon();
else
return 'network-wired-disconnected-symbolic';
},
getIndicatorIcon: function() {
let state = this._device.active_connection.state;
if (state == NetworkManager.ActiveConnectionState.ACTIVATING)
return 'network-wired-acquiring-symbolic';
else if (state == NetworkManager.ActiveConnectionState.ACTIVATED)
return 'network-wired-symbolic';
else
return 'network-wired-disconnected-symbolic';
}
});
const NMDeviceModem = new Lang.Class({ const NMDeviceModem = new Lang.Class({
Name: 'NMDeviceModem', Name: 'NMDeviceModem',
Extends: NMConnectionDevice, Extends: NMConnectionDevice,
@ -512,18 +558,6 @@ const NMDeviceBluetooth = new Lang.Class({
this.item.menu.addMenuItem(createSettingsAction(_("Mobile Broadband Settings"), device)); this.item.menu.addMenuItem(createSettingsAction(_("Mobile Broadband Settings"), device));
}, },
_autoConnect: function() {
// FIXME: DUN devices are configured like modems, so
// We need to spawn the mobile wizard
// but the network panel doesn't support bluetooth at the moment
// so we just create an empty connection and hope
// that this phone supports PAN
let connection = new NetworkManager.Connection();
this._client.add_and_activate_connection(connection, this._device, null, null);
return true;
},
_getMenuIcon: function() { _getMenuIcon: function() {
if (this._device.active_connection) if (this._device.active_connection)
return this.getIndicatorIcon(); return this.getIndicatorIcon();
@ -611,7 +645,7 @@ const NMWirelessDialog = new Lang.Class({
Name: 'NMWirelessDialog', Name: 'NMWirelessDialog',
Extends: ModalDialog.ModalDialog, Extends: ModalDialog.ModalDialog,
_init: function(client, device, settings) { _init: function(client, device) {
this.parent({ styleClass: 'nm-dialog' }); this.parent({ styleClass: 'nm-dialog' });
this._client = client; this._client = client;
@ -620,10 +654,7 @@ const NMWirelessDialog = new Lang.Class({
this._networks = []; this._networks = [];
this._buildLayout(); this._buildLayout();
let connections = settings.list_connections(); this._connections = device.get_available_connections();
this._connections = connections.filter(Lang.bind(this, function(connection) {
return device.connection_valid(connection);
}));
this._apAddedId = device.connect('access-point-added', Lang.bind(this, this._accessPointAdded)); this._apAddedId = device.connect('access-point-added', Lang.bind(this, this._accessPointAdded));
this._apRemovedId = device.connect('access-point-removed', Lang.bind(this, this._accessPointRemoved)); this._apRemovedId = device.connect('access-point-removed', Lang.bind(this, this._accessPointRemoved));
@ -735,16 +766,11 @@ const NMWirelessDialog = new Lang.Class({
_connect: function() { _connect: function() {
let network = this._selectedNetwork; let network = this._selectedNetwork;
let accessPoints = network.accessPoints;
if (network.connections.length > 0) { if (network.connections.length > 0) {
let connection = network.connections[0]; let connection = network.connections[0];
for (let i = 0; i < accessPoints.length; i++) { this._client.activate_connection(connection, this._device, null, null);
if (accessPoints[i].connection_valid(connection)) {
this._client.activate_connection(connection, this._device, accessPoints[i].dbus_path, null);
break;
}
}
} else { } else {
let accessPoints = network.accessPoints;
if ((accessPoints[0]._secType == NMAccessPointSecurity.WPA2_ENT) if ((accessPoints[0]._secType == NMAccessPointSecurity.WPA2_ENT)
|| (accessPoints[0]._secType == NMAccessPointSecurity.WPA_ENT)) { || (accessPoints[0]._secType == NMAccessPointSecurity.WPA_ENT)) {
// 802.1x-enabled APs require further configuration, so they're // 802.1x-enabled APs require further configuration, so they're
@ -978,10 +1004,9 @@ const NMDeviceWireless = new Lang.Class({
Name: 'NMDeviceWireless', Name: 'NMDeviceWireless',
category: NMConnectionCategory.WIRELESS, category: NMConnectionCategory.WIRELESS,
_init: function(client, device, settings) { _init: function(client, device) {
this._client = client; this._client = client;
this._device = device; this._device = device;
this._settings = settings;
this._description = ''; this._description = '';
@ -1049,7 +1074,7 @@ const NMDeviceWireless = new Lang.Class({
}, },
_showDialog: function() { _showDialog: function() {
this._dialog = new NMWirelessDialog(this._client, this._device, this._settings); this._dialog = new NMWirelessDialog(this._client, this._device);
this._dialog.connect('closed', Lang.bind(this, this._dialogClosed)); this._dialog.connect('closed', Lang.bind(this, this._dialogClosed));
this._dialog.open(); this._dialog.open();
}, },
@ -1217,7 +1242,7 @@ const NMVPNSection = new Lang.Class({
}, },
_sync: function() { _sync: function() {
let nItems = this._connectionItems.size(); let nItems = this._connectionItems.size;
this.item.actor.visible = (nItems > 0); this.item.actor.visible = (nItems > 0);
this.parent(); this.parent();
}, },
@ -1239,9 +1264,10 @@ const NMVPNSection = new Lang.Class({
}, },
setActiveConnections: function(vpnConnections) { setActiveConnections: function(vpnConnections) {
this._connectionItems.values().forEach(function(item) { let connections = this._connectionItems.values();
for (let item of connections) {
item.setActiveConnection(null); item.setActiveConnection(null);
}); }
vpnConnections.forEach(Lang.bind(this, function(a) { vpnConnections.forEach(Lang.bind(this, function(a) {
let item = this._connectionItems.get(a._connection.get_uuid()); let item = this._connectionItems.get(a._connection.get_uuid());
item.setActiveConnection(a); item.setActiveConnection(a);
@ -1254,8 +1280,7 @@ const NMVPNSection = new Lang.Class({
getIndicatorIcon: function() { getIndicatorIcon: function() {
let items = this._connectionItems.values(); let items = this._connectionItems.values();
for (let i = 0; i < items.length; i++) { for (let item of items) {
let item = items[i];
let icon = item.getIndicatorIcon(); let icon = item.getIndicatorIcon();
if (icon) if (icon)
return icon; return icon;
@ -1277,6 +1302,7 @@ const NMApplet = new Lang.Class({
// Device types // Device types
this._dtypes = { }; this._dtypes = { };
this._dtypes[NetworkManager.DeviceType.ETHERNET] = NMDeviceWired;
this._dtypes[NetworkManager.DeviceType.WIFI] = NMDeviceWireless; this._dtypes[NetworkManager.DeviceType.WIFI] = NMDeviceWireless;
this._dtypes[NetworkManager.DeviceType.MODEM] = NMDeviceModem; this._dtypes[NetworkManager.DeviceType.MODEM] = NMDeviceModem;
this._dtypes[NetworkManager.DeviceType.BT] = NMDeviceBluetooth; this._dtypes[NetworkManager.DeviceType.BT] = NMDeviceBluetooth;
@ -1284,6 +1310,7 @@ const NMApplet = new Lang.Class({
// Connection types // Connection types
this._ctypes = { }; this._ctypes = { };
this._ctypes[NetworkManager.SETTING_WIRED_SETTING_NAME] = NMConnectionCategory.WIRED;
this._ctypes[NetworkManager.SETTING_WIRELESS_SETTING_NAME] = NMConnectionCategory.WIRELESS; this._ctypes[NetworkManager.SETTING_WIRELESS_SETTING_NAME] = NMConnectionCategory.WIRELESS;
this._ctypes[NetworkManager.SETTING_BLUETOOTH_SETTING_NAME] = NMConnectionCategory.WWAN; this._ctypes[NetworkManager.SETTING_BLUETOOTH_SETTING_NAME] = NMConnectionCategory.WWAN;
this._ctypes[NetworkManager.SETTING_CDMA_SETTING_NAME] = NMConnectionCategory.WWAN; this._ctypes[NetworkManager.SETTING_CDMA_SETTING_NAME] = NMConnectionCategory.WWAN;
@ -1306,6 +1333,15 @@ const NMApplet = new Lang.Class({
this._tryLateInit(); this._tryLateInit();
}, },
_createDeviceCategory: function() {
let category = {
section: new PopupMenu.PopupMenuSection(),
devices: [ ],
};
this.menu.addMenuItem(category.section);
return category;
},
_tryLateInit: function() { _tryLateInit: function() {
if (!this._client || !this._settings) if (!this._client || !this._settings)
return; return;
@ -1321,17 +1357,9 @@ const NMApplet = new Lang.Class({
this._nmDevices = []; this._nmDevices = [];
this._devices = { }; this._devices = { };
this._devices.wireless = { this._devices.wired = this._createDeviceCategory();
section: new PopupMenu.PopupMenuSection(), this._devices.wireless = this._createDeviceCategory();
devices: [ ], this._devices.wwan = this._createDeviceCategory();
};
this.menu.addMenuItem(this._devices.wireless.section);
this._devices.wwan = {
section: new PopupMenu.PopupMenuSection(),
devices: [ ],
};
this.menu.addMenuItem(this._devices.wwan.section);
this._vpnSection = new NMVPNSection(this._client); this._vpnSection = new NMVPNSection(this._client);
this._vpnSection.connect('activation-failed', Lang.bind(this, this._onActivationFailed)); this._vpnSection.connect('activation-failed', Lang.bind(this, this._onActivationFailed));

View File

@ -81,7 +81,7 @@ const AltSwitcher = new Lang.Class({
this._sync(); this._sync();
} }
return false; return Clutter.EVENT_PROPAGATE;
}, },
}); });

View File

@ -42,7 +42,7 @@ const StreamSlider = new Lang.Class({
this.item.actor.add(this._icon); this.item.actor.add(this._icon);
this.item.actor.add(this._slider.actor, { expand: true }); this.item.actor.add(this._slider.actor, { expand: true });
this.item.actor.connect('button-press-event', Lang.bind(this, function(actor, event) { this.item.actor.connect('button-press-event', Lang.bind(this, function(actor, event) {
this._slider.startDragging(event); return this._slider.startDragging(event);
})); }));
this.item.actor.connect('key-press-event', Lang.bind(this, function(actor, event) { this.item.actor.connect('key-press-event', Lang.bind(this, function(actor, event) {
return this._slider.onKeyPressEvent(actor, event); return this._slider.onKeyPressEvent(actor, event);
@ -94,7 +94,7 @@ const StreamSlider = new Lang.Class({
}, },
scroll: function(event) { scroll: function(event) {
this._slider.scroll(event); return this._slider.scroll(event);
}, },
setValue: function(value) { setValue: function(value) {
@ -276,7 +276,7 @@ const VolumeMenu = new Lang.Class({
}, },
scroll: function(event) { scroll: function(event) {
this._output.scroll(event); return this._output.scroll(event);
}, },
_onControlStateChanged: function() { _onControlStateChanged: function() {
@ -329,6 +329,6 @@ const Indicator = new Lang.Class({
}, },
_onScrollEvent: function(actor, event) { _onScrollEvent: function(actor, event) {
this._volumeMenu.scroll(event); return this._volumeMenu.scroll(event);
} }
}); });

View File

@ -1,6 +1,7 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
const Clutter = imports.gi.Clutter; const Clutter = imports.gi.Clutter;
const GLib = imports.gi.GLib;
const Gtk = imports.gi.Gtk; const Gtk = imports.gi.Gtk;
const Lang = imports.lang; const Lang = imports.lang;
const Mainloop = imports.mainloop; const Mainloop = imports.mainloop;
@ -53,7 +54,7 @@ const SwitcherPopup = new Lang.Class({
this.actor.connect('allocate', Lang.bind(this, this._allocate)); this.actor.connect('allocate', Lang.bind(this, this._allocate));
this.actor.connect('destroy', Lang.bind(this, this._onDestroy)); this.actor.connect('destroy', Lang.bind(this, this._onDestroy));
Main.uiGroup.add_actor(this.actor); Main.layoutManager.switcherPopupGroup.add_child(this.actor);
this._haveModal = false; this._haveModal = false;
this._modifierMask = 0; this._modifierMask = 0;
@ -163,6 +164,7 @@ const SwitcherPopup = new Lang.Class({
Main.osdWindow.cancel(); Main.osdWindow.cancel();
this.actor.opacity = 255; this.actor.opacity = 255;
this._initialDelayTimeoutId = 0; this._initialDelayTimeoutId = 0;
return GLib.SOURCE_REMOVE;
})); }));
return true; return true;
}, },
@ -192,7 +194,7 @@ const SwitcherPopup = new Lang.Class({
else else
this._keyPressHandler(keysym, backwards, action); this._keyPressHandler(keysym, backwards, action);
return true; return Clutter.EVENT_STOP;
}, },
_keyReleaseEvent: function(actor, event) { _keyReleaseEvent: function(actor, event) {
@ -202,11 +204,12 @@ const SwitcherPopup = new Lang.Class({
if (state == 0) if (state == 0)
this._finish(event.get_time()); this._finish(event.get_time());
return true; return Clutter.EVENT_STOP;
}, },
_clickedOutside: function(actor, event) { _clickedOutside: function(actor, event) {
this.destroy(); this.destroy();
return Clutter.EVENT_PROPAGATE;
}, },
_scrollHandler: function(direction) { _scrollHandler: function(direction) {
@ -218,6 +221,7 @@ const SwitcherPopup = new Lang.Class({
_scrollEvent: function(actor, event) { _scrollEvent: function(actor, event) {
this._scrollHandler(event.get_scroll_direction()); this._scrollHandler(event.get_scroll_direction());
return Clutter.EVENT_PROPAGATE;
}, },
_itemActivatedHandler: function(n) { _itemActivatedHandler: function(n) {
@ -251,6 +255,7 @@ const SwitcherPopup = new Lang.Class({
_mouseTimedOut: function() { _mouseTimedOut: function() {
this._motionTimeoutId = 0; this._motionTimeoutId = 0;
this.mouseActive = true; this.mouseActive = true;
return GLib.SOURCE_REMOVE;
}, },
_popModal: function() { _popModal: function() {
@ -400,6 +405,7 @@ const SwitcherList = new Lang.Class({
_onItemEnter: function (index) { _onItemEnter: function (index) {
this._itemEntered(index); this._itemEntered(index);
return Clutter.EVENT_PROPAGATE;
}, },
highlight: function(index, justOutline) { highlight: function(index, justOutline) {
@ -446,10 +452,9 @@ const SwitcherList = new Lang.Class({
time: POPUP_SCROLL_TIME, time: POPUP_SCROLL_TIME,
transition: 'easeOutQuad', transition: 'easeOutQuad',
onComplete: Lang.bind(this, function () { onComplete: Lang.bind(this, function () {
if (this._highlighted == 0) { if (this._highlighted == 0)
this._scrollableLeft = false; this._scrollableLeft = false;
this.actor.queue_relayout(); this.actor.queue_relayout();
}
}) })
}); });
}, },
@ -471,10 +476,9 @@ const SwitcherList = new Lang.Class({
time: POPUP_SCROLL_TIME, time: POPUP_SCROLL_TIME,
transition: 'easeOutQuad', transition: 'easeOutQuad',
onComplete: Lang.bind(this, function () { onComplete: Lang.bind(this, function () {
if (this._highlighted == this._items.length - 1) { if (this._highlighted == this._items.length - 1)
this._scrollableRight = false; this._scrollableRight = false;
this.actor.queue_relayout(); this.actor.queue_relayout();
}
}) })
}); });
}, },
@ -509,7 +513,7 @@ const SwitcherList = new Lang.Class({
_getPreferredWidth: function (actor, forHeight, alloc) { _getPreferredWidth: function (actor, forHeight, alloc) {
let [maxChildMin, maxChildNat] = this._maxChildWidth(forHeight); let [maxChildMin, maxChildNat] = this._maxChildWidth(forHeight);
let totalSpacing = this._list.spacing * (this._items.length - 1); let totalSpacing = Math.max(this._list.spacing * (this._items.length - 1), 0);
alloc.min_size = this._items.length * maxChildMin + totalSpacing; alloc.min_size = this._items.length * maxChildMin + totalSpacing;
alloc.natural_size = alloc.min_size; alloc.natural_size = alloc.min_size;
this._minSize = alloc.min_size; this._minSize = alloc.min_size;
@ -539,7 +543,7 @@ const SwitcherList = new Lang.Class({
let childHeight = box.y2 - box.y1; let childHeight = box.y2 - box.y1;
let [maxChildMin, maxChildNat] = this._maxChildWidth(childHeight); let [maxChildMin, maxChildNat] = this._maxChildWidth(childHeight);
let totalSpacing = this._list.spacing * (this._items.length - 1); let totalSpacing = Math.max(this._list.spacing * (this._items.length - 1), 0);
let childWidth = Math.floor(Math.max(0, box.x2 - box.x1 - totalSpacing) / this._items.length); let childWidth = Math.floor(Math.max(0, box.x2 - box.x1 - totalSpacing) / this._items.length);

View File

@ -71,7 +71,7 @@ const UnlockDialog = new Lang.Class({
child: otherUserLabel, child: otherUserLabel,
reactive: true, reactive: true,
x_align: St.Align.START, x_align: St.Align.START,
x_fill: true }); x_fill: false });
this._otherUserButton.connect('clicked', Lang.bind(this, this._otherUserClicked)); this._otherUserButton.connect('clicked', Lang.bind(this, this._otherUserClicked));
this._promptBox.add_child(this._otherUserButton); this._promptBox.add_child(this._otherUserButton);
} else { } else {

View File

@ -79,9 +79,16 @@ const UserWidgetLabel = new Lang.Class({
this._userLoadedId = this._user.connect('notify::is-loaded', Lang.bind(this, this._updateUser)); 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._userChangedId = this._user.connect('changed', Lang.bind(this, this._updateUser));
this._updateUser(); this._updateUser();
// We can't override the destroy vfunc because that might be called during
// object finalization, and we can't call any JS inside a GC finalize callback,
// so we use a signal, that will be disconnected by GObject the first time
// the actor is destroyed (which is guaranteed to be as part of a normal
// destroy() call from JS, possibly from some ancestor)
this.connect('destroy', Lang.bind(this, this._onDestroy));
}, },
vfunc_destroy: function() { _onDestroy: function() {
if (this._userLoadedId != 0) { if (this._userLoadedId != 0) {
this._user.disconnect(this._userLoadedId); this._user.disconnect(this._userLoadedId);
this._userLoadedId = 0; this._userLoadedId = 0;

View File

@ -2,6 +2,7 @@
const Clutter = imports.gi.Clutter; const Clutter = imports.gi.Clutter;
const Gio = imports.gi.Gio; const Gio = imports.gi.Gio;
const GLib = imports.gi.GLib;
const Gtk = imports.gi.Gtk; const Gtk = imports.gi.Gtk;
const Mainloop = imports.mainloop; const Mainloop = imports.mainloop;
const Meta = imports.gi.Meta; const Meta = imports.gi.Meta;
@ -117,13 +118,11 @@ const ViewSelector = new Lang.Class({
this._stageKeyPressId = 0; this._stageKeyPressId = 0;
Main.overview.connect('showing', Lang.bind(this, Main.overview.connect('showing', Lang.bind(this,
function () { function () {
this._resetShowAppsButton();
this._stageKeyPressId = global.stage.connect('key-press-event', this._stageKeyPressId = global.stage.connect('key-press-event',
Lang.bind(this, this._onStageKeyPress)); Lang.bind(this, this._onStageKeyPress));
})); }));
Main.overview.connect('hiding', Lang.bind(this, Main.overview.connect('hiding', Lang.bind(this,
function () { function () {
this._resetShowAppsButton();
if (this._stageKeyPressId != 0) { if (this._stageKeyPressId != 0) {
global.stage.disconnect(this._stageKeyPressId); global.stage.disconnect(this._stageKeyPressId);
this._stageKeyPressId = 0; this._stageKeyPressId = 0;
@ -157,24 +156,28 @@ const ViewSelector = new Lang.Class({
}, },
show: function() { show: function() {
this._activePage = this._workspacesPage;
this.reset(); this.reset();
this._appsPage.hide();
this._searchPage.hide(); this._showAppsBlocked = true;
this._showAppsButton.checked = false;
this._showAppsBlocked = false;
this._workspacesPage.opacity = 255;
this._workspacesDisplay.show(); this._workspacesDisplay.show();
this._activePage = null;
this._syncActivePage();
if (!this._workspacesDisplay.activeWorkspaceHasMaximizedWindows()) if (!this._workspacesDisplay.activeWorkspaceHasMaximizedWindows())
Main.overview.fadeOutDesktop(); Main.overview.fadeOutDesktop();
this._showPage(this._workspacesPage, true);
}, },
zoomFromOverview: function() { leaveOverview: function() {
this._workspacesDisplay.zoomFromOverview();
if (!this._workspacesDisplay.activeWorkspaceHasMaximizedWindows()) if (!this._workspacesDisplay.activeWorkspaceHasMaximizedWindows())
Main.overview.fadeInDesktop(); Main.overview.fadeInDesktop();
// If we're not on the windows page, don't zoom back the primary monitor.
let zoomPrimary = (this._activePage == this._workspacesPage);
this._workspacesDisplay.leaveOverview(zoomPrimary);
}, },
setWorkspacesFullGeometry: function(geom) { setWorkspacesFullGeometry: function(geom) {
@ -183,12 +186,16 @@ const ViewSelector = new Lang.Class({
hide: function() { hide: function() {
this._workspacesDisplay.hide(); this._workspacesDisplay.hide();
if (this._activePage)
this._activePage.hide();
this._activePage = null;
}, },
_addPage: function(actor, name, a11yIcon, params) { _addPage: function(actor, name, a11yIcon, params) {
params = Params.parse(params, { a11yFocus: null }); params = Params.parse(params, { a11yFocus: null });
let page = new St.Bin({ child: actor, let page = new St.Bin({ child: actor,
visible: false,
x_align: St.Align.START, x_align: St.Align.START,
y_align: St.Align.START, y_align: St.Align.START,
x_fill: true, x_fill: true,
@ -203,6 +210,7 @@ const ViewSelector = new Lang.Class({
this._a11yFocusPage(page); this._a11yFocusPage(page);
}) })
});; });;
page.hide();
this.actor.add_actor(page); this.actor.add_actor(page);
return page; return page;
}, },
@ -212,16 +220,16 @@ const ViewSelector = new Lang.Class({
oldPage.hide(); oldPage.hide();
this.emit('page-empty'); this.emit('page-empty');
this._activePage.navigate_focus(null, Gtk.DirectionType.TAB_FORWARD, false);
this._activePage.show(); this._activePage.show();
Tweener.addTween(this._activePage, Tweener.addTween(this._activePage,
{ opacity: 255, { opacity: 255,
time: OverviewControls.SIDE_CONTROLS_ANIMATION_TIME, time: OverviewControls.SIDE_CONTROLS_ANIMATION_TIME,
transition: 'easeOutQuad' transition: 'easeOutQuad'
}); });
}, },
_showPage: function(page, noFade) { _setActivePage: function(page) {
if (page == this._activePage) if (page == this._activePage)
return; return;
@ -229,7 +237,7 @@ const ViewSelector = new Lang.Class({
this._activePage = page; this._activePage = page;
this.emit('page-changed'); this.emit('page-changed');
if (oldPage && !noFade) if (oldPage)
Tweener.addTween(oldPage, Tweener.addTween(oldPage,
{ opacity: 0, { opacity: 0,
time: OverviewControls.SIDE_CONTROLS_ANIMATION_TIME, time: OverviewControls.SIDE_CONTROLS_ANIMATION_TIME,
@ -248,27 +256,32 @@ const ViewSelector = new Lang.Class({
page.navigate_focus(null, Gtk.DirectionType.TAB_FORWARD, false); page.navigate_focus(null, Gtk.DirectionType.TAB_FORWARD, false);
}, },
_onShowAppsButtonToggled: function() { _getActivePage: function() {
if (this._showAppsBlocked) if (this._searchActive)
return; return this._searchPage;
else if (this._showAppsButton.checked)
this._showPage(this._showAppsButton.checked ? return this._appsPage;
this._appsPage : this._workspacesPage); else
return this._workspacesPage;
}, },
_resetShowAppsButton: function() { _syncActivePage: function() {
this._showAppsBlocked = true; let activePage = this._getActivePage();
this._showAppsButton.checked = false; if (activePage == this._activePage)
this._showAppsBlocked = false; return;
this._setActivePage(activePage);
},
this._showPage(this._workspacesPage, true); _onShowAppsButtonToggled: function() {
if (!this._showAppsBlocked)
this._syncActivePage();
}, },
_onStageKeyPress: function(actor, event) { _onStageKeyPress: function(actor, event) {
// Ignore events while anything but the overview has // Ignore events while anything but the overview has
// pushed a modal (system modals, looking glass, ...) // pushed a modal (system modals, looking glass, ...)
if (Main.modalCount > 1) if (Main.modalCount > 1)
return false; return Clutter.EVENT_PROPAGATE;
let modifiers = event.get_state(); let modifiers = event.get_state();
let symbol = event.get_key_symbol(); let symbol = event.get_key_symbol();
@ -280,33 +293,11 @@ const ViewSelector = new Lang.Class({
this._showAppsButton.checked = false; this._showAppsButton.checked = false;
else else
Main.overview.hide(); Main.overview.hide();
return true; return Clutter.EVENT_STOP;
} else if (this._shouldTriggerSearch(symbol)) { } else if (this._shouldTriggerSearch(symbol)) {
this.startSearch(event); this.startSearch(event);
} else if (!this._searchActive) {
if (symbol == Clutter.Tab || symbol == Clutter.Down) {
this._activePage.navigate_focus(null, Gtk.DirectionType.TAB_FORWARD, false);
return true;
} else if (symbol == Clutter.ISO_Left_Tab) {
this._activePage.navigate_focus(null, Gtk.DirectionType.TAB_BACKWARD, false);
return true;
}
} }
return false; return Clutter.EVENT_PROPAGATE;
},
_searchCancelled: function() {
this._showPage(this._showAppsButton.checked ? this._appsPage
: this._workspacesPage);
// Leave the entry focused when it doesn't have any text;
// when replacing a selected search term, Clutter emits
// two 'text-changed' signals, one for deleting the previous
// text and one for the new one - the second one is handled
// incorrectly when we remove focus
// (https://bugzilla.gnome.org/show_bug.cgi?id=636341) */
if (this._text.text != '')
this.reset();
}, },
reset: function () { reset: function () {
@ -399,8 +390,18 @@ const ViewSelector = new Lang.Class({
} }
this._entry.set_secondary_icon(null); this._entry.set_secondary_icon(null);
this._searchCancelled();
// Leave the entry focused when it doesn't have any text;
// when replacing a selected search term, Clutter emits
// two 'text-changed' signals, one for deleting the previous
// text and one for the new one - the second one is handled
// incorrectly when we remove focus
// (https://bugzilla.gnome.org/show_bug.cgi?id=636341) */
if (this._text.text != '')
this.reset();
} }
this._syncActivePage();
}, },
_onKeyPress: function(entry, event) { _onKeyPress: function(entry, event) {
@ -408,7 +409,7 @@ const ViewSelector = new Lang.Class({
if (symbol == Clutter.Escape) { if (symbol == Clutter.Escape) {
if (this._isActivated()) { if (this._isActivated()) {
this.reset(); this.reset();
return true; return Clutter.EVENT_STOP;
} }
} else if (this._searchActive) { } else if (this._searchActive) {
let arrowNext, nextDirection; let arrowNext, nextDirection;
@ -422,18 +423,18 @@ const ViewSelector = new Lang.Class({
if (symbol == Clutter.Tab) { if (symbol == Clutter.Tab) {
this._searchResults.navigateFocus(Gtk.DirectionType.TAB_FORWARD); this._searchResults.navigateFocus(Gtk.DirectionType.TAB_FORWARD);
return true; return Clutter.EVENT_STOP;
} else if (symbol == Clutter.ISO_Left_Tab) { } else if (symbol == Clutter.ISO_Left_Tab) {
this._focusTrap.can_focus = false; this._focusTrap.can_focus = false;
this._searchResults.navigateFocus(Gtk.DirectionType.TAB_BACKWARD); this._searchResults.navigateFocus(Gtk.DirectionType.TAB_BACKWARD);
this._focusTrap.can_focus = true; this._focusTrap.can_focus = true;
return true; return Clutter.EVENT_STOP;
} else if (symbol == Clutter.Down) { } else if (symbol == Clutter.Down) {
this._searchResults.navigateFocus(Gtk.DirectionType.DOWN); this._searchResults.navigateFocus(Gtk.DirectionType.DOWN);
return true; return Clutter.EVENT_STOP;
} else if (symbol == arrowNext && this._text.position == -1) { } else if (symbol == arrowNext && this._text.position == -1) {
this._searchResults.navigateFocus(nextDirection); this._searchResults.navigateFocus(nextDirection);
return true; return Clutter.EVENT_STOP;
} else if (symbol == Clutter.Return || symbol == Clutter.KP_Enter) { } else if (symbol == Clutter.Return || symbol == Clutter.KP_Enter) {
// We can't connect to 'activate' here because search providers // We can't connect to 'activate' here because search providers
// might want to do something with the modifiers in activateDefault. // might want to do something with the modifiers in activateDefault.
@ -442,10 +443,10 @@ const ViewSelector = new Lang.Class({
this._doSearch(); this._doSearch();
} }
this._searchResults.activateDefault(); this._searchResults.activateDefault();
return true; return Clutter.EVENT_STOP;
} }
} }
return false; return Clutter.EVENT_PROPAGATE;
}, },
_onCapturedEvent: function(actor, event) { _onCapturedEvent: function(actor, event) {
@ -460,16 +461,16 @@ const ViewSelector = new Lang.Class({
} }
} }
return false; return Clutter.EVENT_PROPAGATE;
}, },
_doSearch: function () { _doSearch: function () {
this._searchTimeoutId = 0; this._searchTimeoutId = 0;
let terms = getTermsForSearchString(this._entry.get_text()); let terms = getTermsForSearchString(this._entry.get_text());
this._searchResults.setTerms(terms); this._searchResults.setTerms(terms);
this._showPage(this._searchPage);
return GLib.SOURCE_REMOVE;
}, },
getActivePage: function() { getActivePage: function() {
@ -481,13 +482,6 @@ const ViewSelector = new Lang.Class({
return ViewPage.SEARCH; return ViewPage.SEARCH;
}, },
setActivePage: function(page) {
if (page == ViewPage.WINDOWS)
this._showPage(this._workspacesPage);
else
this._showPage(this._appsPage);
},
fadeIn: function() { fadeIn: function() {
let actor = this._activePage; let actor = this._activePage;
Tweener.addTween(actor, { opacity: 255, Tweener.addTween(actor, { opacity: 255,

View File

@ -16,7 +16,7 @@ const WindowAttentionHandler = new Lang.Class({
_getTitleAndBanner: function(app, window) { _getTitleAndBanner: function(app, window) {
let title = app.get_name(); let title = app.get_name();
let banner = _("'%s' is ready").format(window.get_title()); let banner = _("%s is ready").format(window.get_title());
return [title, banner] return [title, banner]
}, },

View File

@ -106,11 +106,11 @@ const DisplayChangeDialog = new Lang.Class({
/* mutter already takes care of failing at timeout */ /* mutter already takes care of failing at timeout */
this._timeoutId = 0; this._timeoutId = 0;
this.close(); this.close();
return false; return GLib.SOURCE_REMOVE;
} }
this._descriptionLabel.text = this._formatCountDown(); this._descriptionLabel.text = this._formatCountDown();
return true; return GLib.SOURCE_CONTINUE;
}, },
_onFailure: function() { _onFailure: function() {
@ -232,12 +232,13 @@ const WorkspaceTracker = new Lang.Class({
let windows = global.get_window_actors(); let windows = global.get_window_actors();
for (i = 0; i < windows.length; i++) { for (i = 0; i < windows.length; i++) {
let win = windows[i]; let actor = windows[i];
let win = actor.get_meta_window();
if (win.get_meta_window().is_on_all_workspaces()) if (win.is_on_all_workspaces())
continue; continue;
let workspaceIndex = win.get_workspace(); let workspaceIndex = win.get_workspace().index();
emptyWorkspaces[workspaceIndex] = false; emptyWorkspaces[workspaceIndex] = false;
} }
@ -278,7 +279,7 @@ const WorkspaceTracker = new Lang.Class({
workspace._keepAliveId = Mainloop.timeout_add(duration, Lang.bind(this, function() { workspace._keepAliveId = Mainloop.timeout_add(duration, Lang.bind(this, function() {
workspace._keepAliveId = 0; workspace._keepAliveId = 0;
this._queueCheckWorkspaces(); this._queueCheckWorkspaces();
return false; return GLib.SOURCE_REMOVE;
})); }));
}, },
@ -290,7 +291,7 @@ const WorkspaceTracker = new Lang.Class({
workspace._lastRemovedWindow = null; workspace._lastRemovedWindow = null;
this._queueCheckWorkspaces(); this._queueCheckWorkspaces();
} }
return false; return GLib.SOURCE_REMOVE;
})); }));
}, },
@ -555,6 +556,12 @@ const WindowManager = new Lang.Class({
Shell.KeyBindingMode.LOGIN_SCREEN, Shell.KeyBindingMode.LOGIN_SCREEN,
Lang.bind(this, this._startA11ySwitcher)); Lang.bind(this, this._startA11ySwitcher));
this.addKeybinding('pause-resume-tweens',
new Gio.Settings({ schema: SHELL_KEYBINDINGS_SCHEMA }),
Meta.KeyBindingFlags.NONE,
Shell.KeyBindingMode.ALL,
Lang.bind(this, this._toggleTweens));
this.addKeybinding('open-application-menu', this.addKeybinding('open-application-menu',
new Gio.Settings({ schema: SHELL_KEYBINDINGS_SCHEMA }), new Gio.Settings({ schema: SHELL_KEYBINDINGS_SCHEMA }),
Meta.KeyBindingFlags.NONE, Meta.KeyBindingFlags.NONE,
@ -742,15 +749,13 @@ const WindowManager = new Lang.Class({
if (shouldDim && !window._dimmed) { if (shouldDim && !window._dimmed) {
window._dimmed = true; window._dimmed = true;
this._dimmedWindows.push(window); this._dimmedWindows.push(window);
if (!Main.overview.visible) this._dimWindow(window);
this._dimWindow(window);
} else if (!shouldDim && window._dimmed) { } else if (!shouldDim && window._dimmed) {
window._dimmed = false; window._dimmed = false;
this._dimmedWindows = this._dimmedWindows.filter(function(win) { this._dimmedWindows = this._dimmedWindows.filter(function(win) {
return win != window; return win != window;
}); });
if (!Main.overview.visible) this._undimWindow(window);
this._undimWindow(window);
} }
}, },
@ -975,25 +980,29 @@ const WindowManager = new Lang.Class({
wgroup.add_actor(switchData.movingWindowBin); wgroup.add_actor(switchData.movingWindowBin);
for (let i = 0; i < windows.length; i++) { for (let i = 0; i < windows.length; i++) {
let window = windows[i]; let actor = windows[i];
let window = actor.get_meta_window();
if (!window.meta_window.showing_on_its_workspace()) if (!window.showing_on_its_workspace())
continue; continue;
if (this._movingWindow && window.meta_window == this._movingWindow) { if (window.is_on_all_workspaces())
switchData.movingWindow = { window: window, continue;
parent: window.get_parent() };
let record = { window: actor,
parent: actor.get_parent() };
if (this._movingWindow && window == this._movingWindow) {
switchData.movingWindow = record;
switchData.windows.push(switchData.movingWindow); switchData.windows.push(switchData.movingWindow);
window.reparent(switchData.movingWindowBin); actor.reparent(switchData.movingWindowBin);
} else if (window.get_workspace() == from) { } else if (window.get_workspace().index() == from) {
switchData.windows.push({ window: window, switchData.windows.push(record);
parent: window.get_parent() }); actor.reparent(switchData.outGroup);
window.reparent(switchData.outGroup); } else if (window.get_workspace().index() == to) {
} else if (window.get_workspace() == to) { switchData.windows.push(record);
switchData.windows.push({ window: window, actor.reparent(switchData.inGroup);
parent: window.get_parent() }); actor.show();
window.reparent(switchData.inGroup);
window.show();
} }
} }
@ -1083,6 +1092,15 @@ const WindowManager = new Lang.Class({
Main.panel.toggleAppMenu(); Main.panel.toggleAppMenu();
}, },
_toggleTweens: function() {
this._tweensPaused = !this._tweensPaused;
const OrigTweener = imports.tweener.tweener;
if (this._tweensPaused)
OrigTweener.pauseAllTweens();
else
OrigTweener.resumeAllTweens();
},
_showWorkspaceSwitcher : function(display, screen, window, binding) { _showWorkspaceSwitcher : function(display, screen, window, binding) {
if (!Main.sessionMode.hasWorkspaces) if (!Main.sessionMode.hasWorkspaces)
return; return;

View File

@ -1,6 +1,7 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
const Clutter = imports.gi.Clutter; const Clutter = imports.gi.Clutter;
const GLib = imports.gi.GLib;
const Lang = imports.lang; const Lang = imports.lang;
const Mainloop = imports.mainloop; const Mainloop = imports.mainloop;
const Meta = imports.gi.Meta; const Meta = imports.gi.Meta;
@ -13,6 +14,7 @@ const DND = imports.ui.dnd;
const Main = imports.ui.main; const Main = imports.ui.main;
const Overview = imports.ui.overview; const Overview = imports.ui.overview;
const Tweener = imports.ui.tweener; const Tweener = imports.ui.tweener;
const WindowManager = imports.ui.windowManager;
const WINDOW_DND_SIZE = 256; const WINDOW_DND_SIZE = 256;
@ -34,6 +36,68 @@ function _interpolate(start, end, step) {
return start + (end - start) * step; return start + (end - start) * step;
} }
const WindowCloneLayout = new Lang.Class({
Name: 'WindowCloneLayout',
Extends: Clutter.LayoutManager,
_init: function(boundingBox) {
this.parent();
this._boundingBox = boundingBox;
},
get boundingBox() {
return this._boundingBox;
},
set boundingBox(b) {
this._boundingBox = b;
this.layout_changed();
},
_makeBoxForWindow: function(window) {
// We need to adjust the position of the actor because of the
// consequences of invisible borders -- in reality, the texture
// has an extra set of "padding" around it that we need to trim
// down.
// The outer rect (from which we compute the bounding box)
// paradoxically is the smaller rectangle, containing the positions
// of the visible frame. The input rect contains everything,
// including the invisible border padding.
let inputRect = window.get_input_rect();
let box = new Clutter.ActorBox();
box.set_origin(inputRect.x - this._boundingBox.x,
inputRect.y - this._boundingBox.y);
box.set_size(inputRect.width, inputRect.height);
return box;
},
vfunc_get_preferred_height: function(container, forWidth) {
return [this._boundingBox.height, this._boundingBox.height];
},
vfunc_get_preferred_width: function(container, forHeight) {
return [this._boundingBox.width, this._boundingBox.width];
},
vfunc_allocate: function(container, box, flags) {
let clone = container.get_children().forEach(function (child) {
let realWindow;
if (child == container._delegate._windowClone)
realWindow = container._delegate.realWindow;
else
realWindow = child.source;
child.allocate(this._makeBoxForWindow(realWindow.meta_window),
flags);
}, this);
},
});
const WindowClone = new Lang.Class({ const WindowClone = new Lang.Class({
Name: 'WindowClone', Name: 'WindowClone',
@ -43,10 +107,7 @@ const WindowClone = new Lang.Class({
this.metaWindow._delegate = this; this.metaWindow._delegate = this;
this._workspace = workspace; this._workspace = workspace;
let [borderX, borderY] = this._getInvisibleBorderPadding(); this._windowClone = new Clutter.Clone({ source: realWindow.get_texture() });
this._windowClone = new Clutter.Clone({ source: realWindow.get_texture(),
x: -borderX,
y: -borderY });
// We expect this.actor to be used for all interaction rather than // We expect this.actor to be used for all interaction rather than
// this._windowClone; as the former is reactive and the latter // this._windowClone; as the former is reactive and the latter
// is not, this just works for most cases. However, for DND all // is not, this just works for most cases. However, for DND all
@ -54,20 +115,13 @@ const WindowClone = new Lang.Class({
// To avoid this, we hide it from pick. // To avoid this, we hide it from pick.
Shell.util_set_hidden_from_pick(this._windowClone, true); Shell.util_set_hidden_from_pick(this._windowClone, true);
this.origX = realWindow.x + borderX;
this.origY = realWindow.y + borderY;
let outerRect = realWindow.meta_window.get_outer_rect();
// The MetaShapedTexture that we clone has a size that includes // The MetaShapedTexture that we clone has a size that includes
// the invisible border; this is inconvenient; rather than trying // the invisible border; this is inconvenient; rather than trying
// to compensate all over the place we insert a ClutterActor into // to compensate all over the place we insert a ClutterActor into
// the hierarchy that is sized to only the visible portion. // the hierarchy that is sized to only the visible portion.
this.actor = new Clutter.Actor({ reactive: true, this.actor = new St.Widget({ reactive: true,
x: this.origX, can_focus: true,
y: this.origY, layout_manager: new WindowCloneLayout() });
width: outerRect.width,
height: outerRect.height });
this.actor.add_child(this._windowClone); this.actor.add_child(this._windowClone);
@ -77,18 +131,27 @@ const WindowClone = new Lang.Class({
this._dragSlot = [0, 0, 0, 0]; this._dragSlot = [0, 0, 0, 0];
this._stackAbove = null; this._stackAbove = null;
this._sizeChangedId = this.realWindow.connect('size-changed', this._windowClone._updateId = this.realWindow.connect('size-changed',
Lang.bind(this, this._onRealWindowSizeChanged)); Lang.bind(this, this._onRealWindowSizeChanged));
this._realWindowDestroyId = this.realWindow.connect('destroy', this._windowClone._destroyId = this.realWindow.connect('destroy', Lang.bind(this, function() {
Lang.bind(this, this._disconnectRealWindowSignals)); // First destroy the clone and then destroy everything
// This will ensure that we never see it in the _disconnectSignals loop
this._windowClone.destroy();
this.destroy();
}));
this._updateAttachedDialogs();
this._computeBoundingBox();
this.actor.x = this._boundingBox.x;
this.actor.y = this._boundingBox.y;
let clickAction = new Clutter.ClickAction(); let clickAction = new Clutter.ClickAction();
clickAction.connect('clicked', Lang.bind(this, this._onClicked)); clickAction.connect('clicked', Lang.bind(this, this._onClicked));
clickAction.connect('long-press', Lang.bind(this, this._onLongPress)); clickAction.connect('long-press', Lang.bind(this, this._onLongPress));
this.actor.add_action(clickAction); this.actor.add_action(clickAction);
this.actor.connect('destroy', Lang.bind(this, this._onDestroy)); 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, this._draggable = DND.makeDraggable(this.actor,
{ restoreOnSuccess: true, { restoreOnSuccess: true,
@ -114,6 +177,83 @@ const WindowClone = new Lang.Class({
return this._slot; return this._slot;
}, },
deleteAll: function() {
// Delete all windows, starting from the bottom-most (most-modal) one
let windows = this.actor.get_children();
for (let i = windows.length - 1; i >= 1; i--) {
let realWindow = windows[i].source;
let metaWindow = realWindow.meta_window;
metaWindow.delete(global.get_current_time());
}
this.metaWindow.delete(global.get_current_time());
},
addAttachedDialog: function(win) {
this._doAddAttachedDialog(win, win.get_compositor_private());
this._computeBoundingBox();
this.emit('size-changed');
},
_doAddAttachedDialog: function(metaWin, realWin) {
let clone = new Clutter.Clone({ source: realWin });
clone._updateId = realWin.connect('size-changed', Lang.bind(this, function() {
this._computeBoundingBox();
this.emit('size-changed');
}));
clone._destroyId = realWin.connect('destroy', Lang.bind(this, function() {
clone.destroy();
this._computeBoundingBox();
this.emit('size-changed');
}));
this.actor.add_child(clone);
},
_updateAttachedDialogs: function() {
let iter = Lang.bind(this, function(win) {
let actor = win.get_compositor_private();
if (!actor)
return false;
if (!win.is_attached_dialog())
return false;
this._doAddAttachedDialog(win, actor);
win.foreach_transient(iter);
return true;
});
this.metaWindow.foreach_transient(iter);
},
get boundingBox() {
return this._boundingBox;
},
getOriginalPosition: function() {
return [this._boundingBox.x, this._boundingBox.y];
},
_computeBoundingBox: function() {
let rect = this.metaWindow.get_outer_rect();
this.actor.get_children().forEach(function (child) {
let realWindow;
if (child == this._windowClone)
realWindow = this.realWindow;
else
realWindow = child.source;
let metaWindow = realWindow.meta_window;
rect = rect.union(metaWindow.get_outer_rect());
}, this);
this._boundingBox = rect;
this.actor.layout_manager.boundingBox = rect;
},
// Find the actor just below us, respecting reparenting done // Find the actor just below us, respecting reparenting done
// by DND code // by DND code
getActualStackAbove: function() { getActualStackAbove: function() {
@ -147,44 +287,26 @@ const WindowClone = new Lang.Class({
this.actor.destroy(); this.actor.destroy();
}, },
_disconnectRealWindowSignals: function() { _disconnectSignals: function() {
if (this._sizeChangedId > 0) this.actor.get_children().forEach(Lang.bind(this, function (child) {
this.realWindow.disconnect(this._sizeChangedId); let realWindow;
this._sizeChangedId = 0; if (child == this._windowClone)
realWindow = this.realWindow;
else
realWindow = child.source;
if (this._realWindowDestroyId > 0) realWindow.disconnect(child._updateId);
this.realWindow.disconnect(this._realWindowDestroyId); realWindow.disconnect(child._destroyId);
this._realWindowDestroyId = 0; }));
},
_getInvisibleBorderPadding: function() {
// We need to adjust the position of the actor because of the
// consequences of invisible borders -- in reality, the texture
// has an extra set of "padding" around it that we need to trim
// down.
// The outer rect paradoxically is the smaller rectangle,
// containing the positions of the visible frame. The input
// rect contains everything, including the invisible border
// padding.
let outerRect = this.metaWindow.get_outer_rect();
let inputRect = this.metaWindow.get_input_rect();
let [borderX, borderY] = [outerRect.x - inputRect.x,
outerRect.y - inputRect.y];
return [borderX, borderY];
}, },
_onRealWindowSizeChanged: function() { _onRealWindowSizeChanged: function() {
let [borderX, borderY] = this._getInvisibleBorderPadding(); this._computeBoundingBox();
let outerRect = this.metaWindow.get_outer_rect();
this.actor.set_size(outerRect.width, outerRect.height);
this._windowClone.set_position(-borderX, -borderY);
this.emit('size-changed'); this.emit('size-changed');
}, },
_onDestroy: function() { _onDestroy: function() {
this._disconnectRealWindowSignals(); this._disconnectSignals();
this.metaWindow._delegate = null; this.metaWindow._delegate = null;
this.actor._delegate = null; this.actor._delegate = null;
@ -197,11 +319,30 @@ const WindowClone = new Lang.Class({
this.disconnectAll(); this.disconnectAll();
}, },
_onClicked: function(action, actor) { _activate: function() {
this._selected = true; this._selected = true;
this.emit('selected', global.get_current_time()); this.emit('selected', global.get_current_time());
}, },
_onKeyPress: function(actor, event) {
let symbol = event.get_key_symbol();
let isEnter = (symbol == Clutter.KEY_Return || symbol == Clutter.KEY_KP_Enter);
if (isEnter) {
this._activate();
return true;
}
return false;
},
_onEnter: function() {
this.actor.grab_key_focus();
},
_onClicked: function(action, actor) {
this._activate();
},
_onLongPress: function(action, actor, state) { _onLongPress: function(action, actor, state) {
// Take advantage of the Clutter policy to consider // Take advantage of the Clutter policy to consider
// a long-press canceled when the pointer movement // a long-press canceled when the pointer movement
@ -301,6 +442,10 @@ const WindowOverlay = new Lang.Class({
Lang.bind(this, this._onEnter)); Lang.bind(this, this._onEnter));
windowClone.actor.connect('leave-event', windowClone.actor.connect('leave-event',
Lang.bind(this, this._onLeave)); Lang.bind(this, this._onLeave));
windowClone.actor.connect('key-focus-in',
Lang.bind(this, this._onEnter));
windowClone.actor.connect('key-focus-out',
Lang.bind(this, this._onLeave));
this._windowAddedId = 0; this._windowAddedId = 0;
@ -429,7 +574,7 @@ const WindowOverlay = new Lang.Class({
Lang.bind(this, Lang.bind(this,
this._onWindowAdded)); this._onWindowAdded));
metaWindow.delete(global.get_current_time()); this._windowClone.deleteAll();
}, },
_windowCanClose: function() { _windowCanClose: function() {
@ -448,7 +593,7 @@ const WindowOverlay = new Lang.Class({
Mainloop.idle_add(Lang.bind(this, Mainloop.idle_add(Lang.bind(this,
function() { function() {
this._windowClone.emit('selected'); this._windowClone.emit('selected');
return false; return GLib.SOURCE_REMOVE;
})); }));
} }
}, },
@ -512,15 +657,17 @@ const WindowOverlay = new Lang.Class({
// as the close button will be shown as needed when the overlays // as the close button will be shown as needed when the overlays
// are shown again // are shown again
if (this._hidden) if (this._hidden)
return; return Clutter.EVENT_PROPAGATE;
this._animateVisible(); this._animateVisible();
this.emit('show-close-button'); this.emit('show-close-button');
return Clutter.EVENT_PROPAGATE;
}, },
_onLeave: function() { _onLeave: function() {
if (this._idleToggleCloseId == 0) if (this._idleToggleCloseId == 0)
this._idleToggleCloseId = Mainloop.timeout_add(750, Lang.bind(this, this._idleToggleCloseButton)); this._idleToggleCloseId = Mainloop.timeout_add(750, Lang.bind(this, this._idleToggleCloseButton));
return Clutter.EVENT_PROPAGATE;
}, },
_idleToggleCloseButton: function() { _idleToggleCloseButton: function() {
@ -530,7 +677,7 @@ const WindowOverlay = new Lang.Class({
!this.closeButton.has_pointer) !this.closeButton.has_pointer)
this._animateInvisible(); this._animateInvisible();
return false; return GLib.SOURCE_REMOVE;
}, },
hideCloseButton: function() { hideCloseButton: function() {
@ -1198,18 +1345,18 @@ const Workspace = new Lang.Class({
// store current cursor position // store current cursor position
this._cursorX = x; this._cursorX = x;
this._cursorY = y; this._cursorY = y;
return true; return GLib.SOURCE_CONTINUE;
} }
let actorUnderPointer = global.stage.get_actor_at_pos(Clutter.PickMode.REACTIVE, x, y); let actorUnderPointer = global.stage.get_actor_at_pos(Clutter.PickMode.REACTIVE, x, y);
for (let i = 0; i < this._windows.length; i++) { for (let i = 0; i < this._windows.length; i++) {
if (this._windows[i].actor == actorUnderPointer) if (this._windows[i].actor == actorUnderPointer)
return true; return GLib.SOURCE_CONTINUE;
} }
this._recalculateWindowPositions(WindowPositionFlags.ANIMATE); this._recalculateWindowPositions(WindowPositionFlags.ANIMATE);
this._repositionWindowsId = 0; this._repositionWindowsId = 0;
return false; return GLib.SOURCE_REMOVE;
}, },
_doRemoveWindow : function(metaWin) { _doRemoveWindow : function(metaWin) {
@ -1284,7 +1431,7 @@ const Workspace = new Lang.Class({
metaWin.get_compositor_private() && metaWin.get_compositor_private() &&
metaWin.get_workspace() == this.metaWorkspace) metaWin.get_workspace() == this.metaWorkspace)
this._doAddWindow(metaWin); this._doAddWindow(metaWin);
return false; return GLib.SOURCE_REMOVE;
})); }));
return; return;
} }
@ -1294,9 +1441,29 @@ const Workspace = new Lang.Class({
if (this._lookupIndex (metaWin) != -1) if (this._lookupIndex (metaWin) != -1)
return; return;
if (!this._isMyWindow(win) || !this._isOverviewWindow(win)) if (!this._isMyWindow(win))
return; return;
if (!this._isOverviewWindow(win)) {
if (metaWin.is_attached_dialog()) {
let parent = metaWin.get_transient_for();
while (parent.is_attached_dialog())
parent = metaWin.get_transient_for();
let idx = this._lookupIndex (parent);
if (idx < 0) {
// parent was not created yet, it will take care
// of the dialog when created
return;
}
let clone = this._windows[idx];
clone.addAttachedDialog(metaWin);
}
return;
}
let [clone, overlay] = this._addWindowClone(win, false); let [clone, overlay] = this._addWindowClone(win, false);
if (win._overviewHint) { if (win._overviewHint) {
@ -1354,39 +1521,46 @@ const Workspace = new Lang.Class({
this._recalculateWindowPositions(WindowPositionFlags.ANIMATE | WindowPositionFlags.INITIAL); this._recalculateWindowPositions(WindowPositionFlags.ANIMATE | WindowPositionFlags.INITIAL);
}, },
// Animates the return from Overview mode _leavingOverview: function() {
zoomFromOverview : function() {
let currentWorkspace = global.screen.get_active_workspace(); let currentWorkspace = global.screen.get_active_workspace();
if (this.metaWorkspace != null && this.metaWorkspace != currentWorkspace)
return false;
this.leavingOverview = true; this.leavingOverview = true;
this._overviewHiddenId = Main.overview.connect('hidden', Lang.bind(this,
this._doneLeavingOverview));
for (let i = 0; i < this._windows.length; i++) { for (let i = 0; i < this._windows.length; i++) {
let clone = this._windows[i]; let clone = this._windows[i];
Tweener.removeTweens(clone.actor); Tweener.removeTweens(clone.actor);
let overlay = this._windowOverlays[i];
if (overlay)
overlay.hide();
} }
if (this._repositionWindowsId > 0) { if (this._repositionWindowsId > 0) {
Mainloop.source_remove(this._repositionWindowsId); Mainloop.source_remove(this._repositionWindowsId);
this._repositionWindowsId = 0; this._repositionWindowsId = 0;
} }
this._overviewHiddenId = Main.overview.connect('hidden', Lang.bind(this,
this._doneLeavingOverview));
if (this.metaWorkspace != null && this.metaWorkspace != currentWorkspace) return true;
},
// Animates the return from Overview mode
zoomFromOverview : function() {
if (!this._leavingOverview())
return; return;
// Position and scale the windows.
for (let i = 0; i < this._windows.length; i++) { for (let i = 0; i < this._windows.length; i++) {
let clone = this._windows[i]; let clone = this._windows[i];
let overlay = this._windowOverlays[i];
if (overlay)
overlay.hide();
if (clone.metaWindow.showing_on_its_workspace()) { if (clone.metaWindow.showing_on_its_workspace()) {
let [origX, origY] = clone.getOriginalPosition();
Tweener.addTween(clone.actor, Tweener.addTween(clone.actor,
{ x: clone.origX, { x: origX,
y: clone.origY, y: origY,
scale_x: 1.0, scale_x: 1.0,
scale_y: 1.0, scale_y: 1.0,
time: Overview.ANIMATION_TIME, time: Overview.ANIMATION_TIME,
@ -1406,6 +1580,31 @@ const Workspace = new Lang.Class({
} }
}, },
fadeFromOverview: function() {
if (!this._leavingOverview())
return;
for (let i = 0; i < this._windows.length; i++) {
let clone = this._windows[i];
if (clone.metaWindow.showing_on_its_workspace()) {
clone.actor.x = clone.origX;
clone.actor.y = clone.origY;
clone.actor.scale_x = 1.0;
clone.actor.scale_y = 1.0;
clone.actor.opacity = 0;
Tweener.addTween(clone.actor,
{ opacity: 255,
time: Overview.ANIMATION_TIME,
transition: 'easeOutQuad'
});
} else {
clone.actor.hide();
}
}
},
destroy : function() { destroy : function() {
this.actor.destroy(); this.actor.destroy();
}, },
@ -1450,8 +1649,7 @@ const Workspace = new Lang.Class({
// Tests if @win should be shown in the Overview // Tests if @win should be shown in the Overview
_isOverviewWindow : function (win) { _isOverviewWindow : function (win) {
let tracker = Shell.WindowTracker.get_default(); return !win.get_meta_window().skip_taskbar;
return tracker.is_window_interesting(win.get_meta_window());
}, },
// Create a clone of a (non-desktop) window and add it to the window list // Create a clone of a (non-desktop) window and add it to the window list

View File

@ -1,6 +1,7 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
const Clutter = imports.gi.Clutter; const Clutter = imports.gi.Clutter;
const GLib = imports.gi.GLib;
const Lang = imports.lang; const Lang = imports.lang;
const Mainloop = imports.mainloop; const Mainloop = imports.mainloop;
const Meta = imports.gi.Meta; const Meta = imports.gi.Meta;
@ -24,7 +25,7 @@ const WorkspaceSwitcherPopup = new Lang.Class({
width: global.screen_width, width: global.screen_width,
height: global.screen_height, height: global.screen_height,
style_class: 'workspace-switcher-group' }); style_class: 'workspace-switcher-group' });
Main.uiGroup.add_actor(this.actor); Main.layoutManager.osdGroup.add_child(this.actor);
this._container = new St.BoxLayout({ style_class: 'workspace-switcher-container' }); this._container = new St.BoxLayout({ style_class: 'workspace-switcher-container' });
this._list = new Shell.GenericContainer({ style_class: 'workspace-switcher' }); this._list = new Shell.GenericContainer({ style_class: 'workspace-switcher' });
@ -156,6 +157,7 @@ const WorkspaceSwitcherPopup = new Lang.Class({
onComplete: function() { this.destroy(); }, onComplete: function() { this.destroy(); },
onCompleteScope: this onCompleteScope: this
}); });
return GLib.SOURCE_REMOVE;
}, },
destroy: function() { destroy: function() {

View File

@ -2,6 +2,7 @@
const Clutter = imports.gi.Clutter; const Clutter = imports.gi.Clutter;
const Gio = imports.gi.Gio; const Gio = imports.gi.Gio;
const GLib = imports.gi.GLib;
const Lang = imports.lang; const Lang = imports.lang;
const Mainloop = imports.mainloop; const Mainloop = imports.mainloop;
const Meta = imports.gi.Meta; const Meta = imports.gi.Meta;
@ -13,6 +14,7 @@ const Background = imports.ui.background;
const DND = imports.ui.dnd; const DND = imports.ui.dnd;
const Main = imports.ui.main; const Main = imports.ui.main;
const Tweener = imports.ui.tweener; const Tweener = imports.ui.tweener;
const WindowManager = imports.ui.windowManager;
const Workspace = imports.ui.workspace; const Workspace = imports.ui.workspace;
const WorkspacesView = imports.ui.workspacesView; const WorkspacesView = imports.ui.workspacesView;
@ -31,20 +33,49 @@ const WORKSPACE_KEEP_ALIVE_TIME = 100;
const OVERRIDE_SCHEMA = 'org.gnome.shell.overrides'; const OVERRIDE_SCHEMA = 'org.gnome.shell.overrides';
/* A layout manager that requests size only for primary_actor, but then allocates
all using a fixed layout */
const PrimaryActorLayout = new Lang.Class({
Name: 'PrimaryActorLayout',
Extends: Clutter.FixedLayout,
_init: function(primaryActor) {
this.parent();
this.primaryActor = primaryActor;
},
vfunc_get_preferred_width: function(forHeight) {
return this.primaryActor.get_preferred_width(forHeight);
},
vfunc_get_preferred_height: function(forWidth) {
return this.primaryActor.get_preferred_height(forWidth);
},
});
const WindowClone = new Lang.Class({ const WindowClone = new Lang.Class({
Name: 'WindowClone', Name: 'WindowClone',
_init : function(realWindow) { _init : function(realWindow) {
this.actor = new Clutter.Clone({ source: realWindow.get_texture(), this.clone = new Clutter.Clone({ source: realWindow });
/* Can't use a Shell.GenericContainer because of DND and reparenting... */
this.actor = new Clutter.Actor({ layout_manager: new PrimaryActorLayout(this.clone),
reactive: true }); reactive: true });
this.actor._delegate = this; this.actor._delegate = this;
this.actor.add_child(this.clone);
this.realWindow = realWindow; this.realWindow = realWindow;
this.metaWindow = realWindow.meta_window; this.metaWindow = realWindow.meta_window;
this._positionChangedId = this.realWindow.connect('position-changed', this.clone._updateId = this.realWindow.connect('position-changed',
Lang.bind(this, this._onPositionChanged)); Lang.bind(this, this._onPositionChanged));
this._realWindowDestroyedId = this.realWindow.connect('destroy', this.clone._destroyId = this.realWindow.connect('destroy', Lang.bind(this, function() {
Lang.bind(this, this._disconnectRealWindowSignals)); // First destroy the clone and then destroy everything
// This will ensure that we never see it in the _disconnectSignals loop
this.clone.destroy();
this.destroy();
}));
this._onPositionChanged(); this._onPositionChanged();
this.actor.connect('button-release-event', this.actor.connect('button-release-event',
@ -60,6 +91,21 @@ const WindowClone = new Lang.Class({
this._draggable.connect('drag-cancelled', Lang.bind(this, this._onDragCancelled)); this._draggable.connect('drag-cancelled', Lang.bind(this, this._onDragCancelled));
this._draggable.connect('drag-end', Lang.bind(this, this._onDragEnd)); this._draggable.connect('drag-end', Lang.bind(this, this._onDragEnd));
this.inDrag = false; this.inDrag = false;
let iter = Lang.bind(this, function(win) {
let actor = win.get_compositor_private();
if (!actor)
return false;
if (!win.is_attached_dialog())
return false;
this._doAddAttachedDialog(win, actor);
win.foreach_transient(iter);
return true;
});
this.metaWindow.foreach_transient(iter);
}, },
// Find the actor just below us, respecting reparenting done // Find the actor just below us, respecting reparenting done
@ -97,25 +143,46 @@ const WindowClone = new Lang.Class({
this.actor.destroy(); this.actor.destroy();
}, },
addAttachedDialog: function(win) {
this._doAddAttachedDialog(win, win.get_compositor_private());
},
_doAddAttachedDialog: function(metaDialog, realDialog) {
let clone = new Clutter.Clone({ source: realDialog });
this._updateDialogPosition(realDialog, clone);
clone._updateId = realDialog.connect('position-changed',
Lang.bind(this, this._updateDialogPosition, clone));
clone._destroyId = realDialog.connect('destroy', Lang.bind(this, function() {
clone.destroy();
}));
this.actor.add_child(clone);
},
_updateDialogPosition: function(realDialog, cloneDialog) {
let metaDialog = realDialog.meta_window;
let dialogRect = metaDialog.get_outer_rect();
let rect = this.metaWindow.get_outer_rect();
cloneDialog.set_position(dialogRect.x - rect.x, dialogRect.y - rect.y);
},
_onPositionChanged: function() { _onPositionChanged: function() {
let rect = this.metaWindow.get_outer_rect(); let rect = this.metaWindow.get_outer_rect();
this.actor.set_position(this.realWindow.x, this.realWindow.y); this.actor.set_position(this.realWindow.x, this.realWindow.y);
}, },
_disconnectRealWindowSignals: function() { _disconnectSignals: function() {
if (this._positionChangedId != 0) { this.actor.get_children().forEach(function(child) {
this.realWindow.disconnect(this._positionChangedId); let realWindow = child.source;
this._positionChangedId = 0;
}
if (this._realWindowDestroyedId != 0) { realWindow.disconnect(child._updateId);
this.realWindow.disconnect(this._realWindowDestroyedId); realWindow.disconnect(child._destroyId);
this._realWindowDestroyedId = 0; });
}
}, },
_onDestroy: function() { _onDestroy: function() {
this._disconnectRealWindowSignals(); this._disconnectSignals();
this.actor._delegate = null; this.actor._delegate = null;
@ -130,7 +197,7 @@ const WindowClone = new Lang.Class({
_onButtonRelease : function (actor, event) { _onButtonRelease : function (actor, event) {
this.emit('selected', event.get_time()); this.emit('selected', event.get_time());
return true; return Clutter.EVENT_STOP;
}, },
_onDragBegin : function (draggable, time) { _onDragBegin : function (draggable, time) {
@ -325,7 +392,7 @@ const WorkspaceThumbnail = new Lang.Class({
metaWin.get_compositor_private() && metaWin.get_compositor_private() &&
metaWin.get_workspace() == this.metaWorkspace) metaWin.get_workspace() == this.metaWorkspace)
this._doAddWindow(metaWin); this._doAddWindow(metaWin);
return false; return GLib.SOURCE_REMOVE;
})); }));
return; return;
} }
@ -343,10 +410,26 @@ const WorkspaceThumbnail = new Lang.Class({
if (this._lookupIndex (metaWin) != -1) if (this._lookupIndex (metaWin) != -1)
return; return;
if (!this._isMyWindow(win) || !this._isOverviewWindow(win)) if (!this._isMyWindow(win))
return; return;
let clone = this._addWindowClone(win); if (this._isOverviewWindow(win)) {
this._addWindowClone(win);
} else if (metaWin.is_attached_dialog()) {
let parent = metaWin.get_transient_for();
while (parent.is_attached_dialog())
parent = metaWin.get_transient_for();
let idx = this._lookupIndex (parent);
if (idx < 0) {
// parent was not created yet, it will take care
// of the dialog when created
return;
}
let clone = this._windows[idx];
clone.addAttachedDialog(metaWin);
}
}, },
_windowAdded : function(metaWorkspace, metaWin) { _windowAdded : function(metaWorkspace, metaWin) {
@ -424,8 +507,7 @@ const WorkspaceThumbnail = new Lang.Class({
// Tests if @win should be shown in the Overview // Tests if @win should be shown in the Overview
_isOverviewWindow : function (win) { _isOverviewWindow : function (win) {
let tracker = Shell.WindowTracker.get_default(); return !win.get_meta_window().skip_taskbar &&
return tracker.is_window_interesting(win.get_meta_window()) &&
win.get_meta_window().showing_on_its_workspace(); win.get_meta_window().showing_on_its_workspace();
}, },
@ -561,7 +643,7 @@ const ThumbnailsBox = new Lang.Class({
this._thumbnails = []; this._thumbnails = [];
this.actor.connect('button-press-event', function() { return true; }); this.actor.connect('button-press-event', function() { return Clutter.EVENT_STOP; });
this.actor.connect('button-release-event', Lang.bind(this, this._onButtonRelease)); this.actor.connect('button-release-event', Lang.bind(this, this._onButtonRelease));
Main.overview.connect('showing', Main.overview.connect('showing',
@ -606,7 +688,7 @@ const ThumbnailsBox = new Lang.Class({
} }
} }
return true; return Clutter.EVENT_STOP;
}, },
_onDragBegin: function() { _onDragBegin: function() {

View File

@ -30,6 +30,7 @@ const WorkspacesViewBase = new Lang.Class({
this.actor = new St.Widget({ style_class: 'workspaces-view', this.actor = new St.Widget({ style_class: 'workspaces-view',
reactive: true }); reactive: true });
this.actor.connect('destroy', Lang.bind(this, this._onDestroy)); this.actor.connect('destroy', Lang.bind(this, this._onDestroy));
global.focus_manager.add_group(this.actor);
// The actor itself isn't a drop target, so we don't want to pick on its area // The actor itself isn't a drop target, so we don't want to pick on its area
this.actor.set_size(0, 0); this.actor.set_size(0, 0);
@ -144,11 +145,22 @@ const WorkspacesView = new Lang.Class({
this._updateWorkspaceActors(false); this._updateWorkspaceActors(false);
}, },
zoomFromOverview: function() { _leaveOverview: function() {
this.actor.remove_clip(); this.actor.remove_clip();
},
for (let w = 0; w < this._workspaces.length; w++) zoomFromOverview: function() {
this._workspaces[w].zoomFromOverview(); this._leaveOverview();
this._workspaces.forEach(function(w) {
w.zoomFromOverview();
});
},
fadeFromOverview: function() {
this._leaveOverview();
this._workspaces.forEach(function(w) {
w.fadeFromOverview();
});
}, },
syncStacking: function(stackIndices) { syncStacking: function(stackIndices) {
@ -236,29 +248,32 @@ const WorkspacesView = new Lang.Class({
}, },
_updateWorkspaces: function() { _updateWorkspaces: function() {
let oldNumWorkspaces = this._workspaces.length;
let newNumWorkspaces = global.screen.n_workspaces; let newNumWorkspaces = global.screen.n_workspaces;
this.scrollAdjustment.upper = newNumWorkspaces; this.scrollAdjustment.upper = newNumWorkspaces;
if (newNumWorkspaces > oldNumWorkspaces) { let needsUpdate = false;
for (let w = oldNumWorkspaces; w < newNumWorkspaces; w++) { for (let j = 0; j < newNumWorkspaces; j++) {
let metaWorkspace = global.screen.get_workspace_by_index(w); let metaWorkspace = global.screen.get_workspace_by_index(j);
let workspace = new Workspace.Workspace(metaWorkspace, this._monitorIndex); let workspace;
this._workspaces.push(workspace);
this.actor.add_actor(workspace.actor);
}
if (this._fullGeometry) if (j >= this._workspaces.length) { /* added */
this._updateWorkspaceActors(false); workspace = new Workspace.Workspace(metaWorkspace, this._monitorIndex);
} else if (newNumWorkspaces < oldNumWorkspaces) { this.actor.add_actor(workspace.actor);
let nRemoved = (newNumWorkspaces - oldNumWorkspaces); this._workspaces[j] = workspace;
let removed = this._workspaces.splice(oldNumWorkspaces, nRemoved); } else {
removed.forEach(function(workspace) { workspace = this._workspaces[j];
workspace.destroy();
}); if (workspace.metaWorkspace != metaWorkspace) { /* removed */
workspace.destroy();
this._workspaces.splice(j, 1);
} /* else kept */
}
} }
if (this._fullGeometry)
this._updateWorkspaceActors(false);
this._syncGeometry(); this._syncGeometry();
}, },
@ -361,6 +376,10 @@ const ExtraWorkspaceView = new Lang.Class({
this._workspace.zoomFromOverview(); this._workspace.zoomFromOverview();
}, },
fadeFromOverview: function() {
this._workspace.fadeFromOverview();
},
syncStacking: function(stackIndices) { syncStacking: function(stackIndices) {
this._workspace.syncStacking(stackIndices); this._workspace.syncStacking(stackIndices);
}, },
@ -371,11 +390,21 @@ const ExtraWorkspaceView = new Lang.Class({
}, },
}); });
const DelegateFocusNavigator = new Lang.Class({
Name: 'DelegateFocusNavigator',
Extends: St.Widget,
vfunc_navigate_focus: function(from, direction) {
return this._delegate.navigateFocus(from, direction);
},
});
const WorkspacesDisplay = new Lang.Class({ const WorkspacesDisplay = new Lang.Class({
Name: 'WorkspacesDisplay', Name: 'WorkspacesDisplay',
_init: function() { _init: function() {
this.actor = new St.Widget({ clip_to_allocation: true }); this.actor = new DelegateFocusNavigator({ clip_to_allocation: true });
this.actor._delegate = this;
this.actor.connect('notify::allocation', Lang.bind(this, this._updateWorkspacesActualGeometry)); this.actor.connect('notify::allocation', Lang.bind(this, this._updateWorkspacesActualGeometry));
this.actor.connect('parent-set', Lang.bind(this, this._parentSet)); this.actor.connect('parent-set', Lang.bind(this, this._parentSet));
@ -391,7 +420,7 @@ const WorkspacesDisplay = new Lang.Class({
Main.overview.addAction(clickAction); Main.overview.addAction(clickAction);
this.actor.bind_property('mapped', clickAction, 'enabled', GObject.BindingFlags.SYNC_CREATE); this.actor.bind_property('mapped', clickAction, 'enabled', GObject.BindingFlags.SYNC_CREATE);
let panAction = new Clutter.PanAction(); let panAction = new Clutter.PanAction({ threshold_trigger_edge: Clutter.GestureTriggerEdge.AFTER });
panAction.connect('pan', Lang.bind(this, this._onPan)); panAction.connect('pan', Lang.bind(this, this._onPan));
panAction.connect('gesture-begin', Lang.bind(this, function() { panAction.connect('gesture-begin', Lang.bind(this, function() {
for (let i = 0; i < this._workspacesViews.length; i++) for (let i = 0; i < this._workspacesViews.length; i++)
@ -399,7 +428,6 @@ const WorkspacesDisplay = new Lang.Class({
return true; return true;
})); }));
panAction.connect('gesture-cancel', Lang.bind(this, function() { panAction.connect('gesture-cancel', Lang.bind(this, function() {
clickAction.release();
for (let i = 0; i < this._workspacesViews.length; i++) for (let i = 0; i < this._workspacesViews.length; i++)
this._workspacesViews[i].endSwipeScroll(); this._workspacesViews[i].endSwipeScroll();
})); }));
@ -437,6 +465,10 @@ const WorkspacesDisplay = new Lang.Class({
return false; return false;
}, },
navigateFocus: function(from, direction) {
return this._getPrimaryView().actor.navigate_focus(from, direction, false);
},
show: function() { show: function() {
this._updateWorkspacesViews(); this._updateWorkspacesViews();
for (let i = 0; i < this._workspacesViews.length; i++) for (let i = 0; i < this._workspacesViews.length; i++)
@ -449,9 +481,18 @@ const WorkspacesDisplay = new Lang.Class({
this._scrollEventId = Main.overview.connect('scroll-event', Lang.bind(this, this._onScrollEvent)); this._scrollEventId = Main.overview.connect('scroll-event', Lang.bind(this, this._onScrollEvent));
}, },
zoomFromOverview: function() { leaveOverview: function(zoomPrimary) {
for (let i = 0; i < this._workspacesViews.length; i++) for (let i = 0; i < this._workspacesViews.length; i++) {
this._workspacesViews[i].zoomFromOverview(); let view = this._workspacesViews[i];
if (i == this._primaryIndex) {
if (zoomPrimary)
view.zoomFromOverview();
else
view.fadeFromOverview();
} else {
view.zoomFromOverview();
}
}
}, },
hide: function() { hide: function() {
@ -599,7 +640,7 @@ const WorkspacesDisplay = new Lang.Class({
_onScrollEvent: function(actor, event) { _onScrollEvent: function(actor, event) {
if (!this.actor.mapped) if (!this.actor.mapped)
return false; return Clutter.EVENT_PROPAGATE;
let activeWs = global.screen.get_active_workspace(); let activeWs = global.screen.get_active_workspace();
let ws; let ws;
switch (event.get_scroll_direction()) { switch (event.get_scroll_direction()) {
@ -610,10 +651,10 @@ const WorkspacesDisplay = new Lang.Class({
ws = activeWs.get_neighbor(Meta.MotionDirection.DOWN); ws = activeWs.get_neighbor(Meta.MotionDirection.DOWN);
break; break;
default: default:
return false; return Clutter.EVENT_PROPAGATE;
} }
Main.wm.actionMoveWorkspace(ws); Main.wm.actionMoveWorkspace(ws);
return true; return Clutter.EVENT_STOP;
} }
}); });
Signals.addSignalMethods(WorkspacesDisplay.prototype); Signals.addSignalMethods(WorkspacesDisplay.prototype);

View File

@ -18,7 +18,7 @@ const XdndHandler = new Lang.Class({
// Used as a drag actor in case we don't have a cursor window clone // Used as a drag actor in case we don't have a cursor window clone
this._dummy = new Clutter.Actor({ width: 1, height: 1, opacity: 0 }); this._dummy = new Clutter.Actor({ width: 1, height: 1, opacity: 0 });
Main.uiGroup.add_actor(this._dummy); Main.layoutManager.sessionGroup.add_actor(this._dummy);
this._dummy.hide(); this._dummy.hide();
if (!Meta.is_wayland_compositor()) if (!Meta.is_wayland_compositor())
@ -62,14 +62,14 @@ const XdndHandler = new Lang.Class({
let cursorWindow = windows[windows.length - 1]; let cursorWindow = windows[windows.length - 1];
// FIXME: more reliable way? // FIXME: more reliable way?
if (!cursorWindow.is_override_redirect()) if (!cursorWindow.get_meta_window().is_override_redirect())
return; return;
let constraint_position = new Clutter.BindConstraint({ coordinate : Clutter.BindCoordinate.POSITION, let constraint_position = new Clutter.BindConstraint({ coordinate : Clutter.BindCoordinate.POSITION,
source: cursorWindow}); source: cursorWindow});
this._cursorWindowClone = new Clutter.Clone({ source: cursorWindow }); this._cursorWindowClone = new Clutter.Clone({ source: cursorWindow });
Main.uiGroup.add_actor(this._cursorWindowClone); Main.layoutManager.sessionGroup.add_actor(this._cursorWindowClone);
// Make sure that the clone has the same position as the source // Make sure that the clone has the same position as the source
this._cursorWindowClone.add_constraint(constraint_position); this._cursorWindowClone.add_constraint(constraint_position);

2077
po/an.po

File diff suppressed because it is too large Load Diff

891
po/ar.po

File diff suppressed because it is too large Load Diff

831
po/as.po

File diff suppressed because it is too large Load Diff

720
po/cs.po

File diff suppressed because it is too large Load Diff

476
po/de.po

File diff suppressed because it is too large Load Diff

526
po/el.po

File diff suppressed because it is too large Load Diff

811
po/es.po

File diff suppressed because it is too large Load Diff

219
po/et.po
View File

@ -13,8 +13,8 @@ msgstr ""
"Project-Id-Version: gnome-shell MASTER\n" "Project-Id-Version: gnome-shell MASTER\n"
"Report-Msgid-Bugs-To: http://bugzilla.gnome.org/enter_bug.cgi?product=gnome-" "Report-Msgid-Bugs-To: http://bugzilla.gnome.org/enter_bug.cgi?product=gnome-"
"shell&keywords=I18N+L10N&component=general\n" "shell&keywords=I18N+L10N&component=general\n"
"POT-Creation-Date: 2013-09-30 11:41+0000\n" "POT-Creation-Date: 2014-01-14 01:18+0000\n"
"PO-Revision-Date: 2013-10-01 16:40+0300\n" "PO-Revision-Date: 2014-01-14 13:33+0300\n"
"Last-Translator: Mattias Põldaru <mahfiaz@gmail.com>\n" "Last-Translator: Mattias Põldaru <mahfiaz@gmail.com>\n"
"Language-Team: Estonian <>\n" "Language-Team: Estonian <>\n"
"Language: et\n" "Language: et\n"
@ -68,14 +68,14 @@ msgstr ""
"Lubab ligipääsu sisemistele silumise ja monitoorimise tööriistadele Alt-F2 " "Lubab ligipääsu sisemistele silumise ja monitoorimise tööriistadele Alt-F2 "
"dialoogi kaudu." "dialoogi kaudu."
msgid "Uuids of extensions to enable" msgid "UUIDs of extensions to enable"
msgstr "Lubatavate laienduste UUID-d" msgstr "Lubatavate laienduste UUID-d"
msgid "" msgid ""
"GNOME Shell extensions have a uuid property; this key lists extensions which " "GNOME Shell extensions have a UUID property; this key lists extensions which "
"should be loaded. Any extension that wants to be loaded needs to be in this " "should be loaded. Any extension that wants to be loaded needs to be in this "
"list. You can also manipulate this list with the EnableExtension and " "list. You can also manipulate this list with the EnableExtension and "
"DisableExtension DBus methods on org.gnome.Shell." "DisableExtension D-Bus methods on org.gnome.Shell."
msgstr "" msgstr ""
"GNOME Shelli laiendustel on UUID omadus; selles võtmes loetletud laiendused " "GNOME Shelli laiendustel on UUID omadus; selles võtmes loetletud laiendused "
"tuleks laadida. Seda loendit saab muuta kasutades EnableExtension ja " "tuleks laadida. Seda loendit saab muuta kasutades EnableExtension ja "
@ -106,11 +106,11 @@ msgstr "Käsudialoogi (Alt-F2) ajalugu"
msgid "History for the looking glass dialog" msgid "History for the looking glass dialog"
msgstr "Otsingudialoogi ajalugu" msgstr "Otsingudialoogi ajalugu"
msgid "Always show the 'Log out' menuitem in the user menu." msgid "Always show the 'Log out' menu item in the user menu."
msgstr "Kasutajamenüüs näidatakse alati 'Logi välja' menüükirjet." msgstr "Kasutajamenüüs näidatakse alati 'Logi välja' menüükirjet."
msgid "" msgid ""
"This key overrides the automatic hiding of the 'Log out' menuitem in single-" "This key overrides the automatic hiding of the 'Log out' menu item in single-"
"user, single-session situations." "user, single-session situations."
msgstr "" msgstr ""
"See võti keelab automaatse 'Logi välja' menüükirje peitmise, kui arvutis on " "See võti keelab automaatse 'Logi välja' menüükirje peitmise, kui arvutis on "
@ -218,6 +218,13 @@ msgstr "Tööalad peamisel monitoril"
msgid "Delay focus changes in mouse mode until the pointer stops moving" msgid "Delay focus changes in mouse mode until the pointer stops moving"
msgstr "Hiire all asuv aken saab fookuse alles hiire peatumisel" msgstr "Hiire all asuv aken saab fookuse alles hiire peatumisel"
#, javascript-format
msgid "There was an error loading the preferences dialog for %s:"
msgstr "%s jaoks eelistuste dialoogi laadimisel esines viga:"
msgid "Extension"
msgstr "Laiendus"
msgid "Select an extension to configure using the combobox above." msgid "Select an extension to configure using the combobox above."
msgstr "Vali seadistatav laiendus kasutades ülemist valikukasti." msgstr "Vali seadistatav laiendus kasutades ülemist valikukasti."
@ -240,6 +247,7 @@ msgstr "Seansi valimine"
msgid "Not listed?" msgid "Not listed?"
msgstr "Pole loendis?" msgstr "Pole loendis?"
#, javascript-format
msgid "(e.g., user or %s)" msgid "(e.g., user or %s)"
msgstr "(nt 'user' või %s)" msgstr "(nt 'user' või %s)"
@ -261,6 +269,7 @@ msgstr "Käsku ei leitud"
msgid "Could not parse command:" msgid "Could not parse command:"
msgstr "Käsku pole võimalik analüüsida:" msgstr "Käsku pole võimalik analüüsida:"
#, javascript-format
msgid "Execution of '%s' failed:" msgid "Execution of '%s' failed:"
msgstr "'%s' käivitamine nurjus:" msgstr "'%s' käivitamine nurjus:"
@ -282,9 +291,11 @@ msgstr "Eemalda lemmikutest"
msgid "Add to Favorites" msgid "Add to Favorites"
msgstr "Lisa lemmikutesse" msgstr "Lisa lemmikutesse"
#, javascript-format
msgid "%s has been added to your favorites." msgid "%s has been added to your favorites."
msgstr "%s lisati lemmikutesse." msgstr "%s lisati lemmikutesse."
#, javascript-format
msgid "%s has been removed from your favorites." msgid "%s has been removed from your favorites."
msgstr "%s eemaldati lemmikutest." msgstr "%s eemaldati lemmikutest."
@ -437,6 +448,7 @@ msgstr "Väline ketas eemaldati"
msgid "Removable Devices" msgid "Removable Devices"
msgstr "Eemaldatavad seadmed" msgstr "Eemaldatavad seadmed"
#, javascript-format
msgid "Open with %s" msgid "Open with %s"
msgstr "Ava programmiga %s" msgstr "Ava programmiga %s"
@ -470,6 +482,7 @@ msgstr "Teenus: "
msgid "Authentication required by wireless network" msgid "Authentication required by wireless network"
msgstr "Juhtmeta võrgu jaoks on vajalik autentimine" msgstr "Juhtmeta võrgu jaoks on vajalik autentimine"
#, javascript-format
msgid "" msgid ""
"Passwords or encryption keys are required to access the wireless network " "Passwords or encryption keys are required to access the wireless network "
"'%s'." "'%s'."
@ -497,6 +510,7 @@ msgstr "PIN: "
msgid "Mobile broadband network password" msgid "Mobile broadband network password"
msgstr "Mobiiliühenduse võrgu parool" msgstr "Mobiiliühenduse võrgu parool"
#, javascript-format
msgid "A password is required to connect to '%s'." msgid "A password is required to connect to '%s'."
msgstr "'%s' ühenduse loomiseks on vaja parooli." msgstr "'%s' ühenduse loomiseks on vaja parooli."
@ -552,17 +566,20 @@ msgstr "<b>%d. %B %Y</b>, <b>%H:%M</b>"
#. Translators: this is the other person changing their old IM name to their new #. Translators: this is the other person changing their old IM name to their new
#. IM name. */ #. IM name. */
#, javascript-format
msgid "%s is now known as %s" msgid "%s is now known as %s"
msgstr "%s nimi on nüüd %s" msgstr "%s nimi on nüüd %s"
#. translators: argument is a room name like #. translators: argument is a room name like
#. * room@jabber.org for example. */ #. * room@jabber.org for example. */
#, javascript-format
msgid "Invitation to %s" msgid "Invitation to %s"
msgstr "Kutse: %s" msgstr "Kutse: %s"
#. translators: first argument is the name of a contact and the second #. translators: first argument is the name of a contact and the second
#. * one the name of a room. "Alice is inviting you to join room@jabber.org #. * one the name of a room. "Alice is inviting you to join room@jabber.org
#. * for example. */ #. * for example. */
#, javascript-format
msgid "%s is inviting you to join %s" msgid "%s is inviting you to join %s"
msgstr "%s kutsub sind liituma: %s" msgstr "%s kutsub sind liituma: %s"
@ -573,10 +590,12 @@ msgid "Accept"
msgstr "Nõustu" msgstr "Nõustu"
#. translators: argument is a contact name like Alice for example. */ #. translators: argument is a contact name like Alice for example. */
#, javascript-format
msgid "Video call from %s" msgid "Video call from %s"
msgstr "%s tahab alustada videokõnet" msgstr "%s tahab alustada videokõnet"
#. translators: argument is a contact name like Alice for example. */ #. translators: argument is a contact name like Alice for example. */
#, javascript-format
msgid "Call from %s" msgid "Call from %s"
msgstr "%s helistab" msgstr "%s helistab"
@ -589,10 +608,12 @@ msgstr "Vasta"
#. * file name. The string will be something #. * file name. The string will be something
#. * like: "Alice is sending you test.ogg" #. * like: "Alice is sending you test.ogg"
#. */ #. */
#, javascript-format
msgid "%s is sending you %s" msgid "%s is sending you %s"
msgstr "%s saadab sulle %s" msgstr "%s saadab sulle %s"
#. To translators: The parameter is the contact's alias */ #. To translators: The parameter is the contact's alias */
#, javascript-format
msgid "%s would like permission to see when you are online" msgid "%s would like permission to see when you are online"
msgstr "%s palub sinu luba, et näha, kui sa oled võrgus" msgstr "%s palub sinu luba, et näha, kui sa oled võrgus"
@ -677,6 +698,7 @@ msgstr "Sisemine viga"
#. translators: argument is the account name, like #. translators: argument is the account name, like
#. * name@jabber.org for example. */ #. * name@jabber.org for example. */
#, javascript-format
msgid "Unable to connect to %s" msgid "Unable to connect to %s"
msgstr "Pole võimalik ühenduda võrguga %s" msgstr "Pole võimalik ühenduda võrguga %s"
@ -710,6 +732,7 @@ msgstr "Kuupäeva ja kella sätted"
msgid "%A %B %e, %Y" msgid "%A %B %e, %Y"
msgstr "%A, %d. %B %Y" msgstr "%A, %d. %B %Y"
#, javascript-format
msgctxt "title" msgctxt "title"
msgid "Log Out %s" msgid "Log Out %s"
msgstr "%s väljalogimine" msgstr "%s väljalogimine"
@ -718,11 +741,13 @@ msgctxt "title"
msgid "Log Out" msgid "Log Out"
msgstr "Väljalogimine" msgstr "Väljalogimine"
#, javascript-format
msgid "%s will be logged out automatically in %d second." msgid "%s will be logged out automatically in %d second."
msgid_plural "%s will be logged out automatically in %d seconds." msgid_plural "%s will be logged out automatically in %d seconds."
msgstr[0] "%s logitakse %d sekundi pärast automaatselt välja." msgstr[0] "%s logitakse %d sekundi pärast automaatselt välja."
msgstr[1] "%s logitakse %d sekundi pärast automaatselt välja." msgstr[1] "%s logitakse %d sekundi pärast automaatselt välja."
#, javascript-format
msgid "You will be logged out automatically in %d second." msgid "You will be logged out automatically in %d second."
msgid_plural "You will be logged out automatically in %d seconds." msgid_plural "You will be logged out automatically in %d seconds."
msgstr[0] "Sind logitakse %d sekundi pärast automaatselt välja." msgstr[0] "Sind logitakse %d sekundi pärast automaatselt välja."
@ -736,6 +761,7 @@ msgctxt "title"
msgid "Power Off" msgid "Power Off"
msgstr "Väljalülitamine" msgstr "Väljalülitamine"
#, javascript-format
msgid "The system will power off automatically in %d second." msgid "The system will power off automatically in %d second."
msgid_plural "The system will power off automatically in %d seconds." msgid_plural "The system will power off automatically in %d seconds."
msgstr[0] "%d sekundi pärast lülitub süsteem automaatselt välja." msgstr[0] "%d sekundi pärast lülitub süsteem automaatselt välja."
@ -753,6 +779,7 @@ msgctxt "title"
msgid "Restart" msgid "Restart"
msgstr "Taaskäivitamine" msgstr "Taaskäivitamine"
#, javascript-format
msgid "The system will restart automatically in %d second." msgid "The system will restart automatically in %d second."
msgid_plural "The system will restart automatically in %d seconds." msgid_plural "The system will restart automatically in %d seconds."
msgstr[0] "Süsteem taaskäivitub automaatselt %d sekundi pärast." msgstr[0] "Süsteem taaskäivitub automaatselt %d sekundi pärast."
@ -762,6 +789,7 @@ msgctxt "title"
msgid "Restart & Install Updates" msgid "Restart & Install Updates"
msgstr "Taaskäivitamine ja uuenduste paigaldamine" msgstr "Taaskäivitamine ja uuenduste paigaldamine"
#, javascript-format
msgid "The system will automatically restart and install updates in %d second." msgid "The system will automatically restart and install updates in %d second."
msgid_plural "" msgid_plural ""
"The system will automatically restart and install updates in %d seconds." "The system will automatically restart and install updates in %d seconds."
@ -779,16 +807,19 @@ msgid "Other users are logged in."
msgstr "Teised kasutajad on sisse logitud." msgstr "Teised kasutajad on sisse logitud."
#. Translators: Remote here refers to a remote session, like a ssh login */ #. Translators: Remote here refers to a remote session, like a ssh login */
#, javascript-format
msgid "%s (remote)" msgid "%s (remote)"
msgstr "%s (kaugühendus)" msgstr "%s (kaugühendus)"
#. Translators: Console here refers to a tty like a VT console */ #. Translators: Console here refers to a tty like a VT console */
#, javascript-format
msgid "%s (console)" msgid "%s (console)"
msgstr "%s (konsool)" msgstr "%s (konsool)"
msgid "Install" msgid "Install"
msgstr "Paigalda" msgstr "Paigalda"
#, javascript-format
msgid "Download and install '%s' from extensions.gnome.org?" msgid "Download and install '%s' from extensions.gnome.org?"
msgstr "Kas laadida alla ja paigaldada '%s' aadressilt extensions.gnome.org?" msgstr "Kas laadida alla ja paigaldada '%s' aadressilt extensions.gnome.org?"
@ -799,6 +830,7 @@ msgid "No extensions installed"
msgstr "Ühtegi laiendust pole paigaldatud" msgstr "Ühtegi laiendust pole paigaldatud"
#. Translators: argument is an extension UUID. */ #. Translators: argument is an extension UUID. */
#, javascript-format
msgid "%s has not emitted any errors." msgid "%s has not emitted any errors."
msgstr "%s ei ole väljastanud ühtegi veateadet." msgstr "%s ei ole väljastanud ühtegi veateadet."
@ -811,6 +843,8 @@ msgstr "Näita vigu"
msgid "Enabled" msgid "Enabled"
msgstr "Lubatud" msgstr "Lubatud"
#. Translators: this is for a network device that cannot be activated
#. because it's disabled by rfkill (airplane mode) */
#. translators: #. translators:
#. * The device has been disabled #. * The device has been disabled
msgid "Disabled" msgid "Disabled"
@ -837,6 +871,9 @@ msgstr "Ava"
msgid "Remove" msgid "Remove"
msgstr "Eemalda" msgstr "Eemalda"
msgid "Notifications"
msgstr "Märguanded"
msgid "Clear Messages" msgid "Clear Messages"
msgstr "Kustuta teated" msgstr "Kustuta teated"
@ -859,6 +896,7 @@ msgctxt "program"
msgid "Unknown" msgid "Unknown"
msgstr "Tundmatu" msgstr "Tundmatu"
#, javascript-format
msgid "%d new message" msgid "%d new message"
msgid_plural "%d new messages" msgid_plural "%d new messages"
msgstr[0] "%d uus sõnum" msgstr[0] "%d uus sõnum"
@ -902,6 +940,7 @@ msgstr "Sulge"
msgid "%A, %B %d" msgid "%A, %B %d"
msgstr "%A, %d. %B" msgstr "%A, %d. %B"
#, javascript-format
msgid "%d new notification" msgid "%d new notification"
msgid_plural "%d new notifications" msgid_plural "%d new notifications"
msgstr[0] "%d uus märguanne" msgstr[0] "%d uus märguanne"
@ -985,71 +1024,24 @@ msgstr "Lülita välja"
msgid "Bluetooth Settings" msgid "Bluetooth Settings"
msgstr "Bluetoothi sätted" msgstr "Bluetoothi sätted"
#, javascript-format
msgid "%d Connected Device" msgid "%d Connected Device"
msgid_plural "%d Connected Devices" msgid_plural "%d Connected Devices"
msgstr[0] "%d ühendatud seade" msgstr[0] "%d ühendatud seade"
msgstr[1] "%d ühendatud seadet" msgstr[1] "%d ühendatud seadet"
msgid "Authorization request from %s"
msgstr "Autoriseerimise päring seadmelt %s"
msgid "Device %s wants to pair with this computer"
msgstr "Seade '%s' tahab selle arvutiga paarduda"
msgid "Allow"
msgstr "Luba"
msgid "Deny"
msgstr "Keela"
msgid "Device %s wants access to the service '%s'"
msgstr "Seade %s soovib ligipääsu teenusele '%s'"
msgid "Always grant access"
msgstr "Luba alati"
msgid "Grant this time only"
msgstr "Luba ainult seekord"
msgid "Reject"
msgstr "Lükka tagasi"
#. Translators: argument is the device short name */
msgid "Pairing confirmation for %s"
msgstr "Paardumise kinnitus seadmele %s"
msgid ""
"Please confirm whether the Passkey '%06d' matches the one on the device."
msgstr "Palun kontrolli, kas parool '%06d' kattub seadme parooliga."
#. Translators: this is the verb, not the noun */
msgid "Matches"
msgstr "Kattub"
msgid "Does not match"
msgstr "Ei kattu"
msgid "Pairing request for %s"
msgstr "Seadmega %s paardumise päring"
msgid "Please enter the PIN mentioned on the device."
msgstr "Palun sisesta seadme poolt öeldav PIN-kood."
msgid "OK"
msgstr "Olgu"
msgid "Brightness" msgid "Brightness"
msgstr "Heledus" msgstr "Heledus"
msgid "Show Keyboard Layout"
msgstr "Klaviatuuripaigutuse kuvamine"
msgid "<unknown>" msgid "<unknown>"
msgstr "<tundmatu>" msgstr "<tundmatu>"
msgid "Off" msgid "Off"
msgstr "Väljas" msgstr "Väljas"
msgid "Network Settings"
msgstr "Võrgusätted"
#. Translators: this is for network devices that are physically present but are not #. Translators: this is for network devices that are physically present but are not
#. under NetworkManager's control (and thus cannot be used in the menu) */ #. under NetworkManager's control (and thus cannot be used in the menu) */
msgid "unmanaged" msgid "unmanaged"
@ -1078,6 +1070,12 @@ msgstr "pole saadaval"
msgid "connection failed" msgid "connection failed"
msgstr "ühendumine nurjus" msgstr "ühendumine nurjus"
msgid "Mobile Broadband Settings"
msgstr "Mobiiliühenduse sätted"
msgid "Hardware Disabled"
msgstr "Riistvara on keelatud"
msgid "Wi-Fi Networks" msgid "Wi-Fi Networks"
msgstr "Wi-Fi võrgud" msgstr "Wi-Fi võrgud"
@ -1090,9 +1088,15 @@ msgstr "Võrke pole"
msgid "Select Network" msgid "Select Network"
msgstr "Võrgu valimine" msgstr "Võrgu valimine"
msgid "Wi-Fi Settings"
msgstr "Wi-Fi sätted"
msgid "Turn On" msgid "Turn On"
msgstr "Lülita sisse" msgstr "Lülita sisse"
msgid "Not Connected"
msgstr "Pole ühenduses"
msgid "VPN" msgid "VPN"
msgstr "VPN" msgstr "VPN"
@ -1105,9 +1109,6 @@ msgstr "Ühendus nurjus"
msgid "Activation of network connection failed" msgid "Activation of network connection failed"
msgstr "Võrguühenduse aktiveerimine nurjus" msgstr "Võrguühenduse aktiveerimine nurjus"
msgid "Battery"
msgstr "Aku"
msgid "Power Settings" msgid "Power Settings"
msgstr "Toitesätted..." msgstr "Toitesätted..."
@ -1117,18 +1118,29 @@ msgstr "Täiesti täis"
msgid "Estimating…" msgid "Estimating…"
msgstr "Andmete kogumine…" msgstr "Andmete kogumine…"
#, javascript-format
msgid "%d%02d Remaining (%d%%)" msgid "%d%02d Remaining (%d%%)"
msgstr "%d%02d jäänud (%d%%)" msgstr "%d%02d jäänud (%d%%)"
#, javascript-format
msgid "%d%02d Until Full (%d%%)" msgid "%d%02d Until Full (%d%%)"
msgstr "%d%02d täitumiseni (%d%%)" msgstr "%d%02d täitumiseni (%d%%)"
msgid "UPS"
msgstr "UPS"
msgid "Battery"
msgstr "Aku"
msgid "Airplane Mode" msgid "Airplane Mode"
msgstr "Lennukirežiim" msgstr "Lennukirežiim"
msgid "On" msgid "On"
msgstr "Sees" msgstr "Sees"
msgid "Network Settings"
msgstr "Võrgusätted"
msgid "Switch User" msgid "Switch User"
msgstr "Vaheta kasutajat" msgstr "Vaheta kasutajat"
@ -1165,16 +1177,7 @@ msgstr "Rakendused"
msgid "Search" msgid "Search"
msgstr "Otsing" msgstr "Otsing"
msgid "" #, javascript-format
"Sorry, no wisdom for you today:\n"
"%s"
msgstr ""
"Vabandust, tänaseks tarkuseteri pole:\n"
"%s"
msgid "%s the Oracle says"
msgstr "Oraakel %s ütleb"
msgid "'%s' is ready" msgid "'%s' is ready"
msgstr "'%s' on valmis" msgstr "'%s' on valmis"
@ -1190,6 +1193,7 @@ msgstr "Taasta sätted"
msgid "Keep Changes" msgid "Keep Changes"
msgstr "Säilita muudatused" msgstr "Säilita muudatused"
#, javascript-format
msgid "Settings changes will revert in %d second" msgid "Settings changes will revert in %d second"
msgid_plural "Settings changes will revert in %d seconds" msgid_plural "Settings changes will revert in %d seconds"
msgstr[0] "Sätete muudatused ennistatakse %d sekundi pärast" msgstr[0] "Sätete muudatused ennistatakse %d sekundi pärast"
@ -1242,11 +1246,61 @@ msgstr "Parool ei saa olla tühi"
msgid "Authentication dialog was dismissed by the user" msgid "Authentication dialog was dismissed by the user"
msgstr "Kasutaja katkestas autentimisdialoogi" msgstr "Kasutaja katkestas autentimisdialoogi"
#~ msgid "There was an error loading the preferences dialog for %s:" #~ msgid "Authorization request from %s"
#~ msgstr "%s jaoks eelistuste dialoogi laadimisel esines viga:" #~ msgstr "Autoriseerimise päring seadmelt %s"
#~ msgid "Extension" #~ msgid "Device %s wants to pair with this computer"
#~ msgstr "Laiendus" #~ msgstr "Seade '%s' tahab selle arvutiga paarduda"
#~ msgid "Allow"
#~ msgstr "Luba"
#~ msgid "Deny"
#~ msgstr "Keela"
#~ msgid "Device %s wants access to the service '%s'"
#~ msgstr "Seade %s soovib ligipääsu teenusele '%s'"
#~ msgid "Always grant access"
#~ msgstr "Luba alati"
#~ msgid "Grant this time only"
#~ msgstr "Luba ainult seekord"
#~ msgid "Reject"
#~ msgstr "Lükka tagasi"
#~ msgid "Pairing confirmation for %s"
#~ msgstr "Paardumise kinnitus seadmele %s"
#~ msgid ""
#~ "Please confirm whether the Passkey '%06d' matches the one on the device."
#~ msgstr "Palun kontrolli, kas parool '%06d' kattub seadme parooliga."
#~ msgid "Matches"
#~ msgstr "Kattub"
#~ msgid "Does not match"
#~ msgstr "Ei kattu"
#~ msgid "Pairing request for %s"
#~ msgstr "Seadmega %s paardumise päring"
#~ msgid "Please enter the PIN mentioned on the device."
#~ msgstr "Palun sisesta seadme poolt öeldav PIN-kood."
#~ msgid "OK"
#~ msgstr "Olgu"
#~ msgid ""
#~ "Sorry, no wisdom for you today:\n"
#~ "%s"
#~ msgstr ""
#~ "Vabandust, tänaseks tarkuseteri pole:\n"
#~ "%s"
#~ msgid "%s the Oracle says"
#~ msgstr "Oraakel %s ütleb"
#~ msgctxt "event list time" #~ msgctxt "event list time"
#~ msgid "%H\\u2236%M" #~ msgid "%H\\u2236%M"
@ -1256,9 +1310,6 @@ msgstr "Kasutaja katkestas autentimisdialoogi"
#~ msgid "%l\\u2236%M\\u2009%p" #~ msgid "%l\\u2236%M\\u2009%p"
#~ msgstr "%l\\u2236%M\\u2009%p" #~ msgstr "%l\\u2236%M\\u2009%p"
#~ msgid "Show Keyboard Layout"
#~ msgstr "Klaviatuuripaigutuse kuvamine"
#~ msgid "Settings Menu" #~ msgid "Settings Menu"
#~ msgstr "Sätete menüü" #~ msgstr "Sätete menüü"
@ -1400,9 +1451,6 @@ msgstr "Kasutaja katkestas autentimisdialoogi"
#~ msgid "Set Up a New Device…" #~ msgid "Set Up a New Device…"
#~ msgstr "Uue seadme häälestamine…" #~ msgstr "Uue seadme häälestamine…"
#~ msgid "hardware disabled"
#~ msgstr "riistvara on keelatud"
#~ msgid "Connection" #~ msgid "Connection"
#~ msgstr "Ühendus" #~ msgstr "Ühendus"
@ -1439,9 +1487,6 @@ msgstr "Kasutaja katkestas autentimisdialoogi"
#~ msgid "Auto Ethernet" #~ msgid "Auto Ethernet"
#~ msgstr "Automaatne ethernet" #~ msgstr "Automaatne ethernet"
#~ msgid "Mobile broadband"
#~ msgstr "Mobiiliühendus"
#~ msgid "Auto broadband" #~ msgid "Auto broadband"
#~ msgstr "Automaatne lairibaühendus" #~ msgstr "Automaatne lairibaühendus"
@ -1496,9 +1541,6 @@ msgstr "Kasutaja katkestas autentimisdialoogi"
#~ msgid "Laptop Battery" #~ msgid "Laptop Battery"
#~ msgstr "Sülearvuti aku" #~ msgstr "Sülearvuti aku"
#~ msgid "UPS"
#~ msgstr "UPS"
#~ msgid "Monitor" #~ msgid "Monitor"
#~ msgstr "Monitor" #~ msgstr "Monitor"
@ -1539,9 +1581,6 @@ msgstr "Kasutaja katkestas autentimisdialoogi"
#~ msgid "Idle" #~ msgid "Idle"
#~ msgstr "Jõude" #~ msgstr "Jõude"
#~ msgid "Notifications"
#~ msgstr "Märguanded"
#~ msgid "Your chat status will be set to busy" #~ msgid "Your chat status will be set to busy"
#~ msgstr "Sinu vestluse olekuks määratakse hõivatud" #~ msgstr "Sinu vestluse olekuks määratakse hõivatud"

584
po/fi.po

File diff suppressed because it is too large Load Diff

1006
po/gl.po

File diff suppressed because it is too large Load Diff

766
po/he.po

File diff suppressed because it is too large Load Diff

637
po/id.po

File diff suppressed because it is too large Load Diff

818
po/it.po

File diff suppressed because it is too large Load Diff

921
po/kk.po

File diff suppressed because it is too large Load Diff

737
po/lt.po

File diff suppressed because it is too large Load Diff

612
po/nb.po

File diff suppressed because it is too large Load Diff

1230
po/nl.po

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

734
po/ru.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