Compare commits

...

432 Commits

Author SHA1 Message Date
cad6f31c1a Bump version to 3.8.3
Update NEWS.
2013-06-07 21:46:20 +02:00
294f59103f window-switcher: Only show windows from current workspace by default
When adding the window switcher, we copied our default values from
the alternate-tab extension. Arguably it makes more sense to mimick
the old mutter/metacity behavior though, so change the default
accordingly.

https://bugzilla.gnome.org/show_bug.cgi?id=701214
2013-06-07 21:34:01 +02:00
f88f51dd99 osdWindow: Disable unredirection while showing the OSD
This allows OSDs to be visible even when displayed on top
of unredirected windows.

https://bugzilla.gnome.org/show_bug.cgi?id=701224
2013-06-07 21:22:03 +02:00
c1eaf97bc6 RemoteMenu: Avoid useless signal connections
If we are missing more than one action, every time action-added is
called, it calls modelChanged() again and re-connect signal for
all action still missing. This patch prevent from connecting signals
again when doing a refresh because a missing action is now available.
All necessary signals have already been connected.

https://bugzilla.gnome.org/show_bug.cgi?id=694612
2013-06-07 20:08:37 +02:00
1420f62dfa RemoteMenu: use detailed action-added signal
This avoid disconnecting all signals if we are waiting for
different actions to be added, leading to incomplete menu.
Previously if we were waiting for 2 different actions in 2
different sections, the first action-added signal would
disconnect the 2nd signal handler as well, so the model of
that section would not be updated when the 2nd action is added.

https://bugzilla.gnome.org/show_bug.cgi?id=694612
2013-06-07 20:08:37 +02:00
3ff194247a main: Use the correct schema for 'dynamic-workspaces'
We currently monitor the shell's override schema for changes to
the 'dynamic-workspaces' key, which ends up being the wrong
schema in classic mode. With the new ability to use mode-specific
overides, we can finally fix this.

https://bugzilla.gnome.org/show_bug.cgi?id=701717
2013-06-07 19:59:41 +02:00
36b1cd13c9 main: Pick up overridesSchema from sessionMode
This will allow the use of mode-specific defaults. For classic mode
we currently implement this with mini-extensions, but this may result
in confusing behavior when settings change due to extensions being
disabled during screen locks (not to mention that those mini-extensions
are hardly an elegant approach).

https://bugzilla.gnome.org/show_bug.cgi?id=701717
2013-06-07 19:59:39 +02:00
bcede26d77 main: Move pref overrides to JS
We will allow to use mode-specific overrides; in preparation for that,
move the code so that we only override preferences after initializing
the session mode.

https://bugzilla.gnome.org/show_bug.cgi?id=701717
2013-06-07 19:58:52 +02:00
fbf1ee8a01 update Simplified Chinese (zh_CN) translation 2013-06-06 11:44:18 +08:00
1360747c9e dnd: Use pushModal() to grab the keyboard
Currently we "only" grab the keyboard when starting a drag operation,
which does not impede keybindings to be processed. This is at best
not harmful (like workspace switching), but may have unintended effects
otherwise - for instance, the hot corner is disabled, so having the
corresponding keyboard shortcut still active is fairly odd (not to
mention that it leaves the system in a confused state).
Fix this by switching to pushModal()/popModal(), which will push a
dedicated keybinding mode for us.

https://bugzilla.gnome.org/show_bug.cgi?id=700877
2013-06-05 16:36:23 +02:00
1d95841da0 screenShield: Clear clipboard on lock
Currently the clipboard's contents may leak to unauthorized parties by
pasting into the unlock dialog's password entry and unmasking the entry.
Prevent this from happening by clearing the clipboard on lock.

https://bugzilla.gnome.org/show_bug.cgi?id=698922
2013-06-05 16:23:52 +02:00
494fcfecf8 osdWindow: Make sure the OSD is always our topmost chrome element
In particular this fixes the OSD showing up behind a modal dialog's
lightbox.

https://bugzilla.gnome.org/show_bug.cgi?id=701269
2013-06-05 15:36:12 +02:00
75705b45ef dash: Grow the empty dash during drag operations
When the dash does not contain any applications (either favorites
or running), it is currently impossable to add a favorite via DND.
Grow the dash slightly in that case to provide a drop target.

https://bugzilla.gnome.org/show_bug.cgi?id=684618
2013-06-05 14:54:45 +02:00
1ad1e48741 dash: Minor cleanup
https://bugzilla.gnome.org/show_bug.cgi?id=684618
2013-06-05 14:54:45 +02:00
ddb682e4fe dash: Use a single code path for clearing the drag placeholder
We currently only keep track of old placeholders when moving past
the dragged app's current favorite position, as this is the only
case where we need to worry about jitter. Still, moving it into
_clearDragPlaceholder() allows us to consolidate code paths, which
is a good thing ...

https://bugzilla.gnome.org/show_bug.cgi?id=684618
2013-06-05 14:54:45 +02:00
5216b77600 dash: Make sure _clearDragPlaceholder() resets _dragPlaceholderPos
The function currently only resets the placeholder position if
there is a placeholder; this is not necessarily true, as the
placeholder may be reset outside _clearDragPlaceholder().
If this happens, the placeholder will temporarily stop working
for the "old" position (and permanently if it's the only position).
Just reset the position unconditionally.

https://bugzilla.gnome.org/show_bug.cgi?id=684618
2013-06-05 14:28:25 +02:00
c93d91d80b Updated Traditional Chinese translation(Hong Kong and Taiwan) 2013-06-04 21:50:40 +08:00
f9e3467b70 appDisplay: Give more horizontal space to control buttons
Before, the text of those buttons were truncated when the text exceeded
the fixed width we had in the CSS.
Now, we give more horizontal space to the control buttons to match
the maximum text length of all buttons.

https://bugzilla.gnome.org/show_bug.cgi?id=696307
2013-06-04 13:53:42 +02:00
13bea1a01b Bump gvc submodule
As of commit 95a1b874d8, the submodule is supposed to be at
revision 3d6aac673b88ff, but commit 31774a7711 accidentally
reverted it back to the previously used revision.
2013-05-31 20:50:42 +02:00
76c930e471 build: Bump gcr requirement
https://bugzilla.gnome.org/show_bug.cgi?id=700972
2013-05-31 20:44:13 +02:00
9f6cd75170 shell-gtk-embed: Lower tray icon windows to the bottom of the stack
Otherwise they break the "top level window" detection used by the
unredirect code in mutter, causes game windows not to be unredirected
when tray icons are present.

https://bugzilla.gnome.org/show_bug.cgi?id=701224
2013-05-30 00:59:11 +02:00
c107882828 xdnd: Lower window activation timeout
The current one is perceived as too high by users, so try a shorter timeout.

https://bugzilla.gnome.org/show_bug.cgi?id=700150
2013-05-29 22:06:32 +02:00
d18e084cd5 Keyboard: clear currentSource after destruction
StLabel doesn't like that we set its properties after destructions,
and this would happen in currentInputSourceChanged() at the end,
when setting the ornament.
2013-05-25 20:39:33 +02:00
2eb779740c messageTray: Check if the clicked summary item has a right click menu
Commit e71129aa68 introduced the
possibility of having summary items without a right click menu so we
should check for one before trying to show it.

https://bugzilla.gnome.org/show_bug.cgi?id=700190
2013-05-24 23:57:47 +02:00
3ce20568d0 status/keyboard: Allow switching input source in the message tray
We still can't show a popup switcher in the message tray but we can at
least degrade gracefully and advance to the next input source.

https://bugzilla.gnome.org/show_bug.cgi?id=697009
2013-05-24 23:57:47 +02:00
d45ab6f15e status/keyboard: Switch input source on special modifiers accelerator
This simply mimics the X server's layout switching behavior by
advancing to the next input source and wrapping around.

https://bugzilla.gnome.org/show_bug.cgi?id=697008
2013-05-24 23:57:47 +02:00
cd7197e605 status/keyboard: Synchronize input source switching with key events
Currently we simply set the gsettings key when activating an input
source. This obviously introduces a time window, between the event that
activates the switch and when the switch is complete, under which key
events are being delivered to applications and interpreted according
to the previous input source.

The patches in bug 696996 introduce a DBus API in g-s-d that allows us
to know when an input source if effectively active. Using that and
freezing keyboard events in the X server until we hear back from g-s-d
we can ensure that events won't be misinterpreted after an input
source switch.

https://bugzilla.gnome.org/show_bug.cgi?id=697007
2013-05-24 23:57:47 +02:00
3f6c1aadef Depend on gcr-base instead of gcr pkg-config file
gnome-shell does not use the UI bits of the Gcr library

https://bugzilla.gnome.org/show_bug.cgi?id=700944
2013-05-24 11:18:17 +02:00
29e8290b65 docs: Include ShellKeyBindingMode in docs
https://bugzilla.gnome.org/show_bug.cgi?id=700900
2013-05-23 17:10:37 +02:00
3074e48405 popupMenu: Allow for an optional border for slider handle
While the default style works well will a solid handle, using both
border and fill color would be desirable in classic mode. Add the
necessary (optional) style properties to allow this.

https://bugzilla.gnome.org/show_bug.cgi?id=697917
2013-05-22 18:47:37 +02:00
12c2939b64 screenshot: Hide cursor while magnifier is active
As with the screen recorder, the magnifier already adds its own
copy of the system cursor, so we should not add it again. Just
as in the screen recorder case, we don't address the case where
the cursor should not be included in the screenshot, but the
magnifier adds it anyway.

https://bugzilla.gnome.org/show_bug.cgi?id=700488
2013-05-22 18:34:45 +02:00
c7eed59562 recorder: Hide cursor while magnifier is active
The magnifier adds its own copy of the system cursor to apply the
expected transformations, so we don't need to add it again in the
recorder; this avoids two different cursors showing up in recordings,
but doesn't address the case where the cursor should not be recorded
at all, but the magnifier adds it anyway.

https://bugzilla.gnome.org/show_bug.cgi?id=700488
2013-05-22 18:34:45 +02:00
73903400c5 screencast: Fix return value in case of invalid file template
If we are passed an invalid file template, ShellRecorder.record()
will return a %NULL filename; as the Screencast DBus interface
expects a string return value, we cannot return the value unmodified
in that case.

https://bugzilla.gnome.org/show_bug.cgi?id=700842
2013-05-22 17:24:04 +02:00
dc7cc9b517 userWidget: Fix leaking instances
UserWidget instances should be destroyed when the actor is. That's
what consumer code expects since the destroy() method is never called.

https://bugzilla.gnome.org/show_bug.cgi?id=700807
2013-05-21 21:55:21 +02:00
b18c239240 appDisplay: Also account for folder popup's close buttons
As the close button of folder popups overlaps at the top, it ends
up being cut off if the folder is located at the very top of the
view. Fix this glitch by taking the button's overlap into account
in that case.

https://bugzilla.gnome.org/show_bug.cgi?id=694371
2013-05-20 18:21:16 +02:00
3c66f1a4d9 appDisplay: Fix cut-off folders in All view
We already take care of growing the view if open folders overlap
at the bottom, however folder popups may still end up being cut
off when opening above the source icon - if the popup is high enough,
its y coordinate will be negative and therefore outside the parent's
allocation. To fix, we can either make sure that folders pop up below
their source icon in that case, or adjust the parent grid's position
as necessary while a folder is open. This implements the latter.

https://bugzilla.gnome.org/show_bug.cgi?id=694371
2013-05-20 18:21:16 +02:00
1dff5fb5b2 appDisplay: Expand AllView
If the view doesn't fill the available space, content should still
start at the top rather than the center - not least the positioning
code for folder popups assumes that, so set the appropriate expand
flags.

https://bugzilla.gnome.org/show_bug.cgi?id=694371
2013-05-20 18:21:16 +02:00
e2561d15b5 theme: polish the session chooser
The session chooser list has an embedded look which doesn't fit
well with the rest of the theme. Give it more of a flat appearance
and simplify the visuals.
https://bugzilla.gnome.org/show_bug.cgi?id=695742
2013-05-19 15:25:58 -04:00
326c3732b8 screenshot: Check for NULL window in screenshot_window()
screenshot_window() currently assumes a focus window, which will
result in a crash if that's not the case.

https://bugzilla.gnome.org/show_bug.cgi?id=700625
2013-05-19 15:32:56 +02:00
5dd020f2e2 recorder: Use workarea to position the recording icon
It looks a bit unpolished to overlap our own chrome with the recording
icon, which may happen when an existing adds UI at the bottom edge.
Fix this by using the primary monitor's workarea for the position rather
than the entire monitor.

https://bugzilla.gnome.org/show_bug.cgi?id=700409
2013-05-18 14:30:16 +02:00
b6edbd46b9 overview: Add focusSearch() method and export it over DBus
Some keyboard spot a dedicated search key, which gnome-settings-daemon
currently handles by spawning gnome-search-tool. It makes a lot of
sense to promote the Shell's integrated search feature instead, so
expose an appropriate DBus method g-s-d can use.

https://bugzilla.gnome.org/show_bug.cgi?id=700536
2013-05-17 18:28:47 +02:00
c330036fef Document --clutter-display in the man page
This is the sole option that was missing from the
man page.

https://bugzilla.gnome.org/show_bug.cgi?id=700339
2013-05-16 18:45:25 -04:00
d0a864b9b9 windowManager: Enable switch-to-workspace-n keybindings in overview
Those keybindings are unassigned by default, but that's not a valid
reason they shouldn't work like the related switch-up/down bindings.

https://bugzilla.gnome.org/show_bug.cgi?id=649977
2013-05-16 00:41:17 +02:00
9bed5b725e network: Fix stupid typo
There is no ACTIVE state in NetworkManager.ActionConnectionState,
it's ACTIVATED.

https://bugzilla.gnome.org/show_bug.cgi?id=700394
2013-05-15 17:48:21 +02:00
f374ecfc75 altTab: Always activate MRU window when activating an app
Commit 2499f2ed80 went back to using shell_app_activate() for
selecting an app, which favors windows on the current workspace;
this is the behavior we want for instance when activating a
launcher, but it's wrong for the alt-tab list - explicitly
request the first (e.g. MRU) window in that case.

https://bugzilla.gnome.org/show_bug.cgi?id=700356
2013-05-15 12:13:41 +02:00
dd8ca02425 PopupMenuManager: Fix child menus
Since commit c84dc6254d, popup menus are closed automatically
when another menu opens (to catch the case where a menu is opened
by keyboard shortcut, which wasn't handled before). However in the
case of child menus, both child and parent are expected to be visible,
so handle this case explicitly.

https://bugzilla.gnome.org/show_bug.cgi?id=699678
2013-05-14 19:09:09 +02:00
ff3f9bdd7d volume: Adjust to icon name changes
The headphone icon gained an audio- prefix, use that instead of
the old name.
2013-05-14 14:28:34 +02:00
fab02ae82f Bump version to 3.8.2
Update NEWS.
2013-05-14 01:33:19 +02:00
d43c5ec27a shellEntry: Set the input-purpose property for password entries
This way input methods can disable themselves automatically for
entries holding passwords.

https://bugzilla.gnome.org/show_bug.cgi?id=700043
2013-05-14 00:40:27 +02:00
f7de35b852 st-entry: add input purpose and hints
Add input-purpose and input-hints properties to StEntry,
and pass these on to StIMText.

https://bugzilla.gnome.org/show_bug.cgi?id=691392
2013-05-14 00:40:18 +02:00
cde0045851 st-im-text: add input purpose and hints
Add input-purpose and input-hints properties to StIMText,
and pass these on to GtkIMContext.

https://bugzilla.gnome.org/show_bug.cgi?id=691392
2013-05-14 00:40:15 +02:00
f844613292 st-im-text: remove undefined st_im_text_set_autoshow_im decl
https://bugzilla.gnome.org/show_bug.cgi?id=691392
2013-05-14 00:40:11 +02:00
ff2e44de53 status/keyboard: Stop destroying the IBusBus object
This is a singleton object inside libibus which means that if we
destroy it (e.g. because ibus-daemon got restarted) then, other
library users, like the ibus gtk+ IM module that we also use
in-process, will break.

https://bugzilla.gnome.org/show_bug.cgi?id=699189
2013-05-14 00:34:55 +02:00
17aa8e0488 polkitAgent: Allow retrying mistyped passwords
Don't hide the polkit agent window when someone mistypes their password.
Allow them to try again. The user can cancel at any point.

https://bugzilla.gnome.org/show_bug.cgi?id=684431
2013-05-13 20:08:34 +02:00
a33df9b046 appDisplay: Implement folder keynav and shortcuts
When opening an application folder, it should take key focus to
allow for keynav; also, Escape closing both folder and app picker
is unexpected, it should only close the popup.

https://bugzilla.gnome.org/show_bug.cgi?id=695314
2013-05-13 19:46:16 +02:00
c25f399f7c Updated Norwegian bokmål translation 2013-05-13 09:48:12 +02:00
bd47d07fbc ScreenShield: clear the lock screen early when deactivating
Upon popMode, MessageTray will try readding all notifications
to their rightful parent, so we must tell NotificationBox to
relinquish them before st_bin_set_child() fails (leaving a dangling
child pointer and crashing at the next allocation)

https://bugzilla.gnome.org/show_bug.cgi?id=698812
2013-05-12 20:20:36 +02:00
72282237e1 data: Fix typo in Screencast docs 2013-05-10 23:44:14 +02:00
dfb44aa51d Expose screencast functionality via DBus
Like screenshots, the screen recorder can be a useful tool in other cases
than being triggered by a keyboard shortcut. To account for that, export
a Screencast DBus API similar to the existing Screenshot interface.

https://bugzilla.gnome.org/show_bug.cgi?id=696247
2013-05-10 19:49:41 +02:00
5516cad087 sessionMode: Add 'allowScreencast' property
Our built-in screen recorder is implemented as a component, so it will
just be disabled when the session mode doesn't allow screencasting.
However we will expose screencasting functionality on DBus as well, and
while it makes sense to restrict its availablity to the same modes as
the existing recorder, exporting/unexporting the service depending on
the session mode is not very consumer friendly.
For that reason, add an additional 'allowScreencast' property that for now
mirrors the availability of the 'recorder' component.

https://bugzilla.gnome.org/show_bug.cgi?id=696247
2013-05-10 19:49:41 +02:00
ab60c31629 shell-recorder: Make drawing the cursor optional
As with screenshots, showing the cursor in a recording may not be
desirable, so add a property to control whether the cursor is drawn
or not.

https://bugzilla.gnome.org/show_bug.cgi?id=696247
2013-05-10 19:49:41 +02:00
52dd030087 shell-recorder: Support specifying the recorded area
Currently we will always record the entire screen. It has been requested
to support recording a specified area analogous to the screenshot API as
well, so add a set_area() method which allows this.

https://bugzilla.gnome.org/show_bug.cgi?id=696247
2013-05-10 19:49:41 +02:00
98240c2857 shell-recorder: Optionally return the filename of the recording
It is currently not always possible to predict the actual output filename
of a recording - the file-template does not necessarily use an absolute
path and may contain %d and %t escape sequences.
This is OK for fire-and-forget uses like the existing keyboard shortcut,
but we will soon expose the functionality on DBus and consumers of that
API might very well need to access the file after the recording. So do
the same as our screenshot API and add an optional (out) parameter to
record().

https://bugzilla.gnome.org/show_bug.cgi?id=696247
2013-05-10 19:49:41 +02:00
65bfd6c6d2 Don't put non-Shell windows in Ctrl+Alt+Tab if they wouldn't be visible
Metacity's Ctrl+Alt+Tab would include X11 windows
with hints like GDK_WINDOW_TYPE_HINT_DOCK and
GDK_WINDOW_TYPE_HINT_DESKTOP (there are more conditions, but that's a
good start). If we're in normal mode, those are visible and it's OK
to display those in the Ctrl+Alt+Tab order, but if we're in the lock
screen or the unlock dialog, they're not visible and it doesn't make
sense to focus them.

Bug: https://bugzilla.gnome.org/show_bug.cgi?id=699862
Signed-off-by: Simon McVittie <simon.mcvittie@collabora.co.uk>
Reviewed-by: Florian Müllner <fmuellner@gnome.org>
2013-05-09 19:31:08 +01:00
1034e33c35 modalDialog: Show spinner when working
Use the same UI concept from the login screen to show spinners when
the polkit or keyring dialogs are working

https://bugzilla.gnome.org/show_bug.cgi?id=684438
2013-05-09 06:41:07 +02:00
d7528b878c components: Allow cancelling of dialog between prompts
Some callers of the keyring prompt keep the dialog up while
processing the prompt. Allow the user to cancel the prompt
while in this state.

This is propagated to the caller, who can cancel the operation
in question when this occurs.

https://bugzilla.gnome.org/show_bug.cgi?id=682830
2013-05-09 05:55:15 +02:00
eb2e66c539 network: don't use active connections that are in invalid states
Only ACTIVE or ACTIVATING connections are important when deciding
what icon to show, don't fallback on any, possibly invalid or deactivating,
active connection object.

https://bugzilla.gnome.org/show_bug.cgi?id=676285
2013-05-09 00:05:36 +02:00
30e9a2a7d0 keyring: Fix button disabled when prompting for confirmation
https://bugzilla.gnome.org/show_bug.cgi?id=696304
2013-05-08 22:13:56 +02:00
e842694316 st-shadow: Fix offset shadow offscreen rendering
The shadows are currently rendered by painting the actor we want to
apply shadow on, in an offscreen buffer. The problem is that when this
actor has an allocation padding (ie allocation that isn't at 0x0
relatively to its parent), this padding is added within the offscreen
buffer and as a result the shadow rendering is truncated because the
offscreen buffer size is the size of the allocation box, not the
allocation box + padding.

This patch reposition the actor at 0x0 with rendering it by changing
the initial transformation matrix when rendering the actor offscreen.

https://bugzilla.gnome.org/show_bug.cgi?id=698301
2013-05-08 16:16:07 +01:00
b33d87a762 loginDialog: Adjust logoBin to modalDialog changes
With modalDialogs' backgroundStack using a BinLayout now, we need
to set approriate expand flags on the iconBin.

https://bugzilla.gnome.org/show_bug.cgi?id=699877
2013-05-08 00:09:53 +02:00
0ff3599d91 modalDialog: Replace Shell.Stack with layout manager
Commit e98eb57e3e added flags to expand the dialog's background
stack, which works fine with the current clutter-1.16 branch, but
breaks on clutter-1.14 (as shipped with GNOME 3.8).
Using an St.Widget with a Clutter.BinLayout fixes this, and is more
modern Clutter usage.

https://bugzilla.gnome.org/show_bug.cgi?id=699877
2013-05-08 00:09:53 +02:00
28d79a1235 osdWindow: Allow popup to grow if necessary
The popup currently has a fixed size based on monitor size. As a result,
the popup's content may overflow if its minimum size is larger than the
popup size. To prevent this, use min-width/min-height for the popup size
so that the popup can grow if necessary.

https://bugzilla.gnome.org/show_bug.cgi?id=696523
2013-05-07 21:35:47 +02:00
522d21154b loginDialog: Remove logo in upper left corner
With optional branding now being shown below the user list, we can
remove the unloved instance in the upper left corner ...

https://bugzilla.gnome.org/show_bug.cgi?id=694912
2013-05-07 20:52:04 +02:00
7c231916c1 loginDialog: (Optionally) show logo below user list
The optional logo on the login screen is currently shown in the
top bar, which is not only a rather unprominent position, it also
gives the wrong suggestion of a clickable element.
Newer designs call for the logo to be shown horizontally centered
at the bottom of the screen, so implement that instead.

https://bugzilla.gnome.org/show_bug.cgi?id=694912
2013-05-07 20:52:04 +02:00
a40bb67fc6 modalDialog: Always use a stack for the background
Currently a system modal dialog's actor hierarchy depends on whether
events should be blocked while the dialog is shown or not. Change
it to always contain a stack, to allow subclasses to add additional
background elements.

https://bugzilla.gnome.org/show_bug.cgi?id=694912
2013-05-07 20:52:04 +02:00
4c350b90c7 dateMenu: do not show "Open Calendar" button with no installed calendar application
https://bugzilla.gnome.org/show_bug.cgi?id=697725
2013-05-06 15:59:17 +01:00
47dee22b05 gdm: Fix regression where domain login hint not shown
Also only keep around realmd while we're actually using it, allow it
to quit if no other clients are active.

https://bugzilla.gnome.org/show_bug.cgi?id=698200
2013-05-03 21:55:45 +02:00
13c0e575f6 ctrlAltTab: Use a symbolic icon for desktop windows
The nautilus icon sticks out pretty badly among the symbolic
icons we use for other desktop components. This commit finds
windows of type DESKTOP, and uses the video-display-symbolic
icon for them.
https://bugzilla.gnome.org/show_bug.cgi?id=697914
2013-05-03 10:27:01 -04:00
ea8736b13a AppMenuButton: Improve handling of signals
If for some reason an extension needs to destroy the AppMenu object,
currently it is not possible to do this cleanly due to these signals
remaining connected.

https://bugzilla.gnome.org/show_bug.cgi?id=698531
2013-05-01 18:33:31 +10:00
303d53e7f5 StIcon: use g_signal_connect_object() for safety
Prevent a crash in case an icon is destroyed before the texture
finishes loading, and something else is keeping the texture alive
for any reason.

https://bugzilla.gnome.org/show_bug.cgi?id=696720
2013-04-29 00:26:51 +02:00
31295dfe83 Updated Lithuanian translation 2013-04-28 13:36:38 +03:00
69ea4553cb dateMenu: append .desktop to evolution strings
Since that is what the actual app_id's are.
2013-04-27 08:32:23 +10:00
0d8d77356e PopupMenuManager: Close active menu when another one opens
We already do this when navigating between menus via mouse or
keynav, but miss cases where a menu is opened by other means,
for instance via a keyboard shortcut.

https://bugzilla.gnome.org/show_bug.cgi?id=686756
2013-04-26 18:16:14 +02:00
8b78032248 panel: Change openAppMenu() to a toggle action
It makes sense to allow closing the app menu with the same shortcut
that is used to open it, so make it a toggle action and allow it
TOPBAR_POPUP mode.

https://bugzilla.gnome.org/show_bug.cgi?id=686756
2013-04-26 18:16:13 +02:00
ad277a563c panel: Add keybinding mode for top bar popups and use it
Allow some keybindings to still work while a top bar menu is open
by assigning it a keybinding mode.

https://bugzilla.gnome.org/show_bug.cgi?id=698938
2013-04-26 18:16:13 +02:00
db26fb201e popupMenu: Allow setting grabHelper params for PopupMenuManager
Currently all keybindings are disabled while some popup menu is open.
However some keybindings may still be useful in some cases, so expose
GrabHelper's modal params parameter to allow specifying a keybinding
mode for particular menus.

https://bugzilla.gnome.org/show_bug.cgi?id=698938
2013-04-26 18:16:13 +02:00
9f00be50d6 shellDBus: Fix Eval() return value when disabled
Eval() is expected to return a boolean success value and a string result.
However when the function is disabled (via the development-tools setting),
we return null for the latter which is not a valid string value.
Return an empty string instead.

https://bugzilla.gnome.org/show_bug.cgi?id=698959
2013-04-26 18:16:12 +02:00
77d21e53d0 backgroundMenu: Ignore releases when using long-press
Otherwise, a release from the long-press will be seen as a
button event that should close the menu.

https://bugzilla.gnome.org/show_bug.cgi?id=697203
2013-04-26 11:24:30 -04:00
ba0b4ba590 layout: Correct hot corner barriers in RTL layouts
https://bugzilla.gnome.org/show_bug.cgi?id=698884
2013-04-26 11:24:25 -04:00
b9fc7a3050 [l10n] Add Interlingua translation 2013-04-24 15:52:53 +02:00
aa053a906d [l10n] Updated Turkish translation 2013-04-20 00:48:22 +03:00
2cda0472bd Bump version to 3.8.1
Update NEWS.
2013-04-16 21:25:54 +02:00
4710753700 panel: Pick up spinner icon from CSS
In order to use a different spinner image in classic mode (or any
other mode specific style), get it from CSS rather than hardcoding
a particular image.

https://bugzilla.gnome.org/show_bug.cgi?id=693688
2013-04-16 19:10:40 +02:00
2b439ef209 theme-node: Add lookup_url/get_url() methods
Similar to the existing generic getter methods, add lookup functions
for URL properties like the standard background-image/border-image
properties.

https://bugzilla.gnome.org/show_bug.cgi?id=693688
2013-04-16 19:10:40 +02:00
2fc76e6d9e panel: Pass a full pathname to AnimatedIcon
For classic mode, we want to use a different styling for the spinner,
so we will pick up the image filename from CSS to make use of mode
specific styling. As the CSS will give us a full pathname, adapt the
API to take a full pathname instead of building it inside AnimatedIcon
from the passed basename.

https://bugzilla.gnome.org/show_bug.cgi?id=693688
2013-04-16 19:10:40 +02:00
ff544450a5 Revert "classic: Invert the spinner color"
This reverts commit f358bb1a96.
2013-04-15 18:40:00 -04:00
b4590da686 Revert "Add an OSD for sticky modifiers"
This reverts commit 96994721ef.
2013-04-15 18:39:52 -04:00
6c4be0311a Revert "Make it possible to always show the a11y status"
This reverts commit 6ce79c62eb.
2013-04-15 18:39:44 -04:00
4a2cdc20f0 Add networkAgent to initial-setup mode
We want to be able to set up e.g. a WEP connection on the
network page of gnome-initial-setup, so we need a network
agent in the session.
2013-04-15 18:05:57 -04:00
6ce79c62eb Make it possible to always show the a11y status
A switch for this is part of the redesign for the universal
access control-center panel.

https://bugzilla.gnome.org/show_bug.cgi?id=698001
2013-04-15 17:48:47 -04:00
96994721ef Add an OSD for sticky modifiers
This commit adds an OSD that displays which modifiers are
currently latched or locked. This is commonly used together
with sticky keys.
https://bugzilla.gnome.org/show_bug.cgi?id=647711
2013-04-15 17:48:47 -04:00
f358bb1a96 classic: Invert the spinner color
https://bugzilla.gnome.org/show_bug.cgi?id=693688
2013-04-15 17:48:47 -04:00
1bce210c51 messageTray: Don't show the context-menu when the tray isn't open
https://bugzilla.gnome.org/show_bug.cgi?id=697709
2013-04-15 12:49:30 -04:00
8a3c8d1b1c Add a note to POTFILES.in about the gvc submodule 2013-04-14 21:59:03 +02:00
08b224de1f Updated Vietnamese translation 2013-04-13 17:53:05 +10:00
86c92c37d2 st-im-text: Override ClutterText's cursor_event to set cursor position
This is both more efficient and accurate than doing it from the paint
vfunc.

https://bugzilla.gnome.org/show_bug.cgi?id=697722
2013-04-10 17:27:28 +02:00
07053c3df7 shellEntry: Remove close method
GrabHelper already takes care of putting the key focus back on the
widget that had it when the grab was established.

ShellEntry's close() has recently become harmful since it's now called
from the menu's destroy() method and that is called in the entry's
destroy handler which means that this._entry might no longer be valid
at close() time.

https://bugzilla.gnome.org/show_bug.cgi?id=697560
2013-04-08 21:02:03 +02:00
4fb33c9b09 dnd: Set the position and scale on the drag actor before it's reparented
We need to do this to ensure that it gets the correct scale, as otherwise
the transform that we retrieve will be incorrect.

https://bugzilla.gnome.org/show_bug.cgi?id=697504
2013-04-08 14:57:49 -04:00
5e6a25c3c2 dnd: Set the scale on the drag actor
The actor is the same as the drag actor in this case, but we tend to
set properties on the drag actor and get them from the actor elsewhere
in this codepath. Make this consistent.

https://bugzilla.gnome.org/show_bug.cgi?id=697504
2013-04-08 14:57:49 -04:00
e14ef4a294 theme: remove excessive padding from notification buttons
Set the button width manually and remove the huge horizontal
padding we had. This means that long button labels don't get cut
off.

https://bugzilla.gnome.org/show_bug.cgi?id=664411
2013-04-08 19:25:46 +02:00
8b659f0f4c St: support -st-natural-width/height CSS properties
It is sometimes desirable to specify the size of a box from CSS without
changing the minimum-width too.
This property implements that.

https://bugzilla.gnome.org/show_bug.cgi?id=664411
2013-04-08 19:25:45 +02:00
a6395c95d4 Small fix in Serbian translation 2013-04-08 15:29:57 +02:00
98e74dfd38 screenshield: Remove box-shadow
This causes very low performance in some situations (like multiscreen). Proper
fixes are too invasive at this point (3.8.1) so lets just remove the shadow
for now and add it back later once he have fixed it.

https://bugzilla.gnome.org/show_bug.cgi?id=697274
2013-04-07 22:06:46 +02:00
1d728186db recorder: Enable the keybinding for all modes
There's not really a good reason to restrict the screen recorder
to normal mode and overview, so allow it for all keybinding modes.

https://bugzilla.gnome.org/show_bug.cgi?id=696200
2013-04-07 21:13:30 +02:00
2499f2ed80 AppSwitcherPopup: Activate only the selected window if any
If there's an explicitly selected window thumbnail we should bring up
only that particular window instead of all the application's windows.

https://bugzilla.gnome.org/show_bug.cgi?id=697480
2013-04-07 21:05:38 +02:00
963905adcd runDialog: don't destroy on close
It's a singleton like the endSessionDialog

https://bugzilla.gnome.org/show_bug.cgi?id=697435
2013-04-06 11:10:30 -04:00
7c21ab0985 Revert "Revert "modalDialog: Destroy dialogs on close""
This reverts commit 007820b7c1.

(I only meant to revert that in my local branch)
2013-04-06 10:53:11 -04:00
77d3712261 popupMenu: close menu on destroy
This fixes a crash if a background menu is open
and the background changes.

https://bugzilla.gnome.org/show_bug.cgi?id=697432
2013-04-06 10:47:16 -04:00
0376f22d41 background: stop monitoring file after removing from cache
https://bugzilla.gnome.org/show_bug.cgi?id=697395
2013-04-06 10:45:53 -04:00
007820b7c1 Revert "modalDialog: Destroy dialogs on close"
This reverts commit 3dd6113a0a.
2013-04-06 10:28:47 -04:00
dc98711477 backgroundMenu: drop cursor object with rest of menu actors
https://bugzilla.gnome.org/show_bug.cgi?id=697395
2013-04-06 09:45:45 -04:00
e98c6ff31b background: when updating image remove old one from cache
We're removing the new content from the cache instead of the
old content.

This commit fixes that.

https://bugzilla.gnome.org/show_bug.cgi?id=697395
2013-04-06 09:44:51 -04:00
9eae74357a background: don't leak background objects during quick changes
We currently let some backgrounds "fall through the cracks" if
a bunch of change notifications come in at once.

This commit fixes that.

https://bugzilla.gnome.org/show_bug.cgi?id=697395
2013-04-06 09:44:50 -04:00
1ee88a2878 screenShield: Ensure we destroy background container widgets
We may accidentally leak a widget when monitors change while
locked otherwise. This is especially bad because we put a
box-shadow on this widget.

https://bugzilla.gnome.org/show_bug.cgi?id=697300
2013-04-04 19:16:49 -04:00
14189e6827 shellEntry: Destroy entry menus when the entry actors are destroyed
This ensures that a menu and manager aren't sticking around.

https://bugzilla.gnome.org/show_bug.cgi?id=697295
2013-04-04 15:04:14 -04:00
3dd6113a0a modalDialog: Destroy dialogs on close
It turns out that we never destroyed modal dialogs when closing
them, causing them to still linger in the scene graph even when
there were no references to them in the JS. The one case where
we don't want to destroy modal dialogs after being closed is
endSessionDialog, so provide a parameter that allows classes
to override this behavior.

https://bugzilla.gnome.org/show_bug.cgi?id=697295
2013-04-04 15:04:14 -04:00
ae5cdea5af Updated Norwegian bokmål translation 2013-04-03 13:31:44 +02:00
3c1f389e25 backgroundMenu: destroy menu when actor is destroyed
This fixes a leak.

https://bugzilla.gnome.org/show_bug.cgi?id=697119
2013-04-02 23:20:15 -04:00
284d821233 Updated Basque language 2013-04-02 21:59:27 +02:00
78272e5592 RemoteSearch: don't sort the last explicitly sorted provider last
It's a confusing semantic, and keeping it causes bugs in the control
center panels.

https://bugzilla.gnome.org/show_bug.cgi?id=694974
2013-04-02 21:49:57 +02:00
098bc41083 Updated Polish translation 2013-04-02 15:58:59 +02:00
c837090282 Update Simplified Chinese translation 2013-04-02 00:55:01 +08:00
cdc1678e6f Updated Belarusian translation. 2013-04-01 15:22:56 +03:00
2a3d76b0cc Update Arabic translation 2013-03-31 23:08:29 +02:00
29e89491de Updated British English translation 2013-03-29 16:07:45 +00:00
d63947aec4 Silly typo in calendar.js
https://bugzilla.gnome.org/show_bug.cgi?id=696436
2013-03-29 16:15:19 +01:00
512f0a67fb shellDBus: Fix SetActive(false) for ScreenSaver DBus API
Someone changed .unlock() to deactivate() for the obvious symmetry
with activate(), but forgot to update it here.

https://bugzilla.gnome.org/show_bug.cgi?id=696585
2013-03-29 10:13:24 -04:00
a7cd4657f5 loginManager.js: Check for logind, not for systemd
It is possible to build systemd without logind, in which case
/sys/fs/cgroup/systemd would still exist. Check for /run/systemd/seats instead,
as recommended by systemd upstream.

For details, see:
<https://mail.gnome.org/archives/desktop-devel-list/2013-March/msg00092.html>

https://bugzilla.gnome.org/show_bug.cgi?id=696252
2013-03-29 11:00:52 +01:00
bf02cde598 altTab: Move input focus to target window before dropping the grab
We chain up on _finish() to drop the grab and destroy the switcher
popup but we should activate the target window first because dropping
the grab results in the previously focused windows getting a focus in
event immediately followed by the focus out event from the target
window activation which we can easily avoid.

https://bugzilla.gnome.org/show_bug.cgi?id=696259
2013-03-28 16:17:07 +01:00
b7dbb35546 Updated Aragonese translation 2013-03-28 11:11:10 +01:00
6fd5f0e3de popupMenu: Fix another child popup regression
When switching menus, we need to make sure we close all existing
grabs, not just the first one.

https://bugzilla.gnome.org/show_bug.cgi?id=695859
2013-03-27 16:32:42 -04:00
e6469df065 popupMenu: Fix a missed rename
this._activeMenu was changed to this.activeMenu, but this wasn't
updated by accident.

https://bugzilla.gnome.org/show_bug.cgi?id=695859
2013-03-27 16:32:42 -04:00
d61fe357f6 layout: Clip the window group when doing the startup animation
This ensures that when we have windows that are already visible,
like desktop icons, they don't fly across the screen from what
seems to be hyperspace to get into view.

https://bugzilla.gnome.org/show_bug.cgi?id=696323
2013-03-27 16:30:00 -04:00
965dd2ab67 Bump version to 3.8.0.1
Update NEWS.
2013-03-27 12:28:56 -04:00
78e011d558 background: fix multimonitor background placement in overview
This is like the previous commit but for monitor index, instead
of effects.

https://bugzilla.gnome.org/show_bug.cgi?id=696712
2013-03-27 12:13:47 -04:00
76590d6c69 background: fix vignette in overview
We no longer apply background effects when loading backgrounds.

This commit fixes that.

https://bugzilla.gnome.org/show_bug.cgi?id=696712
2013-03-27 12:09:02 -04:00
16dc6ce41a Bump version to 3.8.0
Update NEWS.
2013-03-26 22:29:57 +01:00
1dadcee5c9 background: don't choke on huge slide show durations
if a slideshow file has a really large duration we'll currently
throw an exception.

This bug is aggravated by the fact that some versions of
gnome-desktop use UINT_MAX as a sentinel value to mean,
"don't ever update slide".

This commit treats durations that would overflow as infinitely
long.

https://bugzilla.gnome.org/show_bug.cgi?id=696157
2013-03-26 17:02:05 -04:00
bed3bb45f7 background: don't load the same image more than once concurrently
If a background gets requested from the cache while it's still
being loaded from an earlier call, then there will be two concurrent
loads of the same file.

That concurrency is mitigates the effectiveness of the cache and
also causes leaks.

This commit consolidates file loads so that concurrency doesn't
happen.

https://bugzilla.gnome.org/show_bug.cgi?id=696157
2013-03-26 17:02:05 -04:00
18d850d7d6 workspaceThumbnail: always destroy bgManager when destroyed
Right now we only destroy the bgManager object when the
workspaceThumbnail is explicitly destroy with its destroy()
method.

This commit makes sure bgManager gets destroyed when the
workspaceThumbnail actor is destroyed without calling
destroy().

https://bugzilla.gnome.org/show_bug.cgi?id=696157
2013-03-26 17:02:05 -04:00
f920fd8b6f background: properly disconnect background signals
BackgroundManager connects to the changed signal in
the backgrounds it manages.

The signal ids for the changed signal connectionss are stored
as state on the background manager object.

If the background being managed changes while the manager
is still loading the old background, then the signal id
variable can get out of sync with the background object being
managed.

This commit ties the signal id to the background objects themselves,
so there is no opportunity for them to desynchronize.

https://bugzilla.gnome.org/show_bug.cgi?id=696157
2013-03-26 17:02:05 -04:00
b9da6d9ef6 background: When updating actor content, evict old content from cache
Normally backgrounds get evicted from the cache when their actor is
destroyed.  If the actor changes content without destroying itself,
though, we should evict the old content from the cache, too.

https://bugzilla.gnome.org/show_bug.cgi?id=696157
2013-03-26 17:02:04 -04:00
3be489c69e background: always add content to cache
We currently only add the first instance of a background
to the cache.  This means if the actor associated with that
background is destroyed, the content will be evicted and
it will need to get reloaded, even if it's already loaded
on another actor.

This commit ensures every content gets added to the cache.

https://bugzilla.gnome.org/show_bug.cgi?id=696157
2013-03-26 17:02:04 -04:00
cab092aad7 Updated Telugu Translation 2013-03-26 18:53:24 +05:30
0451cba343 Updated LT translation 2013-03-26 12:40:32 +01:00
12334cd9ad Updated Odia Language along with FUEL implementation 2013-03-26 16:09:27 +05:30
9d18a2dff4 screenShield: Go back to a shorter animation when locking manually
Increasing it was mostly to paper over animation jerkiness which
shouldn't be a problem anymore since we removed the desaturate and
blur effects.

https://bugzilla.gnome.org/show_bug.cgi?id=696380
2013-03-26 09:27:24 +01:00
869e1dc241 loginManager: listen to the correct object path
Use GetSession() to get the valid object path for the current
XDG_SESSION_ID.

https://bugzilla.gnome.org/show_bug.cgi?id=696287
2013-03-25 20:53:13 -04:00
b878f3fc4a Restore visibility of windows in initial-setup mode
gnome-initial-setup runs a regular X window, so we need to show it.

https://bugzilla.gnome.org/show_bug.cgi?id=696235
2013-03-25 18:22:48 -04:00
2aeabcc38b Updated Telugu Translations 2013-03-25 21:53:19 +05:30
94778c0dac layout: Fix opening the overview for xdnd
In the (no barriers) fallback case handleDragOver has somehow
ended up being turned into a nop and thus breaking xdnd
overview opening.

Fix that by calling _toggleOverview() when a xdnd source triggers
it.

https://bugzilla.gnome.org/show_bug.cgi?id=696447
2013-03-25 14:43:22 +01:00
390491b37a dateMenu: Re-add special-casing of evolution-calendar
When commit 724a2bd7 changed the way to determine the default
calendar app, it dropped all special handling of evolution.
Unfortunately we still need it to not end up with the default
mail component, so add it back.

https://bugzilla.gnome.org/show_bug.cgi?id=696432
2013-03-25 10:43:30 +01:00
f8ea825577 grabHelper: Consider events that release the grab handled
Currently, if a button-press event results in releasing the last modal
grab (e.g. clicks outside the grabbed actors), we don't consider the
event handled and allow its emission to continue. If we consider
dismissing a grab as an action of its own, any additional action
triggered by the same event becomes an unexpected side effect.
Tweak the capture handler accordingly.

https://bugzilla.gnome.org/show_bug.cgi?id=696422
2013-03-25 10:43:29 +01:00
f77ad7d184 Completed for Malayalam 2013-03-25 14:58:55 +05:30
e467a53def Uploaded Ukranian 2013-03-25 08:00:49 +02:00
9cd2e12915 l10n: Update Japanese translation 2013-03-25 12:10:39 +09:00
627a6587b4 Update Danish translation 2013-03-24 14:57:24 +01:00
9b3b419f7a initial-setup: Add battery icon
There is no reason why there shouldn't be a battery icon in initial-setup,
knowing how much battery you have left is useful in during setup as well.

This also fixes an exception in the lock screen caused by the combined icon
not finding the battery one.

https://bugzilla.gnome.org/show_bug.cgi?id=696212
2013-03-24 09:39:34 +01:00
f37ed44837 Updated Dutch translation 2013-03-23 23:35:30 +01:00
dddc333407 Updated Belarusian translation. 2013-03-23 23:04:07 +03:00
75714fb784 Added slovak translation 2013-03-23 21:01:35 +01:00
5a6342a5fe Updated kn translations 2013-03-23 19:00:18 +05:30
e07379b406 Revert "Remove non-existing file to make intltool happy"
This reverts commit 54bfe34273.

see 8f1df14ae7
-> It very much exists. Do a 'git submodule init && git submodule update'.
2013-03-23 13:35:47 +01:00
54bfe34273 Remove non-existing file to make intltool happy 2013-03-23 12:49:36 +01:00
bef876e4b4 Updated kn translations 2013-03-23 14:44:25 +05:30
6ef9ab6a0b st-scroll-view-fade: Don't fade out gradient
The changes from commit b4f5f1e461 and b394d184cc increased the
instructions required for the fade fragment shader. This is over the limit
for some hardware (like intel gen3), which causes the driver to fallback
to software rendering for the shader. The result is that painting a scrollview
that has a fade effect takes around 30 (!!) seconds.

So lets go back to the old effect for 3.8 until we find a solution.

https://bugzilla.gnome.org/show_bug.cgi?id=696404
2013-03-22 19:56:13 +01:00
53ffdd8d68 Updated Russian translation 2013-03-22 21:03:27 +04:00
ba198034cb screenShield: Remove blur and desaturation from lock screen
There's large performance issues with both the blur and desaturation
that make the screen shield hard to use on slower computers, and this
has always been a temporary stopgap until the user can pick a different
image for the lock screen.

https://bugzilla.gnome.org/show_bug.cgi?id=696322
2013-03-22 12:36:43 -04:00
58e66b9e1b autorunManager: Mark the Removable Devices source as resident
This ensures that it can't be removed when we clear the message
tray.

https://bugzilla.gnome.org/show_bug.cgi?id=696199
2013-03-22 12:36:43 -04:00
ac7efcb43a hindi translation 2013-03-22 18:00:09 +05:30
b514b9ec7c Tamil Translations Updated 2013-03-22 17:23:06 +05:30
f69942eb35 Updated Odia Translation. 2013-03-21 18:18:27 +05:30
f28827f625 Updated Marathi Translations 2013-03-21 09:27:22 +05:30
f20a6b3635 Updated Hungarian translation 2013-03-20 16:40:57 +01:00
7f7ff3ce3e L10N: Updated Persian Translation 2013-03-20 09:22:41 +03:30
0abb0756ba [l10n] Added Tadjik translation 2013-03-19 20:43:49 +01:00
070ed9396c Update French translation 2013-03-19 11:43:32 +01:00
307004a455 Bump version to 3.7.92
Update NEWS.
2013-03-19 00:12:27 +01:00
d097327bd8 loginDialog,unlockDialog: Give user time to read messages
Right now, if multiple messages come in, they just sort of
clobber each other.

This commit sets up a message queue, and introduces pauses
long enough for the user to hopefully be able to read those
messages.

https://bugzilla.gnome.org/show_bug.cgi?id=694688
2013-03-18 19:01:30 -04:00
f72f501931 unlockDialog: ignore resets after success
GDM sends a reset signal after verification succeeds
so that a user-switched login screen can prepare for
the next time it's going to be used.

The unlock screen treats resets as failures, though.
This means, on success, we're emitting "failed" and
clearing any last second messages.

This commit changes the unlock code to ignore resets from
GDM after successful verification.

https://bugzilla.gnome.org/show_bug.cgi?id=694688
2013-03-18 19:01:30 -04:00
e9584cfcab gdm: don't clear user-verifier on reset automatically
Right, the common code between the login screen and
the unlock screen handles clearing the user verifier
when GDM sends a reset.

We don't actually always want to clear the messages on
reset in the unlock case, though, so doing it implicitly
is problematic.

This commit moves the clear() call from the common code
to the specific reset handlers.

https://bugzilla.gnome.org/show_bug.cgi?id=694688
2013-03-18 19:01:30 -04:00
aec0e75d73 grabHelper: Ensure we reset ignoreRelease when we drop our event handler
Since we drop our event handler, we won't see ever the release event
from the button press, so unset the flag so it doesn't muck with the
next time somebody takes a grab.

https://bugzilla.gnome.org/show_bug.cgi?id=696102
2013-03-18 16:49:12 -04:00
a6b4d49454 Use Mutter fullscreen window tracking for hiding chrome and auto-minimize
Getting fullscreen window tracking right in GNOME Shell turned out to
be very hard, because it depended on details both how Mutter handled
fullscreen windows and the exact timing of that. Fullscreen tracking
and auto-minimization of fullscreen windows that lose their fullscreen
status has thus been implemented in Mutter: use that.

https://bugzilla.gnome.org/show_bug.cgi?id=649748
2013-03-18 14:44:10 -04:00
1cc726593e runDialog: Ignore expected IO errors while enumerating $PATH
$PATH might contain non-existent or non-directory entries. Ignore
those error cases.

https://bugzilla.gnome.org/show_bug.cgi?id=696064
2013-03-18 18:00:12 +01:00
5001bd8810 Don't use ClutterX11TexturePixmap directly to embed docked windows
Previously when a client requests that a window should be docked the
shell would reparent the socket window onto the stage's window and
then use ClutterX11TexturePixmap to get a texture to represent the
window. This will not work if Clutter is no longer using the X11
winsys for example if it becomes its own display server. Instead this
patch leaves the socket window as a child of the root window and lets
mutter create a MetaWindow out of it. If Mutter is acting as a display
server then this mechanism will still work via the headless x server.

The ShellGtkEmbed instance now registers for notification of the
‘window-created’ signal of the display so that it can find the
MetaWindow that gets created to represent the socket window. When this
window is found it is prevented from being displayed on the screen by
setting the actor's opacity to 0. An input shape is then set on the
window to prevent it receiving any input.

Instead of being a subclass of ClutterX11TexturePixmap, ShellGtkEmbed
is now a subclass of ClutterClone. When the MetaWindow is found for
the socket window the clone's source is set to the invisible actor for
the window so it can be displayed in the panel as before.

The ShellEmbeddedWindow no longer needs to know what the stage is
because it no longer reparents the socket window. Therefore the
ShellTrayManager doesn't need to know the stage either so
shell_tray_manager_manage_stage has been replaced with just
shell_tray_manager_manage_screen.

https://bugzilla.gnome.org/show_bug.cgi?id=693438
2013-03-18 16:49:47 +00:00
46aa70aa09 searchDisplay: Add an accessible name to the provider icon
https://bugzilla.gnome.org/show_bug.cgi?id=696007
2013-03-18 12:12:40 -04:00
41cf447c45 searchDisplay: Label search result actors for accessibility
https://bugzilla.gnome.org/show_bug.cgi?id=696007
2013-03-18 12:12:40 -04:00
b328fd7aed layout: Move window_group visibility to the layout
This ensures that windows are hidden in the screen shield and in gdm.

https://bugzilla.gnome.org/show_bug.cgi?id=695747
2013-03-18 03:57:36 -04:00
917a24580b Updated gujarati file 2013-03-18 12:33:14 +05:30
af36182879 [l10n] Updated Catalan (Valencian) translation 2013-03-17 19:52:19 +01:00
160c721afc Revert "WorkspacesView: set the clip when setting the geometry"
This reverts commit d3ab367fcd.
Pushed by mistake.
2013-03-17 19:39:58 +01:00
ee0040ef1c WorkspaceThumbnails: animate the right workspace when creating by DND
To create a new workspace by dropping on the placeholder, we move all
the windows down one workspace and then wait for _checkWorkspaces() to
automatically create the empty one at the end.
This means that, from the implementation POV, the new workspace is not
the one created by DND but it's the last one, and this detail was exposed
in the UI because the animation was applied on that one.
Fix that by starting the animation manually from the DND code, and then
blocking the animation from happening when the new workspace is created
with a flag.

https://bugzilla.gnome.org/show_bug.cgi?id=685285
2013-03-17 19:35:15 +01:00
9e60a55dd7 WorkspacesView: don't fail when doing window DND from the last workspace
DND of windows has a lot of side effects, including the possibility of
current workspace disappering from under our feet. We need to account
for that when trying to activate it.

https://bugzilla.gnome.org/show_bug.cgi?id=685285
2013-03-17 19:35:14 +01:00
57f27572ae DND: don't cancel a drag if the actor is destroyed inside acceptDrop
This happens in the case of Workspace/WorkspaceThumbnail: they call
meta_window_change_workspace_by_index(), which fires window-removed
on the old workspace, thus destroying the window clone.

https://bugzilla.gnome.org/show_bug.cgi?id=685285
2013-03-17 19:26:13 +01:00
ceae032112 Workspace/WorkspaceThumbnail: fix Clutter warnings from stacking code
Windows can be restacked at any time, including when the stackAbove
property of the window clone is being dragged, and thus parented to
the uiGroup. To do stacking properly, we need to skip it for the duration
of the drag, and sync it again at the end (which is already done by
mutter because of the workspace change)

https://bugzilla.gnome.org/show_bug.cgi?id=685285
2013-03-17 19:26:13 +01:00
d3ab367fcd WorkspacesView: set the clip when setting the geometry
Fixes clipping the windows when you open the overview with the workspace
switcher expanded and then shrink it.

https://bugzilla.gnome.org/show_bug.cgi?id=694092
2013-03-17 19:26:12 +01:00
0ceefb48c8 Workspace: don't place new windows at random locations
Instead, have them grow from the center of their assigned slots.

https://bugzilla.gnome.org/show_bug.cgi?id=695582
2013-03-17 19:26:09 +01:00
a9815ae1e9 ScreenShield: don't animate arrows if the user is idle
If the user is idle, it is very likely the monitor is off too, so let's
save some power by avoiding animations noone is going to see.

https://bugzilla.gnome.org/show_bug.cgi?id=690857
2013-03-17 19:20:43 +01:00
79140fd132 Updated Belarusian translation. 2013-03-17 16:00:14 +03:00
6c0f48ce25 layout: Only emit fullscreen-changed if things actually changed
This prevents the message tray from doing a lot of work that
it doesn't need to.
2013-03-16 16:50:30 -04:00
da7ab7057d Updated Korean translation 2013-03-16 23:59:08 +09:00
499ae609dd appDisplay: Use a custom LayoutManager for the AllView stack
ClutterBinLayout uses the maximum width/height of all children in
size requests and positions children according to the expand/align
properties. This means that the vertical position of folder popups
is not considered in size requests, so if the main view is smaller
than a folder popup's height and offset, the popup will be truncated
and/or mispositioned. Fix those cases by using a custom LayoutManager
that behaves like ClutterFixedLayout for height requests and like
ClutterBinLayout otherwise.

https://bugzilla.gnome.org/show_bug.cgi?id=694371
2013-03-15 22:41:54 +01:00
e78b3644e4 login-dialog: Increase top/bottom padding
The login dialog has a maximum height set to prevent the user list
from growing indefinitively. However this approach fails if the
monitor height is smaller as said maximum, so add some additional
top/bottom padding to make sure there's some whitespace above/below
the user list in that case as well.

https://bugzilla.gnome.org/show_bug.cgi?id=685851
2013-03-15 19:35:18 +01:00
ce6b39bd1c Revert "doap: add myself to doap file"
I just added myself temporarily to work around
mango.

This reverts commit ec8dfb0cad.
2013-03-15 14:02:31 -04:00
603f528b47 theme: Adjust border-radius for focus indication to match hover
Commit 7b3a689aad changed the border-radius of the hover effect
to match the prelight effect, but not the focus indication, so
the focused item now changes corners on hover. Fix this by using
a consistent border-radius.

https://bugzilla.gnome.org/show_bug.cgi?id=691578
2013-03-15 00:04:03 +01:00
5fecd07045 background: Look at the duration per-step
We need to look at the duration of the current step of the slideshow
to determine when to next queue an event, rather than the full slideshow
duration.

https://bugzilla.gnome.org/show_bug.cgi?id=695882
2013-03-14 17:48:07 -04:00
8edd7ad32e background: Fix a bug with empty animations
Arrays always evaluate to true, even empty arrays,
so we need to check the length to make sure we have
no files.

https://bugzilla.gnome.org/show_bug.cgi?id=695882
2013-03-14 17:48:07 -04:00
3a27d0b849 background: Keep the state of key frame files on Animation
This gets us from a mix of pure getters and class state
to just class state.

https://bugzilla.gnome.org/show_bug.cgi?id=695882
2013-03-14 17:48:07 -04:00
b351536dee background: Rename animationUpdate to updateAnimation
This is more consistent.

https://bugzilla.gnome.org/show_bug.cgi?id=695882
2013-03-14 17:48:07 -04:00
eeea8559b6 background: Fix math to calculate the interval from the duration
The math here before was incorrect. This is still wrong, as we're
looking at the total duration of the animation rather than the next
step.

https://bugzilla.gnome.org/show_bug.cgi?id=695882
2013-03-14 17:48:07 -04:00
17591117c1 background: Fix updating existing images that need loading
Due to weird and strange JS scoping semantics, if we are in a
callback, "i" won't be captured and when the callback is called,
we'll have the wrong index, causing addImage to be called instead
of updateImage.

https://bugzilla.gnome.org/show_bug.cgi?id=695882
2013-03-14 17:48:07 -04:00
c4470fd1e6 background: Set the correct index on images
The pattern is underneath, so we need to add one. It turns out
that ClutterGroup doesn't care about that, but we need to do this
to remove deprecations in mutter.

https://bugzilla.gnome.org/show_bug.cgi?id=695882
2013-03-14 17:48:07 -04:00
45fc7ec01f st-scroll-view-fade: Don't use return in the shader
Returing from main() makes llvmpipe unhappy (produces black output color),
so rework the logic to avoid the return.

https://bugzilla.gnome.org/show_bug.cgi?id=695607
2013-03-14 22:43:14 +01:00
dc54472ca5 messageTray: Remove some dead positioning code
We don't modify the tray box's anchor position, so this shouldn't
ever get called.

https://bugzilla.gnome.org/show_bug.cgi?id=695800
2013-03-14 17:18:20 -04:00
4b3bf05aaf screenShield: Only release logind inhibitor on suspend
To make sure that the screen shield is shown before suspending, we
take a logind inhibitor and release it when the screen shield is
shown. As the screen shield is not only shown on suspend, we can end
up releasing the inhibitor independently from suspending (lock, idle),
in which case the screen might not be locked when we do suspend.
To fix, only release the inhibitor after showing the screen shield
when we are about to suspend.

https://bugzilla.gnome.org/show_bug.cgi?id=693708
2013-03-14 19:09:15 +01:00
ec014a7ecf main: Do not export DBus interfaces before initializing the UI
Since commit 7cdb75e7ce, initializing UI is deferred until the session
mode has been loaded. However DBus is still initialized immediately,
which means that for DBus methods that access properties in Main, there
is now a window between the method being exposed on the bus and the
method being ready to be called. At least g-s-d grabbing global keybindings
is likely to fall in this window on session startup, and almost guaranteed
when regrabbing bindings after a shell restart.
To fix, defer initializing DBus as well.

https://bugzilla.gnome.org/show_bug.cgi?id=694321
2013-03-14 17:28:31 +01:00
a8c87f3bab overview: Only keep ourselves in the overview on button events
This prevents using Control to quickly launch a new instance of
an app in search results or with keyboard navigation.

https://bugzilla.gnome.org/show_bug.cgi?id=695801
2013-03-14 12:05:42 -04:00
b39e76200a overview: Don't use a captured-event handler to detect the control key
captured-event handlers are easily messed up by an earlier event
handler capturing the event. Instead, use the current Clutter event
and check for the state of that.

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

https://bugzilla.gnome.org/show_bug.cgi?id=695801
2013-03-14 12:05:42 -04:00
01deb9ef7d status/keyboard: Check if this._currentSource is valid on activation
this._currentSource might be invalid so check for that to prevent an
exception and still switch to the newly activated source.

https://bugzilla.gnome.org/show_bug.cgi?id=695841
2013-03-14 14:56:28 +01:00
5c89568cca status/keyboard: Always hide the old source panel indicator label
When we switch into an invalid input source we hide the panel
indicator and return early but we were not hiding the previously
active source label and its menu item dot and thus when switching
again to a third input source we would end up showing 2 overlapping
labels in the panel and the menu would have 2 entries with a dot.

https://bugzilla.gnome.org/show_bug.cgi?id=695841
2013-03-14 14:56:27 +01:00
6119b44746 Improve tracking of fullscreen windows
It's possible in some corner cases for the status of the topwindow
to change and make it not fullscreen without ::restacked being
changed. One way that it could happen with the old code was if the
layer of the top window changed from NORMAL to FULLSCREEN.

Change the logic not to look at the layer, which is a function of
Mutter's *intended* stacking, rather than the *actual* stacking,
which is what ::restacked gives you. Instead, look at the top
portion of the stack, down to the first non-override-redirect
window, and see if their are any monitor-sized windows there.

Connect to changes on the top portion of the stack, so we know
if conditions change.

https://bugzilla.gnome.org/show_bug.cgi?id=649748
2013-03-14 08:06:08 -04:00
7af4a7bf88 Updated Czech translation 2013-03-14 12:58:19 +01:00
04e4d69662 IBus.Property's state needs to be kept in IBus.PropType.NORMAL
https://bugzilla.gnome.org/show_bug.cgi?id=695824
2013-03-14 09:41:58 +01:00
a87e0f028a screenShield: Also unlock on Return/Enter
Since that's what I always did before, having it ignore those is
driving me mad.

https://bugzilla.gnome.org/show_bug.cgi?id=686740
2013-03-13 13:27:34 -04:00
31774a7711 theme: Add :focus style for app-view-controls
https://bugzilla.gnome.org/show_bug.cgi?id=694951
2013-03-13 10:42:22 +01:00
a32f27a2aa ctrlAltTab: Fix external DOCK windows
We always add external DOCK windows to the ctrl-alt-tab switcher,
e.g. separate dock applications or nautilus' desktop windows.
Since commit 1f46a0dc26, all items in the switcher are expected
to set a proxy parameter, but the aforementioned code was not
updated accordingly.

https://bugzilla.gnome.org/show_bug.cgi?id=695395
2013-03-13 10:18:16 +01:00
805a409318 keyring: Don't replace an already running prompter
* Prompters have state, and cancelling an already prompter will
   cause prompts that are in progress to fail.
 * In addition allow replacement of our shell prompter for debugging
   purposes.

https://bugzilla.gnome.org/show_bug.cgi?id=695485
2013-03-13 07:57:16 +01:00
42d45bd14a searchDisplay: Scroll the search results when using keynav
This makes keynav for search results much more usable.

https://bugzilla.gnome.org/show_bug.cgi?id=689681
2013-03-12 19:29:48 -04:00
5870709fbc appDisplay: Move ensureIconVisible logic to util, make it more generic
In particular, make it work if we have multiple parents, like in the
search case.

https://bugzilla.gnome.org/show_bug.cgi?id=689681
2013-03-12 19:29:47 -04:00
0fdb7430ff Updated Portuguese translation 2013-03-12 22:38:14 +00:00
4771f80d6f messageTray: Remove the tray left timeout when showing a new notification
https://bugzilla.gnome.org/show_bug.cgi?id=695659
2013-03-12 11:58:53 -04:00
91405583fd messageTray: Fizzle out hover notifications where the values are the same
notify::* doesn't guarantee that the value has changed, only that it
may have been. We need to ensure that we track the old value to make sure
we don't do things like overwrite timeouts if they already exist.

https://bugzilla.gnome.org/show_bug.cgi?id=695659
2013-03-12 11:58:52 -04:00
f864303aac messageTray: Remove summary state management
Now that the tray is modal, the summary is tied to the tray,
and we don't need to have separate states for the tray and
summary. This also removes the nearly invisible opacity tween
on the summary items when opening the message tray.

https://bugzilla.gnome.org/show_bug.cgi?id=695659
2013-03-12 11:58:52 -04:00
e5ebf4a2b2 messageTray: Remove locking
The only way that locking happens is with when the summary box
pointer is active. As it can only happen if the summary state
is active, it's impossible for a notification to be expired,
or the summary to be hidden while it's showing.

https://bugzilla.gnome.org/show_bug.cgi?id=695659
2013-03-12 11:58:52 -04:00
725a36e37a messageTray: Use the bottom monitor's fullscreen state for rate limiting
It makes more sense to use the monitor the tray is on, rather than the
primary monitor. This also matches us with whether we can open the tray
from a barrier/dwell or not.

https://bugzilla.gnome.org/show_bug.cgi?id=695659
2013-03-12 11:58:51 -04:00
78dacfa865 messageTray: Fix idle tracking condition
The user is active if they have less than IDLETIME, not if
they have more than it.

This fixes an issue where notifications may never go away.

https://bugzilla.gnome.org/show_bug.cgi?id=695659
2013-03-12 11:58:51 -04:00
16547fb3c2 messageTray: Clean up code a tiny bit
Remove some duplication by reusing a method.

https://bugzilla.gnome.org/show_bug.cgi?id=695659
2013-03-12 11:58:51 -04:00
9eeabf79f9 messageTray: Fix style
https://bugzilla.gnome.org/show_bug.cgi?id=695659
2013-03-12 11:58:51 -04:00
81b71cc143 messageTray: Remove a few leftover variables
https://bugzilla.gnome.org/show_bug.cgi?id=695659
2013-03-12 11:58:50 -04:00
8301acd4d6 grabHelper: Use a round trip for focusing the default window
We may release the focus grab at any time, so it's not guaranteed
we'll be in event processing. In particular, hovering over and out
of a notification will cause this to happen, as the notification
is hidden on a timeout.

https://bugzilla.gnome.org/show_bug.cgi?id=695659
2013-03-12 11:58:50 -04:00
f80afb1755 [l10n] Updated Estonian translation 2013-03-12 17:53:56 +02:00
71c6b60054 [l10n] Updated Catalan translation 2013-03-11 23:02:08 +01:00
95a1b874d8 Update libgnome-volume-control to master
Pick a few fixes, including a memory leak fix.

https://bugzilla.gnome.org/show_bug.cgi?id=695656
2013-03-11 22:28:55 +01:00
07de96ede9 recorder: Disconnect stage signals when not recording
This causes unnecessary work, so only connect them when needed i.e
while recording.

https://bugzilla.gnome.org/show_bug.cgi?id=695650
2013-03-11 20:11:18 +01:00
209014b083 screenShield: Forward key presses to tne entry when raising the shield
https://bugzilla.gnome.org/show_bug.cgi?id=686740
2013-03-11 15:08:21 -04:00
127f10e7a8 screenShield: Don't wait until the dialog is loaded before opening it
If we wait asynchronously, key presses while the shield is opening
will be dropped in the void.

https://bugzilla.gnome.org/show_bug.cgi?id=686740
2013-03-11 15:08:21 -04:00
67615a0cbc screenShield: Remove bump on key press
Any key press of a character-emitting key will now raise the shell.
Note that the key press will not be forwarded to the entry yet.

https://bugzilla.gnome.org/show_bug.cgi?id=686740
2013-03-11 15:08:20 -04:00
dde20f0c76 screenShield: Move opening of screen shield to key press
This makes the screen shield much more responsive.

https://bugzilla.gnome.org/show_bug.cgi?id=686740
2013-03-11 15:08:20 -04:00
ddced79475 recorder: port to XInput2
Pointer tracking is broken when the pointer is over the stage input
area.  This is apparently fallout from mutter going to XInput2.

This commit changes the mouse event handling code to also use XInput2.

https://bugzilla.gnome.org/show_bug.cgi?id=695324
2013-03-11 13:11:08 -04:00
e80795b7f0 recorder: don't bother selecting for enter/leave/motion events
Mutter already handles that for us.

https://bugzilla.gnome.org/show_bug.cgi?id=695324
2013-03-11 12:35:38 -04:00
080337a4e8 Updated German translation 2013-03-11 14:25:21 +01:00
884af3c986 style: Prevent dash from overlapping content
In order to center the view selector, the dash has been moved to a
separate layer, which means that it will overlap the app picker and
search results if the available width is smaller than the maximum
width that the content will request. Fix this by adding enough
horizontal padding to account for the width the dash will have at
its largest icon size.

https://bugzilla.gnome.org/show_bug.cgi?id=695471
2013-03-11 13:33:05 +01:00
edc95b2cb7 Updated Indonesian translation 2013-03-11 16:47:37 +07:00
96239e95ec userMenu: Add translation comments
Seems like "console" vs. "remote" in the "other users" dialog  confuses some
translators so add a comments to clarify their meaning.

https://bugzilla.gnome.org/show_bug.cgi?id=695601
2013-03-11 10:35:42 +01:00
331ad76675 Updated German translation 2013-03-10 23:59:06 +01:00
29152d3022 layout: Disable the overview hotcorner when we have a full-screen window open
For the same reasons that we disable the tray barrier, we should
disable hot corners as well -- when users have a full-screen game
open, we shouldn't allow overview activation by the hotcorner.

https://bugzilla.gnome.org/show_bug.cgi?id=694997
2013-03-10 12:00:09 -04:00
73fa4b1cbd messageTray: Don't open by pressure when we have a full-screen window open
When we have a full-screen window open, we expect the app to get all of
the chrome, so we should disable the bottom barrier as well.

https://bugzilla.gnome.org/show_bug.cgi?id=694997
2013-03-10 12:00:09 -04:00
7766a91e8c Wanda: so long GNOME 2, and thanks for all the fish.
gnome-panel is going away in 3.8, so we can't rely on it to provide our
friendly and reliable companion. But no regret, because we can ship it
ourselves, and at the same time remove some unnecessary configuration.

https://bugzilla.gnome.org/show_bug.cgi?id=695526
2013-03-10 15:54:40 +01:00
b7bad765aa Updated Latvian translation 2013-03-10 14:56:32 +02:00
5af09a60e9 Main: close the looking glass when we don't have a run dialog
No run dialog means no looking glass either.

https://bugzilla.gnome.org/show_bug.cgi?id=695458
2013-03-08 23:18:31 +01:00
ef623cfbbd Updated Serbian translation 2013-03-08 20:28:31 +01:00
ce5faba185 osdWindow: bump down the OSD window size a bit
Matches what this commit did for g-s-d:
https://git.gnome.org/browse/gnome-settings-daemon/commit/plugins/media-keys?id=fbf3c5aa366ef7212f209e123d4aae315a1a2a8e

https://bugzilla.gnome.org/show_bug.cgi?id=695409
2013-03-07 17:02:41 -05:00
40d9ed535b runDialog: Remove the use of file monitors for file completion
Launching the run dialog to open the looking glass or something
like that shouldn't install a bunch of file monitors that monitor
every IO change to the home and system directories.

Instead, simply scan all the paths when trying to complete.

https://bugzilla.gnome.org/show_bug.cgi?id=695338
2013-03-07 16:35:37 -05:00
d5675765f3 runDialog: Remove tab-completion preloading
This is iffy anyway, since we don't wait for the correct signal.
Just make the user press tab again, like they would do anyway.

https://bugzilla.gnome.org/show_bug.cgi?id=695338
2013-03-07 16:35:37 -05:00
65067c24cc main: Show the greeter dialog when we're prepared
If we don't wait until the stage is mapped, pushing a modal
will fail with an X error.

https://bugzilla.gnome.org/show_bug.cgi?id=694321
2013-03-07 16:35:37 -05:00
e2463cb501 layout: Move showing the stage and the startup-prepared signal
Waiting until we're idle means nothing if we're constructing
complex actors.

https://bugzilla.gnome.org/show_bug.cgi?id=694321
2013-03-07 16:35:36 -05:00
de2f2d7ef1 main: Remove leftover hunk connection to sessionUpdated
We shouldn't connect to sessionUpdated twice.

https://bugzilla.gnome.org/show_bug.cgi?id=694321
2013-03-07 16:35:36 -05:00
7cdb75e7ce Defer initializing UI until after the global session has loaded
https://bugzilla.gnome.org/show_bug.cgi?id=694321
2013-03-07 16:35:36 -05:00
1502e308b8 Updated Slovenian translation 2013-03-07 20:51:04 +01:00
dd1fe68e5c Finnish translation update by Jiri Grönroos 2013-03-07 21:02:09 +02:00
85c1dc5a0c Updated Kazakh translation. 2013-03-07 20:19:30 +06:00
7b3a689aad theme: match the hover effect radius to the prelight effect
Application view: the radius of the corners on the hover effect
should match the radius of the prelight effect that is used for
running apps. Original fix from Bharath Thiruveedula.

https://bugzilla.gnome.org/show_bug.cgi?id=691578
2013-03-07 12:48:38 +00:00
2c28a12cca Updated Uyghur translation
Signed-off-by: Gheyret Kenji <gheyret@gmail.com>
2013-03-07 21:05:47 +09:00
324021fd64 Updated Russian translation 2013-03-07 09:36:24 +04:00
1dceae97c6 Revert "Defer initializing UI until after the global session has loaded"
This reverts commit 0bef925b51.

Just for now.  Jasper has plans to clean up start up eventually.

https://bugzilla.gnome.org/show_bug.cgi?id=694321
2013-03-06 17:26:15 -05:00
0bef925b51 Defer initializing UI until after the global session has loaded
https://bugzilla.gnome.org/show_bug.cgi?id=694321
2013-03-06 14:55:58 -05:00
0ba1f29e40 main: Merge two different session-mode-updated handlers
https://bugzilla.gnome.org/show_bug.cgi?id=694321
2013-03-06 14:34:59 -05:00
3b1e536822 screenShield: Drop fallback implementation
With fallback mode gone, we can no longer rely on gnome-screensaver
being installed. Rather than handling three different cases (GDM,
gnome-screensaver, no lock), disable the lock functionality when
not running under GDM.

https://bugzilla.gnome.org/show_bug.cgi?id=693403
2013-03-06 16:22:07 +01:00
9a83662a18 loginManager: Move UnlockDialog.isSupported() here
With fallback mode dropped, we can no longer rely on gnome-screensaver
to be installed, so we'll have cases where we are unable to lock the
screen. The user menu should not show the "Lock" item in this case,
but as UnlockDialog includes UserMenu, we cannot use the existing check
without creating a circular dependency; move the function to a more
generic place to fix.

https://bugzilla.gnome.org/show_bug.cgi?id=693403
2013-03-06 16:22:07 +01:00
5bcead5b5c build: Really remove build time dependency on tp-logger
Commit 00eb764880 removed the dependency from configure, but kept
the gir include. Remove that as well.

https://bugzilla.gnome.org/show_bug.cgi?id=695272
2013-03-06 16:22:06 +01:00
d8f9502ea2 Updated Traditional Chinese translation(Hong Kong and Taiwan) 2013-03-06 19:07:01 +08:00
020128b9ca background: don't use raise_top() since it's costly
We currently resync the stacking order of the two key frames
every iteration of the animation.  This is costly and unnecessary.

This commit ensures they're stacked properly up front and doesn't
touch them after that.

https://bugzilla.gnome.org/show_bug.cgi?id=694993
2013-03-05 16:03:12 -05:00
1566a4e607 unlockDialog, loginDialog: Connect to the activate signal on the entry
This is the recommended way to connect to an entry's activation binding --
event bubbling is not guaranteed by ClutterText.

https://bugzilla.gnome.org/show_bug.cgi?id=695154
2013-03-05 15:25:11 -05:00
fbd59631ee Assamese translation updated for gnome 3.8 2013-03-05 19:20:22 +05:30
6c36856499 layout: fix errors in fallback HotCorner function 2013-03-05 17:53:59 +11:00
f4cda49988 Bump version to 3.7.91
Update NEWS.
2013-03-05 00:42:25 +01:00
a6b49fe7d6 st-icon: Don't cause a redraw by replacing the icon with itself
Check if the two icons match before setting a new icon, if they
do don't do anything.

Based on patch from Owen Taylor <otaylor@fishsoup.net>

https://bugzilla.gnome.org/show_bug.cgi?id=694988
2013-03-05 00:03:29 +01:00
26966b2bf3 layout: Port the hot corner to pressure barriers
If the X server supports the new barrier features, we should
trigger the overview hot corner with a pressure barrier as well.

https://bugzilla.gnome.org/show_bug.cgi?id=663661
2013-03-04 17:47:48 -05:00
36a7429aa0 overview: Try to do the right thing related to XDnD
Rather than expose a dizzying array of methods related to managing
state that require infecting every user of the overview methods, try
to do the sensible and smart thing internally. Now, the overview
itself tracks when XDND drags start, and simply calling show, hide or
toggle while an XDnD drag is in effect will show the overview, and
will only take the grab until after the XDND drag ends.

https://bugzilla.gnome.org/show_bug.cgi?id=663661
2013-03-04 17:47:47 -05:00
7be1fe09f1 layout: Don't use the corner's position for positioning ripples
The corner may not be there in the future.

https://bugzilla.gnome.org/show_bug.cgi?id=663661
2013-03-04 17:03:24 -05:00
62bf08d323 layout: Put two barriers near every single hot corner
This will make the hot corner easier to hit on multi-monitor
scenarios, and also gives us a convenient set of barriers to
key pressure off of.

https://bugzilla.gnome.org/show_bug.cgi?id=663661
2013-03-04 17:03:24 -05:00
260c082c4e main: defer session update until startup animation
We currently call the session updated handler as soon as
the session modes are read.  This handler sets up keybindings
for leaving the overview (if a user session) and shows the
login dialog (if a gdm session).

We can't do the latter until the stage is mapped because it
takes a grab, and we don't need to do the former until the
user goes into the overview.

This commit defers processing session updates until the
the layout manager says start up is prepared.

It fixes a race condition at login screen startup now that
we don't show the stage right away.

https://bugzilla.gnome.org/show_bug.cgi?id=694321
2013-03-04 16:45:32 -05:00
5e0ff7fd56 main: don't explicitly hide the stage
It's hidden by default, so there's no point in hiding it explicitly.

https://bugzilla.gnome.org/show_bug.cgi?id=694321
2013-03-04 16:45:32 -05:00
aac312ca34 overviewControls: only show chat icon in messages indicator for chats
Only show the chat icon in the new messages indicator when at least one
among the outstanding notifications is a chat.
2013-03-04 16:25:50 -05:00
a90401454a layout: Pass the X/Y coordinates when constructing the corner
There's no guarantee that hot corners will have an actor in
the future -- they may be powered entirely by a barrier.

https://bugzilla.gnome.org/show_bug.cgi?id=663661
2013-03-04 15:50:45 -05:00
5679e6b3a9 layout: Construct the primary monitors's hot corner, too
This cleans up the code considerably, and makes it so that
one path creates all hot corners for all monitors. Why this
wasn't done originally, I have no clue...

The one complication is debouncing if the button and hot corner
are triggered in rapid succession, so we just move this tracking
to the overview.

https://bugzilla.gnome.org/show_bug.cgi?id=663661
2013-03-04 15:50:45 -05:00
194574bb0e layout: Allow multiple barriers to contribute to a PressureBarrier
For the HotCorner case, we want to have to barriers both contribute
to the hot corner pressure, so we can't simply wrap the pressure
barrier.
2013-03-04 15:50:44 -05:00
337d2da38a layout: Move tray-specific event filtration to the user of PressureBarrier
For the HotCorner, we want to have different logic for tossing out
specific events based on the grabbed state, etc. so make us have
to pass in an event filter callback.
2013-03-04 15:50:44 -05:00
df848aa084 layout: Move the keybinding mode to the user of PressureBarrier
For the hot corner case, we want to have the pressure apply both in
and outside of the overview, so we need to move this to the user. At
the same time, use keybinding mode math that's more like what's used
in filterKeybinding.

While it may seem like an abuse of the KeyBindingMode API, it may
become more reasonable if one thinks of the pressure barrier as a
binding of sorts, just applied to the mouse. If a ButtonBinding API
was added to mutter, I think we'd use the existing KeyBindingMode
infastructure there as well.
2013-03-04 15:50:44 -05:00
0cc1615252 layout: Debounce triggering barriers
Ensure that the pointer leaves the barrier before we trigger again.

For the message tray case, this doesn't matter much, as the trigger
won't have any effect after the grab is taken, but in the overview
HotCorner case, this ensures that we don't trigger the overview
transition many times simply by holding pressure against the hot
corner, which is easy to do accidentally.
2013-03-04 15:50:44 -05:00
d4259fa8aa layout: Prevent going into negatives with the pressure
We capped each event to 15px of travel, but we didn't do the same
cap when subtracting events that were too old.
2013-03-04 15:50:43 -05:00
157d7e2b59 Updated Lithuanian translation 2013-03-04 22:45:23 +02:00
ee50904147 Calendar: only show events when configured in Evolution
When no calendars are enabled, hide the events pane completely instead
of showing it empty.

https://bugzilla.gnome.org/show_bug.cgi?id=680083
2013-03-04 18:59:30 +01:00
ec39aa3890 Calendar: dim days from other months, even if they have events
Invert the order of the declarations, so those for calendar-other-month-day
take priority over those for calendar-day-with-events.

https://bugzilla.gnome.org/show_bug.cgi?id=641383
2013-03-04 18:59:30 +01:00
beb0fdf4b8 Calendar: clean up code by always having an event source
Instead of sometimes having an event source and sometimes not, use
the empty event source when the session mode says the calendar is
disabled. This way, the code can assume an event source object and
avoid checks.

https://bugzilla.gnome.org/show_bug.cgi?id=641383
2013-03-04 18:59:30 +01:00
443fe813c3 Calendar: freeze updates when the event source is loading
Check if the event source is currently doing an async call, and prevent
UI updates in that case. This avoids a flash of "No updates" when switching
months.

https://bugzilla.gnome.org/show_bug.cgi?id=641383
2013-03-04 18:59:30 +01:00
69cdc5a9b9 Calendar: force all months at the same height
Add one or two weeks from nearby months to avoid changing the menu height
when navigating it.

https://bugzilla.gnome.org/show_bug.cgi?id=641383
2013-03-04 18:59:30 +01:00
dac54a6019 Migrate from libgnome-keyring to libsecret
* See: https://live.gnome.org/GnomeGoals/LibsecretMigration

https://bugzilla.gnome.org/show_bug.cgi?id=679851
2013-03-04 18:47:52 +01:00
e5ca53e56c status/keyboard: Don't allow the switcher in the message tray
SwitcherPopup relies on being able to pushModal(), setting the stage
input mode to FULLSCREEN, and then doing regular event processing on
the actor it adds to uiGroup. But MessageTray uses GrabHelper which
sets up a 'captured-event' handler on the stage and thus gets all
events itself.

This, of course, breaks the switcher if it's brought up in the message
tray so, for now, we'll just prevent it from being used there.

https://bugzilla.gnome.org/show_bug.cgi?id=693907
2013-03-04 18:32:49 +01:00
7a79236bab theme: use standard styling for ibus candidate popups
This is more consistent and helps with legibility.

https://bugzilla.gnome.org/show_bug.cgi?id=694796
2013-03-04 17:03:31 +00:00
cd37e2908f main: don't hook up overview keybinding until after startup
Toggling the overview during the startup animation reportedly
causes stuck grab and other odd behavior.

There's no reason to handle toggling the overview during this
time anyway.

This commit defers that handling until after startup.

https://bugzilla.gnome.org/show_bug.cgi?id=694837
2013-03-04 11:58:39 -05:00
3368e49aa7 main: drop superfluous Lang.bind(this, ...)
Jasper noticed this and I forgot to clean it up before pushing,
then I just noticed it again when doing some other patches

https://bugzilla.gnome.org/show_bug.cgi?id=694326
2013-03-04 11:35:36 -05:00
9e31f05861 shellEntry: Disable copy action for password entries
Curently it is possible to copy the content of password entries,
and paste it elsewhere in clear text. This is undesirable, so
follow GTK+'s behavior and disable the copy action for password
entries.

https://bugzilla.gnome.org/show_bug.cgi?id=695104
2013-03-04 16:43:59 +01:00
b52f4ed25b st-entry: Disable cut/copy actions in password entries
Curently it is possible to copy the content of password entries,
and paste it elsewhere in clear text. This is undesirable, so
follow GTK+'s behavior and disable the cut/copy actions for
password entries.

https://bugzilla.gnome.org/show_bug.cgi?id=695104
2013-03-04 16:43:59 +01:00
00eb764880 configure.ac: remove telepathy-logger dep
We don't use it in C code any more.

https://bugzilla.gnome.org/show_bug.cgi?id=687748
2013-03-04 16:38:47 +01:00
6d011a3700 workspacesView: Always zoom out switcher when using static workspaces
We always leave the workspace switcher zoomed out when we can assume
that the user is actually making use of workspaces. For the default
dynamic workspace behavior, we make this assumption when more than
two workspaces are in use (e.g. at least two workspaces contain windows
plus an empty one at the end). However this test does not make sense
when using static workspaces - in that case, not using workspaces
would be indicated by a workspace number of 1 (in which case the
entire switcher is hidden completely), so add a check for dynamic
workspaces to the condition.

https://bugzilla.gnome.org/show_bug.cgi?id=695126
2013-03-04 15:51:25 +01:00
f9d9caf417 switcherPopup: Remove separator support
Since the alt-tab switcher stopped using separators, the functionality
is unused, remove it.

https://bugzilla.gnome.org/show_bug.cgi?id=661156
2013-03-04 15:28:38 +01:00
b50702dd52 altTab: Ignore workspaces in popups
Currently both the app switcher and the thumbnail list divide items
first into two groups (based on whether the item is located on the
current workspace or not), and then sort each group individually
by MRU.
The resulting behavior is often confusing, e.g. when using alt-tab
a second time does not switch back to the original window when the first
invocation involved a workspace switch and the workspace contains
windows of more than one application.
Instead, make the behavior more predictable by sorting both lists
strictly by MRU.

https://bugzilla.gnome.org/show_bug.cgi?id=661156
2013-03-04 15:28:37 +01:00
e74a82b9d6 Updated Spanish translation 2013-03-04 14:52:05 +01:00
12fa983242 Updated Norwegian bokmål translation 2013-03-04 14:15:59 +01:00
1607df835a Updated Galician translations 2013-03-04 12:41:17 +01:00
7b705dd670 modalDialog: Fix auto-completion of prompts immediately upon display
Shell modal dialogs can take their action on a certain key's
key-release-event. For example on <enter> the affirmative action is
usually run.

Make sure that the key was also pressed on the dialog and we're not
seeing a spurious key-release-event from a key that was pressed before
the dialog was displayed.

https://bugzilla.gnome.org/show_bug.cgi?id=692937
2013-03-04 09:17:41 +01:00
323e3028b6 Updated Brazilian Portuguese translation 2013-03-04 00:52:05 -03:00
7e1b4692e2 status/keyboard: Don't show the switcher with less than 2 items
https://bugzilla.gnome.org/show_bug.cgi?id=695000
2013-03-04 00:30:04 +01:00
c1dd971ce9 xdndHandler: Ensure that the XDnD clone is on top of the panel
The panel is added to the uiGroup, not the overlay group, so
to stack on top of it, we need to add ourselves to the uiGroup
as well.

https://bugzilla.gnome.org/show_bug.cgi?id=695073
2013-03-03 15:41:52 -05:00
39610e6933 viewSelector: Move the loupe icon to the primary slot
This matches the behavior in GTK+. See the rationale there.

https://bugzilla.gnome.org/show_bug.cgi?id=695069
2013-03-03 15:41:52 -05:00
fdb189102d Updated Russian translation 2013-03-03 23:22:11 +04:00
e54d095064 OtherUsersDialog: wrap the description label
In some languages (like Italian) it doesn't fit in one line.

https://bugzilla.gnome.org/show_bug.cgi?id=695002
2013-03-03 13:51:30 +01:00
e6634c56d3 OtherUsersDialog: don't show closing sessions
It is possible that a session survives after closing, if any processes
(usually PulseAudio and GConf) are still alive at the end. In that case,
ignore it, as the user is already logged out and there is nothing to lose.

https://bugzilla.gnome.org/show_bug.cgi?id=695002
2013-03-03 13:51:30 +01:00
deb77a4dde switcherPopup: Cancel the OSD popup before showing
It is irritating to show two different system popups at the same
time, so let switcher popups like alt-tab cancel out the OSD.

https://bugzilla.gnome.org/show_bug.cgi?id=613543
2013-03-03 12:59:09 +01:00
90ea27c423 shellDBus: Export ShowOSD() method on the bus
Export a simple method to trigger an OSD popup. gnome-settings-daemon
will use this to replace its own OSD UI.

https://bugzilla.gnome.org/show_bug.cgi?id=613543
2013-03-03 12:59:09 +01:00
19533f87e3 osdWindow: Add a simple OSD popup
Implement a basic OSD popup that shows an icon and optionally a label
and a fill level. It is based on the existing OSD implementation in
gnome-settings-daemon, which it will replace.

https://bugzilla.gnome.org/show_bug.cgi?id=613543
2013-03-03 12:59:08 +01:00
e6c5c84133 Updated Greek translation 2013-03-03 13:24:37 +02:00
404aaa5658 Updated Uyghur translation
Signed-off-by: Gheyret Kenji <gheyret@gmail.com>
2013-03-03 16:00:53 +09:00
2c70df25f5 Updated Vietnamese translation 2013-03-03 11:13:32 +07:00
db959ac2eb po/vi: import from Damned Lies 2013-03-03 11:11:26 +07:00
bbf0dce390 Punjabi: Translation updated (aalam) 2013-03-03 07:10:45 +05:30
1cbb8b9851 layout: tweak startup animation
Following designer feedback, this commit makes the startup
animation a little more subtle.

https://bugzilla.gnome.org/show_bug.cgi?id=694326
2013-03-02 17:44:26 -05:00
96387cce47 background: drop StillFrame class
We aren't using it anymore so nix it.

https://bugzilla.gnome.org/show_bug.cgi?id=694326
2013-03-02 17:44:26 -05:00
570fc68cb1 main: put noise texture below startup animation, not still frames
Right now we take a still frame of the desktop before showing the
start up animation.  This gives us an animation over what was
there before startup.

That's not actually desirable when restarting the shell.  We don't
want to animate over undecorated windows, we really want to animate
over the noise texture.

This commit drops the still frames in favor of the noise texture.

https://bugzilla.gnome.org/show_bug.cgi?id=694326
2013-03-02 17:44:26 -05:00
e6ce0057af screenShield: only pop lock-screen mode at the end of lift
This avoids the style of the top panel changing as soon as the lift key
is pressed weakening the curtain effect.

https://bugzilla.gnome.org/show_bug.cgi?id=695023
2013-03-02 17:26:28 -05:00
a3f625fe39 screenshot: Discard invalid sized areas
https://bugzilla.gnome.org/show_bug.cgi?id=694998
2013-03-02 22:26:27 +01:00
bdfe459d64 css: Make input sources switcher symbol font smaller
Particularly when using asian languages the symbol could become large
enough to not fit in the space we have and we'd end up with a totally
ellipsized item.

https://bugzilla.gnome.org/show_bug.cgi?id=695001
2013-03-02 18:42:59 +01:00
95ec8ef5e1 shell-global: Fix regression from 071a4e5f83
The clutter_threads_add_repaint_func_full need to return TRUE otherwise
they will be only called once.

https://bugzilla.gnome.org/show_bug.cgi?id=695006
2013-03-02 18:25:34 +01:00
b8198716d9 l10n: Updated Italian translation 2013-03-02 15:55:04 +01:00
071a4e5f83 shell-global: Don't connect to the stage's paint signal
Doing so causes useless full stage redraws and breaks culling
as clutter cannot know how the signal handler affects painting.

So use clutter_threads_add_repaint_func_full instead.

https://bugzilla.gnome.org/show_bug.cgi?id=694988
2013-03-02 14:43:11 +01:00
d99cd71408 Updated POTFILES.in 2013-03-02 01:31:00 +01:00
030e6aa507 Fix overview sizing with multimonitor
Previously, the overview BoxLayout was sized and positioned explicitly
using the primary monitor coordinates, as its parent was at 0,0 and
with a fixed layout manager. Now we use a bin layout, so we need to
position and size the stack actor, and set the overview boxlayout to
expand.
Take also the occasion to use a MonitorConstraint instead of handling
position and size manually.

https://bugzilla.gnome.org/show_bug.cgi?id=694969
2013-03-02 00:29:13 +01:00
f146b01e3e Fix dash sliding animation with multiple monitors
We used to clip the overview group to prevent the dash from sliding into
neighbor monitors, but now it moved to the groupStack, so we must move
the clip too.

https://bugzilla.gnome.org/show_bug.cgi?id=694970
2013-03-02 00:26:39 +01:00
c249ff9046 theme: tone down search results description font style
- don't use bold
- use regular font size
- make the text shadow less dramatic
2013-03-01 14:21:07 -05:00
8b48560c81 overviewControls: add a new messages indicator
The new messages indicator will be visible when there are non-resident
notifications in the tray.

https://bugzilla.gnome.org/show_bug.cgi?id=687787
2013-03-01 13:50:51 -05:00
bdbea2463b messageTray: add an indicatorCount property
This filters out resident and transient notifications in the normal
case, but just returns the number of unread messages for the Telepathy
implementation.

https://bugzilla.gnome.org/show_bug.cgi?id=687787
2013-03-01 13:17:51 -05:00
8fb2263471 messageTray: emit a signal when we're showing or hiding
This will be useful in a future commit.

https://bugzilla.gnome.org/show_bug.cgi?id=687787
2013-03-01 13:17:51 -05:00
ea55c36a3a st-widget: Don't add hidden actors to the paint volume
We are not painting them anyway.
2013-03-01 19:13:22 +01:00
37595ff3e7 shell-generic-container: Exclude skip_paint actors from the paint volume
We are not painting them so there is no reason to redraw a bigger
area because of them.
2013-03-01 19:13:10 +01:00
cca008b73c overview: Move dash to a separate layer
We generally want view content centered, in particular where the
view itself is symmetrical. So move the dash to a separate layer
and use a placeholder to account for its size when showing the
window picker, which is the only view where it doesn't make sense
to center the content.

https://bugzilla.gnome.org/show_bug.cgi?id=694261
2013-03-01 18:25:53 +01:00
b9dcbd9d33 overview: Use the new main actor in show/hide transitions
Commit 43ed66cf26 changed the toplevel overview actor, so it
makes sense to change the show/hide transitions to use that instead
of the existing group, to avoid elements layered on top of the
group being excluded from the transitions.
2013-03-01 18:25:53 +01:00
b6bf8d5b2d Layout: don't minimize fullscreen windows that are focused
Windows can sometimes be focused, or appear to be focused, without being
at the exact top of the stack, for example in the case of override-redirect
windows, or with attached modal dialogs. In that case, we should not
try to minimize them (as it creates a loop that makes it impossible to restore
the window)

https://bugzilla.gnome.org/show_bug.cgi?id=694905
2013-03-01 18:07:47 +01:00
43ed66cf26 overview: use a bin for the main overview actor
We'll pack the new messages indicator on top of the current overview
group, so we need to pack it into a ClutterBinLayout first.

https://bugzilla.gnome.org/show_bug.cgi?id=687787
2013-03-01 11:34:09 -05:00
57eae1be43 main: register with session manager explicitly
Mutter now makes session registration an explicit required
step.  This is so we can tell the session manager when
we're ready to move on to the next phase.

This commit calls the new Meta.register_with_session() api after we're
initialized.

https://bugzilla.gnome.org/show_bug.cgi?id=694876
2013-03-01 11:31:18 -05:00
b394d184cc scroll-view-fade: Tweak easing at edges
Since commit b4f5f1e461, the effect is eased in at the scroll
view's edges so that it does not appear out of nowhere. However,
the linear easing used is not the best option, as now the effect
appears so late that content near the edges ends up just being
cut off rather than faded out.
So adjust the easing function to have the effect appear faster.

https://bugzilla.gnome.org/show_bug.cgi?id=694327
2013-03-01 17:30:01 +01:00
81e01b6f88 shellDBus: Add methods to handle key grabs
Expose Mutter's external grab API on the bus, so gnome-settings-daemon
can refer keygrabbing to the shell.

https://bugzilla.gnome.org/show_bug.cgi?id=643111
2013-03-01 16:14:30 +01:00
52efe32e0f Updated Basque language 2013-03-01 09:27:53 +01:00
e7886734c4 search: fix description of results
"description" is documented as a valid field for search result metas,
and ListSearchResults implements it, so pass it down to be used.
Also, don't wrap the description in quotes, so that the search provider
can decide if it is an excerpt from the searched text or something else.
And to that extent, set use_markup to true, so that terms can be
highlighted.

https://bugzilla.gnome.org/show_bug.cgi?id=694906
2013-03-01 00:38:50 +01:00
083c37a7b2 workspace: Fix bad window positions with small windows
This can happen if you open two or three terminal windows, and then
open the overview -- they're not centered. The issue is that because
of the WINDOW_CLONE_MAXIMUM_SCALE clamping, the scale that is being
laid out is different from the scale that the layout was calculated
for.

Implement and document a hack-ish solution which simply keeps the
scale for the layout as originally calculated, but centers the
windows inside the cell.

https://bugzilla.gnome.org/show_bug.cgi?id=694902
2013-02-28 18:15:15 -05:00
b24a10aa00 workspace: Use the scaled width when calculating the total width
This is a small inconsistency I found in the code after review.

https://bugzilla.gnome.org/show_bug.cgi?id=694902
2013-02-28 18:13:50 -05:00
e1ef14d12b workspace: Write a giant wall of text describing the algorithm
I wrote this for me to find solutions to some problems we were having
with the current situation, so why not check it in?

https://bugzilla.gnome.org/show_bug.cgi?id=694902
2013-02-28 18:13:50 -05:00
1a33de91e2 workspace: Separate out per-window scaling as a separate variable
Multiplication is linear, so we can split this out as a separate
component. This will make it easier to think of it as an additional
per-window scaling factor, rather than tweaking the scale a bit,
which is more correct to the model.

https://bugzilla.gnome.org/show_bug.cgi?id=694902
2013-02-28 16:26:09 -05:00
6e15e2d72a workspace: Remove unused variable
This typo seems to have been here since the very beginning;
no "state" variable appears anywhere.

https://bugzilla.gnome.org/show_bug.cgi?id=694902
2013-02-28 16:26:08 -05:00
d58b715c52 workspace: Remove some additional features used for GridLayoutStrategy
While we won't tear down the entire strategy infrastructure, we want to
rework some layout code in the future, so just tear this piece out for
now.

https://bugzilla.gnome.org/show_bug.cgi?id=694902
2013-02-28 16:26:08 -05:00
804ff8b5a5 layout: Mark the correct monitor as fullscreen 2013-02-28 13:34:05 -05:00
6e89d2f46a extensionPrefs: Fix opening extension preferences on startup
gnome-shell-extension-prefs supports opening a specific extension's
preferences directly from the command line by passing the UUID.
However this broke when extension loading was changed to be processed
asynchronously, as no extension has been loaded when the command
line argument is processed. Fix by deferring opening the extension's
preferences until all extensions have been loaded.

https://bugzilla.gnome.org/show_bug.cgi?id=694858
2013-02-28 15:37:29 +01:00
e99d69b7d9 extensionUtil: Add ExtensionFinder::extensions-loaded signal
Consumers might want to defer work until the initial loading of
extensions has finished, so add an appropriate signal.

https://bugzilla.gnome.org/show_bug.cgi?id=694858
2013-02-28 15:37:28 +01:00
f25416c3f5 Updated Greek translation 2013-02-28 10:10:11 +02:00
a7bb6a2781 Show the session list when needed
Some of the conditions for showing the user list were not
properly inverted, causing the session list to be hidden
when it shouldn't be and shown when it shouldn't be.

https://bugzilla.gnome.org/show_bug.cgi?id=694784
2013-02-27 18:09:43 -05:00
41f14e0e89 layout: Trigger the tray if one event passes the threshold
As a special-case to the "cap event" rules, this allows a heavy swipe
from top to bottom to allow triggering the tray without having to push
into it.

https://bugzilla.gnome.org/show_bug.cgi?id=694467
2013-02-27 14:01:42 -05:00
01bd10f485 layout: Cap each event to 15px of motion
When pressing against the bottom of the screen, we shouldn't
really take more than 15px from each event, to prevent spruious
mouse movements from opening the barrier.

https://bugzilla.gnome.org/show_bug.cgi?id=694467
2013-02-27 14:01:42 -05:00
476eacd5ca layout: Adjust the pressure barrier threshold values
After a day of experimentation with Cosimo and Jon McCann, we
found that this was the best way to do this.

https://bugzilla.gnome.org/show_bug.cgi?id=694467
2013-02-27 14:01:42 -05:00
ca2fb74f41 Updated Traditional Chinese translation(Hong Kong and Taiwan) 2013-02-27 22:59:02 +08:00
8a2baf5b6e Updated Vietnamese translation 2013-02-26 20:47:16 +07:00
d44fc3aa1b po/vi: import from Damned Lies 2013-02-26 20:34:33 +07:00
7d78c42dfc workspaceThumbnails: remove custom scrolling code
Now that we listen to scroll event on the whole overview group, this
makes the thumbnail switcher scroll twice per-event.
2013-02-25 18:23:42 -05:00
a361180745 layout: Handle _NET_WM_FULLSCREEN_MONITORS
Mark all monitors that fullscreen when window is using
the _NET_WM_FULLSCREEN_MONITORS to be fullscreen on multiple monitors.

https://bugzilla.gnome.org/show_bug.cgi?id=646861
2013-02-25 22:06:45 +01:00
310dc10c4d Center the search results as well
Use overlay_scrollbars and the same padding.

https://bugzilla.gnome.org/show_bug.cgi?id=694701
2013-02-25 14:49:25 -05:00
96e02c4c2e tweener: Look at the XSetting for disabling animations
gnome-settings-daemon will be changed to override the XSetting in
the case where we're on a remote display rather than overwriting a
user setting, so we need to look at the XSetting here.

https://bugzilla.gnome.org/show_bug.cgi?id=694320
2013-02-25 12:59:35 -05:00
afb3b9f029 Updated Norwegian bokmål translation 2013-02-25 18:35:23 +01:00
d5e647a191 ScreenShield: fix positioning of background with multimonitor
Previously, we would create one StBin per monitor, but each was positioned
at 0,0 and sized as the screen, so they would overlap and draw the box shadows
on top of the other backgrounds.
Instead, we need to size appropriately the bin, and then we need to position
the actual MetaBacgroundActor at 0,0, so add a flag to BackgroundManager
for this.
Also, get rid of MetaBackgroundGroup, they do nothing because the screenshield
is not a descendant of the MetaWindowGroup and because the widget in between
blocks the propagation of the visible region. At the same time, use a
widget, not a bin, because StBin requires you to set .child, not call add_child().

https://bugzilla.gnome.org/show_bug.cgi?id=694394
2013-02-25 14:46:40 +01:00
a1d37617a8 Fixed typo in string. Fixes bug #687248 2013-02-25 14:27:31 +01:00
2541f85942 Updated gujarati file 2013-02-25 16:39:49 +05:30
07fd23dc5e Updated Slovenian translation 2013-02-24 21:34:43 +01:00
946311b2a3 Updated Polish translation 2013-02-24 01:55:12 +01:00
4868032215 Updated Czech translation 2013-02-24 01:18:25 +01:00
fb0cf64536 viewSelector: Don't focus search entry on whitespace
We recently started to trim leading and trailing whitespace from
the search string, and not to trigger a search when the resulting
string was empty. However we still allow whitespace to trigger
type-ahead-find, so that the key focus is moved briefly to the
search entry and back to the stage, resulting in a disruptive
flickering of the entry.
Fix this by excluding whitespace from triggering type-ahead-find.

https://bugzilla.gnome.org/show_bug.cgi?id=694475
2013-02-23 09:42:09 +01:00
b37afcdba1 xdnd: Only pick reactive actors
This is the only sane way to get select windows in the overview,
as workspace._dropRect blocks our view otherwise.
2013-02-22 20:02:22 +01:00
f644bee831 xdnd: Don't wait for the stage to be disabled when it is already visible
xdndHandler used to wait for the stage to show up before calling
global.init_xdnd() . Since commit 65303d027a xdndHandler is initalized
later so the stage might be already visible at this point causing the
show signal never to be emitted and thus global.init_xdnd will never
be called.

Fix that by checking by calling global.init_xdnd without waiting for
the stage's show signal to be emitted, as the stage is guaranted to be
visible at this point.
2013-02-22 19:37:40 +01:00
6fcc7e3e23 Background: don't check draw-background key
The key was removed from gsettings-desktop-schemas, GNOME should
always draw a background: the key existed to support xsetroot, but
we no longer read the _XROOTPMAP_ID.

https://bugzilla.gnome.org/show_bug.cgi?id=694463
2013-02-22 17:49:16 +01:00
95602eb85d AppDisplay: fix allocation loop warnings
Don't use a constraint to position the boxpointer horizontally. Instead,
use the right alignment flags and let the layout managers do their job.

https://bugzilla.gnome.org/show_bug.cgi?id=694284
2013-02-22 14:58:13 +01:00
9f3afdf928 windowManager: Don't use show_all
It is deprecated and does not make sense there anyway, so use show() instead.

https://bugzilla.gnome.org/show_bug.cgi?id=694441
2013-02-22 14:28:58 +01:00
627a2412d2 ui: Don't use Clutter.Group
It is deprecated use Clutter.Actor instead.

https://bugzilla.gnome.org/show_bug.cgi?id=694441
2013-02-22 14:28:58 +01:00
acffd1e792 main: Guard against NULL log_domain in default handler
g_str_has_prefix() will assert when passed NULL, so we need to make
sure that we are passed a non-NULL log_domain first.

Spotted by <goughost<at>yahoo.com.cn>

https://bugzilla.gnome.org/show_bug.cgi?id=663601
2013-02-22 11:02:00 +01:00
62ca4ba624 appDisplay: Apply the same padding to AllView and FrequentView
We add some horizontal padding to the AllView's content to make
sure content does not end up underneath the scrollbar; while this
is not required in case of the FrequentView which does not have
a scrollbar, applying the same padding ensures that both views
end up with the same spacing, which makes switching between them
less disruptive.

https://bugzilla.gnome.org/show_bug.cgi?id=694261
2013-02-22 10:57:50 +01:00
6ea8f35343 appDisplay: Center AllView content
If the AllView is scrolled, the vertical scrollbar will take away
some horizontal space on one side, resulting in the content ending
up slightly off-center.
Account for this by using overlay-scrollbars instead.

https://bugzilla.gnome.org/show_bug.cgi?id=694261
2013-02-22 10:57:50 +01:00
1bd8c67041 st-scroll-view: Add :overlay-scrollbars property
If enabled, scrollbars take away from the allocation given to the
view's content. This is usually preferrable to painting the bars on
top of the content, but there are exceptions, for instance when the
content needs to be centered with regard to the view as a whole.
Add a :overlay-scrollbars property to account for those cases.

https://bugzilla.gnome.org/show_bug.cgi?id=694261
2013-02-22 10:57:50 +01:00
7425b382d6 appDisplay: Remove scroll view hack in FrequentView
The frequent view should not be scrolled, but to work around the
icon grid overflowing, we used a (non-scrolling) scroll view anyway.
Now that IconGrid:fillParent allows us to avoid overflow, we can
remove this hack.

https://bugzilla.gnome.org/show_bug.cgi?id=694256
2013-02-22 09:50:57 +01:00
5f61b57d63 iconGrid: Add fillParent property
Setting this property will only display as many icons as fit the parent's
allocation, rather than overflowing.

https://bugzilla.gnome.org/show_bug.cgi?id=694256
2013-02-22 09:46:30 +01:00
9db73767d9 appDisplay: Remove unnecessary StBin from hierarchy
The bin is used to top-align views that don't fill the entire height,
but the same can be achieved by setting appropriate expand properties.
2013-02-22 00:07:54 +01:00
c562245c16 main: don't show stage until still frames are loaded
We sometimes map the stage before we've loaded a background on it
because of a race asynchronously loading the session mode.

This manifests as the startup animating starting over a white
background.

This commit defers showing the stage until after the still frames
are loaded.

https://bugzilla.gnome.org/show_bug.cgi?id=694321
2013-02-21 15:01:39 -05:00
9525216d78 messageTray: Fix warning when opening the tray
As the tray hover handler will call _cancelTrayDwell, we need to
ensure this variable is initialized even if tray dwelling isn't.

https://bugzilla.gnome.org/show_bug.cgi?id=694336
2013-02-21 11:56:33 -05:00
28a71a29e6 Revert "messageTray: Fix warning when opening the tray"
This reverts commit 7b06d34ba4.

https://bugzilla.gnome.org/show_bug.cgi?id=694336
2013-02-21 11:52:20 -05:00
7b06d34ba4 messageTray: Fix warning when opening the tray
As the tray hover handler will call _cancelTrayDwell, we need to
ensure this variable is initialized even if tray dwelling isn't.

https://bugzilla.gnome.org/show_bug.cgi?id=694336
2013-02-21 11:40:49 -05:00
656d24e477 overviewControls: don't set padding on the whole overview group
Set it on the control slider actor instead. At the same time, remove
bottom padding from search results actor.

https://bugzilla.gnome.org/show_bug.cgi?id=694287
2013-02-21 11:37:44 -05:00
df0f03d831 overview: Keep open when a Control key is held
It is useful at times to perform several actions that would usually
close the overview (for instance launching an application) at once.
Currently we allow this by dragging items to a workspace rather than
just clicking it, but it's an odd metaphor with its own set of
problems.
Introduce an alternative approach (inspired by file selection in
file managers) by keeping the overview open if a Control key is
held down.

https://bugzilla.gnome.org/show_bug.cgi?id=686984
2013-02-21 17:21:54 +01:00
1db6d15677 overviewControls: fade view selector and thumbnails slider on DnD
When an item is dragged from a page that is not the windows one, the
only possible target is the dash, so fade out the rest.

https://bugzilla.gnome.org/show_bug.cgi?id=686984
2013-02-21 11:16:43 -05:00
08a0479c9e WorkspaceThumbnail: fix mutter warning
Pass a proper timestamp to workspace activation functions

https://bugzilla.gnome.org/show_bug.cgi?id=694365
2013-02-21 16:10:09 +01:00
6682b7dfa5 Updated Russian translation 2013-02-21 18:22:27 +04:00
aad5d98b43 iconGrid: Take extra spacing into account for height requests
This fixes the clipped app picker in the overview.

https://bugzilla.gnome.org/show_bug.cgi?id=694234
2013-02-20 19:38:38 -05:00
a8a4a85dac lg: add a reference to lookingGlass in the Extensions tab.
When the user clicks on "View Source" or "Web Page" in the "Extensions" tab of
looking glass, the callback _onViewSource() or _onWebPage() is called and they
try to close looking glass: this._lookingGlass.close();

But it does not work and generate the exception "this._lookingGlass is
undefined". This patch fixes that.

https://bugzilla.gnome.org/show_bug.cgi?id=693814
2013-02-20 23:14:53 +00:00
ad71b969b2 Workspace: fix stacking of window clones
We must set the stack above property of window clones, or they will
not stack themselves properly when a drag is cancelled.

https://bugzilla.gnome.org/show_bug.cgi?id=694292
2013-02-20 20:56:58 +01:00
8bcb10391e dash: add a workaround for Clutter bug 692744
https://bugzilla.gnome.org/show_bug.cgi?id=690643
2013-02-20 20:51:11 +01:00
8e7d74bc3b dash: fix icon animation
animateIn and animateOut should not reset the scale, otherwise
extra animate calls (which are possible because the diff algorithm
in _redisplay is not optimal) cause unneeded movement.
Therefore, create new items hidden, and have the creator call
animateIn or set the scale/opacity properties manually.
adjustIconSize must be changed to always set the icon size temporarily,
otherwise the first time it computes the icon size with 0 scale.

https://bugzilla.gnome.org/show_bug.cgi?id=690643
2013-02-20 20:51:11 +01:00
629b6faa22 dash: fix allocation loop when increasing icon size
The DashActor will known to allocate the show apps button only if the
icon size is (temporarily) too big for the containing box, therefore
it should request just that as the minimum size.
This solves a glitch that happened when removing a favorite and at the
same time causing the dash to expand.

https://bugzilla.gnome.org/show_bug.cgi?id=690643
2013-02-20 20:51:11 +01:00
ef1e27966d dash: turn DashItemContainer into a proper St.Widget
This removes a number of unneeded ._delegate accesses and cleans up
the code.

https://bugzilla.gnome.org/show_bug.cgi?id=690643
2013-02-20 20:51:11 +01:00
164 changed files with 37025 additions and 23775 deletions

199
NEWS
View File

@ -1,3 +1,202 @@
3.8.3
=====
* Fix child menu regression introduced in 3.8.2 [Florian; #699678]
* Fix alt-tab not always switching back to the previous window [Florian; #700356]
* Fix VPN network icon regression introduced in 3.8.2 [Florian; #700394]
* Allow switch-to-workspace-n keybindings in overview [Florian; #649977]
* Update man page [Matthias; #700339]
* Add FocusSearch DBus method [Florian; #700536]
* gdm: Update the session chooser style [Allan; #695742]
* Fix some app folders getting truncated at the top [Florian; #694371]
* Fix duplicate cursors in screenshots with magnification [Florian; #700488]
* popupMenu: Allow for an optional border for slider handle [Florian; #697917]
* Synchronize input source switching with key events [Rui; #697007]
* Switch input source on modifiers-only accelerator [Rui; #697008]
* Allow input source switching in message tray [Rui; #697009]
* Tweak timeout for activating windows during XDND [Adel; #700150]
* Fix fullscreen windows not being unredirected when legacy tray icons
are around [Adel; #701224]
* Fix ellipsization in control buttons in app picker [Carlos; #696307]
* Fix DND to empty dash [Florian; #684618]
* Fix OSD window appearing below system modal dialogs [Rui; #701269]
* Clear clipboard on screen lock to prevent information leak [Florian; #698922]
* Allow session mode specific overrides schema [Florian; #701717]
* Fix incomplete app menu if multiple actions only become available later
[Xavier; #694612]
* Fix showing the OSD when a fullscreen app is unredirected [Adel, #701224]
* window-switcher: Only show windows from current workspace by default
[Florian; #701214
* Misc bug fixes [Florian, Rui, Giovanni, Stef; #700409, #700625, #700807,
#700842, #700900, #700944, #700190, #700972, #700877]
Contributors:
Giovanni Campagna, Xavier Claessens, Matthias Clasen, Allan Day,
Adel Gadllah, Rui Matos, Florian Müllner, Carlos Soriano, Stef Walter
Translations:
Cheng-Chia Tseng [zh_HK, zh_TW], eternalhui [zh_CN]
3.8.2
=====
* Fix hotcorner regression in RTL locales [Jasper; #698884]
* Allow some keybindings to work while a top bar menu is open [Florian; #698938]
* Make open-app-menu keybinding a toggle action [Florian; #686756]
* ctrlAltTab: Use symbolic icons for desktop windows [Matthias; #697914]
* gdm: Fix regression where domain login hint not shown [Stef; #698200]
* Hide "Open Calendar" item when no calendar app is installed [Lionel; #697725]
* Update how branding appears on login screen [Florian; #694912, #699877]
* Allow OSD popups to grow if necessary [Marta; #696523]
* Fix offset of shadow offscreen rendering [Lionel; #698301]
* Fix insensitive button preventing empty keyring password [Stef; #696304]
* Allow cancelling keyring dialog between prompts [Stef; #682830]
* modalDialog: Show spinner while working [Stef; #684438]
* Provide a DBus API for screencasting [Florian; #696247]
* Implement app folder keynav and shortcuts [Florian; #695314]
* polkitAgent: Allow retrying after mistyped passwords [Stef; #684431]
* Add input purpose and hints to StEntry and StIMText [Daiki; #691392]
* Set input-purpose property for password entries [Rui; #700043]
* Misc fixes and cleanups [Jasper, Florian, Giovanni, Tim, Rui; #697203,
#698959, #696720, #698531, #676285, #698812, #699189]
Contributors:
Giovanni Campagna, Matthias Clasen, Lionel Landwerlin, Tim Lunn, Rui Matos,
Simon McVittie, Marta Milakovic, Florian Müllner, Jasper St. Pierre,
Daiki Ueno, Stef Walter
Translations:
Muhammet Kara [tr], Nik Kalach [ia], Žygimantas Beručka [lt],
Kjartan Maraas [nb]
3.8.1
=====
* Clip window group during startup animation [Jasper; #696323]
* Check for logind rather than systemd [Martin; #696252]
* Don't special-case last remote search provider position [Giovanni; #694974]
* Fix memory leaks [Ray, Jasper; ##697119, #697295, #697300, #697395]
* AppSwitcherPopup: Activate only the selected window if any [Rui; #697480]
* Enable screen recorder keybinding in all modes [Florian; #696200]
* Remove box-shadow from screen shield for performance reasons [Adel; #697274]
* Add support for -st-natural-width/height CSS properties [Giovanni; #664411]
* Remove excessive padding from notification buttons [Allan; #664411]
* Fix thumbnail dragging in overview [Jasper; #697504]
* theme-node: Add get_url()/lookup_url() methods [Florian; #693688]
* Misc bug fixes and cleanups [Jasper, Rui, Colin, David, Ray, Matthias:
#695859, #696259, #696585, #696436, #697432, #697435, #697560, #697722,
#697709]
Contributors:
Giovanni Campagna, Matthias Clasen, Allan Day, Adel Gadllah, David Gumberg,
Rui Matos, Florian Müllner, Martin Pitt, Jasper St. Pierre, Ray Strode,
Colin Walters
Translations:
Daniel Martinez [an], Bruce Cowan [en_GB], Khaled Hosny [ar],
Ihar Hrachyshka [be], Aron Xu [zh_CN], Wojciech Szczęsny [pl],
Inaki Larranaga Murgoitio [eu], Kjartan Maraas [nb],
Милош Поповић [sr, sr@latin], Trần Ngọc Quân [vi]
3.8.0.1
=======
* Background bug fixes [Ray; #696712]
3.8.0
=====
* Remove blur and desaturation from lock screen [Jasper; #696322]
* Remove scroll view fade near edges [Adel; #696404]
* dateMenu: Open calendar component when using Evolution [Florian; #696432]
* Fix unlocking on fast user switch [Cosimo; #696287]
* Tweak screen shield animation [Rui; #696380]
* Fix major memory leak when changing backgrounds [Ray; #696157]
* Miscellaneous bug fixes [Jasper, Adel, Florian; #696199, #696212, #696422,
#696447, #696235]
Contributors:
Giovanni Campagna, Cosimo Cecchi, Adel Gadllah, Rui Matos, Florian Müllner,
Jasper St. Pierre, Ray Strode
Translations:
Alexandre Franke [fr], Victor Ibragimov [tg], Arash Mousavi [fa],
Gabor Kelemen [hu], Sandeep Sheshrao Shedmake [mr], ManojKumar Giri [or],
Shantha kumar [ta], Rajesh Ranjan [hi], Stas Solovey [ru],
Shankar Prasad [kn], Dušan Kazik [sk], Ihar Hrachyshka [be],
Wouter Bolsterlee [nl], Kris Thomsen [da], Jiro Matsuzawa [ja],
Daniel Korostil [uk], Ani Peter [ml], Krishnababu Krothapalli [te],
Mantas Kriaučiūnas [lt], Praveen Illa [te]
3.7.92
======
* Drop fallback lock implementation [Florian; #693403]
* Don't let the user trigger message-tray when in fullscreen [Jasper; #694997]
* Scroll search results when using keynav [Jasper; #689681]
* Allow raising the shield by starting to type the password [Jasper; #686740]
* Improve tracking of fullscreen windows [Owen; #649748]
* Improve animation of new windows in overview [Giovanni; #695582]
* workspace switcher: Animate new workspaces created by DND [Giovanni; #685285]
* Give user time to read messages on login screen [Ray; #694688]
* Misc bug fixes and cleanups [Jasper, Ray, Florian, Cosimo, Giovanni, Adel,
Stef, Takao, Rui, Neil; #695154, #694993, #695272, #691578, #694321, #695338,
#695409, #695458, #695526, #695601, #695471, #695324, #695650, #695656,
#695659, #695485, #695395, #694951, #695824, #695841, #695801, #694321,
#693708, #695800, #695607, #695882, #691578, #685851, #694371, #690857,
#694092, #695747, #696007, #693438, #696064, #696102
Contributors:
Giovanni Campagna, Cosimo Cecchi, Allan Day, Takao Fujiwara, Adel Gadllah,
Tim Lunn, Rui Matos, Florian Müllner, Neil Roberts, Jasper St. Pierre,
Ray Strode, Stef Walter, Colin Walters, Owen W. Taylor
Translations:
Nilamdyuti Goswami [as], Chao-Hsiung Liao [zh_HK, zh_TW],
Yuri Myasoedov [ru], Gheyret Kenji [ug], Baurzhan Muftakhidinov [kk],
Ville-Pekka Vainio [fi], Matej Urbančič [sl],
Мирослав Николић [sr, sr@latin], Rūdolfs Mazurs [lv], Christian Kirbach [de],
Andika Triwidada [id], Gil Forcada [ca], Mattias Põldaru [et],
Duarte Loreto [pt], Adam Matoušek [cs], Changwoo Ryu [ko],
Ihar Hrachyshka [be], Carles Ferrando [ca@valencia], Sweta Kothari [gu]
3.7.91
======
* overview: Fade out controls during DND that are not targets [Cosimo; #686984]
* overview: Keep open when a Control key is held [Florian; #686984]
* Improve login screen => session transition [Ray; #694321]
* Center application grid horizontally [Florian; #694261]
* Fix hiding panel when fullscreen windows span multiple monitors [Adel; 646861]
* Tweak thresholds of pressure barrier [Jasper; #694467]
* Tweak window picker layout [Jasper; #694902]
* Expose key grab DBus API to gnome-settings-daemon [Florian; #643111]
* Don't always show message tray in overview, add message indicator
[Cosimo; #687787]
* Tweak startup animation [Ray; #694326]
* Add OSD popups and expose them to gnome-settings-daemon [Florian; #613543]
* Move loupe icon to the start of the search entry [Jasper; #695069]
* Don't show the input switcher with less than 2 items [Rui; 695000]
* Fix auto-completion of system modals immediately upon display [Stef; #692937]
* Ignore workspaces in alt-tab [Florian; #661156]
* Disable copying text from password entries [Florian; #695104]
* Use standard styling for ibus candidate popups [Allan; #694796]
* Fix calendar changing height on month changes [Giovanni; #641383]
* Port the hot corner to use pressure barriers [Jasper; #663661]
* Misc bug fixes and cleanups: [Hashem, Giovanni, Alban, Jasper, Cosimo,
Florian, Adel, Daniel, Matthias, Ray, Rui, Guillaume, Stef; #685849, #690643,
#694292, #693814, #694234, #694365, #694287, #694336, #694256, #694261,
#663601, #694441, #694284, #694463, #694475, #687248, #694394, #694320,
#694701, #694784, #694858, #694906, #694327, #694876, #694905, #694969,
#694970, #694988, #695006, #695001, #694998, #695023, #695002, #695073,
#695126, #687748, #694837, #693907, #679851, #694988]
Contributors:
Giovanni Campagna, Cosimo Cecchi, Matthias Clasen, Alban Crequy, Allan Day,
Guillaume Desmottes, Adel Gadllah, Rui Matos, Daniel Mustieles,
Hashem Nasarat, Jasper St. Pierre, Ray Strode, Stef Walter
Translations:
Yuri Myasoedov [ru], Adam Matoušek [cs], Piotr Drąg [pl], Matej Urbančič [sl],
Sweta Kothari [gu], Kjartan Maraas [nb], Nguyễn Thái Ngọc Duy [vi],
Chao-Hsiung Liao [zh_HK, zh_TW], Dimitris Spingos [el],
Inaki Larranaga Murgoitio [eu], Luca Ferretti [it], A S Alam [pa],
Gheyret Kenji [ug], Stas Solovey [ru], Enrico Nicoletto [pt_BR],
Fran Diéguez [gl], Daniel Mustieles [es], Aurimas Černius [lt]
3.7.90
======
* Let GNOME Shell work on EGL and GLES2 [Neil; #693225, #693438, #693339]

View File

@ -1,5 +1,5 @@
AC_PREREQ(2.63)
AC_INIT([gnome-shell],[3.7.90],[https://bugzilla.gnome.org/enter_bug.cgi?product=gnome-shell],[gnome-shell])
AC_INIT([gnome-shell],[3.8.3],[https://bugzilla.gnome.org/enter_bug.cgi?product=gnome-shell],[gnome-shell])
AC_CONFIG_HEADERS([config.h])
AC_CONFIG_SRCDIR([src/shell-global.c])
@ -63,16 +63,15 @@ AM_CONDITIONAL(BUILD_RECORDER, $build_recorder)
CLUTTER_MIN_VERSION=1.13.4
GOBJECT_INTROSPECTION_MIN_VERSION=0.10.1
GJS_MIN_VERSION=1.35.4
MUTTER_MIN_VERSION=3.7.90
MUTTER_MIN_VERSION=3.8.3
GTK_MIN_VERSION=3.7.9
GIO_MIN_VERSION=2.35.0
LIBECAL_MIN_VERSION=3.5.3
LIBEDATASERVER_MIN_VERSION=3.5.3
TELEPATHY_GLIB_MIN_VERSION=0.17.5
TELEPATHY_LOGGER_MIN_VERSION=0.2.4
POLKIT_MIN_VERSION=0.100
STARTUP_NOTIFICATION_MIN_VERSION=0.11
GCR_MIN_VERSION=3.3.90
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.6
@ -94,11 +93,10 @@ PKG_CHECK_MODULES(GNOME_SHELL, gio-unix-2.0 >= $GIO_MIN_VERSION
gobject-introspection-1.0 >= $GOBJECT_INTROSPECTION_MIN_VERSION
libcanberra libcanberra-gtk3
telepathy-glib >= $TELEPATHY_GLIB_MIN_VERSION
telepathy-logger-0.2 >= $TELEPATHY_LOGGER_MIN_VERSION
polkit-agent-1 >= $POLKIT_MIN_VERSION xfixes
libnm-glib libnm-util >= $NETWORKMANAGER_MIN_VERSION
libnm-gtk >= $NETWORKMANAGER_MIN_VERSION
gnome-keyring-1 gcr-3 >= $GCR_MIN_VERSION)
libsecret-unstable gcr-base-3 >= $GCR_MIN_VERSION)
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)

View File

@ -1,3 +1,6 @@
wandadir = $(pkgdatadir)
dist_wanda_DATA = wanda.png
desktopdir=$(datadir)/applications
desktop_DATA = gnome-shell.desktop gnome-shell-extension-prefs.desktop
@ -12,6 +15,7 @@ desktop_DATA = gnome-shell.desktop gnome-shell-extension-prefs.desktop
introspectiondir = $(datadir)/dbus-1/interfaces
introspection_DATA = \
org.gnome.Shell.Screencast.xml \
org.gnome.Shell.Screenshot.xml \
org.gnome.ShellSearchProvider.xml \
org.gnome.ShellSearchProvider2.xml

View File

@ -0,0 +1,96 @@
<!DOCTYPE node PUBLIC
'-//freedesktop//DTD D-BUS Object Introspection 1.0//EN'
'http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd'>
<node>
<!--
org.gnome.Shell.Screencast:
@short_description: Screencast interface
The interface used to record screen contents.
-->
<interface name="org.gnome.Shell.Screencast">
<!--
Screencast:
@file_template: the template for the filename to use
@options: a dictionary of optional parameters
@success: whether the screencast was started successfully
@filename_used: the file where the screencast is being saved
Records a screencast of the whole screen and saves it
(by default) as webm video under a filename derived from
@file_template. The template is either a relative or absolute
filename which may contain some escape sequences - %d and %t
will be replaced by the start date and time of the recording.
If a relative name is used, the screencast will be saved in the
$XDG_VIDEOS_DIR if it exists, or the home directory otherwise.
The actual filename of the saved video is returned in @filename_used.
The set of optional parameters in @options currently consists of:
'draw-cursor'(b): whether the cursor should be included in the
recording (true)
'framerate'(i): the number of frames per second that should be
recorded if possible (30)
'pipeline'(s): the GStreamer pipeline used to encode recordings
in gst-launch format; if not specified, the
recorder will produce vp8 (webm) video (unset)
-->
<method name="Screencast">
<arg type="s" direction="in" name="file_template"/>
<arg type="a{sv}" direction="in" name="options"/>
<arg type="b" direction="in" name="flash"/>
<arg type="b" direction="out" name="success"/>
<arg type="s" direction="out" name="filename_used"/>
</method>
<!--
ScreencastArea:
@x: the X coordinate of the area to capture
@y: the Y coordinate of the area to capture
@width: the width of the area to capture
@height: the height of the area to capture
@file_template: the template for the filename to use
@options: a dictionary of optional parameters
@success: whether the screencast was started successfully
@filename_used: the file where the screencast is being saved
Records a screencast of the passed in area and saves it
(by default) as webm video under a filename derived from
@file_template. The template is either a relative or absolute
filename which may contain some escape sequences - %d and %t
will be replaced by the start date and time of the recording.
If a relative name is used, the screencast will be saved in the
$XDG_VIDEOS_DIR if it exists, or the home directory otherwise.
The actual filename of the saved video is returned in @filename_used.
The set of optional parameters in @options currently consists of:
'draw-cursor'(b): whether the cursor should be included in the
recording (true)
'framerate'(i): the number of frames per second that should be
recorded if possible (30)
'pipeline'(s): the GStreamer pipeline used to encode recordings
in gst-launch format; if not specified, the
recorder will produce vp8 (webm) video (unset)
-->
<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>
<!--
StopScreencast:
@success: whether stopping the recording was successful
Stop the recording started by either Screencast or ScreencastArea.
-->
<method name="StopScreencast">
<arg type="b" direction="out" name="success"/>
</method>
</interface>
</node>

View File

@ -207,7 +207,7 @@ value here is from the GsmPresenceStatus enumeration.</_summary>
</_description>
</key>
<key type="b" name="current-workspace-only">
<default>false</default>
<default>true</default>
<summary>Limit switcher to current workspace.</summary>
<description>
If true, only windows from the current workspace are shown in the switcher.

View File

@ -125,7 +125,8 @@ StScrollBar StButton#vhandle:active {
/* PopupMenu */
.popup-menu-boxpointer {
.popup-menu-boxpointer,
.candidate-popup-boxpointer {
-arrow-border-radius: 8px;
-arrow-background-color: rgba(0,0,0,0.9);
-arrow-border-width: 2px;
@ -315,10 +316,20 @@ StScrollBar StButton#vhandle:active {
.notification-button:focus,
.notification-icon-button:focus,
.hotplug-notification-item:focus,
.modal-dialog-button:focus {
.modal-dialog-button:focus,
.app-view-control:focus {
border-width: 2px;
}
.app-view-control:focus {
padding: 3px;
}
.app-view-control:first-child:ltr:focus,
.app-view-control:last-child:rtl:focus {
border-right-width: 1px;
}
.candidate-page-button:active,
.candidate-page-button:pressed,
.notification-button:active,
@ -501,6 +512,7 @@ StScrollBar StButton#vhandle:active {
}
#appMenu {
spinner-image: url("process-working.svg");
spacing: 4px;
}
@ -644,6 +656,9 @@ StScrollBar StButton#vhandle:active {
#overview {
spacing: 24px;
}
.overview-controls {
padding-bottom: 32px;
}
@ -731,13 +746,36 @@ StScrollBar StButton#vhandle:active {
-vertical-spacing: 32px;
padding-left: 32px;
padding-right: 32px;
padding-bottom: 32px;
padding-bottom: 48px;
}
.window-picker.external-monitor {
padding: 32px;
}
.messages-indicator {
color: #999999;
height: 32px;
}
.messages-indicator-contents {
spacing: 12px;
padding-bottom: 12px;
}
.messages-indicator-contents:hover {
color: white;
text-shadow: black 0px 2px 2px;
}
.messages-indicator-highlight {
background-gradient-start: transparent;
background-gradient-end: #999999;
background-gradient-direction: vertical;
height: 6px;
}
/* Dash */
#dash {
@ -762,6 +800,11 @@ StScrollBar StButton#vhandle:active {
height: 24px;
}
.empty-dash-drop-target {
width: 24px;
height: 24px;
}
/* Search Box */
#searchEntry {
@ -781,7 +824,7 @@ StScrollBar StButton#vhandle:active {
/* Search Results */
#searchResults {
padding: 20px 10px 10px 10px;
padding: 20px 10px 0px 10px;
spacing: 18px;
}
@ -849,16 +892,18 @@ StScrollBar StButton#vhandle:active {
}
.app-view-controls {
width: 250px;
padding-bottom: 32px;
}
.app-view-control {
padding: 4px 16px;
padding: 4px 32px;
}
StScrollView.frequent-apps StScrollBar {
min-width: 0px;
width: 0px;
.search-display > StBoxLayout,
.all-apps > StBoxLayout,
.frequent-apps > StBoxLayout {
/* horizontal padding to make sure scrollbars or dash don't overlap content */
padding: 0px 88px;
}
.app-folder-icon {
@ -881,8 +926,6 @@ StScrollView.frequent-apps StScrollBar {
}
.list-search-result-description {
font-weight: bold;
font-size: 12pt;
color: #eeeeec;
}
@ -936,6 +979,14 @@ StScrollView.frequent-apps StScrollBar {
color:white;
}
.app-display .app-well-app > .overview-icon {
border-radius: 10px;
}
.list-search-result:hover .list-search-result-description {
text-shadow: rgba(0,0,0,0.8) 0px 1px 2px;
}
.show-apps {
padding: 4px 0;
}
@ -1226,15 +1277,15 @@ StScrollView.frequent-apps StScrollBar {
font-weight: bold;
}
.calendar-other-month-day {
color: #333333;
}
.calendar-day-with-events {
font-weight: bold;
color: white;
}
.calendar-other-month-day {
color: #333333;
}
.events-header-vbox {
spacing: 6pt;
padding-right: .5em;
@ -1407,11 +1458,13 @@ StScrollView.frequent-apps StScrollBar {
}
.notification-button {
padding: 4px 42px 5px;
-st-natural-width: 140px;
padding: 4px 4px 5px;
}
.notification-button:focus {
padding: 3px 41px 4px;
-st-natural-width: 138px;
padding: 3px 4px 4px;
}
.notification-icon-button {
@ -1577,12 +1630,26 @@ StScrollView.frequent-apps StScrollBar {
-shell-counter-overlap-y: 13px;
}
/* OSD */
.osd-window {
text-align: center;
font-weight: bold;
spacing: 1em;
}
.osd-window .level {
height: 0.6em;
border-radius: 0.3em;
background-color: rgba(190,190,190,0.2);
}
/* App Switcher */
.switcher-popup {
padding: 8px;
spacing: 16px;
}
.osd-window,
.switcher-list {
background: rgba(0,0,0,0.8);
border: 1px solid rgba(128,128,128,0.40);
@ -2084,23 +2151,12 @@ StScrollView.frequent-apps StScrollBar {
}
/* IBus Candidate Popup */
.candidate-popup-boxpointer {
-arrow-border-radius: 8px;
-arrow-background-color: #707070;
-arrow-border-width: 0px;
-arrow-base: 24px;
-arrow-rise: 11px;
}
.candidate-popup-content {
padding: 0.5em;
spacing: 0.3em;
}
.candidate-popup-text {
font-size: 9pt;
}
.candidate-index {
padding: 0 0.5em 0 0;
color: #cccccc;
@ -2166,6 +2222,9 @@ StScrollView.frequent-apps StScrollBar {
border: none;
background-color: transparent;
padding-bottom: 80px;
padding-top: 80px;
border-radius: 16px;
min-height: 150px;
max-height: 700px;
@ -2283,52 +2342,47 @@ StScrollView.frequent-apps StScrollBar {
width: 15em;
}
.login-dialog-session-list {
color: #ffffff;
font-size: 10.5pt;
.login-dialog-session-list,
.login-dialog-session-list-item {
color: #babdb6;
}
.login-dialog-session-list-button:focus,
.login-dialog-session-list-button:active,
.login-dialog-session-list-button:hover,
.login-dialog-session-list-item:focus,
.login-dialog-session-list-item:hover {
color: white;
}
.login-dialog-session-list-button {
padding: 4px;
}
.login-dialog-session-list-button:focus {
background-color: #4c4c4c;
}
.login-dialog-session-list-button:active {
background-color: #4c4c4c;
}
.login-dialog-session-list-button:hover {
font-weight: bold;
}
.login-dialog-session-list-scroll-view {
background-gradient-start: rgba(80,80,80,0.3);
background-gradient-end: rgba(80,80,80,0.7);
background-gradient-direction: vertical;
box-shadow: inset 0px 2px 4px rgba(0,0,0,0.9);
border-radius: 8px;
border: 1px solid rgba(80,80,80,1.0);
padding: .5em;
padding: 6px;
}
.login-dialog-session-list-item:focus {
background-color: #666666;
.login-dialog-session-list-item {
padding-bottom: 6px;
}
.login-dialog-session-list-triangle {
padding-right: .5em;
padding-right: 6px;
}
.login-dialog-session-list-item-box {
spacing: .25em;
padding-left: 6px;
spacing: 6px;
}
.login-dialog-session-list-item-dot {
width: .75em;
height: .75em;
width: 10px;
height: 10px;
}
.login-dialog-logo-bin {
padding: 24px 0px;
}
.login-dialog .modal-dialog-button-box {
@ -2393,7 +2447,6 @@ StScrollView.frequent-apps StScrollBar {
.screen-shield-background {
background: black;
box-shadow: 0px 4px 8px rgba(0,0,0,0.9);
}
#lockDialogGroup {
@ -2480,7 +2533,7 @@ StScrollView.frequent-apps StScrollBar {
}
.input-source-switcher-symbol {
font-size: 42pt;
font-size: 34pt;
width: 96px;
height: 96px;
}

BIN
data/wanda.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

View File

@ -46,6 +46,7 @@
<xi:include href="doc-gen-org.gnome.Shell.SearchProvider.xml"/>
<xi:include href="doc-gen-org.gnome.Shell.SearchProvider2.xml"/>
<xi:include href="xml/shell-global.xml"/>
<xi:include href="xml/shell-keybinding-modes.xml"/>
<xi:include href="xml/shell-wm.xml"/>
<xi:include href="xml/shell-xfixes-cursor.xml"/>
<xi:include href="xml/shell-util.xml"/>

View File

@ -66,11 +66,4 @@ its dependencies to build from tarballs.</description>
<gnome:userid>fmuellner</gnome:userid>
</foaf:Person>
</maintainer>
<maintainer>
<foaf:Person>
<foaf:name>Ray Strode</foaf:name>
<foaf:mbox rdf:resource="mailto:halfline@gmail.com" />
<gnome:userid>halfline</gnome:userid>
</foaf:Person>
</maintainer>
</Project>

View File

@ -69,6 +69,7 @@ nobase_dist_js_DATA = \
ui/shellEntry.js \
ui/shellMountOperation.js \
ui/notificationDaemon.js \
ui/osdWindow.js \
ui/overview.js \
ui/overviewControls.js \
ui/panel.js \
@ -77,6 +78,7 @@ nobase_dist_js_DATA = \
ui/popupMenu.js \
ui/remoteSearch.js \
ui/runDialog.js \
ui/screencast.js \
ui/screenshot.js \
ui/screenShield.js \
ui/scripting.js \

View File

@ -45,6 +45,7 @@ const Application = new Lang.Class({
this._extensionPrefsModules = {};
this._extensionIters = {};
this._startupUuid = null;
},
_buildModel: function() {
@ -203,6 +204,7 @@ 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();
},
@ -212,6 +214,11 @@ const Application = new Lang.Class({
this._extensionIters[extension.uuid] = iter;
},
_extensionsLoaded: function() {
if (this._startupUuid && this._extensionAvailable(this._startupUuid))
this._selectExtension(this._startupUuid);
this._startupUuid = null;
},
_onActivate: function() {
this._window.present();
@ -232,10 +239,10 @@ const Application = new Lang.Class({
// Strip off "extension:///" prefix which fakes a URI, if it exists
uuid = stripPrefix(uuid, "extension:///");
if (!this._extensionAvailable(uuid))
return 1;
this._selectExtension(uuid);
if (this._extensionAvailable(uuid))
this._selectExtension(uuid);
else
this._startupUuid = uuid;
}
return 0;
}

View File

@ -28,6 +28,7 @@ const Mainloop = imports.mainloop;
const Meta = imports.gi.Meta;
const Lang = imports.lang;
const Pango = imports.gi.Pango;
const Realmd = imports.gdm.realmd;
const Signals = imports.signals;
const Shell = imports.gi.Shell;
const St = imports.gi.St;
@ -39,7 +40,6 @@ const GdmUtil = imports.gdm.util;
const Lightbox = imports.ui.lightbox;
const Main = imports.ui.main;
const ModalDialog = imports.ui.modalDialog;
const Panel = imports.ui.panel;
const PanelMenu = imports.ui.panelMenu;
const Tweener = imports.ui.tweener;
const UserMenu = imports.ui.userMenu;
@ -48,44 +48,10 @@ const UserWidget = imports.ui.userWidget;
const _FADE_ANIMATION_TIME = 0.25;
const _SCROLL_ANIMATION_TIME = 0.5;
const _TIMED_LOGIN_IDLE_THRESHOLD = 5.0;
const _LOGO_ICON_HEIGHT = 16;
const WORK_SPINNER_ICON_SIZE = 24;
const WORK_SPINNER_ANIMATION_DELAY = 1.0;
const WORK_SPINNER_ANIMATION_TIME = 0.3;
const _LOGO_ICON_HEIGHT = 48;
let _loginDialog = null;
const LogoMenuButton = new Lang.Class({
Name: 'LogoMenuButton',
Extends: PanelMenu.Button,
_init: function() {
this.parent(0.0, null, true);
this._settings = new Gio.Settings({ schema: GdmUtil.LOGIN_SCREEN_SCHEMA });
this._settings.connect('changed::' + GdmUtil.LOGO_KEY,
Lang.bind(this, this._updateLogo));
this._iconBin = new St.Bin();
this.actor.add_actor(this._iconBin);
this._updateLogo();
},
_updateLogo: function() {
let path = this._settings.get_string(GdmUtil.LOGO_KEY);
let icon = null;
if (path) {
let file = Gio.file_new_for_path(path);
let cache = St.TextureCache.get_default();
icon = cache.load_uri_async(file.get_uri(), -1, _LOGO_ICON_HEIGHT);
}
this._iconBin.set_child(icon);
}
});
const UserListItem = new Lang.Class({
Name: 'UserListItem',
@ -552,6 +518,12 @@ const LoginDialog = new Lang.Class({
Lang.bind(this, this._updateBanner));
this._settings.connect('changed::' + GdmUtil.DISABLE_USER_LIST_KEY,
Lang.bind(this, this._updateDisableUserList));
this._settings.connect('changed::' + GdmUtil.LOGO_KEY,
Lang.bind(this, this._updateLogo));
this._textureCache = St.TextureCache.get_default();
this._textureCache.connect('texture-file-changed',
Lang.bind(this, this._updateLogoTexture));
this._userSelectionBox = new St.BoxLayout({ style_class: 'login-dialog-user-selection-box',
vertical: true });
@ -594,6 +566,7 @@ const LoginDialog = new Lang.Class({
this._promptEntry = new St.Entry({ style_class: 'login-dialog-prompt-entry',
can_focus: true });
this._promptEntryTextChangedId = 0;
this._promptEntryActivateId = 0;
this._promptBox.add(this._promptEntry,
{ expand: true,
x_fill: true,
@ -608,7 +581,6 @@ const LoginDialog = new Lang.Class({
this._promptBox.add(this._promptLoginHint);
this._signInButton = null;
this._workSpinner = null;
this._sessionList = new SessionList();
this._sessionList.connect('session-activated',
@ -643,6 +615,11 @@ const LoginDialog = new Lang.Class({
x_align: St.Align.START,
x_fill: true });
this._logoBin = new St.Bin({ style_class: 'login-dialog-logo-bin', y_expand: true });
this._logoBin.set_y_align(Clutter.ActorAlign.END);
this.backgroundStack.add_actor(this._logoBin);
this._updateLogo();
if (!this._userManager.is_loaded)
this._userManagerLoadedId = this._userManager.connect('notify::is-loaded',
Lang.bind(this, function() {
@ -689,7 +666,27 @@ const LoginDialog = new Lang.Class({
}
},
_updateLogoTexture: function(cache, uri) {
if (this._logoFileUri != uri)
return;
let icon = null;
if (this._logoFileUri)
icon = this._textureCache.load_uri_async(this._logoFileUri,
-1, _LOGO_ICON_HEIGHT);
this._logoBin.set_child(icon);
},
_updateLogo: function() {
let path = this._settings.get_string(GdmUtil.LOGO_KEY);
this._logoFileUri = path ? Gio.file_new_for_path(path).get_uri() : null;
this._updateLogoTexture(this._textureCache, this._logoFileUri);
},
_reset: function() {
this._userVerifier.clear();
this._updateSensitivity(true);
this._promptMessage.hide();
this._user = null;
@ -705,7 +702,7 @@ const LoginDialog = new Lang.Class({
this._promptEntry.text = '';
this._updateSensitivity(true);
this._setWorking(false);
this.setWorking(false);
},
_onDefaultSessionChanged: function(client, sessionId) {
@ -753,7 +750,7 @@ const LoginDialog = new Lang.Class({
time: _FADE_ANIMATION_TIME,
transition: 'easeOutQuad' });
if (!this._user || (this._user.is_logged_in() && this._verifyingUser))
if ((this._user && !this._user.is_logged_in()) || this._verifyingUser)
this._sessionList.actor.show();
this._promptEntry.grab_key_focus();
@ -771,10 +768,6 @@ const LoginDialog = new Lang.Class({
},
_prepareDialog: function(forSecret, hold) {
this._workSpinner = new Panel.AnimatedIcon('process-working.svg', WORK_SPINNER_ICON_SIZE);
this._workSpinner.actor.opacity = 0;
this._workSpinner.actor.show();
this.buttonLayout.visible = true;
this.clearButtons();
@ -787,12 +780,11 @@ const LoginDialog = new Lang.Class({
y_fill: false,
x_align: St.Align.START,
y_align: St.Align.MIDDLE });
this.buttonLayout.add(this._workSpinner.actor,
{ expand: false,
x_fill: false,
y_fill: false,
x_align: St.Align.END,
y_align: St.Align.MIDDLE });
this.placeSpinner({ expand: false,
x_fill: false,
y_fill: false,
x_align: St.Align.END,
y_align: St.Align.MIDDLE });
this._signInButton = this.addButton({ action: Lang.bind(this, function() {
hold.release();
}),
@ -811,6 +803,11 @@ const LoginDialog = new Lang.Class({
Lang.bind(this, function() {
this._updateSignInButtonSensitivity(this._promptEntry.text.length > 0);
}));
this._promptEntryActivateId =
this._promptEntry.clutter_text.connect('activate', function() {
hold.release();
});
},
_updateSensitivity: function(sensitive) {
@ -835,7 +832,12 @@ const LoginDialog = new Lang.Class({
this._promptEntryTextChangedId = 0;
}
this._setWorking(false);
if (this._promptEntryActivateId > 0) {
this._promptEntry.clutter_text.disconnect(this._promptEntryActivateId);
this._promptEntryActivateId = 0;
}
this.setWorking(false);
this._promptBox.hide();
this._promptLoginHint.hide();
@ -848,36 +850,9 @@ const LoginDialog = new Lang.Class({
this._promptLoginHint.hide();
this.clearButtons();
this._workSpinner = null;
this._signInButton = null;
},
_setWorking: function(working) {
if (!this._workSpinner)
return;
if (working) {
this._workSpinner.play();
Tweener.addTween(this._workSpinner.actor,
{ opacity: 255,
delay: WORK_SPINNER_ANIMATION_DELAY,
time: WORK_SPINNER_ANIMATION_TIME,
transition: 'linear'
});
} else {
Tweener.addTween(this._workSpinner.actor,
{ opacity: 0,
time: WORK_SPINNER_ANIMATION_TIME,
transition: 'linear',
onCompleteScope: this,
onComplete: function() {
if (this._workSpinner)
this._workSpinner.stop();
}
});
}
},
_askQuestion: function(verifier, serviceName, question, passwordChar) {
this._promptLabel.set_text(question);
@ -892,7 +867,7 @@ const LoginDialog = new Lang.Class({
function() {
let text = this._promptEntry.get_text();
this._updateSensitivity(false);
this._setWorking(true);
this.setWorking(true);
this._userVerifier.answerQuery(serviceName, text);
}];
@ -900,24 +875,47 @@ const LoginDialog = new Lang.Class({
return batch.run();
},
_showRealmLoginHint: function(realmManager, hint) {
if (!hint)
return;
hint = hint.replace(/%U/g, 'user');
hint = hint.replace(/%D/g, 'DOMAIN');
hint = hint.replace(/%[^UD]/g, '');
// 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._showLoginHint(null, _("(e.g., user or %s)").format(hint));
},
_askForUsernameAndLogIn: function() {
this._promptLabel.set_text(_("Username: "));
this._promptEntry.set_text('');
this._promptEntry.clutter_text.set_password_char('');
let realmManager = new Realmd.Manager();
let signalId = realmManager.connect('login-format-changed',
Lang.bind(this, this._showRealmLoginHint));
this._showRealmLoginHint(realmManager.loginFormat);
let tasks = [this._showPrompt,
function() {
let userName = this._promptEntry.get_text();
this._promptEntry.reactive = false;
return this._beginVerificationForUser(userName);
},
function() {
realmManager.disconnect(signalId)
realmManager.release();
}];
let batch = new Batch.ConsecutiveBatch(this, tasks);
return batch.run();
},
_onSessionOpened: function(client, serviceName) {
_startSession: function(serviceName) {
Tweener.addTween(this.dialogLayout,
{ opacity: 0,
time: _FADE_ANIMATION_TIME,
@ -940,6 +938,18 @@ const LoginDialog = new Lang.Class({
onCompleteScope: this });
},
_onSessionOpened: function(client, serviceName) {
if (!this._userVerifier.hasPendingMessages) {
this._startSession(serviceName);
} else {
let signalId = this._userVerifier.connect('no-more-messages',
Lang.bind(this, function() {
this._userVerifier.disconnect(signalId);
this._startSession(serviceName);
}));
}
},
_waitForItemForUser: function(userName) {
let item = this._userList.getItemFromUserName(userName);
@ -1003,7 +1013,7 @@ const LoginDialog = new Lang.Class({
function() {
// If we're just starting out, start on the right
// item.
if (!this.is_loaded) {
if (!this._userManager.is_loaded) {
this._userList.jumpToItem(this._timedLoginItem);
}
},
@ -1141,15 +1151,6 @@ const LoginDialog = new Lang.Class({
Lang.bind(this, function(userManager, user) {
this._userList.removeUser(user);
}));
// emitted in idle so caller doesn't have to explicitly check if
// it's loaded immediately after construction
// (since there's no way the caller could be listening for
// 'loaded' yet)
Mainloop.idle_add(Lang.bind(this, function() {
this.emit('loaded');
this.is_loaded = true;
}));
},
_onOpened: function() {
@ -1164,5 +1165,9 @@ const LoginDialog = new Lang.Class({
this.parent();
Main.ctrlAltTabManager.removeGroup(this.dialogLayout);
}
},
addCharacter: function(unichar) {
this._promptEntry.clutter_text.insert_unichar(unichar);
},
});

View File

@ -63,7 +63,7 @@ const Manager = new Lang.Class({
Lang.bind(this, this._reloadRealms))
this._realms = {};
this._aggregateProvider.connect('g-properties-changed',
this._signalId = this._aggregateProvider.connect('g-properties-changed',
Lang.bind(this, function(proxy, properties) {
if ('Realms' in properties.deep_unpack())
this._reloadRealms();
@ -106,7 +106,7 @@ const Manager = new Lang.Class({
realm.connect('g-properties-changed',
Lang.bind(this, function(proxy, properties) {
if ('Configured' in properties.deep_unpack())
this._reloadRealm();
this._reloadRealm(realm);
}));
},
@ -134,6 +134,18 @@ const Manager = new Lang.Class({
this._updateLoginFormat();
return this._loginFormat;
},
release: function() {
Service(Gio.DBus.system,
'org.freedesktop.realmd',
'/org/freedesktop/realmd',
function(service) {
service.ReleaseRemote();
});
this._aggregateProvider.disconnect(this._signalId);
this._realms = { };
this._updateLoginFormat();
}
});
Signals.addSignalMethods(Manager.prototype)

View File

@ -2,13 +2,13 @@
const Clutter = imports.gi.Clutter;
const Gio = imports.gi.Gio;
const GLib = imports.gi.GLib;
const Lang = imports.lang;
const Mainloop = imports.mainloop;
const Signals = imports.signals;
const Batch = imports.gdm.batch;
const Fprint = imports.gdm.fingerprint;
const Realmd = imports.gdm.realmd;
const Main = imports.ui.main;
const Params = imports.misc.params;
const Tweener = imports.ui.tweener;
@ -27,6 +27,9 @@ const ALLOWED_FAILURES_KEY = 'allowed-failures';
const LOGO_KEY = 'logo';
const DISABLE_USER_LIST_KEY = 'disable-user-list';
// Give user 16ms to read each character of a PAM message
const USER_READ_TIME = 16
function fadeInActor(actor) {
if (actor.opacity == 255 && actor.visible)
return null;
@ -113,7 +116,9 @@ const ShellUserVerifier = new Lang.Class({
this._settings = new Gio.Settings({ schema: LOGIN_SCREEN_SCHEMA });
this._fprintManager = new Fprint.FprintManager();
this._realmManager = new Realmd.Manager();
this._messageQueue = [];
this._messageQueueTimeoutId = 0;
this.hasPendingMessages = false;
this._failCounter = 0;
},
@ -153,13 +158,73 @@ const ShellUserVerifier = new Lang.Class({
this._userVerifier.run_dispose();
this._userVerifier = null;
}
this._clearMessageQueue();
},
answerQuery: function(serviceName, answer) {
// Clear any previous message
this.emit('show-message', null, null);
if (!this._userVerifier.hasPendingMessages) {
this._userVerifier.call_answer_query(serviceName, answer, this._cancellable, null);
} else {
let signalId = this._userVerifier.connect('no-more-messages',
Lang.bind(this, function() {
this._userVerifier.disconnect(signalId);
this._userVerifier.call_answer_query(serviceName, answer, this._cancellable, null);
}));
}
},
this._userVerifier.call_answer_query(serviceName, answer, this._cancellable, null);
_getIntervalForMessage: function(message) {
// We probably could be smarter here
return message.length * USER_READ_TIME;
},
finishMessageQueue: function() {
if (!this.hasPendingMessages)
return;
this._messageQueue = [];
this.hasPendingMessages = false;
this.emit('no-more-messages');
},
_queueMessageTimeout: function() {
if (this._messageQueue.length == 0) {
this.finishMessageQueue();
return;
}
if (this._messageQueueTimeoutId != 0)
return;
let message = this._messageQueue.shift();
this.emit('show-message', message.text, message.iconName);
this._messageQueueTimeoutId = GLib.timeout_add(GLib.PRIORITY_DEFAULT,
message.interval,
Lang.bind(this, function() {
this._messageQueueTimeoutId = 0;
this._queueMessageTimeout();
}));
},
_queueMessage: function(message, iconName) {
let interval = this._getIntervalForMessage(message);
this.hasPendingMessages = true;
this._messageQueue.push({ text: message, interval: interval, iconName: iconName });
this._queueMessageTimeout();
},
_clearMessageQueue: function() {
this.finishMessageQueue();
if (this._messageQueueTimeoutId != 0) {
GLib.source_remove(this._messageQueueTimeoutId);
this._messageQueueTimeoutId = 0;
}
this.emit('show-message', null, null);
},
_checkForFingerprintReader: function() {
@ -179,7 +244,7 @@ const ShellUserVerifier = new Lang.Class({
logError(error, where);
this._hold.release();
this.emit('show-message', _("Authentication error"), 'login-dialog-message-warning');
this._queueMessage(_("Authentication error"), 'login-dialog-message-warning');
this._verificationFailed(false);
},
@ -298,7 +363,7 @@ const ShellUserVerifier = new Lang.Class({
// to indicate the user can swipe their finger instead
this.emit('show-login-hint', _("(or swipe finger)"));
} else if (serviceName == PASSWORD_SERVICE_NAME) {
this.emit('show-message', info, 'login-dialog-message-info');
this._queueMessage(info, 'login-dialog-message-info');
}
},
@ -307,22 +372,7 @@ const ShellUserVerifier = new Lang.Class({
// users who haven't enrolled their fingerprint.
if (serviceName != PASSWORD_SERVICE_NAME)
return;
this.emit('show-message', problem, 'login-dialog-message-warning');
},
_showRealmLoginHint: function() {
if (this._realmManager.loginFormat) {
let hint = this._realmManager.loginFormat;
hint = hint.replace(/%U/g, 'user');
hint = hint.replace(/%D/g, 'DOMAIN');
hint = hint.replace(/%[^UD]/g, '');
// 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.emit('show-login-hint',
_("(e.g., user or %s)").format(hint));
}
this._queueMessage(problem, 'login-dialog-message-warning');
},
_onInfoQuery: function(client, serviceName, question) {
@ -330,10 +380,6 @@ const ShellUserVerifier = new Lang.Class({
if (serviceName != PASSWORD_SERVICE_NAME)
return;
this._showRealmLoginHint();
this._realmLoginHintSignalId = this._realmManager.connect('login-format-changed',
Lang.bind(this, this._showRealmLoginHint));
this.emit('ask-question', serviceName, question, '');
},
@ -346,8 +392,6 @@ const ShellUserVerifier = new Lang.Class({
},
_onReset: function() {
this.clear();
// Clear previous attempts to authenticate
this._failCounter = 0;
@ -358,6 +402,15 @@ const ShellUserVerifier = new Lang.Class({
this.emit('verification-complete');
},
_cancelAndReset: function() {
this.cancel();
this._onReset();
},
_retry: function() {
this.begin(this._userName, new Batch.Hold());
},
_verificationFailed: function(retry) {
// For Not Listed / enterprise logins, immediately reset
// the dialog
@ -369,15 +422,25 @@ const ShellUserVerifier = new Lang.Class({
this._failCounter < this._settings.get_int(ALLOWED_FAILURES_KEY);
if (canRetry) {
this.clear();
this.begin(this._userName, new Batch.Hold());
if (!this._userVerifier.hasPendingMessages) {
this._retry();
} else {
let signalId = this._userVerifier.connect('no-more-messages',
Lang.bind(this, function() {
this._userVerifier.disconnect(signalId);
this._retry();
}));
}
} else {
// Allow some time to see the message, then reset everything
Mainloop.timeout_add(3000, Lang.bind(this, function() {
this.cancel();
this._onReset();
}));
if (!this._userVerifier.hasPendingMessages) {
this._cancelAndReset();
} else {
let signalId = this._userVerifier.connect('no-more-messages',
Lang.bind(this, function() {
this._userVerifier.disconnect(signalId);
this._cancelAndReset();
}));
}
}
this.emit('verification-failed');
@ -392,11 +455,6 @@ const ShellUserVerifier = new Lang.Class({
}
this.emit('hide-login-hint');
if (this._realmLoginHintSignalId) {
this._realmManager.disconnect(this._realmLoginHintSignalId);
this._realmLoginHintSignalId = 0;
}
},
});
Signals.addSignalMethods(ShellUserVerifier.prototype);

View File

@ -174,10 +174,15 @@ 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 });
}

View File

@ -33,6 +33,10 @@ const SystemdLoginManagerIface = <interface name='org.freedesktop.login1.Manager
<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>
@ -72,7 +76,36 @@ const ConsoleKitSession = Gio.DBusProxy.makeProxyWrapper(ConsoleKitSessionIface)
const ConsoleKitManager = Gio.DBusProxy.makeProxyWrapper(ConsoleKitManagerIface);
function haveSystemd() {
return GLib.access("/sys/fs/cgroup/systemd", 0) >= 0;
return GLib.access("/run/systemd/seats", 0) >= 0;
}
function versionCompare(required, reference) {
required = required.split('.');
reference = reference.split('.');
for (let i = 0; i < required.length; i++) {
if (required[i] != reference[i])
return required[i] < reference[i];
}
return true;
}
function canLock() {
try {
let params = GLib.Variant.new('(ss)', ['org.gnome.DisplayManager.Manager', 'Version']);
let result = Gio.DBus.system.call_sync('org.gnome.DisplayManager',
'/org/gnome/DisplayManager/Manager',
'org.freedesktop.DBus.Properties',
'Get', params, null,
Gio.DBusCallFlags.NONE,
-1, null);
let version = result.deep_unpack()[0].deep_unpack();
return versionCompare('3.5.91', version);
} catch(e) {
return false;
}
}
let _loginManager = null;
@ -107,15 +140,23 @@ const LoginManagerSystemd = new Lang.Class({
// Having this function is a bit of a hack since the Systemd and ConsoleKit
// session objects have different interfaces - but in both cases there are
// Lock/Unlock signals, and that's all we count upon at the moment.
getCurrentSessionProxy: function() {
if (!this._currentSession) {
this._currentSession = new SystemdLoginSession(Gio.DBus.system,
'org.freedesktop.login1',
'/org/freedesktop/login1/session/' +
GLib.getenv('XDG_SESSION_ID'));
getCurrentSessionProxy: function(callback) {
if (this._currentSession) {
callback (this._currentSession);
return;
}
return this._currentSession;
this._proxy.GetSessionRemote(GLib.getenv('XDG_SESSION_ID'), Lang.bind(this,
function(result, error) {
if (error) {
logError(error, 'Could not get a proxy for the current session');
} else {
this._currentSession = new SystemdLoginSession(Gio.DBus.system,
'org.freedesktop.login1',
result[0]);
callback(this._currentSession);
}
}));
},
canPowerOff: function(asyncCallback) {
@ -204,15 +245,23 @@ const LoginManagerConsoleKit = new Lang.Class({
// Having this function is a bit of a hack since the Systemd and ConsoleKit
// session objects have different interfaces - but in both cases there are
// Lock/Unlock signals, and that's all we count upon at the moment.
getCurrentSessionProxy: function() {
if (!this._currentSession) {
let [currentSessionId] = this._proxy.GetCurrentSessionSync();
this._currentSession = new ConsoleKitSession(Gio.DBus.system,
'org.freedesktop.ConsoleKit',
currentSessionId);
getCurrentSessionProxy: function(callback) {
if (this._currentSession) {
callback (this._currentSession);
return;
}
return this._currentSession;
this._proxy.GetCurrentSessionRemote(Lang.bind(this,
function(result, error) {
if (error) {
logError(error, 'Could not get a proxy for the current session');
} else {
this._currentSession = new ConsoleKitSession(Gio.DBus.system,
'org.freedesktop.ConsoleKit',
result[0]);
callback(this._currentSession);
}
}));
},
canPowerOff: function(asyncCallback) {

View File

@ -5,6 +5,9 @@ const GLib = imports.gi.GLib;
const St = imports.gi.St;
const Main = imports.ui.main;
const Tweener = imports.ui.tweener;
const SCROLL_TIME = 0.1;
// http://daringfireball.net/2010/07/improved_regex_for_matching_urls
const _balancedParens = '\\((?:[^\\s()<>]+|(?:\\(?:[^\\s()<>]+\\)))*\\)';
@ -234,3 +237,39 @@ function makeCloseButton() {
return closeButton;
}
function ensureActorVisibleInScrollView(scrollView, actor) {
let adjustment = scrollView.vscroll.adjustment;
let [value, lower, upper, stepIncrement, pageIncrement, pageSize] = adjustment.get_values();
let offset = 0;
let vfade = scrollView.get_effect("fade");
if (vfade)
offset = vfade.vfade_offset;
let box = actor.get_allocation_box();
let y1 = box.y1, y2 = box.y2;
let parent = actor.get_parent();
while (parent != scrollView) {
if (!parent)
throw new Error("actor not in scroll view");
let box = parent.get_allocation_box();
y1 += box.y1;
y2 += box.y1;
parent = parent.get_parent();
}
if (y1 < value + offset)
value = Math.max(0, y1 - offset);
else if (y2 > value + pageSize - offset)
value = Math.min(upper, y2 + offset - pageSize);
else
return;
Tweener.addTween(adjustment,
{ value: value,
time: SCROLL_TIME,
transition: 'easeOutQuad' });
}

View File

@ -98,43 +98,13 @@ const AppSwitcherPopup = new Lang.Class({
}
},
_getAppLists: function() {
let tracker = Shell.WindowTracker.get_default();
let appSys = Shell.AppSystem.get_default();
let allApps = appSys.get_running ();
let screen = global.screen;
let display = screen.get_display();
let windows = display.get_tab_list(Meta.TabList.NORMAL_ALL, screen,
screen.get_active_workspace());
// windows is only the windows on the current workspace. For
// each one, if it corresponds to an app we know, move that
// app from allApps to apps.
let apps = [];
for (let i = 0; i < windows.length && allApps.length != 0; i++) {
let app = tracker.get_window_app(windows[i]);
let index = allApps.indexOf(app);
if (index != -1) {
apps.push(app);
allApps.splice(index, 1);
}
}
// Now @apps is a list of apps on the current workspace, in
// standard Alt+Tab order (MRU except for minimized windows),
// and allApps is a list of apps that only appear on other
// workspaces, sorted by user_time, which is good enough.
return [apps, allApps];
},
_createSwitcher: function() {
let [localApps, otherApps] = this._getAppLists();
let apps = Shell.AppSystem.get_default().get_running ();
if (localApps.length == 0 && otherApps.length == 0)
if (apps.length == 0)
return false;
this._switcherList = new AppSwitcher(localApps, otherApps, this);
this._switcherList = new AppSwitcher(apps, this);
this._items = this._switcherList.icons;
return true;
@ -262,15 +232,13 @@ const AppSwitcherPopup = new Lang.Class({
},
_finish : function(timestamp) {
this.parent();
let appIcon = this._items[this._selectedIndex];
let window;
if (this._currentWindow >= 0)
window = appIcon.cachedWindows[this._currentWindow];
if (this._currentWindow < 0)
appIcon.app.activate_window(appIcon.cachedWindows[0], timestamp);
else
window = null;
appIcon.app.activate_window(window, timestamp);
Main.activateWindow(appIcon.cachedWindows[this._currentWindow], timestamp);
this.parent();
},
_onDestroy : function() {
@ -429,9 +397,9 @@ const WindowSwitcherPopup = new Lang.Class({
},
_finish: function() {
this.parent();
Main.activateWindow(this._items[this._selectedIndex].window);
this.parent();
}
});
@ -461,34 +429,26 @@ const AppSwitcher = new Lang.Class({
Name: 'AppSwitcher',
Extends: SwitcherPopup.SwitcherList,
_init : function(localApps, otherApps, altTabPopup) {
_init : function(apps, altTabPopup) {
this.parent(true);
// Construct the AppIcons, add to the popup
let activeWorkspace = global.screen.get_active_workspace();
let workspaceIcons = [];
let otherIcons = [];
for (let i = 0; i < localApps.length; i++) {
let appIcon = new AppIcon(localApps[i]);
// Cache the window list now; we don't handle dynamic changes here,
// and we don't want to be continually retrieving it
appIcon.cachedWindows = appIcon.app.get_windows();
workspaceIcons.push(appIcon);
}
for (let i = 0; i < otherApps.length; i++) {
let appIcon = new AppIcon(otherApps[i]);
appIcon.cachedWindows = appIcon.app.get_windows();
otherIcons.push(appIcon);
}
this.icons = [];
this._arrows = [];
for (let i = 0; i < workspaceIcons.length; i++)
this._addIcon(workspaceIcons[i]);
if (workspaceIcons.length > 0 && otherIcons.length > 0)
this.addSeparator();
for (let i = 0; i < otherIcons.length; i++)
this._addIcon(otherIcons[i]);
let windowTracker = Shell.WindowTracker.get_default();
let allWindows = global.display.get_tab_list(Meta.TabList.NORMAL,
global.screen, null);
// Construct the AppIcons, add to the popup
for (let i = 0; i < apps.length; i++) {
let appIcon = new AppIcon(apps[i]);
// Cache the window list now; we don't handle dynamic changes here,
// and we don't want to be continually retrieving it
appIcon.cachedWindows = allWindows.filter(function(w) {
return windowTracker.get_window_app (w) == appIcon.app;
});
this._addIcon(appIcon);
}
this._curApp = -1;
this._iconSize = 0;
@ -514,8 +474,6 @@ const AppSwitcher = new Lang.Class({
let [iconMinHeight, iconNaturalHeight] = this.icons[j].label.get_preferred_height(-1);
let iconSpacing = iconNaturalHeight + iconPadding + iconBorder;
let totalSpacing = this._list.spacing * (this._items.length - 1);
if (this._separator)
totalSpacing += this._separator.width + this._list.spacing;
// We just assume the whole screen here due to weirdness happing with the passed width
let primary = Main.layoutManager.primaryMonitor;
@ -638,24 +596,12 @@ const ThumbnailList = new Lang.Class({
_init : function(windows) {
this.parent(false);
let activeWorkspace = global.screen.get_active_workspace();
// We fake the value of 'separatorAdded' when the app has no window
// on the current workspace, to avoid displaying a useless separator in
// that case.
let separatorAdded = windows.length == 0 || windows[0].get_workspace() != activeWorkspace;
this._labels = new Array();
this._thumbnailBins = new Array();
this._clones = new Array();
this._windows = windows;
for (let i = 0; i < windows.length; i++) {
if (!separatorAdded && windows[i].get_workspace() != activeWorkspace) {
this.addSeparator();
separatorAdded = true;
}
let box = new St.BoxLayout({ style_class: 'thumbnail-box',
vertical: true });

View File

@ -29,7 +29,6 @@ const Util = imports.misc.util;
const MAX_APPLICATION_WORK_MILLIS = 75;
const MENU_POPUP_TIMEOUT = 600;
const SCROLL_TIME = 0.1;
const MAX_COLUMNS = 6;
const INACTIVE_GRID_OPACITY = 77;
@ -157,6 +156,30 @@ const FolderView = new Lang.Class({
}
});
const AllViewLayout = new Lang.Class({
Name: 'AllViewLayout',
Extends: Clutter.BinLayout,
vfunc_get_preferred_height: function(container, forWidth) {
let minBottom = 0;
let naturalBottom = 0;
for (let child = container.get_first_child();
child;
child = child.get_next_sibling()) {
let childY = child.y;
let [childMin, childNatural] = child.get_preferred_height(forWidth);
if (childMin + childY > minBottom)
minBottom = childMin + childY;
if (childNatural + childY > naturalBottom)
naturalBottom = childNatural + childY;
}
return [minBottom, naturalBottom];
}
});
const AllView = new Lang.Class({
Name: 'AllView',
Extends: AlphabeticalView,
@ -164,8 +187,11 @@ const AllView = new Lang.Class({
_init: function() {
this.parent();
this._grid.actor.y_align = Clutter.ActorAlign.START;
this._grid.actor.y_expand = true;
let box = new St.BoxLayout({ vertical: true });
this._stack = new St.Widget({ layout_manager: new Clutter.BinLayout() });
this._stack = new St.Widget({ layout_manager: new AllViewLayout() });
this._stack.add_actor(this._grid.actor);
this._eventBlocker = new St.Widget({ x_expand: true, y_expand: true });
this._stack.add_actor(this._eventBlocker);
@ -175,7 +201,9 @@ const AllView = new Lang.Class({
y_fill: false,
y_align: St.Align.START,
x_expand: true,
style_class: 'vfade' });
y_expand: true,
overlay_scrollbars: true,
style_class: 'all-apps vfade' });
this.actor.add_actor(box);
this.actor.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC);
let action = new Clutter.PanAction({ interpolate: true });
@ -251,35 +279,17 @@ const AllView = new Lang.Class({
this._eventBlocker.reactive = isOpen;
this._currentPopup = isOpen ? popup : null;
this._updateIconOpacities(isOpen);
if (isOpen)
if (isOpen) {
this._ensureIconVisible(popup.actor);
this._grid.actor.y = popup.parentOffset;
} else {
this._grid.actor.y = 0;
}
}));
},
_ensureIconVisible: function(icon) {
let adjustment = this.actor.vscroll.adjustment;
let [value, lower, upper, stepIncrement, pageIncrement, pageSize] = adjustment.get_values();
let offset = 0;
let vfade = this.actor.get_effect("fade");
if (vfade)
offset = vfade.vfade_offset;
// If this gets called as part of a right-click, the actor
// will be needs_allocation, and so "icon.y" would return 0
let box = icon.get_allocation_box();
if (box.y1 < value + offset)
value = Math.max(0, box.y1 - offset);
else if (box.y2 > value + pageSize - offset)
value = Math.min(upper, box.y2 + offset - pageSize);
else
return;
Tweener.addTween(adjustment,
{ value: value,
time: SCROLL_TIME,
transition: 'easeOutQuad' });
Util.ensureActorVisibleInScrollView(this.actor, icon);
},
_updateIconOpacities: function(folderOpen) {
@ -297,22 +307,11 @@ const FrequentView = new Lang.Class({
_init: function() {
this._grid = new IconGrid.IconGrid({ xAlign: St.Align.MIDDLE,
fillParent: true,
columnLimit: MAX_COLUMNS });
let box = new St.BoxLayout({ vertical: true });
box.add(this._grid.actor);
// HACK: IconGrid currently lacks API to only display items that match
// the allocation, so rather than clipping away eventual overflow, we
// use an unscrollable ScrollView with hidden scrollbars to nicely
// fade out cut off items
this.actor = new St.ScrollView({ x_fill: true,
y_fill: false,
y_align: St.Align.START,
x_expand: true,
reactive: false,
style_class: 'frequent-apps vfade' });
this.actor.add_actor(box);
this.actor.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC);
this.actor = new St.Widget({ style_class: 'frequent-apps',
x_expand: true, y_expand: true });
this.actor.add_actor(this._grid.actor);
this._usage = Shell.AppUsage.get_default();
},
@ -335,6 +334,42 @@ const Views = {
ALL: 1
};
const ControlsBoxLayout = Lang.Class({
Name: 'ControlsBoxLayout',
Extends: Clutter.BoxLayout,
/**
* Override the BoxLayout behavior to use the maximum preferred width of all
* buttons for each child
*/
vfunc_get_preferred_width: function(container, forHeight) {
let maxMinWidth = 0;
let maxNaturalWidth = 0;
for (let child = container.get_first_child();
child;
child = child.get_next_sibling()) {
let [minWidth, natWidth] = child.get_preferred_width(forHeight);
maxMinWidth = Math.max(maxMinWidth, minWidth);
maxNaturalWidth = Math.max(maxNaturalWidth, natWidth);
}
let childrenCount = container.get_n_children();
let totalSpacing = this.spacing * (childrenCount - 1);
return [maxMinWidth * childrenCount + totalSpacing,
maxNaturalWidth * childrenCount + totalSpacing];
},
vfunc_set_container: function(container) {
if(this._styleChangedId) {
this._container.disconnect(this._styleChangedId);
this._styleChangedId = 0;
}
if(container != null)
this._styleChangedId = container.connect('style-changed', Lang.bind(this,
function() { this.spacing = this._container.get_theme_node().get_length('spacing'); }));
this._container = container;
}
});
const AppDisplay = new Lang.Class({
Name: 'AppDisplay',
@ -373,14 +408,11 @@ const AppDisplay = new Lang.Class({
this._viewStack = new St.Widget({ layout_manager: new Clutter.BinLayout(),
x_expand: true, y_expand: true });
let bin = new St.Bin({ child: this._viewStack,
clip_to_allocation: true,
x_fill: true, y_fill: true });
this.actor.add(bin, { expand: true });
this.actor.add(this._viewStack, { expand: true });
let layout = new Clutter.BoxLayout({ homogeneous: true });
this._controls = new St.Widget({ style_class: 'app-view-controls',
layout_manager: layout });
let layout = new ControlsBoxLayout({ homogeneous: true });
this._controls = new St.Widget({ style_class: 'app-view-controls' });
this._controls.set_layout_manager(layout);
this.actor.add(new St.Bin({ child: this._controls }));
@ -579,15 +611,15 @@ const FolderIcon = new Lang.Class({
this._popup = new AppFolderPopup(this, side);
this._parentView.addFolderPopup(this._popup);
let constraint = new Clutter.AlignConstraint({ source: this._parentView.actor,
align_axis: Clutter.AlignAxis.X_AXIS,
factor: 0.5 });
this._popup.actor.add_constraint(constraint);
// Position the popup above or below the source icon
if (side == St.Side.BOTTOM) {
this._popup.actor.show();
this._popup.actor.y = this.actor.y - this._popup.actor.height;
let closeButtonOffset = -this._popup.closeButton.translation_y;
let y = this.actor.y - this._popup.actor.height;
let yWithButton = y - closeButtonOffset;
this._popup.parentOffset = yWithButton < 0 ? -yWithButton : 0;
this._popup.actor.y = Math.max(y, closeButtonOffset);
this._popup.actor.hide();
} else {
this._popup.actor.y = this.actor.y + this.actor.height;
@ -610,9 +642,20 @@ const AppFolderPopup = new Lang.Class({
this._arrowSide = side;
this._isOpen = false;
this.parentOffset = 0;
this.actor = new St.Widget({ layout_manager: new Clutter.BinLayout(),
visible: false });
visible: false,
// We don't want to expand really, but look
// at the layout manager of our parent...
//
// DOUBLE HACK: if you set one, you automatically
// get the effect for the other direction too, so
// we need to set the y_align
x_expand: true,
y_expand: true,
x_align: Clutter.ActorAlign.CENTER,
y_align: Clutter.ActorAlign.START });
this._boxPointer = new BoxPointer.BoxPointer(this._arrowSide,
{ style_class: 'app-folder-popup-bin',
x_fill: true,
@ -623,17 +666,31 @@ const AppFolderPopup = new Lang.Class({
this.actor.add_actor(this._boxPointer.actor);
this._boxPointer.bin.set_child(this._view.actor);
let closeButton = Util.makeCloseButton();
closeButton.connect('clicked', Lang.bind(this, this.popdown));
this.actor.add_actor(closeButton);
this.closeButton = Util.makeCloseButton();
this.closeButton.connect('clicked', Lang.bind(this, this.popdown));
this.actor.add_actor(this.closeButton);
this._boxPointer.actor.bind_property('opacity', closeButton, 'opacity',
this._boxPointer.actor.bind_property('opacity', this.closeButton, 'opacity',
GObject.BindingFlags.SYNC_CREATE);
global.focus_manager.add_group(this.actor);
source.actor.connect('destroy', Lang.bind(this,
function() {
this.actor.destroy();
}));
this.actor.connect('key-press-event', Lang.bind(this, this._onKeyPress));
},
_onKeyPress: function(actor, event) {
if (!this._isOpen)
return false;
if (event.get_key_symbol() != Clutter.KEY_Escape)
return false;
this.popdown();
return true;
},
toggle: function() {
@ -648,6 +705,7 @@ const AppFolderPopup = new Lang.Class({
return;
this.actor.show();
this.actor.navigate_focus(null, Gtk.DirectionType.TAB_FORWARD, false);
this._boxPointer.setArrowActor(this._source.actor);
this._boxPointer.show(BoxPointer.PopupAnimation.FADE |

View File

@ -14,7 +14,6 @@ const Params = imports.misc.params;
const Tweener = imports.ui.tweener;
const BACKGROUND_SCHEMA = 'org.gnome.desktop.background';
const DRAW_BACKGROUND_KEY = 'draw-background';
const PRIMARY_COLOR_KEY = 'primary-color';
const SECONDARY_COLOR_KEY = 'secondary-color';
const COLOR_SHADING_TYPE_KEY = 'color-shading-type';
@ -39,6 +38,7 @@ const BackgroundCache = new Lang.Class({
_init: function() {
this._patterns = [];
this._images = [];
this._pendingFileLoads = [];
this._fileMonitors = {};
},
@ -85,10 +85,10 @@ const BackgroundCache = new Lang.Class({
} else {
content.load_gradient(params.shadingType, params.color, params.secondColor);
}
this._patterns.push(content);
}
this._patterns.push(content);
return content;
},
@ -126,9 +126,81 @@ const BackgroundCache = new Lang.Class({
},
removeImageContent: function(content) {
let filename = content.get_filename();
if (filename && this._fileMonitors[filename])
delete this._fileMonitors[filename];
this._removeContent(this._images, content);
},
_loadImageContent: function(params) {
params = Params.parse(params, { monitorIndex: 0,
style: null,
filename: null,
effects: Meta.BackgroundEffects.NONE,
cancellable: null,
onFinished: null });
for (let i = 0; i < this._pendingFileLoads.length; i++) {
if (this._pendingFileLoads[i].filename == params.filename &&
this._pendingFileLoads[i].style == params.style) {
this._pendingFileLoads[i].callers.push({ shouldCopy: true,
monitorIndex: params.monitorIndex,
effects: params.effects,
onFinished: params.onFinished });
return;
}
}
this._pendingFileLoads.push({ filename: params.filename,
style: params.style,
callers: [{ shouldCopy: false,
monitorIndex: params.monitorIndex,
effects: params.effects,
onFinished: params.onFinished }] });
let content = new Meta.Background({ meta_screen: global.screen,
monitor: params.monitorIndex,
effects: params.effects });
content.load_file_async(params.filename,
params.style,
params.cancellable,
Lang.bind(this,
function(object, result) {
try {
content.load_file_finish(result);
this._monitorFile(params.filename);
this._images.push(content);
} catch(e) {
content = null;
}
for (let i = 0; i < this._pendingFileLoads.length; i++) {
let pendingLoad = this._pendingFileLoads[i];
if (pendingLoad.filename != params.filename ||
pendingLoad.style != params.style)
continue;
for (let j = 0; j < pendingLoad.callers.length; j++) {
if (pendingLoad.callers[j].onFinished) {
if (content && pendingLoad.callers[j].shouldCopy) {
content = object.copy(pendingLoad.callers[j].monitorIndex,
pendingLoad.callers[j].effects);
}
pendingLoad.callers[j].onFinished(content);
}
}
this._pendingFileLoads.splice(i, 1);
}
}));
},
getImageContent: function(params) {
params = Params.parse(params, { monitorIndex: 0,
style: null,
@ -166,31 +238,19 @@ const BackgroundCache = new Lang.Class({
if (params.cancellable && params.cancellable.is_cancelled())
content = null;
else
this._images.push(content);
if (params.onFinished)
params.onFinished(content);
} else {
content = new Meta.Background({ meta_screen: global.screen,
monitor: params.monitorIndex,
effects: params.effects });
this._loadImageContent({ filename: params.filename,
style: params.style,
effects: params.effects,
monitorIndex: params.monitorIndex,
cancellable: params.cancellable,
onFinished: params.onFinished });
content.load_file_async(params.filename,
params.style,
params.cancellable,
Lang.bind(this,
function(object, result) {
try {
content.load_file_finish(result);
this._monitorFile(params.filename);
this._images.push(content);
} catch(e) {
content = null;
}
if (params.onFinished)
params.onFinished(content);
}));
}
},
@ -268,9 +328,9 @@ const Background = new Lang.Class({
_destroy: function() {
this._cancellable.cancel();
if (this._animationUpdateTimeoutId) {
GLib.source_remove (this._animationUpdateTimeoutId);
this._animationUpdateTimeoutId = 0
if (this._updateAnimationTimeoutId) {
GLib.source_remove (this._updateAnimationTimeoutId);
this._updateAnimationTimeoutId = 0;
}
let i;
@ -357,7 +417,10 @@ const Background = new Lang.Class({
let actor = new Meta.BackgroundActor();
actor.content = content;
this.actor.add_child(actor);
// The background pattern is the first actor in
// the group, and all images should be above that.
this.actor.insert_child_at_index(actor, index + 1);
this._images[index] = actor;
this._watchCacheFile(filename);
@ -368,27 +431,27 @@ const Background = new Lang.Class({
content.brightness = this._brightness;
content.vignette_sharpness = this._vignetteSharpness;
this._cache.removeImageContent(this._images[index].content);
this._images[index].content = content;
this._watchCacheFile(filename);
},
_updateAnimationProgress: function() {
if (this._images[1]) {
this._images[1].raise_top();
if (this._images[1])
this._images[1].opacity = this._animation.transitionProgress * 255;
}
this._queueAnimationUpdate();
this._queueUpdateAnimation();
},
_updateAnimation: function() {
this._animationUpdateTimeoutId = 0;
this._updateAnimationTimeoutId = 0;
let files = this._animation.getKeyFrameFiles(this._layoutManager.monitors[this._monitorIndex]);
this._animation.update(this._layoutManager.monitors[this._monitorIndex]);
let files = this._animation.keyFrameFiles;
if (!files) {
if (files.length == 0) {
this._setLoaded();
this._queueAnimationUpdate();
this._queueUpdateAnimation();
return;
}
@ -407,7 +470,7 @@ const Background = new Lang.Class({
style: this._style,
filename: files[i],
cancellable: this._cancellable,
onFinished: Lang.bind(this, function(content) {
onFinished: Lang.bind(this, function(content, i) {
numPendingImages--;
if (!content) {
@ -427,27 +490,34 @@ const Background = new Lang.Class({
this._setLoaded();
this._updateAnimationProgress();
}
})
}, i)
});
}
},
_queueAnimationUpdate: function() {
if (this._animationUpdateTimeoutId != 0)
_queueUpdateAnimation: function() {
if (this._updateAnimationTimeoutId != 0)
return;
if (!this._cancellable || this._cancellable.is_cancelled())
return;
if (!this._animation.duration)
if (!this._animation.transitionDuration)
return;
let nSteps = 255 / ANIMATION_OPACITY_STEP_INCREMENT;
let timePerStep = (this._animation.transitionDuration * 1000) / nSteps;
let interval = Math.max(ANIMATION_MIN_WAKEUP_INTERVAL * 1000,
ANIMATION_OPACITY_STEP_INCREMENT / this._animation.duration);
this._animationUpdateTimeoutId = GLib.timeout_add(GLib.PRIORITY_DEFAULT,
timePerStep);
if (interval > GLib.MAXUINT32)
return;
this._updateAnimationTimeoutId = GLib.timeout_add(GLib.PRIORITY_DEFAULT,
interval,
Lang.bind(this, function() {
this._animationUpdateTimeoutId = 0;
this._updateAnimationTimeoutId = 0;
this._updateAnimation();
return false;
}));
@ -490,11 +560,6 @@ const Background = new Lang.Class({
},
_load: function () {
if (!this._settings.get_boolean(DRAW_BACKGROUND_KEY)) {
this._setLoaded();
return;
}
this._cache = getBackgroundCache();
this._loadPattern(this._cache);
@ -565,22 +630,24 @@ const Background = new Lang.Class({
});
Signals.addSignalMethods(Background.prototype);
const StillFrame = new Lang.Class({
Name: 'StillFrame',
const SystemBackground = new Lang.Class({
Name: 'SystemBackground',
_init: function(monitorIndex) {
_init: function() {
this._cache = getBackgroundCache();
this.actor = new Meta.BackgroundActor();
this.actor._delegate = this;
let content = new Meta.Background({ meta_screen: global.screen,
monitor: monitorIndex,
effects: Meta.BackgroundEffects.NONE });
content.load_still_frame();
this.actor.content = content;
this._cache.getImageContent({ style: GDesktopEnums.BackgroundStyle.WALLPAPER,
filename: global.datadir + '/theme/noise-texture.png',
effects: Meta.BackgroundEffects.NONE,
onFinished: Lang.bind(this, function(content) {
this.actor.content = content;
this.emit('loaded');
})
});
}
});
Signals.addSignalMethods(StillFrame.prototype);
Signals.addSignalMethods(SystemBackground.prototype);
const Animation = new Lang.Class({
Name: 'Animation',
@ -589,9 +656,9 @@ const Animation = new Lang.Class({
params = Params.parse(params, { filename: null });
this.filename = params.filename;
this._keyFrames = [];
this.duration = 0.0;
this.keyFrameFiles = [];
this.transitionProgress = 0.0;
this.transitionDuration = 0.0;
this.loaded = false;
},
@ -603,33 +670,31 @@ const Animation = new Lang.Class({
this._show.load_async(null,
Lang.bind(this,
function(object, result) {
this.duration = this._show.get_total_duration();
this.loaded = true;
if (callback)
callback();
}));
},
getKeyFrameFiles: function(monitor) {
update: function(monitor) {
this.keyFrameFiles = [];
if (!this._show)
return null;
return;
if (this._show.get_num_slides() < 1)
return null;
return;
let [progress, duration, isFixed, file1, file2] = this._show.get_current_slide(monitor.width, monitor.height);
this.transitionDuration = duration;
this.transitionProgress = progress;
let files = [];
if (file1)
files.push(file1);
this.keyFrameFiles.push(file1);
if (file2)
files.push(file2);
return files;
this.keyFrameFiles.push(file2);
},
});
Signals.addSignalMethods(Animation.prototype);
@ -641,26 +706,20 @@ const BackgroundManager = new Lang.Class({
params = Params.parse(params, { container: null,
layoutManager: Main.layoutManager,
monitorIndex: null,
effects: Meta.BackgroundEffects.NONE });
effects: Meta.BackgroundEffects.NONE,
controlPosition: true });
this._container = params.container;
this._layoutManager = params.layoutManager;
this._effects = params.effects;
this._monitorIndex = params.monitorIndex;
this._controlPosition = params.controlPosition;
this.background = this._createBackground();
this._newBackground = null;
this._loadedSignalId = 0;
this._changedSignalId = 0;
},
destroy: function() {
if (this._loadedSignalId)
this._newBackground.disconnect(this._loadedSignalId);
if (this._changedSignalId)
this.background.disconnect(this._changedSignalId);
if (this._newBackground) {
this._newBackground.actor.destroy();
this._newBackground = null;
@ -679,22 +738,28 @@ const BackgroundManager = new Lang.Class({
newBackground.saturation = background.saturation;
newBackground.visible = background.visible;
let signalId = newBackground.connect('loaded',
newBackground.loadedSignalId = newBackground.connect('loaded',
Lang.bind(this, function() {
newBackground.disconnect(signalId);
newBackground.disconnect(newBackground.loadedSignalId);
newBackground.loadedSignalId = 0;
Tweener.addTween(background.actor,
{ opacity: 0,
time: FADE_ANIMATION_TIME,
transition: 'easeOutQuad',
onComplete: Lang.bind(this, function() {
this.background = newBackground;
this._newBackground = null;
if (this._newBackground == newBackground) {
this.background = newBackground;
this._newBackground = null;
} else {
newBackground.actor.destroy();
}
background.actor.destroy();
this.emit('changed');
})
});
}));
this._loadedSignalId = signalId;
this._newBackground = newBackground;
},
@ -706,16 +771,26 @@ const BackgroundManager = new Lang.Class({
this._container.add_child(background.actor);
let monitor = this._layoutManager.monitors[this._monitorIndex];
background.actor.set_position(monitor.x, monitor.y);
background.actor.set_size(monitor.width, monitor.height);
background.actor.lower_bottom();
let signalId = background.connect('changed', Lang.bind(this, function() {
background.disconnect(signalId);
background.actor.set_size(monitor.width, monitor.height);
if (this._controlPosition) {
background.actor.set_position(monitor.x, monitor.y);
background.actor.lower_bottom();
}
background.changeSignalId = background.connect('changed', Lang.bind(this, function() {
background.disconnect(background.changeSignalId);
background.changeSignalId = 0;
this._updateBackground(background, this._monitorIndex);
}));
this._changedSignalId = signalId;
background.actor.connect('destroy', Lang.bind(this, function() {
if (background.changeSignalId)
background.disconnect(background.changeSignalId);
if (background.loadedSignalId)
background.disconnect(background.loadedSignalId);
}));
return background;
},

View File

@ -46,8 +46,10 @@ function addBackgroundMenu(actor) {
clickAction.connect('long-press', function(action, actor, state) {
if (state == Clutter.LongPressState.QUERY)
return action.get_button() == 1 && !actor._backgroundMenu.isOpen;
if (state == Clutter.LongPressState.ACTIVATE)
if (state == Clutter.LongPressState.ACTIVATE) {
openMenu();
actor._backgroundManager.ignoreRelease();
}
return true;
});
clickAction.connect('clicked', function(action) {
@ -55,4 +57,12 @@ function addBackgroundMenu(actor) {
openMenu();
});
actor.add_action(clickAction);
actor.connect('destroy', function() {
actor._backgroundMenu.destroy();
actor._backgroundMenu = null;
actor._backgroundManager = null;
cursor.destroy();
});
}

View File

@ -71,7 +71,7 @@ function _formatEventTime(event, clockFormat) {
default:
/* explicit fall-through */
case '12h':
/* Transators: Shown in calendar event list, if 12h format,
/* Translators: Shown in calendar event list, if 12h format,
\u2236 is a ratio character, similar to : and \u2009 is
a thin space */
ret = event.date.toLocaleFormat(C_("event list time", "%l\u2236%M\u2009%p"));
@ -168,6 +168,12 @@ const EmptyEventSource = new Lang.Class({
Name: 'EmptyEventSource',
_init: function() {
this.isLoading = false;
this.isDummy = true;
this.hasCalendars = false;
},
destroy: function() {
},
requestRange: function(begin, end) {
@ -191,6 +197,7 @@ const CalendarServerIface = <interface name="org.gnome.Shell.CalendarServer">
<arg type="b" direction="in" />
<arg type="a(sssbxxa{sv})" direction="out" />
</method>
<property name="HasCalendars" type="b" access="read" />
<signal name="Changed" />
</interface>;
@ -201,8 +208,7 @@ function CalendarServer() {
g_interface_name: CalendarServerInfo.name,
g_interface_info: CalendarServerInfo,
g_name: 'org.gnome.Shell.CalendarServer',
g_object_path: '/org/gnome/Shell/CalendarServer',
g_flags: Gio.DBusProxyFlags.DO_NOT_LOAD_PROPERTIES });
g_object_path: '/org/gnome/Shell/CalendarServer' });
}
function _datesEqual(a, b) {
@ -229,6 +235,8 @@ const DBusEventSource = new Lang.Class({
_init: function() {
this._resetCache();
this.isLoading = false;
this.isDummy = false;
this._initialized = false;
this._dbusProxy = new CalendarServer();
@ -249,11 +257,27 @@ const DBusEventSource = new Lang.Class({
this._onNameVanished();
}));
this._dbusProxy.connect('g-properties-changed', Lang.bind(this, function() {
this.emit('notify::has-calendars');
}));
this._initialized = true;
this.emit('notify::has-calendars');
this._onNameAppeared();
}));
},
destroy: function() {
this._dbusProxy.run_dispose();
},
get hasCalendars() {
if (this._initialized)
return this._dbusProxy.HasCalendars;
else
return false;
},
_resetCache: function() {
this._events = [];
this._lastRequestBegin = null;
@ -293,6 +317,7 @@ const DBusEventSource = new Lang.Class({
}
this._events = newEvents;
this.isLoading = false;
this.emit('changed');
},
@ -315,6 +340,7 @@ const DBusEventSource = new Lang.Class({
requestRange: function(begin, end, forceReload) {
if (forceReload || !(_datesEqual(begin, this._lastRequestBegin) && _datesEqual(end, this._lastRequestEnd))) {
this.isLoading = true;
this._lastRequestBegin = begin;
this._lastRequestEnd = end;
this._curRequestBegin = begin;
@ -389,19 +415,11 @@ const Calendar = new Lang.Class({
// @eventSource: is an object implementing the EventSource API, e.g. the
// requestRange(), getEvents(), hasEvents() methods and the ::changed signal.
setEventSource: function(eventSource) {
if (this._eventSource) {
this._eventSource.disconnect(this._eventSourceChangedId);
this._eventSource = null;
}
this._eventSource = eventSource;
if (this._eventSource) {
this._eventSourceChangedId = this._eventSource.connect('changed', Lang.bind(this, function() {
this._update(false);
}));
this._update(true);
}
this._eventSource.connect('changed', Lang.bind(this, function() {
this._update(false);
}));
this._update(true);
},
// Sets the calendar to show a specific date
@ -538,20 +556,44 @@ const Calendar = new Lang.Class({
children[i].destroy();
// Start at the beginning of the week before the start of the month
//
// We want to show always 6 weeks (to keep the calendar menu at the same
// height if there are no events), so we pad it according to the following
// policy:
//
// 1 - If a month has 6 weeks, we place no padding (example: Dec 2012)
// 2 - If a month has 5 weeks and it starts on week start, we pad one week
// before it (example: Apr 2012)
// 3 - If a month has 5 weeks and it starts on any other day, we pad one week
// after it (example: Nov 2012)
// 4 - If a month has 4 weeks, we pad one week before and one after it
// (example: Feb 2010)
//
// Actually computing the number of weeks is complex, but we know that the
// problematic categories (2 and 4) always start on week start, and that
// all months at the end have 6 weeks.
let beginDate = new Date(this._selectedDate);
beginDate.setDate(1);
beginDate.setSeconds(0);
beginDate.setHours(12);
let year = beginDate.getYear();
let daysToWeekStart = (7 + beginDate.getDay() - this._weekStart) % 7;
beginDate.setTime(beginDate.getTime() - daysToWeekStart * MSECS_IN_DAY);
let startsOnWeekStart = daysToWeekStart == 0;
let weekPadding = startsOnWeekStart ? 7 : 0;
beginDate.setTime(beginDate.getTime() - (weekPadding + daysToWeekStart) * MSECS_IN_DAY);
let iter = new Date(beginDate);
let row = 2;
while (true) {
// nRows here means 6 weeks + one header + one navbar
let nRows = 8;
while (row < 8) {
let button = new St.Button({ label: iter.getDate().toString() });
let rtl = button.get_text_direction() == Clutter.TextDirection.RTL;
if (!this._eventSource)
if (this._eventSource.isDummy)
button.reactive = false;
let iterStr = iter.toUTCString();
@ -560,8 +602,9 @@ const Calendar = new Lang.Class({
this.setDate(newlySelectedDate, false);
}));
let hasEvents = this._eventSource && this._eventSource.hasEvents(iter);
let hasEvents = this._eventSource.hasEvents(iter);
let styleClass = 'calendar-day-base calendar-day';
if (_isWorkDay(iter))
styleClass += ' calendar-work-day'
else
@ -601,17 +644,13 @@ const Calendar = new Lang.Class({
}
iter.setTime(iter.getTime() + MSECS_IN_DAY);
if (iter.getDay() == this._weekStart) {
// We stop on the first "first day of the week" after the month we are displaying
if (iter.getMonth() > this._selectedDate.getMonth() || iter.getYear() > this._selectedDate.getYear())
break;
if (iter.getDay() == this._weekStart)
row++;
}
}
// Signal to the event source that we are interested in events
// only from this date range
if (this._eventSource)
this._eventSource.requestRange(beginDate, iter, forceReload);
this._eventSource.requestRange(beginDate, iter, forceReload);
}
});
@ -629,16 +668,8 @@ const EventsList = new Lang.Class({
},
setEventSource: function(eventSource) {
if (this._eventSource) {
this._eventSource.disconnect(this._eventSourceChangedId);
this._eventSource = null;
}
this._eventSource = eventSource;
if (this._eventSource) {
this._eventSourceChangedId = this._eventSource.connect('changed', Lang.bind(this, this._update));
}
this._eventSource.connect('changed', Lang.bind(this, this._update));
},
_addEvent: function(dayNameBox, timeBox, eventTitleBox, includeDayName, day, time, desc) {
@ -655,9 +686,6 @@ const EventsList = new Lang.Class({
},
_addPeriod: function(header, begin, end, includeDayName, showNothingScheduled) {
if (!this._eventSource)
return;
let events = this._eventSource.getEvents(begin, end);
let clockFormat = this._desktopSettings.get_string(CLOCK_FORMAT_KEY);;
@ -754,6 +782,9 @@ const EventsList = new Lang.Class({
},
_update: function() {
if (this._eventSource.isLoading)
return;
let today = new Date();
if (_sameDay (this._date, today)) {
this._showToday();

View File

@ -292,6 +292,7 @@ const AutorunResidentSource = new Lang.Class({
_init: function(manager) {
this.parent(_("Removable Devices"), 'media-removable');
this.resident = true;
this._mounts = [];

View File

@ -25,7 +25,7 @@ const KeyringDialog = new Lang.Class({
this.prompt = new Shell.KeyringPrompt();
this.prompt.connect('show-password', Lang.bind(this, this._onShowPassword));
this.prompt.connect('show-confirm', Lang.bind(this, this._onShowConfirm));
this.prompt.connect('hide-prompt', Lang.bind(this, this._onHidePrompt));
this.prompt.connect('prompt-close', Lang.bind(this, this._onHidePrompt));
let mainContentBox = new St.BoxLayout({ style_class: 'prompt-dialog-main-layout',
vertical: false });
@ -63,11 +63,17 @@ const KeyringDialog = new Lang.Class({
this._cancelButton = this.addButton({ label: '',
action: Lang.bind(this, this._onCancelButton),
key: Clutter.Escape });
key: Clutter.Escape },
{ expand: true, x_fill: false, x_align: St.Align.START });
this.placeSpinner({ expand: false,
x_fill: false,
y_fill: false,
x_align: St.Align.END,
y_align: St.Align.MIDDLE });
this._continueButton = this.addButton({ label: '',
action: Lang.bind(this, this._onContinueButton),
default: true },
{ expand: true, x_fill: false, x_align: St.Align.END });
{ expand: false, x_fill: false, x_align: St.Align.END });
this.prompt.bind_property('cancel-label', this._cancelButton, 'label', GObject.BindingFlags.SYNC_CREATE);
this.prompt.bind_property('continue-label', this._continueButton, 'label', GObject.BindingFlags.SYNC_CREATE);
@ -143,11 +149,19 @@ const KeyringDialog = new Lang.Class({
},
_updateSensitivity: function(sensitive) {
this._passwordEntry.reactive = sensitive;
this._passwordEntry.clutter_text.editable = sensitive;
if (this._passwordEntry) {
this._passwordEntry.reactive = sensitive;
this._passwordEntry.clutter_text.editable = sensitive;
}
if (this._confirmEntry) {
this._confirmEntry.reactive = sensitive;
this._confirmEntry.clutter_text.editable = sensitive;
}
this._continueButton.can_focus = sensitive;
this._continueButton.reactive = sensitive;
this.setWorking(!sensitive);
},
_ensureOpen: function() {
@ -222,7 +236,7 @@ const KeyringPrompter = new Lang.Class({
enable: function() {
this._prompter.register(Gio.DBus.session);
this._dbusId = Gio.DBus.session.own_name('org.gnome.keyring.SystemPrompter',
Gio.BusNameOwnerFlags.REPLACE, null, null);
Gio.BusNameOwnerFlags.ALLOW_REPLACEMENT, null, null);
},
disable: function() {

View File

@ -31,7 +31,6 @@ const AuthenticationDialog = new Lang.Class({
this.message = message;
this.userNames = userNames;
this._wasDismissed = false;
this._completed = false;
let mainContentBox = new St.BoxLayout({ style_class: 'prompt-dialog-main-layout',
vertical: false });
@ -161,26 +160,32 @@ const AuthenticationDialog = new Lang.Class({
this._cancelButton = this.addButton({ label: _("Cancel"),
action: Lang.bind(this, this.cancel),
key: Clutter.Escape });
key: Clutter.Escape },
{ expand: true, x_fill: false, x_align: St.Align.START });
this.placeSpinner({ expand: false,
x_fill: false,
y_fill: false,
x_align: St.Align.END,
y_align: St.Align.MIDDLE });
this._okButton = this.addButton({ label: _("Authenticate"),
action: Lang.bind(this, this._onAuthenticateButtonPressed),
default: true },
{ expand: true, x_fill: false, x_align: St.Align.END });
{ expand: false, x_fill: false, x_align: St.Align.END });
this._doneEmitted = false;
this._identityToAuth = Polkit.UnixUser.new_for_name(userName);
this._cookie = cookie;
},
performAuthentication: function() {
this.destroySession();
this._session = new PolkitAgent.Session({ identity: this._identityToAuth,
cookie: this._cookie });
this._session.connect('completed', Lang.bind(this, this._onSessionCompleted));
this._session.connect('request', Lang.bind(this, this._onSessionRequest));
this._session.connect('show-error', Lang.bind(this, this._onSessionShowError));
this._session.connect('show-info', Lang.bind(this, this._onSessionShowInfo));
},
startAuthentication: function() {
this._session.initiate();
},
@ -202,14 +207,14 @@ const AuthenticationDialog = new Lang.Class({
log('polkitAuthenticationAgent: Failed to show modal dialog.' +
' Dismissing authentication request for action-id ' + this.actionId +
' cookie ' + this._cookie);
this._emitDone(false, true);
this._emitDone(true);
}
},
_emitDone: function(keepVisible, dismissed) {
_emitDone: function(dismissed) {
if (!this._doneEmitted) {
this._doneEmitted = true;
this.emit('done', keepVisible, dismissed);
this.emit('done', dismissed);
}
},
@ -219,6 +224,7 @@ const AuthenticationDialog = new Lang.Class({
this._okButton.can_focus = sensitive;
this._okButton.reactive = sensitive;
this.setWorking(!sensitive);
},
_onEntryActivate: function() {
@ -237,12 +243,16 @@ const AuthenticationDialog = new Lang.Class({
},
_onSessionCompleted: function(session, gainedAuthorization) {
if (this._completed)
if (this._completed || this._doneEmitted)
return;
this._completed = true;
if (!gainedAuthorization) {
/* Yay, all done */
if (gainedAuthorization) {
this._emitDone(false);
} else {
/* Unless we are showing an existing error message from the PAM
* module (the PAM module could be reporting the authentication
* error providing authentication-method specific information),
@ -258,8 +268,10 @@ const AuthenticationDialog = new Lang.Class({
this._infoMessageLabel.hide();
this._nullMessageLabel.hide();
}
/* Try and authenticate again */
this.performAuthentication();
}
this._emitDone(!gainedAuthorization, false);
},
_onSessionRequest: function(session, request, echo_on) {
@ -303,6 +315,7 @@ const AuthenticationDialog = new Lang.Class({
if (this._session) {
if (!this._completed)
this._session.cancel();
this._completed = false;
this._session = null;
}
},
@ -317,7 +330,7 @@ const AuthenticationDialog = new Lang.Class({
cancel: function() {
this._wasDismissed = true;
this.close(global.get_current_time());
this._emitDone(false, true);
this._emitDone(true);
},
});
Signals.addSignalMethods(AuthenticationDialog.prototype);
@ -327,7 +340,6 @@ const AuthenticationAgent = new Lang.Class({
_init: function() {
this._currentDialog = null;
this._isCompleting = false;
this._handle = null;
this._native = new Shell.PolkitAuthenticationAgent();
this._native.connect('initiate', Lang.bind(this, this._onInitiate));
@ -364,45 +376,24 @@ const AuthenticationAgent = new Lang.Class({
// discussion.
this._currentDialog.connect('done', Lang.bind(this, this._onDialogDone));
this._currentDialog.startAuthentication();
this._currentDialog.performAuthentication();
},
_onCancel: function(nativeAgent) {
this._completeRequest(false, false);
this._completeRequest(false);
},
_onDialogDone: function(dialog, keepVisible, dismissed) {
this._completeRequest(keepVisible, dismissed);
_onDialogDone: function(dialog, dismissed) {
this._completeRequest(dismissed);
},
_reallyCompleteRequest: function(dismissed) {
_completeRequest: function(dismissed) {
this._currentDialog.close();
this._currentDialog.destroySession();
this._currentDialog = null;
this._isCompleting = false;
this._native.complete(dismissed)
this._native.complete(dismissed);
},
_completeRequest: function(keepVisible, wasDismissed) {
if (this._isCompleting)
return;
this._isCompleting = true;
if (keepVisible) {
// Give the user 2 seconds to read 'Authentication Failure' before
// dismissing the dialog
Mainloop.timeout_add(2000,
Lang.bind(this,
function() {
this._reallyCompleteRequest(wasDismissed);
return false;
}));
} else {
this._reallyCompleteRequest(wasDismissed);
}
}
});
const Component = AuthenticationAgent;

View File

@ -20,8 +20,7 @@ const Recorder = new Lang.Class({
Main.wm.addKeybinding('toggle-recording',
this._bindingSettings,
Meta.KeyBindingFlags.NONE,
Shell.KeyBindingMode.NORMAL |
Shell.KeyBindingMode.OVERVIEW,
Shell.KeyBindingMode.ALL,
Lang.bind(this, this._toggleRecorder));
},

View File

@ -640,6 +640,10 @@ const ChatSource = new Lang.Class({
return this._pendingMessages.length;
},
get indicatorCount() {
return this.count;
},
get unseenCount() {
return this.count;
},

View File

@ -89,21 +89,33 @@ const CtrlAltTabManager = new Lang.Class({
let items = this._items.filter(function (item) { return item.proxy.mapped; });
// And add the windows metacity would show in its Ctrl-Alt-Tab list
if (!Main.overview.visible) {
if (Main.sessionMode.hasWindows && !Main.overview.visible) {
let screen = global.screen;
let display = screen.get_display();
let windows = display.get_tab_list(Meta.TabList.DOCKS, screen, screen.get_active_workspace ());
let windowTracker = Shell.WindowTracker.get_default();
let textureCache = St.TextureCache.get_default();
for (let i = 0; i < windows.length; i++) {
let icon;
let app = windowTracker.get_window_app(windows[i]);
if (app)
icon = app.create_icon_texture(POPUP_APPICON_SIZE);
else
icon = textureCache.bind_pixbuf_property(windows[i], 'icon');
let icon = null;
let iconName = null;
if (windows[i].get_window_type () == Meta.WindowType.DESKTOP) {
iconName = 'video-display-symbolic';
} else {
let app = windowTracker.get_window_app(windows[i]);
if (app)
icon = app.create_icon_texture(POPUP_APPICON_SIZE);
else
icon = textureCache.bind_pixbuf_property(windows[i], 'icon');
}
items.push({ name: windows[i].title,
proxy: windows[i].get_compositor_private(),
focusCallback: Lang.bind(windows[i],
function(timestamp) {
Main.activateWindow(this, timestamp);
}),
iconActor: icon,
iconName: iconName,
sortGroup: SortGroup.MIDDLE });
}
}

View File

@ -33,30 +33,26 @@ function getAppFromSource(source) {
// when requesting a size
const DashItemContainer = new Lang.Class({
Name: 'DashItemContainer',
Extends: St.Widget,
_init: function() {
this.actor = new Shell.GenericContainer({ style_class: 'dash-item-container' });
this.actor.connect('get-preferred-width',
Lang.bind(this, this._getPreferredWidth));
this.actor.connect('get-preferred-height',
Lang.bind(this, this._getPreferredHeight));
this.actor.connect('allocate',
Lang.bind(this, this._allocate));
this.actor._delegate = this;
this.parent({ style_class: 'dash-item-container' });
this._labelText = "";
this.label = new St.Label({ style_class: 'dash-label'});
this.label.hide();
Main.layoutManager.addChrome(this.label);
this.actor.label_actor = this.label;
this.label_actor = this.label;
this.child = null;
this._childScale = 1;
this._childOpacity = 255;
this._childScale = 0;
this._childOpacity = 0;
this.animatingOut = false;
},
_allocate: function(actor, box, flags) {
vfunc_allocate: function(box, flags) {
this.set_allocation(box, flags);
if (this.child == null)
return;
@ -78,28 +74,28 @@ const DashItemContainer = new Lang.Class({
this.child.allocate(childBox, flags);
},
_getPreferredHeight: function(actor, forWidth, alloc) {
alloc.min_size = 0;
alloc.natural_size = 0;
vfunc_get_preferred_height: function(forWidth) {
let themeNode = this.get_theme_node();
if (this.child == null)
return;
return [0, 0];
forWidth = themeNode.adjust_for_width(forWidth);
let [minHeight, natHeight] = this.child.get_preferred_height(forWidth);
alloc.min_size += minHeight * this.child.scale_y;
alloc.natural_size += natHeight * this.child.scale_y;
return themeNode.adjust_preferred_height(minHeight * this.child.scale_y,
natHeight * this.child.scale_y);
},
_getPreferredWidth: function(actor, forHeight, alloc) {
alloc.min_size = 0;
alloc.natural_size = 0;
vfunc_get_preferred_width: function(forHeight) {
let themeNode = this.get_theme_node();
if (this.child == null)
return;
return [0, 0];
forHeight = themeNode.adjust_for_height(forHeight);
let [minWidth, natWidth] = this.child.get_preferred_width(forHeight);
alloc.min_size = minWidth * this.child.scale_y;
alloc.natural_size = natWidth * this.child.scale_y;
return themeNode.adjust_preferred_width(minWidth * this.child.scale_y,
natWidth * this.child.scale_y);
},
showLabel: function() {
@ -110,9 +106,9 @@ const DashItemContainer = new Lang.Class({
this.label.opacity = 0;
this.label.show();
let [stageX, stageY] = this.actor.get_transformed_position();
let [stageX, stageY] = this.get_transformed_position();
let itemHeight = this.actor.allocation.y2 - this.actor.allocation.y1;
let itemHeight = this.allocation.y2 - this.allocation.y1;
let labelHeight = this.label.get_height();
let yOffset = Math.floor((itemHeight - labelHeight) / 2)
@ -126,7 +122,7 @@ const DashItemContainer = new Lang.Class({
if (Clutter.get_default_text_direction() == Clutter.TextDirection.RTL)
x = stageX - this.label.get_width() - xOffset;
else
x = stageX + this.actor.get_width() + xOffset;
x = stageX + this.get_width() + xOffset;
this.label.set_position(x, y);
Tweener.addTween(this.label,
@ -156,22 +152,25 @@ const DashItemContainer = new Lang.Class({
if (this.child == actor)
return;
this.actor.destroy_all_children();
this.destroy_all_children();
this.child = actor;
this.actor.add_actor(this.child);
this.add_actor(this.child);
this.child.set_scale_with_gravity(this._childScale, this._childScale,
Clutter.Gravity.CENTER);
this.child.set_opacity(this._childOpacity);
},
animateIn: function() {
show: function(animate) {
if (this.child == null)
return;
this.childScale = 0;
this.childOpacity = 0;
let time = animate ? DASH_ANIMATION_TIME : 0;
Tweener.addTween(this,
{ childScale: 1.0,
childOpacity: 255,
time: DASH_ANIMATION_TIME,
time: time,
transition: 'easeOutQuad'
});
},
@ -180,7 +179,7 @@ const DashItemContainer = new Lang.Class({
if (this.label)
this.label.destroy();
this.actor.destroy();
this.parent();
},
animateOutAndDestroy: function() {
@ -188,19 +187,18 @@ const DashItemContainer = new Lang.Class({
this.label.destroy();
if (this.child == null) {
this.actor.destroy();
this.destroy();
return;
}
this.animatingOut = true;
this.childScale = 1.0;
Tweener.addTween(this,
{ childScale: 0.0,
childOpacity: 0,
time: DASH_ANIMATION_TIME,
transition: 'easeOutQuad',
onComplete: Lang.bind(this, function() {
this.actor.destroy();
this.destroy();
})
});
},
@ -213,7 +211,7 @@ const DashItemContainer = new Lang.Class({
this.child.set_scale_with_gravity(scale, scale,
Clutter.Gravity.CENTER);
this.actor.queue_relayout();
this.queue_relayout();
},
get childScale() {
@ -227,7 +225,7 @@ const DashItemContainer = new Lang.Class({
return;
this.child.set_opacity(opacity);
this.actor.queue_redraw();
this.queue_redraw();
},
get childOpacity() {
@ -328,6 +326,16 @@ const DragPlaceholderItem = new Lang.Class({
}
});
const EmptyDropTargetItem = new Lang.Class({
Name: 'EmptyDropTargetItem',
Extends: DashItemContainer,
_init: function() {
this.parent();
this.setChild(new St.Bin({ style_class: 'empty-dash-drop-target' }));
}
});
const DashActor = new Lang.Class({
Name: 'DashActor',
Extends: St.Widget,
@ -358,6 +366,23 @@ const DashActor = new Lang.Class({
childBox.y1 = contentBox.y2 - showAppsNatHeight;
childBox.y2 = contentBox.y2;
showAppsButton.allocate(childBox, flags);
},
vfunc_get_preferred_height: function(forWidth) {
// We want to request the natural height of all our children
// as our natural height, so we chain up to StWidget (which
// then calls BoxLayout), but we only request the showApps
// button as the minimum size
let [, natHeight] = this.parent(forWidth);
let themeNode = this.get_theme_node();
let adjustedForWidth = themeNode.adjust_for_width(forWidth);
let [, showAppsButton] = this.get_children();
let [minHeight, ] = showAppsButton.get_preferred_height(adjustedForWidth);
[minHeight, ] = themeNode.adjust_preferred_height(minHeight, natHeight);
return [minHeight, natHeight];
}
});
@ -383,12 +408,14 @@ const Dash = new Lang.Class({
this._container.add_actor(this._box);
this._showAppsIcon = new ShowAppsIcon();
this._showAppsIcon.childScale = 1;
this._showAppsIcon.childOpacity = 255;
this._showAppsIcon.icon.setIconSize(this.iconSize);
this._hookUpLabel(this._showAppsIcon);
this.showAppsButton = this._showAppsIcon.toggleButton;
this._container.add_actor(this._showAppsIcon.actor);
this._container.add_actor(this._showAppsIcon);
this.actor = new St.Bin({ child: this._container });
this.actor.connect('notify::height', Lang.bind(this,
@ -424,6 +451,12 @@ const Dash = new Lang.Class({
dragMotion: Lang.bind(this, this._onDragMotion)
};
DND.addDragMonitor(this._dragMonitor);
if (this._box.get_n_children() == 0) {
this._emptyDropTarget = new EmptyDropTargetItem();
this._box.insert_child_at_index(this._emptyDropTarget, 0);
this._emptyDropTarget.show(true);
}
},
_onDragCancelled: function() {
@ -440,6 +473,7 @@ const Dash = new Lang.Class({
_endDrag: function() {
this._clearDragPlaceholder();
this._clearEmptyDropTarget();
this._showAppsIcon.setDragApp(null);
DND.removeDragMonitor(this._dragMonitor);
},
@ -450,7 +484,7 @@ const Dash = new Lang.Class({
return DND.DragMotionResult.CONTINUE;
let showAppsHovered =
this._showAppsIcon.actor.contains(dragEvent.targetActor);
this._showAppsIcon.contains(dragEvent.targetActor);
if (!this._box.contains(dragEvent.targetActor) || showAppsHovered)
this._clearDragPlaceholder();
@ -565,13 +599,13 @@ const Dash = new Lang.Class({
// animating out (which means they will be destroyed at the end of
// the animation)
let iconChildren = this._box.get_children().filter(function(actor) {
return actor._delegate.child &&
actor._delegate.child._delegate &&
actor._delegate.child._delegate.icon &&
!actor._delegate.animatingOut;
return actor.child &&
actor.child._delegate &&
actor.child._delegate.icon &&
!actor.animatingOut;
});
iconChildren.push(this._showAppsIcon.actor);
iconChildren.push(this._showAppsIcon);
if (this._maxHeight == -1)
return;
@ -584,23 +618,18 @@ const Dash = new Lang.Class({
let availHeight = maxContent.y2 - maxContent.y1;
let spacing = themeNode.get_length('spacing');
let firstIcon = iconChildren[0]._delegate.child._delegate.icon;
let firstButton = iconChildren[0].child;
let firstIcon = firstButton._delegate.icon;
let minHeight, natHeight;
// Enforce the current icon size during the size request if
// the icon is animating
if (firstIcon._animating) {
let [currentWidth, currentHeight] = firstIcon.icon.get_size();
// Enforce the current icon size during the size request
let [currentWidth, currentHeight] = firstIcon.icon.get_size();
firstIcon.icon.set_size(this.iconSize, this.iconSize);
[minHeight, natHeight] = iconChildren[0].get_preferred_height(-1);
firstIcon.icon.set_size(this.iconSize, this.iconSize);
[minHeight, natHeight] = firstButton.get_preferred_height(-1);
firstIcon.icon.set_size(currentWidth, currentHeight);
} else {
[minHeight, natHeight] = iconChildren[0].get_preferred_height(-1);
}
firstIcon.icon.set_size(currentWidth, currentHeight);
// Subtract icon padding and box spacing from the available height
availHeight -= iconChildren.length * (natHeight - this.iconSize) +
@ -625,7 +654,7 @@ const Dash = new Lang.Class({
let scale = oldIconSize / newIconSize;
for (let i = 0; i < iconChildren.length; i++) {
let icon = iconChildren[i]._delegate.child._delegate.icon;
let icon = iconChildren[i].child._delegate.icon;
// Set the new size immediately, to keep the icons' sizes
// in sync with this.iconSize
@ -645,15 +674,11 @@ const Dash = new Lang.Class({
icon.icon.set_size(icon.icon.width * scale,
icon.icon.height * scale);
icon._animating = true;
Tweener.addTween(icon.icon,
{ width: targetWidth,
height: targetHeight,
time: DASH_ANIMATION_TIME,
transition: 'easeOutQuad',
onComplete: function() {
icon._animating = false;
}
});
}
},
@ -664,13 +689,13 @@ const Dash = new Lang.Class({
let running = this._appSystem.get_running();
let children = this._box.get_children().filter(function(actor) {
return actor._delegate.child &&
actor._delegate.child._delegate &&
actor._delegate.child._delegate.app;
return actor.child &&
actor.child._delegate &&
actor.child._delegate.app;
});
// Apps currently in the dash
let oldApps = children.map(function(actor) {
return actor._delegate.child._delegate.app;
return actor.child._delegate.app;
});
// Apps supposed to be in the dash
let newApps = [];
@ -736,7 +761,7 @@ const Dash = new Lang.Class({
let insertHere = newApps[newIndex + 1] &&
newApps[newIndex + 1] == oldApps[oldIndex];
let alreadyRemoved = removedActors.reduce(function(result, actor) {
let removedApp = actor._delegate.child._delegate.app;
let removedApp = actor.child._delegate.app;
return result || removedApp == newApps[newIndex];
}, false);
@ -753,11 +778,11 @@ const Dash = new Lang.Class({
}
for (let i = 0; i < addedItems.length; i++)
this._box.insert_child_at_index(addedItems[i].item.actor,
this._box.insert_child_at_index(addedItems[i].item,
addedItems[i].pos);
for (let i = 0; i < removedActors.length; i++) {
let item = removedActors[i]._delegate;
let item = removedActors[i];
// Don't animate item removal when the overview is transitioning
// or hidden
@ -771,25 +796,39 @@ const Dash = new Lang.Class({
// Skip animations on first run when adding the initial set
// of items, to avoid all items zooming in at once
if (!this._shownInitially) {
let animate = this._shownInitially && Main.overview.visible &&
!Main.overview.animationInProgress;
if (!this._shownInitially)
this._shownInitially = true;
return;
for (let i = 0; i < addedItems.length; i++) {
addedItems[i].item.show(animate);
}
// Don't animate item addition when the overview is transitioning
// or hidden
if (!Main.overview.visible || Main.overview.animationInProgress)
return;
for (let i = 0; i < addedItems.length; i++)
addedItems[i].item.animateIn();
// Workaround for https://bugzilla.gnome.org/show_bug.cgi?id=692744
// Without it, StBoxLayout may use a stale size cache
this._box.queue_relayout();
},
_clearDragPlaceholder: function() {
if (this._dragPlaceholder) {
this._animatingPlaceholdersCount++;
this._dragPlaceholder.animateOutAndDestroy();
this._dragPlaceholder.connect('destroy',
Lang.bind(this, function() {
this._animatingPlaceholdersCount--;
}));
this._dragPlaceholder = null;
this._dragPlaceholderPos = -1;
}
this._dragPlaceholderPos = -1;
},
_clearEmptyDropTarget: function() {
if (this._emptyDropTarget) {
this._emptyDropTarget.animateOutAndDestroy();
this._emptyDropTarget = null;
}
},
@ -813,27 +852,22 @@ const Dash = new Lang.Class({
// the remove target has the same size as "normal" items, we don't
// need to do the same adjustment there.
if (this._dragPlaceholder) {
boxHeight -= this._dragPlaceholder.actor.height;
boxHeight -= this._dragPlaceholder.height;
numChildren--;
}
let pos = Math.floor(y * numChildren / boxHeight);
let pos;
if (!this._emptyDropTarget)
pos = Math.floor(y * numChildren / boxHeight);
else
pos = 0; // always insert at the top when dash is empty
if (pos != this._dragPlaceholderPos && pos <= numFavorites && this._animatingPlaceholdersCount == 0) {
this._dragPlaceholderPos = pos;
// Don't allow positioning before or after self
if (favPos != -1 && (pos == favPos || pos == favPos + 1)) {
if (this._dragPlaceholder) {
this._dragPlaceholder.animateOutAndDestroy();
this._animatingPlaceholdersCount++;
this._dragPlaceholder.actor.connect('destroy',
Lang.bind(this, function() {
this._animatingPlaceholdersCount--;
}));
}
this._dragPlaceholder = null;
this._clearDragPlaceholder();
return DND.DragMotionResult.CONTINUE;
}
@ -842,7 +876,7 @@ const Dash = new Lang.Class({
// an animation
let fadeIn;
if (this._dragPlaceholder) {
this._dragPlaceholder.actor.destroy();
this._dragPlaceholder.destroy();
fadeIn = false;
} else {
fadeIn = true;
@ -851,17 +885,16 @@ const Dash = new Lang.Class({
this._dragPlaceholder = new DragPlaceholderItem();
this._dragPlaceholder.child.set_width (this.iconSize);
this._dragPlaceholder.child.set_height (this.iconSize / 2);
this._box.insert_child_at_index(this._dragPlaceholder.actor,
this._box.insert_child_at_index(this._dragPlaceholder,
this._dragPlaceholderPos);
if (fadeIn)
this._dragPlaceholder.animateIn();
this._dragPlaceholder.show(fadeIn);
}
// Remove the drag placeholder if we are not in the
// "favorites zone"
if (pos > numFavorites && this._dragPlaceholder) {
if (pos > numFavorites)
this._clearDragPlaceholder();
}
if (!this._dragPlaceholder)
return DND.DragMotionResult.NO_DROP;
@ -892,10 +925,10 @@ const Dash = new Lang.Class({
let children = this._box.get_children();
for (let i = 0; i < this._dragPlaceholderPos; i++) {
if (this._dragPlaceholder &&
children[i] == this._dragPlaceholder.actor)
children[i] == this._dragPlaceholder)
continue;
let childId = children[i]._delegate.child._delegate.app.get_id();
let childId = children[i].child._delegate.app.get_id();
if (childId == id)
continue;
if (childId in favorites)

View File

@ -100,7 +100,6 @@ const DateMenuButton = new Lang.Class({
Shell.AppSystem.get_default().connect('installed-changed',
Lang.bind(this, this._appInstalledChanged));
this._appInstalledChanged();
item = this.menu.addSettingsAction(_("Date & Time Settings"), 'gnome-datetime-panel.desktop');
if (item) {
@ -157,12 +156,16 @@ const DateMenuButton = new Lang.Class({
},
_appInstalledChanged: function() {
let app = Shell.AppSystem.get_default().lookup_app('gnome-clocks.desktop');
this._openClocksItem.actor.visible = app !== null;
this._calendarApp = undefined;
this._updateEventsVisibility();
},
_setEventsVisibility: function(visible) {
this._openCalendarItem.actor.visible = visible;
_updateEventsVisibility: function() {
let visible = this._eventSource.hasCalendars;
this._openCalendarItem.actor.visible = visible &&
(this._getCalendarApp() != null);
this._openClocksItem.actor.visible = visible &&
(this._getClockApp() != null);
this._separator.visible = visible;
if (visible) {
let alignment = 0.25;
@ -177,8 +180,16 @@ const DateMenuButton = new Lang.Class({
},
_setEventSource: function(eventSource) {
if (this._eventSource)
this._eventSource.destroy();
this._calendar.setEventSource(eventSource);
this._eventList.setEventSource(eventSource);
this._eventSource = eventSource;
this._eventSource.connect('notify::has-calendars', Lang.bind(this, function() {
this._updateEventsVisibility();
}));
},
_sessionUpdated: function() {
@ -187,10 +198,10 @@ const DateMenuButton = new Lang.Class({
if (showEvents) {
eventSource = new Calendar.DBusEventSource();
} else {
eventSource = null;
eventSource = new Calendar.EmptyEventSource();
}
this._setEventSource(eventSource);
this._setEventsVisibility(showEvents);
this._updateEventsVisibility();
// This needs to be handled manually, as the code to
// autohide separators doesn't work across the vbox
@ -207,16 +218,34 @@ const DateMenuButton = new Lang.Class({
this._date.set_text(displayDate.toLocaleFormat(dateFormat));
},
_getCalendarApp: function() {
if (this._calendarApp !== undefined)
return this._calendarApp;
let apps = Gio.AppInfo.get_recommended_for_type('text/calendar');
if (apps && (apps.length > 0))
this._calendarApp = apps[0];
else
this._calendarApp = null;
return this._calendarApp;
},
_getClockApp: function() {
return Shell.AppSystem.get_default().lookup_app('gnome-clocks.desktop');
},
_onOpenCalendarActivate: function() {
this.menu.close();
let app = Gio.AppInfo.get_default_for_type('text/calendar', false);
let app = this._getCalendarApp();
if (app.get_id() == 'evolution.desktop')
app = Gio.DesktopAppInfo.new('evolution-calendar.desktop');
app.launch([], global.create_app_launch_context());
},
_onOpenClocksActivate: function() {
this.menu.close();
let app = Shell.AppSystem.get_default().lookup_app('gnome-clocks.desktop');
let app = this._getClockApp();
app.activate();
}
});

View File

@ -85,11 +85,13 @@ 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)
if (this._dragInProgress && this._dragCancellable)
this._cancelDrag(global.get_current_time());
this.disconnectAll();
}));
@ -102,6 +104,7 @@ const _Draggable = new Lang.Class({
this._buttonDown = false; // The mouse button has been pressed and has not yet been released.
this._dragInProgress = false; // The drag has been started, and has not been dropped or cancelled yet.
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
@ -146,16 +149,16 @@ const _Draggable = new Lang.Class({
_grabEvents: function() {
if (!this._eventsGrabbed) {
Clutter.grab_pointer(_getEventHandlerActor());
Clutter.grab_keyboard(_getEventHandlerActor());
this._eventsGrabbed = true;
this._eventsGrabbed = Main.pushModal(_getEventHandlerActor());
if (this._eventsGrabbed)
Clutter.grab_pointer(_getEventHandlerActor());
}
},
_ungrabEvents: function() {
if (this._eventsGrabbed) {
Clutter.ungrab_pointer();
Clutter.ungrab_keyboard();
Main.popModal(_getEventHandlerActor());
this._eventsGrabbed = false;
}
},
@ -288,19 +291,19 @@ const _Draggable = new Lang.Class({
this._dragOrigY = this._dragActor.y;
this._dragOrigScale = this._dragActor.scale_x;
this._dragActor.reparent(Main.uiGroup);
this._dragActor.raise_top();
Shell.util_set_hidden_from_pick(this._dragActor, true);
// Set the actor's scale such that it will keep the same
// transformed size when it's reparented to the uiGroup
let [scaledWidth, scaledHeight] = this.actor.get_transformed_size();
this._dragActor.set_scale(scaledWidth / this.actor.width,
scaledHeight / this.actor.height);
let [actorStageX, actorStageY] = this.actor.get_transformed_position();
this._dragOffsetX = actorStageX - this._dragStartX;
this._dragOffsetY = actorStageY - this._dragStartY;
// Set the actor's scale such that it will keep the same
// transformed size when it's reparented to the uiGroup
let [scaledWidth, scaledHeight] = this.actor.get_transformed_size();
this.actor.set_scale(scaledWidth / this.actor.width,
scaledHeight / this.actor.height);
this._dragActor.reparent(Main.uiGroup);
this._dragActor.raise_top();
Shell.util_set_hidden_from_pick(this._dragActor, true);
}
this._dragOrigOpacity = this._dragActor.opacity;
@ -439,6 +442,11 @@ const _Draggable = new Lang.Class({
}
}
// At this point it is too late to cancel a drag by destroying
// the actor, the fate of which is decided by acceptDrop and its
// side-effects
this._dragCancellable = false;
while (target) {
if (target._delegate && target._delegate.acceptDrop) {
let [r, targX, targY] = target.transform_stage_point(dropX, dropY);
@ -447,8 +455,6 @@ const _Draggable = new Lang.Class({
targX,
targY,
event.get_time())) {
if (this._actorDestroyed)
return true;
// If it accepted the drop without taking the actor,
// handle it ourselves.
if (this._dragActor.get_parent() == Main.uiGroup) {

View File

@ -225,7 +225,8 @@ const EndSessionDialog = new Lang.Class({
Extends: ModalDialog.ModalDialog,
_init: function() {
this.parent({ styleClass: 'end-session-dialog' });
this.parent({ styleClass: 'end-session-dialog',
destroyOnClose: false });
this._user = AccountsService.UserManager.get_default().get_user(GLib.get_user_name());

View File

@ -248,7 +248,7 @@ const GrabHelper = new Lang.Class({
global.set_stage_input_mode(Shell.StageInputMode.FOCUSED);
}
global.screen.focus_default_window(global.get_current_time());
global.screen.focus_default_window(global.display.get_current_time_roundtrip());
},
// ignoreRelease:
@ -308,6 +308,8 @@ const GrabHelper = new Lang.Class({
if (!this.grabbed && this._capturedEventId > 0) {
global.stage.disconnect(this._capturedEventId);
this._capturedEventId = 0;
this._ignoreRelease = false;
}
if (hadFocus) {
@ -353,6 +355,7 @@ const GrabHelper = new Lang.Class({
this._ignoreRelease = true;
let i = this._actorInGrabStack(event.get_source()) + 1;
this.ungrab({ actor: this._grabStack[i].actor, isUser: true });
return true;
}
return this._modalCount > 0;

View File

@ -176,13 +176,16 @@ const IconGrid = new Lang.Class({
_init: function(params) {
params = Params.parse(params, { rowLimit: null,
columnLimit: null,
fillParent: false,
xAlign: St.Align.MIDDLE });
this._rowLimit = params.rowLimit;
this._colLimit = params.columnLimit;
this._xAlign = params.xAlign;
this._fillParent = params.fillParent;
this.actor = new St.BoxLayout({ style_class: 'icon-grid',
vertical: true });
// Pulled from CSS, but hardcode some defaults here
this._spacing = 0;
this._hItemSize = this._vItemSize = ICON_SIZE;
@ -196,6 +199,11 @@ const IconGrid = new Lang.Class({
},
_getPreferredWidth: function (grid, forHeight, alloc) {
if (this._fillParent)
// Ignore all size requests of children and request a size of 0;
// later we'll allocate as many children as fit the parent
return;
let children = this._grid.get_children();
let nColumns = this._colLimit ? Math.min(this._colLimit,
children.length)
@ -217,12 +225,20 @@ const IconGrid = new Lang.Class({
},
_getPreferredHeight: function (grid, forWidth, alloc) {
if (this._fillParent)
// Ignore all size requests of children and request a size of 0;
// later we'll allocate as many children as fit the parent
return;
let children = this._getVisibleChildren();
let nColumns;
if (forWidth < 0)
let nColumns, spacing;
if (forWidth < 0) {
nColumns = children.length;
else
nColumns = this._computeLayout(forWidth)[0];
spacing = this._spacing;
} else {
[nColumns, , spacing] = this._computeLayout(forWidth);
}
let nRows;
if (nColumns > 0)
nRows = Math.ceil(children.length / nColumns);
@ -230,13 +246,20 @@ const IconGrid = new Lang.Class({
nRows = 0;
if (this._rowLimit)
nRows = Math.min(nRows, this._rowLimit);
let totalSpacing = Math.max(0, nRows - 1) * this._spacing;
let totalSpacing = Math.max(0, nRows - 1) * spacing;
let height = nRows * this._vItemSize + totalSpacing;
alloc.min_size = height;
alloc.natural_size = height;
},
_allocate: function (grid, box, flags) {
if (this._fillParent) {
// Reset the passed in box to fill the parent
let parentBox = this.actor.get_parent().allocation;
let gridBox = this.actor.get_theme_node().get_content_box(parentBox);
box = this._grid.get_theme_node().get_content_box(gridBox);
}
let children = this._getVisibleChildren();
let availWidth = box.x2 - box.x1;
let availHeight = box.y2 - box.y1;
@ -280,7 +303,8 @@ const IconGrid = new Lang.Class({
childBox.x2 = childBox.x1 + width;
childBox.y2 = childBox.y1 + height;
if (this._rowLimit && rowIndex >= this._rowLimit) {
if (this._rowLimit && rowIndex >= this._rowLimit ||
this._fillParent && childBox.y2 > availHeight) {
this._grid.set_skip_paint(children[i], true);
} else {
children[i].allocate(childBox, flags);

View File

@ -1,6 +1,7 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
const Clutter = imports.gi.Clutter;
const GLib = imports.gi.GLib;
const GObject = imports.gi.GObject;
const Lang = imports.lang;
const Mainloop = imports.mainloop;
@ -17,7 +18,6 @@ const Main = imports.ui.main;
const Params = imports.misc.params;
const Tweener = imports.ui.tweener;
const HOT_CORNER_ACTIVATION_TIMEOUT = 0.5;
const STARTUP_ANIMATION_TIME = 0.5;
const KEYBOARD_ANIMATION_TIME = 0.15;
const BACKGROUND_FADE_ANIMATION_TIME = 1.0;
@ -25,8 +25,11 @@ const DEFAULT_BACKGROUND_COLOR = Clutter.Color.from_pixel(0x2e3436ff);
// The message tray takes this much pressure
// in the pressure barrier at once to release it.
const MESSAGE_TRAY_PRESSURE_THRESHOLD = 200; // pixels
const MESSAGE_TRAY_PRESSURE_TIMEOUT = 3000; // ms
const MESSAGE_TRAY_PRESSURE_THRESHOLD = 250; // pixels
const MESSAGE_TRAY_PRESSURE_TIMEOUT = 1000; // ms
const HOT_CORNER_PRESSURE_THRESHOLD = 100; // pixels
const HOT_CORNER_PRESSURE_TIMEOUT = 1000; // ms
function isPopupMetaWindow(actor) {
switch(actor.meta_window.get_window_type()) {
@ -129,9 +132,9 @@ const LayoutManager = new Lang.Class({
this.monitors = [];
this.primaryMonitor = null;
this.primaryIndex = -1;
this.hotCorners = [];
this._keyboardIndex = -1;
this._hotCorners = [];
this._leftPanelBarrier = null;
this._rightPanelBarrier = null;
this._trayBarrier = null;
@ -139,6 +142,7 @@ const LayoutManager = new Lang.Class({
this._updateRegionIdle = 0;
this._trackedActors = [];
this._topActors = [];
this._isPopupWindowVisible = false;
this._startingUp = true;
@ -190,6 +194,7 @@ const LayoutManager = new Lang.Class({
this.trayBox = new St.Widget({ name: 'trayBox',
layout_manager: new Clutter.BinLayout() });
this.addChrome(this.trayBox);
this._setupTrayPressure();
this.keyboardBox = new St.BoxLayout({ name: 'keyboardBox',
reactive: true,
@ -200,9 +205,6 @@ const LayoutManager = new Lang.Class({
global.stage.remove_actor(global.top_window_group);
this.uiGroup.add_actor(global.top_window_group);
this._consoleBackgroundGroup = new Meta.BackgroundGroup();
global.stage.insert_child_below(this._consoleBackgroundGroup, null);
this._backgroundGroup = new Meta.BackgroundGroup();
global.window_group.add_child(this._backgroundGroup);
this._backgroundGroup.lower_bottom();
@ -220,6 +222,8 @@ const LayoutManager = new Lang.Class({
Lang.bind(this, this._windowsRestacked));
global.screen.connect('monitors-changed',
Lang.bind(this, this._monitorsChanged));
global.screen.connect('in-fullscreen-changed',
Lang.bind(this, this._updateFullscreen));
this._monitorsChanged();
},
@ -230,6 +234,8 @@ const LayoutManager = new Lang.Class({
Main.overview.connect('showing', Lang.bind(this, this._overviewShowing));
Main.overview.connect('hidden', Lang.bind(this, this._overviewHidden));
Main.sessionMode.connect('updated', Lang.bind(this, this._sessionUpdated));
this._prepareStartupAnimation();
},
_overviewShowing: function() {
@ -277,56 +283,58 @@ const LayoutManager = new Lang.Class({
_updateHotCorners: function() {
// destroy old hot corners
for (let i = 0; i < this._hotCorners.length; i++)
this._hotCorners[i].destroy();
this._hotCorners = [];
for (let i = 0; i < this.hotCorners.length; i++)
this.hotCorners[i].destroy();
this.hotCorners = [];
let size = this.panelBox.height;
// build new hot corners
for (let i = 0; i < this.monitors.length; i++) {
if (i == this.primaryIndex)
continue;
let monitor = this.monitors[i];
let cornerX = this._rtl ? monitor.x + monitor.width : monitor.x;
let cornerY = monitor.y;
let haveTopLeftCorner = true;
if (i != this.primaryIndex) {
let haveTopLeftCorner = true;
// Check if we have a top left (right for RTL) corner.
// I.e. if there is no monitor directly above or to the left(right)
let besideX = this._rtl ? monitor.x + 1 : cornerX - 1;
let besideY = cornerY;
let aboveX = cornerX;
let aboveY = cornerY - 1;
// Check if we have a top left (right for RTL) corner.
// I.e. if there is no monitor directly above or to the left(right)
let besideX = this._rtl ? monitor.x + 1 : cornerX - 1;
let besideY = cornerY;
let aboveX = cornerX;
let aboveY = cornerY - 1;
for (let j = 0; j < this.monitors.length; j++) {
if (i == j)
for (let j = 0; j < this.monitors.length; j++) {
if (i == j)
continue;
let otherMonitor = this.monitors[j];
if (besideX >= otherMonitor.x &&
besideX < otherMonitor.x + otherMonitor.width &&
besideY >= otherMonitor.y &&
besideY < otherMonitor.y + otherMonitor.height) {
haveTopLeftCorner = false;
break;
}
if (aboveX >= otherMonitor.x &&
aboveX < otherMonitor.x + otherMonitor.width &&
aboveY >= otherMonitor.y &&
aboveY < otherMonitor.y + otherMonitor.height) {
haveTopLeftCorner = false;
break;
}
}
if (!haveTopLeftCorner)
continue;
let otherMonitor = this.monitors[j];
if (besideX >= otherMonitor.x &&
besideX < otherMonitor.x + otherMonitor.width &&
besideY >= otherMonitor.y &&
besideY < otherMonitor.y + otherMonitor.height) {
haveTopLeftCorner = false;
break;
}
if (aboveX >= otherMonitor.x &&
aboveX < otherMonitor.x + otherMonitor.width &&
aboveY >= otherMonitor.y &&
aboveY < otherMonitor.y + otherMonitor.height) {
haveTopLeftCorner = false;
break;
}
}
if (!haveTopLeftCorner)
continue;
let corner = new HotCorner(this);
this._hotCorners.push(corner);
corner.actor.set_position(cornerX, cornerY);
this.addChrome(corner.actor);
let corner = new HotCorner(this, monitor, cornerX, cornerY);
corner.setBarrierSize(size);
this.hotCorners.push(corner);
}
this.emit('hot-corners-changed');
},
_createBackground: function(monitorIndex) {
@ -396,16 +404,15 @@ const LayoutManager = new Lang.Class({
},
_panelBoxChanged: function() {
this.emit('panel-box-changed');
this._updatePanelBarriers();
this._updatePanelBarrier();
let size = this.panelBox.height;
this.hotCorners.forEach(function(corner) {
corner.setBarrierSize(size);
});
},
_updatePanelBarriers: function() {
if (this._leftPanelBarrier) {
this._leftPanelBarrier.destroy();
this._leftPanelBarrier = null;
}
_updatePanelBarrier: function() {
if (this._rightPanelBarrier) {
this._rightPanelBarrier.destroy();
this._rightPanelBarrier = null;
@ -414,10 +421,6 @@ const LayoutManager = new Lang.Class({
if (this.panelBox.height) {
let primary = this.primaryMonitor;
this._leftPanelBarrier = new Meta.Barrier({ display: global.display,
x1: primary.x, y1: primary.y,
x2: primary.x, y2: primary.y + this.panelBox.height,
directions: Meta.BarrierDirection.POSITIVE_X });
this._rightPanelBarrier = new Meta.Barrier({ display: global.display,
x1: primary.x + primary.width, y1: primary.y,
x2: primary.x + primary.width, y2: primary.y + this.panelBox.height,
@ -425,28 +428,44 @@ const LayoutManager = new Lang.Class({
}
},
_setupTrayPressure: function() {
this._trayPressure = new PressureBarrier(MESSAGE_TRAY_PRESSURE_THRESHOLD,
MESSAGE_TRAY_PRESSURE_TIMEOUT,
Shell.KeyBindingMode.NORMAL |
Shell.KeyBindingMode.OVERVIEW);
this._trayPressure.setEventFilter(this._trayBarrierEventFilter);
this._trayPressure.connect('trigger', function(barrier) {
if (Main.layoutManager.bottomMonitor.inFullscreen)
return;
Main.messageTray.openTray();
});
},
_updateTrayBarrier: function() {
let monitor = this.bottomMonitor;
if (this._trayBarrier) {
this._trayPressure.removeBarrier(this._trayBarrier);
this._trayBarrier.destroy();
this._trayBarrier = null;
}
if (this._trayPressure) {
this._trayPressure.destroy();
this._trayPressure = null;
}
this._trayBarrier = new Meta.Barrier({ display: global.display,
x1: monitor.x, x2: monitor.x + monitor.width,
y1: monitor.y + monitor.height, y2: monitor.y + monitor.height,
directions: Meta.BarrierDirection.NEGATIVE_Y });
this._trayPressure.addBarrier(this._trayBarrier);
},
this._trayPressure = new PressureBarrier(this._trayBarrier, MESSAGE_TRAY_PRESSURE_THRESHOLD, MESSAGE_TRAY_PRESSURE_TIMEOUT);
this._trayPressure.connect('trigger', function(barrier) {
Main.messageTray.openTray();
});
_trayBarrierEventFilter: function(event) {
// Throw out all events where the pointer was grabbed by another
// client, as the client that grabbed the pointer expects to have
// complete control over it
if (event.grabbed && Main.modalCount == 0)
return true;
return false;
},
_monitorsChanged: function() {
@ -536,22 +555,11 @@ const LayoutManager = new Lang.Class({
// MetaBackgroundActor inside global.window_group covers the entirety of the
// screen. So, we set no_clear_hint at the end of the animation.
prepareStartupAnimation: function() {
_prepareStartupAnimation: function() {
// Set ourselves to FULLSCREEN input mode while the animation is running
// so events don't get delivered to X11 windows (which are distorted by the animation)
global.stage_input_mode = Shell.StageInputMode.FULLSCREEN;
// build new backgrounds
for (let i = 0; i < this.monitors.length; i++) {
let monitor = this.monitors[i];
let stillFrame = new Background.StillFrame(i);
this._consoleBackgroundGroup.add_child(stillFrame.actor);
stillFrame.actor.set_size(this.monitors[i].width, this.monitors[i].height);
stillFrame.actor.set_position(this.monitors[i].x, this.monitors[i].y);
}
if (Main.sessionMode.isGreeter) {
this.panelBox.translation_y = -this.panelBox.height;
} else {
@ -568,11 +576,43 @@ const LayoutManager = new Lang.Class({
this.uiGroup.set_pivot_point(x / global.screen_width,
y / global.screen_height);
this.uiGroup.scale_x = this.uiGroup.scale_y = 0;
this.uiGroup.scale_x = this.uiGroup.scale_y = 0.5;
this.uiGroup.opacity = 0;
global.window_group.set_clip(monitor.x, monitor.y, monitor.width, monitor.height);
}
this._systemBackground = new Background.SystemBackground();
this._systemBackground.actor.hide();
global.stage.insert_child_below(this._systemBackground.actor, null);
let constraint = new Clutter.BindConstraint({ source: global.stage,
coordinate: Clutter.BindCoordinate.ALL });
this._systemBackground.actor.add_constraint(constraint);
let signalId = this._systemBackground.connect('loaded',
Lang.bind(this, function() {
this._systemBackground.disconnect(signalId);
this._systemBackground.actor.show();
global.stage.show();
this.emit('startup-prepared');
// We're mostly prepared for the startup animation
// now, but since a lot is going on asynchronously
// during startup, let's defer the startup animation
// until the event loop is uncontended and idle.
// This helps to prevent us from running the animation
// when the system is bogged down
GLib.idle_add(GLib.PRIORITY_LOW,
Lang.bind(this, function() {
this._startupAnimation();
return false;
}));
}));
},
startupAnimation: function() {
_startupAnimation: function() {
if (Main.sessionMode.isGreeter)
this._startupAnimationGreeter();
else
@ -593,6 +633,7 @@ const LayoutManager = new Lang.Class({
Tweener.addTween(this.uiGroup,
{ scale_x: 1,
scale_y: 1,
opacity: 255,
time: STARTUP_ANIMATION_TIME,
transition: 'easeOutQuad',
onComplete: this._startupAnimationComplete,
@ -606,20 +647,22 @@ const LayoutManager = new Lang.Class({
global.stage_input_mode = Shell.StageInputMode.NORMAL;
this._consoleBackgroundGroup.destroy();
this._consoleBackgroundGroup = null;
this._systemBackground.actor.destroy();
this._systemBackground = null;
this._startingUp = false;
this.trayBox.show();
this.keyboardBox.show();
if (!Main.sessionMode.isGreeter)
if (!Main.sessionMode.isGreeter) {
this._createSecondaryBackgrounds();
this.emit('panel-box-changed');
global.window_group.remove_clip();
}
this._queueUpdateRegions();
this.emit('startup-complete');
},
showKeyboard: function () {
@ -795,6 +838,11 @@ const LayoutManager = new Lang.Class({
},
_updateVisibility: function() {
let windowsVisible = Main.sessionMode.hasWindows && !this._inOverview;
global.window_group.visible = windowsVisible;
global.top_window_group.visible = windowsVisible;
for (let i = 0; i < this._trackedActors.length; i++) {
let actorData = this._trackedActors[i], visible;
if (!actorData.trackFullscreen)
@ -802,7 +850,7 @@ const LayoutManager = new Lang.Class({
if (!actorData.isToplevel)
continue;
if (this._inOverview || !Main.sessionMode.hasWindows)
if (!windowsVisible)
visible = true;
else if (this.findMonitorForActor(actorData.actor).inFullscreen)
visible = false;
@ -852,92 +900,25 @@ const LayoutManager = new Lang.Class({
},
_updateFullscreen: function() {
let windows = this._getWindowActorsForWorkspace(global.screen.get_active_workspace());
// Reset all monitors to not fullscreen
for (let i = 0; i < this.monitors.length; i++)
this.monitors[i].inFullscreen = false;
this.monitors[i].inFullscreen = global.screen.get_monitor_in_fullscreen (i);
// Ordinary chrome should be visible unless there is a window
// with layer FULLSCREEN, or a window with layer
// OVERRIDE_REDIRECT that covers the whole screen.
// ('override_redirect' is not actually a layer above all
// other windows, but this seems to be how mutter treats it
// currently...) If we wanted to be extra clever, we could
// figure out when an OVERRIDE_REDIRECT window was trying to
// partially overlap us, and then adjust the input region and
// our clip region accordingly...
this._updateVisibility();
this._queueUpdateRegions();
// @windows is sorted bottom to top.
for (let i = windows.length - 1; i > -1; i--) {
let window = windows[i];
let metaWindow = window.meta_window;
let layer = metaWindow.get_layer();
// Skip minimized windows
if (!metaWindow.showing_on_its_workspace())
continue;
if (layer == Meta.StackLayer.FULLSCREEN ||
(layer == Meta.StackLayer.OVERRIDE_REDIRECT && metaWindow.is_monitor_sized())) {
if (metaWindow.is_screen_sized()) {
for (let i = 0; i < this.monitors.length; i++)
this.monitors[i].inFullscreen = true;
} else {
let monitor = this.monitors[metaWindow.get_monitor()];
if (monitor)
monitor.inFullscreen = true;
}
}
}
this.emit('fullscreen-changed');
},
_windowsRestacked: function() {
let wasInFullscreen = [];
for (let i = 0; i < this.monitors.length; i++)
wasInFullscreen[i] = this.monitors[i].inFullscreen;
let primaryWasInFullscreen = this.primaryMonitor.inFullscreen;
this._updateFullscreen();
let changed = false;
for (let i = 0; i < wasInFullscreen.length; i++) {
if (wasInFullscreen[i] != this.monitors[i].inFullscreen) {
changed = true;
break;
}
}
if (!changed && (this._isPopupWindowVisible != global.top_window_group.get_children().some(isPopupMetaWindow)))
if (this._isPopupWindowVisible != global.top_window_group.get_children().some(isPopupMetaWindow))
changed = true;
if (changed) {
this._updateVisibility();
this._queueUpdateRegions();
}
if (primaryWasInFullscreen != this.primaryMonitor.inFullscreen) {
let windows = this._getWindowActorsForWorkspace(global.screen.get_active_workspace());
for (let i = 0; i < windows.length - 1; i++) {
let window = windows[i];
let metaWindow = window.meta_window;
// Skip minimized windows
if (!metaWindow.showing_on_its_workspace())
continue;
// Skip windows that aren't on the primary monitor
if (!metaWindow.is_on_primary_monitor())
continue;
// Minimize monitor sized windows
if (metaWindow.is_monitor_sized())
metaWindow.minimize();
}
this.emit('primary-fullscreen-changed', this.primaryMonitor.inFullscreen);
}
},
_updateRegions: function() {
@ -1067,54 +1048,25 @@ Signals.addSignalMethods(LayoutManager.prototype);
const HotCorner = new Lang.Class({
Name: 'HotCorner',
_init : function(layoutManager) {
_init : function(layoutManager, monitor, x, y) {
// We use this flag to mark the case where the user has entered the
// hot corner and has not left both the hot corner and a surrounding
// guard area (the "environs"). This avoids triggering the hot corner
// multiple times due to an accidental jitter.
this._entered = false;
this.actor = new Clutter.Group({ name: 'hot-corner-environs',
width: 3,
height: 3,
reactive: true });
this._monitor = monitor;
this._corner = new Clutter.Rectangle({ name: 'hot-corner',
width: 1,
height: 1,
opacity: 0,
reactive: true });
this._corner._delegate = this;
this._x = x;
this._y = y;
this.actor.add_actor(this._corner);
this._setupFallbackCornerIfNeeded(layoutManager);
if (Clutter.get_default_text_direction() == Clutter.TextDirection.RTL) {
this._corner.set_position(this.actor.width - this._corner.width, 0);
this.actor.set_anchor_point_from_gravity(Clutter.Gravity.NORTH_EAST);
} else {
this._corner.set_position(0, 0);
}
this._activationTime = 0;
this.actor.connect('leave-event',
Lang.bind(this, this._onEnvironsLeft));
// Clicking on the hot corner environs should result in the
// same behavior as clicking on the hot corner.
this.actor.connect('button-release-event',
Lang.bind(this, this._onCornerClicked));
// In addition to being triggered by the mouse enter event,
// the hot corner can be triggered by clicking on it. This is
// useful if the user wants to undo the effect of triggering
// the hot corner once in the hot corner.
this._corner.connect('enter-event',
Lang.bind(this, this._onCornerEntered));
this._corner.connect('button-release-event',
Lang.bind(this, this._onCornerClicked));
this._corner.connect('leave-event',
Lang.bind(this, this._onCornerLeft));
this._pressureBarrier = new PressureBarrier(HOT_CORNER_PRESSURE_THRESHOLD,
HOT_CORNER_PRESSURE_TIMEOUT,
Shell.KeyBindingMode.NORMAL |
Shell.KeyBindingMode.OVERVIEW);
this._pressureBarrier.connect('trigger', Lang.bind(this, this._toggleOverview));
// Cache the three ripples instead of dynamically creating and destroying them.
this._ripple1 = new St.BoxLayout({ style_class: 'ripple-box', opacity: 0, visible: false });
@ -1126,8 +1078,83 @@ const HotCorner = new Lang.Class({
layoutManager.uiGroup.add_actor(this._ripple3);
},
setBarrierSize: function(size) {
if (this._verticalBarrier) {
this._pressureBarrier.removeBarrier(this._verticalBarrier);
this._verticalBarrier.destroy();
this._verticalBarrier = null;
}
if (this._horizontalBarrier) {
this._pressureBarrier.removeBarrier(this._horizontalBarrier);
this._horizontalBarrier.destroy();
this._horizontalBarrier = null;
}
if (size > 0) {
if (Clutter.get_default_text_direction() == Clutter.TextDirection.RTL) {
this._verticalBarrier = new Meta.Barrier({ display: global.display,
x1: this._x, x2: this._x, y1: this._y, y2: this._y + size,
directions: Meta.BarrierDirection.NEGATIVE_X });
this._horizontalBarrier = new Meta.Barrier({ display: global.display,
x1: this._x - size, x2: this._x, y1: this._y, y2: this._y,
directions: Meta.BarrierDirection.POSITIVE_Y });
} else {
this._verticalBarrier = new Meta.Barrier({ display: global.display,
x1: this._x, x2: this._x, y1: this._y, y2: this._y + size,
directions: Meta.BarrierDirection.POSITIVE_X });
this._horizontalBarrier = new Meta.Barrier({ display: global.display,
x1: this._x, x2: this._x + size, y1: this._y, y2: this._y,
directions: Meta.BarrierDirection.POSITIVE_Y });
}
this._pressureBarrier.addBarrier(this._verticalBarrier);
this._pressureBarrier.addBarrier(this._horizontalBarrier);
}
},
_setupFallbackCornerIfNeeded: function(layoutManager) {
if (!global.display.supports_extended_barriers()) {
this.actor = new Clutter.Actor({ name: 'hot-corner-environs',
x: this._x, y: this._y,
width: 3,
height: 3,
reactive: true });
this._corner = new Clutter.Rectangle({ name: 'hot-corner',
width: 1,
height: 1,
opacity: 0,
reactive: true });
this._corner._delegate = this;
this.actor.add_child(this._corner);
layoutManager.addChrome(this.actor);
if (Clutter.get_default_text_direction() == Clutter.TextDirection.RTL) {
this._corner.set_position(this.actor.width - this._corner.width, 0);
this.actor.set_anchor_point_from_gravity(Clutter.Gravity.NORTH_EAST);
} else {
this._corner.set_position(0, 0);
}
this.actor.connect('leave-event',
Lang.bind(this, this._onEnvironsLeft));
this._corner.connect('enter-event',
Lang.bind(this, this._onCornerEntered));
this._corner.connect('leave-event',
Lang.bind(this, this._onCornerLeft));
}
},
destroy: function() {
this.actor.destroy();
this.setBarrierSize(0);
this._pressureBarrier.destroy();
this._pressureBarrier = null;
if (this.actor)
this.actor.destroy();
},
_animRipple : function(ripple, delay, time, startScale, startOpacity, finalScale) {
@ -1147,9 +1174,8 @@ const HotCorner = new Lang.Class({
ripple.opacity = 255 * Math.sqrt(startOpacity);
ripple.scale_x = ripple.scale_y = startScale;
let [x, y] = this._corner.get_transformed_position();
ripple.x = x;
ripple.y = y;
ripple.x = this._x;
ripple.y = this._y;
Tweener.addTween(ripple, { _opacity: 0,
scale_x: finalScale,
@ -1161,7 +1187,7 @@ const HotCorner = new Lang.Class({
onComplete: function() { ripple.visible = false; } });
},
rippleAnimation: function() {
_rippleAnimation: function() {
// Show three concentric ripples expanding outwards; the exact
// parameters were found by trial and error, so don't look
// for them to make perfect sense mathematically
@ -1172,14 +1198,21 @@ const HotCorner = new Lang.Class({
this._animRipple(this._ripple3, 0.35, 1.0, 0.0, 0.3, 1);
},
_toggleOverview: function() {
if (this._monitor.inFullscreen)
return;
if (Main.overview.shouldToggleByCornerOrButton()) {
this._rippleAnimation();
Main.overview.toggle();
}
},
handleDragOver: function(source, actor, x, y, time) {
if (source != Main.xdndHandler)
return DND.DragMotionResult.CONTINUE;
if (!Main.overview.visible && !Main.overview.animationInProgress) {
this.rippleAnimation();
Main.overview.showTemporarily();
}
this._toggleOverview();
return DND.DragMotionResult.CONTINUE;
},
@ -1187,22 +1220,11 @@ const HotCorner = new Lang.Class({
_onCornerEntered : function() {
if (!this._entered) {
this._entered = true;
if (!Main.overview.animationInProgress) {
this._activationTime = Date.now() / 1000;
this.rippleAnimation();
Main.overview.toggle();
}
this._toggleOverview();
}
return false;
},
_onCornerClicked : function() {
if (this.shouldToggleOverviewOnClick())
Main.overview.toggle();
return true;
},
_onCornerLeft : function(actor, event) {
if (event.get_related() != this.actor)
this._entered = false;
@ -1214,42 +1236,47 @@ const HotCorner = new Lang.Class({
if (event.get_related() != this._corner)
this._entered = false;
return false;
},
// Checks if the Activities button is currently sensitive to
// clicks. The first call to this function within the
// HOT_CORNER_ACTIVATION_TIMEOUT time of the hot corner being
// triggered will return false. This avoids opening and closing
// the overview if the user both triggered the hot corner and
// clicked the Activities button.
shouldToggleOverviewOnClick: function() {
if (Main.overview.animationInProgress)
return false;
if (this._activationTime == 0 || Date.now() / 1000 - this._activationTime > HOT_CORNER_ACTIVATION_TIMEOUT)
return true;
return false;
}
});
const PressureBarrier = new Lang.Class({
Name: 'PressureBarrier',
_init: function(barrier, threshold, timeout) {
this._barrier = barrier;
_init: function(threshold, timeout, keybindingMode) {
this._threshold = threshold;
this._timeout = timeout;
this._orientation = (barrier.y1 == barrier.y2) ? Clutter.Orientation.HORIZONTAL : Clutter.Orientation.VERTICAL;
this._keybindingMode = keybindingMode;
this._barriers = [];
this._eventFilter = null;
this._isTriggered = false;
this._reset();
},
this._barrierHitId = this._barrier.connect('hit', Lang.bind(this, this._onBarrierHit));
this._barrierLeftId = this._barrier.connect('left', Lang.bind(this, this._onBarrierLeft));
addBarrier: function(barrier) {
barrier._pressureHitId = barrier.connect('hit', Lang.bind(this, this._onBarrierHit));
barrier._pressureLeftId = barrier.connect('left', Lang.bind(this, this._onBarrierLeft));
this._barriers.push(barrier);
},
_disconnectBarrier: function(barrier) {
barrier.disconnect(barrier._pressureHitId);
barrier.disconnect(barrier._pressureLeftId);
},
removeBarrier: function(barrier) {
this._disconnectBarrier(barrier);
this._barriers.splice(this._barriers.indexOf(barrier), 1);
},
destroy: function() {
this._barrier.disconnect(this._barrierHitId);
this._barrier.disconnect(this._barrierLeftId);
this._barrier = null;
this._barriers.forEach(Lang.bind(this, this._disconnectBarrier));
this._barriers = [];
},
setEventFilter: function(filter) {
this._eventFilter = filter;
},
_reset: function() {
@ -1258,33 +1285,34 @@ const PressureBarrier = new Lang.Class({
this._lastTime = 0;
},
_getDistanceAcrossBarrier: function(event) {
if (this._orientation == Clutter.Orientation.HORIZONTAL)
_isHorizontal: function(barrier) {
return barrier.y1 == barrier.y2;
},
_getDistanceAcrossBarrier: function(barrier, event) {
if (this._isHorizontal(barrier))
return Math.abs(event.dy);
else
return Math.abs(event.dx);
},
_getDistanceAlongBarrier: function(event) {
if (this._orientation == Clutter.Orientation.HORIZONTAL)
_getDistanceAlongBarrier: function(barrier, event) {
if (this._isHorizontal(barrier))
return Math.abs(event.dx);
else
return Math.abs(event.dy);
},
_isBarrierEventTooOld: function(event) {
// Ignore all events older than this time
let threshold = this._lastTime - this._timeout;
return event.time < threshold;
},
_trimBarrierEvents: function() {
// Events are guaranteed to be sorted in time order from
// oldest to newest, so just look for the first old event,
// and then chop events after that off.
let i = 0;
let threshold = this._lastTime - this._timeout;
while (i < this._barrierEvents.length) {
if (!this._isBarrierEventTooOld(this._barrierEvents[i]))
let [time, distance] = this._barrierEvents[i];
if (time >= threshold)
break;
i++;
}
@ -1292,7 +1320,8 @@ const PressureBarrier = new Lang.Class({
let firstNewEvent = i;
for (i = 0; i < firstNewEvent; i++) {
this._currentPressure -= this._getDistanceAcrossBarrier(this._barrierEvents[i]);
let [time, distance] = this._barrierEvents[i];
this._currentPressure -= distance;
}
this._barrierEvents = this._barrierEvents.slice(firstNewEvent);
@ -1300,24 +1329,35 @@ const PressureBarrier = new Lang.Class({
_onBarrierLeft: function(barrier, event) {
this._reset();
this._isTriggered = false;
},
_trigger: function() {
this._isTriggered = true;
this.emit('trigger');
this._reset();
},
_onBarrierHit: function(barrier, event) {
// Throw out all events where the pointer was grabbed by another
// client, as the client that grabbed the pointer expects to have
// complete control over it
if (event.grabbed && Main.modalCount == 0)
// If we've triggered the barrier, wait until the pointer has the
// left the barrier hitbox until we trigger it again.
if (this._isTriggered)
return;
let isOverview = ((Main.keybindingMode & (Shell.KeyBindingMode.OVERVIEW)) != 0);
// Throw out events where the grab is taken by something that's
// not the overview (modal dialogs, etc.)
if (event.grabbed && !isOverview)
if (this._eventFilter && this._eventFilter(event))
return;
let slide = this._getDistanceAlongBarrier(event);
let distance = this._getDistanceAcrossBarrier(event);
// Throw out all events not in the proper keybinding mode
if (!(this._keybindingMode & Main.keybindingMode))
return;
let slide = this._getDistanceAlongBarrier(barrier, event);
let distance = this._getDistanceAcrossBarrier(barrier, event);
if (distance >= this._threshold) {
this._trigger();
return;
}
// Throw out events where the cursor is move more
// along the axis of the barrier than moving with
@ -1328,13 +1368,13 @@ const PressureBarrier = new Lang.Class({
this._lastTime = event.time;
this._trimBarrierEvents();
this._barrierEvents.push(event);
distance = Math.min(15, distance);
this._barrierEvents.push([event.time, distance]);
this._currentPressure += distance;
if (this._currentPressure >= this._threshold) {
this.emit('trigger');
this._reset();
}
if (this._currentPressure >= this._threshold)
this._trigger();
}
});
Signals.addSignalMethods(PressureBarrier.prototype);

View File

@ -685,7 +685,8 @@ const Memory = new Lang.Class({
const Extensions = new Lang.Class({
Name: 'Extensions',
_init: function() {
_init: function(lookingGlass) {
this._lookingGlass = lookingGlass;
this.actor = new St.BoxLayout({ vertical: true,
name: 'lookingGlassExtensions' });
this._noExtensions = new St.Label({ style_class: 'lg-extensions-none',
@ -912,7 +913,7 @@ const LookingGlass = new Lang.Class({
this._memory = new Memory();
notebook.appendPage('Memory', this._memory.actor);
this._extensions = new Extensions();
this._extensions = new Extensions(this);
notebook.appendPage('Extensions', this._extensions.actor);
this._entry.clutter_text.connect('activate', Lang.bind(this, function (o, e) {

View File

@ -18,11 +18,13 @@ const ExtensionSystem = imports.ui.extensionSystem;
const ExtensionDownloader = imports.ui.extensionDownloader;
const Keyboard = imports.ui.keyboard;
const MessageTray = imports.ui.messageTray;
const OsdWindow = imports.ui.osdWindow;
const Overview = imports.ui.overview;
const Panel = imports.ui.panel;
const Params = imports.misc.params;
const RunDialog = imports.ui.runDialog;
const Layout = imports.ui.layout;
const LoginManager = imports.misc.loginManager;
const LookingGlass = imports.ui.lookingGlass;
const NotificationDaemon = imports.ui.notificationDaemon;
const WindowAttentionHandler = imports.ui.windowAttentionHandler;
@ -31,13 +33,11 @@ const Scripting = imports.ui.scripting;
const SessionMode = imports.ui.sessionMode;
const ShellDBus = imports.ui.shellDBus;
const ShellMountOperation = imports.ui.shellMountOperation;
const UnlockDialog = imports.ui.unlockDialog;
const WindowManager = imports.ui.windowManager;
const Magnifier = imports.ui.magnifier;
const XdndHandler = imports.ui.xdndHandler;
const Util = imports.misc.util;
const OVERRIDES_SCHEMA = 'org.gnome.shell.overrides';
const DEFAULT_BACKGROUND_COLOR = Clutter.Color.from_pixel(0x2e3436ff);
let componentManager = null;
@ -51,12 +51,13 @@ let screenShield = null;
let notificationDaemon = null;
let windowAttentionHandler = null;
let ctrlAltTabManager = null;
let osdWindow = null;
let sessionMode = null;
let shellDBusService = null;
let shellMountOpDBusService = null;
let screenSaverDBus = null;
let modalCount = 0;
let keybindingMode = Shell.KeyBindingMode.NORMAL;
let keybindingMode = Shell.KeyBindingMode.NONE;
let modalActorFocusStack = [];
let uiGroup = null;
let magnifier = null;
@ -66,9 +67,11 @@ let layoutManager = null;
let _startDate;
let _defaultCssStylesheet = null;
let _cssStylesheet = null;
let _overridesSettings = null;
let _workspacesSettings = null;
function _sessionUpdated() {
_loadDefaultStylesheet();
wm.setCustomKeybindingHandler('panel-main-menu',
Shell.KeyBindingMode.NORMAL |
Shell.KeyBindingMode.OVERVIEW,
@ -80,8 +83,9 @@ function _sessionUpdated() {
Shell.KeyBindingMode.NORMAL |
Shell.KeyBindingMode.OVERVIEW,
sessionMode.hasRunDialog ? openRunDialog : null);
if (sessionMode.isGreeter)
screenShield.showDialog();
if (!sessionMode.hasRunDialog && lookingGlass)
lookingGlass.close();
}
function start() {
@ -95,20 +99,37 @@ function start() {
Gio.DesktopAppInfo.set_desktop_env('GNOME');
sessionMode = new SessionMode.SessionMode();
// start session after we know what mode we're running in
let signalId = sessionMode.connect('updated', function() {
sessionMode.disconnect(signalId);
startSession();
});
sessionMode.connect('sessions-loaded', _sessionsLoaded);
sessionMode.init();
}
function startSession() {
sessionMode.connect('updated', _loadDefaultStylesheet);
function _sessionsLoaded() {
sessionMode.connect('updated', _sessionUpdated);
_initializePrefs();
_initializeUI();
shellDBusService = new ShellDBus.GnomeShell();
shellMountOpDBusService = new ShellMountOperation.GnomeShellMountOpHandler();
_sessionUpdated();
}
function _initializePrefs() {
let keys = new Gio.Settings({ schema: sessionMode.overridesSchema }).list_keys();
for (let i = 0; i < keys.length; i++)
Meta.prefs_override_preference_schema (keys[i], sessionMode.overridesSchema);
let workspacesSchema;
if (keys.indexOf('dynamic-workspaces') > -1)
workspacesSchema = sessionMode.overridesSchema;
else
workspacesSchema = 'org.gnome.mutter';
_workspacesSettings = new Gio.Settings({ schema: workspacesSchema });
_workspacesSettings.connect('changed::dynamic-workspaces', _queueCheckWorkspaces);
}
function _initializeUI() {
// Ensure ShellWindowTracker and ShellAppUsage are initialized; this will
// also initialize ShellAppSystem first. ShellAppSystem
// needs to load all the .desktop files, and ShellWindowTracker
@ -134,16 +155,13 @@ function startSession() {
xdndHandler = new XdndHandler.XdndHandler();
ctrlAltTabManager = new CtrlAltTab.CtrlAltTabManager();
osdWindow = new OsdWindow.OsdWindow();
overview = new Overview.Overview();
wm = new WindowManager.WindowManager();
magnifier = new Magnifier.Magnifier();
if (UnlockDialog.isSupported())
if (LoginManager.canLock())
screenShield = new ScreenShield.ScreenShield();
else
screenShield = new ScreenShield.ScreenShieldFallback();
// The message tray relies on being constructed
// after the panel.
panel = new Panel.Panel();
messageTray = new MessageTray.MessageTray();
keyboard = new Keyboard.Keyboard();
@ -152,19 +170,19 @@ function startSession() {
componentManager = new Components.ComponentManager();
layoutManager.init();
layoutManager.prepareStartupAnimation();
overview.init();
global.screen.override_workspace_layout(Meta.ScreenCorner.TOPLEFT,
false, -1, 1);
global.display.connect('overlay-key', Lang.bind(overview, overview.toggle));
sessionMode.connect('updated', _sessionUpdated);
_sessionUpdated();
// Provide the bus object for gnome-session to
// initiate logouts.
EndSessionDialog.init();
// We're ready for the session manager to move to the next phase
Meta.register_with_session();
_startDate = new Date();
log('GNOME Shell started at ' + _startDate);
@ -176,9 +194,6 @@ function startSession() {
Scripting.runPerfScript(module, perfOutput);
}
_overridesSettings = new Gio.Settings({ schema: OVERRIDES_SCHEMA });
_overridesSettings.connect('changed::dynamic-workspaces', _queueCheckWorkspaces);
global.screen.connect('notify::n-workspaces', _nWorkspacesChanged);
global.screen.connect('window-entered-monitor', _windowEnteredMonitor);
@ -190,13 +205,17 @@ function startSession() {
ExtensionDownloader.init();
ExtensionSystem.init();
// Run the startup animation as soon as the mainloop is idle enough.
// This is necessary to have it smooth and without interruptions from
// completed IO tasks
GLib.idle_add(GLib.PRIORITY_LOW, function() {
layoutManager.startupAnimation();
return false;
});
if (sessionMode.isGreeter && screenShield) {
layoutManager.connect('startup-prepared', function() {
screenShield.showDialog();
});
}
layoutManager.connect('startup-complete', function() {
if (keybindingMode == Shell.KeyBindingMode.NONE) {
keybindingMode = Shell.KeyBindingMode.NORMAL;
}
});
}
let _workspaces = [];

View File

@ -1153,6 +1153,11 @@ const Source = new Lang.Class({
return this.notifications.length;
},
get indicatorCount() {
let notifications = this.notifications.filter(function(n) { return !n.isTransient && !n.resident; });
return notifications.length;
},
get unseenCount() {
return this.notifications.filter(function(n) { return !n.acknowledged; }).length;
},
@ -1586,17 +1591,13 @@ const MessageTray = new Lang.Class({
global.focus_manager.add_group(this.actor);
this._summary = new St.BoxLayout({ style_class: 'message-tray-summary',
reactive: true,
track_hover: true,
x_align: Clutter.ActorAlign.END,
x_expand: true,
y_align: Clutter.ActorAlign.CENTER,
y_expand: true });
this._summary.connect('notify::hover', Lang.bind(this, this._onSummaryHoverChanged));
this.actor.add_actor(this._summary);
this._summary.opacity = 0;
this._summaryMotionId = 0;
this._trayMotionId = 0;
this._summaryBoxPointer = new BoxPointer.BoxPointer(St.Side.BOTTOM,
{ reactive: true,
@ -1631,15 +1632,22 @@ const MessageTray = new Lang.Class({
Main.layoutManager.connect('keyboard-visible-changed', Lang.bind(this, this._onKeyboardVisibleChanged));
this._trayState = State.HIDDEN;
this._locked = false;
this._traySummoned = false;
this._useLongerTrayLeftTimeout = false;
this._trayLeftTimeoutId = 0;
// pointerInTray is sort of a misnomer -- it tracks whether
// a message tray notification should expand. The value is
// partially driven by the hover state of the tray, but has
// a lot of complex state related to timeouts and the current
// state of the pointer when a notification pops up.
this._pointerInTray = false;
this._pointerInKeyboard = false;
// This tracks this.actor.hover and is used to fizzle
// out non-changing hover notifications in onTrayHoverChanged.
this._trayHovered = false;
this._keyboardVisible = false;
this._summaryState = State.HIDDEN;
this._pointerInSummary = false;
this._notificationClosed = false;
this._notificationState = State.HIDDEN;
this._notificationTimeoutId = 0;
@ -1661,20 +1669,18 @@ const MessageTray = new Lang.Class({
});
Main.layoutManager.trayBox.add_actor(this.actor);
this.actor.y = 0;
Main.layoutManager.trackChrome(this.actor);
Main.layoutManager.trackChrome(this._notificationWidget);
Main.layoutManager.trackChrome(this._closeButton);
Main.layoutManager.connect('primary-fullscreen-changed', Lang.bind(this, this._onFullscreenChanged));
Main.layoutManager.connect('fullscreen-changed', Lang.bind(this, this._updateState));
Main.layoutManager.connect('hot-corners-changed', Lang.bind(this, this._hotCornersChanged));
// If the overview shows or hides while we're in
// the message tray, revert back to normal mode.
Main.overview.connect('showing', Lang.bind(this, this._escapeTray));
Main.overview.connect('hiding', Lang.bind(this, this._escapeTray));
// Track if we've added the activities button
this._activitiesButtonAdded = false;
Main.sessionMode.connect('updated', Lang.bind(this, this._sessionUpdated));
Main.wm.addKeybinding('toggle-message-tray',
@ -1695,8 +1701,10 @@ const MessageTray = new Lang.Class({
this._sources = new Hash.Map();
this._chatSummaryItemsCount = 0;
this._trayDwellTimeoutId = 0;
this._setupTrayDwellIfNeeded();
this._sessionUpdated();
this._hotCornersChanged();
this._noMessages = new St.Label({ text: _("No Messages"),
style_class: 'no-messages-label',
@ -1713,6 +1721,9 @@ const MessageTray = new Lang.Class({
this.actor.add_action(clickAction);
clickAction.connect('clicked', Lang.bind(this, function(action) {
if (this._trayState != State.SHOWN)
return;
let button = action.get_button();
if (button == 3)
this._openContextMenu();
@ -1723,7 +1734,7 @@ const MessageTray = new Lang.Class({
clickAction.connect('long-press', Lang.bind(this, function(action, actor, state) {
switch (state) {
case Clutter.LongPressState.QUERY:
return true;
return this._trayState == State.SHOWN;
case Clutter.LongPressState.ACTIVATE:
this._openContextMenu();
}
@ -1737,13 +1748,11 @@ const MessageTray = new Lang.Class({
_openContextMenu: function () {
let [x, y, mask] = global.get_pointer();
this._lock();
this._contextMenu.setPosition(Math.round(x), Math.round(y));
this._grabHelper.grab({ actor: this._contextMenu.actor,
grabFocus: true,
onUngrab: Lang.bind(this, function () {
this._contextMenu.close(BoxPointer.PopupAnimation.FULL);
this._unlock();
})
});
this._contextMenu.open(BoxPointer.PopupAnimation.FULL);
@ -1759,7 +1768,6 @@ const MessageTray = new Lang.Class({
if (!global.display.supports_extended_barriers()) {
let pointerWatcher = PointerWatcher.getPointerWatcher();
pointerWatcher.addWatch(TRAY_DWELL_CHECK_INTERVAL, Lang.bind(this, this._checkTrayDwell));
this._trayDwellTimeoutId = 0;
this._trayDwelling = false;
this._trayDwellUserTime = 0;
}
@ -1770,11 +1778,6 @@ const MessageTray = new Lang.Class({
},
_sessionUpdated: function() {
if (!this._activitiesButtonAdded && Main.panel.statusArea.activities) {
this._activitiesButtonAdded = true;
this._grabHelper.addActor(Main.panel.statusArea.activities.hotCorner.actor);
}
if ((Main.sessionMode.isLocked || Main.sessionMode.isGreeter) && this._inCtrlAltTab) {
Main.ctrlAltTabManager.removeGroup(this._summary);
this._inCtrlAltTab = false;
@ -1823,6 +1826,9 @@ const MessageTray = new Lang.Class({
_trayDwellTimeout: function() {
this._trayDwellTimeoutId = 0;
if (Main.layoutManager.bottomMonitor.inFullscreen)
return false;
// We don't want to open the tray when a modal dialog
// is up, so we check the modal count for that. When we are in the
// overview we have to take the overview's modal push into account
@ -1994,18 +2000,6 @@ const MessageTray = new Lang.Class({
this._notificationQueue.splice(index, 1);
},
_lock: function() {
this._locked = true;
},
_unlock: function() {
if (!this._locked)
return;
this._locked = false;
this._pointerInTray = this.actor.hover;
this._updateState();
},
openTray: function() {
if (Main.overview.animationInProgress)
return;
@ -2031,7 +2025,6 @@ const MessageTray = new Lang.Class({
hide: function() {
this._traySummoned = false;
this.actor.set_hover(false);
this._summary.set_hover(false);
this._updateState();
},
@ -2091,13 +2084,19 @@ const MessageTray = new Lang.Class({
this._updateState();
},
_onSummaryHoverChanged: function() {
this._pointerInSummary = this._summary.hover;
this._updateState();
_hotCornersChanged: function() {
let primary = Main.layoutManager.primaryIndex;
let corner = Main.layoutManager.hotCorners[primary];
if (corner && corner.actor)
this._grabHelper.addActor(corner.actor);
},
_onTrayHoverChanged: function() {
if (this.actor.hover) {
if (this.actor.hover == this._trayHovered)
return;
this._trayHovered = this.actor.hover;
if (this._trayHovered) {
// No dwell inside notifications at the bottom of the screen
this._cancelTrayDwell();
@ -2105,13 +2104,6 @@ const MessageTray = new Lang.Class({
if (this._trayState == State.HIDDEN && this._notificationState == State.HIDDEN)
return;
// Don't do anything if this._useLongerTrayLeftTimeout is true, meaning the notification originally
// popped up under the pointer, but this._trayLeftTimeoutId is 0, meaning the pointer didn't leave
// the tray yet. We need to check for this case because sometimes _onTrayHoverChanged() gets called
// multiple times while this.actor.hover is true.
if (this._useLongerTrayLeftTimeout && !this._trayLeftTimeoutId)
return;
this._useLongerTrayLeftTimeout = false;
if (this._trayLeftTimeoutId) {
Mainloop.source_remove(this._trayLeftTimeoutId);
@ -2160,11 +2152,6 @@ const MessageTray = new Lang.Class({
this._updateState();
},
_onFullscreenChanged: function(obj, state) {
this._inFullscreen = state;
this._updateState();
},
_onStatusChanged: function(status) {
if (status == GnomeSession.PresenceStatus.BUSY) {
// remove notification and allow the summary to be closed now
@ -2196,7 +2183,6 @@ const MessageTray = new Lang.Class({
this._trayLeftTimeoutId = 0;
this._useLongerTrayLeftTimeout = false;
this._pointerInTray = false;
this._pointerInSummary = false;
this._updateNotificationTimeout(0);
this._updateState();
}
@ -2204,9 +2190,7 @@ const MessageTray = new Lang.Class({
},
_escapeTray: function() {
this._unlock();
this._pointerInTray = false;
this._pointerInSummary = false;
this._traySummoned = false;
this._setClickedSummaryItem(null);
this._updateNotificationTimeout(0);
@ -2215,7 +2199,7 @@ const MessageTray = new Lang.Class({
// All of the logic for what happens when occurs here; the various
// event handlers merely update variables such as
// 'this._pointerInTray', 'this._summaryState', etc, and
// 'this._pointerInTray', 'this._traySummoned', etc, and
// _updateState() figures out what (if anything) needs to be done
// at the present time.
_updateState: function() {
@ -2223,25 +2207,22 @@ const MessageTray = new Lang.Class({
let notificationQueue = this._notificationQueue;
let notificationUrgent = notificationQueue.length > 0 && notificationQueue[0].urgency == Urgency.CRITICAL;
let notificationForFeedback = notificationQueue.length > 0 && notificationQueue[0].forFeedback;
let notificationsLimited = this._busy || this._inFullscreen;
let notificationsLimited = this._busy || Main.layoutManager.bottomMonitor.inFullscreen;
let notificationsPending = notificationQueue.length > 0 && (!notificationsLimited || notificationUrgent || notificationForFeedback) && Main.sessionMode.hasNotifications;
let nextNotification = notificationQueue.length > 0 ? notificationQueue[0] : null;
let notificationPinned = this._pointerInTray && !this._pointerInSummary && !this._notificationRemoved;
let notificationPinned = this._pointerInTray && !this._notificationRemoved;
let notificationExpanded = this._notification && this._notification.expanded;
let notificationExpired = this._notificationTimeoutId == 0 &&
!(this._notification && this._notification.urgency == Urgency.CRITICAL) &&
!(this._notification && this._notification.focused) &&
!this._pointerInTray &&
!this._locked &&
!(this._pointerInKeyboard && notificationExpanded);
!this._pointerInTray;
let notificationLockedOut = !Main.sessionMode.hasNotifications && this._notification;
let notificationMustClose = this._notificationRemoved || notificationLockedOut || (notificationExpired && this._userActiveWhileNotificationShown) || this._notificationClosed;
let canShowNotification = notificationsPending && this._summaryState == State.HIDDEN;
let canShowNotification = notificationsPending && this._trayState == State.HIDDEN;
if (this._notificationState == State.HIDDEN) {
if (canShowNotification) {
if (canShowNotification)
this._showNotification();
}
} else if (this._notificationState == State.SHOWN) {
if (notificationMustClose)
this._hideNotification();
@ -2251,33 +2232,28 @@ const MessageTray = new Lang.Class({
this._ensureNotificationFocused();
}
// Summary
let summarySummoned = this._pointerInSummary || this._traySummoned;
let summaryPinned = this._pointerInTray || summarySummoned || this._locked;
let summaryHovered = this._pointerInTray || this._pointerInSummary;
let notificationsVisible = this._notificationState != State.HIDDEN;
let notificationsDone = !notificationsVisible && !notificationsPending;
let mustHideSummary = ((notificationsPending && notificationUrgent)
|| notificationsVisible || !Main.sessionMode.hasNotifications);
if (this._summaryState == State.HIDDEN && !mustHideSummary && summarySummoned)
this._showSummary();
else if (this._summaryState == State.SHOWN && (!summaryPinned || mustHideSummary))
this._hideSummary();
let mustHideTray = ((notificationsPending && notificationUrgent)
|| notificationsVisible || !Main.sessionMode.hasNotifications);
// Summary notification
let haveClickedSummaryItem = this._clickedSummaryItem != null;
let summarySourceIsMainNotificationSource = (haveClickedSummaryItem && this._notification &&
this._clickedSummaryItem.source == this._notification.source);
let canShowSummaryBoxPointer = this._summaryState == State.SHOWN;
let canShowSummaryBoxPointer = this._trayState == State.SHOWN;
// We only have sources with empty notification stacks for legacy tray icons. Currently, we never attempt
// to show notifications for legacy tray icons, but this would be necessary if we did.
let requestedNotificationStackIsEmpty = (this._clickedSummaryItemMouseButton == 1 && this._clickedSummaryItem.source.notifications.length == 0);
let wrongSummaryNotificationStack = (this._clickedSummaryItemMouseButton == 1 &&
let requestedNotificationStackIsEmpty = (haveClickedSummaryItem &&
this._clickedSummaryItemMouseButton == 1 &&
this._clickedSummaryItem.source.notifications.length == 0);
let wrongSummaryNotificationStack = (haveClickedSummaryItem &&
this._clickedSummaryItemMouseButton == 1 &&
this._summaryBoxPointer.bin.child != this._clickedSummaryItem.notificationStackWidget);
let wrongSummaryRightClickMenu = (this._clickedSummaryItemMouseButton == 3 &&
let wrongSummaryRightClickMenu = (haveClickedSummaryItem &&
this._clickedSummaryItemMouseButton == 3 &&
this._clickedSummaryItem.rightClickMenu != null &&
this._summaryBoxPointer.bin.child != this._clickedSummaryItem.rightClickMenu);
let wrongSummaryBoxPointer = (haveClickedSummaryItem &&
(wrongSummaryNotificationStack || wrongSummaryRightClickMenu));
@ -2286,7 +2262,7 @@ const MessageTray = new Lang.Class({
if (haveClickedSummaryItem && !summarySourceIsMainNotificationSource && canShowSummaryBoxPointer && !requestedNotificationStackIsEmpty)
this._showSummaryBoxPointer();
} else if (this._summaryBoxPointerState == State.SHOWN) {
if (!haveClickedSummaryItem || !canShowSummaryBoxPointer || wrongSummaryBoxPointer || mustHideSummary) {
if (!haveClickedSummaryItem || !canShowSummaryBoxPointer || wrongSummaryBoxPointer || mustHideTray) {
this._hideSummaryBoxPointer();
if (wrongSummaryBoxPointer)
this._showSummaryBoxPointer();
@ -2296,9 +2272,7 @@ const MessageTray = new Lang.Class({
// Tray itself
let trayIsVisible = (this._trayState == State.SHOWING ||
this._trayState == State.SHOWN);
let trayShouldBeVisible = (this._summaryState == State.SHOWING ||
this._summaryState == State.SHOWN) &&
!this._keyboardVisible;
let trayShouldBeVisible = this._traySummoned && !this._keyboardVisible && !mustHideTray;
if (!trayIsVisible && trayShouldBeVisible)
trayShouldBeVisible = this._showTray();
else if (trayIsVisible && !trayShouldBeVisible)
@ -2348,6 +2322,7 @@ const MessageTray = new Lang.Class({
return false;
}
this.emit('showing');
this._tween(this.actor, '_trayState', State.SHOWN,
{ y: -this.actor.height,
time: ANIMATION_TIME,
@ -2398,6 +2373,7 @@ const MessageTray = new Lang.Class({
// is distracting, so hide it immediately in case it was visible.
this._summaryBoxPointer.actor.hide();
this.emit('hiding');
this._tween(this.actor, '_trayState', State.HIDDEN,
{ y: 0,
time: ANIMATION_TIME,
@ -2434,7 +2410,7 @@ const MessageTray = new Lang.Class({
_showNotification: function() {
this._notification = this._notificationQueue.shift();
this._userActiveWhileNotificationShown = this.idleMonitor.get_idletime() > IDLE_TIME;
this._userActiveWhileNotificationShown = this.idleMonitor.get_idletime() <= IDLE_TIME;
if (!this._userActiveWhileNotificationShown) {
// If the user isn't active, set up a watch to let us know
// when the user becomes active.
@ -2569,6 +2545,14 @@ const MessageTray = new Lang.Class({
this._notificationUnfocusedId = 0;
}
this._useLongerTrayLeftTimeout = false;
if (this._trayLeftTimeoutId) {
Mainloop.source_remove(this._trayLeftTimeoutId);
this._trayLeftTimeoutId = 0;
this._trayLeftMouseX = -1;
this._trayLeftMouseY = -1;
}
if (this._notificationRemoved) {
Tweener.removeTweens(this._notificationWidget);
this._notificationWidget.y = this.actor.height;
@ -2599,7 +2583,11 @@ const MessageTray = new Lang.Class({
this._notificationRemoved = false;
this._closeButton.hide();
this._pointerInTray = false;
this.actor.hover = false; // Clutter doesn't emit notify::hover when actors move
// Clutter will send a leave-event the next time the mouse
// moves, but we need to set this here now to update the
// state machine.
this.actor.hover = false;
this._notificationBin.child = null;
this._notificationWidget.hide();
},
@ -2612,10 +2600,9 @@ const MessageTray = new Lang.Class({
},
_expandNotification: function(autoExpanding) {
// Don't grab focus in notifications that are auto-expanded.
// Don't focus notifications that are auto-expanding.
if (!autoExpanding)
this._grabHelper.grab({ actor: this._notification.actor,
grabFocus: true });
this._ensureNotificationFocused();
if (!this._notificationExpandedId)
this._notificationExpandedId =
@ -2645,30 +2632,11 @@ const MessageTray = new Lang.Class({
}
},
// We use this function to grab focus when the user moves the pointer
// to a notification with CRITICAL urgency that was already auto-expanded.
_ensureNotificationFocused: function() {
this._grabHelper.grab({ actor: this._notification.actor,
grabFocus: true });
},
_showSummary: function() {
this._summary.opacity = 0;
this._tween(this._summary, '_summaryState', State.SHOWN,
{ opacity: 255,
time: ANIMATION_TIME,
transition: 'easeOutQuad',
});
},
_hideSummary: function() {
this._tween(this._summary, '_summaryState', State.HIDDEN,
{ opacity: 0,
time: ANIMATION_TIME,
transition: 'easeOutQuad',
});
},
_onSourceDoneDisplayingContent: function(source, closeTray) {
if (closeTray) {
this._escapeTray();
@ -2712,7 +2680,6 @@ const MessageTray = new Lang.Class({
this._grabHelper.grab({ actor: this._summaryBoxPointer.bin.child,
grabFocus: true,
onUngrab: Lang.bind(this, this._onSummaryBoxPointerUngrabbed) });
this._lock();
this._summaryBoxPointer.actor.opacity = 0;
this._summaryBoxPointer.actor.show();
@ -2747,10 +2714,8 @@ const MessageTray = new Lang.Class({
this._clickedSummaryItem.actor.remove_style_pseudo_class('selected');
this._clickedSummaryItem.actor.disconnect(this._clickedSummaryItemAllocationChangedId);
this._summary.disconnect(this._summaryMotionId);
Main.layoutManager.trayBox.disconnect(this._trayMotionId);
this._clickedSummaryItemAllocationChangedId = 0;
this._summaryMotionId = 0;
this._trayMotionId = 0;
}
this._clickedSummaryItem = item;
@ -2765,8 +2730,6 @@ const MessageTray = new Lang.Class({
// _clickedSummaryItem.actor can change absolute position without changing allocation
this._summaryMotionId = this._summary.connect('allocation-changed',
Lang.bind(this, this._adjustSummaryBoxPointerPosition));
this._trayMotionId = Main.layoutManager.trayBox.connect('notify::anchor-y',
Lang.bind(this, this._adjustSummaryBoxPointerPosition));
}
return true;
@ -2803,8 +2766,6 @@ const MessageTray = new Lang.Class({
this._sourceDoneDisplayingId = 0;
}
this._unlock();
if (this._summaryBoxPointerItem.source.notifications.length == 0) {
this._summaryBoxPointer.actor.hide();
this._hideSummaryBoxPointerCompleted();

View File

@ -22,6 +22,10 @@ const Tweener = imports.ui.tweener;
const OPEN_AND_CLOSE_TIME = 0.1;
const FADE_OUT_DIALOG_TIME = 1.0;
const WORK_SPINNER_ICON_SIZE = 24;
const WORK_SPINNER_ANIMATION_DELAY = 1.0;
const WORK_SPINNER_ANIMATION_TIME = 0.3;
const State = {
OPENED: 0,
CLOSED: 1,
@ -38,13 +42,15 @@ const ModalDialog = new Lang.Class({
styleClass: null,
parentActor: Main.uiGroup,
keybindingMode: Shell.KeyBindingMode.SYSTEM_MODAL,
shouldFadeIn: true });
shouldFadeIn: true,
destroyOnClose: true });
this.state = State.CLOSED;
this._hasModal = false;
this._keybindingMode = params.keybindingMode;
this._shellReactive = params.shellReactive;
this._shouldFadeIn = params.shouldFadeIn;
this._destroyOnClose = params.destroyOnClose;
this._group = new St.Widget({ visible: false,
x: 0,
@ -58,10 +64,14 @@ const ModalDialog = new Lang.Class({
this._group.connect('destroy', Lang.bind(this, this._onGroupDestroy));
this._pressedKey = null;
this._buttonKeys = {};
this._group.connect('key-press-event', Lang.bind(this, this._onKeyPressEvent));
this._group.connect('key-release-event', Lang.bind(this, this._onKeyReleaseEvent));
this._backgroundBin = new St.Bin();
this.backgroundStack = new St.Widget({ layout_manager: new Clutter.BinLayout() });
this._backgroundBin = new St.Bin({ child: this.backgroundStack,
x_fill: true, y_fill: true });
this._monitorConstraint = new Layout.MonitorConstraint();
this._backgroundBin.add_constraint(this._monitorConstraint);
this._group.add_actor(this._backgroundBin);
@ -77,15 +87,10 @@ const ModalDialog = new Lang.Class({
{ inhibitEvents: true });
this._lightbox.highlight(this._backgroundBin);
let stack = new Shell.Stack();
this._backgroundBin.child = stack;
this._eventBlocker = new Clutter.Group({ reactive: true });
stack.add_actor(this._eventBlocker);
stack.add_actor(this.dialogLayout);
} else {
this._backgroundBin.child = this.dialogLayout;
this._eventBlocker = new Clutter.Actor({ reactive: true });
this.backgroundStack.add_actor(this._eventBlocker);
}
this.backgroundStack.add_actor(this.dialogLayout);
this.contentLayout = new St.BoxLayout({ vertical: true });
@ -106,6 +111,8 @@ const ModalDialog = new Lang.Class({
this._initialKeyFocus = this.dialogLayout;
this._initialKeyFocusDestroyId = 0;
this._savedKeyFocus = null;
this._workSpinner = null;
},
destroy: function() {
@ -179,10 +186,57 @@ const ModalDialog = new Lang.Class({
return button;
},
_onKeyReleaseEvent: function(object, event) {
let symbol = event.get_key_symbol();
let buttonInfo = this._buttonKeys[symbol];
placeSpinner: function(layoutInfo) {
/* This is here because of recursive imports */
const Panel = imports.ui.panel;
let spinnerIcon = global.datadir + '/theme/process-working.svg';
this._workSpinner = new Panel.AnimatedIcon(spinnerIcon, WORK_SPINNER_ICON_SIZE);
this._workSpinner.actor.opacity = 0;
this._workSpinner.actor.show();
this.buttonLayout.add(this._workSpinner.actor, layoutInfo);
},
setWorking: function(working) {
if (!this._workSpinner)
return;
Tweener.removeTweens(this._workSpinner.actor);
if (working) {
this._workSpinner.play();
Tweener.addTween(this._workSpinner.actor,
{ opacity: 255,
delay: WORK_SPINNER_ANIMATION_DELAY,
time: WORK_SPINNER_ANIMATION_TIME,
transition: 'linear'
});
} else {
Tweener.addTween(this._workSpinner.actor,
{ opacity: 0,
time: WORK_SPINNER_ANIMATION_TIME,
transition: 'linear',
onCompleteScope: this,
onComplete: function() {
if (this._workSpinner)
this._workSpinner.stop();
}
});
}
},
_onKeyPressEvent: function(object, event) {
this._pressedKey = event.get_key_symbol();
},
_onKeyReleaseEvent: function(object, event) {
let pressedKey = this._pressedKey;
this._pressedKey = null;
let symbol = event.get_key_symbol();
if (symbol != pressedKey)
return false;
let buttonInfo = this._buttonKeys[symbol];
if (!buttonInfo)
return false;
@ -266,6 +320,9 @@ const ModalDialog = new Lang.Class({
this.state = State.CLOSED;
this._group.hide();
this.emit('closed');
if (this._destroyOnClose)
this.destroy();
})
});
},

View File

@ -244,7 +244,7 @@ const NotificationDaemon = new Lang.Class({
Main.overview.connect('hidden',
Lang.bind(this, this._onFocusAppChanged));
this._trayManager.manage_stage(global.stage, Main.messageTray.actor);
this._trayManager.manage_screen(global.screen, Main.messageTray.actor);
},
_imageForNotificationData: function(hints) {

207
js/ui/osdWindow.js Normal file
View File

@ -0,0 +1,207 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
const Clutter = imports.gi.Clutter;
const St = imports.gi.St;
const Lang = imports.lang;
const Layout = imports.ui.layout;
const Main = imports.ui.main;
const Mainloop = imports.mainloop;
const Tweener = imports.ui.tweener;
const Meta = imports.gi.Meta;
const HIDE_TIMEOUT = 1500;
const FADE_TIME = 0.1;
const LEVEL_ANIMATION_TIME = 0.1;
const LevelBar = new Lang.Class({
Name: 'LevelBar',
_init: function() {
this._level = 0;
this.actor = new St.Bin({ style_class: 'level',
x_fill: true, y_fill: true });
this._bar = new St.DrawingArea();
this._bar.connect('repaint', Lang.bind(this, this._repaint));
this.actor.set_child(this._bar);
},
get level() {
return this._level;
},
set level(value) {
let newValue = Math.max(0, Math.min(value, 100));
if (newValue == this._level)
return;
this._level = newValue;
this._bar.queue_repaint();
},
_repaint: function() {
let cr = this._bar.get_context();
let node = this.actor.get_theme_node();
let radius = node.get_border_radius(0); // assume same radius for all corners
Clutter.cairo_set_source_color(cr, node.get_foreground_color());
let [w, h] = this._bar.get_surface_size();
w *= (this._level / 100.);
if (w == 0)
return;
cr.moveTo(radius, 0);
if (w >= radius)
cr.arc(w - radius, radius, radius, 1.5 * Math.PI, 2. * Math.PI);
else
cr.lineTo(w, 0);
if (w >= radius)
cr.arc(w - radius, h - radius, radius, 0, 0.5 * Math.PI);
else
cr.lineTo(w, h);
cr.arc(radius, h - radius, radius, 0.5 * Math.PI, Math.PI);
cr.arc(radius, radius, radius, Math.PI, 1.5 * Math.PI);
cr.fill();
}
});
const OsdWindow = new Lang.Class({
Name: 'OsdWindow',
_init: function() {
this._popupSize = 0;
this.actor = new St.Widget({ x_expand: true,
y_expand: true,
x_align: Clutter.ActorAlign.CENTER,
y_align: Clutter.ActorAlign.CENTER });
this.actor.add_constraint(new Layout.MonitorConstraint({ primary: true }));
this._box = new St.BoxLayout({ style_class: 'osd-window',
vertical: true });
this.actor.add_actor(this._box);
this._box.connect('style-changed', Lang.bind(this, this._onStyleChanged));
this._box.connect('notify::height', Lang.bind(this,
function() {
Meta.later_add(Meta.LaterType.BEFORE_REDRAW, Lang.bind(this,
function() {
this._box.width = this._box.height;
}));
}));
this._icon = new St.Icon();
this._box.add(this._icon, { expand: true });
this._label = new St.Label();
this._box.add(this._label);
this._level = new LevelBar();
this._box.add(this._level.actor);
this._hideTimeoutId = 0;
this._reset();
Main.layoutManager.connect('monitors-changed',
Lang.bind(this, this._monitorsChanged));
this._monitorsChanged();
Main.layoutManager.addChrome(this.actor, { affectsInputRegion: false });
},
setIcon: function(icon) {
this._icon.gicon = icon;
},
setLabel: function(label) {
this._label.visible = (label != undefined);
if (label)
this._label.text = label;
},
setLevel: function(level) {
this._level.actor.visible = (level != undefined);
if (this.actor.visible)
Tweener.addTween(this._level,
{ level: level,
time: LEVEL_ANIMATION_TIME,
transition: 'easeOutQuad' });
else
this._level.level = level;
},
show: function() {
if (!this._icon.gicon)
return;
if (!this.actor.visible) {
Meta.disable_unredirect_for_screen(global.screen);
this.actor.show();
this.actor.opacity = 0;
this.actor.get_parent().set_child_above_sibling(this.actor, null);
Tweener.addTween(this.actor,
{ opacity: 255,
time: FADE_TIME,
transition: 'easeOutQuad' });
}
if (this._hideTimeoutId)
Mainloop.source_remove(this._hideTimeoutId);
this._hideTimeoutId = Mainloop.timeout_add(HIDE_TIMEOUT,
Lang.bind(this, this._hide));
},
cancel: function() {
if (!this._hideTimeoutId)
return;
Mainloop.source_remove(this._hideTimeoutId);
this._hideTimeoutId = 0;
this._hide();
},
_hide: function() {
Tweener.addTween(this.actor,
{ opacity: 0,
time: FADE_TIME,
transition: 'easeOutQuad',
onComplete: Lang.bind(this, this._reset) });
},
_reset: function() {
this.actor.hide();
this.setLabel(null);
this.setLevel(null);
Meta.enable_unredirect_for_screen(global.screen);
},
_monitorsChanged: function() {
/* assume 110x110 on a 640x480 display and scale from there */
let monitor = Main.layoutManager.primaryMonitor;
let scalew = monitor.width / 640.0;
let scaleh = monitor.height / 480.0;
let scale = Math.min(scalew, scaleh);
this._popupSize = 110 * Math.max(1, scale);
this._box.translation_y = monitor.height / 4;
this._icon.icon_size = this._popupSize / 2;
this._box.style_changed();
},
_onStyleChanged: function() {
let themeNode = this._box.get_theme_node();
let horizontalPadding = themeNode.get_horizontal_padding();
let verticalPadding = themeNode.get_vertical_padding();
let topBorder = themeNode.get_border_width(St.Side.TOP);
let bottomBorder = themeNode.get_border_width(St.Side.BOTTOM);
let leftBorder = themeNode.get_border_width(St.Side.LEFT);
let rightBorder = themeNode.get_border_width(St.Side.RIGHT);
let minWidth = this._popupSize - verticalPadding - leftBorder - rightBorder;
let minHeight = this._popupSize - horizontalPadding - topBorder - bottomBorder;
this._box.style = 'min-height: %dpx;'.format(Math.max(minWidth, minHeight));
}
});

View File

@ -13,6 +13,7 @@ const Gdk = imports.gi.Gdk;
const Background = imports.ui.background;
const Dash = imports.ui.dash;
const DND = imports.ui.dnd;
const LayoutManager = imports.ui.layout;
const Main = imports.ui.main;
const MessageTray = imports.ui.messageTray;
const OverviewControls = imports.ui.overviewControls;
@ -30,7 +31,9 @@ const ANIMATION_TIME = 0.25;
// and don't want the shading animation to get cut off
const SHADE_ANIMATION_TIME = .20;
const DND_WINDOW_SWITCH_TIMEOUT = 1250;
const DND_WINDOW_SWITCH_TIMEOUT = 750;
const OVERVIEW_ACTIVATION_TIMEOUT = 0.5;
const ShellInfo = new Lang.Class({
Name: 'ShellInfo',
@ -116,26 +119,37 @@ const Overview = new Lang.Class({
this._desktopFade = new St.Bin();
global.overlay_group.add_actor(this._desktopFade);
let layout = new Clutter.BinLayout();
this._stack = new Clutter.Actor({ layout_manager: layout });
this._stack.add_constraint(new LayoutManager.MonitorConstraint({ primary: true }));
/* Translators: This is the main view to select
activities. See also note for "Activities" string. */
this._overview = new St.BoxLayout({ name: 'overview',
accessible_name: _("Overview"),
reactive: true,
vertical: true });
vertical: true,
x_expand: true,
y_expand: true });
this._overview._delegate = this;
this._groupStack = new St.Widget({ layout_manager: new Clutter.BinLayout(),
x_expand: true, y_expand: true,
clip_to_allocation: true });
this._group = new St.BoxLayout({ name: 'overview-group',
reactive: true,
clip_to_allocation: true });
x_expand: true, y_expand: true });
this._groupStack.add_actor(this._group);
this._backgroundGroup = new Meta.BackgroundGroup();
global.overlay_group.add_child(this._backgroundGroup);
this._backgroundGroup.hide();
this._bgManagers = [];
this._activationTime = 0;
this.visible = false; // animating to overview, in overview, animating out
this._shown = false; // show() and not hide()
this._shownTemporarily = false; // showTemporarily() and not hideTemporarily()
this._modal = false; // have a modal grab
this.animationInProgress = false;
this.visibleTarget = false;
@ -148,8 +162,9 @@ const Overview = new Lang.Class({
this._overview.add_actor(this._coverPane);
this._coverPane.connect('event', Lang.bind(this, function (actor, event) { return true; }));
this._overview.hide();
global.overlay_group.add_actor(this._overview);
this._stack.hide();
this._stack.add_actor(this._overview);
global.overlay_group.add_actor(this._stack);
this._coverPane.hide();
@ -269,15 +284,22 @@ const Overview = new Lang.Class({
this._thumbnailsBox,
this._viewSelector);
this._controls.dashActor.x_align = Clutter.ActorAlign.START;
this._controls.dashActor.y_expand = true;
// Put the dash in a separate layer to allow content to be centered
this._groupStack.add_actor(this._controls.dashActor);
// Pack all the actors into the group
this._group.add_actor(this._controls.dashActor);
this._group.add_actor(this._controls.dashSpacer);
this._group.add(this._viewSelector.actor, { x_fill: true,
expand: true });
this._group.add_actor(this._controls.thumbnailsActor);
// Add our same-line elements after the search entry
this._overview.add(this._group, { y_fill: true,
expand: true });
this._overview.add(this._groupStack, { y_fill: true, expand: true });
this._stack.add_actor(this._controls.indicatorActor);
// TODO - recalculate everything when desktop size changes
this.dashIconSize = this._dash.iconSize;
@ -311,18 +333,22 @@ const Overview = new Lang.Class({
},
_onDragBegin: function() {
this._inXdndDrag = true;
DND.addDragMonitor(this._dragMonitor);
// Remember the workspace we started from
this._lastActiveWorkspaceIndex = global.screen.get_active_workspace_index();
},
_onDragEnd: function(time) {
this._inXdndDrag = false;
// In case the drag was canceled while in the overview
// we have to go back to where we started and hide
// the overview
if (this._shownTemporarily) {
if (this._shown) {
global.screen.get_workspace_by_index(this._lastActiveWorkspaceIndex).activate(time);
this.hideTemporarily();
this.hide();
}
this._resetWindowSwitchTimeout();
this._lastHoveredWindow = null;
@ -370,7 +396,7 @@ const Overview = new Lang.Class({
this._needsFakePointerEvent = true;
Main.activateWindow(dragEvent.targetActor._delegate.metaWindow,
this._windowSwitchTimestamp);
this.hideTemporarily();
this.hide();
this._lastHoveredWindow = null;
}));
}
@ -411,12 +437,8 @@ const Overview = new Lang.Class({
// when it is next shown.
this.hide();
let primary = Main.layoutManager.primaryMonitor;
let workArea = Main.layoutManager.getWorkAreaForMonitor(Main.layoutManager.primaryIndex);
this._overview.set_position(primary.x, primary.y);
this._overview.set_size(primary.width, primary.height);
this._coverPane.set_position(0, workArea.y);
this._coverPane.set_size(workArea.width, workArea.height);
@ -470,12 +492,18 @@ const Overview = new Lang.Class({
if (this._shown)
return;
this._shown = true;
this._syncInputMode();
if (!this._modal)
if (!this._syncInputMode())
return;
this._animateVisible();
},
focusSearch: function() {
this.show();
this._searchEntry.grab_key_focus();
},
fadeInDesktop: function() {
this._desktopFade.opacity = 0;
this._desktopFade.show();
@ -505,6 +533,7 @@ const Overview = new Lang.Class({
this.visible = true;
this.animationInProgress = true;
this.visibleTarget = true;
this._activationTime = Date.now() / 1000;
// All the the actors in the window group are completely obscured,
// hiding the group holding them while the Overview is displayed greatly
@ -516,14 +545,12 @@ const Overview = new Lang.Class({
//
// Disable unredirection while in the overview
Meta.disable_unredirect_for_screen(global.screen);
global.window_group.hide();
global.top_window_group.hide();
this._overview.show();
this._stack.show();
this._backgroundGroup.show();
this._viewSelector.show();
this._overview.opacity = 0;
Tweener.addTween(this._overview,
this._stack.opacity = 0;
Tweener.addTween(this._stack,
{ opacity: 255,
transition: 'easeOutQuad',
time: ANIMATION_TIME,
@ -537,24 +564,6 @@ const Overview = new Lang.Class({
this.emit('showing');
},
// showTemporarily:
//
// Animates the overview visible without grabbing mouse and keyboard input;
// if show() has already been called, this has no immediate effect, but
// will result in the overview not being hidden until hideTemporarily() is
// called.
showTemporarily: function() {
if (this.isDummy)
return;
if (this._shownTemporarily)
return;
this._syncInputMode();
this._animateVisible();
this._shownTemporarily = true;
},
// hide:
//
// Reverses the effect of show()
@ -565,30 +574,22 @@ const Overview = new Lang.Class({
if (!this._shown)
return;
if (!this._shownTemporarily)
this._animateNotVisible();
let event = Clutter.get_current_event();
if (event) {
let type = event.type();
let button = (type == Clutter.EventType.BUTTON_PRESS ||
type == Clutter.EventType.BUTTON_RELEASE);
let ctrl = (event.get_state() & Clutter.ModifierType.CONTROL_MASK) != 0;
if (button && ctrl)
return;
}
this._animateNotVisible();
this._shown = false;
this._syncInputMode();
},
// hideTemporarily:
//
// Reverses the effect of showTemporarily()
hideTemporarily: function() {
if (this.isDummy)
return;
if (!this._shownTemporarily)
return;
if (!this._shown)
this._animateNotVisible();
this._shownTemporarily = false;
this._syncInputMode();
},
toggle: function() {
if (this.isDummy)
return;
@ -599,6 +600,20 @@ const Overview = new Lang.Class({
this.show();
},
// Checks if the Activities button is currently sensitive to
// clicks. The first call to this function within the
// OVERVIEW_ACTIVATION_TIMEOUT time of the hot corner being
// triggered will return false. This avoids opening and closing
// the overview if the user both triggered the hot corner and
// clicked the Activities button.
shouldToggleByCornerOrButton: function() {
if (this.animationInProgress)
return false;
if (this._activationTime == 0 || Date.now() / 1000 - this._activationTime > OVERVIEW_ACTIVATION_TIMEOUT)
return true;
return false;
},
//// Private methods ////
_syncInputMode: function() {
@ -606,22 +621,23 @@ const Overview = new Lang.Class({
// overview we don't have a problem with the release of a press/release
// going to an application.
if (this.animationInProgress)
return;
return true;
if (this._shown) {
if (!this._modal) {
if (Main.pushModal(this._overview,
{ keybindingMode: Shell.KeyBindingMode.OVERVIEW }))
this._modal = true;
else
this.hide();
let shouldBeModal = !this._inXdndDrag;
if (shouldBeModal) {
if (!this._modal) {
if (Main.pushModal(this._overview,
{ keybindingMode: Shell.KeyBindingMode.OVERVIEW })) {
this._modal = true;
} else {
this.hide();
return false;
}
}
} else {
global.stage_input_mode = Shell.StageInputMode.FULLSCREEN;
}
} else if (this._shownTemporarily) {
if (this._modal) {
Main.popModal(this._overview);
this._modal = false;
}
global.stage_input_mode = Shell.StageInputMode.FULLSCREEN;
} else {
if (this._modal) {
Main.popModal(this._overview);
@ -630,6 +646,7 @@ const Overview = new Lang.Class({
else if (global.stage_input_mode == Shell.StageInputMode.FULLSCREEN)
global.stage_input_mode = Shell.StageInputMode.NORMAL;
}
return true;
},
_animateNotVisible: function() {
@ -642,7 +659,7 @@ const Overview = new Lang.Class({
this._viewSelector.zoomFromOverview();
// Make other elements fade out.
Tweener.addTween(this._overview,
Tweener.addTween(this._stack,
{ opacity: 0,
transition: 'easeOutQuad',
time: ANIMATION_TIME,
@ -663,7 +680,7 @@ const Overview = new Lang.Class({
this.emit('shown');
// Handle any calls to hide* while we were showing
if (!this._shown && !this._shownTemporarily)
if (!this._shown)
this._animateNotVisible();
this._syncInputMode();
@ -674,13 +691,10 @@ const Overview = new Lang.Class({
// Re-enable unredirection
Meta.enable_unredirect_for_screen(global.screen);
global.window_group.show();
global.top_window_group.show();
this._viewSelector.hide();
this._desktopFade.hide();
this._backgroundGroup.hide();
this._overview.hide();
this._stack.hide();
this.visible = false;
this.animationInProgress = false;
@ -689,7 +703,7 @@ const Overview = new Lang.Class({
this.emit('hidden');
// Handle any calls to show* while we were hiding
if (this._shown || this._shownTemporarily)
if (this._shown)
this._animateVisible();
this._syncInputMode();

View File

@ -2,6 +2,7 @@
const Clutter = imports.gi.Clutter;
const Lang = imports.lang;
const Meta = imports.gi.Meta;
const St = imports.gi.St;
const Shell = imports.gi.Shell;
@ -98,6 +99,7 @@ const SlidingControl = new Lang.Class({
this.layout = new SlideLayout();
this.layout.slideDirection = params.slideDirection;
this.actor = new St.Widget({ layout_manager: this.layout,
style_class: 'overview-controls',
clip_to_allocation: true });
Main.overview.connect('showing', Lang.bind(this, this._onOverviewShowing));
@ -247,7 +249,7 @@ const ThumbnailsSlider = new Lang.Class({
_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 || 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;
@ -328,19 +330,186 @@ const DashSlider = new Lang.Class({
}
});
const DashSpacer = new Lang.Class({
Name: 'DashSpacer',
Extends: St.Widget,
_init: function(params) {
this.parent(params);
this._bindConstraint = null;
},
setDashActor: function(dashActor) {
if (this._bindConstraint) {
this.remove_constraint(this._bindConstraint);
this._bindConstraint = null;
}
if (dashActor) {
this._bindConstraint = new Clutter.BindConstraint({ source: dashActor,
coordinate: Clutter.BindCoordinate.SIZE });
this.add_constraint(this._bindConstraint);
}
},
vfunc_get_preferred_width: function(forHeight) {
let box = this.get_allocation_box();
let minWidth = this.parent(forHeight)[0];
let natWidth = box.x2 - box.x1;
return [minWidth, natWidth];
},
vfunc_get_preferred_height: function(forWidth) {
let box = this.get_allocation_box();
let minHeight = this.parent(forWidth)[0];
let natHeight = box.y2 - box.y1;
return [minHeight, natHeight];
}
});
const MessagesIndicator = new Lang.Class({
Name: 'MessagesIndicator',
_init: function(viewSelector) {
this._count = 0;
this._sources = [];
this._viewSelector = viewSelector;
this._container = new St.BoxLayout({ style_class: 'messages-indicator-contents',
reactive: true,
track_hover: true,
x_expand: true,
y_expand: true,
x_align: Clutter.ActorAlign.CENTER });
this._icon = new St.Icon({ icon_name: 'user-idle-symbolic',
icon_size: 16 });
this._container.add_actor(this._icon);
this._label = new St.Label();
this._container.add_actor(this._label);
this._highlight = new St.Widget({ style_class: 'messages-indicator-highlight',
x_expand: true,
y_expand: true,
y_align: Clutter.ActorAlign.END,
visible: false });
this._container.connect('notify::hover', Lang.bind(this,
function() {
this._highlight.visible = this._container.hover;
}));
let clickAction = new Clutter.ClickAction();
this._container.add_action(clickAction);
clickAction.connect('clicked', Lang.bind(this,
function() {
Main.messageTray.openTray();
}));
Main.messageTray.connect('showing', Lang.bind(this,
function() {
this._highlight.visible = false;
this._container.hover = false;
}));
let layout = new Clutter.BinLayout();
this.actor = new St.Widget({ layout_manager: layout,
style_class: 'messages-indicator',
y_expand: true,
y_align: Clutter.ActorAlign.END,
visible: false });
this.actor.add_actor(this._container);
this.actor.add_actor(this._highlight);
Main.messageTray.connect('source-added', Lang.bind(this, this._onSourceAdded));
Main.messageTray.connect('source-removed', Lang.bind(this, this._onSourceRemoved));
let sources = Main.messageTray.getSources();
sources.forEach(Lang.bind(this, function(source) { this._onSourceAdded(null, source); }));
this._viewSelector.connect('page-changed', Lang.bind(this, this._updateVisibility));
Main.overview.connect('showing', Lang.bind(this, this._updateVisibility));
},
_onSourceAdded: function(tray, source) {
if (source.trayIcon)
return;
if (source.isTransient)
return;
source.connect('count-updated', Lang.bind(this, this._updateCount));
this._sources.push(source);
this._updateCount();
},
_onSourceRemoved: function(tray, source) {
this._sources.splice(this._sources.indexOf(source), 1);
this._updateCount();
},
_updateCount: function() {
let count = 0;
let hasChats = false;
this._sources.forEach(Lang.bind(this,
function(source) {
count += source.indicatorCount;
hasChats |= source.isChat;
}));
this._count = count;
this._label.text = ngettext("%d new message",
"%d new messages",
count).format(count);
this._icon.visible = hasChats;
this._updateVisibility();
},
_updateVisibility: function() {
let activePage = this._viewSelector.getActivePage();
let visible = ((this._count > 0) && (activePage == ViewSelector.ViewPage.WINDOWS));
this.actor.visible = visible;
}
});
const ControlsManager = new Lang.Class({
Name: 'ControlsManager',
_init: function(dash, thumbnails, viewSelector) {
this._dashSlider = new DashSlider(dash);
this.dashActor = this._dashSlider.actor;
this.dashSpacer = new DashSpacer();
this.dashSpacer.setDashActor(this.dashActor);
this._thumbnailsSlider = new ThumbnailsSlider(thumbnails);
this.thumbnailsActor = this._thumbnailsSlider.actor;
this._indicator = new MessagesIndicator(viewSelector);
this.indicatorActor = this._indicator.actor;
this._viewSelector = viewSelector;
this._viewSelector.connect('page-changed', Lang.bind(this, this._setVisibility));
this._viewSelector.connect('page-empty', Lang.bind(this, this._onPageEmpty));
Main.overview.connect('showing', Lang.bind(this, this._updateSpacerVisibility));
Main.overview.connect('item-drag-begin', Lang.bind(this,
function() {
let activePage = this._viewSelector.getActivePage();
if (activePage != ViewSelector.ViewPage.WINDOWS)
this._viewSelector.fadeHalf();
}));
Main.overview.connect('item-drag-end', Lang.bind(this,
function() {
this._viewSelector.fadeIn();
}));
Main.overview.connect('item-drag-cancelled', Lang.bind(this,
function() {
this._viewSelector.fadeIn();
}));
},
_setVisibility: function() {
@ -368,8 +537,18 @@ const ControlsManager = new Lang.Class({
this._thumbnailsSlider.slideOut();
},
_updateSpacerVisibility: function() {
if (Main.overview.animationInProgress && !Main.overview.visibleTarget)
return;
let activePage = this._viewSelector.getActivePage();
this.dashSpacer.visible = (activePage == ViewSelector.ViewPage.WINDOWS);
},
_onPageEmpty: function() {
this._dashSlider.pageEmpty();
this._thumbnailsSlider.pageEmpty();
this._updateSpacerVisibility();
}
});

View File

@ -18,7 +18,6 @@ const Atk = imports.gi.Atk;
const Config = imports.misc.config;
const CtrlAltTab = imports.ui.ctrlAltTab;
const DND = imports.ui.dnd;
const Layout = imports.ui.layout;
const Overview = imports.ui.overview;
const PopupMenu = imports.ui.popupMenu;
const PanelMenu = imports.ui.panelMenu;
@ -145,8 +144,8 @@ const AnimatedIcon = new Lang.Class({
Name: 'AnimatedIcon',
Extends: Animation,
_init: function(name, size) {
this.parent(global.datadir + '/theme/' + name, size, size, ANIMATED_ICON_UPDATE_TIMEOUT);
_init: function(filename, size) {
this.parent(filename, size, size, ANIMATED_ICON_UPDATE_TIMEOUT);
}
});
@ -203,7 +202,7 @@ const TextShadower = new Lang.Class({
let child = children[i];
let childBox = new Clutter.ActorBox();
// The order of the labels here is arbitrary, except
// we know the "real" label is at the end because Clutter.Group
// we know the "real" label is at the end because Clutter.Actor
// sorts by Z order
switch (i) {
case 0: // top
@ -259,6 +258,7 @@ const AppMenuButton = new Lang.Class({
this._actionGroupNotifyId = 0;
let bin = new St.Bin({ name: 'appMenu' });
bin.connect('style-changed', Lang.bind(this, this._onStyleChanged));
this.actor.add_actor(bin);
this.actor.bind_property("reactive", this.actor, "can-focus", 0);
@ -289,27 +289,25 @@ const AppMenuButton = new Lang.Class({
this._visible = !Main.overview.visible;
if (!this._visible)
this.actor.hide();
Main.overview.connect('hiding', Lang.bind(this, function () {
this._overviewHidingId = Main.overview.connect('hiding', Lang.bind(this, function () {
this.show();
}));
Main.overview.connect('showing', Lang.bind(this, function () {
this._overviewShowingId = Main.overview.connect('showing', Lang.bind(this, function () {
this.hide();
}));
this._stop = true;
this._spinner = new AnimatedIcon('process-working.svg',
PANEL_ICON_SIZE);
this._container.add_actor(this._spinner.actor);
this._spinner.actor.hide();
this._spinner.actor.lower_bottom();
this._spinner = null;
let tracker = Shell.WindowTracker.get_default();
let appSys = Shell.AppSystem.get_default();
tracker.connect('notify::focus-app', Lang.bind(this, this._focusAppChanged));
appSys.connect('app-state-changed', Lang.bind(this, this._onAppStateChanged));
global.window_manager.connect('switch-workspace', Lang.bind(this, this._sync));
this._focusAppNotifyId =
tracker.connect('notify::focus-app', Lang.bind(this, this._focusAppChanged));
this._appStateChangedSignalId =
appSys.connect('app-state-changed', Lang.bind(this, this._onAppStateChanged));
this._switchWorkspaceNotifyId =
global.window_manager.connect('switch-workspace', Lang.bind(this, this._sync));
this._sync();
},
@ -355,6 +353,18 @@ const AppMenuButton = new Lang.Class({
onCompleteScope: this });
},
_onStyleChanged: function(actor) {
let node = actor.get_theme_node();
let [success, icon] = node.lookup_url('spinner-image', false);
if (!success || this._spinnerIcon == icon)
return;
this._spinnerIcon = icon;
this._spinner = new AnimatedIcon(this._spinnerIcon, PANEL_ICON_SIZE);
this._container.add_actor(this._spinner.actor);
this._spinner.actor.hide();
this._spinner.actor.lower_bottom();
},
_onIconBoxStyleChanged: function() {
let node = this._iconBox.get_theme_node();
this._iconBottomClip = node.get_length('app-icon-bottom-clip');
@ -386,6 +396,10 @@ const AppMenuButton = new Lang.Class({
this._stop = true;
this.actor.reactive = true;
if (this._spinner == null)
return;
Tweener.addTween(this._spinner.actor,
{ opacity: 0,
time: SPINNER_ANIMATION_TIME,
@ -402,6 +416,10 @@ const AppMenuButton = new Lang.Class({
startAnimation: function() {
this._stop = false;
this.actor.reactive = false;
if (this._spinner == null)
return;
this._spinner.play();
this._spinner.actor.show();
},
@ -464,6 +482,9 @@ const AppMenuButton = new Lang.Class({
}
this._label.actor.allocate(childBox, flags);
if (this._spinner == null)
return;
if (direction == Clutter.TextDirection.LTR) {
childBox.x1 = Math.floor(iconWidth / 2) + this._label.actor.width;
childBox.x2 = childBox.x1 + this._spinner.actor.width;
@ -554,7 +575,8 @@ const AppMenuButton = new Lang.Class({
return;
}
this._spinner.actor.hide();
if (this._spinner)
this._spinner.actor.hide();
if (this._iconBox.child != null)
this._iconBox.child.destroy();
this._iconBox.hide();
@ -617,6 +639,33 @@ const AppMenuButton = new Lang.Class({
this.setMenu(menu);
this._menuManager.addMenu(menu);
},
destroy: function() {
if (this._appStateChangedSignalId > 0) {
let appSys = Shell.AppSystem.get_default();
appSys.disconnect(this._appStateChangedSignalId);
this._appStateChangedSignalId = 0;
}
if (this._focusAppNotifyId > 0) {
let tracker = Shell.WindowTracker.get_default();
tracker.disconnect(this._focusAppNotifyId);
this._focusAppNotifyId = 0;
}
if (this._overviewHidingId > 0) {
Main.overview.disconnect(this._overviewHidingId);
this._overviewHidingId = 0;
}
if (this._overviewShowingId > 0) {
Main.overview.disconnect(this._overviewShowingId);
this._overviewShowingId = 0;
}
if (this._switchWorkspaceNotifyId > 0) {
global.window_manager.disconnect(this._switchWorkspaceNotifyId);
this._switchWorkspaceNotifyId = 0;
}
this.parent();
}
});
@ -630,23 +679,15 @@ const ActivitiesButton = new Lang.Class({
this.parent(0.0, null, true);
this.actor.accessible_role = Atk.Role.TOGGLE_BUTTON;
let container = new Shell.GenericContainer();
container.connect('get-preferred-width', Lang.bind(this, this._containerGetPreferredWidth));
container.connect('get-preferred-height', Lang.bind(this, this._containerGetPreferredHeight));
container.connect('allocate', Lang.bind(this, this._containerAllocate));
this.actor.add_actor(container);
this.actor.name = 'panelActivities';
/* Translators: If there is no suitable word for "Activities"
in your language, you can use the word for "Overview". */
this._label = new St.Label({ text: _("Activities") });
container.add_actor(this._label);
this.actor.add_actor(this._label);
this.actor.label_actor = this._label;
this.hotCorner = new Layout.HotCorner(Main.layoutManager);
container.add_actor(this.hotCorner.actor);
this.actor.connect('captured-event', Lang.bind(this, this._onCapturedEvent));
this.actor.connect_after('button-release-event', Lang.bind(this, this._onButtonRelease));
this.actor.connect_after('key-release-event', Lang.bind(this, this._onKeyRelease));
@ -661,44 +702,6 @@ const ActivitiesButton = new Lang.Class({
}));
this._xdndTimeOut = 0;
// Since the hot corner uses stage coordinates, Clutter won't
// queue relayouts for us when the panel moves. Queue a relayout
// when that happens.
Main.layoutManager.connect('panel-box-changed', Lang.bind(this, function() {
container.queue_relayout();
}));
},
_containerGetPreferredWidth: function(actor, forHeight, alloc) {
[alloc.min_size, alloc.natural_size] = this._label.get_preferred_width(forHeight);
},
_containerGetPreferredHeight: function(actor, forWidth, alloc) {
[alloc.min_size, alloc.natural_size] = this._label.get_preferred_height(forWidth);
},
_containerAllocate: function(actor, box, flags) {
this._label.allocate(box, flags);
// The hot corner needs to be outside any padding/alignment
// that has been imposed on us
let primary = Main.layoutManager.primaryMonitor;
let hotBox = new Clutter.ActorBox();
let ok, x, y;
if (actor.get_text_direction() == Clutter.TextDirection.LTR) {
[ok, x, y] = actor.transform_stage_point(primary.x, primary.y)
} else {
[ok, x, y] = actor.transform_stage_point(primary.x + primary.width, primary.y);
// hotCorner.actor has northeast gravity, so we don't need
// to adjust x for its width
}
hotBox.x1 = Math.round(x);
hotBox.x2 = hotBox.x1 + this.hotCorner.actor.width;
hotBox.y1 = Math.round(y);
hotBox.y2 = hotBox.y1 + this.hotCorner.actor.height;
this.hotCorner.actor.allocate(hotBox, flags);
},
handleDragOver: function(source, actor, x, y, time) {
@ -708,14 +711,14 @@ const ActivitiesButton = new Lang.Class({
if (this._xdndTimeOut != 0)
Mainloop.source_remove(this._xdndTimeOut);
this._xdndTimeOut = Mainloop.timeout_add(BUTTON_DND_ACTIVATION_TIMEOUT,
Lang.bind(this, this._xdndShowOverview, actor));
Lang.bind(this, this._xdndToggleOverview, actor));
return DND.DragMotionResult.CONTINUE;
},
_onCapturedEvent: function(actor, event) {
if (event.type() == Clutter.EventType.BUTTON_PRESS) {
if (!this.hotCorner.shouldToggleOverviewOnClick())
if (!Main.overview.shouldToggleByCornerOrButton())
return true;
}
return false;
@ -732,15 +735,12 @@ const ActivitiesButton = new Lang.Class({
}
},
_xdndShowOverview: function(actor) {
_xdndToggleOverview: function(actor) {
let [x, y, mask] = global.get_pointer();
let pickedActor = global.stage.get_actor_at_pos(Clutter.PickMode.REACTIVE, x, y);
if (pickedActor == this.actor) {
if (!Main.overview.visible && !Main.overview.animationInProgress) {
Main.overview.showTemporarily();
}
}
if (pickedActor == this.actor && Main.overview.shouldToggleByCornerOrButton())
Main.overview.toggle();
Mainloop.source_remove(this._xdndTimeOut);
this._xdndTimeOut = 0;
@ -923,7 +923,6 @@ const PANEL_ITEM_IMPLEMENTATIONS = {
'volume': imports.ui.status.volume.Indicator,
'battery': imports.ui.status.power.Indicator,
'lockScreen': imports.ui.status.lockScreenMenu.Indicator,
'logo': imports.gdm.loginDialog.LogoMenuButton,
'keyboard': imports.ui.status.keyboard.InputSourceIndicator,
'powerMenu': imports.gdm.powerMenu.PowerMenuButton,
'userMenu': imports.ui.userMenu.UserMenuButton
@ -952,7 +951,7 @@ const Panel = new Lang.Class({
this.statusArea = {};
this.menuManager = new PopupMenu.PopupMenuManager(this);
this.menuManager = new PopupMenu.PopupMenuManager(this, { keybindingMode: Shell.KeyBindingMode.TOPBAR_POPUP });
this._leftBox = new St.BoxLayout({ name: 'panelLeft' });
this.actor.add_actor(this._leftBox);
@ -1106,17 +1105,18 @@ const Panel = new Lang.Class({
return true;
},
openAppMenu: function() {
toggleAppMenu: function() {
let indicator = this.statusArea.appMenu;
if (!indicator) // appMenu not supported by current session mode
return;
let menu = indicator.menu;
if (!indicator.actor.reactive || menu.isOpen)
if (!indicator.actor.reactive)
return;
menu.open();
menu.actor.navigate_focus(null, Gtk.DirectionType.TAB_FORWARD, false);
menu.toggle();
if (menu.isOpen)
menu.actor.navigate_focus(null, Gtk.DirectionType.TAB_FORWARD, false);
},
set boxOpacity(value) {

View File

@ -553,6 +553,10 @@ const PopupSliderMenuItem = new Lang.Class({
let handleRadius = themeNode.get_length('-slider-handle-radius');
let handleBorderWidth = themeNode.get_length('-slider-handle-border-width');
let [hasHandleColor, handleBorderColor] =
themeNode.lookup_color('-slider-handle-border-color', false);
let sliderWidth = width - 2 * handleRadius;
let sliderHeight = themeNode.get_length('-slider-height');
@ -604,7 +608,16 @@ const PopupSliderMenuItem = new Lang.Class({
color.blue / 255,
color.alpha / 255);
cr.arc(handleX, handleY, handleRadius, 0, 2 * Math.PI);
cr.fill();
cr.fillPreserve();
if (hasHandleColor && handleBorderWidth) {
cr.setSourceRGBA(
handleBorderColor.red / 255,
handleBorderColor.green / 255,
handleBorderColor.blue / 255,
handleBorderColor.alpha / 255);
cr.setLineWidth(handleBorderWidth);
cr.stroke();
}
cr.$dispose();
},
@ -1157,6 +1170,7 @@ const PopupMenuBase = new Lang.Class({
},
destroy: function() {
this.close();
this.removeAll();
this.actor.destroy();
@ -1812,6 +1826,8 @@ const RemoteMenu = new Lang.Class({
this._actionStateChangeId = this.actionGroup.connect('action-state-changed', Lang.bind(this, this._actionStateChanged));
this._actionEnableChangeId = this.actionGroup.connect('action-enabled-changed', Lang.bind(this, this._actionEnabledChanged));
this._skipSignalConnection = false;
},
destroy: function() {
@ -1859,7 +1875,7 @@ const RemoteMenu = new Lang.Class({
let action_id = model.get_item_attribute_value(index, Gio.MENU_ATTRIBUTE_ACTION, null).deep_unpack();
if (!this.actionGroup.has_action(action_id)) {
// the action may not be there yet, wait for action-added
return [null, false, 'action-added'];
return [null, false, 'action-added::' + action_id];
}
if (!this._actions[action_id])
@ -1896,7 +1912,7 @@ const RemoteMenu = new Lang.Class({
break;
default:
log('Action "%s" has state of type %s, which is not supported'.format(action_id, action.state.get_type_string()));
return [null, false, 'action-state-changed'];
return [null, false, 'action-state-changed::' + action_id];
}
} else {
target = model.get_item_attribute_value(index, Gio.MENU_ATTRIBUTE_TARGET, null);
@ -1972,13 +1988,16 @@ const RemoteMenu = new Lang.Class({
target.addMenuItem(separator, k+1);
k++;
}
} else if (changeSignal) {
} else if (changeSignal && !this._skipSignalConnection) {
let signalId = this.actionGroup.connect(changeSignal, Lang.bind(this, function(actionGroup, actionName) {
actionGroup.disconnect(signalId);
if (this._actions[actionName]) return;
// force a full update
/* force a full update but do not reconnect signals if other
* actions are missing */
this._skipSignalConnection = true;
this._modelChanged(model, 0, -1, model.get_n_items(), target);
this._skipSignalConnection = false;
}));
}
}
@ -2051,9 +2070,9 @@ const RemoteMenu = new Lang.Class({
const PopupMenuManager = new Lang.Class({
Name: 'PopupMenuManager',
_init: function(owner) {
_init: function(owner, grabParams) {
this._owner = owner;
this._grabHelper = new GrabHelper.GrabHelper(owner.actor);
this._grabHelper = new GrabHelper.GrabHelper(owner.actor, grabParams);
this._menus = [];
},
@ -2086,7 +2105,7 @@ const PopupMenuManager = new Lang.Class({
},
removeMenu: function(menu) {
if (menu == this._activeMenu)
if (menu == this.activeMenu)
this._closeMenu(menu);
let position = this._findMenu(menu);
@ -2110,9 +2129,9 @@ const PopupMenuManager = new Lang.Class({
},
get activeMenu() {
let actor = this._grabHelper.currentGrab.actor;
if (actor)
return actor._delegate;
let firstGrab = this._grabHelper.grabStack[0];
if (firstGrab)
return firstGrab.actor._delegate;
else
return null;
},
@ -2123,6 +2142,8 @@ const PopupMenuManager = new Lang.Class({
_onMenuOpenState: function(menu, open) {
if (open) {
if (this.activeMenu && !this.activeMenu.isChildMenu(menu))
this.activeMenu.close(BoxPointer.PopupAnimation.FADE);
this._grabHelper.grab({ actor: menu.actor, modal: true, focus: menu.sourceActor,
onUngrab: Lang.bind(this, this._closeMenu, menu) });
} else {
@ -2139,13 +2160,8 @@ const PopupMenuManager = new Lang.Class({
},
_changeMenu: function(newMenu) {
let oldMenu = this.activeMenu;
if (oldMenu) {
oldMenu.close(BoxPointer.PopupAnimation.FADE);
newMenu.open(BoxPointer.PopupAnimation.FADE);
} else {
newMenu.open(BoxPointer.PopupAnimation.FULL);
}
newMenu.open(this.activeMenu ? BoxPointer.PopupAnimation.FADE
: BoxPointer.PopupAnimation.FULL);
},
_onMenuSourceEnter: function(menu) {

View File

@ -127,8 +127,6 @@ function remoteProvidersLoaded(loadState) {
// Special case gnome-control-center to be always active and always first
sortOrder.unshift('gnome-control-center.desktop');
let numSorted = sortOrder.length;
loadState.loadedProviders.sort(
function(providerA, providerB) {
let idxA, idxB;
@ -148,15 +146,6 @@ function remoteProvidersLoaded(loadState) {
return GLib.utf8_collate(nameA, nameB);
}
if (numSorted > 1) {
// if providerA is the last, it goes after everything
if ((idxA + 1) == numSorted)
return 1;
// if providerB is the last, it goes after everything
else if ((idxB + 1) == numSorted)
return -1;
}
// if providerA isn't found, it's sorted after providerB
if (idxA == -1)
return 1;
@ -255,6 +244,7 @@ const RemoteSearchProvider = new Lang.Class({
metas[i][prop] = metas[i][prop].deep_unpack();
resultMetas.push({ id: metas[i]['id'],
name: metas[i]['name'],
description: metas[i]['description'],
createIcon: Lang.bind(this,
this.createIcon, metas[i]) });
}

View File

@ -30,144 +30,13 @@ const EXEC_ARG_KEY = 'exec-arg';
const DIALOG_GROW_TIME = 0.1;
const CommandCompleter = new Lang.Class({
Name: 'CommandCompleter',
_init : function() {
this._changedCount = 0;
this._paths = GLib.getenv('PATH').split(':');
this._paths.push(GLib.get_home_dir());
this._valid = false;
this._updateInProgress = false;
this._childs = new Array(this._paths.length);
this._monitors = new Array(this._paths.length);
for (let i = 0; i < this._paths.length; i++) {
this._childs[i] = [];
let file = Gio.file_new_for_path(this._paths[i]);
let info;
try {
info = file.query_info(Gio.FILE_ATTRIBUTE_STANDARD_TYPE, Gio.FileQueryInfoFlags.NONE, null);
} catch (e) {
// FIXME catchall
this._paths[i] = null;
continue;
}
if (info.get_attribute_uint32(Gio.FILE_ATTRIBUTE_STANDARD_TYPE) != Gio.FileType.DIRECTORY)
continue;
this._paths[i] = file.get_path();
this._monitors[i] = file.monitor_directory(Gio.FileMonitorFlags.NONE, null);
if (this._monitors[i] != null) {
this._monitors[i].connect('changed', Lang.bind(this, this._onChanged));
}
}
this._paths = this._paths.filter(function(a) {
return a != null;
});
this._update(0);
},
update : function() {
if (this._valid)
return;
this._update(0);
},
_update : function(i) {
if (i == 0 && this._updateInProgress)
return;
this._updateInProgress = true;
this._changedCount = 0;
this._i = i;
if (i >= this._paths.length) {
this._valid = true;
this._updateInProgress = false;
return;
}
let file = Gio.file_new_for_path(this._paths[i]);
this._childs[this._i] = [];
FileUtils.listDirAsync(file, Lang.bind(this, function (files) {
for (let i = 0; i < files.length; i++) {
this._childs[this._i].push(files[i].get_name());
}
this._update(this._i + 1);
}));
},
_onChanged : function(m, f, of, type) {
if (!this._valid)
return;
let path = f.get_parent().get_path();
let k = undefined;
for (let i = 0; i < this._paths.length; i++) {
if (this._paths[i] == path)
k = i;
}
if (k === undefined) {
return;
}
if (type == Gio.FileMonitorEvent.CREATED) {
this._childs[k].push(f.get_basename());
}
if (type == Gio.FileMonitorEvent.DELETED) {
this._changedCount++;
if (this._changedCount > MAX_FILE_DELETED_BEFORE_INVALID) {
this._valid = false;
}
let name = f.get_basename();
this._childs[k] = this._childs[k].filter(function(e) {
return e != name;
});
}
if (type == Gio.FileMonitorEvent.UNMOUNTED) {
this._childs[k] = [];
}
},
getCompletion: function(text) {
let common = '';
let notInit = true;
if (!this._valid) {
this._update(0);
return common;
}
function _getCommon(s1, s2) {
let k = 0;
for (; k < s1.length && k < s2.length; k++) {
if (s1[k] != s2[k])
break;
}
if (k == 0)
return '';
return s1.substr(0, k);
}
function _hasPrefix(s1, prefix) {
return s1.indexOf(prefix) == 0;
}
for (let i = 0; i < this._childs.length; i++) {
for (let k = 0; k < this._childs[i].length; k++) {
if (!_hasPrefix(this._childs[i][k], text))
continue;
if (notInit) {
common = this._childs[i][k];
notInit = false;
}
common = _getCommon(common, this._childs[i][k]);
}
}
if (common.length)
return common.substr(text.length);
return common;
}
});
const RunDialog = new Lang.Class({
Name: 'RunDialog',
Extends: ModalDialog.ModalDialog,
_init : function() {
this.parent({ styleClass: 'run-dialog' });
this.parent({ styleClass: 'run-dialog',
destroyOnClose: false });
this._lockdownSettings = new Gio.Settings({ schema: LOCKDOWN_SCHEMA });
this._terminalSettings = new Gio.Settings({ schema: TERMINAL_SCHEMA });
@ -242,8 +111,6 @@ const RunDialog = new Lang.Class({
key: Clutter.Escape }]);
this._pathCompleter = new Gio.FilenameCompleter();
this._commandCompleter = new CommandCompleter();
this._group.connect('notify::visible', Lang.bind(this._commandCompleter, this._commandCompleter.update));
this._history = new History.HistoryManager({ gsettingsKey: HISTORY_KEY,
entry: this._entryText });
@ -259,18 +126,6 @@ const RunDialog = new Lang.Class({
return true;
}
if (symbol == Clutter.slash) {
// Need preload data before get completion. GFilenameCompleter load content of parent directory.
// Parent directory for /usr/include/ is /usr/. So need to add fake name('a').
let text = o.get_text().concat('/a');
let prefix;
if (text.lastIndexOf(' ') == -1)
prefix = text;
else
prefix = text.substr(text.lastIndexOf(' ') + 1);
this._getCompletion(prefix);
return false;
}
if (symbol == Clutter.Tab) {
let text = o.get_text();
let prefix;
@ -282,8 +137,6 @@ const RunDialog = new Lang.Class({
if (postfix != null && postfix.length > 0) {
o.insert_text(postfix, -1);
o.set_cursor_position(text.length + postfix.length);
if (postfix[postfix.length - 1] == '/')
this._getCompletion(text + postfix + 'a');
}
return true;
}
@ -291,11 +144,53 @@ const RunDialog = new Lang.Class({
}));
},
_getCommandCompletion: function(text) {
function _getCommon(s1, s2) {
if (s1 == null)
return s2;
let k = 0;
for (; k < s1.length && k < s2.length; k++) {
if (s1[k] != s2[k])
break;
}
if (k == 0)
return '';
return s1.substr(0, k);
}
let paths = GLib.getenv('PATH').split(':');
paths.push(GLib.get_home_dir());
let someResults = paths.map(function(path) {
let results = [];
try {
let file = Gio.File.new_for_path(path);
let fileEnum = file.enumerate_children('standard::name', Gio.FileQueryInfoFlags.NONE, null);
let info;
while ((info = fileEnum.next_file(null))) {
let name = info.get_name();
if (name.slice(0, text.length) == text)
results.push(name);
}
} catch (e if (!e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.NOT_FOUND) &&
!e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.NOT_DIRECTORY))) {
log(e);
} finally {
return results;
}
});
let results = someResults.reduce(function(a, b) {
return a.concat(b);
}, []);
let common = results.reduce(_getCommon, null);
return common.substr(text.length);
},
_getCompletion : function(text) {
if (text.indexOf('/') != -1) {
return this._pathCompleter.get_completion_suffix(text);
} else {
return this._commandCompleter.getCompletion(text);
return this._getCommandCompletion(text);
}
},

View File

@ -38,11 +38,7 @@ const ARROW_DRAG_THRESHOLD = 0.1;
const N_ARROWS = 3;
const ARROW_ANIMATION_TIME = 0.6;
const ARROW_ANIMATION_PEAK_OPACITY = 0.4;
// The distance in px that the lock screen will move to when pressing
// a key that has no effect in the lock screen (bumping it)
const BUMP_SIZE = 25;
const BUMP_TIME = 0.3;
const ARROW_IDLE_TIME = 30000; // ms
const SUMMARY_ICON_SIZE = 48;
@ -54,7 +50,7 @@ const SUMMARY_ICON_SIZE = 48;
// - CURTAIN_SLIDE_TIME is used when raising the shield before unlocking
// - INITIAL_FADE_IN_TIME is used for the initial fade in at startup
const STANDARD_FADE_TIME = 10;
const MANUAL_FADE_TIME = 0.8;
const MANUAL_FADE_TIME = 0.3;
const BACKGROUND_FADE_TIME = 1.0;
const CURTAIN_SLIDE_TIME = 0.3;
const INITIAL_FADE_IN_TIME = 0.25;
@ -435,8 +431,8 @@ const ScreenShield = new Lang.Class({
name: 'lockScreenGroup',
visible: false,
});
this._lockScreenGroup.connect('key-release-event',
Lang.bind(this, this._onLockScreenKeyRelease));
this._lockScreenGroup.connect('key-press-event',
Lang.bind(this, this._onLockScreenKeyPress));
this._lockScreenGroup.connect('scroll-event',
Lang.bind(this, this._onLockScreenScroll));
Main.ctrlAltTabManager.addGroup(this._lockScreenGroup, _("Lock"), 'changes-prevent-symbolic');
@ -447,7 +443,7 @@ const ScreenShield = new Lang.Class({
this._lockScreenGroup.add_actor(this._lockScreenContents);
this._backgroundGroup = new Meta.BackgroundGroup();
this._backgroundGroup = new Clutter.Actor();
this._lockScreenGroup.add_actor(this._backgroundGroup);
this._backgroundGroup.lower_bottom();
@ -456,6 +452,9 @@ const ScreenShield = new Lang.Class({
this._updateBackgrounds();
Main.layoutManager.connect('monitors-changed', Lang.bind(this, this._updateBackgrounds));
this._arrowAnimationId = 0;
this._arrowWatchId = 0;
this._arrowActiveWatchId = 0;
this._arrowContainer = new St.BoxLayout({ style_class: 'screen-shield-arrows',
vertical: true,
x_align: Clutter.ActorAlign.CENTER,
@ -507,14 +506,18 @@ const ScreenShield = new Lang.Class({
this._screenSaverDBus = new ShellDBus.ScreenSaverDBus(this);
this._inhibitor = null;
this._aboutToSuspend = false;
this._loginManager = LoginManager.getLoginManager();
this._loginManager.connect('prepare-for-sleep',
Lang.bind(this, this._prepareForSleep));
this._inhibitSuspend();
this._loginSession = this._loginManager.getCurrentSessionProxy();
this._loginSession.connectSignal('Lock', Lang.bind(this, function() { this.lock(false); }));
this._loginSession.connectSignal('Unlock', Lang.bind(this, function() { this.deactivate(false); }));
this._loginManager.getCurrentSessionProxy(Lang.bind(this,
function(sessionProxy) {
this._loginSession = sessionProxy;
this._loginSession.connectSignal('Lock', Lang.bind(this, function() { this.lock(false); }));
this._loginSession.connectSignal('Unlock', Lang.bind(this, function() { this.deactivate(false); }));
}));
this._settings = new Gio.Settings({ schema: SCREENSAVER_SCHEMA });
@ -538,21 +541,20 @@ const ScreenShield = new Lang.Class({
},
_createBackground: function(monitorIndex) {
let bin = new St.Bin({ style_class: 'screen-shield-background' });
let monitor = Main.layoutManager.monitors[monitorIndex];
let widget = new St.Widget({ style_class: 'screen-shield-background',
x: monitor.x,
y: monitor.y,
width: monitor.width,
height: monitor.height });
let group = new Meta.BackgroundGroup();
bin.child = group;
let bgManager = new Background.BackgroundManager({ container: group,
let bgManager = new Background.BackgroundManager({ container: widget,
monitorIndex: monitorIndex,
effects: Meta.BackgroundEffects.BLUR | Meta.BackgroundEffects.DESATURATE });
bgManager.background.saturation = 0.6;
controlPosition: false });
this._bgManagers.push(bgManager);
this._backgroundGroup.add_child(bin);
bin.lower_bottom();
this._backgroundGroup.add_child(widget);
},
_updateBackgrounds: function() {
@ -560,6 +562,7 @@ const ScreenShield = new Lang.Class({
this._bgManagers[i].destroy();
this._bgManagers = [];
this._backgroundGroup.destroy_all_children();
for (let i = 0; i < Main.layoutManager.monitors.length; i++)
this._createBackground(i);
@ -589,28 +592,28 @@ const ScreenShield = new Lang.Class({
return this._isModal;
},
_onLockScreenKeyRelease: function(actor, event) {
_onLockScreenKeyPress: function(actor, event) {
let symbol = event.get_key_symbol();
let unichar = event.get_key_unicode();
// Do nothing if the lock screen is not fully shown.
// This avoids reusing the previous (and stale) unlock
// dialog if esc is pressed while the curtain is going
// down after cancel.
// Similarly, don't bump if the lock screen is not showing or is
// animating, as the bump overrides the animation and would
// remove any onComplete handler.
if (this._lockScreenState != MessageTray.State.SHOWN)
return false;
if (symbol == Clutter.KEY_Escape ||
symbol == Clutter.KEY_Return ||
symbol == Clutter.KEY_KP_Enter) {
this._liftShield(false, 0);
return true;
}
let isEnter = (symbol == Clutter.KEY_Return || symbol == Clutter.KEY_KP_Enter);
if (!isEnter && !(GLib.unichar_isprint(unichar) || symbol == Clutter.KEY_Escape))
return false;
this._bumpLockScreen();
this._ensureUnlockDialog(true, true);
if (GLib.unichar_isgraph(unichar))
this._dialog.addCharacter(unichar);
this._liftShield(true, 0);
return true;
},
@ -648,6 +651,8 @@ const ScreenShield = new Lang.Class({
},
_prepareForSleep: function(loginManager, aboutToSuspend) {
this._aboutToSuspend = aboutToSuspend;
if (aboutToSuspend) {
if (!this._settings.get_boolean(LOCK_ENABLED_KEY)) {
this._uninhibitSuspend();
@ -848,19 +853,12 @@ const ScreenShield = new Lang.Class({
this._hideLockScreen(false, 0);
},
_bumpLockScreen: function() {
Tweener.removeTweens(this._lockScreenGroup);
Tweener.addTween(this._lockScreenGroup,
{ y: -BUMP_SIZE,
time: BUMP_TIME / 2,
transition: 'easeOutQuad',
onComplete: function() {
Tweener.addTween(this,
{ y: 0,
time: BUMP_TIME / 2,
transition: 'easeInQuad' });
}
});
_hideLockScreenComplete: function() {
if (Main.sessionMode.currentMode == 'lock-screen')
Main.sessionMode.popMode('lock-screen');
this._lockScreenState = MessageTray.State.HIDDEN;
this._lockScreenGroup.hide();
},
_hideLockScreen: function(animate, velocity) {
@ -886,21 +884,13 @@ const ScreenShield = new Lang.Class({
{ y: -h,
time: time,
transition: 'easeInQuad',
onComplete: function() {
this._lockScreenState = MessageTray.State.HIDDEN;
this._lockScreenGroup.hide();
},
onCompleteScope: this,
onComplete: Lang.bind(this, this._hideLockScreenComplete),
});
} else {
this._lockScreenState = MessageTray.State.HIDDEN;
this._lockScreenGroup.hide();
this._hideLockScreenComplete();
}
global.stage.show_cursor();
if (Main.sessionMode.currentMode == 'lock-screen')
Main.sessionMode.popMode('lock-screen');
},
_ensureUnlockDialog: function(onPrimary, allowCancel) {
@ -916,14 +906,12 @@ const ScreenShield = new Lang.Class({
let time = global.get_current_time();
this._dialog.connect('loaded', Lang.bind(this, function() {
if (!this._dialog.open(time, onPrimary)) {
// This is kind of an impossible error: we're already modal
// by the time we reach this...
log('Could not open login dialog: failed to acquire grab');
this.deactivate(true);
}
}));
if (!this._dialog.open(time, onPrimary)) {
// This is kind of an impossible error: we're already modal
// by the time we reach this...
log('Could not open login dialog: failed to acquire grab');
this.deactivate(true);
}
this._dialog.connect('failed', Lang.bind(this, this._onUnlockFailed));
this._dialog.connect('unlocked', Lang.bind(this, this._onUnlockSucceded));
@ -989,16 +977,60 @@ const ScreenShield = new Lang.Class({
Main.sessionMode.pushMode('lock-screen');
},
_startArrowAnimation: function() {
this._arrowActiveWatchId = 0;
if (!this._arrowAnimationId) {
this._arrowAnimationId = Mainloop.timeout_add(6000, Lang.bind(this, this._animateArrows));
this._animateArrows();
}
if (!this._arrowWatchId)
this._arrowWatchId = this.idleMonitor.add_idle_watch(ARROW_IDLE_TIME,
Lang.bind(this, this._pauseArrowAnimation));
},
_pauseArrowAnimation: function() {
if (this._arrowAnimationId) {
Mainloop.source_remove(this._arrowAnimationId);
this._arrowAnimationId = 0;
}
if (!this._arrowActiveWatchId)
this._arrowActiveWatchId = this.idleMonitor.add_user_active_watch(Lang.bind(this, this._startArrowAnimation));
},
_stopArrowAnimation: function() {
if (this._arrowAnimationId) {
Mainloop.source_remove(this._arrowAnimationId);
this._arrowAnimationId = 0;
}
if (this._arrowActiveWatchId) {
this.idleMonitor.remove_watch(this._arrowActiveWatchId);
this._arrowActiveWatchId = 0;
}
if (this._arrowWatchId) {
this.idleMonitor.remove_watch(this._arrowWatchId);
this._arrowWatchId = 0;
}
},
_checkArrowAnimation: function() {
let idleTime = this.idleMonitor.get_idletime();
if (idleTime < ARROW_IDLE_TIME)
this._startArrowAnimation();
else
this._pauseArrowAnimation();
},
_lockScreenShown: function() {
if (this._dialog && !this._isGreeter) {
this._dialog.destroy();
this._dialog = null;
}
if (this._arrowAnimationId)
Mainloop.source_remove(this._arrowAnimationId);
this._arrowAnimationId = Mainloop.timeout_add(6000, Lang.bind(this, this._animateArrows));
this._animateArrows();
this._checkArrowAnimation();
let motionId = global.stage.connect('captured-event', function(stage, event) {
if (event.type() == Clutter.EventType.MOTION) {
@ -1020,7 +1052,8 @@ const ScreenShield = new Lang.Class({
if (prevIsActive != this._isActive)
this.emit('active-changed');
this._uninhibitSuspend();
if (this._aboutToSuspend)
this._uninhibitSuspend();
this.emit('lock-screen-shown');
},
@ -1060,12 +1093,9 @@ const ScreenShield = new Lang.Class({
this._notificationsBox = null;
}
this._lockScreenContentsBox.destroy();
this._stopArrowAnimation();
if (this._arrowAnimationId) {
Mainloop.source_remove(this._arrowAnimationId);
this._arrowAnimationId = 0;
}
this._lockScreenContentsBox.destroy();
this._hasLockScreen = false;
},
@ -1085,6 +1115,9 @@ const ScreenShield = new Lang.Class({
deactivate: function(animate) {
this._hideLockScreen(animate, 0);
if (this._hasLockScreen)
this._clearLockScreen();
if (Main.sessionMode.currentMode == 'lock-screen')
Main.sessionMode.popMode('lock-screen');
if (Main.sessionMode.currentMode == 'unlock-dialog')
@ -1101,9 +1134,6 @@ const ScreenShield = new Lang.Class({
},
_completeDeactivate: function() {
if (this._hasLockScreen)
this._clearLockScreen();
if (this._dialog && !this._isGreeter) {
this._dialog.destroy();
this._dialog = null;
@ -1170,6 +1200,12 @@ const ScreenShield = new Lang.Class({
return;
}
// Clear the clipboard - otherwise, its contents may be leaked
// to unauthorized parties by pasting into the unlock dialog's
// password entry and unmasking the entry
St.Clipboard.get_default().set_text(St.ClipboardType.CLIPBOARD, '');
St.Clipboard.get_default().set_text(St.ClipboardType.PRIMARY, '');
this._isLocked = true;
this.activate(animate);
@ -1177,62 +1213,3 @@ const ScreenShield = new Lang.Class({
},
});
Signals.addSignalMethods(ScreenShield.prototype);
/* Fallback code to handle session locking using gnome-screensaver,
in case the required GDM dependency is not there
*/
const ScreenShieldFallback = new Lang.Class({
Name: 'ScreenShieldFallback',
_init: function() {
Util.spawn(['gnome-screensaver']);
this._proxy = new Gio.DBusProxy({ g_connection: Gio.DBus.session,
g_name: 'org.gnome.ScreenSaver',
g_object_path: '/org/gnome/ScreenSaver',
g_interface_name: 'org.gnome.ScreenSaver',
g_flags: (Gio.DBusProxyFlags.DO_NOT_AUTO_START |
Gio.DBusProxyFlags.DO_NOT_LOAD_PROPERTIES),
});
this._proxy.init(null);
this._proxy.connect('g-signal', Lang.bind(this, this._onSignal));
this._proxy.connect('notify::g-name-owner', Lang.bind(this, this._onNameOwnerChanged));
},
_onNameOwnerChanged: function(object, pspec) {
if (this._proxy.g_name_owner)
[this._locked] = this._proxy.call_sync('GetActive', null,
Gio.DBusCallFlags.NONE, -1, null).deep_unpack();
else
this._locked = false;
this.emit('active-changed', this._locked);
},
_onSignal: function(proxy, senderName, signalName, params) {
if (signalName == 'ActiveChanged') {
[this._locked] = params.deep_unpack();
this.emit('active-changed', this._locked);
}
},
get locked() {
return this._locked;
},
lock: function() {
this._proxy.call('Lock', null, Gio.DBusCallFlags.NONE, -1, null,
Lang.bind(this, function(proxy, result) {
proxy.call_finish(result);
this.emit('lock-screen-shown');
}));
},
unlock: function() {
this._proxy.call('SetActive', GLib.Variant.new('(b)', false),
Gio.DBusCallFlags.NONE, -1, null, null);
},
});
Signals.addSignalMethods(ScreenShieldFallback.prototype);

140
js/ui/screencast.js Normal file
View File

@ -0,0 +1,140 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
const Gio = imports.gi.Gio;
const GLib = imports.gi.GLib;
const Lang = imports.lang;
const Shell = imports.gi.Shell;
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 ScreencastService = new Lang.Class({
Name: 'ScreencastService',
_init: function() {
this._dbusImpl = Gio.DBusExportedObject.wrapJSObject(ScreencastIface, this);
this._dbusImpl.export(Gio.DBus.session, '/org/gnome/Shell/Screencast');
Gio.DBus.session.own_name('org.gnome.Shell.Screencast', Gio.BusNameOwnerFlags.REPLACE, null, null);
this._recorders = new Hash.Map();
Main.sessionMode.connect('updated',
Lang.bind(this, this._sessionModeChanged));
},
_ensureRecorderForSender: function(sender) {
let recorder = this._recorders.get(sender);
if (!recorder) {
recorder = new Shell.Recorder({ stage: global.stage });
recorder._watchNameId =
Gio.bus_watch_name(Gio.BusType.SESSION, sender, 0, null,
Lang.bind(this, this._onNameVanished));
this._recorders.set(sender, recorder);
}
return recorder;
},
_sessionModeChanged: function() {
if (Main.sessionMode.allowScreencast)
return;
for (let sender in this._recorders.keys())
this._recorders.delete(sender);
},
_onNameVanished: function(connection, name) {
this._stopRecordingForSender(name);
},
_stopRecordingForSender: function(sender) {
let recorder = this._recorders.get(sender);
if (!recorder)
return false;
Gio.bus_unwatch_name(recorder._watchNameId);
recorder.close();
this._recorders.delete(sender);
return true;
},
_applyOptionalParameters: function(recorder, options) {
for (let option in options)
options[option] = options[option].deep_unpack();
if (options['pipeline'])
recorder.set_pipeline(options['pipeline']);
if (options['framerate'])
recorder.set_framerate(options['framerate']);
if (options['draw-cursor'])
recorder.set_draw_cursor(options['draw-cursor']);
},
ScreencastAsync: function(params, invocation) {
let returnValue = [false, ''];
if (!Main.sessionMode.allowScreencast)
invocation.return_value(GLib.Variant.new('(bs)', returnValue));
let sender = invocation.get_sender();
let recorder = this._ensureRecorderForSender(sender);
if (!recorder.is_recording()) {
let [fileTemplate, options] = params;
recorder.set_file_template(fileTemplate);
this._applyOptionalParameters(recorder, options);
let [success, fileName] = recorder.record();
returnValue = [success, fileName ? fileName : ''];
}
invocation.return_value(GLib.Variant.new('(bs)', returnValue));
},
ScreencastAreaAsync: function(params, invocation) {
let returnValue = [false, ''];
if (!Main.sessionMode.allowScreencast)
invocation.return_value(GLib.Variant.new('(bs)', returnValue));
let sender = invocation.get_sender();
let recorder = this._ensureRecorderForSender(sender);
if (!recorder.is_recording()) {
let [x, y, width, height, fileTemplate, options] = params;
recorder.set_file_template(fileTemplate);
recorder.set_area(x, y, width, height);
this._applyOptionalParameters(recorder, options);
let [success, fileName] = recorder.record();
returnValue = [success, fileName ? fileName : ''];
}
invocation.return_value(GLib.Variant.new('(bs)', returnValue));
},
StopScreencastAsync: function(params, invocation) {
let success = this._stopRecordingForSender(invocation.get_sender());
invocation.return_value(GLib.Variant.new('(b)', [success]));
}
});

View File

@ -76,6 +76,11 @@ const ScreenshotService = new Lang.Class({
ScreenshotAreaAsync : function (params, invocation) {
let [x, y, width, height, flash, filename, callback] = params;
if (height <= 0 || width <= 0) {
invocation.return_error_literal(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED,
"Invalid params");
return;
}
let screenshot = new Shell.Screenshot();
screenshot.screenshot_area (x, y, width, height, filename,
Lang.bind(this, this._onScreenshotComplete,

View File

@ -4,6 +4,7 @@ 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;
@ -13,6 +14,7 @@ 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;
@ -102,11 +104,11 @@ const ListSearchResult = new Lang.Class({
y_fill: false,
x_align: St.Align.START,
y_align: St.Align.START });
this.actor.label_actor = title;
// TODO: should highlight terms in the description here
if (this.metaInfo['description']) {
let description = new St.Label({ style_class: 'list-search-result-description',
text: '"' + 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,
@ -140,6 +142,7 @@ const GridSearchResult = new Lang.Class({
}
this.actor.set_child(content);
this.actor.label_actor = content.label_actor;
let draggable = DND.makeDraggable(this.actor);
draggable.connect('drag-begin',
@ -228,9 +231,14 @@ const ListSearchResults = new Lang.Class({
this._pendingClear = true;
},
_keyFocusIn: function(icon) {
this.emit('key-focus-in', icon);
},
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);
}
},
@ -247,6 +255,7 @@ const ListSearchResults = new Lang.Class({
return null;
}
});
Signals.addSignalMethods(ListSearchResults.prototype);
const GridSearchResults = new Lang.Class({
Name: 'GridSearchResults',
@ -289,9 +298,14 @@ const GridSearchResults = new Lang.Class({
this._pendingClear = true;
},
_keyFocusIn: function(icon) {
this.emit('key-focus-in', icon);
},
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.actor);
}
},
@ -308,6 +322,7 @@ const GridSearchResults = new Lang.Class({
return null;
}
});
Signals.addSignalMethods(GridSearchResults.prototype);
const SearchResults = new Lang.Class({
Name: 'SearchResults',
@ -331,7 +346,8 @@ const SearchResults = new Lang.Class({
this._scrollView = new St.ScrollView({ x_fill: true,
y_fill: false,
style_class: 'vfade' });
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 });
@ -366,6 +382,10 @@ const SearchResults = new Lang.Class({
return false;
},
_keyFocusIn: function(provider, icon) {
Util.ensureActorVisibleInScrollView(this._scrollView, icon);
},
createProviderMeta: function(provider) {
let providerBox = new St.BoxLayout({ style_class: 'search-section',
vertical: true });
@ -379,6 +399,8 @@ const SearchResults = new Lang.Class({
resultDisplay = new GridSearchResults(provider);
}
resultDisplay.connect('key-focus-in', Lang.bind(this, this._keyFocusIn));
let resultDisplayBin = new St.Bin({ child: resultDisplay.actor,
x_fill: true,
y_fill: true });
@ -557,6 +579,7 @@ const ProviderIcon = new Lang.Class({
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() });

View File

@ -16,6 +16,7 @@ const _modes = {
'restrictive': {
parentMode: null,
stylesheetName: 'gnome-shell.css',
overridesSchema: 'org.gnome.shell.overrides',
hasOverview: false,
showCalendarEvents: false,
allowSettings: false,
@ -45,7 +46,7 @@ const _modes = {
unlockDialog: imports.gdm.loginDialog.LoginDialog,
components: ['polkitAgent'],
panel: {
left: ['logo'],
left: [],
center: ['dateMenu'],
right: ['a11yGreeter', 'display', 'keyboard',
'volume', 'battery', 'powerMenu']
@ -79,12 +80,13 @@ const _modes = {
},
'initial-setup': {
hasWindows: true,
isPrimary: true,
components: ['keyring'],
components: ['networkAgent', 'keyring'],
panel: {
left: [],
center: ['dateMenu'],
right: ['a11yGreeter', 'keyboard', 'volume']
right: ['a11yGreeter', 'keyboard', 'volume', 'battery']
}
},
@ -158,12 +160,7 @@ function listModes() {
const SessionMode = new Lang.Class({
Name: 'SessionMode',
_init: function() {
global.connect('notify::session-mode', Lang.bind(this, this._sync));
this._modes = _modes;
this._modeStack = [DEFAULT_MODE];
this._sync();
init: function() {
_getModes(Lang.bind(this, function(modes) {
this._modes = modes;
let primary = modes[global.session_mode] &&
@ -171,6 +168,8 @@ const SessionMode = new Lang.Class({
let mode = primary ? global.session_mode : 'user';
this._modeStack = [mode];
this._sync();
this.emit('sessions-loaded');
}));
},
@ -197,6 +196,10 @@ const SessionMode = new Lang.Class({
return this._modeStack[this._modeStack.length - 1];
},
get allowScreencast() {
return this.components.indexOf('recorder') != -1;
},
_sync: function() {
let params = this._modes[this.currentMode];
let defaults;

View File

@ -1,15 +1,18 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
const Lang = imports.lang;
const Gio = imports.gi.Gio;
const GLib = imports.gi.GLib;
const Lang = imports.lang;
const Meta = imports.gi.Meta;
const Shell = imports.gi.Shell;
const Config = imports.misc.config;
const ExtensionSystem = imports.ui.extensionSystem;
const ExtensionDownloader = imports.ui.extensionDownloader;
const ExtensionUtils = imports.misc.extensionUtils;
const Hash = imports.misc.hash;
const Main = imports.ui.main;
const Screencast = imports.ui.screencast;
const Screenshot = imports.ui.screenshot;
const GnomeShellIface = <interface name="org.gnome.Shell">
@ -18,6 +21,27 @@ const GnomeShellIface = <interface name="org.gnome.Shell">
<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="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" />
</signal>
<property name="Mode" type="s" access="read" />
<property name="OverviewActive" type="b" access="readwrite" />
<property name="ShellVersion" type="s" access="read" />
@ -47,8 +71,17 @@ const GnomeShell = new Lang.Class({
this._dbusImpl = Gio.DBusExportedObject.wrapJSObject(GnomeShellIface, this);
this._dbusImpl.export(Gio.DBus.session, '/org/gnome/Shell');
this._extensionsSerivce = new GnomeShellExtensions();
this._extensionsService = new GnomeShellExtensions();
this._screencastService = new Screencast.ScreencastService();
this._screenshotService = new Screenshot.ScreenshotService();
this._grabbedAccelerators = new Hash.Map();
this._grabbers = new Hash.Map();
global.display.connect('accelerator-activated', Lang.bind(this,
function(display, action, deviceid) {
this._emitAcceleratorActivated(action, deviceid);
}));
},
/**
@ -67,7 +100,7 @@ const GnomeShell = new Lang.Class({
*/
Eval: function(code) {
if (!global.settings.get_boolean('development-tools'))
return [false, null];
return [false, ''];
let returnValue;
let success;
@ -84,6 +117,106 @@ const GnomeShell = new Lang.Class({
return [success, returnValue];
},
FocusSearch: function() {
Main.overview.focusSearch();
},
ShowOSD: function(params) {
for (let param in params)
params[param] = params[param].deep_unpack();
let icon = null;
if (params['icon'])
icon = Gio.Icon.new_for_string(params['icon']);
Main.osdWindow.setIcon(icon);
Main.osdWindow.setLabel(params['label']);
Main.osdWindow.setLevel(params['level']);
Main.osdWindow.show();
},
GrabAcceleratorAsync: function(params, invocation) {
let [accel, flags] = params;
let sender = invocation.get_sender();
let bindingAction = this._grabAcceleratorForSender(accel, flags, sender);
return invocation.return_value(GLib.Variant.new('(u)', [bindingAction]));
},
GrabAcceleratorsAsync: function(params, invocation) {
let [accels] = params;
let sender = invocation.get_sender();
let bindingActions = [];
for (let i = 0; i < accels.length; i++) {
let [accel, flags] = accels[i];
bindingActions.push(this._grabAcceleratorForSender(accel, flags, sender));
}
return invocation.return_value(GLib.Variant.new('(au)', [bindingActions]));
},
UngrabAcceleratorAsync: function(params, invocation) {
let [action] = params;
let grabbedBy = this._grabbedAccelerators.get(action);
if (invocation.get_sender() != grabbedBy)
return invocation.return_value(GLib.Variant.new('(b)', [false]));
let ungrabSucceeded = global.display.ungrab_accelerator(action);
if (ungrabSucceeded)
this._grabbedAccelerators.delete(action);
return invocation.return_value(GLib.Variant.new('(b)', [ungrabSucceeded]));
},
_emitAcceleratorActivated: function(action, deviceid) {
let destination = this._grabbedAccelerators.get(action);
if (!destination)
return;
let connection = this._dbusImpl.get_connection();
let info = this._dbusImpl.get_info();
connection.emit_signal(destination,
this._dbusImpl.get_object_path(),
info ? info.name : null,
'AcceleratorActivated',
GLib.Variant.new('(uu)', [action, deviceid]));
},
_grabAcceleratorForSender: function(accelerator, flags, sender) {
let bindingAction = global.display.grab_accelerator(accelerator);
if (bindingAction == Meta.KeyBindingAction.NONE)
return Meta.KeyBindingAction.NONE;
let bindingName = Meta.external_binding_name_for_action(bindingAction);
Main.wm.allowKeybinding(bindingName, flags);
this._grabbedAccelerators.set(bindingAction, sender);
if (!this._grabbers.has(sender)) {
let id = Gio.bus_watch_name(Gio.BusType.SESSION, sender, 0, null,
Lang.bind(this, this._onGrabberBusNameVanished));
this._grabbers.set(sender, id);
}
return bindingAction;
},
_ungrabAccelerator: function(action) {
let ungrabSucceeded = global.display.ungrab_accelerator(action);
if (ungrabSucceeded)
this._grabbedAccelerators.delete(action);
},
_onGrabberBusNameVanished: function(connection, name) {
let grabs = this._grabbedAccelerators.items();
for (let i = 0; i < grabs.length; i++) {
let [action, sender] = grabs[i];
if (sender == name)
this._ungrabAccelerator(action);
}
Gio.bus_unwatch_name(this._grabbers.get(name));
this._grabbers.delete(name);
},
Mode: global.session_mode,
get OverviewActive() {
@ -271,7 +404,7 @@ const ScreenSaverDBus = new Lang.Class({
if (active)
this._screenShield.activate(true);
else
this._screenShield.unlock(false);
this._screenShield.deactivate(false);
},
GetActive: function() {

View File

@ -14,9 +14,7 @@ const EntryMenu = new Lang.Class({
Name: 'ShellEntryMenu',
Extends: PopupMenu.PopupMenu,
_init: function(entry, params) {
params = Params.parse (params, { isPassword: false });
_init: function(entry) {
this.parent(entry, 0, St.Side.TOP);
this.actor.add_style_class_name('entry-context-menu');
@ -37,8 +35,6 @@ const EntryMenu = new Lang.Class({
this._pasteItem = item;
this._passwordItem = null;
if (params.isPassword)
this._makePasswordItem();
Main.uiGroup.add_actor(this.actor);
this.actor.hide();
@ -53,19 +49,21 @@ const EntryMenu = new Lang.Class({
},
get isPassword() {
return this._passwordItem != null;
return this._passwordItem != null;
},
set isPassword(v) {
if (v == this.isPassword)
return;
if (v == this.isPassword)
return;
if (v)
this._makePasswordItem();
else {
this._passwordItem.destroy();
this._passwordItem = null;
}
if (v) {
this._makePasswordItem();
this._entry.input_purpose = Gtk.InputPurpose.PASSWORD;
} else {
this._passwordItem.destroy();
this._passwordItem = null;
this._entry.input_purpose = Gtk.InputPurpose.FREE_FORM;
}
},
open: function(animate) {
@ -82,14 +80,10 @@ const EntryMenu = new Lang.Class({
this.actor.grab_key_focus();
},
close: function(animate) {
this._entry.grab_key_focus();
this.parent(animate);
},
_updateCopyItem: function() {
let selection = this._entry.clutter_text.get_selection();
this._copyItem.setSensitive(selection && selection != '');
this._copyItem.setSensitive(!this._entry.clutter_text.password_char &&
selection && selection != '');
},
_updatePasteItem: function() {
@ -159,7 +153,10 @@ function addContextMenu(entry, params) {
if (entry.menu)
return;
entry.menu = new EntryMenu(entry, params);
params = Params.parse (params, { isPassword: false });
entry.menu = new EntryMenu(entry);
entry.menu.isPassword = params.isPassword;
entry._menuManager = new PopupMenu.PopupMenuManager({ actor: entry });
entry._menuManager.addMenu(entry.menu);
@ -170,4 +167,10 @@ function addContextMenu(entry, params) {
entry.connect('button-press-event', Lang.bind(null, _onButtonPressEvent, entry));
entry.connect('popup-menu', Lang.bind(null, _onPopup, entry));
entry.connect('destroy', function() {
entry.menu.destroy();
entry.menu = null;
entry._menuManager = null;
});
}

View File

@ -33,6 +33,33 @@ const KEY_INPUT_SOURCES = 'sources';
const INPUT_SOURCE_TYPE_XKB = 'xkb';
const INPUT_SOURCE_TYPE_IBUS = 'ibus';
// This is the longest we'll keep the keyboard frozen until an input
// source is active.
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 KeyboardManagerProxy = Gio.DBusProxy.makeProxyWrapper(KeyboardManagerInterface);
function releaseKeyboard() {
if (Main.modalCount > 0)
global.display.unfreeze_keyboard(global.get_current_time());
else
global.display.ungrab_keyboard(global.get_current_time());
}
function holdKeyboard() {
global.freeze_keyboard(global.get_current_time());
}
const IBusManager = new Lang.Class({
Name: 'IBusManager',
@ -45,26 +72,24 @@ const IBusManager = new Lang.Class({
this._readyCallback = readyCallback;
this._candidatePopup = new IBusCandidatePopup.CandidatePopup();
this._ibus = null;
this._panelService = null;
this._engines = {};
this._ready = false;
this._registerPropertiesId = 0;
this._currentEngineName = null;
this._nameWatcherId = Gio.DBus.session.watch_name(IBus.SERVICE_IBUS,
Gio.BusNameWatcherFlags.NONE,
Lang.bind(this, this._onNameAppeared),
Lang.bind(this, this._clear));
this._ibus = IBus.Bus.new_async();
this._ibus.connect('connected', Lang.bind(this, this._onConnected));
this._ibus.connect('disconnected', Lang.bind(this, this._clear));
// Need to set this to get 'global-engine-changed' emitions
this._ibus.set_watch_ibus_signal(true);
this._ibus.connect('global-engine-changed', Lang.bind(this, this._engineChanged));
},
_clear: function() {
if (this._panelService)
this._panelService.destroy();
if (this._ibus)
this._ibus.destroy();
this._ibus = null;
this._panelService = null;
this._candidatePopup.setPanelService(null);
this._engines = {};
@ -76,18 +101,12 @@ const IBusManager = new Lang.Class({
this._readyCallback(false);
},
_onNameAppeared: function() {
this._ibus = IBus.Bus.new_async();
this._ibus.connect('connected', Lang.bind(this, this._onConnected));
},
_onConnected: function() {
this._ibus.list_engines_async(-1, null, Lang.bind(this, this._initEngines));
this._ibus.request_name_async(IBus.SERVICE_PANEL,
IBus.BusNameFlag.REPLACE_EXISTING,
-1, null,
Lang.bind(this, this._initPanelService));
this._ibus.connect('disconnected', Lang.bind(this, this._clear));
},
_initEngines: function(ibus, result) {
@ -109,9 +128,6 @@ const IBusManager = new Lang.Class({
this._panelService = new IBus.PanelService({ connection: this._ibus.get_connection(),
object_path: IBus.PATH_PANEL });
this._candidatePopup.setPanelService(this._panelService);
// Need to set this to get 'global-engine-changed' emitions
this._ibus.set_watch_ibus_signal(true);
this._ibus.connect('global-engine-changed', Lang.bind(this, this._engineChanged));
this._panelService.connect('update-property', Lang.bind(this, this._updateProperty));
// If an engine is already active we need to get its properties
this._ibus.get_global_engine_async(-1, null, Lang.bind(this, function(i, result) {
@ -140,6 +156,9 @@ const IBusManager = new Lang.Class({
},
_engineChanged: function(bus, engineName) {
if (!this._ready)
return;
this._currentEngineName = engineName;
if (this._registerPropertiesId != 0)
@ -364,6 +383,15 @@ const InputSourceIndicator = new Lang.Class({
this._ibusManager.connect('property-updated', Lang.bind(this, this._ibusPropertyUpdated));
this._inputSourcesChanged();
this._keyboardManager = new KeyboardManagerProxy(Gio.DBus.session, BUS_NAME, OBJECT_PATH,
function(proxy, error) {
if (error)
log(error.message);
});
this._keyboardManager.g_default_timeout = MAX_INPUT_SOURCE_ACTIVATION_TIME;
global.display.connect('modifiers-accelerator-activated', Lang.bind(this, this._modifiersSwitcher));
this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
this._showLayoutItem = this.menu.addAction(_("Show Keyboard Layout"), Lang.bind(this, this._showLayout));
@ -397,7 +425,43 @@ const InputSourceIndicator = new Lang.Class({
this._inputSourcesChanged();
},
_modifiersSwitcher: function() {
let sourceIndexes = Object.keys(this._inputSources);
if (sourceIndexes.length == 0) {
releaseKeyboard();
return true;
}
let is = this._currentSource;
if (!is)
is = this._inputSources[sourceIndexes[0]];
let nextIndex = is.index + 1;
if (nextIndex > sourceIndexes[sourceIndexes.length - 1])
nextIndex = 0;
while (!(is = this._inputSources[nextIndex]))
nextIndex += 1;
is.activate();
return true;
},
_switchInputSource: function(display, screen, window, binding) {
if (this._mruSources.length < 2)
return;
// HACK: Fall back on simple input source switching since we
// can't show a popup switcher while a GrabHelper grab is in
// effect without considerable work to consolidate the usage
// of pushModal/popModal and grabHelper. See
// https://bugzilla.gnome.org/show_bug.cgi?id=695143 .
if (Main.keybindingMode == Shell.KeyBindingMode.MESSAGE_TRAY ||
Main.keybindingMode == Shell.KeyBindingMode.TOPBAR_POPUP) {
this._modifiersSwitcher();
return;
}
let popup = new InputSourcePopup(this._mruSources, this._keybindingAction, this._keybindingActionBackward);
let modifiers = binding.get_modifiers();
let backwards = modifiers & Meta.VirtualModifier.SHIFT_MASK;
@ -413,6 +477,11 @@ const InputSourceIndicator = new Lang.Class({
let oldSource;
[oldSource, this._currentSource] = [this._currentSource, newSource];
if (oldSource) {
oldSource.menuItem.setShowDot(false);
oldSource.indicatorLabel.hide();
}
if (!newSource || (nVisibleSources < 2 && !newSource.properties)) {
// This source index might be invalid if we weren't able
// to build a menu item for it, so we hide ourselves since
@ -427,11 +496,6 @@ const InputSourceIndicator = new Lang.Class({
this.actor.show();
if (oldSource) {
oldSource.menuItem.setShowDot(false);
oldSource.indicatorLabel.hide();
}
newSource.menuItem.setShowDot(true);
newSource.indicatorLabel.show();
@ -456,6 +520,7 @@ const InputSourceIndicator = new Lang.Class({
this._inputSources = {};
this._ibusSources = {};
this._currentSource = null;
let inputSourcesByShortName = {};
@ -484,10 +549,8 @@ const InputSourceIndicator = new Lang.Class({
let is = new InputSource(type, id, displayName, shortName, i);
is.connect('activate', Lang.bind(this, function() {
if (this._currentSource.index == is.index)
return;
this._settings.set_value(KEY_CURRENT_INPUT_SOURCE,
GLib.Variant.new_uint32(is.index));
holdKeyboard();
this._keyboardManager.SetInputSourceRemote(is.index, releaseKeyboard);
}));
if (!(is.shortName in inputSourcesByShortName))
@ -700,7 +763,7 @@ const InputSourceIndicator = new Lang.Class({
item.prop = prop;
item.connect('activate', Lang.bind(this, function() {
this._ibusManager.activateProperty(item.prop.get_key(),
IBus.PropState.CHECKED);
item.prop.get_state());
}));
break;

View File

@ -2047,6 +2047,7 @@ const NMApplet = new Lang.Class({
let default_ip4 = null;
let default_ip6 = null;
let active_vpn = null;
let active_any = null;
for (let i = 0; i < this._activeConnections.length; i++) {
let a = this._activeConnections[i];
@ -2077,10 +2078,15 @@ const NMApplet = new Lang.Class({
if (a.default6)
default_ip6 = a;
if (a._type == 'vpn')
active_vpn = a;
else if (a.state == NetworkManager.ActiveConnectionState.ACTIVATING)
if (a.state == NetworkManager.ActiveConnectionState.ACTIVATING)
activating = a;
else if (a.state == NetworkManager.ActiveConnectionState.ACTIVATED)
active_any = a;
if (a._type == 'vpn' &&
(a.state == NetworkManager.ActiveConnectionState.ACTIVATING ||
a.state == NetworkManager.ActiveConnectionState.ACTIVATED))
active_vpn = a;
if (!a._primaryDevice) {
if (a._type != NetworkManager.SETTING_VPN_SETTING_NAME) {
@ -2108,7 +2114,7 @@ const NMApplet = new Lang.Class({
}
}
this._mainConnection = activating || default_ip4 || default_ip6 || this._activeConnections[0] || null;
this._mainConnection = activating || default_ip4 || default_ip6 || active_any || null;
this._vpnConnection = active_vpn;
},

View File

@ -307,7 +307,7 @@ const Indicator = new Lang.Class({
this._headphoneIcon.visible = value;
}));
this._headphoneIcon = this.addIcon(new Gio.ThemedIcon({ name: 'headphones-symbolic' }));
this._headphoneIcon = this.addIcon(new Gio.ThemedIcon({ name: 'audio-headphones-symbolic' }));
this._headphoneIcon.visible = false;
this.menu.addMenuItem(this._volumeMenu);

View File

@ -160,6 +160,7 @@ const SwitcherPopup = new Lang.Class({
// disturbed by the popup briefly flashing.
this._initialDelayTimeoutId = Mainloop.timeout_add(POPUP_DELAY_TIMEOUT,
Lang.bind(this, function () {
Main.osdWindow.cancel();
this.actor.opacity = 255;
this._initialDelayTimeoutId = 0;
}));
@ -304,7 +305,7 @@ const SwitcherList = new Lang.Class({
this.actor.connect('allocate', Lang.bind(this, this._allocateTop));
// Here we use a GenericContainer so that we can force all the
// children except the separator to have the same width.
// children to have the same width.
this._list = new Shell.GenericContainer({ style_class: 'switcher-list-item-container' });
this._list.spacing = 0;
this._list.connect('style-changed', Lang.bind(this, function() {
@ -339,7 +340,6 @@ const SwitcherList = new Lang.Class({
this._items = [];
this._highlighted = -1;
this._separator = null;
this._squareItems = squareItems;
this._minSize = 0;
this._scrollableRight = true;
@ -402,12 +402,6 @@ const SwitcherList = new Lang.Class({
this._itemEntered(index);
},
addSeparator: function () {
let box = new St.Bin({ style_class: 'separator' });
this._separator = box;
this._list.add_actor(box);
},
highlight: function(index, justOutline) {
if (this._highlighted != -1) {
this._items[this._highlighted].remove_style_pseudo_class('outlined');
@ -515,14 +509,8 @@ const SwitcherList = new Lang.Class({
_getPreferredWidth: function (actor, forHeight, alloc) {
let [maxChildMin, maxChildNat] = this._maxChildWidth(forHeight);
let separatorWidth = 0;
if (this._separator) {
let [sepMin, sepNat] = this._separator.get_preferred_width(forHeight);
separatorWidth = sepNat + this._list.spacing;
}
let totalSpacing = this._list.spacing * (this._items.length - 1);
alloc.min_size = this._items.length * maxChildMin + separatorWidth + totalSpacing;
alloc.min_size = this._items.length * maxChildMin + totalSpacing;
alloc.natural_size = alloc.min_size;
this._minSize = alloc.min_size;
},
@ -553,14 +541,7 @@ const SwitcherList = new Lang.Class({
let [maxChildMin, maxChildNat] = this._maxChildWidth(childHeight);
let totalSpacing = this._list.spacing * (this._items.length - 1);
let separatorWidth = 0;
if (this._separator) {
let [sepMin, sepNat] = this._separator.get_preferred_width(childHeight);
separatorWidth = sepNat;
totalSpacing += this._list.spacing;
}
let childWidth = Math.floor(Math.max(0, box.x2 - box.x1 - totalSpacing - separatorWidth) / this._items.length);
let childWidth = Math.floor(Math.max(0, box.x2 - box.x1 - totalSpacing) / this._items.length);
let x = 0;
let children = this._list.get_children();
@ -580,14 +561,6 @@ const SwitcherList = new Lang.Class({
children[i].allocate(childBox, flags);
x += this._list.spacing + childWidth;
} else if (children[i] == this._separator) {
// We want the separator to be more compact than the rest.
childBox.x1 = x;
childBox.y1 = 0;
childBox.x2 = x + separatorWidth;
childBox.y2 = childHeight;
children[i].allocate(childBox, flags);
x += this._list.spacing + separatorWidth;
} else {
// Something else, eg, AppSwitcher's arrows;
// we don't allocate it.

View File

@ -1,8 +1,8 @@
// -*- 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 Gtk = imports.gi.Gtk;
const Lang = imports.lang;
const Mainloop = imports.mainloop;
const Shell = imports.gi.Shell;
@ -45,12 +45,9 @@ const Tweener = imports.tweener.tweener;
// calls any of these is almost certainly wrong anyway, because they
// affect the entire application.)
let animationSettings = null;
// Called from Main.start
function init() {
Tweener.setFrameTicker(new ClutterFrameTicker());
animationSettings = new Gio.Settings({ schema: 'org.gnome.desktop.interface' });
}
@ -77,7 +74,7 @@ function _wrapTweening(target, tweeningParameters) {
}
}
if (!animationSettings.get_boolean('enable-animations'))
if (!Gtk.Settings.get_default().gtk_enable_animations)
tweeningParameters['time'] = 0.000001;
_addHandler(target, tweeningParameters, 'onStart', _tweenStarted);

View File

@ -27,35 +27,6 @@ const LoginDialog = imports.gdm.loginDialog;
// The timeout before going back automatically to the lock screen (in seconds)
const IDLE_TIMEOUT = 2 * 60;
function versionCompare(required, reference) {
required = required.split('.');
reference = reference.split('.');
for (let i = 0; i < required.length; i++) {
if (required[i] != reference[i])
return required[i] < reference[i];
}
return true;
}
function isSupported() {
try {
let params = GLib.Variant.new('(ss)', ['org.gnome.DisplayManager.Manager', 'Version']);
let result = Gio.DBus.system.call_sync('org.gnome.DisplayManager',
'/org/gnome/DisplayManager/Manager',
'org.freedesktop.DBus.Properties',
'Get', params, null,
Gio.DBusCallFlags.NONE,
-1, null);
let version = result.deep_unpack()[0].deep_unpack();
return versionCompare('3.5.91', version);
} catch(e) {
return false;
}
}
const UnlockDialog = new Lang.Class({
Name: 'UnlockDialog',
Extends: ModalDialog.ModalDialog,
@ -76,6 +47,7 @@ const UnlockDialog = new Lang.Class({
this._greeterClient = new Gdm.Client();
this._userVerifier = new GdmUtil.ShellUserVerifier(this._greeterClient, { reauthenticationOnly: true });
this._userVerified = false;
this._userVerifier.connect('ask-question', Lang.bind(this, this._onAskQuestion));
this._userVerifier.connect('show-message', Lang.bind(this, this._showMessage));
@ -98,6 +70,7 @@ const UnlockDialog = new Lang.Class({
this._promptEntry = new St.Entry({ style_class: 'login-dialog-prompt-entry',
can_focus: true });
this._promptEntry.clutter_text.connect('activate', Lang.bind(this, this._doUnlock));
this._promptEntry.clutter_text.set_password_char('\u25cf');
ShellEntry.addContextMenu(this._promptEntry, { isPassword: true });
this.setInitialKeyFocus(this._promptEntry);
@ -118,9 +91,6 @@ const UnlockDialog = new Lang.Class({
this._promptLoginHint.hide();
this.contentLayout.add_actor(this._promptLoginHint);
this._workSpinner = new Panel.AnimatedIcon('process-working.svg', LoginDialog.WORK_SPINNER_ICON_SIZE);
this._workSpinner.actor.opacity = 0;
this.allowCancel = false;
this.buttonLayout.visible = true;
this.addButton({ label: _("Cancel"),
@ -131,12 +101,11 @@ const UnlockDialog = new Lang.Class({
y_fill: false,
x_align: St.Align.START,
y_align: St.Align.MIDDLE });
this.buttonLayout.add(this._workSpinner.actor,
{ expand: false,
x_fill: false,
y_fill: false,
x_align: St.Align.END,
y_align: St.Align.MIDDLE });
this.placeSpinner({ expand: false,
x_fill: false,
y_fill: false,
x_align: St.Align.END,
y_align: St.Align.MIDDLE });
this._okButton = this.addButton({ label: _("Unlock"),
action: Lang.bind(this, this._doUnlock),
default: true },
@ -169,11 +138,6 @@ const UnlockDialog = new Lang.Class({
let batch = new Batch.Hold();
this._userVerifier.begin(this._userName, batch);
GLib.idle_add(GLib.PRIORITY_DEFAULT, Lang.bind(this, function() {
this.emit('loaded');
return false;
}));
Main.ctrlAltTabManager.addGroup(this.dialogLayout, _("Unlock Window"), 'dialog-password-symbolic');
this._idleMonitor = new GnomeDesktop.IdleMonitor();
@ -195,28 +159,6 @@ const UnlockDialog = new Lang.Class({
this._okButton.can_focus = sensitive;
},
_setWorking: function(working) {
if (working) {
this._workSpinner.play();
Tweener.addTween(this._workSpinner.actor,
{ opacity: 255,
delay: LoginDialog.WORK_SPINNER_ANIMATION_DELAY,
time: LoginDialog.WORK_SPINNER_ANIMATION_TIME,
transition: 'linear'
});
} else {
Tweener.addTween(this._workSpinner.actor,
{ opacity: 0,
time: LoginDialog.WORK_SPINNER_ANIMATION_TIME,
transition: 'linear',
onCompleteScope: this,
onComplete: function() {
this._workSpinner.stop();
}
});
}
},
_showMessage: function(userVerifier, message, styleClass) {
if (message) {
this._promptMessage.text = message;
@ -247,7 +189,7 @@ const UnlockDialog = new Lang.Class({
this._currentQuery = serviceName;
this._updateSensitivity(true);
this._setWorking(false);
this.setWorking(false);
},
_showLoginHint: function(verifier, message) {
@ -266,7 +208,7 @@ const UnlockDialog = new Lang.Class({
// the actual reply to GDM will be sent as soon as asked
this._firstQuestionAnswer = this._promptEntry.text;
this._updateSensitivity(false);
this._setWorking(true);
this.setWorking(true);
return;
}
@ -277,30 +219,47 @@ const UnlockDialog = new Lang.Class({
this._currentQuery = null;
this._updateSensitivity(false);
this._setWorking(true);
this.setWorking(true);
this._userVerifier.answerQuery(query, this._promptEntry.text);
},
_onVerificationComplete: function() {
_finishUnlock: function() {
this._userVerifier.clear();
this.emit('unlocked');
},
_onVerificationComplete: function() {
this._userVerified = true;
if (!this._userVerifier.hasPendingMessages) {
this._finishUnlock();
} else {
let signalId = this._userVerifier.connect('no-more-messages',
Lang.bind(this, function() {
this._userVerifier.disconnect(signalId);
this._finishUnlock();
}));
}
},
_onReset: function() {
this.emit('failed');
if (!this._userVerified) {
this._userVerifier.clear();
this.emit('failed');
}
},
_onVerificationFailed: function() {
this._currentQuery = null;
this._firstQuestion = true;
this._userVerified = false;
this._promptEntry.text = '';
this._promptEntry.clutter_text.set_password_char('\u25cf');
this._promptEntry.menu.isPassword = true;
this._updateSensitivity(false);
this._setWorking(false);
this.setWorking(false);
},
_escape: function() {
@ -333,4 +292,8 @@ const UnlockDialog = new Lang.Class({
this.destroy();
},
addCharacter: function(unichar) {
this._promptEntry.clutter_text.insert_unichar(unichar);
},
});

View File

@ -52,6 +52,7 @@ const SystemdLoginSessionIface = <interface name='org.freedesktop.login1.Session
<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 SystemdLoginSession = Gio.DBusProxy.makeProxyWrapper(SystemdLoginSessionIface);
@ -599,7 +600,8 @@ const UserMenuButton = new Lang.Class({
Lang.bind(this, this._updateHaveShutdown));
Main.sessionMode.connect('updated', Lang.bind(this, this._sessionUpdated));
Main.screenShield.connect('locked-changed', Lang.bind(this, this._updatePresenceIcon));
if (Main.screenShield)
Main.screenShield.connect('locked-changed', Lang.bind(this, this._updatePresenceIcon));
this._sessionUpdated();
},
@ -655,7 +657,7 @@ const UserMenuButton = new Lang.Class({
_updateLockScreen: function() {
let allowLockScreen = !this._lockdownSettings.get_boolean(DISABLE_LOCK_SCREEN_KEY);
this._lockScreenItem.actor.visible = allowLockScreen;
this._lockScreenItem.actor.visible = allowLockScreen && LoginManager.canLock();
},
_updateInstallUpdates: function() {
@ -863,7 +865,8 @@ const UserMenuButton = new Lang.Class({
_onLoginScreenActivate: function() {
this.menu.close(BoxPointer.PopupAnimation.NONE);
Main.overview.hide();
Main.screenShield.lock(false);
if (Main.screenShield)
Main.screenShield.lock(false);
Gdm.goto_login_session_sync(null);
},
@ -888,6 +891,7 @@ const UserMenuButton = new Lang.Class({
let descriptionLabel = new St.Label({ style_class: 'end-session-dialog-description'});
descriptionLabel.set_text(_("Shutting down might cause them to lose unsaved work."));
descriptionLabel.clutter_text.line_wrap = true;
dialog.contentLayout.add(descriptionLabel, { x_fill: true,
y_fill: true,
y_align: St.Align.START });
@ -913,8 +917,10 @@ const UserMenuButton = new Lang.Class({
session.user.get_real_name() : session.username;
if (session.info.remote)
/* Translators: Remote here refers to a remote session, like a ssh login */
userLabelText = _("%s (remote)").format(userName);
else if (session.info.type == "tty")
/* Translators: Console here refers to a tty like a VT console */
userLabelText = _("%s (console)").format(userName);
else
userLabelText = userName;
@ -961,6 +967,9 @@ const UserMenuButton = new Lang.Class({
if (proxy.Class != 'user')
continue;
if (proxy.State == 'closing')
continue;
if (proxy.Id == GLib.getenv('XDG_SESSION_ID'))
continue;

View File

@ -16,6 +16,7 @@ const UserWidget = new Lang.Class({
this.actor = new St.BoxLayout({ style_class: 'user-widget',
vertical: false });
this.actor.connect('destroy', Lang.bind(this, this._onDestroy));
this._avatar = new UserMenu.UserAvatarWidget(user);
this.actor.add(this._avatar.actor,
@ -36,7 +37,7 @@ const UserWidget = new Lang.Class({
this._updateUser();
},
destroy: function() {
_onDestroy: function() {
if (this._userLoadedId != 0) {
this._user.disconnect(this._userLoadedId);
this._userLoadedId = 0;
@ -46,8 +47,6 @@ const UserWidget = new Lang.Class({
this._user.disconnect(this._userChangedId);
this._userChangedId = 0;
}
this.actor.destroy();
},
_updateUser: function() {

View File

@ -83,11 +83,10 @@ const ViewSelector = new Lang.Class({
this._entry.connect('notify::mapped', Lang.bind(this, this._onMapped));
global.stage.connect('notify::key-focus', Lang.bind(this, this._onStageKeyFocusChanged));
this._inactiveIcon = new St.Icon({ style_class: 'search-entry-icon',
icon_name: 'edit-find-symbolic' });
this._activeIcon = new St.Icon({ style_class: 'search-entry-icon',
icon_name: 'edit-clear-symbolic' });
this._entry.set_secondary_icon(this._inactiveIcon);
this._entry.set_primary_icon(new St.Icon({ style_class: 'search-entry-icon',
icon_name: 'edit-find-symbolic' }));
this._clearIcon = new St.Icon({ style_class: 'search-entry-icon',
icon_name: 'edit-clear-symbolic' });
this._iconClickedId = 0;
this._capturedEventId = 0;
@ -279,8 +278,7 @@ const ViewSelector = new Lang.Class({
else
Main.overview.hide();
return true;
} else if (Clutter.keysym_to_unicode(symbol) ||
(symbol == Clutter.BackSpace && this._searchActive)) {
} else if (this._shouldTriggerSearch(symbol)) {
this.startSearch(event);
} else if (!this._searchActive) {
if (symbol == Clutter.Tab || symbol == Clutter.Down) {
@ -345,6 +343,17 @@ const ViewSelector = new Lang.Class({
}
},
_shouldTriggerSearch: function(symbol) {
let unicode = Clutter.keysym_to_unicode(symbol);
if (unicode == 0)
return false;
if (getTermsForSearchString(String.fromCharCode(unicode)).length > 0)
return true;
return symbol == Clutter.BackSpace && this._searchActive;
},
startSearch: function(event) {
global.stage.set_key_focus(this._text);
this._text.event(event, true);
@ -366,7 +375,7 @@ const ViewSelector = new Lang.Class({
this._searchResults.startingSearch();
if (this._searchActive) {
this._entry.set_secondary_icon(this._activeIcon);
this._entry.set_secondary_icon(this._clearIcon);
if (this._iconClickedId == 0)
this._iconClickedId = this._entry.connect('secondary-icon-clicked',
@ -386,7 +395,7 @@ const ViewSelector = new Lang.Class({
this._searchTimeoutId = 0;
}
this._entry.set_secondary_icon(this._inactiveIcon);
this._entry.set_secondary_icon(null);
this._searchCancelled();
}
},
@ -502,6 +511,22 @@ const ViewSelector = new Lang.Class({
return ViewPage.APPS;
else
return ViewPage.SEARCH;
},
fadeIn: function() {
let actor = this._activePage;
Tweener.addTween(actor, { opacity: 255,
time: OverviewControls.SIDE_CONTROLS_ANIMATION_TIME / 2,
transition: 'easeInQuad'
});
},
fadeHalf: function() {
let actor = this._activePage;
Tweener.addTween(actor, { opacity: 128,
time: OverviewControls.SIDE_CONTROLS_ANIMATION_TIME / 2,
transition: 'easeOutQuad'
});
}
});
Signals.addSignalMethods(ViewSelector.prototype);

View File

@ -11,12 +11,14 @@ const Layout = imports.ui.layout;
const Main = imports.ui.main;
const Panel = imports.ui.panel;
// we could make these gsettings
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 GNOME_PANEL_PIXMAPDIR = '../gnome-panel/fish';
const FISH_GROUP = 'Fish Animation';
const MAGIC_FISH_KEY = 'free the fish';
@ -26,33 +28,16 @@ const WandaIcon = new Lang.Class({
Extends: IconGrid.BaseIcon,
_init : function(fish, label, params) {
this._fish = fish;
let file = GLib.build_filenamev([global.datadir, GNOME_PANEL_PIXMAPDIR, fish + '.fish']);
if (GLib.file_test(file, GLib.FileTest.EXISTS)) {
this._keyfile = new GLib.KeyFile();
this._keyfile.load_from_file(file, GLib.KeyFileFlags.NONE);
this._imageFile = GLib.build_filenamev([global.datadir, GNOME_PANEL_PIXMAPDIR,
this._keyfile.get_string(FISH_GROUP, 'image')]);
let tmpPixbuf = GdkPixbuf.Pixbuf.new_from_file(this._imageFile);
this._imgHeight = tmpPixbuf.height;
this._imgWidth = tmpPixbuf.width / this._keyfile.get_integer(FISH_GROUP, 'frames');
} else {
this._imageFile = null;
}
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) {
if (!this._imageFile) {
return new St.Icon({ icon_name: 'face-smile',
icon_size: iconSize });
}
this._animations = new Panel.Animation(this._imageFile, this._imgWidth, this._imgHeight, FISH_SPEED);
this._animations.play();
return this._animations.actor;

View File

@ -136,6 +136,42 @@ const WindowManager = new Lang.Class({
Shell.KeyBindingMode.NORMAL |
Shell.KeyBindingMode.OVERVIEW,
Lang.bind(this, this._showWorkspaceSwitcher));
this.allowKeybinding('switch-to-workspace-1',
Shell.KeyBindingMode.NORMAL |
Shell.KeyBindingMode.OVERVIEW);
this.allowKeybinding('switch-to-workspace-2',
Shell.KeyBindingMode.NORMAL |
Shell.KeyBindingMode.OVERVIEW);
this.allowKeybinding('switch-to-workspace-3',
Shell.KeyBindingMode.NORMAL |
Shell.KeyBindingMode.OVERVIEW);
this.allowKeybinding('switch-to-workspace-4',
Shell.KeyBindingMode.NORMAL |
Shell.KeyBindingMode.OVERVIEW);
this.allowKeybinding('switch-to-workspace-5',
Shell.KeyBindingMode.NORMAL |
Shell.KeyBindingMode.OVERVIEW);
this.allowKeybinding('switch-to-workspace-6',
Shell.KeyBindingMode.NORMAL |
Shell.KeyBindingMode.OVERVIEW);
this.allowKeybinding('switch-to-workspace-7',
Shell.KeyBindingMode.NORMAL |
Shell.KeyBindingMode.OVERVIEW);
this.allowKeybinding('switch-to-workspace-8',
Shell.KeyBindingMode.NORMAL |
Shell.KeyBindingMode.OVERVIEW);
this.allowKeybinding('switch-to-workspace-9',
Shell.KeyBindingMode.NORMAL |
Shell.KeyBindingMode.OVERVIEW);
this.allowKeybinding('switch-to-workspace-10',
Shell.KeyBindingMode.NORMAL |
Shell.KeyBindingMode.OVERVIEW);
this.allowKeybinding('switch-to-workspace-11',
Shell.KeyBindingMode.NORMAL |
Shell.KeyBindingMode.OVERVIEW);
this.allowKeybinding('switch-to-workspace-12',
Shell.KeyBindingMode.NORMAL |
Shell.KeyBindingMode.OVERVIEW);
this.setCustomKeybindingHandler('switch-applications',
Shell.KeyBindingMode.NORMAL,
Lang.bind(this, this._startAppSwitcher));
@ -172,8 +208,9 @@ const WindowManager = new Lang.Class({
this.addKeybinding('open-application-menu',
new Gio.Settings({ schema: SHELL_KEYBINDINGS_SCHEMA }),
Meta.KeyBindingFlags.NONE,
Shell.KeyBindingMode.NORMAL,
Lang.bind(this, this._openAppMenu));
Shell.KeyBindingMode.NORMAL |
Shell.KeyBindingMode.TOPBAR_POPUP,
Lang.bind(this, this._toggleAppMenu));
Main.overview.connect('showing', Lang.bind(this, function() {
for (let i = 0; i < this._dimmedWindows.length; i++)
@ -564,9 +601,9 @@ const WindowManager = new Lang.Class({
let switchData = {};
this._switchData = switchData;
switchData.inGroup = new Clutter.Group();
switchData.outGroup = new Clutter.Group();
switchData.movingWindowBin = new Clutter.Group();
switchData.inGroup = new Clutter.Actor();
switchData.outGroup = new Clutter.Actor();
switchData.movingWindowBin = new Clutter.Actor();
switchData.windows = [];
let wgroup = global.window_group;
@ -593,7 +630,7 @@ const WindowManager = new Lang.Class({
switchData.windows.push({ window: window,
parent: window.get_parent() });
window.reparent(switchData.inGroup);
window.show_all();
window.show();
}
}
@ -679,8 +716,8 @@ const WindowManager = new Lang.Class({
Main.ctrlAltTabManager.popup(backwards, binding.get_name(), binding.get_mask());
},
_openAppMenu : function(display, screen, window, event, binding) {
Main.panel.openAppMenu();
_toggleAppMenu : function(display, screen, window, event, binding) {
Main.panel.toggleAppMenu();
},
_showWorkspaceSwitcher : function(display, screen, window, binding) {

View File

@ -68,15 +68,15 @@ const WindowClone = new Lang.Class({
// The MetaShapedTexture that we clone has a size that includes
// the invisible border; this is inconvenient; rather than trying
// to compensate all over the place we insert a ClutterGroup into
// to compensate all over the place we insert a ClutterActor into
// the hierarchy that is sized to only the visible portion.
this.actor = new Clutter.Group({ reactive: true,
this.actor = new Clutter.Actor({ reactive: true,
x: this.origX,
y: this.origY,
width: outerRect.width,
height: outerRect.height });
this.actor.add_actor(this._windowClone);
this.actor.add_child(this._windowClone);
this.actor._delegate = this;
@ -121,15 +121,33 @@ const WindowClone = new Lang.Class({
return this._slot;
},
// Find the actor just below us, respecting reparenting done
// by DND code
getActualStackAbove: function() {
if (this._stackAbove == null)
return null;
if (this.inDrag || this._zooming) {
if (this._stackAbove._delegate)
return this._stackAbove._delegate.getActualStackAbove();
else
return null;
} else {
return this._stackAbove;
}
},
setStackAbove: function (actor) {
this._stackAbove = actor;
if (this.inDrag)
// We'll fix up the stack after the drag
return;
if (this._stackAbove == null)
let actualAbove = this.getActualStackAbove();
if (actualAbove == null)
this.actor.lower_bottom();
else
this.actor.raise(this._stackAbove);
this.actor.raise(actualAbove);
},
destroy: function () {
@ -561,6 +579,80 @@ const WindowPositionFlags = {
ANIMATE: 1 << 1
};
// Window Thumbnail Layout Algorithm
// =================================
//
// General overview
// ----------------
//
// The window thumbnail layout algorithm calculates some optimal layout
// by computing layouts with some number of rows, calculating how good
// each layout is, and stopping iterating when it finds one that is worse
// than the previous layout. A layout consists of which windows are in
// which rows, row sizes and other general state tracking that would make
// calculating window positions from this information fairly easy.
//
// We don't compute some global order of windows right now for optimal
// travel when animating into the overview; windows are assumed to be
// in some stable order.
//
// After a layout is computed that's considered the best layout, we
// compute the layout scale to fit it in the area, and then compute
// slots (sizes and positions) for each thumbnail.
//
// Layout generation
// -----------------
//
// Layout generation is naive and simple: we simply add windows to a row
// until we've added too many windows to a row, and then make a new row,
// until we have our required N rows. The potential issue with this strategy
// is that we may have too many windows at the bottom in some pathological
// cases, which tends to make the thumbnails have the shape of a pile of
// sand with a peak, with one window at the top.
//
// Scaling factors
// ---------------
//
// Thumbnail position is mostly straightforward -- the main issue is
// computing an optimal scale for each window that fits the constraints,
// and doesn't make the thumbnail too small to see. There are two factors
// involved in thumbnail scale to make sure that these two goals are met:
// the window scale (calculated by _computeWindowScale) and the layout
// scale (calculated by computeSizeAndScale).
//
// The calculation logic becomes slightly more complicated because row
// and column spacing are not scaled, they're constant, so we can't
// simply generate a bunch of window positions and then scale it. In
// practice, it's not too bad -- we can simply try to fit the layout
// in the input area minus whatever spacing we have, and then add
// it back afterwards.
//
// The window scale is constant for the window's size regardless of the
// input area or the layout scale or rows or anything else, and right
// now just enlarges the window if it's too small. The fact that this
// factor is stable makes it easy to calculate, so there's no sense
// in not applying it in most calculations.
//
// The layout scale depends on the input area, the rows, etc, but is the
// same for the entire layout, rather than being per-window. After
// generating the rows of windows, we basically do some basic math to
// fit the full, unscaled layout to the input area, as described above.
//
// With these two factors combined, the final scale of each thumbnail is
// simply windowScale * layoutScale... almost.
//
// There's one additional constraint: the thumbnail scale must never be
// larger than WINDOW_CLONE_MAXIMUM_SCALE, which means that the inequality:
//
// windowScale * layoutScale <= WINDOW_CLONE_MAXIMUM_SCALE
//
// must always be true. This is for each individual window -- while we
// could adjust layoutScale to make the largest thumbnail smaller than
// WINDOW_CLONE_MAXIMUM_SCALE, it would shrink windows which are already
// under the inequality. To solve this, we simply cheat: we simply keep
// each window's "cell" area to be the same, but we shrink the thumbnail
// and center it horizontally, and align it to the bottom vertically.
const LayoutStrategy = new Lang.Class({
Name: 'LayoutStrategy',
Abstract: true,
@ -583,19 +675,15 @@ const LayoutStrategy = new Lang.Class({
// meant to be scaled
//
// * neither height/fullHeight have any sort of spacing or padding
//
// * if cellWidth is present, all windows in the row will occupy
// the space of cellWidth, centered.
return { x: 0, y: 0,
width: 0, height: 0,
fullWidth: 0, fullHeight: 0,
cellWidth: 0,
windows: [] };
},
// Computes and returns a fancy scale for @window using the
// base scale, @scale.
_computeWindowScale: function(window, scale) {
// Computes and returns an individual scaling factor for @window,
// to be applied in addition to the overal layout scale.
_computeWindowScale: function(window) {
// Since we align windows next to each other, the height of the
// thumbnails is much more important to preserve than the width of
// them, so two windows with equal height, but maybe differering
@ -608,14 +696,13 @@ const LayoutStrategy = new Lang.Class({
// good. We'll use a multiplier of 1.5 for this.
// Map from [0, 1] to [1.5, 1]
let fancyScale = _interpolate(1.5, 1, ratio) * scale;
return fancyScale;
return _interpolate(1.5, 1, ratio);
},
// Compute the size of each row, by assigning to the properties
// row.width, row.height, row.fullWidth, row.fullHeight, and
// (optionally) row.cellWidth, for each row in @layout.rows.
// This method is intended to be called by subclasses.
// (optionally) for each row in @layout.rows. This method is
// intended to be called by subclasses.
_computeRowSizes: function(layout) {
throw new Error('_computeRowSizes not implemented');
},
@ -676,7 +763,7 @@ const LayoutStrategy = new Lang.Class({
computeWindowSlots: function(layout, area) {
this._computeRowSizes(layout);
let { rows: rows, scale: scale, state: state } = layout;
let { rows: rows, scale: scale } = layout;
let slots = [];
@ -697,24 +784,22 @@ const LayoutStrategy = new Lang.Class({
for (let i = 0; i < rows.length; i++) {
let row = rows[i];
row.y += baseY;
let baseX = row.x;
let x = row.x;
for (let j = 0; j < row.windows.length; j++) {
let window = row.windows[j];
let s = this._computeWindowScale(window, scale);
let s = scale * this._computeWindowScale(window);
let cellWidth = window.actor.width * s;
let cellHeight = window.actor.height * s;
s = Math.min(s, WINDOW_CLONE_MAXIMUM_SCALE);
let width = window.actor.width * s;
let height = window.actor.height * s;
let y = row.y + row.height - height;
let cloneWidth = window.actor.width * s;
let x = baseX;
if (row.cellWidth) {
x += (row.cellWidth - width) / 2;
width = row.cellWidth;
}
let cloneX = x + (cellWidth - cloneWidth) / 2;
let cloneY = row.y + row.height - cellHeight;
slots.push([x, y, s, window]);
baseX += width + this._columnSpacing;
slots.push([cloneX, cloneY, s, window]);
x += cellWidth + this._columnSpacing;
}
}
return slots;
@ -753,7 +838,9 @@ const UnalignedLayoutStrategy = new Lang.Class({
let rows = [];
let totalWidth = 0;
for (let i = 0; i < windows.length; i++) {
totalWidth += windows[i].actor.width;
let window = windows[i];
let s = this._computeWindowScale(window);
totalWidth += window.actor.width * s;
}
let idealRowWidth = totalWidth / numRows;
@ -765,7 +852,7 @@ const UnalignedLayoutStrategy = new Lang.Class({
for (; windowIdx < windows.length; windowIdx++) {
let window = windows[windowIdx];
let s = this._computeWindowScale(window, 1);
let s = this._computeWindowScale(window);
let width = window.actor.width * s;
let height = window.actor.height * s;
row.fullHeight = Math.max(row.fullHeight, height);
@ -814,7 +901,7 @@ const Workspace = new Lang.Class({
this.monitorIndex = monitorIndex;
this._monitor = Main.layoutManager.monitors[this.monitorIndex];
this._windowOverlaysGroup = new Clutter.Group();
this._windowOverlaysGroup = new Clutter.Actor();
// Without this the drop area will be overlapped.
this._windowOverlaysGroup.set_size(0, 0);
@ -839,7 +926,7 @@ const Workspace = new Lang.Class({
this._windowOverlays = [];
for (let i = 0; i < windows.length; i++) {
if (this._isOverviewWindow(windows[i])) {
this._addWindowClone(windows[i]);
this._addWindowClone(windows[i], true);
}
}
@ -964,11 +1051,23 @@ const Workspace = new Lang.Class({
if (clone.inDrag)
continue;
clone.slot = [x, y, clone.actor.width * scale, clone.actor.height * scale];
let cloneWidth = clone.actor.width * scale;
let cloneHeight = clone.actor.height * scale;
clone.slot = [x, y, cloneWidth, cloneHeight];
if (overlay && initialPositioning)
if (overlay && (initialPositioning || !clone.positioned))
overlay.hide();
if (!clone.positioned) {
// This window appeared after the overview was already up
// Grow the clone from the center of the slot
clone.actor.x = x + cloneWidth / 2;
clone.actor.y = y + cloneHeight / 2;
clone.actor.scale_x = 0;
clone.actor.scale_y = 0;
clone.positioned = true;
}
if (animate && isOnCurrentWorkspace) {
if (!metaWindow.showing_on_its_workspace()) {
/* Hidden windows should fade in and grow
@ -1154,7 +1253,7 @@ const Workspace = new Lang.Class({
if (!this._isMyWindow(win) || !this._isOverviewWindow(win))
return;
let [clone, overlay] = this._addWindowClone(win);
let [clone, overlay] = this._addWindowClone(win, false);
if (win._overviewHint) {
let x = win._overviewHint.x - this.actor.x;
@ -1163,16 +1262,10 @@ const Workspace = new Lang.Class({
delete win._overviewHint;
clone.slot = [x, y, clone.actor.width * scale, clone.actor.height * scale];
clone.positioned = true;
clone.actor.set_position (x, y);
clone.actor.set_scale (scale, scale);
clone.overlay.relayout(false);
} else {
// Position new windows at the top corner of the workspace rather
// than where they were placed for real to avoid the window
// being clipped to the workspaceView. Its not really more
// natural for the window to suddenly appear in the overview
// on some seemingly random location anyway.
clone.actor.set_position (this._x, this._y);
}
this._currentLayout = null;
@ -1319,10 +1412,11 @@ const Workspace = new Lang.Class({
},
// Create a clone of a (non-desktop) window and add it to the window list
_addWindowClone : function(win) {
_addWindowClone : function(win, positioned) {
let clone = new WindowClone(win, this);
let overlay = new WindowOverlay(clone, this._windowOverlaysGroup);
clone.overlay = overlay;
clone.positioned = positioned;
clone.connect('selected',
Lang.bind(this, this._onCloneSelected));
@ -1349,6 +1443,11 @@ const Workspace = new Lang.Class({
overlay.connect('show-close-button', Lang.bind(this, this._onShowOverlayClose));
if (this._windows.length == 0)
clone.setStackAbove(null);
else
clone.setStackAbove(this._windows[this._windows.length - 1].actor);
this._windows.push(clone);
this._windowOverlays.push(overlay);

View File

@ -62,12 +62,35 @@ const WindowClone = new Lang.Class({
this.inDrag = false;
},
// Find the actor just below us, respecting reparenting done
// by DND code
getActualStackAbove: function() {
if (this._stackAbove == null)
return null;
if (this.inDrag) {
if (this._stackAbove._delegate)
return this._stackAbove._delegate.getActualStackAbove();
else
return null;
} else {
return this._stackAbove;
}
},
setStackAbove: function (actor) {
this._stackAbove = actor;
if (this._stackAbove == null)
// Don't apply the new stacking now, it will be applied
// when dragging ends and window are stacked again
if (actor.inDrag)
return;
let actualAbove = this.getActualStackAbove();
if (actualAbove == null)
this.actor.lower_bottom();
else
this.actor.raise(this._stackAbove);
this.actor.raise(actualAbove);
},
destroy: function () {
@ -166,8 +189,8 @@ const WorkspaceThumbnail = new Lang.Class({
style_class: 'workspace-thumbnail' });
this.actor._delegate = this;
this._contents = new Clutter.Group();
this.actor.add_actor(this._contents);
this._contents = new Clutter.Actor();
this.actor.add_child(this._contents);
this.actor.connect('destroy', Lang.bind(this, this._onDestroy));
@ -361,9 +384,8 @@ const WorkspaceThumbnail = new Lang.Class({
},
destroy : function() {
this.actor.destroy();
this._bgManager.destroy();
this._bgManager = null;
if (this.actor)
this.actor.destroy();
},
workspaceRemoved : function() {
@ -384,6 +406,11 @@ const WorkspaceThumbnail = new Lang.Class({
_onDestroy: function(actor) {
this.workspaceRemoved();
if (this._bgManager) {
this._bgManager.destroy();
this._bgManager = null;
}
this._windows = [];
this.actor = null;
},
@ -535,6 +562,7 @@ const ThumbnailsBox = new Lang.Class({
this._dropPlaceholderPos = -1;
this._dropPlaceholder = new St.Bin({ style_class: 'placeholder' });
this.actor.add_actor(this._dropPlaceholder);
this._spliceIndex = -1;
this._targetScale = 0;
this._scale = 0;
@ -551,7 +579,6 @@ const ThumbnailsBox = new Lang.Class({
this.actor.connect('button-press-event', function() { return true; });
this.actor.connect('button-release-event', Lang.bind(this, this._onButtonRelease));
this.actor.connect('scroll-event', Lang.bind(this, this._onScrollEvent));
Main.overview.connect('showing',
Lang.bind(this, this._createThumbnails));
@ -590,7 +617,7 @@ const ThumbnailsBox = new Lang.Class({
let thumbnail = this._thumbnails[i]
let [w, h] = thumbnail.actor.get_transformed_size();
if (y >= thumbnail.actor.y && y <= thumbnail.actor.y + h) {
thumbnail.activate(event.time);
thumbnail.activate(event.get_time());
break;
}
}
@ -718,6 +745,8 @@ const ThumbnailsBox = new Lang.Class({
return win.get_workspace() >= newWorkspaceIndex;
});
this._spliceIndex = newWorkspaceIndex;
// ... move them down one.
windows.forEach(function(win) {
win.meta_window.change_workspace_by_index(win.get_workspace() + 1,
@ -739,6 +768,14 @@ const ThumbnailsBox = new Lang.Class({
WORKSPACE_KEEP_ALIVE_TIME);
}
// Start the animation on the workspace (which is actually
// an old one which just became empty)
let thumbnail = this._thumbnails[newWorkspaceIndex];
this._setThumbnailState(thumbnail, ThumbnailState.NEW);
thumbnail.slidePosition = 1;
this._queueUpdateStates();
return true;
} else {
return false;
@ -826,7 +863,8 @@ const ThumbnailsBox = new Lang.Class({
this._thumbnails.push(thumbnail);
this.actor.add_actor(thumbnail.actor);
if (start > 0) { // not the initial fill
if (start > 0 && this._spliceIndex == -1) {
// not the initial fill, and not splicing via DND
thumbnail.state = ThumbnailState.NEW;
thumbnail.slidePosition = 1; // start slid out
this._haveNewThumbnails = true;
@ -841,6 +879,9 @@ const ThumbnailsBox = new Lang.Class({
// The thumbnails indicator actually needs to be on top of the thumbnails
this._indicator.raise_top();
// Clear the splice index, we got the message
this._spliceIndex = -1;
},
removeThumbnails: function(start, count) {
@ -1215,16 +1256,5 @@ const ThumbnailsBox = new Lang.Class({
},
onCompleteScope: this
});
},
_onScrollEvent: function (actor, event) {
switch (event.get_scroll_direction()) {
case Clutter.ScrollDirection.UP:
Main.wm.actionMoveWorkspace(Meta.MotionDirection.UP);
break;
case Clutter.ScrollDirection.DOWN:
Main.wm.actionMoveWorkspace(Meta.MotionDirection.DOWN);
break;
}
}
});

View File

@ -386,6 +386,15 @@ const WorkspacesView = new Lang.Class({
let current = Math.round(adj.value);
if (active != current) {
if (!this._workspaces[current]) {
// The current workspace was destroyed. This could happen
// when you are on the last empty workspace, and consolidate
// windows using the thumbnail bar.
// In that case, the intended behavior is to stay on the empty
// workspace, which is the last one, so pick it.
current = this._workspaces.length - 1;
}
let metaWorkspace = this._workspaces[current].metaWorkspace;
metaWorkspace.activate(global.get_current_time());
}

View File

@ -21,14 +21,7 @@ const XdndHandler = new Lang.Class({
Shell.util_set_hidden_from_pick(this._dummy, true);
this._dummy.hide();
// Mutter delays the creation of the output window as long
// as possible to avoid flicker. In case a plugin wants to
// access it directly it has to connect to the stage's show
// signal. (see comment in compositor.c:meta_compositor_manage_screen)
global.stage.connect('show', function () {
global.init_xdnd();
return false;
});
global.init_xdnd();
global.connect('xdnd-enter', Lang.bind(this, this._onEnter));
global.connect('xdnd-position-changed', Lang.bind(this, this._onPositionChanged));
@ -75,7 +68,7 @@ const XdndHandler = new Lang.Class({
source: cursorWindow});
this._cursorWindowClone = new Clutter.Clone({ source: cursorWindow });
global.overlay_group.add_actor(this._cursorWindowClone);
Main.uiGroup.add_actor(this._cursorWindowClone);
Shell.util_set_hidden_from_pick(this._cursorWindowClone, true);
// Make sure that the clone has the same position as the source
@ -89,7 +82,7 @@ const XdndHandler = new Lang.Class({
},
_onPositionChanged: function(obj, x, y) {
let pickedActor = global.stage.get_actor_at_pos(Clutter.PickMode.ALL, x, y);
let pickedActor = global.stage.get_actor_at_pos(Clutter.PickMode.REACTIVE, x, y);
// Make sure that the cursor window is on top
if (this._cursorWindowClone)

View File

@ -125,6 +125,12 @@
<listitem><para>List possible modes and exit</para></listitem>
</varlistentry>
<varlistentry>
<term><option>--clutter-display=<replaceable>DISPLAY</replaceable></option></term>
<listitem><para>Clutter the option display (otherwise ignored)</para></listitem>
</varlistentry>
</variablelist>
</refsect1>

View File

@ -28,6 +28,7 @@ gu
he
hi
hu
ia
id
it
ja
@ -60,6 +61,7 @@ sr@latin
sv
ta
te
tg
th
tr
ug

View File

@ -1,3 +1,6 @@
# List of source files containing translatable strings.
# Please keep this file sorted alphabetically.
[encoding: UTF-8]
data/50-gnome-shell-screenshot.xml.in
data/50-gnome-shell-system.xml.in
data/gnome-shell.desktop.in.in
@ -30,6 +33,7 @@ js/ui/lookingGlass.js
js/ui/main.js
js/ui/messageTray.js
js/ui/notificationDaemon.js
js/ui/overviewControls.js
js/ui/overview.js
js/ui/panel.js
js/ui/popupMenu.js
@ -51,6 +55,7 @@ js/ui/viewSelector.js
js/ui/wanda.js
js/ui/windowAttentionHandler.js
src/calendar-server/evolution-calendar.desktop.in.in
# Please do not remove this file from POTFILES.in. Run "git submodule init && git submodule update" to get it.
src/gvc/gvc-mixer-control.c
src/main.c
src/shell-app.c

2226
po/an.po

File diff suppressed because it is too large Load Diff

895
po/ar.po

File diff suppressed because it is too large Load Diff

829
po/as.po

File diff suppressed because it is too large Load Diff

826
po/be.po

File diff suppressed because it is too large Load Diff

647
po/ca.po

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

1030
po/cs.po

File diff suppressed because it is too large Load Diff

1091
po/da.po

File diff suppressed because it is too large Load Diff

903
po/de.po

File diff suppressed because it is too large Load Diff

1139
po/el.po

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

590
po/es.po

File diff suppressed because it is too large Load Diff

275
po/et.po
View File

@ -13,8 +13,8 @@ msgstr ""
"Project-Id-Version: gnome-shell MASTER\n"
"Report-Msgid-Bugs-To: http://bugzilla.gnome.org/enter_bug.cgi?product=gnome-"
"shell&keywords=I18N+L10N&component=general\n"
"POT-Creation-Date: 2012-12-09 13:03+0000\n"
"PO-Revision-Date: 2012-12-19 16:47+0300\n"
"POT-Creation-Date: 2013-03-11 22:02+0000\n"
"PO-Revision-Date: 2013-03-12 16:28+0300\n"
"Last-Translator: Mattias Põldaru <mahfiaz@gmail.com>\n"
"Language-Team: Estonian <>\n"
"Language: et\n"
@ -104,6 +104,16 @@ msgid ""
"favorites area."
msgstr "Nendele tunnustele vastavaid rakendusi kuvatakse lemmikutes."
msgid "List of categories that should be displayed as folders"
msgstr "Kategooriad, mida tuleb kuvada kaustadena"
msgid ""
"Each category name in this list will be represented as folder in the "
"application view, rather than being displayed inline in the main view."
msgstr ""
"Kõiki selles loetelus olevaid kategooriaid kuvatakse rakenduste vaates "
"kaustadena, mitte peavaates teistega koos."
msgid "History for command (Alt-F2) dialog"
msgstr "Käsudialoogi (Alt-F2) ajalugu"
@ -135,12 +145,6 @@ msgstr ""
"See võti keelab automaatse 'Logi välja' menüükirje peitmise, kui arvutis on "
"üks kasutaja ning avatud üks seanss."
msgid "Show full name in the user menu"
msgstr "Kasutajamenüüs näidatakse kasutaja tervet nime"
msgid "Whether the users full name is shown in the user menu or not."
msgstr "Kas kasutajamenüüs näidatakse kasutaja kogu nime või mitte."
msgid ""
"Whether to remember password for mounting encrypted or remote filesystems"
msgstr ""
@ -299,12 +303,8 @@ msgstr "Laiendus"
msgid "Select an extension to configure using the combobox above."
msgstr "Vali seadistatav laiendus kasutades ülemist valikukasti."
msgid "Session..."
msgstr "Seanss..."
msgctxt "title"
msgid "Sign In"
msgstr "Sisselogimine"
msgid "Session"
msgstr "Seanss"
#. translators: this message is shown below the user list on the
#. login screen. It can be activated to reveal an entry for
@ -368,16 +368,12 @@ msgstr "Käsku pole võimalik analüüsida:"
msgid "Execution of '%s' failed:"
msgstr "'%s' käivitamine nurjus:"
#. Translators: Filter to display all applications
msgid "Frequent"
msgstr "Sage"
msgid "All"
msgstr "Kõik"
msgid "APPLICATIONS"
msgstr "RAKENDUSED"
msgid "SETTINGS"
msgstr "SEADED"
msgid "New Window"
msgstr "Uus aken"
@ -395,6 +391,12 @@ msgstr "%s lisati lemmikutesse."
msgid "%s has been removed from your favorites."
msgstr "%s eemaldati lemmikutest."
msgid "Settings"
msgstr "Sätted"
msgid "Change Background…"
msgstr "Muuda tausta…"
#. Translators: Shown in calendar event list for all day events
#. * Keep it short, best if you can use less then 10 characters
#.
@ -402,15 +404,18 @@ msgctxt "event list time"
msgid "All Day"
msgstr "Kogu päev"
#. Translators: Shown in calendar event list, if 24h format
#. Translators: Shown in calendar event list, if 24h format,
#. \u2236 is a ratio character, similar to :
msgctxt "event list time"
msgid "%H:%M"
msgstr "%H:%M"
msgid "%H\\u2236%M"
msgstr "%H\\u2236%M"
#. Transators: Shown in calendar event list, if 12h format
#. Transators: Shown in calendar event list, if 12h format,
#. \u2236 is a ratio character, similar to : and \u2009 is
#. a thin space
msgctxt "event list time"
msgid "%l:%M %p"
msgstr "%l:%M %p"
msgid "%l\\u2236%M\\u2009%p"
msgstr "%l\\u2236%M\\u2009%p"
#. Translators: Calendar grid abbreviation for Sunday.
#. *
@ -517,6 +522,12 @@ msgstr "Käesolev nädal"
msgid "Next week"
msgstr "Järgmine nädal"
msgid "External drive connected"
msgstr "Väline ketas ühendati"
msgid "External drive disconnected"
msgstr "Väline ketas eemaldati"
msgid "Removable Devices"
msgstr "Eemaldatavad seadmed"
@ -801,12 +812,20 @@ msgstr "Aknad"
msgid "Show Applications"
msgstr "Rakenduste kuvamine"
msgid "Date and Time Settings"
msgstr "Kuupäeva ja kellaaja sätted"
#. Translators: this is the name of the dock/favorites area on
#. the left of the overview
msgid "Dash"
msgstr "Dokk"
msgid "Open Calendar"
msgstr "Ava kalender"
msgid "Open Clocks"
msgstr "Ava kell"
msgid "Date & Time Settings"
msgstr "Kuupäeva ja kella sätted"
#. Translators: This is the date format to use when the calendar popup is
#. * shown - it is shown just below the time in the shell (e.g. "Tue 9:29 AM").
#.
@ -897,9 +916,6 @@ msgstr "Paigalda"
msgid "Download and install '%s' from extensions.gnome.org?"
msgstr "Kas laadida alla ja paigaldada '%s' aadressilt extensions.gnome.org?"
msgid "tray"
msgstr "salv"
msgid "Keyboard"
msgstr "Klaviatuur"
@ -920,6 +936,8 @@ msgstr "Näita vigu"
msgid "Enabled"
msgstr "Lubatud"
#. translators:
#. * The device has been disabled
msgid "Disabled"
msgstr "Keelatud"
@ -944,6 +962,12 @@ msgstr "Ava"
msgid "Remove"
msgstr "Eemalda"
msgid "Clear Messages"
msgstr "Kustuta teated"
msgid "Notification Settings"
msgstr "Märguannete sätted"
msgid "No Messages"
msgstr "Teateid pole"
@ -957,6 +981,12 @@ msgctxt "program"
msgid "Unknown"
msgstr "Tundmatu"
#, c-format
msgid "%d new message"
msgid_plural "%d new messages"
msgstr[0] "%d uus sõnum"
msgstr[1] "%d uut sõnumit"
msgid "Undo"
msgstr "Võta tagasi"
@ -967,13 +997,8 @@ msgstr "Ülevaade"
#. in the search entry when no search is
#. active; it should not exceed ~30
#. characters.
msgid "Type to search..."
msgstr "Otsing..."
#. Translators: this is the name of the dock/favorites area on
#. the left of the overview
msgid "Dash"
msgstr "Dokk"
msgid "Type to search"
msgstr "Otsing"
msgid "Quit"
msgstr "Sulge"
@ -1005,12 +1030,6 @@ msgstr "Sulge"
msgid "%A, %B %d"
msgstr "%A, %d. %B"
#, c-format
msgid "%d new message"
msgid_plural "%d new messages"
msgstr[0] "%d uus sõnum"
msgstr[1] "%d uut sõnumit"
#, c-format
msgid "%d new notification"
msgid_plural "%d new notifications"
@ -1020,8 +1039,24 @@ msgstr[1] "%d uut märguannet"
msgid "Lock"
msgstr "Lukusta"
msgid "Searching..."
msgstr "Otsimine..."
msgid "GNOME needs to lock the screen"
msgstr "GNOME peab ekraani lukustama"
#. We could not become modal, so we can't activate the
#. screenshield. The user is probably very upset at this
#. point, but any application using global grabs is broken
#. Just tell him to stop using this app
#.
#. XXX: another option is to kick the user into the gdm login
#. screen, where we're not affected by grabs
msgid "Unable to lock"
msgstr "Pole võimalik lukustada"
msgid "Lock was blocked by an application"
msgstr "Rakendus blokeeris lukustamise"
msgid "Searching…"
msgstr "Otsing…"
msgid "No results."
msgstr "Tulemused puuduvad."
@ -1089,11 +1124,11 @@ msgstr "Bluetooth"
msgid "Visibility"
msgstr "Nähtavus"
msgid "Send Files to Device..."
msgstr "Failide saatmine seadmesse..."
msgid "Send Files to Device"
msgstr "Failide saatmine seadmesse"
msgid "Set up a New Device..."
msgstr "Uue seadme häälestamine..."
msgid "Set Up a New Device"
msgstr "Uue seadme häälestamine"
msgid "Bluetooth Settings"
msgstr "Bluetoothi sätted"
@ -1111,8 +1146,8 @@ msgstr "ühenduse katkestamine..."
msgid "connecting..."
msgstr "ühendumine..."
msgid "Send Files..."
msgstr "Failide saatmine..."
msgid "Send Files"
msgstr "Failide saatmine"
msgid "Keyboard Settings"
msgstr "Klaviatuurisätted"
@ -1173,7 +1208,7 @@ msgstr "Olgu"
msgid "Show Keyboard Layout"
msgstr "Klaviatuuripaigutuse kuvamine"
msgid "Region and Language Settings"
msgid "Region & Language Settings"
msgstr "Asukoha ja keele sätted"
msgid "Volume, network, battery"
@ -1212,17 +1247,23 @@ msgstr "pole saadaval"
msgid "connection failed"
msgstr "ühendumine nurjus"
msgid "More..."
msgstr "Veel..."
msgid "More"
msgstr "Veel"
#. TRANSLATORS: this is the indication that a connection for another logged in user is active,
#. and we cannot access its settings (including the name)
msgid "Connected (private)"
msgstr "Ühendatud (privaatne)"
msgid "Wired"
msgstr "Juhtmega"
msgid "Auto Ethernet"
msgstr "Automaatne ethernet"
msgid "Mobile broadband"
msgstr "Mobiiliühendus"
msgid "Auto broadband"
msgstr "Automaatne lairibaühendus"
@ -1269,8 +1310,8 @@ msgstr "Toitesätted..."
#. 0 is reported when UPower does not have enough data
#. to estimate battery life
msgid "Estimating..."
msgstr "Andmete kogumine..."
msgid "Estimating"
msgstr "Andmete kogumine"
#, c-format
msgid "%d hour remaining"
@ -1304,10 +1345,10 @@ msgctxt "percent of battery remaining"
msgid "%d%%"
msgstr "%d%%"
msgid "AC adapter"
msgstr "Võrgutoite adapter"
msgid "AC Adapter"
msgstr "Laadija"
msgid "Laptop battery"
msgid "Laptop Battery"
msgstr "Sülearvuti aku"
msgid "UPS"
@ -1322,10 +1363,10 @@ msgstr "Hiir"
msgid "PDA"
msgstr "Elektronmärkmik"
msgid "Cell phone"
msgid "Cell Phone"
msgstr "Mobiiltelefon"
msgid "Media player"
msgid "Media Player"
msgstr "Meediaesitaja"
msgid "Tablet"
@ -1338,6 +1379,9 @@ msgctxt "device"
msgid "Unknown"
msgstr "Tundmatu"
msgid "Volume changed"
msgstr "Helivaljus muutus"
#. Translators: This is the label for audio volume
msgid "Volume"
msgstr "Helivaljus"
@ -1372,9 +1416,6 @@ msgstr "Ühendamata"
msgid "Notifications"
msgstr "Märguanded"
msgid "Settings"
msgstr "Sätted"
msgid "Switch User"
msgstr "Vaheta kasutajat"
@ -1394,6 +1435,22 @@ msgstr ""
"Märguanded on nüüd keelatud, sealhulgas vestlusteated. Sinu netiolekut "
"muudeti, et teised teaksid, et sa ei pruugi nende teateid näha."
msgid "Other users are logged in."
msgstr "Teised kasutajad on sisse logitud."
msgid "Shutting down might cause them to lose unsaved work."
msgstr "Väljalülitamine võib põhjustada salvestamata töö kaotsimineku."
#. Translators: Remote here refers to a remote session, like a ssh login
#, c-format
msgid "%s (remote)"
msgstr "%s (kaugühendus)"
#. Translators: Console here refers to a tty like a VT console
#, c-format
msgid "%s (console)"
msgstr "%s (konsool)"
msgid "Applications"
msgstr "Rakendused"
@ -1412,9 +1469,6 @@ msgstr ""
msgid "%s the Oracle says"
msgstr "Oraakel %s ütleb"
msgid "Your favorite Easter Egg"
msgstr "Sinu lemmiküllatusmuna"
#, c-format
msgid "'%s' is ready"
msgstr "'%s' on valmis"
@ -1422,6 +1476,25 @@ msgstr "'%s' on valmis"
msgid "Evolution Calendar"
msgstr "Evolutioni kalender"
#. translators:
#. * The number of sound outputs on a particular device
#, c-format
msgid "%u Output"
msgid_plural "%u Outputs"
msgstr[0] "%u väljund"
msgstr[1] "%u väljundit"
#. translators:
#. * The number of sound inputs on a particular device
#, c-format
msgid "%u Input"
msgid_plural "%u Inputs"
msgstr[0] "%u sisend"
msgstr[1] "%u sisendit"
msgid "System Sounds"
msgstr "Süsteemi helid"
msgid "Print version"
msgstr "Printimise versioon"
@ -1444,15 +1517,48 @@ msgstr "Paroolid ei kattu."
msgid "Password cannot be blank"
msgstr "Parool ei saa olla tühi"
msgid "United Kingdom"
msgstr "Suurbritannia"
msgid "Default"
msgstr "Vaikimisi"
msgid "Authentication dialog was dismissed by the user"
msgstr "Kasutaja katkestas autentimisdialoogi"
#~ msgid "Show full name in the user menu"
#~ msgstr "Kasutajamenüüs näidatakse kasutaja tervet nime"
#~ msgid "Whether the users full name is shown in the user menu or not."
#~ msgstr "Kas kasutajamenüüs näidatakse kasutaja kogu nime või mitte."
#~ msgctxt "title"
#~ msgid "Sign In"
#~ msgstr "Sisselogimine"
#~ msgid "APPLICATIONS"
#~ msgstr "RAKENDUSED"
#~ msgid "SETTINGS"
#~ msgstr "SEADED"
#~ msgctxt "event list time"
#~ msgid "%H:%M"
#~ msgstr "%H:%M"
#~ msgctxt "event list time"
#~ msgid "%l:%M %p"
#~ msgstr "%l:%M %p"
#~ msgid "tray"
#~ msgstr "salv"
#~ msgid "More..."
#~ msgstr "Veel..."
#~ msgid "Your favorite Easter Egg"
#~ msgstr "Sinu lemmiküllatusmuna"
#~ msgid "United Kingdom"
#~ msgstr "Suurbritannia"
#~ msgid "Default"
#~ msgstr "Vaikimisi"
#~ msgid "Subscription request"
#~ msgstr "Tellimuse päring"
@ -1471,28 +1577,9 @@ msgstr "Kasutaja katkestas autentimisdialoogi"
#~ msgid "Reconnect"
#~ msgstr "Ühendu uuesti"
#~ msgid "Wired"
#~ msgstr "Juhtmega"
#~ msgid "Wireless"
#~ msgstr "Juhtmeta"
#~ msgid "Mobile broadband"
#~ msgstr "Mobiiliühendus"
#~ msgid "%u Output"
#~ msgid_plural "%u Outputs"
#~ msgstr[0] "%u väljund"
#~ msgstr[1] "%u väljundit"
#~ msgid "%u Input"
#~ msgid_plural "%u Inputs"
#~ msgstr[0] "%u sisend"
#~ msgstr[1] "%u sisendit"
#~ msgid "System Sounds"
#~ msgstr "Süsteemi helid"
#~ msgid "disabled OpenSearch providers"
#~ msgstr "keelatud OpenSearch pakkujad"

795
po/eu.po

File diff suppressed because it is too large Load Diff

1102
po/fa.po

File diff suppressed because it is too large Load Diff

1102
po/fi.po

File diff suppressed because it is too large Load Diff

1095
po/fr.po

File diff suppressed because it is too large Load Diff

580
po/gl.po

File diff suppressed because it is too large Load Diff

1182
po/gu.po

File diff suppressed because it is too large Load Diff

1125
po/hi.po

File diff suppressed because it is too large Load Diff

900
po/hu.po

File diff suppressed because it is too large Load Diff

1938
po/ia.po Normal file

File diff suppressed because it is too large Load Diff

1019
po/id.po

File diff suppressed because it is too large Load Diff

358
po/it.po
View File

@ -10,8 +10,8 @@ msgid ""
msgstr ""
"Project-Id-Version: gnome-shell 3.7.x\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2013-02-19 11:03+0100\n"
"PO-Revision-Date: 2013-02-19 11:07+0100\n"
"POT-Creation-Date: 2013-03-02 15:53+0100\n"
"PO-Revision-Date: 2013-03-02 15:54+0100\n"
"Last-Translator: Luca Ferretti <lferrett@gnome.org>\n"
"Language-Team: Italian <tp@lists.linux.it>\n"
"Language: it\n"
@ -58,7 +58,7 @@ msgid "Window management and application launching"
msgstr "Gestisce finestre e avvia applicazioni"
#: ../data/gnome-shell-extension-prefs.desktop.in.in.h:1
#: ../js/extensionPrefs/main.js:152
#: ../js/extensionPrefs/main.js:153
msgid "GNOME Shell Extension Preferences"
msgstr "Preferenze estensioni di GNOME Shell"
@ -128,14 +128,24 @@ msgstr ""
"visualizzate nell'area dei preferiti."
#: ../data/org.gnome.shell.gschema.xml.in.in.h:9
msgid "List of categories that should be displayed as folders"
msgstr "Elenco di categorie che dovrebbero essere mostrare come cartelle"
#: ../data/org.gnome.shell.gschema.xml.in.in.h:10
msgid ""
"Each category name in this list will be represented as folder in the "
"application view, rather than being displayed inline in the main view."
msgstr "Ciascun nome di categoria in questa lista sarà rappresentata come una cartella nella vista applicazioni, invece che essere mostrata nella vista principale"
#: ../data/org.gnome.shell.gschema.xml.in.in.h:11
msgid "History for command (Alt-F2) dialog"
msgstr "Cronologia per il dialogo dei comandi (Alt-F2)"
#: ../data/org.gnome.shell.gschema.xml.in.in.h:10
#: ../data/org.gnome.shell.gschema.xml.in.in.h:12
msgid "History for the looking glass dialog"
msgstr "Cronologia per il dialogo looking glass"
#: ../data/org.gnome.shell.gschema.xml.in.in.h:11
#: ../data/org.gnome.shell.gschema.xml.in.in.h:13
msgid ""
"Internally used to store the last IM presence explicitly set by the user. "
"The value here is from the TpConnectionPresenceType enumeration."
@ -144,7 +154,7 @@ msgstr ""
"esplicitamente dall'utente. Il valore corrisponde alla enumerazione "
"TpConnectionPresenceType."
#: ../data/org.gnome.shell.gschema.xml.in.in.h:12
#: ../data/org.gnome.shell.gschema.xml.in.in.h:14
msgid ""
"Internally used to store the last session presence status for the user. The "
"value here is from the GsmPresenceStatus enumeration."
@ -152,11 +162,11 @@ msgstr ""
"Usato internamente per memorizzare lo stato di presenza dell'ultima sessione "
"per l'utente. Il valore corrisponde alla enumerazione GsmPresenceStatus."
#: ../data/org.gnome.shell.gschema.xml.in.in.h:13
#: ../data/org.gnome.shell.gschema.xml.in.in.h:15
msgid "Always show the 'Log out' menuitem in the user menu."
msgstr "Mostra sempre l'elemento \"Termina sessione\" nel menù utente."
#: ../data/org.gnome.shell.gschema.xml.in.in.h:14
#: ../data/org.gnome.shell.gschema.xml.in.in.h:16
msgid ""
"This key overrides the automatic hiding of the 'Log out' menuitem in single-"
"user, single-session situations."
@ -164,13 +174,13 @@ msgstr ""
"Questa chiave sovrascrive lo scomparsa automatica dell'elemento \"Termina "
"sessione\" nelle modalità singolo utente, sessione singola."
#: ../data/org.gnome.shell.gschema.xml.in.in.h:15
#: ../data/org.gnome.shell.gschema.xml.in.in.h:17
msgid ""
"Whether to remember password for mounting encrypted or remote filesystems"
msgstr ""
"Indica se ricordare la password per montare file system remoti o cifrati"
#: ../data/org.gnome.shell.gschema.xml.in.in.h:16
#: ../data/org.gnome.shell.gschema.xml.in.in.h:18
msgid ""
"The shell will request a password when an encrypted device or a remote "
"filesystem is mounted. If the password can be saved for future use a "
@ -182,73 +192,73 @@ msgstr ""
"aggiunta la corrispettiva casella di selezione. Questa chiave imposta lo "
"stato predefinito di tale casella."
#: ../data/org.gnome.shell.gschema.xml.in.in.h:17
#: ../data/org.gnome.shell.gschema.xml.in.in.h:19
msgid "Show the week date in the calendar"
msgstr "Mostra il numero della settimana nel calendario"
#: ../data/org.gnome.shell.gschema.xml.in.in.h:18
#: ../data/org.gnome.shell.gschema.xml.in.in.h:20
msgid "If true, display the ISO week date in the calendar."
msgstr "Se VERO, mostra il giorno della settimana ISO nel calendario."
#: ../data/org.gnome.shell.gschema.xml.in.in.h:19
#: ../data/org.gnome.shell.gschema.xml.in.in.h:21
msgid "Keybinding to open the application menu"
msgstr "Associazione tasti per aprire menù applicazioni"
#: ../data/org.gnome.shell.gschema.xml.in.in.h:20
#: ../data/org.gnome.shell.gschema.xml.in.in.h:22
msgid "Keybinding to open the application menu."
msgstr "Associazione di tasti per aprire il menù delle applicazioni."
#: ../data/org.gnome.shell.gschema.xml.in.in.h:21
#: ../data/org.gnome.shell.gschema.xml.in.in.h:23
msgid "Keybinding to open the \"Show Applications\" view"
msgstr "Associazione tasti per aprire la vista \"Mostra applicazioni\""
#: ../data/org.gnome.shell.gschema.xml.in.in.h:22
#: ../data/org.gnome.shell.gschema.xml.in.in.h:24
msgid ""
"Keybinding to open the \"Show Applications\" view of the Activities Overview."
msgstr ""
"Associazione di tasti per aprire la vista \"Mosta applicazioni\" della "
"panoramica Attività."
#: ../data/org.gnome.shell.gschema.xml.in.in.h:23
#: ../data/org.gnome.shell.gschema.xml.in.in.h:25
msgid "Keybinding to toggle the visibility of the message tray"
msgstr "Associazione tasti per commutare la visibilità del cassetto messaggi"
#: ../data/org.gnome.shell.gschema.xml.in.in.h:24
#: ../data/org.gnome.shell.gschema.xml.in.in.h:26
msgid "Keybinding to toggle the visibility of the message tray."
msgstr ""
"Associazione di tasti per commutare la visibilità del cassetto messaggi."
#: ../data/org.gnome.shell.gschema.xml.in.in.h:25
#: ../data/org.gnome.shell.gschema.xml.in.in.h:27
msgid "Keybinding to focus the active notification"
msgstr "Associazione tasti dare il focus alla notifica attiva"
#: ../data/org.gnome.shell.gschema.xml.in.in.h:26
#: ../data/org.gnome.shell.gschema.xml.in.in.h:28
msgid "Keybinding to focus the active notification."
msgstr "Associazione di tasti per dare il focus alla notifica attiva."
#: ../data/org.gnome.shell.gschema.xml.in.in.h:27
#: ../data/org.gnome.shell.gschema.xml.in.in.h:29
msgid "Keybinding to toggle the screen recorder"
msgstr "Associazione tasti per commutare registrazione schermo"
#: ../data/org.gnome.shell.gschema.xml.in.in.h:28
#: ../data/org.gnome.shell.gschema.xml.in.in.h:30
msgid "Keybinding to start/stop the builtin screen recorder."
msgstr ""
"Associazione di tasti per avviare/fermare il registratore di schermo "
"incorporato."
#: ../data/org.gnome.shell.gschema.xml.in.in.h:29
#: ../data/org.gnome.shell.gschema.xml.in.in.h:31
msgid "Which keyboard to use"
msgstr "Quale tastiera usare"
#: ../data/org.gnome.shell.gschema.xml.in.in.h:30
#: ../data/org.gnome.shell.gschema.xml.in.in.h:32
msgid "The type of keyboard to use."
msgstr "Il tipo di tastiera da usare."
#: ../data/org.gnome.shell.gschema.xml.in.in.h:31
#: ../data/org.gnome.shell.gschema.xml.in.in.h:33
msgid "Framerate used for recording screencasts."
msgstr "Framerate per la registrazione di screencast."
#: ../data/org.gnome.shell.gschema.xml.in.in.h:32
#: ../data/org.gnome.shell.gschema.xml.in.in.h:34
msgid ""
"The framerate of the resulting screencast recordered by GNOME Shell's "
"screencast recorder in frames-per-second."
@ -256,11 +266,11 @@ msgstr ""
"Il framerate in fotogrammi al secondo dello screencast registrato attraverso "
"il registratore della GNOME Shell."
#: ../data/org.gnome.shell.gschema.xml.in.in.h:33
#: ../data/org.gnome.shell.gschema.xml.in.in.h:35
msgid "The gstreamer pipeline used to encode the screencast"
msgstr "La pipeline di gstreamer utilizzata per codificare lo screencast"
#: ../data/org.gnome.shell.gschema.xml.in.in.h:35
#: ../data/org.gnome.shell.gschema.xml.in.in.h:37
#, no-c-format
msgid ""
"Sets the GStreamer pipeline used to encode recordings. It follows the syntax "
@ -287,11 +297,11 @@ msgstr ""
"usato come un segnaposto per una stima del valore di thread ottimale per il "
"sistema in uso."
#: ../data/org.gnome.shell.gschema.xml.in.in.h:36
#: ../data/org.gnome.shell.gschema.xml.in.in.h:38
msgid "File extension used for storing the screencast"
msgstr "Estensione del file utilizzato per salvare lo screencast"
#: ../data/org.gnome.shell.gschema.xml.in.in.h:37
#: ../data/org.gnome.shell.gschema.xml.in.in.h:39
msgid ""
"The filename for recorded screencasts will be a unique filename based on the "
"current date, and use this extension. It should be changed when recording to "
@ -301,11 +311,11 @@ msgstr ""
"data corrente e utilizza questa estensione. Dovrebbe essere modificato "
"quando si registra utilizzando un diverso formato contenitore."
#: ../data/org.gnome.shell.gschema.xml.in.in.h:38
#: ../data/org.gnome.shell.gschema.xml.in.in.h:40
msgid "The application icon mode."
msgstr "La modalità dell'icona dell'applicazione."
#: ../data/org.gnome.shell.gschema.xml.in.in.h:39
#: ../data/org.gnome.shell.gschema.xml.in.in.h:41
msgid ""
"Configures how the windows are shown in the switcher. Valid possibilities "
"are 'thumbnail-only' (shows a thumbnail of the window), 'app-icon-"
@ -315,22 +325,22 @@ msgstr ""
"sono: \"thumbnail-only\" (mostra una miniatura della finestra), \"app-icon-"
"only\" (mostra solo l'icona dell'applicazione) oppure \"both\"."
#: ../data/org.gnome.shell.gschema.xml.in.in.h:40
#: ../data/org.gnome.shell.gschema.xml.in.in.h:42
msgid "Attach modal dialog to the parent window"
msgstr "Collega la finestra modale a quella genitore"
#: ../data/org.gnome.shell.gschema.xml.in.in.h:41
#: ../data/org.gnome.shell.gschema.xml.in.in.h:43
msgid ""
"This key overrides the key in org.gnome.mutter when running GNOME Shell."
msgstr ""
"Questa chiave scavalca la chiave in org.gnome.mutter quando si esegue GNOME "
"Shell."
#: ../data/org.gnome.shell.gschema.xml.in.in.h:42
#: ../data/org.gnome.shell.gschema.xml.in.in.h:44
msgid "Arrangement of buttons on the titlebar"
msgstr "Disposizione dei pulsanti nella barra del titolo"
#: ../data/org.gnome.shell.gschema.xml.in.in.h:43
#: ../data/org.gnome.shell.gschema.xml.in.in.h:45
msgid ""
"This key overrides the key in org.gnome.desktop.wm.preferences when running "
"GNOME Shell."
@ -338,76 +348,73 @@ msgstr ""
"Questa chiave scavalca la chiave in org.gnome.desktop.wm.preferences quando "
"si esegue GNOME Shell."
#: ../data/org.gnome.shell.gschema.xml.in.in.h:44
#: ../data/org.gnome.shell.gschema.xml.in.in.h:46
msgid "Enable edge tiling when dropping windows on screen edges"
msgstr "Abilita il tiling di bordo quando si trascinano le finestre sui bordi dello schermo"
msgstr ""
"Abilita il tiling di bordo quando si trascinano le finestre sui bordi dello "
"schermo"
#: ../data/org.gnome.shell.gschema.xml.in.in.h:45
#: ../data/org.gnome.shell.gschema.xml.in.in.h:47
msgid "Workspaces are managed dynamically"
msgstr "Spazi di lavoro sono gestiti dinamicamente"
#: ../data/org.gnome.shell.gschema.xml.in.in.h:46
#: ../data/org.gnome.shell.gschema.xml.in.in.h:48
msgid "Workspaces only on primary monitor"
msgstr "Spazi di lavoro solo sul monitor primario"
#: ../js/extensionPrefs/main.js:124
#: ../js/extensionPrefs/main.js:125
#, c-format
msgid "There was an error loading the preferences dialog for %s:"
msgstr ""
"Si è verificato un errore nel caricare il dialogo delle preferenze per %s:"
#: ../js/extensionPrefs/main.js:164
#: ../js/extensionPrefs/main.js:165
msgid "Extension"
msgstr "Estensione"
#: ../js/extensionPrefs/main.js:188
#: ../js/extensionPrefs/main.js:189
msgid "Select an extension to configure using the combobox above."
msgstr ""
"Selezionare una estensione da configurare usando la casella combinata qui "
"sopra."
#: ../js/gdm/loginDialog.js:569
#: ../js/gdm/loginDialog.js:405
msgid "Session…"
msgstr "Sessione…"
#: ../js/gdm/loginDialog.js:726
msgctxt "title"
msgid "Sign In"
msgstr "Accesso"
#. translators: this message is shown below the user list on the
#. login screen. It can be activated to reveal an entry for
#. manually entering the username.
#: ../js/gdm/loginDialog.js:790
#: ../js/gdm/loginDialog.js:629
msgid "Not listed?"
msgstr "Non elencato?"
#: ../js/gdm/loginDialog.js:970 ../js/ui/components/networkAgent.js:137
#: ../js/gdm/loginDialog.js:783 ../js/ui/components/networkAgent.js:137
#: ../js/ui/components/polkitAgent.js:162 ../js/ui/endSessionDialog.js:375
#: ../js/ui/extensionDownloader.js:195 ../js/ui/shellMountOperation.js:399
#: ../js/ui/status/bluetooth.js:415 ../js/ui/unlockDialog.js:178
#: ../js/ui/status/bluetooth.js:415 ../js/ui/unlockDialog.js:126
#: ../js/ui/userMenu.js:932
msgid "Cancel"
msgstr "Annulla"
#: ../js/gdm/loginDialog.js:986
#: ../js/gdm/loginDialog.js:799
msgctxt "button"
msgid "Sign In"
msgstr "Accedi"
#: ../js/gdm/loginDialog.js:986
#: ../js/gdm/loginDialog.js:799
msgid "Next"
msgstr "Avanti"
#. TTLS and PEAP are actually much more complicated, but this complication
#. is not visible here since we only care about phase2 authentication
#. (and don't even care of which one)
#: ../js/gdm/loginDialog.js:1095 ../js/ui/components/networkAgent.js:260
#: ../js/gdm/loginDialog.js:904 ../js/ui/components/networkAgent.js:260
#: ../js/ui/components/networkAgent.js:278
msgid "Username: "
msgstr "Nome utente: "
#: ../js/gdm/loginDialog.js:1391
#: ../js/gdm/loginDialog.js:1157
msgid "Login Window"
msgstr "Finestra di accesso"
@ -430,50 +437,53 @@ msgstr "Riavvia"
msgid "Power Off"
msgstr "Spegni"
#: ../js/gdm/util.js:152
#: ../js/gdm/util.js:182
msgid "Authentication error"
msgstr "Errore di autenticazione"
#. Translators: this message is shown below the password entry field
#. to indicate the user can swipe their finger instead
#: ../js/gdm/util.js:269
#: ../js/gdm/util.js:299
msgid "(or swipe finger)"
msgstr "(o passare il dito)"
#: ../js/gdm/util.js:294
#: ../js/gdm/util.js:324
#, c-format
msgid "(e.g., user or %s)"
msgstr "(p.e. utente o %s)"
#: ../js/misc/util.js:92
#: ../js/misc/util.js:94
msgid "Command not found"
msgstr "Comando non trovato"
#. Replace "Error invoking GLib.shell_parse_argv: " with
#. something nicer
#: ../js/misc/util.js:125
#: ../js/misc/util.js:127
msgid "Could not parse command:"
msgstr "Impossibile analizzare il comando:"
#: ../js/misc/util.js:133
#: ../js/misc/util.js:135
#, c-format
msgid "Execution of '%s' failed:"
msgstr "Esecuzione di «%s» non riuscita:"
#. Translators: Filter to display all applications
#: ../js/ui/appDisplay.js:259
#: ../js/ui/appDisplay.js:348
msgid "Frequent"
msgstr "Frequenti"
#: ../js/ui/appDisplay.js:355
msgid "All"
msgstr "Tutte"
#: ../js/ui/appDisplay.js:624
#: ../js/ui/appDisplay.js:913
msgid "New Window"
msgstr "Nuova finestra"
#: ../js/ui/appDisplay.js:627 ../js/ui/dash.js:286
#: ../js/ui/appDisplay.js:916 ../js/ui/dash.js:284
msgid "Remove from Favorites"
msgstr "Rimuovi dai preferiti"
#: ../js/ui/appDisplay.js:628
#: ../js/ui/appDisplay.js:917
msgid "Add to Favorites"
msgstr "Aggiungi ai preferiti"
@ -489,6 +499,14 @@ msgstr "%s è stato aggiunto ai preferiti."
msgid "%s has been removed from your favorites."
msgstr "%s è stato rimosso dai preferiti."
#: ../js/ui/backgroundMenu.js:19 ../js/ui/userMenu.js:787
msgid "Settings"
msgstr "Impostazioni"
#: ../js/ui/backgroundMenu.js:21
msgid "Change Background…"
msgstr "Cambia sfondo…"
#. Translators: Shown in calendar event list for all day events
#. * Keep it short, best if you can use less then 10 characters
#.
@ -800,39 +818,39 @@ msgid "Mute"
msgstr "Disattiva notifiche"
#. Translators: this is the word "Yesterday" followed by a time string. i.e. "Yesterday, 14:30"
#: ../js/ui/components/telepathyClient.js:938
#: ../js/ui/components/telepathyClient.js:942
#, no-c-format
msgid "<b>Yesterday</b>, <b>%H:%M</b>"
msgstr "<b>Ieri</b>, <b>%-H.%M</b>"
#. Translators: this is the week day name followed by a time string. i.e. "Monday, 14:30
#: ../js/ui/components/telepathyClient.js:944
#: ../js/ui/components/telepathyClient.js:948
#, no-c-format
msgid "<b>%A</b>, <b>%H:%M</b>"
msgstr "<b>%A</b>, <b>%-H.%M</b>"
#. Translators: this is the month name and day number followed by a time string. i.e. "May 25, 14:30"
#: ../js/ui/components/telepathyClient.js:949
#: ../js/ui/components/telepathyClient.js:953
#, no-c-format
msgid "<b>%B</b> <b>%d</b>, <b>%H:%M</b>"
msgstr "<b>%d</b> <b>%B</b>, <b>%-H.%M</b>"
#. Translators: this is the month name, day number, year number followed by a time string. i.e. "May 25 2012, 14:30"
#: ../js/ui/components/telepathyClient.js:953
#: ../js/ui/components/telepathyClient.js:957
#, no-c-format
msgid "<b>%B</b> <b>%d</b> <b>%Y</b>, <b>%H:%M</b> "
msgstr "<b>%d</b> <b>%B</b> <b>%Y</b>, <b>%-H.%M</b>"
#. Translators: this is the other person changing their old IM name to their new
#. IM name.
#: ../js/ui/components/telepathyClient.js:981
#: ../js/ui/components/telepathyClient.js:985
#, c-format
msgid "%s is now known as %s"
msgstr "%s ha cambiato nome in %s"
#. translators: argument is a room name like
#. * room@jabber.org for example.
#: ../js/ui/components/telepathyClient.js:1084
#: ../js/ui/components/telepathyClient.js:1088
#, c-format
msgid "Invitation to %s"
msgstr "Invio su %s"
@ -840,38 +858,38 @@ msgstr "Invio su %s"
#. translators: first argument is the name of a contact and the second
#. * one the name of a room. "Alice is inviting you to join room@jabber.org
#. * for example.
#: ../js/ui/components/telepathyClient.js:1092
#: ../js/ui/components/telepathyClient.js:1096
#, c-format
msgid "%s is inviting you to join %s"
msgstr "%s ti sta invitando su %s"
#: ../js/ui/components/telepathyClient.js:1094
#: ../js/ui/components/telepathyClient.js:1133
#: ../js/ui/components/telepathyClient.js:1173
#: ../js/ui/components/telepathyClient.js:1236
#: ../js/ui/components/telepathyClient.js:1098
#: ../js/ui/components/telepathyClient.js:1137
#: ../js/ui/components/telepathyClient.js:1177
#: ../js/ui/components/telepathyClient.js:1240
msgid "Decline"
msgstr "Declina"
#: ../js/ui/components/telepathyClient.js:1095
#: ../js/ui/components/telepathyClient.js:1174
#: ../js/ui/components/telepathyClient.js:1237
#: ../js/ui/components/telepathyClient.js:1099
#: ../js/ui/components/telepathyClient.js:1178
#: ../js/ui/components/telepathyClient.js:1241
msgid "Accept"
msgstr "Accetta"
#. translators: argument is a contact name like Alice for example.
#: ../js/ui/components/telepathyClient.js:1125
#: ../js/ui/components/telepathyClient.js:1129
#, c-format
msgid "Video call from %s"
msgstr "Videochiamata da %s"
#. translators: argument is a contact name like Alice for example.
#: ../js/ui/components/telepathyClient.js:1128
#: ../js/ui/components/telepathyClient.js:1132
#, c-format
msgid "Call from %s"
msgstr "Chiamata da %s"
#. translators: this is a button label (verb), not a noun
#: ../js/ui/components/telepathyClient.js:1135
#: ../js/ui/components/telepathyClient.js:1139
msgid "Answer"
msgstr "Rispondi"
@ -880,112 +898,112 @@ msgstr "Rispondi"
#. * file name. The string will be something
#. * like: "Alice is sending you test.ogg"
#.
#: ../js/ui/components/telepathyClient.js:1167
#: ../js/ui/components/telepathyClient.js:1171
#, c-format
msgid "%s is sending you %s"
msgstr "%s ti sta inviando %s"
#. To translators: The parameter is the contact's alias
#: ../js/ui/components/telepathyClient.js:1202
#: ../js/ui/components/telepathyClient.js:1206
#, c-format
msgid "%s would like permission to see when you are online"
msgstr "%s chiede il permesso di vedere quando sei online"
#: ../js/ui/components/telepathyClient.js:1294
#: ../js/ui/components/telepathyClient.js:1298
msgid "Network error"
msgstr "Errore di rete"
#: ../js/ui/components/telepathyClient.js:1296
#: ../js/ui/components/telepathyClient.js:1300
msgid "Authentication failed"
msgstr "Autenticazione non riuscita"
#: ../js/ui/components/telepathyClient.js:1298
#: ../js/ui/components/telepathyClient.js:1302
msgid "Encryption error"
msgstr "Errore di cifratura"
#: ../js/ui/components/telepathyClient.js:1300
#: ../js/ui/components/telepathyClient.js:1304
msgid "Certificate not provided"
msgstr "Certificato non fornito"
#: ../js/ui/components/telepathyClient.js:1302
#: ../js/ui/components/telepathyClient.js:1306
msgid "Certificate untrusted"
msgstr "Certificato non fidato"
#: ../js/ui/components/telepathyClient.js:1304
#: ../js/ui/components/telepathyClient.js:1308
msgid "Certificate expired"
msgstr "Certificato scaduto"
#: ../js/ui/components/telepathyClient.js:1306
#: ../js/ui/components/telepathyClient.js:1310
msgid "Certificate not activated"
msgstr "Certificato non attivato"
#: ../js/ui/components/telepathyClient.js:1308
#: ../js/ui/components/telepathyClient.js:1312
msgid "Certificate hostname mismatch"
msgstr "Corrispondenza errata nel nome host del certificato"
#: ../js/ui/components/telepathyClient.js:1310
#: ../js/ui/components/telepathyClient.js:1314
msgid "Certificate fingerprint mismatch"
msgstr "Corrispondenza errata nell'impronta digitare del certificato"
#: ../js/ui/components/telepathyClient.js:1312
#: ../js/ui/components/telepathyClient.js:1316
msgid "Certificate self-signed"
msgstr "Certificato auto-firmato"
#: ../js/ui/components/telepathyClient.js:1314
#: ../js/ui/components/telepathyClient.js:1318
msgid "Status is set to offline"
msgstr "Lo stato è impostato a fuori rete"
#: ../js/ui/components/telepathyClient.js:1316
#: ../js/ui/components/telepathyClient.js:1320
msgid "Encryption is not available"
msgstr "La cifratura non è disponibile"
#: ../js/ui/components/telepathyClient.js:1318
#: ../js/ui/components/telepathyClient.js:1322
msgid "Certificate is invalid"
msgstr "Il certificato non è valido"
#: ../js/ui/components/telepathyClient.js:1320
#: ../js/ui/components/telepathyClient.js:1324
msgid "Connection has been refused"
msgstr "La connessione è stata rifiutata"
#: ../js/ui/components/telepathyClient.js:1322
#: ../js/ui/components/telepathyClient.js:1326
msgid "Connection can't be established"
msgstr "Impossibile stabilire la connessione"
#: ../js/ui/components/telepathyClient.js:1324
#: ../js/ui/components/telepathyClient.js:1328
msgid "Connection has been lost"
msgstr "Connessione persa"
#: ../js/ui/components/telepathyClient.js:1326
#: ../js/ui/components/telepathyClient.js:1330
msgid "This account is already connected to the server"
msgstr "Questo account è già connesso al server"
#: ../js/ui/components/telepathyClient.js:1328
#: ../js/ui/components/telepathyClient.js:1332
msgid ""
"Connection has been replaced by a new connection using the same resource"
msgstr ""
"La connessione è stata sostituita da una nuova connessione usando la stessa "
"risorsa"
#: ../js/ui/components/telepathyClient.js:1330
#: ../js/ui/components/telepathyClient.js:1334
msgid "The account already exists on the server"
msgstr "L'account esiste già sul server"
#: ../js/ui/components/telepathyClient.js:1332
#: ../js/ui/components/telepathyClient.js:1336
msgid "Server is currently too busy to handle the connection"
msgstr "Il server è al momento troppo occupato per gestire la connessione"
#: ../js/ui/components/telepathyClient.js:1334
#: ../js/ui/components/telepathyClient.js:1338
msgid "Certificate has been revoked"
msgstr "Il certificato è stato revocato"
#: ../js/ui/components/telepathyClient.js:1336
#: ../js/ui/components/telepathyClient.js:1340
msgid ""
"Certificate uses an insecure cipher algorithm or is cryptographically weak"
msgstr ""
"Il certificato usa un algoritmo di cifratura non sicuro o è "
"crittograficamente debole"
#: ../js/ui/components/telepathyClient.js:1338
#: ../js/ui/components/telepathyClient.js:1342
msgid ""
"The length of the server certificate, or the depth of the server certificate "
"chain, exceed the limits imposed by the cryptography library"
@ -996,22 +1014,22 @@ msgstr ""
# indica lo stato del device BT, per esempio gli auricolari
# credo sia meglio l'aggettivo che il sostantivo
#: ../js/ui/components/telepathyClient.js:1340
#: ../js/ui/components/telepathyClient.js:1344
msgid "Internal error"
msgstr "Errore interno"
#. translators: argument is the account name, like
#. * name@jabber.org for example.
#: ../js/ui/components/telepathyClient.js:1350
#: ../js/ui/components/telepathyClient.js:1354
#, c-format
msgid "Unable to connect to %s"
msgstr "Impossibile connettersi a %s"
#: ../js/ui/components/telepathyClient.js:1355
#: ../js/ui/components/telepathyClient.js:1359
msgid "View account"
msgstr "Visualizza account"
#: ../js/ui/components/telepathyClient.js:1394
#: ../js/ui/components/telepathyClient.js:1398
msgid "Unknown reason"
msgstr "Motivo sconosciuto"
@ -1019,14 +1037,14 @@ msgstr "Motivo sconosciuto"
msgid "Windows"
msgstr "Finestre"
#: ../js/ui/dash.js:250 ../js/ui/dash.js:288
#: ../js/ui/dash.js:248 ../js/ui/dash.js:286
msgid "Show Applications"
msgstr "Mostra applicazioni"
# cruscotto?!?!?!?!?!?!?
#. Translators: this is the name of the dock/favorites area on
#. the left of the overview
#: ../js/ui/dash.js:418
#: ../js/ui/dash.js:435
msgid "Dash"
msgstr "Dash"
@ -1152,86 +1170,86 @@ msgstr "Installa"
msgid "Download and install '%s' from extensions.gnome.org?"
msgstr "Scaricare e installare «%s» da extensions.gnome.org?"
#: ../js/ui/keyboard.js:621 ../js/ui/status/keyboard.js:314
#: ../js/ui/keyboard.js:619 ../js/ui/status/keyboard.js:314
#: ../js/ui/status/power.js:211
msgid "Keyboard"
msgstr "Tastiera"
#: ../js/ui/lookingGlass.js:692
#: ../js/ui/lookingGlass.js:693
msgid "No extensions installed"
msgstr "Nessuna estensione installata"
#. Translators: argument is an extension UUID.
#: ../js/ui/lookingGlass.js:746
#: ../js/ui/lookingGlass.js:747
#, c-format
msgid "%s has not emitted any errors."
msgstr "%s non ha emesso alcun errore."
#: ../js/ui/lookingGlass.js:752
#: ../js/ui/lookingGlass.js:753
msgid "Hide Errors"
msgstr "Nascondi errori"
#: ../js/ui/lookingGlass.js:756 ../js/ui/lookingGlass.js:816
#: ../js/ui/lookingGlass.js:757 ../js/ui/lookingGlass.js:817
msgid "Show Errors"
msgstr "Mostra errori"
# (ndt) o abilitata?
#: ../js/ui/lookingGlass.js:765
#: ../js/ui/lookingGlass.js:766
msgid "Enabled"
msgstr "Abilitato"
# (ndt) o disabilitata?
#. translators:
#. * The device has been disabled
#: ../js/ui/lookingGlass.js:768 ../src/gvc/gvc-mixer-control.c:1830
#: ../js/ui/lookingGlass.js:769 ../src/gvc/gvc-mixer-control.c:1830
msgid "Disabled"
msgstr "Disabilitato"
#: ../js/ui/lookingGlass.js:770
#: ../js/ui/lookingGlass.js:771
msgid "Error"
msgstr "Errore"
#: ../js/ui/lookingGlass.js:772
#: ../js/ui/lookingGlass.js:773
msgid "Out of date"
msgstr "Non aggiornato"
#: ../js/ui/lookingGlass.js:774
#: ../js/ui/lookingGlass.js:775
msgid "Downloading"
msgstr "Scaricamento"
#: ../js/ui/lookingGlass.js:798
#: ../js/ui/lookingGlass.js:799
msgid "View Source"
msgstr "Visualizza sorgente"
#: ../js/ui/lookingGlass.js:807
#: ../js/ui/lookingGlass.js:808
msgid "Web Page"
msgstr "Pagina web"
#: ../js/ui/messageTray.js:1201
#: ../js/ui/messageTray.js:1182
msgid "Open"
msgstr "Apri"
#: ../js/ui/messageTray.js:1208
#: ../js/ui/messageTray.js:1189
msgid "Remove"
msgstr "Rimuovi"
#: ../js/ui/messageTray.js:1520
#: ../js/ui/messageTray.js:1501
msgid "Clear Messages"
msgstr "Pulisci messaggi"
#: ../js/ui/messageTray.js:1547
#: ../js/ui/messageTray.js:1528
msgid "Notification Settings"
msgstr "Impostazioni notifiche"
#: ../js/ui/messageTray.js:1725
#: ../js/ui/messageTray.js:1707
msgid "No Messages"
msgstr "Nessun messaggio"
#: ../js/ui/messageTray.js:1806
#: ../js/ui/messageTray.js:1787
msgid "Message Tray"
msgstr "Cassetto messaggi"
#: ../js/ui/messageTray.js:2881
#: ../js/ui/messageTray.js:2864
msgid "System Information"
msgstr "Informazione di sistema"
@ -1240,11 +1258,18 @@ msgctxt "program"
msgid "Unknown"
msgstr "Sconosciuto"
#: ../js/ui/overview.js:93
#: ../js/ui/overviewControls.js:460 ../js/ui/screenShield.js:153
#, c-format
msgid "%d new message"
msgid_plural "%d new messages"
msgstr[0] "%d nuovo messaggio"
msgstr[1] "%d nuovi messaggi"
#: ../js/ui/overview.js:82
msgid "Undo"
msgstr "Annulla"
#: ../js/ui/overview.js:140
#: ../js/ui/overview.js:129
msgid "Overview"
msgstr "Panoramica"
@ -1252,7 +1277,7 @@ msgstr "Panoramica"
#. in the search entry when no search is
#. active; it should not exceed ~30
#. characters.
#: ../js/ui/overview.js:220
#: ../js/ui/overview.js:284
msgid "Type to search…"
msgstr "Digita per cercare…"
@ -1266,7 +1291,7 @@ msgstr "Esci"
msgid "Activities"
msgstr "Attività"
#: ../js/ui/panel.js:982
#: ../js/ui/panel.js:983
msgid "Top Bar"
msgstr "Barra superiore"
@ -1289,29 +1314,22 @@ msgstr "Chiudi"
#. Translators: This is a time format for a date in
#. long format
#: ../js/ui/screenShield.js:117
#: ../js/ui/screenShield.js:90
msgid "%A, %B %d"
msgstr "%A, %d %B"
#: ../js/ui/screenShield.js:180
#, c-format
msgid "%d new message"
msgid_plural "%d new messages"
msgstr[0] "%d nuovo messaggio"
msgstr[1] "%d nuovi messaggi"
#: ../js/ui/screenShield.js:182
#: ../js/ui/screenShield.js:155
#, c-format
msgid "%d new notification"
msgid_plural "%d new notifications"
msgstr[0] "%d nuova notifica"
msgstr[1] "%d nuove notifiche"
#: ../js/ui/screenShield.js:469 ../js/ui/userMenu.js:805
#: ../js/ui/screenShield.js:442 ../js/ui/userMenu.js:805
msgid "Lock"
msgstr "Blocca"
#: ../js/ui/screenShield.js:635
#: ../js/ui/screenShield.js:639
msgid "GNOME needs to lock the screen"
msgstr "GNOME deve bloccare lo schermo"
@ -1322,11 +1340,11 @@ msgstr "GNOME deve bloccare lo schermo"
#.
#. XXX: another option is to kick the user into the gdm login
#. screen, where we're not affected by grabs
#: ../js/ui/screenShield.js:754 ../js/ui/screenShield.js:1165
#: ../js/ui/screenShield.js:758 ../js/ui/screenShield.js:1169
msgid "Unable to lock"
msgstr "Impossibile bloccare"
#: ../js/ui/screenShield.js:755 ../js/ui/screenShield.js:1166
#: ../js/ui/screenShield.js:759 ../js/ui/screenShield.js:1170
msgid "Lock was blocked by an application"
msgstr "Il blocco è stato impedito da un'applicazione."
@ -1362,56 +1380,56 @@ msgstr "Password"
msgid "Remember Password"
msgstr "Ricorda password"
#: ../js/ui/shellMountOperation.js:403 ../js/ui/unlockDialog.js:192
#: ../js/ui/shellMountOperation.js:403 ../js/ui/unlockDialog.js:140
msgid "Unlock"
msgstr "Sblocca"
# su Android è Rilevabile :P
#: ../js/ui/status/accessibility.js:35
#: ../js/ui/status/accessibility.js:36
msgid "Accessibility"
msgstr "Accessibilità"
#: ../js/ui/status/accessibility.js:40
#: ../js/ui/status/accessibility.js:41
msgid "Zoom"
msgstr "Ingrandimento"
#: ../js/ui/status/accessibility.js:47
#: ../js/ui/status/accessibility.js:48
msgid "Screen Reader"
msgstr "Lettore schermo"
#: ../js/ui/status/accessibility.js:51
#: ../js/ui/status/accessibility.js:52
msgid "Screen Keyboard"
msgstr "Tastiera a schermo"
#: ../js/ui/status/accessibility.js:55
#: ../js/ui/status/accessibility.js:56
msgid "Visual Alerts"
msgstr "Avvisi visibili"
#: ../js/ui/status/accessibility.js:58
#: ../js/ui/status/accessibility.js:59
msgid "Sticky Keys"
msgstr "Tasti singoli"
#: ../js/ui/status/accessibility.js:61
#: ../js/ui/status/accessibility.js:62
msgid "Slow Keys"
msgstr "Tasti lenti"
#: ../js/ui/status/accessibility.js:64
#: ../js/ui/status/accessibility.js:65
msgid "Bounce Keys"
msgstr "Tasti rimbalzati"
#: ../js/ui/status/accessibility.js:67
#: ../js/ui/status/accessibility.js:68
msgid "Mouse Keys"
msgstr "Mouse da tastiera"
#: ../js/ui/status/accessibility.js:71
#: ../js/ui/status/accessibility.js:72
msgid "Universal Access Settings"
msgstr "Impostazioni accesso universale"
#: ../js/ui/status/accessibility.js:107
#: ../js/ui/status/accessibility.js:129
msgid "High Contrast"
msgstr "Contrasto elevato"
#: ../js/ui/status/accessibility.js:154
#: ../js/ui/status/accessibility.js:178
msgid "Large Text"
msgstr "Caratteri grandi"
@ -1774,11 +1792,11 @@ msgstr "Volume"
msgid "Microphone"
msgstr "Microfono"
#: ../js/ui/unlockDialog.js:203
#: ../js/ui/unlockDialog.js:151
msgid "Log in as another user"
msgstr "Accedi come altro utente"
#: ../js/ui/unlockDialog.js:229
#: ../js/ui/unlockDialog.js:177
msgid "Unlock Window"
msgstr "Sblocca finestra"
@ -1810,10 +1828,6 @@ msgstr "Fuori rete"
msgid "Notifications"
msgstr "Notifiche"
#: ../js/ui/userMenu.js:787
msgid "Settings"
msgstr "Impostazioni"
#: ../js/ui/userMenu.js:795
msgid "Switch User"
msgstr "Cambia utente"
@ -1947,6 +1961,10 @@ msgstr "La password non può essere vuota"
msgid "Authentication dialog was dismissed by the user"
msgstr "Il dialogo di autenticazione è stato annullato dall'utente"
#~ msgctxt "title"
#~ msgid "Sign In"
#~ msgstr "Accesso"
#~ msgid "Clear"
#~ msgstr "Pulisci"

763
po/ja.po

File diff suppressed because it is too large Load Diff

865
po/kk.po

File diff suppressed because it is too large Load Diff

1193
po/kn.po

File diff suppressed because it is too large Load Diff

1044
po/ko.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