Compare commits

...

303 Commits

Author SHA1 Message Date
58ed983b65 Bump version to 3.24.2
Update NEWS.
2017-05-11 15:14:54 +02:00
6f2fc9fe14 docs: Fix typo 2017-05-11 15:14:54 +02:00
185f003363 dateMenu: Fix a runtime warning
GJS now warns about excess parameters, so wrap the queue_relayout()
into an anonymous function instead of using it directly as signal
handler.
2017-05-11 14:46:12 +02:00
6734746707 search: copy result to clipboard if requested
Some search providers such as GNOME Characters want to copy search
results to clipboard.  However, on Wayland, clipboards are only
accessible from applications that have a visible surface on display.

This patch allows a search provider to request the shell to copy a
search result to clipboard when 'clipboardText' is included in the meta
of the result.

https://bugzilla.gnome.org/show_bug.cgi?id=775099
2017-05-11 11:40:27 +02:00
65b9369aaf entry: Fix *-icon-clicked handler
Commit ffe4eaf00d broke the handler by fetching the instance private
from the wrong actor - as we don't use the ::primary-icon-clicked signal,
and the ::secondary-icon-clicked signal still works by accident, nobody
noticed until now ...

https://bugzilla.gnome.org/show_bug.cgi?id=782190
2017-05-05 00:41:34 +02:00
e1e4ce7049 extensionSystem: handle reloading broken extensions
Some extensions out there may fail to reload. When that happens,
we need to catch any exceptions so that we don't leave things in
a broken state that could lead to leaving extensions enabled in
the screen shield.

https://bugzilla.gnome.org/show_bug.cgi?id=781728
2017-04-25 22:03:34 +02:00
812aa10119 Update Arabic translation 2017-04-24 16:41:15 +02:00
b0fa5e5696 extensionPrefs: Avoid a runtime warning
Since 5b3fb024be, the main window is only shown when not launched
with a valid UUID. As GtkDialog isn't meant to be used standalone,
we currently trigger a (harmless but annoying) warning in case
the main window isn't shown; we can avoid the warning by setting
up the preference dialog manually instead of using the GtkDialog
convenience class.

https://bugzilla.gnome.org/show_bug.cgi?id=781545
2017-04-20 19:19:53 +02:00
c7a8c372a1 extensionPrefs: Fix enum member name 2017-04-20 17:37:07 +02:00
73b7d9ace4 WeatherClient: set enabled providers after setting a valid location
So far, the GWeatherInfo was given the enabled weather providers
as a parameter, at construction time. Because of the way in
which libgweather was designed, setting the providers right from
the beginning enabled libgweather to use them internally in order
to update its state. Updating the internal state is only relevant
when there is a valid location set, which is not guaranteed at the
time when the GWeatherInfo object is constructed.

In order to fix this, enable no providers at construction time and
only set valid providers after setting a valid location.

https://bugzilla.gnome.org/show_bug.cgi?id=780404
2017-04-20 17:36:25 +02:00
45c2627d4d Update Serbian translation 2017-04-13 00:10:36 +00:00
635bdea284 Update Italian translation 2017-04-11 06:41:24 +00:00
22131d99ad Bump version to 3.24.1
Update NEWS.
2017-04-11 01:58:50 +02:00
4e22388089 background: Fix file check
The _animationFile property was removed in commit 8a4c862633 ...
2017-04-11 01:39:03 +02:00
c526413119 Update Croatian translation 2017-04-08 15:16:32 +00:00
1336b197d8 Update Greek translation 2017-04-08 15:07:14 +00:00
4b99415215 Updated Danish translation 2017-04-08 16:35:30 +02:00
1ed107a2bf st-texture-cache: Plug some pixbuf refcount leaks on async operations
When extracting the sliced image, the GTask grants data ownership on
g_task_propagate_*, so the pixbuf list must be properly freed. On async
load, we just left a dangling reference when returning on the async
task.

https://bugzilla.gnome.org/show_bug.cgi?id=642652
2017-04-07 14:32:12 +02:00
cad5e06041 panelMenu: consider scale factor when setting max-height
Since the workarea and margins are both in pysical pixels dimensions (we
fetch margins from Clutter, not from the theme), but the CSS expects
logical (scaled) pixels, unless we consider the scale factor when
setting max-height, it won't work on a HiDpi display.

This fixes missing scrollbars when the calendar popup is full on HiDpi
displays.

https://bugzilla.gnome.org/show_bug.cgi?id=753305
2017-04-06 18:32:04 -07:00
65d93eacd3 gvc: Fix some memory leaks 2017-04-06 15:19:36 +02:00
8369dc6b64 portalHelper: Fix portals which require a new window to be loaded
https://bugzilla.gnome.org/show_bug.cgi?id=759044
2017-04-06 12:28:43 +02:00
a0c31478c0 portalHelper: Use the correct enum values
Without this the tests never succeeded because they were comparing
loadEvent to undefined resulting in the icon not changing as it
should.

https://bugzilla.gnome.org/show_bug.cgi?id=780606
2017-04-05 09:27:07 +02:00
647c8df12f popupMenu: Don't handle key events for insensitive source
Generalizing menu toggling via keyboard in commit 1d58ea25ab
fixed keynav in many places, but it turns out that it also adds
unexpected interactions in some cases where the source is not
button-like, as for example the entry context menus provided by
ShellEntry. Commit e33c68a415 fixed one case, however it is still
possible for plain enter/space to unexpectedly trigger the menu
if the entry itself doesn't consume the event, which is the case
when ClutterText:editable is false. However for a general fix, it
makes more sense to consider the source actor's :reactive property
and disable toggling menus via keyboard when they cannot be toggled
by pointer either - expecting non-editable entries to be non-reactive
as well seems like a reasonable assumption, and indeed all our code
follows that pattern.

https://bugzilla.gnome.org/show_bug.cgi?id=758873
2017-04-04 20:58:50 +02:00
6ab045b9ad Update Latvian translation 2017-04-02 14:01:02 +03:00
2ebac8c186 Update Russian translation 2017-03-30 09:53:43 +00:00
06478f242a Update Russian translation 2017-03-29 23:05:18 +00:00
6557ae0a2b portalHelper: Simplify our non-use of cache
Instead of using directories that we'll destroy when done, use the new
"ephemeral" data manager feature, through the JavaScript version of:
webkit_web_context_new_ephemeral()

We also throw an error on startup, in the logs, if WebKitGTK is too old.

https://bugzilla.gnome.org/show_bug.cgi?id=780453
2017-03-28 14:18:25 +02:00
adbec80596 Update Polish translation 2017-03-27 20:40:06 +02:00
2369ef1296 Updated Vietnamese translation
Signed-off-by: Trần Ngọc Quân <vnwildman@gmail.com>
2017-03-27 15:11:44 +07:00
ce0ea0434e Update Polish translation 2017-03-25 21:19:51 +01:00
ede6ec2a28 Updated Lithuanian translation 2017-03-25 13:38:31 +02:00
b4b19b551d Updated Norwegian bokmål translation. 2017-03-25 12:07:57 +01:00
dc295927ed Update Friulian translation 2017-03-23 21:56:40 +00:00
539cbf3593 Update Polish translation 2017-03-23 22:10:55 +01:00
b477d215a8 st: Add missing %NULL check
st_theme_node_get_border_image() may return %NULL, leading to a
segfault in st_border_image_get_file() when glib is compiled with
G_DISABLE_CHECKS.

https://bugzilla.gnome.org/show_bug.cgi?id=780381
2017-03-22 18:51:51 +01:00
5de85c708f calendar-server: Remove unused variables and function
The code that used them was removed in commit 7e0e224e0e.

https://bugzilla.gnome.org/show_bug.cgi?id=780381
2017-03-22 18:51:51 +01:00
ad80cc8950 Update Belarusian translation 2017-03-22 13:22:53 +00:00
bc3a506e68 Update Slovak translation 2017-03-21 21:07:18 +00:00
92d740ba21 Update Galician translation 2017-03-21 20:58:48 +00:00
d65199d2ac Update German translation 2017-03-21 18:35:15 +00:00
257b99ebd1 viewSelector: Set correct arguments on ShowOverviewAction 'activate' signal
It's missing the double argument containing the scale change.
2017-03-21 17:53:36 +00:00
c8be854365 Update Korean translation 2017-03-21 17:12:51 +00:00
436b764952 Update French translation 2017-03-21 16:21:15 +00:00
86063f15ed Update Hungarian translation 2017-03-21 15:09:23 +00:00
716f209537 Updated Ukrainian translation 2017-03-21 16:33:42 +02:00
7bba7fbf37 Update Spanish translation 2017-03-21 11:45:32 +00:00
a102c99c07 Update Finnish translation 2017-03-21 10:49:50 +00:00
5761db5981 Update Italian translation 2017-03-21 07:58:33 +00:00
5d33820bd6 Update Indonesian translation 2017-03-21 07:23:13 +00:00
301acc920d Updated Ukrainian translation 2017-03-21 08:46:20 +02:00
495f9cba72 Update Kazakh translation 2017-03-21 03:59:41 +00:00
726fc1d4f7 Update Brazilian Portuguese translation 2017-03-20 23:55:39 +00:00
dd6452fe2a Update Russian translation 2017-03-20 21:19:59 +00:00
19aa57454b Update Swedish translation 2017-03-20 20:45:02 +00:00
c9555a3537 Update Polish translation 2017-03-20 20:18:02 +01:00
6f473a4f29 network: don't assume the connection path is always non-NULL
It can be NULL according to the libnm-glib documentation.

https://bugzilla.gnome.org/show_bug.cgi?id=780321
2017-03-20 18:43:50 +00:00
f785f4ad02 Updated Czech translation 2017-03-20 19:37:28 +01:00
35d0ba4454 status/a11y: Fix typo
The idle ID being set and being checked didn't quite match up.
2017-03-20 18:16:56 +00:00
c3428f1efa weather: Follow GNOME Weather's location permissions
Our weather integration should follow GNOME Weather as closely as
possible, which means that we should respect its location permission
rather than using our own or none at all (which we can as a "system"
component and as geoclue's authorization agent).

https://bugzilla.gnome.org/show_bug.cgi?id=780252
2017-03-20 19:13:20 +01:00
9cc1e6b85c location: Split out PermissionStore
It doesn't make sense to tie the proxy code for flatpak's permission
store to the location indicator, just because that was the first
component to use it, so split it into a separate module.

https://bugzilla.gnome.org/show_bug.cgi?id=780252
2017-03-20 19:02:08 +01:00
74e1058183 weather: Take global location switch into account
The setting to globally disable location settings altogether isn't
handled by the geoclue service itself, but by the authorization
agent. This means that:

 - it doesn't apply to system components
   (which gnome-shell is now considered[0])
 - it doesn't apply once the geoclue connection
   has been authorized

However users can reasonably expect that we won't use location services
after they disabled them, so handle the setting explicitly.

[0] https://cgit.freedesktop.org/geoclue/commit/?id=a4cef6c0ad08

https://bugzilla.gnome.org/show_bug.cgi?id=780252
2017-03-20 19:02:08 +01:00
7c9f76944b weather: Disentangle _useAutoLocation from Weather setting
We currently use automatic location for weather forecasts if the
corresponding Weather setting is set, however we should take other
factors into account as well:

 - whether location services are enabled at all
 - whether Weather has been authorized to use them

In preparation of these changes, track the setting's value in a
separate property and make _useAutoLocation a getter, so we can
extend it with additional conditions easily.

https://bugzilla.gnome.org/show_bug.cgi?id=780252
2017-03-20 19:02:08 +01:00
d393ca4f09 weather: Track whether a location was set
Setting GWeatherInfo:location to null helpfully doesn't mean
"no location", but "NYC". This obviously isn't what we want
to show users, so track the location validity separately and
consider it when updating the label shown to users.

https://bugzilla.gnome.org/show_bug.cgi?id=780252
2017-03-20 19:02:08 +01:00
a786f0bcd2 screenShield: Do not take an inhibitor when disabled by lockdown
Just as with the normal lock screen settings, we shouldn't request
a logind inhibitor when locking is disabled via lockdown settings.

https://bugzilla.gnome.org/show_bug.cgi?id=780212
2017-03-20 19:02:08 +01:00
199bc85bce screenShield: Do not lock the screen when locked down
When using the 'disable-lock-screen' setting to lock down the screen
lock, the expectation is that users cannot lock the screen. However
as it turns out, all the setting currently does is hiding the lock
button in the system menu and making the lock settings in the privacy
panel inactive. That means that if the 'lock-screen-enabled' setting
isn't disabled and locked down as well, we will just continue to
lock the screen on inactivity - not to mention the keyboard shortcut
that isn't subject to that setting anyway.

Instead of expecting administrators to hunt down every possible way
of locking the screen and disabling it individually, we can easily
handle all cases by refusing to lock the screen when disabled by the
lockdown settings.

https://bugzilla.gnome.org/show_bug.cgi?id=780212
2017-03-20 19:02:08 +01:00
d15b46f5cb workspace: Hide preview overlays from picks
Dragging and dropping app icons is expected to work anywhere over a
workspace, however overlaid elements are added to a separate hierarchy
and can thus block valid drop targets. This wasn't much of an issue
while we had just the window title, but since the addition of the
focus border, drops on window previews stopped working entirely.

Fix this by hiding all non-reactive overlay elements from picks.

https://bugzilla.gnome.org/show_bug.cgi?id=737166
2017-03-20 19:02:07 +01:00
c0861b1227 gdm: Handle absence of Fprint.Manager service
We rely on the service to detect whether a fingerprint reader is
present. It is fine to not support fingerprint authentication
when the service is missing, but currently we don't handle this
case at all and end up with a non-functional login screen.

https://bugzilla.gnome.org/show_bug.cgi?id=780063
2017-03-20 19:02:07 +01:00
f97a3522e5 network: Close Wifi selection dialog when appropriate
Currently when the wifi selection dialog is open when the screen lock is
activated, the dialog remains visible above the shield. This is clearly
broken, so close the dialog automatically on session mode changes if the
mode doesn't allow settings (as changing the access point is arguably a
user setting).

https://bugzilla.gnome.org/show_bug.cgi?id=780054
2017-03-20 19:02:07 +01:00
577e261d1a Bump version to 3.24.0
Update NEWS.
2017-03-20 18:20:00 +01:00
33fcff8a1a Updated Ukrainian translation 2017-03-19 23:41:10 +02:00
cd30572b70 Update Japanese translation 2017-03-19 21:01:19 +00:00
bc711b6dec Update Turkish translation 2017-03-18 12:25:38 +00:00
01f5065b87 Update Latvian translation 2017-03-18 10:33:23 +02:00
9c2bf17ad7 Update French translation 2017-03-16 20:21:56 +00:00
5385b36a81 Updated Serbian translation 2017-03-15 17:59:30 +01:00
72ed9da1fc Updated Serbian translation 2017-03-15 17:54:18 +01:00
d79924bdd1 Update Tajik translation 2017-03-14 19:21:58 +00:00
3b7a4b08e2 Bump version to 3.23.92
Update NEWS.
2017-03-14 17:56:07 +01:00
09af4433b0 windowMenu: Remove left-over variable 2017-03-14 17:47:04 +01:00
50df3084f7 dateMenu: Add vertical separator between message list and calendar
With the background boxes gone from messages, we need some visual
indication for how elements are aligned.

https://bugzilla.gnome.org/show_bug.cgi?id=779820
2017-03-14 17:46:58 +01:00
e90734913d mpris: Add hover effect
It is not immediately obvious that media controls are interactive,
so add a small hover effect.

https://bugzilla.gnome.org/show_bug.cgi?id=779820
2017-03-14 15:22:00 +01:00
af18a0cf40 calendar: Fake baseline alignment for notification timestamp
We don't have GTK's baseline alignment, so all we can do is add some
padding and hope it works out fine for most fonts and sizes ...

https://bugzilla.gnome.org/show_bug.cgi?id=779820
2017-03-14 15:21:56 +01:00
3d399796a6 dateMenu: Add some spacing between displays
Now that we have more than just the "World Clocks" display, it turns
out we need some spacing between sections.

https://bugzilla.gnome.org/show_bug.cgi?id=779820
2017-03-14 15:21:34 +01:00
60a2794c8b messageTray: Ignore showBanners policy for critical notifications
The critical hint is meant to be used for notifications that must not
be missed - running out of battery being the prime example - so it
makes sense to ignore the policy in that case and make sure to always
show them to the user. This is consistent with blocking normal
notifications while showing a fullscreen window, but letting critical
ones through.

https://bugzilla.gnome.org/show_bug.cgi?id=779974
2017-03-14 00:23:37 +01:00
e039871298 padOsd: Allow to switch between pads in the same group
Whenever there's more than one pad in the same group (eg. Wacom ExpressKey
Remotes), show a popdown menu to allow configuring those extra pads.
Devices are hot-pluggable, so the popdown menu will update its state
whenever pads are added/removed.

Also, allow to quickly change between pads by switching to its OSD by
just interacting with them. Always given they are in the same group.

https://bugzilla.gnome.org/show_bug.cgi?id=779986
2017-03-13 21:23:04 +01:00
e057333bf3 padOsd: Add PadChooser class
This is a popdown button that allows choosing between pads in
the same group.

https://bugzilla.gnome.org/show_bug.cgi?id=779986
2017-03-13 21:23:04 +01:00
e0c0d9223e padOsd: shuffle title labels hierarchy
Add some boxes in between, so we can add the pad chooser button
and the overall result is still centered.

https://bugzilla.gnome.org/show_bug.cgi?id=779986
2017-03-13 21:22:43 +01:00
ada21c975f padOsd: peek pads attached to the same tablet
https://bugzilla.gnome.org/show_bug.cgi?id=779986
2017-03-13 16:34:27 +01:00
b4df747464 telepathyClient: Gracefully handle missing telepathy deps
Telepathy's role has been diminishing continuously over the last
couple of years, so while chat integration is a nice feature for
those who use it, it is hard to justify keeping it as a hard
dependency. To address this, split out the component from the
client so we can handle missing typelibs gracefully by not
providing any chat integration.

https://bugzilla.gnome.org/show_bug.cgi?id=779878
2017-03-13 16:23:08 +01:00
9a38011e1e lookingGlass: Don't include telepathy import by default
It's hardly a common include nowadays, and removing it keeps all
telepathy usage contained in the telepathyClient component.

https://bugzilla.gnome.org/show_bug.cgi?id=779878
2017-03-13 16:23:08 +01:00
e0f1fc2694 Updated Serbian translation 2017-03-13 14:07:51 +01:00
da5390340e Update Spanish translation 2017-03-13 07:51:38 +00:00
3a6b41495a windowManager: Add bottom edge drag gesture to show OSK
Adding a way to manually activate the OSK, in cases where it does not pop up
automatically or has been closed by the user.

https://bugzilla.gnome.org/show_bug.cgi?id=757712
2017-03-12 17:38:17 +01:00
ce5875f365 weather: Handle GeoClue not responding
If GeoClue is not responding for some reason, the callback of
Geoclue.Simple.new would not get called, meaning that _gclueFailed
remains false. This is preventing the fallback to the most recently
used location in gnome-weather, because it requires _gclueFailed to be
true (or auto-location to be disabled). So neither code path sets a
location and the libgweather default (New York City) is being used
instead.

https://bugzilla.gnome.org/show_bug.cgi?id=779898
2017-03-11 20:53:11 +01:00
4373d390dc Update Galician translation 2017-03-11 12:23:34 +00:00
9ed512e5c5 Update Galician translation 2017-03-11 01:58:36 +00:00
c5856196a7 updated Punjabi Translation 2017-03-10 18:59:33 -06:00
afc3a8a7e7 Fix build
An accidentally typed character in a translation broke it.

http://build.gnome.org/continuous/buildmaster/builds/2017/03/11/0/build/log-gnome-shell.txt

gl.po:632: 'msgstr' is not a valid JavaScript format string, unlike
'msgid'. Reason: In the directive number 2, the character '$' is not a
valid conversion specifier.
2017-03-11 00:15:19 +00:00
4714c73f0f Updated Galician translations 2017-03-11 01:02:59 +01:00
742155c384 messageTray: Use correct monitor for fullscreen logic
For most notifications, banners are suppressed while the monitor
that is used to display banners is in fullscreen. With the old
message tray at the bottom, this used to be the bottom-most monitor,
but nowadays it's always the primary one, so update the corresponding
code to use the correct monitor.

https://bugzilla.gnome.org/show_bug.cgi?id=779819
2017-03-10 17:21:54 +01:00
2d814bfc5e main: Remove telepathy-specific log handling
The built-in telepathy integration is far less prominent than it
used to be, and doesn't really justify a link time dependency to
send debug message over D-Bus.

https://bugzilla.gnome.org/show_bug.cgi?id=771721
2017-03-10 17:10:52 +01:00
8f8e512b37 main: Use GBusNameOwnerFlags to specify flags
We are still using DBUS_NAME_FLAG_REPLACE_EXISTING from dbus-glib
in some places (whose headers are drawn in via telepathy-glib).
As both GIO and dbus-glib use the values that will end up being
sent on the bus, the define and enum value are interchangeable,
but it's clearly better to consistently use the library that is
explicitly included.

https://bugzilla.gnome.org/show_bug.cgi?id=771721
2017-03-10 17:10:52 +01:00
3c828c8387 shell: Remove TpClient
With the telepathy component now being implemented purely in JS, we
can drop the C helper class.

https://bugzilla.gnome.org/show_bug.cgi?id=771721
2017-03-10 17:10:52 +01:00
7c96b39bef telepathyClient: Implement Tp.BaseClient directly
The telepathy integration was written at a time where gjs didn't
allow to inherit from GObject classes, which is why we needed a
C helper class. This hasn't been the case for a while now, so cut
out the middle man and implement Tp.BaseClient directly.

https://bugzilla.gnome.org/show_bug.cgi?id=771721
2017-03-10 17:02:18 +01:00
64dbc8aa7f Update Italian translation 2017-03-09 22:28:51 +00:00
5649b9c64a Update Russian translation 2017-03-09 22:11:26 +00:00
3d0aab3b66 Updated Czech translation 2017-03-09 19:52:54 +01:00
ce419da6ec Update Indonesian translation 2017-03-09 03:34:23 +00:00
63b49c65ab Update Slovak translation 2017-03-08 20:28:07 +00:00
ff5bd0b925 Updated Danish translation 2017-03-07 21:29:22 +01:00
0892220f63 Update Scottish Gaelic translation
(cherry picked from commit 123e8c45b0)
2017-03-07 12:05:06 +00:00
1c95c9e3ff Update Friulian translation 2017-03-07 07:02:13 +00:00
4b80cbe1cd xdnd: Remove XDnD handling code and receive DnD signals from mutter
Move the XDnD handling code to mutter, and receive DnD handling signals from
mutter directly.

https://bugzilla.gnome.org/show_bug.cgi?id=765003
2017-03-07 08:29:51 +08:00
46f3712421 xdnd: Rename XDnD handling signals to more inclusive ones
Rename the signals which have been used to handle XDnd events to more inclusive
ones. So that these signals can be used to handle the DnD events in Wayland.

https://bugzilla.gnome.org/show_bug.cgi?id=765003
2017-03-07 08:29:51 +08:00
18aa4ff30c Update Swedish translation 2017-03-05 20:54:35 +00:00
8a75143a6e Update German translation 2017-03-05 17:21:23 +00:00
384a6e8684 Update Catalan translation 2017-03-05 10:12:39 +01:00
a0008f7471 Updated Serbian translation 2017-03-05 06:01:52 +01:00
b53f95a9a0 Updated Lithuanian translation 2017-03-04 17:53:41 +02:00
1af88e52dd Update Catalan translation 2017-03-04 08:27:48 +01:00
535028c9a7 Update Korean translation 2017-03-03 16:07:46 +00:00
df816368a5 Update Basque language 2017-03-03 12:36:24 +01:00
f34202c3c8 Update Icelandic translation
(cherry picked from commit 7aa9e79b66)
2017-03-02 17:51:59 +00:00
28c61754a1 Update Belarusian translation 2017-03-02 17:14:40 +00:00
6e46166df4 Updated Danish translation 2017-03-02 13:25:20 +01:00
15feaa1074 Update Hungarian translation 2017-03-02 07:51:02 +00:00
d7c532daee Remove obsolete strings causing validation errors in Hebrew translation 2017-03-02 07:27:12 +01:00
427ec6834d Update Polish translation 2017-03-02 02:08:42 +01:00
e594b30ead Update Chinese (Taiwan) translation 2017-03-02 00:40:07 +00:00
f43a8a75e4 Update Finnish translation 2017-03-01 19:57:03 +00:00
645aa01efd telepathyClient: Use a single update for text and timestamp
Commit c6f22826cf added a call to update() to refresh the notification
time for sent and received messages. However as it omits the bannerMarkup
parameter, escaped text like '&apos;' now makes it through verbatim.
Rather than adding the parameter, we can just refresh the timestamp in
the existing update() call to fix the issue - it means the notification
timestamp is only refreshed for received messages, but that reflects
the text shown in the notification, which isn't updated for sent
messages either.

https://bugzilla.gnome.org/show_bug.cgi?id=779435
2017-03-01 20:46:58 +01:00
252dce1ec2 fix typos
The shell was crashing for me - these fixes from Debarshi seem to
fix it.
2017-03-01 16:24:35 +00:00
da0066eb84 Update Brazilian Portuguese translation 2017-03-01 15:37:47 +00:00
adc811ff8f Bump version to 3.23.91
Update NEWS.
2017-03-01 15:29:03 +01:00
5117ccdeef Update Kazakh translation 2017-03-01 11:05:13 +00:00
19816523c7 mpris: Make forward/backward insensitive when unavailable
Media notifications currently always show the forward and backward
buttons as clickable, regardless of whether the corresponding action
is available or not. Media players usually address this by rendering
controls insensitive in this case, so do the same here.

https://bugzilla.gnome.org/show_bug.cgi?id=773884
2017-03-01 10:55:56 +01:00
846e3f8243 calendar: Add calendar icon to events
Without the boxy background, event messages look a bit plain and
unaligned with other messages. Adding an icon addresses this,
however as repeating the same icon over and over again in case of
many events would be rather noisy, only show it for the top event
as in the mockups.

https://bugzilla.gnome.org/show_bug.cgi?id=775763
2017-03-01 10:55:46 +01:00
d3c050b88d Refine notification style
Update the notification style according to the latest mockups:
 - make notification icons smaller and prefer symbolic variants
 - remove background box when not hovered/focused
 - increase spacing between elements
 - use normal text sizes

https://bugzilla.gnome.org/show_bug.cgi?id=775763
2017-03-01 10:55:42 +01:00
f3d1c78c7d calendar: Use relative times for notification timestamps
For notifications in the message list, it is usually less relevant
when exactly it occurred, but how long ago. So rather than showing
the exact time and expecting the user to figuring out the timespan
themselves, change the format to something human readable.

https://bugzilla.gnome.org/show_bug.cgi?id=775763
2017-03-01 10:55:21 +01:00
c4f2bb5fe0 messageList: Keep secondary actor when showing close button
Currently the secondary actor (if set) and the close button are
exclusive, that is the latter replaces the former on hover. As
the swapping feels rather busy and there's no real reason both
cannot be shown at the same time, keep the secondary actor always
visible.
A welcome side effect is that it no longer needs to be placed at
the end, so we can move the notification timestamp right next to
the corresponding title.

https://bugzilla.gnome.org/show_bug.cgi?id=775763
2017-03-01 10:55:21 +01:00
fec511c786 calendar: Only show section title for other days
The section titles usually don't provide a lot of value - messages
themselves are usually pretty unambiguous about their type, and
having a hidden shortcut to some settings panel or application isn't
essential either - except when showing the selected date when browsing
other days, as it adds context to the listed events. Based on that,
remove the section title as a general MessageListSection feature and
move it into the EventsSection, where we only show it when it is useful.

https://bugzilla.gnome.org/show_bug.cgi?id=775763
2017-03-01 10:55:09 +01:00
8a6157c7c1 messageList: Remove section clear button
With the new "Clear All" button in the message list as a replacement,
we can remove the individual clear buttons from the sections.

https://bugzilla.gnome.org/show_bug.cgi?id=775763
2017-03-01 10:54:32 +01:00
d3bb7903e2 calendar: Add "Clear All" button to message list
We will eventually remove section titles from the message list to
reduce visual noise and give the actual information provided by
the messages more space. So in order to not lose the ability to
mass-dismiss messages, the latest mockups spot a "Clear All" button
at the bottom - implement that.

https://bugzilla.gnome.org/show_bug.cgi?id=775763
2017-03-01 10:53:52 +01:00
239b67eff6 messageList: Make canClear public and notify on changes
The latest mockups contain a button to clear all sections at once.
As some elements cannot be cleared, we need to provide that information
to avoid offering an action that has no effect.

https://bugzilla.gnome.org/show_bug.cgi?id=775763
2017-03-01 10:52:43 +01:00
0e0caee6ba weather: Skip loading indication when updating frequently
Weather conditions - at least as far as online services are
concerned - don't usually change in a couple of minutes.
So when updating shortly after a previous update, assume
the current conditions are still valid and trigger an
update without showing a loading indication. This should
help a bit with not getting stuck permanently in loading
state when on a shitty network.

https://bugzilla.gnome.org/show_bug.cgi?id=754031
2017-03-01 10:52:43 +01:00
62606c68b9 dateMenu: Add Weather section
Similar to the Clocks integration we've had in the date+time drop-down for
a while, the designs have called for a similar section that integrates
GNOME weather as well. Use the WeatherClient added in the previous commit
to implement that section and add it to the popover.

https://bugzilla.gnome.org/show_bug.cgi?id=754031
2017-03-01 10:52:13 +01:00
da831e894c weather: Add WeatherClient
In preparation of integrating GNOME Weather, add a helper class that
retrieves weather information according to Weather's configuration
if the application is installed.

https://bugzilla.gnome.org/show_bug.cgi?id=754031
2017-02-28 16:12:46 +01:00
4b166dcc79 dateMenu: Do a better job at size freezing while browsing dates
In order to avoid distracting popup size changes while browsing
other dates, we freeze the size to the last size request. However
in case of more complex size negotiations - wrapping or ellipsizing
labels, scrollable elements etc. - there's a chance of stray calls
to get_preferred_width/height() that are not used for the actual
allocation. If such a call happens to be the last size request
before the layout is frozen, the saved size will be wrong. To fix
this, save the allocated size rather than the requested one.

https://bugzilla.gnome.org/show_bug.cgi?id=754031
2017-02-27 21:23:48 +01:00
796fdca5c5 dateMenu: Enforce calendar column width
We want the width of the calendar column to be determined by the
calendar, other elements should adjust their allocation accordingly.
However neither ellipsization nor wrapping will kick in unless the
parent's width is restricted, so use a small custom layout manager
that enforces the desired behavior.

https://bugzilla.gnome.org/show_bug.cgi?id=754031
2017-02-27 21:23:47 +01:00
c6f22826cf telepathyClient: Update notification time from message
As the telepathy integration picks up existing channels on startup,
ChatNotifications are another case where the real time the message
was received may be before the time it is picked up by the shell.
While this is less of an annoyance than restored GNotifications, as
it generally only affects restarts from the run dialog, it's an
easy fix now ...

https://bugzilla.gnome.org/show_bug.cgi?id=775799
2017-02-27 20:04:09 +01:00
4e491b6f75 notificationDaemon: Include timestamp in serialized notifications
GNotifications are persistent until dismissed or withdrawn, including
across restarts. As we show the time a notification was received in the
calendar, we need to include that information when serializing the
notification in order to be correct.

https://bugzilla.gnome.org/show_bug.cgi?id=775799
2017-02-27 20:04:09 +01:00
0569bb18f5 messageTray: Add optional datetime parameter to notifications
Since the last notification redesign, we've been showing the time a
notification was received in the calendar drop-down. However as the
time is in fact added by the NotificationSection, it is actually the
time a notification was added to the list. Usually that difference is
not significant, except when previously received notifications are
restored on startup.
In order to be able to address those cases, we need a time that is
associated with the notification itself, so add a datetime property
that defaults to the current time, but may be set from an optional
parameter as well.

https://bugzilla.gnome.org/show_bug.cgi?id=775799
2017-02-27 20:04:08 +01:00
0353ebde5d dateMenu: Use AppSettingsMonitor for world clocks
When gnome-clocks is installed, there is currently a race between the
GSettings schema being added to the database and the world clocks
session trying to use it. The prize if we win that race is an abort
in GIO, so use the newly added AppSettingsMonitor skip the race
altogether.

https://bugzilla.gnome.org/show_bug.cgi?id=766410
2017-02-27 20:02:16 +01:00
b5130c5943 util: Add AppSettingsMonitor
When integrating with optional components like Clocks, it is not safe
to access their GSettings right after the application became visible
to the AppSystem:
Installation is usually not atomic, so the .desktop file may appear
before the settings schema, in which case Gio will abort due to an
"invalid" schema ID.
To address this, add a small helper class that wraps the settings
access in a safe way.

https://bugzilla.gnome.org/show_bug.cgi?id=766410
2017-02-27 20:02:16 +01:00
d54db8ffb3 Update Chinese (Taiwan) translation 2017-02-27 00:09:50 +00:00
0ff5fc8dbb viewSelector: Fix another case of mixing GJS and GObject signals
This is the same issue fixed in commit e08f2a4a04 for several other
classes, but this one somehow slipped through ...
2017-02-26 15:01:24 +01:00
32ec9959ef Update Hungarian translation 2017-02-26 11:57:03 +00:00
838721fc31 Updated Serbian translation 2017-02-26 10:05:55 +01:00
63e9c98248 Updated Serbian translation 2017-02-26 08:50:16 +01:00
6df30cbb64 Updated Galician translations 2017-02-26 02:24:50 +01:00
c102a89962 Update Brazilian Portuguese translation 2017-02-25 11:50:10 +00:00
ff5e39ab79 Update Friulian translation 2017-02-23 23:40:42 +00:00
607b2efcce network: Don't start portal helper under GDM
https://bugzilla.gnome.org/show_bug.cgi?id=769546
2017-02-22 16:21:40 +01:00
27d010110a Update Italian translation 2017-02-21 18:10:58 +00:00
e13602b896 Update Indonesian translation 2017-02-21 14:51:26 +00:00
6777670f0d Updated Ukrainian translation 2017-02-20 13:49:49 +02:00
b05739fa7e Update Polish translation 2017-02-19 21:48:47 +01:00
38854fb06a Updated Norwegian bokmål translation. 2017-02-19 16:34:42 +01:00
b091cfea80 Update Finnish translation 2017-02-18 18:41:55 +00:00
a8955ffe05 Updated Lithuanian translation 2017-02-18 17:35:15 +02:00
475fd72ae1 Update Slovak translation 2017-02-18 08:54:07 +00:00
31675d1812 Update Spanish translation 2017-02-17 10:46:15 +00:00
cbb0c1c091 Update Basque language 2017-02-16 22:00:08 +01:00
c1234f7793 Update Basque language 2017-02-16 16:58:12 +01:00
1e6c44cb6b autogen: Drop usage of gnome-common 2017-02-16 16:45:44 +01:00
2202b9330f Updated Danish translation 2017-02-16 14:24:52 +01:00
0b332fc019 Update Catalan translation 2017-02-16 06:34:51 +01:00
4f4163eb05 Update Kazakh translation 2017-02-16 04:06:43 +00:00
649d360289 Use Unicode in translatable strings
See https://developer.gnome.org/hig/stable/typography.html

