Compare commits

...

79 Commits

Author SHA1 Message Date
Ray Strode
5f571b8531 background: refresh background on gl-video-memory-purged signal
Right now we refresh the background when resuming and when NVIDIA.
But mutter has a signal to tell us specifically when to refresh,
and the signal is only emitted for NVIDIA, so use that instead.
2019-02-17 12:28:08 -05:00
Ray Strode
f4fd379bd6 st-texture-cache: purge on resume
With the proprietary nvidia driver, textures get garbled on suspend,
so the texture cache needs to evict all textures in that situation.
2019-02-17 12:28:07 -05:00
Ray Strode
b9a4340bc8 background: rebuild background, not just animation on resume
Previously, we would only refresh the animation on resume
(to handle clock skew).

But we actually need to rebuild the background, too, on nvidia,
so we should just do a full background change.
2019-02-17 12:28:07 -05:00
Ray Strode
63b622ccea background: refresh after suspend on wayland
At the moment we only refresh after suspend on Xorg.

We need to do it on wayland, too.
2019-02-17 12:28:07 -05:00
Carlos Garnacho
0ad02321de inputMethod: Use forward_key() method to forward key events
ClutterVirtualInputDevice has the limitation that event flags won't be
made to contain CLUTTER_EVENT_FLAG_INPUT_METHOD, possibly causing feedback
loops.

As the event gets injected up the platform dependent bits, we can avoid
care on not pressing the same key twice, we still expect coherence between
key presses and releases from the IM though.

https://gitlab.gnome.org/GNOME/gnome-shell/issues/531
2019-02-17 12:28:07 -05:00
Florian Müllner
e55aacaa10 inputMethod: Fix setting surrounding text
The underlying ibus method expects an object of type IBusText rather
than a plain string.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/228
2019-02-17 12:28:07 -05:00
Andrea Azzarone
ed1a8c582d inputMethod: Add a null-check for text in vfunc_set_surrounding.
Fixes https://gitlab.gnome.org/GNOME/gnome-shell/issues/579
2019-02-17 12:28:07 -05:00
Takao Fujiwara
99b40d8eaa inputMethod: Fix to hide preedit text
ibus_engine_update_preedit_text() should hide the pre-edit text
when visible == false.

https://gitlab.gnome.org/GNOME/gnome-shell/issues/431
2019-02-17 12:28:07 -05:00
Carlos Garnacho
fd36bbbc10 inputMethod: Handle IBusInputContext::forward-key-press
The input method may hint that certain keycodes should be pressed/released
besides the textual information in ::commit. An example is hitting space
in some IMs to commit text, where both ::commit happens, and an space is
visibly inserted. In order to handle this properly, we must honor
::forward-key-press.

In order to cater for the case that a keypress is forwarded while handling
that same keypress in a physical keyboard, check the current event being
handled and just forward it as-is if it matches. This is necessary to
prevent state from being doubly set, and the second event silenced away.

https://gitlab.gnome.org/GNOME/gnome-shell/issues/275

Closes: #275
2019-02-17 12:28:07 -05:00
Florian Müllner
b301d0582a keyboard: Handle no-window case in FocusTracker
For windows, the cursor location needs to be adjusted by the frame
offsets. However we cannot assume that there is a window, as the
shell itself can have the key focus.

https://gitlab.gnome.org/GNOME/gnome-shell/issues/414

(cherry picked from commit 0dee82fb9f)
2019-02-17 12:28:07 -05:00
Carlos Garnacho
26589af153 keyboardManager: Avoid idempotent calls to meta_backend_set_keymap()
But still try to apply the keymap whenever the input sources changed. This
is a different approach to gnome-shell#240 that still avoid redundant
changes to the current keymap, but actually trigger one when input sources
are added.

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

Closes: https://gitlab.gnome.org/GNOME/gnome-shell/issues/691
2019-02-17 12:28:07 -05:00
Florian Müllner
15aaf1a455 osdWindow: Disconnect signals on destroy
Since we started to show OSD windows on all monitors, OSD windows are
destroyed when the corresponding monitor is disconnected. We shouldn't
leave any signal handlers around in that case - they prevent the object
from being garbage collected, and trigger warnings for accessing proper-
ties of invalidated GObjects.

https://gitlab.gnome.org/GNOME/gnome-shell/issues/602
2019-02-17 12:28:06 -05:00
Marco Trevisan (Treviño)
c227be4325 tweener: Save handlers on target and remove them on destroy
Saving handlers we had using the wrapper as a property of the object and delete
them when resetting the object state.
Without doing this an handler could be called on a destroyed target when this
happens on the onComplete callback.

https://bugzilla.gnome.org/show_bug.cgi?id=791233
2019-02-17 12:28:06 -05:00
Florian Müllner
6622fae6bd calendar: chain up to parent on _onDestroy 2019-02-17 12:28:06 -05:00
Marco Trevisan (Treviño)
2f24e0701e automountManager: remove allowAutorun expire timeout on volume removal
If the volume is removed before AUTORUN_EXPIRE_TIMEOUT_SECS seconds, we can stop
the timeout earlier as there's nothing to unset, while the volume instance
won't be valid anymore.

https://bugzilla.gnome.org/show_bug.cgi?id=791233
2019-02-17 12:28:06 -05:00
Marco Trevisan (Treviño)
72e2936f20 messageList: stop syncing if closeButton has been destroyed
The _sync function for Message only updates the close button visibility,
so we can safely stop doing that if the close button get get destroyed earlier
(as it happens when clicking on it).

https://bugzilla.gnome.org/show_bug.cgi?id=791233
2019-02-17 12:28:06 -05:00
Jonas Ådahl
a77b7447d7 dnd: Repick target actor if destroyed mid iteration
The picked target actor may be destroyed (e.g. hover style change
resulting in the ClutterTexture to be destroyed). If we don't handle
this, GJS will abort when it sees the exception caused by Javascript
code trying to access the destroyed target actor.

To handle it, listen on the 'destroy' signal on the target actor, and
repick, so a valid actor is passed to the next motion callback.

Fixes: https://gitlab.gnome.org/GNOME/gnome-shell/issues/632
2019-02-17 12:28:06 -05:00
Marco Trevisan (Treviño)
b5e7e91c78 dnd: Nullify _dragActor after we've destroyed it, and avoid invalid access
We need to avoid that we use the _dragActor instance after that it has
been destroyed or we'll get errors. We now set it to null when this
happens, protecting any access to that.

Add a DragState enum-like object to keep track of the state
instead of using booleans.

Remove duplicated handler on 'destroy' and just use a generic one.

https://bugzilla.gnome.org/show_bug.cgi?id=791233
2019-02-17 12:28:06 -05:00
Olivier Fourdan
8331a68ae3 introspect: Add GetWindows method
The `GetWindows` method gives access to the list of windows for each
application with some of their properties, so utilities such as dogtail
can pick the window of their choice to interfere with using the provided
window id.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/326
(cherry picked from commit 0f45b438e2b956d3cf52622db875dedab45e49b9)
2019-02-17 12:28:06 -05:00
Jonas Ådahl
bb2764dc69 Add app introspection API
Add a D-Bus API that allows the API user to introspect the application
state of the shell. Currently the only exposed information is list of
running applications and which one is active (i.e. has focus).

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/326
(cherry picked from commit 10c68c6b952959d105c3126fc61f22a199e8e848)
2019-02-17 12:28:06 -05:00
Jonas Ådahl
0e7c424e50 remoteAccess: Make indicator orange
Make the indicator for active remote access use the warning color, to
indicate the severity of allowing remote access.

This only makes the indicator icon orange; the icon in the system menu
is still white.
2019-02-17 12:28:06 -05:00
Jonas Ådahl
219adb4510 Add remote access indication and control
Add an indicator for when there is something access the display server
remotely. This could be 1) remote desktop, 2) screen cast or 3) remote
control, but all effectively applications using
org.freedesktop.portal.ScreenCast or org.gnome.portal.RemoteDesktop as
well as gnome-remote-desktop using the corresponding org.gnome.Mutter
APIs directly.

As it is now, it'll simply show a single icon for when anything is
having an active session, and a single action "Turn off" that'll close
every active session.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/160
2019-02-17 12:28:05 -05:00
Florian Müllner
3f221c28a1 closeDialog: Untrack chrome when window loses focus
On X11, reactive chrome must be added to the input region in order
to work as expected. However that region works independently from
any window stacking, with the result that the unresponsive-app dialog
currently blocks all input in the "covered" area, even in windows
stacked above the unresponsive window.

The correct fix would be to track the unobscured parts of the dialog
and set the input region from that, but that's quite cumbersome. So
instead, only track chrome when the corresponding window is focused
(or the dialog itself of course).

https://gitlab.gnome.org/GNOME/gnome-shell/issues/273
2019-02-17 12:28:05 -05:00
Florian Müllner
2effcfcc7d closeDialog: Periodically check for window to become responsive again
The close dialog for non-responding windows is closed automatically
when we detect that the window is responding again. However as we
currently only ping the window in response to certain user actions
(like focusing the window or opening the window menu), this can
easily go undetected.

Address this by periodically pinging the window while the close
dialog is shown.

https://gitlab.gnome.org/GNOME/gnome-shell/issues/298
2019-02-17 12:28:05 -05:00
Florian Müllner
deb2e8bc39 closeDialog: Disable unredirection while showing
The dialog won't be visible when unredirection is in place (for example
while a fullscreen window is focused), so disable unredirection while
the dialog is up.

https://gitlab.gnome.org/GNOME/gnome-shell/issues/298
2019-02-17 12:28:05 -05:00
Florian Müllner
608937cb98 app: Close all closable windows from quit()
There's no relation between a window being hidden from overview/taskbars
and a window not being closable - currently we effectively disable the
fallback quit action for any application with open transients, which
simply doesn't make sense.

Instead, only exclude windows for which the close action has been
explicitly disabled.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/217
2019-02-17 12:28:05 -05:00
Florian Müllner
d727fe3eeb appDisplay: Show full app name on hover 2019-02-17 12:28:05 -05:00
Florian Müllner
a52390187b altSwitcher: Fix error when all alternatives are disabled
While we do consider the case that we don't have a child to show for the
visibility, we are still trying to move the click action unconditionally.

https://gitlab.gnome.org/GNOME/gnome-shell/issues/783
2019-02-17 12:28:05 -05:00
Florian Müllner
d376b829b4 global: Allow overriding the override schema 2019-02-17 12:28:05 -05:00
Florian Müllner
e11404d1cf windowMenu: Bring back workspaces submenu for static workspaces
When the titlebar context menu was moved to the shell, the submenu for
moving to a specific workspace was intentionally left out; some people
are quite attached to it though, so bring it back when static workspaces
are used.
2019-02-17 12:28:04 -05:00
Florian Müllner
585cf9c17d app: Fall back to window title instead of WM_CLASS
It's a bad fallback as it's clearly window-specific (rather than
app-specific), but it likely looks prettier when we fail to associate
a .desktop file ...
2019-02-17 12:28:04 -05:00
Ray Strode
503a9d729c panel: add an icon to the ActivitiesButton
Requested by brand
2019-02-17 12:28:04 -05:00
Florian Müllner
04ea89d683 extensionSystem: Notify about extension issues on update 2019-02-17 12:28:04 -05:00
Rui Matos
1220e0124a extensions: Add a SESSION_MODE extension type
This allows e.g. gnome-tweak-tool to present these extensions in a
different way since they can't be disabled.
2019-02-17 12:28:04 -05:00
Rui Matos
7d9a39c72c shellDBus: Add a DBus method to load a single extension
This allows e.g. gnome-tweak-tool to install an extension from a zip
file and load it into the running shell.
2019-02-17 12:28:03 -05:00
Ray Strode
b474ea0b7c gdmUtil: enable support for GDM's ChoiceList PAM extension
This commit hooks up support for GDM's ChoiceList PAM extension.
2019-02-17 12:28:03 -05:00
Ray Strode
d4b211bd23 gdm: add AuthList control
Ultimately, we want to add support for GDM's new ChoiceList
PAM extension.  That extension allows PAM modules to present
a list of choices to the user. Before we can support that
extension, however, we need to have a list control in the
login-screen/unlock screen.  This commit adds that control.

For the most part, it's a copy-and-paste of the gdm userlist,
but with less features.  It lacks API specific to the users,
lacks the built in timed login indicator, etc. It does feature
a label heading.
2019-02-17 12:28:03 -05:00
Ray Strode
98e4af9712 loginDialog: make info messages themed
They were lacking a definition before leading them to
show up invisible.
2019-02-17 12:28:03 -05:00
Ray Strode
c7665b87a6 data: install process-working.svg to filesystem
This helps prevent unlock failure on inplace upgrades between
7.3 and 7.4
2019-02-17 12:28:03 -05:00
Ray Strode
f7b47666b2 loginDialog: allow timed login with disabled user list
At the moment the timed login feature is implemented in the user list.
If there's no user list, we don't show the indicator anywhere and
don't proceed with timed login.

This commit allows timed login to work when the user list is disabled.
It accomplishes this by putting the timed login indicator on the
auth prompt, in that scenario.
2019-02-17 12:28:02 -05:00
Ray Strode
241585479b authPrompt: stop accepting preemptive answer if user stops typing
We only want to allow the user to type the preemptive password in
one smooth motion.  If they start to type, and then stop typing,
we should discard their preemptive password as expired.

Typing ahead the password is just a convenience for users who don't
want to manually lift the shift before typing their passwords, after
all.
2019-02-17 12:28:02 -05:00
Ray Strode
31612927b2 authPrompt: don't spin unless answering question 2019-02-17 12:28:02 -05:00
Ray Strode
65229b6299 authPrompt: don't fade out auth messages if user types password up front
Right now we fade out any stale auth messages as soon as the user starts
typing. This behavior doesn't really make sense if the user is typing up
front, before a password is asked.
2019-02-17 12:28:02 -05:00
Ray Strode
53f1d46fb5 gdm: update default service when smartcard inserted
Early on at start up we may not know if a smartcard is
available.  Make sure we reupdate the default service
after we get a smartcard insertion event.
2019-02-17 12:28:02 -05:00
Ray Strode
04d526e9f5 gdm: only unlock with smartcard, if smartcard used for login
If a smartcard is used for login, we need to make sure the smartcard
gets used for unlock, too.
2019-02-17 12:28:02 -05:00
Ray Strode
8593532801 smartcardManager: add way to detect if user logged using (any) token
If a user uses a token at login time, we need to make sure they continue
to use the token at unlock time.

As a prerequisite for addressing that problem we need to know up front
if a user logged in with a token at all.

This commit adds the necessary api to detect that case.
2019-02-17 12:28:02 -05:00
Ray Strode
1e0ec69c41 screenShield: unblank when inserting smartcard
If a user inserts the smartcard when the screen is locked/blanked
we should ask them their pin right away.

At the moment they have to wiggle the mouse or do some other
action to get the screen to unblank.
2019-02-17 12:28:02 -05:00
Florian Müllner
9a6054b6b7 appFavorites: Add terminal 2019-02-17 12:28:02 -05:00
Florian Müllner
54633cb1f6 Add 'yelp' to default favorites
Help should be easily available, so add it to the default favorites.
2019-02-17 12:28:02 -05:00
Ray Strode
a506d86139 gnome-shell-favourite-apps-firefox.patch 2019-02-17 12:28:01 -05:00
Florian Müllner
6ed21e1ce0 Bump version to 3.28.3
Update NEWS.
2018-07-18 22:53:05 +02:00
Florian Müllner
9c51c87d8c events: Re-use event messages where possible
Destroying and recreating the entire events list on every change is not only
wasteful, it also breaks the clear functionality as messages scheduled for
removal are replaced with "new" messages after the first message has been
removed.

Address both issues by keeping track of all messages and re-use them
whenever possible.

https://gitlab.gnome.org/GNOME/gnome-shell/issues/325
2018-07-13 23:03:42 +02:00
Florian Müllner
db2245d60b workspaceThumbnail: Don't keep stale clones in list
If a clone gets destroyed before the corresponding MetaWindow is
removed from the workspace, we will still find it in the list of
clones and try to destroy it again. Avoid the resulting warnings
by updating the list of clones immediately when a clone is destroyed.

https://bugzilla.gnome.org/show_bug.cgi?id=791233
2018-07-13 15:11:43 +02:00
Florian Müllner
f26cc3ac23 workspace: Don't keep stale clones in list
If a clone gets destroyed before the corresponding MetaWindow is
removed from the workspace, we will still find it in the list of
clones and try to destroy it again. Avoid the resulting warnings
by updating the list of clones immediately when a clone is destroyed.

https://bugzilla.gnome.org/show_bug.cgi?id=791233
2018-07-13 15:11:43 +02:00
Marco Trevisan (Treviño)
02c5b4b947 workspaceThumbnail: remove unused private win reference 2018-07-13 15:11:43 +02:00
Carlos Garnacho
df57829ea1 keyboard: Implement standalone FocusTracker
And stop using FocusCaretTracker for caret position purposes. This
new object uses 1) the text-input protocol in wayland and 2) Info
from IBusPanelService for X11 (which is meant to work for XIM too).

This drops the usage of AtspiEventListener for OSK purposes, which
is best to avoid.
2018-07-11 18:52:27 +02:00
Didier Roche
da96408098 ui: Theme lookup should respect XDG_DATA_DIRS
Modes, extensions and other GNOME Shell assets are searched in appropriate
subdirectories of each directory in XDG_DATA_DIRS, falling back
to global.datadir.
However, this isn't the case for themes, which are currently always expected
in global.datadir, even when referenced by a mode in a different XDG_DATA_DIR.

