Compare commits

...

525 Commits

Author SHA1 Message Date
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
7e803fdf23 Bump version to 3.23.1
Update NEWS.
2016-10-30 21:52:14 +01:00
ccacb5f6de background: Update animations when coming back from suspend
We currently reload animated backgrounds on timezone changes, but
there are other cases where the time can change unexpectedly and
the background no longer matches the time of day. One case we can
easily handle is when coming back from suspend, so do that.

https://bugzilla.gnome.org/show_bug.cgi?id=773265
2016-10-30 21:10:32 +01:00
5117139add Update Slovak translation 2016-10-30 08:18:22 +00:00
d5c0514e21 browser-plugin: The NPObject returned by NPP_GetValue should be retained
The Mozilla documentation says: "And as always when working with
reference counted NPObjects, the caller is responsible for calling
NPN_ReleaseObject on the NPObject to drop the reference."

Browsers assume that the plugin does the right thing and always call
NPN_ReleaseObject. At some point the object is released and deallocated
and both the plugin and browser still have references to the object
thinking that it's still alive. That's why the crash is sometimes in the
plugin when it tries to use the np object, and sometimes in the browser.

https://bugzilla.gnome.org/post_bug.cgi
2016-10-29 09:08:07 +02:00
d81a6bdf41 Updated Ukrainian translation 2016-10-29 02:34:48 +03:00
2812afed22 gnome-shell-extension-tool: Add a reload option
This might be a good fit for extension developers: With
this option one doesn't need to restart the whole Shell
in order to see their changes in effect.

https://bugzilla.gnome.org/show_bug.cgi?id=772593
2016-10-28 15:41:32 -02:00
f5bd86fa11 Updated Czech translation 2016-10-28 12:42:48 +02:00
b625f1692c Update Friulian translation 2016-10-25 20:20:18 +00:00
36ac1f8902 Update Turkish translation 2016-10-23 19:59:08 +00:00
bec4b5c127 Update Polish translation 2016-10-22 16:09:21 +02:00
78cd8b9f9a Fixes to Catalan translation 2016-10-22 12:55:44 +02:00
205880e74e screenShield: Only allow graphs to lift shield when locked
Since commit 67615a0cbc, any printable key can be used to lift the
screen shield rather than just escape/enter/space. While this is
convenient for unlocking where the input is forwarded to the password
entry, it is potentially dangerous when the screen is inactive but
not locked: If the user types her password, the first character will
lift the shield and the remaining input will go to the focused window.
To prevent this from happening, only allow printable keys when the
screen is actually locked and restrict the key presses that lift the
shield to the original set of escape/enter/space otherwise.

https://bugzilla.gnome.org/show_bug.cgi?id=773328
2016-10-21 22:21:55 +02:00
009d021e4f appDisplay: Add a menu item to launch on the discrete GPU
It will only show up when a discrete GPU is available (detected through
the switcheroo-control D-Bus service), and the application hasn't
alreayd been launched.

Note that this will not currently work for D-Bus activated applications,
eg. the menu item will be available, but the environment variable will
not be passed through to D-Bus to use when launching the application.

https://bugzilla.gnome.org/show_bug.cgi?id=773117
2016-10-21 19:26:49 +02:00
39a840e2c3 shell-app: Add "discrete_gpu" option when launching apps
And adapt existing callers to the new API. This will allow us to
implement a way to launch applications on the discrete GPU for systems
where an "Optimus" system exists.

https://bugzilla.gnome.org/show_bug.cgi?id=773117
2016-10-21 19:26:49 +02:00
56d0d7253b build: Fix git submodule fetching with builddir != srcdir
We were running the git submodule update in builddir, instead of srcdir,
which might have lead to submodules not updating, and submodule tags
being reverted to older versions in some contributions.

https://bugzilla.gnome.org/show_bug.cgi?id=773085
2016-10-21 12:22:15 +02:00
7a29cc47d4 build: Remove use of gjs-internals-1.0.pc
Instead use gjs-1.0.pc, the gjs-internals-1.0 API is not stable across
SpiderMonkey versions and is going away.

https://bugzilla.gnome.org/show_bug.cgi?id=772386
2016-10-18 10:21:11 -07:00
d769b72c43 extensionUtils: Use a unique 'subdir' to create new importers
Apparently importers for the 'same' path are shared, even when the
relative paths resolve to different absolute ones. Until this bug
is fixed properly, we can work around this by expressing the current
extension path as the UUID relative to the parent directory.

https://bugzilla.gnome.org/show_bug.cgi?id=772386
2016-10-18 19:19:32 +02:00
a3439a5230 zh_CN: fix translation of airplane mode 2016-10-18 17:35:29 +08:00
9f45161133 Update zh_CN translation 2016-10-18 17:30:36 +08:00
ed99bef458 extensionUtils: Remove ShellJS library
You can define a new importer object by importing a subdirectory in GJS.
This is undocumented, but it is likely to at least hold until the whole
thing moves to ES6 modules, after which we'll be able to do this purely
in JS with Reflect.Loader.

Since this was the only thing the ShellJS library did, we can remove it
altogether.

This allows us to discontinue use of the gjs-internals-1.0 embedder API.

https://bugzilla.gnome.org/show_bug.cgi?id=772386
2016-10-17 12:36:16 -07:00
c9ad54cd82 Update Friulian translation
(cherry picked from commit 0b8ae22aa3)
2016-10-17 10:24:45 +00:00
d7e42d5d6e Update Friulian translation
(cherry picked from commit 25e1b2548c)
2016-10-17 10:15:18 +00:00
5b339c8371 authPrompt.js: turn off the ellipsization of pam messages
When the user gets long failure messages from pam, the authPrompt
message label will clip the message and ellipsize with '…'.

This commit turns off ellipsization from the label, so it will
properly wrap.

https://bugzilla.gnome.org/show_bug.cgi?id=764445
2016-10-14 09:28:34 -04:00
9c6e68f3e7 bluetooth: Replace "Not In Use" status string with "On"
If Bluetooth is on but there aren't connected devices, the status in the
menu reads "Not in Use". This is potentially confusing: it's a negative
statement, even though Bluetooth is on. It also sits uneasily (and looks
even more confusing) next to the submenu item "Turn Off".

Changing the string to "On" is better.

https://bugzilla.gnome.org/show_bug.cgi?id=756432
2016-10-12 10:35:31 +02:00
70526a8025 log(): Reimplement on top of GLib.log_structured
This allows us to pass metadata fields besides the message
to log. So, if the log() call is made from an extension,
pass the extension name and UUID to the logger.

This is useful for extension developers to debug their code
as well as to instruct their users to send debug info to them
by running something like this:

journalctl GNOME_SHELL_EXTENSION_UUID=<extension@uuid>

https://bugzilla.gnome.org/show_bug.cgi?id=770717
2016-10-11 10:17:12 -03:00
c405081d89 extensionUtils: Allow getCurrentExtension() to be called from anyone
Currently it's assumed only an extension can call this method. However
it can be useful if any part of the shell want to know if it was invoked
by an extension.

https://bugzilla.gnome.org/show_bug.cgi?id=770717
2016-10-11 10:14:23 -03:00
384e01b368 network: request periodic scans while the WiFi list is open
NM upstream would like to reduce periodic scanning, and that means
that clients should request scans themselves while their WiFi list
is open.  Similar to the Windows and macOS WiFi dialogs/lists.

https://bugzilla.gnome.org/show_bug.cgi?id=767918
2016-10-11 14:43:19 +02:00
f819654ec8 osdWindow: always round-up sizes when updating allocation
This fixes the OSD window flickering horizontally at certain
resolutions.

https://bugzilla.gnome.org/show_bug.cgi?id=772287
2016-10-10 17:24:52 -07:00
4670db6629 osdWindow: relayout when scale factor changes
We currently rely on the "monitors-changed" signal of LayoutManager to
relayout the OSD window. That is not enough, since the scale factor also
changes the way the OSD window is sized, and that can be updated after
"monitors-changed" has been received.
The visual effect is that under some circumstances, the OSD window will
have the wrong size under HiDpi.

This commit fixes the issue by triggering another relayout when the
scale factor changes.

https://bugzilla.gnome.org/show_bug.cgi?id=772723
2016-10-10 17:24:52 -07:00
6ebabd50c6 Bump version to 3.22.1
Update NEWS.
2016-10-11 00:57:38 +02:00
0c22a21a24 window-tracker: Consider Flatpak ID for window matching
Our window matching currently fails frequently with Flatpak
applications, as one of the primary hints used to link windows
with .desktop files - the WM_CLASS - no longer matches when
flatpak renames the exported .desktop file. Worse, as Flatpak
applications are run in their own PID namespace, different
apps frequently share a common _NET_WM_PID, resulting in
unrelated apps being grouped together by one of the fallback
paths. To match Flatpak applications reliably, take the newly
exported Flatpak ID into account.

https://bugzilla.gnome.org/show_bug.cgi?id=772615
2016-10-10 23:40:39 +02:00
70a0c4211c Update Croatian translation 2016-10-10 18:16:38 +00:00
a21af541c4 Add Croatian translation 2016-10-09 19:23:52 +00:00
e07ba91486 Update Chinese (Taiwan) translation 2016-10-09 14:14:46 +00:00
a22e9ce9cd st: Ignore filtered selection events not meant to our clipboard window
Other windows like the mutter Xwayland selection bridges might deal with
the clipboard, which would result in events visible on st-clipboard event
filters.

In order to avoid unintended results, ignore events that are not meant for
the clipboard window.

https://bugzilla.gnome.org/show_bug.cgi?id=760745
2016-10-09 10:57:47 +02:00
d4ce51b1b7 altTab: Consider attached modals for window order
Similar to bug 667552 for the app switcher, attached modal dialogs
can result in an unexpected window order in the window switcher:
Selecting a window with an attached dialog will focus the dialog
instead, but as the dialog itself is ignored in the window list,
its last-used timestamp is not taken into account for the position
in the MRU list. Fix this by fetching the list of all NORMAL windows
and filter out skip-taskbar windows ourselves, while making sure that
windows appear in the position of their attached modal dialog where
appropriate.

https://bugzilla.gnome.org/show_bug.cgi?id=747153
2016-10-07 14:51:15 +02:00
830005069c Updated Italian translation 2016-10-06 11:48:53 +00:00
8c49267658 Updated Italian translation 2016-10-03 09:38:47 +00:00
d0bab1f7ac network: Initialize primary and VPN connections on startup
We only connect to the corresponding property notifications after both
Client and RemoteSettings are ready, so we may miss the initial signal
emission. Make sure to pick up the connections in this case to fix the
network indicator not showing up.

https://bugzilla.gnome.org/show_bug.cgi?id=772249
2016-09-30 13:50:30 +02:00
f00826f3fb shell-js: Remove usage of deprecated API
This removes all usage of SpiderMonkey API that is deprecated in mozjs24
and will be removed in mozjs31.

https://bugzilla.gnome.org/show_bug.cgi?id=742249
2016-09-27 17:14:47 -07:00
BM
717c0ea19f Update Uzbek@cyrillic translation 2016-09-25 09:16:36 -04:00
3cd8dd0f32 global: Fix a small memory leak 2016-09-21 23:38:42 +02:00
aedd616346 Update Arabic translation 2016-09-21 14:51:33 +02:00
b3de3ff00b Update Basque language 2016-09-19 13:37:26 +02:00
b66dff8aed Bump version to 3.22.0
Update NEWS.
2016-09-19 23:18:13 +02:00
ff814df03a shell-screenshot: Avoid a crash when the cursor texture is NULL
Analogously to commit 2a7f9f70b8 for the
screen recorder, as a wayland compositor, the cursor texture might not
exist.

https://bugzilla.gnome.org/show_bug.cgi?id=771656
2016-09-19 22:41:51 +02:00
c9a528025c Updated Danish translation 2016-09-19 20:35:22 +00:00
5f3ec8a6f1 Update British English translation 2016-09-18 12:43:02 +02:00
becd29c50a altTab: Skip unminimize effect when cycling to a window
Similar to windows on another workspace, selecting a minimized window
doesn't look quite right - the selected window disappears, then animates
back in. Fix this by adding support for skipping the next effect to the
wm and use it to bypass the unminimize animation.

https://bugzilla.gnome.org/show_bug.cgi?id=771536
2016-09-18 11:00:54 +02:00
a029a35050 altTab: Improve cycling to a window on another workspace
Both 'cycle-group' and 'cycle-window' shortcuts allow cycling through
windows on all workspaces. While this works, it looks quite broken
since we started showing clones for highlighting: the selected window
vanishes (when its clone is destroyed), then slides back in with its
workspace. Instead, slide the selected window to its workspace like
we do for the 'move-to-workspace-*' shortcuts.

https://bugzilla.gnome.org/show_bug.cgi?id=771536
2016-09-18 11:00:54 +02:00
d6a78d61d1 altTab: Restore correct visibility when cycling windows
Commit 3171819c improved window cycling by using a dedicated to clone
for highlighting rather than activating all cycled windows. Original
window actors are hidden while its clone is showing, and shown again
afterwards, however the latter is wrong for actors that are not supposed
to be visible (for example where the window is minimized, or on a different
workspace). Fix this by properly syncing the actor's visibility instead
of showing it unconditionally.

https://bugzilla.gnome.org/show_bug.cgi?id=771536
2016-09-18 11:00:54 +02:00
9be46bd212 Update Arabic translation 2016-09-16 21:30:26 +02:00
4df3afced0 Update Catalan translation 2016-09-16 21:26:51 +02:00
90f8e1df80 Updated Ukrainian translation 2016-09-15 18:12:16 +03:00
ea2ac89e61 Updated Ukrainian translation 2016-09-15 18:06:22 +03:00
695bfb9616 extensionPrefs: Fix extension list width
ScrolledWindow changed its allocation behavior, and the extension
list only takes up the minimum width rather than the available
width as intended. To get the previous behavior back, we need
to set the newly added :propagate-natural-width property ...

https://bugzilla.gnome.org/show_bug.cgi?id=771391
2016-09-14 09:18:23 +02:00
5dbdde8c15 Updated French translation 2016-09-13 10:19:20 +00:00
854bfc17ed Updated Scottish Gaelic translation 2016-09-13 09:48:01 +00:00
c8b192bcae Updated Danish translation 2016-09-13 01:57:54 +02:00
f07306897f Bump version to 3.21.92
Update NEWS.
2016-09-13 00:16:11 +02:00
44d731fff5 Add more options to XGETTEXT_OPTIONS in po/Makevars 2016-09-12 19:43:44 +02:00
52f939f64c Updated Greek translation 2016-09-11 21:20:39 +00:00
f1d12c18d8 Updated Russian translation 2016-09-11 17:52:46 +00:00
373ebb50eb Restore gvc submodule
Commit 68f439425b accidentally dropped the changes from the last
couple of months ...
2016-09-11 19:20:00 +02:00
b0b5be63b9 Restore gnome-shell-sass submodule
Commit 68f439425b accidentally dropped the changes from the last
couple of months ...
2016-09-11 19:17:36 +02:00
68f439425b Updated Galician translations 2016-09-11 00:35:39 +02:00
cae4d92191 loginDialog: fix cancel button in ask for username mode
If the user clicks Not Listed? to enter ask for username mode, clicks
cancel, and then attempts to log in via the user list, the user will see
"Authentication failed" after correctly typing the password, and then
will become stuck in an empty screen with just the gray noise background.

The problem is, we forgot to disconnect from the signal that's waiting
for the next button to be pressed on the username entry screen. Since
the signal handler that executes here is expecting the username to be
input, and isn't prepared for us to have switched back to user list,
various bad things happen. We try to start two gdm-password
conversations at once, for instance, one using the user's password as
the username. I stopped investigating here, because it's easy to fix by
disconnecting from the signal at the right time.

https://bugzilla.gnome.org/show_bug.cgi?id=770328
2016-09-10 16:50:53 -05:00
f336295475 Updated Korean translation 2016-09-10 18:16:31 +00:00
06d0e7d74a telepathyClient: Always clear pending messages on destroy
Since commit 82950ecea, we acknowledge pending messages when closing a
chat notification for a channel we are handling to prevent the channel
from popping up again immediately. While this isn't an issue for channels
we don't handle, the unread messages of the destroyed notification are
still considered for the messages indicator in the top bar, which is
clearly confusing (in particular when we end up showing the indicator
without any notifications in the list). As it's arguably correct to not
meddle with a channel handled by someone else, just reset the cache of
pending messages to address this issue.

https://bugzilla.gnome.org/show_bug.cgi?id=770888
2016-09-09 23:54:28 +02:00
5e0e3edc7b data: Swap default for 'disable-extension-version-check' setting
Nowadays, the user interface has mostly stabilized with most changes
happening under the hood. As a result, extensions written for previous
versions of GNOME Shell are very much expected to keep working on
updates, if it wasn't for the version check that requires a version
bump in the extension metadata. There has been a setting to disable
that check for a while, but it's existence isn't widely known (hence
the common perception that "everything breaks on updates"). While
there is still some risk that an out-of-date extension can be enabled
without error, but fails spectacularly later (where we cannot catch
the exception), it is reasonably small by now when compared to the
~95% of extensions that can be "unbroken", so swap the default value
to disable version checks by default.

https://bugzilla.gnome.org/show_bug.cgi?id=770887
2016-09-09 23:54:28 +02:00
02a51bfa65 windowManager: Fix windows not getting undimmed while hidden
Mutter's plugin destroy event doesn't happen if a window is hidden
when it gets unmanaged so we also need to handle the
MetaWindow::unmanaged signal to check whether the parent should
dimmed.

https://bugzilla.gnome.org/show_bug.cgi?id=752524
2016-09-09 17:17:07 +02:00
dbd04df311 windowManager: Fix windows not getting undimmed in some cases
meta_window_foreach_transient() iterates through all transients of a
window, not only direct transients. This means that simply checking if
a transient is an attached dialog isn't enough because it might be a
non-direct transient for the window we're checking, in which case we
don't want to dim the window.

In particular this fixes windows not getting undimmed when they have
more that one level of transient children and the direct transient gets
destroyed. In that case we would still find at least one non-direct
transient child and decide to keep the window dimmed.

https://bugzilla.gnome.org/show_bug.cgi?id=770163
2016-09-09 17:17:06 +02:00
e6adcd99c7 [l10n] update Persian translations 2016-09-09 18:36:30 +04:30
3171819c36 altTab: Don't mess up MRU order while cycling windows
Commit bd6e7f14d1 reimplemented the cycle keybindings to
fix cycling between more than two windows, but the approach
of highlighting cycled windows by actually focusing them has
the drawback that cycling messes up the MRU order of windows.
To fix this, only change the window focus when the operation
finishes, and use a dedicated actor that draws a border around
a window clone for highlighting.

https://bugzilla.gnome.org/show_bug.cgi?id=771063
2016-09-08 21:32:10 +02:00
e4976b535d WorkspaceSwitcherPopup: allow input events to pass through
There's no particular reason for this actor to be reactive and thus
preventing input events to reach actors underneath, e.g. quickly
clicking on something while the popup isn't yet finished animating
out.

https://bugzilla.gnome.org/show_bug.cgi?id=770382
2016-09-08 19:29:50 +02:00
06d1602f17 Updated French translation 2016-09-08 16:40:26 +00:00
603d0dfbc3 Update Latvian translation 2016-09-08 19:00:21 +03:00
0b6c5b4620 systray: Bail out if the plug window is gone
Instead of crashing when deferencing a NULL pointer.

