Compare commits

...

341 Commits

Author SHA1 Message Date
64b5ec0b11 Bump version to 3.9.3
Update NEWS.
2013-06-18 17:47:30 +02:00
48f9ea3d9e gdm: clear the messages queue when the user answers a prompt
the messages were being shown even when the user entered the
right information they were asked for.

https://bugzilla.gnome.org/show_bug.cgi?id=702458
2013-06-18 11:58:20 -03:00
798a0ca240 Background: don't require a URI scheme for picture-uri
Migration from old settings can result in a path instead of URI
there. This is technically invalid, but can easily recognize it
and avoid the crash.

Minor changes by Ray Strode

https://bugzilla.gnome.org/show_bug.cgi?id=702121
2013-06-18 10:55:52 -04:00
5ee6cbd4c8 Updated Spanish translation 2013-06-17 17:54:56 +02:00
3b219a6a9a Updated Norwegian bokmål translation 2013-06-17 12:29:15 +02:00
536ff6f561 Tajik translation updated 2013-06-16 23:32:30 +05:00
013b6aa44a network: don't fail if we can't read a connection associated with an active
It can happen in legitimate cases, such as a version incompatibility
between NetworkManager and libnm-glib or a restricted permission.

https://bugzilla.gnome.org/show_bug.cgi?id=701849
2013-06-14 20:38:54 +02:00
0e7d3a7558 network: Remove support for virtual networking
This isn't in the new design, and no good can come from this.
Just allow people to use the control center to configure virtual
networking.

https://bugzilla.gnome.org/show_bug.cgi?id=701954
2013-06-14 14:15:17 -04:00
8bd4895538 network: Simplify connections to the firmware signal
The status item will go away soon, so make sure the one-time
fire is given its own function. At the same time, only connect
to the signal when the situation actually matters.

https://bugzilla.gnome.org/show_bug.cgi?id=701954
2013-06-14 14:15:17 -04:00
465c77ddcf network: Make the device field private
With getIndicatorIcon() replacing the main use of the .device
field, we can make this a private API.

https://bugzilla.gnome.org/show_bug.cgi?id=701954
2013-06-14 14:15:17 -04:00
6ef2d4a4cc network: Merge NMConnectionBased back into NMDevice
https://bugzilla.gnome.org/show_bug.cgi?id=701954
2013-06-14 14:15:17 -04:00
7ae7f046c2 network: Rewrite VPN section to be independent of NMConnectionBased
https://bugzilla.gnome.org/show_bug.cgi?id=701954
2013-06-14 14:15:17 -04:00
f4051e810e network: Remove overflow of VPN configurations
It's unlikely that somebody has more than five VPN connections
configured, and the code is

https://bugzilla.gnome.org/show_bug.cgi?id=701954
2013-06-14 14:15:16 -04:00
e6c239d0f3 network: Move indicator icon selection to individual devices
This cuts down on the number of cross-connected "public" API between
the devices, hopefully allowing us to reduce it further.

https://bugzilla.gnome.org/show_bug.cgi?id=701954
2013-06-14 14:15:16 -04:00
35a7a3c1ac network: Always show the VPN indicator when connected to VPN
The new designs ask for this.

https://bugzilla.gnome.org/show_bug.cgi?id=701954
2013-06-14 14:15:11 -04:00
a0991c8261 network: "Remove" support for dial-up modems
NetworkManager has never supported dial-up modems, which are the
only case we have a modem device without any of these capabilities.

https://bugzilla.gnome.org/show_bug.cgi?id=701954
2013-06-14 13:48:35 -04:00
9520880568 network: Remove dead code
No class in here has this.carrier as a property. Presumably, this was
meant to be this.device.carrier, but since this code is going to be
rewritten soon anyway, might as well just junk the never-working
code for now.

https://bugzilla.gnome.org/show_bug.cgi?id=701954
2013-06-14 13:48:35 -04:00
719d793e22 Calendar: refactor the layout of the event list
In order to have event descriptions on multiple lines, but still
maintain proper alignment with the day and time strings, refactor
the whole event list to be one big table. Headers are implemented
as spanning cells, and uneven spacing is a mix of row/column spacing
and cell padding.

https://bugzilla.gnome.org/show_bug.cgi?id=701231
2013-06-14 18:44:47 +02:00
c7fb65c78e configure: Bump gnome-bluetooth requirement
Needed for the changes in the agent.

https://bugzilla.gnome.org/show_bug.cgi?id=700891
2013-06-14 11:36:22 +02:00
dd74ea99a7 bluetooth: Port to BlueZ 5
In BlueZ 4, Authorize() was used to authorize both service
and JustWorks authorization requests. In BlueZ 5 these two
have been split into AuthorizeService() for services and
RequestAuthorization for JustWorks devices. Adapt the
Bluetooth code accordingly.

https://bugzilla.gnome.org/show_bug.cgi?id=700891
2013-06-14 11:36:10 +02:00
c6fe6eb7ab network: Fix a bad signal name
We try to disconnect from firmwareChangedId, not firmwareMissingId.

https://bugzilla.gnome.org/show_bug.cgi?id=701954
2013-06-12 16:58:34 -04:00
2cbee05c8a network: Remove setActiveConnection/clearActiveConnection
This can be more easily achieved by listening for changes to the
device's active-connection property. VPN will still need support to
track active connections, as it does not have an associated
device. But as VPN can track multiple active connections, the names
"set" and "clear" don't quite fit. Rename them to the more-standard
"add" and "remove".

https://bugzilla.gnome.org/show_bug.cgi?id=701954
2013-06-12 16:57:56 -04:00
308b1d6039 dateMenu: Remove bad setColumnWidths call
The correct API is to pass in an array, so I don't even know how
this managed to work before.

https://bugzilla.gnome.org/show_bug.cgi?id=702125
2013-06-12 16:13:47 -04:00
4cd832c05a network: Rename a variable for consistency
We tend to use the name "a" in this method. This matches consistency
with the rest of the code.

https://bugzilla.gnome.org/show_bug.cgi?id=701954
2013-06-12 16:11:37 -04:00
2af4925d95 logout dialog: Show the correct text right away
The end session dialog was waiting a second before updating
its text to display the timer. It is nicer to show the correct
message from the start.

https://bugzilla.gnome.org/show_bug.cgi?id=702056
2013-06-12 05:48:23 -04:00
5e52f0e2a8 Updated Bulgarian translation 2013-06-08 11:09:42 +03:00
a46a68d616 Updated Czech translation 2013-06-08 07:49:24 +02:00
203d7c4b43 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:42:54 +02:00
24703ffa57 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:21:00 +02:00
5cd913a527 windowManager: 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:52:10 +02:00
91844e48e9 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:52:10 +02:00
6c2f3d1d17 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:52:10 +02:00
9c222c7e5c network: Remove _createAPItem
The code flows better if this is inlined like this.

https://bugzilla.gnome.org/show_bug.cgi?id=698918
2013-06-06 17:16:44 -04:00
2249da7976 network: Remove some more dead code
Submenus gone means we can remove the title param and things
that use it.

https://bugzilla.gnome.org/show_bug.cgi?id=698918
2013-06-06 17:16:44 -04:00
a55288bda0 network: Don't create submenus for multiple-connection items
As multiple-connections for a Wi-Fi AP won't fit in the new design,
remove submenus right now. Simply make a simple item that connects
to the first known connection for the AP, which should be the common
case.

https://bugzilla.gnome.org/show_bug.cgi?id=698918
2013-06-06 17:16:07 -04:00
e645edbda7 popupMenu: Fix PopupSliderMenuItem
It seems a bad rebase took this away.
2013-06-06 15:49:20 -04:00
aee7cd73c4 network: Reformat connection code
This makes the code flow the same between removeConnection and checkConnection.

https://bugzilla.gnome.org/show_bug.cgi?id=701755
2013-06-06 15:32:06 -04:00
380a71dd21 network: Remove a dead signal
This signal is unused.

https://bugzilla.gnome.org/show_bug.cgi?id=701755
2013-06-06 14:00:38 -04:00
23dd5cc160 volume: Remove some unused variables
https://bugzilla.gnome.org/show_bug.cgi?id=701755
2013-06-06 14:00:38 -04:00
847cb5b972 slider: Separate PopupSliderMenuItem into its own widget
https://bugzilla.gnome.org/show_bug.cgi?id=701755
2013-06-06 14:00:38 -04:00
cc64091f9c popupMenu: Fix bubbling in the slider widget
https://bugzilla.gnome.org/show_bug.cgi?id=701755
2013-06-06 14:00:38 -04:00
b68eb44ca5 userMenu: Use addSettingsAction
https://bugzilla.gnome.org/show_bug.cgi?id=701755
2013-06-06 14:00:38 -04:00
403540e8a1 userMenu: Move UserAvatarWidget into UserWidget
https://bugzilla.gnome.org/show_bug.cgi?id=701755
2013-06-06 14:00:37 -04:00
c39497222f update Simplified Chinese (zh_CN) translation 2013-06-06 11:44:33 +08:00
9e56e668e0 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 17:32:49 +02:00
41ae93dba0 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:22:27 +02:00
6c527c1bb4 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:40:17 +02:00
90c7876341 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 15:32:43 +02:00
10b77a8305 dash: Minor cleanup
https://bugzilla.gnome.org/show_bug.cgi?id=684618
2013-06-05 15:32:43 +02:00
1902f4773b 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 15:32:43 +02:00
4b95be6a95 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 15:32:43 +02:00
61323926e0 Updated Traditional Chinese translation(Hong Kong and Taiwan) 2013-06-04 21:49:58 +08:00
e30d18febe 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-03 19:26:26 +02:00
9f2f80ae4f Updated German translation 2013-06-02 09:48:44 +02:00
bd6e0ceb81 dash: Simplify some code
https://bugzilla.gnome.org/show_bug.cgi?id=701386
2013-06-01 00:35:24 +02:00
673d7038d8 Restore gvc revision
Commit 9d54e46ce7 accidentally reverted to a previous revision.
2013-05-31 20:57:43 +02:00
3a6231dcc1 build: Bump gcr requirement
https://bugzilla.gnome.org/show_bug.cgi?id=700972
2013-05-31 20:43:24 +02:00
9d54e46ce7 Updated Galician translations 2013-05-31 01:04:06 +02:00
63e6d11892 Tajik updated 2013-05-30 17:29:52 +05:00
0509bb9bb4 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:57:37 +02:00
5c78908a5f 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:04:07 +02:00
5a2269c6c6 overviewControls: Don't push window thumbs over when workspaces are invisible
Make the sliding control invisible when the thumbnails box is as well.

https://bugzilla.gnome.org/show_bug.cgi?id=701167
2013-05-29 13:04:45 -04:00
a7e9655e32 searchDisplay: Remove the setResults/getResultsForDisplay dance
Now that we control our own destiny, I noticed that getResultsToDisplay
is the only user of this._notDisplayedResult, and it's called immediately
after setResults, which is the only thing that sets it. Just remove the
stateness entirely.

https://bugzilla.gnome.org/show_bug.cgi?id=693836
2013-05-29 11:32:50 -04:00
1ec82d2ddd searchDisplay: Remove getVisibleResultCount
This is only used in one place, so we can quickly substitute
where it's needed.

https://bugzilla.gnome.org/show_bug.cgi?id=693836
2013-05-29 11:32:50 -04:00
98eaef621a searchDisplay: Remove the "provider meta"
As everything is tracked on the SearchResults or subclasses of now,
just use that, which we call the "provider display".

https://bugzilla.gnome.org/show_bug.cgi?id=693836
2013-05-29 11:32:50 -04:00
74a6ca58ef searchDisplay: Move the provider actors to the results display
Since the provider icon only appears in the list results, it makes
sense for that to be stored with the results class, rather than outside,
triggered by which sort of display it is.

https://bugzilla.gnome.org/show_bug.cgi?id=693836
2013-05-29 11:32:49 -04:00
747faa43ae searchDisplay: Remove the providerIcon from the providerMeta
Since the resultsDisplay is tracking it, it's not needed.

https://bugzilla.gnome.org/show_bug.cgi?id=693836
2013-05-29 11:32:49 -04:00
32a53f7412 searchDisplay: Remove focus management code
It turns out that this focus code broke sometime in the 3.6 cycle --
when updating results, the focus is always on the text entry, so this
never gets called. We'll eventually replace it with something that
keeps track of the focused result meta, but for now, remove it.

https://bugzilla.gnome.org/show_bug.cgi?id=693836
2013-05-29 11:32:49 -04:00
9c94e9813c searchDisplay: Make renderResults private
There's no need to call this from outside now.

https://bugzilla.gnome.org/show_bug.cgi?id=693836
2013-05-29 11:32:49 -04:00
19749bb37f searchDisplay: Make the results display in charge of updating the actor
While this is a very simple translation right now, soon enough it will
be so that it will have a less crazy "public" API and can do things like
cache result metas.

https://bugzilla.gnome.org/show_bug.cgi?id=693836
2013-05-29 11:32:49 -04:00
5ab4c484a5 searchDisplay: Remove clearDisplayForProvider
Since the two paths that call this want to keep the actor in two different
states, it makes sense to just call the one function that's the same between
both individually.

https://bugzilla.gnome.org/show_bug.cgi?id=693836
2013-05-29 11:32:49 -04:00
e602199bfb searchDisplay: Add a base class for common parts of search results
Right now, this doesn't give us very much, since IconGrid and StBoxLayout
have different APIs. But since we want to introduce result caching, it
makes to reduce the duplication we already have so we don't need to add
the code to do so in both places.

https://bugzilla.gnome.org/show_bug.cgi?id=693836
2013-05-29 11:32:49 -04:00
62e1c08dd6 searchDisplay: Remove pendingClear
It turns out that every time we call getResultsForDisplay is
directly after a setResults, so pendingClear is always true.

https://bugzilla.gnome.org/show_bug.cgi?id=693836
2013-05-29 11:32:49 -04:00
37e2b60cd3 search: Rename pushResults to setResults
pushResults, and the original async search API, were originally intended
so search results that weren't immediate could be added as they come in.
Since then, we've decided that the design of search results is that they
should finish at once with all results. Thus, the code was modified so
that pushResults always overwrote the current result set. As such, it makes
sense to rename the method so that the name matches the behavior.

https://bugzilla.gnome.org/show_bug.cgi?id=693836
2013-05-29 11:32:49 -04:00
f299078585 Updated Czech translation 2013-05-29 12:26:52 +02:00
bf0a0d5bad Bump version to 3.9.2
Update NEWS.
2013-05-28 19:38:25 +02:00
365cda386c messageTray: Fix lightbox outside the overview
Commit d0310bd745 blindly replaced global.overlay_group with
Main.layout.overviewGroup, but unlike the former, the latter is
hidden while the overview is not active, which makes it unsuitable
for the message tray's light box. In fact, with the removal of
global.overlay_group, there is no longer a container which may
be used both inside and outside the overview, so we can either
recreate the lightbox each time we show/hide the overview, or
use different lightboxes altogether; this opts for the latter.

https://bugzilla.gnome.org/show_bug.cgi?id=701097
2013-05-28 16:33:47 +02:00
5de5b7a66a Updated Norwegian bokmål translation 2013-05-28 09:44:18 +02:00
d6de0a64ed Tajik Updated 2013-05-28 12:16:32 +05:00
26f8441f73 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-27 14:07:56 +02:00
51bca08386 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-27 14:05:54 +02:00
1579aad362 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-27 14:05:53 +02:00
a2a580954a 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-27 14:05:51 +02:00
944c28f3b3 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-27 14:05:50 +02:00
c13a597fe0 Updated Spanish translation 2013-05-27 13:54:24 +02:00
86e0ae0b93 [l10n] Minor fix on Catalan translation 2013-05-26 08:21:57 +02:00
f71ffed3c7 Updated Slovenian translation 2013-05-25 21:39:26 +02:00
cae96d9023 Updated slovak translation 2013-05-25 21:12:50 +02:00
676b649731 Tajik updated 2013-05-25 13:17:52 +05:00
634ce34e00 global: Use the new mutter API for focusing the stage window
This way, we aren't "going behind mutter's back" about what the current
focused window is.

https://bugzilla.gnome.org/show_bug.cgi?id=700735
2013-05-24 17:44:17 -04:00
6c3096f71f Updated slovak translation 2013-05-24 23:21:21 +02:00
991ed2da72 messageTray: Fix a stuck grab related to bubble notifications
If the user middle clicks on a summary item in the tray, we'll
try to grab null instead of an actor, which is wrong.

https://bugzilla.gnome.org/show_bug.cgi?id=700854
2013-05-24 13:29:07 -04:00
907f02cd28 Tajik Updated 2013-05-24 20:00:58 +05:00
9ba78ce04a Bluetooth: Use "Passkey" instead of "PIN"
Passkey is the proper name to be used when we are pairing with a Bluetooth
2.1+ device. PIN are only used for older devices which is not the case
here, the message is only shown when dealing with 2.1+ devices.

https://bugzilla.gnome.org/show_bug.cgi?id=697661
2013-05-24 16:42:04 +02:00
14a3d9f7fb 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:59:00 +02:00
f73a01295c messageTray: Don't destroy a notification from within its destroy handler
Nothing but bad can come from this.

https://bugzilla.gnome.org/show_bug.cgi?id=700923
2013-05-23 18:25:39 -04:00
ccfa3d3be1 Re-lock the screen if we're restarted from a previously crashed shell
This way we "fail closed", which is better for security.

See https://bugs.launchpad.net/ubuntu/+source/gdm/+bug/1064584

https://bugzilla.gnome.org/show_bug.cgi?id=691987
2013-05-23 16:10:03 -04:00
727e4c0b37 workspace: don't use multiple later calls to propagate actualGeometry calls
Meta laters are invoked in reverse order of registration, so
having multiple laters propagating the geometry cause all but the
first one in the frame (which is usually wrong) to be ignored.
Instead, queue at most one later call, and use the last set geometry
in the callback.

https://bugzilla.gnome.org/show_bug.cgi?id=700853
2013-05-23 18:10:50 +02:00
6ce470b9b2 docs: Include ShellKeyBindingMode in docs
https://bugzilla.gnome.org/show_bug.cgi?id=700900
2013-05-23 17:07:50 +02:00
4b7e230531 layout: Properly order startup initialization
In order to make sure that the struts and regions are initialized,
we need to make sure that we do with the conditions that nothing
is transformed, like the uiGroup, and that everything is visible.

These invariants broke during a fix to hide the UI until the
system background texture could be loaded. Now, reorder things so
that the system background is loaded, and then the UI is properly
loaded, and so on.

https://bugzilla.gnome.org/show_bug.cgi?id=696159
2013-05-22 12:53:39 -04:00
aefe0d3ddd layout: Fix indentation
https://bugzilla.gnome.org/show_bug.cgi?id=696159
2013-05-22 12:53:39 -04:00
bbb23b515f 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:46:34 +02:00
976166a04a Finish removing the overlay_group concept
In preparation for removing from mutter too.

https://bugzilla.gnome.org/show_bug.cgi?id=700735
2013-05-22 18:34:05 +02:00
b20129c37e 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:33:16 +02:00
4fe1360b2c 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:33:16 +02:00
f0113c5ff5 Overview: use a normal chrome actor to handle events during XDND
Instead of using the input mode, when the overview is not modal
it should use a Chrome-tracked actor, that is added to the input
region. Because the overview always takes pointer input when
visible, the actor is added at startup, and it is shown and hidden
as needed.

https://bugzilla.gnome.org/show_bug.cgi?id=700735
2013-05-22 18:27:27 +02:00
a259016436 screenShield: Pop the modal immediately
Allow people to start typing immediately after unlocking their
session, rather than having to wait for a transition.

https://bugzilla.gnome.org/show_bug.cgi?id=700847
2013-05-22 12:11:19 -04:00
9a79c71e88 global: Remove support for the NONREACTIVE input mode
As it's unused, this is a quick cleanup before we can go onto
more important things.

https://bugzilla.gnome.org/show_bug.cgi?id=700735
2013-05-22 12:11:19 -04:00
e62d22a50e layout: Remove affectsInputRegion
This can easy be worked around by adding things to the uiGroup
instead, so there's really no reason to have it here still.

https://bugzilla.gnome.org/show_bug.cgi?id=700735
2013-05-22 12:11:19 -04:00
402f2d939c layout: Remove use of skip_paint
We no longer use this on the uiGroup.

https://bugzilla.gnome.org/show_bug.cgi?id=700735
2013-05-22 12:11:19 -04:00
374aee75d8 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:22:28 +02:00
88ce65266e Disable all extensions in reverse order
So we avoid having to disable and enable an extension that is to
be disabled later anyway.

https://bugzilla.gnome.org/show_bug.cgi?id=700784
2013-05-22 07:51:23 +02:00
e0a6a623d2 workspacesView: Adapt to changes in windowManager
The actionMoveWorkspace() function was changed in commit 8727661c1,
adapt its use in workspacesView as well.

https://bugzilla.gnome.org/show_bug.cgi?id=659288
2013-05-21 22:42:28 +02:00
d0310bd745 Overview: don't use the overlay_group
It's a deprecated concept, and we want to have our own actor
that we can add to the chrome to handle the input region.

https://bugzilla.gnome.org/show_bug.cgi?id=700735
2013-05-21 22:24:53 +02:00
35c665156b Fix bad rebase
A variable rename was missed.
2013-05-21 22:23:18 +02:00
3754a76f10 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:59:14 +02:00
db2e6e5b95 keyboard: don't raise to the top when showing
The stacking is already correct due to the grouping, and calling
raise_top() results in the keyboard above the OSDs.

https://bugzilla.gnome.org/show_bug.cgi?id=700620
2013-05-20 22:00:36 +02:00
d5f95db68d messageTray: Hide notifications when the tray is summoned
If the user summons the tray, it should take priority over a
notification showing.

https://bugzilla.gnome.org/show_bug.cgi?id=700639
2013-05-20 14:25:55 -04:00
d96726c392 messageTray: Add a synonym for hasNotifications
This prevents lines from getting too long.

https://bugzilla.gnome.org/show_bug.cgi?id=700639
2013-05-20 14:25:55 -04:00
d1c54f55e6 messageTray: Don't hide the tray for urgent notifications
The tray should never close on its own, without the user's input.

https://bugzilla.gnome.org/show_bug.cgi?id=700639
2013-05-20 14:25:55 -04:00
176a73f4e9 messageTray: Clean up variable names
Variable names like "sourceNotificationStackDoneShowing" are too
long, and too undescriptive: this one points to a source, not a
notification stack that has been done showing.
2013-05-20 13:38:23 -04:00
54a9592e19 main: Override the workspace layout in WindowManager
https://bugzilla.gnome.org/show_bug.cgi?id=691746
2013-05-20 13:20:21 -04:00
b2aa29e221 main: Move workspace tracking code to WindowManager
https://bugzilla.gnome.org/show_bug.cgi?id=691746
2013-05-20 13:20:21 -04:00
0eba0f8dd3 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-19 23:30:39 +02:00
d8d0afff0b 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-19 23:30:39 +02:00
b799e8c0a6 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-19 23:30:39 +02:00
583255e1a8 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:03 -04:00
c68ccbf263 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:06 +02:00
d658ec8de2 overviewControls: Move reactive flag to main actor
The main overview actor was made reactive to catch scroll-events
and propagate them; after some code shuffling, the actor that
catches scroll events ended up not being the same actor that's
supposed to propagate this, which broke using the scroll wheel
to switch workspaces.

https://bugzilla.gnome.org/show_bug.cgi?id=700595
2013-05-18 21:07:41 +02:00
8727661c1c WindowManager: Show switcher popup for switch-to-workspace-n keybindings
Currently we show the workspace popup for relative targets ("up", "down"),
but not when targetting a specific workspace directly.
There is not really a good reason for that difference, and as we are about
to introduce a new shortcut to target the last workspace (which does vary
with dynamic workspaces), it makes sense to unify the behavior and always
show the switcher.

https://bugzilla.gnome.org/show_bug.cgi?id=659288
2013-05-18 20:12:49 +02:00
731e8bfe2b Replace 'enable-app-monitoring' setting
The org.gnome.desktop.privacy schema gained a 'remember-app-usage'
key, use that instead of our own preference.

https://bugzilla.gnome.org/show_bug.cgi?id=699714
2013-05-18 20:12:49 +02:00
f88d9c06f5 appDisplay: Hide frequent view when app monitoring is disabled
Currently we stop monitoring application usage when disabling the
'enable-app-monitoring' setting, but we still expose previously
gathered data in the app picker's frequent view. This is not what
users should expect, so hide the view in that case.

https://bugzilla.gnome.org/show_bug.cgi?id=699714
2013-05-18 20:12:49 +02:00
248a0c1b6c 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:29:26 +02:00
434f1edb25 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:27:17 +02:00
2a550e6466 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:43:52 -04:00
4f4132943d Updated Norwegian bokmål translation 2013-05-16 13:27:26 +02:00
62760d5b2d 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:40:11 +02:00
34aa501637 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:47:36 +02:00
6330379f77 network: Use accessPointAdded to add initial access points
This is technically a smidge slower due to the constant bisect insert,
but since this should only happen when we make a Wi-Fi dialog, it's
insignificant.

https://bugzilla.gnome.org/show_bug.cgi?id=700322
2013-05-15 11:13:11 -04:00
30c64baa7f network: Don't pass this._connections to the VPN section
It's always empty by this point.

https://bugzilla.gnome.org/show_bug.cgi?id=700322
2013-05-15 11:13:11 -04:00
cdbed0c615 network: Use checkConnection to set up the initial connections
https://bugzilla.gnome.org/show_bug.cgi?id=700322
2013-05-15 11:13:11 -04:00
f6e7034172 network: Remove an unused getter
https://bugzilla.gnome.org/show_bug.cgi?id=700322
2013-05-15 11:13:11 -04:00
cd9c5b9c5d network: Remove semi-complex primary device finding
According to dcbw (and some updated documentation), there will
always be a 1:1 correspondence between NMActiveConnection and
an NMDevice.

https://bugzilla.gnome.org/show_bug.cgi?id=700322
2013-05-15 11:13:11 -04:00
7833e21b01 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:12:35 +02:00
12ba2b222f Add a way to get backtraces from criticals and warnings
Attaching gdb and running with G_DEBUG=fatal-warnings is not a very
fast to debug a specific issue (especially if you have warnings at
startup, since then you need to run the shell from a terminal).
Instead, introduce a new SHELL_DEBUG environment variable that can
be set to backtrace-warning, causing a gjs_dumpstack() after every
warning or critical.

https://bugzilla.gnome.org/show_bug.cgi?id=700262
2013-05-14 23:25:11 +02:00
8583ca73e4 popupMenu: Fix regular submenus
This method was originally private, but it was renamed quickly
before landing, and I forgot to update it.
2013-05-14 13:58:10 -04:00
b588ae4e0e 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:08:00 +02:00
28abc15c00 volume: Adjust to icon name changes
The headphone icon gained an audio- prefix, use that instead of
the old name.
2013-05-14 14:29:22 +02:00
4d663680d8 Fix build one more time
Third time's the charm.
2013-05-13 18:38:35 -04:00
6505f8e94a Fix build on certain systems
The SCANNERFLAGS were wrong here.
2013-05-13 18:36:36 -04:00
ff3c20dda2 remoteMenu: Minor code cleanups
https://bugzilla.gnome.org/show_bug.cgi?id=700257
2013-05-13 18:34:26 -04:00
c698dee071 remoteMenu: Add support for the submenu show requests
This lets clients defer submenus showing until their submenu model
is ready.

https://bugzilla.gnome.org/show_bug.cgi?id=700257
2013-05-13 18:34:26 -04:00
8891a41793 remoteMenu: Add support for submenu items
Wrap new GtkMenuTracker API that adds an easy way to bind to
tracker items, and use it to add back support for submenus.
This also adds support for a submenu feature that we didn't
have support for before, action namespaces.

https://bugzilla.gnome.org/show_bug.cgi?id=700257
2013-05-13 18:34:26 -04:00
026f61f5aa remoteMenu: Split the tracking code out of RemoteMenu
The tracking logic will be used to more easily implement submenus.

https://bugzilla.gnome.org/show_bug.cgi?id=700257
2013-05-13 18:34:26 -04:00
af063dc2f2 remoteMenu: Allow separator items to have labels
This fixes a regression with remote menus where sections have
labels, like gnome-documents.

https://bugzilla.gnome.org/show_bug.cgi?id=700257
2013-05-13 18:34:26 -04:00
3075f3cfe4 remoteMenu: Add support for extended accessibility roles
https://bugzilla.gnome.org/show_bug.cgi?id=700257
2013-05-13 18:34:26 -04:00
419f2dca15 remoteMenu: Port to GtkMenuTrackerItem
This pulls in new upstream API that Ryan will maintain, removing
code on our side.

Currently, our implementation of submenus will be gone, but this
will be fixed in a few commits.

https://bugzilla.gnome.org/show_bug.cgi?id=700257
2013-05-13 18:34:26 -04:00
5803f69605 popupMenu: Split the remote menu code into its own module
This is getting sufficiently complicated to deserve its own place.

https://bugzilla.gnome.org/show_bug.cgi?id=700257
2013-05-13 18:34:26 -04:00
bfd1cc99a0 Add a separate ShellMenu GIR file for introspecting the copy/paste code
We'll need some of these pieces to be introspectable when we port to
GtkMenuTrackerItem. Due to technical limitations in introspection, we
can't put Gtk-prefixed items in the shell namespace, so add them to
a new introspection library instead.

https://bugzilla.gnome.org/show_bug.cgi?id=700257
2013-05-13 18:34:26 -04:00
a6a2cea414 gtkactionmuxer: Reintroduce the passing of event timestamps
This is a hack we have in our local fork as compared to upstream;
work on a generic "hook" system in here is ongoing, but until then,
this is the easiest way to do it.

https://bugzilla.gnome.org/show_bug.cgi?id=700257
2013-05-13 18:34:26 -04:00
10e857cebe Update copy/paste code from upstream
This includes a rename from the G* namespace to the Gtk* one, which
will help us with introspecting this code. Note that this removes
some of the custom code we added to GActionMuxer to relay event times
to the remote action group. We'll add this back soon.

https://bugzilla.gnome.org/show_bug.cgi?id=700257
2013-05-13 18:34:26 -04:00
ed76b54511 MessageTray: fix typo 2013-05-13 23:41:16 +02:00
9659d056b7 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 21:10:40 +02:00
b79b0952b4 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:41:23 +02:00
fa44dc7d16 MessageTray: don't list the sources all the time
The point of a hash table is that you don't need to list all the
elements. To avoid that, keep a "clearableCount" in MessageTray,
which can be used by the message tray menu to show and hide the
clear item, and that is updated in constant time when sources
are added or removed.

https://bugzilla.gnome.org/show_bug.cgi?id=700194
2013-05-12 21:06:34 +02:00
b0dc841e00 Hash: make .size() constant time
MessageTray calls .size() very often to update the no messages label,
so a linear time implementation is not good enough.

https://bugzilla.gnome.org/show_bug.cgi?id=700194
2013-05-12 21:06:34 +02:00
c72ae375c8 app-system: Remove last real use of shell_app_get_tree_entry
We want to replace our GMenuTreeEntries with GDesktopAppInfos

https://bugzilla.gnome.org/show_bug.cgi?id=698486
2013-05-12 14:45:36 -04:00
0fd6ae5330 app-system: Use g_hash_table_iter_remove
glib now provides an iteration-safe way to remove items from
the hash table, so use it instead of building a separate list.

https://bugzilla.gnome.org/show_bug.cgi?id=698486
2013-05-12 14:44:42 -04:00
c8792ccfa6 app-system: Kill an unused warning
https://bugzilla.gnome.org/show_bug.cgi?id=698486
2013-05-12 14:44:42 -04:00
b689972e67 overview: Don't allow exiting the overview if we have a DND drag
Otherwise, people can drag app icons or window thumbnails out of
the overview, and it just looks weird.

https://bugzilla.gnome.org/show_bug.cgi?id=698484
2013-05-12 14:40:05 -04:00
ae6d7bbfa3 MessageTray: actually respect other components acking notifications
If a notification is marked acknowledged from outside, filter it
out from the queue.

https://bugzilla.gnome.org/show_bug.cgi?id=698812
2013-05-12 20:19:06 +02:00
2591bc90ac ScreenShield: mark music notifications as acknowledged immediately
After all, the user is seeing it (or will see them before unlocking),
so there is no point in queing them as banners.

https://bugzilla.gnome.org/show_bug.cgi?id=698812
2013-05-12 20:19:06 +02:00
61fe000daa 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:19:06 +02:00
c864ebeabb data: Fix typo in Screencast docs 2013-05-10 23:41:36 +02:00
24c530611f 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:01 +02:00
d44d00f0f4 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:01 +02:00
dc3082e66d 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:01 +02:00
c61573a8b7 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:01 +02:00
3b95560d32 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:01 +02:00
990f68375e main: Always pass a default stylesheet when constructing the theme
There is not always a clear distinction between code and style,
which is why the interface ends up being mostly unusable when we
end up without *any* style, for instance because the specified
application-stylesheet is corrupt.
Setting the default stylesheet in addition to the application-stylesheet
is no guarantee for non-default themes not messing up the interface, but
it should at least lower the risk ...

https://bugzilla.gnome.org/show_bug.cgi?id=700097
2013-05-10 19:41:50 +02:00
1290c98c9b 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-10 12:42:18 +02:00
08599afdd4 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-10 13:28:23 +09:00
bb040918e3 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-10 13:25:06 +09:00
6fac33ea7d st-im-text: remove undefined st_im_text_set_autoshow_im decl
https://bugzilla.gnome.org/show_bug.cgi?id=691392
2013-05-10 13:23:51 +09:00
e16c16b3ef workspace: Only show the close buttons for windows that can close
https://bugzilla.gnome.org/show_bug.cgi?id=699269
2013-05-09 15:35:25 -04:00
1eeeead78f 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:28 +01:00
046a1a7af8 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 17:38:21 +02:00
db89648f62 Remove simple uses of ClutterRectangle
https://bugzilla.gnome.org/show_bug.cgi?id=699975
2013-05-09 09:49:12 -04:00
9c839cdc70 dnd: Clean up construction
https://bugzilla.gnome.org/show_bug.cgi?id=699975
2013-05-09 09:49:12 -04:00
938b1ff06a lookingGlass: Remove a useless container
https://bugzilla.gnome.org/show_bug.cgi?id=699975
2013-05-09 09:49:12 -04:00
ecd838bf01 lookingGlass: Remove an unused separator between results
At one time, this may have had styling, but it's not there now,
and I don't see a reason to add it back.

https://bugzilla.gnome.org/show_bug.cgi?id=699975
2013-05-09 09:49:12 -04:00
855a31ff25 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:58:55 +02:00
7464add904 Update libgvc 2013-05-08 21:59:41 -04:00
7514607129 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-08 23:58:53 +02:00
12a1d7b38d keyring: Fix button disabled when prompting for confirmation
https://bugzilla.gnome.org/show_bug.cgi?id=696304
2013-05-08 22:17:43 +02:00
d6fe008b2c 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:17:02 +01:00
d920da6624 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:07:04 +02:00
e2c86cef47 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:07:03 +02:00
8e270dc246 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:34:26 +02:00
22b6a25408 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:58 +02:00
cde695d903 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:58 +02:00
e98eb57e3e 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:58 +02:00
11d997c42b shell-js: Adapt to new gjs interface 2013-05-07 14:35:34 -04:00
eab1ab0fac sessionMode: Remove initial-setup mode
Now that we have external session modes, we can simply
make gnome-initial-setup bundle its own mode.
2013-05-07 14:27:10 -04:00
660b801775 st-bin: Delegate popup-menu signal to child if we have one
This makes it much easier to implement correct popup-menu behavior
in the case of nested bins.

This fixes the context menu key in application search results when a
result has focus.

https://bugzilla.gnome.org/show_bug.cgi?id=699800
2013-05-07 05:14:58 -04:00
eb80503bcc st-theme-node: Make sure that two NULL paint states are not equal
The comment clearly intended that for this to be the case, but a typo
prevented this from actually being done. This fixes the focused state
of the search field not working more than once.

https://bugzilla.gnome.org/show_bug.cgi?id=699799
2013-05-07 02:51:41 -04:00
14ceb10555 dateMenu: do not show "Open Calendar" button with no installed calendar application
https://bugzilla.gnome.org/show_bug.cgi?id=697725
2013-05-06 16:06:33 +01:00
d9a4688e98 panelMenu: Attempt to navigate menus only if we can't navigate inside the menu
This enables key navigation in the calendar.

https://bugzilla.gnome.org/show_bug.cgi?id=667434
2013-05-03 23:20:02 -04:00
092586c931 focus-manager: Add navigate_from_event method
This will be used to implement key navigation inside the calendar without
having to listen to key events manually.

https://bugzilla.gnome.org/show_bug.cgi?id=667434
2013-05-03 23:20:02 -04:00
31478e9fb4 calendar: Ensure clicked calendar item retains key focus
The date actors get destroyed and recreated on every date change which drops
key focus for the selected date. Restore key focus in such a case, but only
when the selected date was actually clicked. Whenever the next/prev month
buttons code is used (for scrolling, mouse click, or keyboard click), have
the corresponding button grab focus. Changing months currently causes the
calendar to update twice as the eventSource gets changed, so key focus gets
lost if it is on a date when the month changes.

https://bugzilla.gnome.org/show_bug.cgi?id=667434
2013-05-03 23:20:02 -04:00
cc7630c236 theme: Add focus styles for the calendar menu
https://bugzilla.gnome.org/show_bug.cgi?id=667434
2013-05-03 23:20:02 -04:00
c29810b2f6 dateMenu: Don't override accessible_role inherited from PanelMenu.Button
The menu is keyboard navigable now, so allow it to be advertised as such.

https://bugzilla.gnome.org/show_bug.cgi?id=667434
2013-05-03 23:20:02 -04:00
c1240d3f2c calendar, dateMenu: Allow focus on menu items
https://bugzilla.gnome.org/show_bug.cgi?id=667434
2013-05-03 23:20:01 -04:00
654f1dd055 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:59:57 +02:00
53c609c278 st-theme-node: Add a to_string function for debugging purposes
https://bugzilla.gnome.org/show_bug.cgi?id=697274
2013-05-03 15:56:05 -04:00
a2fcbb7e65 st-widget: Cache two paint states
In most cases, we'll transition between two states on hover / focus.
Instead of recalculating and repainting our resources on state change,
simply cache the last state when we transition.

https://bugzilla.gnome.org/show_bug.cgi?id=697274
2013-05-03 15:56:05 -04:00
db14dc973a Revert "screenshield: Remove box-shadow"
This reverts commit 98e74dfd38.

https://bugzilla.gnome.org/show_bug.cgi?id=697274
2013-05-03 14:44:04 -04:00
c29aaa047d st-theme-node: Move some allocation-independent textures back to the theme node
The background image, background image shadow and border image are
allocation-indepedent, so we can keep these in the node. Given that these are
are likely cached in the StTextureCache, the slight increase in code complexity
may not be worth caching these textures and materials -- we might be better off
just computing when we need to paint.

https://bugzilla.gnome.org/show_bug.cgi?id=697274
2013-05-03 14:44:03 -04:00
49064ed56d st: Move the theme node drawing state to StWidget
This ensures that two widgets sharing the same theme node won't trample
on each other's prerendered materials if the actors are of different
sizes. This also tries to be very careful to share as much as possible
during a transition.

This has the side effect that if a widget changes state a bunch of times,
we won't cache every state. Since we expect that state changes are
infrequent and that most cases we'll be able to use the texture cache
to do most of the heavy lifting, this cost is much more insignificant
than rendering a number of different actors with the same theme node
and different sizes.

https://bugzilla.gnome.org/show_bug.cgi?id=697274
2013-05-03 10:50:30 -04:00
72bc46d339 st-theme-node-drawing: Move most of the cached paint state to another struct
Since we now share theme nodes between, we shouldn't cache the paint state
across all nodes. As a first step towards putting this in the actor, split
out the state into another structure. Keep it in the theme node for now
so that we don't make too many changes in one commit.

It's possible that some of these pieces of drawing state could be shared
between theme nodes. For the sake of simplicity, assume that none of them
are shared or should be shared. A future commit could identify those that
could be shared and move them back into the theme node.

https://bugzilla.gnome.org/show_bug.cgi?id=697274
2013-05-03 10:50:30 -04:00
40b895d16b st-theme-node-drawing: Depend less on the paint state in some helper functions
We want to put the paint state in the actor rather than in the theme
node, as having two actors with different sizes but the same theme node
is now much less efficient.

https://bugzilla.gnome.org/show_bug.cgi?id=697274
2013-05-03 10:50:30 -04:00
33cad9a824 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:26:00 -04:00
e96d9e0ea1 st-icon: check if gicon is null before unref.
Commit a6b49fe7d6
introduced a check for equality of priv->gicon vs gicon
and unref then return early if so. But if both are null,
we should not unref gicon. Only return.

https://bugzilla.gnome.org/show_bug.cgi?id=698863
2013-05-02 09:51:32 +02:00
ed63bda932 Updated Slovenian translation 2013-05-01 20:34:15 +02:00
18107d567d Bump version to 3.9.1
Update NEWS.
2013-04-30 23:58:35 +02:00
608818fa9f Only recognize common url schemes in notification messages
Before the fix, the message tray highlighted all urls containing "://", even
invalid ones. This change fixes this by have the message tray highlight only
the urls with http, https, ftp schemes.

Credit goes to: Phuong Vu, Liye Fu, Monica Chelliah, Owen Taylor

https://bugzilla.gnome.org/show_bug.cgi?id=661225
2013-04-29 11:22:44 -04:00
9ae2440ec1 Remove LayoutManager::fullscreen-changed
Since we now have global.screen::in-fullscreen-changed, remove the
duplicate signal. To prevent ordering problems in connecting to
this signal, make inFullscreen a property-function of a new Monitor
object rather than a data property we tack on to a Rectangle object.

https://bugzilla.gnome.org/show_bug.cgi?id=649748
2013-04-29 11:17:29 -04:00
ef9c50e63a 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:19:59 +02:00
5d50b08351 Updated Lithuanian translation 2013-04-28 13:37:01 +03:00
123fc19c4e configure: Bump NetworkManager requirement
Since commit 871c28aeeb, NMGtk is no longer optional, so
bump the requirement accordingly.

https://bugzilla.gnome.org/show_bug.cgi?id=699075
2013-04-27 22:51:15 +02:00
a9058e471c WorkspacesView: set the actual geometry when creating workspaces
If we created a workspace after showing the view, we would never
set the geometry on it, which would cause an exception in the
window layout code and leave the DND state tracking in an undefined
state.

https://bugzilla.gnome.org/show_bug.cgi?id=699029
2013-04-27 15:09:19 +02:00
bd1f48d9fe Updated Czech translation 2013-04-27 01:55:09 +02:00
66ab4d217d Updated Czech translation 2013-04-26 19:19:39 +02:00
7a8b392607 network: Remove some genericism in the wireless code
This was presumably originally used in multiple places, but it's
not anymore, so un-generify the code here.

https://bugzilla.gnome.org/show_bug.cgi?id=698918
2013-04-26 12:24:03 -04:00
bfdf069d2d network: Rename "apObj" to "network"
We put these "access point objects" in "this._networks" and
"this._activeNetwork", so let's rename it. This also makes
the fact that each "access point object" can contain multiple
access points a tiny bit less confusing.

https://bugzilla.gnome.org/show_bug.cgi?id=698918
2013-04-26 12:18:39 -04:00
b4b00a48d9 network: Remove explicit autoconnection code
NM is now a lot smarter about dealing with automatic connections, so just
create an empty connection and pass it to it. The only places where NM
requires connection settings is where we require explicit setup: Bluetooth
DUN, WPA-Enterprise and WWAN/VPN. These cases are already handled by
gnome-control-center, where complex configuration is handled, so remove
the automatic connection management for now and just let NM handle it.

https://bugzilla.gnome.org/show_bug.cgi?id=698918
2013-04-26 12:16:06 -04:00
e5f226612e network: Use activeApChanged to get the initial active network
https://bugzilla.gnome.org/show_bug.cgi?id=698918
2013-04-26 12:16:06 -04:00
20619ad3c1 network: Fix some splice mishaps
Calling splice() without a second argument removes all of the elements
after the provided index, not just one.

https://bugzilla.gnome.org/show_bug.cgi?id=698918
2013-04-26 12:16:06 -04:00
37dce7d4c3 network: Deduplicate some similar code
https://bugzilla.gnome.org/show_bug.cgi?id=698918
2013-04-26 12:16:06 -04:00
a67b82e730 network: Remove some dead code
We cannot possibly reach createActiveConnectionItem unless we have
an active network, so the plain unreative menu item cannot ever
be created.

https://bugzilla.gnome.org/show_bug.cgi?id=698918
2013-04-26 12:16:05 -04:00
e0b8ad7911 network: Remove UNKNOWN security type
It's unused.

https://bugzilla.gnome.org/show_bug.cgi?id=698918
2013-04-26 12:16:05 -04:00
dbb39d366e network: Properly disconnect from the state-changed signal
The destroy signal never gets emitted, so we need to properly
disconnect manually when we destroy the wrapper.

https://bugzilla.gnome.org/show_bug.cgi?id=698918
2013-04-26 12:16:05 -04:00
e1de36398d network: Remove some unused helpers
https://bugzilla.gnome.org/show_bug.cgi?id=698918
2013-04-26 12:16:05 -04:00
871c28aeeb network: Require NMGtk
Enough time has passed that we can safely depend on NMGtk in the new
network implementation.

https://bugzilla.gnome.org/show_bug.cgi?id=698918
2013-04-26 12:16:05 -04:00
c84dc6254d 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 17:50:06 +02:00
60cb1ad7c5 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 17:32:54 +02:00
4a5ff5dcfb 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 17:32:53 +02:00
5c40307745 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 17:32:53 +02:00
39426f03e6 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 17:32:52 +02:00
92e5d2b8f5 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:23:37 -04:00
09aa59f98b layout: Correct hot corner barriers in RTL layouts
https://bugzilla.gnome.org/show_bug.cgi?id=698884
2013-04-26 11:23:37 -04:00
c9c1c89a27 dateMenu: append .desktop to evolution strings
Since that is what the actual app_id's are.
2013-04-26 16:54:45 +10:00
96b76709e9 session: Remove the clock from initial setup mode
If you're in the initial setup mode you're not likely to have the
correct time displayed.
2013-04-25 11:52:02 +01:00
ca3107e21b Updated Greek translation 2013-04-25 08:12:32 +03:00
2e4f223207 Updated Malayalam Translation 2013-04-25 08:26:22 +05:30
17df668186 remoteSearch: support serialized GIcons
Since [1], GIO supports generic serialization and deserialization of a
GIcon into a GVariant. This is also implemented by GdkPixbuf and could be
used instead of our homegrown code for it.

This commit adds support to another 'icon' key in the metas dictionary
returned by applications for it. The previous 'gicon' and 'icon-data'
keys are still parsed and supported as before, but are now deprecated.

[1]
https://git.gnome.org/browse/glib/commit/?id=c16f914b40c749b938490a4e10a3c54ec1855c42

https://bugzilla.gnome.org/show_bug.cgi?id=698761
2013-04-24 15:54:31 -04:00
aef70152de 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-04-24 21:47:03 +02:00
e0252f35be workspace: Sort windows when we calculate slots
This ensures that windows don't change positions when we lay
them out again when expanding the workspace switcher.

https://bugzilla.gnome.org/show_bug.cgi?id=698776
2013-04-24 14:10:30 -04:00
0f47534766 Forgot ia.po file 2013-04-24 15:55:12 +02:00
54feaa67e8 [l10n] Add Interlingua translation 2013-04-24 15:53:43 +02:00
64ecfa49eb layout: Ensure that the hotCorners array is always indexable by monitor number
messageTray relies on indexing the hot corners array by monitor number,
so we should make this a guarantee.

https://bugzilla.gnome.org/show_bug.cgi?id=698513
2013-04-23 19:14:01 -04:00
fdae613b14 messageTray: Take modal grabs for the context menu and notification boxpointer
As the context menu and notification boxpointer can only appear if we already
take a modal grab, grabFocus will have problematic results if the focus does
somehow change.

https://bugzilla.gnome.org/show_bug.cgi?id=698483
2013-04-23 16:33:13 -04:00
c57c08b2c6 popupMenu: Fix a bad rebase
The wrong patch got pushed accidentally here
2013-04-23 16:33:13 -04:00
d2103995cb popupMenu: Remove some now-unused code
We don't have any sections with separators, so don't bother
tracking them.

https://bugzilla.gnome.org/show_bug.cgi?id=698427
2013-04-23 15:50:36 -04:00
196fb0f16e popupMenu: Add and use GtkMenuTracker to build the remote menu
This simplifies the code required to build remote menus and
put all the items in the right place, and makes us share our
implementation with GTK+.

https://bugzilla.gnome.org/show_bug.cgi?id=698427
2013-04-23 15:50:36 -04:00
c0afe7260a popupMenu: Create and insert menu items that don't have actions yet
Instead of recreating the entire model, which can be expensive... but
keep them insensitive for now. This also matches what GTK+ does.

https://bugzilla.gnome.org/show_bug.cgi?id=698427
2013-04-23 15:50:36 -04:00
099c8703ae popupMenu: Always use a PopupMenuItem
By this point, we'll know we'll always have a PopupMenuItem.

https://bugzilla.gnome.org/show_bug.cgi?id=698427
2013-04-23 15:50:36 -04:00
b03e480dbf popupMenu: Use a checkmark for boolean items
This matches GTK+'s styling, and it makes most boolean switches
look more natural, as a lot of booleans are not meant for hardware
switches.

https://bugzilla.gnome.org/show_bug.cgi?id=698427
2013-04-23 15:50:36 -04:00
8430353389 popupMenu: Add a check ornament
This will be used to replace switches in the remote menu

https://bugzilla.gnome.org/show_bug.cgi?id=698427
2013-04-23 15:50:36 -04:00
a123ec94ef popupMenu: Use a unicode character for the ornament
This makes it easy to replace the dot with another label in the future.
Change the allocation logic, as text layout is more complicated than
simple icon logic.

https://bugzilla.gnome.org/show_bug.cgi?id=698427
2013-04-23 15:50:36 -04:00
4a2f54f6ff popupMenu: Define the dot next to the menu as an "ornament"
We want to remove switches in remote menus, so make way for
a checkmark ornament for the popup menu item.

https://bugzilla.gnome.org/show_bug.cgi?id=698427
2013-04-23 15:35:55 -04:00
b5c85eaeca messageTray: Fix a regression from 1b13509
It seems this rename somehow got lost in a rebase.
2013-04-22 19:22:33 -04:00
8b3b91d78d workspace: Invalidate the current layout when windows are added or removed
If windows are removed or added, we shouldn't keep the old layout, as it's
not valid anymore. If windows are removed, this is especially bad, as the
rows contain references to the removed window objects, causing crashes.

https://bugzilla.gnome.org/show_bug.cgi?id=698622
2013-04-22 18:33:34 -04:00
e1de3973fe workspace: Recalculate window positions when we have no layout
If for any reason the current layout is invalidated, queue a
reposition.

https://bugzilla.gnome.org/show_bug.cgi?id=698622
2013-04-22 18:33:34 -04:00
c1993a6ffc overview: Fix XDnD
I accidentally removed this import which some XDnD code depends upon.
2013-04-22 18:24:02 -04:00
ab26fc438a workspace: only scale a layout row when it doesn't fit
Instead of applying an additional scale factor to all the rows in the
layout, only do it for those rows that don't fit.
This avoids the visual distraction of resizing a row when there's no
need to.
2013-04-22 18:06:09 -04:00
c37259b01d workspace: Lay out windows based on the real allocation
Instead of doing an entire recalculation of window positions when
sliding the thumbnails box, simply recalculate the position and scale
with basic aspect ratio math. This also ensures that windows won't
miraculously swap positions, even if we reposition windows while the
thumbnails box is expanded.

https://bugzilla.gnome.org/show_bug.cgi?id=694469
2013-04-22 14:01:00 -04:00
bde8cc3285 workspace: Split out window repositioning logic and rename
Split out the part that moves the window clones around from
the part that calculates the window clone positions, and rename
both methods so that the overall meaning is more clear.

https://bugzilla.gnome.org/show_bug.cgi?id=694469
2013-04-22 14:01:00 -04:00
59ba5504d0 workspace: Calculate the window slots when we reposition
Repositioning will eventually be separated from recalculation
to accomodate two different geometries, so we'll need to do
the padding and area manipulation in two different areas.

https://bugzilla.gnome.org/show_bug.cgi?id=694469
2013-04-22 14:01:00 -04:00
65eb5a3d05 workspace: Separate out spacing/padding code
This will be used when we introduce the second geometry.

https://bugzilla.gnome.org/show_bug.cgi?id=694469
2013-04-22 14:01:00 -04:00
b925322e9e workspace: Make room for a second geometry to keep track of
As we want to eventually track two geometries, we need to rename
our very plain "_x, _y, _width, _height". While we could just prefix
them, I think that stuffing them in an object makes more sense.

At the same time, make the variable and method name more descriptive
by adding such a prefix, as well as a bit of documentation.

https://bugzilla.gnome.org/show_bug.cgi?id=694469
2013-04-22 14:01:00 -04:00
f0c2ad00f8 workspacesView: Calculate the workspaces geometry ourselves
To ensure that we don't recalculate window layouts when zooming
in or out, we need to always pass the full geometry. This will
break window repositioning when we zoom back in; for the purposes
of commit clarity, this breaks this feature for now. It will be
added back soon.

https://bugzilla.gnome.org/show_bug.cgi?id=694469
2013-04-22 14:00:59 -04:00
fc53a25a4c overviewControls: Add an accessor for the visible-width property
To add a geometry that's independent of the slide factor of the workspace,
we need to get this from outside the sliding control.

https://bugzilla.gnome.org/show_bug.cgi?id=694469
2013-04-22 14:00:59 -04:00
58872d162b AppDisplay/FrequentView: filter out hidden applications
Filter out all applications which have the NoDisplay, Hidden or
Not/OnlyShowIn bits, as those are not meant to be launched directly.
This also allows the user to filter apps from the frequent view
using alacarte.

https://bugzilla.gnome.org/show_bug.cgi?id=696949
2013-04-22 19:11:17 +02:00
30f1b8f02a Updated Spanish translation 2013-04-22 17:52:13 +02:00
ee4f199a9f 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-04-22 10:14:48 +10:00
e3957f3bac workspacesView: Make setGeometry take a rectangle
This cleanup will be more important in the future,
but for now, we can simply pass a monitor.

https://bugzilla.gnome.org/show_bug.cgi?id=694469
2013-04-20 08:33:26 -04:00
2506673514 workspacesView: Minor cleanup
https://bugzilla.gnome.org/show_bug.cgi?id=694469
2013-04-20 08:33:26 -04:00
7cb12015fd workspacesView: Fix indentation
https://bugzilla.gnome.org/show_bug.cgi?id=694469
2013-04-20 08:33:26 -04:00
caaac9b9ec workspace: Do window slot computing in three steps
This ensures that we have the correct Y value when sorting
windows.

https://bugzilla.gnome.org/show_bug.cgi?id=694469
2013-04-20 08:33:26 -04:00
1dac4d00c4 workspace: Abort relayouting much earlier
This means that the code for computeAllWindowSlots is a bit
cleaner, which will help in the future.

https://bugzilla.gnome.org/show_bug.cgi?id=694469
2013-04-20 08:33:26 -04:00
b41902f4df workspace: Only create one strategy
Now that we don't have any other strategies but the unaligned
one, we only need to construct it once.

https://bugzilla.gnome.org/show_bug.cgi?id=694469
2013-04-20 08:33:26 -04:00
ada70dd683 workspace: Remove more dead code
By the time zoomToOverview is called, an animation will
always be in progress.

https://bugzilla.gnome.org/show_bug.cgi?id=694469
2013-04-20 08:33:26 -04:00
7e5d8a8d54 workspace: Make positionWindows private
It's not used outside, and it's going to be broken up soon.

https://bugzilla.gnome.org/show_bug.cgi?id=694469
2013-04-20 08:33:26 -04:00
e981cae27c workspace: Don't save the current layout
This was saved so that doing something which called relayout
but only changed the area rectangle would simply be needed to
recompute window scaling parameters. With the new overview
relayout, the flow control changed, it turns out that the
current layout is always cleared. Remove this for now, and we'll
put in a different strategy for this.

https://bugzilla.gnome.org/show_bug.cgi?id=694469
2013-04-20 08:33:26 -04:00
d7c377c229 workspace: Use Workspace.WindowPositionFlags.NONE in another case
https://bugzilla.gnome.org/show_bug.cgi?id=694469
2013-04-20 08:33:26 -04:00
8772edcd33 overview: Move the group construction to the controls manager
Instead of creating a bunch of random actors and then passing
them off to the controls manager, let the controls manager
construct them. This leaves the controls manager in charge
of the ordeal.

https://bugzilla.gnome.org/show_bug.cgi?id=694469
2013-04-20 08:33:25 -04:00
254740cf68 [l10n] Updated Turkish translation 2013-04-20 00:44:55 +03:00
c3775c0f56 st-theme-node: Disable transitions if animations-enabled is off
https://bugzilla.gnome.org/show_bug.cgi?id=698391
2013-04-19 14:34:06 -04:00
5ecf40e967 panel: show spinner animation for busy applications
When the active application signals its busy state, we now will show a
spinner on the panel, next to the application name.

https://bugzilla.gnome.org/show_bug.cgi?id=697207
2013-04-19 13:54:56 -04:00
45026df4bd shell-app: track the busy state of GApplications
Watch for property changes on the org.gtk.Application interface, and
transition the state to BUSY when the corresponding property is flipped
on.

https://bugzilla.gnome.org/show_bug.cgi?id=697207
2013-04-19 13:54:56 -04:00
b8830f4a09 shell-app: don't recreate a session proxy every time
Cache the connection inside the ShellAppRunningState structure instead.

https://bugzilla.gnome.org/show_bug.cgi?id=697207
2013-04-19 13:54:56 -04:00
811ee1d989 Revert "messageTray: Don't show the context-menu when the tray isn't open"
This reverts commit 1bce210c51.
2013-04-19 13:38:41 -04:00
8c32102e99 messageTray: Move the notification actor out of the tray
Putting the notification actor in the tray actor has caused a lot
of various bugs and glitches over the years related to syncing the
two, fizzling out events, and so on. It's a much simpler model if
we consider the notification actor and tray to be separate widgets.

As a side effect, this makes the context menu not pop up when we
right-click on notifications.

https://bugzilla.gnome.org/show_bug.cgi?id=695800
2013-04-19 13:38:41 -04:00
1b135095c7 messageTray: Move hover tracking to the notification widget
This does nothing while the tray is active, so it doesn't make sense
to track it on the tray. This also makes the code a lot easier to read,
with notification behavior being labeled "notification" rather than
"tray".

https://bugzilla.gnome.org/show_bug.cgi?id=695800
2013-04-19 13:38:41 -04:00
becf4396c9 Disable naked Super keybinding if sticky
With sticky keys, users should be able to press and release a
modifier and then press a key to activate a modifier-key combination.
Activating the overview on the Super key release keeps these
users from using keyboard shortcuts involving the Super modifier.

The solution implemented here is to simply disable the Super-release
binding if sticky keys are enabled. It is still possible to go
to the overview by using Super-S or Alt-F1.
https://bugzilla.gnome.org/show_bug.cgi?id=685974
2013-04-19 10:25:28 -04:00
929e066506 Add a toggle-overview keybinding
This is a new, regular keybinding for going to the overview.
The default binding is Super-S, which goes well with Super-A
for going to the application grid.
This is separate from the existing panel-main-menu keybinding,
so that we can keep Alt-F1 opening the main menu in classic mode.

https://bugzilla.gnome.org/show_bug.cgi?id=698251
2013-04-18 20:34:41 -04:00
355ad9ac2c Updated Galician translations 2013-04-18 03:23:16 +02: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
142 changed files with 14652 additions and 9558 deletions

135
NEWS
View File

@ -1,3 +1,138 @@
3.9.3
=====
* Don't push window thumbs when workspace switcher is hidden [Jasper; #701167]
* Tweak timeout for activating windows during XDND [Adel; #700150]
* 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]
* window-switcher: Only show windows from current workspace by default
[Florian; #701214]
* logout dialog: Show the correct text right away [Matthias; #702056]
* bluetooth: Port to bluez 5 [Emilio; #700891]
* dateMenu: Allow events to span multiple lines [Giovanni; #701231]
* gdm: Clear message queue when no more messages are pending [Jonh; #702458]
* Misc bug fixes and cleanups [Jasper, Florian, Adel, Giovanni; #693836,
#700972, #701386, #700877, #701755, #698918, #701224, #702125, #701954,
#701849, #702121]
Contributors:
Giovanni Campagna, Matthias Clasen, Fran Diéguez, Adel Gadllah, Rui Matos,
Florian Müllner, Emilio Pozuelo Monfort, Carlos Soriano, Jasper St. Pierre,
Jonh Wendell
Translations:
Marek Černocký [cs], Victor Ibragimov [tg], Fran Diéguez [gl],
Benjamin Steinwender [de], Cheng-Chia Tseng [zh_HK, zh_TW],
eternalhui [zh_CN], Ivaylo Valkov [bg], Kjartan Maraas [nb],
Daniel Mustieles [es]
3.9.2
=====
* Use a symbolic icon for DESKTOP windows [Matthias; #697914]
* Move paint state cache into StWidget [Jasper; #697274]
* gdm: Fix regression where domain login hint not shown [Stef; #698200]
* Make calendar keyboard navigable [Tanner; #667434]
* 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]
* overview: Only show close buttons for windows that may close [Jasper; #699269]
* Add input purpose and hints to StEntry and StIMText [Daiki; #691392]
* Set input-purpose property for password entries [Rui; #700043]
* Provide a DBus API for screencasting [Florian; #696247]
* overview: Disable hotcorner during DND [Jasper; #698484]
* polkitAgent: Allow retrying after mistyped passwords [Stef; #684431]
* Add a way to get backtraces from criticals and warnings [Giovanni; #700262]
* Allow switch-to-workspace-n keybindings in overview [Florian; #649977]
* Update man page [Matthias; #700339]
* Add FocusSearch DBus method [Florian; #700536]
* Hide frequent view when app monitoring is disabled [Florian; #699714]
* Show switcher popup for switch-to-workspace-n keybindings [Elad; #659288]
* gdm: Update the session chooser style [Allan; #695742]
* Fix some app folders getting truncated at the top [Florian; #694371]
* Don't block the message tray while a notification is showing [Jasper; #700639]
* popupMenu: Allow for an optional border for slider handle [Florian; #697917]
* Re-lock screen when restarted after a crash [Colin; #691987]
* 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]
* Misc bug fixes and cleanups [Alban, Jasper, Giovanni, Florian, Rui, Tomeu,
Stef, Gustavo; #698863, #699799, #699800, #676285, #699975, #700097, #698812,
#698486, #700194, #695314, #700257, #699678, #700356, #700322, #700394,
#700409, #700595, #700625, #691746, #700620, #700807, #659288, #700784,
#700842, #700847, #700488, #700735, #696159, #700900, #700853, #700923,
#700944, #697661, #700854, #700190, #699189, #701097]
Contributors:
Elad Alfassa, Alban Browaeys, Giovanni Campagna, Matthias Clasen, Allan Day,
Tanner Doshier, Lionel Landwerlin, Rui Matos, Simon McVittie,
Marta Milakovic, Florian Müllner, Gustavo Padovan, Jasper St. Pierre,
Daiki Ueno, Tomeu Vizoso, Stef Walter, Colin Walters
Translations:
Matej Urbančič [sl], Kjartan Maraas [nb], Victor Ibragimov [tg],
Dušan Kazik [sk], Gil Forcada [ca], Daniel Mustieles [es]
3.9.1
=====
* Add additional toggle-overview keybinding [Matthias; #698251]
* Disable <super> shortcut when sticky keys are enabled [Matthias; #685974]
* Disable tray context menu while a notification displays [Jasper; #695800]
* Watch GApplication busy state [Cosimo; #697207]
* Disable style transitions if animations are disabled [Jasper; #698391]
* Filter out hidden applications from "Frequent" view [Giovanni; #696949]
* Fix window previews swapping place randomly [Jasper; #694469, #698776]
* Add support for serialized GIcons in remote search providers [Cosimo; #698761]
* 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]
* Only recognize common URL schemes in notification messages [Monica; #661225]
* Misc fixes and cleanups [Tim, Jasper, Florian, Giovanni, Owen; #698531,
#698622, #698427, #698483, #698513, #697203, #698959, #698918, #699029,
#699075, #696720, #649748]
Contributors:
Giovanni Campagna, Cosimo Cecchi, Monica Chelliah, Matthias Clasen, Tim Lunn,
Florian Müllner, Jasper St. Pierre, Michael Wood, Owen W. Taylor
Translations:
Fran Diéguez [gl], Muhammet Kara [tr], Daniel Mustieles [es],
Gil Forcada [ia], Anish A [ml], Dimitris Spingos [el], Marek Černocký [cs],
Žygimantas Beručka [lt]
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]

View File

@ -1,5 +1,5 @@
AC_PREREQ(2.63)
AC_INIT([gnome-shell],[3.8.0.1],[https://bugzilla.gnome.org/enter_bug.cgi?product=gnome-shell],[gnome-shell])
AC_INIT([gnome-shell],[3.9.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,18 +63,18 @@ 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.8.0
MUTTER_MIN_VERSION=3.9.3
GTK_MIN_VERSION=3.7.9
GIO_MIN_VERSION=2.35.0
GIO_MIN_VERSION=2.37.0
LIBECAL_MIN_VERSION=3.5.3
LIBEDATASERVER_MIN_VERSION=3.5.3
TELEPATHY_GLIB_MIN_VERSION=0.17.5
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
NETWORKMANAGER_MIN_VERSION=0.9.8
PULSE_MIN_VERS=2.0
# Collect more than 20 libraries for a prize!
@ -96,7 +96,7 @@ PKG_CHECK_MODULES(GNOME_SHELL, gio-unix-2.0 >= $GIO_MIN_VERSION
polkit-agent-1 >= $POLKIT_MIN_VERSION xfixes
libnm-glib libnm-util >= $NETWORKMANAGER_MIN_VERSION
libnm-gtk >= $NETWORKMANAGER_MIN_VERSION
libsecret-unstable 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)
@ -109,7 +109,7 @@ PKG_CHECK_MODULES(DESKTOP_SCHEMAS, gsettings-desktop-schemas >= 3.7.4)
PKG_CHECK_MODULES(CARIBOU, caribou-1.0 >= 0.4.8)
AC_MSG_CHECKING([for bluetooth support])
PKG_CHECK_EXISTS([gnome-bluetooth-1.0 >= 3.1.0],
PKG_CHECK_EXISTS([gnome-bluetooth-1.0 >= 3.9.0],
[BLUETOOTH_DIR=`$PKG_CONFIG --variable=applet_libdir gnome-bluetooth-1.0`
BLUETOOTH_LIBS=`$PKG_CONFIG --variable=applet_libs gnome-bluetooth-1.0`
AC_SUBST([BLUETOOTH_LIBS],["$BLUETOOTH_LIBS"])

View File

@ -11,6 +11,9 @@
<KeyListEntry name="focus-active-notification"
_description="Focus the active notification"/>
<KeyListEntry name="toggle-overview"
_description="Show the overview"/>
<KeyListEntry name="toggle-application-view"
_description="Show all applications"/>

View File

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

@ -46,7 +46,7 @@
<!--
GetResultMetas:
@identifiers: An array of result identifiers as returned by GetInitialResultSet() or GetSubsearchResultSet()
@metas: A dictionary describing the given search result, containing a human-readable 'name' (string), along with the result identifier this meta is for, 'id' (string). Optionally, either 'gicon' (a serialized GIcon) or 'icon-data' (raw image data as (iiibiiay) - width, height, rowstride, has-alpha, bits per sample, channels, data) can be specified if the result can be better served with a thumbnail of the content (such as with images). A 'description' field (string) may also be specified if more context would help the user find the desired result.
@metas: A dictionary describing the given search result, containing a human-readable 'name' (string), along with the result identifier this meta is for, 'id' (string). Optionally, 'icon' (a serialized GIcon as obtained by g_icon_serialize) can be specified if the result can be better served with a thumbnail of the content (such as with images). 'gicon' (a serialized GIcon as obtained by g_icon_to_string) or 'icon-data' (raw image data as (iiibiiay) - width, height, rowstride, has-alpha, bits per sample, channels, data) are deprecated values that can also be used for that purpose. A 'description' field (string) may also be specified if more context would help the user find the desired result.
Return an array of meta data used to display each given result
-->

View File

@ -21,16 +21,6 @@
EnableExtension and DisableExtension DBus methods on org.gnome.Shell.
</_description>
</key>
<key name="enable-app-monitoring" type="b">
<default>true</default>
<_summary>Whether to collect stats about applications usage</_summary>
<_description>
The shell normally monitors active applications in order to present
the most used ones (e.g. in launchers). While this data will be
kept private, you may want to disable this for privacy reasons.
Please note that doing so won't remove already saved data.
</_description>
</key>
<key name="favorite-apps" type="as">
<default>[ 'epiphany.desktop', 'evolution.desktop', 'empathy.desktop', 'rhythmbox.desktop', 'shotwell.desktop', 'libreoffice-writer.desktop', 'nautilus.desktop', 'gnome-documents.desktop' ]</default>
<_summary>List of desktop file IDs for favorite applications</_summary>
@ -117,6 +107,13 @@ value here is from the GsmPresenceStatus enumeration.</_summary>
Overview.
</_description>
</key>
<key name="toggle-overview" type="as">
<default>["&lt;Super&gt;s"]</default>
<_summary>Keybinding to open the overview</_summary>
<_description>
Keybinding to open the Activities Overview.
</_description>
</key>
<key name="toggle-message-tray" type="as">
<default>["&lt;Super&gt;m"]</default>
<_summary>Keybinding to toggle the visibility of the message tray</_summary>
@ -207,7 +204,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

@ -123,8 +123,26 @@ StScrollBar StButton#vhandle:active {
background-image: url("checkbox-focused.svg");
}
/* Slider */
.slider {
height: 1em;
min-width: 15em;
-slider-height: 0.3em;
-slider-background-color: #333333;
-slider-border-color: #5f5f5f;
-slider-active-background-color: #76b0ec;
-slider-active-border-color: #1f6dbc;
-slider-border-width: 1px;
-slider-handle-radius: 0.5em;
}
/* PopupMenu */
.popup-menu-ornament {
text-align: center;
}
.popup-menu-boxpointer,
.candidate-popup-boxpointer {
-arrow-border-radius: 8px;
@ -218,18 +236,6 @@ StScrollBar StButton#vhandle:active {
font-weight: bold;
}
.popup-slider-menu-item {
height: 1em;
min-width: 15em;
-slider-height: 0.3em;
-slider-background-color: #333333;
-slider-border-color: #5f5f5f;
-slider-active-background-color: #76b0ec;
-slider-active-border-color: #1f6dbc;
-slider-border-width: 1px;
-slider-handle-radius: 0.5em;
}
.popup-device-menu-item {
spacing: .5em;
}
@ -512,6 +518,7 @@ StScrollBar StButton#vhandle:active {
}
#appMenu {
spinner-image: url("process-working.svg");
spacing: 4px;
}
@ -799,6 +806,11 @@ StScrollBar StButton#vhandle:active {
height: 24px;
}
.empty-dash-drop-target {
width: 24px;
height: 24px;
}
/* Search Box */
#searchEntry {
@ -886,12 +898,11 @@ StScrollBar StButton#vhandle:active {
}
.app-view-controls {
width: 250px;
padding-bottom: 32px;
}
.app-view-control {
padding: 4px 16px;
padding: 4px 32px;
}
.search-display > StBoxLayout,
@ -1143,9 +1154,9 @@ StScrollBar StButton#vhandle:active {
/* Calendar popup */
#calendarEventsArea {
/* this is the width of the second column of the popup */
min-width: 320px;
#calendarArea {
/* this is the total width of the popup */
width: 720px;
}
.calendar-vertical-separator {
@ -1183,7 +1194,8 @@ StScrollBar StButton#vhandle:active {
background-image: url("calendar-arrow-right.svg");
}
.calendar-change-month-back:hover {
.calendar-change-month-back:hover,
.calendar-change-month-back:focus {
background-color: #999999;
}
.calendar-change-month-back:active {
@ -1201,7 +1213,8 @@ StScrollBar StButton#vhandle:active {
background-image: url("calendar-arrow-left.svg");
}
.calendar-change-month-forward:hover {
.calendar-change-month-forward:hover,
.calendar-change-month-forward:focus {
background-color: #999999;
}
.calendar-change-month-forward:active {
@ -1222,7 +1235,8 @@ StScrollBar StButton#vhandle:active {
height: 2.4em;
}
.calendar-day-base:hover {
.calendar-day-base:hover,
.calendar-day-base:focus {
background-color: #777777;
}
@ -1281,32 +1295,40 @@ StScrollBar StButton#vhandle:active {
color: #333333;
}
.events-header-vbox {
spacing: 6pt;
padding-right: .5em;
.events-table {
min-width: 320px;
spacing-columns: 6pt;
padding: 0 1.4em;
}
.events-header-vbox:rtl {
padding-left: .5em;
.events-table:ltr {
padding-right: 1.9em;
}
.events-header-hbox {
padding: 0.3em 1.4em;
.events-table:rtl {
padding-left: 1.9em;
}
.events-day-header {
font-weight: bold;
color: #999999;
padding: 0.4em 1.4em 0em 1.4em;
padding-left: 0.4em;
padding-top: 1.2em;
}
.events-day-header:first-child {
padding-top: 0;
}
.events-day-header:rtl {
padding: 0em 1.4em 0.4em 1.4em;
padding-left: 0;
padding-right: 0.4em;
}
.events-day-dayname {
color: rgba(153, 153, 153, 1.0);
text-align: left;
min-width: 20px;
}
.events-day-dayname:rtl {
@ -1324,23 +1346,12 @@ StScrollBar StButton#vhandle:active {
.events-day-task {
color: rgba(153, 153, 153, 1.0);
padding-left: 8pt;
}
.events-day-name-box {
min-width: 15pt;
}
.events-time-box {
min-width: 48pt;
padding-right: 12pt;
}
.events-time-box:rtl {
padding-right: 0px;
padding-left: 12pt;
}
.events-event-box {
.events-day-task:rtl {
padding-left: 0px;
padding-right: 8pt;
}
.url-highlighter {
@ -1453,11 +1464,13 @@ StScrollBar StButton#vhandle:active {
}
.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 {
@ -2335,52 +2348,47 @@ StScrollBar StButton#vhandle:active {
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 {

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

@ -68,6 +68,7 @@ nobase_dist_js_DATA = \
ui/sessionMode.js \
ui/shellEntry.js \
ui/shellMountOperation.js \
ui/slider.js \
ui/notificationDaemon.js \
ui/osdWindow.js \
ui/overview.js \
@ -77,7 +78,9 @@ nobase_dist_js_DATA = \
ui/pointerWatcher.js \
ui/popupMenu.js \
ui/remoteSearch.js \
ui/remoteMenu.js \
ui/runDialog.js \
ui/screencast.js \
ui/screenshot.js \
ui/screenShield.js \
ui/scripting.js \

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,53 +40,17 @@ 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;
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',
@ -103,8 +68,8 @@ const UserListItem = new Lang.Class({
x_align: St.Align.START,
x_fill: true });
this._userAvatar = new UserMenu.UserAvatarWidget(this.user,
{ styleClass: 'login-dialog-user-list-item-icon' });
this._userAvatar = new UserWidget.Avatar(this.user,
{ styleClass: 'login-dialog-user-list-item-icon' });
layout.add(this._userAvatar.actor);
let textLayout = new St.BoxLayout({ style_class: 'login-dialog-user-list-item-text-box',
vertical: true });
@ -552,6 +517,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 });
@ -609,7 +580,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',
@ -644,6 +614,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() {
@ -690,6 +665,24 @@ 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();
@ -708,7 +701,7 @@ const LoginDialog = new Lang.Class({
this._promptEntry.text = '';
this._updateSensitivity(true);
this._setWorking(false);
this.setWorking(false);
},
_onDefaultSessionChanged: function(client, sessionId) {
@ -774,10 +767,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();
@ -790,12 +779,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();
}),
@ -848,7 +836,7 @@ const LoginDialog = new Lang.Class({
this._promptEntryActivateId = 0;
}
this._setWorking(false);
this.setWorking(false);
this._promptBox.hide();
this._promptLoginHint.hide();
@ -861,36 +849,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);
@ -905,7 +866,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);
}];
@ -913,17 +874,40 @@ 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);

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

@ -9,7 +9,6 @@ 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;
@ -117,7 +116,6 @@ 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;
@ -166,6 +164,7 @@ const ShellUserVerifier = new Lang.Class({
answerQuery: function(serviceName, answer) {
if (!this._userVerifier.hasPendingMessages) {
this._clearMessageQueue();
this._userVerifier.call_answer_query(serviceName, answer, this._cancellable, null);
} else {
let signalId = this._userVerifier.connect('no-more-messages',
@ -377,30 +376,11 @@ const ShellUserVerifier = new Lang.Class({
this._queueMessage(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));
}
},
_onInfoQuery: function(client, serviceName, question) {
// We only expect questions to come from the main auth service
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, '');
},
@ -476,11 +456,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

@ -58,6 +58,7 @@ const Map = new Lang.Class({
_init: function(iterable) {
this._pool = { };
this._size = 0;
if (iterable) {
for (let i = 0; i < iterable.length; i++) {
@ -99,6 +100,7 @@ const Map = new Lang.Class({
node.value = value;
} else {
this._pool[hash] = { key: key, value: value };
this._size++;
}
},
@ -108,6 +110,7 @@ const Map = new Lang.Class({
if (node && _sameValue(node.key, key)) {
delete this._pool[hash];
this._size--;
return [node.key, node.value];
} else {
return [null, null];
@ -136,6 +139,6 @@ const Map = new Lang.Class({
},
size: function() {
return Object.getOwnPropertyNames(this._pool).length;
return this._size;
},
});

View File

@ -18,7 +18,7 @@ const _urlRegexp = new RegExp(
'(^|' + _leadingJunk + ')' +
'(' +
'(?:' +
'[a-z][\\w-]+://' + // scheme://
'(?:http|https|ftp)://' + // scheme://
'|' +
'www\\d{0,3}[.]' + // www.
'|' +

View File

@ -233,8 +233,10 @@ const AppSwitcherPopup = new Lang.Class({
_finish : function(timestamp) {
let appIcon = this._items[this._selectedIndex];
let window = this._currentWindow > 0 ? this._currentWindow : 0;
appIcon.app.activate_window(appIcon.cachedWindows[window], timestamp);
if (this._currentWindow < 0)
appIcon.app.activate_window(appIcon.cachedWindows[0], timestamp);
else
Main.activateWindow(appIcon.cachedWindows[this._currentWindow], timestamp);
this.parent();
},

View File

@ -187,6 +187,9 @@ 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 AllViewLayout() });
this._stack.add_actor(this._grid.actor);
@ -276,8 +279,12 @@ 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;
}
}));
},
@ -316,6 +323,8 @@ const FrequentView = new Lang.Class({
loadApps: function() {
let mostUsed = this._usage.get_most_used ("");
for (let i = 0; i < mostUsed.length; i++) {
if (!mostUsed[i].get_app_info().should_show())
continue;
let appIcon = new AppIcon(mostUsed[i]);
this._grid.addItem(appIcon.actor, -1);
}
@ -327,6 +336,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',
@ -341,6 +386,9 @@ const AppDisplay = new Lang.Class({
global.settings.connect('changed::app-folder-categories', Lang.bind(this, function() {
Main.queueDeferredWork(this._allAppsWorkId);
}));
this._privacySettings = new Gio.Settings({ schema: 'org.gnome.desktop.privacy' });
this._privacySettings.connect('changed::remember-app-usage',
Lang.bind(this, this._updateFrequentVisibility));
this._views = [];
@ -367,9 +415,9 @@ const AppDisplay = new Lang.Class({
x_expand: true, y_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 }));
@ -384,6 +432,7 @@ const AppDisplay = new Lang.Class({
}));
}
this._showView(Views.FREQUENT);
this._updateFrequentVisibility();
// We need a dummy actor to catch the keyboard focus if the
// user Ctrl-Alt-Tabs here before the deferred work creates
@ -413,6 +462,19 @@ const AppDisplay = new Lang.Class({
}
},
_updateFrequentVisibility: function() {
let enabled = this._privacySettings.get_boolean('remember-app-usage');
this._views[Views.FREQUENT].control.visible = enabled;
let visibleViews = this._views.filter(function(v) {
return v.control.visible;
});
this._controls.visible = visibleViews.length > 1;
if (!enabled && this._views[Views.FREQUENT].view.actor.visible)
this._showView(Views.ALL);
},
_redisplay: function() {
this._redisplayFrequentApps();
this._redisplayAllApps();
@ -483,11 +545,11 @@ const AppSearchProvider = new Lang.Class({
},
getInitialResultSet: function(terms) {
this.searchSystem.pushResults(this, this._appSys.initial_search(terms));
this.searchSystem.setResults(this, this._appSys.initial_search(terms));
},
getSubsearchResultSet: function(previousResults, terms) {
this.searchSystem.pushResults(this, this._appSys.subsearch(previousResults, terms));
this.searchSystem.setResults(this, this._appSys.subsearch(previousResults, terms));
},
activateResult: function(app) {
@ -572,7 +634,11 @@ const FolderIcon = new Lang.Class({
// 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;
@ -595,6 +661,7 @@ 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,
@ -618,17 +685,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() {
@ -643,6 +724,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

@ -126,6 +126,11 @@ 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);
},
@ -426,7 +431,7 @@ const Background = new Lang.Class({
content.brightness = this._brightness;
content.vignette_sharpness = this._vignetteSharpness;
this._cache.removeImageContent(content);
this._cache.removeImageContent(this._images[index].content);
this._images[index].content = content;
this._watchCacheFile(filename);
},
@ -566,7 +571,16 @@ const Background = new Lang.Class({
}
let uri = this._settings.get_string(PICTURE_URI_KEY);
let filename = Gio.File.new_for_uri(uri).get_path();
let filename;
if (GLib.uri_parse_scheme(uri) != null)
filename = Gio.File.new_for_uri(uri).get_path();
else
filename = uri;
if (!filename) {
this._setLoaded();
return;
}
this._loadFile(filename);
},
@ -742,11 +756,15 @@ const BackgroundManager = new Lang.Class({
time: FADE_ANIMATION_TIME,
transition: 'easeOutQuad',
onComplete: Lang.bind(this, function() {
if (this.background == background) {
if (this._newBackground == newBackground) {
this.background = newBackground;
this._newBackground = null;
background.actor.destroy();
} else {
newBackground.actor.destroy();
}
background.actor.destroy();
this.emit('changed');
})
});

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) {
@ -60,5 +62,7 @@ function addBackgroundMenu(actor) {
actor._backgroundMenu.destroy();
actor._backgroundMenu = null;
actor._backgroundManager = null;
cursor.destroy();
});
}

View File

@ -443,16 +443,18 @@ const Calendar = new Lang.Class({
this.actor.add(this._topBox,
{ row: 0, col: 0, col_span: offsetCols + 7 });
let back = new St.Button({ style_class: 'calendar-change-month-back' });
this._topBox.add(back);
back.connect('clicked', Lang.bind(this, this._onPrevMonthButtonClicked));
this._backButton = new St.Button({ style_class: 'calendar-change-month-back',
can_focus: true });
this._topBox.add(this._backButton);
this._backButton.connect('clicked', Lang.bind(this, this._onPrevMonthButtonClicked));
this._monthLabel = new St.Label({style_class: 'calendar-month-label'});
this._topBox.add(this._monthLabel, { expand: true, x_fill: false, x_align: St.Align.MIDDLE });
let forward = new St.Button({ style_class: 'calendar-change-month-forward' });
this._topBox.add(forward);
forward.connect('clicked', Lang.bind(this, this._onNextMonthButtonClicked));
this._forwardButton = new St.Button({ style_class: 'calendar-change-month-forward',
can_focus: true });
this._topBox.add(this._forwardButton);
this._forwardButton.connect('clicked', Lang.bind(this, this._onNextMonthButtonClicked));
// Add weekday labels...
//
@ -511,10 +513,12 @@ const Calendar = new Lang.Class({
}
}
this.setDate(newDate, false);
},
this._backButton.grab_key_focus();
_onNextMonthButtonClicked: function() {
this.setDate(newDate, false);
},
_onNextMonthButtonClicked: function() {
let newDate = new Date(this._selectedDate);
let oldMonth = newDate.getMonth();
if (oldMonth == 11) {
@ -533,7 +537,9 @@ const Calendar = new Lang.Class({
}
}
this.setDate(newDate, false);
this._forwardButton.grab_key_focus();
this.setDate(newDate, false);
},
_onSettingsChange: function() {
@ -590,7 +596,8 @@ const Calendar = new Lang.Class({
// 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 button = new St.Button({ label: iter.getDate().toString(),
can_focus: true });
let rtl = button.get_text_direction() == Clutter.TextDirection.RTL;
if (this._eventSource.isDummy)
@ -598,8 +605,12 @@ const Calendar = new Lang.Class({
let iterStr = iter.toUTCString();
button.connect('clicked', Lang.bind(this, function() {
this._shouldDateGrabFocus = true;
let newlySelectedDate = new Date(iterStr);
this.setDate(newlySelectedDate, false);
this._shouldDateGrabFocus = false;
}));
let hasEvents = this._eventSource.hasEvents(iter);
@ -624,9 +635,6 @@ const Calendar = new Lang.Class({
else if (iter.getMonth() != this._selectedDate.getMonth())
styleClass += ' calendar-other-month-day';
if (_sameDay(this._selectedDate, iter))
button.add_style_pseudo_class('active');
if (hasEvents)
styleClass += ' calendar-day-with-events'
@ -636,6 +644,13 @@ const Calendar = new Lang.Class({
this.actor.add(button,
{ row: row, col: offsetCols + (7 + iter.getDay() - this._weekStart) % 7 });
if (_sameDay(this._selectedDate, iter)) {
button.add_style_pseudo_class('active');
if (this._shouldDateGrabFocus)
button.grab_key_focus();
}
if (this._useWeekdate && iter.getDay() == 4) {
let label = new St.Label({ text: _getCalendarWeekForDate(iter).toString(),
style_class: 'calendar-day-base calendar-week-number'});
@ -660,7 +675,7 @@ const EventsList = new Lang.Class({
Name: 'EventsList',
_init: function() {
this.actor = new St.BoxLayout({ vertical: true, style_class: 'events-header-vbox'});
this.actor = new St.Table({ style_class: 'events-table' });
this._date = new Date();
this._desktopSettings = new Gio.Settings({ schema: 'org.gnome.desktop.interface' });
this._desktopSettings.connect('changed', Lang.bind(this, this._update));
@ -672,55 +687,72 @@ const EventsList = new Lang.Class({
this._eventSource.connect('changed', Lang.bind(this, this._update));
},
_addEvent: function(dayNameBox, timeBox, eventTitleBox, includeDayName, day, time, desc) {
if (includeDayName) {
dayNameBox.add(new St.Label( { style_class: 'events-day-dayname',
text: day } ),
{ x_fill: true } );
}
timeBox.add(new St.Label( { style_class: 'events-day-time',
text: time} ),
{ x_fill: true } );
eventTitleBox.add(new St.Label( { style_class: 'events-day-task',
text: desc} ));
_addEvent: function(event, index, includeDayName) {
let dayString;
if (includeDayName)
dayString = _getEventDayAbbreviation(event.date.getDay());
else
dayString = '';
let dayLabel = new St.Label({ style_class: 'events-day-dayname',
text: dayString });
dayLabel.clutter_text.line_wrap = false;
dayLabel.clutter_text.ellipsize = false;
this.actor.add(dayLabel, { row: index, col: 0,
x_expand: false, x_align: St.Align.END,
y_fill: false, y_align: St.Align.START });
let clockFormat = this._desktopSettings.get_string(CLOCK_FORMAT_KEY);
let timeString = _formatEventTime(event, clockFormat);
let timeLabel = new St.Label({ style_class: 'events-day-time',
text: timeString });
timeLabel.clutter_text.line_wrap = false;
timeLabel.clutter_text.ellipsize = false;
this.actor.add(timeLabel, { row: index, col: 1,
x_expand: false, x_align: St.Align.MIDDLE,
y_fill: false, y_align: St.Align.START });
let titleLabel = new St.Label({ style_class: 'events-day-task',
text: event.summary });
titleLabel.clutter_text.line_wrap = true;
titleLabel.clutter_text.ellipsize = false;
this.actor.add(titleLabel, { row: index, col: 2,
x_expand: true, x_align: St.Align.START,
y_fill: false, y_align: St.Align.START });
},
_addPeriod: function(header, begin, end, includeDayName, showNothingScheduled) {
_addPeriod: function(header, index, begin, end, includeDayName, showNothingScheduled) {
let events = this._eventSource.getEvents(begin, end);
let clockFormat = this._desktopSettings.get_string(CLOCK_FORMAT_KEY);;
if (events.length == 0 && !showNothingScheduled)
return;
return index;
let vbox = new St.BoxLayout( {vertical: true} );
this.actor.add(vbox);
vbox.add(new St.Label({ style_class: 'events-day-header', text: header }));
let box = new St.BoxLayout({style_class: 'events-header-hbox'});
let dayNameBox = new St.BoxLayout({ vertical: true, style_class: 'events-day-name-box' });
let timeBox = new St.BoxLayout({ vertical: true, style_class: 'events-time-box' });
let eventTitleBox = new St.BoxLayout({ vertical: true, style_class: 'events-event-box' });
box.add(dayNameBox, {x_fill: false});
box.add(timeBox, {x_fill: false});
box.add(eventTitleBox, {expand: true});
vbox.add(box);
this.actor.add(new St.Label({ style_class: 'events-day-header', text: header }),
{ row: index, col: 0, col_span: 3,
// In theory, x_expand should be true here, but x_expand
// is a property of the column for StTable, ie all day cells
// get it too
x_expand: false, x_align: St.Align.START,
y_fill: false, y_align: St.Align.START });
index++;
for (let n = 0; n < events.length; n++) {
let event = events[n];
let dayString = _getEventDayAbbreviation(event.date.getDay());
let timeString = _formatEventTime(event, clockFormat);
let summaryString = event.summary;
this._addEvent(dayNameBox, timeBox, eventTitleBox, includeDayName, dayString, timeString, summaryString);
this._addEvent(events[n], index, includeDayName);
index++;
}
if (events.length == 0 && showNothingScheduled) {
let now = new Date();
/* Translators: Text to show if there are no events */
let nothingEvent = new CalendarEvent(now, now, _("Nothing Scheduled"), true);
let timeString = _formatEventTime(nothingEvent, clockFormat);
this._addEvent(dayNameBox, timeBox, eventTitleBox, false, "", timeString, nothingEvent.summary);
this._addEvent(nothingEvent, index, false);
index++;
}
return index;
},
_showOtherDay: function(day) {
@ -737,20 +769,21 @@ const EventsList = new Lang.Class({
else
/* Translators: Shown on calendar heading when selected day occurs on different year */
dayString = day.toLocaleFormat(C_("calendar heading", "%A, %B %d, %Y"));
this._addPeriod(dayString, dayBegin, dayEnd, false, true);
this._addPeriod(dayString, 0, dayBegin, dayEnd, false, true);
},
_showToday: function() {
this.actor.destroy_all_children();
let index = 0;
let now = new Date();
let dayBegin = _getBeginningOfDay(now);
let dayEnd = _getEndOfDay(now);
this._addPeriod(_("Today"), dayBegin, dayEnd, false, true);
index = this._addPeriod(_("Today"), index, dayBegin, dayEnd, false, true);
let tomorrowBegin = new Date(dayBegin.getTime() + 86400 * 1000);
let tomorrowEnd = new Date(dayEnd.getTime() + 86400 * 1000);
this._addPeriod(_("Tomorrow"), tomorrowBegin, tomorrowEnd, false, true);
index = this._addPeriod(_("Tomorrow"), index, tomorrowBegin, tomorrowEnd, false, true);
let dayInWeek = (dayEnd.getDay() - this._weekStart + 7) % 7;
@ -761,7 +794,7 @@ const EventsList = new Lang.Class({
*/
let thisWeekBegin = new Date(dayBegin.getTime() + 2 * 86400 * 1000);
let thisWeekEnd = new Date(dayEnd.getTime() + (6 - dayInWeek) * 86400 * 1000);
this._addPeriod(_("This week"), thisWeekBegin, thisWeekEnd, true, false);
index = this._addPeriod(_("This week"), index, thisWeekBegin, thisWeekEnd, true, false);
} else {
/* otherwise it's one of the two last days of the week ... show
* "Next week" and include events up until and including *next*
@ -769,7 +802,7 @@ const EventsList = new Lang.Class({
*/
let nextWeekBegin = new Date(dayBegin.getTime() + 2 * 86400 * 1000);
let nextWeekEnd = new Date(dayEnd.getTime() + (13 - dayInWeek) * 86400 * 1000);
this._addPeriod(_("Next week"), nextWeekBegin, nextWeekEnd, true, false);
index = this._addPeriod(_("Next week"), index, nextWeekBegin, nextWeekEnd, true, false);
}
},

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() {

View File

@ -16,7 +16,7 @@ const PolkitAgent = imports.gi.PolkitAgent;
const Components = imports.ui.components;
const ModalDialog = imports.ui.modalDialog;
const ShellEntry = imports.ui.shellEntry;
const UserMenu = imports.ui.userMenu;
const UserWidget = imports.ui.userWidget;
const DIALOG_ICON_SIZE = 48;
@ -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 });
@ -101,9 +100,9 @@ const AuthenticationDialog = new Lang.Class({
let userBox = new St.BoxLayout({ style_class: 'polkit-dialog-user-layout',
vertical: false });
messageBox.add(userBox);
this._userAvatar = new UserMenu.UserAvatarWidget(this._user,
{ iconSize: DIALOG_ICON_SIZE,
styleClass: 'polkit-dialog-user-icon' });
this._userAvatar = new UserWidget.Avatar(this._user,
{ iconSize: DIALOG_ICON_SIZE,
styleClass: 'polkit-dialog-user-icon' });
this._userAvatar.actor.hide();
userBox.add(this._userAvatar.actor,
{ x_fill: true,
@ -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

@ -61,8 +61,7 @@ const CtrlAltTabManager = new Lang.Class({
if (item.focusCallback) {
item.focusCallback(timestamp);
} else {
if (global.stage_input_mode == Shell.StageInputMode.NONREACTIVE ||
global.stage_input_mode == Shell.StageInputMode.NORMAL)
if (global.stage_input_mode == Shell.StageInputMode.NORMAL)
global.set_stage_input_mode(Shell.StageInputMode.FOCUSED);
item.root.navigate_focus(null, Gtk.DirectionType.TAB_FORWARD, false);
@ -89,19 +88,25 @@ 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],
@ -109,6 +114,7 @@ const CtrlAltTabManager = new Lang.Class({
Main.activateWindow(this, timestamp);
}),
iconActor: icon,
iconName: iconName,
sortGroup: SortGroup.MIDDLE });
}
}

View File

@ -287,13 +287,7 @@ const ShowAppsIcon = new Lang.Class({
},
handleDragOver: function(source, actor, x, y, time) {
let app = getAppFromSource(source);
if (app == null)
return DND.DragMotionResult.NO_DROP;
let id = app.get_id();
let isFavorite = AppFavorites.getAppFavorites().isFavorite(id);
if (!isFavorite)
if (!this._canRemoveApp(getAppFromSource(source)))
return DND.DragMotionResult.NO_DROP;
return DND.DragMotionResult.MOVE_DROP;
@ -301,7 +295,7 @@ const ShowAppsIcon = new Lang.Class({
acceptDrop: function(source, actor, x, y, time) {
let app = getAppFromSource(source);
if (app == null)
if (!this._canRemoveApp(app))
return false;
let id = app.get_id();
@ -326,6 +320,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,
@ -441,6 +445,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() {
@ -457,6 +467,7 @@ const Dash = new Lang.Class({
_endDrag: function() {
this._clearDragPlaceholder();
this._clearEmptyDropTarget();
this._showAppsIcon.setDragApp(null);
DND.removeDragMonitor(this._dragMonitor);
},
@ -797,9 +808,21 @@ const Dash = new Lang.Class({
_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;
}
},
@ -827,23 +850,18 @@ const Dash = new Lang.Class({
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.connect('destroy',
Lang.bind(this, function() {
this._animatingPlaceholdersCount--;
}));
}
this._dragPlaceholder = null;
this._clearDragPlaceholder();
return DND.DragMotionResult.CONTINUE;
}
@ -868,9 +886,9 @@ const Dash = new Lang.Class({
// 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;

View File

@ -49,11 +49,6 @@ const DateMenuButton = new Lang.Class({
menuAlignment = 1.0 - menuAlignment;
this.parent(menuAlignment);
// At this moment calendar menu is not keyboard navigable at
// all (so not accessible), so it doesn't make sense to set as
// role ATK_ROLE_MENU like other elements of the panel.
this.actor.accessible_role = Atk.Role.LABEL;
this._clockDisplay = new St.Label();
this.actor.add_actor(this._clockDisplay);
@ -85,27 +80,22 @@ const DateMenuButton = new Lang.Class({
vbox.add(this._calendar.actor);
let separator = new PopupMenu.PopupSeparatorMenuItem();
separator.setColumnWidths(1);
vbox.add(separator.actor, {y_align: St.Align.END, expand: true, y_fill: false});
vbox.add(separator.actor, { y_align: St.Align.END, expand: true, y_fill: false });
this._openCalendarItem = new PopupMenu.PopupMenuItem(_("Open Calendar"));
this._openCalendarItem.connect('activate', Lang.bind(this, this._onOpenCalendarActivate));
this._openCalendarItem.actor.can_focus = false;
vbox.add(this._openCalendarItem.actor, {y_align: St.Align.END, expand: true, y_fill: false});
this._openClocksItem = new PopupMenu.PopupMenuItem(_("Open Clocks"));
this._openClocksItem.connect('activate', Lang.bind(this, this._onOpenClocksActivate));
this._openClocksItem.actor.can_focus = false;
vbox.add(this._openClocksItem.actor, {y_align: St.Align.END, expand: true, y_fill: false});
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) {
item.actor.show_on_set_parent = false;
item.actor.can_focus = false;
item.actor.reparent(vbox);
this._dateAndTimeSeparator = separator;
}
@ -116,12 +106,7 @@ const DateMenuButton = new Lang.Class({
hbox.add(this._separator);
// Fill up the second column
vbox = new St.BoxLayout({ name: 'calendarEventsArea',
vertical: true });
hbox.add(vbox, { expand: true });
// Event list
vbox.add(this._eventList.actor, { expand: true });
hbox.add(this._eventList.actor, { expand: true, y_fill: false, y_align: St.Align.START });
// Whenever the menu is opened, select today
this.menu.connect('open-state-changed', Lang.bind(this, function(menu, isOpen) {
@ -157,14 +142,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();
},
_updateEventsVisibility: function() {
let visible = this._eventSource.hasCalendars;
this._openCalendarItem.actor.visible = visible;
this._openClocksItem.actor.visible = visible;
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;
@ -217,18 +204,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);
if (app.get_id() == 'evolution')
app = Gio.DesktopAppInfo.new('evolution-calendar');
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

@ -43,9 +43,7 @@ let dragMonitors = [];
function _getEventHandlerActor() {
if (!eventHandlerActor) {
eventHandlerActor = new Clutter.Rectangle();
eventHandlerActor.width = 0;
eventHandlerActor.height = 0;
eventHandlerActor = new Clutter.Actor({ width: 0, height: 0 });
Main.uiGroup.add_actor(eventHandlerActor);
// We connect to 'event' rather than 'captured-event' because the capturing phase doesn't happen
// when you've grabbed the pointer.
@ -149,16 +147,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;
}
},
@ -291,19 +289,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;

View File

@ -35,7 +35,7 @@ const GnomeSession = imports.misc.gnomeSession;
const Main = imports.ui.main;
const ModalDialog = imports.ui.modalDialog;
const Tweener = imports.ui.tweener;
const UserMenu = imports.ui.userMenu;
const UserWidget = imports.ui.userWidget;
let _endSessionDialog = null;
@ -360,9 +360,9 @@ const EndSessionDialog = new Lang.Class({
icon_size: _DIALOG_ICON_SIZE,
style_class: dialogContent.iconStyleClass });
} else {
let avatarWidget = new UserMenu.UserAvatarWidget(this._user,
{ iconSize: _DIALOG_ICON_SIZE,
styleClass: dialogContent.iconStyleClass });
let avatarWidget = new UserWidget.Avatar(this._user,
{ iconSize: _DIALOG_ICON_SIZE,
styleClass: dialogContent.iconStyleClass });
this._iconBin.child = avatarWidget.actor;
avatarWidget.update();
}
@ -420,6 +420,7 @@ const EndSessionDialog = new Lang.Class({
_startTimer: function() {
let startTime = GLib.get_monotonic_time();
this._secondsLeft = this._totalSecondsToStayOpen;
this._updateDescription();
this._timerId = Mainloop.timeout_add_seconds(1, Lang.bind(this,
function() {

View File

@ -292,7 +292,7 @@ function disableAllExtensions() {
return;
if (initted) {
enabledExtensions.forEach(function(uuid) {
extensionOrder.slice().reverse().forEach(function(uuid) {
disableExtension(uuid);
});
}

View File

@ -211,10 +211,8 @@ const GrabHelper = new Lang.Class({
this._grabbedFromKeynav = hadFocus;
this._preGrabInputMode = global.stage_input_mode;
if (this._preGrabInputMode == Shell.StageInputMode.NONREACTIVE ||
this._preGrabInputMode == Shell.StageInputMode.NORMAL) {
if (this._preGrabInputMode == Shell.StageInputMode.NORMAL)
global.set_stage_input_mode(Shell.StageInputMode.FOCUSED);
}
this._keyFocusNotifyId = global.stage.connect('notify::key-focus', Lang.bind(this, this._onKeyFocusChanged));
this._focusWindowChangedId = metaDisplay.connect('notify::focus-window', Lang.bind(this, this._focusWindowChanged));

View File

@ -118,10 +118,25 @@ const MonitorConstraint = new Lang.Class({
}
});
const Monitor = new Lang.Class({
Name: 'Monitor',
_init: function(index, geometry) {
this.index = index;
this.x = geometry.x;
this.y = geometry.y;
this.width = geometry.width;
this.height = geometry.height;
},
get inFullscreen() {
return global.screen.get_monitor_in_fullscreen(this.index);
}
})
const defaultParams = {
trackFullscreen: false,
affectsStruts: false,
affectsInputRegion: true
};
const LayoutManager = new Lang.Class({
@ -173,10 +188,12 @@ const LayoutManager = new Lang.Class({
global.stage.remove_actor(global.window_group);
this.uiGroup.add_actor(global.window_group);
global.stage.remove_actor(global.overlay_group);
this.uiGroup.add_actor(global.overlay_group);
global.stage.add_child(this.uiGroup);
this.overviewGroup = new St.Widget({ name: 'overviewGroup',
visible: false });
this.addChrome(this.overviewGroup);
this.screenShieldGroup = new St.Widget({ name: 'screenShieldGroup',
visible: false,
clip_to_allocation: true,
@ -227,24 +244,24 @@ const LayoutManager = new Lang.Class({
this._monitorsChanged();
},
// This is called by Main after everything else is constructed;
// it needs access to Main.overview, which didn't exist
// yet when the LayoutManager was constructed.
// This is called by Main after everything else is constructed
init: function() {
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();
this._loadBackground();
},
_overviewShowing: function() {
showOverview: function() {
this.overviewGroup.show();
this._inOverview = true;
this._updateVisibility();
this._queueUpdateRegions();
},
_overviewHidden: function() {
hideOverview: function() {
this.overviewGroup.hide();
this._inOverview = false;
this._updateVisibility();
this._queueUpdateRegions();
@ -261,7 +278,7 @@ const LayoutManager = new Lang.Class({
this.monitors = [];
let nMonitors = screen.get_n_monitors();
for (let i = 0; i < nMonitors; i++)
this.monitors.push(screen.get_monitor_geometry(i));
this.monitors.push(new Monitor(i, screen.get_monitor_geometry(i)));
if (nMonitors == 1) {
this.primaryIndex = this.bottomIndex = 0;
@ -283,8 +300,10 @@ 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.forEach(function(corner) {
if (corner)
corner.destroy();
});
this.hotCorners = [];
let size = this.panelBox.height;
@ -295,9 +314,9 @@ const LayoutManager = new Lang.Class({
let cornerX = this._rtl ? monitor.x + monitor.width : monitor.x;
let cornerY = monitor.y;
if (i != this.primaryIndex) {
let haveTopLeftCorner = true;
let haveTopLeftCorner = true;
if (i != this.primaryIndex) {
// 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;
@ -324,14 +343,15 @@ const LayoutManager = new Lang.Class({
break;
}
}
if (!haveTopLeftCorner)
continue;
}
let corner = new HotCorner(this, monitor, cornerX, cornerY);
corner.setBarrierSize(size);
this.hotCorners.push(corner);
if (haveTopLeftCorner) {
let corner = new HotCorner(this, monitor, cornerX, cornerY);
corner.setBarrierSize(size);
this.hotCorners.push(corner);
} else {
this.hotCorners.push(null);
}
}
this.emit('hot-corners-changed');
@ -408,7 +428,8 @@ const LayoutManager = new Lang.Class({
let size = this.panelBox.height;
this.hotCorners.forEach(function(corner) {
corner.setBarrierSize(size);
if (corner)
corner.setBarrierSize(size);
});
},
@ -536,6 +557,25 @@ const LayoutManager = new Lang.Class({
return this._keyboardIndex;
},
_loadBackground: function() {
this._systemBackground = new Background.SystemBackground();
this._systemBackground.actor.hide();
global.stage.insert_child_below(this._systemBackground.actor, null);
let constraint = new Clutter.BindConstraint({ source: global.stage,
coordinate: Clutter.BindCoordinate.ALL });
this._systemBackground.actor.add_constraint(constraint);
let signalId = this._systemBackground.connect('loaded', Lang.bind(this, function() {
this._systemBackground.disconnect(signalId);
this._systemBackground.actor.show();
global.stage.show();
this._prepareStartupAnimation();
}));
},
// Startup Animations
//
// We have two different animations, depending on whether we're a greeter
@ -581,35 +621,18 @@ const LayoutManager = new Lang.Class({
global.window_group.set_clip(monitor.x, monitor.y, monitor.width, monitor.height);
}
this._systemBackground = new Background.SystemBackground();
this._systemBackground.actor.hide();
this.emit('startup-prepared');
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;
}));
}));
// 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() {
@ -666,7 +689,6 @@ const LayoutManager = new Lang.Class({
},
showKeyboard: function () {
this.keyboardBox.raise_top();
Tweener.addTween(this.keyboardBox,
{ anchor_y: this.keyboardBox.height,
time: KEYBOARD_ANIMATION_TIME,
@ -711,11 +733,10 @@ const LayoutManager = new Lang.Class({
// @actor: an actor to add to the chrome
// @params: (optional) additional params
//
// Adds @actor to the chrome, and (unless %affectsInputRegion in
// @params is %false) extends the input region to include it.
// Changes in @actor's size, position, and visibility will
// automatically result in appropriate changes to the input
// region.
// Adds @actor to the chrome, and extends the input region
// to include it. Changes in @actor's size, position, and
// visibility will automatically result in appropriate changes
// to the input region.
//
// If %affectsStruts in @params is %true (and @actor is along a
// screen edge), then @actor's size and position will also affect
@ -900,13 +921,8 @@ const LayoutManager = new Lang.Class({
},
_updateFullscreen: function() {
for (let i = 0; i < this.monitors.length; i++)
this.monitors[i].inFullscreen = global.screen.get_monitor_in_fullscreen (i);
this._updateVisibility();
this._queueUpdateRegions();
this.emit('fullscreen-changed');
},
_windowsRestacked: function() {
@ -934,7 +950,7 @@ const LayoutManager = new Lang.Class({
for (i = 0; i < this._trackedActors.length; i++) {
let actorData = this._trackedActors[i];
if (!(actorData.affectsInputRegion && wantsInputRegion) && !actorData.affectsStruts)
if (!wantsInputRegion && !actorData.affectsStruts)
continue;
let [x, y] = actorData.actor.get_transformed_position();
@ -944,13 +960,8 @@ const LayoutManager = new Lang.Class({
w = Math.round(w);
h = Math.round(h);
if (actorData.affectsInputRegion && wantsInputRegion) {
let rect = new Meta.Rectangle({ x: x, y: y, width: w, height: h});
if (actorData.actor.get_paint_visibility() &&
!this.uiGroup.get_skip_paint(actorData.actor))
rects.push(rect);
}
if (wantsInputRegion && actorData.actor.get_paint_visibility())
rects.push(new Meta.Rectangle({ x: x, y: y, width: w, height: h }));
if (actorData.affectsStruts) {
// Limit struts to the size of the screen
@ -1092,12 +1103,21 @@ const HotCorner = new Lang.Class({
}
if (size > 0) {
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 });
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);
@ -1112,11 +1132,11 @@ const HotCorner = new Lang.Class({
height: 3,
reactive: true });
this._corner = new Clutter.Rectangle({ name: 'hot-corner',
width: 1,
height: 1,
opacity: 0,
reactive: true });
this._corner = new Clutter.Actor({ name: 'hot-corner',
width: 1,
height: 1,
opacity: 0,
reactive: true });
this._corner._delegate = this;
this.actor.add_child(this._corner);

View File

@ -308,10 +308,6 @@ const Result = new Lang.Class({
box.add(resultTxt);
let objLink = new ObjLink(this._lookingGlass, o);
box.add(objLink.actor);
let line = new Clutter.Rectangle({ name: 'Separator' });
let padBin = new St.Bin({ name: 'Separator', x_fill: true, y_fill: true });
padBin.add_actor(line);
this.actor.add(padBin);
}
});
@ -989,28 +985,18 @@ const LookingGlass = new Lang.Class({
_showCompletions: function(completions) {
if (!this._completionActor) {
let actor = new St.BoxLayout({ vertical: true });
this._completionText = new St.Label({ name: 'LookingGlassAutoCompletionText', style_class: 'lg-completions-text' });
this._completionText.clutter_text.ellipsize = Pango.EllipsizeMode.NONE;
this._completionText.clutter_text.line_wrap = true;
actor.add(this._completionText);
let line = new Clutter.Rectangle();
let padBin = new St.Bin({ x_fill: true, y_fill: true });
padBin.add_actor(line);
actor.add(padBin);
this._completionActor = actor;
this._completionActor = new St.Label({ name: 'LookingGlassAutoCompletionText', style_class: 'lg-completions-text' });
this._completionActor.clutter_text.ellipsize = Pango.EllipsizeMode.NONE;
this._completionActor.clutter_text.line_wrap = true;
this._evalBox.insert_child_below(this._completionActor, this._entryArea);
}
this._completionText.set_text(completions.join(', '));
this._completionActor.set_text(completions.join(', '));
// Setting the height to -1 allows us to get its actual preferred height rather than
// whatever was last given in set_height by Tweener.
this._completionActor.set_height(-1);
let [minHeight, naturalHeight] = this._completionText.get_preferred_height(this._resultsArea.get_width());
let [minHeight, naturalHeight] = this._completionActor.get_preferred_height(this._resultsArea.get_width());
// Don't reanimate if we are already visible
if (this._completionActor.visible) {

View File

@ -38,9 +38,11 @@ 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);
const A11Y_SCHEMA = 'org.gnome.desktop.a11y.keyboard';
const STICKY_KEYS_ENABLE = 'stickykeys-enable';
let componentManager = null;
let panel = null;
let overview = null;
@ -68,7 +70,8 @@ let layoutManager = null;
let _startDate;
let _defaultCssStylesheet = null;
let _cssStylesheet = null;
let _overridesSettings = null;
let _a11ySettings = null;
let dynamicWorkspacesSchema = null;
function _sessionUpdated() {
_loadDefaultStylesheet();
@ -106,6 +109,7 @@ function start() {
function _sessionsLoaded() {
sessionMode.connect('updated', _sessionUpdated);
_initializePrefs();
_initializeUI();
shellDBusService = new ShellDBus.GnomeShell();
@ -114,6 +118,17 @@ function _sessionsLoaded() {
_sessionUpdated();
}
function _initializePrefs() {
let keys = new Gio.Settings({ schema: sessionMode.overridesSchema }).list_keys();
for (let i = 0; i < keys.length; i++)
Meta.prefs_override_preference_schema(keys[i], sessionMode.overridesSchema);
if (keys.indexOf('dynamic-workspaces') > -1)
dynamicWorkspacesSchema = sessionMode.overridesSchema;
else
dynamicWorkspacesSchema = 'org.gnome.mutter';
}
function _initializeUI() {
// Ensure ShellWindowTracker and ShellAppUsage are initialized; this will
// also initialize ShellAppSystem first. ShellAppSystem
@ -123,11 +138,9 @@ function _initializeUI() {
// and recalculate application associations, so to avoid
// races for now we initialize it here. It's better to
// be predictable anyways.
let tracker = Shell.WindowTracker.get_default();
Shell.WindowTracker.get_default();
Shell.AppUsage.get_default();
tracker.connect('startup-sequence-changed', _queueCheckWorkspaces);
_loadDefaultStylesheet();
// Setup the stage hierarchy early
@ -157,9 +170,12 @@ function _initializeUI() {
layoutManager.init();
overview.init();
global.screen.override_workspace_layout(Meta.ScreenCorner.TOPLEFT,
false, -1, 1);
global.display.connect('overlay-key', Lang.bind(overview, overview.toggle));
_a11ySettings = new Gio.Settings({ schema: A11Y_SCHEMA });
global.display.connect('overlay-key', Lang.bind(overview, function () {
if (!_a11ySettings.get_boolean (STICKY_KEYS_ENABLE))
overview.toggle();
}));
// Provide the bus object for gnome-session to
// initiate logouts.
@ -179,17 +195,6 @@ function _initializeUI() {
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);
global.screen.connect('window-left-monitor', _windowLeftMonitor);
global.screen.connect('restacked', _windowsRestacked);
_nWorkspacesChanged();
ExtensionDownloader.init();
ExtensionSystem.init();
@ -203,190 +208,12 @@ function _initializeUI() {
if (keybindingMode == Shell.KeyBindingMode.NONE) {
keybindingMode = Shell.KeyBindingMode.NORMAL;
}
if (screenShield) {
screenShield.lockIfWasLocked();
}
});
}
let _workspaces = [];
let _checkWorkspacesId = 0;
/*
* When the last window closed on a workspace is a dialog or splash
* screen, we assume that it might be an initial window shown before
* the main window of an application, and give the app a grace period
* where it can map another window before we remove the workspace.
*/
const LAST_WINDOW_GRACE_TIME = 1000;
function _checkWorkspaces() {
let i;
let emptyWorkspaces = [];
if (!Meta.prefs_get_dynamic_workspaces()) {
_checkWorkspacesId = 0;
return false;
}
for (i = 0; i < _workspaces.length; i++) {
let lastRemoved = _workspaces[i]._lastRemovedWindow;
if ((lastRemoved &&
(lastRemoved.get_window_type() == Meta.WindowType.SPLASHSCREEN ||
lastRemoved.get_window_type() == Meta.WindowType.DIALOG ||
lastRemoved.get_window_type() == Meta.WindowType.MODAL_DIALOG)) ||
_workspaces[i]._keepAliveId)
emptyWorkspaces[i] = false;
else
emptyWorkspaces[i] = true;
}
let sequences = Shell.WindowTracker.get_default().get_startup_sequences();
for (i = 0; i < sequences.length; i++) {
let index = sequences[i].get_workspace();
if (index >= 0 && index <= global.screen.n_workspaces)
emptyWorkspaces[index] = false;
}
let windows = global.get_window_actors();
for (i = 0; i < windows.length; i++) {
let win = windows[i];
if (win.get_meta_window().is_on_all_workspaces())
continue;
let workspaceIndex = win.get_workspace();
emptyWorkspaces[workspaceIndex] = false;
}
// If we don't have an empty workspace at the end, add one
if (!emptyWorkspaces[emptyWorkspaces.length -1]) {
global.screen.append_new_workspace(false, global.get_current_time());
emptyWorkspaces.push(false);
}
let activeWorkspaceIndex = global.screen.get_active_workspace_index();
let removingCurrentWorkspace = (emptyWorkspaces[activeWorkspaceIndex] &&
activeWorkspaceIndex < emptyWorkspaces.length - 1);
// Don't enter the overview when removing multiple empty workspaces at startup
let showOverview = (removingCurrentWorkspace &&
!emptyWorkspaces.every(function(x) { return x; }));
if (removingCurrentWorkspace) {
// "Merge" the empty workspace we are removing with the one at the end
wm.blockAnimations();
}
// Delete other empty workspaces; do it from the end to avoid index changes
for (i = emptyWorkspaces.length - 2; i >= 0; i--) {
if (emptyWorkspaces[i])
global.screen.remove_workspace(_workspaces[i], global.get_current_time());
}
if (removingCurrentWorkspace) {
global.screen.get_workspace_by_index(global.screen.n_workspaces - 1).activate(global.get_current_time());
wm.unblockAnimations();
if (!overview.visible && showOverview)
overview.show();
}
_checkWorkspacesId = 0;
return false;
}
function keepWorkspaceAlive(workspace, duration) {
if (workspace._keepAliveId)
Mainloop.source_remove(workspace._keepAliveId);
workspace._keepAliveId = Mainloop.timeout_add(duration, function() {
workspace._keepAliveId = 0;
_queueCheckWorkspaces();
return false;
});
}
function _windowRemoved(workspace, window) {
workspace._lastRemovedWindow = window;
_queueCheckWorkspaces();
Mainloop.timeout_add(LAST_WINDOW_GRACE_TIME, function() {
if (workspace._lastRemovedWindow == window) {
workspace._lastRemovedWindow = null;
_queueCheckWorkspaces();
}
return false;
});
}
function _windowLeftMonitor(metaScreen, monitorIndex, metaWin) {
// If the window left the primary monitor, that
// might make that workspace empty
if (monitorIndex == layoutManager.primaryIndex)
_queueCheckWorkspaces();
}
function _windowEnteredMonitor(metaScreen, monitorIndex, metaWin) {
// If the window entered the primary monitor, that
// might make that workspace non-empty
if (monitorIndex == layoutManager.primaryIndex)
_queueCheckWorkspaces();
}
function _windowsRestacked() {
// Figure out where the pointer is in case we lost track of
// it during a grab. (In particular, if a trayicon popup menu
// is dismissed, see if we need to close the message tray.)
global.sync_pointer();
}
function _queueCheckWorkspaces() {
if (_checkWorkspacesId == 0)
_checkWorkspacesId = Meta.later_add(Meta.LaterType.BEFORE_REDRAW, _checkWorkspaces);
}
function _nWorkspacesChanged() {
let oldNumWorkspaces = _workspaces.length;
let newNumWorkspaces = global.screen.n_workspaces;
if (oldNumWorkspaces == newNumWorkspaces)
return false;
let lostWorkspaces = [];
if (newNumWorkspaces > oldNumWorkspaces) {
let w;
// Assume workspaces are only added at the end
for (w = oldNumWorkspaces; w < newNumWorkspaces; w++)
_workspaces[w] = global.screen.get_workspace_by_index(w);
for (w = oldNumWorkspaces; w < newNumWorkspaces; w++) {
let workspace = _workspaces[w];
workspace._windowAddedId = workspace.connect('window-added', _queueCheckWorkspaces);
workspace._windowRemovedId = workspace.connect('window-removed', _windowRemoved);
}
} else {
// Assume workspaces are only removed sequentially
// (e.g. 2,3,4 - not 2,4,7)
let removedIndex;
let removedNum = oldNumWorkspaces - newNumWorkspaces;
for (let w = 0; w < oldNumWorkspaces; w++) {
let workspace = global.screen.get_workspace_by_index(w);
if (_workspaces[w] != workspace) {
removedIndex = w;
break;
}
}
let lostWorkspaces = _workspaces.splice(removedIndex, removedNum);
lostWorkspaces.forEach(function(workspace) {
workspace.disconnect(workspace._windowAddedId);
workspace.disconnect(workspace._windowRemovedId);
});
}
_queueCheckWorkspaces();
return false;
}
function _loadDefaultStylesheet() {
if (!sessionMode.isPrimary)
return;
@ -437,7 +264,8 @@ function loadTheme() {
if (_cssStylesheet != null)
cssStylesheet = _cssStylesheet;
let theme = new St.Theme ({ application_stylesheet: cssStylesheet });
let theme = new St.Theme ({ application_stylesheet: cssStylesheet,
default_stylesheet: _defaultCssStylesheet });
if (previousTheme) {
let customStylesheets = previousTheme.get_custom_stylesheets();

View File

@ -1530,11 +1530,7 @@ const MessageTrayContextMenu = new Lang.Class({
},
_updateClearSensitivity: function() {
let sources = this._tray.getSources();
sources = sources.filter(function(source) {
return !source.trayIcon && !source.isChat && !source.resident;
});
this._clearItem.setSensitive(sources.length > 0);
this._clearItem.setSensitive(this._tray.clearableCount > 0);
},
setPosition: function(x, y) {
@ -1557,23 +1553,22 @@ const MessageTray = new Lang.Class({
this.actor = new St.Widget({ name: 'message-tray',
reactive: true,
track_hover: true,
layout_manager: new Clutter.BinLayout(),
x_expand: true,
y_expand: true,
y_align: Clutter.ActorAlign.START,
});
this.actor.connect('notify::hover', Lang.bind(this, this._onTrayHoverChanged));
this._notificationWidget = new St.Widget({ name: 'notification-container',
reactive: true,
track_hover: true,
y_align: Clutter.ActorAlign.START,
x_align: Clutter.ActorAlign.CENTER,
y_expand: true,
x_expand: true,
layout_manager: new Clutter.BinLayout() });
this._notificationWidget.connect('key-release-event', Lang.bind(this, this._onNotificationKeyRelease));
this.actor.add_actor(this._notificationWidget);
this._notificationWidget.connect('notify::hover', Lang.bind(this, this._onNotificationHoverChanged));
this._notificationBin = new St.Bin({ y_expand: true });
this._notificationBin.set_y_align(Clutter.ActorAlign.START);
@ -1628,24 +1623,25 @@ const MessageTray = new Lang.Class({
{ keybindingMode: Shell.KeyBindingMode.MESSAGE_TRAY });
this._grabHelper.addActor(this._summaryBoxPointer.actor);
this._grabHelper.addActor(this.actor);
this._grabHelper.addActor(this._notificationWidget);
Main.layoutManager.connect('keyboard-visible-changed', Lang.bind(this, this._onKeyboardVisibleChanged));
this._trayState = State.HIDDEN;
this._traySummoned = false;
this._useLongerTrayLeftTimeout = false;
this._useLongerNotificationLeftTimeout = false;
this._trayLeftTimeoutId = 0;
// pointerInTray is sort of a misnomer -- it tracks whether
// pointerInNotification 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
// partially driven by the hover state of the notification, 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._pointerInNotification = false;
// This tracks this.actor.hover and is used to fizzle
// out non-changing hover notifications in onTrayHoverChanged.
this._trayHovered = false;
// This tracks this._notificationWidget.hover and is used to fizzle
// out non-changing hover notifications in onNotificationHoverChanged.
this._notificationHovered = false;
this._keyboardVisible = false;
this._notificationClosed = false;
@ -1657,23 +1653,29 @@ const MessageTray = new Lang.Class({
this._desktopCloneState = State.HIDDEN;
this._notificationRemoved = false;
this._reNotifyAfterHideNotification = null;
this._inFullscreen = false;
this._desktopClone = null;
this._inCtrlAltTab = false;
this._lightbox = new Lightbox.Lightbox(global.overlay_group,
{ inhibitEvents: true,
fadeInTime: ANIMATION_TIME,
fadeOutTime: ANIMATION_TIME,
fadeFactor: 0.2
});
this.clearableCount = 0;
this._lightboxes = [];
let lightboxContainers = [global.window_group,
Main.layoutManager.overviewGroup];
for (let i = 0; i < lightboxContainers.length; i++)
this._lightboxes.push(new Lightbox.Lightbox(lightboxContainers[i],
{ inhibitEvents: true,
fadeInTime: ANIMATION_TIME,
fadeOutTime: ANIMATION_TIME,
fadeFactor: 0.2
}));
Main.layoutManager.trayBox.add_actor(this.actor);
Main.layoutManager.trayBox.add_actor(this._notificationWidget);
Main.layoutManager.trackChrome(this.actor);
Main.layoutManager.trackChrome(this._notificationWidget);
Main.layoutManager.trackChrome(this._closeButton);
Main.layoutManager.connect('fullscreen-changed', Lang.bind(this, this._updateState));
global.screen.connect('in-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
@ -1747,7 +1749,7 @@ const MessageTray = new Lang.Class({
let [x, y, mask] = global.get_pointer();
this._contextMenu.setPosition(Math.round(x), Math.round(y));
this._grabHelper.grab({ actor: this._contextMenu.actor,
grabFocus: true,
modal: true,
onUngrab: Lang.bind(this, function () {
this._contextMenu.close(BoxPointer.PopupAnimation.FULL);
})
@ -1793,12 +1795,12 @@ const MessageTray = new Lang.Class({
y == monitor.y + monitor.height - 1);
if (shouldDwell) {
// We only set up dwell timeout when the user is not hovering over the tray
// (!this.actor.hover). This avoids bringing up the message tray after the
// (!this._notificationHovered). This avoids bringing up the message tray after the
// user clicks on a notification with the pointer on the bottom pixel
// of the monitor. The _trayDwelling variable is used so that we only try to
// fire off one tray dwell - if it fails (because, say, the user has the mouse down),
// we don't try again until the user moves the mouse up and down again.
if (!this._trayDwelling && !this.actor.hover && this._trayDwellTimeoutId == 0) {
if (!this._trayDwelling && !this._notificationHovered && this._trayDwellTimeoutId == 0) {
// Save the interaction timestamp so we can detect user input
let focusWindow = global.display.focus_window;
this._trayDwellUserTime = focusWindow ? focusWindow.user_time : 0;
@ -1896,6 +1898,9 @@ const MessageTray = new Lang.Class({
this._summary.insert_child_at_index(summaryItem.actor, this._chatSummaryItemsCount);
}
if (!source.trayIcon && !source.isChat && !source.resident)
this.clearableCount++;
this._sources.set(source, obj);
obj.notifyId = source.connect('notify', Lang.bind(this, this._onNotify));
@ -1937,6 +1942,9 @@ const MessageTray = new Lang.Class({
if (source.isChat)
this._chatSummaryItemsCount--;
if (!source.trayIcon && !source.isChat && !source.resident)
this.clearableCount--;
source.disconnect(obj.notifyId);
source.disconnect(obj.destroyId);
source.disconnect(obj.mutedChangedId);
@ -1992,7 +2000,6 @@ const MessageTray = new Lang.Class({
}
let index = this._notificationQueue.indexOf(notification);
notification.destroy();
if (index != -1)
this._notificationQueue.splice(index, 1);
},
@ -2021,7 +2028,6 @@ const MessageTray = new Lang.Class({
hide: function() {
this._traySummoned = false;
this.actor.set_hover(false);
this._updateState();
},
@ -2088,25 +2094,21 @@ const MessageTray = new Lang.Class({
this._grabHelper.addActor(corner.actor);
},
_onTrayHoverChanged: function() {
if (this.actor.hover == this._trayHovered)
_onNotificationHoverChanged: function() {
if (this._notificationWidget.hover == this._notificationHovered)
return;
this._trayHovered = this.actor.hover;
if (this._trayHovered) {
this._notificationHovered = this._notificationWidget.hover;
if (this._notificationHovered) {
// No dwell inside notifications at the bottom of the screen
this._cancelTrayDwell();
// Don't do anything if the one pixel area at the bottom is hovered over while the tray is hidden.
if (this._trayState == State.HIDDEN && this._notificationState == State.HIDDEN)
return;
this._useLongerTrayLeftTimeout = false;
if (this._trayLeftTimeoutId) {
Mainloop.source_remove(this._trayLeftTimeoutId);
this._trayLeftTimeoutId = 0;
this._trayLeftMouseX = -1;
this._trayLeftMouseY = -1;
this._useLongerNotificationLeftTimeout = false;
if (this._notificationLeftTimeoutId) {
Mainloop.source_remove(this._notificationLeftTimeoutId);
this._notificationLeftTimeoutId = 0;
this._notificationLeftMouseX = -1;
this._notificationLeftMouseY = -1;
return;
}
@ -2115,32 +2117,32 @@ const MessageTray = new Lang.Class({
global.stage.get_actor_at_pos(Clutter.PickMode.ALL, this._showNotificationMouseX, this._showNotificationMouseY);
this._showNotificationMouseX = -1;
this._showNotificationMouseY = -1;
// Don't set this._pointerInTray to true if the pointer was initially in the area where the notification
// Don't set this._pointerInNotification to true if the pointer was initially in the area where the notification
// popped up. That way we will not be expanding notifications that happen to pop up over the pointer
// automatically. Instead, the user is able to expand the notification by mousing away from it and then
// mousing back in. Because this is an expected action, we set the boolean flag that indicates that a longer
// timeout should be used before popping down the notification.
if (this.actor.contains(actorAtShowNotificationPosition)) {
this._useLongerTrayLeftTimeout = true;
this._useLongerNotificationLeftTimeout = true;
return;
}
}
this._pointerInTray = true;
this._pointerInNotification = true;
this._updateState();
} else {
// We record the position of the mouse the moment it leaves the tray. These coordinates are used in
// this._onTrayLeftTimeout() to determine if the mouse has moved far enough during the initial timeout for us
// this._onNotificationLeftTimeout() to determine if the mouse has moved far enough during the initial timeout for us
// to consider that the user intended to leave the tray and therefore hide the tray. If the mouse is still
// close to its previous position, we extend the timeout once.
let [x, y, mods] = global.get_pointer();
this._trayLeftMouseX = x;
this._trayLeftMouseY = y;
this._notificationLeftMouseX = x;
this._notificationLeftMouseY = y;
// We wait just a little before hiding the message tray in case the user quickly moves the mouse back into it.
// We wait for a longer period if the notification popped up where the mouse pointer was already positioned.
// That gives the user more time to mouse away from the notification and mouse back in in order to expand it.
let timeout = this._useLongerTrayLeftTimeout ? LONGER_HIDE_TIMEOUT * 1000 : HIDE_TIMEOUT * 1000;
this._trayLeftTimeoutId = Mainloop.timeout_add(timeout, Lang.bind(this, this._onTrayLeftTimeout));
let timeout = this._useLongerNotificationLeftTimeout ? LONGER_HIDE_TIMEOUT * 1000 : HIDE_TIMEOUT * 1000;
this._notificationLeftTimeoutId = Mainloop.timeout_add(timeout, Lang.bind(this, this._onNotificationLeftTimeout));
}
},
@ -2164,22 +2166,22 @@ const MessageTray = new Lang.Class({
this._updateState();
},
_onTrayLeftTimeout: function() {
_onNotificationLeftTimeout: function() {
let [x, y, mods] = global.get_pointer();
// We extend the timeout once if the mouse moved no further than MOUSE_LEFT_ACTOR_THRESHOLD to either side or up.
// We don't check how far down the mouse moved because any point above the tray, but below the exit coordinate,
// is close to the tray.
if (this._trayLeftMouseX > -1 &&
y > this._trayLeftMouseY - MOUSE_LEFT_ACTOR_THRESHOLD &&
x < this._trayLeftMouseX + MOUSE_LEFT_ACTOR_THRESHOLD &&
x > this._trayLeftMouseX - MOUSE_LEFT_ACTOR_THRESHOLD) {
this._trayLeftMouseX = -1;
this._trayLeftTimeoutId = Mainloop.timeout_add(LONGER_HIDE_TIMEOUT * 1000,
Lang.bind(this, this._onTrayLeftTimeout));
if (this._notificationLeftMouseX > -1 &&
y > this._notificationLeftMouseY - MOUSE_LEFT_ACTOR_THRESHOLD &&
x < this._notificationLeftMouseX + MOUSE_LEFT_ACTOR_THRESHOLD &&
x > this._notificationLeftMouseX - MOUSE_LEFT_ACTOR_THRESHOLD) {
this._notificationLeftMouseX = -1;
this._notificationLeftTimeoutId = Mainloop.timeout_add(LONGER_HIDE_TIMEOUT * 1000,
Lang.bind(this, this._onNotificationLeftTimeout));
} else {
this._trayLeftTimeoutId = 0;
this._useLongerTrayLeftTimeout = false;
this._pointerInTray = false;
this._notificationLeftTimeoutId = 0;
this._useLongerNotificationLeftTimeout = false;
this._pointerInNotification = false;
this._updateNotificationTimeout(0);
this._updateState();
}
@ -2187,7 +2189,7 @@ const MessageTray = new Lang.Class({
},
_escapeTray: function() {
this._pointerInTray = false;
this._pointerInNotification = false;
this._traySummoned = false;
this._setClickedSummaryItem(null);
this._updateNotificationTimeout(0);
@ -2196,26 +2198,33 @@ 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._traySummoned', etc, and
// 'this._pointerInNotification', 'this._traySummoned', etc, and
// _updateState() figures out what (if anything) needs to be done
// at the present time.
_updateState: function() {
// Notifications
let notificationQueue = this._notificationQueue;
let notificationQueue = this._notificationQueue.filter(function(n) {
return !n.acknowledged;
});
let hasNotifications = Main.sessionMode.hasNotifications;
this._notificationQueue = notificationQueue;
let notificationUrgent = notificationQueue.length > 0 && notificationQueue[0].urgency == Urgency.CRITICAL;
let notificationForFeedback = notificationQueue.length > 0 && notificationQueue[0].forFeedback;
let notificationsLimited = this._busy || Main.layoutManager.bottomMonitor.inFullscreen;
let notificationsPending = notificationQueue.length > 0 && (!notificationsLimited || notificationUrgent || notificationForFeedback) && Main.sessionMode.hasNotifications;
let notificationsPending = notificationQueue.length > 0 && (!notificationsLimited || notificationUrgent || notificationForFeedback) && hasNotifications;
let nextNotification = notificationQueue.length > 0 ? notificationQueue[0] : null;
let notificationPinned = this._pointerInTray && !this._notificationRemoved;
let notificationPinned = this._pointerInNotification && !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;
let notificationLockedOut = !Main.sessionMode.hasNotifications && this._notification;
let notificationMustClose = this._notificationRemoved || notificationLockedOut || (notificationExpired && this._userActiveWhileNotificationShown) || this._notificationClosed;
let canShowNotification = notificationsPending && this._trayState == State.HIDDEN;
!this._pointerInNotification;
let notificationLockedOut = !hasNotifications && this._notification;
let notificationMustClose = (this._notificationRemoved || notificationLockedOut ||
(notificationExpired && this._userActiveWhileNotificationShown) ||
this._notificationClosed || this._traySummoned);
let canShowNotification = notificationsPending && this._trayState == State.HIDDEN && !this._traySummoned;
if (this._notificationState == State.HIDDEN) {
if (canShowNotification)
@ -2229,12 +2238,6 @@ const MessageTray = new Lang.Class({
this._ensureNotificationFocused();
}
let notificationsVisible = this._notificationState != State.HIDDEN;
let notificationsDone = !notificationsVisible && !notificationsPending;
let mustHideTray = ((notificationsPending && notificationUrgent)
|| notificationsVisible || !Main.sessionMode.hasNotifications);
// Summary notification
let haveClickedSummaryItem = this._clickedSummaryItem != null;
let summarySourceIsMainNotificationSource = (haveClickedSummaryItem && this._notification &&
@ -2242,10 +2245,15 @@ const MessageTray = new Lang.Class({
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));
@ -2254,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 || mustHideTray) {
if (!haveClickedSummaryItem || !canShowSummaryBoxPointer || wrongSummaryBoxPointer || !hasNotifications) {
this._hideSummaryBoxPointer();
if (wrongSummaryBoxPointer)
this._showSummaryBoxPointer();
@ -2264,7 +2272,7 @@ const MessageTray = new Lang.Class({
// Tray itself
let trayIsVisible = (this._trayState == State.SHOWING ||
this._trayState == State.SHOWN);
let trayShouldBeVisible = this._traySummoned && !this._keyboardVisible && !mustHideTray;
let trayShouldBeVisible = this._traySummoned && !this._keyboardVisible && hasNotifications;
if (!trayIsVisible && trayShouldBeVisible)
trayShouldBeVisible = this._showTray();
else if (trayIsVisible && !trayShouldBeVisible)
@ -2321,7 +2329,8 @@ const MessageTray = new Lang.Class({
transition: 'easeOutQuad'
});
this._lightbox.show();
for (let i = 0; i < this._lightboxes.length; i++)
this._lightboxes[i].show();
return true;
},
@ -2344,7 +2353,7 @@ const MessageTray = new Lang.Class({
if (this._desktopClone)
this._desktopClone.destroy();
let cloneSource = Main.overview.visible ? global.overlay_group : global.window_group;
let cloneSource = Main.overview.visible ? Main.layoutManager.overviewGroup : global.window_group;
this._desktopClone = new Clutter.Clone({ source: cloneSource,
clip: new Clutter.Geometry(this._bottomMonitorGeometry) });
Main.uiGroup.insert_child_above(this._desktopClone, cloneSource);
@ -2376,7 +2385,8 @@ const MessageTray = new Lang.Class({
// which would happen if GrabHelper ungrabbed for us.
// This is a no-op in that case.
this._grabHelper.ungrab({ actor: this.actor });
this._lightbox.hide();
for (let i = 0; i < this._lightboxes.length; i++)
this._lightboxes[i].hide();
},
_hideDesktopClone: function() {
@ -2425,7 +2435,7 @@ const MessageTray = new Lang.Class({
let [x, y, mods] = global.get_pointer();
// We save the position of the mouse at the time when we started showing the notification
// in order to determine if the notification popped up under it. We make that check if
// the user starts moving the mouse and _onTrayHoverChanged() gets called. We don't
// the user starts moving the mouse and _onNotificationHoverChanged() gets called. We don't
// expand the notification if it just happened to pop up under the mouse unless the user
// explicitly mouses away from it and then mouses back in.
this._showNotificationMouseX = x;
@ -2487,13 +2497,13 @@ const MessageTray = new Lang.Class({
_notificationTimeout: function() {
let [x, y, mods] = global.get_pointer();
if (y > this._lastSeenMouseY + 10 && !this.actor.hover) {
if (y > this._lastSeenMouseY + 10 && !this._notificationHovered) {
// The mouse is moving towards the notification, so don't
// hide it yet. (We just create a new timeout (and destroy
// the old one) each time because the bookkeeping is
// simpler.)
this._updateNotificationTimeout(1000);
} else if (this._useLongerTrayLeftTimeout && !this._trayLeftTimeoutId &&
} else if (this._useLongerNotificationLeftTimeout && !this._notificationLeftTimeoutId &&
(x != this._lastSeenMouseX || y != this._lastSeenMouseY)) {
// Refresh the timeout if the notification originally
// popped up under the pointer, and the pointer is hovering
@ -2537,12 +2547,12 @@ 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;
this._useLongerNotificationLeftTimeout = false;
if (this._notificationLeftTimeoutId) {
Mainloop.source_remove(this._notificationLeftTimeoutId);
this._notificationLeftTimeoutId = 0;
this._notificationLeftMouseX = -1;
this._notificationLeftMouseY = -1;
}
if (this._notificationRemoved) {
@ -2572,14 +2582,9 @@ const MessageTray = new Lang.Class({
if (notification.isTransient)
notification.destroy(NotificationDestroyedReason.EXPIRED);
this._notificationRemoved = false;
this._closeButton.hide();
this._pointerInTray = false;
// 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._pointerInNotification = false;
this._notificationRemoved = false;
this._notificationBin.child = null;
this._notificationWidget.hide();
},
@ -2639,38 +2644,37 @@ const MessageTray = new Lang.Class({
},
_showSummaryBoxPointer: function() {
this._summaryBoxPointerItem = this._clickedSummaryItem;
let child;
let summaryItem = this._clickedSummaryItem;
if (this._clickedSummaryItemMouseButton == 1) {
// Acknowledge all our notifications
summaryItem.source.notifications.forEach(function(n) { n.acknowledged = true; });
child = summaryItem.notificationStackWidget;
let closeButton = summaryItem.closeButton;
closeButton.show();
this._summaryBoxPointerCloseClickedId = closeButton.connect('clicked', Lang.bind(this, this._hideSummaryBoxPointer));
summaryItem.prepareNotificationStackForShowing();
} else if (this._clickedSummaryItemMouseButton == 3) {
child = summaryItem.rightClickMenu;
this._summaryBoxPointerCloseClickedId = 0;
}
// If the user clicked the middle mouse button, or the item
// doesn't have a right-click menu, do nothing.
if (!child)
return;
this._summaryBoxPointerItem = summaryItem;
this._summaryBoxPointerContentUpdatedId = this._summaryBoxPointerItem.connect('content-updated',
Lang.bind(this, this._onSummaryBoxPointerContentUpdated));
this._sourceDoneDisplayingId = this._summaryBoxPointerItem.source.connect('done-displaying-content',
Lang.bind(this, this._onSourceDoneDisplayingContent));
let hasRightClickMenu = this._summaryBoxPointerItem.rightClickMenu != null;
if (this._clickedSummaryItemMouseButton == 1 || !hasRightClickMenu) {
let newQueue = [];
for (let i = 0; i < this._notificationQueue.length; i++) {
let notification = this._notificationQueue[i];
let sameSource = this._summaryBoxPointerItem.source == notification.source;
if (sameSource)
notification.acknowledged = true;
else
newQueue.push(notification);
}
this._notificationQueue = newQueue;
this._summaryBoxPointer.bin.child = this._summaryBoxPointerItem.notificationStackWidget;
let closeButton = this._summaryBoxPointerItem.closeButton;
closeButton.show();
this._summaryBoxPointerCloseClickedId = closeButton.connect('clicked', Lang.bind(this, this._hideSummaryBoxPointer));
this._summaryBoxPointerItem.prepareNotificationStackForShowing();
} else if (this._clickedSummaryItemMouseButton == 3) {
this._summaryBoxPointer.bin.child = this._clickedSummaryItem.rightClickMenu;
this._summaryBoxPointerCloseClickedId = 0;
}
this._summaryBoxPointer.bin.child = child;
this._grabHelper.grab({ actor: this._summaryBoxPointer.bin.child,
grabFocus: true,
modal: true,
onUngrab: Lang.bind(this, this._onSummaryBoxPointerUngrabbed) });
this._summaryBoxPointer.actor.opacity = 0;
@ -2779,17 +2783,14 @@ const MessageTray = new Lang.Class({
this._summaryBoxPointerState = State.HIDDEN;
this._summaryBoxPointer.bin.child = null;
let sourceNotificationStackDoneShowing = null;
if (doneShowingNotificationStack) {
let source = this._summaryBoxPointerItem.source;
this._summaryBoxPointerItem.doneShowingNotificationStack();
sourceNotificationStackDoneShowing = this._summaryBoxPointerItem.source;
}
this._summaryBoxPointerItem = null;
this._summaryBoxPointerItem = null;
if (sourceNotificationStackDoneShowing) {
if (sourceNotificationStackDoneShowing.isTransient && !this._reNotifyAfterHideNotification)
sourceNotificationStackDoneShowing.destroy(NotificationDestroyedReason.EXPIRED);
if (source.isTransient && !this._reNotifyAfterHideNotification)
source.destroy(NotificationDestroyedReason.EXPIRED);
if (this._reNotifyAfterHideNotification) {
this._onNotify(this._reNotifyAfterHideNotification.source, this._reNotifyAfterHideNotification);
this._reNotifyAfterHideNotification = null;

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,
@ -65,7 +69,9 @@ const ModalDialog = new Lang.Class({
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);
@ -81,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.Actor({ reactive: true });
stack.add_actor(this._eventBlocker);
stack.add_actor(this.dialogLayout);
} else {
this._backgroundBin.child = this.dialogLayout;
this.backgroundStack.add_actor(this._eventBlocker);
}
this.backgroundStack.add_actor(this.dialogLayout);
this.contentLayout = new St.BoxLayout({ vertical: true });
@ -110,6 +111,8 @@ const ModalDialog = new Lang.Class({
this._initialKeyFocus = this.dialogLayout;
this._initialKeyFocusDestroyId = 0;
this._savedKeyFocus = null;
this._workSpinner = null;
},
destroy: function() {
@ -183,6 +186,44 @@ const ModalDialog = new Lang.Class({
return button;
},
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();
},

View File

@ -8,6 +8,7 @@ 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;
@ -71,6 +72,7 @@ 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,
@ -80,6 +82,15 @@ const OsdWindow = new Lang.Class({
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 });
@ -96,7 +107,7 @@ const OsdWindow = new Lang.Class({
Lang.bind(this, this._monitorsChanged));
this._monitorsChanged();
Main.layoutManager.addChrome(this.actor, { affectsInputRegion: false });
Main.uiGroup.add_child(this.actor);
},
setIcon: function(icon) {
@ -125,8 +136,10 @@ const OsdWindow = new Lang.Class({
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,
@ -161,6 +174,7 @@ const OsdWindow = new Lang.Class({
this.actor.hide();
this.setLabel(null);
this.setLevel(null);
Meta.enable_unredirect_for_screen(global.screen);
},
_monitorsChanged: function() {
@ -169,11 +183,25 @@ const OsdWindow = new Lang.Class({
let scalew = monitor.width / 640.0;
let scaleh = monitor.height / 480.0;
let scale = Math.min(scalew, scaleh);
let size = 110 * Math.max(1, scale);
this._popupSize = 110 * Math.max(1, scale);
this._box.set_size(size, size);
this._box.translation_y = monitor.height / 4;
this._icon.icon_size = this._popupSize / 2;
this._box.style_changed();
},
this._icon.icon_size = size / 2;
_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

@ -11,7 +11,6 @@ const Shell = imports.gi.Shell;
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;
@ -20,7 +19,6 @@ const OverviewControls = imports.ui.overviewControls;
const Panel = imports.ui.panel;
const Params = imports.misc.params;
const Tweener = imports.ui.tweener;
const ViewSelector = imports.ui.viewSelector;
const WorkspaceThumbnail = imports.ui.workspaceThumbnail;
// Time for initial animation going into Overview mode
@ -31,7 +29,7 @@ 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;
@ -117,7 +115,7 @@ const Overview = new Lang.Class({
let monitor = Main.layoutManager.primaryMonitor;
this._desktopFade = new St.Bin();
global.overlay_group.add_actor(this._desktopFade);
Main.layoutManager.overviewGroup.add_child(this._desktopFade);
let layout = new Clutter.BinLayout();
this._stack = new Clutter.Actor({ layout_manager: layout });
@ -133,17 +131,8 @@ const Overview = new Lang.Class({
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,
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();
Main.layoutManager.overviewGroup.add_child(this._backgroundGroup);
this._bgManagers = [];
this._activationTime = 0;
@ -157,14 +146,13 @@ const Overview = new Lang.Class({
// During transitions, we raise this to the top to avoid having the overview
// area be reactive; it causes too many issues such as double clicks on
// Dash elements, or mouseover handlers in the workspaces.
this._coverPane = new Clutter.Rectangle({ opacity: 0,
reactive: true });
this._coverPane = new Clutter.Actor({ opacity: 0,
reactive: true });
this._overview.add_actor(this._coverPane);
this._coverPane.connect('event', Lang.bind(this, function (actor, event) { return true; }));
this._stack.hide();
this._stack.add_actor(this._overview);
global.overlay_group.add_actor(this._stack);
Main.layoutManager.overviewGroup.add_child(this._stack);
this._coverPane.hide();
@ -177,7 +165,6 @@ const Overview = new Lang.Class({
Main.xdndHandler.connect('drag-end', Lang.bind(this, this._onDragEnd));
global.screen.connect('restacked', Lang.bind(this, this._onRestacked));
this._group.connect('scroll-event', Lang.bind(this, this._onScrollEvent));
this._windowSwitchTimeoutId = 0;
this._windowSwitchTimestamp = 0;
@ -276,28 +263,13 @@ const Overview = new Lang.Class({
this._overview.add_actor(this._searchEntryBin);
// Create controls
this._dash = new Dash.Dash();
this._viewSelector = new ViewSelector.ViewSelector(this._searchEntry,
this._dash.showAppsButton);
this._thumbnailsBox = new WorkspaceThumbnail.ThumbnailsBox();
this._controls = new OverviewControls.ControlsManager(this._dash,
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.dashSpacer);
this._group.add(this._viewSelector.actor, { x_fill: true,
expand: true });
this._group.add_actor(this._controls.thumbnailsActor);
this._controls = new OverviewControls.ControlsManager(this._searchEntry);
this._dash = this._controls.dash;
this._viewSelector = this._controls.viewSelector;
// Add our same-line elements after the search entry
this._overview.add(this._groupStack, { y_fill: true, expand: true });
this._overview.add(this._controls.actor, { y_fill: true, expand: true });
this._controls.actor.connect('scroll-event', Lang.bind(this, this._onScrollEvent));
this._stack.add_actor(this._controls.indicatorActor);
@ -461,6 +433,7 @@ const Overview = new Lang.Class({
beginItemDrag: function(source) {
this.emit('item-drag-begin');
this._inDrag = true;
},
cancelledItemDrag: function(source) {
@ -469,10 +442,12 @@ const Overview = new Lang.Class({
endItemDrag: function(source) {
this.emit('item-drag-end');
this._inDrag = false;
},
beginWindowDrag: function(source) {
this.emit('window-drag-begin');
this._inDrag = true;
},
cancelledWindowDrag: function(source) {
@ -481,24 +456,31 @@ const Overview = new Lang.Class({
endWindowDrag: function(source) {
this.emit('window-drag-end');
this._inDrag = false;
},
// show:
//
// Animates the overview visible and grabs mouse and keyboard input
show : function() {
show: function() {
if (this.isDummy)
return;
if (this._shown)
return;
this._shown = true;
if (!this._syncInputMode())
if (!this._syncGrab())
return;
Main.layoutManager.showOverview();
this._animateVisible();
},
focusSearch: function() {
this.show();
this._searchEntry.grab_key_focus();
},
fadeInDesktop: function() {
this._desktopFade.opacity = 0;
this._desktopFade.show();
@ -540,8 +522,6 @@ const Overview = new Lang.Class({
//
// Disable unredirection while in the overview
Meta.disable_unredirect_for_screen(global.screen);
this._stack.show();
this._backgroundGroup.show();
this._viewSelector.show();
this._stack.opacity = 0;
@ -582,7 +562,7 @@ const Overview = new Lang.Class({
this._animateNotVisible();
this._shown = false;
this._syncInputMode();
this._syncGrab();
},
toggle: function() {
@ -604,6 +584,8 @@ const Overview = new Lang.Class({
shouldToggleByCornerOrButton: function() {
if (this.animationInProgress)
return false;
if (this._inDrag)
return false;
if (this._activationTime == 0 || Date.now() / 1000 - this._activationTime > OVERVIEW_ACTIVATION_TIMEOUT)
return true;
return false;
@ -611,8 +593,8 @@ const Overview = new Lang.Class({
//// Private methods ////
_syncInputMode: function() {
// We delay input mode changes during animation so that when removing the
_syncGrab: function() {
// We delay grab changes during animation so that when removing the
// overview we don't have a problem with the release of a press/release
// going to an application.
if (this.animationInProgress)
@ -630,16 +612,12 @@ const Overview = new Lang.Class({
return false;
}
}
} else {
global.stage_input_mode = Shell.StageInputMode.FULLSCREEN;
}
} else {
if (this._modal) {
Main.popModal(this._overview);
this._modal = false;
}
else if (global.stage_input_mode == Shell.StageInputMode.FULLSCREEN)
global.stage_input_mode = Shell.StageInputMode.NORMAL;
}
return true;
},
@ -678,7 +656,7 @@ const Overview = new Lang.Class({
if (!this._shown)
this._animateNotVisible();
this._syncInputMode();
this._syncGrab();
global.sync_pointer();
},
@ -688,20 +666,19 @@ const Overview = new Lang.Class({
this._viewSelector.hide();
this._desktopFade.hide();
this._backgroundGroup.hide();
this._stack.hide();
this._coverPane.hide();
this.visible = false;
this.animationInProgress = false;
this._coverPane.hide();
this.emit('hidden');
// Handle any calls to show* while we were hiding
if (this._shown)
this._animateVisible();
else
Main.layoutManager.hideOverview();
this._syncInputMode();
this._syncGrab();
// Fake a pointer event if requested
if (this._needsFakePointerEvent) {

View File

@ -1,15 +1,18 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
const GObject = imports.gi.GObject;
const Clutter = imports.gi.Clutter;
const Lang = imports.lang;
const Meta = imports.gi.Meta;
const St = imports.gi.St;
const Shell = imports.gi.Shell;
const Dash = imports.ui.dash;
const Main = imports.ui.main;
const Params = imports.misc.params;
const Tweener = imports.ui.tweener;
const ViewSelector = imports.ui.viewSelector;
const WorkspaceThumbnail = imports.ui.workspaceThumbnail;
const SIDE_CONTROLS_ANIMATION_TIME = 0.16;
@ -244,6 +247,7 @@ const ThumbnailsSlider = new Lang.Class({
Main.layoutManager.connect('monitors-changed', Lang.bind(this, this.updateSlide));
this.actor.connect('notify::hover', Lang.bind(this, this.updateSlide));
this._thumbnailsBox.actor.bind_property('visible', this.actor, 'visible', GObject.BindingFlags.SYNC_CREATE);
},
_getAlwaysZoomOut: function() {
@ -269,6 +273,11 @@ const ThumbnailsSlider = new Lang.Class({
return alwaysZoomOut;
},
getNonExpandedWidth: function() {
let child = this.actor.get_first_child();
return child.get_theme_node().get_length('visible-width');
},
getSlide: function() {
if (!this.visible)
return 0;
@ -280,18 +289,16 @@ const ThumbnailsSlider = new Lang.Class({
let child = this.actor.get_first_child();
let preferredHeight = child.get_preferred_height(-1)[1];
let expandedWidth = child.get_preferred_width(preferredHeight)[1];
let visibleWidth = child.get_theme_node().get_length('visible-width');
return visibleWidth / expandedWidth;
return this.getNonExpandedWidth() / expandedWidth;
},
getVisibleWidth: function() {
let alwaysZoomOut = this._getAlwaysZoomOut();
if (alwaysZoomOut)
return this.parent();
let child = this.actor.get_first_child();
return child.get_theme_node().get_length('visible-width');
else
return this.getNonExpandedWidth();
}
});
@ -309,6 +316,10 @@ const DashSlider = new Lang.Class({
// available allocation
this._dash.actor.x_expand = true;
this._dash.actor.y_expand = true;
this.actor.x_align = Clutter.ActorAlign.START;
this.actor.y_expand = true;
this.actor.add_actor(this._dash.actor);
this._dash.connect('icon-size-changed', Lang.bind(this, this.updateSlide));
@ -479,39 +490,77 @@ const MessagesIndicator = new Lang.Class({
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);
_init: function(searchEntry) {
this.dash = new Dash.Dash();
this._dashSlider = new DashSlider(this.dash);
this._dashSpacer = new DashSpacer();
this._dashSpacer.setDashActor(this._dashSlider.actor);
this._thumbnailsSlider = new ThumbnailsSlider(thumbnails);
this.thumbnailsActor = this._thumbnailsSlider.actor;
this._thumbnailsBox = new WorkspaceThumbnail.ThumbnailsBox();
this._thumbnailsSlider = new ThumbnailsSlider(this._thumbnailsBox);
this._indicator = new MessagesIndicator(viewSelector);
this.viewSelector = new ViewSelector.ViewSelector(searchEntry,
this.dash.showAppsButton);
this.viewSelector.connect('page-changed', Lang.bind(this, this._setVisibility));
this.viewSelector.connect('page-empty', Lang.bind(this, this._onPageEmpty));
this._indicator = new MessagesIndicator(this.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));
this.actor = new St.Widget({ layout_manager: new Clutter.BinLayout(),
reactive: true,
x_expand: true, y_expand: true,
clip_to_allocation: true });
this._group = new St.BoxLayout({ name: 'overview-group',
x_expand: true, y_expand: true });
this.actor.add_actor(this._group);
this.actor.add_actor(this._dashSlider.actor);
this._group.add_actor(this._dashSpacer);
this._group.add(this.viewSelector.actor, { x_fill: true,
expand: true });
this._group.add_actor(this._thumbnailsSlider.actor);
this._group.connect('notify::allocation', Lang.bind(this, this._updateWorkspacesGeometry));
Main.overview.connect('showing', Lang.bind(this, this._updateSpacerVisibility));
Main.overview.connect('item-drag-begin', Lang.bind(this,
function() {
let activePage = this._viewSelector.getActivePage();
let activePage = this.viewSelector.getActivePage();
if (activePage != ViewSelector.ViewPage.WINDOWS)
this._viewSelector.fadeHalf();
this.viewSelector.fadeHalf();
}));
Main.overview.connect('item-drag-end', Lang.bind(this,
function() {
this._viewSelector.fadeIn();
this.viewSelector.fadeIn();
}));
Main.overview.connect('item-drag-cancelled', Lang.bind(this,
function() {
this._viewSelector.fadeIn();
this.viewSelector.fadeIn();
}));
},
_updateWorkspacesGeometry: function() {
let [x, y] = this.actor.get_transformed_position();
let [width, height] = this.actor.get_transformed_size();
let geometry = { x: x, y: y, width: width, height: height };
let spacing = this.actor.get_theme_node().get_length('spacing');
let dashWidth = this._dashSlider.getVisibleWidth() + spacing;
let thumbnailsWidth = this._thumbnailsSlider.getNonExpandedWidth() + spacing;
geometry.width -= dashWidth;
geometry.width -= thumbnailsWidth;
if (this.actor.get_text_direction() == Clutter.TextDirection.LTR)
geometry.x += dashWidth;
else
geometry.x += thumbnailsWidth;
this.viewSelector.setWorkspacesFullGeometry(geometry);
},
_setVisibility: function() {
// Ignore the case when we're leaving the overview, since
// actors will be made visible again when entering the overview
@ -521,7 +570,7 @@ const ControlsManager = new Lang.Class({
(Main.overview.animationInProgress && !Main.overview.visibleTarget))
return;
let activePage = this._viewSelector.getActivePage();
let activePage = this.viewSelector.getActivePage();
let dashVisible = (activePage == ViewSelector.ViewPage.WINDOWS ||
activePage == ViewSelector.ViewPage.APPS);
let thumbnailsVisible = (activePage == ViewSelector.ViewPage.WINDOWS);
@ -541,8 +590,8 @@ const ControlsManager = new Lang.Class({
if (Main.overview.animationInProgress && !Main.overview.visibleTarget)
return;
let activePage = this._viewSelector.getActivePage();
this.dashSpacer.visible = (activePage == ViewSelector.ViewPage.WINDOWS);
let activePage = this.viewSelector.getActivePage();
this._dashSpacer.visible = (activePage == ViewSelector.ViewPage.WINDOWS);
},
_onPageEmpty: function() {

View File

@ -21,6 +21,7 @@ const DND = imports.ui.dnd;
const Overview = imports.ui.overview;
const PopupMenu = imports.ui.popupMenu;
const PanelMenu = imports.ui.panelMenu;
const RemoteMenu = imports.ui.remoteMenu;
const Main = imports.ui.main;
const Tweener = imports.ui.tweener;
@ -144,8 +145,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);
}
});
@ -258,6 +259,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);
@ -288,27 +290,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();
},
@ -354,6 +354,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');
@ -385,6 +397,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,
@ -401,6 +417,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();
},
@ -463,6 +483,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;
@ -546,14 +569,20 @@ const AppMenuButton = new Lang.Class({
}
if (targetApp == this._targetApp) {
if (targetApp && targetApp.get_state() != Shell.AppState.STARTING) {
if (targetApp &&
targetApp.get_state() != Shell.AppState.STARTING &&
targetApp.get_state() != Shell.AppState.BUSY) {
this.stopAnimation();
this._maybeSetMenu();
} else if (targetApp &&
targetApp.get_state() == Shell.AppState.BUSY) {
this.startAnimation();
}
return;
}
this._spinner.actor.hide();
if (this._spinner)
this._spinner.actor.hide();
if (this._iconBox.child != null)
this._iconBox.child.destroy();
this._iconBox.hide();
@ -580,7 +609,8 @@ const AppMenuButton = new Lang.Class({
this._iconBox.set_child(icon);
this._iconBox.show();
if (targetApp.get_state() == Shell.AppState.STARTING)
if (targetApp.get_state() == Shell.AppState.STARTING ||
targetApp.get_state() == Shell.AppState.BUSY)
this.startAnimation();
else
this._maybeSetMenu();
@ -592,11 +622,11 @@ const AppMenuButton = new Lang.Class({
let menu;
if (this._targetApp.action_group && this._targetApp.menu) {
if (this.menu instanceof PopupMenu.RemoteMenu &&
if (this.menu instanceof RemoteMenu.RemoteMenu &&
this.menu.actionGroup == this._targetApp.action_group)
return;
menu = new PopupMenu.RemoteMenu(this.actor, this._targetApp.menu, this._targetApp.action_group);
menu = new RemoteMenu.RemoteMenu(this.actor, this._targetApp.menu, this._targetApp.action_group);
menu.connect('activate', Lang.bind(this, function() {
let win = this._targetApp.get_windows()[0];
win.check_alive(global.get_current_time());
@ -616,6 +646,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();
}
});
@ -873,7 +930,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
@ -902,7 +958,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);
@ -1056,17 +1112,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

@ -184,6 +184,9 @@ const Button = new Lang.Class({
},
_onMenuKeyPress: function(actor, event) {
if (global.focus_manager.navigate_from_event(event))
return true;
let symbol = event.get_key_symbol();
if (symbol == Clutter.KEY_Left || symbol == Clutter.KEY_Right) {
let group = global.focus_manager.get_group(this.actor);

View File

@ -15,9 +15,14 @@ const GrabHelper = imports.ui.grabHelper;
const Main = imports.ui.main;
const Params = imports.misc.params;
const Separator = imports.ui.separator;
const Slider = imports.ui.slider;
const Tweener = imports.ui.tweener;
const SLIDER_SCROLL_STEP = 0.05; /* Slider scrolling step in % */
const Ornament = {
NONE: 0,
DOT: 1,
CHECK: 2,
};
function _ensureStyle(actor) {
if (actor.get_children) {
@ -53,7 +58,9 @@ const PopupBaseMenuItem = new Lang.Class({
this.actor._delegate = this;
this._children = [];
this._dot = null;
this._ornament = Ornament.NONE;
this._ornamentLabel = new St.Label({ style_class: 'popup-menu-ornament' });
this.actor.add_actor(this._ornamentLabel);
this._columnWidths = null;
this._spacing = 0;
this.active = false;
@ -176,40 +183,24 @@ const PopupBaseMenuItem = new Lang.Class({
this._removeChild(child);
},
setShowDot: function(show) {
if (show) {
if (this._dot)
return;
setOrnament: function(ornament) {
if (ornament == this._ornament)
return;
this._dot = new St.DrawingArea({ style_class: 'popup-menu-item-dot' });
this._dot.connect('repaint', Lang.bind(this, this._onRepaintDot));
this.actor.add_actor(this._dot);
this.actor.add_accessible_state (Atk.StateType.CHECKED);
} else {
if (!this._dot)
return;
this._ornament = ornament;
this._dot.destroy();
this._dot = null;
this.actor.remove_accessible_state (Atk.StateType.CHECKED);
if (ornament == Ornament.DOT) {
this._ornamentLabel.text = '\u2022';
this.actor.add_accessible_state(Atk.StateType.CHECKED);
} else if (ornament == Ornament.CHECK) {
this._ornamentLabel.text = '\u2713';
this.actor.add_accessible_state(Atk.StateType.CHECKED);
} else if (ornament == Ornament.NONE) {
this._ornamentLabel.text = '';
this.actor.remove_accessible_state(Atk.StateType.CHECKED);
}
},
_onRepaintDot: function(area) {
let cr = area.get_context();
let [width, height] = area.get_surface_size();
let color = area.get_theme_node().get_foreground_color();
cr.setSourceRGBA (
color.red / 255,
color.green / 255,
color.blue / 255,
color.alpha / 255);
cr.arc(width / 2, height / 2, width / 3, 0, 2 * Math.PI);
cr.fill();
cr.$dispose();
},
// This returns column widths in logical order (i.e. from the dot
// to the image), not in visual order (left to right)
getColumnWidths: function() {
@ -280,26 +271,25 @@ const PopupBaseMenuItem = new Lang.Class({
let height = box.y2 - box.y1;
let direction = this.actor.get_text_direction();
if (this._dot) {
// The dot is placed outside box
// one quarter of padding from the border of the container
// (so 3/4 from the inner border)
// (padding is box.x1)
let dotBox = new Clutter.ActorBox();
let dotWidth = Math.round(box.x1 / 2);
// The ornament is placed outside box
// one quarter of padding from the border of the container
// (so 3/4 from the inner border)
// (padding is box.x1)
let ornamentBox = new Clutter.ActorBox();
let ornamentWidth = box.x1;
if (direction == Clutter.TextDirection.LTR) {
dotBox.x1 = Math.round(box.x1 / 4);
dotBox.x2 = dotBox.x1 + dotWidth;
} else {
dotBox.x2 = box.x2 + 3 * Math.round(box.x1 / 4);
dotBox.x1 = dotBox.x2 - dotWidth;
}
dotBox.y1 = Math.round(box.y1 + (height - dotWidth) / 2);
dotBox.y2 = dotBox.y1 + dotWidth;
this._dot.allocate(dotBox, flags);
ornamentBox.x1 = 0;
ornamentBox.x2 = ornamentWidth;
ornamentBox.y1 = box.y1;
ornamentBox.y2 = box.y2;
if (direction == Clutter.TextDirection.RTL) {
ornamentBox.x1 += box.x2;
ornamentBox.x2 += box.x2;
}
this._ornamentLabel.allocate(ornamentBox, flags);
let x;
if (direction == Clutter.TextDirection.LTR)
x = box.x1;
@ -402,12 +392,19 @@ const PopupSeparatorMenuItem = new Lang.Class({
Name: 'PopupSeparatorMenuItem',
Extends: PopupBaseMenuItem,
_init: function () {
_init: function (text) {
this.parent({ reactive: false,
can_focus: false});
this._box = new St.BoxLayout();
this.addActor(this._box, { span: -1, expand: true });
this.label = new St.Label({ text: text || '' });
this._box.add(this.label);
this.actor.label_actor = this.label;
this._separator = new Separator.HorizontalSeparator({ style_class: 'popup-separator-menu-item' });
this.addActor(this._separator.actor, { span: -1, expand: true });
this._box.add(this._separator.actor, { expand: true });
}
});
@ -517,198 +514,19 @@ const PopupSliderMenuItem = new Lang.Class({
_init: function(value) {
this.parent({ activate: false });
this.actor.connect('key-press-event', Lang.bind(this, this._onKeyPressEvent));
if (isNaN(value))
// Avoid spreading NaNs around
throw TypeError('The slider value must be a number');
this._value = Math.max(Math.min(value, 1), 0);
this._slider = new St.DrawingArea({ style_class: 'popup-slider-menu-item', reactive: true });
this.addActor(this._slider, { span: -1, expand: true });
this._slider.connect('repaint', Lang.bind(this, this._sliderRepaint));
this.actor.connect('button-press-event', Lang.bind(this, this._startDragging));
this.actor.connect('scroll-event', Lang.bind(this, this._onScrollEvent));
this.actor.connect('notify::mapped', Lang.bind(this, function() {
if (!this.actor.mapped)
this._endDragging();
this._slider = new Slider.Slider(value);
this._slider.connect('value-changed', Lang.bind(this, function(actor, value) {
this.emit('value-changed', value);
}));
this._releaseId = this._motionId = 0;
this._dragging = false;
this.addActor(this._slider.actor);
},
setValue: function(value) {
if (isNaN(value))
throw TypeError('The slider value must be a number');
this._value = Math.max(Math.min(value, 1), 0);
this._slider.queue_repaint();
},
_sliderRepaint: function(area) {
let cr = area.get_context();
let themeNode = area.get_theme_node();
let [width, height] = area.get_surface_size();
let handleRadius = themeNode.get_length('-slider-handle-radius');
let sliderWidth = width - 2 * handleRadius;
let sliderHeight = themeNode.get_length('-slider-height');
let sliderBorderWidth = themeNode.get_length('-slider-border-width');
let sliderBorderColor = themeNode.get_color('-slider-border-color');
let sliderColor = themeNode.get_color('-slider-background-color');
let sliderActiveBorderColor = themeNode.get_color('-slider-active-border-color');
let sliderActiveColor = themeNode.get_color('-slider-active-background-color');
cr.setSourceRGBA (
sliderActiveColor.red / 255,
sliderActiveColor.green / 255,
sliderActiveColor.blue / 255,
sliderActiveColor.alpha / 255);
cr.rectangle(handleRadius, (height - sliderHeight) / 2, sliderWidth * this._value, sliderHeight);
cr.fillPreserve();
cr.setSourceRGBA (
sliderActiveBorderColor.red / 255,
sliderActiveBorderColor.green / 255,
sliderActiveBorderColor.blue / 255,
sliderActiveBorderColor.alpha / 255);
cr.setLineWidth(sliderBorderWidth);
cr.stroke();
cr.setSourceRGBA (
sliderColor.red / 255,
sliderColor.green / 255,
sliderColor.blue / 255,
sliderColor.alpha / 255);
cr.rectangle(handleRadius + sliderWidth * this._value, (height - sliderHeight) / 2, sliderWidth * (1 - this._value), sliderHeight);
cr.fillPreserve();
cr.setSourceRGBA (
sliderBorderColor.red / 255,
sliderBorderColor.green / 255,
sliderBorderColor.blue / 255,
sliderBorderColor.alpha / 255);
cr.setLineWidth(sliderBorderWidth);
cr.stroke();
let handleY = height / 2;
let handleX = handleRadius + (width - 2 * handleRadius) * this._value;
let color = themeNode.get_foreground_color();
cr.setSourceRGBA (
color.red / 255,
color.green / 255,
color.blue / 255,
color.alpha / 255);
cr.arc(handleX, handleY, handleRadius, 0, 2 * Math.PI);
cr.fill();
cr.$dispose();
},
_startDragging: function(actor, event) {
if (this._dragging) // don't allow two drags at the same time
return;
this._dragging = true;
// FIXME: we should only grab the specific device that originated
// the event, but for some weird reason events are still delivered
// outside the slider if using clutter_grab_pointer_for_device
Clutter.grab_pointer(this._slider);
this._releaseId = this._slider.connect('button-release-event', Lang.bind(this, this._endDragging));
this._motionId = this._slider.connect('motion-event', Lang.bind(this, this._motionEvent));
let absX, absY;
[absX, absY] = event.get_coords();
this._moveHandle(absX, absY);
},
_endDragging: function() {
if (this._dragging) {
this._slider.disconnect(this._releaseId);
this._slider.disconnect(this._motionId);
Clutter.ungrab_pointer();
this._dragging = false;
this.emit('drag-end');
}
return true;
},
scroll: function(event) {
let direction = event.get_scroll_direction();
let delta;
if (event.is_pointer_emulated())
return;
if (direction == Clutter.ScrollDirection.DOWN) {
delta = -SLIDER_SCROLL_STEP;
} else if (direction == Clutter.ScrollDirection.UP) {
delta = +SLIDER_SCROLL_STEP;
} else if (direction == Clutter.ScrollDirection.SMOOTH) {
let [dx, dy] = event.get_scroll_delta();
// Even though the slider is horizontal, use dy to match
// the UP/DOWN above.
delta = -dy / 10;
}
this._value = Math.min(Math.max(0, this._value + delta), 1);
this._slider.queue_repaint();
this.emit('value-changed', this._value);
},
_onScrollEvent: function(actor, event) {
this.scroll(event);
},
_motionEvent: function(actor, event) {
let absX, absY;
[absX, absY] = event.get_coords();
this._moveHandle(absX, absY);
return true;
},
_moveHandle: function(absX, absY) {
let relX, relY, sliderX, sliderY;
[sliderX, sliderY] = this._slider.get_transformed_position();
relX = absX - sliderX;
relY = absY - sliderY;
let width = this._slider.width;
let handleRadius = this._slider.get_theme_node().get_length('-slider-handle-radius');
let newvalue;
if (relX < handleRadius)
newvalue = 0;
else if (relX > width - handleRadius)
newvalue = 1;
else
newvalue = (relX - handleRadius) / (width - 2 * handleRadius);
this._value = newvalue;
this._slider.queue_repaint();
this.emit('value-changed', this._value);
this._slider.setValue(value);
},
get value() {
return this._value;
},
_onKeyPressEvent: function (actor, event) {
let key = event.get_key_symbol();
if (key == Clutter.KEY_Right || key == Clutter.KEY_Left) {
let delta = key == Clutter.KEY_Right ? 0.1 : -0.1;
this._value = Math.max(0, Math.min(this._value + delta, 1));
this._slider.queue_repaint();
this.emit('value-changed', this._value);
this.emit('drag-end');
return true;
}
return false;
return this._slider.value;
}
});
@ -992,6 +810,9 @@ const PopupMenuBase = new Lang.Class({
},
_updateSeparatorVisibility: function(menuItem) {
if (menuItem.label.text)
return;
let children = this.box.get_children();
let index = children.indexOf(menuItem.actor);
@ -1157,6 +978,7 @@ const PopupMenuBase = new Lang.Class({
},
destroy: function() {
this.close();
this.removeAll();
this.actor.destroy();
@ -1474,23 +1296,12 @@ const PopupMenuSection = new Lang.Class({
this.actor = this.box;
this.actor._delegate = this;
this.isOpen = true;
// an array of externally managed separators
this.separators = [];
},
// deliberately ignore any attempt to open() or close(), but emit the
// corresponding signal so children can still pick it up
open: function() { this.emit('open-state-changed', true); },
close: function() { this.emit('open-state-changed', false); },
destroy: function() {
for (let i = 0; i < this.separators.length; i++)
this.separators[i].destroy();
this.separators = [];
this.parent();
}
});
const PopupSubMenuMenuItem = new Lang.Class({
@ -1525,15 +1336,30 @@ const PopupSubMenuMenuItem = new Lang.Class({
this.parent();
},
setSubmenuShown: function(open) {
if (open)
this.menu.open(BoxPointer.PopupAnimation.FULL);
else
this.menu.close(BoxPointer.PopupAnimation.FULL);
},
_setOpenState: function(open) {
this.setSubmenuShown(open);
},
_getOpenState: function() {
return this.menu.isOpen;
},
_onKeyPressEvent: function(actor, event) {
let symbol = event.get_key_symbol();
if (symbol == Clutter.KEY_Right) {
this.menu.open(BoxPointer.PopupAnimation.FULL);
this._setOpenState(true);
this.menu.actor.navigate_focus(null, Gtk.DirectionType.DOWN, false);
return true;
} else if (symbol == Clutter.KEY_Left && this.menu.isOpen) {
this.menu.close();
} else if (symbol == Clutter.KEY_Left && this._getOpenState()) {
this._setOpenState(false);
return true;
}
@ -1541,11 +1367,11 @@ const PopupSubMenuMenuItem = new Lang.Class({
},
activate: function(event) {
this.menu.open(BoxPointer.PopupAnimation.FULL);
this._setOpenState(true);
},
_onButtonReleaseEvent: function(actor) {
this.menu.toggle();
this._setOpenState(!this._getOpenState());
}
});
@ -1791,269 +1617,15 @@ const PopupComboBoxMenuItem = new Lang.Class({
}
});
/**
* RemoteMenu:
*
* A PopupMenu that tracks a GMenuModel and shows its actions
* (exposed by GApplication/GActionGroup)
*/
const RemoteMenu = new Lang.Class({
Name: 'RemoteMenu',
Extends: PopupMenu,
_init: function(sourceActor, model, actionGroup) {
this.parent(sourceActor, 0.0, St.Side.TOP);
this.model = model;
this.actionGroup = actionGroup;
this._actions = { };
this._modelChanged(this.model, 0, 0, this.model.get_n_items(), this);
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));
},
destroy: function() {
if (this._actionStateChangeId) {
this.actionGroup.disconnect(this._actionStateChangeId);
this._actionStateChangeId = 0;
}
if (this._actionEnableChangeId) {
this.actionGroup.disconnect(this._actionEnableChangeId);
this._actionEnableChangeId = 0;
}
this.parent();
},
_createMenuItem: function(model, index) {
let labelValue = model.get_item_attribute_value(index, Gio.MENU_ATTRIBUTE_LABEL, null);
let label = labelValue ? labelValue.deep_unpack() : '';
// remove all underscores that are not followed by another underscore
label = label.replace(/_([^_])/, '$1');
let section_link = model.get_item_link(index, Gio.MENU_LINK_SECTION);
if (section_link) {
let item = new PopupMenuSection();
if (label) {
let title = new PopupMenuItem(label, { reactive: false,
style_class: 'popup-subtitle-menu-item' });
item._titleMenuItem = title;
title._ignored = true;
item.addMenuItem(title);
}
this._modelChanged(section_link, 0, 0, section_link.get_n_items(), item);
return [item, true, ''];
}
let submenu_link = model.get_item_link(index, Gio.MENU_LINK_SUBMENU);
if (submenu_link) {
let item = new PopupSubMenuMenuItem(label);
this._modelChanged(submenu_link, 0, 0, submenu_link.get_n_items(), item.menu);
return [item, false, ''];
}
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'];
}
if (!this._actions[action_id])
this._actions[action_id] = { enabled: this.actionGroup.get_action_enabled(action_id),
state: this.actionGroup.get_action_state(action_id),
items: [ ],
};
let action = this._actions[action_id];
let item, target, destroyId, specificSignalId;
if (action.state) {
// Docs have get_state_hint(), except that the DBus protocol
// has no provision for it (so ShellApp does not implement it,
// and neither GApplication), and g_action_get_state_hint()
// always returns null
// Funny :)
switch (String.fromCharCode(action.state.classify())) {
case 'b':
item = new PopupSwitchMenuItem(label, action.state.get_boolean());
action.items.push(item);
specificSignalId = item.connect('toggled', Lang.bind(this, function(item) {
this.actionGroup.activate_action(action_id, null);
}));
break;
case 's':
item = new PopupMenuItem(label);
item._remoteTarget = model.get_item_attribute_value(index, Gio.MENU_ATTRIBUTE_TARGET, null).deep_unpack();
action.items.push(item);
item.setShowDot(action.state.deep_unpack() == item._remoteTarget);
specificSignalId = item.connect('activate', Lang.bind(this, function(item) {
this.actionGroup.activate_action(action_id, GLib.Variant.new_string(item._remoteTarget));
}));
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'];
}
} else {
target = model.get_item_attribute_value(index, Gio.MENU_ATTRIBUTE_TARGET, null);
item = new PopupMenuItem(label);
action.items.push(item);
specificSignalId = item.connect('activate', Lang.bind(this, function() {
this.actionGroup.activate_action(action_id, target);
}));
}
item.actor.reactive = item.actor.can_focus = action.enabled;
destroyId = item.connect('destroy', Lang.bind(this, function() {
item.disconnect(destroyId);
item.disconnect(specificSignalId);
let pos = action.items.indexOf(item);
if (pos != -1)
action.items.splice(pos, 1);
}));
return [item, false, ''];
},
_modelChanged: function(model, position, removed, added, target) {
let j, k;
let j0, k0;
let currentItems = target._getMenuItems();
k0 = 0;
// skip ignored items at the beginning
while (k0 < currentItems.length && currentItems[k0]._ignored)
k0++;
// find the right menu item matching the model item
for (j0 = 0; k0 < currentItems.length && j0 < position; j0++, k0++) {
if (currentItems[k0]._ignored)
k0++;
}
if (removed == -1) {
// special flag to indicate we should destroy everything
for (k = k0; k < currentItems.length; k++)
currentItems[k].destroy();
} else {
for (j = j0, k = k0; k < currentItems.length && j < j0 + removed; j++, k++) {
currentItems[k].destroy();
if (currentItems[k]._ignored)
j--;
}
}
for (j = j0, k = k0; j < j0 + added; j++, k++) {
let [item, addSeparator, changeSignal] = this._createMenuItem(model, j);
if (item) {
// separators must be added in the parent to make autohiding work
if (addSeparator) {
let separator = new PopupSeparatorMenuItem();
item.separators.push(separator);
separator._ignored = true;
target.addMenuItem(separator, k+1);
k++;
}
target.addMenuItem(item, k);
if (addSeparator) {
let separator = new PopupSeparatorMenuItem();
item.separators.push(separator);
separator._ignored = true;
target.addMenuItem(separator, k+1);
k++;
}
} else if (changeSignal) {
let signalId = this.actionGroup.connect(changeSignal, Lang.bind(this, function(actionGroup, actionName) {
actionGroup.disconnect(signalId);
if (this._actions[actionName]) return;
// force a full update
this._modelChanged(model, 0, -1, model.get_n_items(), target);
}));
}
}
if (!model._changedId) {
model._changedId = model.connect('items-changed', Lang.bind(this, this._modelChanged, target));
model._destroyId = target.connect('destroy', function() {
if (model._changedId)
model.disconnect(model._changedId);
if (model._destroyId)
target.disconnect(model._destroyId);
model._changedId = 0;
model._destroyId = 0;
});
}
if (target instanceof PopupMenuSection) {
if (target._titleMenuItem)
target.actor.visible = target.numMenuItems != 1;
else
target.actor.visible = target.numMenuItems != 0;
} else {
let sourceItem = target.sourceActor._delegate;
if (sourceItem instanceof PopupSubMenuMenuItem)
sourceItem.actor.visible = target.numMenuItems != 0;
}
},
_actionStateChanged: function(actionGroup, action_id) {
let action = this._actions[action_id];
if (!action)
return;
action.state = actionGroup.get_action_state(action_id);
if (action.items.length) {
switch (String.fromCharCode(action.state.classify())) {
case 'b':
for (let i = 0; i < action.items.length; i++)
action.items[i].setToggleState(action.state.get_boolean());
break;
case 'd':
for (let i = 0; i < action.items.length; i++)
action.items[i].setValue(action.state.get_double());
break;
case 's':
for (let i = 0; i < action.items.length; i++)
action.items[i].setShowDot(action.items[i]._remoteTarget == action.state.deep_unpack());
}
}
},
_actionEnabledChanged: function(actionGroup, action_id) {
let action = this._actions[action_id];
if (!action)
return;
action.enabled = actionGroup.get_action_enabled(action_id);
if (action.items.length) {
for (let i = 0; i < action.items.length; i++) {
let item = action.items[i];
item.actor.reactive = item.actor.can_focus = action.enabled;
}
}
}
});
/* Basic implementation of a menu manager.
* Call addMenu to add menus
*/
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 = [];
},
@ -2123,6 +1695,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 +1713,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) {

199
js/ui/remoteMenu.js Normal file
View File

@ -0,0 +1,199 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
const Atk = imports.gi.Atk;
const GLib = imports.gi.GLib;
const GObject = imports.gi.GObject;
const Gio = imports.gi.Gio;
const Lang = imports.lang;
const Shell = imports.gi.Shell;
const ShellMenu = imports.gi.ShellMenu;
const St = imports.gi.St;
const PopupMenu = imports.ui.popupMenu;
function stripMnemonics(label) {
if (!label)
return '';
// remove all underscores that are not followed by another underscore
return label.replace(/_([^_])/, '$1');
}
function _insertItem(menu, trackerItem, position) {
let mapper;
if (trackerItem.get_is_separator())
mapper = new RemoteMenuSeparatorItemMapper(trackerItem);
else if (trackerItem.get_has_submenu())
mapper = new RemoteMenuSubmenuItemMapper(trackerItem);
else
mapper = new RemoteMenuItemMapper(trackerItem);
let item = mapper.menuItem;
menu.addMenuItem(item, position);
}
function _removeItem(menu, position) {
let items = menu._getMenuItems();
items[position].destroy();
}
const RemoteMenuSeparatorItemMapper = new Lang.Class({
Name: 'RemoteMenuSeparatorItemMapper',
_init: function(trackerItem) {
this._trackerItem = trackerItem;
this.menuItem = new PopupMenu.PopupSeparatorMenuItem();
this._trackerItem.connect('notify::label', Lang.bind(this, this._updateLabel));
this._updateLabel();
this.menuItem.connect('destroy', function() {
trackerItem.run_dispose();
});
},
_updateLabel: function() {
this.menuItem.label.text = stripMnemonics(this._trackerItem.label);
},
});
const RequestSubMenu = new Lang.Class({
Name: 'RequestSubMenu',
Extends: PopupMenu.PopupSubMenuMenuItem,
_init: function() {
this.parent('');
this._requestOpen = false;
},
_setOpenState: function(open) {
this.emit('request-open', open);
this._requestOpen = open;
},
_getOpenState: function() {
return this._requestOpen;
},
});
const RemoteMenuSubmenuItemMapper = new Lang.Class({
Name: 'RemoteMenuSubmenuItemMapper',
_init: function(trackerItem) {
this._trackerItem = trackerItem;
this.menuItem = new RequestSubMenu();
this._trackerItem.connect('notify::label', Lang.bind(this, this._updateLabel));
this._updateLabel();
this._tracker = Shell.MenuTracker.new_for_item_submenu(this._trackerItem,
_insertItem.bind(null, this.menuItem.menu),
_removeItem.bind(null, this.menuItem.menu));
this.menuItem.connect('request-open', Lang.bind(this, function(menu, open) {
this._trackerItem.request_submenu_shown(open);
}));
this._trackerItem.connect('notify::submenu-shown', Lang.bind(this, function() {
this.menuItem.setSubmenuShown(this._trackerItem.get_submenu_shown());
}));
this.menuItem.connect('destroy', function() {
trackerItem.run_dispose();
});
},
destroy: function() {
this._tracker.destroy();
this.parent();
},
_updateLabel: function() {
this.menuItem.label.text = stripMnemonics(this._trackerItem.label);
},
});
const RemoteMenuItemMapper = new Lang.Class({
Name: 'RemoteMenuItemMapper',
_init: function(trackerItem) {
this._trackerItem = trackerItem;
this.menuItem = new PopupMenu.PopupBaseMenuItem();
this._label = new St.Label();
this.menuItem.addActor(this._label);
this.menuItem.actor.label_actor = this._label;
this.menuItem.connect('activate', Lang.bind(this, function() {
this._trackerItem.activated();
}));
this._trackerItem.bind_property('visible', this.menuItem.actor, 'visible', GObject.BindingFlags.SYNC_CREATE);
this._trackerItem.connect('notify::label', Lang.bind(this, this._updateLabel));
this._trackerItem.connect('notify::sensitive', Lang.bind(this, this._updateSensitivity));
this._trackerItem.connect('notify::role', Lang.bind(this, this._updateRole));
this._trackerItem.connect('notify::toggled', Lang.bind(this, this._updateDecoration));
this._updateLabel();
this._updateSensitivity();
this._updateRole();
this.menuItem.connect('destroy', function() {
trackerItem.run_dispose();
});
},
_updateLabel: function() {
this._label.text = stripMnemonics(this._trackerItem.label);
},
_updateSensitivity: function() {
this.menuItem.setSensitive(this._trackerItem.sensitive);
},
_updateDecoration: function() {
let ornamentForRole = {};
ornamentForRole[ShellMenu.MenuTrackerItemRole.RADIO] = PopupMenu.Ornament.DOT;
ornamentForRole[ShellMenu.MenuTrackerItemRole.CHECK] = PopupMenu.Ornament.CHECK;
let ornament = PopupMenu.Ornament.NONE;
if (this._trackerItem.toggled)
ornament = ornamentForRole[this._trackerItem.role];
this.menuItem.setOrnament(ornament);
},
_updateRole: function() {
let a11yRoles = {};
a11yRoles[ShellMenu.MenuTrackerItemRole.NORMAL] = Atk.Role.MENU_ITEM;
a11yRoles[ShellMenu.MenuTrackerItemRole.RADIO] = Atk.Role.RADIO_MENU_ITEM;
a11yRoles[ShellMenu.MenuTrackerItemRole.CHECK] = Atk.Role.CHECK_MENU_ITEM;
let a11yRole = a11yRoles[this._trackerItem.role];
this.menuItem.actor.accessible_role = a11yRole;
this._updateDecoration();
},
});
const RemoteMenu = new Lang.Class({
Name: 'RemoteMenu',
Extends: PopupMenu.PopupMenu,
_init: function(sourceActor, model, actionGroup) {
this.parent(sourceActor, 0.0, St.Side.TOP);
this._model = model;
this._actionGroup = actionGroup;
this._tracker = Shell.MenuTracker.new(this._actionGroup,
this._model,
null, /* action namespace */
_insertItem.bind(null, this),
_removeItem.bind(null, this));
},
destroy: function() {
this._tracker.destroy();
this.parent();
},
});

View File

@ -187,7 +187,9 @@ const RemoteSearchProvider = new Lang.Class({
createIcon: function(size, meta) {
let gicon;
if (meta['gicon']) {
if (meta['icon']) {
gicon = Gio.icon_deserialize(meta['icon']);
} else if (meta['gicon']) {
gicon = Gio.icon_new_for_string(meta['gicon']);
} else if (meta['icon-data']) {
let [width, height, rowStride, hasAlpha,
@ -203,7 +205,7 @@ const RemoteSearchProvider = new Lang.Class({
_getResultsFinished: function(results, error) {
if (error)
return;
this.searchSystem.pushResults(this, results[0]);
this.searchSystem.setResults(this, results[0]);
},
getInitialResultSet: function(terms) {
@ -215,7 +217,7 @@ const RemoteSearchProvider = new Lang.Class({
this._cancellable);
} catch(e) {
log('Error calling GetInitialResultSet for provider %s: %s'.format(this.id, e.toString()));
this.searchSystem.pushResults(this, []);
this.searchSystem.setResults(this, []);
}
},
@ -228,7 +230,7 @@ const RemoteSearchProvider = new Lang.Class({
this._cancellable);
} catch(e) {
log('Error calling GetSubsearchResultSet for provider %s: %s'.format(this.id, e.toString()));
this.searchSystem.pushResults(this, []);
this.searchSystem.setResults(this, []);
}
},
@ -240,8 +242,12 @@ const RemoteSearchProvider = new Lang.Class({
let metas = results[0];
let resultMetas = [];
for (let i = 0; i < metas.length; i++) {
for (let prop in metas[i])
metas[i][prop] = metas[i][prop].deep_unpack();
for (let prop in metas[i]) {
// we can use the serialized icon variant directly
if (prop != 'icon')
metas[i][prop] = metas[i][prop].deep_unpack();
}
resultMetas.push({ id: metas[i]['id'],
name: metas[i]['name'],
description: metas[i]['description'],

View File

@ -35,7 +35,8 @@ const RunDialog = new Lang.Class({
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 });

View File

@ -30,6 +30,7 @@ const SCREENSAVER_SCHEMA = 'org.gnome.desktop.screensaver';
const LOCK_ENABLED_KEY = 'lock-enabled';
const LOCK_DELAY_KEY = 'lock-delay';
const LOCKED_STATE_STR = 'screenShield.locked';
// fraction of screen height the arrow must reach before completing
// the slide up automatically
const ARROW_DRAG_THRESHOLD = 0.1;
@ -214,6 +215,7 @@ const NotificationsBox = new Lang.Class({
if (musicNotification != null &&
this._musicBin.child == null) {
musicNotification.acknowledged = true;
if (musicNotification.actor.get_parent() != null)
musicNotification.actor.get_parent().remove_actor(musicNotification.actor);
this._musicBin.child = musicNotification.actor;
@ -246,6 +248,7 @@ const NotificationsBox = new Lang.Class({
sourceCountChangedId: 0,
sourceTitleChangedId: 0,
sourceUpdatedId: 0,
sourceNotifyId: 0,
musicNotification: null,
sourceBox: null,
titleLabel: null,
@ -256,6 +259,12 @@ const NotificationsBox = new Lang.Class({
this._showSource(source, obj, obj.sourceBox);
this._notificationBox.add(obj.sourceBox, { x_fill: false, x_align: St.Align.START });
if (obj.musicNotification) {
obj.sourceNotifyId = source.connect('notify', Lang.bind(this, function(source, notification) {
notification.acknowledged = true;
}));
}
obj.sourceCountChangedId = source.connect('count-updated', Lang.bind(this, function(source) {
this._countChanged(source, obj);
}));
@ -336,6 +345,8 @@ const NotificationsBox = new Lang.Class({
if (obj.musicNotification) {
this._musicBin.child = null;
obj.musicNotification = null;
source.disconnect(obj.sourceNotifyId);
}
source.disconnect(obj.sourceDestroyId);
@ -562,6 +573,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);
@ -1114,11 +1126,22 @@ 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')
Main.sessionMode.popMode('unlock-dialog');
if (this._dialog && !this._isGreeter)
this._dialog.popModal();
if (this._isModal) {
Main.popModal(this.actor);
this._isModal = false;
}
Tweener.addTween(this._lockDialogGroup, {
scale_x: 0,
scale_y: 0,
@ -1130,21 +1153,12 @@ const ScreenShield = new Lang.Class({
},
_completeDeactivate: function() {
if (this._hasLockScreen)
this._clearLockScreen();
if (this._dialog && !this._isGreeter) {
this._dialog.destroy();
this._dialog = null;
}
this._lightbox.hide();
if (this._isModal) {
Main.popModal(this.actor);
this._isModal = false;
}
this.actor.hide();
if (this._becameActiveId != 0) {
@ -1162,6 +1176,7 @@ const ScreenShield = new Lang.Class({
this._isLocked = false;
this.emit('active-changed');
this.emit('locked-changed');
global.set_runtime_state(LOCKED_STATE_STR, null);
},
activate: function(animate) {
@ -1178,6 +1193,7 @@ const ScreenShield = new Lang.Class({
}
this._resetLockScreen(animate, animate);
global.set_runtime_state(LOCKED_STATE_STR, GLib.Variant.new('b', true));
// We used to set isActive and emit active-changed here,
// but now we do that from lockScreenShown, which means
@ -1199,10 +1215,26 @@ 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);
this.emit('locked-changed');
},
// If the previous shell crashed, and gnome-session restarted us, then re-lock
lockIfWasLocked: function() {
let wasLocked = global.get_runtime_state('b', LOCKED_STATE_STR);
if (wasLocked === null)
return;
Meta.later_add(Meta.LaterType.BEFORE_REDRAW, Lang.bind(this, function() {
this.lock(false);
}));
}
});
Signals.addSignalMethods(ScreenShield.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

@ -51,7 +51,7 @@ const SearchSystem = new Lang.Class({
this._previousResults = [];
},
pushResults: function(provider, results) {
setResults: function(provider, results) {
let i = this._providers.indexOf(provider);
if (i == -1)
return;

View File

@ -180,13 +180,82 @@ const GridSearchResult = new Lang.Class({
}
});
const ListSearchResults = new Lang.Class({
Name: 'ListSearchResults',
const SearchResultsBase = new Lang.Class({
Name: 'SearchResultsBase',
_init: function(provider) {
this.provider = provider;
this.actor = new St.BoxLayout({ style_class: 'search-section-content' });
this._terms = [];
this.actor = new St.BoxLayout({ style_class: 'search-section',
vertical: true });
this._resultDisplayBin = new St.Bin({ x_fill: true,
y_fill: true });
this.actor.add(this._resultDisplayBin, { expand: true });
let separator = new Separator.HorizontalSeparator({ style_class: 'search-section-separator' });
this.actor.add(separator.actor);
},
destroy: function() {
this.actor.destroy();
this._terms = [];
},
_clearResultDisplay: function() {
},
clear: function() {
this._clearResultDisplay();
this.actor.hide();
},
_keyFocusIn: function(icon) {
this.emit('key-focus-in', icon);
},
_setMoreIconVisible: function(visible) {
},
updateSearch: function(providerResults, terms, callback) {
this._terms = terms;
if (providerResults.length == 0) {
this._clearResultDisplay();
this.actor.hide();
callback();
} else {
let maxResults = this._getMaxDisplayedResults();
let results = providerResults.slice(0, maxResults);
let hasMoreResults = results.length < providerResults.length;
this.provider.getResultMetas(results, Lang.bind(this, function(metas) {
this.clear();
// To avoid CSS transitions causing flickering when
// the first search result stays the same, we hide the
// content while filling in the results.
this.actor.hide();
this._clearResultDisplay();
this._renderResults(metas);
this._setMoreIconVisible(hasMoreResults && this.provider.canLaunchSearch);
this.actor.show();
callback();
}));
}
}
});
const ListSearchResults = new Lang.Class({
Name: 'ListSearchResults',
Extends: SearchResultsBase,
_init: function(provider) {
this.parent(provider);
this._container = new St.BoxLayout({ style_class: 'search-section-content' });
this.providerIcon = new ProviderIcon(provider);
this.providerIcon.connect('clicked', Lang.bind(this,
function() {
@ -194,48 +263,27 @@ const ListSearchResults = new Lang.Class({
Main.overview.toggle();
}));
this.actor.add(this.providerIcon, { x_fill: false,
y_fill: false,
x_align: St.Align.START,
y_align: St.Align.START });
this._container.add(this.providerIcon, { x_fill: false,
y_fill: false,
x_align: St.Align.START,
y_align: St.Align.START });
this._content = new St.BoxLayout({ style_class: 'list-search-results',
vertical: true });
this.actor.add(this._content, { expand: true });
this._container.add(this._content, { expand: true });
this._notDisplayedResult = [];
this._terms = [];
this._pendingClear = false;
this._resultDisplayBin.set_child(this._container);
},
getResultsForDisplay: function() {
let alreadyVisible = this._pendingClear ? 0 : this.getVisibleResultCount();
let canDisplay = MAX_LIST_SEARCH_RESULTS_ROWS - alreadyVisible;
let newResults = this._notDisplayedResult.splice(0, canDisplay);
return newResults;
_setMoreIconVisible: function(visible) {
this.providerIcon.moreIcon.visible = true;
},
getVisibleResultCount: function() {
return this._content.get_n_children();
_getMaxDisplayedResults: function() {
return MAX_LIST_SEARCH_RESULTS_ROWS;
},
hasMoreResults: function() {
return this._notDisplayedResult.length > 0;
},
setResults: function(results, terms) {
// copy the lists
this._notDisplayedResult = results.slice(0);
this._terms = terms.slice(0);
this._pendingClear = true;
},
_keyFocusIn: function(icon) {
this.emit('key-focus-in', icon);
},
renderResults: function(metas) {
_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));
@ -243,13 +291,12 @@ const ListSearchResults = new Lang.Class({
}
},
clear: function () {
_clearResultDisplay: function () {
this._content.destroy_all_children();
this._pendingClear = false;
},
getFirstResult: function() {
if (this.getVisibleResultCount() > 0)
if (this._content.get_n_children() > 0)
return this._content.get_child_at_index(0)._delegate;
else
return null;
@ -259,50 +306,24 @@ Signals.addSignalMethods(ListSearchResults.prototype);
const GridSearchResults = new Lang.Class({
Name: 'GridSearchResults',
Extends: SearchResultsBase,
_init: function(provider) {
this.provider = provider;
this.parent(provider);
this._grid = new IconGrid.IconGrid({ rowLimit: MAX_GRID_SEARCH_RESULTS_ROWS,
xAlign: St.Align.START });
this.actor = new St.Bin({ x_align: St.Align.MIDDLE });
this._bin = new St.Bin({ x_align: St.Align.MIDDLE });
this._bin.set_child(this._grid.actor);
this.actor.set_child(this._grid.actor);
this._notDisplayedResult = [];
this._terms = [];
this._pendingClear = false;
this._resultDisplayBin.set_child(this._bin);
},
getResultsForDisplay: function() {
let alreadyVisible = this._pendingClear ? 0 : this._grid.visibleItemsCount();
let canDisplay = this._grid.childrenInRow(this.actor.width) * this._grid.getRowLimit()
- alreadyVisible;
let newResults = this._notDisplayedResult.splice(0, canDisplay);
return newResults;
_getMaxDisplayedResults: function() {
return this._grid.childrenInRow(this._bin.width) * this._grid.getRowLimit();
},
getVisibleResultCount: function() {
return this._grid.visibleItemsCount();
},
hasMoreResults: function() {
return this._notDisplayedResult.length > 0;
},
setResults: function(results, terms) {
// copy the lists
this._notDisplayedResult = results.slice(0);
this._terms = terms.slice(0);
this._pendingClear = true;
},
_keyFocusIn: function(icon) {
this.emit('key-focus-in', icon);
},
renderResults: function(metas) {
_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));
@ -310,13 +331,12 @@ const GridSearchResults = new Lang.Class({
}
},
clear: function () {
_clearResultDisplay: function () {
this._grid.removeAll();
this._pendingClear = false;
},
getFirstResult: function() {
if (this.getVisibleResultCount() > 0)
if (this._grid.visibleItemsCount() > 0)
return this._grid.getItemAtIndex(0)._delegate;
else
return null;
@ -366,9 +386,9 @@ const SearchResults = new Lang.Class({
this._content.add(this._statusBin, { expand: true });
this._statusBin.add_actor(this._statusText);
this._providers = this._searchSystem.getProviders();
this._providerMeta = [];
this._providerDisplays = {};
for (let i = 0; i < this._providers.length; i++) {
this.createProviderMeta(this._providers[i]);
this.createProviderDisplay(this._providers[i]);
}
this._highlightDefault = false;
@ -386,61 +406,33 @@ const SearchResults = new Lang.Class({
Util.ensureActorVisibleInScrollView(this._scrollView, icon);
},
createProviderMeta: function(provider) {
let providerBox = new St.BoxLayout({ style_class: 'search-section',
vertical: true });
let providerIcon = null;
let resultDisplay = null;
createProviderDisplay: function(provider) {
let providerDisplay = null;
if (provider.appInfo) {
resultDisplay = new ListSearchResults(provider);
providerIcon = resultDisplay.providerIcon;
providerDisplay = new ListSearchResults(provider);
} else {
resultDisplay = new GridSearchResults(provider);
providerDisplay = 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 });
providerBox.add(resultDisplayBin, { expand: true });
let separator = new Separator.HorizontalSeparator({ style_class: 'search-section-separator' });
providerBox.add(separator.actor);
this._providerMeta.push({ provider: provider,
actor: providerBox,
icon: providerIcon,
resultDisplay: resultDisplay });
this._content.add(providerBox);
providerDisplay.connect('key-focus-in', Lang.bind(this, this._keyFocusIn));
this._providerDisplays[provider.id] = providerDisplay;
this._content.add(providerDisplay.actor);
},
destroyProviderMeta: function(provider) {
for (let i=0; i < this._providerMeta.length; i++) {
let meta = this._providerMeta[i];
if (meta.provider == provider) {
meta.actor.destroy();
this._providerMeta.splice(i, 1);
break;
}
}
destroyProviderDisplay: function(provider) {
this._providerDisplays[provider.id].destroy();
delete this._providerDisplays[provider.id];
},
_clearDisplay: function() {
for (let i = 0; i < this._providerMeta.length; i++) {
let meta = this._providerMeta[i];
meta.resultDisplay.clear();
meta.actor.hide();
for (let i = 0; i < this._providers.length; i++) {
let provider = this._providers[i];
let providerDisplay = this._providerDisplays[provider.id];
providerDisplay.clear();
}
},
_clearDisplayForProvider: function(provider) {
let meta = this._metaForProvider(provider);
meta.resultDisplay.clear();
meta.actor.hide();
},
reset: function() {
this._searchSystem.reset();
this._statusBin.hide();
@ -454,20 +446,17 @@ const SearchResults = new Lang.Class({
this._statusBin.show();
},
_metaForProvider: function(provider) {
return this._providerMeta[this._providers.indexOf(provider)];
},
_maybeSetInitialSelection: function() {
let newDefaultResult = null;
for (let i = 0; i < this._providerMeta.length; i++) {
let meta = this._providerMeta[i];
for (let i = 0; i < this._providers.length; i++) {
let provider = this._providers[i];
let display = this._providerDisplays[provider.id];
if (!meta.actor.visible)
if (!display.actor.visible)
continue;
let firstResult = meta.resultDisplay.getFirstResult();
let firstResult = display.getFirstResult();
if (firstResult) {
newDefaultResult = firstResult;
break; // select this one!
@ -487,11 +476,14 @@ const SearchResults = new Lang.Class({
_updateStatusText: function () {
let haveResults = false;
for (let i = 0; i < this._providerMeta.length; ++i)
if (this._providerMeta[i].resultDisplay.getFirstResult()) {
for (let i = 0; i < this._providers.length; i++) {
let provider = this._providers[i];
let display = this._providerDisplays[provider.id];
if (display.getFirstResult()) {
haveResults = true;
break;
}
}
if (!haveResults) {
this._statusText.set_text(_("No results."));
@ -504,42 +496,12 @@ const SearchResults = new Lang.Class({
_updateResults: function(searchSystem, results) {
let terms = searchSystem.getTerms();
let [provider, providerResults] = results;
let meta = this._metaForProvider(provider);
let display = this._providerDisplays[provider.id];
if (providerResults.length == 0) {
this._clearDisplayForProvider(provider);
meta.resultDisplay.setResults([], []);
display.updateSearch(providerResults, terms, Lang.bind(this, function() {
this._maybeSetInitialSelection();
this._updateStatusText();
} else {
meta.resultDisplay.setResults(providerResults, terms);
let results = meta.resultDisplay.getResultsForDisplay();
if (meta.icon)
meta.icon.moreIcon.visible =
meta.resultDisplay.hasMoreResults() &&
provider.canLaunchSearch;
provider.getResultMetas(results, Lang.bind(this, function(metas) {
this._clearDisplayForProvider(provider);
meta.actor.show();
// Hiding drops the key focus if we have it
let focus = global.stage.get_key_focus();
// To avoid CSS transitions causing flickering when
// the first search result stays the same, we hide the
// content while filling in the results.
this._content.hide();
meta.resultDisplay.renderResults(metas);
this._maybeSetInitialSelection();
this._updateStatusText();
this._content.show();
if (this._content.contains(focus))
global.stage.set_key_focus(focus);
}));
}
}));
},
activateDefault: function() {

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']
@ -78,17 +79,6 @@ const _modes = {
panelStyle: 'unlock-screen'
},
'initial-setup': {
hasWindows: true,
isPrimary: true,
components: ['keyring'],
panel: {
left: [],
center: ['dateMenu'],
right: ['a11yGreeter', 'keyboard', 'volume', 'battery']
}
},
'user': {
hasOverview: true,
showCalendarEvents: true,
@ -195,6 +185,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

@ -12,6 +12,7 @@ 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">
@ -20,6 +21,7 @@ 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>
@ -70,6 +72,7 @@ const GnomeShell = new Lang.Class({
this._dbusImpl.export(Gio.DBus.session, '/org/gnome/Shell');
this._extensionsService = new GnomeShellExtensions();
this._screencastService = new Screencast.ScreencastService();
this._screenshotService = new Screenshot.ScreenshotService();
this._grabbedAccelerators = new Hash.Map();
@ -97,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;
@ -114,6 +117,10 @@ 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();

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,11 +80,6 @@ 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(!this._entry.clutter_text.password_char &&
@ -160,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);

221
js/ui/slider.js Normal file
View File

@ -0,0 +1,221 @@
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
const Cairo = imports.cairo;
const Clutter = imports.gi.Clutter;
const Lang = imports.lang;
const St = imports.gi.St;
const Signals = imports.signals;
const SLIDER_SCROLL_STEP = 0.05; /* Slider scrolling step in % */
const Slider = new Lang.Class({
Name: "Slider",
_init: function(value) {
if (isNaN(value))
// Avoid spreading NaNs around
throw TypeError('The slider value must be a number');
this._value = Math.max(Math.min(value, 1), 0);
this.actor = new St.DrawingArea({ style_class: 'slider',
can_focus: true,
reactive: true });
this.actor.connect('repaint', Lang.bind(this, this._sliderRepaint));
this.actor.connect('button-press-event', Lang.bind(this, this._startDragging));
this.actor.connect('scroll-event', Lang.bind(this, this._onScrollEvent));
this.actor.connect('key-press-event', Lang.bind(this, this._onKeyPressEvent));
this._releaseId = this._motionId = 0;
this._dragging = false;
},
setValue: function(value) {
if (isNaN(value))
throw TypeError('The slider value must be a number');
this._value = Math.max(Math.min(value, 1), 0);
this.actor.queue_repaint();
},
_sliderRepaint: function(area) {
let cr = area.get_context();
let themeNode = area.get_theme_node();
let [width, height] = area.get_surface_size();
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');
let sliderBorderWidth = themeNode.get_length('-slider-border-width');
let sliderBorderColor = themeNode.get_color('-slider-border-color');
let sliderColor = themeNode.get_color('-slider-background-color');
let sliderActiveBorderColor = themeNode.get_color('-slider-active-border-color');
let sliderActiveColor = themeNode.get_color('-slider-active-background-color');
cr.setSourceRGBA (
sliderActiveColor.red / 255,
sliderActiveColor.green / 255,
sliderActiveColor.blue / 255,
sliderActiveColor.alpha / 255);
cr.rectangle(handleRadius, (height - sliderHeight) / 2, sliderWidth * this._value, sliderHeight);
cr.fillPreserve();
cr.setSourceRGBA (
sliderActiveBorderColor.red / 255,
sliderActiveBorderColor.green / 255,
sliderActiveBorderColor.blue / 255,
sliderActiveBorderColor.alpha / 255);
cr.setLineWidth(sliderBorderWidth);
cr.stroke();
cr.setSourceRGBA (
sliderColor.red / 255,
sliderColor.green / 255,
sliderColor.blue / 255,
sliderColor.alpha / 255);
cr.rectangle(handleRadius + sliderWidth * this._value, (height - sliderHeight) / 2, sliderWidth * (1 - this._value), sliderHeight);
cr.fillPreserve();
cr.setSourceRGBA (
sliderBorderColor.red / 255,
sliderBorderColor.green / 255,
sliderBorderColor.blue / 255,
sliderBorderColor.alpha / 255);
cr.setLineWidth(sliderBorderWidth);
cr.stroke();
let handleY = height / 2;
let handleX = handleRadius + (width - 2 * handleRadius) * this._value;
let color = themeNode.get_foreground_color();
cr.setSourceRGBA (
color.red / 255,
color.green / 255,
color.blue / 255,
color.alpha / 255);
cr.arc(handleX, handleY, handleRadius, 0, 2 * Math.PI);
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();
},
_startDragging: function(actor, event) {
if (this._dragging) // don't allow two drags at the same time
return false;
this._dragging = true;
// FIXME: we should only grab the specific device that originated
// the event, but for some weird reason events are still delivered
// outside the slider if using clutter_grab_pointer_for_device
Clutter.grab_pointer(this.actor);
this._releaseId = this.actor.connect('button-release-event', Lang.bind(this, this._endDragging));
this._motionId = this.actor.connect('motion-event', Lang.bind(this, this._motionEvent));
let absX, absY;
[absX, absY] = event.get_coords();
this._moveHandle(absX, absY);
return true;
},
_endDragging: function() {
if (this._dragging) {
this.actor.disconnect(this._releaseId);
this.actor.disconnect(this._motionId);
Clutter.ungrab_pointer();
this._dragging = false;
this.emit('drag-end');
}
return true;
},
scroll: function(event) {
let direction = event.get_scroll_direction();
let delta;
if (event.is_pointer_emulated())
return;
if (direction == Clutter.ScrollDirection.DOWN) {
delta = -SLIDER_SCROLL_STEP;
} else if (direction == Clutter.ScrollDirection.UP) {
delta = +SLIDER_SCROLL_STEP;
} else if (direction == Clutter.ScrollDirection.SMOOTH) {
let [dx, dy] = event.get_scroll_delta();
// Even though the slider is horizontal, use dy to match
// the UP/DOWN above.
delta = -dy / 10;
}
this._value = Math.min(Math.max(0, this._value + delta), 1);
this.actor.queue_repaint();
this.emit('value-changed', this._value);
},
_onScrollEvent: function(actor, event) {
this.scroll(event);
},
_motionEvent: function(actor, event) {
let absX, absY;
[absX, absY] = event.get_coords();
this._moveHandle(absX, absY);
return true;
},
_onKeyPressEvent: function (actor, event) {
let key = event.get_key_symbol();
if (key == Clutter.KEY_Right || key == Clutter.KEY_Left) {
let delta = key == Clutter.KEY_Right ? 0.1 : -0.1;
this._value = Math.max(0, Math.min(this._value + delta, 1));
this._slider.queue_repaint();
this.emit('value-changed', this._value);
this.emit('drag-end');
return true;
}
return false;
},
_moveHandle: function(absX, absY) {
let relX, relY, sliderX, sliderY;
[sliderX, sliderY] = this.actor.get_transformed_position();
relX = absX - sliderX;
relY = absY - sliderY;
let width = this.actor.width;
let handleRadius = this.actor.get_theme_node().get_length('-slider-handle-radius');
let newvalue;
if (relX < handleRadius)
newvalue = 0;
else if (relX > width - handleRadius)
newvalue = 1;
else
newvalue = (relX - handleRadius) / (width - 2 * handleRadius);
this._value = newvalue;
this.actor.queue_repaint();
this.emit('value-changed', this._value);
},
get value() {
return this._value;
}
});
Signals.addSignalMethods(Slider.prototype);

View File

@ -86,6 +86,7 @@ const Indicator = new Lang.Class({
this._applet.connect('pincode-request', Lang.bind(this, this._pinRequest));
this._applet.connect('confirm-request', Lang.bind(this, this._confirmRequest));
this._applet.connect('auth-request', Lang.bind(this, this._authRequest));
this._applet.connect('auth-service-request', Lang.bind(this, this._authServiceRequest));
this._applet.connect('cancel-request', Lang.bind(this, this._cancelRequest));
},
@ -292,9 +293,14 @@ const Indicator = new Lang.Class({
}
},
_authRequest: function(applet, device_path, name, long_name, uuid) {
_authRequest: function(applet, device_path, name, long_name) {
this._ensureSource();
this._source.notify(new AuthNotification(this._source, this._applet, device_path, name, long_name, uuid));
this._source.notify(new AuthNotification(this._source, this._applet, device_path, name, long_name));
},
_authServiceRequest: function(applet, device_path, name, long_name, uuid) {
this._ensureSource();
this._source.notify(new AuthServiceNotification(this._source, this._applet, device_path, name, long_name, uuid));
},
_confirmRequest: function(applet, device_path, name, long_name, pin) {
@ -316,6 +322,34 @@ const AuthNotification = new Lang.Class({
Name: 'AuthNotification',
Extends: MessageTray.Notification,
_init: function(source, applet, device_path, name, long_name) {
this.parent(source,
_("Bluetooth"),
_("Authorization request from %s").format(name),
{ customContent: true });
this.setResident(true);
this._applet = applet;
this._devicePath = device_path;
this.addBody(_("Device %s wants to pair with this computer").format(long_name));
this.addButton('allow', _("Allow"));
this.addButton('deny', _("Deny"));
this.connect('action-invoked', Lang.bind(this, function(self, action) {
if (action == 'allow')
this._applet.agent_reply_confirm(this._devicePath, true);
else
this._applet.agent_reply_confirm(this._devicePath, false);
this.destroy();
}));
}
});
const AuthServiceNotification = new Lang.Class({
Name: 'AuthServiceNotification',
Extends: MessageTray.Notification,
_init: function(source, applet, device_path, name, long_name, uuid) {
this.parent(source,
_("Bluetooth"),
@ -334,14 +368,14 @@ const AuthNotification = new Lang.Class({
this.connect('action-invoked', Lang.bind(this, function(self, action) {
switch (action) {
case 'always-grant':
this._applet.agent_reply_auth(this._devicePath, true, true);
this._applet.agent_reply_auth_service(this._devicePath, true, true);
break;
case 'grant':
this._applet.agent_reply_auth(this._devicePath, true, false);
this._applet.agent_reply_auth_service(this._devicePath, true, false);
break;
case 'reject':
default:
this._applet.agent_reply_auth(this._devicePath, false, false);
this._applet.agent_reply_auth_service(this._devicePath, false, false);
}
this.destroy();
}));
@ -363,7 +397,7 @@ const ConfirmNotification = new Lang.Class({
this._applet = applet;
this._devicePath = device_path;
this.addBody(_("Device %s wants to pair with this computer").format(long_name));
this.addBody(_("Please confirm whether the PIN '%06d' matches the one on the device.").format(pin));
this.addBody(_("Please confirm whether the Passkey '%06d' matches the one on the device.").format(pin));
/* Translators: this is the verb, not the noun */
this.addButton('matches', _("Matches"));

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)
@ -337,14 +356,14 @@ const InputSourceIndicator = new Lang.Class({
Main.wm.addKeybinding('switch-input-source',
new Gio.Settings({ schema: "org.gnome.desktop.wm.keybindings" }),
Meta.KeyBindingFlags.REVERSES,
Shell.KeyBindingMode.ALL & ~Shell.KeyBindingMode.MESSAGE_TRAY,
Shell.KeyBindingMode.ALL,
Lang.bind(this, this._switchInputSource));
this._keybindingActionBackward =
Main.wm.addKeybinding('switch-input-source-backward',
new Gio.Settings({ schema: "org.gnome.desktop.wm.keybindings" }),
Meta.KeyBindingFlags.REVERSES |
Meta.KeyBindingFlags.REVERSED,
Shell.KeyBindingMode.ALL & ~Shell.KeyBindingMode.MESSAGE_TRAY,
Shell.KeyBindingMode.ALL,
Lang.bind(this, this._switchInputSource));
this._settings = new Gio.Settings({ schema: DESKTOP_INPUT_SOURCES_SCHEMA });
this._settings.connect('changed::' + KEY_CURRENT_INPUT_SOURCE, Lang.bind(this, this._currentInputSourceChanged));
@ -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,10 +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;
@ -417,7 +478,7 @@ const InputSourceIndicator = new Lang.Class({
[oldSource, this._currentSource] = [this._currentSource, newSource];
if (oldSource) {
oldSource.menuItem.setShowDot(false);
oldSource.menuItem.setOrnament(PopupMenu.Ornament.NONE);
oldSource.indicatorLabel.hide();
}
@ -435,7 +496,7 @@ const InputSourceIndicator = new Lang.Class({
this.actor.show();
newSource.menuItem.setShowDot(true);
newSource.menuItem.setOrnament(PopupMenu.Ornament.DOT);
newSource.indicatorLabel.show();
this._buildPropSection(newSource.properties);
@ -459,6 +520,7 @@ const InputSourceIndicator = new Lang.Class({
this._inputSources = {};
this._ibusSources = {};
this._currentSource = null;
let inputSourcesByShortName = {};
@ -487,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 && 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))
@ -660,7 +720,8 @@ const InputSourceIndicator = new Lang.Class({
item.prop = prop;
radioGroup.push(item);
item.radioGroup = radioGroup;
item.setShowDot(prop.get_state() == IBus.PropState.CHECKED);
item.setOrnament(prop.get_state() == IBus.PropState.CHECKED ?
PopupMenu.Ornament.DOT : PopupMenu.Ornament.NONE);
item.connect('activate', Lang.bind(this, function() {
if (item.prop.get_state() == IBus.PropState.CHECKED)
return;
@ -668,12 +729,12 @@ const InputSourceIndicator = new Lang.Class({
let group = item.radioGroup;
for (let i = 0; i < group.length; ++i) {
if (group[i] == item) {
item.setShowDot(true);
item.setOrnament(PopupMenu.Ornament.DOT);
item.prop.set_state(IBus.PropState.CHECKED);
this._ibusManager.activateProperty(item.prop.get_key(),
IBus.PropState.CHECKED);
} else {
group[i].setShowDot(false);
group[i].setOrnament(PopupMenu.Ornament.NONE);
group[i].prop.set_state(IBus.PropState.UNCHECKED);
this._ibusManager.activateProperty(group[i].prop.get_key(),
IBus.PropState.UNCHECKED);

File diff suppressed because it is too large Load Diff

View File

@ -10,8 +10,6 @@ const Signals = imports.signals;
const PanelMenu = imports.ui.panelMenu;
const PopupMenu = imports.ui.popupMenu;
const VOLUME_ADJUSTMENT_STEP = 0.05; /* Volume adjustment step in % */
const VOLUME_NOTIFY_ID = 1;
// Each Gvc.MixerControl is a connection to PulseAudio,
@ -44,7 +42,6 @@ const StreamSlider = new Lang.Class({
this.item.addMenuItem(this._slider);
this._stream = null;
this._shouldShow = true;
},
get stream() {
@ -307,7 +304,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

@ -17,7 +17,6 @@ const ModalDialog = imports.ui.modalDialog;
const Panel = imports.ui.panel;
const ShellEntry = imports.ui.shellEntry;
const Tweener = imports.ui.tweener;
const UserMenu = imports.ui.userMenu;
const UserWidget = imports.ui.userWidget;
const Batch = imports.gdm.batch;
@ -91,9 +90,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"),
@ -104,12 +100,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 },
@ -163,28 +158,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;
@ -215,7 +188,7 @@ const UnlockDialog = new Lang.Class({
this._currentQuery = serviceName;
this._updateSensitivity(true);
this._setWorking(false);
this.setWorking(false);
},
_showLoginHint: function(verifier, message) {
@ -234,7 +207,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;
}
@ -245,7 +218,7 @@ const UnlockDialog = new Lang.Class({
this._currentQuery = null;
this._updateSensitivity(false);
this._setWorking(true);
this.setWorking(true);
this._userVerifier.answerQuery(query, this._promptEntry.text);
},
@ -285,7 +258,7 @@ const UnlockDialog = new Lang.Class({
this._promptEntry.menu.isPassword = true;
this._updateSensitivity(false);
this._setWorking(false);
this.setWorking(false);
},
_escape: function() {

View File

@ -20,8 +20,8 @@ const Main = imports.ui.main;
const ModalDialog = imports.ui.modalDialog;
const PanelMenu = imports.ui.panelMenu;
const PopupMenu = imports.ui.popupMenu;
const Params = imports.misc.params;
const Util = imports.misc.util;
const UserWidget = imports.ui.userWidget;
const LOCKDOWN_SCHEMA = 'org.gnome.desktop.lockdown';
const SCREENSAVER_SCHEMA = 'org.gnome.desktop.screensaver';
@ -32,8 +32,6 @@ const DISABLE_LOG_OUT_KEY = 'disable-log-out';
const ALWAYS_SHOW_LOG_OUT_KEY = 'always-show-log-out';
const SHOW_FULL_NAME_IN_TOP_BAR_KEY = 'show-full-name-in-top-bar';
const DIALOG_ICON_SIZE = 64;
const MAX_USERS_IN_SESSION_DIALOG = 5;
const IMStatus = {
@ -57,48 +55,6 @@ const SystemdLoginSessionIface = <interface name='org.freedesktop.login1.Session
const SystemdLoginSession = Gio.DBusProxy.makeProxyWrapper(SystemdLoginSessionIface);
// Adapted from gdm/gui/user-switch-applet/applet.c
//
// Copyright (C) 2004-2005 James M. Cape <jcape@ignore-your.tv>.
// Copyright (C) 2008,2009 Red Hat, Inc.
const UserAvatarWidget = new Lang.Class({
Name: 'UserAvatarWidget',
_init: function(user, params) {
this._user = user;
params = Params.parse(params, { reactive: false,
iconSize: DIALOG_ICON_SIZE,
styleClass: 'status-chooser-user-icon' });
this._iconSize = params.iconSize;
this.actor = new St.Bin({ style_class: params.styleClass,
track_hover: params.reactive,
reactive: params.reactive });
},
setSensitive: function(sensitive) {
this.actor.can_focus = sensitive;
this.actor.reactive = sensitive;
},
update: function() {
let iconFile = this._user.get_icon_file();
if (iconFile && !GLib.file_test(iconFile, GLib.FileTest.EXISTS))
iconFile = null;
if (iconFile) {
let file = Gio.File.new_for_path(iconFile);
this.actor.child = null;
this.actor.style = 'background-image: url("%s");'.format(iconFile);
} else {
this.actor.style = null;
this.actor.child = new St.Icon({ icon_name: 'avatar-default-symbolic',
icon_size: this._iconSize });
}
}
});
const IMStatusItem = new Lang.Class({
Name: 'IMStatusItem',
Extends: PopupMenu.PopupBaseMenuItem,
@ -170,7 +126,7 @@ const IMStatusChooserItem = new Lang.Class({
this._userManager = AccountsService.UserManager.get_default();
this._user = this._userManager.get_user(GLib.get_user_name());
this._avatar = new UserAvatarWidget(this._user, { reactive: true });
this._avatar = new UserWidget.Avatar(this._user, { reactive: true });
this._iconBin = new St.Button({ child: this._avatar.actor });
this.addActor(this._iconBin);
@ -610,7 +566,6 @@ const UserMenuButton = new Lang.Class({
let allowSettings = Main.sessionMode.allowSettings;
this._statusChooser.setSensitive(allowSettings);
this._systemSettings.visible = allowSettings;
this.setSensitive(!Main.sessionMode.isLocked);
this._updatePresenceIcon();
@ -786,10 +741,7 @@ const UserMenuButton = new Lang.Class({
item = new PopupMenu.PopupSeparatorMenuItem();
this.menu.addMenuItem(item);
item = new PopupMenu.PopupMenuItem(_("Settings"));
item.connect('activate', Lang.bind(this, this._onPreferencesActivate));
this.menu.addMenuItem(item);
this._systemSettings = item;
this.menu.addSettingsAction(_("Settings"), 'gnome-control-center.desktop');
item = new PopupMenu.PopupSeparatorMenuItem();
this.menu.addMenuItem(item);
@ -850,12 +802,6 @@ const UserMenuButton = new Lang.Class({
app.activate();
},
_onPreferencesActivate: function() {
Main.overview.hide();
let app = Shell.AppSystem.get_default().lookup_app('gnome-control-center.desktop');
app.activate();
},
_onLockScreenActivate: function() {
this.menu.close(BoxPointer.PopupAnimation.NONE);
Main.overview.hide();
@ -908,7 +854,7 @@ const UserMenuButton = new Lang.Class({
let session = sessions[i];
let userEntry = new St.BoxLayout({ style_class: 'login-dialog-user-list-item',
vertical: false });
let avatar = new UserAvatarWidget(session.user);
let avatar = new UserWidget.Avatar(session.user);
avatar.update();
userEntry.add(avatar.actor);

View File

@ -3,10 +3,56 @@
//
// A widget showing the user avatar and name
const AccountsService = imports.gi.AccountsService;
const GLib = imports.gi.GLib;
const Gio = imports.gi.Gio;
const Lang = imports.lang;
const St = imports.gi.St;
const UserMenu = imports.ui.userMenu;
const Params = imports.misc.params;
const AVATAR_ICON_SIZE = 64;
// Adapted from gdm/gui/user-switch-applet/applet.c
//
// Copyright (C) 2004-2005 James M. Cape <jcape@ignore-your.tv>.
// Copyright (C) 2008,2009 Red Hat, Inc.
const Avatar = new Lang.Class({
Name: 'Avatar',
_init: function(user, params) {
this._user = user;
params = Params.parse(params, { reactive: false,
iconSize: AVATAR_ICON_SIZE,
styleClass: 'status-chooser-user-icon' });
this._iconSize = params.iconSize;
this.actor = new St.Bin({ style_class: params.styleClass,
track_hover: params.reactive,
reactive: params.reactive });
},
setSensitive: function(sensitive) {
this.actor.can_focus = sensitive;
this.actor.reactive = sensitive;
},
update: function() {
let iconFile = this._user.get_icon_file();
if (iconFile && !GLib.file_test(iconFile, GLib.FileTest.EXISTS))
iconFile = null;
if (iconFile) {
let file = Gio.File.new_for_path(iconFile);
this.actor.child = null;
this.actor.style = 'background-image: url("%s");'.format(iconFile);
} else {
this.actor.style = null;
this.actor.child = new St.Icon({ icon_name: 'avatar-default-symbolic',
icon_size: this._iconSize });
}
}
});
const UserWidget = new Lang.Class({
Name: 'UserWidget',
@ -16,8 +62,9 @@ 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._avatar = new Avatar(user);
this.actor.add(this._avatar.actor,
{ x_fill: true, y_fill: true });
@ -36,7 +83,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 +93,6 @@ const UserWidget = new Lang.Class({
this._user.disconnect(this._userChangedId);
this._userChangedId = 0;
}
this.actor.destroy();
},
_updateUser: function() {

View File

@ -150,6 +150,14 @@ const ViewSelector = new Lang.Class({
Shell.KeyBindingMode.NORMAL |
Shell.KeyBindingMode.OVERVIEW,
Lang.bind(this, this._toggleAppsPage));
Main.wm.addKeybinding('toggle-overview',
new Gio.Settings({ schema: SHELL_KEYBINDINGS_SCHEMA }),
Meta.KeyBindingFlags.NONE,
Shell.KeyBindingMode.NORMAL |
Shell.KeyBindingMode.OVERVIEW,
Lang.bind(Main.overview, Main.overview.toggle));
},
_toggleAppsPage: function() {
@ -178,6 +186,10 @@ const ViewSelector = new Lang.Class({
Main.overview.fadeInDesktop();
},
setWorkspacesFullGeometry: function(geom) {
this._workspacesDisplay.setWorkspacesFullGeometry(geom);
},
hide: function() {
this._workspacesDisplay.hide();
},
@ -496,12 +508,12 @@ const ViewSelector = new Lang.Class({
return;
this._searchSystem.registerProvider(provider);
this._searchResults.createProviderMeta(provider);
this._searchResults.createProviderDisplay(provider);
},
removeSearchProvider: function(provider) {
this._searchSystem.unregisterProvider(provider);
this._searchResults.destroyProviderMeta(provider);
this._searchResults.destroyProviderDisplay(provider);
},
getActivePage: function() {

View File

@ -134,9 +134,9 @@ const WandaSearchProvider = new Lang.Class({
getInitialResultSet: function(terms) {
if (terms.join(' ') == MAGIC_FISH_KEY) {
this.searchSystem.pushResults(this, [ FISH_NAME ]);
this.searchSystem.setResults(this, [ FISH_NAME ]);
} else {
this.searchSystem.pushResults(this, []);
this.searchSystem.setResults(this, []);
}
},

View File

@ -4,6 +4,7 @@ const Clutter = imports.gi.Clutter;
const GLib = imports.gi.GLib;
const Gio = imports.gi.Gio;
const Lang = imports.lang;
const Mainloop = imports.mainloop;
const Meta = imports.gi.Meta;
const St = imports.gi.St;
const Shell = imports.gi.Shell;
@ -66,6 +67,209 @@ function getWindowDimmer(actor) {
}
}
/*
* When the last window closed on a workspace is a dialog or splash
* screen, we assume that it might be an initial window shown before
* the main window of an application, and give the app a grace period
* where it can map another window before we remove the workspace.
*/
const LAST_WINDOW_GRACE_TIME = 1000;
const WorkspaceTracker = new Lang.Class({
Name: 'WorkspaceTracker',
_init: function(wm) {
this._wm = wm;
this._workspaces = [];
this._checkWorkspacesId = 0;
let tracker = Shell.WindowTracker.get_default();
tracker.connect('startup-sequence-changed', Lang.bind(this, this._queueCheckWorkspaces));
global.screen.connect('notify::n-workspaces', Lang.bind(this, this._nWorkspacesChanged));
global.screen.connect('window-entered-monitor', Lang.bind(this, this._windowEnteredMonitor));
global.screen.connect('window-left-monitor', Lang.bind(this, this._windowLeftMonitor));
global.screen.connect('restacked', Lang.bind(this, this._windowsRestacked));
this._workspaceSettings = new Gio.Settings({ schema: Main.dynamicWorkspacesSchema });
this._workspaceSettings.connect('changed::dynamic-workspaces', Lang.bind(this, this._queueCheckWorkspaces));
this._nWorkspacesChanged();
},
_checkWorkspaces: function() {
let i;
let emptyWorkspaces = [];
if (!Meta.prefs_get_dynamic_workspaces()) {
this._checkWorkspacesId = 0;
return false;
}
for (i = 0; i < this._workspaces.length; i++) {
let lastRemoved = this._workspaces[i]._lastRemovedWindow;
if ((lastRemoved &&
(lastRemoved.get_window_type() == Meta.WindowType.SPLASHSCREEN ||
lastRemoved.get_window_type() == Meta.WindowType.DIALOG ||
lastRemoved.get_window_type() == Meta.WindowType.MODAL_DIALOG)) ||
this._workspaces[i]._keepAliveId)
emptyWorkspaces[i] = false;
else
emptyWorkspaces[i] = true;
}
let sequences = Shell.WindowTracker.get_default().get_startup_sequences();
for (i = 0; i < sequences.length; i++) {
let index = sequences[i].get_workspace();
if (index >= 0 && index <= global.screen.n_workspaces)
emptyWorkspaces[index] = false;
}
let windows = global.get_window_actors();
for (i = 0; i < windows.length; i++) {
let win = windows[i];
if (win.get_meta_window().is_on_all_workspaces())
continue;
let workspaceIndex = win.get_workspace();
emptyWorkspaces[workspaceIndex] = false;
}
// If we don't have an empty workspace at the end, add one
if (!emptyWorkspaces[emptyWorkspaces.length -1]) {
global.screen.append_new_workspace(false, global.get_current_time());
emptyWorkspaces.push(false);
}
let activeWorkspaceIndex = global.screen.get_active_workspace_index();
let removingCurrentWorkspace = (emptyWorkspaces[activeWorkspaceIndex] &&
activeWorkspaceIndex < emptyWorkspaces.length - 1);
// Don't enter the overview when removing multiple empty workspaces at startup
let showOverview = (removingCurrentWorkspace &&
!emptyWorkspaces.every(function(x) { return x; }));
if (removingCurrentWorkspace) {
// "Merge" the empty workspace we are removing with the one at the end
this._wm.blockAnimations();
}
// Delete other empty workspaces; do it from the end to avoid index changes
for (i = emptyWorkspaces.length - 2; i >= 0; i--) {
if (emptyWorkspaces[i])
global.screen.remove_workspace(this._workspaces[i], global.get_current_time());
}
if (removingCurrentWorkspace) {
global.screen.get_workspace_by_index(global.screen.n_workspaces - 1).activate(global.get_current_time());
this._wm.unblockAnimations();
if (!Main.overview.visible && showOverview)
Main.overview.show();
}
this._checkWorkspacesId = 0;
return false;
},
keepWorkspaceAlive: function(workspace, duration) {
if (workspace._keepAliveId)
Mainloop.source_remove(workspace._keepAliveId);
workspace._keepAliveId = Mainloop.timeout_add(duration, Lang.bind(this, function() {
workspace._keepAliveId = 0;
this._queueCheckWorkspaces();
return false;
}));
},
_windowRemoved: function(workspace, window) {
workspace._lastRemovedWindow = window;
this._queueCheckWorkspaces();
Mainloop.timeout_add(LAST_WINDOW_GRACE_TIME, Lang.bind(this, function() {
if (workspace._lastRemovedWindow == window) {
workspace._lastRemovedWindow = null;
this._queueCheckWorkspaces();
}
return false;
}));
},
_windowLeftMonitor: function(metaScreen, monitorIndex, metaWin) {
// If the window left the primary monitor, that
// might make that workspace empty
if (monitorIndex == Main.layoutManager.primaryIndex)
this._queueCheckWorkspaces();
},
_windowEnteredMonitor: function(metaScreen, monitorIndex, metaWin) {
// If the window entered the primary monitor, that
// might make that workspace non-empty
if (monitorIndex == Main.layoutManager.primaryIndex)
this._queueCheckWorkspaces();
},
_windowsRestacked: function() {
// Figure out where the pointer is in case we lost track of
// it during a grab. (In particular, if a trayicon popup menu
// is dismissed, see if we need to close the message tray.)
global.sync_pointer();
},
_queueCheckWorkspaces: function() {
if (this._checkWorkspacesId == 0)
this._checkWorkspacesId = Meta.later_add(Meta.LaterType.BEFORE_REDRAW, Lang.bind(this, this._checkWorkspaces));
},
_nWorkspacesChanged: function() {
let oldNumWorkspaces = this._workspaces.length;
let newNumWorkspaces = global.screen.n_workspaces;
if (oldNumWorkspaces == newNumWorkspaces)
return false;
let lostWorkspaces = [];
if (newNumWorkspaces > oldNumWorkspaces) {
let w;
// Assume workspaces are only added at the end
for (w = oldNumWorkspaces; w < newNumWorkspaces; w++)
this._workspaces[w] = global.screen.get_workspace_by_index(w);
for (w = oldNumWorkspaces; w < newNumWorkspaces; w++) {
let workspace = this._workspaces[w];
workspace._windowAddedId = workspace.connect('window-added', Lang.bind(this, this._queueCheckWorkspaces));
workspace._windowRemovedId = workspace.connect('window-removed', Lang.bind(this, this._windowRemoved));
}
} else {
// Assume workspaces are only removed sequentially
// (e.g. 2,3,4 - not 2,4,7)
let removedIndex;
let removedNum = oldNumWorkspaces - newNumWorkspaces;
for (let w = 0; w < oldNumWorkspaces; w++) {
let workspace = global.screen.get_workspace_by_index(w);
if (this._workspaces[w] != workspace) {
removedIndex = w;
break;
}
}
let lostWorkspaces = this._workspaces.splice(removedIndex, removedNum);
lostWorkspaces.forEach(function(workspace) {
workspace.disconnect(workspace._windowAddedId);
workspace.disconnect(workspace._windowRemovedId);
});
}
this._queueCheckWorkspaces();
return false;
}
});
const WindowManager = new Lang.Class({
Name: 'WindowManager',
@ -136,6 +340,90 @@ const WindowManager = new Lang.Class({
Shell.KeyBindingMode.NORMAL |
Shell.KeyBindingMode.OVERVIEW,
Lang.bind(this, this._showWorkspaceSwitcher));
this.setCustomKeybindingHandler('switch-to-workspace-1',
Shell.KeyBindingMode.NORMAL |
Shell.KeyBindingMode.OVERVIEW,
Lang.bind(this, this._showWorkspaceSwitcher));
this.setCustomKeybindingHandler('switch-to-workspace-2',
Shell.KeyBindingMode.NORMAL |
Shell.KeyBindingMode.OVERVIEW,
Lang.bind(this, this._showWorkspaceSwitcher));
this.setCustomKeybindingHandler('switch-to-workspace-3',
Shell.KeyBindingMode.NORMAL |
Shell.KeyBindingMode.OVERVIEW,
Lang.bind(this, this._showWorkspaceSwitcher));
this.setCustomKeybindingHandler('switch-to-workspace-4',
Shell.KeyBindingMode.NORMAL |
Shell.KeyBindingMode.OVERVIEW,
Lang.bind(this, this._showWorkspaceSwitcher));
this.setCustomKeybindingHandler('switch-to-workspace-5',
Shell.KeyBindingMode.NORMAL |
Shell.KeyBindingMode.OVERVIEW,
Lang.bind(this, this._showWorkspaceSwitcher));
this.setCustomKeybindingHandler('switch-to-workspace-6',
Shell.KeyBindingMode.NORMAL |
Shell.KeyBindingMode.OVERVIEW,
Lang.bind(this, this._showWorkspaceSwitcher));
this.setCustomKeybindingHandler('switch-to-workspace-7',
Shell.KeyBindingMode.NORMAL |
Shell.KeyBindingMode.OVERVIEW,
Lang.bind(this, this._showWorkspaceSwitcher));
this.setCustomKeybindingHandler('switch-to-workspace-8',
Shell.KeyBindingMode.NORMAL |
Shell.KeyBindingMode.OVERVIEW,
Lang.bind(this, this._showWorkspaceSwitcher));
this.setCustomKeybindingHandler('switch-to-workspace-9',
Shell.KeyBindingMode.NORMAL |
Shell.KeyBindingMode.OVERVIEW,
Lang.bind(this, this._showWorkspaceSwitcher));
this.setCustomKeybindingHandler('switch-to-workspace-10',
Shell.KeyBindingMode.NORMAL |
Shell.KeyBindingMode.OVERVIEW,
Lang.bind(this, this._showWorkspaceSwitcher));
this.setCustomKeybindingHandler('switch-to-workspace-11',
Shell.KeyBindingMode.NORMAL |
Shell.KeyBindingMode.OVERVIEW,
Lang.bind(this, this._showWorkspaceSwitcher));
this.setCustomKeybindingHandler('switch-to-workspace-12',
Shell.KeyBindingMode.NORMAL |
Shell.KeyBindingMode.OVERVIEW,
Lang.bind(this, this._showWorkspaceSwitcher));
this.setCustomKeybindingHandler('move-to-workspace-1',
Shell.KeyBindingMode.NORMAL,
Lang.bind(this, this._showWorkspaceSwitcher));
this.setCustomKeybindingHandler('move-to-workspace-2',
Shell.KeyBindingMode.NORMAL,
Lang.bind(this, this._showWorkspaceSwitcher));
this.setCustomKeybindingHandler('move-to-workspace-3',
Shell.KeyBindingMode.NORMAL,
Lang.bind(this, this._showWorkspaceSwitcher));
this.setCustomKeybindingHandler('move-to-workspace-4',
Shell.KeyBindingMode.NORMAL,
Lang.bind(this, this._showWorkspaceSwitcher));
this.setCustomKeybindingHandler('move-to-workspace-5',
Shell.KeyBindingMode.NORMAL,
Lang.bind(this, this._showWorkspaceSwitcher));
this.setCustomKeybindingHandler('move-to-workspace-6',
Shell.KeyBindingMode.NORMAL,
Lang.bind(this, this._showWorkspaceSwitcher));
this.setCustomKeybindingHandler('move-to-workspace-7',
Shell.KeyBindingMode.NORMAL,
Lang.bind(this, this._showWorkspaceSwitcher));
this.setCustomKeybindingHandler('move-to-workspace-8',
Shell.KeyBindingMode.NORMAL,
Lang.bind(this, this._showWorkspaceSwitcher));
this.setCustomKeybindingHandler('move-to-workspace-9',
Shell.KeyBindingMode.NORMAL,
Lang.bind(this, this._showWorkspaceSwitcher));
this.setCustomKeybindingHandler('move-to-workspace-10',
Shell.KeyBindingMode.NORMAL,
Lang.bind(this, this._showWorkspaceSwitcher));
this.setCustomKeybindingHandler('move-to-workspace-11',
Shell.KeyBindingMode.NORMAL,
Lang.bind(this, this._showWorkspaceSwitcher));
this.setCustomKeybindingHandler('move-to-workspace-12',
Shell.KeyBindingMode.NORMAL,
Lang.bind(this, this._showWorkspaceSwitcher));
this.setCustomKeybindingHandler('switch-applications',
Shell.KeyBindingMode.NORMAL,
Lang.bind(this, this._startAppSwitcher));
@ -172,8 +460,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++)
@ -183,6 +472,11 @@ const WindowManager = new Lang.Class({
for (let i = 0; i < this._dimmedWindows.length; i++)
this._dimWindow(this._dimmedWindows[i]);
}));
this._workspaceTracker = new WorkspaceTracker(this);
global.screen.override_workspace_layout(Meta.ScreenCorner.TOPLEFT,
false, -1, 1);
},
setCustomKeybindingHandler: function(name, modes, handler) {
@ -679,27 +973,39 @@ 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) {
if (screen.n_workspaces == 1)
return;
let [action,,,direction] = binding.get_name().split('-');
let direction = Meta.MotionDirection[direction.toUpperCase()];
let [action,,,target] = binding.get_name().split('-');
let newWs;
let direction;
if (isNaN(target)) {
direction = Meta.MotionDirection[target.toUpperCase()];
newWs = screen.get_active_workspace().get_neighbor(direction);
} else if (target > 0) {
target--;
newWs = screen.get_workspace_by_index(target);
if (screen.get_active_workspace().index() > target)
direction = Meta.MotionDirection.UP;
else
direction = Meta.MotionDirection.DOWN;
}
if (direction != Meta.MotionDirection.UP &&
direction != Meta.MotionDirection.DOWN)
return;
if (action == 'switch')
newWs = this.actionMoveWorkspace(direction);
this.actionMoveWorkspace(newWs);
else
newWs = this.actionMoveWindow(window, direction);
this.actionMoveWindow(window, newWs);
if (!Main.overview.visible) {
if (this._workspaceSwitcherPopup == null) {
@ -712,31 +1018,27 @@ const WindowManager = new Lang.Class({
}
},
actionMoveWorkspace: function(direction) {
actionMoveWorkspace: function(workspace) {
let activeWorkspace = global.screen.get_active_workspace();
let toActivate = activeWorkspace.get_neighbor(direction);
if (activeWorkspace != toActivate)
toActivate.activate(global.get_current_time());
if (activeWorkspace != workspace)
workspace.activate(global.get_current_time());
return toActivate;
},
actionMoveWindow: function(window, direction) {
actionMoveWindow: function(window, workspace) {
let activeWorkspace = global.screen.get_active_workspace();
let toActivate = activeWorkspace.get_neighbor(direction);
if (activeWorkspace != toActivate) {
if (activeWorkspace != workspace) {
// This won't have any effect for "always sticky" windows
// (like desktop windows or docks)
this._movingWindow = window;
window.change_workspace(toActivate);
window.change_workspace(workspace);
global.display.clear_mouse_mode();
toActivate.activate_with_focus (window, global.get_current_time());
workspace.activate_with_focus (window, global.get_current_time());
}
return toActivate;
},
});

View File

@ -453,6 +453,10 @@ const WindowOverlay = new Lang.Class({
metaWindow.delete(global.get_current_time());
},
_windowCanClose: function() {
return this._windowClone.metaWindow.can_close();
},
_onWindowAdded: function(workspace, win) {
let metaWindow = this._windowClone.metaWindow;
@ -488,12 +492,14 @@ const WindowOverlay = new Lang.Class({
_animateVisible: function() {
this._parentActor.raise_top();
this.closeButton.show();
this.closeButton.opacity = 0;
Tweener.addTween(this.closeButton,
{ opacity: 255,
time: CLOSE_BUTTON_FADE_TIME,
transition: 'easeOutQuad' });
if (this._windowCanClose()) {
this.closeButton.show();
this.closeButton.opacity = 0;
Tweener.addTween(this.closeButton,
{ opacity: 255,
time: CLOSE_BUTTON_FADE_TIME,
transition: 'easeOutQuad' });
}
this.border.show();
this.border.opacity = 0;
@ -753,13 +759,6 @@ const LayoutStrategy = new Lang.Class({
layout.space = space;
},
_getDistance: function (row, actor) {
let dist_x = actor.x - row.x;
let dist_y = actor.y - row.y;
return Math.sqrt(Math.pow(dist_x, 2) + Math.pow(dist_y, 2));
},
computeWindowSlots: function(layout, area) {
this._computeRowSizes(layout);
@ -767,28 +766,36 @@ const LayoutStrategy = new Lang.Class({
let slots = [];
let y = 0;
// Do this in three parts.
let height = 0;
for (let i = 0; i < rows.length; i++) {
let row = rows[i];
row.x = area.x + (area.width - row.width) / 2;
row.y = area.y + y;
y += row.height + this._rowSpacing;
row.windows.sort(Lang.bind(this, function(a, b) {
return this._getDistance(row, a.realWindow) - this._getDistance(row, b.realWindow);
}));
height += row.height + this._rowSpacing;
}
let height = y - this._rowSpacing;
let baseY = (area.height - height) / 2;
height -= this._rowSpacing;
let y = 0;
for (let i = 0; i < rows.length; i++) {
let row = rows[i];
// If this window layout row doesn't fit in the actual
// geometry, then apply an additional scale to it.
row.additionalScale = Math.min(1, area.width / row.width, area.height / height);
row.x = area.x + (Math.max(area.width - row.width, 0) / 2) * row.additionalScale;
row.y = area.y + (y + Math.max(area.height - height, 0) / 2) * row.additionalScale;
y += row.height + this._rowSpacing;
}
for (let i = 0; i < rows.length; i++) {
let row = rows[i];
row.y += baseY;
let x = row.x;
for (let j = 0; j < row.windows.length; j++) {
let window = row.windows[j];
let s = scale * this._computeWindowScale(window);
let s = scale * this._computeWindowScale(window) * row.additionalScale;
let cellWidth = window.actor.width * s;
let cellHeight = window.actor.height * s;
@ -832,6 +839,13 @@ const UnalignedLayoutStrategy = new Lang.Class({
return false;
},
_sortRow: function(row) {
// Sort windows horizontally to minimize travel distance
row.windows.sort(function(a, b) {
return a.realWindow.x - b.realWindow.x;
});
},
computeLayout: function(windows, layout) {
let numRows = layout.numRows;
@ -862,6 +876,7 @@ const UnalignedLayoutStrategy = new Lang.Class({
row.windows.push(window);
row.fullWidth += width;
} else {
this._sortRow(row);
break;
}
}
@ -883,6 +898,14 @@ const UnalignedLayoutStrategy = new Lang.Class({
}
});
function padArea(area, padding) {
return {
x: area.x + padding.left,
y: area.y + padding.top,
width: area.width - padding.left - padding.right,
height: area.height - padding.top - padding.bottom,
};
}
/**
* @metaWorkspace: a #Meta.Workspace, or null
@ -894,10 +917,19 @@ const Workspace = new Lang.Class({
// When dragging a window, we use this slot for reserve space.
this._reservedSlot = null;
this.metaWorkspace = metaWorkspace;
this._x = 0;
this._y = 0;
this._width = 0;
this._height = 0;
// The full geometry is the geometry we should try and position
// windows for. The actual geometry we allocate may be less than
// this, like if the workspace switcher is slid out.
this._fullGeometry = null;
// The actual geometry is the geometry we need to arrange windows
// in. If this is a smaller area than the full geometry, we'll
// do some simple aspect ratio like math to fit the layout calculated
// for the full geometry into this area.
this._actualGeometry = null;
this._currentLayout = null;
this.monitorIndex = monitorIndex;
this._monitor = Main.layoutManager.monitors[this.monitorIndex];
@ -910,7 +942,7 @@ const Workspace = new Lang.Class({
this.actor.add_style_class_name('external-monitor');
this.actor.set_size(0, 0);
this._dropRect = new Clutter.Rectangle({ opacity: 0 });
this._dropRect = new Clutter.Actor({ opacity: 0 });
this._dropRect._delegate = this;
this.actor.add_actor(this._dropRect);
@ -947,23 +979,29 @@ const Workspace = new Lang.Class({
this._positionWindowsFlags = 0;
this._positionWindowsId = 0;
this._currentLayout = null;
},
setGeometry: function(x, y, width, height) {
this._x = x;
this._y = y;
this._width = width;
this._height = height;
setFullGeometry: function(geom) {
this._fullGeometry = geom;
this._recalculateWindowPositions(WindowPositionFlags.NONE);
},
Meta.later_add(Meta.LaterType.BEFORE_REDRAW, Lang.bind(this, function() {
this._dropRect.set_position(x, y);
this._dropRect.set_size(width, height);
setActualGeometry: function(geom) {
this._actualGeometry = geom;
if (this._actualGeometryLater)
return;
this._actualGeometryLater = Meta.later_add(Meta.LaterType.BEFORE_REDRAW, Lang.bind(this, function() {
let geom = this._actualGeometry;
this._dropRect.set_position(geom.x, geom.y);
this._dropRect.set_size(geom.width, geom.height);
this._updateWindowPositions(WindowPositionFlags.NONE);
this._actualGeometryLater = 0;
return false;
}));
this.positionWindows(WindowPositionFlags.NONE);
},
_lookupIndex: function (metaWindow) {
@ -991,37 +1029,32 @@ const Workspace = new Lang.Class({
clone = null;
this._reservedSlot = clone;
this._currentLayout = null;
this.positionWindows(WindowPositionFlags.ANIMATE);
this._recalculateWindowPositions(WindowPositionFlags.ANIMATE);
},
/**
* positionWindows:
* @flags:
* INITIAL - this is the initial positioning of the windows.
* ANIMATE - Indicates that we need animate changing position.
*/
positionWindows: function(flags) {
_recalculateWindowPositions: function(flags) {
this._positionWindowsFlags |= flags;
if (this._positionWindowsId > 0)
return;
this._positionWindowsId = Meta.later_add(Meta.LaterType.BEFORE_REDRAW, Lang.bind(this, function() {
this._realPositionWindows(this._positionWindowsFlags);
this._realRecalculateWindowPositions(this._positionWindowsFlags);
this._positionWindowsFlags = 0;
this._positionWindowsId = 0;
return false;
}));
},
_realPositionWindows : function(flags) {
_realRecalculateWindowPositions: function(flags) {
if (this._repositionWindowsId > 0) {
Mainloop.source_remove(this._repositionWindowsId);
this._repositionWindowsId = 0;
}
let clones = this._windows.slice();
if (clones.length == 0)
return;
clones.sort(function(a, b) {
return a.metaWindow.get_stable_sequence() - b.metaWindow.get_stable_sequence();
@ -1030,11 +1063,25 @@ const Workspace = new Lang.Class({
if (this._reservedSlot)
clones.push(this._reservedSlot);
this._currentLayout = this._computeLayout(clones);
this._updateWindowPositions(flags);
},
_updateWindowPositions: function(flags) {
if (this._currentLayout == null) {
this._recalculateWindowPositions(flags);
return;
}
let initialPositioning = flags & WindowPositionFlags.INITIAL;
let animate = flags & WindowPositionFlags.ANIMATE;
// Start the animations
let slots = this._computeAllWindowSlots(clones);
let layout = this._currentLayout;
let strategy = layout.strategy;
let [, , padding] = this._getSpacingAndPadding();
let area = padArea(this._actualGeometry, padding);
let slots = strategy.computeWindowSlots(layout, area);
let currentWorkspace = global.screen.get_active_workspace();
let isOnCurrentWorkspace = this.metaWorkspace == null || this.metaWorkspace == currentWorkspace;
@ -1148,8 +1195,8 @@ const Workspace = new Lang.Class({
let [x, y, mask] = global.get_pointer();
let pointerHasMoved = (this._cursorX != x && this._cursorY != y);
let inWorkspace = (this._x < x && x < this._x + this._width &&
this._y < y && y < this._y + this._height);
let inWorkspace = (this._fullGeometry.x < x && x < this._fullGeometry.x + this._fullGeometry.width &&
this._fullGeometry.y < y && y < this._fullGeometry.y + this._fullGeometry.height);
if (pointerHasMoved && inWorkspace) {
// store current cursor position
@ -1164,7 +1211,7 @@ const Workspace = new Lang.Class({
return true;
}
this.positionWindows(WindowPositionFlags.ANIMATE);
this._recalculateWindowPositions(WindowPositionFlags.ANIMATE);
return false;
},
@ -1269,7 +1316,7 @@ const Workspace = new Lang.Class({
}
this._currentLayout = null;
this.positionWindows(WindowPositionFlags.ANIMATE);
this._recalculateWindowPositions(WindowPositionFlags.ANIMATE);
},
_windowAdded : function(metaWorkspace, metaWin) {
@ -1306,13 +1353,8 @@ const Workspace = new Lang.Class({
// Animate the full-screen to Overview transition.
zoomToOverview : function() {
this._currentLayout = null;
// Position and scale the windows.
if (Main.overview.animationInProgress)
this.positionWindows(WindowPositionFlags.ANIMATE | WindowPositionFlags.INITIAL);
else
this.positionWindows(WindowPositionFlags.INITIAL);
this._recalculateWindowPositions(WindowPositionFlags.ANIMATE | WindowPositionFlags.INITIAL);
},
// Animates the return from Overview mode
@ -1436,7 +1478,7 @@ const Workspace = new Lang.Class({
}));
clone.connect('size-changed',
Lang.bind(this, function() {
this.positionWindows(0);
this._recalculateWindowPositions(WindowPositionFlags.NONE);
}));
this.actor.add_actor(clone.actor);
@ -1485,12 +1527,14 @@ const Workspace = new Lang.Class({
}
},
_computeLayout: function(windows, area, rowSpacing, columnSpacing) {
_getBestLayout: function(windows, area, rowSpacing, columnSpacing) {
// We look for the largest scale that allows us to fit the
// largest row/tallest column on the workspace.
let lastLayout = {};
let strategy = new UnalignedLayoutStrategy(this._monitor, rowSpacing, columnSpacing);
for (let numRows = 1; ; numRows++) {
let numColumns = Math.ceil(windows.length / numRows);
@ -1500,8 +1544,6 @@ const Workspace = new Lang.Class({
if (numColumns == lastLayout.numColumns)
break;
let strategy = new UnalignedLayoutStrategy(this._monitor, rowSpacing, columnSpacing);
let layout = { area: area, strategy: strategy, numRows: numRows, numColumns: numColumns };
strategy.computeLayout(windows, layout);
strategy.computeScaleAndSpace(layout);
@ -1515,18 +1557,7 @@ const Workspace = new Lang.Class({
return lastLayout;
},
_rectEqual: function(one, two) {
if (one == two)
return true;
return (one.x == two.x &&
one.y == two.y &&
one.width == two.width &&
one.height == two.height);
},
_computeAllWindowSlots: function(windows) {
let totalWindows = windows.length;
_getSpacingAndPadding: function() {
let node = this.actor.get_theme_node();
// Window grid spacing
@ -1539,21 +1570,14 @@ const Workspace = new Lang.Class({
right: node.get_padding(St.Side.RIGHT),
};
if (!totalWindows)
return [];
let closeButtonHeight, captionHeight;
let leftBorder, rightBorder;
if (this._windowOverlays.length) {
// All of the overlays have the same chrome sizes,
// so just pick the first one.
let overlay = this._windowOverlays[0];
[closeButtonHeight, captionHeight] = overlay.chromeHeights();
[leftBorder, rightBorder] = overlay.chromeWidths();
} else {
[closeButtonHeight, captionHeight] = [0, 0];
[leftBorder, rightBorder] = [0, 0];
}
// All of the overlays have the same chrome sizes,
// so just pick the first one.
let overlay = this._windowOverlays[0];
[closeButtonHeight, captionHeight] = overlay.chromeHeights();
[leftBorder, rightBorder] = overlay.chromeWidths();
rowSpacing += captionHeight;
columnSpacing += (rightBorder + leftBorder) / 2;
@ -1562,25 +1586,13 @@ const Workspace = new Lang.Class({
padding.left += leftBorder;
padding.right += rightBorder;
let area = {
x: this._x + padding.left,
y: this._y + padding.top,
width: this._width - padding.left - padding.right,
height: this._height - padding.top - padding.bottom,
};
return [rowSpacing, columnSpacing, padding];
},
if (!this._currentLayout)
this._currentLayout = this._computeLayout(windows, area, rowSpacing, columnSpacing);
let layout = this._currentLayout;
let strategy = layout.strategy;
if (!this._rectEqual(area, layout.area)) {
layout.area = area;
strategy.computeScaleAndSpace(layout);
}
return strategy.computeWindowSlots(layout, area);
_computeLayout: function(windows) {
let [rowSpacing, columnSpacing, padding] = this._getSpacingAndPadding();
let area = padArea(this._fullGeometry, padding);
return this._getBestLayout(windows, area, rowSpacing, columnSpacing);
},
_onCloneSelected : function (clone, time) {

View File

@ -23,6 +23,18 @@ const MAX_WORKSPACES = 16;
const OVERRIDE_SCHEMA = 'org.gnome.shell.overrides';
function rectEqual(one, two) {
if (one == two)
return true;
if (!one || !two)
return false;
return (one.x == two.x &&
one.y == two.y &&
one.width == two.width &&
one.height == two.height);
}
const WorkspacesView = new Lang.Class({
Name: 'WorkspacesView',
@ -43,10 +55,9 @@ const WorkspacesView = new Lang.Class({
this._updateWorkspaceActors(false);
}));
this._width = 0;
this._height = 0;
this._x = 0;
this._y = 0;
this._fullGeometry = null;
this._actualGeometry = null;
this._spacing = 0;
this._animating = false; // tweening
this._scrolling = false; // swipe-scrolling
@ -85,8 +96,8 @@ const WorkspacesView = new Lang.Class({
this._overviewShownId =
Main.overview.connect('shown',
Lang.bind(this, function() {
this.actor.set_clip(this._x, this._y,
this._width, this._height);
this.actor.set_clip(this._fullGeometry.x, this._fullGeometry.y,
this._fullGeometry.width, this._fullGeometry.height);
}));
this.scrollAdjustment = new St.Adjustment({ value: activeWorkspaceIndex,
@ -124,11 +135,9 @@ const WorkspacesView = new Lang.Class({
continue;
let ws = new Workspace.Workspace(null, i);
ws.setGeometry(monitors[i].x,
monitors[i].y,
monitors[i].width,
monitors[i].height);
global.overlay_group.add_actor(ws.actor);
ws.setFullGeometry(monitors[i]);
ws.setActualGeometry(monitors[i]);
Main.layoutManager.overviewGroup.add_actor(ws.actor);
this._extraWorkspaces.push(ws);
}
},
@ -139,18 +148,24 @@ const WorkspacesView = new Lang.Class({
this._extraWorkspaces = [];
},
setGeometry: function(x, y, width, height) {
if (this._x == x && this._y == y &&
this._width == width && this._height == height)
return;
setFullGeometry: function(geom) {
if (rectEqual(this._fullGeometry, geom))
return;
this._width = width;
this._height = height;
this._x = x;
this._y = y;
this._fullGeometry = geom;
for (let i = 0; i < this._workspaces.length; i++)
this._workspaces[i].setGeometry(x, y, width, height);
this._workspaces[i].setFullGeometry(geom);
},
setActualGeometry: function(geom) {
if (rectEqual(this._actualGeometry, geom))
return;
this._actualGeometry = geom;
for (let i = 0; i < this._workspaces.length; i++)
this._workspaces[i].setActualGeometry(geom);
},
_lookupWorkspaceForMetaWindow: function (metaWindow) {
@ -210,7 +225,7 @@ const WorkspacesView = new Lang.Class({
Tweener.removeTweens(workspace.actor);
let y = (w - active) * (this._height + this._spacing);
let y = (w - active) * (this._fullGeometry.height + this._spacing);
if (showAnimation) {
let params = { y: y,
@ -281,8 +296,9 @@ const WorkspacesView = new Lang.Class({
if (newNumWorkspaces > oldNumWorkspaces) {
for (let w = oldNumWorkspaces; w < newNumWorkspaces; w++) {
this._workspaces[w].setGeometry(this._x, this._y,
this._width, this._height);
this._workspaces[w].setFullGeometry(this._fullGeometry);
if (this._actualGeometry)
this._workspaces[w].setActualGeometry(this._actualGeometry);
this.actor.add_actor(this._workspaces[w].actor);
}
@ -430,7 +446,7 @@ const WorkspacesDisplay = new Lang.Class({
_init: function() {
this.actor = new St.Widget({ clip_to_allocation: true });
this.actor.connect('notify::allocation', Lang.bind(this, this._updateWorkspacesGeometry));
this.actor.connect('notify::allocation', Lang.bind(this, this._updateWorkspacesActualGeometry));
this.actor.connect('parent-set', Lang.bind(this, this._parentSet));
let clickAction = new Clutter.ClickAction()
@ -484,6 +500,8 @@ const WorkspacesDisplay = new Lang.Class({
this._notifyOpacityId = 0;
this._scrollEventId = 0;
this._fullGeometry = null;
},
_onPan: function(action) {
@ -572,10 +590,11 @@ const WorkspacesDisplay = new Lang.Class({
this._workspacesViews.push(view);
}
this._updateWorkspacesGeometry();
this._updateWorkspacesFullGeometry();
this._updateWorkspacesActualGeometry();
for (let i = 0; i < this._workspacesViews.length; i++)
global.overlay_group.add_actor(this._workspacesViews[i].actor);
Main.layoutManager.overviewGroup.add_actor(this._workspacesViews[i].actor);
},
_scrollValueChanged: function() {
@ -619,7 +638,7 @@ const WorkspacesDisplay = new Lang.Class({
// This is kinda hackish - we want the primary view to
// appear as parent of this.actor, though in reality it
// is added directly to overlay_group
// is added directly to Main.layoutManager.overviewGroup
this._notifyOpacityId = newParent.connect('notify::opacity',
Lang.bind(this, function() {
let opacity = this.actor.get_parent().opacity;
@ -632,31 +651,48 @@ const WorkspacesDisplay = new Lang.Class({
}));
},
_updateWorkspacesGeometry: function() {
// This geometry should always be the fullest geometry
// the workspaces switcher can ever be allocated, as if
// the sliding controls were never slid in at all.
setWorkspacesFullGeometry: function(geom) {
this._fullGeometry = geom;
this._updateWorkspacesFullGeometry();
},
_updateWorkspacesFullGeometry: function() {
if (!this._workspacesViews.length)
return;
let fullWidth = this.actor.allocation.x2 - this.actor.allocation.x1;
let fullHeight = this.actor.allocation.y2 - this.actor.allocation.y1;
let width = fullWidth;
let height = fullHeight;
let [x, y] = this.actor.get_transformed_position();
let rtl = (Clutter.get_default_text_direction () == Clutter.TextDirection.RTL);
let monitors = Main.layoutManager.monitors;
let m = 0;
for (let i = 0; i < monitors.length; i++) {
if (i == this._primaryIndex) {
this._workspacesViews[m].setGeometry(x, y, width, height);
this._workspacesViews[m].setFullGeometry(this._fullGeometry);
m++;
} else if (!this._workspacesOnlyOnPrimary) {
this._workspacesViews[m].setGeometry(monitors[i].x,
monitors[i].y,
monitors[i].width,
monitors[i].height);
this._workspacesViews[m].setFullGeometry(monitors[i]);
m++;
}
}
},
_updateWorkspacesActualGeometry: function() {
if (!this._workspacesViews.length)
return;
let [x, y] = this.actor.get_transformed_position();
let width = this.actor.allocation.x2 - this.actor.allocation.x1;
let height = this.actor.allocation.y2 - this.actor.allocation.y1;
let geometry = { x: x, y: y, width: width, height: height };
let monitors = Main.layoutManager.monitors;
let m = 0;
for (let i = 0; i < monitors.length; i++) {
if (i == this._primaryIndex) {
this._workspacesViews[m].setActualGeometry(geometry);
m++;
} else if (!this._workspacesOnlyOnPrimary) {
this._workspacesViews[m].setActualGeometry(monitors[i]);
m++;
}
}
@ -724,15 +760,20 @@ const WorkspacesDisplay = new Lang.Class({
_onScrollEvent: function(actor, event) {
if (!this.actor.mapped)
return false;
let activeWs = global.screen.get_active_workspace();
let ws;
switch (event.get_scroll_direction()) {
case Clutter.ScrollDirection.UP:
Main.wm.actionMoveWorkspace(Meta.MotionDirection.UP);
return true;
ws = activeWs.get_neighbor(Meta.MotionDirection.UP);
break;
case Clutter.ScrollDirection.DOWN:
Main.wm.actionMoveWorkspace(Meta.MotionDirection.DOWN);
return true;
ws = activeWs.get_neighbor(Meta.MotionDirection.DOWN);
break;
default:
return false;
}
return false;
Main.wm.actionMoveWorkspace(ws);
return true;
}
});
Signals.addSignalMethods(WorkspacesDisplay.prototype);

View File

@ -16,7 +16,7 @@ const XdndHandler = new Lang.Class({
this._cursorWindowClone = null;
// Used as a drag actor in case we don't have a cursor window clone
this._dummy = new Clutter.Rectangle({ width: 1, height: 1, opacity: 0 });
this._dummy = new Clutter.Actor({ width: 1, height: 1, opacity: 0 });
Main.uiGroup.add_actor(this._dummy);
Shell.util_set_hidden_from_pick(this._dummy, true);
this._dummy.hide();

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

View File

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

779
po/bg.po

File diff suppressed because it is too large Load Diff

View File

@ -11,7 +11,7 @@ msgstr ""
"Report-Msgid-Bugs-To: http://bugzilla.gnome.org/enter_bug.cgi?product=gnome-"
"shell&keywords=I18N+L10N&component=general\n"
"POT-Creation-Date: 2013-03-11 21:29+0000\n"
"PO-Revision-Date: 2013-03-11 00:03+0100\n"
"PO-Revision-Date: 2013-05-26 08:21+0200\n"
"Last-Translator: Gil Forcada <gilforcada@guifi.net>\n"
"Language-Team: Catalan <tradgnome@softcatala.org>\n"
"Language: ca\n"
@ -1048,7 +1048,7 @@ msgstr "Obre els rellotges"
#: ../js/ui/dateMenu.js:105
msgid "Date & Time Settings"
msgstr "Configuració de la data i l'hora"
msgstr "Configuració de la data i de l'hora"
#. 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").

408
po/cs.po

File diff suppressed because it is too large Load Diff

389
po/de.po
View File

@ -17,9 +17,10 @@
msgid ""
msgstr ""
"Project-Id-Version: gnome-shell master\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2013-03-11 14:22+0100\n"
"PO-Revision-Date: 2013-03-11 14:25+0100\n"
"Report-Msgid-Bugs-To: http://bugzilla.gnome.org/enter_bug.cgi?product=gnome-"
"shell&keywords=I18N+L10N&component=general\n"
"POT-Creation-Date: 2013-05-31 22:35+0000\n"
"PO-Revision-Date: 2013-06-02 09:48+0100\n"
"Last-Translator: Christian Kirbach <christian.kirbach@gmail.com>\n"
"Language-Team: Deutsch <gnome-de@gnome.org>\n"
"Language: de_DE\n"
@ -27,7 +28,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
"X-Generator: Gtranslator 2.91.6\n"
"X-Generator: Poedit 1.5.4\n"
#: ../data/50-gnome-shell-screenshot.xml.in.h:1
msgid "Screenshots"
@ -50,10 +51,14 @@ msgid "Focus the active notification"
msgstr "Auf aktive Benachrichtigungen ausrichten"
#: ../data/50-gnome-shell-system.xml.in.h:4
msgid "Show the overview"
msgstr "Die Übersicht anzeigen"
#: ../data/50-gnome-shell-system.xml.in.h:5
msgid "Show all applications"
msgstr "Alle Anwendungen anzeigen"
#: ../data/50-gnome-shell-system.xml.in.h:5
#: ../data/50-gnome-shell-system.xml.in.h:6
msgid "Open the application menu"
msgstr "Das Anwendungsmenü öffnen"
@ -102,27 +107,10 @@ msgstr ""
"gnome.Shell bearbeiten."
#: ../data/org.gnome.shell.gschema.xml.in.in.h:5
msgid "Whether to collect stats about applications usage"
msgstr "Legt fest, ob Statistiken über Anwendungsnutzung erfasst werden sollen"
#: ../data/org.gnome.shell.gschema.xml.in.in.h:6
msgid ""
"The shell normally monitors active applications in order to present the most "
"used ones (e.g. in launchers). While this data will be kept private, you may "
"want to disable this for privacy reasons. Please note that doing so won't "
"remove already saved data."
msgstr ""
"Die Shell überwacht normalerweise aktive Anwendungen, wobei die "
"meistgenutzten zuerst erfasst werden (z.B. in Anwendungsstartern). Zwar "
"werden diese Daten privat gespeichert, doch möglicherweise wollen Sie dies "
"deaktivieren, um Ihre Privatsphäre zu schützen. Bitte beachten Sie, dass "
"bereits gespeicherte Daten hiervon nicht beeinflusst werden."
#: ../data/org.gnome.shell.gschema.xml.in.in.h:7
msgid "List of desktop file IDs for favorite applications"
msgstr "Liste der Kennungen der Desktop-Dateien für bevorzugte Anwendungen"
#: ../data/org.gnome.shell.gschema.xml.in.in.h:8
#: ../data/org.gnome.shell.gschema.xml.in.in.h:6
msgid ""
"The applications corresponding to these identifiers will be displayed in the "
"favorites area."
@ -130,11 +118,11 @@ msgstr ""
"Programme, welche auf diese Bezeichner zutreffen, werden im Favoriten-"
"Bereich angezeigt."
#: ../data/org.gnome.shell.gschema.xml.in.in.h:9
#: ../data/org.gnome.shell.gschema.xml.in.in.h:7
msgid "List of categories that should be displayed as folders"
msgstr "Liste der Kategorien, die als Ordner angezeigt werden sollen"
#: ../data/org.gnome.shell.gschema.xml.in.in.h:10
#: ../data/org.gnome.shell.gschema.xml.in.in.h:8
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."
@ -142,15 +130,15 @@ msgstr ""
"Jeder Kategoriename in dieser Liste wird als Ordner in der Anwendungsansicht "
"dargestellt, anstatt in der Hauptansicht eingebettet."
#: ../data/org.gnome.shell.gschema.xml.in.in.h:11
#: ../data/org.gnome.shell.gschema.xml.in.in.h:9
msgid "History for command (Alt-F2) dialog"
msgstr "Verlauf des Befehlsdialogs (Alt+F2)"
#: ../data/org.gnome.shell.gschema.xml.in.in.h:12
#: ../data/org.gnome.shell.gschema.xml.in.in.h:10
msgid "History for the looking glass dialog"
msgstr "Chronik des Dialogs »looking glass«"
#: ../data/org.gnome.shell.gschema.xml.in.in.h:13
#: ../data/org.gnome.shell.gschema.xml.in.in.h:11
msgid ""
"Internally used to store the last IM presence explicitly set by the user. "
"The value here is from the TpConnectionPresenceType enumeration."
@ -159,7 +147,7 @@ msgstr ""
"der explizit vom Benutzer gesetzt wurde. Der hier verwendete Wert wird der "
"TpConnectionPresenceType-Aufzählung entnommen."
#: ../data/org.gnome.shell.gschema.xml.in.in.h:14
#: ../data/org.gnome.shell.gschema.xml.in.in.h:12
msgid ""
"Internally used to store the last session presence status for the user. The "
"value here is from the GsmPresenceStatus enumeration."
@ -168,11 +156,11 @@ msgstr ""
"Benutzers verwendet. Der hier verwendete Wert wird der GsmPresenceStatus-"
"Aufzählung entnommen."
#: ../data/org.gnome.shell.gschema.xml.in.in.h:15
#: ../data/org.gnome.shell.gschema.xml.in.in.h:13
msgid "Always show the 'Log out' menuitem in the user menu."
msgstr "Den Menüeintrag »Abmelden« immer im Benutzermenü anzeigen."
#: ../data/org.gnome.shell.gschema.xml.in.in.h:16
#: ../data/org.gnome.shell.gschema.xml.in.in.h:14
msgid ""
"This key overrides the automatic hiding of the 'Log out' menuitem in single-"
"user, single-session situations."
@ -180,14 +168,14 @@ msgstr ""
"Dieser Schlüssel überschreibt das automatische Verbergen des Menüeintrags "
"»Abmelden« in Einzelbenutzer, Einzelsitzungssituationen."
#: ../data/org.gnome.shell.gschema.xml.in.in.h:17
#: ../data/org.gnome.shell.gschema.xml.in.in.h:15
msgid ""
"Whether to remember password for mounting encrypted or remote filesystems"
msgstr ""
"Legt fest, ob Passwörter für eingehängte, verschlüsselte oder ferne "
"Dateisysteme gespeichert werden"
#: ../data/org.gnome.shell.gschema.xml.in.in.h:18
#: ../data/org.gnome.shell.gschema.xml.in.in.h:16
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 "
@ -200,34 +188,42 @@ msgstr ""
"angeboten. Dieser Schlüssel stellt den Standardstatus für dieses Ankreuzfeld "
"ein."
#: ../data/org.gnome.shell.gschema.xml.in.in.h:19
#: ../data/org.gnome.shell.gschema.xml.in.in.h:17
msgid "Show the week date in the calendar"
msgstr "Wochentag im Kalender anzeigen"
#: ../data/org.gnome.shell.gschema.xml.in.in.h:20
#: ../data/org.gnome.shell.gschema.xml.in.in.h:18
msgid "If true, display the ISO week date in the calendar."
msgstr ""
"Wenn dieser Wert gesetzt ist, wird der ISO-Wochentag im Kalender angezeigt."
#: ../data/org.gnome.shell.gschema.xml.in.in.h:21
#: ../data/org.gnome.shell.gschema.xml.in.in.h:19
msgid "Keybinding to open the application menu"
msgstr "Tastenkombination zum Öffnen des Anwendungsmenüs"
#: ../data/org.gnome.shell.gschema.xml.in.in.h:22
#: ../data/org.gnome.shell.gschema.xml.in.in.h:20
msgid "Keybinding to open the application menu."
msgstr "Tastenkombination zum Öffnen des Anwendungsmenüs."
#: ../data/org.gnome.shell.gschema.xml.in.in.h:23
#: ../data/org.gnome.shell.gschema.xml.in.in.h:21
msgid "Keybinding to open the \"Show Applications\" view"
msgstr "Tastenkombination zum Öffnen der »Anwendungen anzeigen«-Ansicht"
#: ../data/org.gnome.shell.gschema.xml.in.in.h:24
#: ../data/org.gnome.shell.gschema.xml.in.in.h:22
msgid ""
"Keybinding to open the \"Show Applications\" view of the Activities Overview."
msgstr ""
"Tastenkombination zum Öffnen der »Anwendungen anzeigen«-Ansicht der "
"Aktivitätenübersicht."
#: ../data/org.gnome.shell.gschema.xml.in.in.h:23
msgid "Keybinding to open the overview"
msgstr "Tastenkombination zum Öffnen der Übersicht"
#: ../data/org.gnome.shell.gschema.xml.in.in.h:24
msgid "Keybinding to open the Activities Overview."
msgstr "Tastenkombination zum Öffnen der »Aktivitäten«-Übersicht"
#: ../data/org.gnome.shell.gschema.xml.in.in.h:25
msgid "Keybinding to toggle the visibility of the message tray"
msgstr ""
@ -391,43 +387,50 @@ msgstr "Erweiterung"
msgid "Select an extension to configure using the combobox above."
msgstr "Wählen Sie oben eine Erweiterung aus, die Sie konfigurieren wollen."
#: ../js/gdm/loginDialog.js:405
#: ../js/gdm/loginDialog.js:371
msgid "Session…"
msgstr "Sitzung …"
#. 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:630
#: ../js/gdm/loginDialog.js:601
msgid "Not listed?"
msgstr "Nicht aufgeführt?"
#: ../js/gdm/loginDialog.js:784 ../js/ui/components/networkAgent.js:137
#: ../js/ui/components/polkitAgent.js:162 ../js/ui/endSessionDialog.js:375
#: ../js/gdm/loginDialog.js:776 ../js/ui/components/networkAgent.js:137
#: ../js/ui/components/polkitAgent.js:161 ../js/ui/endSessionDialog.js:376
#: ../js/ui/extensionDownloader.js:195 ../js/ui/shellMountOperation.js:399
#: ../js/ui/status/bluetooth.js:415 ../js/ui/unlockDialog.js:98
#: ../js/ui/status/bluetooth.js:415 ../js/ui/unlockDialog.js:96
#: ../js/ui/userMenu.js:938
msgid "Cancel"
msgstr "Abbrechen"
#: ../js/gdm/loginDialog.js:800
#: ../js/gdm/loginDialog.js:791
msgctxt "button"
msgid "Sign In"
msgstr "Anmelden"
#: ../js/gdm/loginDialog.js:800
#: ../js/gdm/loginDialog.js:791
msgid "Next"
msgstr "Nächstes"
#. Translators: this message is shown below the username entry field
#. to clue the user in on how to login to the local network realm
#: ../js/gdm/loginDialog.js:888
#, c-format
msgid "(e.g., user or %s)"
msgstr "(z.B. Benutzer oder %s)"
#. 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:915 ../js/ui/components/networkAgent.js:260
#: ../js/gdm/loginDialog.js:892 ../js/ui/components/networkAgent.js:260
#: ../js/ui/components/networkAgent.js:278
msgid "Username: "
msgstr "Benutzername:"
#: ../js/gdm/loginDialog.js:1168
#: ../js/gdm/loginDialog.js:1158
msgid "Login Window"
msgstr "Anmeldefenster"
@ -450,53 +453,48 @@ msgstr "Neu starten"
msgid "Power Off"
msgstr "Ausschalten"
#: ../js/gdm/util.js:182
#: ../js/gdm/util.js:247
msgid "Authentication error"
msgstr "Legitimationsfehler"
#. Translators: this message is shown below the password entry field
#. to indicate the user can swipe their finger instead
#: ../js/gdm/util.js:299
#: ../js/gdm/util.js:364
msgid "(or swipe finger)"
msgstr "(oder benutzen Sie den Fingerabdruckleser)"
#: ../js/gdm/util.js:324
#, c-format
msgid "(e.g., user or %s)"
msgstr "(z.B. Benutzer oder %s)"
#: ../js/misc/util.js:94
#: ../js/misc/util.js:97
msgid "Command not found"
msgstr "Befehl nicht gefunden"
#. Replace "Error invoking GLib.shell_parse_argv: " with
#. something nicer
#: ../js/misc/util.js:127
#: ../js/misc/util.js:130
msgid "Could not parse command:"
msgstr "Befehl konnte nicht verarbeitet werden:"
#: ../js/misc/util.js:135
#: ../js/misc/util.js:138
#, c-format
msgid "Execution of '%s' failed:"
msgstr "Ausführung von »%s« ist gescheitert:"
#: ../js/ui/appDisplay.js:348
#: ../js/ui/appDisplay.js:361
msgid "Frequent"
msgstr "Häufig"
#: ../js/ui/appDisplay.js:355
#: ../js/ui/appDisplay.js:368
msgid "All"
msgstr "Alle"
#: ../js/ui/appDisplay.js:913
#: ../js/ui/appDisplay.js:960
msgid "New Window"
msgstr "Neues Fenster"
#: ../js/ui/appDisplay.js:916 ../js/ui/dash.js:284
#: ../js/ui/appDisplay.js:963 ../js/ui/dash.js:284
msgid "Remove from Favorites"
msgstr "Aus Favoriten entfernen"
#: ../js/ui/appDisplay.js:917
#: ../js/ui/appDisplay.js:964
msgid "Add to Favorites"
msgstr "Zu Favoriten hinzufügen"
@ -536,7 +534,7 @@ msgstr "%H\\u2236%M"
# wird nur verwendet, wenn die Anwendung explizit auf 12h-Format eingestellt ist.
# http://linux.die.net/man/3/strftime
#. 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
#: ../js/ui/calendar.js:77
@ -638,35 +636,35 @@ msgid "S"
msgstr "Sa"
#. Translators: Text to show if there are no events
#: ../js/ui/calendar.js:720
#: ../js/ui/calendar.js:735
msgid "Nothing Scheduled"
msgstr "Nichts geplant"
#. Translators: Shown on calendar heading when selected day occurs on current year
#: ../js/ui/calendar.js:736
#: ../js/ui/calendar.js:751
msgctxt "calendar heading"
msgid "%A, %B %d"
msgstr "%A, %d. %B"
#. Translators: Shown on calendar heading when selected day occurs on different year
#: ../js/ui/calendar.js:739
#: ../js/ui/calendar.js:754
msgctxt "calendar heading"
msgid "%A, %B %d, %Y"
msgstr "%a, %d. %B %Y"
#: ../js/ui/calendar.js:749
#: ../js/ui/calendar.js:764
msgid "Today"
msgstr "Heute"
#: ../js/ui/calendar.js:753
#: ../js/ui/calendar.js:768
msgid "Tomorrow"
msgstr "Morgen"
#: ../js/ui/calendar.js:764
#: ../js/ui/calendar.js:779
msgid "This week"
msgstr "Diese Woche"
#: ../js/ui/calendar.js:772
#: ../js/ui/calendar.js:787
msgid "Next week"
msgstr "Nächste Woche"
@ -682,20 +680,20 @@ msgstr "Externes Laufwerk getrennt"
msgid "Removable Devices"
msgstr "Wechseldatenträger"
#: ../js/ui/components/autorunManager.js:593
#: ../js/ui/components/autorunManager.js:594
#, c-format
msgid "Open with %s"
msgstr "Öffnen mit %s"
#: ../js/ui/components/autorunManager.js:619
#: ../js/ui/components/autorunManager.js:620
msgid "Eject"
msgstr "Auswerfen"
#: ../js/ui/components/keyring.js:82 ../js/ui/components/polkitAgent.js:268
#: ../js/ui/components/keyring.js:88 ../js/ui/components/polkitAgent.js:280
msgid "Password:"
msgstr "Passwort:"
#: ../js/ui/components/keyring.js:101
#: ../js/ui/components/keyring.js:107
msgid "Type again:"
msgstr "Erneut eingeben:"
@ -775,15 +773,15 @@ msgstr "Passwort der mobilen Breitbandverbindung"
msgid "A password is required to connect to '%s'."
msgstr "Es wird ein Passwort benötigt, um sich mit »%s« zu verbinden."
#: ../js/ui/components/polkitAgent.js:55
#: ../js/ui/components/polkitAgent.js:54
msgid "Authentication Required"
msgstr "Legitimierung erforderlich"
#: ../js/ui/components/polkitAgent.js:93
#: ../js/ui/components/polkitAgent.js:92
msgid "Administrator"
msgstr "Systemverwalter"
#: ../js/ui/components/polkitAgent.js:165
#: ../js/ui/components/polkitAgent.js:170
msgid "Authenticate"
msgstr "Legitimieren"
@ -791,12 +789,12 @@ msgstr "Legitimieren"
#. * requested authentication was not gained; this can happen
#. * because of an authentication error (like invalid password),
#. * for instance.
#: ../js/ui/components/polkitAgent.js:256 ../js/ui/shellMountOperation.js:383
#: ../js/ui/components/polkitAgent.js:266 ../js/ui/shellMountOperation.js:383
msgid "Sorry, that didn't work. Please try again."
msgstr "Entschuldigung, das hat nicht geklappt. Bitte versuchen Sie es erneut."
#. Translators: this is a filename used for screencast recording
#: ../js/ui/components/recorder.js:48
#: ../js/ui/components/recorder.js:47
#, no-c-format
msgid "Screencast from %d %t"
msgstr "Bildschirmaufzeichnung von %d %t"
@ -1055,26 +1053,26 @@ msgstr "Anwendungen anzeigen"
# Würde ich so übernehmen, oder evtl. »Dock«.
#. Translators: this is the name of the dock/favorites area on
#. the left of the overview
#: ../js/ui/dash.js:435
#: ../js/ui/dash.js:429
msgid "Dash"
msgstr "Dash"
#: ../js/ui/dateMenu.js:91
#: ../js/ui/dateMenu.js:86
msgid "Open Calendar"
msgstr "Kalender öffnen"
#: ../js/ui/dateMenu.js:96
#: ../js/ui/dateMenu.js:90
msgid "Open Clocks"
msgstr "Uhren öffnen"
#: ../js/ui/dateMenu.js:105
#: ../js/ui/dateMenu.js:97
msgid "Date & Time Settings"
msgstr "Einstellungen für Datum und Uhrzeit"
#. 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").
#.
#: ../js/ui/dateMenu.js:215
#: ../js/ui/dateMenu.js:208
msgid "%A %B %e, %Y"
msgstr "%A, %e. %B %Y"
@ -1181,56 +1179,56 @@ msgstr "Installieren"
msgid "Download and install '%s' from extensions.gnome.org?"
msgstr "»%s« von extensions.gnome.org herunterladen und installieren?"
#: ../js/ui/keyboard.js:619 ../js/ui/status/keyboard.js:314
#: ../js/ui/keyboard.js:619 ../js/ui/status/keyboard.js:333
#: ../js/ui/status/power.js:211
msgid "Keyboard"
msgstr "Tastatur"
#: ../js/ui/lookingGlass.js:693
#: ../js/ui/lookingGlass.js:689
msgid "No extensions installed"
msgstr "Keine Erweiterungen installiert"
#. Translators: argument is an extension UUID.
#: ../js/ui/lookingGlass.js:747
#: ../js/ui/lookingGlass.js:743
#, c-format
msgid "%s has not emitted any errors."
msgstr "%s hat keine Fehler ausgegeben."
#: ../js/ui/lookingGlass.js:753
#: ../js/ui/lookingGlass.js:749
msgid "Hide Errors"
msgstr "Fehler verbergen"
#: ../js/ui/lookingGlass.js:757 ../js/ui/lookingGlass.js:817
#: ../js/ui/lookingGlass.js:753 ../js/ui/lookingGlass.js:813
msgid "Show Errors"
msgstr "Fehler anzeigen"
#: ../js/ui/lookingGlass.js:766
#: ../js/ui/lookingGlass.js:762
msgid "Enabled"
msgstr "Aktiviert"
#. translators:
#. * The device has been disabled
#: ../js/ui/lookingGlass.js:769 ../src/gvc/gvc-mixer-control.c:1830
#: ../js/ui/lookingGlass.js:765 ../src/gvc/gvc-mixer-control.c:1830
msgid "Disabled"
msgstr "Deaktiviert"
#: ../js/ui/lookingGlass.js:771
#: ../js/ui/lookingGlass.js:767
msgid "Error"
msgstr "Fehler"
#: ../js/ui/lookingGlass.js:773
#: ../js/ui/lookingGlass.js:769
msgid "Out of date"
msgstr "Veraltet"
#: ../js/ui/lookingGlass.js:775
#: ../js/ui/lookingGlass.js:771
msgid "Downloading"
msgstr "Herunterladen"
#: ../js/ui/lookingGlass.js:799
#: ../js/ui/lookingGlass.js:795
msgid "View Source"
msgstr "Quelle zeigen"
#: ../js/ui/lookingGlass.js:808
#: ../js/ui/lookingGlass.js:804
msgid "Web Page"
msgstr "Webseite"
@ -1250,35 +1248,35 @@ msgstr "Nachrichten leeren"
msgid "Notification Settings"
msgstr "Benachrichtigungseinstellungen"
#: ../js/ui/messageTray.js:1707
#: ../js/ui/messageTray.js:1711
msgid "No Messages"
msgstr "Keine Nachrichten"
#: ../js/ui/messageTray.js:1782
#: ../js/ui/messageTray.js:1784
msgid "Message Tray"
msgstr "Benachrichtigungsfeld"
#: ../js/ui/messageTray.js:2869
#: ../js/ui/messageTray.js:2811
msgid "System Information"
msgstr "Systeminformationen"
#: ../js/ui/notificationDaemon.js:629 ../src/shell-app.c:374
#: ../js/ui/notificationDaemon.js:629 ../src/shell-app.c:378
msgctxt "program"
msgid "Unknown"
msgstr "Unbekannt"
#: ../js/ui/overviewControls.js:463 ../js/ui/screenShield.js:153
#: ../js/ui/overviewControls.js:474 ../js/ui/screenShield.js:150
#, c-format
msgid "%d new message"
msgid_plural "%d new messages"
msgstr[0] "%d neue Nachricht"
msgstr[1] "%d neue Nachrichten"
#: ../js/ui/overview.js:84
#: ../js/ui/overview.js:82
msgid "Undo"
msgstr "Rückgängig"
#: ../js/ui/overview.js:131
#: ../js/ui/overview.js:127
msgid "Overview"
msgstr "Übersicht"
@ -1286,21 +1284,21 @@ msgstr "Übersicht"
#. in the search entry when no search is
#. active; it should not exceed ~30
#. characters.
#: ../js/ui/overview.js:287
#: ../js/ui/overview.js:258
msgid "Type to search…"
msgstr "Suchbegriff eingeben …"
#: ../js/ui/panel.js:612
#: ../js/ui/panel.js:642
msgid "Quit"
msgstr "Beenden"
#. Translators: If there is no suitable word for "Activities"
#. in your language, you can use the word for "Overview".
#: ../js/ui/panel.js:636
#: ../js/ui/panel.js:693
msgid "Activities"
msgstr "Aktivitäten"
#: ../js/ui/panel.js:933
#: ../js/ui/panel.js:989
msgid "Top Bar"
msgstr "Oberes Panel"
@ -1309,15 +1307,15 @@ msgstr "Oberes Panel"
#. "ON" and "OFF") or "toggle-switch-intl" (for toggle
#. switches containing "◯" and "|"). Other values will
#. simply result in invisible toggle switches.
#: ../js/ui/popupMenu.js:727
#: ../js/ui/popupMenu.js:738
msgid "toggle-switch-us"
msgstr "toggle-switch-intl"
#: ../js/ui/runDialog.js:73
#: ../js/ui/runDialog.js:74
msgid "Enter a Command"
msgstr "Bitte geben Sie einen Befehl ein"
#: ../js/ui/runDialog.js:109
#: ../js/ui/runDialog.js:110
msgid "Close"
msgstr "Schließen"
@ -1326,22 +1324,22 @@ msgstr "Schließen"
# %B - ausgeschriebener Name des Monats, abhängig von der gesetzten Umgebung
#. Translators: This is a time format for a date in
#. long format
#: ../js/ui/screenShield.js:90
#: ../js/ui/screenShield.js:87
msgid "%A, %B %d"
msgstr "%A, %d. %B"
#: ../js/ui/screenShield.js:155
#: ../js/ui/screenShield.js:152
#, c-format
msgid "%d new notification"
msgid_plural "%d new notifications"
msgstr[0] "%d neue Benachrichtigung"
msgstr[1] "%d neue Benachrichtigungen"
#: ../js/ui/screenShield.js:442 ../js/ui/userMenu.js:807
#: ../js/ui/screenShield.js:449 ../js/ui/userMenu.js:807
msgid "Lock"
msgstr "Sperren"
#: ../js/ui/screenShield.js:639
#: ../js/ui/screenShield.js:652
msgid "GNOME needs to lock the screen"
msgstr "GNOME muss den Bildschirm sperren"
@ -1352,35 +1350,35 @@ msgstr "GNOME muss den Bildschirm sperren"
#.
#. XXX: another option is to kick the user into the gdm login
#. screen, where we're not affected by grabs
#: ../js/ui/screenShield.js:758 ../js/ui/screenShield.js:1169
#: ../js/ui/screenShield.js:773 ../js/ui/screenShield.js:1213
msgid "Unable to lock"
msgstr "Sperrung fehlgeschlagen"
#: ../js/ui/screenShield.js:759 ../js/ui/screenShield.js:1170
#: ../js/ui/screenShield.js:774 ../js/ui/screenShield.js:1214
msgid "Lock was blocked by an application"
msgstr "Sperrung wurde von einer Anwendung blockiert"
#: ../js/ui/searchDisplay.js:431
#: ../js/ui/searchDisplay.js:445
msgid "Searching…"
msgstr "Suche läuft …"
#: ../js/ui/searchDisplay.js:475
#: ../js/ui/searchDisplay.js:489
msgid "No results."
msgstr "Keine Ergebnisse."
#: ../js/ui/shellEntry.js:29
#: ../js/ui/shellEntry.js:27
msgid "Copy"
msgstr "Kopieren"
#: ../js/ui/shellEntry.js:34
#: ../js/ui/shellEntry.js:32
msgid "Paste"
msgstr "Einfügen"
#: ../js/ui/shellEntry.js:106
#: ../js/ui/shellEntry.js:99
msgid "Show Text"
msgstr "Text anzeigen"
#: ../js/ui/shellEntry.js:108
#: ../js/ui/shellEntry.js:101
msgid "Hide Text"
msgstr "Text verbergen"
@ -1392,7 +1390,7 @@ msgstr "Passwort"
msgid "Remember Password"
msgstr "An Passwort erinnern"
#: ../js/ui/shellMountOperation.js:403 ../js/ui/unlockDialog.js:112
#: ../js/ui/shellMountOperation.js:403 ../js/ui/unlockDialog.js:109
msgid "Unlock"
msgstr "Entsperren"
@ -1447,7 +1445,7 @@ msgstr "Große Schrift"
#: ../js/ui/status/bluetooth.js:28 ../js/ui/status/bluetooth.js:32
#: ../js/ui/status/bluetooth.js:289 ../js/ui/status/bluetooth.js:321
#: ../js/ui/status/bluetooth.js:357 ../js/ui/status/bluetooth.js:388
#: ../js/ui/status/network.js:826
#: ../js/ui/status/network.js:739
msgid "Bluetooth"
msgstr "Bluetooth"
@ -1468,7 +1466,7 @@ msgid "Bluetooth Settings"
msgstr "Bluetooth-Einstellungen"
#. TRANSLATORS: this means that bluetooth was disabled by hardware rfkill
#: ../js/ui/status/bluetooth.js:104 ../js/ui/status/network.js:178
#: ../js/ui/status/bluetooth.js:104 ../js/ui/status/network.js:142
msgid "hardware disabled"
msgstr "Hardware deaktiviert"
@ -1476,12 +1474,12 @@ msgstr "Hardware deaktiviert"
msgid "Connection"
msgstr "Verbindung"
#: ../js/ui/status/bluetooth.js:208 ../js/ui/status/network.js:460
#: ../js/ui/status/bluetooth.js:208 ../js/ui/status/network.js:404
msgid "disconnecting..."
msgstr "Verbindungsabbau …"
#: ../js/ui/status/bluetooth.js:221 ../js/ui/status/network.js:466
#: ../js/ui/status/network.js:1546
#: ../js/ui/status/bluetooth.js:221 ../js/ui/status/network.js:410
#: ../js/ui/status/network.js:1343
msgid "connecting..."
msgstr "Verbindungsaufbau …"
@ -1536,7 +1534,8 @@ msgstr "Gerät »%s« möchte mit diesem Rechner gekoppelt werden"
#: ../js/ui/status/bluetooth.js:366
#, c-format
msgid "Please confirm whether the PIN '%06d' matches the one on the device."
msgid ""
"Please confirm whether the Passkey '%06d' matches the one on the device."
msgstr ""
"Bitte bestätigen Sie, ob die PIN »%06d« mit der des Gerätes übereinstimmt."
@ -1562,11 +1561,11 @@ msgstr "Bitte geben Sie die auf dem Gerät angezeigte PIN ein."
msgid "OK"
msgstr "OK"
#: ../js/ui/status/keyboard.js:368
#: ../js/ui/status/keyboard.js:396
msgid "Show Keyboard Layout"
msgstr "Tastaturbelegung zeigen"
#: ../js/ui/status/keyboard.js:373
#: ../js/ui/status/keyboard.js:401
msgid "Region & Language Settings"
msgstr "Einstellungen für Region und Sprache"
@ -1574,117 +1573,91 @@ msgstr "Einstellungen für Region und Sprache"
msgid "Volume, network, battery"
msgstr "Lautstärke, Netzwerk, Batterie"
#: ../js/ui/status/network.js:104
#: ../js/ui/status/network.js:75
msgid "<unknown>"
msgstr "<Unbekannt>"
#: ../js/ui/status/network.js:127
msgid "Wi-Fi"
msgstr "WLAN"
#. Translators: this indicates that wireless or wwan is disabled by hardware killswitch
#: ../js/ui/status/network.js:200
#: ../js/ui/status/network.js:164
msgid "disabled"
msgstr "Deaktiviert"
#. Translators: this is for network devices that are physically present but are not
#. under NetworkManager's control (and thus cannot be used in the menu)
#: ../js/ui/status/network.js:458
#: ../js/ui/status/network.js:402
msgid "unmanaged"
msgstr "nicht verwaltet"
#. Translators: this is for network connections that require some kind of key or password
#: ../js/ui/status/network.js:469 ../js/ui/status/network.js:1549
#: ../js/ui/status/network.js:413 ../js/ui/status/network.js:1346
msgid "authentication required"
msgstr "Legitimierung erforderlich"
#. Translators: this is for devices that require some kind of firmware or kernel
#. module, which is missing
#: ../js/ui/status/network.js:479
#: ../js/ui/status/network.js:423
msgid "firmware missing"
msgstr "Firmware fehlt"
#. Translators: this is for wired network devices that are physically disconnected
#: ../js/ui/status/network.js:486
#: ../js/ui/status/network.js:430
msgid "cable unplugged"
msgstr "Kabel nicht angeschlossen"
#. Translators: this is for a network device that cannot be activated (for example it
#. is disabled by rfkill, or it has no coverage
#: ../js/ui/status/network.js:491
#: ../js/ui/status/network.js:435
msgid "unavailable"
msgstr "nicht verfügbar"
#: ../js/ui/status/network.js:493 ../js/ui/status/network.js:1551
#: ../js/ui/status/network.js:437 ../js/ui/status/network.js:1348
msgid "connection failed"
msgstr "Verbindung gescheitert"
#: ../js/ui/status/network.js:552 ../js/ui/status/network.js:1435
#: ../js/ui/status/network.js:1627
#: ../js/ui/status/network.js:490 ../js/ui/status/network.js:1236
#: ../js/ui/status/network.js:1424
msgid "More…"
msgstr "Mehr …"
#. TRANSLATORS: this is the indication that a connection for another logged in user is active,
#. and we cannot access its settings (including the name)
#: ../js/ui/status/network.js:588 ../js/ui/status/network.js:1365
#: ../js/ui/status/network.js:518 ../js/ui/status/network.js:1191
msgid "Connected (private)"
msgstr "Verbunden (privat)"
#: ../js/ui/status/network.js:667
#: ../js/ui/status/network.js:597
msgid "Wired"
msgstr "Kabelgebunden"
#: ../js/ui/status/network.js:668
msgid "Auto Ethernet"
msgstr "Ethernet (automatisch)"
#: ../js/ui/status/network.js:695
#: ../js/ui/status/network.js:611
msgid "Mobile broadband"
msgstr "Mobiles Breitband"
#: ../js/ui/status/network.js:728
msgid "Auto broadband"
msgstr "Mobiles Breitband (automatisch)"
#: ../js/ui/status/network.js:731
msgid "Auto dial-up"
msgstr "Einwählverbindung (automatisch)"
#. TRANSLATORS: this the automatic wireless connection name (including the network name)
#: ../js/ui/status/network.js:861 ../js/ui/status/network.js:1382
#, c-format
msgid "Auto %s"
msgstr "%s (automatisch)"
#: ../js/ui/status/network.js:863
msgid "Auto bluetooth"
msgstr "Bluetooth (automatisch)"
#: ../js/ui/status/network.js:1384
msgid "Auto wireless"
msgstr "Drahtlos (automatisch)"
#: ../js/ui/status/network.js:1729
#: ../js/ui/status/network.js:1522
msgid "Enable networking"
msgstr "Netzwerk aktivieren"
#: ../js/ui/status/network.js:1771
msgid "Wi-Fi"
msgstr "WLAN"
#: ../js/ui/status/network.js:1790
#: ../js/ui/status/network.js:1583
msgid "Network Settings"
msgstr "Netzwerkeinstellungen"
#: ../js/ui/status/network.js:1807
#: ../js/ui/status/network.js:1600
msgid "Network Manager"
msgstr "Netzwerk-Verwaltung"
#: ../js/ui/status/network.js:1897
#: ../js/ui/status/network.js:1690
msgid "Connection failed"
msgstr "Verbindung gescheitert"
#: ../js/ui/status/network.js:1898
#: ../js/ui/status/network.js:1691
msgid "Activation of network connection failed"
msgstr "Aktivierung der Netzwerkverbindung ist gescheitert"
#: ../js/ui/status/network.js:2276
#: ../js/ui/status/network.js:2047
msgid "Networking is disabled"
msgstr "Netzwerk ist deaktiviert"
@ -1798,11 +1771,11 @@ msgstr "Lautstärke"
msgid "Microphone"
msgstr "Mikrofon"
#: ../js/ui/unlockDialog.js:123
#: ../js/ui/unlockDialog.js:120
msgid "Log in as another user"
msgstr "Als anderer Benutzer anmelden"
#: ../js/ui/unlockDialog.js:149
#: ../js/ui/unlockDialog.js:141
msgid "Unlock Window"
msgstr "Fenster entsperren"
@ -1928,37 +1901,37 @@ msgid_plural "%u Inputs"
msgstr[0] "%u Eingang"
msgstr[1] "%u Eingänge"
#: ../src/gvc/gvc-mixer-control.c:2371
#: ../src/gvc/gvc-mixer-control.c:2373
msgid "System Sounds"
msgstr "Systemklänge"
#: ../src/main.c:347
#: ../src/main.c:372
msgid "Print version"
msgstr "Version ausgeben"
#: ../src/main.c:353
#: ../src/main.c:378
msgid "Mode used by GDM for login screen"
msgstr "Der durch GDM im Anmeldefenster verwendete Modus"
#: ../src/main.c:359
#: ../src/main.c:384
msgid "Use a specific mode, e.g. \"gdm\" for login screen"
msgstr ""
"Einen spezifischen Modus nutzen, wie z.B. »gdm« für den Anmeldebildschirm"
#: ../src/main.c:365
#: ../src/main.c:390
msgid "List possible modes"
msgstr "Die möglichen Modi auflisten"
#: ../src/shell-app.c:622
#: ../src/shell-app.c:626
#, c-format
msgid "Failed to launch '%s'"
msgstr "»%s« konnte nicht gestartet werden"
#: ../src/shell-keyring-prompt.c:708
#: ../src/shell-keyring-prompt.c:714
msgid "Passwords do not match."
msgstr "Passwörter stimmen nicht überein."
#: ../src/shell-keyring-prompt.c:716
#: ../src/shell-keyring-prompt.c:722
msgid "Password cannot be blank"
msgstr "Das Passwort darf nicht leer sein"
@ -1966,6 +1939,40 @@ msgstr "Das Passwort darf nicht leer sein"
msgid "Authentication dialog was dismissed by the user"
msgstr "Der Dialog zur Legitimierung wurde vom Benutzer geschlossen"
#~ msgid "Whether to collect stats about applications usage"
#~ msgstr ""
#~ "Legt fest, ob Statistiken über Anwendungsnutzung erfasst werden sollen"
#~ msgid ""
#~ "The shell normally monitors active applications in order to present the "
#~ "most used ones (e.g. in launchers). While this data will be kept private, "
#~ "you may want to disable this for privacy reasons. Please note that doing "
#~ "so won't remove already saved data."
#~ msgstr ""
#~ "Die Shell überwacht normalerweise aktive Anwendungen, wobei die "
#~ "meistgenutzten zuerst erfasst werden (z.B. in Anwendungsstartern). Zwar "
#~ "werden diese Daten privat gespeichert, doch möglicherweise wollen Sie "
#~ "dies deaktivieren, um Ihre Privatsphäre zu schützen. Bitte beachten Sie, "
#~ "dass bereits gespeicherte Daten hiervon nicht beeinflusst werden."
#~ msgid "Auto Ethernet"
#~ msgstr "Ethernet (automatisch)"
#~ msgid "Auto broadband"
#~ msgstr "Mobiles Breitband (automatisch)"
#~ msgid "Auto dial-up"
#~ msgstr "Einwählverbindung (automatisch)"
#~ msgid "Auto %s"
#~ msgstr "%s (automatisch)"
#~ msgid "Auto bluetooth"
#~ msgstr "Bluetooth (automatisch)"
#~ msgid "Auto wireless"
#~ msgstr "Drahtlos (automatisch)"
#~ msgctxt "title"
#~ msgid "Sign In"
#~ msgstr "Anmelden"

239
po/el.po
View File

@ -5,8 +5,8 @@ msgstr ""
"Project-Id-Version: gnome-shell.po.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: 2013-03-02 23:02+0000\n"
"PO-Revision-Date: 2013-03-03 13:22+0300\n"
"POT-Creation-Date: 2013-04-19 02:48+0000\n"
"PO-Revision-Date: 2013-04-25 08:11+0300\n"
"Last-Translator: Dimitris Spingos (Δημήτρης Σπίγγος) <dmtrs32@gmail.com>\n"
"Language-Team: team@gnome.gr\n"
"Language: el\n"
@ -40,10 +40,14 @@ msgid "Focus the active notification"
msgstr "Εστίαση στην ενεργή ειδοποίηση"
#: ../data/50-gnome-shell-system.xml.in.h:4
msgid "Show the overview"
msgstr "Εμφάνιση της επισκόπησης"
#: ../data/50-gnome-shell-system.xml.in.h:5
msgid "Show all applications"
msgstr "Προβολή όλων των εφαρμογών"
#: ../data/50-gnome-shell-system.xml.in.h:5
#: ../data/50-gnome-shell-system.xml.in.h:6
msgid "Open the application menu"
msgstr "Άνοιγμα του μενού εφαρμογών"
@ -223,45 +227,55 @@ msgstr ""
"επισκόπησης ενεργειών."
#: ../data/org.gnome.shell.gschema.xml.in.in.h:25
#| msgid "Keybinding to open the \"Show Applications\" view"
msgid "Keybinding to open the overview"
msgstr "Συνδυασμός πλήκτρων για το άνοιγμα της επισκόπησης"
#: ../data/org.gnome.shell.gschema.xml.in.in.h:26
#| msgid "Keybinding to open the \"Show Applications\" view"
msgid "Keybinding to open the Activities Overview."
msgstr "Συνδυασμός πλήκτρων για το άνοιγμα της προβολής ενέργειες."
#: ../data/org.gnome.shell.gschema.xml.in.in.h:27
msgid "Keybinding to toggle the visibility of the message tray"
msgstr "Συνδυασμός πλήκτρων για την ορατότητα της περιοχής ειδοποιήσεων"
#: ../data/org.gnome.shell.gschema.xml.in.in.h:26
#: ../data/org.gnome.shell.gschema.xml.in.in.h:28
msgid "Keybinding to toggle the visibility of the message tray."
msgstr "Συνδυασμός πλήκτρων για την ορατότητα της περιοχής ειδοποιήσεων."
#: ../data/org.gnome.shell.gschema.xml.in.in.h:27
#: ../data/org.gnome.shell.gschema.xml.in.in.h:29
msgid "Keybinding to focus the active notification"
msgstr "Ο συνδυασμός πλήκτρων για εστίαση της ενεργής ειδοποίησης"
#: ../data/org.gnome.shell.gschema.xml.in.in.h:28
#: ../data/org.gnome.shell.gschema.xml.in.in.h:30
msgid "Keybinding to focus the active notification."
msgstr "Ο συνδυασμός πλήκτρων για εστίαση της ενεργής ειδοποίησης."
#: ../data/org.gnome.shell.gschema.xml.in.in.h:29
#: ../data/org.gnome.shell.gschema.xml.in.in.h:31
msgid "Keybinding to toggle the screen recorder"
msgstr "Συνδυασμός πλήκτρων για την εναλλαγή της μαγνητοσκόπησης οθόνης"
#: ../data/org.gnome.shell.gschema.xml.in.in.h:30
#: ../data/org.gnome.shell.gschema.xml.in.in.h:32
msgid "Keybinding to start/stop the builtin screen recorder."
msgstr ""
"Συνδυασμός πλήκτρων για το άνοιγμα/κλείσιμο της ενσωματωμένης "
"μαγνητοσκόπησης οθόνης."
#: ../data/org.gnome.shell.gschema.xml.in.in.h:31
#: ../data/org.gnome.shell.gschema.xml.in.in.h:33
msgid "Which keyboard to use"
msgstr "Ποιο πληκτρολόγιο θα χρησιμοποιηθεί"
#: ../data/org.gnome.shell.gschema.xml.in.in.h:32
#: ../data/org.gnome.shell.gschema.xml.in.in.h:34
msgid "The type of keyboard to use."
msgstr "Ο τύπος του πληκτρολογίου που θα χρησιμοποιηθεί."
#: ../data/org.gnome.shell.gschema.xml.in.in.h:33
#: ../data/org.gnome.shell.gschema.xml.in.in.h:35
msgid "Framerate used for recording screencasts."
msgstr ""
"Ο ρυθμός καρέ που θα χρησιμοποιηθεί για την καταγραφή του βίντεο οθόνης."
#: ../data/org.gnome.shell.gschema.xml.in.in.h:34
#: ../data/org.gnome.shell.gschema.xml.in.in.h:36
msgid ""
"The framerate of the resulting screencast recordered by GNOME Shell's "
"screencast recorder in frames-per-second."
@ -269,13 +283,13 @@ msgstr ""
"Ο ρυθμός καρέ του στιγμιότυπου που παράγεται από τον εγγραφέα βίντεο οθόνης "
"του GNOME Shell σε καρέ ανά δευτερόλεπτο."
#: ../data/org.gnome.shell.gschema.xml.in.in.h:35
#: ../data/org.gnome.shell.gschema.xml.in.in.h:37
msgid "The gstreamer pipeline used to encode the screencast"
msgstr ""
"Ο δίαυλος του gstreamer που χρησιμοποιήθηκε για την κωδικοποίηση του βίντεο "
"οθόνης"
#: ../data/org.gnome.shell.gschema.xml.in.in.h:37
#: ../data/org.gnome.shell.gschema.xml.in.in.h:39
#, no-c-format
msgid ""
"Sets the GStreamer pipeline used to encode recordings. It follows the syntax "
@ -303,12 +317,12 @@ msgstr ""
"χρησιμοποιείται ως παράδειγμα για το πιθανό βέλτιστο αριθμό πυρήνων του "
"συστήματος."
#: ../data/org.gnome.shell.gschema.xml.in.in.h:38
#: ../data/org.gnome.shell.gschema.xml.in.in.h:40
msgid "File extension used for storing the screencast"
msgstr ""
"Επέκταση αρχείου που θα χρησιμοποιηθεί για την αποθήκευση του βίντεο οθόνης"
#: ../data/org.gnome.shell.gschema.xml.in.in.h:39
#: ../data/org.gnome.shell.gschema.xml.in.in.h:41
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 "
@ -318,11 +332,11 @@ msgstr ""
"βασισμένο στην τρέχουσα ημερομηνία και θα χρησιμοποιεί αυτή την επέκταση. Θα "
"πρέπει να αλλάζει όταν γίνεται εγγραφή σε διαφορετικό πρότυπο περιέκτη."
#: ../data/org.gnome.shell.gschema.xml.in.in.h:40
#: ../data/org.gnome.shell.gschema.xml.in.in.h:42
msgid "The application icon mode."
msgstr "Η κατάσταση εικονιδίου εφαρμογής."
#: ../data/org.gnome.shell.gschema.xml.in.in.h:41
#: ../data/org.gnome.shell.gschema.xml.in.in.h:43
msgid ""
"Configures how the windows are shown in the switcher. Valid possibilities "
"are 'thumbnail-only' (shows a thumbnail of the window), 'app-icon-"
@ -333,22 +347,22 @@ msgstr ""
"παραθύρου), 'app-icon-only' (εμφανίζει μόνο το εικονίδιο της εφαρμογής) ή "
"'both' - και τα δύο."
#: ../data/org.gnome.shell.gschema.xml.in.in.h:42
#: ../data/org.gnome.shell.gschema.xml.in.in.h:44
msgid "Attach modal dialog to the parent window"
msgstr "Προσάρτηση αναγκαστικού διαλόγου στο γονικό παράθυρο"
#: ../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.mutter when running GNOME Shell."
msgstr ""
"Αυτό το κλειδί υπερισχύει του κλειδιού στο org.gnome.mutter όταν εκτελείται "
"το κέλυφος GNOME."
#: ../data/org.gnome.shell.gschema.xml.in.in.h:44
#: ../data/org.gnome.shell.gschema.xml.in.in.h:46
msgid "Arrangement of buttons on the titlebar"
msgstr "Διάταξη των κουμπιών στη γραμμή τίτλου"
#: ../data/org.gnome.shell.gschema.xml.in.in.h:45
#: ../data/org.gnome.shell.gschema.xml.in.in.h:47
msgid ""
"This key overrides the key in org.gnome.desktop.wm.preferences when running "
"GNOME Shell."
@ -356,17 +370,17 @@ msgstr ""
"Αυτό το κλειδί υπερισχύει του κλειδιού στο org.gnome.desktop.wm.preferences "
"όταν εκτελείται το κέλυφος GNOME."
#: ../data/org.gnome.shell.gschema.xml.in.in.h:46
#: ../data/org.gnome.shell.gschema.xml.in.in.h:48
msgid "Enable edge tiling when dropping windows on screen edges"
msgstr ""
"Ενεργοποίηση της παράθεσης άκρων όταν αποθέτετε παράθυρα στις άκρες της "
"οθόνης"
#: ../data/org.gnome.shell.gschema.xml.in.in.h:47
#: ../data/org.gnome.shell.gschema.xml.in.in.h:49
msgid "Workspaces are managed dynamically"
msgstr "Οι χώροι εργασίας διαχειρίζονται δυναμικά"
#: ../data/org.gnome.shell.gschema.xml.in.in.h:48
#: ../data/org.gnome.shell.gschema.xml.in.in.h:50
msgid "Workspaces only on primary monitor"
msgstr "Χώροι εργασίας μόνο στην κύρια οθόνη"
@ -388,43 +402,42 @@ msgstr ""
"πολλαπλών επιλογών."
#: ../js/gdm/loginDialog.js:405
#| msgid "Session..."
msgid "Session…"
msgstr "Συνεδρία…"
#. 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:629
#: ../js/gdm/loginDialog.js:630
msgid "Not listed?"
msgstr "Δεν είστε στη λίστα;"
#: ../js/gdm/loginDialog.js:783 ../js/ui/components/networkAgent.js:137
#: ../js/ui/components/polkitAgent.js:162 ../js/ui/endSessionDialog.js:375
#: ../js/gdm/loginDialog.js:787 ../js/ui/components/networkAgent.js:137
#: ../js/ui/components/polkitAgent.js:162 ../js/ui/endSessionDialog.js:376
#: ../js/ui/extensionDownloader.js:195 ../js/ui/shellMountOperation.js:399
#: ../js/ui/status/bluetooth.js:415 ../js/ui/unlockDialog.js:126
#: ../js/ui/userMenu.js:932
#: ../js/ui/status/bluetooth.js:415 ../js/ui/unlockDialog.js:100
#: ../js/ui/userMenu.js:938
msgid "Cancel"
msgstr "Ακύρωση"
#: ../js/gdm/loginDialog.js:799
#: ../js/gdm/loginDialog.js:803
msgctxt "button"
msgid "Sign In"
msgstr "Σύνδεση"
#: ../js/gdm/loginDialog.js:799
#: ../js/gdm/loginDialog.js:803
msgid "Next"
msgstr "Επόμενο"
#. 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:904 ../js/ui/components/networkAgent.js:260
#: ../js/gdm/loginDialog.js:918 ../js/ui/components/networkAgent.js:260
#: ../js/ui/components/networkAgent.js:278
msgid "Username: "
msgstr "Όνομα χρήστη: "
#: ../js/gdm/loginDialog.js:1157
#: ../js/gdm/loginDialog.js:1174
msgid "Login Window"
msgstr "Παράθυρο σύνδεσης"
@ -433,8 +446,8 @@ msgstr "Παράθυρο σύνδεσης"
msgid "Power"
msgstr "Ενέργεια"
#: ../js/gdm/powerMenu.js:93 ../js/ui/userMenu.js:694 ../js/ui/userMenu.js:698
#: ../js/ui/userMenu.js:814
#: ../js/gdm/powerMenu.js:93 ../js/ui/userMenu.js:696 ../js/ui/userMenu.js:700
#: ../js/ui/userMenu.js:816
msgid "Suspend"
msgstr "Αναστολή"
@ -442,58 +455,58 @@ msgstr "Αναστολή"
msgid "Restart"
msgstr "Επανεκκίνηση"
#: ../js/gdm/powerMenu.js:103 ../js/ui/userMenu.js:696
#: ../js/ui/userMenu.js:698 ../js/ui/userMenu.js:813 ../js/ui/userMenu.js:936
#: ../js/gdm/powerMenu.js:103 ../js/ui/userMenu.js:698
#: ../js/ui/userMenu.js:700 ../js/ui/userMenu.js:815 ../js/ui/userMenu.js:942
msgid "Power Off"
msgstr "Απενεργοποίηση"
#: ../js/gdm/util.js:182
#: ../js/gdm/util.js:249
msgid "Authentication error"
msgstr "Σφάλμα πιστοποίησης"
#. Translators: this message is shown below the password entry field
#. to indicate the user can swipe their finger instead
#: ../js/gdm/util.js:299
#: ../js/gdm/util.js:366
msgid "(or swipe finger)"
msgstr "(ή περάστε το δάκτυλο σας)"
#: ../js/gdm/util.js:324
#: ../js/gdm/util.js:391
#, c-format
msgid "(e.g., user or %s)"
msgstr "(π.χ χρήστης ή %s)"
#: ../js/misc/util.js:94
#: ../js/misc/util.js:97
msgid "Command not found"
msgstr "Δε βρέθηκε η εντολή"
#. Replace "Error invoking GLib.shell_parse_argv: " with
#. something nicer
#: ../js/misc/util.js:127
#: ../js/misc/util.js:130
msgid "Could not parse command:"
msgstr "Δεν ήταν δυνατό να επεξεργαστεί η εντολή:"
#: ../js/misc/util.js:135
#: ../js/misc/util.js:138
#, c-format
msgid "Execution of '%s' failed:"
msgstr "Η εκτέλεση του '%s' απέτυχε:"
#: ../js/ui/appDisplay.js:348
#: ../js/ui/appDisplay.js:349
msgid "Frequent"
msgstr "Συχνό"
#: ../js/ui/appDisplay.js:355
#: ../js/ui/appDisplay.js:356
msgid "All"
msgstr "Όλα"
#: ../js/ui/appDisplay.js:913
#: ../js/ui/appDisplay.js:914
msgid "New Window"
msgstr "Νέο παράθυρο"
#: ../js/ui/appDisplay.js:916 ../js/ui/dash.js:284
#: ../js/ui/appDisplay.js:917 ../js/ui/dash.js:284
msgid "Remove from Favorites"
msgstr "Αφαίρεση από τα αγαπημένα"
#: ../js/ui/appDisplay.js:917
#: ../js/ui/appDisplay.js:918
msgid "Add to Favorites"
msgstr "Προσθήκη στα αγαπημένα"
@ -507,7 +520,7 @@ msgstr "Tο %s προστέθηκε στα αγαπημένα σας."
msgid "%s has been removed from your favorites."
msgstr "Tο %s αφαιρέθηκε από τα αγαπημένα σας."
#: ../js/ui/backgroundMenu.js:19 ../js/ui/userMenu.js:787
#: ../js/ui/backgroundMenu.js:19 ../js/ui/userMenu.js:789
msgid "Settings"
msgstr "Ρυθμίσεις"
@ -530,7 +543,7 @@ msgctxt "event list time"
msgid "%H\\u2236%M"
msgstr "%Ω\\u2236%Λ"
#. 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
#: ../js/ui/calendar.js:77
@ -632,35 +645,35 @@ msgid "S"
msgstr "Σ"
#. Translators: Text to show if there are no events
#: ../js/ui/calendar.js:692
#: ../js/ui/calendar.js:720
msgid "Nothing Scheduled"
msgstr "Τίποτα προγραμματισμένο"
#. Translators: Shown on calendar heading when selected day occurs on current year
#: ../js/ui/calendar.js:708
#: ../js/ui/calendar.js:736
msgctxt "calendar heading"
msgid "%A, %B %d"
msgstr "%A, %B %d"
#. Translators: Shown on calendar heading when selected day occurs on different year
#: ../js/ui/calendar.js:711
#: ../js/ui/calendar.js:739
msgctxt "calendar heading"
msgid "%A, %B %d, %Y"
msgstr "%A, %B %d, %Y"
#: ../js/ui/calendar.js:721
#: ../js/ui/calendar.js:749
msgid "Today"
msgstr "Σήμερα"
#: ../js/ui/calendar.js:725
#: ../js/ui/calendar.js:753
msgid "Tomorrow"
msgstr "Αύριο"
#: ../js/ui/calendar.js:736
#: ../js/ui/calendar.js:764
msgid "This week"
msgstr "Αυτή η εβδομάδα"
#: ../js/ui/calendar.js:744
#: ../js/ui/calendar.js:772
msgid "Next week"
msgstr "Επόμενη εβδομάδα"
@ -676,12 +689,12 @@ msgstr "Αποσυνδέθηκε εξωτερικός δίσκος"
msgid "Removable Devices"
msgstr "Αφαιρούμενες συσκευές"
#: ../js/ui/components/autorunManager.js:593
#: ../js/ui/components/autorunManager.js:594
#, c-format
msgid "Open with %s"
msgstr "Άνοιγμα με %s"
#: ../js/ui/components/autorunManager.js:619
#: ../js/ui/components/autorunManager.js:620
msgid "Eject"
msgstr "Εξαγωγή"
@ -790,7 +803,7 @@ msgid "Sorry, that didn't work. Please try again."
msgstr "Συγνώμη, αυτό δεν λειτούργησε. Παρακαλώ προσπαθήστε ξανά."
#. Translators: this is a filename used for screencast recording
#: ../js/ui/components/recorder.js:48
#: ../js/ui/components/recorder.js:47
#, no-c-format
msgid "Screencast from %d %t"
msgstr "Βίντεο οθόνης από %d %t"
@ -1037,7 +1050,7 @@ msgstr "Προβολή λογαριασμού"
msgid "Unknown reason"
msgstr "Άγνωστος λόγος"
#: ../js/ui/ctrlAltTab.js:29 ../js/ui/viewSelector.js:97
#: ../js/ui/ctrlAltTab.js:29 ../js/ui/viewSelector.js:96
msgid "Windows"
msgstr "Παράθυρα"
@ -1066,7 +1079,7 @@ msgstr "Ρυθμίσεις ημερομηνίας & ώρας"
#. 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").
#.
#: ../js/ui/dateMenu.js:205
#: ../js/ui/dateMenu.js:215
msgid "%A %B %e, %Y"
msgstr "%A %B %e, %Y"
@ -1235,7 +1248,6 @@ msgid "Remove"
msgstr "Αφαίρεση"
#: ../js/ui/messageTray.js:1501
#| msgid "No Messages"
msgid "Clear Messages"
msgstr "Καθαρισμός μηνυμάτων"
@ -1243,15 +1255,15 @@ msgstr "Καθαρισμός μηνυμάτων"
msgid "Notification Settings"
msgstr "Ρυθμίσεις ειδοποιήσεων"
#: ../js/ui/messageTray.js:1707
#: ../js/ui/messageTray.js:1709
msgid "No Messages"
msgstr "Κανένα μήνυμα"
#: ../js/ui/messageTray.js:1787
#: ../js/ui/messageTray.js:1785
msgid "Message Tray"
msgstr "Περιοχή ειδοποιήσεων"
#: ../js/ui/messageTray.js:2864
#: ../js/ui/messageTray.js:2813
msgid "System Information"
msgstr "Πληροφορίες συστήματος"
@ -1260,14 +1272,14 @@ msgctxt "program"
msgid "Unknown"
msgstr "Άγνωστο"
#: ../js/ui/overviewControls.js:460 ../js/ui/screenShield.js:153
#: ../js/ui/overviewControls.js:463 ../js/ui/screenShield.js:149
#, c-format
msgid "%d new message"
msgid_plural "%d new messages"
msgstr[0] "%d νέο μήνυμα"
msgstr[1] "%d νέα μηνύματα"
#: ../js/ui/overview.js:82
#: ../js/ui/overview.js:84
msgid "Undo"
msgstr "Αναίρεση"
@ -1279,22 +1291,21 @@ msgstr "Επισκόπηση"
#. in the search entry when no search is
#. active; it should not exceed ~30
#. characters.
#: ../js/ui/overview.js:284
#| msgid "Type to search..."
#: ../js/ui/overview.js:271
msgid "Type to search…"
msgstr "Πληκτρολογήστε για αναζήτηση…"
#: ../js/ui/panel.js:613
#: ../js/ui/panel.js:633
msgid "Quit"
msgstr "Έξοδος"
#. Translators: If there is no suitable word for "Activities"
#. in your language, you can use the word for "Overview".
#: ../js/ui/panel.js:642
#: ../js/ui/panel.js:657
msgid "Activities"
msgstr "Δραστηριότητες"
#: ../js/ui/panel.js:983
#: ../js/ui/panel.js:954
msgid "Top Bar"
msgstr "Πάνω μπάρα"
@ -1307,32 +1318,32 @@ msgstr "Πάνω μπάρα"
msgid "toggle-switch-us"
msgstr "toggle-switch-intl"
#: ../js/ui/runDialog.js:205
#: ../js/ui/runDialog.js:74
msgid "Enter a Command"
msgstr "Εισαγωγή εντολής"
#: ../js/ui/runDialog.js:241
#: ../js/ui/runDialog.js:110
msgid "Close"
msgstr "Κλείσιμο"
#. Translators: This is a time format for a date in
#. long format
#: ../js/ui/screenShield.js:90
#: ../js/ui/screenShield.js:86
msgid "%A, %B %d"
msgstr "%A, %B %d"
#: ../js/ui/screenShield.js:155
#: ../js/ui/screenShield.js:151
#, c-format
msgid "%d new notification"
msgid_plural "%d new notifications"
msgstr[0] "%d νέα ειδοποίηση"
msgstr[1] "%d νέες ειδοποιήσεις"
#: ../js/ui/screenShield.js:442 ../js/ui/userMenu.js:805
#: ../js/ui/screenShield.js:438 ../js/ui/userMenu.js:807
msgid "Lock"
msgstr "Κλείδωμα"
#: ../js/ui/screenShield.js:639
#: ../js/ui/screenShield.js:641
msgid "GNOME needs to lock the screen"
msgstr "Το GNOME χρειάζεται να κλειδώσει την οθόνη"
@ -1343,21 +1354,19 @@ msgstr "Το GNOME χρειάζεται να κλειδώσει την οθόν
#.
#. XXX: another option is to kick the user into the gdm login
#. screen, where we're not affected by grabs
#: ../js/ui/screenShield.js:758 ../js/ui/screenShield.js:1169
#| msgid "Unable to connect to %s"
#: ../js/ui/screenShield.js:762 ../js/ui/screenShield.js:1198
msgid "Unable to lock"
msgstr "Αδυναμία κλειδώματος"
#: ../js/ui/screenShield.js:759 ../js/ui/screenShield.js:1170
#: ../js/ui/screenShield.js:763 ../js/ui/screenShield.js:1199
msgid "Lock was blocked by an application"
msgstr "Το κλείδωμα εμποδίστηκε από μια εφαρμογή"
#: ../js/ui/searchDisplay.js:431
#| msgid "Searching..."
#: ../js/ui/searchDisplay.js:453
msgid "Searching…"
msgstr "Αναζήτηση…"
#: ../js/ui/searchDisplay.js:475
#: ../js/ui/searchDisplay.js:497
msgid "No results."
msgstr "Δε βρέθηκαν αποτελέσματα."
@ -1369,11 +1378,11 @@ msgstr "Αντιγραφή"
msgid "Paste"
msgstr "Επικόλληση"
#: ../js/ui/shellEntry.js:105
#: ../js/ui/shellEntry.js:101
msgid "Show Text"
msgstr "Εμφάνιση κειμένου"
#: ../js/ui/shellEntry.js:107
#: ../js/ui/shellEntry.js:103
msgid "Hide Text"
msgstr "Απόκρυψη κειμένου"
@ -1385,7 +1394,7 @@ msgstr "Κωδικός"
msgid "Remember Password"
msgstr "Απομνημόνευση κωδικού"
#: ../js/ui/shellMountOperation.js:403 ../js/ui/unlockDialog.js:140
#: ../js/ui/shellMountOperation.js:403 ../js/ui/unlockDialog.js:114
msgid "Unlock"
msgstr "Ξεκλείδωμα"
@ -1449,12 +1458,10 @@ msgid "Visibility"
msgstr "Ορατότητα"
#: ../js/ui/status/bluetooth.js:59
#| msgid "Send Files to Device..."
msgid "Send Files to Device…"
msgstr "Αποστολή αρχείων σε συσκευή…"
#: ../js/ui/status/bluetooth.js:60
#| msgid "Set Up a New Device..."
msgid "Set Up a New Device…"
msgstr "Ρύθμιση νέας συσκευής…"
@ -1481,7 +1488,6 @@ msgid "connecting..."
msgstr "σύνδεση..."
#: ../js/ui/status/bluetooth.js:239
#| msgid "Send Files..."
msgid "Send Files…"
msgstr "Αποστολή αρχείων…"
@ -1694,7 +1700,6 @@ msgstr "Ρυθμίσεις τροφοδοσίας"
#. 0 is reported when UPower does not have enough data
#. to estimate battery life
#: ../js/ui/status/power.js:99
#| msgid "Estimating..."
msgid "Estimating…"
msgstr "Υπολογισμός…"
@ -1794,59 +1799,59 @@ msgstr "Ένταση ήχου"
msgid "Microphone"
msgstr "Μικρόφωνο"
#: ../js/ui/unlockDialog.js:151
#: ../js/ui/unlockDialog.js:125
msgid "Log in as another user"
msgstr "Είσοδος ως άλλος χρήστης"
#: ../js/ui/unlockDialog.js:177
#: ../js/ui/unlockDialog.js:146
msgid "Unlock Window"
msgstr "Ξεκλείδωμα παραθύρου"
#: ../js/ui/userMenu.js:192
#: ../js/ui/userMenu.js:193
msgid "Available"
msgstr "Διαθέσιμος-η"
#: ../js/ui/userMenu.js:195
#: ../js/ui/userMenu.js:196
msgid "Busy"
msgstr "Απασχολημένος-η"
#: ../js/ui/userMenu.js:198
#: ../js/ui/userMenu.js:199
msgid "Invisible"
msgstr "Αόρατος-η"
#: ../js/ui/userMenu.js:201
#: ../js/ui/userMenu.js:202
msgid "Away"
msgstr "Απουσιάζει"
#: ../js/ui/userMenu.js:204
#: ../js/ui/userMenu.js:205
msgid "Idle"
msgstr "Αδρανής"
#: ../js/ui/userMenu.js:207
#: ../js/ui/userMenu.js:208
msgid "Offline"
msgstr "Εκτός σύνδεσης"
#: ../js/ui/userMenu.js:779
#: ../js/ui/userMenu.js:781
msgid "Notifications"
msgstr "Ειδοποιήσεις"
#: ../js/ui/userMenu.js:795
#: ../js/ui/userMenu.js:797
msgid "Switch User"
msgstr "Αλλαγή χρήστη"
#: ../js/ui/userMenu.js:800
#: ../js/ui/userMenu.js:802
msgid "Log Out"
msgstr "Αποσύνδεση"
#: ../js/ui/userMenu.js:820
#: ../js/ui/userMenu.js:822
msgid "Install Updates & Restart"
msgstr "Εγκατάσταση ενημερώσεων & επανεκκίνηση"
#: ../js/ui/userMenu.js:838
#: ../js/ui/userMenu.js:840
msgid "Your chat status will be set to busy"
msgstr "Η κατάσταση συνομιλίας σας θα ορισθεί σε απασχολημένος"
#: ../js/ui/userMenu.js:839
#: ../js/ui/userMenu.js:841
msgid ""
"Notifications are now disabled, including chat messages. Your online status "
"has been adjusted to let others know that you might not see their messages."
@ -1855,34 +1860,36 @@ msgstr ""
"κατάσταση σας έχει ορισθεί έτσι ώστε να γίνεται γνωστό ότι πιθανόν να μην "
"δείτε τα μηνύματα τους."
#: ../js/ui/userMenu.js:885
#: ../js/ui/userMenu.js:888
msgid "Other users are logged in."
msgstr "Και άλλοι χρήστες είναι συνδεμένοι."
#: ../js/ui/userMenu.js:890
#: ../js/ui/userMenu.js:893
msgid "Shutting down might cause them to lose unsaved work."
msgstr ""
"Κλείνοντας μπορεί να τους προκαλέσετε την απώλεια αναποθήκευτης εργασίας."
#: ../js/ui/userMenu.js:916
#. Translators: Remote here refers to a remote session, like a ssh login
#: ../js/ui/userMenu.js:921
#, c-format
msgid "%s (remote)"
msgstr "%s (απομακρυσμένο)"
#: ../js/ui/userMenu.js:918
#. Translators: Console here refers to a tty like a VT console
#: ../js/ui/userMenu.js:924
#, c-format
msgid "%s (console)"
msgstr "%s (κονσόλα)"
#: ../js/ui/viewSelector.js:101
#: ../js/ui/viewSelector.js:100
msgid "Applications"
msgstr "Εφαρμογές"
#: ../js/ui/viewSelector.js:105
#: ../js/ui/viewSelector.js:104
msgid "Search"
msgstr "Αναζήτηση"
#: ../js/ui/wanda.js:92
#: ../js/ui/wanda.js:77
#, c-format
msgid ""
"Sorry, no wisdom for you today:\n"
@ -1891,7 +1898,7 @@ msgstr ""
"Συγγνώμη, κανένα απόφθεγμα για εσάς σήμερα:\n"
"%s"
#: ../js/ui/wanda.js:96
#: ../js/ui/wanda.js:81
#, c-format
msgid "%s the Oracle says"
msgstr "%s ο Προφήτης λέει"

545
po/es.po

File diff suppressed because it is too large Load Diff

484
po/gl.po

File diff suppressed because it is too large Load Diff

1950
po/ia.po Normal file

File diff suppressed because it is too large Load Diff

View File

@ -461,7 +461,7 @@ msgstr "Nepavyko įvykdyti „%s“:"
#: ../js/ui/appDisplay.js:349
msgid "Frequent"
msgstr "Dažniausios"
msgstr "Dažnai naudojamos"
#: ../js/ui/appDisplay.js:356
msgid "All"
@ -1262,7 +1262,7 @@ msgstr "Apžvalga"
#. characters.
#: ../js/ui/overview.js:271
msgid "Type to search…"
msgstr "Rašykite ko ieškote…"
msgstr "Rašykite, ko ieškote…"
#: ../js/ui/panel.js:612
msgid "Quit"
@ -1299,7 +1299,7 @@ msgstr "Užverti"
#. long format
#: ../js/ui/screenShield.js:86
msgid "%A, %B %d"
msgstr "%A, %B %d"
msgstr "%A, %B %d d."
#: ../js/ui/screenShield.js:151
#, c-format

320
po/ml.po
View File

@ -10,9 +10,9 @@ 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: 2013-03-23 11:49+0000\n"
"PO-Revision-Date: 2013-03-25 14:57+0530\n"
"Last-Translator: Ani Peter <peter.ani@gmail.com>\n"
"POT-Creation-Date: 2013-04-24 18:23+0000\n"
"PO-Revision-Date: 2013-04-25 00:32+0530\n"
"Last-Translator: Balasankar C <c.balasankar@gmail.com>\n"
"Language-Team: American English <kde-i18n-doc@kde.org>\n"
"Language: ml\n"
"MIME-Version: 1.0\n"
@ -44,10 +44,14 @@ msgid "Focus the active notification"
msgstr "സജീവമായ അറിയിപ്പിനെ കേന്ദ്രീകരിക്കുക"
#: ../data/50-gnome-shell-system.xml.in.h:4
msgid "Show the overview"
msgstr "പൊതുവായ അവലോകനം കാണിക്കുക"
#: ../data/50-gnome-shell-system.xml.in.h:5
msgid "Show all applications"
msgstr "എല്ലാ പ്രയോഗങ്ങളും കാണിയ്ക്കുക"
#: ../data/50-gnome-shell-system.xml.in.h:5
#: ../data/50-gnome-shell-system.xml.in.h:6
msgid "Open the application menu"
msgstr "പ്രയോഗത്തിന്റെ മെനു തുറക്കുക"
@ -71,8 +75,7 @@ msgstr "ഗ്നോം ഷെല്‍ എക്സ്റ്റെന്‍ഷ
#: ../data/org.gnome.shell.gschema.xml.in.in.h:1
msgid "Enable internal tools useful for developers and testers from Alt-F2"
msgstr ""
"Alt-F2-ല്‍ ഡവലപ്പര്‍മാര്‍ക്കും ടെസ്റ്റേര്‍സിനും പ്രയോജനകരമായ ആന്തരിക "
"പ്രയോഗങ്ങള്‍ പ്രവര്‍ത്തന "
"Alt-F2-ല്‍ ഡവലപ്പര്‍മാര്‍ക്കും ടെസ്റ്റേര്‍സിനും പ്രയോജനകരമായ ആന്തരിക പ്രയോഗങ്ങള്‍ പ്രവര്‍ത്തന "
"സജ്ജമാക്കുന്നു"
#: ../data/org.gnome.shell.gschema.xml.in.in.h:2
@ -80,8 +83,7 @@ msgid ""
"Allows access to internal debugging and monitoring tools using the Alt-F2 "
"dialog."
msgstr ""
"Alt-F2 ഡയലോഗ് ഉപയോഗിച്ചു് ആന്തരിക ഡീബഗ്ഗിലേക്കും നീരീക്ഷണ പ്രയോഗങ്ങളിലേക്കും "
"പ്രവേശനം "
"Alt-F2 ഡയലോഗ് ഉപയോഗിച്ചു് ആന്തരിക ഡീബഗ്ഗിലേക്കും നീരീക്ഷണ പ്രയോഗങ്ങളിലേക്കും പ്രവേശനം "
"അനുവദിയ്ക്കുക."
#: ../data/org.gnome.shell.gschema.xml.in.in.h:3
@ -95,19 +97,14 @@ msgid ""
"list. You can also manipulate this list with the EnableExtension and "
"DisableExtension DBus methods on org.gnome.Shell."
msgstr ""
"ഗ്നോം ഷെല്‍ എക്സ്റ്റെന്‍ഷനുകള്‍ക്കു് ഒരു യുയുഐഡി വിശേഷതയുണ്ടു്; ലഭ്യമാക്കേണ്ട "
"എക്സ്റ്റെന്‍ഷനുകള്‍ ഈ കീ പട്ടിക "
"ലഭ്യമാക്കുന്നു. ലഭ്യമാക്കേണ്ട ഏതു് എക്സ്റ്റെന്‍ഷനും ഈ പട്ടികയിലുണ്ടാവണം. "
"org.gnome.Shell-ല്‍ "
"നിങ്ങള്‍ക്കു് EnableExtension, DisableExtension എന്നീ ഡീബസ് രീതികളിലൂടെ ഈ "
"പട്ടിക "
"ഗ്നോം ഷെല്‍ എക്സ്റ്റെന്‍ഷനുകള്‍ക്കു് ഒരു യുയുഐഡി വിശേഷതയുണ്ടു്; ലഭ്യമാക്കേണ്ട എക്സ്റ്റെന്‍ഷനുകള്‍ ഈ കീ പട്ടിക "
"ലഭ്യമാക്കുന്നു. ലഭ്യമാക്കേണ്ട ഏതു് എക്സ്റ്റെന്‍ഷനും ഈ പട്ടികയിലുണ്ടാവണം. org.gnome.Shell-ല്‍ "
"നിങ്ങള്‍ക്കു് EnableExtension, DisableExtension എന്നീ ഡീബസ് രീതികളിലൂടെ ഈ പട്ടിക "
"കൈകാര്യം ചെയ്യുവാനും സാധിയ്ക്കുന്നു."
#: ../data/org.gnome.shell.gschema.xml.in.in.h:5
msgid "Whether to collect stats about applications usage"
msgstr ""
"പ്രയോഗങ്ങളുടെ ഉപയോഗത്തെപ്പറ്റിയുള്ള സ്ഥിതിവിവരക്കണക്കുകള്‍ ശേഖരിയ്ക്കണമോ "
"എന്നു്"
msgstr "പ്രയോഗങ്ങളുടെ ഉപയോഗത്തെപ്പറ്റിയുള്ള സ്ഥിതിവിവരക്കണക്കുകള്‍ ശേഖരിയ്ക്കണമോ എന്നു്"
#: ../data/org.gnome.shell.gschema.xml.in.in.h:6
msgid ""
@ -116,12 +113,9 @@ msgid ""
"want to disable this for privacy reasons. Please note that doing so won't "
"remove already saved data."
msgstr ""
"ഏറ്റവും കൂടുതല്‍ തവണ ഉപയോഗിയ്ക്കുന്ന പ്രയോഗങ്ങള്‍ ലഭ്യമാക്കുന്നതിനായി ഷെല്‍ "
"സാധാരണയായി സജീവമായ "
"പ്രയോഗങ്ങളെ നിരീക്ഷിയ്ക്കുന്നു. (ഉദാഹരണത്തിനു്, ലോഞ്ചേര്‍സ്). ഈ ഡേറ്റാ "
"സ്വകാര്യമായി "
"സൂക്ഷിയ്ക്കുന്നെങ്കിലും, ചില കാരണങ്ങളാല്‍ ഇതു് പ്രവര്‍ത്തന "
"രഹിതമാക്കേണ്ടതുണ്ടു്. ഇങ്ങനെ ചെയ്യുന്നതു് "
"ഏറ്റവും കൂടുതല്‍ തവണ ഉപയോഗിയ്ക്കുന്ന പ്രയോഗങ്ങള്‍ ലഭ്യമാക്കുന്നതിനായി ഷെല്‍ സാധാരണയായി സജീവമായ "
"പ്രയോഗങ്ങളെ നിരീക്ഷിയ്ക്കുന്നു. (ഉദാഹരണത്തിനു്, ലോഞ്ചേര്‍സ്). ഈ ഡേറ്റാ സ്വകാര്യമായി "
"സൂക്ഷിയ്ക്കുന്നെങ്കിലും, ചില കാരണങ്ങളാല്‍ ഇതു് പ്രവര്‍ത്തന രഹിതമാക്കേണ്ടതുണ്ടു്. ഇങ്ങനെ ചെയ്യുന്നതു് "
"നിങ്ങള്‍ സൂക്ഷിച്ച ഡേറ്റയെ ബാധിയ്ക്കുന്നതല്ല."
#: ../data/org.gnome.shell.gschema.xml.in.in.h:7
@ -132,8 +126,7 @@ msgstr "ഇഷ്ടമുള്ള പ്രയോഗങ്ങള്‍ക്
msgid ""
"The applications corresponding to these identifiers will be displayed in the "
"favorites area."
msgstr ""
"ഈ ഐഡന്റിഫയറുകള്‍ക്കുള്ള പ്രയോഗങ്ങള്‍ ഉചിതമായ സ്ഥലങ്ങളില്‍ കാണിയ്ക്കുന്നു."
msgstr "ഈ ഐഡന്റിഫയറുകള്‍ക്കുള്ള പ്രയോഗങ്ങള്‍ ഉചിതമായ സ്ഥലങ്ങളില്‍ കാണിയ്ക്കുന്നു."
#: ../data/org.gnome.shell.gschema.xml.in.in.h:9
msgid "List of categories that should be displayed as folders"
@ -144,8 +137,8 @@ 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 ""
"ഈ പട്ടികയിലുള്ള ഓരോ വിഭാഗത്തിന്റെ പേരും, പ്രധാന കാഴ്ചയില്‍ ഓരോ വരിയായി "
"കാണിയ്ക്കുന്നതിനു് പകരം പ്രയോഗങ്ങളുടെ കാഴ്ചയില്‍ ഫോള്‍ഡറായി കാണിയ്ക്കുന്നു. "
"ഈ പട്ടികയിലുള്ള ഓരോ വിഭാഗത്തിന്റെ പേരും, പ്രധാന കാഴ്ചയില്‍ ഓരോ വരിയായി കാണിയ്ക്കുന്നതിനു് "
"പകരം പ്രയോഗങ്ങളുടെ കാഴ്ചയില്‍ ഫോള്‍ഡറായി കാണിയ്ക്കുന്നു. "
#: ../data/org.gnome.shell.gschema.xml.in.in.h:11
msgid "History for command (Alt-F2) dialog"
@ -160,8 +153,7 @@ msgid ""
"Internally used to store the last IM presence explicitly set by the user. "
"The value here is from the TpConnectionPresenceType enumeration."
msgstr ""
"ഉപയോക്താവു് സജ്ജമാക്കിയ അവസാന ഐഎം ആന്തരികമായി സൂക്ഷിയ്ക്കുന്നതിനു് "
"ഉപയോഗിയ്ക്കുന്നു. മൂല്യം "
"ഉപയോക്താവു് സജ്ജമാക്കിയ അവസാന ഐഎം ആന്തരികമായി സൂക്ഷിയ്ക്കുന്നതിനു് ഉപയോഗിയ്ക്കുന്നു. മൂല്യം "
"TpConnectionPresenceType തരത്തിലുള്ളതാകുന്നു."
#: ../data/org.gnome.shell.gschema.xml.in.in.h:14
@ -169,8 +161,7 @@ msgid ""
"Internally used to store the last session presence status for the user. The "
"value here is from the GsmPresenceStatus enumeration."
msgstr ""
"ഉപയോക്താവിനുള്ള അവസാന സെഷന്‍ അവസ്ഥ ആന്തരികമായി സൂക്ഷിയ്ക്കുന്നതിനു് "
"ഉപയോഗിയ്ക്കുന്നു. മൂല്യം "
"ഉപയോക്താവിനുള്ള അവസാന സെഷന്‍ അവസ്ഥ ആന്തരികമായി സൂക്ഷിയ്ക്കുന്നതിനു് ഉപയോഗിയ്ക്കുന്നു. മൂല്യം "
"GsmPresenceStatus തരത്തിലുള്ളതാകുന്നു."
#: ../data/org.gnome.shell.gschema.xml.in.in.h:15
@ -182,15 +173,13 @@ msgid ""
"This key overrides the automatic hiding of the 'Log out' menuitem in single-"
"user, single-session situations."
msgstr ""
"സിംഗിള്‍ യൂസര്‍, സിംഗിള്‍ സെഷനില്‍ 'ലോഗൌട്ട്' മെനുവസ്തു അദൃശ്യമാക്കുന്നതിനായി "
"ഈ കീ ഉപയോഗിയ്ക്കുന്നു"
"സിംഗിള്‍ യൂസര്‍, സിംഗിള്‍ സെഷനില്‍ 'ലോഗൌട്ട്' മെനുവസ്തു അദൃശ്യമാക്കുന്നതിനായി ഈ കീ ഉപയോഗിയ്ക്കുന്നു"
#: ../data/org.gnome.shell.gschema.xml.in.in.h:17
msgid ""
"Whether to remember password for mounting encrypted or remote filesystems"
msgstr ""
"എന്‍ക്രിപ്റ്റ് ചെയ്തതോ വിദൂരമോ ആയ ഫയല്‍സിസ്റ്റങ്ങള്‍ മൌണ്ട് ചെയ്യുമ്പോഴുള്ള "
"രഹസ്യവാക്ക് ഓര്‍മ്മിക്കണോ എന്ന്"
"എന്‍ക്രിപ്റ്റ് ചെയ്തതോ വിദൂരമോ ആയ ഫയല്‍സിസ്റ്റങ്ങള്‍ മൌണ്ട് ചെയ്യുമ്പോഴുള്ള രഹസ്യവാക്ക് ഓര്‍മ്മിക്കണോ എന്ന്"
#: ../data/org.gnome.shell.gschema.xml.in.in.h:18
msgid ""
@ -199,10 +188,9 @@ msgid ""
"'Remember Password' checkbox will be present. This key sets the default "
"state of the checkbox."
msgstr ""
"ഒരു എന്‍ക്രിപ്റ്റ് ചെയ്ത ഡിവൈസ് അല്ലെങ്കില്‍ വിദൂര ഫയല്‍സിസ്റ്റം മൌണ്ട് "
"ചെയ്യുമ്പോള്‍ ഷെല്‍ ഒരു രഹസ്യവാക്ക് ആവശ്യപ്പെടുന്നു. രഹസ്യവാക്ക് "
"സൂക്ഷിയ്ക്കുവാന്‍ സാധ്യമെങ്കില്‍, 'രഹസ്യവാക്ക് ഓര്‍ത്തു്വയ്ക്കുക' "
"ചെക്ക്ബോക്സ് കാണാം. ഈ കീ ചെക്ക്ബോക്സിന്റെ സ്വതവേയുള്ള അവസ്ഥ സജ്ജമാക്കുന്നു."
"ഒരു എന്‍ക്രിപ്റ്റ് ചെയ്ത ഡിവൈസ് അല്ലെങ്കില്‍ വിദൂര ഫയല്‍സിസ്റ്റം മൌണ്ട് ചെയ്യുമ്പോള്‍ ഷെല്‍ ഒരു രഹസ്യവാക്ക് "
"ആവശ്യപ്പെടുന്നു. രഹസ്യവാക്ക് സൂക്ഷിയ്ക്കുവാന്‍ സാധ്യമെങ്കില്‍, 'രഹസ്യവാക്ക് ഓര്‍ത്തു്വയ്ക്കുക' ചെക്ക്ബോക്സ് "
"കാണാം. ഈ കീ ചെക്ക്ബോക്സിന്റെ സ്വതവേയുള്ള അവസ്ഥ സജ്ജമാക്കുന്നു."
#: ../data/org.gnome.shell.gschema.xml.in.in.h:19
msgid "Show the week date in the calendar"
@ -228,61 +216,65 @@ msgstr "\"പ്രയോഗങ്ങള്‍ കാണിയ്ക്കുക
msgid ""
"Keybinding to open the \"Show Applications\" view of the Activities Overview."
msgstr ""
"പ്രവര്‍ത്തികളുടെ അവലോകനത്തിന്റെ \"പ്രയോഗങ്ങള്‍ കാണിയ്ക്കുക\" എന്ന കാഴ്ച "
"തുറക്കുന്നതിനുള്ള കീബൈന്‍ഡിങ്"
"പ്രവര്‍ത്തികളുടെ അവലോകനത്തിന്റെ \"പ്രയോഗങ്ങള്‍ കാണിയ്ക്കുക\" എന്ന കാഴ്ച തുറക്കുന്നതിനുള്ള കീബൈന്‍ഡിങ്"
#: ../data/org.gnome.shell.gschema.xml.in.in.h:25
msgid "Keybinding to open the overview"
msgstr "പൊതുവായ അവലോകനം തുറക്കുന്നതിനുള്ള കീബൈന്‍ഡിങ്"
#: ../data/org.gnome.shell.gschema.xml.in.in.h:26
msgid "Keybinding to open the Activities Overview."
msgstr "പ്രയോഗങ്ങളുടെ പൊതുവായ അവലോകനം എന്ന കാഴ്ച തുറക്കുന്നതിനുള്ള കീബൈന്‍ഡിങ്"
#: ../data/org.gnome.shell.gschema.xml.in.in.h:27
msgid "Keybinding to toggle the visibility of the message tray"
msgstr "സന്ദേശ ട്രേയുടെ ദൃശ്യത ടൊഗ്ഗിള്‍ ചെയ്യുന്നതിനുള്ള കീക്കൂട്ടം"
#: ../data/org.gnome.shell.gschema.xml.in.in.h:26
#: ../data/org.gnome.shell.gschema.xml.in.in.h:28
msgid "Keybinding to toggle the visibility of the message tray."
msgstr "സന്ദേശ ട്രേയുടെ ദൃശ്യത ടൊഗ്ഗിള്‍ ചെയ്യുന്നതിനുള്ള കീക്കൂട്ടം."
#: ../data/org.gnome.shell.gschema.xml.in.in.h:27
#: ../data/org.gnome.shell.gschema.xml.in.in.h:29
msgid "Keybinding to focus the active notification"
msgstr "സജീവമായ അറിയിപ്പിനുള്ള കീബൈന്‍ഡിങ്"
#: ../data/org.gnome.shell.gschema.xml.in.in.h:28
#: ../data/org.gnome.shell.gschema.xml.in.in.h:30
msgid "Keybinding to focus the active notification."
msgstr "സജീവമായ അറിയിപ്പിനുള്ള കീബൈന്‍ഡിങ്."
#: ../data/org.gnome.shell.gschema.xml.in.in.h:29
#: ../data/org.gnome.shell.gschema.xml.in.in.h:31
msgid "Keybinding to toggle the screen recorder"
msgstr "സ്ക്രീന്‍ റിക്കോര്‍ഡര്‍ ടൊഗ്ഗിള്‍ ചെയ്യുന്നതിനുള്ള കീക്കൂട്ടം"
#: ../data/org.gnome.shell.gschema.xml.in.in.h:30
#: ../data/org.gnome.shell.gschema.xml.in.in.h:32
msgid "Keybinding to start/stop the builtin screen recorder."
msgstr ""
"ബിള്‍ട്ടിന്‍ സ്ക്രീന്‍ റിക്കോര്‍ഡര്‍ തുടങ്ങുവാന്‍/നിര്‍ത്തുന്നതിനുള്ള "
"കീക്കൂട്ടം."
msgstr "ബിള്‍ട്ടിന്‍ സ്ക്രീന്‍ റിക്കോര്‍ഡര്‍ തുടങ്ങുവാന്‍/നിര്‍ത്തുന്നതിനുള്ള കീക്കൂട്ടം."
#: ../data/org.gnome.shell.gschema.xml.in.in.h:31
#: ../data/org.gnome.shell.gschema.xml.in.in.h:33
msgid "Which keyboard to use"
msgstr "ഏതു് കീബോര്‍ഡ് ഉപയോഗിയ്ക്കണം"
#: ../data/org.gnome.shell.gschema.xml.in.in.h:32
#: ../data/org.gnome.shell.gschema.xml.in.in.h:34
msgid "The type of keyboard to use."
msgstr "ഏതു് തരം കീബോര്‍ഡ് ഉപയോഗിയ്ക്കണം."
#: ../data/org.gnome.shell.gschema.xml.in.in.h:33
#: ../data/org.gnome.shell.gschema.xml.in.in.h:35
msgid "Framerate used for recording screencasts."
msgstr "സ്ക്രീന്‍കാസ്റ്റുകള്‍ റിക്കോര്‍ഡ് ചെയ്യുന്നതിനുള്ള ഫ്രെയിം റേറ്റ്."
#: ../data/org.gnome.shell.gschema.xml.in.in.h:34
#: ../data/org.gnome.shell.gschema.xml.in.in.h:36
msgid ""
"The framerate of the resulting screencast recordered by GNOME Shell's "
"screencast recorder in frames-per-second."
msgstr ""
"ഗ്നോം ഷെല്ലിന്റെ സ്ക്രീന്‍കാസ്റ്റ് റിക്കോര്‍ഡര്‍ റീക്കോര്‍ഡ് ചെയ്തിട്ടുള്ള "
"സ്ക്രീന്‍കാസ്റ്റിന്റെ "
"ഗ്നോം ഷെല്ലിന്റെ സ്ക്രീന്‍കാസ്റ്റ് റിക്കോര്‍ഡര്‍ റീക്കോര്‍ഡ് ചെയ്തിട്ടുള്ള സ്ക്രീന്‍കാസ്റ്റിന്റെ "
"ഫ്രെയിംറേറ്റ്, ഒരു സെക്കന്‍ഡില്‍ ഒരു ഫ്രെയിം."
#: ../data/org.gnome.shell.gschema.xml.in.in.h:35
#: ../data/org.gnome.shell.gschema.xml.in.in.h:37
msgid "The gstreamer pipeline used to encode the screencast"
msgstr "സ്ക്രീന്‍കാസ്റ്റ് എന്‍കോഡ് ചെയ്യുന്നതിനുള്ള gstreamer പൈപ്പ്‌ലൈന്‍"
#: ../data/org.gnome.shell.gschema.xml.in.in.h:37
#: ../data/org.gnome.shell.gschema.xml.in.in.h:39
#, no-c-format
msgid ""
"Sets the GStreamer pipeline used to encode recordings. It follows the syntax "
@ -296,78 +288,68 @@ msgid ""
"threads=%T ! queue ! webmmux' and records to WEBM using the VP8 codec. %T is "
"used as a placeholder for a guess at the optimal thread count on the system."
msgstr ""
"റിക്കോര്‍ഡിങുകള്‍ എന്‍കോഡ് ചെയ്യുന്നതിനായി GStreamer പൈപ്പ് ലൈന്‍ "
"ഉപയോഗിയ്ക്കുന്നു. gst-launch-"
"നുള്ള സിന്റാക്സ് ഉപയോഗിയ്ക്കുന്നു. കാലിയായി സജ്ജമാക്കുമ്പോള്‍ "
"കാലിയാകുന്നു.ഇതു് നിലവില്‍ 'vp8enc "
"റിക്കോര്‍ഡിങുകള്‍ എന്‍കോഡ് ചെയ്യുന്നതിനായി GStreamer പൈപ്പ് ലൈന്‍ ഉപയോഗിയ്ക്കുന്നു. gst-launch-"
"നുള്ള സിന്റാക്സ് ഉപയോഗിയ്ക്കുന്നു. കാലിയായി സജ്ജമാക്കുമ്പോള്‍ കാലിയാകുന്നു.ഇതു് നിലവില്‍ 'vp8enc "
"min_quantizer=13 max_quantizer=13 cpu-used=5 deadline=1000000 threads=%T ! "
"queue ! webmmux' ആകുന്നുസ WEBM VP8 കോഡ് ഉപയോഗിച്ചു് റിക്കോര്‍ഡ് ചെയ്യുന്നു."
#: ../data/org.gnome.shell.gschema.xml.in.in.h:38
#: ../data/org.gnome.shell.gschema.xml.in.in.h:40
msgid "File extension used for storing the screencast"
msgstr "സ്ക്രീന്‍കാസ്റ്റ് സൂക്ഷിയ്ക്കുന്നതിനുള്ള ഫയല്‍ എക്സ്റ്റെന്‍ഷന്‍"
#: ../data/org.gnome.shell.gschema.xml.in.in.h:39
#: ../data/org.gnome.shell.gschema.xml.in.in.h:41
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 "
"a different container format."
msgstr ""
"റിക്കോര്‍ഡ് ചെയ്ത സ്ക്രീന്‍കാസ്റ്റുകള്‍ക്കുള്ള ഫയല്‍നാമം നിലവിലുള്ള തീയതി, "
"എക്സ്റ്റെന്‍ഷന്‍ എന്നിവ "
"അനുസരിച്ചാകുന്നു. മറ്റൊരു ശൈലിയിലേക്കു് റിക്കോര്‍ഡ് ചെയ്യുമ്പോള്‍ ഇതു് "
"മാറ്റണം."
"റിക്കോര്‍ഡ് ചെയ്ത സ്ക്രീന്‍കാസ്റ്റുകള്‍ക്കുള്ള ഫയല്‍നാമം നിലവിലുള്ള തീയതി, എക്സ്റ്റെന്‍ഷന്‍ എന്നിവ "
"അനുസരിച്ചാകുന്നു. മറ്റൊരു ശൈലിയിലേക്കു് റിക്കോര്‍ഡ് ചെയ്യുമ്പോള്‍ ഇതു് മാറ്റണം."
#: ../data/org.gnome.shell.gschema.xml.in.in.h:40
#: ../data/org.gnome.shell.gschema.xml.in.in.h:42
msgid "The application icon mode."
msgstr "പ്രയോഗത്തിന്റെ ഐക്കണ്‍ മോഡ്."
#: ../data/org.gnome.shell.gschema.xml.in.in.h:41
#: ../data/org.gnome.shell.gschema.xml.in.in.h:43
msgid ""
"Configures how the windows are shown in the switcher. Valid possibilities "
"are 'thumbnail-only' (shows a thumbnail of the window), 'app-icon-"
"only' (shows only the application icon) or 'both'."
msgstr ""
"സ്വിച്ചറില്‍ ജാലകങ്ങള്‍ എങ്ങനെ കാണിയ്ക്കുന്നു എന്നു് ക്രമീകരിയ്ക്കുന്നു. "
"ശരിയായ "
"സാധ്യതകള്‍: 'thumbnail-only' (ജാലകത്തിന്റെ പ്രതിരൂപം കാണിയ്ക്കുന്നു), "
"'app-icon-"
"സ്വിച്ചറില്‍ ജാലകങ്ങള്‍ എങ്ങനെ കാണിയ്ക്കുന്നു എന്നു് ക്രമീകരിയ്ക്കുന്നു. ശരിയായ സാധ്യതകള്‍: "
"'thumbnail-only' (ജാലകത്തിന്റെ പ്രതിരൂപം കാണിയ്ക്കുന്നു), 'app-icon-"
"only' (പ്രയോഗത്തിന്റെ പ്രതിരൂപം കാണിയ്ക്കുന്നു) അല്ലെങ്കില്‍ 'both'."
#: ../data/org.gnome.shell.gschema.xml.in.in.h:42
#: ../data/org.gnome.shell.gschema.xml.in.in.h:44
msgid "Attach modal dialog to the parent window"
msgstr "പേരന്റ് ജാലകത്തിലേക്കു് ഡയലോഗ് ചേര്‍ക്കുക"
#: ../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.mutter when running GNOME Shell."
msgstr ""
"ഗ്നോം ഷെല്‍ പ്രവര്‍ത്തിയ്ക്കുമ്പോള്‍ org.gnome.mutter-ലുള്ള കീ ഈ കീ "
"തിരുത്തിയെഴുതുന്നു."
msgstr "ഗ്നോം ഷെല്‍ പ്രവര്‍ത്തിയ്ക്കുമ്പോള്‍ org.gnome.mutter-ലുള്ള കീ ഈ കീ തിരുത്തിയെഴുതുന്നു."
#: ../data/org.gnome.shell.gschema.xml.in.in.h:44
#: ../data/org.gnome.shell.gschema.xml.in.in.h:46
msgid "Arrangement of buttons on the titlebar"
msgstr "തലക്കെട്ടിനുള്ള ബാറില്‍ ബട്ടണുകളുടെ ക്രമീകരണം"
#: ../data/org.gnome.shell.gschema.xml.in.in.h:45
#: ../data/org.gnome.shell.gschema.xml.in.in.h:47
msgid ""
"This key overrides the key in org.gnome.desktop.wm.preferences when running "
"GNOME Shell."
msgstr ""
"ഗ്നോം ഷെല്‍ പ്രവര്‍ത്തിയ്ക്കുമ്പോള്‍ org.gnome.desktop.wm.preferences-ലുള്ള "
"കീ ഈ കീ തിരുത്തിയെഴുതുന്നു."
"ഗ്നോം ഷെല്‍ പ്രവര്‍ത്തിയ്ക്കുമ്പോള്‍ org.gnome.desktop.wm.preferences-ലുള്ള കീ ഈ കീ "
"തിരുത്തിയെഴുതുന്നു."
#: ../data/org.gnome.shell.gschema.xml.in.in.h:46
#: ../data/org.gnome.shell.gschema.xml.in.in.h:48
msgid "Enable edge tiling when dropping windows on screen edges"
msgstr ""
"സ്ക്രീന്‍ കോണുകളില്‍ ജാലകങ്ങള്‍ എത്തിയ്ക്കുമ്പോള്‍ കോണ്‍ ചരിയ്ക്കുന്നതിനായി "
"പ്രവര്‍ത്തന സജ്ജമാക്കുക"
msgstr "സ്ക്രീന്‍ കോണുകളില്‍ ജാലകങ്ങള്‍ എത്തിയ്ക്കുമ്പോള്‍ കോണ്‍ ചരിയ്ക്കുന്നതിനായി പ്രവര്‍ത്തന സജ്ജമാക്കുക"
#: ../data/org.gnome.shell.gschema.xml.in.in.h:47
#: ../data/org.gnome.shell.gschema.xml.in.in.h:49
msgid "Workspaces are managed dynamically"
msgstr "പണിയിടങ്ങള്‍ ഡയനാമിക്കായി കൈകാര്യം ചെയ്തിരിക്കുന്നു"
#: ../data/org.gnome.shell.gschema.xml.in.in.h:48
#: ../data/org.gnome.shell.gschema.xml.in.in.h:50
msgid "Workspaces only on primary monitor"
msgstr "പ്രധാന മോണിറ്ററില്‍ മാത്രം പണിയിടങ്ങള്‍"
@ -382,12 +364,9 @@ msgstr "എക്സ്റ്റെന്‍ഷന്‍"
#: ../js/extensionPrefs/main.js:189
msgid "Select an extension to configure using the combobox above."
msgstr ""
"മുകളിലുള്ള കോമ്പോ ബോക്സ് ഉപയോഗിച്ചു് ക്രമീകരിയ്ക്കുന്നതിനുള്ളൊരു "
"എക്സ്റ്റെന്‍ഷന്‍ തെര‍ഞ്ഞെടുക്കുക."
msgstr "മുകളിലുള്ള കോമ്പോ ബോക്സ് ഉപയോഗിച്ചു് ക്രമീകരിയ്ക്കുന്നതിനുള്ളൊരു എക്സ്റ്റെന്‍ഷന്‍ തെര‍ഞ്ഞെടുക്കുക."
#: ../js/gdm/loginDialog.js:405
#| msgid "Session..."
msgid "Session…"
msgstr "പ്രവര്‍ത്തനവേള..."
@ -398,32 +377,32 @@ msgstr "പ്രവര്‍ത്തനവേള..."
msgid "Not listed?"
msgstr "ലഭ്യമല്ലേ?"
#: ../js/gdm/loginDialog.js:786 ../js/ui/components/networkAgent.js:137
#: ../js/ui/components/polkitAgent.js:162 ../js/ui/endSessionDialog.js:375
#: ../js/gdm/loginDialog.js:787 ../js/ui/components/networkAgent.js:137
#: ../js/ui/components/polkitAgent.js:162 ../js/ui/endSessionDialog.js:376
#: ../js/ui/extensionDownloader.js:195 ../js/ui/shellMountOperation.js:399
#: ../js/ui/status/bluetooth.js:415 ../js/ui/unlockDialog.js:99
#: ../js/ui/status/bluetooth.js:415 ../js/ui/unlockDialog.js:100
#: ../js/ui/userMenu.js:938
msgid "Cancel"
msgstr "വേണ്ട"
#: ../js/gdm/loginDialog.js:802
#: ../js/gdm/loginDialog.js:803
msgctxt "button"
msgid "Sign In"
msgstr "അകത്തുകയറുക"
#: ../js/gdm/loginDialog.js:802
#: ../js/gdm/loginDialog.js:803
msgid "Next"
msgstr "അടുത്തത്"
#. 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:917 ../js/ui/components/networkAgent.js:260
#: ../js/gdm/loginDialog.js:918 ../js/ui/components/networkAgent.js:260
#: ../js/ui/components/networkAgent.js:278
msgid "Username: "
msgstr "ഉപയോക്തൃ നാമം: "
#: ../js/gdm/loginDialog.js:1173
#: ../js/gdm/loginDialog.js:1174
msgid "Login Window"
msgstr "പ്രവേശന ജാലകം"
@ -476,23 +455,23 @@ msgstr "ആജ്ഞ പ്രാവര്‍ത്തികമാക്കാ
msgid "Execution of '%s' failed:"
msgstr "'%s' നടപ്പിലാക്കുന്നതില്‍ പരാജയപ്പെട്ടു:"
#: ../js/ui/appDisplay.js:349
#: ../js/ui/appDisplay.js:351
msgid "Frequent"
msgstr "ഇടയ്ക്കിടെ"
#: ../js/ui/appDisplay.js:356
#: ../js/ui/appDisplay.js:358
msgid "All"
msgstr "എല്ലാം"
#: ../js/ui/appDisplay.js:914
#: ../js/ui/appDisplay.js:916
msgid "New Window"
msgstr "പുതിയ വിന്‍ഡോ"
#: ../js/ui/appDisplay.js:917 ../js/ui/dash.js:284
#: ../js/ui/appDisplay.js:919 ../js/ui/dash.js:284
msgid "Remove from Favorites"
msgstr "ഇഷ്ടപ്പെട്ടവയില്‍ നിന്നും നീക്കം ചെയ്യുക"
#: ../js/ui/appDisplay.js:918
#: ../js/ui/appDisplay.js:920
msgid "Add to Favorites"
msgstr "ഇഷ്ടപ്പെട്ടവയിലേക്ക് ചേര്‍ക്കുക"
@ -529,7 +508,7 @@ msgctxt "event list time"
msgid "%H\\u2236%M"
msgstr "%H\\u2236%M"
#. 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
#: ../js/ui/calendar.js:77
@ -732,8 +711,7 @@ msgid ""
"Passwords or encryption keys are required to access the wireless network "
"'%s'."
msgstr ""
"വയര്‍ലെസ് നെറ്റ്‌വര്‍ക്ക് '%s'-ലേക്ക് പ്രവേശിക്കുന്നതിനായി രഹസ്യവാക്കുകള്‍ "
"അല്ലെങ്കില്‍ എന്‍ക്രിപ്ഷന്‍ കീകള്‍ "
"വയര്‍ലെസ് നെറ്റ്‌വര്‍ക്ക് '%s'-ലേക്ക് പ്രവേശിക്കുന്നതിനായി രഹസ്യവാക്കുകള്‍ അല്ലെങ്കില്‍ എന്‍ക്രിപ്ഷന്‍ കീകള്‍ "
"ആവശ്യമുണ്ടു്."
#: ../js/ui/components/networkAgent.js:314
@ -790,7 +768,7 @@ msgid "Sorry, that didn't work. Please try again."
msgstr "ക്ഷമിക്കണം, അതു ശരിയല്ല. ദയവായി വീണ്ടും ശ്രമിക്കുക."
#. Translators: this is a filename used for screencast recording
#: ../js/ui/components/recorder.js:48
#: ../js/ui/components/recorder.js:47
#, no-c-format
msgid "Screencast from %d %t"
msgstr "%d-ല്‍ നിന്നുള്ള സ്ക്രീന്‍കാസ്റ്റ്, %t-ല്‍"
@ -913,8 +891,7 @@ msgstr "%s നിങ്ങള്‍ക്കു് %s അയച്ചിരി
#: ../js/ui/components/telepathyClient.js:1206
#, c-format
msgid "%s would like permission to see when you are online"
msgstr ""
"നിങ്ങള്‍ ഓണ്‍ലൈന്‍ ആകുമ്പോള്‍ കാണുന്നതിനുള്ള അനുമതി %s-നു് ആവശ്യമുണ്ടു്"
msgstr "നിങ്ങള്‍ ഓണ്‍ലൈന്‍ ആകുമ്പോള്‍ കാണുന്നതിനുള്ള അനുമതി %s-നു് ആവശ്യമുണ്ടു്"
#: ../js/ui/components/telepathyClient.js:1298
msgid "Network error"
@ -987,9 +964,7 @@ msgstr "ഈ അക്കൌണ്ട് നിലവില്‍ സര്‍വ
#: ../js/ui/components/telepathyClient.js:1332
msgid ""
"Connection has been replaced by a new connection using the same resource"
msgstr ""
"അതേ ശ്രോതസ്സ് ഉപയോഗിച്ചു് ഒരു പുതിയ കണക്ഷന്‍ ഉപയോഗിച്ചു് ഈ കണക്ഷന്‍ "
"മാറ്റിസ്ഥാപിയ്ക്കുന്നു"
msgstr "അതേ ശ്രോതസ്സ് ഉപയോഗിച്ചു് ഒരു പുതിയ കണക്ഷന്‍ ഉപയോഗിച്ചു് ഈ കണക്ഷന്‍ മാറ്റിസ്ഥാപിയ്ക്കുന്നു"
#: ../js/ui/components/telepathyClient.js:1334
msgid "The account already exists on the server"
@ -1006,17 +981,14 @@ msgstr "സമ്മതപത്രം വീണ്ടും ആവശ്യപ
#: ../js/ui/components/telepathyClient.js:1340
msgid ""
"Certificate uses an insecure cipher algorithm or is cryptographically weak"
msgstr ""
"സമ്മതപത്രം സുരക്ഷിതമല്ലാത്തൊരു സിഫര്‍ ആല്‍ഗോരിഥം ഉപയോഗിയ്ക്കുന്നു "
"അല്ലെങ്കില്‍ ഉചിതമല്ല"
msgstr "സമ്മതപത്രം സുരക്ഷിതമല്ലാത്തൊരു സിഫര്‍ ആല്‍ഗോരിഥം ഉപയോഗിയ്ക്കുന്നു അല്ലെങ്കില്‍ ഉചിതമല്ല"
#: ../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"
msgstr ""
"സര്‍വറിന്റെ സമ്മതപത്രത്തിന്റെ വ്യാപ്തി, അല്ലെങ്കില്‍ സര്‍വര്‍ സമ്മതപത്ര "
"ചെയിന്റെ വ്യാപ്തി, എന്നിവ "
"സര്‍വറിന്റെ സമ്മതപത്രത്തിന്റെ വ്യാപ്തി, അല്ലെങ്കില്‍ സര്‍വര്‍ സമ്മതപത്ര ചെയിന്റെ വ്യാപ്തി, എന്നിവ "
"പരിധിയില്‍ കൂടുന്നു"
#: ../js/ui/components/telepathyClient.js:1344
@ -1085,8 +1057,7 @@ msgstr "പുറത്ത് കടക്കുക"
#: ../js/ui/endSessionDialog.js:65
msgid "Click Log Out to quit these applications and log out of the system."
msgstr ""
"ഈ പ്രയോഗങ്ങളില്‍ നിന്നും പുറത്തു് കടക്കുന്നതിനായി പുറത്തു കടക്കുക ക്ലിക്ക് "
"ചെയ്തു് സിസ്റ്റത്തില്‍ നിന്നും "
"ഈ പ്രയോഗങ്ങളില്‍ നിന്നും പുറത്തു് കടക്കുന്നതിനായി പുറത്തു കടക്കുക ക്ലിക്ക് ചെയ്തു് സിസ്റ്റത്തില്‍ നിന്നും "
"പുറത്തു് കടക്കുക."
#: ../js/ui/endSessionDialog.js:67
@ -1120,8 +1091,7 @@ msgstr "നിര്‍ത്തുക"
#: ../js/ui/endSessionDialog.js:84
msgid "Click Power Off to quit these applications and power off the system."
msgstr ""
"ഈ പ്രയോഗങ്ങളില്‍ നിന്നും പുറത്തു് കടക്കുന്നതിനായി പവര്‍ ഓഫ് ചെയ്യുക ക്ലിക്ക് "
"ചെയ്തു സിസ്റ്റിന്റെ പവര്‍ "
"ഈ പ്രയോഗങ്ങളില്‍ നിന്നും പുറത്തു് കടക്കുന്നതിനായി പവര്‍ ഓഫ് ചെയ്യുക ക്ലിക്ക് ചെയ്തു സിസ്റ്റിന്റെ പവര്‍ "
"ഓഫ് ചെയ്യുക."
#: ../js/ui/endSessionDialog.js:86
@ -1152,8 +1122,7 @@ msgstr "പുനരാരംഭിക്കുക"
#: ../js/ui/endSessionDialog.js:101
msgid "Click Restart to quit these applications and restart the system."
msgstr ""
"ഈ പ്രയോഗങ്ങള്‍ നിറുത്തി സിസ്റ്റം പുനരാരംഭിക്കുവാന്‍ പുനരാരംഭിക്കൂ അമര്‍ത്തുക"
msgstr "ഈ പ്രയോഗങ്ങള്‍ നിറുത്തി സിസ്റ്റം പുനരാരംഭിക്കുവാന്‍ പുനരാരംഭിക്കൂ അമര്‍ത്തുക"
#: ../js/ui/endSessionDialog.js:103
#, c-format
@ -1173,9 +1142,7 @@ msgstr "ഇന്‍സ്റ്റോള്‍"
#: ../js/ui/extensionDownloader.js:204
#, c-format
msgid "Download and install '%s' from extensions.gnome.org?"
msgstr ""
"extensions.gnome.org ഇല്‍ നിന്നും '%s' ഡൗണ്‍ലോട് ചെയ്ത് ഇന്‍സ്റ്റോള്‍ "
"ചെയ്യേണമോ?"
msgstr "extensions.gnome.org ഇല്‍ നിന്നും '%s' ഡൗണ്‍ലോട് ചെയ്ത് ഇന്‍സ്റ്റോള്‍ ചെയ്യേണമോ?"
#: ../js/ui/keyboard.js:619 ../js/ui/status/keyboard.js:314
#: ../js/ui/status/power.js:211
@ -1204,7 +1171,9 @@ msgstr "പിശകുകള്‍ കാണിക്കുക"
msgid "Enabled"
msgstr "പ്രവര്‍ത്തനക്ഷമമാക്കി"
#: ../js/ui/lookingGlass.js:769
#. translators:
#. * The device has been disabled
#: ../js/ui/lookingGlass.js:769 ../src/gvc/gvc-mixer-control.c:1830
msgid "Disabled"
msgstr "പ്രവര്‍ത്തനരഹിതമാക്കി"
@ -1237,7 +1206,6 @@ msgid "Remove"
msgstr "നീക്കം ചെയ്യുക"
#: ../js/ui/messageTray.js:1501
#| msgid "No Messages"
msgid "Clear Messages"
msgstr "സന്ദേശങ്ങള്‍ വെടിപ്പാക്കുക"
@ -1245,35 +1213,35 @@ msgstr "സന്ദേശങ്ങള്‍ വെടിപ്പാക്ക
msgid "Notification Settings"
msgstr "അറിയിപ്പു് ക്രമീകരണങ്ങള്‍"
#: ../js/ui/messageTray.js:1709
#: ../js/ui/messageTray.js:1710
msgid "No Messages"
msgstr "സന്ദേശങ്ങളില്ല"
#: ../js/ui/messageTray.js:1782
#: ../js/ui/messageTray.js:1783
msgid "Message Tray"
msgstr "സന്ദേശത്തിന്റെ ട്രേ"
#: ../js/ui/messageTray.js:2810
#: ../js/ui/messageTray.js:2801
msgid "System Information"
msgstr "സിസ്റ്റത്തെക്കുറിച്ചുള്ള വിവരം"
#: ../js/ui/notificationDaemon.js:629 ../src/shell-app.c:374
#: ../js/ui/notificationDaemon.js:629 ../src/shell-app.c:378
msgctxt "program"
msgid "Unknown"
msgstr "അജ്ഞാതം"
#: ../js/ui/overviewControls.js:463 ../js/ui/screenShield.js:149
#: ../js/ui/overviewControls.js:472 ../js/ui/screenShield.js:149
#, c-format
msgid "%d new message"
msgid_plural "%d new messages"
msgstr[0] "%d പുതിയ സന്ദേശം"
msgstr[1] "%d പുതിയ സന്ദേശങ്ങള്‍"
#: ../js/ui/overview.js:84
#: ../js/ui/overview.js:82
msgid "Undo"
msgstr "വേണ്ട"
#: ../js/ui/overview.js:129
#: ../js/ui/overview.js:127
msgid "Overview"
msgstr "അവലോകനം"
@ -1281,22 +1249,21 @@ msgstr "അവലോകനം"
#. in the search entry when no search is
#. active; it should not exceed ~30
#. characters.
#: ../js/ui/overview.js:271
#| msgid "Type to search..."
#: ../js/ui/overview.js:260
msgid "Type to search…"
msgstr "തെരയുന്നതിനായി ടൈപ്പ് ചെയ്യുക..."
#: ../js/ui/panel.js:612
#: ../js/ui/panel.js:641
msgid "Quit"
msgstr "നിര്‍ത്തുക"
#. Translators: If there is no suitable word for "Activities"
#. in your language, you can use the word for "Overview".
#: ../js/ui/panel.js:636
#: ../js/ui/panel.js:692
msgid "Activities"
msgstr "പ്രവര്‍ത്തനങ്ങള്‍"
#: ../js/ui/panel.js:933
#: ../js/ui/panel.js:989
msgid "Top Bar"
msgstr "മുകളിലുള്ള ബാര്‍"
@ -1305,15 +1272,15 @@ msgstr "മുകളിലുള്ള ബാര്‍"
#. "ON" and "OFF") or "toggle-switch-intl" (for toggle
#. switches containing "◯" and "|"). Other values will
#. simply result in invisible toggle switches.
#: ../js/ui/popupMenu.js:727
#: ../js/ui/popupMenu.js:718
msgid "toggle-switch-us"
msgstr "toggle-switch-us"
#: ../js/ui/runDialog.js:73
#: ../js/ui/runDialog.js:74
msgid "Enter a Command"
msgstr "ഒരു കമാന്‍ഡ് നല്‍കുക"
#: ../js/ui/runDialog.js:109
#: ../js/ui/runDialog.js:110
msgid "Close"
msgstr "അടക്കുക"
@ -1334,7 +1301,7 @@ msgstr[1] "%d പുതിയ അറിയിപ്പുകള്‍"
msgid "Lock"
msgstr "പൂട്ടുക"
#: ../js/ui/screenShield.js:637
#: ../js/ui/screenShield.js:641
msgid "GNOME needs to lock the screen"
msgstr "ഗ്നോമിന് സ്ക്രീന്‍ പൂട്ടണം"
@ -1345,17 +1312,15 @@ msgstr "ഗ്നോമിന് സ്ക്രീന്‍ പൂട്ടണ
#.
#. XXX: another option is to kick the user into the gdm login
#. screen, where we're not affected by grabs
#: ../js/ui/screenShield.js:758 ../js/ui/screenShield.js:1194
#| msgid "Unable to connect to %s"
#: ../js/ui/screenShield.js:762 ../js/ui/screenShield.js:1198
msgid "Unable to lock"
msgstr "പൂട്ടുവാന്‍ സാധ്യമല്ല"
#: ../js/ui/screenShield.js:759 ../js/ui/screenShield.js:1195
#: ../js/ui/screenShield.js:763 ../js/ui/screenShield.js:1199
msgid "Lock was blocked by an application"
msgstr "പൂട്ടുന്ന സംവിധാനം ഒരു പ്രയോഗം തടസ്സപ്പെടുത്തിയിരിയ്ക്കുന്നു"
#: ../js/ui/searchDisplay.js:453
#| msgid "Searching..."
msgid "Searching…"
msgstr "തെരയുന്നു..."
@ -1371,11 +1336,11 @@ msgstr "പകര്‍ത്തുക"
msgid "Paste"
msgstr "ഒട്ടിയ്ക്കുക"
#: ../js/ui/shellEntry.js:106
#: ../js/ui/shellEntry.js:101
msgid "Show Text"
msgstr "പദാവലി കാണിക്കുക"
#: ../js/ui/shellEntry.js:108
#: ../js/ui/shellEntry.js:103
msgid "Hide Text"
msgstr "പദാവലി മറക്കുക"
@ -1387,7 +1352,7 @@ msgstr "രഹസ്യവാക്ക്"
msgid "Remember Password"
msgstr "രഹസ്യവാക്ക് ഓര്‍ത്തു് വയ്ക്കുക"
#: ../js/ui/shellMountOperation.js:403 ../js/ui/unlockDialog.js:113
#: ../js/ui/shellMountOperation.js:403 ../js/ui/unlockDialog.js:114
msgid "Unlock"
msgstr "പൂട്ട് തുറക്കുക"
@ -1451,12 +1416,10 @@ msgid "Visibility"
msgstr "കാഴ്ച"
#: ../js/ui/status/bluetooth.js:59
#| msgid "Send Files to Device..."
msgid "Send Files to Device…"
msgstr "ഡിവൈസിലേക്കു് ഫയലുകള്‍ അയയ്ക്കുക..."
#: ../js/ui/status/bluetooth.js:60
#| msgid "Set Up a New Device..."
msgid "Set Up a New Device…"
msgstr "പുതിയൊരു ഡിവൈസ് സജ്ജമാക്കുക..."
@ -1483,7 +1446,6 @@ msgid "connecting..."
msgstr "ബന്ധിപ്പിയ്ക്കുന്നു...."
#: ../js/ui/status/bluetooth.js:239
#| msgid "Send Files..."
msgid "Send Files…"
msgstr "ഫയലുകള്‍ അയയ്ക്കുക..."
@ -1696,7 +1658,6 @@ msgstr "ഊര്‍ജ്ജ ക്രമീകരണങ്ങള്‍"
#. 0 is reported when UPower does not have enough data
#. to estimate battery life
#: ../js/ui/status/power.js:99
#| msgid "Estimating..."
msgid "Estimating…"
msgstr "കണക്കുകൂട്ടുന്നു..."
@ -1796,11 +1757,11 @@ msgstr "ഒച്ച"
msgid "Microphone"
msgstr "മൈക്രോഫോണ്‍"
#: ../js/ui/unlockDialog.js:124
#: ../js/ui/unlockDialog.js:125
msgid "Log in as another user"
msgstr "മറ്റൊരു ഉപയോക്താവായി പ്രവേശിയ്ക്കുക"
#: ../js/ui/unlockDialog.js:145
#: ../js/ui/unlockDialog.js:146
msgid "Unlock Window"
msgstr "ജാലകത്തിന്റെ പൂട്ടു തുറക്കുക"
@ -1853,10 +1814,8 @@ msgid ""
"Notifications are now disabled, including chat messages. Your online status "
"has been adjusted to let others know that you might not see their messages."
msgstr ""
"ചാറ്റ് സന്ദേശങ്ങള്‍ എന്ന പോലെ അറിയിപ്പുകള്‍ പ്രവര്‍ത്തന രഹിതമാക്കുന്നു. "
"മറ്റുള്ളവരുടെ ചാറ്റ് സന്ദേശങ്ങള്‍ "
"നിങ്ങള്‍ക്കു് കാണുവാന്‍ സാധ്യമല്ല എന്നു് നിങ്ങളുടെ ഓണ്‍ലൈന്‍ അവസ്ഥയില്‍ "
"വ്യക്തമാക്കുന്നു."
"ചാറ്റ് സന്ദേശങ്ങള്‍ എന്ന പോലെ അറിയിപ്പുകള്‍ പ്രവര്‍ത്തന രഹിതമാക്കുന്നു. മറ്റുള്ളവരുടെ ചാറ്റ് സന്ദേശങ്ങള്‍ "
"നിങ്ങള്‍ക്കു് കാണുവാന്‍ സാധ്യമല്ല എന്നു് നിങ്ങളുടെ ഓണ്‍ലൈന്‍ അവസ്ഥയില്‍ വ്യക്തമാക്കുന്നു."
#: ../js/ui/userMenu.js:888
msgid "Other users are logged in."
@ -1909,6 +1868,28 @@ msgstr "'%s' തയ്യാറാണ്"
msgid "Evolution Calendar"
msgstr "ഇവല്യൂഷന്‍ കലണ്ടര്‍"
#. translators:
#. * The number of sound outputs on a particular device
#: ../src/gvc/gvc-mixer-control.c:1837
#, c-format
msgid "%u Output"
msgid_plural "%u Outputs"
msgstr[0] "%u ഔട്ട്പുട്ട്"
msgstr[1] "%u ഔട്ട്പുട്ടുകള്‍"
#. translators:
#. * The number of sound inputs on a particular device
#: ../src/gvc/gvc-mixer-control.c:1847
#, c-format
msgid "%u Input"
msgid_plural "%u Inputs"
msgstr[0] "%u ഇന്‍പുട്ട്"
msgstr[1] "%u ഇന്‍പുട്ടുകള്‍"
#: ../src/gvc/gvc-mixer-control.c:2371
msgid "System Sounds"
msgstr "സിസ്റ്റം ശബ്ദങ്ങള്‍"
#: ../src/main.c:347
msgid "Print version"
msgstr "പ്രിന്റ് ചെയ്യുവാന്‍ സാധിയ്ക്കുന്ന പതിപ്പു്"
@ -1925,7 +1906,7 @@ msgstr "ഒരു പ്രത്യേക മോഡ് ഉപയോഗിയ്
msgid "List possible modes"
msgstr "സാധ്യമായ മോഡുകള്‍ ലഭ്യമാക്കുക"
#: ../src/shell-app.c:622
#: ../src/shell-app.c:626
#, c-format
msgid "Failed to launch '%s'"
msgstr "'%s' ലഭ്യമാക്കുന്നതില്‍ പരാജയം"
@ -1955,19 +1936,6 @@ msgstr "ഉപയോക്താവു് ആധികാരികത ഉറപ
#~ msgid "More..."
#~ msgstr "കൂടുതല്‍..."
#~ msgid "%u Output"
#~ msgid_plural "%u Outputs"
#~ msgstr[0] "%u ഔട്ട്പുട്ട്"
#~ msgstr[1] "%u ഔട്ട്പുട്ടുകള്‍"
#~ msgid "%u Input"
#~ msgid_plural "%u Inputs"
#~ msgstr[0] "%u ഇന്‍പുട്ട്"
#~ msgstr[1] "%u ഇന്‍പുട്ടുകള്‍"
#~ msgid "System Sounds"
#~ msgstr "സിസ്റ്റം ശബ്ദങ്ങള്‍"
#~ msgctxt "event list time"
#~ msgid "%H:%M"
#~ msgstr "%H:%M"

478
po/nb.po

File diff suppressed because it is too large Load Diff

401
po/sk.po
View File

@ -10,8 +10,8 @@ msgstr ""
"Project-Id-Version: gnome-shell\n"
"Report-Msgid-Bugs-To: http://bugzilla.gnome.org/enter_bug.cgi?product=gnome-"
"shell&keywords=I18N+L10N&component=general\n"
"POT-Creation-Date: 2013-03-23 11:49+0000\n"
"PO-Revision-Date: 2013-03-23 16:21+0000\n"
"POT-Creation-Date: 2013-05-24 21:21+0000\n"
"PO-Revision-Date: 2013-05-24 23:24+0100\n"
"Last-Translator: Dušan Kazik <prescott66@gmail.com>\n"
"Language-Team: Slovak <gnome-sk-list@gnome.org>\n"
"Language: sk\n"
@ -34,22 +34,30 @@ msgstr "Zaznamenať dianie na obrazovke"
msgid "System"
msgstr "Systém"
# nazov klavesovej skratky
#: ../data/50-gnome-shell-system.xml.in.h:2
msgid "Show the message tray"
msgstr "Zobrazí lištu správ"
msgstr "Zobraz lištu správ"
# nazov klavesovej skratky
#: ../data/50-gnome-shell-system.xml.in.h:3
msgid "Focus the active notification"
msgstr "Zamerať aktívne oznámenie"
# tooltip
# nazov klavesovej skratky
#: ../data/50-gnome-shell-system.xml.in.h:4
msgid "Show all applications"
msgstr "Zobrazí všetky aplikácie"
msgid "Show the overview"
msgstr "Zobraziť prehľad"
# nazov klavesovej skratky
#: ../data/50-gnome-shell-system.xml.in.h:5
msgid "Show all applications"
msgstr "Zobraziť všetky aplikácie"
# nazov klavesovej skratky
#: ../data/50-gnome-shell-system.xml.in.h:6
msgid "Open the application menu"
msgstr "Otvorí ponuku aplikácií"
msgstr "Otvor ponuku aplikácií"
#: ../data/gnome-shell.desktop.in.in.h:1
msgid "GNOME Shell"
@ -100,26 +108,10 @@ msgstr ""
"gnome.Shell."
#: ../data/org.gnome.shell.gschema.xml.in.in.h:5
msgid "Whether to collect stats about applications usage"
msgstr "Či sa majú zhromažďovať štatistické údaje o používaní aplikácií"
#: ../data/org.gnome.shell.gschema.xml.in.in.h:6
msgid ""
"The shell normally monitors active applications in order to present the most "
"used ones (e.g. in launchers). While this data will be kept private, you may "
"want to disable this for privacy reasons. Please note that doing so won't "
"remove already saved data."
msgstr ""
"Prostredie shell obvykle sleduje aktívne aplikácie, aby mohlo ponúkať "
"najpoužívanejšie z nich (napr. v spúšťačoch). Aj keď sú tieto údaje "
"uchovávané v tajnosti, môžete ich kvôli lepšej ochrane súkromia zakázať. Ak "
"tak urobíte, údaje, ktoré už boli uložené, zostanú zachované."
#: ../data/org.gnome.shell.gschema.xml.in.in.h:7
msgid "List of desktop file IDs for favorite applications"
msgstr "Zoznam identifikátorov súborov plochy pre obľúbené aplikácie"
#: ../data/org.gnome.shell.gschema.xml.in.in.h:8
#: ../data/org.gnome.shell.gschema.xml.in.in.h:6
msgid ""
"The applications corresponding to these identifiers will be displayed in the "
"favorites area."
@ -128,29 +120,29 @@ msgstr ""
"obľúbenými aplikáciami."
# summary
#: ../data/org.gnome.shell.gschema.xml.in.in.h:9
#: ../data/org.gnome.shell.gschema.xml.in.in.h:7
msgid "List of categories that should be displayed as folders"
msgstr "Zoznam kategórií, ktoré sa majú zobraziť ako priečinky"
# description
#: ../data/org.gnome.shell.gschema.xml.in.in.h:10
#: ../data/org.gnome.shell.gschema.xml.in.in.h:8
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 ""
"Každá z názvov kategórií v tomto zoznamu bude reprezentovaná ako priečinok v zobrazení aplikácií namiesto toho, aby sa zobrazila v hlavnom zobrazení."
"Každá z názvov kategórií v tomto zoznamu bude reprezentovaná ako priečinok v "
"zobrazení aplikácií namiesto toho, aby sa zobrazila v hlavnom zobrazení."
#: ../data/org.gnome.shell.gschema.xml.in.in.h:11
#: ../data/org.gnome.shell.gschema.xml.in.in.h:9
msgid "History for command (Alt-F2) dialog"
msgstr "História dialógového okna príkazov (Alt-F2)"
# * https://live.gnome.org/GnomeShell/LookingGlass
#: ../data/org.gnome.shell.gschema.xml.in.in.h:12
#: ../data/org.gnome.shell.gschema.xml.in.in.h:10
msgid "History for the looking glass dialog"
msgstr "História dialógového okna integrovaného odlaďovača"
#: ../data/org.gnome.shell.gschema.xml.in.in.h:13
#: ../data/org.gnome.shell.gschema.xml.in.in.h:11
msgid ""
"Internally used to store the last IM presence explicitly set by the user. "
"The value here is from the TpConnectionPresenceType enumeration."
@ -159,7 +151,7 @@ msgstr ""
"komunikátora výlučne nastavenej používateľom. Táto hodnota je z vymenovaných "
"hodnôt typu TpConnectionPresenceType."
#: ../data/org.gnome.shell.gschema.xml.in.in.h:14
#: ../data/org.gnome.shell.gschema.xml.in.in.h:12
msgid ""
"Internally used to store the last session presence status for the user. The "
"value here is from the GsmPresenceStatus enumeration."
@ -168,11 +160,11 @@ msgstr ""
"používateľa. Táto hodnota je z vymenovaných hodnôt typu "
"GsmPresenceStatusType."
#: ../data/org.gnome.shell.gschema.xml.in.in.h:15
#: ../data/org.gnome.shell.gschema.xml.in.in.h:13
msgid "Always show the 'Log out' menuitem in the user menu."
msgstr "Vždy zobraziť položku „Odhlásiť sa“ v ponuke používateľa"
#: ../data/org.gnome.shell.gschema.xml.in.in.h:16
#: ../data/org.gnome.shell.gschema.xml.in.in.h:14
msgid ""
"This key overrides the automatic hiding of the 'Log out' menuitem in single-"
"user, single-session situations."
@ -181,7 +173,7 @@ msgstr ""
"s jedným používateľom alebo jednou reláciou."
# summary
#: ../data/org.gnome.shell.gschema.xml.in.in.h:17
#: ../data/org.gnome.shell.gschema.xml.in.in.h:15
msgid ""
"Whether to remember password for mounting encrypted or remote filesystems"
msgstr ""
@ -189,7 +181,7 @@ msgstr ""
"prenosných súborových systémov"
# description
#: ../data/org.gnome.shell.gschema.xml.in.in.h:18
#: ../data/org.gnome.shell.gschema.xml.in.in.h:16
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 "
@ -201,34 +193,42 @@ msgstr ""
"zobrazí sa zaškrtávacie pole „Zapamätať heslo“. Tento kľúč nastaví "
"predvolený stav zaškrtávacieho poľa."
#: ../data/org.gnome.shell.gschema.xml.in.in.h:19
#: ../data/org.gnome.shell.gschema.xml.in.in.h:17
msgid "Show the week date in the calendar"
msgstr "Zobraziť čísla týždňov v kalendári"
#: ../data/org.gnome.shell.gschema.xml.in.in.h:20
#: ../data/org.gnome.shell.gschema.xml.in.in.h:18
msgid "If true, display the ISO week date in the calendar."
msgstr ""
"Ak je true, zobrazí v kalendári poradie dní v týždni podľa štandardu ISO."
#: ../data/org.gnome.shell.gschema.xml.in.in.h:21
#: ../data/org.gnome.shell.gschema.xml.in.in.h:19
msgid "Keybinding to open the application menu"
msgstr "Klávesová skratka na otvorenie ponuky aplikácií"
#: ../data/org.gnome.shell.gschema.xml.in.in.h:22
#: ../data/org.gnome.shell.gschema.xml.in.in.h:20
msgid "Keybinding to open the application menu."
msgstr "Klávesová skratka na otvorenie ponuky aplikácií."
#: ../data/org.gnome.shell.gschema.xml.in.in.h:23
#: ../data/org.gnome.shell.gschema.xml.in.in.h:21
msgid "Keybinding to open the \"Show Applications\" view"
msgstr "Klávesová skratka na otvorenie pohľadu „Zobraziť aplikácie“"
#: ../data/org.gnome.shell.gschema.xml.in.in.h:24
#: ../data/org.gnome.shell.gschema.xml.in.in.h:22
msgid ""
"Keybinding to open the \"Show Applications\" view of the Activities Overview."
msgstr ""
"Klávesová skratka na otvorenie pohľadu „Zobraziť aplikácie“ v prehľade "
"aktivít."
#: ../data/org.gnome.shell.gschema.xml.in.in.h:23
msgid "Keybinding to open the overview"
msgstr "Klávesová skratka na otvorenie prehľadu"
#: ../data/org.gnome.shell.gschema.xml.in.in.h:24
msgid "Keybinding to open the Activities Overview."
msgstr "Klávesová skratka na otvorenie prehľadu aktivít."
#: ../data/org.gnome.shell.gschema.xml.in.in.h:25
msgid "Keybinding to toggle the visibility of the message tray"
msgstr "Klávesová skratka na prepnutie viditeľnosti lišty správ"
@ -384,7 +384,7 @@ msgstr "Rozšírenie"
msgid "Select an extension to configure using the combobox above."
msgstr "Použitím ponuky vyberte rozšírenie na nastavenie"
#: ../js/gdm/loginDialog.js:405
#: ../js/gdm/loginDialog.js:371
msgid "Session…"
msgstr "Relácia…"
@ -392,36 +392,43 @@ msgstr "Relácia…"
#. 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:630
#: ../js/gdm/loginDialog.js:601
msgid "Not listed?"
msgstr "Nie ste v zozname?"
#: ../js/gdm/loginDialog.js:786 ../js/ui/components/networkAgent.js:137
#: ../js/ui/components/polkitAgent.js:162 ../js/ui/endSessionDialog.js:375
#: ../js/gdm/loginDialog.js:776 ../js/ui/components/networkAgent.js:137
#: ../js/ui/components/polkitAgent.js:161 ../js/ui/endSessionDialog.js:376
#: ../js/ui/extensionDownloader.js:195 ../js/ui/shellMountOperation.js:399
#: ../js/ui/status/bluetooth.js:415 ../js/ui/unlockDialog.js:99
#: ../js/ui/status/bluetooth.js:415 ../js/ui/unlockDialog.js:96
#: ../js/ui/userMenu.js:938
msgid "Cancel"
msgstr "Zrušiť"
#: ../js/gdm/loginDialog.js:802
#: ../js/gdm/loginDialog.js:791
msgctxt "button"
msgid "Sign In"
msgstr "Prihlásiť sa"
#: ../js/gdm/loginDialog.js:802
#: ../js/gdm/loginDialog.js:791
msgid "Next"
msgstr "Ďalej"
#. Translators: this message is shown below the username entry field
#. to clue the user in on how to login to the local network realm
#: ../js/gdm/loginDialog.js:888
#, c-format
msgid "(e.g., user or %s)"
msgstr "(napr., používateľ alebo %s)"
#. 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:917 ../js/ui/components/networkAgent.js:260
#: ../js/gdm/loginDialog.js:892 ../js/ui/components/networkAgent.js:260
#: ../js/ui/components/networkAgent.js:278
msgid "Username: "
msgstr "Používateľské meno: "
#: ../js/gdm/loginDialog.js:1173
#: ../js/gdm/loginDialog.js:1158
msgid "Login Window"
msgstr "Prihlasovacie okno"
@ -444,21 +451,16 @@ msgstr "Reštartovať"
msgid "Power Off"
msgstr "Vypnúť"
#: ../js/gdm/util.js:249
#: ../js/gdm/util.js:247
msgid "Authentication error"
msgstr "Chyba pri overovaní totožnosti"
#. Translators: this message is shown below the password entry field
#. to indicate the user can swipe their finger instead
#: ../js/gdm/util.js:366
#: ../js/gdm/util.js:364
msgid "(or swipe finger)"
msgstr "(alebo prejdite prstom)"
#: ../js/gdm/util.js:391
#, c-format
msgid "(e.g., user or %s)"
msgstr "(napr., používateľ alebo %s)"
#: ../js/misc/util.js:97
msgid "Command not found"
msgstr "Príkaz nebol nájdený"
@ -474,23 +476,23 @@ msgstr "Nepodarilo sa analyzovať príkaz:"
msgid "Execution of '%s' failed:"
msgstr "Spustenie „%s“ zlyhalo:"
#: ../js/ui/appDisplay.js:349
#: ../js/ui/appDisplay.js:361
msgid "Frequent"
msgstr "Často používané"
#: ../js/ui/appDisplay.js:356
#: ../js/ui/appDisplay.js:368
msgid "All"
msgstr "Všetky"
#: ../js/ui/appDisplay.js:914
#: ../js/ui/appDisplay.js:960
msgid "New Window"
msgstr "Nové okno"
#: ../js/ui/appDisplay.js:917 ../js/ui/dash.js:284
#: ../js/ui/appDisplay.js:963 ../js/ui/dash.js:284
msgid "Remove from Favorites"
msgstr "Odstrániť z obľúbených"
#: ../js/ui/appDisplay.js:918
#: ../js/ui/appDisplay.js:964
msgid "Add to Favorites"
msgstr "Pridať do obľúbených"
@ -527,7 +529,7 @@ msgctxt "event list time"
msgid "%H\\u2236%M"
msgstr "%H\\u2236%M"
#. 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
#: ../js/ui/calendar.js:77
@ -629,35 +631,35 @@ msgid "S"
msgstr "So"
#. Translators: Text to show if there are no events
#: ../js/ui/calendar.js:720
#: ../js/ui/calendar.js:735
msgid "Nothing Scheduled"
msgstr "Žiadne naplánované udalosti"
#. Translators: Shown on calendar heading when selected day occurs on current year
#: ../js/ui/calendar.js:736
#: ../js/ui/calendar.js:751
msgctxt "calendar heading"
msgid "%A, %B %d"
msgstr "%A, %e. %B"
#. Translators: Shown on calendar heading when selected day occurs on different year
#: ../js/ui/calendar.js:739
#: ../js/ui/calendar.js:754
msgctxt "calendar heading"
msgid "%A, %B %d, %Y"
msgstr "%A, %e. %B %Y"
#: ../js/ui/calendar.js:749
#: ../js/ui/calendar.js:764
msgid "Today"
msgstr "Dnes"
#: ../js/ui/calendar.js:753
#: ../js/ui/calendar.js:768
msgid "Tomorrow"
msgstr "Zajtra"
#: ../js/ui/calendar.js:764
#: ../js/ui/calendar.js:779
msgid "This week"
msgstr "Tento týždeň"
#: ../js/ui/calendar.js:772
#: ../js/ui/calendar.js:787
msgid "Next week"
msgstr "Ďalší týždeň"
@ -683,11 +685,11 @@ msgstr "Otvoriť pomocou programu %s"
msgid "Eject"
msgstr "Vysunúť"
#: ../js/ui/components/keyring.js:82 ../js/ui/components/polkitAgent.js:268
#: ../js/ui/components/keyring.js:88 ../js/ui/components/polkitAgent.js:280
msgid "Password:"
msgstr "Heslo:"
#: ../js/ui/components/keyring.js:101
#: ../js/ui/components/keyring.js:107
msgid "Type again:"
msgstr "Zadajte znovu:"
@ -767,16 +769,16 @@ msgstr "Heslo k mobilnej sieti"
msgid "A password is required to connect to '%s'."
msgstr "Na pripojenie k „%s“ sa požaduje heslo."
#: ../js/ui/components/polkitAgent.js:55
#: ../js/ui/components/polkitAgent.js:54
msgid "Authentication Required"
msgstr "Požaduje sa overenie totožnosti"
# PŠ: ináč toto je riadna hlúposť, keďže sa pýta heslo používateľa "root"
#: ../js/ui/components/polkitAgent.js:93
#: ../js/ui/components/polkitAgent.js:92
msgid "Administrator"
msgstr "Správca"
#: ../js/ui/components/polkitAgent.js:165
#: ../js/ui/components/polkitAgent.js:170
msgid "Authenticate"
msgstr "Overiť totožnosť"
@ -784,13 +786,13 @@ msgstr "Overiť totožnosť"
#. * requested authentication was not gained; this can happen
#. * because of an authentication error (like invalid password),
#. * for instance.
#: ../js/ui/components/polkitAgent.js:256 ../js/ui/shellMountOperation.js:383
#: ../js/ui/components/polkitAgent.js:266 ../js/ui/shellMountOperation.js:383
msgid "Sorry, that didn't work. Please try again."
msgstr "Prepáčte, ale nezabralo to. Skúste to, prosím, znova."
# %d je datum, %t je cas
#. Translators: this is a filename used for screencast recording
#: ../js/ui/components/recorder.js:48
#: ../js/ui/components/recorder.js:47
#, no-c-format
msgid "Screencast from %d %t"
msgstr "Záznam videa obrazovky dňa %d o %t"
@ -1049,22 +1051,22 @@ msgstr "Zobrazí aplikácie"
msgid "Dash"
msgstr "Dok"
#: ../js/ui/dateMenu.js:91
#: ../js/ui/dateMenu.js:86
msgid "Open Calendar"
msgstr "Otvoriť kalendár"
#: ../js/ui/dateMenu.js:96
#: ../js/ui/dateMenu.js:90
msgid "Open Clocks"
msgstr "Otvoriť hodiny"
#: ../js/ui/dateMenu.js:105
#: ../js/ui/dateMenu.js:97
msgid "Date & Time Settings"
msgstr "Nastavenia dátumu a času"
#. 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").
#.
#: ../js/ui/dateMenu.js:215
#: ../js/ui/dateMenu.js:208
msgid "%A %B %e, %Y"
msgstr "%A, %e. %B %Y"
@ -1178,50 +1180,52 @@ msgstr "Stiahnuť a nainštalovať „%s“ z extensions.gnome.org?"
msgid "Keyboard"
msgstr "Klávesnica"
#: ../js/ui/lookingGlass.js:693
#: ../js/ui/lookingGlass.js:689
msgid "No extensions installed"
msgstr "Žiadne nainštalované rozšírenia"
#. Translators: argument is an extension UUID.
#: ../js/ui/lookingGlass.js:747
#: ../js/ui/lookingGlass.js:743
#, c-format
msgid "%s has not emitted any errors."
msgstr "%s nevyslal žiadnu chybu."
#: ../js/ui/lookingGlass.js:753
#: ../js/ui/lookingGlass.js:749
msgid "Hide Errors"
msgstr "Skryť chyby"
#: ../js/ui/lookingGlass.js:757 ../js/ui/lookingGlass.js:817
#: ../js/ui/lookingGlass.js:753 ../js/ui/lookingGlass.js:813
msgid "Show Errors"
msgstr "Zobraziť chyby"
#: ../js/ui/lookingGlass.js:766
#: ../js/ui/lookingGlass.js:762
msgid "Enabled"
msgstr "Povolené"
#: ../js/ui/lookingGlass.js:769
#. translators:
#. * The device has been disabled
#: ../js/ui/lookingGlass.js:765 ../src/gvc/gvc-mixer-control.c:1830
msgid "Disabled"
msgstr "Zakázané"
#: ../js/ui/lookingGlass.js:771
#: ../js/ui/lookingGlass.js:767
msgid "Error"
msgstr "Chyba"
#: ../js/ui/lookingGlass.js:773
#: ../js/ui/lookingGlass.js:769
msgid "Out of date"
msgstr "Neaktuálne"
#: ../js/ui/lookingGlass.js:775
#: ../js/ui/lookingGlass.js:771
msgid "Downloading"
msgstr "Sťahuje sa"
# PK: ide tu o zdrojovy kod?
#: ../js/ui/lookingGlass.js:799
#: ../js/ui/lookingGlass.js:795
msgid "View Source"
msgstr "Zobraziť zdroj"
#: ../js/ui/lookingGlass.js:808
#: ../js/ui/lookingGlass.js:804
msgid "Web Page"
msgstr "Webová stránka"
@ -1241,26 +1245,26 @@ msgstr "Vymazať správy"
msgid "Notification Settings"
msgstr "Nastavenia oznámení"
#: ../js/ui/messageTray.js:1709
#: ../js/ui/messageTray.js:1707
msgid "No Messages"
msgstr "Žiadne správy"
# DK: zvazoval som pouzit "Panel správ"
# neviem co bude vhodnejsie ako preklad "tray"
#: ../js/ui/messageTray.js:1782
#: ../js/ui/messageTray.js:1780
msgid "Message Tray"
msgstr "Lišta správ"
#: ../js/ui/messageTray.js:2810
#: ../js/ui/messageTray.js:2800
msgid "System Information"
msgstr "Informácie o systéme"
#: ../js/ui/notificationDaemon.js:629 ../src/shell-app.c:374
#: ../js/ui/notificationDaemon.js:629 ../src/shell-app.c:378
msgctxt "program"
msgid "Unknown"
msgstr "Neznámy"
#: ../js/ui/overviewControls.js:463 ../js/ui/screenShield.js:149
#: ../js/ui/overviewControls.js:472 ../js/ui/screenShield.js:150
#, c-format
msgid "%d new message"
msgid_plural "%d new messages"
@ -1268,11 +1272,11 @@ msgstr[0] "%d nových správ"
msgstr[1] "%d nová správa"
msgstr[2] "%d nové správy"
#: ../js/ui/overview.js:84
#: ../js/ui/overview.js:82
msgid "Undo"
msgstr "Vrátiť"
#: ../js/ui/overview.js:129
#: ../js/ui/overview.js:127
msgid "Overview"
msgstr "Prehľad"
@ -1281,21 +1285,21 @@ msgstr "Prehľad"
#. in the search entry when no search is
#. active; it should not exceed ~30
#. characters.
#: ../js/ui/overview.js:271
#: ../js/ui/overview.js:258
msgid "Type to search…"
msgstr "Zadajte text na vyhľadanie…"
#: ../js/ui/panel.js:612
#: ../js/ui/panel.js:642
msgid "Quit"
msgstr "Ukončiť"
#. Translators: If there is no suitable word for "Activities"
#. in your language, you can use the word for "Overview".
#: ../js/ui/panel.js:636
#: ../js/ui/panel.js:693
msgid "Activities"
msgstr "Aktivity"
#: ../js/ui/panel.js:933
#: ../js/ui/panel.js:989
msgid "Top Bar"
msgstr "Horná lišta"
@ -1304,15 +1308,15 @@ msgstr "Horná lišta"
#. "ON" and "OFF") or "toggle-switch-intl" (for toggle
#. switches containing "◯" and "|"). Other values will
#. simply result in invisible toggle switches.
#: ../js/ui/popupMenu.js:727
#: ../js/ui/popupMenu.js:738
msgid "toggle-switch-us"
msgstr "toggle-switch-intl"
#: ../js/ui/runDialog.js:73
#: ../js/ui/runDialog.js:74
msgid "Enter a Command"
msgstr "Zadajte príkaz"
#: ../js/ui/runDialog.js:109
#: ../js/ui/runDialog.js:110
msgid "Close"
msgstr "Zavrieť"
@ -1321,11 +1325,11 @@ msgstr "Zavrieť"
# v ostatnych retazcoch je pouzite %e, tak to bude asi OK
#. Translators: This is a time format for a date in
#. long format
#: ../js/ui/screenShield.js:86
#: ../js/ui/screenShield.js:87
msgid "%A, %B %d"
msgstr "%A, %e. %B"
#: ../js/ui/screenShield.js:151
#: ../js/ui/screenShield.js:152
#, c-format
msgid "%d new notification"
msgid_plural "%d new notifications"
@ -1333,11 +1337,11 @@ msgstr[0] "%d nových oznámení"
msgstr[1] "%d nové oznámenie"
msgstr[2] "%d nové oznámenia"
#: ../js/ui/screenShield.js:438 ../js/ui/userMenu.js:807
#: ../js/ui/screenShield.js:449 ../js/ui/userMenu.js:807
msgid "Lock"
msgstr "Uzamknúť"
#: ../js/ui/screenShield.js:637
#: ../js/ui/screenShield.js:652
msgid "GNOME needs to lock the screen"
msgstr "Prostredie GNOME vyžaduje uzamknutie obrazovky"
@ -1348,11 +1352,11 @@ msgstr "Prostredie GNOME vyžaduje uzamknutie obrazovky"
#.
#. XXX: another option is to kick the user into the gdm login
#. screen, where we're not affected by grabs
#: ../js/ui/screenShield.js:758 ../js/ui/screenShield.js:1194
#: ../js/ui/screenShield.js:773 ../js/ui/screenShield.js:1213
msgid "Unable to lock"
msgstr "Nepodarilo sa uzamknúť obrazovku"
#: ../js/ui/screenShield.js:759 ../js/ui/screenShield.js:1195
#: ../js/ui/screenShield.js:774 ../js/ui/screenShield.js:1214
msgid "Lock was blocked by an application"
msgstr "Uzamknutie bolo zablokované aplikáciou"
@ -1364,19 +1368,19 @@ msgstr "Hľadá sa…"
msgid "No results."
msgstr "Žiadne výsledky."
#: ../js/ui/shellEntry.js:29
#: ../js/ui/shellEntry.js:27
msgid "Copy"
msgstr "Kopírovať"
#: ../js/ui/shellEntry.js:34
#: ../js/ui/shellEntry.js:32
msgid "Paste"
msgstr "Prilepiť"
#: ../js/ui/shellEntry.js:106
#: ../js/ui/shellEntry.js:99
msgid "Show Text"
msgstr "Zobraziť text"
#: ../js/ui/shellEntry.js:108
#: ../js/ui/shellEntry.js:101
msgid "Hide Text"
msgstr "Skryť text"
@ -1388,7 +1392,7 @@ msgstr "Heslo"
msgid "Remember Password"
msgstr "Zapamätať heslo"
#: ../js/ui/shellMountOperation.js:403 ../js/ui/unlockDialog.js:113
#: ../js/ui/shellMountOperation.js:403 ../js/ui/unlockDialog.js:109
msgid "Unlock"
msgstr "Odblokovať"
@ -1446,7 +1450,7 @@ msgstr "Veľký text"
#: ../js/ui/status/bluetooth.js:28 ../js/ui/status/bluetooth.js:32
#: ../js/ui/status/bluetooth.js:289 ../js/ui/status/bluetooth.js:321
#: ../js/ui/status/bluetooth.js:357 ../js/ui/status/bluetooth.js:388
#: ../js/ui/status/network.js:826
#: ../js/ui/status/network.js:739
msgid "Bluetooth"
msgstr "Bluetooth"
@ -1467,7 +1471,7 @@ msgid "Bluetooth Settings"
msgstr "Nastavenia Bluetooth"
#. TRANSLATORS: this means that bluetooth was disabled by hardware rfkill
#: ../js/ui/status/bluetooth.js:104 ../js/ui/status/network.js:178
#: ../js/ui/status/bluetooth.js:104 ../js/ui/status/network.js:142
msgid "hardware disabled"
msgstr "hardvér zakázaný"
@ -1475,12 +1479,12 @@ msgstr "hardvér zakázaný"
msgid "Connection"
msgstr "Pripojenie"
#: ../js/ui/status/bluetooth.js:208 ../js/ui/status/network.js:460
#: ../js/ui/status/bluetooth.js:208 ../js/ui/status/network.js:404
msgid "disconnecting..."
msgstr "odpája sa…"
#: ../js/ui/status/bluetooth.js:221 ../js/ui/status/network.js:466
#: ../js/ui/status/network.js:1546
#: ../js/ui/status/bluetooth.js:221 ../js/ui/status/network.js:410
#: ../js/ui/status/network.js:1343
msgid "connecting..."
msgstr "pripája sa…"
@ -1536,8 +1540,9 @@ msgstr "Zariadenie %s sa chce spárovať s týmto počítačom"
#: ../js/ui/status/bluetooth.js:366
#, c-format
msgid "Please confirm whether the PIN '%06d' matches the one on the device."
msgstr "Prosím, potvrďte, či sa PIN „%06d“ zhoduje s tým na zariadení."
msgid ""
"Please confirm whether the Passkey '%06d' matches the one on the device."
msgstr "Prosím, potvrďte, či sa heslo „%06d“ zhoduje s tým na zariadení."
#. Translators: this is the verb, not the noun
#: ../js/ui/status/bluetooth.js:369
@ -1574,117 +1579,91 @@ msgid "Volume, network, battery"
msgstr "Hlasitosť, sieť, batéria"
# zariadenie
#: ../js/ui/status/network.js:104
#: ../js/ui/status/network.js:75
msgid "<unknown>"
msgstr "<neznáme>"
#: ../js/ui/status/network.js:127
msgid "Wi-Fi"
msgstr "Wi-Fi"
#. Translators: this indicates that wireless or wwan is disabled by hardware killswitch
#: ../js/ui/status/network.js:200
#: ../js/ui/status/network.js:164
msgid "disabled"
msgstr "zakázané"
#. Translators: this is for network devices that are physically present but are not
#. under NetworkManager's control (and thus cannot be used in the menu)
#: ../js/ui/status/network.js:458
#: ../js/ui/status/network.js:402
msgid "unmanaged"
msgstr "nespravované"
#. Translators: this is for network connections that require some kind of key or password
#: ../js/ui/status/network.js:469 ../js/ui/status/network.js:1549
#: ../js/ui/status/network.js:413 ../js/ui/status/network.js:1346
msgid "authentication required"
msgstr "požaduje sa overenie totožnosti"
#. Translators: this is for devices that require some kind of firmware or kernel
#. module, which is missing
#: ../js/ui/status/network.js:479
#: ../js/ui/status/network.js:423
msgid "firmware missing"
msgstr "chýba firmvér"
#. Translators: this is for wired network devices that are physically disconnected
#: ../js/ui/status/network.js:486
#: ../js/ui/status/network.js:430
msgid "cable unplugged"
msgstr "kábel odpojený"
#. Translators: this is for a network device that cannot be activated (for example it
#. is disabled by rfkill, or it has no coverage
#: ../js/ui/status/network.js:491
#: ../js/ui/status/network.js:435
msgid "unavailable"
msgstr "nedostupné"
#: ../js/ui/status/network.js:493 ../js/ui/status/network.js:1551
#: ../js/ui/status/network.js:437 ../js/ui/status/network.js:1348
msgid "connection failed"
msgstr "pripojenie zlyhalo"
#: ../js/ui/status/network.js:552 ../js/ui/status/network.js:1435
#: ../js/ui/status/network.js:1627
#: ../js/ui/status/network.js:490 ../js/ui/status/network.js:1236
#: ../js/ui/status/network.js:1424
msgid "More…"
msgstr "Viac…"
#. TRANSLATORS: this is the indication that a connection for another logged in user is active,
#. and we cannot access its settings (including the name)
#: ../js/ui/status/network.js:588 ../js/ui/status/network.js:1365
#: ../js/ui/status/network.js:518 ../js/ui/status/network.js:1191
msgid "Connected (private)"
msgstr "Pripojené (súkromne)"
#: ../js/ui/status/network.js:667
#: ../js/ui/status/network.js:597
msgid "Wired"
msgstr "Drôtové pripojenie"
#: ../js/ui/status/network.js:668
msgid "Auto Ethernet"
msgstr "Automatický ethernet"
#: ../js/ui/status/network.js:695
#: ../js/ui/status/network.js:611
msgid "Mobile broadband"
msgstr "Širokopásmové pripojenie"
#: ../js/ui/status/network.js:728
msgid "Auto broadband"
msgstr "Automatické širokopásmové pripojenie"
#: ../js/ui/status/network.js:731
msgid "Auto dial-up"
msgstr "Automatické vytáčané pripojenie"
#. TRANSLATORS: this the automatic wireless connection name (including the network name)
#: ../js/ui/status/network.js:861 ../js/ui/status/network.js:1382
#, c-format
msgid "Auto %s"
msgstr "Automatické pripojenie %s"
#: ../js/ui/status/network.js:863
msgid "Auto bluetooth"
msgstr "Automatický bluetooth"
#: ../js/ui/status/network.js:1384
msgid "Auto wireless"
msgstr "Automatická bezdrôtová sieť"
#: ../js/ui/status/network.js:1729
#: ../js/ui/status/network.js:1522
msgid "Enable networking"
msgstr "Povoliť sieť"
#: ../js/ui/status/network.js:1771
msgid "Wi-Fi"
msgstr "Wi-Fi"
#: ../js/ui/status/network.js:1790
#: ../js/ui/status/network.js:1583
msgid "Network Settings"
msgstr "Nastavenia siete"
#: ../js/ui/status/network.js:1807
#: ../js/ui/status/network.js:1600
msgid "Network Manager"
msgstr "Správca siete"
#: ../js/ui/status/network.js:1897
#: ../js/ui/status/network.js:1690
msgid "Connection failed"
msgstr "Pripojenie zlyhalo"
#: ../js/ui/status/network.js:1898
#: ../js/ui/status/network.js:1691
msgid "Activation of network connection failed"
msgstr "Aktivácia pripojenia k sieti zlyhala"
#: ../js/ui/status/network.js:2276
#: ../js/ui/status/network.js:2047
msgid "Networking is disabled"
msgstr "Sieť je zakázaná"
@ -1802,11 +1781,11 @@ msgstr "Hlasitosť"
msgid "Microphone"
msgstr "Mikrofón"
#: ../js/ui/unlockDialog.js:124
#: ../js/ui/unlockDialog.js:120
msgid "Log in as another user"
msgstr "Prihlásiť ako iný používateľ"
#: ../js/ui/unlockDialog.js:145
#: ../js/ui/unlockDialog.js:141
msgid "Unlock Window"
msgstr "Odomykacie okno"
@ -1915,32 +1894,56 @@ msgstr "Program „%s“ je pripravený"
msgid "Evolution Calendar"
msgstr "Kalendár Evolution"
#: ../src/main.c:347
#. translators:
#. * The number of sound outputs on a particular device
#: ../src/gvc/gvc-mixer-control.c:1837
#, c-format
msgid "%u Output"
msgid_plural "%u Outputs"
msgstr[0] "%u výstupov"
msgstr[1] "%u výstup"
msgstr[2] "%u výstupy"
#. translators:
#. * The number of sound inputs on a particular device
#: ../src/gvc/gvc-mixer-control.c:1847
#, c-format
msgid "%u Input"
msgid_plural "%u Inputs"
msgstr[0] "%u vstupov"
msgstr[1] "%u vstup"
msgstr[2] "%u vstupy"
#: ../src/gvc/gvc-mixer-control.c:2373
msgid "System Sounds"
msgstr "Systémové zvuky"
#: ../src/main.c:372
msgid "Print version"
msgstr "Verzia pre tlač"
#: ../src/main.c:353
#: ../src/main.c:378
msgid "Mode used by GDM for login screen"
msgstr "Režim používaný GDM pre prihlasovaciu obrazovku"
#: ../src/main.c:359
#: ../src/main.c:384
msgid "Use a specific mode, e.g. \"gdm\" for login screen"
msgstr "Použitie zvláštneho režimu, napr. „gdm“ pre prihlasovaciu obrazovku"
#: ../src/main.c:365
#: ../src/main.c:390
msgid "List possible modes"
msgstr "Zoznam možných režimov"
#: ../src/shell-app.c:622
#: ../src/shell-app.c:626
#, c-format
msgid "Failed to launch '%s'"
msgstr "Zlyhalo spustenie „%s“"
#: ../src/shell-keyring-prompt.c:708
#: ../src/shell-keyring-prompt.c:714
msgid "Passwords do not match."
msgstr "Heslá sa nezhodujú."
#: ../src/shell-keyring-prompt.c:716
#: ../src/shell-keyring-prompt.c:722
msgid "Password cannot be blank"
msgstr "Heslo nemôže byť prázdne"
@ -1948,3 +1951,35 @@ msgstr "Heslo nemôže byť prázdne"
#: ../src/shell-polkit-authentication-agent.c:343
msgid "Authentication dialog was dismissed by the user"
msgstr "Dialógové okno overenia totožnosti bolo zatvorené používateľom"
#~ msgid "Whether to collect stats about applications usage"
#~ msgstr "Či sa majú zhromažďovať štatistické údaje o používaní aplikácií"
#~ msgid ""
#~ "The shell normally monitors active applications in order to present the "
#~ "most used ones (e.g. in launchers). While this data will be kept private, "
#~ "you may want to disable this for privacy reasons. Please note that doing "
#~ "so won't remove already saved data."
#~ msgstr ""
#~ "Prostredie shell obvykle sleduje aktívne aplikácie, aby mohlo ponúkať "
#~ "najpoužívanejšie z nich (napr. v spúšťačoch). Aj keď sú tieto údaje "
#~ "uchovávané v tajnosti, môžete ich kvôli lepšej ochrane súkromia zakázať. "
#~ "Ak tak urobíte, údaje, ktoré už boli uložené, zostanú zachované."
#~ msgid "Auto Ethernet"
#~ msgstr "Automatický ethernet"
#~ msgid "Auto broadband"
#~ msgstr "Automatické širokopásmové pripojenie"
#~ msgid "Auto dial-up"
#~ msgstr "Automatické vytáčané pripojenie"
#~ msgid "Auto %s"
#~ msgstr "Automatické pripojenie %s"
#~ msgid "Auto bluetooth"
#~ msgstr "Automatický bluetooth"
#~ msgid "Auto wireless"
#~ msgstr "Automatická bezdrôtová sieť"

407
po/sl.po

File diff suppressed because it is too large Load Diff

163
po/sr.po
View File

@ -8,7 +8,7 @@ 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: 2013-03-04 08:38+0000\n"
"POT-Creation-Date: 2013-03-31 01:48+0000\n"
"PO-Revision-Date: 2013-03-08 20:26+0200\n"
"Last-Translator: Мирослав Николић <miroslavnikolic@rocketmail.com>\n"
"Language-Team: Serbian <gnom@prevod.org>\n"
@ -16,8 +16,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=4; plural=n==1? 3 : n%10==1 && n%100!=11 ? 0 : "
"n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n"
"Plural-Forms: nplurals=4; plural=n==1? 3 : n%10==1 && n%100!=11 ? 0 : n"
"%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n"
"X-Project-Style: gnome\n"
#: ../data/50-gnome-shell-screenshot.xml.in.h:1
@ -365,53 +365,52 @@ msgid "Select an extension to configure using the combobox above."
msgstr "Изаберите проширење за подешавање користећи прозорче за избор."
#: ../js/gdm/loginDialog.js:405
#| msgid "Session..."
msgid "Session…"
msgstr "Сесија…"
#. 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:629
#: ../js/gdm/loginDialog.js:630
msgid "Not listed?"
msgstr "Није на списку?"
#: ../js/gdm/loginDialog.js:783 ../js/ui/components/networkAgent.js:137
#: ../js/gdm/loginDialog.js:786 ../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:126
#: ../js/ui/userMenu.js:934
#: ../js/ui/status/bluetooth.js:415 ../js/ui/unlockDialog.js:99
#: ../js/ui/userMenu.js:938
msgid "Cancel"
msgstr "Откажи"
#: ../js/gdm/loginDialog.js:799
#: ../js/gdm/loginDialog.js:802
msgctxt "button"
msgid "Sign In"
msgstr "Пријави ме"
#: ../js/gdm/loginDialog.js:799
#: ../js/gdm/loginDialog.js:802
msgid "Next"
msgstr "Даље"
#. 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:904 ../js/ui/components/networkAgent.js:260
#: ../js/gdm/loginDialog.js:917 ../js/ui/components/networkAgent.js:260
#: ../js/ui/components/networkAgent.js:278
msgid "Username: "
msgstr "Корисничко име: "
#: ../js/gdm/loginDialog.js:1157
#: ../js/gdm/loginDialog.js:1173
msgid "Login Window"
msgstr "Прозор за пријављивање"
#. Translators: accessible name of the power menu in the login screen
#: ../js/gdm/powerMenu.js:36
msgid "Power"
msgstr "Угаси"
msgstr "Напајање"
#: ../js/gdm/powerMenu.js:93 ../js/ui/userMenu.js:695 ../js/ui/userMenu.js:699
#: ../js/ui/userMenu.js:815
#: ../js/gdm/powerMenu.js:93 ../js/ui/userMenu.js:696 ../js/ui/userMenu.js:700
#: ../js/ui/userMenu.js:816
msgid "Suspend"
msgstr "Обустави"
@ -419,58 +418,58 @@ msgstr "Обустави"
msgid "Restart"
msgstr "Поново покрени"
#: ../js/gdm/powerMenu.js:103 ../js/ui/userMenu.js:697
#: ../js/ui/userMenu.js:699 ../js/ui/userMenu.js:814 ../js/ui/userMenu.js:938
#: ../js/gdm/powerMenu.js:103 ../js/ui/userMenu.js:698
#: ../js/ui/userMenu.js:700 ../js/ui/userMenu.js:815 ../js/ui/userMenu.js:942
msgid "Power Off"
msgstr "Угаси"
msgstr "Искључи"
#: ../js/gdm/util.js:182
#: ../js/gdm/util.js:249
msgid "Authentication error"
msgstr "Грешка потврђивања идентитета"
#. Translators: this message is shown below the password entry field
#. to indicate the user can swipe their finger instead
#: ../js/gdm/util.js:299
#: ../js/gdm/util.js:366
msgid "(or swipe finger)"
msgstr "(или лупите прст)"
#: ../js/gdm/util.js:324
#: ../js/gdm/util.js:391
#, c-format
msgid "(e.g., user or %s)"
msgstr "(нпр., корисник или %s)"
#: ../js/misc/util.js:94
#: ../js/misc/util.js:97
msgid "Command not found"
msgstr "Наредба није нађена"
#. Replace "Error invoking GLib.shell_parse_argv: " with
#. something nicer
#: ../js/misc/util.js:127
#: ../js/misc/util.js:130
msgid "Could not parse command:"
msgstr "Не могу да обрадим наредбу:"
#: ../js/misc/util.js:135
#: ../js/misc/util.js:138
#, c-format
msgid "Execution of '%s' failed:"
msgstr "Није успело покретање „%s“:"
#: ../js/ui/appDisplay.js:348
#: ../js/ui/appDisplay.js:349
msgid "Frequent"
msgstr "Често"
#: ../js/ui/appDisplay.js:355
#: ../js/ui/appDisplay.js:356
msgid "All"
msgstr "Све"
#: ../js/ui/appDisplay.js:913
#: ../js/ui/appDisplay.js:914
msgid "New Window"
msgstr "Нови прозор"
#: ../js/ui/appDisplay.js:916 ../js/ui/dash.js:284
#: ../js/ui/appDisplay.js:917 ../js/ui/dash.js:284
msgid "Remove from Favorites"
msgstr "Уклони из омиљених"
#: ../js/ui/appDisplay.js:917
#: ../js/ui/appDisplay.js:918
msgid "Add to Favorites"
msgstr "Додај у омиљене"
@ -484,7 +483,7 @@ msgstr "„%s“ је додат међу омиљене."
msgid "%s has been removed from your favorites."
msgstr "„%s“ је уклоњен из омиљених."
#: ../js/ui/backgroundMenu.js:19 ../js/ui/userMenu.js:788
#: ../js/ui/backgroundMenu.js:19 ../js/ui/userMenu.js:789
msgid "Settings"
msgstr "Подешавања"
@ -507,7 +506,7 @@ msgctxt "event list time"
msgid "%H\\u2236%M"
msgstr "%H\\u2236%M"
#. 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
#: ../js/ui/calendar.js:77
@ -609,35 +608,35 @@ msgid "S"
msgstr "Суб"
#. Translators: Text to show if there are no events
#: ../js/ui/calendar.js:692
#: ../js/ui/calendar.js:720
msgid "Nothing Scheduled"
msgstr "Ништа планирано"
#. Translators: Shown on calendar heading when selected day occurs on current year
#: ../js/ui/calendar.js:708
#: ../js/ui/calendar.js:736
msgctxt "calendar heading"
msgid "%A, %B %d"
msgstr "%A, %B %d"
#. Translators: Shown on calendar heading when selected day occurs on different year
#: ../js/ui/calendar.js:711
#: ../js/ui/calendar.js:739
msgctxt "calendar heading"
msgid "%A, %B %d, %Y"
msgstr "%A, %B %d, %Y"
#: ../js/ui/calendar.js:721
#: ../js/ui/calendar.js:749
msgid "Today"
msgstr "Данас"
#: ../js/ui/calendar.js:725
#: ../js/ui/calendar.js:753
msgid "Tomorrow"
msgstr "Сутра"
#: ../js/ui/calendar.js:736
#: ../js/ui/calendar.js:764
msgid "This week"
msgstr "Ове недеље"
#: ../js/ui/calendar.js:744
#: ../js/ui/calendar.js:772
msgid "Next week"
msgstr "Следеће недеље"
@ -653,12 +652,12 @@ msgstr "Спољни уређај је искључен"
msgid "Removable Devices"
msgstr "Уклоњиви уређаји"
#: ../js/ui/components/autorunManager.js:593
#: ../js/ui/components/autorunManager.js:594
#, c-format
msgid "Open with %s"
msgstr "Отвори програмом %s"
#: ../js/ui/components/autorunManager.js:619
#: ../js/ui/components/autorunManager.js:620
msgid "Eject"
msgstr "Избаци"
@ -1038,7 +1037,7 @@ msgstr "Подешавања датума и времена"
#. 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").
#.
#: ../js/ui/dateMenu.js:205
#: ../js/ui/dateMenu.js:215
msgid "%A %B %e, %Y"
msgstr "%A, %e. %b., %R"
@ -1213,7 +1212,6 @@ msgid "Remove"
msgstr "Уклони"
#: ../js/ui/messageTray.js:1501
#| msgid "No Messages"
msgid "Clear Messages"
msgstr "Очисти поруке"
@ -1221,15 +1219,15 @@ msgstr "Очисти поруке"
msgid "Notification Settings"
msgstr "Поставке обавештења"
#: ../js/ui/messageTray.js:1707
#: ../js/ui/messageTray.js:1709
msgid "No Messages"
msgstr "Нема порука"
#: ../js/ui/messageTray.js:1787
#: ../js/ui/messageTray.js:1782
msgid "Message Tray"
msgstr "Фиока порука"
#: ../js/ui/messageTray.js:2864
#: ../js/ui/messageTray.js:2810
msgid "System Information"
msgstr "Подаци о систему"
@ -1238,7 +1236,7 @@ msgctxt "program"
msgid "Unknown"
msgstr "Непознат"
#: ../js/ui/overviewControls.js:460 ../js/ui/screenShield.js:153
#: ../js/ui/overviewControls.js:463 ../js/ui/screenShield.js:149
#, c-format
msgid "%d new message"
msgid_plural "%d new messages"
@ -1247,7 +1245,7 @@ msgstr[1] "%d нове поруке"
msgstr[2] "%d нових порука"
msgstr[3] "Једна нова порука"
#: ../js/ui/overview.js:82
#: ../js/ui/overview.js:84
msgid "Undo"
msgstr "Опозови"
@ -1259,22 +1257,21 @@ msgstr "Преглед"
#. in the search entry when no search is
#. active; it should not exceed ~30
#. characters.
#: ../js/ui/overview.js:284
#| msgid "Type to search..."
#: ../js/ui/overview.js:271
msgid "Type to search…"
msgstr "Упишите текст за претрагу…"
#: ../js/ui/panel.js:613
#: ../js/ui/panel.js:612
msgid "Quit"
msgstr "Изађи"
#. Translators: If there is no suitable word for "Activities"
#. in your language, you can use the word for "Overview".
#: ../js/ui/panel.js:642
#: ../js/ui/panel.js:636
msgid "Activities"
msgstr "Активности"
#: ../js/ui/panel.js:983
#: ../js/ui/panel.js:933
msgid "Top Bar"
msgstr "Горња трака"
@ -1287,21 +1284,21 @@ msgstr "Горња трака"
msgid "toggle-switch-us"
msgstr "toggle-switch-intl"
#: ../js/ui/runDialog.js:205
#: ../js/ui/runDialog.js:73
msgid "Enter a Command"
msgstr "Унесите наредбу"
#: ../js/ui/runDialog.js:241
#: ../js/ui/runDialog.js:109
msgid "Close"
msgstr "Затвори"
#. Translators: This is a time format for a date in
#. long format
#: ../js/ui/screenShield.js:90
#: ../js/ui/screenShield.js:86
msgid "%A, %B %d"
msgstr "%A, %d. %B"
#: ../js/ui/screenShield.js:155
#: ../js/ui/screenShield.js:151
#, c-format
msgid "%d new notification"
msgid_plural "%d new notifications"
@ -1310,11 +1307,11 @@ msgstr[1] "%d нова обавештења"
msgstr[2] "%d нових обавештења"
msgstr[3] "Једно ново обавештење"
#: ../js/ui/screenShield.js:442 ../js/ui/userMenu.js:806
#: ../js/ui/screenShield.js:438 ../js/ui/userMenu.js:807
msgid "Lock"
msgstr "Закључај"
#: ../js/ui/screenShield.js:639
#: ../js/ui/screenShield.js:640
msgid "GNOME needs to lock the screen"
msgstr "Гном мора да закључа екран"
@ -1325,21 +1322,19 @@ msgstr "Гном мора да закључа екран"
#.
#. XXX: another option is to kick the user into the gdm login
#. screen, where we're not affected by grabs
#: ../js/ui/screenShield.js:758 ../js/ui/screenShield.js:1169
#| msgid "Unable to connect to %s"
#: ../js/ui/screenShield.js:761 ../js/ui/screenShield.js:1197
msgid "Unable to lock"
msgstr "Не могу да закључам"
#: ../js/ui/screenShield.js:759 ../js/ui/screenShield.js:1170
#: ../js/ui/screenShield.js:762 ../js/ui/screenShield.js:1198
msgid "Lock was blocked by an application"
msgstr "Неки програм је блокирао закључавање"
#: ../js/ui/searchDisplay.js:431
#| msgid "Searching..."
#: ../js/ui/searchDisplay.js:453
msgid "Searching…"
msgstr "Тражим…"
#: ../js/ui/searchDisplay.js:475
#: ../js/ui/searchDisplay.js:497
msgid "No results."
msgstr "Нема одговарајућих резултата."
@ -1351,11 +1346,11 @@ msgstr "Умножи"
msgid "Paste"
msgstr "Убаци"
#: ../js/ui/shellEntry.js:105
#: ../js/ui/shellEntry.js:106
msgid "Show Text"
msgstr "Прикажи текст"
#: ../js/ui/shellEntry.js:107
#: ../js/ui/shellEntry.js:108
msgid "Hide Text"
msgstr "Сакриј текст"
@ -1367,7 +1362,7 @@ msgstr "Лозинка"
msgid "Remember Password"
msgstr "Запамти лозинку"
#: ../js/ui/shellMountOperation.js:403 ../js/ui/unlockDialog.js:140
#: ../js/ui/shellMountOperation.js:403 ../js/ui/unlockDialog.js:113
msgid "Unlock"
msgstr "Откључај"
@ -1431,12 +1426,10 @@ msgid "Visibility"
msgstr "Видљивост"
#: ../js/ui/status/bluetooth.js:59
#| msgid "Send Files to Device..."
msgid "Send Files to Device…"
msgstr "Пошаљи датотеке на уређај…"
#: ../js/ui/status/bluetooth.js:60
#| msgid "Set Up a New Device..."
msgid "Set Up a New Device…"
msgstr "Подеси нови уређај…"
@ -1463,7 +1456,6 @@ msgid "connecting..."
msgstr "повезујем се..."
#: ../js/ui/status/bluetooth.js:239
#| msgid "Send Files..."
msgid "Send Files…"
msgstr "Пошаљи датотеке…"
@ -1676,7 +1668,6 @@ msgstr "Подешавања напајања"
#. 0 is reported when UPower does not have enough data
#. to estimate battery life
#: ../js/ui/status/power.js:99
#| msgid "Estimating..."
msgid "Estimating…"
msgstr "Приближно…"
@ -1784,11 +1775,11 @@ msgstr "Јачина звука"
msgid "Microphone"
msgstr "Микрофон"
#: ../js/ui/unlockDialog.js:151
#: ../js/ui/unlockDialog.js:124
msgid "Log in as another user"
msgstr "Пријавите се као други корсник"
#: ../js/ui/unlockDialog.js:177
#: ../js/ui/unlockDialog.js:145
msgid "Unlock Window"
msgstr "Откључај прозор"
@ -1816,27 +1807,27 @@ msgstr "Мирује"
msgid "Offline"
msgstr "Ван мреже"
#: ../js/ui/userMenu.js:780
#: ../js/ui/userMenu.js:781
msgid "Notifications"
msgstr "Обавештења"
#: ../js/ui/userMenu.js:796
#: ../js/ui/userMenu.js:797
msgid "Switch User"
msgstr "Промени корисника"
#: ../js/ui/userMenu.js:801
#: ../js/ui/userMenu.js:802
msgid "Log Out"
msgstr "Одјави ме"
#: ../js/ui/userMenu.js:821
#: ../js/ui/userMenu.js:822
msgid "Install Updates & Restart"
msgstr "Инсталирај ажурирања и поново покрени"
#: ../js/ui/userMenu.js:839
#: ../js/ui/userMenu.js:840
msgid "Your chat status will be set to busy"
msgstr "Ваше стање ћаскања ће бити постављено на заузето"
#: ../js/ui/userMenu.js:840
#: ../js/ui/userMenu.js:841
msgid ""
"Notifications are now disabled, including chat messages. Your online status "
"has been adjusted to let others know that you might not see their messages."
@ -1845,20 +1836,22 @@ msgstr ""
"мрежи је подешено тако да ће остали знати да ви не можете видети њихове "
"поруке."
#: ../js/ui/userMenu.js:886
#: ../js/ui/userMenu.js:888
msgid "Other users are logged in."
msgstr "Други корисници су пријављени."
#: ../js/ui/userMenu.js:891
#: ../js/ui/userMenu.js:893
msgid "Shutting down might cause them to lose unsaved work."
msgstr "Искључивање може да доведе до тога да изгубе несачувани рад."
#: ../js/ui/userMenu.js:918
#. Translators: Remote here refers to a remote session, like a ssh login
#: ../js/ui/userMenu.js:921
#, c-format
msgid "%s (remote)"
msgstr "%s (удаљено)"
#: ../js/ui/userMenu.js:920
#. Translators: Console here refers to a tty like a VT console
#: ../js/ui/userMenu.js:924
#, c-format
msgid "%s (console)"
msgstr "%s (љуска)"
@ -1871,7 +1864,7 @@ msgstr "Програми"
msgid "Search"
msgstr "Тражи"
#: ../js/ui/wanda.js:92
#: ../js/ui/wanda.js:77
#, c-format
msgid ""
"Sorry, no wisdom for you today:\n"
@ -1880,7 +1873,7 @@ msgstr ""
"Извините, данас за вас нема мудрости:\n"
"%s"
#: ../js/ui/wanda.js:96
#: ../js/ui/wanda.js:81
#, c-format
msgid "%s the Oracle says"
msgstr "Пророк је рекао %s"

View File

@ -8,7 +8,7 @@ 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: 2013-03-04 08:38+0000\n"
"POT-Creation-Date: 2013-03-31 01:48+0000\n"
"PO-Revision-Date: 2013-03-08 20:26+0200\n"
"Last-Translator: Miroslav Nikolić <miroslavnikolic@rocketmail.com>\n"
"Language-Team: Serbian <gnom@prevod.org>\n"
@ -16,8 +16,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=4; plural=n==1? 3 : n%10==1 && n%100!=11 ? 0 : "
"n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n"
"Plural-Forms: nplurals=4; plural=n==1? 3 : n%10==1 && n%100!=11 ? 0 : n"
"%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n"
"X-Project-Style: gnome\n"
#: ../data/50-gnome-shell-screenshot.xml.in.h:1
@ -365,53 +365,52 @@ msgid "Select an extension to configure using the combobox above."
msgstr "Izaberite proširenje za podešavanje koristeći prozorče za izbor."
#: ../js/gdm/loginDialog.js:405
#| msgid "Session..."
msgid "Session…"
msgstr "Sesija…"
#. 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:629
#: ../js/gdm/loginDialog.js:630
msgid "Not listed?"
msgstr "Nije na spisku?"
#: ../js/gdm/loginDialog.js:783 ../js/ui/components/networkAgent.js:137
#: ../js/gdm/loginDialog.js:786 ../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:126
#: ../js/ui/userMenu.js:934
#: ../js/ui/status/bluetooth.js:415 ../js/ui/unlockDialog.js:99
#: ../js/ui/userMenu.js:938
msgid "Cancel"
msgstr "Otkaži"
#: ../js/gdm/loginDialog.js:799
#: ../js/gdm/loginDialog.js:802
msgctxt "button"
msgid "Sign In"
msgstr "Prijavi me"
#: ../js/gdm/loginDialog.js:799
#: ../js/gdm/loginDialog.js:802
msgid "Next"
msgstr "Dalje"
#. 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:904 ../js/ui/components/networkAgent.js:260
#: ../js/gdm/loginDialog.js:917 ../js/ui/components/networkAgent.js:260
#: ../js/ui/components/networkAgent.js:278
msgid "Username: "
msgstr "Korisničko ime: "
#: ../js/gdm/loginDialog.js:1157
#: ../js/gdm/loginDialog.js:1173
msgid "Login Window"
msgstr "Prozor za prijavljivanje"
#. Translators: accessible name of the power menu in the login screen
#: ../js/gdm/powerMenu.js:36
msgid "Power"
msgstr "Ugasi"
msgstr "Napajanje"
#: ../js/gdm/powerMenu.js:93 ../js/ui/userMenu.js:695 ../js/ui/userMenu.js:699
#: ../js/ui/userMenu.js:815
#: ../js/gdm/powerMenu.js:93 ../js/ui/userMenu.js:696 ../js/ui/userMenu.js:700
#: ../js/ui/userMenu.js:816
msgid "Suspend"
msgstr "Obustavi"
@ -419,58 +418,58 @@ msgstr "Obustavi"
msgid "Restart"
msgstr "Ponovo pokreni"
#: ../js/gdm/powerMenu.js:103 ../js/ui/userMenu.js:697
#: ../js/ui/userMenu.js:699 ../js/ui/userMenu.js:814 ../js/ui/userMenu.js:938
#: ../js/gdm/powerMenu.js:103 ../js/ui/userMenu.js:698
#: ../js/ui/userMenu.js:700 ../js/ui/userMenu.js:815 ../js/ui/userMenu.js:942
msgid "Power Off"
msgstr "Ugasi"
msgstr "Isključi"
#: ../js/gdm/util.js:182
#: ../js/gdm/util.js:249
msgid "Authentication error"
msgstr "Greška potvrđivanja identiteta"
#. Translators: this message is shown below the password entry field
#. to indicate the user can swipe their finger instead
#: ../js/gdm/util.js:299
#: ../js/gdm/util.js:366
msgid "(or swipe finger)"
msgstr "(ili lupite prst)"
#: ../js/gdm/util.js:324
#: ../js/gdm/util.js:391
#, c-format
msgid "(e.g., user or %s)"
msgstr "(npr., korisnik ili %s)"
#: ../js/misc/util.js:94
#: ../js/misc/util.js:97
msgid "Command not found"
msgstr "Naredba nije nađena"
#. Replace "Error invoking GLib.shell_parse_argv: " with
#. something nicer
#: ../js/misc/util.js:127
#: ../js/misc/util.js:130
msgid "Could not parse command:"
msgstr "Ne mogu da obradim naredbu:"
#: ../js/misc/util.js:135
#: ../js/misc/util.js:138
#, c-format
msgid "Execution of '%s' failed:"
msgstr "Nije uspelo pokretanje „%s“:"
#: ../js/ui/appDisplay.js:348
#: ../js/ui/appDisplay.js:349
msgid "Frequent"
msgstr "Često"
#: ../js/ui/appDisplay.js:355
#: ../js/ui/appDisplay.js:356
msgid "All"
msgstr "Sve"
#: ../js/ui/appDisplay.js:913
#: ../js/ui/appDisplay.js:914
msgid "New Window"
msgstr "Novi prozor"
#: ../js/ui/appDisplay.js:916 ../js/ui/dash.js:284
#: ../js/ui/appDisplay.js:917 ../js/ui/dash.js:284
msgid "Remove from Favorites"
msgstr "Ukloni iz omiljenih"
#: ../js/ui/appDisplay.js:917
#: ../js/ui/appDisplay.js:918
msgid "Add to Favorites"
msgstr "Dodaj u omiljene"
@ -484,7 +483,7 @@ msgstr "„%s“ je dodat među omiljene."
msgid "%s has been removed from your favorites."
msgstr "„%s“ je uklonjen iz omiljenih."
#: ../js/ui/backgroundMenu.js:19 ../js/ui/userMenu.js:788
#: ../js/ui/backgroundMenu.js:19 ../js/ui/userMenu.js:789
msgid "Settings"
msgstr "Podešavanja"
@ -507,7 +506,7 @@ msgctxt "event list time"
msgid "%H\\u2236%M"
msgstr "%H\\u2236%M"
#. 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
#: ../js/ui/calendar.js:77
@ -609,35 +608,35 @@ msgid "S"
msgstr "Sub"
#. Translators: Text to show if there are no events
#: ../js/ui/calendar.js:692
#: ../js/ui/calendar.js:720
msgid "Nothing Scheduled"
msgstr "Ništa planirano"
#. Translators: Shown on calendar heading when selected day occurs on current year
#: ../js/ui/calendar.js:708
#: ../js/ui/calendar.js:736
msgctxt "calendar heading"
msgid "%A, %B %d"
msgstr "%A, %B %d"
#. Translators: Shown on calendar heading when selected day occurs on different year
#: ../js/ui/calendar.js:711
#: ../js/ui/calendar.js:739
msgctxt "calendar heading"
msgid "%A, %B %d, %Y"
msgstr "%A, %B %d, %Y"
#: ../js/ui/calendar.js:721
#: ../js/ui/calendar.js:749
msgid "Today"
msgstr "Danas"
#: ../js/ui/calendar.js:725
#: ../js/ui/calendar.js:753
msgid "Tomorrow"
msgstr "Sutra"
#: ../js/ui/calendar.js:736
#: ../js/ui/calendar.js:764
msgid "This week"
msgstr "Ove nedelje"
#: ../js/ui/calendar.js:744
#: ../js/ui/calendar.js:772
msgid "Next week"
msgstr "Sledeće nedelje"
@ -653,12 +652,12 @@ msgstr "Spoljni uređaj je isključen"
msgid "Removable Devices"
msgstr "Uklonjivi uređaji"
#: ../js/ui/components/autorunManager.js:593
#: ../js/ui/components/autorunManager.js:594
#, c-format
msgid "Open with %s"
msgstr "Otvori programom %s"
#: ../js/ui/components/autorunManager.js:619
#: ../js/ui/components/autorunManager.js:620
msgid "Eject"
msgstr "Izbaci"
@ -1038,7 +1037,7 @@ msgstr "Podešavanja datuma i vremena"
#. 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").
#.
#: ../js/ui/dateMenu.js:205
#: ../js/ui/dateMenu.js:215
msgid "%A %B %e, %Y"
msgstr "%A, %e. %b., %R"
@ -1213,7 +1212,6 @@ msgid "Remove"
msgstr "Ukloni"
#: ../js/ui/messageTray.js:1501
#| msgid "No Messages"
msgid "Clear Messages"
msgstr "Očisti poruke"
@ -1221,15 +1219,15 @@ msgstr "Očisti poruke"
msgid "Notification Settings"
msgstr "Postavke obaveštenja"
#: ../js/ui/messageTray.js:1707
#: ../js/ui/messageTray.js:1709
msgid "No Messages"
msgstr "Nema poruka"
#: ../js/ui/messageTray.js:1787
#: ../js/ui/messageTray.js:1782
msgid "Message Tray"
msgstr "Fioka poruka"
#: ../js/ui/messageTray.js:2864
#: ../js/ui/messageTray.js:2810
msgid "System Information"
msgstr "Podaci o sistemu"
@ -1238,7 +1236,7 @@ msgctxt "program"
msgid "Unknown"
msgstr "Nepoznat"
#: ../js/ui/overviewControls.js:460 ../js/ui/screenShield.js:153
#: ../js/ui/overviewControls.js:463 ../js/ui/screenShield.js:149
#, c-format
msgid "%d new message"
msgid_plural "%d new messages"
@ -1247,7 +1245,7 @@ msgstr[1] "%d nove poruke"
msgstr[2] "%d novih poruka"
msgstr[3] "Jedna nova poruka"
#: ../js/ui/overview.js:82
#: ../js/ui/overview.js:84
msgid "Undo"
msgstr "Opozovi"
@ -1259,22 +1257,21 @@ msgstr "Pregled"
#. in the search entry when no search is
#. active; it should not exceed ~30
#. characters.
#: ../js/ui/overview.js:284
#| msgid "Type to search..."
#: ../js/ui/overview.js:271
msgid "Type to search…"
msgstr "Upišite tekst za pretragu…"
#: ../js/ui/panel.js:613
#: ../js/ui/panel.js:612
msgid "Quit"
msgstr "Izađi"
#. Translators: If there is no suitable word for "Activities"
#. in your language, you can use the word for "Overview".
#: ../js/ui/panel.js:642
#: ../js/ui/panel.js:636
msgid "Activities"
msgstr "Aktivnosti"
#: ../js/ui/panel.js:983
#: ../js/ui/panel.js:933
msgid "Top Bar"
msgstr "Gornja traka"
@ -1287,21 +1284,21 @@ msgstr "Gornja traka"
msgid "toggle-switch-us"
msgstr "toggle-switch-intl"
#: ../js/ui/runDialog.js:205
#: ../js/ui/runDialog.js:73
msgid "Enter a Command"
msgstr "Unesite naredbu"
#: ../js/ui/runDialog.js:241
#: ../js/ui/runDialog.js:109
msgid "Close"
msgstr "Zatvori"
#. Translators: This is a time format for a date in
#. long format
#: ../js/ui/screenShield.js:90
#: ../js/ui/screenShield.js:86
msgid "%A, %B %d"
msgstr "%A, %d. %B"
#: ../js/ui/screenShield.js:155
#: ../js/ui/screenShield.js:151
#, c-format
msgid "%d new notification"
msgid_plural "%d new notifications"
@ -1310,11 +1307,11 @@ msgstr[1] "%d nova obaveštenja"
msgstr[2] "%d novih obaveštenja"
msgstr[3] "Jedno novo obaveštenje"
#: ../js/ui/screenShield.js:442 ../js/ui/userMenu.js:806
#: ../js/ui/screenShield.js:438 ../js/ui/userMenu.js:807
msgid "Lock"
msgstr "Zaključaj"
#: ../js/ui/screenShield.js:639
#: ../js/ui/screenShield.js:640
msgid "GNOME needs to lock the screen"
msgstr "Gnom mora da zaključa ekran"
@ -1325,21 +1322,19 @@ msgstr "Gnom mora da zaključa ekran"
#.
#. XXX: another option is to kick the user into the gdm login
#. screen, where we're not affected by grabs
#: ../js/ui/screenShield.js:758 ../js/ui/screenShield.js:1169
#| msgid "Unable to connect to %s"
#: ../js/ui/screenShield.js:761 ../js/ui/screenShield.js:1197
msgid "Unable to lock"
msgstr "Ne mogu da zaključam"
#: ../js/ui/screenShield.js:759 ../js/ui/screenShield.js:1170
#: ../js/ui/screenShield.js:762 ../js/ui/screenShield.js:1198
msgid "Lock was blocked by an application"
msgstr "Neki program je blokirao zaključavanje"
#: ../js/ui/searchDisplay.js:431
#| msgid "Searching..."
#: ../js/ui/searchDisplay.js:453
msgid "Searching…"
msgstr "Tražim…"
#: ../js/ui/searchDisplay.js:475
#: ../js/ui/searchDisplay.js:497
msgid "No results."
msgstr "Nema odgovarajućih rezultata."
@ -1351,11 +1346,11 @@ msgstr "Umnoži"
msgid "Paste"
msgstr "Ubaci"
#: ../js/ui/shellEntry.js:105
#: ../js/ui/shellEntry.js:106
msgid "Show Text"
msgstr "Prikaži tekst"
#: ../js/ui/shellEntry.js:107
#: ../js/ui/shellEntry.js:108
msgid "Hide Text"
msgstr "Sakrij tekst"
@ -1367,7 +1362,7 @@ msgstr "Lozinka"
msgid "Remember Password"
msgstr "Zapamti lozinku"
#: ../js/ui/shellMountOperation.js:403 ../js/ui/unlockDialog.js:140
#: ../js/ui/shellMountOperation.js:403 ../js/ui/unlockDialog.js:113
msgid "Unlock"
msgstr "Otključaj"
@ -1431,12 +1426,10 @@ msgid "Visibility"
msgstr "Vidljivost"
#: ../js/ui/status/bluetooth.js:59
#| msgid "Send Files to Device..."
msgid "Send Files to Device…"
msgstr "Pošalji datoteke na uređaj…"
#: ../js/ui/status/bluetooth.js:60
#| msgid "Set Up a New Device..."
msgid "Set Up a New Device…"
msgstr "Podesi novi uređaj…"
@ -1463,7 +1456,6 @@ msgid "connecting..."
msgstr "povezujem se..."
#: ../js/ui/status/bluetooth.js:239
#| msgid "Send Files..."
msgid "Send Files…"
msgstr "Pošalji datoteke…"
@ -1676,7 +1668,6 @@ msgstr "Podešavanja napajanja"
#. 0 is reported when UPower does not have enough data
#. to estimate battery life
#: ../js/ui/status/power.js:99
#| msgid "Estimating..."
msgid "Estimating…"
msgstr "Približno…"
@ -1784,11 +1775,11 @@ msgstr "Jačina zvuka"
msgid "Microphone"
msgstr "Mikrofon"
#: ../js/ui/unlockDialog.js:151
#: ../js/ui/unlockDialog.js:124
msgid "Log in as another user"
msgstr "Prijavite se kao drugi korsnik"
#: ../js/ui/unlockDialog.js:177
#: ../js/ui/unlockDialog.js:145
msgid "Unlock Window"
msgstr "Otključaj prozor"
@ -1816,27 +1807,27 @@ msgstr "Miruje"
msgid "Offline"
msgstr "Van mreže"
#: ../js/ui/userMenu.js:780
#: ../js/ui/userMenu.js:781
msgid "Notifications"
msgstr "Obaveštenja"
#: ../js/ui/userMenu.js:796
#: ../js/ui/userMenu.js:797
msgid "Switch User"
msgstr "Promeni korisnika"
#: ../js/ui/userMenu.js:801
#: ../js/ui/userMenu.js:802
msgid "Log Out"
msgstr "Odjavi me"
#: ../js/ui/userMenu.js:821
#: ../js/ui/userMenu.js:822
msgid "Install Updates & Restart"
msgstr "Instaliraj ažuriranja i ponovo pokreni"
#: ../js/ui/userMenu.js:839
#: ../js/ui/userMenu.js:840
msgid "Your chat status will be set to busy"
msgstr "Vaše stanje ćaskanja će biti postavljeno na zauzeto"
#: ../js/ui/userMenu.js:840
#: ../js/ui/userMenu.js:841
msgid ""
"Notifications are now disabled, including chat messages. Your online status "
"has been adjusted to let others know that you might not see their messages."
@ -1845,20 +1836,22 @@ msgstr ""
"mreži je podešeno tako da će ostali znati da vi ne možete videti njihove "
"poruke."
#: ../js/ui/userMenu.js:886
#: ../js/ui/userMenu.js:888
msgid "Other users are logged in."
msgstr "Drugi korisnici su prijavljeni."
#: ../js/ui/userMenu.js:891
#: ../js/ui/userMenu.js:893
msgid "Shutting down might cause them to lose unsaved work."
msgstr "Isključivanje može da dovede do toga da izgube nesačuvani rad."
#: ../js/ui/userMenu.js:918
#. Translators: Remote here refers to a remote session, like a ssh login
#: ../js/ui/userMenu.js:921
#, c-format
msgid "%s (remote)"
msgstr "%s (udaljeno)"
#: ../js/ui/userMenu.js:920
#. Translators: Console here refers to a tty like a VT console
#: ../js/ui/userMenu.js:924
#, c-format
msgid "%s (console)"
msgstr "%s (ljuska)"
@ -1871,7 +1864,7 @@ msgstr "Programi"
msgid "Search"
msgstr "Traži"
#: ../js/ui/wanda.js:92
#: ../js/ui/wanda.js:77
#, c-format
msgid ""
"Sorry, no wisdom for you today:\n"
@ -1880,7 +1873,7 @@ msgstr ""
"Izvinite, danas za vas nema mudrosti:\n"
"%s"
#: ../js/ui/wanda.js:96
#: ../js/ui/wanda.js:81
#, c-format
msgid "%s the Oracle says"
msgstr "Prorok je rekao %s"

1053
po/tg.po

File diff suppressed because it is too large Load Diff

2602
po/tr.po

File diff suppressed because it is too large Load Diff

442
po/vi.po
View File

@ -1,18 +1,19 @@
# Vietnamese translation for gnome-shell.
# Copyright (C) 2010 GNOME i18n Project for Vietnamese.
# Copyright (C) 2013 GNOME i18n Project for Vietnamese.
# This file is distributed under the same license as the gnome-shell package.
# Nguyễn Thái Ngọc Duy <pclouds@gmail.com>, 2010-2013.
# Ngô Chin <ndtrung4419@gmail.com>, 2011.
# Trần Ngọc Quân <vnwildman@gmail.com>, 2013.
#
msgid ""
msgstr ""
"Project-Id-Version: gnome-shell\n"
"Report-Msgid-Bugs-To: http://bugzilla.gnome.org/enter_bug.cgi?product=gnome-"
"shell&keywords=I18N+L10N&component=general\n"
"POT-Creation-Date: 2013-03-02 23:02+0000\n"
"PO-Revision-Date: 2013-03-03 11:13+0700\n"
"Last-Translator: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n"
"Language-Team: Vietnamese <vi-VN@googlegroups.com>\n"
"POT-Creation-Date: 2013-03-23 11:49+0000\n"
"PO-Revision-Date: 2013-04-13 17:51+1000\n"
"Last-Translator: Trần Ngọc Quân <vnwildman@gmail.com>\n"
"Language-Team: Vietnamese <translation-team-vi@lists.sourceforge.net>\n"
"Language: vi\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
@ -49,7 +50,7 @@ msgstr "Mở trình đơn ứng dụng"
#: ../data/gnome-shell.desktop.in.in.h:1
msgid "GNOME Shell"
msgstr "GNOME Shell"
msgstr "Hệ vỏ GNOME"
#: ../data/gnome-shell.desktop.in.in.h:2
msgid "Window management and application launching"
@ -58,11 +59,11 @@ msgstr "Quản lý cửa sổ và chạy ứng dụng"
#: ../data/gnome-shell-extension-prefs.desktop.in.in.h:1
#: ../js/extensionPrefs/main.js:153
msgid "GNOME Shell Extension Preferences"
msgstr "Tuỳ thích phần mở rộng GNOME Shell"
msgstr "Cá nhân hóa phần mở rộng hệ vỏ GNOME"
#: ../data/gnome-shell-extension-prefs.desktop.in.in.h:2
msgid "Configure GNOME Shell Extensions"
msgstr "Cấu hình phần mở rộng GNOME Shell"
msgstr "Cấu hình phần mở rộng Hệ vỏ GNOME"
#: ../data/org.gnome.shell.gschema.xml.in.in.h:1
msgid "Enable internal tools useful for developers and testers from Alt-F2"
@ -87,7 +88,7 @@ msgid ""
"list. You can also manipulate this list with the EnableExtension and "
"DisableExtension DBus methods on org.gnome.Shell."
msgstr ""
"Phần mở rộng GNOME Shell có thuộc tính uuid. Khoá này liệt kê danh sách phần "
"Phần mở rộng Hệ vỏ GNOME có thuộc tính uuid; khóa này liệt kê danh sách phần "
"mở rộng nên nạp. Bất kỳ phần mở rộng nào muốn nạp phải nằm trong danh sách "
"này. Bạn có thể thao tác trên danh sách này với phương thức DBus "
"EnableExtension và DisableExtension trên org.gnome.Shell."
@ -120,13 +121,15 @@ msgstr ""
#: ../data/org.gnome.shell.gschema.xml.in.in.h:9
msgid "List of categories that should be displayed as folders"
msgstr ""
msgstr "Liệt kê các các-ta-lốc mà nó có thể hiển thị như một thư mục"
#: ../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 ""
"Mỗi tên các-ta-lốc trong danh sách này sẽ được xuất hiện như là một thư mục "
"trong trình bày ứng dụng, thay vì hiển thị cùng dòng trong trình bày chính. "
#: ../data/org.gnome.shell.gschema.xml.in.in.h:11
msgid "History for command (Alt-F2) dialog"
@ -154,18 +157,22 @@ msgstr ""
#: ../data/org.gnome.shell.gschema.xml.in.in.h:15
msgid "Always show the 'Log out' menuitem in the user menu."
msgstr "Luôn hiện mục \"Đăng xuất\" trên trình đơn người dùng."
msgstr "Luôn hiện mục Đăng xuất trên trình đơn người dùng."
#: ../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."
msgstr ""
"Khóa này sẽ đè lên việc tự động ẩn trình đơn 'Đăng xuất' ở chế độ đơn-người-"
"dùng, đơn-phiên-làm-việc. "
#: ../data/org.gnome.shell.gschema.xml.in.in.h:17
msgid ""
"Whether to remember password for mounting encrypted or remote filesystems"
msgstr ""
"Hoặc là ghi nhớ mật khẩu dành cho việc gắn hệ thống tập tin đã mã hóa hoặc "
"hệ thống tập tin trên máy chủ"
#: ../data/org.gnome.shell.gschema.xml.in.in.h:18
msgid ""
@ -174,6 +181,10 @@ msgid ""
"'Remember Password' checkbox will be present. This key sets the default "
"state of the checkbox."
msgstr ""
"Hệ vỏ sẽ yêu cầu mật khẩu khi có thư mục được mã hóa hay hệ thống tập tin "
"máy mạng được gắn. Nếu mật khẩu có thể ghi lại để dùng trong lần sau, hộp "
"dấu kiểm “Nhớ mật khẩu” sẽ xuất hiện. Khóa này đặt trạng thái mặc định cho "
"hộp dấu kiểm."
#: ../data/org.gnome.shell.gschema.xml.in.in.h:19
msgid "Show the week date in the calendar"
@ -226,27 +237,27 @@ msgstr "Phím chạy hoặc ngừng trình thu màn hình."
#: ../data/org.gnome.shell.gschema.xml.in.in.h:31
msgid "Which keyboard to use"
msgstr "Loại bàn phím cần dùng"
msgstr "Bàn phím cần dùng"
#: ../data/org.gnome.shell.gschema.xml.in.in.h:32
msgid "The type of keyboard to use."
msgstr "Loại bàn phím cần dùng."
msgstr "Kiểu bàn phím cần dùng."
#: ../data/org.gnome.shell.gschema.xml.in.in.h:33
msgid "Framerate used for recording screencasts."
msgstr "Tốc độ khung dùng lưu screencast."
msgstr "Tốc độ khung hình sẽ dùng khi ghi screencast."
#: ../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."
msgstr ""
"Tốc độ khung của screencast lưu bởi bộ thu GNOME Shell theo số khung mỗi "
"giây."
"Tốc độ khung hình của screencast được ghi bởi bộ thu Hệ vỏ GNOME tính theo "
"số khung mỗi giây."
#: ../data/org.gnome.shell.gschema.xml.in.in.h:35
msgid "The gstreamer pipeline used to encode the screencast"
msgstr "Ống dẫn gstreamer để thu screencast"
msgstr "Ống dẫn gstreamer dùng để thu screencast"
#: ../data/org.gnome.shell.gschema.xml.in.in.h:37
#, no-c-format
@ -267,9 +278,9 @@ msgstr ""
"source pad không kết nối; đầu ra từ pad sẽ được ghi vào tập tin kết quả. Tuy "
"nhiên ống dẫn có thể tự lưu đầu ra riêng - có thể hữu dụng để gửi kết quả "
"đến máy chủ icecast thông qua shout2send hoặc tương tự. Nếu bỏ chọn hoặc đặt "
"giá trị rỗng, ống dẫn mặc định sẽ được dùng, hiện thời là 'vp8enc "
"giá trị rỗng, ống dẫn mặc định sẽ được dùng, hiện thời là vp8enc "
"min_quantizer=13 max_quantizer=13 cpu-used=5 deadline=1000000 threads=%T ! "
"queue ! webmmux' và lưu ở dạng WEBM dùng VP8 codec. %T được dùng để thế chỗ "
"queue ! webmmux và lưu ở dạng WEBM dùng VP8 codec. %T được dùng để thế chỗ "
"cho số thread dự đoán tối ưu cho hệ thống."
#: ../data/org.gnome.shell.gschema.xml.in.in.h:38
@ -296,25 +307,31 @@ msgid ""
"are 'thumbnail-only' (shows a thumbnail of the window), 'app-icon-"
"only' (shows only the application icon) or 'both'."
msgstr ""
"Cấu hình về cách hiển thị các cửa sổ ở bảng chuyển đổi. Các kiểu có thể là "
"'thumbnail-only' (hiển thị ảnh thu nhỏ của cửa sổ), 'app-icon-only' (chỉ "
"hiển thị biểu tượng của ứng dụng) hoặc 'both' (cả hai)."
#: ../data/org.gnome.shell.gschema.xml.in.in.h:42
msgid "Attach modal dialog to the parent window"
msgstr ""
msgstr "Gắn hộp thoại dạng modal vào cửa sổ mẹ"
#: ../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 ""
"Khóa này sẽ đè lên khóa có trong org.gnome.mutter khi chạy hệ vỏ GNOME."
#: ../data/org.gnome.shell.gschema.xml.in.in.h:44
msgid "Arrangement of buttons on the titlebar"
msgstr ""
msgstr "Sắp đặt các nút trên thanh tiêu đề"
#: ../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."
msgstr ""
"Khóa này đè lên khóa có trong org.gnome.desktop.wm.preferences khi chạy hệ "
"vỏ GNOME."
#: ../data/org.gnome.shell.gschema.xml.in.in.h:46
msgid "Enable edge tiling when dropping windows on screen edges"
@ -348,46 +365,46 @@ msgstr "Phiên làm việc…"
#. 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:629
#: ../js/gdm/loginDialog.js:630
msgid "Not listed?"
msgstr "Không có trong danh sách?"
#: ../js/gdm/loginDialog.js:783 ../js/ui/components/networkAgent.js:137
#: ../js/gdm/loginDialog.js:786 ../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:126
#: ../js/ui/userMenu.js:932
#: ../js/ui/status/bluetooth.js:415 ../js/ui/unlockDialog.js:99
#: ../js/ui/userMenu.js:938
msgid "Cancel"
msgstr "Thôi"
#: ../js/gdm/loginDialog.js:799
#: ../js/gdm/loginDialog.js:802
msgctxt "button"
msgid "Sign In"
msgstr "Đăng nhập"
#: ../js/gdm/loginDialog.js:799
#: ../js/gdm/loginDialog.js:802
msgid "Next"
msgstr "Tới"
msgstr "Kế tiếp"
#. 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:904 ../js/ui/components/networkAgent.js:260
#: ../js/gdm/loginDialog.js:917 ../js/ui/components/networkAgent.js:260
#: ../js/ui/components/networkAgent.js:278
msgid "Username: "
msgstr "Tên người dùng: "
msgstr "Tài khoản: "
#: ../js/gdm/loginDialog.js:1157
#: ../js/gdm/loginDialog.js:1173
msgid "Login Window"
msgstr "Cửa sổ đặt nhập"
msgstr "Cửa sổ đăng nhập"
#. Translators: accessible name of the power menu in the login screen
#: ../js/gdm/powerMenu.js:36
msgid "Power"
msgstr "Nguồn"
#: ../js/gdm/powerMenu.js:93 ../js/ui/userMenu.js:694 ../js/ui/userMenu.js:698
#: ../js/ui/userMenu.js:814
#: ../js/gdm/powerMenu.js:93 ../js/ui/userMenu.js:696 ../js/ui/userMenu.js:700
#: ../js/ui/userMenu.js:816
msgid "Suspend"
msgstr "Ngưng"
@ -395,58 +412,58 @@ msgstr "Ngưng"
msgid "Restart"
msgstr "Khởi động lại"
#: ../js/gdm/powerMenu.js:103 ../js/ui/userMenu.js:696
#: ../js/ui/userMenu.js:698 ../js/ui/userMenu.js:813 ../js/ui/userMenu.js:936
#: ../js/gdm/powerMenu.js:103 ../js/ui/userMenu.js:698
#: ../js/ui/userMenu.js:700 ../js/ui/userMenu.js:815 ../js/ui/userMenu.js:942
msgid "Power Off"
msgstr "Tắt máy"
#: ../js/gdm/util.js:182
#: ../js/gdm/util.js:249
msgid "Authentication error"
msgstr "Lỗi xác thực"
#. Translators: this message is shown below the password entry field
#. to indicate the user can swipe their finger instead
#: ../js/gdm/util.js:299
#: ../js/gdm/util.js:366
msgid "(or swipe finger)"
msgstr "(hoặc quẹt ngón tay)"
#: ../js/gdm/util.js:324
#: ../js/gdm/util.js:391
#, c-format
msgid "(e.g., user or %s)"
msgstr "(ví dụ người dùng hoặc %s)"
msgstr "(ví dụ: tài khoản hoặc %s)"
#: ../js/misc/util.js:94
#: ../js/misc/util.js:97
msgid "Command not found"
msgstr "Không tìm thấy lệnh"
#. Replace "Error invoking GLib.shell_parse_argv: " with
#. something nicer
#: ../js/misc/util.js:127
#: ../js/misc/util.js:130
msgid "Could not parse command:"
msgstr "Không thể phân tích lệnh:"
#: ../js/misc/util.js:135
#: ../js/misc/util.js:138
#, c-format
msgid "Execution of '%s' failed:"
msgstr "Lỗi thực hiện '%s':"
msgstr "Lỗi thực hiện %s:"
#: ../js/ui/appDisplay.js:348
#: ../js/ui/appDisplay.js:349
msgid "Frequent"
msgstr "Thường dùng"
#: ../js/ui/appDisplay.js:355
#: ../js/ui/appDisplay.js:356
msgid "All"
msgstr "Tất cả"
#: ../js/ui/appDisplay.js:913
#: ../js/ui/appDisplay.js:914
msgid "New Window"
msgstr "Cửa sổ mới"
#: ../js/ui/appDisplay.js:916 ../js/ui/dash.js:284
#: ../js/ui/appDisplay.js:917 ../js/ui/dash.js:284
msgid "Remove from Favorites"
msgstr "Bỏ đánh dấu ưa thích"
#: ../js/ui/appDisplay.js:917
#: ../js/ui/appDisplay.js:918
msgid "Add to Favorites"
msgstr "Đánh dấu ưa thích"
@ -460,13 +477,13 @@ msgstr "Đã được đánh dấu ưa thích cho %s."
msgid "%s has been removed from your favorites."
msgstr "Đã bỏ đánh dấu ưa thích cho %s"
#: ../js/ui/backgroundMenu.js:19 ../js/ui/userMenu.js:787
#: ../js/ui/backgroundMenu.js:19 ../js/ui/userMenu.js:789
msgid "Settings"
msgstr "Thiết lập"
msgstr "Cài đặt"
#: ../js/ui/backgroundMenu.js:21
msgid "Change Background…"
msgstr "Thay đổi nền…"
msgstr "Đổi ảnh nền…"
#. Translators: Shown in calendar event list for all day events
#. * Keep it short, best if you can use less then 10 characters
@ -585,35 +602,35 @@ msgid "S"
msgstr "T7"
#. Translators: Text to show if there are no events
#: ../js/ui/calendar.js:692
#: ../js/ui/calendar.js:720
msgid "Nothing Scheduled"
msgstr "Không có lịch hẹn"
#. Translators: Shown on calendar heading when selected day occurs on current year
#: ../js/ui/calendar.js:708
#: ../js/ui/calendar.js:736
msgctxt "calendar heading"
msgid "%A, %B %d"
msgstr "%A, %d %B"
#. Translators: Shown on calendar heading when selected day occurs on different year
#: ../js/ui/calendar.js:711
#: ../js/ui/calendar.js:739
msgctxt "calendar heading"
msgid "%A, %B %d, %Y"
msgstr "%A, %d %B %Y"
#: ../js/ui/calendar.js:721
#: ../js/ui/calendar.js:749
msgid "Today"
msgstr "Hôm nay"
#: ../js/ui/calendar.js:725
#: ../js/ui/calendar.js:753
msgid "Tomorrow"
msgstr "Ngày mai"
#: ../js/ui/calendar.js:736
#: ../js/ui/calendar.js:764
msgid "This week"
msgstr "Tuần này"
#: ../js/ui/calendar.js:744
#: ../js/ui/calendar.js:772
msgid "Next week"
msgstr "Tuần tới"
@ -629,12 +646,12 @@ msgstr "Ổ ngoài đã ngắt kết nối"
msgid "Removable Devices"
msgstr "Thiết bị di động"
#: ../js/ui/components/autorunManager.js:593
#: ../js/ui/components/autorunManager.js:594
#, c-format
msgid "Open with %s"
msgstr "Mở bằng %s"
#: ../js/ui/components/autorunManager.js:619
#: ../js/ui/components/autorunManager.js:620
msgid "Eject"
msgstr "Đẩy ra"
@ -685,7 +702,7 @@ msgstr "Mạng không dây cần xác thực"
msgid ""
"Passwords or encryption keys are required to access the wireless network "
"'%s'."
msgstr "Cần mật mã hoặc khoá mã để truy cập mạng không dây '%s'"
msgstr "Cần mật mã hoặc khoá mã để truy cập mạng không dây %s"
#: ../js/ui/components/networkAgent.js:314
msgid "Wired 802.1X authentication"
@ -718,7 +735,7 @@ msgstr "Mật khẩu mạng băng thông rộng"
#: ../js/ui/components/networkAgent.js:337
#, c-format
msgid "A password is required to connect to '%s'."
msgstr "Cần mật khẩu để kết nối đến '%s'."
msgstr "Cần mật khẩu để kết nối đến %s."
#: ../js/ui/components/polkitAgent.js:55
msgid "Authentication Required"
@ -772,7 +789,7 @@ msgstr "Ngừng im lặng"
#: ../js/ui/components/telepathyClient.js:480
msgid "Mute"
msgstr "Im lặng"
msgstr "Câm"
#. Translators: this is the word "Yesterday" followed by a time string. i.e. "Yesterday, 14:30"
#: ../js/ui/components/telepathyClient.js:942
@ -983,7 +1000,7 @@ msgstr "Xem tài khoản"
msgid "Unknown reason"
msgstr "Lý do không biết"
#: ../js/ui/ctrlAltTab.js:29 ../js/ui/viewSelector.js:97
#: ../js/ui/ctrlAltTab.js:29 ../js/ui/viewSelector.js:96
msgid "Windows"
msgstr "Cửa sổ"
@ -1012,7 +1029,7 @@ msgstr "Thiết lập ngày giờ"
#. 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").
#.
#: ../js/ui/dateMenu.js:205
#: ../js/ui/dateMenu.js:215
msgid "%A %B %e, %Y"
msgstr "%A %e %B, %Y"
@ -1108,7 +1125,7 @@ msgstr "Cài đặt"
#: ../js/ui/extensionDownloader.js:204
#, c-format
msgid "Download and install '%s' from extensions.gnome.org?"
msgstr "Tải và cài đặt '%s' từ extensions.gnome.org chứ?"
msgstr "Tải và cài đặt %s từ extensions.gnome.org chứ?"
#: ../js/ui/keyboard.js:619 ../js/ui/status/keyboard.js:314
#: ../js/ui/status/power.js:211
@ -1137,9 +1154,7 @@ msgstr "Hiện lỗi"
msgid "Enabled"
msgstr "Bật"
#. translators:
#. * The device has been disabled
#: ../js/ui/lookingGlass.js:769 ../src/gvc/gvc-mixer-control.c:1830
#: ../js/ui/lookingGlass.js:769
msgid "Disabled"
msgstr "Tắt"
@ -1179,15 +1194,15 @@ msgstr "Xoá thông báo"
msgid "Notification Settings"
msgstr "Thiết lập thông báo"
#: ../js/ui/messageTray.js:1707
#: ../js/ui/messageTray.js:1709
msgid "No Messages"
msgstr "Không có thông báo"
#: ../js/ui/messageTray.js:1787
#: ../js/ui/messageTray.js:1782
msgid "Message Tray"
msgstr "Khay thông báo"
#: ../js/ui/messageTray.js:2864
#: ../js/ui/messageTray.js:2810
msgid "System Information"
msgstr "Thông tin hệ thống"
@ -1196,13 +1211,13 @@ msgctxt "program"
msgid "Unknown"
msgstr "Không biết"
#: ../js/ui/overviewControls.js:460 ../js/ui/screenShield.js:153
#: ../js/ui/overviewControls.js:463 ../js/ui/screenShield.js:149
#, c-format
msgid "%d new message"
msgid_plural "%d new messages"
msgstr[0] "%d tin nhắn mới"
#: ../js/ui/overview.js:82
#: ../js/ui/overview.js:84
msgid "Undo"
msgstr "Hoàn lại"
@ -1214,21 +1229,21 @@ msgstr "Tổng quan"
#. in the search entry when no search is
#. active; it should not exceed ~30
#. characters.
#: ../js/ui/overview.js:284
#: ../js/ui/overview.js:271
msgid "Type to search…"
msgstr "Nhập để tìm…"
#: ../js/ui/panel.js:613
#: ../js/ui/panel.js:612
msgid "Quit"
msgstr "Thoát"
#. Translators: If there is no suitable word for "Activities"
#. in your language, you can use the word for "Overview".
#: ../js/ui/panel.js:642
#: ../js/ui/panel.js:636
msgid "Activities"
msgstr "Hoạt động"
#: ../js/ui/panel.js:983
#: ../js/ui/panel.js:933
msgid "Top Bar"
msgstr "Thanh đỉnh"
@ -1241,31 +1256,31 @@ msgstr "Thanh đỉnh"
msgid "toggle-switch-us"
msgstr "toggle-switch-intl"
#: ../js/ui/runDialog.js:205
#: ../js/ui/runDialog.js:73
msgid "Enter a Command"
msgstr "Nhập lệnh"
#: ../js/ui/runDialog.js:241
#: ../js/ui/runDialog.js:109
msgid "Close"
msgstr "Đóng"
#. Translators: This is a time format for a date in
#. long format
#: ../js/ui/screenShield.js:90
#: ../js/ui/screenShield.js:86
msgid "%A, %B %d"
msgstr "%A, %d %B"
#: ../js/ui/screenShield.js:155
#: ../js/ui/screenShield.js:151
#, c-format
msgid "%d new notification"
msgid_plural "%d new notifications"
msgstr[0] "%d thông báo mới"
#: ../js/ui/screenShield.js:442 ../js/ui/userMenu.js:805
#: ../js/ui/screenShield.js:438 ../js/ui/userMenu.js:807
msgid "Lock"
msgstr "Khoá"
#: ../js/ui/screenShield.js:639
#: ../js/ui/screenShield.js:637
msgid "GNOME needs to lock the screen"
msgstr "GNOME cần khoá màn hình"
@ -1276,19 +1291,19 @@ msgstr "GNOME cần khoá màn hình"
#.
#. XXX: another option is to kick the user into the gdm login
#. screen, where we're not affected by grabs
#: ../js/ui/screenShield.js:758 ../js/ui/screenShield.js:1169
#: ../js/ui/screenShield.js:758 ../js/ui/screenShield.js:1194
msgid "Unable to lock"
msgstr "Không thể khoá"
#: ../js/ui/screenShield.js:759 ../js/ui/screenShield.js:1170
#: ../js/ui/screenShield.js:759 ../js/ui/screenShield.js:1195
msgid "Lock was blocked by an application"
msgstr "Một ứng dụng đã ngăn cản khoá"
#: ../js/ui/searchDisplay.js:431
#: ../js/ui/searchDisplay.js:453
msgid "Searching…"
msgstr "Đang tìm…"
#: ../js/ui/searchDisplay.js:475
#: ../js/ui/searchDisplay.js:497
msgid "No results."
msgstr "Không có kết quả."
@ -1300,11 +1315,11 @@ msgstr "Chép"
msgid "Paste"
msgstr "Dán"
#: ../js/ui/shellEntry.js:105
#: ../js/ui/shellEntry.js:106
msgid "Show Text"
msgstr "Hiện chữ"
#: ../js/ui/shellEntry.js:107
#: ../js/ui/shellEntry.js:108
msgid "Hide Text"
msgstr "Ẩn chữ"
@ -1316,7 +1331,7 @@ msgstr "Mật khẩu"
msgid "Remember Password"
msgstr "Nhớ mật khẩu"
#: ../js/ui/shellMountOperation.js:403 ../js/ui/unlockDialog.js:140
#: ../js/ui/shellMountOperation.js:403 ../js/ui/unlockDialog.js:113
msgid "Unlock"
msgstr "Bỏ khoá"
@ -1433,7 +1448,7 @@ msgstr "Yêu cầu cấp quyền từ %s"
#: ../js/ui/status/bluetooth.js:328
#, c-format
msgid "Device %s wants access to the service '%s'"
msgstr "Thiết bị %s muốn truy cập dịch vụ '%s'"
msgstr "Thiết bị %s muốn truy cập dịch vụ %s"
#: ../js/ui/status/bluetooth.js:330
msgid "Always grant access"
@ -1461,7 +1476,7 @@ msgstr "Thiết bị %s muốn kết nối với máy tính này"
#: ../js/ui/status/bluetooth.js:366
#, c-format
msgid "Please confirm whether the PIN '%06d' matches the one on the device."
msgstr "Vui lòng xác nhận PIN '%06d' khớp với số trên thiết bị."
msgstr "Vui lòng xác nhận PIN %06d khớp với số trên thiết bị."
#. Translators: this is the verb, not the noun
#: ../js/ui/status/bluetooth.js:369
@ -1717,59 +1732,59 @@ msgstr "Âm lượng"
msgid "Microphone"
msgstr "Micrô"
#: ../js/ui/unlockDialog.js:151
#: ../js/ui/unlockDialog.js:124
msgid "Log in as another user"
msgstr "Đăng nhập người dùng khác"
#: ../js/ui/unlockDialog.js:177
#: ../js/ui/unlockDialog.js:145
msgid "Unlock Window"
msgstr "Bỏ khoá cửa sổ"
#: ../js/ui/userMenu.js:192
#: ../js/ui/userMenu.js:193
msgid "Available"
msgstr "Có mặt"
#: ../js/ui/userMenu.js:195
#: ../js/ui/userMenu.js:196
msgid "Busy"
msgstr "Bận"
#: ../js/ui/userMenu.js:198
#: ../js/ui/userMenu.js:199
msgid "Invisible"
msgstr "Giấu mặt"
#: ../js/ui/userMenu.js:201
#: ../js/ui/userMenu.js:202
msgid "Away"
msgstr "Vắng mặt"
#: ../js/ui/userMenu.js:204
#: ../js/ui/userMenu.js:205
msgid "Idle"
msgstr "Nhàn rỗi"
#: ../js/ui/userMenu.js:207
#: ../js/ui/userMenu.js:208
msgid "Offline"
msgstr "Ngoại tuyến"
#: ../js/ui/userMenu.js:779
#: ../js/ui/userMenu.js:781
msgid "Notifications"
msgstr "Thông báo"
#: ../js/ui/userMenu.js:795
#: ../js/ui/userMenu.js:797
msgid "Switch User"
msgstr "Chuyển người dùng"
#: ../js/ui/userMenu.js:800
#: ../js/ui/userMenu.js:802
msgid "Log Out"
msgstr "Đăng xuất"
#: ../js/ui/userMenu.js:820
#: ../js/ui/userMenu.js:822
msgid "Install Updates & Restart"
msgstr "Cài đặt bản cập nhật và khởi động lại"
#: ../js/ui/userMenu.js:838
#: ../js/ui/userMenu.js:840
msgid "Your chat status will be set to busy"
msgstr "Trạng thái nhắn tin của bạn sẽ được đặt là bận"
#: ../js/ui/userMenu.js:839
#: ../js/ui/userMenu.js:841
msgid ""
"Notifications are now disabled, including chat messages. Your online status "
"has been adjusted to let others know that you might not see their messages."
@ -1777,33 +1792,35 @@ msgstr ""
"Thông báo đã bị tắt, bao gồm tin nhắn. Trạng thái trực tuyến của bạn đã được "
"điều chỉnh để mọi người biết bạn sẽ không xem tin nhắn họ gửi đến."
#: ../js/ui/userMenu.js:885
#: ../js/ui/userMenu.js:888
msgid "Other users are logged in."
msgstr "Người dùng khác đang đăng nhập."
#: ../js/ui/userMenu.js:890
#: ../js/ui/userMenu.js:893
msgid "Shutting down might cause them to lose unsaved work."
msgstr "Tắt sẽ làm mất những kết quả chưa được lưu."
#: ../js/ui/userMenu.js:916
#. Translators: Remote here refers to a remote session, like a ssh login
#: ../js/ui/userMenu.js:921
#, c-format
msgid "%s (remote)"
msgstr "%s (ở xa)"
#: ../js/ui/userMenu.js:918
#. Translators: Console here refers to a tty like a VT console
#: ../js/ui/userMenu.js:924
#, c-format
msgid "%s (console)"
msgstr "%s (console)"
#: ../js/ui/viewSelector.js:101
#: ../js/ui/viewSelector.js:100
msgid "Applications"
msgstr "Ứng dụng"
#: ../js/ui/viewSelector.js:105
#: ../js/ui/viewSelector.js:104
msgid "Search"
msgstr "Tìm"
#: ../js/ui/wanda.js:92
#: ../js/ui/wanda.js:77
#, c-format
msgid ""
"Sorry, no wisdom for you today:\n"
@ -1812,7 +1829,7 @@ msgstr ""
"Rất tiếc, không có lời thông thái nào hôm nay:\n"
"%s"
#: ../js/ui/wanda.js:96
#: ../js/ui/wanda.js:81
#, c-format
msgid "%s the Oracle says"
msgstr "Nhà tiên tri %s nói"
@ -1820,32 +1837,12 @@ msgstr "Nhà tiên tri %s nói"
#: ../js/ui/windowAttentionHandler.js:19
#, c-format
msgid "'%s' is ready"
msgstr "'%s' đã sẵn sàng"
msgstr "%s đã sẵn sàng"
#: ../src/calendar-server/evolution-calendar.desktop.in.in.h:1
msgid "Evolution Calendar"
msgstr "Lịch Evolution"
#. translators:
#. * The number of sound outputs on a particular device
#: ../src/gvc/gvc-mixer-control.c:1837
#, c-format
msgid "%u Output"
msgid_plural "%u Outputs"
msgstr[0] "%u đầu ra"
#. translators:
#. * The number of sound inputs on a particular device
#: ../src/gvc/gvc-mixer-control.c:1847
#, c-format
msgid "%u Input"
msgid_plural "%u Inputs"
msgstr[0] "%u đầu vào"
#: ../src/gvc/gvc-mixer-control.c:2371
msgid "System Sounds"
msgstr "Âm thanh hệ thống"
#: ../src/main.c:347
msgid "Print version"
msgstr "In phiên bản"
@ -1856,7 +1853,7 @@ msgstr "Chể độ dùng bởi GDM cho màn hình đăng nhập"
#: ../src/main.c:359
msgid "Use a specific mode, e.g. \"gdm\" for login screen"
msgstr "Dùng chế độ đặc biệt, ví dụ \"gdm\" cho màn hình đăng nhập"
msgstr "Dùng chế độ đặc biệt, ví dụ gdm cho màn hình đăng nhập"
#: ../src/main.c:365
msgid "List possible modes"
@ -1865,7 +1862,7 @@ msgstr "Danh sách chế độ"
#: ../src/shell-app.c:622
#, c-format
msgid "Failed to launch '%s'"
msgstr "Lỗi chạy '%s'"
msgstr "Lỗi chạy %s"
#: ../src/shell-keyring-prompt.c:708
msgid "Passwords do not match."
@ -1879,6 +1876,17 @@ msgstr "Mật khẩu không thể không có"
msgid "Authentication dialog was dismissed by the user"
msgstr "Hộp thoại xác thực bị người dùng bỏ qua"
#~ msgid "%u Output"
#~ msgid_plural "%u Outputs"
#~ msgstr[0] "%u đầu ra"
#~ msgid "%u Input"
#~ msgid_plural "%u Inputs"
#~ msgstr[0] "%u đầu vào"
#~ msgid "System Sounds"
#~ msgstr "Âm thanh hệ thống"
#~ msgctxt "title"
#~ msgid "Sign In"
#~ msgstr "Đăng nhập"
@ -1910,7 +1918,7 @@ msgstr "Hộp thoại xác thực bị người dùng bỏ qua"
#~ msgstr "%l:%M %p"
#~ msgid "Failed to unmount '%s'"
#~ msgstr "Lỗi bỏ gắn kết '%s'"
#~ msgstr "Lỗi bỏ gắn kết %s"
#~ msgid "Retry"
#~ msgstr "Thử lại"
@ -1925,7 +1933,7 @@ msgstr "Hộp thoại xác thực bị người dùng bỏ qua"
#~ msgstr "Lỗi duyệt tập tin"
#~ msgid "The requested device cannot be browsed, error is '%s'"
#~ msgstr "Không thể duyệt thiết bị yêu cầu , lỗi là '%s'"
#~ msgstr "Không thể duyệt thiết bị yêu cầu , lỗi là %s"
#~ msgid "Wireless"
#~ msgstr "Mạng không dây"
@ -2070,155 +2078,3 @@ msgstr "Hộp thoại xác thực bị người dùng bỏ qua"
#~ msgid "Show password"
#~ msgstr "Hiện mật khẩu"
#~| msgid "If true, display seconds in time."
#~ msgid "If true, display onscreen keyboard."
#~ msgstr "Nếu đúng (true), hiện bàn phím màn hình."
#~| msgid "Screen Keyboard"
#~ msgid "Show the onscreen keyboard"
#~ msgstr "Hiện bàn phím màn hình"
#~ msgid "%s has finished starting"
#~ msgstr "%s đã hoàn tất khởi chạy"
#~ msgid "Uuids of extensions to disable"
#~ msgstr "UUID của phần mở rộng cần tắt"
#~ msgid "You're now connected to mobile broadband connection '%s'"
#~ msgstr "Đã nối mạng '%s' (băng thông rộng)"
#~ msgid "You're now connected to wireless network '%s'"
#~ msgstr "Đã nối mạng '%s' (không dây)"
#~ msgid "You're now connected to wired network '%s'"
#~ msgstr "Đã nối mạng '%s' (dây)"
#~ msgid "You're now connected to VPN network '%s'"
#~ msgstr "Đã nối mạng VPN '%s'"
#~ msgid "Localization Settings"
#~ msgstr "Thiết lập bản địa hoá"
#~ msgid "Less than a minute ago"
#~ msgstr "Chưa đến một phút"
#~ msgid "%d minute ago"
#~ msgid_plural "%d minutes ago"
#~ msgstr[0] "%d phút trước"
#~ msgid "%d hour ago"
#~ msgid_plural "%d hours ago"
#~ msgstr[0] "%d giờ trước"
#~ msgid "%d day ago"
#~ msgid_plural "%d days ago"
#~ msgstr[0] "%d ngày trước"
#~ msgid "%d week ago"
#~ msgid_plural "%d weeks ago"
#~ msgstr[0] "%d tuần trước"
#~ msgid "Shut Down"
#~ msgstr "Tắt máy"
#~ msgid "Click Shut Down to quit these applications and shut down the system."
#~ msgstr "Nhấn Tắt máy để thoát những ứng dụng này và tắt hệ thống."
#~ msgid "The system will shut down automatically in %d seconds."
#~ msgstr "Hệ thống sẽ tự động tắt sau %d giây."
#~ msgid "Shutting down the system."
#~ msgstr "Tắt hệ thống."
#~ msgid "Confirm"
#~ msgstr "Xác nhận"
#~ msgid "Clip the crosshairs at the center"
#~ msgstr "Cắt lưới chéo ở giữa"
#~ msgid "Color of the crosshairs"
#~ msgstr "Màu lưới chéo"
#~ msgid ""
#~ "Determines the length of the vertical and horizontal lines that make up "
#~ "the crosshairs."
#~ msgstr "Xác định độ dài và rộng của những dòng tạo nên lưới chéo."
#~ msgid ""
#~ "Determines the transparency of the crosshairs, from fully opaque to fully "
#~ "transparent."
#~ msgstr "Xác định độ trong suốt của lưới chéo, từ đặc đến trong suốt."
#~ msgid "Enable lens mode"
#~ msgstr "Bật chế độ gương"
#~ msgid "Show or hide crosshairs"
#~ msgstr "Hiện hoặc ẩn lưới chéo"
#~ msgid "Show or hide the magnifier"
#~ msgstr "Hiện hoặc ẩn kính lúp"
#~ msgid "Thickness of the crosshairs"
#~ msgstr "Độ dày lưới chéo"
#~ msgid ""
#~ "Width of the vertical and horizontal lines that make up the crosshairs."
#~ msgstr "Độ rộng của đường dọc/ngang hình thành dấu gạch chéo."
#~ msgid "PREFERENCES"
#~ msgstr "TUỲ THÍCH"
#~ msgid "Shut Down..."
#~ msgstr "Tắt máy..."
#~ msgid "Search your computer"
#~ msgstr "Tìm trong máy"
#~ msgid "Customize the panel clock"
#~ msgstr "Tuỳ biến đồng hồ"
#~ msgid "Clock Format"
#~ msgstr "Dạng đồng hồ"
#~| msgid "System Preferences..."
#~ msgid "Clock Preferences"
#~ msgstr "Thiết lập đồng hồ"
#~ msgid "Panel Display"
#~ msgstr "Khung hiển thị"
#~ msgid "Show seco_nds"
#~ msgstr "Hiện _giây"
#~ msgid "_12 hour format"
#~ msgstr "Dạng _12 giờ"
#~ msgid "_24 hour format"
#~ msgstr "Dạng _24 giờ"
#~| msgid "System Preferences..."
#~ msgid "Preferences"
#~ msgstr "Thiết lập"
#~ msgid ""
#~ "Can't add a new workspace because maximum workspaces limit has been "
#~ "reached."
#~ msgstr ""
#~ "Không thể thêm vùng làm việc mới vì đã đạt giới hạn số vùng làm việc tối "
#~ "đa."
#~ msgid "Can't remove the first workspace."
#~ msgstr "Không thể bỏ vùng làm việc đầu tiên."
#~ msgid "Drag here to add favorites"
#~ msgstr "Kéo vào đây để thêm vào danh mục ưa thích"
#~ msgid "Find..."
#~ msgstr "Tìm"
#~ msgid "Sidebar"
#~ msgstr "Thanh bên"
#~ msgid "Recent Documents"
#~ msgstr "Tài liệu gần đây"

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -129,13 +129,18 @@ shell_public_headers_h = \
shell-wm.h \
shell-xfixes-cursor.h
shell_private_sources = \
gactionmuxer.h \
gactionmuxer.c \
gactionobservable.h \
gactionobservable.c \
gactionobserver.h \
gactionobserver.c
shell_private_sources = \
gtkactionmuxer.h \
gtkactionmuxer.c \
gtkactionobservable.h \
gtkactionobservable.c \
gtkactionobserver.h \
gtkactionobserver.c \
gtkmenutrackeritem.c \
gtkmenutrackeritem.h \
gtkmenutracker.c \
gtkmenutracker.h \
$(NULL)
libgnome_shell_la_SOURCES = \
$(shell_built_sources) \
@ -158,6 +163,8 @@ libgnome_shell_la_SOURCES = \
shell-invert-lightness-effect.c \
shell-keyring-prompt.h \
shell-keyring-prompt.c \
shell-menu-tracker.c \
shell-menu-tracker.h \
shell-mount-operation.c \
shell-network-agent.c \
shell-perf-log.c \
@ -286,12 +293,34 @@ libgnome_shell_la_LIBADD = \
libgnome_shell_la_CPPFLAGS = $(gnome_shell_cflags)
Shell-0.1.gir: libgnome-shell.la St-1.0.gir
ShellMenu-0.1.gir: libgnome-shell.la
ShellMenu_0_1_gir_INCLUDES = Gio-2.0
ShellMenu_0_1_gir_CFLAGS = $(libgnome_shell_la_CPPFLAGS) -I $(srcdir)
ShellMenu_0_1_gir_LIBS = libgnome-shell.la
ShellMenu_0_1_gir_FILES = \
gtkactionmuxer.h \
gtkactionmuxer.c \
gtkactionobservable.h \
gtkactionobservable.c \
gtkactionobserver.h \
gtkactionobserver.c \
gtkmenutrackeritem.c \
gtkmenutrackeritem.h \
$(NULL)
ShellMenu_0_1_gir_SCANNERFLAGS = \
--namespace=ShellMenu --identifier-prefix=Gtk \
$(if $(BLUETOOTH_DIR),-L $(BLUETOOTH_DIR),)
INTROSPECTION_GIRS += ShellMenu-0.1.gir
CLEANFILES += ShellMenu-0.1.gir
Shell-0.1.gir: libgnome-shell.la St-1.0.gir ShellMenu-0.1.gir
Shell_0_1_gir_INCLUDES = Clutter-1.0 ClutterX11-1.0 Meta-3.0 TelepathyGLib-0.12 Soup-2.4 GMenu-3.0 NetworkManager-1.0 NMClient-1.0
Shell_0_1_gir_CFLAGS = $(libgnome_shell_la_CPPFLAGS) -I $(srcdir)
Shell_0_1_gir_LIBS = libgnome-shell.la
Shell_0_1_gir_FILES = $(libgnome_shell_la_gir_sources)
Shell_0_1_gir_SCANNERFLAGS = --include-uninstalled=$(builddir)/St-1.0.gir \
Shell_0_1_gir_SCANNERFLAGS = \
--include-uninstalled=$(builddir)/St-1.0.gir \
--include-uninstalled=$(builddir)/ShellMenu-0.1.gir \
--add-include-path=$(MUTTER_GIR_DIR) $(if $(BLUETOOTH_DIR),-L $(BLUETOOTH_DIR),)
INTROSPECTION_GIRS += Shell-0.1.gir
CLEANFILES += Shell-0.1.gir

View File

@ -1,546 +0,0 @@
/*
* Copyright © 2011 Canonical Limited
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the licence, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*
* Author: Ryan Lortie <desrt@desrt.ca>
*/
#include "config.h"
#include "gactionmuxer.h"
#include "gactionobservable.h"
#include "gactionobserver.h"
#include <clutter/clutter.h>
#include <string.h>
/*
* SECTION:gactionmuxer
* @short_description: Aggregate and monitor several action groups
*
* #GActionMuxer is a #GActionGroup and #GActionObservable that is
* capable of containing other #GActionGroup instances.
*
* The typical use is aggregating all of the actions applicable to a
* particular context into a single action group, with namespacing.
*
* Consider the case of two action groups -- one containing actions
* applicable to an entire application (such as 'quit') and one
* containing actions applicable to a particular window in the
* application (such as 'fullscreen').
*
* In this case, each of these action groups could be added to a
* #GActionMuxer with the prefixes "app" and "win", respectively. This
* would expose the actions as "app.quit" and "win.fullscreen" on the
* #GActionGroup interface presented by the #GActionMuxer.
*
* Activations and state change requests on the #GActionMuxer are wired
* through to the underlying action group in the expected way.
*
* This class is typically only used at the site of "consumption" of
* actions (eg: when displaying a menu that contains many actions on
* different objects).
*/
static void g_action_muxer_group_iface_init (GActionGroupInterface *iface);
static void g_action_muxer_observable_iface_init (GActionObservableInterface *iface);
typedef GObjectClass GActionMuxerClass;
struct _GActionMuxer
{
GObject parent_instance;
GHashTable *actions;
GHashTable *groups;
};
G_DEFINE_TYPE_WITH_CODE (GActionMuxer, g_action_muxer, G_TYPE_OBJECT,
G_IMPLEMENT_INTERFACE (G_TYPE_ACTION_GROUP, g_action_muxer_group_iface_init)
G_IMPLEMENT_INTERFACE (G_TYPE_ACTION_OBSERVABLE, g_action_muxer_observable_iface_init))
typedef struct
{
GActionMuxer *muxer;
GSList *watchers;
gchar *fullname;
} Action;
typedef struct
{
GActionMuxer *muxer;
GActionGroup *group;
gchar *prefix;
gulong handler_ids[4];
} Group;
static gchar **
g_action_muxer_list_actions (GActionGroup *action_group)
{
GActionMuxer *muxer = G_ACTION_MUXER (action_group);
GHashTableIter iter;
gchar *key;
gchar **keys;
gsize i;
keys = g_new (gchar *, g_hash_table_size (muxer->actions) + 1);
i = 0;
g_hash_table_iter_init (&iter, muxer->actions);
while (g_hash_table_iter_next (&iter, (gpointer *) &key, NULL))
keys[i++] = g_strdup (key);
keys[i] = NULL;
return keys;
}
static Group *
g_action_muxer_find_group (GActionMuxer *muxer,
const gchar **name)
{
const gchar *dot;
gchar *prefix;
Group *group;
dot = strchr (*name, '.');
if (!dot)
return NULL;
prefix = g_strndup (*name, dot - *name);
group = g_hash_table_lookup (muxer->groups, prefix);
g_free (prefix);
*name = dot + 1;
return group;
}
static Action *
g_action_muxer_lookup_action (GActionMuxer *muxer,
const gchar *prefix,
const gchar *action_name,
gchar **fullname)
{
Action *action;
*fullname = g_strconcat (prefix, ".", action_name, NULL);
action = g_hash_table_lookup (muxer->actions, *fullname);
return action;
}
static void
g_action_muxer_action_enabled_changed (GActionGroup *action_group,
const gchar *action_name,
gboolean enabled,
gpointer user_data)
{
Group *group = user_data;
gchar *fullname;
Action *action;
GSList *node;
action = g_action_muxer_lookup_action (group->muxer, group->prefix, action_name, &fullname);
for (node = action ? action->watchers : NULL; node; node = node->next)
g_action_observer_action_enabled_changed (node->data, G_ACTION_OBSERVABLE (group->muxer), fullname, enabled);
g_action_group_action_enabled_changed (G_ACTION_GROUP (group->muxer), fullname, enabled);
g_free (fullname);
}
static void
g_action_muxer_action_state_changed (GActionGroup *action_group,
const gchar *action_name,
GVariant *state,
gpointer user_data)
{
Group *group = user_data;
gchar *fullname;
Action *action;
GSList *node;
action = g_action_muxer_lookup_action (group->muxer, group->prefix, action_name, &fullname);
for (node = action ? action->watchers : NULL; node; node = node->next)
g_action_observer_action_state_changed (node->data, G_ACTION_OBSERVABLE (group->muxer), fullname, state);
g_action_group_action_state_changed (G_ACTION_GROUP (group->muxer), fullname, state);
g_free (fullname);
}
static void
g_action_muxer_action_added (GActionGroup *action_group,
const gchar *action_name,
gpointer user_data)
{
const GVariantType *parameter_type;
Group *group = user_data;
gboolean enabled;
GVariant *state;
if (g_action_group_query_action (group->group, action_name, &enabled, &parameter_type, NULL, NULL, &state))
{
gchar *fullname;
Action *action;
GSList *node;
action = g_action_muxer_lookup_action (group->muxer, group->prefix, action_name, &fullname);
for (node = action ? action->watchers : NULL; node; node = node->next)
g_action_observer_action_added (node->data,
G_ACTION_OBSERVABLE (group->muxer),
fullname, parameter_type, enabled, state);
g_action_group_action_added (G_ACTION_GROUP (group->muxer), fullname);
if (state)
g_variant_unref (state);
g_free (fullname);
}
}
static void
g_action_muxer_action_removed (GActionGroup *action_group,
const gchar *action_name,
gpointer user_data)
{
Group *group = user_data;
gchar *fullname;
Action *action;
GSList *node;
action = g_action_muxer_lookup_action (group->muxer, group->prefix, action_name, &fullname);
for (node = action ? action->watchers : NULL; node; node = node->next)
g_action_observer_action_removed (node->data, G_ACTION_OBSERVABLE (group->muxer), fullname);
g_action_group_action_removed (G_ACTION_GROUP (group->muxer), fullname);
g_free (fullname);
}
static gboolean
g_action_muxer_query_action (GActionGroup *action_group,
const gchar *action_name,
gboolean *enabled,
const GVariantType **parameter_type,
const GVariantType **state_type,
GVariant **state_hint,
GVariant **state)
{
GActionMuxer *muxer = G_ACTION_MUXER (action_group);
Group *group;
group = g_action_muxer_find_group (muxer, &action_name);
if (!group)
return FALSE;
return g_action_group_query_action (group->group, action_name, enabled,
parameter_type, state_type, state_hint, state);
}
static GVariant *
get_platform_data (void)
{
gchar time[32];
GVariantBuilder *builder;
GVariant *result;
g_snprintf (time, 32, "_TIME%d", clutter_get_current_event_time ());
builder = g_variant_builder_new (G_VARIANT_TYPE ("a{sv}"));
g_variant_builder_add (builder, "{sv}", "desktop-startup-id",
g_variant_new_string (time));
result = g_variant_builder_end (builder);
g_variant_builder_unref (builder);
return result;
}
static void
g_action_muxer_activate_action (GActionGroup *action_group,
const gchar *action_name,
GVariant *parameter)
{
GActionMuxer *muxer = G_ACTION_MUXER (action_group);
Group *group;
group = g_action_muxer_find_group (muxer, &action_name);
if (group)
{
if (G_IS_REMOTE_ACTION_GROUP (group->group))
g_remote_action_group_activate_action_full (G_REMOTE_ACTION_GROUP (group->group),
action_name,
parameter,
get_platform_data ());
else
g_action_group_activate_action (group->group, action_name, parameter);
}
}
static void
g_action_muxer_change_action_state (GActionGroup *action_group,
const gchar *action_name,
GVariant *state)
{
GActionMuxer *muxer = G_ACTION_MUXER (action_group);
Group *group;
group = g_action_muxer_find_group (muxer, &action_name);
if (group)
{
if (G_IS_REMOTE_ACTION_GROUP (group->group))
g_remote_action_group_change_action_state_full (G_REMOTE_ACTION_GROUP (group->group),
action_name,
state,
get_platform_data ());
else
g_action_group_change_action_state (group->group, action_name, state);
}
}
static void
g_action_muxer_unregister_internal (Action *action,
gpointer observer)
{
GActionMuxer *muxer = action->muxer;
GSList **ptr;
for (ptr = &action->watchers; *ptr; ptr = &(*ptr)->next)
if ((*ptr)->data == observer)
{
*ptr = g_slist_remove (*ptr, observer);
if (action->watchers == NULL)
{
g_hash_table_remove (muxer->actions, action->fullname);
g_free (action->fullname);
g_slice_free (Action, action);
g_object_unref (muxer);
}
break;
}
}
static void
g_action_muxer_weak_notify (gpointer data,
GObject *where_the_object_was)
{
Action *action = data;
g_action_muxer_unregister_internal (action, where_the_object_was);
}
static void
g_action_muxer_register_observer (GActionObservable *observable,
const gchar *name,
GActionObserver *observer)
{
GActionMuxer *muxer = G_ACTION_MUXER (observable);
Action *action;
action = g_hash_table_lookup (muxer->actions, name);
if (action == NULL)
{
action = g_slice_new (Action);
action->muxer = g_object_ref (muxer);
action->fullname = g_strdup (name);
action->watchers = NULL;
g_hash_table_insert (muxer->actions, action->fullname, action);
}
action->watchers = g_slist_prepend (action->watchers, observer);
g_object_weak_ref (G_OBJECT (observer), g_action_muxer_weak_notify, action);
}
static void
g_action_muxer_unregister_observer (GActionObservable *observable,
const gchar *name,
GActionObserver *observer)
{
GActionMuxer *muxer = G_ACTION_MUXER (observable);
Action *action;
action = g_hash_table_lookup (muxer->actions, name);
g_object_weak_unref (G_OBJECT (observer), g_action_muxer_weak_notify, action);
g_action_muxer_unregister_internal (action, observer);
}
static void
g_action_muxer_free_group (gpointer data)
{
Group *group = data;
gint i;
/* 'for loop' or 'four loop'? */
for (i = 0; i < 4; i++)
g_signal_handler_disconnect (group->group, group->handler_ids[i]);
g_object_unref (group->group);
g_free (group->prefix);
g_slice_free (Group, group);
}
static void
g_action_muxer_finalize (GObject *object)
{
GActionMuxer *muxer = G_ACTION_MUXER (object);
g_assert_cmpint (g_hash_table_size (muxer->actions), ==, 0);
g_hash_table_unref (muxer->actions);
g_hash_table_unref (muxer->groups);
G_OBJECT_CLASS (g_action_muxer_parent_class)
->finalize (object);
}
static void
g_action_muxer_init (GActionMuxer *muxer)
{
muxer->actions = g_hash_table_new (g_str_hash, g_str_equal);
muxer->groups = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, g_action_muxer_free_group);
}
static void
g_action_muxer_observable_iface_init (GActionObservableInterface *iface)
{
iface->register_observer = g_action_muxer_register_observer;
iface->unregister_observer = g_action_muxer_unregister_observer;
}
static void
g_action_muxer_group_iface_init (GActionGroupInterface *iface)
{
iface->list_actions = g_action_muxer_list_actions;
iface->query_action = g_action_muxer_query_action;
iface->activate_action = g_action_muxer_activate_action;
iface->change_action_state = g_action_muxer_change_action_state;
}
static void
g_action_muxer_class_init (GObjectClass *class)
{
class->finalize = g_action_muxer_finalize;
}
/*
* g_action_muxer_insert:
* @muxer: a #GActionMuxer
* @prefix: the prefix string for the action group
* @action_group: a #GActionGroup
*
* Adds the actions in @action_group to the list of actions provided by
* @muxer. @prefix is prefixed to each action name, such that for each
* action <varname>x</varname> in @action_group, there is an equivalent
* action @prefix<literal>.</literal><varname>x</varname> in @muxer.
*
* For example, if @prefix is "<literal>app</literal>" and @action_group
* contains an action called "<literal>quit</literal>", then @muxer will
* now contain an action called "<literal>app.quit</literal>".
*
* If any #GActionObservers are registered for actions in the group,
* "action_added" notifications will be emitted, as appropriate.
*
* @prefix must not contain a dot ('.').
*/
void
g_action_muxer_insert (GActionMuxer *muxer,
const gchar *prefix,
GActionGroup *action_group)
{
gchar **actions;
Group *group;
gint i;
/* TODO: diff instead of ripout and replace */
g_action_muxer_remove (muxer, prefix);
group = g_slice_new (Group);
group->muxer = muxer;
group->group = g_object_ref (action_group);
group->prefix = g_strdup (prefix);
g_hash_table_insert (muxer->groups, group->prefix, group);
actions = g_action_group_list_actions (group->group);
for (i = 0; actions[i]; i++)
g_action_muxer_action_added (group->group, actions[i], group);
g_strfreev (actions);
group->handler_ids[0] = g_signal_connect (group->group, "action-added",
G_CALLBACK (g_action_muxer_action_added), group);
group->handler_ids[1] = g_signal_connect (group->group, "action-removed",
G_CALLBACK (g_action_muxer_action_removed), group);
group->handler_ids[2] = g_signal_connect (group->group, "action-enabled-changed",
G_CALLBACK (g_action_muxer_action_enabled_changed), group);
group->handler_ids[3] = g_signal_connect (group->group, "action-state-changed",
G_CALLBACK (g_action_muxer_action_state_changed), group);
}
/*
* g_action_muxer_remove:
* @muxer: a #GActionMuxer
* @prefix: the prefix of the action group to remove
*
* Removes a #GActionGroup from the #GActionMuxer.
*
* If any #GActionObservers are registered for actions in the group,
* "action_removed" notifications will be emitted, as appropriate.
*/
void
g_action_muxer_remove (GActionMuxer *muxer,
const gchar *prefix)
{
Group *group;
group = g_hash_table_lookup (muxer->groups, prefix);
if (group != NULL)
{
gchar **actions;
gint i;
g_hash_table_steal (muxer->groups, prefix);
actions = g_action_group_list_actions (group->group);
for (i = 0; actions[i]; i++)
g_action_muxer_action_removed (group->group, actions[i], group);
g_strfreev (actions);
g_action_muxer_free_group (group);
}
}
/*
* g_action_muxer_new:
*
* Creates a new #GActionMuxer.
*/
GActionMuxer *
g_action_muxer_new (void)
{
return g_object_new (G_TYPE_ACTION_MUXER, NULL);
}

View File

@ -1,53 +0,0 @@
/*
* Copyright © 2011 Canonical Limited
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the licence, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*
* Author: Ryan Lortie <desrt@desrt.ca>
*/
#ifndef __G_ACTION_MUXER_H__
#define __G_ACTION_MUXER_H__
#include <gio/gio.h>
G_BEGIN_DECLS
#define G_TYPE_ACTION_MUXER (g_action_muxer_get_type ())
#define G_ACTION_MUXER(inst) (G_TYPE_CHECK_INSTANCE_CAST ((inst), \
G_TYPE_ACTION_MUXER, GActionMuxer))
#define G_IS_ACTION_MUXER(inst) (G_TYPE_CHECK_INSTANCE_TYPE ((inst), \
G_TYPE_ACTION_MUXER))
typedef struct _GActionMuxer GActionMuxer;
G_GNUC_INTERNAL
GType g_action_muxer_get_type (void);
G_GNUC_INTERNAL
GActionMuxer * g_action_muxer_new (void);
G_GNUC_INTERNAL
void g_action_muxer_insert (GActionMuxer *muxer,
const gchar *prefix,
GActionGroup *group);
G_GNUC_INTERNAL
void g_action_muxer_remove (GActionMuxer *muxer,
const gchar *prefix);
G_END_DECLS
#endif /* __G_ACTION_MUXER_H__ */

View File

@ -1,80 +0,0 @@
/*
* Copyright © 2011 Canonical Limited
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2 of the
* licence or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307,
* USA.
*
* Authors: Ryan Lortie <desrt@desrt.ca>
*/
#include "config.h"
#include "gactionobservable.h"
G_DEFINE_INTERFACE (GActionObservable, g_action_observable, G_TYPE_OBJECT)
/*
* SECTION:gactionobserable
* @short_description: an interface implemented by objects that report
* changes to actions
*/
void
g_action_observable_default_init (GActionObservableInterface *iface)
{
}
/*
* g_action_observable_register_observer:
* @observable: a #GActionObservable
* @action_name: the name of the action
* @observer: the #GActionObserver to which the events will be reported
*
* Registers @observer as being interested in changes to @action_name on
* @observable.
*/
void
g_action_observable_register_observer (GActionObservable *observable,
const gchar *action_name,
GActionObserver *observer)
{
g_return_if_fail (G_IS_ACTION_OBSERVABLE (observable));
G_ACTION_OBSERVABLE_GET_IFACE (observable)
->register_observer (observable, action_name, observer);
}
/*
* g_action_observable_unregister_observer:
* @observable: a #GActionObservable
* @action_name: the name of the action
* @observer: the #GActionObserver to which the events will be reported
*
* Removes the registration of @observer as being interested in changes
* to @action_name on @observable.
*
* If the observer was registered multiple times, it must be
* unregistered an equal number of times.
*/
void
g_action_observable_unregister_observer (GActionObservable *observable,
const gchar *action_name,
GActionObserver *observer)
{
g_return_if_fail (G_IS_ACTION_OBSERVABLE (observable));
G_ACTION_OBSERVABLE_GET_IFACE (observable)
->unregister_observer (observable, action_name, observer);
}

View File

@ -1,64 +0,0 @@
/*
* Copyright © 2011 Canonical Limited
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2 of the
* licence or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307,
* USA.
*
* Authors: Ryan Lortie <desrt@desrt.ca>
*/
#ifndef __G_ACTION_OBSERVABLE_H__
#define __G_ACTION_OBSERVABLE_H__
#include "gactionobserver.h"
G_BEGIN_DECLS
#define G_TYPE_ACTION_OBSERVABLE (g_action_observable_get_type ())
#define G_ACTION_OBSERVABLE(inst) (G_TYPE_CHECK_INSTANCE_CAST ((inst), \
G_TYPE_ACTION_OBSERVABLE, GActionObservable))
#define G_IS_ACTION_OBSERVABLE(inst) (G_TYPE_CHECK_INSTANCE_TYPE ((inst), \
G_TYPE_ACTION_OBSERVABLE))
#define G_ACTION_OBSERVABLE_GET_IFACE(inst) (G_TYPE_INSTANCE_GET_INTERFACE ((inst), \
G_TYPE_ACTION_OBSERVABLE, GActionObservableInterface))
typedef struct _GActionObservableInterface GActionObservableInterface;
struct _GActionObservableInterface
{
GTypeInterface g_iface;
void (* register_observer) (GActionObservable *observable,
const gchar *action_name,
GActionObserver *observer);
void (* unregister_observer) (GActionObservable *observable,
const gchar *action_name,
GActionObserver *observer);
};
G_GNUC_INTERNAL
GType g_action_observable_get_type (void);
G_GNUC_INTERNAL
void g_action_observable_register_observer (GActionObservable *observable,
const gchar *action_name,
GActionObserver *observer);
G_GNUC_INTERNAL
void g_action_observable_unregister_observer (GActionObservable *observable,
const gchar *action_name,
GActionObserver *observer);
G_END_DECLS
#endif /* __G_ACTION_OBSERVABLE_H__ */

View File

@ -1,90 +0,0 @@
/*
* Copyright © 2011 Canonical Limited
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2 of the
* licence or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307,
* USA.
*
* Authors: Ryan Lortie <desrt@desrt.ca>
*/
#ifndef __G_ACTION_OBSERVER_H__
#define __G_ACTION_OBSERVER_H__
#include <gio/gio.h>
G_BEGIN_DECLS
#define G_TYPE_ACTION_OBSERVER (g_action_observer_get_type ())
#define G_ACTION_OBSERVER(inst) (G_TYPE_CHECK_INSTANCE_CAST ((inst), \
G_TYPE_ACTION_OBSERVER, GActionObserver))
#define G_IS_ACTION_OBSERVER(inst) (G_TYPE_CHECK_INSTANCE_TYPE ((inst), \
G_TYPE_ACTION_OBSERVER))
#define G_ACTION_OBSERVER_GET_IFACE(inst) (G_TYPE_INSTANCE_GET_INTERFACE ((inst), \
G_TYPE_ACTION_OBSERVER, GActionObserverInterface))
typedef struct _GActionObserverInterface GActionObserverInterface;
typedef struct _GActionObservable GActionObservable;
typedef struct _GActionObserver GActionObserver;
struct _GActionObserverInterface
{
GTypeInterface g_iface;
void (* action_added) (GActionObserver *observer,
GActionObservable *observable,
const gchar *action_name,
const GVariantType *parameter_type,
gboolean enabled,
GVariant *state);
void (* action_enabled_changed) (GActionObserver *observer,
GActionObservable *observable,
const gchar *action_name,
gboolean enabled);
void (* action_state_changed) (GActionObserver *observer,
GActionObservable *observable,
const gchar *action_name,
GVariant *state);
void (* action_removed) (GActionObserver *observer,
GActionObservable *observable,
const gchar *action_name);
};
G_GNUC_INTERNAL
GType g_action_observer_get_type (void);
G_GNUC_INTERNAL
void g_action_observer_action_added (GActionObserver *observer,
GActionObservable *observable,
const gchar *action_name,
const GVariantType *parameter_type,
gboolean enabled,
GVariant *state);
G_GNUC_INTERNAL
void g_action_observer_action_enabled_changed (GActionObserver *observer,
GActionObservable *observable,
const gchar *action_name,
gboolean enabled);
G_GNUC_INTERNAL
void g_action_observer_action_state_changed (GActionObserver *observer,
GActionObservable *observable,
const gchar *action_name,
GVariant *state);
G_GNUC_INTERNAL
void g_action_observer_action_removed (GActionObserver *observer,
GActionObservable *observable,
const gchar *action_name);
G_END_DECLS
#endif /* __G_ACTION_OBSERVER_H__ */

808
src/gtkactionmuxer.c Normal file
View File

@ -0,0 +1,808 @@
/*
* Copyright © 2011 Canonical Limited
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the licence, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
* Author: Ryan Lortie <desrt@desrt.ca>
*/
#include "config.h"
#include "gtkactionmuxer.h"
#include "gtkactionobservable.h"
#include "gtkactionobserver.h"
#include <clutter/clutter.h>
#include <string.h>
/**
* SECTION:gtkactionmuxer
* @short_description: Aggregate and monitor several action groups
*
* #GtkActionMuxer is a #GActionGroup and #GtkActionObservable that is
* capable of containing other #GActionGroup instances.
*
* The typical use is aggregating all of the actions applicable to a
* particular context into a single action group, with namespacing.
*
* Consider the case of two action groups -- one containing actions
* applicable to an entire application (such as 'quit') and one
* containing actions applicable to a particular window in the
* application (such as 'fullscreen').
*
* In this case, each of these action groups could be added to a
* #GtkActionMuxer with the prefixes "app" and "win", respectively. This
* would expose the actions as "app.quit" and "win.fullscreen" on the
* #GActionGroup interface presented by the #GtkActionMuxer.
*
* Activations and state change requests on the #GtkActionMuxer are wired
* through to the underlying action group in the expected way.
*
* This class is typically only used at the site of "consumption" of
* actions (eg: when displaying a menu that contains many actions on
* different objects).
*/
static void gtk_action_muxer_group_iface_init (GActionGroupInterface *iface);
static void gtk_action_muxer_observable_iface_init (GtkActionObservableInterface *iface);
typedef GObjectClass GtkActionMuxerClass;
struct _GtkActionMuxer
{
GObject parent_instance;
GHashTable *observed_actions;
GHashTable *groups;
GtkActionMuxer *parent;
};
G_DEFINE_TYPE_WITH_CODE (GtkActionMuxer, gtk_action_muxer, G_TYPE_OBJECT,
G_IMPLEMENT_INTERFACE (G_TYPE_ACTION_GROUP, gtk_action_muxer_group_iface_init)
G_IMPLEMENT_INTERFACE (GTK_TYPE_ACTION_OBSERVABLE, gtk_action_muxer_observable_iface_init))
enum
{
PROP_0,
PROP_PARENT,
NUM_PROPERTIES
};
static GParamSpec *properties[NUM_PROPERTIES];
typedef struct
{
GtkActionMuxer *muxer;
GSList *watchers;
gchar *fullname;
} Action;
typedef struct
{
GtkActionMuxer *muxer;
GActionGroup *group;
gchar *prefix;
gulong handler_ids[4];
} Group;
static void
gtk_action_muxer_append_group_actions (gpointer key,
gpointer value,
gpointer user_data)
{
const gchar *prefix = key;
Group *group = value;
GArray *actions = user_data;
gchar **group_actions;
gchar **action;
group_actions = g_action_group_list_actions (group->group);
for (action = group_actions; *action; action++)
{
gchar *fullname;
fullname = g_strconcat (prefix, ".", *action, NULL);
g_array_append_val (actions, fullname);
}
g_strfreev (group_actions);
}
static gchar **
gtk_action_muxer_list_actions (GActionGroup *action_group)
{
GtkActionMuxer *muxer = GTK_ACTION_MUXER (action_group);
GArray *actions;
actions = g_array_new (TRUE, FALSE, sizeof (gchar *));
for ( ; muxer != NULL; muxer = muxer->parent)
{
g_hash_table_foreach (muxer->groups,
gtk_action_muxer_append_group_actions,
actions);
}
return (gchar **) g_array_free (actions, FALSE);
}
static Group *
gtk_action_muxer_find_group (GtkActionMuxer *muxer,
const gchar *full_name,
const gchar **action_name)
{
const gchar *dot;
gchar *prefix;
Group *group;
dot = strchr (full_name, '.');
if (!dot)
return NULL;
prefix = g_strndup (full_name, dot - full_name);
group = g_hash_table_lookup (muxer->groups, prefix);
g_free (prefix);
if (action_name)
*action_name = dot + 1;
return group;
}
static void
gtk_action_muxer_action_enabled_changed (GtkActionMuxer *muxer,
const gchar *action_name,
gboolean enabled)
{
Action *action;
GSList *node;
action = g_hash_table_lookup (muxer->observed_actions, action_name);
for (node = action ? action->watchers : NULL; node; node = node->next)
gtk_action_observer_action_enabled_changed (node->data, GTK_ACTION_OBSERVABLE (muxer), action_name, enabled);
g_action_group_action_enabled_changed (G_ACTION_GROUP (muxer), action_name, enabled);
}
static void
gtk_action_muxer_group_action_enabled_changed (GActionGroup *action_group,
const gchar *action_name,
gboolean enabled,
gpointer user_data)
{
Group *group = user_data;
gchar *fullname;
fullname = g_strconcat (group->prefix, ".", action_name, NULL);
gtk_action_muxer_action_enabled_changed (group->muxer, fullname, enabled);
g_free (fullname);
}
static void
gtk_action_muxer_parent_action_enabled_changed (GActionGroup *action_group,
const gchar *action_name,
gboolean enabled,
gpointer user_data)
{
GtkActionMuxer *muxer = user_data;
gtk_action_muxer_action_enabled_changed (muxer, action_name, enabled);
}
static void
gtk_action_muxer_action_state_changed (GtkActionMuxer *muxer,
const gchar *action_name,
GVariant *state)
{
Action *action;
GSList *node;
action = g_hash_table_lookup (muxer->observed_actions, action_name);
for (node = action ? action->watchers : NULL; node; node = node->next)
gtk_action_observer_action_state_changed (node->data, GTK_ACTION_OBSERVABLE (muxer), action_name, state);
g_action_group_action_state_changed (G_ACTION_GROUP (muxer), action_name, state);
}
static void
gtk_action_muxer_group_action_state_changed (GActionGroup *action_group,
const gchar *action_name,
GVariant *state,
gpointer user_data)
{
Group *group = user_data;
gchar *fullname;
fullname = g_strconcat (group->prefix, ".", action_name, NULL);
gtk_action_muxer_action_state_changed (group->muxer, fullname, state);
g_free (fullname);
}
static void
gtk_action_muxer_parent_action_state_changed (GActionGroup *action_group,
const gchar *action_name,
GVariant *state,
gpointer user_data)
{
GtkActionMuxer *muxer = user_data;
gtk_action_muxer_action_state_changed (muxer, action_name, state);
}
static void
gtk_action_muxer_action_added (GtkActionMuxer *muxer,
const gchar *action_name,
GActionGroup *original_group,
const gchar *orignal_action_name)
{
const GVariantType *parameter_type;
gboolean enabled;
GVariant *state;
Action *action;
action = g_hash_table_lookup (muxer->observed_actions, action_name);
if (action && action->watchers &&
g_action_group_query_action (original_group, orignal_action_name,
&enabled, &parameter_type, NULL, NULL, &state))
{
GSList *node;
for (node = action->watchers; node; node = node->next)
gtk_action_observer_action_added (node->data,
GTK_ACTION_OBSERVABLE (muxer),
action_name, parameter_type, enabled, state);
if (state)
g_variant_unref (state);
}
g_action_group_action_added (G_ACTION_GROUP (muxer), action_name);
}
static void
gtk_action_muxer_action_added_to_group (GActionGroup *action_group,
const gchar *action_name,
gpointer user_data)
{
Group *group = user_data;
gchar *fullname;
fullname = g_strconcat (group->prefix, ".", action_name, NULL);
gtk_action_muxer_action_added (group->muxer, fullname, action_group, action_name);
g_free (fullname);
}
static void
gtk_action_muxer_action_added_to_parent (GActionGroup *action_group,
const gchar *action_name,
gpointer user_data)
{
GtkActionMuxer *muxer = user_data;
gtk_action_muxer_action_added (muxer, action_name, action_group, action_name);
}
static void
gtk_action_muxer_action_removed (GtkActionMuxer *muxer,
const gchar *action_name)
{
Action *action;
GSList *node;
action = g_hash_table_lookup (muxer->observed_actions, action_name);
for (node = action ? action->watchers : NULL; node; node = node->next)
gtk_action_observer_action_removed (node->data, GTK_ACTION_OBSERVABLE (muxer), action_name);
g_action_group_action_removed (G_ACTION_GROUP (muxer), action_name);
}
static void
gtk_action_muxer_action_removed_from_group (GActionGroup *action_group,
const gchar *action_name,
gpointer user_data)
{
Group *group = user_data;
gchar *fullname;
fullname = g_strconcat (group->prefix, ".", action_name, NULL);
gtk_action_muxer_action_removed (group->muxer, fullname);
g_free (fullname);
}
static void
gtk_action_muxer_action_removed_from_parent (GActionGroup *action_group,
const gchar *action_name,
gpointer user_data)
{
GtkActionMuxer *muxer = user_data;
gtk_action_muxer_action_removed (muxer, action_name);
}
static gboolean
gtk_action_muxer_query_action (GActionGroup *action_group,
const gchar *action_name,
gboolean *enabled,
const GVariantType **parameter_type,
const GVariantType **state_type,
GVariant **state_hint,
GVariant **state)
{
GtkActionMuxer *muxer = GTK_ACTION_MUXER (action_group);
Group *group;
const gchar *unprefixed_name;
group = gtk_action_muxer_find_group (muxer, action_name, &unprefixed_name);
if (group)
return g_action_group_query_action (group->group, unprefixed_name, enabled,
parameter_type, state_type, state_hint, state);
if (muxer->parent)
return g_action_group_query_action (G_ACTION_GROUP (muxer->parent), action_name,
enabled, parameter_type,
state_type, state_hint, state);
return FALSE;
}
static void
gtk_action_muxer_activate_action (GActionGroup *action_group,
const gchar *action_name,
GVariant *parameter)
{
GtkActionMuxer *muxer = GTK_ACTION_MUXER (action_group);
Group *group;
const gchar *unprefixed_name;
group = gtk_action_muxer_find_group (muxer, action_name, &unprefixed_name);
if (group)
g_action_group_activate_action (group->group, unprefixed_name, parameter);
else if (muxer->parent)
g_action_group_activate_action (G_ACTION_GROUP (muxer->parent), action_name, parameter);
}
static GVariant *
get_platform_data (void)
{
gchar time[32];
GVariantBuilder *builder;
GVariant *result;
g_snprintf (time, 32, "_TIME%d", clutter_get_current_event_time ());
builder = g_variant_builder_new (G_VARIANT_TYPE ("a{sv}"));
g_variant_builder_add (builder, "{sv}", "desktop-startup-id",
g_variant_new_string (time));
result = g_variant_builder_end (builder);
g_variant_builder_unref (builder);
return result;
}
static void
gtk_action_muxer_change_action_state (GActionGroup *action_group,
const gchar *action_name,
GVariant *state)
{
GtkActionMuxer *muxer = GTK_ACTION_MUXER (action_group);
Group *group;
const gchar *unprefixed_name;
group = gtk_action_muxer_find_group (muxer, action_name, &unprefixed_name);
if (group)
{
if (G_IS_REMOTE_ACTION_GROUP (group->group))
g_remote_action_group_change_action_state_full (G_REMOTE_ACTION_GROUP (group->group),
unprefixed_name,
state,
get_platform_data ());
else
g_action_group_change_action_state (group->group, unprefixed_name, state);
}
else if (muxer->parent)
g_action_group_change_action_state (G_ACTION_GROUP (muxer->parent), action_name, state);
}
static void
gtk_action_muxer_unregister_internal (Action *action,
gpointer observer)
{
GtkActionMuxer *muxer = action->muxer;
GSList **ptr;
for (ptr = &action->watchers; *ptr; ptr = &(*ptr)->next)
if ((*ptr)->data == observer)
{
*ptr = g_slist_remove (*ptr, observer);
if (action->watchers == NULL)
g_hash_table_remove (muxer->observed_actions, action->fullname);
break;
}
}
static void
gtk_action_muxer_weak_notify (gpointer data,
GObject *where_the_object_was)
{
Action *action = data;
gtk_action_muxer_unregister_internal (action, where_the_object_was);
}
static void
gtk_action_muxer_register_observer (GtkActionObservable *observable,
const gchar *name,
GtkActionObserver *observer)
{
GtkActionMuxer *muxer = GTK_ACTION_MUXER (observable);
Action *action;
action = g_hash_table_lookup (muxer->observed_actions, name);
if (action == NULL)
{
action = g_slice_new (Action);
action->muxer = muxer;
action->fullname = g_strdup (name);
action->watchers = NULL;
g_hash_table_insert (muxer->observed_actions, action->fullname, action);
}
action->watchers = g_slist_prepend (action->watchers, observer);
g_object_weak_ref (G_OBJECT (observer), gtk_action_muxer_weak_notify, action);
}
static void
gtk_action_muxer_unregister_observer (GtkActionObservable *observable,
const gchar *name,
GtkActionObserver *observer)
{
GtkActionMuxer *muxer = GTK_ACTION_MUXER (observable);
Action *action;
action = g_hash_table_lookup (muxer->observed_actions, name);
g_object_weak_unref (G_OBJECT (observer), gtk_action_muxer_weak_notify, action);
gtk_action_muxer_unregister_internal (action, observer);
}
static void
gtk_action_muxer_free_group (gpointer data)
{
Group *group = data;
gint i;
/* 'for loop' or 'four loop'? */
for (i = 0; i < 4; i++)
g_signal_handler_disconnect (group->group, group->handler_ids[i]);
g_object_unref (group->group);
g_free (group->prefix);
g_slice_free (Group, group);
}
static void
gtk_action_muxer_free_action (gpointer data)
{
Action *action = data;
GSList *it;
for (it = action->watchers; it; it = it->next)
g_object_weak_unref (G_OBJECT (it->data), gtk_action_muxer_weak_notify, action);
g_slist_free (action->watchers);
g_free (action->fullname);
g_slice_free (Action, action);
}
static void
gtk_action_muxer_finalize (GObject *object)
{
GtkActionMuxer *muxer = GTK_ACTION_MUXER (object);
g_assert_cmpint (g_hash_table_size (muxer->observed_actions), ==, 0);
g_hash_table_unref (muxer->observed_actions);
g_hash_table_unref (muxer->groups);
G_OBJECT_CLASS (gtk_action_muxer_parent_class)
->finalize (object);
}
static void
gtk_action_muxer_dispose (GObject *object)
{
GtkActionMuxer *muxer = GTK_ACTION_MUXER (object);
if (muxer->parent)
{
g_signal_handlers_disconnect_by_func (muxer->parent, gtk_action_muxer_action_added_to_parent, muxer);
g_signal_handlers_disconnect_by_func (muxer->parent, gtk_action_muxer_action_removed_from_parent, muxer);
g_signal_handlers_disconnect_by_func (muxer->parent, gtk_action_muxer_parent_action_enabled_changed, muxer);
g_signal_handlers_disconnect_by_func (muxer->parent, gtk_action_muxer_parent_action_state_changed, muxer);
g_clear_object (&muxer->parent);
}
g_hash_table_remove_all (muxer->observed_actions);
G_OBJECT_CLASS (gtk_action_muxer_parent_class)
->dispose (object);
}
static void
gtk_action_muxer_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec)
{
GtkActionMuxer *muxer = GTK_ACTION_MUXER (object);
switch (property_id)
{
case PROP_PARENT:
g_value_set_object (value, gtk_action_muxer_get_parent (muxer));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
}
}
static void
gtk_action_muxer_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec)
{
GtkActionMuxer *muxer = GTK_ACTION_MUXER (object);
switch (property_id)
{
case PROP_PARENT:
gtk_action_muxer_set_parent (muxer, g_value_get_object (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
}
}
static void
gtk_action_muxer_init (GtkActionMuxer *muxer)
{
muxer->observed_actions = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, gtk_action_muxer_free_action);
muxer->groups = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, gtk_action_muxer_free_group);
}
static void
gtk_action_muxer_observable_iface_init (GtkActionObservableInterface *iface)
{
iface->register_observer = gtk_action_muxer_register_observer;
iface->unregister_observer = gtk_action_muxer_unregister_observer;
}
static void
gtk_action_muxer_group_iface_init (GActionGroupInterface *iface)
{
iface->list_actions = gtk_action_muxer_list_actions;
iface->query_action = gtk_action_muxer_query_action;
iface->activate_action = gtk_action_muxer_activate_action;
iface->change_action_state = gtk_action_muxer_change_action_state;
}
static void
gtk_action_muxer_class_init (GObjectClass *class)
{
class->get_property = gtk_action_muxer_get_property;
class->set_property = gtk_action_muxer_set_property;
class->finalize = gtk_action_muxer_finalize;
class->dispose = gtk_action_muxer_dispose;
properties[PROP_PARENT] = g_param_spec_object ("parent", "Parent",
"The parent muxer",
GTK_TYPE_ACTION_MUXER,
G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS);
g_object_class_install_properties (class, NUM_PROPERTIES, properties);
}
/**
* gtk_action_muxer_insert:
* @muxer: a #GtkActionMuxer
* @prefix: the prefix string for the action group
* @action_group: a #GActionGroup
*
* Adds the actions in @action_group to the list of actions provided by
* @muxer. @prefix is prefixed to each action name, such that for each
* action <varname>x</varname> in @action_group, there is an equivalent
* action @prefix<literal>.</literal><varname>x</varname> in @muxer.
*
* For example, if @prefix is "<literal>app</literal>" and @action_group
* contains an action called "<literal>quit</literal>", then @muxer will
* now contain an action called "<literal>app.quit</literal>".
*
* If any #GtkActionObservers are registered for actions in the group,
* "action_added" notifications will be emitted, as appropriate.
*
* @prefix must not contain a dot ('.').
*/
void
gtk_action_muxer_insert (GtkActionMuxer *muxer,
const gchar *prefix,
GActionGroup *action_group)
{
gchar **actions;
Group *group;
gint i;
/* TODO: diff instead of ripout and replace */
gtk_action_muxer_remove (muxer, prefix);
group = g_slice_new (Group);
group->muxer = muxer;
group->group = g_object_ref (action_group);
group->prefix = g_strdup (prefix);
g_hash_table_insert (muxer->groups, group->prefix, group);
actions = g_action_group_list_actions (group->group);
for (i = 0; actions[i]; i++)
gtk_action_muxer_action_added_to_group (group->group, actions[i], group);
g_strfreev (actions);
group->handler_ids[0] = g_signal_connect (group->group, "action-added",
G_CALLBACK (gtk_action_muxer_action_added_to_group), group);
group->handler_ids[1] = g_signal_connect (group->group, "action-removed",
G_CALLBACK (gtk_action_muxer_action_removed_from_group), group);
group->handler_ids[2] = g_signal_connect (group->group, "action-enabled-changed",
G_CALLBACK (gtk_action_muxer_group_action_enabled_changed), group);
group->handler_ids[3] = g_signal_connect (group->group, "action-state-changed",
G_CALLBACK (gtk_action_muxer_group_action_state_changed), group);
}
/**
* gtk_action_muxer_remove:
* @muxer: a #GtkActionMuxer
* @prefix: the prefix of the action group to remove
*
* Removes a #GActionGroup from the #GtkActionMuxer.
*
* If any #GtkActionObservers are registered for actions in the group,
* "action_removed" notifications will be emitted, as appropriate.
*/
void
gtk_action_muxer_remove (GtkActionMuxer *muxer,
const gchar *prefix)
{
Group *group;
group = g_hash_table_lookup (muxer->groups, prefix);
if (group != NULL)
{
gchar **actions;
gint i;
g_hash_table_steal (muxer->groups, prefix);
actions = g_action_group_list_actions (group->group);
for (i = 0; actions[i]; i++)
gtk_action_muxer_action_removed_from_group (group->group, actions[i], group);
g_strfreev (actions);
gtk_action_muxer_free_group (group);
}
}
/**
* gtk_action_muxer_new:
*
* Creates a new #GtkActionMuxer.
*/
GtkActionMuxer *
gtk_action_muxer_new (void)
{
return g_object_new (GTK_TYPE_ACTION_MUXER, NULL);
}
/**
* gtk_action_muxer_get_parent:
* @muxer: a #GtkActionMuxer
*
* Returns: (transfer none): the parent of @muxer, or NULL.
*/
GtkActionMuxer *
gtk_action_muxer_get_parent (GtkActionMuxer *muxer)
{
g_return_val_if_fail (GTK_IS_ACTION_MUXER (muxer), NULL);
return muxer->parent;
}
/**
* gtk_action_muxer_set_parent:
* @muxer: a #GtkActionMuxer
* @parent: (allow-none): the new parent #GtkActionMuxer
*
* Sets the parent of @muxer to @parent.
*/
void
gtk_action_muxer_set_parent (GtkActionMuxer *muxer,
GtkActionMuxer *parent)
{
g_return_if_fail (GTK_IS_ACTION_MUXER (muxer));
g_return_if_fail (parent == NULL || GTK_IS_ACTION_MUXER (parent));
if (muxer->parent == parent)
return;
if (muxer->parent != NULL)
{
gchar **actions;
gchar **it;
actions = g_action_group_list_actions (G_ACTION_GROUP (muxer->parent));
for (it = actions; *it; it++)
gtk_action_muxer_action_removed (muxer, *it);
g_strfreev (actions);
g_signal_handlers_disconnect_by_func (muxer->parent, gtk_action_muxer_action_added_to_parent, muxer);
g_signal_handlers_disconnect_by_func (muxer->parent, gtk_action_muxer_action_removed_from_parent, muxer);
g_signal_handlers_disconnect_by_func (muxer->parent, gtk_action_muxer_parent_action_enabled_changed, muxer);
g_signal_handlers_disconnect_by_func (muxer->parent, gtk_action_muxer_parent_action_state_changed, muxer);
g_object_unref (muxer->parent);
}
muxer->parent = parent;
if (muxer->parent != NULL)
{
gchar **actions;
gchar **it;
g_object_ref (muxer->parent);
actions = g_action_group_list_actions (G_ACTION_GROUP (muxer->parent));
for (it = actions; *it; it++)
gtk_action_muxer_action_added (muxer, *it, G_ACTION_GROUP (muxer->parent), *it);
g_strfreev (actions);
g_signal_connect (muxer->parent, "action-added",
G_CALLBACK (gtk_action_muxer_action_added_to_parent), muxer);
g_signal_connect (muxer->parent, "action-removed",
G_CALLBACK (gtk_action_muxer_action_removed_from_parent), muxer);
g_signal_connect (muxer->parent, "action-enabled-changed",
G_CALLBACK (gtk_action_muxer_parent_action_enabled_changed), muxer);
g_signal_connect (muxer->parent, "action-state-changed",
G_CALLBACK (gtk_action_muxer_parent_action_state_changed), muxer);
}
g_object_notify_by_pspec (G_OBJECT (muxer), properties[PROP_PARENT]);
}

52
src/gtkactionmuxer.h Normal file
View File

@ -0,0 +1,52 @@
/*
* Copyright © 2011 Canonical Limited
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the licence, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
* Author: Ryan Lortie <desrt@desrt.ca>
*/
#ifndef __GTK_ACTION_MUXER_H__
#define __GTK_ACTION_MUXER_H__
#include <gio/gio.h>
G_BEGIN_DECLS
#define GTK_TYPE_ACTION_MUXER (gtk_action_muxer_get_type ())
#define GTK_ACTION_MUXER(inst) (G_TYPE_CHECK_INSTANCE_CAST ((inst), \
GTK_TYPE_ACTION_MUXER, GtkActionMuxer))
#define GTK_IS_ACTION_MUXER(inst) (G_TYPE_CHECK_INSTANCE_TYPE ((inst), \
GTK_TYPE_ACTION_MUXER))
typedef struct _GtkActionMuxer GtkActionMuxer;
GType gtk_action_muxer_get_type (void);
GtkActionMuxer * gtk_action_muxer_new (void);
void gtk_action_muxer_insert (GtkActionMuxer *muxer,
const gchar *prefix,
GActionGroup *action_group);
void gtk_action_muxer_remove (GtkActionMuxer *muxer,
const gchar *prefix);
GtkActionMuxer * gtk_action_muxer_get_parent (GtkActionMuxer *muxer);
void gtk_action_muxer_set_parent (GtkActionMuxer *muxer,
GtkActionMuxer *parent);
G_END_DECLS
#endif /* __GTK_ACTION_MUXER_H__ */

78
src/gtkactionobservable.c Normal file
View File

@ -0,0 +1,78 @@
/*
* Copyright © 2011 Canonical Limited
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2 of the
* licence or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
* Authors: Ryan Lortie <desrt@desrt.ca>
*/
#include "config.h"
#include "gtkactionobservable.h"
G_DEFINE_INTERFACE (GtkActionObservable, gtk_action_observable, G_TYPE_OBJECT)
/*
* SECTION:gtkactionobserable
* @short_description: an interface implemented by objects that report
* changes to actions
*/
void
gtk_action_observable_default_init (GtkActionObservableInterface *iface)
{
}
/**
* gtk_action_observable_register_observer:
* @observable: a #GtkActionObservable
* @action_name: the name of the action
* @observer: the #GtkActionObserver to which the events will be reported
*
* Registers @observer as being interested in changes to @action_name on
* @observable.
*/
void
gtk_action_observable_register_observer (GtkActionObservable *observable,
const gchar *action_name,
GtkActionObserver *observer)
{
g_return_if_fail (GTK_IS_ACTION_OBSERVABLE (observable));
GTK_ACTION_OBSERVABLE_GET_IFACE (observable)
->register_observer (observable, action_name, observer);
}
/**
* gtk_action_observable_unregister_observer:
* @observable: a #GtkActionObservable
* @action_name: the name of the action
* @observer: the #GtkActionObserver to which the events will be reported
*
* Removes the registration of @observer as being interested in changes
* to @action_name on @observable.
*
* If the observer was registered multiple times, it must be
* unregistered an equal number of times.
*/
void
gtk_action_observable_unregister_observer (GtkActionObservable *observable,
const gchar *action_name,
GtkActionObserver *observer)
{
g_return_if_fail (GTK_IS_ACTION_OBSERVABLE (observable));
GTK_ACTION_OBSERVABLE_GET_IFACE (observable)
->unregister_observer (observable, action_name, observer);
}

60
src/gtkactionobservable.h Normal file
View File

@ -0,0 +1,60 @@
/*
* Copyright © 2011 Canonical Limited
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2 of the
* licence or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
* Authors: Ryan Lortie <desrt@desrt.ca>
*/
#ifndef __GTK_ACTION_OBSERVABLE_H__
#define __GTK_ACTION_OBSERVABLE_H__
#include "gtkactionobserver.h"
G_BEGIN_DECLS
#define GTK_TYPE_ACTION_OBSERVABLE (gtk_action_observable_get_type ())
#define GTK_ACTION_OBSERVABLE(inst) (G_TYPE_CHECK_INSTANCE_CAST ((inst), \
GTK_TYPE_ACTION_OBSERVABLE, GtkActionObservable))
#define GTK_IS_ACTION_OBSERVABLE(inst) (G_TYPE_CHECK_INSTANCE_TYPE ((inst), \
GTK_TYPE_ACTION_OBSERVABLE))
#define GTK_ACTION_OBSERVABLE_GET_IFACE(inst) (G_TYPE_INSTANCE_GET_INTERFACE ((inst), \
GTK_TYPE_ACTION_OBSERVABLE, \
GtkActionObservableInterface))
typedef struct _GtkActionObservableInterface GtkActionObservableInterface;
struct _GtkActionObservableInterface
{
GTypeInterface g_iface;
void (* register_observer) (GtkActionObservable *observable,
const gchar *action_name,
GtkActionObserver *observer);
void (* unregister_observer) (GtkActionObservable *observable,
const gchar *action_name,
GtkActionObserver *observer);
};
GType gtk_action_observable_get_type (void);
void gtk_action_observable_register_observer (GtkActionObservable *observable,
const gchar *action_name,
GtkActionObserver *observer);
void gtk_action_observable_unregister_observer (GtkActionObservable *observable,
const gchar *action_name,
GtkActionObserver *observer);
G_END_DECLS
#endif /* __GTK_ACTION_OBSERVABLE_H__ */

View File

@ -1,7 +1,7 @@
/*
* Copyright © 2011 Canonical Limited
*
* This program is free software: you can redistribute it and/or modify
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2 of the
* licence or (at your option) any later version.
@ -12,25 +12,23 @@
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307,
* USA.
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
* Authors: Ryan Lortie <desrt@desrt.ca>
*/
#include "config.h"
#include "gactionobserver.h"
#include "gtkactionobserver.h"
G_DEFINE_INTERFACE (GActionObserver, g_action_observer, G_TYPE_OBJECT)
G_DEFINE_INTERFACE (GtkActionObserver, gtk_action_observer, G_TYPE_OBJECT)
/**
* SECTION:gactionobserver
* SECTION:gtkactionobserver
* @short_description: an interface implemented by objects that are
* interested in monitoring actions for changes
*
* GActionObserver is a simple interface allowing objects that wish to
* GtkActionObserver is a simple interface allowing objects that wish to
* be notified of changes to actions to be notified of those changes.
*
* It is also possible to monitor changes to action groups using
@ -52,13 +50,13 @@ G_DEFINE_INTERFACE (GActionObserver, g_action_observer, G_TYPE_OBJECT)
*/
void
g_action_observer_default_init (GActionObserverInterface *class)
gtk_action_observer_default_init (GtkActionObserverInterface *class)
{
}
/*
* g_action_observer_action_added:
* @observer: a #GActionObserver
/**
* gtk_action_observer_action_added:
* @observer: a #GtkActionObserver
* @observable: the source of the event
* @action_name: the name of the action
* @enabled: %TRUE if the action is now enabled
@ -74,22 +72,22 @@ g_action_observer_default_init (GActionObserverInterface *class)
* observer has explicitly registered itself to receive events.
*/
void
g_action_observer_action_added (GActionObserver *observer,
GActionObservable *observable,
const gchar *action_name,
const GVariantType *parameter_type,
gboolean enabled,
GVariant *state)
gtk_action_observer_action_added (GtkActionObserver *observer,
GtkActionObservable *observable,
const gchar *action_name,
const GVariantType *parameter_type,
gboolean enabled,
GVariant *state)
{
g_return_if_fail (G_IS_ACTION_OBSERVER (observer));
g_return_if_fail (GTK_IS_ACTION_OBSERVER (observer));
G_ACTION_OBSERVER_GET_IFACE (observer)
GTK_ACTION_OBSERVER_GET_IFACE (observer)
->action_added (observer, observable, action_name, parameter_type, enabled, state);
}
/*
* g_action_observer_action_enabled_changed:
* @observer: a #GActionObserver
/**
* gtk_action_observer_action_enabled_changed:
* @observer: a #GtkActionObserver
* @observable: the source of the event
* @action_name: the name of the action
* @enabled: %TRUE if the action is now enabled
@ -101,45 +99,45 @@ g_action_observer_action_added (GActionObserver *observer,
* observer has explicitly registered itself to receive events.
*/
void
g_action_observer_action_enabled_changed (GActionObserver *observer,
GActionObservable *observable,
const gchar *action_name,
gboolean enabled)
gtk_action_observer_action_enabled_changed (GtkActionObserver *observer,
GtkActionObservable *observable,
const gchar *action_name,
gboolean enabled)
{
g_return_if_fail (G_IS_ACTION_OBSERVER (observer));
g_return_if_fail (GTK_IS_ACTION_OBSERVER (observer));
G_ACTION_OBSERVER_GET_IFACE (observer)
GTK_ACTION_OBSERVER_GET_IFACE (observer)
->action_enabled_changed (observer, observable, action_name, enabled);
}
/*
* g_action_observer_action_state_changed:
* @observer: a #GActionObserver
/**
* gtk_action_observer_action_state_changed:
* @observer: a #GtkActionObserver
* @observable: the source of the event
* @action_name: the name of the action
* @state: the new state of the action
*
* This function is called when an action that the observer is
* registered to receive events for changes its state.
* registered to receive events for changes to its state.
*
* This function should only be called by objects with which the
* observer has explicitly registered itself to receive events.
*/
void
g_action_observer_action_state_changed (GActionObserver *observer,
GActionObservable *observable,
const gchar *action_name,
GVariant *state)
gtk_action_observer_action_state_changed (GtkActionObserver *observer,
GtkActionObservable *observable,
const gchar *action_name,
GVariant *state)
{
g_return_if_fail (G_IS_ACTION_OBSERVER (observer));
g_return_if_fail (GTK_IS_ACTION_OBSERVER (observer));
G_ACTION_OBSERVER_GET_IFACE (observer)
GTK_ACTION_OBSERVER_GET_IFACE (observer)
->action_state_changed (observer, observable, action_name, state);
}
/*
* g_action_observer_action_removed:
* @observer: a #GActionObserver
/**
* gtk_action_observer_action_removed:
* @observer: a #GtkActionObserver
* @observable: the source of the event
* @action_name: the name of the action
*
@ -150,12 +148,12 @@ g_action_observer_action_state_changed (GActionObserver *observer,
* observer has explicitly registered itself to receive events.
*/
void
g_action_observer_action_removed (GActionObserver *observer,
GActionObservable *observable,
const gchar *action_name)
gtk_action_observer_action_removed (GtkActionObserver *observer,
GtkActionObservable *observable,
const gchar *action_name)
{
g_return_if_fail (G_IS_ACTION_OBSERVER (observer));
g_return_if_fail (GTK_IS_ACTION_OBSERVER (observer));
G_ACTION_OBSERVER_GET_IFACE (observer)
GTK_ACTION_OBSERVER_GET_IFACE (observer)
->action_removed (observer, observable, action_name);
}

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