The fix is to have the theme finding pattern follow the same logic as other
elements.
Fixes #167.


(cherry picked from commit d6d09fd3c8)
2018-06-20 23:24:07 +00:00
Marco Trevisan (Treviño)
4b2e0247af st-texture-cache: Save cairo surfaces to a different map
The default keyed_surface is meant to handle CoglTextures thus we can't
add cairo surfaces to it, as the DestroyNotify function won't handle them.

Then the quicker way is to just add another Hash table for handling
such types of textures, with proper destroy function.


(cherry picked from commit 1f03599d1c)
2018-06-20 23:00:20 +00:00
Marco Trevisan (Treviño)
2c617e5a3a st-texture-cache: Don't add NULL textures to cache
This might cause a crash when cleaning up the cache as the hash table has
cogl_object_unref as DestroyNotify function but that assumes that
the passed object is a valid CoglObject.

Fixes: #210


(cherry picked from commit a24999b7a3)
2018-06-20 22:59:29 +00:00
Joe Rabinoff
4ff7e84c51 Change "const" to "var"
These variables are in fact used from other modules, so gjs complains about them
being const.


(cherry picked from commit 8237a1f6e0)
2018-06-20 22:30:17 +00:00
Daniel van Vugt
9f76b6e4a2 magnifier.js: Fix zoom juddering
Make Zoom respond to the mouse silky-smoothly.

It was previously hard-coded to: 1000/50 = 20 FPS.

https://bugzilla.gnome.org/show_bug.cgi?id=682013
https://launchpad.net/bugs/1691675


(cherry picked from commit 94101e8bb8)
2018-06-07 08:42:32 +00:00
Gun Chleoc
0ac0f7e85b Update Scottish Gaelic translation 2018-06-01 10:36:10 +00:00
Marco Trevisan (Treviño)
73b00ff1a7 st-label: Unset clutter text instance on disposal
The instance is owned by the actor (being its child), and thus when the
disposal happens for the parent the text is disposed too, thus it's just
safer to nullify its reference so that we won't try to access to invalid
objects later, and this might be the case since the JS objects could be kept
around until they aren't finalized.

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


(cherry picked from commit 44894262f4)
2018-05-29 09:57:50 +00:00
Pieter Schalk Schoeman
a52597ac5b Update Afrikaans translation 2018-05-19 20:59:51 +00:00
Mario Sanchez Prada
9a2597f80b network: Update the icon in the panel whenever NM's state changes
Similar to what it's done when the main connection changes, we need
to make sure that the icon in the panel gets updated before calling
_syncConnectivity(), so that the icon gets always updated if needed,
regardless of whether there's an active connection or not.