Bugzilla: https://bugzilla.gnome.org/show_bug.cgi?id=755313
2016-09-08 12:08:02 +02:00
d7894dbc44 Updated Dutch translation Master 2016-09-07 17:19:57 +02:00
d25d8126ea Updated Portuguese translation 2016-09-07 05:49:14 +00:00
2402d3e115 Updated Swedish translation 2016-09-06 22:07:24 +00:00
ac4284d348 Updated Hebrew translation 2016-09-06 12:21:39 +03:00
f9ef80749a recorder: Composite captured images before passing into gstreamer
Mutter may capture the screen in multiple capture regions. If this is
done, take these images and composite them onto one large image, which
is then passed into the gstreamer source.
2016-09-06 15:22:23 +08:00
22f0d3076e screenshot: Composite multiple captures into one image
When clutter gives us multiple captures (multiple cairo_surface_t's),
composite them into one large image and use that as final screenshot
result. This makes screenshooting work when mutter uses multiple views.

https://bugzilla.gnome.org/show_bug.cgi?id=770128
2016-09-06 15:22:23 +08:00
127b6dca1c updated Punjabi Translation 2016-09-05 07:29:17 -05:00
8cfff33291 Updated Vietnamese translation
Signed-off-by: Trần Ngọc Quân <vnwildman@gmail.com>
2016-09-05 15:04:03 +07:00
21f534c7f0 Updated Turkish translation 2016-09-04 19:12:28 +00:00
9faa1db942 Updated Lithuanian translation 2016-09-04 12:28:10 +03:00
2fc9bffb23 Updated Kazakh translation 2016-09-04 04:15:00 +00:00
f16eae45a2 Updated Korean translation 2016-09-03 14:07:31 +00:00
622e73c34c Bump version to 3.21.91
Update NEWS.
2016-08-30 00:26:31 +02:00
eb1c3d7045 Updated Serbian translation 2016-08-28 09:16:02 +02:00
fc26895f70 Updated Slovenian translation 2016-08-25 22:53:27 +02:00
ca224b379f Updated Brazilian Portuguese translation 2016-08-22 21:13:36 +00:00
42b609b852 Updated Friulian translation 2016-08-22 20:53:03 +00:00
a24169e2aa Updated Spanish translation 2016-08-22 20:44:47 +02:00
144d1dca88 Updated Indonesian translation 2016-08-22 09:47:46 +00:00
38ab6ba3ec Updated Slovak translation 2016-08-21 16:01:41 +00:00
bc6a0626c1 Updated Finnish translation 2016-08-21 09:45:31 +00:00
497f4f4a3c Updated German translation 2016-08-21 09:39:47 +00:00
8c8c89a5f1 Bump version to 3.21.90.1
The 3.21.90 tarball got corrupted, so do another point release.
2016-08-20 23:02:34 +02:00
d658a5148a recorder: Print absolute path if output file can't be opened 2016-08-20 16:03:31 +02:00
2c3e0dab0f Updated Polish translation 2016-08-20 10:26:50 +02:00
e2400e35bd Updated Hungarian translation 2016-08-19 22:01:16 +00:00
fc4562491b Updated Czech translation 2016-08-19 23:17:20 +02:00
6e3bedb888 Add translator comments to .desktop files 2016-08-19 23:15:20 +02:00
2b8332df5e Bump version to 3.21.90
Update NEWS.
2016-08-19 22:16:00 +02:00
795e7d4b59 build: Say good-bye to intltool
intltool is unmaintained nowadays while upstream gettext gained
support for formats like GSettings schemas and .desktop files,
and offers a mechanism to teach it about other XML formats not
yet supported out of the box which we can use for the rest.
So there's nothing stopping us, just make the switch ...

https://bugzilla.gnome.org/show_bug.cgi?id=769074
2016-08-19 22:13:14 +02:00
522d46a525 Updated Indonesian translation 2016-08-19 06:21:39 +00:00
dcecf5e350 Updated Brazilian Portuguese translation 2016-08-19 02:26:11 +00:00
a61c929450 Updated Turkish translation 2016-08-16 04:02:44 +00:00
5992e9f524 Updated Czech translation 2016-08-12 17:31:44 +02:00
ee4cd05ebd Updated Finnish translation 2016-08-12 12:42:53 +00:00
af5e65fd79 global: Make timestamp parameter unsigned
Negative values don't make sense to timestamps, and an unsigned
timestamp as returned by shell_global_get_current_time() or
Gdk/Clutter events may exceed the range of signed integers.

https://bugzilla.gnome.org/show_bug.cgi?id=769216
2016-08-11 09:04:22 +02:00
284cbf3ea7 shell: Remove shell_util_text_insert_keyval()
It is now unused.
2016-08-10 11:25:50 +02:00
c3e68955e3 keyboard: Implement more of the wayland caribou adapter
Have it notify properly of changes to the current input source, as
well as exposing those in get_groups().

The support for virtual keyboard events has been replaced by
ClutterVirtualInputDevice, which can be thought of as the equivalent
to the XTEST devices in X11.

https://bugzilla.gnome.org/show_bug.cgi?id=765009
2016-08-10 11:23:58 +02:00
ffa28e7ee7 Updated Hebrew translation 2016-08-07 15:42:02 +03:00
78d81f909c Updated Hungarian translation 2016-08-04 21:54:56 +00:00
34551bf48b Bump g-i requirement
We need commit bd475c00d9 to pick up mutter's clutter fork.
2016-08-03 21:46:54 +02:00
e02cd53ac5 Updated Lithuanian translation 2016-08-03 21:56:30 +03:00
b7f5154bd3 Updated German translation 2016-08-02 20:15:37 +00:00
d80247918c Updated Spanish translation 2016-08-02 16:50:47 +02:00
bb8c2d3e13 Updated Portuguese translation 2016-07-27 07:42:37 +00:00
6e0e37519d calendar-server: Add back missing return value
In commit 7e0e224e0, when moving from e_cal_recur_generate_instances()
to e_cal_client_generate_instances(), the return value of the
ECalRecurInstanceFn callback was accidentally removed; add it
back.

https://bugzilla.gnome.org/show_bug.cgi?id=769156
2016-07-25 18:55:22 +02:00
5c19ae5878 Updated Friulian translation 2016-07-23 15:51:45 +00:00
8713473c64 Add Language headers to po files
Future versions of gettext will fail if this header is missing.
2016-07-21 02:46:17 +02:00
a4b4f2f6fd Updated POTFILES.in 2016-07-21 00:50:20 +02:00
03f22135b5 Bump version to 3.21.4
Update NEWS.
2016-07-20 21:07:19 +02:00
5b79f657eb data: Dist portals keyfile
Whoops, forgot that in the previous commit :-(
2016-07-20 21:07:19 +02:00
4fc0c513af Provide org.freedesktop.impl.portal.access implementation
If a sandboxed app requests access to some system resource (camera,
microphone, location), the portal frontend needs to ask the user
for permission. In GNOME, we want this to be a system modal dialog,
so provide an org.freedesktop.impl.portal.access implementation
that exposes a generic system modal permission dialog on the bus.

https://bugzilla.gnome.org/show_bug.cgi?id=768669
2016-07-20 17:14:12 +02:00
f5c058a036 Use clutter_stage_capture instead of cogl's read_pixels
There is no longer any guarantee that there'll be one single
framebuffer to read pixels from. In order to still read pixels from the
stage, use the new clutter_stage_capture API.

https://bugzilla.gnome.org/show_bug.cgi?id=768979
2016-07-20 14:15:32 +08:00
0dac0ad516 build: Bump gsettings-desktop-schemas requirement
Require at least 3.21.3 for the MRU input source schema.

https://bugzilla.gnome.org/show_bug.cgi?id=768956
2016-07-19 17:18:56 +02:00
5d4d1e26fd Updated Chinese (Hong Kong) translation 2016-07-18 22:26:23 +00:00
2f0039e7dd app: Add a construct-only app-info property
This will allow us to create a ShellApp from JS code, for instance
for .desktop files that aren't known to the AppSystem.

https://bugzilla.gnome.org/show_bug.cgi?id=762206
2016-07-13 01:28:13 +02:00
9202309bed Updated Polish translation 2016-07-12 21:22:17 +02:00
7e0e224e0e calendar-server: Use the actual recurrence ID of events
Instead of querying the client for a list of objects and using
e_cal_recur_generate_instances() to get occurrences for each of
them, we can use e_cal_client_generate_instances_sync() which
combines the functionality of both functions. This doesn't only
save us some lines of code (yay!), but also gives us access to
the real recurrence ID of an event, so we can get rid of the hack
of faking one.

https://bugzilla.gnome.org/show_bug.cgi?id=748226
2016-07-08 18:05:58 +02:00
35825cf0c7 calendar-server: Get recurrence ID from occurrences
We use the triplet of source ID, UID and recurrence ID to create
an ID to unambiguously identify an event, which we use to implement
hiding dismissed events from the calendar. However we currently
try to fetch the recurrence ID from the objects returned by
e_cal_client_get_object_list_sync(), which are always the primary
events with no recurrence ID. Instead, we need a recurrence ID
associated with each occurrence.

https://bugzilla.gnome.org/show_bug.cgi?id=748226
2016-07-08 18:05:57 +02:00
b2d79b6362 calendar-server: Fetch default zone from client
We are already setting the default zone on the client, no need
to pass it around.

https://bugzilla.gnome.org/show_bug.cgi?id=748226
2016-07-08 18:05:57 +02:00
f5e1dc86cd calendar-server: Fix a memory leak
App will take ownership of the location string when the timezone
changes, but not when there was no change - free the memory in
that case.

https://bugzilla.gnome.org/show_bug.cgi?id=748226
2016-07-08 18:05:57 +02:00
8c51f0076f calendar-server: Minor optimization
We use the same query string for all sources, so no need to
allocate/free it on each loop iteration.

https://bugzilla.gnome.org/show_bug.cgi?id=748226
2016-07-08 16:11:43 +02:00
8347152730 calendar: Do not overload :active to mark selected day
We currently use the :active pseudo class to mark the selected day
in the calendar. Whenever the selected date changes, the class is
added to the corresponding button and removed from all others.
However when the selected date doesn't change (i.e. when clicking
the already selected date), the buttons are not updated and the
use of the :active class conflicts with StButton's builtin handling
of the class - the class is removed on the button up event and the
button is deselected.
Fix this by simply using a different pseudo class.

https://bugzilla.gnome.org/show_bug.cgi?id=746867
2016-07-08 16:11:43 +02:00
3d77dd8f51 calendar: Refresh calendar when ignored events changes
The last patch fixed marking days in the calendar where all
events are ignored, but it doesn't pick up the change when
an event is hidden. Emit an appropriate change notification
to fix this issue.

https://bugzilla.gnome.org/show_bug.cgi?id=768538
2016-07-08 15:01:32 +02:00
82e6935281 calendar: Move handling of ignored events to event source
Ignoring events is currently implemented in the message list's
event section, which means that the calendar does not consider
ignored events when marking days with events. In order to fix
this, move the handling of ignored events to the event source,
which is shared between both components.

https://bugzilla.gnome.org/show_bug.cgi?id=768538
2016-07-08 15:01:32 +02:00
61070e6ec0 calendar-server: Remove an unnecessary check
calendar_appointment_new() never returns %NULL, so no need to check
for it.
2016-07-07 15:54:57 +02:00
128697d6a7 osdWindow: Use a constraint to enforce ratio
Commit 9b07ce1d0d broke the code that keeps the OSD window square.
Use that opportunity to move away from the hack of setting the
min-height style property from code and adjusting the width on
allocate, and implement a proper constraint instead.

https://bugzilla.gnome.org/show_bug.cgi?id=768317
2016-07-05 20:46:57 +02:00
424fa01eca osdWindow: Fix blurry level bar
ClutterActor:width is a floating point property, so it will not be
automatically rounded to non-fractional values that properly align
to pixels. To fix the resulting blurriness, add explicit rounding.

https://bugzilla.gnome.org/show_bug.cgi?id=768317
2016-07-05 20:41:13 +02:00
775187b2e4 osdWindow: Fix level bar width
Commit 9b07ce1d0d changed the OSD window's level bar to be a regular
actor instead of a custom drawn bar. The bar actor's width depends on
both the configured level (e.g. 40%) and the available width, however
the width is currently only updated when the configured level changes.
Fix that by properly considering changes to the parent's width as well.

https://bugzilla.gnome.org/show_bug.cgi?id=768317
2016-07-05 17:47:44 +02:00
99b5e10acf overview: Move ::scroll-event signal handling (again)
Commit c39ffa111 moved the signal handling from the controls- to the
background-group to enable scrolling on non-primary monitors.
However this broke scrolling on reactive overview elements as the
workspace switcher, as they're not descendants of the background.
To fix, move scroll-event handling to the overview group itself,
which is the common ancestor of all overview elements.

https://bugzilla.gnome.org/show_bug.cgi?id=768316
2016-07-05 17:47:44 +02:00
208ed6e90d Updated Slovak translation 2016-07-05 14:53:34 +00:00
de8d4c4cd8 Update URL in a translator comment 2016-07-01 18:46:22 +02:00
3ae591434d Updated British English translation 2016-07-01 17:27:42 +01:00
61fb62f969 Restart: fix maximized windows flickering to the wrong struts
When we restart, we need to update the struts for the screen before
we enter the main loop, or maximized windows will get resized to the
size of the screen without struts, then resized back.

A workaround is needed for a Clutter bug that occurs when we get
the size of an actor before the first paint of the stage.

https://bugzilla.gnome.org/show_bug.cgi?id=761566
2016-06-30 14:17:19 -04:00
c4584c20dc run-js-test: fix running in hi-dpi mode 2016-06-30 14:17:19 -04:00
c6eb95ff3a Updated Spanish translation 2016-06-30 14:02:07 +00:00
ab68360d53 endSessionDialog: Add support for system upgrades
https://bugzilla.gnome.org/show_bug.cgi?id=763611
2016-06-30 11:42:11 +02:00
58a733dc93 endSessionDialog: Use new PackageKit DBus API
https://bugzilla.gnome.org/show_bug.cgi?id=763611
2016-06-30 11:33:07 +02:00
db8f6b4848 endSessionDialog: Rename a variable
https://bugzilla.gnome.org/show_bug.cgi?id=763611
2016-06-30 11:33:06 +02:00
e72d388a67 background: free MetaBackground explicitly when its MetaBackgroundActor is destroyed
The memory which MetaBackground resides is freed automatically, when its
wrapper object Background is freed by garbage collection. But because the
memory for MetaBackground is huge, changing the background or changing the
background mode repeatedly makes a lot of memory to be in use until garbage
collection runs.

This patch frees the MetaBackground object explicitly when its
MetaBackgroundActor is destroyed which is the moment that the memory in the
object is not used anymore.

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

Signed-off-by: Hyungwon Hwang <hyungwon.hwang7@gmail.com>
2016-06-29 13:27:10 +02:00
b5dd4d1456 screenShield: Chain up Arrow's style_changed vfunc
This makes style changes propagate to our child widget as they
should.

https://bugzilla.gnome.org/show_bug.cgi?id=739178
2016-06-28 19:53:17 +02:00
a7562b4148 screenShield: Stop using an offscreen buffer for the arrow actor
This isn't a performance critical actor and the NVIDIA driver discards
offscreen buffers in some cases which would require us to go through
extra hoops to handle here which isn't worth it.

https://bugzilla.gnome.org/show_bug.cgi?id=739178
2016-06-28 19:53:17 +02:00
358f64d66b main: Reload theme on video memory purge errors
The theme machinery uses FBOs in some cases (mainly for shadows) which
need to be reloaded if we get a video memory purged error.

https://bugzilla.gnome.org/show_bug.cgi?id=739178
2016-06-28 19:53:17 +02:00
2a7f9f70b8 shell-recorder: Avoid a crash when the cursor texture is NULL
When running as a wayland compositor, MetaCursorTracker might
legitimately not have a displayed cursor because e.g. a client unsets
the cursor surface.

Note that, under an X session, the assumption that the tracker always
has a cursor texture is true because XFixesGetCursorImage() always
returns data even if the cursor isn't visible.

https://bugzilla.gnome.org/show_bug.cgi?id=767001
2016-06-28 19:03:33 +02:00
c91085caf7 shell-recorder: Ensure we remove the redraw timeout on finalize
Otherwise we may end up using freed memory and crashing

https://bugzilla.gnome.org/show_bug.cgi?id=767001
2016-06-28 19:03:32 +02:00
21ddbf0b8f workspacesView: Consider workspaces-only-on-primary when panning
It is odd to switch workspaces on the primary monitor when panning on
a monitor without workspaces, so reject the gesture on non-primary
monitors when workspaces-only-on-primary is disabled.

https://bugzilla.gnome.org/show_bug.cgi?id=766883
2016-06-27 16:31:00 +02:00
2ad2853278 workspacesView: Consider workspaces-only-on-primary when scrolling
It is odd to switch workspaces using the scroll wheel when the pointer
is on a monitor without workspaces, so only handle scroll events on
non-primary monitors when workspaces-only-on-primary is disabled.

https://bugzilla.gnome.org/show_bug.cgi?id=766883
2016-06-27 16:31:00 +02:00
e16f63a8e4 workspacesView: Allow activating empty workspaces on any monitor
We allow activating a workspace by clicking it when we know that
the user did not try to select a window and missed (namely: the
workspace is empty). However we currently always check for an
empty workspace on the primary monitor, which doesn't make sense
when the click happened on a different monitor.

https://bugzilla.gnome.org/show_bug.cgi?id=766883
2016-06-27 16:31:00 +02:00
c39ffa111f overview: Move overview actions and scrolling to background group
Both the Overview::scroll-event and actions added via addAction()
are meant to work anywhere in the overview, but for now only work
on the primary monitor. Move the handling to the background group
that is known to span all outputs to fix.

https://bugzilla.gnome.org/show_bug.cgi?id=766883
2016-06-27 16:31:00 +02:00
5182129196 overview: Remove stack actor
The stack was used to overlay a message indicator over the overview
group. That indicator is long gone, so there's no longer a need for
an intermediate actor in the hierarchy.

https://bugzilla.gnome.org/show_bug.cgi?id=766883
2016-06-27 16:31:00 +02:00
02bad8e92b workspacesDisplay: Cancel click when panning
When switching between workspaces via panning, we don't want to
leave the overview when we end up on an empty workspace.

https://bugzilla.gnome.org/show_bug.cgi?id=766883
2016-06-27 16:31:00 +02:00
500ea13155 workspacesView: Initialize the adjustment's upper bound
Initializing the upper bound to zero means that on panning we'd start
scrolling from the first workspace even if the current workspace when
entering the overview was different since StAdjustment clamps the
value to be inside bounds.

https://bugzilla.gnome.org/show_bug.cgi?id=766883
2016-06-27 14:43:17 +02:00
ce8e7481e7 Updated Indonesian translation 2016-06-24 10:55:24 +00:00
528f2e3cdc Updated Indonesian translation
(cherry picked from commit 23788b9e7d)
2016-06-24 10:52:54 +00:00
408211ba73 Arrow: compute a paint volume that accounts for the shadow
Otherwise the shadow gets clipped to the actor's allocation.

https://bugzilla.gnome.org/show_bug.cgi?id=767954
2016-06-23 18:57:05 +02:00
e02467eada ScreenShield: fix setting each arrow's opacity on _animateArrows()
https://bugzilla.gnome.org/show_bug.cgi?id=767954
2016-06-23 18:57:04 +02:00
3e93a1bdd6 StShadowHelper: properly use the actor's box to paint the shadow
We're using an unitialized box resulting in an undefined shadow box
size.

_st_paint_shadow_with_opacity() already computes the shadow's bounding
box from the source actor's box so we just need to pass that along.

https://bugzilla.gnome.org/show_bug.cgi?id=767954
2016-06-23 18:57:02 +02:00
a69a9ba51a Bump version to 3.21.3
Update NEWS.
2016-06-21 21:55:26 +02:00
1c0e0191e0 build: Fix check-for-missing for srcdir != builddir 2016-06-21 21:55:26 +02:00
f233122d4d Updated Brazilian Portuguese translation 2016-06-14 00:53:53 +00:00
72bfa91259 theme-node: Fix leak on stylesheet change.
on_custom_stylesheet_changed() would set properties_computed to FALSE
without freeing the old properties, then the properties pointer would
be overwritten in ensure_properties().

https://bugzilla.gnome.org/show_bug.cgi?id=710230
2016-06-12 00:57:18 +02:00
ef195f0185 Updated Spanish translation 2016-06-06 07:10:55 +00:00
47da6b139e Updated Turkish translation 2016-06-04 21:13:45 +00:00
2705434955 NetworkAgent: Handle VPN service aliases
A VPN plugin can support multiple services, indicated by an 'aliases' key.

We need to be able to spawn the appropriate auth-dialog for these aliases,
as well as the base service.

Covered as an afterthought (from comment 57) in
https://bugzilla.gnome.org/show_bug.cgi?id=658484

See also https://bugzilla.gnome.org/show_bug.cgi?id=746664 and
https://bugzilla.gnome.org/show_bug.cgi?id=767197
2016-06-03 18:27:46 +01:00
a7e030d0f9 Updated Occitan translation 2016-05-30 18:45:39 +00:00
8a44170f83 Updated Portuguese translation 2016-05-30 14:31:38 +00:00
2ea6ae05e5 keyboard: save the MRU input sources list when switching
And restore it when reloading the current list of sources, if
appropriate.

https://bugzilla.gnome.org/show_bug.cgi?id=766826
2016-05-27 10:46:58 -07:00
5c0eba7d3b keyboard: add an interactive argument to input source activation
This is useful to differentiate between a change due to user interaction
or automatic loading.

https://bugzilla.gnome.org/show_bug.cgi?id=766826
2016-05-27 10:46:58 -07:00
f81887772a keyboard: split out a function to udpate the MRU list
We're going to add saving of the MRU list in the function in a later
commit.

https://bugzilla.gnome.org/show_bug.cgi?id=766826
2016-05-27 10:46:58 -07:00
9aa3d864dc keyboard: split out a function
We're going to use this in a later commit.

https://bugzilla.gnome.org/show_bug.cgi?id=766826
2016-05-27 10:46:58 -07:00
2425b11df6 system: Do not disable suspend action when locked
gnome-settings-daemon now allows the corresponding keybinding, so
for consistency it makes sense to show the button as well.

https://bugzilla.gnome.org/show_bug.cgi?id=725960
2016-05-27 17:04:47 +02:00
1cb644529f loginManager: Extend canSuspend() callback
The underlying logind API does not only indicate whether suspend is
available, but also whether the user is eligible for executing the
operation without further authentication. This information can be
relevant, so pass it to the callback.

https://bugzilla.gnome.org/show_bug.cgi?id=725960
2016-05-27 17:04:46 +02:00
6cff0fd994 Bump version to 3.21.2
Update NEWS.
2016-05-27 15:57:07 +02:00
437256e0f1 location: Update for PermissionStore DBus API changes
As xdg-app has been renamed to Flatpak, the permission store's
bus name and interface name have been changes as well.

https://bugzilla.gnome.org/show_bug.cgi?id=766598
2016-05-27 15:31:50 +02:00
841e0132e9 network: Improve labels for Bluetooth devices
Bluetooth is not "Mobile Broadband", so rename the settings link
accordingly. Also use a more assertive connect label.

https://bugzilla.gnome.org/show_bug.cgi?id=757019
2016-05-27 01:03:25 +02:00
1545596c7e AppIconMenu: properly destroy on source destroy.
If the source actor is destroyed while the popupMenu is shown -- this
can happen if a non favorite application was closing or crashes -- the
menu actor is improperly destroyed.

This makes the popupMenu close first and does a clean ungrab instead.

https://bugzilla.gnome.org/show_bug.cgi?id=757556
2016-05-27 01:03:25 +02:00
38406e070c Use the org.gnome.desktop.calendar schema instead of our own
This setting is now shared by Shell and Calendar.

https://bugzilla.gnome.org/show_bug.cgi?id=766318
2016-05-26 23:05:24 +02:00
9b07ce1d0d osdWindow: don't use custom cairo drawing
We can just set the width on a regular actor inside the StBin.

https://bugzilla.gnome.org/show_bug.cgi?id=758471
2016-05-20 17:28:06 -07:00
bf8d30603e windowManager: Avoid code duplication
The various switcher keybindings are handled identically, except for
the popup that is shown; update the code to reflect that instead of
duplicating the code again and again.

https://bugzilla.gnome.org/show_bug.cgi?id=730739
2016-05-19 17:34:00 +02:00
bd6e7f14d1 altTab: Take over cycle-windows/cycle-group keybindings
The code to handle cycling through windows without showing a popup
was removed from mutter a while ago, which left the corresponding
keybindings mostly broken (i.e. they now only switch between two
windows). With the various switch-foo keybindings handled by the
shell, it is now easier to take over the cycle-foo keybindings as
well.

https://bugzilla.gnome.org/show_bug.cgi?id=730739
2016-05-19 17:34:00 +02:00
5226d8b086 st: Init framebuffer early to fix gnome-shell crash on NVIDIA drivers
Checking offscreen for COGL_INVALID_HANDLE is not sufficient,
as cogl_offscreen_new_with_texture doesn't initialize framebuffer
objects but lets Cogl solve this the lazy way.
cogl_offscreen_new_with_texture will never return COGL_INVALID_HANDLE
anyways.

https://bugzilla.gnome.org/show_bug.cgi?id=764898
2016-05-17 15:00:04 +02:00
bd92331780 Updated Icelandic translation
(cherry picked from commit 3bbf681385)
2016-05-14 22:23:59 +00:00
387f5143f0 st: Use case-insensitive shortcuts
For shortcuts that involve a letter (like <ctrl>c), we currently only
accept the lower-case variant. This makes shortcuts awkward to use when
caps-lock is active, and is inconsistent with GTK+, so accept upper-case
variants as well.

https://bugzilla.gnome.org/show_bug.cgi?id=766325
2016-05-12 18:10:04 +02:00
b7867fe44c build: Set rpath on more executables
We need to point executables to our private cogl/clutter forks.
Commit 093fd54e2 did this for the main executable, but forgot
the extension-prefs tool and other helpers.
2016-05-12 18:10:04 +02:00
ddea54a539 ScreenShield: set LockedHint property from systemd
Logind recently got support for a hint property in Session Object to
inform if session is Locked or not. It is up to desktop environments
to keep this property up to date.

https://bugzilla.gnome.org/show_bug.cgi?id=764773
2016-05-12 15:24:06 +02:00
84da49c715 app: Consider minimized windows for app comparisons
We used to take window visibility into account when comparing apps
until commit 1dfc38d078, following changes in the window switcher
due to auto-minimization. However auto-minimization was abolished
and the window switcher changes reverted, so it makes sense again
to sort apps without non-minimized windows last again.

https://bugzilla.gnome.org/show_bug.cgi?id=766238
2016-05-10 21:36:33 +02:00
513dff45c1 Updated Occitan translation 2016-05-09 19:07:49 +00:00
3d697baa26 Updated Japanese translation 2016-05-08 06:16:50 +00:00
9eda10d091 Updated Norwegian bokmål translation. 2016-05-01 14:21:21 +02:00
0f82da8735 Updated Portuguese translation 2016-04-30 15:47:20 +00:00
296b61b61c Bump version to 3.21.1
Update NEWS.
2016-04-29 12:22:01 +02:00
974a896dbc Updated Scottish Gaelic translation 2016-04-29 09:57:17 +00:00
093fd54e2b build: Point executables to our private lib path
We now link to cogl/clutter forks in a private location, so make
sure we set the rpath of executables to point the runtime linker
to the correct location.
2016-04-28 19:35:05 +02:00
5ae3e5aeb7 build: Explicitly add mutter-cogl-pango dependency 2016-04-28 14:11:04 +02:00
af28a219be Build with merged mutter/clutter/cogl
https://bugzilla.gnome.org/show_bug.cgi?id=760439
2016-04-27 20:19:59 +02:00
1883df2927 dnd: Cancel the animation on drag actor destruction
If the drag actor is destroyed before the animation
callback is called, the callback is never called and
we're sticked with dnd grabing the events after we
dropped the target.

https://bugzilla.gnome.org/show_bug.cgi?id=757676
2016-04-27 18:22:00 +02:00
3274f270e3 Updated Esperanto translation 2016-04-27 00:08:10 +02:00
c97626e516 Update gvc submodule
https://bugzilla.gnome.org/show_bug.cgi?id=765607
2016-04-26 15:47:29 +02:00
9c483dd9a6 system: Only show rotation lock when a builtin output is present
We currently show the orientation lock button when an accelerometer
is present, however gnome-settings-daemon's xrandr plugin only applies
rotation when a builtin monitor is present. Update the button's
visibility to match gnome-settings-daemon.

https://bugzilla.gnome.org/show_bug.cgi?id=765267
2016-04-21 21:16:50 +02:00
8fd6e93fbe workspaceThumbnail: Fix size request signatures
ClutterLayoutManager's size request methods have an additional container
argument before the for-width/height parameters compared to ClutterActor.

https://bugzilla.gnome.org/show_bug.cgi?id=763068
2016-04-21 16:04:04 +02:00
8416ba25de st: Don't assert when corner texture creation fails 2016-04-15 19:05:04 +02:00
63f6ff9151 Do not skip CoglError parameters
While CoglError is a define to GError, it doesn't follow the convention
of ignoring errors when NULL is passed, but rather treats the error as
fatal :-(
That's clearly unwanted for a compositor, so make sure to always pass
an error parameter where a runtime error is possible

https://bugzilla.gnome.org/show_bug.cgi?id=765061
2016-04-15 18:22:18 +02:00
59c2ace98c st: Do not try to unref NULL CoglObjects
https://bugzilla.gnome.org/show_bug.cgi?id=765061
2016-04-15 18:22:18 +02:00
cf4465027a [l10n][fa] Fix weekday translation string 2016-04-14 23:05:11 +04:30
a23b293fe2 modalDialog: Fix invalid argument 'timestamp' for pushModal
https://bugzilla.gnome.org/show_bug.cgi?id=722752
2016-04-14 11:10:51 +02:00
c039a3ddda recorder: Fall back to ~ if XDG_VIDEOS_DIR doesn't exist
Unlike screenshots, recordings fail when the default directory doesn't
exist. Fall back to home instead.

https://bugzilla.gnome.org/show_bug.cgi?id=765015
2016-04-13 21:25:31 +02:00
ebe071bd50 Bump version to 3.20.1
Update NEWS.
2016-04-13 18:46:38 +02:00
2edfd458b7 Update Arabic translation 2016-04-10 20:28:02 +02:00
3b750aa815 Added Bulgarian translation 2016-04-09 08:30:01 +03:00
d96f97e55a Update Persian translations 2016-04-08 20:46:03 +04:30
55ac2f46ba Updated Friulian translation 2016-04-08 09:31:04 +00:00
262c04ab91 Updated Friulian translation 2016-04-05 20:14:39 +00:00
c80e7784fb Updated Friulian translation 2016-04-02 23:34:03 +00:00
763567377f Updated Friulian translation 2016-03-31 08:56:25 +00:00
ea9dcbf8b7 Updated Friulian translation 2016-03-31 08:46:12 +00:00
2b383bf73e Updated Friulian translation 2016-03-31 06:40:06 +00:00
b8dcbfebb2 Updated Friulian translation 2016-03-30 22:18:45 +00:00
a257aa35d5 Updated Friulian translation 2016-03-30 22:09:08 +00:00
941513b280 st: Fix offscreen leak if cogl_framebuffer_allocate fails
If cogl_framebuffer_allocate fails in _st_create_shadow_pipeline_from_actor, the
CoglOffscreen* that was allocated earlier in the function is leaked.

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

Signed-off-by: Aaron Plattner <aplattner@nvidia.com>
2016-03-30 15:59:10 -04:00
a9bb0558bc Updated Czech translation 2016-03-30 08:27:21 +02:00
58834b80d7 update zh_CN translation 2016-03-26 15:13:42 +08:00
b125a0e371 Updated Vietnamese translation
Signed-off-by: Trần Ngọc Quân <vnwildman@gmail.com>
2016-03-26 13:43:56 +07:00
980ac0da8a Updated Friulian translation 2016-03-24 22:11:37 +00:00
f15fb0bd73 Updated Chinese (Taiwan) translation 2016-03-24 17:08:39 +00:00
7d25592165 Updated Basque language 2016-03-23 20:56:09 +01:00
9ee36f2b71 Updated Slovenian translation 2016-03-22 22:27:08 +01:00
f3e226103f Updated Ukrainian translation 2016-03-22 22:31:00 +02:00
a03e5662e2 Bump version to 3.20.0
Update NEWS.
2016-03-22 18:14:58 +01:00
16bb3efeb9 Updated Japanese translation 2016-03-21 02:44:48 +00:00
e01d867e69 Updated Danish translation 2016-03-20 23:45:33 +01:00
1d4dfd7d5f Update Latvian translation 2016-03-20 21:27:04 +02:00
da05d1d864 Updated French translation 2016-03-20 02:13:36 +00:00
6499424eba Updated Turkish translation 2016-03-19 18:57:04 +00:00
824a602963 Updated Swedish translation 2016-03-18 10:12:11 +00:00
0092d8fff3 Updated Italian translation 2016-03-17 20:21:40 +00:00
5fbe454836 Updated Kazakh translation 2016-03-17 03:39:25 +00:00
23a59d387b Updated Korean translation 2016-03-16 19:50:25 +00:00
6b2a68e553 Bump version to 3.19.92
Update NEWS.
2016-03-16 19:03:53 +01:00
82950ecea0 telepathyClient: Acknowledge messages before closing
While a channel has pending messages, it will pop up again when
dismissed. That is clearly not what users expect, so clear them
out first before closing a channel.

https://bugzilla.gnome.org/show_bug.cgi?id=747991
2016-03-16 18:59:44 +01:00
2da4df219c Updated Russian translation 2016-03-13 21:05:14 +00:00
8b5597fd8d Updated Lithuanian translation 2016-03-13 21:21:30 +02:00
82ae06ad55 Updated Brazilian Portuguese translation 2016-03-13 16:16:19 +00:00
c594b66a2a [l10n] Updated Catalan translation 2016-03-13 14:47:13 +01:00
13e3318e4d Updated Finnish translation 2016-03-13 10:33:44 +00:00
4aa4bb4a6a Updated Slovenian translation 2016-03-12 22:04:47 +01:00
4a74df86e2 Updated Greek translation 2016-03-12 12:38:15 +00:00
30ebc9c241 Updated German translation 2016-03-12 12:33:42 +00:00
e0f6cf538d Updated Galician translations 2016-03-12 13:16:26 +01:00
ba71382c72 Updated Spanish translation 2016-03-11 15:31:51 +00:00
87eb0d7e2f Updated Hebrew translation 2016-03-11 14:51:10 +02:00
da199242b2 theme: Actually apply style changes
Commit e86c2826e updated the SASS submodule without actually applying
the changes to the generated CSS.

https://bugzilla.gnome.org/show_bug.cgi?id=762480
2016-03-11 11:09:19 +01:00
5e3d378667 Updated Hungarian translation 2016-03-11 06:48:23 +00:00
a6d2735373 Updated Serbian translation 2016-03-11 02:57:07 +01:00
2ea435a928 Updated Slovak translation 2016-03-10 18:21:12 +00:00
75ba75900c extensionPrefs: Stop using custom CSS
GTK+ now has a documented CSS class for circular buttons that we can
use for the preference buttons instead of custom CSS.
2016-03-10 18:16:33 +01:00
7bacf4e344 Updated Polish translation 2016-03-10 17:27:29 +01:00
258993d8ad Updated Czech translation 2016-03-10 16:35:36 +01:00
ff19e411a2 location: Style reason label
https://bugzilla.gnome.org/show_bug.cgi?id=762480
2016-03-10 15:24:21 +00:00
e86c2826ef Update to latest gnome-shell-sass
https://bugzilla.gnome.org/show_bug.cgi?id=762480
2016-03-10 15:24:21 +00:00
64741e41df location: Replace description w/ privacy note
https://bugzilla.gnome.org/show_bug.cgi?id=762480
2016-03-10 14:51:32 +00:00
fceac27412 Updated Danish translation 2016-03-06 19:50:19 +01:00
0a394799da Updated Friulian translation 2016-03-06 14:05:09 +00:00
b83f2c0e33 Updated Dutch translation 2016-03-05 21:57:19 +01:00
225f825faf Updated Slovenian translation 2016-03-05 20:45:01 +01:00
ed054f4f40 Updated Korean translation 2016-03-05 12:49:32 +00:00
a1244a9b26 Update Latvian translation 2016-03-03 22:08:36 +02:00
3a3714f4ff Bump version to 3.19.91
Update NEWS.
2016-03-03 17:13:03 +01:00
be483c4137 legacyTray: Style the slider's child, not the slider
This avoids jiggling when showing/hiding the tray. Based on a
suggestion from maxnevesnunes@gmail.com in bug 750022.

https://bugzilla.gnome.org/show_bug.cgi?id=747957
2016-03-03 17:09:47 +01:00
3492121c3f location: Only ask user once
Let's make it really simple and ask user interactively, once. This
simplifies things for:

* Privacy panel of gnome-control-center as it doesn't have to filter
  applications.

* Apps: If they are denied access, they can simply point users to
  privacy panel of gnome-control-center since they can be sure location
  access for the app can be enabled in there.

Also it's less annoying to user. Before this patch, if they denied
access to application, they had to keep doing that at least each time
they launched the application.

https://bugzilla.gnome.org/show_bug.cgi?id=762559
2016-03-03 16:06:20 +00:00
364f1453c1 Updated Hebrew translation 2016-03-03 14:52:51 +02:00
9392e50cf1 Updated Russian translation 2016-03-02 22:15:25 +00:00
f60a6ab465 Updated Lithuanian translation 2016-03-02 20:52:50 +02:00
f3a92d558d Update Arabic translation 2016-03-02 14:45:02 +04:00
d387d4a60d Update zh_CN translation 2016-03-02 13:50:42 +08:00
4503ca4ca0 Update zh_CN translation 2016-03-02 13:47:56 +08:00
eeb10c0ce3 Updated Czech translation 2016-03-01 10:51:13 +01:00
c69fcc2ef8 Bugfix in Afrikaans (af) translation 2016-03-01 08:51:00 +02:00
7d67d88ae8 Updated translation for Afrikaans (af) 2016-02-29 19:52:58 +02:00
310622b14e Updated Kazakh translation 2016-02-29 09:26:51 +00:00
00065b84e1 Updated Hungarian translation 2016-02-28 16:43:16 +00:00
4f7a8902f8 Updated Occitan translation 2016-02-27 18:48:31 +00:00
d20a6e0988 Mark an invalid string in the Irish translation as fuzzy
Apparently, javascript-format in gettext doesn't support reversing
the order of variables with %1$s, and this string trips validation.
2016-02-27 18:47:34 +01:00
96fa7b7e77 Update Catalan translation 2016-02-27 16:36:48 +01:00
61e4d40852 Updated Swedish translation 2016-02-27 13:33:58 +00:00
cc826f77fb Updated German translation 2016-02-26 14:17:51 +00:00
1de288c5bb build: Fix build with clang -Werror
https://bugzilla.gnome.org/show_bug.cgi?id=755659
2016-02-26 02:06:55 +08:00
fe986faa2d Updated Greek translation 2016-02-25 09:48:13 +00:00
f11b404622 Updated Galician translations 2016-02-23 16:24:15 +01:00
508668107b st-entry: Disable middle-click-paste when entry is not editable
Should only allow pasting the primary selection when the entry is
editable.

https://bugzilla.gnome.org/show_bug.cgi?id=762507
2016-02-23 06:48:50 -06:00
674454621f Updated Ukrainian translation 2016-02-23 13:08:54 +02:00
2c907bd422 Updated Chinese (Taiwan) translation 2016-02-23 02:52:30 +00:00
4eb6c0c4ee location: Put app permission in GNOME table
Alex told me that since it's not geoclue but rather GNOME-components
storing/accessing app permissions, it's better if we put it under
'gnome' rather than generic 'desktop' table.
2016-02-22 22:55:09 +00:00
dd2eff2b6f Updated Spanish translation 2016-02-22 21:26:18 +01:00
d8960b396b windowManager: Only animate dimming changes when necessary
Now that we no longer skip dimming/undimming windows while showing
the overview, we can still save a bit of work by changing the dimming
without animation while the window is hidden.

https://bugzilla.gnome.org/show_bug.cgi?id=762475
2016-02-22 19:42:57 +01:00
4c29604e1e windowManager: Always check dimming when an attached modal opens/closes
We skip window animations while the overview is shown (and the window
group is hidden) to avoid unnecessary work. However when an attached
modal dialog is opened or closed, this involves checking whether the
parent window should be dimmed - skipping that test means that we can
simply fail to dim or undim a window altogether, so do that check
unconditionally.

https://bugzilla.gnome.org/show_bug.cgi?id=762475
2016-02-22 19:42:57 +01:00
ede0bf2d88 messageList: Add missing import
We lost that when code was split out from calendar.js ...
2016-02-22 19:33:17 +01:00
893bfdf85f Updated Brazilian Portuguese translation 2016-02-20 21:51:41 +00:00
ac7a4c27fd updated Punjabi Translation 2016-02-20 12:36:37 -06:00
4fe0233139 Updated Polish translation 2016-02-20 16:29:15 +01:00
f9f9c7fe5b Updated Serbian translation 2016-02-19 20:25:26 +01:00
f1b90f174a Bump version to 3.19.90
Update NEWS.
2016-02-19 18:12:28 +01:00
3dd74c86c1 Update Catalan translation 2016-02-19 16:19:47 +01:00
0edbdc529e location: Add translator comments
https://bugzilla.gnome.org/show_bug.cgi?id=762270
2016-02-18 17:37:29 +01:00
b08523b170 Updated Slovak translation 2016-02-18 15:36:25 +00:00
cd2f8d8177 Update to latest gnome-shell-sass
The new location dialog theming comes from there.

https://bugzilla.gnome.org/show_bug.cgi?id=762119
2016-02-18 15:11:11 +00:00
a1e8c79d38 location: Ask user to authorize applications
While we could have implemented this already a while ago, this would
have been a completely false security mechanism since we had no way of
reliably identifying applications. Since now with xdg-app, we can at least
reliably identify bundled applications, let's give users a choice of
which applications in particular they are OK with giving location data
to.

While we still can't reliably identify system (non-xdg-app) applications,
it seems extremely unlikely we'll ever be able to do that (at least not
in the near future) so we'll have to trust them to not lie about their
IDs.

Next release of geoclue will take the ID of bundled application directly
from corresponding xdg-app metadata so bundled applications can't simply
lie about their IDs.

https://bugzilla.gnome.org/show_bug.cgi?id=762119
2016-02-18 15:11:11 +00:00
34fc454764 location: Add AppAuthorizer class
This class will be responsible for authorizing applications that try to
access location information. Since this is mainly targetted for xdg-app
applications, we make use of xdg-app's D-Bus API to store
per-application authorization.

https://bugzilla.gnome.org/show_bug.cgi?id=762119
2016-02-18 15:11:11 +00:00
e98a434ede location: Add dialog to ask for location data access
Add a dialog that is used in a following patch, to ask user if they want
a requesting application to gain access to their location.

Co-author: Florian Müllner <fmuellner@gnome.org>

https://bugzilla.gnome.org/show_bug.cgi?id=762119
2016-02-18 15:11:10 +00:00
02cdc065e7 media section touch ups
- make the missing album art more subtle. Negative space
  asked for sizing the box slightly larger. Don't hate me
  for using border-width for it ;)
2016-02-18 14:58:54 +01:00
77eb8f98c0 Updated Italian translation 2016-02-18 13:05:52 +00:00
68679e1e7e Updated German translation 2016-02-18 09:24:16 +01:00
05f2dbf205 Updated Polish translation 2016-02-17 22:32:49 +01:00
45779bc7be Updated Slovak translation 2016-02-17 21:01:26 +00:00
1bf27b1f18 ibusCandidatePopup: Handle relative cursor signal absence gracefully
Only recent IBus versions have support for this signal
which is used for wayland clients. In order to work
with older IBus versions we can silently ignore the
signal's absence.

https://bugzilla.gnome.org/show_bug.cgi?id=753476
2016-02-17 18:01:02 +01:00
3ecdfaffd2 calendar: Add Media section
We lost media controls outside of notification banners when
implementing the new notification designs. Reimplement this
functionality as a dedicated "Media" section in the message
list based on MPRIS.

https://bugzilla.gnome.org/show_bug.cgi?id=756491
2016-02-17 15:15:16 +01:00
ee8fd1e613 calendar: Split out message list base classes
Currently both the base classes for messages/sections and the message
list itself that instantiates the available sections are located in
the same module. As a result, it isn't possible to define sections
in a different module without introducing circular dependencies. The
Calendar module is already unwieldily large, so split it up a bit to
avoid it growing even bigger in the future.

https://bugzilla.gnome.org/show_bug.cgi?id=756491
2016-02-17 14:56:52 +01:00
ccfd5e35d6 location: Better name for a field
_proxy -> _managerProxy.

https://bugzilla.gnome.org/show_bug.cgi?id=762119
2016-02-17 13:04:16 +00:00
b2eab65a81 Updated POTFILES.in 2016-02-16 18:39:42 +01:00
00814dd159 shell: Fix another indentation warning
The compiler doesn't know about preprocessor conditionals, so indentation
changes confuse -Wmisleading-indentation.
2016-02-16 18:05:14 +01:00
57f9ffcaa7 shell: Fix an indentation issue ...
...pointed out by GCC's new -Wmisleading-indentation warning.
2016-02-16 17:35:39 +01:00
ce83f378a5 shell: Fix coding style 2016-02-16 17:35:39 +01:00
30c7545ff3 audioDeviceSelection: Add audio device selection dialog
It is not always possible to determine the type of audio device that
got plugged in. Add a system modal dialog to query the user in that
case and export in on the bus to gnome-settings-daemon.

https://bugzilla.gnome.org/show_bug.cgi?id=760284
2016-02-16 17:02:00 +01:00
a13357c2a8 ibusCandidatePopup: Add support for relative cursor positioning
IBus now provides a new method for cursor positioning where the
coordinates are relative to the focused window. This is useful for
wayland clients which don't have access to their global coordinates.

https://bugzilla.gnome.org/show_bug.cgi?id=753476
2016-02-15 18:06:53 +01:00
75dc5c16c8 appFavorites: Update Nibbles in rename list 2016-02-12 20:17:02 -06:00
acd5d70209 theme: use update icon for app grid
https://bugzilla.gnome.org/show_bug.cgi?id=761772
2016-02-12 12:12:02 +01:00
669d20bcf0 extensionPrefs: Fix prefs button 2016-02-11 15:01:53 +01:00
793a8005a5 Updated French translation 2016-02-11 08:43:48 +00:00
23b81fb241 Updated Polish translation 2016-02-06 16:17:22 +01:00
73ba9d33eb Updated Slovak translation 2016-02-05 06:37:26 +00:00
75e2a7228c Updated Friulian translation 2016-02-04 16:53:47 +00:00
91d70f2487 theme: make week numbers more legible
https://bugzilla.gnome.org/show_bug.cgi?id=683245
2016-02-01 13:16:20 +01:00
779b1ae8e5 slider: Emit a 'drag-begin' signal when starting to drag
We are already emitting a 'drag-end' signal when no more dragging
is happening, so it makes sense to emit a 'drag-begin' too when
starting, so that apps interested in implementing different logic
between those two events can easily do it without needing to deal
with the underlying 'button-press-event' signal for the actor.

https://bugzilla.gnome.org/show_bug.cgi?id=761208
2016-01-27 22:35:11 +00:00
346ffd14d7 NetworkAgent: correctly identify the VPN secret requests
The non-interactive requests for 'vpn' settings are forwarded to the UI because
it is able to talk to the auth helpers. However, the VPN requests are identified
by the connection type instead of setting type. That is incorrect and the UI
is not prepared to handle such requests; tries to construct a dialog and fails
miserably:

  Gjs-Message: JS LOG: Invalid connection type: vpn

  (gnome-shell:13133): Gjs-WARNING **: JS ERROR: Error: No property 'text' in property list (or its value was undefined)
  NetworkSecretDialog<._init@resource:///org/gnome/shell/ui/components/networkAgent.js:60
  wrapper@resource:///org/gnome/gjs/modules/lang.js:169
  _Base.prototype._construct@resource:///org/gnome/gjs/modules/lang.js:110
  Class.prototype._construct/newClass@resource:///org/gnome/gjs/modules/lang.js:204
  NetworkAgent<._handleRequest@resource:///org/gnome/shell/ui/components/networkAgent.js:724
  wrapper@resource:///org/gnome/gjs/modules/lang.js:169
  NetworkAgent<._newRequest@resource:///org/gnome/shell/ui/components/networkAgent.js:715
  wrapper@resource:///org/gnome/gjs/modules/lang.js:169

https://bugzilla.gnome.org/show_bug.cgi?id=760999
2016-01-26 17:31:34 +01:00
558b51f555 Updated Hungarian translation 2016-01-25 11:16:10 +00:00
ef18b7ea25 Updated Bulgarian translation 2016-01-22 07:45:32 +02:00
0044e225aa Bump version to 3.19.4
Update NEWS.
2016-01-21 21:50:35 +01:00
c25c143b24 st-widget: Avoid passing NULL to atk_object_get_role()
This never worked since the code landed but apparently no-one noticed
until now.

The intent here is to return the accessible's default role if none has
been explicitly set on the StWidget instance.

https://bugzilla.gnome.org/show_bug.cgi?id=760945
2016-01-21 16:49:06 +01:00
b87da87252 st-widget: Fix a potentially infinite recursion
Commit ffe4eaf00d changed this code to
call st_widget_get_accessible_role() instead of using the value
directly which would be an infinite recursion if that function didn't
have a bug. As it is, this just resulted in

CRITICAL **: atk_object_get_role: assertion 'ATK_IS_OBJECT
(accessible)' failed

https://bugzilla.gnome.org/show_bug.cgi?id=760945
2016-01-21 16:49:05 +01:00
f9258bb5e3 Updated Russian translation 2016-01-15 10:17:59 +00:00
3d747b00e6 tone down modal dialogs borders
https://bugzilla.gnome.org/show_bug.cgi?id=760577
2016-01-13 15:04:49 +01:00
450345b4d0 style week numbers
https://bugzilla.gnome.org/show_bug.cgi?id=683245
2016-01-13 14:49:23 +01:00
7563e1ebcd Updated Lithuanian translation 2016-01-10 18:12:39 +02:00
f96cc4dd69 Updated Turkish translation 2016-01-09 21:33:23 +00:00
c65a9c4d2e authPrompt: Do not allow bypassing disabled Sign In button
The Next and Sign In buttons are disabled when the username/password
field is empty. However, the user can still bypass this button by
pressing the enter key, leading to some odd glitches with the log in
for 'Not Listed?' users.

This is easy to fix by simply not progressing to the next screen when
the button is disabled.