https://bugzilla.gnome.org/show_bug.cgi?id=772210
2017-02-16 02:07:14 +01:00
9bcdd9c274 Update POTFILES.in 2017-02-16 02:02:40 +01:00
fbc60199bc Bump version to 3.23.90
Update NEWS.
2017-02-16 01:27:39 +01:00
785c813771 status: Add nightLight indicator
The display configuration now exposes a setting to automatically
shift the display color at nighttime. As there are cases where
disabling the filtering temporarily is useful, it makes sense to
expose the feature in the system menu for quick access.

https://bugzilla.gnome.org/show_bug.cgi?id=741224
2017-02-15 23:20:14 +01:00
75f8279a19 extensionPrefs: Tweak UI
Update according to the latest mockups:
 - don't use a border around the list as specified
   by the latest HIG version
 - use more generous spacing between controls
 - allow extension descriptions to take up two lines
 - drop GNOME branding from the window title
 - make the app name consistent with the window title

https://bugzilla.gnome.org/show_bug.cgi?id=778672
2017-02-15 23:20:14 +01:00
5d07832e96 extensionPrefs: Expose kill-switch
While the extension prefs tool is not meant as the primary way for
users to configure extensions - that will be Tweak Tool - it still
doesn't hurt to expose the extension kill switch to easily turn
extensions back on after a session crash.

https://bugzilla.gnome.org/show_bug.cgi?id=778664
2017-02-15 23:20:14 +01:00
7395aaf9b4 extensionSystem: Add kill-switch setting to disable user extensions
When gnome-shell fails to start on login, gnome-session tries to
re-launch it again with all extensions disabled. This is currently
implemented by clearing the list of enabled extensions, which means
the user needs to re-enable their extensions manually again.
To make this process less annoying, add a single 'kill-switch' setting
gnome-session can use without interfering with the user setting.

https://bugzilla.gnome.org/show_bug.cgi?id=778664
2017-02-15 23:20:14 +01:00
2c070d38fb system: Switch between alternatives on long-press
On systems that support both shutdown and suspend, the latter operation
is currently only accessible via pressing the Alt key. As using the
keyboard may be inconvenient or simply not possible (e.g. on touch),
allow switching between alternatives via long-press as well.

https://bugzilla.gnome.org/show_bug.cgi?id=721173
2017-02-15 23:20:14 +01:00
2c5bc4a1a9 appFavorites: Only use renamed ID if it can be resolved
We currently assume that if a .desktop file has been renamed (that
is, it is in our rename list), the updated ID will be used. That
assumption was mostly sound when the list contained only GNOME apps
following the same release cycle as gnome-shell, but as applications
with less ties to the GNOME schedule adopt the reverse DNS notation,
it becomes more likely for apps to appear in the list before actually
being updated on the system. Handle this case by only renaming IDs
for which the replacement can be resolved to an existing application.

https://bugzilla.gnome.org/show_bug.cgi?id=745626
2017-02-15 23:20:14 +01:00
fa82af251f location: Initialize permissions
The permissions hash is initialized after consulting the permission
store, however the lookup is skipped for requests that cannot be
resolved to an application, resulting in an error when accessing
the uninitialized hash for saving. Just make sure that the property
is always initialized to avoid that error.

https://bugzilla.gnome.org/show_bug.cgi?id=778661
2017-02-15 23:20:14 +01:00
e08f2a4a04 Don't mix GJS and GObject signal systems
GJS implements a basic signal system that allows monkey-patching
JS objects with signal methods resembling the GObject ones. However
it's clearly not a good idea to replace the actual GObject methods,
so use the proper GObject facilities when inheriting from GObject.

https://bugzilla.gnome.org/show_bug.cgi?id=778660
2017-02-15 23:20:14 +01:00
30e17036e8 network: Ensure the connection list is sorted after rename
Items were inserted correctly but the synchronisation was lost if the
name of a connection was changed. Simply making sure the position is
correct after a connection is updated fixes the issue.

Reported-by: Oliver Haessler <ohaessle@redhat.com>

https://bugzilla.gnome.org/show_bug.cgi?id=778686
2017-02-15 22:49:07 +01:00
c75785efff ui: Allow moving menu items to a certain position
This function is a helper to simplify keeping menu items ordered when
their order is updated on the fly (e.g. network connections being
renamed).

https://bugzilla.gnome.org/show_bug.cgi?id=778686
2017-02-15 22:49:04 +01:00
3bf89055e3 extensionDownloader: return tuple of string on success
Fixes: https://bugzilla.gnome.org/show_bug.cgi?id=777544
2017-02-15 23:15:20 +04:00
a76869216a portalHelper: Don't fail to load because of TLS errors
Accept self-signed and expired certificates as if we errored out, we
couldn't access the network at all. Consider this insecure though.

https://bugzilla.gnome.org/show_bug.cgi?id=778253
2017-02-15 14:30:07 +01:00
a9fd8bfa5e Updated Ukrainian translation 2017-02-15 15:13:51 +02:00
02a7b0dcfd tests: require given version of Gtk 2017-02-15 12:04:53 +00:00
dd8c06f2c5 tests: load required version of Clutter/Gtk early 2017-02-15 12:04:53 +00:00
c63b7f0c3f Updated Spanish translation 2017-02-14 20:33:27 +01:00
a46ea3f8a0 Use the versioned libmutter*.so versions
Mutter now provides versioned libraries and pkg-config files, meaning
an application using libmutter and friends need to depend on a specific
version of the API.

https://bugzilla.gnome.org/show_bug.cgi?id=777317
2017-02-14 11:23:09 +08:00
93071d9167 loginDialog: don't allow type ahead at the login screen
It's weird if after you select a username from the user list, there's
a password already filled in.

This commit disables at that feature for the login screen
(but keeps it in tact for the unlock screen)

https://bugzilla.gnome.org/show_bug.cgi?id=766139
2017-02-14 03:05:33 +01:00
2b2e9d4098 Updated Czech translation 2017-02-13 23:26:32 +01:00
0429aad8bf Updated Norwegian bokmål translation. 2017-02-13 20:43:07 +01:00
2e74920a64 Update Indonesian translation 2017-02-13 15:05:26 +00:00
b5bf82b5db portalHelper: Fix signal arguments
How did this work in tests?!

https://bugzilla.gnome.org/show_bug.cgi?id=778552
2017-02-13 11:54:35 +01:00
98cdd44543 portalHelper: Fix runtime warning
When there is no URI, then the title should be empty, not null:
Gjs-WARNING **: JS ERROR: Error: Argument 'str' (type utf8) may not be null

https://bugzilla.gnome.org/show_bug.cgi?id=778552
2017-02-13 11:54:35 +01:00
304b68eff9 portalHelper: Add security icon to titlebar
This adds a security icon (either secure or insecure) to the portal
helper's title bar. As soon as a part or all of the page and its content
is served insecurely, the icon shown will be a broken padlock.

https://bugzilla.gnome.org/show_bug.cgi?id=749197
2017-02-13 10:26:56 +01:00
18074951b9 Updated Czech translation 2017-02-11 15:14:44 +01:00
0008ef70e1 windowManager: Use g-s-d wacom dbus helpers to update pad leds/oleds
This keeps feedback on the device itself in sync with the overall pad
state, a feature we had previously through g-s-d.

https://bugzilla.gnome.org/show_bug.cgi?id=776543
2017-02-10 23:55:04 +01:00
c3cdbd0dac windowManager: Handle MetaDisplay::show-osd signal
Propagate as-is to the OsdWindowManager.

https://bugzilla.gnome.org/show_bug.cgi?id=771098
2017-02-10 23:55:04 +01:00
aefd61c3db js: Avoid double declarations with let
The following code is a syntax error in ES6:

    let a = 'something';
    let a = 'other thing';

Previously GJS would silently accept this code, but in the next release the
SpiderMonkey JS engine will be more ES6-compliant.

https://bugzilla.gnome.org/show_bug.cgi?id=778425
2017-02-10 13:35:50 -08:00
f7752ac699 ibusManager: Use const correctly
Per ES6, a variable declared const should only be valid inside its lexical
scope. Previously, GJS would accept this code, but that will change in the
SpiderMonkey JS engine in the next release of GJS.

https://bugzilla.gnome.org/show_bug.cgi?id=778425
2017-02-10 13:19:08 -08:00
d017e6749c main: Destroy GjsContext before exit
Here are a few places where I missed it before: the GjsContext must be
unrefed before exiting, or it will crash on exit.

https://bugzilla.gnome.org/show_bug.cgi?id=778425
2017-02-10 13:19:01 -08:00
ddfdfaed78 Use /proc/self/cmdline on Solaris as well in shell_global_reexec_self()
Solaris 11.3.5 and later have a Linux-compatible implementation of
/proc/self/cmdline, so the code to use it can be enabled in gnome-shell
on Solaris - if used on an older OS, it simply fails to open the file
and returns without doing anything, just as the code did before enabling
this.

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

Signed-off-by: Alan Coopersmith <alan.coopersmith@oracle.com>
2017-02-10 11:22:30 +01:00
a870a4d6de widget: Only include visible actors in focus chain
It isn't useful to move the keyboard focus to a hidden actor, so
only include visible actors in the focus chain - this is in fact
the documented behavior of st_widget_get_focus_chain(), so having
the default implementation return all children has always been
unexpected.

https://bugzilla.gnome.org/show_bug.cgi?id=778158
2017-02-08 14:50:36 +01:00
e6e786a19c st-theme-node: Fix lookup of time values
We have a time when the content type is seconds *or* milliseconds,
not seconds *and* milliseconds. Whoops ...

https://bugzilla.gnome.org/show_bug.cgi?id=778145
2017-02-06 14:30:18 +01:00
01975b61f5 AppFavorites: order alphabetically by key 2017-02-06 09:40:43 +02:00
3c61bef92d Update zh_CN translation 2017-02-05 17:58:50 +08:00
050f2090fb Update Finnish translation 2017-02-04 18:30:23 +00:00
7746f1a5c4 Make all our window clones use the MetaWindowActor as source
Using a MetaWindowActor's shaped texture as the source for window
clones means that if there are further MetaSurfaceActor children
(e.g. a wayland client using sub-surfaces) they don't get cloned.

This obviously wasn't an issue until wayland clients introduced the
possibility of having multiple MetaSurfaceActors under a
MetaWindowActor but there's no fundamental reason we can't clone the
toplevel actor.

WorkspaceThumbnail.WindowClone is the one class that was already using
the MetaWindowActor instead of the texture although it seems to have
been an unintended change in commit
8b99617513.

https://bugzilla.gnome.org/show_bug.cgi?id=756715
2017-02-02 14:28:00 +01:00
97a1cdbe7a Update Belarusian translation 2017-02-02 12:41:21 +00:00
b1dcea7cf1 background: Disconnect from 'prepare-for-sleep' signal
This signal connection was keeping Background instances from being
garbage collected.

https://bugzilla.gnome.org/show_bug.cgi?id=777934
2017-01-31 13:53:26 +01:00
9f6f48025d background: Remove a couple of unused variables
Nothing uses these.

https://bugzilla.gnome.org/show_bug.cgi?id=777934
2017-01-31 13:48:11 +01:00
5e66ac2674 Update Polish translation 2017-01-30 03:02:45 +01:00
93c66b3537 Fix a translator comment
They need to be exactly one line above a string to show up in .po files.
2017-01-28 02:01:14 +01:00
e0d7d28c20 windowManager: Avoid fullscreen animation if the window has no texture
There is hardly anything to animate, so just avoid the animation in this
case.

https://bugzilla.gnome.org/show_bug.cgi?id=777784
2017-01-26 17:51:39 +01:00
a82c564a73 windowManager: Avoid reentrancy on the ::size-changed handler
We have no guarantees on the number of ::size-changed signals that we may
receive, so the _sizeChangedWindow handler may run multiple times, which
leads to multiple calls to meta_plugin_size_change_completed(). So double
check the actor is not already being animated in the _sizeChangedWindow
handler to avoid reentrancy.

https://bugzilla.gnome.org/show_bug.cgi?id=777784
2017-01-26 17:51:39 +01:00
6a40e72329 Update Kazakh translation 2017-01-25 09:02:11 +00:00
3737a9950c Update Slovak translation 2017-01-24 19:35:56 +00:00
7784bc0905 build: Remove C++ check
As it's not used any more since commit
ed99bef458.

https://bugzilla.gnome.org/show_bug.cgi?id=762444
2017-01-24 14:17:36 +01:00
49607e1313 portalHelper: Don't change the main window title
The title of the window should not be in control of a potentially
hostile hotspot provider, so only set the subtitle to be that of the
page, the main title will stay the same.

The subtitle will also be set to a URI, so that the hotspot cannot be
used to control the title shown in our UI.

Helps https://bugzilla.gnome.org/show_bug.cgi?id=749197
2017-01-24 13:36:09 +01:00
a81f18592a portalHelper: Set a minimum window size
Even though the window is maximised when created, the window is still
resizable. This avoids making the window smaller than usable. If the
screen is smaller than the minimum window size, the maximise should make
it fullscreen and non-resizable.

https://bugzilla.gnome.org/show_bug.cgi?id=735233
2017-01-24 13:36:09 +01:00
2ff988ef37 portalHelper: Use private data/cache directories
https://bugzilla.gnome.org/show_bug.cgi?id=775639
2017-01-24 13:36:09 +01:00
5136369c18 Properly detect changes in .desktop files
This fixes the shell not picking updates to the contents of the underlying
.desktop files for application launchers, or when a .desktop file is
overriden by a user-installed one under ~/.local/share/applications

https://bugzilla.gnome.org/show_bug.cgi?id=773636
2017-01-23 17:25:39 -06:00
7557207b47 Update French translation
(cherry picked from commit 3c6c51125c)
2017-01-22 18:13:16 +00:00
f9d1e2fec0 Update Polish translation 2017-01-21 20:16:24 +01:00
f9a03f212c ibusCandidatePopup: handle mouse scroll event on candidates
When use mouse scroll button on input method candidates,
move the cursor up/down on candidates.

https://bugzilla.gnome.org/show_bug.cgi?id=776032
2017-01-19 15:18:43 +01:00
d200fb1d14 portalHelper: Handle Ctrl+W/Ctrl+Q to close window
https://bugzilla.gnome.org/show_bug.cgi?id=764133
2017-01-19 14:04:34 +01:00
eb844b095a Update Slovak translation 2017-01-15 19:28:34 +00:00
dc638c04a6 Update Catalan translation 2017-01-15 19:51:00 +01:00
b3cbce97ed Update Brazilian Portuguese translation 2017-01-15 13:20:27 +00:00
14a32c128d Fix Icon filename in translations 2017-01-12 18:01:27 +01:00
2e332ffd12 Revert "objectManager: handle proxies coming and going"
This reverts commit 1ef6262139.

https://bugzilla.gnome.org/show_bug.cgi?id=772589
2017-01-09 22:34:40 -05:00
71d9d483f2 Update Slovak translation 2017-01-07 16:03:47 +00:00
1ef6262139 objectManager: handle proxies coming and going
Ever since commit b8e29ae8c7
(I think), start up is littered with this message:

 Gjs-WARNING **: JS ERROR: could not get remote objects for service
 org.gnome.SettingsDaemon.Smartcard path

since gnome-shell is now started before gnome-settings-daemon.

This commit addresses the problem by making the object manager code
not try to autostart its proxy, and instead wait for it to appear.

https://bugzilla.gnome.org/show_bug.cgi?id=772589
2017-01-05 13:11:21 -05:00
da7db509e7 network: Avoid JS error when activating VPN connection
If the call to settings.get_connection_by_path in
ensureActiveConnectionProps returns null, we'll hit a JS error here.
Seems to happen always when activating a VPN connection. Avoid that.

Giovanni says:

"I believe this is papering over an existing bug, but it's possible for
settings.get_connection_by_path() to legitimately return null (if the
connection is owned by a different user and invisible to the current
one), so the fix is correct anyway."

https://bugzilla.gnome.org/show_bug.cgi?id=759793
2016-12-27 12:14:19 -06:00
2a525bd8e8 Updated Spanish translation 2016-12-22 20:15:20 +01:00
51da2bf363 Update Hungarian translation 2016-12-20 15:12:34 +00:00
d2c0ade880 Update Hungarian translation 2016-12-20 15:10:07 +00:00
bcc3eccdab Update Finnish translation 2016-12-16 20:30:27 +00:00
e581e249ad Bump version to 3.23.3
Update NEWS.
2016-12-15 16:10:22 +01:00
c131c44ef6 gtk-embed: Don't try to compare with unrealized window
After having embedded a Gtk window, we start to listen for the
corresponding MetaWindow to know when it has been mapped by the
compositor. If the embedder does not realize the window immediately,
and some other window is created and mapped before the embedder
realizes the window, we would prior to this patch try to dereference
the not created GdkWindow. Fix this by NULL checking the GdkWindow
before dereferencing. We will never miss the needed MetaWindow creation
since it can not have been mapped have it not yet been realized.

https://bugzilla.gnome.org/show_bug.cgi?id=776130
2016-12-15 19:42:48 +08:00
cdd23d9cc7 appFavorites: add Calculator to rename list again
So far it's only the second app to be on the rename list twice, but no
doubt there will soon be more....
2016-12-12 18:48:51 -06:00
dc110db4e0 tests: Destroy GjsContext before exit
This will be required in the upcoming version of GJS.

https://bugzilla.gnome.org/show_bug.cgi?id=775374
2016-12-09 18:50:39 -08:00
678670bf1b appFavorites: add Epiphany to rename list 2016-12-09 12:39:12 -06:00
07fc15a1eb Update Italian translation
(cherry picked from commit 473158db8e)
2016-12-09 10:35:25 +00:00
83005e27da main: Destroy GjsContext before exit
This will be required in the upcoming version of GJS.

The reference count on ShellGlobal is 2 at this point, because JS holds a
reference due to the "window.global = Shell.Global.get()" line in
ui/environment.js. Therefore, destroy the GjsContext first, then unref
the ShellGlobal object.

Cleaning up ShellGlobal was previously only enabled behind a debug
environment variable, but it should be required now.

https://bugzilla.gnome.org/show_bug.cgi?id=775374
2016-12-07 11:34:15 -08:00
56b20ef779 helpers: Destroy GjsContext before exit
This will be required in the upcoming version of GJS.

https://bugzilla.gnome.org/show_bug.cgi?id=775374
2016-12-07 11:34:15 -08:00
04adeec8f5 appFavorites: add Geary in rename list
Signed-off-by: Niels De Graef <nielsdegraef@gmail.com>

https://bugzilla.gnome.org/show_bug.cgi?id=775507
2016-12-07 14:48:46 +01:00
62d640cd9e updated Punjabi Translation 2016-12-05 18:27:32 -06:00
9d7ad6748c Update Chinese (Taiwan) translation 2016-11-28 16:10:44 +00:00
accd24e379 notificationDaemon: Keep source alive when replacing notification
When a GNotification has the same ID as a previous one, it should
be shown as a new notification after withdrawing the old one.
However for this to work, we must not destroy the corresponding
source if withdrawing the old notification lets the notification
count drop to zero, so make sure the source is kept alive until
the replace operation has completed.

https://bugzilla.gnome.org/show_bug.cgi?id=775149
2016-11-28 15:42:23 +01:00
75d797a0ac Update Kazakh translation 2016-11-27 15:40:12 +00:00
e1e321d3a7 NotificationDaemon: create the application proxy asynchronously
Clicking on calendar notifications might block till the DBus request times
out if the application being poked happens to be non-responsive. Perform
this asynchronously so we don't block if that is the case.
2016-11-26 15:00:35 +01:00
f14f238150 Update German translation 2016-11-26 10:56:44 +00:00
ab3200019a Update German translation 2016-11-25 22:24:45 +00:00
28c028f7ac Update Turkish translation 2016-11-24 09:49:54 +00:00
08a159d0d8 Bump version to 3.23.2
Update NEWS.
2016-11-23 22:23:26 +01:00
26aa32c6cc build: Fix file reference 2016-11-23 22:23:26 +01:00
09e6bb5d56 appDisplay: Fix completion handler for empty animations
If an onComplete handler is passed to animate(), it is set to run at
the end of the animation via the icon grid's ::animation-done signal.
Currently the signal is connected after starting the animation, with
the result that the handler doesn't run when the animation completes
immediately (because there are no icons to animate). Fix this by only
starting the animation after connecting the signal.

https://bugzilla.gnome.org/show_bug.cgi?id=774381
2016-11-23 22:11:00 +01:00
e661d904de appDisplay: Use correct view for animation
We currently assume that the current view matches the 'app-picker-view'
setting. While that is usually the case, there is one notable exception:
While there isn't sufficient usage data (yet), we show all applications
instead of an empty frequent view regardless of the setting. We should
animate the actually visible icons in that case, not the (non-existent)
ones from the hidden frequent view.

https://bugzilla.gnome.org/show_bug.cgi?id=774381
2016-11-23 22:11:00 +01:00
407d51e871 Update Russian translation
(cherry picked from commit f395d3892c)
2016-11-23 21:08:42 +00:00
c4a07fad83 portalHelper: Use a constant for the host name and URI
https://bugzilla.gnome.org/show_bug.cgi?id=769940
2016-11-23 21:38:24 +01:00
9ea8fdc1d1 portalHelper: Address intermittent TLS failures
Users are currently experiencing intermittent (and hard to debug) TLS
errors when loading the portal authentication page. This could be
caused by using http://www.gnome.org/ for our connectivity checks
because it redirects to HTTPS.

We can completely remove TLS from the equation by not using HTTPS.
http://nmcheck.gnome.org/ is a good choice because it doesn't redirect
to HTTPS and was created for NetworkManager's connectivity check.

https://bugzilla.gnome.org/show_bug.cgi?id=769940
2016-11-23 21:38:24 +01:00
3d6bf43649 windowManager: Handle fullscreening from zero sized windows
Wayland clients can request their surfaces to be fullscreened before
commiting a buffer which means that we need to handle fullscreen
requests for which the old size is 0x0, preferably without warnings.

Since the mapping animation also runs for these windows, we can simply
bail out and ignore the fullscreen size change.

https://bugzilla.gnome.org/show_bug.cgi?id=770345
2016-11-23 18:43:11 +01:00
7bc1d57ad7 windowManager: Fix fullscreen animations of wayland clients
Wayland clients are in control of their window size so the existing
mutter plugin API, which assumes size changes are synchronous, doesn't
work for them since when our size-change handler runs the MetaWindow's
size isn't final yet.

To fix this, the mutter plugin API was extended with a size-changed
vfunc that lets us know when the MetaWindow size has actually
changed. This way we can make the window snapshot and get the old
window size on the existing size-change handler and later, on the new
size-changed handler, get the new size and start the animation.

https://bugzilla.gnome.org/show_bug.cgi?id=770345
2016-11-23 18:43:07 +01:00
68b671a4f4 shell-wm: Add a size-changed signal to handle the new plugin vfunc
https://bugzilla.gnome.org/show_bug.cgi?id=770345
2016-11-23 18:42:59 +01:00
1de1fd44c5 texture-cache: Warn when loading sliced image fails
Sliced images are loaded into a group actor with one child actor
per slice. In case loading the image fails, we currently quietly
return the empty group actor, which makes diagnosing problems
unnecessarily hard - just be a bit more verbose on failure.

https://bugzilla.gnome.org/show_bug.cgi?id=774805
2016-11-22 18:38:10 +01:00
e5101eb407 animations: Guard against empty animations
Our animation code not only relies on the animation being loaded
(which we handle), but also on having at least one frame - otherwise
the computation of the next frame index will turn up NaN through
division by zero. Guard against this case by treating empty animations
as not loaded.

https://bugzilla.gnome.org/show_bug.cgi?id=774805
2016-11-22 18:38:10 +01:00
48e0d86340 Updated Norwegian bokmål translation. 2016-11-21 08:32:50 +01:00
c64cf30160 Update Friulian translation 2016-11-20 04:05:59 +00:00
ff9d777c01 Update Finnish translation
(cherry picked from commit d0e811214b)
2016-11-19 17:11:46 +00:00
d8c33deb33 Update Kazakh translation
(cherry picked from commit 52bbee80a0)
2016-11-19 12:05:43 +00:00
c03ff0bd4f Update Brazilian Portuguese translation
(cherry picked from commit 7098d6930f)
2016-11-18 23:41:47 +00:00
d597633d8f Updated Czech translation 2016-11-18 00:44:06 +01:00
4f6eb49be3 Update Polish translation 2016-11-18 00:05:56 +01:00
d23bd4c4a6 runDialog: Mark error message as translatable
https://bugzilla.gnome.org/show_bug.cgi?id=774643
2016-11-17 22:14:30 +01:00
7f12265685 Updated Czech translation 2016-11-12 12:13:02 +01:00
250023b823 Update Friulian translation 2016-11-10 20:34:06 +00:00
3b52691ab4 Update Spanish translation 2016-11-10 15:39:40 +00:00
b6cd548186 network: Always show primary icon when connected
The top bar's network menu only supports a subset of device types
supported by NetworkManager. While not having lesser used options
in the menu itself is perfectly reasonable, not showing any network
icon at all in the top bar when the system is fully connected is
weird.

https://bugzilla.gnome.org/show_bug.cgi?id=773890
2016-11-10 14:32:07 +01:00
b3fabf11b1 network: Summarize sections with too many devices
Any network devices appear as top level items in the system status
menu, so on system with an unusually high number of devices, the
menu can end up exceeding the available screen height. While this
is a corner case, leaving important system actions unreachable is
bad. The system menu does not lend itself to scrolling, so handle
this case instead by summarizing sections ("n connections") where
the number of devices exceeds a threshold.

https://bugzilla.gnome.org/show_bug.cgi?id=773892
2016-11-10 14:32:07 +01:00
15be562fdf networkAgent: Invalidate VPN plugin cache on changes
Currently the cache is built once when the first VPN request is
handled, so plugins that are installed or uninstalled after that
aren't picked up. Fix this by invalidating the cache on changes
to the plugin directory.

https://bugzilla.gnome.org/show_bug.cgi?id=773893
2016-11-10 14:32:07 +01:00
599fa0b76c Update Russian translation
(cherry picked from commit 5858b2266a)
2016-11-08 18:24:56 +00:00
c520eb4de0 Updated Czech translation 2016-11-08 13:05:31 +01:00
e33c68a415 popupMenu: don't handle key presses directly if there are modifiers
commit 1d58ea25ab changed the
popupMenu code to handle key presses on source actors directly.

This fixed keynav into the session gear menu at the login screen.

Unfortunately, it also causes spurious pop ups if a modifier happens
to be held down.

This commit checks for modifiers and short circuits the up front
key handling if any are found.

https://bugzilla.gnome.org/show_bug.cgi?id=740043
2016-11-07 14:01:23 -05:00
97bd224261 Update Hungarian translation 2016-11-05 20:20:39 +00:00
503e086c56 Update Friulian translation 2016-11-04 20:03:16 +00:00
7dd6b7f04f theme: Update from SASS 2016-11-04 16:55:49 +01:00
0b05b7a527 viewSelection: Handle touchpad 3-finger pinches
In order to show the overview, just like touchscreens do.

https://bugzilla.gnome.org/show_bug.cgi?id=765937
2016-11-04 16:35:11 +01:00
7e5274619a windowManager: Update API call
This function has now a more generic name, so it caters for both
swipe and pinch touchpad gestures.

https://bugzilla.gnome.org/show_bug.cgi?id=765937
2016-11-04 16:35:11 +01:00
900957d658 Update gnome-shell-sass module 2016-11-04 16:33:43 +01:00
e006b9b400 ui: Add PadOsd
This is an implementation of the pad OSD that's been previously
present in gnome-settings-daemon. Since things are moving closer
to the compositor, it makes sense to have this implemented as shell
UI.

https://bugzilla.gnome.org/show_bug.cgi?id=771067
2016-11-04 16:08:10 +01:00
d042dd73aa Update Hungarian translation 2016-11-04 06:17:53 +00:00
347972e45f screenShield: Raise lightbox on blank
The lightboxes used for screen blanking are created during initialization
and shown each time the screen should blank. During the (potentially long)
time where the lightbox is hidden, any actor could be raised above the
lightbox - in particular any popup menu raises itself to the top when
opened. To not exclude those elements from screen blanking, raise the
lightbox every time it is shown.

https://bugzilla.gnome.org/show_bug.cgi?id=773875
2016-11-03 21:15:20 +01:00
151 changed files with 23910 additions and 14262 deletions

161
NEWS
View File

