Compare commits

...

398 Commits

Author SHA1 Message Date
2639e30d9c Bump version to 3.11.2
Update NEWS.
2013-11-13 21:24:30 +01:00
78a0218a91 build: Add built js-resources to CLEANFILES 2013-11-13 21:24:30 +01:00
e12bf8daed shellDBus: Fix error message returned from Eval
Annoyingly, `message` on errors are non-enumerable, which mean that
JSON.stringify on the error will produce `{}`. Just cast it to a string
for now.
2013-11-13 15:15:03 -05:00
04e2072e2c Updated Tamil Translations 2013-11-11 14:45:06 +05:30
7bafe20a34 Update Chinese simplified translation 2013-11-10 14:19:51 +08:00
554d5aeb7c More invalid source fixes
https://bugzilla.gnome.org/show_bug.cgi?id=711732
2013-11-09 17:58:59 +01:00
3991d2729d dash: Make sure we clear the timeout IDs for the label tooltip
https://bugzilla.gnome.org/show_bug.cgi?id=711732
2013-11-09 11:44:44 -05:00
5bc8a0860a tweener: Remove the onAnimationStart/onAnimationComplete callbacks
Our gnome-shell tweener integration has had hooks to determine when
the tweens have started and completed... except that they had a bug
in them. When a tween completed, it queued an idle handler to run
the callback in. If no tweens were running when the idle was removing,
it reset the tween state that contained the idle handler ID. It also
returned false, meaning that the source would always get removed.

If the actor had a tween in-flight when the idle was fired, it wouldn't
clean up after itself. While this is also a simple bug fix, remove the
callback so we don't queue unnecessary, unused idles.

https://bugzilla.gnome.org/show_bug.cgi?id=711732
2013-11-09 11:44:44 -05:00
ad03fb0815 app-system: Add back StartupWMClass matching
While unfortunate that we still have to scan all apps with get_all(),
support for this feature will be short-lived, so hopefully we can drop
it in the future as new apps adapt to the desktop file / app ID
recommendations.

For now, simply scan all desktop IDs.

https://bugzilla.gnome.org/show_bug.cgi?id=711631
2013-11-07 16:35:03 -05:00
e10d2a68f3 app-system: Put back support for the installed-changed signal
Use the new GAppInfoMonitor that Ryan added to glib to know when the
set of apps has changed.

https://bugzilla.gnome.org/show_bug.cgi?id=711631
2013-11-07 16:35:03 -05:00
213ee8d381 ShellApp: Connect applications to systemd journal (if available)
Systemd-for-the-user-session would also do this, but that's a deeply
invasive change that I may not actually get to this cycle.  This
change is tiny and non-invasive, but provides an important benefit:
You can actually reliably tell *which* applications are logging which
messages (assuming they're launched by the shell).

This actually complements a recent change in DBus:
See https://bugs.freedesktop.org/show_bug.cgi?id=68559
which does a similar thing for bus activated apps.

https://bugzilla.gnome.org/show_bug.cgi?id=711626
2013-11-07 13:44:03 -05:00
52b1a1b835 popupMenu: Fix removing the active menu from PopupMenuManager
Commit b42af9aa99 changed the parameter list of _closeMenu()
to account for changes in the GrabHelper ungrab mechanism, but
didn't update other callers.

https://bugzilla.gnome.org/show_bug.cgi?id=709806
2013-11-07 00:09:50 +01:00
fce2930b85 dnd: Don't queue an idle handler if we already have one
Removing an existing source before scheduling a new one is not wrong,
but slightly less effective than doing nothing and relying on the
previously created source to do the job.

https://bugzilla.gnome.org/show_bug.cgi?id=711555
2013-11-06 18:36:42 +01:00
735f589b1c dnd: Don't try to remove an invalid idle source
As the handler returns false, the corresponding source is removed
automatically and its id invalidated. Reset the id to 0 to reflect
this, otherwise newer versions of GLib will print a warning when
we later try to remove it explicitly.

https://bugzilla.gnome.org/show_bug.cgi?id=711555
2013-11-06 16:40:50 +01:00
69f17da5ca trivial: Fix the signedness of boolean fields
The standard old kludge with gboolean being signed, not unsigned.
Encountered while printing the values for debugging.

https://bugzilla.gnome.org/show_bug.cgi?id=644306
2013-11-05 09:11:49 -05:00
5c0ee02251 trivial: st-widget: Remove super old 'stylable' property
I don't think we ever used this, even way back in 3.0...

https://bugzilla.gnome.org/show_bug.cgi?id=644306
2013-11-04 21:11:00 -05:00
0cb4c7e437 Updated German translation 2013-11-04 21:05:26 +01:00
842c792868 search: Only do a subsearch if the previous results have returned from DBus
There's a potential race condition in the search code: if we have an
outstanding search call to a provider for search "A", and if before it comes
back we do a subsearch for "AB", we won't have any results to pass along.

Previously, we used an empty list when storing the provider results, so we
effectively told the remote search app to filter through this empty list for
any search results that meet the new query, meaning we showed the user 0
results for the provider in this case.

Now that we don't store an empty list, but instead store `undefined`, this race
raises a warning. Solve it by doing an initial search query in this case
instead.

The search code isn't too smart about chained subsearches: now, if we hit this
race while already on a subsearch, we'll do an initial search for the subsearch
query instead, but that is much better than showing the user nothing. This
could be fixed in the future for a performance improvement.

Reviewed-by: Florian Müllner <fmuellner@gnome.org>
2013-11-04 14:50:45 -05:00
4ba8518462 messageTray: Use a regular tween when expanding the notification
When a notification becomes expanded, it's either already shown,
or in the process of being shown. Don't set the state to SHOWING
again, which confuses our state machine.
2013-11-04 14:25:29 -05:00
143dfb6246 messageTray: Simplify code
If notificationRemoved, then mustClose is true, so we don't need to
double-check for this.
2013-11-04 14:16:28 -05:00
da4238ec68 Synchronize shell startup
The asynchronous nature of extension loading, session loading, and more,
makes the code racy as to what is initialized first, and hard to debug.
Additionally, since gjs is single-threaded, the only code we're running
in a thread anyway is readdir, which is going to be I/O bound, so the
code here is actually likely to be faster.

Drop this in favor of some good old fashioned synchronous loading.
2013-11-04 11:50:20 -05:00
5f9e3edbe1 notificationDaemon: Only store policies for "real" apps
Fake, window-backed apps should not have a policy for them.
2013-11-04 11:47:43 -05:00
1c68aee577 screenShield: Fix details in notifications
bannerBodyMarkup is a boolean flag to indicate that bannerBodyText
contains markup, not the markup text itself.

https://bugzilla.gnome.org/show_bug.cgi?id=711416
2013-11-04 16:46:25 +01:00
e8d9a4bd49 screencast: Validate parameters of ScreencastArea
... just as we do for screenshots.

https://bugzilla.gnome.org/show_bug.cgi?id=699752
2013-11-04 16:21:45 +01:00
9520e87a38 screencast: Fix disabling screencasts via session mode
If screencasts are disabled, we return a DBus error, but still start
the recording happily - add early returns in that case.

https://bugzilla.gnome.org/show_bug.cgi?id=699752
2013-11-04 16:21:45 +01:00
f9f5004909 screenshot: Extend ScreenshotArea parameter validation
We currently only ensure that width and height are positive, so it
is still possible to pass in values that don't make any sense at all
(which may even result in a crash when exceeding limits imposed by
X11).
There is nothing to screenshot outside the actual screen area, so
restrict the parameters to that.

https://bugzilla.gnome.org/show_bug.cgi?id=699752
2013-11-04 16:21:45 +01:00
4f7014b2d5 networkAgent: Make sure to update the OK button on dialog pop up
For consistency.
2013-11-04 08:55:59 -05:00
01dbfddb64 workspace: Remove unused includes and constants 2013-11-04 10:32:17 +01:00
6266a22d86 Updated Greek translation 2013-11-04 10:53:08 +02:00
09fe31179a app-system: Fix memory leak
The shell app takes a ref on the info.
2013-11-03 16:20:00 -05:00
78343f4837 app-system: Fix bad code
I had this locally, but forgot to amend before pushing apparently
2013-11-03 16:19:53 -05:00
a5619bc0a3 app-system: Fix const warning 2013-11-03 12:50:21 -05:00
dcb28aad2a app-system: Fix the keys in the id_to_app table
The ID that's passed to us isn't usable as a key to store, as it's
probably junk after the method returns. Use the app's storage for
the ID instead.
2013-11-03 12:10:00 -05:00
754cf172f5 Updated Norwegian bokmål translation 2013-11-03 16:03:44 +01:00
7890af1659 app-system: Lazily create ShellApps for apps we care about
Rather than create all ShellApps up-front, create them lazily. We really
had no reason to do this before as we were scanning GMenu to get all the
apps, but doing this can remove a need for get_all, which is slow and
memory-hungry.
2013-11-02 20:50:35 -04:00
d27d9fe694 app-system: Remove use of gnome-menus internally
We want to transition to a system in the future where we have a desktop
file cache. As we no longer differentiate categories or similar, it no
longer makes sense to have app visibility based on categories. Thus,
we no longer need to use gnome-menus to list all apps. The potential
issue here is reloading all desktop files when new files are created,
but this can be dealt with individually.

The "All Applications" view still uses gnome-menus.

https://bugzilla.gnome.org/show_bug.cgi?id=698486
2013-11-02 20:12:37 -04:00
634a599db6 appDisplay: Ignore the NoDisplay flag for directories
This makes us match the native app search.

https://bugzilla.gnome.org/show_bug.cgi?id=698486
2013-11-02 20:12:37 -04:00
5d0d859a1f app-system: Remove visible_id_to_app
Since appDisplay.js makes its own GMenu tree, it's not necessary
anymore. This does mean that searches will show apps in NoDisplay
categories, but that's an obscure enough edge case not to matter.

https://bugzilla.gnome.org/show_bug.cgi?id=698486
2013-11-02 20:12:37 -04:00
40c966fcd6 app-system: Remove lookup_app_for_path
It's absurdly silly. Just modify the one place that uses it
to be better.

https://bugzilla.gnome.org/show_bug.cgi?id=698486
2013-11-02 20:12:37 -04:00
d9245598a4 app-system: Remove known_vendor_prefixes
This does remove support for legacy prefixed app infos with
subdirs, but since we want to remove support for the menu spec,
let's not even bother.

https://bugzilla.gnome.org/show_bug.cgi?id=698486
2013-11-02 20:12:37 -04:00
03b0f4b16b app-system: Remove get_tree
Make clients construct their own gmenu tree if they need it.

https://bugzilla.gnome.org/show_bug.cgi?id=698486
2013-11-02 20:12:37 -04:00
2daa0d057b app-system: Map wmclass to ID rather than apps
This makes the refcounting and memory management easier to understand.
2013-11-02 20:12:36 -04:00
76eca409a3 app-system: Don't use gmenu_tree_entry_get_desktop_app_info
It's a broken method when it comes to giving us a useful GDesktopAppInfo,
and it's hard to fix libgmenu properly, so simply recreate the app info
using the desktop file ID that libgmenu has.
2013-11-02 20:12:36 -04:00
d84b018ba7 app: Port to be based on GDesktopAppInfo
We weren't using the GMenuTreeEntry for anything special anymore,
so remove it.

https://bugzilla.gnome.org/show_bug.cgi?id=698486
2013-11-02 20:12:36 -04:00
027c3d1661 app-system: Remove lookup_app_by_tree_entry
We want to move away from gnome-menus eventually, so the simple
utility method isn't really worth keeping around. Reimplement it
in the one place that uses it.

https://bugzilla.gnome.org/show_bug.cgi?id=698486
2013-11-02 20:12:36 -04:00
4965b1ca7b search: Fix previous commit
It was pushed by accident before it was tested...
2013-11-02 20:11:13 -04:00
9cd7ea9371 search: Make the internal search interface callback-based
Long ago, the search system worked in a synchronous manner: providers
were given a query, and results were collected in a single array of
[provider, results] pairs, and then the search display was updated
from that.

We introduced an asynchronous search system when we wanted to potentially
add a Zeitgeist search provider to the Shell in 3.2. For a while, search
providers were either async or sync, which worked by storing a dummy array
in the results, and adding a method for search providers to add results
later.

Later, we removed the search system entirely and ported the remaining
search providers to simply use the API to modify the empty array, but the
remains of the synchronous search system with its silly array still
lingered.

Finally, it's time to modernize. Promises^WCallbacks are the future.

Port the one remaining in-shell search engine (app search) to the new
callback based system, and simplify the remote search system in the
process.
2013-11-02 20:07:06 -04:00
dc2468b27b remoteSearch: Do filtering here of providers here
We already do ordering at load time, so why not filtering?
2013-11-02 20:07:06 -04:00
ea2451d882 overviewControls: Fix bad expression causing incorrect thumbnails allocation
`a + b ? c : d` is parsed as `(a + b) ? c : d`, not the more intuitive
`a + (b ? c : d)`.

This was causing a bad slide animation and Clutter warnings when coming
out of the overview.
2013-11-02 20:07:06 -04:00
252617bd70 search: Remove unnecessary import and full reference
I'm surprised this worked, actually...
2013-11-02 18:01:26 -04:00
8bd7003ea7 bluetooth: Parse pins starting with 0 correctly
If we have a numeric PIN that starts with 0, it will be treated
as an octal number rather than a number that just starts with 0.
2013-11-02 17:55:54 -04:00
280203158c Updated Russian translation 2013-11-01 23:32:39 +04:00
d456c3f62e system: Restore support for 'disable-restart-buttons'
The org.gnome.login-screen schema contains a key to disable the
power/restart buttons; our support for this fell victim to the
new combined status menu, add it back.

https://bugzilla.gnome.org/show_bug.cgi?id=711244
2013-11-01 13:08:02 +01:00
f64d17963b Support disabling browser plugin
Some downstreams may not want it for security reasons.

https://bugzilla.gnome.org/show_bug.cgi?id=711218
2013-10-31 12:44:51 -04:00
f12378cf7b search: Hide overview when activating result
This was (accidentally?) dropped by commit 3749b09366.

https://bugzilla.gnome.org/show_bug.cgi?id=711205
2013-10-31 16:19:25 +00:00
15ff426be8 shell_global_reexec_self: add support for OpenBSD
https://bugzilla.gnome.org/show_bug.cgi?id=709571
2013-10-31 11:46:59 +01:00
c4a6837d56 build: Make sure built-sources are introspected as needed 2013-10-31 00:01:38 +01:00
e6c28cf509 Revert "overviewControls: Always allocate the actor its full size"
This reverts commit f5a9dbb348.

This broke the alignment of the workspace thumbnail widget. I don't
know why, but let's not break things if we can...
2013-10-30 18:33:13 -04:00
a347a75617 st-theme: Use constructed instead of constructor 2013-10-30 18:33:13 -04:00
7fc2183826 build: Do not ship generated source-files in tarball 2013-10-30 23:29:45 +01:00
b6c3c9891c workspacesView: Make sure to update workspace actors when entering the overview
Otherwise, they will be in the wrong positions.
2013-10-30 18:20:54 -04:00
d401b493a4 search: Fix Return for searching in the overview 2013-10-30 17:43:12 -04:00
da1a8308b6 build: Also look for generated js-resources.* files in builddir 2013-10-30 21:41:52 +01:00
106d827a21 build: Also look for resources in $(builddir)
Since misc/config.js is built, we need to tell the resource compiler
to find it too.

Fixes the build in Continuous where srcdir != builddir.
2013-10-30 14:00:58 -04:00
1ebb162a00 Load JS from GResource
Since gjs can now load JS from a GResource, compile it in the
gnome-shell binary. This should be a bit faster, and make life easier
with JHBuild.
2013-10-30 13:27:16 -04:00
9d2791d9f8 dnd: Don't use reparent for adding actors to the uiGroup
It's deprecated, terrible, and causes get_theme_node crashes.
2013-10-30 13:20:02 -04:00
04a00f6564 loginDialog: Use UserWidget
https://bugzilla.gnome.org/show_bug.cgi?id=706851
2013-10-30 13:19:02 -04:00
a5dd44c77f userWidget: Use the user name if the real name doesn't fit
This meets the new designs.

https://bugzilla.gnome.org/show_bug.cgi?id=706851
2013-10-30 13:19:02 -04:00
8f86fd6bae workspacesView: Simplify the workspacesOnlyOnPrimary implementation
Before, workspacesOnlyOnPrimary was implemented in quite a crazy manner:

 * If workspacesOnlyOnPrimary was false, we'd create one WorkspacesView per
   monitor, with the primary one being a bit special.

 * If workspacesOnlyOnPrimary was true, we'd create one WorkspacesView, and
   additional montiors would be handled inside that WorkspacesView as
   "extra workspaces".

This caused numerous bugs as the two modes weren't consistently
implemented, and a lot of code was duplicated between all the modes.
Fix this by always creating WorkspaceViews, even if it only handles
one interface. We do this by having two different WorkspacesView-ish
classes: WorkspacesView handles the traditional combination of lots
of workspces, and a new ExtraWorkspaceView is in control of only one
workspace.
2013-10-30 13:17:39 -04:00
d5cd534320 workspacesView: Make each WorkspacesView own its set of workspaces
Right now, the workspace update code is complex and spread across parts:
WorkspacesView takes a set of workspaces and looks like it owns them, but
WorkspacesDisplay is actually in charge of setting them up and creating
new ones for each WorkspacesView.

Change initialization and handling to move all of the creation/destruction
responsibilities to WorkspacesView.

We pass in monitorIndex into each WorkspacesView, which is a lie in the
workspacesOnlyOnPrimary case, as the primary WorkspacesView currently has
the responsibility of handling the extra workspaces on all the other
monitors. The commit will clean this up and punt the responsibility back
to WorkspacesDisplay.
2013-10-30 13:17:39 -04:00
a5a6fd3bc2 workspacesView: Don't tween the upper of our scroll adjustment
This really doesn't make sense. The new upper should be the new workspace
index as soon as it's available.
2013-10-30 13:17:39 -04:00
287ddda5df workspacesView: Don't zoom into the overview based on a signal
Instead, simply have somebody else call us, like we do for hiding
the overview as well.
2013-10-30 13:17:39 -04:00
7747f1c31d workspacesView: Don't use a drag monitor to get the clone
Just use the new variable passed to the signal.
2013-10-30 13:17:39 -04:00
8097cbbbe3 workspacesView: Don't do any special handling for item-dragging
The code here really only cares about new windows.
2013-10-30 13:17:39 -04:00
e4c07875a3 overview: Send the clone with the window-drag events
This allows clients that care about the actual item we're dragging to
make smarter decisions without adding a drag monitor themselves.
2013-10-30 13:17:38 -04:00
026fd4cf35 workspace: Punt the geometry-fizzling-out logic here 2013-10-30 13:17:38 -04:00
87016f9620 workspacesView: Remove spacing
It's not used in the theme and it complicates the layout code a bit
too much; in fact, if set, things start breaking.
2013-10-30 13:17:38 -04:00
88393f0f65 overviewControls: Move translation-x to SlideLayout
Not because ClutterActor is bad or wrong, but because I always get
confused on the difference, and having them both in SlideLayout
makes the code a bit easier to read and understand.
2013-10-30 13:16:45 -04:00
f5a9dbb348 overviewControls: Always allocate the actor its full size
This is the new Clutter way -- if the actor wants to adjust its
alignment, it will do it itself with its alignment flags.
2013-10-30 13:16:45 -04:00
dbf3bb112c overviewControls: Make getSlide/updateSlide private 2013-10-30 13:16:45 -04:00
f3186bd501 overviewControls: Make visible and inDrag private
These don't need to be accessed from outside SlidingControl,
so don't let them be.
2013-10-30 13:16:44 -04:00
3f1a252b91 overviewControls: Move slideOut on overview hide to the parent as well 2013-10-30 13:16:44 -04:00
1240d6be76 overviewControls: Remove dead code
The parent SlidingControl had an onOverviewShowing, but we had
overridden it with the same code in both subclasses. Just move it
back to SlidingControl.
2013-10-30 13:16:44 -04:00
faf7b62f5c overviewControls: Mark the DashSlider as x_expand
Actors need to expand in order for them to their x_aligns to be taken
into account.
2013-10-30 13:16:44 -04:00
445011b1e5 overviewControls: Add the parent's box into the allocation
Currently, this is always 0, but this will change when we introduce
a custom layout manager into the story.
2013-10-30 13:16:44 -04:00
e630fec63a search: Fix adding items to icon grids 2013-10-30 13:06:56 -04:00
17421e8a63 iconGrid: Actually throw programmer errors
This way we get a backtrace.
2013-10-30 13:05:20 -04:00
af06b78605 searchDisplay: Cache result display actors
When we create a result actor, cache it, so it can be used for
subsearches of the same initial. For now, to keep memory usage
and the stage graph relatively clean, don't persist the actors
across searches, but maybe we should do this in the future.

This also means that we don't query getResultMetas for items
that we've seen in the same initial search.

https://bugzilla.gnome.org/show_bug.cgi?id=704912
2013-10-30 13:01:20 -04:00
3749b09366 searchDisplay: Make the search result actors stateless, by removing terms
We want to cache result actors between searches, so we shouldn't
instantiate them with search-specific info.

https://bugzilla.gnome.org/show_bug.cgi?id=704912
2013-10-30 13:01:20 -04:00
27cac10d0c appDisplay: Use a proper string key for the app search provider
Since we're going to be caching results based on the result ID,
we need to return a string-based result ID to cache on.

https://bugzilla.gnome.org/show_bug.cgi?id=704912
2013-10-30 13:00:47 -04:00
0590962d36 viewSelector: Move all of the provider-loading logic to SearchSystem
The existing provider system is split between a confusing mess of
RemoteSearch, SearchSystem, SearchDisplay, and ViewSelector, partly
because of the vestigal in-shell search system. Move most of the
logic to search.js so it's easier to read.
2013-10-30 12:59:41 -04:00
c0c20d49a5 search: Always fetch the list of search providers
We fetch and store the list of providers from the search system when we
construct SearchResults, but we never update this list when providers are
changed at runtime, causing various bugs making the search not seem as
snappy as it should be. Make sure to always fetch the list of providers
from the search system.
2013-10-30 12:59:31 -04:00
cf7cf45003 Bump version to 3.11.1
Update NEWS.
2013-10-30 17:04:40 +01:00
633dd0d9de notificationDaemon: Save notifications on source destruction
While the existing comment is correct in that a source's notifications
will be destroyed first, the code takes a shortcut which prevents the
Source::count-updated signal from being emitted. Given that the purpose
of the signal is to keep notification counters up-to-date which is
pointless when the source is about to be destroyed, the shortcut makes
sense; just save notifications explicitly in that case.

https://bugzilla.gnome.org/show_bug.cgi?id=710596
2013-10-30 16:40:33 +01:00
b929320d4c lookingGlass: Remove Memory tab and add a gc Icon to toolbar
With js24 it won't be possible to access gjs memory stats from C code.

https://bugzilla.gnome.org/show_bug.cgi?id=711052
2013-10-30 07:44:34 +11:00
7296bedd8e remove direct access to jsapi
with js24 its not possible to access jsapi directly from C code

https://bugzilla.gnome.org/show_bug.cgi?id=711052
2013-10-30 07:44:34 +11:00
e9fbbf4000 port shell-js to c++
https://bugzilla.gnome.org/show_bug.cgi?id=711052
2013-10-30 07:44:34 +11:00
dd44219aa5 Merge searchDisplay.js and search.js
search.js used to do a lot more, but now that most of the
functionality has been moved to the remote search system,
it doesn't do a lot. Merge searchDisplay.js into it.
2013-10-29 16:02:32 -04:00
8cc1fe007d search: Actually crash when seeing errors from a native search provider
We don't implement many of these, and not catching the error lets us
see stack traces and other such information a lot faster.

https://bugzilla.gnome.org/show_bug.cgi?id=704912
2013-10-29 16:02:32 -04:00
c0b45c9fc4 Remove wanda
It's been broken for quite a bit since we removed Panel.Animation,
and hasn't really ever worked with our new search results. It's also
the only non-remote provider left.

Maybe we'll add it back as a remote provider later, but for now, just
ditch it.
2013-10-29 15:46:49 -04:00
41315f45a9 notificationDaemon: Fix custom icons
The 'icon' property contains a serialized GIcon, so we need to
deserialize it when setting the icon.

https://bugzilla.gnome.org/show_bug.cgi?id=710596
2013-10-28 12:28:37 +01:00
04d28a0eea notificationDaemon: Fix urgency hint
We currently mark notifications as urgent which merely contain the
'urgent' property, even when set to false. Look at the actual value
instead.

https://bugzilla.gnome.org/show_bug.cgi?id=710596
2013-10-28 12:28:37 +01:00
1e9cd3f785 Updated Brazilian Portuguese translation
Fixes "Off" translation
2013-10-27 15:46:38 -02:00
f462dd6a4c Updated Hebrew translation
Maybe DL not updated?
2013-10-27 16:40:28 +02:00
34e75fc595 notificationDaemon: Fix button parameter name
Gio ended up using 'target' rather than 'action-target'.

https://bugzilla.gnome.org/show_bug.cgi?id=710596
2013-10-27 11:38:36 +01:00
dac513e046 notificationDaemon: Unpack button label
deep_unpack() doesn't unpack as deeply as one might hope ...

https://bugzilla.gnome.org/show_bug.cgi?id=710596
2013-10-27 11:38:36 +01:00
2c538d247b catch more errors on extensions enable() and disable()
https://bugzilla.gnome.org/show_bug.cgi?id=688331
2013-10-26 16:35:47 +02:00
f3b7f61e54 AltTabSwitcherPopup: check the number of items after creating the popup child
The popup can be empty if the alt-tab switcher is configured
in workspace-only mode, even if there are applications running.

https://bugzilla.gnome.org/show_bug.cgi?id=710745
2013-10-26 16:29:27 +02:00
d47ecf19f5 need space between item in endsession dialog session-list and app-list
https://bugzilla.gnome.org/show_bug.cgi?id=710543
2013-10-26 16:24:41 +02:00
da19b344b5 RemoteSearch: don't autostart dbus search providers at login
Use the new glib flag that allows us to create the proxy immediately
but only activate the service when making the first call.

https://bugzilla.gnome.org/show_bug.cgi?id=708830
2013-10-26 15:20:52 +02:00
eb66407926 NotificationDaemon: fix more fallout
Missing Gtk import for action-icon buttons.

https://bugzilla.gnome.org/show_bug.cgi?id=710596
2013-10-26 14:56:50 +02:00
61c5b8e7d2 notificationDaemon: Pass the correct id to makeButton()
The function expects the action's ID, not the notification's one.

https://bugzilla.gnome.org/show_bug.cgi?id=710596
2013-10-25 14:15:10 +01:00
4b09d57ec2 Fix fallout from notification changes
Commit 5f081b8f8d moved code without moving a helper function
used.

https://bugzilla.gnome.org/show_bug.cgi?id=710596
2013-10-25 14:15:10 +01:00
a16f699dfc theme: Add some vertical padding on login screen
This was apparently lost during some rewrite this cycle ...

https://bugzilla.gnome.org/show_bug.cgi?id=710555
2013-10-25 14:15:10 +01:00
b908a3d70a Stringify the xml definitions for E4X removal
https://bugzilla.gnome.org/show_bug.cgi?id=691409
2013-10-25 08:57:27 +11:00
d519c7263e Background: Drop "saturation" related source
"saturation" was removed from MetaBackground in mutter with
https://git.gnome.org/browse/mutter/commit/?id=0e589061
2013-10-23 21:37:27 +02:00
5dedc5d8ba shell-app: Remove old unused functionality 2013-10-21 17:49:46 -04:00
3ca1784ff4 notificationDaemon: Fix activating with a target
Targets should not be unpacked, and action IDs should.
2013-10-21 16:50:18 -04:00
b54d512f3f notificationDaemon: Fix loading/saving of notifications 2013-10-21 16:14:14 -04:00
9d8fb19f55 notificationDaemon: Write notifications out to disk
This allows notifications to persist even after reboots and
gnome-shell restarts.

https://bugzilla.gnome.org/show_bug.cgi?id=710137
2013-10-21 14:13:21 -04:00
1ac4ab7edc shell-global: Add new APIs for saving/loading persistent state
https://bugzilla.gnome.org/show_bug.cgi?id=710137
2013-10-21 14:13:21 -04:00
c9b73ac731 shell-global: Handle empty variants better
In cases where we have an array of 0 elements or similar, the
data returned may be NULL. Since g_file_replace_contents will
assert in this case, simply check for this and delete the file
instead.

https://bugzilla.gnome.org/show_bug.cgi?id=710137
2013-10-21 14:13:21 -04:00
e0b87f1e14 notificationDaemon: Implement the new GTK+ notifications API
The new API is designed to support features like persistence and uses
the new org.freedesktop.Application specification for activating
actions on notifications. While we won't add support for persistence
yet, implement the new notification spec with parity of the old one.

https://bugzilla.gnome.org/show_bug.cgi?id=710137
2013-10-21 14:12:47 -04:00
394743efc8 notificationDaemon: Rename the existing implementation to the FdoNotificationSource
We'll add a new, simpler private implementation that's used by the new
GNotification API in gio.

https://bugzilla.gnome.org/show_bug.cgi?id=710137
2013-10-21 12:30:25 -04:00
27a86a4756 notificationDaemon: Move nextNotificationId inside the daemon class
This won't be used by the new notification daemon.

https://bugzilla.gnome.org/show_bug.cgi?id=710137
2013-10-21 12:30:25 -04:00
8ee0ef2cde messageTray: Don't always open the source when clicking on the notification
Some consumers may not always want to open the app, so make clients that
want to do this explicitly connect to the 'clicked' signal.

https://bugzilla.gnome.org/show_bug.cgi?id=710137
2013-10-21 12:30:25 -04:00
43f4682ec4 messageTray: Make addButton/addAction take a callback
This is a much simpler API for consumers to manage.

https://bugzilla.gnome.org/show_bug.cgi?id=710137
2013-10-21 12:30:25 -04:00
5f081b8f8d messageTray: Remove useActionIcons feature
This can be put in the legacy notification daemon with the new
addButtonFull API, to create icon names for actions.

https://bugzilla.gnome.org/show_bug.cgi?id=710137
2013-10-21 12:30:25 -04:00
5023542882 messageTray: Split out addButton to allow consumers to pass a pre-made button
Some consumers may want to construct their buttons specially, so allow them
to do that by adding a new API that takes a button instead of a label.

https://bugzilla.gnome.org/show_bug.cgi?id=710137
2013-10-21 12:30:25 -04:00
88d0731d80 messageTray: Replace setButtonSensitive by simply returning the button
We want to remove 'id's from buttons, and simply returning the button actor
is more powerful anyway.

https://bugzilla.gnome.org/show_bug.cgi?id=710137
2013-10-21 12:30:25 -04:00
06cb8c52d7 Updated Hebrew translation 2013-10-20 19:52:43 +03:00
4d1358b7ed st-widget: Use g_clear_pointer
https://bugzilla.gnome.org/show_bug.cgi?id=710541
2013-10-20 14:25:16 +02:00
0cfa7c1c56 power: Fix undefined variables
A couple of variables that should have been gathered from the proxy
and weren't.
2013-10-19 18:00:08 +02:00
76928390a3 Updated Russian translation 2013-10-18 18:30:12 +04:00
af1f9cd76d network: Don't use StButtons for items in selector
Their use blocks activation of the default button by keyboard, which
is important for accessibility. Use a Clutter.ClickAction instead,
which doesn't have this problem as it only considers mouse events.

https://bugzilla.gnome.org/show_bug.cgi?id=710144
2013-10-17 19:46:30 +02:00
2f39f3d146 Revert "network: being able to use keyboard to connect to a Wireless"
This reverts commit d175a588f7.

https://bugzilla.gnome.org/show_bug.cgi?id=710144
2013-10-17 19:46:29 +02:00
f72f39bc26 messageTray: Only try to focus the summary when summoning the tray by <Super>M
Otherwise, when closing the tray, we'll try to focus an actor, which will
focus the stage window, which will drop the focus from whatever window we
already had focused.

https://bugzilla.gnome.org/show_bug.cgi?id=710347
2013-10-17 13:07:42 -04:00
2659ba6bb4 power: Fix typo
JS ERROR: ReferenceError: this_proxy is not defined
Indicator<._getStatus@/usr/share/gnome-shell/js/ui/status/power.js:66
2013-10-17 18:12:02 +02:00
0b8c0c202e power: Use UPower directly instead of gnome-settings-daemon
UPower master exports a display device that can be used to
compute whether to show a status icon, and what we should show.

https://bugzilla.gnome.org/show_bug.cgi?id=710273
2013-10-17 17:36:27 +02:00
37c8132632 workspace: Adapt to mutter API changes 2013-10-15 15:46:36 -04:00
02f2f694e4 Bump version to 3.10.1
Update NEWS.
2013-10-15 20:27:52 +02:00
d175a588f7 network: being able to use keyboard to connect to a Wireless
https://bugzilla.gnome.org/show_bug.cgi?id=710144
2013-10-15 20:27:05 +02:00
4bb41f2f66 Revert "network: being able to use keyboard to connect to a Wireless"
This reverts commit d581d29198.
2013-10-15 20:14:02 +02:00
088c46c7be Revert "Bump version to 3.10.1"
This reverts commit 4228c40b3d.
2013-10-15 20:14:00 +02:00
4228c40b3d Bump version to 3.10.1
Update NEWS.
2013-10-15 20:06:25 +02:00
d581d29198 network: being able to use keyboard to connect to a Wireless
https://bugzilla.gnome.org/show_bug.cgi?id=710144
2013-10-15 19:10:38 +02:00
5a7e854f9e appDisplay: Remember selected view across sessions
The application picker will always open with the view that was last
selected during the session, but the selection is reset on each
restart. This results in some annoyance for users that use the
ALL view exclusively, as they have to toggle views once each
session - the same would apply to exclusive FREQUENT view users
were the defaults to be changed, so the best solution is to simply
make the selected view persistent by storing it in GSettings.

https://bugzilla.gnome.org/show_bug.cgi?id=710042
2013-10-15 19:06:53 +02:00
6e13823ccc shell-js: fix incorrect G_BEGIN_DECLS in header 2013-10-15 09:21:59 +11:00
5c5f2fdf8f a11y: setting ATK_ROLE_ARROW to object unicodeArrow
https://bugzilla.gnome.org/show_bug.cgi?id=710120
2013-10-14 22:29:09 +02:00
96aa33f4ef messageTray: Don't remove and re-add the focus group on button changes
https://bugzilla.gnome.org/show_bug.cgi?id=710115
2013-10-14 15:24:53 -04:00
25fd23e703 messageTray: Split out the notification's destroy handler
This is complex enough to split out.

https://bugzilla.gnome.org/show_bug.cgi?id=710115
2013-10-14 15:24:53 -04:00
99cf4e5787 messageTray: Only connect to a notification's open/destroy once
If we pushNotification the same notification multiple times, we
won't append it to the array again, but we will attach multiple
handlers needlessly.

https://bugzilla.gnome.org/show_bug.cgi?id=710115
2013-10-14 15:24:53 -04:00
66a4cb5875 messageTray: Move the notification policy classes here
The NotificationDaemon really should be for the hookup of remote
notifications, rather than policies.

https://bugzilla.gnome.org/show_bug.cgi?id=710115
2013-10-14 15:24:53 -04:00
da14e2c349 messageTray: Clean up code that determines if something is clearable
https://bugzilla.gnome.org/show_bug.cgi?id=710115
2013-10-14 15:24:53 -04:00
4cda61a16a gdm: support pre-authenticated logins from oVirt
oVirt is software for managing medium-to-large scale deployments of
virtual machine guests across multiple hosts. It supports a feature
where users can authenticate with a central server and get
transparently connected to a guest system and then automatically get logged
into that guest to an associated user session.

Guests using old versions of GDM support this single-sign-on capability
by means of a greeter plugin, using the old greeter's extension
API.

This commit adds similar support to the gnome-shell based login screen.

How it works:

* The OVirtCredentialsManager singleton listens for

  'org.ovirt.vdsm.Credentials.UserAuthenticated'

  D-Bus signal on the system bus from the

  'org.ovirt.vdsm.Credentials'

  bus name. The service that provides that bus name is called
  the oVirt guest agent. It is also responsible for interacting
  with the the central server to get user credentials.

* This UserAuthenticated signal passes, as a parameter, the a token
  which needs to be passed through to the PAM service that is specifically
  set up to integrate with the oVirt authentication architecture.
  The singleton object keeps the token internally so it can be queried
  later on.

* The OVirtCredentialsManager emits a signal 'user-authenticated' on
  it's object once the dbus signal is triggered

* When the 'user-authenticated' signal is emitted, the login screen
  tells GDM to start user verification using the PAM service. The
  authentication stack of the service includes a PAM module
  provided by oVirt that securely retrieves user credentials
  from the oVirt guest agent. The PAM module then forwards those
  credentials on to other modules in the stack so, e.g.,
  the user's gnome keyring can be automatically unlocked.

* In case of the screen shield being visible, it also will react on that
  'user-authenticated' signal and lift the shield.
  In that case the login screen will check on construction time if
  the signal has already been triggered, and a token is available.
  If a token is available it will immediately trigger the functionality
  as described above.

Signed-off-by: Vinzenz Feenstra <evilissimo@redhat.com>

https://bugzilla.gnome.org/show_bug.cgi?id=702162
2013-10-14 13:54:30 -04:00
002afda503 SearchDisplay: handle certain result IDs specially
Allow the prefix 'special:' applied to result IDs to mark results
that should be always shown, even when they would overflow the
maximum results cap. This will be used by epiphany for the special
"Search the Web" result.

https://bugzilla.gnome.org/show_bug.cgi?id=707055
2013-10-14 18:47:20 +02:00
cb7a2e8c6a shell-global: Use G_VARIANT_TYPE macro for checking 2013-10-14 10:52:45 -04:00
d21ae1dad1 shell-global: Fix an invalid memory botch-up
The value we return is a floating ref, which gjs shouldn't
try to free.

https://bugzilla.gnome.org/show_bug.cgi?id=710104
2013-10-14 09:49:51 -04:00
4548859509 shell-global: Fix a few memory leaks
https://bugzilla.gnome.org/show_bug.cgi?id=710104
2013-10-14 09:49:51 -04:00
09c6e6427a Updated Serbian translation 2013-10-14 10:29:57 +02:00
8c34398a15 Updated Slovenian translation 2013-10-13 23:43:34 +02:00
a65b705080 [l10n] Updated Catalan (Valencian) translation 2013-10-13 22:43:34 +02:00
7e28c71074 [l10n] Update Catalan translation 2013-10-13 22:43:31 +02:00
726f4a6715 Updated Lithuanian translation 2013-10-13 20:06:00 +03:00
a444b43548 Updated Portuguese translation 2013-10-13 12:22:54 +01:00
473bb139d1 Updated Latvian translation 2013-10-13 13:35:18 +03:00
d084770cea NetworkMenu: fix regression for VPN connections
Fix regression from e898e29910,
the code was moved from a method to a global function, but one
call site was not updated.

https://bugzilla.gnome.org/show_bug.cgi?id=710019
2013-10-13 02:11:14 +02:00
619389ed20 NotificationDaemon: fix icons for notifications without an app
NotificationDaemon doesn't pass a gicon to the Notification constructor,
because it calls .update() immediately after, so messageTray.js
calls into Source.createIcon(), which returns null and crashes.
Instead, shortcut the Notification constructor by skipping
.update() completely.

https://bugzilla.gnome.org/show_bug.cgi?id=709998
2013-10-13 01:23:18 +02:00
ad043e009e workspaceThumbnail: Drop the _background hack
The _background hack was added because the old way the zooming animation
worked, it set the allocation of the workspaces view and thumbnails box
to the final position and used animations to smoothly animate.

During the 3.6 cycle when we added the new search view, Cosimo changed the
way the zoom animation works so that rather than set the final allocation
and animate, we actually do adjust the allocation of the workspaces view
and thumbnails box.

So, as the hack is no longer necessary, we can drop it.

https://bugzilla.gnome.org/show_bug.cgi?id=694881
2013-10-12 14:38:13 -04:00
89b9d079b1 overviewControls: Don't use the child's preferred size to slide from
In order for the workspace thumbnails box to have the correct size,
we need to constrain the width of the thumbnails box to the height we're
given, instead of assuming an unlimited height.

https://bugzilla.gnome.org/show_bug.cgi?id=694881
2013-10-12 14:38:13 -04:00
58a8845047 overviewControls: Don't try to align something sliding to the right
0 is already the correct value.

https://bugzilla.gnome.org/show_bug.cgi?id=694881
2013-10-12 14:38:13 -04:00
3e6c8e68b4 overviewControls: Clarify some code with a comment
translationX is sort of a bad name, since it confuses with the
actor's translation, which is used for sliding without allocation.

https://bugzilla.gnome.org/show_bug.cgi?id=694881
2013-10-12 14:38:13 -04:00
40cd92f701 overviewControls: Correct the use of x2 in SlidingControl
The x2 here needs to be more than just the width; it needs to
be added onto the x1.

https://bugzilla.gnome.org/show_bug.cgi?id=694881
2013-10-12 14:38:13 -04:00
e216addf7c Updated Dutch translation 2013-10-12 19:59:34 +02:00
9291594330 app-system: remove outdated comment
This parameter was removed before 3.2 but the comment stuck around.
2013-10-12 10:09:36 -05:00
f6010864ea layout: Flush region update in showOverview
We cannot wait for the queued update region to fire when
xdnd is being used because a wrong input shape can result
into a xdnd leave event when the user moves the pointer fast.

https://bugzilla.gnome.org/show_bug.cgi?id=708887
2013-10-11 20:16:44 +02:00
13e6a6def5 Revert "overview: Ignore dragEnd while the animation is still in progress"
This reverts commit 80a3bb85aa.

https://bugzilla.gnome.org/show_bug.cgi?id=708887
2013-10-11 20:16:44 +02:00
575b373cd5 power: Use the icon from the primary device for status
https://bugzilla.gnome.org/show_bug.cgi?id=709925
2013-10-11 13:37:10 -04:00
0892065649 notificationDaemon: Raise the app when clicking on a notification, not the MRU window
https://bugzilla.gnome.org/show_bug.cgi?id=709866
2013-10-11 13:37:10 -04:00
766ef367fb notificationDaemon: Fix the fallback for image-data
The indentation here is wrong, the else actually belongs to the outer
if statement, not the inner if statement.
2013-10-11 13:37:10 -04:00
0c7d9958f5 notificationDaemon: Remove dead code 2013-10-11 13:37:09 -04:00
425b8f6073 Updated Czech translation 2013-10-11 18:28:52 +02:00
63593e45a6 Make dropdown arrows consistent size
Since the agregate menu does 120% of font-size, make this
for all dropdown arrows in gnome-shell and rename the css
class to make clear that it is used in overall gnome-shell

https://bugzilla.gnome.org/show_bug.cgi?id=709564
2013-10-11 17:32:55 +02:00
a6ee9806de Uploaded Ukranian 2013-10-11 15:02:28 +03:00
a6579f4ceb Updated Brazilian Portuguese translation 2013-10-11 07:24:18 -03:00
639622a4fe [l10n] Updated Italian translation. 2013-10-11 09:41:24 +02:00
e28ec2f5ab Updated Indonesian translation 2013-10-11 10:15:14 +07:00
873753c735 Updated Hebrew translation 2013-10-11 01:14:45 +03:00
ff14951be4 Updated Hebrew translation 2013-10-11 01:11:25 +03:00
b47b445558 Updated Polish translation 2013-10-10 23:43:39 +02:00
6e9a2fea89 messageTray: Add 'Notifications' switch to tray menu
According to the designs, the notifications switch was supposed
to move from the user menu to the new message tray menu. However
so far the new system status implementation only removed the old
switch, so add it back in its new place now.

https://bugzilla.gnome.org/show_bug.cgi?id=707073
2013-10-10 23:13:47 +02:00
64d2679b3c Updated Czech translation 2013-10-10 21:09:42 +02:00
3c3d4dfccb Updated Hungarian translation 2013-10-10 13:43:23 +02:00
0ccffed517 Updated Spanish translation 2013-10-10 10:49:53 +02:00
20c18c1fc0 Suppress animation for titles in overview
Because of the animation and collision with relayout, the title of windows in overview may not appear, mainly
the first time we enter in overview

With an animation delay of 0.1s, you'll not see the difference

https://bugzilla.gnome.org/show_bug.cgi?id=709392
2013-10-10 08:51:13 +02:00
a21c0097c2 Tajik translation updated 2013-10-10 11:48:03 +05:00
404d9ef2af [l10n] Updated Italian translation. 2013-10-10 08:37:21 +02:00
503fa1cbce Updated Indonesian translation 2013-10-10 12:59:23 +07:00
63f7991d0f Updated Brazilian Portuguese translation 2013-10-09 23:26:40 -03:00
ae301c1f39 Updated Galician translations 2013-10-09 23:09:57 +02:00
8e911fb719 Updated Galician translations 2013-10-09 23:04:21 +02:00
a0d84e44c5 L10N: Updated Persian translations 2013-10-10 00:28:17 +03:30
81fb7ebb31 Fix some broken GTK-Doc comment blocks 2013-10-09 20:14:57 +02:00
3751211590 shell-global: Fix introspection issues
Remove stray bullet points, and don't actually mark for introspection
since it's private anyway (it starts with a _)
2013-10-09 13:31:00 -04:00
6b4cba09be Updated Polish translation 2013-10-09 19:04:21 +02:00
6a7d184b7b NetworkMenu: make the settings launcher point to the right devices
Tell gnome-control-center to focus on the associated device when
launching it from one of the submenus.

https://bugzilla.gnome.org/show_bug.cgi?id=709246
2013-10-09 18:39:44 +02:00
bde5cfc8bb NetworkMenu/NMDeviceModem: use the operator name when we have it
Instead of the connection name, as the operator name is usually
shorter and more useful.

https://bugzilla.gnome.org/show_bug.cgi?id=709043
2013-10-09 18:39:44 +02:00
777c7a952b NetworkMenu/NMDeviceModem: fix status texts for airplane mode
Show "Hardware Disabled" when disabled by HW switch, and
generically "Disabled" when airplane mode is active, as
indicated by v4 mockups.
Note that bluetooth is not affected by NM handling of airplane
mode (and generally the firmware makes the USB bluetooth
adapter disappear when rfkilled), so this is in NMDeviceModem
instead of NMConnectionDevice.

https://bugzilla.gnome.org/show_bug.cgi?id=709043
2013-10-09 18:39:44 +02:00
c79bdd9029 NetworkMenu/NMConnectionDevice: fix status text
Be consistent with v4 mockups

https://bugzilla.gnome.org/show_bug.cgi?id=709043
2013-10-09 18:39:44 +02:00
6a154efe65 Network: show Not Connected instead of Off when wifi radio is on
When wifi is powered but not connected, show Not Connected instead
of off. This avoids a Off status next to a Turn Off menu item.

https://bugzilla.gnome.org/show_bug.cgi?id=709043
2013-10-09 18:39:44 +02:00
627f3ef36b keyring: Cancel active prompts on disable()
Since commit 1242a16265, we will use a fake prompt which
cancels alls requests without dialog when the keyring component
is disabled. However this does only apply to new requests, dialogs
that are already active when the session mode changes are kept
open. This is not quite as expected, so cancel the prompt in that
case.

https://bugzilla.gnome.org/show_bug.cgi?id=708910
2013-10-09 17:58:37 +02:00
3d28836f2c keyring: Remove unused global
https://bugzilla.gnome.org/show_bug.cgi?id=708910
2013-10-09 17:58:37 +02:00
c28bd04958 Finnish translation update 2013-10-09 14:23:48 +03:00
a6fb3acb42 NetworkMenu: hide the "Turn On" item when the rfkill is hardware blocked
If wifi is disabled in hardware, there is nothing we can do at
the sw level, so hide the menu item.

https://bugzilla.gnome.org/show_bug.cgi?id=709635
2013-10-08 22:20:27 +02:00
8a8b3bf96e NetworkMenu: fix wireless-enabled property notifications
The property is on the NMClient, not NMDevice. Also, make sure
we disconnect the signal when the item is destroyed.
Also, connect to wireless-hardware-enabled, which we'll use soon.

https://bugzilla.gnome.org/show_bug.cgi?id=709635
2013-10-08 22:20:27 +02:00
f7624e5f05 network: make the icon visible again when going from ethernet to nothing
https://bugzilla.gnome.org/show_bug.cgi?id=709638
2013-10-08 14:26:38 -04:00
55edfd2e4a notificationDaemon: Focus the new window before destroying the notification
Destroying the notification will make the key focus be reset to NULL, which
means that gnome-shell will try to focus the MRU window, thinking the user is
done interacting and wants to go back to whatever they were doing.

Unfortunately, since we focus two windows at the same time, they will have
the same timestamp, meaning that the window that actually gets focused will
be a race as to whoever responds to their WM_TAKE_FOCUS event last.

If we explicitly set the focus beforehand, then gnome-shell will believe it
got key focus taken away from it, and won't try to focus the MRU when the
key focus drops to NULL.

https://bugzilla.gnome.org/show_bug.cgi?id=703265
2013-10-08 13:05:34 -04:00
91878dd52c Updated Indonesian translation 2013-10-08 17:07:23 +07:00
c132358ec9 Updated Latvian translation 2013-10-07 21:54:39 +03:00
e426f8ac47 BoxPointer: account for border width when requesting size
We must reduce the forWidth in the call to get_preferred_height()
with the border width, otherwise we might request a smaller height
that we actually need and overflow.

https://bugzilla.gnome.org/show_bug.cgi?id=696564
2013-10-07 20:18:48 +02:00
740dca8afc build: Bump gjs requirement
https://bugzilla.gnome.org/show_bug.cgi?id=709543
2013-10-07 09:37:59 +02:00
6ae06d319c [l10n] Updated Catalan (Valencian) translation 2013-10-06 21:58:43 +02:00
30bc2b2f9c [l10n] Update Catalan translation 2013-10-06 21:06:39 +02:00
7dc8e9d657 Updated Russian translation 2013-10-06 12:31:47 +04:00
1ab2fa5bf0 [l10n]Updated Turkish translation 2013-10-06 09:19:37 +03:00
779a1077bf Updated Serbian translation 2013-10-05 20:59:51 +02:00
815bf7a53a L10N: Updated Persian translations 2013-10-05 18:06:59 +03:30
91a382dfb5 Fix Lithuanian calendar translation 2013-10-05 16:51:19 +03:00
2d8d4cd57d Updated Serbian translation 2013-10-05 06:49:07 +02:00
0c5fe2b3bf Updated Serbian translation 2013-10-05 06:08:07 +02:00
56c487347f Updated Belarusian translation. 2013-10-03 23:02:05 +03:00
0a572fce1b Updated Norwegian bokmål translation 2013-10-03 20:38:08 +02:00
e898e29910 NetworkMenu/NMConnectionDevice: grab the connection before using it
If the active connection for the device is not the primary or
activating globally, it won't have the _connection and _primaryDevice
expando properties, so grab them from the settings object.

https://bugzilla.gnome.org/show_bug.cgi?id=709043
2013-10-03 16:03:41 +02:00
843f076225 NetworkMenu/NMDeviceWireless: use the device state instead of active connection state
Since we connect to signals for that, we need to sync on that, or
we can miss a notification.

https://bugzilla.gnome.org/show_bug.cgi?id=709043
2013-10-03 16:01:27 +02:00
fdb732c8c2 Bluetooth: fix ngettext call
https://bugzilla.gnome.org/show_bug.cgi?id=709043
2013-10-03 16:01:27 +02:00
33896a4e8f network: fix NMConnectionSection destruction
The patch fixes the following warning, and along with it, the proper
destruction of the NMConnectionSection is performed so that items get
correctly removed from the menu.

(gnome-shell:24528): Gjs-WARNING **: JS ERROR: TypeError:
this.statusItem is undefined
NMConnectionSection<.destroy@/home/aleksander/gnome/install/share/gnome-shell/js/ui/status/network.js:173
wrapper@/home/aleksander/gnome/install/share/gjs-1.0/lang.js:213
_parent@/home/aleksander/gnome/install/share/gjs-1.0/lang.js:175
NMConnectionDevice<.destroy@/home/aleksander/gnome/install/share/gnome-shell/js/ui/status/network.js:292
wrapper@/home/aleksander/gnome/install/share/gjs-1.0/lang.js:213
_parent@/home/aleksander/gnome/install/share/gjs-1.0/lang.js:175
NMDeviceModem<.destroy@/home/aleksander/gnome/install/share/gnome-shell/js/ui/status/network.js:448
wrapper@/home/aleksander/gnome/install/share/gjs-1.0/lang.js:213
NMApplet<._removeDeviceWrapper@/home/aleksander/gnome/install/share/gnome-shell/js/ui/status/network.js:1421
wrapper@/home/aleksander/gnome/install/share/gjs-1.0/lang.js:213
NMApplet<._deviceRemoved@/home/aleksander/gnome/install/share/gnome-shell/js/ui/status/network.js:1416
wrapper@/home/aleksander/gnome/install/share/gjs-1.0/lang.js:213

https://bugzilla.gnome.org/show_bug.cgi?id=709248
2013-10-03 00:50:02 +02:00
51e016a0d6 theme: modify the avatar and user name
Change the avatar and user name border radius, padding
and text size to be consistent with mockups.

https://bugzilla.gnome.org/show_bug.cgi?id=702309
2013-10-02 22:26:30 +02:00
8737b06559 loginDialog: MessageType is now in GdmUtil
https://bugzilla.gnome.org/show_bug.cgi?id=709286
2013-10-02 13:58:09 -04:00
15ab285174 layout: Use monitor index when adding bg managers
Don't assume that this._bgManagers.push() (i.e adding to the end) is always
correct.

On startup we call _createPrimaryBackground which passes in the primary index
which may not be 0.
2013-10-02 15:58:22 +02:00
3a4782cc64 app-system: Fix some enum warnings
https://bugzilla.gnome.org/show_bug.cgi?id=698486
2013-10-02 09:49:03 -04:00
0256a6d47b app: Use g_variant_lookup instead of dict iteration 2013-10-02 09:49:02 -04:00
8b0e846e0e background: Disconnect settings signal handler on destroy
We connect to the changed signal in _init() but never actually disconnect from
it. The callback has a reference to "this" which results into the background
object not getting garbage collected.

Fix that leaks by disconnecting in _destroy()

https://bugzilla.gnome.org/show_bug.cgi?id=709263
2013-10-02 15:43:30 +02:00
41acb5d3cc Updated Czech translation 2013-10-02 09:56:45 +02:00
a2f9b8ea9b workspacesView: Remove dead code 2013-10-01 18:41:26 -04:00
6237a1c505 workspace: Remove unused leftover constant
from the window zooming days
2013-10-01 18:41:26 -04:00
7c08db0b0f [l10n] Updated Italian translation. 2013-10-01 19:22:11 +02:00
df1270ac49 Updated Danish translation 2013-10-01 19:10:05 +02:00
46edc053d4 overview: Add cover pane directly to overviewGroup
The cover pane is used to block events during transitions, but as
workspaces don't share the same container as other overview elements,
they are currently excempt from the event blocking.
Move the cover pane to the top-level overview container instead.

https://bugzilla.gnome.org/show_bug.cgi?id=709034
2013-10-01 17:16:51 +02:00
908046c31a [l10n] Updated Estonian translation 2013-10-01 17:14:01 +03:00
8380c79875 network: Update the network indicator when the VPN state changes 2013-10-01 10:25:46 -04:00
8a4879a96a Updated Traditional Chinese translation(Hong Kong and Taiwan) 2013-09-30 19:40:48 +08:00
cdf1a77f08 Updated Spanish translation 2013-09-30 12:00:58 +02:00
3f9857ccbd Assamese translation updated 2013-09-30 13:32:07 +05:30
1d65a31420 Updated Lithuanian translation 2013-09-29 20:33:17 +03:00
dafdf0838a Updated Slovak translation 2013-09-29 17:41:47 +01:00
f9cf135f68 update Punjabi Translaiton 2013-09-29 05:26:34 -05:00
a1878e54c9 Updated Norwegian bokmål translation 2013-09-29 11:29:08 +02:00
95e5d899a9 Updated Basque language 2013-09-29 10:53:34 +02:00
ee8321df67 Updated Slovenian translation 2013-09-28 21:49:04 +02:00
4918213e68 Tajik translation updated 2013-09-28 19:39:12 +05:00
ed7f349fc6 Updated Galician translations 2013-09-28 16:25:15 +02:00
2888f22a24 Updated Norwegian bokmål translation 2013-09-28 14:53:19 +02:00
fcb217f681 Updated Brazilian Portuguese translation 2013-09-28 05:16:53 -03:00
9ffa9fe1a8 Updated Galician translations 2013-09-27 21:38:08 +02:00
905020c507 Updated Slovak translation 2013-09-27 17:40:35 +01:00
02f5500641 theme: Make indicators checked&active like checked 2013-09-27 17:06:26 +02:00
465af55d6e theme: Add hover/active states to indicators
Until now we had the same svg for hover, active and checked
states in the pagination indicators. Just differentiate between
them using differents svg.

svg files provided by Jakub Steiner

https://bugzilla.gnome.org/show_bug.cgi?id=708852
2013-09-27 15:50:28 +02:00
80a3bb85aa overview: Ignore dragEnd while the animation is still in progress
Moving the mouse fast enough during xdnd will trigger a xdnd-leave event
because the input shape is not updated until after the animation is done.

So simply ignore the leave events while the animation is in progress.

https://bugzilla.gnome.org/show_bug.cgi?id=708887
2013-09-27 12:54:22 +02:00
ea26bd3003 Updated Latvian translation 2013-09-26 23:30:59 +03:00
508a511d2a Revert "overviewControls: Don't allow appearing controls to "pop in""
This reverts commit e31693bbee.

This doesn't properly adjust the allocation, leading to an unbalanced
overview where things aren't centered properly. Just revert for now,
and we'll rethink this next cycle.
2013-09-26 16:20:06 -04:00
2d80cb71db searchDisplay: Scroll results when the user focuses a provider icon
Otherwise, it seems odd to highlight results the user can't see
simply by pressing down a lot.

https://bugzilla.gnome.org/show_bug.cgi?id=708868
2013-09-26 15:17:29 -04:00
e31693bbee overviewControls: Don't allow appearing controls to "pop in"
When coming back from search or apps, the workspace thumbnails and dash
don't slide in but "pop in". This is because of bad timing: when slideIn
is called, we immediately start the translation animation, and it
completes before by the time we fade the new page in.

Fix this by calling slideIn and slideOut at two different times: we now
slide out when the old page with our controls is fading out, and slide in
when the new page with our controls is fading in.

https://bugzilla.gnome.org/show_bug.cgi?id=708340
2013-09-26 13:39:20 -04:00
fb561f10a7 network: Make sure to set the signal icon at dialog item construction time
We forgot to set it here; it would be updated if there was changes in the
signal, but not when it was created.

https://bugzilla.gnome.org/show_bug.cgi?id=708442
2013-09-26 11:06:42 -04:00
0c57d53e03 Update Esperanto translation 2013-09-26 09:09:37 -04:00
3b1b9f589b SystemMenu: wait for a completed paint before switching VT
Activating the GDM login screen switches VT and causes X to freeze
event processing (because it lost the drm master), so must make
sure to have painted the lock screen at least once before proceeding,
or the user can go back and see the unlocked desktop.

https://bugzilla.gnome.org/show_bug.cgi?id=708051
2013-09-26 10:46:42 +02:00
ac8d39acf4 Updated Lithuanian translation 2013-09-25 23:22:27 +03:00
664e795217 [l10n]Updated Turkish translation 2013-09-25 21:16:28 +03:00
82bf323f63 Updated German translation 2013-09-25 15:25:31 +02:00
547ac85113 Updated Basque language 2013-09-25 11:17:01 +02:00
46e0e4430d Bump version to 3.10.0.1
Update NEWS.
2013-09-24 16:04:57 -04:00
609a31ea46 loginManager: fix versionCompare function
It's important to compare the version components as integers,
not strings, so "10" evaulates as greater than "5"

This fixes the login screen in gnome 3.10.

https://bugzilla.gnome.org/show_bug.cgi?id=708691
2013-09-24 14:22:09 -04:00
3e99eb10d1 Updated Norwegian bokmål translation 2013-09-24 19:38:41 +02:00
b9d935af0c ActivitiesButton: close the dummy menu when activating the button
We need to close the menu to make sure that any grabs held by
the PopupMenuManager are released, and events are properly delivered.

https://bugzilla.gnome.org/show_bug.cgi?id=707852
2013-09-24 16:28:31 +02:00
31d3e82aa8 Updated Czech translation 2013-09-24 16:10:40 +02:00
dfdc17197b Punjabi Translation updated by Aman 2013-09-24 07:54:25 -05:00
62b965b4b7 Updated Spanish translation 2013-09-24 14:39:14 +02:00
ba221abea5 Updated Belarusian translation. 2013-09-24 15:03:09 +03:00
aa026c7134 Updated Traditional Chinese translation(Hong Kong and Taiwan) 2013-09-24 19:13:45 +08:00
496cfff97a Assamese translation updated 2013-09-24 14:25:28 +05:30
ccaa7f5f3e Updated Russian translation 2013-09-24 12:18:45 +04:00
f492d21c70 Update Kazakh translation 2013-09-24 06:37:02 +06:00
1983541f8c Bump version to 3.10.0
Update NEWS.
2013-09-23 23:33:14 +02:00
e4cb3672b9 Updated Galician translations 2013-09-23 22:24:36 +02:00
a06a78a9c1 aggregate-menu: Increase width
Add 20px more width to make longer strings (translations) fit better.

https://bugzilla.gnome.org/show_bug.cgi?id=708472
2013-09-23 22:23:46 +02:00
2ba91ad837 Updated Slovenian translation 2013-09-23 21:18:03 +02:00
66eb3ea723 Updated Polish translation 2013-09-23 20:38:24 +02:00
d30e992b20 Updated Polish translation 2013-09-23 20:35:58 +02:00
c6a342563f Updated Danish translation 2013-09-23 19:43:15 +02:00
fd584eda05 l10n: Update Japanese translation 2013-09-24 00:01:51 +09:00
4301506590 Updated Hebrew translation
Signed-off-by: Yosef Or Boczko <yoseforb@gmail.com>
2013-09-23 17:59:51 +03:00
88f7c3a970 Updated Indonesian translation 2013-09-23 21:25:49 +07:00
f21a9f0cc2 [l10n] Updated Italian translation. 2013-09-23 16:21:33 +02:00
2233c2e618 Updated Brazilian Portuguese translation 2013-09-23 10:56:43 -03:00
6264419bd4 Update French translation 2013-09-23 15:48:18 +02:00
b62effb8fa add missing translation markers around string in schema 2013-09-23 15:35:06 +02:00
c8a07dd612 messageTray: Fix condition for adding the tray to CtrlAltTab
With the current condition, we wrongly add the message tray to
CtrlAltTab if we start up locked or as greeter.

https://bugzilla.gnome.org/show_bug.cgi?id=708380
2013-09-23 13:32:17 +02:00
02c99e4b25 authPrompt: Clear _queryingService on verification failure
A conversation is finished after failing, and we are expecting a new
one to be started shortly after. However if we encounter an existing
reference to a previously set _queryingService, we will clear the
password entry, which might already contain a partially typed password
at that point. The behavior does make sense in the case of conflicting
conversations, but in the failure case it is both unexpected and
annoying, so clear _queryingService early to prevent this.

https://bugzilla.gnome.org/show_bug.cgi?id=708186
2013-09-23 13:32:17 +02:00
1242a16265 keyring: Don't unregister the prompt when disabled
gnome-keyring provides a fallback in case our builtin prompt fails
to register, so keyring dialogs may still pop up even when they
are supposed to be disabled.
Instead, keep the prompt registered but cancel requests immediately
while disabled.

https://bugzilla.gnome.org/show_bug.cgi?id=708187
2013-09-23 13:32:17 +02:00
a89fd17b8e shell: Make KeyringPrompt.cancel() callable from signal handlers
gcr/gnome-keyring don't handle the case where prompt_password_async()/
prompt_confirm_async() return their result from within the function
very well (or rather: break badly). Calling gcr_prompt_close() instead
is safe, but to avoid these kind of errors in the future, modify
shell_keyring_prompt_cancel() to work as expected in this case.

https://bugzilla.gnome.org/show_bug.cgi?id=708187
2013-09-23 13:32:17 +02:00
3d5e7bd6f1 Updated Indonesian translation 2013-09-23 09:40:56 +07:00
cefcb89487 Updated Portuguese translation 2013-09-22 23:50:24 +01:00
005272bde9 bluetooth: Actually add the menu item to the bluetooth menu
https://bugzilla.gnome.org/show_bug.cgi?id=708541
2013-09-22 22:22:49 +02:00
491e60e4f2 Updated Galician translations 2013-09-22 19:49:52 +02:00
e5f72fd302 Updated Hebrew translation 2013-09-22 13:58:19 +03:00
5f21b100b8 Updated Ukrainian 2013-09-22 11:28:53 +03:00
1a4c7629c5 Translate 'suspend' as 'pauzestand' for consistency 2013-09-21 23:27:43 +02:00
d21734ee47 Updated Dutch translation 2013-09-21 23:04:37 +02:00
e140e2c367 Updated Latvian translatio 2013-09-21 21:53:36 +03:00
7ced1f5b54 focusCaretTracker: Lower AT-SPI's timeout values
Have AT-SPI calls time out after 250ms, to mitigate the effect of a
deadlock when querying another application that is trying to query
gnome-shell.

https://bugzilla.gnome.org/show_bug.cgi?id=708387
2013-09-21 04:51:42 -05:00
54b028ee3e Updated Ukrainian 2013-09-21 11:42:12 +03:00
703336e1ea Updated Esperanto translation 2013-09-21 09:54:37 +02:00
9e936252ae Updated Polish translation 2013-09-20 17:44:36 +02:00
fc71a0f081 Updated Polish translation 2013-09-20 17:29:48 +02:00
86c72fa15d Updated Traditional Chinese translation(Hong Kong and Taiwan) 2013-09-20 13:43:49 +08:00
6ba5af1e9e Updated Romanian Translation 2013-09-19 21:54:35 +02:00
33a4f59cfb popupMenu: Center the labels in submenu items
https://bugzilla.gnome.org/show_bug.cgi?id=708330
2013-09-19 12:40:43 -04:00
39134f0d9b networkAgent: Don't allow ellipsization of Password label
We don't want password entries to grow when entering more characters
that fit the available width; as labels' ClutterText ellipsizes by
default, the password labels allow entries to grow by shrinking.
Setting the appropriate ellipsize mode fixes this.

https://bugzilla.gnome.org/show_bug.cgi?id=708324
2013-09-19 07:53:57 +02:00
30e7440851 keyring: Don't allow ellipsization of Password label
We don't want the password entry to grow when entering more characters
that fit the available width; as labels' ClutterText ellipsizes by
default, the password label allows the entry to grow by shrinking.
Setting the appropriate ellipsize mode fixes this.

https://bugzilla.gnome.org/show_bug.cgi?id=708324
2013-09-19 07:53:57 +02:00
be1a7bac7c networkAgent: Port to ClutterTableLayout
We don't make use of any functionality StTable provides over
ClutterTableLayout, so port all users to the Clutter layout
in order to remove our own copy of the code.

https://bugzilla.gnome.org/show_bug.cgi?id=703833
2013-09-19 07:53:57 +02:00
fb52a93a28 keyring: Port to ClutterTableLayout
We don't make use of any functionality StTable provides over
ClutterTableLayout, so port all users to the Clutter layout
in order to remove our own copy of the code.

https://bugzilla.gnome.org/show_bug.cgi?id=703833
2013-09-19 07:53:56 +02:00
efdf1ff755 main: Close runDialog as necessary on session mode changes
We already do this for looking glass, but it makes even less sense
for the normal run dialog - if a mode sets runDialog to false, the
intention is to not allow executing aribitrary commands.

https://bugzilla.gnome.org/show_bug.cgi?id=708218
2013-09-19 07:53:56 +02:00
2c00dad211 network: Make sure to resync when the activating connection changes
Otherwise, we may be left with a stale activating connection if a
connection is activating, but doesn't fully activate for whatever
reason.

https://bugzilla.gnome.org/show_bug.cgi?id=708322
2013-09-18 17:15:01 -04:00
c23786c73e St: Fix fade effect
Commit 4095a58eb9 introduced a
regression, since we have to take into account four cases,
top, bottom, right, and left, and that can't be merged into
two like that commit did.
So fix it to make fade effect works again.

https://bugzilla.gnome.org/show_bug.cgi?id=708256
2013-09-18 20:01:49 +02:00
7f1b07b76f Revert "Background: Drop "saturation" related source"
This reverts commit 2f35ad6e65.
2013-09-18 13:54:54 +02:00
2f35ad6e65 Background: Drop "saturation" related source
"saturation" was removed from MetaBackground in mutter with
https://git.gnome.org/browse/mutter/commit/?id=0e589061
2013-09-18 13:49:35 +02:00
159c7d34c7 l10n: Update Japanese translation 2013-09-18 20:41:47 +09:00
fe8e990ed7 Punjabi Translation updated by Aman 2013-09-17 22:08:46 -05:00
1fb9b18cb6 Updated Belarusian translation. 2013-09-17 22:46:22 +03:00
5c2586127b Update gvc
A translator accidentally undid this.
2013-09-17 11:54:44 -04:00
661b266b45 Updated Esperanto translation
Reviewed by Ken Price
2013-09-17 10:11:50 -04:00
98af044196 Updated Romanian Translation 2013-09-17 09:55:18 +02:00
8006c336f5 Bump version to 3.9.92
Update NEWS.
2013-09-16 23:59:39 +02:00
bdf07d2ce8 Updated Greek translation 2013-09-16 22:38:25 +03:00
efcf858e60 Updated Hebrew translation 2013-09-16 21:55:49 +03:00
93d9c16672 appDisplay: Rework indicators animation
Previously the animation was not entirely according to the mockup.
Now we are closer to the mockup.

The padding for the indicators are decremented, since we need that
to make the animation not too quick. As a drawback, maybe visually
is not as good as before, or the area to click dots is too much little.
Just make that change for now and test it widely, and we can change
that after.

https://bugzilla.gnome.org/show_bug.cgi?id=707565
2013-09-16 18:49:24 +02:00
7aaf261f5a [l10n] Updated Italian translation. 2013-09-16 14:29:11 +02:00
5eb4450012 Updated Hungarian translation 2013-09-16 13:13:38 +02:00
49c8cdd8f6 a11y: check states EXPANDABLE/EXPANDED on PopupSubMenuMenuItem
https://bugzilla.gnome.org/show_bug.cgi?id=708038
2013-09-16 12:36:16 +02:00
c860b96a86 Updated Basque language 2013-09-15 15:39:35 +02:00
69403bda80 Updated slovak translation 2013-09-15 10:22:30 +02:00
f5456b66ff Updated slovak translation 2013-09-15 10:19:30 +02:00
28b4c413cb Updated slovak translation 2013-09-15 10:12:56 +02:00
5b97250bb1 Updated slovak translation 2013-09-15 10:09:03 +02:00
5d26c29eaa Updated slovak translation 2013-09-15 10:07:23 +02:00
613944eccd Update Kazakh translation 2013-09-15 14:00:57 +06:00
8d0e8fc021 Updated Polish translation 2013-09-15 01:22:01 +02:00
41ee70d414 Update Russian translation 2013-09-14 20:56:06 +02:00
3691e8ddd7 Remove "Menu" from the name of the Settings menu
Its presence makes Orca present "Settings Menu menu". Removing it does
not introduce any new strings.

https://bugzilla.gnome.org/show_bug.cgi?id=708080
2013-09-14 14:07:17 -04:00
be54e94045 Update French translation 2013-09-14 19:08:19 +02:00
366ca72342 Updated Danish translation 2013-09-14 15:55:57 +02:00
fc4e392ac1 Updated Danish translation 2013-09-13 22:03:50 +02:00
507be35d3a Updated Korean translation 2013-09-14 04:27:43 +09:00
5c0d62cd0e Updated German translation 2013-09-13 19:31:45 +02:00
7b7c4568b2 appDisplay: Change pages with page down/up keys
Add key bindings to app picker to allow change pages using
the page up/down keys.

https://bugzilla.gnome.org/show_bug.cgi?id=707979
2013-09-13 19:16:11 +02:00
f38091d96b appDisplay: Move boundary page assertions
Since the function that manages the changes between pages is
goToPage, just move the assertions of page >= 0 and page < nPages
to that function

https://bugzilla.gnome.org/show_bug.cgi?id=707979
2013-09-13 18:58:46 +02:00
7c78e1fbf5 appDisplay: Fix indicator animation position
The original position was calculated with the stage and the
transformed position of the indicator when mapped. The values
were wrong on some situations, so lets calculate the position
based on the dots width.

https://bugzilla.gnome.org/show_bug.cgi?id=707580
2013-09-13 18:15:33 +02:00
72f0a48fac theme: Erase appDisplay padding
Since now AllView doesn't have a scrollbar this
padding is not necesary, and will allow to place
the indicators correctly using only the indicators
padding in a upcoming patch.

https://bugzilla.gnome.org/show_bug.cgi?id=707580
2013-09-13 18:13:41 +02:00
193f872ebe Magnifier: don't initialize if we don't need it
Let's avoid initializing AT-SPI and start monitoring events if we
are not actually using the magnifier.

https://bugzilla.gnome.org/show_bug.cgi?id=708020
2013-09-13 16:09:33 +02:00
c3f96cf0e8 data: Fix make dist and conditionally install gnome-shell-wayland 2013-09-13 15:11:04 +02:00
df09109d81 overviewControls: Use a custom layout to catch all geometry changes
We currently update workspaces geometry when we are notified about
allocation changes of the overview group; however as the geometry
is based on stage coordinates, we miss notifications when the
allocation relative to the parent is unchanged, which happens when
the primary monitor's position changes but not its resolution.
Use a custom layout manager to give us a signal that is emitted
reliably.

https://bugzilla.gnome.org/show_bug.cgi?id=708009
2013-09-13 13:50:31 +02:00
662cb9e2a3 Updated Spanish translation 2013-09-13 12:49:59 +02:00
daa54a3798 Assamese Translation Updated 2013-09-13 15:10:33 +05:30
f035a1a0e0 Updated Galician translations 2013-09-13 10:28:22 +02:00
2688bf3333 Tajik translation updated 2013-09-13 13:14:07 +05:00
4095a58eb9 st-scroll-view-fade: Reduce number of GLSL uniforms and instructions
The vvalue and hvalue uniforms are only used to decide whether we
should do fade the edges or not based on the fade_edges uniform.
The result does not change accross fragments so there is no reason
to recompute it for every fragment (pixel) so just split the edge
fade into two uniforms and compute the "should we fade the edges"
boolean once for every direction (when setting the uniforms) instead
of for every single fragment twice.

This reduces the number of uniforms as well as the the number of instructions
which are limited on older hardware. It should also be more efficent.

https://bugzilla.gnome.org/show_bug.cgi?id=708007
2013-09-13 09:45:19 +02:00
c1b1ebe97e Updated Czech translation 2013-09-13 08:57:44 +02:00
a47b97d443 Updated Brazilian Portuguese translation 2013-09-12 23:02:30 -03:00
df5d5583eb lookingGlass: Fix position on multi-head
We currently assume that the primary monitor is located at (0, 0),
fix that.

https://bugzilla.gnome.org/show_bug.cgi?id=707996
2013-09-13 00:03:24 +02:00
79e764d5ec Update .gitignore 2013-09-12 23:28:37 +02:00
2fcb04e5b2 Updated Lithuanian translation 2013-09-12 22:41:11 +03:00
da1e264687 dnd: Use sync_pointer rather than complex enter/leave tracking
https://bugzilla.gnome.org/show_bug.cgi?id=707940
2013-09-12 14:33:33 -04:00
03975287d2 Updated Slovenian translation 2013-09-12 20:30:32 +02:00
50a61b38f7 Updated Polish translation 2013-09-12 19:39:01 +02:00
1fe072471e Updated POTFILES.in 2013-09-12 19:36:37 +02:00
93e840295e Update .gitignore 2013-09-12 11:16:20 -04:00
6ab7d640f0 Updated British English translation 2013-09-12 14:38:32 +01:00
255cb8edb1 AppFolderPopup: fix the position of close buttons
We need to adjust the offset of close buttons, in case the box
pointer has the arrow at the top. To do so, extend close buttons
to hook into a boxpointer (since that's the common use for them)
and automatically adjust their position.

https://bugzilla.gnome.org/show_bug.cgi?id=707842
2013-09-12 14:33:35 +02:00
367fb32493 Updated Hungarian translation 2013-09-12 13:58:25 +02:00
ef6d1fd6ce Updated Hungarian translation 2013-09-12 13:42:27 +02:00
3e8ab0645b ScreenShield: fix a typo due to the MetaCursorTracker switch
And replace another show_cursor() usage with the new API.

Reviewed-by: Carlos Soriano in IRC.
2013-09-12 13:17:23 +02:00
135727c9f7 Add support for running wayland under gnome-session
Include a .desktop file that autostarts us as a wayland compositor.

https://bugzilla.gnome.org/show_bug.cgi?id=707467
2013-09-12 10:34:25 +02:00
c58448817b ShellGlobal: use MetaCursorTracker to query the pointer position
Gdk uses Xwayland, so it only sees the events we forward to X11
clients. Instead, we can use the abstraction API provided by
mutter and get the right value automatically.
Also, we need to use MetaCursorTracker to handle the cursor
visibility too.

https://bugzilla.gnome.org/show_bug.cgi?id=707467
2013-09-12 10:34:25 +02:00
8ae0f1a9dc StEntry: add a hook to set the cursor from libgnome-shell
We need to call into MetaScreen to set the cursor, but we can't
do that from libst, so add a hook that libgnome-shell can fill,
and remove more ClutterX11 usage.

https://bugzilla.gnome.org/show_bug.cgi?id=707467
2013-09-12 10:34:25 +02:00
ba9c1d98f6 ShellGlobal: use a different window for IBus when running on wayland
When running as a wayland compositor, the clutter stage doesn't
have an usable window for IPC, so just create another one.

Also, disable freezing the keyboard when running on wayland, as
we can't do it really.

https://bugzilla.gnome.org/show_bug.cgi?id=707467
2013-09-12 10:34:25 +02:00
4db6e70f97 Disable XDND when running as a wayland compositor
We can't do xdnd on wayland easily, so let's disable this for 3.10

https://bugzilla.gnome.org/show_bug.cgi?id=707467
2013-09-12 10:34:25 +02:00
9d1f789937 ShellGlobal: repurpose the stage_gdk_window as the IBus window
And use it directly in the IBus event handling (by pushing it down
to StIMText)

https://bugzilla.gnome.org/show_bug.cgi?id=707467
2013-09-12 10:34:25 +02:00
11c2933e23 ShellGlobal: remove cursor manipulation functions
Use the new API in MetaScreen instead, which is automatically
routed to MetaCursorTracker as appropriate.

https://bugzilla.gnome.org/show_bug.cgi?id=707467
2013-09-12 10:34:22 +02:00
fbd4951ea7 [l10n] Updated Estonian translation 2013-09-12 07:54:11 +03:00
156 changed files with 26445 additions and 29918 deletions

7
.gitignore vendored
View File

@ -19,6 +19,8 @@ configure
data/50-gnome-shell-*.xml
data/gnome-shell.desktop
data/gnome-shell.desktop.in
data/gnome-shell-wayland.desktop
data/gnome-shell-wayland.desktop.in
data/gnome-shell-extension-prefs.desktop
data/gnome-shell-extension-prefs.desktop.in
data/gschemas.compiled
@ -41,6 +43,8 @@ docs/reference/*/xml/
docs/reference/shell/doc-gen-*
gtk-doc.make
js/misc/config.js
js/js-resources.c
js/js-resources.h
intltool-extract.in
intltool-merge.in
intltool-update.in
@ -71,13 +75,14 @@ src/calendar-server/evolution-calendar.desktop.in
src/calendar-server/org.gnome.Shell.CalendarServer.service
src/gnome-shell
src/gnome-shell-calendar-server
src/gnome-shell-extension-tool
src/gnome-shell-extension-prefs
src/gnome-shell-extension-tool
src/gnome-shell-hotplug-sniffer
src/gnome-shell-jhbuild
src/gnome-shell-perf-helper
src/gnome-shell-perf-tool
src/gnome-shell-real
src/gnome-shell-wayland
src/hotplug-sniffer/org.gnome.Shell.HotplugSniffer.service
src/run-js-test
src/test-recorder

View File

@ -1,7 +1,11 @@
# Point to our macro directory and pick up user flags from the environment
ACLOCAL_AMFLAGS = -I m4 ${ACLOCAL_FLAGS}
SUBDIRS = data js src browser-plugin tests po docs
SUBDIRS = data js src tests po docs
if BUILD_BROWSER_PLUGIN
SUBDIRS += browser-plugin
endif
if ENABLE_MAN
SUBDIRS += man

163
NEWS
View File

@ -1,3 +1,166 @@
3.11.2
======
* Cache search result display actors [Jasper; #704912]
* Use username in userWidget if real name doesn't fit [Jasper; #706851]
* Support shell_global_reexec_self() on OpenBSD [Antoine; #709571]
* Support disabling browser plugin [Colin; #711218]
* Restore support for 'disable-restart-buttons' [Florian; #711244]
* Validate parameters of exposed DBus methods [Florian; #699752]
* Connect applications to systemd journal if available [Colin; #711626]
* Misc bug fixes and cleanups [Florian, Jasper; #711205, #698486, #711416,
#644306, #711555, #709806, #711631, #711732]
Contributors:
Cosimo Cecchi, Antoine Jacoutot, Florian Müllner, Jasper St. Pierre,
Rico Tzschichholz, Colin Walters
Translations:
Yuri Myasoedov [ru], Kjartan Maraas [nb], Efstathios Iosifidis [el],
Benjamin Steinwender [de], eternalhui [zh_CN], Shantha kumar [ta]
3.11.1
======
* power: Use UPower directly instead of gnome-settings-daemon [Bastien; #710273]
* Implement support for new GTK+ notification API [Jasper, Giovanni, Florian;
#710137, #710596]
* gdm: Don't allow user-list to fill up the entire screen [Florian; #710555]
* Don't autostart remote search providers at login [Giovanni; #708830]
* Fix spacing in end-session dialog [Sebastien; #710543]
* Prepare for js24 [Tim; #711052]
* Misc bug fixes and cleanups [Jasper, Florian, Adel, Tim, Sebastien; #710347,
#710144, #710541, #691409, #710745, #688331, #704912]
Contributors:
Giovanni Campagna, Adel Gadllah, Sebastien Lafargue, Tim Lunn,
Florian Müllner, Bastien Nocera, Jasper St. Pierre, Rico Tzschichholz
Translations:
Stas Solovey [ru], Yosef Or Boczko [he], Rafael Ferreira [pt_BR]
3.10.1
======
* Make sure lock screen is drawn once before switching user [Giovanni; #708051]
* Fix signal strength indicators in network selector [Jasper; #708442]
* Scroll search results when focusing provider icons [Jasper; #708868]
* Add separate hover/active states to page indicators [Carlos; #708852]
* Tweak appearance of user name and avatar [Yash; #702309]
* Hide "Turn On" in network menu when disabled by hardware [Giovanni; #709635]
* Cancel open keyring prompts when the screen is locked [Florian; #708910]
* Differentiate "Not Connected" and "Off" in network menu [Giovanni; #709043]
* Make network settings items point to the right device [Giovanni; #709246]
* Remove animation of window preview titles [Sebastien; #709392]
* Add 'Notifications' switch to tray menu [Florian; #707073]
* Make dropdown arrows consistent [Carlos; #709564]
* power: Use icon from primary device for status [Jasper; #709925]
* Fix XDND drags to overview [Adel; #708887]
* Fix workspace switcher disappearing with too many workspaces [Jasper; #694881]
* Handle search results with 'special:' prefix specially [Giovanni; #707055]
* gdm: Support pre-authenticated logins from oVirt [Vinzenz; #702162]
* Use ARROW role for labels representing arrows [Alejandro; #710120]
* Make selected view in app picker persistent [Florian; #710042]
* Make network selector navigable by keyboard [Alejandro; #710144]
* Misc bug fixes [Florian, Adel, Jasper, Aleksander, Giovanni, Dan, Michael,
Tim; #709034, #709263, #698486, #709286, #709248, #709543, #696564, #703265,
#709638, #709866, #709998, #710019, #710104, #710115]
Contributors:
Giovanni Campagna, Michael Catanzaro, Vinzenz Feenstra, Adel Gadllah,
Yash Girdhar, Sebastien Lafargue, Tim Lunn, Aleksander Morgado,
Florian Müllner, Alejandro Piñeiro, Carlos Soriano, Jasper St. Pierre,
Dieter Verfaillie, Dan Winship
Translations:
Inaki Larranaga Murgoitio [eu], Christian Kirbach [de], Muhammet Kara [tr],
Aurimas Černius [lt], Ryan Lortie [eo], Rūdolfs Mazurs [lv],
Dušan Kazik [sk], Fran Diéguez [gl], Enrico Nicoletto [pt_BR],
Kjartan Maraas [nb], Victor Ibragimov [tg], Matej Urbančič [sl],
A S Alam [pa], Nilamdyuti Goswami [as], Daniel Mustieles [es],
Cheng-Chia Tseng [zh_HK, zh_TW], Mattias Põldaru [et], Kenneth Nielsen [da],
Milo Casagrande [it], Marek Černocký [cs], Ihar Hrachyshka [be],
Мирослав Николић [sr, sr@latin], Arash Mousavi [fa], Yuri Myasoedov [ru],
Gil Forcada [ca], Carles Ferrando [ca@valencia], Andika Triwidada [id],
Timo Jyrinki [fi], Piotr Drąg [pl], Rafael Ferreira [pt_BR],
Gabor Kelemen [hu], Yosef Or Boczko [he], Daniel Korostil [uk],
Wouter Bolsterlee [nl], António Lima [pt]
3.10.0.1
=========
* Fix login screen [Ray; #708691]
Contributors:
Ray Strode, Giovanni Campagna, Jasper St. Pierree
Translations:
Kjartan Maraas [nb], Marek Černocký [cs], A S Alam [pa], Daniel Mustieles [es],
Ihar Hrachyshka [be], Chao-Hsiung Liao [zh_HK], Nilamdyuti Goswami [as],
Yuri Myasoedov [ru], Baurzhan Muftakhidinov [kk]
3.10.0
======
* Fix fade effect in ScrollViews [Carlos; #708256]
* network: Resync when activating connection changes [Jasper; #708322]
* Close run dialog when the screen locks [Florian; #708218]
* Fix entry growing out of password dialogs [Florian; #708324, #703833]
* Vertically center labels in submenu items [Jasper; #708330]
* https://bugzilla.gnome.org/show_bug.cgi?id=708387 [Mike; #708387]
* Fix bluetooth icon not being added to status menu [Jasper; #708541]
* Fix GNOME 2 keyring dialogs appearing on lock screen [Florian; #708187]
* Fix passwords being cleared twice when authentication fails [Florian; #708186]
* Fix message tray appearing in a11y popup on login screen [Florian; #708380]
* Increase width of aggregate menu popup [Adel; #708472]
Contributors:
Adel Gadllah, Mike Gorse, Ryan Lortie, Florian Müllner, Frédéric Péters,
Carlos Soriano, Jasper St. Pierre, Rico Tzschichholz
Translations:
Daniel Șerbănescu [ro], Ryan Lortie [eo], Ihar Hrachyshka [be],
A S Alam [pa], Jiro Matsuzawa [ja], Chao-Hsiung Liao [zh_HK, zh_TW],
Piotr Drąg [pl], Kristjan SCHMIDT [eo], Daniel Korostil [uk],
Rūdolfs Mazurs [lv], Reinout van Schouwen [nl], Yosef Or Boczko [he],
Fran Diéguez [gl], António Lima [pt], Andika Triwidada [id],
Alexandre Franke [fr], Rafael Ferreira [pt_BR], Milo Casagrande [it],
Kenneth Nielsen [da], Matej Urbančič [sl]
3.9.92
======
* Don't show page indicators if there's only one page [Florian; #707363]
* Make :active style of app and non-app results consistent [Jakub; #704714]
* Fade app pages when scrolled [Florian; #707409]
* Don't block scrolling on page indicators [Carlos; #707609]
* Tweak visual appearance of folder views [Florian; #707662]
* Don't put minimized apps at the end of the app switcher [Florian; #707663]
* Merge the wayland branch [Giovanni, Neil; #707467]
* Make search entry behave better in RTL locales [Matthias, Florian; #705779]
* Allow to change app pages with pageUp/pageDown keys [Carlos; #707979]
* Set approriate a11y states on expandable menu items [Alejandro; #708038]
* Improve page indicator animation [Carlos; #707565]
* Misc bug fixes and cleanups [Florian, Olivier, Jasper, Giovanni, Magdalen,
Adel, Carlos, Rico, Joanmarie; #707308, #707430, #707508, #707557, #707600,
#707614, #707666, #707814, #707806, #707801, #707889, #707892, #707935,
#707842, #707940, #707996, #708007, #708009, #708020, #707580, #708080]
Contributors:
Magdalen Berns, Olivier Blin, Giovanni Campagna, Matthias Clasen,
Joanmarie Diggs, Adel Gadllah, Florian Müllner, Alejandro Piñeiro,
Neil Roberts, Carlos Soriano, Jasper St. Pierre, Jakub Steiner,
Rico Tzschichholz
Translations:
Rafael Ferreira [pt_BR], Fran Diéguez [gl], Daniel Mustieles [es],
Aurimas Černius [lt], Luca Ferretti [it], Piotr Drąg [pl],
Chao-Hsiung Liao [zh_HK, zh_TW], Timo Jyrinki [fi], Daniel Korostil [uk],
Dušan Kazik [sk], Adam Matoušek [cs], Marek Černocký [cs],
Jiro Matsuzawa [ja], Yuri Myasoedov [ru], Tobias Endrigkeit [de],
Kjartan Maraas [nb], Victor Ibragimov [tg], Мирослав Николић [sr, sr@latin],
A S Alam [pa], Khaled Hosny [ar], Andika Triwidada [id],
Nilamdyuti Goswami [as], Ihar Hrachyshka [be], Rūdolfs Mazurs [lv],
Mattias Põldaru [et], Gabor Kelemen [hu], Bruce Cowan [en_GB],
Matej Urbančič [sl], Enrico Nicoletto [pt_BR], Benjamin Steinwender [de],
Changwoo Ryu [ko], Kris Thomsen [da], Alexandre Franke [fr],
Evgeny Bobkin [ru], Baurzhan Muftakhidinov [kk], Peter Mráz [sk],
Inaki Larranaga Murgoitio [eu], Yosef Or Boczko [he]
3.9.91
======
* Improve submenu styling [Jakub; #706037]

View File

@ -1,5 +1,5 @@
AC_PREREQ(2.63)
AC_INIT([gnome-shell],[3.9.91],[https://bugzilla.gnome.org/enter_bug.cgi?product=gnome-shell],[gnome-shell])
AC_INIT([gnome-shell],[3.11.2],[https://bugzilla.gnome.org/enter_bug.cgi?product=gnome-shell],[gnome-shell])
AC_CONFIG_HEADERS([config.h])
AC_CONFIG_SRCDIR([src/shell-global.c])
@ -16,6 +16,7 @@ m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])])
# Checks for programs.
AC_PROG_CC
AC_PROG_CXX
# Initialize libtool
LT_PREREQ([2.2.6])
@ -57,10 +58,25 @@ fi
AM_CONDITIONAL(BUILD_RECORDER, $build_recorder)
AC_ARG_ENABLE([systemd],
AS_HELP_STRING([--enable-systemd], [Use systemd]),
[enable_systemd=$enableval],
[enable_systemd=auto])
AS_IF([test x$enable_systemd != xno], [
AC_MSG_CHECKING([for libsystemd-journal])
PKG_CHECK_EXISTS([libsystemd-journal],
[have_systemd=yes
AC_DEFINE([HAVE_SYSTEMD], [1], [Define if we have systemd])],
[have_systemd=no])
AC_MSG_RESULT($have_systemd)
])
AC_MSG_RESULT($enable_systemd)
CLUTTER_MIN_VERSION=1.13.4
GOBJECT_INTROSPECTION_MIN_VERSION=0.10.1
GJS_MIN_VERSION=1.35.4
MUTTER_MIN_VERSION=3.9.91
GJS_MIN_VERSION=1.38.1
MUTTER_MIN_VERSION=3.11.1
GTK_MIN_VERSION=3.7.9
GIO_MIN_VERSION=2.37.0
LIBECAL_MIN_VERSION=3.5.3
@ -70,7 +86,6 @@ POLKIT_MIN_VERSION=0.100
STARTUP_NOTIFICATION_MIN_VERSION=0.11
GCR_MIN_VERSION=3.7.5
GNOME_DESKTOP_REQUIRED_VERSION=3.7.90
GNOME_MENUS_REQUIRED_VERSION=3.5.3
NETWORKMANAGER_MIN_VERSION=0.9.8
PULSE_MIN_VERS=2.0
@ -80,7 +95,6 @@ SHARED_PCS="gio-unix-2.0 >= $GIO_MIN_VERSION
gtk+-3.0 >= $GTK_MIN_VERSION
atk-bridge-2.0
gjs-internals-1.0 >= $GJS_MIN_VERSION
libgnome-menu-3.0 >= $GNOME_MENUS_REQUIRED_VERSION
$recorder_modules
gdk-x11-3.0 libsoup-2.4
xtst
@ -94,6 +108,9 @@ SHARED_PCS="gio-unix-2.0 >= $GIO_MIN_VERSION
libnm-glib libnm-util >= $NETWORKMANAGER_MIN_VERSION
libnm-gtk >= $NETWORKMANAGER_MIN_VERSION
libsecret-unstable gcr-base-3 >= $GCR_MIN_VERSION"
if test x$have_systemd = xyes; then
SHARED_PCS="${SHARED_PCS} libsystemd-journal"
fi
PKG_CHECK_MODULES(GNOME_SHELL, $SHARED_PCS)
PKG_CHECK_MODULES(MUTTER, libmutter >= $MUTTER_MIN_VERSION)
@ -109,12 +126,20 @@ PKG_CHECK_MODULES(GNOME_SHELL_JS, gio-2.0 gjs-internals-1.0 >= $GJS_MIN_VERSION)
PKG_CHECK_MODULES(ST, clutter-1.0 gtk+-3.0 libcroco-0.6 >= 0.6.8 x11)
PKG_CHECK_MODULES(SHELL_PERF_HELPER, gtk+-3.0 gio-2.0)
PKG_CHECK_MODULES(SHELL_HOTPLUG_SNIFFER, gio-2.0 gdk-pixbuf-2.0)
PKG_CHECK_MODULES(BROWSER_PLUGIN, gio-2.0 >= $GIO_MIN_VERSION json-glib-1.0 >= 0.13.2)
PKG_CHECK_MODULES(TRAY, gtk+-3.0)
PKG_CHECK_MODULES(GVC, libpulse >= $PULSE_MIN_VERS libpulse-mainloop-glib gobject-2.0)
PKG_CHECK_MODULES(DESKTOP_SCHEMAS, gsettings-desktop-schemas >= 3.7.4)
PKG_CHECK_MODULES(CARIBOU, caribou-1.0 >= 0.4.8)
AC_ARG_ENABLE(browser-plugin,
[AS_HELP_STRING([--enable-browser-plugin],
[Enable browser plugin [default=yes]])],,
enable_browser_plugin=yes)
AS_IF([test x$enable_browser_plugin = xyes], [
PKG_CHECK_MODULES(BROWSER_PLUGIN, gio-2.0 >= $GIO_MIN_VERSION json-glib-1.0 >= 0.13.2)
])
AM_CONDITIONAL(BUILD_BROWSER_PLUGIN, test x$enable_browser_plugin = xyes)
AC_MSG_CHECKING([for bluetooth support])
PKG_CHECK_EXISTS([gnome-bluetooth-1.0 >= 3.9.0],
[BLUETOOTH_DIR=`$PKG_CONFIG --variable=applet_libdir gnome-bluetooth-1.0`
@ -147,6 +172,9 @@ AC_SUBST(MUTTER_TYPELIB_DIR)
GJS_CONSOLE=`$PKG_CONFIG --variable=gjs_console gjs-1.0`
AC_SUBST(GJS_CONSOLE)
GLIB_COMPILE_RESOURCES=`$PKG_CONFIG --variable glib_compile_resources gio-2.0`
AC_SUBST(GLIB_COMPILE_RESOURCES)
AC_CHECK_FUNCS(fdwalk)
AC_CHECK_FUNCS(mallinfo)
AC_CHECK_HEADERS([sys/resource.h])

View File

@ -1,8 +1,9 @@
wandadir = $(pkgdatadir)
dist_wanda_DATA = wanda.png
desktopdir=$(datadir)/applications
desktop_DATA = gnome-shell.desktop gnome-shell-extension-prefs.desktop
if HAVE_MUTTER_WAYLAND
desktop_DATA += gnome-shell-wayland.desktop
endif HAVE_MUTTER_WAYLAND
# We substitute in bindir so it works as an autostart
# file when built in a non-system prefix
@ -41,8 +42,10 @@ dist_theme_DATA = \
theme/message-tray-background.png \
theme/more-results.svg \
theme/noise-texture.png \
theme/page-indicator-active.svg \
theme/page-indicator-active.svg \
theme/page-indicator-inactive.svg \
theme/page-indicator-checked.svg \
theme/page-indicator-hover.svg \
theme/panel-button-border.svg \
theme/panel-button-highlight-narrow.svg \
theme/panel-button-highlight-wide.svg \
@ -83,6 +86,7 @@ convert_DATA = gnome-shell-overrides.convert
EXTRA_DIST = \
gnome-shell.desktop.in.in \
gnome-shell-wayland.desktop.in.in \
gnome-shell-extension-prefs.desktop.in.in \
$(introspection_DATA) \
$(menu_DATA) \
@ -92,6 +96,7 @@ EXTRA_DIST = \
CLEANFILES = \
gnome-shell.desktop.in \
gnome-shell-wayland.desktop.in \
gnome-shell-extension-prefs.in \
$(desktop_DATA) \
$(keys_DATA) \

View File

@ -0,0 +1,15 @@
[Desktop Entry]
Type=Application
_Name=GNOME Shell (wayland compositor)
_Comment=Window management and application launching
Exec=@bindir@/mutter-launch -- gnome-shell-wayland --wayland
X-GNOME-Bugzilla-Bugzilla=GNOME
X-GNOME-Bugzilla-Product=gnome-shell
X-GNOME-Bugzilla-Component=general
X-GNOME-Bugzilla-Version=@VERSION@
Categories=GNOME;GTK;Core;
OnlyShowIn=GNOME;
NoDisplay=true
X-GNOME-Autostart-Phase=DisplayServer
X-GNOME-Autostart-Notify=true
X-GNOME-AutoRestart=false

View File

@ -37,6 +37,13 @@
application view, rather than being displayed inline in the main view.
</_description>
</key>
<key name="app-picker-view" type="u">
<default>0</default>
<summary>App Picker View</summary>
<description>
Index of the currently selected view in the application picker.
</description>
</key>
<key name="command-history" type="as">
<default>[]</default>
<_summary>History for command (Alt-F2) dialog</_summary>
@ -216,10 +223,10 @@
<key name="focus-change-on-pointer-rest" type="b">
<default>true</default>
<summary>Delay focus changes in mouse mode until the pointer stops moving</summary>
<description>
<_summary>Delay focus changes in mouse mode until the pointer stops moving</_summary>
<_description>
This key overrides the key in org.gnome.mutter when running GNOME Shell.
</description>
</_description>
</key>
</schema>
</schemalist>

View File

@ -157,7 +157,7 @@ StScrollBar StButton#vhandle:active {
min-width: 200px;
}
.popup-submenu-menu-item-triangle {
.unicode-arrow {
font-size: 120%;
}
@ -306,16 +306,13 @@ StScrollBar StButton#vhandle:active {
font-size: 12pt;
border-bottom: 1px solid #666;
padding: 12px;
}
.nm-dialog-item:checked {
background-color: #333;
}
.nm-dialog-item-box {
spacing: 20px;
}
.nm-dialog-item:selected {
background-color: #333;
}
.nm-dialog-icons {
spacing: .5em;
}
@ -642,7 +639,7 @@ StScrollBar StButton#vhandle:active {
}
.aggregate-menu {
width: 340px;
width: 360px;
}
.aggregate-menu .popup-menu-icon {
@ -693,7 +690,9 @@ StScrollBar StButton#vhandle:active {
padding-bottom: 32px;
}
.workspace-thumbnails-background {
.workspace-thumbnails {
spacing: 11px;
visible-width: 32px; /* Amount visible before hovering */
border: 1px solid rgba(128, 128, 128, 0.4);
border-right: 0px;
border-radius: 9px 0px 0px 9px;
@ -701,18 +700,13 @@ StScrollBar StButton#vhandle:active {
padding: 11px 7px 11px 11px;
}
.workspace-thumbnails-background:rtl {
.workspace-thumbnails:rtl {
border-right: 1px;
border-left: 0px;
border-radius: 0px 9px 9px 0px;
padding: 11px 11px 11px 7px;
}
.workspace-thumbnails {
spacing: 11px;
visible-width: 32px; /* Amount visible before hovering */
}
.workspace-thumbnail-indicator {
border: 4px solid rgba(255,255,255,0.7);
border-radius: 4px;
@ -918,7 +912,6 @@ StScrollBar StButton#vhandle:active {
}
.app-display {
padding: 8px;
spacing: 20px;
}
@ -942,7 +935,7 @@ StScrollBar StButton#vhandle:active {
}
.page-indicator {
padding: 15px 30px;
padding: 15px 20px;
}
.page-indicator .page-indicator-icon {
@ -951,11 +944,19 @@ StScrollBar StButton#vhandle:active {
background-image: url(page-indicator-inactive.svg);
}
.page-indicator:hover .page-indicator-icon,
.page-indicator:checked .page-indicator-icon {
.page-indicator:hover .page-indicator-icon {
background-image: url(page-indicator-hover.svg);
}
.page-indicator:active .page-indicator-icon {
background-image: url(page-indicator-active.svg);
}
.page-indicator:checked .page-indicator-icon,
.page-indicator:checked:active .page-indicator-icon {
background-image: url(page-indicator-checked.svg);
}
.no-frequent-applications-label {
font-size: 18pt;
color: #999999;
@ -1966,6 +1967,11 @@ StScrollBar StButton#vhandle:active {
padding-left: 50px;
}
.end-session-dialog-session-list,
.end-session-dialog-app-list {
spacing: 1em;
}
.end-session-dialog-list-header {
font-weight: bold;
}
@ -2269,7 +2275,7 @@ StScrollBar StButton#vhandle:active {
.framed-user-icon {
border: 2px solid #8b8b8b;
border-radius: 5px;
border-radius: 3px;
background-size: contain;
}
@ -2313,7 +2319,7 @@ StScrollBar StButton#vhandle:active {
}
.login-dialog-user-list-item {
border-radius: 10px;
border-radius: 5px;
padding: .2em;
}
@ -2326,19 +2332,20 @@ StScrollBar StButton#vhandle:active {
}
.login-dialog-user-list-item .login-dialog-user-list-item-name {
font-size: 20pt;
padding-left: 9px;
font-size: 20px;
padding-left: 18px;
font-weight: bold;
}
.login-dialog-user-list:expanded .login-dialog-user-list-item {
color: #666666;
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: white;
color: #bfbfbf;
text-shadow: black 0px 2px 2px;
}
@ -2370,7 +2377,7 @@ StScrollBar StButton#vhandle:active {
.login-dialog-user-list-item-icon {
border: 2px solid #8b8b8b;
border-radius: 8px;
border-radius: 3px;
width: 64px;
height: 64px;
}
@ -2382,6 +2389,10 @@ StScrollBar StButton#vhandle:active {
padding-top: 1em;
}
.login-dialog-user-selection-box {
padding: 100px 0;
}
.login-dialog-user-selection-box .login-dialog-not-listed-label {
padding-left: 2px;
}
@ -2487,10 +2498,11 @@ StScrollBar StButton#vhandle:active {
}
.user-widget-label {
font-size: 16pt;
font-size: 20px;
font-weight: bold;
text-align: left;
padding-left: 15px;
padding-left: 18px;
color:white;
text-shadow: black 0px 4px 3px 0px;
}

View File

@ -14,7 +14,7 @@
id="svg4703"
version="1.1"
inkscape:version="0.48.4 r9939"
sodipodi:docname="page-indicator-active.svg">
sodipodi:docname="page-indicator-pushed.svg">
<defs
id="defs4705" />
<sodipodi:namedview
@ -24,18 +24,22 @@
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="22.197802"
inkscape:cx="2.1522887"
inkscape:cy="16.782904"
inkscape:zoom="31.392433"
inkscape:cx="1.0245308"
inkscape:cy="13.3715"
inkscape:current-layer="layer1"
showgrid="true"
inkscape:grid-bbox="true"
inkscape:document-units="px"
inkscape:window-width="1920"
inkscape:window-height="1021"
inkscape:window-width="2560"
inkscape:window-height="1374"
inkscape:window-x="0"
inkscape:window-y="27"
inkscape:window-maximized="1" />
inkscape:window-maximized="1">
<inkscape:grid
type="xygrid"
id="grid6140" />
</sodipodi:namedview>
<metadata
id="metadata4708">
<rdf:RDF>
@ -44,7 +48,7 @@
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
@ -54,14 +58,14 @@
inkscape:groupmode="layer"
transform="translate(0,2)">
<path
transform="matrix(0.72823872,0,0,0.8336417,-1512.2872,-525.55618)"
d="m 2099.9808,638.83099 c 0,5.29998 -4.9184,9.59645 -10.9854,9.59645 -6.0671,0 -10.9854,-4.29647 -10.9854,-9.59645 0,-5.29997 4.9183,-9.59645 10.9854,-9.59645 6.067,0 10.9854,4.29648 10.9854,9.59645 z"
transform="matrix(0.54617904,0,0,0.62523128,-1131.9904,-392.39214)"
d="m 2099.9808,638.83099 a 10.985409,9.5964489 0 1 1 -21.9708,0 10.985409,9.5964489 0 1 1 21.9708,0 z"
sodipodi:ry="9.5964489"
sodipodi:rx="10.985409"
sodipodi:cy="638.83099"
sodipodi:cx="2088.9954"
id="path4711"
style="fill:#fdffff;fill-opacity:0.94117647;stroke:none"
style="fill:#fdffff;fill-opacity:1;stroke:none"
sodipodi:type="arc" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

@ -0,0 +1,67 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="18"
height="18"
id="svg4703"
version="1.1"
inkscape:version="0.48.4 r9939"
sodipodi:docname="page-indicator-active.svg">
<defs
id="defs4705" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="22.197802"
inkscape:cx="2.1522887"
inkscape:cy="16.782904"
inkscape:current-layer="layer1"
showgrid="true"
inkscape:grid-bbox="true"
inkscape:document-units="px"
inkscape:window-width="1920"
inkscape:window-height="1021"
inkscape:window-x="0"
inkscape:window-y="27"
inkscape:window-maximized="1" />
<metadata
id="metadata4708">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
<g
id="layer1"
inkscape:label="Layer 1"
inkscape:groupmode="layer"
transform="translate(0,2)">
<path
transform="matrix(0.72823872,0,0,0.8336417,-1512.2872,-525.55618)"
d="m 2099.9808,638.83099 c 0,5.29998 -4.9184,9.59645 -10.9854,9.59645 -6.0671,0 -10.9854,-4.29647 -10.9854,-9.59645 0,-5.29997 4.9183,-9.59645 10.9854,-9.59645 6.067,0 10.9854,4.29648 10.9854,9.59645 z"
sodipodi:ry="9.5964489"
sodipodi:rx="10.985409"
sodipodi:cy="638.83099"
sodipodi:cx="2088.9954"
id="path4711"
style="fill:#fdffff;fill-opacity:0.94117647;stroke:none"
sodipodi:type="arc" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

@ -0,0 +1,67 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="18"
height="18"
id="svg5266"
version="1.1"
inkscape:version="0.48.4 r9939"
sodipodi:docname="page-indicator-inactive.svg">
<defs
id="defs5268" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:zoom="11.313709"
inkscape:cx="-2.307566"
inkscape:cy="17.859535"
inkscape:current-layer="layer1"
showgrid="true"
inkscape:grid-bbox="true"
inkscape:document-units="px"
inkscape:window-width="2560"
inkscape:window-height="1374"
inkscape:window-x="0"
inkscape:window-y="27"
inkscape:window-maximized="1" />
<metadata
id="metadata5271">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
id="layer1"
inkscape:label="Layer 1"
inkscape:groupmode="layer"
transform="translate(0,2)">
<path
sodipodi:type="arc"
style="fill:none;fill-opacity:0;stroke:#ffffff;stroke-width:2.93356276000000005;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
id="path5274"
sodipodi:cx="2088.9954"
sodipodi:cy="638.83099"
sodipodi:rx="10.985409"
sodipodi:ry="9.5964489"
d="m 2099.9808,638.83099 c 0,5.29998 -4.9184,9.59645 -10.9854,9.59645 -6.0671,0 -10.9854,-4.29647 -10.9854,-9.59645 0,-5.29997 4.9183,-9.59645 10.9854,-9.59645 6.067,0 10.9854,4.29648 10.9854,9.59645 z"
transform="matrix(0.63720887,0,0,0.72943648,-1322.1264,-458.98661)" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

@ -25,14 +25,14 @@
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:zoom="11.313709"
inkscape:cx="13.381365"
inkscape:cx="-2.307566"
inkscape:cy="17.859535"
inkscape:current-layer="layer1"
showgrid="true"
inkscape:grid-bbox="true"
inkscape:document-units="px"
inkscape:window-width="1920"
inkscape:window-height="1021"
inkscape:window-width="2560"
inkscape:window-height="1374"
inkscape:window-x="0"
inkscape:window-y="27"
inkscape:window-maximized="1" />
@ -55,7 +55,7 @@
transform="translate(0,2)">
<path
sodipodi:type="arc"
style="fill:#ffffff;fill-opacity:0;stroke:#ffffff;stroke-width:2.93356276;stroke-miterlimit:4;stroke-opacity:0.39215686;stroke-dasharray:none"
style="fill:none;fill-opacity:0;stroke:#ffffff;stroke-width:2.93356276000000005;stroke-miterlimit:4;stroke-opacity:0.39215686000000000;stroke-dasharray:none"
id="path5274"
sodipodi:cx="2088.9954"
sodipodi:cy="638.83099"

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

View File

@ -1,7 +1,5 @@
NULL =
EXTRA_DIST = misc/config.js.in
CLEANFILES = misc/config.js
BUILT_SOURCES =
misc/config.js: misc/config.js.in Makefile
[ -d $(@D) ] || $(mkdir_p) $(@D) ; \
@ -14,111 +12,26 @@ misc/config.js: misc/config.js.in Makefile
-e "s|[@]sysconfdir@|$(sysconfdir)|g" \
$< > $@
jsdir = $(pkgdatadir)/js
js_resource_files = $(shell $(GLIB_COMPILE_RESOURCES) --sourcedir=$(srcdir) --generate-dependencies $(srcdir)/js-resources.gresource.xml)
js-resources.h: js-resources.gresource.xml $(js_resource_files) misc/config.js
$(AM_V_GEN) $(GLIB_COMPILE_RESOURCES) --target=$@ --sourcedir=$(srcdir) --sourcedir=$(builddir) --generate --c-name shell_js_resources $<
js-resources.c: js-resources.gresource.xml $(js_resource_files) misc/config.js
$(AM_V_GEN) $(GLIB_COMPILE_RESOURCES) --target=$@ --sourcedir=$(srcdir) --sourcedir=$(builddir) --generate --c-name shell_js_resources $<
nobase_dist_js_DATA = \
gdm/authPrompt.js \
gdm/batch.js \
gdm/fingerprint.js \
gdm/loginDialog.js \
gdm/realmd.js \
gdm/util.js \
extensionPrefs/main.js \
misc/config.js \
misc/extensionUtils.js \
misc/fileUtils.js \
misc/gnomeSession.js \
misc/hash.js \
misc/history.js \
misc/jsParse.js \
misc/loginManager.js \
misc/modemManager.js \
misc/objectManager.js \
misc/params.js \
misc/smartcardManager.js \
misc/util.js \
perf/core.js \
ui/altTab.js \
ui/animation.js \
ui/appDisplay.js \
ui/appFavorites.js \
ui/backgroundMenu.js \
ui/background.js \
ui/boxpointer.js \
ui/calendar.js \
ui/checkBox.js \
ui/ctrlAltTab.js \
ui/dash.js \
ui/dateMenu.js \
ui/dnd.js \
ui/endSessionDialog.js \
ui/extensionSystem.js \
ui/extensionDownloader.js \
ui/environment.js \
ui/focusCaretTracker.js\
ui/ibusCandidatePopup.js\
ui/grabHelper.js \
ui/iconGrid.js \
ui/keyboard.js \
ui/layout.js \
ui/lightbox.js \
ui/lookingGlass.js \
ui/magnifier.js \
ui/magnifierDBus.js \
ui/main.js \
ui/messageTray.js \
ui/modalDialog.js \
ui/separator.js \
ui/sessionMode.js \
ui/shellEntry.js \
ui/shellMountOperation.js \
ui/slider.js \
ui/notificationDaemon.js \
ui/osdWindow.js \
ui/overview.js \
ui/overviewControls.js \
ui/panel.js \
ui/panelMenu.js \
ui/pointerWatcher.js \
ui/popupMenu.js \
ui/remoteSearch.js \
ui/remoteMenu.js \
ui/runDialog.js \
ui/screencast.js \
ui/screenshot.js \
ui/screenShield.js \
ui/scripting.js \
ui/search.js \
ui/searchDisplay.js \
ui/shellDBus.js \
ui/status/accessibility.js \
ui/status/brightness.js \
ui/status/keyboard.js \
ui/status/network.js \
ui/status/power.js \
ui/status/rfkill.js \
ui/status/volume.js \
ui/status/bluetooth.js \
ui/status/screencast.js \
ui/status/system.js \
ui/switcherPopup.js \
ui/tweener.js \
ui/unlockDialog.js \
ui/userWidget.js \
ui/viewSelector.js \
ui/wanda.js \
ui/windowAttentionHandler.js \
ui/windowManager.js \
ui/workspace.js \
ui/workspaceThumbnail.js \
ui/workspacesView.js \
ui/workspaceSwitcherPopup.js \
ui/xdndHandler.js \
ui/components/__init__.js \
ui/components/autorunManager.js \
ui/components/automountManager.js \
ui/components/networkAgent.js \
ui/components/polkitAgent.js \
ui/components/telepathyClient.js \
ui/components/keyring.js \
js_built_sources = js-resources.c js-resources.h
BUILT_SOURCES += $(js_built_sources)
all-local: $(js_built_sources)
js_resource_dist_files = $(filter-out misc/config.js, $(js_resource_files))
EXTRA_DIST = \
$(js_resource_dist_files) \
js-resources.gresource.xml \
misc/config.js.in \
$(NULL)
CLEANFILES = \
$(js_built_sources) \
$(NULL)

View File

@ -13,13 +13,15 @@ const _ = Gettext.gettext;
const Config = imports.misc.config;
const ExtensionUtils = imports.misc.extensionUtils;
const GnomeShellIface = <interface name="org.gnome.Shell.Extensions">
<signal name="ExtensionStatusChanged">
<arg type="s" name="uuid"/>
<arg type="i" name="state"/>
<arg type="s" name="error"/>
</signal>
</interface>;
const GnomeShellIface = '<node> \
<interface name="org.gnome.Shell.Extensions"> \
<signal name="ExtensionStatusChanged"> \
<arg type="s" name="uuid"/> \
<arg type="i" name="state"/> \
<arg type="s" name="error"/> \
</signal> \
</interface> \
</node>';
const GnomeShellProxy = Gio.DBusProxy.makeProxyWrapper(GnomeShellIface);
@ -204,11 +206,11 @@ const Application = new Lang.Class({
_scanExtensions: function() {
let finder = new ExtensionUtils.ExtensionFinder();
finder.connect('extension-found', Lang.bind(this, this._extensionFound));
finder.connect('extensions-loaded', Lang.bind(this, this._extensionsLoaded));
finder.scanExtensions();
this._extensionsLoaded();
},
_extensionFound: function(signals, extension) {
_extensionFound: function(finder, extension) {
let iter = this._model.append();
this._model.set(iter, [0, 1], [extension.uuid, extension.metadata.name]);
this._extensionIters[extension.uuid] = iter;

View File

@ -59,6 +59,7 @@ const AuthPrompt = new Lang.Class({
this._userVerifier.connect('verification-complete', Lang.bind(this, this._onVerificationComplete));
this._userVerifier.connect('reset', Lang.bind(this, this._onReset));
this._userVerifier.connect('smartcard-status-changed', Lang.bind(this, this._onSmartcardStatusChanged));
this._userVerifier.connect('ovirt-user-authenticated', Lang.bind(this, this._onOVirtUserAuthenticated));
this.smartcardDetected = this._userVerifier.smartcardDetected;
this.connect('next', Lang.bind(this, function() {
@ -219,6 +220,11 @@ const AuthPrompt = new Lang.Class({
this.emit('prompted');
},
_onOVirtUserAuthenticated: function() {
if (this.verificationStatus != AuthPromptStatus.VERIFICATION_SUCCEEDED)
this.reset();
},
_onSmartcardStatusChanged: function() {
this.smartcardDetected = this._userVerifier.smartcardDetected;
@ -244,6 +250,7 @@ const AuthPrompt = new Lang.Class({
},
_onVerificationFailed: function() {
this._queryingService = null;
this.clear();
this.updateSensitivity(true);
@ -443,10 +450,11 @@ const AuthPrompt = new Lang.Class({
// The user is constant at the unlock screen, so it will immediately
// respond to the request with the username
beginRequestType = BeginRequestType.PROVIDE_USERNAME;
} else if (this.smartcardDetected &&
this._userVerifier.serviceIsForeground(GdmUtil.SMARTCARD_SERVICE_NAME)) {
} else if (this._userVerifier.serviceIsForeground(GdmUtil.OVIRT_SERVICE_NAME) ||
(this.smartcardDetected &&
this._userVerifier.serviceIsForeground(GdmUtil.SMARTCARD_SERVICE_NAME))) {
// We don't need to know the username if the user preempted the login screen
// with a smartcard.
// with a smartcard or with preauthenticated oVirt credentials
beginRequestType = BeginRequestType.DONT_PROVIDE_USERNAME;
} else {
// In all other cases, we should get the username up front.

View File

@ -5,11 +5,13 @@ const Lang = imports.lang;
const Shell = imports.gi.Shell;
const Signals = imports.signals;
const FprintManagerIface = <interface name='net.reactivated.Fprint.Manager'>
<method name='GetDefaultDevice'>
<arg type='o' direction='out' />
</method>
</interface>;
const FprintManagerIface = '<node> \
<interface name="net.reactivated.Fprint.Manager"> \
<method name="GetDefaultDevice"> \
<arg type="o" direction="out" /> \
</method> \
</interface> \
</node>';
const FprintManagerInfo = Gio.DBusInterfaceInfo.new_for_xml(FprintManagerIface);

View File

@ -59,7 +59,7 @@ const UserListItem = new Lang.Class({
this._userChangedId = this.user.connect('changed',
Lang.bind(this, this._onUserChanged));
let layout = new St.BoxLayout({ vertical: false });
let layout = new St.BoxLayout({ vertical: true });
this.actor = new St.Button({ style_class: 'login-dialog-user-list-item',
button_mask: St.ButtonMask.ONE | St.ButtonMask.THREE,
can_focus: true,
@ -68,39 +68,18 @@ const UserListItem = new Lang.Class({
x_align: St.Align.START,
x_fill: true });
this._userAvatar = new UserWidget.Avatar(this.user,
{ styleClass: 'login-dialog-user-list-item-icon' });
layout.add(this._userAvatar.actor);
let textLayout = new St.BoxLayout({ style_class: 'login-dialog-user-list-item-text-box',
vertical: true });
layout.add(textLayout, { expand: true });
this._nameLabel = new St.Label({ style_class: 'login-dialog-user-list-item-name' });
this.actor.label_actor = this._nameLabel;
textLayout.add(this._nameLabel,
{ y_fill: false,
y_align: St.Align.MIDDLE,
expand: true });
this._userWidget = new UserWidget.UserWidget(this.user);
layout.add(this._userWidget.actor);
this._timedLoginIndicator = new St.Bin({ style_class: 'login-dialog-timed-login-indicator',
scale_x: 0 });
textLayout.add(this._timedLoginIndicator,
{ x_fill: true,
x_align: St.Align.MIDDLE,
y_fill: false,
y_align: St.Align.END });
layout.add(this._timedLoginIndicator);
this.actor.connect('clicked', Lang.bind(this, this._onClicked));
this._onUserChanged();
},
_onUserChanged: function() {
this._nameLabel.set_text(this.user.get_real_name());
this._userAvatar.update();
this._updateLoggedIn();
},
syncStyleClasses: function() {
this._updateLoggedIn();
},
@ -189,7 +168,6 @@ const UserList = new Lang.Class({
for (let userName in this._items) {
let item = this._items[userName];
item.actor.sync_hover();
item.syncStyleClasses();
}
},
@ -619,7 +597,7 @@ const LoginDialog = new Lang.Class({
// Translators: this message is shown below the username entry field
// to clue the user in on how to login to the local network realm
this._authPrompt.setMessage(_("(e.g., user or %s)").format(hint), AuthPrompt.MessageType.HINT);
this._authPrompt.setMessage(_("(e.g., user or %s)").format(hint), GdmUtil.MessageType.HINT);
},
_askForUsernameAndBeginVerification: function() {

64
js/gdm/oVirt.js Normal file
View File

@ -0,0 +1,64 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
const Gio = imports.gi.Gio;
const Lang = imports.lang;
const Signals = imports.signals;
const OVirtCredentialsIface = '<node> \
<interface name="org.ovirt.vdsm.Credentials"> \
<signal name="UserAuthenticated"> \
<arg type="s" name="token"/> \
</signal> \
</interface> \
</node>';
const OVirtCredentialsInfo = Gio.DBusInterfaceInfo.new_for_xml(OVirtCredentialsIface);
let _oVirtCredentialsManager = null;
function OVirtCredentials() {
var self = new Gio.DBusProxy({ g_connection: Gio.DBus.system,
g_interface_name: OVirtCredentialsInfo.name,
g_interface_info: OVirtCredentialsInfo,
g_name: 'org.ovirt.vdsm.Credentials',
g_object_path: '/org/ovirt/vdsm/Credentials',
g_flags: (Gio.DBusProxyFlags.DO_NOT_LOAD_PROPERTIES) });
self.init(null);
return self;
}
const OVirtCredentialsManager = new Lang.Class({
Name: 'OVirtCredentialsManager',
_init: function() {
this._token = null;
this._credentials = new OVirtCredentials();
this._credentials.connectSignal('UserAuthenticated',
Lang.bind(this, this._onUserAuthenticated));
},
_onUserAuthenticated: function(proxy, sender, [token]) {
this._token = token;
this.emit('user-authenticated', token);
},
hasToken: function() {
return this._token != null;
},
getToken: function() {
return this._token;
},
resetToken: function() {
this._token = null;
}
});
Signals.addSignalMethods(OVirtCredentialsManager.prototype);
function getOVirtCredentialsManager() {
if (!_oVirtCredentialsManager)
_oVirtCredentialsManager = new OVirtCredentialsManager();
return _oVirtCredentialsManager;
}

View File

@ -5,52 +5,58 @@ const Lang = imports.lang;
const Shell = imports.gi.Shell;
const Signals = imports.signals;
const ProviderIface = <interface name='org.freedesktop.realmd.Provider'>
<property name="Name" type="s" access="read"/>
<property name="Version" type="s" access="read"/>
<property name="Realms" type="ao" access="read"/>
<method name="Discover">
<arg name="string" type="s" direction="in"/>
<arg name="options" type="a{sv}" direction="in"/>
<arg name="relevance" type="i" direction="out"/>
<arg name="realm" type="ao" direction="out"/>
</method>
</interface>;
const ProviderIface = '<node> \
<interface name="org.freedesktop.realmd.Provider"> \
<property name="Name" type="s" access="read"/> \
<property name="Version" type="s" access="read"/> \
<property name="Realms" type="ao" access="read"/> \
<method name="Discover"> \
<arg name="string" type="s" direction="in"/> \
<arg name="options" type="a{sv}" direction="in"/> \
<arg name="relevance" type="i" direction="out"/> \
<arg name="realm" type="ao" direction="out"/> \
</method> \
</interface> \
</node>';
const Provider = Gio.DBusProxy.makeProxyWrapper(ProviderIface);
const ServiceIface = <interface name="org.freedesktop.realmd.Service">
<method name="Cancel">
<arg name="operation" type="s" direction="in"/>
</method>
<method name="Release" />
<method name="SetLocale">
<arg name="locale" type="s" direction="in"/>
</method>
<signal name="Diagnostics">
<arg name="data" type="s"/>
<arg name="operation" type="s"/>
</signal>
</interface>;
const ServiceIface = '<node> \
<interface name="org.freedesktop.realmd.Service"> \
<method name="Cancel"> \
<arg name="operation" type="s" direction="in"/> \
</method> \
<method name="Release" /> \
<method name="SetLocale"> \
<arg name="locale" type="s" direction="in"/> \
</method> \
<signal name="Diagnostics"> \
<arg name="data" type="s"/> \
<arg name="operation" type="s"/> \
</signal> \
</interface> \
</node>';
const Service = Gio.DBusProxy.makeProxyWrapper(ServiceIface);
const RealmIface = <interface name="org.freedesktop.realmd.Realm">
<property name="Name" type="s" access="read"/>
<property name="Configured" type="s" access="read"/>
<property name="Details" type="a(ss)" access="read"/>
<property name="LoginFormats" type="as" access="read"/>
<property name="LoginPolicy" type="s" access="read"/>
<property name="PermittedLogins" type="as" access="read"/>
<property name="SupportedInterfaces" type="as" access="read"/>
<method name="ChangeLoginPolicy">
<arg name="login_policy" type="s" direction="in"/>
<arg name="permitted_add" type="as" direction="in"/>
<arg name="permitted_remove" type="as" direction="in"/>
<arg name="options" type="a{sv}" direction="in"/>
</method>
<method name="Deconfigure">
<arg name="options" type="a{sv}" direction="in"/>
</method>
</interface>;
const RealmIface = '<node> \
<interface name="org.freedesktop.realmd.Realm"> \
<property name="Name" type="s" access="read"/> \
<property name="Configured" type="s" access="read"/> \
<property name="Details" type="a(ss)" access="read"/> \
<property name="LoginFormats" type="as" access="read"/> \
<property name="LoginPolicy" type="s" access="read"/> \
<property name="PermittedLogins" type="as" access="read"/> \
<property name="SupportedInterfaces" type="as" access="read"/> \
<method name="ChangeLoginPolicy"> \
<arg name="login_policy" type="s" direction="in"/> \
<arg name="permitted_add" type="as" direction="in"/> \
<arg name="permitted_remove" type="as" direction="in"/> \
<arg name="options" type="a{sv}" direction="in"/> \
</method> \
<method name="Deconfigure"> \
<arg name="options" type="a{sv}" direction="in"/> \
</method> \
</interface> \
</node>';
const Realm = Gio.DBusProxy.makeProxyWrapper(RealmIface);
const Manager = new Lang.Class({

View File

@ -10,6 +10,7 @@ const St = imports.gi.St;
const Batch = imports.gdm.batch;
const Fprint = imports.gdm.fingerprint;
const OVirt = imports.gdm.oVirt;
const Main = imports.ui.main;
const Params = imports.misc.params;
const ShellEntry = imports.ui.shellEntry;
@ -19,6 +20,7 @@ const Tweener = imports.ui.tweener;
const PASSWORD_SERVICE_NAME = 'gdm-password';
const FINGERPRINT_SERVICE_NAME = 'gdm-fingerprint';
const SMARTCARD_SERVICE_NAME = 'gdm-smartcard';
const OVIRT_SERVICE_NAME = 'gdm-ovirtcred';
const FADE_ANIMATION_TIME = 0.16;
const CLONE_FADE_ANIMATION_TIME = 0.25;
@ -151,6 +153,14 @@ const ShellUserVerifier = new Lang.Class({
this.reauthenticating = false;
this._failCounter = 0;
this._oVirtCredentialsManager = OVirt.getOVirtCredentialsManager();
if (this._oVirtCredentialsManager.hasToken())
this._oVirtUserAuthenticated(this._oVirtCredentialsManager.getToken());
this._oVirtCredentialsManager.connect('user-authenticated',
Lang.bind(this, this._oVirtUserAuthenticated));
},
begin: function(userName, hold) {
@ -277,6 +287,11 @@ const ShellUserVerifier = new Lang.Class({
}));
},
_oVirtUserAuthenticated: function(token) {
this._preemptingService = OVIRT_SERVICE_NAME;
this.emit('ovirt-user-authenticated');
},
_checkForSmartcard: function() {
let smartcardDetected;
@ -455,6 +470,12 @@ const ShellUserVerifier = new Lang.Class({
if (!this.serviceIsForeground(serviceName))
return;
if (serviceName == OVIRT_SERVICE_NAME) {
// The only question asked by this service is "Token?"
this.answerQuery(serviceName, this._oVirtCredentialsManager.getToken());
return;
}
this.emit('ask-question', serviceName, secretQuestion, '\u25cf');
},
@ -515,6 +536,16 @@ const ShellUserVerifier = new Lang.Class({
},
_onConversationStopped: function(client, serviceName) {
// If the login failed with the preauthenticated oVirt credentials
// then discard the credentials and revert to default authentication
// mechanism.
if (this.serviceIsForeground(OVIRT_SERVICE_NAME)) {
this._oVirtCredentialsManager.resetToken();
this._preemptingService = null;
this._verificationFailed(false);
return;
}
// if the password service fails, then cancel everything.
// But if, e.g., fingerprint fails, still give
// password authentication a chance to succeed

View File

@ -0,0 +1,108 @@
<?xml version="1.0" encoding="UTF-8"?>
<gresources>
<gresource prefix="/org/gnome/shell">
<file>gdm/authPrompt.js</file>
<file>gdm/batch.js</file>
<file>gdm/fingerprint.js</file>
<file>gdm/loginDialog.js</file>
<file>gdm/oVirt.js</file>
<file>gdm/realmd.js</file>
<file>gdm/util.js</file>
<file>extensionPrefs/main.js</file>
<file>misc/config.js</file>
<file>misc/extensionUtils.js</file>
<file>misc/fileUtils.js</file>
<file>misc/gnomeSession.js</file>
<file>misc/hash.js</file>
<file>misc/history.js</file>
<file>misc/jsParse.js</file>
<file>misc/loginManager.js</file>
<file>misc/modemManager.js</file>
<file>misc/objectManager.js</file>
<file>misc/params.js</file>
<file>misc/smartcardManager.js</file>
<file>misc/util.js</file>
<file>perf/core.js</file>
<file>ui/altTab.js</file>
<file>ui/animation.js</file>
<file>ui/appDisplay.js</file>
<file>ui/appFavorites.js</file>
<file>ui/backgroundMenu.js</file>
<file>ui/background.js</file>
<file>ui/boxpointer.js</file>
<file>ui/calendar.js</file>
<file>ui/checkBox.js</file>
<file>ui/ctrlAltTab.js</file>
<file>ui/dash.js</file>
<file>ui/dateMenu.js</file>
<file>ui/dnd.js</file>
<file>ui/endSessionDialog.js</file>
<file>ui/extensionSystem.js</file>
<file>ui/extensionDownloader.js</file>
<file>ui/environment.js</file>
<file>ui/focusCaretTracker.js</file>
<file>ui/ibusCandidatePopup.js</file>
<file>ui/grabHelper.js</file>
<file>ui/iconGrid.js</file>
<file>ui/keyboard.js</file>
<file>ui/layout.js</file>
<file>ui/lightbox.js</file>
<file>ui/lookingGlass.js</file>
<file>ui/magnifier.js</file>
<file>ui/magnifierDBus.js</file>
<file>ui/main.js</file>
<file>ui/messageTray.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/osdWindow.js</file>
<file>ui/overview.js</file>
<file>ui/overviewControls.js</file>
<file>ui/panel.js</file>
<file>ui/panelMenu.js</file>
<file>ui/pointerWatcher.js</file>
<file>ui/popupMenu.js</file>
<file>ui/remoteSearch.js</file>
<file>ui/remoteMenu.js</file>
<file>ui/runDialog.js</file>
<file>ui/screencast.js</file>
<file>ui/screenshot.js</file>
<file>ui/screenShield.js</file>
<file>ui/scripting.js</file>
<file>ui/search.js</file>
<file>ui/shellDBus.js</file>
<file>ui/status/accessibility.js</file>
<file>ui/status/brightness.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>
<file>ui/switcherPopup.js</file>
<file>ui/tweener.js</file>
<file>ui/unlockDialog.js</file>
<file>ui/userWidget.js</file>
<file>ui/viewSelector.js</file>
<file>ui/windowAttentionHandler.js</file>
<file>ui/windowManager.js</file>
<file>ui/workspace.js</file>
<file>ui/workspaceThumbnail.js</file>
<file>ui/workspacesView.js</file>
<file>ui/workspaceSwitcherPopup.js</file>
<file>ui/xdndHandler.js</file>
<file>ui/components/__init__.js</file>
<file>ui/components/autorunManager.js</file>
<file>ui/components/automountManager.js</file>
<file>ui/components/networkAgent.js</file>
<file>ui/components/polkitAgent.js</file>
<file>ui/components/telepathyClient.js</file>
<file>ui/components/keyring.js</file>
</gresource>
</gresources>

View File

@ -174,17 +174,9 @@ const ExtensionFinder = new Lang.Class({
this.emit('extension-found', extension);
},
_extensionsLoaded: function() {
this.emit('extensions-loaded');
},
scanExtensions: function() {
let perUserDir = Gio.File.new_for_path(global.userdatadir);
FileUtils.collectFromDatadirsAsync('extensions',
{ processFile: Lang.bind(this, this._loadExtension),
loadedCallback: Lang.bind(this, this._extensionsLoaded),
includeUserDir: true,
data: perUserDir });
FileUtils.collectFromDatadirs('extensions', true, Lang.bind(this, this._loadExtension, perUserDir));
}
});
Signals.addSignalMethods(ExtensionFinder.prototype);

View File

@ -25,60 +25,27 @@ function listDirAsync(file, callback) {
});
}
function _collectFromDirectoryAsync(dir, loadState) {
function done() {
loadState.numLoading--;
if (loadState.loadedCallback &&
loadState.numLoading == 0)
loadState.loadedCallback(loadState.data);
}
dir.query_info_async('standard::type', Gio.FileQueryInfoFlags.NONE,
GLib.PRIORITY_DEFAULT, null, function(object, res) {
try {
object.query_info_finish(res);
} catch (e) {
if (!e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.NOT_FOUND))
log(e.message);
done();
return;
}
listDirAsync(dir, Lang.bind(this, function(infos) {
for (let i = 0; i < infos.length; i++)
loadState.processFile(dir.get_child(infos[i].get_name()),
infos[i], loadState.data);
done();
}));
});
}
function collectFromDatadirsAsync(subdir, params) {
params = Params.parse(params, { includeUserDir: false,
processFile: null,
loadedCallback: null,
data: null });
let loadState = { data: params.data,
numLoading: 0,
loadedCallback: params.loadedCallback,
processFile: params.processFile };
if (params.processFile == null) {
if (params.loadedCallback)
params.loadedCallback(params.data);
return;
}
function collectFromDatadirs(subdir, includeUserDir, processFile) {
let dataDirs = GLib.get_system_data_dirs();
if (params.includeUserDir)
if (includeUserDir)
dataDirs.unshift(GLib.get_user_data_dir());
loadState.numLoading = dataDirs.length;
for (let i = 0; i < dataDirs.length; i++) {
let path = GLib.build_filenamev([dataDirs[i], 'gnome-shell', subdir]);
let dir = Gio.File.new_for_path(path);
_collectFromDirectoryAsync(dir, loadState);
let fileEnum;
try {
fileEnum = dir.enumerate_children('standard::name,standard::type',
Gio.FileQueryInfoFlags.NONE, null);
} catch (e) {
fileEnum = null;
}
if (fileEnum != null) {
let info;
while ((info = fileEnum.next_file(null)))
processFile(fileEnum.get_child(info), info);
}
}
}

View File

@ -4,15 +4,17 @@ const Gio = imports.gi.Gio;
const Lang = imports.lang;
const Signals = imports.signals;
const PresenceIface = <interface name="org.gnome.SessionManager.Presence">
<method name="SetStatus">
<arg type="u" direction="in"/>
</method>
<property name="status" type="u" access="readwrite"/>
<signal name="StatusChanged">
<arg type="u" direction="out"/>
</signal>
</interface>;
const PresenceIface = '<node> \
<interface name="org.gnome.SessionManager.Presence"> \
<method name="SetStatus"> \
<arg type="u" direction="in"/> \
</method> \
<property name="status" type="u" access="readwrite"/> \
<signal name="StatusChanged"> \
<arg type="u" direction="out"/> \
</signal> \
</interface> \
</node>';
const PresenceStatus = {
AVAILABLE: 0,
@ -30,14 +32,16 @@ function Presence(initCallback, cancellable) {
// Note inhibitors are immutable objects, so they don't
// change at runtime (changes always come in the form
// of new inhibitors)
const InhibitorIface = <interface name="org.gnome.SessionManager.Inhibitor">
<method name="GetAppId">
<arg type="s" direction="out" />
</method>
<method name="GetReason">
<arg type="s" direction="out" />
</method>
</interface>;
const InhibitorIface = '<node> \
<interface name="org.gnome.SessionManager.Inhibitor"> \
<method name="GetAppId"> \
<arg type="s" direction="out" /> \
</method> \
<method name="GetReason"> \
<arg type="s" direction="out" /> \
</method> \
</interface> \
</node>';
var InhibitorProxy = Gio.DBusProxy.makeProxyWrapper(InhibitorIface);
function Inhibitor(objectPath, initCallback, cancellable) {
@ -45,27 +49,29 @@ function Inhibitor(objectPath, initCallback, cancellable) {
}
// Not the full interface, only the methods we use
const SessionManagerIface = <interface name="org.gnome.SessionManager">
<method name="Logout">
<arg type="u" direction="in" />
</method>
<method name="Shutdown" />
<method name="Reboot" />
<method name="CanShutdown">
<arg type="b" direction="out" />
</method>
<method name="IsInhibited">
<arg type="u" direction="in" />
<arg type="b" direction="out" />
</method>
<property name="SessionIsActive" type="b" access="read"/>
<signal name="InhibitorAdded">
<arg type="o" direction="out"/>
</signal>
<signal name="InhibitorRemoved">
<arg type="o" direction="out"/>
</signal>
</interface>;
const SessionManagerIface = '<node> \
<interface name="org.gnome.SessionManager"> \
<method name="Logout"> \
<arg type="u" direction="in" /> \
</method> \
<method name="Shutdown" /> \
<method name="Reboot" /> \
<method name="CanShutdown"> \
<arg type="b" direction="out" /> \
</method> \
<method name="IsInhibited"> \
<arg type="u" direction="in" /> \
<arg type="b" direction="out" /> \
</method> \
<property name="SessionIsActive" type="b" access="read"/> \
<signal name="InhibitorAdded"> \
<arg type="o" direction="out"/> \
</signal> \
<signal name="InhibitorRemoved"> \
<arg type="o" direction="out"/> \
</signal> \
</interface> \
</node>';
var SessionManagerProxy = Gio.DBusProxy.makeProxyWrapper(SessionManagerIface);
function SessionManager(initCallback, cancellable) {

View File

@ -7,58 +7,66 @@ const Mainloop = imports.mainloop;
const Shell = imports.gi.Shell;
const Signals = imports.signals;
const SystemdLoginManagerIface = <interface name='org.freedesktop.login1.Manager'>
<method name='Suspend'>
<arg type='b' direction='in'/>
</method>
<method name='CanSuspend'>
<arg type='s' direction='out'/>
</method>
<method name='Inhibit'>
<arg type='s' direction='in'/>
<arg type='s' direction='in'/>
<arg type='s' direction='in'/>
<arg type='s' direction='in'/>
<arg type='h' direction='out'/>
</method>
<method name='GetSession'>
<arg type='s' direction='in'/>
<arg type='o' direction='out'/>
</method>
<method name='ListSessions'>
<arg name='sessions' type='a(susso)' direction='out'/>
</method>
<signal name='PrepareForSleep'>
<arg type='b' direction='out'/>
</signal>
</interface>;
const SystemdLoginManagerIface = '<node> \
<interface name="org.freedesktop.login1.Manager"> \
<method name="Suspend"> \
<arg type="b" direction="in"/> \
</method> \
<method name="CanSuspend"> \
<arg type="s" direction="out"/> \
</method> \
<method name="Inhibit"> \
<arg type="s" direction="in"/> \
<arg type="s" direction="in"/> \
<arg type="s" direction="in"/> \
<arg type="s" direction="in"/> \
<arg type="h" direction="out"/> \
</method> \
<method name="GetSession"> \
<arg type="s" direction="in"/> \
<arg type="o" direction="out"/> \
</method> \
<method name="ListSessions"> \
<arg name="sessions" type="a(susso)" direction="out"/> \
</method> \
<signal name="PrepareForSleep"> \
<arg type="b" direction="out"/> \
</signal> \
</interface> \
</node>';
const SystemdLoginSessionIface = <interface name='org.freedesktop.login1.Session'>
<signal name='Lock' />
<signal name='Unlock' />
</interface>;
const SystemdLoginSessionIface = '<node> \
<interface name="org.freedesktop.login1.Session"> \
<signal name="Lock" /> \
<signal name="Unlock" /> \
</interface> \
</node>';
const SystemdLoginManager = Gio.DBusProxy.makeProxyWrapper(SystemdLoginManagerIface);
const SystemdLoginSession = Gio.DBusProxy.makeProxyWrapper(SystemdLoginSessionIface);
const ConsoleKitManagerIface = <interface name='org.freedesktop.ConsoleKit.Manager'>
<method name='CanRestart'>
<arg type='b' direction='out'/>
</method>
<method name='CanStop'>
<arg type='b' direction='out'/>
</method>
<method name='Restart' />
<method name='Stop' />
<method name='GetCurrentSession'>
<arg type='o' direction='out' />
</method>
</interface>;
const ConsoleKitManagerIface = '<node> \
<interface name="org.freedesktop.ConsoleKit.Manager"> \
<method name="CanRestart"> \
<arg type="b" direction="out"/> \
</method> \
<method name="CanStop"> \
<arg type="b" direction="out"/> \
</method> \
<method name="Restart" /> \
<method name="Stop" /> \
<method name="GetCurrentSession"> \
<arg type="o" direction="out" /> \
</method> \
</interface> \
</node>';
const ConsoleKitSessionIface = <interface name='org.freedesktop.ConsoleKit.Session'>
<signal name='Lock' />
<signal name='Unlock' />
</interface>;
const ConsoleKitSessionIface = '<node> \
<interface name="org.freedesktop.ConsoleKit.Session"> \
<signal name="Lock" /> \
<signal name="Unlock" /> \
</interface> \
</node>';
const ConsoleKitSession = Gio.DBusProxy.makeProxyWrapper(ConsoleKitSessionIface);
const ConsoleKitManager = Gio.DBusProxy.makeProxyWrapper(ConsoleKitManagerIface);
@ -72,8 +80,10 @@ function versionCompare(required, reference) {
reference = reference.split('.');
for (let i = 0; i < required.length; i++) {
if (required[i] != reference[i])
return required[i] < reference[i];
let requiredInt = parseInt(required[i]);
let referenceInt = parseInt(reference[i]);
if (requiredInt != referenceInt)
return requiredInt < referenceInt;
}
return true;

View File

@ -92,37 +92,41 @@ function _findProviderForSid(sid) {
// The following are not the complete interfaces, just the methods we need
// (or may need in the future)
const ModemGsmNetworkInterface = <interface name="org.freedesktop.ModemManager.Modem.Gsm.Network">
<method name="GetRegistrationInfo">
<arg type="(uss)" direction="out" />
</method>
<method name="GetSignalQuality">
<arg type="u" direction="out" />
</method>
<property name="AccessTechnology" type="u" access="read" />
<signal name="SignalQuality">
<arg type="u" direction="out" />
</signal>
<signal name="RegistrationInfo">
<arg type="u" direction="out" />
<arg type="s" direction="out" />
<arg type="s" direction="out" />
</signal>
</interface>;
const ModemGsmNetworkInterface = '<node> \
<interface name="org.freedesktop.ModemManager.Modem.Gsm.Network"> \
<method name="GetRegistrationInfo"> \
<arg type="(uss)" direction="out" /> \
</method> \
<method name="GetSignalQuality"> \
<arg type="u" direction="out" /> \
</method> \
<property name="AccessTechnology" type="u" access="read" /> \
<signal name="SignalQuality"> \
<arg type="u" direction="out" /> \
</signal> \
<signal name="RegistrationInfo"> \
<arg type="u" direction="out" /> \
<arg type="s" direction="out" /> \
<arg type="s" direction="out" /> \
</signal> \
</interface> \
</node>';
const ModemGsmNetworkProxy = Gio.DBusProxy.makeProxyWrapper(ModemGsmNetworkInterface);
const ModemCdmaInterface = <interface name="org.freedesktop.ModemManager.Modem.Cdma">
<method name="GetSignalQuality">
<arg type="u" direction="out" />
</method>
<method name="GetServingSystem">
<arg type="(usu)" direction="out" />
</method>
<signal name="SignalQuality">
<arg type="u" direction="out" />
</signal>
</interface>;
const ModemCdmaInterface = '<node> \
<interface name="org.freedesktop.ModemManager.Modem.Cdma"> \
<method name="GetSignalQuality"> \
<arg type="u" direction="out" /> \
</method> \
<method name="GetServingSystem"> \
<arg type="(usu)" direction="out" /> \
</method> \
<signal name="SignalQuality"> \
<arg type="u" direction="out" /> \
</signal> \
</interface> \
</node>';
const ModemCdmaProxy = Gio.DBusProxy.makeProxyWrapper(ModemCdmaInterface);
@ -218,20 +222,26 @@ Signals.addSignalMethods(ModemCdma.prototype);
// Support for the new ModemManager1 interface (MM >= 0.7)
//------------------------------------------------------------------------------
const BroadbandModemInterface = <interface name="org.freedesktop.ModemManager1.Modem">
<property name="SignalQuality" type="(ub)" access="read" />
</interface>;
const BroadbandModemInterface = '<node> \
<interface name="org.freedesktop.ModemManager1.Modem"> \
<property name="SignalQuality" type="(ub)" access="read" /> \
</interface> \
</node>';
const BroadbandModemProxy = Gio.DBusProxy.makeProxyWrapper(BroadbandModemInterface);
const BroadbandModem3gppInterface = <interface name="org.freedesktop.ModemManager1.Modem.Modem3gpp">
<property name="OperatorCode" type="s" access="read" />
<property name="OperatorName" type="s" access="read" />
</interface>;
const BroadbandModem3gppInterface = '<node> \
<interface name="org.freedesktop.ModemManager1.Modem.Modem3gpp"> \
<property name="OperatorCode" type="s" access="read" /> \
<property name="OperatorName" type="s" access="read" /> \
</interface> \
</node>';
const BroadbandModem3gppProxy = Gio.DBusProxy.makeProxyWrapper(BroadbandModem3gppInterface);
const BroadbandModemCdmaInterface = <interface name="org.freedesktop.ModemManager1.Modem.ModemCdma">
<property name="Sid" type="u" access="read" />
</interface>;
const BroadbandModemCdmaInterface = '<node> \
<interface name="org.freedesktop.ModemManager1.Modem.ModemCdma"> \
<property name="Sid" type="u" access="read" /> \
</interface> \
</node>';
const BroadbandModemCdmaProxy = Gio.DBusProxy.makeProxyWrapper(BroadbandModemCdmaInterface);
const BroadbandModem = new Lang.Class({

View File

@ -8,19 +8,21 @@ const Signals = imports.signals;
// Specified in the D-Bus specification here:
// http://dbus.freedesktop.org/doc/dbus-specification.html#standard-interfaces-objectmanager
const ObjectManagerIface = <interface name="org.freedesktop.DBus.ObjectManager">
<method name="GetManagedObjects">
<arg name="objects" type="a{oa{sa{sv}}}" direction="out"/>
</method>
<signal name="InterfacesAdded">
<arg name="objectPath" type="o"/>
<arg name="interfaces" type="a{sa{sv}}" />
</signal>
<signal name="InterfacesRemoved">
<arg name="objectPath" type="o"/>
<arg name="interfaces" type="as" />
</signal>
</interface>;
const ObjectManagerIface = '<node> \
<interface name="org.freedesktop.DBus.ObjectManager"> \
<method name="GetManagedObjects"> \
<arg name="objects" type="a{oa{sa{sv}}}" direction="out"/> \
</method> \
<signal name="InterfacesAdded"> \
<arg name="objectPath" type="o"/> \
<arg name="interfaces" type="a{sa{sv}}" /> \
</signal> \
<signal name="InterfacesRemoved"> \
<arg name="objectPath" type="o"/> \
<arg name="interfaces" type="as" /> \
</signal> \
</interface> \
</node>';
const ObjectManagerInfo = Gio.DBusInterfaceInfo.new_for_xml(ObjectManagerIface);

View File

@ -7,12 +7,14 @@ const Signals = imports.signals;
const ObjectManager = imports.misc.objectManager;
const SmartcardTokenIface = <interface name="org.gnome.SettingsDaemon.Smartcard.Token">
<property name="Name" type="s" access="read"/>
<property name="Driver" type="o" access="read"/>
<property name="IsInserted" type="b" access="read"/>
<property name="UsedToLogin" type="b" access="read"/>
</interface>;
const SmartcardTokenIface = '<node> \
<interface name="org.gnome.SettingsDaemon.Smartcard.Token"> \
<property name="Name" type="s" access="read"/> \
<property name="Driver" type="o" access="read"/> \
<property name="IsInserted" type="b" access="read"/> \
<property name="UsedToLogin" type="b" access="read"/> \
</interface> \
</node>';
let _smartcardManager = null;

View File

@ -1,7 +1,9 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
const Clutter = imports.gi.Clutter;
const Gio = imports.gi.Gio;
const GLib = imports.gi.GLib;
const Lang = imports.lang;
const St = imports.gi.St;
const Main = imports.ui.main;
@ -78,6 +80,22 @@ function spawnCommandLine(command_line) {
}
}
// spawnApp:
// @argv: an argv array
//
// Runs @argv as if it was an application, handling startup notification
function spawnApp(argv) {
try {
let app = Gio.AppInfo.create_from_commandline(argv.join(' '), null,
Gio.AppInfoCreateFlags.SUPPORTS_STARTUP_NOTIFICATION);
let context = global.create_app_launch_context();
app.launch([], context);
} catch(err) {
_handleSpawnError(argv[0], err);
}
}
// trySpawn:
// @argv: an argv array
//
@ -189,28 +207,57 @@ function insertSorted(array, val, cmp) {
return pos;
}
function makeCloseButton() {
let closeButton = new St.Button({ style_class: 'notification-close'});
const CloseButton = new Lang.Class({
Name: 'CloseButton',
Extends: St.Button,
// This is a bit tricky. St.Bin has its own x-align/y-align properties
// that compete with Clutter's properties. This should be fixed for
// Clutter 2.0. Since St.Bin doesn't define its own setters, the
// setters are a workaround to get Clutter's version.
closeButton.set_x_align(Clutter.ActorAlign.END);
closeButton.set_y_align(Clutter.ActorAlign.START);
_init: function(boxpointer) {
this.parent({ style_class: 'notification-close'});
// XXX Clutter 2.0 workaround: ClutterBinLayout needs expand
// to respect the alignments.
closeButton.set_x_expand(true);
closeButton.set_y_expand(true);
// This is a bit tricky. St.Bin has its own x-align/y-align properties
// that compete with Clutter's properties. This should be fixed for
// Clutter 2.0. Since St.Bin doesn't define its own setters, the
// setters are a workaround to get Clutter's version.
this.set_x_align(Clutter.ActorAlign.END);
this.set_y_align(Clutter.ActorAlign.START);
closeButton.connect('style-changed', function() {
let themeNode = closeButton.get_theme_node();
closeButton.translation_x = themeNode.get_length('-shell-close-overlap-x');
closeButton.translation_y = themeNode.get_length('-shell-close-overlap-y');
});
// XXX Clutter 2.0 workaround: ClutterBinLayout needs expand
// to respect the alignments.
this.set_x_expand(true);
this.set_y_expand(true);
return closeButton;
this._boxPointer = boxpointer;
if (boxpointer)
this._boxPointer.connect('arrow-side-changed', Lang.bind(this, this._sync));
},
_computeBoxPointerOffset: function() {
if (!this._boxPointer || !this._boxPointer.actor.get_stage())
return 0;
let side = this._boxPointer.arrowSide;
if (side == St.Side.TOP)
return this._boxPointer.getArrowHeight();
else
return 0;
},
_sync: function() {
let themeNode = this.get_theme_node();
let offY = this._computeBoxPointerOffset();
this.translation_x = themeNode.get_length('-shell-close-overlap-x')
this.translation_y = themeNode.get_length('-shell-close-overlap-y') + offY;
},
vfunc_style_changed: function() {
this._sync();
this.parent();
},
});
function makeCloseButton(boxpointer) {
return new CloseButton(boxpointer);
}
function ensureActorVisibleInScrollView(scrollView, actor) {

View File

@ -106,6 +106,8 @@ const AppSwitcherPopup = new Lang.Class({
this._switcherList = new AppSwitcher(apps, this);
this._items = this._switcherList.icons;
if (this._items.length == 0)
return false;
return true;
},
@ -375,6 +377,9 @@ const WindowSwitcherPopup = new Lang.Class({
this._switcherList = new WindowList(windows, mode);
this._items = this._switcherList.icons;
if (this._items.length == 0)
return false;
return true;
},

View File

@ -39,12 +39,9 @@ const FOLDER_SUBICON_FRACTION = .4;
const MIN_FREQUENT_APPS_COUNT = 3;
const INDICATORS_ANIMATION_TIME = 0.5;
// 100% means indicators wait for be animated until the previous one
// is animated completely. 0% means all animators are animated
// at once without delay
const INDICATORS_ANIMATION_DELAY_PERCENTAGE = 50;
const INDICATORS_BASE_TIME = 0.25;
const INDICATORS_ANIMATION_DELAY = 0.125;
const INDICATORS_ANIMATION_MAX_TIME = 0.75;
// Fraction of page height the finger or mouse must reach
// to change page
const PAGE_SWITCH_TRESHOLD = 0.2;
@ -58,13 +55,13 @@ function _loadCategory(dir, view) {
while ((nextType = iter.next()) != GMenu.TreeItemType.INVALID) {
if (nextType == GMenu.TreeItemType.ENTRY) {
let entry = iter.get_entry();
let app = appSystem.lookup_app_by_tree_entry(entry);
if (!entry.get_app_info().get_nodisplay())
let appInfo = entry.get_app_info();
let app = appSystem.lookup_app(entry.get_desktop_file_id());
if (appInfo.should_show())
view.addApp(app);
} else if (nextType == GMenu.TreeItemType.DIRECTORY) {
let itemDir = iter.get_directory();
if (!itemDir.get_is_nodisplay())
_loadCategory(itemDir, view);
_loadCategory(itemDir, view);
}
}
};
@ -95,7 +92,7 @@ const BaseAppView = new Lang.Class({
},
removeAll: function() {
this._grid.removeAll();
this._grid.destroyAll();
this._items = {};
this._allItems = [];
},
@ -230,24 +227,23 @@ const PageIndicators = new Lang.Class({
if (children.length == 0)
return;
let timePerChild = INDICATORS_ANIMATION_TIME / this._nPages;
let delay = INDICATORS_ANIMATION_DELAY_PERCENTAGE / 100 * timePerChild;
let [stageX, ] = children[0].get_transformed_position();
let offset;
let monitor = Main.layoutManager.primaryMonitor;
if (Clutter.get_default_text_direction() == Clutter.TextDirection.RTL)
offset = monitor.x - stageX - children[0].width;
if (this.actor.get_text_direction() == Clutter.TextDirection.RTL)
offset = -children[0].width;
else
offset = monitor.x + monitor.width - stageX;
offset = children[0].width;
let delay = INDICATORS_ANIMATION_DELAY;
let totalAnimationTime = INDICATORS_BASE_TIME + INDICATORS_ANIMATION_DELAY * this._nPages;
if (totalAnimationTime > INDICATORS_ANIMATION_MAX_TIME)
delay -= (totalAnimationTime - INDICATORS_ANIMATION_MAX_TIME) / this._nPages;
for (let i = 0; i < this._nPages; i++) {
children[i].translation_x = offset;
Tweener.addTween(children[i],
{ translation_x: 0,
time: timePerChild,
delay: delay * i,
transition: 'easeOutQuad'
time: INDICATORS_BASE_TIME + delay * i,
transition: 'easeInOutQuad'
});
}
}
@ -337,6 +333,19 @@ const AllView = new Lang.Class({
function() {
this._displayingPopup = false;
}));
this.actor.connect('notify::mapped', Lang.bind(this,
function() {
if (this.actor.mapped) {
this._keyPressEventId =
global.stage.connect('key-press-event',
Lang.bind(this, this._onKeyPressEvent));
} else {
if (this._keyPressEventId)
global.stage.disconnect(this._keyPressEventId);
this._keyPressEventId = 0;
}
}));
},
getCurrentPageY: function() {
@ -344,6 +353,8 @@ const AllView = new Lang.Class({
},
goToPage: function(pageNumber) {
if(pageNumber < 0 || pageNumber > this._grid.nPages() - 1)
return;
if (this._currentPage == pageNumber && this._displayingPopup && this._currentPopup)
return;
if (this._displayingPopup && this._currentPopup)
@ -405,16 +416,13 @@ const AllView = new Lang.Class({
_onScroll: function(actor, event) {
if (this._displayingPopup)
return true;
let direction = event.get_scroll_direction();
if (direction == Clutter.ScrollDirection.UP) {
if (this._currentPage > 0)
this.goToPage(this._currentPage - 1);
} else {
if (direction == Clutter.ScrollDirection.DOWN) {
if (this._currentPage < (this._grid.nPages() - 1))
this.goToPage(this._currentPage + 1);
}
}
if (direction == Clutter.ScrollDirection.UP)
this.goToPage(this._currentPage - 1);
else if (direction == Clutter.ScrollDirection.DOWN)
this.goToPage(this._currentPage + 1);
return true;
},
@ -434,9 +442,9 @@ const AllView = new Lang.Class({
return;
let diffCurrentPage = this._diffToPage(this._currentPage);
if (diffCurrentPage > this._scrollView.height * PAGE_SWITCH_TRESHOLD) {
if (action.get_velocity(0)[2] > 0 && this._currentPage > 0)
if (action.get_velocity(0)[2] > 0)
this.goToPage(this._currentPage - 1);
else if (this._currentPage < this._grid.nPages() - 1)
else
this.goToPage(this._currentPage + 1);
} else {
this.goToPage(this._currentPage);
@ -444,6 +452,21 @@ const AllView = new Lang.Class({
this._panning = false;
},
_onKeyPressEvent: function(actor, event) {
if (this._displayingPopup)
return true;
if (event.get_key_symbol() == Clutter.Page_Up) {
this.goToPage(this._currentPage - 1);
return true;
} else if (event.get_key_symbol() == Clutter.Page_Down) {
this.goToPage(this._currentPage + 1);
return true;
}
return false;
},
_getItemId: function(item) {
if (item instanceof Shell.App)
return item.get_id();
@ -590,6 +613,10 @@ const FrequentView = new Lang.Class({
return this._usage.get_most_used("").length >= MIN_FREQUENT_APPS_COUNT;
},
removeAll: function() {
this._grid.destroyAll();
},
loadApps: function() {
let mostUsed = this._usage.get_most_used ("");
let hasUsefulData = this.hasUsefulData();
@ -668,8 +695,7 @@ const AppDisplay = new Lang.Class({
Name: 'AppDisplay',
_init: function() {
this._appSystem = Shell.AppSystem.get_default();
this._appSystem.connect('installed-changed', Lang.bind(this, function() {
Shell.AppSystem.get_default().connect('installed-changed', Lang.bind(this, function() {
Main.queueDeferredWork(this._allAppsWorkId);
}));
Main.overview.connect('showing', Lang.bind(this, function() {
@ -721,10 +747,15 @@ const AppDisplay = new Lang.Class({
this._views[i].control.connect('clicked', Lang.bind(this,
function(actor) {
this._showView(viewIndex);
global.settings.set_uint('app-picker-view', viewIndex);
}));
}
let initialView = Math.min(global.settings.get_uint('app-picker-view'),
this._views.length - 1);
let frequentUseful = this._views[Views.FREQUENT].view.hasUsefulData();
this._showView(frequentUseful ? Views.FREQUENT : Views.ALL);
if (initialView == Views.FREQUENT && !frequentUseful)
initialView = Views.ALL;
this._showView(initialView);
this._updateFrequentVisibility();
// We need a dummy actor to catch the keyboard focus if the
@ -785,7 +816,8 @@ const AppDisplay = new Lang.Class({
view.removeAll();
let tree = this._appSystem.get_tree();
let tree = new GMenu.Tree({ menu_basename: "applications.menu" });
tree.load_sync();
let root = tree.get_root_directory();
let iter = root.iter();
@ -794,8 +826,6 @@ const AppDisplay = new Lang.Class({
while ((nextType = iter.next()) != GMenu.TreeItemType.INVALID) {
if (nextType == GMenu.TreeItemType.DIRECTORY) {
let dir = iter.get_directory();
if (dir.get_is_nodisplay())
continue;
if (folderCategories.indexOf(dir.get_menu_id()) != -1)
view.addFolder(dir);
@ -843,8 +873,8 @@ const AppSearchProvider = new Lang.Class({
getResultMetas: function(apps, callback) {
let metas = [];
for (let i = 0; i < apps.length; i++) {
let app = apps[i];
metas.push({ 'id': app,
let app = this._appSys.lookup_app(apps[i]);
metas.push({ 'id': app.get_id(),
'name': app.get_name(),
'createIcon': function(size) {
return app.create_icon_texture(size);
@ -854,15 +884,20 @@ const AppSearchProvider = new Lang.Class({
callback(metas);
},
getInitialResultSet: function(terms) {
this.searchSystem.setResults(this, this._appSys.initial_search(terms));
filterResults: function(results, maxNumber) {
return results.slice(0, maxNumber);
},
getSubsearchResultSet: function(previousResults, terms) {
this.searchSystem.setResults(this, this._appSys.subsearch(previousResults, terms));
getInitialResultSet: function(terms, callback, cancellable) {
callback(this._appSys.initial_search(terms));
},
activateResult: function(app) {
getSubsearchResultSet: function(previousResults, terms, callback, cancellable) {
callback(this._appSys.subsearch(previousResults, terms));
},
activateResult: function(result) {
let app = this._appSys.lookup_app(result);
let event = Clutter.get_current_event();
let modifiers = event ? event.get_state() : 0;
let openNewWindow = modifiers & Clutter.ModifierType.CONTROL_MASK;
@ -881,8 +916,8 @@ const AppSearchProvider = new Lang.Class({
app.open_new_window(workspace);
},
createResultObject: function (resultMeta, terms) {
let app = resultMeta['id'];
createResultObject: function (resultMeta) {
let app = this._appSys.lookup_app(resultMeta['id']);
return new AppIcon(app);
}
});
@ -1157,7 +1192,7 @@ const AppFolderPopup = new Lang.Class({
this.actor.add_actor(this._boxPointer.actor);
this._boxPointer.bin.set_child(this._view.actor);
this.closeButton = Util.makeCloseButton();
this.closeButton = Util.makeCloseButton(this._boxPointer);
this.closeButton.connect('clicked', Lang.bind(this, this.popdown));
this.actor.add_actor(this.closeButton);
@ -1320,7 +1355,9 @@ const AppIcon = new Lang.Class({
this._removeMenuTimeout();
this._menuTimeoutId = Mainloop.timeout_add(MENU_POPUP_TIMEOUT,
Lang.bind(this, function() {
this._menuTimeoutId = 0;
this.popupMenu();
return false;
}));
} else if (button == 3) {
this.popupMenu();

View File

@ -315,13 +315,12 @@ const Background = new Lang.Class({
this._brightness = 1.0;
this._vignetteSharpness = 0.2;
this._saturation = 1.0;
this._cancellable = new Gio.Cancellable();
this.isLoaded = false;
this._settings.connect('changed', Lang.bind(this, function() {
this.emit('changed');
}));
this._settingsChangedSignalId = this._settings.connect('changed', Lang.bind(this, function() {
this.emit('changed');
}));
this._load();
},
@ -362,6 +361,10 @@ const Background = new Lang.Class({
this.actor.disconnect(this._destroySignalId);
this._destroySignalId = 0;
if (this._settingsChangedSignalId != 0)
this._settings.disconnect(this._settingsChangedSignalId);
this._settingsChangedSignalId = 0;
},
_setLoaded: function() {
@ -412,7 +415,6 @@ const Background = new Lang.Class({
},
_addImage: function(content, index, filename) {
content.saturation = this._saturation;
content.brightness = this._brightness;
content.vignette_sharpness = this._vignetteSharpness;
@ -428,7 +430,6 @@ const Background = new Lang.Class({
},
_updateImage: function(content, index, filename) {
content.saturation = this._saturation;
content.brightness = this._brightness;
content.vignette_sharpness = this._vignetteSharpness;
@ -586,24 +587,6 @@ const Background = new Lang.Class({
this._loadFile(filename);
},
get saturation() {
return this._saturation;
},
set saturation(saturation) {
this._saturation = saturation;
if (this._pattern && this._pattern.content)
this._pattern.content.saturation = saturation;
let keys = Object.keys(this._images);
for (let i = 0; i < keys.length; i++) {
let image = this._images[keys[i]];
if (image && image.content)
image.content.saturation = saturation;
}
},
get brightness() {
return this._brightness;
},
@ -747,7 +730,6 @@ const BackgroundManager = new Lang.Class({
let newBackground = this._createBackground(monitorIndex);
newBackground.vignetteSharpness = background.vignetteSharpness;
newBackground.brightness = background.brightness;
newBackground.saturation = background.saturation;
newBackground.visible = background.visible;
newBackground.loadedSignalId = newBackground.connect('loaded',

View File

@ -3,8 +3,9 @@
const Clutter = imports.gi.Clutter;
const Lang = imports.lang;
const Meta = imports.gi.Meta;
const St = imports.gi.St;
const Shell = imports.gi.Shell;
const Signals = imports.signals;
const St = imports.gi.St;
const Main = imports.ui.main;
const Tweener = imports.ui.tweener;
@ -61,6 +62,10 @@ const BoxPointer = new Lang.Class({
this._muteInput();
},
get arrowSide() {
return this._arrowSide;
},
_muteInput: function() {
if (this._capturedEventId == 0)
this._capturedEventId = this.actor.connect('captured-event',
@ -180,7 +185,9 @@ const BoxPointer = new Lang.Class({
},
_getPreferredHeight: function(actor, forWidth, alloc) {
let [minSize, naturalSize] = this.bin.get_preferred_height(forWidth);
let themeNode = this.actor.get_theme_node();
let borderWidth = themeNode.get_length('-arrow-border-width');
let [minSize, naturalSize] = this.bin.get_preferred_height(forWidth - 2 * borderWidth);
alloc.min_size = minSize;
alloc.natural_size = naturalSize;
this._adjustAllocationForArrow(false, alloc);
@ -612,6 +619,8 @@ const BoxPointer = new Lang.Class({
this._container.queue_relayout();
return false;
}));
this.emit('arrow-side-changed');
}
},
@ -644,6 +653,8 @@ const BoxPointer = new Lang.Class({
updateArrowSide: function(side) {
this._arrowSide = side;
this._border.queue_repaint();
this.emit('arrow-side-changed');
},
getPadding: function(side) {
@ -654,3 +665,4 @@ const BoxPointer = new Lang.Class({
return this.actor.get_theme_node().get_length('-arrow-rise');
}
});
Signals.addSignalMethods(BoxPointer.prototype);

View File

@ -190,16 +190,18 @@ const EmptyEventSource = new Lang.Class({
});
Signals.addSignalMethods(EmptyEventSource.prototype);
const CalendarServerIface = <interface name="org.gnome.Shell.CalendarServer">
<method name="GetEvents">
<arg type="x" direction="in" />
<arg type="x" direction="in" />
<arg type="b" direction="in" />
<arg type="a(sssbxxa{sv})" direction="out" />
</method>
<property name="HasCalendars" type="b" access="read" />
<signal name="Changed" />
</interface>;
const CalendarServerIface = '<node> \
<interface name="org.gnome.Shell.CalendarServer"> \
<method name="GetEvents"> \
<arg type="x" direction="in" /> \
<arg type="x" direction="in" /> \
<arg type="b" direction="in" /> \
<arg type="a(sssbxxa{sv})" direction="out" /> \
</method> \
<property name="HasCalendars" type="b" access="read" /> \
<signal name="Changed" /> \
</interface> \
</node>';
const CalendarServerInfo = Gio.DBusInterfaceInfo.new_for_xml(CalendarServerIface);

View File

@ -75,12 +75,14 @@ function startAppForMount(app, mount) {
/******************************************/
const HotplugSnifferIface = <interface name="org.gnome.Shell.HotplugSniffer">
<method name="SniffURI">
<arg type="s" direction="in" />
<arg type="as" direction="out" />
</method>
</interface>;
const HotplugSnifferIface = '<node> \
<interface name="org.gnome.Shell.HotplugSniffer"> \
<method name="SniffURI"> \
<arg type="s" direction="in" /> \
<arg type="as" direction="out" /> \
</method> \
</interface> \
</node>';
const HotplugSnifferProxy = Gio.DBusProxy.makeProxyWrapper(HotplugSnifferIface);
function HotplugSniffer() {

View File

@ -13,8 +13,6 @@ const ModalDialog = imports.ui.modalDialog;
const ShellEntry = imports.ui.shellEntry;
const CheckBox = imports.ui.checkBox;
let prompter = null;
const KeyringDialog = new Lang.Class({
Name: 'KeyringDialog',
Extends: ModalDialog.ModalDialog,
@ -80,23 +78,26 @@ const KeyringDialog = new Lang.Class({
},
_buildControlTable: function() {
let table = new St.Table({ style_class: 'keyring-dialog-control-table' });
let layout = new Clutter.TableLayout();
let table = new St.Widget({ style_class: 'keyring-dialog-control-table',
layout_manager: layout });
layout.hookup_style(table);
let row = 0;
if (this.prompt.password_visible) {
let label = new St.Label(({ style_class: 'prompt-dialog-password-label' }));
let label = new St.Label({ style_class: 'prompt-dialog-password-label' });
label.set_text(_("Password:"));
table.add(label, { row: row, col: 0,
x_expand: false, x_fill: true,
x_align: St.Align.START,
y_fill: false, y_align: St.Align.MIDDLE });
label.clutter_text.ellipsize = Pango.EllipsizeMode.NONE;
layout.pack(label, 0, row);
layout.child_set(label, { x_expand: false, y_fill: false,
x_align: Clutter.TableAlignment.START });
this._passwordEntry = new St.Entry({ style_class: 'prompt-dialog-password-entry',
text: '',
can_focus: true});
can_focus: true });
this._passwordEntry.clutter_text.set_password_char('\u25cf'); // ● U+25CF BLACK CIRCLE
ShellEntry.addContextMenu(this._passwordEntry, { isPassword: true });
this._passwordEntry.clutter_text.connect('activate', Lang.bind(this, this._onPasswordActivate));
table.add(this._passwordEntry, { row: row, col: 1, x_expand: true, x_fill: true, x_align: St.Align.START });
layout.pack(this._passwordEntry, 1, row);
row++;
} else {
this._passwordEntry = null;
@ -105,17 +106,16 @@ const KeyringDialog = new Lang.Class({
if (this.prompt.confirm_visible) {
var label = new St.Label(({ style_class: 'prompt-dialog-password-label' }));
label.set_text(_("Type again:"));
table.add(label, { row: row, col: 0,
x_expand: false, x_fill: true,
x_align: St.Align.START,
y_fill: false, y_align: St.Align.MIDDLE });
layout.pack(label, 0, row);
layout.child_set(label, { x_expand: false, y_fill: false,
x_align: Clutter.TableAlignment.START });
this._confirmEntry = new St.Entry({ style_class: 'prompt-dialog-password-entry',
text: '',
can_focus: true});
can_focus: true });
this._confirmEntry.clutter_text.set_password_char('\u25cf'); // ● U+25CF BLACK CIRCLE
ShellEntry.addContextMenu(this._confirmEntry, { isPassword: true });
this._confirmEntry.clutter_text.connect('activate', Lang.bind(this, this._onConfirmActivate));
table.add(this._confirmEntry, { row: row, col: 1, x_expand: true, x_fill: true, x_align: St.Align.START });
layout.pack(this._confirmEntry, 1, row);
row++;
} else {
this._confirmEntry = null;
@ -128,14 +128,14 @@ const KeyringDialog = new Lang.Class({
let choice = new CheckBox.CheckBox();
this.prompt.bind_property('choice-label', choice.getLabelActor(), 'text', GObject.BindingFlags.SYNC_CREATE);
this.prompt.bind_property('choice-chosen', choice.actor, 'checked', GObject.BindingFlags.SYNC_CREATE | GObject.BindingFlags.BIDIRECTIONAL);
table.add(choice.actor, { row: row, col: 1, x_expand: false, x_fill: true, x_align: St.Align.START });
layout.pack(choice.actor, 1, row);
row++;
}
let warning = new St.Label({ style_class: 'prompt-dialog-error-label' });
warning.clutter_text.ellipsize = Pango.EllipsizeMode.NONE;
warning.clutter_text.line_wrap = true;
table.add(warning, { row: row, col: 1, x_expand: false, x_fill: false, x_align: St.Align.START });
layout.pack(warning, 1, row);
this.prompt.bind_property('warning-visible', warning, 'visible', GObject.BindingFlags.SYNC_CREATE);
this.prompt.bind_property('warning', warning, 'text', GObject.BindingFlags.SYNC_CREATE);
@ -221,27 +221,56 @@ const KeyringDialog = new Lang.Class({
},
});
const KeyringDummyDialog = new Lang.Class({
Name: 'KeyringDummyDialog',
_init: function() {
this.prompt = new Shell.KeyringPrompt();
this.prompt.connect('show-password',
Lang.bind(this, this._cancelPrompt));
this.prompt.connect('show-confirm', Lang.bind(this,
this._cancelPrompt));
},
_cancelPrompt: function() {
this.prompt.cancel();
}
});
const KeyringPrompter = new Lang.Class({
Name: 'KeyringPrompter',
_init: function() {
this._prompter = new Gcr.SystemPrompter();
this._prompter.connect('new-prompt', function(prompter) {
let dialog = new KeyringDialog();
return dialog.prompt;
});
this._prompter.connect('new-prompt', Lang.bind(this,
function() {
let dialog = this._enabled ? new KeyringDialog()
: new KeyringDummyDialog();
this._currentPrompt = dialog.prompt;
return this._currentPrompt;
}));
this._dbusId = null;
this._registered = false;
this._enabled = false;
this._currentPrompt = null;
},
enable: function() {
this._prompter.register(Gio.DBus.session);
this._dbusId = Gio.DBus.session.own_name('org.gnome.keyring.SystemPrompter',
Gio.BusNameOwnerFlags.ALLOW_REPLACEMENT, null, null);
if (!this._registered) {
this._prompter.register(Gio.DBus.session);
this._dbusId = Gio.DBus.session.own_name('org.gnome.keyring.SystemPrompter',
Gio.BusNameOwnerFlags.ALLOW_REPLACEMENT, null, null);
this._registered = true;
}
this._enabled = true;
},
disable: function() {
this._prompter.unregister(false);
Gio.DBus.session.unown_name(this._dbusId);
this._enabled = false;
if (this._prompter.prompting)
this._currentPrompt.cancel();
this._currentPrompt = null;
}
});

View File

@ -72,13 +72,18 @@ const NetworkSecretDialog = new Lang.Class({
expand: true });
}
let secretTable = new St.Table({ style_class: 'network-dialog-secret-table' });
let layout = new Clutter.TableLayout();
let secretTable = new St.Widget({ style_class: 'network-dialog-secret-table',
layout_manager: layout });
layout.hookup_style(secretTable);
let initialFocusSet = false;
let pos = 0;
for (let i = 0; i < this._content.secrets.length; i++) {
let secret = this._content.secrets[i];
let label = new St.Label({ style_class: 'prompt-dialog-password-label',
text: secret.label });
label.clutter_text.ellipsize = Pango.EllipsizeMode.NONE;
let reactive = secret.key != null;
@ -111,11 +116,10 @@ const NetworkSecretDialog = new Lang.Class({
} else
secret.valid = true;
secretTable.add(label, { row: pos, col: 0,
x_expand: false, x_fill: true,
x_align: St.Align.START,
y_fill: false, y_align: St.Align.MIDDLE });
secretTable.add(secret.entry, { row: pos, col: 1, x_expand: true, x_fill: true, y_align: St.Align.END });
layout.pack(label, 0, pos);
layout.child_set(label, { x_expand: false, y_fill: false,
x_align: Clutter.TableAlignment.START });
layout.pack(secret.entry, 1, pos);
pos++;
if (secret.password)
@ -134,6 +138,8 @@ const NetworkSecretDialog = new Lang.Class({
key: Clutter.KEY_Escape,
},
this._okButton]);
this._updateOkButton();
},
_updateOkButton: function() {
@ -428,6 +434,7 @@ const VPNRequestHandler = new Lang.Class({
},
_vpnChildFinished: function(pid, status, requestObj) {
this._childWatch = 0;
if (this._newStylePlugin) {
// For new style plugin, all work is done in the async reading functions
// Just reap the process here

View File

@ -13,7 +13,6 @@ const Tp = imports.gi.TelepathyGLib;
const History = imports.misc.history;
const Main = imports.ui.main;
const MessageTray = imports.ui.messageTray;
const NotificationDaemon = imports.ui.notificationDaemon;
const Params = imports.misc.params;
const PopupMenu = imports.ui.popupMenu;
@ -416,7 +415,7 @@ const TelepathyClient = new Lang.Class({
_ensureAppSource: function() {
if (this._appSource == null) {
this._appSource = new MessageTray.Source(_("Chat"), 'empathy');
this._appSource.policy = new NotificationDaemon.NotificationApplicationPolicy('empathy');
this._appSource.policy = new MessageTray.NotificationApplicationPolicy('empathy');
Main.messageTray.add(this._appSource);
this._appSource.connect('destroy', Lang.bind(this, function () {
@ -447,6 +446,7 @@ const ChatSource = new Lang.Class({
this._closedId = this._channel.connect('invalidated', Lang.bind(this, this._channelClosed));
this._notification = new ChatNotification(this);
this._notification.connect('clicked', Lang.bind(this, this.open));
this._notification.setUrgency(MessageTray.Urgency.HIGH);
this._notifyTimeoutId = 0;
@ -488,7 +488,7 @@ const ChatSource = new Lang.Class({
},
_createPolicy: function() {
return new NotificationDaemon.NotificationApplicationPolicy('empathy');
return new MessageTray.NotificationApplicationPolicy('empathy');
},
_updateAlias: function() {
@ -545,20 +545,19 @@ const ChatSource = new Lang.Class({
this._notification.update(this._notification.title, null, { customContent: true });
},
open: function(notification) {
if (this._client.is_handling_channel(this._channel)) {
// We are handling the channel, try to pass it to Empathy
this._client.delegate_channels_async([this._channel],
global.get_current_time(),
'org.freedesktop.Telepathy.Client.Empathy.Chat', null);
}
else {
// We are not the handler, just ask to present the channel
let dbus = Tp.DBusDaemon.dup();
let cd = Tp.ChannelDispatcher.new(dbus);
open: function() {
if (this._client.is_handling_channel(this._channel)) {
// We are handling the channel, try to pass it to Empathy
this._client.delegate_channels_async([this._channel],
global.get_current_time(),
'org.freedesktop.Telepathy.Client.Empathy.Chat', null);
} else {
// We are not the handler, just ask to present the channel
let dbus = Tp.DBusDaemon.dup();
let cd = Tp.ChannelDispatcher.new(dbus);
cd.present_channel_async(this._channel, global.get_current_time(), null);
}
cd.present_channel_async(this._channel, global.get_current_time(), null);
}
},
_getLogMessages: function() {
@ -961,6 +960,8 @@ const ChatNotification = new Lang.Class({
},
appendTimestamp: function() {
this._timestampTimeoutId = 0;
let lastMessageTime = this._history[0].time;
let lastMessageDate = new Date(lastMessageTime * 1000);
@ -1061,7 +1062,7 @@ const ApproverSource = new Lang.Class({
},
_createPolicy: function() {
return new NotificationDaemon.NotificationApplicationPolicy('empathy');
return new MessageTray.NotificationApplicationPolicy('empathy');
},
destroy: function() {
@ -1096,22 +1097,16 @@ const RoomInviteNotification = new Lang.Class({
* for example. */
this.addBody(_("%s is inviting you to join %s").format(inviter.get_alias(), channel.get_identifier()));
this.addButton('decline', _("Decline"));
this.addButton('accept', _("Accept"));
this.connect('action-invoked', Lang.bind(this, function(self, action) {
switch (action) {
case 'decline':
dispatchOp.leave_channels_async(Tp.ChannelGroupChangeReason.NONE,
'', function(src, result) {
src.leave_channels_finish(result)});
break;
case 'accept':
dispatchOp.handle_with_time_async('', global.get_current_time(),
function(src, result) {
src.handle_with_time_finish(result)});
break;
}
this.addAction(_("Decline"), Lang.bind(this, function() {
dispatchOp.leave_channels_async(Tp.ChannelGroupChangeReason.NONE, '', function(src, result) {
src.leave_channels_finish(result);
});
this.destroy();
}));
this.addAction(_("Accept"), Lang.bind(this, function() {
dispatchOp.handle_with_time_async('', global.get_current_time(), function(src, result) {
src.handle_with_time_finish(result);
});
this.destroy();
}));
}
@ -1137,23 +1132,17 @@ const AudioVideoNotification = new Lang.Class({
this.setUrgency(MessageTray.Urgency.CRITICAL);
this.addButton('reject', _("Decline"));
this.addAction(_("Decline"), Lang.bind(this, function() {
dispatchOp.leave_channels_async(Tp.ChannelGroupChangeReason.NONE, '', function(src, result) {
src.leave_channels_finish(result);
});
this.destroy();
}));
/* translators: this is a button label (verb), not a noun */
this.addButton('answer', _("Answer"));
this.connect('action-invoked', Lang.bind(this, function(self, action) {
switch (action) {
case 'reject':
dispatchOp.leave_channels_async(Tp.ChannelGroupChangeReason.NONE,
'', function(src, result) {
src.leave_channels_finish(result)});
break;
case 'answer':
dispatchOp.handle_with_time_async('', global.get_current_time(),
function(src, result) {
src.handle_with_time_finish(result)});
break;
}
this.addAction(_("Answer"), Lang.bind(this, function() {
dispatchOp.handle_with_time_async('', global.get_current_time(), function(src, result) {
src.handle_with_time_finish(result);
});
this.destroy();
}));
}
@ -1177,22 +1166,16 @@ const FileTransferNotification = new Lang.Class({
{ customContent: true });
this.setResident(true);
this.addButton('decline', _("Decline"));
this.addButton('accept', _("Accept"));
this.connect('action-invoked', Lang.bind(this, function(self, action) {
switch (action) {
case 'decline':
dispatchOp.leave_channels_async(Tp.ChannelGroupChangeReason.NONE,
'', function(src, result) {
src.leave_channels_finish(result)});
break;
case 'accept':
dispatchOp.handle_with_time_async('', global.get_current_time(),
function(src, result) {
src.handle_with_time_finish(result)});
break;
}
this.addAction(_("Decline"), Lang.bind(this, function() {
dispatchOp.leave_channels_async(Tp.ChannelGroupChangeReason.NONE, '', function(src, result) {
src.leave_channels_finish(result);
});
this.destroy();
}));
this.addAction(_("Accept"), Lang.bind(this, function() {
dispatchOp.handle_with_time_async('', global.get_current_time(), function(src, result) {
src.handle_with_time_finish(result);
});
this.destroy();
}));
}
@ -1240,27 +1223,20 @@ const SubscriptionRequestNotification = new Lang.Class({
this.addActor(layout);
this.addButton('decline', _("Decline"));
this.addButton('accept', _("Accept"));
this.addAction(_("Decline"), Lang.bind(this, function() {
contact.remove_async(function(src, result) {
src.remove_finish(result);
});
}));
this.addAction(_("Accept"), Lang.bind(this, function() {
// Authorize the contact and request to see his status as well
contact.authorize_publication_async(function(src, result) {
src.authorize_publication_finish(result);
});
this.connect('action-invoked', Lang.bind(this, function(self, action) {
switch (action) {
case 'decline':
contact.remove_async(function(src, result) {
src.remove_finish(result)});
break;
case 'accept':
// Authorize the contact and request to see his status as well
contact.authorize_publication_async(function(src, result) {
src.authorize_publication_finish(result)});
contact.request_subscription_async('', function(src, result) {
src.request_subscription_finish(result)});
break;
}
// rely on _subscriptionStatesChangedCb to destroy the
// notification
contact.request_subscription_async('', function(src, result) {
src.request_subscription_finish(result);
});
}));
this._changedId = contact.connect('subscription-states-changed',
@ -1359,18 +1335,11 @@ const AccountNotification = new Lang.Class({
this._account = account;
this.addButton('view', _("View account"));
this.connect('action-invoked', Lang.bind(this, function(self, action) {
switch (action) {
case 'view':
let cmd = 'empathy-accounts --select-account=' +
account.get_path_suffix();
let app_info = Gio.app_info_create_from_commandline(cmd, null, 0);
app_info.launch([], global.create_app_launch_context());
break;
}
this.destroy();
this.addAction(_("View account"), Lang.bind(this, function() {
let cmd = 'empathy-accounts --select-account=' +
account.get_path_suffix();
let app_info = Gio.app_info_create_from_commandline(cmd, null, 0);
app_info.launch([], global.create_app_launch_context());
}));
this._enabledId = account.connect('notify::enabled',

View File

@ -576,6 +576,7 @@ const Dash = new Lang.Class({
Lang.bind(this, function() {
this._labelShowing = true;
item.showLabel();
this._showLabelTimeoutId = 0;
return false;
}));
if (this._resetHoverTimeoutId > 0) {
@ -592,6 +593,7 @@ const Dash = new Lang.Class({
this._resetHoverTimeoutId = Mainloop.timeout_add(DASH_ITEM_HOVER_TIMEOUT,
Lang.bind(this, function() {
this._labelShowing = false;
this._resetHoverTimeoutId = 0;
return false;
}));
}

View File

@ -5,6 +5,7 @@ const GLib = imports.gi.GLib;
const Gtk = imports.gi.Gtk;
const St = imports.gi.St;
const Lang = imports.lang;
const Meta = imports.gi.Meta;
const Shell = imports.gi.Shell;
const Signals = imports.signals;
const Tweener = imports.ui.tweener;
@ -27,9 +28,9 @@ const DragMotionResult = {
};
const DRAG_CURSOR_MAP = {
0: Shell.Cursor.DND_UNSUPPORTED_TARGET,
1: Shell.Cursor.DND_COPY,
2: Shell.Cursor.DND_MOVE
0: Meta.Cursor.DND_UNSUPPORTED_TARGET,
1: Meta.Cursor.DND_COPY,
2: Meta.Cursor.DND_MOVE
};
const DragDropResult = {
@ -85,11 +86,6 @@ const _Draggable = new Lang.Class({
this.actor.connect('destroy', Lang.bind(this, function() {
this._actorDestroyed = true;
// If the drag actor is destroyed and we were going to fix
// up its hover state, fix up the parent hover state instead
if (this.actor == this._firstLeaveActor)
this._firstLeaveActor = this._dragOrigParent;
if (this._dragInProgress && this._dragCancellable)
this._cancelDrag(global.get_current_time());
this.disconnectAll();
@ -105,12 +101,6 @@ const _Draggable = new Lang.Class({
this._animationInProgress = false; // The drag is over and the item is in the process of animating to its original position (snapping back or reverting).
this._dragCancellable = true;
// During the drag, we eat enter/leave events so that actors don't prelight.
// But we remember the actors that we first left/last entered so we can
// fix up the hover state after the drag ends.
this._firstLeaveActor = null;
this._lastEnterActor = null;
this._eventsGrabbed = false;
},
@ -196,11 +186,6 @@ const _Draggable = new Lang.Class({
this._cancelDrag(event.get_time());
return true;
}
} else if (event.type() == Clutter.EventType.LEAVE) {
if (this._firstLeaveActor == null)
this._firstLeaveActor = event.get_source();
} else if (event.type() == Clutter.EventType.ENTER) {
this._lastEnterActor = event.get_source();
}
return false;
@ -244,14 +229,14 @@ const _Draggable = new Lang.Class({
if (this._onEventId)
this._ungrabActor();
this._grabEvents();
global.set_cursor(Shell.Cursor.DND_IN_DRAG);
global.screen.set_cursor(Meta.Cursor.DND_IN_DRAG);
this._dragX = this._dragStartX = stageX;
this._dragY = this._dragStartY = stageY;
if (this.actor._delegate && this.actor._delegate.getDragActor) {
this._dragActor = this.actor._delegate.getDragActor();
this._dragActor.reparent(Main.uiGroup);
Main.uiGroup.add_child(this._dragActor);
this._dragActor.raise_top();
Shell.util_set_hidden_from_pick(this._dragActor, true);
@ -300,7 +285,8 @@ const _Draggable = new Lang.Class({
this._dragOffsetX = actorStageX - this._dragStartX;
this._dragOffsetY = actorStageY - this._dragStartY;
this._dragActor.reparent(Main.uiGroup);
this._dragOrigParent.remove_actor(this._dragActor);
Main.uiGroup.add_child(this._dragActor);
this._dragActor.raise_top();
Shell.util_set_hidden_from_pick(this._dragActor, true);
}
@ -360,6 +346,7 @@ const _Draggable = new Lang.Class({
},
_updateDragHover : function () {
this._updateHoverId = 0;
let target = this._dragActor.get_stage().get_actor_at_pos(Clutter.PickMode.ALL,
this._dragX, this._dragY);
let dragEvent = {
@ -374,7 +361,7 @@ const _Draggable = new Lang.Class({
if (motionFunc) {
let result = motionFunc(dragEvent);
if (result != DragMotionResult.CONTINUE) {
global.set_cursor(DRAG_CURSOR_MAP[result]);
global.screen.set_cursor(DRAG_CURSOR_MAP[result]);
return false;
}
}
@ -392,19 +379,19 @@ const _Draggable = new Lang.Class({
targY,
0);
if (result != DragMotionResult.CONTINUE) {
global.set_cursor(DRAG_CURSOR_MAP[result]);
global.screen.set_cursor(DRAG_CURSOR_MAP[result]);
return false;
}
}
target = target.get_parent();
}
global.set_cursor(Shell.Cursor.DND_IN_DRAG);
global.screen.set_cursor(Meta.Cursor.DND_IN_DRAG);
return false;
},
_queueUpdateDragHover: function() {
if (this._updateHoverId)
GLib.source_remove(this._updateHoverId);
return;
this._updateHoverId = GLib.idle_add(GLib.PRIORITY_DEFAULT,
Lang.bind(this, this._updateDragHover));
@ -470,7 +457,7 @@ const _Draggable = new Lang.Class({
}
this._dragInProgress = false;
global.unset_cursor();
global.screen.set_cursor(Meta.Cursor.DEFAULT);
this.emit('drag-end', event.get_time(), true);
this._dragComplete();
return true;
@ -522,7 +509,7 @@ const _Draggable = new Lang.Class({
let [snapBackX, snapBackY, snapBackScale] = this._getRestoreLocation();
if (this._actorDestroyed) {
global.unset_cursor();
global.screen.set_cursor(Meta.Cursor.DEFAULT);
if (!this._buttonDown)
this._dragComplete();
this.emit('drag-end', eventTime, false);
@ -570,13 +557,14 @@ const _Draggable = new Lang.Class({
_onAnimationComplete : function (dragActor, eventTime) {
if (this._dragOrigParent) {
dragActor.reparent(this._dragOrigParent);
Main.uiGroup.remove_child(this._dragActor);
this._dragOrigParent.add_actor(this._dragActor);
dragActor.set_scale(this._dragOrigScale, this._dragOrigScale);
dragActor.set_position(this._dragOrigX, this._dragOrigY);
} else {
dragActor.destroy();
}
global.unset_cursor();
global.screen.set_cursor(Meta.Cursor.DEFAULT);
this.emit('drag-end', eventTime, false);
this._animationInProgress = false;
@ -584,33 +572,12 @@ const _Draggable = new Lang.Class({
this._dragComplete();
},
// Actor is an actor we have entered or left during the drag; call
// st_widget_sync_hover on all StWidget ancestors
_syncHover: function(actor) {
while (actor) {
let parent = actor.get_parent();
if (actor instanceof St.Widget)
actor.sync_hover();
actor = parent;
}
},
_dragComplete: function() {
if (!this._actorDestroyed)
Shell.util_set_hidden_from_pick(this._dragActor, false);
this._ungrabEvents();
if (this._firstLeaveActor) {
this._syncHover(this._firstLeaveActor);
this._firstLeaveActor = null;
}
if (this._lastEnterActor) {
this._syncHover(this._lastEnterActor);
this._lastEnterActor = null;
}
global.sync_pointer();
if (this._updateHoverId) {
GLib.source_remove(this._updateHoverId);

View File

@ -43,20 +43,22 @@ const _DIALOG_ICON_SIZE = 32;
const GSM_SESSION_MANAGER_LOGOUT_FORCE = 2;
const EndSessionDialogIface = <interface name="org.gnome.SessionManager.EndSessionDialog">
<method name="Open">
<arg type="u" direction="in" />
<arg type="u" direction="in" />
<arg type="u" direction="in" />
<arg type="ao" direction="in" />
</method>
<method name="Close" />
<signal name="ConfirmedLogout" />
<signal name="ConfirmedReboot" />
<signal name="ConfirmedShutdown" />
<signal name="Canceled" />
<signal name="Closed" />
</interface>;
const EndSessionDialogIface = '<node> \
<interface name="org.gnome.SessionManager.EndSessionDialog"> \
<method name="Open"> \
<arg type="u" direction="in" /> \
<arg type="u" direction="in" /> \
<arg type="u" direction="in" /> \
<arg type="ao" direction="in" /> \
</method> \
<method name="Close" /> \
<signal name="ConfirmedLogout" /> \
<signal name="ConfirmedReboot" /> \
<signal name="ConfirmedShutdown" /> \
<signal name="Canceled" /> \
<signal name="Closed" /> \
</interface> \
</node>';
const logoutDialogContent = {
subjectWithUser: C_("title", "Log Out %s"),
@ -131,13 +133,15 @@ const DialogContent = {
const MAX_USERS_IN_SESSION_DIALOG = 5;
const LogindSessionIface = <interface name='org.freedesktop.login1.Session'>
<property name="Id" type="s" access="read"/>
<property name="Remote" type="b" access="read"/>
<property name="Class" type="s" access="read"/>
<property name="Type" type="s" access="read"/>
<property name="State" type="s" access="read"/>
</interface>;
const LogindSessionIface = '<node> \
<interface name="org.freedesktop.login1.Session"> \
<property name="Id" type="s" access="read"/> \
<property name="Remote" type="b" access="read"/> \
<property name="Class" type="s" access="read"/> \
<property name="Type" type="s" access="read"/> \
<property name="State" type="s" access="read"/> \
</interface> \
</node>';
const LogindSession = Gio.DBusProxy.makeProxyWrapper(LogindSessionIface);
@ -269,13 +273,15 @@ const EndSessionDialog = new Lang.Class({
this._applicationHeader = new St.Label({ style_class: 'end-session-dialog-list-header',
text: _("Some applications are busy or have unsaved work.") });
this._applicationList = new St.BoxLayout({ vertical: true });
this._applicationList = new St.BoxLayout({ style_class: 'end-session-dialog-app-list',
vertical: true });
this._inhibitorSection.add_actor(this._applicationHeader);
this._inhibitorSection.add_actor(this._applicationList);
this._sessionHeader = new St.Label({ style_class: 'end-session-dialog-list-header',
text: _("Other users are logged in.") });
this._sessionList = new St.BoxLayout({ vertical: true });
this._sessionList = new St.BoxLayout({ style_class: 'end-session-dialog-session-list',
vertical: true });
this._inhibitorSection.add_actor(this._sessionHeader);
this._inhibitorSection.add_actor(this._sessionList);
@ -409,6 +415,7 @@ const EndSessionDialog = new Lang.Class({
let dialogContent = DialogContent[this._type];
let button = dialogContent.confirmButtons[dialogContent.confirmButtons.length - 1];
this._confirm(button.signal);
this._timerId = 0;
return false;
}));

View File

@ -76,7 +76,11 @@ function disableExtension(uuid) {
theme.unload_stylesheet(extension.stylesheet.get_path());
}
extension.stateObj.disable();
try {
extension.stateObj.disable();
} catch(e) {
logExtensionError(uuid, e);
}
for (let i = 0; i < order.length; i++) {
let uuid = order[i];
@ -89,8 +93,10 @@ function disableExtension(uuid) {
extensionOrder.splice(orderIdx, 1);
extension.state = ExtensionState.DISABLED;
_signals.emit('extension-state-changed', extension);
if ( extension.state != ExtensionState.ERROR ) {
extension.state = ExtensionState.DISABLED;
_signals.emit('extension-state-changed', extension);
}
}
function enableExtension(uuid) {
@ -117,10 +123,15 @@ function enableExtension(uuid) {
}
}
extension.stateObj.enable();
extension.state = ExtensionState.ENABLED;
_signals.emit('extension-state-changed', extension);
try {
extension.stateObj.enable();
extension.state = ExtensionState.ENABLED;
_signals.emit('extension-state-changed', extension);
return;
} catch(e) {
logExtensionError(uuid, e);
return;
}
}
function logExtensionError(uuid, error) {
@ -150,7 +161,8 @@ function loadExtension(extension) {
} else {
let enabled = enabledExtensions.indexOf(extension.uuid) != -1;
if (enabled) {
initExtension(extension.uuid);
if (!initExtension(extension.uuid))
return;
if (extension.state == ExtensionState.DISABLED)
enableExtension(extension.uuid);
} else {
@ -205,7 +217,12 @@ function initExtension(uuid) {
extensionModule = extension.imports.extension;
if (extensionModule.init) {
extensionState = extensionModule.init(extension);
try {
extensionState = extensionModule.init(extension);
} catch(e) {
logExtensionError(uuid, e);
return false;
}
}
if (!extensionState)
@ -214,6 +231,7 @@ function initExtension(uuid) {
extension.state = ExtensionState.DISABLED;
_signals.emit('extension-loaded', uuid);
return true;
}
function getEnabledExtensions() {
@ -235,11 +253,7 @@ function onEnabledExtensionsChanged() {
newEnabledExtensions.filter(function(uuid) {
return enabledExtensions.indexOf(uuid) == -1;
}).forEach(function(uuid) {
try {
enableExtension(uuid);
} catch(e) {
logExtensionError(uuid, e);
}
enableExtension(uuid);
});
// Find and disable all the newly disabled extensions: UUIDs found in the
@ -247,11 +261,7 @@ function onEnabledExtensionsChanged() {
enabledExtensions.filter(function(item) {
return newEnabledExtensions.indexOf(item) == -1;
}).forEach(function(uuid) {
try {
disableExtension(uuid);
} catch(e) {
logExtensionError(uuid, e);
}
disableExtension(uuid);
});
enabledExtensions = newEnabledExtensions;
@ -262,12 +272,8 @@ function _loadExtensions() {
enabledExtensions = getEnabledExtensions();
let finder = new ExtensionUtils.ExtensionFinder();
finder.connect('extension-found', function(signals, extension) {
try {
loadExtension(extension);
} catch(e) {
logExtensionError(extension.uuid, e);
}
finder.connect('extension-found', function(finder, extension) {
loadExtension(extension);
});
finder.scanExtensions();
}

View File

@ -33,6 +33,7 @@ const FocusCaretTracker = new Lang.Class({
_init: function() {
Atspi.init();
Atspi.set_timeout(250, 250);
this._atspiListener = Atspi.EventListener.new(Lang.bind(this, this._onChanged));
},

View File

@ -413,15 +413,18 @@ const IconGrid = new Lang.Class({
},
removeAll: function() {
this._items = [];
this._grid.remove_all_children();
},
destroyAll: function() {
this._items = [];
this._grid.destroy_all_children();
},
addItem: function(item, index) {
if (!item.icon || !item.icon instanceof BaseIcon) {
log('Only items with a BaseIcon icon property can be added to IconGrid');
return;
}
if (!item.icon instanceof BaseIcon)
throw new Error('Only items with a BaseIcon icon property can be added to IconGrid');
this._items.push(item);
if (index !== undefined)

View File

@ -23,27 +23,29 @@ const KEYBOARD_TYPE = 'keyboard-type';
const A11Y_APPLICATIONS_SCHEMA = 'org.gnome.desktop.a11y.applications';
const SHOW_KEYBOARD = 'screen-keyboard-enabled';
const CaribouKeyboardIface = <interface name='org.gnome.Caribou.Keyboard'>
<method name='Show'>
<arg type='u' direction='in' />
</method>
<method name='Hide'>
<arg type='u' direction='in' />
</method>
<method name='SetCursorLocation'>
<arg type='i' direction='in' />
<arg type='i' direction='in' />
<arg type='i' direction='in' />
<arg type='i' direction='in' />
</method>
<method name='SetEntryLocation'>
<arg type='i' direction='in' />
<arg type='i' direction='in' />
<arg type='i' direction='in' />
<arg type='i' direction='in' />
</method>
<property name='Name' access='read' type='s' />
</interface>;
const CaribouKeyboardIface = '<node> \
<interface name="org.gnome.Caribou.Keyboard"> \
<method name="Show"> \
<arg type="u" direction="in" /> \
</method> \
<method name="Hide"> \
<arg type="u" direction="in" /> \
</method> \
<method name="SetCursorLocation"> \
<arg type="i" direction="in" /> \
<arg type="i" direction="in" /> \
<arg type="i" direction="in" /> \
<arg type="i" direction="in" /> \
</method> \
<method name="SetEntryLocation"> \
<arg type="i" direction="in" /> \
<arg type="i" direction="in" /> \
<arg type="i" direction="in" /> \
<arg type="i" direction="in" /> \
</method> \
<property name="Name" access="read" type="s" /> \
</interface> \
</node>';
const Key = new Lang.Class({
Name: 'Key',

View File

@ -251,7 +251,7 @@ const LayoutManager = new Lang.Class({
this._inOverview = true;
this._updateVisibility();
this._queueUpdateRegions();
this._updateRegions();
},
hideOverview: function() {
@ -362,7 +362,7 @@ const LayoutManager = new Lang.Class({
BackgroundMenu.addBackgroundMenu(bgManager.background.actor);
}));
this._bgManagers.push(bgManager);
this._bgManagers[monitorIndex] = bgManager;
return bgManager.background;
},

View File

@ -629,55 +629,6 @@ const Inspector = new Lang.Class({
Signals.addSignalMethods(Inspector.prototype);
const Memory = new Lang.Class({
Name: 'Memory',
_init: function() {
this.actor = new St.BoxLayout({ vertical: true });
this._glibc_uordblks = new St.Label();
this.actor.add(this._glibc_uordblks);
this._js_bytes = new St.Label();
this.actor.add(this._js_bytes);
this._gjs_boxed = new St.Label();
this.actor.add(this._gjs_boxed);
this._gjs_gobject = new St.Label();
this.actor.add(this._gjs_gobject);
this._gjs_function = new St.Label();
this.actor.add(this._gjs_function);
this._gjs_closure = new St.Label();
this.actor.add(this._gjs_closure);
this._last_gc_seconds_ago = new St.Label();
this.actor.add(this._last_gc_seconds_ago);
this._gcbutton = new St.Button({ label: 'Full GC',
style_class: 'lg-obj-inspector-button' });
this._gcbutton.connect('clicked', Lang.bind(this, function () { System.gc(); this._renderText(); }));
this.actor.add(this._gcbutton, { x_align: St.Align.START,
x_fill: false });
this.actor.connect('notify::mapped', Lang.bind(this, this._renderText));
},
_renderText: function() {
if (!this.actor.mapped)
return;
let memInfo = global.get_memory_info();
this._glibc_uordblks.text = 'glibc_uordblks: ' + memInfo.glibc_uordblks;
this._js_bytes.text = 'js bytes: ' + memInfo.js_bytes;
this._gjs_boxed.text = 'gjs_boxed: ' + memInfo.gjs_boxed;
this._gjs_gobject.text = 'gjs_gobject: ' + memInfo.gjs_gobject;
this._gjs_function.text = 'gjs_function: ' + memInfo.gjs_function;
this._gjs_closure.text = 'gjs_closure: ' + memInfo.gjs_closure;
this._last_gc_seconds_ago.text = 'last_gc_seconds_ago: ' + memInfo.last_gc_seconds_ago;
}
});
const Extensions = new Lang.Class({
Name: 'Extensions',
@ -880,6 +831,19 @@ const LookingGlass = new Lang.Class({
return true;
}));
let gcIcon = new St.Icon({ icon_name: 'gnome-fs-trash-full',
icon_size: 24 });
toolbar.add_actor(gcIcon);
gcIcon.reactive = true;
gcIcon.connect('button-press-event', Lang.bind(this, function () {
gcIcon.icon_name = 'gnome-fs-trash-empty';
System.gc();
this._timeoutId = Mainloop.timeout_add(500, Lang.bind(this, function () {
gcIcon.icon_name = 'gnome-fs-trash-full';
Mainloop.source_remove(this._timeoutId);
}));
}));
let notebook = new Notebook();
this._notebook = notebook;
this.actor.add(notebook.actor, { expand: true });
@ -907,9 +871,6 @@ const LookingGlass = new Lang.Class({
this._windowList = new WindowList(this);
notebook.appendPage('Windows', this._windowList.actor);
this._memory = new Memory();
notebook.appendPage('Memory', this._memory.actor);
this._extensions = new Extensions(this);
notebook.appendPage('Extensions', this._extensions.actor);
@ -1072,15 +1033,15 @@ const LookingGlass = new Lang.Class({
let myWidth = primary.width * 0.7;
let availableHeight = primary.height - Main.layoutManager.keyboardBox.height;
let myHeight = Math.min(primary.height * 0.7, availableHeight * 0.9);
this.actor.x = (primary.width - myWidth) / 2;
this._hiddenY = Main.layoutManager.panelBox.height - myHeight - 4; // -4 to hide the top corners
this.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._targetY = this._hiddenY + myHeight;
this.actor.y = this._hiddenY;
this.actor.width = myWidth;
this.actor.height = myHeight;
this._objInspector.actor.set_size(Math.floor(myWidth * 0.8), Math.floor(myHeight * 0.8));
this._objInspector.actor.set_position(primary.x + this.actor.x + Math.floor(myWidth * 0.1),
primary.y + this._targetY + Math.floor(myHeight * 0.1));
this._objInspector.actor.set_position(this.actor.x + Math.floor(myWidth * 0.1),
this._targetY + Math.floor(myHeight * 0.1));
},
insertObject: function(obj) {

View File

@ -57,6 +57,20 @@ const Magnifier = new Lang.Class({
// Magnifier is a manager of ZoomRegions.
this._zoomRegions = [];
// Export to dbus.
magDBusService = new MagnifierDBus.ShellMagnifier();
let showAtLaunch = this._settingsInit();
this.setActive(showAtLaunch);
},
_initialize: function() {
if (this._initialized)
return;
this._initialized = true;
this._settingsInitLate();
// Create small clutter tree for the magnified mouse.
let cursorTracker = Meta.CursorTracker.get_for_screen(global.screen);
this._mouseSprite = new Clutter.Texture();
@ -72,15 +86,11 @@ const Magnifier = new Lang.Class({
let aZoomRegion = new ZoomRegion(this, this._cursorRoot);
this._zoomRegions.push(aZoomRegion);
let showAtLaunch = this._settingsInit(aZoomRegion);
this._settingsInitRegion(aZoomRegion);
aZoomRegion.scrollContentsTo(this.xMouse, this.yMouse);
cursorTracker.connect('cursor-changed', Lang.bind(this, this._updateMouseSprite));
this._cursorTracker = cursorTracker;
// Export to dbus.
magDBusService = new MagnifierDBus.ShellMagnifier();
this.setActive(showAtLaunch);
},
/**
@ -88,7 +98,7 @@ const Magnifier = new Lang.Class({
* Show the system mouse pointer.
*/
showSystemCursor: function() {
global.stage.show_cursor();
this._cursorTracker.set_pointer_visible(true);
},
/**
@ -96,7 +106,7 @@ const Magnifier = new Lang.Class({
* Hide the system mouse pointer.
*/
hideSystemCursor: function() {
global.stage.hide_cursor();
this._cursorTracker.set_pointer_visible(false);
},
/**
@ -105,6 +115,12 @@ const Magnifier = new Lang.Class({
* @activate: Boolean to activate or de-activate the magnifier.
*/
setActive: function(activate) {
if (activate == this.isActive())
return;
if (activate)
this._initialize();
this._zoomRegions.forEach (function(zoomRegion, index, array) {
zoomRegion.setActive(activate);
});
@ -117,7 +133,7 @@ const Magnifier = new Lang.Class({
// Make sure system mouse pointer is shown when all zoom regions are
// invisible.
if (!activate)
global.stage.show_cursor();
this._cursorTracker.set_pointer_visible(true);
// Notify interested parties of this change
this.emit('active-changed', activate);
@ -432,64 +448,68 @@ const Magnifier = new Lang.Class({
this._mouseSprite.set_anchor_point(xHot, yHot);
},
_settingsInit: function(zoomRegion) {
_settingsInitRegion: function(zoomRegion) {
// Mag factor is accurate to two decimal places.
let aPref = parseFloat(this._settings.get_double(MAG_FACTOR_KEY).toFixed(2));
if (aPref != 0.0)
zoomRegion.setMagFactor(aPref, aPref);
aPref = this._settings.get_enum(SCREEN_POSITION_KEY);
if (aPref)
zoomRegion.setScreenPosition(aPref);
zoomRegion.setLensMode(this._settings.get_boolean(LENS_MODE_KEY));
zoomRegion.setClampScrollingAtEdges(!this._settings.get_boolean(CLAMP_MODE_KEY));
aPref = this._settings.get_enum(MOUSE_TRACKING_KEY);
if (aPref)
zoomRegion.setMouseTrackingMode(aPref);
aPref = this._settings.get_enum(FOCUS_TRACKING_KEY);
if (aPref)
zoomRegion.setFocusTrackingMode(aPref);
aPref = this._settings.get_enum(CARET_TRACKING_KEY);
if (aPref)
zoomRegion.setCaretTrackingMode(aPref);
aPref = this._settings.get_boolean(INVERT_LIGHTNESS_KEY);
if (aPref)
zoomRegion.setInvertLightness(aPref);
aPref = this._settings.get_double(COLOR_SATURATION_KEY);
if (aPref)
zoomRegion.setColorSaturation(aPref);
let bc = {};
bc.r = this._settings.get_double(BRIGHT_RED_KEY);
bc.g = this._settings.get_double(BRIGHT_GREEN_KEY);
bc.b = this._settings.get_double(BRIGHT_BLUE_KEY);
zoomRegion.setBrightness(bc);
bc.r = this._settings.get_double(CONTRAST_RED_KEY);
bc.g = this._settings.get_double(CONTRAST_GREEN_KEY);
bc.b = this._settings.get_double(CONTRAST_BLUE_KEY);
zoomRegion.setContrast(bc);
},
_settingsInit: function() {
this._appSettings = new Gio.Settings({ schema: APPLICATIONS_SCHEMA });
this._settings = new Gio.Settings({ schema: MAGNIFIER_SCHEMA });
if (zoomRegion) {
// Mag factor is accurate to two decimal places.
let aPref = parseFloat(this._settings.get_double(MAG_FACTOR_KEY).toFixed(2));
if (aPref != 0.0)
zoomRegion.setMagFactor(aPref, aPref);
this._appSettings.connect('changed::' + SHOW_KEY, Lang.bind(this, function() {
let active = this._appSettings.get_boolean(SHOW_KEY);
this.setActive(active);
}));
aPref = this._settings.get_enum(SCREEN_POSITION_KEY);
if (aPref)
zoomRegion.setScreenPosition(aPref);
zoomRegion.setLensMode(this._settings.get_boolean(LENS_MODE_KEY));
zoomRegion.setClampScrollingAtEdges(!this._settings.get_boolean(CLAMP_MODE_KEY));
aPref = this._settings.get_enum(MOUSE_TRACKING_KEY);
if (aPref)
zoomRegion.setMouseTrackingMode(aPref);
aPref = this._settings.get_enum(FOCUS_TRACKING_KEY);
if (aPref)
zoomRegion.setFocusTrackingMode(aPref);
aPref = this._settings.get_enum(CARET_TRACKING_KEY);
if (aPref)
zoomRegion.setCaretTrackingMode(aPref);
aPref = this._settings.get_boolean(INVERT_LIGHTNESS_KEY);
if (aPref)
zoomRegion.setInvertLightness(aPref);
aPref = this._settings.get_double(COLOR_SATURATION_KEY);
if (aPref)
zoomRegion.setColorSaturation(aPref);
let bc = {};
bc.r = this._settings.get_double(BRIGHT_RED_KEY);
bc.g = this._settings.get_double(BRIGHT_GREEN_KEY);
bc.b = this._settings.get_double(BRIGHT_BLUE_KEY);
zoomRegion.setBrightness(bc);
bc.r = this._settings.get_double(CONTRAST_RED_KEY);
bc.g = this._settings.get_double(CONTRAST_GREEN_KEY);
bc.b = this._settings.get_double(CONTRAST_BLUE_KEY);
zoomRegion.setContrast(bc);
}
return this._appSettings.get_boolean(SHOW_KEY);
},
_settingsInitLate: function() {
let showCrosshairs = this._settings.get_boolean(SHOW_CROSS_HAIRS_KEY);
this.addCrosshairs();
this.setCrosshairsVisible(showCrosshairs);
this._appSettings.connect('changed::' + SHOW_KEY,
Lang.bind(this, function() {
this.setActive(this._appSettings.get_boolean(SHOW_KEY));
}));
this._settings.connect('changed::' + SCREEN_POSITION_KEY,
Lang.bind(this, this._updateScreenPosition));
this._settings.connect('changed::' + MAG_FACTOR_KEY,
@ -553,8 +573,6 @@ const Magnifier = new Lang.Class({
Lang.bind(this, function() {
this.setCrosshairsClip(this._settings.get_boolean(CROSS_HAIRS_CLIP_KEY));
}));
return this._appSettings.get_boolean(SHOW_KEY);
},
_updateScreenPosition: function() {
@ -732,14 +750,17 @@ const ZoomRegion = new Lang.Class({
* @activate: Boolean to show/hide the ZoomRegion.
*/
setActive: function(activate) {
if (activate && !this.isActive()) {
if (activate == this.isActive())
return;
if (activate) {
this._createActors();
if (this._isMouseOverRegion())
this._magnifier.hideSystemCursor();
this._updateMagViewGeometry();
this._updateCloneGeometry();
this._updateMousePosition();
} else if (!activate && this.isActive()) {
} else {
this._destroyActors();
}
},

View File

@ -9,85 +9,89 @@ const ZOOM_SERVICE_PATH = '/org/gnome/Magnifier/ZoomRegion';
// Subset of gnome-mag's Magnifier dbus interface -- to be expanded. See:
// http://git.gnome.org/browse/gnome-mag/tree/xml/...Magnifier.xml
const MagnifierIface = <interface name="org.gnome.Magnifier">
<method name="setActive">
<arg type="b" direction="in" />
</method>
<method name="isActive">
<arg type="b" direction="out" />
</method>
<method name="showCursor" />
<method name="hideCursor" />
<method name="createZoomRegion">
<arg type="d" direction="in" />
<arg type="d" direction="in" />
<arg type="ai" direction="in" />
<arg type="ai" direction="in" />
<arg type="o" direction="out" />
</method>
<method name="addZoomRegion">
<arg type="o" direction="in" />
<arg type="b" direction="out" />
</method>
<method name="getZoomRegions">
<arg type="ao" direction="out" />
</method>
<method name="clearAllZoomRegions" />
<method name="fullScreenCapable">
<arg type="b" direction="out" />
</method>
<method name="setCrosswireSize">
<arg type="i" direction="in" />
</method>
<method name="getCrosswireSize">
<arg type="i" direction="out" />
</method>
<method name="setCrosswireLength">
<arg type="i" direction="in" />
</method>
<method name="getCrosswireLength">
<arg type="i" direction="out" />
</method>
<method name="setCrosswireClip">
<arg type="b" direction="in" />
</method>
<method name="getCrosswireClip">
<arg type="b" direction="out" />
</method>
<method name="setCrosswireColor">
<arg type="u" direction="in" />
</method>
<method name="getCrosswireColor">
<arg type="u" direction="out" />
</method>
</interface>;
const MagnifierIface = '<node> \
<interface name="org.gnome.Magnifier"> \
<method name="setActive"> \
<arg type="b" direction="in" /> \
</method> \
<method name="isActive"> \
<arg type="b" direction="out" /> \
</method> \
<method name="showCursor" /> \
<method name="hideCursor" /> \
<method name="createZoomRegion"> \
<arg type="d" direction="in" /> \
<arg type="d" direction="in" /> \
<arg type="ai" direction="in" /> \
<arg type="ai" direction="in" /> \
<arg type="o" direction="out" /> \
</method> \
<method name="addZoomRegion"> \
<arg type="o" direction="in" /> \
<arg type="b" direction="out" /> \
</method> \
<method name="getZoomRegions"> \
<arg type="ao" direction="out" /> \
</method> \
<method name="clearAllZoomRegions" /> \
<method name="fullScreenCapable"> \
<arg type="b" direction="out" /> \
</method> \
<method name="setCrosswireSize"> \
<arg type="i" direction="in" /> \
</method> \
<method name="getCrosswireSize"> \
<arg type="i" direction="out" /> \
</method> \
<method name="setCrosswireLength"> \
<arg type="i" direction="in" /> \
</method> \
<method name="getCrosswireLength"> \
<arg type="i" direction="out" /> \
</method> \
<method name="setCrosswireClip"> \
<arg type="b" direction="in" /> \
</method> \
<method name="getCrosswireClip"> \
<arg type="b" direction="out" /> \
</method> \
<method name="setCrosswireColor"> \
<arg type="u" direction="in" /> \
</method> \
<method name="getCrosswireColor"> \
<arg type="u" direction="out" /> \
</method> \
</interface> \
</node>';
// Subset of gnome-mag's ZoomRegion dbus interface -- to be expanded. See:
// http://git.gnome.org/browse/gnome-mag/tree/xml/...ZoomRegion.xml
const ZoomRegionIface = <interface name="org.gnome.Magnifier.ZoomRegion">
<method name="setMagFactor">
<arg type="d" direction="in" />
<arg type="d" direction="in" />
</method>
<method name="getMagFactor">
<arg type="d" direction="out" />
<arg type="d" direction="out" />
</method>
<method name="setRoi">
<arg type="ai" direction="in" />
</method>
<method name="getRoi">
<arg type="ai" direction="out" />
</method>
<method name="shiftContentsTo">
<arg type="i" direction="in" />
<arg type="i" direction="in" />
<arg type="b" direction="out" />
</method>
<method name="moveResize">
<arg type="ai" direction="in" />
</method>
</interface>;
const ZoomRegionIface = '<node> \
<interface name="org.gnome.Magnifier.ZoomRegion"> \
<method name="setMagFactor"> \
<arg type="d" direction="in" /> \
<arg type="d" direction="in" /> \
</method> \
<method name="getMagFactor"> \
<arg type="d" direction="out" /> \
<arg type="d" direction="out" /> \
</method> \
<method name="setRoi"> \
<arg type="ai" direction="in" /> \
</method> \
<method name="getRoi"> \
<arg type="ai" direction="out" /> \
</method> \
<method name="shiftContentsTo"> \
<arg type="i" direction="in" /> \
<arg type="i" direction="in" /> \
<arg type="b" direction="out" /> \
</method> \
<method name="moveResize"> \
<arg type="ai" direction="in" /> \
</method> \
</interface> \
</node>';
// For making unique ZoomRegion DBus proxy object paths of the form:
// '/org/gnome/Magnifier/ZoomRegion/zoomer0',

View File

@ -90,8 +90,12 @@ function _sessionUpdated() {
Shell.KeyBindingMode.OVERVIEW,
sessionMode.hasRunDialog ? openRunDialog : null);
if (!sessionMode.hasRunDialog && lookingGlass)
lookingGlass.close();
if (!sessionMode.hasRunDialog) {
if (runDialog)
runDialog.close();
if (lookingGlass)
lookingGlass.close();
}
}
function start() {
@ -108,11 +112,6 @@ function start() {
Gio.DesktopAppInfo.set_desktop_env('GNOME');
sessionMode = new SessionMode.SessionMode();
sessionMode.connect('sessions-loaded', _sessionsLoaded);
sessionMode.init();
}
function _sessionsLoaded() {
sessionMode.connect('updated', _sessionUpdated);
_initializePrefs();
_initializeUI();

View File

@ -215,10 +215,10 @@ const URLHighlighter = new Lang.Class({
let urlId = this._findUrlAtPos(event);
if (urlId != -1 && !this._cursorChanged) {
global.set_cursor(Shell.Cursor.POINTING_HAND);
global.screen.set_cursor(Meta.Cursor.POINTING_HAND);
this._cursorChanged = true;
} else if (urlId == -1) {
global.unset_cursor();
global.screen.set_cursor(Meta.Cursor.DEFAULT);
this._cursorChanged = false;
}
return false;
@ -229,7 +229,7 @@ const URLHighlighter = new Lang.Class({
if (this._cursorChanged) {
this._cursorChanged = false;
global.unset_cursor();
global.screen.set_cursor(Meta.Cursor.DEFAULT);
}
}));
},
@ -280,10 +280,6 @@ const URLHighlighter = new Lang.Class({
}
});
function strHasSuffix(string, suffix) {
return string.substr(-suffix.length) == suffix;
}
// NotificationPolicy:
// An object that holds all bits of configurable policy related to a notification
// source, such as whether to play sound or honour the critical bit.
@ -310,6 +306,126 @@ const NotificationPolicy = new Lang.Class({
});
Signals.addSignalMethods(NotificationPolicy.prototype);
const NotificationGenericPolicy = new Lang.Class({
Name: 'NotificationGenericPolicy',
Extends: NotificationPolicy,
_init: function() {
// Don't chain to parent, it would try setting
// our properties to the defaults
this.id = 'generic';
this._masterSettings = new Gio.Settings({ schema: 'org.gnome.desktop.notifications' });
this._masterSettings.connect('changed', Lang.bind(this, this._changed));
},
store: function() { },
destroy: function() {
this._masterSettings.run_dispose();
},
_changed: function(settings, key) {
this.emit('policy-changed', key);
},
get enable() {
return true;
},
get enableSound() {
return true;
},
get showBanners() {
return this._masterSettings.get_boolean('show-banners');
},
get forceExpanded() {
return false;
},
get showInLockScreen() {
return this._masterSettings.get_boolean('show-in-lock-screen');
},
get detailsInLockScreen() {
return false;
}
});
const NotificationApplicationPolicy = new Lang.Class({
Name: 'NotificationApplicationPolicy',
Extends: NotificationPolicy,
_init: function(id) {
// Don't chain to parent, it would try setting
// our properties to the defaults
this.id = id;
this._canonicalId = this._canonicalizeId(id);
this._masterSettings = new Gio.Settings({ schema: 'org.gnome.desktop.notifications' });
this._settings = new Gio.Settings({ schema: 'org.gnome.desktop.notifications.application',
path: '/org/gnome/desktop/notifications/application/' + this._canonicalId + '/' });
this._masterSettings.connect('changed', Lang.bind(this, this._changed));
this._settings.connect('changed', Lang.bind(this, this._changed));
},
store: function() {
this._settings.set_string('application-id', this.id + '.desktop');
let apps = this._masterSettings.get_strv('application-children');
if (apps.indexOf(this._canonicalId) < 0) {
apps.push(this._canonicalId);
this._masterSettings.set_strv('application-children', apps);
}
},
destroy: function() {
this._masterSettings.run_dispose();
this._settings.run_dispose();
},
_changed: function(settings, key) {
this.emit('policy-changed', key);
},
_canonicalizeId: function(id) {
// Keys are restricted to lowercase alphanumeric characters and dash,
// and two dashes cannot be in succession
return id.toLowerCase().replace(/[^a-z0-9\-]/g, '-').replace(/--+/g, '-');
},
get enable() {
return this._settings.get_boolean('enable');
},
get enableSound() {
return this._settings.get_boolean('enable-sound-alerts');
},
get showBanners() {
return this._masterSettings.get_boolean('show-banners') &&
this._settings.get_boolean('show-banners');
},
get forceExpanded() {
return this._settings.get_boolean('force-expanded');
},
get showInLockScreen() {
return this._masterSettings.get_boolean('show-in-lock-screen') &&
this._settings.get_boolean('show-in-lock-screen');
},
get detailsInLockScreen() {
return this._settings.get_boolean('details-in-lock-screen');
}
});
// Notification:
// @source: the notification's Source
// @title: the title
@ -383,7 +499,6 @@ const Notification = new Lang.Class({
this.focused = false;
this.acknowledged = false;
this._destroyed = false;
this._useActionIcons = false;
this._customContent = false;
this.bannerBodyText = null;
this.bannerBodyMarkup = false;
@ -438,7 +553,12 @@ const Notification = new Lang.Class({
this._bannerLabel = this._bannerUrlHighlighter.actor;
this._bannerBox.add_actor(this._bannerLabel);
this.update(title, banner, params);
// If called with only one argument we assume the caller
// will call .update() later on. This is the case of
// NotificationDaemon, which wants to use the same code
// for new and updated notifications
if (arguments.length != 1)
this.update(title, banner, params);
},
// update:
@ -711,19 +831,8 @@ const Notification = new Lang.Class({
}
},
// addButton:
// @id: the action ID
// @label: the label for the action's button
//
// Adds a button with the given @label to the notification. All
// action buttons will appear in a single row at the bottom of
// the notification.
//
// If the button is clicked, the notification will emit the
// %action-invoked signal with @id as a parameter
addButton: function(id, label) {
addButton: function(button, callback) {
if (!this._buttonBox) {
let box = new St.BoxLayout({ style_class: 'notification-actions' });
this.setActionArea(box, { x_expand: false,
y_expand: false,
@ -731,49 +840,40 @@ const Notification = new Lang.Class({
y_fill: false,
x_align: St.Align.END });
this._buttonBox = box;
global.focus_manager.add_group(this._buttonBox);
}
let button = new St.Button({ can_focus: true });
button._actionId = id;
let iconName = strHasSuffix(id, '-symbolic') ? id : id + '-symbolic';
if (this._useActionIcons && Gtk.IconTheme.get_default().has_icon(iconName)) {
button.add_style_class_name('notification-icon-button');
button.child = new St.Icon({ icon_name: iconName });
} else {
button.add_style_class_name('notification-button');
button.label = label;
}
if (this._buttonBox.get_n_children() > 0)
global.focus_manager.remove_group(this._buttonBox);
this._buttonBox.add(button);
global.focus_manager.add_group(this._buttonBox);
button.connect('clicked', Lang.bind(this, this._onActionInvoked, id));
button.connect('clicked', Lang.bind(this, function() {
callback();
if (!this.resident) {
// We don't hide a resident notification when the user invokes one of its actions,
// because it is common for such notifications to update themselves with new
// information based on the action. We'd like to display the updated information
// in place, rather than pop-up a new notification.
this.emit('done-displaying');
this.destroy();
}
}));
this.updated();
return button;
},
// setButtonSensitive:
// @id: the action ID
// @sensitive: whether the button should be sensitive
// addAction:
// @label: the label for the action's button
// @callback: the callback for the action
//
// If the notification contains a button with action ID @id,
// its sensitivity will be set to @sensitive. Insensitive
// buttons cannot be clicked.
setButtonSensitive: function(id, sensitive) {
if (!this._buttonBox)
return;
// Adds a button with the given @label to the notification. All
// action buttons will appear in a single row at the bottom of
// the notification.
addAction: function(label, callback) {
let button = new St.Button({ style_class: 'notification-button',
label: label,
can_focus: true });
let button = this._buttonBox.get_children().filter(function(b) {
return b._actionId == id;
})[0];
if (!button || button.reactive == sensitive)
return;
button.reactive = sensitive;
return this.addButton(button, callback);
},
setUrgency: function(urgency) {
@ -792,10 +892,6 @@ const Notification = new Lang.Class({
this.forFeedback = forFeedback;
},
setUseActionIcons: function(useIcons) {
this._useActionIcons = useIcons;
},
_styleChanged: function() {
this._spacing = this._table.get_theme_node().get_length('spacing-columns');
},
@ -1020,18 +1116,6 @@ const Notification = new Lang.Class({
this.actor.add_style_class_name('notification-unexpanded');
},
_onActionInvoked: function(actor, mouseButtonClicked, id) {
this.emit('action-invoked', id);
if (!this.resident) {
// We don't hide a resident notification when the user invokes one of its actions,
// because it is common for such notifications to update themselves with new
// information based on the action. We'd like to display the updated information
// in place, rather than pop-up a new notification.
this.emit('done-displaying');
this.destroy();
}
},
_onClicked: function() {
this.emit('clicked');
// We hide all types of notifications once the user clicks on them because the common
@ -1206,6 +1290,10 @@ const Source = new Lang.Class({
return this.count > 1;
},
get isClearable() {
return !this.trayIcon && !this.isChat && !this.resident;
},
countUpdated: function() {
this.emit('count-updated');
},
@ -1277,25 +1365,25 @@ const Source = new Lang.Class({
return this._mainIcon.actor;
},
_onNotificationDestroy: function(notification) {
let index = this.notifications.indexOf(notification);
if (index < 0)
return;
this.notifications.splice(index, 1);
if (this.notifications.length == 0)
this._lastNotificationRemoved();
this.countUpdated();
},
pushNotification: function(notification) {
if (this.notifications.indexOf(notification) < 0) {
this.notifications.push(notification);
this.emit('notification-added', notification);
}
if (this.notifications.indexOf(notification) >= 0)
return;
notification.connect('clicked', Lang.bind(this, this.open));
notification.connect('destroy', Lang.bind(this,
function () {
let index = this.notifications.indexOf(notification);
if (index < 0)
return;
this.notifications.splice(index, 1);
if (this.notifications.length == 0)
this._lastNotificationRemoved();
this.countUpdated();
}));
notification.connect('destroy', Lang.bind(this, this._onNotificationDestroy));
this.notifications.push(notification);
this.emit('notification-added', notification);
this.countUpdated();
},
@ -1507,26 +1595,42 @@ const MessageTrayMenu = new Lang.Class({
this._tray = tray;
this._presence = new GnomeSession.Presence(Lang.bind(this, function(proxy, error) {
if (error) {
logError(error, 'Error while reading gnome-session presence');
return;
}
this._onStatusChanged(proxy.status);
}));
this._presence.connectSignal('StatusChanged', Lang.bind(this, function(proxy, senderName, [status]) {
this._onStatusChanged(status);
}));
this._accountManager = Tp.AccountManager.dup();
this._accountManager.connect('most-available-presence-changed',
Lang.bind(this, this._onIMPresenceChanged));
this._accountManager.prepare_async(null, Lang.bind(this, this._onIMPresenceChanged));
this.actor.hide();
Main.layoutManager.addChrome(this.actor);
this._busyItem = new PopupMenu.PopupSwitchMenuItem(_("Notifications"));
this._busyItem.connect('toggled', Lang.bind(this, this._updatePresence));
this.addMenuItem(this._busyItem);
let separator = new PopupMenu.PopupSeparatorMenuItem();
this.addMenuItem(separator);
this._clearItem = this.addAction(_("Clear Messages"), function() {
let toDestroy = [];
let sources = tray.getSources();
for (let i = 0; i < sources.length; i++) {
// We exclude trayIcons, chat and resident sources
if (sources[i].trayIcon ||
sources[i].isChat ||
sources[i].resident)
continue;
toDestroy.push(sources[i]);
}
let toDestroy = tray.getSources().filter(function(source) {
return source.isClearable;
})
for (let i = 0; i < toDestroy.length; i++) {
toDestroy[i].destroy();
}
toDestroy.forEach(function(source) {
source.destroy();
});
toDestroy = null;
tray.close();
});
@ -1541,9 +1645,43 @@ const MessageTrayMenu = new Lang.Class({
settingsItem.connect('activate', function() { tray.close(); });
},
_onStatusChanged: function(status) {
this._sessionStatus = status;
this._busyItem.setToggleState(status != GnomeSession.PresenceStatus.BUSY);
},
_onIMPresenceChanged: function(am, type) {
if (type == Tp.ConnectionPresenceType.AVAILABLE &&
this._sessionStatus == GnomeSession.PresenceStatus.BUSY)
this._presence.SetStatusRemote(GnomeSession.PresenceStatus.AVAILABLE);
},
_updateClearSensitivity: function() {
this._clearItem.setSensitive(this._tray.clearableCount > 0);
},
_updatePresence: function(item, state) {
let status = state ? GnomeSession.PresenceStatus.AVAILABLE
: GnomeSession.PresenceStatus.BUSY;
this._presence.SetStatusRemote(status);
let [type, s ,msg] = this._accountManager.get_most_available_presence();
let newType = 0;
let newStatus;
if (status == GnomeSession.PresenceStatus.BUSY &&
type == Tp.ConnectionPresenceType.AVAILABLE) {
newType = Tp.ConnectionPresenceType.BUSY;
newStatus = 'busy';
} else if (status == GnomeSession.PresenceStatus.AVAILABLE &&
type == Tp.ConnectionPresenceType.BUSY) {
newType = Tp.ConnectionPresenceType.AVAILABLE;
newStatus = 'available';
}
if (newType > 0)
this._accountManager.set_all_requested_presences(newType,
newStatus, msg);
}
});
const MessageTrayMenuButton = new Lang.Class({
@ -1805,8 +1943,9 @@ const MessageTray = new Lang.Class({
},
_sessionUpdated: function() {
if ((Main.sessionMode.isLocked || Main.sessionMode.isGreeter) && this._inCtrlAltTab) {
Main.ctrlAltTabManager.removeGroup(this._summary);
if (Main.sessionMode.isLocked || Main.sessionMode.isGreeter) {
if (this._inCtrlAltTab)
Main.ctrlAltTabManager.removeGroup(this._summary);
this._inCtrlAltTab = false;
} else if (!this._inCtrlAltTab) {
Main.ctrlAltTabManager.addGroup(this._summary, _("Message Tray"), 'user-available-symbolic',
@ -1925,7 +2064,7 @@ const MessageTray = new Lang.Class({
this._summary.insert_child_at_index(summaryItem.actor, this._chatSummaryItemsCount);
}
if (!source.trayIcon && !source.isChat && !source.resident)
if (source.isClearable)
this.clearableCount++;
this._sources.set(source, obj);
@ -1969,7 +2108,7 @@ const MessageTray = new Lang.Class({
if (source.isChat)
this._chatSummaryItemsCount--;
if (!source.trayIcon && !source.isChat && !source.resident)
if (source.isClearable)
this.clearableCount--;
source.disconnect(obj.notifyId);
@ -2034,7 +2173,10 @@ const MessageTray = new Lang.Class({
},
toggleAndNavigate: function() {
if (this.toggle())
if (!this.toggle())
return;
if (this._traySummoned)
this._summary.navigate_focus(null, Gtk.DirectionType.TAB_FORWARD, false);
},
@ -2231,7 +2373,6 @@ const MessageTray = new Lang.Class({
this._showNotification();
}
} else if (this._notificationState == State.SHOWN) {
let pinned = this._pointerInNotification && !this._notificationRemoved;
let expired = (this._userActiveWhileNotificationShown &&
this._notificationTimeoutId == 0 &&
!(this._notification.urgency == Urgency.CRITICAL) &&
@ -2242,9 +2383,9 @@ const MessageTray = new Lang.Class({
if (mustClose) {
let animate = hasNotifications && !this._notificationRemoved;
this._hideNotification(animate);
} else if (pinned && !this._notification.expanded) {
} else if (this._pointerInNotification && !this._notification.expanded) {
this._expandNotification(false);
} else if (pinned) {
} else if (this._pointerInNotification) {
this._ensureNotificationFocused();
}
}
@ -2614,12 +2755,12 @@ const MessageTray = new Lang.Class({
} else if (this._notification.y != expandedY) {
// Tween also opacity here, to override a possible tween that's
// currently hiding the notification.
this._tween(this._notificationWidget, '_notificationState', State.SHOWN,
{ y: expandedY,
opacity: 255,
time: ANIMATION_TIME,
transition: 'easeOutQuad'
});
Tweener.addTween(this._notificationWidget,
{ y: expandedY,
opacity: 255,
time: ANIMATION_TIME,
transition: 'easeOutQuad'
});
}
},

View File

@ -4,6 +4,7 @@ const Clutter = imports.gi.Clutter;
const GdkPixbuf = imports.gi.GdkPixbuf;
const Gio = imports.gi.Gio;
const GLib = imports.gi.GLib;
const Gtk = imports.gi.Gtk;
const Lang = imports.lang;
const Shell = imports.gi.Shell;
const Mainloop = imports.mainloop;
@ -15,54 +16,56 @@ const MessageTray = imports.ui.messageTray;
const Params = imports.misc.params;
const Util = imports.misc.util;
let nextNotificationId = 1;
// Should really be defined in Gio.js
const BusIface = <interface name="org.freedesktop.DBus">
<method name="GetConnectionUnixProcessID">
<arg type="s" direction="in" />
<arg type="u" direction="out" />
</method>
</interface>;
const BusIface = '<node> \
<interface name="org.freedesktop.DBus"> \
<method name="GetConnectionUnixProcessID"> \
<arg type="s" direction="in" /> \
<arg type="u" direction="out" /> \
</method> \
</interface> \
</node>';
var BusProxy = Gio.DBusProxy.makeProxyWrapper(BusIface);
function Bus() {
return new BusProxy(Gio.DBus.session, 'org.freedesktop.DBus', '/org/freedesktop/DBus');
}
const NotificationDaemonIface = <interface name="org.freedesktop.Notifications">
<method name="Notify">
<arg type="s" direction="in"/>
<arg type="u" direction="in"/>
<arg type="s" direction="in"/>
<arg type="s" direction="in"/>
<arg type="s" direction="in"/>
<arg type="as" direction="in"/>
<arg type="a{sv}" direction="in"/>
<arg type="i" direction="in"/>
<arg type="u" direction="out"/>
</method>
<method name="CloseNotification">
<arg type="u" direction="in"/>
</method>
<method name="GetCapabilities">
<arg type="as" direction="out"/>
</method>
<method name="GetServerInformation">
<arg type="s" direction="out"/>
<arg type="s" direction="out"/>
<arg type="s" direction="out"/>
<arg type="s" direction="out"/>
</method>
<signal name="NotificationClosed">
<arg type="u"/>
<arg type="u"/>
</signal>
<signal name="ActionInvoked">
<arg type="u"/>
<arg type="s"/>
</signal>
</interface>;
const FdoNotificationsIface = '<node> \
<interface name="org.freedesktop.Notifications"> \
<method name="Notify"> \
<arg type="s" direction="in"/> \
<arg type="u" direction="in"/> \
<arg type="s" direction="in"/> \
<arg type="s" direction="in"/> \
<arg type="s" direction="in"/> \
<arg type="as" direction="in"/> \
<arg type="a{sv}" direction="in"/> \
<arg type="i" direction="in"/> \
<arg type="u" direction="out"/> \
</method> \
<method name="CloseNotification"> \
<arg type="u" direction="in"/> \
</method> \
<method name="GetCapabilities"> \
<arg type="as" direction="out"/> \
</method> \
<method name="GetServerInformation"> \
<arg type="s" direction="out"/> \
<arg type="s" direction="out"/> \
<arg type="s" direction="out"/> \
<arg type="s" direction="out"/> \
</method> \
<signal name="NotificationClosed"> \
<arg type="u"/> \
<arg type="u"/> \
</signal> \
<signal name="ActionInvoked"> \
<arg type="u"/> \
<arg type="s"/> \
</signal> \
</interface> \
</node>';
const NotificationClosedReason = {
EXPIRED: 1,
@ -103,131 +106,11 @@ const STANDARD_TRAY_ICON_IMPLEMENTATIONS = {
'ibus-ui-gtk': 'keyboard'
};
const NotificationGenericPolicy = new Lang.Class({
Name: 'NotificationGenericPolicy',
Extends: MessageTray.NotificationPolicy,
const FdoNotificationDaemon = new Lang.Class({
Name: 'FdoNotificationDaemon',
_init: function() {
// Don't chain to parent, it would try setting
// our properties to the defaults
this.id = 'generic';
this._masterSettings = new Gio.Settings({ schema: 'org.gnome.desktop.notifications' });
this._masterSettings.connect('changed', Lang.bind(this, this._changed));
},
store: function() { },
destroy: function() {
this._masterSettings.run_dispose();
},
_changed: function(settings, key) {
this.emit('policy-changed', key);
},
get enable() {
return true;
},
get enableSound() {
return true;
},
get showBanners() {
return this._masterSettings.get_boolean('show-banners');
},
get forceExpanded() {
return false;
},
get showInLockScreen() {
return this._masterSettings.get_boolean('show-in-lock-screen');
},
get detailsInLockScreen() {
return false;
}
});
const NotificationApplicationPolicy = new Lang.Class({
Name: 'NotificationApplicationPolicy',
Extends: MessageTray.NotificationPolicy,
_init: function(id) {
// Don't chain to parent, it would try setting
// our properties to the defaults
this.id = id;
this._canonicalId = this._canonicalizeId(id)
this._masterSettings = new Gio.Settings({ schema: 'org.gnome.desktop.notifications' });
this._settings = new Gio.Settings({ schema: 'org.gnome.desktop.notifications.application',
path: '/org/gnome/desktop/notifications/application/' + this._canonicalId + '/' });
this._masterSettings.connect('changed', Lang.bind(this, this._changed));
this._settings.connect('changed', Lang.bind(this, this._changed));
},
store: function() {
this._settings.set_string('application-id', this.id + '.desktop');
let apps = this._masterSettings.get_strv('application-children');
if (apps.indexOf(this._canonicalId) < 0) {
apps.push(this._canonicalId);
this._masterSettings.set_strv('application-children', apps);
}
},
destroy: function() {
this._masterSettings.run_dispose();
this._settings.run_dispose();
},
_changed: function(settings, key) {
this.emit('policy-changed', key);
},
_canonicalizeId: function(id) {
// Keys are restricted to lowercase alphanumeric characters and dash,
// and two dashes cannot be in succession
return id.toLowerCase().replace(/[^a-z0-9\-]/g, '-').replace(/--+/g, '-');
},
get enable() {
return this._settings.get_boolean('enable');
},
get enableSound() {
return this._settings.get_boolean('enable-sound-alerts');
},
get showBanners() {
return this._masterSettings.get_boolean('show-banners') &&
this._settings.get_boolean('show-banners');
},
get forceExpanded() {
return this._settings.get_boolean('force-expanded');
},
get showInLockScreen() {
return this._masterSettings.get_boolean('show-in-lock-screen') &&
this._settings.get_boolean('show-in-lock-screen');
},
get detailsInLockScreen() {
return this._settings.get_boolean('details-in-lock-screen');
}
});
const NotificationDaemon = new Lang.Class({
Name: 'NotificationDaemon',
_init: function() {
this._dbusImpl = Gio.DBusExportedObject.wrapJSObject(NotificationDaemonIface, this);
this._dbusImpl = Gio.DBusExportedObject.wrapJSObject(FdoNotificationsIface, this);
this._dbusImpl.export(Gio.DBus.session, '/org/freedesktop/Notifications');
this._sources = [];
@ -235,6 +118,8 @@ const NotificationDaemon = new Lang.Class({
this._notifications = {};
this._busProxy = new Bus();
this._nextNotificationId = 1;
this._trayManager = new Shell.TrayManager();
this._trayIconAddedId = this._trayManager.connect('tray-icon-added', Lang.bind(this, this._onTrayIconAdded));
this._trayIconRemovedId = this._trayManager.connect('tray-icon-removed', Lang.bind(this, this._onTrayIconRemoved));
@ -333,7 +218,7 @@ const NotificationDaemon = new Lang.Class({
}
}
let source = new Source(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) {
@ -372,7 +257,7 @@ const NotificationDaemon = new Lang.Class({
hints['category'] == 'presence.offline')) {
// Ignore replacesId since we already sent back a
// NotificationClosed for that id.
id = nextNotificationId++;
id = this._nextNotificationId++;
Mainloop.idle_add(Lang.bind(this,
function () {
this._emitNotificationClosed(id, NotificationClosedReason.DISMISSED);
@ -396,12 +281,13 @@ const NotificationDaemon = new Lang.Class({
if (!hints['image-path'] && hints['image_path'])
hints['image-path'] = hints['image_path']; // version 1.1 of the spec
if (!hints['image-data'])
if (!hints['image-data']) {
if (hints['image_data'])
hints['image-data'] = hints['image_data']; // version 1.1 of the spec
else if (hints['icon_data'] && !hints['image-path'])
// early versions of the spec; 'icon_data' should only be used if 'image-path' is not available
hints['image-data'] = hints['icon_data'];
}
let ndata = { appName: appName,
icon: icon,
@ -415,7 +301,7 @@ const NotificationDaemon = new Lang.Class({
ndata.notification = this._notifications[replacesId].notification;
} else {
replacesId = 0;
ndata.id = id = nextNotificationId++;
ndata.id = id = this._nextNotificationId++;
}
this._notifications[id] = ndata;
@ -470,6 +356,19 @@ const NotificationDaemon = new Lang.Class({
return invocation.return_value(GLib.Variant.new('(u)', [id]));
},
_makeButton: function(id, label, useActionIcons) {
let button = new St.Button({ can_focus: true });
let iconName = id.endsWith('-symbolic') ? id : id + '-symbolic';
if (useActionIcons && Gtk.IconTheme.get_default().has_icon(iconName)) {
button.add_style_class_name('notification-icon-button');
button.child = new St.Icon({ icon_name: iconName });
} else {
button.add_style_class_name('notification-button');
button.label = label;
}
return button;
},
_notifyForSource: function(source, ndata) {
let [id, icon, summary, body, actions, hints, notification] =
[ndata.id, ndata.icon, ndata.summary, ndata.body,
@ -495,10 +394,6 @@ const NotificationDaemon = new Lang.Class({
}
this._emitNotificationClosed(ndata.id, notificationClosedReason);
}));
notification.connect('action-invoked', Lang.bind(this,
function(n, actionId) {
this._emitActionInvoked(ndata.id, actionId);
}));
}
// Mark music notifications so they can be shown in the screen shield
@ -532,18 +427,33 @@ const NotificationDaemon = new Lang.Class({
soundName: hints['sound-name'] });
notification.setImage(image);
let hasDefaultAction = false;
if (actions.length) {
notification.setUseActionIcons(hints['action-icons'] == true);
let useActionIcons = (hints['action-icons'] == true);
for (let i = 0; i < actions.length - 1; i += 2) {
if (actions[i] == 'default')
notification.connect('clicked', Lang.bind(this,
function() {
this._emitActionInvoked(ndata.id, "default");
}));
else
notification.addButton(actions[i], actions[i + 1]);
let [actionId, label] = [actions[i], actions[i+1]];
if (actionId == 'default') {
hasDefaultAction = true;
} else {
notification.addButton(this._makeButton(actionId, label, useActionIcons), Lang.bind(this, function() {
this._emitActionInvoked(ndata.id, actionId);
}));
}
}
}
if (hasDefaultAction) {
notification.connect('clicked', Lang.bind(this, function() {
this._emitActionInvoked(ndata.id, 'default');
}));
} else {
notification.connect('clicked', Lang.bind(this, function() {
source.open();
}));
}
switch (hints.urgency) {
case Urgency.LOW:
notification.setUrgency(MessageTray.Urgency.LOW);
@ -636,8 +546,8 @@ const NotificationDaemon = new Lang.Class({
}
});
const Source = new Lang.Class({
Name: 'NotificationDaemonSource',
const FdoNotificationDaemonSource = new Lang.Class({
Name: 'FdoNotificationDaemonSource',
Extends: MessageTray.Source,
_init: function(title, pid, sender, trayIcon, appId) {
@ -672,11 +582,11 @@ const Source = new Lang.Class({
},
_createPolicy: function() {
if (this.app) {
if (this.app && this.app.get_app_info()) {
let id = this.app.get_id().replace(/\.desktop$/,'');
return new NotificationApplicationPolicy(id);
return new MessageTray.NotificationApplicationPolicy(id);
} else {
return new NotificationGenericPolicy();
return new MessageTray.NotificationGenericPolicy();
}
},
@ -752,22 +662,6 @@ const Source = new Lang.Class({
return null;
},
_setApp: function(appId) {
if (this.app)
return;
this.app = this._getApp(appId);
if (!this.app)
return;
// Only override the icon if we were previously using
// notification-based icons (ie, not a trayicon) or if it was unset before
if (!this.trayIcon) {
this.useNotificationIcon = false;
this.iconUpdated();
}
},
setTitle: function(title) {
// Do nothing if .app is set, we don't want to override the
// app name with whatever is provided through libnotify (usually
@ -778,9 +672,9 @@ const Source = new Lang.Class({
this.parent(title);
},
open: function(notification) {
this.destroyNonResidentNotifications();
open: function() {
this.openApp();
this.destroyNonResidentNotifications();
},
_lastNotificationRemoved: function() {
@ -792,11 +686,8 @@ const Source = new Lang.Class({
if (this.app == null)
return;
let windows = this.app.get_windows();
if (windows.length > 0) {
let mostRecentWindow = windows[0];
Main.activateWindow(mostRecentWindow);
}
this.app.activate();
Main.overview.hide();
},
destroy: function() {
@ -823,3 +714,276 @@ const Source = new Lang.Class({
}
}
});
const GtkNotificationDaemonNotification = new Lang.Class({
Name: 'GtkNotificationDaemonNotification',
Extends: MessageTray.Notification,
_init: function(source, notification) {
this.parent(source);
this._serialized = GLib.Variant.new('a{sv}', notification);
let { "title": title,
"body": body,
"icon": gicon,
"urgent": urgent,
"buttons": buttons,
"default-action": defaultAction,
"default-action-target": defaultActionTarget } = notification;
this.setUrgency(urgent.unpack() ? MessageTray.Urgency.CRITICAL
: MessageTray.Urgency.NORMAL);
if (buttons) {
buttons.deep_unpack().forEach(Lang.bind(this, function(button) {
this.addAction(button.label.unpack(),
Lang.bind(this, this._onButtonClicked, button));
}));
}
this._defaultAction = defaultAction ? defaultAction.unpack() : null;
this._defaultActionTarget = defaultActionTarget;
this.update(title.unpack(), body ? body.unpack() : null,
{ gicon: gicon ? Gio.icon_deserialize(gicon) : null });
},
_activateAction: function(namespacedActionId, target) {
if (namespacedActionId) {
if (namespacedActionId.startsWith('app.')) {
let actionId = namespacedActionId.slice('app.'.length);
this.source.activateAction(actionId, target);
}
} else {
this.source.open();
}
},
_onButtonClicked: function(button) {
let { 'action': action, 'target': actionTarget } = button;
this._activateAction(action.unpack(), actionTarget);
},
_onClicked: function() {
this._activateAction(this._defaultAction, this._defaultActionTarget);
this.parent();
},
serialize: function() {
return this._serialized;
},
});
const FdoApplicationIface = '<node> \
<interface name="org.freedesktop.Application"> \
<method name="ActivateAction"> \
<arg type="s" direction="in" /> \
<arg type="av" direction="in" /> \
<arg type="a{sv}" direction="in" /> \
</method> \
<method name="Activate"> \
<arg type="a{sv}" direction="in" /> \
</method> \
</interface> \
</node>';
const FdoApplicationProxy = Gio.DBusProxy.makeProxyWrapper(FdoApplicationIface);
function objectPathFromAppId(appId) {
return '/' + appId.replace(/\./g, '/');
}
function getPlatformData() {
let startupId = GLib.Variant.new('s', '_TIME' + global.get_current_time());
return { "desktop-startup-id": startupId };
}
function InvalidAppError() {}
const GtkNotificationDaemonAppSource = new Lang.Class({
Name: 'GtkNotificationDaemonAppSource',
Extends: MessageTray.Source,
_init: function(appId) {
this._appId = appId;
this._objectPath = objectPathFromAppId(appId);
this._app = Shell.AppSystem.get_default().lookup_app(appId + '.desktop');
if (!this._app)
throw new InvalidAppError();
this._notifications = {};
this.parent(this._app.get_name());
},
createIcon: function(size) {
return this._app.create_icon_texture(size);
},
_createPolicy: function() {
return new MessageTray.NotificationApplicationPolicy(this._appId);
},
_createApp: function() {
return new FdoApplicationProxy(Gio.DBus.session, this._appId, this._objectPath);
},
activateAction: function(actionId, target) {
let app = this._createApp();
app.ActivateActionRemote(actionId, target ? [target] : [], getPlatformData());
},
open: function() {
let app = this._createApp();
app.ActivateRemote(getPlatformData());
},
addNotification: function(notificationId, notificationParams, showBanner) {
if (this._notifications[notificationId])
this._notifications[notificationId].destroy();
let notification = new GtkNotificationDaemonNotification(this, notificationParams);
notification.connect('destroy', Lang.bind(this, function() {
delete this._notifications[notificationId];
}));
this._notifications[notificationId] = notification;
if (showBanner)
this.notify(notification);
else
this.pushNotification(notification);
},
removeNotification: function(notificationId) {
if (this._notifications[notificationId])
this._notifications[notificationId].destroy(MessageTray.NotificationDestroyedReason.SOURCE_CLOSED);
},
serialize: function() {
let notifications = [];
for (let notificationId in this._notifications) {
let notification = this._notifications[notificationId];
notifications.push([notificationId, notification.serialize()]);
}
return [this._appId, notifications];
},
});
const GtkNotificationsIface = '<node> \
<interface name="org.gtk.Notifications"> \
<method name="AddNotification"> \
<arg type="s" direction="in" /> \
<arg type="s" direction="in" /> \
<arg type="a{sv}" direction="in" /> \
</method> \
<method name="RemoveNotification"> \
<arg type="s" direction="in" /> \
<arg type="s" direction="in" /> \
</method> \
</interface> \
</node>';
const GtkNotificationDaemon = new Lang.Class({
Name: 'GtkNotificationDaemon',
_init: function() {
this._sources = {};
this._loadNotifications();
this._dbusImpl = Gio.DBusExportedObject.wrapJSObject(GtkNotificationsIface, this);
this._dbusImpl.export(Gio.DBus.session, '/org/gtk/Notifications');
Gio.DBus.session.own_name('org.gtk.Notifications', Gio.BusNameOwnerFlags.REPLACE, null, null);
},
_ensureAppSource: function(appId) {
if (this._sources[appId])
return this._sources[appId];
let source = new GtkNotificationDaemonAppSource(appId);
source.connect('destroy', Lang.bind(this, function() {
delete this._sources[appId];
this._saveNotifications();
}));
source.connect('count-updated', Lang.bind(this, this._saveNotifications));
Main.messageTray.add(source);
this._sources[appId] = source;
return source;
},
_loadNotifications: function() {
this._isLoading = true;
let value = global.get_persistent_state('a(sa(sv))', 'notifications');
if (value) {
let sources = value.deep_unpack();
sources.forEach(Lang.bind(this, function([appId, notifications]) {
if (notifications.length == 0)
return;
let source;
try {
source = this._ensureAppSource(appId);
} catch(e if e instanceof InvalidAppError) {
return;
}
notifications.forEach(function([notificationId, notification]) {
source.addNotification(notificationId, notification.deep_unpack(), false);
});
}));
}
this._isLoading = false;
},
_saveNotifications: function() {
if (this._isLoading)
return;
let sources = [];
for (let appId in this._sources) {
let source = this._sources[appId];
sources.push(source.serialize());
}
global.set_persistent_state('notifications', new GLib.Variant('a(sa(sv))', sources));
},
AddNotificationAsync: function(params, invocation) {
let [appId, notificationId, notification] = params;
let source;
try {
source = this._ensureAppSource(appId);
} catch(e if e instanceof InvalidAppError) {
invocation.return_dbus_error('org.gtk.Notifications.InvalidApp', 'The app by ID "%s" could not be found'.format(appId));
return;
}
source.addNotification(notificationId, notification, true);
invocation.return_value(null);
},
RemoveNotificationAsync: function(params, invocation) {
let [appId, notificationId] = params;
let source = this._sources[appId];
if (source)
source.removeNotification(notificationId);
invocation.return_value(null);
},
});
const NotificationDaemon = new Lang.Class({
Name: 'NotificationDaemon',
_init: function() {
this._fdoNotificationDaemon = new FdoNotificationDaemon();
this._gtkNotificationDaemon = new GtkNotificationDaemon();
},
});

View File

@ -78,10 +78,8 @@ const ShellInfo = new Lang.Class({
}
this._undoCallback = undoCallback;
if (undoCallback) {
notification.addButton('system-undo', _("Undo"));
notification.connect('action-invoked', Lang.bind(this, this._onUndoClicked));
}
if (undoCallback)
notification.addAction(_("Undo"), Lang.bind(this, this._onUndoClicked));
this._source.notify(notification);
}
@ -148,7 +146,7 @@ const Overview = new Lang.Class({
// Dash elements, or mouseover handlers in the workspaces.
this._coverPane = new Clutter.Actor({ opacity: 0,
reactive: true });
this._stack.add_actor(this._coverPane);
Main.layoutManager.overviewGroup.add_child(this._coverPane);
this._coverPane.connect('event', Lang.bind(this, function (actor, event) { return true; }));
this._stack.add_actor(this._overview);
@ -365,11 +363,13 @@ const Overview = new Lang.Class({
this._lastHoveredWindow = dragEvent.targetActor._delegate.metaWindow;
this._windowSwitchTimeoutId = Mainloop.timeout_add(DND_WINDOW_SWITCH_TIMEOUT,
Lang.bind(this, function() {
this._windowSwitchTimeoutId = 0;
this._needsFakePointerEvent = true;
Main.activateWindow(dragEvent.targetActor._delegate.metaWindow,
this._windowSwitchTimestamp);
this.hide();
this._lastHoveredWindow = null;
return false;
}));
}
@ -445,17 +445,17 @@ const Overview = new Lang.Class({
this._inDrag = false;
},
beginWindowDrag: function(source) {
this.emit('window-drag-begin');
beginWindowDrag: function(clone) {
this.emit('window-drag-begin', clone);
this._inDrag = true;
},
cancelledWindowDrag: function(source) {
this.emit('window-drag-cancelled');
cancelledWindowDrag: function(clone) {
this.emit('window-drag-cancelled', clone);
},
endWindowDrag: function(source) {
this.emit('window-drag-end');
endWindowDrag: function(clone) {
this.emit('window-drag-end', clone);
this._inDrag = false;
},

View File

@ -36,6 +36,7 @@ const SlideLayout = new Lang.Class({
_init: function(params) {
this._slideX = 1;
this._translationX = 0;
this._direction = SlideDirection.LEFT;
this.parent(params);
@ -55,18 +56,21 @@ const SlideLayout = new Lang.Class({
vfunc_allocate: function(container, box, flags) {
let child = container.get_first_child();
let [, , natWidth, natHeight] = child.get_preferred_size();
let availWidth = Math.round(box.x2 - box.x1);
let availHeight = Math.round(box.y2 - box.y1);
let [, natWidth] = child.get_preferred_width(availHeight);
// Align the actor inside the clipped box, as the actor's alignment
// flags only determine what to do if the allocated box is bigger
// than the actor's box.
let realDirection = getRtlSlideDirection(this._direction, child);
let translationX = (realDirection == SlideDirection.LEFT) ?
(availWidth - natWidth) : (natWidth - availWidth);
let alignX = (realDirection == SlideDirection.LEFT) ? (availWidth - natWidth) : 0;
let actorBox = new Clutter.ActorBox({ x1: translationX,
y1: 0,
x2: child.x_expand ? availWidth : natWidth,
y2: child.y_expand ? availHeight : natHeight });
let actorBox = new Clutter.ActorBox();
actorBox.x1 = box.x1 + alignX + this._translationX;
actorBox.x2 = actorBox.x1 + (child.x_expand ? availWidth : natWidth);
actorBox.y1 = box.y1;
actorBox.y2 = actorBox.y1 + availHeight;
child.allocate(actorBox, flags);
},
@ -87,7 +91,16 @@ const SlideLayout = new Lang.Class({
get slideDirection() {
return this._direction;
}
},
set translationX(value) {
this._translationX = value;
this.layout_changed();
},
get translationX() {
return this._translationX;
},
});
const SlidingControl = new Lang.Class({
@ -96,8 +109,8 @@ const SlidingControl = new Lang.Class({
_init: function(params) {
params = Params.parse(params, { slideDirection: SlideDirection.LEFT });
this.visible = true;
this.inDrag = false;
this._visible = true;
this._inDrag = false;
this.layout = new SlideLayout();
this.layout.slideDirection = params.slideDirection;
@ -106,6 +119,7 @@ const SlidingControl = new Lang.Class({
clip_to_allocation: true });
Main.overview.connect('showing', Lang.bind(this, this._onOverviewShowing));
Main.overview.connect('hiding', Lang.bind(this, this._onOverviewHiding));
Main.overview.connect('item-drag-begin', Lang.bind(this, this._onDragBegin));
Main.overview.connect('item-drag-end', Lang.bind(this, this._onDragEnd));
@ -116,12 +130,12 @@ const SlidingControl = new Lang.Class({
Main.overview.connect('window-drag-end', Lang.bind(this, this._onWindowDragEnd));
},
getSlide: function() {
_getSlide: function() {
throw new Error('getSlide() must be overridden');
},
updateSlide: function() {
Tweener.addTween(this.layout, { slideX: this.getSlide(),
_updateSlide: function() {
Tweener.addTween(this.layout, { slideX: this._getSlide(),
time: SIDE_CONTROLS_ANIMATION_TIME,
transition: 'easeOutQuad' });
},
@ -148,28 +162,30 @@ const SlidingControl = new Lang.Class({
let translationEnd = 0;
let translation = this._getTranslation();
if (this.visible) {
if (this._visible) {
translationStart = translation;
} else {
translationEnd = translation;
}
if (this.actor.translation_x == translationEnd)
if (this.layout.translationX == translationEnd)
return;
this.actor.translation_x = translationStart;
Tweener.addTween(this.actor, { translation_x: translationEnd,
time: SIDE_CONTROLS_ANIMATION_TIME,
transition: 'easeOutQuad'
});
this.layout.translationX = translationStart;
Tweener.addTween(this.layout, { translationX: translationEnd,
time: SIDE_CONTROLS_ANIMATION_TIME,
transition: 'easeOutQuad' });
},
_onOverviewShowing: function() {
// reset any translation and make sure the actor is visible when
// entering the overview
this.visible = true;
this.layout.slideX = this.getSlide();
this.actor.translation_x = 0;
this._visible = true;
this.layout.slideX = this._getSlide();
this.layout.translationX = this._getTranslation();
this.slideIn();
},
_onOverviewHiding: function() {
this.slideOut();
},
_onWindowDragBegin: function() {
@ -181,14 +197,14 @@ const SlidingControl = new Lang.Class({
},
_onDragBegin: function() {
this.inDrag = true;
this.actor.translation_x = 0;
this.updateSlide();
this._inDrag = true;
this.layout.translationX = 0;
this._updateSlide();
},
_onDragEnd: function() {
this.inDrag = false;
this.updateSlide();
this._inDrag = false;
this._updateSlide();
},
fadeIn: function() {
@ -206,13 +222,13 @@ const SlidingControl = new Lang.Class({
},
slideIn: function() {
this.visible = true;
this._visible = true;
this._updateTranslation();
// we will update slideX and the translation from pageEmpty
},
slideOut: function() {
this.visible = false;
this._visible = false;
this._updateTranslation();
// we will update slideX from pageEmpty
},
@ -222,7 +238,7 @@ const SlidingControl = new Lang.Class({
// selector; this means we can now safely set the full slide for
// the next page, since slideIn or slideOut might have been called,
// changing the visiblity
this.layout.slideX = this.getSlide();
this.layout.slideX = this._getSlide();
this._updateTranslation();
}
});
@ -236,26 +252,20 @@ const ThumbnailsSlider = new Lang.Class({
this._thumbnailsBox = thumbnailsBox;
// SlideLayout reads the actor's expand flags to decide
// whether to allocate the natural size to its child, or the whole
// available allocation
this._thumbnailsBox.actor.y_expand = true;
this.actor.request_mode = Clutter.RequestMode.WIDTH_FOR_HEIGHT;
this.actor.reactive = true;
this.actor.track_hover = true;
this.actor.add_actor(this._thumbnailsBox.actor);
Main.layoutManager.connect('monitors-changed', Lang.bind(this, this.updateSlide));
Main.overview.connect('hiding', Lang.bind(this, this.slideOut));
this.actor.connect('notify::hover', Lang.bind(this, this.updateSlide));
Main.layoutManager.connect('monitors-changed', Lang.bind(this, this._updateSlide));
this.actor.connect('notify::hover', Lang.bind(this, this._updateSlide));
this._thumbnailsBox.actor.bind_property('visible', this.actor, 'visible', GObject.BindingFlags.SYNC_CREATE);
},
_getAlwaysZoomOut: function() {
// Always show the pager when hover, during a drag, or if workspaces are
// actually used, e.g. there are windows on more than one
let alwaysZoomOut = this.actor.hover || this.inDrag || !Meta.prefs_get_dynamic_workspaces() || global.screen.n_workspaces > 2;
let alwaysZoomOut = this.actor.hover || this._inDrag || !Meta.prefs_get_dynamic_workspaces() || global.screen.n_workspaces > 2;
if (!alwaysZoomOut) {
let monitors = Main.layoutManager.monitors;
@ -275,20 +285,13 @@ const ThumbnailsSlider = new Lang.Class({
return alwaysZoomOut;
},
_onOverviewShowing: function() {
this.visible = true;
this.layout.slideX = this.getSlide();
this.actor.translation_x = this._getTranslation();
this.slideIn();
},
getNonExpandedWidth: function() {
let child = this.actor.get_first_child();
return child.get_theme_node().get_length('visible-width');
},
getSlide: function() {
if (!this.visible)
_getSlide: function() {
if (!this._visible)
return 0;
let alwaysZoomOut = this._getAlwaysZoomOut();
@ -324,31 +327,23 @@ const DashSlider = new Lang.Class({
// whether to allocate the natural size to its child, or the whole
// available allocation
this._dash.actor.x_expand = true;
this._dash.actor.y_expand = true;
this.actor.x_expand = true;
this.actor.x_align = Clutter.ActorAlign.START;
this.actor.y_expand = true;
this.actor.add_actor(this._dash.actor);
this._dash.connect('icon-size-changed', Lang.bind(this, this.updateSlide));
Main.overview.connect('hiding', Lang.bind(this, this.slideOut));
this._dash.connect('icon-size-changed', Lang.bind(this, this._updateSlide));
},
getSlide: function() {
if (this.visible || this.inDrag)
_getSlide: function() {
if (this._visible || this._inDrag)
return 1;
else
return 0;
},
_onOverviewShowing: function() {
this.visible = true;
this.layout.slideX = this.getSlide();
this.actor.translation_x = this._getTranslation();
this.slideIn();
},
_onWindowDragBegin: function() {
this.fadeHalf();
},
@ -504,6 +499,17 @@ const MessagesIndicator = new Lang.Class({
}
});
const ControlsLayout = new Lang.Class({
Name: 'ControlsLayout',
Extends: Clutter.BinLayout,
Signals: { 'allocation-changed': { flags: GObject.SignalFlags.RUN_LAST } },
vfunc_allocate: function(container, box, flags) {
this.parent(container, box, flags);
this.emit('allocation-changed');
}
});
const ControlsManager = new Lang.Class({
Name: 'ControlsManager',
@ -524,7 +530,8 @@ const ControlsManager = new Lang.Class({
this._indicator = new MessagesIndicator(this.viewSelector);
this.indicatorActor = this._indicator.actor;
this.actor = new St.Widget({ layout_manager: new Clutter.BinLayout(),
let layout = new ControlsLayout();
this.actor = new St.Widget({ layout_manager: layout,
reactive: true,
x_expand: true, y_expand: true,
clip_to_allocation: true });
@ -539,7 +546,7 @@ const ControlsManager = new Lang.Class({
expand: true });
this._group.add_actor(this._thumbnailsSlider.actor);
this._group.connect('notify::allocation', Lang.bind(this, this._updateWorkspacesGeometry));
layout.connect('allocation-changed', Lang.bind(this, this._updateWorkspacesGeometry));
Main.overview.connect('showing', Lang.bind(this, this._updateSpacerVisibility));
Main.overview.connect('item-drag-begin', Lang.bind(this,

View File

@ -213,9 +213,7 @@ const AppMenuButton = new Lang.Class({
this._label = new TextShadower();
this._label.actor.y_align = Clutter.ActorAlign.CENTER;
this._hbox.add_actor(this._label.actor);
this._arrow = new St.Label({ text: '\u25BE',
y_expand: true,
y_align: Clutter.ActorAlign.CENTER });
this._arrow = PopupMenu.unicodeArrow(St.Side.BOTTOM);
this._hbox.add_actor(this._arrow);
this._iconBottomClip = 0;
@ -611,6 +609,7 @@ const ActivitiesButton = new Lang.Class({
_onButtonRelease: function() {
Main.overview.toggle();
this.menu.close();
},
_onKeyRelease: function(actor, event) {
@ -804,7 +803,7 @@ const AggregateMenu = new Lang.Class({
Extends: PanelMenu.Button,
_init: function() {
this.parent(0.0, _("Settings Menu"), false);
this.parent(0.0, _("Settings"), false);
this.menu.actor.add_style_class_name('aggregate-menu');
this._indicators = new St.BoxLayout({ style_class: 'panel-status-indicators-box' });
@ -832,9 +831,7 @@ const AggregateMenu = new Lang.Class({
this._indicators.add_child(this._rfkill.indicators);
this._indicators.add_child(this._volume.indicators);
this._indicators.add_child(this._power.indicators);
this._indicators.add_child(new St.Label({ text: '\u25BE',
y_expand: true,
y_align: Clutter.ActorAlign.CENTER }));
this._indicators.add_child(PopupMenu.unicodeArrow(St.Side.BOTTOM));
this.menu.addMenuItem(this._volume.menu);
this.menu.addMenuItem(this._brightness.menu);

View File

@ -42,6 +42,33 @@ function isPopupMenuItemVisible(child) {
return child.visible;
}
/**
* @side Side to which the arrow points.
*/
function unicodeArrow(side) {
let arrowChar;
switch (side) {
case St.Side.TOP:
arrowChar = '\u25B4';
break;
case St.Side.RIGHT:
arrowChar = '\u25B8';
break;
case St.Side.BOTTOM:
arrowChar = '\u25BE';
break;
case St.Side.LEFT:
arrowChar = '\u25C2';
break;
}
return new St.Label({ text: arrowChar,
style_class: 'unicode-arrow',
accessible_role: Atk.Role.ARROW,
y_expand: true,
y_align: Clutter.ActorAlign.CENTER });
}
const PopupBaseMenuItem = new Lang.Class({
Name: 'PopupBaseMenuItem',
@ -948,18 +975,21 @@ const PopupSubMenuMenuItem = new Lang.Class({
this.actor.add_child(this.icon);
}
this.label = new St.Label({ text: text });
this.label = new St.Label({ text: text,
y_expand: true,
y_align: Clutter.ActorAlign.CENTER });
this.actor.add_child(this.label);
this.actor.label_actor = this.label;
let expander = new St.Bin({ style_class: 'popup-menu-item-expander' });
this.actor.add(expander, { expand: true });
this.status = new St.Label({ style_class: 'popup-status-menu-item' });
this.status = new St.Label({ style_class: 'popup-status-menu-item',
y_expand: true,
y_align: Clutter.ActorAlign.CENTER });
this.actor.add_child(this.status);
this._triangle = new St.Label({ text: '\u25B8',
style_class: 'popup-submenu-menu-item-triangle' });
this._triangle = unicodeArrow(St.Side.RIGHT);
this._triangle.pivot_point = new Clutter.Point({ x: 0.5, y: 0.6 });
this._triangleBin = new St.Widget({ y_expand: true,
@ -969,6 +999,7 @@ const PopupSubMenuMenuItem = new Lang.Class({
this._triangleBin.set_scale(-1.0, 1.0);
this.actor.add_child(this._triangleBin);
this.actor.add_accessible_state (Atk.StateType.EXPANDABLE);
this.menu = new PopupSubMenu(this.actor, this._triangle);
this.menu.connect('open-state-changed', Lang.bind(this, this._subMenuOpenStateChanged));
@ -990,9 +1021,11 @@ const PopupSubMenuMenuItem = new Lang.Class({
if (open) {
this.actor.add_style_pseudo_class('open');
this._getTopMenu()._setOpenedSubMenu(this.menu);
this.actor.add_accessible_state (Atk.StateType.EXPANDED);
} else {
this.actor.remove_style_pseudo_class('open');
this._getTopMenu()._setOpenedSubMenu(null);
this.actor.remove_accessible_state (Atk.StateType.EXPANDED);
}
},
@ -1081,7 +1114,7 @@ const PopupMenuManager = new Lang.Class({
removeMenu: function(menu) {
if (menu == this.activeMenu)
this._closeMenu(menu);
this._closeMenu(false, menu);
let position = this._findMenu(menu);
if (position == -1) // not a menu we manage

View File

@ -7,58 +7,63 @@ const Lang = imports.lang;
const St = imports.gi.St;
const Shell = imports.gi.Shell;
const FileUtils = imports.misc.fileUtils;
const Search = imports.ui.search;
const KEY_FILE_GROUP = 'Shell Search Provider';
const SearchProviderIface = <interface name="org.gnome.Shell.SearchProvider">
<method name="GetInitialResultSet">
<arg type="as" direction="in" />
<arg type="as" direction="out" />
</method>
<method name="GetSubsearchResultSet">
<arg type="as" direction="in" />
<arg type="as" direction="in" />
<arg type="as" direction="out" />
</method>
<method name="GetResultMetas">
<arg type="as" direction="in" />
<arg type="aa{sv}" direction="out" />
</method>
<method name="ActivateResult">
<arg type="s" direction="in" />
</method>
</interface>;
const SearchProviderIface = '<node> \
<interface name="org.gnome.Shell.SearchProvider"> \
<method name="GetInitialResultSet"> \
<arg type="as" direction="in" /> \
<arg type="as" direction="out" /> \
</method> \
<method name="GetSubsearchResultSet"> \
<arg type="as" direction="in" /> \
<arg type="as" direction="in" /> \
<arg type="as" direction="out" /> \
</method> \
<method name="GetResultMetas"> \
<arg type="as" direction="in" /> \
<arg type="aa{sv}" direction="out" /> \
</method> \
<method name="ActivateResult"> \
<arg type="s" direction="in" /> \
</method> \
</interface> \
</node>';
const SearchProvider2Iface = <interface name="org.gnome.Shell.SearchProvider2">
<method name="GetInitialResultSet">
<arg type="as" direction="in" />
<arg type="as" direction="out" />
</method>
<method name="GetSubsearchResultSet">
<arg type="as" direction="in" />
<arg type="as" direction="in" />
<arg type="as" direction="out" />
</method>
<method name="GetResultMetas">
<arg type="as" direction="in" />
<arg type="aa{sv}" direction="out" />
</method>
<method name="ActivateResult">
<arg type="s" direction="in" />
<arg type="as" direction="in" />
<arg type="u" direction="in" />
</method>
<method name="LaunchSearch">
<arg type="as" direction="in" />
<arg type="u" direction="in" />
</method>
</interface>;
const SearchProvider2Iface = '<node> \
<interface name="org.gnome.Shell.SearchProvider2"> \
<method name="GetInitialResultSet"> \
<arg type="as" direction="in" /> \
<arg type="as" direction="out" /> \
</method> \
<method name="GetSubsearchResultSet"> \
<arg type="as" direction="in" /> \
<arg type="as" direction="in" /> \
<arg type="as" direction="out" /> \
</method> \
<method name="GetResultMetas"> \
<arg type="as" direction="in" /> \
<arg type="aa{sv}" direction="out" /> \
</method> \
<method name="ActivateResult"> \
<arg type="s" direction="in" /> \
<arg type="as" direction="in" /> \
<arg type="u" direction="in" /> \
</method> \
<method name="LaunchSearch"> \
<arg type="as" direction="in" /> \
<arg type="u" direction="in" /> \
</method> \
</interface> \
</node>';
var SearchProviderProxy = Gio.DBusProxy.makeProxyWrapper(SearchProviderIface);
var SearchProvider2Proxy = Gio.DBusProxy.makeProxyWrapper(SearchProvider2Iface);
var SearchProviderProxyInfo = Gio.DBusInterfaceInfo.new_for_xml(SearchProviderIface);
var SearchProvider2ProxyInfo = Gio.DBusInterfaceInfo.new_for_xml(SearchProvider2Iface);
function loadRemoteSearchProviders(addProviderCallback) {
function loadRemoteSearchProviders(callback) {
let objectPaths = {};
let loadedProviders = [];
@ -112,30 +117,25 @@ function loadRemoteSearchProviders(addProviderCallback) {
}
}
let dataDirs = GLib.get_system_data_dirs();
dataDirs.forEach(function(dataDir) {
let path = GLib.build_filenamev([dataDir, 'gnome-shell', 'search-providers']);
let dir = Gio.File.new_for_path(path);
let fileEnum;
try {
fileEnum = dir.enumerate_children('standard::name,standard::type',
Gio.FileQueryInfoFlags.NONE, null);
} catch (e) {
fileEnum = null;
}
if (fileEnum != null) {
let info;
while ((info = fileEnum.next_file(null)))
loadRemoteSearchProvider(fileEnum.get_child(info));
}
});
let searchSettings = new Gio.Settings({ schema: Search.SEARCH_PROVIDERS_SCHEMA });
if (searchSettings.get_boolean('disable-external')) {
callback([]);
return;
}
FileUtils.collectFromDatadirs('search-providers', false, loadRemoteSearchProvider);
let sortOrder = searchSettings.get_strv('sort-order');
// Special case gnome-control-center to be always active and always first
sortOrder.unshift('gnome-control-center.desktop');
loadedProviders = loadedProviders.filter(function(provider) {
let appId = provider.appInfo.get_id();
let disabled = searchSettings.get_strv('disabled');
return disabled.indexOf(appId) == -1;
});
loadedProviders.sort(function(providerA, providerB) {
let idxA, idxB;
let appIdA, appIdB;
@ -166,28 +166,28 @@ function loadRemoteSearchProviders(addProviderCallback) {
return (idxA - idxB);
});
loadedProviders.forEach(addProviderCallback);
callback(loadedProviders);
}
const RemoteSearchProvider = new Lang.Class({
Name: 'RemoteSearchProvider',
_init: function(appInfo, dbusName, dbusPath, proxyType) {
if (!proxyType)
proxyType = SearchProviderProxy;
_init: function(appInfo, dbusName, dbusPath, proxyInfo) {
if (!proxyInfo)
proxyInfo = SearchProviderProxyInfo;
this.proxy = new proxyType(Gio.DBus.session,
dbusName, dbusPath, Lang.bind(this, this._onProxyConstructed));
this.proxy = new Gio.DBusProxy({ g_bus_type: Gio.BusType.SESSION,
g_name: dbusName,
g_object_path: dbusPath,
g_interface_info: proxyInfo,
g_interface_name: proxyInfo.name,
g_flags: (Gio.DBusProxyFlags.DO_NOT_AUTO_START_AT_CONSTRUCTION |
Gio.DBusProxyFlags.DO_NOT_LOAD_PROPERTIES) });
this.proxy.init_async(GLib.PRIORITY_DEFAULT, null, null);
this.appInfo = appInfo;
this.id = appInfo.get_id();
this.isRemoteProvider = true;
this._cancellable = new Gio.Cancellable();
},
_onProxyConstructed: function(proxy) {
// Do nothing
},
createIcon: function(size, meta) {
@ -207,40 +207,43 @@ const RemoteSearchProvider = new Lang.Class({
icon_size: size });
},
_getResultsFinished: function(results, error) {
if (error)
filterResults: function(results, maxNumber) {
if (results.length <= maxNumber)
return results;
let regularResults = results.filter(function(r) { return !r.startsWith('special:'); });
let specialResults = results.filter(function(r) { return r.startsWith('special:'); });
return regularResults.slice(0, maxNumber).concat(specialResults.slice(0, maxNumber));
},
_getResultsFinished: function(results, error, callback) {
if (error) {
if (!error.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED))
log('Received error from DBus search provider %s: %s'.format(this.id, String(error)));
callback([]);
return;
this.searchSystem.setResults(this, results[0]);
}
callback(results[0]);
},
getInitialResultSet: function(terms) {
this._cancellable.cancel();
this._cancellable.reset();
try {
this.proxy.GetInitialResultSetRemote(terms,
Lang.bind(this, this._getResultsFinished),
this._cancellable);
} catch(e) {
log('Error calling GetInitialResultSet for provider %s: %s'.format(this.id, e.toString()));
this.searchSystem.setResults(this, []);
}
getInitialResultSet: function(terms, callback, cancellable) {
this.proxy.GetInitialResultSetRemote(terms,
Lang.bind(this, this._getResultsFinished, callback),
cancellable);
},
getSubsearchResultSet: function(previousResults, newTerms) {
this._cancellable.cancel();
this._cancellable.reset();
try {
this.proxy.GetSubsearchResultSetRemote(previousResults, newTerms,
Lang.bind(this, this._getResultsFinished),
this._cancellable);
} catch(e) {
log('Error calling GetSubsearchResultSet for provider %s: %s'.format(this.id, e.toString()));
this.searchSystem.setResults(this, []);
}
getSubsearchResultSet: function(previousResults, newTerms, callback, cancellable) {
this.proxy.GetSubsearchResultSetRemote(previousResults, newTerms,
Lang.bind(this, this._getResultsFinished, callback),
cancellable);
},
_getResultMetasFinished: function(results, error, callback) {
if (error) {
if (!error.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED))
log('Received error from DBus search provider %s during GetResultMetas: %s'.format(this.id, String(error)));
callback([]);
return;
}
@ -262,17 +265,10 @@ const RemoteSearchProvider = new Lang.Class({
callback(resultMetas);
},
getResultMetas: function(ids, callback) {
this._cancellable.cancel();
this._cancellable.reset();
try {
this.proxy.GetResultMetasRemote(ids,
Lang.bind(this, this._getResultMetasFinished, callback),
this._cancellable);
} catch(e) {
log('Error calling GetResultMetas for provider %s: %s'.format(this.id, e.toString()));
callback([]);
}
getResultMetas: function(ids, callback, cancellable) {
this.proxy.GetResultMetasRemote(ids,
Lang.bind(this, this._getResultMetasFinished, callback),
cancellable);
},
activateResult: function(id) {
@ -292,7 +288,7 @@ const RemoteSearchProvider2 = new Lang.Class({
Extends: RemoteSearchProvider,
_init: function(appInfo, dbusName, dbusPath) {
this.parent(appInfo, dbusName, dbusPath, SearchProvider2Proxy);
this.parent(appInfo, dbusName, dbusPath, SearchProvider2ProxyInfo);
this.canLaunchSearch = true;
},

View File

@ -19,6 +19,7 @@ const Background = imports.ui.background;
const GnomeSession = imports.misc.gnomeSession;
const Hash = imports.misc.hash;
const Layout = imports.ui.layout;
const OVirt = imports.gdm.oVirt;
const LoginManager = imports.misc.loginManager;
const Lightbox = imports.ui.lightbox;
const Main = imports.ui.main;
@ -197,8 +198,8 @@ const NotificationsBox = new Lang.Class({
let body = '';
if (n.bannerBodyText) {
body = n.bannerBodyMarkup ? n.bannerBodyText :
GLib.markup_escape_text(n.bannerBodyMarkup, -1);
body = n.bannerBodyMarkup ? n.bannerBodyText
: GLib.markup_escape_text(n.bannerBodyText, -1);
}
let label = new St.Label({ style_class: 'screen-shield-notification-count-text' });
@ -545,6 +546,13 @@ const ScreenShield = new Lang.Class({
this._liftShield(true, 0);
}));
this._oVirtCredentialsManager = OVirt.getOVirtCredentialsManager();
this._oVirtCredentialsManager.connect('user-authenticated',
Lang.bind(this, function() {
if (this._isLocked)
this._liftShield(true, 0);
}));
this._inhibitor = null;
this._aboutToSuspend = false;
this._loginManager = LoginManager.getLoginManager();
@ -584,6 +592,7 @@ const ScreenShield = new Lang.Class({
this._shortLightbox.connect('shown', Lang.bind(this, this._onShortLightboxShown));
this.idleMonitor = Meta.IdleMonitor.get_core();
this._cursorTracker = Meta.CursorTracker.get_for_screen(global.screen);
},
_createBackground: function(monitorIndex) {
@ -953,7 +962,7 @@ const ScreenShield = new Lang.Class({
this._hideLockScreenComplete();
}
global.stage.show_cursor();
this._cursorTracker.set_pointer_visible(true);
},
_ensureUnlockDialog: function(onPrimary, allowCancel) {
@ -1086,15 +1095,15 @@ const ScreenShield = new Lang.Class({
this._checkArrowAnimation();
let motionId = global.stage.connect('captured-event', function(stage, event) {
let motionId = global.stage.connect('captured-event', Lang.bind(this, function(stage, event) {
if (event.type() == Clutter.EventType.MOTION) {
global.stage.show_cursor();
this._cursorTracker.set_pointer_visible(true);
global.stage.disconnect(motionId);
}
return false;
});
global.stage.hide_cursor();
}));
this._cursorTracker.set_pointer_visible(false);
this._lockScreenState = MessageTray.State.SHOWN;
this._lockScreenGroup.fixed_position_set = false;

View File

@ -9,27 +9,29 @@ const Signals = imports.signals;
const Hash = imports.misc.hash;
const Main = imports.ui.main;
const ScreencastIface = <interface name="org.gnome.Shell.Screencast">
<method name="Screencast">
<arg type="s" direction="in" name="file_template"/>
<arg type="a{sv}" direction="in" name="options"/>
<arg type="b" direction="out" name="success"/>
<arg type="s" direction="out" name="filename_used"/>
</method>
<method name="ScreencastArea">
<arg type="i" direction="in" name="x"/>
<arg type="i" direction="in" name="y"/>
<arg type="i" direction="in" name="width"/>
<arg type="i" direction="in" name="height"/>
<arg type="s" direction="in" name="file_template"/>
<arg type="a{sv}" direction="in" name="options"/>
<arg type="b" direction="out" name="success"/>
<arg type="s" direction="out" name="filename_used"/>
</method>
<method name="StopScreencast">
<arg type="b" direction="out" name="success"/>
</method>
</interface>;
const ScreencastIface = '<node> \
<interface name="org.gnome.Shell.Screencast"> \
<method name="Screencast"> \
<arg type="s" direction="in" name="file_template"/> \
<arg type="a{sv}" direction="in" name="options"/> \
<arg type="b" direction="out" name="success"/> \
<arg type="s" direction="out" name="filename_used"/> \
</method> \
<method name="ScreencastArea"> \
<arg type="i" direction="in" name="x"/> \
<arg type="i" direction="in" name="y"/> \
<arg type="i" direction="in" name="width"/> \
<arg type="i" direction="in" name="height"/> \
<arg type="s" direction="in" name="file_template"/> \
<arg type="a{sv}" direction="in" name="options"/> \
<arg type="b" direction="out" name="success"/> \
<arg type="s" direction="out" name="filename_used"/> \
</method> \
<method name="StopScreencast"> \
<arg type="b" direction="out" name="success"/> \
</method> \
</interface> \
</node>';
const ScreencastService = new Lang.Class({
Name: 'ScreencastService',
@ -103,8 +105,10 @@ const ScreencastService = new Lang.Class({
ScreencastAsync: function(params, invocation) {
let returnValue = [false, ''];
if (!Main.sessionMode.allowScreencast)
if (!Main.sessionMode.allowScreencast) {
invocation.return_value(GLib.Variant.new('(bs)', returnValue));
return;
}
let sender = invocation.get_sender();
let recorder = this._ensureRecorderForSender(sender);
@ -122,8 +126,10 @@ const ScreencastService = new Lang.Class({
ScreencastAreaAsync: function(params, invocation) {
let returnValue = [false, ''];
if (!Main.sessionMode.allowScreencast)
if (!Main.sessionMode.allowScreencast) {
invocation.return_value(GLib.Variant.new('(bs)', returnValue));
return;
}
let sender = invocation.get_sender();
let recorder = this._ensureRecorderForSender(sender);
@ -131,6 +137,16 @@ const ScreencastService = new Lang.Class({
if (!recorder.is_recording()) {
let [x, y, width, height, fileTemplate, options] = params;
if (x < 0 || y < 0 ||
width <= 0 || height <= 0 ||
x + width > global.screen_width ||
y + height > global.screen_height) {
invocation.return_error_literal(Gio.IOErrorEnum,
Gio.IOErrorEnum.CANCELLED,
"Invalid params");
return;
}
recorder.set_file_template(fileTemplate);
recorder.set_area(x, y, width, height);
this._applyOptionalParameters(recorder, options);

View File

@ -6,6 +6,7 @@ const Gio = imports.gi.Gio;
const GLib = imports.gi.GLib;
const Gtk = imports.gi.Gtk;
const Lang = imports.lang;
const Meta = imports.gi.Meta;
const Shell = imports.gi.Shell;
const Signals = imports.signals;
const St = imports.gi.St;
@ -14,45 +15,47 @@ const Lightbox = imports.ui.lightbox;
const Main = imports.ui.main;
const Tweener = imports.ui.tweener;
const ScreenshotIface = <interface name="org.gnome.Shell.Screenshot">
<method name="ScreenshotArea">
<arg type="i" direction="in" name="x"/>
<arg type="i" direction="in" name="y"/>
<arg type="i" direction="in" name="width"/>
<arg type="i" direction="in" name="height"/>
<arg type="b" direction="in" name="flash"/>
<arg type="s" direction="in" name="filename"/>
<arg type="b" direction="out" name="success"/>
<arg type="s" direction="out" name="filename_used"/>
</method>
<method name="ScreenshotWindow">
<arg type="b" direction="in" name="include_frame"/>
<arg type="b" direction="in" name="include_cursor"/>
<arg type="b" direction="in" name="flash"/>
<arg type="s" direction="in" name="filename"/>
<arg type="b" direction="out" name="success"/>
<arg type="s" direction="out" name="filename_used"/>
</method>
<method name="Screenshot">
<arg type="b" direction="in" name="include_cursor"/>
<arg type="b" direction="in" name="flash"/>
<arg type="s" direction="in" name="filename"/>
<arg type="b" direction="out" name="success"/>
<arg type="s" direction="out" name="filename_used"/>
</method>
<method name="SelectArea">
<arg type="i" direction="out" name="x"/>
<arg type="i" direction="out" name="y"/>
<arg type="i" direction="out" name="width"/>
<arg type="i" direction="out" name="height"/>
</method>
<method name="FlashArea">
<arg type="i" direction="in" name="x"/>
<arg type="i" direction="in" name="y"/>
<arg type="i" direction="in" name="width"/>
<arg type="i" direction="in" name="height"/>
</method>
</interface>;
const ScreenshotIface = '<node> \
<interface name="org.gnome.Shell.Screenshot"> \
<method name="ScreenshotArea"> \
<arg type="i" direction="in" name="x"/> \
<arg type="i" direction="in" name="y"/> \
<arg type="i" direction="in" name="width"/> \
<arg type="i" direction="in" name="height"/> \
<arg type="b" direction="in" name="flash"/> \
<arg type="s" direction="in" name="filename"/> \
<arg type="b" direction="out" name="success"/> \
<arg type="s" direction="out" name="filename_used"/> \
</method> \
<method name="ScreenshotWindow"> \
<arg type="b" direction="in" name="include_frame"/> \
<arg type="b" direction="in" name="include_cursor"/> \
<arg type="b" direction="in" name="flash"/> \
<arg type="s" direction="in" name="filename"/> \
<arg type="b" direction="out" name="success"/> \
<arg type="s" direction="out" name="filename_used"/> \
</method> \
<method name="Screenshot"> \
<arg type="b" direction="in" name="include_cursor"/> \
<arg type="b" direction="in" name="flash"/> \
<arg type="s" direction="in" name="filename"/> \
<arg type="b" direction="out" name="success"/> \
<arg type="s" direction="out" name="filename_used"/> \
</method> \
<method name="SelectArea"> \
<arg type="i" direction="out" name="x"/> \
<arg type="i" direction="out" name="y"/> \
<arg type="i" direction="out" name="width"/> \
<arg type="i" direction="out" name="height"/> \
</method> \
<method name="FlashArea"> \
<arg type="i" direction="in" name="x"/> \
<arg type="i" direction="in" name="y"/> \
<arg type="i" direction="in" name="width"/> \
<arg type="i" direction="in" name="height"/> \
</method> \
</interface> \
</node>';
const ScreenshotService = new Lang.Class({
Name: 'ScreenshotService',
@ -76,7 +79,9 @@ const ScreenshotService = new Lang.Class({
ScreenshotAreaAsync : function (params, invocation) {
let [x, y, width, height, flash, filename, callback] = params;
if (height <= 0 || width <= 0) {
if (x < 0 || y < 0 ||
width <= 0 || height <= 0 ||
x + width > global.screen_width || y + height > global.screen_height) {
invocation.return_error_literal(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED,
"Invalid params");
return;
@ -167,7 +172,7 @@ const SelectArea = new Lang.Class({
if (!Main.pushModal(this._group) || this._group.visible)
return;
global.set_cursor(Shell.Cursor.CROSSHAIR);
global.screen.set_cursor(Meta.Cursor.CROSSHAIR);
this._group.visible = true;
},
@ -238,7 +243,7 @@ const SelectArea = new Lang.Class({
function() {
Main.popModal(this._group);
this._group.destroy();
global.unset_cursor();
global.screen.set_cursor(Meta.Cursor.DEFAULT);
this.emit('finished', geometry);
})

View File

@ -69,16 +69,18 @@ function waitLeisure() {
};
}
const PerfHelperIface = <interface name="org.gnome.Shell.PerfHelper">
<method name="CreateWindow">
<arg type="i" direction="in" />
<arg type="i" direction="in" />
<arg type="b" direction="in" />
<arg type="b" direction="in" />
</method>
<method name="WaitWindows" />
<method name="DestroyWindows" />
</interface>;
const PerfHelperIface = '<node> \
<interface name="org.gnome.Shell.PerfHelper"> \
<method name="CreateWindow"> \
<arg type="i" direction="in" /> \
<arg type="i" direction="in" /> \
<arg type="b" direction="in" /> \
<arg type="b" direction="in" /> \
</method> \
<method name="WaitWindows" /> \
<method name="DestroyWindows" /> \
</interface> \
</node>';
var PerfHelperProxy = Gio.DBusProxy.makeProxyWrapper(PerfHelperIface);
function PerfHelper() {

View File

@ -1,105 +1,706 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
const Clutter = imports.gi.Clutter;
const Lang = imports.lang;
const Gio = imports.gi.Gio;
const Gtk = imports.gi.Gtk;
const Meta = imports.gi.Meta;
const Signals = imports.signals;
const St = imports.gi.St;
const Atk = imports.gi.Atk;
const AppDisplay = imports.ui.appDisplay;
const DND = imports.ui.dnd;
const IconGrid = imports.ui.iconGrid;
const Main = imports.ui.main;
const Overview = imports.ui.overview;
const RemoteSearch = imports.ui.remoteSearch;
const Separator = imports.ui.separator;
const Util = imports.misc.util;
const SEARCH_PROVIDERS_SCHEMA = 'org.gnome.desktop.search-providers';
const MAX_LIST_SEARCH_RESULTS_ROWS = 3;
const MAX_GRID_SEARCH_RESULTS_ROWS = 1;
const SearchSystem = new Lang.Class({
Name: 'SearchSystem',
_init: function() {
this._providers = [];
this._remoteProviders = [];
this.reset();
this._registerProvider(new AppDisplay.AppSearchProvider());
this._searchSettings = new Gio.Settings({ schema: SEARCH_PROVIDERS_SCHEMA });
this._searchSettings.connect('changed::disabled', Lang.bind(this, this._reloadRemoteProviders));
this._searchSettings.connect('changed::disable-external', Lang.bind(this, this._reloadRemoteProviders));
this._searchSettings.connect('changed::sort-order', Lang.bind(this, this._reloadRemoteProviders));
this._reloadRemoteProviders();
this._cancellable = new Gio.Cancellable();
},
registerProvider: function (provider) {
provider.searchSystem = this;
addProvider: function(provider) {
this._providers.push(provider);
if (provider.isRemoteProvider)
this._remoteProviders.push(provider);
this.emit('providers-changed');
},
unregisterProvider: function (provider) {
let index = this._providers.indexOf(provider);
if (index == -1)
return;
provider.searchSystem = null;
this._providers.splice(index, 1);
_reloadRemoteProviders: function() {
let remoteProviders = this._providers.filter(function(provider) {
return provider.isRemoteProvider;
});
remoteProviders.forEach(Lang.bind(this, function(provider) {
this._unregisterProvider(provider);
}));
let remoteIndex = this._remoteProviders.indexOf(provider);
if (remoteIndex != -1)
this._remoteProviders.splice(remoteIndex, 1);
RemoteSearch.loadRemoteSearchProviders(Lang.bind(this, function(providers) {
providers.forEach(Lang.bind(this, this._registerProvider));
}));
this.emit('providers-changed');
},
_registerProvider: function (provider) {
this._providers.push(provider);
},
_unregisterProvider: function (provider) {
let index = this._providers.indexOf(provider);
this._providers.splice(index, 1);
},
getProviders: function() {
return this._providers;
},
getRemoteProviders: function() {
return this._remoteProviders;
},
getTerms: function() {
return this._previousTerms;
return this._terms;
},
reset: function() {
this._previousTerms = [];
this._previousResults = [];
this._terms = [];
this._results = {};
},
setResults: function(provider, results) {
let i = this._providers.indexOf(provider);
if (i == -1)
return;
this._previousResults[i] = [provider, results];
this.emit('search-updated', this._previousResults[i]);
_gotResults: function(results, provider) {
this._results[provider.id] = results;
this.emit('search-updated', provider, results);
},
updateSearchResults: function(terms) {
setTerms: function(terms) {
this._cancellable.cancel();
this._cancellable.reset();
let previousResults = this._results;
let previousTerms = this._terms;
this.reset();
if (!terms)
return;
let searchString = terms.join(' ');
let previousSearchString = this._previousTerms.join(' ');
let previousSearchString = previousTerms.join(' ');
if (searchString == previousSearchString)
return;
let isSubSearch = false;
if (this._previousTerms.length > 0)
if (previousTerms.length > 0)
isSubSearch = searchString.indexOf(previousSearchString) == 0;
let previousResultsArr = this._previousResults;
this._terms = terms;
let results = [];
this._previousTerms = terms;
this._previousResults = results;
if (isSubSearch) {
for (let i = 0; i < this._providers.length; i++) {
let [provider, previousResults] = previousResultsArr[i];
try {
results.push([provider, []]);
provider.getSubsearchResultSet(previousResults, terms);
} catch (error) {
log('A ' + error.name + ' has occured in ' + provider.id + ': ' + error.message);
}
}
} else {
for (let i = 0; i < this._providers.length; i++) {
let provider = this._providers[i];
try {
results.push([provider, []]);
provider.getInitialResultSet(terms);
} catch (error) {
log('A ' + error.name + ' has occured in ' + provider.id + ': ' + error.message);
}
}
}
this._providers.forEach(Lang.bind(this, function(provider) {
let previousProviderResults = previousResults[provider.id];
if (isSubSearch && previousProviderResults)
provider.getSubsearchResultSet(previousProviderResults, terms, Lang.bind(this, this._gotResults, provider), this._cancellable);
else
provider.getInitialResultSet(terms, Lang.bind(this, this._gotResults, provider), this._cancellable);
}));
}
});
Signals.addSignalMethods(SearchSystem.prototype);
const MaxWidthBin = new Lang.Class({
Name: 'MaxWidthBin',
Extends: St.Bin,
vfunc_allocate: function(box, flags) {
let themeNode = this.get_theme_node();
let maxWidth = themeNode.get_max_width();
let availWidth = box.x2 - box.x1;
let adjustedBox = box;
if (availWidth > maxWidth) {
let excessWidth = availWidth - maxWidth;
adjustedBox.x1 += Math.floor(excessWidth / 2);
adjustedBox.x2 -= Math.floor(excessWidth / 2);
}
this.parent(adjustedBox, flags);
}
});
const SearchResult = new Lang.Class({
Name: 'SearchResult',
_init: function(provider, metaInfo) {
this.provider = provider;
this.metaInfo = metaInfo;
this.actor = new St.Button({ reactive: true,
can_focus: true,
track_hover: true,
x_align: St.Align.START,
y_fill: true });
this.actor._delegate = this;
this.actor.connect('clicked', Lang.bind(this, this.activate));
},
activate: function() {
this.emit('activate', this.metaInfo.id);
},
setSelected: function(selected) {
if (selected)
this.actor.add_style_pseudo_class('selected');
else
this.actor.remove_style_pseudo_class('selected');
}
});
Signals.addSignalMethods(SearchResult.prototype);
const ListSearchResult = new Lang.Class({
Name: 'ListSearchResult',
Extends: SearchResult,
ICON_SIZE: 64,
_init: function(provider, metaInfo) {
this.parent(provider, metaInfo);
this.actor.style_class = 'list-search-result';
this.actor.x_fill = true;
let content = new St.BoxLayout({ style_class: 'list-search-result-content',
vertical: false });
this.actor.set_child(content);
// An icon for, or thumbnail of, content
let icon = this.metaInfo['createIcon'](this.ICON_SIZE);
if (icon) {
content.add(icon);
}
let details = new St.BoxLayout({ vertical: true });
content.add(details, { x_fill: true,
y_fill: false,
x_align: St.Align.START,
y_align: St.Align.MIDDLE });
let title = new St.Label({ style_class: 'list-search-result-title',
text: this.metaInfo['name'] })
details.add(title, { x_fill: false,
y_fill: false,
x_align: St.Align.START,
y_align: St.Align.START });
this.actor.label_actor = title;
if (this.metaInfo['description']) {
let description = new St.Label({ style_class: 'list-search-result-description' });
description.clutter_text.set_markup(this.metaInfo['description']);
details.add(description, { x_fill: false,
y_fill: false,
x_align: St.Align.START,
y_align: St.Align.END });
}
}
});
const GridSearchResult = new Lang.Class({
Name: 'GridSearchResult',
Extends: SearchResult,
_init: function(provider, metaInfo) {
this.parent(provider, metaInfo);
this.actor.style_class = 'grid-search-result';
let content = provider.createResultObject(metaInfo);
let dragSource = null;
if (content == null) {
let actor = new St.Bin();
let icon = new IconGrid.BaseIcon(this.metaInfo['name'],
{ createIcon: this.metaInfo['createIcon'] });
actor.set_child(icon.actor);
actor.label_actor = icon.label;
dragSource = icon.icon;
content = { actor: actor, icon: icon };
} else {
if (content._delegate && content._delegate.getDragActorSource)
dragSource = content._delegate.getDragActorSource();
}
this.actor.set_child(content.actor);
this.actor.label_actor = content.actor.label_actor;
this.icon = content.icon;
let draggable = DND.makeDraggable(this.actor);
draggable.connect('drag-begin',
Lang.bind(this, function() {
Main.overview.beginItemDrag(this);
}));
draggable.connect('drag-cancelled',
Lang.bind(this, function() {
Main.overview.cancelledItemDrag(this);
}));
draggable.connect('drag-end',
Lang.bind(this, function() {
Main.overview.endItemDrag(this);
}));
if (!dragSource)
// not exactly right, but alignment problems are hard to notice
dragSource = content;
this._dragActorSource = dragSource;
},
getDragActorSource: function() {
return this._dragActorSource;
},
getDragActor: function() {
return this.metaInfo['createIcon'](Main.overview.dashIconSize);
},
shellWorkspaceLaunch: function(params) {
if (this.provider.dragActivateResult)
this.provider.dragActivateResult(this.metaInfo.id, params);
else
this.provider.activateResult(this.metaInfo.id, this.terms);
}
});
const SearchResultsBase = new Lang.Class({
Name: 'SearchResultsBase',
_init: function(provider) {
this.provider = provider;
this._terms = [];
this.actor = new St.BoxLayout({ style_class: 'search-section',
vertical: true });
this._resultDisplayBin = new St.Bin({ x_fill: true,
y_fill: true });
this.actor.add(this._resultDisplayBin, { expand: true });
let separator = new Separator.HorizontalSeparator({ style_class: 'search-section-separator' });
this.actor.add(separator.actor);
this._resultDisplays = {};
this._cancellable = new Gio.Cancellable();
},
destroy: function() {
this.actor.destroy();
this._terms = [];
},
_clearResultDisplay: function() {
},
clear: function() {
this._resultDisplays = {};
this._clearResultDisplay();
this.actor.hide();
},
_keyFocusIn: function(actor) {
this.emit('key-focus-in', actor);
},
_activateResult: function(result, id) {
this.provider.activateResult(id, this._terms);
Main.overview.toggle();
},
_setMoreIconVisible: function(visible) {
},
_ensureResultActors: function(results, callback) {
let metasNeeded = results.filter(Lang.bind(this, function(resultId) {
return this._resultDisplays[resultId] === undefined;
}));
if (metasNeeded.length === 0) {
callback();
} else {
this._cancellable.cancel();
this._cancellable.reset();
this.provider.getResultMetas(metasNeeded, Lang.bind(this, function(metas) {
metasNeeded.forEach(Lang.bind(this, function(resultId, i) {
let meta = metas[i];
let display = this._createResultDisplay(meta);
display.connect('activate', Lang.bind(this, this._activateResult));
display.actor.connect('key-focus-in', Lang.bind(this, this._keyFocusIn));
this._resultDisplays[resultId] = display;
}));
callback();
}), this._cancellable);
}
},
updateSearch: function(providerResults, terms, callback) {
this._terms = terms;
if (providerResults.length == 0) {
this._clearResultDisplay();
this.actor.hide();
callback();
} else {
let maxResults = this._getMaxDisplayedResults();
let results = this.provider.filterResults(providerResults, maxResults);
let hasMoreResults = results.length < providerResults.length;
this._ensureResultActors(results, Lang.bind(this, function() {
this._clearResultDisplay();
// To avoid CSS transitions causing flickering when
// the first search result stays the same, we hide the
// content while filling in the results.
this.actor.hide();
this._clearResultDisplay();
results.forEach(Lang.bind(this, function(resultId) {
this._addItem(this._resultDisplays[resultId]);
}));
this._setMoreIconVisible(hasMoreResults && this.provider.canLaunchSearch);
this.actor.show();
callback();
}));
}
}
});
const ListSearchResults = new Lang.Class({
Name: 'ListSearchResults',
Extends: SearchResultsBase,
_init: function(provider) {
this.parent(provider);
this._container = new St.BoxLayout({ style_class: 'search-section-content' });
this.providerIcon = new ProviderIcon(provider);
this.providerIcon.connect('key-focus-in', Lang.bind(this, this._keyFocusIn));
this.providerIcon.connect('clicked', Lang.bind(this,
function() {
provider.launchSearch(this._terms);
Main.overview.toggle();
}));
this._container.add(this.providerIcon, { x_fill: false,
y_fill: false,
x_align: St.Align.START,
y_align: St.Align.START });
this._content = new St.BoxLayout({ style_class: 'list-search-results',
vertical: true });
this._container.add(this._content, { expand: true });
this._resultDisplayBin.set_child(this._container);
},
_setMoreIconVisible: function(visible) {
this.providerIcon.moreIcon.visible = true;
},
_getMaxDisplayedResults: function() {
return MAX_LIST_SEARCH_RESULTS_ROWS;
},
_clearResultDisplay: function () {
this._content.remove_all_children();
},
_createResultDisplay: function(meta) {
return new ListSearchResult(this.provider, meta);
},
_addItem: function(display) {
this._content.add_actor(display.actor);
},
getFirstResult: function() {
if (this._content.get_n_children() > 0)
return this._content.get_child_at_index(0)._delegate;
else
return null;
}
});
Signals.addSignalMethods(ListSearchResults.prototype);
const GridSearchResults = new Lang.Class({
Name: 'GridSearchResults',
Extends: SearchResultsBase,
_init: function(provider) {
this.parent(provider);
this._grid = new IconGrid.IconGrid({ rowLimit: MAX_GRID_SEARCH_RESULTS_ROWS,
xAlign: St.Align.START });
this._bin = new St.Bin({ x_align: St.Align.MIDDLE });
this._bin.set_child(this._grid.actor);
this._resultDisplayBin.set_child(this._bin);
},
_getMaxDisplayedResults: function() {
return this._grid.columnsForWidth(this._bin.width) * this._grid.getRowLimit();
},
_renderResults: function(metas) {
for (let i = 0; i < metas.length; i++) {
let display = new GridSearchResult(this.provider, metas[i]);
display.connect('activate', Lang.bind(this, this._activateResult));
display.actor.connect('key-focus-in', Lang.bind(this, this._keyFocusIn));
this._grid.addItem(display);
}
},
_clearResultDisplay: function () {
this._grid.removeAll();
},
_createResultDisplay: function(meta) {
return new GridSearchResult(this.provider, meta);
},
_addItem: function(display) {
this._grid.addItem(display);
},
getFirstResult: function() {
if (this._grid.visibleItemsCount() > 0)
return this._grid.getItemAtIndex(0)._delegate;
else
return null;
}
});
Signals.addSignalMethods(GridSearchResults.prototype);
const SearchResults = new Lang.Class({
Name: 'SearchResults',
_init: function() {
this.actor = new St.BoxLayout({ name: 'searchResults',
vertical: true });
this._content = new St.BoxLayout({ name: 'searchResultsContent',
vertical: true });
this._contentBin = new MaxWidthBin({ name: 'searchResultsBin',
x_fill: true,
y_fill: true,
child: this._content });
let scrollChild = new St.BoxLayout();
scrollChild.add(this._contentBin, { expand: true });
this._scrollView = new St.ScrollView({ x_fill: true,
y_fill: false,
overlay_scrollbars: true,
style_class: 'search-display vfade' });
this._scrollView.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC);
this._scrollView.add_actor(scrollChild);
let action = new Clutter.PanAction({ interpolate: true });
action.connect('pan', Lang.bind(this, this._onPan));
this._scrollView.add_action(action);
this.actor.add(this._scrollView, { x_fill: true,
y_fill: true,
expand: true,
x_align: St.Align.START,
y_align: St.Align.START });
this._statusText = new St.Label({ style_class: 'search-statustext' });
this._statusBin = new St.Bin({ x_align: St.Align.MIDDLE,
y_align: St.Align.MIDDLE });
this._content.add(this._statusBin, { expand: true });
this._statusBin.add_actor(this._statusText);
this._highlightDefault = false;
this._defaultResult = null;
this._searchSystem = new SearchSystem();
this._searchSystem.connect('search-updated', Lang.bind(this, this._updateResults));
this._searchSystem.connect('providers-changed', Lang.bind(this, this._updateProviderDisplays));
this._updateProviderDisplays();
},
_onPan: function(action) {
let [dist, dx, dy] = action.get_motion_delta(0);
let adjustment = this._scrollView.vscroll.adjustment;
adjustment.value -= (dy / this.actor.height) * adjustment.page_size;
return false;
},
_keyFocusIn: function(provider, actor) {
Util.ensureActorVisibleInScrollView(this._scrollView, actor);
},
_ensureProviderDisplay: function(provider) {
if (provider.display)
return;
let providerDisplay;
if (provider.appInfo)
providerDisplay = new ListSearchResults(provider);
else
providerDisplay = new GridSearchResults(provider);
providerDisplay.connect('key-focus-in', Lang.bind(this, this._keyFocusIn));
this._content.add(providerDisplay.actor);
provider.display = providerDisplay;
},
_updateProviderDisplays: function() {
this._searchSystem.getProviders().forEach(Lang.bind(this, this._ensureProviderDisplay));
},
_clearDisplay: function() {
this._searchSystem.getProviders().forEach(function(provider) {
provider.display.clear();
});
},
reset: function() {
this._searchSystem.reset();
this._statusBin.hide();
this._clearDisplay();
this._defaultResult = null;
},
startingSearch: function() {
this.reset();
this._statusText.set_text(_("Searching…"));
this._statusBin.show();
},
setTerms: function(terms) {
this._searchSystem.setTerms(terms);
},
_maybeSetInitialSelection: function() {
let newDefaultResult = null;
let providers = this._searchSystem.getProviders();
for (let i = 0; i < providers.length; i++) {
let provider = providers[i];
let display = provider.display;
if (!display.actor.visible)
continue;
let firstResult = display.getFirstResult();
if (firstResult) {
newDefaultResult = firstResult;
break; // select this one!
}
}
if (newDefaultResult != this._defaultResult) {
if (this._defaultResult)
this._defaultResult.setSelected(false);
if (newDefaultResult)
newDefaultResult.setSelected(this._highlightDefault);
this._defaultResult = newDefaultResult;
}
},
_updateStatusText: function () {
let haveResults = this._searchSystem.getProviders().some(function(provider) {
let display = provider.display;
return (display.getFirstResult() != null);
});
if (!haveResults) {
this._statusText.set_text(_("No results."));
this._statusBin.show();
} else {
this._statusBin.hide();
}
},
_updateResults: function(searchSystem, provider, results) {
let terms = searchSystem.getTerms();
let display = provider.display;
display.updateSearch(results, terms, Lang.bind(this, function() {
this._maybeSetInitialSelection();
this._updateStatusText();
}));
},
activateDefault: function() {
if (this._defaultResult)
this._defaultResult.activate();
},
highlightDefault: function(highlight) {
this._highlightDefault = highlight;
if (this._defaultResult)
this._defaultResult.setSelected(highlight);
},
navigateFocus: function(direction) {
let rtl = this.actor.get_text_direction() == Clutter.TextDirection.RTL;
if (direction == Gtk.DirectionType.TAB_BACKWARD ||
direction == (rtl ? Gtk.DirectionType.RIGHT
: Gtk.DirectionType.LEFT) ||
direction == Gtk.DirectionType.UP) {
this.actor.navigate_focus(null, direction, false);
return;
}
let from = this._defaultResult ? this._defaultResult.actor : null;
this.actor.navigate_focus(from, direction, false);
}
});
const ProviderIcon = new Lang.Class({
Name: 'ProviderIcon',
Extends: St.Button,
PROVIDER_ICON_SIZE: 48,
_init: function(provider) {
this.provider = provider;
this.parent({ style_class: 'search-provider-icon',
reactive: true,
can_focus: true,
accessible_name: provider.appInfo.get_name(),
track_hover: true });
this._content = new St.Widget({ layout_manager: new Clutter.BinLayout() });
this.set_child(this._content);
let rtl = (this.get_text_direction() == Clutter.TextDirection.RTL);
this.moreIcon = new St.Widget({ style_class: 'search-provider-icon-more',
visible: false,
x_align: rtl ? Clutter.ActorAlign.START : Clutter.ActorAlign.END,
y_align: Clutter.ActorAlign.END,
x_expand: true,
y_expand: true });
let icon = new St.Icon({ icon_size: this.PROVIDER_ICON_SIZE,
gicon: provider.appInfo.get_icon() });
this._content.add_actor(icon);
this._content.add_actor(this.moreIcon);
}
});

View File

@ -1,566 +0,0 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
const Clutter = imports.gi.Clutter;
const Lang = imports.lang;
const Gtk = imports.gi.Gtk;
const Meta = imports.gi.Meta;
const Signals = imports.signals;
const St = imports.gi.St;
const Atk = imports.gi.Atk;
const DND = imports.ui.dnd;
const IconGrid = imports.ui.iconGrid;
const Main = imports.ui.main;
const Overview = imports.ui.overview;
const Separator = imports.ui.separator;
const Search = imports.ui.search;
const Util = imports.misc.util;
const MAX_LIST_SEARCH_RESULTS_ROWS = 3;
const MAX_GRID_SEARCH_RESULTS_ROWS = 1;
const MaxWidthBin = new Lang.Class({
Name: 'MaxWidthBin',
Extends: St.Bin,
vfunc_allocate: function(box, flags) {
let themeNode = this.get_theme_node();
let maxWidth = themeNode.get_max_width();
let availWidth = box.x2 - box.x1;
let adjustedBox = box;
if (availWidth > maxWidth) {
let excessWidth = availWidth - maxWidth;
adjustedBox.x1 += Math.floor(excessWidth / 2);
adjustedBox.x2 -= Math.floor(excessWidth / 2);
}
this.parent(adjustedBox, flags);
}
});
const SearchResult = new Lang.Class({
Name: 'SearchResult',
_init: function(provider, metaInfo, terms) {
this.provider = provider;
this.metaInfo = metaInfo;
this.terms = terms;
this.actor = new St.Button({ reactive: true,
can_focus: true,
track_hover: true,
x_align: St.Align.START,
y_fill: true });
this.actor._delegate = this;
this.actor.connect('clicked', Lang.bind(this, this.activate));
},
activate: function() {
this.provider.activateResult(this.metaInfo.id, this.terms);
Main.overview.toggle();
},
setSelected: function(selected) {
if (selected)
this.actor.add_style_pseudo_class('selected');
else
this.actor.remove_style_pseudo_class('selected');
}
});
const ListSearchResult = new Lang.Class({
Name: 'ListSearchResult',
Extends: SearchResult,
ICON_SIZE: 64,
_init: function(provider, metaInfo, terms) {
this.parent(provider, metaInfo, terms);
this.actor.style_class = 'list-search-result';
this.actor.x_fill = true;
let content = new St.BoxLayout({ style_class: 'list-search-result-content',
vertical: false });
this.actor.set_child(content);
// An icon for, or thumbnail of, content
let icon = this.metaInfo['createIcon'](this.ICON_SIZE);
if (icon) {
content.add(icon);
}
let details = new St.BoxLayout({ vertical: true });
content.add(details, { x_fill: true,
y_fill: false,
x_align: St.Align.START,
y_align: St.Align.MIDDLE });
let title = new St.Label({ style_class: 'list-search-result-title',
text: this.metaInfo['name'] })
details.add(title, { x_fill: false,
y_fill: false,
x_align: St.Align.START,
y_align: St.Align.START });
this.actor.label_actor = title;
if (this.metaInfo['description']) {
let description = new St.Label({ style_class: 'list-search-result-description' });
description.clutter_text.set_markup(this.metaInfo['description']);
details.add(description, { x_fill: false,
y_fill: false,
x_align: St.Align.START,
y_align: St.Align.END });
}
}
});
const GridSearchResult = new Lang.Class({
Name: 'GridSearchResult',
Extends: SearchResult,
_init: function(provider, metaInfo, terms) {
this.parent(provider, metaInfo, terms);
this.actor.style_class = 'grid-search-result';
let content = provider.createResultObject(metaInfo, terms);
let dragSource = null;
if (content == null) {
let actor = new St.Bin();
let icon = new IconGrid.BaseIcon(this.metaInfo['name'],
{ createIcon: this.metaInfo['createIcon'] });
actor.set_child(icon.actor);
actor.label_actor = icon.label;
dragSource = icon.icon;
content = { actor: actor, icon: icon };
} else {
if (content._delegate && content._delegate.getDragActorSource)
dragSource = content._delegate.getDragActorSource();
}
this.actor.set_child(content.actor);
this.actor.label_actor = content.actor.label_actor;
this.icon = content.icon;
let draggable = DND.makeDraggable(this.actor);
draggable.connect('drag-begin',
Lang.bind(this, function() {
Main.overview.beginItemDrag(this);
}));
draggable.connect('drag-cancelled',
Lang.bind(this, function() {
Main.overview.cancelledItemDrag(this);
}));
draggable.connect('drag-end',
Lang.bind(this, function() {
Main.overview.endItemDrag(this);
}));
if (!dragSource)
// not exactly right, but alignment problems are hard to notice
dragSource = content;
this._dragActorSource = dragSource;
},
getDragActorSource: function() {
return this._dragActorSource;
},
getDragActor: function() {
return this.metaInfo['createIcon'](Main.overview.dashIconSize);
},
shellWorkspaceLaunch: function(params) {
if (this.provider.dragActivateResult)
this.provider.dragActivateResult(this.metaInfo.id, params);
else
this.provider.activateResult(this.metaInfo.id, this.terms);
}
});
const SearchResultsBase = new Lang.Class({
Name: 'SearchResultsBase',
_init: function(provider) {
this.provider = provider;
this._terms = [];
this.actor = new St.BoxLayout({ style_class: 'search-section',
vertical: true });
this._resultDisplayBin = new St.Bin({ x_fill: true,
y_fill: true });
this.actor.add(this._resultDisplayBin, { expand: true });
let separator = new Separator.HorizontalSeparator({ style_class: 'search-section-separator' });
this.actor.add(separator.actor);
},
destroy: function() {
this.actor.destroy();
this._terms = [];
},
_clearResultDisplay: function() {
},
clear: function() {
this._clearResultDisplay();
this.actor.hide();
},
_keyFocusIn: function(icon) {
this.emit('key-focus-in', icon);
},
_setMoreIconVisible: function(visible) {
},
updateSearch: function(providerResults, terms, callback) {
this._terms = terms;
if (providerResults.length == 0) {
this._clearResultDisplay();
this.actor.hide();
callback();
} else {
let maxResults = this._getMaxDisplayedResults();
let results = providerResults.slice(0, maxResults);
let hasMoreResults = results.length < providerResults.length;
this.provider.getResultMetas(results, Lang.bind(this, function(metas) {
this.clear();
// To avoid CSS transitions causing flickering when
// the first search result stays the same, we hide the
// content while filling in the results.
this.actor.hide();
this._clearResultDisplay();
this._renderResults(metas);
this._setMoreIconVisible(hasMoreResults && this.provider.canLaunchSearch);
this.actor.show();
callback();
}));
}
}
});
const ListSearchResults = new Lang.Class({
Name: 'ListSearchResults',
Extends: SearchResultsBase,
_init: function(provider) {
this.parent(provider);
this._container = new St.BoxLayout({ style_class: 'search-section-content' });
this.providerIcon = new ProviderIcon(provider);
this.providerIcon.connect('clicked', Lang.bind(this,
function() {
provider.launchSearch(this._terms);
Main.overview.toggle();
}));
this._container.add(this.providerIcon, { x_fill: false,
y_fill: false,
x_align: St.Align.START,
y_align: St.Align.START });
this._content = new St.BoxLayout({ style_class: 'list-search-results',
vertical: true });
this._container.add(this._content, { expand: true });
this._resultDisplayBin.set_child(this._container);
},
_setMoreIconVisible: function(visible) {
this.providerIcon.moreIcon.visible = true;
},
_getMaxDisplayedResults: function() {
return MAX_LIST_SEARCH_RESULTS_ROWS;
},
_renderResults: function(metas) {
for (let i = 0; i < metas.length; i++) {
let display = new ListSearchResult(this.provider, metas[i], this._terms);
display.actor.connect('key-focus-in', Lang.bind(this, this._keyFocusIn));
this._content.add_actor(display.actor);
}
},
_clearResultDisplay: function () {
this._content.destroy_all_children();
},
getFirstResult: function() {
if (this._content.get_n_children() > 0)
return this._content.get_child_at_index(0)._delegate;
else
return null;
}
});
Signals.addSignalMethods(ListSearchResults.prototype);
const GridSearchResults = new Lang.Class({
Name: 'GridSearchResults',
Extends: SearchResultsBase,
_init: function(provider) {
this.parent(provider);
this._grid = new IconGrid.IconGrid({ rowLimit: MAX_GRID_SEARCH_RESULTS_ROWS,
xAlign: St.Align.START });
this._bin = new St.Bin({ x_align: St.Align.MIDDLE });
this._bin.set_child(this._grid.actor);
this._resultDisplayBin.set_child(this._bin);
},
_getMaxDisplayedResults: function() {
return this._grid.columnsForWidth(this._bin.width) * this._grid.getRowLimit();
},
_renderResults: function(metas) {
for (let i = 0; i < metas.length; i++) {
let display = new GridSearchResult(this.provider, metas[i], this._terms);
display.actor.connect('key-focus-in', Lang.bind(this, this._keyFocusIn));
this._grid.addItem(display);
}
},
_clearResultDisplay: function () {
this._grid.removeAll();
},
getFirstResult: function() {
if (this._grid.visibleItemsCount() > 0)
return this._grid.getItemAtIndex(0)._delegate;
else
return null;
}
});
Signals.addSignalMethods(GridSearchResults.prototype);
const SearchResults = new Lang.Class({
Name: 'SearchResults',
_init: function(searchSystem) {
this._searchSystem = searchSystem;
this._searchSystem.connect('search-updated', Lang.bind(this, this._updateResults));
this.actor = new St.BoxLayout({ name: 'searchResults',
vertical: true });
this._content = new St.BoxLayout({ name: 'searchResultsContent',
vertical: true });
this._contentBin = new MaxWidthBin({ name: 'searchResultsBin',
x_fill: true,
y_fill: true,
child: this._content });
let scrollChild = new St.BoxLayout();
scrollChild.add(this._contentBin, { expand: true });
this._scrollView = new St.ScrollView({ x_fill: true,
y_fill: false,
overlay_scrollbars: true,
style_class: 'search-display vfade' });
this._scrollView.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC);
this._scrollView.add_actor(scrollChild);
let action = new Clutter.PanAction({ interpolate: true });
action.connect('pan', Lang.bind(this, this._onPan));
this._scrollView.add_action(action);
this.actor.add(this._scrollView, { x_fill: true,
y_fill: true,
expand: true,
x_align: St.Align.START,
y_align: St.Align.START });
this._statusText = new St.Label({ style_class: 'search-statustext' });
this._statusBin = new St.Bin({ x_align: St.Align.MIDDLE,
y_align: St.Align.MIDDLE });
this._content.add(this._statusBin, { expand: true });
this._statusBin.add_actor(this._statusText);
this._providers = this._searchSystem.getProviders();
this._providerDisplays = {};
for (let i = 0; i < this._providers.length; i++) {
this.createProviderDisplay(this._providers[i]);
}
this._highlightDefault = false;
this._defaultResult = null;
},
_onPan: function(action) {
let [dist, dx, dy] = action.get_motion_delta(0);
let adjustment = this._scrollView.vscroll.adjustment;
adjustment.value -= (dy / this.actor.height) * adjustment.page_size;
return false;
},
_keyFocusIn: function(provider, icon) {
Util.ensureActorVisibleInScrollView(this._scrollView, icon);
},
createProviderDisplay: function(provider) {
let providerDisplay = null;
if (provider.appInfo) {
providerDisplay = new ListSearchResults(provider);
} else {
providerDisplay = new GridSearchResults(provider);
}
providerDisplay.connect('key-focus-in', Lang.bind(this, this._keyFocusIn));
this._providerDisplays[provider.id] = providerDisplay;
this._content.add(providerDisplay.actor);
},
destroyProviderDisplay: function(provider) {
this._providerDisplays[provider.id].destroy();
delete this._providerDisplays[provider.id];
},
_clearDisplay: function() {
for (let i = 0; i < this._providers.length; i++) {
let provider = this._providers[i];
let providerDisplay = this._providerDisplays[provider.id];
providerDisplay.clear();
}
},
reset: function() {
this._searchSystem.reset();
this._statusBin.hide();
this._clearDisplay();
this._defaultResult = null;
},
startingSearch: function() {
this.reset();
this._statusText.set_text(_("Searching…"));
this._statusBin.show();
},
_maybeSetInitialSelection: function() {
let newDefaultResult = null;
for (let i = 0; i < this._providers.length; i++) {
let provider = this._providers[i];
let display = this._providerDisplays[provider.id];
if (!display.actor.visible)
continue;
let firstResult = display.getFirstResult();
if (firstResult) {
newDefaultResult = firstResult;
break; // select this one!
}
}
if (newDefaultResult != this._defaultResult) {
if (this._defaultResult)
this._defaultResult.setSelected(false);
if (newDefaultResult)
newDefaultResult.setSelected(this._highlightDefault);
this._defaultResult = newDefaultResult;
}
},
_updateStatusText: function () {
let haveResults = false;
for (let i = 0; i < this._providers.length; i++) {
let provider = this._providers[i];
let display = this._providerDisplays[provider.id];
if (display.getFirstResult()) {
haveResults = true;
break;
}
}
if (!haveResults) {
this._statusText.set_text(_("No results."));
this._statusBin.show();
} else {
this._statusBin.hide();
}
},
_updateResults: function(searchSystem, results) {
let terms = searchSystem.getTerms();
let [provider, providerResults] = results;
let display = this._providerDisplays[provider.id];
display.updateSearch(providerResults, terms, Lang.bind(this, function() {
this._maybeSetInitialSelection();
this._updateStatusText();
}));
},
activateDefault: function() {
if (this._defaultResult)
this._defaultResult.activate();
},
highlightDefault: function(highlight) {
this._highlightDefault = highlight;
if (this._defaultResult)
this._defaultResult.setSelected(highlight);
},
navigateFocus: function(direction) {
let rtl = this.actor.get_text_direction() == Clutter.TextDirection.RTL;
if (direction == Gtk.DirectionType.TAB_BACKWARD ||
direction == (rtl ? Gtk.DirectionType.RIGHT
: Gtk.DirectionType.LEFT) ||
direction == Gtk.DirectionType.UP) {
this.actor.navigate_focus(null, direction, false);
return;
}
let from = this._defaultResult ? this._defaultResult.actor : null;
this.actor.navigate_focus(from, direction, false);
}
});
const ProviderIcon = new Lang.Class({
Name: 'ProviderIcon',
Extends: St.Button,
PROVIDER_ICON_SIZE: 48,
_init: function(provider) {
this.provider = provider;
this.parent({ style_class: 'search-provider-icon',
reactive: true,
can_focus: true,
accessible_name: provider.appInfo.get_name(),
track_hover: true });
this._content = new St.Widget({ layout_manager: new Clutter.BinLayout() });
this.set_child(this._content);
let rtl = (this.get_text_direction() == Clutter.TextDirection.RTL);
this.moreIcon = new St.Widget({ style_class: 'search-provider-icon-more',
visible: false,
x_align: rtl ? Clutter.ActorAlign.START : Clutter.ActorAlign.END,
y_align: Clutter.ActorAlign.END,
x_expand: true,
y_expand: true });
let icon = new St.Icon({ icon_size: this.PROVIDER_ICON_SIZE,
gicon: provider.appInfo.get_icon() });
this._content.add_actor(icon);
this._content.add_actor(this.moreIcon);
}
});

View File

@ -102,19 +102,12 @@ const _modes = {
}
};
function _getModes(modesLoadedCallback) {
FileUtils.collectFromDatadirsAsync('modes',
{ processFile: _loadMode,
loadedCallback: modesLoadedCallback,
data: _modes });
}
function _loadMode(file, info, loadedData) {
function _loadMode(file, info) {
let name = info.get_name();
let suffix = name.indexOf('.json');
let modeName = suffix == -1 ? name : name.slice(name, suffix);
if (loadedData.hasOwnProperty(modeName))
if (_modes.hasOwnProperty(modeName))
return;
let fileContent, success, tag, newMode;
@ -125,18 +118,23 @@ function _loadMode(file, info, loadedData) {
return;
}
loadedData[modeName] = {};
_modes[modeName] = {};
let propBlacklist = ['unlockDialog'];
for (let prop in loadedData[DEFAULT_MODE]) {
if (newMode[prop] !== undefined &&
propBlacklist.indexOf(prop) == -1)
loadedData[modeName][prop]= newMode[prop];
loadedData[modeName][prop] = newMode[prop];
}
loadedData[modeName]['isPrimary'] = true;
_modes[modeName]['isPrimary'] = true;
}
function _getModes() {
FileUtils.collectFromDatadirs('modes', false, _loadMode);
}
function listModes() {
_getModes(function(modes) {
let modes = _getModes();
modes.forEach(function() {
let names = Object.getOwnPropertyNames(modes);
for (let i = 0; i < names.length; i++)
if (_modes[names[i]].isPrimary)
@ -149,17 +147,12 @@ function listModes() {
const SessionMode = new Lang.Class({
Name: 'SessionMode',
init: function() {
_getModes(Lang.bind(this, function(modes) {
this._modes = modes;
let primary = modes[global.session_mode] &&
modes[global.session_mode].isPrimary;
let mode = primary ? global.session_mode : 'user';
this._modeStack = [mode];
this._sync();
this.emit('sessions-loaded');
}));
_init: function() {
let isPrimary = (_modes[global.session_mode] &&
_modes[global.session_mode].isPrimary);
let mode = isPrimary ? global.session_mode : 'user';
this._modeStack = [mode];
this._sync();
},
pushMode: function(mode) {
@ -186,13 +179,13 @@ const SessionMode = new Lang.Class({
},
_sync: function() {
let params = this._modes[this.currentMode];
let params = _modes[this.currentMode];
let defaults;
if (params.parentMode)
defaults = Params.parse(this._modes[params.parentMode],
this._modes[DEFAULT_MODE]);
defaults = Params.parse(_modes[params.parentMode],
_modes[DEFAULT_MODE]);
else
defaults = this._modes[DEFAULT_MODE];
defaults = _modes[DEFAULT_MODE];
params = Params.parse(params, defaults);
// A simplified version of Lang.copyProperties, handles

View File

@ -15,59 +15,63 @@ const Main = imports.ui.main;
const Screenshot = imports.ui.screenshot;
const ViewSelector = imports.ui.viewSelector;
const GnomeShellIface = <interface name="org.gnome.Shell">
<method name="Eval">
<arg type="s" direction="in" name="script" />
<arg type="b" direction="out" name="success" />
<arg type="s" direction="out" name="result" />
</method>
<method name="FocusSearch"/>
<method name="ShowOSD">
<arg type="a{sv}" direction="in" name="params"/>
</method>
<method name="FocusApp">
<arg type="s" direction="in" name="id"/>
</method>
<method name="ShowApplications" />
<method name="GrabAccelerator">
<arg type="s" direction="in" name="accelerator"/>
<arg type="u" direction="in" name="flags"/>
<arg type="u" direction="out" name="action"/>
</method>
<method name="GrabAccelerators">
<arg type="a(su)" direction="in" name="accelerators"/>
<arg type="au" direction="out" name="actions"/>
</method>
<method name="UngrabAccelerator">
<arg type="u" direction="in" name="action"/>
<arg type="b" direction="out" name="success"/>
</method>
<signal name="AcceleratorActivated">
<arg name="action" type="u" />
<arg name="deviceid" type="u" />
<arg name="timestamp" type="u" />
</signal>
<property name="Mode" type="s" access="read" />
<property name="OverviewActive" type="b" access="readwrite" />
<property name="ShellVersion" type="s" access="read" />
</interface>;
const GnomeShellIface = '<node> \
<interface name="org.gnome.Shell"> \
<method name="Eval"> \
<arg type="s" direction="in" name="script" /> \
<arg type="b" direction="out" name="success" /> \
<arg type="s" direction="out" name="result" /> \
</method> \
<method name="FocusSearch"/> \
<method name="ShowOSD"> \
<arg type="a{sv}" direction="in" name="params"/> \
</method> \
<method name="FocusApp"> \
<arg type="s" direction="in" name="id"/> \
</method> \
<method name="ShowApplications" /> \
<method name="GrabAccelerator"> \
<arg type="s" direction="in" name="accelerator"/> \
<arg type="u" direction="in" name="flags"/> \
<arg type="u" direction="out" name="action"/> \
</method> \
<method name="GrabAccelerators"> \
<arg type="a(su)" direction="in" name="accelerators"/> \
<arg type="au" direction="out" name="actions"/> \
</method> \
<method name="UngrabAccelerator"> \
<arg type="u" direction="in" name="action"/> \
<arg type="b" direction="out" name="success"/> \
</method> \
<signal name="AcceleratorActivated"> \
<arg name="action" type="u" /> \
<arg name="deviceid" type="u" /> \
<arg name="timestamp" type="u" /> \
</signal> \
<property name="Mode" type="s" access="read" /> \
<property name="OverviewActive" type="b" access="readwrite" /> \
<property name="ShellVersion" type="s" access="read" /> \
</interface> \
</node>';
const ScreenSaverIface = <interface name="org.gnome.ScreenSaver">
<method name="Lock">
</method>
<method name="GetActive">
<arg name="active" direction="out" type="b" />
</method>
<method name="SetActive">
<arg name="value" direction="in" type="b" />
</method>
<method name="GetActiveTime">
<arg name="value" direction="out" type="u" />
</method>
<signal name="ActiveChanged">
<arg name="new_value" type="b" />
</signal>
</interface>;
const ScreenSaverIface = '<node> \
<interface name="org.gnome.ScreenSaver"> \
<method name="Lock"> \
</method> \
<method name="GetActive"> \
<arg name="active" direction="out" type="b" /> \
</method> \
<method name="SetActive"> \
<arg name="value" direction="in" type="b" /> \
</method> \
<method name="GetActiveTime"> \
<arg name="value" direction="out" type="u" /> \
</method> \
<signal name="ActiveChanged"> \
<arg name="new_value" type="b" /> \
</signal> \
</interface> \
</node>';
const GnomeShell = new Lang.Class({
Name: 'GnomeShellDBus',
@ -115,7 +119,7 @@ const GnomeShell = new Lang.Class({
returnValue = '';
success = true;
} catch (e) {
returnValue = JSON.stringify(e);
returnValue = '' + e;
success = false;
}
return [success, returnValue];
@ -246,41 +250,43 @@ const GnomeShell = new Lang.Class({
ShellVersion: Config.PACKAGE_VERSION
});
const GnomeShellExtensionsIface = <interface name="org.gnome.Shell.Extensions">
<method name="ListExtensions">
<arg type="a{sa{sv}}" direction="out" name="extensions" />
</method>
<method name="GetExtensionInfo">
<arg type="s" direction="in" name="extension" />
<arg type="a{sv}" direction="out" name="info" />
</method>
<method name="GetExtensionErrors">
<arg type="s" direction="in" name="extension" />
<arg type="as" direction="out" name="errors" />
</method>
<signal name="ExtensionStatusChanged">
<arg type="s" name="uuid"/>
<arg type="i" name="state"/>
<arg type="s" name="error"/>
</signal>
<method name="InstallRemoteExtension">
<arg type="s" direction="in" name="uuid"/>
<arg type="s" direction="out" name="result"/>
</method>
<method name="UninstallExtension">
<arg type="s" direction="in" name="uuid"/>
<arg type="b" direction="out" name="success"/>
</method>
<method name="LaunchExtensionPrefs">
<arg type="s" direction="in" name="uuid"/>
</method>
<method name="ReloadExtension">
<arg type="s" direction="in" name="uuid"/>
</method>
<method name="CheckForUpdates">
</method>
<property name="ShellVersion" type="s" access="read" />
</interface>;
const GnomeShellExtensionsIface = '<node> \
<interface name="org.gnome.Shell.Extensions"> \
<method name="ListExtensions"> \
<arg type="a{sa{sv}}" direction="out" name="extensions" /> \
</method> \
<method name="GetExtensionInfo"> \
<arg type="s" direction="in" name="extension" /> \
<arg type="a{sv}" direction="out" name="info" /> \
</method> \
<method name="GetExtensionErrors"> \
<arg type="s" direction="in" name="extension" /> \
<arg type="as" direction="out" name="errors" /> \
</method> \
<signal name="ExtensionStatusChanged"> \
<arg type="s" name="uuid"/> \
<arg type="i" name="state"/> \
<arg type="s" name="error"/> \
</signal> \
<method name="InstallRemoteExtension"> \
<arg type="s" direction="in" name="uuid"/> \
<arg type="s" direction="out" name="result"/> \
</method> \
<method name="UninstallExtension"> \
<arg type="s" direction="in" name="uuid"/> \
<arg type="b" direction="out" name="success"/> \
</method> \
<method name="LaunchExtensionPrefs"> \
<arg type="s" direction="in" name="uuid"/> \
</method> \
<method name="ReloadExtension"> \
<arg type="s" direction="in" name="uuid"/> \
</method> \
<method name="CheckForUpdates"> \
</method> \
<property name="ShellVersion" type="s" access="read" /> \
</interface> \
</node>';
const GnomeShellExtensions = new Lang.Class({
Name: 'GnomeShellExtensionsDBus',

View File

@ -521,36 +521,38 @@ const ShellProcessesDialog = new Lang.Class({
});
Signals.addSignalMethods(ShellProcessesDialog.prototype);
const GnomeShellMountOpIface = <interface name="org.Gtk.MountOperationHandler">
<method name="AskPassword">
<arg type="s" direction="in" name="object_id"/>
<arg type="s" direction="in" name="message"/>
<arg type="s" direction="in" name="icon_name"/>
<arg type="s" direction="in" name="default_user"/>
<arg type="s" direction="in" name="default_domain"/>
<arg type="u" direction="in" name="flags"/>
<arg type="u" direction="out" name="response"/>
<arg type="a{sv}" direction="out" name="response_details"/>
</method>
<method name="AskQuestion">
<arg type="s" direction="in" name="object_id"/>
<arg type="s" direction="in" name="message"/>
<arg type="s" direction="in" name="icon_name"/>
<arg type="as" direction="in" name="choices"/>
<arg type="u" direction="out" name="response"/>
<arg type="a{sv}" direction="out" name="response_details"/>
</method>
<method name="ShowProcesses">
<arg type="s" direction="in" name="object_id"/>
<arg type="s" direction="in" name="message"/>
<arg type="s" direction="in" name="icon_name"/>
<arg type="ai" direction="in" name="application_pids"/>
<arg type="as" direction="in" name="choices"/>
<arg type="u" direction="out" name="response"/>
<arg type="a{sv}" direction="out" name="response_details"/>
</method>
<method name="Close"/>
</interface>;
const GnomeShellMountOpIface = '<node> \
<interface name="org.Gtk.MountOperationHandler"> \
<method name="AskPassword"> \
<arg type="s" direction="in" name="object_id"/> \
<arg type="s" direction="in" name="message"/> \
<arg type="s" direction="in" name="icon_name"/> \
<arg type="s" direction="in" name="default_user"/> \
<arg type="s" direction="in" name="default_domain"/> \
<arg type="u" direction="in" name="flags"/> \
<arg type="u" direction="out" name="response"/> \
<arg type="a{sv}" direction="out" name="response_details"/> \
</method> \
<method name="AskQuestion"> \
<arg type="s" direction="in" name="object_id"/> \
<arg type="s" direction="in" name="message"/> \
<arg type="s" direction="in" name="icon_name"/> \
<arg type="as" direction="in" name="choices"/> \
<arg type="u" direction="out" name="response"/> \
<arg type="a{sv}" direction="out" name="response_details"/> \
</method> \
<method name="ShowProcesses"> \
<arg type="s" direction="in" name="object_id"/> \
<arg type="s" direction="in" name="message"/> \
<arg type="s" direction="in" name="icon_name"/> \
<arg type="ai" direction="in" name="application_pids"/> \
<arg type="as" direction="in" name="choices"/> \
<arg type="u" direction="out" name="response"/> \
<arg type="a{sv}" direction="out" name="response_details"/> \
</method> \
<method name="Close"/> \
</interface> \
</node>';
const ShellMountOperationType = {
NONE: 0,

View File

@ -43,9 +43,7 @@ const ATIndicator = new Lang.Class({
this._hbox = new St.BoxLayout({ style_class: 'panel-status-menu-box' });
this._hbox.add_child(new St.Icon({ style_class: 'system-status-icon',
icon_name: 'preferences-desktop-accessibility-symbolic' }));
this._hbox.add_child(new St.Label({ text: '\u25BE',
y_expand: true,
y_align: Clutter.ActorAlign.CENTER }));
this._hbox.add_child(PopupMenu.unicodeArrow(St.Side.BOTTOM));
this.actor.add_child(this._hbox);

View File

@ -9,7 +9,6 @@ const St = imports.gi.St;
const Main = imports.ui.main;
const MessageTray = imports.ui.messageTray;
const NotificationDaemon = imports.ui.notificationDaemon;
const PanelMenu = imports.ui.panelMenu;
const PopupMenu = imports.ui.popupMenu;
@ -31,6 +30,7 @@ const Indicator = new Lang.Class({
this._applet.killswitch_state = GnomeBluetooth.KillswitchState.SOFT_BLOCKED;
}));
this._item.menu.addSettingsAction(_("Bluetooth Settings"), 'gnome-bluetooth-panel.desktop');
this.menu.addMenuItem(this._item);
this._applet = new GnomeBluetoothApplet.Applet();
this._applet.connect('devices-changed', Lang.bind(this, this._sync));
@ -54,13 +54,13 @@ const Indicator = new Lang.Class({
this._item.actor.visible = on;
if (on)
this._item.status.text = ngettext("%d Connected Device", "%d Connected Devices").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 NotificationDaemon.NotificationApplicationPolicy('gnome-bluetooth-panel');
this._source.policy = new MessageTray.NotificationApplicationPolicy('gnome-bluetooth-panel');
Main.messageTray.add(this._source);
}
},
@ -105,8 +105,8 @@ const AuthNotification = new Lang.Class({
this._devicePath = device_path;
this.addBody(_("Device %s wants to pair with this computer").format(long_name));
this.addButton('allow', _("Allow"));
this.addButton('deny', _("Deny"));
this.addAction('allow', _("Allow"));
this.addAction('deny', _("Deny"));
this.connect('action-invoked', Lang.bind(this, function(self, action) {
if (action == 'allow')
@ -133,9 +133,9 @@ const AuthServiceNotification = new Lang.Class({
this._devicePath = device_path;
this.addBody(_("Device %s wants access to the service '%s'").format(long_name, uuid));
this.addButton('always-grant', _("Always grant access"));
this.addButton('grant', _("Grant this time only"));
this.addButton('reject', _("Reject"));
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) {
@ -172,8 +172,8 @@ const ConfirmNotification = new Lang.Class({
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.addButton('matches', _("Matches"));
this.addButton('does-not-match', _("Does not match"));
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')
@ -207,47 +207,48 @@ const PinNotification = new Lang.Class({
let key = event.get_key_symbol();
if (key == Clutter.KEY_Return) {
if (this._canActivateOkButton())
this.emit('action-invoked', 'ok');
this._ok();
return true;
} else if (key == Clutter.KEY_Escape) {
this.emit('action-invoked', 'cancel');
this._cancel();
return true;
}
return false;
}));
this.addActor(this._entry);
this.addButton('ok', _("OK"));
this.addButton('cancel', _("Cancel"));
let okButton = this.addAction(_("OK"), Lang.bind(this, this._ok));
this.addAction(_("Cancel"), Lang.bind(this, this._cancel));
this.setButtonSensitive('ok', this._canActivateOkButton());
this._entry.clutter_text.connect('text-changed', Lang.bind(this,
function() {
this.setButtonSensitive('ok', this._canActivateOkButton());
}));
this.connect('action-invoked', Lang.bind(this, function(self, action) {
if (action == 'ok') {
if (this._numeric) {
let num = parseInt(this._entry.text);
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);
} else {
if (this._numeric)
this._applet.agent_reply_passkey(this._devicePath, -1);
else
this._applet.agent_reply_pincode(this._devicePath, null);
}
this.destroy();
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)

View File

@ -11,9 +11,11 @@ const Slider = imports.ui.slider;
const BUS_NAME = 'org.gnome.SettingsDaemon.Power';
const OBJECT_PATH = '/org/gnome/SettingsDaemon/Power';
const BrightnessInterface = <interface name="org.gnome.SettingsDaemon.Power.Screen">
<property name='Brightness' type='i' access='readwrite'/>
</interface>;
const BrightnessInterface = '<node> \
<interface name="org.gnome.SettingsDaemon.Power.Screen"> \
<property name="Brightness" type="i" access="readwrite"/> \
</interface> \
</node>';
const BrightnessProxy = Gio.DBusProxy.makeProxyWrapper(BrightnessInterface);

View File

@ -41,11 +41,13 @@ const MAX_INPUT_SOURCE_ACTIVATION_TIME = 4000; // ms
const BUS_NAME = 'org.gnome.SettingsDaemon.Keyboard';
const OBJECT_PATH = '/org/gnome/SettingsDaemon/Keyboard';
const KeyboardManagerInterface = <interface name="org.gnome.SettingsDaemon.Keyboard">
<method name="SetInputSource">
<arg type="u" direction="in" />
</method>
</interface>;
const KeyboardManagerInterface = '<node> \
<interface name="org.gnome.SettingsDaemon.Keyboard"> \
<method name="SetInputSource"> \
<arg type="u" direction="in" /> \
</method> \
</interface> \
</node>';
const KeyboardManagerProxy = Gio.DBusProxy.makeProxyWrapper(KeyboardManagerInterface);
@ -339,9 +341,7 @@ const InputSourceIndicator = new Lang.Class({
this._hbox = new St.BoxLayout({ style_class: 'panel-status-menu-box' });
this._hbox.add_child(this._container);
this._hbox.add_child(new St.Label({ text: '\u25BE',
y_expand: true,
y_align: Clutter.ActorAlign.CENTER }));
this._hbox.add_child(PopupMenu.unicodeArrow(St.Side.BOTTOM));
this.actor.add_child(this._hbox);
this.actor.add_style_class_name('panel-status-button');

View File

@ -16,7 +16,6 @@ const Main = imports.ui.main;
const PanelMenu = imports.ui.panelMenu;
const PopupMenu = imports.ui.popupMenu;
const MessageTray = imports.ui.messageTray;
const NotificationDaemon = imports.ui.notificationDaemon;
const ModalDialog = imports.ui.modalDialog;
const ModemManager = imports.misc.modemManager;
const Util = imports.misc.util;
@ -73,6 +72,27 @@ function ssidToLabel(ssid) {
return label;
}
function ensureActiveConnectionProps(active, settings) {
if (!active._connection) {
active._connection = settings.get_connection_by_path(active.connection);
// This list is guaranteed to have only one device in it.
let device = active.get_devices()[0]._delegate;
active._primaryDevice = device;
}
}
function createSettingsAction(label, device) {
let item = new PopupMenu.PopupMenuItem(label);
item.connect('activate', function() {
Util.spawnApp(['gnome-control-center', 'network', 'show-device',
device.get_path()]);
});
return item;
}
const NMConnectionItem = new Lang.Class({
Name: 'NMConnectionItem',
@ -170,8 +190,7 @@ const NMConnectionSection = new Lang.Class({
},
destroy: function() {
this.statusItem.destroy();
this.section.destroy();
this.item.destroy();
},
_sync: function() {
@ -268,12 +287,12 @@ const NMConnectionDevice = new Lang.Class({
Extends: NMConnectionSection,
Abstract: true,
_init: function(client, device) {
_init: function(client, device, settings) {
this.parent(client);
this._device = device;
this._settings = settings;
this._autoConnectItem = this.item.menu.addAction(_("Connect"), Lang.bind(this, this._autoConnect));
this.item.menu.addSettingsAction(_("Network Settings"), 'gnome-network-panel.desktop');
this._stateChangedId = this._device.connect('state-changed', Lang.bind(this, this._deviceStateChanged));
this._activeConnectionChangedId = this._device.connect('notify::active-connection', Lang.bind(this, this._activeConnectionChanged));
@ -301,6 +320,7 @@ const NMConnectionDevice = new Lang.Class({
this._activeConnection = this._device.active_connection;
if (this._activeConnection) {
ensureActiveConnectionProps(this._activeConnection, this._settings);
let item = this._connectionItems.get(this._activeConnection._connection.get_uuid());
item.setActiveConnection(this._activeConnection);
}
@ -356,8 +376,9 @@ const NMConnectionDevice = new Lang.Class({
switch(this._device.state) {
case NetworkManager.DeviceState.DISCONNECTED:
return _("Off");
case NetworkManager.DeviceState.ACTIVATED:
return '';
return this.parent();
case NetworkManager.DeviceState.UNMANAGED:
/* Translators: this is for network devices that are physically present but are not
under NetworkManager's control (and thus cannot be used in the menu) */
@ -399,8 +420,11 @@ const NMDeviceModem = new Lang.Class({
Extends: NMConnectionDevice,
category: NMConnectionCategory.WWAN,
_init: function(client, device) {
this.parent(client, device);
_init: function(client, device, settings) {
this.parent(client, device, settings);
this.item.menu.addMenuItem(createSettingsAction(_("Mobile Broadband Settings"), device));
this._mobileDevice = null;
let capabilities = device.current_capabilities;
@ -414,16 +438,7 @@ const NMDeviceModem = new Lang.Class({
this._mobileDevice = new ModemManager.ModemGsm(device.udi);
if (this._mobileDevice) {
this._operatorNameId = this._mobileDevice.connect('notify::operator-name', Lang.bind(this, function() {
if (this._operatorItem) {
let name = this._mobileDevice.operator_name;
if (name) {
this._operatorItem.label.text = name;
this._operatorItem.actor.show();
} else
this._operatorItem.actor.hide();
}
}));
this._operatorNameId = this._mobileDevice.connect('notify::operator-name', Lang.bind(this, this._sync));
this._signalQualityId = this._mobileDevice.connect('notify::signal-quality', Lang.bind(this, function() {
this.emit('icon-changed');
}));
@ -448,6 +463,20 @@ const NMDeviceModem = new Lang.Class({
this.parent();
},
_getStatus: function() {
if (!this._client.wwan_hardware_enabled)
return _("Hardware Disabled");
else if (!this._client.wwan_enabled)
/* Translators: this is for a network device that cannot be activated
because it's disabled by rfkill (airplane mode) */
return _("Disabled");
else if (this._device.state == NetworkManager.DeviceState.ACTIVATED &&
this._mobileDevice && this._mobileDevice.operator_name)
return this._mobileDevice.operator_name;
else
return this.parent();
},
_getMenuIcon: function() {
if (this._device.active_connection)
return this.getIndicatorIcon();
@ -477,6 +506,12 @@ const NMDeviceBluetooth = new Lang.Class({
Extends: NMConnectionDevice,
category: NMConnectionCategory.WWAN,
_init: function(client, device, settings) {
this.parent(client, device, settings);
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
@ -514,31 +549,30 @@ const NMWirelessDialogItem = new Lang.Class({
this._network = network;
this._ap = network.accessPoints[0];
this.actor = new St.Button({ style_class: 'nm-dialog-item',
can_focus: true,
x_fill: true });
this.actor = new St.BoxLayout({ style_class: 'nm-dialog-item',
can_focus: true,
reactive: true });
this.actor.connect('key-focus-in', Lang.bind(this, function() {
this.emit('selected');
}));
this.actor.connect('clicked', Lang.bind(this, function() {
let action = new Clutter.ClickAction();
action.connect('clicked', Lang.bind(this, function() {
this.actor.grab_key_focus();
}));
this._content = new St.BoxLayout({ style_class: 'nm-dialog-item-box' });
this.actor.set_child(this._content);
this.actor.add_action(action);
let title = ssidToLabel(this._ap.get_ssid());
this._label = new St.Label({ text: title });
this.actor.label_actor = this._label;
this._content.add(this._label, { x_align: St.Align.START });
this.actor.add(this._label, { x_align: St.Align.START });
this._selectedIcon = new St.Icon({ style_class: 'nm-dialog-icon',
icon_name: 'object-select-symbolic' });
this._content.add(this._selectedIcon);
this.actor.add(this._selectedIcon);
this._icons = new St.BoxLayout({ style_class: 'nm-dialog-icons' });
this._content.add(this._icons, { expand: true, x_fill: false, x_align: St.Align.END });
this.actor.add(this._icons, { expand: true, x_fill: false, x_align: St.Align.END });
this._secureIcon = new St.Icon({ style_class: 'nm-dialog-icon' });
if (this._ap._secType != NMAccessPointSecurity.NONE)
@ -547,18 +581,24 @@ const NMWirelessDialogItem = new Lang.Class({
this._signalIcon = new St.Icon({ style_class: 'nm-dialog-icon' });
this._icons.add_actor(this._signalIcon);
this._sync();
},
_sync: function() {
this._signalIcon.icon_name = this._getSignalIcon();
},
updateBestAP: function(ap) {
this._ap = ap;
this._signalIcon.icon_name = this._getIcon();
this._sync();
},
setActive: function(isActive) {
this._selectedIcon.opacity = isActive ? 255 : 0;
},
_getIcon: function() {
_getSignalIcon: function() {
if (this._ap.mode == NM80211Mode.ADHOC)
return 'network-workgroup-symbolic';
else
@ -915,13 +955,13 @@ const NMWirelessDialog = new Lang.Class({
_selectNetwork: function(network) {
if (this._selectedNetwork)
this._selectedNetwork.item.actor.checked = false;
this._selectedNetwork.item.actor.remove_style_pseudo_class('selected');
this._selectedNetwork = network;
this._updateSensitivity();
if (this._selectedNetwork)
this._selectedNetwork.item.actor.checked = true;
this._selectedNetwork.item.actor.add_style_pseudo_class('selected');
},
_createNetworkItem: function(network) {
@ -952,9 +992,10 @@ const NMDeviceWireless = new Lang.Class({
this._toggleItem.connect('activate', Lang.bind(this, this._toggleWifi));
this.item.menu.addMenuItem(this._toggleItem);
this.item.menu.addSettingsAction(_("Network Settings"), 'gnome-network-panel.desktop');
this.item.menu.addMenuItem(createSettingsAction(_("Wi-Fi Settings"), device));
this._wirelessEnabledChangedId = this._device.connect('notify::wireless-enabled', Lang.bind(this, this._sync));
this._wirelessEnabledChangedId = this._client.connect('notify::wireless-enabled', Lang.bind(this, this._sync));
this._wirelessHwEnabledChangedId = this._client.connect('notify::wireless-hardware-enabled', Lang.bind(this, this._sync));
this._activeApChangedId = this._device.connect('notify::active-access-point', Lang.bind(this, this._activeApChanged));
this._stateChangedId = this._device.connect('state-changed', Lang.bind(this, this._deviceStateChanged));
@ -974,6 +1015,14 @@ const NMDeviceWireless = new Lang.Class({
this._activeAccessPoint.disconnect(this._strengthChangedId);
this._strengthChangedId = 0;
}
if (this._wirelessEnabledChangedId) {
this._client.disconnect(this._wirelessEnabledChangedId);
this._wirelessEnabledChangedId = 0;
}
if (this._wirelessHwEnabledChangedId) {
this._client.disconnect(this._wirelessHwEnabledChangedId);
this._wirelessHwEnabledChangedId = 0;
}
this.item.destroy();
},
@ -1032,6 +1081,7 @@ const NMDeviceWireless = new Lang.Class({
_sync: function() {
this._toggleItem.label.text = this._client.wireless_enabled ? _("Turn Off") : _("Turn On");
this._toggleItem.actor.visible = this._client.wireless_hardware_enabled;
this.item.status.text = this._getStatus();
this.item.icon.icon_name = this._getMenuIcon();
@ -1045,10 +1095,17 @@ const NMDeviceWireless = new Lang.Class({
_getStatus: function() {
let ap = this._device.active_access_point;
if (!ap)
return _("Off"); // XXX -- interpret actual status
return ssidToLabel(ap.get_ssid());
if (ap)
return ssidToLabel(ap.get_ssid());
else if (!this._client.wireless_hardware_enabled)
return _("Hardware Disabled");
else if (!this._client.wireless_enabled)
return _("Off");
else if (this._device.state == NetworkManager.DeviceState.DISCONNECTED)
return _("Not Connected");
else
return '';
},
_getMenuIcon: function() {
@ -1059,7 +1116,8 @@ const NMDeviceWireless = new Lang.Class({
},
getIndicatorIcon: function() {
if (this._device.active_connection.state == NetworkManager.ActiveConnectionState.ACTIVATING)
if (this._device.state >= NetworkManager.DeviceState.PREPARE &&
this._device.state < NetworkManager.DeviceState.ACTIVATED)
return 'network-wireless-acquiring-symbolic';
let ap = this._device.active_access_point;
@ -1117,6 +1175,7 @@ const NMVPNConnectionItem = new Lang.Class({
this.emit('activation-failed', reason);
}
this.emit('icon-changed');
this.parent();
},
@ -1287,6 +1346,7 @@ const NMApplet = new Lang.Class({
this._client.connect('notify::networking-enabled', Lang.bind(this, this._syncNMState));
this._client.connect('notify::state', Lang.bind(this, this._syncNMState));
this._client.connect('notify::primary-connection', Lang.bind(this, this._syncMainConnection));
this._client.connect('notify::activating-connection', Lang.bind(this, this._syncMainConnection));
this._client.connect('notify::active-connections', Lang.bind(this, this._syncVPNConnections));
this._client.connect('device-added', Lang.bind(this, this._deviceAdded));
this._client.connect('device-removed', Lang.bind(this, this._deviceRemoved));
@ -1305,7 +1365,7 @@ const NMApplet = new Lang.Class({
if (!this._source) {
this._source = new MessageTray.Source(_("Network Manager"),
'network-transmit-receive');
this._source.policy = new NotificationDaemon.NotificationApplicationPolicy('gnome-network-panel');
this._source.policy = new MessageTray.NotificationApplicationPolicy('gnome-network-panel');
this._source.connect('destroy', Lang.bind(this, function() {
this._source = null;
@ -1417,28 +1477,18 @@ const NMApplet = new Lang.Class({
devices.splice(pos, 1);
},
_ensureActiveConnectionProps: function(a) {
if (!a._connection) {
a._connection = this._settings.get_connection_by_path(a.connection);
// This list is guaranteed to have only one device in it.
let device = a.get_devices()[0]._delegate;
a._primaryDevice = device;
}
},
_getMainConnection: function() {
let connection;
connection = this._client.get_primary_connection();
if (connection) {
this._ensureActiveConnectionProps(connection);
ensureActiveConnectionProps(connection, this._settings);
return connection;
}
connection = this._client.get_activating_connection();
if (connection) {
this._ensureActiveConnectionProps(connection);
ensureActiveConnectionProps(connection, this._settings);
return connection;
}
@ -1474,7 +1524,7 @@ const NMApplet = new Lang.Class({
return (a instanceof NMClient.VPNConnection);
});
vpnConnections.forEach(Lang.bind(this, function(a) {
this._ensureActiveConnectionProps(a);
ensureActiveConnectionProps(a, this._settings);
}));
this._vpnSection.setActiveConnections(vpnConnections);
@ -1577,6 +1627,7 @@ const NMApplet = new Lang.Class({
_updateIcon: function() {
if (!this._client.networking_enabled || !this._mainConnection) {
this._primaryIndicator.icon_name = 'network-offline-symbolic';
this._primaryIndicator.visible = true;
} else {
let dev = this._mainConnection._primaryDevice;
this._primaryIndicator.visible = (dev != null);

View File

@ -8,20 +8,22 @@ const Main = imports.ui.main;
const PanelMenu = imports.ui.panelMenu;
const PopupMenu = imports.ui.popupMenu;
const BUS_NAME = 'org.gnome.SettingsDaemon.Power';
const OBJECT_PATH = '/org/gnome/SettingsDaemon/Power';
const BUS_NAME = 'org.freedesktop.UPower';
const OBJECT_PATH = '/org/freedesktop/UPower/devices/DisplayDevice';
const PowerManagerInterface = <interface name="org.gnome.SettingsDaemon.Power">
<method name="GetDevices">
<arg type="a(susdut)" direction="out" />
</method>
<method name="GetPrimaryDevice">
<arg type="(susdut)" direction="out" />
</method>
<property name="Icon" type="s" access="read" />
</interface>;
const DisplayDeviceInterface = '<node> \
<interface name="org.freedesktop.UPower.Device"> \
<property name="Type" type="u" access="read"/> \
<property name="State" type="u" access="read"/> \
<property name="Percentage" type="d" access="read"/> \
<property name="TimeToEmpty" type="x" access="read"/> \
<property name="TimeToFull" type="x" access="read"/> \
<property name="IsPresent" type="b" access="read"/> \
<property name="IconName" type="s" access="read"/> \
</interface> \
</node>';
const PowerManagerProxy = Gio.DBusProxy.makeProxyWrapper(PowerManagerInterface);
const PowerManagerProxy = Gio.DBusProxy.makeProxyWrapper(DisplayDeviceInterface);
const Indicator = new Lang.Class({
Name: 'PowerIndicator',
@ -32,7 +34,7 @@ const Indicator = new Lang.Class({
this._indicator = this._addIndicator();
this._proxy = new PowerManagerProxy(Gio.DBus.session, BUS_NAME, OBJECT_PATH,
this._proxy = new PowerManagerProxy(Gio.DBus.system, BUS_NAME, OBJECT_PATH,
Lang.bind(this, function(proxy, error) {
if (error) {
log(error.message);
@ -43,7 +45,7 @@ const Indicator = new Lang.Class({
this._sync();
}));
this._item = new PopupMenu.PopupSubMenuMenuItem(_("Battery"), true);
this._item = new PopupMenu.PopupSubMenuMenuItem("", true);
this._item.menu.addSettingsAction(_("Power Settings"), 'gnome-power-panel.desktop');
this.menu.addMenuItem(this._item);
@ -56,11 +58,18 @@ const Indicator = new Lang.Class({
this.menu.setSensitive(sensitive);
},
_statusForDevice: function(device) {
let [device_id, device_type, icon, percentage, state, seconds] = device;
_getStatus: function() {
let seconds = 0;
if (state == UPower.DeviceState.FULLY_CHARGED)
if (this._proxy.State == UPower.DeviceState.FULLY_CHARGED)
return _("Fully Charged");
else if (this._proxy.State == UPower.DeviceState.CHARGING)
seconds = this._proxy.TimeToFull;
else if (this._proxy.State == UPower.DeviceState.DISCHARGING)
seconds = this._proxy.TimeToEmpty;
// state is one of PENDING_CHARGING, PENDING_DISCHARGING
else
return _("Estimating…");
let time = Math.round(seconds / 60);
if (time == 0) {
@ -72,52 +81,43 @@ const Indicator = new Lang.Class({
let minutes = time % 60;
let hours = Math.floor(time / 60);
if (state == UPower.DeviceState.DISCHARGING) {
if (this._proxy.State == UPower.DeviceState.DISCHARGING) {
// Translators: this is <hours>:<minutes> Remaining (<percentage>)
return _("%d\u2236%02d Remaining (%d%%)").format(hours, minutes, percentage);
return _("%d\u2236%02d Remaining (%d%%)").format(hours, minutes, this._proxy.Percentage);
}
if (state == UPower.DeviceState.CHARGING) {
if (this._proxy.State == UPower.DeviceState.CHARGING) {
// Translators: this is <hours>:<minutes> Until Full (<percentage>)
return _("%d\u2236%02d Until Full (%d%%)").format(hours, minutes, percentage);
return _("%d\u2236%02d Until Full (%d%%)").format(hours, minutes, this._proxy.Percentage);
}
// state is one of PENDING_CHARGING, PENDING_DISCHARGING
return _("Estimating…");
},
_syncStatusLabel: function() {
this._proxy.GetPrimaryDeviceRemote(Lang.bind(this, function(result, error) {
if (error) {
this._item.actor.hide();
return;
}
let [device] = result;
let [device_id, device_type] = device;
if (device_type == UPower.DeviceKind.BATTERY) {
this._item.status.text = this._statusForDevice(device);
this._item.actor.show();
} else {
this._item.actor.hide();
}
}));
},
_syncIcon: function() {
let icon = this._proxy.Icon;
if (icon) {
let gicon = Gio.icon_new_for_string(icon);
this._indicator.gicon = gicon;
this._item.icon.gicon = gicon;
} else {
// If there's no battery, then we use the power icon.
this._indicator.icon_name = 'system-shutdown-symbolic';
}
return null;
},
_sync: function() {
this._syncIcon();
this._syncStatusLabel();
}
// Do we have batteries or a UPS?
let visible = this._proxy.IsPresent;
if (visible) {
this._item.actor.show();
} else {
// If there's no battery, then we use the power icon.
this._item.actor.hide();
this._indicator.icon_name = 'system-shutdown-symbolic';
return;
}
// The icons
let icon = this._proxy.IconName;
this._indicator.icon_name = icon;
this._item.icon.icon_name = icon;
// The status label
this._item.status.text = this._getStatus();
// The sub-menu heading
if (this._proxy.Type == UPower.DeviceKind.UPS)
this._item.label.text = _("UPS");
else
this._item.label.text = _("Battery");
},
});

View File

@ -9,9 +9,11 @@ const PopupMenu = imports.ui.popupMenu;
const BUS_NAME = 'org.gnome.SettingsDaemon.Rfkill';
const OBJECT_PATH = '/org/gnome/SettingsDaemon/Rfkill';
const RfkillManagerInterface = <interface name="org.gnome.SettingsDaemon.Rfkill">
<property name="AirplaneMode" type="b" access="readwrite" />
</interface>;
const RfkillManagerInterface = '<node> \
<interface name="org.gnome.SettingsDaemon.Rfkill"> \
<property name="AirplaneMode" type="b" access="readwrite" /> \
</interface> \
</node>';
const RfkillManagerProxy = Gio.DBusProxy.makeProxyWrapper(RfkillManagerInterface);

View File

@ -18,10 +18,12 @@ const PopupMenu = imports.ui.popupMenu;
const LOCKDOWN_SCHEMA = 'org.gnome.desktop.lockdown';
const SCREENSAVER_SCHEMA = 'org.gnome.desktop.screensaver';
const LOGIN_SCREEN_SCHEMA = 'org.gnome.login-screen';
const PRIVACY_SCHEMA = 'org.gnome.desktop.privacy'
const DISABLE_USER_SWITCH_KEY = 'disable-user-switching';
const DISABLE_LOCK_SCREEN_KEY = 'disable-lock-screen';
const DISABLE_LOG_OUT_KEY = 'disable-log-out';
const DISABLE_RESTART_KEY = 'disable-restart-buttons';
const ALWAYS_SHOW_LOG_OUT_KEY = 'always-show-log-out';
const AltSwitcher = new Lang.Class({
@ -91,6 +93,7 @@ const Indicator = new Lang.Class({
this.parent();
this._screenSaverSettings = new Gio.Settings({ schema: SCREENSAVER_SCHEMA });
this._loginScreenSettings = new Gio.Settings({ schema: LOGIN_SCREEN_SCHEMA });
this._lockdownSettings = new Gio.Settings({ schema: LOCKDOWN_SCHEMA });
this._privacySettings = new Gio.Settings({ schema: PRIVACY_SCHEMA });
this._orientationSettings = new Gio.Settings({ schema: 'org.gnome.settings-daemon.peripherals.touchscreen' });
@ -261,7 +264,10 @@ const Indicator = new Lang.Class({
},
_updatePowerOff: function() {
this._powerOffAction.visible = this._haveShutdown && !Main.sessionMode.isLocked;
let disabled = Main.sessionMode.isLocked ||
(Main.sessionMode.isGreeter &&
this._loginScreenSettings.get_boolean(DISABLE_RESTART_KEY));
this._powerOffAction.visible = this._haveShutdown && !disabled;
this._updateActionsVisibility();
},
@ -273,7 +279,10 @@ const Indicator = new Lang.Class({
},
_updateSuspend: function() {
this._suspendAction.visible = this._haveSuspend && !Main.sessionMode.isLocked;
let disabled = Main.sessionMode.isLocked ||
(Main.sessionMode.isGreeter &&
this._loginScreenSettings.get_boolean(DISABLE_RESTART_KEY));
this._suspendAction.visible = this._haveShutdown && !disabled;
this._updateActionsVisibility();
},
@ -372,7 +381,11 @@ const Indicator = new Lang.Class({
Main.overview.hide();
if (Main.screenShield)
Main.screenShield.lock(false);
Gdm.goto_login_session_sync(null);
Clutter.threads_add_repaint_func_full(Clutter.RepaintFlags.POST_PAINT, function() {
Gdm.goto_login_session_sync(null);
return false;
});
},
_onQuitSessionActivate: function() {

View File

@ -11,29 +11,8 @@ const Signals = imports.signals;
const Tweener = imports.tweener.tweener;
// This is a wrapper around imports.tweener.tweener that adds a bit of
// Clutter integration and some additional callbacks:
//
// 1. If the tweening target is a Clutter.Actor, then the tweenings
// will automatically be removed if the actor is destroyed
//
// 2. If target._delegate.onAnimationStart() exists, it will be
// called when the target starts being animated.
//
// 3. If target._delegate.onAnimationComplete() exists, it will be
// called once the target is no longer being animated.
//
// The onAnimationStart() and onAnimationComplete() callbacks differ
// from the tweener onStart and onComplete parameters, in that (1)
// they track whether or not the target has *any* tweens attached to
// it, as opposed to be called for *each* tween, and (2)
// onAnimationComplete() is always called when the object stops being
// animated, regardless of whether it stopped normally or abnormally.
//
// onAnimationComplete() is called at idle time, which means that if a
// tween completes and then another is added before returning to the
// main loop, the complete callback will not be called (until the new
// tween finishes).
// Clutter integration. If the tweening target is a Clutter.Actor, then
// the tweenings will automatically be removed if the actor is destroyed.
// ActionScript Tweener methods that imports.tweener.tweener doesn't
// currently implement: getTweens, getVersion, registerTransition,
@ -77,7 +56,6 @@ function _wrapTweening(target, tweeningParameters) {
if (!Gtk.Settings.get_default().gtk_enable_animations)
tweeningParameters['time'] = 0.000001;
_addHandler(target, tweeningParameters, 'onStart', _tweenStarted);
_addHandler(target, tweeningParameters, 'onComplete', _tweenCompleted);
}
@ -85,7 +63,7 @@ function _getTweenState(target) {
// If we were paranoid, we could keep a plist mapping targets to
// states... but we're not that paranoid.
if (!target.__ShellTweenerState)
_resetTweenState(target);
target.__ShellTweenerState = {};
return target.__ShellTweenerState;
}
@ -95,8 +73,6 @@ function _resetTweenState(target) {
if (state) {
if (state.destroyedId)
state.actor.disconnect(state.destroyedId);
if (state.idleCompletedId)
Mainloop.source_remove(state.idleCompletedId);
}
target.__ShellTweenerState = {};
@ -122,32 +98,9 @@ function _actorDestroyed(target) {
Tweener.removeTweens(target);
}
function _tweenStarted(target) {
let state = _getTweenState(target);
let delegate = target._delegate;
if (!state.running && delegate && delegate.onAnimationStart)
delegate.onAnimationStart();
state.running = true;
}
function _tweenCompleted(target) {
let state = _getTweenState(target);
if (!state.idleCompletedId)
state.idleCompletedId = Mainloop.idle_add(Lang.bind(null, _idleCompleted, target));
}
function _idleCompleted(target) {
let state = _getTweenState(target);
let delegate = target._delegate;
if (!isTweening(target)) {
if (!isTweening(target))
_resetTweenState(target);
if (delegate && delegate.onAnimationComplete)
delegate.onAnimationComplete();
}
return false;
}
function getTweenCount(scope) {

View File

@ -1,7 +1,8 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
//
// A widget showing the user avatar and name
const Clutter = imports.gi.Clutter;
const AccountsService = imports.gi.AccountsService;
const GLib = imports.gi.GLib;
const Gio = imports.gi.Gio;
@ -56,6 +57,83 @@ const Avatar = new Lang.Class({
}
});
const UserWidgetLabel = new Lang.Class({
Name: 'UserWidgetLabel',
Extends: St.Widget,
_init: function(user) {
this.parent({ layout_manager: new Clutter.BinLayout() });
this._user = user;
this._realNameLabel = new St.Label({ style_class: 'user-widget-label',
y_align: Clutter.ActorAlign.CENTER });
this.add_child(this._realNameLabel);
this._userNameLabel = new St.Label({ style_class: 'user-widget-label',
y_align: Clutter.ActorAlign.CENTER });
this.add_child(this._userNameLabel);
this._currentLabel = null;
this._userLoadedId = this._user.connect('notify::is-loaded', Lang.bind(this, this._updateUser));
this._userChangedId = this._user.connect('changed', Lang.bind(this, this._updateUser));
this._updateUser();
},
vfunc_destroy: function() {
if (this._userLoadedId != 0) {
this._user.disconnect(this._userLoadedId);
this._userLoadedId = 0;
}
if (this._userChangedId != 0) {
this._user.disconnect(this._userChangedId);
this._userChangedId = 0;
}
},
vfunc_allocate: function(box, flags) {
this.set_allocation(box, flags);
let availWidth = box.x2 - box.x1;
let availHeight = box.y2 - box.y1;
let [minRealNameWidth, minRealNameHeight,
natRealNameWidth, natRealNameHeight] = this._realNameLabel.get_preferred_size();
let [minUserNameWidth, minUserNameHeight,
natUserNameWidth, natUserNameHeight] = this._userNameLabel.get_preferred_size();
if (natRealNameWidth <= availWidth)
this._currentLabel = this._realNameLabel;
else
this._currentLabel = this._userNameLabel;
let childBox = new Clutter.ActorBox();
childBox.x1 = 0;
childBox.y1 = 0;
childBox.x2 = availWidth;
childBox.y2 = availHeight;
this._currentLabel.allocate(childBox, flags);
},
vfunc_paint: function() {
this._currentLabel.paint();
},
_updateUser: function() {
if (this._user.is_loaded) {
this._realNameLabel.text = this._user.get_real_name();
this._userNameLabel.text = this._user.get_user_name();
} else {
this._realNameLabel.text = '';
this._userNameLabel.text = '';
}
},
});
const UserWidget = new Lang.Class({
Name: 'UserWidget',
@ -67,22 +145,14 @@ const UserWidget = new Lang.Class({
this.actor.connect('destroy', Lang.bind(this, this._onDestroy));
this._avatar = new Avatar(user);
this.actor.add(this._avatar.actor,
{ x_fill: true, y_fill: true });
this.actor.add_child(this._avatar.actor);
this._label = new St.Label({ style_class: 'user-widget-label' });
this.actor.add(this._label,
{ expand: true,
x_fill: true,
y_fill: false,
y_align: St.Align.MIDDLE });
this._label = new UserWidgetLabel(user);
this.actor.add_child(this._label);
this._userLoadedId = this._user.connect('notify::is-loaded',
Lang.bind(this, this._updateUser));
this._userChangedId = this._user.connect('changed',
Lang.bind(this, this._updateUser));
if (this._user.is_loaded)
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._updateUser();
},
_onDestroy: function() {
@ -98,11 +168,6 @@ const UserWidget = new Lang.Class({
},
_updateUser: function() {
if (this._user.is_loaded)
this._label.text = this._user.get_real_name();
else
this._label.text = '';
this._avatar.update();
}
});

View File

@ -14,12 +14,9 @@ const AppDisplay = imports.ui.appDisplay;
const Main = imports.ui.main;
const OverviewControls = imports.ui.overviewControls;
const Params = imports.misc.params;
const RemoteSearch = imports.ui.remoteSearch;
const Search = imports.ui.search;
const SearchDisplay = imports.ui.searchDisplay;
const ShellEntry = imports.ui.shellEntry;
const Tweener = imports.ui.tweener;
const Wanda = imports.ui.wanda;
const WorkspacesView = imports.ui.workspacesView;
const SHELL_KEYBINDINGS_SCHEMA = 'org.gnome.shell.keybindings';
@ -66,8 +63,6 @@ const ViewSelector = new Lang.Class({
this._searchActive = false;
this._searchTimeoutId = 0;
this._searchSystem = new Search.SearchSystem();
this._entry = searchEntry;
ShellEntry.addContextMenu(this._entry);
@ -103,24 +98,11 @@ const ViewSelector = new Lang.Class({
this._appsPage = this._addPage(this.appDisplay.actor,
_("Applications"), 'view-grid-symbolic');
this._searchResults = new SearchDisplay.SearchResults(this._searchSystem);
this._searchResults = new Search.SearchResults();
this._searchPage = this._addPage(this._searchResults.actor,
_("Search"), 'edit-find-symbolic',
{ a11yFocus: this._entry });
this._searchSettings = new Gio.Settings({ schema: Search.SEARCH_PROVIDERS_SCHEMA });
this._searchSettings.connect('changed::disabled', Lang.bind(this, this._reloadRemoteProviders));
this._searchSettings.connect('changed::disable-external', Lang.bind(this, this._reloadRemoteProviders));
this._searchSettings.connect('changed::sort-order', Lang.bind(this, this._reloadRemoteProviders));
// Default search providers
// Wanda comes obviously first
this.addSearchProvider(new Wanda.WandaSearchProvider());
this.addSearchProvider(new AppDisplay.AppSearchProvider());
// Load remote search providers provided by applications
RemoteSearch.loadRemoteSearchProviders(Lang.bind(this, this.addSearchProvider));
// Since the entry isn't inside the results container we install this
// dummy widget as the last results container child so that we can
// include the entry in the keynav tab path
@ -486,45 +468,10 @@ const ViewSelector = new Lang.Class({
let terms = getTermsForSearchString(this._entry.get_text());
this._searchSystem.updateSearchResults(terms);
this._searchResults.setTerms(terms);
this._showPage(this._searchPage);
},
_shouldUseSearchProvider: function(provider) {
// the disable-external GSetting only affects remote providers
if (!provider.isRemoteProvider)
return true;
if (this._searchSettings.get_boolean('disable-external'))
return false;
let appId = provider.appInfo.get_id();
let disable = this._searchSettings.get_strv('disabled');
return disable.indexOf(appId) == -1;
},
_reloadRemoteProviders: function() {
// removeSearchProvider() modifies the provider list we iterate on,
// so make a copy first
let remoteProviders = this._searchSystem.getRemoteProviders().slice(0);
remoteProviders.forEach(Lang.bind(this, this.removeSearchProvider));
RemoteSearch.loadRemoteSearchProviders(Lang.bind(this, this.addSearchProvider));
},
addSearchProvider: function(provider) {
if (!this._shouldUseSearchProvider(provider))
return;
this._searchSystem.registerProvider(provider);
this._searchResults.createProviderDisplay(provider);
},
removeSearchProvider: function(provider) {
this._searchSystem.unregisterProvider(provider);
this._searchResults.destroyProviderDisplay(provider);
},
getActivePage: function() {
if (this._activePage == this._workspacesPage)
return ViewPage.WINDOWS;

View File

@ -1,156 +0,0 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
const GdkPixbuf = imports.gi.GdkPixbuf;
const GLib = imports.gi.GLib;
const Gio = imports.gi.Gio;
const Lang = imports.lang;
const St = imports.gi.St;
const IconGrid = imports.ui.iconGrid;
const Layout = imports.ui.layout;
const Main = imports.ui.main;
const Panel = imports.ui.panel;
const FISH_NAME = 'wanda';
const FISH_FILENAME = 'wanda.png';
const FISH_SPEED = 300;
const FISH_COMMAND = 'fortune';
// The size of an individual frame in the animation
const FISH_HEIGHT = 22;
const FISH_WIDTH = 36;
const FISH_GROUP = 'Fish Animation';
const MAGIC_FISH_KEY = 'free the fish';
const WandaIcon = new Lang.Class({
Name: 'WandaIcon',
Extends: IconGrid.BaseIcon,
_init : function(fish, label, params) {
this.parent(label, params);
this._fish = fish;
this._imageFile = GLib.build_filenamev([global.datadir, fish + '.png']);
this._imgHeight = FISH_HEIGHT;
this._imgWidth = FISH_WIDTH;
},
createIcon: function(iconSize) {
this._animations = new Panel.Animation(this._imageFile, this._imgWidth, this._imgHeight, FISH_SPEED);
this._animations.play();
return this._animations.actor;
},
_createIconTexture: function(size) {
if (size == this.iconSize)
return;
this.parent(size);
}
});
const WandaIconBin = new Lang.Class({
Name: 'WandaIconBin',
_init: function(fish, label, params) {
this.actor = new St.Bin({ reactive: true,
track_hover: true });
this.icon = new WandaIcon(fish, label, params);
this.actor.child = this.icon.actor;
this.actor.label_actor = this.icon.label;
},
});
const FortuneDialog = new Lang.Class({
Name: 'FortuneDialog',
_init: function(name, command) {
let text;
try {
let [res, stdout, stderr, status] = GLib.spawn_command_line_sync(command);
text = String.fromCharCode.apply(null, stdout);
} catch(e) {
text = _("Sorry, no wisdom for you today:\n%s").format(e.message);
}
this._title = new St.Label({ style_class: 'prompt-dialog-headline',
text: _("%s the Oracle says").format(name) });
this._label = new St.Label({ style_class: 'prompt-dialog-description',
text: text });
this._label.clutter_text.line_wrap = true;
this._box = new St.BoxLayout({ vertical: true,
style_class: 'prompt-dialog' // this is just to force a reasonable width
});
this._box.add(this._title, { align: St.Align.MIDDLE });
this._box.add(this._label, { expand: true });
this._button = new St.Button({ button_mask: St.ButtonMask.ONE,
style_class: 'modal-dialog',
reactive: true });
this._button.connect('clicked', Lang.bind(this, this.destroy));
this._button.child = this._box;
this._bin = new St.Bin({ x_align: St.Align.MIDDLE,
y_align: St.Align.MIDDLE });
this._bin.add_constraint(new Layout.MonitorConstraint({ primary: true }));
this._bin.add_actor(this._button);
Main.layoutManager.addChrome(this._bin);
GLib.timeout_add_seconds(GLib.PRIORITY_DEFAULT, 10, Lang.bind(this, this.destroy));
},
destroy: function() {
this._bin.destroy();
}
});
function capitalize(str) {
return str[0].toUpperCase() + str.substring(1, str.length);
}
const WandaSearchProvider = new Lang.Class({
Name: 'WandaSearchProvider',
_init: function() {
this.id = 'wanda';
},
getResultMetas: function(fish, callback) {
callback([{ 'id': fish[0], // there may be many fish in the sea, but
// only one which speaks the truth!
'name': capitalize(fish[0]),
'createIcon': function(iconSize) {
return new St.Icon({ gicon: Gio.icon_new_for_string('face-smile'),
icon_size: iconSize });
}
}]);
},
getInitialResultSet: function(terms) {
if (terms.join(' ') == MAGIC_FISH_KEY) {
this.searchSystem.setResults(this, [ FISH_NAME ]);
} else {
this.searchSystem.setResults(this, []);
}
},
getSubsearchResultSet: function(previousResults, terms) {
this.getInitialResultSet(terms);
},
activateResult: function(fish) {
if (this._dialog)
this._dialog.destroy();
this._dialog = new FortuneDialog(capitalize(fish), FISH_COMMAND);
},
createResultObject: function (resultMeta, terms) {
return new WandaIconBin(resultMeta.id, resultMeta.name);
}
});

View File

@ -39,6 +39,9 @@ const WindowAttentionHandler = new Lang.Class({
let [title, banner] = this._getTitleAndBanner(app, window);
let notification = new MessageTray.Notification(source, title, banner);
notification.connect('clicked', function() {
source.open();
});
notification.setForFeedback(true);
source.notify(notification);
@ -79,7 +82,7 @@ const Source = new Lang.Class({
return this._app.create_icon_texture(size);
},
open : function(notification) {
open: function() {
Main.activateWindow(this._window);
this.destroy();
}

View File

@ -10,21 +10,14 @@ const St = imports.gi.St;
const Signals = imports.signals;
const DND = imports.ui.dnd;
const Lightbox = imports.ui.lightbox;
const Main = imports.ui.main;
const Overview = imports.ui.overview;
const Panel = imports.ui.panel;
const Tweener = imports.ui.tweener;
const FOCUS_ANIMATION_TIME = 0.15;
const WINDOW_DND_SIZE = 256;
const SCROLL_SCALE_AMOUNT = 100 / 5;
const WINDOW_CLONE_MAXIMUM_SCALE = 0.7;
const LIGHTBOX_FADE_TIME = 0.1;
const CLOSE_BUTTON_FADE_TIME = 0.1;
const DRAGGING_WINDOW_OPACITY = 100;
@ -345,19 +338,6 @@ const WindowOverlay = new Lang.Class({
this._animateVisible();
},
fadeIn: function() {
if (!this._hidden)
return;
this.show();
this.title.opacity = 0;
this._parentActor.raise_top();
Tweener.addTween(this.title,
{ opacity: 255,
time: CLOSE_BUTTON_FADE_TIME,
transition: 'easeOutQuad' });
},
chromeHeights: function () {
return [Math.max(this.borderSize, this.closeButton.height - this.closeButton._overlap),
this.title.height + this.title._spacing];
@ -374,7 +354,6 @@ const WindowOverlay = new Lang.Class({
let border = this.border;
Tweener.removeTweens(button);
Tweener.removeTweens(title);
Tweener.removeTweens(border);
let [cloneX, cloneY, cloneWidth, cloneHeight] = this._windowClone.slot;
@ -908,6 +887,19 @@ function padArea(area, padding) {
};
}
function rectEqual(one, two) {
if (one == two)
return true;
if (!one || !two)
return false;
return (one.x == two.x &&
one.y == two.y &&
one.width == two.width &&
one.height == two.height);
}
/**
* @metaWorkspace: a #Meta.Workspace, or null
*/
@ -983,11 +975,17 @@ const Workspace = new Lang.Class({
},
setFullGeometry: function(geom) {
if (rectEqual(this._fullGeometry, geom))
return;
this._fullGeometry = geom;
this._recalculateWindowPositions(WindowPositionFlags.NONE);
},
setActualGeometry: function(geom) {
if (rectEqual(this._actualGeometry, geom))
return;
this._actualGeometry = geom;
if (this._actualGeometryLater)
@ -1144,7 +1142,7 @@ const Workspace = new Lang.Class({
clone.actor.set_scale(scale, scale);
clone.actor.set_opacity(255);
clone.overlay.relayout(false);
this._showWindowOverlay(clone, overlay, isOnCurrentWorkspace);
this._showWindowOverlay(clone, overlay);
}
}
},
@ -1174,23 +1172,19 @@ const Workspace = new Lang.Class({
time: Overview.ANIMATION_TIME,
transition: 'easeOutQuad',
onComplete: Lang.bind(this, function() {
this._showWindowOverlay(clone, overlay, true);
this._showWindowOverlay(clone, overlay);
})
});
clone.overlay.relayout(true);
},
_showWindowOverlay: function(clone, overlay, fade) {
_showWindowOverlay: function(clone, overlay) {
if (clone.inDrag)
return;
if (overlay) {
if (fade)
overlay.fadeIn();
else
if (overlay && overlay._hidden)
overlay.show();
}
},
_delayedWindowRepositioning: function() {
@ -1214,6 +1208,7 @@ const Workspace = new Lang.Class({
}
this._recalculateWindowPositions(WindowPositionFlags.ANIMATE);
this._repositionWindowsId = 0;
return false;
},
@ -1469,17 +1464,17 @@ const Workspace = new Lang.Class({
clone.connect('selected',
Lang.bind(this, this._onCloneSelected));
clone.connect('drag-begin',
Lang.bind(this, function(clone) {
Main.overview.beginWindowDrag();
Lang.bind(this, function() {
Main.overview.beginWindowDrag(clone);
overlay.hide();
}));
clone.connect('drag-cancelled',
Lang.bind(this, function(clone) {
Main.overview.cancelledWindowDrag();
Lang.bind(this, function() {
Main.overview.cancelledWindowDrag(clone);
}));
clone.connect('drag-end',
Lang.bind(this, function(clone) {
Main.overview.endWindowDrag();
Lang.bind(this, function() {
Main.overview.endWindowDrag(clone);
overlay.show();
}));
clone.connect('size-changed',
@ -1641,9 +1636,7 @@ const Workspace = new Lang.Class({
metaWindow.move_to_monitor(this.monitorIndex);
let index = this.metaWorkspace ? this.metaWorkspace.index() : global.screen.get_active_workspace_index();
metaWindow.change_workspace_by_index(index,
false, // don't create workspace
time);
metaWindow.change_workspace_by_index(index, false);
return true;
} else if (source.shellWorkspaceLaunch) {
source.shellWorkspaceLaunch({ workspace: this.metaWorkspace ? this.metaWorkspace.index() : -1,

View File

@ -438,16 +438,16 @@ const WorkspaceThumbnail = new Lang.Class({
this.activate(time);
}));
clone.connect('drag-begin',
Lang.bind(this, function(clone) {
Main.overview.beginWindowDrag();
Lang.bind(this, function() {
Main.overview.beginWindowDrag(clone);
}));
clone.connect('drag-cancelled',
Lang.bind(this, function(clone) {
Main.overview.cancelledWindowDrag();
Lang.bind(this, function() {
Main.overview.cancelledWindowDrag(clone);
}));
clone.connect('drag-end',
Lang.bind(this, function(clone) {
Main.overview.endWindowDrag();
Lang.bind(this, function() {
Main.overview.endWindowDrag(clone);
}));
this._contents.add_actor(clone.actor);
@ -507,9 +507,7 @@ const WorkspaceThumbnail = new Lang.Class({
if (metaWindow.get_monitor() != this.monitorIndex)
metaWindow.move_to_monitor(this.monitorIndex);
metaWindow.change_workspace_by_index(this.metaWorkspace.index(),
false, // don't create workspace
time);
metaWindow.change_workspace_by_index(this.metaWorkspace.index(), false);
return true;
} else if (source.shellWorkspaceLaunch) {
source.shellWorkspaceLaunch({ workspace: this.metaWorkspace ? this.metaWorkspace.index() : -1,
@ -536,20 +534,6 @@ const ThumbnailsBox = new Lang.Class({
this.actor.connect('allocate', Lang.bind(this, this._allocate));
this.actor._delegate = this;
// When we animate the scale, we don't animate the requested size of the thumbnails, rather
// we ask for our final size and then animate within that size. This slightly simplifies the
// interaction with the main workspace windows (instead of constantly reallocating them
// to a new size, they get a new size once, then use the standard window animation code
// allocate the windows to their new positions), however it causes problems for drawing
// the background and border wrapped around the thumbnail as we animate - we can't just pack
// the container into a box and set style properties on the box since that box would wrap
// around the final size not the animating size. So instead we fake the background with
// an actor underneath the content and adjust the allocation of our children to leave space
// for the border and padding of the background actor.
this._background = new St.Bin({ style_class: 'workspace-thumbnails-background' });
this.actor.add_actor(this._background);
let indicator = new St.Bin({ style_class: 'workspace-thumbnail-indicator' });
// We don't want the indicator to affect drag-and-drop
@ -753,14 +737,12 @@ const ThumbnailsBox = new Lang.Class({
// ... move them down one.
windows.forEach(function(win) {
win.meta_window.change_workspace_by_index(win.get_workspace() + 1,
true, time);
win.meta_window.change_workspace_by_index(win.get_workspace() + 1, true);
});
if (isWindow)
// ... and bam, a workspace, good as new.
source.metaWindow.change_workspace_by_index(newWorkspaceIndex,
true, time);
source.metaWindow.change_workspace_by_index(newWorkspaceIndex, true);
else if (source.shellWorkspaceLaunch) {
source.shellWorkspaceLaunch({ workspace: newWorkspaceIndex,
timestamp: time });
@ -1042,9 +1024,6 @@ const ThumbnailsBox = new Lang.Class({
},
_getPreferredHeight: function(actor, forWidth, alloc) {
// See comment about this._background in _init()
let themeNode = this._background.get_theme_node();
// Note that for getPreferredWidth/Height we cheat a bit and skip propagating
// the size request to our children because we know how big they are and know
// that the actors aren't depending on the virtual functions being called.
@ -1052,24 +1031,21 @@ const ThumbnailsBox = new Lang.Class({
if (this._thumbnails.length == 0)
return;
let spacing = this.actor.get_theme_node().get_length('spacing');
let themeNode = this.actor.get_theme_node();
let spacing = themeNode.get_length('spacing');
let nWorkspaces = global.screen.n_workspaces;
let totalSpacing = (nWorkspaces - 1) * spacing;
[alloc.min_size, alloc.natural_size] =
themeNode.adjust_preferred_height(totalSpacing,
totalSpacing + nWorkspaces * this._porthole.height * MAX_THUMBNAIL_SCALE);
alloc.min_size = totalSpacing;
alloc.natural_size = totalSpacing + nWorkspaces * this._porthole.height * MAX_THUMBNAIL_SCALE;
},
_getPreferredWidth: function(actor, forHeight, alloc) {
// See comment about this._background in _init()
let themeNode = this._background.get_theme_node();
if (this._thumbnails.length == 0)
return;
// We don't animate our preferred width, which is always reported according
// to the actual number of current workspaces, we just animate within that
let themeNode = this.actor.get_theme_node();
let spacing = this.actor.get_theme_node().get_length('spacing');
let nWorkspaces = global.screen.n_workspaces;
@ -1081,28 +1057,26 @@ const ThumbnailsBox = new Lang.Class({
scale = Math.min(scale, MAX_THUMBNAIL_SCALE);
let width = Math.round(this._porthole.width * scale);
[alloc.min_size, alloc.natural_size] =
themeNode.adjust_preferred_width(width, width);
alloc.min_size = width;
alloc.natural_size = width;
},
_allocate: function(actor, box, flags) {
let rtl = (Clutter.get_default_text_direction () == Clutter.TextDirection.RTL);
// See comment about this._background in _init()
let themeNode = this._background.get_theme_node();
let contentBox = themeNode.get_content_box(box);
if (this._thumbnails.length == 0) // not visible
return;
let themeNode = this.actor.get_theme_node();
let portholeWidth = this._porthole.width;
let portholeHeight = this._porthole.height;
let spacing = this.actor.get_theme_node().get_length('spacing');
let spacing = themeNode.get_length('spacing');
// Compute the scale we'll need once everything is updated
let nWorkspaces = global.screen.n_workspaces;
let totalSpacing = (nWorkspaces - 1) * spacing;
let avail = (contentBox.y2 - contentBox.y1) - totalSpacing;
let avail = (box.y2 - box.y1) - totalSpacing;
let newScale = (avail / nWorkspaces) / portholeHeight;
newScale = Math.min(newScale, MAX_THUMBNAIL_SCALE);
@ -1131,21 +1105,6 @@ const ThumbnailsBox = new Lang.Class({
else
slideOffset = thumbnailWidth + themeNode.get_padding(St.Side.RIGHT);
let childBox = new Clutter.ActorBox();
// The background is horizontally restricted to correspond to the current thumbnail size
// but otherwise covers the entire allocation
if (rtl) {
childBox.x1 = box.x1;
childBox.x2 = box.x2 - ((contentBox.x2 - contentBox.x1) - thumbnailWidth);
} else {
childBox.x1 = box.x1 + ((contentBox.x2 - contentBox.x1) - thumbnailWidth);
childBox.x2 = box.x2;
}
childBox.y1 = box.y1;
childBox.y2 = box.y2;
this._background.allocate(childBox, flags);
let indicatorY1 = this._indicatorY;
let indicatorY2;
// when not animating, the workspace position overrides this._indicatorY
@ -1157,7 +1116,7 @@ const ThumbnailsBox = new Lang.Class({
let indicatorLeftFullBorder = indicatorThemeNode.get_padding(St.Side.LEFT) + indicatorThemeNode.get_border_width(St.Side.LEFT);
let indicatorRightFullBorder = indicatorThemeNode.get_padding(St.Side.RIGHT) + indicatorThemeNode.get_border_width(St.Side.RIGHT);
let y = contentBox.y1;
let y = box.y1;
if (this._dropPlaceholderPos == -1) {
Meta.later_add(Meta.LaterType.BEFORE_REDRAW, Lang.bind(this, function() {
@ -1165,6 +1124,8 @@ const ThumbnailsBox = new Lang.Class({
}));
}
let childBox = new Clutter.ActorBox();
for (let i = 0; i < this._thumbnails.length; i++) {
let thumbnail = this._thumbnails[i];
@ -1173,10 +1134,10 @@ const ThumbnailsBox = new Lang.Class({
let x1, x2;
if (rtl) {
x1 = contentBox.x1 + slideOffset * thumbnail.slidePosition;
x1 = box.x1 + slideOffset * thumbnail.slidePosition;
x2 = x1 + thumbnailWidth;
} else {
x1 = contentBox.x2 - thumbnailWidth + slideOffset * thumbnail.slidePosition;
x1 = box.x2 - thumbnailWidth + slideOffset * thumbnail.slidePosition;
x2 = x1 + thumbnailWidth;
}
@ -1223,11 +1184,11 @@ const ThumbnailsBox = new Lang.Class({
}
if (rtl) {
childBox.x1 = contentBox.x1;
childBox.x2 = contentBox.x1 + thumbnailWidth;
childBox.x1 = box.x1;
childBox.x2 = box.x1 + thumbnailWidth;
} else {
childBox.x1 = contentBox.x2 - thumbnailWidth;
childBox.x2 = contentBox.x2;
childBox.x1 = box.x2 - thumbnailWidth;
childBox.x2 = box.x2;
}
childBox.x1 -= indicatorLeftFullBorder;
childBox.x2 += indicatorRightFullBorder;

View File

@ -23,76 +23,92 @@ const MAX_WORKSPACES = 16;
const OVERRIDE_SCHEMA = 'org.gnome.shell.overrides';
function rectEqual(one, two) {
if (one == two)
return true;
const WorkspacesViewBase = new Lang.Class({
Name: 'WorkspacesViewBase',
if (!one || !two)
return false;
return (one.x == two.x &&
one.y == two.y &&
one.width == two.width &&
one.height == two.height);
}
const WorkspacesView = new Lang.Class({
Name: 'WorkspacesView',
_init: function(workspaces) {
_init: function(monitorIndex) {
this.actor = new St.Widget({ style_class: 'workspaces-view',
reactive: true });
this.actor.connect('destroy', Lang.bind(this, this._onDestroy));
// 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.connect('destroy', Lang.bind(this, this._onDestroy));
this.actor.connect('style-changed', Lang.bind(this,
function() {
let node = this.actor.get_theme_node();
this._spacing = node.get_length('spacing');
this._updateWorkspaceActors(false);
}));
this._monitorIndex = monitorIndex;
this._fullGeometry = null;
this._actualGeometry = null;
this._spacing = 0;
this._inDrag = false;
this._windowDragBeginId = Main.overview.connect('window-drag-begin', Lang.bind(this, this._dragBegin));
this._windowDragEndId = Main.overview.connect('window-drag-end', Lang.bind(this, this._dragEnd));
},
_onDestroy: function() {
this._dragEnd();
if (this._windowDragBeginId > 0) {
Main.overview.disconnect(this._windowDragBeginId);
this._windowDragBeginId = 0;
}
if (this._windowDragEndId > 0) {
Main.overview.disconnect(this._windowDragEndId);
this._windowDragEndId = 0;
}
},
_dragBegin: function(overview, clone) {
this._inDrag = true;
this._setReservedSlot(clone);
},
_dragEnd: function() {
this._inDrag = false;
this._setReservedSlot(null);
},
destroy: function() {
this.actor.destroy();
},
setFullGeometry: function(geom) {
this._fullGeometry = geom;
this._syncGeometry();
},
setActualGeometry: function(geom) {
this._actualGeometry = geom;
this._syncGeometry();
},
});
const WorkspacesView = new Lang.Class({
Name: 'WorkspacesView',
Extends: WorkspacesViewBase,
_init: function(monitorIndex) {
this.parent(monitorIndex);
this._animating = false; // tweening
this._scrolling = false; // swipe-scrolling
this._animatingScroll = false; // programatically updating the adjustment
this._zoomOut = false; // zoom to a larger area
this._inDrag = false; // dragging a window
this._settings = new Gio.Settings({ schema: OVERRIDE_SCHEMA });
this._updateExtraWorkspacesId =
this._settings.connect('changed::workspaces-only-on-primary',
Lang.bind(this, this._updateExtraWorkspaces));
let activeWorkspaceIndex = global.screen.get_active_workspace_index();
this._workspaces = workspaces;
this.scrollAdjustment = new St.Adjustment({ value: activeWorkspaceIndex,
lower: 0,
page_increment: 1,
page_size: 1,
step_increment: 0,
upper: 0 });
this.scrollAdjustment.connect('notify::value',
Lang.bind(this, this._onScroll));
// Add workspace actors
for (let w = 0; w < global.screen.n_workspaces; w++)
this.actor.add_actor(this._workspaces[w].actor);
this._workspaces[activeWorkspaceIndex].actor.raise_top();
this._workspaces = [];
this._updateWorkspaces();
this._updateWorkspacesId = global.screen.connect('notify::n-workspaces', Lang.bind(this, this._updateWorkspaces));
this._extraWorkspaces = [];
this._updateExtraWorkspaces();
// Position/scale the desktop windows and their children after the
// workspaces have been created. This cannot be done first because
// window movement depends on the Workspaces object being accessible
// as an Overview member.
this._overviewShowingId =
Main.overview.connect('showing',
Lang.bind(this, function() {
for (let w = 0; w < this._workspaces.length; w++)
this._workspaces[w].zoomToOverview();
for (let w = 0; w < this._extraWorkspaces.length; w++)
this._extraWorkspaces[w].zoomToOverview();
}));
this._overviewShownId =
Main.overview.connect('shown',
Lang.bind(this, function() {
@ -100,80 +116,21 @@ const WorkspacesView = new Lang.Class({
this._fullGeometry.width, this._fullGeometry.height);
}));
this.scrollAdjustment = new St.Adjustment({ value: activeWorkspaceIndex,
lower: 0,
page_increment: 1,
page_size: 1,
step_increment: 0,
upper: this._workspaces.length });
this.scrollAdjustment.connect('notify::value',
Lang.bind(this, this._onScroll));
this._switchWorkspaceNotifyId =
global.window_manager.connect('switch-workspace',
Lang.bind(this, this._activeWorkspaceChanged));
this._itemDragBeginId = Main.overview.connect('item-drag-begin',
Lang.bind(this, this._dragBegin));
this._itemDragEndId = Main.overview.connect('item-drag-end',
Lang.bind(this, this._dragEnd));
this._windowDragBeginId = Main.overview.connect('window-drag-begin',
Lang.bind(this, this._dragBegin));
this._windowDragEndId = Main.overview.connect('window-drag-end',
Lang.bind(this, this._dragEnd));
},
_updateExtraWorkspaces: function() {
this._destroyExtraWorkspaces();
if (!this._settings.get_boolean('workspaces-only-on-primary'))
return;
let monitors = Main.layoutManager.monitors;
for (let i = 0; i < monitors.length; i++) {
if (i == Main.layoutManager.primaryIndex)
continue;
let ws = new Workspace.Workspace(null, i);
ws.setFullGeometry(monitors[i]);
ws.setActualGeometry(monitors[i]);
Main.layoutManager.overviewGroup.add_actor(ws.actor);
this._extraWorkspaces.push(ws);
}
},
_destroyExtraWorkspaces: function() {
for (let m = 0; m < this._extraWorkspaces.length; m++)
this._extraWorkspaces[m].destroy();
this._extraWorkspaces = [];
},
setFullGeometry: function(geom) {
if (rectEqual(this._fullGeometry, geom))
return;
this._fullGeometry = geom;
_setReservedSlot: function(clone) {
for (let i = 0; i < this._workspaces.length; i++)
this._workspaces[i].setFullGeometry(geom);
this._workspaces[i].setReservedSlot(clone);
},
setActualGeometry: function(geom) {
if (rectEqual(this._actualGeometry, geom))
return;
this._actualGeometry = geom;
_syncGeometry: function() {
for (let i = 0; i < this._workspaces.length; i++)
this._workspaces[i].setActualGeometry(geom);
},
_lookupWorkspaceForMetaWindow: function (metaWindow) {
for (let i = 0; i < this._workspaces.length; i++) {
if (this._workspaces[i].containsMetaWindow(metaWindow))
return this._workspaces[i];
}
return null;
this._workspaces[i].setFullGeometry(this._fullGeometry);
for (let i = 0; i < this._workspaces.length; i++)
this._workspaces[i].setActualGeometry(this._actualGeometry);
},
getActiveWorkspace: function() {
@ -181,29 +138,22 @@ const WorkspacesView = new Lang.Class({
return this._workspaces[active];
},
hide: function() {
let activeWorkspaceIndex = global.screen.get_active_workspace_index();
let activeWorkspace = this._workspaces[activeWorkspaceIndex];
activeWorkspace.actor.raise_top();
zoomToOverview: function() {
for (let w = 0; w < this._workspaces.length; w++)
this._workspaces[w].zoomToOverview();
this._updateWorkspaceActors(false);
},
zoomFromOverview: function() {
this.actor.remove_clip();
for (let w = 0; w < this._workspaces.length; w++)
this._workspaces[w].zoomFromOverview();
for (let w = 0; w < this._extraWorkspaces.length; w++)
this._extraWorkspaces[w].zoomFromOverview();
},
destroy: function() {
this.actor.destroy();
},
syncStacking: function(stackIndices) {
for (let i = 0; i < this._workspaces.length; i++)
this._workspaces[i].syncStacking(stackIndices);
for (let i = 0; i < this._extraWorkspaces.length; i++)
this._extraWorkspaces[i].syncStacking(stackIndices);
},
_scrollToActive: function() {
@ -225,7 +175,7 @@ const WorkspacesView = new Lang.Class({
Tweener.removeTweens(workspace.actor);
let y = (w - active) * (this._fullGeometry.height + this._spacing);
let y = (w - active) * this._fullGeometry.height;
if (showAnimation) {
let params = { y: y,
@ -285,25 +235,31 @@ const WorkspacesView = new Lang.Class({
});
},
updateWorkspaces: function(oldNumWorkspaces, newNumWorkspaces) {
let active = global.screen.get_active_workspace_index();
_updateWorkspaces: function() {
let oldNumWorkspaces = this._workspaces.length;
let newNumWorkspaces = global.screen.n_workspaces;
Tweener.addTween(this.scrollAdjustment,
{ upper: newNumWorkspaces,
time: WORKSPACE_SWITCH_TIME,
transition: 'easeOutQuad'
});
this.scrollAdjustment.upper = newNumWorkspaces;
if (newNumWorkspaces > oldNumWorkspaces) {
for (let w = oldNumWorkspaces; w < newNumWorkspaces; w++) {
this._workspaces[w].setFullGeometry(this._fullGeometry);
if (this._actualGeometry)
this._workspaces[w].setActualGeometry(this._actualGeometry);
this.actor.add_actor(this._workspaces[w].actor);
let metaWorkspace = global.screen.get_workspace_by_index(w);
let workspace = new Workspace.Workspace(metaWorkspace, this._monitorIndex);
this._workspaces.push(workspace);
this.actor.add_actor(workspace.actor);
}
this._updateWorkspaceActors(false);
if (this._fullGeometry)
this._updateWorkspaceActors(false);
} else if (newNumWorkspaces < oldNumWorkspaces) {
let nRemoved = (newNumWorkspaces - oldNumWorkspaces);
let removed = this._workspaces.splice(oldNumWorkspaces, nRemoved);
removed.forEach(function(workspace) {
workspace.destroy();
});
}
this._syncGeometry();
},
_activeWorkspaceChanged: function(wm, from, to, direction) {
@ -314,70 +270,12 @@ const WorkspacesView = new Lang.Class({
},
_onDestroy: function() {
this._destroyExtraWorkspaces();
this.parent();
this.scrollAdjustment.run_dispose();
Main.overview.disconnect(this._overviewShowingId);
Main.overview.disconnect(this._overviewShownId);
global.window_manager.disconnect(this._switchWorkspaceNotifyId);
this._settings.disconnect(this._updateExtraWorkspacesId);
if (this._inDrag)
this._dragEnd();
if (this._itemDragBeginId > 0) {
Main.overview.disconnect(this._itemDragBeginId);
this._itemDragBeginId = 0;
}
if (this._itemDragEndId > 0) {
Main.overview.disconnect(this._itemDragEndId);
this._itemDragEndId = 0;
}
if (this._windowDragBeginId > 0) {
Main.overview.disconnect(this._windowDragBeginId);
this._windowDragBeginId = 0;
}
if (this._windowDragEndId > 0) {
Main.overview.disconnect(this._windowDragEndId);
this._windowDragEndId = 0;
}
},
_dragBegin: function() {
if (this._scrolling)
return;
this._inDrag = true;
this._firstDragMotion = true;
this._dragMonitor = {
dragMotion: Lang.bind(this, this._onDragMotion)
};
DND.addDragMonitor(this._dragMonitor);
},
_onDragMotion: function(dragEvent) {
if (Main.overview.animationInProgress)
return DND.DragMotionResult.CONTINUE;
if (this._firstDragMotion) {
this._firstDragMotion = false;
for (let i = 0; i < this._workspaces.length; i++)
this._workspaces[i].setReservedSlot(dragEvent.dragActor._delegate);
for (let i = 0; i < this._extraWorkspaces.length; i++)
this._extraWorkspaces[i].setReservedSlot(dragEvent.dragActor._delegate);
}
return DND.DragMotionResult.CONTINUE;
},
_dragEnd: function() {
DND.removeDragMonitor(this._dragMonitor);
this._inDrag = false;
for (let i = 0; i < this._workspaces.length; i++)
this._workspaces[i].setReservedSlot(null);
for (let i = 0; i < this._extraWorkspaces.length; i++)
this._extraWorkspaces[i].setReservedSlot(null);
global.screen.disconnect(this._updateWorkspacesId);
},
startSwipeScroll: function() {
@ -433,13 +331,45 @@ const WorkspacesView = new Lang.Class({
this._workspaces[i].actor.y += dy;
}
},
_getWorkspaceIndexToRemove: function() {
return global.screen.get_active_workspace_index();
}
});
Signals.addSignalMethods(WorkspacesView.prototype);
const ExtraWorkspaceView = new Lang.Class({
Name: 'ExtraWorkspaceView',
Extends: WorkspacesViewBase,
_init: function(monitorIndex) {
this.parent(monitorIndex);
this._workspace = new Workspace.Workspace(null, monitorIndex);
this.actor.add_actor(this._workspace.actor);
},
_setReservedSlot: function(clone) {
this._workspace.setReservedSlot(clone);
},
_syncGeometry: function() {
this._workspace.setFullGeometry(this._fullGeometry);
this._workspace.setActualGeometry(this._actualGeometry);
},
zoomToOverview: function() {
this._workspace.zoomToOverview();
},
zoomFromOverview: function() {
this._workspace.zoomFromOverview();
},
syncStacking: function(stackIndices) {
this._workspace.syncStacking(stackIndices);
},
startSwipeScroll: function() {
},
endSwipeScroll: function() {
},
});
const WorkspacesDisplay = new Lang.Class({
Name: 'WorkspacesDisplay',
@ -484,7 +414,6 @@ const WorkspacesDisplay = new Lang.Class({
this._primaryIndex = Main.layoutManager.primaryIndex;
this._workspacesViews = [];
this._workspaces = [];
this._primaryScrollAdjustment = null;
this._settings = new Gio.Settings({ schema: OVERRIDE_SCHEMA });
@ -493,9 +422,6 @@ const WorkspacesDisplay = new Lang.Class({
this._workspacesOnlyOnPrimaryChanged));
this._workspacesOnlyOnPrimaryChanged();
global.screen.connect('notify::n-workspaces',
Lang.bind(this, this._workspacesChanged));
this._switchWorkspaceNotifyId = 0;
this._notifyOpacityId = 0;
@ -513,6 +439,8 @@ const WorkspacesDisplay = new Lang.Class({
show: function() {
this._updateWorkspacesViews();
for (let i = 0; i < this._workspacesViews.length; i++)
this._workspacesViews[i].zoomToOverview();
this._restackedNotifyId =
Main.overview.connect('windows-restacked',
@ -522,9 +450,8 @@ const WorkspacesDisplay = new Lang.Class({
},
zoomFromOverview: function() {
for (let i = 0; i < this._workspacesViews.length; i++) {
this._workspacesViews[i].hide();
}
for (let i = 0; i < this._workspacesViews.length; i++)
this._workspacesViews[i].zoomFromOverview();
},
hide: function() {
@ -556,46 +483,38 @@ const WorkspacesDisplay = new Lang.Class({
this._workspacesViews[i].destroy();
this._workspacesViews = [];
this._workspaces = [];
let monitors = Main.layoutManager.monitors;
for (let i = 0; i < monitors.length; i++) {
let view;
if (this._workspacesOnlyOnPrimary && i != this._primaryIndex)
continue; // we are only interested in the primary monitor
view = new ExtraWorkspaceView(i);
else
view = new WorkspacesView(i);
let monitorWorkspaces = [];
for (let w = 0; w < global.screen.n_workspaces; w++) {
let metaWorkspace = global.screen.get_workspace_by_index(w);
monitorWorkspaces.push(new Workspace.Workspace(metaWorkspace, i));
}
this._workspaces.push(monitorWorkspaces);
let view = new WorkspacesView(monitorWorkspaces);
view.actor.connect('scroll-event', Lang.bind(this, this._onScrollEvent));
if (this._workspacesOnlyOnPrimary || i == this._primaryIndex) {
if (i == this._primaryIndex) {
this._scrollAdjustment = view.scrollAdjustment;
this._scrollAdjustment.connect('notify::value',
Lang.bind(this, this._scrollValueChanged));
}
this._workspacesViews.push(view);
Main.layoutManager.overviewGroup.add_actor(view.actor);
}
this._updateWorkspacesFullGeometry();
this._updateWorkspacesActualGeometry();
for (let i = 0; i < this._workspacesViews.length; i++)
Main.layoutManager.overviewGroup.add_actor(this._workspacesViews[i].actor);
},
_scrollValueChanged: function() {
if (this._workspacesOnlyOnPrimary)
return;
for (let i = 0; i < this._workspacesViews.length; i++) {
if (i == this._primaryIndex)
continue;
let adjustment = this._workspacesViews[i].scrollAdjustment;
if (!adjustment)
continue;
// the adjustments work in terms of workspaces, so the
// values map directly
adjustment.value = this._scrollAdjustment.value;
@ -605,10 +524,7 @@ const WorkspacesDisplay = new Lang.Class({
_getPrimaryView: function() {
if (!this._workspacesViews.length)
return null;
if (this._workspacesOnlyOnPrimary)
return this._workspacesViews[0];
else
return this._workspacesViews[this._primaryIndex];
return this._workspacesViews[this._primaryIndex];
},
activeWorkspaceHasMaximizedWindows: function() {
@ -654,15 +570,9 @@ const WorkspacesDisplay = new Lang.Class({
return;
let monitors = Main.layoutManager.monitors;
let m = 0;
for (let i = 0; i < monitors.length; i++) {
if (i == this._primaryIndex) {
this._workspacesViews[m].setFullGeometry(this._fullGeometry);
m++;
} else if (!this._workspacesOnlyOnPrimary) {
this._workspacesViews[m].setFullGeometry(monitors[i]);
m++;
}
let geometry = (i == this._primaryIndex) ? this._fullGeometry : monitors[i];
this._workspacesViews[i].setFullGeometry(geometry);
}
},
@ -673,18 +583,12 @@ const WorkspacesDisplay = new Lang.Class({
let [x, y] = this.actor.get_transformed_position();
let width = this.actor.allocation.x2 - this.actor.allocation.x1;
let height = this.actor.allocation.y2 - this.actor.allocation.y1;
let geometry = { x: x, y: y, width: width, height: height };
let primaryGeometry = { x: x, y: y, width: width, height: height };
let monitors = Main.layoutManager.monitors;
let m = 0;
for (let i = 0; i < monitors.length; i++) {
if (i == this._primaryIndex) {
this._workspacesViews[m].setActualGeometry(geometry);
m++;
} else if (!this._workspacesOnlyOnPrimary) {
this._workspacesViews[m].setActualGeometry(monitors[i]);
m++;
}
let geometry = (i == this._primaryIndex) ? primaryGeometry : monitors[i];
this._workspacesViews[i].setActualGeometry(geometry);
}
},
@ -693,60 +597,6 @@ const WorkspacesDisplay = new Lang.Class({
this._workspacesViews[i].syncStacking(stackIndices);
},
_workspacesChanged: function() {
if (!this._workspacesViews.length)
return;
let oldNumWorkspaces = this._workspaces[0].length;
let newNumWorkspaces = global.screen.n_workspaces;
let active = global.screen.get_active_workspace_index();
let lostWorkspaces = [];
if (newNumWorkspaces > oldNumWorkspaces) {
let monitors = Main.layoutManager.monitors;
let m = 0;
for (let i = 0; i < monitors.length; i++) {
if (this._workspacesOnlyOnPrimary &&
i != this._primaryIndex)
continue;
// Assume workspaces are only added at the end
for (let w = oldNumWorkspaces; w < newNumWorkspaces; w++) {
let metaWorkspace = global.screen.get_workspace_by_index(w);
this._workspaces[m][w] =
new Workspace.Workspace(metaWorkspace, i);
}
m++;
}
} else {
// Assume workspaces are only removed sequentially
// (e.g. 2,3,4 - not 2,4,7)
let removedIndex;
let removedNum = oldNumWorkspaces - newNumWorkspaces;
for (let w = 0; w < oldNumWorkspaces; w++) {
let metaWorkspace = global.screen.get_workspace_by_index(w);
if (this._workspaces[0][w].metaWorkspace != metaWorkspace) {
removedIndex = w;
break;
}
}
for (let i = 0; i < this._workspaces.length; i++) {
lostWorkspaces = this._workspaces[i].splice(removedIndex,
removedNum);
for (let l = 0; l < lostWorkspaces.length; l++) {
lostWorkspaces[l].disconnectAll();
lostWorkspaces[l].destroy();
}
}
}
for (let i = 0; i < this._workspacesViews.length; i++)
this._workspacesViews[i].updateWorkspaces(oldNumWorkspaces,
newNumWorkspaces);
},
_onScrollEvent: function(actor, event) {
if (!this.actor.mapped)
return false;

View File

@ -3,6 +3,7 @@
const Clutter = imports.gi.Clutter;
const Lang = imports.lang;
const Main = imports.ui.main;
const Meta = imports.gi.Meta;
const Shell = imports.gi.Shell;
const Signals = imports.signals;
const DND = imports.ui.dnd;
@ -20,7 +21,8 @@ const XdndHandler = new Lang.Class({
Main.uiGroup.add_actor(this._dummy);
this._dummy.hide();
global.init_xdnd();
if (!Meta.is_wayland_compositor())
global.init_xdnd();
global.connect('xdnd-enter', Lang.bind(this, this._onEnter));
global.connect('xdnd-position-changed', Lang.bind(this, this._onPositionChanged));

View File

@ -4,6 +4,7 @@
data/50-gnome-shell-system.xml.in
data/gnome-shell.desktop.in.in
data/gnome-shell-extension-prefs.desktop.in.in
data/gnome-shell-wayland.desktop.in.in
data/org.gnome.shell.gschema.xml.in.in
js/extensionPrefs/main.js
js/gdm/authPrompt.js
@ -37,7 +38,7 @@ js/ui/panel.js
js/ui/popupMenu.js
js/ui/runDialog.js
js/ui/screenShield.js
js/ui/searchDisplay.js
js/ui/search.js
js/ui/shellEntry.js
js/ui/shellMountOperation.js
js/ui/status/accessibility.js
@ -51,7 +52,6 @@ js/ui/status/system.js
js/ui/status/volume.js
js/ui/unlockDialog.js
js/ui/viewSelector.js
js/ui/wanda.js
js/ui/windowAttentionHandler.js
js/ui/windowManager.js
src/calendar-server/evolution-calendar.desktop.in.in

488
po/as.po

File diff suppressed because it is too large Load Diff

449
po/be.po

File diff suppressed because it is too large Load Diff

1866
po/ca.po

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

505
po/cs.po

File diff suppressed because it is too large Load Diff

1565
po/da.po

File diff suppressed because it is too large Load Diff

845
po/de.po

File diff suppressed because it is too large Load Diff

1851
po/el.po

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

2921
po/eo.po

File diff suppressed because it is too large Load Diff

479
po/es.po

File diff suppressed because it is too large Load Diff

1007
po/et.po

File diff suppressed because it is too large Load Diff

1750
po/eu.po

File diff suppressed because it is too large Load Diff

1798
po/fa.po

File diff suppressed because it is too large Load Diff

431
po/fi.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