https://bugzilla.gnome.org/show_bug.cgi?id=746180
2016-01-07 17:19:04 -06:00
c01bd37edc Updated Norwegian bokmål translation. 2016-01-07 22:59:36 +01:00
021cecbce2 NetworkAgent: Fix double-unref in get_secrets_keyring_cb()
In get_secrets_keyring_cb, we own a ref on the 'attributes' hash table
from secret_item_get_attributes), and a ref on the 'secret' object (from
secret_item_get_secret(), but in the SHELL_KEYRING_SK_TAG case, we unref
these once before breaking out of the loop, and the second time after
breaking out of the loop.

https://bugzilla.gnome.org/show_bug.cgi?id=759708
2016-01-07 15:27:42 +01:00
2a0cb7ff05 Updated Czech translation 2016-01-04 23:55:22 +01:00
0085a94706 Add flag no-javascript-format for date string 2016-01-04 19:41:49 +01:00
5db38194dc Updated German translation 2016-01-02 16:21:17 +00:00
2a26143149 Updated Indonesian translation
(cherry picked from commit cca01e3f02)
2016-01-02 12:12:53 +00:00
62f22557aa Updated Brazilian Portuguese translation 2015-12-31 18:39:27 +00:00
516ea5a02e Updated Lithuanian translation 2015-12-20 14:54:29 +02:00
9154471aba Updated Lithuanian translation 2015-12-20 14:51:57 +02:00
fbf6746acf Bump version to 3.19.3
Update NEWS.
2015-12-17 01:35:39 +01:00
a36686a6aa extensionSystem: Fix updating extension list on session update
Before reenabling all extensions, we update the list of enabled extensions
to catch any changes that happened while extensions were enabled. However
this is currently broken as onEnabledExtensionsChanged() is a nop while
disabled, so just call getEnabledExtensions() directly.
2015-12-16 23:50:42 +01:00
fd837d74d1 Updated Czech translation 2015-12-06 23:00:19 +01:00
fd57334395 Updated Czech translation 2015-12-06 22:53:28 +01:00
85100cb65f Updated Kazakh translation 2015-12-06 14:34:14 +00:00
c70f6278d6 Updated Slovak translation 2015-12-06 12:04:43 +00:00
e573441bac Updated Turkish translation 2015-12-05 23:34:42 +00:00
5ed9571b37 Updated Ukrainian translation 2015-12-05 16:56:48 +02:00
9d203ddc0f workspace: Keep track of the dragging touch sequence
draggable.startDrag() is called directly here (i.e. manualMode is not set),
we must keep track of the touch event and pass it to startDrag() then.

https://bugzilla.gnome.org/show_bug.cgi?id=756748
2015-12-04 12:16:56 +01:00
508a13ae72 dnd: Implement touch event support
We need to keep track of the pointer emulating touch sequence. In order
to have events properly redirected on touch devices, the
Clutter.grab_pointer and ungrab_pointer() have been replaced by the grab()
and grab_sequence() ClutterInputDevice methods, one or the other is used
depending on the device triggering DnD.

An extra "sequence" argument has been added to startDrag, passing null here
will resort to pointer grabs.

This is enough to make thumbnails in the WorkspaceBox draggable through
touch.

https://bugzilla.gnome.org/show_bug.cgi?id=756748
2015-12-04 11:50:13 +01:00
c0b50cbdf2 workspaceThumbnail: Enable activation of thumbnails in the WorkspaceBox
We need a separate handler for TOUCH_BEGIN/END events.

https://bugzilla.gnome.org/show_bug.cgi?id=756748
2015-12-04 11:50:13 +01:00
06f78549bd workspaceThumbnail: Enable activation of window clones on touch
We must handle the TOUCH_END event separately for the evdev input
backend.

https://bugzilla.gnome.org/show_bug.cgi?id=756748
2015-12-04 11:50:13 +01:00
67afd7a6d8 popupMenu: Fix touch handling of PopupSubMenuMenuItem
It overrides ::button-release-event in order to implement the
hidden/shown toggling, it must do the same on TOUCH_END, otherwise
menus stay shown on touch.

https://bugzilla.gnome.org/show_bug.cgi?id=756748
2015-12-04 11:50:13 +01:00
ffa8c2f2b1 workspacesView: Return from overview when tapping on an empty workspace
This works for pointers and touch on X11, there is however no pointer
emulation on evdev, so touch triggers ::clicked with button==0 which
is ignored.

https://bugzilla.gnome.org/show_bug.cgi?id=756748
2015-12-04 11:50:12 +01:00
3803a880e8 loginDialog: Reconsider user for user list when user changes
Generally a user-changed operation will be uninteresting, but if the
user is currently in the user list and the account changes to locked, we
want to remove it from the list, or if the user is not in the list and
the account changed to unlocked, we want to add it to the list. This
fixes the case where a new user account created in gnome-control-center
does not appear in the user list. The password mode is set in the new
account immediately after it is created, but the operations are not
atomic, so the login dialog considers the new user account when it is
still locked and rejects it from being displayed, then immediately
afterwards the account is unlocked. This commit causes the login dialog
to show the account when this occurs.

The containsUser() check here is not strictly necessary, but reduces
spurious calls to addUser() and removeUser(), since there's no easy way
to check if the locked status of the account has changed (as it's much
easier to connect to one signal on the UserManager than to
notify::locked on each User object).

https://bugzilla.gnome.org/show_bug.cgi?id=758568
2015-12-02 18:23:36 +01:00
965aedb0bb background: Reload animation on timezone changes
Animated backgrounds are based on a start time in local time - in case
of a timezone change, that time is no longer accurate. To fix, we need
to either make BGSlideShow aware of timezone changes (and notify us to
update the animation), or just reload the animation - timezone changes
should be a rare event, so go with the simpler second option.

https://bugzilla.gnome.org/show_bug.cgi?id=758939
2015-12-02 17:18:39 +01:00
80911535a7 altTab: Fix window-switcher on HiDPI displays
We need to take the scale factor into account to avoid tiny window
previews on HiDPI.

https://bugzilla.gnome.org/show_bug.cgi?id=758676
2015-12-02 10:31:36 +01:00
ca401d5036 build: Bump gsettings-desktop-schemas requirement
We need 3.19.2 for the show-battery-percentage key.
2015-12-01 16:40:55 +01:00
a1c091d98d Bump version to 3.19.2
Update NEWS.
2015-11-25 00:34:56 +01:00
e1e08f0a68 loginDialog: Fix TypeError when user is deleted
LoginDialog has a private _user, but UserListItem has a public user.
Easy to get wrong since _user would be the right thing to type in 90% of
this file.
2015-11-23 17:44:49 -06:00
1a4f629554 Updated Russian translation 2015-11-23 19:20:29 +00:00
4113be770b Updated Spanish translation 2015-11-23 19:02:49 +01:00
cf3f4850b8 Updated Esperanto translation 2015-11-23 00:39:12 +01:00
14f374096a Updated Czech translation 2015-11-22 13:05:02 +01:00
6fef5c37f7 Updated Portuguese translation 2015-11-21 09:03:47 +00:00
6e7455aa1e Updated Hebrew translation 2015-11-19 20:38:03 +02:00
03bf6fa399 theme-node: Use the correct framebuffer in paint_* methods
Since commit 48a54e8ac4, paint() has an explicit framebuffer parameter,
however a couple of submethods are still using the draw framebuffer,
which breaks when rendering to an offscreen buffer.
2015-11-19 14:08:14 +01:00
f777e761c0 st: Fix some more cogl deprecations
Replace the remaining cogl_set_source* calls with the explicit
pipeline/framebuffer API.
2015-11-19 14:07:24 +01:00
31201d9618 power: Add battery percentage label
An oft requested feature, available in 4 separate extensions to
gnome-shell, and in most mobile OSes.

https://bugzilla.gnome.org/show_bug.cgi?id=735771
2015-11-19 14:04:22 +01:00
d95d78ac15 browser-plugin: Do not create a new object every time NPPVpluginScriptableNPObject is requested
Merge PluginData and PluginObject structs into a single one and create
the scriptable object associated to the plugin instance in NPP_New. Then,
when NPPVpluginScriptableNPObject is requested we just return the
scriptable object associated to the given instance. This caused the
crashes in NPN_InvokeDefault with WebKit, since we had multiple
scriptable objects for the same instance, but only one of those objects
had the onchange listener installed. Firefox seems to cache the
scriptable object for the instance and therefore NPPVpluginScriptableNPObject
is requested only once.

https://bugzilla.gnome.org/show_bug.cgi?id=737932
2015-11-17 13:17:31 -06:00
bef4f17c49 Updated Spanish translation 2015-11-17 18:52:52 +01:00
f4b7ab0cb6 browser-plugin: Set windowless mode and don't claim to need XEmbed
NPAPI plugins are windowed by default, so we need to set
NPPVpluginWindowBool value to FALSE on startup. This way the browser
will not create a GtkSocket for a GtkPlug that we are not going to
create. It doesn't make sense to claim that we need XEmbed either.

https://bugzilla.gnome.org/show_bug.cgi?id=757940
2015-11-17 11:35:03 -06:00
a180dde01c Updated Scottish Gaelic translation 2015-11-17 17:10:55 +00:00
385c918e2e Updated Scottish Gaelic translation 2015-11-17 16:10:24 +00:00
d7401c8646 Revert "power: Stop making time estimates"
This reverts commit 6c08799c7b.

See https://bugzilla.gnome.org/show_bug.cgi?id=708472#c87
2015-11-17 13:16:45 +01:00
a456d5eb19 bluetooth: Remove unused imports
https://bugzilla.gnome.org/show_bug.cgi?id=758220
2015-11-17 11:25:02 +01:00
6c08799c7b power: Stop making time estimates
Any time estimates we can come up with are notoriously unreliable;
even on devices that report correct (dis)charging rates, any change
in workload, screen brightness etc. can throw our estimate off by
a huge amount. This is further compounded by bad firmware and battery
firmware which reports inaccurate data as neither Windows nor Android do
not use that data.

So instead, limit ourselves to only showing the current percentage
and leave its interpretation to the user.

As an added bonus, we end up with shorter strings that are less likely
to cause problems with ellipsization when translated.

https://bugzilla.gnome.org/show_bug.cgi?id=708472
2015-11-17 10:58:45 +01:00
8d7bb6496c autorunManager: Follow Files' notification policy
Builtin chat and network notifications already follow the notification
policy of appropriate applications, it makes sense to do the same for
autorun notifications to give users control over hotplug notifications
in Settings.
2015-11-17 00:00:31 +01:00
f0496a2d3c Added Scottish Gaelic translation 2015-11-16 19:00:46 +00:00
6664553b7e Revert "browser-plugin: Set windowless mode and don't claim to need XEmbed"
This reverts commit a52c91e9e5.

https://bugzilla.gnome.org/show_bug.cgi?id=758035
2015-11-16 10:57:03 -06:00
2a950ca3b3 Updated Norwegian bokmål translation. 2015-11-15 20:00:58 +01:00
463cd6382c Updated Finnish translation 2015-11-15 16:53:02 +00:00
78db025b10 appFavorites: Add gnome-terminal to the rename list
https://bugzilla.gnome.org/show_bug.cgi?id=745626
2015-11-14 19:53:41 +01:00
f3265c28a9 Updated Portuguese translation 2015-11-14 07:59:17 +00:00
a6e5e459d3 Updated Hebrew translation 2015-11-13 12:29:54 +02:00
9ba399bf18 power: Add thin space between digits and percentage sign
As mentioned by Matthias Clasen on IRC, we should have a thin space
between the percentage digits and the sign itself.

https://bugzilla.gnome.org/show_bug.cgi?id=757816
2015-11-12 16:19:30 +01:00
a52c91e9e5 browser-plugin: Set windowless mode and don't claim to need XEmbed
NPAPI plugins are windowed by default, so we need to set
NPPVpluginWindowBool value to FALSE on startup. This way the browser
will not create a GtkSocket for a GtkPlug that we are not going to
create. It doesn't make sense to claim that we need XEmbed either.

https://bugzilla.gnome.org/show_bug.cgi?id=757940
2015-11-12 12:11:56 +01:00
9a7b47c23f st: Fix Gaussian kernel calculation
The result of subtracting unsigned operands is unsigned, which throws
off our calculation in case it should be negative.

This partly reverts 18b6f13395.

https://bugzilla.gnome.org/show_bug.cgi?id=757779
2015-11-12 01:02:05 +01:00
18f7d20006 Update zh_CN translations 2015-11-11 00:18:26 +08:00
3f0ee88657 browser-plugin: link with -Wl,-z,nodelete
This ensures that the module will not be unloaded, since GObject types
registered statically can't be reloaded. This should fix crashes with
browsers that correctly unload the plugins.

https://bugzilla.gnome.org/show_bug.cgi?id=737932
2015-11-10 15:23:49 +01:00
c634718dfa shell: Fix crash in polkit agent
The polkit agent does not take ownership of the request's cancellable,
so it may no longer be valid after the request finished and we need
to disconnect it before that. Before the GTask port in 8b4249ef2,
it was safe to do that when freeing the request data because requests
completed in an idle, but now we need to do it before returning the
task result.

https://bugzilla.gnome.org/show_bug.cgi?id=757668
2015-11-10 11:56:37 +01:00
df6b31de05 Updated POTFILES.in 2015-11-10 01:07:42 +01:00
b8e29ae8c7 data: merge gnome-shell.desktop and gnome-shell-wayland.desktop into one file
We can autodetect what to do based on the user's session, so drop
the separate desktop files.

This, along with some future changes, will enable us to be bus
activatable.

https://bugzilla.gnome.org/show_bug.cgi?id=741666
2015-11-09 10:37:24 -05:00
cdba8e5cea Revert "browser-plugin: try to avoid a crash"
This reverts commit faae1a028e.
2015-11-07 08:09:11 -06:00
4fccdaafb7 Updated Portuguese translation 2015-11-05 05:51:05 +00:00
df0b465e76 StTextureCache: Fix a fallout from GTask port
Set the task data that load_pixbuf_thread func expects.

https://bugzilla.gnome.org/show_bug.cgi?id=757418
2015-11-01 00:27:35 +01:00
aacdd4fd5e browser-plugin: fix spelling of GNOME 2015-10-30 17:41:16 +01:00
5f68c3a324 Bump version to 3.19.1
Update NEWS.
2015-10-29 15:50:20 +01:00
8ceae3b054 bluetooth: Show the Bluetooth menu when there were setup devices
If we detected that Bluetooth devices were setup, show the Bluetooth
menu so that users can easily turn Bluetooth back on.

This is a bit of a hack, as we cannot detect whether there is a
Bluetooth adapter at all when it's disabled, so we cannot tell whether
there were any Bluetooth devices setup, at some point. This state is
saved in the gnome-shell GSettings in the had-bluetooth-devices-setup
key.

Checking whether we saw Bluetooth devices at one point is a good
enough guess of whether there will be some in the future.

https://bugzilla.gnome.org/show_bug.cgi?id=723848
2015-10-28 11:51:07 +01:00
3fc5afaff1 Updated Czech translation 2015-10-28 10:56:48 +01:00
8b7464c648 st_theme_node_prerender_shadow: guard against failure to allocate a texture
If we are trying to render a shadow at a size that is very large in one
direction, but small in the other direction (so that we don't 9-slice
the texture), then allocating the backing texture for the offscreen
buffer may fail due to texture-size limits. Don't crash in that case.

https://bugzilla.gnome.org/show_bug.cgi?id=757150
2015-10-27 15:51:40 -04:00
3e602b1765 calendar: Fix number formatting in some languages
Some languages require using a conversion modifier to display the day
number in a translated shape. fa_IR is affected for example.

https://bugzilla.gnome.org/show_bug.cgi?id=673235
2015-10-26 17:48:40 +01:00
5858028411 theme: tone down search entry stroke
https://bugzilla.gnome.org/show_bug.cgi?id=757011
2015-10-26 16:00:48 +01:00
2c682ace81 use osd colors for search (for classic)
https://bugzilla.gnome.org/show_bug.cgi?id=757011
2015-10-26 15:49:16 +01:00
45f3106814 Updated Romanian Translations 2015-10-25 10:19:21 +01:00
aa947f9948 Updated Romanian translation
(cherry picked from commit 9e64a1e3d6)
2015-10-24 17:02:27 +00:00
0c72d1fcbd ActivitiesButton: fix overview being toggled while still animating
Adds the missing checks for whether we should toggle the overview, on
button and key release.

https://bugzilla.gnome.org/show_bug.cgi?id=756925
2015-10-23 13:44:27 +02:00
6d22670307 Defend against failure of cairo_pattern_get_surface()
There are quite a few crashes in retrace.fedoraproject.org that are a result of
of cairo_pattern_get_surface() failing, then a subsequent call to
cairo_image_surface_get_width() crashing because no surface was returned to the
out parameter. Knowing what causes these is hard - my best guess is widgets getting
allocated at ridiculous sizes - but avoiding the crash makes sense in any case.

See https://bugzilla.redhat.com/show_bug.cgi?id=1206754

https://bugzilla.gnome.org/show_bug.cgi?id=756983
2015-10-22 15:14:55 -04:00
0b9e68e305 runDialog: Reload resource on 'rt'
Moving the default theme to a resource broke the 'rt' command;
reload the resource before the theme to fix it.

https://bugzilla.gnome.org/show_bug.cgi?id=738942
2015-10-21 20:54:30 +02:00
da8155cbe5 Updated Hungarian translation
(cherry picked from commit 10e4382a7d)
2015-10-21 06:08:52 +00:00
5b7a052e18 animation: do spinner animation with low priority
It's very unexpected that a spinner animation would
preempt idles from running.

This commit runs the spinner animation with a low
priority to ensure it doesn't take over the main
loop.

https://bugzilla.gnome.org/show_bug.cgi?id=754814
2015-10-20 17:10:06 -04:00
6f26e39082 animation: Run every 16ms not ever 14ms
Right now the spinner animation updates every 14ms.
60 frames per second would be one frame per 16.667ms,
so we're waking up more frequently than we need to.

This commit changes the wakeup to happen after 16ms.

https://bugzilla.gnome.org/show_bug.cgi?id=754814
2015-10-20 17:10:06 -04:00
489b96a310 gdm: don't emit start-session-when-ready from idle function
There's no point in delaying the emission.  We should do it
right away.

https://bugzilla.gnome.org/show_bug.cgi?id=754814
2015-10-20 17:10:06 -04:00
e65d90d624 Fix text-scaling-factor under wayland.
The text-scaling-factor GSetting was not being properly propagated
to clutter and the Pango font map; under X this is done by Clutter,
which listens to XSETTINGS directly.

https://bugzilla.gnome.org/show_bug.cgi?id=756447
2015-10-20 09:35:47 -04:00
9c74e22313 windowMenu: Ensure the source actor isn't sized 0x0
If the source actor is sized 0x0, the grabHelper will close the menu
on button release if the menu ends up flipped because in that case the
release event happens when the pointer is neither over the source
actor (since it's 0x0) or over the menu actor. A zero sized source
actor works for the non-flipped menu case because the menu's actor
itself ends up underneath the pointer.

https://bugzilla.gnome.org/show_bug.cgi?id=756605
2015-10-20 15:00:33 +02:00
48a1fce151 Add RLM as appropriate 2015-10-18 17:22:24 +04:00
83e7f6f496 windowManager: fix fullscreen clone being left around
If we get another effect on the same actor, we should make sure to
remove the clone through the "overwrite" methods provided by Tweener, or
there will be a race that might end up with a stray clone being left
around.

https://bugzilla.gnome.org/show_bug.cgi?id=756714
2015-10-16 13:47:14 -07:00
3c5c3a6597 Fixed some issues reported by Bjørn Lie in bug 740906. 2015-10-16 18:10:11 +02:00
1c3ea1649f windowManager: Fix fullscreen animations on dualscreen
The translation should describe the difference between the fullscreened
and unfullscreened position of the window - however we are currently
assuming a fullscreen position of (0, 0) instead of the monitor's origin,
which causes glitches on dualscreen setups.

https://bugzilla.gnome.org/show_bug.cgi?id=756697
2015-10-16 15:50:39 +02:00
48a54e8ac4 theme-node: Pass an explicit framebuffer to paint()
This allows us to paint to an offscreen buffer without using the
deprecated cogl_push_framebuffer/cogl_pop_framebuffer functions.
2015-10-16 00:16:38 +02:00
113a854048 st: Rename *material to *pipeline
... since the last commit changed the type from CoglMaterial to
CoglPipeline.
2015-10-15 23:42:19 +02:00
882f5fa79e st: Fix a bunch of cogl deprecations 2015-10-15 23:05:11 +02:00
9acdb8012c tray: Get rid of deprecation warnings
gdk_window_set_composited() is deprecated, and we don't need it as
we end up setting it to the default anyway.
We do need gtk_widget_set_double_buffered() though, which has been
deprecated as well because it is only meaningful on X11 - but so
is XEmbed, so just shut up that warning.
2015-10-15 23:05:11 +02:00
731d64e0e4 tray: Don't use gdk_display_supports_composite()
Composite is a hard requirement for mutter's compositor, so if we get
to the point of managing the tray, we already know that the extension
is supported. So let's get rid of yet another deprecation warning.
2015-10-15 23:05:11 +02:00
ccf1bd9f27 tray-manager: Don't use GdkColor
It has been deprecated for a while in favor of GdkRgba, though in our
case translating ClutterColors to an intermediate color type before
setting _NET_SYSTEM_TRAY_COLORS is a bit silly, so just move to
ClutterColor as the rest of the code base.
2015-10-15 23:05:11 +02:00
c164a8fe03 st: Use ClutterCanvas for StDrawingArea
Stop chasing down cogl deprecations by delegating all texture
handling to a ClutterCanvas.
2015-10-15 23:01:11 +02:00
1a39666f7c shell: Port to GTask 2015-10-15 22:59:49 +02:00
f2731d4d6a st: Port to GTask
GSimpleAsyncResult has been deprecated for a while.
2015-10-15 22:59:48 +02:00
3e63fb7abe Port screenshot to GTask 2015-10-15 22:59:48 +02:00
8b4249ef26 Port polkit agent to GTask 2015-10-15 22:59:48 +02:00
bf0be6ef12 hotplug-sniffer: Port to GTask
GSimpleAsyncResult is deprecated.
2015-10-15 22:59:48 +02:00
294702d3f1 shell: Use G_DECLARE_*_TYPE macros
Cut down on boilerplate by using the (no longer that) new helper
macros. We don't care about breaking ABI in private libraries, so
use G_DECLARE_FINAL_TYPE even where the class struct used to be
exposed in the header, except for types we inherit from ourselves
(obviously) or where the class exposes any vfuncs (where changes
could affect inheritance in extensions).
2015-10-15 22:58:28 +02:00
58f3b7c748 shell: Drop questionable vfuncs
Both ShellAppSystem and ShellTrayManager are used as singletons, which
significantly reduces the usefulness of inheritance - it's unlikely for
extensions to inherit from them anyway (AND use any of the vfuncs), so
drop them to allow defining the types as final in an upcoming commit.
2015-10-15 22:13:18 +02:00
e25502aeb2 shell: Use G_DEFINE_TYPE_WITH_PRIVATE() and friends 2015-10-15 22:03:06 +02:00
ffe4eaf00d st: Use G_DECLARE_*_TYPE
Cut down on boilerplate by using the (no longer that) new helper
macros. We don't care about breaking ABI in private libraries, so
use G_DECLARE_FINAL_TYPE even where the class struct used to be
exposed in the header, except for types we inherit from ourselves
(obviously) or where the class exposes any vfuncs (where changes
could affect inheritance in extensions).
2015-10-15 22:02:35 +02:00
2f88a7a1e1 st: Drop vfuncs from StThemeNodeTransition
They are unused, as we don't use them ourselves and the class is not
exposed to introspection. Drop them to allow defining the type as final
in an upcoming commit.
2015-10-15 21:43:08 +02:00
cd7d564125 st: Use G_DEFINE_TYPE_WITH_PRIVATE() and friends 2015-10-15 21:05:22 +02:00
ede81017ec hotplug-sniffer: Modernize GObject usage 2015-10-15 21:04:07 +02:00
a539e6236a calendar-server: Modernize GObject usage 2015-10-15 21:04:07 +02:00
261 changed files with 41066 additions and 29270 deletions

10
.gitignore vendored
View File

@ -16,11 +16,8 @@ config.log
config.status
config
configure
data/50-gnome-shell-*.xml
data/gnome-shell.desktop
data/gnome-shell.desktop.in
data/gnome-shell-wayland.desktop
data/gnome-shell-wayland.desktop.in
data/org.gnome.Shell.desktop
data/org.gnome.Shell.desktop.in
data/gnome-shell-extension-prefs.desktop
data/gnome-shell-extension-prefs.desktop.in
data/gnome-shell-theme.gresource
@ -28,8 +25,6 @@ data/gschemas.compiled
data/perf-background.xml
data/org.gnome.shell.gschema.xml
data/org.gnome.shell.gschema.valid
data/org.gnome.shell.evolution.calendar.gschema.xml
data/org.gnome.shell.evolution.calendar.gschema.valid
data/org.gnome.Shell.PortalHelper.desktop
data/org.gnome.Shell.PortalHelper.service
data/theme/.sass-cache
@ -76,7 +71,6 @@ src/*-marshal.[ch]
src/Makefile
src/Makefile.in
src/calendar-server/evolution-calendar.desktop
src/calendar-server/evolution-calendar.desktop.in
src/calendar-server/org.gnome.Shell.CalendarServer.service
src/gnome-shell
src/gnome-shell-calendar-server

337
NEWS
View File

@ -1,3 +1,340 @@
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]
* Include extension UUID in structured log metadata [Jonh; #770717]
* Line-wrap PAM messages on login screen [Tao; #764445]
* Add a way to launch an app on the discrete GPU [Bastien; #773117]
* Only allow graphs to lift screen shield when locked [Florian; #773328]
* Add reload option to gnome-shell-extension-tool [Jonh; #772593]
* Update background animations when resuming from suspend [Florian; #773265]
* Misc. bug fixes [Cosimo, Bastien, Florian, Philip, Carlos; #772723, #772287,
#756432, #772386, #772386, #773085, #773634]
Contributors:
Cosimo Cecchi, Philip Chimento, Carlos Garcia Campos, Florian Müllner,
Bastien Nocera, Jonh Wendell, Dan Williams, Tao Yang
Translations:
Fabio Tomat [fur], Philip Chimento [zh_CN], YunQiang Su [zh_CN],
Jordi Mas [ca], Piotr Drąg [pl], Muhammet Kara [tr], Marek Černocký [cs],
Daniel Korostil [uk], Dušan Kazik [sk]
3.22.1
======
* Fix hidden network indicator on startup [Florian; #772249]
* Fix order of windows with modal dialogs in window switcher [Florian; #747153]
* Fix feedback loop between StClipboard and X11 bridge [Carlos; #760745]
* Reliably match windows from Flatpak apps [Florian; #772615]
* Misc. bug fixes [Philip; #742249]
Contributors:
Philip Chimento, Carlos Garnacho, Florian Müllner
Translations:
Inaki Larranaga Murgoitio [eu], Khaled Hosny [ar], BM [uz@cyrillic],
Milo Casagrande [it], Cheng-Chia Tseng [zh_TW], gogo [hr]
3.22.0
======
* Misc. bug fixes [Florian, Rui; #771391, #771536] #771656]
Contributors:
Rui Matos, Florian Müllner
Translations:
Ask Hjorth Larsen [da], GNOME Translation Robot [gd], Alexandre Franke [fr],
Daniel Korostil [uk], Jordi Mas [ca], Khaled Hosny [ar], David King [en_GB]
3.21.92
=======
* Adjust screen capture to work with multiple stage views [Jonas; #770128]
* Improve handling of cycle shortcuts [Florian; #771063]
* Fix windows not getting undimmed in some cases [Rui; #770163, #752524]
* Disable extension version check by default [Florian; #770887]
* Misc. bug fixes [Rui, Florian, Michael; #770382, #770888, #770328]
Contributors:
Jonas Ådahl, Michael Catanzaro, Fran Dieguez, Olivier Fourdan, Rui Matos,
Florian Müllner
Translations:
Changwoo Ryu [ko], Baurzhan Muftakhidinov [kk], Aurimas Černius [lt],
Muhammet Kara [tr], Trần Ngọc Quân [vi], A S Alam [pa], Yosef Or Boczko [he],
Anders Jonsson [sv], Tiago Santos [pt], Hannie Dumoleyn [nl],
Rūdolfs Mazurs [lv], Claude Paroz [fr], Arash Mousavi [fa],
Fran Dieguez [gl], Stas Solovey [ru], Tom Tryfonidis [el]
3.21.91
=======
Translations:
Mario Blättermann [de], Jiri Grönroos [fi], Dušan Kazik [sk],
Andika Triwidada [id], Daniel Mustieles [es], Fabio Tomat [fur],
Enrico Nicoletto [pt_BR], Matej Urbančič [sl], Мирослав Николић [sr, sr@latin]
3.21.90.1
=========
Contributors:
Piotr Drąg
Translations:
Marek Černocký [cs], Balázs Úr [hu]
3.21.90
=======
* Improve on-screen keyboard on wayland [Carlos; #765009]
* Misc. bug fixes [Florian; #769156, #769216, #769074]
Contributors:
Carlos Garnacho, Florian Müllner
Translations:
Fabio Tomat [fur], Tiago Santos [pt], Daniel Mustieles [es],
Bernd Homuth [de], Aurimas Černius [lt], Balázs Úr [hu],
Yosef Or Boczko [he], Jiri Grönroos [fi], Marek Cernocky [cs],
Muhammet Kara [tr], Enrico Nicoletto [pt_BR], Andika Triwidada [id]
3.21.4
======
* overview: Fix switching workspaces when scrolling on non-primary monitors
[Florian; #766883, #768316]
* Fix crash when using screen recorder under wayland [Rui; #767001]
* Update theme on video memory purge errors [Rui; #739178]
* Free old backgrounds immediately [Hyungwon; #766353]
* Add support for system upgrades to end session dialog [Kalev; #763611]
* Fix maximized windows flickering to the wrong size on restart [Owen; #761566]
* Hide ignored events in calendar as well [Florian; #768538]
* calendar: Only hide dismissed occurrence of recurring event [Florian; #748226]
* Provide org.freedesktop.impl.portal.access implementation [Florian; #768669]
* Misc. bug fixes and cleanups [Rui, Florian, Marinus, Jonas; #767954, #768317,
#746867, #762206, #768956, #768979]
Contributors:
Jonas Ådahl, Piotr Drąg, Hyungwon Hwang, Kalev Lember, Rui Matos,
Florian Müllner, Marinus Schraal, Owen W. Taylor
Translations:
Andika Triwidada [id], Daniel Mustieles [es], Bruce Cowan [en_GB],
Dušan Kazik [sk], Piotr Drąg [pl], Chao-Hsiung Liao [zh_HK]
3.21.3
======
* Do not disable suspend action when locked [Florian; #725960]
* Remember input sources MRU list [Cosimo; #766826]
* networkAgent: Handle VPN service aliases [David; #658484]
* Plug a memory leak [Hans; #710230]
Contributors:
Cosimo Cecchi, Florian Müllner, Hans Petter Jansson, David Woodhouse
Translations:
Tiago Santos [pt], Cédric Valmary [oc], Muhammet Kara [tr],
Daniel Mustieles [es], Rafael Fontenelle [pt_BR]
3.21.2
======
* Fix sorting of hidden apps in app switcher [Florian; #766238]
* Set logind's LockedHint property when locked [Victor; #764773]
* Allocate framebuffers early to fix a crash on NVIDIA [Martin; #764898]
* Fix cycle-windows/cycle-group keybindings [Florian; #730739]
* Switch to shared desktop schema for calendar settings [Iain; #766318]
* Misc. bug fixes [Florian, Cosimo, Michele; #766325, #758471, #757556,
#757019, #766598]
Contributors:
Cosimo Cecchi, Michele Gaio, Iain Lane, Florian Müllner, Martin Szulecki,
Victor Toso
Translations:
Tiago Santos [pt], Kjartan Maraas [nb], Jiro Matsuzawa [ja],
Cédric Valmary [oc], Sveinn í Felli [is]
3.21.1
======
* Save screencasts in HOME if XDG_VIDEO_DIR doesn't exist [Florian; #765015]
* Don't show orientation lock when g-s-d won't rotate [Florian; #765267]
* Misc. bug fixes [Heiher, Florian, Marek, Rui; #722752, #765061, #763068,
#765607, #757676, #760439]
Contributors:
Heiher, Marek Chalupa, Rui Matos, Florian Müllner
Translations:
Arash Mousavi [fa], Kristjan SCHMIDT [eo], GNOME Translation Robot [gd]
3.20.1
======
* Plug a memory leak [Aaron; #735705]
Contributors:
Aaron Plattner
Translations:
Daniel Korostil [uk], Matej Urbančič [sl], Inaki Larranaga Murgoitio [eu],
Cheng-Chia Tseng [zh_TW], Fabio Tomat [fur], Trần Ngọc Quân [vi],
YunQiang Su [zh_CN], Marek Černocký [cs], Arash Mousavi [fa],
Alexander Shopov [bg], Khaled Hosny [ar]
3.20.0
======
Translations:
Changwoo Ryu [ko], Baurzhan Muftakhidinov [kk], Milo Casagrande [it],
Anders Jonsson [sv], Muhammet Kara [tr], Alexandre Franke [fr],
Rūdolfs Mazurs [lv], Ask Hjorth Larsen [da], Jiro Matsuzawa [ja]
3.19.92
=======
* Update location dialog according to latest mockups [Zeeshan; #762480]
* Fix deleting chat notifications in calendar [Florian; #747991]
Contributors:
Zeeshan Ali (Khattak), Florian Müllner
Translations:
Rūdolfs Mazurs [lv], Changwoo Ryu [ko], Matej Urbančič [sl],
Justin van Steijn [nl], Fabio Tomat [fur], Kris Thomsen [da],
Marek Černocký [cs], Piotr Drąg [pl], Dušan Kazik [sk],
Мирослав Николић [sr, sr@latin], Balázs Úr [hu], Yosef Or Boczko [he],
Daniel Mustieles [es], Fran Dieguez [gl], Bernd Homuth [de],
Tom Tryfonidis [el], Jiri Grönroos [fi], Gil Forcada [ca],
Artur Morais [pt_BR], Aurimas Černius [lt], Stas Solovey [ru]
3.19.91
=======
* location: Ask user only once [Zeeshan; #762559]
* Fix jiggling when auto-hiding legacy tray [Florian; #747957]
* Misc. bug fixes [Florian, Michael, Ting-Wei; #762475, #762507, #755659]
Contributors:
Zeeshan Ali (Khattak), Michael Catanzaro, Ting-Wei Lan, Florian Müllner
Translations:
Мирослав Николић [sr, sr@latin], Piotr Drąg [pl], A S Alam [pa],
Artur de Aquino Morais [pt_BR], Daniel Mustieles [es],
Chao-Hsiung Liao [zh_TW], Daniel Korostil [uk], Fran Dieguez [gl],
Tom Tryfonidis [el], Bernd Homuth [de], Sebastian Rasmussen [sv],
Jordi Mas [ca], Piotr Drąg [ga], Cédric Valmary [oc], Gábor Kelemen [hu],
Baurzhan Muftakhidinov [kk], Friedel Wolff [af], Marek Černocký [cs],
Mingye Wang (Arthur2e5) [zh_CN], Aron Xu [zh_CN], Khaled Hosny [ar],
Aurimas Černius [lt], Stas Solovey [ru], Yosef Or Boczko [he]
3.19.90
=======
* Correctly identify VPN secret requests [Lubomir; #760999]
* Improve week number presentation [Jakub; #683245]
* Add audio device selection dialog [Florian; #760284]
* Add media controls to the time and date drop down [Florian; #756491]
* Fix IBus candidate popup position under wayland [Rui; #753476]
* Ask user to grant applications access to location [Zeeshan; #762119]
* Misc. bug fixes [Mario, Jakub, Florian; #761208, #761772, #762270]
Contributors:
Zeeshan Ali (Khattak), Michael Catanzaro, Rui Matos, Florian Müllner,
Lubomir Rintel, Mario Sanchez Prada, Jakub Steiner
Translations:
Alexander Shopov [bg], Balázs Meskó [hu], Fabio Tomat [fur],
Dušan Kazik [sk], Piotr Drąg [pl], Alexandre Franke [fr],
Mario Blättermann [de], Milo Casagrande [it], Jordi Mas [ca]
3.19.4
======
* gdm: Do not allow bypassing disabled Sign In button [Michael; #746180]
* Style week numbers in calendar [Jakub; #683245]
* Misc. bug fixes [Christophe, Jakub, Rui; #759708, #760577, #760945]
Contributors:
Michael Catanzaro, Marek Černocký, Christophe Fergeau, Rui Matos,
Jakub Steiner
Translations:
Aurimas Černius [lt], Enrico Nicoletto [pt_BR], Andika Triwidada [id],
Mario Blättermann [de], Marek Černocký [cs], Kjartan Maraas [nb],
Muhammet Kara [tr], Stas Solovey [ru]
3.19.3
======
* Fix thumbnail scaling in window switcher on HiDPI [Florian; #758676]
* Update animated backgrounds on timezone changes [Florian; #758939]
* loginDialog: Update user list on user changes [Michael; #758568]
* Fix touch interaction on wayland [Carlos; #756748]
Contributors:
Michael Catanzaro, Carlos Garnacho, Kalev Lember, Florian Müllner
Translations:
Daniel Korostil [uk], Muhammet Kara [tr], Dušan Kazik [sk],
Baurzhan Muftakhidinov [kk], Marek Černocký [cs]
3.19.2
======
* Make gnome-shell DBus activatable [Ray; #741666]
* Fix browser plugin crash in Firefox [Carlos; #737932, #757940]
* Optionally show battery percentage in system status area [Bastien; #735771]
* Misc. bug fixes [Kalev, Florian, Bastien; #757418, #757668, #757779, #757816,
#745626, #758220]
Contributors:
Michael Biebl, Michael Catanzaro, Piotr Drąg, Carlos Garcia Campos,
Kalev Lember, Florian Müllner, Bastien Nocera, Ray Strode
Translations:
Pedro Albuquerque [pt], liushuyu [zh_CN], Yosef Or Boczko [he],
Jiri Grönroos [fi], Kjartan Maraas [nb], GNOME Translation Robot [gd],
Daniel Mustieles [es], Marek Černocký [cs], Kristjan SCHMIDT [eo],
Stas Solovey [ru]
3.19.1
======
* Respect text-scaling factor under wayland [Owen; #756447]
* Show the Bluetooth submenu when there were setup devices [Bastien; #723848]
* Misc. bug fixes [Florian, Cosimo, Rui, Ray, Owen, Jakub, Bastien;
#756697, #756714, #756605, #754814, #738942, #756983, #756925,
#757011, #673235, #757150]
Contributors:
Cosimo Cecchi, Rui Matos, Florian Müllner, Bastien Nocera, Jakub Steiner,
Ray Strode, Owen W. Taylor
Translations:
Kjartan Maraas [nb], Khaled Hosny [ar], Balázs Meskó [hu],
Daniel Șerbănescu [ro], Marek Černocký [cs]
3.18.1
======
* Fix screen freezes when a notification is pushed [Carlos; #755425]

View File

@ -11,6 +11,8 @@ test -z "$srcdir" && srcdir=.
exit 1
}
pushd $srcdir
# Fetch submodules if needed
if test ! -f src/gvc/Makefile.am || test ! -f data/theme/gnome-shell-sass/COPYING;
then
@ -19,6 +21,8 @@ then
fi
git submodule update
popd
which gnome-autogen.sh || {
echo "You need to install gnome-common from GNOME Git (or from"
echo "your OS vendor's package manager)."

View File

@ -3,7 +3,10 @@ mozillalibdir = $(BROWSER_PLUGIN_DIR)
mozillalib_LTLIBRARIES = libgnome-shell-browser-plugin.la
libgnome_shell_browser_plugin_la_LDFLAGS = -module -avoid-version -no-undefined
# Browsers can unload and reload the module while browsing, which is not supported by GObject.
# We pass -Wl,-z,nodelete to the linker to ensure the module is never unloaded.
# https://bugzilla.gnome.org/show_bug.cgi?id=737932
libgnome_shell_browser_plugin_la_LDFLAGS = -module -avoid-version -no-undefined -Wl,-z,nodelete
libgnome_shell_browser_plugin_la_LIBADD = \
$(BROWSER_PLUGIN_LIBS)

View File

@ -33,20 +33,16 @@
#include <json-glib/json-glib.h>
#define ORIGIN "extensions.gnome.org"
#define PLUGIN_NAME "Gnome Shell Integration"
#define PLUGIN_DESCRIPTION "This plugin provides integration with Gnome Shell " \
#define PLUGIN_NAME "GNOME Shell Integration"
#define PLUGIN_DESCRIPTION "This plugin provides integration with GNOME Shell " \
"for live extension enabling and disabling. " \
"It can be used only by extensions.gnome.org"
#define PLUGIN_MIME_STRING "application/x-gnome-shell-integration::Gnome Shell Integration Dummy Content-Type";
#define PLUGIN_MIME_STRING "application/x-gnome-shell-integration::GNOME Shell Integration Dummy Content-Type";
#define PLUGIN_API_VERSION 5
#define EXTENSION_DISABLE_VERSION_CHECK_KEY "disable-extension-version-validation"
typedef struct {
GDBusProxy *proxy;
} PluginData;
static NPNetscapeFuncs funcs;
static inline gchar *
@ -145,121 +141,6 @@ check_origin_and_protocol (NPP instance)
return ret;
}
/* =============== public entry points =================== */
NPError
NP_Initialize(NPNetscapeFuncs *pfuncs, NPPluginFuncs *plugin)
{
/* global initialization routine, called once when plugin
is loaded */
g_debug ("plugin loaded");
memcpy (&funcs, pfuncs, sizeof (funcs));
plugin->size = sizeof(NPPluginFuncs);
plugin->newp = NPP_New;
plugin->destroy = NPP_Destroy;
plugin->getvalue = NPP_GetValue;
plugin->setwindow = NPP_SetWindow;
return NPERR_NO_ERROR;
}
NPError
NP_Shutdown(void)
{
return NPERR_NO_ERROR;
}
const char*
NP_GetMIMEDescription(void)
{
return PLUGIN_MIME_STRING;
}
NPError
NP_GetValue(void *instance,
NPPVariable variable,
void *value)
{
switch (variable) {
case NPPVpluginNameString:
*(char**)value = PLUGIN_NAME;
break;
case NPPVpluginDescriptionString:
*(char**)value = PLUGIN_DESCRIPTION;
break;
default:
;
}
return NPERR_NO_ERROR;
}
NPError
NPP_New(NPMIMEType mimetype,
NPP instance,
uint16_t mode,
int16_t argc,
char **argn,
char **argv,
NPSavedData *saved)
{
/* instance initialization function */
PluginData *data;
GError *error = NULL;
g_debug ("plugin created");
if (!check_origin_and_protocol (instance))
return NPERR_GENERIC_ERROR;
data = g_slice_new (PluginData);
instance->pdata = data;
data->proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION,
G_DBUS_PROXY_FLAGS_NONE,
NULL, /* interface info */
"org.gnome.Shell",
"/org/gnome/Shell",
"org.gnome.Shell.Extensions",
NULL, /* GCancellable */
&error);
if (!data->proxy)
{
/* ignore error if the shell is not running, otherwise warn */
if (error->domain != G_DBUS_ERROR ||
error->code != G_DBUS_ERROR_NAME_HAS_NO_OWNER)
{
g_warning ("Failed to set up Shell proxy: %s", error->message);
}
g_clear_error (&error);
return NPERR_GENERIC_ERROR;
}
g_debug ("plugin created successfully");
return NPERR_NO_ERROR;
}
NPError
NPP_Destroy(NPP instance,
NPSavedData **saved)
{
/* instance finalization function */
PluginData *data = instance->pdata;
g_debug ("plugin destroyed");
g_object_unref (data->proxy);
g_slice_free (PluginData, data);
return NPERR_NO_ERROR;
}
/* =================== scripting interface =================== */
typedef struct {
@ -282,14 +163,6 @@ on_shell_signal (GDBusProxy *proxy,
{
PluginObject *obj = user_data;
/* FIXME: We have half a dozen bug reports in which this function crashes in
* WebKit due to a null NPObject. This should never happen, but since it is
* happening, let's turn the crash into a critical.
*
* https://bugzilla.gnome.org/show_bug.cgi?id=737932
*/
g_return_if_fail (obj->instance);
if (strcmp (signal_name, "ExtensionStatusChanged") == 0)
{
gchar *uuid;
@ -320,12 +193,6 @@ on_shell_appeared (GDBusConnection *connection,
{
PluginObject *obj = (PluginObject*) user_data;
/* FIXME: Not sure if this is ever hit or not, but let's play it safe.
*
* https://bugzilla.gnome.org/show_bug.cgi?id=737932
*/
g_return_if_fail (obj->instance);
if (obj->restart_listener)
{
NPVariant result = { NPVariantType_Void };
@ -344,45 +211,18 @@ static NPObject *
plugin_object_allocate (NPP instance,
NPClass *klass)
{
PluginData *data = instance->pdata;
PluginObject *obj = g_slice_new0 (PluginObject);
PluginObject *obj = (PluginObject *) funcs.memalloc (sizeof (PluginObject));
memset (obj, 0, sizeof (PluginObject));
obj->instance = instance;
obj->proxy = g_object_ref (data->proxy);
obj->settings = g_settings_new (SHELL_SCHEMA);
obj->signal_id = g_signal_connect (obj->proxy, "g-signal",
G_CALLBACK (on_shell_signal), obj);
obj->watch_name_id = g_bus_watch_name (G_BUS_TYPE_SESSION,
"org.gnome.Shell",
G_BUS_NAME_WATCHER_FLAGS_NONE,
on_shell_appeared,
NULL,
obj,
NULL);
g_debug ("plugin object created");
return (NPObject*)obj;
return (NPObject*) obj;
}
static void
plugin_object_deallocate (NPObject *npobj)
{
PluginObject *obj = (PluginObject*)npobj;
g_signal_handler_disconnect (obj->proxy, obj->signal_id);
g_object_unref (obj->proxy);
if (obj->listener)
funcs.releaseobject (obj->listener);
if (obj->watch_name_id)
g_bus_unwatch_name (obj->watch_name_id);
g_debug ("plugin object destroyed");
g_slice_free (PluginObject, obj);
funcs.memfree (npobj);
}
static inline gboolean
@ -1033,6 +873,149 @@ init_methods_and_properties (void)
onextension_changed_id = funcs.getstringidentifier ("onchange");
}
/* =============== public entry points =================== */
NPError
NP_Initialize(NPNetscapeFuncs *pfuncs, NPPluginFuncs *plugin)
{
/* global initialization routine, called once when plugin
is loaded */
g_debug ("plugin loaded");
memcpy (&funcs, pfuncs, sizeof (funcs));
plugin->size = sizeof(NPPluginFuncs);
plugin->newp = NPP_New;
plugin->destroy = NPP_Destroy;
plugin->getvalue = NPP_GetValue;
plugin->setwindow = NPP_SetWindow;
plugin->event = NPP_HandleEvent;
return NPERR_NO_ERROR;
}
NPError
NP_Shutdown(void)
{
return NPERR_NO_ERROR;
}
const char*
NP_GetMIMEDescription(void)
{
return PLUGIN_MIME_STRING;
}
NPError
NP_GetValue(void *instance,
NPPVariable variable,
void *value)
{
switch (variable) {
case NPPVpluginNameString:
*(char**)value = PLUGIN_NAME;
break;
case NPPVpluginDescriptionString:
*(char**)value = PLUGIN_DESCRIPTION;
break;
default:
;
}
return NPERR_NO_ERROR;
}
NPError
NPP_New(NPMIMEType mimetype,
NPP instance,
uint16_t mode,
int16_t argc,
char **argn,
char **argv,
NPSavedData *saved)
{
/* instance initialization function */
PluginObject *obj;
GError *error = NULL;
g_debug ("plugin created");
if (!check_origin_and_protocol (instance))
return NPERR_GENERIC_ERROR;
/* set windowless mode */
funcs.setvalue(instance, NPPVpluginWindowBool, NULL);
g_debug ("creating scriptable object");
init_methods_and_properties ();
obj = (PluginObject *) funcs.createobject (instance, &plugin_class);
instance->pdata = obj;
obj->proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION,
G_DBUS_PROXY_FLAGS_NONE,
NULL, /* interface info */
"org.gnome.Shell",
"/org/gnome/Shell",
"org.gnome.Shell.Extensions",
NULL, /* GCancellable */
&error);
if (!obj->proxy)
{
/* ignore error if the shell is not running, otherwise warn */
if (!g_error_matches (error, G_DBUS_ERROR, G_DBUS_ERROR_NAME_HAS_NO_OWNER))
{
g_warning ("Failed to set up Shell proxy: %s", error->message);
}
g_clear_error (&error);
return NPERR_GENERIC_ERROR;
}
obj->settings = g_settings_new (SHELL_SCHEMA);
obj->signal_id = g_signal_connect (obj->proxy, "g-signal",
G_CALLBACK (on_shell_signal), obj);
obj->watch_name_id = g_bus_watch_name (G_BUS_TYPE_SESSION,
"org.gnome.Shell",
G_BUS_NAME_WATCHER_FLAGS_NONE,
on_shell_appeared,
NULL,
obj,
NULL);
g_debug ("plugin created successfully");
return NPERR_NO_ERROR;
}
NPError
NPP_Destroy(NPP instance,
NPSavedData **saved)
{
/* instance finalization function */
PluginObject *obj = (PluginObject *) instance->pdata;
if (!obj)
return NPERR_INVALID_INSTANCE_ERROR;
g_debug ("plugin destroyed");
g_signal_handler_disconnect (obj->proxy, obj->signal_id);
g_object_unref (obj->proxy);
if (obj->listener)
funcs.releaseobject (obj->listener);
if (obj->restart_listener)
funcs.releaseobject (obj->restart_listener);
if (obj->watch_name_id)
g_bus_unwatch_name (obj->watch_name_id);
funcs.releaseobject((NPObject *)obj);
return NPERR_NO_ERROR;
}
NPError
NPP_GetValue(NPP instance,
NPPVariable variable,
@ -1043,13 +1026,11 @@ NPP_GetValue(NPP instance,
switch (variable) {
case NPPVpluginScriptableNPObject:
g_debug ("creating scriptable object");
init_methods_and_properties ();
if (!instance->pdata)
return NPERR_INVALID_INSTANCE_ERROR;
*(NPObject**)value = funcs.createobject (instance, &plugin_class);
break;
case NPPVpluginNeedsXEmbed:
*(bool *)value = TRUE;
funcs.retainobject (instance->pdata);
*(NPObject**)value = instance->pdata;
break;
default:
@ -1067,3 +1048,11 @@ NPP_SetWindow(NPP instance,
{
return NPERR_NO_ERROR;
}
int16_t
NPP_HandleEvent(NPP instance,
void *event)
{
/* Ignore the event */
return FALSE;
}

View File

@ -1,5 +1,5 @@
AC_PREREQ(2.63)
AC_INIT([gnome-shell],[3.18.1],[https://bugzilla.gnome.org/enter_bug.cgi?product=gnome-shell],[gnome-shell])
AC_INIT([gnome-shell],[3.23.3],[https://bugzilla.gnome.org/enter_bug.cgi?product=gnome-shell],[gnome-shell])
AX_IS_RELEASE([git-directory])
AC_CONFIG_HEADERS([config.h])
@ -24,13 +24,14 @@ LT_PREREQ([2.2.6])
LT_INIT([disable-static])
# i18n
IT_PROG_INTLTOOL([0.40])
GETTEXT_PACKAGE=gnome-shell
AC_SUBST(GETTEXT_PACKAGE)
AC_DEFINE_UNQUOTED(GETTEXT_PACKAGE, "$GETTEXT_PACKAGE",
[The prefix for our gettext translation domains.])
AM_GNU_GETTEXT_VERSION([0.19.6])
AM_GNU_GETTEXT([external])
PKG_PROG_PKG_CONFIG([0.22])
AC_PATH_PROG([XSLTPROC], [xsltproc])
@ -52,7 +53,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 clutter-1.0)
PKG_CHECK_MODULES(TEST_SHELL_RECORDER, $recorder_modules mutter-clutter-1.0)
else
AC_MSG_RESULT(no)
fi
@ -75,9 +76,9 @@ AS_IF([test x$enable_systemd != xno], [
AC_MSG_RESULT($enable_systemd)
CLUTTER_MIN_VERSION=1.21.5
GOBJECT_INTROSPECTION_MIN_VERSION=1.45.4
GJS_MIN_VERSION=1.39.0
MUTTER_MIN_VERSION=3.18.1
GOBJECT_INTROSPECTION_MIN_VERSION=1.49.1
GJS_MIN_VERSION=1.47.0
MUTTER_MIN_VERSION=3.23.3
GTK_MIN_VERSION=3.15.0
GIO_MIN_VERSION=2.45.3
LIBECAL_MIN_VERSION=3.5.3
@ -95,11 +96,11 @@ SHARED_PCS="gio-unix-2.0 >= $GIO_MIN_VERSION
libxml-2.0
gtk+-3.0 >= $GTK_MIN_VERSION
atk-bridge-2.0
gjs-internals-1.0 >= $GJS_MIN_VERSION
gjs-1.0 >= $GJS_MIN_VERSION
$recorder_modules
gdk-x11-3.0 libsoup-2.4
clutter-x11-1.0 >= $CLUTTER_MIN_VERSION
clutter-glx-1.0 >= $CLUTTER_MIN_VERSION
mutter-clutter-1.0 >= $CLUTTER_MIN_VERSION
mutter-cogl-pango-1.0
libstartup-notification-1.0 >= $STARTUP_NOTIFICATION_MIN_VERSION
gobject-introspection-1.0 >= $GOBJECT_INTROSPECTION_MIN_VERSION
libcanberra libcanberra-gtk3
@ -113,13 +114,13 @@ fi
PKG_CHECK_MODULES(GNOME_SHELL, $SHARED_PCS)
PKG_CHECK_MODULES(MUTTER, libmutter >= $MUTTER_MIN_VERSION)
PKG_CHECK_MODULES(GNOME_SHELL_JS, gio-2.0 gjs-internals-1.0 >= $GJS_MIN_VERSION)
PKG_CHECK_MODULES(ST, clutter-1.0 gtk+-3.0 libcroco-0.6 >= 0.6.8 x11)
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(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, gtk+-3.0)
PKG_CHECK_MODULES(TRAY, mutter-clutter-1.0 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.13.1)
PKG_CHECK_MODULES(DESKTOP_SCHEMAS, gsettings-desktop-schemas >= 3.21.3)
AC_ARG_ENABLE(browser-plugin,
[AS_HELP_STRING([--enable-browser-plugin],
@ -254,7 +255,6 @@ AC_CONFIG_FILES([
docs/reference/st/Makefile
docs/reference/st/st-docs.sgml
js/Makefile
src/calendar-server/evolution-calendar.desktop.in
src/Makefile
src/gvc/Makefile
browser-plugin/Makefile

View File

@ -1,24 +1,24 @@
<?xml version="1.0" encoding="UTF-8" ?>
<KeyListEntries schema="org.gnome.shell.keybindings"
group="system"
_name="System"
name="System"
wm_name="GNOME Shell"
package="gnome-shell">
<KeyListEntry name="toggle-message-tray"
_description="Show the notification list"/>
description="Show the notification list"/>
<KeyListEntry name="focus-active-notification"
_description="Focus the active notification"/>
description="Focus the active notification"/>
<KeyListEntry name="toggle-overview"
_description="Show the overview"/>
description="Show the overview"/>
<KeyListEntry name="toggle-application-view"
_description="Show all applications"/>
description="Show all applications"/>
<KeyListEntry name="open-application-menu"
_description="Open the application menu"/>
description="Open the application menu"/>
</KeyListEntries>

View File

@ -2,17 +2,21 @@ CLEANFILES =
NULL =
desktopdir=$(datadir)/applications
desktop_DATA = gnome-shell.desktop gnome-shell-wayland.desktop gnome-shell-extension-prefs.desktop
desktop_DATA = org.gnome.Shell.desktop gnome-shell-extension-prefs.desktop
if HAVE_NETWORKMANAGER
desktop_DATA += org.gnome.Shell.PortalHelper.desktop
portaldir = $(datadir)/xdg-desktop-portal/portals
portal_DATA = gnome-shell.portal
servicedir = $(datadir)/dbus-1/services
service_DATA = org.gnome.Shell.PortalHelper.service
CLEANFILES += \
org.gnome.Shell.PortalHelper.service \
org.gnome.Shell.PortalHelper.desktop \
org.gnome.Shell.PortalHelper.service \
org.gnome.Shell.PortalHelper.desktop \
org.gnome.Shell.PortalHelper.desktop.in \
$(NULL)
endif
@ -28,10 +32,13 @@ endif
-e "s|@VERSION[@]|$(VERSION)|" \
$< > $@ || rm $@
@INTLTOOL_DESKTOP_RULE@
%.desktop:%.desktop.in
$(AM_V_GEN) $(MSGFMT) --desktop --template $(builddir)/$< \
-d $(top_srcdir)/po -o $@
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 \
@ -57,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)
@ -80,14 +88,11 @@ perf-background.xml: perf-background.xml.in
$< > $@ || rm $@
keysdir = @GNOME_KEYBINDINGS_KEYSDIR@
keys_in_files = 50-gnome-shell-system.xml.in
keys_DATA = $(keys_in_files:.xml.in=.xml)
keys_DATA = 50-gnome-shell-system.xml
gsettings_SCHEMAS = org.gnome.shell.gschema.xml
@INTLTOOL_XML_NOMERGE_RULE@
%.gschema.xml.in: %.gschema.xml.in.in Makefile
%.gschema.xml: %.gschema.xml.in Makefile
$(AM_V_GEN) sed -e 's|@GETTEXT_PACKAGE[@]|$(GETTEXT_PACKAGE)|g' \
$< > $@ || rm $@
@ -104,32 +109,29 @@ convertdir = $(datadir)/GConf/gsettings
convert_DATA = gnome-shell-overrides.convert
EXTRA_DIST = \
gnome-shell.desktop.in.in \
gnome-shell-wayland.desktop.in.in \
org.gnome.Shell.desktop.in.in \
gnome-shell-extension-prefs.desktop.in.in \
$(portal_DATA) \
$(introspection_DATA) \
$(menu_DATA) \
$(convert_DATA) \
$(keys_in_files) \
$(keys_DATA) \
$(dist_theme_files) \
perf-background.xml.in \
org.gnome.Shell.PortalHelper.desktop.in \
org.gnome.Shell.PortalHelper.desktop.in.in \
org.gnome.Shell.PortalHelper.service.in \
org.gnome.shell.gschema.xml.in.in \
org.gnome.shell.gschema.xml.in \
gnome-shell-theme.gresource.xml \
$(resource_files) \
$(NULL)
CLEANFILES += \
gnome-shell.desktop.in \
gnome-shell-wayland.desktop.in \
org.gnome.Shell.desktop.in \
gnome-shell-extension-prefs.in \
$(desktop_DATA) \
$(keys_DATA) \
$(gsettings_SCHEMAS) \
perf-background.xml \
gschemas.compiled \
org.gnome.shell.gschema.valid \
org.gnome.shell.gschema.xml.in \
gnome-shell-theme.gresource \
$(NULL)

View File

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

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

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

4
data/gnome-shell.portal Normal file
View File

@ -0,0 +1,4 @@
[portal]
DBusName=org.freedesktop.impl.portal.desktop.gnome
Interfaces=org.freedesktop.impl.portal.Access
UseIn=gnome

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

@ -1,9 +1,10 @@
[Desktop Entry]
_Name=Network Login
Name=Network Login
Type=Application
Exec=gapplication launch org.gnome.Shell.PortalHelper
DBusActivatable=true
NoDisplay=true
# Translators: Do NOT translate or transliterate this text (this is an icon file name)!
Icon=network-workgroup
StartupNotify=true
OnlyShowIn=GNOME;

View File

@ -1,7 +1,7 @@
[Desktop Entry]
Type=Application
_Name=GNOME Shell
_Comment=Window management and application launching
Name=GNOME Shell
Comment=Window management and application launching
Exec=@bindir@/gnome-shell
X-GNOME-Bugzilla-Bugzilla=GNOME
X-GNOME-Bugzilla-Product=gnome-shell
@ -10,7 +10,7 @@ X-GNOME-Bugzilla-Version=@VERSION@
Categories=GNOME;GTK;Core;
OnlyShowIn=GNOME;
NoDisplay=true
X-GNOME-Autostart-Phase=WindowManager
X-GNOME-Autostart-Phase=DisplayServer
X-GNOME-Provides=panel;windowmanager;
X-GNOME-Autostart-Notify=true
X-GNOME-AutoRestart=false

View File

@ -3,133 +3,131 @@
gettext-domain="@GETTEXT_PACKAGE@">
<key name="development-tools" type="b">
<default>true</default>
<_summary>
<summary>
Enable internal tools useful for developers and testers from Alt-F2
</_summary>
<_description>
</summary>
<description>
Allows access to internal debugging and monitoring tools
using the Alt-F2 dialog.
</_description>
</description>
</key>
<key name="enabled-extensions" type="as">
<default>[]</default>
<_summary>UUIDs of extensions to enable</_summary>
<_description>
<summary>UUIDs of extensions to enable</summary>
<description>
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.
</_description>
</description>
</key>
<key name="disable-extension-version-validation" type="b">
<default>false</default>
<_summary>Disables the validation of extension version compatibility</_summary>
<_description>
<default>true</default>
<summary>Disables the validation of extension version compatibility</summary>
<description>
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.
</_description>
</description>
</key>
<key name="favorite-apps" type="as">
<default>[ 'epiphany.desktop', 'evolution.desktop', 'rhythmbox.desktop', 'shotwell.desktop', 'org.gnome.Nautilus.desktop', 'org.gnome.Software.desktop' ]</default>
<_summary>List of desktop file IDs for favorite applications</_summary>
<_description>
<summary>List of desktop file IDs for favorite applications</summary>
<description>
The applications corresponding to these identifiers
will be displayed in the favorites area.
</_description>
</description>
</key>
<key name="app-picker-view" type="u">
<default>0</default>
<_summary>App Picker View</_summary>
<_description>
<summary>App Picker View</summary>
<description>
Index of the currently selected view in the application picker.
</_description>
</description>
</key>
<key name="command-history" type="as">
<default>[]</default>
<_summary>History for command (Alt-F2) dialog</_summary>
<summary>History for command (Alt-F2) dialog</summary>
</key>
<key name="looking-glass-history" type="as">
<default>[]</default>
<!-- Translators: looking glass is a debugger and inspector tool, see https://live.gnome.org/GnomeShell/LookingGlass -->
<_summary>History for the looking glass dialog</_summary>
<!-- Translators: looking glass is a debugger and inspector tool, see https://wiki.gnome.org/Projects/GnomeShell/LookingGlass -->
<summary>History for the looking glass dialog</summary>
</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>
<_description>
<summary>Always show the 'Log out' menu item in the user menu.</summary>
<description>
This key overrides the automatic hiding of the 'Log out'
menu item in single-user, single-session situations.
</_description>
</description>
</key>
<key name="remember-mount-password" type="b">
<default>false</default>
<_summary>Whether to remember password for mounting encrypted or remote filesystems</_summary>
<_description>
<summary>Whether to remember password for mounting encrypted or remote filesystems</summary>
<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.
This key sets the default state of the checkbox.
</_description>
</description>
</key>
<key name="had-bluetooth-devices-setup" type="b">
<default>false</default>
<summary>Whether the default Bluetooth adapter had set up devices associated to it</summary>
<description>
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.
</description>
</key>
<child name="calendar" schema="org.gnome.shell.calendar"/>
<child name="keybindings" schema="org.gnome.shell.keybindings"/>
<child name="keyboard" schema="org.gnome.shell.keyboard"/>
</schema>
<schema id="org.gnome.shell.calendar" path="/org/gnome/shell/calendar/"
gettext-domain="@GETTEXT_PACKAGE@">
<key name="show-weekdate" type="b">
<default>false</default>
<_summary>Show the week date in the calendar</_summary>
<_description>
If true, display the ISO week date in the calendar.
</_description>
</key>
</schema>
<schema id="org.gnome.shell.keybindings" path="/org/gnome/shell/keybindings/"
gettext-domain="@GETTEXT_PACKAGE@">
<key name="open-application-menu" type="as">
<default>["&lt;Super&gt;F10"]</default>
<_summary>Keybinding to open the application menu</_summary>
<_description>
<summary>Keybinding to open the application menu</summary>
<description>
Keybinding to open the application menu.
</_description>
</description>
</key>
<key name="toggle-application-view" type="as">
<default>["&lt;Super&gt;a"]</default>
<_summary>Keybinding to open the "Show Applications" view</_summary>
<_description>
<summary>Keybinding to open the "Show Applications" view</summary>
<description>
Keybinding to open the "Show Applications" view of the Activities
Overview.
</_description>
</description>
</key>
<key name="toggle-overview" type="as">
<default>["&lt;Super&gt;s"]</default>
<_summary>Keybinding to open the overview</_summary>
<_description>
<summary>Keybinding to open the overview</summary>
<description>
Keybinding to open the Activities Overview.
</_description>
</description>
</key>
<key name="toggle-message-tray" type="as">
<default>["&lt;Super&gt;v","&lt;Super&gt;m"]</default>
<_summary>Keybinding to toggle the visibility of the notification list</_summary>
<_description>
<summary>Keybinding to toggle the visibility of the notification list</summary>
<description>
Keybinding to toggle the visibility of the notification list.
</_description>
</description>
</key>
<key name="focus-active-notification" type="as">
<default>["&lt;Super&gt;n"]</default>
<_summary>Keybinding to focus the active notification</_summary>
<_description>
<summary>Keybinding to focus the active notification</summary>
<description>
Keybinding to focus the active notification.
</_description>
</description>
</key>
<key name="pause-resume-tweens" type="as">
<default>[]</default>
<_summary>Keybinding that pauses and resumes all running tweens, for debugging purposes</_summary>
<_description></_description>
<summary>Keybinding that pauses and resumes all running tweens, for debugging purposes</summary>
<description></description>
</key>
</schema>
@ -137,10 +135,10 @@
gettext-domain="@GETTEXT_PACKAGE@">
<key name="keyboard-type" type="s">
<default>'touch'</default>
<_summary>Which keyboard to use</_summary>
<_description>
<summary>Which keyboard to use</summary>
<description>
The type of keyboard to use.
</_description>
</description>
</key>
</schema>
@ -149,11 +147,11 @@
gettext-domain="@GETTEXT_PACKAGE@">
<key type="b" name="current-workspace-only">
<default>false</default>
<_summary>Limit switcher to current workspace.</_summary>
<_description>
<summary>Limit switcher to current workspace.</summary>
<description>
If true, only applications that have windows on the current workspace are shown in the switcher.
Otherwise, all applications are included.
</_description>
</description>
</key>
</schema>
@ -167,20 +165,20 @@
gettext-domain="@GETTEXT_PACKAGE@">
<key name="app-icon-mode" enum="org.gnome.shell.window-switcher.AppIconMode">
<default>'both'</default>
<_summary>The application icon mode.</_summary>
<_description>
<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'.
</_description>
</description>
</key>
<key type="b" name="current-workspace-only">
<default>true</default>
<_summary>Limit switcher to current workspace.</_summary>
<_description>
<summary>Limit switcher to current workspace.</summary>
<description>
If true, only windows from the current workspace are shown in the switcher.
Otherwise, all windows are included.
</_description>
</description>
</key>
</schema>
@ -188,43 +186,43 @@
gettext-domain="@GETTEXT_PACKAGE@">
<key name="attach-modal-dialogs" type="b">
<default>true</default>
<_summary>Attach modal dialog to the parent window</_summary>
<_description>
<summary>Attach modal dialog to the parent window</summary>
<description>
This key overrides the key in org.gnome.mutter when running
GNOME Shell.
</_description>
</description>
</key>
<key name="edge-tiling" type="b">
<default>true</default>
<_summary>Enable edge tiling when dropping windows on screen edges</_summary>
<_description>
<summary>Enable edge tiling when dropping windows on screen edges</summary>
<description>
This key overrides the key in org.gnome.mutter when running GNOME Shell.
</_description>
</description>
</key>
<key name="dynamic-workspaces" type="b">
<default>true</default>
<_summary>Workspaces are managed dynamically</_summary>
<_description>
<summary>Workspaces are managed dynamically</summary>
<description>
This key overrides the key in org.gnome.mutter when running GNOME Shell.
</_description>
</description>
</key>
<key name="workspaces-only-on-primary" type="b">
<default>true</default>
<_summary>Workspaces only on primary monitor</_summary>
<_description>
<summary>Workspaces only on primary monitor</summary>
<description>
This key overrides the key in org.gnome.mutter when running GNOME Shell.
</_description>
</description>
</key>
<key name="focus-change-on-pointer-rest" type="b">
<default>true</default>
<_summary>Delay focus changes in mouse mode until the pointer stops moving</_summary>
<_description>
<summary>Delay focus changes in mouse mode until the pointer stops moving</summary>
<description>
This key overrides the key in org.gnome.mutter when running GNOME Shell.
</_description>
</description>
</key>
</schema>
</schemalist>

View File

@ -41,9 +41,9 @@ stage {
icon-shadow: 0 1px black;
box-shadow: inset 0px 0px 0px 1px #215d9c; }
.button:insensitive {
color: #7f7f7f;
color: gray;
border-color: rgba(0, 0, 0, 0.7);
background-color: rgba(62, 67, 68, 0.7);
background-color: rgba(62, 67, 69, 0.7);
box-shadow: none;
text-shadow: none;
icon-shadow: none; }
@ -65,9 +65,9 @@ stage {
icon-shadow: 0 1px black;
padding: 12px; }
.modal-dialog-linked-button:insensitive {
color: #7f7f7f;
color: gray;
border-color: rgba(0, 0, 0, 0.7);
background-color: rgba(62, 67, 68, 0.7);
background-color: rgba(62, 67, 69, 0.7);
box-shadow: none;
text-shadow: none;
icon-shadow: none; }
@ -107,8 +107,8 @@ StEntry {
box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.4);
border-color: rgba(166, 166, 166, 0.5); }
StEntry:insensitive {
color: #7f7f7f;
border-color: #0d0d0d;
color: gray;
border-color: #0e0e0e;
box-shadow: none; }
StEntry StIcon.capslock-warning {
icon-size: 16px;
@ -142,7 +142,7 @@ StScrollBar {
.slider {
height: 1em;
-slider-height: 0.3em;
-slider-background-color: #0d0d0d;
-slider-background-color: #0e0e0e;
-slider-border-color: black;
-slider-active-background-color: #215d9c;
-slider-active-border-color: #184472;
@ -199,7 +199,7 @@ StScrollBar {
border-radius: 9px;
color: #eeeeec;
background-color: rgba(23, 25, 26, 0.95);
border: 3px solid rgba(238, 238, 236, 0.5); }
border: 1px solid rgba(238, 238, 236, 0.2); }
.modal-dialog .modal-dialog-content-box {
padding: 24px; }
.modal-dialog .run-dialog-entry {
@ -224,7 +224,7 @@ StScrollBar {
/* End Session Dialog */
.end-session-dialog {
spacing: 42px;
border: 3px solid rgba(238, 238, 236, 0.2); }
border: 1px solid rgba(238, 238, 236, 0.2); }
.end-session-dialog-list {
padding-top: 20px; }
@ -399,6 +399,77 @@ StScrollBar {
width: 48px;
height: 48px; }
/* Audio selection dialog */
.audio-device-selection-dialog {
spacing: 30px; }
.audio-selection-content {
spacing: 20px;
padding: 24px; }
.audio-selection-title {
font-weight: bold;
text-align: center; }
.audio-selection-box {
spacing: 20px; }
.audio-selection-device {
border: 1px solid rgba(238, 238, 236, 0.2);
border-radius: 12px; }
.audio-selection-device:active, .audio-selection-device:hover, .audio-selection-device:focus {
background-color: #215d9c; }
.audio-selection-device-box {
padding: 20px;
spacing: 20px; }
.audio-selection-device-icon {
icon-size: 64px; }
/* Access Dialog */
.access-dialog {
spacing: 30px; }
.access-dialog-main-layout {
padding: 12px 20px 0;
spacing: 12px; }
.access-dialog-content {
max-width: 28em;
spacing: 20px; }
.access-dialog-icon {
min-width: 48px;
icon-size: 48px; }
.access-dialog-title {
font-weight: bold; }
.access-dialog-subtitle {
color: #999999;
font-weight: bold; }
/* Geolocation Dialog */
.geolocation-dialog {
spacing: 30px; }
.geolocation-dialog-main-layout {
spacing: 12px; }
.geolocation-dialog-content {
spacing: 20px; }
.geolocation-dialog-icon {
icon-size: 48px; }
.geolocation-dialog-title {
font-weight: bold; }
.geolocation-dialog-reason {
color: #999999;
font-weight: bold; }
/* Network Agent Dialog */
.network-dialog-secret-table {
spacing-rows: 15px;
@ -487,6 +558,17 @@ StScrollBar {
border-radius: 0.3em;
background-color: rgba(11, 12, 13, 0.5);
color: #eeeeec; }
.osd-window .level-bar {
background-color: #eeeeec;
border-radius: 0.3em; }
/* Pad OSD */
.pad-osd-window {
padding: 32px;
background-color: rgba(0, 0, 0, 0.8); }
.combo-box-label {
width: 15em; }
/* App Switcher */
.switcher-popup {
@ -530,6 +612,10 @@ StScrollBar {
width: 96px;
height: 96px; }
/* Window Cycler */
.cycler-highlight {
border: 5px solid #215d9c; }
/* Workspace Switcher */
.workspace-switcher-group {
padding: 12px; }
@ -625,6 +711,8 @@ StScrollBar {
#panel .panel-status-indicators-box,
#panel .panel-status-menu-box {
spacing: 2px; }
#panel .power-status.panel-status-indicators-box {
spacing: 0; }
#panel .screencast-indicator {
color: #f57900; }
@ -716,7 +804,7 @@ StScrollBar {
border-radius: 1.4em; }
.calendar-day-base:hover, .calendar-day-base:focus {
background-color: #0d0d0d; }
.calendar-day-base:active {
.calendar-day-base:active, .calendar-day-base:selected {
color: white;
background-color: #215d9c;
border-color: transparent; }
@ -735,7 +823,7 @@ StScrollBar {
border-left-width: 1px; }
.calendar-nonwork-day {
color: #7f7f7f; }
color: gray; }
.calendar-today {
font-weight: bold;
@ -750,6 +838,17 @@ StScrollBar {
color: rgba(255, 255, 255, 0.15);
opacity: 0.5; }
.calendar-week-number {
font-size: 70%;
font-weight: bold;
width: 2.3em;
height: 1.8em;
border-radius: 2px;
padding: 0.5em 0 0;
margin: 6px;
background-color: rgba(255, 255, 255, 0.3);
color: #000; }
/* Message list */
.message-list {
width: 31.5em; }
@ -808,6 +907,23 @@ StScrollBar {
padding: 8px;
font-size: .9em; }
.message-media-control {
padding: 6px; }
.message-media-control:last-child:ltr {
padding-right: 18px; }
.message-media-control:last-child:rtl {
padding-left: 18px; }
.media-message-cover-icon {
icon-size: 32px; }
.media-message-cover-icon.fallback {
color: #1a1a1a;
background-color: #000;
border: 2px solid #000;
border-radius: 2px;
icon-size: 16px;
padding: 8px; }
.system-switch-user-submenu-icon.user-icon {
icon-size: 20px;
padding: 0 2px; }
@ -960,10 +1076,14 @@ StScrollBar {
.search-entry {
width: 320px;
padding: 7px 9px;
border-radius: 6px; }
border-radius: 6px;
border-color: #747467;
color: #eeeeec;
background-color: #2e3436; }
.search-entry:focus {
padding: 6px 8px;
border-width: 2px; }
border-width: 2px;
border-color: #215d9c; }
.search-entry .search-entry-icon {
icon-size: 1em;
padding: 0 4px;
@ -1491,9 +1611,9 @@ StScrollBar {
text-shadow: none;
icon-shadow: none; }
.login-dialog .modal-dialog-button:default:insensitive {
color: #7f7f7f;
color: gray;
border-color: rgba(0, 0, 0, 0.7);
background-color: rgba(62, 67, 68, 0.7);
background-color: rgba(62, 67, 69, 0.7);
box-shadow: none;
text-shadow: none;
icon-shadow: none; }

View File

@ -41,9 +41,9 @@ stage {
icon-shadow: 0 1px black;
box-shadow: inset 0px 0px 0px 1px #215d9c; }
.button:insensitive {
color: #939695;
color: #949796;
border-color: rgba(0, 0, 0, 0.7);
background-color: rgba(66, 71, 73, 0.7);
background-color: rgba(66, 72, 73, 0.7);
box-shadow: none;
text-shadow: none;
icon-shadow: none; }
@ -65,9 +65,9 @@ stage {
icon-shadow: 0 1px black;
padding: 12px; }
.modal-dialog-linked-button:insensitive {
color: #939695;
color: #949796;
border-color: rgba(0, 0, 0, 0.7);
background-color: rgba(66, 71, 73, 0.7);
background-color: rgba(66, 72, 73, 0.7);
box-shadow: none;
text-shadow: none;
icon-shadow: none; }
@ -107,8 +107,8 @@ StEntry {
box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.4);
border-color: rgba(154, 154, 142, 0.5); }
StEntry:insensitive {
color: #939695;
border-color: #323636;
color: #949796;
border-color: #333636;
box-shadow: none; }
StEntry StIcon.capslock-warning {
icon-size: 16px;
@ -131,10 +131,10 @@ StScrollBar {
background-color: transparent; }
StScrollBar StButton#vhandle, StScrollBar StButton#hhandle {
border-radius: 8px;
background-color: #a5a8a6;
background-color: #a6a8a7;
margin: 3px; }
StScrollBar StButton#vhandle:hover, StScrollBar StButton#hhandle:hover {
background-color: #c9cbc9; }
background-color: #cacbc9; }
StScrollBar StButton#vhandle:active, StScrollBar StButton#hhandle:active {
background-color: #215d9c; }
@ -142,7 +142,7 @@ StScrollBar {
.slider {
height: 1em;
-slider-height: 0.3em;
-slider-background-color: #323636;
-slider-background-color: #333636;
-slider-border-color: #1c1f1f;
-slider-active-background-color: #215d9c;
-slider-active-border-color: #184472;
@ -199,7 +199,7 @@ StScrollBar {
border-radius: 9px;
color: #eeeeec;
background-color: rgba(23, 25, 26, 0.95);
border: 3px solid rgba(238, 238, 236, 0.5); }
border: 1px solid rgba(238, 238, 236, 0.2); }
.modal-dialog .modal-dialog-content-box {
padding: 24px; }
.modal-dialog .run-dialog-entry {
@ -224,7 +224,7 @@ StScrollBar {
/* End Session Dialog */
.end-session-dialog {
spacing: 42px;
border: 3px solid rgba(238, 238, 236, 0.2); }
border: 1px solid rgba(238, 238, 236, 0.2); }
.end-session-dialog-list {
padding-top: 20px; }
@ -399,6 +399,77 @@ StScrollBar {
width: 48px;
height: 48px; }
/* Audio selection dialog */
.audio-device-selection-dialog {
spacing: 30px; }
.audio-selection-content {
spacing: 20px;
padding: 24px; }
.audio-selection-title {
font-weight: bold;
text-align: center; }
.audio-selection-box {
spacing: 20px; }
.audio-selection-device {
border: 1px solid rgba(238, 238, 236, 0.2);
border-radius: 12px; }
.audio-selection-device:active, .audio-selection-device:hover, .audio-selection-device:focus {
background-color: #215d9c; }
.audio-selection-device-box {
padding: 20px;
spacing: 20px; }
.audio-selection-device-icon {
icon-size: 64px; }
/* Access Dialog */
.access-dialog {
spacing: 30px; }
.access-dialog-main-layout {
padding: 12px 20px 0;
spacing: 12px; }
.access-dialog-content {
max-width: 28em;
spacing: 20px; }
.access-dialog-icon {
min-width: 48px;
icon-size: 48px; }
.access-dialog-title {
font-weight: bold; }
.access-dialog-subtitle {
color: #8e8e80;
font-weight: bold; }
/* Geolocation Dialog */
.geolocation-dialog {
spacing: 30px; }
.geolocation-dialog-main-layout {
spacing: 12px; }
.geolocation-dialog-content {
spacing: 20px; }
.geolocation-dialog-icon {
icon-size: 48px; }
.geolocation-dialog-title {
font-weight: bold; }
.geolocation-dialog-reason {
color: #8e8e80;
font-weight: bold; }
/* Network Agent Dialog */
.network-dialog-secret-table {
spacing-rows: 15px;
@ -487,6 +558,17 @@ StScrollBar {
border-radius: 0.3em;
background-color: rgba(11, 12, 13, 0.5);
color: #eeeeec; }
.osd-window .level-bar {
background-color: #eeeeec;
border-radius: 0.3em; }
/* Pad OSD */
.pad-osd-window {
padding: 32px;
background-color: rgba(0, 0, 0, 0.8); }
.combo-box-label {
width: 15em; }
/* App Switcher */
.switcher-popup {
@ -530,6 +612,10 @@ StScrollBar {
width: 96px;
height: 96px; }
/* Window Cycler */
.cycler-highlight {
border: 5px solid #215d9c; }
/* Workspace Switcher */
.workspace-switcher-group {
padding: 12px; }
@ -625,6 +711,8 @@ StScrollBar {
#panel .panel-status-indicators-box,
#panel .panel-status-menu-box {
spacing: 2px; }
#panel .power-status.panel-status-indicators-box {
spacing: 0; }
#panel .screencast-indicator {
color: #f57900; }
@ -716,7 +804,7 @@ StScrollBar {
border-radius: 1.4em; }
.calendar-day-base:hover, .calendar-day-base:focus {
background-color: #454c4c; }
.calendar-day-base:active {
.calendar-day-base:active, .calendar-day-base:selected {
color: white;
background-color: #215d9c;
border-color: transparent; }
@ -735,7 +823,7 @@ StScrollBar {
border-left-width: 1px; }
.calendar-nonwork-day {
color: #939695; }
color: #949796; }
.calendar-today {
font-weight: bold;
@ -750,6 +838,17 @@ StScrollBar {
color: rgba(238, 238, 236, 0.15);
opacity: 0.5; }
.calendar-week-number {
font-size: 70%;
font-weight: bold;
width: 2.3em;
height: 1.8em;
border-radius: 2px;
padding: 0.5em 0 0;
margin: 6px;
background-color: rgba(238, 238, 236, 0.3);
color: #393f3f; }
/* Message list */
.message-list {
width: 31.5em; }
@ -808,6 +907,23 @@ StScrollBar {
padding: 8px;
font-size: .9em; }
.message-media-control {
padding: 6px; }
.message-media-control:last-child:ltr {
padding-right: 18px; }
.message-media-control:last-child:rtl {
padding-left: 18px; }
.media-message-cover-icon {
icon-size: 32px; }
.media-message-cover-icon.fallback {
color: #515a5a;
background-color: #393f3f;
border: 2px solid #393f3f;
border-radius: 2px;
icon-size: 16px;
padding: 8px; }
.system-switch-user-submenu-icon.user-icon {
icon-size: 20px;
padding: 0 2px; }
@ -960,10 +1076,14 @@ StScrollBar {
.search-entry {
width: 320px;
padding: 7px 9px;
border-radius: 6px; }
border-radius: 6px;
border-color: #747467;
color: #eeeeec;
background-color: #2e3436; }
.search-entry:focus {
padding: 6px 8px;
border-width: 2px; }
border-width: 2px;
border-color: #215d9c; }
.search-entry .search-entry-icon {
icon-size: 1em;
padding: 0 4px;
@ -1491,9 +1611,9 @@ StScrollBar {
text-shadow: none;
icon-shadow: none; }
.login-dialog .modal-dialog-button:default:insensitive {
color: #939695;
color: #949796;
border-color: rgba(0, 0, 0, 0.7);
background-color: rgba(66, 71, 73, 0.7);
background-color: rgba(66, 72, 73, 0.7);
box-shadow: none;
text-shadow: none;
icon-shadow: none; }

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

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

View File

@ -78,7 +78,7 @@ expand_content_files=
# e.g. GTKDOC_CFLAGS=-I$(top_srcdir) -I$(top_builddir) $(GTK_DEBUG_FLAGS)
# e.g. GTKDOC_LIBS=$(top_builddir)/gtk/$(gtktargetlib)
GTKDOC_CFLAGS=
GTKDOC_LIBS=$(top_builddir)/src/libst-1.0.la
GTKDOC_LIBS=$(top_builddir)/src/libst-1.0.la -rpath $(MUTTER_TYPELIB_DIR)
# This includes the standard gtk-doc make rules, copied by gtkdocize.
include $(top_srcdir)/gtk-doc.make

View File

@ -23,11 +23,6 @@ const GnomeShellIface = '<node> \
</interface> \
</node>';
const customCss = '.prefs-button { \
padding: 8px; \
border-radius: 20px; \
}';
const GnomeShellProxy = Gio.DBusProxy.makeProxyWrapper(GnomeShellIface);
function stripPrefix(string, prefix) {
@ -157,6 +152,7 @@ const Application = new Lang.Class({
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 });
this._window.add(scroll);
@ -176,21 +172,6 @@ const Application = new Lang.Class({
this._window.show_all();
},
_addCustomStyle: function() {
let provider = new Gtk.CssProvider();
try {
provider.load_from_data(customCss, -1);
} catch(e) {
log('Failed to add application style');
return;
}
let screen = this._window.window.get_screen();
let priority = Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION;
Gtk.StyleContext.add_provider_for_screen(screen, provider, priority);
},
_sortList: function(row1, row2) {
let name1 = ExtensionUtils.extensions[row1.uuid].metadata.name;
let name2 = ExtensionUtils.extensions[row2.uuid].metadata.name;
@ -239,7 +220,6 @@ const Application = new Lang.Class({
_onStartup: function(app) {
this._buildUI(app);
this._addCustomStyle();
this._scanExtensions();
},
@ -316,7 +296,7 @@ const ExtensionRow = new Lang.Class({
button.add(new Gtk.Image({ icon_name: 'emblem-system-symbolic',
icon_size: Gtk.IconSize.BUTTON,
visible: true }));
button.get_style_context().add_class('prefs-button');
button.get_style_context().add_class('circular');
hbox.add(button);
this.prefsButton = button;

View File

@ -13,6 +13,7 @@ const Params = imports.misc.params;
const ShellEntry = imports.ui.shellEntry;
const Tweener = imports.ui.tweener;
const UserWidget = imports.ui.userWidget;
const Pango = imports.gi.Pango;
const DEFAULT_BUTTON_WELL_ICON_SIZE = 16;
const DEFAULT_BUTTON_WELL_ANIMATION_DELAY = 1.0;
@ -113,6 +114,7 @@ const AuthPrompt = new Lang.Class({
this._message = new St.Label({ opacity: 0,
styleClass: 'login-dialog-message' });
this._message.clutter_text.line_wrap = true;
this._message.clutter_text.ellipsize = Pango.EllipsizeMode.NONE;
this.actor.add(this._message, { x_fill: false, x_align: St.Align.START, y_align: St.Align.START });
this._buttonBox = new St.BoxLayout({ style_class: 'login-dialog-button-box',
@ -189,7 +191,8 @@ const AuthPrompt = new Lang.Class({
this._updateNextButtonSensitivity(this._entry.text.length > 0);
}));
this._entry.clutter_text.connect('activate', Lang.bind(this, function() {
this.emit('next');
if (this.nextButton.reactive)
this.emit('next');
}));
},

View File

@ -96,7 +96,7 @@ const UserListItem = new Lang.Class({
},
_onDestroy: function() {
this._user.disconnect(this._userChangedId);
this.user.disconnect(this._userChangedId);
},
_onClicked: function() {
@ -212,6 +212,10 @@ const UserList = new Lang.Class({
return item;
},
containsUser: function(user) {
return this._items[user.get_user_name()] != null;
},
addUser: function(user) {
if (!user.is_loaded)
return;
@ -800,6 +804,11 @@ const LoginDialog = new Lang.Class({
this._user = null;
if (this._nextSignalId) {
this._authPrompt.disconnect(this._nextSignalId);
this._nextSignalId = 0;
}
if (beginRequest == AuthPrompt.BeginRequestType.PROVIDE_USERNAME) {
if (!this._disableUserList)
this._showUserList();
@ -924,11 +933,7 @@ const LoginDialog = new Lang.Class({
},
onUpdateScope: this,
onComplete: function() {
let id = Mainloop.idle_add(Lang.bind(this, function() {
this._greeter.call_start_session_when_ready_sync(serviceName, true, null);
return GLib.SOURCE_REMOVE;
}));
GLib.Source.set_name_by_id(id, '[gnome-shell] this._greeter.call_start_session_when_ready_sync');
this._greeter.call_start_session_when_ready_sync(serviceName, true, null);
},
onCompleteScope: this });
},
@ -1130,6 +1135,10 @@ const LoginDialog = new Lang.Class({
this._userManager.disconnect(this._userRemovedId);
this._userRemovedId = 0;
}
if (this._userChangedId) {
this._userManager.disconnect(this._userChangedId);
this._userChangedId = 0;
}
this._textureCache.disconnect(this._updateLogoTextureId);
Main.layoutManager.disconnect(this._startupCompleteId);
if (this._settings) {
@ -1176,6 +1185,14 @@ const LoginDialog = new Lang.Class({
this._userList.removeUser(user);
}));
this._userChangedId = this._userManager.connect('user-changed',
Lang.bind(this, function(userManager, user) {
if (this._userList.containsUser(user) && user.locked)
this._userList.removeUser(user);
else if (!this._userList.containsUser(user) && !user.locked)
this._userList.addUser(user);
}));
return GLib.SOURCE_REMOVE;
},

View File

@ -31,10 +31,12 @@
<file>portalHelper/main.js</file>
<file>ui/accessDialog.js</file>
<file>ui/altTab.js</file>
<file>ui/animation.js</file>
<file>ui/appDisplay.js</file>
<file>ui/appFavorites.js</file>
<file>ui/audioDeviceSelection.js</file>
<file>ui/backgroundMenu.js</file>
<file>ui/background.js</file>
<file>ui/boxpointer.js</file>
@ -62,12 +64,15 @@
<file>ui/magnifierDBus.js</file>
<file>ui/main.js</file>
<file>ui/messageTray.js</file>
<file>ui/messageList.js</file>
<file>ui/modalDialog.js</file>
<file>ui/mpris.js</file>
<file>ui/notificationDaemon.js</file>
<file>ui/osdWindow.js</file>
<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>

View File

@ -6,9 +6,7 @@
const Lang = imports.lang;
const Signals = imports.signals;
const GLib = imports.gi.GLib;
const Gio = imports.gi.Gio;
const ShellJS = imports.gi.ShellJS;
const Config = imports.misc.config;
const FileUtils = imports.misc.fileUtils;
@ -21,14 +19,25 @@ const ExtensionType = {
// Maps uuid -> metadata object
const extensions = {};
/**
* getCurrentExtension:
*
* Returns the current extension, or null if not called from an extension.
*/
function getCurrentExtension() {
let stack = (new Error()).stack;
let stack = (new Error()).stack.split('\n');
let extensionStackLine;
// Assuming we're importing this directly from an extension (and we shouldn't
// ever not be), its UUID should be directly in the path here.
let extensionStackLine = stack.split('\n')[1];
// Search for an occurrence of an extension stack frame
// Start at 1 because 0 is the stack frame of this function
for (let i = 1; i < stack.length; i++) {
if (stack[i].indexOf('/gnome-shell/extensions/') > -1) {
extensionStackLine = stack[i];
break;
}
}
if (!extensionStackLine)
throw new Error('Could not find current extension');
return null;
// The stack line is like:
// init([object Object])@/home/user/data/gnome-shell/extensions/u@u.id/prefs.js:8
@ -38,7 +47,7 @@ function getCurrentExtension() {
// @/home/user/data/gnome-shell/extensions/u@u.id/prefs.js:8
let match = new RegExp('@(.+):\\d+').exec(extensionStackLine);
if (!match)
throw new Error('Could not find current extension');
return null;
let path = match[1];
let file = Gio.File.new_for_path(path);
@ -52,7 +61,7 @@ function getCurrentExtension() {
file = file.get_parent();
}
throw new Error('Could not find current extension');
return null;
}
/**
@ -140,12 +149,13 @@ function createExtensionObject(uuid, dir, type) {
return extension;
}
var _extension = null;
function installImporter(extension) {
_extension = extension;
ShellJS.add_extension_importer('imports.misc.extensionUtils._extension', 'imports', extension.path);
_extension = null;
let oldSearchPath = imports.searchPath.slice(); // make a copy
imports.searchPath = [extension.dir.get_parent().get_path()];
// importing a "subdir" creates a new importer object that doesn't affect
// the global one
extension.imports = imports[extension.uuid];
imports.searchPath = oldSearchPath;
}
const ExtensionFinder = new Lang.Class({

View File

@ -40,6 +40,9 @@ const SystemdLoginSessionIface = '<node> \
<signal name="Lock" /> \
<signal name="Unlock" /> \
<property name="Active" type="b" access="read" /> \
<method name="SetLockedHint"> \
<arg type="b" direction="in"/> \
</method> \
</interface> \
</node>';
@ -131,10 +134,13 @@ const LoginManagerSystemd = new Lang.Class({
canSuspend: function(asyncCallback) {
this._proxy.CanSuspendRemote(function(result, error) {
if (error)
asyncCallback(false);
else
asyncCallback(result[0] != 'no' && result[0] != 'na');
if (error) {
asyncCallback(false, false);
} else {
let needsAuth = result[0] == 'challenge';
let canSuspend = needsAuth || result[0] == 'yes';
asyncCallback(canSuspend, needsAuth);
}
});
},
@ -187,7 +193,7 @@ const LoginManagerDummy = new Lang.Class({
},
canSuspend: function(asyncCallback) {
asyncCallback(false);
asyncCallback(false, false);
},
listSessions: function(asyncCallback) {

View File

@ -94,7 +94,7 @@ function spawnApp(argv) {
Gio.AppInfoCreateFlags.SUPPORTS_STARTUP_NOTIFICATION);
let context = global.create_app_launch_context(0, -1);
app.launch([], context);
app.launch([], context, false);
} catch(err) {
_handleSpawnError(argv[0], err);
}

View File

@ -20,6 +20,8 @@ const PortalHelperResult = {
};
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> \
@ -50,7 +52,7 @@ const PortalWindow = new Lang.Class({
this.parent({ application: application });
if (!url) {
url = 'http://www.gnome.org';
url = CONNECTIVITY_CHECK_URI;
this._originalUrlWasGnome = true;
} else {
this._originalUrlWasGnome = false;
@ -112,12 +114,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;
}
}

202
js/ui/accessDialog.js Normal file
View File

@ -0,0 +1,202 @@
const Clutter = imports.gi.Clutter;
const Gio = imports.gi.Gio;
const GLib = imports.gi.GLib;
const Lang = imports.lang;
const Pango = imports.gi.Pango;
const Shell = imports.gi.Shell;
const St = imports.gi.St;
const CheckBox = imports.ui.checkBox;
const ModalDialog = imports.ui.modalDialog;
const RequestIface = '<node> \
<interface name="org.freedesktop.impl.portal.Request"> \
<method name="Close"/> \
</interface> \
</node>';
const AccessIface = '<node> \
<interface name="org.freedesktop.impl.portal.Access"> \
<method name="AccessDialog"> \
<arg type="o" name="handle" direction="in"/> \
<arg type="s" name="app_id" direction="in"/> \
<arg type="s" name="parent_window" direction="in"/> \
<arg type="s" name="title" direction="in"/> \
<arg type="s" name="subtitle" direction="in"/> \
<arg type="s" name="body" direction="in"/> \
<arg type="a{sv}" name="options" direction="in"/> \
<arg type="u" name="response" direction="out"/> \
<arg type="a{sv}" name="results" direction="out"/> \
</method> \
</interface> \
</node>';
const DialogResponse = {
OK: 0,
CANCEL: 1,
CLOSED: 2
};
const AccessDialog = new Lang.Class({
Name: 'AccessDialog',
Extends: ModalDialog.ModalDialog,
_init: function(invocation, handle, title, subtitle, body, options) {
this.parent({ styleClass: 'access-dialog' });
this._invocation = invocation;
this._handle = handle;
this._requestExported = false;
this._request = Gio.DBusExportedObject.wrapJSObject(RequestIface, this);
for (let option in options)
options[option] = options[option].deep_unpack();
this._buildLayout(title, subtitle, body, options);
},
_buildLayout: function(title, subtitle, body, options) {
// No support for non-modal system dialogs, so ignore the option
//let modal = options['modal'] || true;
let denyLabel = options['deny_label'] || _("Deny Access");
let grantLabel = options['grant_label'] || _("Grant Access");
let iconName = options['icon'] || null;
let choices = options['choices'] || [];
let mainContentBox = new St.BoxLayout();
mainContentBox.style_class = 'access-dialog-main-layout';
this.contentLayout.add_actor(mainContentBox);
let icon = new St.Icon({ style_class: 'access-dialog-icon',
icon_name: iconName,
y_align: Clutter.ActorAlign.START });
mainContentBox.add_actor(icon);
let messageBox = new St.BoxLayout({ vertical: true });
messageBox.style_class = 'access-dialog-content',
mainContentBox.add_actor(messageBox);
let label;
label = new St.Label({ style_class: 'access-dialog-title headline',
text: title });
messageBox.add_actor(label);
label = new St.Label({ style_class: 'access-dialog-subtitle',
text: subtitle });
label.clutter_text.ellipsize = Pango.EllipsizeMode.NONE;
label.clutter_text.line_wrap = true;
messageBox.add_actor(label);
this._choices = new Map();
for (let i = 0; i < choices.length; i++) {
let [id, name, opts, selected] = choices[i];
if (opts.length > 0)
continue; // radio buttons, not implemented
let check = new CheckBox.CheckBox();
check.getLabelActor().text = name;
check.actor.checked = selected == "true";
messageBox.add_actor(check.actor);
this._choices.set(id, check);
}
label = new St.Label({ text: body });
label.clutter_text.ellipsize = Pango.EllipsizeMode.NONE;
label.clutter_text.line_wrap = true;
messageBox.add_actor(label);
this.addButton({ label: denyLabel,
action: () => {
this._sendResponse(DialogResponse.CANCEL);
},
key: Clutter.KEY_Escape });
this.addButton({ label: grantLabel,
action: () => {
this._sendResponse(DialogResponse.OK);
}});
},
open: function() {
this.parent();
let connection = this._invocation.get_connection();
this._requestExported = this._request.export(connection, this._handle);
},
CloseAsync: function(invocation, params) {
if (this._invocation.get_sender() != invocation.get_sender()) {
invocation.return_error_literal(Gio.DBusError,
Gio.DBusError.ACCESS_DENIED,
'');
return;
}
this._sendResponse(DialogResponse.CLOSED);
},
_sendResponse: function(response) {
if (this._requestExported)
this._request.unexport();
this._requestExported = false;
let results = {};
if (response == DialogResponse.OK) {
for (let [id, check] of this._choices) {
let checked = check.actor.checked ? 'true' : 'false';
results[id] = new GLib.Variant('s', checked);
}
}
// Delay actual response until the end of the close animation (if any)
this.connect('closed', () => {
this._invocation.return_value(new GLib.Variant('(ua{sv})',
[response, results]));
});
this.close();
}
});
const AccessDialogDBus = new Lang.Class({
Name: 'AccessDialogDBus',
_init: function() {
this._accessDialog = null;
this._windowTracker = Shell.WindowTracker.get_default();
this._dbusImpl = Gio.DBusExportedObject.wrapJSObject(AccessIface, this);
this._dbusImpl.export(Gio.DBus.session, '/org/freedesktop/portal/desktop');
Gio.DBus.session.own_name('org.freedesktop.impl.portal.desktop.gnome', Gio.BusNameOwnerFlags.REPLACE, null, null);
},
AccessDialogAsync: function(params, invocation) {
if (this._accessDialog) {
invocation.return_error_literal(Gio.DBusError,
Gio.DBusError.LIMITS_EXCEEDED,
'Already showing a system access dialog');
return;
}
let [handle, appId, parentWindow, title, subtitle, body, options] = params;
// We probably want to use parentWindow and global.display.focus_window
// for this check in the future
if (appId && appId + '.desktop' != this._windowTracker.focus_app.id) {
invocation.return_error_literal(Gio.DBusError,
Gio.DBusError.ACCESS_DENIED,
'Only the focused app is allowed to show a system access dialog');
return;
}
let dialog = new AccessDialog(invocation, handle, title,
subtitle, body, options);
dialog.open();
dialog.connect('closed', () => { this._accessDialog = null; });
this._accessDialog = dialog;
}
});

View File

@ -46,6 +46,19 @@ function _createWindowClone(window, size) {
y_expand: true });
};
function getWindows(workspace) {
// We ignore skip-taskbar windows in switchers, but if they are attached
// to their parent, their position in the MRU list may be more appropriate
// than the parent; so start with the complete list ...
let windows = global.display.get_tab_list(Meta.TabList.NORMAL_ALL,
workspace);
// ... map windows to their parent where appropriate ...
return windows.map(w => {
return w.is_attached_dialog() ? w.get_transient_for() : w;
// ... and filter out skip-taskbar windows and duplicates
}).filter((w, i, a) => !w.skip_taskbar && a.indexOf(w) == i);
}
const AppSwitcherPopup = new Lang.Class({
Name: 'AppSwitcherPopup',
Extends: SwitcherPopup.SwitcherPopup,
@ -354,6 +367,149 @@ const AppSwitcherPopup = new Lang.Class({
}
});
const CyclerHighlight = new Lang.Class({
Name: 'CyclerHighlight',
_init: function() {
this._window = null;
this.actor = new St.Widget({ layout_manager: new Clutter.BinLayout() });
this._clone = new Clutter.Clone();
this.actor.add_actor(this._clone);
this._highlight = new St.Widget({ style_class: 'cycler-highlight' });
this.actor.add_actor(this._highlight);
let coordinate = Clutter.BindCoordinate.ALL;
let constraint = new Clutter.BindConstraint({ coordinate: coordinate });
this._clone.bind_property('source', constraint, 'source', 0);
this.actor.add_constraint(constraint);
this.actor.connect('notify::allocation',
Lang.bind(this, this._onAllocationChanged));
this.actor.connect('destroy', Lang.bind(this, this._onDestroy));
},
set window(w) {
if (this._window == w)
return;
this._window = w;
if (this._clone.source)
this._clone.source.sync_visibility();
let windowActor = this._window ? this._window.get_compositor_private()
: null;
if (windowActor)
windowActor.hide();
this._clone.source = windowActor;
},
_onAllocationChanged: function() {
if (!this._window) {
this._highlight.set_size(0, 0);
this._highlight.hide();
} else {
let [x, y] = this.actor.allocation.get_origin();
let rect = this._window.get_frame_rect();
this._highlight.set_size(rect.width, rect.height);
this._highlight.set_position(rect.x - x, rect.y - y);
this._highlight.show();
}
},
_onDestroy: function() {
this.window = null;
}
});
const CyclerPopup = new Lang.Class({
Name: 'CyclerPopup',
Extends: SwitcherPopup.SwitcherPopup,
Abstract: true,
_init : function() {
this.parent();
this._items = this._getWindows();
if (this._items.length == 0)
return;
this._highlight = new CyclerHighlight();
global.window_group.add_actor(this._highlight.actor);
// We don't show an actual popup, so just provide what SwitcherPopup
// expects instead of inheriting from SwitcherList
this._switcherList = { actor: new St.Widget(),
highlight: Lang.bind(this, this._highlightItem),
connect: function() {} };
},
_highlightItem: function(index, justOutline) {
this._highlight.window = this._items[index];
global.window_group.set_child_above_sibling(this._highlight.actor, null);
},
_finish: function() {
let window = this._items[this._selectedIndex];
let ws = window.get_workspace();
let activeWs = global.screen.get_active_workspace();
if (window.minimized) {
Main.wm.skipNextEffect(window.get_compositor_private());
window.unminimize();
}
if (activeWs == ws) {
Main.activateWindow(window);
} else {
// If the selected window is on a different workspace, we don't
// want it to disappear, then slide in with the workspace; instead,
// always activate it on the active workspace ...
activeWs.activate_with_focus(window, global.get_current_time());
// ... then slide it over to the original workspace if necessary
Main.wm.actionMoveWindow(window, ws);
}
this.parent();
},
_onDestroy: function() {
this._highlight.actor.destroy();
this.parent();
}
});
const GroupCyclerPopup = new Lang.Class({
Name: 'GroupCyclerPopup',
Extends: CyclerPopup,
_getWindows: function() {
let app = Shell.WindowTracker.get_default().focus_app;
return app ? app.get_windows() : [];
},
_keyPressHandler: function(keysym, action) {
if (action == Meta.KeyBindingAction.CYCLE_GROUP)
this._select(this._next());
else if (action == Meta.KeyBindingAction.CYCLE_GROUP_BACKWARD)
this._select(this._previous());
else
return Clutter.EVENT_PROPAGATE;
return Clutter.EVENT_STOP;
}
});
const WindowSwitcherPopup = new Lang.Class({
Name: 'WindowSwitcherPopup',
Extends: SwitcherPopup.SwitcherPopup,
@ -374,7 +530,7 @@ const WindowSwitcherPopup = new Lang.Class({
_getWindowList: function() {
let workspace = this._settings.get_boolean('current-workspace-only') ? global.screen.get_active_workspace() : null;
return global.display.get_tab_list(Meta.TabList.NORMAL, workspace);
return getWindows(workspace);
},
_keyPressHandler: function(keysym, action) {
@ -401,6 +557,32 @@ const WindowSwitcherPopup = new Lang.Class({
}
});
const WindowCyclerPopup = new Lang.Class({
Name: 'WindowCyclerPopup',
Extends: CyclerPopup,
_init: function() {
this._settings = new Gio.Settings({ schema_id: 'org.gnome.shell.window-switcher' });
this.parent();
},
_getWindows: function() {
let workspace = this._settings.get_boolean('current-workspace-only') ? global.screen.get_active_workspace() : null;
return getWindows(workspace);
},
_keyPressHandler: function(keysym, action) {
if (action == Meta.KeyBindingAction.CYCLE_WINDOWS)
this._select(this._next());
else if (action == Meta.KeyBindingAction.CYCLE_WINDOWS_BACKWARD)
this._select(this._previous());
else
return Clutter.EVENT_PROPAGATE;
return Clutter.EVENT_STOP;
}
});
const AppIcon = new Lang.Class({
Name: 'AppIcon',
@ -685,15 +867,17 @@ const WindowIcon = new Lang.Class({
this._icon.destroy_all_children();
let scaleFactor = St.ThemeContext.get_for_stage(global.stage).scale_factor;
switch (mode) {
case AppIconMode.THUMBNAIL_ONLY:
size = WINDOW_PREVIEW_SIZE;
this._icon.add_actor(_createWindowClone(mutterWindow, WINDOW_PREVIEW_SIZE));
this._icon.add_actor(_createWindowClone(mutterWindow, size * scaleFactor));
break;
case AppIconMode.BOTH:
size = WINDOW_PREVIEW_SIZE;
this._icon.add_actor(_createWindowClone(mutterWindow, WINDOW_PREVIEW_SIZE));
this._icon.add_actor(_createWindowClone(mutterWindow, size * scaleFactor));
if (this.app)
this._icon.add_actor(this._createAppIcon(this.app,
@ -705,7 +889,7 @@ const WindowIcon = new Lang.Class({
this._icon.add_actor(this._createAppIcon(this.app, size));
}
this._icon.set_size(size, size);
this._icon.set_size(size * scaleFactor, size * scaleFactor);
},
_createAppIcon: function(app, size) {

View File

@ -7,7 +7,7 @@ const St = imports.gi.St;
const Signals = imports.signals;
const Atk = imports.gi.Atk;
const ANIMATED_ICON_UPDATE_TIMEOUT = 14;
const ANIMATED_ICON_UPDATE_TIMEOUT = 16;
const Animation = new Lang.Class({
Name: 'Animation',
@ -33,7 +33,7 @@ const Animation = new Lang.Class({
if (this._frame == 0)
this._showFrame(0);
this._timeoutId = Mainloop.timeout_add(this._speed, Lang.bind(this, this._update));
this._timeoutId = GLib.timeout_add(GLib.PRIORITY_LOW, this._speed, Lang.bind(this, this._update));
GLib.Source.set_name_by_id(this._timeoutId, '[gnome-shell] this._update');
}
@ -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

@ -60,6 +60,18 @@ const PAGE_SWITCH_TIME = 0.3;
const VIEWS_SWITCH_TIME = 0.4;
const VIEWS_SWITCH_ANIMATION_DELAY = 0.1;
const SWITCHEROO_BUS_NAME = 'net.hadess.SwitcherooControl';
const SWITCHEROO_OBJECT_PATH = '/net/hadess/SwitcherooControl';
const SwitcherooProxyInterface = '<node> \
<interface name="net.hadess.SwitcherooControl"> \
<property name="HasDualGpu" type="b" access="read"/> \
</interface> \
</node>';
const SwitcherooProxy = Gio.DBusProxy.makeProxyWrapper(SwitcherooProxyInterface);
let discreteGpuAvailable = false;
function _getCategories(info) {
let categoriesStr = info.get_categories();
if (!categoriesStr)
@ -198,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() {
@ -213,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) {
@ -969,10 +981,36 @@ const AppDisplay = new Lang.Class({
initialView = Views.ALL;
this._showView(initialView);
this._updateFrequentVisibility();
Gio.DBus.system.watch_name(SWITCHEROO_BUS_NAME,
Gio.BusNameWatcherFlags.NONE,
Lang.bind(this, this._switcherooProxyAppeared),
Lang.bind(this, function() {
this._switcherooProxy = null;
this._updateDiscreteGpuAvailable();
}));
},
_updateDiscreteGpuAvailable: function() {
if (!this._switcherooProxy)
discreteGpuAvailable = false;
else
discreteGpuAvailable = this._switcherooProxy.HasDualGpu;
},
_switcherooProxyAppeared: function() {
this._switcherooProxy = new SwitcherooProxy(Gio.DBus.system, SWITCHEROO_BUS_NAME, SWITCHEROO_OBJECT_PATH,
Lang.bind(this, function(proxy, error) {
if (error) {
log(error.message);
return;
}
this._updateDiscreteGpuAvailable();
}));
},
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
@ -1814,7 +1852,7 @@ const AppIconMenu = new Lang.Class({
if (!source.actor.mapped)
this.close();
}));
source.actor.connect('destroy', Lang.bind(this, function () { this.actor.destroy(); }));
source.actor.connect('destroy', Lang.bind(this, this.destroy));
Main.uiGroup.add_actor(this.actor);
},
@ -1861,6 +1899,19 @@ const AppIconMenu = new Lang.Class({
this._appendSeparator();
}
if (discreteGpuAvailable &&
this._source.app.state == Shell.AppState.STOPPED &&
actions.indexOf('activate-discrete-gpu') == -1) {
this._onDiscreteGpuMenuItem = this._appendMenuItem(_("Launch using Dedicated Graphics Card"));
this._onDiscreteGpuMenuItem.connect('activate', Lang.bind(this, function() {
if (this._source.app.state == Shell.AppState.STOPPED)
this._source.animateLaunch();
this._source.app.launch(0, -1, true);
this.emit('activate-window', null);
}));
}
for (let i = 0; i < actions.length; i++) {
let action = actions[i];
let item = this._appendMenuItem(appInfo.get_action_name(action));

View File

@ -10,22 +10,27 @@ 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',
'gnect.desktop': 'four-in-a-row.desktop',
'gnibbles.desktop': 'gnome-nibbles.desktop',
'gnibbles.desktop': 'org.gnome.Nibbles.desktop',
'gnobots2.desktop': 'gnome-robots.desktop',
'gnome-boxes.desktop': 'org.gnome.Boxes.desktop',
'gnome-clocks.desktop': 'org.gnome.clocks.desktop',
'gnome-calculator.desktop': 'org.gnome.Calculator.desktop',
'gnome-contacts.desktop': 'org.gnome.Contacts.desktop',
'gnome-documents.desktop': 'org.gnome.Documents.desktop',
'gnome-font-viewer.desktop': 'org.gnome.font-viewer.desktop',
'gnome-nibbles.desktop': 'org.gnome.Nibbles.desktop',
'gnome-photos.desktop': 'org.gnome.Photos.desktop',
'gnome-screenshot.desktop': 'org.gnome.Screenshot.desktop',
'gnome-software.desktop': 'org.gnome.Software.desktop',
'gnome-terminal.desktop': 'org.gnome.Terminal.desktop',
'gnome-weather.desktop': 'org.gnome.Weather.Application.desktop',
'gnomine.desktop': 'gnome-mines.desktop',
'gnotravex.desktop': 'gnome-tetravex.desktop',

View File

@ -0,0 +1,216 @@
const Clutter = imports.gi.Clutter;
const Gio = imports.gi.Gio;
const GLib = imports.gi.GLib;
const Lang = imports.lang;
const Meta = imports.gi.Meta;
const Shell = imports.gi.Shell;
const St = imports.gi.St;
const Main = imports.ui.main;
const ModalDialog = imports.ui.modalDialog;
const AudioDevice = {
HEADPHONES: 1 << 0,
HEADSET: 1 << 1,
MICROPHONE: 1 << 2
};
const AudioDeviceSelectionIface = '<node> \
<interface name="org.gnome.Shell.AudioDeviceSelection"> \
<method name="Open"> \
<arg name="devices" direction="in" type="as" /> \
</method> \
<method name="Close"> \
</method> \
<signal name="DeviceSelected"> \
<arg name="device" type="s" /> \
</signal> \
</interface> \
</node>';
const AudioDeviceSelectionDialog = new Lang.Class({
Name: 'AudioDeviceSelectionDialog',
Extends: ModalDialog.ModalDialog,
_init: function(devices) {
this.parent({ styleClass: 'audio-device-selection-dialog' });
this._deviceItems = {};
this._buildLayout();
if (devices & AudioDevice.HEADPHONES)
this._addDevice(AudioDevice.HEADPHONES);
if (devices & AudioDevice.HEADSET)
this._addDevice(AudioDevice.HEADSET);
if (devices & AudioDevice.MICROPHONE)
this._addDevice(AudioDevice.MICROPHONE);
if (this._selectionBox.get_n_children() < 2)
throw new Error('Too few devices for a selection');
},
destroy: function() {
this.parent();
},
_buildLayout: function(devices) {
let title = new St.Label({ style_class: 'audio-selection-title',
text: _("Select Audio Device"),
x_align: Clutter.ActorAlign.CENTER });
this.contentLayout.style_class = 'audio-selection-content';
this.contentLayout.add(title);
this._selectionBox = new St.BoxLayout({ style_class: 'audio-selection-box' });
this.contentLayout.add(this._selectionBox, { expand: true });
this.addButton({ action: Lang.bind(this, this._openSettings),
label: _("Sound Settings") });
this.addButton({ action: Lang.bind(this, this.close),
label: _("Cancel"),
key: Clutter.Escape });
},
_getDeviceLabel: function(device) {
switch(device) {
case AudioDevice.HEADPHONES:
return _("Headphones");
case AudioDevice.HEADSET:
return _("Headset");
case AudioDevice.MICROPHONE:
return _("Microphone");
default:
return null;
}
},
_getDeviceIcon: function(device) {
switch(device) {
case AudioDevice.HEADPHONES:
return 'audio-headphones-symbolic';
case AudioDevice.HEADSET:
return 'audio-headset-symbolic';
case AudioDevice.MICROPHONE:
return 'audio-input-microphone-symbolic';
default:
return null;
}
},
_addDevice: function(device) {
let box = new St.BoxLayout({ style_class: 'audio-selection-device-box',
vertical: true });
box.connect('notify::height',
function() {
Meta.later_add(Meta.LaterType.BEFORE_REDRAW,
function() {
box.width = box.height;
});
});
let icon = new St.Icon({ style_class: 'audio-selection-device-icon',
icon_name: this._getDeviceIcon(device) });
box.add(icon);
let label = new St.Label({ style_class: 'audio-selection-device-label',
text: this._getDeviceLabel(device),
x_align: Clutter.ActorAlign.CENTER });
box.add(label);
let button = new St.Button({ style_class: 'audio-selection-device',
can_focus: true,
child: box });
this._selectionBox.add(button);
button.connect('clicked', Lang.bind(this,
function() {
this.emit('device-selected', device);
this.close();
Main.overview.hide();
}));
},
_openSettings: function() {
let desktopFile = 'gnome-sound-panel.desktop'
let app = Shell.AppSystem.get_default().lookup_app(desktopFile);
if (!app) {
log('Settings panel for desktop file ' + desktopFile + ' could not be loaded!');
return;
}
this.close();
Main.overview.hide();
app.activate();
}
});
const AudioDeviceSelectionDBus = new Lang.Class({
Name: 'AudioDeviceSelectionDBus',
_init: function() {
this._audioSelectionDialog = null;
this._dbusImpl = Gio.DBusExportedObject.wrapJSObject(AudioDeviceSelectionIface, this);
this._dbusImpl.export(Gio.DBus.session, '/org/gnome/Shell/AudioDeviceSelection');
Gio.DBus.session.own_name('org.gnome.Shell.AudioDeviceSelection', Gio.BusNameOwnerFlags.REPLACE, null, null);
},
_onDialogClosed: function() {
this._audioSelectionDialog = null;
},
_onDeviceSelected: function(dialog, device) {
let connection = this._dbusImpl.get_connection();
let info = this._dbusImpl.get_info();
let deviceName = Object.keys(AudioDevice).filter(
function(dev) {
return AudioDevice[dev] == device;
})[0].toLowerCase();
connection.emit_signal(this._audioSelectionDialog._sender,
this._dbusImpl.get_object_path(),
info ? info.name : null,
'DeviceSelected',
GLib.Variant.new('(s)', [deviceName]));
},
OpenAsync: function(params, invocation) {
if (this._audioSelectionDialog) {
invocation.return_value(null);
return;
}
let [deviceNames] = params;
let devices = 0;
deviceNames.forEach(function(n) {
devices |= AudioDevice[n.toUpperCase()];
});
let dialog;
try {
dialog = new AudioDeviceSelectionDialog(devices);
} catch(e) {
invocation.return_value(null);
return;
}
dialog._sender = invocation.get_sender();
dialog.connect('closed', Lang.bind(this, this._onDialogClosed));
dialog.connect('device-selected',
Lang.bind(this, this._onDeviceSelected));
dialog.open();
this._audioSelectionDialog = dialog;
invocation.return_value(null);
},
CloseAsync: function(params, invocation) {
if (this._audioSelectionDialog &&
this._audioSelectionDialog._sender == invocation.get_sender())
this._audioSelectionDialog.close();
invocation.return_value(null);
}
});

View File

@ -102,6 +102,7 @@ const Lang = imports.lang;
const Meta = imports.gi.Meta;
const Signals = imports.signals;
const LoginManager = imports.misc.loginManager;
const Main = imports.ui.main;
const Params = imports.misc.params;
const Tweener = imports.ui.tweener;
@ -247,6 +248,20 @@ const Background = new Lang.Class({
this._cancellable = new Gio.Cancellable();
this.isLoaded = false;
this._clock = new GnomeDesktop.WallClock();
this._timezoneChangedId = this._clock.connect('notify::timezone',
Lang.bind(this, function() {
if (this._animation)
this._loadAnimation(this._animation.file);
}));
LoginManager.getLoginManager().connect('prepare-for-sleep',
(lm, aboutToSuspend) => {
if (aboutToSuspend)
return;
this._refreshAnimation();
});
this._settingsChangedSignalId = this._settings.connect('changed', Lang.bind(this, function() {
this.emit('changed');
}));
@ -265,16 +280,26 @@ const Background = new Lang.Class({
}
this._fileWatches = null;
if (this._timezoneChangedId != 0)
this._clock.disconnect(this._timezoneChangedId);
this._timezoneChangedId = 0;
if (this._settingsChangedSignalId != 0)
this._settings.disconnect(this._settingsChangedSignalId);
this._settingsChangedSignalId = 0;
},
updateResolution: function() {
if (this._animation) {
this._removeAnimationTimeout();
this._updateAnimation();
}
if (this._animation)
this._refreshAnimation();
},
_refreshAnimation: function() {
if (!this._animation)
return;
this._removeAnimationTimeout();
this._updateAnimation();
},
_setLoaded: function() {
@ -685,6 +710,7 @@ const BackgroundManager = new Lang.Class({
time: FADE_ANIMATION_TIME,
transition: 'easeOutQuad',
onComplete: function() {
oldBackgroundActor.background.run_dispose();
oldBackgroundActor.destroy();
}
});

File diff suppressed because it is too large Load Diff

View File

@ -64,7 +64,8 @@ function startAppForMount(app, mount) {
try {
retval = app.launch(files,
global.create_app_launch_context(0, -1))
global.create_app_launch_context(0, -1),
false)
} catch (e) {
log('Unable to launch the application ' + app.get_name()
+ ': ' + e.toString());
@ -313,6 +314,10 @@ const AutorunSource = new Lang.Class({
getIcon: function() {
return this.mount.get_icon();
},
_createPolicy: function() {
return new MessageTray.NotificationApplicationPolicy('org.gnome.Nautilus');
}
});

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;
@ -796,13 +803,21 @@ const NetworkAgent = new Lang.Class({
path = GLib.build_filenamev([Config.LIBEXECDIR, path]);
}
if (GLib.file_test(path, GLib.FileTest.IS_EXECUTABLE))
if (GLib.file_test(path, GLib.FileTest.IS_EXECUTABLE)) {
this._vpnBinaries[service] = { fileName: path, externalUIMode: externalUIMode, supportsHints: hints };
else
try {
let aliases = keyfile.get_string_list('VPN Connection', 'aliases');
for (let alias of aliases) {
this._vpnBinaries[alias] = { fileName: path, externalUIMode: externalUIMode, supportsHints: hints };
}
} catch(e) { } // ignore errors if key does not exist
} else {
throw new Error('VPN plugin at %s is not executable'.format(path));
}
} 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

@ -12,9 +12,9 @@ const St = imports.gi.St;
const Tpl = imports.gi.TelepathyLogger;
const Tp = imports.gi.TelepathyGLib;
const Calendar = imports.ui.calendar;
const History = imports.misc.history;
const Main = imports.ui.main;
const MessageList = imports.ui.messageList;
const MessageTray = imports.ui.messageTray;
const Params = imports.misc.params;
const PopupMenu = imports.ui.popupMenu;
@ -469,11 +469,17 @@ const ChatSource = new Lang.Class({
destroy: function(reason) {
if (this._client.is_handling_channel(this._channel)) {
this._ackMessages();
// The chat box has been destroyed so it can't
// handle the channel any more.
this._channel.close_async(function(channel, result) {
channel.close_finish(result);
});
} else {
// Don't indicate any unread messages when the notification
// that represents them has been destroyed.
this._pendingMessages = [];
this.countUpdated();
}
// Keep source alive while the channel is open
@ -866,7 +872,7 @@ const ChatNotificationBanner = new Lang.Class({
},
_addMessage: function(message) {
let highlighter = new Calendar.URLHighlighter(message.body, true, true);
let highlighter = new MessageList.URLHighlighter(message.body, true, true);
let body = highlighter.actor;
let styles = message.styles;

View File

@ -259,7 +259,7 @@ const ShowAppsIcon = new Lang.Class({
},
_createIcon: function(size) {
this._iconActor = new St.Icon({ icon_name: 'view-grid-symbolic',
this._iconActor = new St.Icon({ icon_name: 'view-app-grid-symbolic',
icon_size: size,
style_class: 'show-apps-icon',
track_hover: true });

View File

@ -360,7 +360,7 @@ const DateMenuButton = new Lang.Class({
}));
// Fill up the first column
this._messageList = new Calendar.MessageList();
this._messageList = new Calendar.CalendarMessageList();
hbox.add(this._messageList.actor, { expand: true, y_fill: false, y_align: St.Align.START });
// Fill up the second column

View File

@ -79,9 +79,12 @@ const _Draggable = new Lang.Class({
dragActorOpacity: undefined });
this.actor = actor;
if (!params.manualMode)
if (!params.manualMode) {
this.actor.connect('button-press-event',
Lang.bind(this, this._onButtonPress));
this.actor.connect('touch-event',
Lang.bind(this, this._onTouchEvent));
}
this.actor.connect('destroy', Lang.bind(this, function() {
this._actorDestroyed = true;
@ -121,8 +124,50 @@ const _Draggable = new Lang.Class({
return Clutter.EVENT_PROPAGATE;
},
_onTouchEvent: function (actor, event) {
if (event.type() != Clutter.EventType.TOUCH_BEGIN ||
!global.display.is_pointer_emulating_sequence(event.get_event_sequence()))
return Clutter.EVENT_PROPAGATE;
if (Tweener.getTweenCount(actor))
return Clutter.EVENT_PROPAGATE;
this._touchSequence = event.get_event_sequence();
this._buttonDown = true;
this._grabActor();
let [stageX, stageY] = event.get_coords();
this._dragStartX = stageX;
this._dragStartY = stageY;
return Clutter.EVENT_PROPAGATE;
},
_grabDevice: function(actor) {
let manager = Clutter.DeviceManager.get_default();
let pointer = manager.get_core_device(Clutter.InputDeviceType.POINTER_DEVICE);
if (pointer && this._touchSequence)
pointer.sequence_grab(this._touchSequence, actor);
else if (pointer)
pointer.grab (actor);
this._grabbedDevice = pointer;
},
_ungrabDevice: function() {
if (this._touchSequence)
this._grabbedDevice.sequence_ungrab (this._touchSequence);
else
this._grabbedDevice.ungrab();
this._touchSequence = null;
this._grabbedDevice = null;
},
_grabActor: function() {
Clutter.grab_pointer(this.actor);
this._grabDevice(this.actor);
this._onEventId = this.actor.connect('event',
Lang.bind(this, this._onEvent));
},
@ -131,7 +176,7 @@ const _Draggable = new Lang.Class({
if (!this._onEventId)
return;
Clutter.ungrab_pointer();
this._ungrabDevice();
this.actor.disconnect(this._onEventId);
this._onEventId = null;
},
@ -140,13 +185,13 @@ const _Draggable = new Lang.Class({
if (!this._eventsGrabbed) {
this._eventsGrabbed = Main.pushModal(_getEventHandlerActor());
if (this._eventsGrabbed)
Clutter.grab_pointer(_getEventHandlerActor());
this._grabDevice(_getEventHandlerActor());
}
},
_ungrabEvents: function() {
if (this._eventsGrabbed) {
Clutter.ungrab_pointer();
this._ungrabDevice();
Main.popModal(_getEventHandlerActor());
this._eventsGrabbed = false;
}
@ -157,7 +202,9 @@ const _Draggable = new Lang.Class({
// didn't start the drag, to drop the draggable in case the drag was in progress, and
// to complete the drag and ensure that whatever happens to be under the pointer does
// not get triggered if the drag was cancelled with Esc.
if (event.type() == Clutter.EventType.BUTTON_RELEASE) {
if (event.type() == Clutter.EventType.BUTTON_RELEASE ||
(event.type() == Clutter.EventType.TOUCH_END &&
global.display.is_pointer_emulating_sequence(event.get_event_sequence()))) {
this._buttonDown = false;
if (this._dragInProgress) {
return this._dragActorDropped(event);
@ -172,7 +219,9 @@ const _Draggable = new Lang.Class({
}
// We intercept MOTION event to figure out if the drag has started and to draw
// this._dragActor under the pointer when dragging is in progress
} else if (event.type() == Clutter.EventType.MOTION) {
} else if (event.type() == Clutter.EventType.MOTION ||
(event.type() == Clutter.EventType.TOUCH_UPDATE &&
global.display.is_pointer_emulating_sequence(event.get_event_sequence()))) {
if (this._dragInProgress) {
return this._updateDragPosition(event);
} else if (this._dragActor == null) {
@ -214,7 +263,7 @@ const _Draggable = new Lang.Class({
* This function is useful to call if you've specified manualMode
* for the draggable.
*/
startDrag: function (stageX, stageY, time) {
startDrag: function (stageX, stageY, time, sequence) {
currentDraggable = this;
this._dragInProgress = true;
@ -228,6 +277,8 @@ const _Draggable = new Lang.Class({
this.emit('drag-begin', time);
if (this._onEventId)
this._ungrabActor();
this._touchSequence = sequence;
this._grabEvents();
global.screen.set_cursor(Meta.Cursor.DND_IN_DRAG);
@ -338,8 +389,8 @@ const _Draggable = new Lang.Class({
let threshold = Gtk.Settings.get_default().gtk_dnd_drag_threshold;
if ((Math.abs(stageX - this._dragStartX) > threshold ||
Math.abs(stageY - this._dragStartY) > threshold)) {
this.startDrag(stageX, stageY, event.get_time());
this._updateDragPosition(event);
this.startDrag(stageX, stageY, event.get_time(), this._touchSequence);
this._updateDragPosition(event);
}
return true;
@ -520,20 +571,13 @@ const _Draggable = new Lang.Class({
return;
}
this._animationInProgress = true;
// No target, so snap back
Tweener.addTween(this._dragActor,
{ x: snapBackX,
y: snapBackY,
scale_x: snapBackScale,
scale_y: snapBackScale,
opacity: this._dragOrigOpacity,
time: SNAP_BACK_ANIMATION_TIME,
transition: 'easeOutQuad',
onComplete: this._onAnimationComplete,
onCompleteScope: this,
onCompleteParams: [this._dragActor, eventTime]
});
this._animateDragEnd(eventTime,
{ x: snapBackX,
y: snapBackY,
scale_x: snapBackScale,
scale_y: snapBackScale,
time: SNAP_BACK_ANIMATION_TIME,
});
},
_restoreDragActor: function(eventTime) {
@ -545,18 +589,44 @@ const _Draggable = new Lang.Class({
this._dragActor.set_scale(restoreScale, restoreScale);
this._dragActor.opacity = 0;
this._animateDragEnd(eventTime,
{ time: REVERT_ANIMATION_TIME });
},
_animateDragEnd: function (eventTime, params) {
this._animationInProgress = true;
Tweener.addTween(this._dragActor,
{ opacity: this._dragOrigOpacity,
time: REVERT_ANIMATION_TIME,
transition: 'easeOutQuad',
onComplete: this._onAnimationComplete,
onCompleteScope: this,
onCompleteParams: [this._dragActor, eventTime]
});
// finish animation if the actor gets destroyed
// during it
this._dragActorDestroyId =
this._dragActor.connect('destroy',
Lang.bind(this, this._finishAnimation));
params['opacity'] = this._dragOrigOpacity;
params['transition'] = 'easeOutQuad';
params['onComplete'] = this._onAnimationComplete;
params['onCompleteScope'] = this;
params['onCompleteParams'] = [this._dragActor, eventTime];
// start the animation
Tweener.addTween(this._dragActor, params)
},
_finishAnimation : function () {
if (!this._animationInProgress)
return
this._animationInProgress = false;
if (!this._buttonDown)
this._dragComplete();
global.screen.set_cursor(Meta.Cursor.DEFAULT);
},
_onAnimationComplete : function (dragActor, eventTime) {
dragActor.disconnect(this._dragActorDestroyId);
this._dragActorDestroyId = 0;
if (this._dragOrigParent) {
Main.uiGroup.remove_child(this._dragActor);
this._dragOrigParent.add_actor(this._dragActor);
@ -565,12 +635,9 @@ const _Draggable = new Lang.Class({
} else {
dragActor.destroy();
}
global.screen.set_cursor(Meta.Cursor.DEFAULT);
this.emit('drag-end', eventTime, false);
this._animationInProgress = false;
if (!this._buttonDown)
this._dragComplete();
this.emit('drag-end', eventTime, false);
this._finishAnimation();
},
_dragComplete: function() {

View File

@ -1,6 +1,6 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
/*
* Copyright 2010 Red Hat, Inc
* Copyright 2010-2016 Red Hat, Inc
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -114,7 +114,7 @@ const restartDialogContent = {
showOtherSessions: true,
};
const restartInstallDialogContent = {
const restartUpdateDialogContent = {
subject: C_("title", "Restart & Install Updates"),
description: function(seconds) {
@ -132,18 +132,38 @@ const restartInstallDialogContent = {
showOtherSessions: true,
};
const restartUpgradeDialogContent = {
subject: C_("title", "Restart & Install Upgrade"),
upgradeDescription: function(distroName, distroVersion) {
/* Translators: This is the text displayed for system upgrades in the
shut down dialog. First %s gets replaced with the distro name and
second %s with the distro version to upgrade to */
return _("%s %s will be installed after restart. Upgrade installation can take a long time: ensure that you have backed up and that the computer is plugged in.").format(distroName, distroVersion);
},
disableTimer: true,
showBatteryWarning: false,
confirmButtons: [{ signal: 'ConfirmedReboot',
label: C_("button", "Restart &amp; Install") }],
iconName: 'view-refresh-symbolic',
iconStyleClass: 'end-session-dialog-shutdown-icon',
showOtherSessions: true,
};
const DialogType = {
LOGOUT: 0 /* GSM_SHELL_END_SESSION_DIALOG_TYPE_LOGOUT */,
SHUTDOWN: 1 /* GSM_SHELL_END_SESSION_DIALOG_TYPE_SHUTDOWN */,
RESTART: 2 /* GSM_SHELL_END_SESSION_DIALOG_TYPE_RESTART */,
UPDATE_RESTART: 3
UPDATE_RESTART: 3,
UPGRADE_RESTART: 4
};
const DialogContent = {
0 /* DialogType.LOGOUT */: logoutDialogContent,
1 /* DialogType.SHUTDOWN */: shutdownDialogContent,
2 /* DialogType.RESTART */: restartDialogContent,
3 /* DialogType.UPDATE_RESTART */: restartInstallDialogContent
3 /* DialogType.UPDATE_RESTART */: restartUpdateDialogContent,
4 /* DialogType.UPGRADE_RESTART */: restartUpgradeDialogContent
};
const MAX_USERS_IN_SESSION_DIALOG = 5;
@ -163,7 +183,10 @@ const LogindSession = Gio.DBusProxy.makeProxyWrapper(LogindSessionIface);
const PkOfflineIface = '<node> \
<interface name="org.freedesktop.PackageKit.Offline"> \
<property name="UpdatePrepared" type="b" access="read"/> \
<property name="TriggerAction" type="s" access="read"/> \
<property name="UpdateTriggered" type="b" access="read"/> \
<property name="UpgradePrepared" type="b" access="read"/> \
<property name="UpgradeTriggered" type="b" access="read"/> \
<property name="PreparedUpgrade" type="a{sv}" access="read"/> \
<method name="Trigger"> \
<arg type="s" name="action" direction="in"/> \
</method> \
@ -415,11 +438,19 @@ const EndSessionDialog = new Lang.Class({
if (dialogContent.descriptionWithUser)
description = dialogContent.descriptionWithUser(realName, displayTime);
else
description = dialogContent.description(displayTime);
}
}
// Use a different description when we are installing a system upgrade
if (dialogContent.upgradeDescription) {
let name = this._pkOfflineProxy.PreparedUpgrade['name'].deep_unpack();
let version = this._pkOfflineProxy.PreparedUpgrade['version'].deep_unpack();
if (name != null && version != null)
description = dialogContent.upgradeDescription(name, version);
}
// Fall back to regular description
if (!description)
description = dialogContent.description(displayTime);
@ -698,9 +729,12 @@ const EndSessionDialog = new Lang.Class({
this._totalSecondsToStayOpen = totalSecondsToStayOpen;
this._type = type;
if (this._type == DialogType.RESTART &&
this._pkOfflineProxy.TriggerAction == 'reboot')
this._type = DialogType.UPDATE_RESTART;
if (this._type == DialogType.RESTART) {
if (this._pkOfflineProxy.UpdateTriggered)
this._type = DialogType.UPDATE_RESTART;
else if (this._pkOfflineProxy.UpgradeTriggered)
this._type = DialogType.UPGRADE_RESTART;
}
this._applications = [];
this._applicationList.destroy_all_children();
@ -727,19 +761,19 @@ const EndSessionDialog = new Lang.Class({
if (dialogContent.showOtherSessions)
this._loadSessions();
let updateAlreadyTriggered = this._pkOfflineProxy.TriggerAction == 'power-off' || this._pkOfflineProxy.TriggerAction == 'reboot';
let updateTriggered = this._pkOfflineProxy.UpdateTriggered;
let updatePrepared = this._pkOfflineProxy.UpdatePrepared;
let updatesAllowed = this._updatesPermission && this._updatesPermission.allowed;
_setCheckBoxLabel(this._checkBox, dialogContent.checkBoxText);
this._checkBox.actor.visible = (dialogContent.checkBoxText && updatePrepared && updatesAllowed);
this._checkBox.actor.checked = (updatePrepared && updateAlreadyTriggered);
this._checkBox.actor.checked = (updatePrepared && updateTriggered);
// We show the warning either together with the checkbox, or when
// updates have already been triggered, but the user doesn't have
// enough permissions to cancel them.
this._batteryWarning.visible = (dialogContent.showBatteryWarning &&
(this._checkBox.actor.visible || updatePrepared && updateAlreadyTriggered && !updatesAllowed));
(this._checkBox.actor.visible || updatePrepared && updateTriggered && !updatesAllowed));
this._updateButtons();
@ -749,7 +783,9 @@ const EndSessionDialog = new Lang.Class({
return;
}
this._startTimer();
if (!dialogContent.disableTimer)
this._startTimer();
this._sync();
let signalId = this.connect('opened',

View File

@ -61,10 +61,19 @@ function _patchLayoutClass(layoutClass, styleProps) {
};
}
function _makeLoggingFunc(func) {
return function() {
return func([].join.call(arguments, ', '));
};
function _loggingFunc() {
let fields = {'MESSAGE': [].join.call(arguments, ', ')};
let domain = "GNOME Shell";
// If the caller is an extension, add it as metadata
let extension = imports.misc.extensionUtils.getCurrentExtension();
if (extension != null) {
domain = extension.metadata.name;
fields['GNOME_SHELL_EXTENSION_UUID'] = extension.uuid;
fields['GNOME_SHELL_EXTENSION_NAME'] = extension.metadata.name;
}
GLib.log_structured(domain, GLib.LogLevelFlags.LEVEL_MESSAGE, fields);
}
function init() {
@ -72,7 +81,7 @@ function init() {
// browser convention of having that namespace be called 'window'.)
window.global = Shell.Global.get();
window.log = _makeLoggingFunc(window.log);
window.log = _loggingFunc;
window._ = Gettext.gettext;
window.C_ = Gettext.pgettext;

View File

@ -334,7 +334,7 @@ function _sessionUpdated() {
// from allowExtensions in the future
if (Main.sessionMode.allowExtensions) {
if (initted)
onEnabledExtensionsChanged();
enabledExtensions = getEnabledExtensions();
enableAllExtensions();
} else {
disableAllExtensions();

View File

@ -158,10 +158,22 @@ const CandidatePopup = new Lang.Class({
panelService.connect('set-cursor-location',
Lang.bind(this, function(ps, x, y, w, h) {
Main.layoutManager.setDummyCursorGeometry(x, y, w, h);
if (this._boxPointer.actor.visible)
this._boxPointer.setPosition(Main.layoutManager.dummyCursor, 0);
this._setDummyCursorGeometry(x, y, w, h);
}));
try {
panelService.connect('set-cursor-location-relative',
Lang.bind(this, function(ps, x, y, w, h) {
if (!global.display.focus_window)
return;
let window = global.display.focus_window.get_compositor_private();
this._setDummyCursorGeometry(window.x + x, window.y + y, w, h);
}));
} catch(e) {
// Only recent IBus versions have support for this signal
// which is used for wayland clients. In order to work
// with older IBus versions we can silently ignore the
// signal's absence.
}
panelService.connect('update-preedit-text',
Lang.bind(this, function(ps, text, cursorPosition, visible) {
this._preeditText.visible = visible;
@ -246,6 +258,12 @@ const CandidatePopup = new Lang.Class({
}));
},
_setDummyCursorGeometry: function(x, y, w, h) {
Main.layoutManager.setDummyCursorGeometry(x, y, w, h);
if (this._boxPointer.actor.visible)
this._boxPointer.setPosition(Main.layoutManager.dummyCursor, 0);
},
_updateVisibility: function() {
let isVisible = (this._preeditText.visible ||
this._auxText.visible ||

View File

@ -10,6 +10,7 @@ const Meta = imports.gi.Meta;
const Shell = imports.gi.Shell;
const Signals = imports.signals;
const St = imports.gi.St;
const InputSourceManager = imports.ui.status.keyboard;
const BoxPointer = imports.ui.boxpointer;
const Layout = imports.ui.layout;
@ -757,19 +758,48 @@ const ShellWaylandAdapter = new Lang.Class({
Name: 'ShellWaylandAdapter',
Extends: Caribou.XAdapter,
_init: function () {
this.parent();
let deviceManager = Clutter.DeviceManager.get_default();
this._virtualDevice = deviceManager.create_virtual_device(Clutter.InputDeviceType.KEYBOARD_DEVICE);
this._inputSourceManager = InputSourceManager.getInputSourceManager();
this._sourceChangedId = this._inputSourceManager.connect('current-source-changed',
Lang.bind(this, this._onSourceChanged));
this._sourcesModifiedId = this._inputSourceManager.connect ('sources-changed',
Lang.bind(this, this._onSourcesModified));
},
_onSourcesModified: function () {
this.emit('config-changed');
},
_onSourceChanged: function (inputSourceManager, oldSource) {
let source = inputSourceManager.currentSource;
this.emit('group-changed', source.index, source.id, '');
},
vfunc_get_groups: function () {
let inputSources = this._inputSourceManager.inputSources;
let groups = []
let variants = [];
for (let i in inputSources) {
let is = inputSources[i];
groups[is.index] = is.id;
variants[is.index] = '';
}
return [groups, groups.length, variants, variants.length];
},
vfunc_keyval_press: function(keyval) {
let focus = global.stage.get_key_focus();
if (focus instanceof Clutter.Text)
Shell.util_text_insert_keyval(focus, keyval);
else
this.parent(keyval);
this._virtualDevice.notify_keyval(Clutter.get_current_event_time(),
keyval, Clutter.KeyState.PRESSED);
},
vfunc_keyval_release: function(keyval) {
let focus = global.stage.get_key_focus();
if (focus instanceof Clutter.Text)
return; // do nothing
else
this.parent(keyval);
this._virtualDevice.notify_keyval(Clutter.get_current_event_time(),
keyval, Clutter.KeyState.RELEASED);
},
});

View File

@ -220,7 +220,8 @@ const LayoutManager = new Lang.Class({
global.stage.add_child(this.uiGroup);
this.overviewGroup = new St.Widget({ name: 'overviewGroup',
visible: false });
visible: false,
reactive: true });
this.addChrome(this.overviewGroup);
this.screenShieldGroup = new St.Widget({ name: 'screenShieldGroup',
@ -591,7 +592,10 @@ const LayoutManager = new Lang.Class({
this.addChrome(this._coverPane);
if (Meta.is_restart()) {
// On restart, we don't do an animation
// On restart, we don't do an animation. Force an update of the
// regions immediately so that maximized windows restore to the
// right size taking struts into account.
this._updateRegions();
} else if (Main.sessionMode.isGreeter) {
this.panelBox.translation_y = -this.panelBox.height;
} else {
@ -938,6 +942,11 @@ const LayoutManager = new Lang.Class({
if (Main.modalCount > 0)
return GLib.SOURCE_REMOVE;
// Bug workaround - get_transformed_position()/get_transformed_size() don't work after
// a change in stage size until the first pick or paint.
// https://bugzilla.gnome.org/show_bug.cgi?id=761565
global.stage.get_actor_at_pos(Clutter.PickMode.ALL, 0, 0);
let rects = [], struts = [], i;
let isPopupMenuVisible = global.top_window_group.get_children().some(isPopupMetaWindow);
let wantsInputRegion = !isPopupMenuVisible;

View File

@ -50,15 +50,14 @@ const LegacyTray = new Lang.Class({
this._slideLayout.translationX = 0;
this._slideLayout.slideDirection = OverviewControls.SlideDirection.LEFT;
this._slider = new St.Widget({ style_class: 'legacy-tray',
x_expand: true, y_expand: true,
this._slider = new St.Widget({ x_expand: true, y_expand: true,
x_align: Clutter.ActorAlign.START,
y_align: Clutter.ActorAlign.END,
layout_manager: this._slideLayout });
this.actor.add_actor(this._slider);
this._slider.connect('notify::allocation', Lang.bind(this, this._syncBarrier));
this._box = new St.BoxLayout();
this._box = new St.BoxLayout({ style_class: 'legacy-tray' });
this._slider.add_actor(this._box);
this._concealHandle = new St.Button({ style_class: 'legacy-tray-handle',

View File

@ -11,6 +11,8 @@ const Meta = imports.gi.Meta;
const Shell = imports.gi.Shell;
const St = imports.gi.St;
const AccessDialog = imports.ui.accessDialog;
const AudioDeviceSelection = imports.ui.audioDeviceSelection;
const Components = imports.ui.components;
const CtrlAltTab = imports.ui.ctrlAltTab;
const EndSessionDialog = imports.ui.endSessionDialog;
@ -24,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;
@ -59,9 +62,12 @@ let screenShield = null;
let notificationDaemon = null;
let windowAttentionHandler = null;
let ctrlAltTabManager = null;
let padOsdService = null;
let osdWindowManager = null;
let osdMonitorLabeler = null;
let sessionMode = null;
let shellAccessDialogDBusService = null;
let shellAudioSelectionDBusService = null;
let shellDBusService = null;
let shellMountOpDBusService = null;
let screenSaverDBus = null;
@ -78,6 +84,7 @@ let _startDate;
let _defaultCssStylesheet = null;
let _cssStylesheet = null;
let _a11ySettings = null;
let _themeResource = null;
function _sessionUpdated() {
if (sessionMode.isPrimary)
@ -119,6 +126,8 @@ function start() {
_loadDefaultStylesheet);
_initializeUI();
shellAccessDialogDBusService = new AccessDialog.AccessDialogDBus();
shellAudioSelectionDBusService = new AudioDeviceSelection.AudioDeviceSelectionDBus();
shellDBusService = new ShellDBus.GnomeShell();
shellMountOpDBusService = new ShellMountOperation.GnomeShellMountOpHandler();
@ -137,9 +146,7 @@ function _initializeUI() {
Shell.WindowTracker.get_default();
Shell.AppUsage.get_default();
let resource = Gio.Resource.load(global.datadir + '/gnome-shell-theme.gresource');
resource._register();
reloadThemeResource();
_loadDefaultStylesheet();
// Setup the stage hierarchy early
@ -150,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();
@ -189,6 +197,8 @@ function _initializeUI() {
return true;
});
global.display.connect('gl-video-memory-purged', loadTheme);
// Provide the bus object for gnome-session to
// initiate logouts.
EndSessionDialog.init();
@ -290,6 +300,14 @@ function setThemeStylesheet(cssStylesheet) {
_cssStylesheet = cssStylesheet ? Gio.File.new_for_path(cssStylesheet) : null;
}
function reloadThemeResource() {
if (_themeResource)
_themeResource._unregister();
_themeResource = Gio.Resource.load(global.datadir + '/gnome-shell-theme.gresource');
_themeResource._register();
}
/**
* loadTheme:
*

726
js/ui/messageList.js Normal file
View File

@ -0,0 +1,726 @@
const Atk = imports.gi.Atk;
const Clutter = imports.gi.Clutter;
const Gio = imports.gi.Gio;
const GLib = imports.gi.GLib;
const GObject = imports.gi.GObject;
const Lang = imports.lang;
const Main = imports.ui.main;
const MessageTray = imports.ui.messageTray;
const Meta = imports.gi.Meta;
const Pango = imports.gi.Pango;
const Signals = imports.signals;
const St = imports.gi.St;
const Calendar = imports.ui.calendar;
const Tweener = imports.ui.tweener;
const Util = imports.misc.util;
const MESSAGE_ANIMATION_TIME = 0.1;
const DEFAULT_EXPAND_LINES = 6;
function _fixMarkup(text, allowMarkup) {
if (allowMarkup) {
// Support &amp;, &quot;, &apos;, &lt; and &gt;, escape all other
// occurrences of '&'.
let _text = text.replace(/&(?!amp;|quot;|apos;|lt;|gt;)/g, '&amp;');
// Support <b>, <i>, and <u>, escape anything else
// so it displays as raw markup.
_text = _text.replace(/<(?!\/?[biu]>)/g, '&lt;');
try {
Pango.parse_markup(_text, -1, '');
return _text;
} catch (e) {}
}
// !allowMarkup, or invalid markup
return GLib.markup_escape_text(text, -1);
}
const URLHighlighter = new Lang.Class({
Name: 'URLHighlighter',
_init: function(text, lineWrap, allowMarkup) {
if (!text)
text = '';
this.actor = new St.Label({ reactive: true, style_class: 'url-highlighter',
x_expand: true, x_align: Clutter.ActorAlign.START });
this._linkColor = '#ccccff';
this.actor.connect('style-changed', Lang.bind(this, function() {
let [hasColor, color] = this.actor.get_theme_node().lookup_color('link-color', false);
if (hasColor) {
let linkColor = color.to_string().substr(0, 7);
if (linkColor != this._linkColor) {
this._linkColor = linkColor;
this._highlightUrls();
}
}
}));
this.actor.clutter_text.line_wrap = lineWrap;
this.actor.clutter_text.line_wrap_mode = Pango.WrapMode.WORD_CHAR;
this.setMarkup(text, allowMarkup);
this.actor.connect('button-press-event', Lang.bind(this, function(actor, event) {
// Don't try to URL highlight when invisible.
// The MessageTray doesn't actually hide us, so
// we need to check for paint opacities as well.
if (!actor.visible || actor.get_paint_opacity() == 0)
return Clutter.EVENT_PROPAGATE;
// Keep Notification.actor from seeing this and taking
// a pointer grab, which would block our button-release-event
// handler, if an URL is clicked
return this._findUrlAtPos(event) != -1;
}));
this.actor.connect('button-release-event', Lang.bind(this, function (actor, event) {
if (!actor.visible || actor.get_paint_opacity() == 0)
return Clutter.EVENT_PROPAGATE;
let urlId = this._findUrlAtPos(event);
if (urlId != -1) {
let url = this._urls[urlId].url;
if (url.indexOf(':') == -1)
url = 'http://' + url;
Gio.app_info_launch_default_for_uri(url, global.create_app_launch_context(0, -1));
return Clutter.EVENT_STOP;
}
return Clutter.EVENT_PROPAGATE;
}));
this.actor.connect('motion-event', Lang.bind(this, function(actor, event) {
if (!actor.visible || actor.get_paint_opacity() == 0)
return Clutter.EVENT_PROPAGATE;
let urlId = this._findUrlAtPos(event);
if (urlId != -1 && !this._cursorChanged) {
global.screen.set_cursor(Meta.Cursor.POINTING_HAND);
this._cursorChanged = true;
} else if (urlId == -1) {
global.screen.set_cursor(Meta.Cursor.DEFAULT);
this._cursorChanged = false;
}
return Clutter.EVENT_PROPAGATE;
}));
this.actor.connect('leave-event', Lang.bind(this, function() {
if (!this.actor.visible || this.actor.get_paint_opacity() == 0)
return Clutter.EVENT_PROPAGATE;
if (this._cursorChanged) {
this._cursorChanged = false;
global.screen.set_cursor(Meta.Cursor.DEFAULT);
}
return Clutter.EVENT_PROPAGATE;
}));
},
setMarkup: function(text, allowMarkup) {
text = text ? _fixMarkup(text, allowMarkup) : '';
this._text = text;
this.actor.clutter_text.set_markup(text);
/* clutter_text.text contain text without markup */
this._urls = Util.findUrls(this.actor.clutter_text.text);
this._highlightUrls();
},
_highlightUrls: function() {
// text here contain markup
let urls = Util.findUrls(this._text);
let markup = '';
let pos = 0;
for (let i = 0; i < urls.length; i++) {
let url = urls[i];
let str = this._text.substr(pos, url.pos - pos);
markup += str + '<span foreground="' + this._linkColor + '"><u>' + url.url + '</u></span>';
pos = url.pos + url.url.length;
}
markup += this._text.substr(pos);
this.actor.clutter_text.set_markup(markup);
},
_findUrlAtPos: function(event) {
let success;
let [x, y] = event.get_coords();
[success, x, y] = this.actor.transform_stage_point(x, y);
let find_pos = -1;
for (let i = 0; i < this.actor.clutter_text.text.length; i++) {
let [success, px, py, line_height] = this.actor.clutter_text.position_to_coords(i);
if (py > y || py + line_height < y || x < px)
continue;
find_pos = i;
}
if (find_pos != -1) {
for (let i = 0; i < this._urls.length; i++)
if (find_pos >= this._urls[i].pos &&
this._urls[i].pos + this._urls[i].url.length > find_pos)
return i;
}
return -1;
}
});
const ScaleLayout = new Lang.Class({
Name: 'ScaleLayout',
Extends: Clutter.BinLayout,
_connectContainer: function(container) {
if (this._container == container)
return;
if (this._container)
for (let id of this._signals)
this._container.disconnect(id);
this._container = container;
this._signals = [];
if (this._container)
for (let signal of ['notify::scale-x', 'notify::scale-y']) {
let id = this._container.connect(signal, Lang.bind(this,
function() {
this.layout_changed();
}));
this._signals.push(id);
}
},
vfunc_get_preferred_width: function(container, forHeight) {
this._connectContainer(container);
let [min, nat] = this.parent(container, forHeight);
return [Math.floor(min * container.scale_x),
Math.floor(nat * container.scale_x)];
},
vfunc_get_preferred_height: function(container, forWidth) {
this._connectContainer(container);
let [min, nat] = this.parent(container, forWidth);
return [Math.floor(min * container.scale_y),
Math.floor(nat * container.scale_y)];
}
});
const LabelExpanderLayout = new Lang.Class({
Name: 'LabelExpanderLayout',
Extends: Clutter.LayoutManager,
Properties: { 'expansion': GObject.ParamSpec.double('expansion',
'Expansion',
'Expansion of the layout, between 0 (collapsed) ' +
'and 1 (fully expanded',
GObject.ParamFlags.READABLE | GObject.ParamFlags.WRITABLE,
0, 1, 0)},
_init: function(params) {
this._expansion = 0;
this._expandLines = DEFAULT_EXPAND_LINES;
this.parent(params);
},
get expansion() {
return this._expansion;
},
set expansion(v) {
if (v == this._expansion)
return;
this._expansion = v;
this.notify('expansion');
let visibleIndex = this._expansion > 0 ? 1 : 0;
for (let i = 0; this._container && i < this._container.get_n_children(); i++)
this._container.get_child_at_index(i).visible = (i == visibleIndex);
this.layout_changed();
},
set expandLines(v) {
if (v == this._expandLines)
return;
this._expandLines = v;
if (this._expansion > 0)
this.layout_changed();
},
vfunc_set_container: function(container) {
this._container = container;
},
vfunc_get_preferred_width: function(container, forHeight) {
let [min, nat] = [0, 0];
for (let i = 0; i < container.get_n_children(); i++) {
if (i > 1)
break; // we support one unexpanded + one expanded child
let child = container.get_child_at_index(i);
let [childMin, childNat] = child.get_preferred_width(forHeight);
[min, nat] = [Math.max(min, childMin), Math.max(nat, childNat)];
}
return [min, nat];
},
vfunc_get_preferred_height: function(container, forWidth) {
let [min, nat] = [0, 0];
let children = container.get_children();
if (children[0])
[min, nat] = children[0].get_preferred_height(forWidth);
if (children[1]) {
let [min2, nat2] = children[1].get_preferred_height(forWidth);
let [expMin, expNat] = [Math.min(min2, min * this._expandLines),
Math.min(nat2, nat * this._expandLines)];
[min, nat] = [min + this._expansion * (expMin - min),
nat + this._expansion * (expNat - nat)];
}
return [min, nat];
},
vfunc_allocate: function(container, box, flags) {
for (let i = 0; i < container.get_n_children(); i++) {
let child = container.get_child_at_index(i);
if (child.visible)
child.allocate(box, flags);
}
}
});
const Message = new Lang.Class({
Name: 'Message',
_init: function(title, body) {
this.expanded = false;
this.actor = new St.Button({ style_class: 'message',
accessible_role: Atk.Role.NOTIFICATION,
can_focus: true,
x_expand: true, x_fill: true });
this.actor.connect('key-press-event',
Lang.bind(this, this._onKeyPressed));
let vbox = new St.BoxLayout({ vertical: true });
this.actor.set_child(vbox);
let hbox = new St.BoxLayout();
vbox.add_actor(hbox);
this._actionBin = new St.Widget({ layout_manager: new ScaleLayout(),
visible: false });
vbox.add_actor(this._actionBin);
this._iconBin = new St.Bin({ style_class: 'message-icon-bin',
y_expand: true,
visible: false });
hbox.add_actor(this._iconBin);
let contentBox = new St.BoxLayout({ style_class: 'message-content',
vertical: true, x_expand: true });
hbox.add_actor(contentBox);
this._mediaControls = new St.BoxLayout();
hbox.add_actor(this._mediaControls);
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.setTitle(title);
titleBox.add_actor(this.titleLabel);
this._secondaryBin = new St.Bin({ style_class: 'message-secondary-bin' });
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 });
titleBox.add_actor(this._closeButton);
this._bodyStack = new St.Widget({ x_expand: true });
this._bodyStack.layout_manager = new LabelExpanderLayout();
contentBox.add_actor(this._bodyStack);
this.bodyLabel = new URLHighlighter('', false, this._useBodyMarkup);
this.bodyLabel.actor.add_style_class_name('message-body');
this._bodyStack.add_actor(this.bodyLabel.actor);
this.setBody(body);
this._closeButton.connect('clicked', Lang.bind(this, this.close));
this.actor.connect('notify::hover', Lang.bind(this, this._sync));
this.actor.connect('clicked', Lang.bind(this, this._onClicked));
this.actor.connect('destroy', Lang.bind(this, this._onDestroy));
this._sync();
},
close: function() {
this.emit('close');
},
setIcon: function(actor) {
this._iconBin.child = actor;
this._iconBin.visible = (actor != null);
},
setSecondaryActor: function(actor) {
this._secondaryBin.child = actor;
},
setTitle: function(text) {
let title = text ? _fixMarkup(text.replace(/\n/g, ' '), false) : '';
this.titleLabel.clutter_text.set_markup(title);
},
setBody: function(text) {
this._bodyText = text;
this.bodyLabel.setMarkup(text ? text.replace(/\n/g, ' ') : '',
this._useBodyMarkup);
if (this._expandedLabel)
this._expandedLabel.setMarkup(text, this._useBodyMarkup);
},
setUseBodyMarkup: function(enable) {
if (this._useBodyMarkup === enable)
return;
this._useBodyMarkup = enable;
if (this.bodyLabel)
this.setBody(this._bodyText);
},
setActionArea: function(actor) {
if (actor == null) {
if (this._actionBin.get_n_children() > 0)
this._actionBin.get_child_at_index(0).destroy();
return;
}
if (this._actionBin.get_n_children() > 0)
throw new Error('Message already has an action area');
this._actionBin.add_actor(actor);
this._actionBin.visible = this.expanded;
},
addMediaControl: function(iconName, callback) {
let icon = new St.Icon({ icon_name: iconName, icon_size: 16 });
let button = new St.Button({ style_class: 'message-media-control',
child: icon });
button.connect('clicked', callback);
this._mediaControls.add_actor(button);
return button;
},
setExpandedBody: function(actor) {
if (actor == null) {
if (this._bodyStack.get_n_children() > 1)
this._bodyStack.get_child_at_index(1).destroy();
return;
}
if (this._bodyStack.get_n_children() > 1)
throw new Error('Message already has an expanded body actor');
this._bodyStack.insert_child_at_index(actor, 1);
},
setExpandedLines: function(nLines) {
this._bodyStack.layout_manager.expandLines = nLines;
},
expand: function(animate) {
this.expanded = true;
this._actionBin.visible = (this._actionBin.get_n_children() > 0);
if (this._bodyStack.get_n_children() < 2) {
this._expandedLabel = new URLHighlighter(this._bodyText,
true, this._useBodyMarkup);
this.setExpandedBody(this._expandedLabel.actor);
}
if (animate) {
Tweener.addTween(this._bodyStack.layout_manager,
{ expansion: 1,
time: MessageTray.ANIMATION_TIME,
transition: 'easeOutQuad' });
this._actionBin.scale_y = 0;
Tweener.addTween(this._actionBin,
{ scale_y: 1,
time: MessageTray.ANIMATION_TIME,
transition: 'easeOutQuad' });
} else {
this._bodyStack.layout_manager.expansion = 1;
this._actionBin.scale_y = 1;
}
this.emit('expanded');
},
unexpand: function(animate) {
if (animate) {
Tweener.addTween(this._bodyStack.layout_manager,
{ expansion: 0,
time: MessageTray.ANIMATION_TIME,
transition: 'easeOutQuad' });
Tweener.addTween(this._actionBin,
{ scale_y: 0,
time: MessageTray.ANIMATION_TIME,
transition: 'easeOutQuad',
onCompleteScope: this,
onComplete: function() {
this._actionBin.hide();
this.expanded = false;
}});
} else {
this._bodyStack.layout_manager.expansion = 0;
this._actionBin.scale_y = 0;
this.expanded = false;
}
this.emit('unexpanded');
},
canClose: function() {
return this._mediaControls.get_n_children() == 0;
},
_sync: function() {
let hovered = this.actor.hover;
this._closeButton.visible = hovered && this.canClose();
this._secondaryBin.visible = !hovered;
},
_onClicked: function() {
},
_onDestroy: function() {
},
_onKeyPressed: function(a, event) {
let keysym = event.get_key_symbol();
if (keysym == Clutter.KEY_Delete ||
keysym == Clutter.KEY_KP_Delete) {
this.close();
return Clutter.EVENT_STOP;
}
return Clutter.EVENT_PROPAGATE;
}
});
Signals.addSignalMethods(Message.prototype);
const MessageListSection = new Lang.Class({
Name: 'MessageListSection',
_init: function(title) {
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 });
this.actor.add_actor(this._list);
this._list.connect('actor-added', Lang.bind(this, this._sync));
this._list.connect('actor-removed', Lang.bind(this, this._sync));
let id = Main.sessionMode.connect('updated',
Lang.bind(this, this._sync));
this.actor.connect('destroy', function() {
Main.sessionMode.disconnect(id);
});
this._messages = new Map();
this._date = new Date();
this.empty = true;
this._sync();
},
_onTitleClicked: function() {
Main.overview.hide();
Main.panel.closeCalendar();
},
_onKeyFocusIn: function(actor) {
this.emit('key-focus-in', actor);
},
get allowed() {
return true;
},
setDate: function(date) {
if (Calendar.sameDay(date, this._date))
return;
this._date = date;
this._sync();
},
addMessage: function(message, animate) {
this.addMessageAtIndex(message, -1, animate);
},
addMessageAtIndex: function(message, index, animate) {
let obj = {
container: null,
destroyId: 0,
keyFocusId: 0,
closeId: 0
};
let pivot = new Clutter.Point({ x: .5, y: .5 });
let scale = animate ? 0 : 1;
obj.container = new St.Widget({ layout_manager: new ScaleLayout(),
pivot_point: pivot,
scale_x: scale, scale_y: scale });
obj.keyFocusId = message.actor.connect('key-focus-in',
Lang.bind(this, this._onKeyFocusIn));
obj.destroyId = message.actor.connect('destroy',
Lang.bind(this, function() {
this.removeMessage(message, false);
}));
obj.closeId = message.connect('close',
Lang.bind(this, function() {
this.removeMessage(message, true);
}));
this._messages.set(message, obj);
obj.container.add_actor(message.actor);
this._list.insert_child_at_index(obj.container, index);
if (animate)
Tweener.addTween(obj.container, { scale_x: 1,
scale_y: 1,
time: MESSAGE_ANIMATION_TIME,
transition: 'easeOutQuad' });
},
moveMessage: function(message, index, animate) {
let obj = this._messages.get(message);
if (!animate) {
this._list.set_child_at_index(obj.container, index);
return;
}
let onComplete = Lang.bind(this, function() {
this._list.set_child_at_index(obj.container, index);
Tweener.addTween(obj.container, { scale_x: 1,
scale_y: 1,
time: MESSAGE_ANIMATION_TIME,
transition: 'easeOutQuad' });
});
Tweener.addTween(obj.container, { scale_x: 0,
scale_y: 0,
time: MESSAGE_ANIMATION_TIME,
transition: 'easeOutQuad',
onComplete: onComplete });
},
removeMessage: function(message, animate) {
let obj = this._messages.get(message);
message.actor.disconnect(obj.destroyId);
message.actor.disconnect(obj.keyFocusId);
message.disconnect(obj.closeId);
this._messages.delete(message);
if (animate) {
Tweener.addTween(obj.container, { scale_x: 0, scale_y: 0,
time: MESSAGE_ANIMATION_TIME,
transition: 'easeOutQuad',
onComplete: function() {
obj.container.destroy();
global.sync_pointer();
}});
} else {
obj.container.destroy();
global.sync_pointer();
}
},
clear: function() {
let messages = [...this._messages.keys()].filter(function(message) {
return message.canClose();
});
// If there are few messages, letting them all zoom out looks OK
if (messages.length < 2) {
messages.forEach(function(message) {
message.close();
});
} else {
// Otherwise we slide them out one by one, and then zoom them
// out "off-screen" in the end to smoothly shrink the parent
let delay = MESSAGE_ANIMATION_TIME / Math.max(messages.length, 5);
for (let i = 0; i < messages.length; i++) {
let message = messages[i];
let obj = this._messages.get(message);
Tweener.addTween(obj.container,
{ anchor_x: this._list.width,
opacity: 0,
time: MESSAGE_ANIMATION_TIME,
delay: i * delay,
transition: 'easeOutQuad',
onComplete: function() {
message.close();
}});
}
}
},
_canClear: function() {
for (let message of this._messages.keys())
if (message.canClose())
return true;
return false;
},
_shouldShow: function() {
return !this.empty;
},
_sync: function() {
let empty = this._list.get_n_children() == 0;
let changed = this.empty !== empty;
this.empty = empty;
if (changed)
this.emit('empty-changed');
this._closeButton.visible = this._canClear();
this.actor.visible = this.allowed && this._shouldShow();
}
});
Signals.addSignalMethods(MessageListSection.prototype);

View File

@ -259,7 +259,7 @@ const ModalDialog = new Lang.Class({
if (this.state == State.OPENED || this.state == State.OPENING)
return true;
if (!this.pushModal({ timestamp: timestamp }))
if (!this.pushModal(timestamp))
return false;
this._fadeOpen(onPrimary);
@ -318,8 +318,11 @@ const ModalDialog = new Lang.Class({
pushModal: function (timestamp) {
if (this._hasModal)
return true;
if (!Main.pushModal(this._group, { timestamp: timestamp,
actionMode: this._actionMode }))
let params = { actionMode: this._actionMode };
if (timestamp)
params['timestamp'] = timestamp;
if (!Main.pushModal(this._group, params))
return false;
this._hasModal = true;

270
js/ui/mpris.js Normal file
View File

@ -0,0 +1,270 @@
const Gio = imports.gi.Gio;
const Lang = imports.lang;
const Signals = imports.signals;
const Shell = imports.gi.Shell;
const St = imports.gi.St;
const Calendar = imports.ui.calendar;
const Main = imports.ui.main;
const MessageList = imports.ui.messageList;
const DBusIface = '<node> \
<interface name="org.freedesktop.DBus"> \
<method name="ListNames"> \
<arg type="as" direction="out" name="names" /> \
</method> \
<signal name="NameOwnerChanged"> \
<arg type="s" direction="out" name="name" /> \
<arg type="s" direction="out" name="oldOwner" /> \
<arg type="s" direction="out" name="newOwner" /> \
</signal> \
</interface> \
</node>';
const DBusProxy = Gio.DBusProxy.makeProxyWrapper(DBusIface);
const MprisIface = '<node> \
<interface name="org.mpris.MediaPlayer2"> \
<method name="Raise" /> \
<property name="CanRaise" type="b" access="read" /> \
<property name="DesktopEntry" type="s" access="read" /> \
</interface> \
</node>';
const MprisProxy = Gio.DBusProxy.makeProxyWrapper(MprisIface);
const MprisPlayerIface = '<node> \
<interface name="org.mpris.MediaPlayer2.Player"> \
<method name="PlayPause" /> \
<method name="Next" /> \
<method name="Previous" /> \
<property name="CanPlay" type="b" access="read" /> \
<property name="Metadata" type="a{sv}" access="read" /> \
<property name="PlaybackStatus" type="s" access="read" /> \
</interface> \
</node>';
const MprisPlayerProxy = Gio.DBusProxy.makeProxyWrapper(MprisPlayerIface);
const MPRIS_PLAYER_PREFIX = 'org.mpris.MediaPlayer2.';
const MediaMessage = new Lang.Class({
Name: 'MediaMessage',
Extends: MessageList.Message,
_init: function(player) {
this._player = player;
this.parent('', '');
this._icon = new St.Icon({ style_class: 'media-message-cover-icon' });
this.setIcon(this._icon);
this.addMediaControl('media-skip-backward-symbolic',
Lang.bind(this, function() {
this._player.previous();
}));
this._playPauseButton = this.addMediaControl(null,
Lang.bind(this, function() {
this._player.playPause();
}));
this.addMediaControl('media-skip-forward-symbolic',
Lang.bind(this, function() {
this._player.next();
}));
this._player.connect('changed', Lang.bind(this, this._update));
this._player.connect('closed', Lang.bind(this, this.close));
this._update();
},
_onClicked: function() {
this._player.raise();
Main.panel.closeCalendar();
},
_update: function() {
this.setTitle(this._player.trackArtists.join(', '));
this.setBody(this._player.trackTitle);
if (this._player.trackCoverUrl) {
let file = Gio.File.new_for_uri(this._player.trackCoverUrl);
this._icon.gicon = new Gio.FileIcon({ file: file });
this._icon.remove_style_class_name('fallback');
} else {
this._icon.icon_name = 'audio-x-generic-symbolic';
this._icon.add_style_class_name('fallback');
}
let isPlaying = this._player.status == 'Playing';
let iconName = isPlaying ? 'media-playback-pause-symbolic'
: 'media-playback-start-symbolic';
this._playPauseButton.child.icon_name = iconName;
}
});
const MprisPlayer = new Lang.Class({
Name: 'MprisPlayer',
_init: function(busName) {
this._mprisProxy = new MprisProxy(Gio.DBus.session, busName,
'/org/mpris/MediaPlayer2',
Lang.bind(this, this._onMprisProxyReady));
this._playerProxy = new MprisPlayerProxy(Gio.DBus.session, busName,
'/org/mpris/MediaPlayer2',
Lang.bind(this, this._onPlayerProxyReady));
this._visible = false;
this._trackArtists = [];
this._trackTitle = '';
this._trackCoverUrl = '';
},
get status() {
return this._playerProxy.PlaybackStatus;
},
get trackArtists() {
return this._trackArtists;
},
get trackTitle() {
return this._trackTitle;
},
get trackCoverUrl() {
return this._trackCoverUrl;
},
playPause: function() {
this._playerProxy.PlayPauseRemote();
},
next: function() {
this._playerProxy.NextRemote();
},
previous: function() {
this._playerProxy.PreviousRemote();
},
raise: function() {
// The remote Raise() method may run into focus stealing prevention,
// so prefer activating the app via .desktop file if possible
let app = null;
if (this._mprisProxy.DesktopEntry) {
let desktopId = this._mprisProxy.DesktopEntry + '.desktop';
app = Shell.AppSystem.get_default().lookup_app(desktopId);
}
if (app)
app.activate();
else if (this._mprisProxy.CanRaise)
this._mprisProxy.RaiseRemote();
},
_close: function() {
this._mprisProxy.disconnect(this._ownerNotifyId);
this._mprisProxy = null;
this._playerProxy.disconnect(this._propsChangedId);
this._playerProxy = null;
this.emit('closed');
},
_onMprisProxyReady: function() {
this._ownerNotifyId = this._mprisProxy.connect('notify::g-name-owner',
Lang.bind(this, function() {
if (!this._mprisProxy.g_name_owner)
this._close();
}));
},
_onPlayerProxyReady: function() {
this._propsChangedId = this._playerProxy.connect('g-properties-changed',
Lang.bind(this, this._updateState));
this._updateState();
},
_updateState: function() {
let metadata = {};
for (let prop in this._playerProxy.Metadata)
metadata[prop] = this._playerProxy.Metadata[prop].deep_unpack();
this._trackArtists = metadata['xesam:artist'] || [_("Unknown artist")];
this._trackTitle = metadata['xesam:title'] || _("Unknown title");
this._trackCoverUrl = metadata['mpris:artUrl'] || '';
this.emit('changed');
let visible = this._playerProxy.CanPlay;
if (this._visible != visible) {
this._visible = visible;
if (visible)
this.emit('show');
else
this._close();
}
}
});
Signals.addSignalMethods(MprisPlayer.prototype);
const MediaSection = new Lang.Class({
Name: 'MediaSection',
Extends: MessageList.MessageListSection,
_init: function() {
this.parent(_("Media"));
this._players = new Map();
this._proxy = new DBusProxy(Gio.DBus.session,
'org.freedesktop.DBus',
'/org/freedesktop/DBus',
Lang.bind(this, this._onProxyReady));
},
_shouldShow: function() {
return !this.empty && Calendar.isToday(this._date);
},
_addPlayer: function(busName) {
if (this._players.get(busName))
return;
let player = new MprisPlayer(busName);
player.connect('closed', Lang.bind(this,
function() {
this._players.delete(busName);
}));
player.connect('show', Lang.bind(this,
function() {
let message = new MediaMessage(player);
this.addMessage(message, true);
}));
this._players.set(busName, player);
},
_onProxyReady: function() {
this._proxy.ListNamesRemote(Lang.bind(this,
function([names]) {
names.forEach(Lang.bind(this,
function(name) {
if (!name.startsWith(MPRIS_PLAYER_PREFIX))
return;
this._addPlayer(name);
}));
}));
this._proxy.connectSignal('NameOwnerChanged',
Lang.bind(this, this._onNameOwnerChanged));
},
_onNameOwnerChanged: function(proxy, sender, [name, oldOwner, newOwner]) {
if (!name.startsWith(MPRIS_PLAYER_PREFIX))
return;
if (newOwner && !oldOwner)
this._addPlayer(name);
}
});

View File

@ -690,6 +690,7 @@ const GtkNotificationDaemonAppSource = new Lang.Class({
throw new InvalidAppError();
this._notifications = {};
this._notificationPending = false;
this.parent(this._app.get_name());
},
@ -702,27 +703,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 +745,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) {

View File

@ -22,11 +22,13 @@ const LevelBar = new Lang.Class({
this._level = 0;
this.actor = new St.Bin({ style_class: 'level',
x_fill: true, y_fill: true });
this._bar = new St.DrawingArea();
this._bar.connect('repaint', Lang.bind(this, this._repaint));
x_align: St.Align.START,
y_fill: true });
this._bar = new St.Widget({ style_class: 'level-bar' });
this.actor.set_child(this._bar);
this.actor.connect('notify::width', () => { this.level = this.level; });
},
get level() {
@ -34,39 +36,44 @@ const LevelBar = new Lang.Class({
},
set level(value) {
let newValue = Math.max(0, Math.min(value, 100));
if (newValue == this._level)
return;
this._level = newValue;
this._bar.queue_repaint();
this._level = Math.max(0, Math.min(value, 100));
let alloc = this.actor.get_allocation_box();
let newWidth = Math.round((alloc.x2 - alloc.x1) * this._level / 100);
if (newWidth != this._bar.width)
this._bar.width = newWidth;
}
});
const OsdWindowConstraint = new Lang.Class({
Name: 'OsdWindowConstraint',
Extends: Clutter.Constraint,
_init: function(props) {
this._minSize = 0;
this.parent(props);
},
_repaint: function() {
let cr = this._bar.get_context();
set minSize(v) {
this._minSize = v;
if (this.actor)
this.actor.queue_relayout();
},
let node = this.actor.get_theme_node();
let radius = node.get_border_radius(0); // assume same radius for all corners
Clutter.cairo_set_source_color(cr, node.get_foreground_color());
vfunc_update_allocation: function(actor, actorBox) {
// Clutter will adjust the allocation for margins,
// so add it to our minimum size
let minSize = this._minSize + actor.margin_top + actor.margin_bottom;
let [width, height] = actorBox.get_size();
let [w, h] = this._bar.get_surface_size();
w *= (this._level / 100.);
// Enforce a ratio of 1
let size = Math.ceil(Math.max(minSize, height));
actorBox.set_size(size, size);
if (w == 0)
return;
cr.moveTo(radius, 0);
if (w >= radius)
cr.arc(w - radius, radius, radius, 1.5 * Math.PI, 2. * Math.PI);
else
cr.lineTo(w, 0);
if (w >= radius)
cr.arc(w - radius, h - radius, radius, 0, 0.5 * Math.PI);
else
cr.lineTo(w, h);
cr.arc(radius, h - radius, radius, 0.5 * Math.PI, Math.PI);
cr.arc(radius, radius, radius, Math.PI, 1.5 * Math.PI);
cr.fill();
cr.$dispose();
// Recenter
let [x, y] = actorBox.get_origin();
actorBox.set_origin(Math.ceil(x + width / 2 - size / 2),
Math.ceil(y + height / 2 - size / 2));
}
});
@ -74,7 +81,6 @@ const OsdWindow = new Lang.Class({
Name: 'OsdWindow',
_init: function(monitorIndex) {
this._popupSize = 0;
this.actor = new St.Widget({ x_expand: true,
y_expand: true,
x_align: Clutter.ActorAlign.CENTER,
@ -84,19 +90,12 @@ const OsdWindow = new Lang.Class({
let constraint = new Layout.MonitorConstraint({ index: monitorIndex });
this.actor.add_constraint(constraint);
this._boxConstraint = new OsdWindowConstraint();
this._box = new St.BoxLayout({ style_class: 'osd-window',
vertical: true });
this._box.add_constraint(this._boxConstraint);
this.actor.add_actor(this._box);
this._box.connect('style-changed', Lang.bind(this, this._onStyleChanged));
this._box.connect('notify::height', Lang.bind(this,
function() {
Meta.later_add(Meta.LaterType.BEFORE_REDRAW, Lang.bind(this,
function() {
this._box.width = this._box.height;
}));
}));
this._icon = new St.Icon();
this._box.add(this._icon, { expand: true });
@ -110,8 +109,11 @@ const OsdWindow = new Lang.Class({
this._reset();
Main.layoutManager.connect('monitors-changed',
Lang.bind(this, this._monitorsChanged));
this._monitorsChanged();
Lang.bind(this, this._relayout));
let themeContext = St.ThemeContext.get_for_stage(global.stage);
themeContext.connect('notify::scale-factor',
Lang.bind(this, this._relayout));
this._relayout();
Main.uiGroup.add_child(this.actor);
},
@ -189,7 +191,7 @@ const OsdWindow = new Lang.Class({
this.setLevel(null);
},
_monitorsChanged: function() {
_relayout: function() {
/* assume 110x110 on a 640x480 display and scale from there */
let monitor = Main.layoutManager.monitors[this._monitorIndex];
if (!monitor)
@ -198,30 +200,12 @@ const OsdWindow = new Lang.Class({
let scalew = monitor.width / 640.0;
let scaleh = monitor.height / 480.0;
let scale = Math.min(scalew, scaleh);
this._popupSize = 110 * Math.max(1, scale);
let popupSize = 110 * Math.max(1, scale);
let scaleFactor = St.ThemeContext.get_for_stage(global.stage).scale_factor;
this._icon.icon_size = this._popupSize / (2 * scaleFactor);
this._icon.icon_size = popupSize / (2 * scaleFactor);
this._box.translation_y = monitor.height / 4;
this._box.style_changed();
},
_onStyleChanged: function() {
let themeNode = this._box.get_theme_node();
let horizontalPadding = themeNode.get_horizontal_padding();
let verticalPadding = themeNode.get_vertical_padding();
let topBorder = themeNode.get_border_width(St.Side.TOP);
let bottomBorder = themeNode.get_border_width(St.Side.BOTTOM);
let leftBorder = themeNode.get_border_width(St.Side.LEFT);
let rightBorder = themeNode.get_border_width(St.Side.RIGHT);
let minWidth = this._popupSize - verticalPadding - leftBorder - rightBorder;
let minHeight = this._popupSize - horizontalPadding - topBorder - bottomBorder;
// minWidth/minHeight here are in real pixels,
// but the theme takes measures in unscaled dimensions
let scaleFactor = St.ThemeContext.get_for_stage(global.stage).scale_factor;
this._box.style = 'min-height: %dpx;'.format(Math.max(minWidth, minHeight) / scaleFactor);
this._boxConstraint.minSize = popupSize;
}
});

View File

@ -107,18 +107,12 @@ const Overview = new Lang.Class({
this._overviewCreated = true;
let layout = new Clutter.BinLayout();
this._stack = new Clutter.Actor({ layout_manager: layout });
this._stack.add_constraint(new LayoutManager.MonitorConstraint({ primary: true }));
/* Translators: This is the main view to select
activities. See also note for "Activities" string. */
this._overview = new St.BoxLayout({ name: 'overview',
accessible_name: _("Overview"),
reactive: true,
vertical: true,
x_expand: true,
y_expand: true });
vertical: true });
this._overview.add_constraint(new LayoutManager.MonitorConstraint({ primary: true }));
this._overview._delegate = this;
// The main Background actors are inside global.window_group which are
@ -126,7 +120,7 @@ const Overview = new Lang.Class({
// one. Instances of this class share a single CoglTexture behind the
// scenes which allows us to show the background with different
// rendering options without duplicating the texture data.
this._backgroundGroup = new Meta.BackgroundGroup();
this._backgroundGroup = new Meta.BackgroundGroup({ reactive: true });
Main.layoutManager.overviewGroup.add_child(this._backgroundGroup);
this._bgManagers = [];
@ -149,8 +143,7 @@ const Overview = new Lang.Class({
Main.layoutManager.overviewGroup.add_child(this._coverPane);
this._coverPane.connect('event', Lang.bind(this, function (actor, event) { return Clutter.EVENT_STOP; }));
this._stack.add_actor(this._overview);
Main.layoutManager.overviewGroup.add_child(this._stack);
Main.layoutManager.overviewGroup.add_child(this._overview);
this._coverPane.hide();
@ -159,6 +152,9 @@ const Overview = new Lang.Class({
dragMotion: Lang.bind(this, this._onDragMotion)
};
Main.layoutManager.overviewGroup.connect('scroll-event',
Lang.bind(this, this._onScrollEvent));
Main.xdndHandler.connect('drag-begin', Lang.bind(this, this._onDragBegin));
Main.xdndHandler.connect('drag-end', Lang.bind(this, this._onDragEnd));
@ -255,7 +251,6 @@ const Overview = new Lang.Class({
// Add our same-line elements after the search entry
this._overview.add(this._controls.actor, { y_fill: true, expand: true });
this._controls.actor.connect('scroll-event', Lang.bind(this, this._onScrollEvent));
// TODO - recalculate everything when desktop size changes
this.dashIconSize = this._dash.iconSize;
@ -372,7 +367,7 @@ const Overview = new Lang.Class({
if (this.isDummy)
return;
this._overview.add_action(action);
this._backgroundGroup.add_action(action);
},
_getDesktopClone: function() {
@ -552,8 +547,8 @@ const Overview = new Lang.Class({
Meta.disable_unredirect_for_screen(global.screen);
this.viewSelector.show();
this._stack.opacity = 0;
Tweener.addTween(this._stack,
this._overview.opacity = 0;
Tweener.addTween(this._overview,
{ opacity: 255,
transition: 'easeOutQuad',
time: ANIMATION_TIME,
@ -618,7 +613,7 @@ const Overview = new Lang.Class({
this.viewSelector.animateFromOverview();
// Make other elements fade out.
Tweener.addTween(this._stack,
Tweener.addTween(this._overview,
{ opacity: 0,
transition: 'easeOutQuad',
time: ANIMATION_TIME,

View File

@ -421,7 +421,6 @@ const ControlsManager = new Lang.Class({
let layout = new ControlsLayout();
this.actor = new St.Widget({ layout_manager: layout,
reactive: true,
x_expand: true, y_expand: true,
clip_to_allocation: true });
this._group = new St.BoxLayout({ name: 'overview-group',

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

@ -0,0 +1,761 @@
// -*- 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 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._settings = settings;
this._imagePath = imagePath;
this._editionMode = editionMode;
this._capturedEventId = global.stage.connect('captured-event', Lang.bind(this, this._onCapturedEvent));
let deviceManager = Clutter.DeviceManager.get_default();
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();
}));
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._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());
this.actor.add_actor(this._titleLabel);
this._tipLabel = new St.Label({ x_align: Clutter.ActorAlign.CENTER });
this.actor.add_actor(this._tipLabel);
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);
},
_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;
}
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();
if (this._deviceRemovedId != 0) {
let deviceManager = Clutter.DeviceManager.get_default();
deviceManager.disconnect(this._deviceRemovedId);
this._deviceRemovedId = 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

@ -459,7 +459,8 @@ const ActivitiesButton = new Lang.Class({
if (event.type() == Clutter.EventType.TOUCH_END ||
event.type() == Clutter.EventType.BUTTON_RELEASE)
Main.overview.toggle();
if (Main.overview.shouldToggleByCornerOrButton())
Main.overview.toggle();
return Clutter.EVENT_PROPAGATE;
},
@ -467,7 +468,8 @@ const ActivitiesButton = new Lang.Class({
_onKeyRelease: function(actor, event) {
let symbol = event.get_key_symbol();
if (symbol == Clutter.KEY_Return || symbol == Clutter.KEY_space) {
Main.overview.toggle();
if (Main.overview.shouldToggleByCornerOrButton())
Main.overview.toggle();
}
return Clutter.EVENT_PROPAGATE;
},

View File

@ -783,6 +783,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();
@ -1146,6 +1156,16 @@ const PopupSubMenuMenuItem = new Lang.Class({
this.actor.remove_style_pseudo_class ('active');
this._setOpenState(!this._getOpenState());
return Clutter.EVENT_PROPAGATE;
},
_onTouchEvent: function(actor, event) {
if (event.type() == Clutter.EventType.TOUCH_END) {
// Since we override the parent, we need to manage what the parent does
// with the active style class
this.actor.remove_style_pseudo_class ('active');
this._setOpenState(!this._getOpenState());
}
return Clutter.EVENT_PROPAGATE;
}
});

View File

@ -297,7 +297,7 @@ const RemoteSearchProvider = new Lang.Class({
// the provider is not compatible with the new version of the interface, launch
// the app itself but warn so we can catch the error in logs
log('Search provider ' + this.appInfo.get_id() + ' does not implement LaunchSearch');
this.appInfo.launch([], global.create_app_launch_context(0, -1));
this.appInfo.launch([], global.create_app_launch_context(0, -1), false);
}
});

View File

@ -61,6 +61,7 @@ const RunDialog = new Lang.Class({
// rt is short for "reload theme"
'rt': Lang.bind(this, function() {
Main.reloadThemeResource();
Main.loadTheme();
})
};
@ -273,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

@ -349,7 +349,6 @@ const Arrow = new Lang.Class({
_init: function(params) {
this.parent(params);
this.x_fill = this.y_fill = true;
this.set_offscreen_redirect(Clutter.OffscreenRedirect.ALWAYS);
this._drawingArea = new St.DrawingArea();
this._drawingArea.connect('repaint', Lang.bind(this, this._drawArrow));
@ -377,6 +376,22 @@ const Arrow = new Lang.Class({
cr.$dispose();
},
vfunc_get_paint_volume: function(volume) {
if (!this.parent(volume))
return false;
if (!this._shadow)
return true;
let shadow_box = new Clutter.ActorBox();
this._shadow.get_box(this._drawingArea.get_allocation_box(), shadow_box);
volume.set_width(Math.max(shadow_box.x2 - shadow_box.x1, volume.get_width()));
volume.set_height(Math.max(shadow_box.y2 - shadow_box.y1, volume.get_height()));
return true;
},
vfunc_style_changed: function() {
let node = this.get_theme_node();
this._shadow = node.get_shadow('-arrow-shadow');
@ -384,6 +399,8 @@ const Arrow = new Lang.Class({
this._shadowHelper = St.ShadowHelper.new(this._shadow);
else
this._shadowHelper = null;
this.parent();
},
vfunc_paint: function() {
@ -559,6 +576,9 @@ const ScreenShield = new Lang.Class({
if (prevIsActive != this._isActive)
this.emit('active-changed');
if (this._loginSession)
this._loginSession.SetLockedHintRemote(active);
this._syncInhibitor();
},
@ -645,7 +665,10 @@ const ScreenShield = new Lang.Class({
let isEnter = (symbol == Clutter.KEY_Return ||
symbol == Clutter.KEY_KP_Enter ||
symbol == Clutter.KEY_ISO_Enter);
if (!isEnter && !(GLib.unichar_isprint(unichar) || symbol == Clutter.KEY_Escape))
let isEscape = (symbol == Clutter.KEY_Escape);
let isLiftChar = (GLib.unichar_isprint(unichar) &&
(this._isLocked || !GLib.unichar_isgraph(unichar)));
if (!isEnter && !isEscape && !isLiftChar)
return Clutter.EVENT_PROPAGATE;
if (this._isLocked &&
@ -708,7 +731,7 @@ const ScreenShield = new Lang.Class({
let unitaryDelay = ARROW_ANIMATION_TIME / (arrows.length + 1);
let maxOpacity = 255 * ARROW_ANIMATION_PEAK_OPACITY;
for (let i = 0; i < arrows.length; i++) {
arrows.opacity = 0;
arrows[i].opacity = 0;
Tweener.addTween(arrows[i],
{ opacity: 0,
delay: unitaryDelay * (N_ARROWS - (i + 1)),
@ -827,6 +850,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)

View File

@ -137,6 +137,10 @@ const Slider = new Lang.Class({
this._motionId = this.actor.connect('motion-event', Lang.bind(this, this._motionEvent));
}
// We need to emit 'drag-begin' before moving the handle to make
// sure that no 'value-changed' signal is emitted before this one.
this.emit('drag-begin');
let absX, absY;
[absX, absY] = event.get_coords();
this._moveHandle(absX, absY);
@ -224,6 +228,7 @@ const Slider = new Lang.Class({
let delta = key == Clutter.KEY_Right ? 0.1 : -0.1;
this._value = Math.max(0, Math.min(this._value + delta, 1));
this.actor.queue_repaint();
this.emit('drag-begin');
this.emit('value-changed', this._value);
this.emit('drag-end');
return Clutter.EVENT_STOP;

View File

@ -1,11 +1,8 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
const Clutter = imports.gi.Clutter;
const GLib = imports.gi.GLib;
const Gio = imports.gi.Gio;
const GnomeBluetooth = imports.gi.GnomeBluetooth;
const Lang = imports.lang;
const St = imports.gi.St;
const Main = imports.ui.main;
const PanelMenu = imports.ui.panelMenu;
@ -23,6 +20,8 @@ const RfkillManagerInterface = '<node> \
const RfkillManagerProxy = Gio.DBusProxy.makeProxyWrapper(RfkillManagerInterface);
const HAD_BLUETOOTH_DEVICES_SETUP = 'had-bluetooth-devices-setup';
const Indicator = new Lang.Class({
Name: 'BTIndicator',
Extends: PanelMenu.SystemIndicator,
@ -32,6 +31,7 @@ const Indicator = new Lang.Class({
this._indicator = this._addIndicator();
this._indicator.icon_name = 'bluetooth-active-symbolic';
this._hadSetupDevices = global.settings.get_boolean(HAD_BLUETOOTH_DEVICES_SETUP);
this._proxy = new RfkillManagerProxy(Gio.DBus.session, BUS_NAME, OBJECT_PATH,
Lang.bind(this, function(proxy, error) {
@ -44,13 +44,15 @@ const Indicator = new Lang.Class({
}));
this._proxy.connect('g-properties-changed', Lang.bind(this, this._sync));
// The Bluetooth menu only appears when Bluetooth is in use,
// so just statically build it with a "Turn Off" menu item.
this._item = new PopupMenu.PopupSubMenuMenuItem('', true);
this._item = new PopupMenu.PopupSubMenuMenuItem(_("Bluetooth"), true);
this._item.icon.icon_name = 'bluetooth-active-symbolic';
this._item.menu.addAction(_("Turn Off"), Lang.bind(this, function() {
this._proxy.BluetoothAirplaneMode = true;
this._toggleItem = new PopupMenu.PopupMenuItem('');
this._toggleItem.connect('activate', Lang.bind(this, function() {
this._proxy.BluetoothAirplaneMode = !this._proxy.BluetoothAirplaneMode;
}));
this._item.menu.addMenuItem(this._toggleItem);
this._item.menu.addSettingsAction(_("Bluetooth Settings"), 'gnome-bluetooth-panel.desktop');
this.menu.addMenuItem(this._item);
@ -68,42 +70,75 @@ const Indicator = new Lang.Class({
while (ret) {
let isDefault = this._model.get_value(iter,
GnomeBluetooth.Column.DEFAULT);
if (isDefault)
let isPowered = this._model.get_value(iter,
GnomeBluetooth.Column.POWERED);
if (isDefault && isPowered)
return iter;
ret = this._model.iter_next(iter);
}
return null;
},
_getNConnectedDevices: function() {
// nDevices is the number of devices setup for the current default
// adapter if one exists and is powered. If unpowered or unavailable,
// nDevice is "1" if it had setup devices associated to it the last
// time it was seen, and "-1" if not.
//
// nConnectedDevices is the number of devices connected to the default
// adapter if one exists and is powered, or -1 if it's not available.
_getNDevices: function() {
let adapter = this._getDefaultAdapter();
if (!adapter)
return 0;
return [ this._hadSetupDevices ? 1 : -1, -1 ];
let nConnectedDevices = 0;
let nDevices = 0;
let [ret, iter] = this._model.iter_children(adapter);
while (ret) {
let isConnected = this._model.get_value(iter,
GnomeBluetooth.Column.CONNECTED);
if (isConnected)
nConnectedDevices++;
let isPaired = this._model.get_value(iter,
GnomeBluetooth.Column.PAIRED);
let isTrusted = this._model.get_value(iter,
GnomeBluetooth.Column.TRUSTED);
if (isPaired || isTrusted)
nDevices++;
ret = this._model.iter_next(iter);
}
return nDevices;
if (this._hadSetupDevices != (nDevices > 0)) {
this._hadSetupDevices = !this._hadSetupDevices;
global.settings.set_boolean(HAD_BLUETOOTH_DEVICES_SETUP, this._hadSetupDevices);
}
return [ nDevices, nConnectedDevices];
},
_sync: function() {
let nDevices = this._getNConnectedDevices();
let [ nDevices, nConnectedDevices ] = this._getNDevices();
let sensitive = !Main.sessionMode.isLocked && !Main.sessionMode.isGreeter;
this.menu.setSensitive(sensitive);
this._indicator.visible = nDevices > 0;
this._item.actor.visible = this._proxy.BluetoothHasAirplaneMode && !this._proxy.BluetoothAirplaneMode;
this._indicator.visible = nConnectedDevices > 0;
// Remember if there were setup devices and show the menu
// if we've seen setup devices and we're not hard blocked
if (nDevices > 0)
/* Translators: this is the number of connected bluetooth devices */
this._item.label.text = ngettext("%d Connected", "%d Connected", nDevices).format(nDevices);
this._item.actor.visible = !this._proxy.BluetoothHardwareAirplaneMode;
else
this._item.label.text = _("Not In Use");
this._item.actor.visible = this._proxy.BluetoothHasAirplaneMode && !this._proxy.BluetoothAirplaneMode;
if (nConnectedDevices > 0)
/* Translators: this is the number of connected bluetooth devices */
this._item.label.text = ngettext("%d Connected", "%d Connected", nConnectedDevices).format(nConnectedDevices);
else if (nConnectedDevices == -1)
this._item.label.text = _("Off");
else
this._item.label.text = _("On");
this._toggleItem.label.text = this._proxy.BluetoothAirplaneMode ? _("Turn On") : _("Turn Off");
},
});

View File

@ -61,8 +61,8 @@ const InputSource = new Lang.Class({
this.emit('changed');
},
activate: function() {
this.emit('activate');
activate: function(interactive) {
this.emit('activate', !!interactive);
},
_getXkbId: function() {
@ -109,7 +109,7 @@ const InputSourcePopup = new Lang.Class({
_finish : function() {
this.parent();
this._items[this._selectedIndex].activate();
this._items[this._selectedIndex].activate(true);
},
});
@ -159,6 +159,14 @@ const InputSourceSettings = new Lang.Class({
return [];
},
get mruSources() {
return [];
},
set mruSources(sourcesList) {
// do nothing
},
get keyboardOptions() {
return [];
},
@ -251,6 +259,7 @@ const InputSourceSessionSettings = new Lang.Class({
_DESKTOP_INPUT_SOURCES_SCHEMA: 'org.gnome.desktop.input-sources',
_KEY_INPUT_SOURCES: 'sources',
_KEY_MRU_SOURCES: 'mru-sources',
_KEY_KEYBOARD_OPTIONS: 'xkb-options',
_KEY_PER_WINDOW: 'per-window',
@ -261,9 +270,9 @@ const InputSourceSessionSettings = new Lang.Class({
this._settings.connect('changed::' + this._KEY_PER_WINDOW, Lang.bind(this, this._emitPerWindowChanged));
},
get inputSources() {
_getSourcesList: function(key) {
let sourcesList = [];
let sources = this._settings.get_value(this._KEY_INPUT_SOURCES);
let sources = this._settings.get_value(key);
let nSources = sources.n_children();
for (let i = 0; i < nSources; i++) {
@ -273,6 +282,19 @@ const InputSourceSessionSettings = new Lang.Class({
return sourcesList;
},
get inputSources() {
return this._getSourcesList(this._KEY_INPUT_SOURCES);
},
get mruSources() {
return this._getSourcesList(this._KEY_MRU_SOURCES);
},
set mruSources(sourcesList) {
let sources = GLib.Variant.new('a(ss)', sourcesList);
this._settings.set_value(this._KEY_MRU_SOURCES, sources);
},
get keyboardOptions() {
return this._settings.get_strv(this._KEY_KEYBOARD_OPTIONS);
},
@ -372,7 +394,7 @@ const InputSourceManager = new Lang.Class({
while (!(is = this._inputSources[nextIndex]))
nextIndex += 1;
is.activate();
is.activate(true);
return true;
},
@ -400,6 +422,25 @@ const InputSourceManager = new Lang.Class({
this._keyboardManager.reapply();
},
_updateMruSettings: function() {
// If IBus is not ready we don't have a full picture of all
// the available sources, so don't update the setting
if (!this._ibusReady)
return;
// If IBus is temporarily disabled, don't update the setting
if (this._disableIBus)
return;
let sourcesList = [];
for (let i = 0; i < this._mruSources.length; ++i) {
let source = this._mruSources[i];
sourcesList.push([source.type, source.id]);
}
this._settings.mruSources = sourcesList;
},
_currentInputSourceChanged: function(newSource) {
let oldSource;
[oldSource, this._currentSource] = [this._currentSource, newSource];
@ -416,7 +457,7 @@ const InputSourceManager = new Lang.Class({
this._changePerWindowSource();
},
_activateInputSource: function(is) {
_activateInputSource: function(is, interactive) {
KeyboardManager.holdKeyboard();
this._keyboardManager.apply(is.xkbId);
@ -434,6 +475,54 @@ const InputSourceManager = new Lang.Class({
this._ibusManager.setEngine(engine, KeyboardManager.releaseKeyboard);
this._currentInputSourceChanged(is);
if (interactive)
this._updateMruSettings();
},
_updateMruSources: function() {
let sourcesList = [];
for (let i in this._inputSources)
sourcesList.push(this._inputSources[i]);
this._keyboardManager.setUserLayouts(sourcesList.map(function(x) { return x.xkbId; }));
if (!this._disableIBus && this._mruSourcesBackup) {
this._mruSources = this._mruSourcesBackup;
this._mruSourcesBackup = null;
}
// Initialize from settings when we have no MRU sources list
if (this._mruSources.length == 0) {
let mruSettings = this._settings.mruSources;
for (let i = 0; i < mruSettings.length; i++) {
let mruSettingSource = mruSettings[i];
let mruSource = null;
for (let j = 0; j < sourcesList.length; j++) {
let source = sourcesList[j];
if (source.type == mruSettingSource.type &&
source.id == mruSettingSource.id) {
mruSource = source;
break;
}
}
if (mruSource)
this._mruSources.push(mruSource);
}
}
let mruSources = [];
for (let i = 0; i < this._mruSources.length; i++) {
for (let j = 0; j < sourcesList.length; j++)
if (this._mruSources[i].type == sourcesList[j].type &&
this._mruSources[i].id == sourcesList[j].id) {
mruSources = mruSources.concat(sourcesList.splice(j, 1));
break;
}
}
this._mruSources = mruSources.concat(sourcesList);
},
_inputSourcesChanged: function() {
@ -510,30 +599,10 @@ const InputSourceManager = new Lang.Class({
this.emit('sources-changed');
let sourcesList = [];
for (let i in this._inputSources)
sourcesList.push(this._inputSources[i]);
this._keyboardManager.setUserLayouts(sourcesList.map(function(x) { return x.xkbId; }));
if (!this._disableIBus && this._mruSourcesBackup) {
this._mruSources = this._mruSourcesBackup;
this._mruSourcesBackup = null;
}
let mruSources = [];
for (let i = 0; i < this._mruSources.length; i++) {
for (let j = 0; j < sourcesList.length; j++)
if (this._mruSources[i].type == sourcesList[j].type &&
this._mruSources[i].id == sourcesList[j].id) {
mruSources = mruSources.concat(sourcesList.splice(j, 1));
break;
}
}
this._mruSources = mruSources.concat(sourcesList);
this._updateMruSources();
if (this._mruSources.length > 0)
this._mruSources[0].activate();
this._mruSources[0].activate(false);
// All ibus engines are preloaded here to reduce the launching time
// when users switch the input sources.
@ -642,7 +711,7 @@ const InputSourceManager = new Lang.Class({
}
if (window._currentSource)
window._currentSource.activate();
window._currentSource.activate(false);
},
_sourcesPerWindowChanged: function() {
@ -763,7 +832,10 @@ const InputSourceIndicator = new Lang.Class({
let is = this._inputSourceManager.inputSources[i];
let menuItem = new LayoutMenuItem(is.displayName, is.shortName);
menuItem.connect('activate', Lang.bind(is, is.activate));
menuItem.connect('activate', function() {
is.activate(true);
});
let indicatorLabel = new St.Label({ text: is.shortName,
visible: false });

View File

@ -1,5 +1,6 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
const Clutter = imports.gi.Clutter;
const GLib = imports.gi.GLib;
const Gio = imports.gi.Gio;
const Lang = imports.lang;
@ -7,12 +8,18 @@ const Lang = imports.lang;
const Main = imports.ui.main;
const PanelMenu = imports.ui.panelMenu;
const PopupMenu = imports.ui.popupMenu;
const ModalDialog = imports.ui.modalDialog;
const Shell = imports.gi.Shell;
const Signals = imports.signals;
const St = imports.gi.St;
const LOCATION_SCHEMA = 'org.gnome.system.location';
const MAX_ACCURACY_LEVEL = 'max-accuracy-level';
const ENABLED = 'enabled';
const APP_PERMISSIONS_TABLE = 'gnome';
const APP_PERMISSIONS_ID = 'geolocation';
const GeoclueAccuracyLevel = {
NONE: 0,
COUNTRY: 1,
@ -22,6 +29,15 @@ const GeoclueAccuracyLevel = {
EXACT: 8
};
function accuracyLevelToString(accuracyLevel) {
for (let key in GeoclueAccuracyLevel) {
if (GeoclueAccuracyLevel[key] == accuracyLevel)
return key;
}
return 'NONE';
}
var GeoclueIface = '<node> \
<interface name="org.freedesktop.GeoClue2.Manager"> \
<property name="InUse" type="b" access="read"/> \
@ -46,6 +62,26 @@ 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,
@ -83,64 +119,66 @@ const Indicator = new Lang.Class({
this._onSessionUpdated();
this._onMaxAccuracyLevelChanged();
this._connectToGeoclue();
this._connectToPermissionStore();
},
get MaxAccuracyLevel() {
return this._getMaxAccuracyLevel();
},
// We (and geoclue) have currently no way to reliably identifying apps so
// for now, lets just authorize all apps as long as they provide a valid
// desktop ID. We also ensure they don't get more accuracy than global max.
AuthorizeApp: function(desktop_id, reqAccuracyLevel) {
var appSystem = Shell.AppSystem.get_default();
var app = appSystem.lookup_app(desktop_id + ".desktop");
if (app == null) {
return [false, 0];
}
AuthorizeAppAsync: function(params, invocation) {
let [desktopId, reqAccuracyLevel] = params;
let allowedAccuracyLevel = clamp(reqAccuracyLevel, 0, this._getMaxAccuracyLevel());
return [true, allowedAccuracyLevel];
let authorizer = new AppAuthorizer(desktopId,
reqAccuracyLevel,
this._permStoreProxy,
this._getMaxAccuracyLevel());
authorizer.authorize(Lang.bind(this, function(accuracyLevel) {
let ret = (accuracyLevel != GeoclueAccuracyLevel.NONE);
invocation.return_value(GLib.Variant.new('(bu)',
[ret, accuracyLevel]));
}));
},
_syncIndicator: function() {
if (this._proxy == null) {
if (this._managerProxy == null) {
this._indicator.visible = false;
this._item.actor.visible = false;
return;
}
this._indicator.visible = this._proxy.InUse;
this._indicator.visible = this._managerProxy.InUse;
this._item.actor.visible = this._indicator.visible;
this._updateMenuLabels();
},
_connectToGeoclue: function() {
if (this._proxy != null || this._connecting)
if (this._managerProxy != null || this._connecting)
return false;
this._connecting = true;
new GeoclueManager(Gio.DBus.system,
'org.freedesktop.GeoClue2',
'/org/freedesktop/GeoClue2/Manager',
Lang.bind(this, this._onProxyReady));
Lang.bind(this, this._onManagerProxyReady));
return true;
},
_onProxyReady: function(proxy, error) {
_onManagerProxyReady: function(proxy, error) {
if (error != null) {
log(error.message);
this._connecting = false;
return;
}
this._proxy = proxy;
this._propertiesChangedId = this._proxy.connect('g-properties-changed',
this._managerProxy = proxy;
this._propertiesChangedId = this._managerProxy.connect('g-properties-changed',
Lang.bind(this, this._onGeocluePropsChanged));
this._syncIndicator();
this._proxy.AddAgentRemote('gnome-shell', Lang.bind(this, this._onAgentRegistered));
this._managerProxy.AddAgentRemote('gnome-shell', Lang.bind(this, this._onAgentRegistered));
},
_onAgentRegistered: function(result, error) {
@ -153,10 +191,10 @@ const Indicator = new Lang.Class({
_onGeoclueVanished: function() {
if (this._propertiesChangedId) {
this._proxy.disconnect(this._propertiesChangedId);
this._managerProxy.disconnect(this._propertiesChangedId);
this._propertiesChangedId = 0;
}
this._proxy = null;
this._managerProxy = null;
this._syncIndicator();
},
@ -211,9 +249,206 @@ const Indicator = new Lang.Class({
let unpacked = properties.deep_unpack();
if ("InUse" in unpacked)
this._syncIndicator();
}
},
_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));
},
_onPermStoreProxyReady: function(proxy, error) {
if (error != null) {
log(error.message);
return;
}
this._permStoreProxy = proxy;
},
});
function clamp(value, min, max) {
return Math.max(min, Math.min(max, value));
}
const AppAuthorizer = new Lang.Class({
Name: 'LocationAppAuthorizer',
_init: function(desktopId,
reqAccuracyLevel,
permStoreProxy,
maxAccuracyLevel) {
this.desktopId = desktopId;
this.reqAccuracyLevel = reqAccuracyLevel;
this._permStoreProxy = permStoreProxy;
this._maxAccuracyLevel = maxAccuracyLevel;
this._accuracyLevel = GeoclueAccuracyLevel.NONE;
},
authorize: function(onAuthDone) {
this._onAuthDone = onAuthDone;
let appSystem = Shell.AppSystem.get_default();
this._app = appSystem.lookup_app(this.desktopId + ".desktop");
if (this._app == null || this._permStoreProxy == null) {
this._completeAuth();
return;
}
this._permStoreProxy.LookupRemote(APP_PERMISSIONS_TABLE,
APP_PERMISSIONS_ID,
Lang.bind(this,
this._onPermLookupDone));
},
_onPermLookupDone: function(result, error) {
if (error != null) {
if (error.domain == Gio.DBusError) {
// Likely no xdg-app installed, just authorize the app
this._accuracyLevel = this.reqAccuracyLevel;
this._permStoreProxy = null;
this._completeAuth();
} else {
// Currently xdg-app throws an error if we lookup for
// unknown ID (which would be the case first time this code
// runs) so we continue with user authorization as normal
// and ID is added to the store if user says "yes".
log(error.message);
this._permissions = {};
this._userAuthorizeApp();
}
return;
}
[this._permissions] = result;
let permission = this._permissions[this.desktopId];
if (permission == null) {
this._userAuthorizeApp();
} else {
let [levelStr] = permission || ['NONE'];
this._accuracyLevel = GeoclueAccuracyLevel[levelStr] ||
GeoclueAccuracyLevel.NONE;
this._completeAuth();
}
},
_userAuthorizeApp: function() {
let name = this._app.get_name();
let appInfo = this._app.get_app_info();
let reason = appInfo.get_string("X-Geoclue-Reason");
this._showAppAuthDialog(name, reason);
},
_showAppAuthDialog: function(name, reason) {
this._dialog = new GeolocationDialog(name,
reason,
this.reqAccuracyLevel);
let responseId = this._dialog.connect('response', Lang.bind(this,
function(dialog, level) {
this._dialog.disconnect(responseId);
this._accuracyLevel = level;
this._completeAuth();
}));
this._dialog.open();
},
_completeAuth: function() {
if (this._accuracyLevel != GeoclueAccuracyLevel.NONE) {
this._accuracyLevel = clamp(this._accuracyLevel,
0,
this._maxAccuracyLevel);
}
this._saveToPermissionStore();
this._onAuthDone(this._accuracyLevel);
},
_saveToPermissionStore: function() {
if (this._permStoreProxy == null)
return;
let levelStr = accuracyLevelToString(this._accuracyLevel);
let dateStr = Math.round(Date.now() / 1000).toString();
this._permissions[this.desktopId] = [levelStr, dateStr];
let data = GLib.Variant.new('av', {});
this._permStoreProxy.SetRemote(APP_PERMISSIONS_TABLE,
true,
APP_PERMISSIONS_ID,
this._permissions,
data,
function (result, error) {
if (error != null)
log(error.message);
});
},
});
const GeolocationDialog = new Lang.Class({
Name: 'GeolocationDialog',
Extends: ModalDialog.ModalDialog,
_init: function(name, reason, reqAccuracyLevel) {
this.parent({ styleClass: 'geolocation-dialog' });
this.reqAccuracyLevel = reqAccuracyLevel;
let mainContentBox = new St.BoxLayout({ style_class: 'geolocation-dialog-main-layout' });
this.contentLayout.add_actor(mainContentBox);
let icon = new St.Icon({ style_class: 'geolocation-dialog-icon',
icon_name: 'find-location-symbolic',
y_align: Clutter.ActorAlign.START });
mainContentBox.add_actor(icon);
let messageBox = new St.BoxLayout({ style_class: 'geolocation-dialog-content',
vertical: true });
mainContentBox.add_actor(messageBox);
this._title = new St.Label({ style_class: 'geolocation-dialog-title headline' });
messageBox.add_actor(this._title);
this._reason = new St.Label({ style_class: 'geolocation-dialog-reason' });
messageBox.add_actor(this._reason);
this._privacyNote = new St.Label();
messageBox.add_actor(this._privacyNote);
let button = this.addButton({ label: _("Deny Access"),
action: Lang.bind(this, this._onDenyClicked),
key: Clutter.KEY_Escape });
this.addButton({ label: _("Grant Access"),
action: Lang.bind(this, this._onGrantClicked) });
this.setInitialKeyFocus(button);
/* Translators: %s is an application name */
this._title.text = _("Give %s access to your location?").format(name);
this._privacyNote.text = _("Location access can be changed at any time from the privacy settings.");
if (reason)
this._reason.text = reason;
this._reason.visible = (reason != null);
},
_onGrantClicked: function() {
this.emit('response', this.reqAccuracyLevel);
this.close();
},
_onDenyClicked: function() {
this.emit('response', GeoclueAccuracyLevel.NONE);
this.close();
}
});
Signals.addSignalMethods(GeolocationDialog.prototype);

View File

@ -5,6 +5,7 @@ const GObject = imports.gi.GObject;
const Gio = imports.gi.Gio;
const Gtk = imports.gi.Gtk;
const Lang = imports.lang;
const Mainloop = imports.mainloop;
const NetworkManager = imports.gi.NetworkManager;
const NMClient = imports.gi.NMClient;
const NMGtk = imports.gi.NMGtk;
@ -39,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'];
@ -621,7 +624,7 @@ const NMDeviceBluetooth = new Lang.Class({
_init: function(client, device, settings) {
this.parent(client, device, settings);
this.item.menu.addMenuItem(createSettingsAction(_("Mobile Broadband Settings"), device));
this.item.menu.addMenuItem(createSettingsAction(_("Bluetooth Settings"), device));
},
_getDescription: function() {
@ -629,7 +632,7 @@ const NMDeviceBluetooth = new Lang.Class({
},
getConnectLabel: function() {
return _("Use as Internet connection");
return _("Connect to Internet");
},
getIndicatorIcon: function() {
@ -752,10 +755,9 @@ const NMWirelessDialog = new Lang.Class({
this._updateSensitivity();
this._syncView();
if (accessPoints.length == 0) {
/* If there are no visible access points, request a scan */
this._device.request_scan_simple(null);
}
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();
},
destroy: function() {
@ -780,9 +782,19 @@ const NMWirelessDialog = new Lang.Class({
this._airplaneModeChangedId = 0;
}
if (this._scanTimeoutId) {
Mainloop.source_remove(this._scanTimeoutId);
this._scanTimeoutId = 0;
}
this.parent();
},
_onScanTimeout: function() {
this._device.request_scan_simple(null);
return GLib.SOURCE_CONTINUE;
},
_activeApChanged: function() {
if (this._activeNetwork)
this._activeNetwork.item.setActive(false);
@ -1491,7 +1503,7 @@ const NMVPNSection = new Lang.Class({
if (nItems > 1) {
let appSys = Shell.AppSystem.get_default();
let app = appSys.lookup_app('gnome-network-panel.desktop');
app.launch(0, -1);
app.launch(0, -1, false);
} else {
let connection = this._connections[0];
Util.spawnApp(['gnome-control-center', 'network', 'show-device',
@ -1552,6 +1564,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,
@ -1595,15 +1674,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;
@ -1620,9 +1690,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));
@ -1632,6 +1706,8 @@ const NMApplet = new Lang.Class({
this._readConnections();
this._readDevices();
this._syncNMState();
this._syncMainConnection();
this._syncVPNConnections();
this._client.connect('notify::manager-running', Lang.bind(this, this._syncNMState));
this._client.connect('notify::networking-enabled', Lang.bind(this, this._syncNMState));
@ -2008,13 +2084,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

@ -1,6 +1,8 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
const Gio = imports.gi.Gio;
const Clutter = imports.gi.Clutter;
const St = imports.gi.St;
const Lang = imports.lang;
const UPower = imports.gi.UPowerGlib;
@ -25,6 +27,8 @@ const DisplayDeviceInterface = '<node> \
const PowerManagerProxy = Gio.DBusProxy.makeProxyWrapper(DisplayDeviceInterface);
const SHOW_BATTERY_PERCENTAGE = 'show-battery-percentage';
const Indicator = new Lang.Class({
Name: 'PowerIndicator',
Extends: PanelMenu.SystemIndicator,
@ -32,7 +36,15 @@ const Indicator = new Lang.Class({
_init: function() {
this.parent();
this._desktopSettings = new Gio.Settings({ schema_id: 'org.gnome.desktop.interface' });
this._desktopSettings.connect('changed::' + SHOW_BATTERY_PERCENTAGE,
Lang.bind(this, this._sync));
this._indicator = this._addIndicator();
this._percentageLabel = new St.Label({ y_expand: true,
y_align: Clutter.ActorAlign.CENTER });
this.indicators.add(this._percentageLabel, { expand: true, y_fill: true });
this.indicators.add_style_class_name('power-status');
this._proxy = new PowerManagerProxy(Gio.DBus.system, BUS_NAME, OBJECT_PATH,
Lang.bind(this, function(proxy, error) {
@ -83,12 +95,12 @@ const Indicator = new Lang.Class({
if (this._proxy.State == UPower.DeviceState.DISCHARGING) {
// Translators: this is <hours>:<minutes> Remaining (<percentage>)
return _("%d\u2236%02d Remaining (%d%%)").format(hours, minutes, this._proxy.Percentage);
return _("%d\u2236%02d Remaining (%d\u2009%%)").format(hours, minutes, this._proxy.Percentage);
}
if (this._proxy.State == UPower.DeviceState.CHARGING) {
// Translators: this is <hours>:<minutes> Until Full (<percentage>)
return _("%d\u2236%02d Until Full (%d%%)").format(hours, minutes, this._proxy.Percentage);
return _("%d\u2236%02d Until Full (%d\u2009%%)").format(hours, minutes, this._proxy.Percentage);
}
return null;
@ -99,10 +111,12 @@ const Indicator = new Lang.Class({
let visible = this._proxy.IsPresent;
if (visible) {
this._item.actor.show();
this._percentageLabel.visible = this._desktopSettings.get_boolean(SHOW_BATTERY_PERCENTAGE);
} else {
// If there's no battery, then we use the power icon.
this._item.actor.hide();
this._indicator.icon_name = 'system-shutdown-symbolic';
this._percentageLabel.hide();
return;
}
@ -111,6 +125,14 @@ const Indicator = new Lang.Class({
this._indicator.icon_name = icon;
this._item.icon.icon_name = icon;
// The icon label
let label
if (this._proxy.State == UPower.DeviceState.FULLY_CHARGED)
label = _("%d\u2009%%").format(100);
else
label = _("%d\u2009%%").format(this._proxy.Percentage);
this._percentageLabel.clutter_text.set_markup('<span size="smaller">' + label + '</span>');
// The status label
this._item.label.text = this._getStatus();
},

View File

@ -6,6 +6,7 @@ const Gdm = imports.gi.Gdm;
const Gio = imports.gi.Gio;
const GLib = imports.gi.GLib;
const Lang = imports.lang;
const Meta = imports.gi.Meta;
const Shell = imports.gi.Shell;
const St = imports.gi.St;
@ -110,6 +111,7 @@ const Indicator = new Lang.Class({
this._session = new GnomeSession.SessionManager();
this._loginManager = LoginManager.getLoginManager();
this._monitorManager = Meta.MonitorManager.get();
this._haveShutdown = true;
this._haveSuspend = true;
@ -155,6 +157,8 @@ const Indicator = new Lang.Class({
this._orientationSettings.connect('changed::orientation-lock',
Lang.bind(this, this._updateOrientationLock));
Main.layoutManager.connect('monitors-changed',
Lang.bind(this, this._updateOrientationLock));
Gio.DBus.system.watch_name(SENSOR_BUS_NAME,
Gio.BusNameWatcherFlags.NONE,
Lang.bind(this, this._sensorProxyAppeared),
@ -264,7 +268,8 @@ const Indicator = new Lang.Class({
_updateOrientationLock: function() {
if (this._sensorProxy)
this._orientationLockAction.visible = this._sensorProxy.HasAccelerometer;
this._orientationLockAction.visible = this._sensorProxy.HasAccelerometer &&
this._monitorManager.get_is_builtin_display_on();
else
this._orientationLockAction.visible = false;
@ -301,14 +306,17 @@ const Indicator = new Lang.Class({
},
_updateHaveSuspend: function() {
this._loginManager.canSuspend(Lang.bind(this, function(result) {
this._haveSuspend = result;
this._updateSuspend();
}));
this._loginManager.canSuspend(Lang.bind(this,
function(canSuspend, needsAuth) {
this._haveSuspend = canSuspend;
this._suspendNeedsAuth = needsAuth;
this._updateSuspend();
}));
},
_updateSuspend: function() {
let disabled = Main.sessionMode.isLocked ||
let disabled = (Main.sessionMode.isLocked &&
this._suspendNeedsAuth) ||
(Main.sessionMode.isGreeter &&
this._loginScreenSettings.get_boolean(DISABLE_RESTART_KEY));
this._suspendAction.visible = this._haveSuspend && !disabled;

View File

@ -23,6 +23,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,6 +52,28 @@ 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,
@ -156,7 +179,7 @@ const ViewSelector = new Lang.Class({
this.appDisplay = new AppDisplay.AppDisplay();
this._appsPage = this._addPage(this.appDisplay.actor,
_("Applications"), 'view-grid-symbolic');
_("Applications"), 'view-app-grid-symbolic');
this._searchResults = new Search.SearchResults();
this._searchPage = this._addPage(this._searchResults.actor,
@ -230,11 +253,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,7 @@ 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 SHELL_KEYBINDINGS_SCHEMA = 'org.gnome.shell.keybindings';
const MINIMIZE_WINDOW_ANIMATION_TIME = 0.2;
@ -510,7 +511,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) {
@ -683,6 +684,8 @@ const WindowManager = new Lang.Class({
this._dimmedWindows = [];
this._skippedActors = [];
this._allowedKeybindings = {};
this._isWorkspacePrepended = false;
@ -703,6 +706,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));
@ -850,22 +854,34 @@ const WindowManager = new Lang.Class({
Lang.bind(this, this._showWorkspaceSwitcher));
this.setCustomKeybindingHandler('switch-applications',
Shell.ActionMode.NORMAL,
Lang.bind(this, this._startAppSwitcher));
Lang.bind(this, this._startSwitcher));
this.setCustomKeybindingHandler('switch-group',
Shell.ActionMode.NORMAL,
Lang.bind(this, this._startAppSwitcher));
Lang.bind(this, this._startSwitcher));
this.setCustomKeybindingHandler('switch-applications-backward',
Shell.ActionMode.NORMAL,
Lang.bind(this, this._startAppSwitcher));
Lang.bind(this, this._startSwitcher));
this.setCustomKeybindingHandler('switch-group-backward',
Shell.ActionMode.NORMAL,
Lang.bind(this, this._startAppSwitcher));
Lang.bind(this, this._startSwitcher));
this.setCustomKeybindingHandler('switch-windows',
Shell.ActionMode.NORMAL,
Lang.bind(this, this._startWindowSwitcher));
Lang.bind(this, this._startSwitcher));
this.setCustomKeybindingHandler('switch-windows-backward',
Shell.ActionMode.NORMAL,
Lang.bind(this, this._startWindowSwitcher));
Lang.bind(this, this._startSwitcher));
this.setCustomKeybindingHandler('cycle-windows',
Shell.ActionMode.NORMAL,
Lang.bind(this, this._startSwitcher));
this.setCustomKeybindingHandler('cycle-windows-backward',
Shell.ActionMode.NORMAL,
Lang.bind(this, this._startSwitcher));
this.setCustomKeybindingHandler('cycle-group',
Shell.ActionMode.NORMAL,
Lang.bind(this, this._startSwitcher));
this.setCustomKeybindingHandler('cycle-group-backward',
Shell.ActionMode.NORMAL,
Lang.bind(this, this._startSwitcher));
this.setCustomKeybindingHandler('switch-panels',
Shell.ActionMode.NORMAL |
Shell.ActionMode.OVERVIEW |
@ -903,6 +919,7 @@ 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));
Main.overview.connect('showing', Lang.bind(this, function() {
for (let i = 0; i < this._dimmedWindows.length; i++)
@ -932,7 +949,13 @@ const WindowManager = new Lang.Class({
gesture = new AppSwitchAction();
gesture.connect('activated', Lang.bind(this, this._switchApp));
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) {
@ -1023,6 +1046,10 @@ const WindowManager = new Lang.Class({
this._workspaceTracker.keepWorkspaceAlive(workspace, duration);
},
skipNextEffect: function(actor) {
this._skippedActors.push(actor);
},
setCustomKeybindingHandler: function(name, modes, handler) {
if (Meta.keybindings_set_custom_handler(name, handler))
this.allowKeybinding(name, modes);
@ -1049,6 +1076,9 @@ const WindowManager = new Lang.Class({
},
_shouldAnimateActor: function(actor, types) {
if (this._removeEffect(this._skippedActors, actor))
return false;
if (!this._shouldAnimate())
return false;
@ -1226,35 +1256,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) {
actor.translation_x = oldFrameRect.x;
actor.translation_y = oldFrameRect.y;
this._fullscreenAnimation(shellwm, actor, oldFrameRect);
},
_unfullscreenWindow: function(shellwm, actor, oldFrameRect, oldBufferRect) {
let targetRect = actor.meta_window.get_frame_rect();
actor.translation_x = -targetRect.x;
actor.translation_y = -targetRect.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);
@ -1262,10 +1274,26 @@ 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;
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,
@ -1278,9 +1306,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;
@ -1294,7 +1330,10 @@ const WindowManager = new Lang.Class({
transition: 'easeOutQuad',
onComplete: this._sizeChangeWindowDone,
onCompleteScope: this,
onCompleteParams: [shellwm, actor]
onCompleteParams: [shellwm, actor],
onOverwrite: this._sizeChangeWindowOverwritten,
onOverwriteScope: this,
onOverwriteParams: [shellwm, actor]
});
// Now unfreeze actor updates, to get it to the new size.
@ -1303,6 +1342,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);
@ -1310,21 +1358,25 @@ 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))
this._clearFullscreenInfo(actor);
},
_hasAttachedDialogs: function(window, ignoreWindow) {
var count = 0;
window.foreach_transient(function(win) {
if (win != ignoreWindow && win.is_attached_dialog())
if (win != ignoreWindow &&
win.is_attached_dialog() &&
win.get_transient_for() == window) {
count++;
return false;
return false;
}
return true;
});
return count != 0;
},
@ -1352,11 +1404,14 @@ const WindowManager = new Lang.Class({
let dimmer = getWindowDimmer(actor);
if (!dimmer)
return;
Tweener.addTween(dimmer,
{ dimFactor: 1.0,
time: DIM_TIME,
transition: 'linear'
});
if (this._shouldAnimate())
Tweener.addTween(dimmer,
{ dimFactor: 1.0,
time: DIM_TIME,
transition: 'linear'
});
else
dimmer.dimFactor = 1.0;
},
_undimWindow: function(window) {
@ -1366,10 +1421,13 @@ const WindowManager = new Lang.Class({
let dimmer = getWindowDimmer(actor);
if (!dimmer)
return;
Tweener.addTween(dimmer,
{ dimFactor: 0.0,
time: UNDIM_TIME,
transition: 'linear' });
if (this._shouldAnimate())
Tweener.addTween(dimmer,
{ dimFactor: 0.0,
time: UNDIM_TIME,
transition: 'linear' });
else
dimmer.dimFactor = 0.0;
},
_mapWindow : function(shellwm, actor) {
@ -1387,6 +1445,14 @@ const WindowManager = new Lang.Class({
actor._windowType = type;
}));
actor.meta_window.connect('unmanaged', Lang.bind(this, function(window) {
let parent = window.get_transient_for();
if (parent)
this._checkDimming(parent);
}));
if (actor.meta_window.is_attached_dialog())
this._checkDimming(actor.get_meta_window().get_transient_for());
let types = [Meta.WindowType.NORMAL,
Meta.WindowType.DIALOG,
@ -1396,9 +1462,6 @@ const WindowManager = new Lang.Class({
return;
}
if (actor.meta_window.is_attached_dialog())
this._checkDimming(actor.get_meta_window().get_transient_for());
switch (actor._windowType) {
case Meta.WindowType.NORMAL:
actor.set_pivot_point(0.5, 1.0);
@ -1481,6 +1544,9 @@ const WindowManager = new Lang.Class({
});
}
if (window.is_attached_dialog())
this._checkDimming(window.get_transient_for(), window);
let types = [Meta.WindowType.NORMAL,
Meta.WindowType.DIALOG,
Meta.WindowType.MODAL_DIALOG];
@ -1515,7 +1581,6 @@ const WindowManager = new Lang.Class({
if (window.is_attached_dialog()) {
let parent = window.get_transient_for();
this._checkDimming(parent, window);
actor._parentDestroyId = parent.connect('unmanaged', Lang.bind(this, function () {
Tweener.removeTweens(actor);
this._destroyWindowDone(shellwm, actor);
@ -1721,23 +1786,37 @@ const WindowManager = new Lang.Class({
this._windowMenuManager.showWindowMenuForWindow(window, menu, rect);
},
_startAppSwitcher : function(display, screen, window, binding) {
_startSwitcher: function(display, screen, window, binding) {
let constructor = null;
switch (binding.get_name()) {
case 'switch-applications':
case 'switch-applications-backward':
case 'switch-group':
case 'switch-group-backward':
constructor = AltTab.AppSwitcherPopup;
break;
case 'switch-windows':
case 'switch-windows-backward':
constructor = AltTab.WindowSwitcherPopup;
break;
case 'cycle-windows':
case 'cycle-windows-backward':
constructor = AltTab.WindowCyclerPopup;
break;
case 'cycle-group':
case 'cycle-group-backward':
constructor = AltTab.GroupCyclerPopup;
break;
}
if (!constructor)
return;
/* prevent a corner case where both popups show up at once */
if (this._workspaceSwitcherPopup != null)
this._workspaceSwitcherPopup.destroy();
let tabPopup = new AltTab.AppSwitcherPopup();
if (!tabPopup.show(binding.is_reversed(), binding.get_name(), binding.get_mask()))
tabPopup.destroy();
},
_startWindowSwitcher : function(display, screen, window, binding) {
/* prevent a corner case where both popups show up at once */
if (this._workspaceSwitcherPopup != null)
this._workspaceSwitcherPopup.destroy();
let tabPopup = new AltTab.WindowSwitcherPopup();
let tabPopup = new constructor();
if (!tabPopup.show(binding.is_reversed(), binding.get_name(), binding.get_mask()))
tabPopup.destroy();

View File

@ -214,7 +214,7 @@ const WindowMenuManager = new Lang.Class({
menu.close();
});
this._sourceActor.set_size(rect.width, rect.height);
this._sourceActor.set_size(Math.max(1, rect.width), Math.max(1, rect.height));
this._sourceActor.set_position(rect.x, rect.y);
this._sourceActor.show();

View File

@ -361,6 +361,9 @@ const WindowClone = new Lang.Class({
// a long-press canceled when the pointer movement
// exceeds dnd-drag-threshold to manually start the drag
if (state == Clutter.LongPressState.CANCEL) {
let event = Clutter.get_current_event();
this._dragTouchSequence = event.get_event_sequence();
// A click cancels a long-press before any click handler is
// run - make sure to not start a drag in that case
Meta.later_add(Meta.LaterType.BEFORE_REDRAW, Lang.bind(this,
@ -369,7 +372,7 @@ const WindowClone = new Lang.Class({
return;
let [x, y] = action.get_coords();
action.release();
this._draggable.startDrag(x, y, global.get_current_time());
this._draggable.startDrag(x, y, global.get_current_time(), this._dragTouchSequence);
}));
}
return true;

View File

@ -19,8 +19,7 @@ const WorkspaceSwitcherPopup = new Lang.Class({
Name: 'WorkspaceSwitcherPopup',
_init : function() {
this.actor = new St.Widget({ reactive: true,
x: 0,
this.actor = new St.Widget({ x: 0,
y: 0,
width: global.screen_width,
height: global.screen_height,

View File

@ -45,11 +45,11 @@ const PrimaryActorLayout = new Lang.Class({
this.primaryActor = primaryActor;
},
vfunc_get_preferred_width: function(forHeight) {
vfunc_get_preferred_width: function(container, forHeight) {
return this.primaryActor.get_preferred_width(forHeight);
},
vfunc_get_preferred_height: function(forWidth) {
vfunc_get_preferred_height: function(container, forWidth) {
return this.primaryActor.get_preferred_height(forWidth);
},
});
@ -80,6 +80,8 @@ const WindowClone = new Lang.Class({
this.actor.connect('button-release-event',
Lang.bind(this, this._onButtonRelease));
this.actor.connect('touch-event',
Lang.bind(this, this._onTouchEvent));
this.actor.connect('destroy', Lang.bind(this, this._onDestroy));
@ -200,6 +202,15 @@ const WindowClone = new Lang.Class({
return Clutter.EVENT_STOP;
},
_onTouchEvent : function (actor, event) {
if (event.type() != Clutter.EventType.TOUCH_END ||
!global.display.is_pointer_emulating_sequence(event.get_event_sequence()))
return Clutter.EVENT_PROPAGATE;
this.emit('selected', event.get_time());
return Clutter.EVENT_STOP;
},
_onDragBegin : function (draggable, time) {
this.inDrag = true;
this.emit('drag-begin');
@ -642,6 +653,7 @@ const ThumbnailsBox = new Lang.Class({
this.actor.connect('button-press-event', function() { return Clutter.EVENT_STOP; });
this.actor.connect('button-release-event', Lang.bind(this, this._onButtonRelease));
this.actor.connect('touch-event', Lang.bind(this, this._onTouchEvent));
Main.overview.connect('showing',
Lang.bind(this, this._createThumbnails));
@ -672,18 +684,31 @@ const ThumbnailsBox = new Lang.Class({
global.screen.n_workspaces > 1;
},
_onButtonRelease: function(actor, event) {
let [stageX, stageY] = event.get_coords();
_activateThumbnailAtPoint: function (stageX, stageY, time) {
let [r, x, y] = this.actor.transform_stage_point(stageX, stageY);
for (let i = 0; i < this._thumbnails.length; i++) {
let thumbnail = this._thumbnails[i]
let [w, h] = thumbnail.actor.get_transformed_size();
if (y >= thumbnail.actor.y && y <= thumbnail.actor.y + h) {
thumbnail.activate(event.get_time());
thumbnail.activate(time);
break;
}
}
},
_onButtonRelease: function(actor, event) {
let [stageX, stageY] = event.get_coords();
this._activateThumbnailAtPoint(stageX, stageY, event.get_time());
return Clutter.EVENT_STOP;
},
_onTouchEvent: function (actor, event) {
if (event.type() == Clutter.EventType.TOUCH_END &&
global.display.is_pointer_emulating_sequence(event.get_event_sequence())) {
let [stageX, stageY] = event.get_coords();
this._activateThumbnailAtPoint(stageX, stageY, event.get_time());
}
return Clutter.EVENT_STOP;
},

View File

@ -103,7 +103,7 @@ const WorkspacesView = new Lang.Class({
page_increment: 1,
page_size: 1,
step_increment: 0,
upper: 0 });
upper: global.screen.n_workspaces });
this.scrollAdjustment.connect('notify::value',
Lang.bind(this, this._onScroll));
@ -374,6 +374,10 @@ const ExtraWorkspaceView = new Lang.Class({
this._workspace.setActualGeometry(this._actualGeometry);
},
getActiveWorkspace: function() {
return this._workspace;
},
animateToOverview: function(animationType) {
if (animationType == AnimationType.ZOOM)
this._workspace.zoomToOverview();
@ -421,8 +425,10 @@ const WorkspacesDisplay = new Lang.Class({
// Only switch to the workspace when there's no application
// windows open. The problem is that it's too easy to miss
// an app window and get the wrong one focused.
if (action.get_button() == 1 &&
this._getPrimaryView().getActiveWorkspace().isEmpty())
let event = Clutter.get_current_event();
let index = this._getMonitorIndexForEvent(event);
if ((action.get_button() == 1 || action.get_button() == 0) &&
this._workspacesViews[index].getActiveWorkspace().isEmpty())
Main.overview.hide();
}));
Main.overview.addAction(clickAction);
@ -431,11 +437,18 @@ const WorkspacesDisplay = new Lang.Class({
let panAction = new Clutter.PanAction({ threshold_trigger_edge: Clutter.GestureTriggerEdge.AFTER });
panAction.connect('pan', Lang.bind(this, this._onPan));
panAction.connect('gesture-begin', Lang.bind(this, function() {
if (this._workspacesOnlyOnPrimary) {
let event = Clutter.get_current_event();
if (this._getMonitorIndexForEvent(event) != this._primaryIndex)
return false;
}
for (let i = 0; i < this._workspacesViews.length; i++)
this._workspacesViews[i].startSwipeScroll();
return true;
}));
panAction.connect('gesture-cancel', Lang.bind(this, function() {
clickAction.release();
for (let i = 0; i < this._workspacesViews.length; i++)
this._workspacesViews[i].endSwipeScroll();
}));
@ -581,6 +594,12 @@ const WorkspacesDisplay = new Lang.Class({
}
},
_getMonitorIndexForEvent: function(event) {
let [x, y] = event.get_coords();
let rect = new Meta.Rectangle({ x: x, y: y, width: 1, height: 1 });
return global.screen.get_monitor_index_for_rect(rect);
},
_getPrimaryView: function() {
if (!this._workspacesViews.length)
return null;
@ -661,6 +680,11 @@ const WorkspacesDisplay = new Lang.Class({
_onScrollEvent: function(actor, event) {
if (!this.actor.mapped)
return Clutter.EVENT_PROPAGATE;
if (this._workspacesOnlyOnPrimary &&
this._getMonitorIndexForEvent(event) != this._primaryIndex)
return Clutter.EVENT_PROPAGATE;
let activeWs = global.screen.get_active_workspace();
let ws;
switch (event.get_scroll_direction()) {

View File

@ -140,7 +140,7 @@
<para>
<filename>/usr/share/gnome-session/sessions/gnome.session</filename>,
<filename>/usr/share/applications/gnome-shell.desktop</filename>.</para>
<filename>/usr/share/applications/org.gnome.Shell.desktop</filename>.</para>
</refsect1>
<refsect1>

View File

@ -24,10 +24,12 @@ fi
fr
fur
ga
gd
gl
gu
he
hi
hr
hu
ia
id

68
po/Makevars Normal file
View File

@ -0,0 +1,68 @@
# Makefile variables for PO directory in any package using GNU gettext.
# Usually the message domain is the same as the package name.
DOMAIN = $(PACKAGE)
# These two variables depend on the location of this directory.
subdir = po
top_builddir = ..
# These options get passed to xgettext.
XGETTEXT_OPTIONS = --from-code=UTF-8 --keyword=_ --keyword=N_ \
--keyword=C_:1c,2 --keyword=NC_:1c,2 \
--keyword=g_dngettext:2,3 --add-comments \
--flag=g_dngettext:2:pass-c-format \
--flag=g_strdup_printf:1:c-format \
--flag=g_string_printf:2:c-format \
--flag=g_string_append_printf:2:c-format \
--flag=g_error_new:3:c-format \
--flag=g_set_error:4:c-format \
--flag=g_markup_printf_escaped:1:c-format \
--flag=g_log:3:c-format \
--flag=g_print:1:c-format \
--flag=g_printerr:1:c-format \
--flag=g_printf:1:c-format \
--flag=g_fprintf:2:c-format \
--flag=g_sprintf:2:c-format \
--flag=g_snprintf:3:c-format
# This is the copyright holder that gets inserted into the header of the
# $(DOMAIN).pot file. Set this to the copyright holder of the surrounding
# package. (Note that the msgstr strings, extracted from the package's
# sources, belong to the copyright holder of the package.) Translators are
# expected to transfer the copyright for their translations to this person
# or entity, or to disclaim their copyright. The empty string stands for
# the public domain; in this case the translators are expected to disclaim
# their copyright.
COPYRIGHT_HOLDER = Translation copyright holder
# This is the email address or URL to which the translators shall report
# bugs in the untranslated strings:
# - Strings which are not entire sentences, see the maintainer guidelines
# in the GNU gettext documentation, section 'Preparing Strings'.
# - Strings which use unclear terms or require additional context to be
# understood.
# - Strings which make invalid assumptions about notation of date, time or
# money.
# - Pluralisation problems.
# - Incorrect English spelling.
# - Incorrect formatting.
# It can be your email address, or a mailing list address where translators
# can write to without being subscribed, or the URL of a web page through
# which the translators can contact you.
MSGID_BUGS_ADDRESS = http://bugzilla.gnome.org/enter_bug.cgi?product=gnome-shell&keywords=I18N+L10N&component=general
# This is the list of locale categories, beyond LC_MESSAGES, for which the
# message catalogs shall be used. It is usually empty.
EXTRA_LOCALE_CATEGORIES =
# Ignore the timestamp of the .pot file, as git clones do not have
# deterministic timestamps, and .po files are updated by translators
# (only) in GNOME projects.
PO_DEPENDS_ON_POT = no
# This tells whether or not to forcibly update $(DOMAIN).pot and
# regenerate PO files on "make dist". Possible values are "yes" and
# "no". Set this to no if the POT file and PO files are maintained
# externally.
DIST_DEPENDS_ON_UPDATE_PO = no

View File

@ -1,20 +1,20 @@
# List of source files containing translatable strings.
# Please keep this file sorted alphabetically.
[encoding: UTF-8]
data/50-gnome-shell-system.xml.in
data/gnome-shell.desktop.in.in
data/50-gnome-shell-system.xml
data/gnome-shell-extension-prefs.desktop.in.in
data/gnome-shell-wayland.desktop.in.in
data/org.gnome.shell.gschema.xml.in.in
data/org.gnome.Shell.PortalHelper.desktop.in
data/org.gnome.Shell.desktop.in.in
data/org.gnome.shell.gschema.xml.in
data/org.gnome.Shell.PortalHelper.desktop.in.in
js/extensionPrefs/main.js
js/gdm/authPrompt.js
js/gdm/loginDialog.js
js/gdm/util.js
js/misc/util.js
js/portalHelper/main.js
js/ui/accessDialog.js
js/ui/appDisplay.js
js/ui/appFavorites.js
js/ui/audioDeviceSelection.js
js/ui/backgroundMenu.js
js/ui/calendar.js
js/ui/components/automountManager.js
@ -33,10 +33,13 @@ js/ui/keyboard.js
js/ui/legacyTray.js
js/ui/lookingGlass.js
js/ui/main.js
js/ui/messageList.js
js/ui/messageTray.js
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
@ -59,7 +62,7 @@ js/ui/viewSelector.js
js/ui/windowAttentionHandler.js
js/ui/windowManager.js
js/ui/windowMenu.js
src/calendar-server/evolution-calendar.desktop.in.in
src/calendar-server/evolution-calendar.desktop.in
# Please do not remove this file from POTFILES.in. Run "git submodule init && git submodule update" to get it.
src/gvc/gvc-mixer-control.c
src/main.c

View File

@ -1,4 +0,0 @@
data/org.gnome.shell.evolution.calendar.gschema.xml.in
src/calendar-server/evolution-calendar.desktop.in
# Meh, autofools :-(
sub/src/calendar-server/evolution-calendar.desktop.in

1403
po/af.po

File diff suppressed because it is too large Load Diff

921
po/ar.po

File diff suppressed because it is too large Load Diff

View File

@ -13,7 +13,7 @@ msgstr ""
"PO-Revision-Date: 2014-09-15 14:59+0530\n"
"Last-Translator: Nilamdyuti Goswami <ngoswami@redhat.com>\n"
"Language-Team: Assamese <kde-i18n-doc@kde.org>\n"
"Language: as_IN\n"
"Language: as\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"

719
po/bg.po

File diff suppressed because it is too large Load Diff

View File

@ -7,6 +7,7 @@ msgstr ""
"PO-Revision-Date: 2011-04-04 11:04+0600\n"
"Last-Translator: Israt Jahan <israt@ankur.org.bd>\n"
"Language-Team: Bengali <ankur-bd-l10n@googlegroups.com>\n"
"Language: bn\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"

View File

@ -11,7 +11,7 @@ msgstr ""
"PO-Revision-Date: 2014-12-30 16:45+0000\n"
"Last-Translator: \n"
"Language-Team: American English <kde-i18n-doc@kde.org>\n"
"Language: en_US\n"
"Language: bn_IN\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"

915
po/ca.po

File diff suppressed because it is too large Load Diff

View File

@ -14,7 +14,7 @@ msgstr ""
"PO-Revision-Date: 2014-09-14 23:32+0200\n"
"Last-Translator: Gil Forcada <gilforcada@guifi.net>\n"
"Language-Team: Catalan <tradgnome@softcatala.org>\n"
"Language: ca-XV\n"
"Language: ca@valencia\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bits\n"

973
po/cs.po

File diff suppressed because it is too large Load Diff

910
po/da.po

File diff suppressed because it is too large Load Diff

1379
po/de.po

File diff suppressed because it is too large Load Diff

931
po/el.po

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

1804
po/eo.po

File diff suppressed because it is too large Load Diff

1008
po/es.po

File diff suppressed because it is too large Load Diff

913
po/eu.po

File diff suppressed because it is too large Load Diff

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