This is needed because there's at least one case when an icon should
be shown when the computer is not connected to any network: when a
hotspot has been enabled, which can be useful even if there's not
an internet connection to share (e.g. to easily allow connecting
other devices to the computer.

Closes: https://gitlab.gnome.org/GNOME/gnome-shell/issues/214


(cherry picked from commit d8b9e23502)
2018-05-17 20:28:26 +00:00
Florian Müllner
e1ed4b25e1 networkAgent: Fix fallout from libnm port
While the libnm-glib version of the function returns a GByteArray*
that gjs can directly cast to the required gutf8*, the libnm function
returns GBytes* from which we need to explicitly fetch the data.

https://gitlab.gnome.org/GNOME/gnome-shell/issues/136


(cherry picked from commit c0a453f64f)
2018-05-09 14:53:15 +00:00
Florian Müllner
c70b18764b Bump version to 3.28.2
Update NEWS.
2018-05-08 22:18:02 +02:00
Florian Müllner
4398516520 build: Include Cally in St introspection
CallyActor is exposed indirectly via StAccessible's parent type,
so add the dependency to shut up a gjs warning.

https://bugzilla.gnome.org/show_bug.cgi?id=781471
2018-05-08 22:02:11 +02:00
Florian Müllner
220514d10e remoteSearch: Actually return icons
Since commit 3b1330880f, a remote search result's createIcon() method
no longer returns the created icon, whoops ...

https://gitlab.gnome.org/GNOME/gnome-shell/issues/249
2018-05-08 22:02:11 +02:00
Silvère Latchurié
18312d9ccd osdWindow: Fix blurriness at certain resolutions
The y position wasn't rounded, leading to some blurriness at vertical
resolutions that aren't a multiple of 4 (e.g. 1050).

https://bugzilla.gnome.org/show_bug.cgi?id=782011
2018-05-08 22:02:11 +02:00
Ray Strode
234b1441e4 keyboardManager: take group index into account when preserving keymap
commit 642107a2 attempts to avoid resetting the current keymap on
spurious input source changes.

It does this by checking if the current layout id is found in
the new list of layouts and resetting the current layout to the
associated match in the list. By not nullifying the current
layout, it won't get subsequently reset.

Unfortunately, if the order of the list changes, resetting the
current keymap is still necessary, since the order corresponds
with the index of the activated group.

This commit changes the code to nullify the current layout if
its group index changes.

https://bugzilla.redhat.com/show_bug.cgi?id=1573923
2018-05-08 13:56:55 -04:00
Rafael Fontenelle
e909db5848 Update Brazilian Portuguese translation 2018-05-02 18:46:32 +00:00
Carlos Garnacho
702338bc7d keyboardManager: Preserve current keymap across reloads
The IM can pretty much update the input sources anytime (even if
to set the same ones). That ends up triggering rebuilding all user
defined keymaps, and losing modifier state if we are unfortunate
enough that this caught us while pressing one.

One common situation seems to be password entries, resulting in
the wrong character being printed if the first character happens
to require the shift key.

If the current keymap is not found in the newly loaded list,
this._current will end up null, with the same behavior as we get
currently (immediate keymap reload).

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

https://gitlab.gnome.org/GNOME/gnome-shell/issues/240

Closes: #240
2018-04-29 17:52:56 +02:00
Florian Müllner
7c9dbc66d9 polkitAgent: Guard against repeated close() calls
We use the close() method to disconnect signal handlers set up in
init(), however the handler ID is only valid in the first call in
case the method is called more than once.

https://gitlab.gnome.org/GNOME/gnome-shell/issues/221
2018-04-21 22:39:15 +02:00
Stas Solovey
0d031dc20f Update Russian translation 2018-04-19 20:32:53 +00:00
Marco Trevisan (Treviño)
b476e851b7 workspaceThumbnail: only update _porthole if the overview is visible
Otherwise it happens that porthole is computed again after that the
overlay is hidden (triggered by a layout reallocation) and thus not
regenerated again afterwards.

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


(cherry picked from commit 5fcf40b973)
2018-04-18 00:35:42 +00:00
Marco Trevisan (Treviño)
a27be6a540 workspaceThumbnail: rebuild thumbnails if workareas size changed
https://bugzilla.gnome.org/show_bug.cgi?id=792687


(cherry picked from commit c29bd46e7a)
2018-04-18 00:34:45 +00:00
Marco Trevisan (Treviño)
4b6a57fabe workspaceThumbnail: initialize porthole based on workArea
https://bugzilla.gnome.org/show_bug.cgi?id=792687


(cherry picked from commit b99e304f1e)
2018-04-18 00:33:39 +00:00
Mario Sanchez Prada
92758890bb popupMenu: Fix wrong call to clutter_actor_add_child()
Specify the horizontal alignment via the x_align property when creating
the StIcon, since this function expects one argument, not two.


(cherry picked from commit cdbc99e992)
2018-04-18 00:32:37 +00:00
60 changed files with 2894 additions and 1269 deletions

28
NEWS
View File

@ -1,3 +1,31 @@
3.28.3
======
* Fix lagging pointer when zoomed [Daniel; #682013]
* Fix "Clear All" for calendar events [Florian; #325]
* Misc. bug fixes [Florian, Mario, Marco; #136, #214, #788931, #791233]
Contributors:
Carlos Garnacho, Florian Müllner, Mario Sanchez Prada, Joe Rabinoff,
Didier Roche, Marco Trevisan (Treviño), Daniel van Vugt
Translators:
Pieter Schalk Schoeman [af], Gun Chleoc [gd]
3.28.2
======
* Fix lock-up on cancelling polkit dialog [Florian; #221]
* Guard against untimely keyboard map changes [Carlos; #240]
* Fix blurriness of OSD under some resolutions [Silvère; #782011]
* Fix icons in search provider results [Florian; #249]
* Misc. bug fixes [Marco, Florian; #792687, #781471]
Contributors:
Carlos Garnacho, Silvère Latchurié, Florian Müllner, Mario Sanchez Prada,
Ray Strode, Marco Trevisan (Treviño)
Translators:
Stas Solovey [ru], Rafael Fontenelle [pt_BR]
3.28.1
======
* Fix compose characters in shell entries [Carlos; #115]

View File

@ -46,7 +46,8 @@ dbus_interfaces = [
'org.gnome.Shell.Screencast.xml',
'org.gnome.Shell.Screenshot.xml',
'org.gnome.ShellSearchProvider.xml',
'org.gnome.ShellSearchProvider2.xml'
'org.gnome.ShellSearchProvider2.xml',
'org.gnome.Shell.Introspect.xml'
]
install_data(dbus_interfaces, install_dir: ifacedir)

View File

@ -0,0 +1,61 @@
<!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.Introspect:
@short_description: Introspection interface
The interface used to introspect the state of Shell, such as running
applications, currently active application, etc.
-->
<interface name="org.gnome.Shell.Introspect">
<!--
RunningApplicationsChanged:
@short_description: Notifies when the running applications changes
-->
<signal name="RunningApplicationsChanged" />
<!--
GetRunningApplications:
@short_description: Retrieves the description of all running applications
Each application is associated by an application ID. The details of
each application consists of a varlist of keys and values. Available
keys are listed below.
'active-on-seats' - (as) list of seats the application is active on
(a seat only has at most one active
application)
-->
<method name="GetRunningApplications">
<arg name="apps" direction="out" type="a{sa{sv}}" />
</method>
<!--
GetWindows:
@short_description: Retrieves the current list of windows and their properties
A window is exposed as:
* t ID: unique ID of the window
* a{sv} properties: high-level properties
Known properties:
- "title" (s): (readonly) title of the window
- "app-id" (s): (readonly) application ID of the window
- "wm-class" (s): (readonly) class of the window
- "client-type" (u): (readonly) 0 for Wayland, 1 for X11
- "is-hidden" (b): (readonly) if the window is currently hidden
- "has-focus" (b): (readonly) if the window currently have
keyboard focus
- "width" (u): (readonly) width of the window
- "height" (u): (readonly) height of the window
-->
<method name="GetWindows">
<arg name="windows" direction="out" type="a{ta{sv}}" />
</method>
</interface>
</node>

View File

@ -39,7 +39,7 @@
</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>
<default>[ 'firefox.desktop', 'evolution.desktop', 'rhythmbox.desktop', 'shotwell.desktop', 'org.gnome.Nautilus.desktop', 'org.gnome.Software.desktop', 'yelp.desktop', 'gnome-terminal.desktop' ]</default>
<summary>List of desktop file IDs for favorite applications</summary>
<description>
The applications corresponding to these identifiers
@ -90,6 +90,14 @@
adapter is ever seen not to have devices associated to it.
</description>
</key>
<key name="introspect" type="b">
<default>false</default>
<summary>Enable introspection API</summary>
<description>
Enables a D-Bus API that allows to introspect the application state of
the shell.
</description>
</key>
<child name="keybindings" schema="org.gnome.shell.keybindings"/>
<child name="keyboard" schema="org.gnome.shell.keyboard"/>
</schema>

View File

@ -776,6 +776,11 @@ StScrollBar {
//dimensions of the icon are hardcoded
}
.panel-logo-icon {
padding-right: .4em;
icon-size: 1em;
}
.system-status-icon,
.app-menu-icon > StIcon,
.popup-menu-arrow {
@ -824,6 +829,8 @@ StScrollBar {
.screencast-indicator { color: $warning_color; }
.remote-access-indicator { color: $warning_color; }
&.solid {
background-color: black;
/* transition from transparent to solid */
@ -1397,6 +1404,14 @@ StScrollBar {
}
.app-well-hover-text {
text-align: center;
color: $osd_fg_color;
background-color: $osd_bg_color;
border-radius: 5px;
padding: 3px;
}
.app-well-app-running-dot { //running apps indicator
width: 10px; height: 3px;
background-color: $selected_bg_color;
@ -1769,7 +1784,12 @@ StScrollBar {
.login-dialog-banner { color: darken($osd_fg_color,10%); }
.login-dialog-button-box { spacing: 5px; }
.login-dialog-message-warning { color: $warning_color; }
.login-dialog-message-hint { padding-top: 0; padding-bottom: 20px; }
.login-dialog-message-hint, .login-dialog-message {
color: darken($osd_fg_color, 20%);
padding-top: 0;
padding-bottom: 20px;
min-height: 2.75em;
}
.login-dialog-user-selection-box { padding: 100px 0px; }
.login-dialog-not-listed-label {
padding-left: 2px;
@ -1825,6 +1845,10 @@ StScrollBar {
padding-bottom: 12px;
spacing: 8px;
width: 23em;
.login-dialog-timed-login-indicator {
height: 2px;
background-color: darken($fg_color,40%);
}
}
.login-dialog-prompt-label {

View File

@ -23,3 +23,5 @@ foreach style: styles
],
depend_files: theme_sources)
endforeach
install_data('process-working.svg', install_dir: themedir)

195
js/gdm/authList.js Normal file
View File

@ -0,0 +1,195 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
/*
* Copyright 2017 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
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
const Clutter = imports.gi.Clutter;
const GObject = imports.gi.GObject;
const Gtk = imports.gi.Gtk;
const Lang = imports.lang;
const Meta = imports.gi.Meta;
const Signals = imports.signals;
const St = imports.gi.St;
const Tweener = imports.ui.tweener;
const _SCROLL_ANIMATION_TIME = 0.5;
const AuthListItem = new Lang.Class({
Name: 'AuthListItem',
_init(key, text) {
this.key = key;
let label = new St.Label({ style_class: 'auth-list-item-label',
y_align: Clutter.ActorAlign.CENTER });
label.text = text;
this.actor = new St.Button({ style_class: 'login-dialog-user-list-item',
button_mask: St.ButtonMask.ONE | St.ButtonMask.THREE,
can_focus: true,
child: label,
reactive: true,
x_align: St.Align.START,
x_fill: true });
this.actor.connect('key-focus-in', () => {
this._setSelected(true);
});
this.actor.connect('key-focus-out', () => {
this._setSelected(false);
});
this.actor.connect('notify::hover', () => {
this._setSelected(this.actor.hover);
});
this.actor.connect('clicked', this._onClicked.bind(this));
},
_onClicked() {
this.emit('activate');
},
_setSelected(selected) {
if (selected) {
this.actor.add_style_pseudo_class('selected');
this.actor.grab_key_focus();
} else {
this.actor.remove_style_pseudo_class('selected');
}
}
});
Signals.addSignalMethods(AuthListItem.prototype);
const AuthList = new Lang.Class({
Name: 'AuthList',
_init() {
this.actor = new St.BoxLayout({ vertical: true,
style_class: 'login-dialog-auth-list-layout' });
this.label = new St.Label({ style_class: 'prompt-dialog-headline' });
this.actor.add_actor(this.label);
this._scrollView = new St.ScrollView({ style_class: 'login-dialog-user-list-view'});
this._scrollView.set_policy(Gtk.PolicyType.NEVER,
Gtk.PolicyType.AUTOMATIC);
this.actor.add_actor(this._scrollView);
this._box = new St.BoxLayout({ vertical: true,
style_class: 'login-dialog-user-list',
pseudo_class: 'expanded' });
this._scrollView.add_actor(this._box);
this._items = {};
this.actor.connect('key-focus-in', this._moveFocusToItems.bind(this));
},
_moveFocusToItems() {
let hasItems = Object.keys(this._items).length > 0;
if (!hasItems)
return;
if (global.stage.get_key_focus() != this.actor)
return;
let focusSet = this.actor.navigate_focus(null, Gtk.DirectionType.TAB_FORWARD, false);
if (!focusSet) {
Meta.later_add(Meta.LaterType.BEFORE_REDRAW, () => {
this._moveFocusToItems();
return false;
});
}
},
_onItemActivated(activatedItem) {
this.emit('activate', activatedItem.key);
},
scrollToItem(item) {
let box = item.actor.get_allocation_box();
let adjustment = this._scrollView.get_vscroll_bar().get_adjustment();
let value = (box.y1 + adjustment.step_increment / 2.0) - (adjustment.page_size / 2.0);
Tweener.removeTweens(adjustment);
Tweener.addTween (adjustment,
{ value: value,
time: _SCROLL_ANIMATION_TIME,
transition: 'easeOutQuad' });
},
jumpToItem(item) {
let box = item.actor.get_allocation_box();
let adjustment = this._scrollView.get_vscroll_bar().get_adjustment();
let value = (box.y1 + adjustment.step_increment / 2.0) - (adjustment.page_size / 2.0);
adjustment.set_value(value);
},
getItem(key) {
let item = this._items[key];
if (!item)
return null;
return item;
},
addItem(key, text) {
this.removeItem(key);
let item = new AuthListItem(key, text);
this._box.add(item.actor, { x_fill: true });
this._items[key] = item;
item.connect('activate',
this._onItemActivated.bind(this));
// Try to keep the focused item front-and-center
item.actor.connect('key-focus-in',
() => { this.scrollToItem(item); });
this._moveFocusToItems();
this.emit('item-added', item);
},
removeItem(key) {
let item = this._items[key];
if (!item)
return;
item.actor.destroy();
delete this._items[key];
},
numItems() {
return Object.keys(this._items).length;
},
clear() {
this.label.text = "";
this._box.destroy_all_children();
this._items = {};
}
});
Signals.addSignalMethods(AuthList.prototype);

View File

@ -2,14 +2,17 @@
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 Signals = imports.signals;
const St = imports.gi.St;
const Animation = imports.ui.animation;
const AuthList = imports.gdm.authList;
const Batch = imports.gdm.batch;
const GdmUtil = imports.gdm.util;
const Meta = imports.gi.Meta;
const Params = imports.misc.params;
const ShellEntry = imports.ui.shellEntry;
const Tweener = imports.ui.tweener;
@ -47,6 +50,8 @@ var AuthPrompt = new Lang.Class({
this._gdmClient = gdmClient;
this._mode = mode;
this._idleMonitor = Meta.IdleMonitor.get_core();
let reauthenticationOnly;
if (this._mode == AuthPromptMode.UNLOCK_ONLY)
reauthenticationOnly = true;
@ -57,6 +62,7 @@ var AuthPrompt = new Lang.Class({
this._userVerifier.connect('ask-question', this._onAskQuestion.bind(this));
this._userVerifier.connect('show-message', this._onShowMessage.bind(this));
this._userVerifier.connect('show-choice-list', this._onShowChoiceList.bind(this));
this._userVerifier.connect('verification-failed', this._onVerificationFailed.bind(this));
this._userVerifier.connect('verification-complete', this._onVerificationComplete.bind(this));
this._userVerifier.connect('reset', this._onReset.bind(this));
@ -66,11 +72,16 @@ var AuthPrompt = new Lang.Class({
this.connect('next', () => {
this.updateSensitivity(false);
this.startSpinning();
if (this._queryingService) {
this.startSpinning();
this._userVerifier.answerQuery(this._queryingService, this._entry.text);
} else {
this._preemptiveAnswer = this._entry.text;
if (this._preemptiveAnswerWatchId) {
this._idleMonitor.remove_watch(this._preemptiveAnswerWatchId);
this._preemptiveAnswerWatchId = 0;
}
}
});
@ -109,6 +120,33 @@ var AuthPrompt = new Lang.Class({
this._entry.grab_key_focus();
this._timedLoginIndicator = new St.Bin({ style_class: 'login-dialog-timed-login-indicator',
scale_x: 0 });
this.actor.add(this._timedLoginIndicator);
this._authList = new AuthList.AuthList();
this._authList.connect('activate', (list, key) => {
this._authList.actor.reactive = false;
Tweener.addTween(this._authList.actor,
{ opacity: 0,
time: MESSAGE_FADE_OUT_ANIMATION_TIME,
transition: 'easeOutQuad',
onComplete: () => {
this._authList.clear();
this._authList.actor.hide();
this._userVerifier.selectChoice(this._queryingService, key);
}
});
});
this._authList.actor.hide();
this.actor.add(this._authList.actor,
{ expand: true,
x_fill: true,
y_fill: false,
x_align: St.Align.START });
this._message = new St.Label({ opacity: 0,
styleClass: 'login-dialog-message' });
this._message.clutter_text.line_wrap = true;
@ -134,7 +172,46 @@ var AuthPrompt = new Lang.Class({
this._defaultButtonWell.add_child(this._spinner.actor);
},
showTimedLoginIndicator(time) {
let hold = new Batch.Hold();
this.hideTimedLoginIndicator();
let startTime = GLib.get_monotonic_time();
this._timedLoginTimeoutId = GLib.timeout_add (GLib.PRIORITY_DEFAULT, 33,
() => {
let currentTime = GLib.get_monotonic_time();
let elapsedTime = (currentTime - startTime) / GLib.USEC_PER_SEC;
this._timedLoginIndicator.scale_x = elapsedTime / time;
if (elapsedTime >= time) {
this._timedLoginTimeoutId = 0;
hold.release();
return GLib.SOURCE_REMOVE;
}
return GLib.SOURCE_CONTINUE;
});
GLib.Source.set_name_by_id(this._timedLoginTimeoutId, '[gnome-shell] this._timedLoginTimeoutId');
return hold;
},
hideTimedLoginIndicator() {
if (this._timedLoginTimeoutId) {
GLib.source_remove(this._timedLoginTimeoutId);
this._timedLoginTimeoutId = 0;
}
this._timedLoginIndicator.scale_x = 0.;
},
_onDestroy() {
if (this._preemptiveAnswerWatchId) {
this._idleMonitor.remove_watch(this._preemptiveAnswerWatchId);
this._preemptiveAnswerWatchId = 0;
}
this._userVerifier.destroy();
this._userVerifier = null;
},
@ -176,7 +253,7 @@ var AuthPrompt = new Lang.Class({
this._updateNextButtonSensitivity(this._entry.text.length > 0);
this._entry.clutter_text.connect('text-changed', () => {
if (!this._userVerifier.hasPendingMessages)
if (!this._userVerifier.hasPendingMessages && this._queryingService && !this._preemptiveAnswer)
this._fadeOutMessage();
this._updateNextButtonSensitivity(this._entry.text.length > 0 || this.verificationStatus == AuthPromptStatus.VERIFYING);
@ -213,6 +290,21 @@ var AuthPrompt = new Lang.Class({
this.emit('prompted');
},
_onShowChoiceList(userVerifier, serviceName, promptMessage, choiceList) {
if (this._queryingService)
this.clear();
this._queryingService = serviceName;
if (this._preemptiveAnswer)
this._preemptiveAnswer = null;
this.nextButton.label = _("Next");
this.setChoiceList(promptMessage, choiceList);
this.updateSensitivity(true);
this.emit('prompted');
},
_onOVirtUserAuthenticated() {
if (this.verificationStatus != AuthPromptStatus.VERIFICATION_SUCCEEDED)
this.reset();
@ -341,6 +433,8 @@ var AuthPrompt = new Lang.Class({
clear() {
this._entry.text = '';
this.stopSpinning();
this._authList.clear();
this._authList.actor.hide();
},
setPasswordChar(passwordChar) {
@ -349,14 +443,49 @@ var AuthPrompt = new Lang.Class({
},
setQuestion(question) {
if (this._preemptiveAnswerWatchId) {
this._idleMonitor.remove_watch(this._preemptiveAnswerWatchId);
this._preemptiveAnswerWatchId = 0;
}
this._label.set_text(question);
this._authList.actor.hide();
this._label.show();
this._entry.show();
this._entry.grab_key_focus();
},
_fadeInChoiceList() {
this._authList.actor.opacity = 0;
this._authList.actor.show();
this._authList.actor.reactive = false;
Tweener.addTween(this._authList.actor,
{ opacity: 255,
time: MESSAGE_FADE_OUT_ANIMATION_TIME,
transition: 'easeOutQuad',
onComplete: () => {
this._authList.actor.reactive = true;
}
});
},
setChoiceList(promptMessage, choiceList) {
this._authList.clear();
this._authList.label.text = promptMessage;
for (let key in choiceList) {
let text = choiceList[key];
this._authList.addItem(key, text);
}
this._label.hide();
this._entry.hide();
if (this._message.text == "")
this._message.hide();
this._fadeInChoiceList();
},
getAnswer() {
let text;
@ -392,6 +521,7 @@ var AuthPrompt = new Lang.Class({
else
this._message.remove_style_class_name('login-dialog-message-hint');
this._message.show();
if (message) {
Tweener.removeTweens(this._message);
this._message.text = message;
@ -407,7 +537,7 @@ var AuthPrompt = new Lang.Class({
},
updateSensitivity(sensitive) {
this._updateNextButtonSensitivity(sensitive && (this._entry.text.length > 0 || this.verificationStatus == AuthPromptStatus.VERIFYING));
this._updateNextButtonSensitivity(sensitive && !this._authList.actor.visible && (this._entry.text.length > 0 || this.verificationStatus == AuthPromptStatus.VERIFYING));
this._entry.reactive = sensitive;
this._entry.clutter_text.editable = sensitive;
},
@ -434,12 +564,31 @@ var AuthPrompt = new Lang.Class({
}
},
_onUserStoppedTypePreemptiveAnswer() {
if (!this._preemptiveAnswerWatchId ||
this._preemptiveAnswer ||
this._queryingService)
return;
this._idleMonitor.remove_watch(this._preemptiveAnswerWatchId);
this._preemptiveAnswerWatchId = 0;
this._entry.text = '';
this.updateSensitivity(false);
},
reset() {
let oldStatus = this.verificationStatus;
this.verificationStatus = AuthPromptStatus.NOT_VERIFYING;
this.cancelButton.reactive = true;
this.nextButton.label = _("Next");
if (this._preemptiveAnswerWatchId) {
this._idleMonitor.remove_watch(this._preemptiveAnswerWatchId);
}
this._preemptiveAnswerWatchId = this._idleMonitor.add_idle_watch (500,
this._onUserStoppedTypePreemptiveAnswer.bind(this));
if (this._userVerifier)
this._userVerifier.cancel();

View File

@ -418,6 +418,11 @@ var LoginDialog = new Lang.Class({
this._userManager = AccountsService.UserManager.get_default()
this._gdmClient = new Gdm.Client();
try {
this._gdmClient.set_enabled_extensions([Gdm.UserVerifierChoiceList.interface_info().name]);
} catch(e) {
}
this._settings = new Gio.Settings({ schema_id: GdmUtil.LOGIN_SCREEN_SCHEMA });
this._settings.connect('changed::' + GdmUtil.BANNER_MESSAGE_KEY,
@ -738,6 +743,9 @@ var LoginDialog = new Lang.Class({
if (this._authPrompt.verificationStatus == AuthPrompt.AuthPromptStatus.NOT_VERIFYING)
this._authPrompt.reset();
if (this._disableUserList && this._timedLoginUserListHold)
this._timedLoginUserListHold.release();
}
},
@ -1019,17 +1027,33 @@ var LoginDialog = new Lang.Class({
},
_startTimedLogin(userName, delay) {
this._timedLoginUserName = userName;
this._timedLoginItem = null;
this._timedLoginDelay = delay;
this._timedLoginAnimationTime = delay;
let tasks = [() => this._waitForItemForUser(userName),
let tasks = [() => {
if (this._disableUserList)
return;
this._timedLoginUserListHold = this._waitForItemForUser(userName);
return this._timedLoginUserListHold;
},
() => {
this._timedLoginUserListHold = null;
if (this._disableUserList)
return;
this._timedLoginItem = this._userList.getItemFromUserName(userName);
},
() => {
if (this._disableUserList)
return;
// If we're just starting out, start on the right
// item.
if (!this._userManager.is_loaded) {
@ -1040,6 +1064,9 @@ var LoginDialog = new Lang.Class({
this._blockTimedLoginUntilIdle,
() => {
if (this._disableUserList)
return;
this._userList.scrollToItem(this._timedLoginItem);
},
@ -1064,7 +1091,9 @@ var LoginDialog = new Lang.Class({
if (this._timedLoginItem)
this._timedLoginItem.hideTimedLoginIndicator();
let userName = this._timedLoginItem.user.get_user_name();
this._authPrompt.hideTimedLoginIndicator();
let userName = this._timedLoginUserName;
if (userName)
this._startTimedLogin(userName, this._timedLoginDelay);

View File

@ -134,7 +134,6 @@ var ShellUserVerifier = new Lang.Class({
this._settings = new Gio.Settings({ schema_id: LOGIN_SCREEN_SCHEMA });
this._settings.connect('changed',
this._updateDefaultService.bind(this));
this._updateDefaultService();
this._fprintManager = Fprint.FprintManager();
this._smartcardManager = SmartcardManager.getSmartcardManager();
@ -146,6 +145,8 @@ var ShellUserVerifier = new Lang.Class({
this.smartcardDetected = false;
this._checkForSmartcard();
this._updateDefaultService();
this._smartcardInsertedId = this._smartcardManager.connect('smartcard-inserted',
this._checkForSmartcard.bind(this));
this._smartcardRemovedId = this._smartcardManager.connect('smartcard-removed',
@ -199,6 +200,10 @@ var ShellUserVerifier = new Lang.Class({
if (this._userVerifier) {
this._userVerifier.run_dispose();
this._userVerifier = null;
if (this._userVerifierChoiceList) {
this._userVerifierChoiceList.run_dispose();
this._userVerifierChoiceList = null;
}
}
},
@ -226,6 +231,10 @@ var ShellUserVerifier = new Lang.Class({
this._oVirtCredentialsManager = null;
},
selectChoice(serviceName, key) {
this._userVerifierChoiceList.call_select_choice(serviceName, key, this._cancellable, null);
},
answerQuery(serviceName, answer) {
if (!this.hasPendingMessages) {
this._userVerifier.call_answer_query(serviceName, answer, this._cancellable, null);
@ -334,6 +343,8 @@ var ShellUserVerifier = new Lang.Class({
else if (this._preemptingService == SMARTCARD_SERVICE_NAME)
this._preemptingService = null;
this._updateDefaultService();
this.emit('smartcard-status-changed');
}
},
@ -364,6 +375,11 @@ var ShellUserVerifier = new Lang.Class({
return;
}
if (client.get_user_verifier_choice_list)
this._userVerifierChoiceList = client.get_user_verifier_choice_list();
else
this._userVerifierChoiceList = null;
this.reauthenticating = true;
this._connectSignals();
this._beginVerification();
@ -381,6 +397,11 @@ var ShellUserVerifier = new Lang.Class({
return;
}
if (client.get_user_verifier_choice_list)
this._userVerifierChoiceList = client.get_user_verifier_choice_list();
else
this._userVerifierChoiceList = null;
this._connectSignals();
this._beginVerification();
this._hold.release();
@ -394,6 +415,9 @@ var ShellUserVerifier = new Lang.Class({
this._userVerifier.connect('conversation-stopped', this._onConversationStopped.bind(this));
this._userVerifier.connect('reset', this._onReset.bind(this));
this._userVerifier.connect('verification-complete', this._onVerificationComplete.bind(this));
if (this._userVerifierChoiceList)
this._userVerifierChoiceList.connect('choice-query', this._onChoiceListQuery.bind(this));
},
_getForegroundService() {
@ -412,7 +436,9 @@ var ShellUserVerifier = new Lang.Class({
},
_updateDefaultService() {
if (this._settings.get_boolean(PASSWORD_AUTHENTICATION_KEY))
if (this._smartcardManager.loggedInWithToken())
this._defaultService = SMARTCARD_SERVICE_NAME;
else if (this._settings.get_boolean(PASSWORD_AUTHENTICATION_KEY))
this._defaultService = PASSWORD_SERVICE_NAME;
else if (this._settings.get_boolean(SMARTCARD_AUTHENTICATION_KEY))
this._defaultService = SMARTCARD_SERVICE_NAME;
@ -468,6 +494,13 @@ var ShellUserVerifier = new Lang.Class({
this._startService(FINGERPRINT_SERVICE_NAME);
},
_onChoiceListQuery(client, serviceName, promptMessage, list) {
if (!this.serviceIsForeground(serviceName))
return;
this.emit('show-choice-list', serviceName, promptMessage, list.deep_unpack());
},
_onInfo(client, serviceName, info) {
if (this.serviceIsForeground(serviceName)) {
this._queueMessage(info, MessageType.INFO);

View File

@ -1,6 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<gresources>
<gresource prefix="/org/gnome/shell">
<file>gdm/authList.js</file>
<file>gdm/authPrompt.js</file>
<file>gdm/batch.js</file>
<file>gdm/fingerprint.js</file>
@ -18,6 +19,7 @@
<file>misc/history.js</file>
<file>misc/ibusManager.js</file>
<file>misc/inputMethod.js</file>
<file>misc/introspect.js</file>
<file>misc/jsParse.js</file>
<file>misc/keyboardManager.js</file>
<file>misc/loginManager.js</file>
@ -130,6 +132,7 @@
<file>ui/status/rfkill.js</file>
<file>ui/status/volume.js</file>
<file>ui/status/bluetooth.js</file>
<file>ui/status/remoteAccess.js</file>
<file>ui/status/screencast.js</file>
<file>ui/status/system.js</file>
<file>ui/status/thunderbolt.js</file>

View File

@ -13,7 +13,8 @@ const FileUtils = imports.misc.fileUtils;
var ExtensionType = {
SYSTEM: 1,
PER_USER: 2
PER_USER: 2,
SESSION_MODE: 3
};
// Maps uuid -> metadata object

View File

@ -115,6 +115,11 @@ var IBusManager = new Lang.Class({
object_path: IBus.PATH_PANEL });
this._candidatePopup.setPanelService(this._panelService);
this._panelService.connect('update-property', this._updateProperty.bind(this));
this._panelService.connect('set-cursor-location', (ps, x, y, w, h) => {
let cursorLocation = { x, y, width: w, height: h };
this.emit('set-cursor-location', cursorLocation);
});
try {
// IBus versions older than 1.5.10 have a bug which
// causes spurious set-content-type emissions when

View File

@ -15,6 +15,8 @@ var InputMethod = new Lang.Class({
this._purpose = 0;
this._enabled = true;
this._currentFocus = null;
this._preeditStr = '';
this._preeditPos = 0;
this._ibus = IBus.Bus.new_async();
this._ibus.connect('connected', this._onConnected.bind(this));
this._ibus.connect('disconnected', this._clear.bind(this));
@ -64,6 +66,9 @@ var InputMethod = new Lang.Class({
this._context.connect('commit-text', this._onCommitText.bind(this));
this._context.connect('delete-surrounding-text', this._onDeleteSurroundingText.bind(this));
this._context.connect('update-preedit-text', this._onUpdatePreeditText.bind(this));
this._context.connect('show-preedit-text', this._onShowPreeditText.bind(this));
this._context.connect('hide-preedit-text', this._onHidePreeditText.bind(this));
this._context.connect('forward-key-event', this._onForwardKeyEvent.bind(this));
this._updateCapabilities();
},
@ -73,6 +78,8 @@ var InputMethod = new Lang.Class({
this._hints = 0;
this._purpose = 0;
this._enabled = false;
this._preeditStr = ''
this._preeditPos = 0;
},
_emitRequestSurrounding() {
@ -89,11 +96,36 @@ var InputMethod = new Lang.Class({
},
_onUpdatePreeditText(context, text, pos, visible) {
let str = null;
if (visible && text != null)
str = text.get_text();
if (text == null)
return;
this._preeditStr = text.get_text();
this._preeditPos = pos;
if (visible)
this.set_preedit_text(this._preeditStr, pos);
else
this.set_preedit_text(null, pos);
},
this.set_preedit_text(str, pos);
_onShowPreeditText(context) {
this.set_preedit_text(this._preeditStr, this._preeditPos);
},
_onHidePreeditText(context) {
this.set_preedit_text(null, this._preeditPos);
},
_onForwardKeyEvent(context, keyval, keycode, state) {
let press = (state & IBus.ModifierType.RELEASE_MASK) == 0;
state &= ~(IBus.ModifierType.RELEASE_MASK);
let curEvent = Clutter.get_current_event();
let time;
if (curEvent)
time = curEvent.get_time();
else
time = global.display.get_current_time_roundtrip();
this.forward_key(keyval, keycode + 8, state & Clutter.ModifierType.MODIFIER_MASK, time, press);
},
vfunc_focus_in(focus) {
@ -135,8 +167,11 @@ var InputMethod = new Lang.Class({
},
vfunc_set_surrounding(text, cursor, anchor) {
if (this._context)
this._context.set_surrounding_text(text, cursor, anchor);
if (!this._context || !text)
return;
let ibusText = IBus.Text.new_from_string(text);
this._context.set_surrounding_text(ibusText, cursor, anchor);
},
vfunc_update_content_hints(hints) {
@ -197,6 +232,7 @@ var InputMethod = new Lang.Class({
if (event.type() == Clutter.EventType.KEY_RELEASE)
state |= IBus.ModifierType.RELEASE_MASK;
this._context.process_key_event_async(event.get_key_symbol(),
event.get_key_code() - 8, // Convert XKB keycodes to evcodes
state, -1, null,

174
js/misc/introspect.js Normal file
View File

@ -0,0 +1,174 @@
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 INTROSPECT_SCHEMA = 'org.gnome.shell';
const INTROSPECT_KEY = 'introspect';
const APP_WHITELIST = ['org.freedesktop.impl.portal.desktop.gtk'];
const IntrospectDBusIface = '<node> \
<interface name="org.gnome.Shell.Introspect"> \
<signal name="RunningApplicationsChanged" /> \
<method name="GetRunningApplications"> \
<arg name="apps" direction="out" type="a{sa{sv}}" /> \
</method> \
<method name="GetWindows"> \
<arg name="windows" direction="out" type="a{ta{sv}}" /> \
</method> \
</interface> \
</node>';
var IntrospectService = new Lang.Class({
Name: 'IntrospectService',
_init() {
this._dbusImpl = Gio.DBusExportedObject.wrapJSObject(IntrospectDBusIface,
this);
this._dbusImpl.export(Gio.DBus.session, '/org/gnome/Shell/Introspect');
Gio.DBus.session.own_name('org.gnome.Shell.Introspect',
Gio.BusNameOwnerFlags.REPLACE,
null, null);
this._runningApplications = {};
this._runningApplicationsDirty = true;
this._activeApplication = null;
this._activeApplicationDirty = true;
this._appSystem = Shell.AppSystem.get_default();
this._appSystem.connect('app-state-changed',
() => {
this._runningApplicationsDirty = true;
this._syncRunningApplications();
});
this._settings = new Gio.Settings({ schema_id: INTROSPECT_SCHEMA });
let tracker = Shell.WindowTracker.get_default();
tracker.connect('notify::focus-app',
() => {
this._activeApplicationDirty = true;
this._syncRunningApplications();
});
this._syncRunningApplications();
},
_isStandaloneApp(app) {
let windows = app.get_windows();
return app.get_windows().some(w => w.transient_for == null);
},
_isIntrospectEnabled() {
return this._settings.get_boolean(INTROSPECT_KEY);
},
_isSenderWhitelisted(sender) {
return APP_WHITELIST.includes(sender);
},
_syncRunningApplications() {
let tracker = Shell.WindowTracker.get_default();
let apps = this._appSystem.get_running();
let seatName = "seat0";
let newRunningApplications = {};
let newActiveApplication = null;
let focusedApp = tracker.focus_app;
for (let app of apps) {
let appInfo = {};
let isAppActive = (focusedApp == app);
if (!this._isStandaloneApp(app))
continue;
if (isAppActive) {
appInfo['active-on-seats'] = new GLib.Variant('as', [seatName]);
newActiveApplication = app.get_id();
}
newRunningApplications[app.get_id()] = appInfo;
}
if (this._runningApplicationsDirty ||
(this._activeApplicationDirty &&
this._activeApplication != newActiveApplication)) {
this._runningApplications = newRunningApplications;
this._activeApplication = newActiveApplication;
this._dbusImpl.emit_signal('RunningApplicationsChanged', null);
}
this._runningApplicationsDirty = false;
this._activeApplicationDirty = false;
},
_isEligibleWindow(window) {
if (window.is_override_redirect())
return false;
let type = window.get_window_type();
return (type == Meta.WindowType.NORMAL ||
type == Meta.WindowType.DIALOG ||
type == Meta.WindowType.MODAL_DIALOG ||
type == Meta.WindowType.UTILITY);
},
GetRunningApplicationsAsync(params, invocation) {
if (!this._isIntrospectEnabled() &&
!this._isSenderWhitelisted(invocation.get_sender())) {
invocation.return_error_literal(Gio.DBusError,
Gio.DBusError.ACCESS_DENIED,
'App introspection not allowed');
return;
}
invocation.return_value(new GLib.Variant('(a{sa{sv}})', [this._runningApplications]));
},
GetWindowsAsync(params, invocation) {
let focusWindow = global.display.get_focus_window();
let apps = this._appSystem.get_running();
let windowsList = {};
if (!this._isIntrospectEnabled()) {
invocation.return_error_literal(Gio.DBusError,
Gio.DBusError.ACCESS_DENIED,
'App introspection not allowed');
return;
}
for (let app of apps) {
let windows = app.get_windows();
for (let window of windows) {
if (!this._isEligibleWindow(window))
continue;
let windowId = window.get_id();
let frameRect = window.get_frame_rect();
let title = window.get_title();
let wmClass = window.get_wm_class();
windowsList[windowId] = {
'app-id': GLib.Variant.new('s', app.get_id()),
'client-type': GLib.Variant.new('u', window.get_client_type()),
'is-hidden': GLib.Variant.new('b', window.is_hidden()),
'has-focus': GLib.Variant.new('b', (window == focusWindow)),
'width': GLib.Variant.new('u', frameRect.width),
'height': GLib.Variant.new('u', frameRect.height)
};
// These properties may not be available for all windows:
if (title != null)
windowsList[windowId]['title'] = GLib.Variant.new('s', title);
if (wmClass != null)
windowsList[windowId]['wm-class'] = GLib.Variant.new('s', wmClass);
}
}
invocation.return_value(new GLib.Variant('(a{ta{sv}})', [windowsList]));
}
});

View File

@ -52,11 +52,20 @@ var KeyboardManager = new Lang.Class({
this._current = null;
this._localeLayoutInfo = this._getLocaleLayout();
this._layoutInfos = {};
this._currentKeymap = null;
},
_applyLayoutGroup(group) {
let options = this._buildOptionsString();
let [layouts, variants] = this._buildGroupStrings(group);
if (this._currentKeymap &&
this._currentKeymap.layouts == layouts &&
this._currentKeymap.variants == variants &&
this._currentKeymap.options == options)
return;
this._currentKeymap = {layouts, variants, options};
Meta.get_backend().set_keymap(layouts, variants, options);
},

View File

@ -112,6 +112,13 @@ var SmartcardManager = new Lang.Class({
return false;
return true;
},
loggedInWithToken() {
if (this._loginToken)
return true;
return false;
}
});

View File

@ -1628,6 +1628,20 @@ var AppIcon = new Lang.Class({
this.actor.connect('clicked', this._onClicked.bind(this));
this.actor.connect('popup-menu', this._onKeyboardPopupMenu.bind(this));
this._hoverText = null;
this._hoverTimeoutId = 0;
if (this.icon.label) {
this._hoverText = new St.Label({ style_class: 'app-well-hover-text',
text: this.icon.label.text,
visible: false });
this._hoverText.clutter_text.line_wrap = true;
Main.layoutManager.addChrome(this._hoverText);
this.actor.connect('notify::hover', this._syncHoverText.bind(this));
this.connect('sync-tooltip', this._syncHoverText.bind(this));
}
this._menu = null;
this._menuManager = new PopupMenu.PopupMenuManager(this);
@ -1659,12 +1673,39 @@ var AppIcon = new Lang.Class({
this.app.disconnect(this._stateChangedId);
this._stateChangedId = 0;
this._removeMenuTimeout();
this._removeHoverTimeout();
if (this._hoverText)
this._hoverText.destroy();
this._hoverText = null;
},
_createIcon(iconSize) {
return this.app.create_icon_texture(iconSize);
},
_syncHoverText() {
if (this.shouldShowTooltip()) {
if (this._hoverTimeoutId)
return;
this._hoverTimeoutId = Mainloop.timeout_add(300, () => {
this._hoverText.style = `max-width: ${2 * this.icon.iconSize}px;`;
this._hoverText.ensure_style();
let [x, y] = this.icon.label.get_transformed_position();
let offset = (this._hoverText.width - this.icon.label.width) / 2;
this._hoverText.set_position(Math.floor(x - offset), Math.floor(y));
this._hoverText.show();
this._hoverTimeoutId = 0;
return GLib.SOURCE_REMOVE;
});
} else {
this._removeHoverTimeout();
this._hoverText.hide();
}
},
_removeMenuTimeout() {
if (this._menuTimeoutId > 0) {
Mainloop.source_remove(this._menuTimeoutId);
@ -1672,6 +1713,13 @@ var AppIcon = new Lang.Class({
}
},
_removeHoverTimeout() {
if (this._hoverTimeoutId > 0) {
Mainloop.source_remove(this._hoverTimeoutId);
this._hoverTimeoutId = 0;
}
},
_updateRunningStyle() {
if (this.app.state != Shell.AppState.STOPPED)
this._dot.show();

View File

@ -41,6 +41,7 @@ const RENAMED_DESKTOP_IDS = {
'gnotravex.desktop': 'gnome-tetravex.desktop',
'gnotski.desktop': 'gnome-klotski.desktop',
'gtali.desktop': 'tali.desktop',
'mozilla-firefox.desktop': 'firefox.desktop',
'nautilus.desktop': 'org.gnome.Nautilus.desktop',
'polari.desktop': 'org.gnome.Polari.desktop',
'totem.desktop': 'org.gnome.Totem.desktop',

View File

@ -264,7 +264,7 @@ var Background = new Lang.Class({
(lm, aboutToSuspend) => {
if (aboutToSuspend)
return;
this._refreshAnimation();
this.emit('changed');
});
this._settingsChangedSignalId = this._settings.connect('changed', () => {
@ -539,10 +539,15 @@ var BackgroundSource = new Lang.Class({
this._backgrounds = [];
this._monitorsChangedId = global.screen.connect('monitors-changed',
this._onMonitorsChanged.bind(this));
this._refresh.bind(this));
global.display.connect('gl-video-memory-purged', () => {
Meta.Background.refresh_all();
this._refresh();
});
},
_onMonitorsChanged() {
_refresh() {
for (let monitorIndex in this._backgrounds) {
let background = this._backgrounds[monitorIndex];

View File

@ -802,6 +802,8 @@ var NotificationMessage = new Lang.Class({
},
_onDestroy() {
this.parent();
if (this._updatedId)
this.notification.disconnect(this._updatedId);
this._updatedId = 0;
@ -821,6 +823,8 @@ var EventsSection = new Lang.Class({
this._desktopSettings.connect('changed', this._reloadEvents.bind(this));
this._eventSource = new EmptyEventSource();
this._messageById = new Map();
this.parent();
this._title = new St.Button({ style_class: 'events-section-title',
@ -875,20 +879,32 @@ var EventsSection = new Lang.Class({
this._reloading = true;
this._list.destroy_all_children();
let periodBegin = _getBeginningOfDay(this._date);
let periodEnd = _getEndOfDay(this._date);
let events = this._eventSource.getEvents(periodBegin, periodEnd);
let ids = events.map(e => e.id);
this._messageById.forEach((message, id) => {
if (ids.includes(id))
return;
this._messageById.delete(id);
this.removeMessage(message);
});
for (let i = 0; i < events.length; i++) {
let event = events[i];
let message = new EventMessage(event, this._date);
message.connect('close', () => {
this._ignoreEvent(event);
});
this.addMessage(message, false);
let message = this._messageById.get(event.id);
if (!message) {
message = new EventMessage(event, this._date);
message.connect('close', () => {
this._ignoreEvent(event);
});
this._messageById.set(event.id, message);
this.addMessage(message, false);
} else {
this.moveMessage(message, i, false);
}
}
this._reloading = false;

View File

@ -2,6 +2,7 @@
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 Meta = imports.gi.Meta;
@ -13,6 +14,7 @@ const Tweener = imports.ui.tweener;
var FROZEN_WINDOW_BRIGHTNESS = -0.3
var DIALOG_TRANSITION_TIME = 0.15
var ALIVE_TIMEOUT = 5000;
var CloseDialog = new Lang.Class({
Name: 'CloseDialog',
@ -26,6 +28,10 @@ var CloseDialog = new Lang.Class({
this.parent();
this._window = window;
this._dialog = null;
this._tracked = undefined;
this._timeoutId = 0;
this._windowFocusChangedId = 0;
this._keyFocusChangedId = 0;
},
get window() {
@ -93,10 +99,57 @@ var CloseDialog = new Lang.Class({
this.response(Meta.CloseDialogResponse.FORCE_CLOSE);
},
_onFocusChanged() {
if (Meta.is_wayland_compositor())
return;
let focusWindow = global.display.focus_window;
let keyFocus = global.stage.key_focus;
let shouldTrack;
if (focusWindow != null)
shouldTrack = focusWindow == this._window;
else
shouldTrack = keyFocus && this._dialog.contains(keyFocus);
if (this._tracked === shouldTrack)
return;
if (shouldTrack)
Main.layoutManager.trackChrome(this._dialog,
{ affectsInputRegion: true });
else
Main.layoutManager.untrackChrome(this._dialog);
// The buttons are broken when they aren't added to the input region,
// so disable them properly in that case
this._dialog.buttonLayout.get_children().forEach(b => {
b.reactive = shouldTrack;
});
this._tracked = shouldTrack;
},
vfunc_show() {
if (this._dialog != null)
return;
Meta.disable_unredirect_for_screen(global.screen);
this._timeoutId = GLib.timeout_add(GLib.PRIORITY_DEFAULT, ALIVE_TIMEOUT,
() => {
this._window.check_alive(global.display.get_current_time_roundtrip());
return GLib.SOURCE_CONTINUE;
});
this._windowFocusChangedId =
global.display.connect('notify::focus-window',
this._onFocusChanged.bind(this));
this._keyFocusChangedId =
global.stage.connect('notify::key-focus',
this._onFocusChanged.bind(this));
this._addWindowEffect();
this._initDialog();
@ -107,9 +160,7 @@ var CloseDialog = new Lang.Class({
{ scale_y: 1,
transition: 'linear',
time: DIALOG_TRANSITION_TIME,
onComplete: () => {
Main.layoutManager.trackChrome(this._dialog, { affectsInputRegion: true });
}
onComplete: this._onFocusChanged.bind(this)
});
},
@ -117,6 +168,17 @@ var CloseDialog = new Lang.Class({
if (this._dialog == null)
return;
Meta.enable_unredirect_for_screen(global.screen);
GLib.source_remove(this._timeoutId);
this._timeoutId = 0;
global.display.disconnect(this._windowFocusChangedId)
this._windowFocusChangedId = 0;
global.stage.disconnect(this._keyFocusChangedId);
this._keyFocusChangedId = 0;
let dialog = this._dialog;
this._dialog = null;
this._removeWindowEffect();

View File

@ -210,6 +210,10 @@ var AutomountManager = new Lang.Class({
},
_onVolumeRemoved(monitor, volume) {
if (volume._allowAutorunExpireId && volume._allowAutorunExpireId > 0) {
Mainloop.source_remove(volume._allowAutorunExpireId);
delete volume._allowAutorunExpireId;
}
this._volumeQueue =
this._volumeQueue.filter(element => (element != volume));
},
@ -234,8 +238,10 @@ var AutomountManager = new Lang.Class({
_allowAutorunExpire(volume) {
let id = Mainloop.timeout_add_seconds(AUTORUN_EXPIRE_TIMEOUT_SECS, () => {
volume.allowAutorun = false;
delete volume._allowAutorunExpireId;
return GLib.SOURCE_REMOVE;
});
volume._allowAutorunExpireId = id;
GLib.Source.set_name_by_id(id, '[gnome-shell] volume.allowAutorun');
}
});

View File

@ -655,7 +655,7 @@ var NetworkAgent = new Lang.Class({
switch (connectionType) {
case '802-11-wireless':
let wirelessSetting = connection.get_setting_wireless();
let ssid = NM.utils_ssid_to_utf8(wirelessSetting.get_ssid());
let ssid = NM.utils_ssid_to_utf8(wirelessSetting.get_ssid().get_data());
title = _("Authentication required by wireless network");
body = _("Passwords or encryption keys are required to access the wireless network “%s”.").format(ssid);
break;

View File

@ -201,7 +201,9 @@ var AuthenticationDialog = new Lang.Class({
close(timestamp) {
this.parent(timestamp);
Main.sessionMode.disconnect(this._sessionUpdatedId);
if (this._sessionUpdatedId)
Main.sessionMode.disconnect(this._sessionUpdatedId);
this._sessionUpdatedId = 0;
},
_ensureOpen() {

View File

@ -27,6 +27,12 @@ var DragMotionResult = {
CONTINUE: 3
};
var DragState = {
INIT: 0,
DRAGGING: 1,
CANCELLED: 2,
};
var DRAG_CURSOR_MAP = {
0: Meta.Cursor.DND_UNSUPPORTED_TARGET,
1: Meta.Cursor.DND_COPY,
@ -78,6 +84,8 @@ var _Draggable = new Lang.Class({
dragActorOpacity: undefined });
this.actor = actor;
this._dragState = DragState.INIT;
if (!params.manualMode) {
this.actor.connect('button-press-event',
this._onButtonPress.bind(this));
@ -88,7 +96,7 @@ var _Draggable = new Lang.Class({
this.actor.connect('destroy', () => {
this._actorDestroyed = true;
if (this._dragInProgress && this._dragCancellable)
if (this._dragState == DragState.DRAGGING && this._dragCancellable)
this._cancelDrag(global.get_current_time());
this.disconnectAll();
});
@ -100,7 +108,6 @@ var _Draggable = new Lang.Class({
this._dragActorOpacity = params.dragActorOpacity;
this._buttonDown = false; // The mouse button has been pressed and has not yet been released.
this._dragInProgress = false; // The drag has been started, and has not been dropped or cancelled yet.
this._animationInProgress = false; // The drag is over and the item is in the process of animating to its original position (snapping back or reverting).
this._dragCancellable = true;
@ -206,9 +213,10 @@ var _Draggable = new Lang.Class({
(event.type() == Clutter.EventType.TOUCH_END &&
global.display.is_pointer_emulating_sequence(event.get_event_sequence()))) {
this._buttonDown = false;
if (this._dragInProgress) {
if (this._dragState == DragState.DRAGGING) {
return this._dragActorDropped(event);
} else if (this._dragActor != null && !this._animationInProgress) {
} else if ((this._dragActor != null || this._dragState == DragState.CANCELLED) &&
!this._animationInProgress) {
// Drag must have been cancelled with Esc.
this._dragComplete();
return Clutter.EVENT_STOP;
@ -222,14 +230,14 @@ var _Draggable = new Lang.Class({
} 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) {
if (this._dragActor && this._dragState == DragState.DRAGGING) {
return this._updateDragPosition(event);
} else if (this._dragActor == null) {
} else if (this._dragActor == null && this._dragState != DragState.CANCELLED) {
return this._maybeStartDrag(event);
}
// We intercept KEY_PRESS event so that we can process Esc key press to cancel
// dragging and ignore all other key presses.
} else if (event.type() == Clutter.EventType.KEY_PRESS && this._dragInProgress) {
} else if (event.type() == Clutter.EventType.KEY_PRESS && this._dragState == DragState.DRAGGING) {
let symbol = event.get_key_symbol();
if (symbol == Clutter.Escape) {
this._cancelDrag(event.get_time());
@ -265,7 +273,7 @@ var _Draggable = new Lang.Class({
*/
startDrag(stageX, stageY, time, sequence) {
currentDraggable = this;
this._dragInProgress = true;
this._dragState = DragState.DRAGGING;
// Special-case St.Button: the pointer grab messes with the internal
// state, so force a reset to a reasonable state here
@ -342,6 +350,13 @@ var _Draggable = new Lang.Class({
Shell.util_set_hidden_from_pick(this._dragActor, true);
}
this._dragActorDestroyId = this._dragActor.connect('destroy', () => {
// Cancel ongoing animation (if any)
this._finishAnimation();
this._dragActor = null;
this._dragState = DragState.CANCELLED;
});
this._dragOrigOpacity = this._dragActor.opacity;
if (this._dragActorOpacity != undefined)
this._dragActor.opacity = this._dragActorOpacity;
@ -396,10 +411,15 @@ var _Draggable = new Lang.Class({
return true;
},
_pickTargetActor() {
return this._dragActor.get_stage().get_actor_at_pos(Clutter.PickMode.ALL,
this._dragX, this._dragY);
},
_updateDragHover() {
this._updateHoverId = 0;
let target = this._dragActor.get_stage().get_actor_at_pos(Clutter.PickMode.ALL,
this._dragX, this._dragY);
let target = this._pickTargetActor();
let dragEvent = {
x: this._dragX,
y: this._dragY,
@ -407,6 +427,18 @@ var _Draggable = new Lang.Class({
source: this.actor._delegate,
targetActor: target
};
let targetActorDestroyHandlerId;
let handleTargetActorDestroyClosure;
handleTargetActorDestroyClosure = () => {
target = this._pickTargetActor();
dragEvent.targetActor = target;
targetActorDestroyHandlerId =
target.connect('destroy', handleTargetActorDestroyClosure);
};
targetActorDestroyHandlerId =
target.connect('destroy', handleTargetActorDestroyClosure);
for (let i = 0; i < dragMonitors.length; i++) {
let motionFunc = dragMonitors[i].dragMotion;
if (motionFunc) {
@ -417,6 +449,7 @@ var _Draggable = new Lang.Class({
}
}
}
dragEvent.targetActor.disconnect(targetActorDestroyHandlerId);
while (target) {
if (target._delegate && target._delegate.handleDragOver) {
@ -500,7 +533,7 @@ var _Draggable = new Lang.Class({
event.get_time())) {
// If it accepted the drop without taking the actor,
// handle it ourselves.
if (this._dragActor.get_parent() == Main.uiGroup) {
if (this._dragActor && this._dragActor.get_parent() == Main.uiGroup) {
if (this._restoreOnSuccess) {
this._restoreDragActor(event.get_time());
return true;
@ -508,7 +541,7 @@ var _Draggable = new Lang.Class({
this._dragActor.destroy();
}
this._dragInProgress = false;
this._dragState = DragState.INIT;
global.screen.set_cursor(Meta.Cursor.DEFAULT);
this.emit('drag-end', event.get_time(), true);
this._dragComplete();
@ -557,20 +590,22 @@ var _Draggable = new Lang.Class({
_cancelDrag(eventTime) {
this.emit('drag-cancelled', eventTime);
this._dragInProgress = false;
let [snapBackX, snapBackY, snapBackScale] = this._getRestoreLocation();
let wasCancelled = (this._dragState == DragState.CANCELLED);
this._dragState = DragState.CANCELLED;
if (this._actorDestroyed) {
if (this._actorDestroyed || wasCancelled) {
global.screen.set_cursor(Meta.Cursor.DEFAULT);
if (!this._buttonDown)
this._dragComplete();
this.emit('drag-end', eventTime, false);
if (!this._dragOrigParent)
if (!this._dragOrigParent && this._dragActor)
this._dragActor.destroy();
return;
}
let [snapBackX, snapBackY, snapBackScale] = this._getRestoreLocation();
this._animateDragEnd(eventTime,
{ x: snapBackX,
y: snapBackY,
@ -581,7 +616,7 @@ var _Draggable = new Lang.Class({
},
_restoreDragActor(eventTime) {
this._dragInProgress = false;
this._dragState = DragState.INIT;
let [restoreX, restoreY, restoreScale] = this._getRestoreLocation();
// fade the actor back in at its original location
@ -596,12 +631,6 @@ var _Draggable = new Lang.Class({
_animateDragEnd(eventTime, params) {
this._animationInProgress = true;
// finish animation if the actor gets destroyed
// during it
this._dragActorDestroyId =
this._dragActor.connect('destroy',
this._finishAnimation.bind(this));
params['opacity'] = this._dragOrigOpacity;
params['transition'] = 'easeOutQuad';
params['onComplete'] = this._onAnimationComplete;
@ -624,9 +653,6 @@ var _Draggable = new Lang.Class({
},
_onAnimationComplete(dragActor, eventTime) {
dragActor.disconnect(this._dragActorDestroyId);
this._dragActorDestroyId = 0;
if (this._dragOrigParent) {
Main.uiGroup.remove_child(this._dragActor);
this._dragOrigParent.add_actor(this._dragActor);
@ -641,7 +667,7 @@ var _Draggable = new Lang.Class({
},
_dragComplete() {
if (!this._actorDestroyed)
if (!this._actorDestroyed && this._dragActor)
Shell.util_set_hidden_from_pick(this._dragActor, false);
this._ungrabEvents();
@ -652,7 +678,12 @@ var _Draggable = new Lang.Class({
this._updateHoverId = 0;
}
this._dragActor = undefined;
if (this._dragActor) {
this._dragActor.disconnect(this._dragActorDestroyId);
this._dragActor = null;
}
this._dragState = DragState.INIT;
currentDraggable = null;
}
});

View File

@ -7,6 +7,7 @@ const GLib = imports.gi.GLib;
const Gio = imports.gi.Gio;
const St = imports.gi.St;
const Config = imports.misc.config;
const ExtensionUtils = imports.misc.extensionUtils;
const Main = imports.ui.main;
@ -306,6 +307,36 @@ function _onVersionValidationChanged() {
}
}
function _doUpdateCheck() {
let version = Config.PACKAGE_VERSION.split('.');
if (parseInt(version[1]) % 2 == 0)
version.pop();
let pkgCacheDir = GLib.get_user_cache_dir() + '/gnome-shell/';
let updateStamp = Gio.file_new_for_path(pkgCacheDir +
'update-check-' + version.join('.'));
if (updateStamp.query_exists(null))
return;
GLib.mkdir_with_parents (pkgCacheDir, 0o755);
updateStamp.create(0, null).close(null);
let nOutdated = enabledExtensions.reduce(function(n, uuid) {
let extension = ExtensionUtils.extensions[uuid];
if (extension && extension.state == ExtensionState.OUT_OF_DATE)
n++;
return n;
}, 0);
if (nOutdated == 0)
return;
Main.notify(ngettext("%d extension is out of date",
"%d extensions are out of date",
nOutdated).format(nOutdated),
_("You can visit http://extensions.gnome.org for updates"));
}
function _loadExtensions() {
global.settings.connect('changed::' + ENABLED_EXTENSIONS_KEY, onEnabledExtensionsChanged);
global.settings.connect('changed::' + DISABLE_USER_EXTENSIONS_KEY, onEnabledExtensionsChanged);
@ -316,8 +347,11 @@ function _loadExtensions() {
let finder = new ExtensionUtils.ExtensionFinder();
finder.connect('extension-found', (finder, extension) => {
loadExtension(extension);
if (Main.sessionMode.enabledExtensions.indexOf(extension.uuid) != -1)
extension.type = ExtensionUtils.ExtensionType.SESSION_MODE;
});
finder.scanExtensions();
_doUpdateCheck();
}
function enableAllExtensions() {

View File

@ -1,6 +1,5 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
const FocusCaretTracker = imports.ui.focusCaretTracker;
const Atspi = imports.gi.Atspi;
const Clutter = imports.gi.Clutter;
const Gdk = imports.gi.Gdk;
@ -13,6 +12,7 @@ const Signals = imports.signals;
const St = imports.gi.St;
const InputSourceManager = imports.ui.status.keyboard;
const IBusManager = imports.misc.ibusManager;
const BoxPointer = imports.ui.boxpointer;
const Layout = imports.ui.layout;
const Main = imports.ui.main;
@ -261,6 +261,7 @@ var Key = new Lang.Class({
this._extended_keyboard = null;
this._pressTimeoutId = 0;
this._capturedPress = false;
this._capturedEventId = 0;
this._unmapId = 0;
this._longPress = false;
@ -484,6 +485,79 @@ var KeyboardModel = new Lang.Class({
}
});
var FocusTracker = new Lang.Class({
Name: 'FocusTracker',
_init() {
this._currentWindow = null;
this._currentWindowPositionId = 0;
global.screen.get_display().connect('notify::focus-window', () => {
this._setCurrentWindow(global.screen.get_display().focus_window);
this.emit('window-changed', this._currentWindow);
});
/* Valid for wayland clients */
Main.inputMethod.connect('cursor-location-changed', (o, rect) => {
let newRect = { x: rect.get_x(), y: rect.get_y(), width: rect.get_width(), height: rect.get_height() };
this._setCurrentRect(newRect);
});
this._ibusManager = IBusManager.getIBusManager();
this._ibusManager.connect('set-cursor-location', (manager, rect) => {
/* Valid for X11 clients only */
if (Main.inputMethod.currentFocus)
return;
this._setCurrentRect(rect);
});
},
get currentWindow() {
return this._currentWindow;
},
_setCurrentWindow(window) {
if (this._currentWindow)
this._currentWindow.disconnect(this._currentWindowPositionId);
this._currentWindow = window;
if (window) {
this._currentWindowPositionId = this._currentWindow.connect('position-changed', () => {
if (global.display.get_grab_op() == Meta.GrabOp.NONE)
this.emit('position-changed');
else
this.emit('reset');
});
}
},
_setCurrentRect(rect) {
if (this._currentWindow) {
let frameRect = this._currentWindow.get_frame_rect();
rect.x -= frameRect.x;
rect.y -= frameRect.y;
}
this._rect = rect;
this.emit('position-changed');
},
getCurrentRect() {
let rect = { x: this._rect.x, y: this._rect.y,
width: this._rect.width, height: this._rect.height };
if (this._currentWindow) {
let frameRect = this._currentWindow.get_frame_rect();
rect.x += frameRect.x;
rect.y += frameRect.y;
}
return rect;
}
});
Signals.addSignalMethods(FocusTracker.prototype);
var Keyboard = new Lang.Class({
Name: 'Keyboard',
@ -491,15 +565,10 @@ var Keyboard = new Lang.Class({
this.actor = null;
this._focusInExtendedKeys = false;
this._focusCaretTracker = new FocusCaretTracker.FocusCaretTracker();
this._focusCaretTracker.connect('focus-changed', this._onFocusChanged.bind(this));
this._focusCaretTracker.connect('caret-moved', this._onCaretMoved.bind(this));
this._languagePopup = null;
this._currentAccessible = null;
this._caretTrackingEnabled = false;
this._updateCaretPositionId = 0;
this._currentFocusWindow = null;
this._originalWindowY = null;
this._animFocusedWindow = null;
this._delayedAnimFocusWindow = null;
this._enableKeyboard = false; // a11y settings value
this._enabled = false; // enabled state (by setting or device type)
@ -510,6 +579,14 @@ var Keyboard = new Lang.Class({
this._lastDeviceId = null;
this._suggestions = null;
this._focusTracker = new FocusTracker();
this._focusTracker.connect('position-changed', this._onFocusPositionChanged.bind(this));
this._focusTracker.connect('reset', () => {
this._delayedAnimFocusWindow = null;
this._animFocusedWindow = null;
this._oskFocusWindow = null;
});
Meta.get_backend().connect('last-device-changed',
(backend, deviceId) => {
let manager = Clutter.DeviceManager.get_default();
@ -532,102 +609,15 @@ var Keyboard = new Lang.Class({
this._keyboardRestingId = 0;
Main.layoutManager.connect('monitors-changed', this._relayout.bind(this));
//Main.inputMethod.connect('cursor-location-changed', (o, rect) => {
// if (this._keyboardVisible) {
// let currentWindow = global.screen.get_display().focus_window;
// this.setCursorLocation(currentWindow, rect.get_x(), rect.get_y(),
// rect.get_width(), rect.get_height());
// }
//});
},
get visible() {
return this._keyboardVisible;
},
_setCaretTrackerEnabled(enabled) {
if (this._caretTrackingEnabled == enabled)
return;
this._caretTrackingEnabled = enabled;
if (enabled) {
this._focusCaretTracker.registerFocusListener();
this._focusCaretTracker.registerCaretListener();
} else {
this._focusCaretTracker.deregisterFocusListener();
this._focusCaretTracker.deregisterCaretListener();
}
},
_updateCaretPosition(accessible) {
if (this._updateCaretPositionId)
GLib.source_remove(this._updateCaretPositionId);
if (!this._keyboardRequested)
return;
this._updateCaretPositionId = GLib.idle_add(GLib.PRIORITY_DEFAULT_IDLE, () => {
this._updateCaretPositionId = 0;
let currentWindow = global.screen.get_display().focus_window;
if (!currentWindow) {
this.setCursorLocation(null);
return GLib.SOURCE_REMOVE;
}
let windowRect = currentWindow.get_frame_rect();
let text = accessible.get_text_iface();
let component = accessible.get_component_iface();
try {
let caretOffset = text.get_caret_offset();
let caretRect = text.get_character_extents(caretOffset, Atspi.CoordType.WINDOW);
let focusRect = component.get_extents(Atspi.CoordType.WINDOW);
if (caretRect.width == 0 && caretRect.height == 0)
caretRect = focusRect;
this.setCursorLocation(currentWindow, caretRect.x, caretRect.y, caretRect.width, caretRect.height);
} catch (e) {
log('Error updating caret position for OSK: ' + e.message);
}
return GLib.SOURCE_REMOVE;
});
GLib.Source.set_name_by_id(this._updateCaretPositionId, '[gnome-shell] this._updateCaretPosition');
},
_focusIsTextEntry(accessible) {
try {
let role = accessible.get_role();
let stateSet = accessible.get_state_set();
return stateSet.contains(Atspi.StateType.EDITABLE) || role == Atspi.Role.TERMINAL;
} catch (e) {
log('Error determining accessible role: ' + e.message);
return false;
}
},
_onFocusChanged(caretTracker, event) {
let accessible = event.source;
if (!this._focusIsTextEntry(accessible))
return;
let focused = event.detail1 != 0;
if (focused) {
this._currentAccessible = accessible;
this._updateCaretPosition(accessible);
this.show(Main.layoutManager.focusIndex);
} else if (this._currentAccessible == accessible) {
this._currentAccessible = null;
this.hide();
}
},
_onCaretMoved(caretTracker, event) {
let accessible = event.source;
if (this._currentAccessible == accessible)
this._updateCaretPosition(accessible);
_onFocusPositionChanged(focusTracker) {
let rect = focusTracker.getCurrentRect();
this.setCursorLocation(focusTracker.currentWindow, rect.x, rect.y, rect.width, rect.height);
},
_lastDeviceIsTouchscreen() {
@ -650,8 +640,6 @@ var Keyboard = new Lang.Class({
if (!this._enabled && !this._keyboardController)
return;
this._setCaretTrackerEnabled(this._enabled);
if (this._enabled && !this._keyboardController)
this._setupKeyboard();
else if (!this._enabled)
@ -1027,11 +1015,14 @@ var Keyboard = new Lang.Class({
if (!this._keyboardRequested)
return;
if (this._currentAccessible)
this._updateCaretPosition(this._currentAccessible);
Main.layoutManager.keyboardIndex = monitor;
this._relayout();
Main.layoutManager.showKeyboard();
if (this._delayedAnimFocusWindow) {
this._setAnimationWindow(this._delayedAnimFocusWindow);
this._delayedAnimFocusWindow = null;
}
},
hide() {
@ -1102,8 +1093,9 @@ var Keyboard = new Lang.Class({
window.move_frame(true, frameRect.x, frameRect.y);
},
_animateWindow(window, show, deltaY) {
_animateWindow(window, show) {
let windowActor = window.get_compositor_private();
let deltaY = Main.layoutManager.keyboardBox.height;
if (!windowActor)
return;
@ -1124,35 +1116,39 @@ var Keyboard = new Lang.Class({
}
},
setCursorLocation(window, x, y , w, h) {
if (window == this._oskFocusWindow)
_setAnimationWindow(window) {
if (this._animFocusedWindow == window)
return;
if (this._oskFocusWindow) {
let display = global.screen.get_display();
if (this._animFocusedWindow)
this._animateWindow(this._animFocusedWindow, false);
if (window)
this._animateWindow(window, true);
if (display.get_grab_op() == Meta.GrabOp.NONE ||
display.get_focus_window() != this._oskFocusWindow)
this._animateWindow(this._oskFocusWindow, false, this._oskFocusWindowDelta);
this._animFocusedWindow = window;
},
this._oskFocusWindow = null;
this._oskFocusWindowDelta = null;
}
setCursorLocation(window, x, y , w, h) {
let monitor = Main.layoutManager.keyboardMonitor;
if (window) {
let monitor = Main.layoutManager.keyboardMonitor;
if (window && monitor) {
let keyboardHeight = Main.layoutManager.keyboardBox.height;
let frameRect = window.get_frame_rect();
let windowActor = window.get_compositor_private();
let delta = 0;
let focusObscured = false;
if (frameRect.y + y + h >= monitor.height - keyboardHeight)
delta = keyboardHeight;
this._animateWindow(window, true, delta);
this._oskFocusWindow = window;
this._oskFocusWindowDelta = delta;
if (y + h >= monitor.y + monitor.height - keyboardHeight) {
if (this._keyboardVisible)
this._setAnimationWindow(window);
else
this._delayedAnimFocusWindow = window;
} else if (y < keyboardHeight) {
this._delayedAnimFocusWindow = null;
this._setAnimationWindow(null);
}
} else {
this._setAnimationWindow(null);
}
this._oskFocusWindow = window;
},
});

View File

@ -278,18 +278,6 @@ var LayoutManager = new Lang.Class({
global.screen.connect('in-fullscreen-changed',
this._updateFullscreen.bind(this));
this._monitorsChanged();
// NVIDIA drivers don't preserve FBO contents across
// suspend/resume, see
// https://bugzilla.gnome.org/show_bug.cgi?id=739178
if (Shell.util_need_background_refresh()) {
LoginManager.getLoginManager().connect('prepare-for-sleep',
(lm, suspending) => {
if (suspending)
return;
Meta.Background.refresh_all();
});
}
},
// This is called by Main after everything else is constructed

View File

@ -19,7 +19,6 @@ const MagnifierDBus = imports.ui.magnifierDBus;
const Params = imports.misc.params;
const PointerWatcher = imports.ui.pointerWatcher;
var MOUSE_POLL_FREQUENCY = 50;
var CROSSHAIRS_CLIP_SIZE = [100, 100];
var NO_CHANGE = 0.0;
@ -152,8 +151,10 @@ var Magnifier = new Lang.Class({
* Turn on mouse tracking, if not already doing so.
*/
startTrackingMouse() {
if (!this._pointerWatch)
this._pointerWatch = PointerWatcher.getPointerWatcher().addWatch(MOUSE_POLL_FREQUENCY, this.scrollToMousePos.bind(this));
if (!this._pointerWatch) {
let interval = 1000 / Clutter.get_default_frame_rate();
this._pointerWatch = PointerWatcher.getPointerWatcher().addWatch(interval, this.scrollToMousePos.bind(this));
}
},
/**

View File

@ -20,6 +20,7 @@ const Environment = imports.ui.environment;
const ExtensionSystem = imports.ui.extensionSystem;
const ExtensionDownloader = imports.ui.extensionDownloader;
const InputMethod = imports.misc.inputMethod;
const Introspect = imports.misc.introspect;
const Keyboard = imports.ui.keyboard;
const MessageTray = imports.ui.messageTray;
const ModalDialog = imports.ui.modalDialog;
@ -82,6 +83,7 @@ var keyboard = null;
var layoutManager = null;
var kbdA11yDialog = null;
var inputMethod = null;
var introspectService = null;
let _startDate;
let _defaultCssStylesheet = null;
let _cssStylesheet = null;
@ -187,6 +189,8 @@ function _initializeUI() {
windowAttentionHandler = new WindowAttentionHandler.WindowAttentionHandler();
componentManager = new Components.ComponentManager();
introspectService = new Introspect.IntrospectService();
layoutManager.init();
overview.init();
@ -207,7 +211,11 @@ function _initializeUI() {
return true;
});
global.display.connect('gl-video-memory-purged', loadTheme);
global.display.connect('gl-video-memory-purged', () => {
let cache = St.TextureCache.get_default();
cache.clear();
loadTheme();
});
// Provide the bus object for gnome-session to
// initiate logouts.
@ -256,6 +264,14 @@ function _getStylesheet(name) {
if (stylesheet.query_exists(null))
return stylesheet;
let dataDirs = GLib.get_system_data_dirs();
for (let i = 0; i < dataDirs.length; i++) {
let path = GLib.build_filenamev([dataDirs[i], 'gnome-shell', 'theme', name]);
let stylesheet = Gio.file_new_for_path(path);
if (stylesheet.query_exists(null))
return stylesheet;
}
stylesheet = Gio.File.new_for_path(global.datadir + '/theme/' + name);
if (stylesheet.query_exists(null))
return stylesheet;

View File

@ -362,7 +362,8 @@ var Message = new Lang.Class({
this.setBody(body);
this._closeButton.connect('clicked', this.close.bind(this));
this.actor.connect('notify::hover', this._sync.bind(this));
let actorHoverId = this.actor.connect('notify::hover', this._sync.bind(this));
this._closeButton.connect('destroy', this.actor.disconnect.bind(this.actor, actorHoverId));
this.actor.connect('clicked', this._onClicked.bind(this));
this.actor.connect('destroy', this._onDestroy.bind(this));
this._sync();

View File

@ -108,15 +108,30 @@ var OsdWindow = new Lang.Class({
this._hideTimeoutId = 0;
this._reset();
Main.layoutManager.connect('monitors-changed',
this._relayout.bind(this));
this.actor.connect('destroy', this._onDestroy.bind(this));
this._monitorsChangedId =
Main.layoutManager.connect('monitors-changed',
this._relayout.bind(this));
let themeContext = St.ThemeContext.get_for_stage(global.stage);
themeContext.connect('notify::scale-factor',
this._relayout.bind(this));
this._scaleChangedId =
themeContext.connect('notify::scale-factor',
this._relayout.bind(this));
this._relayout();
Main.uiGroup.add_child(this.actor);
},
_onDestroy() {
if (this._monitorsChangedId)
Main.layoutManager.disconnect(this._monitorsChangedId);
this._monitorsChangedId = 0;
let themeContext = St.ThemeContext.get_for_stage(global.stage);
if (this._scaleChangedId)
themeContext.disconnect(this._scaleChangedId);
this._scaleChangedId = 0;
},
setIcon(icon) {
this._icon.gicon = icon;
},
@ -204,7 +219,7 @@ var OsdWindow = new Lang.Class({
let scaleFactor = St.ThemeContext.get_for_stage(global.stage).scale_factor;
this._icon.icon_size = popupSize / (2 * scaleFactor);
this._box.translation_y = monitor.height / 4;
this._box.translation_y = Math.round(monitor.height / 4);
this._boxConstraint.minSize = popupSize;
}
});

View File

@ -406,11 +406,18 @@ var ActivitiesButton = new Lang.Class({
this.actor.name = 'panelActivities';
let box = new St.BoxLayout();
this.actor.add_actor(box);
let iconFile = Gio.File.new_for_path('/usr/share/icons/hicolor/scalable/apps/start-here.svg');
this._icon = new St.Icon({ gicon: new Gio.FileIcon({ file: iconFile }),
style_class: 'panel-logo-icon' });
box.add_actor(this._icon);
/* Translators: If there is no suitable word for "Activities"
in your language, you can use the word for "Overview". */
this._label = new St.Label({ text: _("Activities"),
y_align: Clutter.ActorAlign.CENTER });
this.actor.add_actor(this._label);
box.add_actor(this._label);
this.actor.label_actor = this._label;
@ -709,6 +716,7 @@ var AggregateMenu = new Lang.Class({
this._bluetooth = null;
}
this._remoteAccess = new imports.ui.status.remoteAccess.RemoteAccessApplet();
this._power = new imports.ui.status.power.Indicator();
this._rfkill = new imports.ui.status.rfkill.Indicator();
this._volume = new imports.ui.status.volume.Indicator();
@ -729,6 +737,7 @@ var AggregateMenu = new Lang.Class({
if (this._bluetooth) {
this._indicators.add_child(this._bluetooth.indicators);
}
this._indicators.add_child(this._remoteAccess.indicators);
this._indicators.add_child(this._rfkill.indicators);
this._indicators.add_child(this._volume.indicators);
this._indicators.add_child(this._power.indicators);
@ -743,6 +752,7 @@ var AggregateMenu = new Lang.Class({
if (this._bluetooth) {
this.menu.addMenuItem(this._bluetooth.menu);
}
this.menu.addMenuItem(this._remoteAccess.menu);
this.menu.addMenuItem(this._location.menu);
this.menu.addMenuItem(this._rfkill.menu);
this.menu.addMenuItem(this._power.menu);

View File

@ -394,8 +394,9 @@ var PopupImageMenuItem = new Lang.Class({
_init(text, icon, params) {
this.parent(params);
this._icon = new St.Icon({ style_class: 'popup-menu-icon' });
this.actor.add_child(this._icon, { align: St.Align.END });
this._icon = new St.Icon({ style_class: 'popup-menu-icon',
x_align: Clutter.ActorAlign.END });
this.actor.add_child(this._icon);
this.label = new St.Label({ text: text });
this.actor.add_child(this.label);
this.actor.label_actor = this.label;

View File

@ -295,7 +295,7 @@ var RemoteSearchProvider = new Lang.Class({
name: metas[i]['name'],
description: metas[i]['description'],
createIcon: size => {
this.createIcon(size, metas[i]);
return this.createIcon(size, metas[i]);
},
clipboardText: metas[i]['clipboardText'] });
}

View File

@ -515,8 +515,10 @@ var ScreenShield = new Lang.Class({
this._smartcardManager = SmartcardManager.getSmartcardManager();
this._smartcardManager.connect('smartcard-inserted',
(manager, token) => {
if (this._isLocked && token.UsedToLogin)
if (this._isLocked && token.UsedToLogin) {
this._wakeUpScreen();
this._liftShield(true, 0);
}
});
this._oVirtCredentialsManager = OVirt.getOVirtCredentialsManager();

View File

@ -322,6 +322,10 @@ const GnomeShellExtensionsIface = '<node> \
</method> \
<method name="CheckForUpdates"> \
</method> \
<method name="LoadUserExtension"> \
<arg type="s" direction="in" name="uuid"/> \
<arg type="b" direction="out" name="success"/> \
</method> \
<property name="ShellVersion" type="s" access="read" /> \
</interface> \
</node>';
@ -424,6 +428,22 @@ var GnomeShellExtensions = new Lang.Class({
ExtensionDownloader.checkForUpdates();
},
LoadUserExtension(uuid) {
let extension = ExtensionUtils.extensions[uuid];
if (extension)
return true;
let dir = Gio.File.new_for_path(GLib.build_filenamev([global.userdatadir, 'extensions', uuid]));
try {
extension = ExtensionUtils.createExtensionObject(uuid, dir, ExtensionUtils.ExtensionType.PER_USER);
ExtensionSystem.loadExtension(extension);
} catch (e) {
log('Could not load user extension from %s'.format(dir.get_path()));
return false;
}
return true;
},
ShellVersion: Config.PACKAGE_VERSION,
_extensionStateChanged(_, newState) {

View File

@ -1944,6 +1944,7 @@ var NMApplet = new Lang.Class({
this.indicators.visible = this._client.nm_running;
this.menu.actor.visible = this._client.networking_enabled;
this._updateIcon();
this._syncConnectivity();
},

View File

@ -0,0 +1,81 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
const Lang = imports.lang;
const Meta = imports.gi.Meta;
const PanelMenu = imports.ui.panelMenu;
const PopupMenu = imports.ui.popupMenu;
var RemoteAccessApplet = new Lang.Class({
Name: 'RemoteAccessApplet',
Extends: PanelMenu.SystemIndicator,
_init() {
this.parent();
let backend = Meta.get_backend();
let controller = backend.get_remote_access_controller();
if (!controller)
return;
// We can't possibly know about all types of screen sharing on X11, so
// showing these controls on X11 might give a false sense of security.
// Thus, only enable these controls when using Wayland, where we are
// in control of sharing.
if (!Meta.is_wayland_compositor())
return;
this._handles = new Set();
this._indicator = null;
this._menuSection = null;
controller.connect('new-handle', (controller, handle) => {
this._onNewHandle(handle);
});
},
_ensureControls() {
if (this._indicator)
return;
this._indicator = this._addIndicator();
this._indicator.icon_name = 'screen-shared-symbolic';
this._indicator.add_style_class_name('remote-access-indicator');
this._item =
new PopupMenu.PopupSubMenuMenuItem(_("Screen is Being Shared"),
true);
this._item.menu.addAction(_("Turn off"),
() => {
for (let handle of this._handles)
handle.stop();
});
this._item.icon.icon_name = 'screen-shared-symbolic';
this.menu.addMenuItem(this._item);
},
_sync() {
if (this._handles.size == 0) {
this._indicator.visible = false;
this._item.actor.visible = false;
} else {
this._indicator.visible = true;
this._item.actor.visible = true;
}
},
_onStopped(handle) {
this._handles.delete(handle);
this._sync();
},
_onNewHandle(handle) {
this._handles.add(handle);
handle.connect('stopped', this._onStopped.bind(this));
if (this._handles.size == 1) {
this._ensureControls();
this._sync();
}
},
});

View File

@ -58,6 +58,9 @@ var AltSwitcher = new Lang.Class({
childToShow = this._standard;
} else if (this._alternate.visible) {
childToShow = this._alternate;
} else {
this.actor.hide();
return;
}
let childShown = this.actor.get_child();
@ -79,7 +82,7 @@ var AltSwitcher = new Lang.Class({
global.sync_pointer();
}
this.actor.visible = (childToShow != null);
this.actor.show();
},
_onDestroy() {

View File

@ -69,30 +69,67 @@ function _getTweenState(target) {
return target.__ShellTweenerState;
}
function _ensureHandlers(target) {
if (!target.__ShellTweenerHandlers)
target.__ShellTweenerHandlers = {};
return target.__ShellTweenerHandlers;
}
function _resetTweenState(target) {
let state = target.__ShellTweenerState;
if (state) {
if (state.destroyedId)
if (state.destroyedId) {
state.actor.disconnect(state.destroyedId);
delete state.destroyedId;
}
}
_removeHandler(target, 'onComplete', _tweenCompleted);
target.__ShellTweenerState = {};
}
function _addHandler(target, params, name, handler) {
if (params[name]) {
let oldHandler = params[name];
let oldScope = params[name + 'Scope'];
let oldParams = params[name + 'Params'];
let eventScope = oldScope ? oldScope : target;
let wrapperNeeded = false;
let tweenerHandlers = _ensureHandlers(target);
params[name] = () => {
oldHandler.apply(eventScope, oldParams);
handler(target);
};
} else
params[name] = () => { handler(target); };
if (!(name in tweenerHandlers)) {
tweenerHandlers[name] = [];
wrapperNeeded = true;
}
let handlers = tweenerHandlers[name];
handlers.push(handler);
if (wrapperNeeded) {
if (params[name]) {
let oldHandler = params[name];
let oldScope = params[name + 'Scope'];
let oldParams = params[name + 'Params'];
let eventScope = oldScope ? oldScope : target;
params[name] = () => {
oldHandler.apply(eventScope, oldParams);
handlers.forEach((h) => h(target));
};
} else {
params[name] = () => { handlers.forEach((h) => h(target)); };
}
}
}
function _removeHandler(target, name, handler) {
let tweenerHandlers = _ensureHandlers(target);
if (name in tweenerHandlers) {
let handlers = tweenerHandlers[name];
let handlerIndex = handlers.indexOf(handler);
while (handlerIndex > -1) {
handlers.splice(handlerIndex, 1);
handlerIndex = handlers.indexOf(handler);
}
}
}
function _actorDestroyed(target) {

View File

@ -51,7 +51,14 @@ var UnlockDialog = new Lang.Class({
y_expand: true });
this.actor.add_child(this._promptBox);
this._authPrompt = new AuthPrompt.AuthPrompt(new Gdm.Client(), AuthPrompt.AuthPromptMode.UNLOCK_ONLY);
this._gdmClient = new Gdm.Client();
try {
this._gdmClient.set_enabled_extensions([Gdm.UserVerifierChoiceList.interface_info().name]);
} catch(e) {
}
this._authPrompt = new AuthPrompt.AuthPrompt(this._gdmClient, AuthPrompt.AuthPromptMode.UNLOCK_ONLY);
this._authPrompt.connect('failed', this._fail.bind(this));
this._authPrompt.connect('cancelled', this._fail.bind(this));
this._authPrompt.connect('reset', this._onReset.bind(this));

View File

@ -24,7 +24,7 @@ const EdgeDragAction = imports.ui.edgeDragAction;
const CloseDialog = imports.ui.closeDialog;
const SwitchMonitor = imports.ui.switchMonitor;
const SHELL_KEYBINDINGS_SCHEMA = 'org.gnome.shell.keybindings';
var SHELL_KEYBINDINGS_SCHEMA = 'org.gnome.shell.keybindings';
var MINIMIZE_WINDOW_ANIMATION_TIME = 0.2;
var SHOW_WINDOW_ANIMATION_TIME = 0.15;
var DIALOG_SHOW_WINDOW_ANIMATION_TIME = 0.1;

View File

@ -123,6 +123,22 @@ var WindowMenu = new Lang.Class({
window.change_workspace(workspace.get_neighbor(dir));
});
}
let nWorkspaces = global.screen.n_workspaces;
if (nWorkspaces > 1 && !Meta.prefs_get_dynamic_workspaces()) {
item = new PopupMenu.PopupSubMenuMenuItem(_("Move to another workspace"));
this.addMenuItem(item);
let currentIndex = global.screen.get_active_workspace_index();
for (let i = 0; i < nWorkspaces; i++) {
let index = i;
let name = Meta.prefs_get_workspace_name(i);
let subitem = item.menu.addAction(name, () => {
window.change_workspace_by_index(index, false);
});
subitem.setSensitive(currentIndex != i);
}
}
}
}

View File

@ -1431,34 +1431,26 @@ var Workspace = new Lang.Class({
_doRemoveWindow(metaWin) {
let win = metaWin.get_compositor_private();
// find the position of the window in our list
let index = this._lookupIndex (metaWin);
let clone = this._removeWindowClone(metaWin);
if (index == -1)
return;
let clone = this._windows[index];
this._windows.splice(index, 1);
this._windowOverlays.splice(index, 1);
// If metaWin.get_compositor_private() returned non-NULL, that
// means the window still exists (and is just being moved to
// another workspace or something), so set its overviewHint
// accordingly. (If it returned NULL, then the window is being
// destroyed; we'd like to animate this, but it's too late at
// this point.)
if (win) {
let [stageX, stageY] = clone.actor.get_transformed_position();
let [stageWidth, stageHeight] = clone.actor.get_transformed_size();
win._overviewHint = {
x: stageX,
y: stageY,
scale: stageWidth / clone.actor.width
};
if (clone) {
// If metaWin.get_compositor_private() returned non-NULL, that
// means the window still exists (and is just being moved to
// another workspace or something), so set its overviewHint
// accordingly. (If it returned NULL, then the window is being
// destroyed; we'd like to animate this, but it's too late at
// this point.)
if (win) {
let [stageX, stageY] = clone.actor.get_transformed_position();
let [stageWidth, stageHeight] = clone.actor.get_transformed_size();
win._overviewHint = {
x: stageX,
y: stageY,
scale: stageWidth / clone.actor.width
};
}
clone.destroy();
}
clone.destroy();
// We need to reposition the windows; to avoid shuffling windows
// around while the user is interacting with the workspace, we delay
@ -1848,6 +1840,9 @@ var Workspace = new Lang.Class({
clone.connect('size-changed', () => {
this._recalculateWindowPositions(WindowPositionFlags.NONE);
});
clone.actor.connect('destroy', () => {
this._removeWindowClone(clone.metaWindow);
});
this.actor.add_actor(clone.actor);
@ -1869,6 +1864,17 @@ var Workspace = new Lang.Class({
return [clone, overlay];
},
_removeWindowClone(metaWin) {
// find the position of the window in our list
let index = this._lookupIndex (metaWin);
if (index == -1)
return null;
this._windowOverlays.splice(index, 1);
return this._windows.splice(index, 1).pop();
},
_onShowOverlayClose(windowOverlay) {
for (let i = 0; i < this._windowOverlays.length; i++) {
let overlay = this._windowOverlays[i];

View File

@ -31,7 +31,7 @@ var WORKSPACE_CUT_SIZE = 10;
var WORKSPACE_KEEP_ALIVE_TIME = 100;
const OVERRIDE_SCHEMA = 'org.gnome.shell.overrides';
var OVERRIDE_SCHEMA = 'org.gnome.shell.overrides';
/* A layout manager that requests size only for primary_actor, but then allocates
all using a fixed layout */
@ -241,7 +241,7 @@ var WindowClone = new Lang.Class({
Signals.addSignalMethods(WindowClone.prototype);
const ThumbnailState = {
var ThumbnailState = {
NEW : 0,
ANIMATING_IN : 1,
NORMAL: 2,
@ -275,8 +275,8 @@ var WorkspaceThumbnail = new Lang.Class({
this._createBackground();
let monitor = Main.layoutManager.primaryMonitor;
this.setPorthole(monitor.x, monitor.y, monitor.width, monitor.height);
let workArea = Main.layoutManager.getWorkAreaForMonitor(this.monitorIndex);
this.setPorthole(workArea.x, workArea.y, workArea.width, workArea.height);
let windows = global.get_window_actors().filter(actor => {
let win = actor.meta_window;
@ -321,8 +321,6 @@ var WorkspaceThumbnail = new Lang.Class({
},
setPorthole(x, y, width, height) {
this._portholeX = x;
this._portholeY = y;
this.actor.set_size(width, height);
this._contents.set_position(-x, -y);
},
@ -374,18 +372,9 @@ var WorkspaceThumbnail = new Lang.Class({
},
_doRemoveWindow(metaWin) {
let win = metaWin.get_compositor_private();
// find the position of the window in our list
let index = this._lookupIndex (metaWin);
if (index == -1)
return;
let clone = this._windows[index];
this._windows.splice(index, 1);
clone.destroy();
let clone = this._removeWindowClone(metaWin);
if (clone)
clone.destroy();
},
_doAddWindow(metaWin) {
@ -537,6 +526,9 @@ var WorkspaceThumbnail = new Lang.Class({
clone.connect('drag-end', () => {
Main.overview.endWindowDrag(clone.metaWindow);
});
clone.actor.connect('destroy', () => {
this._removeWindowClone(clone.metaWindow);
});
this._contents.add_actor(clone.actor);
if (this._windows.length == 0)
@ -549,6 +541,16 @@ var WorkspaceThumbnail = new Lang.Class({
return clone;
},
_removeWindowClone(metaWin) {
// find the position of the window in our list
let index = this._lookupIndex (metaWin);
if (index == -1)
return null;
return this._windows.splice(index, 1).pop();
},
activate(time) {
if (this.state > ThumbnailState.NORMAL)
return;
@ -675,11 +677,7 @@ var ThumbnailsBox = new Lang.Class({
this._settings.connect('changed::dynamic-workspaces',
this._updateSwitcherVisibility.bind(this));
Main.layoutManager.connect('monitors-changed', () => {
this._destroyThumbnails();
if (Main.overview.visible)
this._createThumbnails();
});
Main.layoutManager.connect('monitors-changed', this._rebuildThumbnails.bind(this));
},
_updateSwitcherVisibility() {
@ -872,6 +870,9 @@ var ThumbnailsBox = new Lang.Class({
Main.overview.connect('windows-restacked',
this._syncStacking.bind(this));
this._workareasChangedId =
global.screen.connect('workareas-changed', this._rebuildThumbnails.bind(this));
this._targetScale = 0;
this._scale = 0;
this._pendingScaleUpdate = false;
@ -901,12 +902,24 @@ var ThumbnailsBox = new Lang.Class({
this._syncStackingId = 0;
}
if (this._workareasChangedId > 0) {
global.screen.disconnect(this._workareasChangedId);
this._workareasChangedId = 0;
}
for (let w = 0; w < this._thumbnails.length; w++)
this._thumbnails[w].destroy();
this._thumbnails = [];
this._porthole = null;
},
_rebuildThumbnails() {
this._destroyThumbnails();
if (Main.overview.visible)
this._createThumbnails();
},
_workspacesChanged() {
let validThumbnails =
this._thumbnails.filter(t => t.state <= ThumbnailState.NORMAL);
@ -1159,7 +1172,7 @@ var ThumbnailsBox = new Lang.Class({
// The "porthole" is the portion of the screen that we show in the
// workspaces
_ensurePorthole() {
if (!Main.layoutManager.primaryMonitor)
if (!Main.layoutManager.primaryMonitor || !Main.overview.visible)
return false;
if (!this._porthole)

View File

@ -1,5 +1,5 @@
project('gnome-shell', 'c',
version: '3.28.1',
version: '3.28.3',
meson_version: '>= 0.42.0',
license: 'GPLv2+'
)
@ -56,6 +56,7 @@ mozplugindir = join_paths(libdir, 'mozilla', 'plugins')
portaldir = join_paths(datadir, 'xdg-desktop-portal', 'portals')
schemadir = join_paths(datadir, 'glib-2.0', 'schemas')
servicedir = join_paths(datadir, 'dbus-1', 'services')
themedir = join_paths(pkgdatadir, 'theme')
plugindir = get_variable('BROWSER_PLUGIN_DIR', mozplugindir)

1500
po/af.po

File diff suppressed because it is too large Load Diff

757
po/gd.po

File diff suppressed because it is too large Load Diff

View File

@ -15,22 +15,22 @@
# Georges Basile Stavracas Neto <georges.stavracas@gmail.com>, 2014.
# Felipe Braga <fbobraga@gmail.com>, 2015.
# Artur de Aquino Morais <artur.morais93@outlook.com>, 2016.
# Rafael Fontenelle <rafaelff@gnome.org>, 2013-2017.
# Rafael Fontenelle <rafaelff@gnome.org>, 2013-2018.
# Enrico Nicoletto <liverig@gmail.com>, 2013-2018.
msgid ""
msgstr ""
"Project-Id-Version: gnome-shell\n"
"Report-Msgid-Bugs-To: https://gitlab.gnome.org/GNOME/gnome-shell/issues\n"
"POT-Creation-Date: 2018-03-16 21:34+0000\n"
"PO-Revision-Date: 2018-02-09 21:52-0200\n"
"Last-Translator: Enrico Nicoletto <liverig@gmail.com>\n"
"POT-Creation-Date: 2018-04-13 18:31+0000\n"
"PO-Revision-Date: 2018-05-02 15:45-0200\n"
"Last-Translator: Rafael Fontenelle <rafaelff@gnome.org>\n"
"Language-Team: Brazilian Portuguese <gnome-pt_br-list@gnome.org>\n"
"Language: pt_BR\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
"X-Generator: Poedit 2.0.6\n"
"X-Generator: Virtaal 1.0.0-beta1\n"
"X-Project-Style: gnome\n"
#: data/50-gnome-shell-system.xml:6
@ -356,7 +356,7 @@ msgid "There was an error loading the preferences dialog for %s:"
msgstr "Ocorreu um erro ao carregar o dialogo de preferências para %s:"
#: js/gdm/authPrompt.js:147 js/ui/audioDeviceSelection.js:71
#: js/ui/components/networkAgent.js:117 js/ui/components/polkitAgent.js:148
#: js/ui/components/networkAgent.js:117 js/ui/components/polkitAgent.js:153
#: js/ui/endSessionDialog.js:482 js/ui/extensionDownloader.js:197
#: js/ui/shellMountOperation.js:343 js/ui/status/network.js:919
msgid "Cancel"
@ -642,7 +642,7 @@ msgstr "Negar acesso"
#: js/ui/accessDialog.js:64 js/ui/status/location.js:396
msgid "Grant Access"
msgstr "Garantir acesso"
msgstr "Conceder acesso"
#: js/ui/appDisplay.js:793
msgid "Frequently used applications will appear here"
@ -676,12 +676,12 @@ msgstr "Adicionar aos favoritos"
msgid "Show Details"
msgstr "Mostrar detalhes"
#: js/ui/appFavorites.js:138
#: js/ui/appFavorites.js:140
#, javascript-format
msgid "%s has been added to your favorites."
msgstr "%s foi adicionado aos seus favoritos."
#: js/ui/appFavorites.js:172
#: js/ui/appFavorites.js:174
#, javascript-format
msgid "%s has been removed from your favorites."
msgstr "%s foi removido dos seus favoritos."
@ -876,7 +876,7 @@ msgstr "Unidade externa desconectada"
msgid "Open with %s"
msgstr "Abrir com %s"
#: js/ui/components/keyring.js:107 js/ui/components/polkitAgent.js:284
#: js/ui/components/keyring.js:107 js/ui/components/polkitAgent.js:295
msgid "Password:"
msgstr "Senha:"
@ -964,15 +964,15 @@ msgstr "Uma senha é necessária para se conectar a “%s”."
msgid "Network Manager"
msgstr "Gerenciador de rede"
#: js/ui/components/polkitAgent.js:43
#: js/ui/components/polkitAgent.js:48
msgid "Authentication Required"
msgstr "Autenticação necessária"
#: js/ui/components/polkitAgent.js:71
#: js/ui/components/polkitAgent.js:76
msgid "Administrator"
msgstr "Administrador"
#: js/ui/components/polkitAgent.js:151
#: js/ui/components/polkitAgent.js:156
msgid "Authenticate"
msgstr "Autenticação"
@ -980,7 +980,7 @@ msgstr "Autenticação"
#. * requested authentication was not gained; this can happen
#. * because of an authentication error (like invalid password),
#. * for instance.
#: js/ui/components/polkitAgent.js:270 js/ui/shellMountOperation.js:327
#: js/ui/components/polkitAgent.js:281 js/ui/shellMountOperation.js:327
msgid "Sorry, that didnt work. Please try again."
msgstr "Desculpe, isto não funcionou. Por favor, tente novamente."
@ -1028,7 +1028,7 @@ msgstr "Adicionar relógios mundiais…"
msgid "World Clocks"
msgstr "Relógios mundiais"
#: js/ui/dateMenu.js:225
#: js/ui/dateMenu.js:227
msgid "Weather"
msgstr "Meteorologia"
@ -1036,7 +1036,7 @@ msgstr "Meteorologia"
#. libgweather for the possible condition strings. If at all
#. possible, the sentence should match the grammatical case etc. of
#. the inserted conditions.
#: js/ui/dateMenu.js:289
#: js/ui/dateMenu.js:291
#, javascript-format
msgid "%s all day."
msgstr "%s por todo o dia."
@ -1045,7 +1045,7 @@ msgstr "%s por todo o dia."
#. libgweather for the possible condition strings. If at all
#. possible, the sentence should match the grammatical case etc. of
#. the inserted conditions.
#: js/ui/dateMenu.js:295
#: js/ui/dateMenu.js:297
#, javascript-format
msgid "%s, then %s later."
msgstr "%s, depois %s mais tarde."
@ -1054,30 +1054,30 @@ msgstr "%s, depois %s mais tarde."
#. libgweather for the possible condition strings. If at all
#. possible, the sentence should match the grammatical case etc. of
#. the inserted conditions.
#: js/ui/dateMenu.js:301
#: js/ui/dateMenu.js:303
#, javascript-format
msgid "%s, then %s, followed by %s later."
msgstr "%s, depois %s, seguido de %s mais tarde."
#: js/ui/dateMenu.js:312
#: js/ui/dateMenu.js:314
msgid "Select a location…"
msgstr "Selecione uma localização…"
#: js/ui/dateMenu.js:315
#: js/ui/dateMenu.js:317
msgid "Loading…"
msgstr "Carregando…"
#. Translators: %s is a temperature with unit, e.g. "23℃"
#: js/ui/dateMenu.js:321
#: js/ui/dateMenu.js:323
#, javascript-format
msgid "Feels like %s."
msgstr "Sensação térmica de %s."
#: js/ui/dateMenu.js:324
#: js/ui/dateMenu.js:326
msgid "Go online for weather information"
msgstr "Conecte-se à internet para obter as informações meteorológicas"
#: js/ui/dateMenu.js:326
#: js/ui/dateMenu.js:328
msgid "Weather information is currently unavailable"
msgstr "No momento as informações meteorológicas não estão disponíveis"

View File

@ -18,8 +18,8 @@ msgid ""
msgstr ""
"Project-Id-Version: gnome-shell\n"
"Report-Msgid-Bugs-To: https://gitlab.gnome.org/GNOME/gnome-shell/issues\n"
"POT-Creation-Date: 2018-04-12 11:47+0000\n"
"PO-Revision-Date: 2018-04-12 16:48+0300\n"
"POT-Creation-Date: 2018-04-13 18:31+0000\n"
"PO-Revision-Date: 2018-04-19 23:31+0300\n"
"Last-Translator: Stas Solovey <whats_up@tut.by>\n"
"Language-Team: Русский <gnome-cyr@gnome.org>\n"
"Language: ru\n"
@ -344,7 +344,7 @@ msgid "There was an error loading the preferences dialog for %s:"
msgstr "Возникла ошибка загрузки диалогового окна параметров для %s:"
#: js/gdm/authPrompt.js:147 js/ui/audioDeviceSelection.js:71
#: js/ui/components/networkAgent.js:117 js/ui/components/polkitAgent.js:149
#: js/ui/components/networkAgent.js:117 js/ui/components/polkitAgent.js:153
#: js/ui/endSessionDialog.js:482 js/ui/extensionDownloader.js:197
#: js/ui/shellMountOperation.js:343 js/ui/status/network.js:919
msgid "Cancel"
@ -563,7 +563,6 @@ msgstr "Вчера, %H%M"
msgid "%A, %H%M"
msgstr "%A, %H%M"
# fix даты "11 мар., 20:35"
#. Translators: this is the month name and day number
#. followed by a time string in 24h format.
#. i.e. "May 25, 14:30"
@ -572,7 +571,6 @@ msgstr "%A, %H%M"
msgid "%B %d, %H%M"
msgstr "%-d %B, %H%M"
# fix даты
#. Translators: this is the month name, day number, year
#. number followed by a time string in 24h format.
#. i.e. "May 25 2012, 14:30"
@ -581,7 +579,6 @@ msgstr "%-d %B, %H%M"
msgid "%B %d %Y, %H%M"
msgstr "%-d %B %Y, %H%M"
# по всей видимости разрабы коммент перепутали c "Translators: Time in 12h format"
#. Translators: Time in 12h format
#: js/misc/util.js:257
msgid "%l%M %p"
@ -823,7 +820,6 @@ msgctxt "calendar heading"
msgid "%A, %B %d"
msgstr "%A, %-d %B"
# fix для даты в календаре и на экране блокировки
#: js/ui/calendar.js:868
msgctxt "calendar heading"
msgid "%A, %B %d, %Y"
@ -876,7 +872,7 @@ msgstr "Внешний диск отключён"
msgid "Open with %s"
msgstr "Открыть с помощью %s"
#: js/ui/components/keyring.js:107 js/ui/components/polkitAgent.js:285
#: js/ui/components/keyring.js:107 js/ui/components/polkitAgent.js:295
msgid "Password:"
msgstr "Пароль:"
@ -963,15 +959,15 @@ msgstr "Для подключения к «%s» требуется пароль.
msgid "Network Manager"
msgstr "Диспетчер сети"
#: js/ui/components/polkitAgent.js:44
#: js/ui/components/polkitAgent.js:48
msgid "Authentication Required"
msgstr "Требуется подтверждение подлинности"
#: js/ui/components/polkitAgent.js:72
#: js/ui/components/polkitAgent.js:76
msgid "Administrator"
msgstr "Администратор"
#: js/ui/components/polkitAgent.js:152
#: js/ui/components/polkitAgent.js:156
msgid "Authenticate"
msgstr "Подтвердить"
@ -979,7 +975,7 @@ msgstr "Подтвердить"
#. * requested authentication was not gained; this can happen
#. * because of an authentication error (like invalid password),
#. * for instance.
#: js/ui/components/polkitAgent.js:271 js/ui/shellMountOperation.js:327
#: js/ui/components/polkitAgent.js:281 js/ui/shellMountOperation.js:327
msgid "Sorry, that didnt work. Please try again."
msgstr "Не удалось подтвердить подлинность. Попробуйте снова."
@ -1004,7 +1000,6 @@ msgstr "Показать приложения"
msgid "Dash"
msgstr "Панель приложений"
# fix для даты в календаре и на экране блокировки
#. Translators: This is the date format to use when the calendar popup is
#. * shown - it is shown just below the time in the shell (e.g. "Tue 9:29 AM").
#.
@ -1012,7 +1007,6 @@ msgstr "Панель приложений"
msgid "%B %e %Y"
msgstr "%-d %B %Y"
# fix для даты в календаре и на экране блокировки
#. Translators: This is the accessible name of the date button shown
#. * below the time in the shell; it should combine the weekday and the
#. * date, e.g. "Tuesday February 17 2015".
@ -1029,7 +1023,7 @@ msgstr "Добавить мировые часы…"
msgid "World Clocks"
msgstr "Мировые часы"
#: js/ui/dateMenu.js:225
#: js/ui/dateMenu.js:227
msgid "Weather"
msgstr "Погода"
@ -1037,7 +1031,7 @@ msgstr "Погода"
#. libgweather for the possible condition strings. If at all
#. possible, the sentence should match the grammatical case etc. of
#. the inserted conditions.
#: js/ui/dateMenu.js:289
#: js/ui/dateMenu.js:291
#, javascript-format
msgid "%s all day."
msgstr "%s весь день."
@ -1046,7 +1040,7 @@ msgstr "%s весь день."
#. libgweather for the possible condition strings. If at all
#. possible, the sentence should match the grammatical case etc. of
#. the inserted conditions.
#: js/ui/dateMenu.js:295
#: js/ui/dateMenu.js:297
#, javascript-format
msgid "%s, then %s later."
msgstr "%s, затем позднее %s."
@ -1055,30 +1049,30 @@ msgstr "%s, затем позднее %s."
#. libgweather for the possible condition strings. If at all
#. possible, the sentence should match the grammatical case etc. of
#. the inserted conditions.
#: js/ui/dateMenu.js:301
#: js/ui/dateMenu.js:303
#, javascript-format
msgid "%s, then %s, followed by %s later."
msgstr "%s, затем %s, позже %s."
#: js/ui/dateMenu.js:312
#: js/ui/dateMenu.js:314
msgid "Select a location…"
msgstr "Выберите местоположение…"
#: js/ui/dateMenu.js:315
#: js/ui/dateMenu.js:317
msgid "Loading…"
msgstr "Загрузка…"
#. Translators: %s is a temperature with unit, e.g. "23℃"
#: js/ui/dateMenu.js:321
#: js/ui/dateMenu.js:323
#, javascript-format
msgid "Feels like %s."
msgstr "Ощущается как %s."
#: js/ui/dateMenu.js:324
#: js/ui/dateMenu.js:326
msgid "Go online for weather information"
msgstr "Подключите интернет для получения информации о погоде"
#: js/ui/dateMenu.js:326
#: js/ui/dateMenu.js:328
msgid "Weather information is currently unavailable"
msgstr "Информация о погоде сейчас недоступна"

View File

@ -38,6 +38,7 @@ extern GType gnome_shell_plugin_get_type (void);
static gboolean is_gdm_mode = FALSE;
static char *session_mode = NULL;
static char *override_schema = NULL;
static int caught_signal = 0;
#define DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER 1
@ -450,6 +451,12 @@ GOptionEntry gnome_shell_options[] = {
N_("List possible modes"),
NULL
},
{
"override-schema", 0, 0, G_OPTION_ARG_STRING,
&override_schema,
N_("Override the override schema"),
"SCHEMA"
},
{ NULL }
};
@ -507,7 +514,9 @@ main (int argc, char **argv)
if (session_mode == NULL)
session_mode = is_gdm_mode ? (char *)"gdm" : (char *)"user";
_shell_global_init ("session-mode", session_mode, NULL);
_shell_global_init ("session-mode", session_mode,
"override-schema", override_schema,
NULL);
shell_prefs_init ();

View File

@ -265,7 +265,7 @@ shell_app_get_name (ShellApp *app)
const char *name = NULL;
if (window)
name = meta_window_get_wm_class (window);
name = meta_window_get_title (window);
if (!name)
name = C_("program", "Unknown");
return name;
@ -1159,7 +1159,7 @@ shell_app_request_quit (ShellApp *app)
{
MetaWindow *win = iter->data;
if (meta_window_is_skip_taskbar (win))
if (!meta_window_can_close (win))
continue;
meta_window_delete (win, shell_global_get_current_time (shell_global_get ()));

View File

@ -65,6 +65,7 @@ struct _ShellGlobal {
MetaScreen *meta_screen;
char *session_mode;
char *override_schema;
XserverRegion input_region;
@ -96,6 +97,7 @@ enum {
PROP_0,
PROP_SESSION_MODE,
PROP_OVERRIDE_SCHEMA,
PROP_SCREEN,
PROP_DISPLAY,
PROP_SCREEN_WIDTH,
@ -138,6 +140,10 @@ shell_global_set_property(GObject *object,
g_clear_pointer (&global->session_mode, g_free);
global->session_mode = g_ascii_strdown (g_value_get_string (value), -1);
break;
case PROP_OVERRIDE_SCHEMA:
g_clear_pointer (&global->override_schema, g_free);
global->override_schema = g_value_dup_string (value);
break;
case PROP_FRAME_TIMESTAMPS:
global->frame_timestamps = g_value_get_boolean (value);
break;
@ -163,6 +169,9 @@ shell_global_get_property(GObject *object,
case PROP_SESSION_MODE:
g_value_set_string (value, shell_global_get_session_mode (global));
break;
case PROP_OVERRIDE_SCHEMA:
g_value_set_string (value, global->override_schema);
break;
case PROP_SCREEN:
g_value_set_object (value, global->meta_screen);
break;
@ -368,6 +377,13 @@ shell_global_class_init (ShellGlobalClass *klass)
g_param_spec_string ("session-mode",
"Session Mode",
"The session mode to use",
NULL,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
g_object_class_install_property (gobject_class,
PROP_OVERRIDE_SCHEMA,
g_param_spec_string ("override-schema",
"Override Schema",
"The override schema to use",
"user",
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
g_object_class_install_property (gobject_class,
@ -1360,7 +1376,9 @@ shell_global_get_overrides_settings (ShellGlobal *global)
if (!settings)
{
if (strcmp (global->session_mode, "classic") == 0)
if (global->override_schema != NULL)
schema = global->override_schema;
else if (strcmp (global->session_mode, "classic") == 0)
schema = "org.gnome.shell.extensions.classic-overrides";
else if (strcmp (global->session_mode, "user") == 0)
schema = "org.gnome.shell.overrides";

View File

@ -396,18 +396,6 @@ get_gl_vendor (void)
return vendor;
}
gboolean
shell_util_need_background_refresh (void)
{
if (!clutter_check_windowing_backend (CLUTTER_WINDOWING_X11))
return FALSE;
if (g_strcmp0 (get_gl_vendor (), "NVIDIA Corporation") == 0)
return TRUE;
return FALSE;
}
static gboolean
canvas_draw_cb (ClutterContent *content,
cairo_t *cr,

View File

@ -142,7 +142,7 @@ libst_gir = gnome.generate_gir(libst,
sources: st_gir_sources,
nsversion: '1.0',
namespace: 'St',
includes: ['Clutter-' + mutter_api_version, 'Gtk-3.0'],
includes: ['Clutter-' + mutter_api_version, 'Cally-' + mutter_api_version, 'Gtk-3.0'],
dependencies: [mutter_dep],
include_directories: include_directories('..'),
extra_args: ['-DST_COMPILATION', '--quiet'],

View File

@ -180,6 +180,7 @@ st_label_dispose (GObject *object)
{
StLabelPrivate *priv = ST_LABEL (object)->priv;
priv->label = NULL;
g_clear_pointer (&priv->text_shadow_pipeline, cogl_object_unref);
G_OBJECT_CLASS (st_label_parent_class)->dispose (object);

View File

@ -37,6 +37,7 @@ struct _StTextureCachePrivate
/* Things that were loaded with a cache policy != NONE */
GHashTable *keyed_cache; /* char * -> CoglTexture* */
GHashTable *keyed_surface_cache; /* char * -> cairo_surface_t* */
/* Presently this is used to de-duplicate requests for GIcons and async URIs. */
GHashTable *outstanding_requests; /* char * -> AsyncTextureLoadData * */
@ -104,6 +105,18 @@ st_texture_cache_class_init (StTextureCacheClass *klass)
G_TYPE_NONE, 1, G_TYPE_FILE);
}
/* Evicts all cached textures */
void
st_texture_cache_clear (StTextureCache *cache)
{
GHashTableIter iter;
gpointer key;
gpointer value;
g_hash_table_remove_all (cache->priv->keyed_cache);
g_signal_emit (cache, signals[ICON_THEME_CHANGED], 0);
}
/* Evicts all cached textures for named icons */
static void
st_texture_cache_evict_icons (StTextureCache *cache)
@ -145,6 +158,10 @@ st_texture_cache_init (StTextureCache *self)
self->priv->keyed_cache = g_hash_table_new_full (g_str_hash, g_str_equal,
g_free, cogl_object_unref);
self->priv->keyed_surface_cache = g_hash_table_new_full (g_str_hash,
g_str_equal,
g_free,
(GDestroyNotify) cairo_surface_destroy);
self->priv->outstanding_requests = g_hash_table_new_full (g_str_hash, g_str_equal,
g_free, NULL);
self->priv->file_monitors = g_hash_table_new_full (g_file_hash, (GEqualFunc) g_file_equal,
@ -166,6 +183,7 @@ st_texture_cache_dispose (GObject *object)
}
g_clear_pointer (&self->priv->keyed_cache, g_hash_table_destroy);
g_clear_pointer (&self->priv->keyed_surface_cache, g_hash_table_destroy);
g_clear_pointer (&self->priv->outstanding_requests, g_hash_table_destroy);
g_clear_pointer (&self->priv->file_monitors, g_hash_table_destroy);
@ -520,6 +538,8 @@ finish_texture_load (AsyncTextureLoadData *data,
goto out;
texdata = pixbuf_to_cogl_texture (pixbuf);
if (!texdata)
goto out;
if (data->policy != ST_TEXTURE_CACHE_POLICY_NONE)
{
@ -986,7 +1006,7 @@ file_changed_cb (GFileMonitor *monitor,
g_free (key);
key = g_strdup_printf (CACHE_PREFIX_FILE_FOR_CAIRO "%u", file_hash);
g_hash_table_remove (cache->priv->keyed_cache, key);
g_hash_table_remove (cache->priv->keyed_surface_cache, key);
g_free (key);
g_signal_emit (cache, signals[TEXTURE_FILE_CHANGED], 0, file);
@ -1273,6 +1293,9 @@ st_texture_cache_load_file_sync_to_cogl_texture (StTextureCache *cache,
texdata = pixbuf_to_cogl_texture (pixbuf);
g_object_unref (pixbuf);
if (!texdata)
goto out;
if (policy == ST_TEXTURE_CACHE_POLICY_FOREVER)
{
cogl_object_ref (texdata);
@ -1304,7 +1327,7 @@ st_texture_cache_load_file_sync_to_cairo_surface (StTextureCache *cache,
key = g_strdup_printf (CACHE_PREFIX_FILE_FOR_CAIRO "%u", g_file_hash (file));
surface = g_hash_table_lookup (cache->priv->keyed_cache, key);
surface = g_hash_table_lookup (cache->priv->keyed_surface_cache, key);
if (surface == NULL)
{
@ -1318,7 +1341,8 @@ st_texture_cache_load_file_sync_to_cairo_surface (StTextureCache *cache,
if (policy == ST_TEXTURE_CACHE_POLICY_FOREVER)
{
cairo_surface_reference (surface);
g_hash_table_insert (cache->priv->keyed_cache, g_strdup (key), surface);
g_hash_table_insert (cache->priv->keyed_surface_cache,
g_strdup (key), surface);
}
}
else

View File

@ -52,6 +52,7 @@ typedef enum {
} StTextureCachePolicy;
StTextureCache* st_texture_cache_get_default (void);
void st_texture_cache_clear (StTextureCache *cache);
ClutterActor *
st_texture_cache_load_sliced_image (StTextureCache *cache,