@ -1,3 +1,164 @@
3.24.2
======
* Only fetch weather information when there's a valid location [Rares; #780404]
* Handle extension errors during reload due to settings change [Emilio; #781728]
* Fix StEntry::primary-icon-clicked emission [Florian; #782190]
* Allow search providers to provide clipboard text for results [Daiki; #775099]
* Misc. bug fixes [Florian; #781545]
Contributors:
Florian Müllner, Emilio Pozuelo Monfort, Daiki Ueno, Rares Visalom
Translations:
Milo Casagrande [it], Милош Поповић [sr], Khaled Hosny [ar]
3.24.1
======
* Close Wifi selection dialog on lock [Florian; #780054]
* Fix DND over window previews in overview [Florian; #737166]
* Do not lock the screen when disabled by lockdown settings [Florian; #780212]
* Follow GNOME Weather's location permissions [Florian; #780252]
* Fix portals that require a new window to be loaded [Catalin; #759044]
* Fix restricting menus to screen height on HiDPI displays [Cosimo; #753305]
* Misc. bug fixes and cleanups [Florian, Cosimo, Bastien, Catalin, Carlos;
#780063, #780321, #780381, #780453, #758873, #780606, #642652]
Contributors:
Cosimo Cecchi, Carlos Garnacho, Catalin Iacob, Florian Müllner, Bastien Nocera
Translations:
Marek Cernocky [cs], Piotr Drąg [pl], Anders Jonsson [sv], Stas Solovey [ru],
Rafael Fontenelle [pt_BR], Baurzhan Muftakhidinov [kk], Daniel Korostil [uk],
Kukuh Syafaat [id], Milo Casagrande [it], Jiri Grönroos [fi],
Daniel Mustieles [es], Balázs Úr [hu], Guillaume Bernard [fr],
Changwoo Ryu [ko], Mario Blättermann [de], Fran Dieguez [gl],
Dušan Kazik [sk], Yuras Shumovich [be], Fabio Tomat [fur],
Kjartan Maraas [nb], Aurimas Černius [lt], Trần Ngọc Quân [vi],
Rūdolfs Mazurs [lv], Ask Hjorth Larsen [da], Tom Tryfonidis [el], gogo [hr]
3.24.0
======
Translations:
GNOME Translation Robot [tg], Мирослав Николић [sr, sr@latin],
Guillaume Bernard [fr], Rūdolfs Mazurs [lv], Emin Tufan Çetin [tr],
sujiniku [ja], Daniel Korostil [uk]
3.23.92
=======
* Implement DND to overview on wayland [Hyungwon; #765003]
* Make telepathy optional at runtime [Florian; #771721, #779878]
* Don't show forecasts for NYC when geoclue gets stuck [Sebastian; #779898]
* Add bottom edge drag gesture to bring up the OSK [Jan-Michael; #757712]
* Allow switching between pads in the same group [Carlos; #779986]
* Ignore showBanners policy for critical notifications [Florian; #779974]
* Misc. bug fixes [Florian; #779435, #779819, #779820]
Contributors:
Jan-Michael Brummer, Allan Day, Carlos Garnacho, Hyungwon Hwang,
Sebastian Keller, Florian Müllner
Translations:
Enrico Nicoletto [pt_BR], Jiri Grönroos [fi], Chao-Hsiung Liao [zh_TW],
Piotr Drąg [pl], Piotr Drąg [he], Balázs Meskó [hu], Kris Thomsen [da],
Yuras Shumovich [be], Sveinn í Felli [is], Inaki Larranaga Murgoitio [eu],
Changwoo Ryu [ko], Jordi Mas [ca], Aurimas Černius [lt],
Мирослав Николић [sr, sr@latin], Christian Kirbach [de], Anders Jonsson [sv],
Fabio Tomat [fur], GNOME Translation Robot [gd], Dušan Kazik [sk],
Kukuh Syafaat [id], Marek Černocký [cs], Stas Solovey [ru],
Milo Casagrande [it], Fran Dieguez [gl], Daniel Boles [gl], A S Alam [pa],
Daniel Mustieles [es]
3.23.91
=======
* Use the original timestamps for restored notifications [Florian; #766410]
* Add weather information to date+time drop-down [Florian; #754031]
* Refine message list layout in date+time drop-down [Florian; #775763]
* Make next/prev media controls insensitive when unavailable [Florian; #773884]
* Misc. bug fixes [Piotr, Bastien, Florian; #772210, #769546, #775799]
Contributors:
Piotr Drąg, Carlos Garnacho, Florian Müllner, Bastien Nocera
Translations:
Baurzhan Muftakhidinov [kk], Jordi Mas [ca], Ask Hjorth Larsen [da],
Inaki Larranaga Murgoitio [eu], Daniel Mustieles [es], Dušan Kazik [sk],
Aurimas Černius [lt], Jiri Grönroos [fi], Kjartan Maraas [nb],
Piotr Drąg [pl], Daniel Korostil [uk], Kukuh Syafaat [id],
Milo Casagrande [it], Fabio Tomat [fur], Rafael Fontenelle [pt_BR],
Fran Dieguez [gl], Мирослав Николић [sr, sr@latin], Balázs Meskó [hu],
Chao-Hsiung Liao [zh_TW]
3.23.90
=======
* Handle Ctrl+Q and Ctrl+W in portal window [Bastien; #764133]
* Allow to scroll through ibus candidates with mouse [Peng; #776032]
* Reload apps on .desktop file content changes [Adrian; #773636]
* Use private data/cache directories in portal helper [Bastien; #775639]
* Fix subsurfaces not showing up in previews [Rui; #756715]
* Fix theme node transitions [Florian; #778145]
* Update pad (o)leds on mode switches [Carlos; #776543]
* Add security indicators to defend against malicious portals [Bastien; #749197]
* Don't allow type ahead at the login screen [Ray; #766139]
* Don't fail to load because of TLS errors [Bastien; #778253]
* Ensure the network lists remains sorted on rename [Benjamin; #778686]
* Toggle power-off/suspend button on long-press [Florian; #721173]
* Add "kill-switch" for user extensions [Florian; #778664]
* Add night light indicator to status area [Florian; #741224]
* Misc. bug fixes [Michael, Bastien, Carlos, Rui, Florian, Alan, Philip, Jonas;
#759793, #735233, #762444, #777784, #777934, #778158, #776199, #778425,
#771098, #778552, #777317, #778660, #778661, #745626, #778672]
Contributors:
Jonas Ådahl, Benjamin Berg, Michael Catanzaro, Philip Chimento,
Alan Coopersmith, Piotr Drąg, Carlos Garnacho, Yuri Konotopov,
Lionel Landwerlin, Rui Matos, Florian Müllner, Bastien Nocera,
Adrian Perez de Castro, Robert Roth, Ray Strode, Peng Wu
Translations:
Jiri Grönroos [fi], Balázs Meskó [hu], Gábor Kelemen [hu],
Daniel Mustieles [es], Dušan Kazik [sk],
Piotr Drąg [ar, eu, fa, hr, pa, pt, sr, sr@latin], Rafael Fontenelle [pt_BR],
Jordi Mas [ca], Piotr Drąg [pl], Alexandre Franke [fr],
Baurzhan Muftakhidinov [kk], Yuras Shumovich [be], Mandy Wang [zh_CN],
Marek Černocký [cs], Kukuh Syafaat [id], Kjartan Maraas [nb],
Daniel Korostil [uk]
3.23.3
======
* Fix replacing of GNotifications [Florian; #775149]
* Prepare for mozjs31 GJS [Philip; #775374]
* Misc. bug fixes [Niels, Jonas; #775507, #776130]
Contributors:
Jonas Ådahl, Michael Catanzaro, Philip Chimento, Niels De Graef,
Carlos Garnacho, Florian Müllner
Translations:
Muhammet Kara [tr], Christian Kirbach [de], Baurzhan Muftakhidinov [kk],
Cheng-Chia Tseng [zh_TW], A S Alam [pa], Gianvito Cavasoli [it]
3.23.2
======
* Implement Pad configuration OSD [Carlos; #771067]
* Show overview on three-finger touchpad pinch [Carlos; #765937]
* Summarize network sections with too many devices [Florian; #773892]
* Always show primary network icon when connected [Florian; #773890]
* Fix fullscreen transitions on wayland [Rui; #770345]
* Work around portal failures by using a URL without HTPPS redirect [Debarshi; #769940]
* Fix app view hiding when no usage data is available [Florian, Xiaoguang; #774381]
* Misc. bug fixes [Florian, Ray; #773875, #740043, #773893, #774643, #774805]
Contributors:
Carlos Garnacho, Rui Matos, Florian Müllner, Debarshi Ray, Ray Strode,
Xiaoguang Wang
Translations:
Balázs Meskó [hu], Fabio Tomat [fur], Marek Cernocky [cs], Stas Solovey [ru],
Daniel Mustieles [es], Marek Černocký [cs], Piotr Drąg [pl],
Rafael Fontenelle [pt_BR], Baurzhan Muftakhidinov [kk], Jiri Grönroos [fi],
Kjartan Maraas [nb]
3.23.1
======
* Request periodic scans while WiFi list is open [Dan; #767918]

View File

@ -4,15 +4,15 @@
srcdir=`dirname $0`
test -z "$srcdir" && srcdir=.
(test -f $srcdir/configure.ac \
&& test -d $srcdir/src) || {
pushd $srcdir
(test -f configure.ac \
&& test -d src) || {
echo -n "**Error**: Directory "\`$srcdir\'" does not look like the"
echo " top-level gnome-shell directory"
exit 1
}
pushd $srcdir
# Fetch submodules if needed
if test ! -f src/gvc/Makefile.am || test ! -f data/theme/gnome-shell-sass/COPYING;
then
@ -21,11 +21,13 @@ then
fi
git submodule update
aclocal --install || exit 1
gtkdocize --copy || exit 1
intltoolize --force --copy --automake || exit 1
autoreconf --verbose --force --install || exit 1
popd
which gnome-autogen.sh || {
echo "You need to install gnome-common from GNOME Git (or from"
echo "your OS vendor's package manager)."
exit 1
}
. gnome-autogen.sh
if [ "$NOCONFIGURE" = "" ]; then
$srcdir/configure "$@" || exit 1
fi

View File

@ -1,5 +1,5 @@
AC_PREREQ(2.63)
AC_INIT([gnome-shell],[3.23.1],[https://bugzilla.gnome.org/enter_bug.cgi?product=gnome-shell],[gnome-shell])
AC_INIT([gnome-shell],[3.24.2],[https://bugzilla.gnome.org/enter_bug.cgi?product=gnome-shell],[gnome-shell])
AX_IS_RELEASE([git-directory])
AC_CONFIG_HEADERS([config.h])
@ -17,7 +17,6 @@ m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])])
# Checks for programs.
AC_PROG_CC
AC_PROG_CXX
# Initialize libtool
LT_PREREQ([2.2.6])
@ -42,6 +41,15 @@ GLIB_GSETTINGS
AM_PATH_PYTHON([3])
AC_SUBST(PYTHON)
# We depend on a specific version of the libmutter API. The mutter variants of
# the Cogl and Clutter libraries also use this API version.
LIBMUTTER_API_VERSION=0
LIBMUTTER=libmutter-$LIBMUTTER_API_VERSION
LIBMUTTER_COGL=mutter-cogl-$LIBMUTTER_API_VERSION
LIBMUTTER_COGL_PANGO=mutter-cogl-pango-$LIBMUTTER_API_VERSION
LIBMUTTER_CLUTTER=mutter-clutter-$LIBMUTTER_API_VERSION
# We need at least this, since gst_plugin_register_static() was added
# in 0.10.16, but nothing older than 0.10.21 has been tested.
GSTREAMER_MIN_VERSION=0.11.92
@ -53,7 +61,7 @@ if $PKG_CONFIG --exists gstreamer-1.0 '>=' $GSTREAMER_MIN_VERSION ; then
AC_MSG_RESULT(yes)
build_recorder=true
recorder_modules="gstreamer-1.0 gstreamer-base-1.0 x11 gtk+-3.0"
PKG_CHECK_MODULES(TEST_SHELL_RECORDER, $recorder_modules mutter-clutter-1.0)
PKG_CHECK_MODULES(TEST_SHELL_RECORDER, $recorder_modules $LIBMUTTER_CLUTTER)
else
AC_MSG_RESULT(no)
fi
@ -75,15 +83,13 @@ AS_IF([test x$enable_systemd != xno], [
AC_MSG_RESULT($enable_systemd)
CLUTTER_MIN_VERSION=1.21.5
GOBJECT_INTROSPECTION_MIN_VERSION=1.49.1
GJS_MIN_VERSION=1.47.0
MUTTER_MIN_VERSION=3.23.1
MUTTER_MIN_VERSION=3.24.0
GTK_MIN_VERSION=3.15.0
GIO_MIN_VERSION=2.45.3
LIBECAL_MIN_VERSION=3.5.3
LIBEDATASERVER_MIN_VERSION=3.17.2
TELEPATHY_GLIB_MIN_VERSION=0.17.5
POLKIT_MIN_VERSION=0.100
STARTUP_NOTIFICATION_MIN_VERSION=0.11
GCR_MIN_VERSION=3.7.5
@ -99,12 +105,11 @@ SHARED_PCS="gio-unix-2.0 >= $GIO_MIN_VERSION
gjs-1.0 >= $GJS_MIN_VERSION
$recorder_modules
gdk-x11-3.0 libsoup-2.4
mutter-clutter-1.0 >= $CLUTTER_MIN_VERSION
mutter-cogl-pango-1.0
$LIBMUTTER_CLUTTER >= $MUTTER_MIN_VERSION
$LIBMUTTER_COGL_PANGO
libstartup-notification-1.0 >= $STARTUP_NOTIFICATION_MIN_VERSION
gobject-introspection-1.0 >= $GOBJECT_INTROSPECTION_MIN_VERSION
libcanberra libcanberra-gtk3
telepathy-glib >= $TELEPATHY_GLIB_MIN_VERSION
polkit-agent-1 >= $POLKIT_MIN_VERSION
gcr-base-3 >= $GCR_MIN_VERSION"
if test x$have_systemd = xyes; then
@ -112,16 +117,18 @@ if test x$have_systemd = xyes; then
fi
PKG_CHECK_MODULES(GNOME_SHELL, $SHARED_PCS)
PKG_CHECK_MODULES(MUTTER, libmutter >= $MUTTER_MIN_VERSION)
PKG_CHECK_MODULES(MUTTER, $LIBMUTTER >= $MUTTER_MIN_VERSION)
PKG_CHECK_MODULES(GNOME_SHELL_JS, gio-2.0 gjs-1.0 >= $GJS_MIN_VERSION)
PKG_CHECK_MODULES(ST, mutter-clutter-1.0 gtk+-3.0 libcroco-0.6 >= 0.6.8 x11)
PKG_CHECK_MODULES(ST, $LIBMUTTER_CLUTTER gtk+-3.0 libcroco-0.6 >= 0.6.8 x11)
PKG_CHECK_MODULES(SHELL_PERF_HELPER, gtk+-3.0 gio-2.0)
PKG_CHECK_MODULES(SHELL_HOTPLUG_SNIFFER, gio-2.0 gdk-pixbuf-2.0)
PKG_CHECK_MODULES(TRAY, mutter-clutter-1.0 gtk+-3.0)
PKG_CHECK_MODULES(TRAY, $LIBMUTTER_CLUTTER gtk+-3.0)
PKG_CHECK_MODULES(GVC, libpulse >= $PULSE_MIN_VERS libpulse-mainloop-glib gobject-2.0)
PKG_CHECK_MODULES(DESKTOP_SCHEMAS, gsettings-desktop-schemas >= 3.21.3)
AC_SUBST(LIBMUTTER_API_VERSION)
AC_ARG_ENABLE(browser-plugin,
[AS_HELP_STRING([--enable-browser-plugin],
[Enable browser plugin [default=yes]])],,
@ -146,10 +153,10 @@ AC_SUBST([GNOME_KEYBINDINGS_KEYSDIR])
GOBJECT_INTROSPECTION_CHECK([$GOBJECT_INTROSPECTION_MIN_VERSION])
MUTTER_GIR_DIR=`$PKG_CONFIG --variable=girdir libmutter`
MUTTER_GIR_DIR=`$PKG_CONFIG --variable=girdir $LIBMUTTER`
AC_SUBST(MUTTER_GIR_DIR)
MUTTER_TYPELIB_DIR=`$PKG_CONFIG --variable=typelibdir libmutter`
MUTTER_TYPELIB_DIR=`$PKG_CONFIG --variable=typelibdir $LIBMUTTER`
AC_SUBST(MUTTER_TYPELIB_DIR)
GJS_CONSOLE=`$PKG_CONFIG --variable=gjs_console gjs-1.0`

View File

@ -38,6 +38,7 @@ endif
introspectiondir = $(datadir)/dbus-1/interfaces
introspection_DATA = \
org.gnome.Shell.PadOsd.xml \
org.gnome.Shell.Screencast.xml \
org.gnome.Shell.Screenshot.xml \
org.gnome.ShellSearchProvider.xml \
@ -63,6 +64,7 @@ dist_theme_files = \
theme/gnome-shell-sass/NEWS \
theme/gnome-shell-sass/README \
theme/gnome-shell-sass/gnome-shell-sass.doap \
theme/pad-osd.css \
theme/parse-sass.sh \
$(NULL)

View File

@ -1,6 +1,6 @@
[Desktop Entry]
Type=Application
Name=GNOME Shell Extension Preferences
Name=Shell Extensions
Comment=Configure GNOME Shell Extensions
Exec=@bindir@/gnome-shell-extension-prefs %u
X-GNOME-Bugzilla-Bugzilla=GNOME

View File

@ -22,6 +22,7 @@
<file>no-events.svg</file>
<file>no-notifications.svg</file>
<file>noise-texture.png</file>
<file>pad-osd.css</file>
<file>page-indicator-active.svg</file>
<file>page-indicator-inactive.svg</file>
<file>page-indicator-checked.svg</file>

View File

@ -0,0 +1,28 @@
<!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.PadOSD:
@short_description: Pad OSD interface
The interface used to show button map OSD on pad devices.
-->
<interface name='org.gnome.Shell.Wacom.PadOsd'>
<!--
Show:
@device_node: device node file, usually in /dev/input/...
@edition_mode: whether toggling edition mode on when showing
Shows the pad button map OSD for the requested device, the OSD
will be shown according the current device settings (output
mapping, left handed mode, ...)
-->
<method name='Show'>
<arg name='device_node' direction='in' type='o'/>
<arg name='edition_mode' direction='in' type='b'/>
</method>
</interface>
</node>

View File

@ -21,6 +21,14 @@
EnableExtension and DisableExtension D-Bus methods on org.gnome.Shell.
</description>
</key>
<key name="disable-user-extensions" type="b">
<default>false</default>
<summary>Disable user extensions</summary>
<description>
Disable all extensions the user has enabled without affecting
the “enabled-extension” setting.
</description>
</key>
<key name="disable-extension-version-validation" type="b">
<default>true</default>
<summary>Disables the validation of extension version compatibility</summary>
@ -56,9 +64,9 @@
</key>
<key name="always-show-log-out" type="b">
<default>false</default>
<summary>Always show the 'Log out' menu item in the user menu.</summary>
<summary>Always show the Log out menu item in the user menu.</summary>
<description>
This key overrides the automatic hiding of the 'Log out'
This key overrides the automatic hiding of the Log out
menu item in single-user, single-session situations.
</description>
</key>
@ -68,7 +76,7 @@
<description>
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 'Remember Password' checkbox will be present.
future use a Remember Password checkbox will be present.
This key sets the default state of the checkbox.
</description>
</key>
@ -97,9 +105,9 @@
</key>
<key name="toggle-application-view" type="as">
<default>["&lt;Super&gt;a"]</default>
<summary>Keybinding to open the "Show Applications" view</summary>
<summary>Keybinding to open the Show Applications view</summary>
<description>
Keybinding to open the "Show Applications" view of the Activities
Keybinding to open the Show Applications view of the Activities
Overview.
</description>
</key>
@ -168,8 +176,8 @@
<summary>The application icon mode.</summary>
<description>
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'.
are thumbnail-only (shows a thumbnail of the window), app-icon-only
(shows only the application icon) or both.
</description>
</key>
<key type="b" name="current-workspace-only">

View File

@ -562,6 +562,18 @@ StScrollBar {
background-color: #eeeeec;
border-radius: 0.3em; }
/* Pad OSD */
.pad-osd-window {
padding: 32px;
background-color: rgba(0, 0, 0, 0.8); }
.pad-osd-window .pad-osd-title-box {
spacing: 12px; }
.pad-osd-window .pad-osd-title-menu-box {
spacing: 6px; }
.combo-box-label {
width: 15em; }
/* App Switcher */
.switcher-popup {
padding: 8px;
@ -726,9 +738,20 @@ StScrollBar {
.datemenu-displays-section {
padding-bottom: 3em; }
.datemenu-displays-box {
spacing: 1em; }
.datemenu-calendar-column {
border: 0 solid #0d0d0d; }
.datemenu-calendar-column:ltr {
border-left-width: 1px; }
.datemenu-calendar-column:rtl {
border-right-width: 1px; }
.datemenu-today-button,
.world-clocks-button,
.message-list-section-title {
.weather-button,
.events-section-title {
border-radius: 4px;
padding: .4em; }
@ -741,12 +764,15 @@ StScrollBar {
.datemenu-today-button:hover, .datemenu-today-button:focus,
.world-clocks-button:hover,
.world-clocks-button:focus,
.message-list-section-title:hover,
.message-list-section-title:focus {
.weather-button:hover,
.weather-button:focus,
.events-section-title:hover,
.events-section-title:focus {
background-color: #0d0d0d; }
.datemenu-today-button:active,
.world-clocks-button:active,
.message-list-section-title:active {
.weather-button:active,
.events-section-title:active {
color: white;
background-color: #215d9c; }
@ -754,13 +780,17 @@ StScrollBar {
font-size: 1.5em; }
.world-clocks-header,
.message-list-section-title {
.weather-header,
.events-section-title {
color: #999999;
font-weight: bold; }
.world-clocks-grid {
spacing-rows: 0.4em; }
.weather-box {
spacing: 0.4em; }
.calendar-month-label {
color: #f2f2f2;
font-weight: bold;
@ -845,69 +875,68 @@ StScrollBar {
.message-list {
width: 31.5em; }
.message-list-clear-button.button {
background-color: transparent;
margin: 1.5em 1.5em 0; }
.message-list-clear-button.button:hover, .message-list-clear-button.button:focus {
background-color: #0d0d0d; }
.message-list-sections {
spacing: 1.5em; }
spacing: 1em; }
.message-list-section,
.message-list-section-list {
spacing: 0.7em; }
.message-list-section-title-box {
spacing: 0.4em; }
.message-list-section-close > StIcon {
icon-size: 16px;
border-radius: 8px;
color: #000;
background-color: #666666; }
/* FIXME: how do you do this in sass? */
.message-list-section-close:hover > StIcon,
.message-list-section-close:focus > StIcon {
background-color: #999999; }
.message {
background-color: #0d0d0d;
border-radius: 3px; }
.message:hover, .message:focus {
background-color: #262626; }
background-color: #0d0d0d; }
.message-icon-bin {
padding: 8px 0px 8px 8px; }
padding: 10px 3px 10px 10px; }
.message-icon-bin:rtl {
padding: 8px 8px 8px 0px; }
padding: 10px 10px 10px 3px; }
.message-icon-bin > StIcon {
icon-size: 32px; }
.message-secondary-bin:ltr {
padding-left: 8px; }
.message-secondary-bin:rtl {
padding-right: 8px; }
color: #cccccc;
icon-size: 16px;
-st-icon-style: symbolic; }
.message-secondary-bin {
color: #999999; }
padding: 0 12px; }
.message-secondary-bin > .event-time {
color: #999999;
font-size: 0.7em;
/* HACK: the label should be baseline-aligned with a 1em label,
fake this with some bottom padding */
padding-bottom: 0.13em; }
.message-secondary-bin > StIcon {
icon-size: 16px; }
.message-title {
font-weight: bold;
font-size: 1.1em; }
color: #f2f2f2; }
.message-content {
padding: 8px;
font-size: .9em; }
color: #cccccc;
padding: 10px; }
.message-media-control {
padding: 6px; }
padding: 12px;
color: #cccccc; }
.message-media-control:last-child:ltr {
padding-right: 18px; }
.message-media-control:last-child:rtl {
padding-left: 18px; }
.message-media-control:hover {
color: #fff; }
.message-media-control:insensitive {
color: #999999; }
.media-message-cover-icon {
icon-size: 32px; }
icon-size: 48px !important; }
.media-message-cover-icon.fallback {
color: #1a1a1a;
background-color: #000;

View File

@ -562,6 +562,18 @@ StScrollBar {
background-color: #eeeeec;
border-radius: 0.3em; }
/* Pad OSD */
.pad-osd-window {
padding: 32px;
background-color: rgba(0, 0, 0, 0.8); }
.pad-osd-window .pad-osd-title-box {
spacing: 12px; }
.pad-osd-window .pad-osd-title-menu-box {
spacing: 6px; }
.combo-box-label {
width: 15em; }
/* App Switcher */
.switcher-popup {
padding: 8px;
@ -726,9 +738,20 @@ StScrollBar {
.datemenu-displays-section {
padding-bottom: 3em; }
.datemenu-displays-box {
spacing: 1em; }
.datemenu-calendar-column {
border: 0 solid #454c4c; }
.datemenu-calendar-column:ltr {
border-left-width: 1px; }
.datemenu-calendar-column:rtl {
border-right-width: 1px; }
.datemenu-today-button,
.world-clocks-button,
.message-list-section-title {
.weather-button,
.events-section-title {
border-radius: 4px;
padding: .4em; }
@ -741,12 +764,15 @@ StScrollBar {
.datemenu-today-button:hover, .datemenu-today-button:focus,
.world-clocks-button:hover,
.world-clocks-button:focus,
.message-list-section-title:hover,
.message-list-section-title:focus {
.weather-button:hover,
.weather-button:focus,
.events-section-title:hover,
.events-section-title:focus {
background-color: #454c4c; }
.datemenu-today-button:active,
.world-clocks-button:active,
.message-list-section-title:active {
.weather-button:active,
.events-section-title:active {
color: white;
background-color: #215d9c; }
@ -754,13 +780,17 @@ StScrollBar {
font-size: 1.5em; }
.world-clocks-header,
.message-list-section-title {
.weather-header,
.events-section-title {
color: #8e8e80;
font-weight: bold; }
.world-clocks-grid {
spacing-rows: 0.4em; }
.weather-box {
spacing: 0.4em; }
.calendar-month-label {
color: #e2e2df;
font-weight: bold;
@ -845,69 +875,68 @@ StScrollBar {
.message-list {
width: 31.5em; }
.message-list-clear-button.button {
background-color: transparent;
margin: 1.5em 1.5em 0; }
.message-list-clear-button.button:hover, .message-list-clear-button.button:focus {
background-color: #454c4c; }
.message-list-sections {
spacing: 1.5em; }
spacing: 1em; }
.message-list-section,
.message-list-section-list {
spacing: 0.7em; }
.message-list-section-title-box {
spacing: 0.4em; }
.message-list-section-close > StIcon {
icon-size: 16px;
border-radius: 8px;
color: #393f3f;
background-color: #59594f; }
/* FIXME: how do you do this in sass? */
.message-list-section-close:hover > StIcon,
.message-list-section-close:focus > StIcon {
background-color: #8e8e80; }
.message {
background-color: #454c4c;
border-radius: 3px; }
.message:hover, .message:focus {
background-color: #5d6767; }
background-color: #454c4c; }
.message-icon-bin {
padding: 8px 0px 8px 8px; }
padding: 10px 3px 10px 10px; }
.message-icon-bin:rtl {
padding: 8px 8px 8px 0px; }
padding: 10px 10px 10px 3px; }
.message-icon-bin > StIcon {
icon-size: 32px; }
.message-secondary-bin:ltr {
padding-left: 8px; }
.message-secondary-bin:rtl {
padding-right: 8px; }
color: #bebeb6;
icon-size: 16px;
-st-icon-style: symbolic; }
.message-secondary-bin {
color: #8e8e80; }
padding: 0 12px; }
.message-secondary-bin > .event-time {
color: #8e8e80;
font-size: 0.7em;
/* HACK: the label should be baseline-aligned with a 1em label,
fake this with some bottom padding */
padding-bottom: 0.13em; }
.message-secondary-bin > StIcon {
icon-size: 16px; }
.message-title {
font-weight: bold;
font-size: 1.1em; }
color: #e2e2df; }
.message-content {
padding: 8px;
font-size: .9em; }
color: #bebeb6;
padding: 10px; }
.message-media-control {
padding: 6px; }
padding: 12px;
color: #bebeb6; }
.message-media-control:last-child:ltr {
padding-right: 18px; }
.message-media-control:last-child:rtl {
padding-left: 18px; }
.message-media-control:hover {
color: #eeeeec; }
.message-media-control:insensitive {
color: #8e8e80; }
.media-message-cover-icon {
icon-size: 32px; }
icon-size: 48px !important; }
.media-message-cover-icon.fallback {
color: #515a5a;
background-color: #393f3f;

30
data/theme/pad-osd.css Normal file
View File

@ -0,0 +1,30 @@
.Leader {
stroke-width: .5 !important;
stroke: #535353;
fill: none !important;
}
.Button {
stroke-width: .25;
stroke: #ededed;
fill: #ededed;
}
.Ring {
stroke-width: .5 !important;
stroke: #535353 !important;
fill: none !important;
}
.Label {
stroke: none !important;
stroke-width: .1 !important;
font-size: .1 !important;
fill: transparent !important;
}
.TouchStrip, .TouchRing {
stroke-width: .1 !important;
stroke: #ededed !important;
fill: #535353 !important;
}

View File

@ -125,7 +125,7 @@ EXTRA_DIST +=
# Files not to distribute
# for --rebuild-types in $(SCAN_OPTIONS), e.g. $(DOC_MODULE).types
# for --rebuild-sections in $(SCAN_OPTIONS) e.g. $(DOC_MODULE)-sections.txt
DISTCLEANFILES = $(DOC_MODULES).types
DISTCLEANFILES = $(DOC_MODULE).types
# Comment this out if you want 'make check' to test you doc status
# and run some sanity checks

View File

@ -50,7 +50,6 @@
<xi:include href="xml/shell-util.xml"/>
<xi:include href="xml/shell-mount-operation.xml"/>
<xi:include href="xml/shell-polkit-authentication-agent.xml"/>
<xi:include href="xml/shell-tp-client.xml"/>
</chapter>
<chapter id="object-tree">
<title>Object Hierarchy</title>

View File

@ -11,6 +11,7 @@ misc/config.js: misc/config.js.in Makefile
-e "s|[@]datadir@|$(datadir)|g" \
-e "s|[@]libexecdir@|$(libexecdir)|g" \
-e "s|[@]sysconfdir@|$(sysconfdir)|g" \
-e "s|[@]LIBMUTTER_API_VERSION@|$(LIBMUTTER_API_VERSION)|g" \
$< > $@
js_resource_files = $(shell $(GLIB_COMPILE_RESOURCES) --sourcedir=$(srcdir) --sourcedir=$(builddir) --generate-dependencies $(srcdir)/js-resources.gresource.xml)

View File

@ -5,6 +5,7 @@ const GLib = imports.gi.GLib;
const GObject = imports.gi.GObject;
const Gio = imports.gi.Gio;
const Gtk = imports.gi.Gtk;
const Gdk = imports.gi.Gdk;
const Pango = imports.gi.Pango;
const Format = imports.format;
@ -92,9 +93,11 @@ const Application = new Lang.Class({
widget = this._buildErrorUI(extension, e);
}
let dialog = new Gtk.Dialog({ use_header_bar: true,
modal: true,
title: extension.metadata.name });
let dialog = new Gtk.Window({ modal: !this._skipMainWindow,
type_hint: Gdk.WindowTypeHint.DIALOG });
dialog.set_titlebar(new Gtk.HeaderBar({ show_close_button: true,
title: extension.metadata.name,
visible: true }));
if (this._skipMainWindow) {
this.application.add_window(dialog);
@ -107,7 +110,7 @@ const Application = new Lang.Class({
}
dialog.set_default_size(600, 400);
dialog.get_content_area().add(widget);
dialog.add(widget);
dialog.show();
},
@ -143,17 +146,21 @@ const Application = new Lang.Class({
this._window = new Gtk.ApplicationWindow({ application: app,
window_position: Gtk.WindowPosition.CENTER });
this._window.set_size_request(800, 500);
this._window.set_default_size(800, 500);
this._titlebar = new Gtk.HeaderBar({ show_close_button: true,
title: _("GNOME Shell Extensions") });
title: _("Shell Extensions") });
this._window.set_titlebar(this._titlebar);
let scroll = new Gtk.ScrolledWindow({ hscrollbar_policy: Gtk.PolicyType.NEVER,
shadow_type: Gtk.ShadowType.IN,
halign: Gtk.Align.CENTER,
propagate_natural_width: true,
margin: 18 });
let killSwitch = new Gtk.Switch({ valign: Gtk.Align.CENTER });
this._titlebar.pack_end(killSwitch);
this._settings = new Gio.Settings({ schema_id: 'org.gnome.shell' });
this._settings.bind('disable-user-extensions', killSwitch, 'active',
Gio.SettingsBindFlags.DEFAULT |
Gio.SettingsBindFlags.INVERT_BOOLEAN);
let scroll = new Gtk.ScrolledWindow({ hscrollbar_policy: Gtk.PolicyType.NEVER });
this._window.add(scroll);
this._extensionSelector = new Gtk.ListBox({ selection_mode: Gtk.SelectionMode.NONE });
@ -246,6 +253,18 @@ const Application = new Lang.Class({
}
});
const DescriptionLabel = new Lang.Class({
Name: 'DescriptionLabel',
Extends: Gtk.Label,
vfunc_get_preferred_height_for_width: function(width) {
// Hack: Request the maximum height allowed by the line limit
if (this.lines > 0)
return this.parent(0);
return this.parent(width);
}
});
const ExtensionRow = new Lang.Class({
Name: 'ExtensionRow',
Extends: Gtk.ListBoxRow,
@ -264,6 +283,10 @@ const ExtensionRow = new Lang.Class({
Lang.bind(this, function() {
this._switch.sensitive = this._canEnable();
}));
this._settings.connect('changed::disable-user-extensions',
Lang.bind(this, function() {
this._switch.sensitive = this._canEnable();
}));
this._buildUI();
},
@ -272,7 +295,8 @@ const ExtensionRow = new Lang.Class({
let extension = ExtensionUtils.extensions[this.uuid];
let hbox = new Gtk.Box({ orientation: Gtk.Orientation.HORIZONTAL,
hexpand: true, margin: 12, spacing: 6 });
hexpand: true, margin_end: 24, spacing: 24,
margin: 12 });
this.add(hbox);
let vbox = new Gtk.Box({ orientation: Gtk.Orientation.VERTICAL,
@ -286,9 +310,9 @@ const ExtensionRow = new Lang.Class({
vbox.add(label);
let desc = extension.metadata.description.split('\n')[0];
label = new Gtk.Label({ label: desc,
ellipsize: Pango.EllipsizeMode.END,
halign: Gtk.Align.START });
label = new DescriptionLabel({ label: desc, wrap: true, lines: 2,
ellipsize: Pango.EllipsizeMode.END,
xalign: 0, yalign: 0 });
vbox.add(label);
let button = new Gtk.Button({ valign: Gtk.Align.CENTER,
@ -319,7 +343,8 @@ const ExtensionRow = new Lang.Class({
let extension = ExtensionUtils.extensions[this.uuid];
let checkVersion = !this._settings.get_boolean('disable-extension-version-validation');
return !(checkVersion && ExtensionUtils.isOutOfDate(extension));
return !this._settings.get_boolean('disable-user-extensions') &&
!(checkVersion && ExtensionUtils.isOutOfDate(extension));
},
_isEnabled: function() {

View File

@ -23,6 +23,12 @@ function FprintManager() {
g_object_path: '/net/reactivated/Fprint/Manager',
g_flags: (Gio.DBusProxyFlags.DO_NOT_LOAD_PROPERTIES) });
self.init(null);
try {
self.init(null);
} catch(e) {
log('Failed to connect to Fprint service: ' + e.message);
return null;
}
return self;
}

View File

@ -1225,7 +1225,7 @@ const LoginDialog = new Lang.Class({
},
addCharacter: function(unichar) {
this._authPrompt.addCharacter(unichar);
// Don't allow type ahead at the login screen
},
finish: function(onComplete) {

View File

@ -133,7 +133,7 @@ const ShellUserVerifier = new Lang.Class({
Lang.bind(this, this._updateDefaultService));
this._updateDefaultService();
this._fprintManager = new Fprint.FprintManager();
this._fprintManager = Fprint.FprintManager();
this._smartcardManager = SmartcardManager.getSmartcardManager();
// We check for smartcards right away, since an inserted smartcard
@ -293,7 +293,8 @@ const ShellUserVerifier = new Lang.Class({
_checkForFingerprintReader: function() {
this._haveFingerprintReader = false;
if (!this._settings.get_boolean(FINGERPRINT_AUTHENTICATION_KEY)) {
if (!this._settings.get_boolean(FINGERPRINT_AUTHENTICATION_KEY) ||
this._fprintManager == null) {
this._updateDefaultService();
return;
}

View File

@ -23,8 +23,10 @@
<file>misc/modemManager.js</file>
<file>misc/objectManager.js</file>
<file>misc/params.js</file>
<file>misc/permissionStore.js</file>
<file>misc/smartcardManager.js</file>
<file>misc/util.js</file>
<file>misc/weather.js</file>
<file>perf/core.js</file>
<file>perf/hwtest.js</file>
@ -72,6 +74,7 @@
<file>ui/osdMonitorLabeler.js</file>
<file>ui/overview.js</file>
<file>ui/overviewControls.js</file>
<file>ui/padOsd.js</file>
<file>ui/panel.js</file>
<file>ui/panelMenu.js</file>
<file>ui/pointerWatcher.js</file>
@ -116,6 +119,7 @@
<file>ui/status/brightness.js</file>
<file>ui/status/location.js</file>
<file>ui/status/keyboard.js</file>
<file>ui/status/nightLight.js</file>
<file>ui/status/network.js</file>
<file>ui/status/power.js</file>
<file>ui/status/rfkill.js</file>

View File

@ -15,3 +15,5 @@ const LOCALEDIR = '@datadir@/locale';
/* other standard directories */
const LIBEXECDIR = '@libexecdir@';
const SYSCONFDIR = '@sysconfdir@';
/* g-i package versions */
const LIBMUTTER_API_VERSION = '@LIBMUTTER_API_VERSION@'

View File

@ -6,10 +6,11 @@ const Lang = imports.lang;
const Mainloop = imports.mainloop;
const Signals = imports.signals;
let IBusCandidatePopup;
try {
var IBus = imports.gi.IBus;
_checkIBusVersion(1, 5, 2);
const IBusCandidatePopup = imports.ui.ibusCandidatePopup;
IBusCandidatePopup = imports.ui.ibusCandidatePopup;
} catch (e) {
var IBus = null;
log(e);

View File

@ -128,7 +128,8 @@ const KeyboardManager = new Lang.Class({
if (!found)
[, , id] = GnomeDesktop.get_input_source_from_locale(DEFAULT_LOCALE);
let [found, , , _layout, _variant] = this._xkbInfo.get_layout_info(id);
let _layout, _variant;
[found, , , _layout, _variant] = this._xkbInfo.get_layout_info(id);
if (found)
return { layout: _layout, variant: _variant };
else

View File

@ -0,0 +1,37 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
const Gio = imports.gi.Gio;
const PermissionStoreIface = '<node> \
<interface name="org.freedesktop.impl.portal.PermissionStore"> \
<method name="Lookup"> \
<arg name="table" type="s" direction="in"/> \
<arg name="id" type="s" direction="in"/> \
<arg name="permissions" type="a{sas}" direction="out"/> \
<arg name="data" type="v" direction="out"/> \
</method> \
<method name="Set"> \
<arg name="table" type="s" direction="in"/> \
<arg name="create" type="b" direction="in"/> \
<arg name="id" type="s" direction="in"/> \
<arg name="app_permissions" type="a{sas}" direction="in"/> \
<arg name="data" type="v" direction="in"/> \
</method> \
<signal name="Changed"> \
<arg name="table" type="s" direction="out"/> \
<arg name="id" type="s" direction="out"/> \
<arg name="deleted" type="b" direction="out"/> \
<arg name="data" type="v" direction="out"/> \
<arg name="permissions" type="a{sas}" direction="out"/> \
</signal> \
</interface> \
</node>';
const PermissionStoreProxy = Gio.DBusProxy.makeProxyWrapper(PermissionStoreIface);
function PermissionStore(initCallback, cancellable) {
return new PermissionStoreProxy(Gio.DBus.session,
'org.freedesktop.impl.portal.PermissionStore',
'/org/freedesktop/impl/portal/PermissionStore',
initCallback, cancellable);
};

View File

@ -1,9 +1,12 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
const Clutter = imports.gi.Clutter;
const Gettext = imports.gettext;
const Gio = imports.gi.Gio;
const GLib = imports.gi.GLib;
const Lang = imports.lang;
const Mainloop = imports.mainloop;
const Signals = imports.signals;
const Shell = imports.gi.Shell;
const St = imports.gi.St;
@ -161,6 +164,41 @@ function _handleSpawnError(command, err) {
Main.notifyError(title, err.message);
}
function formatTimeSpan(date) {
let now = GLib.DateTime.new_now_local();
let timespan = now.difference(date);
let minutesAgo = timespan / GLib.TIME_SPAN_MINUTE;
let hoursAgo = timespan / GLib.TIME_SPAN_HOUR;
let daysAgo = timespan / GLib.TIME_SPAN_DAY;
let weeksAgo = daysAgo / 7;
let monthsAgo = daysAgo / 30;
let yearsAgo = weeksAgo / 52;
if (minutesAgo < 5)
return _("Just now");
if (hoursAgo < 1)
return Gettext.ngettext("%d minute ago",
"%d minutes ago", minutesAgo).format(minutesAgo);
if (daysAgo < 1)
return Gettext.ngettext("%d hour ago",
"%d hours ago", hoursAgo).format(hoursAgo);
if (daysAgo < 2)
return _("Yesterday");
if (daysAgo < 15)
return Gettext.ngettext("%d day ago",
"%d days ago", daysAgo).format(daysAgo);
if (weeksAgo < 8)
return Gettext.ngettext("%d week ago",
"%d weeks ago", weeksAgo).format(weeksAgo);
if (yearsAgo < 1)
return Gettext.ngettext("%d month ago",
"%d months ago", monthsAgo).format(monthsAgo);
return Gettext.ngettext("%d year ago",
"%d years ago", yearsAgo).format(yearsAgo);
}
function formatTime(time, params) {
let date;
// HACK: The built-in Date type sucks at timezones, which we need for the
@ -398,3 +436,94 @@ function ensureActorVisibleInScrollView(scrollView, actor) {
time: SCROLL_TIME,
transition: 'easeOutQuad' });
}
const AppSettingsMonitor = new Lang.Class({
Name: 'AppSettingsMonitor',
_init: function(appId, schemaId) {
this._appId = appId;
this._schemaId = schemaId;
this._app = null;
this._settings = null;
this._handlers = [];
this._schemaSource = Gio.SettingsSchemaSource.get_default();
this._appSystem = Shell.AppSystem.get_default();
this._appSystem.connect('installed-changed',
Lang.bind(this, this._onInstalledChanged));
this._onInstalledChanged();
},
get available() {
return this._app != null && this._settings != null;
},
activateApp: function() {
if (this._app)
this._app.activate();
},
watchSetting: function(key, callback) {
let handler = { id: 0, key: key, callback: callback };
this._handlers.push(handler);
this._connectHandler(handler);
},
_connectHandler: function(handler) {
if (!this._settings || handler.id > 0)
return;
handler.id = this._settings.connect('changed::' + handler.key,
handler.callback);
handler.callback(this._settings, handler.key);
},
_disconnectHandler: function(handler) {
if (this._settings && handler.id > 0)
this._settings.disconnect(handler.id);
handler.id = 0;
},
_onInstalledChanged: function() {
let hadApp = (this._app != null);
this._app = this._appSystem.lookup_app(this._appId);
let haveApp = (this._app != null);
if (hadApp == haveApp)
return;
if (haveApp)
this._checkSettings();
else
this._setSettings(null);
},
_setSettings: function(settings) {
this._handlers.forEach((handler) => { this._disconnectHandler(handler); });
let hadSettings = (this._settings != null);
this._settings = settings;
let haveSettings = (this._settings != null);
this._handlers.forEach((handler) => { this._connectHandler(handler); });
if (hadSettings != haveSettings)
this.emit('available-changed');
},
_checkSettings: function() {
let schema = this._schemaSource.lookup(this._schemaId, true);
if (schema) {
this._setSettings(new Gio.Settings({ settings_schema: schema }));
} else if (this._app) {
Mainloop.timeout_add_seconds(1, () => {
this._checkSettings();
return GLib.SOURCE_REMOVE;
});
}
}
});
Signals.addSignalMethods(AppSettingsMonitor.prototype);

247
js/misc/weather.js Normal file
View File

@ -0,0 +1,247 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
const Geoclue = imports.gi.Geoclue;
const Gio = imports.gi.Gio;
const GLib = imports.gi.GLib;
const GWeather = imports.gi.GWeather;
const Lang = imports.lang;
const Signals = imports.signals;
const PermissionStore = imports.misc.permissionStore;
const Util = imports.misc.util;
// Minimum time between updates to show loading indication
const UPDATE_THRESHOLD = 10 * GLib.TIME_SPAN_MINUTE;
const WeatherClient = new Lang.Class({
Name: 'WeatherClient',
_init: function() {
this._loading = false;
this._locationValid = false;
this._lastUpdate = GLib.DateTime.new_from_unix_local(0);
this._autoLocationRequested = false;
this._mostRecentLocation = null;
this._gclueService = null;
this._gclueStarted = false;
this._gclueStarting = false;
this._gclueLocationChangedId = 0;
this._weatherAuthorized = false;
this._permStore = new PermissionStore.PermissionStore((proxy, error) => {
if (error) {
log('Failed to connect to permissionStore: ' + error.message);
return;
}
this._permStore.LookupRemote('gnome', 'geolocation', (res, error) => {
if (error)
log('Error looking up permission: ' + error.message);
let [perms, data] = error ? [{}, null] : res;
let params = ['gnome', 'geolocation', false, data, perms];
this._onPermStoreChanged(this._permStore, '', params);
});
});
this._permStore.connectSignal('Changed',
Lang.bind(this, this._onPermStoreChanged));
this._locationSettings = new Gio.Settings({ schema_id: 'org.gnome.system.location' });
this._locationSettings.connect('changed::enabled',
Lang.bind(this, this._updateAutoLocation));
this._world = GWeather.Location.get_world();
this._providers = GWeather.Provider.METAR |
GWeather.Provider.YR_NO |
GWeather.Provider.OWM;
this._weatherInfo = new GWeather.Info({ enabled_providers: 0 });
this._weatherInfo.connect_after('updated', () => {
this._lastUpdate = GLib.DateTime.new_now_local();
this.emit('changed');
});
this._weatherAppMon = new Util.AppSettingsMonitor('org.gnome.Weather.Application.desktop',
'org.gnome.Weather.Application');
this._weatherAppMon.connect('available-changed', () => { this.emit('changed'); });
this._weatherAppMon.watchSetting('automatic-location',
Lang.bind(this, this._onAutomaticLocationChanged));
this._weatherAppMon.watchSetting('locations',
Lang.bind(this, this._onLocationsChanged));
},
get available() {
return this._weatherAppMon.available;
},
get loading() {
return this._loading;
},
get hasLocation() {
return this._locationValid;
},
get info() {
return this._weatherInfo;
},
activateApp: function() {
this._weatherAppMon.activateApp();
},
update: function() {
if (!this._locationValid)
return;
let now = GLib.DateTime.new_now_local();
// Update without loading indication if the current info is recent enough
if (this._weatherInfo.is_valid() &&
now.difference(this._lastUpdate) < UPDATE_THRESHOLD)
this._weatherInfo.update();
else
this._loadInfo();
},
get _useAutoLocation() {
return this._autoLocationRequested &&
this._locationSettings.get_boolean('enabled') &&
this._weatherAuthorized;
},
_loadInfo: function() {
let id = this._weatherInfo.connect('updated', () => {
this._weatherInfo.disconnect(id);
this._loading = false;
});
this._loading = true;
this.emit('changed');
this._weatherInfo.update();
},
_locationsEqual: function(loc1, loc2) {
if (loc1 == loc2)
return true;
if (loc1 == null || loc2 == null)
return false;
return loc1.equal(loc2);
},
_setLocation: function(location) {
if (this._locationsEqual(this._weatherInfo.location, location))
return;
this._weatherInfo.abort();
this._weatherInfo.set_location(location);
this._locationValid = (location != null);
this._weatherInfo.set_enabled_providers(location ? this._providers : 0);
if (location)
this._loadInfo();
else
this.emit('changed');
},
_updateLocationMonitoring: function() {
if (this._useAutoLocation) {
if (this._gclueLocationChangedId != 0 || this._gclueService == null)
return;
this._gclueLocationChangedId =
this._gclueService.connect('notify::location',
Lang.bind(this, this._onGClueLocationChanged));
this._onGClueLocationChanged();
} else {
if (this._gclueLocationChangedId)
this._gclueService.disconnect(this._gclueLocationChangedId);
this._gclueLocationChangedId = 0;
}
},
_startGClueService: function() {
if (this._gclueStarting)
return;
this._gclueStarting = true;
Geoclue.Simple.new('org.gnome.Shell', Geoclue.AccuracyLevel.CITY, null,
(o, res) => {
try {
this._gclueService = Geoclue.Simple.new_finish(res);
} catch(e) {
log('Failed to connect to Geoclue2 service: ' + e.message);
this._setLocation(this._mostRecentLocation);
return;
}
this._gclueStarted = true;
this._gclueService.get_client().distance_threshold = 100;
this._updateLocationMonitoring();
});
},
_onGClueLocationChanged: function() {
let geoLocation = this._gclueService.location;
let location = GWeather.Location.new_detached(geoLocation.description,
null,
geoLocation.latitude,
geoLocation.longitude);
this._setLocation(location);
},
_onAutomaticLocationChanged: function(settings, key) {
let useAutoLocation = settings.get_boolean(key);
if (this._autoLocationRequested == useAutoLocation)
return;
this._autoLocationRequested = useAutoLocation;
this._updateAutoLocation();
},
_updateAutoLocation: function() {
this._updateLocationMonitoring();
if (this._useAutoLocation)
this._startGClueService();
else
this._setLocation(this._mostRecentLocation);
},
_onLocationsChanged: function(settings, key) {
let serialized = settings.get_value(key).deep_unpack().shift();
let mostRecentLocation = null;
if (serialized)
mostRecentLocation = this._world.deserialize(serialized);
if (this._locationsEqual(this._mostRecentLocation, mostRecentLocation))
return;
this._mostRecentLocation = mostRecentLocation;
if (!this._useAutoLocation || !this._gclueStarted)
this._setLocation(this._mostRecentLocation);
},
_onPermStoreChanged: function(proxy, sender, params) {
let [table, id, deleted, data, perms] = params;
if (table != 'gnome' || id != 'geolocation')
return;
let permission = perms['org.gnome.Weather.Application'] || ['NONE'];
let [accuracy] = permission;
this._weatherAuthorized = accuracy != 'NONE';
this._updateAutoLocation();
}
});
Signals.addSignalMethods(WeatherClient.prototype);

View File

@ -19,7 +19,15 @@ const PortalHelperResult = {
RECHECK: 2
};
const PortalHelperSecurityLevel = {
NOT_YET_DETERMINED: 0,
SECURE: 1,
INSECURE: 2
};
const INACTIVITY_TIMEOUT = 30000; //ms
const CONNECTIVITY_CHECK_HOST = 'nmcheck.gnome.org';
const CONNECTIVITY_CHECK_URI = 'http://' + CONNECTIVITY_CHECK_HOST;
const CONNECTIVITY_RECHECK_RATELIMIT_TIMEOUT = 30 * GLib.USEC_PER_SEC;
const HelperDBusInterface = '<node> \
@ -42,6 +50,71 @@ const HelperDBusInterface = '<node> \
</interface> \
</node>';
const PortalHeaderBar = new Lang.Class({
Name: 'PortalHeaderBar',
Extends: Gtk.HeaderBar,
_init: function() {
this.parent({ show_close_button: true });
// See ephy-title-box.c in epiphany for the layout
let vbox = new Gtk.Box({ orientation: Gtk.Orientation.VERTICAL,
spacing: 0 });
this.set_custom_title(vbox);
/* TRANSLATORS: this is the title of the wifi captive portal login window */
let titleLabel = new Gtk.Label({ label: _("Hotspot Login"),
wrap: false,
single_line_mode: true,
ellipsize: Pango.EllipsizeMode.END });
titleLabel.get_style_context().add_class('title');
vbox.add(titleLabel);
let hbox = new Gtk.Box({ orientation: Gtk.Orientation.HORIZONTAL,
spacing: 4,
halign: Gtk.Align.CENTER,
valign: Gtk.Align.BASELINE });
hbox.get_style_context().add_class('subtitle');
vbox.add(hbox);
this._lockImage = new Gtk.Image({ icon_size: Gtk.IconSize.MENU,
valign: Gtk.Align.BASELINE });
hbox.add(this._lockImage);
this.subtitleLabel = new Gtk.Label({ wrap: false,
single_line_mode: true,
ellipsize: Pango.EllipsizeMode.END,
valign: Gtk.Align.BASELINE,
selectable: true});
this.subtitleLabel.get_style_context().add_class('subtitle');
hbox.add(this.subtitleLabel);
vbox.show_all();
},
setSubtitle: function(label) {
this.subtitleLabel.set_text(label);
},
setSecurityIcon: function(securityLevel) {
switch (securityLevel) {
case PortalHelperSecurityLevel.NOT_YET_DETERMINED:
this._lockImage.hide();
break;
case PortalHelperSecurityLevel.SECURE:
this._lockImage.show();
this._lockImage.set_from_icon_name("channel-secure-symbolic", Gtk.IconSize.MENU);
this._lockImage.set_tooltip_text(null);
break;
case PortalHelperSecurityLevel.INSECURE:
this._lockImage.show();
this._lockImage.set_from_icon_name("channel-insecure-symbolic", Gtk.IconSize.MENU);
this._lockImage.set_tooltip_text(_('Your connection to this hotspot login is not secure. Passwords or other information you enter on this page can be viewed by people nearby.'));
break;
}
},
});
const PortalWindow = new Lang.Class({
Name: 'PortalWindow',
Extends: Gtk.ApplicationWindow,
@ -49,8 +122,14 @@ const PortalWindow = new Lang.Class({
_init: function(application, url, timestamp, doneCallback) {
this.parent({ application: application });
this.connect('delete-event', Lang.bind(this, this.destroyWindow));
this._headerBar = new PortalHeaderBar();
this._headerBar.setSecurityIcon(PortalHelperSecurityLevel.NOT_YET_DETERMINED);
this.set_titlebar(this._headerBar);
this._headerBar.show();
if (!url) {
url = 'http://www.gnome.org';
url = CONNECTIVITY_CHECK_URI;
this._originalUrlWasGnome = true;
} else {
this._originalUrlWasGnome = false;
@ -62,28 +141,37 @@ const PortalWindow = new Lang.Class({
this._lastRecheck = 0;
this._recheckAtExit = false;
this._webView = new WebKit.WebView();
this._webContext = WebKit.WebContext.new_ephemeral();
this._webContext.set_cache_model(WebKit.CacheModel.DOCUMENT_VIEWER);
this._webView = WebKit.WebView.new_with_context(this._webContext);
this._webView.connect('decide-policy', Lang.bind(this, this._onDecidePolicy));
this._webView.connect('load-changed', Lang.bind(this, this._onLoadChanged));
this._webView.connect('insecure-content-detected', Lang.bind(this, this._onInsecureContentDetected));
this._webView.connect('load-failed-with-tls-errors', Lang.bind(this, this._onLoadFailedWithTlsErrors));
this._webView.load_uri(url);
this._webView.connect('notify::title', Lang.bind(this, this._syncTitle));
this._syncTitle();
this._webView.connect('notify::uri', Lang.bind(this, this._syncUri));
this._syncUri();
this.add(this._webView);
this._webView.show();
this.set_size_request(600, 450);
this.maximize();
this.present_with_time(timestamp);
this.application.set_accels_for_action('app.quit', ['<Primary>q', '<Primary>w']);
},
_syncTitle: function() {
let title = this._webView.title;
destroyWindow: function() {
this.destroy();
},
if (title) {
this.title = title;
} else {
/* TRANSLATORS: this is the title of the wifi captive portal login
* window, until we know the title of the actual login page */
this.title = _("Web Authentication Redirect");
}
_syncUri: function() {
let uri = this._webView.uri;
if (uri)
this._headerBar.setSubtitle(GLib.uri_unescape_string(uri, null));
else
this._headerBar.setSubtitle('');
},
refresh: function() {
@ -99,8 +187,46 @@ const PortalWindow = new Lang.Class({
return false;
},
_onLoadChanged: function(view, loadEvent) {
if (loadEvent == WebKit.LoadEvent.STARTED) {
this._headerBar.setSecurityIcon(PortalHelperSecurityLevel.NOT_YET_DETERMINED);
} else if (loadEvent == WebKit.LoadEvent.COMMITTED) {
let tlsInfo = this._webView.get_tls_info();
let ret = tlsInfo[0];
let flags = tlsInfo[2];
if (ret && flags == 0)
this._headerBar.setSecurityIcon(PortalHelperSecurityLevel.SECURE);
else
this._headerBar.setSecurityIcon(PortalHelperSecurityLevel.INSECURE);
}
},
_onInsecureContentDetected: function () {
this._headerBar.setSecurityIcon(PortalHelperSecurityLevel.INSECURE);
},
_onLoadFailedWithTlsErrors: function (view, failingURI, certificate, errors) {
this._headerBar.setSecurityIcon(PortalHelperSecurityLevel.INSECURE);
let uri = new Soup.URI(failingURI);
this._webContext.allow_tls_certificate_for_host(certificate, uri.get_host());
this._webView.load_uri(failingURI);
return true;
},
_onDecidePolicy: function(view, decision, type) {
if (type == WebKit.PolicyDecisionType.NEW_WINDOW_ACTION) {
let navigationAction = decision.get_navigation_action();
if (navigationAction.is_user_gesture()) {
// Even though the portal asks for a new window,
// perform the navigation in the current one. Some
// portals open a window as their last login step and
// ignoring that window causes them to not let the
// user go through. We don't risk popups taking over
// the page because we check that the navigation is
// user initiated.
this._webView.load_request(navigationAction.get_request());
}
decision.ignore();
return true;
}
@ -112,12 +238,12 @@ const PortalWindow = new Lang.Class({
let uri = new Soup.URI(request.get_uri());
if (!uri.host_equal(this._uri) && this._originalUrlWasGnome) {
if (uri.get_host() == 'www.gnome.org' && this._everSeenRedirect) {
if (uri.get_host() == CONNECTIVITY_CHECK_HOST && this._everSeenRedirect) {
// Yay, we got to gnome!
decision.ignore();
this._doneCallback(PortalHelperResult.COMPLETED);
return true;
} else if (uri.get_host() != 'www.gnome.org') {
} else if (uri.get_host() != CONNECTIVITY_CHECK_HOST) {
this._everSeenRedirect = true;
}
}
@ -166,6 +292,10 @@ const WebPortalHelper = new Lang.Class({
this._dbusImpl = Gio.DBusExportedObject.wrapJSObject(HelperDBusInterface, this);
this._queue = [];
let action = new Gio.SimpleAction({ name: 'quit' });
action.connect('activate', () => { this.active_window.destroyWindow(); });
this.add_action(action);
},
vfunc_dbus_register: function(connection, path) {
@ -197,7 +327,7 @@ const WebPortalHelper = new Lang.Class({
if (obj.connection == connection) {
if (obj.window)
obj.window.destroy();
obj.window.destroyWindow();
this._queue.splice(i, 1);
break;
}
@ -239,6 +369,11 @@ function initEnvironment() {
function main(argv) {
initEnvironment();
if (!WebKit.WebContext.new_ephemeral) {
log('WebKitGTK 2.16 is required for the portal-helper, see https://bugzilla.gnome.org/show_bug.cgi?id=780453');
return 1;
}
Gettext.bindtextdomain(Config.GETTEXT_PACKAGE, Config.LOCALEDIR);
Gettext.textdomain(Config.GETTEXT_PACKAGE);

View File

@ -33,10 +33,9 @@ const AppIconMode = {
};
function _createWindowClone(window, size) {
let windowTexture = window.get_texture();
let [width, height] = windowTexture.get_size();
let [width, height] = window.get_size();
let scale = Math.min(1.0, size / width, size / height);
return new Clutter.Clone({ source: windowTexture,
return new Clutter.Clone({ source: window,
width: width * scale,
height: height * scale,
x_align: Clutter.ActorAlign.CENTER,

View File

@ -67,7 +67,7 @@ const Animation = new Lang.Class({
},
_animationsLoaded: function() {
this._isLoaded = true;
this._isLoaded = this._animations.get_n_children() > 0;
if (this._isPlaying)
this.play();

View File

@ -210,6 +210,14 @@ const BaseAppView = new Lang.Class({
},
animate: function(animationDirection, onComplete) {
if (onComplete) {
let animationDoneId = this._grid.connect('animation-done', Lang.bind(this,
function () {
this._grid.disconnect(animationDoneId);
onComplete();
}));
}
if (animationDirection == IconGrid.AnimationDirection.IN) {
let toAnimate = this._grid.actor.connect('notify::allocation', Lang.bind(this,
function() {
@ -225,14 +233,6 @@ const BaseAppView = new Lang.Class({
} else {
this._doSpringAnimation(animationDirection);
}
if (onComplete) {
let animationDoneId = this._grid.connect('animation-done', Lang.bind(this,
function () {
this._grid.disconnect(animationDoneId);
onComplete();
}));
}
},
animateSwitch: function(animationDirection) {
@ -899,6 +899,8 @@ const ControlsBoxLayout = Lang.Class({
const ViewStackLayout = new Lang.Class({
Name: 'ViewStackLayout',
Extends: Clutter.BinLayout,
Signals: { 'allocated-size-changed': { param_types: [GObject.TYPE_INT,
GObject.TYPE_INT] } },
vfunc_allocate: function (actor, box, flags) {
let availWidth = box.x2 - box.x1;
@ -909,7 +911,6 @@ const ViewStackLayout = new Lang.Class({
this.parent(actor, box, flags);
}
});
Signals.addSignalMethods(ViewStackLayout.prototype);
const AppDisplay = new Lang.Class({
Name: 'AppDisplay',
@ -1010,7 +1011,7 @@ const AppDisplay = new Lang.Class({
},
animate: function(animationDirection, onComplete) {
let currentView = this._views[global.settings.get_uint('app-picker-view')].view;
let currentView = this._views.filter(v => v.control.has_style_pseudo_class('checked')).pop().view;
// Animate controls opacity using iconGrid animation time, since
// it will be the time the AllView or FrequentView takes to show

View File

@ -10,8 +10,10 @@ const RENAMED_DESKTOP_IDS = {
'baobab.desktop': 'org.gnome.baobab.desktop',
'cheese.desktop': 'org.gnome.Cheese.desktop',
'dconf-editor.desktop': 'ca.desrt.dconf-editor.desktop',
'epiphany.desktop': 'org.gnome.Epiphany.desktop',
'file-roller.desktop': 'org.gnome.FileRoller.desktop',
'gcalctool.desktop': 'gnome-calculator.desktop',
'gcalctool.desktop': 'org.gnome.Calculator.desktop',
'geary.desktop': 'org.gnome.Geary.desktop',
'gedit.desktop': 'org.gnome.gedit.desktop',
'glchess.desktop': 'gnome-chess.desktop',
'glines.desktop': 'five-or-more.desktop',
@ -19,6 +21,7 @@ const RENAMED_DESKTOP_IDS = {
'gnibbles.desktop': 'org.gnome.Nibbles.desktop',
'gnobots2.desktop': 'gnome-robots.desktop',
'gnome-boxes.desktop': 'org.gnome.Boxes.desktop',
'gnome-calculator.desktop': 'org.gnome.Calculator.desktop',
'gnome-clocks.desktop': 'org.gnome.clocks.desktop',
'gnome-contacts.desktop': 'org.gnome.Contacts.desktop',
'gnome-documents.desktop': 'org.gnome.Documents.desktop',
@ -56,12 +59,14 @@ const AppFavorites = new Lang.Class({
reload: function() {
let ids = global.settings.get_strv(this.FAVORITE_APPS_KEY);
let appSys = Shell.AppSystem.get_default();
// Map old desktop file names to the current ones
let updated = false;
ids = ids.map(function (id) {
let newId = RENAMED_DESKTOP_IDS[id];
if (newId !== undefined) {
if (newId !== undefined &&
appSys.lookup_app(newId) != null) {
updated = true;
return newId;
}
@ -71,7 +76,6 @@ const AppFavorites = new Lang.Class({
if (updated)
global.settings.set_strv(this.FAVORITE_APPS_KEY, ids);
let appSys = Shell.AppSystem.get_default();
let apps = ids.map(function (id) {
return appSys.lookup_app(id);
}).filter(function (app) {

View File

@ -142,7 +142,6 @@ const BackgroundCache = new Lang.Class({
Name: 'BackgroundCache',
_init: function() {
this._pendingFileLoads = [];
this._fileMonitors = {};
this._backgroundSources = {};
this._animations = {};
@ -167,7 +166,8 @@ const BackgroundCache = new Lang.Class({
settingsSchema: null,
onLoaded: null });
if (this._animations[params.settingsSchema] && _fileEqual0(this._animationFile, params.file)) {
let animation = this._animations[params.settingsSchema];
if (animation && _fileEqual0(animation.file, params.file)) {
if (params.onLoaded) {
let id = GLib.idle_add(GLib.PRIORITY_DEFAULT, Lang.bind(this, function() {
params.onLoaded(this._animations[params.settingsSchema]);
@ -178,7 +178,7 @@ const BackgroundCache = new Lang.Class({
return;
}
let animation = new Animation({ file: params.file });
animation = new Animation({ file: params.file });
animation.load(Lang.bind(this, function() {
this._animations[params.settingsSchema] = animation;
@ -255,7 +255,8 @@ const Background = new Lang.Class({
this._loadAnimation(this._animation.file);
}));
LoginManager.getLoginManager().connect('prepare-for-sleep',
let loginManager = LoginManager.getLoginManager();
this._prepareForSleepId = loginManager.connect('prepare-for-sleep',
(lm, aboutToSuspend) => {
if (aboutToSuspend)
return;
@ -284,6 +285,10 @@ const Background = new Lang.Class({
this._clock.disconnect(this._timezoneChangedId);
this._timezoneChangedId = 0;
if (this._prepareForSleepId != 0)
LoginManager.getLoginManager().disconnect(this._prepareForSleepId);
this._prepareForSleepId = 0;
if (this._settingsChangedSignalId != 0)
this._settings.disconnect(this._settingsChangedSignalId);
this._settingsChangedSignalId = 0;
@ -377,11 +382,9 @@ const Background = new Lang.Class({
let cache = Meta.BackgroundImageCache.get_default();
let numPendingImages = files.length;
let images = [];
for (let i = 0; i < files.length; i++) {
this._watchFile(files[i]);
let image = cache.load(files[i]);
images.push(image);
if (image.is_loaded()) {
numPendingImages--;
if (numPendingImages == 0)

View File

@ -20,7 +20,7 @@ const MSECS_IN_DAY = 24 * 60 * 60 * 1000;
const SHOW_WEEKDATE_KEY = 'show-weekdate';
const ELLIPSIS_CHAR = '\u2026';
const MESSAGE_ICON_SIZE = 32;
const MESSAGE_ICON_SIZE = 16;
// alias to prevent xgettext from picking up strings translated in GTK+
const gtk30_ = Gettext_gtk30.gettext;
@ -706,6 +706,14 @@ const EventMessage = new Lang.Class({
this._date = date;
this.parent(this._formatEventTime(), event.summary);
this._icon = new St.Icon({ icon_name: 'x-office-calendar-symbolic' });
this.setIcon(this._icon);
this.actor.connect('style-changed', () => {
let iconVisible = this.actor.get_parent().has_style_pseudo_class('first-child');
this._icon.opacity = (iconVisible ? 255 : 0);
});
},
_formatEventTime: function() {
@ -811,7 +819,16 @@ const EventsSection = new Lang.Class({
this._desktopSettings.connect('changed', Lang.bind(this, this._reloadEvents));
this._eventSource = new EmptyEventSource();
this.parent('');
this.parent();
this._title = new St.Button({ style_class: 'events-section-title',
label: '',
x_align: St.Align.START,
can_focus: true });
this.actor.insert_child_below(this._title, null);
this._title.connect('clicked', Lang.bind(this, this._onTitleClicked));
this._title.connect('key-focus-in', Lang.bind(this, this._onKeyFocusIn));
Shell.AppSystem.get_default().connect('installed-changed',
Lang.bind(this, this._appInstalledChanged));
@ -832,10 +849,10 @@ const EventsSection = new Lang.Class({
},
_updateTitle: function() {
if (isToday(this._date)) {
this._title.label = _("Events");
this._title.visible = !isToday(this._date);
if (!this._title.visible)
return;
}
let dayFormat;
let now = new Date();
@ -897,7 +914,8 @@ const EventsSection = new Lang.Class({
},
_onTitleClicked: function() {
this.parent();
Main.overview.hide();
Main.panel.closeCalendar();
let app = this._getCalendarApp();
if (app.get_id() == 'evolution.desktop')
@ -928,7 +946,7 @@ const NotificationSection = new Lang.Class({
Extends: MessageList.MessageListSection,
_init: function() {
this.parent(_("Notifications"));
this.parent();
this._sources = new Map();
this._nUrgent = 0;
@ -946,10 +964,14 @@ const NotificationSection = new Lang.Class({
!Main.sessionMode.isGreeter;
},
_createTimeLabel: function() {
let label = Util.createTimeLabel(new Date());
label.style_class = 'event-time',
label.x_align = Clutter.ActorAlign.END;
_createTimeLabel: function(datetime) {
let label = new St.Label({ style_class: 'event-time',
x_align: Clutter.ActorAlign.START,
y_align: Clutter.ActorAlign.END });
label.connect('notify::mapped', () => {
if (label.mapped)
label.text = Util.formatTimeSpan(datetime);
});
return label;
},
@ -970,13 +992,13 @@ const NotificationSection = new Lang.Class({
_onNotificationAdded: function(source, notification) {
let message = new NotificationMessage(notification);
message.setSecondaryActor(this._createTimeLabel());
message.setSecondaryActor(this._createTimeLabel(notification.datetime));
let isUrgent = notification.urgency == MessageTray.Urgency.CRITICAL;
let updatedId = notification.connect('updated', Lang.bind(this,
function() {
message.setSecondaryActor(this._createTimeLabel());
message.setSecondaryActor(this._createTimeLabel(notification.datetime));
this.moveMessage(message, isUrgent ? 0 : this._nUrgent, this.actor.mapped);
}));
let destroyId = notification.connect('destroy', Lang.bind(this,
@ -1017,26 +1039,8 @@ const NotificationSection = new Lang.Class({
message.notification.acknowledged = true;
},
_onTitleClicked: function() {
this.parent();
let app = Shell.AppSystem.get_default().lookup_app('gnome-notifications-panel.desktop');
if (!app) {
log('Settings panel for desktop file ' + desktopFile + ' could not be loaded!');
return;
}
app.activate();
},
_shouldShow: function() {
return !this.empty && isToday(this._date);
},
_sync: function() {
this.parent();
this._title.reactive = Main.sessionMode.allowSettings;
}
});
@ -1098,12 +1102,26 @@ const CalendarMessageList = new Lang.Class({
this._placeholder = new Placeholder();
this.actor.add_actor(this._placeholder.actor);
let box = new St.BoxLayout({ vertical: true,
x_expand: true, y_expand: true });
this.actor.add_actor(box);
this._scrollView = new St.ScrollView({ style_class: 'vfade',
overlay_scrollbars: true,
x_expand: true, y_expand: true,
x_fill: true, y_fill: true });
this._scrollView.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC);
this.actor.add_actor(this._scrollView);
box.add_actor(this._scrollView);
this._clearButton = new St.Button({ style_class: 'message-list-clear-button button',
label: _("Clear All"),
can_focus: true });
this._clearButton.set_x_align(Clutter.ActorAlign.END);
this._clearButton.connect('clicked', () => {
let sections = [...this._sections.keys()];
sections.forEach((s) => { s.clear(); });
});
box.add_actor(this._clearButton);
this._sectionList = new St.BoxLayout({ style_class: 'message-list-sections',
vertical: true,
@ -1129,6 +1147,7 @@ const CalendarMessageList = new Lang.Class({
destroyId: 0,
visibleId: 0,
emptyChangedId: 0,
canClearChangedId: 0,
keyFocusId: 0
};
obj.destroyId = section.actor.connect('destroy', Lang.bind(this,
@ -1139,6 +1158,8 @@ const CalendarMessageList = new Lang.Class({
Lang.bind(this, this._sync));
obj.emptyChangedId = section.connect('empty-changed',
Lang.bind(this, this._sync));
obj.canClearChangedId = section.connect('can-clear-changed',
Lang.bind(this, this._sync));
obj.keyFocusId = section.connect('key-focus-in',
Lang.bind(this, this._onKeyFocusIn));
@ -1152,6 +1173,7 @@ const CalendarMessageList = new Lang.Class({
section.actor.disconnect(obj.destroyId);
section.actor.disconnect(obj.visibleId);
section.disconnect(obj.emptyChangedId);
section.disconnect(obj.canClearChangedId);
section.disconnect(obj.keyFocusId);
this._sections.delete(section);
@ -1172,10 +1194,16 @@ const CalendarMessageList = new Lang.Class({
if (!visible)
return;
let showPlaceholder = sections.every(function(s) {
let empty = sections.every(function(s) {
return s.empty || !s.actor.visible;
});
this._placeholder.actor.visible = showPlaceholder;
this._placeholder.actor.visible = empty;
this._clearButton.visible = !empty;
let canClear = sections.some(function(s) {
return s.canClear && s.actor.visible;
});
this._clearButton.reactive = canClear;
},
setEventSource: function(eventSource) {

View File

@ -615,6 +615,14 @@ const NetworkAgent = new Lang.Class({
this._vpnRequests = { };
this._notifications = { };
this._pluginDir = Gio.file_new_for_path(GLib.build_filenamev([Config.SYSCONFDIR, 'NetworkManager/VPN']));
try {
let monitor = this._pluginDir.monitor(Gio.FileMonitorFlags.NONE, null);
monitor.connect('changed', () => { this._vpnCacheBuilt = false; });
} catch(e) {
log('Failed to create monitor for VPN plugin dir: ' + e.message);
}
this._native.connect('new-request', Lang.bind(this, this._newRequest));
this._native.connect('cancel-request', Lang.bind(this, this._cancelRequest));
@ -765,9 +773,8 @@ const NetworkAgent = new Lang.Class({
this._vpnCacheBuilt = true;
this._vpnBinaries = { };
let dir = Gio.file_new_for_path(GLib.build_filenamev([Config.SYSCONFDIR, 'NetworkManager/VPN']));
try {
let fileEnum = dir.enumerate_children('standard::name', Gio.FileQueryInfoFlags.NONE, null);
let fileEnum = this._pluginDir.enumerate_children('standard::name', Gio.FileQueryInfoFlags.NONE, null);
let info;
while ((info = fileEnum.next_file(null))) {
@ -777,7 +784,7 @@ const NetworkAgent = new Lang.Class({
try {
let keyfile = new GLib.KeyFile();
keyfile.load_from_file(dir.get_child(name).get_path(), GLib.KeyFileFlags.NONE);
keyfile.load_from_file(this._pluginDir.get_child(name).get_path(), GLib.KeyFileFlags.NONE);
let service = keyfile.get_string('VPN Connection', 'service');
let binary = keyfile.get_string('GNOME', 'auth-dialog');
let externalUIMode = false;
@ -810,7 +817,7 @@ const NetworkAgent = new Lang.Class({
}
} catch(e) {
log('Error \'%s\' while processing VPN keyfile \'%s\''.
format(e.message, dir.get_child(name).get_path()));
format(e.message, this._pluginDir.get_child(name).get_path()));
continue;
}
}

View File

@ -298,7 +298,7 @@ const AuthenticationDialog = new Lang.Class({
* requested authentication was not gained; this can happen
* because of an authentication error (like invalid password),
* for instance. */
this._errorMessageLabel.set_text(_("Sorry, that didn\'t work. Please try again."));
this._errorMessageLabel.set_text(_("Sorry, that didnt work. Please try again."));
this._errorMessageLabel.show();
this._infoMessageLabel.hide();
this._nullMessageLabel.hide();

View File

@ -6,11 +6,17 @@ const GLib = imports.gi.GLib;
const Gtk = imports.gi.Gtk;
const Lang = imports.lang;
const Mainloop = imports.mainloop;
const Shell = imports.gi.Shell;
const Signals = imports.signals;
const St = imports.gi.St;
const Tpl = imports.gi.TelepathyLogger;
const Tp = imports.gi.TelepathyGLib;
var Tpl = null;
var Tp = null;
try {
Tpl = imports.gi.TelepathyLogger;
Tp = imports.gi.TelepathyGLib;
} catch(e) {
log('Telepathy is not available, chat integration will be disabled.');
}
const History = imports.misc.history;
const Main = imports.ui.main;
@ -20,6 +26,8 @@ const Params = imports.misc.params;
const PopupMenu = imports.ui.popupMenu;
const Util = imports.misc.util;
const HAVE_TP = (Tp != null && Tpl != null);
// See Notification.appendMessage
const SCROLLBACK_IMMEDIATE_TIME = 3 * 60; // 3 minutes
const SCROLLBACK_RECENT_TIME = 15 * 60; // 15 minutes
@ -71,8 +79,43 @@ function makeMessageFromTplEvent(event) {
};
}
const TelepathyClient = new Lang.Class({
const TelepathyComponent = new Lang.Class({
Name: 'TelepathyComponent',
_init: function() {
this._client = null;
if (!HAVE_TP)
return; // Telepathy isn't available
this._client = new TelepathyClient();
},
enable: function() {
if (!this._client)
return;
try {
this._client.register();
} catch (e) {
throw new Error('Couldn\'t register Telepathy client. Error: \n' + e);
}
if (!this._client.account_manager.is_prepared(Tp.AccountManager.get_feature_quark_core()))
this._client.account_manager.prepare_async(null, null);
},
disable: function() {
if (!this._client)
return;
this._client.unregister();
}
});
const TelepathyClient = HAVE_TP ? new Lang.Class({
Name: 'TelepathyClient',
Extends: Tp.BaseClient,
_init: function() {
// channel path -> ChatSource
@ -97,39 +140,28 @@ const TelepathyClient = new Lang.Class({
// channel matching its filters is detected.
// The second argument, recover, means _observeChannels will be run
// for any existing channel as well.
this._tpClient = new Shell.TpClient({ name: 'GnomeShell',
account_manager: this._accountManager,
uniquify_name: true });
this._tpClient.set_observe_channels_func(
Lang.bind(this, this._observeChannels));
this._tpClient.set_approve_channels_func(
Lang.bind(this, this._approveChannels));
this._tpClient.set_handle_channels_func(
Lang.bind(this, this._handleChannels));
this.parent({ name: 'GnomeShell',
account_manager: this._accountManager,
uniquify_name: true });
// We only care about single-user text-based chats
let filter = {};
filter[Tp.PROP_CHANNEL_CHANNEL_TYPE] = Tp.IFACE_CHANNEL_TYPE_TEXT;
filter[Tp.PROP_CHANNEL_TARGET_HANDLE_TYPE] = Tp.HandleType.CONTACT;
this.set_observer_recover(true);
this.add_observer_filter(filter);
this.add_approver_filter(filter);
this.add_handler_filter(filter);
// Allow other clients (such as Empathy) to pre-empt our channels if
// needed
this._tpClient.set_delegated_channels_callback(
this.set_delegated_channels_callback(
Lang.bind(this, this._delegatedChannelsCb));
},
enable: function() {
try {
this._tpClient.register();
} catch (e) {
throw new Error('Couldn\'t register Telepathy client. Error: \n' + e);
}
if (!this._accountManager.is_prepared(Tp.AccountManager.get_feature_quark_core()))
this._accountManager.prepare_async(null, null);
},
disable: function() {
this._tpClient.unregister();
},
_observeChannels: function(observer, account, conn, channels,
dispatchOp, requests, context) {
vfunc_observe_channels: function(account, conn, channels,
dispatchOp, requests, context) {
let len = channels.length;
for (let i = 0; i < len; i++) {
let channel = channels[i];
@ -153,7 +185,7 @@ const TelepathyClient = new Lang.Class({
if (this._chatSources[channel.get_object_path()])
return;
let source = new ChatSource(account, conn, channel, contact, this._tpClient);
let source = new ChatSource(account, conn, channel, contact, this);
this._chatSources[channel.get_object_path()] = source;
source.connect('destroy', Lang.bind(this,
@ -162,8 +194,8 @@ const TelepathyClient = new Lang.Class({
}));
},
_handleChannels: function(handler, account, conn, channels,
requests, user_action_time, context) {
vfunc_handle_channels: function(account, conn, channels, requests,
user_action_time, context) {
this._handlingChannels(account, conn, channels, true);
context.accept();
},
@ -193,7 +225,7 @@ const TelepathyClient = new Lang.Class({
// Telepathy spec states that handlers must foreground channels
// in HandleChannels calls which are already being handled.
if (notify && this._tpClient.is_handling_channel(channel)) {
if (notify && this.is_handling_channel(channel)) {
// We are already handling the channel, display the source
let source = this._chatSources[channel.get_object_path()];
if (source)
@ -202,8 +234,8 @@ const TelepathyClient = new Lang.Class({
}
},
_approveChannels: function(approver, account, conn, channels,
dispatchOp, context) {
vfunc_add_dispatch_operation: function(account, conn, channels,
dispatchOp, context) {
let channel = channels[0];
let chanType = channel.get_channel_type();
@ -230,7 +262,7 @@ const TelepathyClient = new Lang.Class({
}
// Approve private text channels right away as we are going to handle it
dispatchOp.claim_with_async(this._tpClient, Lang.bind(this, function(dispatchOp, result) {
dispatchOp.claim_with_async(this, Lang.bind(this, function(dispatchOp, result) {
try {
dispatchOp.claim_with_finish(result);
this._handlingChannels(account, conn, [channel], false);
@ -246,7 +278,7 @@ const TelepathyClient = new Lang.Class({
// Nothing to do as we don't make a distinction between observed and
// handled channels.
},
});
}) : null;
const ChatSource = new Lang.Class({
Name: 'ChatSource',
@ -660,7 +692,9 @@ const ChatNotification = new Lang.Class({
}
if (message.direction == NotificationDirection.RECEIVED)
this.update(this.source.title, messageBody, { bannerMarkup: true });
this.update(this.source.title, messageBody,
{ datetime: GLib.DateTime.new_from_unix_local (message.timestamp),
bannerMarkup: true });
let group = (message.direction == NotificationDirection.RECEIVED ?
'received' : 'sent');
@ -962,4 +996,4 @@ const ChatNotificationBanner = new Lang.Class({
}
});
const Component = TelepathyClient;
const Component = TelepathyComponent;

View File

@ -8,6 +8,7 @@ const Gtk = imports.gi.Gtk;
const GWeather = imports.gi.GWeather;
const Lang = imports.lang;
const Mainloop = imports.mainloop;
const Pango = imports.gi.Pango;
const Cairo = imports.cairo;
const Clutter = imports.gi.Clutter;
const Shell = imports.gi.Shell;
@ -20,6 +21,7 @@ const Main = imports.ui.main;
const PanelMenu = imports.ui.panelMenu;
const PopupMenu = imports.ui.popupMenu;
const Calendar = imports.ui.calendar;
const Weather = imports.misc.weather;
function _isToday(date) {
let now = new Date();
@ -36,7 +38,7 @@ const TodayButton = new Lang.Class({
// on the current date can be confusing. So don't make the button reactive
// until the selected date changes.
this.actor = new St.Button({ style_class: 'datemenu-today-button',
x_align: St.Align.START,
x_expand: true, x_align: St.Align.START,
can_focus: true,
reactive: false
});
@ -77,7 +79,7 @@ const TodayButton = new Lang.Class({
* below the time in the shell; it should combine the weekday and the
* date, e.g. "Tuesday February 17 2015".
*/
let dateFormat = Shell.util_translate_time_string (N_("%A %B %e %Y"));
dateFormat = Shell.util_translate_time_string (N_("%A %B %e %Y"));
this.actor.accessible_name = date.toLocaleFormat(dateFormat);
}
});
@ -87,9 +89,7 @@ const WorldClocksSection = new Lang.Class({
_init: function() {
this._clock = new GnomeDesktop.WallClock();
this._settings = null;
this._clockNotifyId = 0;
this._changedId = 0;
this._locations = [];
@ -98,8 +98,7 @@ const WorldClocksSection = new Lang.Class({
can_focus: true });
this.actor.connect('clicked', Lang.bind(this,
function() {
let app = this._getClockApp();
app.activate();
this._clockAppMon.activateApp();
Main.overview.hide();
Main.panel.closeCalendar();
@ -112,40 +111,25 @@ const WorldClocksSection = new Lang.Class({
this.actor.child = this._grid;
Shell.AppSystem.get_default().connect('installed-changed',
Lang.bind(this, this._sync));
this._clockAppMon = new Util.AppSettingsMonitor('org.gnome.clocks.desktop',
'org.gnome.clocks');
this._clockAppMon.connect('available-changed',
Lang.bind(this, this._sync));
this._clockAppMon.watchSetting('world-clocks',
Lang.bind(this, this._clocksChanged));
this._sync();
},
_getClockApp: function() {
return Shell.AppSystem.get_default().lookup_app('org.gnome.clocks.desktop');
},
_sync: function() {
this.actor.visible = (this._getClockApp() != null);
if (this.actor.visible) {
if (!this._settings) {
this._settings = new Gio.Settings({ schema_id: 'org.gnome.clocks' });
this._changedId =
this._settings.connect('changed::world-clocks',
Lang.bind(this, this._clocksChanged));
this._clocksChanged();
}
} else {
if (this._settings)
this._settings.disconnect(this._changedId);
this._settings = null;
this._changedId = 0;
}
this.actor.visible = this._clockAppMon.available;
},
_clocksChanged: function() {
_clocksChanged: function(settings) {
this._grid.destroy_all_children();
this._locations = [];
let world = GWeather.Location.get_world();
let clocks = this._settings.get_value('world-clocks').deep_unpack();
let clocks = settings.get_value('world-clocks').deep_unpack();
for (let i = 0; i < clocks.length; i++) {
let l = world.deserialize(clocks[i].location);
this._locations.push({ location: l });
@ -210,6 +194,136 @@ const WorldClocksSection = new Lang.Class({
}
});
const WeatherSection = new Lang.Class({
Name: 'WeatherSection',
_init: function() {
this._weatherClient = new Weather.WeatherClient();
this.actor = new St.Button({ style_class: 'weather-button',
x_fill: true,
can_focus: true });
this.actor.connect('clicked', () => {
this._weatherClient.activateApp();
Main.overview.hide();
Main.panel.closeCalendar();
});
this.actor.connect('notify::mapped', () => {
if (this.actor.mapped)
this._weatherClient.update();
});
let box = new St.BoxLayout({ style_class: 'weather-box',
vertical: true });
this.actor.child = box;
box.add_child(new St.Label({ style_class: 'weather-header',
x_align: Clutter.ActorAlign.START,
text: _("Weather") }));
this._conditionsLabel = new St.Label({ style_class: 'weather-conditions',
x_align: Clutter.ActorAlign.START });
this._conditionsLabel.clutter_text.ellipsize = Pango.EllipsizeMode.NONE;
this._conditionsLabel.clutter_text.line_wrap = true;
box.add_child(this._conditionsLabel);
this._weatherClient.connect('changed', Lang.bind(this, this._sync));
this._sync();
},
_getSummary: function(info) {
let summary = info.get_conditions();
if (summary == '-')
return info.get_sky();
return summary;
},
_sameSummary: function(info1, info2) {
let [ok1, phenom1, qualifier1] = info1.get_value_conditions();
let [ok2, phenom2, qualifier2] = info2.get_value_conditions();
if (ok1 || ok2)
return ok1 == ok2 && phenom1 == phenom2 && qualifier1 == qualifier2;
let [, sky1] = info1.get_value_sky();
let [, sky2] = info2.get_value_sky();
return sky1 == sky2;
},
_getSummaryText: function() {
let info = this._weatherClient.info;
let forecasts = info.get_forecast_list();
if (forecasts.length == 0) // No forecasts, just current conditions
return '%s.'.format(this._getSummary(info));
let current = info;
let summaries = [this._getSummary(info)];
for (let i = 0; i < forecasts.length; i++) {
let [ok, timestamp] = forecasts[i].get_value_update();
if (!_isToday(new Date(timestamp * 1000)))
continue; // Ignore forecasts from other days
if (this._sameSummary(current, forecasts[i]))
continue; // Ignore consecutive runs of equal summaries
current = forecasts[i];
if (summaries.push(this._getSummary(current)) == 3)
break; // Use a maximum of three summaries
}
let fmt;
switch(summaries.length) {
/* Translators: %s is a weather condition like "Clear sky"; see
libgweather for the possible condition strings. If at all
possible, the sentence should match the grammatical case etc. of
the inserted conditions. */
case 1: fmt = _("%s all day."); break;
/* Translators: %s is a weather condition like "Clear sky"; see
libgweather for the possible condition strings. If at all
possible, the sentence should match the grammatical case etc. of
the inserted conditions. */
case 2: fmt = _("%s, then %s later."); break;
/* Translators: %s is a weather condition like "Clear sky"; see
libgweather for the possible condition strings. If at all
possible, the sentence should match the grammatical case etc. of
the inserted conditions. */
case 3: fmt = _("%s, then %s, followed by %s later."); break;
}
return String.prototype.format.apply(fmt, summaries);
},
_getLabelText: function() {
if (!this._weatherClient.hasLocation)
return _("Select a location…");
if (this._weatherClient.loading)
return _("Loading…");
let info = this._weatherClient.info;
if (info.is_valid())
return this._getSummaryText() + ' ' +
/* Translators: %s is a temperature with unit, e.g. "23℃" */
_("Feels like %s.").format(info.get_apparent());
if (info.network_error())
return _("Go online for weather information");
return _("Weather information is currently unavailable");
},
_sync: function() {
this.actor.visible = this._weatherClient.available;
if (!this.actor.visible)
return;
this._conditionsLabel.text = this._getLabelText();
}
});
const MessagesIndicator = new Lang.Class({
Name: 'MessagesIndicator',
@ -256,8 +370,7 @@ const IndicatorPad = new Lang.Class({
_init: function(actor) {
this._source = actor;
this._source.connect('notify::visible',
Lang.bind(this, this.queue_relayout));
this._source.connect('notify::visible', () => { this.queue_relayout(); });
this.parent();
},
@ -297,14 +410,38 @@ const FreezableBinLayout = new Lang.Class({
vfunc_get_preferred_width: function(container, forHeight) {
if (!this._frozen || this._savedWidth.some(isNaN))
this._savedWidth = this.parent(container, forHeight);
return this.parent(container, forHeight);
return this._savedWidth;
},
vfunc_get_preferred_height: function(container, forWidth) {
if (!this._frozen || this._savedHeight.some(isNaN))
this._savedHeight = this.parent(container, forWidth);
return this.parent(container, forWidth);
return this._savedHeight;
},
vfunc_allocate: function(container, allocation, flags) {
this.parent(container, allocation, flags);
let [width, height] = allocation.get_size();
this._savedWidth = [width, width];
this._savedHeight = [height, height];
}
});
const CalendarColumnLayout = new Lang.Class({
Name: 'CalendarColumnLayout',
Extends: Clutter.BoxLayout,
_init: function(actor) {
this.parent({ orientation: Clutter.Orientation.VERTICAL });
this._calActor = actor;
},
vfunc_get_preferred_width: function(container, forHeight) {
if (!this._calActor || this._calActor.get_parent() != container)
return this.parent(container, forHeight);
return this._calActor.get_preferred_width(forHeight);
}
});
@ -364,14 +501,16 @@ const DateMenuButton = new Lang.Class({
hbox.add(this._messageList.actor, { expand: true, y_fill: false, y_align: St.Align.START });
// Fill up the second column
vbox = new St.BoxLayout({ style_class: 'datemenu-calendar-column',
vertical: true });
let boxLayout = new CalendarColumnLayout(this._calendar.actor);
vbox = new St.Widget({ style_class: 'datemenu-calendar-column',
layout_manager: boxLayout });
boxLayout.hookup_style(vbox);
hbox.add(vbox);
this._date = new TodayButton(this._calendar);
vbox.add_actor(this._date.actor);
vbox.add(this._calendar.actor);
vbox.add_actor(this._calendar.actor);
this._displaysSection = new St.ScrollView({ style_class: 'datemenu-displays-section vfade',
x_expand: true, x_fill: true,
@ -386,6 +525,8 @@ const DateMenuButton = new Lang.Class({
this._clocksItem = new WorldClocksSection();
displaysBox.add(this._clocksItem.actor, { x_fill: true });
this._weatherItem = new WeatherSection();
displaysBox.add(this._weatherItem.actor, { x_fill: true });
// Done with hbox for calendar and event list

View File

@ -14,6 +14,7 @@ const DRAG_DISTANCE = 80;
const EdgeDragAction = new Lang.Class({
Name: 'EdgeDragAction',
Extends: Clutter.GestureAction,
Signals: { 'activated': {} },
_init : function(side, allowedModes) {
this.parent();
@ -81,4 +82,3 @@ const EdgeDragAction = new Lang.Class({
this.emit('activated');
}
});
Signals.addSignalMethods(EdgeDragAction.prototype);

View File

@ -457,7 +457,6 @@ const EndSessionDialog = new Lang.Class({
_setLabelText(this._descriptionLabel, description);
_setLabelText(this._subjectLabel, subject);
let dialogContent = DialogContent[this._type];
if (dialogContent.iconName) {
this._iconBin.child = new St.Icon({ icon_name: dialogContent.iconName,
icon_size: _DIALOG_ICON_SIZE,

View File

@ -1,6 +1,8 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
imports.gi.versions.Clutter = '1.0';
const Config = imports.misc.config;
imports.gi.versions.Clutter = Config.LIBMUTTER_API_VERSION;
imports.gi.versions.Gio = '2.0';
imports.gi.versions.Gdk = '3.0';
imports.gi.versions.GdkPixbuf = '2.0';

View File

@ -252,7 +252,7 @@ const InstallExtensionDialog = new Lang.Class({
return;
}
invocation.return_value(GLib.Variant.new('(s)', 'successful'));
invocation.return_value(GLib.Variant.new('(s)', ['successful']));
}
_httpSession.queue_message(message, Lang.bind(this, function(session, message) {

View File

@ -38,6 +38,7 @@ const connect = Lang.bind(_signals, _signals.connect);
const disconnect = Lang.bind(_signals, _signals.disconnect);
const ENABLED_EXTENSIONS_KEY = 'enabled-extensions';
const DISABLE_USER_EXTENSIONS_KEY = 'disable-user-extensions';
const EXTENSION_DISABLE_VERSION_CHECK_KEY = 'disable-extension-version-validation';
var initted = false;
@ -238,11 +239,16 @@ function initExtension(uuid) {
}
function getEnabledExtensions() {
let extensions = global.settings.get_strv(ENABLED_EXTENSIONS_KEY);
if (!Array.isArray(Main.sessionMode.enabledExtensions))
let extensions;
if (Array.isArray(Main.sessionMode.enabledExtensions))
extensions = Main.sessionMode.enabledExtensions;
else
extensions = [];
if (global.settings.get_boolean(DISABLE_USER_EXTENSIONS_KEY))
return extensions;
return Main.sessionMode.enabledExtensions.concat(extensions);
return extensions.concat(global.settings.get_strv(ENABLED_EXTENSIONS_KEY));
}
function onEnabledExtensionsChanged() {
@ -276,18 +282,27 @@ function _onVersionValidationChanged() {
// temporarily disable them all
enabledExtensions = [];
for (let uuid in ExtensionUtils.extensions)
reloadExtension(ExtensionUtils.extensions[uuid]);
try {
reloadExtension(ExtensionUtils.extensions[uuid]);
} catch(e) {
logExtensionError(uuid, e);
}
enabledExtensions = getEnabledExtensions();
if (Main.sessionMode.allowExtensions) {
enabledExtensions.forEach(function(uuid) {
enableExtension(uuid);
try {
enableExtension(uuid);
} catch(e) {
logExtensionError(uuid, e);
}
});
}
}
function _loadExtensions() {
global.settings.connect('changed::' + ENABLED_EXTENSIONS_KEY, onEnabledExtensionsChanged);
global.settings.connect('changed::' + DISABLE_USER_EXTENSIONS_KEY, onEnabledExtensionsChanged);
global.settings.connect('changed::' + EXTENSION_DISABLE_VERSION_CHECK_KEY, _onVersionValidationChanged);
enabledExtensions = getEnabledExtensions();

View File

@ -19,6 +19,7 @@ const CandidateArea = new Lang.Class({
_init: function() {
this.actor = new St.BoxLayout({ vertical: true,
reactive: true,
visible: false });
this._candidateBoxes = [];
for (let i = 0; i < MAX_CANDIDATES_PER_PAGE; ++i) {
@ -39,6 +40,19 @@ const CandidateArea = new Lang.Class({
}));
}
this.actor.connect('scroll-event', Lang.bind(this, function(actor, event) {
let direction = event.get_scroll_direction();
switch(direction) {
case Clutter.ScrollDirection.UP:
this.emit('cursor-up');
break;
case Clutter.ScrollDirection.DOWN:
this.emit('cursor-down');
break;
};
return Clutter.EVENT_PROPAGATE;
}));
this._buttonBox = new St.BoxLayout({ style_class: 'candidate-page-button-box' });
this._previousButton = new St.Button({ style_class: 'candidate-page-button candidate-page-button-previous button' });
@ -144,6 +158,14 @@ const CandidatePopup = new Lang.Class({
this._candidateArea.connect('next-page', Lang.bind(this, function() {
this._panelService.page_down();
}));
this._candidateArea.connect('cursor-up', Lang.bind(this, function() {
this._panelService.cursor_up();
}));
this._candidateArea.connect('cursor-down', Lang.bind(this, function() {
this._panelService.cursor_down();
}));
this._candidateArea.connect('candidate-clicked', Lang.bind(this, function(ca, index, button, state) {
this._panelService.candidate_clicked(index, button, state);
}));

View File

@ -33,7 +33,6 @@ var commandHeader = 'const Clutter = imports.gi.Clutter; ' +
'const Mainloop = imports.mainloop; ' +
'const Meta = imports.gi.Meta; ' +
'const Shell = imports.gi.Shell; ' +
'const Tp = imports.gi.TelepathyGLib; ' +
'const Main = imports.ui.main; ' +
'const Lang = imports.lang; ' +
'const Tweener = imports.ui.tweener; ' +

View File

@ -26,6 +26,7 @@ const ModalDialog = imports.ui.modalDialog;
const OsdWindow = imports.ui.osdWindow;
const OsdMonitorLabeler = imports.ui.osdMonitorLabeler;
const Overview = imports.ui.overview;
const PadOsd = imports.ui.padOsd;
const Panel = imports.ui.panel;
const Params = imports.misc.params;
const RunDialog = imports.ui.runDialog;
@ -61,6 +62,7 @@ let screenShield = null;
let notificationDaemon = null;
let windowAttentionHandler = null;
let ctrlAltTabManager = null;
let padOsdService = null;
let osdWindowManager = null;
let osdMonitorLabeler = null;
let sessionMode = null;
@ -155,6 +157,7 @@ function _initializeUI() {
// working until it's updated.
uiGroup = layoutManager.uiGroup;
padOsdService = new PadOsd.PadOsdService();
screencastService = new Screencast.ScreencastService();
xdndHandler = new XdndHandler.XdndHandler();
ctrlAltTabManager = new CtrlAltTab.CtrlAltTabManager();

View File

@ -318,6 +318,7 @@ const Message = new Lang.Class({
this._iconBin = new St.Bin({ style_class: 'message-icon-bin',
y_expand: true,
y_align: St.Align.START,
visible: false });
hbox.add_actor(this._iconBin);
@ -331,18 +332,18 @@ const Message = new Lang.Class({
let titleBox = new St.BoxLayout();
contentBox.add_actor(titleBox);
this.titleLabel = new St.Label({ style_class: 'message-title',
x_expand: true,
x_align: Clutter.ActorAlign.START });
this.titleLabel = new St.Label({ style_class: 'message-title' });
this.setTitle(title);
titleBox.add_actor(this.titleLabel);
this._secondaryBin = new St.Bin({ style_class: 'message-secondary-bin' });
this._secondaryBin = new St.Bin({ style_class: 'message-secondary-bin',
x_expand: true, y_expand: true,
x_fill: true, y_fill: true });
titleBox.add_actor(this._secondaryBin);
let closeIcon = new St.Icon({ icon_name: 'window-close-symbolic',
icon_size: 16 });
this._closeButton = new St.Button({ child: closeIcon, visible: false });
this._closeButton = new St.Button({ child: closeIcon, opacity: 0 });
titleBox.add_actor(this._closeButton);
this._bodyStack = new St.Widget({ x_expand: true });
@ -493,9 +494,8 @@ const Message = new Lang.Class({
},
_sync: function() {
let hovered = this.actor.hover;
this._closeButton.visible = hovered && this.canClose();
this._secondaryBin.visible = !hovered;
let visible = this.actor.hover && this.canClose();
this._closeButton.opacity = visible ? 255 : 0;
},
_onClicked: function() {
@ -520,32 +520,10 @@ Signals.addSignalMethods(Message.prototype);
const MessageListSection = new Lang.Class({
Name: 'MessageListSection',
_init: function(title) {
_init: function() {
this.actor = new St.BoxLayout({ style_class: 'message-list-section',
clip_to_allocation: true,
x_expand: true, vertical: true });
let titleBox = new St.BoxLayout({ style_class: 'message-list-section-title-box' });
this.actor.add_actor(titleBox);
this._title = new St.Button({ style_class: 'message-list-section-title',
label: title,
can_focus: true,
x_expand: true,
x_align: St.Align.START });
titleBox.add_actor(this._title);
this._title.connect('clicked', Lang.bind(this, this._onTitleClicked));
this._title.connect('key-focus-in', Lang.bind(this, this._onKeyFocusIn));
let closeIcon = new St.Icon({ icon_name: 'window-close-symbolic' });
this._closeButton = new St.Button({ style_class: 'message-list-section-close',
child: closeIcon,
accessible_name: _("Clear section"),
can_focus: true });
this._closeButton.set_x_align(Clutter.ActorAlign.END);
titleBox.add_actor(this._closeButton);
this._closeButton.connect('clicked', Lang.bind(this, this.clear));
this._list = new St.BoxLayout({ style_class: 'message-list-section-list',
vertical: true });
@ -563,14 +541,10 @@ const MessageListSection = new Lang.Class({
this._messages = new Map();
this._date = new Date();
this.empty = true;
this.canClear = false;
this._sync();
},
_onTitleClicked: function() {
Main.overview.hide();
Main.panel.closeCalendar();
},
_onKeyFocusIn: function(actor) {
this.emit('key-focus-in', actor);
},
@ -719,7 +693,13 @@ const MessageListSection = new Lang.Class({
if (changed)
this.emit('empty-changed');
this._closeButton.visible = this._canClear();
let canClear = this._canClear();
changed = this.canClear !== canClear;
this.canClear = canClear;
if (changed)
this.emit('can-clear-changed');
this.actor.visible = this.allowed && this._shouldShow();
}
});

View File

@ -368,6 +368,7 @@ const Notification = new Lang.Class({
secondaryGIcon: null,
bannerMarkup: false,
clear: false,
datetime: null,
soundName: null,
soundFile: null });
@ -375,6 +376,11 @@ const Notification = new Lang.Class({
this.bannerBodyText = banner;
this.bannerBodyMarkup = params.bannerMarkup;
if (params.datetime)
this.datetime = params.datetime;
else
this.datetime = GLib.DateTime.new_now_local();
if (params.gicon || params.clear)
this.gicon = params.gicon;
@ -535,7 +541,8 @@ const NotificationBanner = new Lang.Class({
_addSecondaryIcon: function() {
if (this.notification.secondaryGIcon) {
let icon = new St.Icon({ gicon: this.notification.secondaryGIcon });
let icon = new St.Icon({ gicon: this.notification.secondaryGIcon,
x_align: Clutter.ActorAlign.END });
this.setSecondaryActor(icon);
}
},
@ -796,7 +803,7 @@ const Source = new Lang.Class({
notification.acknowledged = false;
this.pushNotification(notification);
if (this.policy.showBanners) {
if (this.policy.showBanners || notification.urgency == Urgency.CRITICAL) {
this.emit('notify', notification);
} else {
notification.playSound();
@ -1224,7 +1231,7 @@ const MessageTray = new Lang.Class({
if (this._notificationState == State.HIDDEN) {
let nextNotification = this._notificationQueue[0] || null;
if (hasNotifications && nextNotification) {
let limited = this._busy || Main.layoutManager.bottomMonitor.inFullscreen;
let limited = this._busy || Main.layoutManager.primaryMonitor.inFullscreen;
let showNextNotification = (!limited || nextNotification.forFeedback || nextNotification.urgency == Urgency.CRITICAL);
if (showNextNotification)
this._showNotification();

View File

@ -36,6 +36,8 @@ const MprisPlayerIface = '<node> \
<method name="PlayPause" /> \
<method name="Next" /> \
<method name="Previous" /> \
<property name="CanGoNext" type="b" access="read" /> \
<property name="CanGoPrevious" type="b" access="read" /> \
<property name="CanPlay" type="b" access="read" /> \
<property name="Metadata" type="a{sv}" access="read" /> \
<property name="PlaybackStatus" type="s" access="read" /> \
@ -57,7 +59,7 @@ const MediaMessage = new Lang.Class({
this._icon = new St.Icon({ style_class: 'media-message-cover-icon' });
this.setIcon(this._icon);
this.addMediaControl('media-skip-backward-symbolic',
this._prevButton = this.addMediaControl('media-skip-backward-symbolic',
Lang.bind(this, function() {
this._player.previous();
}));
@ -67,7 +69,7 @@ const MediaMessage = new Lang.Class({
this._player.playPause();
}));
this.addMediaControl('media-skip-forward-symbolic',
this._nextButton = this.addMediaControl('media-skip-forward-symbolic',
Lang.bind(this, function() {
this._player.next();
}));
@ -82,6 +84,10 @@ const MediaMessage = new Lang.Class({
Main.panel.closeCalendar();
},
_updateNavButton: function(button, sensitive) {
button.reactive = sensitive;
},
_update: function() {
this.setTitle(this._player.trackArtists.join(', '));
this.setBody(this._player.trackTitle);
@ -99,6 +105,9 @@ const MediaMessage = new Lang.Class({
let iconName = isPlaying ? 'media-playback-pause-symbolic'
: 'media-playback-start-symbolic';
this._playPauseButton.child.icon_name = iconName;
this._updateNavButton(this._prevButton, this._player.canGoPrevious);
this._updateNavButton(this._nextButton, this._player.canGoNext);
}
});
@ -139,10 +148,18 @@ const MprisPlayer = new Lang.Class({
this._playerProxy.PlayPauseRemote();
},
get canGoNext() {
return this._playerProxy.CanGoNext;
},
next: function() {
this._playerProxy.NextRemote();
},
get canGoPrevious() {
return this._playerProxy.CanGoPrevious;
},
previous: function() {
this._playerProxy.PreviousRemote();
},
@ -214,7 +231,7 @@ const MediaSection = new Lang.Class({
Extends: MessageList.MessageListSection,
_init: function() {
this.parent(_("Media"));
this.parent();
this._players = new Map();

View File

@ -186,7 +186,7 @@ const FdoNotificationDaemon = new Lang.Class({
return source;
}
let source = new FdoNotificationDaemonSource(title, pid, sender, ndata ? ndata.hints['desktop-entry'] : null);
source = new FdoNotificationDaemonSource(title, pid, sender, ndata ? ndata.hints['desktop-entry'] : null);
this._sources.push(source);
source.connect('destroy', Lang.bind(this, function() {
@ -600,7 +600,8 @@ const GtkNotificationDaemonNotification = new Lang.Class({
"priority": priority,
"buttons": buttons,
"default-action": defaultAction,
"default-action-target": defaultActionTarget } = notification;
"default-action-target": defaultActionTarget,
"timestamp": time } = notification;
if (priority) {
let urgency = PRIORITY_URGENCY_MAP[priority.unpack()];
@ -623,7 +624,8 @@ const GtkNotificationDaemonNotification = new Lang.Class({
this._defaultActionTarget = defaultActionTarget;
this.update(title.unpack(), body ? body.unpack() : null,
{ gicon: gicon ? Gio.icon_deserialize(gicon) : null });
{ gicon: gicon ? Gio.icon_deserialize(gicon) : null,
datetime : time ? GLib.DateTime.new_from_unix_local(time.unpack()) : null });
},
_activateAction: function(namespacedActionId, target) {
@ -690,6 +692,7 @@ const GtkNotificationDaemonAppSource = new Lang.Class({
throw new InvalidAppError();
this._notifications = {};
this._notificationPending = false;
this.parent(this._app.get_name());
},
@ -702,27 +705,35 @@ const GtkNotificationDaemonAppSource = new Lang.Class({
return new MessageTray.NotificationApplicationPolicy(this._appId);
},
_createApp: function() {
return new FdoApplicationProxy(Gio.DBus.session, this._appId, this._objectPath);
_createApp: function(callback) {
return new FdoApplicationProxy(Gio.DBus.session, this._appId, this._objectPath, callback);
},
activateAction: function(actionId, target) {
let app = this._createApp();
app.ActivateActionRemote(actionId, target ? [target] : [], getPlatformData());
this._createApp(function (app, error) {
if (error == null)
app.ActivateActionRemote(actionId, target ? [target] : [], getPlatformData());
else
logError(error, 'Failed to activate application proxy');
});
Main.overview.hide();
Main.panel.closeCalendar();
},
open: function() {
let app = this._createApp();
app.ActivateRemote(getPlatformData());
this._createApp(function (app, error) {
if (error == null)
app.ActivateRemote(getPlatformData());
else
logError(error, 'Failed to open application proxy');
});
Main.overview.hide();
Main.panel.closeCalendar();
},
addNotification: function(notificationId, notificationParams, showBanner) {
this._notificationPending = true;
if (this._notifications[notificationId])
this._notifications[notificationId].destroy();
@ -736,6 +747,14 @@ const GtkNotificationDaemonAppSource = new Lang.Class({
this.notify(notification);
else
this.pushNotification(notification);
this._notificationPending = false;
},
destroy: function(reason) {
if (this._notificationPending)
return;
this.parent(reason);
},
removeNotification: function(notificationId) {
@ -847,6 +866,9 @@ const GtkNotificationDaemon = new Lang.Class({
return;
}
let timestamp = GLib.DateTime.new_now_local().to_unix();
notification['timestamp'] = new GLib.Variant('x', timestamp);
source.addNotification(notificationId, notification, true);
invocation.return_value(null);

View File

@ -107,9 +107,9 @@ const Overview = new Lang.Class({
this._overviewCreated = true;
/* Translators: This is the main view to select
activities. See also note for "Activities" string. */
this._overview = new St.BoxLayout({ name: 'overview',
/* Translators: This is the main view to select
activities. See also note for "Activities" string. */
accessible_name: _("Overview"),
vertical: true });
this._overview.add_constraint(new LayoutManager.MonitorConstraint({ primary: true }));
@ -378,7 +378,7 @@ const Overview = new Lang.Class({
return null;
let window = windows[0];
let clone = new Clutter.Clone({ source: window.get_texture(),
let clone = new Clutter.Clone({ source: window,
x: window.x, y: window.y });
clone.source.connect('destroy', Lang.bind(this, function() {
clone.destroy();

900
js/ui/padOsd.js Normal file
View File

@ -0,0 +1,900 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
const Lang = imports.lang;
const Meta = imports.gi.Meta;
const Shell = imports.gi.Shell;
const Clutter = imports.gi.Clutter;
const St = imports.gi.St;
const Rsvg = imports.gi.Rsvg;
const GObject = imports.gi.GObject;
const GLib = imports.gi.GLib;
const Gtk = imports.gi.Gtk;
const Gio = imports.gi.Gio;
const GDesktopEnums = imports.gi.GDesktopEnums;
const Atk = imports.gi.Atk;
const Cairo = imports.cairo;
const Signals = imports.signals;
const Main = imports.ui.main;
const PopupMenu = imports.ui.popupMenu;
const Layout = imports.ui.layout;
const ACTIVE_COLOR = "#729fcf";
const LTR = 0;
const RTL = 1;
const CW = 0;
const CCW = 1;
const UP = 0;
const DOWN = 1;
const PadChooser = new Lang.Class({
Name: 'PadChooser',
_init: function (device, groupDevices) {
this.actor = new St.Button({ style_class: 'pad-chooser-button',
toggle_mode: true,
x_fill: false,
y_fill: false,
x_align: St.Align.MIDDLE,
y_align: St.Align.MIDDLE });
this.currentDevice = device;
this._padChooserMenu = null;
let arrow = new St.Icon({ style_class: 'popup-menu-arrow',
icon_name: 'pan-down-symbolic',
accessible_role: Atk.Role.ARROW });
this.actor.set_child(arrow);
this._ensureMenu(groupDevices);
this.actor.connect('destroy', Lang.bind(this, this._onDestroy));
this.actor.connect('clicked', Lang.bind(this, function (actor) {
if (actor.get_checked()) {
if (this._padChooserMenu != null)
this._padChooserMenu.open(true);
else
this.set_checked(false);
} else {
this._padChooserMenu.close(true);
}
}));
},
_ensureMenu: function (devices) {
this._padChooserMenu = new PopupMenu.PopupMenu(this.actor, 0.5, St.Side.TOP);
this._padChooserMenu.connect('menu-closed', Lang.bind(this, function() { this.actor.set_checked(false); }));
this._padChooserMenu.actor.hide();
Main.uiGroup.add_actor(this._padChooserMenu.actor);
for (let i = 0; i < devices.length; i++) {
let device = devices[i];
if (device == this.currentDevice)
continue;
this._padChooserMenu.addAction(device.get_device_name(), () => {
this.emit('pad-selected', device);
});
}
},
_onDestroy: function () {
this._padChooserMenu.destroy();
},
update: function (devices) {
if (this._padChooserMenu)
this._padChooserMenu.actor.destroy();
this.actor.set_checked(false);
this._ensureMenu(devices);
},
destroy: function () {
this.actor.destroy();
},
});
Signals.addSignalMethods(PadChooser.prototype);
const KeybindingEntry = new Lang.Class({
Name: 'KeybindingEntry',
_init: function () {
this.actor = new St.Entry({ hint_text: _("New shortcut…"),
style: 'width: 10em' });
this.actor.connect('captured-event', Lang.bind(this, this._onCapturedEvent));
},
_onCapturedEvent: function (actor, event) {
if (event.type() != Clutter.EventType.KEY_PRESS)
return Clutter.EVENT_PROPAGATE;
let str = Gtk.accelerator_name_with_keycode(null,
event.get_key_symbol(),
event.get_key_code(),
event.get_state());
this.actor.set_text(str);
this.emit('keybinding-edited', str);
return Clutter.EVENT_STOP;
}
});
Signals.addSignalMethods(KeybindingEntry.prototype);
const ActionComboBox = new Lang.Class({
Name: 'ActionComboBox',
_init: function () {
this.actor = new St.Button({ style_class: 'button' });
this.actor.connect('clicked', Lang.bind(this, this._onButtonClicked));
this.actor.set_toggle_mode(true);
let boxLayout = new Clutter.BoxLayout({ orientation: Clutter.Orientation.HORIZONTAL,
spacing: 6 });
let box = new St.Widget({ layout_manager: boxLayout });
this.actor.set_child(box);
this._label = new St.Label({ style_class: 'combo-box-label' });
box.add_child(this._label)
let arrow = new St.Icon({ style_class: 'popup-menu-arrow',
icon_name: 'pan-down-symbolic',
accessible_role: Atk.Role.ARROW,
y_expand: true,
y_align: Clutter.ActorAlign.CENTER });
box.add_child(arrow);
this._editMenu = new PopupMenu.PopupMenu(this.actor, 0, St.Side.TOP);
this._editMenu.connect('menu-closed', Lang.bind(this, function() { this.actor.set_checked(false); }));
this._editMenu.actor.hide();
Main.uiGroup.add_actor(this._editMenu.actor);
this._actionLabels = new Map();
this._actionLabels.set(GDesktopEnums.PadButtonAction.NONE, _("Application defined"));
this._actionLabels.set(GDesktopEnums.PadButtonAction.HELP, _("Show on-screen help"));
this._actionLabels.set(GDesktopEnums.PadButtonAction.SWITCH_MONITOR, _("Switch monitor"));
this._actionLabels.set(GDesktopEnums.PadButtonAction.KEYBINDING, _("Assign keystroke"));
for (let [action, label] of this._actionLabels.entries()) {
let selectedAction = action;
this._editMenu.addAction(label, Lang.bind(this, function() { this._onActionSelected(selectedAction) }));
}
this.setAction(GDesktopEnums.PadButtonAction.NONE);
},
_onActionSelected: function (action) {
this.setAction(action);
this.popdown();
this.emit('action-selected', action);
},
setAction: function (action) {
this._label.set_text(this._actionLabels.get(action));
},
popup: function () {
this._editMenu.open(true);
},
popdown: function () {
this._editMenu.close(true);
},
_onButtonClicked: function () {
if (this.actor.get_checked())
this.popup();
else
this.popdown();
}
});
Signals.addSignalMethods(ActionComboBox.prototype);
const ActionEditor = new Lang.Class({
Name: 'ActionEditor',
_init: function () {
let boxLayout = new Clutter.BoxLayout({ orientation: Clutter.Orientation.HORIZONTAL,
spacing: 12 });
this.actor = new St.Widget({ layout_manager: boxLayout });
this._actionComboBox = new ActionComboBox();
this._actionComboBox.connect('action-selected', Lang.bind(this, this._onActionSelected));
this.actor.add_actor(this._actionComboBox.actor);
this._keybindingEdit = new KeybindingEntry();
this._keybindingEdit.connect('keybinding-edited', Lang.bind(this, this._onKeybindingEdited));
this.actor.add_actor(this._keybindingEdit.actor);
this._doneButton = new St.Button({ label: _("Done"),
style_class: 'button',
x_expand: false});
this._doneButton.connect('clicked', Lang.bind(this, this._onEditingDone));
this.actor.add_actor(this._doneButton);
},
_updateKeybindingEntryState: function () {
if (this._currentAction == GDesktopEnums.PadButtonAction.KEYBINDING) {
this._keybindingEdit.actor.set_text(this._currentKeybinding);
this._keybindingEdit.actor.show();
this._keybindingEdit.actor.grab_key_focus();
} else {
this._keybindingEdit.actor.hide();
}
},
setSettings: function (settings) {
this._buttonSettings = settings;
this._currentAction = this._buttonSettings.get_enum('action');
this._currentKeybinding = this._buttonSettings.get_string('keybinding');
this._actionComboBox.setAction(this._currentAction);
this._updateKeybindingEntryState();
},
close: function() {
this._actionComboBox.popdown();
this.actor.hide();
},
_onKeybindingEdited: function (entry, keybinding) {
this._currentKeybinding = keybinding;
},
_onActionSelected: function (menu, action) {
this._currentAction = action;
this._updateKeybindingEntryState();
},
_storeSettings: function () {
if (!this._buttonSettings)
return;
let keybinding = null;
if (this._currentAction == GDesktopEnums.PadButtonAction.KEYBINDING)
keybinding = this._currentKeybinding;
this._buttonSettings.set_enum('action', this._currentAction);
if (keybinding)
this._buttonSettings.set_string('keybinding', keybinding);
else
this._buttonSettings.reset('keybinding');
},
_onEditingDone: function () {
this._storeSettings();
this.close();
this.emit('done');
}
});
Signals.addSignalMethods(ActionEditor.prototype);
const PadDiagram = new Lang.Class({
Name: 'PadDiagram',
Extends: St.DrawingArea,
Properties: { 'left-handed': GObject.ParamSpec.boolean('left-handed',
'left-handed', 'Left handed',
GObject.ParamFlags.READWRITE |
GObject.ParamFlags.CONSTRUCT_ONLY,
false),
'image': GObject.ParamSpec.string('image', 'image', 'Image',
GObject.ParamFlags.READWRITE |
GObject.ParamFlags.CONSTRUCT_ONLY,
null),
'editor-actor': GObject.ParamSpec.object('editor-actor',
'editor-actor',
'Editor actor',
GObject.ParamFlags.READWRITE |
GObject.ParamFlags.CONSTRUCT_ONLY,
Clutter.Actor.$gtype) },
_init: function (params) {
let file = Gio.File.new_for_uri('resource:///org/gnome/shell/theme/pad-osd.css');
let [success, css, etag] = file.load_contents(null);
this._css = css;
this._labels = [];
this._activeButtons = [];
this.parent(params);
},
get left_handed() {
return this._leftHanded;
},
set left_handed(leftHanded) {
this._leftHanded = leftHanded;
},
get image() {
return this._imagePath;
},
set image(imagePath) {
let originalHandle = Rsvg.Handle.new_from_file(imagePath);
let dimensions = originalHandle.get_dimensions();
this._imageWidth = dimensions.width;
this._imageHeight = dimensions.height;
this._imagePath = imagePath;
this._handle = this._composeStyledDiagram();
},
get editor_actor() {
return this._editorActor;
},
set editor_actor(actor) {
actor.hide();
this._editorActor = actor;
this.add_actor(actor);
},
_wrappingSvgHeader: function () {
return ('<?xml version="1.0" encoding="UTF-8" standalone="no"?>' +
'<svg version="1.1" xmlns="http://www.w3.org/2000/svg" ' +
'xmlns:xi="http://www.w3.org/2001/XInclude" ' +
'width="' + this._imageWidth + '" height="' + this._imageHeight + '"> ' +
'<style type="text/css">');
},
_wrappingSvgFooter: function () {
return ('</style>' +
'<xi:include href="' + this._imagePath + '" />' +
'</svg>');
},
_cssString: function () {
let css = this._css;
for (let i = 0; i < this._activeButtons.length; i++) {
let ch = String.fromCharCode('A'.charCodeAt() + this._activeButtons[i]);
css += ('.' + ch + ' { ' +
' stroke: ' + ACTIVE_COLOR + ' !important; ' +
' fill: ' + ACTIVE_COLOR + ' !important; ' +
'} ');
}
return css;
},
_composeStyledDiagram: function () {
let svgData = '';
if (!GLib.file_test(this._imagePath, GLib.FileTest.EXISTS))
return null;
svgData += this._wrappingSvgHeader();
svgData += this._cssString();
svgData += this._wrappingSvgFooter();
let handle = new Rsvg.Handle();
handle.set_base_uri(GLib.path_get_dirname(this._imagePath));
handle.write(svgData);
handle.close();
return handle;
},
_updateDiagramScale: function () {
if (this._handle == null)
return;
[this._actorWidth, this._actorHeight] = this.get_size();
let dimensions = this._handle.get_dimensions();
let scaleX = this._actorWidth / dimensions.width;
let scaleY = this._actorHeight / dimensions.height;
this._scale = Math.min(scaleX, scaleY);
},
_allocateChild: function (child, x, y, direction) {
let [prefHeight, natHeight] = child.get_preferred_height(-1);
let [prefWidth, natWidth] = child.get_preferred_width(natHeight);
let childBox = new Clutter.ActorBox();
if (direction == LTR) {
childBox.x1 = x;
childBox.x2 = x + natWidth;
} else {
childBox.x1 = x - natWidth;
childBox.x2 = x;
}
childBox.y1 = y - natHeight / 2;
childBox.y2 = y + natHeight / 2;
child.allocate(childBox, 0);
},
vfunc_allocate: function (box, flags) {
this.parent(box, flags);
this._updateDiagramScale();
for (let i = 0; i < this._labels.length; i++) {
let [label, action, idx, dir] = this._labels[i];
let [found, x, y, arrangement] = this.getLabelCoords(action, idx, dir);
this._allocateChild(label, x, y, arrangement);
}
if (this._editorActor && this._curEdited) {
let [label, action, idx, dir] = this._curEdited;
let [found, x, y, arrangement] = this.getLabelCoords(action, idx, dir);
this._allocateChild(this._editorActor, x, y, arrangement);
}
},
vfunc_repaint: function () {
if (this._handle == null)
return;
if (this._scale == null)
this._updateDiagramScale();
let [width, height] = this.get_surface_size();
let dimensions = this._handle.get_dimensions();
let cr = this.get_context();
cr.save();
cr.translate(width/2, height/2);
cr.scale(this._scale, this._scale);
if (this._leftHanded)
cr.rotate(Math.PI);
cr.translate(-dimensions.width/2, -dimensions.height/2);
this._handle.render_cairo(cr);
cr.restore();
cr.$dispose();
},
_transformPoint: function (x, y) {
if (this._handle == null || this._scale == null)
return [x, y];
// I miss Cairo.Matrix
let dimensions = this._handle.get_dimensions();
x = x * this._scale + this._actorWidth / 2 - dimensions.width / 2 * this._scale;
y = y * this._scale + this._actorHeight / 2 - dimensions.height / 2 * this._scale;;
return [Math.round(x), Math.round(y)];
},
_getItemLabelCoords: function (labelName, leaderName) {
if (this._handle == null)
return [false];
let leaderPos, leaderSize, pos;
let found, direction;
[found, pos] = this._handle.get_position_sub('#' + labelName);
if (!found)
return [false];
[found, leaderPos] = this._handle.get_position_sub('#' + leaderName);
[found, leaderSize] = this._handle.get_dimensions_sub('#' + leaderName);
if (!found)
return [false];
if (pos.x > leaderPos.x + leaderSize.width)
direction = LTR;
else
direction = RTL;
if (this._leftHanded) {
direction = 1 - direction;
pos.x = this._imageWidth - pos.x;
pos.y = this._imageHeight - pos.y;
}
let [x, y] = this._transformPoint(pos.x, pos.y)
return [true, x, y, direction];
},
getButtonLabelCoords: function (button) {
let ch = String.fromCharCode('A'.charCodeAt() + button);
let labelName = 'Label' + ch;
let leaderName = 'Leader' + ch;
return this._getItemLabelCoords(labelName, leaderName);
},
getRingLabelCoords: function (number, dir) {
let numStr = number > 0 ? number.toString() : '';
let dirStr = dir == CW ? 'CW' : 'CCW';
let labelName = 'LabelRing' + numStr + dirStr;
let leaderName = 'LeaderRing' + numStr + dirStr;
return this._getItemLabelCoords(labelName, leaderName);
},
getStripLabelCoords: function (number, dir) {
let numStr = number > 0 ? (number + 1).toString() : '';
let dirStr = dir == UP ? 'Up' : 'Down';
let labelName = 'LabelStrip' + numStr + dirStr;
let leaderName = 'LeaderStrip' + numStr + dirStr;
return this._getItemLabelCoords(labelName, leaderName);
},
getLabelCoords: function (action, idx, dir) {
if (action == Meta.PadActionType.BUTTON)
return this.getButtonLabelCoords(idx);
else if (action == Meta.PadActionType.RING)
return this.getRingLabelCoords(idx, dir);
else if (action == Meta.PadActionType.STRIP)
return this.getStripLabelCoords(idx, dir);
return [false];
},
_invalidateSvg: function () {
if (this._handle == null)
return;
this._handle = this._composeStyledDiagram();
this.queue_repaint();
},
activateButton: function (button) {
this._activeButtons.push(button);
this._invalidateSvg();
},
deactivateButton: function (button) {
for (let i = 0; i < this._activeButtons.length; i++) {
if (this._activeButtons[i] == button)
this._activeButtons.splice(i, 1);
}
this._invalidateSvg();
},
addLabel: function (label, type, idx, dir) {
this._labels.push([label, type, idx, dir]);
this.add_actor(label);
},
stopEdition: function (str) {
this._editorActor.hide();
if (this._curEdited) {
let [label, action, idx, dir] = this._curEdited;
if (str != null) {
label.set_text(str);
let [found, x, y, arrangement] = this.getLabelCoords(action, idx, dir);
this._allocateChild(label, x, y, arrangement);
}
label.show();
this._curEdited = null;
}
},
startEdition: function(action, idx, dir) {
let editedLabel;
this.stopEdition();
for (let i = 0; i < this._labels.length; i++) {
let [label, itemAction, itemIdx, itemDir] = this._labels[i];
if (action == itemAction && idx == itemIdx && dir == itemDir) {
this._curEdited = this._labels[i];
editedLabel = label;
break;
}
}
if (this._curEdited == null)
return;
let [found] = this.getLabelCoords(action, idx, dir);
if (!found)
return;
this._editorActor.show();
editedLabel.hide();
}
});
const PadOsd = new Lang.Class({
Name: 'PadOsd',
_init: function (padDevice, settings, imagePath, editionMode, monitorIndex) {
this.padDevice = padDevice;
this._groupPads = [ padDevice ];
this._settings = settings;
this._imagePath = imagePath;
this._editionMode = editionMode;
this._capturedEventId = global.stage.connect('captured-event', Lang.bind(this, this._onCapturedEvent));
this._padChooser = null;
let deviceManager = Clutter.DeviceManager.get_default();
this._deviceAddedId = deviceManager.connect('device-added', Lang.bind(this, function (manager, device) {
if (device.get_device_type() == Clutter.InputDeviceType.PAD_DEVICE &&
this.padDevice.is_grouped(device)) {
this._groupPads.push(device);
this._updatePadChooser();
}
}));
this._deviceRemovedId = deviceManager.connect('device-removed', Lang.bind(this, function (manager, device) {
// If the device is being removed, destroy the padOsd.
if (device == this.padDevice) {
this.destroy();
} else if (this._groupPads.indexOf(device) != -1) {
// Or update the pad chooser if the device belongs to
// the same group.
this._groupPads.splice(this._groupPads.indexOf(device), 1);
this._updatePadChooser();
}
}));
deviceManager.list_devices().forEach(Lang.bind(this, function(device) {
if (device != this.padDevice &&
device.get_device_type() == Clutter.InputDeviceType.PAD_DEVICE &&
this.padDevice.is_grouped(device))
this._groupPads.push(device);
}));
this.actor = new St.BoxLayout({ style_class: 'pad-osd-window',
x_expand: true,
y_expand: true,
vertical: true,
reactive: true });
this.actor.connect('destroy', Lang.bind(this, this._onDestroy));
Main.uiGroup.add_actor(this.actor);
this._monitorIndex = monitorIndex;
let constraint = new Layout.MonitorConstraint({ index: monitorIndex });
this.actor.add_constraint(constraint);
this._titleBox = new St.BoxLayout({ style_class: 'pad-osd-title-box',
vertical: false,
x_expand: false,
x_align: Clutter.ActorAlign.CENTER });
this.actor.add_actor(this._titleBox);
let labelBox = new St.BoxLayout({ style_class: 'pad-osd-title-menu-box',
vertical: true });
this._titleBox.add_actor(labelBox);
this._titleLabel = new St.Label({ style: 'font-side: larger; font-weight: bold;',
x_align: Clutter.ActorAlign.CENTER });
this._titleLabel.clutter_text.set_text(padDevice.get_device_name());
labelBox.add_actor(this._titleLabel);
this._tipLabel = new St.Label({ x_align: Clutter.ActorAlign.CENTER });
labelBox.add_actor(this._tipLabel);
this._updatePadChooser();
this._actionEditor = new ActionEditor();
this._actionEditor.connect('done', Lang.bind(this, this._endButtonActionEdition));
this._padDiagram = new PadDiagram({ image: this._imagePath,
left_handed: settings.get_boolean('left-handed'),
editor_actor: this._actionEditor.actor,
x_expand: true,
y_expand: true });
this.actor.add_actor(this._padDiagram);
// FIXME: Fix num buttons.
let i = 0;
for (i = 0; i < 50; i++) {
let [found] = this._padDiagram.getButtonLabelCoords(i);
if (!found)
break;
this._createLabel(Meta.PadActionType.BUTTON, i);
}
for (i = 0; i < padDevice.get_n_rings(); i++) {
this._createLabel(Meta.PadActionType.RING, i, CW);
this._createLabel(Meta.PadActionType.RING, i, CCW);
}
for (i = 0; i < padDevice.get_n_strips(); i++) {
this._createLabel(Meta.PadActionType.STRIP, i, UP);
this._createLabel(Meta.PadActionType.STRIP, i, DOWN);
}
let buttonBox = new St.Widget({ layout_manager: new Clutter.BinLayout(),
x_expand: true,
x_align: Clutter.ActorAlign.CENTER,
y_align: Clutter.ActorAlign.CENTER });
this.actor.add_actor(buttonBox);
this._editButton = new St.Button({ label: _("Edit…"),
style_class: 'button',
x_align: Clutter.ActorAlign.CENTER,
can_focus: true });
this._editButton.connect('clicked', Lang.bind(this, function () { this.setEditionMode(true) }));
buttonBox.add_actor(this._editButton);
this._syncEditionMode();
Main.pushModal(this.actor);
},
_updatePadChooser: function () {
if (this._groupPads.length > 1) {
if (this._padChooser == null) {
this._padChooser = new PadChooser(this.padDevice, this._groupPads)
this._padChooser.connect('pad-selected', Lang.bind(this, function (chooser, pad) {
this._requestForOtherPad(pad);
}));
this._titleBox.add_child(this._padChooser.actor);
} else {
this._padChooser.update(this._groupPads);
}
} else if (this._padChooser != null) {
this._padChooser.destroy();
this._padChooser = null;
}
},
_requestForOtherPad: function (pad) {
if (pad == this.padDevice ||
this._groupPads.indexOf(pad) == -1)
return;
let editionMode = this._editionMode;
this.destroy();
global.display.request_pad_osd(pad, editionMode);
},
_createLabel: function (type, number, dir) {
let str = global.display.get_pad_action_label(this.padDevice, type, number);
let label = new St.Label({ text: str ? str : _("None") });
this._padDiagram.addLabel(label, type, number, dir);
},
_onCapturedEvent : function (actor, event) {
if (event.type() == Clutter.EventType.PAD_BUTTON_PRESS &&
event.get_source_device() == this.padDevice) {
this._padDiagram.activateButton(event.get_button());
if (this._editionMode)
this._startButtonActionEdition(event.get_button());
return Clutter.EVENT_STOP;
} else if (event.type() == Clutter.EventType.PAD_BUTTON_RELEASE &&
event.get_source_device() == this.padDevice) {
this._padDiagram.deactivateButton(event.get_button());
return Clutter.EVENT_STOP;
} else if (event.type() == Clutter.EventType.KEY_PRESS &&
(!this._editionMode || event.get_key_symbol() == Clutter.Escape)) {
if (this._editingButtonAction != null)
this._endButtonActionEdition();
else
this.destroy();
return Clutter.EVENT_STOP;
}
// If the event comes from another pad in the same group,
// show the OSD for it.
if (this._groupPads.indexOf(event.get_source_device()) != -1) {
this._requestForOtherPad(event.get_source_device());
return Clutter.EVENT_STOP;
}
return Clutter.EVENT_PROPAGATE;
},
_syncEditionMode: function () {
this._editButton.set_reactive(!this._editionMode);
this._editButton.save_easing_state();
this._editButton.set_easing_duration(200);
this._editButton.set_opacity(this._editionMode ? 128 : 255);
this._editButton.restore_easing_state();
let title;
if (this._editionMode) {
title = _("Press a button to configure");
this._tipLabel.set_text(_("Press Esc to exit"));
} else {
title = this.padDevice.get_device_name();
this._tipLabel.set_text(_("Press any key to exit"));
}
this._titleLabel.clutter_text.set_markup('<span size="larger"><b>' + title + '</b></span>');
},
_endButtonActionEdition: function () {
this._actionEditor.close();
if (this._editingButtonAction != null) {
let str = global.display.get_pad_action_label(this.padDevice,
Meta.PadActionType.BUTTON,
this._editingButtonAction);
this._padDiagram.stopEdition(str ? str : _("None"))
this._editingButtonAction = null;
}
this._editedButtonSettings = null;
},
_startButtonActionEdition: function (button) {
if (this._editingButtonAction == button)
return;
this._endButtonActionEdition();
this._editingButtonAction = button;
let ch = String.fromCharCode('A'.charCodeAt() + button);
let settingsPath = this._settings.path + "button" + ch + '/';
this._editedButtonSettings = Gio.Settings.new_with_path('org.gnome.desktop.peripherals.tablet.pad-button',
settingsPath);
this._actionEditor.setSettings(this._editedButtonSettings);
this._padDiagram.startEdition(Meta.PadActionType.BUTTON, button);
},
setEditionMode: function (editionMode) {
if (this._editionMode == editionMode)
return;
this._editionMode = editionMode;
this._syncEditionMode();
},
destroy: function () {
this.actor.destroy();
},
_onDestroy: function () {
Main.popModal(this.actor);
this._actionEditor.close();
let deviceManager = Clutter.DeviceManager.get_default();
if (this._deviceRemovedId != 0) {
deviceManager.disconnect(this._deviceRemovedId);
this._deviceRemovedId = 0;
}
if (this._deviceAddedId != 0) {
deviceManager.disconnect(this._deviceAddedId);
this._deviceAddedId = 0;
}
if (this._capturedEventId != 0) {
global.stage.disconnect(this._capturedEventId);
this._capturedEventId = 0;
}
this.actor = null;
this.emit('closed');
}
});
Signals.addSignalMethods(PadOsd.prototype);
const PadOsdIface = '<node> \
<interface name="org.gnome.Shell.Wacom.PadOsd"> \
<method name="Show"> \
<arg name="device_node" direction="in" type="o"/> \
<arg name="edition_mode" direction="in" type="b"/> \
</method> \
</interface> \
</node>';
const PadOsdService = new Lang.Class({
Name: 'PadOsdService',
_init: function() {
this._dbusImpl = Gio.DBusExportedObject.wrapJSObject(PadOsdIface, this);
this._dbusImpl.export(Gio.DBus.session, '/org/gnome/Shell/Wacom');
Gio.DBus.session.own_name('org.gnome.Shell.Wacom.PadOsd', Gio.BusNameOwnerFlags.REPLACE, null, null);
},
ShowAsync: function(params, invocation) {
let [deviceNode, editionMode] = params;
let deviceManager = Clutter.DeviceManager.get_default();
let devices = deviceManager.list_devices();
let padDevice = null;
devices.forEach(Lang.bind(this, function(device) {
if (deviceNode == device.get_device_node())
padDevice = device;
}));
if (padDevice == null ||
padDevice.get_device_type() != Clutter.InputDeviceType.PAD_DEVICE) {
invocation.return_error_literal(Gio.IOErrorEnum,
Gio.IOErrorEnum.CANCELLED,
"Invalid params");
return;
}
global.display.request_pad_osd(padDevice, editionMode);
invocation.return_value(null);
}
});
Signals.addSignalMethods(PadOsdService.prototype);

View File

@ -719,9 +719,11 @@ const AggregateMenu = new Lang.Class({
this._system = new imports.ui.status.system.Indicator();
this._screencast = new imports.ui.status.screencast.Indicator();
this._location = new imports.ui.status.location.Indicator();
this._nightLight = new imports.ui.status.nightLight.Indicator();
this._indicators.add_child(this._screencast.indicators);
this._indicators.add_child(this._location.indicators);
this._indicators.add_child(this._nightLight.indicators);
if (this._network) {
this._indicators.add_child(this._network.indicators);
}
@ -745,6 +747,7 @@ const AggregateMenu = new Lang.Class({
this.menu.addMenuItem(this._location.menu);
this.menu.addMenuItem(this._rfkill.menu);
this.menu.addMenuItem(this._power.menu);
this.menu.addMenuItem(this._nightLight.menu);
this.menu.addMenuItem(this._system.menu);
menuLayout.addSizeChild(this._location.menu.actor);

View File

@ -174,8 +174,14 @@ const Button = new Lang.Class({
// menu is higher then the screen; it's useful if part of the menu is
// scrollable so the minimum height is smaller than the natural height
let workArea = Main.layoutManager.getWorkAreaForMonitor(Main.layoutManager.primaryIndex);
let scaleFactor = St.ThemeContext.get_for_stage(global.stage).scale_factor;
let verticalMargins = this.menu.actor.margin_top + this.menu.actor.margin_bottom;
this.menu.actor.style = ('max-height: ' + Math.round(workArea.height - verticalMargins) + 'px;');
// The workarea and margin dimensions are in physical pixels, but CSS
// measures are in logical pixels, so make sure to consider the scale
// factor when computing max-height
let maxHeight = Math.round((workArea.height - verticalMargins) / scaleFactor);
this.menu.actor.style = ('max-height: %spx;').format(maxHeight);
},
destroy: function() {

View File

@ -605,6 +605,24 @@ const PopupMenuBase = new Lang.Class({
menuItem.actor.show();
},
moveMenuItem: function(menuItem, position) {
let items = this._getMenuItems();
let i = 0;
while (i < items.length && position > 0) {
if (items[i] != menuItem)
position--;
i++;
}
if (i < items.length) {
if (items[i] != menuItem)
this.box.set_child_below_sibling(menuItem.actor, items[i].actor);
} else {
this.box.set_child_above_sibling(menuItem.actor, null);
}
},
addMenuItem: function(menuItem, position) {
let before_item = null;
if (position == undefined) {
@ -767,6 +785,11 @@ const PopupMenu = new Lang.Class({
},
_onKeyPress: function(actor, event) {
// Disable toggling the menu by keyboard
// when it cannot be toggled by pointer
if (!actor.reactive)
return Clutter.EVENT_PROPAGATE;
let navKey;
switch (this._boxPointer.arrowSide) {
case St.Side.TOP:
@ -783,6 +806,16 @@ const PopupMenu = new Lang.Class({
break;
}
let state = event.get_state();
// if user has a modifier down (except capslock)
// then don't handle the key press here
state &= ~Clutter.ModifierType.LOCK_MASK;
state &= Clutter.ModifierType.MODIFIER_MASK;
if (state)
return Clutter.EVENT_PROPAGATE;
let symbol = event.get_key_symbol();
if (symbol == Clutter.KEY_space || symbol == Clutter.KEY_Return) {
this.toggle();

View File

@ -278,7 +278,8 @@ const RemoteSearchProvider = new Lang.Class({
name: metas[i]['name'],
description: metas[i]['description'],
createIcon: Lang.bind(this,
this.createIcon, metas[i]) });
this.createIcon, metas[i]),
clipboardText: metas[i]['clipboardText'] });
}
callback(resultMetas);
},

View File

@ -274,7 +274,7 @@ const RunDialog = new Lang.Class({
_restart: function() {
if (Meta.is_wayland_compositor()) {
this._showError('Restart is not available on Wayland');
this._showError(_("Restart is not available on Wayland"));
return;
}
this._shouldFadeOut = false;

View File

@ -33,6 +33,9 @@ const SCREENSAVER_SCHEMA = 'org.gnome.desktop.screensaver';
const LOCK_ENABLED_KEY = 'lock-enabled';
const LOCK_DELAY_KEY = 'lock-delay';
const LOCKDOWN_SCHEMA = 'org.gnome.desktop.lockdown';
const DISABLE_LOCK_KEY = 'disable-lock-screen';
const LOCKED_STATE_STR = 'screenShield.locked';
// fraction of screen height the arrow must reach before completing
// the slide up automatically
@ -541,6 +544,9 @@ const ScreenShield = new Lang.Class({
this._settings = new Gio.Settings({ schema_id: SCREENSAVER_SCHEMA });
this._settings.connect('changed::' + LOCK_ENABLED_KEY, Lang.bind(this, this._syncInhibitor));
this._lockSettings = new Gio.Settings({ schema_id: LOCKDOWN_SCHEMA });
this._lockSettings.connect('changed::' + DISABLE_LOCK_KEY, Lang.bind(this, this._syncInhibitor));
this._isModal = false;
this._hasLockScreen = false;
this._isGreeter = false;
@ -701,8 +707,10 @@ const ScreenShield = new Lang.Class({
},
_syncInhibitor: function() {
let lockEnabled = this._settings.get_boolean(LOCK_ENABLED_KEY);
let lockLocked = this._lockSettings.get_boolean(DISABLE_LOCK_KEY);
let inhibit = (this._loginSession && this._loginSession.Active &&
!this._isActive && this._settings.get_boolean(LOCK_ENABLED_KEY));
!this._isActive && lockEnabled && !lockLocked);
if (inhibit) {
this._loginManager.inhibit(_("GNOME needs to lock the screen"),
Lang.bind(this, function(inhibitor) {
@ -850,6 +858,7 @@ const ScreenShield = new Lang.Class({
},
_activateFade: function(lightbox, time) {
Main.uiGroup.set_child_above_sibling(lightbox.actor, null);
lightbox.show(time);
if (this._becameActiveId == 0)
@ -1289,6 +1298,11 @@ const ScreenShield = new Lang.Class({
},
lock: function(animate) {
if (this._lockSettings.get_boolean(DISABLE_LOCK_KEY)) {
log('Screen lock is locked down, not locking') // lock, lock - who's there?
return;
}
// Warn the user if we can't become modal
if (!this._becomeModal()) {
Main.notifyError(_("Unable to lock"),

View File

@ -152,6 +152,8 @@ const SearchResultsBase = new Lang.Class({
this._resultDisplays = {};
this._clipboard = St.Clipboard.get_default();
this._cancellable = new Gio.Cancellable();
},
@ -181,6 +183,8 @@ const SearchResultsBase = new Lang.Class({
_activateResult: function(result, id) {
this.provider.activateResult(id, this._terms);
if (result.metaInfo.clipboardText)
this._clipboard.set_text(St.ClipboardType.CLIPBOARD, result.metaInfo.clipboardText);
Main.overview.toggle();
},

View File

@ -380,7 +380,7 @@ const ShellMountPasswordDialog = new Lang.Class({
this.setInitialKeyFocus(this._passwordEntry);
this._errorMessageLabel = new St.Label({ style_class: 'prompt-dialog-error-label',
text: _("Sorry, that didn\'t work. Please try again.") });
text: _("Sorry, that didnt work. Please try again.") });
this._errorMessageLabel.clutter_text.ellipsize = Pango.EllipsizeMode.NONE;
this._errorMessageLabel.clutter_text.line_wrap = true;
this._errorMessageLabel.hide();

View File

@ -102,8 +102,8 @@ const ATIndicator = new Lang.Class({
if (this._syncMenuVisibilityIdle)
return;
this._syncMenuVisbilityIdle = Mainloop.idle_add(Lang.bind(this, this._syncMenuVisibility));
GLib.Source.set_name_by_id(this._syncMenuVisbilityIdle, '[gnome-shell] this._syncMenuVisibility');
this._syncMenuVisibilityIdle = Mainloop.idle_add(Lang.bind(this, this._syncMenuVisibility));
GLib.Source.set_name_by_id(this._syncMenuVisibilityIdle, '[gnome-shell] this._syncMenuVisibility');
},
_buildItemExtended: function(string, initial_value, writable, on_set) {

View File

@ -9,6 +9,7 @@ const Main = imports.ui.main;
const PanelMenu = imports.ui.panelMenu;
const PopupMenu = imports.ui.popupMenu;
const ModalDialog = imports.ui.modalDialog;
const PermissionStore = imports.misc.permissionStore;
const Shell = imports.gi.Shell;
const Signals = imports.signals;
const St = imports.gi.St;
@ -62,26 +63,6 @@ var AgentIface = '<node> \
</interface> \
</node>';
var PermissionStoreIface = '<node> \
<interface name="org.freedesktop.impl.portal.PermissionStore"> \
<method name="Lookup"> \
<arg name="table" type="s" direction="in"/> \
<arg name="id" type="s" direction="in"/> \
<arg name="permissions" type="a{sas}" direction="out"/> \
<arg name="data" type="v" direction="out"/> \
</method> \
<method name="Set"> \
<arg name="table" type="s" direction="in"/> \
<arg name="create" type="b" direction="in"/> \
<arg name="id" type="s" direction="in"/> \
<arg name="app_permissions" type="a{sas}" direction="in"/> \
<arg name="data" type="v" direction="in"/> \
</method> \
</interface> \
</node>';
const PermissionStore = Gio.DBusProxy.makeProxyWrapper(PermissionStoreIface);
const Indicator = new Lang.Class({
Name: 'LocationIndicator',
Extends: PanelMenu.SystemIndicator,
@ -253,10 +234,7 @@ const Indicator = new Lang.Class({
_connectToPermissionStore: function() {
this._permStoreProxy = null;
new PermissionStore(Gio.DBus.session,
'org.freedesktop.impl.portal.PermissionStore',
'/org/freedesktop/impl/portal/PermissionStore',
Lang.bind(this, this._onPermStoreProxyReady));
new PermissionStore.PermissionStore(Lang.bind(this, this._onPermStoreProxyReady), null);
},
_onPermStoreProxyReady: function(proxy, error) {
@ -284,6 +262,7 @@ const AppAuthorizer = new Lang.Class({
this.reqAccuracyLevel = reqAccuracyLevel;
this._permStoreProxy = permStoreProxy;
this._maxAccuracyLevel = maxAccuracyLevel;
this._permissions = {};
this._accuracyLevel = GeoclueAccuracyLevel.NONE;
},

View File

@ -40,6 +40,8 @@ const NMAccessPointSecurity = {
WPA2_ENT: 6
};
const MAX_DEVICE_ITEMS = 4;
// small optimization, to avoid using [] all the time
const NM80211Mode = NetworkManager['80211Mode'];
const NM80211ApFlags = NetworkManager['80211ApFlags'];
@ -297,11 +299,22 @@ const NMConnectionSection = new Lang.Class({
let item = this._connectionItems.get(connection.get_uuid());
if (item)
item.updateForConnection(connection);
this._updateForConnection(item, connection);
else
this._addConnection(connection);
},
_updateForConnection: function(item, connection) {
let pos = this._connections.indexOf(connection);
this._connections.splice(pos, 1);
pos = Util.insertSorted(this._connections, connection, Lang.bind(this, this._connectionSortFunction));
this._labelSection.moveMenuItem(item.labelItem, pos);
this._radioSection.moveMenuItem(item.radioItem, pos);
item.updateForConnection(connection);
},
_addConnection: function(connection) {
let item = this._makeConnectionItem(connection);
if (!item)
@ -756,6 +769,14 @@ const NMWirelessDialog = new Lang.Class({
this._scanTimeoutId = Mainloop.timeout_add_seconds(15, Lang.bind(this, this._onScanTimeout));
GLib.Source.set_name_by_id(this._scanTimeoutId, '[gnome-shell] this._onScanTimeout');
this._onScanTimeout();
let id = Main.sessionMode.connect('updated', () => {
if (Main.sessionMode.allowSettings)
return;
Main.sessionMode.disconnect(id);
this.close();
});
},
destroy: function() {
@ -1341,7 +1362,11 @@ const NMDeviceWireless = new Lang.Class({
if (!this._device.active_connection)
return false;
let connection = this._settings.get_connection_by_path(this._device.active_connection.connection);
let connectionPath = this._device.active_connection.connection;
if (!connectionPath)
return false;
let connection = this._settings.get_connection_by_path(connectionPath);
if (!connection)
return false;
@ -1418,7 +1443,7 @@ const NMVPNConnectionItem = new Lang.Class({
case NetworkManager.VPNConnectionState.PREPARE:
case NetworkManager.VPNConnectionState.CONNECT:
case NetworkManager.VPNConnectionState.IP_CONFIG_GET:
return _("connecting...");
return _("connecting");
case NetworkManager.VPNConnectionState.NEED_AUTH:
/* Translators: this is for network connections that require some kind of key or password */
return _("authentication required");
@ -1541,8 +1566,10 @@ const NMVPNSection = new Lang.Class({
item.setActiveConnection(null);
}
vpnConnections.forEach(Lang.bind(this, function(a) {
let item = this._connectionItems.get(a._connection.get_uuid());
item.setActiveConnection(a);
if (a._connection) {
let item = this._connectionItems.get(a._connection.get_uuid());
item.setActiveConnection(a);
}
}));
},
@ -1562,6 +1589,73 @@ const NMVPNSection = new Lang.Class({
});
Signals.addSignalMethods(NMVPNSection.prototype);
const DeviceCategory = new Lang.Class({
Name: 'DeviceCategory',
Extends: PopupMenu.PopupMenuSection,
_init: function(category) {
this.parent();
this._category = category;
this.devices = [];
this.section = new PopupMenu.PopupMenuSection();
this.section.box.connect('actor-added', Lang.bind(this, this._sync));
this.section.box.connect('actor-removed', Lang.bind(this, this._sync));
this.addMenuItem(this.section);
this._summaryItem = new PopupMenu.PopupSubMenuMenuItem('', true);
this._summaryItem.icon.icon_name = this._getSummaryIcon();
this.addMenuItem(this._summaryItem);
this._summaryItem.menu.addSettingsAction(_('Network Settings'),
'gnome-network-panel.desktop');
this._summaryItem.actor.hide();
},
_sync: function() {
let nDevices = this.section.box.get_children().reduce(
function(prev, child) {
return prev + (child.visible ? 1 : 0);
}, 0);
this._summaryItem.label.text = this._getSummaryLabel(nDevices);
let shouldSummarize = nDevices > MAX_DEVICE_ITEMS;
this._summaryItem.actor.visible = shouldSummarize;
this.section.actor.visible = !shouldSummarize;
},
_getSummaryIcon: function() {
switch(this._category) {
case NMConnectionCategory.WIRED:
return 'network-wired-symbolic';
case NMConnectionCategory.WIRELESS:
case NMConnectionCategory.WWAN:
return 'network-wireless-symbolic';
}
return '';
},
_getSummaryLabel: function(nDevices) {
switch(this._category) {
case NMConnectionCategory.WIRED:
return ngettext("%s Wired Connection",
"%s Wired Connections",
nDevices).format(nDevices);
case NMConnectionCategory.WIRELESS:
return ngettext("%s Wi-Fi Connection",
"%s Wi-Fi Connections",
nDevices).format(nDevices);
case NMConnectionCategory.WWAN:
return ngettext("%s Modem Connection",
"%s Modem Connections",
nDevices).format(nDevices);
}
return '';
}
});
const NMApplet = new Lang.Class({
Name: 'NMApplet',
Extends: PanelMenu.SystemIndicator,
@ -1605,15 +1699,6 @@ const NMApplet = new Lang.Class({
this._tryLateInit();
},
_createDeviceCategory: function() {
let category = {
section: new PopupMenu.PopupMenuSection(),
devices: [ ],
};
this.menu.addMenuItem(category.section);
return category;
},
_tryLateInit: function() {
if (!this._client || !this._settings)
return;
@ -1630,9 +1715,13 @@ const NMApplet = new Lang.Class({
this._nmDevices = [];
this._devices = { };
this._devices.wired = this._createDeviceCategory();
this._devices.wireless = this._createDeviceCategory();
this._devices.wwan = this._createDeviceCategory();
let categories = [NMConnectionCategory.WIRED,
NMConnectionCategory.WIRELESS,
NMConnectionCategory.WWAN];
for (let category of categories) {
this._devices[category] = new DeviceCategory(category);
this.menu.addMenuItem(this._devices[category]);
}
this._vpnSection = new NMVPNSection(this._client);
this._vpnSection.connect('activation-failed', Lang.bind(this, this._onActivationFailed));
@ -1989,7 +2078,7 @@ const NMApplet = new Lang.Class({
// (but in general we should only prompt a portal if we know there is a portal)
if (GLib.getenv('GNOME_SHELL_CONNECTIVITY_TEST') != null)
isPortal = isPortal || this._client.connectivity < NetworkManager.ConnectivityState.FULL;
if (!isPortal)
if (!isPortal || Main.sessionMode.isGreeter)
return;
let path = this._mainConnection.get_path();
@ -2020,13 +2109,24 @@ const NMApplet = new Lang.Class({
},
_updateIcon: function() {
if (!this._client.networking_enabled || !this._mainConnection) {
if (!this._client.networking_enabled) {
this._primaryIndicator.visible = false;
} else {
let dev = this._mainConnection._primaryDevice;
this._primaryIndicator.visible = (dev != null);
if (dev)
let dev = null;
if (this._mainConnection)
dev = this._mainConnection._primaryDevice;
let state = this._client.get_state();
let connected = state == NetworkManager.State.CONNECTED_GLOBAL;
this._primaryIndicator.visible = (dev != null) || connected;
if (dev) {
this._primaryIndicator.icon_name = dev.getIndicatorIcon();
} else if (connected) {
if (this._client.connectivity == NetworkManager.ConnectivityState.FULL)
this._primaryIndicator.icon_name = 'network-wired-symbolic';
else
this._primaryIndicator.icon_name = 'network-wired-no-route-symbolic';
}
}
this._vpnIndicator.icon_name = this._vpnSection.getIndicatorIcon();

View File

@ -0,0 +1,74 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
const Gio = imports.gi.Gio;
const Lang = imports.lang;
const Main = imports.ui.main;
const PanelMenu = imports.ui.panelMenu;
const PopupMenu = imports.ui.popupMenu;
const BUS_NAME = 'org.gnome.SettingsDaemon.Color';
const OBJECT_PATH = '/org/gnome/SettingsDaemon/Color';
const ColorInterface = '<node> \
<interface name="org.gnome.SettingsDaemon.Color"> \
<property name="DisabledUntilTomorrow" type="b" access="readwrite"/> \
<property name="NightLightActive" type="b" access="read"/> \
</interface> \
</node>';
const ColorProxy = Gio.DBusProxy.makeProxyWrapper(ColorInterface);
const Indicator = new Lang.Class({
Name: 'NightLightIndicator',
Extends: PanelMenu.SystemIndicator,
_init: function() {
this.parent();
this._indicator = this._addIndicator();
this._indicator.icon_name = 'night-light-symbolic';
this._proxy = new ColorProxy(Gio.DBus.session, BUS_NAME, OBJECT_PATH,
(proxy, error) => {
if (error) {
log(error.message);
return;
}
this._proxy.connect('g-properties-changed',
Lang.bind(this, this._sync));
this._sync();
});
this._item = new PopupMenu.PopupSubMenuMenuItem("", true);
this._item.icon.icon_name = 'night-light-symbolic';
this._disableItem = this._item.menu.addAction('', () => {
this._proxy.DisabledUntilTomorrow = !this._proxy.DisabledUntilTomorrow;
});
this._item.menu.addAction(_("Turn Off"), () => {
let settings = new Gio.Settings({ schema_id: 'org.gnome.settings-daemon.plugins.color' });
settings.set_boolean('night-light-enabled', false);
});
this._item.menu.addSettingsAction(_("Display Settings"), 'gnome-display-panel.desktop');
this.menu.addMenuItem(this._item);
Main.sessionMode.connect('updated', Lang.bind(this, this._sessionUpdated));
this._sessionUpdated();
this._sync();
},
_sessionUpdated: function() {
let sensitive = !Main.sessionMode.isLocked && !Main.sessionMode.isGreeter;
this.menu.setSensitive(sensitive);
},
_sync: function() {
let visible = this._proxy.NightLightActive;
let disabled = this._proxy.DisabledUntilTomorrow;
this._item.label.text = disabled ? _("Night Light Disabled")
: _("Night Light On");
this._disableItem.label.text = disabled ? _("Resume")
: _("Disable Until Tomorrow");
this._item.actor.visible = this._indicator.visible = visible;
}
});

View File

@ -48,8 +48,14 @@ const AltSwitcher = new Lang.Class({
this._capturedEventId = global.stage.connect('captured-event', Lang.bind(this, this._onCapturedEvent));
this._flipped = false;
this._clickAction = new Clutter.ClickAction();
this._clickAction.connect('long-press', Lang.bind(this, this._onLongPress));
this.actor = new St.Bin();
this.actor.connect('destroy', Lang.bind(this, this._onDestroy));
this.actor.connect('notify::mapped', () => { this._flipped = false; });
},
_sync: function() {
@ -58,14 +64,25 @@ const AltSwitcher = new Lang.Class({
if (this._standard.visible && this._alternate.visible) {
let [x, y, mods] = global.get_pointer();
let altPressed = (mods & Clutter.ModifierType.MOD1_MASK) != 0;
childToShow = altPressed ? this._alternate : this._standard;
if (this._flipped)
childToShow = altPressed ? this._standard : this._alternate;
else
childToShow = altPressed ? this._alternate : this._standard;
} else if (this._standard.visible) {
childToShow = this._standard;
} else if (this._alternate.visible) {
childToShow = this._alternate;
}
if (this.actor.get_child() != childToShow) {
let childShown = this.actor.get_child();
if (childShown != childToShow) {
if (childShown) {
if (childShown.fake_release)
childShown.fake_release();
childShown.remove_action(this._clickAction);
}
childToShow.add_action(this._clickAction);
let hasFocus = this.actor.contains(global.stage.get_key_focus());
this.actor.set_child(childToShow);
if (hasFocus)
@ -96,6 +113,16 @@ const AltSwitcher = new Lang.Class({
return Clutter.EVENT_PROPAGATE;
},
_onLongPress: function(action, actor, state) {
if (state == Clutter.LongPressState.QUERY ||
state == Clutter.LongPressState.CANCEL)
return true;
this._flipped = !this._flipped;
this._sync();
return true;
}
});
const Indicator = new Lang.Class({

View File

@ -10,6 +10,7 @@ const Signals = imports.signals;
const Lang = imports.lang;
const Shell = imports.gi.Shell;
const St = imports.gi.St;
const GObject = imports.gi.GObject;
const AppDisplay = imports.ui.appDisplay;
const Main = imports.ui.main;
@ -23,6 +24,7 @@ const EdgeDragAction = imports.ui.edgeDragAction;
const IconGrid = imports.ui.iconGrid;
const SHELL_KEYBINDINGS_SCHEMA = 'org.gnome.shell.keybindings';
const PINCH_GESTURE_THRESHOLD = 0.7;
const ViewPage = {
WINDOWS: 1,
@ -51,9 +53,32 @@ function getTermsForSearchString(searchString) {
return terms;
}
const TouchpadShowOverviewAction = new Lang.Class({
Name: 'TouchpadShowOverviewAction',
_init: function(actor) {
actor.connect('captured-event', Lang.bind(this, this._handleEvent));
},
_handleEvent: function(actor, event) {
if (event.type() != Clutter.EventType.TOUCHPAD_PINCH)
return Clutter.EVENT_PROPAGATE;
if (event.get_touchpad_gesture_finger_count() != 3)
return Clutter.EVENT_PROPAGATE;
if (event.get_gesture_phase() == Clutter.TouchpadGesturePhase.END)
this.emit('activated', event.get_gesture_pinch_scale ());
return Clutter.EVENT_STOP;
}
});
Signals.addSignalMethods(TouchpadShowOverviewAction.prototype);
const ShowOverviewAction = new Lang.Class({
Name: 'ShowOverviewAction',
Extends: Clutter.GestureAction,
Signals: { 'activated': { param_types: [GObject.TYPE_DOUBLE] } },
_init : function() {
this.parent();
@ -112,7 +137,6 @@ const ShowOverviewAction = new Lang.Class({
this.emit('activated', areaDiff);
}
});
Signals.addSignalMethods(ShowOverviewAction.prototype);
const ViewSelector = new Lang.Class({
Name: 'ViewSelector',
@ -230,11 +254,16 @@ const ViewSelector = new Lang.Class({
global.stage.add_action(gesture);
gesture = new ShowOverviewAction();
gesture.connect('activated', Lang.bind(this, function(action, areaDiff) {
if (areaDiff < 0.7)
Main.overview.show();
}));
gesture.connect('activated', Lang.bind(this, this._pinchGestureActivated));
global.stage.add_action(gesture);
gesture = new TouchpadShowOverviewAction(global.stage);
gesture.connect('activated', Lang.bind(this, this._pinchGestureActivated));
},
_pinchGestureActivated: function(action, scale) {
if (scale < PINCH_GESTURE_THRESHOLD)
Main.overview.show();
},
_toggleAppsPage: function() {

View File

@ -17,6 +17,8 @@ const Main = imports.ui.main;
const ModalDialog = imports.ui.modalDialog;
const Tweener = imports.ui.tweener;
const WindowMenu = imports.ui.windowMenu;
const PadOsd = imports.ui.padOsd;
const EdgeDragAction = imports.ui.edgeDragAction;
const SHELL_KEYBINDINGS_SCHEMA = 'org.gnome.shell.keybindings';
const MINIMIZE_WINDOW_ANIMATION_TIME = 0.2;
@ -32,6 +34,25 @@ const UNDIM_TIME = 0.250;
const DISPLAY_REVERT_TIMEOUT = 20; // in seconds - keep in sync with mutter
const ONE_SECOND = 1000; // in ms
const GSD_WACOM_BUS_NAME = 'org.gnome.SettingsDaemon.Wacom';
const GSD_WACOM_OBJECT_PATH = '/org/gnome/SettingsDaemon/Wacom';
const GsdWacomIface = '<node name="/org/gnome/SettingsDaemon/Wacom"> \
<interface name="org.gnome.SettingsDaemon.Wacom"> \
<method name="SetGroupModeLED"> \
<arg name="device_path" direction="in" type="s"/> \
<arg name="group" direction="in" type="u"/> \
<arg name="mode" direction="in" type="u"/> \
</method> \
<method name="SetOLEDLabels"> \
<arg name="device_path" direction="in" type="s"/> \
<arg name="labels" direction="in" type="as"/> \
</method> \
</interface> \
</node>';
const GsdWacomProxy = Gio.DBusProxy.makeProxyWrapper(GsdWacomIface);
const DisplayChangeDialog = new Lang.Class({
Name: 'DisplayChangeDialog',
Extends: ModalDialog.ModalDialog,
@ -510,7 +531,7 @@ const TouchpadWorkspaceSwitchAction = new Lang.Class({
if (event.type() != Clutter.EventType.TOUCHPAD_SWIPE)
return Clutter.EVENT_PROPAGATE;
if (event.get_gesture_swipe_finger_count() != 4)
if (event.get_touchpad_gesture_finger_count() != 4)
return Clutter.EVENT_PROPAGATE;
if (event.get_gesture_phase() == Clutter.TouchpadGesturePhase.UPDATE) {
@ -534,6 +555,7 @@ Signals.addSignalMethods(TouchpadWorkspaceSwitchAction.prototype);
const WorkspaceSwitchAction = new Lang.Class({
Name: 'WorkspaceSwitchAction',
Extends: Clutter.SwipeAction,
Signals: { 'activated': { param_types: [Meta.MotionDirection.$gtype] } },
_init : function() {
const MOTION_THRESHOLD = 50;
@ -571,11 +593,11 @@ const WorkspaceSwitchAction = new Lang.Class({
this.emit('activated', dir);
}
});
Signals.addSignalMethods(WorkspaceSwitchAction.prototype);
const AppSwitchAction = new Lang.Class({
Name: 'AppSwitchAction',
Extends: Clutter.GestureAction,
Signals: { 'activated': {} },
_init : function() {
this.parent();
@ -637,7 +659,6 @@ const AppSwitchAction = new Lang.Class({
return true;
}
});
Signals.addSignalMethods(AppSwitchAction.prototype);
const ResizePopup = new Lang.Class({
Name: 'ResizePopup',
@ -655,7 +676,7 @@ const ResizePopup = new Lang.Class({
set: function(rect, displayW, displayH) {
/* Translators: This represents the size of a window. The first number is
* the width of the window and the second is the height. */
let text = _("%d x %d").format(displayW, displayH);
let text = _("%d × %d").format(displayW, displayH);
this._label.set_text(text);
this._widget.set_position(rect.x, rect.y);
@ -705,6 +726,7 @@ const WindowManager = new Lang.Class({
this._shellwm.connect('minimize', Lang.bind(this, this._minimizeWindow));
this._shellwm.connect('unminimize', Lang.bind(this, this._unminimizeWindow));
this._shellwm.connect('size-change', Lang.bind(this, this._sizeChangeWindow));
this._shellwm.connect('size-changed', Lang.bind(this, this._sizeChangedWindow));
this._shellwm.connect('map', Lang.bind(this, this._mapWindow));
this._shellwm.connect('destroy', Lang.bind(this, this._destroyWindow));
this._shellwm.connect('filter-keybinding', Lang.bind(this, this._filterKeybinding));
@ -917,6 +939,35 @@ const WindowManager = new Lang.Class({
Lang.bind(this, this._toggleCalendar));
global.display.connect('show-resize-popup', Lang.bind(this, this._showResizePopup));
global.display.connect('show-pad-osd', Lang.bind(this, this._showPadOsd));
global.display.connect('show-osd', Lang.bind(this, function (display, monitorIndex, iconName, label) {
let icon = Gio.Icon.new_for_string(iconName);
Main.osdWindowManager.show(monitorIndex, icon, label, null);
}));
this._gsdWacomProxy = new GsdWacomProxy(Gio.DBus.session, GSD_WACOM_BUS_NAME,
GSD_WACOM_OBJECT_PATH,
Lang.bind(this, function(proxy, error) {
if (error) {
log(error.message);
return;
}
}));
global.display.connect('pad-mode-switch', Lang.bind(this, function (display, pad, group, mode) {
let labels = [];
//FIXME: Fix num buttons
for (let i = 0; i < 50; i++) {
let str = display.get_pad_action_label(pad, Meta.PadActionType.BUTTON, i);
labels.push(str ? str: '');
}
if (this._gsdWacomProxy) {
this._gsdWacomProxy.SetOLEDLabelsRemote(pad.get_device_node(), labels);
this._gsdWacomProxy.SetGroupModeLEDRemote(pad.get_device_node(), group, mode);
}
}));
Main.overview.connect('showing', Lang.bind(this, function() {
for (let i = 0; i < this._dimmedWindows.length; i++)
@ -947,6 +998,18 @@ const WindowManager = new Lang.Class({
gesture.connect('activated', Lang.bind(this, this._switchApp));
global.stage.add_action(gesture);
gesture = new EdgeDragAction.EdgeDragAction(St.Side.BOTTOM, Shell.ActionMode.ALL);
gesture.connect('activated', Lang.bind(this, function() {
Main.keyboard.show(Main.layoutManager.bottomIndex);
}));
global.stage.add_action(gesture);
},
_showPadOsd: function (display, device, settings, imagePath, editionMode, monitorIndex) {
this._currentPadOsd = new PadOsd.PadOsd(device, settings, imagePath, editionMode, monitorIndex);
this._currentPadOsd.connect('closed', Lang.bind(this, function() { this._currentPadOsd = null }));
return this._currentPadOsd.actor;
},
_actionSwitchWorkspace: function(action, direction) {
@ -1073,6 +1136,9 @@ const WindowManager = new Lang.Class({
if (!this._shouldAnimate())
return false;
if (!actor.get_texture())
return false;
let type = actor.meta_window.get_window_type();
return types.indexOf(type) >= 0;
},
@ -1247,37 +1313,17 @@ const WindowManager = new Lang.Class({
return;
}
if (whichChange == Meta.SizeChange.FULLSCREEN)
this._fullscreenWindow(shellwm, actor, oldFrameRect, oldBufferRect);
else if (whichChange == Meta.SizeChange.UNFULLSCREEN)
this._unfullscreenWindow(shellwm, actor, oldFrameRect, oldBufferRect);
if ((whichChange == Meta.SizeChange.FULLSCREEN ||
whichChange == Meta.SizeChange.UNFULLSCREEN) &&
oldFrameRect.width > 0 && oldFrameRect.height > 0)
this._fullscreenAnimation(shellwm, actor, oldFrameRect, whichChange);
else
shellwm.completed_size_change(actor);
},
_fullscreenWindow: function(shellwm, actor, oldFrameRect, oldBufferRect) {
let monitor = Main.layoutManager.monitors[actor.meta_window.get_monitor()];
actor.translation_x = oldFrameRect.x - monitor.x;
actor.translation_y = oldFrameRect.y - monitor.y;
this._fullscreenAnimation(shellwm, actor, oldFrameRect);
},
_unfullscreenWindow: function(shellwm, actor, oldFrameRect, oldBufferRect) {
let targetRect = actor.meta_window.get_frame_rect();
let monitor = Main.layoutManager.monitors[actor.meta_window.get_monitor()];
actor.translation_x = -(targetRect.x - monitor.x);
actor.translation_y = -(targetRect.y - monitor.y);
this._fullscreenAnimation(shellwm, actor, oldFrameRect);
},
_fullscreenAnimation: function(shellwm, actor, oldFrameRect) {
this._resizing.push(actor);
_fullscreenAnimation: function(shellwm, actor, oldFrameRect, change) {
// Position a clone of the window on top of the old position,
// while actor updates are frozen.
// Note that the MetaWindow has up to date sizing information for
// the new geometry already.
let targetRect = actor.meta_window.get_frame_rect();
let actorContent = Shell.util_get_content_for_window_actor(actor, oldFrameRect);
let actorClone = new St.Widget({ content: actorContent });
actorClone.set_offscreen_redirect(Clutter.OffscreenRedirect.ALWAYS);
@ -1285,10 +1331,28 @@ const WindowManager = new Lang.Class({
actorClone.set_size(oldFrameRect.width, oldFrameRect.height);
Main.uiGroup.add_actor(actorClone);
actor.__fullscreenClone = actorClone;
let rect = change == Meta.SizeChange.FULLSCREEN ? oldFrameRect : null;
let scaleX = targetRect.width / oldFrameRect.width;
let scaleY = targetRect.height / oldFrameRect.height;
if (this._clearFullscreenInfo(actor))
this._shellwm.completed_size_change(actor);
actor.__fullscreenInfo = { clone: actorClone,
oldRect: rect };
},
_sizeChangedWindow: function(shellwm, actor) {
if (!actor.__fullscreenInfo)
return;
if (this._resizing.indexOf(actor) != -1)
return;
let actorClone = actor.__fullscreenInfo.clone;
let targetRect = actor.meta_window.get_frame_rect();
let scaleX = targetRect.width / actorClone.width;
let scaleY = targetRect.height / actorClone.height;
this._resizing.push(actor);
// Now scale and fade out the clone
Tweener.addTween(actorClone,
@ -1301,9 +1365,17 @@ const WindowManager = new Lang.Class({
transition: 'easeOutQuad'
});
let monitor = Main.layoutManager.monitors[actor.meta_window.get_monitor()];
let oldRect = actor.__fullscreenInfo.oldRect;
if (oldRect) {
actor.translation_x = oldRect.x - monitor.x;
actor.translation_y = oldRect.y - monitor.y;
} else {
actor.translation_x = -(targetRect.x - monitor.x);
actor.translation_y = -(targetRect.y - monitor.y);
}
// Now set scale the actor to size it as the clone.
// Note that the caller of this function already set a translation
// on the actor.
actor.scale_x = 1 / scaleX;
actor.scale_y = 1 / scaleY;
@ -1329,6 +1401,15 @@ const WindowManager = new Lang.Class({
shellwm.completed_size_change(actor);
},
_clearFullscreenInfo: function(actor) {
if (actor.__fullscreenInfo) {
actor.__fullscreenInfo.clone.destroy();
delete actor.__fullscreenInfo;
return true;
}
return false;
},
_sizeChangeWindowDone: function(shellwm, actor) {
if (this._removeEffect(this._resizing, actor)) {
Tweener.removeTweens(actor);
@ -1336,23 +1417,13 @@ const WindowManager = new Lang.Class({
actor.scale_y = 1.0;
actor.translation_x = 0;
actor.translation_y = 0;
let actorClone = actor.__fullscreenClone;
if (actorClone) {
actorClone.destroy();
delete actor.__fullscreenClone;
}
this._clearFullscreenInfo(actor);
}
},
_sizeChangeWindowOverwritten: function(shellwm, actor) {
if (this._removeEffect(this._resizing, actor)) {
let actorClone = actor.__fullscreenClone;
if (actorClone) {
actorClone.destroy();
delete actor.__fullscreenClone;
}
}
if (this._removeEffect(this._resizing, actor))
this._clearFullscreenInfo(actor);
},
_hasAttachedDialogs: function(window, ignoreWindow) {

View File

@ -97,8 +97,6 @@ const WindowMenu = new Lang.Class({
if (window.is_always_on_all_workspaces())
item.setSensitive(false);
let nWorkspaces = global.screen.n_workspaces;
if (!isSticky) {
let workspace = window.get_workspace();
if (workspace != workspace.get_neighbor(Meta.MotionDirection.LEFT)) {

View File

@ -111,7 +111,7 @@ const WindowClone = new Lang.Class({
this.metaWindow._delegate = this;
this._workspace = workspace;
this._windowClone = new Clutter.Clone({ source: realWindow.get_texture() });
this._windowClone = new Clutter.Clone({ source: realWindow });
// We expect this.actor to be used for all interaction rather than
// this._windowClone; as the former is reactive and the latter
// is not, this just works for most cases. However, for DND all
@ -471,6 +471,10 @@ const WindowOverlay = new Lang.Class({
this.title = title;
this.closeButton = button;
// Don't block drop targets
Shell.util_set_hidden_from_pick(this.title, true);
Shell.util_set_hidden_from_pick(this.border, true);
parentActor.add_actor(this.title);
parentActor.add_actor(this.border);
parentActor.add_actor(this.closeButton);

View File

@ -24,9 +24,10 @@ const XdndHandler = new Lang.Class({
if (!Meta.is_wayland_compositor())
global.init_xdnd();
global.connect('xdnd-enter', Lang.bind(this, this._onEnter));
global.connect('xdnd-position-changed', Lang.bind(this, this._onPositionChanged));
global.connect('xdnd-leave', Lang.bind(this, this._onLeave));
var dnd = Meta.get_backend().get_dnd();
dnd.connect('dnd-enter', Lang.bind(this, this._onEnter));
dnd.connect('dnd-position-change', Lang.bind(this, this._onPositionChanged));
dnd.connect('dnd-leave', Lang.bind(this, this._onLeave));
this._windowGroupVisibilityHandlerId = 0;
},

View File

@ -39,6 +39,7 @@ js/ui/mpris.js
js/ui/notificationDaemon.js
js/ui/overviewControls.js
js/ui/overview.js
js/ui/padOsd.js
js/ui/panel.js
js/ui/popupMenu.js
js/ui/runDialog.js
@ -52,6 +53,7 @@ js/ui/status/brightness.js
js/ui/status/keyboard.js
js/ui/status/location.js
js/ui/status/network.js
js/ui/status/nightLight.js
js/ui/status/power.js
js/ui/status/rfkill.js
js/ui/status/system.js

1301
po/ar.po

File diff suppressed because it is too large Load Diff

2495
po/be.po

File diff suppressed because it is too large Load Diff

1481
po/ca.po

File diff suppressed because it is too large Load Diff

697
po/cs.po

File diff suppressed because it is too large Load Diff

807
po/da.po

File diff suppressed because it is too large Load Diff

755
po/de.po

File diff suppressed because it is too large Load Diff

830
po/el.po

File diff suppressed because it is too large Load Diff

788
po/es.po

File diff suppressed because it is too large Load Diff

718
po/eu.po

File diff suppressed because it is too large Load Diff

View File

@ -1674,7 +1674,7 @@ msgstr "تقویم اوولوشن"
#. Translators: Do NOT translate or transliterate this text (this is an icon file name)!
#: src/calendar-server/evolution-calendar.desktop.in:6
msgid "evolution"
msgstr "اوولوشن"
msgstr "evolution"
#. translators:
#. * The number of sound outputs on a particular device

790
po/fi.po

File diff suppressed because it is too large Load Diff

726
po/fr.po

File diff suppressed because it is too large Load Diff

719
po/fur.po

File diff suppressed because it is too large Load Diff

357
po/gd.po
View File

@ -1,14 +1,14 @@
# Scottish Gaelic translation for gnome-shell.
# Copyright (C) 2015 gnome-shell's COPYRIGHT HOLDER
# This file is distributed under the same license as the gnome-shell package.
# GunChleoc <fios@foramnagaidhlig.net>, 2015, 2016.
# GunChleoc <fios@foramnagaidhlig.net>, 2015, 2016, 2017.
msgid ""
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: 2016-09-12 23:57+0000\n"
"PO-Revision-Date: 2016-09-13 10:47+0100\n"
"Report-Msgid-Bugs-To: https://bugzilla.gnome.org/enter_bug.cgi?product"
"=gnome-shell&keywords=I18N+L10N&component=general\n"
"POT-Creation-Date: 2017-03-02 17:53+0000\n"
"PO-Revision-Date: 2017-03-07 12:03+0100\n"
"Last-Translator: GunChleoc <fios@foramnagaidhlig.net>\n"
"Language-Team: Fòram na Gàidhlig\n"
"Language: gd\n"
@ -61,10 +61,136 @@ msgstr "Slige GNOME"
msgid "Window management and application launching"
msgstr "Stiùireadh uinneagan is tòiseachadh aplacaidean"
#: data/org.gnome.shell.gschema.xml.in:6
msgid "Enable internal tools useful for developers and testers from Alt-F2"
msgstr "Cuir an comas innealan an luchd-leasachaidh 's deuchainne o Alt-F2"
#: data/org.gnome.shell.gschema.xml.in:9
msgid ""
"Allows access to internal debugging and monitoring tools using the Alt-F2 "
"dialog."
msgstr ""
"Ceadaich inntrigeadh dha na h-innealan a chum dì-bhugachaidh 's sgrùdaidh le "
"còmhradh Alt-F2."
#: data/org.gnome.shell.gschema.xml.in:16
msgid "UUIDs of extensions to enable"
msgstr "UUIDs nan leudachan ri an cur an comas"
#: data/org.gnome.shell.gschema.xml.in:17
msgid ""
"GNOME Shell extensions have a UUID property; this key lists extensions which "
"should be loaded. Any extension that wants to be loaded needs to be in this "
"list. You can also manipulate this list with the EnableExtension and "
"DisableExtension D-Bus methods on org.gnome.Shell."
msgstr ""
"Tha buadh UUID aig leudachain na Slige GNOME; seallaidh an iuchair sin na "
"leudachain a bu chòir luchdadh. Feumaidh gach leudachan a tha ag iarraidh "
"luchdadh a bhith air an liosta seo. 'S urrainn dhut an liosta seo "
"atharrachadh cuideachd leis na modhan D-Bus EnableExtension agus "
"DisableExtension air org.gnome.Shell."
#: data/org.gnome.shell.gschema.xml.in:26
msgid "Disables the validation of extension version compatibility"
msgstr ""
"Cuiridh seo à comas dearbhadh na co-chòrdalachd airson tionndadh nan "
"leudachan"
#: data/org.gnome.shell.gschema.xml.in:27
msgid ""
"GNOME Shell will only load extensions that claim to support the current "
"running version. Enabling this option will disable this check and try to "
"load all extensions regardless of the versions they claim to support."
msgstr ""
"Cha luchdaich an t-Slige GNOME ach leudachain a dh'innseas gu bheil iar co-"
"chòrdail leis an tionndadh a tha 'ga ruith. Ma chuireas tu an roghainn seo "
"an comas, thèid an dearbhadh a chur à comas agus feuchaidh sinn ris a h-uile "
"leudachan a luchdadh ge b' e dè na tionndaidhean ris an cuir iad taic dhan "
"rèir-san."
#: data/org.gnome.shell.gschema.xml.in:35
msgid "List of desktop file IDs for favorite applications"
msgstr ""
"Liosta dhe IDan nam faidhlichean desktop airson nan aplacaidean as annsa "
"leat"
#: data/org.gnome.shell.gschema.xml.in:36
msgid ""
"The applications corresponding to these identifiers will be displayed in the "
"favorites area."
msgstr ""
"Thèid na h-aplacaidean a fhreagras ris na h-aithnichearan seo a shealltainn "
"air raon nan annsachdan."
#: data/org.gnome.shell.gschema.xml.in:43
msgid "App Picker View"
msgstr "Sealladh roghnaichear nan aplacaid"
#: data/org.gnome.shell.gschema.xml.in:44
msgid "Index of the currently selected view in the application picker."
msgstr "Inneacs an t-seallaidh làithrich ann an roghnaichear nan aplacaid."
#: data/org.gnome.shell.gschema.xml.in:50
msgid "History for command (Alt-F2) dialog"
msgstr "Eachdraidh a' chòmhraidh-àithne (Alt-F2)"
#. Translators: looking glass is a debugger and inspector tool, see https://wiki.gnome.org/Projects/GnomeShell/LookingGlass
#: data/org.gnome.shell.gschema.xml.in:55
msgid "History for the looking glass dialog"
msgstr "Eachdraidh a' chomhraidh aig looking glass"
#: data/org.gnome.shell.gschema.xml.in:59
msgid "Always show the 'Log out' menu item in the user menu."
msgstr ""
"Seall nì \"Clàraich a-mach\" air clàr-taice a' chleachdaiche an-còmhnaidh."
#: data/org.gnome.shell.gschema.xml.in:60
msgid ""
"This key overrides the automatic hiding of the 'Log out' menu item in single-"
"user, single-session situations."
msgstr ""
"Tar-àithnidh an iuchair seo am falach fèin-obrachail aig \"Clàraich a-mach\" "
"air a' chlar-taice ann an suidheachaidhean le aon chleachdaiche 's aon "
"seisean a-mhàin."
#: data/org.gnome.shell.gschema.xml.in:67
msgid ""
"Whether to remember password for mounting encrypted or remote filesystems"
msgstr ""
"Co-dhiù an dèid am facal-faire a chuimhneachadh airson munntachadh "
"shiostaman-fhaidhlichean crioptaichte no cèine"
#: data/org.gnome.shell.gschema.xml.in:68
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 "
"'Remember Password' checkbox will be present. This key sets the default "
"state of the checkbox."
msgstr ""
"Iarraidh an t-slige facal-fàire ort nuair a thèid siostam-fhaidhlichean "
"crioptaichte no cèin a mhunntachadh. Ma ghabhas am facal-faire sàbhaladh "
"airson na h-ama ri teachd, bidh bogsa-còmhraige \"Cuimhnich am facal-fàire\" "
"ann. Suidhichidh an iuchair seo staid tùsail na bogsa-còmhraige ud."
#: data/org.gnome.shell.gschema.xml.in:77
msgid ""
"Whether the default Bluetooth adapter had set up devices associated to it"
msgstr ""
"Co-dhiù an robh uidheaman co-cheangailte ris an adaptar Bluetooth gus nach "
"robh"
#: data/org.gnome.shell.gschema.xml.in:78
msgid ""
"The shell will only show a Bluetooth menu item if a Bluetooth adapter is "
"powered, or if there were devices set up associated with the default "
"adapter. This will be reset if the default adapter is ever seen not to have "
"devices associated to it."
msgstr ""
"Cha seall an t-slige nì clàir-taice \"Bluetooth\" ach ma tha cumhachd aig "
"adaptar Bluetooth na ma chaidh uidheaman co-cheangailte ris an adaptar "
"tùsail roimhe. Thèid seo ath-shuidheachadh ma chithear an t-adaptar tùsail "
"gun uidheam co-cheangailte ris."
#: data/org.gnome.shell.gschema.xml.in:93
msgid "Keybinding to open the application menu"
msgstr "Nasgadh iuchrach gus clàr-taice na h-aplacaid fhosgladh"
@ -74,12 +200,10 @@ msgid "Keybinding to open the application menu."
msgstr "Nasgadh iuchrach gus clàr-taice na h-aplacaid fhosgladh."
#: data/org.gnome.shell.gschema.xml.in:100
#| msgid "Keybinding to open the application menu"
msgid "Keybinding to open the \"Show Applications\" view"
msgstr "Nasgadh iuchrach gus an sealladh \"Seall aplacaidean\" fhosgladh"
#: data/org.gnome.shell.gschema.xml.in:101
#| msgid "Keybinding to open the application menu."
msgid ""
"Keybinding to open the \"Show Applications\" view of the Activities Overview."
msgstr ""
@ -87,23 +211,19 @@ msgstr ""
"gnìomhachd fhosgladh."
#: data/org.gnome.shell.gschema.xml.in:108
#| msgid "Keybinding to open the application menu"
msgid "Keybinding to open the overview"
msgstr "Nasgadh iuchrach gus am foir-shealladh fhosgladh"
#: data/org.gnome.shell.gschema.xml.in:109
#| msgid "Keybinding to open the application menu."
msgid "Keybinding to open the Activities Overview."
msgstr "Nasgadh iuchrach gus foir-shealladh na gnìomhachd fhosgladh."
#: data/org.gnome.shell.gschema.xml.in:115
#| msgid "Keybinding to focus the active notification"
msgid "Keybinding to toggle the visibility of the notification list"
msgstr ""
"Nasgadh iuchrach gus an fhaicsinneachd air liosta nam brathan a thoglachadh"
#: data/org.gnome.shell.gschema.xml.in:116
#| msgid "Keybinding to focus the active notification."
msgid "Keybinding to toggle the visibility of the notification list."
msgstr ""
"Nasgadh iuchrach gus an fhaicsinneachd air liosta nam brathan a thoglachadh."
@ -116,10 +236,94 @@ msgstr "Nasgadh iuchrach gus am fòcas a chur air a' bhrath ghnìomhach"
msgid "Keybinding to focus the active notification."
msgstr "Nasgadh iuchrach gus am fòcas a chur air a' bhrath ghnìomhach."
#: data/org.gnome.shell.gschema.xml.in:129
msgid ""
"Keybinding that pauses and resumes all running tweens, for debugging purposes"
msgstr ""
"Nasgadh iuchrach a chuir gach tween a tha 'ga ruith 'na stad 's a "
"thòisicheas orra a-rithist a chum dì-bhugachaidh"
#: data/org.gnome.shell.gschema.xml.in:138
msgid "Which keyboard to use"
msgstr "Am meur-chlàr ri chleachdadh"
#: data/org.gnome.shell.gschema.xml.in:139
msgid "The type of keyboard to use."
msgstr "An seòrsa de mheur-chlàr a thèid a chleachdadh."
#: data/org.gnome.shell.gschema.xml.in:150
#: data/org.gnome.shell.gschema.xml.in:177
msgid "Limit switcher to current workspace."
msgstr "Cuingich an t-suidsear air an rum-obrach làithreach."
#: data/org.gnome.shell.gschema.xml.in:151
msgid ""
"If true, only applications that have windows on the current workspace are "
"shown in the switcher. Otherwise, all applications are included."
msgstr ""
"Mas e true a th' ann, cha dèid a shealltainn san t-suidsear ach na "
"h-aplacaidean aig a bheil uinneag san rum-obrach làithreach. Mur e, thèid a "
"h-uile aplacaid a ghabhail a-steach."
#: data/org.gnome.shell.gschema.xml.in:168
msgid "The application icon mode."
msgstr "Modh ìomhaigheag na h-aplacaid."
#: data/org.gnome.shell.gschema.xml.in:169
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 ""
"Rèitichidh seo an dòigh sa thèid na h-uinneagan a shealltainn san "
"t-suidsear. 'S e \"thumbnail-only\" (seallaidh seo dealbhag na h-uinneige), "
"\"app-icon-only\" (seallaidh seo ìomhaigheag na h-aplacaid) no \"both\" "
"(seallaidh seo an dà chuid dhiubh) a tha sna luachan dligheach."
#: data/org.gnome.shell.gschema.xml.in:178
msgid ""
"If true, only windows from the current workspace are shown in the switcher. "
"Otherwise, all windows are included."
msgstr ""
"Mas e true a th' ann, cha dèid a shealltainn san t-suidsear ach na "
"h-uinneagan a tha san rum-obrach làithreach. Mur e, thèid a h-uile uinneag a "
"ghabhail a-steach."
#: data/org.gnome.shell.gschema.xml.in:189
msgid "Attach modal dialog to the parent window"
msgstr "Ceangail còmhradh mòdach ris an uinneag-pàraint"
#: data/org.gnome.shell.gschema.xml.in:190
#: data/org.gnome.shell.gschema.xml.in:199
#: data/org.gnome.shell.gschema.xml.in:207
#: data/org.gnome.shell.gschema.xml.in:215
#: data/org.gnome.shell.gschema.xml.in:223
msgid ""
"This key overrides the key in org.gnome.mutter when running GNOME Shell."
msgstr ""
"Tar-àithnidh an iuchair seo an iuchair ann an org.gnome.mutter nuair a thèid "
"Slige GNOME a ruith."
#: data/org.gnome.shell.gschema.xml.in:198
msgid "Enable edge tiling when dropping windows on screen edges"
msgstr ""
"Cuir leacadh nan oirean an comas nuair a thèid uinneagan a leigeil às aig "
"oir na sgrìn"
#: data/org.gnome.shell.gschema.xml.in:206
msgid "Workspaces are managed dynamically"
msgstr "Thèid na rumannan-obrach a stiùireadh a làimh"
#: data/org.gnome.shell.gschema.xml.in:214
msgid "Workspaces only on primary monitor"
msgstr "Rumannan-obrach air a' phrìomh-sgrìn a-mhàin"
#: data/org.gnome.shell.gschema.xml.in:222
msgid "Delay focus changes in mouse mode until the pointer stops moving"
msgstr ""
"Cuir dàil air atharraichean an fòcais ann am modh luchaige gus an sguir an "
"tomhaire air gluasad"
#: data/org.gnome.Shell.PortalHelper.desktop.in.in:3
msgid "Network Login"
msgstr "Clàradh a-steach lìonraidh"
@ -141,7 +345,7 @@ msgstr "Leudachain na Slige GNOME"
#: js/gdm/authPrompt.js:147 js/ui/audioDeviceSelection.js:71
#: js/ui/components/networkAgent.js:145 js/ui/components/polkitAgent.js:179
#: js/ui/endSessionDialog.js:483 js/ui/extensionDownloader.js:195
#: js/ui/shellMountOperation.js:399 js/ui/status/network.js:916
#: js/ui/shellMountOperation.js:399 js/ui/status/network.js:926
msgid "Cancel"
msgstr "Sguir dheth"
@ -331,12 +535,12 @@ msgstr "Cuir ris na h-annsachdan"
msgid "Show Details"
msgstr "Seall am mion-fhiosrachadh"
#: js/ui/appFavorites.js:134
#: js/ui/appFavorites.js:136
#, javascript-format
msgid "%s has been added to your favorites."
msgstr "Chaidh %s a chur ris na h-annsachdan agad."
#: js/ui/appFavorites.js:168
#: js/ui/appFavorites.js:170
#, javascript-format
msgid "%s has been removed from your favorites."
msgstr "Chaidh %s a toirt air falbh o na h-annsachdan agad."
@ -346,7 +550,6 @@ msgid "Select Audio Device"
msgstr "Tagh uidheam fuaime"
#: js/ui/audioDeviceSelection.js:69
#| msgid "Account Settings"
msgid "Sound Settings"
msgstr "Roghainnean fuaime"
@ -499,8 +702,8 @@ msgstr "Facal-faire:"
msgid "Type again:"
msgstr "Am facal-faire a-rithist:"
#: js/ui/components/networkAgent.js:140 js/ui/status/network.js:269
#: js/ui/status/network.js:352 js/ui/status/network.js:919
#: js/ui/components/networkAgent.js:140 js/ui/status/network.js:270
#: js/ui/status/network.js:353 js/ui/status/network.js:929
msgid "Connect"
msgstr "Ceangail"
@ -528,11 +731,11 @@ msgstr "Facal-faire na h-iuchrach prìobhaidich: "
msgid "Service: "
msgstr "Seirbheis: "
#: js/ui/components/networkAgent.js:320 js/ui/components/networkAgent.js:658
#: js/ui/components/networkAgent.js:320 js/ui/components/networkAgent.js:666
msgid "Authentication required by wireless network"
msgstr "Tha an lìonra uèirleas ag iarraidh dearbhadh"
#: js/ui/components/networkAgent.js:321 js/ui/components/networkAgent.js:659
#: js/ui/components/networkAgent.js:321 js/ui/components/networkAgent.js:667
#, javascript-format
msgid ""
"Passwords or encryption keys are required to access the wireless network "
@ -541,7 +744,7 @@ msgstr ""
"Tha feum air faclan-faire no iuchraichean crioptachaidh gus an lìonra "
"uèirleas “%s” inntrigeadh."
#: js/ui/components/networkAgent.js:325 js/ui/components/networkAgent.js:662
#: js/ui/components/networkAgent.js:325 js/ui/components/networkAgent.js:670
msgid "Wired 802.1X authentication"
msgstr "Dearbhadh Wired 802.1X"
@ -549,15 +752,15 @@ msgstr "Dearbhadh Wired 802.1X"
msgid "Network name: "
msgstr "Ainm an lìonraidh: "
#: js/ui/components/networkAgent.js:332 js/ui/components/networkAgent.js:666
#: js/ui/components/networkAgent.js:332 js/ui/components/networkAgent.js:674
msgid "DSL authentication"
msgstr "Dearbhadh DSL"
#: js/ui/components/networkAgent.js:339 js/ui/components/networkAgent.js:672
#: js/ui/components/networkAgent.js:339 js/ui/components/networkAgent.js:680
msgid "PIN code required"
msgstr "Tha feum air còd PIN"
#: js/ui/components/networkAgent.js:340 js/ui/components/networkAgent.js:673
#: js/ui/components/networkAgent.js:340 js/ui/components/networkAgent.js:681
msgid "PIN code is needed for the mobile broadband device"
msgstr "Tha feum air còd PIN airson an inneil-làimhe banna-leathainn"
@ -565,17 +768,17 @@ msgstr "Tha feum air còd PIN airson an inneil-làimhe banna-leathainn"
msgid "PIN: "
msgstr "PIN: "
#: js/ui/components/networkAgent.js:348 js/ui/components/networkAgent.js:679
#: js/ui/components/networkAgent.js:348 js/ui/components/networkAgent.js:687
msgid "Mobile broadband network password"
msgstr "Facal-faire a' bhanna-leathainn inneil-làimhe"
#: js/ui/components/networkAgent.js:349 js/ui/components/networkAgent.js:663
#: js/ui/components/networkAgent.js:667 js/ui/components/networkAgent.js:680
#: js/ui/components/networkAgent.js:349 js/ui/components/networkAgent.js:671
#: js/ui/components/networkAgent.js:675 js/ui/components/networkAgent.js:688
#, javascript-format
msgid "A password is required to connect to “%s”."
msgstr "tha feum air facal-faire airson ceangal ri “%s”."
#: js/ui/components/networkAgent.js:647 js/ui/status/network.js:1658
#: js/ui/components/networkAgent.js:655 js/ui/status/network.js:1672
msgid "Network Manager"
msgstr "Manaidsear nan lìonra"
@ -769,8 +972,6 @@ msgid "Power off after updates are installed"
msgstr "Cuir a' chumhachd dheth nuair a bhios na h-ùrachaidhean air an stàladh"
#: js/ui/endSessionDialog.js:137
#| msgctxt "title"
#| msgid "Restart & Install Updates"
msgctxt "title"
msgid "Restart & Install Upgrade"
msgstr "Ath-thòisich ⁊ stàlaich an t-àrdachadh"
@ -896,14 +1097,10 @@ msgid "System Information"
msgstr "Fiosrachadh an t-siostaim"
#: js/ui/mpris.js:194
#| msgctxt "program"
#| msgid "Unknown"
msgid "Unknown artist"
msgstr "Neach-ciùil nach aithne dhuinn"
#: js/ui/mpris.js:195
#| msgctxt "program"
#| msgid "Unknown"
msgid "Unknown title"
msgstr "Tiotal nach aithne dhuinn"
@ -963,6 +1160,10 @@ msgstr "Cuir a-steach àithne"
msgid "Close"
msgstr "Dùin"
#: js/ui/runDialog.js:277
msgid "Restart is not available on Wayland"
msgstr "Chan eil ath-thòiseachadh ri làimh air Wayland"
#: js/ui/runDialog.js:282
msgid "Restarting…"
msgstr "'Ga thòiseachadh às ùr…"
@ -1006,11 +1207,11 @@ msgstr "Feumaidh GNOME an sgrìn a glasadh"
#.
#. XXX: another option is to kick the user into the gdm login
#. screen, where we're not affected by grabs
#: js/ui/screenShield.js:825 js/ui/screenShield.js:1291
#: js/ui/screenShield.js:825 js/ui/screenShield.js:1292
msgid "Unable to lock"
msgstr "Cha ghabh a ghlasadh"
#: js/ui/screenShield.js:826 js/ui/screenShield.js:1292
#: js/ui/screenShield.js:826 js/ui/screenShield.js:1293
msgid "Lock was blocked by an application"
msgstr "Chaidh a' ghlas a bhacadh le aplacaid"
@ -1094,7 +1295,7 @@ msgstr "Teacsa mòr"
msgid "Bluetooth"
msgstr "Bluetooth"
#: js/ui/status/bluetooth.js:56 js/ui/status/network.js:624
#: js/ui/status/bluetooth.js:56 js/ui/status/network.js:625
msgid "Bluetooth Settings"
msgstr "Roghainnean Bluetooth"
@ -1116,13 +1317,13 @@ msgstr "Dheth"
msgid "Not In Use"
msgstr "Chan eil e 'ga chleachdadh"
#: js/ui/status/bluetooth.js:142 js/ui/status/network.js:1279
#: js/ui/status/bluetooth.js:142 js/ui/status/network.js:1289
msgid "Turn On"
msgstr "Cuir air"
#: js/ui/status/bluetooth.js:142 js/ui/status/network.js:178
#: js/ui/status/network.js:353 js/ui/status/network.js:1279
#: js/ui/status/network.js:1394 js/ui/status/rfkill.js:90
#: js/ui/status/bluetooth.js:142 js/ui/status/network.js:179
#: js/ui/status/network.js:354 js/ui/status/network.js:1289
#: js/ui/status/network.js:1404 js/ui/status/rfkill.js:90
#: js/ui/status/rfkill.js:117
msgid "Turn Off"
msgstr "Cuir dheth"
@ -1171,18 +1372,18 @@ msgstr ""
"'S urrainn dhut inntrigeadh an ionaid atharrachadh uair sam bith ann an "
"roghainnean na prìobhaideachd."
#: js/ui/status/network.js:101
#: js/ui/status/network.js:102
msgid "<unknown>"
msgstr "<neo-aithnichte>"
#. Translators: %s is a network identifier
#: js/ui/status/network.js:451 js/ui/status/network.js:1308
#: js/ui/status/network.js:452 js/ui/status/network.js:1318
#, javascript-format
msgid "%s Off"
msgstr "%s dheth"
#. Translators: %s is a network identifier
#: js/ui/status/network.js:454
#: js/ui/status/network.js:455
#, javascript-format
msgid "%s Connected"
msgstr "%s ceangailte"
@ -1190,168 +1391,168 @@ msgstr "%s ceangailte"
#. 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);
#. %s is a network identifier
#: js/ui/status/network.js:459
#: js/ui/status/network.js:460
#, javascript-format
msgid "%s Unmanaged"
msgstr "%s gun stiùireadh"
#. Translators: %s is a network identifier
#: js/ui/status/network.js:462
#: js/ui/status/network.js:463
#, javascript-format
msgid "%s Disconnecting"
msgstr "A' dì-cheangal %s"
#. Translators: %s is a network identifier
#: js/ui/status/network.js:469 js/ui/status/network.js:1300
#: js/ui/status/network.js:470 js/ui/status/network.js:1310
#, javascript-format
msgid "%s Connecting"
msgstr "A' ceangal %s"
#. Translators: this is for network connections that require some kind of key or password; %s is a network identifier
#: js/ui/status/network.js:472
#: js/ui/status/network.js:473
#, javascript-format
msgid "%s Requires Authentication"
msgstr "Tha %s ag iarraidh dearbhadh"
#. Translators: this is for devices that require some kind of firmware or kernel
#. module, which is missing; %s is a network identifier
#: js/ui/status/network.js:480
#: js/ui/status/network.js:481
#, javascript-format
msgid "Firmware Missing For %s"
msgstr "Tha bathar-an-sàs a dhìth air %s"
#. Translators: this is for a network device that cannot be activated (for example it
#. is disabled by rfkill, or it has no coverage; %s is a network identifier
#: js/ui/status/network.js:484
#: js/ui/status/network.js:485
#, javascript-format
msgid "%s Unavailable"
msgstr "Chan eil %s ri fhaighinn"
#. Translators: %s is a network identifier
#: js/ui/status/network.js:487
#: js/ui/status/network.js:488
#, javascript-format
msgid "%s Connection Failed"
msgstr "Dh'fhàillig le %s a cheangal"
#: js/ui/status/network.js:503
#: js/ui/status/network.js:504
msgid "Wired Settings"
msgstr "Roghainnean le uèir"
#: js/ui/status/network.js:545
#: js/ui/status/network.js:546
msgid "Mobile Broadband Settings"
msgstr "Roghainnean banna-leathainn inneal-làimhe"
#. Translators: %s is a network identifier
#: js/ui/status/network.js:588 js/ui/status/network.js:1305
#: js/ui/status/network.js:589 js/ui/status/network.js:1315
#, javascript-format
msgid "%s Hardware Disabled"
msgstr "Tha bathar-cruaidh %s à comas"
#. Translators: this is for a network device that cannot be activated
#. because it's disabled by rfkill (airplane mode); %s is a network identifier
#: js/ui/status/network.js:592
#: js/ui/status/network.js:593
#, javascript-format
msgid "%s Disabled"
msgstr "%s à comas"
#: js/ui/status/network.js:632
#: js/ui/status/network.js:633
msgid "Connect to Internet"
msgstr "Ceangail ris an eadar-lìon"
#: js/ui/status/network.js:813
#: js/ui/status/network.js:823
msgid "Airplane Mode is On"
msgstr "Tha am modh itealain air"
#: js/ui/status/network.js:814
#: js/ui/status/network.js:824
msgid "Wi-Fi is disabled when airplane mode is on."
msgstr "Tha WiFi à comas fhad 's a tha am modh itealain air."
#: js/ui/status/network.js:815
#: js/ui/status/network.js:825
msgid "Turn Off Airplane Mode"
msgstr "Cuir am modh itealain dheth"
#: js/ui/status/network.js:824
#: js/ui/status/network.js:834
msgid "Wi-Fi is Off"
msgstr "Tha WiFi dheth"
#: js/ui/status/network.js:825
#: js/ui/status/network.js:835
msgid "Wi-Fi needs to be turned on in order to connect to a network."
msgstr "Feumaidh tu WiFi a chur air gus ceangal ri lìonra."
#: js/ui/status/network.js:826
#: js/ui/status/network.js:836
msgid "Turn On Wi-Fi"
msgstr "Cuir WiFi air"
#: js/ui/status/network.js:851
#: js/ui/status/network.js:861
msgid "Wi-Fi Networks"
msgstr "Lìonraidhean WiFi"
#: js/ui/status/network.js:853
#: js/ui/status/network.js:863
msgid "Select a network"
msgstr "Tagh lìonra"
#: js/ui/status/network.js:883
#: js/ui/status/network.js:893
msgid "No Networks"
msgstr "Chan eil lìonra ann"
#: js/ui/status/network.js:904 js/ui/status/rfkill.js:115
#: js/ui/status/network.js:914 js/ui/status/rfkill.js:115
msgid "Use hardware switch to turn off"
msgstr "Cleachd suidse bathair-chruaidh gus a chur dheth"
#: js/ui/status/network.js:1171
#: js/ui/status/network.js:1181
msgid "Select Network"
msgstr "Tagh lìonra"
#: js/ui/status/network.js:1177
#: js/ui/status/network.js:1187
msgid "Wi-Fi Settings"
msgstr "Roghainnean WiFi"
#. Translators: %s is a network identifier
#: js/ui/status/network.js:1296
#: js/ui/status/network.js:1306
#, javascript-format
msgid "%s Hotspot Active"
msgstr "Tha %s hotspot gnìomhach"
#. Translators: %s is a network identifier
#: js/ui/status/network.js:1311
#: js/ui/status/network.js:1321
#, javascript-format
msgid "%s Not Connected"
msgstr "Chan eil %s ceangailte"
#: js/ui/status/network.js:1411
#: js/ui/status/network.js:1421
msgid "connecting..."
msgstr "'ga cheangal..."
#. Translators: this is for network connections that require some kind of key or password
#: js/ui/status/network.js:1414
#: js/ui/status/network.js:1424
msgid "authentication required"
msgstr "tha feum air dearbhadh"
#: js/ui/status/network.js:1416
#: js/ui/status/network.js:1426
msgid "connection failed"
msgstr "dh'fhàillig leis a' cheangal"
#: js/ui/status/network.js:1482 js/ui/status/rfkill.js:93
#: js/ui/status/network.js:1492 js/ui/status/rfkill.js:93
msgid "Network Settings"
msgstr "Roghainnean an lìonraidh"
#: js/ui/status/network.js:1484
#: js/ui/status/network.js:1494
msgid "VPN Settings"
msgstr "Roghainnean VPN"
#: js/ui/status/network.js:1503
#: js/ui/status/network.js:1513
msgid "VPN"
msgstr "VPN"
#: js/ui/status/network.js:1513
#: js/ui/status/network.js:1523
msgid "VPN Off"
msgstr "Tha VPN dheth"
#: js/ui/status/network.js:1697
#: js/ui/status/network.js:1711
msgid "Connection failed"
msgstr "Dh'fhàillig leis a' cheangal"
#: js/ui/status/network.js:1698
#: js/ui/status/network.js:1712
msgid "Activation of network connection failed"
msgstr "Dh'fhàillig gnìomhachadh a' cheangail ris an lìonra"

767
po/gl.po

File diff suppressed because it is too large Load Diff

View File

@ -2319,33 +2319,9 @@ msgstr "המשתמש בחר להתעלם מתיבת דו־שיח האימות"
#~ msgid "Networking is disabled"
#~ msgstr "תכונת הרשת מנוטרלת"
#~ msgid "%d hour remaining"
#~ msgid_plural "%d hours remaining"
#~ msgstr[0] "נותרה שעה"
#~ msgstr[1] "נותרו %d שעות"
#~ msgstr[2] "נותרו שעתיים"
#~ msgid "%d %s %d %s remaining"
#~ msgstr "%d %s %d %s נותרו"
#~ msgid "hour"
#~ msgid_plural "hours"
#~ msgstr[0] "שעה"
#~ msgstr[1] "שעות"
#~ msgstr[2] "שעתיים"
#~ msgid "minute"
#~ msgid_plural "minutes"
#~ msgstr[0] "דקה"
#~ msgstr[1] "דקות"
#~ msgstr[2] "דקות"
#~ msgid "%d minute remaining"
#~ msgid_plural "%d minutes remaining"
#~ msgstr[0] "דקה אחת נותרה"
#~ msgstr[1] "%d דקות נותרו"
#~ msgstr[2] "שתי דקות נותרו"
#~ msgid "AC Adapter"
#~ msgstr "מתאם חשמל"
@ -2611,30 +2587,6 @@ msgstr "המשתמש בחר להתעלם מתיבת דו־שיח האימות"
#~ msgid "Less than a minute ago"
#~ msgstr "לפני פחות מדקה"
#~ msgid "%d minute ago"
#~ msgid_plural "%d minutes ago"
#~ msgstr[0] "לפני דקה"
#~ msgstr[1] "לפני %d דקות"
#~ msgstr[2] "לפני 2 דקות"
#~ msgid "%d hour ago"
#~ msgid_plural "%d hours ago"
#~ msgstr[0] "לפני שעה"
#~ msgstr[1] "לפני %d שעות"
#~ msgstr[2] "לפני שעתיים"
#~ msgid "%d day ago"
#~ msgid_plural "%d days ago"
#~ msgstr[0] "לפני יום"
#~ msgstr[1] "לפני %d ימים"
#~ msgstr[2] "לפני יומיים"
#~ msgid "%d week ago"
#~ msgid_plural "%d weeks ago"
#~ msgstr[0] "לפני שבוע"
#~ msgstr[1] "לפני %d שבועות"
#~ msgstr[2] "לפני שבועיים"
#~ msgid "Shut Down"
#~ msgstr "כיבוי"

779
po/hr.po

File diff suppressed because it is too large Load Diff

1471
po/hu.po

File diff suppressed because it is too large Load Diff

748
po/id.po

File diff suppressed because it is too large Load Diff

855
po/is.po

File diff suppressed because it is too large Load Diff

771
po/it.po

File diff suppressed because it is too large Load Diff

1121
po/ja.po

File diff suppressed because it is too large Load Diff

761
po/kk.po

File diff suppressed because it is too large Load Diff

730
po/ko.po

File diff suppressed because it is too large Load Diff

770
po/lt.po

File diff suppressed because it is too large Load Diff

739
po/lv.po

File diff suppressed because it is too large Load Diff

1071
po/nb.po

File diff suppressed because it is too large Load Diff

794
po/pa.po

File diff suppressed because it is too large Load Diff

756
po/pl.po

File diff suppressed because it is too large Load Diff

View File

@ -301,7 +301,7 @@ msgstr "Sessão na rede"
#. Translators: Do NOT translate or transliterate this text (this is an icon file name)!
#: data/org.gnome.Shell.PortalHelper.desktop.in.in:9
msgid "network-workgroup"
msgstr "Grupo de Trabalho na Rede"
msgstr "network-workgroup"
#: js/extensionPrefs/main.js:117
#, javascript-format
@ -1685,7 +1685,7 @@ msgstr "Calendário do Evolution"
#. Translators: Do NOT translate or transliterate this text (this is an icon file name)!
#: src/calendar-server/evolution-calendar.desktop.in:6
msgid "evolution"
msgstr "Evolution"
msgstr "evolution"
#. translators:
#. * The number of sound outputs on a particular device

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